From 87b7905457ca9ab5cb57a0ea6164a72b3158a707 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 8 Mar 2020 16:04:52 +0100 Subject: [PATCH 001/232] Removed output of credentials [skip ci] --- Directory.Build.props | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b9b05c5bb..6ce7c7c6e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -63,14 +63,6 @@ - - - - - - - - $(Box_ClientId) From d0846b0f09a70c9b943eed59d43d04dbce7342ba Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 9 Mar 2020 21:50:37 +0100 Subject: [PATCH 002/232] First step in moving towards replaceable notification messages, extracted the logic to do so into it's own module. [skip ci] --- Greenshot/Forms/MainForm.cs | 33 ++--- Greenshot/Helpers/CaptureHelper.cs | 69 ++++------ .../Helpers/NotifyIconNotificationService.cs | 125 ++++++++++++++++++ GreenshotPlugin/Core/WindowsVersion.cs | 6 + 4 files changed, 168 insertions(+), 65 deletions(-) create mode 100644 Greenshot/Helpers/NotifyIconNotificationService.cs diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index dcdee013b..917553305 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -46,7 +46,6 @@ using System.Threading.Tasks; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -using GreenshotPlugin.UnmanagedHelpers.Enums; namespace Greenshot { /// @@ -350,6 +349,12 @@ namespace Greenshot { // Make the notify icon available SimpleServiceProvider.Current.AddService(notifyIcon); + // TODO: Enable check if the Windows 10 notification service is available + //if (WindowsVersion.IsBeforeWindows10) + //{ + SimpleServiceProvider.Current.AddService(new NotifyIconNotificationService()); + //} + // Disable access to the settings, for feature #3521446 contextmenu_settings.Visible = !_conf.DisableSettings; @@ -428,20 +433,7 @@ namespace Greenshot { HandleDataTransport(dataTransport); } - private void BalloonTipClicked(object sender, EventArgs e) { - try { - ShowSetting(); - } finally { - BalloonTipClosed(sender, e); - } - } - - private void BalloonTipClosed(object sender, EventArgs e) { - notifyIcon.BalloonTipClicked -= BalloonTipClicked; - notifyIcon.BalloonTipClosed -= BalloonTipClosed; - } - - private void HandleDataTransport(CopyDataTransport dataTransport) { + private void HandleDataTransport(CopyDataTransport dataTransport) { foreach(KeyValuePair command in dataTransport.Commands) { LOG.Debug("Data received, Command = " + command.Key + ", Data: " + command.Value); switch(command.Key) { @@ -451,14 +443,9 @@ namespace Greenshot { break; case CommandEnum.FirstLaunch: LOG.Info("FirstLaunch: Created new configuration, showing balloon."); - try { - notifyIcon.BalloonTipClicked += BalloonTipClicked; - notifyIcon.BalloonTipClosed += BalloonTipClosed; - notifyIcon.ShowBalloonTip(2000, "Greenshot", Language.GetFormattedString(LangKey.tooltip_firststart, HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.RegionHotkey)), ToolTipIcon.Info); - } catch (Exception ex) { - LOG.Warn("Exception while showing first launch: ", ex); - } - break; + var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); + notifyIconClassicMessageHandler.ShowInfoMessage(Language.GetFormattedString(LangKey.tooltip_firststart, HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.RegionHotkey)), 2000, ShowSetting); + break; case CommandEnum.ReloadConfig: LOG.Info("Reload requested"); try { diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index c2d1f2aab..761b2ec11 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -41,7 +41,7 @@ using GreenshotPlugin.UnmanagedHelpers.Enums; namespace Greenshot.Helpers { /// - /// CaptureHelper contains all the capture logic + /// CaptureHelper contains all the capture logic /// public class CaptureHelper : IDisposable { private static readonly ILog Log = LogManager.GetLogger(typeof(CaptureHelper)); @@ -177,7 +177,7 @@ namespace Greenshot.Helpers { public CaptureHelper(CaptureMode captureMode) { _captureMode = captureMode; - _capture = new Capture(); + _capture = new Capture(); } public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor) : this(captureMode) { @@ -192,7 +192,7 @@ namespace Greenshot.Helpers { public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor, IDestination destination) : this(captureMode, captureMouseCursor) { _capture.CaptureDetails.AddDestination(destination); } - + public WindowDetails SelectedCaptureWindow { get { return _selectedCaptureWindow; @@ -201,7 +201,7 @@ namespace Greenshot.Helpers { _selectedCaptureWindow = value; } } - + private void DoCaptureFeedback() { if (CoreConfig.PlayCameraSound) { SoundHelper.Play(); @@ -459,13 +459,13 @@ namespace Greenshot.Helpers { _capture.Dispose(); } } - + /// /// Pre-Initialization for CaptureWithFeedback, this will get all the windows before we change anything /// private Thread PrepareForCaptureWithFeedback() { _windows = new List(); - + // If the App Launcher is visisble, no other windows are active WindowDetails appLauncherWindow = WindowDetails.GetAppLauncher(); if (appLauncherWindow != null && appLauncherWindow.Visible) { @@ -514,14 +514,12 @@ namespace Greenshot.Helpers { /// /// If a balloon tip is show for a taken capture, this handles the click on it /// - /// - /// - private void OpenCaptureOnClick(object sender, EventArgs e) { + /// SurfaceMessageEventArgs + private void OpenCaptureOnClick(SurfaceMessageEventArgs e) { var notifyIcon = SimpleServiceProvider.Current.GetInstance(); if (!(notifyIcon.Tag is SurfaceMessageEventArgs eventArgs)) { Log.Warn("OpenCaptureOnClick called without SurfaceMessageEventArgs"); - RemoveEventHandler(sender, e); - return; + return; } ISurface surface = eventArgs.Surface; if (surface != null) @@ -537,17 +535,9 @@ namespace Greenshot.Helpers { } } Log.DebugFormat("Deregistering the BalloonTipClicked"); - RemoveEventHandler(sender, e); - } + } - private void RemoveEventHandler(object sender, EventArgs e) { - var notifyIcon = SimpleServiceProvider.Current.GetInstance(); - notifyIcon.BalloonTipClicked -= OpenCaptureOnClick; - notifyIcon.BalloonTipClosed -= RemoveEventHandler; - notifyIcon.Tag = null; - } - - /// + /// /// This is the SurfaceMessageEvent receiver /// /// object @@ -556,27 +546,22 @@ namespace Greenshot.Helpers { if (string.IsNullOrEmpty(eventArgs?.Message)) { return; } - var notifyIcon = SimpleServiceProvider.Current.GetInstance(); + var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); switch (eventArgs.MessageType) { case SurfaceMessageTyp.Error: - notifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Error); + notifyIconClassicMessageHandler.ShowErrorMessage(eventArgs.Message, 10000); break; case SurfaceMessageTyp.Info: - notifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Info); + notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, 10000); break; case SurfaceMessageTyp.FileSaved: case SurfaceMessageTyp.UploadedUri: // Show a balloon and register an event handler to open the "capture" for if someone clicks the balloon. - notifyIcon.BalloonTipClicked += OpenCaptureOnClick; - notifyIcon.BalloonTipClosed += RemoveEventHandler; - // Store for later usage - notifyIcon.Tag = eventArgs; - notifyIcon.ShowBalloonTip(10000, "Greenshot", eventArgs.Message, ToolTipIcon.Info); + notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, 10000, () => OpenCaptureOnClick(eventArgs)); break; } } - private void HandleCapture() { // Flag to see if the image was "exported" so the FileEditor doesn't // ask to save the file as long as nothing is done. @@ -587,7 +572,7 @@ namespace Greenshot.Helpers { var selectionRectangle = new Rectangle(Point.Empty, _capture.Image.Size); var ocrInfo = _capture.CaptureDetails.OcrInformation; if (ocrInfo != null) - { + { var textResult = new StringBuilder(); foreach (var line in ocrInfo.Lines) { @@ -666,10 +651,10 @@ namespace Greenshot.Helpers { Modified = !outputMade }; - // Register notify events if this is wanted + // Register notify events if this is wanted if (CoreConfig.ShowTrayNotification && !CoreConfig.HideTrayicon) { surface.SurfaceMessage += SurfaceMessageReceived; - + } // Let the processors do their job foreach(var processor in SimpleServiceProvider.Current.GetAllInstances()) { @@ -677,7 +662,7 @@ namespace Greenshot.Helpers { Log.InfoFormat("Calling processor {0}", processor.Description); processor.ProcessCapture(surface, _capture.CaptureDetails); } - + // As the surfaces copies the reference to the image, make sure the image is not being disposed (a trick to save memory) _capture.Image = null; @@ -749,7 +734,7 @@ namespace Greenshot.Helpers { // Nothing to capture, code up in the stack will capture the full screen return false; } - // Fix for Bug #3430560 + // Fix for Bug #3430560 CoreConfig.LastCapturedRegion = _selectedCaptureWindow.WindowRectangle; bool returnValue = CaptureWindow(_selectedCaptureWindow, _capture, CoreConfig.WindowCaptureMode) != null; return returnValue; @@ -775,7 +760,7 @@ namespace Greenshot.Helpers { } return windowToCapture; } - + /// /// Check if Process uses PresentationFramework.dll -> meaning it uses WPF /// @@ -992,9 +977,9 @@ namespace Greenshot.Helpers { private void CaptureWithFeedback() { - // The following, to be precise the HideApp, causes the app to close as described in BUG-1620 + // The following, to be precise the HideApp, causes the app to close as described in BUG-1620 // Added check for metro (Modern UI) apps, which might be maximized and cover the screen. - + //foreach(WindowDetails app in WindowDetails.GetMetroApps()) { // if (app.Maximised) { // app.HideApp(); diff --git a/Greenshot/Helpers/NotifyIconNotificationService.cs b/Greenshot/Helpers/NotifyIconNotificationService.cs new file mode 100644 index 000000000..bba6b1517 --- /dev/null +++ b/Greenshot/Helpers/NotifyIconNotificationService.cs @@ -0,0 +1,125 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows.Forms; +using GreenshotPlugin.Core; +using log4net; + +namespace Greenshot.Helpers +{ + /// + /// Notify the user with messages via the NotifyIcon + /// + public class NotifyIconNotificationService + { + private static readonly ILog Log = LogManager.GetLogger(typeof(NotifyIconNotificationService)); + private readonly NotifyIcon _notifyIcon; + + public NotifyIconNotificationService() + { + _notifyIcon = SimpleServiceProvider.Current.GetInstance(); + } + + /// + /// This will show a warning message to the user + /// + /// string + /// + /// Action called if the user clicks the notification + /// Action + public void ShowWarningMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + { + ShowMessage(message, timeout, ToolTipIcon.Warning, onClickAction, onClosedAction); + } + + /// + /// This will show an error message to the user + /// + /// string + /// + /// Action called if the user clicks the notification + /// Action + public void ShowErrorMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + { + ShowMessage(message, timeout, ToolTipIcon.Error, onClickAction, onClosedAction); + } + + /// + /// This will show an info message to the user + /// + /// string + /// int + /// Action called if the user clicks the notification + /// Action + public void ShowInfoMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + { + ShowMessage(message, timeout, ToolTipIcon.Info, onClickAction, onClosedAction); + } + + /// + /// This will show a message to the user + /// + /// string + /// int + /// ToolTipIcon + /// Action + /// Action + public void ShowMessage(string message, int timeout, ToolTipIcon level, Action onClickAction = null, Action onClosedAction = null) { + void BalloonClickedHandler(object s, EventArgs e) + { + try + { + onClickAction?.Invoke(); + } + catch (Exception ex) + { + Log.Warn("Exception while handling the onclick action: ", ex); + } + + _notifyIcon.BalloonTipClicked -= BalloonClickedHandler; + } + + if (onClickAction != null) + { + _notifyIcon.BalloonTipClicked += BalloonClickedHandler; + } + + void BalloonClosedHandler(object s, EventArgs e) + { + try + { + onClosedAction?.Invoke(); + } + catch (Exception ex) + { + Log.Warn("Exception while handling the onClosed action: ", ex); + } + + _notifyIcon.BalloonTipClosed -= BalloonClosedHandler; + // Remove the other handler too + _notifyIcon.BalloonTipClicked -= BalloonClickedHandler; + } + _notifyIcon.BalloonTipClosed += BalloonClosedHandler; + _notifyIcon.ShowBalloonTip(timeout, @"Greenshot", message, level); + } + } +} diff --git a/GreenshotPlugin/Core/WindowsVersion.cs b/GreenshotPlugin/Core/WindowsVersion.cs index 3337fe5be..ae9600f25 100644 --- a/GreenshotPlugin/Core/WindowsVersion.cs +++ b/GreenshotPlugin/Core/WindowsVersion.cs @@ -21,6 +21,12 @@ namespace GreenshotPlugin.Core /// true if we are running on Windows 10 public static bool IsWindows10 { get; } = WinVersion.Major == 10; + /// + /// Test if the current OS is before Windows 10 + /// + /// true if we are running on Windows before 10 + public static bool IsBeforeWindows10 { get; } = WinVersion.Major < 10; + /// /// Test if the current OS is Windows 10 or later /// From 1ba0bf9b1093578ea0506bfe59ed2cbe644b4b15 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 10 Mar 2020 13:17:13 +0100 Subject: [PATCH 003/232] Working on making multiple notification systems possible, removing the old "notifyicon" balloon for Windows 10. --- Greenshot/Forms/MainForm.cs | 35 +++--- Greenshot/Helpers/CaptureHelper.cs | 2 +- .../Helpers/NotifyIconNotificationService.cs | 2 +- .../Interfaces/INotificationService.cs | 55 +++++++++ .../ToastNotificationService.cs | 107 ++++++++++++++++++ GreenshotWin10Plugin/Win10Plugin.cs | 12 +- 6 files changed, 189 insertions(+), 24 deletions(-) create mode 100644 GreenshotPlugin/Interfaces/INotificationService.cs create mode 100644 GreenshotWin10Plugin/ToastNotificationService.cs diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index 917553305..c880aa209 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -349,12 +349,6 @@ namespace Greenshot { // Make the notify icon available SimpleServiceProvider.Current.AddService(notifyIcon); - // TODO: Enable check if the Windows 10 notification service is available - //if (WindowsVersion.IsBeforeWindows10) - //{ - SimpleServiceProvider.Current.AddService(new NotifyIconNotificationService()); - //} - // Disable access to the settings, for feature #3521446 contextmenu_settings.Visible = !_conf.DisableSettings; @@ -374,8 +368,14 @@ namespace Greenshot { // Load all the plugins PluginHelper.Instance.LoadPlugins(); - // Check destinations, remove all that don't exist - foreach(string destination in _conf.OutputDestinations.ToArray()) { + // Check to see if there is already another INotificationService + if (SimpleServiceProvider.Current.GetInstance() == null) + { + SimpleServiceProvider.Current.AddService(new NotifyIconNotificationService()); + } + + // Check destinations, remove all that don't exist + foreach (string destination in _conf.OutputDestinations.ToArray()) { if (DestinationHelper.GetDestination(destination) == null) { _conf.OutputDestinations.Remove(destination); } @@ -416,6 +416,7 @@ namespace Greenshot { if (dataTransport != null) { HandleDataTransport(dataTransport); } + // Make Greenshot use less memory after startup if (_conf.MinimizeWorkingSetSize) { PsAPI.EmptyWorkingSet(); @@ -443,7 +444,7 @@ namespace Greenshot { break; case CommandEnum.FirstLaunch: LOG.Info("FirstLaunch: Created new configuration, showing balloon."); - var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); + var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); notifyIconClassicMessageHandler.ShowInfoMessage(Language.GetFormattedString(LangKey.tooltip_firststart, HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.RegionHotkey)), 2000, ShowSetting); break; case CommandEnum.ReloadConfig: @@ -497,14 +498,14 @@ namespace Greenshot { base.WndProc(ref m); } - /// + /// /// Helper method to cleanly register a hotkey /// - /// - /// - /// - /// - /// + /// StringBuilder + /// string + /// string + /// HotKeyHandler + /// bool private static bool RegisterHotkey(StringBuilder failedKeys, string functionName, string hotkeyString, HotKeyHandler handler) { Keys modifierKeyCode = HotkeyControl.HotkeyModifiersFromString(hotkeyString); Keys virtualKeyCode = HotkeyControl.HotkeyFromString(hotkeyString); @@ -547,8 +548,8 @@ namespace Greenshot { /// /// Fix icon reference /// - /// - /// + /// object + /// PropertyChangedEventArgs private void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "IconSize") { diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index 761b2ec11..0007727ef 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -546,7 +546,7 @@ namespace Greenshot.Helpers { if (string.IsNullOrEmpty(eventArgs?.Message)) { return; } - var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); + var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); switch (eventArgs.MessageType) { case SurfaceMessageTyp.Error: notifyIconClassicMessageHandler.ShowErrorMessage(eventArgs.Message, 10000); diff --git a/Greenshot/Helpers/NotifyIconNotificationService.cs b/Greenshot/Helpers/NotifyIconNotificationService.cs index bba6b1517..e69464f84 100644 --- a/Greenshot/Helpers/NotifyIconNotificationService.cs +++ b/Greenshot/Helpers/NotifyIconNotificationService.cs @@ -29,7 +29,7 @@ namespace Greenshot.Helpers /// /// Notify the user with messages via the NotifyIcon /// - public class NotifyIconNotificationService + public class NotifyIconNotificationService : INotificationService { private static readonly ILog Log = LogManager.GetLogger(typeof(NotifyIconNotificationService)); private readonly NotifyIcon _notifyIcon; diff --git a/GreenshotPlugin/Interfaces/INotificationService.cs b/GreenshotPlugin/Interfaces/INotificationService.cs new file mode 100644 index 000000000..a6605e588 --- /dev/null +++ b/GreenshotPlugin/Interfaces/INotificationService.cs @@ -0,0 +1,55 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Helpers +{ + public interface INotificationService + { + /// + /// This will show a warning message to the user + /// + /// string + /// + /// Action called if the user clicks the notification + /// Action + void ShowWarningMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null); + + /// + /// This will show an error message to the user + /// + /// string + /// + /// Action called if the user clicks the notification + /// Action + void ShowErrorMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null); + + /// + /// This will show an info message to the user + /// + /// string + /// int + /// Action called if the user clicks the notification + /// Action + void ShowInfoMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null); + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/GreenshotWin10Plugin/ToastNotificationService.cs new file mode 100644 index 000000000..e21bf0389 --- /dev/null +++ b/GreenshotWin10Plugin/ToastNotificationService.cs @@ -0,0 +1,107 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.IO; +using System.Linq; +using Windows.UI.Notifications; +using Greenshot.Helpers; +using log4net; + +namespace GreenshotWin10Plugin +{ + public class ToastNotificationService : INotificationService + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ToastNotificationService)); + + private void ShowMessage(string message, Action onClickAction, Action onClosedAction) + { + // Get a toast XML template + var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText01); + + // Fill in the text elements + var stringElement = toastXml.GetElementsByTagName("text").First(); + stringElement.AppendChild(toastXml.CreateTextNode(message)); + + // Specify the absolute path to an image + //string imagePath = "file:///" + Path.GetFullPath("toastImageAndText.png"); + //var imageElement = toastXml.GetElementsByTagName("image").First(); + //imageElement.Attributes.GetNamedItem("src").NodeValue = imagePath; + + // Create the toast and attach event listeners + var toast = new ToastNotification(toastXml); + + void ToastActivatedHandler(ToastNotification toastNotification, object sender) + { + try + { + onClickAction?.Invoke(); + } + catch (Exception ex) + { + Log.Warn("Exception while handling the onclick action: ", ex); + } + + toast.Activated -= ToastActivatedHandler; + } + + if (onClickAction != null) + { + toast.Activated += ToastActivatedHandler; + } + + void ToastDismissedHandler(ToastNotification toastNotification, ToastDismissedEventArgs eventArgs) + { + Log.Debug("Toast closed"); + try + { + onClosedAction?.Invoke(); + } + catch (Exception ex) + { + Log.Warn("Exception while handling the onClosed action: ", ex); + } + + toast.Dismissed -= ToastDismissedHandler; + // Remove the other handler too + toast.Activated -= ToastActivatedHandler; + } + toast.Dismissed += ToastDismissedHandler; + // Show the toast. Be sure to specify the AppUserModelId on your application's shortcut! + ToastNotificationManager.CreateToastNotifier(@"Greenshot").Show(toast); + } + + public void ShowWarningMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + { + ShowMessage(message, onClickAction, onClosedAction); + } + + public void ShowErrorMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + { + ShowMessage(message, onClickAction, onClosedAction); + } + + public void ShowInfoMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + { + ShowMessage(message, onClickAction, onClosedAction); + } + } +} diff --git a/GreenshotWin10Plugin/Win10Plugin.cs b/GreenshotWin10Plugin/Win10Plugin.cs index f760c9a52..d21fa269e 100644 --- a/GreenshotWin10Plugin/Win10Plugin.cs +++ b/GreenshotWin10Plugin/Win10Plugin.cs @@ -20,7 +20,7 @@ */ using System; -using System.Collections.Generic; +using Greenshot.Helpers; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; @@ -34,14 +34,14 @@ namespace GreenshotWin10Plugin /// This is the Win10Plugin /// [Plugin("Win10", false)] - public class Win10Plugin : IGreenshotPlugin + public sealed class Win10Plugin : IGreenshotPlugin { public void Dispose() { Dispose(true); } - protected void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { @@ -63,8 +63,10 @@ namespace GreenshotWin10Plugin { return false; } - // Set this as IOcrProvider - SimpleServiceProvider.Current.AddService(new Win10OcrProvider()); + + SimpleServiceProvider.Current.AddService(new ToastNotificationService()); + // Set this as IOcrProvider + SimpleServiceProvider.Current.AddService(new Win10OcrProvider()); // Add the processor SimpleServiceProvider.Current.AddService(new Win10OcrProcessor()); From 7e96c99b3d67bb87f8fbf15a3280309d92e878e0 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 10 Mar 2020 22:06:47 +0100 Subject: [PATCH 004/232] Updates for the notification service, now an icon is shown and it now follows the configuration settings. [skip ci] --- .../Destinations/ClipboardDestination.cs | 2 +- Greenshot/Destinations/EditorDestination.cs | 2 +- Greenshot/Destinations/EmailDestination.cs | 2 +- Greenshot/Destinations/FileDestination.cs | 2 +- .../Destinations/FileWithDialogDestination.cs | 2 +- Greenshot/Destinations/PrinterDestination.cs | 2 +- Greenshot/Forms/CaptureForm.cs | 4 +- Greenshot/Forms/ImageEditorForm.cs | 2 +- Greenshot/Forms/LanguageDialog.cs | 2 +- Greenshot/Forms/MainForm.cs | 5 +- .../Helpers/NotifyIconNotificationService.cs | 11 ++++- GreenshotJiraPlugin/Forms/JiraForm.cs | 2 +- .../Destinations/OutlookDestination.cs | 2 +- GreenshotPlugin/Controls/BackgroundForm.cs | 2 +- GreenshotPlugin/Controls/GreenshotForm.cs | 2 +- GreenshotPlugin/Controls/OAuthLoginForm.cs | 2 +- GreenshotPlugin/Controls/PleaseWaitForm.cs | 2 +- GreenshotPlugin/Core/AbstractDestination.cs | 2 +- GreenshotPlugin/Core/GreenshotResources.cs | 27 +++++------ .../Interfaces/INotificationService.cs | 5 +- .../Destinations/Win10ShareDestination.cs | 2 +- .../ToastNotificationService.cs | 48 +++++++++++++++++-- GreenshotWin10Plugin/Win10Plugin.cs | 1 - 23 files changed, 90 insertions(+), 43 deletions(-) diff --git a/Greenshot/Destinations/ClipboardDestination.cs b/Greenshot/Destinations/ClipboardDestination.cs index 3d415aed8..9cfb0aec5 100644 --- a/Greenshot/Destinations/ClipboardDestination.cs +++ b/Greenshot/Destinations/ClipboardDestination.cs @@ -58,7 +58,7 @@ namespace Greenshot.Destinations { public override Image DisplayIcon { get { - return GreenshotResources.getImage("Clipboard.Image"); + return GreenshotResources.GetImage("Clipboard.Image"); } } diff --git a/Greenshot/Destinations/EditorDestination.cs b/Greenshot/Destinations/EditorDestination.cs index 2e9252d8b..09cce0f56 100644 --- a/Greenshot/Destinations/EditorDestination.cs +++ b/Greenshot/Destinations/EditorDestination.cs @@ -37,7 +37,7 @@ namespace Greenshot.Destinations { private static readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection(); public const string DESIGNATION = "Editor"; private readonly IImageEditor editor; - private static readonly Image greenshotIcon = GreenshotResources.getGreenshotIcon().ToBitmap(); + private static readonly Image greenshotIcon = GreenshotResources.GetGreenshotIcon().ToBitmap(); public EditorDestination() { } diff --git a/Greenshot/Destinations/EmailDestination.cs b/Greenshot/Destinations/EmailDestination.cs index 4f8ab24e2..abda77c7c 100644 --- a/Greenshot/Destinations/EmailDestination.cs +++ b/Greenshot/Destinations/EmailDestination.cs @@ -32,7 +32,7 @@ namespace Greenshot.Destinations { /// Description of EmailDestination. /// public class EmailDestination : AbstractDestination { - private static readonly Image MailIcon = GreenshotResources.getImage("Email.Image"); + private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); private static bool _isActiveFlag; private static string _mapiClient; public const string DESIGNATION = "EMail"; diff --git a/Greenshot/Destinations/FileDestination.cs b/Greenshot/Destinations/FileDestination.cs index 568337ac6..559d28135 100644 --- a/Greenshot/Destinations/FileDestination.cs +++ b/Greenshot/Destinations/FileDestination.cs @@ -48,7 +48,7 @@ namespace Greenshot.Destinations { public override Keys EditorShortcutKeys => Keys.Control | Keys.S; - public override Image DisplayIcon => GreenshotResources.getImage("Save.Image"); + public override Image DisplayIcon => GreenshotResources.GetImage("Save.Image"); public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { ExportInformation exportInformation = new ExportInformation(Designation, Description); diff --git a/Greenshot/Destinations/FileWithDialogDestination.cs b/Greenshot/Destinations/FileWithDialogDestination.cs index 6acb60088..e211d14f7 100644 --- a/Greenshot/Destinations/FileWithDialogDestination.cs +++ b/Greenshot/Destinations/FileWithDialogDestination.cs @@ -61,7 +61,7 @@ namespace Greenshot.Destinations { public override Image DisplayIcon { get { - return GreenshotResources.getImage("Save.Image"); + return GreenshotResources.GetImage("Save.Image"); } } diff --git a/Greenshot/Destinations/PrinterDestination.cs b/Greenshot/Destinations/PrinterDestination.cs index b9781d286..e2156256b 100644 --- a/Greenshot/Destinations/PrinterDestination.cs +++ b/Greenshot/Destinations/PrinterDestination.cs @@ -59,7 +59,7 @@ namespace Greenshot.Destinations { public override Keys EditorShortcutKeys => Keys.Control | Keys.P; - public override Image DisplayIcon => GreenshotResources.getImage("Printer.Image"); + public override Image DisplayIcon => GreenshotResources.GetImage("Printer.Image"); public override bool IsDynamic => true; diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs index dc5332708..e415d1053 100644 --- a/Greenshot/Forms/CaptureForm.cs +++ b/Greenshot/Forms/CaptureForm.cs @@ -59,7 +59,7 @@ namespace Greenshot.Forms { /// Initialize the background brush /// static CaptureForm() { - Image backgroundForTransparency = GreenshotResources.getImage("Checkerboard.Image"); + Image backgroundForTransparency = GreenshotResources.GetImage("Checkerboard.Image"); BackgroundBrush = new TextureBrush(backgroundForTransparency, WrapMode.Tile); } @@ -415,7 +415,7 @@ namespace Greenshot.Forms { } /// - /// + /// /// /// /// diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index a40c96b4a..bcb8c275c 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -175,7 +175,7 @@ namespace Greenshot { { panel1.Controls.Add(_surface); } - Image backgroundForTransparency = GreenshotResources.getImage("Checkerboard.Image"); + Image backgroundForTransparency = GreenshotResources.GetImage("Checkerboard.Image"); if (_surface != null) { _surface.TransparencyBackgroundBrush = new TextureBrush(backgroundForTransparency, WrapMode.Tile); diff --git a/Greenshot/Forms/LanguageDialog.cs b/Greenshot/Forms/LanguageDialog.cs index 7565285b8..7d6ba2f33 100644 --- a/Greenshot/Forms/LanguageDialog.cs +++ b/Greenshot/Forms/LanguageDialog.cs @@ -38,7 +38,7 @@ namespace Greenshot.Forms { // The InitializeComponent() call is required for Windows Forms designer support. // InitializeComponent(); - Icon = GreenshotResources.getGreenshotIcon(); + Icon = GreenshotResources.GetGreenshotIcon(); Load += FormLoad; FormClosing += PreventFormClose; } diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index c880aa209..a197a8cf5 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -231,7 +231,7 @@ namespace Greenshot { // A dirty fix to make sure the message box is visible as a Greenshot window on the taskbar using Form dummyForm = new Form { - Icon = GreenshotResources.getGreenshotIcon(), + Icon = GreenshotResources.GetGreenshotIcon(), ShowInTaskbar = true, FormBorderStyle = FormBorderStyle.None, Location = new Point(int.MinValue, int.MinValue) @@ -345,7 +345,7 @@ namespace Greenshot { // Make the main menu available SimpleServiceProvider.Current.AddService(contextMenu); - notifyIcon.Icon = GreenshotResources.getGreenshotIcon(); + notifyIcon.Icon = GreenshotResources.GetGreenshotIcon(); // Make the notify icon available SimpleServiceProvider.Current.AddService(notifyIcon); @@ -371,6 +371,7 @@ namespace Greenshot { // Check to see if there is already another INotificationService if (SimpleServiceProvider.Current.GetInstance() == null) { + // If not we add the internal NotifyIcon notification service SimpleServiceProvider.Current.AddService(new NotifyIconNotificationService()); } diff --git a/Greenshot/Helpers/NotifyIconNotificationService.cs b/Greenshot/Helpers/NotifyIconNotificationService.cs index e69464f84..e5d49a643 100644 --- a/Greenshot/Helpers/NotifyIconNotificationService.cs +++ b/Greenshot/Helpers/NotifyIconNotificationService.cs @@ -22,6 +22,8 @@ using System; using System.Windows.Forms; using GreenshotPlugin.Core; +using GreenshotPlugin.IniFile; +using GreenshotPlugin.Interfaces; using log4net; namespace Greenshot.Helpers @@ -32,6 +34,7 @@ namespace Greenshot.Helpers public class NotifyIconNotificationService : INotificationService { private static readonly ILog Log = LogManager.GetLogger(typeof(NotifyIconNotificationService)); + private static readonly CoreConfiguration CoreConfiguration = IniConfig.GetIniSection(); private readonly NotifyIcon _notifyIcon; public NotifyIconNotificationService() @@ -83,7 +86,13 @@ namespace Greenshot.Helpers /// ToolTipIcon /// Action /// Action - public void ShowMessage(string message, int timeout, ToolTipIcon level, Action onClickAction = null, Action onClosedAction = null) { + private void ShowMessage(string message, int timeout, ToolTipIcon level, Action onClickAction = null, Action onClosedAction = null) { + // Do not inform the user if this is disabled + if (!CoreConfiguration.ShowTrayNotification) + { + return; + } + void BalloonClickedHandler(object s, EventArgs e) { try diff --git a/GreenshotJiraPlugin/Forms/JiraForm.cs b/GreenshotJiraPlugin/Forms/JiraForm.cs index 9bf669083..551fadadc 100644 --- a/GreenshotJiraPlugin/Forms/JiraForm.cs +++ b/GreenshotJiraPlugin/Forms/JiraForm.cs @@ -40,7 +40,7 @@ namespace GreenshotJiraPlugin.Forms { public JiraForm(JiraConnector jiraConnector) { InitializeComponent(); - Icon = GreenshotResources.getGreenshotIcon(); + Icon = GreenshotResources.GetGreenshotIcon(); AcceptButton = uploadButton; CancelButton = cancelButton; diff --git a/GreenshotOfficePlugin/Destinations/OutlookDestination.cs b/GreenshotOfficePlugin/Destinations/OutlookDestination.cs index 91e58b273..ac88ec091 100644 --- a/GreenshotOfficePlugin/Destinations/OutlookDestination.cs +++ b/GreenshotOfficePlugin/Destinations/OutlookDestination.cs @@ -40,7 +40,7 @@ namespace GreenshotOfficePlugin.Destinations { private const int IconApplication = 0; private const int IconMeeting = 2; - private static readonly Image MailIcon = GreenshotResources.getImage("Email.Image"); + private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); private static readonly OfficeConfiguration OfficeConfig = IniConfig.GetIniSection(); private static readonly string ExePath; private static readonly bool IsActiveFlag; diff --git a/GreenshotPlugin/Controls/BackgroundForm.cs b/GreenshotPlugin/Controls/BackgroundForm.cs index a3152ac4a..5d90c6920 100644 --- a/GreenshotPlugin/Controls/BackgroundForm.cs +++ b/GreenshotPlugin/Controls/BackgroundForm.cs @@ -51,7 +51,7 @@ namespace GreenshotPlugin.Controls { // The InitializeComponent() call is required for Windows Forms designer support. // InitializeComponent(); - Icon = GreenshotResources.getGreenshotIcon(); + Icon = GreenshotResources.GetGreenshotIcon(); _shouldClose = false; Text = title; label_pleasewait.Text = text; diff --git a/GreenshotPlugin/Controls/GreenshotForm.cs b/GreenshotPlugin/Controls/GreenshotForm.cs index 32a9fb64f..a7926095f 100644 --- a/GreenshotPlugin/Controls/GreenshotForm.cs +++ b/GreenshotPlugin/Controls/GreenshotForm.cs @@ -146,7 +146,7 @@ namespace GreenshotPlugin.Controls { protected override void OnLoad(EventArgs e) { // Every GreenshotForm should have it's default icon // And it might not ne needed for a Tool Window, but still for the task manager / switcher it's important - Icon = GreenshotResources.getGreenshotIcon(); + Icon = GreenshotResources.GetGreenshotIcon(); if (!DesignMode) { if (!_applyLanguageManually) { ApplyLanguage(); diff --git a/GreenshotPlugin/Controls/OAuthLoginForm.cs b/GreenshotPlugin/Controls/OAuthLoginForm.cs index 2c788893c..2b834d128 100644 --- a/GreenshotPlugin/Controls/OAuthLoginForm.cs +++ b/GreenshotPlugin/Controls/OAuthLoginForm.cs @@ -50,7 +50,7 @@ namespace GreenshotPlugin.Controls { } InitializeComponent(); ClientSize = size; - Icon = GreenshotResources.getGreenshotIcon(); + Icon = GreenshotResources.GetGreenshotIcon(); Text = browserTitle; _addressTextBox.Text = authorizationLink; diff --git a/GreenshotPlugin/Controls/PleaseWaitForm.cs b/GreenshotPlugin/Controls/PleaseWaitForm.cs index 430520267..995b0c17c 100644 --- a/GreenshotPlugin/Controls/PleaseWaitForm.cs +++ b/GreenshotPlugin/Controls/PleaseWaitForm.cs @@ -37,7 +37,7 @@ namespace GreenshotPlugin.Controls { // The InitializeComponent() call is required for Windows Forms designer support. // InitializeComponent(); - Icon = GreenshotResources.getGreenshotIcon(); + Icon = GreenshotResources.GetGreenshotIcon(); } /// diff --git a/GreenshotPlugin/Core/AbstractDestination.cs b/GreenshotPlugin/Core/AbstractDestination.cs index df4d2163d..886dd5dab 100644 --- a/GreenshotPlugin/Core/AbstractDestination.cs +++ b/GreenshotPlugin/Core/AbstractDestination.cs @@ -234,7 +234,7 @@ namespace GreenshotPlugin.Core { menu.Items.Add(new ToolStripSeparator()); ToolStripMenuItem closeItem = new ToolStripMenuItem(Language.GetString("editor_close")) { - Image = GreenshotResources.getImage("Close.Image") + Image = GreenshotResources.GetImage("Close.Image") }; closeItem.Click += delegate { // This menu entry is the close itself, we can dispose the surface diff --git a/GreenshotPlugin/Core/GreenshotResources.cs b/GreenshotPlugin/Core/GreenshotResources.cs index 358dbab46..8f59dee91 100644 --- a/GreenshotPlugin/Core/GreenshotResources.cs +++ b/GreenshotPlugin/Core/GreenshotResources.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -26,21 +26,18 @@ namespace GreenshotPlugin.Core { /// Centralized storage of the icons & bitmaps /// public static class GreenshotResources { - private static readonly ComponentResourceManager greenshotResources = new ComponentResourceManager(typeof(GreenshotResources)); + private static readonly ComponentResourceManager GreenshotResourceManager = new ComponentResourceManager(typeof(GreenshotResources)); - public static Image getImage(string imageName) { - return (Image)greenshotResources.GetObject(imageName); + public static Image GetImage(string imageName) { + return (Image)GreenshotResourceManager.GetObject(imageName); } - public static Icon getIcon(string imageName) { - return (Icon)greenshotResources.GetObject(imageName); - } - - public static Icon getGreenshotIcon() { - return getIcon("Greenshot.Icon"); + public static Icon GetIcon(string imageName) { + return (Icon)GreenshotResourceManager.GetObject(imageName); } - public static Image getGreenshotImage() { - return getImage("Greenshot.Image"); + public static Icon GetGreenshotIcon() { + return GetIcon("Greenshot.Icon"); } + } } diff --git a/GreenshotPlugin/Interfaces/INotificationService.cs b/GreenshotPlugin/Interfaces/INotificationService.cs index a6605e588..922d718ba 100644 --- a/GreenshotPlugin/Interfaces/INotificationService.cs +++ b/GreenshotPlugin/Interfaces/INotificationService.cs @@ -21,8 +21,11 @@ using System; -namespace Greenshot.Helpers +namespace GreenshotPlugin.Interfaces { + /// + /// This is the interface for the different notification service implementations + /// public interface INotificationService { /// diff --git a/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs b/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs index 7fc82a1b8..a01ae2216 100644 --- a/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs +++ b/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs @@ -167,7 +167,7 @@ namespace GreenshotWin10Plugin.Destinations // Create logo RandomAccessStreamReference logoRandomAccessStreamReference; - using (var logo = GreenshotResources.getGreenshotIcon().ToBitmap()) + using (var logo = GreenshotResources.GetGreenshotIcon().ToBitmap()) using (var logoThumbnail = ImageHelper.CreateThumbnail(logo, 30, 30)) { ImageOutput.SaveToStream(logoThumbnail, null, logoStream, outputSettings); diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/GreenshotWin10Plugin/ToastNotificationService.cs index e21bf0389..1c3ad9dda 100644 --- a/GreenshotWin10Plugin/ToastNotificationService.cs +++ b/GreenshotWin10Plugin/ToastNotificationService.cs @@ -20,20 +20,51 @@ */ using System; +using System.Drawing.Imaging; using System.IO; using System.Linq; using Windows.UI.Notifications; -using Greenshot.Helpers; +using GreenshotPlugin.Core; +using GreenshotPlugin.IniFile; +using GreenshotPlugin.Interfaces; using log4net; namespace GreenshotWin10Plugin { + /// + /// This service provides a way to inform (notify) the user. + /// public class ToastNotificationService : INotificationService { private static readonly ILog Log = LogManager.GetLogger(typeof(ToastNotificationService)); + private static readonly CoreConfiguration CoreConfiguration = IniConfig.GetIniSection(); + + private readonly string _imageFilePath; + public ToastNotificationService() + { + var localAppData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Greenshot"); + if (!Directory.Exists(localAppData)) + { + Directory.CreateDirectory(localAppData); + } + _imageFilePath = Path.Combine(localAppData, "greenshot.png"); + + if (File.Exists(_imageFilePath)) + { + return; + } + + using var greenshotImage = GreenshotResources.GetGreenshotIcon().ToBitmap(); + greenshotImage.Save(_imageFilePath, ImageFormat.Png); + } private void ShowMessage(string message, Action onClickAction, Action onClosedAction) { + // Do not inform the user if this is disabled + if (!CoreConfiguration.ShowTrayNotification) + { + return; + } // Get a toast XML template var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText01); @@ -41,10 +72,17 @@ namespace GreenshotWin10Plugin var stringElement = toastXml.GetElementsByTagName("text").First(); stringElement.AppendChild(toastXml.CreateTextNode(message)); - // Specify the absolute path to an image - //string imagePath = "file:///" + Path.GetFullPath("toastImageAndText.png"); - //var imageElement = toastXml.GetElementsByTagName("image").First(); - //imageElement.Attributes.GetNamedItem("src").NodeValue = imagePath; + if (_imageFilePath != null && File.Exists(_imageFilePath)) + { + // Specify the absolute path to an image + var imageElement = toastXml.GetElementsByTagName("image").First(); + var imageSrcNode = imageElement.Attributes.GetNamedItem("src"); + if (imageSrcNode != null) + { + imageSrcNode.NodeValue = _imageFilePath; + } + } + // Create the toast and attach event listeners var toast = new ToastNotification(toastXml); diff --git a/GreenshotWin10Plugin/Win10Plugin.cs b/GreenshotWin10Plugin/Win10Plugin.cs index d21fa269e..947ce180c 100644 --- a/GreenshotWin10Plugin/Win10Plugin.cs +++ b/GreenshotWin10Plugin/Win10Plugin.cs @@ -20,7 +20,6 @@ */ using System; -using Greenshot.Helpers; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; From a29f6faa27cd6230ab47dd17207cc84b3404ea4e Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 11 Mar 2020 15:22:17 +0100 Subject: [PATCH 005/232] Working on improving the toast notifications [skip ci] --- Greenshot/greenshot.manifest | 74 ++-- GreenshotPlugin/Core/WindowsVersion.cs | 3 + .../DesktopNotificationManagerCompat.cs | 384 ++++++++++++++++++ .../Native/GreenshotNotificationActivator.cs | 41 ++ .../ToastNotificationService.cs | 32 +- 5 files changed, 496 insertions(+), 38 deletions(-) create mode 100644 GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs create mode 100644 GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs diff --git a/Greenshot/greenshot.manifest b/Greenshot/greenshot.manifest index 919fcb895..cae29e2dc 100644 --- a/Greenshot/greenshot.manifest +++ b/Greenshot/greenshot.manifest @@ -1,44 +1,48 @@  - - - - - True/PM - - + + + + + True/PM + + true + true + PerMonitorV2,PerMonitor + true + true + + - + + - + - + - - - + - - - - - - - - - - + + + + + + + + + + \ No newline at end of file diff --git a/GreenshotPlugin/Core/WindowsVersion.cs b/GreenshotPlugin/Core/WindowsVersion.cs index ae9600f25..6dd4faa08 100644 --- a/GreenshotPlugin/Core/WindowsVersion.cs +++ b/GreenshotPlugin/Core/WindowsVersion.cs @@ -15,6 +15,7 @@ namespace GreenshotPlugin.Core /// public static Version WinVersion { get; } = Environment.OSVersion.Version; + public static double WinVersionTotal = WinVersion.Major + (double)WinVersion.Minor / 10; /// /// Test if the current OS is Windows 10 /// @@ -39,6 +40,8 @@ namespace GreenshotPlugin.Core /// true if we are running on Windows 7 or later public static bool IsWindows7OrLater { get; } = WinVersion.Major == 6 && WinVersion.Minor >= 1 || WinVersion.Major > 6; + public static bool IsWindows7OrLower { get; } = WinVersionTotal <= 6.1; + /// /// Test if the current OS is Windows 8.0 /// diff --git a/GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs b/GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs new file mode 100644 index 000000000..703768582 --- /dev/null +++ b/GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs @@ -0,0 +1,384 @@ +// ****************************************************************** +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. +// ****************************************************************** + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using Windows.UI.Notifications; +using GreenshotPlugin.Core; + +namespace GreenshotWin10Plugin.Native +{ + public class DesktopNotificationManagerCompat + { + public const string TOAST_ACTIVATED_LAUNCH_ARG = "-ToastActivated"; + + private static bool _registeredAumidAndComServer; + private static string _aumid; + private static bool _registeredActivator; + + /// + /// If not running under the Desktop Bridge, you must call this method to register your AUMID with the Compat library and to + /// register your COM CLSID and EXE in LocalServer32 registry. Feel free to call this regardless, and we will no-op if running + /// under Desktop Bridge. Call this upon application startup, before calling any other APIs. + /// + /// An AUMID that uniquely identifies your application. + public static void RegisterAumidAndComServer(string aumid) + where T : NotificationActivator + { + if (string.IsNullOrWhiteSpace(aumid)) + { + throw new ArgumentException("You must provide an AUMID.", nameof(aumid)); + } + + // If running as Desktop Bridge + if (DesktopBridgeHelpers.IsRunningAsUwp()) + { + // Clear the AUMID since Desktop Bridge doesn't use it, and then we're done. + // Desktop Bridge apps are registered with platform through their manifest. + // Their LocalServer32 key is also registered through their manifest. + _aumid = null; + _registeredAumidAndComServer = true; + return; + } + + _aumid = aumid; + + String exePath = Process.GetCurrentProcess().MainModule.FileName; + RegisterComServer(exePath); + + _registeredAumidAndComServer = true; + } + + private static void RegisterComServer(string exePath) + where T : NotificationActivator + { + // We register the EXE to start up when the notification is activated + string regString = $"SOFTWARE\\Classes\\CLSID\\{{{typeof(T).GUID}}}\\LocalServer32"; + var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(regString); + + // Include a flag so we know this was a toast activation and should wait for COM to process + // We also wrap EXE path in quotes for extra security + key.SetValue(null, '"' + exePath + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG); + } + + /// + /// Registers the activator type as a COM server client so that Windows can launch your activator. + /// + /// Your implementation of NotificationActivator. Must have GUID and ComVisible attributes on class. + public static void RegisterActivator() where T : NotificationActivator + { + // Register type + var regService = new RegistrationServices(); + + regService.RegisterTypeForComClients( + typeof(T), + RegistrationClassContext.LocalServer, + RegistrationConnectionType.MultipleUse); + + _registeredActivator = true; + } + + /// + /// Creates a toast notifier. You must have called first (and also if you're a classic Win32 app), or this will throw an exception. + /// + /// + public static ToastNotifier CreateToastNotifier() + { + EnsureRegistered(); + + if (_aumid != null) + { + // Non-Desktop Bridge + return ToastNotificationManager.CreateToastNotifier(_aumid); + } + + // Desktop Bridge + return ToastNotificationManager.CreateToastNotifier(); + } + + /// + /// Gets the object. You must have called first (and also if you're a classic Win32 app), or this will throw an exception. + /// + public static DesktopNotificationHistoryCompat History + { + get + { + EnsureRegistered(); + + return new DesktopNotificationHistoryCompat(_aumid); + } + } + + private static void EnsureRegistered() + { + // If not registered AUMID yet + if (!_registeredAumidAndComServer) + { + // Check if Desktop Bridge + if (DesktopBridgeHelpers.IsRunningAsUwp()) + { + // Implicitly registered, all good! + _registeredAumidAndComServer = true; + } + + else + { + // Otherwise, incorrect usage + throw new Exception("You must call RegisterAumidAndComServer first."); + } + } + + // If not registered activator yet + if (!_registeredActivator) + { + // Incorrect usage + throw new Exception("You must call RegisterActivator first."); + } + } + + /// + /// Gets a boolean representing whether http images can be used within toasts. This is true if running under Desktop Bridge. + /// + public static bool CanUseHttpImages { get { return DesktopBridgeHelpers.IsRunningAsUwp(); } } + + /// + /// Code from https://github.com/qmatteoq/DesktopBridgeHelpers/edit/master/DesktopBridge.Helpers/Helpers.cs + /// + private static class DesktopBridgeHelpers + { + const long APPMODEL_ERROR_NO_PACKAGE = 15700L; + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName); + + private static bool? _isRunningAsUwp; + public static bool IsRunningAsUwp() + { + if (_isRunningAsUwp != null) return _isRunningAsUwp.Value; + + if (WindowsVersion.IsWindows7OrLower) + { + _isRunningAsUwp = false; + } + else + { + int length = 0; + StringBuilder sb = new StringBuilder(0); + GetCurrentPackageFullName(ref length, sb); + + sb = new StringBuilder(length); + int result = GetCurrentPackageFullName(ref length, sb); + + _isRunningAsUwp = result != APPMODEL_ERROR_NO_PACKAGE; + } + + return _isRunningAsUwp.Value; + } + } + } + + /// + /// Manages the toast notifications for an app including the ability the clear all toast history and removing individual toasts. + /// + public sealed class DesktopNotificationHistoryCompat + { + private string _aumid; + private ToastNotificationHistory _history; + + /// + /// Do not call this. Instead, call to obtain an instance. + /// + /// + internal DesktopNotificationHistoryCompat(string aumid) + { + _aumid = aumid; + _history = ToastNotificationManager.History; + } + + /// + /// Removes all notifications sent by this app from action center. + /// + public void Clear() + { + if (_aumid != null) + { + _history.Clear(_aumid); + } + else + { + _history.Clear(); + } + } + + /// + /// Gets all notifications sent by this app that are currently still in Action Center. + /// + /// A collection of toasts. + public IReadOnlyList GetHistory() + { + return _aumid != null ? _history.GetHistory(_aumid) : _history.GetHistory(); + } + + /// + /// Removes an individual toast, with the specified tag label, from action center. + /// + /// The tag label of the toast notification to be removed. + public void Remove(string tag) + { + if (_aumid != null) + { + _history.Remove(tag, string.Empty, _aumid); + } + else + { + _history.Remove(tag); + } + } + + /// + /// Removes a toast notification from the action using the notification's tag and group labels. + /// + /// The tag label of the toast notification to be removed. + /// The group label of the toast notification to be removed. + public void Remove(string tag, string group) + { + if (_aumid != null) + { + _history.Remove(tag, group, _aumid); + } + else + { + _history.Remove(tag, group); + } + } + + /// + /// Removes a group of toast notifications, identified by the specified group label, from action center. + /// + /// The group label of the toast notifications to be removed. + public void RemoveGroup(string group) + { + if (_aumid != null) + { + _history.RemoveGroup(group, _aumid); + } + else + { + _history.RemoveGroup(group); + } + } + } + + /// + /// Apps must implement this activator to handle notification activation. + /// + public abstract class NotificationActivator : NotificationActivator.INotificationActivationCallback + { + public void Activate(string appUserModelId, string invokedArgs, NOTIFICATION_USER_INPUT_DATA[] data, uint dataCount) + { + OnActivated(invokedArgs, new NotificationUserInput(data), appUserModelId); + } + + /// + /// This method will be called when the user clicks on a foreground or background activation on a toast. Parent app must implement this method. + /// + /// The arguments from the original notification. This is either the launch argument if the user clicked the body of your toast, or the arguments from a button on your toast. + /// Text and selection values that the user entered in your toast. + /// Your AUMID. + public abstract void OnActivated(string arguments, NotificationUserInput userInput, string appUserModelId); + + // These are the new APIs for Windows 10 + #region NewAPIs + [StructLayout(LayoutKind.Sequential), Serializable] + public struct NOTIFICATION_USER_INPUT_DATA + { + [MarshalAs(UnmanagedType.LPWStr)] + public string Key; + + [MarshalAs(UnmanagedType.LPWStr)] + public string Value; + } + + [ComImport, + Guid("53E31837-6600-4A81-9395-75CFFE746F94"), ComVisible(true), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface INotificationActivationCallback + { + void Activate( + [In, MarshalAs(UnmanagedType.LPWStr)] + string appUserModelId, + [In, MarshalAs(UnmanagedType.LPWStr)] + string invokedArgs, + [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] + NOTIFICATION_USER_INPUT_DATA[] data, + [In, MarshalAs(UnmanagedType.U4)] + uint dataCount); + } + #endregion + } + + /// + /// Text and selection values that the user entered on your notification. The Key is the ID of the input, and the Value is what the user entered. + /// + public class NotificationUserInput : IReadOnlyDictionary + { + private NotificationActivator.NOTIFICATION_USER_INPUT_DATA[] _data; + + internal NotificationUserInput(NotificationActivator.NOTIFICATION_USER_INPUT_DATA[] data) + { + _data = data; + } + + public string this[string key] => _data.First(i => i.Key == key).Value; + + public IEnumerable Keys => _data.Select(i => i.Key); + + public IEnumerable Values => _data.Select(i => i.Value); + + public int Count => _data.Length; + + public bool ContainsKey(string key) + { + return _data.Any(i => i.Key == key); + } + + public IEnumerator> GetEnumerator() + { + return _data.Select(i => new KeyValuePair(i.Key, i.Value)).GetEnumerator(); + } + + public bool TryGetValue(string key, out string value) + { + foreach (var item in _data) + { + if (item.Key == key) + { + value = item.Value; + return true; + } + } + + value = null; + return false; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs b/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs new file mode 100644 index 000000000..74922476f --- /dev/null +++ b/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs @@ -0,0 +1,41 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; +using log4net; + +namespace GreenshotWin10Plugin.Native +{ + // The GUID CLSID must be unique to your app. Create a new GUID if copying this code. + [ClassInterface(ClassInterfaceType.None)] + [ComSourceInterfaces(typeof(INotificationActivationCallback))] + [Guid("F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08"), ComVisible(true)] + public class GreenshotNotificationActivator : NotificationActivator + { + private static readonly ILog Log = LogManager.GetLogger(typeof(GreenshotNotificationActivator)); + + public override void OnActivated(string invokedArgs, NotificationUserInput userInput, string appUserModelId) + { + // TODO: Handle activation + Log.Info("Activated"); + } + } +} diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/GreenshotWin10Plugin/ToastNotificationService.cs index 1c3ad9dda..05d930bc8 100644 --- a/GreenshotWin10Plugin/ToastNotificationService.cs +++ b/GreenshotWin10Plugin/ToastNotificationService.cs @@ -27,6 +27,7 @@ using Windows.UI.Notifications; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; +using GreenshotWin10Plugin.Native; using log4net; namespace GreenshotWin10Plugin @@ -42,6 +43,11 @@ namespace GreenshotWin10Plugin private readonly string _imageFilePath; public ToastNotificationService() { + // Register AUMID and COM server (for Desktop Bridge apps, this no-ops) + DesktopNotificationManagerCompat.RegisterAumidAndComServer("Greenshot.Greenshot"); + // Register COM server and activator type + DesktopNotificationManagerCompat.RegisterActivator(); + var localAppData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Greenshot"); if (!Directory.Exists(localAppData)) { @@ -58,6 +64,12 @@ namespace GreenshotWin10Plugin greenshotImage.Save(_imageFilePath, ImageFormat.Png); } + /// + /// This creates the actual toast + /// + /// string + /// Action called when clicked + /// Action called when the toast is closed private void ShowMessage(string message, Action onClickAction, Action onClosedAction) { // Do not inform the user if this is disabled @@ -65,6 +77,14 @@ namespace GreenshotWin10Plugin { return; } + // Prepare the toast notifier. Be sure to specify the AppUserModelId on your application's shortcut! + var toastNotifier = DesktopNotificationManagerCompat.CreateToastNotifier(); + if (toastNotifier.Setting != NotificationSetting.Enabled) + { + Log.DebugFormat("Ignored toast due to {0}", toastNotifier.Setting); + return; + } + // Get a toast XML template var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText01); @@ -83,7 +103,6 @@ namespace GreenshotWin10Plugin } } - // Create the toast and attach event listeners var toast = new ToastNotification(toastXml); @@ -121,10 +140,17 @@ namespace GreenshotWin10Plugin toast.Dismissed -= ToastDismissedHandler; // Remove the other handler too toast.Activated -= ToastActivatedHandler; + toast.Failed -= ToastOnFailed; } toast.Dismissed += ToastDismissedHandler; - // Show the toast. Be sure to specify the AppUserModelId on your application's shortcut! - ToastNotificationManager.CreateToastNotifier(@"Greenshot").Show(toast); + toast.Failed += ToastOnFailed; + toastNotifier.Show(toast); + } + + private void ToastOnFailed(ToastNotification sender, ToastFailedEventArgs args) + { + Log.WarnFormat("Failed to display a toast due to {0}", args.ErrorCode); + Log.Debug(sender.Content.GetXml()); } public void ShowWarningMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) From f20604601056d6a3d3bdd8feec23a2727f883c2e Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 16 Mar 2020 14:20:14 +0100 Subject: [PATCH 006/232] Made notifications work again, activation doesn't work yet due to missing ToastActivatorCLSID on the shortcut. --- Greenshot/Helpers/CaptureHelper.cs | 5 +- Greenshot/releases/innosetup/setup.iss | 5 +- .../Native/DesktopBridgeHelpers.cs | 53 ++++ .../DesktopNotificationHistoryCompat.cs | 109 +++++++ .../DesktopNotificationManagerCompat.cs | 298 +++--------------- .../Native/GreenshotNotificationActivator.cs | 4 +- .../Native/INotificationActivationCallback.cs | 35 ++ .../Native/NotificationActivator.cs | 35 ++ .../Native/NotificationUserInput.cs | 70 ++++ .../Structs/NotificationUserInputData.cs | 30 ++ .../ToastNotificationService.cs | 17 +- 11 files changed, 392 insertions(+), 269 deletions(-) create mode 100644 GreenshotWin10Plugin/Native/DesktopBridgeHelpers.cs create mode 100644 GreenshotWin10Plugin/Native/DesktopNotificationHistoryCompat.cs create mode 100644 GreenshotWin10Plugin/Native/INotificationActivationCallback.cs create mode 100644 GreenshotWin10Plugin/Native/NotificationActivator.cs create mode 100644 GreenshotWin10Plugin/Native/NotificationUserInput.cs create mode 100644 GreenshotWin10Plugin/Native/Structs/NotificationUserInputData.cs diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index 0007727ef..ea7707f1f 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -552,7 +552,10 @@ namespace Greenshot.Helpers { notifyIconClassicMessageHandler.ShowErrorMessage(eventArgs.Message, 10000); break; case SurfaceMessageTyp.Info: - notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, 10000); + notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, 10000, () => + { + Log.Info("Clicked!"); + }); break; case SurfaceMessageTyp.FileSaved: case SurfaceMessageTyp.UploadedUri: diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 5933fd823..bf4485edf 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -189,10 +189,11 @@ Root: HKLM; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; V Root: HKLM; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser [Icons] -Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app} -Name: {group}\Uninstall {#ExeName}; Filename: {uninstallexe}; WorkingDir: {app}; AppUserModelID: "{#ExeName}.{#ExeName}" +Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app}; AppUserModelID: "{#ExeName}" +Name: {group}\Uninstall {#ExeName}; Filename: {uninstallexe}; WorkingDir: {app}; Name: {group}\Readme.txt; Filename: {app}\readme.txt; WorkingDir: {app} Name: {group}\License.txt; Filename: {app}\license.txt; WorkingDir: {app} + [Languages] Name: en; MessagesFile: compiler:Default.isl Name: cn; MessagesFile: Languages\ChineseSimplified.isl diff --git a/GreenshotWin10Plugin/Native/DesktopBridgeHelpers.cs b/GreenshotWin10Plugin/Native/DesktopBridgeHelpers.cs new file mode 100644 index 000000000..0c7728ee0 --- /dev/null +++ b/GreenshotWin10Plugin/Native/DesktopBridgeHelpers.cs @@ -0,0 +1,53 @@ +// ****************************************************************** +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. +// ****************************************************************** + +using System.Runtime.InteropServices; +using System.Text; +using GreenshotPlugin.Core; + +namespace GreenshotWin10Plugin.Native +{ + /// + /// Code from https://github.com/qmatteoq/DesktopBridgeHelpers/edit/master/DesktopBridge.Helpers/Helpers.cs + /// + public static class DesktopBridgeHelpers + { + const long AppModelErrorNoPackage = 15700L; + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName); + + private static bool? _isRunningAsUwp; + public static bool IsRunningAsUwp() + { + if (_isRunningAsUwp != null) return _isRunningAsUwp.Value; + + if (WindowsVersion.IsWindows7OrLower) + { + _isRunningAsUwp = false; + } + else + { + int length = 0; + StringBuilder sb = new StringBuilder(0); + GetCurrentPackageFullName(ref length, sb); + + sb = new StringBuilder(length); + int result = GetCurrentPackageFullName(ref length, sb); + + _isRunningAsUwp = result != AppModelErrorNoPackage; + } + + return _isRunningAsUwp.Value; + } + } +} diff --git a/GreenshotWin10Plugin/Native/DesktopNotificationHistoryCompat.cs b/GreenshotWin10Plugin/Native/DesktopNotificationHistoryCompat.cs new file mode 100644 index 000000000..f536755ab --- /dev/null +++ b/GreenshotWin10Plugin/Native/DesktopNotificationHistoryCompat.cs @@ -0,0 +1,109 @@ +// ****************************************************************** +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. +// ****************************************************************** + +using System.Collections.Generic; +using Windows.UI.Notifications; + +namespace GreenshotWin10Plugin.Native +{ + /// + /// Manages the toast notifications for an app including the ability the clear all toast history and removing individual toasts. + /// + public sealed class DesktopNotificationHistoryCompat + { + private readonly string _applicationUserModelId; + private readonly ToastNotificationHistory _history; + + /// + /// Do not call this. Instead, call to obtain an instance. + /// + /// + internal DesktopNotificationHistoryCompat(string applicationUserModelId) + { + _applicationUserModelId = applicationUserModelId; + _history = ToastNotificationManager.History; + } + + /// + /// Removes all notifications sent by this app from action center. + /// + public void Clear() + { + if (_applicationUserModelId != null) + { + _history.Clear(_applicationUserModelId); + } + else + { + _history.Clear(); + } + } + + /// + /// Gets all notifications sent by this app that are currently still in Action Center. + /// + /// A collection of toasts. + public IReadOnlyList GetHistory() + { + return _applicationUserModelId != null ? _history.GetHistory(_applicationUserModelId) : _history.GetHistory(); + } + + /// + /// Removes an individual toast, with the specified tag label, from action center. + /// + /// The tag label of the toast notification to be removed. + public void Remove(string tag) + { + if (_applicationUserModelId != null) + { + _history.Remove(tag, string.Empty, _applicationUserModelId); + } + else + { + _history.Remove(tag); + } + } + + /// + /// Removes a toast notification from the action using the notification's tag and group labels. + /// + /// The tag label of the toast notification to be removed. + /// The group label of the toast notification to be removed. + public void Remove(string tag, string group) + { + if (_applicationUserModelId != null) + { + _history.Remove(tag, group, _applicationUserModelId); + } + else + { + _history.Remove(tag, group); + } + } + + /// + /// Removes a group of toast notifications, identified by the specified group label, from action center. + /// + /// The group label of the toast notifications to be removed. + public void RemoveGroup(string group) + { + if (_applicationUserModelId != null) + { + _history.RemoveGroup(group, _applicationUserModelId); + } + else + { + _history.RemoveGroup(group); + } + } + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs b/GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs index 703768582..a30c0ff3e 100644 --- a/GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs +++ b/GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs @@ -11,37 +11,31 @@ // ****************************************************************** using System; -using System.Collections; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; using Windows.UI.Notifications; -using GreenshotPlugin.Core; namespace GreenshotWin10Plugin.Native { - public class DesktopNotificationManagerCompat + public static class DesktopNotificationManagerCompat { public const string TOAST_ACTIVATED_LAUNCH_ARG = "-ToastActivated"; private static bool _registeredAumidAndComServer; - private static string _aumid; + private static string _applicationUserModelId; private static bool _registeredActivator; /// - /// If not running under the Desktop Bridge, you must call this method to register your AUMID with the Compat library and to + /// If not running under the Desktop Bridge, you must call this method to register your applicationUserModelId (AUMID) with the Compat library and to /// register your COM CLSID and EXE in LocalServer32 registry. Feel free to call this regardless, and we will no-op if running /// under Desktop Bridge. Call this upon application startup, before calling any other APIs. /// - /// An AUMID that uniquely identifies your application. - public static void RegisterAumidAndComServer(string aumid) - where T : NotificationActivator + /// An applicationUserModelId (AUMID) that uniquely identifies your application. + public static void RegisterAumidAndComServer(string applicationUserModelId) where T : NotificationActivator { - if (string.IsNullOrWhiteSpace(aumid)) + if (string.IsNullOrWhiteSpace(applicationUserModelId)) { - throw new ArgumentException("You must provide an AUMID.", nameof(aumid)); + throw new ArgumentException("You must provide an Application User Model Id (AUMID).", nameof(applicationUserModelId)); } // If running as Desktop Bridge @@ -50,29 +44,41 @@ namespace GreenshotWin10Plugin.Native // Clear the AUMID since Desktop Bridge doesn't use it, and then we're done. // Desktop Bridge apps are registered with platform through their manifest. // Their LocalServer32 key is also registered through their manifest. - _aumid = null; + _applicationUserModelId = null; _registeredAumidAndComServer = true; return; } - _aumid = aumid; + _applicationUserModelId = applicationUserModelId; - String exePath = Process.GetCurrentProcess().MainModule.FileName; - RegisterComServer(exePath); + string exePath = Process.GetCurrentProcess().MainModule?.FileName; + if (exePath != null) + { + RegisterComServer(exePath); + } _registeredAumidAndComServer = true; } - private static void RegisterComServer(string exePath) - where T : NotificationActivator + /// + /// Register the application an a com server + /// + /// type to register for + /// string + private static void RegisterComServer(string exePath) where T : NotificationActivator { // We register the EXE to start up when the notification is activated - string regString = $"SOFTWARE\\Classes\\CLSID\\{{{typeof(T).GUID}}}\\LocalServer32"; - var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(regString); + var guid = typeof(T).GUID; + if (guid == null) + { + throw new ArgumentException("You must provide an Guid on your NotificationActivator."); + } + string regString = $"SOFTWARE\\Classes\\CLSID\\{{{guid}}}\\LocalServer32"; + using var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(regString); // Include a flag so we know this was a toast activation and should wait for COM to process // We also wrap EXE path in quotes for extra security - key.SetValue(null, '"' + exePath + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG); + key?.SetValue(null, '"' + exePath + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG); } /// @@ -84,26 +90,23 @@ namespace GreenshotWin10Plugin.Native // Register type var regService = new RegistrationServices(); - regService.RegisterTypeForComClients( - typeof(T), - RegistrationClassContext.LocalServer, - RegistrationConnectionType.MultipleUse); + regService.RegisterTypeForComClients(typeof(T), RegistrationClassContext.LocalServer, RegistrationConnectionType.MultipleUse); _registeredActivator = true; } /// - /// Creates a toast notifier. You must have called first (and also if you're a classic Win32 app), or this will throw an exception. + /// Creates a toast notifier. You must have called first (and also if you're a classic Win32 app), or this will throw an exception. /// - /// + /// ToastNotifier public static ToastNotifier CreateToastNotifier() { EnsureRegistered(); - if (_aumid != null) + if (_applicationUserModelId != null) { // Non-Desktop Bridge - return ToastNotificationManager.CreateToastNotifier(_aumid); + return ToastNotificationManager.CreateToastNotifier(_applicationUserModelId); } // Desktop Bridge @@ -111,7 +114,7 @@ namespace GreenshotWin10Plugin.Native } /// - /// Gets the object. You must have called first (and also if you're a classic Win32 app), or this will throw an exception. + /// Gets the object. You must have called first (and also if you're a classic Win32 app), or this will throw an exception. /// public static DesktopNotificationHistoryCompat History { @@ -119,10 +122,13 @@ namespace GreenshotWin10Plugin.Native { EnsureRegistered(); - return new DesktopNotificationHistoryCompat(_aumid); + return new DesktopNotificationHistoryCompat(_applicationUserModelId); } } + /// + /// Checks if the AUMID is correctly registered, if not this throws an exception + /// private static void EnsureRegistered() { // If not registered AUMID yet @@ -153,232 +159,6 @@ namespace GreenshotWin10Plugin.Native /// /// Gets a boolean representing whether http images can be used within toasts. This is true if running under Desktop Bridge. /// - public static bool CanUseHttpImages { get { return DesktopBridgeHelpers.IsRunningAsUwp(); } } - - /// - /// Code from https://github.com/qmatteoq/DesktopBridgeHelpers/edit/master/DesktopBridge.Helpers/Helpers.cs - /// - private static class DesktopBridgeHelpers - { - const long APPMODEL_ERROR_NO_PACKAGE = 15700L; - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName); - - private static bool? _isRunningAsUwp; - public static bool IsRunningAsUwp() - { - if (_isRunningAsUwp != null) return _isRunningAsUwp.Value; - - if (WindowsVersion.IsWindows7OrLower) - { - _isRunningAsUwp = false; - } - else - { - int length = 0; - StringBuilder sb = new StringBuilder(0); - GetCurrentPackageFullName(ref length, sb); - - sb = new StringBuilder(length); - int result = GetCurrentPackageFullName(ref length, sb); - - _isRunningAsUwp = result != APPMODEL_ERROR_NO_PACKAGE; - } - - return _isRunningAsUwp.Value; - } - } - } - - /// - /// Manages the toast notifications for an app including the ability the clear all toast history and removing individual toasts. - /// - public sealed class DesktopNotificationHistoryCompat - { - private string _aumid; - private ToastNotificationHistory _history; - - /// - /// Do not call this. Instead, call to obtain an instance. - /// - /// - internal DesktopNotificationHistoryCompat(string aumid) - { - _aumid = aumid; - _history = ToastNotificationManager.History; - } - - /// - /// Removes all notifications sent by this app from action center. - /// - public void Clear() - { - if (_aumid != null) - { - _history.Clear(_aumid); - } - else - { - _history.Clear(); - } - } - - /// - /// Gets all notifications sent by this app that are currently still in Action Center. - /// - /// A collection of toasts. - public IReadOnlyList GetHistory() - { - return _aumid != null ? _history.GetHistory(_aumid) : _history.GetHistory(); - } - - /// - /// Removes an individual toast, with the specified tag label, from action center. - /// - /// The tag label of the toast notification to be removed. - public void Remove(string tag) - { - if (_aumid != null) - { - _history.Remove(tag, string.Empty, _aumid); - } - else - { - _history.Remove(tag); - } - } - - /// - /// Removes a toast notification from the action using the notification's tag and group labels. - /// - /// The tag label of the toast notification to be removed. - /// The group label of the toast notification to be removed. - public void Remove(string tag, string group) - { - if (_aumid != null) - { - _history.Remove(tag, group, _aumid); - } - else - { - _history.Remove(tag, group); - } - } - - /// - /// Removes a group of toast notifications, identified by the specified group label, from action center. - /// - /// The group label of the toast notifications to be removed. - public void RemoveGroup(string group) - { - if (_aumid != null) - { - _history.RemoveGroup(group, _aumid); - } - else - { - _history.RemoveGroup(group); - } - } - } - - /// - /// Apps must implement this activator to handle notification activation. - /// - public abstract class NotificationActivator : NotificationActivator.INotificationActivationCallback - { - public void Activate(string appUserModelId, string invokedArgs, NOTIFICATION_USER_INPUT_DATA[] data, uint dataCount) - { - OnActivated(invokedArgs, new NotificationUserInput(data), appUserModelId); - } - - /// - /// This method will be called when the user clicks on a foreground or background activation on a toast. Parent app must implement this method. - /// - /// The arguments from the original notification. This is either the launch argument if the user clicked the body of your toast, or the arguments from a button on your toast. - /// Text and selection values that the user entered in your toast. - /// Your AUMID. - public abstract void OnActivated(string arguments, NotificationUserInput userInput, string appUserModelId); - - // These are the new APIs for Windows 10 - #region NewAPIs - [StructLayout(LayoutKind.Sequential), Serializable] - public struct NOTIFICATION_USER_INPUT_DATA - { - [MarshalAs(UnmanagedType.LPWStr)] - public string Key; - - [MarshalAs(UnmanagedType.LPWStr)] - public string Value; - } - - [ComImport, - Guid("53E31837-6600-4A81-9395-75CFFE746F94"), ComVisible(true), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface INotificationActivationCallback - { - void Activate( - [In, MarshalAs(UnmanagedType.LPWStr)] - string appUserModelId, - [In, MarshalAs(UnmanagedType.LPWStr)] - string invokedArgs, - [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] - NOTIFICATION_USER_INPUT_DATA[] data, - [In, MarshalAs(UnmanagedType.U4)] - uint dataCount); - } - #endregion - } - - /// - /// Text and selection values that the user entered on your notification. The Key is the ID of the input, and the Value is what the user entered. - /// - public class NotificationUserInput : IReadOnlyDictionary - { - private NotificationActivator.NOTIFICATION_USER_INPUT_DATA[] _data; - - internal NotificationUserInput(NotificationActivator.NOTIFICATION_USER_INPUT_DATA[] data) - { - _data = data; - } - - public string this[string key] => _data.First(i => i.Key == key).Value; - - public IEnumerable Keys => _data.Select(i => i.Key); - - public IEnumerable Values => _data.Select(i => i.Value); - - public int Count => _data.Length; - - public bool ContainsKey(string key) - { - return _data.Any(i => i.Key == key); - } - - public IEnumerator> GetEnumerator() - { - return _data.Select(i => new KeyValuePair(i.Key, i.Value)).GetEnumerator(); - } - - public bool TryGetValue(string key, out string value) - { - foreach (var item in _data) - { - if (item.Key == key) - { - value = item.Value; - return true; - } - } - - value = null; - return false; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + public static bool CanUseHttpImages => DesktopBridgeHelpers.IsRunningAsUwp(); } } \ No newline at end of file diff --git a/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs b/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs index 74922476f..d2da5f4c9 100644 --- a/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs +++ b/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs @@ -24,7 +24,9 @@ using log4net; namespace GreenshotWin10Plugin.Native { - // The GUID CLSID must be unique to your app. Create a new GUID if copying this code. + /// + /// This implements the NotificationActivator + /// [ClassInterface(ClassInterfaceType.None)] [ComSourceInterfaces(typeof(INotificationActivationCallback))] [Guid("F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08"), ComVisible(true)] diff --git a/GreenshotWin10Plugin/Native/INotificationActivationCallback.cs b/GreenshotWin10Plugin/Native/INotificationActivationCallback.cs new file mode 100644 index 000000000..59dd61443 --- /dev/null +++ b/GreenshotWin10Plugin/Native/INotificationActivationCallback.cs @@ -0,0 +1,35 @@ +// ****************************************************************** +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. +// ****************************************************************** + +using System.Runtime.InteropServices; +using GreenshotWin10Plugin.Native.Structs; + +namespace GreenshotWin10Plugin.Native +{ + /// + /// This is the interface which allows your notifications to be clicked, which active the application + /// + [ComImport, Guid("53E31837-6600-4A81-9395-75CFFE746F94"), + ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface INotificationActivationCallback + { + void Activate( + [In, MarshalAs(UnmanagedType.LPWStr)] + string appUserModelId, + [In, MarshalAs(UnmanagedType.LPWStr)] + string invokedArgs, + [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] + NotificationUserInputData[] data, + [In, MarshalAs(UnmanagedType.U4)] + uint dataCount); + } +} diff --git a/GreenshotWin10Plugin/Native/NotificationActivator.cs b/GreenshotWin10Plugin/Native/NotificationActivator.cs new file mode 100644 index 000000000..bedf3f5f4 --- /dev/null +++ b/GreenshotWin10Plugin/Native/NotificationActivator.cs @@ -0,0 +1,35 @@ +// ****************************************************************** +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. +// ****************************************************************** + +using GreenshotWin10Plugin.Native.Structs; + +namespace GreenshotWin10Plugin.Native +{ + /// + /// Apps must implement this activator to handle notification activation. + /// + public abstract class NotificationActivator : INotificationActivationCallback + { + public void Activate(string appUserModelId, string invokedArgs, NotificationUserInputData[] data, uint dataCount) + { + OnActivated(invokedArgs, new NotificationUserInput(data), appUserModelId); + } + + /// + /// This method will be called when the user clicks on a foreground or background activation on a toast. Parent app must implement this method. + /// + /// The arguments from the original notification. This is either the launch argument if the user clicked the body of your toast, or the arguments from a button on your toast. + /// Text and selection values that the user entered in your toast. + /// Your AUMID. + public abstract void OnActivated(string arguments, NotificationUserInput userInput, string appUserModelId); + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Native/NotificationUserInput.cs b/GreenshotWin10Plugin/Native/NotificationUserInput.cs new file mode 100644 index 000000000..57b184c70 --- /dev/null +++ b/GreenshotWin10Plugin/Native/NotificationUserInput.cs @@ -0,0 +1,70 @@ +// ****************************************************************** +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. +// ****************************************************************** + +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using GreenshotWin10Plugin.Native.Structs; + +namespace GreenshotWin10Plugin.Native +{ + /// + /// Text and selection values that the user entered on your notification. The Key is the ID of the input, and the Value is what the user entered. + /// + public class NotificationUserInput : IReadOnlyDictionary + { + private readonly NotificationUserInputData[] _notificationUserInputData; + + internal NotificationUserInput(NotificationUserInputData[] notificationUserInputData) + { + _notificationUserInputData = notificationUserInputData; + } + + public string this[string key] => _notificationUserInputData.First(i => i.Key == key).Value; + + public IEnumerable Keys => _notificationUserInputData.Select(i => i.Key); + + public IEnumerable Values => _notificationUserInputData.Select(i => i.Value); + + public int Count => _notificationUserInputData.Length; + + public bool ContainsKey(string key) + { + return _notificationUserInputData.Any(i => i.Key == key); + } + + public IEnumerator> GetEnumerator() + { + return _notificationUserInputData.Select(i => new KeyValuePair(i.Key, i.Value)).GetEnumerator(); + } + + public bool TryGetValue(string key, out string value) + { + foreach (var item in _notificationUserInputData) + { + if (item.Key == key) + { + value = item.Value; + return true; + } + } + + value = null; + return false; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Native/Structs/NotificationUserInputData.cs b/GreenshotWin10Plugin/Native/Structs/NotificationUserInputData.cs new file mode 100644 index 000000000..357aaa378 --- /dev/null +++ b/GreenshotWin10Plugin/Native/Structs/NotificationUserInputData.cs @@ -0,0 +1,30 @@ +// ****************************************************************** +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. +// ****************************************************************** + +using System; +using System.Runtime.InteropServices; + +namespace GreenshotWin10Plugin.Native.Structs +{ + /// + /// See NOTIFICATION_USER_INPUT_DATA structure + /// + [StructLayout(LayoutKind.Sequential), Serializable] + public struct NotificationUserInputData + { + [MarshalAs(UnmanagedType.LPWStr)] + public string Key; + + [MarshalAs(UnmanagedType.LPWStr)] + public string Value; + } +} diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/GreenshotWin10Plugin/ToastNotificationService.cs index 05d930bc8..4af060bf9 100644 --- a/GreenshotWin10Plugin/ToastNotificationService.cs +++ b/GreenshotWin10Plugin/ToastNotificationService.cs @@ -44,7 +44,7 @@ namespace GreenshotWin10Plugin public ToastNotificationService() { // Register AUMID and COM server (for Desktop Bridge apps, this no-ops) - DesktopNotificationManagerCompat.RegisterAumidAndComServer("Greenshot.Greenshot"); + DesktopNotificationManagerCompat.RegisterAumidAndComServer("Greenshot"); // Register COM server and activator type DesktopNotificationManagerCompat.RegisterActivator(); @@ -68,9 +68,10 @@ namespace GreenshotWin10Plugin /// This creates the actual toast /// /// string + /// milliseconds until the toast timeouts /// Action called when clicked /// Action called when the toast is closed - private void ShowMessage(string message, Action onClickAction, Action onClosedAction) + private void ShowMessage(string message, int timeout, Action onClickAction, Action onClosedAction) { // Do not inform the user if this is disabled if (!CoreConfiguration.ShowTrayNotification) @@ -104,7 +105,11 @@ namespace GreenshotWin10Plugin } // Create the toast and attach event listeners - var toast = new ToastNotification(toastXml); + var toast = new ToastNotification(toastXml) + { + ExpiresOnReboot = true, + ExpirationTime = timeout > 0 ? DateTimeOffset.Now.AddMilliseconds(timeout) : (DateTimeOffset?)null + }; void ToastActivatedHandler(ToastNotification toastNotification, object sender) { @@ -155,17 +160,17 @@ namespace GreenshotWin10Plugin public void ShowWarningMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) { - ShowMessage(message, onClickAction, onClosedAction); + ShowMessage(message, timeout, onClickAction, onClosedAction); } public void ShowErrorMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) { - ShowMessage(message, onClickAction, onClosedAction); + ShowMessage(message, timeout, onClickAction, onClosedAction); } public void ShowInfoMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) { - ShowMessage(message, onClickAction, onClosedAction); + ShowMessage(message, timeout, onClickAction, onClosedAction); } } } From 5fbd6052390a3f541972956572602e63d634e453 Mon Sep 17 00:00:00 2001 From: Robin Date: Fri, 27 Mar 2020 08:57:38 +0100 Subject: [PATCH 007/232] Backport of language changes from #160 for the next 1.x release [skip ci] --- Greenshot/Languages/help-pt-BR.html | 461 ++++++++++++++++++ Greenshot/Languages/language-pt-BR.xml | 165 +++++-- .../website/language-website-pt-BR.xml | 19 + 3 files changed, 603 insertions(+), 42 deletions(-) create mode 100644 Greenshot/Languages/help-pt-BR.html create mode 100644 Greenshot/Languages/website/language-website-pt-BR.xml diff --git a/Greenshot/Languages/help-pt-BR.html b/Greenshot/Languages/help-pt-BR.html new file mode 100644 index 000000000..4c1c913a1 --- /dev/null +++ b/Greenshot/Languages/help-pt-BR.html @@ -0,0 +1,461 @@ + + + + Greenshot Help + + + + +

Ajuda do Greenshot

+ + Verso 1.0 + Traduo Portugus do Brasil por JNylson (nylsinho_ba@hotmail.com) + +

Contedo

+
    +
  1. Criar uma captura de tela
  2. +
      +
    1. Capturar uma regio
    2. +
    3. Capturar a ltima regio
    4. +
    5. Capturar janela
    6. +
    7. Capturar a tela inteira
    8. +
    9. Capturar Internet Explorer
    10. +
    + +
  3. Usar o editor de imagem
  4. +
      +
    1. Desenhar formas
    2. +
    3. Adicionar texto
    4. +
    5. Realar coisas
    6. +
    7. Ofuscar coisas
    8. +
    9. Adicionar efeitos
    10. +
    11. Recortar a captura de tela
    12. +
    13. Adicionar grficos a uma captura
    14. +
    15. Reutilizar elementos desenhados
    16. +
    17. Exportar a captura
    18. +
    +
  5. Configuraes
  6. +
      +
    1. Configuraes gerais
    2. +
    3. Configuraes de captura
    4. +
    5. Configuraes de sada
    6. +
    7. Configuraes de destino
    8. +
    9. Configuraes de impresso
    10. +
    11. Configuraes avanadas
    12. +
    +
  7. Quer ajudar?
  8. +
      +
    1. Faa uma doao
    2. +
    3. Espalhe a palavra
    4. +
    5. Envie uma traduo
    6. +
    +
+ + +

Criar uma captura de tela

+

+ Pode criar uma captura de tela ou usando a tecla Print do seu teclado + ou clicando com o boto direito do mouse no cone Greenshot da bandeja do sistema.
+ Existem diversas opes para criar uma captura de tela: +

+ + +

Capturar regio Print

+

+ O modo de capturar uma regio permite-lhe selecionar uma parte da tela a ser capturada.
+ Aps iniciar o modo regio, ir visualizar uma mira a apontar a posio do mouse + no tela. Clique e mantenha o boto pressionado no local onde pretende que fique um dos cantos + da sua captura. Mantendo o boto do mouse pressionado, arraste o mouse para definir o + retngulo a ser capturado. Quando o retngulo verde cobrir a rea que pretende + capturar, solte o boto do mouse. +

+

+ Pode usar a tecla Space para alternar entre o modo regio e o modo + janela. +

+

+ Se pretende capturar uma rea exata, ser mais fcil selecionar a rea inicial da + captura um pouco maior e depois recortar a captura de tela + usando o editor de imagem do Greenshot. +

+ + +

Capturar a ltima regio Shift + Print

+

+ Se acabou de capturar uma regio ou uma janela, + pode capturar novamente a mesma regio usando esta opo. +

+ + +

Capturar uma janela Alt + Print

+

+ Cria uma captura da janela que est atualmente ativa. +

+

+ Para sistemas com o Windows 7 ou Vista, use a configurao do modo Captura de Janela para controlar + como o Greenshot manipula as bordas da janela semi transparente (Aero), p.e. substituindo a + transparncia com uma cor personalizada. +

+

+ O dilogo de configuraes oferece uma opo de no capturar + a janela ativa de imediato, mas permitindo-lhe selecionar uma interativamente. + Se esta opo for selecionada, pode selecionar uma janela clicando nela (Tal como no + modo regio, o Greenshot ir realar a rea que + ir ser capturada).
Se pretender capturar uma janela secundria (p.e. uma janela do + navegador (sem barras de ferramentas, etc.) ou um simples quadro de uma pgina web que use 'framesets') + aponte o cursor do mouse para a janela e pressione a tecla PgDown. Depois de + fazer isso, pode selecionar elementos secundrios da janela para serem capturados. +

+

+ A captura dos menus de contexto diferente: ao usar o atalho "Capturar janela" + far desaparecer o menu de contexto, e obviamente acontecer o mesmo se usar + o menu de contexto do Greenshot para criar a captura. Se pretende capturar + um menu de contexto que faz surgir clicando com o boto direito do mouse em qualquer coisa, + simplesmente ativa o modo regio Print, e depois pressione a tecla Space. +

+ + +

Capturar tela completo Control + Print

+

+ Cria uma captura da totalidade da tela. +

+ + +

Capturar Internet Explorer Control + Shift + Print

+

+ Cria confortavelmente uma captura da pgina web atualmente aberta no Internet Explorer. + Use o menu de contexto do Greenshot para selecionar o separador do Internet Explorer a capturar, ou pressione + Crtl + Shift + Print para capturar a aba ativa. +

+ + + +

Usar o editor de imagem

+

+ O Greenshot possui um editor de imagem fcil de usar, fornecendo uma srie de funcionalidades + para adicionar anotaes e formas a uma captura. Ele tambm permite realar ou + ofuscar partes da sua captura. +

+

+ O editor de imagem do Greenshot pode ser usado no apenas em capturas. Tambm pode + abrir imagens de um arquivo ou da rea de transferncia para editar. Basta clicar com o boto + direito do mouse no cone do Greenshot na bandeja do sistema e selecionar Abrir imagem de arquivo + ou Abrir imagem da rea de transferncia, respectivamente. +

+

+ Por padro, o editor de imagem aberto sempre que feita uma captura de tela. + Se no pretender usar o editor de imagem, pode desativar esta + funcionalidade no dilogo configuraes. +

+ + + +

Desenhar formas

+

+ Selecione uma das ferramentas de desenho de formas na barra de ferramentas situada do lado + esquerdo do editor de imagem ou do menu Objeto. Para sua convenincia, tambm existe + uma tecla associada a cada ferramenta.
+ As formas disponveis so: retngulo R, elipse E, linha L, + seta A e de linha livre F.
+ Clique, mantenha pressionado o boto do mouse e arraste para definir a posio e tamanho da forma. + Solte o boto do mouse quando tiver terminado. +

+

+ Pode mover ou redimensionar as formas existentes com a ferramenta de seleo + ESC da barra de ferramentas.
Para cada tipo de elemento existe um conjunto + prprio de opes disponveis para alterar o aspecto do elemento.(p.e. espessura da linha, + cor da linha, cor de preenchimento). Pode alterar as opes de um elemento existente depois + de selecion-lo, mas tambm para o prximo elemento a ser desenhado aps selecionar uma ferramenta de desenho. +

+

+ Pode selecionar vrios elementos para editar ao mesmo tempo. Para selecionar vrios + elementos, mantenha pressionada a tecla Shift enquanto clica nos elementos. +

+

+ Se pretende desenhar formas com lados iguais (p.e. forar um retngulo a ser quadrado) mantenha + pressionada a tecla Shift ao desenhar. Ao desenhar linhas ou setas, manter pressionada a tecla Shift + resulta no ngulo da linha ser rodado em passos de 15.
+ Pode tambm usar o Shift se pretender redimensionar um objeto existente mantendo as suas propores. +

+

+ Ao desenhar ou redimensionar, pode manter pressionada a tecla Ctrl para ter o objeto ancorado + no seu centro geomtrico. P.e. o objeto tambm redimensionado na direo oposta. (Isto + muito til se pretende desenhar uma elipse volta de qualquer coisa na sua captura.) +

+ + +

Adicionar texto

+

+ o uso da ferramenta texto T semelhante das ferramentas de + forma. Desenhe simplesmente o elemento de texto do + tamanho desejado, depois digite o texto no seu interior.
+ Faa duplo clique num elemento de texto existente para editar o seu contedo.
+ Pressione Return ou Enter quando tiver concludo a edio. +

+

+ Se necessita inserir quebras de linha dentro de uma caixa de texto, pressione Shift + Return ou + Shift + Enter. +

+ + +

Realar coisas

+

+ Aps selecionar a ferramenta de realar H, pode definir a rea para ser + realada do mesmo modo como desenharia uma forma.
+ Existem diversas opes para realar, entre as quais pode escolher clicando no + boto mais esquerda da barra de ferramentas na parte superior: +

+
    +
  • Realar texto: reala uma rea aplicando-lhe uma cor brilhante, como + os marcadores de texto usados no escritrio
  • +
  • Realar rea: desfoca* e escurece tudo fora da rea selecionada
  • +
  • Escala Cinza: tudo o que est fora da rea selecionada ficar na escala cinza
  • +
  • Ampliar: a rea selecionada ser exibida com ampliao
  • +
+ + +

Ofuscar coisas

+

+ Ofuscar partes de uma captura uma boa ideia se contiver dados que no se pretende que sejam + vistos por outras pessoas, p.e. dados de contas bancrias, nomes, senhas ou rostos na imagem.
+ Use a ferramenta ofuscar O exatamente do mesmo modo que a de realar. +
+ As opes disponveis para ofuscao so: +

+
    +
  • Pixelizar: aumenta o tamanho do pixeis na rea selecionada
  • +
  • Desfocar*: desfoca a rea selecionada
  • +
+ +

+ * Dependendo do desempenho do seu computador, a aplicao do efeito desfocar pode tornar lento + o editor de imagens do Greenshot. Se notar que o editor de imagem reage com lentido logo que + o efeito aplicado, tente reduzir o valor para a Qualidade de Pr-visualizao + na barra de ferramentas ou reduza o valor do Raio de desfocagem.
+ Se o desempenho de desfoque continuar mau para poder trabalhar com ele, deve optar por + usar o efeito Pixelizar. +

+ +

Adicionar efeitos

+

+ Pode adicionar diferentes efeitos sua captura. Pode querer aplicar uma borda, sombra ou efeito + de cantos arredondados, p.e. para visualizar em separado a sua captura do restante contedo do documento. + Os efeitos Escala Cinza e Inverter so teis principalmente antes de imprimir, poupando tinta ou toner + ao imprimir capturas coloridas ou escuras. +

+ + +

Recortar a Captura

+

+ Se precisa apenas de uma parte da imagem que capturou, use a ferramenta de recorte C + para recort-la para a rea desejada.
+ Aps selecionar a ferramenta recortar, desenhe um retngulo na rea da captura que quer + manter. Pode redimensionar a rea selecionada como qualquer outro elemento.
+ Quando estiver satisfeito com a sua seleo, use o boto confirmar da barra de ferramentas ou + pressione a tecla Enter. Pode cancelar o recorte clicando no boto cancelar ou pressionando + ESC. +

+

+ Recorte Automtico: Se necessita recortar uma borda de uma cor slida de fundo da sua + captura escolha simplesmente Recorte Automtico do menu Editar e o Greenshot + ir selecionar automaticamente a rea para recortar. +

+ + +

+ Use as ferramentas de rotao para girar a captura no sentido horrio ou anti-horrio. +

+ + +

Adicionar grficos a uma captura

+

+ Pode muito simplesmente adicionar grficos ou imagens sua captura arrastando e soltando um + arquivo de imagem na janela do editor. Pode tambm inserir capturas de outras janelas selecionando + Inserir janela do menu Editar. Surge uma lista com todas as janelas abertas, + permitindo-lhe selecionar uma para ser inserida. +

+ + +

Reutilizar elementos de desenho

+

+ Se estiver a usar os mesmos ou elementos semelhantes na maioria das capturas + (p.e. um campo de texto contendo o tipo de navegador e a verso, ou a ofuscar o mesmo + elemento em vrias capturas) pode reutilizar os elementos.
+ Selecione Salvar objetos para arquivo do menu Objetos para + salvar o conjunto atual de elementos e reutiliz-los mais tarde. Carregar objetos de arquivo + aplica os mesmos elementos a outra captura. +

+ + +

Exportar a captura

+

+ Aps editar a captura, pode exportar o resultado para diversos fins, dependendo das + suas necessidades. Pode aceder a todas as opes de exportao atravs do menu Arquivo, + da barra de ferramentas superior ou via teclas de atalho: +

+
    +
  • Salvar Control + S: salva a imagem para um arquivo (se a imagem j tiver sido guardada, exibe o dilogo Salvar como...
  • +
  • Salvar como... Control + Shift + S: deixa-o escolher a localizao, nome do arquivo e formato da imagem para o arquivo a salvar
  • +
  • Copiar imagem para a rea de transferncia Control + Shift + C: coloca uma cpia da imagem na rea de transferncia, permitindo colar em outros programas
  • +
  • Imprimir... Control + P: envia a imagem para uma impressora
  • +
  • E-Mail Control + E: abre uma nova mensagem no cliente de e-mail padro, adicionando a imagem como anexo
  • +
+

+ Existem plugins para exportar capturas para outros destinos, e.g. DropBox, Google Photos, Flickr. Deve + selecionar os plugins apropriados durante o processo de instalao. +

+

+ Aps salvar uma imagem do editor, clique com o boto direito do mouse na barra de estado + na parte inferior da janela do editor para copiar o atalho do arquivo para a rea de transferncia + ou abrir a pasta respectiva no Explorador do Windows. +

+ + + +

O Dilogo Configuraes

+ + +

Configuraes Gerais

+
    +
  • Idioma: O idioma preferido a usar.
    + Pode transferir arquivos de idiomas adicionais para o Greenshot aqui.
  • +
  • Iniciar o Greenshot no inicializao: Inicia o programa no inicializao do sistema.
  • +
  • Teclas de Atalho: Personaliza as teclas de atalho a serem usadas para criar capturas.
  • +
  • Usar proxy padro do sistema: Se selecionado, o Greenshot usa proxy padro do sistema para procurar atualizaes.
  • +
  • Intervalo de procura de atualizaes em dias: O Greenshot pode procurar atualizaes automaticamente. Use esta configurao para ajustar o + intervalo (em dias) ou defina-o para 0 para desligar a procura de atualizaes.
  • +
+ + +

Configuraes de Captura

+
    +
  • Capturar cursor do mouse: Se selecionada, o cursor do mouse ser capturado. O cursor tratado no editor como um elemento separado, por isso pode mov-lo ou remov-lo mais tarde.
  • +
  • Reproduzir som de Cmara: Som audvel ao fazer a captura
  • +
  • Milissegundos de espera antes da captura: Adiciona um tempo de atraso personalizado antes de capturar realmente a tela.
  • +
  • Usar modo de captura janela interativa: Em vez de capturar a janela ativa de imediato, o modo interativo permite-lhe + selecionar a janela a capturar. Tambm possvel capturar janelas secundrias, ver captura de janela.
  • +
  • + Captura estilo Aero (apenas Windows Vista / 7): Se estiver a usar o Greenshot no Windows Vista ou Windows 7 com janelas estilo aero ativado, pode + escolher como sero tratadas as bordas transparentes da janela ao criar uma captura em modo janela. Use esta configurao para evitar capturar elementos do + fundo a brilhar atravs das bordas transparentes. +
      +
    • Auto: Deixa o Greenshot decidir como tratar a transparncia.
    • +
    • Como exibida: As bordas transparentes so capturadas tal como exibidas na tela.
    • +
    • Usar cor padro: aplicada uma cor slida padro em vez da transparncia.
    • +
    • Usar cor personalizada: Selecione uma cor slida para ser aplicada em vez da transparncia.
    • +
    • Preservar transparncia: As bordas so capturadas mantendo a transparncia, no capturando elementos que possam estar no fundo. (Nota: as reas + transparentes sero exibidas usando um padro selecionado no editor. O padro no exportado ao salvar a captura para um arquivo. Lembre-se de salvar + como arquivo PNG para suporte completo da transparncia.)
    • +
    +
  • +
  • Capturar Internet Explorer: Permite a captura confortvel de pgina web com o Internet Explorer.
  • +
  • Redimensionar a janela do editor ao tamanho da captura: Se selecionado, a janela do editor ser redimensionada automaticamente para o tamanho da captura.
  • + +
+ + +

Configuraes de Sada

+
    +
  • Destino da captura: Permite-lhe escolher o(s) destino(s) para a sua captura imediatamente aps faze-la.
  • +
  • Configuraes preferidas do arquivo de sada: Pasta e nome de arquivo a ser usado ao salvar diretamente ou para ser sugerido ao salvar (usando o dilogo Salvar como). Clique no boto ? para aprender mais sobre os marcadores que podem ser usados como padro de nome de arquivo.
  • +
  • Configuraes JPEG: Qualidade a ser usada ao salvar arquivos JPEG
  • +
+ + +

Configuraes de Destino

+

+ Por padro, o Greenshot deixa-o selecionar dinamicamente um destino aps criar a captura, exibindo um pequeno + menu com diferentes destinos sua escolha. Se no quer ou no necessita de estar sempre a alterar os destinos, + pode preferir configurar o Greenshot para exportar diretamente para um ou mais destinos, sem exibir o dilogo de + seleco dos destinos.
+ Nota: tal como exportar da janela do editor, os destinos exibidos variam + dependendo dos plugins que tem instalados com o Greenshot. +

+ + +

Configuraes de impresso

+
    +
  • Reduzir impresso para caber no tamanho do papel: Se a imagem exceder o tamanho do papel, ser reduzida para caber na pgina.
  • +
  • Ampliar impresso para caber no tamanho do papel: Se a imagem for mais pequena do que o tamanho do papel, ser dimensionada para ser impressa to grande quanto possvel sem exceder o tamanho do papel.
  • +
  • Rodar impresso para orientao da pgina: A imagem de formato paisagem ser rodada 90° para impresso.
  • +
  • Imprimir com cores invertidas: A captura ser invertida antes de ser impressa, til p.e. ao imprimir uma captura de texto branco em fundo preto (para poupar toner/tinta).
  • +
  • Forar impresso em escala cinza: As cores sero convertidas para a escala cinza antes de imprimir.
  • +
+ + +

Configuraes de Plugins

+

+ Exibe uma lista de plugins do Greenshot instalados. Selecione um da lista e clique Configurar para acessar configurao de um plugin. +

+ + +

Configuraes avanadas

+

+ Queremos dizer: melhor no alterar nada aqui se no souber o que est fazendo, pois estas configuraes podem provocar comportamentos inesperados. +

+ + + +

Quer ajudar?

+ +

+ De momento, no precisamos de ajuda no desenvolvimento. Contudo, h vrias coisas que + pode fazer para ajudar o Greenshot e a equipe de desenvolvimento.
+ Antecipadamente obrigado :) +

+ + +

Faa uma doao

+

+ Estamos investindo muito trabalho no Greenshot e gastando bastante tempo para fornecer + um bom software gratuito e de cdigo aberto. Se acha que + isso o torna mais produtivo, e lhe poupa (ou sua empresa) + muito tempo e dinheiro, ou se simplesmente gosta do Greenshot e + da ideia de software de cdigo aberto: por favor considere compensar o nosso esforo, doando.
+ Por favor visite a nossa pgina web para ver como pode apoiar a equipe de desenvolvimento do Greenshot:
+ http://getgreenshot.org/support/ +

+ + +

Espalhe a palavra

+

+ Se gosta do Greenshot, deixe que as pessoas saibam: Fale sobre o Greenshot aos seus amigos e colegas. + Os seus seguidores, tambm :)
+ Classifique o Greenshot nos portais de software ou tenha um link da nossa pgina no seu blog ou site. +

+ + +

Envie uma traduo

+

+ O Greenshot no est disponvel no seu idioma preferido? Se acha que pode traduzir + uma pea de software, mais do que bem-vindo. + Se um usurio registado no sourceforge.net, pode enviar tradues para o nosso + monitor de tradues.
+ Por favor certifique-se de que no existe traduo para o seu idioma na nossa + pgina de downloads. Veja tambm no nosso monitor de tradues, + se existe alguma traduo a decorrer, ou pelo menos em discusso.
+ Tenha em ateno que s disponibilizaremos uma traduo na nossa pgina de downloads se ela + tiver sido enviada atravs da sua conta no sourceforge.net. Uma vez que o mais provvel ns + no sermos capazes de perceber a sua traduo, bom que outros utilizadores do sourceforge + tenham possibilidade de contact-lo sobre de aperfeioamentos no caso de nova verso do Greenshot. +

+ + + + + diff --git a/Greenshot/Languages/language-pt-BR.xml b/Greenshot/Languages/language-pt-BR.xml index efeee419a..4f379ae80 100644 --- a/Greenshot/Languages/language-pt-BR.xml +++ b/Greenshot/Languages/language-pt-BR.xml @@ -5,22 +5,33 @@ Se você gostou do Greenshot, por favor contribua: O Greenshot está armazenado no GitHub em Ícones de Yusuke Kamiyamane (Biblioteca Fugue, licença "Creative Commons Attribution 3.0") - Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom -O Greenshot não tem NENHUMA GARANTIA. Este software gratuito pode ser redistribuido sob algumas condições. -Detalhes sobre a licença GNU: + + Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + O Greenshot não tem NENHUMA GARANTIA. Este software gratuito pode ser redistribuído sob algumas condições. + Detalhes sobre a licença GNU: + Sobre o Greenshot Greenshot - O revolucionário Utilitário de Captura de Tela Fechar - Desculpe, ocorreu um erro inesperado. + + Desculpe, ocorreu um erro inesperado. -A boa notícia é: você pode nos ajudar a corrigir o problema nos enviando uma descrição do erro. -Por favor visite a URL abaixo, crie um novo reporte de erro e cole o conteúdo da área de texto na descrição do erro. + A boa notícia é: você pode nos ajudar a corrigir o problema nos enviando uma descrição do erro. + Por favor visite a URL abaixo, crie um novo reporte de erro e cole o conteúdo da área de texto na descrição do erro. -Por favor adicione um resumo significativo do erro, além de qualquer informação que considere útil para a reprodução o problema. -Também apreciaremos muito se você puder verificar se já não existe um reporte de erro para este problema. (Você pode usar a opção de busca para encontrar rapidamente.) Obrigado :) + Por favor adicione um resumo significativo do erro, além de qualquer informação que considere útil para a reprodução o problema. + Também apreciaremos muito se você puder verificar se já não existe um reporte de erro para este problema. (Você pode usar a opção de busca para encontrar rapidamente.) Obrigado :) + Erro + Cancelar Um erro inesperado ocorreu ao tentar escrever na área de transferência. O Greenshot não conseguiu escrever na área de transferência porque o processo {0} bloqueou o acesso. + Não foi possível encontrar uma imagem na área de transferência. + Windows Bitmap + Device independent Bitmap (DIB) + HTML + HTML com imagens inline + PNG Alfa Aplicar Azul @@ -30,19 +41,34 @@ Também apreciaremos muito se você puder verificar se já não existe um report Vermelho Seletor de Cores Transparência - Não foi possível salvar o arquivo de configuração do Greenshot. Por favor verifique as permissões de acceso a '{0}'. + O destino {0} rejeitou acesso do Greenshot, provavelmente um diálogo está aberta. Feche o diálogo e tente novamente. + Acesso ao Greenshot rejeitado + Não foi possível salvar o arquivo de configuração do Greenshot. Por favor verifique as permissões de acesso a '{0}'. Sobre o Greenshot Capturar região - Abrir imagen da área de transferência + Abrir imagem da área de transferência Capturar a tela inteira + todos + inferior + esquerda + direita + superior + Capturar Internet Explorer + Capturar Internet Explorer da lista Capturar a última região Capturar tela + Capturar janela da lista Suporte do Greenshot Sair Ajuda Abrir imagem do arquivo + Abrir último local capturado Preferências rápidas Preferências... + Erro ao exportar para {0}. Por favor, tente novamente. + Outlook com HTML + Outlook com texto + Abrir imagem no editor Organizar Ponta das setas Em ambos @@ -113,82 +139,137 @@ Também apreciaremos muito se você puder verificar se já não existe um report Trazer para frente Erro Uma instância do Greenshot já está sendo executada. - Não foi possível salvar o arquivo em {0}. -Por favor verifique o caminho selecionado para o armazenamento. - O arquivo "{0}" não põde ser aberto. + + Não foi possível salvar o arquivo em {0}. + Por favor verifique o caminho selecionado para o armazenamento. + + O arquivo "{0}" não pode ser aberto. O link '{0}' não pode ser aberto. A tela capturada não pôde ser salva, por favor encontre um local adequado. + O nome do arquivo ou nome do diretório gerado não é válido. Corrija o padrão de nome de arquivo e tente novamente. + Especialista + Criar uma imagem de 8 bits se as cores são menos de 256, tendo um > imagem de 8 bits + Verificar atualizações instáveis + Formatos da área de transferência + O número para ${NUM} no padrão de nome de arquivo + Eu sei o que estou fazendo! + Rodapé padrão de impressão + Minimizar footprint de memória, mas com uma penalidade de desempenho (não recomendado). + Faça algumas otimizações para usar com computador remoto + Reutilizar editor se possível + Suprimir o diálogo salvar ao fechar o editor + Mostrar miniaturas de janelas no menu de contexto (para Vista e windows 7) + Exportado to: {0} + Ocorreu um erro ao exportar para {0}: Ajuda do Greenshot + Teclas de atalho Por favor selecione a qualidade desejada para a imagem JPEG. Salvar esta qualidade JPEG como padrão e não perguntar novamente Qualidade Greenshot para JPEG + Ok Ocorreu um erro ao se tentar imprimir. Centralizar a impressão na página Aumentar o tamanho da impressão para ocupar toda a página Rotacionar a impressão de acordo com a orientação da página Diminuir o tamanho da impressão para caber na página + configurações de cor Salvar as opções como padrão e não perguntar de novo + Imprimir com cores invertidas + Configurações de layout da página + Impressão colorida + Forçar impressão em tons de cinza + Forçar impressão preto / branco Imprimir data / hora na parte inferior da página - Opçoes de impressão do Greenshot - Salvar diretamente (Usando a configuração padrão para arquivos de captura) - Perguntar a qualidade do JPEG toda vez que uma imagem for salva + Opções de impressão do Greenshot + Salvar com qualidade padrão e não perguntar novamente + Qualidade do Greenshot + Salvar diretamente (Usando configuração padrão para arquivos capturados) Mostrar as opções de impressão toda vez que uma imagem for impressa + Perguntar a qualidade do JPEG toda vez que uma imagem for salva Configurações da Aplicação Executar o Greenshot ao iniciar o Windows Captura Capturar também o cursor do mouse Usar modo interativo + intervalo de verificação de atualização em dias (0=sem verificar) + Configurar Copiar o caminho completo do arquivo para a Área de transferência Destino da tela capturada Área de transferência - Abrir imagem no editor Enviar por e-mail Salvar em um arquivo Salvar como... (mostrar caixa de diálogo) + Selecione o destino dinamicamente Enviar para impressora + Editor Formato do nome Geral - Qualidade do JPEG - Configurações para JPEG + Qualidade JPEG + Configurações JPEG Idioma - Os seguientes marcadores de posição serão substituídos automaticamente pelo formato definido: -${YYYY} ano, 4 dígitos -${MM} mês, 2 dígitos -${DD} dia, 2 dígitos -${hh} hora, 2 dígitos -${mm} minuto, 2 dígitos -${ss} segundo, 2 dígitos -${NUM} número incremental, 6 dígitos -${title} Título da janela -${user} Usuário do Windows -${domain} Domínio de Windows -${hostname} Nome do Computador + + Os seguientes marcadores de posição serão substituídos automaticamente pelo formato definido: + ${YYYY} ano, 4 dígitos + ${MM} mês, 2 dígitos + ${DD} dia, 2 dígitos + ${hh} hora, 2 dígitos + ${mm} minuto, 2 dígitos + ${ss} segundo, 2 dígitos + ${NUM} número incremental, 6 dígitos + ${title} Título da janela + ${user} Usuário do Windows + ${domain} Domínio do Windows + ${hostname} Nome do Computador -Você também pode fazer o Greenshot criar diretórios dinamicamente, simplesmente usando o símbolo de barra invertida (\) para separar diretórios e nome de arquivo. -Exemplo: o formato ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} -irá gerar um diretório para o dia atual dentro do caminho de armazenamento padrão, exemplo: 2008-06-29, os nomes das telas capturadas serão baseados na -hora atual, ejemplo: 11_58_32 (mais a extensão definida nas configurações de preferência) + Você também pode fazer o Greenshot criar diretórios dinamicamente, simplesmente usando o símbolo de barra invertida (\) para separar diretórios e nome de arquivo. + Exemplo: o formato ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} + irá gerar um diretório para o dia atual dentro do caminho de armazenamento padrão, exemplo: 2008-06-29, os nomes das telas capturadas serão baseados na + hora atual, ejemplo: 11_58_32 (mais a extensão definida nas configurações de preferência) + + Rede e atualizações Captura Reproduzir o som de uma câmera - Configurações Padrão para os Arquivos de Captura + Plugins + Criado por + Caminho da DLL + Nome + Versões + Configurações Padrão para os Arquivos Capturados Formato da imagem Impressora Opções de Impressão + Configurações de qualidade + Reduzir a quantidade de cores para um máximo de 256 Configurar teclas de atalho Simular o flash de uma câmera + Mostrar notificações + Mostrar lupa Caminho Preferências Formato usado para gerar o nome dos arquivos quando se salvam as telas capturadas Idioma da interface de usuário do Greenshot (necessita reiniciar) - Formato da imagen usado por padrão + Formato da imagem usado por padrão Configurar os atalhos Print, Ctrl + Print, Alt + Print para uso pelo Greenshot quando este iniciar, e até que ele seja finalizado. - Lugar onde as telas capturadas serão salvas por padrão (deixar em branco para salvar na Área de Trabalho) + Local onde as telas capturadas serão salvas por padrão (deixar em branco para salvar na Área de Trabalho) + Usar proxy padrão do sistema Efeitos Milisegundos à esperar antes de iniciar a captura + Modo de captura de janela + Captura de janela Botão direito aqui ou pressionar a tecla Print. + A versão mais recente do Greenshot está disponível! Você quer baixar o Greenshot {0}? + Por favor aguarde enquanto a página no Internet Explorer é capturado ... Atenção - Uma ou mais teclas de atalho não puderam ser configuradas. Por isso pode não ser possível utilizar as teclas de atalho do Greenshot. -Este problema é geralmente causado por outro aplicativo solicitando acesso a estas teclas de atalho. -Por favor desative o outro programa que está utilizando a tecla Print ou utilize as funções do Greenshot via o menu de contexto do ícone no System Tray. + + Uma ou mais teclas de atalho não puderam ser configuradas. Por isso pode não ser possível usar as teclas de atalho do Greenshot. + Este problema é geralmente causado por outro aplicativo solicitando acesso a estas teclas de atalho. + Por favor desative o outro programa que está usando a tecla Print ou use as funções do Greenshot via menu de contexto no ícone da bandeja do sistema. + + Usar cor personalizada + Preservar a transparência + Automaticamente + Usar cores padrão + Como exibido + Tamanho do ícone - \ No newline at end of file + diff --git a/Greenshot/Languages/website/language-website-pt-BR.xml b/Greenshot/Languages/website/language-website-pt-BR.xml new file mode 100644 index 000000000..3549a06ae --- /dev/null +++ b/Greenshot/Languages/website/language-website-pt-BR.xml @@ -0,0 +1,19 @@ + + + + Downloads + Greenshot - uma ferramenta de captura de tela gratuito e otimizado para a produtividade + Greenshot é gratuito e open source + Se você achar que Greenshot economiza um monte de tempo e dinheiro, você é muito bem-vindo ao <a href="/support/">apoiar o desenvolvimento</a> deste software de captura de tela. + Greenshot foi publicado <a href="http://en.wikipedia.org/wiki/GNU_General_Public_License" target="_blank">GPL</a>, e.x. este software pode ser baixado e usado gratuitamente, mesmo em um ambiente comercial. + Quer ver mais? + Claro que há mais que Greenshot pode fazer por você. Ter um olhar para alguns <a title="Imagens do Greenshot em ação" href="/screenshots/">screenshots</a> de Greenshot em ação ou tentar <a title="Baixe a versão mais recente estável do Greenshot" href="/downloads/">latest release</a>. + O que é Greenshot???? + Criar rapidamente capturas de tela de uma região selecionada, janela ou tela cheia; você pode até capturar páginas completas (rolagem) do Internet Explorer. + Anote facilmente, destaque ou ofuscar partes da imagem. + Greenshot é uma ferramenta de software de captura de tela leve para windows com os seguintes recursos principais: + ...e muito mais opções simplesmente para a criação e trabalhar com captura de tela todos os dias. + Exportar a imagem de várias maneiras: salvar em arquivo, enviar para a impressora, copiar para área de transferência, anexar a e-mail, enviar programas do Office ou upload para sites de fotos como o Flickr ou Google Fotos e outros. + Sendo fácil de entender e configurável, Greenshot é uma ferramenta eficiente para gerenciar projetos, desenvolvedores de software, escritores técnicos, testadores e qualquer outra pessoa criando captura de tela. + + \ No newline at end of file From 3055d42689d0ed46fdeb3ea7ebd2f41b92fff97a Mon Sep 17 00:00:00 2001 From: Robin Date: Sun, 12 Apr 2020 23:23:02 +0200 Subject: [PATCH 008/232] Fixed Windows 10 incompatibility with 1809 Removed experimental QR code Updated dependencies. --- Directory.Build.props | 2 +- Greenshot/Forms/CaptureForm.cs | 66 +++---------------- Greenshot/Greenshot.csproj | 1 - Greenshot/Helpers/CaptureHelper.cs | 25 +------ Greenshot/Helpers/QrExtensions.cs | 52 --------------- Greenshot/Processors/ZXingQrProcessor.cs | 52 --------------- Greenshot/greenshot.manifest | 2 +- Greenshot/releases/innosetup/setup.iss | 1 - .../GreenshotJiraPlugin.csproj | 2 +- GreenshotPlugin/Core/Capture.cs | 17 +---- GreenshotPlugin/Core/CaptureDetails.cs | 4 -- GreenshotPlugin/GreenshotPlugin.csproj | 1 - .../Hooking/WindowsOpenCloseMonitor.cs | 2 +- GreenshotPlugin/Interfaces/ICaptureDetails.cs | 8 +-- .../GreenshotWin10Plugin.csproj | 2 +- .../ToastNotificationService.cs | 2 +- 16 files changed, 18 insertions(+), 221 deletions(-) delete mode 100644 Greenshot/Helpers/QrExtensions.cs delete mode 100644 Greenshot/Processors/ZXingQrProcessor.cs diff --git a/Directory.Build.props b/Directory.Build.props index 6ce7c7c6e..37b63badc 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -56,7 +56,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs index e415d1053..bad4a0d24 100644 --- a/Greenshot/Forms/CaptureForm.cs +++ b/Greenshot/Forms/CaptureForm.cs @@ -31,7 +31,6 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Globalization; -using System.Linq; using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; @@ -39,7 +38,6 @@ using System.Windows.Forms; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; -using ZXing; namespace Greenshot.Forms { /// @@ -153,11 +151,11 @@ namespace Greenshot.Forms { InitializeComponent(); // Only double-buffer when we are not in a TerminalServerSession DoubleBuffered = !IsTerminalServerSession; - Text = "Greenshot capture form"; + Text = @"Greenshot capture form"; - // Make sure we never capture the captureform + // Make sure we never capture the capture-form WindowDetails.RegisterIgnoreHandle(Handle); - // Unregister at close + // Un-register at close FormClosing += ClosingHandler; // set cursor location @@ -322,7 +320,7 @@ namespace Greenshot.Forms { if (_capture.CaptureDetails.OcrInformation is null) { var ocrProvider = SimpleServiceProvider.Current.GetInstance(); - if (ocrProvider is object) + if (ocrProvider != null) { var uiTaskScheduler = SimpleServiceProvider.Current.GetInstance(); @@ -338,30 +336,10 @@ namespace Greenshot.Forms { Invalidate(); } break; - case Keys.Q: - if (_capture.CaptureDetails.QrResult is null) - { - // create a barcode reader instance - IBarcodeReader reader = new BarcodeReader(); - // detect and decode the barcode inside the bitmap - var result = reader.Decode((Bitmap)_capture.Image); - // do something with the result - if (result != null) - { - Log.InfoFormat("Found QR of type {0} with text {1}", result.BarcodeFormat, result.Text); - _capture.CaptureDetails.QrResult = result; - } - } - else - { - Invalidate(); - } - break; - } + } } - - /// + /// /// The mousedown handler of the capture form /// /// @@ -402,13 +380,7 @@ namespace Greenshot.Forms { _captureRect = new Rectangle(_mouseMovePos, new Size(1, 1)); // Go and process the capture DialogResult = DialogResult.OK; - } else if (_capture.CaptureDetails.QrResult != null && _capture.CaptureDetails.QrResult.BoundingQrBox().Contains(_mouseMovePos)) - { - // Handle a click on a QR code - _captureRect = new Rectangle(_mouseMovePos, Size.Empty); - // Go and process the capture - DialogResult = DialogResult.OK; - } else { + } else { Invalidate(); } @@ -891,29 +863,7 @@ namespace Greenshot.Forms { } } - - // QR Code - if (_capture.CaptureDetails.QrResult != null) - { - var result = _capture.CaptureDetails.QrResult; - - var boundingBox = _capture.CaptureDetails.QrResult.BoundingQrBox(); - if (!boundingBox.IsEmpty) - { - Log.InfoFormat("Found QR of type {0} - {1}", result.BarcodeFormat, result.Text); - Invalidate(boundingBox); - using var pen = new Pen(Color.BlueViolet, 10); - using var solidBrush = new SolidBrush(Color.Green); - - using var solidWhiteBrush = new SolidBrush(Color.White); - using var font = new Font(FontFamily.GenericSerif, 12, FontStyle.Regular); - graphics.FillRectangle(solidWhiteBrush, boundingBox); - graphics.DrawRectangle(pen, boundingBox); - graphics.DrawString(result.Text, font, solidBrush, boundingBox); - } - } - - // Only draw Cursor if it's (partly) visible + // Only draw Cursor if it's (partly) visible if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new Rectangle(_capture.CursorLocation, _capture.Cursor.Size))) { graphics.DrawIcon(_capture.Cursor, _capture.CursorLocation.X, _capture.CursorLocation.Y); } diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj index a321ad9b9..1b25c59a2 100644 --- a/Greenshot/Greenshot.csproj +++ b/Greenshot/Greenshot.csproj @@ -18,7 +18,6 @@ - diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index ea7707f1f..d8a617995 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -145,7 +145,7 @@ namespace Greenshot.Helpers { public static void CaptureWindowInteractive(bool captureMouse) { - using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Window); + using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Window, captureMouse); captureHelper.MakeCapture(); } @@ -608,28 +608,7 @@ namespace Greenshot.Helpers { return; } - // User clicked on a QR Code - var qrResult = _capture.CaptureDetails.QrResult; - if (qrResult != null && _captureRect.Size.IsEmpty && qrResult.BoundingQrBox().Contains(_captureRect.Location)) - { - if (qrResult.Text.StartsWith("http")) - { - Process.Start(qrResult.Text); - } - else - { - Clipboard.SetText(qrResult.Text); - } - // Disable capturing - _captureMode = CaptureMode.None; - // Dispose the capture, we don't need it anymore (the surface copied all information and we got the title (if any)). - _capture.Dispose(); - _capture = null; - return; - } - - - // Make sure the user sees that the capture is made + // Make sure the user sees that the capture is made if (_capture.CaptureDetails.CaptureMode == CaptureMode.File || _capture.CaptureDetails.CaptureMode == CaptureMode.Clipboard) { // Maybe not "made" but the original is still there... somehow outputMade = true; diff --git a/Greenshot/Helpers/QrExtensions.cs b/Greenshot/Helpers/QrExtensions.cs deleted file mode 100644 index ac96863ad..000000000 --- a/Greenshot/Helpers/QrExtensions.cs +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ZXing; - -namespace Greenshot.Helpers -{ - public static class QrExtensions - { - /// - /// Find the bounding box for the Qr Result. - /// - /// Result - /// Rectangle - public static Rectangle BoundingQrBox(this Result result) - { - var xValues = result.ResultPoints.Select(p => (int)p.X).ToList(); - int xMin = xValues.Min(); - int xMax = xValues.Max(); - - var yValues = result.ResultPoints.Select(p => (int)p.Y).ToList(); - int yMin = yValues.Min(); - int yMax = yValues.Max(); - - return new Rectangle(xMin, yMin, xMax - xMin, yMax - yMin); - } - } -} diff --git a/Greenshot/Processors/ZXingQrProcessor.cs b/Greenshot/Processors/ZXingQrProcessor.cs deleted file mode 100644 index 0fa9e08e4..000000000 --- a/Greenshot/Processors/ZXingQrProcessor.cs +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using log4net; -using ZXing; - -namespace Greenshot.Processors { - /// - /// This processor processes a capture to see if there is a QR ode on it - /// - public class ZXingQrProcessor : AbstractProcessor { - private static readonly ILog LOG = LogManager.GetLogger(typeof(ZXingQrProcessor)); - - public override string Designation => "ZXingQrProcessor"; - - public override string Description => Designation; - - public override bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails) { - // create a barcode reader instance - IBarcodeReader reader = new BarcodeReader(); - // detect and decode the barcode inside the bitmap - var result = reader.Decode((Bitmap)surface.Image); - // do something with the result - if (result == null) return false; - - LOG.InfoFormat("Found QR of type {0} - {1}", result.BarcodeFormat, result.Text); - captureDetails.QrResult = result; - return true; - } - } -} diff --git a/Greenshot/greenshot.manifest b/Greenshot/greenshot.manifest index cae29e2dc..77ba35d7a 100644 --- a/Greenshot/greenshot.manifest +++ b/Greenshot/greenshot.manifest @@ -16,7 +16,7 @@ - + diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index bf4485edf..b2fd8e371 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -26,7 +26,6 @@ Source: {#ReleaseDir}\Dapplo.Log.dll; DestDir: {app}; Components: greenshot; Fla Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Newtonsoft.Json.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\zxing*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: ..\..\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion Source: {#ReleaseDir}\checksum.SHA256; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion ;Source: ..\greenshot-defaults.ini; DestDir: {app}; Flags: overwritereadonly ignoreversion replacesameversion diff --git a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj b/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj index b739c7aab..5579b7dac 100644 --- a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj +++ b/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj @@ -12,6 +12,6 @@ - + \ No newline at end of file diff --git a/GreenshotPlugin/Core/Capture.cs b/GreenshotPlugin/Core/Capture.cs index 78b93627b..95a7fb872 100644 --- a/GreenshotPlugin/Core/Capture.cs +++ b/GreenshotPlugin/Core/Capture.cs @@ -2,11 +2,9 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; -using System.Linq; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; using log4net; -using ZXing; namespace GreenshotPlugin.Core { @@ -20,7 +18,7 @@ namespace GreenshotPlugin.Core private Rectangle _screenBounds; /// - /// Get/Set the Screenbounds + /// Get/Set the screen bounds /// public Rectangle ScreenBounds { get { @@ -180,19 +178,6 @@ namespace GreenshotPlugin.Core // TODO: Remove invisible lines/words? CaptureDetails.OcrInformation?.Offset(-cropRectangle.Location.X, -cropRectangle.Location.Y); - // Offset the Qr information - // TODO: Remove invisible QR codes? - var oldQrResult = CaptureDetails.QrResult; - if (oldQrResult != null) - { - CaptureDetails.OcrInformation?.Offset(-cropRectangle.Location.X, -cropRectangle.Location.Y); - var offsetPoints = CaptureDetails.QrResult.ResultPoints - .Select(p => new ResultPoint(p.X - cropRectangle.Location.X, p.Y - cropRectangle.Location.Y)).ToArray(); - - var newQqResult = new Result(oldQrResult.Text, oldQrResult.RawBytes, offsetPoints, oldQrResult.BarcodeFormat); - CaptureDetails.QrResult = newQqResult; - } - // Remove invisible elements var visibleElements = new List(); foreach(var captureElement in _elements) { diff --git a/GreenshotPlugin/Core/CaptureDetails.cs b/GreenshotPlugin/Core/CaptureDetails.cs index 9f7682d5a..f6e0474ea 100644 --- a/GreenshotPlugin/Core/CaptureDetails.cs +++ b/GreenshotPlugin/Core/CaptureDetails.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; -using ZXing; namespace GreenshotPlugin.Core { @@ -45,9 +44,6 @@ namespace GreenshotPlugin.Core /// public OcrInformation OcrInformation { get; set; } - /// - public Result QrResult { get; set; } - /// public Dictionary MetaData { get; } = new Dictionary(); diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj index 16ba0a08c..1a9598bc0 100644 --- a/GreenshotPlugin/GreenshotPlugin.csproj +++ b/GreenshotPlugin/GreenshotPlugin.csproj @@ -16,7 +16,6 @@ - diff --git a/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs b/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs index 088b045e3..e62cdf89a 100644 --- a/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs +++ b/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs @@ -102,7 +102,7 @@ namespace GreenshotPlugin.Hooking } /// - /// WinEventDelegate for the creation & destruction + /// WinEventDelegate for the creation and destruction /// /// /// diff --git a/GreenshotPlugin/Interfaces/ICaptureDetails.cs b/GreenshotPlugin/Interfaces/ICaptureDetails.cs index 33df1a822..055cd598b 100644 --- a/GreenshotPlugin/Interfaces/ICaptureDetails.cs +++ b/GreenshotPlugin/Interfaces/ICaptureDetails.cs @@ -22,7 +22,6 @@ using System; using System.Collections.Generic; using GreenshotPlugin.Interfaces.Ocr; -using ZXing; namespace GreenshotPlugin.Interfaces { /// @@ -100,10 +99,5 @@ namespace GreenshotPlugin.Interfaces { /// Store the OCR information for this capture /// OcrInformation OcrInformation { get; set; } - - /// - /// Store the QR information for this capture - /// - Result QrResult { get; set; } - } + } } diff --git a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj b/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj index 4e6095274..a17df050e 100644 --- a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj +++ b/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj @@ -12,7 +12,7 @@ - + diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/GreenshotWin10Plugin/ToastNotificationService.cs index 4af060bf9..70ef5084a 100644 --- a/GreenshotWin10Plugin/ToastNotificationService.cs +++ b/GreenshotWin10Plugin/ToastNotificationService.cs @@ -107,7 +107,7 @@ namespace GreenshotWin10Plugin // Create the toast and attach event listeners var toast = new ToastNotification(toastXml) { - ExpiresOnReboot = true, + // Windows 10 first with 1903: ExpiresOnReboot = true, ExpirationTime = timeout > 0 ? DateTimeOffset.Now.AddMilliseconds(timeout) : (DateTimeOffset?)null }; From 87f3b6a8717f80bfb0297eb112a418c817b0518c Mon Sep 17 00:00:00 2001 From: Robin Date: Tue, 14 Apr 2020 12:31:52 +0200 Subject: [PATCH 009/232] Improving stability for the notification issue reported in #182 --- GreenshotPlugin/Core/SimpleServiceProvider.cs | 4 + .../ToastNotificationService.cs | 375 ++++++++++-------- GreenshotWin10Plugin/Win10Plugin.cs | 2 +- 3 files changed, 204 insertions(+), 177 deletions(-) diff --git a/GreenshotPlugin/Core/SimpleServiceProvider.cs b/GreenshotPlugin/Core/SimpleServiceProvider.cs index 5482f107a..9ffd9d590 100644 --- a/GreenshotPlugin/Core/SimpleServiceProvider.cs +++ b/GreenshotPlugin/Core/SimpleServiceProvider.cs @@ -43,6 +43,10 @@ namespace GreenshotPlugin.Core foreach (var service in services) { + if (service == null) + { + continue; + } currentServices.Add(service); } } diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/GreenshotWin10Plugin/ToastNotificationService.cs index 70ef5084a..413a51c00 100644 --- a/GreenshotWin10Plugin/ToastNotificationService.cs +++ b/GreenshotWin10Plugin/ToastNotificationService.cs @@ -1,176 +1,199 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing.Imaging; -using System.IO; -using System.Linq; -using Windows.UI.Notifications; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotWin10Plugin.Native; -using log4net; - -namespace GreenshotWin10Plugin -{ - /// - /// This service provides a way to inform (notify) the user. - /// - public class ToastNotificationService : INotificationService - { - private static readonly ILog Log = LogManager.GetLogger(typeof(ToastNotificationService)); - private static readonly CoreConfiguration CoreConfiguration = IniConfig.GetIniSection(); - - private readonly string _imageFilePath; - public ToastNotificationService() - { - // Register AUMID and COM server (for Desktop Bridge apps, this no-ops) - DesktopNotificationManagerCompat.RegisterAumidAndComServer("Greenshot"); - // Register COM server and activator type - DesktopNotificationManagerCompat.RegisterActivator(); - - var localAppData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Greenshot"); - if (!Directory.Exists(localAppData)) - { - Directory.CreateDirectory(localAppData); - } - _imageFilePath = Path.Combine(localAppData, "greenshot.png"); - - if (File.Exists(_imageFilePath)) - { - return; - } - - using var greenshotImage = GreenshotResources.GetGreenshotIcon().ToBitmap(); - greenshotImage.Save(_imageFilePath, ImageFormat.Png); - } - - /// - /// This creates the actual toast - /// - /// string - /// milliseconds until the toast timeouts - /// Action called when clicked - /// Action called when the toast is closed - private void ShowMessage(string message, int timeout, Action onClickAction, Action onClosedAction) - { - // Do not inform the user if this is disabled - if (!CoreConfiguration.ShowTrayNotification) - { - return; - } - // Prepare the toast notifier. Be sure to specify the AppUserModelId on your application's shortcut! - var toastNotifier = DesktopNotificationManagerCompat.CreateToastNotifier(); - if (toastNotifier.Setting != NotificationSetting.Enabled) - { - Log.DebugFormat("Ignored toast due to {0}", toastNotifier.Setting); - return; - } - - // Get a toast XML template - var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText01); - - // Fill in the text elements - var stringElement = toastXml.GetElementsByTagName("text").First(); - stringElement.AppendChild(toastXml.CreateTextNode(message)); - - if (_imageFilePath != null && File.Exists(_imageFilePath)) - { - // Specify the absolute path to an image - var imageElement = toastXml.GetElementsByTagName("image").First(); - var imageSrcNode = imageElement.Attributes.GetNamedItem("src"); - if (imageSrcNode != null) - { - imageSrcNode.NodeValue = _imageFilePath; - } - } - - // Create the toast and attach event listeners - var toast = new ToastNotification(toastXml) - { - // Windows 10 first with 1903: ExpiresOnReboot = true, - ExpirationTime = timeout > 0 ? DateTimeOffset.Now.AddMilliseconds(timeout) : (DateTimeOffset?)null - }; - - void ToastActivatedHandler(ToastNotification toastNotification, object sender) - { - try - { - onClickAction?.Invoke(); - } - catch (Exception ex) - { - Log.Warn("Exception while handling the onclick action: ", ex); - } - - toast.Activated -= ToastActivatedHandler; - } - - if (onClickAction != null) - { - toast.Activated += ToastActivatedHandler; - } - - void ToastDismissedHandler(ToastNotification toastNotification, ToastDismissedEventArgs eventArgs) - { - Log.Debug("Toast closed"); - try - { - onClosedAction?.Invoke(); - } - catch (Exception ex) - { - Log.Warn("Exception while handling the onClosed action: ", ex); - } - - toast.Dismissed -= ToastDismissedHandler; - // Remove the other handler too - toast.Activated -= ToastActivatedHandler; - toast.Failed -= ToastOnFailed; - } - toast.Dismissed += ToastDismissedHandler; - toast.Failed += ToastOnFailed; - toastNotifier.Show(toast); - } - - private void ToastOnFailed(ToastNotification sender, ToastFailedEventArgs args) - { - Log.WarnFormat("Failed to display a toast due to {0}", args.ErrorCode); - Log.Debug(sender.Content.GetXml()); - } - - public void ShowWarningMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) - { - ShowMessage(message, timeout, onClickAction, onClosedAction); - } - - public void ShowErrorMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) - { - ShowMessage(message, timeout, onClickAction, onClosedAction); - } - - public void ShowInfoMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) - { - ShowMessage(message, timeout, onClickAction, onClosedAction); - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using Windows.Foundation.Metadata; +using Windows.UI.Notifications; +using GreenshotPlugin.Core; +using GreenshotPlugin.IniFile; +using GreenshotPlugin.Interfaces; +using GreenshotWin10Plugin.Native; +using log4net; + +namespace GreenshotWin10Plugin +{ + /// + /// This service provides a way to inform (notify) the user. + /// + public class ToastNotificationService : INotificationService + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ToastNotificationService)); + private static readonly CoreConfiguration CoreConfiguration = IniConfig.GetIniSection(); + + private readonly string _imageFilePath; + public ToastNotificationService() + { + // Register AUMID and COM server (for Desktop Bridge apps, this no-ops) + DesktopNotificationManagerCompat.RegisterAumidAndComServer("Greenshot"); + // Register COM server and activator type + DesktopNotificationManagerCompat.RegisterActivator(); + + var localAppData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Greenshot"); + if (!Directory.Exists(localAppData)) + { + Directory.CreateDirectory(localAppData); + } + _imageFilePath = Path.Combine(localAppData, "greenshot.png"); + + if (File.Exists(_imageFilePath)) + { + return; + } + + using var greenshotImage = GreenshotResources.GetGreenshotIcon().ToBitmap(); + greenshotImage.Save(_imageFilePath, ImageFormat.Png); + } + + /// + /// This creates the actual toast + /// + /// string + /// milliseconds until the toast timeouts + /// Action called when clicked + /// Action called when the toast is closed + private void ShowMessage(string message, int timeout, Action onClickAction, Action onClosedAction) + { + // Do not inform the user if this is disabled + if (!CoreConfiguration.ShowTrayNotification) + { + return; + } + // Prepare the toast notifier. Be sure to specify the AppUserModelId on your application's shortcut! + var toastNotifier = DesktopNotificationManagerCompat.CreateToastNotifier(); + if (toastNotifier.Setting != NotificationSetting.Enabled) + { + Log.DebugFormat("Ignored toast due to {0}", toastNotifier.Setting); + return; + } + + // Get a toast XML template + var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText01); + + // Fill in the text elements + var stringElement = toastXml.GetElementsByTagName("text").First(); + stringElement.AppendChild(toastXml.CreateTextNode(message)); + + if (_imageFilePath != null && File.Exists(_imageFilePath)) + { + // Specify the absolute path to an image + var imageElement = toastXml.GetElementsByTagName("image").First(); + var imageSrcNode = imageElement.Attributes.GetNamedItem("src"); + if (imageSrcNode != null) + { + imageSrcNode.NodeValue = _imageFilePath; + } + } + + // Create the toast and attach event listeners + var toast = new ToastNotification(toastXml) + { + // Windows 10 first with 1903: ExpiresOnReboot = true, + ExpirationTime = timeout > 0 ? DateTimeOffset.Now.AddMilliseconds(timeout) : (DateTimeOffset?)null + }; + + void ToastActivatedHandler(ToastNotification toastNotification, object sender) + { + try + { + onClickAction?.Invoke(); + } + catch (Exception ex) + { + Log.Warn("Exception while handling the onclick action: ", ex); + } + + toast.Activated -= ToastActivatedHandler; + } + + if (onClickAction != null) + { + toast.Activated += ToastActivatedHandler; + } + + void ToastDismissedHandler(ToastNotification toastNotification, ToastDismissedEventArgs eventArgs) + { + Log.Debug("Toast closed"); + try + { + onClosedAction?.Invoke(); + } + catch (Exception ex) + { + Log.Warn("Exception while handling the onClosed action: ", ex); + } + + toast.Dismissed -= ToastDismissedHandler; + // Remove the other handler too + toast.Activated -= ToastActivatedHandler; + toast.Failed -= ToastOnFailed; + } + toast.Dismissed += ToastDismissedHandler; + toast.Failed += ToastOnFailed; + try + { + toastNotifier.Show(toast); + } + catch (Exception ex) + { + Log.Error("Couldn't show notification.", ex); + } + } + + private void ToastOnFailed(ToastNotification sender, ToastFailedEventArgs args) + { + Log.WarnFormat("Failed to display a toast due to {0}", args.ErrorCode); + Log.Debug(sender.Content.GetXml()); + } + + public void ShowWarningMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + { + ShowMessage(message, timeout, onClickAction, onClosedAction); + } + + public void ShowErrorMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + { + ShowMessage(message, timeout, onClickAction, onClosedAction); + } + + public void ShowInfoMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + { + ShowMessage(message, timeout, onClickAction, onClosedAction); + } + + /// + /// Factory method, helping with checking if the notification service is even available + /// + /// ToastNotificationService + public static ToastNotificationService Create() + { + if (ApiInformation.IsTypePresent("Windows.ApplicationModel.Background.ToastNotificationActionTrigger")) + { + return new ToastNotificationService(); + } + Log.Warn("ToastNotificationActionTrigger not available."); + + return null; + } + } +} diff --git a/GreenshotWin10Plugin/Win10Plugin.cs b/GreenshotWin10Plugin/Win10Plugin.cs index 947ce180c..1e0519071 100644 --- a/GreenshotWin10Plugin/Win10Plugin.cs +++ b/GreenshotWin10Plugin/Win10Plugin.cs @@ -63,7 +63,7 @@ namespace GreenshotWin10Plugin return false; } - SimpleServiceProvider.Current.AddService(new ToastNotificationService()); + SimpleServiceProvider.Current.AddService(ToastNotificationService.Create()); // Set this as IOcrProvider SimpleServiceProvider.Current.AddService(new Win10OcrProvider()); // Add the processor From 6e7a911477689b340776e6b921182a9e4b93a1cd Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 15 Apr 2020 22:49:43 +0200 Subject: [PATCH 010/232] This should fix showing the notification on the first start. --- Greenshot/Forms/MainForm.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index a197a8cf5..9a7f21290 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -352,7 +352,7 @@ namespace Greenshot { // Disable access to the settings, for feature #3521446 contextmenu_settings.Visible = !_conf.DisableSettings; - // Make sure all hotkeys pass this window! + // Make sure all hot-keys pass this window! HotkeyControl.RegisterHotkeyHwnd(Handle); RegisterHotkeys(); @@ -444,9 +444,11 @@ namespace Greenshot { Exit(); break; case CommandEnum.FirstLaunch: - LOG.Info("FirstLaunch: Created new configuration, showing balloon."); - var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); - notifyIconClassicMessageHandler.ShowInfoMessage(Language.GetFormattedString(LangKey.tooltip_firststart, HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.RegionHotkey)), 2000, ShowSetting); + Invoke((MethodInvoker)delegate { + LOG.Info("FirstLaunch: Created new configuration, showing balloon."); + var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); + notifyIconClassicMessageHandler.ShowInfoMessage(Language.GetFormattedString(LangKey.tooltip_firststart, HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.RegionHotkey)), 2000, ShowSetting); + }); break; case CommandEnum.ReloadConfig: LOG.Info("Reload requested"); From 9c31b900215b0dc9166a8b9fa727012dd29c6173 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 16 Apr 2020 21:19:07 +0200 Subject: [PATCH 011/232] Fix #182, the notifications don't work due to a quirk in the Windows API. --- GreenshotWin10Plugin/ToastNotificationService.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/GreenshotWin10Plugin/ToastNotificationService.cs index 413a51c00..5f51d7fd6 100644 --- a/GreenshotWin10Plugin/ToastNotificationService.cs +++ b/GreenshotWin10Plugin/ToastNotificationService.cs @@ -81,10 +81,19 @@ namespace GreenshotWin10Plugin } // Prepare the toast notifier. Be sure to specify the AppUserModelId on your application's shortcut! var toastNotifier = DesktopNotificationManagerCompat.CreateToastNotifier(); - if (toastNotifier.Setting != NotificationSetting.Enabled) + + // Here is an interesting article on reading the settings: https://www.rudyhuyn.com/blog/2018/02/10/toastnotifier-and-settings-careful-with-non-uwp-applications/ + try { - Log.DebugFormat("Ignored toast due to {0}", toastNotifier.Setting); - return; + if (toastNotifier.Setting != NotificationSetting.Enabled) + { + Log.DebugFormat("Ignored toast due to {0}", toastNotifier.Setting); + return; + } + } + catch (Exception) + { + Log.Info("Ignoring exception as this means that there was no stored settings."); } // Get a toast XML template From 700fb07e4092fe0148679b8482c42cda344b3918 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 16 Apr 2020 21:19:58 +0200 Subject: [PATCH 012/232] Changed the update check, this should be more stable and flexible. --- Greenshot/Drawing/Surface.cs | 2 +- Greenshot/Forms/MainForm.Designer.cs | 22 +-- Greenshot/Forms/MainForm.cs | 94 ++++------ Greenshot/Helpers/Entities/UpdateFeed.cs | 35 ++++ Greenshot/Helpers/UpdateHelper.cs | 184 ------------------- Greenshot/Helpers/UpdateService.cs | 222 +++++++++++++++++++++++ GreenshotPlugin/Core/RssHelper.cs | 204 --------------------- 7 files changed, 304 insertions(+), 459 deletions(-) create mode 100644 Greenshot/Helpers/Entities/UpdateFeed.cs delete mode 100644 Greenshot/Helpers/UpdateHelper.cs create mode 100644 Greenshot/Helpers/UpdateService.cs delete mode 100644 GreenshotPlugin/Core/RssHelper.cs diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 3ec79db52..bd56db3a2 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -239,7 +239,7 @@ namespace Greenshot.Drawing _counterStart = value; Invalidate(); - _propertyChanged?.Invoke(this, new PropertyChangedEventArgs("CounterStart")); + _propertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CounterStart))); } } diff --git a/Greenshot/Forms/MainForm.Designer.cs b/Greenshot/Forms/MainForm.Designer.cs index a93b815d0..f94f4b87d 100644 --- a/Greenshot/Forms/MainForm.Designer.cs +++ b/Greenshot/Forms/MainForm.Designer.cs @@ -73,7 +73,6 @@ namespace Greenshot { this.toolStripCloseSeparator = new System.Windows.Forms.ToolStripSeparator(); this.contextmenu_exit = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); - this.backgroundWorkerTimer = new System.Windows.Forms.Timer(this.components); this.contextMenu.SuspendLayout(); this.SuspendLayout(); // @@ -122,7 +121,7 @@ namespace Greenshot { this.contextmenu_capturelastregion.Name = "contextmenu_capturelastregion"; this.contextmenu_capturelastregion.ShortcutKeyDisplayString = "Shift + Print"; this.contextmenu_capturelastregion.Size = new System.Drawing.Size(170, 22); - this.contextmenu_capturelastregion.Click += new System.EventHandler(this.Contextmenu_capturelastregionClick); + this.contextmenu_capturelastregion.Click += new System.EventHandler(this.Contextmenu_CaptureLastRegionClick); // // contextmenu_capturewindow // @@ -130,7 +129,7 @@ namespace Greenshot { this.contextmenu_capturewindow.Name = "contextmenu_capturewindow"; this.contextmenu_capturewindow.ShortcutKeyDisplayString = "Alt + Print"; this.contextmenu_capturewindow.Size = new System.Drawing.Size(170, 22); - this.contextmenu_capturewindow.Click += new System.EventHandler(this.Contextmenu_capturewindow_Click); + this.contextmenu_capturewindow.Click += new System.EventHandler(this.Contextmenu_CaptureWindow_Click); // // contextmenu_capturefullscreen // @@ -144,7 +143,7 @@ namespace Greenshot { this.contextmenu_captureie.Name = "contextmenu_captureie"; this.contextmenu_captureie.ShortcutKeyDisplayString = "Ctrl + Shift + Print"; this.contextmenu_captureie.Size = new System.Drawing.Size(170, 22); - this.contextmenu_captureie.Click += new System.EventHandler(this.Contextmenu_captureie_Click); + this.contextmenu_captureie.Click += new System.EventHandler(this.Contextmenu_CaptureIe_Click); // // toolStripListCaptureSeparator // @@ -210,7 +209,7 @@ namespace Greenshot { this.contextmenu_settings.Image = ((System.Drawing.Image)(resources.GetObject("contextmenu_settings.Image"))); this.contextmenu_settings.Name = "contextmenu_settings"; this.contextmenu_settings.Size = new System.Drawing.Size(170, 22); - this.contextmenu_settings.Click += new System.EventHandler(this.Contextmenu_settingsClick); + this.contextmenu_settings.Click += new System.EventHandler(this.Contextmenu_SettingsClick); // // toolStripMiscSeparator // @@ -229,13 +228,13 @@ namespace Greenshot { this.contextmenu_donate.Image = ((System.Drawing.Image)(resources.GetObject("contextmenu_donate.Image"))); this.contextmenu_donate.Name = "contextmenu_donate"; this.contextmenu_donate.Size = new System.Drawing.Size(170, 22); - this.contextmenu_donate.Click += new System.EventHandler(this.Contextmenu_donateClick); + this.contextmenu_donate.Click += new System.EventHandler(this.Contextmenu_DonateClick); // // contextmenu_about // this.contextmenu_about.Name = "contextmenu_about"; this.contextmenu_about.Size = new System.Drawing.Size(170, 22); - this.contextmenu_about.Click += new System.EventHandler(this.Contextmenu_aboutClick); + this.contextmenu_about.Click += new System.EventHandler(this.Contextmenu_AboutClick); // // toolStripCloseSeparator // @@ -255,12 +254,6 @@ namespace Greenshot { this.notifyIcon.Text = "Greenshot"; this.notifyIcon.MouseUp += new System.Windows.Forms.MouseEventHandler(this.NotifyIconClickTest); // - // backgroundWorkerTimer - // - this.backgroundWorkerTimer.Enabled = true; - this.backgroundWorkerTimer.Interval = 300000; - this.backgroundWorkerTimer.Tick += new System.EventHandler(this.BackgroundWorkerTimerTick); - // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -282,8 +275,7 @@ namespace Greenshot { private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_capturewindowfromlist; private System.Windows.Forms.ToolStripSeparator toolStripListCaptureSeparator; private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_openrecentcapture; - private System.Windows.Forms.Timer backgroundWorkerTimer; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_captureie; + private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_captureie; private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_donate; private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_openfile; private System.Windows.Forms.ToolStripSeparator toolStripPluginSeparator; diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index 9a7f21290..b96211a97 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -418,6 +418,11 @@ namespace Greenshot { HandleDataTransport(dataTransport); } + // Start the update check in the background + var updateService = new UpdateService(); + updateService.Startup(); + SimpleServiceProvider.Current.AddService(updateService); + // Make Greenshot use less memory after startup if (_conf.MinimizeWorkingSetSize) { PsAPI.EmptyWorkingSet(); @@ -444,11 +449,9 @@ namespace Greenshot { Exit(); break; case CommandEnum.FirstLaunch: - Invoke((MethodInvoker)delegate { LOG.Info("FirstLaunch: Created new configuration, showing balloon."); var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); notifyIconClassicMessageHandler.ShowInfoMessage(Language.GetFormattedString(LangKey.tooltip_firststart, HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.RegionHotkey)), 2000, ShowSetting); - }); break; case CommandEnum.ReloadConfig: LOG.Info("Reload requested"); @@ -554,15 +557,16 @@ namespace Greenshot { /// object /// PropertyChangedEventArgs private void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == "IconSize") - { - ApplyDpiScaling(); - string ieExePath = PluginUtils.GetExePath("iexplore.exe"); - if (!string.IsNullOrEmpty(ieExePath)) { - contextmenu_captureie.Image = PluginUtils.GetCachedExeIcon(ieExePath, 0); - } - } - } + if (e.PropertyName != "IconSize") + { + return; + } + ApplyDpiScaling(); + string ieExePath = PluginUtils.GetExePath("iexplore.exe"); + if (!string.IsNullOrEmpty(ieExePath)) { + contextmenu_captureie.Image = PluginUtils.GetCachedExeIcon(ieExePath, 0); + } + } /// /// Modify the DPI settings depending in the current value @@ -627,7 +631,7 @@ namespace Greenshot { /// /// Check if OneDrive is blocking hotkeys /// - /// true if onedrive has hotkeys turned on + /// true if one-drive has hotkeys turned on private static bool IsOneDriveBlockingHotkey() { if (!WindowsVersion.IsWindows10OrLater) @@ -706,14 +710,16 @@ namespace Greenshot { private void CaptureFile() { var openFileDialog = new OpenFileDialog { - Filter = "Image files (*.greenshot, *.png, *.jpg, *.gif, *.bmp, *.ico, *.tiff, *.wmf)|*.greenshot; *.png; *.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.tiff; *.tif; *.wmf" + Filter = @"Image files (*.greenshot, *.png, *.jpg, *.gif, *.bmp, *.ico, *.tiff, *.wmf)|*.greenshot; *.png; *.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.tiff; *.tif; *.wmf" }; - if (openFileDialog.ShowDialog() == DialogResult.OK) { - if (File.Exists(openFileDialog.FileName)) { - CaptureHelper.CaptureFile(openFileDialog.FileName); - } - } - } + if (openFileDialog.ShowDialog() != DialogResult.OK) + { + return; + } + if (File.Exists(openFileDialog.FileName)) { + CaptureHelper.CaptureFile(openFileDialog.FileName); + } + } private void CaptureFullScreen() { CaptureHelper.CaptureFullscreen(true, _conf.ScreenCaptureMode); @@ -807,7 +813,7 @@ namespace Greenshot { int index = counter.ContainsKey(tabData.Key) ? counter[tabData.Key] : 0; captureIeTabItem.Image = tabData.Key.DisplayIcon; captureIeTabItem.Tag = new KeyValuePair(tabData.Key, index++); - captureIeTabItem.Click += Contextmenu_captureiefromlist_Click; + captureIeTabItem.Click += Contextmenu_CaptureIeFromList_Click; contextmenu_captureiefromlist.DropDownItems.Add(captureIeTabItem); if (counter.ContainsKey(tabData.Key)) { counter[tabData.Key] = index; @@ -884,7 +890,7 @@ namespace Greenshot { // captureForm.MakeCapture(CaptureMode.Window, false); // Now we check which windows are there to capture ToolStripMenuItem captureWindowFromListMenuItem = (ToolStripMenuItem)sender; - AddCaptureWindowMenuItems(captureWindowFromListMenuItem, Contextmenu_capturewindowfromlist_Click); + AddCaptureWindowMenuItems(captureWindowFromListMenuItem, Contextmenu_CaptureWindowFromList_Click); } private void CaptureWindowFromListMenuDropDownClosed(object sender, EventArgs e) { @@ -959,19 +965,19 @@ namespace Greenshot { }); } - private void Contextmenu_capturelastregionClick(object sender, EventArgs e) { + private void Contextmenu_CaptureLastRegionClick(object sender, EventArgs e) { BeginInvoke((MethodInvoker)delegate { CaptureHelper.CaptureLastRegion(false); }); } - private void Contextmenu_capturewindow_Click(object sender,EventArgs e) { + private void Contextmenu_CaptureWindow_Click(object sender,EventArgs e) { BeginInvoke((MethodInvoker)delegate { CaptureHelper.CaptureWindowInteractive(false); }); } - private void Contextmenu_capturewindowfromlist_Click(object sender,EventArgs e) { + private void Contextmenu_CaptureWindowFromList_Click(object sender,EventArgs e) { ToolStripMenuItem clickedItem = (ToolStripMenuItem)sender; BeginInvoke((MethodInvoker)delegate { try { @@ -983,11 +989,11 @@ namespace Greenshot { }); } - private void Contextmenu_captureie_Click(object sender, EventArgs e) { + private void Contextmenu_CaptureIe_Click(object sender, EventArgs e) { CaptureIE(); } - private void Contextmenu_captureiefromlist_Click(object sender, EventArgs e) { + private void Contextmenu_CaptureIeFromList_Click(object sender, EventArgs e) { if (!_conf.IECapture) { LOG.InfoFormat("IE Capture is disabled."); return; @@ -1015,9 +1021,9 @@ namespace Greenshot { /// /// Context menu entry "Support Greenshot" /// - /// - /// - private void Contextmenu_donateClick(object sender, EventArgs e) { + /// object + /// EventArgs + private void Contextmenu_DonateClick(object sender, EventArgs e) { BeginInvoke((MethodInvoker)delegate { Process.Start("http://getgreenshot.org/support/?version=" + Assembly.GetEntryAssembly().GetName().Version); }); @@ -1028,7 +1034,7 @@ namespace Greenshot { /// /// /// - private void Contextmenu_settingsClick(object sender, EventArgs e) { + private void Contextmenu_SettingsClick(object sender, EventArgs e) { BeginInvoke((MethodInvoker)ShowSetting); } @@ -1056,7 +1062,7 @@ namespace Greenshot { /// /// /// - private void Contextmenu_aboutClick(object sender, EventArgs e) { + private void Contextmenu_AboutClick(object sender, EventArgs e) { ShowAbout(); } @@ -1110,7 +1116,7 @@ namespace Greenshot { // Only add if the value is not fixed if (!_conf.Values["CaptureMousepointer"].IsFixed) { - // For the capture mousecursor option + // For the capture mouse-cursor option ToolStripMenuSelectListItem captureMouseItem = new ToolStripMenuSelectListItem { Text = Language.GetString("settings_capture_mousepointer"), @@ -1463,27 +1469,5 @@ namespace Greenshot { notifyIcon = null; } } - - - /// - /// Do work in the background - /// - /// - /// - private void BackgroundWorkerTimerTick(object sender, EventArgs e) { - if (_conf.MinimizeWorkingSetSize) { - PsAPI.EmptyWorkingSet(); - } - if (UpdateHelper.IsUpdateCheckNeeded()) { - LOG.Debug("BackgroundWorkerTimerTick checking for update"); - // Start update check in the background - var backgroundTask = new Thread(UpdateHelper.CheckAndAskForUpdate) - { - Name = "Update check", - IsBackground = true - }; - backgroundTask.Start(); - } - } - } + } } \ No newline at end of file diff --git a/Greenshot/Helpers/Entities/UpdateFeed.cs b/Greenshot/Helpers/Entities/UpdateFeed.cs new file mode 100644 index 000000000..a7a80afb8 --- /dev/null +++ b/Greenshot/Helpers/Entities/UpdateFeed.cs @@ -0,0 +1,35 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Newtonsoft.Json; + +namespace Greenshot.Helpers.Entities +{ + [JsonObject] + public class UpdateFeed + { + [JsonProperty("release")] + public string CurrentReleaseVersion { get; set; } + + [JsonProperty("beta")] + public string CurrentBetaVersion { get; set; } + } +} diff --git a/Greenshot/Helpers/UpdateHelper.cs b/Greenshot/Helpers/UpdateHelper.cs deleted file mode 100644 index 479a66955..000000000 --- a/Greenshot/Helpers/UpdateHelper.cs +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Reflection; -using System.Windows.Forms; -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using log4net; - -namespace Greenshot.Helpers { - /// - /// Description of RssFeedHelper. - /// - public static class UpdateHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(UpdateHelper)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const string StableDownloadLink = "https://getgreenshot.org/downloads/"; - private const string VersionHistoryLink = "https://getgreenshot.org/version-history/"; - private static readonly object LockObject = new object(); - private static RssFile _latestGreenshot; - private static string _downloadLink = StableDownloadLink; - - /// - /// Is an update check needed? - /// - /// bool true if yes - public static bool IsUpdateCheckNeeded() { - lock (LockObject) - { - if (CoreConfig.UpdateCheckInterval == 0) - { - return false; - } - DateTime checkTime = CoreConfig.LastUpdateCheck; - checkTime = checkTime.AddDays(CoreConfig.UpdateCheckInterval); - if (DateTime.Now.CompareTo(checkTime) < 0) - { - Log.DebugFormat("No need to check RSS feed for updates, feed check will be after {0}", checkTime); - return false; - } - Log.DebugFormat("Update check is due, last check was {0} check needs to be made after {1} (which is one {2} later)", CoreConfig.LastUpdateCheck, checkTime, CoreConfig.UpdateCheckInterval); - if (!RssHelper.IsRssModifiedAfter(CoreConfig.LastUpdateCheck)) - { - Log.DebugFormat("RSS feed has not been updated since after {0}", CoreConfig.LastUpdateCheck); - return false; - } - } - return true; - } - - /// - /// Read the RSS feed to see if there is a Greenshot update - /// - public static void CheckAndAskForUpdate() { - lock (LockObject) { - Version currentVersion = Assembly.GetExecutingAssembly().GetName().Version; - // Test like this: - // currentVersion = new Version("0.8.1.1198"); - - // Make sure we update the LastUpdateCheck, in case an error occurs we should not retry every 5 minutes - // This actually prevents an update check, but rather one to less than many to many - CoreConfig.LastUpdateCheck = DateTime.Now; - - try - { - _latestGreenshot = null; - ProcessRssInfo(currentVersion); - if (_latestGreenshot != null) { - var notifyIcon = SimpleServiceProvider.Current.GetInstance(); - - notifyIcon.BalloonTipClicked += HandleBalloonTipClick; - notifyIcon.BalloonTipClosed += CleanupBalloonTipClick; - notifyIcon.ShowBalloonTip(10000, "Greenshot", Language.GetFormattedString(LangKey.update_found, "'" + _latestGreenshot.File + "'"), ToolTipIcon.Info); - } - } catch (Exception e) { - Log.Error("An error occured while checking for updates, the error will be ignored: ", e); - } - } - } - - private static void CleanupBalloonTipClick(object sender, EventArgs e) { - var notifyIcon = SimpleServiceProvider.Current.GetInstance(); - notifyIcon.BalloonTipClicked -= HandleBalloonTipClick; - notifyIcon.BalloonTipClosed -= CleanupBalloonTipClick; - } - - private static void HandleBalloonTipClick(object sender, EventArgs e) { - try { - if (_latestGreenshot != null) { - // "Direct" download link - // Process.Start(latestGreenshot.Link); - // Go to getgreenshot.org - Process.Start(_downloadLink); - } - } catch (Exception) { - MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, _downloadLink), Language.GetString(LangKey.error)); - } finally { - CleanupBalloonTipClick(sender, e); - } - } - - private static void ProcessRssInfo(Version currentVersion) { - // Reset latest Greenshot - IList rssFiles = RssHelper.ReadRss(); - - if (rssFiles == null) { - return; - } - - // Retrieve the current and latest greenshot - foreach(RssFile rssFile in rssFiles) { - if (rssFile.File.StartsWith("Greenshot")) { - // check for exe - if (!rssFile.IsExe) { - continue; - } - - // do we have a version? - if (rssFile.Version == null) { - Log.DebugFormat("Skipping unversioned exe {0} which is published at {1} : {2}", rssFile.File, rssFile.Pubdate.ToLocalTime(), rssFile.Link); - continue; - } - - // if the file is unstable, we will skip it when: - // the current version is a release or release candidate AND check unstable is turned off. - if (rssFile.IsUnstable) { - // Skip if we shouldn't check unstables - if ((CoreConfig.BuildState == BuildStates.RELEASE) && !CoreConfig.CheckForUnstable) { - continue; - } - } - - // if the file is a release candidate, we will skip it when: - // the current version is a release AND check unstable is turned off. - if (rssFile.IsReleaseCandidate) { - if (CoreConfig.BuildState == BuildStates.RELEASE && !CoreConfig.CheckForUnstable) { - continue; - } - } - - // Compare versions - int versionCompare = rssFile.Version.CompareTo(currentVersion); - if (versionCompare > 0) { - Log.DebugFormat("Found newer Greenshot '{0}' with version {1} published at {2} : {3}", rssFile.File, rssFile.Version, rssFile.Pubdate.ToLocalTime(), rssFile.Link); - if (_latestGreenshot == null || rssFile.Version.CompareTo(_latestGreenshot.Version) > 0) { - _latestGreenshot = rssFile; - if (rssFile.IsReleaseCandidate || rssFile.IsUnstable) { - _downloadLink = VersionHistoryLink; - } else { - _downloadLink = StableDownloadLink; - } - } - } else if (versionCompare < 0) { - Log.DebugFormat("Skipping older greenshot with version {0}", rssFile.Version); - } else if (versionCompare == 0) { - Log.DebugFormat("Found current version as exe {0} with version {1} published at {2} : {3}", rssFile.File, rssFile.Version, rssFile.Pubdate.ToLocalTime(), rssFile.Link); - } - } - } - } - } -} diff --git a/Greenshot/Helpers/UpdateService.cs b/Greenshot/Helpers/UpdateService.cs new file mode 100644 index 000000000..d1f755472 --- /dev/null +++ b/Greenshot/Helpers/UpdateService.cs @@ -0,0 +1,222 @@ +// Greenshot - a free and open source screenshot tool +// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// +// For more information see: http://getgreenshot.org/ +// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 1 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Diagnostics; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Dapplo.HttpExtensions; +using Dapplo.HttpExtensions.JsonNet; +using Greenshot.Configuration; +using Greenshot.Helpers.Entities; +using GreenshotPlugin.Core; +using GreenshotPlugin.IniFile; +using GreenshotPlugin.Interfaces; +using log4net; + +namespace Greenshot.Helpers +{ + /// + /// This processes the information, if there are updates available. + /// + public class UpdateService + { + private static readonly ILog Log = LogManager.GetLogger(typeof(UpdateService)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static readonly Uri UpdateFeed = new Uri("https://getgreenshot.org/update-feed.json"); + private static readonly Uri Downloads = new Uri("https://getgreenshot.org/downloads"); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + /// + /// Provides the current version + /// + public Version CurrentVersion { get; } + + /// + /// Provides the latest known version + /// + public Version LatestReleaseVersion { get; private set; } + + /// + /// The latest beta version + /// + public Version LatestBetaVersion { get; private set; } + + /// + /// Checks if there is an release update available + /// + public bool IsUpdateAvailable => LatestReleaseVersion > CurrentVersion; + + /// + /// Checks if there is an beta update available + /// + public bool IsBetaUpdateAvailable => LatestBetaVersion > CurrentVersion; + + /// + /// Keep track of when the update was shown, so it won't be every few minutes + /// + public DateTimeOffset LastUpdateShown = DateTimeOffset.MinValue; + + /// + /// Constructor with dependencies + /// + public UpdateService() + { + JsonNetJsonSerializer.RegisterGlobally(); + var version = FileVersionInfo.GetVersionInfo(GetType().Assembly.Location); + LatestReleaseVersion = CurrentVersion = new Version(version.FileMajorPart, version.FileMinorPart, version.FileBuildPart); + CoreConfig.LastSaveWithVersion = CurrentVersion.ToString(); + } + + /// + /// Start the background task which checks for updates + /// + public void Startup() + { + _ = BackgroundTask(() => TimeSpan.FromDays(CoreConfig.UpdateCheckInterval), UpdateCheck, _cancellationTokenSource.Token); + } + + /// + /// Stop the update checks + /// + public void Shutdown() + { + if (!_cancellationTokenSource.IsCancellationRequested) + { + _cancellationTokenSource.Cancel(); + } + } + + /// + /// This runs a periodic task in the background + /// + /// Func which returns a TimeSpan + /// Func which returns a task + /// CancellationToken + /// Task + private async Task BackgroundTask(Func intervalFactory, Func reoccurringTask, CancellationToken cancellationToken = default) + { + // Initial delay, to make sure this doesn't happen at the startup + await Task.Delay(20000, cancellationToken); + Log.Info("Starting background task to check for updates"); + await Task.Run(async () => + { + while (!cancellationToken.IsCancellationRequested) + { + var interval = intervalFactory(); + var task = reoccurringTask; + // If the check is disabled, handle that here + if (TimeSpan.Zero == interval) + { + interval = TimeSpan.FromMinutes(10); + task = c => Task.FromResult(true); + } + + try + { + await task(cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + Log.Error("Error occured when trying to check for updates.", ex); + } + + try + { + await Task.Delay(interval, cancellationToken).ConfigureAwait(false); + } + catch (TaskCanceledException) + { + // Ignore, this always happens + } + catch (Exception ex) + { + Log.Error("Error occured await for the next update check.", ex); + } + + } + }, cancellationToken).ConfigureAwait(false); + } + + /// + /// Do the actual update check + /// + /// CancellationToken + /// Task + private async Task UpdateCheck(CancellationToken cancellationToken = default) + { + Log.InfoFormat("Checking for updates from {0}", UpdateFeed); + var updateFeed = await UpdateFeed.GetAsAsync(cancellationToken); + if (updateFeed == null) + { + return; + } + + CoreConfig.LastUpdateCheck = DateTime.Now; + + ProcessFeed(updateFeed); + + // Only show if the update was shown >24 hours ago. + if (DateTimeOffset.Now.AddDays(-1) > LastUpdateShown) + { + if (IsBetaUpdateAvailable) + { + LastUpdateShown = DateTimeOffset.Now; + ShowUpdate(LatestBetaVersion); + } else if (IsUpdateAvailable) + { + LastUpdateShown = DateTimeOffset.Now; + ShowUpdate(LatestReleaseVersion); + } + } + + } + + + /// + /// This takes care of creating the toast view model, publishing it, and disposing afterwards + /// + /// Version + private void ShowUpdate(Version newVersion) + { + var notificationService = SimpleServiceProvider.Current.GetInstance(); + var message = Language.GetFormattedString(LangKey.update_found, newVersion.ToString()); + notificationService.ShowInfoMessage(message, 10000, () => Process.Start(Downloads.AbsoluteUri)); + } + + /// + /// Process the update feed to get the latest version + /// + /// + private void ProcessFeed(UpdateFeed updateFeed) + { + var latestReleaseString = Regex.Replace(updateFeed.CurrentReleaseVersion, "[a-zA-Z\\-]*", ""); + if (Version.TryParse(latestReleaseString, out var latestReleaseVersion)) + { + LatestReleaseVersion = latestReleaseVersion; + } + var latestBetaString = Regex.Replace(updateFeed.CurrentBetaVersion, "[a-zA-Z\\-]*", ""); + if (Version.TryParse(latestBetaString, out var latestBetaVersion)) + { + LatestBetaVersion = latestBetaVersion; + } + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/RssHelper.cs b/GreenshotPlugin/Core/RssHelper.cs deleted file mode 100644 index f7a48289c..000000000 --- a/GreenshotPlugin/Core/RssHelper.cs +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Net; -using System.Text.RegularExpressions; -using System.Xml; -using log4net; - -namespace GreenshotPlugin.Core { - public class RssFile { - public string File { get; } - private readonly DateTime _pubdate; - public DateTime Pubdate => _pubdate; - - public string Link { get; } - public Version Version { get; set; } - - public string Language { get; set; } - - public bool IsExe { - get { - if (File != null) { - return File.ToLower().EndsWith(".exe"); - } - return false; - } - } - - public bool IsUnstable { - get { - if (File != null) { - return File.ToLower().Contains("unstable"); - } - return false; - } - } - - public bool IsReleaseCandidate { - get { - if (File != null) { - return Regex.IsMatch(File.ToLower(), "rc[0-9]+"); - } - return false; - } - } - - public RssFile(string file, string pubdate, string link) { - File = file; - if (!DateTime.TryParse(pubdate, out _pubdate)) - { - DateTime.TryParseExact(pubdate.Replace(" UT", ""), "ddd, dd MMM yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out _pubdate); - } - Link = link; - } - } - - /// - /// Description of RssHelper. - /// - public class RssHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(RssHelper)); - private const string Rssfeed = "http://getgreenshot.org/project-feed/"; - - /// - /// This is using the HTTP HEAD Method to check if the RSS Feed is modified after the supplied date - /// - /// DateTime - /// true if the feed is newer - public static bool IsRssModifiedAfter(DateTime updateTime) { - DateTime lastModified = NetworkHelper.GetLastModified(new Uri(Rssfeed)); - if (lastModified == DateTime.MinValue) - { - // Time could not be read, just take now and add one hour to it. - // This assist BUG-1850 - lastModified = DateTime.Now.AddHours(1); - } - return updateTime.CompareTo(lastModified) < 0; - } - - /// - /// Read the Greenshot RSS feed, so we can use this information to check for updates - /// - /// List with RssFile(s) - public static IList ReadRss() { - XmlDocument rssDoc = new XmlDocument(); - try { - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(Rssfeed); - XmlTextReader rssReader = new XmlTextReader(webRequest.GetResponse().GetResponseStream()); - - // Load the XML content into a XmlDocument - rssDoc.Load(rssReader); - } catch (Exception wE) { - Log.WarnFormat("Problem reading RSS from {0}", Rssfeed); - Log.Warn(wE.Message); - return null; - } - - // Loop for the tag - XmlNode nodeRss = null; - for (int i = 0; i < rssDoc.ChildNodes.Count; i++) { - // If it is the rss tag - if (rssDoc.ChildNodes[i].Name == "rss") { - // tag found - nodeRss = rssDoc.ChildNodes[i]; - } - } - - if (nodeRss == null) { - Log.Debug("No RSS Feed!"); - return null; - } - - // Loop for the tag - XmlNode nodeChannel = null; - for (int i = 0; i < nodeRss.ChildNodes.Count; i++) { - // If it is the channel tag - if (nodeRss.ChildNodes[i].Name == "channel") { - // tag found - nodeChannel = nodeRss.ChildNodes[i]; - } - } - - if (nodeChannel == null) { - Log.Debug("No channel in RSS feed!"); - return null; - } - - IList rssFiles = new List(); - - // Loop for the , <link>, <description> and all the other tags - for (int i = 0; i < nodeChannel.ChildNodes.Count; i++) { - // If it is the item tag, then it has children tags which we will add as items to the ListView - - if (nodeChannel.ChildNodes[i].Name != "item") - { - continue; - } - XmlNode nodeItem = nodeChannel.ChildNodes[i]; - string link = nodeItem["link"]?.InnerText; - string pubdate = nodeItem["pubDate"]?.InnerText; - try { - if (link == null) - { - continue; - } - Match match = Regex.Match(Uri.UnescapeDataString(link), @"^.*\/(Greenshot.+)\/download$"); - if (!match.Success) - { - continue; - } - string file = match.Groups[1].Value; - - RssFile rssFile = new RssFile(file, pubdate, link); - if (file.EndsWith(".exe") ||file.EndsWith(".zip")) { - string version = Regex.Replace(file, @".*[a-zA-Z_]\-", string.Empty); - version = version.Replace(@"\-[a-zA-Z]+.*",""); - version = Regex.Replace(version, @"\.exe$", string.Empty); - version = Regex.Replace(version, @"\.zip$", string.Empty); - version = Regex.Replace(version, @"RC[0-9]+", string.Empty); - if (version.Trim().Length > 0) { - version = version.Replace('-','.'); - version = version.Replace(',','.'); - version = Regex.Replace(version, @"^[a-zA-Z_]*\.", string.Empty); - version = Regex.Replace(version, @"\.[a-zA-Z_]*$", string.Empty); - - try { - rssFile.Version = new Version(version); - } catch (Exception) { - Log.DebugFormat("Found invalid version {0} in file {1}", version, file); - } - } - rssFiles.Add(rssFile); - } - } catch (Exception ex) { - Log.WarnFormat("Couldn't read RSS entry for: {0}", nodeChannel["title"]?.InnerText); - Log.Warn("Reason: ", ex); - } - } - - return rssFiles; - } - } -} From 1d20faea2b64ef1b671a70a6cbd2cb4d26855199 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Sat, 25 Apr 2020 21:59:21 +0200 Subject: [PATCH 013/232] Fixed the manifest, somehow there was an error which prevented DPI support. --- Greenshot/greenshot.manifest | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Greenshot/greenshot.manifest b/Greenshot/greenshot.manifest index 77ba35d7a..89cf7a2b6 100644 --- a/Greenshot/greenshot.manifest +++ b/Greenshot/greenshot.manifest @@ -2,14 +2,14 @@ <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> <!-- Make sure windows Vista and above treat Greenshot as "DPI Aware" See: http://msdn.microsoft.com/en-us/library/ms633543.aspx --> <asmv3:application> - <asmv3:windowsSettings xmlns:ws2005="http://schemas.microsoft.com/SMI/2005/WindowsSettings" xmlns:ws2011="http://schemas.microsoft.com/SMI/2011/WindowsSettings" xmlns:ws2016="http://schemas.microsoft.com/SMI/2016/WindowsSettings" xmlns:ws2017="http://schemas.microsoft.com/SMI/2017/WindowsSettings"> - <ws2005:dpiAware>True/PM</ws2005:dpiAware> + <asmv3:windowsSettings> + <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware> <!-- Important for Greenshot, so it can enumerate immersive windows (UWP etc) from the desktop --> - <ws2011:disableWindowFiltering>true</ws2011:disableWindowFiltering> - <ws2011:printerDriverIsolation>true</ws2011:printerDriverIsolation> - <ws2016:dpiAwareness>PerMonitorV2,PerMonitor</ws2016:dpiAwareness> - <ws2016:longPathAware>true</ws2016:longPathAware> - <ws2017:gdiScaling>true</ws2017:gdiScaling> + <disableWindowFiltering xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">true</disableWindowFiltering> + <printerDriverIsolation xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">true</printerDriverIsolation> + <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2,PerMonitor</dpiAwareness> + <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware> + <gdiScaling xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">false</gdiScaling> </asmv3:windowsSettings> </asmv3:application> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> @@ -33,7 +33,7 @@ The presence of the "requestedExecutionLevel" node will disable file and registry virtualization on Vista. See: http://msdn.microsoft.com/en-us/library/aa965884%28v=vs.85%29.aspx - + Use the "level" attribute to specify the User Account Control level: asInvoker = Never prompt for elevation requireAdministrator = Always prompt for elevation From 8b45489b1123ea33adec779b32ce8dfb0f1a6a1a Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Sun, 26 Apr 2020 16:50:17 +0300 Subject: [PATCH 014/232] Zoom feature for the editor --- Greenshot/Drawing/Adorners/AbstractAdorner.cs | 17 ++ Greenshot/Drawing/Adorners/MoveAdorner.cs | 2 +- Greenshot/Drawing/Adorners/ResizeAdorner.cs | 2 +- Greenshot/Drawing/Adorners/TargetAdorner.cs | 2 +- Greenshot/Drawing/CropContainer.cs | 17 +- Greenshot/Drawing/DrawableContainer.cs | 2 +- Greenshot/Drawing/DrawableContainerList.cs | 2 +- Greenshot/Drawing/Surface.cs | 100 +++++++-- Greenshot/Drawing/TextContainer.cs | 14 +- Greenshot/Forms/ImageEditorForm.Designer.cs | 212 +++++++++++++++++- Greenshot/Forms/ImageEditorForm.cs | 167 ++++++++++++-- Greenshot/Forms/ImageEditorForm.resx | 81 +++++++ .../icons/fugue/magnifier-zoom-actual.png | Bin 0 -> 742 bytes Greenshot/icons/fugue/magnifier-zoom-fit.png | Bin 0 -> 726 bytes Greenshot/icons/fugue/magnifier-zoom-in.png | Bin 0 -> 733 bytes Greenshot/icons/fugue/magnifier-zoom-out.png | Bin 0 -> 707 bytes Greenshot/icons/fugue/magnifier-zoom.png | Bin 0 -> 676 bytes GreenshotPlugin/Interfaces/ISurface.cs | 19 +- 18 files changed, 585 insertions(+), 52 deletions(-) create mode 100644 Greenshot/icons/fugue/magnifier-zoom-actual.png create mode 100644 Greenshot/icons/fugue/magnifier-zoom-fit.png create mode 100644 Greenshot/icons/fugue/magnifier-zoom-in.png create mode 100644 Greenshot/icons/fugue/magnifier-zoom-out.png create mode 100644 Greenshot/icons/fugue/magnifier-zoom.png diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs index 0612753aa..fc3d72371 100644 --- a/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ b/Greenshot/Drawing/Adorners/AbstractAdorner.cs @@ -116,6 +116,23 @@ namespace Greenshot.Drawing.Adorners } } + /// <summary> + /// Return the bounds of the Adorner as displayed on the parent Surface + /// </summary> + protected virtual Rectangle SurfaceBounds + { + get + { + Point[] points = { Location }; + var matrix = Owner.Parent.ZoomMatrix; + if (!matrix.IsIdentity) + { + matrix.TransformPoints(points); + } + return new Rectangle(points[0].X - _size.Width / 2, points[0].Y - _size.Height / 2, _size.Width, _size.Height); + } + } + /// <summary> /// The adorner is active if the edit status is not idle or undrawn /// </summary> diff --git a/Greenshot/Drawing/Adorners/MoveAdorner.cs b/Greenshot/Drawing/Adorners/MoveAdorner.cs index ec3dcf2d3..21c42a9fa 100644 --- a/Greenshot/Drawing/Adorners/MoveAdorner.cs +++ b/Greenshot/Drawing/Adorners/MoveAdorner.cs @@ -142,7 +142,7 @@ namespace Greenshot.Drawing.Adorners { Graphics targetGraphics = paintEventArgs.Graphics; - var bounds = Bounds; + var bounds = SurfaceBounds; GraphicsState state = targetGraphics.Save(); targetGraphics.SmoothingMode = SmoothingMode.None; diff --git a/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/Greenshot/Drawing/Adorners/ResizeAdorner.cs index e75126f10..ef61b17bc 100644 --- a/Greenshot/Drawing/Adorners/ResizeAdorner.cs +++ b/Greenshot/Drawing/Adorners/ResizeAdorner.cs @@ -169,7 +169,7 @@ namespace Greenshot.Drawing.Adorners { Graphics targetGraphics = paintEventArgs.Graphics; - var bounds = Bounds; + var bounds = SurfaceBounds; GraphicsState state = targetGraphics.Save(); targetGraphics.SmoothingMode = SmoothingMode.None; diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/Greenshot/Drawing/Adorners/TargetAdorner.cs index 8ca0a91ef..23cf29d09 100644 --- a/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ b/Greenshot/Drawing/Adorners/TargetAdorner.cs @@ -96,7 +96,7 @@ namespace Greenshot.Drawing.Adorners { Graphics targetGraphics = paintEventArgs.Graphics; - var bounds = Bounds; + var bounds = SurfaceBounds; targetGraphics.FillRectangle(Brushes.Green, bounds.X, bounds.Y, bounds.Width, bounds.Height); } diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs index 2dc9761c0..f5288074d 100644 --- a/Greenshot/Drawing/CropContainer.cs +++ b/Greenshot/Drawing/CropContainer.cs @@ -56,7 +56,15 @@ namespace Greenshot.Drawing { /// We need to override the DrawingBound, return a rectangle in the size of the image, to make sure this element is always draw /// (we create a transparent brown over the complete picture) /// </summary> - public override Rectangle DrawingBounds => new Rectangle(0,0,_parent?.Width??0, _parent?.Height ?? 0); + public override Rectangle DrawingBounds { + get { + if (_parent?.Image is Image image) { + return new Rectangle(0, 0, image.Width, image.Height); + } else { + return new Rectangle(); + } + } + } public override void Draw(Graphics g, RenderMode rm) { if (_parent == null) @@ -67,17 +75,18 @@ namespace Greenshot.Drawing { using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100)); Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); Rectangle selectionRect = new Rectangle(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1); + Size imageSize = _parent.Image.Size; DrawSelectionBorder(g, selectionRect); // top - g.FillRectangle(cropBrush, new Rectangle(0, 0, _parent.Width, cropRectangle.Top)); + g.FillRectangle(cropBrush, new Rectangle(0, 0, imageSize.Width, cropRectangle.Top)); // left g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); // right - g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, _parent.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); + g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); // bottom - g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, _parent.Width, _parent.Height - (cropRectangle.Top + cropRectangle.Height))); + g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height))); } public override bool HasContextMenu { diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index 8d805b1f0..65ff42de3 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -298,7 +298,7 @@ namespace Greenshot.Drawing public virtual void Invalidate() { if (Status != EditStatus.UNDRAWN) { - _parent?.Invalidate(DrawingBounds); + _parent?.InvalidateElements(DrawingBounds); } } diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs index d3c325f5b..17b879538 100644 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ b/Greenshot/Drawing/DrawableContainerList.cs @@ -286,7 +286,7 @@ namespace Greenshot.Drawing { { region = Rectangle.Union(region, dc.DrawingBounds); } - Parent.Invalidate(region); + Parent.InvalidateElements(region); } /// <summary> /// Indicates whether the given list of elements can be pulled up, diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index bd56db3a2..5c38bea8e 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -298,10 +298,34 @@ namespace Greenshot.Drawing set { _image = value; - Size = _image.Size; + UpdateSize(); } } + [NonSerialized] + private float _zoomFactor = 1.0f; + public float ZoomFactor + { + get => _zoomFactor; + set + { + _zoomFactor = value; + ZoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0); + UpdateSize(); + } + } + + public Matrix ZoomMatrix { get; private set; } = new Matrix(1, 0, 0, 1, 0, 0); + + /// <summary> + /// Sets the surface size as zoomed image size. + /// </summary> + private void UpdateSize() + { + var size = _image.Size; + Size = new Size((int)(size.Width * _zoomFactor), (int)(size.Height * _zoomFactor)); + } + /// <summary> /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements. /// e.g. used to decided if and which line thickness is shown when multiple elements are selected. @@ -447,7 +471,6 @@ namespace Greenshot.Drawing // Set new values Image = newImage; - Size = newImage.Size; _modified = true; } @@ -1086,6 +1109,12 @@ namespace Greenshot.Drawing return null; } + /// <summary> + /// Translate mouse coordinates as if they were applied directly to unscaled image. + /// </summary> + private MouseEventArgs InverseZoomMouseCoordinates(MouseEventArgs e) + => new MouseEventArgs(e.Button, e.Clicks, (int)(e.X / _zoomFactor), (int)(e.Y / _zoomFactor), e.Delta); + /// <summary> /// This event handler is called when someone presses the mouse on a surface. /// </summary> @@ -1093,6 +1122,7 @@ namespace Greenshot.Drawing /// <param name="e"></param> private void SurfaceMouseDown(object sender, MouseEventArgs e) { + e = InverseZoomMouseCoordinates(e); // Handle Adorners var adorner = FindActiveAdorner(e); @@ -1187,6 +1217,7 @@ namespace Greenshot.Drawing /// <param name="e"></param> private void SurfaceMouseUp(object sender, MouseEventArgs e) { + e = InverseZoomMouseCoordinates(e); // Handle Adorners var adorner = FindActiveAdorner(e); @@ -1276,6 +1307,8 @@ namespace Greenshot.Drawing /// <param name="e"></param> private void SurfaceMouseMove(object sender, MouseEventArgs e) { + e = InverseZoomMouseCoordinates(e); + // Handle Adorners var adorner = FindActiveAdorner(e); if (adorner != null) @@ -1371,6 +1404,25 @@ namespace Greenshot.Drawing return GetImage(RenderMode.EXPORT); } + private Rectangle ZoomClipRectangle(Rectangle rc, double scale) + => new Rectangle( + (int)(rc.X * scale), + (int)(rc.Y * scale), + (int)((rc.Width + 1) * scale) + 1, // making sure to redraw enough pixels when moving scaled image + (int)((rc.Height + 1) * scale) + 1 + ); + + private RectangleF ZoomClipRectangle(RectangleF rc, double scale) + => new RectangleF( + (float)Math.Floor(rc.X * scale), + (float)Math.Floor(rc.Y * scale), + (float)Math.Ceiling(rc.Width * scale), + (float)Math.Ceiling(rc.Height * scale) + ); + + public void InvalidateElements(Rectangle rc) + => Invalidate(ZoomClipRectangle(rc, _zoomFactor)); + /// <summary> /// This is the event handler for the Paint Event, try to draw as little as possible! /// </summary> @@ -1379,14 +1431,16 @@ namespace Greenshot.Drawing private void SurfacePaint(object sender, PaintEventArgs paintEventArgs) { Graphics targetGraphics = paintEventArgs.Graphics; - Rectangle clipRectangle = paintEventArgs.ClipRectangle; - if (Rectangle.Empty.Equals(clipRectangle)) + Rectangle targetClipRectangle = paintEventArgs.ClipRectangle; + if (Rectangle.Empty.Equals(targetClipRectangle)) { LOG.Debug("Empty cliprectangle??"); return; } + Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, 1.0 / _zoomFactor); - if (_elements.HasIntersectingFilters(clipRectangle)) + bool isZoomedIn = ZoomFactor > 1f; + if (_elements.HasIntersectingFilters(imageClipRectangle) || isZoomedIn) { if (_buffer != null) { @@ -1409,18 +1463,38 @@ namespace Greenshot.Drawing //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; //graphics.CompositingQuality = CompositingQuality.HighQuality; //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - DrawBackground(graphics, clipRectangle); - graphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); - graphics.SetClip(targetGraphics); - _elements.Draw(graphics, _buffer, RenderMode.EDIT, clipRectangle); + DrawBackground(graphics, imageClipRectangle); + graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + graphics.SetClip(ZoomClipRectangle(targetGraphics.ClipBounds, 1.0 / _zoomFactor)); + _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle); } - targetGraphics.DrawImage(_buffer, clipRectangle, clipRectangle, GraphicsUnit.Pixel); + targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); + if (isZoomedIn) + { + var state = targetGraphics.Save(); + targetGraphics.SmoothingMode = SmoothingMode.None; + targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; + targetGraphics.CompositingQuality = CompositingQuality.HighQuality; + targetGraphics.PixelOffsetMode = PixelOffsetMode.None; + + targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + + targetGraphics.Restore(state); + } + else + { + targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + } + targetGraphics.ResetTransform(); } else { - DrawBackground(targetGraphics, clipRectangle); - targetGraphics.DrawImage(Image, clipRectangle, clipRectangle, GraphicsUnit.Pixel); - _elements.Draw(targetGraphics, null, RenderMode.EDIT, clipRectangle); + DrawBackground(targetGraphics, targetClipRectangle); + + targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); + targetGraphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); + targetGraphics.ResetTransform(); } // No clipping for the adorners diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index 0f4866d71..bd4c75274 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -442,14 +442,20 @@ namespace Greenshot.Drawing correction = -1; } Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - _textBox.Left = absRectangle.Left + lineWidth; - _textBox.Top = absRectangle.Top + lineWidth; + Point[] points = { absRectangle.Location, absRectangle.Location + absRectangle.Size }; + var matrix = Parent.ZoomMatrix; + if (!matrix.IsIdentity) + { + matrix.TransformPoints(points); + } + _textBox.Left = points[0].X + lineWidth; + _textBox.Top = points[0].Y + lineWidth; if (lineThickness <= 1) { lineWidth = 0; } - _textBox.Width = absRectangle.Width - 2 * lineWidth + correction; - _textBox.Height = absRectangle.Height - 2 * lineWidth + correction; + _textBox.Width = points[1].X - points[0].X - 2 * lineWidth + correction; + _textBox.Height = points[1].Y - points[0].Y - 2 * lineWidth + correction; } public override void ApplyBounds(RectangleF newBounds) diff --git a/Greenshot/Forms/ImageEditorForm.Designer.cs b/Greenshot/Forms/ImageEditorForm.Designer.cs index 9a653cc21..5789a19a6 100644 --- a/Greenshot/Forms/ImageEditorForm.Designer.cs +++ b/Greenshot/Forms/ImageEditorForm.Designer.cs @@ -194,6 +194,26 @@ namespace Greenshot { this.alignLeftToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.alignCenterToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.alignRightToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.zoomMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); + this.zoomInMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoomOutMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoomMenuSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.zoomBestFitMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoomMenuSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this.zoom25MenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoom50MenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoom66MenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoom75MenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoomMenuSeparator3 = new System.Windows.Forms.ToolStripSeparator(); + this.zoomActualSizeMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoomMenuSeparator4 = new System.Windows.Forms.ToolStripSeparator(); + this.zoom200MenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoom300MenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoom400MenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoom600MenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.zoomStatusDropDownBtn = new System.Windows.Forms.ToolStripDropDownButton(); + this.zoomMainMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.statusStripSpacer = new System.Windows.Forms.ToolStripStatusLabel(); this.topToolStripContainer.BottomToolStripPanel.SuspendLayout(); this.topToolStripContainer.ContentPanel.SuspendLayout(); this.topToolStripContainer.LeftToolStripPanel.SuspendLayout(); @@ -203,6 +223,7 @@ namespace Greenshot { this.tableLayoutPanel1.SuspendLayout(); this.toolsToolStrip.SuspendLayout(); this.menuStrip1.SuspendLayout(); + this.zoomMenuStrip.SuspendLayout(); this.destinationsToolStrip.SuspendLayout(); this.propertiesToolStrip.SuspendLayout(); this.fileSavedStatusContextMenu.SuspendLayout(); @@ -238,7 +259,9 @@ namespace Greenshot { this.statusStrip1.Dock = System.Windows.Forms.DockStyle.None; this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.dimensionsLabel, - this.statusLabel}); + this.statusLabel, + this.statusStripSpacer, + this.zoomStatusDropDownBtn}); this.statusStrip1.Location = new System.Drawing.Point(0, 0); this.statusStrip1.Name = "statusStrip1"; this.statusStrip1.Size = new System.Drawing.Size(785, 24); @@ -538,6 +561,7 @@ namespace Greenshot { this.editToolStripMenuItem, this.objectToolStripMenuItem, this.pluginToolStripMenuItem, + this.zoomMainMenuItem, this.helpToolStripMenuItem}); this.menuStrip1.Name = "menuStrip1"; this.menuStrip1.BackColor = System.Drawing.SystemColors.Control; @@ -1624,6 +1648,171 @@ namespace Greenshot { this.alignRightToolStripMenuItem.Name = "alignRightToolStripMenuItem"; this.alignRightToolStripMenuItem.Tag = System.Drawing.StringAlignment.Far; // + // zoomMainMenuItem + // + this.zoomMainMenuItem.DropDown = this.zoomMenuStrip; + this.zoomMainMenuItem.Name = "zoomMainMenuItem"; + this.zoomMainMenuItem.Size = new System.Drawing.Size(51, 20); + this.zoomMainMenuItem.Text = "Zoom"; + // + // zoomMenuStrip + // + this.zoomMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.zoomInMenuItem, + this.zoomOutMenuItem, + this.zoomMenuSeparator1, + this.zoomBestFitMenuItem, + this.zoomMenuSeparator2, + this.zoom25MenuItem, + this.zoom50MenuItem, + this.zoom66MenuItem, + this.zoom75MenuItem, + this.zoomMenuSeparator3, + this.zoomActualSizeMenuItem, + this.zoomMenuSeparator4, + this.zoom200MenuItem, + this.zoom300MenuItem, + this.zoom400MenuItem, + this.zoom600MenuItem}); + this.zoomMenuStrip.Name = "zoomMenuStrip"; + this.zoomMenuStrip.Size = new System.Drawing.Size(210, 292); + // + // zoomInMenuItem + // + this.zoomInMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomInMenuItem.Image"))); + this.zoomInMenuItem.Name = "zoomInMenuItem"; + this.zoomInMenuItem.ShortcutKeyDisplayString = "Ctrl++"; + this.zoomInMenuItem.Size = new System.Drawing.Size(209, 22); + this.zoomInMenuItem.Text = "Zoom In"; + this.zoomInMenuItem.Click += new System.EventHandler(this.ZoomInMenuItemClick); + // + // zoomOutMenuItem + // + this.zoomOutMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomOutMenuItem.Image"))); + this.zoomOutMenuItem.Name = "zoomOutMenuItem"; + this.zoomOutMenuItem.ShortcutKeyDisplayString = "Ctrl+-"; + this.zoomOutMenuItem.Size = new System.Drawing.Size(209, 22); + this.zoomOutMenuItem.Text = "Zoom Out"; + this.zoomOutMenuItem.Click += new System.EventHandler(this.ZoomOutMenuItemClick); + // + // zoomMenuSeparator1 + // + this.zoomMenuSeparator1.Name = "zoomMenuSeparator1"; + this.zoomMenuSeparator1.Size = new System.Drawing.Size(206, 6); + // + // zoomBestFitMenuItem + // + this.zoomBestFitMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomBestFitMenuItem.Image"))); + this.zoomBestFitMenuItem.Name = "zoomBestFitMenuItem"; + this.zoomBestFitMenuItem.ShortcutKeyDisplayString = "Ctrl+*"; + this.zoomBestFitMenuItem.Size = new System.Drawing.Size(209, 22); + this.zoomBestFitMenuItem.Text = "Best Fit"; + this.zoomBestFitMenuItem.Click += new System.EventHandler(this.ZoomBestFitMenuItemClick); + // + // zoomMenuSeparator2 + // + this.zoomMenuSeparator2.Name = "zoomMenuSeparator2"; + this.zoomMenuSeparator2.Size = new System.Drawing.Size(206, 6); + // + // zoom25MenuItem + // + this.zoom25MenuItem.Name = "zoom25MenuItem"; + this.zoom25MenuItem.Size = new System.Drawing.Size(209, 22); + this.zoom25MenuItem.Tag = "25"; + this.zoom25MenuItem.Text = "25%"; + this.zoom25MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); + // + // zoom50MenuItem + // + this.zoom50MenuItem.Name = "zoom50MenuItem"; + this.zoom50MenuItem.Size = new System.Drawing.Size(209, 22); + this.zoom50MenuItem.Tag = "50"; + this.zoom50MenuItem.Text = "50%"; + this.zoom50MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); + // + // zoom66MenuItem + // + this.zoom66MenuItem.Name = "zoom66MenuItem"; + this.zoom66MenuItem.Size = new System.Drawing.Size(209, 22); + this.zoom66MenuItem.Tag = "66"; + this.zoom66MenuItem.Text = "66%"; + this.zoom66MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); + // + // zoom75MenuItem + // + this.zoom75MenuItem.Name = "zoom75MenuItem"; + this.zoom75MenuItem.Size = new System.Drawing.Size(209, 22); + this.zoom75MenuItem.Tag = "75"; + this.zoom75MenuItem.Text = "75%"; + this.zoom75MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); + // + // zoomMenuSeparator3 + // + this.zoomMenuSeparator3.Name = "zoomMenuSeparator3"; + this.zoomMenuSeparator3.Size = new System.Drawing.Size(206, 6); + // + // zoomActualSizeMenuItem + // + this.zoomActualSizeMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomActualSizeMenuItem.Image"))); + this.zoomActualSizeMenuItem.Name = "zoomActualSizeMenuItem"; + this.zoomActualSizeMenuItem.ShortcutKeyDisplayString = "Ctrl+/"; + this.zoomActualSizeMenuItem.Size = new System.Drawing.Size(209, 22); + this.zoomActualSizeMenuItem.Tag = "100"; + this.zoomActualSizeMenuItem.Text = "100% - Actual Size"; + this.zoomActualSizeMenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); + // + // zoomMenuSeparator4 + // + this.zoomMenuSeparator4.Name = "zoomMenuSeparator4"; + this.zoomMenuSeparator4.Size = new System.Drawing.Size(206, 6); + // + // zoom200MenuItem + // + this.zoom200MenuItem.Name = "zoom200MenuItem"; + this.zoom200MenuItem.Size = new System.Drawing.Size(209, 22); + this.zoom200MenuItem.Tag = "200"; + this.zoom200MenuItem.Text = "200%"; + this.zoom200MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); + // + // zoom300MenuItem + // + this.zoom300MenuItem.Name = "zoom300MenuItem"; + this.zoom300MenuItem.Size = new System.Drawing.Size(209, 22); + this.zoom300MenuItem.Tag = "300"; + this.zoom300MenuItem.Text = "300%"; + this.zoom300MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); + // + // zoom400MenuItem + // + this.zoom400MenuItem.Name = "zoom400MenuItem"; + this.zoom400MenuItem.Size = new System.Drawing.Size(209, 22); + this.zoom400MenuItem.Tag = "400"; + this.zoom400MenuItem.Text = "400%"; + this.zoom400MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); + // + // zoom600MenuItem + // + this.zoom600MenuItem.Name = "zoom600MenuItem"; + this.zoom600MenuItem.Size = new System.Drawing.Size(209, 22); + this.zoom600MenuItem.Tag = "600"; + this.zoom600MenuItem.Text = "600%"; + this.zoom600MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); + // + // statusStripSpacer + // + this.statusStripSpacer.Name = "statusStripSpacer"; + this.statusStripSpacer.Size = new System.Drawing.Size(599, 19); + this.statusStripSpacer.Spring = true; + // + // zoomStatusDropDownBtn + // + this.zoomStatusDropDownBtn.DropDown = this.zoomMenuStrip; + this.zoomStatusDropDownBtn.Image = ((System.Drawing.Image)(resources.GetObject("zoomStatusDropDownBtn.Image"))); + this.zoomStatusDropDownBtn.ImageTransparentColor = System.Drawing.Color.Magenta; + this.zoomStatusDropDownBtn.Name = "zoomStatusDropDownBtn"; + this.zoomStatusDropDownBtn.Size = new System.Drawing.Size(64, 22); + this.zoomStatusDropDownBtn.Text = "100%"; + // // ImageEditorForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); @@ -1645,6 +1834,7 @@ namespace Greenshot { this.statusStrip1.ResumeLayout(true); this.tableLayoutPanel1.ResumeLayout(true); this.toolsToolStrip.ResumeLayout(true); + this.zoomMenuStrip.ResumeLayout(false); this.menuStrip1.ResumeLayout(true); this.destinationsToolStrip.ResumeLayout(true); this.propertiesToolStrip.ResumeLayout(true); @@ -1794,5 +1984,25 @@ namespace Greenshot { private Greenshot.Controls.ToolStripColorButton btnLineColor; private GreenshotPlugin.Controls.GreenshotToolStripMenuItem autoCropToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator17; + private System.Windows.Forms.ContextMenuStrip zoomMenuStrip; + private System.Windows.Forms.ToolStripMenuItem zoomInMenuItem; + private System.Windows.Forms.ToolStripMenuItem zoomOutMenuItem; + private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator1; + private System.Windows.Forms.ToolStripMenuItem zoomBestFitMenuItem; + private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator2; + private System.Windows.Forms.ToolStripMenuItem zoom25MenuItem; + private System.Windows.Forms.ToolStripMenuItem zoom50MenuItem; + private System.Windows.Forms.ToolStripMenuItem zoom66MenuItem; + private System.Windows.Forms.ToolStripMenuItem zoom75MenuItem; + private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator3; + private System.Windows.Forms.ToolStripMenuItem zoomActualSizeMenuItem; + private System.Windows.Forms.ToolStripSeparator zoomMenuSeparator4; + private System.Windows.Forms.ToolStripMenuItem zoom200MenuItem; + private System.Windows.Forms.ToolStripMenuItem zoom300MenuItem; + private System.Windows.Forms.ToolStripMenuItem zoom400MenuItem; + private System.Windows.Forms.ToolStripMenuItem zoom600MenuItem; + private System.Windows.Forms.ToolStripDropDownButton zoomStatusDropDownBtn; + private System.Windows.Forms.ToolStripMenuItem zoomMainMenuItem; + private System.Windows.Forms.ToolStripStatusLabel statusStripSpacer; } } diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index bcb8c275c..dd9ec94e1 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -66,6 +66,12 @@ namespace Greenshot { // whether part of the editor controls are disabled depending on selected item(s) private bool _controlsDisabledDueToConfirmable; + /// <summary> + /// All provided zoom values (in percents) in ascending order. + /// </summary> + private readonly int[] ZOOM_VALUES = new[] { 25, 50, 66, 75, 100, 200, 300, 400, 600 }; + private int _zoomValue = 100; + /// <summary> /// An Implementation for the IImageEditor, this way Plugins have access to the HWND handles wich can be used with Win32 API calls. /// </summary> @@ -420,20 +426,14 @@ namespace Greenshot { /// </summary> /// <param name="sender"></param> /// <param name="e"></param> - private void SurfaceSizeChanged(object sender, EventArgs e) { - if (EditorConfiguration.MatchSizeToCapture) { - // Set editor's initial size to the size of the surface plus the size of the chrome - Size imageSize = Surface.Image.Size; - Size currentFormSize = Size; - Size currentImageClientSize = panel1.ClientSize; - int minimumFormWidth = 650; - int minimumFormHeight = 530; - int newWidth = Math.Max(minimumFormWidth, currentFormSize.Width - currentImageClientSize.Width + imageSize.Width); - int newHeight = Math.Max(minimumFormHeight, currentFormSize.Height - currentImageClientSize.Height + imageSize.Height); - Size = new Size(newWidth, newHeight); + private void SurfaceSizeChanged(object sender, EventArgs e) + { + if (EditorConfiguration.MatchSizeToCapture) + { + Size = GetOptimalWindowSize(); } dimensionsLabel.Text = Surface.Image.Width + "x" + Surface.Image.Height; - ImageEditorFormResize(sender, new EventArgs()); + AlignCanvasPositionAfterResize(); } public ISurface Surface { @@ -860,15 +860,34 @@ namespace Greenshot { case Keys.Oemcomma: // Rotate CCW Ctrl + , RotateCcwToolstripButtonClick(sender, e); break; - case Keys.OemPeriod: // Rotate CW Ctrl + . + case Keys.OemPeriod: // Rotate CW Ctrl + . RotateCwToolstripButtonClick(sender, e); break; - case Keys.Add: // Ctrl + + - case Keys.Oemplus: // Ctrl + + + case Keys.Add: // Ctrl + Num+ + case Keys.Oemplus: // Ctrl + + + ZoomInMenuItemClick(sender, e); + break; + case Keys.Subtract: // Ctrl + Num- + case Keys.OemMinus: // Ctrl + - + ZoomOutMenuItemClick(sender, e); + break; + case Keys.Divide: // Ctrl + Num/ + case Keys.OemQuestion: // Ctrl + / (?) + ZoomSetValueMenuItemClick(zoomActualSizeMenuItem, e); + break; + case Keys.Multiply: // Ctrl + Num* + case Keys.D8: // Ctrl + 8 (*) + ZoomBestFitMenuItemClick(sender, e); + break; + } + } else if (e.Modifiers.Equals(Keys.Control | Keys.Shift)) { + switch (e.KeyCode) { + case Keys.Add: // Ctrl + Shift + Num+ + case Keys.Oemplus: // Ctrl + Shift + + EnlargeCanvasToolStripMenuItemClick(sender, e); break; - case Keys.Subtract: // Ctrl + - - case Keys.OemMinus: // Ctrl + - + case Keys.Subtract: // Ctrl + Shift + Num- + case Keys.OemMinus: // Ctrl + Shift + - ShrinkCanvasToolStripMenuItemClick(sender, e); break; } @@ -1444,28 +1463,130 @@ namespace Greenshot { } private void ImageEditorFormResize(object sender, EventArgs e) { + AlignCanvasPositionAfterResize(); + } + + private void AlignCanvasPositionAfterResize() { if (Surface?.Image == null || panel1 == null) { return; } - Size imageSize = Surface.Image.Size; - Size currentClientSize = panel1.ClientSize; var canvas = Surface as Control; + Size canvasSize = canvas.Size; + Size currentClientSize = panel1.ClientSize; Panel panel = (Panel) canvas?.Parent; if (panel == null) { return; } int offsetX = -panel.HorizontalScroll.Value; int offsetY = -panel.VerticalScroll.Value; - if (currentClientSize.Width > imageSize.Width) { - canvas.Left = offsetX + (currentClientSize.Width - imageSize.Width) / 2; + if (currentClientSize.Width > canvasSize.Width) { + canvas.Left = offsetX + (currentClientSize.Width - canvasSize.Width) / 2; } else { canvas.Left = offsetX + 0; } - if (currentClientSize.Height > imageSize.Height) { - canvas.Top = offsetY + (currentClientSize.Height - imageSize.Height) / 2; + if (currentClientSize.Height > canvasSize.Height) { + canvas.Top = offsetY + (currentClientSize.Height - canvasSize.Height) / 2; } else { canvas.Top = offsetY + 0; } } + + /// <summary> + /// Compute a size as a sum of surface size and chrome. + /// Upper bound is working area of the screen. Lower bound is fixed value. + /// </summary> + private Size GetOptimalWindowSize() { + var surfaceSize = (Surface as Control).Size; + var chromeSize = GetChromeSize(); + var newWidth = chromeSize.Width + surfaceSize.Width; + var newHeight = chromeSize.Height + surfaceSize.Height; + + // Upper bound. Don't make it bigger than the available working area. + var screen = Screen.FromControl(this); + var workingArea = screen.WorkingArea; + newWidth = Math.Min(newWidth, workingArea.Width); + newHeight = Math.Min(newHeight, workingArea.Height); + + // Lower bound. Don't make it smaller than a fixed value. + int minimumFormWidth = 650; + int minimumFormHeight = 530; + newWidth = Math.Max(minimumFormWidth, newWidth); + newHeight = Math.Max(minimumFormHeight, newHeight); + + return new Size(newWidth, newHeight); + } + + private Size GetChromeSize() + => Size - panel1.ClientSize; + + /// <summary> + /// Compute a size that the form can take without getting out of working area of the screen. + /// </summary> + private Size GetAvailableScreenSpace() { + var screen = Screen.FromControl(this); + var screenBounds = screen.Bounds; + var workingArea = screen.WorkingArea; + if (Left > screenBounds.Left && Top > screenBounds.Top) { + return new Size(workingArea.Width - Left, workingArea.Height - Top); + } else { + return workingArea.Size; + } + } + + private void ZoomInMenuItemClick(object sender, EventArgs e) { + var nextIndex = Array.FindIndex(ZOOM_VALUES, v => v > _zoomValue); + var nextValue = nextIndex < 0 ? ZOOM_VALUES[ZOOM_VALUES.Length - 1] : ZOOM_VALUES[nextIndex]; + + ZoomSetValue(nextValue); + } + + private void ZoomOutMenuItemClick(object sender, EventArgs e) { + var nextIndex = Array.FindLastIndex(ZOOM_VALUES, v => v < _zoomValue); + var nextValue = nextIndex < 0 ? ZOOM_VALUES[0] : ZOOM_VALUES[nextIndex]; + + ZoomSetValue(nextValue); + } + + private void ZoomSetValueMenuItemClick(object sender, EventArgs e) { + var senderMenuItem = (ToolStripMenuItem)sender; + int zoomPercent = int.Parse((string)senderMenuItem.Tag); + + ZoomSetValue(zoomPercent); + } + + private void ZoomBestFitMenuItemClick(object sender, EventArgs e) { + var maxWindowSize = GetAvailableScreenSpace(); + var chromeSize = GetChromeSize(); + var maxImageSize = maxWindowSize - chromeSize; + var imageSize = Surface.Image.Size; + + static bool isFit(int zoom, int source, int boundary) + => source * zoom / 100 <= boundary; + + var nextValue = Array.FindLast( + ZOOM_VALUES, + zoom => isFit(zoom, imageSize.Width, maxImageSize.Width) + && isFit(zoom, imageSize.Height, maxImageSize.Height) + ); + + ZoomSetValue(nextValue); + } + + private void ZoomSetValue(int value) { + _zoomValue = value; + Surface.ZoomFactor = 1f * value / 100; + + // Update zoom controls + string valueString = value.ToString(); + zoomStatusDropDownBtn.Text = valueString + "%"; + foreach (var item in zoomMenuStrip.Items) { + if (item is ToolStripMenuItem menuItem) { + menuItem.Checked = menuItem.Tag as string == valueString; + } + } + + Size = GetOptimalWindowSize(); + AlignCanvasPositionAfterResize(); + } } } diff --git a/Greenshot/Forms/ImageEditorForm.resx b/Greenshot/Forms/ImageEditorForm.resx index e4188604b..025543b10 100644 --- a/Greenshot/Forms/ImageEditorForm.resx +++ b/Greenshot/Forms/ImageEditorForm.resx @@ -937,6 +937,84 @@ BIhPAPEZIL7CAAQ6fptA+D+IJskFIM2cgtoMKm6rQfg/iEY3oB9oC8jWozBbgXquAvFykGYQkDJuZlBy WQvC/0E0QRfANIJoLmF9BnXPHTD8H8QmyQD9wBMMSPg/iE20ATK6uQwWUTeR8X8Qn2gDHJOfM6Dh/yA+ igHkZijqZSZyXQAA4IG1TpHFZ2gAAAAASUVORK5CYII= +</value> + </data> + <data name="zoomInMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m + dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJKSURBVDhPY/j//z+DX8FVDBxZ/ZAhqeWVRkrbm7lA + fB+If0HpuSBxkDxIHU4DIqruB0bXPrzftODpia0n3+668/zLiaNXPh3oXf7yFEgcJA9SBzbALeMsCvbI + Oq/hk3fx/rSND3ccufH60MuPP259+vb7+etPP28/evPt7PztT3b5AuVB6sAGWMUcQMdz83svnth96cWB + q48/ngBpBor9B9FP3n47d+3JpxMlEy6dAqkDG6Djtwkd35+77e72M/feXbj78suDd19+fQCK/QfRID5I + fOme+3tA6sAGqLitRse/dp5/fgCkGMj+j44/fvv97PC118eA7F9gA5Rc1qLj+wu239sNsgmk+Ofvv5+B + Yv9BNDgsPv68tWrfw0MgdWAD1D13oOO52W3nz+6/+urw/ZdfT4M0AcXgYQAMyHPF3RcvgdSBDXBwcGCw + s7NjsLW1ZbCxsWEwd8q0Mgo+/GLe5gdnbz77fBoU+mCbgfSz998vbtj/6pRxyMn7egHHILGAbIC1tbU8 + 0JDijsl7/ltFXnjVOOP5pZNXvpx+/u7H9VNXv5zpmPvymk3crfvmkdcDDYPPQNIBzACgRi03N/eaHTv2 + /BcVFWtWs2qxc0x+PheI7wPxLyg91z7xiYZF1E0GFAOAtlsEBga3HTly5r+iolIPCwuLqpJxCYNTyisM + DDSAAcUAoO3eCQkpEy5evPtfT89gGlCzMRAzEG2Aubl5ya1br/7b2zvPY2VldQFpJskAPT09LRERkRag + 5hiYZhAWlrEhzgDy8X8GAJItIDq7n94UAAAAAElFTkSuQmCC +</value> + </data> + <data name="zoomOutMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m + dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIySURBVDhPY/j//z+DtrY2g559IYNfwVU4jqx+yJDU + 8kojpe3NXCC+D8S/oPRckDhIHqQObACyRhiOqLofGF378H7Tgqcntp58u+vO8y8njl75dKB3+ctTIHGQ + PEgd2AC3jLMo2CPrvIZP3sX70zY+3HHkxutDj958O/vk7bdzIAxiz9/+ZJcvUB6kDmyAVcwBdDw3v/fi + id2XXhy4+vjjCZhmGL725NOJkgmXToHUgQ3Q8duEju/P3XZ3+5l77y7cffnlAToGiS/dc38PSB3YABW3 + 1ej4187zzw+AFAPZ/9Hxx2+/nx2+9voYkP0LbICSy1p0fH/B9nu7QTaBFH/69vs5Mn798eetVfseHgKp + Axug7rkDHc/Nbjt/dv/VV4fvv/x6Gj0MgAF5rrj74iWQOrABDg4ODHZ2dgy2trYMNjY2DOZOmVZGwYdf + zNv84OzNZ59RDHj2/vvFDftfnTIOOXlfL+AYJBaQDbC2tpYHGlLcMXnPf6vIC68aZzy/dPLKl9PP3/24 + furqlzMdc19es4m7dd888nqgYfAZSDqAGQDUqOXm5l6zY8ee/6KiYs1qVi12jsnP5wLxfSD+BaXn2ic+ + 0bCIusmAYgDQdovAwOC2I0fO/FdUVOphYWFRVTIuYXBKeYWBgQYwoBgAtN07ISFlwsWLd//r6RlMA2o2 + BmIGog0wNzcvuXXr1X97e+d5rKysLiDNJBmgp6enJSIi0gLUHAPTDMLCMjbEGUA+/s8AAJUZIgOF4ptY + AAAAAElFTkSuQmCC +</value> + </data> + <data name="zoomBestFitMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m + dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJISURBVDhPnZLLaxNRFIfvIvkLTF0J0uAjNDKoWaTk + bS1RUYshLowWqZqFD/BBs/KxUEMoaKEgiJuRbqRQ6UaojTqUYGpJYmpMSFuMxklK2mmmmba2kzSZINd7 + pk1p4qa6+Djn3vs73x24gzDGSKvVIsp6B3XcntzEdS+LLnt5jdtXoAksQdqoNOzDOeRkwdbBGufuso4L + D7Lso/7Z0HBYeP+DE0OfkiuB3oF8BPbhHHKywH51oo7j12OaUzfj7ADDhTJ8MbNclOZWSlUOgH5wdD50 + mpxDThYYOgON0Ld646F0XsyQHgOFpYpcgZywNuPpS0QgJwsOdLxphKXfpkdAQHq8KErL0EOFNfSvGJaB + nCzYY3/diPQuxgUgmBfWMHx6Tih9gQrrX6XqXHBqYRxyskDdPtQI2z/y8wMISI8r1d+rMAwV1iAYHM1+ + hJws2H/C3wh9wxebyC4UZ0iPAV4oyxVYKkpc95N4AnKywGazIYvFgsxmMzKZTEjfds1w2BmcH2JmvxdW + K5svAIjlKj8cLCR1Z8MsdWZ8/RW2CoxG424i6e55xmCD6yv/8AWXCCfFz9xieToyKUZ76PyU6WKK1bum + HYec0fX/oCYggy12+7H7fj+Dm5p2Pt5n8FqOXOFoAkuQNiptvZTTtJ7/huoE5PZWh8PpGxuL4uZm9VOF + QrFXrfOgNjf/F0SA6gTk9pNdXe6+eDyNKergczKsI6BtC/R6vSeV4rHVevSlUqlsh+F/ElAU1aJSqbxk + uLM2DOzYZdqe4P/B6A86Ah9NBTgWLgAAAABJRU5ErkJggg== +</value> + </data> + <data name="zoomActualSizeMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m + dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJXSURBVDhPnZLda1JhHMefC/0Lcl0FMelFZhwqLxy+ + t4YV1UjsImvFKi+qQS9MuujlohIZ1GAQjG7O2k0ERdALpW3SZNpQ0zllall6NKwzj1OWczId8fT8zuaY + drO6+PBwvs/393kezjkIY4ykUimitNdQ19XoGqabGXTOyknMtjmawBBqqysNOexDjxesH6xz4gZjOHU7 + w9wd+eF96yuMfmPL3o8zJdfA05wfctiHHi/QXwg2cPBSSHLkcpgZepVxeD7nJ+YXaz9LlWU2X6p+/T5X + CT62Z0ePkn3o8QJFt6sZ+spA2DsWmXVlC5VMrzWESYZBQp6nYtmS1zIY8UOPF+zqet0MQ79L2kEQSBWn + i+XaPMlwMldOQwY8cTJO6PGCbfrnzdTeh1i+CMDJJFu7AeCO5SehxwvEnS+aYUbsqTEY5n4tJarLvxdI + hmGF9wCCZx8yE9DjBTsPOZqhe22h4HiUc8+VqtnT1/2YZBhWuAV5kVN998MR6PECnU6HNBoNUqvVSKVS + IXnHRcVeo3t2+E06mOYW4zBUp7BQTb0c5/yy4z6GOja58hXWC5RK5VYi6et/6MQK0zR35xEb8c2UP7HF + pbg/Wg7007mY6kyCkZvihj3GwMp/UBeQwTa9/sAth8OJW1o239uhsGr2nWdpAkOora609mxW0n7yC2oQ + kNPbDQajzeMJ4NZW8QOBQLBdLLOgDjP3F0SAGgTk9MM9PebBcDiJKWr3EBmWEdCGBXK53JJIcFir3T8s + FAo7YfifBBRFtYlEIisZ7q4PA5u2qDYm+H8w+gNv9h/ta4LougAAAABJRU5ErkJggg== +</value> + </data> + <data name="zoomStatusDropDownBtn.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHYSURBVDhPY8AH4ltfa6S0vZ6b3Pr6PhD/AtEgPkgcqgQ3 + iKi6Hxhd8/B+0/ynJ7acfLvrzrPPJ45c+Xigd9nLUyBxkDxUKSZwyzmj4Z176f7UjQ92HL7++tCjN9/O + Pn7z7RwIg9jztz3e5QOUB6mDakEFVjH75xb0Xjyx++KLA1cefToO0wzD1558OlE84eJpkDqoFlSg7bvp + /pytd3aADMCFl+6+vwekDqoFFSi7rf614/xzuGJ0Fzx+++3soauvjoHUQbWgAiXnNffn77i3G6wZqBib + ASv3PTgEUgfVggrUPLfPzWo/d3bv5VeH77/4fBrdgEevv54r7rpwCaQOqgUVWDpmWhkGHXoxf/P9szef + fkIx4Nn7b5fW73t5yjj45H2doKOYsWBpaSlvbW1d3DF5z3/LyAuvGqY/vXTiyqfTz999v37qyucz7fNe + XrOOvXXfNOIaZjqwsbHRcnV1r9mxY89/UVHRZlXLZjuH5GdzHZOf3XdMevYLRIP49vFPMW0G2moRGBjc + duTImf8KCko9bGxsqlApwgBos098fPKEixfv/tfT05/KyspqDJUiDpiZmZXcuvXqv52d8zxmZmYXqDDx + wMDAQEtYWLgFaHMMVIhegIEBADK7VwLsrsplAAAAAElFTkSuQmCC </value> </data> <data name="btnStepLabel01.Image" type="System.Resources.ResXFileRef, System.Windows.Forms"> @@ -1026,4 +1104,7 @@ <metadata name="fileSavedStatusContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <value>17, 17</value> </metadata> + <metadata name="zoomMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <value>782, 17</value> + </metadata> </root> \ No newline at end of file diff --git a/Greenshot/icons/fugue/magnifier-zoom-actual.png b/Greenshot/icons/fugue/magnifier-zoom-actual.png new file mode 100644 index 0000000000000000000000000000000000000000..21cf71d635eba0f9646931cbe60c96972a285ac4 GIT binary patch literal 742 zcmV<C0vY{@P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!h)G02RCwB?Q%z_SK@^_dopkfFNz-Cz z+S;Zylr%M|gdWu5K`ND^AXGuH5Iop=v^FJ&wilryLNK1hiz0YX@K7&e4@!xG*b-6? zp(c`(#?XXflih5xyUljinbnF(4;FmzF|*(M-kW)E-cp*T0iVwYm_uhlPhb-4nZ?2Z zlgZRi({vbrj$m|R<S<qcLJ>)l(v^w`AQ8JqUw}r_G&HU#Qq<#yg(0so<LPD#g&#;> zO-lat&+;<%hp_CWo<Nr6x?p^2KSFBs+!_0qK~Iy}*Jbt56h$>#kl5vfLaV)&Sz0bd zYbr|7BtR6)br1wT>~?`dUoUIyaaddn_cz+du77Z{kmhI#P{;i?o976%MRa-sK@b`- zGU(-s#Fyvg;^NJtJmI&>ijv9+LT<Y%2Ygn6=zf==G`67gaJ%^{*%ZZ{5_D1$)-*e; zEQ@bpBfJqZxN@aazX3vYBXXO0sYZOqT=ovuKy!pAD{Ek^gx}0pRie`q7z~z1ti(U@ zt&pJ^+&uH-LV_baSxFy|2EbaPWG6bkgm&pJJ{18n69ly;|KpE|iKQWbHP`E~lpov* z<o9Z;?ILMCDXOtGxrJqI5xD>THJ4#0d2;-;()Q?CiO%NO{Mae$_wEkJWjEEz%4)^@ z>K*TZ23rVel{9P!9>5cLF%$|f27?o~Tl#LiiN&v7jm67#lgKdUh^ki7BnJK!e8S;q zyD&RDHx~?EzE>=6KeZ~Q3`H^T_l+so{j-C=UICqVyFH^bGjr3y;H8Jz?6>Eb&VU1$ zo<LC)@BI9o>8YtJPg1FkB}^s20ZmVU|E$-;!vl7n=hL{9w|h>$u=>vg6nVD)v7Z7A Y06Z)@+8V}-SpWb407*qoM6N<$g5B>}-T(jq literal 0 HcmV?d00001 diff --git a/Greenshot/icons/fugue/magnifier-zoom-fit.png b/Greenshot/icons/fugue/magnifier-zoom-fit.png new file mode 100644 index 0000000000000000000000000000000000000000..8364359fdea5b43e86d72af9e429679c0dd59064 GIT binary patch literal 726 zcmV;{0xA88P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!cu7P-RCwBA{Qv(ygN}|41G9)5gMwiS z0}OC;^DuC7a%wO!F_i+jPCzUT#7}{E-@kwVy1#$_e&g%cFAOXo#mcU$7|_B0|NjDi z{`}sjuFUe%Sd-(nx*Yq<mv8_5IC1&A?zw9}wgcshfXdc`4fyfn2a0B(ts4LS{ppML z6MJc?$0s4c%__&l$jB(h&%mIq$njrR{N1C)8(#MP{`2oT*nlrzKBGIJ)YMS$rI{|T zL{!mfd62-S$(9U$xyQkht0tQNId$pPi(_X#mNJ0^K7IOxj-B*0dEUe1w#=~l`0>~8 zhaein|M}<dKSLefPat(rFZ@JzfwYVy*Fz9v?|fGV7AD5;>?}<0fHXUh&(Fch!X_uh z!v)kQ4R*o5e@y83>GK!ge}m*K!?!W8voi7Uak5H+Xb>L+p1=6^2c!;c04pmuI^K8s z{6`_6jZ7fEp5JbsAK(8<fM^i^-~a!NC(nKm0I6dHr2|JtN1(0$7(i?g{>`Rq^;<A% zU3I3?XM1xIZZ>8nMnnuTFdsbq@m1Z#yWGG3{PkqPjQ{`gtiLW>20Hu{@16Ua>B=3Z z7algeKjoxYcpg9h^L5{euUuOWe&l9h<tzI4|LYAFG|gJT6c|)gRN5RH8`UDHnz#GF z>E!qWr$3{lL}q5L?mvIN-T>)gLDFm?Dk|<*TwGZh8ynX9{{6c}ygxtOW@KbOgpo`c z{=!)-kXZQVt*or>T3A?_9~&Dy{qf^R%YnkT8HfO21AhMesaaLkmY<p$Isf|gtLuP5 zXBmhDU;}_TYnzpomcYl4A8!D?vIi#l@#P7E27sfH5&#fj0RICl?2mR+zyJUM07*qo IM6N<$f^Jx9DF6Tf literal 0 HcmV?d00001 diff --git a/Greenshot/icons/fugue/magnifier-zoom-in.png b/Greenshot/icons/fugue/magnifier-zoom-in.png new file mode 100644 index 0000000000000000000000000000000000000000..800ec120597e77ae21effe2342270f69f4c2c3b8 GIT binary patch literal 733 zcmV<30wVp1P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!e@R3^RCwB?Q(b7&P!vwmH0e+Jw=vdk zb5%>}I_yve{tO>vL!1h_O%NOeA7nl{+Odc3RS}`sS6>vt2Ys?m5c{B%Du^4kDh$_3 zpR|;=h-;JnBx$l6?+u%{3~}IrkCU8xzVF_1&$+m&s@TQwI;J<PmBGwr^AJH0i|}_G zq939Jkpck31VPBRT1||^{$i>MrX@*;2Yh68G-xUW2I*?`ClFWGgwV%zF$vcrFzuNp zAd2D+GTe0t0408I!ufS1Kw11A>wdG*U~^bObDx{!yPR?%k*vpM1>^`sXf_)=!1LUq z&x=+42WXSaN>PYBdHtQ6CJBbXG5lD_ZVw#9f1o@~faiHV#z%ro&Baho6J>BKKsBQ{ z@{$6&+8xDo<dBU=d0Qn&`YY%k@L0aV-JNIHq<1@bbmqAOI!AVSiW0=lHstkd0ss(t zfl|35$lVUQj*?AA!WKNc%;b_&O-TkC%9XYPc_mH2Xte4DQkhTOVecT**l2X*ZW}cK za~MSA1-T4V3|r0CoiLWt1U$kWcnW}_nLv=K(1Z8c*~Dn5UFvh00j#^3c{))+o*;0; zhtCZuy(+qB+8!f!_h0oIJ8LJVPf5M^AJ>UuiLOkZwABauNTpa-TB((m<;5G$P8#hI zptka)jywz}a3&I2yvee&w_N@kuhN-oSJRosj!85aEHOoC<q?PcgM7TFr}x6bLNv;< zm+#hU8;@*Ky@2C}x4Y+b^Y_<Q7r=R+FK{{>j?S~}rF+HV_a`u1!1iF8fFw!5rKQ{R zb8}Z7=5k*WFqFmiXqo_gSue-NhMgS8<zXqWw->qU%0C5g)VBYzUjhsOn}0<&?S0Lw P00000NkvXXu0mjfX;4x~ literal 0 HcmV?d00001 diff --git a/Greenshot/icons/fugue/magnifier-zoom-out.png b/Greenshot/icons/fugue/magnifier-zoom-out.png new file mode 100644 index 0000000000000000000000000000000000000000..3ec2b7a5d32c41a3313a95bec8f326ba356b3b46 GIT binary patch literal 707 zcmV;!0zCbRP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!Wl2OqRCwB?Q%z_SK@^_-&3{a6OHE@F zHIy_ZDV848;z1%+Q4p&jSXex0ua>6dkX{uLg1LH81P=-xq6aa85~3GVVpJ&FNG@s! zNl@F}{OxXbJL~MymSlUd;DZM<`~A#&ytkO5C?FUN0;2yEI52S?Y=y;Q1tybe6vy!> zx`t7@QI=7rA%t<B=L@Y?6Oby|H~kdoLs8(2DDnxvkE~4wj77i4P^<lcLUx4@ef%n< z5FSCaXPSW^2t8u->L`SA;_OMsw{bsh_Vk<ja13Bx7fuiFvnhKWQZbog6Os&9aaGW4 zHhQvN=b}C@sEr&n7@ZcHR>j-q=zJt(xBCxazf_)9LA_qrcMu*A3>TbM+GV5(hbY4y zu-%c_iJ<NGtMvEqW(%U;z`fsP{()Y1oMuv9J(z!ff#!vcHqyB@0|;?Fr(CJ>Qr{i} ztCCUuST`t2uvw|LWuz->1{7t{8>DlexWitLwXxRdNEC??-5^u|SkAK!q)TfCF8&Ux z0s?g>)RgGZgZKH_<YcH_9&(x>MG{>T!iW!_8)9Zza2gEuIJtBFikIrF9Gf{I4&Hyv z;-#{odgi!I^bC>KQblg1vn}I`x161%>=CH63ZzavhBokGBoe*JFtfLuBR5`Wa@VeA za*du%BnWd{mRki?Lw1Re4h#&QUtEmE80PZb_4Tz!Hjyo281Zh$nu3k()8-W5IiJrz zy|56QXP8U(N~NDq(B~r9MQ8@1C<d06ZqLunU3s{=`X#B38tgJO1N3LToSGVQa2!`a pt-RR+xmxz02ADdw|B1f>3;;}Y5)Y3gBsBm4002ovPDHLkV1nfvIIaKy literal 0 HcmV?d00001 diff --git a/Greenshot/icons/fugue/magnifier-zoom.png b/Greenshot/icons/fugue/magnifier-zoom.png new file mode 100644 index 0000000000000000000000000000000000000000..941b1035673a42d2c0dfe636ef27fd1d7236775f GIT binary patch literal 676 zcmV;V0$crwP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0000PbVXQnQ*UN; zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!MoC0LRCwBA`TzevgMZ;Q26Vv9&BMUS z$*IA_#8e98IsvgX5I+UtegFRb>;C@z`;D((zc8>c-~j*s{|o&2^LwAVGRsS2O^(~@ za_lc(zWw*(#O3e0=dS(O4wNqfDq9aW;Kz?2D4Kz`YW(~6x6jL&|E8Wg8<(62r!W&E z1Eaho6Pv6A?|&hI-?!Io|Je8Y&)@4zAPrx>d`7{aK7A}zk^lcvRgs-Tkei(qq#15F zkZrEZ$EU8u@CKv~?1E39KB4=-Nmo<$CXnWM_Ws+?XYUz)qAM`e=KHf_-vcM87ck_d zWhA*C!Z@1Je0=CZ#KFS+6R1xb?1g{-n9%Xl=P$qihHB=;7Rb+EeES1Z2R49}l^Y%J zJAMA65Hk}K^KYOsbj|<%{bxLR_JaUO9oP$!-#dVU{}@1N0)&6F>CQcVI&z(f&bO!1 zLY)6tks_O!iIL^Zr7u4Yoctlk&d%4(f*Jq+<yn7SwhVL(7N5QB1Jk3YY%e@)cz?=C zvGP2A{^#qylV4f39QY{8!pc|l@Bh~uENGgwfGIGjsHn6#Ha4<FP$hr&0j}iu1E;^B zq(o+BuI@j7zTN=oVL{StAu1~FS6p0K85<kc`~Lm=MZCX0+-78CK7<*Bf5D`elLW*7 zp#Oc8mDODe3oG+uV}qwXe*9=TQ1~_j0pMXT4l&^8&z~AqRc-mHsgd)qU%$E@D0G&A z2=MFIKZpUqoVCr$N=xA5$B#FFUfBav@bTpdf`%}HqKy&&5MTg@o)G8w|DD_b0000< KMNUMnLSTZ6q*TfP literal 0 HcmV?d00001 diff --git a/GreenshotPlugin/Interfaces/ISurface.cs b/GreenshotPlugin/Interfaces/ISurface.cs index 44a150364..8ab44c810 100644 --- a/GreenshotPlugin/Interfaces/ISurface.cs +++ b/GreenshotPlugin/Interfaces/ISurface.cs @@ -21,6 +21,7 @@ using System; using System.Drawing; +using System.Drawing.Drawing2D; using System.IO; using System.Windows.Forms; using GreenshotPlugin.Effects; @@ -147,8 +148,13 @@ namespace GreenshotPlugin.Interfaces /// <param name="container"></param> /// <returns>This returns false if the container is deleted but still in the undo stack</returns> bool IsOnSurface(IDrawableContainer container); - void Invalidate(Rectangle rectangleToInvalidate); void Invalidate(); + /// <summary> + /// Invalidates the specified region of the Surface. + /// Takes care of the Surface zoom level, accepts rectangle in the coordinate space of the Image. + /// </summary> + /// <param name="rectangleToInvalidate">Bounding rectangle for updated elements, in the coordinate space of the Image.</param> + void InvalidateElements(Rectangle rectangleToInvalidate); bool Modified { get; @@ -189,6 +195,15 @@ namespace GreenshotPlugin.Interfaces int Width { get; } int Height { get; } + /// <summary> + /// Zoom value applied to the surface. 1.0f for actual size (100%). + /// </summary> + float ZoomFactor { get; set; } + /// <summary> + /// Matrix representing zoom applied to the surface. + /// </summary> + Matrix ZoomMatrix { get; } + void MakeUndoable(IMemento memento, bool allowMerge); } -} \ No newline at end of file +} From 136953aa4e16f4c7150becaea546f70f9622872a Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Mon, 27 Apr 2020 01:13:22 +0300 Subject: [PATCH 015/232] Fixes for some identified issues - better interface for coordinate translation; - correct context menu location; - speech bubble tail can be dragged over the whole image. --- Greenshot/Drawing/Adorners/AbstractAdorner.cs | 11 ++------ Greenshot/Drawing/Adorners/TargetAdorner.cs | 22 +++++++-------- Greenshot/Drawing/DrawableContainerList.cs | 7 ++--- Greenshot/Drawing/Surface.cs | 28 +++++++++++++++++-- Greenshot/Drawing/TextContainer.cs | 15 ++++------ GreenshotPlugin/Interfaces/ISurface.cs | 11 ++++++-- 6 files changed, 55 insertions(+), 39 deletions(-) diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs index fc3d72371..51ae7f14f 100644 --- a/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ b/Greenshot/Drawing/Adorners/AbstractAdorner.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * @@ -123,13 +123,8 @@ namespace Greenshot.Drawing.Adorners { get { - Point[] points = { Location }; - var matrix = Owner.Parent.ZoomMatrix; - if (!matrix.IsIdentity) - { - matrix.TransformPoints(points); - } - return new Rectangle(points[0].X - _size.Width / 2, points[0].Y - _size.Height / 2, _size.Width, _size.Height); + Point displayLocation = Owner.Parent.ToSurfaceCoordinates(Location); + return new Rectangle(displayLocation.X - _size.Width / 2, displayLocation.Y - _size.Height / 2, _size.Width, _size.Height); } } diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/Greenshot/Drawing/Adorners/TargetAdorner.cs index 23cf29d09..4011754f7 100644 --- a/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ b/Greenshot/Drawing/Adorners/TargetAdorner.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * @@ -61,26 +61,26 @@ namespace Greenshot.Drawing.Adorners Owner.Invalidate(); Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); - Rectangle surfaceBounds = new Rectangle(0, 0, Owner.Parent.Width, Owner.Parent.Height); + Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height); // Check if gripper inside the parent (surface), if not we need to move it inside // This was made for BUG-1682 - if (!surfaceBounds.Contains(newGripperLocation)) + if (!imageBounds.Contains(newGripperLocation)) { - if (newGripperLocation.X > surfaceBounds.Right) + if (newGripperLocation.X > imageBounds.Right) { - newGripperLocation.X = surfaceBounds.Right - 5; + newGripperLocation.X = imageBounds.Right - 5; } - if (newGripperLocation.X < surfaceBounds.Left) + if (newGripperLocation.X < imageBounds.Left) { - newGripperLocation.X = surfaceBounds.Left; + newGripperLocation.X = imageBounds.Left; } - if (newGripperLocation.Y > surfaceBounds.Bottom) + if (newGripperLocation.Y > imageBounds.Bottom) { - newGripperLocation.Y = surfaceBounds.Bottom - 5; + newGripperLocation.Y = imageBounds.Bottom - 5; } - if (newGripperLocation.Y < surfaceBounds.Top) + if (newGripperLocation.Y < imageBounds.Top) { - newGripperLocation.Y = surfaceBounds.Top; + newGripperLocation.Y = imageBounds.Top; } } diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs index 17b879538..9451b06ea 100644 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ b/Greenshot/Drawing/DrawableContainerList.cs @@ -523,9 +523,9 @@ namespace Greenshot.Drawing { } } - public virtual void ShowContextMenu(MouseEventArgs e, ISurface surface) + public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface) { - if (!(surface is Surface)) + if (!(iSurface is Surface surface)) { return; } @@ -542,8 +542,7 @@ namespace Greenshot.Drawing { ContextMenuStrip menu = new ContextMenuStrip(); AddContextMenuItems(menu, surface); if (menu.Items.Count > 0) { - // TODO: cast should be somehow avoided - menu.Show((Surface)surface, e.Location); + menu.Show(surface, surface.ToSurfaceCoordinates(e.Location)); while (true) { if (menu.Visible) { Application.DoEvents(); diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 5c38bea8e..0057a0838 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * @@ -302,6 +302,8 @@ namespace Greenshot.Drawing } } + [NonSerialized] + private Matrix _zoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); [NonSerialized] private float _zoomFactor = 1.0f; public float ZoomFactor @@ -310,12 +312,11 @@ namespace Greenshot.Drawing set { _zoomFactor = value; - ZoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0); + _zoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0); UpdateSize(); } } - public Matrix ZoomMatrix { get; private set; } = new Matrix(1, 0, 0, 1, 0, 0); /// <summary> /// Sets the surface size as zoomed image size. @@ -2108,5 +2109,26 @@ namespace Greenshot.Drawing { return _elements.Contains(container); } + + public Point ToSurfaceCoordinates(Point point) + { + Point[] points = { point }; + _zoomMatrix.TransformPoints(points); + return points[0]; + } + + public Rectangle ToSurfaceCoordinates(Rectangle rc) + { + if (_zoomMatrix.IsIdentity) + { + return rc; + } + else + { + Point[] points = { rc.Location, rc.Location + rc.Size }; + _zoomMatrix.TransformPoints(points); + return new Rectangle(points[0].X, points[0].Y, points[1].X - points[0].X, points[1].Y - points[1].Y); + } + } } } diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index bd4c75274..726ab5b7f 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -442,20 +442,15 @@ namespace Greenshot.Drawing correction = -1; } Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Point[] points = { absRectangle.Location, absRectangle.Location + absRectangle.Size }; - var matrix = Parent.ZoomMatrix; - if (!matrix.IsIdentity) - { - matrix.TransformPoints(points); - } - _textBox.Left = points[0].X + lineWidth; - _textBox.Top = points[0].Y + lineWidth; + Rectangle displayRectangle = Parent.ToSurfaceCoordinates(absRectangle); + _textBox.Left = displayRectangle.X + lineWidth; + _textBox.Top = displayRectangle.Y + lineWidth; if (lineThickness <= 1) { lineWidth = 0; } - _textBox.Width = points[1].X - points[0].X - 2 * lineWidth + correction; - _textBox.Height = points[1].Y - points[0].Y - 2 * lineWidth + correction; + _textBox.Width = displayRectangle.Width - 2 * lineWidth + correction; + _textBox.Height = displayRectangle.Height - 2 * lineWidth + correction; } public override void ApplyBounds(RectangleF newBounds) diff --git a/GreenshotPlugin/Interfaces/ISurface.cs b/GreenshotPlugin/Interfaces/ISurface.cs index 8ab44c810..a94415cbc 100644 --- a/GreenshotPlugin/Interfaces/ISurface.cs +++ b/GreenshotPlugin/Interfaces/ISurface.cs @@ -21,7 +21,6 @@ using System; using System.Drawing; -using System.Drawing.Drawing2D; using System.IO; using System.Windows.Forms; using GreenshotPlugin.Effects; @@ -200,9 +199,15 @@ namespace GreenshotPlugin.Interfaces /// </summary> float ZoomFactor { get; set; } /// <summary> - /// Matrix representing zoom applied to the surface. + /// Translate a point from image coorditate space to surface coordinate space. /// </summary> - Matrix ZoomMatrix { get; } + /// <param name="point">A point in the coordinate space of the image.</param> + Point ToSurfaceCoordinates(Point point); + /// <summary> + /// Translate a rectangle from image coorditate space to surface coordinate space. + /// </summary> + /// <param name="rc">A rectangle in the coordinate space of the image.</param> + Rectangle ToSurfaceCoordinates(Rectangle rc); void MakeUndoable(IMemento memento, bool allowMerge); } From 79742d1b4d01a11b2dc6d10e7a0074d6824ecc43 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Mon, 27 Apr 2020 01:14:52 +0300 Subject: [PATCH 016/232] Code review nitpicks --- Greenshot/Drawing/Adorners/AbstractAdorner.cs | 4 ++-- Greenshot/Drawing/Adorners/MoveAdorner.cs | 2 +- Greenshot/Drawing/Adorners/ResizeAdorner.cs | 2 +- Greenshot/Drawing/Adorners/TargetAdorner.cs | 4 ++-- Greenshot/Drawing/CropContainer.cs | 2 +- Greenshot/Drawing/Surface.cs | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs index 51ae7f14f..70a56f29e 100644 --- a/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ b/Greenshot/Drawing/Adorners/AbstractAdorner.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * @@ -119,7 +119,7 @@ namespace Greenshot.Drawing.Adorners /// <summary> /// Return the bounds of the Adorner as displayed on the parent Surface /// </summary> - protected virtual Rectangle SurfaceBounds + protected virtual Rectangle BoundsOnSurface { get { diff --git a/Greenshot/Drawing/Adorners/MoveAdorner.cs b/Greenshot/Drawing/Adorners/MoveAdorner.cs index 21c42a9fa..d07a25ef7 100644 --- a/Greenshot/Drawing/Adorners/MoveAdorner.cs +++ b/Greenshot/Drawing/Adorners/MoveAdorner.cs @@ -142,7 +142,7 @@ namespace Greenshot.Drawing.Adorners { Graphics targetGraphics = paintEventArgs.Graphics; - var bounds = SurfaceBounds; + var bounds = BoundsOnSurface; GraphicsState state = targetGraphics.Save(); targetGraphics.SmoothingMode = SmoothingMode.None; diff --git a/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/Greenshot/Drawing/Adorners/ResizeAdorner.cs index ef61b17bc..dce78b461 100644 --- a/Greenshot/Drawing/Adorners/ResizeAdorner.cs +++ b/Greenshot/Drawing/Adorners/ResizeAdorner.cs @@ -169,7 +169,7 @@ namespace Greenshot.Drawing.Adorners { Graphics targetGraphics = paintEventArgs.Graphics; - var bounds = SurfaceBounds; + var bounds = BoundsOnSurface; GraphicsState state = targetGraphics.Save(); targetGraphics.SmoothingMode = SmoothingMode.None; diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/Greenshot/Drawing/Adorners/TargetAdorner.cs index 4011754f7..67c01a533 100644 --- a/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ b/Greenshot/Drawing/Adorners/TargetAdorner.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * @@ -96,7 +96,7 @@ namespace Greenshot.Drawing.Adorners { Graphics targetGraphics = paintEventArgs.Graphics; - var bounds = SurfaceBounds; + var bounds = BoundsOnSurface; targetGraphics.FillRectangle(Brushes.Green, bounds.X, bounds.Y, bounds.Width, bounds.Height); } diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs index f5288074d..58cee17b1 100644 --- a/Greenshot/Drawing/CropContainer.cs +++ b/Greenshot/Drawing/CropContainer.cs @@ -61,7 +61,7 @@ namespace Greenshot.Drawing { if (_parent?.Image is Image image) { return new Rectangle(0, 0, image.Width, image.Height); } else { - return new Rectangle(); + return Rectangle.Empty; } } } diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 0057a0838..3d1f309a3 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * @@ -1405,7 +1405,7 @@ namespace Greenshot.Drawing return GetImage(RenderMode.EXPORT); } - private Rectangle ZoomClipRectangle(Rectangle rc, double scale) + private static Rectangle ZoomClipRectangle(Rectangle rc, double scale) => new Rectangle( (int)(rc.X * scale), (int)(rc.Y * scale), @@ -1413,7 +1413,7 @@ namespace Greenshot.Drawing (int)((rc.Height + 1) * scale) + 1 ); - private RectangleF ZoomClipRectangle(RectangleF rc, double scale) + private static RectangleF ZoomClipRectangle(RectangleF rc, double scale) => new RectangleF( (float)Math.Floor(rc.X * scale), (float)Math.Floor(rc.Y * scale), From 41082c2be15c94a8a3dfe9fd0e9db06c99139a96 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Mon, 27 Apr 2020 01:18:05 +0300 Subject: [PATCH 017/232] Image size in OneNoteExporter There is now a distinction between Surface size and Surface.Image size. --- GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs b/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs index 23525b608..611594334 100644 --- a/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs +++ b/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs @@ -95,7 +95,7 @@ namespace GreenshotOfficePlugin.OfficeExport var pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); ImageOutput.SaveToStream(surfaceToUpload, pngStream, pngOutputSettings); var base64String = Convert.ToBase64String(pngStream.GetBuffer()); - var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Width, surfaceToUpload.Height); + var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Image.Width, surfaceToUpload.Image.Height); var pageChangesXml = string.Format(XmlOutline, imageXmlStr, page.Id, OnenoteNamespace2010, page.Name); LOG.InfoFormat("Sending XML: {0}", pageChangesXml); oneNoteApplication.ComObject.UpdatePageContent(pageChangesXml, DateTime.MinValue, XMLSchema.xs2010, false); From 95c759e3fd62eaed79a5bbbde218e1a0c7e00bd8 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Mon, 27 Apr 2020 01:19:38 +0300 Subject: [PATCH 018/232] Changed shortcuts - Ctrl+0, Ctrl+9 --- Greenshot/Forms/ImageEditorForm.Designer.cs | 4 ++-- Greenshot/Forms/ImageEditorForm.cs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Greenshot/Forms/ImageEditorForm.Designer.cs b/Greenshot/Forms/ImageEditorForm.Designer.cs index 5789a19a6..606b72773 100644 --- a/Greenshot/Forms/ImageEditorForm.Designer.cs +++ b/Greenshot/Forms/ImageEditorForm.Designer.cs @@ -1704,7 +1704,7 @@ namespace Greenshot { // this.zoomBestFitMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomBestFitMenuItem.Image"))); this.zoomBestFitMenuItem.Name = "zoomBestFitMenuItem"; - this.zoomBestFitMenuItem.ShortcutKeyDisplayString = "Ctrl+*"; + this.zoomBestFitMenuItem.ShortcutKeyDisplayString = "Ctrl+9"; this.zoomBestFitMenuItem.Size = new System.Drawing.Size(209, 22); this.zoomBestFitMenuItem.Text = "Best Fit"; this.zoomBestFitMenuItem.Click += new System.EventHandler(this.ZoomBestFitMenuItemClick); @@ -1755,7 +1755,7 @@ namespace Greenshot { // this.zoomActualSizeMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("zoomActualSizeMenuItem.Image"))); this.zoomActualSizeMenuItem.Name = "zoomActualSizeMenuItem"; - this.zoomActualSizeMenuItem.ShortcutKeyDisplayString = "Ctrl+/"; + this.zoomActualSizeMenuItem.ShortcutKeyDisplayString = "Ctrl+0"; this.zoomActualSizeMenuItem.Size = new System.Drawing.Size(209, 22); this.zoomActualSizeMenuItem.Tag = "100"; this.zoomActualSizeMenuItem.Text = "100% - Actual Size"; diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index dd9ec94e1..3396acd15 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -871,12 +871,12 @@ namespace Greenshot { case Keys.OemMinus: // Ctrl + - ZoomOutMenuItemClick(sender, e); break; - case Keys.Divide: // Ctrl + Num/ - case Keys.OemQuestion: // Ctrl + / (?) + case Keys.NumPad0: // Ctrl + Num0 + case Keys.D0: // Ctrl + 0 ZoomSetValueMenuItemClick(zoomActualSizeMenuItem, e); break; - case Keys.Multiply: // Ctrl + Num* - case Keys.D8: // Ctrl + 8 (*) + case Keys.NumPad9: // Ctrl + Num9 + case Keys.D9: // Ctrl + 9 ZoomBestFitMenuItemClick(sender, e); break; } From ec2c46daa852d5692bf891ca1700ac6c267abfd3 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Mon, 27 Apr 2020 01:23:23 +0300 Subject: [PATCH 019/232] GetOptimalWindowSize - bound by available screen space Limiting by working area size was not good enough - having whole chrome on screen is important. --- Greenshot/Forms/ImageEditorForm.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index 3396acd15..4609ff4a8 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -1502,10 +1502,9 @@ namespace Greenshot { var newHeight = chromeSize.Height + surfaceSize.Height; // Upper bound. Don't make it bigger than the available working area. - var screen = Screen.FromControl(this); - var workingArea = screen.WorkingArea; - newWidth = Math.Min(newWidth, workingArea.Width); - newHeight = Math.Min(newHeight, workingArea.Height); + var maxWindowSize = GetAvailableScreenSpace(); + newWidth = Math.Min(newWidth, maxWindowSize.Width); + newHeight = Math.Min(newHeight, maxWindowSize.Height); // Lower bound. Don't make it smaller than a fixed value. int minimumFormWidth = 650; From 3d39241f82799b741afb039e65783f6d0e52f9c0 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Mon, 27 Apr 2020 16:00:58 +0300 Subject: [PATCH 020/232] More fixes for Surface.Image size - crop works properly; - Freehand drawings are selectable everywhere at all zoom levels. Known issue: freehand selection outline is not drawn --- Greenshot/Drawing/FreehandContainer.cs | 13 ++++++++++--- Greenshot/Drawing/Surface.cs | 8 ++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Greenshot/Drawing/FreehandContainer.cs b/Greenshot/Drawing/FreehandContainer.cs index 129ba4822..c7d5cf1e8 100644 --- a/Greenshot/Drawing/FreehandContainer.cs +++ b/Greenshot/Drawing/FreehandContainer.cs @@ -47,8 +47,8 @@ namespace Greenshot.Drawing { /// Constructor /// </summary> public FreehandContainer(Surface parent) : base(parent) { - Width = parent.Width; - Height = parent.Height; + Width = parent.Image.Width; + Height = parent.Image.Height; Top = 0; Left = 0; } @@ -236,7 +236,14 @@ namespace Greenshot.Drawing { int safetymargin = 10; return new Rectangle(myBounds.Left + Left - (safetymargin+lineThickness), myBounds.Top + Top - (safetymargin+lineThickness), myBounds.Width + 2*(lineThickness+safetymargin), myBounds.Height + 2*(lineThickness+safetymargin)); } - return new Rectangle(0, 0, _parent?.Width??0, _parent?.Height?? 0); + if (_parent?.Image is Image image) + { + return new Rectangle(0, 0, image.Width, image.Height); + } + else + { + return Rectangle.Empty; + } } } diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 3d1f309a3..e9d26ef05 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -991,13 +991,13 @@ namespace Greenshot.Drawing { cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); } - if (cropRectangle.Left + cropRectangle.Width > Width) + if (cropRectangle.Left + cropRectangle.Width > Image.Width) { - cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Width - cropRectangle.Left, cropRectangle.Height); + cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height); } - if (cropRectangle.Top + cropRectangle.Height > Height) + if (cropRectangle.Top + cropRectangle.Height > Image.Height) { - cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Height - cropRectangle.Top); + cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top); } if (cropRectangle.Height > 0 && cropRectangle.Width > 0) { From 169dbdccec9e117d6bcaabb26bcbf66e90fc2471 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Mon, 27 Apr 2020 19:15:08 +0300 Subject: [PATCH 021/232] Rework for paste from clipboard - location is determined by the same code for images and text; - use visible area to determine the location. --- Greenshot/Drawing/DrawableContainer.cs | 27 ----- Greenshot/Drawing/Surface.cs | 99 +++++++++++++++---- .../Interfaces/Drawing/Container.cs | 1 - GreenshotPlugin/Interfaces/ISurface.cs | 16 ++- 4 files changed, 93 insertions(+), 50 deletions(-) diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index 65ff42de3..e7caf7ea3 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -302,33 +302,6 @@ namespace Greenshot.Drawing } } - public void AlignToParent(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) { - if (_parent == null) - { - return; - } - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - if (horizontalAlignment == HorizontalAlignment.Left) { - Left = lineThickness/2; - } - if (horizontalAlignment == HorizontalAlignment.Right) { - Left = _parent.Width - Width - lineThickness/2; - } - if (horizontalAlignment == HorizontalAlignment.Center) { - Left = (_parent.Width / 2) - (Width / 2) - lineThickness/2; - } - - if (verticalAlignment == VerticalAlignment.TOP) { - Top = lineThickness/2; - } - if (verticalAlignment == VerticalAlignment.BOTTOM) { - Top = _parent.Height - Height - lineThickness/2; - } - if (verticalAlignment == VerticalAlignment.CENTER) { - Top = (_parent.Height / 2) - (Height / 2) - lineThickness/2; - } - } - public virtual bool InitContent() { return true; } public virtual void OnDoubleClick() {} diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index e9d26ef05..4435a7f39 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -305,6 +305,8 @@ namespace Greenshot.Drawing [NonSerialized] private Matrix _zoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); [NonSerialized] + private Matrix _inverseZoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); + [NonSerialized] private float _zoomFactor = 1.0f; public float ZoomFactor { @@ -313,6 +315,7 @@ namespace Greenshot.Drawing { _zoomFactor = value; _zoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0); + _inverseZoomMatrix = new Matrix(1f / _zoomFactor, 0, 0, 1f / _zoomFactor, 0, 0); UpdateSize(); } } @@ -803,9 +806,9 @@ namespace Greenshot.Drawing return cursorContainer; } - public ITextContainer AddTextContainer(string text, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor) + public ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor) { - TextContainer textContainer = new TextContainer(this) {Text = text}; + TextContainer textContainer = new TextContainer(this) {Text = text, Left = x, Top = y}; textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name); textContainer.SetFieldValue(FieldType.FONT_BOLD, bold); textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic); @@ -816,8 +819,6 @@ namespace Greenshot.Drawing textContainer.SetFieldValue(FieldType.SHADOW, shadow); // Make sure the Text fits textContainer.FitToText(); - // Align to Surface - textContainer.AlignToParent(horizontalAlignment, verticalAlignment); //AggregatedProperties.UpdateElement(textContainer); AddElement(textContainer); @@ -1817,43 +1818,72 @@ namespace Greenshot.Drawing } else if (ClipboardHelper.ContainsImage(clipboard)) { - int x = 10; - int y = 10; - - // FEATURE-995: Added a check for the current mouse cursor location, to paste the image on that location. - var mousePositionOnControl = PointToClient(MousePosition); - if (ClientRectangle.Contains(mousePositionOnControl)) - { - x = mousePositionOnControl.X; - y = mousePositionOnControl.Y; - } + Point pasteLocation = GetPasteLocation(0.1f, 0.1f); foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) { if (clipboardImage != null) { DeselectAllElements(); - IImageContainer container = AddImageContainer(clipboardImage as Bitmap, x, y); + IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y); SelectElement(container); clipboardImage.Dispose(); - x += 10; - y += 10; + pasteLocation.X += 10; + pasteLocation.Y += 10; } } } else if (ClipboardHelper.ContainsText(clipboard)) { + Point pasteLocation = GetPasteLocation(0.4f, 0.4f); + string text = ClipboardHelper.GetText(clipboard); if (text != null) { DeselectAllElements(); - ITextContainer textContainer = AddTextContainer(text, HorizontalAlignment.Center, VerticalAlignment.CENTER, + ITextContainer textContainer = AddTextContainer(text, pasteLocation.X, pasteLocation.Y, FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); SelectElement(textContainer); } } } + /// <summary> + /// Find a location to paste elements. + /// If mouse is over the surface - use it's position, otherwise use the visible area. + /// Return a point in image coordinate space. + /// </summary> + /// <param name="horizontalRatio">0.0f for the left edge of visible area, 1.0f for the right edge of visible area.</param> + /// <param name="verticalRatio">0.0f for the top edge of visible area, 1.0f for the bottom edge of visible area.</param> + private Point GetPasteLocation(float horizontalRatio = 0.5f, float verticalRatio = 0.5f) + { + var point = PointToClient(MousePosition); + var rc = GetVisibleRectangle(); + if (!rc.Contains(point)) + { + point = new Point( + rc.Left + (int)(rc.Width * horizontalRatio), + rc.Top + (int)(rc.Height * verticalRatio) + ); + } + return ToImageCoordinates(point); + } + + /// <summary> + /// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space). + /// </summary> + private Rectangle GetVisibleRectangle() + { + var bounds = Bounds; + var clientArea = Parent.ClientRectangle; + return new Rectangle( + Math.Max(0, -bounds.Left), + Math.Max(0, -bounds.Top), + clientArea.Width, + clientArea.Height + ); + } + /// <summary> /// Duplicate all the selecteded elements /// </summary> @@ -2127,7 +2157,38 @@ namespace Greenshot.Drawing { Point[] points = { rc.Location, rc.Location + rc.Size }; _zoomMatrix.TransformPoints(points); - return new Rectangle(points[0].X, points[0].Y, points[1].X - points[0].X, points[1].Y - points[1].Y); + return new Rectangle( + points[0].X, + points[0].Y, + points[1].X - points[0].X, + points[1].Y - points[0].Y + ); + } + } + + public Point ToImageCoordinates(Point point) + { + Point[] points = { point }; + _inverseZoomMatrix.TransformPoints(points); + return points[0]; + } + + public Rectangle ToImageCoordinates(Rectangle rc) + { + if (_inverseZoomMatrix.IsIdentity) + { + return rc; + } + else + { + Point[] points = { rc.Location, rc.Location + rc.Size }; + _inverseZoomMatrix.TransformPoints(points); + return new Rectangle( + points[0].X, + points[0].Y, + points[1].X - points[0].X, + points[1].Y - points[0].Y + ); } } } diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/GreenshotPlugin/Interfaces/Drawing/Container.cs index b2b6e3d19..35a6cf50a 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Container.cs @@ -102,7 +102,6 @@ namespace GreenshotPlugin.Interfaces.Drawing get; set; } - void AlignToParent(HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment); void Invalidate(); bool ClickableAt(int x, int y); void MoveBy(int x, int y); diff --git a/GreenshotPlugin/Interfaces/ISurface.cs b/GreenshotPlugin/Interfaces/ISurface.cs index a94415cbc..e32247188 100644 --- a/GreenshotPlugin/Interfaces/ISurface.cs +++ b/GreenshotPlugin/Interfaces/ISurface.cs @@ -84,8 +84,8 @@ namespace GreenshotPlugin.Interfaces /// The TextContainer will be "re"sized to the text size. /// </summary> /// <param name="text">String to show</param> - /// <param name="horizontalAlignment">Left, Center, Right</param> - /// <param name="verticalAlignment">TOP, CENTER, BOTTOM</param> + /// <param name="x">Where to put the container, X coordinate in the Image coordinate space</param> + /// <param name="y">Where to put the container, Y coordinate in the Image coordinate space</param> /// <param name="family">FontFamily</param> /// <param name="size">Font Size in float</param> /// <param name="italic">bool true if italic</param> @@ -94,7 +94,7 @@ namespace GreenshotPlugin.Interfaces /// <param name="borderSize">size of border (0 for none)</param> /// <param name="color">Color of string</param> /// <param name="fillColor">Color of background (e.g. Color.Transparent)</param> - ITextContainer AddTextContainer(string text, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor); + ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor); IImageContainer AddImageContainer(Image image, int x, int y); ICursorContainer AddCursorContainer(Cursor cursor, int x, int y); @@ -208,6 +208,16 @@ namespace GreenshotPlugin.Interfaces /// </summary> /// <param name="rc">A rectangle in the coordinate space of the image.</param> Rectangle ToSurfaceCoordinates(Rectangle rc); + /// <summary> + /// Translate a point from surface coorditate space to image coordinate space. + /// </summary> + /// <param name="point">A point in the coordinate space of the surface.</param> + Point ToImageCoordinates(Point point); + /// <summary> + /// Translate a rectangle from surface coorditate space to image coordinate space. + /// </summary> + /// <param name="rc">A rectangle in the coordinate space of the surface.</param> + Rectangle ToImageCoordinates(Rectangle rc); void MakeUndoable(IMemento memento, bool allowMerge); } From 195b5c3ab7579e850e1816c4ec72aaae2ebe46ae Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Mon, 27 Apr 2020 19:15:36 +0300 Subject: [PATCH 022/232] Fix NPE --- Greenshot/Drawing/TextContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index 726ab5b7f..c73424908 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -428,7 +428,7 @@ namespace Greenshot.Drawing /// </summary> private void UpdateTextBoxPosition() { - if (_textBox == null) + if (_textBox == null || Parent == null) { return; } From 2be1898c53f90c4769e38d55685f3688f2795c91 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Mon, 27 Apr 2020 19:30:22 +0300 Subject: [PATCH 023/232] Width and Height shouldn't be exposed through ISurface anymore --- GreenshotPlugin/Interfaces/ISurface.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/GreenshotPlugin/Interfaces/ISurface.cs b/GreenshotPlugin/Interfaces/ISurface.cs index e32247188..73b31b05d 100644 --- a/GreenshotPlugin/Interfaces/ISurface.cs +++ b/GreenshotPlugin/Interfaces/ISurface.cs @@ -191,8 +191,6 @@ namespace GreenshotPlugin.Interfaces get; set; } - int Width { get; } - int Height { get; } /// <summary> /// Zoom value applied to the surface. 1.0f for actual size (100%). From 5fe700bc840c1aac874ac474ae03c362d1d1a615 Mon Sep 17 00:00:00 2001 From: MXI <KillyMXI@users.noreply.github.com> Date: Mon, 27 Apr 2020 21:00:59 +0300 Subject: [PATCH 024/232] Fix GetAvailableScreenSpace on secondary screens Co-Authored-By: jklingen <jklingen@users.noreply.github.com> --- Greenshot/Forms/ImageEditorForm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index 4609ff4a8..d5de0b5c9 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -1526,7 +1526,7 @@ namespace Greenshot { var screenBounds = screen.Bounds; var workingArea = screen.WorkingArea; if (Left > screenBounds.Left && Top > screenBounds.Top) { - return new Size(workingArea.Width - Left, workingArea.Height - Top); + return new Size(workingArea.Right - Left, workingArea.Bottom - Top); } else { return workingArea.Size; } From d47271e7e14c848145411a2ef5820424f3c62d7b Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Tue, 28 Apr 2020 18:55:43 +0300 Subject: [PATCH 025/232] Fix rendering quality at small zoom levels when redrawing small parts --- Greenshot/Drawing/Surface.cs | 42 +++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 4435a7f39..09bbe028e 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * @@ -1473,19 +1473,11 @@ namespace Greenshot.Drawing targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); if (isZoomedIn) { - var state = targetGraphics.Save(); - targetGraphics.SmoothingMode = SmoothingMode.None; - targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; - targetGraphics.CompositingQuality = CompositingQuality.HighQuality; - targetGraphics.PixelOffsetMode = PixelOffsetMode.None; - - targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - - targetGraphics.Restore(state); + DrawSharpImage(targetGraphics, _buffer, imageClipRectangle); } else { - targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + DrawSmoothImage(targetGraphics, _buffer, imageClipRectangle); } targetGraphics.ResetTransform(); } @@ -1494,7 +1486,7 @@ namespace Greenshot.Drawing DrawBackground(targetGraphics, targetClipRectangle); targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); - targetGraphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + DrawSmoothImage(targetGraphics, Image, imageClipRectangle); _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); targetGraphics.ResetTransform(); } @@ -1511,6 +1503,32 @@ namespace Greenshot.Drawing } } + private void DrawSmoothImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) + { + var state = targetGraphics.Save(); + targetGraphics.SmoothingMode = SmoothingMode.HighQuality; + targetGraphics.InterpolationMode = InterpolationMode.HighQualityBilinear; + targetGraphics.CompositingQuality = CompositingQuality.HighQuality; + targetGraphics.PixelOffsetMode = PixelOffsetMode.None; + + targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + + targetGraphics.Restore(state); + } + + private void DrawSharpImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) + { + var state = targetGraphics.Save(); + targetGraphics.SmoothingMode = SmoothingMode.None; + targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; + targetGraphics.CompositingQuality = CompositingQuality.HighQuality; + targetGraphics.PixelOffsetMode = PixelOffsetMode.None; + + targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + + targetGraphics.Restore(state); + } + private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) { // check if we need to draw the checkerboard From 4c0277be90fc31ab5119ba23f716f5a0ad5f771e Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Tue, 28 Apr 2020 19:19:17 +0300 Subject: [PATCH 026/232] Robust clip region resize --- Greenshot/Drawing/Surface.cs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 09bbe028e..a6da5b4ed 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -1406,24 +1406,24 @@ namespace Greenshot.Drawing return GetImage(RenderMode.EXPORT); } - private static Rectangle ZoomClipRectangle(Rectangle rc, double scale) - => new Rectangle( + private static Rectangle ZoomClipRectangle(Rectangle rc, double scale, int inflateAmount = 0) + { + rc = new Rectangle( (int)(rc.X * scale), (int)(rc.Y * scale), - (int)((rc.Width + 1) * scale) + 1, // making sure to redraw enough pixels when moving scaled image - (int)((rc.Height + 1) * scale) + 1 - ); - - private static RectangleF ZoomClipRectangle(RectangleF rc, double scale) - => new RectangleF( - (float)Math.Floor(rc.X * scale), - (float)Math.Floor(rc.Y * scale), - (float)Math.Ceiling(rc.Width * scale), - (float)Math.Ceiling(rc.Height * scale) + (int)(rc.Width * scale) + 1, + (int)(rc.Height * scale) + 1 ); + if (scale > 1) + { + inflateAmount = (int)(inflateAmount * scale); + } + rc.Inflate(inflateAmount, inflateAmount); + return rc; + } public void InvalidateElements(Rectangle rc) - => Invalidate(ZoomClipRectangle(rc, _zoomFactor)); + => Invalidate(ZoomClipRectangle(rc, _zoomFactor, 1)); /// <summary> /// This is the event handler for the Paint Event, try to draw as little as possible! @@ -1439,7 +1439,7 @@ namespace Greenshot.Drawing LOG.Debug("Empty cliprectangle??"); return; } - Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, 1.0 / _zoomFactor); + Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, 1.0 / _zoomFactor, 2); bool isZoomedIn = ZoomFactor > 1f; if (_elements.HasIntersectingFilters(imageClipRectangle) || isZoomedIn) @@ -1467,7 +1467,7 @@ namespace Greenshot.Drawing //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; DrawBackground(graphics, imageClipRectangle); graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - graphics.SetClip(ZoomClipRectangle(targetGraphics.ClipBounds, 1.0 / _zoomFactor)); + graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), 1.0 / _zoomFactor, 2)); _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle); } targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); From e6e2ed523ab166529dd15a08eabe8fab65e31071 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Tue, 28 Apr 2020 21:43:01 +0300 Subject: [PATCH 027/232] Keep center of visible area static on zoom when possible --- Greenshot/Drawing/Surface.cs | 2 +- Greenshot/Forms/ImageEditorForm.cs | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index a6da5b4ed..339e4b02c 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -1890,7 +1890,7 @@ namespace Greenshot.Drawing /// <summary> /// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space). /// </summary> - private Rectangle GetVisibleRectangle() + public Rectangle GetVisibleRectangle() { var bounds = Bounds; var clientArea = Parent.ClientRectangle; diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index d5de0b5c9..ec53969f5 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -1572,8 +1572,24 @@ namespace Greenshot { } private void ZoomSetValue(int value) { + var surface = Surface as Surface; + var panel = surface?.Parent as Panel; + if (panel == null) + { + return; + } + + // Store old scroll position + var rc = surface.GetVisibleRectangle(); + var size = surface.Size; + var horizontalCenter = 1.0 * (rc.Left + rc.Width / 2) / size.Width; + var verticalCenter = 1.0 * (rc.Top + rc.Height / 2) / size.Height; + + // Set the new zoom value _zoomValue = value; Surface.ZoomFactor = 1f * value / 100; + Size = GetOptimalWindowSize(); + AlignCanvasPositionAfterResize(); // Update zoom controls string valueString = value.ToString(); @@ -1584,8 +1600,13 @@ namespace Greenshot { } } - Size = GetOptimalWindowSize(); - AlignCanvasPositionAfterResize(); + // Restore scroll position + rc = surface.GetVisibleRectangle(); + size = surface.Size; + panel.AutoScrollPosition = new Point( + (int)(horizontalCenter * size.Width) - rc.Width / 2, + (int)(verticalCenter * size.Height) - rc.Height / 2 + ); } } } From 1ef2df9602dc155279e78024c7247e2618905446 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Tue, 28 Apr 2020 21:46:45 +0300 Subject: [PATCH 028/232] Unneeded using after 169dbdc --- Greenshot/Drawing/DrawableContainer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index e7caf7ea3..33339ee00 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -33,7 +33,6 @@ using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; -using System.Windows.Forms; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Drawing.Adorners; From 99742ad05ad203c44b7ef8ed7a857a3de08d47dd Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Wed, 29 Apr 2020 23:23:29 +0300 Subject: [PATCH 029/232] Fix for Best Fit on images bigger than 4 times the available space --- Greenshot/Forms/ImageEditorForm.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index ec53969f5..334a72dc3 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -1562,11 +1562,12 @@ namespace Greenshot { static bool isFit(int zoom, int source, int boundary) => source * zoom / 100 <= boundary; - var nextValue = Array.FindLast( + var nextIndex = Array.FindLastIndex( ZOOM_VALUES, zoom => isFit(zoom, imageSize.Width, maxImageSize.Width) && isFit(zoom, imageSize.Height, maxImageSize.Height) ); + var nextValue = nextIndex < 0 ? ZOOM_VALUES[0] : ZOOM_VALUES[nextIndex]; ZoomSetValue(nextValue); } From 464e5e872f723b2cd0df343c5b82c309088a41c6 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Thu, 30 Apr 2020 17:39:03 +0300 Subject: [PATCH 030/232] Fix weird scroll position when going from no scroll zoom value Also prefer top left corner in that situation - it is less disorienting when working with screenshots. --- Greenshot/Forms/ImageEditorForm.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index 334a72dc3..ca0cb1a7b 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -1581,10 +1581,19 @@ namespace Greenshot { } // Store old scroll position + // When no scroll is currently needed - prefer top left corner. + var horizontalCenter = 0.0; + var verticalCenter = 0.0; var rc = surface.GetVisibleRectangle(); var size = surface.Size; - var horizontalCenter = 1.0 * (rc.Left + rc.Width / 2) / size.Width; - var verticalCenter = 1.0 * (rc.Top + rc.Height / 2) / size.Height; + if (size.Width > rc.Width) + { + horizontalCenter = 1.0 * (rc.Left + rc.Width / 2) / size.Width; + } + if (size.Height > rc.Height) + { + verticalCenter = 1.0 * (rc.Top + rc.Height / 2) / size.Height; + } // Set the new zoom value _zoomValue = value; From dcf75fd081b6b0792069fa7a88c4cccf0b8ee626 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Thu, 30 Apr 2020 17:57:36 +0300 Subject: [PATCH 031/232] Use Fractions to represent zoom factor The goal is to be able to get as close as possible to perfect 66.(6)% (2/3) zoom factor, and also remove types mismatch between the editor form and the surface. --- Greenshot/Drawing/Surface.cs | 13 +- Greenshot/Forms/ImageEditorForm.Designer.cs | 18 +-- Greenshot/Forms/ImageEditorForm.cs | 24 ++-- GreenshotPlugin/Core/Fraction.cs | 152 ++++++++++++++++++++ GreenshotPlugin/Interfaces/ISurface.cs | 5 +- 5 files changed, 183 insertions(+), 29 deletions(-) create mode 100644 GreenshotPlugin/Core/Fraction.cs diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 339e4b02c..811466cf7 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -307,15 +307,16 @@ namespace Greenshot.Drawing [NonSerialized] private Matrix _inverseZoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); [NonSerialized] - private float _zoomFactor = 1.0f; - public float ZoomFactor + private Fraction _zoomFactor = Fraction.Identity; + public Fraction ZoomFactor { get => _zoomFactor; set { _zoomFactor = value; + var inverse = _zoomFactor.Inverse(); _zoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0); - _inverseZoomMatrix = new Matrix(1f / _zoomFactor, 0, 0, 1f / _zoomFactor, 0, 0); + _inverseZoomMatrix = new Matrix(inverse, 0, 0, inverse, 0, 0); UpdateSize(); } } @@ -1439,9 +1440,9 @@ namespace Greenshot.Drawing LOG.Debug("Empty cliprectangle??"); return; } - Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, 1.0 / _zoomFactor, 2); + Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2); - bool isZoomedIn = ZoomFactor > 1f; + bool isZoomedIn = _zoomFactor > Fraction.Identity; if (_elements.HasIntersectingFilters(imageClipRectangle) || isZoomedIn) { if (_buffer != null) @@ -1467,7 +1468,7 @@ namespace Greenshot.Drawing //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; DrawBackground(graphics, imageClipRectangle); graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), 1.0 / _zoomFactor, 2)); + graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), _zoomFactor.Inverse(), 2)); _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle); } targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); diff --git a/Greenshot/Forms/ImageEditorForm.Designer.cs b/Greenshot/Forms/ImageEditorForm.Designer.cs index 606b72773..04da3d0a0 100644 --- a/Greenshot/Forms/ImageEditorForm.Designer.cs +++ b/Greenshot/Forms/ImageEditorForm.Designer.cs @@ -1718,7 +1718,7 @@ namespace Greenshot { // this.zoom25MenuItem.Name = "zoom25MenuItem"; this.zoom25MenuItem.Size = new System.Drawing.Size(209, 22); - this.zoom25MenuItem.Tag = "25"; + this.zoom25MenuItem.Tag = "1/4"; this.zoom25MenuItem.Text = "25%"; this.zoom25MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); // @@ -1726,7 +1726,7 @@ namespace Greenshot { // this.zoom50MenuItem.Name = "zoom50MenuItem"; this.zoom50MenuItem.Size = new System.Drawing.Size(209, 22); - this.zoom50MenuItem.Tag = "50"; + this.zoom50MenuItem.Tag = "1/2"; this.zoom50MenuItem.Text = "50%"; this.zoom50MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); // @@ -1734,7 +1734,7 @@ namespace Greenshot { // this.zoom66MenuItem.Name = "zoom66MenuItem"; this.zoom66MenuItem.Size = new System.Drawing.Size(209, 22); - this.zoom66MenuItem.Tag = "66"; + this.zoom66MenuItem.Tag = "2/3"; this.zoom66MenuItem.Text = "66%"; this.zoom66MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); // @@ -1742,7 +1742,7 @@ namespace Greenshot { // this.zoom75MenuItem.Name = "zoom75MenuItem"; this.zoom75MenuItem.Size = new System.Drawing.Size(209, 22); - this.zoom75MenuItem.Tag = "75"; + this.zoom75MenuItem.Tag = "3/4"; this.zoom75MenuItem.Text = "75%"; this.zoom75MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); // @@ -1757,7 +1757,7 @@ namespace Greenshot { this.zoomActualSizeMenuItem.Name = "zoomActualSizeMenuItem"; this.zoomActualSizeMenuItem.ShortcutKeyDisplayString = "Ctrl+0"; this.zoomActualSizeMenuItem.Size = new System.Drawing.Size(209, 22); - this.zoomActualSizeMenuItem.Tag = "100"; + this.zoomActualSizeMenuItem.Tag = "1/1"; this.zoomActualSizeMenuItem.Text = "100% - Actual Size"; this.zoomActualSizeMenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); // @@ -1770,7 +1770,7 @@ namespace Greenshot { // this.zoom200MenuItem.Name = "zoom200MenuItem"; this.zoom200MenuItem.Size = new System.Drawing.Size(209, 22); - this.zoom200MenuItem.Tag = "200"; + this.zoom200MenuItem.Tag = "2/1"; this.zoom200MenuItem.Text = "200%"; this.zoom200MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); // @@ -1778,7 +1778,7 @@ namespace Greenshot { // this.zoom300MenuItem.Name = "zoom300MenuItem"; this.zoom300MenuItem.Size = new System.Drawing.Size(209, 22); - this.zoom300MenuItem.Tag = "300"; + this.zoom300MenuItem.Tag = "3/1"; this.zoom300MenuItem.Text = "300%"; this.zoom300MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); // @@ -1786,7 +1786,7 @@ namespace Greenshot { // this.zoom400MenuItem.Name = "zoom400MenuItem"; this.zoom400MenuItem.Size = new System.Drawing.Size(209, 22); - this.zoom400MenuItem.Tag = "400"; + this.zoom400MenuItem.Tag = "4/1"; this.zoom400MenuItem.Text = "400%"; this.zoom400MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); // @@ -1794,7 +1794,7 @@ namespace Greenshot { // this.zoom600MenuItem.Name = "zoom600MenuItem"; this.zoom600MenuItem.Size = new System.Drawing.Size(209, 22); - this.zoom600MenuItem.Tag = "600"; + this.zoom600MenuItem.Tag = "6/1"; this.zoom600MenuItem.Text = "600%"; this.zoom600MenuItem.Click += new System.EventHandler(this.ZoomSetValueMenuItemClick); // diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index ca0cb1a7b..0b5c40d42 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -69,8 +69,7 @@ namespace Greenshot { /// <summary> /// All provided zoom values (in percents) in ascending order. /// </summary> - private readonly int[] ZOOM_VALUES = new[] { 25, 50, 66, 75, 100, 200, 300, 400, 600 }; - private int _zoomValue = 100; + private readonly Fraction[] ZOOM_VALUES = new Fraction[] { (1, 4), (1, 2), (2, 3), (3, 4), (1 ,1), (2, 1), (3, 1), (4, 1), (6, 1) }; /// <summary> /// An Implementation for the IImageEditor, this way Plugins have access to the HWND handles wich can be used with Win32 API calls. @@ -1533,14 +1532,16 @@ namespace Greenshot { } private void ZoomInMenuItemClick(object sender, EventArgs e) { - var nextIndex = Array.FindIndex(ZOOM_VALUES, v => v > _zoomValue); + var zoomValue = Surface.ZoomFactor; + var nextIndex = Array.FindIndex(ZOOM_VALUES, v => v > zoomValue); var nextValue = nextIndex < 0 ? ZOOM_VALUES[ZOOM_VALUES.Length - 1] : ZOOM_VALUES[nextIndex]; ZoomSetValue(nextValue); } private void ZoomOutMenuItemClick(object sender, EventArgs e) { - var nextIndex = Array.FindLastIndex(ZOOM_VALUES, v => v < _zoomValue); + var zoomValue = Surface.ZoomFactor; + var nextIndex = Array.FindLastIndex(ZOOM_VALUES, v => v < zoomValue); var nextValue = nextIndex < 0 ? ZOOM_VALUES[0] : ZOOM_VALUES[nextIndex]; ZoomSetValue(nextValue); @@ -1548,7 +1549,7 @@ namespace Greenshot { private void ZoomSetValueMenuItemClick(object sender, EventArgs e) { var senderMenuItem = (ToolStripMenuItem)sender; - int zoomPercent = int.Parse((string)senderMenuItem.Tag); + var zoomPercent = Fraction.Parse((string)senderMenuItem.Tag); ZoomSetValue(zoomPercent); } @@ -1559,8 +1560,8 @@ namespace Greenshot { var maxImageSize = maxWindowSize - chromeSize; var imageSize = Surface.Image.Size; - static bool isFit(int zoom, int source, int boundary) - => source * zoom / 100 <= boundary; + static bool isFit(Fraction scale, int source, int boundary) + => (int)(source * scale) <= boundary; var nextIndex = Array.FindLastIndex( ZOOM_VALUES, @@ -1572,7 +1573,7 @@ namespace Greenshot { ZoomSetValue(nextValue); } - private void ZoomSetValue(int value) { + private void ZoomSetValue(Fraction value) { var surface = Surface as Surface; var panel = surface?.Parent as Panel; if (panel == null) @@ -1596,14 +1597,13 @@ namespace Greenshot { } // Set the new zoom value - _zoomValue = value; - Surface.ZoomFactor = 1f * value / 100; + Surface.ZoomFactor = value; Size = GetOptimalWindowSize(); AlignCanvasPositionAfterResize(); // Update zoom controls - string valueString = value.ToString(); - zoomStatusDropDownBtn.Text = valueString + "%"; + zoomStatusDropDownBtn.Text = ((int)(100 * (double)value)).ToString() + "%"; + var valueString = value.ToString(); foreach (var item in zoomMenuStrip.Items) { if (item is ToolStripMenuItem menuItem) { menuItem.Checked = menuItem.Tag as string == valueString; diff --git a/GreenshotPlugin/Core/Fraction.cs b/GreenshotPlugin/Core/Fraction.cs new file mode 100644 index 000000000..312b91bb8 --- /dev/null +++ b/GreenshotPlugin/Core/Fraction.cs @@ -0,0 +1,152 @@ +using System; +using System.Text.RegularExpressions; + +namespace GreenshotPlugin.Core +{ + /// <summary> + /// Basic Fraction (Rational) numbers with features only needed to represent scale factors. + /// </summary> + public readonly struct Fraction : IEquatable<Fraction>, IComparable<Fraction> + { + public static Fraction Identity { get; } = new Fraction(1, 1); + + public uint Numerator { get; } + public uint Denominator { get; } + + public Fraction(uint numerator, uint denominator) + { + if (denominator == 0) + { + throw new ArgumentException("Can't divide by zero.", nameof(denominator)); + } + if (numerator == 0) + { + throw new ArgumentException("Zero is not supported by this implementation.", nameof(numerator)); + } + var gcd = GreatestCommonDivisor(numerator, denominator); + Numerator = numerator / gcd; + Denominator = denominator / gcd; + } + + public Fraction Inverse() + => new Fraction(Denominator, Numerator); + + #region Parse + + private static readonly Regex PARSE_REGEX = new Regex(@"^([1-9][0-9]*)\/([1-9][0-9]*)$", RegexOptions.Compiled); + public static bool TryParse(string str, out Fraction result) + { + var match = PARSE_REGEX.Match(str); + if (!match.Success) + { + result = Identity; + return false; + } + var numerator = uint.Parse(match.Groups[1].Value); + var denominator = uint.Parse(match.Groups[2].Value); + result = new Fraction(numerator, denominator); + return true; + } + + public static Fraction Parse(string str) + => TryParse(str, out var result) + ? result + : throw new ArgumentException($"Could not parse the input \"{str}\".", nameof(str)); + + #endregion + + #region Overrides, interface implementations + + public override string ToString() + => $"{Numerator}/{Denominator}"; + + public override bool Equals(object obj) + => obj is Fraction fraction && Equals(fraction); + + public bool Equals(Fraction other) + => Numerator == other.Numerator && Denominator == other.Denominator; + + public override int GetHashCode() + { + unchecked + { + int hashCode = -1534900553; + hashCode = hashCode * -1521134295 + Numerator.GetHashCode(); + hashCode = hashCode * -1521134295 + Denominator.GetHashCode(); + return hashCode; + } + } + + public int CompareTo(Fraction other) + => (int)(Numerator * other.Denominator) - (int)(other.Numerator * Denominator); + + #endregion + + #region Equality operators + + public static bool operator ==(Fraction left, Fraction right) + => left.Equals(right); + + public static bool operator !=(Fraction left, Fraction right) + => !(left == right); + + #endregion + + #region Comparison operators + + public static bool operator <(Fraction left, Fraction right) + => left.CompareTo(right) < 0; + + public static bool operator <=(Fraction left, Fraction right) + => left.CompareTo(right) <= 0; + + public static bool operator >(Fraction left, Fraction right) + => left.CompareTo(right) > 0; + + public static bool operator >=(Fraction left, Fraction right) + => left.CompareTo(right) >= 0; + + #endregion + + #region Scale operators + + public static Fraction operator *(Fraction left, Fraction right) + => new Fraction(left.Numerator * right.Numerator, left.Denominator * right.Denominator); + + public static Fraction operator *(Fraction left, uint right) + => new Fraction(left.Numerator * right, left.Denominator); + + public static Fraction operator *(uint left, Fraction right) + => new Fraction(left * right.Numerator, right.Denominator); + + public static Fraction operator /(Fraction left, Fraction right) + => new Fraction(left.Numerator * right.Denominator, left.Denominator * right.Numerator); + + public static Fraction operator /(Fraction left, uint right) + => new Fraction(left.Numerator, left.Denominator * right); + + public static Fraction operator /(uint left, Fraction right) + => new Fraction(left * right.Denominator, right.Numerator); + + #endregion + + #region Type conversion operators + + public static implicit operator double(Fraction fraction) + => 1.0 * fraction.Numerator / fraction.Denominator; + + public static implicit operator float(Fraction fraction) + => 1.0f * fraction.Numerator / fraction.Denominator; + + public static implicit operator Fraction(uint number) + => new Fraction(number, 1u); + + public static implicit operator Fraction((uint numerator, uint demoninator) tuple) + => new Fraction(tuple.numerator, tuple.demoninator); + + #endregion + + private static uint GreatestCommonDivisor(uint a, uint b) + => (b != 0) ? GreatestCommonDivisor(b, a % b) : a; + } +} diff --git a/GreenshotPlugin/Interfaces/ISurface.cs b/GreenshotPlugin/Interfaces/ISurface.cs index 73b31b05d..068ab0f29 100644 --- a/GreenshotPlugin/Interfaces/ISurface.cs +++ b/GreenshotPlugin/Interfaces/ISurface.cs @@ -23,6 +23,7 @@ using System; using System.Drawing; using System.IO; using System.Windows.Forms; +using GreenshotPlugin.Core; using GreenshotPlugin.Effects; using GreenshotPlugin.Interfaces.Drawing; @@ -193,9 +194,9 @@ namespace GreenshotPlugin.Interfaces } /// <summary> - /// Zoom value applied to the surface. 1.0f for actual size (100%). + /// Zoom value applied to the surface. /// </summary> - float ZoomFactor { get; set; } + Fraction ZoomFactor { get; set; } /// <summary> /// Translate a point from image coorditate space to surface coordinate space. /// </summary> From bac1ff4ba06e855239658688cf8e23002efb248c Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Thu, 30 Apr 2020 18:30:51 +0300 Subject: [PATCH 032/232] Fix for pixel jerk --- Greenshot/Drawing/Surface.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 811466cf7..2ea5e0b00 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -1440,6 +1440,25 @@ namespace Greenshot.Drawing LOG.Debug("Empty cliprectangle??"); return; } + + // Correction to prevent rounding errors at certain zoom levels. + // When zooming to N/M, clip rectangle top and left coordinates should be multiples of N. + if (_zoomFactor.Numerator > 1 && _zoomFactor.Denominator > 1) + { + int horizontalCorrection = targetClipRectangle.Left % (int)_zoomFactor.Numerator; + int verticalCorrection = targetClipRectangle.Top % (int)_zoomFactor.Numerator; + if (horizontalCorrection != 0) + { + targetClipRectangle.X -= horizontalCorrection; + targetClipRectangle.Width += horizontalCorrection; + } + if (verticalCorrection != 0) + { + targetClipRectangle.Y -= verticalCorrection; + targetClipRectangle.Height += verticalCorrection; + } + } + Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2); bool isZoomedIn = _zoomFactor > Fraction.Identity; From f494385ef73d45527357b5eabb79a40dffbed0e7 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Thu, 30 Apr 2020 19:16:05 +0300 Subject: [PATCH 033/232] Naming consistency - not a percentage value anymore --- Greenshot/Forms/ImageEditorForm.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index 0b5c40d42..1e177e428 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -1549,9 +1549,9 @@ namespace Greenshot { private void ZoomSetValueMenuItemClick(object sender, EventArgs e) { var senderMenuItem = (ToolStripMenuItem)sender; - var zoomPercent = Fraction.Parse((string)senderMenuItem.Tag); + var nextValue = Fraction.Parse((string)senderMenuItem.Tag); - ZoomSetValue(zoomPercent); + ZoomSetValue(nextValue); } private void ZoomBestFitMenuItemClick(object sender, EventArgs e) { From d93c9d6a3a24c18a0490b72e3ddfbc48849ca221 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Fri, 1 May 2020 00:46:27 +0300 Subject: [PATCH 034/232] TextContainer's TextBox on zoom - fix for position, update font size --- Greenshot/Drawing/TextContainer.cs | 59 +++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index c73424908..939dd3de6 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -22,6 +22,7 @@ using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Memento; +using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces.Drawing; using System; using System.ComponentModel; @@ -155,6 +156,24 @@ namespace Greenshot.Drawing FieldChanged += TextContainer_FieldChanged; } + protected override void SwitchParent(Surface newParent) + { + _parent.SizeChanged -= Parent_SizeChanged; + base.SwitchParent(newParent); + _parent.SizeChanged += Parent_SizeChanged; + } + + private void Parent_SizeChanged(object sender, EventArgs e) + { + UpdateTextBoxPosition(); + UpdateTextBoxFont(); + } + + public override void ApplyBounds(RectangleF newBounds) + { + base.ApplyBounds(newBounds); + UpdateTextBoxPosition(); + } public override void Invalidate() { @@ -255,7 +274,8 @@ namespace Greenshot.Drawing AcceptsTab = true, AcceptsReturn = true, BorderStyle = BorderStyle.None, - Visible = false + Visible = false, + Font = new Font(FontFamily.GenericSansSerif, 1) // just need something non-default here }; _textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged); @@ -388,7 +408,6 @@ namespace Greenshot.Drawing var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize); _font?.Dispose(); _font = newFont; - _textBox.Font = _font; } catch (Exception ex) { @@ -400,7 +419,6 @@ namespace Greenshot.Drawing var newFont = CreateFont(fontFamily, fontBold, fontItalic, fontSize); _font?.Dispose(); _font = newFont; - _textBox.Font = _font; } catch (Exception) { @@ -413,6 +431,8 @@ namespace Greenshot.Drawing } } + UpdateTextBoxFont(); + UpdateAlignment(); } @@ -423,7 +443,29 @@ namespace Greenshot.Drawing } /// <summary> - /// This will create the textbox exactly to the inner size of the element + /// Set TextBox font according to the TextContainer font and the parent zoom factor. + /// </summary> + private void UpdateTextBoxFont() + { + if (_textBox == null || _font == null) + { + return; + } + + var textBoxFontScale = _parent?.ZoomFactor ?? Fraction.Identity; + + var newFont = new Font( + _font.FontFamily, + _font.Size * textBoxFontScale, + _font.Style, + GraphicsUnit.Pixel + ); + _textBox.Font.Dispose(); + _textBox.Font = newFont; + } + + /// <summary> + /// This will align the textbox exactly to the inner size of the element /// is a bit of a hack, but for now it seems to work... /// </summary> private void UpdateTextBoxPosition() @@ -453,12 +495,9 @@ namespace Greenshot.Drawing _textBox.Height = displayRectangle.Height - 2 * lineWidth + correction; } - public override void ApplyBounds(RectangleF newBounds) - { - base.ApplyBounds(newBounds); - UpdateTextBoxPosition(); - } - + /// <summary> + /// Set TextBox text align and fore color according to field values. + /// </summary> private void UpdateTextBoxFormat() { if (_textBox == null) From ef5b5deb7ade72376f7adef6081125ab90cec90d Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Fri, 1 May 2020 18:16:33 +0300 Subject: [PATCH 035/232] Smarter zoom - keep selected elements in sight --- Greenshot/Drawing/DrawableContainerList.cs | 24 ++++++++++++ Greenshot/Drawing/Surface.cs | 7 ++++ Greenshot/Forms/ImageEditorForm.cs | 38 +++++++++++++------ .../Interfaces/Drawing/Container.cs | 4 ++ 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs index 9451b06ea..3d200598e 100644 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ b/Greenshot/Drawing/DrawableContainerList.cs @@ -235,6 +235,30 @@ namespace Greenshot.Drawing { return false; } + /// <summary> + /// A rectangle containing DrawingBounds of all drawableContainers in this list, + /// or empty rectangle if nothing is there. + /// </summary> + public Rectangle DrawingBounds + { + get + { + if (Count == 0) + { + return Rectangle.Empty; + } + else + { + var result = this[0].DrawingBounds; + for (int i = 1; i < Count; i++) + { + result = Rectangle.Union(result, this[i].DrawingBounds); + } + return result; + } + } + } + /// <summary> /// Triggers all elements in the list ot be redrawn. /// </summary> diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 2ea5e0b00..8b33b6a56 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -1922,6 +1922,13 @@ namespace Greenshot.Drawing ); } + /// <summary> + /// Get the rectangle bounding all selected elements (in surface coordinates space), + /// or empty rectangle if nothing is selcted. + /// </summary> + public Rectangle GetSelectionRectangle() + => ToSurfaceCoordinates(selectedElements.DrawingBounds); + /// <summary> /// Duplicate all the selecteded elements /// </summary> diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index 1e177e428..8bf59df27 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -1580,21 +1580,37 @@ namespace Greenshot { { return; } + if (value == Surface.ZoomFactor) + { + return; + } - // Store old scroll position - // When no scroll is currently needed - prefer top left corner. - var horizontalCenter = 0.0; - var verticalCenter = 0.0; - var rc = surface.GetVisibleRectangle(); + // Store scroll position + var rc = surface.GetVisibleRectangle(); // use visible rc by default var size = surface.Size; - if (size.Width > rc.Width) + if (value > Surface.ZoomFactor) // being smart on zoom-in { - horizontalCenter = 1.0 * (rc.Left + rc.Width / 2) / size.Width; - } - if (size.Height > rc.Height) - { - verticalCenter = 1.0 * (rc.Top + rc.Height / 2) / size.Height; + var sel = surface.GetSelectionRectangle(); + if (sel != Rectangle.Empty) + { + rc.Intersect(sel); // zoom to visible part of selection + } + else + { + // if image fits completely to currently visible rc and there are no things to focus on + // - prefer top left corner to zoom-in as less disorienting for screenshots + if (size.Width < rc.Width) + { + rc.Width = 0; + } + if (size.Height < rc.Height) + { + rc.Height = 0; + } + } } + var horizontalCenter = 1.0 * (rc.Left + rc.Width / 2) / size.Width; + var verticalCenter = 1.0 * (rc.Top + rc.Height / 2) / size.Height; // Set the new zoom value Surface.ZoomFactor = value; diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/GreenshotPlugin/Interfaces/Drawing/Container.cs index 35a6cf50a..f4065801a 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Container.cs @@ -145,6 +145,10 @@ namespace GreenshotPlugin.Interfaces.Drawing get; set; } + Rectangle DrawingBounds + { + get; + } void MakeBoundsChangeUndoable(bool allowMerge); void Transform(Matrix matrix); void MoveBy(int dx, int dy); From 0fce43404d4a87c28713cfa9fdf10c845142e8c1 Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Fri, 1 May 2020 18:45:10 +0300 Subject: [PATCH 036/232] Fix: prevent image blurring at 100% zoom Even at 100% GDI+ manages to do some smoothing. Also minor optimization - not messing with Graphics state when not needed. --- Greenshot/Drawing/Surface.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 8b33b6a56..9f2a839cd 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -1461,8 +1461,7 @@ namespace Greenshot.Drawing Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2); - bool isZoomedIn = _zoomFactor > Fraction.Identity; - if (_elements.HasIntersectingFilters(imageClipRectangle) || isZoomedIn) + if (_elements.HasIntersectingFilters(imageClipRectangle) || _zoomFactor > Fraction.Identity) { if (_buffer != null) { @@ -1491,7 +1490,11 @@ namespace Greenshot.Drawing _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle); } targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); - if (isZoomedIn) + if (_zoomFactor == Fraction.Identity) + { + targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + } + else if(_zoomFactor > Fraction.Identity) { DrawSharpImage(targetGraphics, _buffer, imageClipRectangle); } @@ -1506,7 +1509,14 @@ namespace Greenshot.Drawing DrawBackground(targetGraphics, targetClipRectangle); targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); - DrawSmoothImage(targetGraphics, Image, imageClipRectangle); + if (_zoomFactor == Fraction.Identity) + { + targetGraphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + } + else + { + DrawSmoothImage(targetGraphics, Image, imageClipRectangle); + } _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); targetGraphics.ResetTransform(); } From b2a6fc877403388eb007fe8272242c964a0c0a1e Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Fri, 1 May 2020 18:53:08 +0300 Subject: [PATCH 037/232] No ScaleTransform is needed at 100% zoom --- Greenshot/Drawing/Surface.cs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 9f2a839cd..6c89238f0 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -1489,36 +1489,39 @@ namespace Greenshot.Drawing graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), _zoomFactor.Inverse(), 2)); _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle); } - targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); if (_zoomFactor == Fraction.Identity) { targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); } - else if(_zoomFactor > Fraction.Identity) - { - DrawSharpImage(targetGraphics, _buffer, imageClipRectangle); - } else { - DrawSmoothImage(targetGraphics, _buffer, imageClipRectangle); + targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); + if (_zoomFactor > Fraction.Identity) + { + DrawSharpImage(targetGraphics, _buffer, imageClipRectangle); + } + else + { + DrawSmoothImage(targetGraphics, _buffer, imageClipRectangle); + } + targetGraphics.ResetTransform(); } - targetGraphics.ResetTransform(); } else { DrawBackground(targetGraphics, targetClipRectangle); - - targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); if (_zoomFactor == Fraction.Identity) { targetGraphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); } else { + targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); DrawSmoothImage(targetGraphics, Image, imageClipRectangle); + _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); + targetGraphics.ResetTransform(); } - _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); - targetGraphics.ResetTransform(); } // No clipping for the adorners From 79ea558dbbdede0d1fcd5a1f2a7520d8d800648b Mon Sep 17 00:00:00 2001 From: Killy <killy.mxi@gmail.com> Date: Sat, 2 May 2020 01:52:05 +0300 Subject: [PATCH 038/232] Fix: zoom-in when selection is out of sight --- Greenshot/Forms/ImageEditorForm.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index 8bf59df27..d397b8bc8 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -1590,10 +1590,11 @@ namespace Greenshot { var size = surface.Size; if (value > Surface.ZoomFactor) // being smart on zoom-in { - var sel = surface.GetSelectionRectangle(); - if (sel != Rectangle.Empty) + var selection = surface.GetSelectionRectangle(); + selection.Intersect(rc); + if (selection != Rectangle.Empty) { - rc.Intersect(sel); // zoom to visible part of selection + rc = selection; // zoom to visible part of selection } else { From 5a06b02d0ddf88c5f6e4720464efbd7f9f31731c Mon Sep 17 00:00:00 2001 From: Greenshot-AppVeyor <getgreenshot@gmail.com> Date: Sat, 2 May 2020 21:44:44 +0200 Subject: [PATCH 039/232] Backport Italian Language Updates from Pull Request #198 --- Greenshot/Languages/language-it-IT.xml | 629 +++++++++++++------------ 1 file changed, 328 insertions(+), 301 deletions(-) diff --git a/Greenshot/Languages/language-it-IT.xml b/Greenshot/Languages/language-it-IT.xml index 58c8d11de..bb553e735 100644 --- a/Greenshot/Languages/language-it-IT.xml +++ b/Greenshot/Languages/language-it-IT.xml @@ -1,313 +1,340 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.0.4" languagegroup="1"> - <resources> - <resource name="about_bugs">Per favore, riporta le anomalie a</resource> - <resource name="about_donations">Se gradisci Greenshot, puoi darci il tuo aiuto su:</resource> - <resource name="about_host">Greenshot è disponibile su GitHub a</resource> - <resource name="about_icons">Icone prese da Yusuke Kamiyamane's Fugue icon set (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom -Greenshot viene fornito SENZA ALCUNA GARANZIA. Questo è "free software", e potete ri-distribuirlo secondo certe condizioni. -Dettagli sulla General Public License GNU:</resource> - <resource name="about_title">Notizie su Greenshot</resource> - <resource name="about_translation">Traduzione in Italiano curata da tonytogna</resource> - <resource name="application_title">Greenshot - Uno straordinario strumento per copiare immagini dallo schermo</resource> - <resource name="bugreport_cancel">Chiudi</resource> - <resource name="bugreport_info">Opss, si è verificato un errore inaspettato. +<language description="Italiano" ietf="it-IT" version="1.3.0" languagegroup="1"> + <resources> + <resource name="about_bugs">Seganal le anomalie a</resource> + <resource name="about_donations">Se ti piace Greenshot, dacci il tuo aiuto su:</resource> + <resource name="about_host">Greenshot è disponibile su GitHub in</resource> + <resource name="about_icons">Libreria icone del set icone Fugue di Yusuke Kamiyamane (Creative Commons Attribution 3.0 license)</resource> + <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +Greenshot viene fornito SENZA ALCUNA GARANZIA. +Questo software è garuitio", e potete ri-distribuirlo secondo certe condizioni. +Dettagli della General Public License GNU: + </resource> + <resource name="about_title">Notizie su Greenshot</resource> + <resource name="about_translation">Traduzione in Italiano curata da bovirus e tonytogna</resource> + <resource name="application_title">Greenshot - Uno straordinario strumento per copiare immagini dallo schermo</resource> + <resource name="bugreport_cancel">Chiudi</resource> + <resource name="bugreport_info">Si è verificato un errore inaspettato. -La buona notizia è: puoi aiutarci ad eliminarlo riempiendo la segnalazione errori. -Visita la pagina internet qui sotto, crea una nuova segnalazione errore e copia nella descrizione il contenuto preso dall'area di testo. +La buona notizia è che puoi aiutarci ad eliminarlo segnalandoci l'errore. +Visita la pagina internet qui sotto, crea una nuova segnalazione errore e copia nella descrizione il +contenuto preso dall'area di testo. -Aggiungi un riepilogo significativo e includi qualsiasi informazione tu consideri possa esserci d'aiuto per risolvere il problema. -Inoltre, apprezzeremo molto se prima di inserire, tu controllassi se esiste già una segnalazione per questo tipo di errore (puoi usare la ricerca) Grazie :)</resource> - <resource name="bugreport_title">Errore</resource> - <resource name="CANCEL">Annulla</resource> - <resource name="clipboard_error">Si è verificato un errore inaspettato durante la scrittura sugli appunti.</resource> - <resource name="clipboard_noimage">Nessuna immagine sugli Appunti.</resource> - <resource name="clipboard_inuse">Greenshot non è riuscito a scrivere sugli appunti poichè il processo {0} teneva l'accesso bloccato.</resource> - <resource name="ClipboardFormat.BITMAP">Windows Bitmap</resource> - <resource name="ClipboardFormat.DIB">Device Independend Bitmap (DIB)</resource> - <resource name="ClipboardFormat.HTML">HTML</resource> - <resource name="ClipboardFormat.HTMLDATAURL">HTML con immagini in linea</resource> - <resource name="ClipboardFormat.PNG">PNG</resource> - <resource name="colorpicker_alpha">Alfa</resource> - <resource name="colorpicker_apply">Applica</resource> - <resource name="colorpicker_blue">Blu</resource> - <resource name="colorpicker_green">Verde</resource> - <resource name="colorpicker_htmlcolor">Colore HTML</resource> - <resource name="colorpicker_recentcolors">Colori usati di recente</resource> - <resource name="colorpicker_red">Rosso</resource> - <resource name="colorpicker_title">Scelta colore</resource> - <resource name="colorpicker_transparent">Trasparente</resource> - <resource name="com_rejected">La destinazione {0} ha rifiutato l'accesso a Greenshot, probabilmente c'è una finestra aperta. Chiudi la finestra e riprova nuovamente.</resource> - <resource name="com_rejected_title">Accesso rifiutato a Greenshot</resource> - <resource name="config_unauthorizedaccess_write">Il file di configurazione di Greenshot non può essere salvato. Controllare i permessi di accesso per '{0}'.</resource> - <resource name="contextmenu_about">Notizie su Greenshot</resource> - <resource name="contextmenu_capturearea">Cattura regione</resource> - <resource name="contextmenu_captureclipboard">Apri immagine dagli appunti</resource> - <resource name="contextmenu_capturefullscreen">Cattura schermo intero</resource> - <resource name="contextmenu_capturefullscreen_all">Tutto</resource> - <resource name="contextmenu_capturefullscreen_bottom">Basso</resource> - <resource name="contextmenu_capturefullscreen_left">Sinistra</resource> - <resource name="contextmenu_capturefullscreen_right">Destra</resource> - <resource name="contextmenu_capturefullscreen_top">Alto</resource> - <resource name="contextmenu_captureie">Cattura Internet Explorer</resource> - <resource name="contextmenu_captureiefromlist">Cattura Internet Explorer da lista</resource> - <resource name="contextmenu_capturelastregion">Cattura ultima regione</resource> - <resource name="contextmenu_capturewindow">Cattura finestra</resource> - <resource name="contextmenu_capturewindowfromlist">Cattura finestra da lista</resource> - <resource name="contextmenu_donate">Supporta Greenshot</resource> - <resource name="contextmenu_exit">Esci</resource> - <resource name="contextmenu_help">Aiuto</resource> - <resource name="contextmenu_openfile">Apri immagine da file</resource> - <resource name="contextmenu_openrecentcapture">Apri ultima ubicazione di cattura</resource> - <resource name="contextmenu_quicksettings">Preferenze veloci</resource> - <resource name="contextmenu_settings">Preferenze...</resource> - <resource name="destination_exportfailed">Errori durente l'esportazione verso {0}. Pregasi riprovare nuovamente.</resource> - <resource name="editor_align_bottom">In basso</resource> - <resource name="editor_align_center">Centro</resource> - <resource name="editor_align_horizontal">Allineamento orizzontale</resource> - <resource name="editor_align_left">Sinistra</resource> - <resource name="editor_align_middle">In mezzo</resource> - <resource name="editor_align_right">Destra</resource> - <resource name="editor_align_top">Alto</resource> - <resource name="editor_align_vertical">Allineamento verticale</resource> - <resource name="editor_arrange">Disponi</resource> - <resource name="editor_arrowheads">Tipi di punta di freccia</resource> - <resource name="editor_arrowheads_both">Entrambe</resource> - <resource name="editor_arrowheads_end">Punto finale</resource> - <resource name="editor_arrowheads_none">Nessuna</resource> - <resource name="editor_arrowheads_start">Punto iniziale</resource> - <resource name="editor_autocrop">Ritaglia Automaticamente</resource> - <resource name="editor_backcolor">Colore di riempimento</resource> - <resource name="editor_blur_radius">Raggio sfumatura</resource> - <resource name="editor_bold">Grassetto</resource> - <resource name="editor_border">Bordi</resource> - <resource name="editor_brightness">Luminosità</resource> - <resource name="editor_cancel">Cancella</resource> - <resource name="editor_clipboardfailed">Errore durante l'accesso agli appunti. Ritenta nuovamente.</resource> - <resource name="editor_close">Chiudi</resource> - <resource name="editor_close_on_save">Desideri salvare l'immagine?</resource> - <resource name="editor_close_on_save_title">Salva l'immagine?</resource> - <resource name="editor_confirm">Conferma</resource> - <resource name="editor_copyimagetoclipboard">Copia immagine sugli appunti</resource> - <resource name="editor_copypathtoclipboard">Copia percorso sugli appunti</resource> - <resource name="editor_copytoclipboard">Copia</resource> - <resource name="editor_crop">Ritaglia (C)</resource> - <resource name="editor_cursortool">Strumento di selezione (ESC)</resource> - <resource name="editor_cuttoclipboard">Taglia</resource> - <resource name="editor_deleteelement">Elimina</resource> - <resource name="editor_downonelevel">Giù di un livello</resource> - <resource name="editor_downtobottom">Giù fino in fondo</resource> - <resource name="editor_drawarrow">Disegna freccia (A)</resource> - <resource name="editor_drawellipse">Disegna ellisse (E)</resource> - <resource name="editor_drawfreehand">Disegna mano libera (F)</resource> - <resource name="editor_drawhighlighter">Evidenzia (H)</resource> - <resource name="editor_drawline">Disegna linea (L)</resource> - <resource name="editor_drawrectangle">Disegna rettangolo (R)</resource> - <resource name="editor_drawtextbox">Aggiungi casella di testo (T)</resource> - <resource name="editor_duplicate">Duplica elementi selezionati</resource> - <resource name="editor_edit">Modifica</resource> - <resource name="editor_effects">Effetti</resource> - <resource name="editor_email">E-Mail</resource> - <resource name="editor_file">File</resource> - <resource name="editor_fontsize">Dimensioni</resource> - <resource name="editor_forecolor">Colore linea</resource> - <resource name="editor_grayscale">Scala di grigi</resource> - <resource name="editor_highlight_area">Evidenzia l'area</resource> - <resource name="editor_highlight_grayscale">Scala di grigi</resource> - <resource name="editor_highlight_magnify">Ingrandisci</resource> - <resource name="editor_highlight_mode">Modalità evidenziazione</resource> - <resource name="editor_highlight_text">Evidenzia il testo</resource> - <resource name="editor_image_shadow">Aggiungi ombra</resource> - <resource name="editor_imagesaved">Immagine salvata su {0}.</resource> - <resource name="editor_insertwindow">Inserisci finestra</resource> - <resource name="editor_invert">Negativo</resource> - <resource name="editor_italic">Corsivo</resource> - <resource name="editor_load_objects">Carica oggetti da file</resource> - <resource name="editor_magnification_factor">Fattore di ingrandimento</resource> - <resource name="editor_match_capture_size">Adatta a dimensioni di cattura</resource> - <resource name="editor_obfuscate">Offusca (O)</resource> - <resource name="editor_obfuscate_blur">Sfuma</resource> - <resource name="editor_obfuscate_mode">Modalità di offuscamento</resource> - <resource name="editor_obfuscate_pixelize">Offusca/ pixelize</resource> - <resource name="editor_object">Oggetti</resource> - <resource name="editor_opendirinexplorer">Apri cartella su Windows Explorer</resource> - <resource name="editor_pastefromclipboard">Incolla</resource> - <resource name="editor_pixel_size">Dimensioni pixel</resource> - <resource name="editor_preview_quality">Qualità anteprima</resource> - <resource name="editor_print">Stampa</resource> - <resource name="editor_redo">Ripeti azione {0}</resource> - <resource name="editor_resetsize">Azzera Dimensione</resource> - <resource name="editor_resize_percent">Percentuale</resource> - <resource name="editor_resize_pixel">Pixels</resource> - <resource name="editor_rotateccw">Ruota senso antiorario</resource> - <resource name="editor_rotatecw">Ruota senso orario</resource> - <resource name="editor_save">Salva</resource> - <resource name="editor_save_objects">Salva oggetti su file</resource> - <resource name="editor_saveas">Salva come...</resource> - <resource name="editor_selectall">Seleziona tutto</resource> - <resource name="editor_senttoprinter">Stampa inviata a '{0}'.</resource> - <resource name="editor_shadow">Ombra</resource> - <resource name="editor_image_shadow">Ombra</resource> - <resource name="editor_storedtoclipboard">Immagine posta negli appunti (clipboard).</resource> - <resource name="editor_thickness">Spessore linea</resource> - <resource name="editor_title">Gestione Immagini di Greenshot</resource> - <resource name="editor_torn_edge">Bordi strappati</resource> - <resource name="editor_undo">Annulla azione {0}</resource> - <resource name="editor_uponelevel">Su di un livello</resource> - <resource name="editor_uptotop">Su fino in cima</resource> - <resource name="EmailFormat.MAPI">Client MAPI</resource> - <resource name="EmailFormat.OUTLOOK_HTML">Outlook con HTML</resource> - <resource name="EmailFormat.OUTLOOK_TXT">Outlook con testo</resource> - <resource name="error">Errore</resource> - <resource name="error_multipleinstances">Un istanza di Greenshot è già attiva.</resource> - <resource name="error_nowriteaccess">Non è possibile salvare il file su {0}. -Verifica l'accesso in scrittura sulla destinazione di salvataggio.</resource> - <resource name="error_openfile">Il file "{0}" non può essere aperto.</resource> - <resource name="error_openlink">Impossibile aprire il link '{0}'.</resource> - <resource name="error_save">Impossibile salvare l'immagine, è necessario trovare una destinazione valida.</resource> - <resource name="expertsettings">Utente esperto</resource> - <resource name="expertsettings_autoreducecolors">Crea una immagine 8-bit se i colori sono meno di 256 e l'immagine ha > 8 bits</resource> - <resource name="expertsettings_checkunstableupdates">Controlla anche per Aggiornamenti instabili</resource> - <resource name="expertsettings_clipboardformats">Formati degli appunti</resource> - <resource name="expertsettings_counter">Numero per var. ${NUM} nel modello del nome file</resource> - <resource name="expertsettings_enableexpert">Sono consapevole di ciò che sto facendo!</resource> - <resource name="expertsettings_footerpattern">Modello piede di stampa</resource> - <resource name="expertsettings_minimizememoryfootprint">Riduci uso della memoria, perdendo però in prestazioni (sconsigliato).</resource> - <resource name="expertsettings_optimizeforrdp">Esegui ottimizzazioni per uso con desktop remoto</resource> - <resource name="expertsettings_reuseeditorifpossible">Riutilizza la Gestione Immagini, se possibile</resource> - <resource name="expertsettings_suppresssavedialogatclose">Evita avviso di salvataggio in chiusura della gestione immagini</resource> - <resource name="expertsettings_thumbnailpreview">Mostra anteprima finestra nel menù di contesto (Vista e Windows 7)</resource> - <resource name="exported_to">Esportato su: {0}</resource> - <resource name="exported_to_error">Si è verificato un errore durante l'esportazione verso {0}:</resource> - <resource name="help_title">Guida di Greenshot</resource> - <resource name="hotkeys">Scorciatoie di tastiera</resource> - <resource name="jpegqualitydialog_choosejpegquality">Scegliere la qualità per l'immagine JPEG.</resource> - <resource name="jpegqualitydialog_dontaskagain">Salva come qualità JPEG di default, e non chiedere nuovamente</resource> - <resource name="jpegqualitydialog_title">Qualità JPEG di Greenshot</resource> - <resource name="OK">Ok</resource> - <resource name="print_error">Si è verificato un errore durante la stampa.</resource> - <resource name="printoptions_allowcenter">Centra nella pagina</resource> - <resource name="printoptions_allowenlarge">Ingrandisci fino alle dimensioni pagina</resource> - <resource name="printoptions_allowrotate">Ruota a seconda dell'orientamento pagina</resource> - <resource name="printoptions_allowshrink">Riduci alle dimensioni pagina</resource> - <resource name="printoptions_dontaskagain">Salva le opzioni come default, e non chiedere più</resource> - <resource name="printoptions_inverted">Stampa con colori invertiti (negativo)</resource> - <resource name="printoptions_colors">Impostazione Colori</resource> - <resource name="printoptions_printgrayscale">Forza stampa in scala di grigi</resource> - <resource name="printoptions_printmonochrome">Forza stampa in bianco e nero</resource> - <resource name="printoptions_timestamp">Stampa data / ora sul piede della pagina</resource> - <resource name="printoptions_title">Opzioni di stampa di Greenshot</resource> - <resource name="printoptions_layout">Impostazioni Layout di pagina</resource> - <resource name="printoptions_printcolor">Forza stampa a colori</resource> - <resource name="qualitydialog_dontaskagain">Save come qualità di default, e non chiedere più</resource> - <resource name="qualitydialog_title">Qualità di Greenshot</resource> - <resource name="quicksettings_destination_file">Salva direttamente (usando le impostazioni di emissione preferite)</resource> - <resource name="settings_alwaysshowprintoptionsdialog">Visualizza scelta opzioni di stampa ogni volta che si stampa un'immagine</resource> - <resource name="settings_alwaysshowqualitydialog">Visualizza scelta qualità ogni volta che si salva una immagine</resource> - <resource name="settings_applicationsettings">Impostazioni dell'applicazione</resource> - <resource name="settings_autostartshortcut">Lancia Greenshot all'avvio</resource> - <resource name="settings_capture">Cattura</resource> - <resource name="settings_capture_mousepointer">Cattura puntatore mouse</resource> - <resource name="settings_capture_windows_interactive">Usa la modalità di cattura via finestra interattiva</resource> - <resource name="settings_checkperiod">Intervallo di controllo aggiornamento, in giorni (0=nessun controllo)</resource> - <resource name="settings_configureplugin">Configura</resource> - <resource name="settings_copypathtoclipboard">Copia percorso file sugli appunti, ogni volta che una immagine viene salvata</resource> - <resource name="settings_destination">Destinazione dell'immagine</resource> - <resource name="settings_destination_clipboard">Copia sugli appunti</resource> - <resource name="settings_destination_editor">Apri in Gest. Immagini</resource> - <resource name="settings_destination_email">E-Mail</resource> - <resource name="settings_destination_file">Salva direttamente (usando le impostazioni qui sotto esposte)</resource> - <resource name="settings_destination_fileas">Salva come (visualizzando le scelte)</resource> - <resource name="settings_destination_picker">Scegli la destinazione dinamicamente</resource> - <resource name="settings_destination_printer">Invia alla stampante</resource> - <resource name="settings_editor">Gestione Immagini</resource> - <resource name="settings_filenamepattern">Modello del Nome File</resource> - <resource name="settings_general">Generali</resource> - <resource name="settings_iecapture">Cattura Internet Explorer</resource> - <resource name="settings_jpegquality">Qualità JPEG</resource> - <resource name="settings_jpegsettings">Impostazioni JPEG</resource> - <resource name="settings_language">Lingua</resource> - <resource name="settings_message_filenamepattern">I parametri racchiusi tra % verranno sostituiti automaticamente: -${YYYY} anno, 4 digits -${MM} mese, 2 digits -${DD} giorno, 2 digits -${hh} ora, 2 digits -${mm} minuti, 2 digits -${ss} secondi, 2 digits -${NUM} numero progressivo, 6 digits +Aggiungi un riepilogo significativo e includi qualsiasi informazione tu consideri possa esserci d'aiuto per +risolvere il problema. +Inoltre apprezzeremo molto, se prima di inserire la segnaalzione, controllassi se esiste già una +segnalazione per questo tipo di errore (puoi usare la ricerca) +Grazie :) + </resource> + <resource name="bugreport_title">Errore</resource> + <resource name="CANCEL">Annulla</resource> + <resource name="clipboard_error">Si è verificato un errore inaspettato durante la scrittura negli Appunti. + </resource> + <resource name="clipboard_noimage">Nessuna immagine sugli Appunti.</resource> + <resource name="clipboard_inuse">Greenshot non è riuscito a scrivere negli Appunti poichè il processo {0} teneva + l'accesso bloccato. + </resource> + <resource name="ClipboardFormat.BITMAP">BMO (Bitmap Windows)</resource> + <resource name="ClipboardFormat.DIB">DIB (Device independent Bitmap)</resource> + <resource name="ClipboardFormat.HTML">HTML</resource> + <resource name="ClipboardFormat.HTMLDATAURL">HTML con immagini in linea</resource> + <resource name="ClipboardFormat.PNG">PNG</resource> + <resource name="colorpicker_alpha">Alfa</resource> + <resource name="colorpicker_apply">Applica</resource> + <resource name="colorpicker_blue">Blu</resource> + <resource name="colorpicker_green">Verde</resource> + <resource name="colorpicker_htmlcolor">Colore HTML</resource> + <resource name="colorpicker_recentcolors">Colori usati di recente</resource> + <resource name="colorpicker_red">Rosso</resource> + <resource name="colorpicker_title">Scelta colore</resource> + <resource name="colorpicker_transparent">Trasparente</resource> + <resource name="com_rejected">La destinazione {0} ha rifiutato l'accesso a Greenshot. +Probabilmente c'è una finestra aperta. +Chiudi la finestra e riprova nuovamente.</resource> + <resource name="com_rejected_title">Accesso rifiutato a Greenshot</resource> + <resource name="config_unauthorizedaccess_write">Il file di configurazione di Greenshot non può essere salvato. +Controlla i permessi di accesso per '{0}'.</resource> + <resource name="contextmenu_about">Notizie su Greenshot</resource> + <resource name="contextmenu_capturearea">Cattura regione</resource> + <resource name="contextmenu_captureclipboard">Apri immagine dagli Appunti</resource> + <resource name="contextmenu_capturefullscreen">Cattura schermo intero</resource> + <resource name="contextmenu_capturefullscreen_all">Tutto</resource> + <resource name="contextmenu_capturefullscreen_bottom">Basso</resource> + <resource name="contextmenu_capturefullscreen_left">Sinistra</resource> + <resource name="contextmenu_capturefullscreen_right">Destra</resource> + <resource name="contextmenu_capturefullscreen_top">Alto</resource> + <resource name="contextmenu_captureie">Cattura Internet Explorer</resource> + <resource name="contextmenu_captureiefromlist">Cattura Internet Explorer da elenco</resource> + <resource name="contextmenu_capturelastregion">Cattura ultima regione</resource> + <resource name="contextmenu_capturewindow">Cattura finestra</resource> + <resource name="contextmenu_capturewindowfromlist">Cattura finestra da elenco</resource> + <resource name="contextmenu_donate">Supporta Greenshot</resource> + <resource name="contextmenu_exit">Esci</resource> + <resource name="contextmenu_help">Aiuto</resource> + <resource name="contextmenu_openfile">Apri immagine da file</resource> + <resource name="contextmenu_openrecentcapture">Apri ultimo percorso cattura</resource> + <resource name="contextmenu_quicksettings">Imposatzioni rapide</resource> + <resource name="contextmenu_settings">Impostazioni...</resource> + <resource name="destination_exportfailed">Errori durente l'esportazione in {0}. Riprova.</resource> + <resource name="editor_align_bottom">In basso</resource> + <resource name="editor_align_center">Centro</resource> + <resource name="editor_align_horizontal">Allineamento orizzontale</resource> + <resource name="editor_align_left">Sinistra</resource> + <resource name="editor_align_middle">In mezzo</resource> + <resource name="editor_align_right">Destra</resource> + <resource name="editor_align_top">Alto</resource> + <resource name="editor_align_vertical">Allineamento verticale</resource> + <resource name="editor_arrange">Disponi</resource> + <resource name="editor_arrowheads">Tipi di punta di freccia</resource> + <resource name="editor_arrowheads_both">Entrambe</resource> + <resource name="editor_arrowheads_end">Punto finale</resource> + <resource name="editor_arrowheads_none">Nessuna</resource> + <resource name="editor_arrowheads_start">Punto iniziale</resource> + <resource name="editor_autocrop">Ritaglia Automaticamente</resource> + <resource name="editor_backcolor">Colore di riempimento</resource> + <resource name="editor_blur_radius">Raggio sfumatura</resource> + <resource name="editor_bold">Grassetto</resource> + <resource name="editor_border">Bordi</resource> + <resource name="editor_brightness">Luminosità</resource> + <resource name="editor_cancel">Cancella</resource> + <resource name="editor_clipboardfailed">Errore durante l'accesso agli appunti. Ritenta nuovamente.</resource> + <resource name="editor_close">Chiudi</resource> + <resource name="editor_close_on_save">Desideri salvare l'immagine?</resource> + <resource name="editor_close_on_save_title">Salva l'immagine?</resource> + <resource name="editor_confirm">Conferma</resource> + <resource name="editor_copyimagetoclipboard">Copia immagine sugli appunti</resource> + <resource name="editor_copypathtoclipboard">Copia percorso sugli appunti</resource> + <resource name="editor_copytoclipboard">Copia</resource> + <resource name="editor_crop">Ritaglia (C)</resource> + <resource name="editor_cursortool">Strumento di selezione (ESC)</resource> + <resource name="editor_cuttoclipboard">Taglia</resource> + <resource name="editor_deleteelement">Elimina</resource> + <resource name="editor_downonelevel">Giù di un livello</resource> + <resource name="editor_downtobottom">Giù fino in fondo</resource> + <resource name="editor_drawarrow">Disegna freccia (A)</resource> + <resource name="editor_drawellipse">Disegna ellisse (E)</resource> + <resource name="editor_drawfreehand">Disegna mano libera (F)</resource> + <resource name="editor_drawhighlighter">Evidenzia (H)</resource> + <resource name="editor_drawline">Disegna linea (L)</resource> + <resource name="editor_drawrectangle">Disegna rettangolo (R)</resource> + <resource name="editor_drawtextbox">Aggiungi casella di testo (T)</resource> + <resource name="editor_duplicate">Duplica elementi selezionati</resource> + <resource name="editor_edit">Modifica</resource> + <resource name="editor_effects">Effetti</resource> + <resource name="editor_email">E-Mail</resource> + <resource name="editor_file">File</resource> + <resource name="editor_fontsize">Dimensioni</resource> + <resource name="editor_forecolor">Colore linea</resource> + <resource name="editor_grayscale">Scala di grigi</resource> + <resource name="editor_highlight_area">Evidenzia l'area</resource> + <resource name="editor_highlight_grayscale">Scala di grigi</resource> + <resource name="editor_highlight_magnify">Ingrandisci</resource> + <resource name="editor_highlight_mode">Modalità evidenziazione</resource> + <resource name="editor_highlight_text">Evidenzia il testo</resource> + <resource name="editor_image_shadow">Aggiungi ombra</resource> + <resource name="editor_imagesaved">Immagine salvata su {0}.</resource> + <resource name="editor_insertwindow">Inserisci finestra</resource> + <resource name="editor_invert">Negativo</resource> + <resource name="editor_italic">Corsivo</resource> + <resource name="editor_load_objects">Carica oggetti da file</resource> + <resource name="editor_magnification_factor">Fattore di ingrandimento</resource> + <resource name="editor_match_capture_size">Adatta a dimensioni di cattura</resource> + <resource name="editor_obfuscate">Offusca (O)</resource> + <resource name="editor_obfuscate_blur">Sfuma</resource> + <resource name="editor_obfuscate_mode">Modalità di offuscamento</resource> + <resource name="editor_obfuscate_pixelize">Offusca/ pixelize</resource> + <resource name="editor_object">Oggetti</resource> + <resource name="editor_opendirinexplorer">Apri cartella su Windows Explorer</resource> + <resource name="editor_pastefromclipboard">Incolla</resource> + <resource name="editor_pixel_size">Dimensioni pixel</resource> + <resource name="editor_preview_quality">Qualità anteprima</resource> + <resource name="editor_print">Stampa</resource> + <resource name="editor_redo">Ripeti azione {0}</resource> + <resource name="editor_resetsize">Azzera Dimensione</resource> + <resource name="editor_resize_percent">Percentuale</resource> + <resource name="editor_resize_pixel">Pixels</resource> + <resource name="editor_rotateccw">Ruota senso antiorario</resource> + <resource name="editor_rotatecw">Ruota senso orario</resource> + <resource name="editor_save">Salva</resource> + <resource name="editor_save_objects">Salva oggetti su file</resource> + <resource name="editor_saveas">Salva come...</resource> + <resource name="editor_selectall">Seleziona tutto</resource> + <resource name="editor_senttoprinter">Stampa inviata a '{0}'.</resource> + <resource name="editor_shadow">Ombra</resource> + <resource name="editor_image_shadow">Ombra</resource> + <resource name="editor_storedtoclipboard">Immagine posta negli appunti (clipboard).</resource> + <resource name="editor_thickness">Spessore linea</resource> + <resource name="editor_title">Gestione Immagini di Greenshot</resource> + <resource name="editor_torn_edge">Bordi strappati</resource> + <resource name="editor_undo">Annulla azione {0}</resource> + <resource name="editor_uponelevel">Su di un livello</resource> + <resource name="editor_uptotop">Su fino in cima</resource> + <resource name="EmailFormat.MAPI">Client MAPI</resource> + <resource name="EmailFormat.OUTLOOK_HTML">Outlook con HTML</resource> + <resource name="EmailFormat.OUTLOOK_TXT">Outlook con testo</resource> + <resource name="error">Errore</resource> + <resource name="error_multipleinstances">È già attiva un'istanza di Greenshot.</resource> + <resource name="error_nowriteaccess"> +Non è possibile salvare il file in {0}. +Verifica l'accesso in scrittura nel percorso di salvataggio. + </resource> + <resource name="error_openfile">Il file "{0}" non può essere aperto.</resource> + <resource name="error_openlink">Impossibile aprire il collegamento '{0}'.</resource> + <resource name="error_save">Impossibile salvare l'immagine. +È necessario trovare una destinazione valida. + </resource> + <resource name="error_save_invalid_chars">Il nome file o cartella generato non è valido. +Correggi la maschera noem file e riprova. + </resource> + <resource name="expertsettings">Utente esperto</resource> + <resource name="expertsettings_autoreducecolors">Crea una immagine a 8bit se i colori sono meno di 256 el'immagine ha > 8 bit</resource> + <resource name="expertsettings_checkunstableupdates">Controlla disponibilità Aggiornamenti versioni beta</resource> + <resource name="expertsettings_clipboardformats">Formati degli Appunti</resource> + <resource name="expertsettings_counter">Numero per var. ${NUM} nel modello del nome file</resource> + <resource name="expertsettings_enableexpert">Sono consapevole di ciò che sto facendo!</resource> + <resource name="expertsettings_footerpattern">Modello piè di pagina</resource> + <resource name="expertsettings_minimizememoryfootprint">Riduci uso della memoria perdendo però in prestazioni (sconsigliato).</resource> + <resource name="expertsettings_optimizeforrdp">Esegui ottimizzazioni per uso con desktop remoto</resource> + <resource name="expertsettings_reuseeditorifpossible">Riutilizza se possibile la gestione immagini</resource> + <resource name="expertsettings_suppresssavedialogatclose">Evita avviso di salvataggio in chiusura della gestione immagini</resource> + <resource name="expertsettings_thumbnailpreview">Visualizza anteprima finestra nel menù di contesto (Vista e Windows 7)</resource> + <resource name="exported_to">Esportato in: {0}</resource> + <resource name="exported_to_error">Si è verificato un errore durante l'esportazione in {0}:</resource> + <resource name="help_title">Guida di Greenshot</resource> + <resource name="hotkeys">Scorciatoie tastiera</resource> + <resource name="jpegqualitydialog_choosejpegquality">Scegli la qualità dell'immagine JPEG.</resource> + <resource name="OK">OK</resource> + <resource name="print_error">Si è verificato un errore durante la stampa.</resource> + <resource name="printoptions_allowcenter">Centra nella pagina</resource> + <resource name="printoptions_allowenlarge">Ingrandisci fino alle dimensioni pagina</resource> + <resource name="printoptions_allowrotate">Ruota a seconda dell'orientamento pagina</resource> + <resource name="printoptions_allowshrink">Riduci alle dimensioni pagina</resource> + <resource name="printoptions_colors">Impostazioni colore</resource> + <resource name="printoptions_dontaskagain">Salva le opzioni come predefinite e non chiedere più</resource> + <resource name="printoptions_inverted">Stampa con colori invertiti (negativo)</resource> + <resource name="printoptions_layout">Impostazioni layout pagina</resource> + <resource name="printoptions_printcolor">Forza stampa a colori</resource> + <resource name="printoptions_printgrayscale">Forza stampa in scala di grigi</resource> + <resource name="printoptions_printmonochrome">Forza stampa in bianco e nero</resource> + <resource name="printoptions_timestamp">Aggiungi data/ora nel piè di pagina</resource> + <resource name="printoptions_title">Opzioni di stampa di Greenshot</resource> + <resource name="qualitydialog_dontaskagain">Save come qualità predefinita e non chiedere più</resource> + <resource name="qualitydialog_title">Qualità di Greenshot</resource> + <resource name="quicksettings_destination_file">Salva direttamente (usando le impostazioni preferite file destinazione)</resource> + <resource name="settings_alwaysshowprintoptionsdialog">Visualizza scelta opzioni di stampa ogni volta che stampi un'immagine</resource> + <resource name="settings_alwaysshowqualitydialog">Visualizza scelta qualità ogni volta che si salva un'immagine</resource> + <resource name="settings_applicationsettings">Impostazioni applicazione</resource> + <resource name="settings_autostartshortcut">Esegui Greenshot all'avvio del sistema</resource> + <resource name="settings_capture">Cattura</resource> + <resource name="settings_capture_mousepointer">Cattura puntatore mouse</resource> + <resource name="settings_capture_windows_interactive">Usa la modalità di cattura via finestra interattiva</resource> + <resource name="settings_checkperiod">Intervallo controllo aggiornamento in giorni (0=nessun controllo)</resource> + <resource name="settings_configureplugin">Imposta</resource> + <resource name="settings_copypathtoclipboard">Ogni volta che una immagine viene salvata copia percorso file negli Appunti</resource> + <resource name="settings_destination">Destinazione immagine</resource> + <resource name="settings_destination_clipboard">Copia negli Appunti</resource> + <resource name="settings_destination_editor">Apri in Gest. Immagini</resource> + <resource name="settings_destination_email">Email</resource> + <resource name="settings_destination_file">Salva direttamente (usando le impostazioni esposte qui sotto)</resource> + <resource name="settings_destination_fileas">Salva come (visualizzando le scelte)</resource> + <resource name="settings_destination_picker">Scegli la destinazione dinamicamente</resource> + <resource name="settings_destination_printer">Invia alla stampante</resource> + <resource name="settings_editor">Gestione immagini</resource> + <resource name="settings_filenamepattern">Modello nome fFile</resource> + <resource name="settings_general">Generali</resource> + <resource name="settings_iecapture">Cattura Internet Explorer</resource> + <resource name="settings_jpegquality">Qualità JPEG</resource> + <resource name="settings_jpegsettings">Impostazioni JPEG</resource> + <resource name="settings_language">Lingua</resource> + <resource name="settings_message_filenamepattern">I parametri racchiusi tra % verranno automaticamente sostituiti: +${YYYY} anno, 4 numeri +${MM} mese, 2 numeri +${DD} giorno, 2 numeri +${hh} ora, 2 nuemri +${mm} minuti, 2 numeri +${ss} secondi, 2 numeri +${NUM} numero progressivo, 6 numeri ${title} Titolo finestra ${user} Utente Windows ${domain} Dominio Windows ${hostname} Nome PC -Puoi anche chiedere a Greenshot di creare le cartelle dinamicamente, basta usare la barra rovescia (\) per separare cartelle e nome file. -Esempio: il modello ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} -genererà una cartella per il giorno corrente sulla destinazione di memorizzazione di default, es: 2008-06-29, il nome del file di immagine sarà basato sull'orario -corrente, es: 11_58_32 (più l'estensione definita nelle impostazioni)</resource> - <resource name="settings_network">Rete e aggiornamenti</resource> - <resource name="settings_output">Emissione</resource> - <resource name="settings_playsound">Emetti suono fotocamera</resource> - <resource name="settings_plugins">Componenti Aggiuntivi</resource> - <resource name="settings_plugins_createdby">Creato da</resource> - <resource name="settings_plugins_dllpath">Percorso DLL</resource> - <resource name="settings_plugins_name">Nome</resource> - <resource name="settings_plugins_version">Versione</resource> - <resource name="settings_preferredfilesettings">Impostazioni Preferite per l'Emissione File</resource> - <resource name="settings_primaryimageformat">Formato immagine</resource> - <resource name="settings_printer">Stampante</resource> - <resource name="settings_printoptions">Opzioni di stampa</resource> - <resource name="settings_qualitysettings">Impostazioni Qualità</resource> - <resource name="settings_reducecolors">Riduci i colori a un massimo di 256</resource> - <resource name="settings_registerhotkeys">Registra scorciatoie di tastiera</resource> - <resource name="settings_showflashlight">Mostra torcia elettrica</resource> - <resource name="settings_shownotify">Mostra le notifiche</resource> - <resource name="settings_zoom">Mostra lente ingrandimento</resource> - <resource name="settings_storagelocation">Destinaz. salvataggio</resource> - <resource name="settings_title">Impostazioni</resource> - <resource name="settings_tooltip_filenamepattern">Modello usato per generare il nome file in fase di salvataggio delle immagini</resource> - <resource name="settings_tooltip_language">Lingua dell'interfaccia utente di Greenshot (richiede il riavvio)</resource> - <resource name="settings_tooltip_primaryimageformat">Formato immagine di default</resource> - <resource name="settings_tooltip_registerhotkeys">Definisce se le scorciatoie Stamp, Ctrl + Stamp, Alt + Stamp sono riservate per uso globale di Greenshot dall'avvio del programma fino a quando viene chiuso.</resource> - <resource name="settings_tooltip_storagelocation">Destinazione dove le immagini dello schermo vengono salvate per default (lasciare vuoto per salvare sul desktop)</resource> - <resource name="settings_usedefaultproxy">Usa il proxy di default del sistema</resource> - <resource name="settings_visualization">Effetti</resource> - <resource name="settings_waittime">Millisecondi di attesa prima di catturare</resource> - <resource name="settings_window_capture_mode">Modalità cattura finestra</resource> - <resource name="settings_windowscapture">Cattura finestra</resource> - <resource name="tooltip_firststart">Clicca tasto destro qui, o premi il tasto Stamp.</resource> - <resource name="update_found">Una nuova versione di Greenshot è ora disponibile! Vuoi scaricare Greenshot {0}?</resource> - <resource name="wait_ie_capture">Attendere prego, finchè la pagina di Internet Explorer viene catturata...</resource> - <resource name="warning">Attenzione</resource> - <resource name="warning_hotkeys">La registrazione della/e scorciatoie di tastiera "{0}" non è andata a buon fine. Questo problema è causato probabilmente da un altro software{1} che richiede l'uso delle stesse scorciatoie di tastiera. E' possibile però variare le impostazioni delle scorciatoie, oppure disattivare il software. +Puoi anche chiedere a Greenshot di creare le cartelle dinamicamente, usando la barra rovesciata (\) per +separare cartelle e nome file. +Esempio modello: ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} +creerà nelal destinazione predefinita una cartella con il giorno corrente , es: 2008-06-29. +Il nome del file di immagine sarà basato sull'orario attuale, es: 11_58_32 (più l'estensione definita nelle +impostazioni) + </resource> + <resource name="settings_network">Rete e aggiornamenti</resource> + <resource name="settings_output">Destinazionione</resource> + <resource name="settings_playsound">Riproduci suono fotocamera</resource> + <resource name="settings_plugins">Componenti Aggiuntivi</resource> + <resource name="settings_plugins_createdby">Creato da</resource> + <resource name="settings_plugins_dllpath">Percorso DLL</resource> + <resource name="settings_plugins_name">Nome</resource> + <resource name="settings_plugins_version">Versione</resource> + <resource name="settings_preferredfilesettings">Impostazioni preferite file destinazione</resource> + <resource name="settings_primaryimageformat">Formato immagine</resource> + <resource name="settings_printer">Stampante</resource> + <resource name="settings_printoptions">Opzioni di stampa</resource> + <resource name="settings_qualitysettings">Impostazioni qualità</resource> + <resource name="settings_reducecolors">Riduci i colori a un massimo di 256</resource> + <resource name="settings_registerhotkeys">Registra scorciatoie tastiera</resource> + <resource name="settings_showflashlight">Visualizza torcia elettrica</resource> + <resource name="settings_shownotify">Visualizza notifiche</resource> + <resource name="settings_zoom">Visualizza lente ingrandimento</resource> + <resource name="settings_storagelocation">Percorso salvataggio</resource> + <resource name="settings_title">Impostazioni</resource> + <resource name="settings_tooltip_filenamepattern">Modello usato per generare il nome file in fase di salvataggio delle immagini</resource> + <resource name="settings_tooltip_language">Lingua dell'interfaccia utente di Greenshot (richiede il riavvio)</resource> + <resource name="settings_tooltip_primaryimageformat">Formato immagine predefinito</resource> + <resource name="settings_tooltip_registerhotkeys">Definisce se le scorciatoie Stamp, Ctrl + Stamp, Alt + Stamp sono riservate per uso globale di Greenshot dall'avvio del programma fino a quando viene chiuso.</resource> + <resource name="settings_tooltip_storagelocation">Percorso predefinito dove le immagini catturate vengono salvate (lascia vuoto per salvare sul desktop)</resource> + <resource name="settings_usedefaultproxy">Usa proxy predefinito del sistema</resource> + <resource name="settings_visualization">Effetti</resource> + <resource name="settings_waittime">Millisecondi di attesa prima di catturare</resource> + <resource name="settings_window_capture_mode">Modalità cattura finestra</resource> + <resource name="settings_windowscapture">Cattura finestra</resource> + <resource name="tooltip_firststart">Cic tasto destro mouse qui, o premi il tasto 'Stamp'.</resource> + <resource name="update_found">È disponibile una nuova versione {0} di Greenshot! Vuoi scaricare ora la nuova versione di Greenshot?</resource> + <resource name="wait_ie_capture">Attendi finchè viene completata la cattura della pagina di Internet Explorer...</resource> + <resource name="warning">Attenzione</resource> + <resource name="warning_hotkeys">La registrazione della/e scorciatoie di tastiera "{0}" non è andata a buon fine. +Questo problema è causato probabilmente da un altro software che richiede l'uso delle stesse scorciatoie di +tastiera. +E' possibile però variare le impostazioni delle scorciatoie, oppure disattivare il software. -In alternativa alle scorciatoie di tastiera, tutte le funzioni di Greenshot sono comunque disponibili dal menù visualizzabile con tasto destro del mouse sull'icona G nella barra.</resource> - <resource name="WindowCaptureMode.Aero">Usa colori personalizzati</resource> - <resource name="WindowCaptureMode.AeroTransparent">Conserva la trasparenza</resource> - <resource name="WindowCaptureMode.Auto">Automaticamente</resource> - <resource name="WindowCaptureMode.GDI">Usa i colori di default</resource> - <resource name="WindowCaptureMode.Screen">Come visualizzata</resource> +In alternativa alle scorciatoie di tastiera, tutte le funzioni di Greenshot sono comunque disponibili dal +menù visualizzabile con il tasto destro del mouse sull'icona G nella barra. + </resource> - <resource name="editor_counter">Aggiungi conteggio</resource> - <resource name="editor_speechbubble">Aggiungi nuvoletta</resource> - <resource name="editor_resize">Ridimensiona</resource> - <resource name="editor_resize_settings">Impostazioni ridimensionamento</resource> - <resource name="editor_resize_aspectratio">Mantieni il rapporto dimensioni</resource> - <resource name="editor_resize_width">Larghezza</resource> - <resource name="editor_resize_height">Altezza</resource> - <resource name="editor_dropshadow_darkness">Intensità ombra</resource> - <resource name="editor_dropshadow_offset">Offset ombra</resource> - <resource name="editor_dropshadow_settings">Impostazioni Ombreggiatura</resource> - <resource name="editor_dropshadow_thickness">Spessore ombra</resource> + <resource name="WindowCaptureModes.Aero">Usa colori personalizzati</resource> + <resource name="WindowCaptureModes.AeroTransparent">Mantieni trasparenza</resource> + <resource name="WindowCaptureModes.Auto">Automaticamente</resource> + <resource name="WindowCaptureModes.GDI">Usa i colori predefiniti</resource> + <resource name="WindowCaptureModes.Screen">Come visualizzata</resource> + <resource name="settings_iconsize">Dimensione icona</resource> + <resource name="editor_counter">Aggiungi conteggio</resource> + <resource name="editor_speechbubble">Aggiungi nuvoletta</resource> + <resource name="editor_resize">Ridimensiona</resource> + <resource name="editor_resize_settings">Impostazioni ridimensionamento</resource> + <resource name="editor_resize_aspectratio">Mantieni il rapporto dimensioni</resource> + <resource name="editor_resize_width">Larghezza</resource> + <resource name="editor_resize_height">Altezza</resource> + <resource name="editor_dropshadow_darkness">Intensità ombra</resource> + <resource name="editor_dropshadow_offset">Offset ombra</resource> + <resource name="editor_dropshadow_settings">Impostazioni Ombreggiatura</resource> + <resource name="editor_dropshadow_thickness">Spessore ombra</resource> - <resource name="editor_tornedge_horizontaltoothrange">Intervallo orizzontale dentellatura</resource> - <resource name="editor_tornedge_settings">Impostazioni Bordi Strappati</resource> - <resource name="editor_tornedge_toothsize">Dimensione dentellatura</resource> - <resource name="editor_tornedge_verticaltoothrange">Intervallo verticale dentellatura</resource> - <resource name="editor_tornedge_left">Strappo lato sinistro</resource> - <resource name="editor_tornedge_right">Strappo lato destro</resource> - <resource name="editor_tornedge_top">Strappo lato in alto</resource> - <resource name="editor_tornedge_bottom">Strappo lato in basso</resource> - <resource name="editor_tornedge_shadow">Genera ombra</resource> - </resources> + <resource name="editor_tornedge_horizontaltoothrange">Intervallo orizzontale dentellatura</resource> + <resource name="editor_tornedge_settings">Impostazioni Bordi Strappati</resource> + <resource name="editor_tornedge_toothsize">Dimensione dentellatura</resource> + <resource name="editor_tornedge_verticaltoothrange">Intervallo verticale dentellatura</resource> + <resource name="editor_tornedge_left">Strappo lato sinistro</resource> + <resource name="editor_tornedge_right">Strappo lato destro</resource> + <resource name="editor_tornedge_top">Strappo lato in alto</resource> + <resource name="editor_tornedge_bottom">Strappo lato in basso</resource> + <resource name="editor_tornedge_shadow">Genera ombra</resource> + </resources> </language> From 161339c4bfa2c5a4927898faad1510d01df7d9d1 Mon Sep 17 00:00:00 2001 From: Greenshot-AppVeyor <getgreenshot@gmail.com> Date: Sat, 2 May 2020 21:52:05 +0200 Subject: [PATCH 040/232] Backport German Language Updates from Pull Request #168 --- Greenshot/Languages/language-de-DE.xml | 31 +++++++++++++------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Greenshot/Languages/language-de-DE.xml b/Greenshot/Languages/language-de-DE.xml index 07876d483..2435a7105 100644 --- a/Greenshot/Languages/language-de-DE.xml +++ b/Greenshot/Languages/language-de-DE.xml @@ -14,7 +14,7 @@ Detaillierte Informationen zur GNU General Public License:</resource> <resource name="bugreport_info">Tut uns leid, ein unerwarteter Fehler ist aufgetreten. Die gute Nachricht ist: Sie können uns helfen, ihn zu beseitigen, indem Sie uns einen Fehlerbericht zukommen lassen. Besuchen Sie die unten stehende URL und erstellen Sie einen neuen Fehlerbericht. -Bitte geben Sie eine aussgekräftige Zusammenfassung an, fügen Sie den Inhalt des Textfelds in die Beschreibung ein, und ergänzen Sie diese mit zusätzlichen +Bitte geben Sie eine aussagekräftige Zusammenfassung an, fügen Sie den Inhalt des Textfelds in die Beschreibung ein, und ergänzen Sie diese mit zusätzlichen Informationen, die für das Nachvollziehen des Fehlers hilfreich sein könnten. Wir wären sehr dankbar, wenn Sie vorher prüfen würden, ob dieser Fehler schon gemeldet wurde - nutzen Sie einfach die Suche, um bestehende Fehlerberichte schnell zu finden. Vielen Dank :)</resource> @@ -161,12 +161,12 @@ schnell zu finden. Vielen Dank :)</resource> <resource name="error_multipleinstances">Greenshot läuft bereits.</resource> <resource name="error_nowriteaccess">Konnte Datei nicht nach {0} speichern. Bitte überprüfen Sie die Schreibrechte oder wählen Sie einen anderen Speicherort.</resource> - <resource name="error_openfile">Die Datei "{0}" konnte nicht geöffnet werden.</resource> + <resource name="error_openfile">Die Datei '{0}' konnte nicht geöffnet werden.</resource> <resource name="error_openlink">Konnte Link '{0}' nicht öffnen.</resource> <resource name="error_save">Screenshot konnte nicht gespeichert werden, bitte wählen Sie einen anderen Speicherort.</resource> <resource name="error_save_invalid_chars">Der generierte Datei- oder Verzeichnisname ist nicht gültig. Bitte korrigieren Sie das Dateiname-Muster und versuchen Sie es erneut.</resource> <resource name="expertsettings">Experten</resource> - <resource name="expertsettings_autoreducecolors">8-Bit-Bilder erstellen bei weniger als 256 Farben</resource> + <resource name="expertsettings_autoreducecolors">8-Bit-Bilder bei weniger als 256 Farben erstellen</resource> <resource name="expertsettings_checkunstableupdates">Auch instabile Updates anbieten</resource> <resource name="expertsettings_clipboardformats">Zwischenablage-Formate</resource> <resource name="expertsettings_counter">Wert für ${NUM} im Dateiname-Muster</resource> @@ -178,7 +178,7 @@ Bitte überprüfen Sie die Schreibrechte oder wählen Sie einen anderen Speicher <resource name="expertsettings_suppresssavedialogatclose">Speichern-Dialog beim Schließen des Editors unterdrücken</resource> <resource name="expertsettings_thumbnailpreview">Fenster-Vorschau im Kontextmenü anzeigen (für Vista und Windows 7)</resource> <resource name="exported_to">Exportiert nach: {0}</resource> - <resource name="exported_to_error">Beim Export zu {0} ist ein Fehler aufgetreten:</resource> + <resource name="exported_to_error">Beim Export nach {0} ist ein Fehler aufgetreten:</resource> <resource name="help_title">Greenshot - Hilfe</resource> <resource name="hotkeys">Tastenkombinationen</resource> <resource name="jpegqualitydialog_choosejpegquality">Bitte wählen Sie die Qualität Ihres JPEG-Bildes.</resource> @@ -194,7 +194,7 @@ Bitte überprüfen Sie die Schreibrechte oder wählen Sie einen anderen Speicher <resource name="printoptions_layout">Layout-Einstellungen</resource> <resource name="printoptions_printcolor">Farbdruck</resource> <resource name="printoptions_printgrayscale">Nur in Graustufen ausdrucken</resource> - <resource name="printoptions_printmonochrome">Schwarzweiß-Druck erzwingen</resource> + <resource name="printoptions_printmonochrome">Schwarz-Weiß-Druck erzwingen</resource> <resource name="printoptions_timestamp">Datum und Uhrzeit am Ende der Seite einfügen</resource> <resource name="printoptions_title">Greenshot - Druckeinstellungen</resource> <resource name="qualitydialog_dontaskagain">Als Standardqualität speichern und nicht wieder fragen</resource> @@ -206,16 +206,16 @@ Bitte überprüfen Sie die Schreibrechte oder wählen Sie einen anderen Speicher <resource name="settings_autostartshortcut">Greenshot mit Windows starten</resource> <resource name="settings_capture">Abfotografieren</resource> <resource name="settings_capture_mousepointer">Mauszeiger mitfotografieren</resource> - <resource name="settings_capture_windows_interactive">Fenster-Teile einzeln abfotografieren</resource> + <resource name="settings_capture_windows_interactive">Fensterteile einzeln abfotografieren</resource> <resource name="settings_checkperiod">Prüfen auf Updates alle X Tage (0=keine Prüfung)</resource> - <resource name="settings_configureplugin">Konfigurieren</resource> + <resource name="settings_configureplugin">Konfigurieren...</resource> <resource name="settings_copypathtoclipboard">Dateipfad in die Zwischenablage kopieren, wenn ein Bild gespeichert wird</resource> <resource name="settings_destination">Ziele</resource> <resource name="settings_destination_clipboard">In Zwischenablage kopieren</resource> <resource name="settings_destination_editor">Im Greenshot-Editor öffnen</resource> <resource name="settings_destination_email">E-Mail</resource> <resource name="settings_destination_file">Sofort speichern</resource> - <resource name="settings_destination_fileas">Speichern unter (mit Dialog)</resource> + <resource name="settings_destination_fileas">Speichern unter... (mit Dialog)</resource> <resource name="settings_destination_picker">Ziel dynamisch auswählen</resource> <resource name="settings_destination_printer">An Drucker senden</resource> <resource name="settings_editor">Editor</resource> @@ -238,7 +238,7 @@ ${domain} Windows-Domäne ${hostname} Computername Greenshot kann auch Verzeichnisse dynamisch erstellen. -Verwenden Sie das Backslash-Symbol \ um Verzeichnisse vom Dateinamen zu trennen. +Verwenden Sie den Backslash \ um Verzeichnisse vom Dateinamen zu trennen. Zum Beispiel: ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} Dieses Muster legt ein Verzeichnis für den aktuellen Tag im Standard-Speicherort an und speichert die Bilddateien im Uhrzeit-Format, mit der vorgegebenen Dateiendung ab. z.B. C:\Users\MaxMustermann\Desktop\2012-08-13\12-58-32.png</resource> @@ -264,22 +264,21 @@ z.B. C:\Users\MaxMustermann\Desktop\2012-08-13\12-58-32.png</resource> <resource name="settings_tooltip_filenamepattern">Muster, das beim Speichern von Screenshots zum Generieren von Dateinamen verwendet wird</resource> <resource name="settings_tooltip_language">Sprache der Benutzeroberfläche</resource> <resource name="settings_tooltip_primaryimageformat">Standard-Bildformat</resource> - <resource name="settings_tooltip_registerhotkeys">Legt fest, ob beim Programmstart die Tastenkombinationen Drucken, Strg + Drucken, Alt + Drucken beim Betriebssystem zur globalen -Verwendung durch Greenshot reserviert werden, bis das Programm geschlossen wird.</resource> + <resource name="settings_tooltip_registerhotkeys">Legt fest, ob beim Programmstart die Tastenkombinationen Druck, Strg + Druck, Alt + Druck beim Betriebssystem zur globalen Verwendung durch Greenshot reserviert werden, bis das Programm geschlossen wird.</resource> <resource name="settings_tooltip_storagelocation">Standardpfad für Bildschirmausdrucke. Leer lassen für Desktop.</resource> <resource name="settings_usedefaultproxy">Standard-Proxyserver des Betriebssystems verwenden</resource> <resource name="settings_visualization">Effekte</resource> - <resource name="settings_waittime">Millisekunden warten vor abfotografieren</resource> - <resource name="settings_window_capture_mode">Fenster abfotografier Modus</resource> + <resource name="settings_waittime">Millisekunden vor dem Abfotografieren warten</resource> + <resource name="settings_window_capture_mode">Abfotografiermodus-Fenster</resource> <resource name="settings_windowscapture">Fenster abfotografieren</resource> <resource name="settings_zoom">Lupe anzeigen</resource> - <resource name="tooltip_firststart">Klicken Sie hier mit der rechten Maustaste oder drücken Sie die {0} Taste.</resource> - <resource name="update_found">Eine neuere Greenshot Version steht zur Verfügung. Wollen Sie Greenshot {0} herunterladen?</resource> + <resource name="tooltip_firststart">Klicken Sie hier mit der rechten Maustaste oder drücken Sie die Taste {0}.</resource> + <resource name="update_found">Eine neuere Greenshot-Version steht zur Verfügung. Wollen Sie Greenshot {0} herunterladen?</resource> <resource name="wait_ie_capture">Bitte warten Sie, während die Seite im Internet Explorer abfotografiert wird...</resource> <resource name="warning">Hinweis</resource> <resource name="warning_hotkeys">Die globale Tastenkombination "{0}" konnte nicht aktiviert werden. Vermutlich wurde dieselbe Tastenkombination bereits von einem anderen Programm{1} reserviert. -Sie können die Tastenkombinationen für Greenshot ändern, oder das Programm, das die Tastenkombination verwendet, deaktivieren. +Sie können die Tastenkombination für Greenshot ändern, oder das Programm, das die Tastenkombination verwendet, deaktivieren. Sie können aber auch alle Greenshot-Funktionen über das Kontextmenü des Greenshot-Icons im Infobereich verwenden.</resource> <resource name="WindowCaptureMode.Aero">Benutzerdefinierte Farbe verwenden</resource> From debea3ad0269d28ea43e4c8de7a3a60bc415e010 Mon Sep 17 00:00:00 2001 From: Greenshot-AppVeyor <getgreenshot@gmail.com> Date: Sat, 2 May 2020 21:55:13 +0200 Subject: [PATCH 041/232] Backport Russion Language Updates from Pull Request #180 --- Greenshot/Languages/language-ru-RU.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Greenshot/Languages/language-ru-RU.xml b/Greenshot/Languages/language-ru-RU.xml index 6955968e3..9823d8bf1 100644 --- a/Greenshot/Languages/language-ru-RU.xml +++ b/Greenshot/Languages/language-ru-RU.xml @@ -25,7 +25,7 @@ Greenshot поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. <resource name="clipboard_inuse">Greenshot не смог записать в буфер обмена, доступ заблокирован процессом {0}.</resource> <resource name="clipboard_noimage">Изображение в буфере обмена не найдено.</resource> <resource name="ClipboardFormat.BITMAP">Windows Bitmap</resource> - <resource name="ClipboardFormat.DIB">Устройство Independend Bitmap (DIB)</resource> + <resource name="ClipboardFormat.DIB">Устройство independent Bitmap (DIB)</resource> <resource name="ClipboardFormat.HTML">HTML</resource> <resource name="ClipboardFormat.HTMLDATAURL">HTML со встроенными изображениями</resource> <resource name="ClipboardFormat.PNG">PNG</resource> @@ -38,7 +38,7 @@ Greenshot поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. <resource name="colorpicker_red">Красный</resource> <resource name="colorpicker_title">Палитра цветов</resource> <resource name="colorpicker_transparent">Прозрачный</resource> - <resource name="com_rejected">Назначение {0} отклонил доступ к Greenshot, вероятно, отрыто окно. Закройте диалоговое окно и попробуйте ещё раз.</resource> + <resource name="com_rejected">Назначение {0} отклонил доступ к Greenshot, вероятно, открыто окно. Закройте диалоговое окно и попробуйте ещё раз.</resource> <resource name="com_rejected_title">Доступ к Greenshot отклонён</resource> <resource name="config_unauthorizedaccess_write">Не удалось сохранить файл конфигурации Greenshot's. Пожалуйста, проверьте права доступа для '{0}'.</resource> <resource name="contextmenu_about">О программе Greenshot</resource> @@ -61,7 +61,7 @@ Greenshot поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. <resource name="contextmenu_openfile">Открыть изображение из файла</resource> <resource name="contextmenu_openrecentcapture">Открыть последнее место захвата</resource> <resource name="contextmenu_quicksettings">Быстрые настройки</resource> - <resource name="contextmenu_settings">Предпочтения...</resource> + <resource name="contextmenu_settings">Настройки...</resource> <resource name="destination_exportfailed">Ошибка при экспорте {0}. Пожалуйста, попробуйте ещё раз.</resource> <resource name="editor_align_bottom">Внизу</resource> <resource name="editor_align_center">По центру</resource> @@ -229,6 +229,7 @@ Greenshot поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. <resource name="settings_editor">Редактор</resource> <resource name="settings_filenamepattern">Шаблон имени файла</resource> <resource name="settings_general">Общие</resource> + <resource name="settings_iconsize">Размер иконки</resource> <resource name="settings_iecapture">Захват Internet Explorer</resource> <resource name="settings_jpegquality">Качество JPEG</resource> <resource name="settings_language">Язык</resource> From e8343b4ed2c879790b8d85c77bc64d337248f6a3 Mon Sep 17 00:00:00 2001 From: jklingen <jens@getgreenshot.org> Date: Sun, 3 May 2020 18:27:04 +0200 Subject: [PATCH 042/232] Installer: Backport Russian Translation for the Installer from PR #186 --- Greenshot/releases/innosetup/setup.iss | 1298 ++++++++++++------------ 1 file changed, 656 insertions(+), 642 deletions(-) diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index b2fd8e371..0c42af120 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -1,642 +1,656 @@ -#define ExeName "Greenshot" -#define Version GetEnv('BuildVersionSimple') -#define FileVersion GetEnv('AssemblyInformationalVersion') -#define BaseDir "..\..\.." -#define ReleaseDir "..\..\bin\Release\net472" -#define BinDir "bin\Release\net472" - -; Include the scripts to install .NET Framework -; See http://www.codeproject.com/KB/install/dotnetfx_innosetup_instal.aspx -#include "scripts\products.iss" -#include "scripts\products\stringversion.iss" -#include "scripts\products\winversion.iss" -#include "scripts\products\fileversion.iss" -#include "scripts\products\msi20.iss" -#include "scripts\products\msi31.iss" -#include "scripts\products\dotnetfxversion.iss" -#include "scripts\products\dotnetfx47.iss" - -[Files] -Source: {#ReleaseDir}\Greenshot.exe; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\GreenshotPlugin.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\Greenshot.exe.config; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\log4net.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\Dapplo.Http*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\Dapplo.Log.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\Newtonsoft.Json.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: ..\..\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion -Source: {#ReleaseDir}\checksum.SHA256; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -;Source: ..\greenshot-defaults.ini; DestDir: {app}; Flags: overwritereadonly ignoreversion replacesameversion -Source: ..\additional_files\installer.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion -Source: ..\additional_files\license.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion -Source: ..\additional_files\readme.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion - -; Core language files -Source: ..\..\Languages\*nl-NL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*en-US*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*de-DE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; - -; Additional language files -Source: ..\..\Languages\*ar-SY*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\arSY; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ca-CA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\caCA; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*cs-CZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\csCZ; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*da-DK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\daDK; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*de-x-franconia*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\dexfranconia; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*el-GR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\elGR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*es-ES*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\esES; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*et-EE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\etEE; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fa-IR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\faIR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fi-FI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\fiFI; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fr-FR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frFR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fr-QC*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frQC; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*he-IL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\heIL; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*hu-HU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\huHU; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*id-ID*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\idID; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*it-IT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\itIT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ja-JP*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\jaJP; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ko-KR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\koKR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*kab-DZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\kabDZ; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*lt-LT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ltLT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*lv-LV*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\lvLV; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*nn-NO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\nnNO; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*pl-PL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\plPL; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*pt-BR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptBR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*pt-PT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptPT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ro-RO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\roRO; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ru-RU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ruRU; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sk-SK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\skSK; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sl-SI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\slSI; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sr-RS*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\srRS; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sv-SE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\svSE; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*tr-TR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\trTR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*uk-UA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ukUA; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*vi-VN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\viVN; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhCN; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion; - -;Office Plugin -Source: {#BaseDir}\GreenshotOfficePlugin\{#BinDir}\GreenshotOfficePlugin.dll; DestDir: {app}\Plugins\GreenshotOfficePlugin; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -;OCR Plugin -Source: {#BaseDir}\GreenshotOCRPlugin\{#BinDir}\GreenshotOCRPlugin.dll; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotOCRPlugin\Languages\language_ocr*.xml; DestDir: {app}\Languages\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe.config; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -;JIRA Plugin -Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\GreenshotJiraPlugin.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\Dapplo.Jira.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotJiraPlugin\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion; -;Imgur Plugin -Source: {#BaseDir}\GreenshotImgurPlugin\{#BinDir}\GreenshotImgurPlugin.dll; DestDir: {app}\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotImgurPlugin\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion; -;Box Plugin -Source: {#BaseDir}\GreenshotBoxPlugin\{#BinDir}\GreenshotBoxPlugin.dll; DestDir: {app}\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotBoxPlugin\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion; -;DropBox Plugin -Source: {#BaseDir}\GreenshotDropBoxPlugin\{#BinDir}\GreenshotDropboxPlugin.dll; DestDir: {app}\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotDropBoxPlugin\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion; -;Flickr Plugin -Source: {#BaseDir}\GreenshotFlickrPlugin\{#BinDir}\GreenshotFlickrPlugin.dll; DestDir: {app}\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotFlickrPlugin\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion; -;Photobucket Plugin -Source: {#BaseDir}\GreenshotPhotobucketPlugin\{#BinDir}\GreenshotPhotobucketPlugin.dll; DestDir: {app}\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotPhotobucketPlugin\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion; -;Picasa Plugin -Source: {#BaseDir}\GreenshotPicasaPlugin\{#BinDir}\GreenshotPicasaPlugin.dll; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotPicasaPlugin\Languages\language_picasa*.xml; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion; -;Confluence Plugin -Source: {#BaseDir}\GreenshotConfluencePlugin\{#BinDir}\GreenshotConfluencePlugin.dll; DestDir: {app}\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotConfluencePlugin\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; -;ExternalCommand Plugin -Source: {#BaseDir}\GreenshotExternalCommandPlugin\{#BinDir}\GreenshotExternalCommandPlugin.dll; DestDir: {app}\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotExternalCommandPlugin\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion; -;Win 10 Plugin -Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\GreenshotWin10Plugin.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -[Setup] -; changes associations is used when the installer installs new extensions, it clears the explorer icon cache -ChangesAssociations=yes -AppId={#ExeName} -AppName={#ExeName} -AppMutex=F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08 -AppPublisher={#ExeName} -AppPublisherURL=http://getgreenshot.org -AppSupportURL=http://getgreenshot.org -AppUpdatesURL=http://getgreenshot.org -AppVerName={#ExeName} {#Version} -AppVersion={#Version} -ArchitecturesInstallIn64BitMode=x64 -Compression=lzma2/ultra64 -SolidCompression=yes -DefaultDirName={code:DefDirRoot}\{#ExeName} -DefaultGroupName={#ExeName} -InfoBeforeFile=..\additional_files\readme.txt -LicenseFile=..\additional_files\license.txt -LanguageDetectionMethod=uilanguage -MinVersion=6.1.7600 -OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE -OutputDir=..\ -PrivilegesRequired=lowest -SetupIconFile=..\..\icons\applicationIcon\icon.ico -; Create a SHA1 signature -; SignTool=SignTool sign /debug /fd sha1 /tr http://time.certum.pl /td sha1 $f -; Append a SHA256 to the previous SHA1 signature (this is what as does) -; SignTool=SignTool sign /debug /as /fd sha256 /tr http://time.certum.pl /td sha256 $f -; SignedUninstaller=yes -UninstallDisplayIcon={app}\{#ExeName}.exe -Uninstallable=true -VersionInfoCompany={#ExeName} -VersionInfoProductName={#ExeName} -VersionInfoProductTextVersion={#FileVersion} -VersionInfoTextVersion={#FileVersion} -VersionInfoVersion={#Version} -; Reference a bitmap, max size 164x314 -WizardImageFile=installer-large.bmp -; Reference a bitmap, max size 55x58 -WizardSmallImageFile=installer-small.bmp -[Registry] -; Delete all startup entries, so we don't have leftover values -Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; -Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; -Root: HKCU32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() -Root: HKLM32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() - -; delete filetype mappings -; HKEY_LOCAL_USER - for current user only -Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; -Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; -; HKEY_LOCAL_MACHINE - for all users when admin (with the noerror this doesn't matter) -Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; -Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; - -; Create the startup entries if requested to do so -; HKEY_LOCAL_USER - for current user only -Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: users-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: IsRegularUser -; HKEY_LOCAL_MACHINE - for all users when admin -Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: not IsRegularUser - -; Register our own filetype for all users -; HKEY_LOCAL_USER - for current user only -Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser -Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser -Root: HKCU; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser -Root: HKCU; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser -; HKEY_LOCAL_MACHINE - for all users when admin -Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser -Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser -Root: HKLM; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser -Root: HKLM; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser - -[Icons] -Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app}; AppUserModelID: "{#ExeName}" -Name: {group}\Uninstall {#ExeName}; Filename: {uninstallexe}; WorkingDir: {app}; -Name: {group}\Readme.txt; Filename: {app}\readme.txt; WorkingDir: {app} -Name: {group}\License.txt; Filename: {app}\license.txt; WorkingDir: {app} - -[Languages] -Name: en; MessagesFile: compiler:Default.isl -Name: cn; MessagesFile: Languages\ChineseSimplified.isl -Name: de; MessagesFile: compiler:Languages\German.isl -Name: es; MessagesFile: compiler:Languages\Spanish.isl -Name: fi; MessagesFile: compiler:Languages\Finnish.isl -Name: fr; MessagesFile: compiler:Languages\French.isl -Name: nl; MessagesFile: compiler:Languages\Dutch.isl -Name: lt; MessagesFile: Languages\Latvian.isl -Name: nn; MessagesFile: Languages\NorwegianNynorsk.isl -Name: sr; MessagesFile: Languages\SerbianCyrillic.isl -Name: sv; MessagesFile: Languages\Swedish.isl -Name: uk; MessagesFile: compiler:Languages\Ukrainian.isl - -[Tasks] -Name: startup; Description: {cm:startup} - -[CustomMessages] - -de.confluence=Confluence Plug-in -de.default=Standard installation -en.office=Microsoft Office Plug-in -de.externalcommand=Externes Kommando Plug-in -de.imgur=Imgur Plug-in (Siehe: http://imgur.com) -de.jira=Jira Plug-in -de.language=Zusätzliche Sprachen -de.ocr=OCR Plug-in (benötigt Microsoft Office Document Imaging (MODI)) -de.optimize=Optimierung der Leistung, kann etwas dauern. -de.startgreenshot={#ExeName} starten -de.startup={#ExeName} starten wenn Windows hochfährt -de.win10=Windows 10 Plug-in - -en.confluence=Confluence plug-in -en.default=Default installation -en.office=Microsoft Office plug-in -en.externalcommand=Open with external command plug-in -en.imgur=Imgur plug-in (See: http://imgur.com) -en.jira=Jira plug-in -en.language=Additional languages -en.ocr=OCR plug-in (needs Microsoft Office Document Imaging (MODI)) -en.optimize=Optimizing performance, this may take a while. -en.startgreenshot=Start {#ExeName} -en.startup=Start {#ExeName} with Windows start -en.win10=Windows 10 plug-in - -es.confluence=Extensión para Confluence -es.default=${default} -es.externalcommand=Extensión para abrir con programas externos -es.imgur=Extensión para Imgur (Ver http://imgur.com) -es.jira=Extensión para Jira -es.language=Idiomas adicionales -es.ocr=Extensión para OCR (necesita Microsoft Office Document Imaging (MODI)) -es.optimize=Optimizando rendimiento; por favor, espera. -es.startgreenshot=Lanzar {#ExeName} -es.startup=Lanzar {#ExeName} al iniciarse Windows -es.win10=Extensión para Windows 10 - -fi.confluence=Confluence-liitännäinen -fi.default=${default} -fi.office=Microsoft-Office-liitännäinen -fi.externalcommand=Avaa Ulkoinen komento-liitännäisellä -fi.imgur=Imgur-liitännäinen (Katso: http://imgur.com) -fi.jira=Jira-liitännäinen -fi.language=Lisäkielet -fi.ocr=OCR-liitännäinen (Tarvitaan: Microsoft Office Document Imaging (MODI)) -fi.optimize=Optimoidaan suorituskykyä, tämä voi kestää hetken. -fi.startgreenshot=Käynnistä {#ExeName} -fi.startup=Käynnistä {#ExeName} Windowsin käynnistyessä -fi.win10=Windows 10-liitännäinen - -fr.confluence=Greffon Confluence -fr.default=${default} -fr.office=Greffon Microsoft Office -fr.externalcommand=Ouvrir avec le greffon de commande externe -fr.imgur=Greffon Imgur (Voir: http://imgur.com) -fr.jira=Greffon Jira -fr.language=Langues additionnelles -fr.ocr=Greffon OCR (nécessite Document Imaging de Microsoft Office [MODI]) -fr.optimize=Optimisation des performances, Ceci peut prendre un certain temps. -fr.startgreenshot=Démarrer {#ExeName} -fr.startup=Lancer {#ExeName} au démarrage de Windows -fr.win10=Greffon Windows 10 - -lt.confluence=Confluence spraudnis -lt.default=${default} -lt.office=Microsoft Office spraudnis -lt.externalcommand=Pielāgotu darbību spraudnis -lt.imgur=Imgur spraudnis (Vairāk šeit: http://imgur.com) -lt.jira=Jira spraudnis -lt.language=Papildus valodas -lt.ocr=OCR spraudnis (nepieciešams Microsoft Office Document Imaging (MODI)) -lt.optimize=Uzlaboju veikstpēju, tas prasīs kādu laiciņu. -lt.startgreenshot=Palaist {#ExeName} -lt.startup=Palaist {#ExeName} uzsākot darbus -lt.win10=Windows 10 spraudnis - -nl.confluence=Confluence plug-in -nl.default=Standaardinstallatie -nl.office=Microsoft Office plug-in -nl.externalcommand=Openen met extern commando plug-in -nl.imgur=Imgur plug-in (zie: http://imgur.com) -nl.jira=Jira plug-in -nl.language=Extra talen -nl.ocr=OCR plug-in (vereist Microsoft Office Document Imaging (MODI)) -nl.optimize=Prestaties verbeteren, even geduld. -nl.startgreenshot={#ExeName} starten -nl.startup={#ExeName} automatisch starten met Windows -nl.win10=Windows 10 plug-in - -nn.confluence=Confluence-tillegg -nn.default=Default installation -nn.office=Microsoft Office Tillegg -nn.externalcommand=Tillegg for å opne med ekstern kommando -nn.imgur=Imgur-tillegg (sjå http://imgur.com) -nn.jira=Jira-tillegg -nn.language=Andre språk -nn.ocr=OCR-tillegg (krev Microsoft Office Document Imaging (MODI)) -nn.optimize=Optimaliserar ytelse, dette kan ta litt tid... -nn.startgreenshot=Start {#ExeName} -nn.startup=Start {#ExeName} når Windows startar -nn.win10=Windows 10 Tillegg - -sr.confluence=Прикључак за Конфлуенс -sr.default=${default} -sr.externalcommand=Отвори са прикључком за спољне наредбе -sr.imgur=Прикључак за Имиџер (http://imgur.com) -sr.jira=Прикључак за Џиру -sr.language=Додатни језици -sr.ocr=OCR прикључак (захтева Microsoft Office Document Imaging (MODI)) -sr.optimize=Оптимизујем перформансе… -sr.startgreenshot=Покрени Гриншот -sr.startup=Покрени програм са системом -sr.win10=Прикључак за Windows 10 - -sv.startup=Starta {#ExeName} med Windows -sv.startgreenshot=Starta {#ExeName} -sv.jira=Jira-insticksprogram -sv.confluence=Confluence-insticksprogram -sv.externalcommand=Öppna med externt kommando-insticksprogram -sv.ocr=OCR-insticksprogram (kräver Microsoft Office Document Imaging (MODI)) -sv.imgur=Imgur-insticksprogram (Se: http://imgur.com) -sv.language=Ytterligare språk -sv.optimize=Optimerar prestanda, detta kan ta en stund. -sv.win10=Windows 10-insticksprogram - -uk.confluence=Плагін Confluence -uk.default=${default} -uk.externalcommand=Плагін запуску зовнішньої команди -uk.imgur=Плагін Imgur (див.: http://imgur.com) -uk.jira=Плагін Jira -uk.language=Додаткові мови -uk.ocr=Плагін OCR (потребує Microsoft Office Document Imaging (MODI)) -uk.optimize=Оптимізація продуктивності, це може забрати час. -uk.startgreenshot=Запустити {#ExeName} -uk.startup=Запускати {#ExeName} під час запуску Windows -uk.win10=Плагін Windows 10 - -cn.confluence=Confluence插件 -cn.default=${default} -cn.externalcommand=使用外部命令打开插件 -cn.imgur=Imgur插件( (请访问: http://imgur.com)) -cn.jira=Jira插件 -cn.language=其它语言 -cn.ocr=OCR插件(需要Microsoft Office Document Imaging (MODI)的支持) -cn.optimize=正在优化性能,这可能需要一点时间。 -cn.startgreenshot=启动{#ExeName} -cn.startup=让{#ExeName}随Windows一起启动 -cn.win10=Windows 10插件 - -[Types] -Name: "default"; Description: "{cm:default}" -Name: "full"; Description: "{code:FullInstall}" -Name: "compact"; Description: "{code:CompactInstall}" -Name: "custom"; Description: "{code:CustomInstall}"; Flags: iscustom - -[Components] -Name: "greenshot"; Description: "Greenshot"; Types: default full compact custom; Flags: fixed -Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning -Name: "plugins\ocr"; Description: {cm:ocr}; Types: default full custom; Flags: disablenouninstallwarning -Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flags: disablenouninstallwarning -Name: "plugins\confluence"; Description: {cm:confluence}; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\externalcommand"; Description: {cm:externalcommand}; Types: default full custom; Flags: disablenouninstallwarning -;Name: "plugins\networkimport"; Description: "Network Import Plugin"; Types: full -Name: "plugins\box"; Description: "Box Plugin"; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\dropbox"; Description: "Dropbox Plugin"; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\flickr"; Description: "Flickr Plugin"; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\picasa"; Description: "Picasa Plugin"; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\photobucket"; Description: "Photobucket Plugin"; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\win10"; Description: "Windows 10 Plugin"; Types: default full custom; Flags: disablenouninstallwarning; Check: IsWindows10OrNewer() -Name: "languages"; Description: {cm:language}; Types: full custom; Flags: disablenouninstallwarning -Name: "languages\arSY"; Description: "العربية"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') -Name: "languages\caCA"; Description: "Català"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\csCZ"; Description: "Ceština"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\daDK"; Description: "Dansk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\dexfranconia"; Description: "Frängisch (Deutsch)"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\elGR"; Description: "ελληνικά"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('4') -Name: "languages\esES"; Description: "Español"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\etEE"; Description: "Eesti"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\faIR"; Description: "پارسی"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') -Name: "languages\fiFI"; Description: "Suomi"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\frFR"; Description: "Français"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\frQC"; Description: "Français - Québec"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\heIL"; Description: "עִבְרִית"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('c') -Name: "languages\huHU"; Description: "Magyar"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\idID"; Description: "Bahasa Indonesia"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\itIT"; Description: "Italiano"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\jaJP"; Description: "日本語"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('7') -Name: "languages\koKR"; Description: "한국어"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8') -Name: "languages\kabDZ"; Description: "Taqbaylit"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8') -Name: "languages\ltLT"; Description: "Lietuvių"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3') -Name: "languages\lvLV"; Description: "Latviski"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3') -Name: "languages\nnNO"; Description: "Nynorsk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\plPL"; Description: "Polski"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\ptBR"; Description: "Português do Brasil"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\ptPT"; Description: "Português de Portugal"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\ruRU"; Description: "Pусский"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') -Name: "languages\roRO"; Description: "Română"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\skSK"; Description: "Slovenčina"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\slSI"; Description: "Slovenščina"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\srRS"; Description: "Српски"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') -Name: "languages\svSE"; Description: "Svenska"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\trTR"; Description: "Türk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('6') -Name: "languages\ukUA"; Description: "Українська"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') -Name: "languages\viVN"; Description: "Việt"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('e') -Name: "languages\zhCN"; Description: "简体中文"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('a') -Name: "languages\zhTW"; Description: "繁體中文"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('9') -[Code] -// Do we have a regular user trying to install this? -function IsRegularUser(): Boolean; -begin - Result := not (IsAdmin or IsAdminInstallMode); -end; - -// The following code is used to select the installation path, this is localappdata if non poweruser -function DefDirRoot(Param: String): String; -begin - if IsRegularUser then - Result := ExpandConstant('{localappdata}') - else - Result := ExpandConstant('{pf}') -end; - - -function FullInstall(Param : String) : String; -begin - result := SetupMessage(msgFullInstallation); -end; - -function CustomInstall(Param : String) : String; -begin - result := SetupMessage(msgCustomInstallation); -end; - -function CompactInstall(Param : String) : String; -begin - result := SetupMessage(msgCompactInstallation); -end; -///////////////////////////////////////////////////////////////////// -// The following uninstall code was found at: -// http://stackoverflow.com/questions/2000296/innosetup-how-to-automatically-uninstall-previous-installed-version -// and than modified to work in a 32/64 bit environment -///////////////////////////////////////////////////////////////////// -function GetUninstallStrings(): array of String; -var - sUnInstPath: String; - sUnInstallString: String; - asUninstallStrings : array of String; - index : Integer; -begin - sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1'); - sUnInstallString := ''; - index := 0; - - // Retrieve uninstall string from HKLM32 or HKCU32 - if RegQueryStringValue(HKLM32, sUnInstPath, 'UninstallString', sUnInstallString) then - begin - SetArrayLength(asUninstallStrings, index + 1); - asUninstallStrings[index] := sUnInstallString; - index := index +1; - end; - - if RegQueryStringValue(HKCU32, sUnInstPath, 'UninstallString', sUnInstallString) then - begin - SetArrayLength(asUninstallStrings, index + 1); - asUninstallStrings[index] := sUnInstallString; - index := index +1; - end; - - // Only for Windows with 64 bit support: Retrieve uninstall string from HKLM64 or HKCU64 - if IsWin64 then - begin - if RegQueryStringValue(HKLM64, sUnInstPath, 'UninstallString', sUnInstallString) then - begin - SetArrayLength(asUninstallStrings, index + 1); - asUninstallStrings[index] := sUnInstallString; - index := index +1; - end; - - if RegQueryStringValue(HKCU64, sUnInstPath, 'UninstallString', sUnInstallString) then - begin - SetArrayLength(asUninstallStrings, index + 1); - asUninstallStrings[index] := sUnInstallString; - index := index +1; - end; - end; - Result := asUninstallStrings; -end; - -///////////////////////////////////////////////////////////////////// -procedure UnInstallOldVersions(); -var - sUnInstallString: String; - index: Integer; - isUninstallMade: Boolean; - iResultCode : Integer; - asUninstallStrings : array of String; -begin - isUninstallMade := false; - asUninstallStrings := GetUninstallStrings(); - for index := 0 to (GetArrayLength(asUninstallStrings) -1) do - begin - sUnInstallString := RemoveQuotes(asUninstallStrings[index]); - if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then - isUninstallMade := true; - end; - - // Wait a few seconds to prevent installation issues, otherwise files are removed in one process while the other tries to link to them - if (isUninstallMade) then - Sleep(2000); -end; - -///////////////////////////////////////////////////////////////////// -procedure CurStepChanged(CurStep: TSetupStep); -begin - if (CurStep=ssInstall) then - begin - UnInstallOldVersions(); - end; -end; -///////////////////////////////////////////////////////////////////// -// End of unstall code -///////////////////////////////////////////////////////////////////// - -// Build a list of greenshot parameters from the supplied installer parameters -function GetParamsForGS(argument: String): String; -var - i: Integer; - parametersString: String; - currentParameter: String; - foundStart: Boolean; - foundNoRun: Boolean; - foundLanguage: Boolean; -begin - foundNoRun := false; - foundLanguage := false; - foundStart := false; - for i:= 0 to ParamCount() do begin - currentParameter := ParamStr(i); - - // check if norun is supplied - if Lowercase(currentParameter) = '/norun' then begin - foundNoRun := true; - continue; - end; - - if foundStart then begin - parametersString := parametersString + ' ' + currentParameter; - foundStart := false; - end - else begin - if Lowercase(currentParameter) = '/language' then begin - foundStart := true; - foundLanguage := true; - parametersString := parametersString + ' ' + currentParameter; - end; - end; - end; - if not foundLanguage then begin - parametersString := parametersString + ' /language ' + ExpandConstant('{language}'); - end; - if foundNoRun then begin - parametersString := parametersString + ' /norun'; - end; - // For debugging comment out the following - //MsgBox(parametersString, mbInformation, MB_OK); - - Result := parametersString; -end; - -// Check if language group is installed -function hasLanguageGroup(argument: String): Boolean; -var - keyValue: String; - returnValue: Boolean; -begin - returnValue := true; - if (RegQueryStringValue( HKLM, 'SYSTEM\CurrentControlSet\Control\Nls\Language Groups', argument, keyValue)) then begin - if Length(keyValue) = 0 then begin - returnValue := false; - end; - end; - Result := returnValue; -end; - -function hasDotNet() : boolean; -begin - Result := netfxspversion(NetFx4x, '') >= 71; -end; - -// Initialize the setup -function InitializeSetup(): Boolean; -begin - // Check for .NET and install 4.7.1 if we don't have it - if not hasDotNet() then - begin - // Enhance installer, if needed, otherwise .NET installations won't work - msi20('2.0'); - msi31('3.0'); - - //install .net 4.7.1 - dotnetfx47(71); - end; - Result := true; -end; - -function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean; -var - Version: TWindowsVersion; -begin - GetWindowsVersionEx(Version); - Result := - (Version.Major > Major) or - ((Version.Major = Major) and (Version.Minor >= Minor)); -end; - -function IsWindows10OrNewer: Boolean; -begin - Result := IsWindowsVersionOrNewer(10, 0); -end; - -[Run] -Filename: "{app}\{#ExeName}.exe"; Description: "{cm:startgreenshot}"; Parameters: "{code:GetParamsForGS}"; WorkingDir: "{app}"; Flags: nowait postinstall runasoriginaluser -Filename: "http://getgreenshot.org/thank-you/?language={language}&version={#Version}"; Flags: shellexec runasoriginaluser - -[InstallDelete] -Name: {app}; Type: dirifempty; +#define ExeName "Greenshot" +#define Version GetEnv('BuildVersionSimple') +#define FileVersion GetEnv('AssemblyInformationalVersion') +#define BaseDir "..\..\.." +#define ReleaseDir "..\..\bin\Release\net472" +#define BinDir "bin\Release\net472" + +; Include the scripts to install .NET Framework +; See http://www.codeproject.com/KB/install/dotnetfx_innosetup_instal.aspx +#include "scripts\products.iss" +#include "scripts\products\stringversion.iss" +#include "scripts\products\winversion.iss" +#include "scripts\products\fileversion.iss" +#include "scripts\products\msi20.iss" +#include "scripts\products\msi31.iss" +#include "scripts\products\dotnetfxversion.iss" +#include "scripts\products\dotnetfx47.iss" + +[Files] +Source: {#ReleaseDir}\Greenshot.exe; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\GreenshotPlugin.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\Greenshot.exe.config; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\log4net.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\Dapplo.Http*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\Dapplo.Log.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\Newtonsoft.Json.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: ..\..\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion +Source: {#ReleaseDir}\checksum.SHA256; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +;Source: ..\greenshot-defaults.ini; DestDir: {app}; Flags: overwritereadonly ignoreversion replacesameversion +Source: ..\additional_files\installer.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion +Source: ..\additional_files\license.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion +Source: ..\additional_files\readme.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion + +; Core language files +Source: ..\..\Languages\*nl-NL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*en-US*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*de-DE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; + +; Additional language files +Source: ..\..\Languages\*ar-SY*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\arSY; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*ca-CA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\caCA; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*cs-CZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\csCZ; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*da-DK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\daDK; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*de-x-franconia*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\dexfranconia; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*el-GR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\elGR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*es-ES*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\esES; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*et-EE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\etEE; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*fa-IR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\faIR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*fi-FI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\fiFI; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*fr-FR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frFR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*fr-QC*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frQC; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*he-IL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\heIL; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*hu-HU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\huHU; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*id-ID*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\idID; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*it-IT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\itIT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*ja-JP*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\jaJP; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*ko-KR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\koKR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*kab-DZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\kabDZ; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*lt-LT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ltLT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*lv-LV*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\lvLV; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*nn-NO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\nnNO; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*pl-PL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\plPL; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*pt-BR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptBR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*pt-PT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptPT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*ro-RO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\roRO; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*ru-RU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ruRU; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*sk-SK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\skSK; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*sl-SI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\slSI; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*sr-RS*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\srRS; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*sv-SE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\svSE; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*tr-TR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\trTR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*uk-UA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ukUA; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*vi-VN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\viVN; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhCN; Flags: overwritereadonly ignoreversion replacesameversion; +Source: ..\..\Languages\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion; + +;Office Plugin +Source: {#BaseDir}\GreenshotOfficePlugin\{#BinDir}\GreenshotOfficePlugin.dll; DestDir: {app}\Plugins\GreenshotOfficePlugin; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +;OCR Plugin +Source: {#BaseDir}\GreenshotOCRPlugin\{#BinDir}\GreenshotOCRPlugin.dll; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotOCRPlugin\Languages\language_ocr*.xml; DestDir: {app}\Languages\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe.config; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +;JIRA Plugin +Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\GreenshotJiraPlugin.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\Dapplo.Jira.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotJiraPlugin\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion; +;Imgur Plugin +Source: {#BaseDir}\GreenshotImgurPlugin\{#BinDir}\GreenshotImgurPlugin.dll; DestDir: {app}\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotImgurPlugin\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion; +;Box Plugin +Source: {#BaseDir}\GreenshotBoxPlugin\{#BinDir}\GreenshotBoxPlugin.dll; DestDir: {app}\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotBoxPlugin\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion; +;DropBox Plugin +Source: {#BaseDir}\GreenshotDropBoxPlugin\{#BinDir}\GreenshotDropboxPlugin.dll; DestDir: {app}\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotDropBoxPlugin\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion; +;Flickr Plugin +Source: {#BaseDir}\GreenshotFlickrPlugin\{#BinDir}\GreenshotFlickrPlugin.dll; DestDir: {app}\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotFlickrPlugin\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion; +;Photobucket Plugin +Source: {#BaseDir}\GreenshotPhotobucketPlugin\{#BinDir}\GreenshotPhotobucketPlugin.dll; DestDir: {app}\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotPhotobucketPlugin\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion; +;Picasa Plugin +Source: {#BaseDir}\GreenshotPicasaPlugin\{#BinDir}\GreenshotPicasaPlugin.dll; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotPicasaPlugin\Languages\language_picasa*.xml; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion; +;Confluence Plugin +Source: {#BaseDir}\GreenshotConfluencePlugin\{#BinDir}\GreenshotConfluencePlugin.dll; DestDir: {app}\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotConfluencePlugin\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; +;ExternalCommand Plugin +Source: {#BaseDir}\GreenshotExternalCommandPlugin\{#BinDir}\GreenshotExternalCommandPlugin.dll; DestDir: {app}\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotExternalCommandPlugin\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion; +;Win 10 Plugin +Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\GreenshotWin10Plugin.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +[Setup] +; changes associations is used when the installer installs new extensions, it clears the explorer icon cache +ChangesAssociations=yes +AppId={#ExeName} +AppName={#ExeName} +AppMutex=F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08 +AppPublisher={#ExeName} +AppPublisherURL=http://getgreenshot.org +AppSupportURL=http://getgreenshot.org +AppUpdatesURL=http://getgreenshot.org +AppVerName={#ExeName} {#Version} +AppVersion={#Version} +ArchitecturesInstallIn64BitMode=x64 +Compression=lzma2/ultra64 +SolidCompression=yes +DefaultDirName={code:DefDirRoot}\{#ExeName} +DefaultGroupName={#ExeName} +InfoBeforeFile=..\additional_files\readme.txt +LicenseFile=..\additional_files\license.txt +LanguageDetectionMethod=uilanguage +MinVersion=6.1.7600 +OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE +OutputDir=..\ +PrivilegesRequired=lowest +SetupIconFile=..\..\icons\applicationIcon\icon.ico +; Create a SHA1 signature +; SignTool=SignTool sign /debug /fd sha1 /tr http://time.certum.pl /td sha1 $f +; Append a SHA256 to the previous SHA1 signature (this is what as does) +; SignTool=SignTool sign /debug /as /fd sha256 /tr http://time.certum.pl /td sha256 $f +; SignedUninstaller=yes +UninstallDisplayIcon={app}\{#ExeName}.exe +Uninstallable=true +VersionInfoCompany={#ExeName} +VersionInfoProductName={#ExeName} +VersionInfoProductTextVersion={#FileVersion} +VersionInfoTextVersion={#FileVersion} +VersionInfoVersion={#Version} +; Reference a bitmap, max size 164x314 +WizardImageFile=installer-large.bmp +; Reference a bitmap, max size 55x58 +WizardSmallImageFile=installer-small.bmp +[Registry] +; Delete all startup entries, so we don't have leftover values +Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; +Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; +Root: HKCU32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() +Root: HKLM32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() + +; delete filetype mappings +; HKEY_LOCAL_USER - for current user only +Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; +Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; +; HKEY_LOCAL_MACHINE - for all users when admin (with the noerror this doesn't matter) +Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; +Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; + +; Create the startup entries if requested to do so +; HKEY_LOCAL_USER - for current user only +Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: users-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: IsRegularUser +; HKEY_LOCAL_MACHINE - for all users when admin +Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: not IsRegularUser + +; Register our own filetype for all users +; HKEY_LOCAL_USER - for current user only +Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser +Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser +Root: HKCU; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser +Root: HKCU; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser +; HKEY_LOCAL_MACHINE - for all users when admin +Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser +Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser +Root: HKLM; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser +Root: HKLM; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser + +[Icons] +Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app}; AppUserModelID: "{#ExeName}" +Name: {group}\Uninstall {#ExeName}; Filename: {uninstallexe}; WorkingDir: {app}; +Name: {group}\Readme.txt; Filename: {app}\readme.txt; WorkingDir: {app} +Name: {group}\License.txt; Filename: {app}\license.txt; WorkingDir: {app} + +[Languages] +Name: en; MessagesFile: compiler:Default.isl +Name: cn; MessagesFile: Languages\ChineseSimplified.isl +Name: de; MessagesFile: compiler:Languages\German.isl +Name: es; MessagesFile: compiler:Languages\Spanish.isl +Name: fi; MessagesFile: compiler:Languages\Finnish.isl +Name: fr; MessagesFile: compiler:Languages\French.isl +Name: nl; MessagesFile: compiler:Languages\Dutch.isl +Name: lt; MessagesFile: Languages\Latvian.isl +Name: nn; MessagesFile: Languages\NorwegianNynorsk.isl +Name: ru; MessagesFile: compiler:Languages\Russian.isl +Name: sr; MessagesFile: Languages\SerbianCyrillic.isl +Name: sv; MessagesFile: Languages\Swedish.isl +Name: uk; MessagesFile: compiler:Languages\Ukrainian.isl + +[Tasks] +Name: startup; Description: {cm:startup} + +[CustomMessages] + +de.confluence=Confluence Plug-in +de.default=Standard installation +en.office=Microsoft Office Plug-in +de.externalcommand=Externes Kommando Plug-in +de.imgur=Imgur Plug-in (Siehe: http://imgur.com) +de.jira=Jira Plug-in +de.language=Zusätzliche Sprachen +de.ocr=OCR Plug-in (benötigt Microsoft Office Document Imaging (MODI)) +de.optimize=Optimierung der Leistung, kann etwas dauern. +de.startgreenshot={#ExeName} starten +de.startup={#ExeName} starten wenn Windows hochfährt +de.win10=Windows 10 Plug-in + +en.confluence=Confluence plug-in +en.default=Default installation +en.office=Microsoft Office plug-in +en.externalcommand=Open with external command plug-in +en.imgur=Imgur plug-in (See: http://imgur.com) +en.jira=Jira plug-in +en.language=Additional languages +en.ocr=OCR plug-in (needs Microsoft Office Document Imaging (MODI)) +en.optimize=Optimizing performance, this may take a while. +en.startgreenshot=Start {#ExeName} +en.startup=Start {#ExeName} with Windows start +en.win10=Windows 10 plug-in + +es.confluence=Extensión para Confluence +es.default=${default} +es.externalcommand=Extensión para abrir con programas externos +es.imgur=Extensión para Imgur (Ver http://imgur.com) +es.jira=Extensión para Jira +es.language=Idiomas adicionales +es.ocr=Extensión para OCR (necesita Microsoft Office Document Imaging (MODI)) +es.optimize=Optimizando rendimiento; por favor, espera. +es.startgreenshot=Lanzar {#ExeName} +es.startup=Lanzar {#ExeName} al iniciarse Windows +es.win10=Extensión para Windows 10 + +fi.confluence=Confluence-liitännäinen +fi.default=${default} +fi.office=Microsoft-Office-liitännäinen +fi.externalcommand=Avaa Ulkoinen komento-liitännäisellä +fi.imgur=Imgur-liitännäinen (Katso: http://imgur.com) +fi.jira=Jira-liitännäinen +fi.language=Lisäkielet +fi.ocr=OCR-liitännäinen (Tarvitaan: Microsoft Office Document Imaging (MODI)) +fi.optimize=Optimoidaan suorituskykyä, tämä voi kestää hetken. +fi.startgreenshot=Käynnistä {#ExeName} +fi.startup=Käynnistä {#ExeName} Windowsin käynnistyessä +fi.win10=Windows 10-liitännäinen + +fr.confluence=Greffon Confluence +fr.default=${default} +fr.office=Greffon Microsoft Office +fr.externalcommand=Ouvrir avec le greffon de commande externe +fr.imgur=Greffon Imgur (Voir: http://imgur.com) +fr.jira=Greffon Jira +fr.language=Langues additionnelles +fr.ocr=Greffon OCR (nécessite Document Imaging de Microsoft Office [MODI]) +fr.optimize=Optimisation des performances, Ceci peut prendre un certain temps. +fr.startgreenshot=Démarrer {#ExeName} +fr.startup=Lancer {#ExeName} au démarrage de Windows +fr.win10=Greffon Windows 10 + +lt.confluence=Confluence spraudnis +lt.default=${default} +lt.office=Microsoft Office spraudnis +lt.externalcommand=Pielāgotu darbību spraudnis +lt.imgur=Imgur spraudnis (Vairāk šeit: http://imgur.com) +lt.jira=Jira spraudnis +lt.language=Papildus valodas +lt.ocr=OCR spraudnis (nepieciešams Microsoft Office Document Imaging (MODI)) +lt.optimize=Uzlaboju veikstpēju, tas prasīs kādu laiciņu. +lt.startgreenshot=Palaist {#ExeName} +lt.startup=Palaist {#ExeName} uzsākot darbus +lt.win10=Windows 10 spraudnis + +nl.confluence=Confluence plug-in +nl.default=Standaardinstallatie +nl.office=Microsoft Office plug-in +nl.externalcommand=Openen met extern commando plug-in +nl.imgur=Imgur plug-in (zie: http://imgur.com) +nl.jira=Jira plug-in +nl.language=Extra talen +nl.ocr=OCR plug-in (vereist Microsoft Office Document Imaging (MODI)) +nl.optimize=Prestaties verbeteren, even geduld. +nl.startgreenshot={#ExeName} starten +nl.startup={#ExeName} automatisch starten met Windows +nl.win10=Windows 10 plug-in + +nn.confluence=Confluence-tillegg +nn.default=Default installation +nn.office=Microsoft Office Tillegg +nn.externalcommand=Tillegg for å opne med ekstern kommando +nn.imgur=Imgur-tillegg (sjå http://imgur.com) +nn.jira=Jira-tillegg +nn.language=Andre språk +nn.ocr=OCR-tillegg (krev Microsoft Office Document Imaging (MODI)) +nn.optimize=Optimaliserar ytelse, dette kan ta litt tid... +nn.startgreenshot=Start {#ExeName} +nn.startup=Start {#ExeName} når Windows startar +nn.win10=Windows 10 Tillegg + +ru.confluence=Плагин Confluence +ru.default=${default} +ru.office=Плагин Microsoft Office +ru.externalcommand=Открыть с плагином с помощью внешней команды +ru.imgur=Плагин Imgur (смотрите https://imgur.com/) +ru.jira=Плагин Jira +ru.language=Дополнительные языки +ru.ocr=Плагин OCR (требуется Microsoft Office Document Imaging (MODI)) +ru.optimize=Идет оптимизация производительности, это может занять некоторое время. +ru.startgreenshot=Запустить {#ExeName} +ru.startup=Запускать {#ExeName} при старте Windows +ru.win10=Плагин Windows 10 + +sr.confluence=Прикључак за Конфлуенс +sr.default=${default} +sr.externalcommand=Отвори са прикључком за спољне наредбе +sr.imgur=Прикључак за Имиџер (http://imgur.com) +sr.jira=Прикључак за Џиру +sr.language=Додатни језици +sr.ocr=OCR прикључак (захтева Microsoft Office Document Imaging (MODI)) +sr.optimize=Оптимизујем перформансе… +sr.startgreenshot=Покрени Гриншот +sr.startup=Покрени програм са системом +sr.win10=Прикључак за Windows 10 + +sv.startup=Starta {#ExeName} med Windows +sv.startgreenshot=Starta {#ExeName} +sv.jira=Jira-insticksprogram +sv.confluence=Confluence-insticksprogram +sv.externalcommand=Öppna med externt kommando-insticksprogram +sv.ocr=OCR-insticksprogram (kräver Microsoft Office Document Imaging (MODI)) +sv.imgur=Imgur-insticksprogram (Se: http://imgur.com) +sv.language=Ytterligare språk +sv.optimize=Optimerar prestanda, detta kan ta en stund. +sv.win10=Windows 10-insticksprogram + +uk.confluence=Плагін Confluence +uk.default=${default} +uk.externalcommand=Плагін запуску зовнішньої команди +uk.imgur=Плагін Imgur (див.: http://imgur.com) +uk.jira=Плагін Jira +uk.language=Додаткові мови +uk.ocr=Плагін OCR (потребує Microsoft Office Document Imaging (MODI)) +uk.optimize=Оптимізація продуктивності, це може забрати час. +uk.startgreenshot=Запустити {#ExeName} +uk.startup=Запускати {#ExeName} під час запуску Windows +uk.win10=Плагін Windows 10 + +cn.confluence=Confluence插件 +cn.default=${default} +cn.externalcommand=使用外部命令打开插件 +cn.imgur=Imgur插件( (请访问: http://imgur.com)) +cn.jira=Jira插件 +cn.language=其它语言 +cn.ocr=OCR插件(需要Microsoft Office Document Imaging (MODI)的支持) +cn.optimize=正在优化性能,这可能需要一点时间。 +cn.startgreenshot=启动{#ExeName} +cn.startup=让{#ExeName}随Windows一起启动 +cn.win10=Windows 10插件 + +[Types] +Name: "default"; Description: "{cm:default}" +Name: "full"; Description: "{code:FullInstall}" +Name: "compact"; Description: "{code:CompactInstall}" +Name: "custom"; Description: "{code:CustomInstall}"; Flags: iscustom + +[Components] +Name: "greenshot"; Description: "Greenshot"; Types: default full compact custom; Flags: fixed +Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning +Name: "plugins\ocr"; Description: {cm:ocr}; Types: default full custom; Flags: disablenouninstallwarning +Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flags: disablenouninstallwarning +Name: "plugins\confluence"; Description: {cm:confluence}; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\externalcommand"; Description: {cm:externalcommand}; Types: default full custom; Flags: disablenouninstallwarning +;Name: "plugins\networkimport"; Description: "Network Import Plugin"; Types: full +Name: "plugins\box"; Description: "Box Plugin"; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\dropbox"; Description: "Dropbox Plugin"; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\flickr"; Description: "Flickr Plugin"; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\picasa"; Description: "Picasa Plugin"; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\photobucket"; Description: "Photobucket Plugin"; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\win10"; Description: "Windows 10 Plugin"; Types: default full custom; Flags: disablenouninstallwarning; Check: IsWindows10OrNewer() +Name: "languages"; Description: {cm:language}; Types: full custom; Flags: disablenouninstallwarning +Name: "languages\arSY"; Description: "العربية"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') +Name: "languages\caCA"; Description: "Català"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\csCZ"; Description: "Ceština"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\daDK"; Description: "Dansk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\dexfranconia"; Description: "Frängisch (Deutsch)"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\elGR"; Description: "ελληνικά"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('4') +Name: "languages\esES"; Description: "Español"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\etEE"; Description: "Eesti"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\faIR"; Description: "پارسی"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') +Name: "languages\fiFI"; Description: "Suomi"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\frFR"; Description: "Français"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\frQC"; Description: "Français - Québec"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\heIL"; Description: "עִבְרִית"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('c') +Name: "languages\huHU"; Description: "Magyar"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\idID"; Description: "Bahasa Indonesia"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\itIT"; Description: "Italiano"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\jaJP"; Description: "日本語"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('7') +Name: "languages\koKR"; Description: "한국어"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8') +Name: "languages\kabDZ"; Description: "Taqbaylit"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8') +Name: "languages\ltLT"; Description: "Lietuvių"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3') +Name: "languages\lvLV"; Description: "Latviski"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3') +Name: "languages\nnNO"; Description: "Nynorsk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\plPL"; Description: "Polski"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\ptBR"; Description: "Português do Brasil"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\ptPT"; Description: "Português de Portugal"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\ruRU"; Description: "Pусский"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') +Name: "languages\roRO"; Description: "Română"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\skSK"; Description: "Slovenčina"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\slSI"; Description: "Slovenščina"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\srRS"; Description: "Српски"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') +Name: "languages\svSE"; Description: "Svenska"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\trTR"; Description: "Türk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('6') +Name: "languages\ukUA"; Description: "Українська"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') +Name: "languages\viVN"; Description: "Việt"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('e') +Name: "languages\zhCN"; Description: "简体中文"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('a') +Name: "languages\zhTW"; Description: "繁體中文"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('9') +[Code] +// Do we have a regular user trying to install this? +function IsRegularUser(): Boolean; +begin + Result := not (IsAdmin or IsAdminInstallMode); +end; + +// The following code is used to select the installation path, this is localappdata if non poweruser +function DefDirRoot(Param: String): String; +begin + if IsRegularUser then + Result := ExpandConstant('{localappdata}') + else + Result := ExpandConstant('{pf}') +end; + + +function FullInstall(Param : String) : String; +begin + result := SetupMessage(msgFullInstallation); +end; + +function CustomInstall(Param : String) : String; +begin + result := SetupMessage(msgCustomInstallation); +end; + +function CompactInstall(Param : String) : String; +begin + result := SetupMessage(msgCompactInstallation); +end; +///////////////////////////////////////////////////////////////////// +// The following uninstall code was found at: +// http://stackoverflow.com/questions/2000296/innosetup-how-to-automatically-uninstall-previous-installed-version +// and than modified to work in a 32/64 bit environment +///////////////////////////////////////////////////////////////////// +function GetUninstallStrings(): array of String; +var + sUnInstPath: String; + sUnInstallString: String; + asUninstallStrings : array of String; + index : Integer; +begin + sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1'); + sUnInstallString := ''; + index := 0; + + // Retrieve uninstall string from HKLM32 or HKCU32 + if RegQueryStringValue(HKLM32, sUnInstPath, 'UninstallString', sUnInstallString) then + begin + SetArrayLength(asUninstallStrings, index + 1); + asUninstallStrings[index] := sUnInstallString; + index := index +1; + end; + + if RegQueryStringValue(HKCU32, sUnInstPath, 'UninstallString', sUnInstallString) then + begin + SetArrayLength(asUninstallStrings, index + 1); + asUninstallStrings[index] := sUnInstallString; + index := index +1; + end; + + // Only for Windows with 64 bit support: Retrieve uninstall string from HKLM64 or HKCU64 + if IsWin64 then + begin + if RegQueryStringValue(HKLM64, sUnInstPath, 'UninstallString', sUnInstallString) then + begin + SetArrayLength(asUninstallStrings, index + 1); + asUninstallStrings[index] := sUnInstallString; + index := index +1; + end; + + if RegQueryStringValue(HKCU64, sUnInstPath, 'UninstallString', sUnInstallString) then + begin + SetArrayLength(asUninstallStrings, index + 1); + asUninstallStrings[index] := sUnInstallString; + index := index +1; + end; + end; + Result := asUninstallStrings; +end; + +///////////////////////////////////////////////////////////////////// +procedure UnInstallOldVersions(); +var + sUnInstallString: String; + index: Integer; + isUninstallMade: Boolean; + iResultCode : Integer; + asUninstallStrings : array of String; +begin + isUninstallMade := false; + asUninstallStrings := GetUninstallStrings(); + for index := 0 to (GetArrayLength(asUninstallStrings) -1) do + begin + sUnInstallString := RemoveQuotes(asUninstallStrings[index]); + if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then + isUninstallMade := true; + end; + + // Wait a few seconds to prevent installation issues, otherwise files are removed in one process while the other tries to link to them + if (isUninstallMade) then + Sleep(2000); +end; + +///////////////////////////////////////////////////////////////////// +procedure CurStepChanged(CurStep: TSetupStep); +begin + if (CurStep=ssInstall) then + begin + UnInstallOldVersions(); + end; +end; +///////////////////////////////////////////////////////////////////// +// End of unstall code +///////////////////////////////////////////////////////////////////// + +// Build a list of greenshot parameters from the supplied installer parameters +function GetParamsForGS(argument: String): String; +var + i: Integer; + parametersString: String; + currentParameter: String; + foundStart: Boolean; + foundNoRun: Boolean; + foundLanguage: Boolean; +begin + foundNoRun := false; + foundLanguage := false; + foundStart := false; + for i:= 0 to ParamCount() do begin + currentParameter := ParamStr(i); + + // check if norun is supplied + if Lowercase(currentParameter) = '/norun' then begin + foundNoRun := true; + continue; + end; + + if foundStart then begin + parametersString := parametersString + ' ' + currentParameter; + foundStart := false; + end + else begin + if Lowercase(currentParameter) = '/language' then begin + foundStart := true; + foundLanguage := true; + parametersString := parametersString + ' ' + currentParameter; + end; + end; + end; + if not foundLanguage then begin + parametersString := parametersString + ' /language ' + ExpandConstant('{language}'); + end; + if foundNoRun then begin + parametersString := parametersString + ' /norun'; + end; + // For debugging comment out the following + //MsgBox(parametersString, mbInformation, MB_OK); + + Result := parametersString; +end; + +// Check if language group is installed +function hasLanguageGroup(argument: String): Boolean; +var + keyValue: String; + returnValue: Boolean; +begin + returnValue := true; + if (RegQueryStringValue( HKLM, 'SYSTEM\CurrentControlSet\Control\Nls\Language Groups', argument, keyValue)) then begin + if Length(keyValue) = 0 then begin + returnValue := false; + end; + end; + Result := returnValue; +end; + +function hasDotNet() : boolean; +begin + Result := netfxspversion(NetFx4x, '') >= 71; +end; + +// Initialize the setup +function InitializeSetup(): Boolean; +begin + // Check for .NET and install 4.7.1 if we don't have it + if not hasDotNet() then + begin + // Enhance installer, if needed, otherwise .NET installations won't work + msi20('2.0'); + msi31('3.0'); + + //install .net 4.7.1 + dotnetfx47(71); + end; + Result := true; +end; + +function IsWindowsVersionOrNewer(Major, Minor: Integer): Boolean; +var + Version: TWindowsVersion; +begin + GetWindowsVersionEx(Version); + Result := + (Version.Major > Major) or + ((Version.Major = Major) and (Version.Minor >= Minor)); +end; + +function IsWindows10OrNewer: Boolean; +begin + Result := IsWindowsVersionOrNewer(10, 0); +end; + +[Run] +Filename: "{app}\{#ExeName}.exe"; Description: "{cm:startgreenshot}"; Parameters: "{code:GetParamsForGS}"; WorkingDir: "{app}"; Flags: nowait postinstall runasoriginaluser +Filename: "http://getgreenshot.org/thank-you/?language={language}&version={#Version}"; Flags: shellexec runasoriginaluser + +[InstallDelete] +Name: {app}; Type: dirifempty; From 53c93e25b576b7c3397ae981e7f8d3206c79b794 Mon Sep 17 00:00:00 2001 From: jklingen <jens@getgreenshot.org> Date: Sun, 3 May 2020 18:27:33 +0200 Subject: [PATCH 043/232] Installer: Backport: Fix Prefix for German Translation Message --- Greenshot/releases/innosetup/setup.iss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 0c42af120..f15a578aa 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -1,4 +1,4 @@ -#define ExeName "Greenshot" +#define ExeName "Greenshot" #define Version GetEnv('BuildVersionSimple') #define FileVersion GetEnv('AssemblyInformationalVersion') #define BaseDir "..\..\.." @@ -215,7 +215,7 @@ Name: startup; Description: {cm:startup} de.confluence=Confluence Plug-in de.default=Standard installation -en.office=Microsoft Office Plug-in +de.office=Microsoft Office Plug-in de.externalcommand=Externes Kommando Plug-in de.imgur=Imgur Plug-in (Siehe: http://imgur.com) de.jira=Jira Plug-in From 2a5ae1557e132b0d332bf7bdb094d462938059ca Mon Sep 17 00:00:00 2001 From: MXI <KillyMXI@users.noreply.github.com> Date: Mon, 11 May 2020 00:03:53 +0300 Subject: [PATCH 044/232] Converters fix for release 1.3 (#204) * Converters fix for release 1.3 --- .../Drawing/Fields/Binding/DecimalFloatConverter.cs | 8 ++++---- .../Drawing/Fields/Binding/DecimalIntConverter.cs | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs index b4a4283e4..70581bc10 100644 --- a/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs +++ b/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs @@ -35,13 +35,13 @@ namespace Greenshot.Drawing.Fields.Binding { } protected override float convert(decimal o) { - return Convert.ToInt16(o); + return Convert.ToSingle(o); } public static DecimalFloatConverter GetInstance() - { - return _uniqueInstance ??= new DecimalFloatConverter(); - } + { + return _uniqueInstance ??= new DecimalFloatConverter(); + } } } diff --git a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs index d71d27528..693e532dd 100644 --- a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs +++ b/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * @@ -35,13 +35,13 @@ namespace Greenshot.Drawing.Fields.Binding { } protected override int convert(decimal o) { - return Convert.ToInt16(o); + return Convert.ToInt32(o); } public static DecimalIntConverter GetInstance() - { - return _uniqueInstance ??= new DecimalIntConverter(); - } + { + return _uniqueInstance ??= new DecimalIntConverter(); + } } } From 5db1f5564b660734b2fe18dee070e23be7c8d7da Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sun, 10 May 2020 23:04:31 +0200 Subject: [PATCH 045/232] Fixed the issue that someone could have a windows 10 version which is older than what we can support. (#207) Also upgrade Inno Setup and SVG --- Directory.Build.props | 2 +- Greenshot/Greenshot.csproj | 2 +- GreenshotPlugin/Core/WindowsVersion.cs | 7 ++++++- GreenshotPlugin/GreenshotPlugin.csproj | 2 +- GreenshotWin10Plugin/Win10Plugin.cs | 8 ++++++-- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 37b63badc..1415521cf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -56,7 +56,7 @@ </PropertyGroup> <ItemGroup Condition="!$(MSBuildProjectName.Contains('Tests')) And $(MSBuildProjectName.StartsWith('Greenshot'))"> - <PackageReference Include="Nerdbank.GitVersioning" Version="3.1.74"> + <PackageReference Include="Nerdbank.GitVersioning" Version="3.1.91"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference> diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj index 1b25c59a2..080651ceb 100644 --- a/Greenshot/Greenshot.csproj +++ b/Greenshot/Greenshot.csproj @@ -17,7 +17,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Tools.InnoSetup" version="6.0.3" GeneratePathProperty="true" /> + <PackageReference Include="Tools.InnoSetup" version="6.0.4" GeneratePathProperty="true" /> </ItemGroup> <ItemGroup> diff --git a/GreenshotPlugin/Core/WindowsVersion.cs b/GreenshotPlugin/Core/WindowsVersion.cs index 6dd4faa08..cd263d518 100644 --- a/GreenshotPlugin/Core/WindowsVersion.cs +++ b/GreenshotPlugin/Core/WindowsVersion.cs @@ -41,7 +41,7 @@ namespace GreenshotPlugin.Core public static bool IsWindows7OrLater { get; } = WinVersion.Major == 6 && WinVersion.Minor >= 1 || WinVersion.Major > 6; public static bool IsWindows7OrLower { get; } = WinVersionTotal <= 6.1; - + /// <summary> /// Test if the current OS is Windows 8.0 /// </summary> @@ -102,6 +102,11 @@ namespace GreenshotPlugin.Core /// <returns>true if we are running on Windows XP or later</returns> public static bool IsWindowsXpOrLater { get; } = WinVersion.Major >= 5 || WinVersion.Major == 5 && WinVersion.Minor >= 1; + /// <summary> + /// Returns the windows build number + /// </summary> + public static int BuildVersion => WinVersion.Build; + /// <summary> /// Test if the current Windows version is 10 and the build number or later /// See the build numbers <a href="https://en.wikipedia.org/wiki/Windows_10_version_history">here</a> diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj index 1a9598bc0..574e0fafc 100644 --- a/GreenshotPlugin/GreenshotPlugin.csproj +++ b/GreenshotPlugin/GreenshotPlugin.csproj @@ -15,7 +15,7 @@ <ItemGroup> <PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="0.10.9" /> <PackageReference Include="log4net" version="2.0.8" /> - <PackageReference Include="Svg" Version="3.0.102" /> + <PackageReference Include="Svg" Version="3.1.1" /> <Reference Include="Accessibility" /> <Reference Include="CustomMarshalers" /> </ItemGroup> diff --git a/GreenshotWin10Plugin/Win10Plugin.cs b/GreenshotWin10Plugin/Win10Plugin.cs index 1e0519071..53344f391 100644 --- a/GreenshotWin10Plugin/Win10Plugin.cs +++ b/GreenshotWin10Plugin/Win10Plugin.cs @@ -35,7 +35,9 @@ namespace GreenshotWin10Plugin [Plugin("Win10", false)] public sealed class Win10Plugin : IGreenshotPlugin { - public void Dispose() + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10Plugin)); + + public void Dispose() { Dispose(true); } @@ -58,8 +60,10 @@ namespace GreenshotWin10Plugin /// <returns>true if plugin is initialized, false if not (doesn't show)</returns> public bool Initialize() { - if (!WindowsVersion.IsWindows10OrLater) + // Here we check if the build version of Windows is actually what we support + if (!WindowsVersion.IsWindows10BuildOrLater(17763)) { + Log.WarnFormat("No support for Windows build {0}", WindowsVersion.BuildVersion); return false; } From 6a09345649ab36fcc74db305a072597b2009927a Mon Sep 17 00:00:00 2001 From: Robin <robin@dapplo.net> Date: Mon, 20 Jul 2020 00:00:42 +0200 Subject: [PATCH 046/232] Fixed a typo Fixed #218 Added JPEG (vs JPG) as a format which can be handled Updated dependencies --- Greenshot/Greenshot.csproj | 2 +- GreenshotJiraPlugin/GreenshotJiraPlugin.csproj | 2 +- GreenshotPlugin/Core/ClipboardHelper.cs | 11 +++++++---- GreenshotPlugin/GreenshotPlugin.csproj | 2 +- GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs | 10 +++++++++- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj index 080651ceb..03b68dc1b 100644 --- a/Greenshot/Greenshot.csproj +++ b/Greenshot/Greenshot.csproj @@ -17,7 +17,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Tools.InnoSetup" version="6.0.4" GeneratePathProperty="true" /> + <PackageReference Include="Tools.InnoSetup" version="6.0.5" GeneratePathProperty="true" /> </ItemGroup> <ItemGroup> diff --git a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj b/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj index 5579b7dac..6901a31c5 100644 --- a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj +++ b/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj @@ -12,6 +12,6 @@ </ItemGroup> <ItemGroup> <ProjectReference Include="..\GreenshotPlugin\GreenshotPlugin.csproj" /> - <PackageReference Include="Dapplo.Jira" version="0.9.21" /> + <PackageReference Include="Dapplo.Jira" version="0.9.28" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/GreenshotPlugin/Core/ClipboardHelper.cs b/GreenshotPlugin/Core/ClipboardHelper.cs index 272624c26..3933ccf71 100644 --- a/GreenshotPlugin/Core/ClipboardHelper.cs +++ b/GreenshotPlugin/Core/ClipboardHelper.cs @@ -49,6 +49,7 @@ namespace GreenshotPlugin.Core { private static readonly string FORMAT_PNG_OFFICEART = "PNG+Office Art"; private static readonly string FORMAT_17 = "Format17"; private static readonly string FORMAT_JPG = "JPG"; + private static readonly string FORMAT_JPEG = "JPEG"; private static readonly string FORMAT_JFIF = "JFIF"; private static readonly string FORMAT_JFIF_OFFICEART = "JFIF+Office Art"; private static readonly string FORMAT_GIF = "GIF"; @@ -253,7 +254,9 @@ EndSelection:<<<<<<<4 || dataObject.GetDataPresent(FORMAT_PNG) || dataObject.GetDataPresent(FORMAT_17) || dataObject.GetDataPresent(FORMAT_JPG) - || dataObject.GetDataPresent(FORMAT_GIF)) { + || dataObject.GetDataPresent(FORMAT_JFIF) + || dataObject.GetDataPresent(FORMAT_JPEG) + || dataObject.GetDataPresent(FORMAT_GIF)) { return true; } var imageFiles = GetImageFilenames(dataObject); @@ -345,9 +348,9 @@ EndSelection:<<<<<<<4 if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) { // Outlook ?? Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front..."); - retrieveFormats = new[] { DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF }; + retrieveFormats = new[] { DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF }; } else { - retrieveFormats = new[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF }; + retrieveFormats = new[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF }; } foreach (string currentFormat in retrieveFormats) { if (formats != null && formats.Contains(currentFormat)) { @@ -700,7 +703,7 @@ EndSelection:<<<<<<<4 //now copy to clipboard IDataObject dataObj = new DataObject(); dataObj.SetData(format.Name, false, obj); - // Use false to make the object dissapear when the application stops. + // Use false to make the object disappear when the application stops. SetDataObject(dataObj, true); } diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj index 574e0fafc..461aa6c84 100644 --- a/GreenshotPlugin/GreenshotPlugin.csproj +++ b/GreenshotPlugin/GreenshotPlugin.csproj @@ -13,7 +13,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="0.10.9" /> + <PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="1.0.3" /> <PackageReference Include="log4net" version="2.0.8" /> <PackageReference Include="Svg" Version="3.1.1" /> <Reference Include="Accessibility" /> diff --git a/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs b/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs index c5b5a8f4f..3ed89b95d 100644 --- a/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs +++ b/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs @@ -41,9 +41,17 @@ namespace GreenshotWin10Plugin.Processors { } var ocrProvider = SimpleServiceProvider.Current.GetInstance<IOcrProvider>(); + if (ocrProvider == null) + { + return false; + } + var ocrResult = Task.Run(async () => await ocrProvider.DoOcrAsync(surface)).Result; - if (!ocrResult.HasContent) return false; + if (!ocrResult.HasContent) + { + return false; + } captureDetails.OcrInformation = ocrResult; From d602433c535dcb34dd1edfbffd2b6a0927e35b9d Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Tue, 21 Jul 2020 12:56:02 +0200 Subject: [PATCH 047/232] Added additional guards and a configuration for the Win10 plugin, which disables the OCR by default. --- GreenshotPicasaPlugin/PicasaConfiguration.cs | 12 ++++++------ GreenshotPlugin/Core/AbstractProcessor.cs | 2 +- .../Processors/Win10OcrProcessor.cs | 13 ++++++++++++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/GreenshotPicasaPlugin/PicasaConfiguration.cs b/GreenshotPicasaPlugin/PicasaConfiguration.cs index eb8eb7100..a1372f598 100644 --- a/GreenshotPicasaPlugin/PicasaConfiguration.cs +++ b/GreenshotPicasaPlugin/PicasaConfiguration.cs @@ -1,19 +1,19 @@ /* * A Picasa Plugin for Greenshot * Copyright (C) 2011 Francis Noel - * + * * For more information see: http://getgreenshot.org/ - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -42,13 +42,13 @@ namespace GreenshotPicasaPlugin { set; } - [IniProperty("UploadUser", Description = "The picasa user to upload to", DefaultValue = "default")] + [IniProperty("UploadUser", Description = "The Picasa user to upload to", DefaultValue = "default")] public string UploadUser { get; set; } - [IniProperty("UploadAlbum", Description = "The picasa album to upload to", DefaultValue = "default")] + [IniProperty("UploadAlbum", Description = "The Picasa album to upload to", DefaultValue = "default")] public string UploadAlbum { get; set; diff --git a/GreenshotPlugin/Core/AbstractProcessor.cs b/GreenshotPlugin/Core/AbstractProcessor.cs index 5e82b1d23..1dce1ab16 100644 --- a/GreenshotPlugin/Core/AbstractProcessor.cs +++ b/GreenshotPlugin/Core/AbstractProcessor.cs @@ -32,7 +32,7 @@ namespace GreenshotPlugin.Core { return 1; } if (Priority == other.Priority) { - return Description.CompareTo(other.Description); + return string.Compare(Description, other.Description, StringComparison.Ordinal); } return Priority - other.Priority; } diff --git a/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs b/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs index 3ed89b95d..6cab7b81d 100644 --- a/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs +++ b/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs @@ -21,6 +21,7 @@ using System.Threading.Tasks; using GreenshotPlugin.Core; +using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; @@ -29,13 +30,23 @@ namespace GreenshotWin10Plugin.Processors { /// This processor processes a capture to see if there is text on it /// </summary> public class Win10OcrProcessor : AbstractProcessor { + private static readonly Win10Configuration Win10Configuration = IniConfig.GetIniSection<Win10Configuration>(); public override string Designation => "Windows10OcrProcessor"; public override string Description => Designation; public override bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails) { - if (captureDetails.OcrInformation != null) + if (!Win10Configuration.AlwaysRunOCROnCapture) + { + return false; + } + + if (surface == null) + { + return false; + } + if (captureDetails == null || captureDetails.OcrInformation != null) { return false; } From 1f7e4e296250b085156e3438fff38e389c676bf2 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Tue, 21 Jul 2020 12:58:58 +0200 Subject: [PATCH 048/232] Forgot to add the new class... Silly me.... --- GreenshotWin10Plugin/Win10Configuration.cs | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 GreenshotWin10Plugin/Win10Configuration.cs diff --git a/GreenshotWin10Plugin/Win10Configuration.cs b/GreenshotWin10Plugin/Win10Configuration.cs new file mode 100644 index 000000000..642296e94 --- /dev/null +++ b/GreenshotWin10Plugin/Win10Configuration.cs @@ -0,0 +1,33 @@ +/* + * A Picasa Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using GreenshotPlugin.IniFile; + +namespace GreenshotWin10Plugin +{ + /// <summary> + /// Description of Win10Configuration. + /// </summary> + [IniSection("Win10", Description = "Greenshot Win10 Plugin configuration")] + public class Win10Configuration : IniSection { + [IniProperty("AlwaysRunOCROnCapture", Description="Determines if OCR is run automatically on every capture", DefaultValue="False")] + public bool AlwaysRunOCROnCapture { get; set; } + } +} From 90d1e114e0346ce500f80edb5617f2b0946eca57 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Wed, 29 Jul 2020 10:34:52 +0200 Subject: [PATCH 049/232] BUG-2644: Fixed a NPRE when exporting to Powerpoint when it's not running yet. --- .../OfficeExport/PowerpointExporter.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs b/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs index 237fea1f9..a9d5632c4 100644 --- a/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs +++ b/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs @@ -1,19 +1,19 @@ // Greenshot - a free and open source screenshot tool // Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom -// +// // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 1 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. @@ -243,7 +243,7 @@ namespace GreenshotOfficePlugin.OfficeExport // Ignore, probably no PowerPoint running return null; } - if (powerPointApplication.ComObject != null) + if (powerPointApplication?.ComObject != null) { InitializeVariables(powerPointApplication); } From 80c262d47f721af828a3f18c07054789a0863c74 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Thu, 6 Aug 2020 16:52:11 +0200 Subject: [PATCH 050/232] Improvement for #220, the size of the font is calculated according to the size of the counter --- Greenshot/Drawing/StepLabelContainer.cs | 39 ++++++------------------- 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/Greenshot/Drawing/StepLabelContainer.cs b/Greenshot/Drawing/StepLabelContainer.cs index 26510e515..b750fcb20 100644 --- a/Greenshot/Drawing/StepLabelContainer.cs +++ b/Greenshot/Drawing/StepLabelContainer.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -40,9 +40,7 @@ namespace Greenshot.Drawing { private readonly bool _drawAsRectangle = false; - private float fontSize = 16; - - public StepLabelContainer(Surface parent) : base(parent) { + public StepLabelContainer(Surface parent) : base(parent) { parent.AddStepLabel(this); InitContent(); Init(); @@ -168,26 +166,6 @@ namespace Greenshot.Drawing { return true; } - /// <summary> - /// Make sure the size of the font is scaled - /// </summary> - /// <param name="matrix"></param> - public override void Transform(Matrix matrix) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - int widthBefore = rect.Width; - int heightBefore = rect.Height; - - // Transform this container - base.Transform(matrix); - rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - - int widthAfter = rect.Width; - int heightAfter = rect.Height; - float factor = ((float)widthAfter / widthBefore + (float)heightAfter / heightBefore) / 2; - - fontSize *= factor; - } - /// <summary> /// Override the parent, calculate the label number, than draw /// </summary> @@ -209,6 +187,7 @@ namespace Greenshot.Drawing { EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false); } + float fontSize = Math.Min(Width,Height) / 1.4f; using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name); using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel); TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font); @@ -219,9 +198,9 @@ namespace Greenshot.Drawing { Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); if (_drawAsRectangle) { return RectangleContainer.RectangleClickableAt(rect, 0, fillColor, x, y); - } else { - return EllipseContainer.EllipseClickableAt(rect, 0, fillColor, x, y); } - } + + return EllipseContainer.EllipseClickableAt(rect, 0, fillColor, x, y); + } } } From ca0095491b65b5b6b76759ace0d4e9c750afe4dd Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Thu, 6 Aug 2020 17:02:26 +0200 Subject: [PATCH 051/232] Fixed an issue which was described in #217, also did some hardening that it doesn't happen on other locations in the TextContainer. --- Greenshot/Drawing/TextContainer.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index 939dd3de6..ddfb2918e 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -158,9 +158,15 @@ namespace Greenshot.Drawing protected override void SwitchParent(Surface newParent) { - _parent.SizeChanged -= Parent_SizeChanged; + if (_parent != null) + { + _parent.SizeChanged -= Parent_SizeChanged; + } base.SwitchParent(newParent); - _parent.SizeChanged += Parent_SizeChanged; + if (_parent != null) + { + _parent.SizeChanged += Parent_SizeChanged; + } } private void Parent_SizeChanged(object sender, EventArgs e) @@ -320,8 +326,12 @@ namespace Greenshot.Drawing private void HideTextBox() { - _parent.Focus(); + _parent?.Focus(); _textBox?.Hide(); + if (_parent == null) + { + return; + } _parent.KeysLocked = false; _parent.Controls.Remove(_textBox); } From 7fd013b6c8598bc297d76638d6e2cbeb8463d6be Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Thu, 6 Aug 2020 21:19:50 +0200 Subject: [PATCH 052/232] Release/1.3 (#224) * Update Italian language for 1.3 installer * Update Italian language for 1.3 --- .../installer/language-installer-it-IT.xml | 14 ++ Greenshot/Languages/language-it-IT.xml | 147 +++++++++--------- 2 files changed, 84 insertions(+), 77 deletions(-) create mode 100644 Greenshot/Languages/installer/language-installer-it-IT.xml diff --git a/Greenshot/Languages/installer/language-installer-it-IT.xml b/Greenshot/Languages/installer/language-installer-it-IT.xml new file mode 100644 index 000000000..7aa745871 --- /dev/null +++ b/Greenshot/Languages/installer/language-installer-it-IT.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<language description="Italian" ietf="it-IT" version="1.0.0" languagegroup="1"> + <resources> + <resource name="startup">Esegui {#ExeName} all'avvio di Windows</resource> + <resource name="startgreenshot">Esegui {#ExeName}</resource> + <resource name="jira">Plugin Jira</resource> + <resource name="confluence">Plugin Confluence</resource> + <resource name="externalcommand">Apri con comando esterno plugin</resource> + <resource name="ocr">Plugin OCR (richiede Microsoft Office Document Imaging (MODI))</resource> + <resource name="imgur">Plugin Imgur (vedi: http://imgur.com)</resource> + <resource name="language">Lingue aggiuntive</resource> + <resource name="optimize">Ottimizzazione prestazioni (può richiedere tempo).</resource> + </resources> +</language> \ No newline at end of file diff --git a/Greenshot/Languages/language-it-IT.xml b/Greenshot/Languages/language-it-IT.xml index bb553e735..cef5e4705 100644 --- a/Greenshot/Languages/language-it-IT.xml +++ b/Greenshot/Languages/language-it-IT.xml @@ -8,8 +8,7 @@ <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom Greenshot viene fornito SENZA ALCUNA GARANZIA. Questo software è garuitio", e potete ri-distribuirlo secondo certe condizioni. -Dettagli della General Public License GNU: - </resource> +Dettagli della General Public License GNU:</resource> <resource name="about_title">Notizie su Greenshot</resource> <resource name="about_translation">Traduzione in Italiano curata da bovirus e tonytogna</resource> <resource name="application_title">Greenshot - Uno straordinario strumento per copiare immagini dallo schermo</resource> @@ -20,19 +19,15 @@ La buona notizia è che puoi aiutarci ad eliminarlo segnalandoci l'errore. Visita la pagina internet qui sotto, crea una nuova segnalazione errore e copia nella descrizione il contenuto preso dall'area di testo. -Aggiungi un riepilogo significativo e includi qualsiasi informazione tu consideri possa esserci d'aiuto per -risolvere il problema. -Inoltre apprezzeremo molto, se prima di inserire la segnaalzione, controllassi se esiste già una -segnalazione per questo tipo di errore (puoi usare la ricerca) -Grazie :) - </resource> +Aggiungi un riepilogo significativo e includi qualsiasi informazione tu consideri possa esserci d'aiuto per risolvere il problema. +Inoltre apprezzeremo molto, se prima di inserire la segnalazione, controllassi se esiste già una segnalazione per questo tipo di errore (puoi usare la ricerca) +Grazie :)</resource> <resource name="bugreport_title">Errore</resource> <resource name="CANCEL">Annulla</resource> <resource name="clipboard_error">Si è verificato un errore inaspettato durante la scrittura negli Appunti. </resource> <resource name="clipboard_noimage">Nessuna immagine sugli Appunti.</resource> - <resource name="clipboard_inuse">Greenshot non è riuscito a scrivere negli Appunti poichè il processo {0} teneva - l'accesso bloccato. + <resource name="clipboard_inuse">Greenshot non è riuscito a scrivere negli Appunti poiché il processo {0} teneva l'accesso bloccato. </resource> <resource name="ClipboardFormat.BITMAP">BMO (Bitmap Windows)</resource> <resource name="ClipboardFormat.DIB">DIB (Device independent Bitmap)</resource> @@ -73,9 +68,9 @@ Controlla i permessi di accesso per '{0}'.</resource> <resource name="contextmenu_help">Aiuto</resource> <resource name="contextmenu_openfile">Apri immagine da file</resource> <resource name="contextmenu_openrecentcapture">Apri ultimo percorso cattura</resource> - <resource name="contextmenu_quicksettings">Imposatzioni rapide</resource> + <resource name="contextmenu_quicksettings">Impostazioni rapide</resource> <resource name="contextmenu_settings">Impostazioni...</resource> - <resource name="destination_exportfailed">Errori durente l'esportazione in {0}. Riprova.</resource> + <resource name="destination_exportfailed">Errori durante l'esportazione in {0}. Riprova.</resource> <resource name="editor_align_bottom">In basso</resource> <resource name="editor_align_center">Centro</resource> <resource name="editor_align_horizontal">Allineamento orizzontale</resource> @@ -96,14 +91,14 @@ Controlla i permessi di accesso per '{0}'.</resource> <resource name="editor_bold">Grassetto</resource> <resource name="editor_border">Bordi</resource> <resource name="editor_brightness">Luminosità</resource> - <resource name="editor_cancel">Cancella</resource> - <resource name="editor_clipboardfailed">Errore durante l'accesso agli appunti. Ritenta nuovamente.</resource> + <resource name="editor_cancel">Annulla</resource> + <resource name="editor_clipboardfailed">Errore durante l'accesso agli Appunti. Ritenta nuovamente.</resource> <resource name="editor_close">Chiudi</resource> - <resource name="editor_close_on_save">Desideri salvare l'immagine?</resource> - <resource name="editor_close_on_save_title">Salva l'immagine?</resource> + <resource name="editor_close_on_save">Vuoi salvare l'immagine?</resource> + <resource name="editor_close_on_save_title">Vuoi salvare l'immagine?</resource> <resource name="editor_confirm">Conferma</resource> - <resource name="editor_copyimagetoclipboard">Copia immagine sugli appunti</resource> - <resource name="editor_copypathtoclipboard">Copia percorso sugli appunti</resource> + <resource name="editor_copyimagetoclipboard">Copia immagine negli Appunti</resource> + <resource name="editor_copypathtoclipboard">Copia percorso negli appunti</resource> <resource name="editor_copytoclipboard">Copia</resource> <resource name="editor_crop">Ritaglia (C)</resource> <resource name="editor_cursortool">Strumento di selezione (ESC)</resource> @@ -113,15 +108,15 @@ Controlla i permessi di accesso per '{0}'.</resource> <resource name="editor_downtobottom">Giù fino in fondo</resource> <resource name="editor_drawarrow">Disegna freccia (A)</resource> <resource name="editor_drawellipse">Disegna ellisse (E)</resource> - <resource name="editor_drawfreehand">Disegna mano libera (F)</resource> + <resource name="editor_drawfreehand">Disegna a mano libera (F)</resource> <resource name="editor_drawhighlighter">Evidenzia (H)</resource> <resource name="editor_drawline">Disegna linea (L)</resource> <resource name="editor_drawrectangle">Disegna rettangolo (R)</resource> - <resource name="editor_drawtextbox">Aggiungi casella di testo (T)</resource> + <resource name="editor_drawtextbox">Aggiungi casella testo (T)</resource> <resource name="editor_duplicate">Duplica elementi selezionati</resource> <resource name="editor_edit">Modifica</resource> <resource name="editor_effects">Effetti</resource> - <resource name="editor_email">E-Mail</resource> + <resource name="editor_email">Email</resource> <resource name="editor_file">File</resource> <resource name="editor_fontsize">Dimensioni</resource> <resource name="editor_forecolor">Colore linea</resource> @@ -130,7 +125,7 @@ Controlla i permessi di accesso per '{0}'.</resource> <resource name="editor_highlight_grayscale">Scala di grigi</resource> <resource name="editor_highlight_magnify">Ingrandisci</resource> <resource name="editor_highlight_mode">Modalità evidenziazione</resource> - <resource name="editor_highlight_text">Evidenzia il testo</resource> + <resource name="editor_highlight_text">Evidenzia testo</resource> <resource name="editor_image_shadow">Aggiungi ombra</resource> <resource name="editor_imagesaved">Immagine salvata su {0}.</resource> <resource name="editor_insertwindow">Inserisci finestra</resource> @@ -142,7 +137,7 @@ Controlla i permessi di accesso per '{0}'.</resource> <resource name="editor_obfuscate">Offusca (O)</resource> <resource name="editor_obfuscate_blur">Sfuma</resource> <resource name="editor_obfuscate_mode">Modalità di offuscamento</resource> - <resource name="editor_obfuscate_pixelize">Offusca/ pixelize</resource> + <resource name="editor_obfuscate_pixelize">Offusca/pixelizza</resource> <resource name="editor_object">Oggetti</resource> <resource name="editor_opendirinexplorer">Apri cartella su Windows Explorer</resource> <resource name="editor_pastefromclipboard">Incolla</resource> @@ -150,9 +145,9 @@ Controlla i permessi di accesso per '{0}'.</resource> <resource name="editor_preview_quality">Qualità anteprima</resource> <resource name="editor_print">Stampa</resource> <resource name="editor_redo">Ripeti azione {0}</resource> - <resource name="editor_resetsize">Azzera Dimensione</resource> + <resource name="editor_resetsize">Azzera dimensione</resource> <resource name="editor_resize_percent">Percentuale</resource> - <resource name="editor_resize_pixel">Pixels</resource> + <resource name="editor_resize_pixel">Pixel</resource> <resource name="editor_rotateccw">Ruota senso antiorario</resource> <resource name="editor_rotatecw">Ruota senso orario</resource> <resource name="editor_save">Salva</resource> @@ -162,9 +157,9 @@ Controlla i permessi di accesso per '{0}'.</resource> <resource name="editor_senttoprinter">Stampa inviata a '{0}'.</resource> <resource name="editor_shadow">Ombra</resource> <resource name="editor_image_shadow">Ombra</resource> - <resource name="editor_storedtoclipboard">Immagine posta negli appunti (clipboard).</resource> + <resource name="editor_storedtoclipboard">Immagine copiata negli Appunti.</resource> <resource name="editor_thickness">Spessore linea</resource> - <resource name="editor_title">Gestione Immagini di Greenshot</resource> + <resource name="editor_title">Gestione immagini di Greenshot</resource> <resource name="editor_torn_edge">Bordi strappati</resource> <resource name="editor_undo">Annulla azione {0}</resource> <resource name="editor_uponelevel">Su di un livello</resource> @@ -176,19 +171,16 @@ Controlla i permessi di accesso per '{0}'.</resource> <resource name="error_multipleinstances">È già attiva un'istanza di Greenshot.</resource> <resource name="error_nowriteaccess"> Non è possibile salvare il file in {0}. -Verifica l'accesso in scrittura nel percorso di salvataggio. - </resource> +Verifica l'accesso in scrittura nel percorso di salvataggio.</resource> <resource name="error_openfile">Il file "{0}" non può essere aperto.</resource> <resource name="error_openlink">Impossibile aprire il collegamento '{0}'.</resource> <resource name="error_save">Impossibile salvare l'immagine. -È necessario trovare una destinazione valida. - </resource> +È necessario trovare una destinazione valida.</resource> <resource name="error_save_invalid_chars">Il nome file o cartella generato non è valido. -Correggi la maschera noem file e riprova. - </resource> +Correggi la maschera noem file e riprova.</resource> <resource name="expertsettings">Utente esperto</resource> - <resource name="expertsettings_autoreducecolors">Crea una immagine a 8bit se i colori sono meno di 256 el'immagine ha > 8 bit</resource> - <resource name="expertsettings_checkunstableupdates">Controlla disponibilità Aggiornamenti versioni beta</resource> + <resource name="expertsettings_autoreducecolors">Crea una immagine a 8bit se i colori sono meno di 256 e l'immagine ha > 8 bit</resource> + <resource name="expertsettings_checkunstableupdates">Controlla disponibilità aggiornamenti versioni beta</resource> <resource name="expertsettings_clipboardformats">Formati degli Appunti</resource> <resource name="expertsettings_counter">Numero per var. ${NUM} nel modello del nome file</resource> <resource name="expertsettings_enableexpert">Sono consapevole di ciò che sto facendo!</resource> @@ -200,7 +192,7 @@ Correggi la maschera noem file e riprova. <resource name="expertsettings_thumbnailpreview">Visualizza anteprima finestra nel menù di contesto (Vista e Windows 7)</resource> <resource name="exported_to">Esportato in: {0}</resource> <resource name="exported_to_error">Si è verificato un errore durante l'esportazione in {0}:</resource> - <resource name="help_title">Guida di Greenshot</resource> + <resource name="help_title">Guida in linea Greenshot</resource> <resource name="hotkeys">Scorciatoie tastiera</resource> <resource name="jpegqualitydialog_choosejpegquality">Scegli la qualità dell'immagine JPEG.</resource> <resource name="OK">OK</resource> @@ -218,7 +210,7 @@ Correggi la maschera noem file e riprova. <resource name="printoptions_printmonochrome">Forza stampa in bianco e nero</resource> <resource name="printoptions_timestamp">Aggiungi data/ora nel piè di pagina</resource> <resource name="printoptions_title">Opzioni di stampa di Greenshot</resource> - <resource name="qualitydialog_dontaskagain">Save come qualità predefinita e non chiedere più</resource> + <resource name="qualitydialog_dontaskagain">Salva come qualità predefinita e non chiedere più</resource> <resource name="qualitydialog_title">Qualità di Greenshot</resource> <resource name="quicksettings_destination_file">Salva direttamente (usando le impostazioni preferite file destinazione)</resource> <resource name="settings_alwaysshowprintoptionsdialog">Visualizza scelta opzioni di stampa ogni volta che stampi un'immagine</resource> @@ -233,14 +225,14 @@ Correggi la maschera noem file e riprova. <resource name="settings_copypathtoclipboard">Ogni volta che una immagine viene salvata copia percorso file negli Appunti</resource> <resource name="settings_destination">Destinazione immagine</resource> <resource name="settings_destination_clipboard">Copia negli Appunti</resource> - <resource name="settings_destination_editor">Apri in Gest. Immagini</resource> + <resource name="settings_destination_editor">Apri in Gestione immagini</resource> <resource name="settings_destination_email">Email</resource> - <resource name="settings_destination_file">Salva direttamente (usando le impostazioni esposte qui sotto)</resource> + <resource name="settings_destination_file">Salva direttamente (usando impostazioni indicate qui sotto)</resource> <resource name="settings_destination_fileas">Salva come (visualizzando le scelte)</resource> - <resource name="settings_destination_picker">Scegli la destinazione dinamicamente</resource> + <resource name="settings_destination_picker">Scegli dinamicamente la destinazione</resource> <resource name="settings_destination_printer">Invia alla stampante</resource> <resource name="settings_editor">Gestione immagini</resource> - <resource name="settings_filenamepattern">Modello nome fFile</resource> + <resource name="settings_filenamepattern">Modello nome file</resource> <resource name="settings_general">Generali</resource> <resource name="settings_iecapture">Cattura Internet Explorer</resource> <resource name="settings_jpegquality">Qualità JPEG</resource> @@ -250,7 +242,7 @@ Correggi la maschera noem file e riprova. ${YYYY} anno, 4 numeri ${MM} mese, 2 numeri ${DD} giorno, 2 numeri -${hh} ora, 2 nuemri +${hh} ora, 2 numeri ${mm} minuti, 2 numeri ${ss} secondi, 2 numeri ${NUM} numero progressivo, 6 numeri @@ -262,12 +254,11 @@ ${hostname} Nome PC Puoi anche chiedere a Greenshot di creare le cartelle dinamicamente, usando la barra rovesciata (\) per separare cartelle e nome file. Esempio modello: ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} -creerà nelal destinazione predefinita una cartella con il giorno corrente , es: 2008-06-29. +creerà nella destinazione predefinita una cartella con il giorno attuale, es: 2008-06-29. Il nome del file di immagine sarà basato sull'orario attuale, es: 11_58_32 (più l'estensione definita nelle -impostazioni) - </resource> +impostazioni)</resource> <resource name="settings_network">Rete e aggiornamenti</resource> - <resource name="settings_output">Destinazionione</resource> + <resource name="settings_output">Destinazione</resource> <resource name="settings_playsound">Riproduci suono fotocamera</resource> <resource name="settings_plugins">Componenti Aggiuntivi</resource> <resource name="settings_plugins_createdby">Creato da</resource> @@ -289,7 +280,7 @@ impostazioni) <resource name="settings_tooltip_filenamepattern">Modello usato per generare il nome file in fase di salvataggio delle immagini</resource> <resource name="settings_tooltip_language">Lingua dell'interfaccia utente di Greenshot (richiede il riavvio)</resource> <resource name="settings_tooltip_primaryimageformat">Formato immagine predefinito</resource> - <resource name="settings_tooltip_registerhotkeys">Definisce se le scorciatoie Stamp, Ctrl + Stamp, Alt + Stamp sono riservate per uso globale di Greenshot dall'avvio del programma fino a quando viene chiuso.</resource> + <resource name="settings_tooltip_registerhotkeys">Definisce se le scorciatoie 'Stamp', 'Ctrl+Stamp', 'Alt+Stamp' sono riservate per uso globale di Greenshot dall'avvio del programma fino a quando viene chiuso.</resource> <resource name="settings_tooltip_storagelocation">Percorso predefinito dove le immagini catturate vengono salvate (lascia vuoto per salvare sul desktop)</resource> <resource name="settings_usedefaultproxy">Usa proxy predefinito del sistema</resource> <resource name="settings_visualization">Effetti</resource> @@ -301,40 +292,42 @@ impostazioni) <resource name="wait_ie_capture">Attendi finchè viene completata la cattura della pagina di Internet Explorer...</resource> <resource name="warning">Attenzione</resource> <resource name="warning_hotkeys">La registrazione della/e scorciatoie di tastiera "{0}" non è andata a buon fine. -Questo problema è causato probabilmente da un altro software che richiede l'uso delle stesse scorciatoie di -tastiera. +Questo problema è causato probabilmente da un altro software che richiede l'uso delle stesse scorciatoie di tastiera. E' possibile però variare le impostazioni delle scorciatoie, oppure disattivare il software. -In alternativa alle scorciatoie di tastiera, tutte le funzioni di Greenshot sono comunque disponibili dal -menù visualizzabile con il tasto destro del mouse sull'icona G nella barra. - </resource> +In alternativa alle scorciatoie di tastiera, tutte le funzioni di Greenshot sono comunque disponibili dal menù visualizzabile con il tasto destro del mouse sull'icona G nella barra.</resource> - <resource name="WindowCaptureModes.Aero">Usa colori personalizzati</resource> - <resource name="WindowCaptureModes.AeroTransparent">Mantieni trasparenza</resource> - <resource name="WindowCaptureModes.Auto">Automaticamente</resource> - <resource name="WindowCaptureModes.GDI">Usa i colori predefiniti</resource> + <resource name="WindowCaptureModes.Aero">Usa colori personalizzati</resource> + <resource name="WindowCaptureModes.AeroTransparent">Mantieni trasparenza</resource> + <resource name="WindowCaptureModes.Auto">Automaticamente</resource> + <resource name="WindowCaptureModes.GDI">Usa i colori predefiniti</resource> <resource name="WindowCaptureModes.Screen">Come visualizzata</resource> - <resource name="settings_iconsize">Dimensione icona</resource> - <resource name="editor_counter">Aggiungi conteggio</resource> - <resource name="editor_speechbubble">Aggiungi nuvoletta</resource> - <resource name="editor_resize">Ridimensiona</resource> - <resource name="editor_resize_settings">Impostazioni ridimensionamento</resource> - <resource name="editor_resize_aspectratio">Mantieni il rapporto dimensioni</resource> - <resource name="editor_resize_width">Larghezza</resource> - <resource name="editor_resize_height">Altezza</resource> - <resource name="editor_dropshadow_darkness">Intensità ombra</resource> - <resource name="editor_dropshadow_offset">Offset ombra</resource> - <resource name="editor_dropshadow_settings">Impostazioni Ombreggiatura</resource> - <resource name="editor_dropshadow_thickness">Spessore ombra</resource> - <resource name="editor_tornedge_horizontaltoothrange">Intervallo orizzontale dentellatura</resource> - <resource name="editor_tornedge_settings">Impostazioni Bordi Strappati</resource> - <resource name="editor_tornedge_toothsize">Dimensione dentellatura</resource> - <resource name="editor_tornedge_verticaltoothrange">Intervallo verticale dentellatura</resource> - <resource name="editor_tornedge_left">Strappo lato sinistro</resource> - <resource name="editor_tornedge_right">Strappo lato destro</resource> - <resource name="editor_tornedge_top">Strappo lato in alto</resource> - <resource name="editor_tornedge_bottom">Strappo lato in basso</resource> - <resource name="editor_tornedge_shadow">Genera ombra</resource> + <!-- 1.2 --> + <resource name="editor_dropshadow_darkness">Intensità ombra</resource> + <resource name="editor_dropshadow_offset">Offset ombra</resource> + <resource name="editor_dropshadow_settings">Impostazioni ombreggiatura</resource> + <resource name="editor_dropshadow_thickness">Spessore ombra</resource> + + <resource name="editor_tornedge_horizontaltoothrange">Intervallo orizzontale dentellatura</resource> + <resource name="editor_tornedge_settings">Impostazioni bordi strappati</resource> + <resource name="editor_tornedge_toothsize">Dimensione dentellatura</resource> + <resource name="editor_tornedge_verticaltoothrange">Intervallo verticale dentellatura</resource> + <resource name="editor_tornedge_left">Strappo lato sinistro</resource> + <resource name="editor_tornedge_right">Strappo lato destro</resource> + <resource name="editor_tornedge_top">Strappo lato in alto</resource> + <resource name="editor_tornedge_bottom">Strappo lato in basso</resource> + <resource name="editor_tornedge_shadow">Genera ombra</resource> + + <resource name="editor_counter">Aggiungi conteggio</resource> + <resource name="editor_speechbubble">Aggiungi nuvoletta</resource> + + <resource name="editor_resize">Ridimensiona</resource> + <resource name="editor_resize_settings">Impostazioni ridimensionamento</resource> + <resource name="editor_resize_aspectratio">Mantieni rapporto dimensioni</resource> + <resource name="editor_resize_width">Larghezza</resource> + <resource name="editor_resize_height">Altezza</resource> + <resource name="settings_iconsize">Dimensione icona</resource> + </resources> </language> From 926855cd70b1dc065a3cc2124a88fa43f0ceb20e Mon Sep 17 00:00:00 2001 From: Peter F <github@peterfab.com> Date: Thu, 6 Aug 2020 15:27:39 -0400 Subject: [PATCH 053/232] Add placeholder for random alphanumerics in filename (#216) --- Greenshot/Languages/language-en-US.xml | 1 + GreenshotPlugin/Core/FilenameHelper.cs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/Greenshot/Languages/language-en-US.xml b/Greenshot/Languages/language-en-US.xml index f2f2e1137..319871fa4 100644 --- a/Greenshot/Languages/language-en-US.xml +++ b/Greenshot/Languages/language-en-US.xml @@ -232,6 +232,7 @@ ${hh} hour, 2 digits ${mm} minute, 2 digits ${ss} second, 2 digits ${NUM} incrementing number, 6 digits +${RRR...} random alphanumerics, same length as 'R's ${title} Window title ${user} Windows user ${domain} Windows domain diff --git a/GreenshotPlugin/Core/FilenameHelper.cs b/GreenshotPlugin/Core/FilenameHelper.cs index 47987163f..23fdbd9b4 100644 --- a/GreenshotPlugin/Core/FilenameHelper.cs +++ b/GreenshotPlugin/Core/FilenameHelper.cs @@ -44,6 +44,8 @@ namespace GreenshotPlugin.Core { private const int MaxTitleLength = 80; private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>(); private const string UnsafeReplacement = "_"; + private static readonly Random RandomNumberGen = new Random(); + private static readonly Regex RandRegexp = new Regex("^R+$", RegexOptions.Compiled); /// <summary> /// Remove invalid characters from the fully qualified filename @@ -160,6 +162,7 @@ namespace GreenshotPlugin.Core { string replaceValue = string.Empty; string variable = match.Groups["variable"].Value; string parameters = match.Groups["parameters"].Value; + string randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; if (parameters.Length > 0) { string[] parms = SplitRegexp.Split(parameters); @@ -241,6 +244,10 @@ namespace GreenshotPlugin.Core { if (filenameSafeMode) { replaceValue = MakePathSafe(replaceValue); } + } else if (RandRegexp.IsMatch(variable)) { + for (int i = 0; i < variable.Length; i++) { + replaceValue += randomChars[RandomNumberGen.Next(randomChars.Length)]; + } } else { // Handle other variables // Default use "now" for the capture take´n From f159a871ca191360fe7afb4c695d6eea19f89d0f Mon Sep 17 00:00:00 2001 From: jklingen <jklingen@users.noreply.github.com> Date: Thu, 6 Aug 2020 21:29:55 +0200 Subject: [PATCH 054/232] Propagate DPI Changes down to Drawable Containers and Adorners and Resize Grippers Accordingly (#200) * Propagate DPI Changes down to Drawable Containers and Adorners and Resize Grippers Accordingly * Make Grippers Slightly Larger * Add White Border to Grippers for Better Contrast on Dark Backgrounds --- Greenshot/Drawing/Adorners/AbstractAdorner.cs | 13 +- Greenshot/Drawing/Adorners/MoveAdorner.cs | 6 +- Greenshot/Drawing/Adorners/ResizeAdorner.cs | 6 +- Greenshot/Drawing/Adorners/TargetAdorner.cs | 237 +++++++++--------- Greenshot/Drawing/DrawableContainer.cs | 12 + Greenshot/Drawing/DrawableContainerList.cs | 13 +- Greenshot/Drawing/Surface.cs | 11 + Greenshot/Forms/ImageEditorForm.cs | 2 + .../Interfaces/Drawing/Adorners/IAdorner.cs | 6 + .../Interfaces/Drawing/Container.cs | 7 + 10 files changed, 185 insertions(+), 128 deletions(-) diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs index 70a56f29e..f6032d62f 100644 --- a/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ b/Greenshot/Drawing/Adorners/AbstractAdorner.cs @@ -22,6 +22,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; +using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces.Drawing; using GreenshotPlugin.Interfaces.Drawing.Adorners; @@ -31,7 +32,8 @@ namespace Greenshot.Drawing.Adorners { public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE; - protected Size _size = new Size(4, 4); + private static readonly Size defaultSize = new Size(6, 6); + protected Size _size = defaultSize; public AbstractAdorner(IDrawableContainer owner) { @@ -139,6 +141,15 @@ namespace Greenshot.Drawing.Adorners } } + /// <summary> + /// Adjust UI elements to the supplied DPI settings + /// </summary> + /// <param name="dpi"></param> + public void AdjustToDpi(uint dpi) + { + _size = DpiHelper.ScaleWithDpi(defaultSize, dpi); + } + /// <summary> /// Draw the adorner /// </summary> diff --git a/Greenshot/Drawing/Adorners/MoveAdorner.cs b/Greenshot/Drawing/Adorners/MoveAdorner.cs index d07a25ef7..916d569f4 100644 --- a/Greenshot/Drawing/Adorners/MoveAdorner.cs +++ b/Greenshot/Drawing/Adorners/MoveAdorner.cs @@ -145,14 +145,12 @@ namespace Greenshot.Drawing.Adorners var bounds = BoundsOnSurface; GraphicsState state = targetGraphics.Save(); - targetGraphics.SmoothingMode = SmoothingMode.None; targetGraphics.CompositingMode = CompositingMode.SourceCopy; - targetGraphics.PixelOffsetMode = PixelOffsetMode.Half; - targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; try { - targetGraphics.FillRectangle(Brushes.Black, bounds.X, bounds.Y, bounds.Width, bounds.Height); + targetGraphics.FillRectangle(Brushes.Black, bounds); + targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); } catch { diff --git a/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/Greenshot/Drawing/Adorners/ResizeAdorner.cs index dce78b461..d624add48 100644 --- a/Greenshot/Drawing/Adorners/ResizeAdorner.cs +++ b/Greenshot/Drawing/Adorners/ResizeAdorner.cs @@ -172,12 +172,10 @@ namespace Greenshot.Drawing.Adorners var bounds = BoundsOnSurface; GraphicsState state = targetGraphics.Save(); - targetGraphics.SmoothingMode = SmoothingMode.None; targetGraphics.CompositingMode = CompositingMode.SourceCopy; - targetGraphics.PixelOffsetMode = PixelOffsetMode.Half; - targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; - targetGraphics.FillRectangle(Brushes.Black, bounds.X, bounds.Y, bounds.Width , bounds.Height); + targetGraphics.FillRectangle(Brushes.Black, bounds); + targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); targetGraphics.Restore(state); } } diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/Greenshot/Drawing/Adorners/TargetAdorner.cs index 67c01a533..542657c14 100644 --- a/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ b/Greenshot/Drawing/Adorners/TargetAdorner.cs @@ -1,118 +1,119 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Adorners -{ - /// <summary> - /// This implements the special "gripper" for the Speech-Bubble tail - /// </summary> - public class TargetAdorner : AbstractAdorner - { - - public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) - { - Location = location; - } - - /// <summary> - /// Handle the mouse down - /// </summary> - /// <param name="sender"></param> - /// <param name="mouseEventArgs"></param> - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.MOVING; - } - - /// <summary> - /// Handle the mouse move - /// </summary> - /// <param name="sender"></param> - /// <param name="mouseEventArgs"></param> - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.MOVING) - { - return; - } - - Owner.Invalidate(); - Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); - Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height); - // Check if gripper inside the parent (surface), if not we need to move it inside - // This was made for BUG-1682 - if (!imageBounds.Contains(newGripperLocation)) - { - if (newGripperLocation.X > imageBounds.Right) - { - newGripperLocation.X = imageBounds.Right - 5; - } - if (newGripperLocation.X < imageBounds.Left) - { - newGripperLocation.X = imageBounds.Left; - } - if (newGripperLocation.Y > imageBounds.Bottom) - { - newGripperLocation.Y = imageBounds.Bottom - 5; - } - if (newGripperLocation.Y < imageBounds.Top) - { - newGripperLocation.Y = imageBounds.Top; - } - } - - Location = newGripperLocation; - Owner.Invalidate(); - } - - /// <summary> - /// Draw the adorner - /// </summary> - /// <param name="paintEventArgs">PaintEventArgs</param> - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = BoundsOnSurface; - targetGraphics.FillRectangle(Brushes.Green, bounds.X, bounds.Y, bounds.Width, bounds.Height); - } - - /// <summary> - /// Made sure this adorner is transformed - /// </summary> - /// <param name="matrix">Matrix</param> - public override void Transform(Matrix matrix) - { - if (matrix == null) - { - return; - } - Point[] points = new[] { Location }; - matrix.TransformPoints(points); - Location = points[0]; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using GreenshotPlugin.Interfaces.Drawing; + +namespace Greenshot.Drawing.Adorners +{ + /// <summary> + /// This implements the special "gripper" for the Speech-Bubble tail + /// </summary> + public class TargetAdorner : AbstractAdorner + { + + public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) + { + Location = location; + } + + /// <summary> + /// Handle the mouse down + /// </summary> + /// <param name="sender"></param> + /// <param name="mouseEventArgs"></param> + public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) + { + EditStatus = EditStatus.MOVING; + } + + /// <summary> + /// Handle the mouse move + /// </summary> + /// <param name="sender"></param> + /// <param name="mouseEventArgs"></param> + public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) + { + if (EditStatus != EditStatus.MOVING) + { + return; + } + + Owner.Invalidate(); + Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); + Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height); + // Check if gripper inside the parent (surface), if not we need to move it inside + // This was made for BUG-1682 + if (!imageBounds.Contains(newGripperLocation)) + { + if (newGripperLocation.X > imageBounds.Right) + { + newGripperLocation.X = imageBounds.Right - 5; + } + if (newGripperLocation.X < imageBounds.Left) + { + newGripperLocation.X = imageBounds.Left; + } + if (newGripperLocation.Y > imageBounds.Bottom) + { + newGripperLocation.Y = imageBounds.Bottom - 5; + } + if (newGripperLocation.Y < imageBounds.Top) + { + newGripperLocation.Y = imageBounds.Top; + } + } + + Location = newGripperLocation; + Owner.Invalidate(); + } + + /// <summary> + /// Draw the adorner + /// </summary> + /// <param name="paintEventArgs">PaintEventArgs</param> + public override void Paint(PaintEventArgs paintEventArgs) + { + Graphics targetGraphics = paintEventArgs.Graphics; + + var bounds = BoundsOnSurface; + targetGraphics.FillRectangle(Brushes.Green, bounds); + targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); + } + + /// <summary> + /// Made sure this adorner is transformed + /// </summary> + /// <param name="matrix">Matrix</param> + public override void Transform(Matrix matrix) + { + if (matrix == null) + { + return; + } + Point[] points = new[] { Location }; + matrix.TransformPoints(points); + Location = points[0]; + } + } +} diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index 33339ee00..a85cee791 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -369,6 +369,18 @@ namespace Greenshot.Drawing Draw(graphics, renderMode); } + /// <summary> + /// Adjust UI elements to the supplied DPI settings + /// </summary> + /// <param name="dpi"></param> + public void AdjustToDpi(uint dpi) + { + foreach(var adorner in Adorners) + { + adorner.AdjustToDpi(dpi); + } + } + public virtual bool Contains(int x, int y) { return Bounds.Contains(x , y); } diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs index 3d200598e..666986002 100644 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ b/Greenshot/Drawing/DrawableContainerList.cs @@ -604,5 +604,16 @@ namespace Greenshot.Drawing { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(true); } - } + + /// <summary> + /// Adjust UI elements to the supplied DPI settings + /// </summary> + /// <param name="dpi"></param> + public void AdjustToDpi(uint dpi) + { + foreach (var drawableContainer in this) { + drawableContainer.AdjustToDpi(dpi); + } + } + } } diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index 6c89238f0..d7a4487fc 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -432,6 +432,17 @@ namespace Greenshot.Drawing /// </summary> public ICaptureDetails CaptureDetails { get; set; } + /// <summary> + /// Adjust UI elements to the supplied DPI settings + /// </summary> + /// <param name="dpi"></param> + public void AdjustToDpi(uint dpi) + { + foreach (var element in this._elements) { + element.AdjustToDpi(dpi); + } + } + /// <summary> /// Base Surface constructor /// </summary> diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index d397b8bc8..ab7d037f7 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -101,6 +101,8 @@ namespace Greenshot { destinationsToolStrip.ImageScalingSize = newSize; propertiesToolStrip.ImageScalingSize = newSize; propertiesToolStrip.MinimumSize = new Size(150, newSize.Height + 10); + + _surface.AdjustToDpi(dpi); } public ImageEditorForm(ISurface iSurface, bool outputMade) diff --git a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs b/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs index e35af2141..b8e087101 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs @@ -87,5 +87,11 @@ namespace GreenshotPlugin.Interfaces.Drawing.Adorners /// </summary> /// <param name="matrix">Matrix</param> void Transform(Matrix matrix); + + /// <summary> + /// Adjust UI elements to the supplied DPI settings + /// </summary> + /// <param name="dpi"></param> + void AdjustToDpi(uint dpi); } } diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/GreenshotPlugin/Interfaces/Drawing/Container.cs index f4065801a..c8d85bdd7 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Container.cs @@ -120,6 +120,12 @@ namespace GreenshotPlugin.Interfaces.Drawing /// Available adorners for the DrawableContainer /// </summary> IList<IAdorner> Adorners { get; } + + /// <summary> + /// Adjust UI elements to the supplied DPI settings + /// </summary> + /// <param name="dpi"></param> + void AdjustToDpi(uint dpi); } public interface IDrawableContainerList : IList<IDrawableContainer>, IDisposable @@ -167,6 +173,7 @@ namespace GreenshotPlugin.Interfaces.Drawing void PushElementsToBottom(IDrawableContainerList elements); void ShowContextMenu(MouseEventArgs e, ISurface surface); void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e); + void AdjustToDpi(uint dpi); } public interface ITextContainer : IDrawableContainer From 63a9df5844a2e0b1760805c790e9fa1fbfd8dad7 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Thu, 6 Aug 2020 22:00:59 +0200 Subject: [PATCH 055/232] Fixed two issues with the adorner resize, sometime the initial value wasn't set and also there were some drawing artifacts. Still needs testing though. --- Greenshot/Drawing/Adorners/AbstractAdorner.cs | 17 +++++----- Greenshot/Drawing/DrawableContainer.cs | 31 +++++++++---------- GreenshotPlugin/Core/DpiHelper.cs | 4 +++ .../Interfaces/Drawing/Adorners/IAdorner.cs | 15 ++++++--- .../Interfaces/Drawing/Container.cs | 10 +++--- 5 files changed, 42 insertions(+), 35 deletions(-) diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs index f6032d62f..ecf0ce53d 100644 --- a/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ b/Greenshot/Drawing/Adorners/AbstractAdorner.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -32,11 +32,12 @@ namespace Greenshot.Drawing.Adorners { public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE; - private static readonly Size defaultSize = new Size(6, 6); - protected Size _size = defaultSize; + private static readonly Size DefaultSize = new Size(6, 6); + protected Size _size; public AbstractAdorner(IDrawableContainer owner) { + _size = DpiHelper.ScaleWithDpi(DefaultSize, 0); Owner = owner; } @@ -144,10 +145,10 @@ namespace Greenshot.Drawing.Adorners /// <summary> /// Adjust UI elements to the supplied DPI settings /// </summary> - /// <param name="dpi"></param> + /// <param name="dpi">uint</param> public void AdjustToDpi(uint dpi) { - _size = DpiHelper.ScaleWithDpi(defaultSize, dpi); + _size = DpiHelper.ScaleWithDpi(DefaultSize, dpi); } /// <summary> diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index a85cee791..87b555914 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -32,6 +32,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; +using System.Linq; using System.Runtime.Serialization; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; @@ -205,10 +206,8 @@ namespace Greenshot.Drawing } public Size Size { - get { - return new Size(width, height); - } - set { + get => new Size(width, height); + set { width = value.Width; height = value.Height; } @@ -219,15 +218,9 @@ namespace Greenshot.Drawing /// </summary> [NonSerialized] private IList<IAdorner> _adorners = new List<IAdorner>(); - public IList<IAdorner> Adorners - { - get - { - return _adorners; - } - } + public IList<IAdorner> Adorners => _adorners; - [NonSerialized] + [NonSerialized] // will store current bounds of this DrawableContainer before starting a resize protected Rectangle _boundsBeforeResize = Rectangle.Empty; @@ -236,8 +229,8 @@ namespace Greenshot.Drawing protected RectangleF _boundsAfterResize = RectangleF.Empty; public Rectangle Bounds { - get { return GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); } - set { + get => GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + set { Left = Round(value.Left); Top = Round(value.Top); Width = Round(value.Width); @@ -279,8 +272,12 @@ namespace Greenshot.Drawing return new Rectangle(Point.Empty, _parent.Image.Size); } } - // Take a base safetymargin + // Take a base safety margin int lineThickness = 5; + + // add adorner size + lineThickness += Adorners.Max(adorner => Math.Max(adorner.Bounds.Width, adorner.Bounds.Height)); + if (HasField(FieldType.LINE_THICKNESS)) { lineThickness += GetFieldValueAsInt(FieldType.LINE_THICKNESS); } @@ -372,10 +369,10 @@ namespace Greenshot.Drawing /// <summary> /// Adjust UI elements to the supplied DPI settings /// </summary> - /// <param name="dpi"></param> + /// <param name="dpi">uint with dpi value</param> public void AdjustToDpi(uint dpi) { - foreach(var adorner in Adorners) + foreach(var adorner in Adorners) { adorner.AdjustToDpi(dpi); } diff --git a/GreenshotPlugin/Core/DpiHelper.cs b/GreenshotPlugin/Core/DpiHelper.cs index 2c67eb1b5..171cf19ee 100644 --- a/GreenshotPlugin/Core/DpiHelper.cs +++ b/GreenshotPlugin/Core/DpiHelper.cs @@ -35,6 +35,10 @@ namespace GreenshotPlugin.Core /// <returns>double</returns> public static float DpiScaleFactor(uint dpi) { + if (dpi == 0) + { + dpi = Dpi; + } return (float)dpi / DefaultScreenDpi; } diff --git a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs b/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs index b8e087101..5d729376c 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -32,6 +32,11 @@ namespace GreenshotPlugin.Interfaces.Drawing.Adorners /// </summary> bool IsActive { get; } + /// <summary> + /// These are the bounds of the adorner + /// </summary> + Rectangle Bounds { get; } + /// <summary> /// The current edit status, this is needed to locate the adorner to send events to /// </summary> @@ -44,7 +49,7 @@ namespace GreenshotPlugin.Interfaces.Drawing.Adorners /// <summary> /// Is the current point "over" the Adorner? - /// If this is the case, the + /// If this is the case, the /// </summary> /// <param name="point">Point to test</param> /// <returns>true if so</returns> diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/GreenshotPlugin/Interfaces/Drawing/Container.cs index c8d85bdd7..0044a0bb0 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Container.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -124,7 +124,7 @@ namespace GreenshotPlugin.Interfaces.Drawing /// <summary> /// Adjust UI elements to the supplied DPI settings /// </summary> - /// <param name="dpi"></param> + /// <param name="dpi">uint</param> void AdjustToDpi(uint dpi); } From 133438ab554c387477c0f606290bb810ea453fdd Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Thu, 6 Aug 2020 22:28:00 +0200 Subject: [PATCH 056/232] After work for #224 --- Greenshot/releases/innosetup/setup.iss | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index f15a578aa..f4b7cae5b 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -200,6 +200,7 @@ Name: de; MessagesFile: compiler:Languages\German.isl Name: es; MessagesFile: compiler:Languages\Spanish.isl Name: fi; MessagesFile: compiler:Languages\Finnish.isl Name: fr; MessagesFile: compiler:Languages\French.isl +Name: it; MessagesFile: compiler:Languages\Italian.isl Name: nl; MessagesFile: compiler:Languages\Dutch.isl Name: lt; MessagesFile: Languages\Latvian.isl Name: nn; MessagesFile: Languages\NorwegianNynorsk.isl @@ -277,6 +278,30 @@ fr.startgreenshot=Démarrer {#ExeName} fr.startup=Lancer {#ExeName} au démarrage de Windows fr.win10=Greffon Windows 10 +it.startup=Esegui {#ExeName} all''avvio di Windows +it.startgreenshot=Esegui {#ExeName} +it.jira=Plugin Jira +it.confluence=Plugin Confluence +it.externalcommand=Apri con comando esterno plugin +it.ocr=Plugin OCR (richiede Microsoft Office Document Imaging (MODI)) +it.imgur=Plugin Imgur (vedi: http://imgur.com) +it.language=Lingue aggiuntive +it.optimize=Ottimizzazione prestazioni (può richiedere tempo). +it.win10=Plugin Windows 10 + +lt.confluence=Confluence spraudnis +lt.default=${default} +lt.office=Microsoft Office spraudnis +lt.externalcommand=Pielāgotu darbību spraudnis +lt.imgur=Imgur spraudnis (Vairāk šeit: http://imgur.com) +lt.jira=Jira spraudnis +lt.language=Papildus valodas +lt.ocr=OCR spraudnis (nepieciešams Microsoft Office Document Imaging (MODI)) +lt.optimize=Uzlaboju veikstpēju, tas prasīs kādu laiciņu. +lt.startgreenshot=Palaist {#ExeName} +lt.startup=Palaist {#ExeName} uzsākot darbus +lt.win10=Windows 10 spraudnis + lt.confluence=Confluence spraudnis lt.default=${default} lt.office=Microsoft Office spraudnis From dd91c97cb85e380461b493158b32f25487df047f Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Fri, 7 Aug 2020 08:02:18 +0200 Subject: [PATCH 057/232] Small improvement for the translations in the installer [skip ci] --- Greenshot/releases/innosetup/setup.iss | 60 +++++++++++++------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index f4b7cae5b..8d2546a4e 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -214,32 +214,32 @@ Name: startup; Description: {cm:startup} [CustomMessages] -de.confluence=Confluence Plug-in -de.default=Standard installation -de.office=Microsoft Office Plug-in -de.externalcommand=Externes Kommando Plug-in -de.imgur=Imgur Plug-in (Siehe: http://imgur.com) -de.jira=Jira Plug-in -de.language=Zusätzliche Sprachen -de.ocr=OCR Plug-in (benötigt Microsoft Office Document Imaging (MODI)) -de.optimize=Optimierung der Leistung, kann etwas dauern. -de.startgreenshot={#ExeName} starten -de.startup={#ExeName} starten wenn Windows hochfährt -de.win10=Windows 10 Plug-in - en.confluence=Confluence plug-in en.default=Default installation -en.office=Microsoft Office plug-in en.externalcommand=Open with external command plug-in en.imgur=Imgur plug-in (See: http://imgur.com) en.jira=Jira plug-in en.language=Additional languages en.ocr=OCR plug-in (needs Microsoft Office Document Imaging (MODI)) +en.office=Microsoft Office plug-in en.optimize=Optimizing performance, this may take a while. en.startgreenshot=Start {#ExeName} en.startup=Start {#ExeName} with Windows start en.win10=Windows 10 plug-in +de.confluence=Confluence Plug-in +de.default=Standard installation +de.externalcommand=Externes Kommando Plug-in +de.imgur=Imgur Plug-in (Siehe: http://imgur.com) +de.jira=Jira Plug-in +de.language=Zusätzliche Sprachen +de.ocr=OCR Plug-in (benötigt Microsoft Office Document Imaging (MODI)) +de.office=Microsoft Office Plug-in +de.optimize=Optimierung der Leistung, kann etwas dauern. +de.startgreenshot={#ExeName} starten +de.startup={#ExeName} starten wenn Windows hochfährt +de.win10=Windows 10 Plug-in + es.confluence=Extensión para Confluence es.default=${default} es.externalcommand=Extensión para abrir con programas externos @@ -254,12 +254,12 @@ es.win10=Extensión para Windows 10 fi.confluence=Confluence-liitännäinen fi.default=${default} -fi.office=Microsoft-Office-liitännäinen fi.externalcommand=Avaa Ulkoinen komento-liitännäisellä fi.imgur=Imgur-liitännäinen (Katso: http://imgur.com) fi.jira=Jira-liitännäinen fi.language=Lisäkielet fi.ocr=OCR-liitännäinen (Tarvitaan: Microsoft Office Document Imaging (MODI)) +fi.office=Microsoft-Office-liitännäinen fi.optimize=Optimoidaan suorituskykyä, tämä voi kestää hetken. fi.startgreenshot=Käynnistä {#ExeName} fi.startup=Käynnistä {#ExeName} Windowsin käynnistyessä @@ -267,36 +267,38 @@ fi.win10=Windows 10-liitännäinen fr.confluence=Greffon Confluence fr.default=${default} -fr.office=Greffon Microsoft Office fr.externalcommand=Ouvrir avec le greffon de commande externe fr.imgur=Greffon Imgur (Voir: http://imgur.com) fr.jira=Greffon Jira fr.language=Langues additionnelles fr.ocr=Greffon OCR (nécessite Document Imaging de Microsoft Office [MODI]) +fr.office=Greffon Microsoft Office fr.optimize=Optimisation des performances, Ceci peut prendre un certain temps. fr.startgreenshot=Démarrer {#ExeName} fr.startup=Lancer {#ExeName} au démarrage de Windows fr.win10=Greffon Windows 10 -it.startup=Esegui {#ExeName} all''avvio di Windows -it.startgreenshot=Esegui {#ExeName} -it.jira=Plugin Jira it.confluence=Plugin Confluence +it.default=Installazione di default it.externalcommand=Apri con comando esterno plugin -it.ocr=Plugin OCR (richiede Microsoft Office Document Imaging (MODI)) it.imgur=Plugin Imgur (vedi: http://imgur.com) +it.jira=Plugin Jira it.language=Lingue aggiuntive +it.ocr=Plugin OCR (richiede Microsoft Office Document Imaging (MODI)) +it.office=Plugin Microsoft Office it.optimize=Ottimizzazione prestazioni (può richiedere tempo). +it.startgreenshot=Esegui {#ExeName} +it.startup=Esegui {#ExeName} all''avvio di Windows it.win10=Plugin Windows 10 lt.confluence=Confluence spraudnis lt.default=${default} -lt.office=Microsoft Office spraudnis lt.externalcommand=Pielāgotu darbību spraudnis lt.imgur=Imgur spraudnis (Vairāk šeit: http://imgur.com) lt.jira=Jira spraudnis lt.language=Papildus valodas lt.ocr=OCR spraudnis (nepieciešams Microsoft Office Document Imaging (MODI)) +lt.office=Microsoft Office spraudnis lt.optimize=Uzlaboju veikstpēju, tas prasīs kādu laiciņu. lt.startgreenshot=Palaist {#ExeName} lt.startup=Palaist {#ExeName} uzsākot darbus @@ -304,12 +306,12 @@ lt.win10=Windows 10 spraudnis lt.confluence=Confluence spraudnis lt.default=${default} -lt.office=Microsoft Office spraudnis lt.externalcommand=Pielāgotu darbību spraudnis lt.imgur=Imgur spraudnis (Vairāk šeit: http://imgur.com) lt.jira=Jira spraudnis lt.language=Papildus valodas lt.ocr=OCR spraudnis (nepieciešams Microsoft Office Document Imaging (MODI)) +lt.office=Microsoft Office spraudnis lt.optimize=Uzlaboju veikstpēju, tas prasīs kādu laiciņu. lt.startgreenshot=Palaist {#ExeName} lt.startup=Palaist {#ExeName} uzsākot darbus @@ -317,12 +319,12 @@ lt.win10=Windows 10 spraudnis nl.confluence=Confluence plug-in nl.default=Standaardinstallatie -nl.office=Microsoft Office plug-in nl.externalcommand=Openen met extern commando plug-in nl.imgur=Imgur plug-in (zie: http://imgur.com) nl.jira=Jira plug-in nl.language=Extra talen nl.ocr=OCR plug-in (vereist Microsoft Office Document Imaging (MODI)) +nl.office=Microsoft Office plug-in nl.optimize=Prestaties verbeteren, even geduld. nl.startgreenshot={#ExeName} starten nl.startup={#ExeName} automatisch starten met Windows @@ -330,12 +332,12 @@ nl.win10=Windows 10 plug-in nn.confluence=Confluence-tillegg nn.default=Default installation -nn.office=Microsoft Office Tillegg nn.externalcommand=Tillegg for å opne med ekstern kommando nn.imgur=Imgur-tillegg (sjå http://imgur.com) nn.jira=Jira-tillegg nn.language=Andre språk nn.ocr=OCR-tillegg (krev Microsoft Office Document Imaging (MODI)) +nn.office=Microsoft Office Tillegg nn.optimize=Optimaliserar ytelse, dette kan ta litt tid... nn.startgreenshot=Start {#ExeName} nn.startup=Start {#ExeName} når Windows startar @@ -343,12 +345,12 @@ nn.win10=Windows 10 Tillegg ru.confluence=Плагин Confluence ru.default=${default} -ru.office=Плагин Microsoft Office ru.externalcommand=Открыть с плагином с помощью внешней команды ru.imgur=Плагин Imgur (смотрите https://imgur.com/) ru.jira=Плагин Jira ru.language=Дополнительные языки ru.ocr=Плагин OCR (требуется Microsoft Office Document Imaging (MODI)) +ru.office=Плагин Microsoft Office ru.optimize=Идет оптимизация производительности, это может занять некоторое время. ru.startgreenshot=Запустить {#ExeName} ru.startup=Запускать {#ExeName} при старте Windows @@ -366,15 +368,15 @@ sr.startgreenshot=Покрени Гриншот sr.startup=Покрени програм са системом sr.win10=Прикључак за Windows 10 -sv.startup=Starta {#ExeName} med Windows -sv.startgreenshot=Starta {#ExeName} -sv.jira=Jira-insticksprogram sv.confluence=Confluence-insticksprogram sv.externalcommand=Öppna med externt kommando-insticksprogram -sv.ocr=OCR-insticksprogram (kräver Microsoft Office Document Imaging (MODI)) sv.imgur=Imgur-insticksprogram (Se: http://imgur.com) +sv.jira=Jira-insticksprogram sv.language=Ytterligare språk +sv.ocr=OCR-insticksprogram (kräver Microsoft Office Document Imaging (MODI)) sv.optimize=Optimerar prestanda, detta kan ta en stund. +sv.startgreenshot=Starta {#ExeName} +sv.startup=Starta {#ExeName} med Windows sv.win10=Windows 10-insticksprogram uk.confluence=Плагін Confluence From eb2e7261e3294832452e9e19a95104f74d3fea71 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Fri, 7 Aug 2020 09:40:33 +0200 Subject: [PATCH 058/232] Improvements for the translation possibilities in the installer, and some enhancements for italian as was suggested in #225 [skip ci] --- Greenshot/releases/innosetup/setup.iss | 143 ++++++++++++++++--------- 1 file changed, 95 insertions(+), 48 deletions(-) diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 8d2546a4e..57b171a7f 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -213,16 +213,58 @@ Name: uk; MessagesFile: compiler:Languages\Ukrainian.isl Name: startup; Description: {cm:startup} [CustomMessages] +;Language names in the original language +dexfranconia=Frängisch (Deutsch) +arSY=العربية +caCA=Català +csCZ=Ceština +daDK=Dansk +elGR=ελληνικά +esES=Español +etEE=Eesti +faIR=پارسی +fiFI=Suomi +frFR=Français +frQC=Français - Québec +heIL=עִבְרִית +huHU=Magyar +idID=Bahasa Indonesia +itIT=Italiano +jaJP=日本語 +kabDZ=Taqbaylit +koKR=한국어 +ltLT=Lietuvių +lvLV=Latviski +nnNO=Nynorsk +plPL=Polski +ptBR=Português do Brasil +ptPT=Português de Portugal +roRO=Română +ruRU=Pусский +skSK=Slovenčina +slSI=Slovenščina +srRS=Српски +svSE=Svenska +trTR=Türk +ukUA=Українська +viVN=Việt +zhCN=简体中文 +zhTW=繁體中文 +en.box=Box plug-in en.confluence=Confluence plug-in en.default=Default installation +en.dropbox=Dropbox plug-in en.externalcommand=Open with external command plug-in +en.flickr=Flickr plug-in en.imgur=Imgur plug-in (See: http://imgur.com) en.jira=Jira plug-in en.language=Additional languages en.ocr=OCR plug-in (needs Microsoft Office Document Imaging (MODI)) en.office=Microsoft Office plug-in en.optimize=Optimizing performance, this may take a while. +en.photobucket=Photobucket plug-in +en.picasa=Picasa plug-in en.startgreenshot=Start {#ExeName} en.startup=Start {#ExeName} with Windows start en.win10=Windows 10 plug-in @@ -278,15 +320,20 @@ fr.startgreenshot=Démarrer {#ExeName} fr.startup=Lancer {#ExeName} au démarrage de Windows fr.win10=Greffon Windows 10 +it.box=Plugin Box it.confluence=Plugin Confluence it.default=Installazione di default +it.dropbox=Plugin Dropbox it.externalcommand=Apri con comando esterno plugin +it.flickr=Plugin Flickr it.imgur=Plugin Imgur (vedi: http://imgur.com) it.jira=Plugin Jira it.language=Lingue aggiuntive it.ocr=Plugin OCR (richiede Microsoft Office Document Imaging (MODI)) it.office=Plugin Microsoft Office it.optimize=Ottimizzazione prestazioni (può richiedere tempo). +it.photobucket=Plugin Photobucket +it.picasa=Plugin Picasa it.startgreenshot=Esegui {#ExeName} it.startup=Esegui {#ExeName} all''avvio di Windows it.win10=Plugin Windows 10 @@ -411,56 +458,56 @@ Name: "custom"; Description: "{code:CustomInstall}"; Flags: iscustom [Components] Name: "greenshot"; Description: "Greenshot"; Types: default full compact custom; Flags: fixed -Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning -Name: "plugins\ocr"; Description: {cm:ocr}; Types: default full custom; Flags: disablenouninstallwarning -Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flags: disablenouninstallwarning -Name: "plugins\confluence"; Description: {cm:confluence}; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\externalcommand"; Description: {cm:externalcommand}; Types: default full custom; Flags: disablenouninstallwarning ;Name: "plugins\networkimport"; Description: "Network Import Plugin"; Types: full -Name: "plugins\box"; Description: "Box Plugin"; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\dropbox"; Description: "Dropbox Plugin"; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\flickr"; Description: "Flickr Plugin"; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\picasa"; Description: "Picasa Plugin"; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\photobucket"; Description: "Photobucket Plugin"; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\win10"; Description: "Windows 10 Plugin"; Types: default full custom; Flags: disablenouninstallwarning; Check: IsWindows10OrNewer() +Name: "plugins\box"; Description: {cm:box}; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\confluence"; Description: {cm:confluence}; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\dropbox"; Description: {cm:dropbox}; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\externalcommand"; Description: {cm:externalcommand}; Types: default full custom; Flags: disablenouninstallwarning +Name: "plugins\flickr"; Description: {cm:flickr}; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flags: disablenouninstallwarning +Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\ocr"; Description: {cm:ocr}; Types: default full custom; Flags: disablenouninstallwarning +Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning +Name: "plugins\photobucket"; Description: {cm:photobucket}; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\picasa"; Description: {cm:picasa}; Types: full custom; Flags: disablenouninstallwarning +Name: "plugins\win10"; Description: {cm:win10}; Types: default full custom; Flags: disablenouninstallwarning; Check: IsWindows10OrNewer() Name: "languages"; Description: {cm:language}; Types: full custom; Flags: disablenouninstallwarning -Name: "languages\arSY"; Description: "العربية"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') -Name: "languages\caCA"; Description: "Català"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\csCZ"; Description: "Ceština"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\daDK"; Description: "Dansk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\dexfranconia"; Description: "Frängisch (Deutsch)"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\elGR"; Description: "ελληνικά"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('4') -Name: "languages\esES"; Description: "Español"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\etEE"; Description: "Eesti"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\faIR"; Description: "پارسی"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') -Name: "languages\fiFI"; Description: "Suomi"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\frFR"; Description: "Français"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\frQC"; Description: "Français - Québec"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\heIL"; Description: "עִבְרִית"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('c') -Name: "languages\huHU"; Description: "Magyar"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\idID"; Description: "Bahasa Indonesia"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\itIT"; Description: "Italiano"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\jaJP"; Description: "日本語"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('7') -Name: "languages\koKR"; Description: "한국어"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8') -Name: "languages\kabDZ"; Description: "Taqbaylit"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8') -Name: "languages\ltLT"; Description: "Lietuvių"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3') -Name: "languages\lvLV"; Description: "Latviski"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3') -Name: "languages\nnNO"; Description: "Nynorsk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\plPL"; Description: "Polski"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\ptBR"; Description: "Português do Brasil"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\ptPT"; Description: "Português de Portugal"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\ruRU"; Description: "Pусский"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') -Name: "languages\roRO"; Description: "Română"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\skSK"; Description: "Slovenčina"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\slSI"; Description: "Slovenščina"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') -Name: "languages\srRS"; Description: "Српски"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') -Name: "languages\svSE"; Description: "Svenska"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') -Name: "languages\trTR"; Description: "Türk"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('6') -Name: "languages\ukUA"; Description: "Українська"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') -Name: "languages\viVN"; Description: "Việt"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('e') -Name: "languages\zhCN"; Description: "简体中文"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('a') -Name: "languages\zhTW"; Description: "繁體中文"; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('9') +Name: "languages\arSY"; Description: {cm:arSY}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') +Name: "languages\caCA"; Description: {cm:caCA}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\csCZ"; Description: {cm:csCZ}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\daDK"; Description: {cm:daDK}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\dexfranconia"; Description: {cm:dexfranconia}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\elGR"; Description: {cm:elGR}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('4') +Name: "languages\esES"; Description: {cm:esES}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\etEE"; Description: {cm:etEE}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\faIR"; Description: {cm:faIR}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') +Name: "languages\fiFI"; Description: {cm:fiFI}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\frFR"; Description: {cm:frFR}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\frQC"; Description: {cm:frQC}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\heIL"; Description: {cm:heIL}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('c') +Name: "languages\huHU"; Description: {cm:huHU}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\idID"; Description: {cm:idID}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\itIT"; Description: {cm:itIT}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\jaJP"; Description: {cm:jaJP}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('7') +Name: "languages\kabDZ"; Description: {cm:kabDZ}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8') +Name: "languages\koKR"; Description: {cm:koKR}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('8') +Name: "languages\ltLT"; Description: {cm:ltLT}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3') +Name: "languages\lvLV"; Description: {cm:lvLV}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('3') +Name: "languages\nnNO"; Description: {cm:nnNO}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\plPL"; Description: {cm:plPL}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\ptBR"; Description: {cm:ptBR}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\ptPT"; Description: {cm:ptPT}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\roRO"; Description: {cm:roRO}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\ruRU"; Description: {cm:ruRU}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') +Name: "languages\skSK"; Description: {cm:skSK}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\slSI"; Description: {cm:slSI}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('2') +Name: "languages\srRS"; Description: {cm:srRS}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') +Name: "languages\svSE"; Description: {cm:svSE}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('1') +Name: "languages\trTR"; Description: {cm:trTR}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('6') +Name: "languages\ukUA"; Description: {cm:ukUA}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('5') +Name: "languages\viVN"; Description: {cm:viVN}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('e') +Name: "languages\zhCN"; Description: {cm:zhCN}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('a') +Name: "languages\zhTW"; Description: {cm:zhTW}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('9') [Code] // Do we have a regular user trying to install this? function IsRegularUser(): Boolean; From f2f47c64dbc8034e1bcba6b5031f4c439d237248 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Sat, 8 Aug 2020 12:20:53 +0200 Subject: [PATCH 059/232] Update setup.iss (#228) Add Italian translation for additional lanuage Modify script to use "Uninstall" string localziation Add "Uninstall" string localziation for English and Italian. --- Greenshot/releases/innosetup/setup.iss | 42 ++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 57b171a7f..38636fce7 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -189,7 +189,7 @@ Root: HKLM; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: st [Icons] Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app}; AppUserModelID: "{#ExeName}" -Name: {group}\Uninstall {#ExeName}; Filename: {uninstallexe}; WorkingDir: {app}; +Name: {group}\{cm:UninstallIconDescription} {#ExeName}; Filename: {uninstallexe}; WorkingDir: {app}; Name: {group}\Readme.txt; Filename: {app}\readme.txt; WorkingDir: {app} Name: {group}\License.txt; Filename: {app}\license.txt; WorkingDir: {app} @@ -268,6 +268,7 @@ en.picasa=Picasa plug-in en.startgreenshot=Start {#ExeName} en.startup=Start {#ExeName} with Windows start en.win10=Windows 10 plug-in +en.UninstallIconDescription=Uninstall de.confluence=Confluence Plug-in de.default=Standard installation @@ -322,7 +323,7 @@ fr.win10=Greffon Windows 10 it.box=Plugin Box it.confluence=Plugin Confluence -it.default=Installazione di default +it.default=Installazione predefinita it.dropbox=Plugin Dropbox it.externalcommand=Apri con comando esterno plugin it.flickr=Plugin Flickr @@ -337,6 +338,43 @@ it.picasa=Plugin Picasa it.startgreenshot=Esegui {#ExeName} it.startup=Esegui {#ExeName} all''avvio di Windows it.win10=Plugin Windows 10 +it.UninstallIconDescription=Disinstalla +it.dexfranconia=Fräncofono (Tedesco) +it.arSY=Arabo (Siria) +it.caCA=Catalano +it.csCZ=Ceco +it.daDK=Danese +it.elGR=Greco +it.esES=Spagnolo +it.etEE=Eesti +it.faIR=Farsi (Iran) +it.fiFI=Suomi +it.frFR=Francese +it.frQC=Francese (Québec) +it.heIL=Ebraico (Israele) +it.huHU=Ungherese +it.idID=Bahasa Indonesia +it.itIT=Italiano +it.jaJP=Giapponese +it.kabDZ=Taqbaylit +it.koKR=Coreano +it.ltLT=Lituano +it.lvLV=Latviano +it.nnNO=Norvegese +it.plPL=Polacco +it.ptBR=Portoghese (Brasile) +it.ptPT=Portoghese (Portogallo) +it.roRO=Rumeno +it.ruRU=Russo +it.skSK=Slovacco +it.slSI=Sloveno +it.srRS=Serbo (Russia) +it.svSE=Svedese +it.trTR=Türco +it.ukUA=Ucraino +it.viVN=Vietnamita +it.zhCN=Cinese (Semplificato) +it.zhTW=Cinese (Taiwan) lt.confluence=Confluence spraudnis lt.default=${default} From 90ad04caf7c49d9e2b55eecb390cc17690fafb06 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Tue, 11 Aug 2020 16:59:11 +0200 Subject: [PATCH 060/232] italian language files update (#230) * Update Italian language (GUI) * Update Italian language (website) * Update italian.iss * Update Italin language Box plugin * Update Italian language Confluence Plugin * Update Italian language Dropbox plugin * Update Italian langueg External command plugin * Update italian language Flickr plugin * Update Italian language Imgur plugin * Update Italian language Jira plugin * Update Italian language OCR plugin * Update Italian language Photobucket plugin * Update Italian language Picasa plugin --- Greenshot/Languages/language-it-IT.xml | 14 +++--- .../website/language-website-it-IT.xml | 20 ++++---- .../innosetup/scripts/lang/italian.iss | 10 ++-- .../Languages/language_boxplugin-it-IT.xml | 12 ++--- .../language_confluenceplugin-it-IT.xml | 22 ++++----- .../language_dropboxplugin-it-IT.xml | 12 ++--- .../language_externalcommandplugin-it-IT.xml | 46 +++++++++++++------ .../Languages/language_flickrplugin-it-IT.xml | 12 ++--- .../Languages/language_imgurplugin-it-IT.xml | 21 +++++---- .../Languages/language_jiraplugin-it-IT.xml | 14 +++--- .../Languages/language_ocrplugin-it-IT.xml | 6 +-- .../language_photobucketplugin-it-IT.xml | 10 ++-- .../Languages/language_picasaplugin-it-IT.xml | 44 ++++++++++++------ 13 files changed, 142 insertions(+), 101 deletions(-) diff --git a/Greenshot/Languages/language-it-IT.xml b/Greenshot/Languages/language-it-IT.xml index cef5e4705..93379225a 100644 --- a/Greenshot/Languages/language-it-IT.xml +++ b/Greenshot/Languages/language-it-IT.xml @@ -1,15 +1,15 @@ <?xml version="1.0" encoding="utf-8"?> <language description="Italiano" ietf="it-IT" version="1.3.0" languagegroup="1"> <resources> - <resource name="about_bugs">Seganal le anomalie a</resource> - <resource name="about_donations">Se ti piace Greenshot, dacci il tuo aiuto su:</resource> - <resource name="about_host">Greenshot è disponibile su GitHub in</resource> + <resource name="about_bugs">Segnala eventuali bug a questo indirizzo</resource> + <resource name="about_donations">Se ti piace Greenshot, supportaci su:</resource> + <resource name="about_host">Greenshot è disponibile nel repository GitHub</resource> <resource name="about_icons">Libreria icone del set icone Fugue di Yusuke Kamiyamane (Creative Commons Attribution 3.0 license)</resource> <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom Greenshot viene fornito SENZA ALCUNA GARANZIA. Questo software è garuitio", e potete ri-distribuirlo secondo certe condizioni. Dettagli della General Public License GNU:</resource> - <resource name="about_title">Notizie su Greenshot</resource> + <resource name="about_title">Info su Greenshot</resource> <resource name="about_translation">Traduzione in Italiano curata da bovirus e tonytogna</resource> <resource name="application_title">Greenshot - Uno straordinario strumento per copiare immagini dallo schermo</resource> <resource name="bugreport_cancel">Chiudi</resource> @@ -49,7 +49,7 @@ Chiudi la finestra e riprova nuovamente.</resource> <resource name="com_rejected_title">Accesso rifiutato a Greenshot</resource> <resource name="config_unauthorizedaccess_write">Il file di configurazione di Greenshot non può essere salvato. Controlla i permessi di accesso per '{0}'.</resource> - <resource name="contextmenu_about">Notizie su Greenshot</resource> + <resource name="contextmenu_about">Info su Greenshot</resource> <resource name="contextmenu_capturearea">Cattura regione</resource> <resource name="contextmenu_captureclipboard">Apri immagine dagli Appunti</resource> <resource name="contextmenu_capturefullscreen">Cattura schermo intero</resource> @@ -260,8 +260,8 @@ impostazioni)</resource> <resource name="settings_network">Rete e aggiornamenti</resource> <resource name="settings_output">Destinazione</resource> <resource name="settings_playsound">Riproduci suono fotocamera</resource> - <resource name="settings_plugins">Componenti Aggiuntivi</resource> - <resource name="settings_plugins_createdby">Creato da</resource> + <resource name="settings_plugins">Componenti aggiuntivi</resource> + <resource name="settings_plugins_createdby">Autore</resource> <resource name="settings_plugins_dllpath">Percorso DLL</resource> <resource name="settings_plugins_name">Nome</resource> <resource name="settings_plugins_version">Versione</resource> diff --git a/Greenshot/Languages/website/language-website-it-IT.xml b/Greenshot/Languages/website/language-website-it-IT.xml index 31f1b1dfb..6e4d8c737 100644 --- a/Greenshot/Languages/website/language-website-it-IT.xml +++ b/Greenshot/Languages/website/language-website-it-IT.xml @@ -2,18 +2,18 @@ <language description="Italiano" ietf="it-IT" version="1.0.2" languagegroup="1"> <resources> <resource name="home_downloads">Download</resource> - <resource name="home_headline">Greenshot - strumento di cattura gratis ottimizzato per la produttività</resource> - <resource name="home_opensource">Greenshot è gratuito e open source</resource> - <resource name="home_opensource_donate">Se si scopre che Greenshot risparmiare un sacco di tempo e / o denaro, è possibile <a href="/support/">sostenere lo sviluppo</a> di questa strumento di cattura.</resource> - <resource name="home_opensource_gpl">Greenshot è pubblicato sotto licenza <a href="http://en.wikipedia.org/wiki/GNU_General_Public_License" target="_blank">GPL</a>. Questo software può essere scaricato e utilizzato gratuitamente, anche in un ambiente commerciale.</resource> + <resource name="home_headline">Greenshot - è uno strumento di cattura gratuito ottimizzato per la produttività</resource> + <resource name="home_opensource">Greenshot è gratuito ed open source</resource> + <resource name="home_opensource_donate">Se scopri che Greenshot ti fa risparmiare un sacco di tempo e/o denaro, puoi <a href="/support/">sostenere lo sviluppo</a> di questa strumento di cattura.</resource> + <resource name="home_opensource_gpl">Greenshot è pubblicato sotto licenza <a href="http://en.wikipedia.org/wiki/GNU_General_Public_License" target="_blank">GPL</a>. Questo software può essere scaricato e usato gratuitamente, anche in un ambiente commerciale.</resource> <resource name="home_seemore">Vuoi saperne di più?</resource> - <resource name="home_seemore_screenshots">Naturalmente c'è molto di più che si può fare per Greenshot. Check out alcuni <a href="/screenshots/">screenshot</a> di Greenshot in azione o provare la versione <a href="/downloads/">più recente</a>.</resource> + <resource name="home_seemore_screenshots">Naturalmente Greenshot pò fare molto di più per te. Guarda alcunr <a title="schermate di Greenshot in azione" href="/screenshots/">screenshots</a> of Greenshot in action or try the <a title="Scarica la versione stabile più recente di Greenshot" href="/downloads/">latest release</a>.</resource> <resource name="home_whatis">Greenshot - Che cosa è questo?</resource> - <resource name="home_whatis_create">Rapidamente rendere le immagini di uno schermo selezionata regione, finestra o completo schermo. È possibile anche catturare le pagine web da Internet Explorer completi (scorrimento).</resource> - <resource name="home_whatis_edit">Annotare, evidenziare o nascondere parti di screenshot è facilmente.</resource> - <resource name="home_whatis_intro">Greenshot è uno strumento di cattura schermo per Windows con leggeri caratteristiche essenziali:</resource> + <resource name="home_whatis_create">Cattura facilmente una zona, una finestra o lo schermo per intero. È possibile anche catturare le pagine web complete (incluso lo scorrimento) in Internet Explorer.</resource> + <resource name="home_whatis_edit">Annota, evidenzia o nascondi facilmente parti di una schermata.</resource> + <resource name="home_whatis_intro">Greenshot è uno strumento di cattura schermo per Windows con le seguenti funzionalità principali:</resource> <resource name="home_whatis_more">... e molte altre opzioni per creare e lavorare con le immagini ogni giorno.</resource> - <resource name="home_whatis_send">Esportazione screenshot in vari modi: salvare in un file, stampa, copia negli appunti, attaccare a un messaggio, inviare ai programmi di Office o caricare su siti di foto come Flickr e Picasa, tra gli altri.</resource> - <resource name="home_whatis_usage">Essere facile da capire e configurare, Greenshot è uno strumento efficace per i project manager, sviluppatori di software, redattori tecnici, collaudatori e chiunque altro la creazione di screenshot.</resource> + <resource name="home_whatis_send">Esporta la schermate in vari modi: salvataggio in un file, stampa, copia negli Appunti, come allegati ad un messaggio, invio a programmi come Office o upload in siti di foto come Flickr e Picasa, etc.</resource> + <resource name="home_whatis_usage">Greenshot è facile da comprendere e configurare, ed è uno strumento efficace per i project manager, sviluppatori di software, redattori tecnici, collaudatori e chiunque altro crea schermate.</resource> </resources> </language> \ No newline at end of file diff --git a/Greenshot/releases/innosetup/scripts/lang/italian.iss b/Greenshot/releases/innosetup/scripts/lang/italian.iss index 67efc61ce..534bf7db6 100644 --- a/Greenshot/releases/innosetup/scripts/lang/italian.iss +++ b/Greenshot/releases/innosetup/scripts/lang/italian.iss @@ -4,14 +4,14 @@ Name: "it"; MessagesFile: "compiler:Languages\Italian.isl" [CustomMessages] ;http://www.microsoft.com/globaldev/reference/lcid-all.mspx it.lcid=1040 -it.depdownload_msg=Le seguenti applicazioni sono necessarie per procedere con l'installazione:%n%n%1%nSi desidera scaricarle ed installarle adesso? +it.depdownload_msg=Per procedere con l'installazione sono necessarie le seguenti applicazioni:%n%n%1%nVuoi scaricare ed installarle le applicazioni adesso? it.depdownload_memo_title=Dipendenze da scaricare it.depinstall_memo_title=Dipendenze da installare -it.depinstall_title=Installazione delle dipendenze -it.depinstall_description=Si prega di attendere mentre vengono installate le dipendenze necessarie sul computer. +it.depinstall_title=Installazione dipendenze +it.depinstall_description=Attendi mentre vengono installate le dipendenze necessarie. it.depinstall_status=Installazione %1... -it.depinstall_missing=%1 deve essere installato per poter continuare. Si prega di installare %1 ed eseguire nuovamente il programma d'installazione. -it.depinstall_error=Si è verificato un errore durante l'installazione delle dipendenze. Si prega di riavviare il computer ed eseguire nuovamente il programma d'installazione oppure di installare manualmente le seguenti applicazioni:%n +it.depinstall_missing=per poter continuare deve essere installato %1.%n%nInstalla %1 ed esegui nuovamente il programma d'installazione. +it.depinstall_error=Si è verificato un errore durante l'installazione delle dipendenze.%n%nRiavvia il computer ed esegui nuovamente il programma d'installazione oppure installa manualmente le seguenti dipendenze:%n it.isxdl_langfile=italian.ini diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml b/GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml index e53e65909..786acfac8 100644 --- a/GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml +++ b/GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.0.0"> +<language description="Italiano" ietf="it-IT" version="1.0.1"> <resources> <resource name="label_AfterUploadLinkToClipBoard"> - Collegamento agli appunti + Collegamento agli Appunti </resource> <resource name="label_AfterUpload"> - Dopo il carico + Dopo il caricamento </resource> <resource name="Configure"> - Configurazione di Box + Impostazioni di Box </resource> <resource name="upload_menu_item"> Carica su Box @@ -17,7 +17,7 @@ Impostazioni di Box </resource> <resource name="upload_success"> - Immagine caricata correttamente su Box! + caricamento immagine su Box completato! </resource> <resource name="upload_failure"> Si è verificato un errore durante il caricamento su Box: @@ -26,7 +26,7 @@ Formato immagine </resource> <resource name="communication_wait"> - Comunicazione con Box. Attendere prego... + Comunicazione con Box... </resource> </resources> </language> \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml b/GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml index 1f145ac54..ba12ed4f4 100644 --- a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml +++ b/GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="0.8.0"> +<language description="Italiano" ietf="it-IT" version="1.0.1"> <resources> <resource name="plugin_settings"> Impostazioni di Confluence </resource> <resource name="login_error"> - Si è verificato un problema durante il collegamento: {0} + Si è verificato un problema durante il caricamento: {0} </resource> <resource name="label_url"> - Indirizzo Url + Indirizzo URL </resource> <resource name="label_timeout"> Timeout @@ -17,10 +17,10 @@ Utente </resource> <resource name="label_password"> - Parola d'ordine + Password </resource> <resource name="login_title"> - Inserisci le tue credenziali di collegamento a Confluence + Inserisci le credenziali di accesso a Confluence </resource> <resource name="OK"> OK @@ -32,7 +32,7 @@ Carica su Confluence </resource> <resource name="upload_success"> - Immagine caricata correttamente su Confluence! + Caricamento immagine su Confluence completato! </resource> <resource name="upload_failure"> Si è verificato un errore durante il caricamento su Confluence: @@ -44,10 +44,10 @@ Formato di caricamento </resource> <resource name="copy_wikimarkup"> - Copia Wikimarkup sugli appunti + Copia Wikimarkup negli Appunti </resource> <resource name="filename"> - Nome File + Nome file </resource> <resource name="upload"> Carica @@ -59,7 +59,7 @@ Cerca pagine </resource> <resource name="browse_pages"> - Naviga pagine + Sfoglia pagine </resource> <resource name="search_text"> Cerca testo @@ -68,13 +68,13 @@ Cerca </resource> <resource name="loading"> - Caricamento dati di Confluence, attendere prego... + Caricamento dati di Confluence... </resource> <resource name="include_person_spaces"> Includi spazi personali in ricerca e navigazione </resource> <resource name="communication_wait"> - Trasferimento dati verso Confluence, attendere prego... + Trasferimento dati su Confluence... </resource> </resources> </language> \ No newline at end of file diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml b/GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml index ec618c12e..e295eebab 100644 --- a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml +++ b/GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml @@ -1,17 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.0.0"> +<language description="Italiano" ietf="it-IT" version="1.0.1"> <resources> <resource name="label_AfterUploadLinkToClipBoard"> - Collegamento agli appunti + Collegamento agli Appunti </resource> <resource name="label_AfterUploadOpenHistory"> Apri cronologia </resource> <resource name="label_AfterUpload"> - Dopo il carico + Dopo il caricamento </resource> <resource name="Configure"> - Configurazione di Dropbox + Impostazioni di Dropbox </resource> <resource name="upload_menu_item"> Carica su Dropbox @@ -20,7 +20,7 @@ Impostazioni di Dropbox </resource> <resource name="upload_success"> - Immagine caricata correttamente su Dropbox! + Caricamento immagine su Dropbox completato! </resource> <resource name="upload_failure"> Si è verificato un errore durante il caricamento su Dropbox: @@ -29,7 +29,7 @@ Formato immagine </resource> <resource name="communication_wait"> - Comunicazione con Dropbox. Attendere prego... + Comunicazione con Dropbox... </resource> </resources> </language> \ No newline at end of file diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml b/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml index 3c0b77f87..164465ae9 100644 --- a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml +++ b/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml @@ -1,15 +1,35 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.1.4" languagegroup="2"> - <resources> - <resource name="contextmenu_configure">Configurazione comandi esterni</resource> - <resource name="label_argument">Parametri</resource> - <resource name="label_command">Comando</resource> - <resource name="label_information">{0} è il nome file della vostra immagine</resource> - <resource name="label_name">Nome</resource> - <resource name="settings_delete">Elimina</resource> - <resource name="settings_detail_title">Configurazione comando</resource> - <resource name="settings_edit">Modifica</resource> - <resource name="settings_new">Nuovo</resource> - <resource name="settings_title">Impostazioni comandi esterni</resource> - </resources> +<language description="Italiano" ietf="it-IT" version="1.1.5"> + <resources> + <resource name="contextmenu_configure"> + Impostazioni comandi esterni + </resource> + <resource name="settings_title"> + Impostazioni comandi esterni + </resource> + <resource name="settings_detail_title"> + Impostazioni comando + </resource> + <resource name="settings_new"> + Nuovo + </resource> + <resource name="settings_delete"> + Elimina + </resource> + <resource name="settings_edit"> + Modifica + </resource> + <resource name="label_name"> + Nome + </resource> + <resource name="label_command"> + Comando + </resource> + <resource name="label_argument"> + Argomenti + </resource> + <resource name="label_information"> + {0} è il noem file della schermata + </resource> + </resources> </language> \ No newline at end of file diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml b/GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml index 88347e287..0630da364 100644 --- a/GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml +++ b/GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.0.0"> +<language description="Italiano" ietf="it-IT" version="1.0.1"> <resources> <resource name="label_HiddenFromSearch"> Visibilità @@ -8,13 +8,13 @@ Liv. sicurezza </resource> <resource name="label_AfterUploadLinkToClipBoard"> - Collegamento agli appunti + Collegamento agli Appunti </resource> <resource name="label_AfterUpload"> - Dopo il carico + Dopo il caricamento </resource> <resource name="Configure"> - Configurazione Flickr + Impostazioni Flickr </resource> <resource name="upload_menu_item"> Carica su Flickr @@ -23,7 +23,7 @@ Impostazioni di Flickr </resource> <resource name="upload_success"> - Immagine caricata correttamente su Flickr! + Caricamento immagine su Flickr completato! </resource> <resource name="upload_failure"> Si è verificato un errore durante il caricamento su Flickr: @@ -32,7 +32,7 @@ Formato immagine </resource> <resource name="communication_wait"> - Comunicazione con Flickr. Attendere prego... + Comunicazione con Flickr... </resource> <resource name="public"> Pubblica diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml b/GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml index f3bb72df1..ebab6e677 100644 --- a/GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml +++ b/GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.0.0"> +<language description="Italiano" ietf="it-IT" version="1.0.1"> <resources> <resource name="upload_menu_item"> Carica su Imgur @@ -8,7 +8,7 @@ Impostazioni Imgur </resource> <resource name="label_url"> - Url + URL </resource> <resource name="OK"> OK @@ -17,34 +17,37 @@ Annulla </resource> <resource name="upload_success"> - Immagine caricata correttamente su Imgur! + caricamento immagine su Imgur completato! </resource> <resource name="upload_failure"> - Si è verificato un problema durante il collegamento: + Si è verificato un problema durante il caricamento: </resource> <resource name="label_upload_format"> Formato immagine </resource> <resource name="communication_wait"> - Comunicazione con Imgur. Attendere prego... + Comunicazione con Imgur... </resource> <resource name="delete_question"> - Sei sicuro si voler eliminare l'immagine {0} da Imgur? + Sei sicuro di voler eliminare l'immagine {0} da Imgur? </resource> <resource name="clear_question"> - Sei sicuro si voler eliminare la cronologia locale di Imgur? + Sei sicuro di voler eliminare la cronologia locale di Imgur? </resource> <resource name="delete_title"> Elimina Imgur {0} </resource> + <resource name="anonymous_access"> + Usa accesso anonimo + </resource> <resource name="use_page_link"> - Usa il collegamento alla pagina invece di quello all'immagine su appunti + Negli Appunti usa collegamento pagina invece di quello all'immagine </resource> <resource name="history"> Cronologia </resource> <resource name="configure"> - Configurazione + Impostazioni </resource> </resources> </language> \ No newline at end of file diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml b/GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml index 8b9febaf8..be20028fb 100644 --- a/GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml +++ b/GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.0.0"> +<language description="Italiano" ietf="it-IT" version="1.0.1"> <resources> <resource name="upload_menu_item"> Carica su Jira @@ -14,7 +14,7 @@ ID </resource> <resource name="column_reporter"> - Reporter + Segnalatore </resource> <resource name="column_summary"> Riepilogo @@ -23,7 +23,7 @@ Commento </resource> <resource name="label_filename"> - Nome File + Nome file </resource> <resource name="label_jira"> JIRA @@ -35,10 +35,10 @@ Si è verificato un problema durante il collegamento: {0} </resource> <resource name="label_url"> - Url + URL </resource> <resource name="login_title"> - Inserisci le tue credenziali di collegamento a Jira + Inserisci le credenziali di accesso a Jira </resource> <resource name="settings_title"> Impostazioni Jira @@ -50,7 +50,7 @@ Annulla </resource> <resource name="upload_success"> - Immagine caricata correttamente su Jira! + caricamento immagine su Jira completato! </resource> <resource name="upload_failure"> Si è verificato un errore durante il caricamento su Jira: @@ -59,7 +59,7 @@ Formato immagine </resource> <resource name="communication_wait"> - Trasferimento dati verso JIRA, attendere prego... + Trasferimento dati verso JIRA... </resource> </resources> </language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-it-IT.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-it-IT.xml index 670f233e2..52259f004 100644 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-it-IT.xml +++ b/GreenshotOCRPlugin/Languages/language_ocrplugin-it-IT.xml @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.0.0"> +<language description="Italiano" ietf="it-IT" version="1.0.1"> <resources> <resource name="language"> Lingua OCR </resource> <resource name="orient_image"> - Orienta + Orientamento immagine </resource> <resource name="straighten_image"> - Raddrizza + Raddrizza immagine </resource> </resources> </language> \ No newline at end of file diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml b/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml index f0c1e80d2..3ec36383f 100644 --- a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml +++ b/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.0.0"> +<language description="Italiano" ietf="it-IT" version="1.0.1"> <resources> <resource name="upload_menu_item"> Carica su Photobucket @@ -14,7 +14,7 @@ Annulla </resource> <resource name="upload_success"> - Immagine caricata correttamente su Photobucket! + Caricamento immagine su Photobucket completato! </resource> <resource name="upload_failure"> Si è verificato un errore durante il caricamento su Photobucket: @@ -23,13 +23,13 @@ Formato immagine </resource> <resource name="communication_wait"> - Comunicazione con Photobucket. Attendere prego... + Comunicazione con Photobucket... </resource> <resource name="use_page_link"> - Usa il collegamento alla pagina invece di quello all'immagine su appunti + Negli Appunti usa il collegamento pagina invece di quello all'immagine </resource> <resource name="configure"> - Configurazione Photobucket + Impostazioni Photobucket </resource> </resources> </language> diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-it-IT.xml b/GreenshotPicasaPlugin/Languages/language_picasaplugin-it-IT.xml index a72279d00..6f0b76c78 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-it-IT.xml +++ b/GreenshotPicasaPlugin/Languages/language_picasaplugin-it-IT.xml @@ -1,14 +1,32 @@ <?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.1.4" languagegroup="2"> - <resources> - <resource name="communication_wait">Comunicazione con Picasa. Attendere prego...</resource> - <resource name="Configure">Configurazione Picasa</resource> - <resource name="label_AfterUpload">Dopo il carico</resource> - <resource name="label_AfterUploadLinkToClipBoard">Collegamento agli appunti</resource> - <resource name="label_upload_format">Formato immagine</resource> - <resource name="settings_title">Impostazioni di Picasa</resource> - <resource name="upload_failure">Si è verificato un errore durante il caricamento su Picasa:</resource> - <resource name="upload_menu_item">Carica su Picasa</resource> - <resource name="upload_success">Immagine caricata correttamente su Picasa!</resource> - </resources> -</language> \ No newline at end of file +<language description="Italiano" ietf="it-IT" version="1.1.5"> + <resources> + <resource name="label_AfterUploadLinkToClipBoard"> + Collegamento agli Appunti + </resource> + <resource name="label_AfterUpload"> + Dopo il caricamento + </resource> + <resource name="Configure"> + Impostazioni Picasa + </resource> + <resource name="upload_menu_item"> + Carica su Picasa + </resource> + <resource name="settings_title"> + Impostazioni Picasa + </resource> + <resource name="upload_success"> + Caricamento immagine su Picasa completato! + </resource> + <resource name="upload_failure"> + Si è verificato un errore durante il caricamento su Picasa: + </resource> + <resource name="label_upload_format"> + Formato immagine + </resource> + <resource name="communication_wait"> + Comunicazione con Picasa... + </resource> + </resources> +</language> From 2c6de5b5e698c39f819253cf81c6052340879855 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Wed, 12 Aug 2020 19:36:19 +0200 Subject: [PATCH 061/232] Update Italian language (#238) [skip ci] --- .../releases/innosetup/scripts/isxdl/italian.ini | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Greenshot/releases/innosetup/scripts/isxdl/italian.ini b/Greenshot/releases/innosetup/scripts/isxdl/italian.ini index 9c290c6de..3aaaf1336 100644 --- a/Greenshot/releases/innosetup/scripts/isxdl/italian.ini +++ b/Greenshot/releases/innosetup/scripts/isxdl/italian.ini @@ -16,23 +16,23 @@ 116=Collegamento a %1 ; Messaggi di errore -120=Errore nel collegamento a Internet.\n\n%1 +120=Errore nel collegamento ad Internet.\n\n%1 121=Errore nell'apertura di %1.\n\nIl server ha restituito il codice %2. 122=Errore nella lettura dell'URL.\n\n%1 123=Errore nella scrittura del file %1.\n\n%2 124=Errore nell'apertura del file %1.\n\n%2 -125='%1' è un URL non valido. +125='%1' è una URL non valida. 126=Errore nell'apertura di %1.\n\n%2 127=Errore durante l'invio della richiesta.\n\n%1 -128=Protocollo non supportato. Sono supportati solo i protocolli HTTP e FTP. +128=Protocollo non supportato.\nSono supportati solo i protocolli HTTP e FTP. 129=Impossibile connettersi a %1.\n\n%2 -130=Impossibile risolvere il codice di servizio.\n\n%1 +130=Richiesta codice servizio fallita.\n\n%1 131=Errore nella richiesta del file.\n\n%1 ; Altro -144=Informazioni su... +144=Informazioni sul programma... 146=Download -147=Il programma d'installazione sta scaricando sul computer i files aggiuntivi. +147=Il programma d'installazione sta scaricando nel computer i file aggiuntivi. ; Etichette 160=File: @@ -41,7 +41,7 @@ 163=Tempo trascorso: 164=Tempo rimanente: 165=File attuale: -166=Avanzamento generale: +166=Progresso generale: 167=Annulla 168=OK 169=Nome utente e password From 232e20cb72e696e43fad6410915c308caca1b987 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Wed, 12 Aug 2020 19:36:46 +0200 Subject: [PATCH 062/232] Update Italian language (#237) --- Greenshot/Languages/language-it-IT.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Greenshot/Languages/language-it-IT.xml b/Greenshot/Languages/language-it-IT.xml index 93379225a..e715221b8 100644 --- a/Greenshot/Languages/language-it-IT.xml +++ b/Greenshot/Languages/language-it-IT.xml @@ -297,11 +297,11 @@ E' possibile però variare le impostazioni delle scorciatoie, oppure disattivare In alternativa alle scorciatoie di tastiera, tutte le funzioni di Greenshot sono comunque disponibili dal menù visualizzabile con il tasto destro del mouse sull'icona G nella barra.</resource> - <resource name="WindowCaptureModes.Aero">Usa colori personalizzati</resource> - <resource name="WindowCaptureModes.AeroTransparent">Mantieni trasparenza</resource> - <resource name="WindowCaptureModes.Auto">Automaticamente</resource> - <resource name="WindowCaptureModes.GDI">Usa i colori predefiniti</resource> - <resource name="WindowCaptureModes.Screen">Come visualizzata</resource> + <resource name="WindowCaptureMode.Aero">Usa colori personalizzati</resource> + <resource name="WindowCaptureMode.AeroTransparent">Mantieni trasparenza</resource> + <resource name="WindowCaptureMode.Auto">Automaticamente</resource> + <resource name="WindowCaptureMode.GDI">Usa i colori predefiniti</resource> + <resource name="WindowCaptureModes.Screen">Come visualizzata</resource> <!-- 1.2 --> <resource name="editor_dropshadow_darkness">Intensità ombra</resource> From 6adefe32dfd95af6946e1b526e3400570888b7fe Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Sun, 16 Aug 2020 10:32:57 +0200 Subject: [PATCH 063/232] Italian language update @Lakritzator Align strings numbers (Add a new string) Add refence about translation date Please merge. --- Greenshot/Languages/language-it-IT.xml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Greenshot/Languages/language-it-IT.xml b/Greenshot/Languages/language-it-IT.xml index e715221b8..9693dd080 100644 --- a/Greenshot/Languages/language-it-IT.xml +++ b/Greenshot/Languages/language-it-IT.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?> <language description="Italiano" ietf="it-IT" version="1.3.0" languagegroup="1"> <resources> <resource name="about_bugs">Segnala eventuali bug a questo indirizzo</resource> @@ -10,25 +10,22 @@ Greenshot viene fornito SENZA ALCUNA GARANZIA. Questo software è garuitio", e potete ri-distribuirlo secondo certe condizioni. Dettagli della General Public License GNU:</resource> <resource name="about_title">Info su Greenshot</resource> - <resource name="about_translation">Traduzione in Italiano curata da bovirus e tonytogna</resource> + <resource name="about_translation">Traduzione italiana (v. 16.08.2020) di bovirus e tonytogna</resource> <resource name="application_title">Greenshot - Uno straordinario strumento per copiare immagini dallo schermo</resource> <resource name="bugreport_cancel">Chiudi</resource> <resource name="bugreport_info">Si è verificato un errore inaspettato. La buona notizia è che puoi aiutarci ad eliminarlo segnalandoci l'errore. -Visita la pagina internet qui sotto, crea una nuova segnalazione errore e copia nella descrizione il -contenuto preso dall'area di testo. +Visita la pagina internet qui sotto, crea una nuova segnalazione errore e copia nella descrizione il contenuto preso dall'area di testo. Aggiungi un riepilogo significativo e includi qualsiasi informazione tu consideri possa esserci d'aiuto per risolvere il problema. Inoltre apprezzeremo molto, se prima di inserire la segnalazione, controllassi se esiste già una segnalazione per questo tipo di errore (puoi usare la ricerca) Grazie :)</resource> <resource name="bugreport_title">Errore</resource> <resource name="CANCEL">Annulla</resource> - <resource name="clipboard_error">Si è verificato un errore inaspettato durante la scrittura negli Appunti. - </resource> + <resource name="clipboard_error">Si è verificato un errore inaspettato durante la scrittura negli Appunti.</resource> <resource name="clipboard_noimage">Nessuna immagine sugli Appunti.</resource> - <resource name="clipboard_inuse">Greenshot non è riuscito a scrivere negli Appunti poiché il processo {0} teneva l'accesso bloccato. - </resource> + <resource name="clipboard_inuse">Greenshot non è riuscito a scrivere negli Appunti poiché il processo {0} teneva l'accesso bloccato.</resource> <resource name="ClipboardFormat.BITMAP">BMO (Bitmap Windows)</resource> <resource name="ClipboardFormat.DIB">DIB (Device independent Bitmap)</resource> <resource name="ClipboardFormat.HTML">HTML</resource> @@ -236,7 +233,6 @@ Correggi la maschera noem file e riprova.</resource> <resource name="settings_general">Generali</resource> <resource name="settings_iecapture">Cattura Internet Explorer</resource> <resource name="settings_jpegquality">Qualità JPEG</resource> - <resource name="settings_jpegsettings">Impostazioni JPEG</resource> <resource name="settings_language">Lingua</resource> <resource name="settings_message_filenamepattern">I parametri racchiusi tra % verranno automaticamente sostituiti: ${YYYY} anno, 4 numeri @@ -301,7 +297,7 @@ In alternativa alle scorciatoie di tastiera, tutte le funzioni di Greenshot sono <resource name="WindowCaptureMode.AeroTransparent">Mantieni trasparenza</resource> <resource name="WindowCaptureMode.Auto">Automaticamente</resource> <resource name="WindowCaptureMode.GDI">Usa i colori predefiniti</resource> - <resource name="WindowCaptureModes.Screen">Come visualizzata</resource> + <resource name="WindowCaptureMode.Screen">Come visualizzata</resource> <!-- 1.2 --> <resource name="editor_dropshadow_darkness">Intensità ombra</resource> @@ -313,6 +309,7 @@ In alternativa alle scorciatoie di tastiera, tutte le funzioni di Greenshot sono <resource name="editor_tornedge_settings">Impostazioni bordi strappati</resource> <resource name="editor_tornedge_toothsize">Dimensione dentellatura</resource> <resource name="editor_tornedge_verticaltoothrange">Intervallo verticale dentellatura</resource> + <resource name="editor_tornedge_all">Strappo su tutti i lati</resource> <resource name="editor_tornedge_left">Strappo lato sinistro</resource> <resource name="editor_tornedge_right">Strappo lato destro</resource> <resource name="editor_tornedge_top">Strappo lato in alto</resource> From f8f4584778f69d93779d0a3cc53a5df4e3cdc769 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Sun, 16 Aug 2020 10:36:48 +0200 Subject: [PATCH 064/232] Update English language @Lakritzator Add strings for "about_translation" (useful for translator). This string available in other languages. Please merge. --- Greenshot/Languages/language-en-US.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/Greenshot/Languages/language-en-US.xml b/Greenshot/Languages/language-en-US.xml index 319871fa4..b052785ec 100644 --- a/Greenshot/Languages/language-en-US.xml +++ b/Greenshot/Languages/language-en-US.xml @@ -9,6 +9,7 @@ Greenshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Details about the GNU General Public License:</resource> <resource name="about_title">About Greenshot</resource> + <resource name="about_translation">Info about translation</resource> <resource name="application_title">Greenshot - the revolutionary screenshot utility</resource> <resource name="bugreport_cancel">Close</resource> <resource name="bugreport_info">Sorry, an unexpected error occured. From af0bc8327aa7cf479c84af50210689bd36a92866 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Sun, 16 Aug 2020 20:36:51 +0200 Subject: [PATCH 065/232] Update Italian language (removed double string editor_image_shadow) (#245) [skip ci] --- Greenshot/Languages/language-it-IT.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/Greenshot/Languages/language-it-IT.xml b/Greenshot/Languages/language-it-IT.xml index 9693dd080..2d9fc43e0 100644 --- a/Greenshot/Languages/language-it-IT.xml +++ b/Greenshot/Languages/language-it-IT.xml @@ -153,7 +153,6 @@ Controlla i permessi di accesso per '{0}'.</resource> <resource name="editor_selectall">Seleziona tutto</resource> <resource name="editor_senttoprinter">Stampa inviata a '{0}'.</resource> <resource name="editor_shadow">Ombra</resource> - <resource name="editor_image_shadow">Ombra</resource> <resource name="editor_storedtoclipboard">Immagine copiata negli Appunti.</resource> <resource name="editor_thickness">Spessore linea</resource> <resource name="editor_title">Gestione immagini di Greenshot</resource> From d8aeab5514802b8bd2aa550198264e0ca6ad10aa Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Sun, 16 Aug 2020 20:37:43 +0200 Subject: [PATCH 066/232] Update installer script (#243) [skip ci] Add changes to have icon description for Readme/License multi-language Add Italian translation for the icon descriptions. --- Greenshot/releases/innosetup/setup.iss | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 38636fce7..7735af213 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -190,8 +190,8 @@ Root: HKLM; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: st [Icons] Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app}; AppUserModelID: "{#ExeName}" Name: {group}\{cm:UninstallIconDescription} {#ExeName}; Filename: {uninstallexe}; WorkingDir: {app}; -Name: {group}\Readme.txt; Filename: {app}\readme.txt; WorkingDir: {app} -Name: {group}\License.txt; Filename: {app}\license.txt; WorkingDir: {app} +Name: {group}\{cm:ShowReadme}; Filename: {app}\readme.txt; WorkingDir: {app} +Name: {group}\{cm:ShowLicense}; Filename: {app}\license.txt; WorkingDir: {app} [Languages] Name: en; MessagesFile: compiler:Default.isl @@ -269,6 +269,8 @@ en.startgreenshot=Start {#ExeName} en.startup=Start {#ExeName} with Windows start en.win10=Windows 10 plug-in en.UninstallIconDescription=Uninstall +en.ShowLicense=Show licenze +en.ShowReadme=how Readme de.confluence=Confluence Plug-in de.default=Standard installation @@ -339,6 +341,8 @@ it.startgreenshot=Esegui {#ExeName} it.startup=Esegui {#ExeName} all''avvio di Windows it.win10=Plugin Windows 10 it.UninstallIconDescription=Disinstalla +it.ShowLicense=Visualizza licenza (in inglese) +it.ShowReadme=Visualizza Readme (in inglese) it.dexfranconia=Fräncofono (Tedesco) it.arSY=Arabo (Siria) it.caCA=Catalano From 94c778d82cdd7866c1789bb16fd98244a42b89b5 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Fri, 23 Oct 2020 00:28:50 +0200 Subject: [PATCH 067/232] Improve DPI support (#254) * Improving the DPI handling for most forms, there are still issues with: * the AboutForm.Designer.cs where the title with the version scales differently. * the destination picker doesn't seem to scale the font correctly. Some parts are not tested yet... * Solved the issue with the destination picker font, and some other small issues. There still is an issue when using Powertoys (the feature which is experimental), that the capture is somehow skipping. --- Greenshot/App.config | 5 +- Greenshot/Forms/AboutForm.Designer.cs | 9 ++- Greenshot/Forms/CaptureForm.Designer.cs | 4 +- .../Forms/DropShadowSettingsForm.Designer.cs | 8 +-- Greenshot/Forms/ImageEditorForm.Designer.cs | 10 ++- Greenshot/Forms/ImageEditorForm.cs | 12 ++-- Greenshot/Forms/MainForm.Designer.cs | 22 +++--- Greenshot/Forms/MainForm.cs | 9 ++- .../Forms/MovableShowColorForm.Designer.cs | 9 +-- .../Forms/PrintOptionsDialog.Designer.cs | 13 ---- .../Forms/ResizeSettingsForm.Designer.cs | 7 +- Greenshot/Forms/SettingsForm.Designer.cs | 19 ------ .../Forms/TornEdgeSettingsForm.Designer.cs | 13 +--- Greenshot/GreenshotMain.cs | 8 +-- Greenshot/Helpers/CaptureHelper.cs | 6 +- .../Forms/SettingsForm.Designer.cs | 1 - .../Forms/SettingsForm.Designer.cs | 1 - .../SettingsForm.Designer.cs | 4 +- .../SettingsFormDetail.Designer.cs | 4 +- .../Forms/SettingsForm.Designer.cs | 5 -- .../Forms/ImgurHistory.Designer.cs | 7 +- .../Forms/SettingsForm.Designer.cs | 2 - GreenshotImgurPlugin/ImgurUtils.cs | 15 ++-- .../Forms/JiraForm.Designer.cs | 5 -- .../Forms/SettingsForm.Designer.cs | 1 - .../Forms/SettingsForm.Designer.cs | 1 - .../Controls/BackgroundForm.Designer.cs | 6 +- GreenshotPlugin/Controls/GreenshotForm.cs | 26 +++---- .../Controls/OAuthLoginForm.Designer.cs | 4 +- .../Controls/PleaseWaitForm.Designer.cs | 6 +- .../Controls/QualityDialog.Designer.cs | 3 +- GreenshotPlugin/Core/AbstractDestination.cs | 19 ++++-- GreenshotPlugin/Core/DpiHelper.cs | 26 +++++-- GreenshotPlugin/Core/OAuthHelper.cs | 68 ++++++++++++++----- GreenshotPlugin/Core/WindowDetails.cs | 54 ++++++++------- GreenshotPlugin/Interfaces/IDestination.cs | 12 ++-- GreenshotPlugin/UnmanagedHelpers/User32.cs | 8 ++- 37 files changed, 216 insertions(+), 216 deletions(-) diff --git a/Greenshot/App.config b/Greenshot/App.config index 61ebd6224..f15ae706e 100644 --- a/Greenshot/App.config +++ b/Greenshot/App.config @@ -4,7 +4,10 @@ <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> </startup> - <runtime> + <System.Windows.Forms.ApplicationConfigurationSection> + <add key="DpiAwareness" value="PerMonitorV2" /> + </System.Windows.Forms.ApplicationConfigurationSection> + <runtime> <loadFromRemoteSources enabled="true" /> <relativeBindForResources enabled="true" /> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> diff --git a/Greenshot/Forms/AboutForm.Designer.cs b/Greenshot/Forms/AboutForm.Designer.cs index f5018e313..1b35f8699 100644 --- a/Greenshot/Forms/AboutForm.Designer.cs +++ b/Greenshot/Forms/AboutForm.Designer.cs @@ -67,7 +67,7 @@ namespace Greenshot.Forms { // // lblTitle // - this.lblTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblTitle.Font = new System.Drawing.Font(System.Drawing.FontFamily.GenericSansSerif, 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.lblTitle.Location = new System.Drawing.Point(108, 12); this.lblTitle.Name = "lblTitle"; this.lblTitle.Size = new System.Drawing.Size(263, 19); @@ -195,8 +195,11 @@ namespace Greenshot.Forms { // // AboutForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + //this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + //this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleDimensions = new System.Drawing.SizeF(96, 96); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(530, 293); this.Controls.Add(this.lblTranslation); this.Controls.Add(this.pictureBox1); diff --git a/Greenshot/Forms/CaptureForm.Designer.cs b/Greenshot/Forms/CaptureForm.Designer.cs index 124a34d3e..ee3b43b99 100644 --- a/Greenshot/Forms/CaptureForm.Designer.cs +++ b/Greenshot/Forms/CaptureForm.Designer.cs @@ -55,8 +55,8 @@ namespace Greenshot.Forms { // // CaptureForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.ClientSize = new System.Drawing.Size(0, 0); this.Cursor = System.Windows.Forms.Cursors.Cross; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; diff --git a/Greenshot/Forms/DropShadowSettingsForm.Designer.cs b/Greenshot/Forms/DropShadowSettingsForm.Designer.cs index 5791dee14..ba8e7b3bc 100644 --- a/Greenshot/Forms/DropShadowSettingsForm.Designer.cs +++ b/Greenshot/Forms/DropShadowSettingsForm.Designer.cs @@ -105,7 +105,6 @@ namespace Greenshot.Forms { // // label3 // - this.label3.AutoSize = true; this.label3.Location = new System.Drawing.Point(153, 35); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(14, 13); @@ -166,7 +165,6 @@ namespace Greenshot.Forms { // // labelDarkness // - this.labelDarkness.AutoSize = true; this.labelDarkness.LanguageKey = "editor_dropshadow_darkness"; this.labelDarkness.Location = new System.Drawing.Point(12, 73); this.labelDarkness.Name = "labelDarkness"; @@ -175,7 +173,6 @@ namespace Greenshot.Forms { // // labelOffset // - this.labelOffset.AutoSize = true; this.labelOffset.LanguageKey = "editor_dropshadow_offset"; this.labelOffset.Location = new System.Drawing.Point(12, 35); this.labelOffset.Name = "labelOffset"; @@ -184,7 +181,6 @@ namespace Greenshot.Forms { // // labelThickness // - this.labelThickness.AutoSize = true; this.labelThickness.LanguageKey = "editor_dropshadow_thickness"; this.labelThickness.Location = new System.Drawing.Point(12, 9); this.labelThickness.Name = "labelThickness"; @@ -194,8 +190,8 @@ namespace Greenshot.Forms { // DropShadowSettingsForm // this.AcceptButton = this.buttonOK; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.CancelButton = this.buttonCancel; this.ClientSize = new System.Drawing.Size(230, 154); this.ControlBox = false; diff --git a/Greenshot/Forms/ImageEditorForm.Designer.cs b/Greenshot/Forms/ImageEditorForm.Designer.cs index 04da3d0a0..cce905007 100644 --- a/Greenshot/Forms/ImageEditorForm.Designer.cs +++ b/Greenshot/Forms/ImageEditorForm.Designer.cs @@ -231,8 +231,8 @@ namespace Greenshot { // // topToolStripContainer // - this.topToolStripContainer.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.topToolStripContainer.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.topToolStripContainer.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.topToolStripContainer.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; // // topToolStripContainer.BottomToolStripPanel // @@ -1037,7 +1037,6 @@ namespace Greenshot { // // propertiesToolStrip // - this.propertiesToolStrip.AutoSize = false; this.propertiesToolStrip.ClickThrough = true; this.propertiesToolStrip.ImageScalingSize = coreConfiguration.ScaledIconSize; this.propertiesToolStrip.Dock = System.Windows.Forms.DockStyle.Fill; @@ -1225,7 +1224,6 @@ namespace Greenshot { // fontFamilyComboBox // this.fontFamilyComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.fontFamilyComboBox.AutoSize = false; this.fontFamilyComboBox.MaxDropDownItems = 20; this.fontFamilyComboBox.Name = "fontFamilyComboBox"; this.fontFamilyComboBox.Size = new System.Drawing.Size(200, 20); @@ -1815,8 +1813,8 @@ namespace Greenshot { // // ImageEditorForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.ClientSize = new System.Drawing.Size(785, 485); this.Controls.Add(this.topToolStripContainer); this.KeyPreview = true; diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index ab7d037f7..6e19df179 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -102,13 +102,12 @@ namespace Greenshot { propertiesToolStrip.ImageScalingSize = newSize; propertiesToolStrip.MinimumSize = new Size(150, newSize.Height + 10); - _surface.AdjustToDpi(dpi); + _surface?.AdjustToDpi(dpi); + UpdateUi(); } public ImageEditorForm(ISurface iSurface, bool outputMade) { - // Make sure we change the icon size depending on the scaling - DpiChanged += AdjustToDpi; EditorList.Add(this); // @@ -116,6 +115,8 @@ namespace Greenshot { // ManualLanguageApply = true; InitializeComponent(); + // Make sure we change the icon size depending on the scaling + DpiChanged += AdjustToDpi; Load += delegate { var thread = new Thread(AddDestinations) { @@ -236,7 +237,10 @@ namespace Greenshot { MouseWheel += PanelMouseWheel; // Make sure the value is set correctly when starting - counterUpDown.Value = Surface.CounterStart; + if (Surface != null) + { + counterUpDown.Value = Surface.CounterStart; + } ApplyLanguage(); } diff --git a/Greenshot/Forms/MainForm.Designer.cs b/Greenshot/Forms/MainForm.Designer.cs index f94f4b87d..751d43452 100644 --- a/Greenshot/Forms/MainForm.Designer.cs +++ b/Greenshot/Forms/MainForm.Designer.cs @@ -50,31 +50,30 @@ namespace Greenshot { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); this.contextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); - this.contextmenu_capturearea = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.contextmenu_capturearea = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.contextmenu_capturelastregion = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.contextmenu_capturewindow = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.contextmenu_capturefullscreen = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.contextmenu_captureie = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.toolStripListCaptureSeparator = new System.Windows.Forms.ToolStripSeparator(); this.contextmenu_capturewindowfromlist = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.contextmenu_captureiefromlist = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.toolStripOtherSourcesSeparator = new System.Windows.Forms.ToolStripSeparator(); this.contextmenu_captureclipboard = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.contextmenu_openfile = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.toolStripOpenFolderSeparator = new System.Windows.Forms.ToolStripSeparator(); this.contextmenu_openrecentcapture = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.toolStripPluginSeparator = new System.Windows.Forms.ToolStripSeparator(); this.contextmenu_quicksettings = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.contextmenu_settings = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.toolStripMiscSeparator = new System.Windows.Forms.ToolStripSeparator(); this.contextmenu_help = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.contextmenu_donate = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); this.contextmenu_about = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.contextmenu_exit = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.toolStripListCaptureSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripOtherSourcesSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripOpenFolderSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripPluginSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripMiscSeparator = new System.Windows.Forms.ToolStripSeparator(); this.toolStripCloseSeparator = new System.Windows.Forms.ToolStripSeparator(); - this.contextmenu_exit = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); - this.contextMenu.SuspendLayout(); - this.SuspendLayout(); + this.contextMenu.SuspendLayout(); + this.SuspendLayout(); // // contextMenu // @@ -250,10 +249,11 @@ namespace Greenshot { // // notifyIcon // + this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); this.notifyIcon.ContextMenuStrip = this.contextMenu; this.notifyIcon.Text = "Greenshot"; this.notifyIcon.MouseUp += new System.Windows.Forms.MouseEventHandler(this.NotifyIconClickTest); - // + // // MainForm // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index b96211a97..e7eed651e 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -245,7 +245,7 @@ namespace Greenshot { return; } // Make sure we can use forms - WindowsFormsHost.EnableWindowsFormsInterop(); + WindowsFormsHost.EnableWindowsFormsInterop(); // BUG-1809: Add message filter, to filter out all the InputLangChanged messages which go to a target control with a handle > 32 bit. Application.AddMessageFilter(new WmInputLangChangeRequestFilter()); @@ -744,7 +744,10 @@ namespace Greenshot { } - private void ContextMenuOpening(object sender, CancelEventArgs e) { + private void ContextMenuOpening(object sender, CancelEventArgs e) + { + var factor = DeviceDpi / 96f; + contextMenu.Scale(new SizeF(factor,factor)); contextmenu_captureclipboard.Enabled = ClipboardHelper.ContainsImage(); contextmenu_capturelastregion.Enabled = coreConfiguration.LastCapturedRegion != Rectangle.Empty; @@ -1025,7 +1028,7 @@ namespace Greenshot { /// <param name="e">EventArgs</param> private void Contextmenu_DonateClick(object sender, EventArgs e) { BeginInvoke((MethodInvoker)delegate { - Process.Start("http://getgreenshot.org/support/?version=" + Assembly.GetEntryAssembly().GetName().Version); + Process.Start("http://getgreenshot.org/support/?version=" + EnvironmentInfo.GetGreenshotVersion(true)); }); } diff --git a/Greenshot/Forms/MovableShowColorForm.Designer.cs b/Greenshot/Forms/MovableShowColorForm.Designer.cs index 811772d0b..4f614842a 100644 --- a/Greenshot/Forms/MovableShowColorForm.Designer.cs +++ b/Greenshot/Forms/MovableShowColorForm.Designer.cs @@ -52,7 +52,6 @@ namespace Greenshot.Forms // // label1 // - this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(40, 5); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(37, 13); @@ -69,7 +68,6 @@ namespace Greenshot.Forms // // label2 // - this.label2.AutoSize = true; this.label2.Location = new System.Drawing.Point(2, 37); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(33, 13); @@ -92,7 +90,6 @@ namespace Greenshot.Forms // // label4 // - this.label4.AutoSize = true; this.label4.Location = new System.Drawing.Point(2, 50); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(42, 13); @@ -108,7 +105,6 @@ namespace Greenshot.Forms // // label6 // - this.label6.AutoSize = true; this.label6.Location = new System.Drawing.Point(2, 63); this.label6.Name = "label6"; this.label6.Size = new System.Drawing.Size(34, 13); @@ -124,7 +120,6 @@ namespace Greenshot.Forms // // label5 // - this.label5.AutoSize = true; this.label5.Location = new System.Drawing.Point(2, 76); this.label5.Name = "label5"; this.label5.Size = new System.Drawing.Size(40, 13); @@ -156,8 +151,8 @@ namespace Greenshot.Forms // this.Visible = false; this.Location = new System.Drawing.Point(-10000,-10000); - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.ClientSize = new System.Drawing.Size(100, 100); this.Controls.Add(this.panel1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; diff --git a/Greenshot/Forms/PrintOptionsDialog.Designer.cs b/Greenshot/Forms/PrintOptionsDialog.Designer.cs index 990fedc5b..43d40c06e 100644 --- a/Greenshot/Forms/PrintOptionsDialog.Designer.cs +++ b/Greenshot/Forms/PrintOptionsDialog.Designer.cs @@ -68,7 +68,6 @@ namespace Greenshot.Forms // // checkbox_dontaskagain // - this.checkbox_dontaskagain.AutoSize = true; this.checkbox_dontaskagain.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkbox_dontaskagain.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkbox_dontaskagain.LanguageKey = "printoptions_dontaskagain"; @@ -82,7 +81,6 @@ namespace Greenshot.Forms // // checkboxAllowShrink // - this.checkboxAllowShrink.AutoSize = true; this.checkboxAllowShrink.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowShrink.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowShrink.LanguageKey = "printoptions_allowshrink"; @@ -97,7 +95,6 @@ namespace Greenshot.Forms // // checkboxAllowEnlarge // - this.checkboxAllowEnlarge.AutoSize = true; this.checkboxAllowEnlarge.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowEnlarge.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowEnlarge.LanguageKey = "printoptions_allowenlarge"; @@ -112,7 +109,6 @@ namespace Greenshot.Forms // // checkboxAllowCenter // - this.checkboxAllowCenter.AutoSize = true; this.checkboxAllowCenter.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowCenter.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowCenter.LanguageKey = "printoptions_allowcenter"; @@ -127,7 +123,6 @@ namespace Greenshot.Forms // // checkboxAllowRotate // - this.checkboxAllowRotate.AutoSize = true; this.checkboxAllowRotate.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowRotate.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowRotate.LanguageKey = "printoptions_allowrotate"; @@ -155,7 +150,6 @@ namespace Greenshot.Forms // // checkboxDateTime // - this.checkboxDateTime.AutoSize = true; this.checkboxDateTime.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxDateTime.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxDateTime.LanguageKey = "printoptions_timestamp"; @@ -182,7 +176,6 @@ namespace Greenshot.Forms // // checkboxPrintInverted // - this.checkboxPrintInverted.AutoSize = true; this.checkboxPrintInverted.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxPrintInverted.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxPrintInverted.LanguageKey = "printoptions_inverted"; @@ -197,7 +190,6 @@ namespace Greenshot.Forms // // radioBtnGrayScale // - this.radioBtnGrayScale.AutoSize = true; this.radioBtnGrayScale.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnGrayScale.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnGrayScale.LanguageKey = "printoptions_printgrayscale"; @@ -212,7 +204,6 @@ namespace Greenshot.Forms // // radioBtnMonochrome // - this.radioBtnMonochrome.AutoSize = true; this.radioBtnMonochrome.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnMonochrome.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnMonochrome.LanguageKey = "printoptions_printmonochrome"; @@ -227,7 +218,6 @@ namespace Greenshot.Forms // // groupBoxPrintLayout // - this.groupBoxPrintLayout.AutoSize = true; this.groupBoxPrintLayout.Controls.Add(this.checkboxDateTime); this.groupBoxPrintLayout.Controls.Add(this.checkboxAllowShrink); this.groupBoxPrintLayout.Controls.Add(this.checkboxAllowEnlarge); @@ -243,7 +233,6 @@ namespace Greenshot.Forms // // groupBoxColors // - this.groupBoxColors.AutoSize = true; this.groupBoxColors.Controls.Add(this.checkboxPrintInverted); this.groupBoxColors.Controls.Add(this.radioBtnColorPrint); this.groupBoxColors.Controls.Add(this.radioBtnGrayScale); @@ -258,7 +247,6 @@ namespace Greenshot.Forms // // radioBtnColorPrint // - this.radioBtnColorPrint.AutoSize = true; this.radioBtnColorPrint.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnColorPrint.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnColorPrint.LanguageKey = "printoptions_printcolor"; @@ -274,7 +262,6 @@ namespace Greenshot.Forms // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.AutoSize = true; this.ClientSize = new System.Drawing.Size(355, 390); this.Controls.Add(this.groupBoxColors); this.Controls.Add(this.groupBoxPrintLayout); diff --git a/Greenshot/Forms/ResizeSettingsForm.Designer.cs b/Greenshot/Forms/ResizeSettingsForm.Designer.cs index 0cf811fbe..f6a7fad48 100644 --- a/Greenshot/Forms/ResizeSettingsForm.Designer.cs +++ b/Greenshot/Forms/ResizeSettingsForm.Designer.cs @@ -76,7 +76,6 @@ namespace Greenshot.Forms { // // checkbox_aspectratio // - this.checkbox_aspectratio.AutoSize = true; this.checkbox_aspectratio.LanguageKey = "editor_resize_aspectratio"; this.checkbox_aspectratio.Location = new System.Drawing.Point(22, 64); this.checkbox_aspectratio.Name = "checkbox_aspectratio"; @@ -86,7 +85,6 @@ namespace Greenshot.Forms { // // label_width // - this.label_width.AutoSize = true; this.label_width.LanguageKey = "editor_resize_width"; this.label_width.Location = new System.Drawing.Point(19, 15); this.label_width.Name = "label_width"; @@ -95,7 +93,6 @@ namespace Greenshot.Forms { // // label_height // - this.label_height.AutoSize = true; this.label_height.LanguageKey = "editor_resize_height"; this.label_height.Location = new System.Drawing.Point(19, 38); this.label_height.Name = "label_height"; @@ -140,8 +137,8 @@ namespace Greenshot.Forms { // ResizeSettingsForm // this.AcceptButton = this.buttonOK; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.CancelButton = this.buttonCancel; this.ClientSize = new System.Drawing.Size(244, 122); this.ControlBox = false; diff --git a/Greenshot/Forms/SettingsForm.Designer.cs b/Greenshot/Forms/SettingsForm.Designer.cs index 473463a1e..80cbd9437 100644 --- a/Greenshot/Forms/SettingsForm.Designer.cs +++ b/Greenshot/Forms/SettingsForm.Designer.cs @@ -705,7 +705,6 @@ namespace Greenshot { // // colorButton_window_background // - this.colorButton_window_background.AutoSize = true; this.colorButton_window_background.Image = ((System.Drawing.Image)(resources.GetObject("colorButton_window_background.Image"))); this.colorButton_window_background.Location = new System.Drawing.Point(374, 37); this.colorButton_window_background.Name = "colorButton_window_background"; @@ -716,7 +715,6 @@ namespace Greenshot { // // radiobuttonWindowCapture // - this.radiobuttonWindowCapture.AutoSize = true; this.radiobuttonWindowCapture.LanguageKey = "settings_window_capture_mode"; this.radiobuttonWindowCapture.Location = new System.Drawing.Point(11, 44); this.radiobuttonWindowCapture.Name = "radiobuttonWindowCapture"; @@ -727,7 +725,6 @@ namespace Greenshot { // // radiobuttonInteractiveCapture // - this.radiobuttonInteractiveCapture.AutoSize = true; this.radiobuttonInteractiveCapture.LanguageKey = "settings_capture_windows_interactive"; this.radiobuttonInteractiveCapture.Location = new System.Drawing.Point(11, 20); this.radiobuttonInteractiveCapture.Name = "radiobuttonInteractiveCapture"; @@ -868,7 +865,6 @@ namespace Greenshot { // // groupBoxColors // - this.groupBoxColors.AutoSize = true; this.groupBoxColors.Controls.Add(this.checkboxPrintInverted); this.groupBoxColors.Controls.Add(this.radioBtnColorPrint); this.groupBoxColors.Controls.Add(this.radioBtnGrayScale); @@ -882,7 +878,6 @@ namespace Greenshot { // // checkboxPrintInverted // - this.checkboxPrintInverted.AutoSize = true; this.checkboxPrintInverted.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxPrintInverted.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxPrintInverted.LanguageKey = "printoptions_inverted"; @@ -896,7 +891,6 @@ namespace Greenshot { // // radioBtnColorPrint // - this.radioBtnColorPrint.AutoSize = true; this.radioBtnColorPrint.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnColorPrint.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnColorPrint.LanguageKey = "printoptions_printcolor"; @@ -910,7 +904,6 @@ namespace Greenshot { // // radioBtnGrayScale // - this.radioBtnGrayScale.AutoSize = true; this.radioBtnGrayScale.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnGrayScale.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnGrayScale.LanguageKey = "printoptions_printgrayscale"; @@ -925,7 +918,6 @@ namespace Greenshot { // // radioBtnMonochrome // - this.radioBtnMonochrome.AutoSize = true; this.radioBtnMonochrome.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnMonochrome.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.radioBtnMonochrome.LanguageKey = "printoptions_printmonochrome"; @@ -939,7 +931,6 @@ namespace Greenshot { // // groupBoxPrintLayout // - this.groupBoxPrintLayout.AutoSize = true; this.groupBoxPrintLayout.Controls.Add(this.checkboxDateTime); this.groupBoxPrintLayout.Controls.Add(this.checkboxAllowShrink); this.groupBoxPrintLayout.Controls.Add(this.checkboxAllowEnlarge); @@ -954,7 +945,6 @@ namespace Greenshot { // // checkboxDateTime // - this.checkboxDateTime.AutoSize = true; this.checkboxDateTime.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxDateTime.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxDateTime.LanguageKey = "printoptions_timestamp"; @@ -968,7 +958,6 @@ namespace Greenshot { // // checkboxAllowShrink // - this.checkboxAllowShrink.AutoSize = true; this.checkboxAllowShrink.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowShrink.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowShrink.LanguageKey = "printoptions_allowshrink"; @@ -982,7 +971,6 @@ namespace Greenshot { // // checkboxAllowEnlarge // - this.checkboxAllowEnlarge.AutoSize = true; this.checkboxAllowEnlarge.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowEnlarge.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowEnlarge.LanguageKey = "printoptions_allowenlarge"; @@ -996,7 +984,6 @@ namespace Greenshot { // // checkboxAllowRotate // - this.checkboxAllowRotate.AutoSize = true; this.checkboxAllowRotate.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowRotate.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowRotate.LanguageKey = "printoptions_allowrotate"; @@ -1010,7 +997,6 @@ namespace Greenshot { // // checkboxAllowCenter // - this.checkboxAllowCenter.AutoSize = true; this.checkboxAllowCenter.CheckAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowCenter.ImageAlign = System.Drawing.ContentAlignment.TopLeft; this.checkboxAllowCenter.LanguageKey = "printoptions_allowcenter"; @@ -1075,7 +1061,6 @@ namespace Greenshot { // button_pluginconfigure // this.button_pluginconfigure.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.button_pluginconfigure.AutoSize = true; this.button_pluginconfigure.Enabled = false; this.button_pluginconfigure.LanguageKey = "settings_configureplugin"; this.button_pluginconfigure.Location = new System.Drawing.Point(6, 285); @@ -1164,7 +1149,6 @@ namespace Greenshot { // // label_counter // - this.label_counter.AutoSize = true; this.label_counter.LanguageKey = "expertsettings_counter"; this.label_counter.Location = new System.Drawing.Point(7, 285); this.label_counter.Name = "label_counter"; @@ -1181,7 +1165,6 @@ namespace Greenshot { // // label_footerpattern // - this.label_footerpattern.AutoSize = true; this.label_footerpattern.LanguageKey = "expertsettings_footerpattern"; this.label_footerpattern.Location = new System.Drawing.Point(7, 259); this.label_footerpattern.Name = "label_footerpattern"; @@ -1229,7 +1212,6 @@ namespace Greenshot { // // label_clipboardformats // - this.label_clipboardformats.AutoSize = true; this.label_clipboardformats.LanguageKey = "expertsettings_clipboardformats"; this.label_clipboardformats.Location = new System.Drawing.Point(7, 39); this.label_clipboardformats.Name = "label_clipboardformats"; @@ -1273,7 +1255,6 @@ namespace Greenshot { // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.AutoSize = true; this.ClientSize = new System.Drawing.Size(451, 431); this.Controls.Add(this.tabcontrol); this.Controls.Add(this.settings_confirm); diff --git a/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs b/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs index c14ed7557..5320e17de 100644 --- a/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs +++ b/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs @@ -123,7 +123,6 @@ namespace Greenshot.Forms { // // label3 // - this.label3.AutoSize = true; this.label3.Location = new System.Drawing.Point(153, 63); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(12, 13); @@ -184,7 +183,6 @@ namespace Greenshot.Forms { // // labelDarkness // - this.labelDarkness.AutoSize = true; this.labelDarkness.LanguageKey = "editor_dropshadow_darkness"; this.labelDarkness.Location = new System.Drawing.Point(12, 97); this.labelDarkness.Name = "labelDarkness"; @@ -194,7 +192,6 @@ namespace Greenshot.Forms { // // labelOffset // - this.labelOffset.AutoSize = true; this.labelOffset.LanguageKey = "editor_dropshadow_offset"; this.labelOffset.Location = new System.Drawing.Point(12, 63); this.labelOffset.Name = "labelOffset"; @@ -203,7 +200,6 @@ namespace Greenshot.Forms { // // labelThickness // - this.labelThickness.AutoSize = true; this.labelThickness.LanguageKey = "editor_dropshadow_thickness"; this.labelThickness.Location = new System.Drawing.Point(12, 37); this.labelThickness.Name = "labelThickness"; @@ -234,7 +230,6 @@ namespace Greenshot.Forms { // // label_toothsize // - this.label_toothsize.AutoSize = true; this.label_toothsize.LanguageKey = "editor_tornedge_toothsize"; this.label_toothsize.Location = new System.Drawing.Point(12, 140); this.label_toothsize.Name = "label_toothsize"; @@ -243,7 +238,6 @@ namespace Greenshot.Forms { // // label_horizontaltoothrange // - this.label_horizontaltoothrange.AutoSize = true; this.label_horizontaltoothrange.LanguageKey = "editor_tornedge_horizontaltoothrange"; this.label_horizontaltoothrange.Location = new System.Drawing.Point(12, 166); this.label_horizontaltoothrange.Name = "label_horizontaltoothrange"; @@ -273,7 +267,6 @@ namespace Greenshot.Forms { // // labelVerticaltoothrange // - this.labelVerticaltoothrange.AutoSize = true; this.labelVerticaltoothrange.LanguageKey = "editor_tornedge_verticaltoothrange"; this.labelVerticaltoothrange.Location = new System.Drawing.Point(12, 192); this.labelVerticaltoothrange.Name = "labelVerticaltoothrange"; @@ -351,7 +344,6 @@ namespace Greenshot.Forms { // // shadowCheckbox // - this.shadowCheckbox.AutoSize = true; this.shadowCheckbox.LanguageKey = "editor_tornedge_shadow"; this.shadowCheckbox.Location = new System.Drawing.Point(12, 12); this.shadowCheckbox.Name = "shadowCheckbox"; @@ -362,7 +354,6 @@ namespace Greenshot.Forms { // // all // - this.all.AutoSize = true; this.all.LanguageKey = "editor_tornedge_all"; this.all.Location = new System.Drawing.Point(251, 12); this.all.Name = "all"; @@ -374,8 +365,8 @@ namespace Greenshot.Forms { // TornEdgeSettingsForm // this.AcceptButton = this.buttonOK; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.CancelButton = this.buttonCancel; this.ClientSize = new System.Drawing.Size(502, 223); this.ControlBox = false; diff --git a/Greenshot/GreenshotMain.cs b/Greenshot/GreenshotMain.cs index b6f448c25..6a993d99b 100644 --- a/Greenshot/GreenshotMain.cs +++ b/Greenshot/GreenshotMain.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index d8a617995..156470802 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -846,7 +846,7 @@ namespace Greenshot.Helpers { // Restore the window making sure it's visible! windowToCapture.Restore(); } else { - windowToCapture.ToForeground(false); + windowToCapture.ToForeground(); } tmpCapture = windowToCapture.CaptureGdiWindow(captureForWindow); if (tmpCapture != null) { @@ -941,7 +941,7 @@ namespace Greenshot.Helpers { } private void SetDpi() { - // Workaround for proble with DPI retrieval, the FromHwnd activates the window... + // Workaround for problem with DPI retrieval, the FromHwnd activates the window... WindowDetails previouslyActiveWindow = WindowDetails.GetActiveWindow(); // Workaround for changed DPI settings in Windows 7 var mainForm = SimpleServiceProvider.Current.GetInstance<MainForm>(); @@ -950,7 +950,7 @@ namespace Greenshot.Helpers { _capture.CaptureDetails.DpiY = graphics.DpiY; } // Set previouslyActiveWindow as foreground window - previouslyActiveWindow?.ToForeground(false); + previouslyActiveWindow?.ToForeground(); if (_capture.CaptureDetails != null) { ((Bitmap) _capture.Image)?.SetResolution(_capture.CaptureDetails.DpiX, _capture.CaptureDetails.DpiY); } diff --git a/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs b/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs index dc7991f8d..385452002 100644 --- a/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs @@ -109,7 +109,6 @@ namespace GreenshotBoxPlugin { // checkboxAfterUploadLinkToClipBoard // this.checkboxAfterUploadLinkToClipBoard.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.checkboxAfterUploadLinkToClipBoard.AutoSize = true; this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "box.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(208, 45); this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; diff --git a/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs b/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs index 3e8226dc9..80c0009b1 100644 --- a/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs @@ -106,7 +106,6 @@ namespace GreenshotDropboxPlugin { // // checkboxAfterUploadLinkToClipBoard // - this.checkboxAfterUploadLinkToClipBoard.AutoSize = true; this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "dropbox.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(116, 37); this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; diff --git a/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs b/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs index 17df962df..0a7ed7d7f 100644 --- a/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs +++ b/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs @@ -130,8 +130,8 @@ namespace GreenshotExternalCommandPlugin { // SettingsForm // this.AcceptButton = this.buttonOk; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.CancelButton = this.buttonCancel; this.ClientSize = new System.Drawing.Size(365, 208); this.Controls.Add(this.button_edit); diff --git a/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs b/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs index 200bd7a30..028efa2cd 100644 --- a/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs +++ b/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs @@ -168,8 +168,8 @@ namespace GreenshotExternalCommandPlugin { // SettingsFormDetail // this.AcceptButton = this.buttonOk; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; this.CancelButton = this.buttonCancel; this.ClientSize = new System.Drawing.Size(360, 172); diff --git a/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs b/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs index 98881585e..498e37d18 100644 --- a/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs @@ -105,7 +105,6 @@ namespace GreenshotFlickrPlugin { // // checkBoxPublic // - this.checkBoxPublic.AutoSize = true; this.checkBoxPublic.LanguageKey = "flickr.public"; this.checkBoxPublic.Location = new System.Drawing.Point(174, 88); this.checkBoxPublic.Name = "checkBoxPublic"; @@ -117,7 +116,6 @@ namespace GreenshotFlickrPlugin { // // checkBoxFamily // - this.checkBoxFamily.AutoSize = true; this.checkBoxFamily.LanguageKey = "flickr.family"; this.checkBoxFamily.Location = new System.Drawing.Point(265, 88); this.checkBoxFamily.Name = "checkBoxFamily"; @@ -129,7 +127,6 @@ namespace GreenshotFlickrPlugin { // // checkBoxFriend // - this.checkBoxFriend.AutoSize = true; this.checkBoxFriend.LanguageKey = "flickr.friend"; this.checkBoxFriend.Location = new System.Drawing.Point(350, 88); this.checkBoxFriend.Name = "checkBoxFriend"; @@ -170,7 +167,6 @@ namespace GreenshotFlickrPlugin { // // checkboxAfterUploadLinkToClipBoard // - this.checkboxAfterUploadLinkToClipBoard.AutoSize = true; this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "flickr.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(173, 116); this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; @@ -182,7 +178,6 @@ namespace GreenshotFlickrPlugin { // // checkBox_hiddenfromsearch // - this.checkBox_hiddenfromsearch.AutoSize = true; this.checkBox_hiddenfromsearch.LanguageKey = "flickr.label_HiddenFromSearch"; this.checkBox_hiddenfromsearch.Location = new System.Drawing.Point(174, 60); this.checkBox_hiddenfromsearch.Name = "checkBox_hiddenfromsearch"; diff --git a/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs b/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs index 6e9b286ae..5b38b0e65 100644 --- a/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs +++ b/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs @@ -87,7 +87,6 @@ namespace GreenshotImgurPlugin // deleteButton // this.deleteButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.deleteButton.AutoSize = true; this.deleteButton.Location = new System.Drawing.Point(109, 272); this.deleteButton.Name = "deleteButton"; this.deleteButton.Size = new System.Drawing.Size(75, 23); @@ -99,7 +98,6 @@ namespace GreenshotImgurPlugin // openButton // this.openButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.openButton.AutoSize = true; this.openButton.Location = new System.Drawing.Point(109, 305); this.openButton.Name = "openButton"; this.openButton.Size = new System.Drawing.Size(75, 23); @@ -122,7 +120,6 @@ namespace GreenshotImgurPlugin // clipboardButton // this.clipboardButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.clipboardButton.AutoSize = true; this.clipboardButton.Location = new System.Drawing.Point(109, 338); this.clipboardButton.Name = "clipboardButton"; this.clipboardButton.Size = new System.Drawing.Size(129, 23); @@ -144,8 +141,8 @@ namespace GreenshotImgurPlugin // // ImgurHistory // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.ClientSize = new System.Drawing.Size(534, 372); this.Controls.Add(this.clearHistoryButton); this.Controls.Add(this.clipboardButton); diff --git a/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs b/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs index 4888dc356..788597c39 100644 --- a/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs @@ -109,7 +109,6 @@ namespace GreenshotImgurPlugin { // // checkbox_anonymous_access // - this.checkbox_anonymous_access.AutoSize = true; this.checkbox_anonymous_access.LanguageKey = "imgur.anonymous_access"; this.checkbox_anonymous_access.Location = new System.Drawing.Point(15, 38); this.checkbox_anonymous_access.Name = "checkbox_anonymous_access"; @@ -121,7 +120,6 @@ namespace GreenshotImgurPlugin { // // checkbox_usepagelink // - this.checkbox_usepagelink.AutoSize = true; this.checkbox_usepagelink.LanguageKey = "imgur.use_page_link"; this.checkbox_usepagelink.Location = new System.Drawing.Point(15, 57); this.checkbox_usepagelink.Name = "checkbox_usepagelink"; diff --git a/GreenshotImgurPlugin/ImgurUtils.cs b/GreenshotImgurPlugin/ImgurUtils.cs index 817ff44fa..a38c12b95 100644 --- a/GreenshotImgurPlugin/ImgurUtils.cs +++ b/GreenshotImgurPlugin/ImgurUtils.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -171,12 +171,11 @@ namespace GreenshotImgurPlugin { { AuthUrlPattern = AuthUrlPattern, TokenUrl = TokenUrl, - RedirectUrl = "https://imgur.com", + RedirectUrl = "https://getgreenshot.org/oauth/imgur", CloudServiceName = "Imgur", ClientId = ImgurCredentials.CONSUMER_KEY, ClientSecret = ImgurCredentials.CONSUMER_SECRET, - AuthorizeMode = OAuth2AuthorizeMode.EmbeddedBrowser, - BrowserSize = new Size(680, 880), + AuthorizeMode = OAuth2AuthorizeMode.OutOfBoundAuto, RefreshToken = Config.RefreshToken, AccessToken = Config.AccessToken, AccessTokenExpires = Config.AccessTokenExpires @@ -280,7 +279,7 @@ namespace GreenshotImgurPlugin { /// <param name="imgurInfo"></param> public static void DeleteImgurImage(ImgurInfo imgurInfo) { Log.InfoFormat("Deleting Imgur image for {0}", imgurInfo.DeleteHash); - + try { string url = Config.ImgurApi3Url + "/image/" + imgurInfo.DeleteHash + ".xml"; HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.DELETE); diff --git a/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs b/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs index 12e85ca40..ac718241e 100644 --- a/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs +++ b/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs @@ -71,7 +71,6 @@ namespace GreenshotJiraPlugin.Forms { // // label_jirafilter // - this.label_jirafilter.AutoSize = true; this.label_jirafilter.Location = new System.Drawing.Point(14, 14); this.label_jirafilter.Name = "label_jirafilter"; this.label_jirafilter.Size = new System.Drawing.Size(52, 13); @@ -80,7 +79,6 @@ namespace GreenshotJiraPlugin.Forms { // // label_jira // - this.label_jira.AutoSize = true; this.label_jira.Location = new System.Drawing.Point(14, 41); this.label_jira.Name = "label_jira"; this.label_jira.Size = new System.Drawing.Size(30, 13); @@ -127,7 +125,6 @@ namespace GreenshotJiraPlugin.Forms { // label_filename // this.label_filename.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.label_filename.AutoSize = true; this.label_filename.Location = new System.Drawing.Point(14, 222); this.label_filename.Name = "label_filename"; this.label_filename.Size = new System.Drawing.Size(49, 13); @@ -137,7 +134,6 @@ namespace GreenshotJiraPlugin.Forms { // label_comment // this.label_comment.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.label_comment.AutoSize = true; this.label_comment.Location = new System.Drawing.Point(14, 248); this.label_comment.Name = "label_comment"; this.label_comment.Size = new System.Drawing.Size(51, 13); @@ -167,7 +163,6 @@ namespace GreenshotJiraPlugin.Forms { // label1 // this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(14, 274); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(23, 13); diff --git a/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs b/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs index 4cd900c68..a7dcc758e 100644 --- a/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs @@ -96,7 +96,6 @@ namespace GreenshotPhotobucketPlugin { // // checkbox_usepagelink // - this.checkbox_usepagelink.AutoSize = true; this.checkbox_usepagelink.LanguageKey = "photobucket.use_page_link"; this.checkbox_usepagelink.Location = new System.Drawing.Point(15, 43); this.checkbox_usepagelink.Name = "checkbox_usepagelink"; diff --git a/GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs b/GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs index 41cb346f9..0d2447e41 100644 --- a/GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs @@ -108,7 +108,6 @@ namespace GreenshotPicasaPlugin { // checkboxAfterUploadLinkToClipBoard // this.checkboxAfterUploadLinkToClipBoard.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.checkboxAfterUploadLinkToClipBoard.AutoSize = true; this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "picasa.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(197, 50); this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; diff --git a/GreenshotPlugin/Controls/BackgroundForm.Designer.cs b/GreenshotPlugin/Controls/BackgroundForm.Designer.cs index bef6439b5..fbfee52bd 100644 --- a/GreenshotPlugin/Controls/BackgroundForm.Designer.cs +++ b/GreenshotPlugin/Controls/BackgroundForm.Designer.cs @@ -55,7 +55,6 @@ namespace GreenshotPlugin.Controls // // label_pleasewait // - this.label_pleasewait.AutoSize = true; this.label_pleasewait.Dock = System.Windows.Forms.DockStyle.Fill; this.label_pleasewait.Location = new System.Drawing.Point(0, 0); this.label_pleasewait.Name = "label_pleasewait"; @@ -73,9 +72,8 @@ namespace GreenshotPlugin.Controls // // BackgroundForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSize = true; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.ClientSize = new System.Drawing.Size(169, 52); this.ControlBox = true; this.Controls.Add(this.label_pleasewait); diff --git a/GreenshotPlugin/Controls/GreenshotForm.cs b/GreenshotPlugin/Controls/GreenshotForm.cs index a7926095f..1f6ce5675 100644 --- a/GreenshotPlugin/Controls/GreenshotForm.cs +++ b/GreenshotPlugin/Controls/GreenshotForm.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -101,10 +101,10 @@ namespace GreenshotPlugin.Controls { _designTimeToolStripItems = new Dictionary<string, ToolStripItem>(); try { ITypeResolutionService typeResService = GetService(typeof(ITypeResolutionService)) as ITypeResolutionService; - + // Add a hard-path if you are using SharpDevelop // Language.AddLanguageFilePath(@"C:\Greenshot\Greenshot\Languages"); - + // this "type" Assembly currentAssembly = GetType().Assembly; if (typeResService != null) @@ -209,11 +209,11 @@ namespace GreenshotPlugin.Controls { } private void ClearChangeNotifications() { - // The m_changeService value is null when not in design mode, - // as the IComponentChangeService is only available at design time. + // The m_changeService value is null when not in design mode, + // as the IComponentChangeService is only available at design time. m_changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService)); - // Clear our the component change events to prepare for re-siting. + // Clear our the component change events to prepare for re-siting. if (m_changeService != null) { m_changeService.ComponentChanged -= OnComponentChanged; m_changeService.ComponentAdded -= OnComponentAdded; @@ -335,7 +335,7 @@ namespace GreenshotPlugin.Controls { } } } - + /// <summary> /// Helper method to cache the fieldinfo values, so we don't need to reflect all the time! /// </summary> @@ -379,8 +379,8 @@ namespace GreenshotPlugin.Controls { ApplyLanguage(applyToControl); } } - - if (DesignMode) { + + if (DesignMode) { foreach (Control designControl in _designTimeControls.Values) { ApplyLanguage(designControl); } @@ -514,7 +514,7 @@ namespace GreenshotPlugin.Controls { iniValue.Value = comboxBox.GetSelectedEnum(); iniDirty = true; } - + } } } diff --git a/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs b/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs index 572829a76..e8ca384a2 100644 --- a/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs +++ b/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs @@ -70,8 +70,8 @@ namespace GreenshotPlugin.Controls { // // OAuthLoginForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.ClientSize = new System.Drawing.Size(595, 315); this.Controls.Add(this._browser); this.Controls.Add(this._addressTextBox); diff --git a/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs b/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs index d287b3dde..c308b4b07 100644 --- a/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs +++ b/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs @@ -50,7 +50,6 @@ namespace GreenshotPlugin.Controls { // // label_pleasewait // - this.label_pleasewait.AutoSize = true; this.label_pleasewait.Dock = System.Windows.Forms.DockStyle.Fill; this.label_pleasewait.Location = new System.Drawing.Point(0, 0); this.label_pleasewait.Name = "label_pleasewait"; @@ -77,9 +76,8 @@ namespace GreenshotPlugin.Controls { // // PleaseWaitForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSize = true; + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.CancelButton = this.cancelButton; this.ClientSize = new System.Drawing.Size(169, 76); this.Controls.Add(this.cancelButton); diff --git a/GreenshotPlugin/Controls/QualityDialog.Designer.cs b/GreenshotPlugin/Controls/QualityDialog.Designer.cs index cf10c3a2e..eaf714d06 100644 --- a/GreenshotPlugin/Controls/QualityDialog.Designer.cs +++ b/GreenshotPlugin/Controls/QualityDialog.Designer.cs @@ -108,7 +108,6 @@ namespace GreenshotPlugin.Controls { // // checkBox_reduceColors // - this.checkBox_reduceColors.AutoSize = true; this.checkBox_reduceColors.Location = new System.Drawing.Point(12, 11); this.checkBox_reduceColors.Name = "checkBox_reduceColors"; this.checkBox_reduceColors.Size = new System.Drawing.Size(95, 17); @@ -116,7 +115,7 @@ namespace GreenshotPlugin.Controls { this.checkBox_reduceColors.Text = "settings_reducecolors"; this.checkBox_reduceColors.UseVisualStyleBackColor = true; // - // QualityDialog + // QualityDialog // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; diff --git a/GreenshotPlugin/Core/AbstractDestination.cs b/GreenshotPlugin/Core/AbstractDestination.cs index 886dd5dab..ba9878c23 100644 --- a/GreenshotPlugin/Core/AbstractDestination.cs +++ b/GreenshotPlugin/Core/AbstractDestination.cs @@ -155,10 +155,16 @@ namespace GreenshotPlugin.Core { TopLevel = true }; - menu.Opened += (sender, args) => - { - var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, DpiHelper.GetDpi(menu.Handle)); - menu.ImageScalingSize = scaledIconSize; + menu.Opening += (sender, args) => + { + // find the DPI settings for the screen where this is going to land + var screenDpi = DpiHelper.GetDpi(menu.Location); + var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, screenDpi); + menu.SuspendLayout(); + var fontSize = DpiHelper.ScaleWithDpi(12f, screenDpi); + menu.Font = new Font(FontFamily.GenericSansSerif, fontSize, FontStyle.Regular, GraphicsUnit.Pixel); + menu.ImageScalingSize = scaledIconSize; + menu.ResumeLayout(); }; menu.Closing += delegate(object source, ToolStripDropDownClosingEventArgs eventArgs) { @@ -191,7 +197,10 @@ namespace GreenshotPlugin.Core { menu.MouseEnter += delegate { // in case the menu has been unfocused, focus again so that dropdown menus will still open on mouseenter - if(!menu.ContainsFocus) menu.Focus(); + if (!menu.ContainsFocus) + { + menu.Focus(); + } }; foreach (IDestination destination in destinations) { // Fix foreach loop variable for the delegate diff --git a/GreenshotPlugin/Core/DpiHelper.cs b/GreenshotPlugin/Core/DpiHelper.cs index 171cf19ee..991f2897e 100644 --- a/GreenshotPlugin/Core/DpiHelper.cs +++ b/GreenshotPlugin/Core/DpiHelper.cs @@ -453,6 +453,24 @@ namespace GreenshotPlugin.Core } } + /// <summary> + /// Return the DPI for the screen which the location is located on + /// </summary> + /// <param name="location">POINT</param> + /// <returns>uint</returns> + public static uint GetDpi(POINT location) + { + RECT rect = new RECT(location.X, location.Y, 1,1); + IntPtr hMonitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONEAREST); + var result = GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY); + if (result.Succeeded()) + { + return dpiX; + } + return DefaultScreenDpi; + } + + /// <summary> /// Retrieve the DPI value for the supplied window handle /// </summary> @@ -476,7 +494,8 @@ namespace GreenshotPlugin.Core { var hMonitor = User32.MonitorFromWindow(hWnd, MonitorFrom.DefaultToNearest); // ReSharper disable once UnusedVariable - if (GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY)) + var result = GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY); + if (result.Succeeded()) { return dpiX; } @@ -544,9 +563,8 @@ namespace GreenshotPlugin.Core /// <param name="dpiX">out int for the horizontal dpi</param> /// <param name="dpiY">out int for the vertical dpi</param> /// <returns>true if all okay</returns> - [DllImport("shcore")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetDpiForMonitor(IntPtr hMonitor, MonitorDpiType dpiType, out uint dpiX, out uint dpiY); + [DllImport("shcore.dll", SetLastError = true)] + private static extern HResult GetDpiForMonitor(IntPtr hMonitor, MonitorDpiType dpiType, out uint dpiX, out uint dpiY); /// <summary> /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748621(v=vs.85).aspx">EnableNonClientDpiScaling function</a> diff --git a/GreenshotPlugin/Core/OAuthHelper.cs b/GreenshotPlugin/Core/OAuthHelper.cs index 3908a6702..ce059189f 100644 --- a/GreenshotPlugin/Core/OAuthHelper.cs +++ b/GreenshotPlugin/Core/OAuthHelper.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -32,6 +32,8 @@ using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading; +using System.Windows.Forms; +using GreenshotPlugin.Hooking; namespace GreenshotPlugin.Core { /// <summary> @@ -41,16 +43,17 @@ namespace GreenshotPlugin.Core { HMACSHA1, PLAINTEXT, } - + /// <summary> - /// Specify the autorize mode that is used to get the token from the cloud service. + /// Specify the authorize mode that is used to get the token from the cloud service. /// </summary> public enum OAuth2AuthorizeMode { - Unknown, // Will give an exception, caller needs to specify another value - LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener - MonitorTitle, // Not implemented yet: Will monitor for title changes - Pin, // Not implemented yet: Will ask the user to enter the shown PIN - EmbeddedBrowser // Will open into an embedded _browser (OAuthLoginForm), and catch the redirect + Unknown, // Will give an exception, caller needs to specify another value + LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener + MonitorTitle, // Not implemented yet: Will monitor for title changes + Pin, // Not implemented yet: Will ask the user to enter the shown PIN + EmbeddedBrowser, // Will open into an embedded _browser (OAuthLoginForm), and catch the redirect + OutOfBoundAuto } /// <summary> @@ -211,7 +214,7 @@ namespace GreenshotPlugin.Core { // // List of know and used oauth parameters' names - // + // protected const string OAUTH_CONSUMER_KEY_KEY = "oauth_consumer_key"; protected const string OAUTH_CALLBACK_KEY = "oauth_callback"; protected const string OAUTH_VERSION_KEY = "oauth_version"; @@ -395,7 +398,7 @@ namespace GreenshotPlugin.Core { } /// <summary> - /// Generate the timestamp for the signature + /// Generate the timestamp for the signature /// </summary> /// <returns></returns> public static string GenerateTimeStamp() { @@ -472,7 +475,7 @@ namespace GreenshotPlugin.Core { /// <summary> /// Get the access token /// </summary> - /// <returns>The access token.</returns> + /// <returns>The access token.</returns> private string GetAccessToken() { if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) { Exception e = new Exception("The request token and verifier were not set"); @@ -1121,12 +1124,43 @@ Greenshot received information from CloudServiceName. You can close this browser { OAuth2AuthorizeMode.LocalServer => AuthenticateViaLocalServer(settings), OAuth2AuthorizeMode.EmbeddedBrowser => AuthenticateViaEmbeddedBrowser(settings), - _ => throw new NotImplementedException($"Authorize mode '{settings.AuthorizeMode}' is not 'yet' implemented."), + OAuth2AuthorizeMode.OutOfBoundAuto => AuthenticateViaDefaultBrowser(settings), + _ => throw new NotImplementedException($"Authorize mode '{settings.AuthorizeMode}' is not 'yet' implemented."), }; return completed; } - /// <summary> + /// <summary> + /// Authenticate via the default browser + /// If this works, return the code + /// </summary> + /// <param name="settings">OAuth2Settings with the Auth / Token url etc</param> + /// <returns>true if completed, false if canceled</returns> + private static bool AuthenticateViaDefaultBrowser(OAuth2Settings settings) + { + var monitor = new WindowsTitleMonitor(); + + string[] code = new string[1]; + monitor.TitleChangeEvent += args => + { + if (args.Title.Contains(settings.State)) + { + code[0] = args.Title; + settings.Code = args.Title; + } + }; + using (var process = Process.Start(settings.FormattedAuthUrl)) + { + while (string.IsNullOrEmpty(code[0])) + { + Application.DoEvents(); + } + }; + + return true; + } + + /// <summary> /// Authenticate via an embedded browser /// If this works, return the code /// </summary> @@ -1192,7 +1226,7 @@ Greenshot received information from CloudServiceName. You can close this browser } /// <summary> - /// Check and authenticate or refresh tokens + /// Check and authenticate or refresh tokens /// </summary> /// <param name="settings">OAuth2Settings</param> public static void CheckAndAuthenticateOrRefresh(OAuth2Settings settings) { diff --git a/GreenshotPlugin/Core/WindowDetails.cs b/GreenshotPlugin/Core/WindowDetails.cs index 883c7aa1e..4fff18959 100644 --- a/GreenshotPlugin/Core/WindowDetails.cs +++ b/GreenshotPlugin/Core/WindowDetails.cs @@ -1137,46 +1137,50 @@ namespace GreenshotPlugin.Core /// <summary> /// Set the window as foreground window /// </summary> - /// <param name="handle">hWnd of the window to bring to the foreground</param> - /// <param name="workaround">bool with true to use a trick to really bring the window to the foreground</param> - public static void ToForeground(IntPtr handle, bool workaround = true) + /// <param name="hWnd">hWnd of the window to bring to the foreground</param> + public static void ToForeground(IntPtr hWnd) { - var window = new WindowDetails(handle); + var foregroundWindow = User32.GetForegroundWindow(); + if (hWnd == foregroundWindow) + { + return; + } + + var window = new WindowDetails(hWnd); // Nothing we can do if it's not visible! if (!window.Visible) { return; } + + var threadId1 = User32.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero); + var threadId2 = User32.GetWindowThreadProcessId(hWnd, IntPtr.Zero); + + // Show window in foreground. + if (threadId1 != threadId2) + { + User32.AttachThreadInput(threadId1, threadId2, 1); + User32.SetForegroundWindow(hWnd); + User32.AttachThreadInput(threadId1, threadId2, 0); + } + else + { + User32.SetForegroundWindow(hWnd); + } + + User32.BringWindowToTop(hWnd); + if (window.Iconic) { window.Iconic = false; - while (window.Iconic) - { - Application.DoEvents(); - } } - // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms633539(v=vs.85).aspx - if (workaround) - { - const byte alt = 0xA4; - const int extendedKey = 0x1; - const int keyup = 0x2; - // Simulate an "ALT" key press. - User32.keybd_event(alt, 0x45, extendedKey | 0, 0); - // Simulate an "ALT" key release. - User32.keybd_event(alt, 0x45, extendedKey | keyup, 0); - } - // Show window in forground. - User32.BringWindowToTop(handle); - User32.SetForegroundWindow(handle); } /// <summary> /// Set the window as foreground window /// </summary> - /// <param name="workaround">true to use a workaround, otherwise the window might only flash</param> - public void ToForeground(bool workaround = true) { - ToForeground(Handle, workaround); + public void ToForeground() { + ToForeground(Handle); } /// <summary> diff --git a/GreenshotPlugin/Interfaces/IDestination.cs b/GreenshotPlugin/Interfaces/IDestination.cs index 371d2b6b3..e4f39d796 100644 --- a/GreenshotPlugin/Interfaces/IDestination.cs +++ b/GreenshotPlugin/Interfaces/IDestination.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -104,8 +104,8 @@ namespace GreenshotPlugin.Interfaces { Keys EditorShortcutKeys { get; } - - /// <summary> + + /// <summary> /// Gets the dynamic destinations /// </summary> IEnumerable<IDestination> DynamicDestinations(); diff --git a/GreenshotPlugin/UnmanagedHelpers/User32.cs b/GreenshotPlugin/UnmanagedHelpers/User32.cs index 3c5a90a71..d6ae3acb1 100644 --- a/GreenshotPlugin/UnmanagedHelpers/User32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/User32.cs @@ -52,9 +52,6 @@ namespace GreenshotPlugin.UnmanagedHelpers { public const int MONITOR_DEFAULTTONEAREST = 2; public const int CURSOR_SHOWING = 0x00000001; - [DllImport("user32", SetLastError = true)] - public static extern bool keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo); - /// <summary> /// Determines whether the specified window handle identifies an existing window. /// </summary> @@ -72,6 +69,11 @@ namespace GreenshotPlugin.UnmanagedHelpers { public static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("user32", SetLastError = true)] public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId); + [DllImport("user32", SetLastError = true)] + public static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId); + [DllImport("user32")] + public static extern IntPtr AttachThreadInput(int idAttach, int idAttachTo, int fAttach); + [DllImport("user32", SetLastError = true)] public static extern IntPtr GetParent(IntPtr hWnd); [DllImport("user32", SetLastError = true)] From ffdc685e802a43c9c360eba5916f775bc059cedd Mon Sep 17 00:00:00 2001 From: jklingen <jklingen@users.noreply.github.com> Date: Sun, 1 Nov 2020 16:57:28 +0100 Subject: [PATCH 068/232] Add Explaining Comment for about_translation String --- Greenshot/Languages/language-en-US.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Greenshot/Languages/language-en-US.xml b/Greenshot/Languages/language-en-US.xml index b052785ec..1efcd15e9 100644 --- a/Greenshot/Languages/language-en-US.xml +++ b/Greenshot/Languages/language-en-US.xml @@ -9,7 +9,7 @@ Greenshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Details about the GNU General Public License:</resource> <resource name="about_title">About Greenshot</resource> - <resource name="about_translation">Info about translation</resource> + <resource name="about_translation"><!-- diplayed in about dialog, use to add credits or other translation-related info, e.g. "English translation by Jane Doe" --></resource> <resource name="application_title">Greenshot - the revolutionary screenshot utility</resource> <resource name="bugreport_cancel">Close</resource> <resource name="bugreport_info">Sorry, an unexpected error occured. From 633b31ec293997f40910733ffe25375ef369a4ac Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sat, 2 Jan 2021 21:53:47 +0100 Subject: [PATCH 069/232] THis fixes an exception when Greenshot is used via wine. --- GreenshotPlugin/Core/ImageHelper.cs | 57 +++++++++++++++++------------ 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs index 8c31eaf4c..e5e5a1b60 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -1351,22 +1351,22 @@ namespace GreenshotPlugin.Core { // Make sure both images have the same resolution newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using Graphics graphics = Graphics.FromImage(newImage); - if (fromTransparentToNon) - { - // Rule 2: Make sure the background color is white - graphics.Clear(Color.White); - } - // decide fastest copy method - if (isAreaEqual) - { - graphics.DrawImageUnscaled(sourceImage, 0, 0); - } - else - { - graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel); - } - } + using Graphics graphics = Graphics.FromImage(newImage); + if (fromTransparentToNon) + { + // Rule 2: Make sure the background color is white + graphics.Clear(Color.White); + } + // decide fastest copy method + if (isAreaEqual) + { + graphics.DrawImageUnscaled(sourceImage, 0, 0); + } + else + { + graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel); + } + } else { // Let GDI+ decide how to convert, need to test what is quicker... @@ -1374,18 +1374,27 @@ namespace GreenshotPlugin.Core { // Make sure both images have the same resolution newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); } - // Clone property items (EXIF information etc) - foreach (var propertyItem in sourceImage.PropertyItems) + + // In WINE someone getting the PropertyItems doesn't work + try { - try + // Clone property items (EXIF information etc) + foreach (var propertyItem in sourceImage.PropertyItems) { - newImage.SetPropertyItem(propertyItem); - } - catch (Exception ex) - { - Log.Warn("Problem cloning a propertyItem.", ex); + try + { + newImage.SetPropertyItem(propertyItem); + } + catch (Exception innerEx) + { + Log.Warn("Problem cloning a propertyItem.", innerEx); + } } } + catch (Exception ex) + { + Log.Warn("Problem cloning a propertyItem.", ex); + } return newImage; } From e174a9a36b382fb87b71899fac8cf35c6e061a27 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sat, 2 Jan 2021 21:54:48 +0100 Subject: [PATCH 070/232] Update of dependencies. --- Directory.Build.props | 6 +++--- Greenshot/Greenshot.csproj | 2 +- GreenshotJiraPlugin/GreenshotJiraPlugin.csproj | 3 ++- GreenshotJiraPlugin/JiraConnector.cs | 4 ++-- GreenshotPlugin/GreenshotPlugin.csproj | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 1415521cf..520eb0976 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -8,7 +8,7 @@ <PackageProjectUrl>https://github.com/greenshot/greenshot</PackageProjectUrl> <PackageLicenseUrl>https://www.gnu.org/licenses/gpl.html</PackageLicenseUrl> <PackageLicenseExpression>GPL</PackageLicenseExpression> - <LangVersion>latest</LangVersion> + <LangVersion>9</LangVersion> <UseWPF>true</UseWPF> <UseWindowsForms>true</UseWindowsForms> <RuntimeIdentifiers>win10-x64;win10-x86;win-x64;win-x86</RuntimeIdentifiers> @@ -56,7 +56,7 @@ </PropertyGroup> <ItemGroup Condition="!$(MSBuildProjectName.Contains('Tests')) And $(MSBuildProjectName.StartsWith('Greenshot'))"> - <PackageReference Include="Nerdbank.GitVersioning" Version="3.1.91"> + <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference> @@ -102,7 +102,7 @@ </Tokens> </ItemGroup> - <ItemGroup Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"> + <ItemGroup> <PackageReference Include="MSBuildTasks" Version="1.5.0.235" GeneratePathProperty="true"/> </ItemGroup> diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj index 03b68dc1b..9419fb179 100644 --- a/Greenshot/Greenshot.csproj +++ b/Greenshot/Greenshot.csproj @@ -17,7 +17,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Tools.InnoSetup" version="6.0.5" GeneratePathProperty="true" /> + <PackageReference Include="Tools.InnoSetup" version="6.1.2" GeneratePathProperty="true" /> </ItemGroup> <ItemGroup> diff --git a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj b/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj index 6901a31c5..2c4e72fe6 100644 --- a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj +++ b/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj @@ -12,6 +12,7 @@ </ItemGroup> <ItemGroup> <ProjectReference Include="..\GreenshotPlugin\GreenshotPlugin.csproj" /> - <PackageReference Include="Dapplo.Jira" version="0.9.28" /> + <PackageReference Include="Dapplo.Jira" version="1.1.21" /> + <PackageReference Include="Dapplo.Jira.SvgWinForms" Version="1.1.21" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/GreenshotJiraPlugin/JiraConnector.cs b/GreenshotJiraPlugin/JiraConnector.cs index 163771019..b836ea560 100644 --- a/GreenshotJiraPlugin/JiraConnector.cs +++ b/GreenshotJiraPlugin/JiraConnector.cs @@ -29,8 +29,8 @@ using System.Windows.Forms; using Dapplo.HttpExtensions; using Dapplo.HttpExtensions.Extensions; using Dapplo.Jira; -using Dapplo.Jira.Converters; using Dapplo.Jira.Entities; +using Dapplo.Jira.SvgWinForms.Converters; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; @@ -241,7 +241,7 @@ namespace GreenshotJiraPlugin { /// <param name="body">text</param> /// <param name="visibility">the visibility role</param> /// <param name="cancellationToken">CancellationToken</param> - public async Task AddCommentAsync(string issueKey, string body, string visibility = null, CancellationToken cancellationToken = default) + public async Task AddCommentAsync(string issueKey, string body, Visibility visibility = null, CancellationToken cancellationToken = default) { await CheckCredentialsAsync(cancellationToken); await _jiraClient.Issue.AddCommentAsync(issueKey, body, visibility, cancellationToken).ConfigureAwait(false); diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj index 461aa6c84..3caa4a7c4 100644 --- a/GreenshotPlugin/GreenshotPlugin.csproj +++ b/GreenshotPlugin/GreenshotPlugin.csproj @@ -14,7 +14,7 @@ <ItemGroup> <PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="1.0.3" /> - <PackageReference Include="log4net" version="2.0.8" /> + <PackageReference Include="log4net" version="2.0.12" /> <PackageReference Include="Svg" Version="3.1.1" /> <Reference Include="Accessibility" /> <Reference Include="CustomMarshalers" /> From 24c9b8fb36e30ae3a743ac94ce6daf7d00395e6e Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sun, 10 Jan 2021 10:33:53 +0100 Subject: [PATCH 071/232] This reduces the native code in favor of another library so there is less to maintain. --- Greenshot/Forms/MainForm.cs | 4 +- Greenshot/Helpers/CaptureHelper.cs | 14 +- .../Helpers/NotifyIconNotificationService.cs | 18 +- Greenshot/Helpers/UpdateService.cs | 2 +- .../Interfaces/INotificationService.cs | 12 +- .../GreenshotWin10Plugin.csproj | 2 +- .../Native/DesktopBridgeHelpers.cs | 53 --- .../DesktopNotificationHistoryCompat.cs | 109 ------ .../DesktopNotificationManagerCompat.cs | 164 --------- .../Native/GreenshotNotificationActivator.cs | 3 +- .../Native/INotificationActivationCallback.cs | 35 -- .../Native/NotificationActivator.cs | 35 -- .../Native/NotificationUserInput.cs | 70 ---- .../Structs/NotificationUserInputData.cs | 30 -- .../ToastNotificationService.cs | 20 +- README.md | 2 +- appveyor12.yml | 89 ----- appveyor13.yml | 92 ----- build.ps1 | 343 ------------------ prebuild.ps1 | 53 --- 20 files changed, 42 insertions(+), 1108 deletions(-) delete mode 100644 GreenshotWin10Plugin/Native/DesktopBridgeHelpers.cs delete mode 100644 GreenshotWin10Plugin/Native/DesktopNotificationHistoryCompat.cs delete mode 100644 GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs delete mode 100644 GreenshotWin10Plugin/Native/INotificationActivationCallback.cs delete mode 100644 GreenshotWin10Plugin/Native/NotificationActivator.cs delete mode 100644 GreenshotWin10Plugin/Native/NotificationUserInput.cs delete mode 100644 GreenshotWin10Plugin/Native/Structs/NotificationUserInputData.cs delete mode 100644 appveyor12.yml delete mode 100644 appveyor13.yml delete mode 100644 build.ps1 delete mode 100644 prebuild.ps1 diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index e7eed651e..61f5141bd 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -451,7 +451,7 @@ namespace Greenshot { case CommandEnum.FirstLaunch: LOG.Info("FirstLaunch: Created new configuration, showing balloon."); var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance<INotificationService>(); - notifyIconClassicMessageHandler.ShowInfoMessage(Language.GetFormattedString(LangKey.tooltip_firststart, HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.RegionHotkey)), 2000, ShowSetting); + notifyIconClassicMessageHandler.ShowInfoMessage(Language.GetFormattedString(LangKey.tooltip_firststart, HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.RegionHotkey)), TimeSpan.FromMinutes(10), ShowSetting); break; case CommandEnum.ReloadConfig: LOG.Info("Reload requested"); @@ -901,7 +901,7 @@ namespace Greenshot { } private void ShowThumbnailOnEnter(object sender, EventArgs e) { - if (!(sender is ToolStripMenuItem captureWindowItem)) return; + if (sender is not ToolStripMenuItem captureWindowItem) return; WindowDetails window = captureWindowItem.Tag as WindowDetails; if (_thumbnailForm == null) { _thumbnailForm = new ThumbnailForm(); diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index 156470802..42f28e4ad 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -516,10 +516,10 @@ namespace Greenshot.Helpers { /// </summary> /// <param name="e">SurfaceMessageEventArgs</param> private void OpenCaptureOnClick(SurfaceMessageEventArgs e) { - var notifyIcon = SimpleServiceProvider.Current.GetInstance<NotifyIcon>(); - if (!(notifyIcon.Tag is SurfaceMessageEventArgs eventArgs)) { + var notifyIcon = SimpleServiceProvider.Current.GetInstance<NotifyIcon>(); + if (notifyIcon.Tag is not SurfaceMessageEventArgs eventArgs) { Log.Warn("OpenCaptureOnClick called without SurfaceMessageEventArgs"); - return; + return; } ISurface surface = eventArgs.Surface; if (surface != null) @@ -549,18 +549,18 @@ namespace Greenshot.Helpers { var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance<INotificationService>(); switch (eventArgs.MessageType) { case SurfaceMessageTyp.Error: - notifyIconClassicMessageHandler.ShowErrorMessage(eventArgs.Message, 10000); + notifyIconClassicMessageHandler.ShowErrorMessage(eventArgs.Message, TimeSpan.FromHours(1)); break; case SurfaceMessageTyp.Info: - notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, 10000, () => - { + notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, TimeSpan.FromHours(1), () => + { Log.Info("Clicked!"); }); break; case SurfaceMessageTyp.FileSaved: case SurfaceMessageTyp.UploadedUri: // Show a balloon and register an event handler to open the "capture" for if someone clicks the balloon. - notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, 10000, () => OpenCaptureOnClick(eventArgs)); + notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, TimeSpan.FromHours(1), () => OpenCaptureOnClick(eventArgs)); break; } } diff --git a/Greenshot/Helpers/NotifyIconNotificationService.cs b/Greenshot/Helpers/NotifyIconNotificationService.cs index e5d49a643..7398a7890 100644 --- a/Greenshot/Helpers/NotifyIconNotificationService.cs +++ b/Greenshot/Helpers/NotifyIconNotificationService.cs @@ -46,10 +46,10 @@ namespace Greenshot.Helpers /// This will show a warning message to the user /// </summary> /// <param name="message">string</param> - /// <param name="timeout"></param> + /// <param name="timeout">TimeSpan</param> /// <param name="onClickAction">Action called if the user clicks the notification</param> /// <param name="onClosedAction">Action</param> - public void ShowWarningMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + public void ShowWarningMessage(string message, TimeSpan? timeout = null, Action onClickAction = null, Action onClosedAction = null) { ShowMessage(message, timeout, ToolTipIcon.Warning, onClickAction, onClosedAction); } @@ -58,10 +58,10 @@ namespace Greenshot.Helpers /// This will show an error message to the user /// </summary> /// <param name="message">string</param> - /// <param name="timeout"></param> + /// <param name="timeout">TimeSpan</param> /// <param name="onClickAction">Action called if the user clicks the notification</param> /// <param name="onClosedAction">Action</param> - public void ShowErrorMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + public void ShowErrorMessage(string message, TimeSpan? timeout = null, Action onClickAction = null, Action onClosedAction = null) { ShowMessage(message, timeout, ToolTipIcon.Error, onClickAction, onClosedAction); } @@ -70,10 +70,10 @@ namespace Greenshot.Helpers /// This will show an info message to the user /// </summary> /// <param name="message">string</param> - /// <param name="timeout">int</param> + /// <param name="timeout">TimeSpan</param> /// <param name="onClickAction">Action called if the user clicks the notification</param> /// <param name="onClosedAction">Action</param> - public void ShowInfoMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + public void ShowInfoMessage(string message, TimeSpan? timeout = null, Action onClickAction = null, Action onClosedAction = null) { ShowMessage(message, timeout, ToolTipIcon.Info, onClickAction, onClosedAction); } @@ -82,11 +82,11 @@ namespace Greenshot.Helpers /// This will show a message to the user /// </summary> /// <param name="message">string</param> - /// <param name="timeout">int</param> + /// <param name="timeout">TimeSpan</param> /// <param name="level">ToolTipIcon</param> /// <param name="onClickAction">Action</param> /// <param name="onClosedAction">Action</param> - private void ShowMessage(string message, int timeout, ToolTipIcon level, Action onClickAction = null, Action onClosedAction = null) { + private void ShowMessage(string message, TimeSpan? timeout = null, ToolTipIcon level = ToolTipIcon.Info, Action onClickAction = null, Action onClosedAction = null) { // Do not inform the user if this is disabled if (!CoreConfiguration.ShowTrayNotification) { @@ -128,7 +128,7 @@ namespace Greenshot.Helpers _notifyIcon.BalloonTipClicked -= BalloonClickedHandler; } _notifyIcon.BalloonTipClosed += BalloonClosedHandler; - _notifyIcon.ShowBalloonTip(timeout, @"Greenshot", message, level); + _notifyIcon.ShowBalloonTip(timeout.HasValue ? (int)timeout.Value.TotalMilliseconds : 5000, @"Greenshot", message, level); } } } diff --git a/Greenshot/Helpers/UpdateService.cs b/Greenshot/Helpers/UpdateService.cs index d1f755472..ceb3488be 100644 --- a/Greenshot/Helpers/UpdateService.cs +++ b/Greenshot/Helpers/UpdateService.cs @@ -198,7 +198,7 @@ namespace Greenshot.Helpers { var notificationService = SimpleServiceProvider.Current.GetInstance<INotificationService>(); var message = Language.GetFormattedString(LangKey.update_found, newVersion.ToString()); - notificationService.ShowInfoMessage(message, 10000, () => Process.Start(Downloads.AbsoluteUri)); + notificationService.ShowInfoMessage(message, TimeSpan.FromHours(1), () => Process.Start(Downloads.AbsoluteUri)); } /// <summary> diff --git a/GreenshotPlugin/Interfaces/INotificationService.cs b/GreenshotPlugin/Interfaces/INotificationService.cs index 922d718ba..c1342b5e4 100644 --- a/GreenshotPlugin/Interfaces/INotificationService.cs +++ b/GreenshotPlugin/Interfaces/INotificationService.cs @@ -32,27 +32,27 @@ namespace GreenshotPlugin.Interfaces /// This will show a warning message to the user /// </summary> /// <param name="message">string</param> - /// <param name="timeout"></param> + /// <param name="timeout">TimeSpan</param> /// <param name="onClickAction">Action called if the user clicks the notification</param> /// <param name="onClosedAction">Action</param> - void ShowWarningMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null); + void ShowWarningMessage(string message, TimeSpan? timeout = null, Action onClickAction = null, Action onClosedAction = null); /// <summary> /// This will show an error message to the user /// </summary> /// <param name="message">string</param> - /// <param name="timeout"></param> + /// <param name="timeout">TimeSpan</param> /// <param name="onClickAction">Action called if the user clicks the notification</param> /// <param name="onClosedAction">Action</param> - void ShowErrorMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null); + void ShowErrorMessage(string message, TimeSpan? timeout = null, Action onClickAction = null, Action onClosedAction = null); /// <summary> /// This will show an info message to the user /// </summary> /// <param name="message">string</param> - /// <param name="timeout">int</param> + /// <param name="timeout">TimeSpan</param> /// <param name="onClickAction">Action called if the user clicks the notification</param> /// <param name="onClosedAction">Action</param> - void ShowInfoMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null); + void ShowInfoMessage(string message, TimeSpan? timeout = null, Action onClickAction = null, Action onClosedAction = null); } } \ No newline at end of file diff --git a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj b/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj index a17df050e..00229a0ab 100644 --- a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj +++ b/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj @@ -12,7 +12,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.Windows.SDK.Contracts" version="10.0.17763.1000" /> + <PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" version="6.1.1" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\GreenshotPlugin\GreenshotPlugin.csproj" /> diff --git a/GreenshotWin10Plugin/Native/DesktopBridgeHelpers.cs b/GreenshotWin10Plugin/Native/DesktopBridgeHelpers.cs deleted file mode 100644 index 0c7728ee0..000000000 --- a/GreenshotWin10Plugin/Native/DesktopBridgeHelpers.cs +++ /dev/null @@ -1,53 +0,0 @@ -// ****************************************************************** -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. -// ****************************************************************** - -using System.Runtime.InteropServices; -using System.Text; -using GreenshotPlugin.Core; - -namespace GreenshotWin10Plugin.Native -{ - /// <summary> - /// Code from https://github.com/qmatteoq/DesktopBridgeHelpers/edit/master/DesktopBridge.Helpers/Helpers.cs - /// </summary> - public static class DesktopBridgeHelpers - { - const long AppModelErrorNoPackage = 15700L; - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName); - - private static bool? _isRunningAsUwp; - public static bool IsRunningAsUwp() - { - if (_isRunningAsUwp != null) return _isRunningAsUwp.Value; - - if (WindowsVersion.IsWindows7OrLower) - { - _isRunningAsUwp = false; - } - else - { - int length = 0; - StringBuilder sb = new StringBuilder(0); - GetCurrentPackageFullName(ref length, sb); - - sb = new StringBuilder(length); - int result = GetCurrentPackageFullName(ref length, sb); - - _isRunningAsUwp = result != AppModelErrorNoPackage; - } - - return _isRunningAsUwp.Value; - } - } -} diff --git a/GreenshotWin10Plugin/Native/DesktopNotificationHistoryCompat.cs b/GreenshotWin10Plugin/Native/DesktopNotificationHistoryCompat.cs deleted file mode 100644 index f536755ab..000000000 --- a/GreenshotWin10Plugin/Native/DesktopNotificationHistoryCompat.cs +++ /dev/null @@ -1,109 +0,0 @@ -// ****************************************************************** -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. -// ****************************************************************** - -using System.Collections.Generic; -using Windows.UI.Notifications; - -namespace GreenshotWin10Plugin.Native -{ - /// <summary> - /// Manages the toast notifications for an app including the ability the clear all toast history and removing individual toasts. - /// </summary> - public sealed class DesktopNotificationHistoryCompat - { - private readonly string _applicationUserModelId; - private readonly ToastNotificationHistory _history; - - /// <summary> - /// Do not call this. Instead, call <see cref="DesktopNotificationManagerCompat.History"/> to obtain an instance. - /// </summary> - /// <param name="applicationUserModelId"></param> - internal DesktopNotificationHistoryCompat(string applicationUserModelId) - { - _applicationUserModelId = applicationUserModelId; - _history = ToastNotificationManager.History; - } - - /// <summary> - /// Removes all notifications sent by this app from action center. - /// </summary> - public void Clear() - { - if (_applicationUserModelId != null) - { - _history.Clear(_applicationUserModelId); - } - else - { - _history.Clear(); - } - } - - /// <summary> - /// Gets all notifications sent by this app that are currently still in Action Center. - /// </summary> - /// <returns>A collection of toasts.</returns> - public IReadOnlyList<ToastNotification> GetHistory() - { - return _applicationUserModelId != null ? _history.GetHistory(_applicationUserModelId) : _history.GetHistory(); - } - - /// <summary> - /// Removes an individual toast, with the specified tag label, from action center. - /// </summary> - /// <param name="tag">The tag label of the toast notification to be removed.</param> - public void Remove(string tag) - { - if (_applicationUserModelId != null) - { - _history.Remove(tag, string.Empty, _applicationUserModelId); - } - else - { - _history.Remove(tag); - } - } - - /// <summary> - /// Removes a toast notification from the action using the notification's tag and group labels. - /// </summary> - /// <param name="tag">The tag label of the toast notification to be removed.</param> - /// <param name="group">The group label of the toast notification to be removed.</param> - public void Remove(string tag, string group) - { - if (_applicationUserModelId != null) - { - _history.Remove(tag, group, _applicationUserModelId); - } - else - { - _history.Remove(tag, group); - } - } - - /// <summary> - /// Removes a group of toast notifications, identified by the specified group label, from action center. - /// </summary> - /// <param name="group">The group label of the toast notifications to be removed.</param> - public void RemoveGroup(string group) - { - if (_applicationUserModelId != null) - { - _history.RemoveGroup(group, _applicationUserModelId); - } - else - { - _history.RemoveGroup(group); - } - } - } -} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs b/GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs deleted file mode 100644 index a30c0ff3e..000000000 --- a/GreenshotWin10Plugin/Native/DesktopNotificationManagerCompat.cs +++ /dev/null @@ -1,164 +0,0 @@ -// ****************************************************************** -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. -// ****************************************************************** - -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Windows.UI.Notifications; - -namespace GreenshotWin10Plugin.Native -{ - public static class DesktopNotificationManagerCompat - { - public const string TOAST_ACTIVATED_LAUNCH_ARG = "-ToastActivated"; - - private static bool _registeredAumidAndComServer; - private static string _applicationUserModelId; - private static bool _registeredActivator; - - /// <summary> - /// If not running under the Desktop Bridge, you must call this method to register your applicationUserModelId (AUMID) with the Compat library and to - /// register your COM CLSID and EXE in LocalServer32 registry. Feel free to call this regardless, and we will no-op if running - /// under Desktop Bridge. Call this upon application startup, before calling any other APIs. - /// </summary> - /// <param name="applicationUserModelId">An applicationUserModelId (AUMID) that uniquely identifies your application.</param> - public static void RegisterAumidAndComServer<T>(string applicationUserModelId) where T : NotificationActivator - { - if (string.IsNullOrWhiteSpace(applicationUserModelId)) - { - throw new ArgumentException("You must provide an Application User Model Id (AUMID).", nameof(applicationUserModelId)); - } - - // If running as Desktop Bridge - if (DesktopBridgeHelpers.IsRunningAsUwp()) - { - // Clear the AUMID since Desktop Bridge doesn't use it, and then we're done. - // Desktop Bridge apps are registered with platform through their manifest. - // Their LocalServer32 key is also registered through their manifest. - _applicationUserModelId = null; - _registeredAumidAndComServer = true; - return; - } - - _applicationUserModelId = applicationUserModelId; - - string exePath = Process.GetCurrentProcess().MainModule?.FileName; - if (exePath != null) - { - RegisterComServer<T>(exePath); - } - - _registeredAumidAndComServer = true; - } - - /// <summary> - /// Register the application an a com server - /// </summary> - /// <typeparam name="T">type to register for</typeparam> - /// <param name="exePath">string</param> - private static void RegisterComServer<T>(string exePath) where T : NotificationActivator - { - // We register the EXE to start up when the notification is activated - var guid = typeof(T).GUID; - if (guid == null) - { - throw new ArgumentException("You must provide an Guid on your NotificationActivator."); - } - string regString = $"SOFTWARE\\Classes\\CLSID\\{{{guid}}}\\LocalServer32"; - using var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(regString); - - // Include a flag so we know this was a toast activation and should wait for COM to process - // We also wrap EXE path in quotes for extra security - key?.SetValue(null, '"' + exePath + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG); - } - - /// <summary> - /// Registers the activator type as a COM server client so that Windows can launch your activator. - /// </summary> - /// <typeparam name="T">Your implementation of NotificationActivator. Must have GUID and ComVisible attributes on class.</typeparam> - public static void RegisterActivator<T>() where T : NotificationActivator - { - // Register type - var regService = new RegistrationServices(); - - regService.RegisterTypeForComClients(typeof(T), RegistrationClassContext.LocalServer, RegistrationConnectionType.MultipleUse); - - _registeredActivator = true; - } - - /// <summary> - /// Creates a toast notifier. You must have called <see cref="RegisterActivator{T}"/> first (and also <see cref="RegisterAumidAndComServer{T}"/> if you're a classic Win32 app), or this will throw an exception. - /// </summary> - /// <returns>ToastNotifier</returns> - public static ToastNotifier CreateToastNotifier() - { - EnsureRegistered(); - - if (_applicationUserModelId != null) - { - // Non-Desktop Bridge - return ToastNotificationManager.CreateToastNotifier(_applicationUserModelId); - } - - // Desktop Bridge - return ToastNotificationManager.CreateToastNotifier(); - } - - /// <summary> - /// Gets the <see cref="DesktopNotificationHistoryCompat"/> object. You must have called <see cref="RegisterActivator{T}"/> first (and also <see cref="RegisterAumidAndComServer{T}"/> if you're a classic Win32 app), or this will throw an exception. - /// </summary> - public static DesktopNotificationHistoryCompat History - { - get - { - EnsureRegistered(); - - return new DesktopNotificationHistoryCompat(_applicationUserModelId); - } - } - - /// <summary> - /// Checks if the AUMID is correctly registered, if not this throws an exception - /// </summary> - private static void EnsureRegistered() - { - // If not registered AUMID yet - if (!_registeredAumidAndComServer) - { - // Check if Desktop Bridge - if (DesktopBridgeHelpers.IsRunningAsUwp()) - { - // Implicitly registered, all good! - _registeredAumidAndComServer = true; - } - - else - { - // Otherwise, incorrect usage - throw new Exception("You must call RegisterAumidAndComServer first."); - } - } - - // If not registered activator yet - if (!_registeredActivator) - { - // Incorrect usage - throw new Exception("You must call RegisterActivator first."); - } - } - - /// <summary> - /// Gets a boolean representing whether http images can be used within toasts. This is true if running under Desktop Bridge. - /// </summary> - public static bool CanUseHttpImages => DesktopBridgeHelpers.IsRunningAsUwp(); - } -} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs b/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs index d2da5f4c9..a892e20f4 100644 --- a/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs +++ b/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs @@ -21,6 +21,7 @@ using System.Runtime.InteropServices; using log4net; +using Microsoft.Toolkit.Uwp.Notifications; namespace GreenshotWin10Plugin.Native { @@ -28,7 +29,7 @@ namespace GreenshotWin10Plugin.Native /// This implements the NotificationActivator /// </summary> [ClassInterface(ClassInterfaceType.None)] - [ComSourceInterfaces(typeof(INotificationActivationCallback))] + [ComSourceInterfaces(typeof(NotificationActivator.INotificationActivationCallback))] [Guid("F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08"), ComVisible(true)] public class GreenshotNotificationActivator : NotificationActivator { diff --git a/GreenshotWin10Plugin/Native/INotificationActivationCallback.cs b/GreenshotWin10Plugin/Native/INotificationActivationCallback.cs deleted file mode 100644 index 59dd61443..000000000 --- a/GreenshotWin10Plugin/Native/INotificationActivationCallback.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ****************************************************************** -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. -// ****************************************************************** - -using System.Runtime.InteropServices; -using GreenshotWin10Plugin.Native.Structs; - -namespace GreenshotWin10Plugin.Native -{ - /// <summary> - /// This is the interface which allows your notifications to be clicked, which active the application - /// </summary> - [ComImport, Guid("53E31837-6600-4A81-9395-75CFFE746F94"), - ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface INotificationActivationCallback - { - void Activate( - [In, MarshalAs(UnmanagedType.LPWStr)] - string appUserModelId, - [In, MarshalAs(UnmanagedType.LPWStr)] - string invokedArgs, - [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] - NotificationUserInputData[] data, - [In, MarshalAs(UnmanagedType.U4)] - uint dataCount); - } -} diff --git a/GreenshotWin10Plugin/Native/NotificationActivator.cs b/GreenshotWin10Plugin/Native/NotificationActivator.cs deleted file mode 100644 index bedf3f5f4..000000000 --- a/GreenshotWin10Plugin/Native/NotificationActivator.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ****************************************************************** -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. -// ****************************************************************** - -using GreenshotWin10Plugin.Native.Structs; - -namespace GreenshotWin10Plugin.Native -{ - /// <summary> - /// Apps must implement this activator to handle notification activation. - /// </summary> - public abstract class NotificationActivator : INotificationActivationCallback - { - public void Activate(string appUserModelId, string invokedArgs, NotificationUserInputData[] data, uint dataCount) - { - OnActivated(invokedArgs, new NotificationUserInput(data), appUserModelId); - } - - /// <summary> - /// This method will be called when the user clicks on a foreground or background activation on a toast. Parent app must implement this method. - /// </summary> - /// <param name="arguments">The arguments from the original notification. This is either the launch argument if the user clicked the body of your toast, or the arguments from a button on your toast.</param> - /// <param name="userInput">Text and selection values that the user entered in your toast.</param> - /// <param name="appUserModelId">Your AUMID.</param> - public abstract void OnActivated(string arguments, NotificationUserInput userInput, string appUserModelId); - } -} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Native/NotificationUserInput.cs b/GreenshotWin10Plugin/Native/NotificationUserInput.cs deleted file mode 100644 index 57b184c70..000000000 --- a/GreenshotWin10Plugin/Native/NotificationUserInput.cs +++ /dev/null @@ -1,70 +0,0 @@ -// ****************************************************************** -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. -// ****************************************************************** - -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using GreenshotWin10Plugin.Native.Structs; - -namespace GreenshotWin10Plugin.Native -{ - /// <summary> - /// Text and selection values that the user entered on your notification. The Key is the ID of the input, and the Value is what the user entered. - /// </summary> - public class NotificationUserInput : IReadOnlyDictionary<string, string> - { - private readonly NotificationUserInputData[] _notificationUserInputData; - - internal NotificationUserInput(NotificationUserInputData[] notificationUserInputData) - { - _notificationUserInputData = notificationUserInputData; - } - - public string this[string key] => _notificationUserInputData.First(i => i.Key == key).Value; - - public IEnumerable<string> Keys => _notificationUserInputData.Select(i => i.Key); - - public IEnumerable<string> Values => _notificationUserInputData.Select(i => i.Value); - - public int Count => _notificationUserInputData.Length; - - public bool ContainsKey(string key) - { - return _notificationUserInputData.Any(i => i.Key == key); - } - - public IEnumerator<KeyValuePair<string, string>> GetEnumerator() - { - return _notificationUserInputData.Select(i => new KeyValuePair<string, string>(i.Key, i.Value)).GetEnumerator(); - } - - public bool TryGetValue(string key, out string value) - { - foreach (var item in _notificationUserInputData) - { - if (item.Key == key) - { - value = item.Value; - return true; - } - } - - value = null; - return false; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Native/Structs/NotificationUserInputData.cs b/GreenshotWin10Plugin/Native/Structs/NotificationUserInputData.cs deleted file mode 100644 index 357aaa378..000000000 --- a/GreenshotWin10Plugin/Native/Structs/NotificationUserInputData.cs +++ /dev/null @@ -1,30 +0,0 @@ -// ****************************************************************** -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License (MIT). -// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH -// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. -// ****************************************************************** - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotWin10Plugin.Native.Structs -{ - /// <summary> - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/notificationactivationcallback/ns-notificationactivationcallback-notification_user_input_data">NOTIFICATION_USER_INPUT_DATA structure</a> - /// </summary> - [StructLayout(LayoutKind.Sequential), Serializable] - public struct NotificationUserInputData - { - [MarshalAs(UnmanagedType.LPWStr)] - public string Key; - - [MarshalAs(UnmanagedType.LPWStr)] - public string Value; - } -} diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/GreenshotWin10Plugin/ToastNotificationService.cs index 5f51d7fd6..4b41f6f61 100644 --- a/GreenshotWin10Plugin/ToastNotificationService.cs +++ b/GreenshotWin10Plugin/ToastNotificationService.cs @@ -30,6 +30,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotWin10Plugin.Native; using log4net; +using Microsoft.Toolkit.Uwp.Notifications; namespace GreenshotWin10Plugin { @@ -69,10 +70,10 @@ namespace GreenshotWin10Plugin /// This creates the actual toast /// </summary> /// <param name="message">string</param> - /// <param name="timeout">milliseconds until the toast timeouts</param> + /// <param name="timeout">TimeSpan until the toast timeouts</param> /// <param name="onClickAction">Action called when clicked</param> /// <param name="onClosedAction">Action called when the toast is closed</param> - private void ShowMessage(string message, int timeout, Action onClickAction, Action onClosedAction) + private void ShowMessage(string message, TimeSpan? timeout = default, Action onClickAction = null, Action onClosedAction = null) { // Do not inform the user if this is disabled if (!CoreConfiguration.ShowTrayNotification) @@ -118,7 +119,7 @@ namespace GreenshotWin10Plugin var toast = new ToastNotification(toastXml) { // Windows 10 first with 1903: ExpiresOnReboot = true, - ExpirationTime = timeout > 0 ? DateTimeOffset.Now.AddMilliseconds(timeout) : (DateTimeOffset?)null + ExpirationTime = timeout.HasValue ? DateTimeOffset.Now.Add(timeout.Value) : (DateTimeOffset?)null }; void ToastActivatedHandler(ToastNotification toastNotification, object sender) @@ -142,7 +143,11 @@ namespace GreenshotWin10Plugin void ToastDismissedHandler(ToastNotification toastNotification, ToastDismissedEventArgs eventArgs) { - Log.Debug("Toast closed"); + Log.Debug($"Toast closed with reason {eventArgs.Reason}"); + if (eventArgs.Reason != ToastDismissalReason.UserCanceled) + { + return; + } try { onClosedAction?.Invoke(); @@ -156,6 +161,7 @@ namespace GreenshotWin10Plugin // Remove the other handler too toast.Activated -= ToastActivatedHandler; toast.Failed -= ToastOnFailed; + } toast.Dismissed += ToastDismissedHandler; toast.Failed += ToastOnFailed; @@ -175,17 +181,17 @@ namespace GreenshotWin10Plugin Log.Debug(sender.Content.GetXml()); } - public void ShowWarningMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + public void ShowWarningMessage(string message, TimeSpan? timeout = null, Action onClickAction = null, Action onClosedAction = null) { ShowMessage(message, timeout, onClickAction, onClosedAction); } - public void ShowErrorMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + public void ShowErrorMessage(string message, TimeSpan? timeout = null, Action onClickAction = null, Action onClosedAction = null) { ShowMessage(message, timeout, onClickAction, onClosedAction); } - public void ShowInfoMessage(string message, int timeout, Action onClickAction = null, Action onClosedAction = null) + public void ShowInfoMessage(string message, TimeSpan? timeout = null, Action onClickAction = null, Action onClosedAction = null) { ShowMessage(message, timeout, onClickAction, onClosedAction); } diff --git a/README.md b/README.md index 4f29e36a2..29ef417c7 100644 --- a/README.md +++ b/README.md @@ -21,4 +21,4 @@ Being easy to understand and configurable, Greenshot is an efficient tool for pr About this repository --------------------- -This repository is for Greenshot 1.2.10, which is a bugfix of 1.2.9.129 +This repository is for Greenshot 1.3 diff --git a/appveyor12.yml b/appveyor12.yml deleted file mode 100644 index 112aff0be..000000000 --- a/appveyor12.yml +++ /dev/null @@ -1,89 +0,0 @@ -version: 1.2.10.{build} -branches: - only: - - release/1.2.10 -skip_tags: true -configuration: Release -platform: Any CPU -shallow_clone: true -clone_depth: 1 -assembly_info: - patch: true - file: '**\AssemblyInfo.*' - assembly_version: '{version}' - assembly_file_version: '{version}' - assembly_informational_version: '{version}-$(build_type)-$(APPVEYOR_REPO_COMMIT)' -environment: - credentials_box_client_id: - secure: 8MKxTOowo2fat6cNXGbFfvn6typiEtmCKsrptrWiEFUEoKlT1DUn40iGNcIELRA1 - credentials_box_client_secret: - secure: hJhzDVJuGd/WMnoSXhosvOM/1PGcYlKbtQjA6xyrmnmZcqCTMzqIdA6JXlo/V2Br - credentials_dropbox_consumer_key: - secure: Da/6KY1cu9CUM3iOqSpcUw== - credentials_dropbox_consumer_secret: - secure: KkyKyUY+buT/MZagXDP4cw== - credentials_flickr_consumer_key: - secure: fY8s0OkOMYwCjSZoL/6yZcP8xeT6J2EJLjbUMI5lAW42S5QT2U2B41KrmeP2NpnQ - credentials_flickr_consumer_secret: - secure: 9TthlljPHXWPkDDeG3uiFVJ9YJwHZOV0ZsojaIBBuvw= - credentials_imgur_consumer_key: - secure: XRTg1Ecs6ER9m4779CJAng== - credentials_imgur_consumer_secret: - secure: gcCp/gJF8vqmnCUPKyb04H8Oz9mWmiB00U5X7iI/DGr5mxjoCG1khc6/zn6aSSqn - credentials_photobucket_consumer_key: - secure: oo9GD1Y8dkrli6hMfnnYsw== - credentials_photobucket_consumer_secret: - secure: GiNPoe9klM/YkoHIA/YHqOYrIaYwSFK7Ph9m8jT9uPP1l6+Hd5K8dVMw5DNa50oG - credentials_picasa_consumer_key: - secure: bjKXhFZkDqaq98XBrz5oQKQfT8CLpuv2ZAiBIwkzloaAPUs97b5yx6h/xFaE4NLS - credentials_picasa_consumer_secret: - secure: yNptTpmJWypbu9alOQtetxU66drr2FKxoPflNgRJdag= - build_type: RELEASE - rsakey: - secure: GNomwdlwZOCyd8d7xEWTnMVs1lpOeHvF+tlnvcbXGovLRtwAp2Ufu0r7paGY7BHGGkIs2WE7xUfyQ9UauVB+58JZ6fwVega8ucUgVJhl4x0QQNN2d6sULUhHfhuEHmxw+FDO/FxKFE6Lmf+ZRY+OGiw0wKIl4qD7mGRHcDQTipNEsTbau8HzqRVCdu3dx7pODC61DlsbO71xLF7UlqnmuZE+91Zz3V6AgaqE246n1499d6bXBYw1AH+8opNnKDFLnTHf7hUVcZn9mj6tKZXeTCuVUOr/SVQcgHKxlBlqzhfaEkxCR5GPtzQRqwDMxEycmFvj2wNP/sie6UEGhQxE4YMCc2OgqNOkpc5BbP/fxLr/SLFOEf1XXzTWCFMhsgpHx7TZbgQH26sa0rK/xaBRacZlwAaNk7V2nFZT7TebYEFy6zWNr9Y+IyeXIofj42XQTNXv8d8hyh+UYLByVEFYRf2DnActQkZQyNdWjZ+CxDV50QSZZs8FT3IIqraHYKsj2ITAN5LrUtWCi7bpNJL0UGo0EJiB2i0bp++tEAAwyrCljxI8d4bbGl/flHk/xd+ysQPnomndijeObjguEzqT8pyXZluSZhF+lI50mIDhMdtdAfMi5yn5RW7P6NWOSlC8xgQQgMZylsuSvRflKbEd/gsoDyEOnakNcdH2jekt9OD6GnuYM7iHkbMC89LBZ0VaHNGvCC+BQXdGUG7O9R3NthZcDXE7q7xbtGRB5ncVQDRfKoT5HVfiV6bSDrcfRODiuR59mZgiSYtZG+3kQWYUKn2wagvZKckGukA0SlOuTRCKZhgLcVHhWeRWeGE3iJ8K6BeHf2EgB8Qr6ayTyTUjBcn+u4qqWKgkvG4qRavlvrBSdMrAXWIKE8vSq1od0A2ZzP6+HCsrkuUR+HFfpE2dpjeckoa5vATQgyn8j5x11iIOB9HnT3YKbZ0aTU4rQgYMJXA/fPcgKDGkAPdgtGbQLssy/mwSdsXBYtMgEcs7vI9laR8Ik+NK2dbFHGFPnxS43WToGyKBxojt8SZbgPJXm22WRrN1+9AZvvhI7/mpZiEE7HWgNRClZYuqbfCMpelLGvVq832OLjelrWMJ0XBVNHnOw0p8qZKI1UpqQJXX1nL8j3JttEVHsfryIanM03kNDL0dX1VAKECKUMCVQ6i6tG4VWsR0C2JccPJ3PSoPgo5KMJhuZNaBoiPjZ2eaMREV6vUYbBYzrvdDQzUcE2stacREl4eJzGJ4GP5h08GQmIirGF/SCyZV1CadAbKZVjqb70XpIbE6NT/+84O82LZR4ui5KgTAv87lTZgvNJ7LxM7rRg1awj/iBxQeARNJxuPMPlk1CVx8Z3091UdL1K1avPKa85lCRwCkDKLcJPO9tlqi4dVjCrwpoCJkQMm3fbTl/BgHn00/RsnFZ2qfl5m2DyF+XuaOPauzsRdLUFAC4h44qoUuzRb4Pv6RFhN5CI4fddRKafNBHU9f69UCkO080/hIjTdj0+bpr4oNY4UEi80huyJY/c0iUPE8o48qBB8F3cW30SwhPmuphn4/18lB8GEwEPqoatmli4QRaDFUCUf9Hj0DEUqEAya/OHOW7/PvWcw/l/ZaIMUpOZ6q0xvPDAXokFRJAWzZhG7hNbWNEzQ3f/BjlYlYsBtMY0JUU8mH6YxwIzIGbHiLTBC0OglH0rDd5W+3NaUG9FZ//o9MAP5j2QqwSuFWXppbigh4zk+h17eJn5zhld7dtvOr+YmgYULj6NFIDKBZHUJdqLYScVzdc1p812FCCBcLmmw4RnwuF+RldHixTdy4UZ17T/hD4OLpWCINl9lUAficC0OFeLJLHxFW6Em8SCbZ3aUtFDIQD8oTqzUHZhGWYF2ukrOc8Dzm4FQ8xy3BhqfntTod1gwoilIirsP/z+GGMnTltkqiqK+gCmkVOfICwNFmHltZeJrmDQ4YU5abR09Yr1TaAk3CzWjV1XGBaf/oek0+tFkMOtZNdFRdlzLLE90PsZZFFnZhFBoNoOhYnMB9K2VqgEpJs0nXvF6qBOllptcpBYUYMzMdb0Ggu6m1d/phxuBuOsm+Xtr0Zw8Xd0vxIOQNDGsskCDIEUYWYajw2i66MmRPRyFEennXfLA0WIPpztXvfsrKjf42rjE3RukBsRff1Sci68cel4fGfmvj2y7gW0Tt -before_build: -- nuget restore -- ps: .\prebuild.ps1 -build: - project: greenshot.sln - verbosity: normal -after_build: -- ps: .\build.ps1 -test: off -artifacts: -- path: Greenshot\releases\Greenshot*INSTALLER*.exe - name: Installer -- path: Greenshot\releases\Greenshot*paf.exe - name: Portable -- path: Greenshot\releases\Greenshot-NO*.zip - name: Zip -- path: Greenshot\releases\additional_files\readme.txt - name: Readme -- path: Greenshot\releases\Greenshot-DEBUGSYMBOLS*.zip - name: DEBUGSYMBOLS -deploy: -- provider: GitHub - tag: Greenshot-$(build_type)-$(APPVEYOR_BUILD_VERSION) - description: - auth_token: - secure: 4sYcNGg7byBFtR7EkJHS8d3H3qP0u0LodlJWCV7g/4jEyv3vvVxqzh19zZ6Zgrf1 - prerelease: true - draft: true - on: - build_type: /^(RC|UNSTABLE).*/ -- provider: GitHub - tag: Greenshot-$(build_type)-$(APPVEYOR_BUILD_VERSION) - auth_token: - secure: 4sYcNGg7byBFtR7EkJHS8d3H3qP0u0LodlJWCV7g/4jEyv3vvVxqzh19zZ6Zgrf1 - prerelease: false - draft: true - on: - build_type: RELEASE -notifications: -- provider: Email - to: - - robin@getgreenshot.org - - jens@getgreenshot.org - on_build_success: true - on_build_failure: true - on_build_status_changed: false diff --git a/appveyor13.yml b/appveyor13.yml deleted file mode 100644 index 01d1c6d3e..000000000 --- a/appveyor13.yml +++ /dev/null @@ -1,92 +0,0 @@ -version: 1.3.0.{build} -branches: - only: - - develop -skip_tags: true -configuration: Release -platform: Any CPU -shallow_clone: true -assembly_info: - patch: true - file: '**\AssemblyInfo.*' - assembly_version: '{version}' - assembly_file_version: '{version}' - assembly_informational_version: '{version}-$(build_type)-$(APPVEYOR_REPO_COMMIT)' -environment: - credentials_box_client_id: - secure: 8MKxTOowo2fat6cNXGbFfvn6typiEtmCKsrptrWiEFUEoKlT1DUn40iGNcIELRA1 - credentials_box_client_secret: - secure: hJhzDVJuGd/WMnoSXhosvOM/1PGcYlKbtQjA6xyrmnmZcqCTMzqIdA6JXlo/V2Br - credentials_dropbox_consumer_key: - secure: Da/6KY1cu9CUM3iOqSpcUw== - credentials_dropbox_consumer_secret: - secure: KkyKyUY+buT/MZagXDP4cw== - credentials_flickr_consumer_key: - secure: fY8s0OkOMYwCjSZoL/6yZcP8xeT6J2EJLjbUMI5lAW42S5QT2U2B41KrmeP2NpnQ - credentials_flickr_consumer_secret: - secure: 9TthlljPHXWPkDDeG3uiFVJ9YJwHZOV0ZsojaIBBuvw= - credentials_imgur_consumer_key: - secure: XRTg1Ecs6ER9m4779CJAng== - credentials_imgur_consumer_secret: - secure: gcCp/gJF8vqmnCUPKyb04H8Oz9mWmiB00U5X7iI/DGr5mxjoCG1khc6/zn6aSSqn - credentials_photobucket_consumer_key: - secure: oo9GD1Y8dkrli6hMfnnYsw== - credentials_photobucket_consumer_secret: - secure: GiNPoe9klM/YkoHIA/YHqOYrIaYwSFK7Ph9m8jT9uPP1l6+Hd5K8dVMw5DNa50oG - credentials_picasa_consumer_key: - secure: bjKXhFZkDqaq98XBrz5oQKQfT8CLpuv2ZAiBIwkzloaAPUs97b5yx6h/xFaE4NLS - credentials_picasa_consumer_secret: - secure: yNptTpmJWypbu9alOQtetxU66drr2FKxoPflNgRJdag= - build_type: ALPHA -before_build: - - nuget restore - - ps: Build/prebuild.ps1 -build: - project: greenshot.sln - verbosity: normal -after_build: -- ps: Build/build.ps1 -test: off -artifacts: -- path: AssemblyDir\Greenshot*INSTALLER*.exe - name: Installer -- path: AssemblyDir\Greenshot*paf.exe - name: Portable -- path: AssemblyDir\Greenshot-NO*.zip - name: Zip -- path: Build\additional_files\readme.txt - name: Readme -- path: AssemblyDir\Greenshot-DEBUGSYMBOLS*.zip - name: DEBUGSYMBOLS -deploy: -- provider: GitHub - tag: Greenshot-$(build_type)-$(APPVEYOR_BUILD_VERSION) - description: - auth_token: - secure: h0R+O/UoDM5Fy9XBfpRWLxFdR4a6CS+hDxr/MUeiRSviAmUsSlvsGSyOG6KiAVrL - prerelease: true - on: - build_type: RELEASE_CANDIDATE -- provider: GitHub - tag: Greenshot-$(build_type)-$(APPVEYOR_BUILD_VERSION) - description: - auth_token: - secure: h0R+O/UoDM5Fy9XBfpRWLxFdR4a6CS+hDxr/MUeiRSviAmUsSlvsGSyOG6KiAVrL - prerelease: true - on: - build_type: BETA -- provider: GitHub - tag: Greenshot-$(build_type)-$(APPVEYOR_BUILD_VERSION) - auth_token: - secure: h0R+O/UoDM5Fy9XBfpRWLxFdR4a6CS+hDxr/MUeiRSviAmUsSlvsGSyOG6KiAVrL - on: - build_type: RELEASE -notifications: -- provider: Email - to: - - robin@getgreenshot.org - - jens@getgreenshot.org - - thomas@getgreenshot.org - on_build_success: true - on_build_failure: true - on_build_status_changed: true \ No newline at end of file diff --git a/build.ps1 b/build.ps1 deleted file mode 100644 index 9bfcc6797..000000000 --- a/build.ps1 +++ /dev/null @@ -1,343 +0,0 @@ -################################################################ -# Greenshot BUILD script, written for the Windows Power Shell -# Assumes the installation of Microsoft .NET Framework 4.5 -################################################################ -# Greenshot - a free and open source screenshot tool -# Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom -# -# For more information see: http://getgreenshot.org/ -# The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 1 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -################################################################ - -$version=$env:APPVEYOR_BUILD_VERSION -if ( !$version ) { - $version = "1.3.0.0" -} - -$buildType=$env:build_type -if ( !$buildType ) { - $buildType = "local" -} - -$gitcommit=$env:APPVEYOR_REPO_COMMIT -if ( !$gitcommit ) { - $gitcommit = "abcdefghijklmnopqrstuvwxy" -} - -$gitcommit=$gitcommit.SubString(0, [math]::Min($gitcommit.Length, 7)) -$detailversion=$version + '-' + $gitcommit + " " + $buildType -$release=(([version]$version).build) % 2 -eq 1 -$fileversion=$version + "-" + $buildType - -Write-Host "Building Greenshot $detailversion" - -# Create a MD5 string for the supplied filename -Function MD5($filename) { - $fileStream = new-object -TypeName System.IO.FileStream -ArgumentList "$filename", "Open", "Read", "Read" - $MD5CryptoServiceProvider = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider - $hash = $MD5CryptoServiceProvider.ComputeHash($fileStream) - return [System.BitConverter]::ToString($hash) -replace "-", "" -} - -# Sign the specify file -Function SignWithCertificate($filename) { - Write-Host "Signing $filename" - $signSha1Arguments = @('sign', '/debug', '/fd', 'sha1' , '/tr', 'http://time.certum.pl', '/td', 'sha1' , $filename) - $signSha256Arguments = @('sign', '/debug', '/as', '/fd', 'sha256', '/tr', 'http://time.certum.pl', '/td', 'sha256', $filename) - - Start-Process -wait $env:SignTool -ArgumentList $signSha1Arguments -NoNewWindow - Start-Process -wait $env:SignTool -ArgumentList $signSha256Arguments -NoNewWindow -} - -# Sign the file with Signtool before they are packed in the installer / .zip etc -Function SignBinaryFilesBeforeBuildingInstaller() { - $sourcebase = "$(get-location)\Greenshot\bin\Release" - - $INCLUDE=@("*.exe", "*.gsp", "*.dll") - Get-ChildItem -Path "$sourcebase" -Recurse -Include $INCLUDE -Exclude "log4net.dll" | foreach { - SignWithCertificate($_) - } -} - -# Fill the templates -Function FillTemplates { - Write-Host "Filling templates for version $detailversion`n`n" - - Get-ChildItem . -recurse *.template | - foreach { - $oldfile = $_.FullName - $newfile = $_.FullName -replace '\.template','' - Write-Host "Modifying file : $oldfile to $newfile" - # Read the file - $template = Get-Content $oldfile - # Create an empty array, this will contain the replaced lines - $newtext = @() - foreach ($line in $template) { - $newtext += $line -replace "\@VERSION\@", $version -replace "\@DETAILVERSION\@", $detailversion -replace "\@FILEVERSION\@", $fileversion - } - # Write the new information to the file - $newtext | Set-Content $newfile -encoding UTF8 - } -} - -# Create the MD5 checksum file -Function MD5Checksums { - echo "MD5 Checksums:" - $sourcebase = "$(get-location)\Greenshot\bin\Release" - - $INCLUDE=@("*.exe", "*.gsp", "*.dll") - Get-ChildItem -Path "$sourcebase" -Recurse -Include $INCLUDE | foreach { - $currentMD5 = MD5($_.fullname) - $name = $_.Name - echo "$name : $currentMD5" - } -} - -# This function creates the paf.exe -Function PackagePortable { - $sourcebase = "$(get-location)\Greenshot\bin\Release" - $destbase = "$(get-location)\Greenshot\releases" - - # Only remove the paf we are going to create, to prevent adding but keeping the history - if (Test-Path ("$destbase\GreenshotPortable-$version.paf.exe")) { - Remove-Item "$destbase\GreenshotPortable-$version.paf.exe" -Confirm:$false - } - # Remove the directory to create the files in - if (Test-Path ("$destbase\portabletmp")) { - Remove-Item "$destbase\portabletmp" -recurse -Confirm:$false - } - Copy-Item -Path "$destbase\portable" -Destination "$destbase\portabletmp" -Recurse - - $INCLUDE=@("*.gsp", "*.dll", "*.exe", "*.config") - Get-ChildItem -Path "$sourcebase\Plugins\" -Recurse -Include $INCLUDE | foreach { - $path = $_.fullname -replace ".*\\Plugins\\", "$destbase\portabletmp\App\Greenshot\Plugins\" - New-Item -ItemType File -Path "$path" -Force | Out-Null - Copy-Item -Path $_ -Destination "$path" -Force - } - - $INCLUDE=@("help-*.html","language-*.xml") - Get-ChildItem -Path "$(get-location)\Greenshot\Languages\" -Recurse -Include $INCLUDE -Exclude "*installer*","*website*" | foreach { - $path = $_.fullname -replace ".*\\Languages\\", "$destbase\portabletmp\App\Greenshot\Languages\" - New-Item -ItemType File -Path "$path" -Force | Out-Null - Copy-Item -Path $_ -Destination "$path" -Force - } - Copy-Item -Path "$sourcebase\Languages\Plugins\" -Destination "$destbase\portabletmp\App\Greenshot\Languages\Plugins\" -Recurse - - @( "$sourcebase\checksum.MD5", - "$sourcebase\Greenshot.exe.config", - "$sourcebase\GreenshotPlugin.dll", - "$sourcebase\LinqBridge.dll", - "$sourcebase\log4net.dll", - "$sourcebase\log4net-portable.xml", - "$destbase\additional_files\*.txt" ) | foreach { Copy-Item $_ "$destbase\portabletmp\App\Greenshot\" } - - Copy-Item -Path "$sourcebase\Languages\help-en-US.html" -Destination "$destbase\portabletmp\help.html" - - Copy-Item -Path "$sourcebase\Greenshot.exe" -Destination "$destbase\portabletmp" - - Copy-Item -Path "$destbase\appinfo.ini" -Destination "$destbase\portabletmp\App\AppInfo\appinfo.ini" - - $portableOutput = "$(get-location)\portable" - $portableInstaller = "$(get-location)\greenshot\tools\PortableApps.comInstaller\PortableApps.comInstaller.exe" - $arguments = @("$destbase\portabletmp") - Write-Host "Starting $portableInstaller $arguments" - $portableResult = Start-Process -wait -PassThru "$portableInstaller" -ArgumentList $arguments -NoNewWindow -RedirectStandardOutput "$portableOutput.log" -RedirectStandardError "$portableOutput.error" - Write-Host "Log output:" - Get-Content "$portableOutput.log"| Write-Host - if ($portableResult.ExitCode -ne 0) { - Write-Host "Error output:" - Get-Content "$portableOutput.error"| Write-Host - exit -1 - } - Start-Sleep -m 1500 - Remove-Item "$destbase\portabletmp" -Recurse -Confirm:$false - - # sign the .paf.exe - $pafFiles = @("*.paf.exe") - Get-ChildItem -Path "$destbase" -Recurse -Include $pafFiles | foreach { - SignWithCertificate($_) - } - - return -} - -# This function creates the .zip -Function PackageZip { - $sourcebase = "$(get-location)\Greenshot\bin\Release" - $destbase = "$(get-location)\Greenshot\releases" - $destzip = "$destbase\NO-INSTALLER" - - # Only remove the zip we are going to create, to prevent adding but keeping the history - if (Test-Path ("$destbase\Greenshot-NO-INSTALLER-$fileversion.zip")) { - Remove-Item "$destbase\Greenshot-NO-INSTALLER-$fileversion.zip" -Confirm:$false - } - # Remove the directory to create the files in - if (Test-Path ("$destzip")) { - Remove-Item "$destzip" -recurse -Confirm:$false - } - New-Item -ItemType directory -Path "$destzip" | Out-Null - - echo ";dummy config, used to make greenshot store the configuration in this directory" | Set-Content "$destzip\greenshot.ini" -encoding UTF8 - echo ";In this file you should add your default settings" | Set-Content "$destzip\greenshot-defaults.ini" -encoding UTF8 - echo ";In this file you should add your fixed settings" | Set-Content "$destzip\greenshot-fixed.ini" -encoding UTF8 - - $INCLUDE=@("*.gsp", "*.dll", "*.exe", "*.config") - Get-ChildItem -Path "$sourcebase\Plugins\" -Recurse -Include $INCLUDE | foreach { - $path = $_.fullname -replace ".*\\Plugins\\", "$destzip\Plugins\" - New-Item -ItemType File -Path "$path" -Force | Out-Null - Copy-Item -Path $_ -Destination "$path" -Force - } - - $INCLUDE=@("help-*.html","language-*.xml") - Get-ChildItem -Path "$(get-location)\Greenshot\Languages\" -Recurse -Include $INCLUDE -Exclude "*installer*","*website*" | foreach { - $path = $_.fullname -replace ".*\\Languages\\", "$destzip\Languages\" - New-Item -ItemType File -Path "$path" -Force | Out-Null - Copy-Item -Path $_ -Destination "$path" -Force - } - Copy-Item -Path "$sourcebase\Languages\Plugins\" -Destination "$destzip\Languages\Plugins\" -Recurse - - @( "$sourcebase\checksum.MD5", - "$sourcebase\Greenshot.exe", - "$sourcebase\Greenshot.exe.config", - "$sourcebase\GreenshotPlugin.dll", - "$sourcebase\LinqBridge.dll", - "$sourcebase\log4net.dll", - "$(get-location)\Greenshot\log4net-zip.xml" - "$destbase\additional_files\*.txt" ) | foreach { Copy-Item $_ "$destzip\" } - - Rename-Item "$destzip\log4net-zip.xml" "$destzip\log4net.xml" - - $zipOutput = "$(get-location)\zip" - $zip7 = "$(get-location)\greenshot\tools\7zip\7za.exe" - $arguments = @('a', '-mx9', '-tzip', '-r', "$destbase\Greenshot-NO-INSTALLER-$fileversion.zip", "$destzip\*") - Write-Host "Starting $zip7 $arguments" - $zipResult = Start-Process -wait -PassThru "$zip7" -ArgumentList $arguments -NoNewWindow -RedirectStandardOutput "$zipOutput.log" -RedirectStandardError "$zipOutput.error" - Write-Host "Log output:" - Get-Content "$zipOutput.log"| Write-Host - if ($zipResult.ExitCode -ne 0) { - Write-Host "Error output:" - Get-Content "$zipOutput.error"| Write-Host - exit -1 - } - Start-Sleep -m 1500 - Remove-Item "$destzip" -Recurse -Confirm:$false - return -} - -# This function creates the debug symbols .zip -Function PackageDbgSymbolsZip { - $sourcebase = "$(get-location)\Greenshot\bin\Release" - $destbase = "$(get-location)\Greenshot\releases" - $destdbgzip = "$destbase\DEBUGSYMBOLS" - - # Only remove the zip we are going to create, to prevent adding but keeping the history - if (Test-Path ("$destbase\Greenshot-DEBUGSYMBOLS-$fileversion.zip")) { - Remove-Item "$destbase\Greenshot-DEBUGSYMBOLS-$fileversion.zip" -Confirm:$false - } - # Remove the directory to create the files in - if (Test-Path ("$destdbgzip")) { - Remove-Item "$destdbgzip" -recurse -Confirm:$false - } - New-Item -ItemType directory -Path "$destdbgzip" | Out-Null - - $INCLUDE=@("*.pdb") - Get-ChildItem -Path "$sourcebase\Plugins\" -Recurse -Include $INCLUDE | foreach { - $path = $_.fullname -replace ".*\\Plugins\\", "$destdbgzip\Plugins\" - New-Item -ItemType File -Path "$path" -Force | Out-Null - Copy-Item -Path $_ -Destination "$path" -Force - } - - @( "$sourcebase\*.pdb") | foreach { Copy-Item $_ "$destdbgzip\" } - - $zipOutput = "$(get-location)\dbgzip" - $zip7 = "$(get-location)\greenshot\tools\7zip\7za.exe" - $arguments = @('a', '-mx9', '-tzip', '-r', "$destbase\Greenshot-DEBUGSYMBOLS-$fileversion.zip", "$destdbgzip\*") - Write-Host "Starting $zip7 $arguments" - $zipResult = Start-Process -wait -PassThru "$zip7" -ArgumentList $arguments -NoNewWindow -RedirectStandardOutput "$zipOutput.log" -RedirectStandardError "$zipOutput.error" - Write-Host "Log output:" - Get-Content "$zipOutput.log"| Write-Host - if ($zipResult.ExitCode -ne 0) { - Write-Host "Error output:" - Get-Content "$zipOutput.error"| Write-Host - exit -1 - } - Start-Sleep -m 1500 - Remove-Item "$destdbgzip" -Recurse -Confirm:$false - return -} - -# This function creates the installer -Function PackageInstaller { - $setupOutput = "$(get-location)\setup" - $innoSetup = "$(get-location)\packages\Tools.InnoSetup.5.5.9\tools\ISCC.exe" - $innoSetupFile = "$(get-location)\greenshot\releases\innosetup\setup.iss" - Write-Host "Starting $innoSetup $innoSetupFile" - $arguments = @("/Qp /SSignTool=""$env:SignTool `$p""", $innoSetupFile) - $setupResult = Start-Process -wait -PassThru "$innoSetup" -ArgumentList $arguments -NoNewWindow -RedirectStandardOutput "$setupOutput.log" -RedirectStandardError "$setupOutput.error" - Write-Host "Log output:" - Get-Content "$setupOutput.log"| Write-Host - if ($setupResult.ExitCode -ne 0) { - Write-Host "Error output:" - Get-Content "$setupOutput.error"| Write-Host - exit -1 - } - return -} - -# This function tags the current -Function TagCode { - Write-Host "Add remote via git, so SSH key works" - git remote add tagorigin git@bitbucket.org:greenshot/greenshot.git - Write-Host "Setting id_rsa with the content from environment rsakey so we can push a tag" - # Write the RSA key contents from the AppVeyor rsakey UI ENV variable to the private key file - $key = $env:rsakey - $fileContent = "-----BEGIN RSA PRIVATE KEY-----" + "`n" - for ($i = 0; $i -lt $key.Length / 64; $i++) { - $min = [math]::min(64, $key.Length - ($i * 64)); - $fileContent += $key.substring($i*64, $min) + "`n"; - } - $fileContent += "-----END RSA PRIVATE KEY-----" + "`n" - Set-Content c:\users\appveyor\.ssh\id_rsa $fileContent - git config --global user.email "getgreenshot@gmail.com" - git config --global user.name "Greenshot-AppVeyor" - Write-Host "Tagging repo with $fileversion" - git tag -a $fileversion -m 'Build from AppVeyor' - Write-Host "Pushing tag $fileversion to remote" - git push tagorigin $fileversion - return -} - -FillTemplates - -echo "Signing executables" -SignBinaryFilesBeforeBuildingInstaller - -# This must be after the signing, otherwise they would be different. -echo "Generating MD5" -MD5Checksums | Set-Content "$(get-location)\Greenshot\bin\Release\checksum.MD5" -encoding UTF8 - -echo "Generating Installer" -PackageInstaller - -echo "Generating ZIP" -PackageZip - -echo "Generating Portable" -PackagePortable - -echo "Generating Debug Symbols ZIP" -PackageDbgSymbolsZip - diff --git a/prebuild.ps1 b/prebuild.ps1 deleted file mode 100644 index 6d1333950..000000000 --- a/prebuild.ps1 +++ /dev/null @@ -1,53 +0,0 @@ -################################################################ -# Greenshot PRE-BUILD script, written for the Windows Power Shell -# Assumes the installation of Microsoft .NET Framework 4.5 -################################################################ -# Greenshot - a free and open source screenshot tool -# Copyright (C) 2007-2016 Thomas Braun, Jens Klingen, Robin Krom -# -# For more information see: http://getgreenshot.org/ -# The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 1 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. -################################################################ - -# Fill the credentials -Function FillCredentials { - Write-Host "Filling credentials with Environment variable values`n`n" - Get-ChildItem . -recurse *Credentials.cs | foreach { - $template = Get-Content $_.FullName - # Create an empty array, this will contain the replaced lines - $newtext = @() - foreach ($line in $template) { - get-childitem -path env:credentials_* | foreach { - $varname=$_.Name - $varvalue=$_.Value - $line = $line -replace "\@$varname\@", $varvalue - } - $newtext += $line - } - # Write the new information to the file - Write-Host "Updating $_" - $newtext | Set-Content $_.FullName -encoding UTF8 - } -} - -FillCredentials - -# Write the certificate to a file -[System.Convert]::FromBase64String($env:Certificate) | set-content "greenshot.pfx" -encoding byte -# Decode password to secure string -$password = ConvertTo-SecureString $env:CertificatePassword -AsPlainText -Force -# Import pfx -Import-PfxCertificate -FilePath .\Greenshot.pfx -CertStoreLocation Cert:\CurrentUser\My -Password $password From 328e7e569d8327bce20ec887d6d64b669cdfbcba Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sat, 23 Jan 2021 23:41:22 +0100 Subject: [PATCH 072/232] BUG-2693: This should fix an issue where Greenshot doesn't detect a MAPI client, we weren't looking at the 32 bit location. --- GreenshotPlugin/Core/EmailConfigHelper.cs | 50 +++++------------ GreenshotPlugin/Core/RegistryHelper.cs | 66 +++++++++++++++++++++++ 2 files changed, 80 insertions(+), 36 deletions(-) create mode 100644 GreenshotPlugin/Core/RegistryHelper.cs diff --git a/GreenshotPlugin/Core/EmailConfigHelper.cs b/GreenshotPlugin/Core/EmailConfigHelper.cs index 7da960b09..bbd816e96 100644 --- a/GreenshotPlugin/Core/EmailConfigHelper.cs +++ b/GreenshotPlugin/Core/EmailConfigHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,46 +18,25 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + using System.IO; -using Microsoft.Win32; namespace GreenshotPlugin.Core { /// <summary> /// Description of EmailConfigHelper. /// </summary> public static class EmailConfigHelper { - private const string OutlookPathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"; - private const string MapiClientKey = @"SOFTWARE\Clients\Mail"; - private const string MapiLocationKey = @"SOFTWARE\Microsoft\Windows Messaging Subsystem"; - private const string MapiKey = @"MAPI"; - public static string GetMapiClient() { - using (RegistryKey key = Registry.CurrentUser.OpenSubKey(MapiClientKey, false)) { - if (key != null) { - return (string)key.GetValue(string.Empty); - } - } - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(MapiClientKey, false)) - { - return (string) key?.GetValue(string.Empty); - } - } - - public static bool HasMapi() - { - using RegistryKey key = Registry.LocalMachine.OpenSubKey(MapiLocationKey, false); - return key != null && "1".Equals(key.GetValue(MapiKey, "0")); - } + public static string GetMapiClient() => RegistryHelper.ReadLocalMachineSoftwareKey(@"Clients\Mail"); - public static string GetOutlookExePath() { - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(OutlookPathKey, false)) { - if (key != null) { - // "" is the default key, which should point to the outlook location - return (string)key.GetValue(string.Empty); - } - } - return null; + public static bool HasMapi() + { + var value = RegistryHelper.ReadLocalMachineSoftwareKey(@"Microsoft\Windows Messaging Subsystem", "MAPI", "0"); + return "1".Equals(value); + } + + public static string GetOutlookExePath() => RegistryHelper.ReadLocalMachineSoftwareKey(@"Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"); /// <summary> /// Check if Outlook is installed @@ -65,12 +44,11 @@ namespace GreenshotPlugin.Core { /// <returns>Returns true if outlook is installed</returns> public static bool HasOutlook() { string outlookPath = GetOutlookExePath(); - if (outlookPath != null) { - if (File.Exists(outlookPath)) { - return true; - } + if (outlookPath == null) + { + return false; } - return false; + return File.Exists(outlookPath); } } } diff --git a/GreenshotPlugin/Core/RegistryHelper.cs b/GreenshotPlugin/Core/RegistryHelper.cs new file mode 100644 index 000000000..e5f068ab4 --- /dev/null +++ b/GreenshotPlugin/Core/RegistryHelper.cs @@ -0,0 +1,66 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; +using Microsoft.Win32; + +namespace GreenshotPlugin.Core +{ + /// <summary> + /// A helper class for accessing the registry + /// </summary> + public static class RegistryHelper + { + /// <summary> + /// Retrieve a registry value + /// </summary> + /// <param name="keyName">string with the name of the key</param> + /// <param name="value">string with the name of the value below the key, null will retrieve the default</param> + /// <param name="defaultValue">string with the default value to return</param> + /// <returns>string with the value</returns> + public static string ReadLocalMachineSoftwareKey(string keyName, string value = null, string defaultValue = null) + { + string result = null; + value ??= string.Empty; + if (Environment.Is64BitOperatingSystem) + { + using var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\{keyName}", false); + + if (key != null) + { + result = (string)key.GetValue(value, defaultValue); + } + } + + if (string.IsNullOrEmpty(result)) + { + using var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\wow6432node\{keyName}", false); + + if (key != null) + { + result = (string)key.GetValue(value, defaultValue); + } + } + + return result; + } + } +} From 2733c6cf2651e3d3fbe7e677762df3cc7bae2838 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Wed, 27 Jan 2021 23:50:22 +0100 Subject: [PATCH 073/232] Fixed an issue with the build, where MSBuild.Community.Tasks.Targets wasn't found. Also improved the registry reading for the MAPI control. --- Directory.Build.props | 9 ++++++--- Greenshot/Greenshot.csproj | 7 +++++++ Greenshot/Helpers/MailHelper.cs | 14 +++++++------- GreenshotJiraPlugin/GreenshotJiraPlugin.csproj | 4 ++-- GreenshotPlugin/Core/EmailConfigHelper.cs | 7 ++++--- ...{RegistryHelper.cs => RegistryKeyExtensions.cs} | 9 +++++---- GreenshotPlugin/GreenshotPlugin.csproj | 4 ++-- 7 files changed, 33 insertions(+), 21 deletions(-) rename GreenshotPlugin/Core/{RegistryHelper.cs => RegistryKeyExtensions.cs} (82%) diff --git a/Directory.Build.props b/Directory.Build.props index 520eb0976..ce53be91e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -102,11 +102,14 @@ </Tokens> </ItemGroup> - <ItemGroup> - <PackageReference Include="MSBuildTasks" Version="1.5.0.235" GeneratePathProperty="true"/> + <ItemGroup Condition="$(MSBuildProjectName.Contains('Plugin'))"> + <PackageReference Include="MSBuildTasks" Version="1.5.0.235" GeneratePathProperty="true" DevelopmentDependency="true" /> </ItemGroup> + <PropertyGroup Condition="'$(PkgTools_MSBuildTasks)' == ''"> + <PkgTools_MSBuildTasks>$(userprofile)\.nuget\packages\msbuildtasks\1.5.0.235\tools\</PkgTools_MSBuildTasks> + </PropertyGroup> - <Import Project="$(PkgTools_MSBuildTasks)MSBuild.Community.Tasks.Targets" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"/> + <Import Project="$(PkgTools_MSBuildTasks)MSBuild.Community.Tasks.Targets" Condition="$(MSBuildProjectName.Contains('Plugin'))"/> <Target Name="ProcessTemplates" BeforeTargets="PrepareForBuild" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"> <Message Text="Processing: $(ProjectDir)$(ProjectName).Credentials.template" Importance="high"/> diff --git a/Greenshot/Greenshot.csproj b/Greenshot/Greenshot.csproj index 9419fb179..630501ce8 100644 --- a/Greenshot/Greenshot.csproj +++ b/Greenshot/Greenshot.csproj @@ -46,6 +46,13 @@ <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> </ItemGroup> + + <ItemGroup> + <PackageReference Update="MSBuildTasks" Version="1.5.0.235"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + </ItemGroup> <UsingTask TaskName="SetEnvironmentVariableTask" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll"> <ParameterGroup> diff --git a/Greenshot/Helpers/MailHelper.cs b/Greenshot/Helpers/MailHelper.cs index d3daaf446..a78799eae 100644 --- a/Greenshot/Helpers/MailHelper.cs +++ b/Greenshot/Helpers/MailHelper.cs @@ -174,7 +174,7 @@ namespace Greenshot.Helpers { /// </summary> public void ShowDialog() { // Create the mail message in an STA thread - var thread = new Thread(_ShowMail) + var thread = new Thread(ShowMail) { IsBackground = true, Name = "Create MAPI mail" @@ -202,7 +202,7 @@ namespace Greenshot.Helpers { /// <summary> /// Sends the mail message. /// </summary> - private void _ShowMail() { + private void ShowMail() { var message = new MapiHelperInterop.MapiMessage(); using var interopRecipients = Recipients.GetInteropRepresentation(); @@ -215,7 +215,7 @@ namespace Greenshot.Helpers { // Check if we need to add attachments if (Files.Count > 0) { // Add attachments - message.Files = _AllocAttachments(out message.FileCount); + message.Files = AllocAttachments(out message.FileCount); } // Signal the creating thread (make the remaining code async) @@ -227,7 +227,7 @@ namespace Greenshot.Helpers { if (Files.Count > 0) { // Deallocate the files - _DeallocFiles(message); + DeallocFiles(message); } MAPI_CODES errorCode = (MAPI_CODES)Enum.ToObject(typeof(MAPI_CODES), error); @@ -245,14 +245,14 @@ namespace Greenshot.Helpers { return; } Recipients = new RecipientCollection(); - _ShowMail(); + ShowMail(); } /// <summary> /// Deallocates the files in a message. /// </summary> /// <param name="message">The message to deallocate the files from.</param> - private void _DeallocFiles(MapiHelperInterop.MapiMessage message) { + private void DeallocFiles(MapiHelperInterop.MapiMessage message) { if (message.Files != IntPtr.Zero) { Type fileDescType = typeof(MapiFileDescriptor); int fsize = Marshal.SizeOf(fileDescType); @@ -274,7 +274,7 @@ namespace Greenshot.Helpers { /// </summary> /// <param name="fileCount"></param> /// <returns></returns> - private IntPtr _AllocAttachments(out int fileCount) { + private IntPtr AllocAttachments(out int fileCount) { fileCount = 0; if (Files == null) { return IntPtr.Zero; diff --git a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj b/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj index 2c4e72fe6..d37465111 100644 --- a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj +++ b/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj @@ -12,7 +12,7 @@ </ItemGroup> <ItemGroup> <ProjectReference Include="..\GreenshotPlugin\GreenshotPlugin.csproj" /> - <PackageReference Include="Dapplo.Jira" version="1.1.21" /> - <PackageReference Include="Dapplo.Jira.SvgWinForms" Version="1.1.21" /> + <PackageReference Include="Dapplo.Jira" version="1.1.38" /> + <PackageReference Include="Dapplo.Jira.SvgWinForms" Version="1.1.38" /> </ItemGroup> </Project> \ No newline at end of file diff --git a/GreenshotPlugin/Core/EmailConfigHelper.cs b/GreenshotPlugin/Core/EmailConfigHelper.cs index bbd816e96..354f02c33 100644 --- a/GreenshotPlugin/Core/EmailConfigHelper.cs +++ b/GreenshotPlugin/Core/EmailConfigHelper.cs @@ -20,6 +20,7 @@ */ using System.IO; +using Microsoft.Win32; namespace GreenshotPlugin.Core { /// <summary> @@ -27,16 +28,16 @@ namespace GreenshotPlugin.Core { /// </summary> public static class EmailConfigHelper { - public static string GetMapiClient() => RegistryHelper.ReadLocalMachineSoftwareKey(@"Clients\Mail"); + public static string GetMapiClient() => Registry.LocalMachine.ReadKey64Or32(@"Clients\Mail"); public static bool HasMapi() { - var value = RegistryHelper.ReadLocalMachineSoftwareKey(@"Microsoft\Windows Messaging Subsystem", "MAPI", "0"); + var value = Registry.LocalMachine.ReadKey64Or32(@"Microsoft\Windows Messaging Subsystem", "MAPI", "0"); return "1".Equals(value); } - public static string GetOutlookExePath() => RegistryHelper.ReadLocalMachineSoftwareKey(@"Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"); + public static string GetOutlookExePath() => Registry.LocalMachine.ReadKey64Or32(@"Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"); /// <summary> /// Check if Outlook is installed diff --git a/GreenshotPlugin/Core/RegistryHelper.cs b/GreenshotPlugin/Core/RegistryKeyExtensions.cs similarity index 82% rename from GreenshotPlugin/Core/RegistryHelper.cs rename to GreenshotPlugin/Core/RegistryKeyExtensions.cs index e5f068ab4..73fd66a47 100644 --- a/GreenshotPlugin/Core/RegistryHelper.cs +++ b/GreenshotPlugin/Core/RegistryKeyExtensions.cs @@ -27,22 +27,23 @@ namespace GreenshotPlugin.Core /// <summary> /// A helper class for accessing the registry /// </summary> - public static class RegistryHelper + public static class RegistryKeyExtensions { /// <summary> /// Retrieve a registry value /// </summary> + /// <param name="registryKey">RegistryKey like Registry.LocalMachine</param> /// <param name="keyName">string with the name of the key</param> /// <param name="value">string with the name of the value below the key, null will retrieve the default</param> /// <param name="defaultValue">string with the default value to return</param> /// <returns>string with the value</returns> - public static string ReadLocalMachineSoftwareKey(string keyName, string value = null, string defaultValue = null) + public static string ReadKey64Or32(this RegistryKey registryKey, string keyName, string value = null, string defaultValue = null) { string result = null; value ??= string.Empty; if (Environment.Is64BitOperatingSystem) { - using var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\{keyName}", false); + using var key = registryKey.OpenSubKey($@"SOFTWARE\{keyName}", false); if (key != null) { @@ -52,7 +53,7 @@ namespace GreenshotPlugin.Core if (string.IsNullOrEmpty(result)) { - using var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\wow6432node\{keyName}", false); + using var key = registryKey.OpenSubKey($@"SOFTWARE\wow6432node\{keyName}", false); if (key != null) { diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj index 3caa4a7c4..29371bcfd 100644 --- a/GreenshotPlugin/GreenshotPlugin.csproj +++ b/GreenshotPlugin/GreenshotPlugin.csproj @@ -13,9 +13,9 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="1.0.3" /> + <PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="1.0.8" /> <PackageReference Include="log4net" version="2.0.12" /> - <PackageReference Include="Svg" Version="3.1.1" /> + <PackageReference Include="Svg" Version="3.2.3" /> <Reference Include="Accessibility" /> <Reference Include="CustomMarshalers" /> </ItemGroup> From 5103cb5da6a3b5740c469563b1462950fa893b92 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Thu, 28 Jan 2021 08:20:13 +0100 Subject: [PATCH 074/232] Trying to get MSBuild.Community.Tasks working in the CI Pipeline, also removed "mixed" as a target platform. --- Directory.Build.props | 14 ++++++--- Greenshot.sln | 43 ---------------------------- GreenshotJiraPlugin/JiraConnector.cs | 2 +- azure-pipelines.yml | 4 +++ 4 files changed, 15 insertions(+), 48 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index ce53be91e..78cd56c7b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -102,14 +102,20 @@ </Tokens> </ItemGroup> + <!-- Acticate MSBuild.Community.Tasks to use the TemplateFile Task--> <ItemGroup Condition="$(MSBuildProjectName.Contains('Plugin'))"> <PackageReference Include="MSBuildTasks" Version="1.5.0.235" GeneratePathProperty="true" DevelopmentDependency="true" /> </ItemGroup> - <PropertyGroup Condition="'$(PkgTools_MSBuildTasks)' == ''"> - <PkgTools_MSBuildTasks>$(userprofile)\.nuget\packages\msbuildtasks\1.5.0.235\tools\</PkgTools_MSBuildTasks> + <PropertyGroup Condition="Exists('$(PkgTools_MSBuildTasks)MSBuild.Community.Tasks.Targets')"> + <MSBuildTasksPath>$(PkgTools_MSBuildTasks)</MSBuildTasksPath> </PropertyGroup> - - <Import Project="$(PkgTools_MSBuildTasks)MSBuild.Community.Tasks.Targets" Condition="$(MSBuildProjectName.Contains('Plugin'))"/> + <PropertyGroup Condition="Exists('$(userprofile)\.nuget\packages\msbuildtasks\1.5.0.235\tools\MSBuild.Community.Tasks.Targets')"> + <MSBuildTasksPath>$(userprofile)\.nuget\packages\msbuildtasks\1.5.0.235\tools\</MSBuildTasksPath> + </PropertyGroup> + <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')"> + <MSBuildTasksPath>$(MSBuildExtensionsPath)\MSBuildCommunityTasks\</MSBuildTasksPath> + </PropertyGroup> + <Import Project="$(MSBuildTasksPath)MSBuild.Community.Tasks.Targets" Condition="$(MSBuildProjectName.Contains('Plugin'))"/> <Target Name="ProcessTemplates" BeforeTargets="PrepareForBuild" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"> <Message Text="Processing: $(ProjectDir)$(ProjectName).Credentials.template" Importance="high"/> diff --git a/Greenshot.sln b/Greenshot.sln index 6b3723f7a..27df62d85 100644 --- a/Greenshot.sln +++ b/Greenshot.sln @@ -54,172 +54,129 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|Mixed Platforms = Debug|Mixed Platforms Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU - Release|Mixed Platforms = Release|Mixed Platforms Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|x86.ActiveCfg = Debug|Any CPU {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|x86.Build.0 = Debug|Any CPU {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Any CPU.Build.0 = Release|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|x86.ActiveCfg = Release|Any CPU {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|x86.Build.0 = Release|Any CPU {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.ActiveCfg = Debug|Any CPU {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.Build.0 = Debug|Any CPU {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Any CPU.ActiveCfg = Release|Any CPU {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Any CPU.Build.0 = Release|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.ActiveCfg = Release|Any CPU {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.Build.0 = Release|Any CPU {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.ActiveCfg = Debug|Any CPU {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.Build.0 = Debug|Any CPU {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.ActiveCfg = Release|Any CPU {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.Build.0 = Release|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.ActiveCfg = Release|Any CPU {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.Build.0 = Release|Any CPU {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.ActiveCfg = Debug|Any CPU {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.Build.0 = Debug|Any CPU {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.ActiveCfg = Release|Any CPU {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.Build.0 = Release|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.ActiveCfg = Release|Any CPU {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.Build.0 = Release|Any CPU {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.Build.0 = Debug|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.ActiveCfg = Debug|Any CPU {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.Build.0 = Debug|Any CPU {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.ActiveCfg = Release|Any CPU {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.Build.0 = Release|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.ActiveCfg = Release|Any CPU {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.Build.0 = Release|Any CPU {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.ActiveCfg = Debug|Any CPU {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.Build.0 = Debug|Any CPU {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.ActiveCfg = Release|Any CPU {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.Build.0 = Release|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.ActiveCfg = Release|Any CPU {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.Build.0 = Release|Any CPU {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|x86.ActiveCfg = Debug|Any CPU {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|x86.Build.0 = Debug|Any CPU {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|Any CPU.ActiveCfg = Release|Any CPU {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|Any CPU.Build.0 = Release|Any CPU - {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|x86.ActiveCfg = Release|Any CPU {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|x86.Build.0 = Release|Any CPU {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Debug|x86.ActiveCfg = Debug|Any CPU {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Debug|x86.Build.0 = Debug|Any CPU {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Release|Any CPU.ActiveCfg = Release|Any CPU {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Release|Any CPU.Build.0 = Release|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Release|Mixed Platforms.Build.0 = Release|Any CPU {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Release|x86.ActiveCfg = Release|Any CPU {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Release|x86.Build.0 = Release|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.ActiveCfg = Debug|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.Build.0 = Debug|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Any CPU.ActiveCfg = Release|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Any CPU.Build.0 = Release|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|x86.ActiveCfg = Release|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|x86.Build.0 = Release|Any CPU {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|x86.ActiveCfg = Debug|Any CPU {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|x86.Build.0 = Debug|Any CPU {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Any CPU.Build.0 = Release|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|x86.ActiveCfg = Release|Any CPU {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|x86.Build.0 = Release|Any CPU {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|x86.ActiveCfg = Debug|Any CPU {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|x86.Build.0 = Debug|Any CPU {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Any CPU.Build.0 = Release|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|x86.ActiveCfg = Release|Any CPU {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|x86.Build.0 = Release|Any CPU {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|x86.ActiveCfg = Debug|Any CPU {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|x86.Build.0 = Debug|Any CPU {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Any CPU.Build.0 = Release|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|x86.ActiveCfg = Release|Any CPU {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|x86.Build.0 = Release|Any CPU {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|x86.ActiveCfg = Debug|Any CPU {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|x86.Build.0 = Debug|Any CPU {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Any CPU.ActiveCfg = Release|Any CPU {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Any CPU.Build.0 = Release|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Mixed Platforms.Build.0 = Release|Any CPU {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|x86.ActiveCfg = Release|Any CPU {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|x86.Build.0 = Release|Any CPU {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|x86.ActiveCfg = Debug|Any CPU {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|x86.Build.0 = Debug|Any CPU {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Any CPU.ActiveCfg = Release|Any CPU {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Any CPU.Build.0 = Release|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Mixed Platforms.Build.0 = Release|Any CPU {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|x86.ActiveCfg = Release|Any CPU {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|x86.Build.0 = Release|Any CPU {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|x86.ActiveCfg = Debug|Any CPU {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|x86.Build.0 = Debug|Any CPU {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Any CPU.ActiveCfg = Release|Any CPU {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Any CPU.Build.0 = Release|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Mixed Platforms.Build.0 = Release|Any CPU {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|x86.ActiveCfg = Release|Any CPU {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection diff --git a/GreenshotJiraPlugin/JiraConnector.cs b/GreenshotJiraPlugin/JiraConnector.cs index b836ea560..841a240d1 100644 --- a/GreenshotJiraPlugin/JiraConnector.cs +++ b/GreenshotJiraPlugin/JiraConnector.cs @@ -210,7 +210,7 @@ namespace GreenshotJiraPlugin { await CheckCredentialsAsync(cancellationToken); try { - return await _jiraClient.Issue.GetAsync(issueKey, cancellationToken).ConfigureAwait(false); + return await _jiraClient.Issue.GetAsync(issueKey, cancellationToken: cancellationToken).ConfigureAwait(false); } catch { diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5043dd397..2b613130b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -37,6 +37,10 @@ stages: restoreSolution: '$(solution)' feedsToUse: config + - powershell: | + choco install msbuild.communitytasks + displayName: 'Installing MSBuild community tasks' + - task: MSBuild@1 displayName: Generate templates inputs: From 5f242a79c8259124d930b98fa5d3744c863aafa7 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Thu, 28 Jan 2021 08:23:31 +0100 Subject: [PATCH 075/232] Changed the order of the installation of the MSBuild Tasks, otherwise this will certainly not work. --- azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2b613130b..329355afa 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -30,6 +30,10 @@ stages: steps: - task: NuGetToolInstaller@1 + - powershell: | + choco install msbuild.communitytasks + displayName: 'Installing MSBuild community tasks' + - task: NuGetCommand@2 displayName: NuGet restore inputs: @@ -37,10 +41,6 @@ stages: restoreSolution: '$(solution)' feedsToUse: config - - powershell: | - choco install msbuild.communitytasks - displayName: 'Installing MSBuild community tasks' - - task: MSBuild@1 displayName: Generate templates inputs: From 6831505ead092c07652a3edcd4c0ff01bd0c9b30 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Thu, 28 Jan 2021 09:12:55 +0100 Subject: [PATCH 076/232] Added Directory.Build.targets, this seems to help to import the target correctly. Removed chocolatey package again, as this seems to be the more stable approach (let's see if the build runs...) --- Directory.Build.props | 20 +-- Directory.Build.targets | 9 + GreenshotConfluencePlugin/Confluence.cs | 4 +- .../ConfluenceDestination.cs | 3 +- GreenshotConfluencePlugin/ConfluencePlugin.cs | 4 +- GreenshotConfluencePlugin/ConfluenceUtils.cs | 12 +- .../Forms/ConfluenceConfigurationForm.xaml | 24 +-- .../Forms/ConfluenceConfigurationForm.xaml.cs | 2 +- .../Forms/ConfluencePagePicker.xaml | 2 +- .../Forms/ConfluencePagePicker.xaml.cs | 3 +- .../Forms/ConfluenceSearch.xaml | 11 +- .../Forms/ConfluenceSearch.xaml.cs | 10 +- .../Forms/ConfluenceTreePicker.xaml | 6 +- .../Forms/ConfluenceTreePicker.xaml.cs | 25 ++- .../Forms/ConfluenceUpload.xaml | 18 +- .../Forms/ConfluenceUpload.xaml.cs | 30 ++-- .../Forms/ListViewColumnSorter.cs | 162 +++++++++--------- .../Support/ITranslationProvider.cs | 2 +- .../Support/LanguageChangedEventManager.cs | 2 +- .../Support/LanguageXMLTranslationProvider.cs | 2 +- .../Support/TranslateExtension.cs | 2 +- .../Support/TranslationData.cs | 2 +- .../Support/TranslationManager.cs | 2 +- azure-pipelines.yml | 4 - 24 files changed, 175 insertions(+), 186 deletions(-) create mode 100644 Directory.Build.targets diff --git a/Directory.Build.props b/Directory.Build.props index 78cd56c7b..b1f50e7b1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -18,6 +18,7 @@ <EmbedUntrackedSources>true</EmbedUntrackedSources> <TargetFramework>net472</TargetFramework> <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> + <Deterministic>true</Deterministic> </PropertyGroup> <!-- ILLinker and single file settings --> @@ -102,25 +103,10 @@ </Tokens> </ItemGroup> - <!-- Acticate MSBuild.Community.Tasks to use the TemplateFile Task--> - <ItemGroup Condition="$(MSBuildProjectName.Contains('Plugin'))"> + <!-- Add MSBuild.Community.Tasks to use the TemplateFile Task--> + <ItemGroup Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"> <PackageReference Include="MSBuildTasks" Version="1.5.0.235" GeneratePathProperty="true" DevelopmentDependency="true" /> </ItemGroup> - <PropertyGroup Condition="Exists('$(PkgTools_MSBuildTasks)MSBuild.Community.Tasks.Targets')"> - <MSBuildTasksPath>$(PkgTools_MSBuildTasks)</MSBuildTasksPath> - </PropertyGroup> - <PropertyGroup Condition="Exists('$(userprofile)\.nuget\packages\msbuildtasks\1.5.0.235\tools\MSBuild.Community.Tasks.Targets')"> - <MSBuildTasksPath>$(userprofile)\.nuget\packages\msbuildtasks\1.5.0.235\tools\</MSBuildTasksPath> - </PropertyGroup> - <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')"> - <MSBuildTasksPath>$(MSBuildExtensionsPath)\MSBuildCommunityTasks\</MSBuildTasksPath> - </PropertyGroup> - <Import Project="$(MSBuildTasksPath)MSBuild.Community.Tasks.Targets" Condition="$(MSBuildProjectName.Contains('Plugin'))"/> - - <Target Name="ProcessTemplates" BeforeTargets="PrepareForBuild" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"> - <Message Text="Processing: $(ProjectDir)$(ProjectName).Credentials.template" Importance="high"/> - <TemplateFile Template="$(ProjectDir)$(ProjectName).Credentials.template" OutputFilename="$(ProjectDir)$(ProjectName).Credentials.cs" Tokens="@(Tokens)" /> - </Target> <Target Name="PostBuild" BeforeTargets="PostBuildEvent" Condition="$(MSBuildProjectName.Contains('Plugin')) And !$(MSBuildProjectName.Contains('Test')) And !$(MSBuildProjectName.Contains('Demo'))"> <Exec Command=" diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 000000000..e84907085 --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,9 @@ +<Project> + + <Import Project="$(PkgMSBuildTasks)\tools\MSBuild.Community.Tasks.Targets" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"/> + + <Target Name="ProcessTemplates" BeforeTargets="PrepareForBuild" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"> + <Message Text="Processing: $(ProjectDir)$(ProjectName).Credentials.template" Importance="high"/> + <TemplateFile Template="$(ProjectDir)$(ProjectName).Credentials.template" OutputFilename="$(ProjectDir)$(ProjectName).Credentials.cs" Tokens="@(Tokens)" /> + </Target> +</Project> \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Confluence.cs b/GreenshotConfluencePlugin/Confluence.cs index 3ccfce630..69833cb77 100644 --- a/GreenshotConfluencePlugin/Confluence.cs +++ b/GreenshotConfluencePlugin/Confluence.cs @@ -18,15 +18,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + using System; using System.Collections.Generic; using System.Windows.Forms; -using GreenshotConfluencePlugin; using GreenshotConfluencePlugin.confluence; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Confluence { +namespace GreenshotConfluencePlugin { public class Page { public Page(RemotePage page) { Id = page.id; diff --git a/GreenshotConfluencePlugin/ConfluenceDestination.cs b/GreenshotConfluencePlugin/ConfluenceDestination.cs index 63bf60f01..7403495e2 100644 --- a/GreenshotConfluencePlugin/ConfluenceDestination.cs +++ b/GreenshotConfluencePlugin/ConfluenceDestination.cs @@ -25,7 +25,6 @@ using System.Drawing; using System.IO; using System.Threading; using System.Windows; -using Confluence; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; @@ -129,7 +128,7 @@ namespace GreenshotConfluencePlugin { bool openPage = (_page == null) && ConfluenceConfig.OpenPageAfterUpload; string filename = FilenameHelper.GetFilenameWithoutExtensionFromPattern(CoreConfig.OutputFileFilenamePattern, captureDetails); if (selectedPage == null) { - ConfluenceUpload confluenceUpload = new ConfluenceUpload(filename); + Forms.ConfluenceUpload confluenceUpload = new Forms.ConfluenceUpload(filename); bool? dialogResult = confluenceUpload.ShowDialog(); if (dialogResult.HasValue && dialogResult.Value) { selectedPage = confluenceUpload.SelectedPage; diff --git a/GreenshotConfluencePlugin/ConfluencePlugin.cs b/GreenshotConfluencePlugin/ConfluencePlugin.cs index 78680f24a..2f5ea3539 100644 --- a/GreenshotConfluencePlugin/ConfluencePlugin.cs +++ b/GreenshotConfluencePlugin/ConfluencePlugin.cs @@ -19,14 +19,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -using Confluence; using GreenshotPlugin.Core; using System; using System.Windows; +using GreenshotConfluencePlugin.Forms; +using GreenshotConfluencePlugin.Support; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -using TranslationByMarkupExtension; namespace GreenshotConfluencePlugin { /// <summary> diff --git a/GreenshotConfluencePlugin/ConfluenceUtils.cs b/GreenshotConfluencePlugin/ConfluenceUtils.cs index 7c9e84b00..9b3394cc7 100644 --- a/GreenshotConfluencePlugin/ConfluenceUtils.cs +++ b/GreenshotConfluencePlugin/ConfluenceUtils.cs @@ -33,8 +33,8 @@ namespace GreenshotConfluencePlugin { public class ConfluenceUtils { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluenceUtils)); - public static List<Confluence.Page> GetCurrentPages() { - List<Confluence.Page> pages = new List<Confluence.Page>(); + public static List<Page> GetCurrentPages() { + List<Page> pages = new List<Page>(); Regex pageIdRegex = new Regex(@"pageId=(\d+)"); Regex spacePageRegex = new Regex(@"\/display\/([^\/]+)\/([^#]+)"); foreach(string browserurl in GetBrowserUrls()) { @@ -50,7 +50,7 @@ namespace GreenshotConfluencePlugin { long pageId = long.Parse(pageIdMatch[0].Groups[1].Value); try { bool pageDouble = false; - foreach(Confluence.Page page in pages) { + foreach(Page page in pages) { if (page.Id == pageId) { pageDouble = true; LOG.DebugFormat("Skipping double page with ID {0}", pageId); @@ -58,7 +58,7 @@ namespace GreenshotConfluencePlugin { } } if (!pageDouble) { - Confluence.Page page = ConfluencePlugin.ConfluenceConnector.GetPage(pageId); + Page page = ConfluencePlugin.ConfluenceConnector.GetPage(pageId); LOG.DebugFormat("Adding page {0}", page.Title); pages.Add(page); } @@ -82,7 +82,7 @@ namespace GreenshotConfluencePlugin { } try { bool pageDouble = false; - foreach(Confluence.Page page in pages) { + foreach(Page page in pages) { if (page.Title.Equals(title)) { LOG.DebugFormat("Skipping double page with title {0}", title); pageDouble = true; @@ -90,7 +90,7 @@ namespace GreenshotConfluencePlugin { } } if (!pageDouble) { - Confluence.Page page = ConfluencePlugin.ConfluenceConnector.GetPage(space, title); + Page page = ConfluencePlugin.ConfluenceConnector.GetPage(space, title); LOG.DebugFormat("Adding page {0}", page.Title); pages.Add(page); diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml b/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml index b22e55d9b..c6b6b48a6 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml +++ b/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml @@ -1,33 +1,33 @@ -<Window x:Class="GreenshotConfluencePlugin.ConfluenceConfigurationForm" +<Window x:Class="GreenshotConfluencePlugin.Forms.ConfluenceConfigurationForm" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:gscp="clr-namespace:GreenshotConfluencePlugin" - xmlns:l="clr-namespace:TranslationByMarkupExtension" - xmlns:gsc="clr-namespace:GreenshotPlugin.Core;assembly=GreenshotPlugin" - Title="{l:Translate plugin_settings}" SizeToContent="WidthAndHeight" ResizeMode="NoResize" Icon="/GreenshotConfluencePlugin;component/Images/Confluence.ico"> + xmlns:gsc="clr-namespace:GreenshotPlugin.Core;assembly=GreenshotPlugin" + xmlns:support="clr-namespace:GreenshotConfluencePlugin.Support" + Title="{support:Translate plugin_settings}" SizeToContent="WidthAndHeight" ResizeMode="NoResize" Icon="/GreenshotConfluencePlugin;component/Images/Confluence.ico"> <Window.Resources> <gscp:EnumDisplayer Type="{x:Type gsc:OutputFormat}" x:Key="outputFormats"/> </Window.Resources> <StackPanel> - <CheckBox IsChecked="{Binding IncludePersonSpaces}" Content="{l:Translate include_person_spaces}"/> - <CheckBox IsChecked="{Binding OpenPageAfterUpload}" Content="{l:Translate open_page_after_upload}"/> - <CheckBox IsChecked="{Binding CopyWikiMarkupForImageToClipboard}" Content="{l:Translate copy_wikimarkup}"/> + <CheckBox IsChecked="{Binding IncludePersonSpaces}" Content="{support:Translate include_person_spaces}"/> + <CheckBox IsChecked="{Binding OpenPageAfterUpload}" Content="{support:Translate open_page_after_upload}"/> + <CheckBox IsChecked="{Binding CopyWikiMarkupForImageToClipboard}" Content="{support:Translate copy_wikimarkup}"/> <StackPanel Orientation="Horizontal"> - <Label Content="{l:Translate label_url}" /> + <Label Content="{support:Translate label_url}" /> <TextBox Text="{Binding Url}"/> </StackPanel> <StackPanel Orientation="Horizontal"> - <Label Content="{l:Translate label_timeout}" /> + <Label Content="{support:Translate label_timeout}" /> <TextBox Text="{Binding Timeout}"/> </StackPanel> <StackPanel Orientation="Horizontal"> - <Label Content="{l:Translate upload_format}" /> + <Label Content="{support:Translate upload_format}" /> <ComboBox ItemsSource="{Binding Source={StaticResource outputFormats},Path=DisplayNames}" SelectedValue="{Binding UploadFormat, Converter={StaticResource outputFormats}}" /> </StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> - <Button IsDefault="True" Content="{l:Translate OK}" Click="Button_OK_Click"/> - <Button IsCancel="True" Content="{l:Translate CANCEL}"/> + <Button IsDefault="True" Content="{support:Translate OK}" Click="Button_OK_Click"/> + <Button IsCancel="True" Content="{support:Translate CANCEL}"/> </StackPanel> </StackPanel> </Window> \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs b/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs index ca662b316..8545d91a0 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs +++ b/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs @@ -21,7 +21,7 @@ using System.Windows; -namespace GreenshotConfluencePlugin { +namespace GreenshotConfluencePlugin.Forms { /// <summary> /// Interaction logic for ConfluenceConfigurationForm.xaml /// </summary> diff --git a/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml b/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml index 6455e86b5..e9ae3f97b 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml +++ b/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml @@ -1,4 +1,4 @@ -<Page x:Class="GreenshotConfluencePlugin.ConfluencePagePicker" +<Page x:Class="GreenshotConfluencePlugin.Forms.ConfluencePagePicker" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Loaded="Page_Loaded"> diff --git a/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs b/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs index 9d52f49e9..7ce72fd4f 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs +++ b/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs @@ -19,10 +19,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -using Confluence; using System.Collections.Generic; -namespace GreenshotConfluencePlugin { +namespace GreenshotConfluencePlugin.Forms { /// <summary> /// Interaction logic for ConfluencePagePicker.xaml /// </summary> diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml b/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml index e30f9ab6e..073a437fe 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml +++ b/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> -<Page x:Class="GreenshotConfluencePlugin.ConfluenceSearch" +<Page x:Class="GreenshotConfluencePlugin.Forms.ConfluenceSearch" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:l="clr-namespace:TranslationByMarkupExtension" Loaded="Page_Loaded"> + xmlns:support="clr-namespace:GreenshotConfluencePlugin.Support" + Loaded="Page_Loaded"> <Grid MaxHeight="500"> <Grid.ColumnDefinitions> <ColumnDefinition Width="100" /> @@ -16,9 +17,9 @@ </Grid.RowDefinitions> <Label Grid.Row="0" Grid.Column="0" Content="Space" /> <ComboBox Grid.Row="0" Grid.Column="1" Name="SpaceComboBox" ItemsSource="{Binding Path=Spaces}" DisplayMemberPath="Name" SelectedValuePath="Key"/> - <Label Grid.Row="1" Grid.Column="0" Content="{l:Translate search_text}" /> - <TextBox Grid.Row="1" Grid.Column="1" Name="searchText" Text="" KeyDown="SearchText_KeyDown" TextChanged="searchText_TextChanged"/> - <Button Grid.Row="2" Grid.ColumnSpan="2" Name="Search" Content="{l:Translate search}" Click="Search_Click" IsEnabled="False"/> + <Label Grid.Row="1" Grid.Column="0" Content="{support:Translate search_text}" /> + <TextBox Grid.Row="1" Grid.Column="1" Name="searchText" Text="" KeyDown="SearchText_KeyDown" TextChanged="SearchText_TextChanged"/> + <Button Grid.Row="2" Grid.ColumnSpan="2" Name="Search" Content="{support:Translate search}" Click="Search_Click" IsEnabled="False"/> <ListView Grid.Row="3" Grid.ColumnSpan="2" Name="PageListView" SelectionMode="Single" ItemsSource="{Binding Path=Pages}" SelectionChanged="PageListView_SelectionChanged"> <ListView.ItemTemplate> <DataTemplate> diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs b/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs index 1b5c3877e..e30ed9dc4 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs +++ b/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs @@ -25,15 +25,15 @@ using System.Linq; using System.Windows; using GreenshotPlugin.IniFile; -namespace GreenshotConfluencePlugin { +namespace GreenshotConfluencePlugin.Forms { public partial class ConfluenceSearch { private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection<ConfluenceConfiguration>(); private readonly ConfluenceUpload _confluenceUpload; - public IEnumerable<Confluence.Space> Spaces => _confluenceUpload.Spaces; + public IEnumerable<Space> Spaces => _confluenceUpload.Spaces; - public ObservableCollection<Confluence.Page> Pages { get; } = new ObservableCollection<Confluence.Page>(); + public ObservableCollection<Page> Pages { get; } = new ObservableCollection<Page>(); public ConfluenceSearch(ConfluenceUpload confluenceUpload) { _confluenceUpload = confluenceUpload; @@ -56,7 +56,7 @@ namespace GreenshotConfluencePlugin { private void SelectionChanged() { if (PageListView.HasItems && PageListView.SelectedItems.Count > 0) { - _confluenceUpload.SelectedPage = (Confluence.Page)PageListView.SelectedItem; + _confluenceUpload.SelectedPage = (Page)PageListView.SelectedItem; } else { _confluenceUpload.SelectedPage = null; } @@ -86,7 +86,7 @@ namespace GreenshotConfluencePlugin { SelectionChanged(); } - private void searchText_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) { + private void SearchText_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) { Search.IsEnabled = !string.IsNullOrEmpty(searchText.Text); } } diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml b/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml index 97352d47e..4ca2a11ad 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml +++ b/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> -<Page x:Class="GreenshotConfluencePlugin.ConfluenceTreePicker" +<Page x:Class="GreenshotConfluencePlugin.Forms.ConfluenceTreePicker" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:l="clr-namespace:TranslationByMarkupExtension" + xmlns:support="clr-namespace:GreenshotConfluencePlugin.Support" Loaded="Page_Loaded"> <Grid Width="500"> <TreeView Name="ConfluenceTreeView" MaxHeight="500" @@ -10,7 +10,7 @@ VerticalAlignment="Top" HorizontalAlignment="Left" /> <Border Name="ShowBusy" BorderBrush="Black" BorderThickness="1" Background="#80000000" Visibility="Visible"> <TextBlock Margin="0" TextWrapping="Wrap" HorizontalAlignment="Center" VerticalAlignment="Center" - FontSize="18" FontWeight="Bold" Foreground="#7EFFFFFF" Text="{l:Translate loading}"/> + FontSize="18" FontWeight="Bold" Foreground="#7EFFFFFF" Text="{support:Translate loading}"/> </Border> </Grid> </Page> \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs b/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs index 78fb2235d..b154ad357 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs +++ b/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs @@ -27,10 +27,7 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Threading; -using Confluence; -using Page = Confluence.Page; - -namespace GreenshotConfluencePlugin { +namespace GreenshotConfluencePlugin.Forms { /// <summary> /// Interaction logic for ConfluenceTreePicker.xaml /// </summary> @@ -47,10 +44,10 @@ namespace GreenshotConfluencePlugin { InitializeComponent(); } - private void pageTreeViewItem_DoubleClick(object sender, MouseButtonEventArgs eventArgs) { + private void PageTreeViewItem_DoubleClick(object sender, MouseButtonEventArgs eventArgs) { Log.Debug("spaceTreeViewItem_MouseLeftButtonDown is called!"); TreeViewItem clickedItem = eventArgs.Source as TreeViewItem; - if (!(clickedItem?.Tag is Page page)) { + if (clickedItem?.Tag is not Page page) { return; } if (clickedItem.HasItems) @@ -70,20 +67,20 @@ namespace GreenshotConfluencePlugin { Tag = childPage }; clickedItem.Items.Add(pageTreeViewItem); - pageTreeViewItem.PreviewMouseDoubleClick += pageTreeViewItem_DoubleClick; - pageTreeViewItem.PreviewMouseLeftButtonDown += pageTreeViewItem_Click; + pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick; + pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click; } ShowBusy.Visibility = Visibility.Collapsed; })); }) { Name = "Loading childpages for confluence page " + page.Title }.Start(); } - private void pageTreeViewItem_Click(object sender, MouseButtonEventArgs eventArgs) { + private void PageTreeViewItem_Click(object sender, MouseButtonEventArgs eventArgs) { Log.Debug("pageTreeViewItem_PreviewMouseDoubleClick is called!"); - if (!(eventArgs.Source is TreeViewItem clickedItem)) { + if (eventArgs.Source is not TreeViewItem clickedItem) { return; } - Confluence.Page page = clickedItem.Tag as Confluence.Page; + Page page = clickedItem.Tag as Page; _confluenceUpload.SelectedPage = page; if (page != null) { Log.Debug("Page selected: " + page.Title); @@ -107,14 +104,14 @@ namespace GreenshotConfluencePlugin { // Get homepage try { - Confluence.Page page = _confluenceConnector.GetSpaceHomepage(space); + Page page = _confluenceConnector.GetSpaceHomepage(space); TreeViewItem pageTreeViewItem = new TreeViewItem { Header = page.Title, Tag = page }; - pageTreeViewItem.PreviewMouseDoubleClick += pageTreeViewItem_DoubleClick; - pageTreeViewItem.PreviewMouseLeftButtonDown += pageTreeViewItem_Click; + pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick; + pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click; spaceTreeViewItem.Items.Add(pageTreeViewItem); ConfluenceTreeView.Items.Add(spaceTreeViewItem); } catch (Exception ex) { diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml b/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml index aa97142a6..f6ec6f13a 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml +++ b/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml @@ -1,17 +1,17 @@ -<Window x:Class="GreenshotConfluencePlugin.ConfluenceUpload" +<Window x:Class="GreenshotConfluencePlugin.Forms.ConfluenceUpload" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:l="clr-namespace:TranslationByMarkupExtension" - Title="{l:Translate upload_menu_item}" Height="640" Width="500" Icon="/GreenshotConfluencePlugin;component/Images/Confluence.ico"> + xmlns:support="clr-namespace:GreenshotConfluencePlugin.Support" + Title="{support:Translate upload_menu_item}" Height="640" Width="500" Icon="/GreenshotConfluencePlugin;component/Images/Confluence.ico"> <StackPanel> <TabControl> - <TabItem Header="{l:Translate open_pages}" Name="PickerTab"> + <TabItem Header="{support:Translate open_pages}" Name="PickerTab"> <Frame NavigationUIVisibility="Hidden" Content="{Binding Path=PickerPage}" Height="500"/> </TabItem> - <TabItem Header="{l:Translate search_pages}" Name="SearchTab"> + <TabItem Header="{support:Translate search_pages}" Name="SearchTab"> <Frame NavigationUIVisibility="Hidden" Content="{Binding Path=SearchPage}" Height="500"/> </TabItem> - <TabItem Header="{l:Translate browse_pages}"> + <TabItem Header="{support:Translate browse_pages}"> <Frame NavigationUIVisibility="Hidden" Content="{Binding Path=BrowsePage}" Height="500"/> </TabItem> </TabControl> @@ -23,12 +23,12 @@ <Grid.RowDefinitions> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> - <Label Grid.Row="0" Grid.Column="0" Content="{l:Translate filename}" /> + <Label Grid.Row="0" Grid.Column="0" Content="{support:Translate filename}" /> <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=Filename}" /> </Grid> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> - <Button Name="Upload" Content="{l:Translate upload}" IsDefault="True" IsEnabled="False" Click="Upload_Click" /> - <Button Name="Cancel" Content="{l:Translate CANCEL}" IsCancel="True" /> + <Button Name="Upload" Content="{support:Translate upload}" IsDefault="True" IsEnabled="False" Click="Upload_Click" /> + <Button Name="Cancel" Content="{support:Translate CANCEL}" IsCancel="True" /> </StackPanel> </StackPanel> </Window> \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs b/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs index 76c82b2df..86c5ff4e4 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs +++ b/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs @@ -18,23 +18,23 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Windows; -using System.Windows.Controls; -namespace GreenshotConfluencePlugin { +namespace GreenshotConfluencePlugin.Forms { /// <summary> /// Interaction logic for ConfluenceUpload.xaml /// </summary> public partial class ConfluenceUpload : Window { - private Page _pickerPage; - public Page PickerPage { + private System.Windows.Controls.Page _pickerPage; + public System.Windows.Controls.Page PickerPage { get { if (_pickerPage == null) { - List<Confluence.Page> pages = ConfluenceUtils.GetCurrentPages(); + List<Page> pages = ConfluenceUtils.GetCurrentPages(); if (pages != null && pages.Count > 0) { _pickerPage = new ConfluencePagePicker(this, pages); } @@ -43,21 +43,19 @@ namespace GreenshotConfluencePlugin { } } - private Page _searchPage; - public Page SearchPage { + private System.Windows.Controls.Page _searchPage; + public System.Windows.Controls.Page SearchPage { get { return _searchPage ??= new ConfluenceSearch(this); } } - private Page _browsePage; - public Page BrowsePage { + private System.Windows.Controls.Page _browsePage; + public System.Windows.Controls.Page BrowsePage { get { return _browsePage ??= new ConfluenceTreePicker(this); } } - private Confluence.Page _selectedPage; - public Confluence.Page SelectedPage { - get { - return _selectedPage; - } + private Page _selectedPage; + public Page SelectedPage { + get => _selectedPage; set { _selectedPage = value; Upload.IsEnabled = _selectedPage != null; @@ -75,8 +73,8 @@ namespace GreenshotConfluencePlugin { } private static DateTime _lastLoad = DateTime.Now; - private static IList<Confluence.Space> _spaces; - public IList<Confluence.Space> Spaces { + private static IList<Space> _spaces; + public IList<Space> Spaces { get { UpdateSpaces(); while (_spaces == null) { diff --git a/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs b/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs index fa3d4e027..85b380840 100644 --- a/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs +++ b/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs @@ -18,92 +18,96 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + using System.Collections; using System.Windows.Forms; -/// <summary> -/// This class is an implementation of the 'IComparer' interface. -/// </summary> -public class ListViewColumnSorter : IComparer { +namespace GreenshotConfluencePlugin.Forms +{ /// <summary> - /// Specifies the column to be sorted + /// This class is an implementation of the 'IComparer' interface. /// </summary> - private int _columnToSort; - /// <summary> - /// Specifies the order in which to sort (i.e. 'Ascending'). - /// </summary> - private SortOrder _orderOfSort; - /// <summary> - /// Case insensitive comparer object - /// </summary> - private readonly CaseInsensitiveComparer _objectCompare; + public class ListViewColumnSorter : IComparer { + /// <summary> + /// Specifies the column to be sorted + /// </summary> + private int _columnToSort; + /// <summary> + /// Specifies the order in which to sort (i.e. 'Ascending'). + /// </summary> + private SortOrder _orderOfSort; + /// <summary> + /// Case insensitive comparer object + /// </summary> + private readonly CaseInsensitiveComparer _objectCompare; - /// <summary> - /// Class constructor. Initializes various elements - /// </summary> - public ListViewColumnSorter() { - // Initialize the column to '0' - _columnToSort = 0; + /// <summary> + /// Class constructor. Initializes various elements + /// </summary> + public ListViewColumnSorter() { + // Initialize the column to '0' + _columnToSort = 0; - // Initialize the sort order to 'none' - _orderOfSort = SortOrder.None; + // Initialize the sort order to 'none' + _orderOfSort = SortOrder.None; + + // Initialize the CaseInsensitiveComparer object + _objectCompare = new CaseInsensitiveComparer(); + } + + /// <summary> + /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison. + /// </summary> + /// <param name="x">First object to be compared</param> + /// <param name="y">Second object to be compared</param> + /// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns> + public int Compare(object x, object y) { + int compareResult; + ListViewItem listviewX, listviewY; + + // Cast the objects to be compared to ListViewItem objects + listviewX = (ListViewItem)x; + listviewY = (ListViewItem)y; + + // Compare the two items + compareResult = _objectCompare.Compare(listviewX.SubItems[_columnToSort].Text, listviewY.SubItems[_columnToSort].Text); + + // Calculate correct return value based on object comparison + if (_orderOfSort == SortOrder.Ascending) { + // Ascending sort is selected, return normal result of compare operation + return compareResult; + } else if (_orderOfSort == SortOrder.Descending) { + // Descending sort is selected, return negative result of compare operation + return (-compareResult); + } else { + // Return '0' to indicate they are equal + return 0; + } + } + + /// <summary> + /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0'). + /// </summary> + public int SortColumn { + set { + _columnToSort = value; + } + get { + return _columnToSort; + } + } + + /// <summary> + /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending'). + /// </summary> + public SortOrder Order { + set { + _orderOfSort = value; + } + get { + return _orderOfSort; + } + } - // Initialize the CaseInsensitiveComparer object - _objectCompare = new CaseInsensitiveComparer(); } - - /// <summary> - /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison. - /// </summary> - /// <param name="x">First object to be compared</param> - /// <param name="y">Second object to be compared</param> - /// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns> - public int Compare(object x, object y) { - int compareResult; - ListViewItem listviewX, listviewY; - - // Cast the objects to be compared to ListViewItem objects - listviewX = (ListViewItem)x; - listviewY = (ListViewItem)y; - - // Compare the two items - compareResult = _objectCompare.Compare(listviewX.SubItems[_columnToSort].Text, listviewY.SubItems[_columnToSort].Text); - - // Calculate correct return value based on object comparison - if (_orderOfSort == SortOrder.Ascending) { - // Ascending sort is selected, return normal result of compare operation - return compareResult; - } else if (_orderOfSort == SortOrder.Descending) { - // Descending sort is selected, return negative result of compare operation - return (-compareResult); - } else { - // Return '0' to indicate they are equal - return 0; - } - } - - /// <summary> - /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0'). - /// </summary> - public int SortColumn { - set { - _columnToSort = value; - } - get { - return _columnToSort; - } - } - - /// <summary> - /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending'). - /// </summary> - public SortOrder Order { - set { - _orderOfSort = value; - } - get { - return _orderOfSort; - } - } - } diff --git a/GreenshotConfluencePlugin/Support/ITranslationProvider.cs b/GreenshotConfluencePlugin/Support/ITranslationProvider.cs index 79efd538c..02180f036 100644 --- a/GreenshotConfluencePlugin/Support/ITranslationProvider.cs +++ b/GreenshotConfluencePlugin/Support/ITranslationProvider.cs @@ -1,4 +1,4 @@ -namespace TranslationByMarkupExtension { +namespace GreenshotConfluencePlugin.Support { public interface ITranslationProvider { /// <summary> /// Translates the specified key. diff --git a/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs b/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs index 8fe9289d3..c9fb55704 100644 --- a/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs +++ b/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs @@ -1,7 +1,7 @@ using System; using System.Windows; -namespace TranslationByMarkupExtension +namespace GreenshotConfluencePlugin.Support { public class LanguageChangedEventManager : WeakEventManager { diff --git a/GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs b/GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs index 3b23c0d58..23dbc4fc1 100644 --- a/GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs +++ b/GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs @@ -1,6 +1,6 @@ using GreenshotPlugin.Core; -namespace TranslationByMarkupExtension { +namespace GreenshotConfluencePlugin.Support { /// <summary> /// /// </summary> diff --git a/GreenshotConfluencePlugin/Support/TranslateExtension.cs b/GreenshotConfluencePlugin/Support/TranslateExtension.cs index c581efc77..3730e7baa 100644 --- a/GreenshotConfluencePlugin/Support/TranslateExtension.cs +++ b/GreenshotConfluencePlugin/Support/TranslateExtension.cs @@ -2,7 +2,7 @@ using System.Windows.Data; using System.Windows.Markup; -namespace TranslationByMarkupExtension +namespace GreenshotConfluencePlugin.Support { /// <summary> /// The Translate Markup extension returns a binding to a TranslationData diff --git a/GreenshotConfluencePlugin/Support/TranslationData.cs b/GreenshotConfluencePlugin/Support/TranslationData.cs index e659a0be3..0b6371505 100644 --- a/GreenshotConfluencePlugin/Support/TranslationData.cs +++ b/GreenshotConfluencePlugin/Support/TranslationData.cs @@ -2,7 +2,7 @@ using System.ComponentModel; using System.Windows; -namespace TranslationByMarkupExtension { +namespace GreenshotConfluencePlugin.Support { public class TranslationData : IWeakEventListener, INotifyPropertyChanged { private readonly string _key; diff --git a/GreenshotConfluencePlugin/Support/TranslationManager.cs b/GreenshotConfluencePlugin/Support/TranslationManager.cs index d11d36cd5..241cce868 100644 --- a/GreenshotConfluencePlugin/Support/TranslationManager.cs +++ b/GreenshotConfluencePlugin/Support/TranslationManager.cs @@ -1,6 +1,6 @@ using System; -namespace TranslationByMarkupExtension { +namespace GreenshotConfluencePlugin.Support { public class TranslationManager { private static TranslationManager _translationManager; diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 329355afa..5043dd397 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -30,10 +30,6 @@ stages: steps: - task: NuGetToolInstaller@1 - - powershell: | - choco install msbuild.communitytasks - displayName: 'Installing MSBuild community tasks' - - task: NuGetCommand@2 displayName: NuGet restore inputs: From 5899d97ec2c4cc65af35dedb0f280c441e7438c1 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Thu, 28 Jan 2021 21:49:02 +0100 Subject: [PATCH 077/232] Another try to fix the build. --- Directory.Build.props | 2 +- Directory.Build.targets | 6 +++++- azure-pipelines.yml | 13 ++----------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b1f50e7b1..c87c75734 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -104,7 +104,7 @@ </ItemGroup> <!-- Add MSBuild.Community.Tasks to use the TemplateFile Task--> - <ItemGroup Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"> + <ItemGroup> <PackageReference Include="MSBuildTasks" Version="1.5.0.235" GeneratePathProperty="true" DevelopmentDependency="true" /> </ItemGroup> diff --git a/Directory.Build.targets b/Directory.Build.targets index e84907085..f2ce406a1 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,6 +1,10 @@ <Project> - <Import Project="$(PkgMSBuildTasks)\tools\MSBuild.Community.Tasks.Targets" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"/> + <PropertyGroup Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"> + <MSBuildCommunityTasksPath>$(PkgMSBuildTasks)\tools\</MSBuildCommunityTasksPath> + </PropertyGroup> + + <Import Project="$(MSBuildCommunityTasksPath)MSBuild.Community.Tasks.Targets" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"/> <Target Name="ProcessTemplates" BeforeTargets="PrepareForBuild" Condition="Exists('$(ProjectDir)$(ProjectName).Credentials.template')"> <Message Text="Processing: $(ProjectDir)$(ProjectName).Credentials.template" Importance="high"/> diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5043dd397..21d640496 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -28,22 +28,13 @@ stages: vmImage: 'Windows-latest' steps: - - task: NuGetToolInstaller@1 - - - task: NuGetCommand@2 - displayName: NuGet restore - inputs: - command: 'restore' - restoreSolution: '$(solution)' - feedsToUse: config - - task: MSBuild@1 - displayName: Generate templates + displayName: Restore nuget packages and generate credential templates inputs: solution: '$(solution)' platform: $(buildPlatform) configuration: $(buildConfiguration) - msbuildArguments: '/t:PrepareForBuild' + msbuildArguments: '/restore /t:PrepareForBuild' - task: MSBuild@1 displayName: Build and package From e5019bbb9d3fcf0936b77a610a47a9aaa82d7629 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sun, 31 Jan 2021 20:34:56 +0100 Subject: [PATCH 078/232] A fix for a bug reported in #258, there still was a DLL missing. [skip ci] --- Greenshot/releases/innosetup/setup.iss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 7735af213..3195d1f55 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -85,7 +85,7 @@ Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe; DestDi Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe.config; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; ;JIRA Plugin Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\GreenshotJiraPlugin.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\Dapplo.Jira.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\Dapplo.Jira*.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\GreenshotJiraPlugin\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion; ;Imgur Plugin Source: {#BaseDir}\GreenshotImgurPlugin\{#BinDir}\GreenshotImgurPlugin.dll; DestDir: {app}\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; @@ -133,7 +133,7 @@ DefaultGroupName={#ExeName} InfoBeforeFile=..\additional_files\readme.txt LicenseFile=..\additional_files\license.txt LanguageDetectionMethod=uilanguage -MinVersion=6.1.7600 +MinVersion=6.1sp1 OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE OutputDir=..\ PrivilegesRequired=lowest From d9a6922310a3ebd04553cd7a90383f42b0b077be Mon Sep 17 00:00:00 2001 From: k41c <51283438+k41c@users.noreply.github.com> Date: Fri, 19 Feb 2021 13:57:38 +0100 Subject: [PATCH 079/232] Update ImageEditorForm.cs --- Greenshot/Forms/ImageEditorForm.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index 6e19df179..c67b434f0 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -898,13 +898,29 @@ namespace Greenshot { } } } - +DateTime zoomStartTime = DateTime.Now; /// <summary> /// This is a "work-around" for the MouseWheel event which doesn't get to the panel /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void PanelMouseWheel(object sender, MouseEventArgs e) { + if (System.Windows.Forms.Control.ModifierKeys.Equals(Keys.Control)) + { + if (zoomStartTime.AddMilliseconds(100) < DateTime.Now) //waiting for next zoom step 100 ms + { + zoomStartTime = DateTime.Now; + if (e.Delta > 0) + { + ZoomInMenuItemClick(sender, e); + } + else if (e.Delta < 0) + { + ZoomOutMenuItemClick(sender, e); + } + } + + } panel1.Focus(); } From a3e4f2f92e4db63bd622e92f3420997abc9223cb Mon Sep 17 00:00:00 2001 From: k41c <51283438+k41c@users.noreply.github.com> Date: Fri, 19 Feb 2021 13:58:39 +0100 Subject: [PATCH 080/232] Update NonJumpingPanel.cs --- Greenshot/Controls/NonJumpingPanel.cs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/Greenshot/Controls/NonJumpingPanel.cs b/Greenshot/Controls/NonJumpingPanel.cs index 51658a105..f8595c28a 100644 --- a/Greenshot/Controls/NonJumpingPanel.cs +++ b/Greenshot/Controls/NonJumpingPanel.cs @@ -38,16 +38,28 @@ namespace GreenshotPlugin.Controls { /// </summary> /// <param name="e">MouseEventArgs</param> protected override void OnMouseWheel(MouseEventArgs e) - { - if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift) - { + {//Check if Scrollbars available and CTRL key pressed -> Zoom IN OUT + if((VScroll || HScroll)&& (ModifierKeys & Keys.Control) == Keys.Control) + { VScroll = false; + HScroll = false; base.OnMouseWheel(e); VScroll = true; + HScroll = true; } - else - { - base.OnMouseWheel(e); + else + { + //Vertical Scoll with SHIFT key pressed + if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift ) + { + VScroll = false; + base.OnMouseWheel(e); + VScroll = true; + } + else + { + base.OnMouseWheel(e); + } } } } From ee9d1325b57a746371a56c476841ef69b9e975de Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Fri, 19 Feb 2021 23:06:41 +0100 Subject: [PATCH 081/232] Formatting fix --- Greenshot/Controls/NonJumpingPanel.cs | 80 ++++++++++++++------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/Greenshot/Controls/NonJumpingPanel.cs b/Greenshot/Controls/NonJumpingPanel.cs index f8595c28a..4d107da45 100644 --- a/Greenshot/Controls/NonJumpingPanel.cs +++ b/Greenshot/Controls/NonJumpingPanel.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom * @@ -22,45 +22,49 @@ using System.Drawing; using System.Windows.Forms; -namespace GreenshotPlugin.Controls { - /// <summary> - /// See: http://nickstips.wordpress.com/2010/03/03/c-panel-resets-scroll-position-after-focus-is-lost-and-regained/ - /// </summary> - public class NonJumpingPanel : Panel { - protected override Point ScrollToControl(Control activeControl) { - // Returning the current location prevents the panel from - // scrolling to the active control when the panel loses and regains focus - return DisplayRectangle.Location; - } +namespace GreenshotPlugin.Controls +{ + /// <summary> + /// See: http://nickstips.wordpress.com/2010/03/03/c-panel-resets-scroll-position-after-focus-is-lost-and-regained/ + /// </summary> + public class NonJumpingPanel : Panel + { + protected override Point ScrollToControl(Control activeControl) + { + // Returning the current location prevents the panel from + // scrolling to the active control when the panel loses and regains focus + return DisplayRectangle.Location; + } - /// <summary> - /// Add horizontal scrolling to the panel, when using the wheel and the shift key is pressed - /// </summary> - /// <param name="e">MouseEventArgs</param> - protected override void OnMouseWheel(MouseEventArgs e) - {//Check if Scrollbars available and CTRL key pressed -> Zoom IN OUT - if((VScroll || HScroll)&& (ModifierKeys & Keys.Control) == Keys.Control) + /// <summary> + /// Add horizontal scrolling to the panel, when using the wheel and the shift key is pressed + /// </summary> + /// <param name="e">MouseEventArgs</param> + protected override void OnMouseWheel(MouseEventArgs e) + { + //Check if Scrollbars available and CTRL key pressed -> Zoom IN OUT + if ((VScroll || HScroll) && (ModifierKeys & Keys.Control) == Keys.Control) { - VScroll = false; - HScroll = false; - base.OnMouseWheel(e); - VScroll = true; - HScroll = true; - } + VScroll = false; + HScroll = false; + base.OnMouseWheel(e); + VScroll = true; + HScroll = true; + } else { - //Vertical Scoll with SHIFT key pressed - if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift ) - { - VScroll = false; - base.OnMouseWheel(e); - VScroll = true; - } - else - { - base.OnMouseWheel(e); - } - } - } - } + //Vertical Scoll with SHIFT key pressed + if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift) + { + VScroll = false; + base.OnMouseWheel(e); + VScroll = true; + } + else + { + base.OnMouseWheel(e); + } + } + } + } } From c8ade4258b572ef1f8abe9acee21224c7dee6645 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin.krom@gmail.com> Date: Fri, 19 Feb 2021 23:12:15 +0100 Subject: [PATCH 082/232] Fixed formatting --- Greenshot/Forms/ImageEditorForm.cs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index c67b434f0..ece824bdb 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -66,6 +66,9 @@ namespace Greenshot { // whether part of the editor controls are disabled depending on selected item(s) private bool _controlsDisabledDueToConfirmable; + // Used for tracking the mouse scrollwheel changes + private DateTime _zoomStartTime = DateTime.Now; + /// <summary> /// All provided zoom values (in percents) in ascending order. /// </summary> @@ -898,18 +901,24 @@ namespace Greenshot { } } } -DateTime zoomStartTime = DateTime.Now; + /// <summary> /// This is a "work-around" for the MouseWheel event which doesn't get to the panel /// </summary> /// <param name="sender"></param> /// <param name="e"></param> - private void PanelMouseWheel(object sender, MouseEventArgs e) { + /// <summary> + /// This is a "work-around" for the MouseWheel event which doesn't get to the panel + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + private void PanelMouseWheel(object sender, MouseEventArgs e) + { if (System.Windows.Forms.Control.ModifierKeys.Equals(Keys.Control)) - { - if (zoomStartTime.AddMilliseconds(100) < DateTime.Now) //waiting for next zoom step 100 ms - { - zoomStartTime = DateTime.Now; + { + if (_zoomStartTime.AddMilliseconds(100) < DateTime.Now) //waiting for next zoom step 100 ms + { + _zoomStartTime = DateTime.Now; if (e.Delta > 0) { ZoomInMenuItemClick(sender, e); @@ -919,12 +928,12 @@ DateTime zoomStartTime = DateTime.Now; ZoomOutMenuItemClick(sender, e); } } - - } + + } panel1.Focus(); } - protected override bool ProcessKeyPreview(ref Message msg) { + protected override bool ProcessKeyPreview(ref Message msg) { // disable default key handling if surface has requested a lock if (!_surface.KeysLocked) { return base.ProcessKeyPreview(ref msg); From f116e5db54c0a8e2b92e1012b69d470651f3a303 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Mon, 1 Mar 2021 20:11:00 +0100 Subject: [PATCH 083/232] Place the funding and templates in the 1.3 as this seems to be taken from the default branch. [skip ci] --- .github/FUNDING.yml | 9 +++++ .github/ISSUE_TEMPLATE/bug_report.md | 33 +++++++++++++++++++ .../ISSUE_TEMPLATE/developer-bug-report.md | 33 +++++++++++++++++++ .../developer-feature-request.md | 22 +++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 22 +++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 .github/FUNDING.yml create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/developer-bug-report.md create mode 100644 .github/ISSUE_TEMPLATE/developer-feature-request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..a7184f71b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,9 @@ +# These are supported funding model platforms + +# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +github: lakritzator +patreon: # Replace with a single Patreon username +open_collective: greenshot +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +custom: https://getgreenshot.org/support/ diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..1f5ca2f11 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,33 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +This GitHub repository is for developers, if you want to report a bug for Greenshot as a user please do so in our JIRA issue system here: https://greenshot.atlassian.net/projects/BUGS/issues/filter=allopenissues + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Example steps to reproduce the behavior: +1. Capture '....' +2. Open Editor +3. Add a line +4. Resize + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Versions (please complete the following information):** + - Greenshot version + - Windows version + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/developer-bug-report.md b/.github/ISSUE_TEMPLATE/developer-bug-report.md new file mode 100644 index 000000000..1ffa7da1e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/developer-bug-report.md @@ -0,0 +1,33 @@ +--- +name: Developer Bug report +about: Create a bug report to help us improve our code +title: '' +labels: '' +assignees: '' + +--- + +This GitHub repository is for developers, if you want to report a bug for Greenshot as a user please do so in our JIRA issue system here: https://greenshot.atlassian.net/projects/BUGS/issues/filter=allopenissues + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Example steps to reproduce the behavior: +1. Capture '....' +2. Open Editor +3. Add a line +4. Resize + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Versions (please complete the following information):** + - Greenshot version + - Windows version + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/developer-feature-request.md b/.github/ISSUE_TEMPLATE/developer-feature-request.md new file mode 100644 index 000000000..883534a57 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/developer-feature-request.md @@ -0,0 +1,22 @@ +--- +name: Developer feature request +about: Suggest an technical idea for this project +title: '' +labels: '' +assignees: '' + +--- + +This GitHub repository is for developers, if you want to request a feature for Greenshot as a user please do so in our JIRA issue system here: https://greenshot.atlassian.net/projects/FEATURE/issues/filter=allopenissues + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..64323a13d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,22 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +This GitHub repository is for developers, if you want to request a feature for Greenshot as a user please do so in our JIRA issue system here: https://greenshot.atlassian.net/projects/FEATURE/issues/filter=allopenissues + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From aff8ba2109d80797ab81165f645919524eae4981 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Mon, 8 Mar 2021 22:08:12 +0100 Subject: [PATCH 084/232] Fixed copyright, fixed some spelling and updated some of the code to a newer syntax. --- .gitignore | 5 +- Directory.Build.props | 2 +- Greenshot.sln.DotSettings | 4 + .../Configuration/EditorConfiguration.cs | 2 +- Greenshot/Configuration/LanguageKeys.cs | 2 +- Greenshot/Controls/BindableToolStripButton.cs | 2 +- .../Controls/BindableToolStripComboBox.cs | 2 +- .../BindableToolStripDropDownButton.cs | 2 +- Greenshot/Controls/ColorButton.cs | 3 +- ...ontextMenuToolStripProfessionalRenderer.cs | 2 +- .../CustomToolStripProfessionalRenderer.cs | 2 +- Greenshot/Controls/FontFamilyComboBox.cs | 2 +- Greenshot/Controls/MenuStripEx.cs | 2 +- Greenshot/Controls/NonJumpingPanel.cs | 4 +- Greenshot/Controls/Pipette.cs | 3 +- Greenshot/Controls/ToolStripColorButton.cs | 3 +- Greenshot/Controls/ToolStripEx.cs | 2 +- Greenshot/Controls/ToolStripNumericUpDown.cs | 2 +- .../Destinations/ClipboardDestination.cs | 2 +- Greenshot/Destinations/EditorDestination.cs | 3 +- Greenshot/Destinations/EmailDestination.cs | 2 +- Greenshot/Destinations/FileDestination.cs | 3 +- .../Destinations/FileWithDialogDestination.cs | 2 +- Greenshot/Destinations/PickerDestination.cs | 2 +- Greenshot/Destinations/PrinterDestination.cs | 2 +- Greenshot/Drawing/Adorners/AbstractAdorner.cs | 2 +- Greenshot/Drawing/Adorners/MoveAdorner.cs | 2 +- Greenshot/Drawing/Adorners/ResizeAdorner.cs | 2 +- Greenshot/Drawing/Adorners/TargetAdorner.cs | 2 +- Greenshot/Drawing/ArrowContainer.cs | 2 +- Greenshot/Drawing/CropContainer.cs | 21 +- Greenshot/Drawing/CursorContainer.cs | 2 +- Greenshot/Drawing/DrawableContainer.cs | 44 +-- Greenshot/Drawing/DrawableContainerList.cs | 3 +- Greenshot/Drawing/EllipseContainer.cs | 2 +- .../Drawing/Fields/AbstractFieldHolder.cs | 2 +- .../Fields/AbstractFieldHolderWithChildren.cs | 2 +- .../Binding/AbstractBindingConverter.cs | 2 +- .../Fields/Binding/BidirectionalBinding.cs | 2 +- .../DecimalDoublePercentageConverter.cs | 2 +- .../Fields/Binding/DecimalFloatConverter.cs | 2 +- .../Fields/Binding/DecimalIntConverter.cs | 2 +- .../Fields/Binding/IBindingConverter.cs | 2 +- .../Fields/Binding/IBindingValidator.cs | 2 +- .../Fields/Binding/NotNullValidator.cs | 2 +- Greenshot/Drawing/Fields/Field.cs | 2 +- Greenshot/Drawing/Fields/FieldAggregator.cs | 2 +- Greenshot/Drawing/Fields/FieldType.cs | 2 +- Greenshot/Drawing/FilterContainer.cs | 2 +- Greenshot/Drawing/Filters/AbstractFilter.cs | 2 +- Greenshot/Drawing/Filters/BlurFilter.cs | 2 +- Greenshot/Drawing/Filters/BrightnessFilter.cs | 2 +- Greenshot/Drawing/Filters/GrayscaleFilter.cs | 2 +- Greenshot/Drawing/Filters/HighlightFilter.cs | 2 +- Greenshot/Drawing/Filters/IFilter.cs | 2 +- Greenshot/Drawing/Filters/MagnifierFilter.cs | 2 +- .../Drawing/Filters/PixelizationFilter.cs | 2 +- Greenshot/Drawing/FreehandContainer.cs | 2 +- Greenshot/Drawing/HighlightContainer.cs | 2 +- Greenshot/Drawing/IconContainer.cs | 2 +- Greenshot/Drawing/ImageContainer.cs | 2 +- Greenshot/Drawing/LineContainer.cs | 2 +- Greenshot/Drawing/ObfuscateContainer.cs | 2 +- Greenshot/Drawing/Positions.cs | 2 +- Greenshot/Drawing/RectangleContainer.cs | 2 +- Greenshot/Drawing/RoundedRectangle.cs | 2 +- Greenshot/Drawing/Surface.cs | 2 +- Greenshot/Drawing/TextContainer.cs | 24 +- Greenshot/Forms/AboutForm.Designer.cs | 2 +- Greenshot/Forms/AboutForm.cs | 2 +- Greenshot/Forms/AnimatingBaseForm.cs | 4 +- Greenshot/Forms/BaseForm.cs | 4 +- Greenshot/Forms/BugReportForm.Designer.cs | 2 +- Greenshot/Forms/BugReportForm.cs | 2 +- Greenshot/Forms/CaptureForm.Designer.cs | 2 +- Greenshot/Forms/CaptureForm.cs | 2 +- Greenshot/Forms/ColorDialog.Designer.cs | 4 +- Greenshot/Forms/ColorDialog.cs | 8 +- Greenshot/Forms/ColorPickerToolStripButton.cs | 10 +- .../Forms/DropShadowSettingsForm.Designer.cs | 2 +- Greenshot/Forms/DropShadowSettingsForm.cs | 2 +- Greenshot/Forms/ImageEditorForm.Designer.cs | 8 +- Greenshot/Forms/ImageEditorForm.cs | 5 +- Greenshot/Forms/LanguageDialog.Designer.cs | 2 +- Greenshot/Forms/LanguageDialog.cs | 2 +- Greenshot/Forms/MainForm.Designer.cs | 4 +- Greenshot/Forms/MainForm.cs | 21 +- Greenshot/Forms/MovableShowColorForm.cs | 2 +- .../Forms/PrintOptionsDialog.Designer.cs | 2 +- Greenshot/Forms/PrintOptionsDialog.cs | 2 +- .../Forms/ResizeSettingsForm.Designer.cs | 2 +- Greenshot/Forms/ResizeSettingsForm.cs | 2 +- Greenshot/Forms/SettingsForm.Designer.cs | 4 +- Greenshot/Forms/SettingsForm.cs | 12 +- Greenshot/Forms/ToolStripMenuSelectList.cs | 2 +- .../Forms/TornEdgeSettingsForm.Designer.cs | 2 +- Greenshot/Forms/TornEdgeSettingsForm.cs | 2 +- Greenshot/GreenshotMain.cs | 13 +- Greenshot/Help/HelpFileLoader.cs | 2 +- Greenshot/Helpers/CaptureHelper.cs | 2 +- Greenshot/Helpers/Colors.cs | 2 +- Greenshot/Helpers/CopyData.cs | 42 +-- Greenshot/Helpers/DestinationHelper.cs | 2 +- Greenshot/Helpers/Entities/UpdateFeed.cs | 2 +- Greenshot/Helpers/EnvironmentInfo.cs | 10 +- Greenshot/Helpers/GeometryHelper.cs | 2 +- Greenshot/Helpers/GuiRectangle.cs | 2 +- Greenshot/Helpers/IECaptureHelper.cs | 82 ++--- Greenshot/Helpers/IEInterop/IEContainer.cs | 2 +- Greenshot/Helpers/MailHelper.cs | 302 ++++++++---------- .../Helpers/NotifyIconNotificationService.cs | 2 +- Greenshot/Helpers/PluginHelper.cs | 2 +- Greenshot/Helpers/PrintHelper.cs | 39 ++- Greenshot/Helpers/ProcessorHelper.cs | 2 +- Greenshot/Helpers/ResourceMutex.cs | 33 +- Greenshot/Helpers/ScaleHelper.cs | 31 +- Greenshot/Helpers/SoundHelper.cs | 2 +- Greenshot/Helpers/StartupHelper.cs | 6 +- Greenshot/Helpers/ToolStripItemEndisabler.cs | 24 +- Greenshot/Helpers/UpdateService.cs | 2 +- Greenshot/Helpers/WindowWrapper.cs | 32 -- Greenshot/Languages/language-ar-SY.xml | 2 +- Greenshot/Languages/language-ca-CA.xml | 2 +- Greenshot/Languages/language-cs-CZ.xml | 2 +- Greenshot/Languages/language-de-DE.xml | 2 +- .../Languages/language-de-x-franconia.xml | 2 +- Greenshot/Languages/language-el-GR.xml | 2 +- Greenshot/Languages/language-en-US.xml | 2 +- Greenshot/Languages/language-es-ES.xml | 2 +- Greenshot/Languages/language-et-EE.xml | 2 +- Greenshot/Languages/language-fi-FI.xml | 2 +- Greenshot/Languages/language-fr-FR.xml | 2 +- Greenshot/Languages/language-fr-QC.xml | 2 +- Greenshot/Languages/language-he-IL.xml | 2 +- Greenshot/Languages/language-hu-HU.xml | 2 +- Greenshot/Languages/language-id-ID.xml | 54 ++-- Greenshot/Languages/language-it-IT.xml | 2 +- Greenshot/Languages/language-ja-JP.xml | 2 +- Greenshot/Languages/language-kab-DZ.xml | 2 +- Greenshot/Languages/language-ko-KR.xml | 2 +- Greenshot/Languages/language-lt-LT.xml | 2 +- Greenshot/Languages/language-nl-NL.xml | 2 +- Greenshot/Languages/language-nn-NO.xml | 2 +- Greenshot/Languages/language-pl-PL.xml | 2 +- Greenshot/Languages/language-pt-BR.xml | 2 +- Greenshot/Languages/language-pt-PT.xml | 2 +- Greenshot/Languages/language-ru-RU.xml | 2 +- Greenshot/Languages/language-sk-SK.xml | 2 +- Greenshot/Languages/language-sl-SI.xml | 22 +- Greenshot/Languages/language-sr-RS.xml | 2 +- Greenshot/Languages/language-sv-SE.xml | 2 +- Greenshot/Languages/language-tr-TR.xml | 2 +- Greenshot/Languages/language-uk-UA.xml | 2 +- Greenshot/Languages/language-vi-VN.xml | 2 +- Greenshot/Languages/language-zh-CN.xml | 2 +- Greenshot/Languages/language-zh-TW.xml | 2 +- Greenshot/Memento/AddElementMemento.cs | 2 +- Greenshot/Memento/AddElementsMemento.cs | 2 +- Greenshot/Memento/ChangeFieldHolderMemento.cs | 19 +- Greenshot/Memento/DeleteElementMemento.cs | 35 +- Greenshot/Memento/DeleteElementsMemento.cs | 4 +- .../DrawableContainerBoundsChangeMemento.cs | 23 +- .../Memento/SurfaceBackgroundChangeMemento.cs | 25 +- Greenshot/Memento/TextChangeMemento.cs | 30 +- Greenshot/Processors/TitleFixProcessor.cs | 2 +- .../releases/innosetup/scripts/products.pas | 2 +- GreenshotBoxPlugin/BoxConfiguration.cs | 3 +- GreenshotBoxPlugin/BoxDestination.cs | 2 +- GreenshotBoxPlugin/BoxEntities.cs | 2 +- GreenshotBoxPlugin/BoxPlugin.cs | 17 +- GreenshotBoxPlugin/BoxUtils.cs | 2 +- GreenshotBoxPlugin/Forms/BoxForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 4 +- GreenshotBoxPlugin/Forms/SettingsForm.cs | 6 +- .../GreenshotBoxPlugin.Credentials.template | 2 +- GreenshotBoxPlugin/LanguageKeys.cs | 2 +- GreenshotBoxPlugin/Properties/AssemblyInfo.cs | 2 +- GreenshotConfluencePlugin/Confluence.cs | 2 +- .../ConfluenceConfiguration.cs | 2 +- .../ConfluenceDestination.cs | 2 +- GreenshotConfluencePlugin/ConfluencePlugin.cs | 2 +- GreenshotConfluencePlugin/ConfluenceUtils.cs | 2 +- GreenshotConfluencePlugin/EnumDisplayer.cs | 2 +- .../Forms/ConfluenceConfigurationForm.xaml.cs | 2 +- .../Forms/ConfluencePagePicker.xaml.cs | 2 +- .../Forms/ConfluenceSearch.xaml.cs | 2 +- .../Forms/ConfluenceTreePicker.xaml.cs | 2 +- .../Forms/ConfluenceUpload.xaml.cs | 2 +- .../Forms/ListViewColumnSorter.cs | 2 +- GreenshotConfluencePlugin/LanguageKeys.cs | 2 +- GreenshotDropboxPlugin/DropboxDestination.cs | 2 +- GreenshotDropboxPlugin/DropboxPlugin.cs | 2 +- .../DropboxPluginConfiguration.cs | 3 +- GreenshotDropboxPlugin/DropboxUtils.cs | 2 +- GreenshotDropboxPlugin/Forms/DropboxForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 2 +- GreenshotDropboxPlugin/Forms/SettingsForm.cs | 6 +- ...reenshotDropboxPlugin.Credentials.template | 2 +- GreenshotDropboxPlugin/LanguageKeys.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- .../ExternalCommandConfiguration.cs | 2 +- .../ExternalCommandDestination.cs | 2 +- .../ExternalCommandForm.cs | 2 +- .../ExternalCommandPlugin.cs | 2 +- GreenshotExternalCommandPlugin/IconCache.cs | 2 +- .../SettingsForm.Designer.cs | 2 +- .../SettingsForm.cs | 2 +- .../SettingsFormDetail.Designer.cs | 2 +- .../SettingsFormDetail.cs | 2 +- GreenshotFlickrPlugin/FlickrConfiguration.cs | 3 +- GreenshotFlickrPlugin/FlickrDestination.cs | 2 +- GreenshotFlickrPlugin/FlickrPlugin.cs | 2 +- GreenshotFlickrPlugin/FlickrUtils.cs | 2 +- GreenshotFlickrPlugin/Forms/FlickrForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 4 +- GreenshotFlickrPlugin/Forms/SettingsForm.cs | 6 +- ...GreenshotFlickrPlugin.Credentials.template | 2 +- GreenshotFlickrPlugin/LanguageKeys.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- GreenshotImgurPlugin/Forms/ImgurForm.cs | 4 +- .../Forms/ImgurHistory.Designer.cs | 4 +- GreenshotImgurPlugin/Forms/ImgurHistory.cs | 6 +- .../Forms/SettingsForm.Designer.cs | 4 +- GreenshotImgurPlugin/Forms/SettingsForm.cs | 5 +- .../GreenshotImgurPlugin.Credentials.template | 2 +- GreenshotImgurPlugin/ImgurConfiguration.cs | 3 +- GreenshotImgurPlugin/ImgurDestination.cs | 2 +- GreenshotImgurPlugin/ImgurInfo.cs | 2 +- GreenshotImgurPlugin/ImgurPlugin.cs | 3 +- GreenshotImgurPlugin/ImgurUtils.cs | 2 +- GreenshotImgurPlugin/LanguageKeys.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- GreenshotJiraPlugin/AsyncMemoryCache.cs | 2 +- .../Forms/JiraForm.Designer.cs | 2 +- GreenshotJiraPlugin/Forms/JiraForm.cs | 2 +- GreenshotJiraPlugin/Forms/JiraFormBase.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 2 +- GreenshotJiraPlugin/Forms/SettingsForm.cs | 2 +- GreenshotJiraPlugin/IssueTypeBitmapCache.cs | 2 +- GreenshotJiraPlugin/JiraConfiguration.cs | 2 +- GreenshotJiraPlugin/JiraConnector.cs | 2 +- GreenshotJiraPlugin/JiraDestination.cs | 2 +- GreenshotJiraPlugin/JiraDetails.cs | 2 +- GreenshotJiraPlugin/JiraEventArgs.cs | 2 +- GreenshotJiraPlugin/JiraEventTypes.cs | 2 +- GreenshotJiraPlugin/JiraMonitor.cs | 2 +- GreenshotJiraPlugin/JiraPlugin.cs | 2 +- GreenshotJiraPlugin/LanguageKeys.cs | 2 +- GreenshotJiraPlugin/Log4NetLogger.cs | 2 +- GreenshotOCRCommand/COMWrapper.cs | 5 +- GreenshotOCRCommand/ComProgIdAttribute.cs | 4 +- GreenshotOCRCommand/Modi/CompressionLevel.cs | 2 +- GreenshotOCRCommand/Modi/FileFormat.cs | 4 +- GreenshotOCRCommand/Modi/ICommon.cs | 2 +- GreenshotOCRCommand/Modi/IDispatch.cs | 2 +- GreenshotOCRCommand/Modi/IDocument.cs | 5 +- GreenshotOCRCommand/Modi/IImage.cs | 2 +- GreenshotOCRCommand/Modi/IImages.cs | 2 +- GreenshotOCRCommand/Modi/ILayout.cs | 2 +- GreenshotOCRCommand/Modi/IMiRect.cs | 2 +- GreenshotOCRCommand/Modi/IMiRects.cs | 2 +- GreenshotOCRCommand/Modi/IWord.cs | 2 +- GreenshotOCRCommand/Modi/IWords.cs | 2 +- GreenshotOCRCommand/Modi/ModiLanguage.cs | 2 +- GreenshotOCRCommand/Program.cs | 3 +- .../Properties/AssemblyInfo.cs | 2 +- GreenshotOCRPlugin/ModiLanguage.cs | 2 +- GreenshotOCRPlugin/OCRConfiguration.cs | 2 +- GreenshotOCRPlugin/OCRDestination.cs | 2 +- GreenshotOCRPlugin/OCRForm.cs | 2 +- GreenshotOCRPlugin/OCRPlugin.cs | 2 +- GreenshotOCRPlugin/SettingsForm.Designer.cs | 2 +- GreenshotOCRPlugin/SettingsForm.cs | 8 +- .../Destinations/ExcelDestination.cs | 2 +- .../Destinations/OneNoteDestination.cs | 2 +- .../Destinations/OutlookDestination.cs | 2 +- .../Destinations/PowerpointDestination.cs | 2 +- .../Destinations/WordDestination.cs | 2 +- GreenshotOfficePlugin/OfficeConfiguration.cs | 2 +- .../OfficeExport/Entities/OneNoteNotebook.cs | 2 +- .../OfficeExport/Entities/OneNotePage.cs | 2 +- .../OfficeExport/Entities/OneNoteSection.cs | 2 +- .../OfficeExport/ExcelExporter.cs | 2 +- .../OfficeExport/OneNoteExporter.cs | 2 +- .../OfficeExport/OutlookEmailExporter.cs | 2 +- .../OfficeExport/PowerpointExporter.cs | 2 +- .../OfficeExport/WordExporter.cs | 2 +- .../OfficeInterop/EmailFormat.cs | 2 +- .../OfficeInterop/OfficeVersions.cs | 2 +- GreenshotOfficePlugin/OfficePlugin.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- .../Forms/PhotobucketForm.cs | 4 +- .../Forms/SettingsForm.Designer.cs | 4 +- .../Forms/SettingsForm.cs | 4 +- ...shotPhotobucketPlugin.Credentials.template | 2 +- GreenshotPhotobucketPlugin/LanguageKeys.cs | 2 +- .../PhotobucketConfiguration.cs | 3 +- .../PhotobucketDestination.cs | 2 +- GreenshotPhotobucketPlugin/PhotobucketInfo.cs | 2 +- .../PhotobucketPlugin.cs | 2 +- .../PhotobucketUtils.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- GreenshotPicasaPlugin/Forms/PicasaForm.cs | 15 +- .../Forms/SettingsForm.Designer.cs | 2 +- GreenshotPicasaPlugin/Forms/SettingsForm.cs | 2 +- ...GreenshotPicasaPlugin.Credentials.template | 2 +- GreenshotPicasaPlugin/PicasaConfiguration.cs | 1 + .../Properties/AssemblyInfo.cs | 2 +- GreenshotPlugin/Controls/AnimatingForm.cs | 2 +- .../Controls/BackgroundForm.Designer.cs | 2 +- GreenshotPlugin/Controls/BackgroundForm.cs | 2 +- .../Controls/ExtendedWebBrowser.cs | 2 +- .../Controls/FormWithoutActivation.cs | 2 +- GreenshotPlugin/Controls/GreenshotButton.cs | 2 +- GreenshotPlugin/Controls/GreenshotCheckBox.cs | 2 +- .../Controls/GreenshotColumnSorter.cs | 2 +- GreenshotPlugin/Controls/GreenshotComboBox.cs | 2 +- GreenshotPlugin/Controls/GreenshotForm.cs | 2 +- GreenshotPlugin/Controls/GreenshotGroupBox.cs | 2 +- GreenshotPlugin/Controls/GreenshotLabel.cs | 2 +- .../Controls/GreenshotRadioButton.cs | 2 +- GreenshotPlugin/Controls/GreenshotTabPage.cs | 2 +- GreenshotPlugin/Controls/GreenshotTextBox.cs | 2 +- .../Controls/GreenshotToolDropDownButton.cs | 2 +- .../Controls/GreenshotToolStripButton.cs | 2 +- .../Controls/GreenshotToolStripLabel.cs | 2 +- .../Controls/GreenshotToolStripMenuItem.cs | 2 +- GreenshotPlugin/Controls/HotkeyControl.cs | 2 +- .../Controls/IGreenshotConfigBindable.cs | 2 +- .../Controls/IGreenshotLanguageBindable.cs | 2 +- .../Controls/OAuthLoginForm.Designer.cs | 2 +- GreenshotPlugin/Controls/OAuthLoginForm.cs | 2 +- .../Controls/PleaseWaitForm.Designer.cs | 2 +- GreenshotPlugin/Controls/PleaseWaitForm.cs | 2 +- .../Controls/QualityDialog.Designer.cs | 2 +- GreenshotPlugin/Controls/QualityDialog.cs | 2 +- .../Controls/SaveImageFileDialog.cs | 2 +- GreenshotPlugin/Controls/ThumbnailForm.cs | 2 +- GreenshotPlugin/Core/AbstractDestination.cs | 2 +- GreenshotPlugin/Core/AbstractProcessor.cs | 2 +- GreenshotPlugin/Core/AccessibleHelper.cs | 4 +- GreenshotPlugin/Core/AnimationHelpers.cs | 2 +- GreenshotPlugin/Core/BinaryStructHelper.cs | 2 +- GreenshotPlugin/Core/Cache.cs | 2 +- GreenshotPlugin/Core/CaptureHandler.cs | 2 +- GreenshotPlugin/Core/ClipboardHelper.cs | 2 +- GreenshotPlugin/Core/CoreConfiguration.cs | 2 +- GreenshotPlugin/Core/CredentialsHelper.cs | 6 +- GreenshotPlugin/Core/DisplayKeyAttribute.cs | 2 +- GreenshotPlugin/Core/EnumExtensions.cs | 2 +- GreenshotPlugin/Core/Enums/HResult.cs | 2 +- GreenshotPlugin/Core/EventDelay.cs | 2 +- GreenshotPlugin/Core/FastBitmap.cs | 2 +- GreenshotPlugin/Core/FilenameHelper.cs | 2 +- GreenshotPlugin/Core/GreenshotResources.cs | 2 +- GreenshotPlugin/Core/HResultExtensions.cs | 2 +- GreenshotPlugin/Core/IEHelper.cs | 2 +- GreenshotPlugin/Core/IImage.cs | 2 +- GreenshotPlugin/Core/ImageHelper.cs | 2 +- GreenshotPlugin/Core/ImageOutput.cs | 2 +- GreenshotPlugin/Core/InterfaceUtils.cs | 2 +- GreenshotPlugin/Core/Language.cs | 2 +- GreenshotPlugin/Core/LogHelper.cs | 2 +- GreenshotPlugin/Core/NetworkHelper.cs | 2 +- GreenshotPlugin/Core/OAuthHelper.cs | 2 +- GreenshotPlugin/Core/ObjectExtensions.cs | 2 +- GreenshotPlugin/Core/PluginUtils.cs | 2 +- GreenshotPlugin/Core/QuantizerHelper.cs | 2 +- GreenshotPlugin/Core/StringExtensions.cs | 2 +- GreenshotPlugin/Core/SvgImage.cs | 2 +- GreenshotPlugin/Core/WindowCapture.cs | 4 +- GreenshotPlugin/Core/WindowDetails.cs | 18 +- GreenshotPlugin/Core/WindowsEnumerator.cs | 2 +- .../Core/WmInputLangChangeRequestFilter.cs | 2 +- GreenshotPlugin/Effects/AdjustEffect.cs | 2 +- GreenshotPlugin/Effects/BorderEffect.cs | 2 +- GreenshotPlugin/Effects/DropShadowEffect.cs | 2 +- GreenshotPlugin/Effects/GrayscaleEffect.cs | 2 +- GreenshotPlugin/Effects/IEffect.cs | 2 +- GreenshotPlugin/Effects/InvertEffect.cs | 2 +- GreenshotPlugin/Effects/MonochromeEffect.cs | 2 +- GreenshotPlugin/Effects/ReduceColorsEffect.cs | 2 +- GreenshotPlugin/Effects/ResizeCanvasEffect.cs | 2 +- GreenshotPlugin/Effects/ResizeEffect.cs | 2 +- GreenshotPlugin/Effects/RotateEffect.cs | 2 +- GreenshotPlugin/Effects/TornEdgeEffect.cs | 2 +- GreenshotPlugin/Hooking/WindowsEventHook.cs | 10 +- .../Hooking/WindowsOpenCloseMonitor.cs | 2 +- .../Hooking/WindowsTitleMonitor.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLBodyElement.cs | 2 +- .../IEInterop/IHTMLCurrentStyle.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLDocument.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLDocument2.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLDocument3.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLDocument4.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLDocument5.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLElement.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLElement2.cs | 2 +- .../IEInterop/IHTMLElementCollection.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLFrameBase.cs | 2 +- .../IEInterop/IHTMLFramesCollection2.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLRect.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLScreen.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLScreen2.cs | 2 +- .../IEInterop/IHTMLSelectionObject.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLStyle.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLTxtRange.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLWindow2.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLWindow3.cs | 2 +- GreenshotPlugin/IEInterop/IHTMLWindow4.cs | 2 +- GreenshotPlugin/IEInterop/IWebBrowser2.cs | 2 +- GreenshotPlugin/IniFile/IniAttributes.cs | 2 +- GreenshotPlugin/IniFile/IniConfig.cs | 2 +- GreenshotPlugin/IniFile/IniReader.cs | 2 +- GreenshotPlugin/IniFile/IniSection.cs | 2 +- GreenshotPlugin/IniFile/IniValue.cs | 2 +- GreenshotPlugin/Interfaces/CaptureMode.cs | 2 +- .../Interfaces/Drawing/Adorners/IAdorner.cs | 2 +- .../Interfaces/Drawing/Container.cs | 2 +- GreenshotPlugin/Interfaces/Drawing/IField.cs | 2 +- .../Interfaces/Drawing/IFieldholder.cs | 2 +- .../Interfaces/Drawing/IMemento.cs | 2 +- GreenshotPlugin/Interfaces/DrawingModes.cs | 2 +- .../Interfaces/Forms/ImageEditor.cs | 2 +- GreenshotPlugin/Interfaces/ICapture.cs | 2 +- GreenshotPlugin/Interfaces/ICaptureDetails.cs | 2 +- GreenshotPlugin/Interfaces/ICaptureElement.cs | 2 +- GreenshotPlugin/Interfaces/IDestination.cs | 2 +- .../Interfaces/INotificationService.cs | 2 +- GreenshotPlugin/Interfaces/IProcessor.cs | 2 +- GreenshotPlugin/Interfaces/ISurface.cs | 2 +- .../Interfaces/Ocr/IOcrProvider.cs | 2 +- .../Interfaces/Plugin/PluginAttribute.cs | 2 +- .../Interfaces/ScreenCaptureMode.cs | 2 +- .../Interfaces/SurfaceDrawingModeEventArgs.cs | 2 +- .../SurfaceDrawingModeEventHandler.cs | 2 +- .../Interfaces/SurfaceElementEventArgs.cs | 2 +- .../Interfaces/SurfaceElementEventHandler.cs | 2 +- .../Interfaces/SurfaceMessageEventArgs.cs | 2 +- .../Interfaces/SurfaceMessageEventHandler.cs | 2 +- .../Interfaces/SurfaceMessageTyp.cs | 2 +- .../SurfaceSizeChangeEventHandler.cs | 2 +- .../Interfaces/VerticalAlignment.cs | 2 +- GreenshotPlugin/Interop/COMWrapper.cs | 2 +- GreenshotPlugin/Interop/ComProgIdAttribute.cs | 2 +- GreenshotPlugin/Interop/IAppVisibility.cs | 2 +- GreenshotPlugin/Interop/IDispatch.cs | 2 +- GreenshotPlugin/Interop/IOleCommandTarget.cs | 2 +- GreenshotPlugin/Interop/IOleWindow.cs | 4 +- GreenshotPlugin/Interop/IServiceProvider.cs | 2 +- GreenshotPlugin/Interop/IUnknown.cs | 2 +- GreenshotPlugin/UnmanagedHelpers/DWM.cs | 2 +- .../UnmanagedHelpers/EnumWindowsProc.cs | 2 +- .../Enums/DWMWINDOWATTRIBUTE.cs | 2 +- .../UnmanagedHelpers/Enums/DWM_BB.cs | 2 +- .../UnmanagedHelpers/Enums/DWM_BLURBEHIND.cs | 2 +- .../Enums/DWM_THUMBNAIL_PROPERTIES.cs | 2 +- .../UnmanagedHelpers/Enums/SYSCOLOR.cs | 2 +- .../Enums/WindowStyleFlags.cs | 2 +- GreenshotPlugin/UnmanagedHelpers/GDI32.cs | 2 +- GreenshotPlugin/UnmanagedHelpers/GDIplus.cs | 2 +- GreenshotPlugin/UnmanagedHelpers/Kernel32.cs | 2 +- GreenshotPlugin/UnmanagedHelpers/PsAPI.cs | 2 +- GreenshotPlugin/UnmanagedHelpers/Shell32.cs | 2 +- .../UnmanagedHelpers/Structs/SIZE.cs | 2 +- GreenshotPlugin/UnmanagedHelpers/User32.cs | 26 +- GreenshotPlugin/UnmanagedHelpers/Win32.cs | 2 +- .../UnmanagedHelpers/WinEventDelegate.cs | 4 +- GreenshotPlugin/UnmanagedHelpers/WinMM.cs | 2 +- .../Destinations/Win10OcrDestination.cs | 2 +- .../Destinations/Win10ShareDestination.cs | 2 +- GreenshotWin10Plugin/Internal/ShareInfo.cs | 2 +- .../Native/GreenshotNotificationActivator.cs | 2 +- .../Native/IDataTransferManagerInterOp.cs | 2 +- .../Processors/Win10OcrProcessor.cs | 2 +- .../ToastNotificationService.cs | 2 +- GreenshotWin10Plugin/Win10OcrProvider.cs | 4 +- GreenshotWin10Plugin/Win10Plugin.cs | 14 +- 478 files changed, 972 insertions(+), 1089 deletions(-) create mode 100644 Greenshot.sln.DotSettings delete mode 100644 Greenshot/Helpers/WindowWrapper.cs diff --git a/.gitignore b/.gitignore index 2f5969501..3afd2d7ab 100644 --- a/.gitignore +++ b/.gitignore @@ -211,4 +211,7 @@ _Pvt_Extensions/ ModelManifest.xml # Greenshot credentials files -*.credentials.cs \ No newline at end of file +*.credentials.cs + +# Rider files +.idea \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index c87c75734..1a2e9d3a4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ <Project> <PropertyGroup> - <Copyright>Copyright © Greenshot 2004-2020</Copyright> + <Copyright>Copyright © Greenshot 2004-2021</Copyright> <Authors>Greenshot</Authors> <PackageIconUrl>https://getgreenshot.org/favicon.ico</PackageIconUrl> <RepositoryUrl>https://github.com/greenshot/greenshot</RepositoryUrl> diff --git a/Greenshot.sln.DotSettings b/Greenshot.sln.DotSettings new file mode 100644 index 000000000..aecc39af3 --- /dev/null +++ b/Greenshot.sln.DotSettings @@ -0,0 +1,4 @@ +<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> + <s:Boolean x:Key="/Default/UserDictionary/Words/=Klingen/@EntryIndexedValue">True</s:Boolean> + <s:Boolean x:Key="/Default/UserDictionary/Words/=Krom/@EntryIndexedValue">True</s:Boolean> + <s:Boolean x:Key="/Default/UserDictionary/Words/=Photobucket/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> \ No newline at end of file diff --git a/Greenshot/Configuration/EditorConfiguration.cs b/Greenshot/Configuration/EditorConfiguration.cs index 61bdc0733..019ea9ef6 100644 --- a/Greenshot/Configuration/EditorConfiguration.cs +++ b/Greenshot/Configuration/EditorConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Configuration/LanguageKeys.cs b/Greenshot/Configuration/LanguageKeys.cs index 08f982374..022f141f1 100644 --- a/Greenshot/Configuration/LanguageKeys.cs +++ b/Greenshot/Configuration/LanguageKeys.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Controls/BindableToolStripButton.cs b/Greenshot/Controls/BindableToolStripButton.cs index 893264403..b44a1a31c 100644 --- a/Greenshot/Controls/BindableToolStripButton.cs +++ b/Greenshot/Controls/BindableToolStripButton.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Controls/BindableToolStripComboBox.cs b/Greenshot/Controls/BindableToolStripComboBox.cs index e6e8ad105..3637f2380 100644 --- a/Greenshot/Controls/BindableToolStripComboBox.cs +++ b/Greenshot/Controls/BindableToolStripComboBox.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Controls/BindableToolStripDropDownButton.cs b/Greenshot/Controls/BindableToolStripDropDownButton.cs index 4a04e1f23..4071d6b81 100644 --- a/Greenshot/Controls/BindableToolStripDropDownButton.cs +++ b/Greenshot/Controls/BindableToolStripDropDownButton.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Controls/ColorButton.cs b/Greenshot/Controls/ColorButton.cs index 935729732..fe31d2e11 100644 --- a/Greenshot/Controls/ColorButton.cs +++ b/Greenshot/Controls/ColorButton.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -24,6 +24,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using GreenshotPlugin.Controls; +using ColorDialog = Greenshot.Forms.ColorDialog; namespace Greenshot.Controls { /// <summary> diff --git a/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs b/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs index 5031f82bb..e5ebf5478 100644 --- a/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs +++ b/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs b/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs index cb851ea2f..d559d771b 100644 --- a/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs +++ b/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Controls/FontFamilyComboBox.cs b/Greenshot/Controls/FontFamilyComboBox.cs index dc5975be3..d37244eab 100644 --- a/Greenshot/Controls/FontFamilyComboBox.cs +++ b/Greenshot/Controls/FontFamilyComboBox.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Controls/MenuStripEx.cs b/Greenshot/Controls/MenuStripEx.cs index ea973a791..31aa8f190 100644 --- a/Greenshot/Controls/MenuStripEx.cs +++ b/Greenshot/Controls/MenuStripEx.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Controls/NonJumpingPanel.cs b/Greenshot/Controls/NonJumpingPanel.cs index 4d107da45..d5565c637 100644 --- a/Greenshot/Controls/NonJumpingPanel.cs +++ b/Greenshot/Controls/NonJumpingPanel.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -22,7 +22,7 @@ using System.Drawing; using System.Windows.Forms; -namespace GreenshotPlugin.Controls +namespace Greenshot.Controls { /// <summary> /// See: http://nickstips.wordpress.com/2010/03/03/c-panel-resets-scroll-position-after-focus-is-lost-and-regained/ diff --git a/Greenshot/Controls/Pipette.cs b/Greenshot/Controls/Pipette.cs index bbe2b5686..ca7333d81 100644 --- a/Greenshot/Controls/Pipette.cs +++ b/Greenshot/Controls/Pipette.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -25,6 +25,7 @@ using System.Windows.Forms; using Greenshot.Forms; using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.UnmanagedHelpers.Enums; +using ColorDialog = Greenshot.Forms.ColorDialog; namespace Greenshot.Controls { /// <summary> diff --git a/Greenshot/Controls/ToolStripColorButton.cs b/Greenshot/Controls/ToolStripColorButton.cs index 706a54cf3..951e117fd 100644 --- a/Greenshot/Controls/ToolStripColorButton.cs +++ b/Greenshot/Controls/ToolStripColorButton.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -24,6 +24,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using GreenshotPlugin.Controls; +using ColorDialog = Greenshot.Forms.ColorDialog; namespace Greenshot.Controls { public class ToolStripColorButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable { diff --git a/Greenshot/Controls/ToolStripEx.cs b/Greenshot/Controls/ToolStripEx.cs index b3f669fdd..7d2ca63ed 100644 --- a/Greenshot/Controls/ToolStripEx.cs +++ b/Greenshot/Controls/ToolStripEx.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Controls/ToolStripNumericUpDown.cs b/Greenshot/Controls/ToolStripNumericUpDown.cs index 2cb53314b..13652fc41 100644 --- a/Greenshot/Controls/ToolStripNumericUpDown.cs +++ b/Greenshot/Controls/ToolStripNumericUpDown.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Destinations/ClipboardDestination.cs b/Greenshot/Destinations/ClipboardDestination.cs index 9cfb0aec5..a1172ede4 100644 --- a/Greenshot/Destinations/ClipboardDestination.cs +++ b/Greenshot/Destinations/ClipboardDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Destinations/EditorDestination.cs b/Greenshot/Destinations/EditorDestination.cs index 09cce0f56..415607640 100644 --- a/Greenshot/Destinations/EditorDestination.cs +++ b/Greenshot/Destinations/EditorDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.Drawing; using Greenshot.Configuration; +using Greenshot.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; diff --git a/Greenshot/Destinations/EmailDestination.cs b/Greenshot/Destinations/EmailDestination.cs index abda77c7c..0ba93ff59 100644 --- a/Greenshot/Destinations/EmailDestination.cs +++ b/Greenshot/Destinations/EmailDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Destinations/FileDestination.cs b/Greenshot/Destinations/FileDestination.cs index 559d28135..d6e89c0d5 100644 --- a/Greenshot/Destinations/FileDestination.cs +++ b/Greenshot/Destinations/FileDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -24,6 +24,7 @@ using System.IO; using System.Windows.Forms; using Greenshot.Configuration; +using Greenshot.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.Controls; using GreenshotPlugin.IniFile; diff --git a/Greenshot/Destinations/FileWithDialogDestination.cs b/Greenshot/Destinations/FileWithDialogDestination.cs index e211d14f7..b378f5f34 100644 --- a/Greenshot/Destinations/FileWithDialogDestination.cs +++ b/Greenshot/Destinations/FileWithDialogDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Destinations/PickerDestination.cs b/Greenshot/Destinations/PickerDestination.cs index 26f8fbfb5..e7ea94c83 100644 --- a/Greenshot/Destinations/PickerDestination.cs +++ b/Greenshot/Destinations/PickerDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Destinations/PrinterDestination.cs b/Greenshot/Destinations/PrinterDestination.cs index e2156256b..3a45268e2 100644 --- a/Greenshot/Destinations/PrinterDestination.cs +++ b/Greenshot/Destinations/PrinterDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs index ecf0ce53d..5461b4df4 100644 --- a/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ b/Greenshot/Drawing/Adorners/AbstractAdorner.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ diff --git a/Greenshot/Drawing/Adorners/MoveAdorner.cs b/Greenshot/Drawing/Adorners/MoveAdorner.cs index 916d569f4..c8ef3ea22 100644 --- a/Greenshot/Drawing/Adorners/MoveAdorner.cs +++ b/Greenshot/Drawing/Adorners/MoveAdorner.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ diff --git a/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/Greenshot/Drawing/Adorners/ResizeAdorner.cs index d624add48..b2e7261a9 100644 --- a/Greenshot/Drawing/Adorners/ResizeAdorner.cs +++ b/Greenshot/Drawing/Adorners/ResizeAdorner.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/Greenshot/Drawing/Adorners/TargetAdorner.cs index 542657c14..e0d0bbf13 100644 --- a/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ b/Greenshot/Drawing/Adorners/TargetAdorner.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ diff --git a/Greenshot/Drawing/ArrowContainer.cs b/Greenshot/Drawing/ArrowContainer.cs index 739f9d430..acfd1ad03 100644 --- a/Greenshot/Drawing/ArrowContainer.cs +++ b/Greenshot/Drawing/ArrowContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs index 58cee17b1..da160f11e 100644 --- a/Greenshot/Drawing/CropContainer.cs +++ b/Greenshot/Drawing/CropContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -57,12 +57,13 @@ namespace Greenshot.Drawing { /// (we create a transparent brown over the complete picture) /// </summary> public override Rectangle DrawingBounds { - get { - if (_parent?.Image is Image image) { + get + { + if (_parent?.Image is { } image) { return new Rectangle(0, 0, image.Width, image.Height); - } else { - return Rectangle.Empty; } + + return Rectangle.Empty; } } @@ -89,11 +90,9 @@ namespace Greenshot.Drawing { g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height))); } - public override bool HasContextMenu { - get { - // No context menu for the CropContainer - return false; - } - } + /// <summary> + /// No context menu for the CropContainer + /// </summary> + public override bool HasContextMenu => false; } } diff --git a/Greenshot/Drawing/CursorContainer.cs b/Greenshot/Drawing/CursorContainer.cs index 5558508a8..15078bd76 100644 --- a/Greenshot/Drawing/CursorContainer.cs +++ b/Greenshot/Drawing/CursorContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index 87b555914..60eb1e98d 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -98,8 +98,8 @@ namespace Greenshot.Drawing [NonSerialized] private PropertyChangedEventHandler _propertyChanged; public event PropertyChangedEventHandler PropertyChanged { - add { _propertyChanged += value; } - remove{ _propertyChanged -= value; } + add => _propertyChanged += value; + remove => _propertyChanged -= value; } public IList<IFilter> Filters { @@ -117,22 +117,18 @@ namespace Greenshot.Drawing [NonSerialized] internal Surface _parent; public ISurface Parent { - get { return _parent; } - set { SwitchParent((Surface)value); } + get => _parent; + set => SwitchParent((Surface)value); } [NonSerialized] private TargetAdorner _targetAdorner; - public TargetAdorner TargetAdorner { - get { - return _targetAdorner; - } - } + public TargetAdorner TargetAdorner => _targetAdorner; [NonSerialized] private bool _selected; public bool Selected { - get {return _selected;} + get => _selected; set { _selected = value; OnPropertyChanged("Selected"); @@ -142,18 +138,14 @@ namespace Greenshot.Drawing [NonSerialized] private EditStatus _status = EditStatus.UNDRAWN; public EditStatus Status { - get { - return _status; - } - set { - _status = value; - } + get => _status; + set => _status = value; } private int left; public int Left { - get { return left; } + get => left; set { if (value == left) { return; @@ -164,7 +156,7 @@ namespace Greenshot.Drawing private int top; public int Top { - get { return top; } + get => top; set { if (value == top) { return; @@ -175,7 +167,7 @@ namespace Greenshot.Drawing private int width; public int Width { - get { return width; } + get => width; set { if (value == width) { return; @@ -186,7 +178,7 @@ namespace Greenshot.Drawing private int height; public int Height { - get { return height; } + get => height; set { if (value == height) { return; @@ -196,9 +188,7 @@ namespace Greenshot.Drawing } public Point Location { - get { - return new Point(left, top); - } + get => new Point(left, top); set { left = value.X; top = value.Y; @@ -330,11 +320,7 @@ namespace Greenshot.Drawing Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight)); } - public bool hasFilters { - get { - return Filters.Count > 0; - } - } + public bool hasFilters => Filters.Count > 0; public abstract void Draw(Graphics graphics, RenderMode renderMode); diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs index 666986002..a7107543e 100644 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ b/Greenshot/Drawing/DrawableContainerList.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -30,6 +30,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Threading; using System.Windows.Forms; +using Greenshot.Forms; using GreenshotPlugin.Interfaces; namespace Greenshot.Drawing { diff --git a/Greenshot/Drawing/EllipseContainer.cs b/Greenshot/Drawing/EllipseContainer.cs index c7a3985d6..b7d03ecfe 100644 --- a/Greenshot/Drawing/EllipseContainer.cs +++ b/Greenshot/Drawing/EllipseContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs index 561501634..48dfd95f9 100644 --- a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs +++ b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs index 636e708e4..bb6ae068c 100644 --- a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs +++ b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs b/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs index ff3232d2f..a1ffd80c1 100644 --- a/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs +++ b/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs b/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs index 28a4bddf0..5a9652d5c 100644 --- a/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs +++ b/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs index b1efb78f3..0ac7d02bb 100644 --- a/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs +++ b/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs index 70581bc10..528af1c2e 100644 --- a/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs +++ b/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs index 693e532dd..6a8ff7e84 100644 --- a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs +++ b/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs b/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs index 1a8fcefc3..cdb573470 100644 --- a/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs +++ b/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs b/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs index 146b91afb..d21b575a4 100644 --- a/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs +++ b/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs b/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs index 692254c37..5d15b6699 100644 --- a/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs +++ b/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/Field.cs b/Greenshot/Drawing/Fields/Field.cs index 798444625..f08033fd0 100644 --- a/Greenshot/Drawing/Fields/Field.cs +++ b/Greenshot/Drawing/Fields/Field.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/FieldAggregator.cs b/Greenshot/Drawing/Fields/FieldAggregator.cs index c22268091..6606a96b1 100644 --- a/Greenshot/Drawing/Fields/FieldAggregator.cs +++ b/Greenshot/Drawing/Fields/FieldAggregator.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Fields/FieldType.cs b/Greenshot/Drawing/Fields/FieldType.cs index 9976d24af..7531e5b27 100644 --- a/Greenshot/Drawing/Fields/FieldType.cs +++ b/Greenshot/Drawing/Fields/FieldType.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/FilterContainer.cs b/Greenshot/Drawing/FilterContainer.cs index 489e8e357..9ea6bc1a1 100644 --- a/Greenshot/Drawing/FilterContainer.cs +++ b/Greenshot/Drawing/FilterContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Filters/AbstractFilter.cs b/Greenshot/Drawing/Filters/AbstractFilter.cs index 7c54545bd..419038d40 100644 --- a/Greenshot/Drawing/Filters/AbstractFilter.cs +++ b/Greenshot/Drawing/Filters/AbstractFilter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Filters/BlurFilter.cs b/Greenshot/Drawing/Filters/BlurFilter.cs index 711c1d02b..79f617ac6 100644 --- a/Greenshot/Drawing/Filters/BlurFilter.cs +++ b/Greenshot/Drawing/Filters/BlurFilter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Filters/BrightnessFilter.cs b/Greenshot/Drawing/Filters/BrightnessFilter.cs index 852aca9de..a43a68f67 100644 --- a/Greenshot/Drawing/Filters/BrightnessFilter.cs +++ b/Greenshot/Drawing/Filters/BrightnessFilter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/Greenshot/Drawing/Filters/GrayscaleFilter.cs index 4758d12bd..f66b29fba 100644 --- a/Greenshot/Drawing/Filters/GrayscaleFilter.cs +++ b/Greenshot/Drawing/Filters/GrayscaleFilter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Filters/HighlightFilter.cs b/Greenshot/Drawing/Filters/HighlightFilter.cs index 36c574493..38b6a8ee7 100644 --- a/Greenshot/Drawing/Filters/HighlightFilter.cs +++ b/Greenshot/Drawing/Filters/HighlightFilter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Filters/IFilter.cs b/Greenshot/Drawing/Filters/IFilter.cs index 91fdfe74d..8c3b5b23e 100644 --- a/Greenshot/Drawing/Filters/IFilter.cs +++ b/Greenshot/Drawing/Filters/IFilter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Filters/MagnifierFilter.cs b/Greenshot/Drawing/Filters/MagnifierFilter.cs index 601d09967..68b033ef5 100644 --- a/Greenshot/Drawing/Filters/MagnifierFilter.cs +++ b/Greenshot/Drawing/Filters/MagnifierFilter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Filters/PixelizationFilter.cs b/Greenshot/Drawing/Filters/PixelizationFilter.cs index 7be7d47a6..dbf19d3f7 100644 --- a/Greenshot/Drawing/Filters/PixelizationFilter.cs +++ b/Greenshot/Drawing/Filters/PixelizationFilter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/FreehandContainer.cs b/Greenshot/Drawing/FreehandContainer.cs index c7d5cf1e8..0485f2ae5 100644 --- a/Greenshot/Drawing/FreehandContainer.cs +++ b/Greenshot/Drawing/FreehandContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/HighlightContainer.cs b/Greenshot/Drawing/HighlightContainer.cs index 858e1508b..788360004 100644 --- a/Greenshot/Drawing/HighlightContainer.cs +++ b/Greenshot/Drawing/HighlightContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/IconContainer.cs b/Greenshot/Drawing/IconContainer.cs index 013fb057f..b35ce28ff 100644 --- a/Greenshot/Drawing/IconContainer.cs +++ b/Greenshot/Drawing/IconContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/ImageContainer.cs b/Greenshot/Drawing/ImageContainer.cs index 0e23855bb..fee072aa1 100644 --- a/Greenshot/Drawing/ImageContainer.cs +++ b/Greenshot/Drawing/ImageContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/LineContainer.cs b/Greenshot/Drawing/LineContainer.cs index af73529d4..eac855644 100644 --- a/Greenshot/Drawing/LineContainer.cs +++ b/Greenshot/Drawing/LineContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/ObfuscateContainer.cs b/Greenshot/Drawing/ObfuscateContainer.cs index 07ea899ba..f1fdbf156 100644 --- a/Greenshot/Drawing/ObfuscateContainer.cs +++ b/Greenshot/Drawing/ObfuscateContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Positions.cs b/Greenshot/Drawing/Positions.cs index 847d08415..f7061d023 100644 --- a/Greenshot/Drawing/Positions.cs +++ b/Greenshot/Drawing/Positions.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ diff --git a/Greenshot/Drawing/RectangleContainer.cs b/Greenshot/Drawing/RectangleContainer.cs index 623e28b22..2e86fa509 100644 --- a/Greenshot/Drawing/RectangleContainer.cs +++ b/Greenshot/Drawing/RectangleContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/RoundedRectangle.cs b/Greenshot/Drawing/RoundedRectangle.cs index 8a519d1ed..a5d4ea6a0 100644 --- a/Greenshot/Drawing/RoundedRectangle.cs +++ b/Greenshot/Drawing/RoundedRectangle.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs index d7a4487fc..ed3118db6 100644 --- a/Greenshot/Drawing/Surface.cs +++ b/Greenshot/Drawing/Surface.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index ddfb2918e..4cc369dda 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -67,25 +67,21 @@ namespace Greenshot.Drawing // there is a binding on the following property! public string Text { - get { return text; } - set - { - ChangeText(value, true); - } + get => text; + set => ChangeText(value, true); } internal void ChangeText(string newText, bool allowUndoable) { - if ((text == null && newText != null) || !string.Equals(text, newText)) + if ((text != null || newText == null) && string.Equals(text, newText)) return; + + if (makeUndoable && allowUndoable) { - if (makeUndoable && allowUndoable) - { - makeUndoable = false; - _parent.MakeUndoable(new TextChangeMemento(this), false); - } - text = newText; - OnPropertyChanged("Text"); + makeUndoable = false; + _parent.MakeUndoable(new TextChangeMemento(this), false); } + text = newText; + OnPropertyChanged("Text"); } public TextContainer(Surface parent) : base(parent) diff --git a/Greenshot/Forms/AboutForm.Designer.cs b/Greenshot/Forms/AboutForm.Designer.cs index 1b35f8699..551f88671 100644 --- a/Greenshot/Forms/AboutForm.Designer.cs +++ b/Greenshot/Forms/AboutForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/AboutForm.cs b/Greenshot/Forms/AboutForm.cs index 0be368cbe..f3c67edd8 100644 --- a/Greenshot/Forms/AboutForm.cs +++ b/Greenshot/Forms/AboutForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool -* Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/AnimatingBaseForm.cs b/Greenshot/Forms/AnimatingBaseForm.cs index db1c2b54d..5456ba037 100644 --- a/Greenshot/Forms/AnimatingBaseForm.cs +++ b/Greenshot/Forms/AnimatingBaseForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -21,7 +21,7 @@ using GreenshotPlugin.Controls; -namespace Greenshot { +namespace Greenshot.Forms { /// <summary> /// This class is only here to help in the Designer mode, so it's clear where the language files are /// </summary> diff --git a/Greenshot/Forms/BaseForm.cs b/Greenshot/Forms/BaseForm.cs index 392f37803..ffc0e86db 100644 --- a/Greenshot/Forms/BaseForm.cs +++ b/Greenshot/Forms/BaseForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -21,7 +21,7 @@ using GreenshotPlugin.Controls; -namespace Greenshot { +namespace Greenshot.Forms { /// <summary> /// This class is only here to help in the Designer mode, so it's clear where the language files are /// </summary> diff --git a/Greenshot/Forms/BugReportForm.Designer.cs b/Greenshot/Forms/BugReportForm.Designer.cs index 3b4c6afdb..2c5a7ae52 100644 --- a/Greenshot/Forms/BugReportForm.Designer.cs +++ b/Greenshot/Forms/BugReportForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/BugReportForm.cs b/Greenshot/Forms/BugReportForm.cs index f74aa431d..7c26e1b54 100644 --- a/Greenshot/Forms/BugReportForm.cs +++ b/Greenshot/Forms/BugReportForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/CaptureForm.Designer.cs b/Greenshot/Forms/CaptureForm.Designer.cs index ee3b43b99..9f36ebdb9 100644 --- a/Greenshot/Forms/CaptureForm.Designer.cs +++ b/Greenshot/Forms/CaptureForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs index bad4a0d24..bf21382e8 100644 --- a/Greenshot/Forms/CaptureForm.cs +++ b/Greenshot/Forms/CaptureForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/ColorDialog.Designer.cs b/Greenshot/Forms/ColorDialog.Designer.cs index 32330fb3a..d5060d8c0 100644 --- a/Greenshot/Forms/ColorDialog.Designer.cs +++ b/Greenshot/Forms/ColorDialog.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace Greenshot { +namespace Greenshot.Forms { public partial class ColorDialog { /// <summary> /// Designer variable used to keep track of non-visual components. diff --git a/Greenshot/Forms/ColorDialog.cs b/Greenshot/Forms/ColorDialog.cs index bcf7e8889..f69c8f2fc 100644 --- a/Greenshot/Forms/ColorDialog.cs +++ b/Greenshot/Forms/ColorDialog.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,17 +19,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -using Greenshot.Configuration; -using Greenshot.Controls; using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.Threading; using System.Windows.Forms; +using Greenshot.Configuration; +using Greenshot.Controls; using GreenshotPlugin.IniFile; -namespace Greenshot { +namespace Greenshot.Forms { /// <summary> /// Description of ColorDialog. /// </summary> diff --git a/Greenshot/Forms/ColorPickerToolStripButton.cs b/Greenshot/Forms/ColorPickerToolStripButton.cs index 53816dca5..8f7730845 100644 --- a/Greenshot/Forms/ColorPickerToolStripButton.cs +++ b/Greenshot/Forms/ColorPickerToolStripButton.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -20,12 +20,12 @@ */ using System; +using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; -using System.Diagnostics; -namespace Greenshot +namespace Greenshot.Forms { public delegate void ColorPickerEventHandler(object o, ColorPickerEventArgs e); @@ -34,12 +34,12 @@ namespace Greenshot private Color _color; public Point Offset = new Point(0,0); public event ColorPickerEventHandler ColorPicked; - private readonly Greenshot.ColorDialog _cd; + private readonly ColorDialog _cd; public ColorPickerToolStripButton() { - _cd = Greenshot.ColorDialog.GetInstance(); + _cd = ColorDialog.GetInstance(); Click += ToolStripButton1Click; } diff --git a/Greenshot/Forms/DropShadowSettingsForm.Designer.cs b/Greenshot/Forms/DropShadowSettingsForm.Designer.cs index ba8e7b3bc..0f7a89618 100644 --- a/Greenshot/Forms/DropShadowSettingsForm.Designer.cs +++ b/Greenshot/Forms/DropShadowSettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/DropShadowSettingsForm.cs b/Greenshot/Forms/DropShadowSettingsForm.cs index 2511a3328..4f7c413c7 100644 --- a/Greenshot/Forms/DropShadowSettingsForm.cs +++ b/Greenshot/Forms/DropShadowSettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/ImageEditorForm.Designer.cs b/Greenshot/Forms/ImageEditorForm.Designer.cs index cce905007..0db33a212 100644 --- a/Greenshot/Forms/ImageEditorForm.Designer.cs +++ b/Greenshot/Forms/ImageEditorForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -21,7 +21,7 @@ using Greenshot.Controls; -namespace Greenshot { +namespace Greenshot.Forms { partial class ImageEditorForm { /// <summary> /// Designer variable used to keep track of non-visual components. @@ -56,7 +56,7 @@ namespace Greenshot { this.dimensionsLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); - this.panel1 = new GreenshotPlugin.Controls.NonJumpingPanel(); + this.panel1 = new NonJumpingPanel(); this.toolsToolStrip = new Greenshot.Controls.ToolStripEx(); this.btnCursor = new GreenshotPlugin.Controls.GreenshotToolStripButton(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); @@ -1977,7 +1977,7 @@ namespace Greenshot { private GreenshotPlugin.Controls.GreenshotToolStripButton btnRect; private System.Windows.Forms.ToolStripContainer topToolStripContainer; private Greenshot.Controls.ToolStripEx destinationsToolStrip; - private GreenshotPlugin.Controls.NonJumpingPanel panel1; + private NonJumpingPanel panel1; private Greenshot.Controls.ToolStripColorButton btnFillColor; private Greenshot.Controls.ToolStripColorButton btnLineColor; private GreenshotPlugin.Controls.GreenshotToolStripMenuItem autoCropToolStripMenuItem; diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index ece824bdb..a9fe79239 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -31,7 +31,6 @@ using Greenshot.Destinations; using Greenshot.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Drawing.Fields.Binding; -using Greenshot.Forms; using Greenshot.Help; using Greenshot.Helpers; using GreenshotPlugin.Controls; @@ -45,7 +44,7 @@ using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.UnmanagedHelpers.Structs; using log4net; -namespace Greenshot { +namespace Greenshot.Forms { /// <summary> /// Description of ImageEditorForm. /// </summary> diff --git a/Greenshot/Forms/LanguageDialog.Designer.cs b/Greenshot/Forms/LanguageDialog.Designer.cs index 6ae29249b..6ad4c0e60 100644 --- a/Greenshot/Forms/LanguageDialog.Designer.cs +++ b/Greenshot/Forms/LanguageDialog.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/LanguageDialog.cs b/Greenshot/Forms/LanguageDialog.cs index 7d6ba2f33..d78c36008 100644 --- a/Greenshot/Forms/LanguageDialog.cs +++ b/Greenshot/Forms/LanguageDialog.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/MainForm.Designer.cs b/Greenshot/Forms/MainForm.Designer.cs index 751d43452..281886180 100644 --- a/Greenshot/Forms/MainForm.Designer.cs +++ b/Greenshot/Forms/MainForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace Greenshot { +namespace Greenshot.Forms { partial class MainForm { /// <summary> /// Designer variable used to keep track of non-visual components. diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index 61f5141bd..8ff531ca0 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -29,25 +29,24 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading; +using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.Integration; using Greenshot.Configuration; -using Greenshot.Forms; -using Greenshot.Help; -using Greenshot.Helpers; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; using Greenshot.Destinations; using Greenshot.Drawing; -using log4net; -using Timer = System.Timers.Timer; -using System.Threading.Tasks; +using Greenshot.Help; +using Greenshot.Helpers; +using GreenshotPlugin.Controls; +using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; +using GreenshotPlugin.UnmanagedHelpers; +using log4net; +using Timer = System.Timers.Timer; -namespace Greenshot { +namespace Greenshot.Forms { /// <summary> /// Description of MainForm. /// </summary> diff --git a/Greenshot/Forms/MovableShowColorForm.cs b/Greenshot/Forms/MovableShowColorForm.cs index 22c40183f..fb8e7df5f 100644 --- a/Greenshot/Forms/MovableShowColorForm.cs +++ b/Greenshot/Forms/MovableShowColorForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/PrintOptionsDialog.Designer.cs b/Greenshot/Forms/PrintOptionsDialog.Designer.cs index 43d40c06e..0de6ca3a9 100644 --- a/Greenshot/Forms/PrintOptionsDialog.Designer.cs +++ b/Greenshot/Forms/PrintOptionsDialog.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/PrintOptionsDialog.cs b/Greenshot/Forms/PrintOptionsDialog.cs index b4a2de28e..7e1ae603c 100644 --- a/Greenshot/Forms/PrintOptionsDialog.cs +++ b/Greenshot/Forms/PrintOptionsDialog.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/ResizeSettingsForm.Designer.cs b/Greenshot/Forms/ResizeSettingsForm.Designer.cs index f6a7fad48..e7675bb57 100644 --- a/Greenshot/Forms/ResizeSettingsForm.Designer.cs +++ b/Greenshot/Forms/ResizeSettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/ResizeSettingsForm.cs b/Greenshot/Forms/ResizeSettingsForm.cs index 0d0aad23f..52bfb8d21 100644 --- a/Greenshot/Forms/ResizeSettingsForm.cs +++ b/Greenshot/Forms/ResizeSettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/SettingsForm.Designer.cs b/Greenshot/Forms/SettingsForm.Designer.cs index 80cbd9437..f0cb33f46 100644 --- a/Greenshot/Forms/SettingsForm.Designer.cs +++ b/Greenshot/Forms/SettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace Greenshot { +namespace Greenshot.Forms { partial class SettingsForm { /// <summary> /// Designer variable used to keep track of non-visual components. diff --git a/Greenshot/Forms/SettingsForm.cs b/Greenshot/Forms/SettingsForm.cs index 90fc1df51..7bd37e0ec 100644 --- a/Greenshot/Forms/SettingsForm.cs +++ b/Greenshot/Forms/SettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -26,22 +26,20 @@ using System.Drawing; using System.Globalization; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using System.Windows.Forms; - using Greenshot.Configuration; using Greenshot.Destinations; using Greenshot.Helpers; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; -using System.Text.RegularExpressions; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.UnmanagedHelpers.Enums; using log4net; -namespace Greenshot { +namespace Greenshot.Forms { /// <summary> /// Description of SettingsForm. /// </summary> @@ -453,9 +451,9 @@ namespace Greenshot { } // retrieve the set clipboard formats - List<ClipboardFormat> clipboardFormats = new List<ClipboardFormat>(); + var clipboardFormats = new List<ClipboardFormat>(); foreach (int index in listview_clipboardformats.CheckedIndices) { - ListViewItem item = listview_clipboardformats.Items[index]; + var item = listview_clipboardformats.Items[index]; if (item.Checked) { clipboardFormats.Add((ClipboardFormat)item.Tag); } diff --git a/Greenshot/Forms/ToolStripMenuSelectList.cs b/Greenshot/Forms/ToolStripMenuSelectList.cs index a109798f5..4ddfe7cdd 100644 --- a/Greenshot/Forms/ToolStripMenuSelectList.cs +++ b/Greenshot/Forms/ToolStripMenuSelectList.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs b/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs index 5320e17de..f2692729f 100644 --- a/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs +++ b/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Forms/TornEdgeSettingsForm.cs b/Greenshot/Forms/TornEdgeSettingsForm.cs index 632d554ae..520f795b9 100644 --- a/Greenshot/Forms/TornEdgeSettingsForm.cs +++ b/Greenshot/Forms/TornEdgeSettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/GreenshotMain.cs b/Greenshot/GreenshotMain.cs index 6a993d99b..045478d6d 100644 --- a/Greenshot/GreenshotMain.cs +++ b/Greenshot/GreenshotMain.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -22,6 +22,7 @@ using System; using System.Globalization; using System.Net; using System.Reflection; +using Greenshot.Forms; // Remove AppendPrivatePath warning: #pragma warning disable 0618 @@ -38,11 +39,11 @@ namespace Greenshot { Assembly ayResult = null; string sShortAssemblyName = args.Name.Split(',')[0]; Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (Assembly ayAssembly in ayAssemblies) { - if (sShortAssemblyName == ayAssembly.FullName.Split(',')[0]) { - ayResult = ayAssembly; - break; - } + foreach (Assembly ayAssembly in ayAssemblies) + { + if (sShortAssemblyName != ayAssembly.FullName.Split(',')[0]) continue; + ayResult = ayAssembly; + break; } return ayResult; } diff --git a/Greenshot/Help/HelpFileLoader.cs b/Greenshot/Help/HelpFileLoader.cs index 10c4c69bb..4dec29979 100644 --- a/Greenshot/Help/HelpFileLoader.cs +++ b/Greenshot/Help/HelpFileLoader.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index 42f28e4ad..8b5d19bd7 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/Colors.cs b/Greenshot/Helpers/Colors.cs index 0b30c7373..4588f4274 100644 --- a/Greenshot/Helpers/Colors.cs +++ b/Greenshot/Helpers/Colors.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/CopyData.cs b/Greenshot/Helpers/CopyData.cs index 2168c0736..3bbebc8b4 100644 --- a/Greenshot/Helpers/CopyData.cs +++ b/Greenshot/Helpers/CopyData.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -158,11 +158,12 @@ namespace Greenshot.Helpers { /// <summary> /// Clears up any resources associated with this object. /// </summary> - protected virtual void Dispose(bool disposing) { - if (disposing && _channels != null) { - _channels.Clear(); - _channels = null; - } + protected virtual void Dispose(bool disposing) + { + if (!disposing || _channels == null) return; + + _channels.Clear(); + _channels = null; } /// <summary> @@ -249,10 +250,10 @@ namespace Greenshot.Helpers { int i = 0; foreach (CopyDataChannel cdc in Dictionary.Values) { i++; - if (i == index) { - ret = cdc; - break; - } + if (i != index) continue; + + ret = cdc; + break; } return ret; } @@ -337,14 +338,14 @@ namespace Greenshot.Helpers { /// </summary> public class CopyDataChannel : IDisposable { [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern IntPtr GetProp(IntPtr hwnd, string lpString); + private static extern IntPtr GetProp(IntPtr hWnd, string lpString); [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern bool SetProp(IntPtr hwnd, string lpString, IntPtr hData); + private static extern bool SetProp(IntPtr hWnd, string lpString, IntPtr hData); [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern IntPtr RemoveProp(IntPtr hwnd, string lpString); + private static extern IntPtr RemoveProp(IntPtr hWnd, string lpString); [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, ref COPYDATASTRUCT lParam); + private static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, ref COPYDATASTRUCT lParam); [StructLayout(LayoutKind.Sequential)] private struct COPYDATASTRUCT { @@ -460,13 +461,14 @@ namespace Greenshot.Helpers { /// <summary> /// Clears up any resources associated with this channel. /// </summary> - protected virtual void Dispose(bool disposing) { - if (disposing) { - if (ChannelName.Length > 0) { - RemoveChannel(); - } - ChannelName = string.Empty; + protected virtual void Dispose(bool disposing) + { + if (!disposing) return; + + if (ChannelName.Length > 0) { + RemoveChannel(); } + ChannelName = string.Empty; } /// <summary> diff --git a/Greenshot/Helpers/DestinationHelper.cs b/Greenshot/Helpers/DestinationHelper.cs index 49cec43da..1169edb40 100644 --- a/Greenshot/Helpers/DestinationHelper.cs +++ b/Greenshot/Helpers/DestinationHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/Entities/UpdateFeed.cs b/Greenshot/Helpers/Entities/UpdateFeed.cs index a7a80afb8..280518fc8 100644 --- a/Greenshot/Helpers/Entities/UpdateFeed.cs +++ b/Greenshot/Helpers/Entities/UpdateFeed.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/EnvironmentInfo.cs b/Greenshot/Helpers/EnvironmentInfo.cs index 59caf857e..cc88802aa 100644 --- a/Greenshot/Helpers/EnvironmentInfo.cs +++ b/Greenshot/Helpers/EnvironmentInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -209,18 +209,18 @@ namespace Greenshot.Helpers } } } - if (ex is ExternalException) + if (ex is ExternalException externalException) { // e.g. COMException - report.AppendLine().AppendLine("ErrorCode: 0x" + (ex as ExternalException).ErrorCode.ToString("X")); + report.AppendLine().AppendLine("ErrorCode: 0x" + externalException.ErrorCode.ToString("X")); } report.AppendLine().AppendLine("Stack:").AppendLine(ex.StackTrace); - if (ex is ReflectionTypeLoadException) + if (ex is ReflectionTypeLoadException reflectionTypeLoadException) { report.AppendLine().AppendLine("LoaderExceptions: "); - foreach (Exception cbE in (ex as ReflectionTypeLoadException).LoaderExceptions) + foreach (Exception cbE in reflectionTypeLoadException.LoaderExceptions) { report.AppendLine(cbE.Message); } diff --git a/Greenshot/Helpers/GeometryHelper.cs b/Greenshot/Helpers/GeometryHelper.cs index d8f2dd3fd..e20cf5035 100644 --- a/Greenshot/Helpers/GeometryHelper.cs +++ b/Greenshot/Helpers/GeometryHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/GuiRectangle.cs b/Greenshot/Helpers/GuiRectangle.cs index 770874e78..c24e591ec 100644 --- a/Greenshot/Helpers/GuiRectangle.cs +++ b/Greenshot/Helpers/GuiRectangle.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/IECaptureHelper.cs b/Greenshot/Helpers/IECaptureHelper.cs index cfe36a96b..f74403176 100644 --- a/Greenshot/Helpers/IECaptureHelper.cs +++ b/Greenshot/Helpers/IECaptureHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -50,14 +50,14 @@ namespace Greenshot.Helpers { // Helper method to activate a certain IE Tab public static void ActivateIeTab(WindowDetails ieWindowDetails, int tabIndex) { WindowDetails directUiWindowDetails = IEHelper.GetDirectUI(ieWindowDetails); - if(directUiWindowDetails != null) { - // Bring window to the front - ieWindowDetails.Restore(); - // Get accessible - Accessible ieAccessible = new Accessible(directUiWindowDetails.Handle); - // Activate Tab - ieAccessible.ActivateIETab(tabIndex); - } + if (directUiWindowDetails == null) return; + + // Bring window to the front + ieWindowDetails.Restore(); + // Get accessible + Accessible ieAccessible = new Accessible(directUiWindowDetails.Handle); + // Activate Tab + ieAccessible.ActivateIETab(tabIndex); } /// <summary> @@ -68,14 +68,14 @@ namespace Greenshot.Helpers { /// <returns></returns> public static bool IsMostlyIeWindow(WindowDetails someWindow, int minimumPercentage) { WindowDetails ieWindow = someWindow.GetChild("Internet Explorer_Server"); - if (ieWindow != null) { - Rectangle wholeClient = someWindow.ClientRectangle; - Rectangle partClient = ieWindow.ClientRectangle; - int percentage = (int)(100*(float)(partClient.Width * partClient.Height) / (wholeClient.Width * wholeClient.Height)); - Log.InfoFormat("Window {0}, ie part {1}, percentage {2}", wholeClient, partClient, percentage); - if (percentage > minimumPercentage) { - return true; - } + if (ieWindow == null) return false; + + Rectangle wholeClient = someWindow.ClientRectangle; + Rectangle partClient = ieWindow.ClientRectangle; + int percentage = (int)(100*(float)(partClient.Width * partClient.Height) / (wholeClient.Width * wholeClient.Height)); + Log.InfoFormat("Window {0}, ie part {1}, percentage {2}", wholeClient, partClient, percentage); + if (percentage > minimumPercentage) { + return true; } return false; } @@ -336,9 +336,8 @@ namespace Greenshot.Helpers { /// <param name="windowToCapture">window to use</param> /// <returns>ICapture with the content (if any)</returns> public static ICapture CaptureIe(ICapture capture, WindowDetails windowToCapture) { - if (windowToCapture == null) { - windowToCapture = WindowDetails.GetActiveWindow(); - } + windowToCapture ??= WindowDetails.GetActiveWindow(); + // Show backgroundform after retrieving the active window.. BackgroundForm backgroundForm = new BackgroundForm(Language.GetString(LangKey.contextmenu_captureie), Language.GetString(LangKey.wait_ie_capture)); backgroundForm.Show(); @@ -474,27 +473,28 @@ namespace Greenshot.Helpers { continue; } // check if we need to move - if (otherFrame.DestinationRectangle.IntersectsWith(currentFrame.DestinationRectangle) && !otherFrame.SourceRectangle.IntersectsWith(currentFrame.SourceRectangle)) { - bool horizalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; - bool verticalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; - bool horizalMove = currentFrame.SourceLeft < currentFrame.DestinationLeft; - bool verticalMove = currentFrame.SourceTop < currentFrame.DestinationTop; - bool leftOf = currentFrame.SourceRight <= otherFrame.SourceLeft; - bool belowOf = currentFrame.SourceBottom <= otherFrame.SourceTop; + if (!otherFrame.DestinationRectangle.IntersectsWith(currentFrame.DestinationRectangle) || + otherFrame.SourceRectangle.IntersectsWith(currentFrame.SourceRectangle)) continue; + + bool horizontalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; + bool verticalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; + bool horizontalMove = currentFrame.SourceLeft < currentFrame.DestinationLeft; + bool verticalMove = currentFrame.SourceTop < currentFrame.DestinationTop; + bool leftOf = currentFrame.SourceRight <= otherFrame.SourceLeft; + bool belowOf = currentFrame.SourceBottom <= otherFrame.SourceTop; - if ((horizalResize || horizalMove) && leftOf) { - // Current frame resized horizontally, so move other horizontally - Log.DebugFormat("Moving Frame {0} horizontally to the right of {1}", otherFrame.Name, currentFrame.Name); - otherFrame.DestinationLeft = currentFrame.DestinationRight; - movedFrame = true; - } else if ((verticalResize || verticalMove) && belowOf){ - // Current frame resized vertically, so move other vertically - Log.DebugFormat("Moving Frame {0} vertically to the bottom of {1}", otherFrame.Name, currentFrame.Name); - otherFrame.DestinationTop = currentFrame.DestinationBottom; - movedFrame = true; - } else { - Log.DebugFormat("Frame {0} intersects with {1}", otherFrame.Name, currentFrame.Name); - } + if ((horizontalResize || horizontalMove) && leftOf) { + // Current frame resized horizontally, so move other horizontally + Log.DebugFormat("Moving Frame {0} horizontally to the right of {1}", otherFrame.Name, currentFrame.Name); + otherFrame.DestinationLeft = currentFrame.DestinationRight; + movedFrame = true; + } else if ((verticalResize || verticalMove) && belowOf){ + // Current frame resized vertically, so move other vertically + Log.DebugFormat("Moving Frame {0} vertically to the bottom of {1}", otherFrame.Name, currentFrame.Name); + otherFrame.DestinationTop = currentFrame.DestinationBottom; + movedFrame = true; + } else { + Log.DebugFormat("Frame {0} intersects with {1}", otherFrame.Name, currentFrame.Name); } } } @@ -504,7 +504,7 @@ namespace Greenshot.Helpers { // Correct cursor location to be inside the window capture.MoveMouseLocation(-documentContainer.ContentWindow.Location.X, -documentContainer.ContentWindow.Location.Y); // See if the page has the correct size, as we capture the full frame content AND might have moved them - // the normal pagesize will no longer be enough + // the normal pageSize will no longer be enough foreach(DocumentContainer frameData in documentContainer.Frames) { if (!movedMouse && frameData.SourceRectangle.Contains(capture.CursorLocation)) { // Correct mouse cursor location for scrolled position (so it shows on the capture where it really was) diff --git a/Greenshot/Helpers/IEInterop/IEContainer.cs b/Greenshot/Helpers/IEInterop/IEContainer.cs index 56d83ff29..824cf3fa9 100644 --- a/Greenshot/Helpers/IEInterop/IEContainer.cs +++ b/Greenshot/Helpers/IEInterop/IEContainer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/MailHelper.cs b/Greenshot/Helpers/MailHelper.cs index a78799eae..5111ba2cf 100644 --- a/Greenshot/Helpers/MailHelper.cs +++ b/Greenshot/Helpers/MailHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -76,20 +76,20 @@ namespace Greenshot.Helpers { public static void SendImage(ISurface surface, ICaptureDetails captureDetails) { string tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings()); - if (tmpFile != null) { - // Store the list of currently active windows, so we can make sure we show the email window later! - var windowsBefore = WindowDetails.GetVisibleWindows(); - //bool isEmailSend = false; - //if (EmailConfigHelper.HasOutlook() && (CoreConfig.OutputEMailFormat == EmailFormat.OUTLOOK_HTML || CoreConfig.OutputEMailFormat == EmailFormat.OUTLOOK_TXT)) { - // isEmailSend = OutlookExporter.ExportToOutlook(tmpFile, captureDetails); - //} - if (/*!isEmailSend &&*/ EmailConfigHelper.HasMapi()) { - // Fallback to MAPI - // Send the email - SendImage(tmpFile, captureDetails.Title); - } - WindowDetails.ActiveNewerWindows(windowsBefore); + if (tmpFile == null) return; + + // Store the list of currently active windows, so we can make sure we show the email window later! + var windowsBefore = WindowDetails.GetVisibleWindows(); + //bool isEmailSend = false; + //if (EmailConfigHelper.HasOutlook() && (CoreConfig.OutputEMailFormat == EmailFormat.OUTLOOK_HTML || CoreConfig.OutputEMailFormat == EmailFormat.OUTLOOK_TXT)) { + // isEmailSend = OutlookExporter.ExportToOutlook(tmpFile, captureDetails); + //} + if (/*!isEmailSend &&*/ EmailConfigHelper.HasMapi()) { + // Fallback to MAPI + // Send the email + SendImage(tmpFile, captureDetails.Title); } + WindowDetails.ActiveNewerWindows(windowsBefore); } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] @@ -199,74 +199,83 @@ namespace Greenshot.Helpers { _manualResetEvent?.Close(); } - /// <summary> - /// Sends the mail message. - /// </summary> - private void ShowMail() { - var message = new MapiHelperInterop.MapiMessage(); + /// <summary> + /// Sends the mail message. + /// </summary> + private void ShowMail() + { + while (true) + { + var message = new MapiHelperInterop.MapiMessage(); - using var interopRecipients = Recipients.GetInteropRepresentation(); - message.Subject = Subject; - message.NoteText = Body; + using var interopRecipients = Recipients.GetInteropRepresentation(); + message.Subject = Subject; + message.NoteText = Body; - message.Recipients = interopRecipients.Handle; - message.RecipientCount = Recipients.Count; + message.Recipients = interopRecipients.Handle; + message.RecipientCount = Recipients.Count; - // Check if we need to add attachments - if (Files.Count > 0) { - // Add attachments - message.Files = AllocAttachments(out message.FileCount); - } + // Check if we need to add attachments + if (Files.Count > 0) + { + // Add attachments + message.Files = AllocAttachments(out message.FileCount); + } - // Signal the creating thread (make the remaining code async) - _manualResetEvent.Set(); + // Signal the creating thread (make the remaining code async) + _manualResetEvent.Set(); - const int MAPI_DIALOG = 0x8; - //const int MAPI_LOGON_UI = 0x1; - int error = MapiHelperInterop.MAPISendMail(IntPtr.Zero, IntPtr.Zero, message, MAPI_DIALOG, 0); + const int MAPI_DIALOG = 0x8; + //const int MAPI_LOGON_UI = 0x1; + int error = MapiHelperInterop.MAPISendMail(IntPtr.Zero, IntPtr.Zero, message, MAPI_DIALOG, 0); - if (Files.Count > 0) { - // Deallocate the files - DeallocFiles(message); - } - MAPI_CODES errorCode = (MAPI_CODES)Enum.ToObject(typeof(MAPI_CODES), error); + if (Files.Count > 0) + { + // Deallocate the files + DeallocFiles(message); + } - // Check for error - if (errorCode == MAPI_CODES.SUCCESS || errorCode == MAPI_CODES.USER_ABORT) - { - return; - } - string errorText = GetMapiError(errorCode); - Log.Error("Error sending MAPI Email. Error: " + errorText + " (code = " + errorCode + ")."); - MessageBox.Show(errorText, "Mail (MAPI) destination", MessageBoxButtons.OK, MessageBoxIcon.Error); - // Recover from bad settings, show again - if (errorCode != MAPI_CODES.INVALID_RECIPS) - { - return; - } - Recipients = new RecipientCollection(); - ShowMail(); + MAPI_CODES errorCode = (MAPI_CODES) Enum.ToObject(typeof(MAPI_CODES), error); + + // Check for error + if (errorCode == MAPI_CODES.SUCCESS || errorCode == MAPI_CODES.USER_ABORT) + { + return; + } + + string errorText = GetMapiError(errorCode); + Log.Error("Error sending MAPI Email. Error: " + errorText + " (code = " + errorCode + ")."); + MessageBox.Show(errorText, "Mail (MAPI) destination", MessageBoxButtons.OK, MessageBoxIcon.Error); + // Recover from bad settings, show again + if (errorCode != MAPI_CODES.INVALID_RECIPS) + { + return; + } + + Recipients = new RecipientCollection(); + } } - /// <summary> + /// <summary> /// Deallocates the files in a message. /// </summary> /// <param name="message">The message to deallocate the files from.</param> - private void DeallocFiles(MapiHelperInterop.MapiMessage message) { - if (message.Files != IntPtr.Zero) { - Type fileDescType = typeof(MapiFileDescriptor); - int fsize = Marshal.SizeOf(fileDescType); + private void DeallocFiles(MapiHelperInterop.MapiMessage message) + { + if (message.Files == IntPtr.Zero) return; + + Type fileDescType = typeof(MapiFileDescriptor); + int fsize = Marshal.SizeOf(fileDescType); - // Get the ptr to the files - IntPtr runptr = message.Files; - // Release each file - for (int i = 0; i < message.FileCount; i++) { - Marshal.DestroyStructure(runptr, fileDescType); - runptr = new IntPtr(runptr.ToInt64() + fsize); - } - // Release the file - Marshal.FreeHGlobal(message.Files); + // Get the ptr to the files + IntPtr runptr = message.Files; + // Release each file + for (int i = 0; i < message.FileCount; i++) { + Marshal.DestroyStructure(runptr, fileDescType); + runptr = new IntPtr(runptr.ToInt64() + fsize); } + // Release the file + Marshal.FreeHGlobal(message.Files); } /// <summary> @@ -337,93 +346,39 @@ namespace Greenshot.Helpers { /// <summary> /// Logs any Mapi errors. /// </summary> - private string GetMapiError(MAPI_CODES errorCode) { - - string error = string.Empty; - - switch (errorCode) { - case MAPI_CODES.USER_ABORT: - error = "User Aborted."; - break; - case MAPI_CODES.FAILURE: - error = "MAPI Failure."; - break; - case MAPI_CODES.LOGIN_FAILURE: - error = "Login Failure."; - break; - case MAPI_CODES.DISK_FULL: - error = "MAPI Disk full."; - break; - case MAPI_CODES.INSUFFICIENT_MEMORY: - error = "MAPI Insufficient memory."; - break; - case MAPI_CODES.BLK_TOO_SMALL: - error = "MAPI Block too small."; - break; - case MAPI_CODES.TOO_MANY_SESSIONS: - error = "MAPI Too many sessions."; - break; - case MAPI_CODES.TOO_MANY_FILES: - error = "MAPI too many files."; - break; - case MAPI_CODES.TOO_MANY_RECIPIENTS: - error = "MAPI too many recipients."; - break; - case MAPI_CODES.ATTACHMENT_NOT_FOUND: - error = "MAPI Attachment not found."; - break; - case MAPI_CODES.ATTACHMENT_OPEN_FAILURE: - error = "MAPI Attachment open failure."; - break; - case MAPI_CODES.ATTACHMENT_WRITE_FAILURE: - error = "MAPI Attachment Write Failure."; - break; - case MAPI_CODES.UNKNOWN_RECIPIENT: - error = "MAPI Unknown recipient."; - break; - case MAPI_CODES.BAD_RECIPTYPE: - error = "MAPI Bad recipient type."; - break; - case MAPI_CODES.NO_MESSAGES: - error = "MAPI No messages."; - break; - case MAPI_CODES.INVALID_MESSAGE: - error = "MAPI Invalid message."; - break; - case MAPI_CODES.TEXT_TOO_LARGE: - error = "MAPI Text too large."; - break; - case MAPI_CODES.INVALID_SESSION: - error = "MAPI Invalid session."; - break; - case MAPI_CODES.TYPE_NOT_SUPPORTED: - error = "MAPI Type not supported."; - break; - case MAPI_CODES.AMBIGUOUS_RECIPIENT: - error = "MAPI Ambiguous recipient."; - break; - case MAPI_CODES.MESSAGE_IN_USE: - error = "MAPI Message in use."; - break; - case MAPI_CODES.NETWORK_FAILURE: - error = "MAPI Network failure."; - break; - case MAPI_CODES.INVALID_EDITFIELDS: - error = "MAPI Invalid edit fields."; - break; - case MAPI_CODES.INVALID_RECIPS: - error = "MAPI Invalid Recipients."; - break; - case MAPI_CODES.NOT_SUPPORTED: - error = "MAPI Not supported."; - break; - case MAPI_CODES.NO_LIBRARY: - error = "MAPI No Library."; - break; - case MAPI_CODES.INVALID_PARAMETER: - error = "MAPI Invalid parameter."; - break; - } + private string GetMapiError(MAPI_CODES errorCode) + { + string error = errorCode switch + { + MAPI_CODES.USER_ABORT => "User Aborted.", + MAPI_CODES.FAILURE => "MAPI Failure.", + MAPI_CODES.LOGIN_FAILURE => "Login Failure.", + MAPI_CODES.DISK_FULL => "MAPI Disk full.", + MAPI_CODES.INSUFFICIENT_MEMORY => "MAPI Insufficient memory.", + MAPI_CODES.BLK_TOO_SMALL => "MAPI Block too small.", + MAPI_CODES.TOO_MANY_SESSIONS => "MAPI Too many sessions.", + MAPI_CODES.TOO_MANY_FILES => "MAPI too many files.", + MAPI_CODES.TOO_MANY_RECIPIENTS => "MAPI too many recipients.", + MAPI_CODES.ATTACHMENT_NOT_FOUND => "MAPI Attachment not found.", + MAPI_CODES.ATTACHMENT_OPEN_FAILURE => "MAPI Attachment open failure.", + MAPI_CODES.ATTACHMENT_WRITE_FAILURE => "MAPI Attachment Write Failure.", + MAPI_CODES.UNKNOWN_RECIPIENT => "MAPI Unknown recipient.", + MAPI_CODES.BAD_RECIPTYPE => "MAPI Bad recipient type.", + MAPI_CODES.NO_MESSAGES => "MAPI No messages.", + MAPI_CODES.INVALID_MESSAGE => "MAPI Invalid message.", + MAPI_CODES.TEXT_TOO_LARGE => "MAPI Text too large.", + MAPI_CODES.INVALID_SESSION => "MAPI Invalid session.", + MAPI_CODES.TYPE_NOT_SUPPORTED => "MAPI Type not supported.", + MAPI_CODES.AMBIGUOUS_RECIPIENT => "MAPI Ambiguous recipient.", + MAPI_CODES.MESSAGE_IN_USE => "MAPI Message in use.", + MAPI_CODES.NETWORK_FAILURE => "MAPI Network failure.", + MAPI_CODES.INVALID_EDITFIELDS => "MAPI Invalid edit fields.", + MAPI_CODES.INVALID_RECIPS => "MAPI Invalid Recipients.", + MAPI_CODES.NOT_SUPPORTED => "MAPI Not supported.", + MAPI_CODES.NO_LIBRARY => "MAPI No Library.", + MAPI_CODES.INVALID_PARAMETER => "MAPI Invalid parameter.", + _ => string.Empty + }; return error; } @@ -466,7 +421,7 @@ namespace Greenshot.Helpers { } [DllImport("MAPI32.DLL", SetLastError = true, CharSet=CharSet.Ansi)] - public static extern int MAPISendMail(IntPtr session, IntPtr hwnd, MapiMessage message, int flg, int rsv); + public static extern int MAPISendMail(IntPtr session, IntPtr hWnd, MapiMessage message, int flg, int rsv); } } @@ -542,7 +497,7 @@ namespace Greenshot.Helpers { } /// <summary> - /// Represents a colleciton of recipients for a mail message. + /// Represents a collection of recipients for a mail message. /// </summary> public class RecipientCollection : CollectionBase { /// <summary> @@ -627,25 +582,26 @@ namespace Greenshot.Helpers { /// <summary> /// Disposes of resources. /// </summary> - public void Dispose() { - if (Handle != IntPtr.Zero) { - Type type = typeof(MapiMailMessage.MapiHelperInterop.MapiRecipDesc); - int size = Marshal.SizeOf(type); + public void Dispose() + { + if (Handle == IntPtr.Zero) return; + + Type type = typeof(MapiMailMessage.MapiHelperInterop.MapiRecipDesc); + int size = Marshal.SizeOf(type); - // destroy all the structures in the memory area - IntPtr ptr = Handle; - for (int i = 0; i < _count; i++) { - Marshal.DestroyStructure(ptr, type); - ptr = new IntPtr(ptr.ToInt64() + size); - } + // destroy all the structures in the memory area + IntPtr ptr = Handle; + for (int i = 0; i < _count; i++) { + Marshal.DestroyStructure(ptr, type); + ptr = new IntPtr(ptr.ToInt64() + size); + } - // free the memory - Marshal.FreeHGlobal(Handle); + // free the memory + Marshal.FreeHGlobal(Handle); - Handle = IntPtr.Zero; - _count = 0; - } - } + Handle = IntPtr.Zero; + _count = 0; + } } } } \ No newline at end of file diff --git a/Greenshot/Helpers/NotifyIconNotificationService.cs b/Greenshot/Helpers/NotifyIconNotificationService.cs index 7398a7890..708da7592 100644 --- a/Greenshot/Helpers/NotifyIconNotificationService.cs +++ b/Greenshot/Helpers/NotifyIconNotificationService.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/PluginHelper.cs b/Greenshot/Helpers/PluginHelper.cs index 1d31e8e38..38de55b24 100644 --- a/Greenshot/Helpers/PluginHelper.cs +++ b/Greenshot/Helpers/PluginHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/PrintHelper.cs b/Greenshot/Helpers/PrintHelper.cs index 5de51a20f..d04f8e317 100644 --- a/Greenshot/Helpers/PrintHelper.cs +++ b/Greenshot/Helpers/PrintHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -102,7 +102,7 @@ namespace Greenshot.Helpers { returnPrinterSettings = _printDocument.PrinterSettings; } } catch (Exception e) { - Log.Error("An error ocurred while trying to print", e); + Log.Error("An error occurred while trying to print", e); MessageBox.Show(Language.GetString(LangKey.print_error), Language.GetString(LangKey.error)); } return returnPrinterSettings; @@ -115,21 +115,20 @@ namespace Greenshot.Helpers { /// <returns>printer settings if actually printed, or null if print was cancelled or has failed</returns> public PrinterSettings PrintWithDialog() { PrinterSettings returnPrinterSettings = null; - if (_printDialog.ShowDialog() == DialogResult.OK) { - DialogResult? printOptionsResult = ShowPrintOptionsDialog(); - try { - if (printOptionsResult == null || printOptionsResult == DialogResult.OK) { - if (!IsColorPrint()) { - _printDocument.DefaultPageSettings.Color = false; - } - _printDocument.Print(); - returnPrinterSettings = _printDialog.PrinterSettings; - } - } catch (Exception e) { - Log.Error("An error ocurred while trying to print", e); - MessageBox.Show(Language.GetString(LangKey.print_error), Language.GetString(LangKey.error)); - } + if (_printDialog.ShowDialog() != DialogResult.OK) return null; + DialogResult? printOptionsResult = ShowPrintOptionsDialog(); + try { + if (printOptionsResult == null || printOptionsResult == DialogResult.OK) { + if (!IsColorPrint()) { + _printDocument.DefaultPageSettings.Color = false; + } + _printDocument.Print(); + returnPrinterSettings = _printDialog.PrinterSettings; + } + } catch (Exception e) { + Log.Error("An error occurred while trying to print", e); + MessageBox.Show(Language.GetString(LangKey.print_error), Language.GetString(LangKey.error)); } return returnPrinterSettings; } @@ -153,9 +152,7 @@ namespace Greenshot.Helpers { } private void DrawImageForPrint(object sender, PrintPageEventArgs e) { - - - // Create the output settins + // Create the output settings SurfaceOutputSettings printOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); ApplyEffects(printOutputSettings); @@ -190,7 +187,7 @@ namespace Greenshot.Helpers { RectangleF imageRect = image.GetBounds(ref gu); // rotate the image if it fits the page better if (CoreConfig.OutputPrintAllowRotate) { - if ((pageRect.Width > pageRect.Height && imageRect.Width < imageRect.Height) || (pageRect.Width < pageRect.Height && imageRect.Width > imageRect.Height)) { + if (pageRect.Width > pageRect.Height && imageRect.Width < imageRect.Height || pageRect.Width < pageRect.Height && imageRect.Width > imageRect.Height) { image.RotateFlip(RotateFlipType.Rotate270FlipNone); imageRect = image.GetBounds(ref gu); if (alignment.Equals(ContentAlignment.TopLeft)) { @@ -203,7 +200,7 @@ namespace Greenshot.Helpers { // scale the image to fit the page better if (CoreConfig.OutputPrintAllowEnlarge || CoreConfig.OutputPrintAllowShrink) { SizeF resizedRect = ScaleHelper.GetScaledSize(imageRect.Size, pageRect.Size, false); - if ((CoreConfig.OutputPrintAllowShrink && resizedRect.Width < printRect.Width) || CoreConfig.OutputPrintAllowEnlarge && resizedRect.Width > printRect.Width) { + if (CoreConfig.OutputPrintAllowShrink && resizedRect.Width < printRect.Width || CoreConfig.OutputPrintAllowEnlarge && resizedRect.Width > printRect.Width) { printRect.Size = resizedRect; } } diff --git a/Greenshot/Helpers/ProcessorHelper.cs b/Greenshot/Helpers/ProcessorHelper.cs index 0ccf0fbe6..25598944a 100644 --- a/Greenshot/Helpers/ProcessorHelper.cs +++ b/Greenshot/Helpers/ProcessorHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/ResourceMutex.cs b/Greenshot/Helpers/ResourceMutex.cs index 7a70031c1..9854c3dca 100644 --- a/Greenshot/Helpers/ResourceMutex.cs +++ b/Greenshot/Helpers/ResourceMutex.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -106,7 +106,7 @@ namespace Greenshot.Helpers catch (AbandonedMutexException e) { // Another instance didn't cleanup correctly! - // we can ignore the exception, it happend on the "waitone" but still the mutex belongs to us + // we can ignore the exception, it happened on the "waitOne" but still the mutex belongs to us Log.WarnFormat("{0} didn't cleanup correctly, but we got the mutex {1}.", _resourceName, _mutexId); Log.Warn(e); } @@ -132,26 +132,25 @@ namespace Greenshot.Helpers /// The real disposing code /// </summary> /// <param name="disposing">true if dispose is called, false when the finalizer is called</param> - protected virtual void Dispose(bool disposing) + protected void Dispose(bool disposing) { - if (!_disposedValue) + if (_disposedValue) return; + + if (_applicationMutex != null) { - if (_applicationMutex != null) + try { - try - { - _applicationMutex.ReleaseMutex(); - _applicationMutex = null; - Log.InfoFormat("Released Mutex {0} for {1}", _mutexId, _resourceName); - } - catch (Exception ex) - { - Log.ErrorFormat("Error releasing Mutex {0} for {1}", _mutexId, _resourceName); - Log.Error(ex); - } + _applicationMutex.ReleaseMutex(); + _applicationMutex = null; + Log.InfoFormat("Released Mutex {0} for {1}", _mutexId, _resourceName); + } + catch (Exception ex) + { + Log.ErrorFormat("Error releasing Mutex {0} for {1}", _mutexId, _resourceName); + Log.Error(ex); } - _disposedValue = true; } + _disposedValue = true; } /// <summary> diff --git a/Greenshot/Helpers/ScaleHelper.cs b/Greenshot/Helpers/ScaleHelper.cs index b7c7b1d62..76e0091c6 100644 --- a/Greenshot/Helpers/ScaleHelper.cs +++ b/Greenshot/Helpers/ScaleHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -64,7 +64,7 @@ namespace Greenshot.Helpers { /// calculates the position of an element depending on the desired alignment within a RectangleF /// </summary> /// <param name="currentRect">the bounds of the element to be aligned</param> - /// <param name="targetRect">the rectangle reference for aligment of the element</param> + /// <param name="targetRect">the rectangle reference for alignment of the element</param> /// <param name="alignment">the System.Drawing.ContentAlignment value indicating how the element is to be aligned should the width or height differ from targetSize</param> /// <returns>a new RectangleF object with Location aligned aligned to targetRect</returns> public static RectangleF GetAlignedRectangle(RectangleF currentRect, RectangleF targetRect, ContentAlignment alignment) { @@ -136,15 +136,13 @@ namespace Greenshot.Helpers { /// <param name="resizeHandleCoords">coordinates of the used handle/gripper</param> /// <param name="options">ScaleOptions to use when scaling</param> public static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords, ScaleOptions? options) { - if(options == null) { - options = GetScaleOptions(); - } + options ??= GetScaleOptions(); - if((options & ScaleOptions.Rational) == ScaleOptions.Rational) { + if ((options & ScaleOptions.Rational) == ScaleOptions.Rational) { adjustCoordsForRationalScale(originalRectangle, resizeHandlePosition, ref resizeHandleCoords); } - if((options & ScaleOptions.Centered) == ScaleOptions.Centered) { + if ((options & ScaleOptions.Centered) == ScaleOptions.Centered) { // store center coordinates of rectangle float rectCenterX = originalRectangle.Left + originalRectangle.Width / 2; float rectCenterY = originalRectangle.Top + originalRectangle.Height / 2; @@ -332,14 +330,14 @@ namespace Greenshot.Helpers { } public class ShapeAngleRoundBehavior : IDoubleProcessor { - public static ShapeAngleRoundBehavior Instance = new ShapeAngleRoundBehavior(); + public static ShapeAngleRoundBehavior Instance = new(); private ShapeAngleRoundBehavior() {} public double Process(double angle) { return Math.Round((angle+45)/90)*90 - 45; } } public class LineAngleRoundBehavior : IDoubleProcessor { - public static LineAngleRoundBehavior Instance = new LineAngleRoundBehavior(); + public static LineAngleRoundBehavior Instance = new(); private LineAngleRoundBehavior() {} public double Process(double angle) { return Math.Round(angle/15)*15; @@ -354,21 +352,6 @@ namespace Greenshot.Helpers { return fixedAngle; } } - - - - - - /*public static int FindGripperPostition(float anchorX, float anchorY, float gripperX, float gripperY) { - if(gripperY > anchorY) { - if(gripperX > anchorY) return Gripper.POSITION_BOTTOM_RIGHT; - else return Gripper.POSITION_BOTTOM_LEFT; - } else { - if(gripperX > anchorY) return Gripper.POSITION_TOP_RIGHT; - else return Gripper.POSITION_TOP_LEFT; - } - }*/ - } } \ No newline at end of file diff --git a/Greenshot/Helpers/SoundHelper.cs b/Greenshot/Helpers/SoundHelper.cs index eb9139290..427909d86 100644 --- a/Greenshot/Helpers/SoundHelper.cs +++ b/Greenshot/Helpers/SoundHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/StartupHelper.cs b/Greenshot/Helpers/StartupHelper.cs index 9e5e4461b..1ca5180e8 100644 --- a/Greenshot/Helpers/StartupHelper.cs +++ b/Greenshot/Helpers/StartupHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -226,9 +226,9 @@ namespace Greenshot.Helpers { } /// <summary> - /// Test if there is a link in the Statup folder + /// Test if there is a link in the Startup folder /// </summary> - /// <returns></returns> + /// <returns>bool</returns> public static bool IsInStartupFolder() { try { string lnkName = Path.GetFileNameWithoutExtension(Application.ExecutablePath) + ".lnk"; diff --git a/Greenshot/Helpers/ToolStripItemEndisabler.cs b/Greenshot/Helpers/ToolStripItemEndisabler.cs index 268a8d2b2..db5a5d178 100644 --- a/Greenshot/Helpers/ToolStripItemEndisabler.cs +++ b/Greenshot/Helpers/ToolStripItemEndisabler.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -63,24 +63,26 @@ namespace Greenshot.Helpers { Endisable(tsi, false, PropagationMode.CHILDREN); } - private static void Endisable(ToolStrip ts, bool enable, PropagationMode mode){ - if((mode & PropagationMode.CHILDREN) == PropagationMode.CHILDREN) { - foreach(ToolStripItem tsi in ts.Items) { - Endisable(tsi, enable, PropagationMode.CHILDREN); - } + private static void Endisable(ToolStrip ts, bool enable, PropagationMode mode) + { + if ((mode & PropagationMode.CHILDREN) != PropagationMode.CHILDREN) return; + + foreach(ToolStripItem tsi in ts.Items) { + Endisable(tsi, enable, PropagationMode.CHILDREN); } } private static void Endisable(ToolStripItem tsi, bool enable, PropagationMode mode){ - if(tsi is ToolStripDropDownItem) { - Endisable(tsi as ToolStripDropDownItem, enable, mode); + if (tsi is ToolStripDropDownItem item) { + Endisable(item, enable, mode); } else { tsi.Enabled = enable; } - if((mode & PropagationMode.ANCESTORS) == PropagationMode.ANCESTORS) { - if(tsi.OwnerItem != null) Endisable(tsi.OwnerItem, enable, PropagationMode.ANCESTORS); - } + + if ((mode & PropagationMode.ANCESTORS) != PropagationMode.ANCESTORS) return; + if (tsi.OwnerItem != null) Endisable(tsi.OwnerItem, enable, PropagationMode.ANCESTORS); + } private static void Endisable(ToolStripDropDownItem tsddi, bool enable, PropagationMode mode) { diff --git a/Greenshot/Helpers/UpdateService.cs b/Greenshot/Helpers/UpdateService.cs index ceb3488be..8c1728fb8 100644 --- a/Greenshot/Helpers/UpdateService.cs +++ b/Greenshot/Helpers/UpdateService.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Helpers/WindowWrapper.cs b/Greenshot/Helpers/WindowWrapper.cs deleted file mode 100644 index 1fde215e0..000000000 --- a/Greenshot/Helpers/WindowWrapper.cs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -using System; -using System.Windows.Forms; - -namespace Greenshot.Helpers { - public class WindowWrapper : IWin32Window { - public WindowWrapper(IntPtr handle) { - Handle = handle; - } - - public IntPtr Handle { get; } - } -} diff --git a/Greenshot/Languages/language-ar-SY.xml b/Greenshot/Languages/language-ar-SY.xml index eec227d75..c5c6edc84 100644 --- a/Greenshot/Languages/language-ar-SY.xml +++ b/Greenshot/Languages/language-ar-SY.xml @@ -5,7 +5,7 @@ <resource name="about_donations">اذا اعجبك البرنامج انت مدعو لدعمنا:</resource> <resource name="about_host">جرين شوت استضيف بواسطة GitHub في</resource> <resource name="about_icons">الايقونات بواسطة مجموعة ايقونات يوسوكي كامياماني (تحت رخصة المشاع الإبداعي الاصدار 3.0)</resource> - <resource name="about_license">حقوق النشر © 2007 - 2020 توماس براون, جينس كلنجين, روبين كروم + <resource name="about_license">حقوق النشر © 2007 -2021 توماس براون, جينس كلنجين, روبين كروم جرين شوت لا يأتي مع أية ضمان. هذا برنامج حر, مرحبا بك لتعيد توزيعه تحت شروط معينة. تفاصيل حول رخصة جنو العمومية:</resource> <resource name="about_title">حول جرين شوت</resource> diff --git a/Greenshot/Languages/language-ca-CA.xml b/Greenshot/Languages/language-ca-CA.xml index 374d58705..9f92f7446 100644 --- a/Greenshot/Languages/language-ca-CA.xml +++ b/Greenshot/Languages/language-ca-CA.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Si Greenshot us agrada , us agrairem que ens ajudeu:</resource> <resource name="about_host">Greenshot s'allotja a sourceforge.net</resource> <resource name="about_icons">Icones del conjunt d'icones Fugue de Yusuke Kamiyamane(Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot s'ofereix SENSE CAP GARANTIA. Aquest és un programari gratuït, i podeu redistribuir-lo amb algunes condicions. Detalls sobre la Llicència General Publica GNU:</resource> <resource name="about_title">Quant a Greenshot</resource> diff --git a/Greenshot/Languages/language-cs-CZ.xml b/Greenshot/Languages/language-cs-CZ.xml index 392ba617d..c34389ebf 100644 --- a/Greenshot/Languages/language-cs-CZ.xml +++ b/Greenshot/Languages/language-cs-CZ.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Pokud se vám Greenshot líbí, uvítáme Vaší podporu</resource> <resource name="about_host">Greenshot je hostován na sourceforge.net</resource> <resource name="about_icons">Ikony pochází ze sady Yusuke Kamiyamane's Fugue (licence Creative Commons Attribution 3.0)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot je ABSOLUTNĚ BEZ ZÁRUKY. Toto je svobodný software, můžete jej dále šířit za určitých podmínek. Podrobnosti o GNU General Public License:</resource> <resource name="about_title">O programu Greenshot</resource> diff --git a/Greenshot/Languages/language-de-DE.xml b/Greenshot/Languages/language-de-DE.xml index 2435a7105..9ece82568 100644 --- a/Greenshot/Languages/language-de-DE.xml +++ b/Greenshot/Languages/language-de-DE.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Wenn Sie Greenshot mögen, können Sie uns gerne unterstützen:</resource> <resource name="about_host">Greenshot wird von GitHub gehostet unter</resource> <resource name="about_icons">Icons aus Yusuke Kamiyamane's Fugue icon set (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Für Greenshot besteht KEINERLEI GARANTIE. Greenshot ist freie Software, die Sie unter bestimmten Bedingungen weitergeben dürfen. Detaillierte Informationen zur GNU General Public License:</resource> <resource name="about_title">Über Greenshot</resource> diff --git a/Greenshot/Languages/language-de-x-franconia.xml b/Greenshot/Languages/language-de-x-franconia.xml index abbf24bbf..b989bcfe7 100644 --- a/Greenshot/Languages/language-de-x-franconia.xml +++ b/Greenshot/Languages/language-de-x-franconia.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Wenn der Greenshot gfälld, kannsd uns gern a weng helfn:</resource> <resource name="about_host">Greenshot is a bei GitHub, und zwa dordn:</resource> <resource name="about_icons">Dei Fuztl-Bildla sin vom Yusuke Kamiyamane's Fugue icon set (Griäidif Gommens Äddribuschn 3.0 Laisns)</resource> - <resource name="about_license">Kobbireid (C) 2007-2020 Domas Braun, Jens Glingen, Robin Grohm + <resource name="about_license">Kobbireid (C) 2007-2021 Domas Braun, Jens Glingen, Robin Grohm A Garandie gibds für Greenshot ned, des kannst vergessn. Greenshot is umsonsd und wennsd mogst, kannsd es a rumreichn. Mehr Infos zur GNU Dschännerel Bablig Laisns:</resource> <resource name="about_title">Was issn Greenshot???</resource> diff --git a/Greenshot/Languages/language-el-GR.xml b/Greenshot/Languages/language-el-GR.xml index 732b54f0c..14cb68bef 100644 --- a/Greenshot/Languages/language-el-GR.xml +++ b/Greenshot/Languages/language-el-GR.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Αν σας αρέσει το Greenshot, είστε ευπρόσδεκτοι να μας υποστηρίξετε:</resource> <resource name="about_host">Το Greenshot φιλοξενείται από τη GitHub:</resource> <resource name="about_icons">Εικονίδια από Yusuke Kamiyamane's Fugue icon set (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Δεν παρέχεται ΚΑΜΙΑ ΕΓΓΥΗΣΗ για το Greenshot. Είναι ελεύθερο λογισμικό. Είστε ελεύθεροι να το αναδιανείμετε κάτω από ορισμένες συνθήκες. Λεπτομέρειες σχετικά με την GNU General Public License:</resource> <resource name="about_title">Πληροφορίες για το Greenshot</resource> diff --git a/Greenshot/Languages/language-en-US.xml b/Greenshot/Languages/language-en-US.xml index 1efcd15e9..0537c965b 100644 --- a/Greenshot/Languages/language-en-US.xml +++ b/Greenshot/Languages/language-en-US.xml @@ -5,7 +5,7 @@ <resource name="about_donations">If you like Greenshot, you are welcome to support us:</resource> <resource name="about_host">Greenshot is hosted by GitHub at</resource> <resource name="about_icons">Icons from Yusuke Kamiyamane's Fugue icon set (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Details about the GNU General Public License:</resource> <resource name="about_title">About Greenshot</resource> diff --git a/Greenshot/Languages/language-es-ES.xml b/Greenshot/Languages/language-es-ES.xml index 22d44abf5..b84aee912 100644 --- a/Greenshot/Languages/language-es-ES.xml +++ b/Greenshot/Languages/language-es-ES.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Si te gusta Greenshot, te agradeceremos que nos ayudes:</resource> <resource name="about_host">Greenshot está alojado en GitHub en</resource> <resource name="about_icons">Iconos del conjunto de iconos Fugue de Yusuke Kamiyamane(Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot viene ABSOLUTAMENTE SIN GARANTIA. Este es software gratuito, y eres bienvenido a redistribuirlo bajo ciertas condiciones. Detalles acerca de la Licencia General Publica GNU:</resource> <resource name="about_title">Acerca de Greenshot</resource> diff --git a/Greenshot/Languages/language-et-EE.xml b/Greenshot/Languages/language-et-EE.xml index 0de7a68f7..b358977e8 100644 --- a/Greenshot/Languages/language-et-EE.xml +++ b/Greenshot/Languages/language-et-EE.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Greenshoti kasutamismugavust ja arendust saate toetada siin:</resource> <resource name="about_host">Greenshot asub portaalis GitHub</resource> <resource name="about_icons">Yusuke Kamiyamane on ikoonide tegija Fugue ikooni paketist (Creative Commons Attribution 3.0 litsents)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot ei paku GARANTIID. See on vabaravaline programm ja Te võite seda levitava vabalt teatud tingimuste alusel. Lisainfo GNU Põhilise Avaliku Litsentsi kohta:</resource> <resource name="about_title">Info Greenshoti kohta</resource> diff --git a/Greenshot/Languages/language-fi-FI.xml b/Greenshot/Languages/language-fi-FI.xml index 13a01263c..f66cc5013 100644 --- a/Greenshot/Languages/language-fi-FI.xml +++ b/Greenshot/Languages/language-fi-FI.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Jos pidät Greenshotista niin toivottavasti tuet meitä:</resource> <resource name="about_host">Greenshot is hosted by GitHub at</resource> <resource name="about_icons">Ikonit ovat Yusuke Kamiyamane:n Fugue ikonisarjasta (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Details about the GNU General Public License:</resource> <resource name="about_title">Tietoja Greenshotista</resource> diff --git a/Greenshot/Languages/language-fr-FR.xml b/Greenshot/Languages/language-fr-FR.xml index 26349708d..53f8e21f6 100644 --- a/Greenshot/Languages/language-fr-FR.xml +++ b/Greenshot/Languages/language-fr-FR.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Si vous aimez Greenshot, vous pouvez nous soutenir :</resource> <resource name="about_host">Greenshot est hébergé par GitHub à</resource> <resource name="about_icons">Icônes provenant du lot d'icônes Fugue de Kamiyamane Yuusuke (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright © 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright © 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot vous est fourni SANS AUCUNE GARANTIE. C'est un logiciel gratuit que vous êtes libres de redistribuer sous certaines conditions. Détails de la GNU General Public License :</resource> <resource name="about_title">À propos de Greenshot</resource> diff --git a/Greenshot/Languages/language-fr-QC.xml b/Greenshot/Languages/language-fr-QC.xml index 629591d62..17c0e5537 100644 --- a/Greenshot/Languages/language-fr-QC.xml +++ b/Greenshot/Languages/language-fr-QC.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Si vous aimez Greenshot, vous pouvez nous soutenir :</resource> <resource name="about_host">Greenshot est hébergé par GitHub à</resource> <resource name="about_icons">Icônes provenant du lot d'icônes Fugue de Kamiyamane Yuusuke (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright © 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright © 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot vous est fourni SANS AUCUNE GARANTIE. C'est un logiciel gratuit que vous êtes libres de redistribuer sous certaines conditions. Détails de la GNU General Public License :</resource> <resource name="about_title">A propos de Greenshot</resource> diff --git a/Greenshot/Languages/language-he-IL.xml b/Greenshot/Languages/language-he-IL.xml index 10f5a3c31..4df909d37 100644 --- a/Greenshot/Languages/language-he-IL.xml +++ b/Greenshot/Languages/language-he-IL.xml @@ -5,7 +5,7 @@ <resource name="about_donations">:אם את\ה נהנה\ית משימוש בתוכנה, את\ה מוזמן לתרום לנו</resource> <resource name="about_host">Greenshot is hosted by GitHub at</resource> <resource name="about_icons">Icons from Yusuke Kamiyamane's Fugue icon set (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Details about the GNU General Public License:</resource> <resource name="about_title">Greenshot אודות התוכנה</resource> diff --git a/Greenshot/Languages/language-hu-HU.xml b/Greenshot/Languages/language-hu-HU.xml index c20c0cf99..0d5a06df9 100644 --- a/Greenshot/Languages/language-hu-HU.xml +++ b/Greenshot/Languages/language-hu-HU.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Ha szereted Greenshot -ot, akkor támogass minket:</resource> <resource name="about_host">Greenshot kiszolgálója a GitHub</resource> <resource name="about_icons">Az ikonokat Yusuke Kamiyamane's Fugue készítette (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Szerzői jog (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Szerzői jog (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom SEMMIFÉLE GARANCIA sincs a Greenshot -hoz. Ez egy ingyenes program, és hálásak vagyunk, hogy terjeszted bizonyos feltételekkel. Részletek a GNU Fő Nyílvános Engedélyről:</resource> <resource name="about_title">Greenshot névjegye</resource> diff --git a/Greenshot/Languages/language-id-ID.xml b/Greenshot/Languages/language-id-ID.xml index ea35af361..e474cae59 100644 --- a/Greenshot/Languages/language-id-ID.xml +++ b/Greenshot/Languages/language-id-ID.xml @@ -5,18 +5,18 @@ <resource name="about_donations">Jika anda menyukai Greenshot, anda dipersilahkan untuk mendukung kami:</resource> <resource name="about_host">Greenshot dikelola oleh GitHub di</resource> <resource name="about_icons">Ikon dari Yusuke Kamiyamane Fugue ikon set (lisensi Creative Commons Attribution 3.0)</resource> - <resource name="about_license">Hak Cipta milik Thomas Braun, Jens Klingen, Robin Krom 2007-2020 -Greenshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. + <resource name="about_license">Hak Cipta milik Thomas Braun, Jens Klingen, Robin Krom 2007-2021 +Greenshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Details about the GNU General Public License:</resource> <resource name="about_title">Tentang Greenshot</resource> <resource name="application_title">Greenshot - utilitas penangkap layar yang revolusioner</resource> <resource name="bugreport_cancel">Tutup</resource> - <resource name="bugreport_info">Maaf, kesalahan yang tak terduga terjadi. - -Kabar baiknya: anda dapat membantu kami memperbaikinya dengan mengisi laporan kesalahan. -Harap kunjungi laman berikut, buat laporan kesalahan baru dan letakkan konten dari area teks ke wadah deskripsi. - -Harap tambah penjelasan yang berarti dan sertakan informasi lain yang penting untuk kami tiru kesalahannya. + <resource name="bugreport_info">Maaf, kesalahan yang tak terduga terjadi. + +Kabar baiknya: anda dapat membantu kami memperbaikinya dengan mengisi laporan kesalahan. +Harap kunjungi laman berikut, buat laporan kesalahan baru dan letakkan konten dari area teks ke wadah deskripsi. + +Harap tambah penjelasan yang berarti dan sertakan informasi lain yang penting untuk kami tiru kesalahannya. Juga, kami sangat terbantu apabila anda mengecek laporan lain yang sama dengan kepunyaan anda. (Anda dapat menggunakan pencarian untuk mencari dengan cepat.) Terima kasih :)</resource> <resource name="bugreport_title">Kesalahan</resource> <resource name="CANCEL">Batal</resource> @@ -180,7 +180,7 @@ Juga, kami sangat terbantu apabila anda mengecek laporan lain yang sama dengan k <resource name="EmailFormat.OUTLOOK_TXT">Outlook dengan teks</resource> <resource name="error">Kesalahan</resource> <resource name="error_multipleinstances">Sesuatu dari Greenshot telah dijalankan.</resource> - <resource name="error_nowriteaccess">Tidak dapat berkas {0}. + <resource name="error_nowriteaccess">Tidak dapat berkas {0}. Harap cek aksesibilitas menuis pada lokasi penyimpanan yang dipilih.</resource> <resource name="error_openfile">Berkas "{0}" tidak dapat dibuka.</resource> <resource name="error_openlink">Tidak dapat membuka link '{0}'.</resource> @@ -245,22 +245,22 @@ Harap cek aksesibilitas menuis pada lokasi penyimpanan yang dipilih.</resource> <resource name="settings_iecapture">Tangkap Internet Explorer</resource> <resource name="settings_jpegquality">Kualitas JPEG</resource> <resource name="settings_language">Bahasa</resource> - <resource name="settings_message_filenamepattern">Pedoman berikut akan ditimpa otomatis dalam pola yang ditetapkan: -${YYYY} tahun, 4 digit -${MM} bulan, 2 digit -${DD} hari, 2 digit -${hh} jam, 2 digit -${mm} menit, 2 digit -${ss} detik, 2 digit -${NUM} angka tambahan, 6 digit -${title} judul jendela -${user} pengguna Windows -${domain} domain Windows -${hostname} nama PC - -Anda juga dapat membuat direktori Greenshot secara dinamis, cukup gunakan simbol garis miring {\} untuk memisahkan folder dan nama berkas -Contoh: pola ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} -akan menbuat folder untuk hari terbaru di lokasi penyimpan default, cont. 2008-06-29, nama berkas didasarkan pada waktu terbaru + <resource name="settings_message_filenamepattern">Pedoman berikut akan ditimpa otomatis dalam pola yang ditetapkan: +${YYYY} tahun, 4 digit +${MM} bulan, 2 digit +${DD} hari, 2 digit +${hh} jam, 2 digit +${mm} menit, 2 digit +${ss} detik, 2 digit +${NUM} angka tambahan, 6 digit +${title} judul jendela +${user} pengguna Windows +${domain} domain Windows +${hostname} nama PC + +Anda juga dapat membuat direktori Greenshot secara dinamis, cukup gunakan simbol garis miring {\} untuk memisahkan folder dan nama berkas +Contoh: pola ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} +akan menbuat folder untuk hari terbaru di lokasi penyimpan default, cont. 2008-06-29, nama berkas didasarkan pada waktu terbaru cont, 11_58_32 (ditambah ekstensi yang ditetapkan pada pengaturan)</resource> <resource name="settings_network">Jaringan dan pembaruan</resource> <resource name="settings_output">Output</resource> @@ -296,8 +296,8 @@ cont, 11_58_32 (ditambah ekstensi yang ditetapkan pada pengaturan)</resource> <resource name="update_found">Versi baru Greenshot telah tersedia! Apakah anda ingin mengunduh Greenshot {0}?</resource> <resource name="wait_ie_capture">Harap tunggu ketika halaman Internet Explorer sedang ditangkap</resource> <resource name="warning">Peringatan</resource> - <resource name="warning_hotkeys">hotkey {0} tak dapat terdaftar, kemungkinan akibat alat lain telah mengklaim penggunaan hotkey, anda dapat mengganti hotkey yang lain atau menonaktifkannya. - + <resource name="warning_hotkeys">hotkey {0} tak dapat terdaftar, kemungkinan akibat alat lain telah mengklaim penggunaan hotkey, anda dapat mengganti hotkey yang lain atau menonaktifkannya. + Semua fitur Greenshot masih bekerja dengan baik dari ikon tray menu konteks tanpa hotkey.</resource> <resource name="WindowCaptureMode.Aero">Gunakan warna kesukaan</resource> <resource name="WindowCaptureMode.AeroTransparent">Pertahankan kebeningan</resource> diff --git a/Greenshot/Languages/language-it-IT.xml b/Greenshot/Languages/language-it-IT.xml index 2d9fc43e0..a2b3db147 100644 --- a/Greenshot/Languages/language-it-IT.xml +++ b/Greenshot/Languages/language-it-IT.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Se ti piace Greenshot, supportaci su:</resource> <resource name="about_host">Greenshot è disponibile nel repository GitHub</resource> <resource name="about_icons">Libreria icone del set icone Fugue di Yusuke Kamiyamane (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot viene fornito SENZA ALCUNA GARANZIA. Questo software è garuitio", e potete ri-distribuirlo secondo certe condizioni. Dettagli della General Public License GNU:</resource> diff --git a/Greenshot/Languages/language-ja-JP.xml b/Greenshot/Languages/language-ja-JP.xml index 2111930ad..c894b9573 100644 --- a/Greenshot/Languages/language-ja-JP.xml +++ b/Greenshot/Languages/language-ja-JP.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Greenshot がお気に召したなら、是非支援をお願いします :</resource> <resource name="about_host">Greenshot は GitHub によって運営されています :</resource> <resource name="about_icons">上山根 祐輔氏の Fugue Icons を使用しています (Creative Commons Attribution 3.0 license) :</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot には一切の保障がありません。GNU General Public License に定められた条件下で再配布をおこなうことができます。:</resource> <resource name="about_title">Greenshot について</resource> <resource name="application_title">Greenshot - the revolutionary screenshot utility</resource> diff --git a/Greenshot/Languages/language-kab-DZ.xml b/Greenshot/Languages/language-kab-DZ.xml index 39244e170..31930d2db 100644 --- a/Greenshot/Languages/language-kab-DZ.xml +++ b/Greenshot/Languages/language-kab-DZ.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Ma tḥemled Greenshot, Mudd-aɣ-d afus :</resource> <resource name="about_host">Greenshot yezdeɣ di sourceforge.net di</resource> <resource name="about_icons">Tignitin i d-yekkan seg uqettun n tignitin Fugue n Kamiyamane Yuusuke (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright © 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright © 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot yettunefk-d S WAR ṬMANA. d aseɣẓan ilelli i tzemreḍ ad tezuzreḍ s kra n tewtilin. Talqayt ɣef GNU General Public License :</resource> <resource name="about_title">Ɣef Greenshot</resource> diff --git a/Greenshot/Languages/language-ko-KR.xml b/Greenshot/Languages/language-ko-KR.xml index 64379ce8c..a332cea33 100644 --- a/Greenshot/Languages/language-ko-KR.xml +++ b/Greenshot/Languages/language-ko-KR.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Greenshot이 좋다면 아래 URL로 방문하셔서 지원할 수 있습니다.</resource> <resource name="about_host">Greenshot은 GitHub 관리하에 아래 링크에서 호스팅되고 있습니다</resource> <resource name="about_icons">아이콘은 Yusuke Kamiyamane's Fugue icon set으로부터 제공받은 것입니다. (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Details about the GNU General Public License:</resource> <resource name="about_title">Greenshot 프로그램 소개...</resource> diff --git a/Greenshot/Languages/language-lt-LT.xml b/Greenshot/Languages/language-lt-LT.xml index f69425916..e84388901 100644 --- a/Greenshot/Languages/language-lt-LT.xml +++ b/Greenshot/Languages/language-lt-LT.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Jei jums patiko Greenshot, galite mus paremti:</resource> <resource name="about_host">Greenshot talpinamas GitHub</resource> <resource name="about_icons">IIkonų rinkinys Fugue, аutorius Yusuke Kamiyamane, licencija Creative Commons Attribution 3.0</resource> - <resource name="about_license">Visos teisės saugomos (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Visos teisės saugomos (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot pateikiama BE JOKIŲ GARANTIJŲ. Greenshot — laisvai platinama PĮ su GPL licencija ir jūs galite laisvai ją platinti, laikydamasi licencinės sutarties:</resource> <resource name="about_title">Apie Greenshot</resource> <resource name="application_title">Greenshot — revoliucinis įrankis ekrano nuotraukoms daryti</resource> diff --git a/Greenshot/Languages/language-nl-NL.xml b/Greenshot/Languages/language-nl-NL.xml index 66601348d..507ece7dc 100644 --- a/Greenshot/Languages/language-nl-NL.xml +++ b/Greenshot/Languages/language-nl-NL.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Als Greenshot u bevalt, wilt u ons wellicht ondersteunen:</resource> <resource name="about_host">Greenshot wordt uitgegeven door sourceforge.net op</resource> <resource name="about_icons">Iconen afkomstig van Yusuke Kamiyamane's Fugue (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot komt zonder enige garantie! Dit is gratis software en het staat u vrij het onder bepaalde voorwaarden te verspreiden. Details over de GNU General Public License:</resource> <resource name="about_title">Over Greenshot</resource> diff --git a/Greenshot/Languages/language-nn-NO.xml b/Greenshot/Languages/language-nn-NO.xml index 291e1e2db..003b11b9a 100644 --- a/Greenshot/Languages/language-nn-NO.xml +++ b/Greenshot/Languages/language-nn-NO.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Om du likar Greenshot er du velkomen til å støtte oss:</resource> <resource name="about_host">Greenshot held virtuelt hus hjå GitHub:</resource> <resource name="about_icons">Ikon frå Yusuke Kamiyamane sit "Fugue" ikonsett (Creative Commons Attribution 3.0-lisens)</resource> - <resource name="about_license">Med kopirett (C) 2007-2020 Thomas Braun, Jens Klingen og Robin Krom. Norsk omsetjing av Ivar Barstad. + <resource name="about_license">Med kopirett (C) 2007-2021 Thomas Braun, Jens Klingen og Robin Krom. Norsk omsetjing av Ivar Barstad. Greenshot har ABSOLUTT INGEN GARANTI. Dette er gratis programvare, og du står fritt til å distribuere det under visse vilkår. Detaljar om GNU General Public-lisens:</resource> <resource name="about_title">Om Greenshot</resource> diff --git a/Greenshot/Languages/language-pl-PL.xml b/Greenshot/Languages/language-pl-PL.xml index ea6e96b0a..54e2fd993 100644 --- a/Greenshot/Languages/language-pl-PL.xml +++ b/Greenshot/Languages/language-pl-PL.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Jeśli podoba Ci się Greenshot, chętnie przyjmiemy Twoje wsparcie:</resource> <resource name="about_host">Greenshot jest utrzymywany przez GitHub pod adresem:</resource> <resource name="about_icons">Ikony z zestawu Fugue od Yusuke Kamiyamane (licencja Creative Commons Attribution 3.0):</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot nie jest objęty JAKĄKOLWIEK GWARANCJĄ. Jako wolne oprogramowanie może być rozpowszechniany na określonych warunkach. Szczegóły na temat Powszechnej Licencji Publicznej GNU:</resource> <resource name="about_title">O Greenshot</resource> diff --git a/Greenshot/Languages/language-pt-BR.xml b/Greenshot/Languages/language-pt-BR.xml index 4f379ae80..8bfd938ed 100644 --- a/Greenshot/Languages/language-pt-BR.xml +++ b/Greenshot/Languages/language-pt-BR.xml @@ -6,7 +6,7 @@ <resource name="about_host">O Greenshot está armazenado no GitHub em</resource> <resource name="about_icons">Ícones de Yusuke Kamiyamane (Biblioteca Fugue, licença "Creative Commons Attribution 3.0")</resource> <resource name="about_license"> - Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom O Greenshot não tem NENHUMA GARANTIA. Este software gratuito pode ser redistribuído sob algumas condições. Detalhes sobre a licença GNU: </resource> diff --git a/Greenshot/Languages/language-pt-PT.xml b/Greenshot/Languages/language-pt-PT.xml index 8e53f804b..dabc42762 100644 --- a/Greenshot/Languages/language-pt-PT.xml +++ b/Greenshot/Languages/language-pt-PT.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Se gostou do Greenshot, por favor contribua:</resource> <resource name="about_host">O Greenshot está armazenado no GitHub em</resource> <resource name="about_icons">Ícones da colecção Fugue de Yusuke Kamiyamane (Licença "Creative Commons Attribution 3.0")</resource> - <resource name="about_license">Direitos de Autor (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Direitos de Autor (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom O Greenshot não tem NENHUMA GARANTIA. Este software gratuito pode ser redistribuído sob algumas condições. Detalhes sobre a licença GNU:</resource> <resource name="about_title">Acerca do Greenshot</resource> diff --git a/Greenshot/Languages/language-ru-RU.xml b/Greenshot/Languages/language-ru-RU.xml index 9823d8bf1..42d85df80 100644 --- a/Greenshot/Languages/language-ru-RU.xml +++ b/Greenshot/Languages/language-ru-RU.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Если вам нравится Greenshot, вы можете поддержать нас:</resource> <resource name="about_host">Greenshot размещается на GitHub</resource> <resource name="about_icons">Набор иконок Yusuke Kamiyamane's Fugue (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.Это бесплатная программа и вы можете распространять её на определённых условиях. Подробно о GNU General Public License:</resource> <resource name="about_title">О программе Greenshot</resource> diff --git a/Greenshot/Languages/language-sk-SK.xml b/Greenshot/Languages/language-sk-SK.xml index 47ed2b116..f47c2bd5b 100644 --- a/Greenshot/Languages/language-sk-SK.xml +++ b/Greenshot/Languages/language-sk-SK.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Ak se vám Greenshot páči, uvítame vašu podporu:</resource> <resource name="about_host">Greenshot je na GitHub</resource> <resource name="about_icons">Ikony z Yusuke Kamiyamane's Fugue icon set (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot je ÚPLNE BEZ ZÁRUKY. Toto je FREE software, a môžete ho distribuovať za určitých podmienok. Podrobnosti o GNU General Public License:</resource> <resource name="about_title">O Greenshote</resource> diff --git a/Greenshot/Languages/language-sl-SI.xml b/Greenshot/Languages/language-sl-SI.xml index 5993e8c89..fd0dc2bc4 100644 --- a/Greenshot/Languages/language-sl-SI.xml +++ b/Greenshot/Languages/language-sl-SI.xml @@ -5,18 +5,18 @@ <resource name="about_donations">Če vam je Greenshot všeč nas prosim podprite:</resource> <resource name="about_host">Greenshot gostuje pri GitHub</resource> <resource name="about_icons">Ikone: Yusuke Kamiyamane's Fugue icon set (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Avtorske pravice (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom -Greenshot absolutno ne ponuja NOBENE GARANCIJE. Program je brezplačen in ga lahko distribuirate pod določenimi pogoji. + <resource name="about_license">Avtorske pravice (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom +Greenshot absolutno ne ponuja NOBENE GARANCIJE. Program je brezplačen in ga lahko distribuirate pod določenimi pogoji. Licenčne podrobnosti GNU General Public License:</resource> <resource name="about_title">O Greenshot-u</resource> <resource name="application_title">Greenshot - revolucija zajema zaslonskih slik</resource> <resource name="bugreport_cancel">Zapri</resource> - <resource name="bugreport_info">Oprostite, program je izvedel nepričakovano napako. - -Dobra novica je, da nam lahko pomagate pri odpravi te napake. -Prosimo obiščite spodnji URL, prijavite napako (create bug) in prilepite vsebino opisa napake. - -Prosimo dopišite še razumljiv opis kako ste prišli do težave, da jo bomo lahko ponovili. + <resource name="bugreport_info">Oprostite, program je izvedel nepričakovano napako. + +Dobra novica je, da nam lahko pomagate pri odpravi te napake. +Prosimo obiščite spodnji URL, prijavite napako (create bug) in prilepite vsebino opisa napake. + +Prosimo dopišite še razumljiv opis kako ste prišli do težave, da jo bomo lahko ponovili. Pred objavo preverite tudi ali je napaka že prijavlja s strani kakšnega drugega uporabnika. Hvala :)</resource> <resource name="bugreport_title">Napaka</resource> <resource name="CANCEL">Prekliči</resource> @@ -143,7 +143,7 @@ Pred objavo preverite tudi ali je napaka že prijavlja s strani kakšnega drugeg <resource name="EmailFormat.OUTLOOK_TXT">Outlook kot text</resource> <resource name="error">Napaka</resource> <resource name="error_multipleinstances">Greenshot že teče!</resource> - <resource name="error_nowriteaccess">Ne morem shraniti v {0}. + <resource name="error_nowriteaccess">Ne morem shraniti v {0}. Prosim preverite pravice pisanja v ta direktorij.</resource> <resource name="error_openfile">Datoteka "{0}" ne more biti odprta.</resource> <resource name="error_openlink">Ne morem odpreti povezave '{0}'.</resource> @@ -235,8 +235,8 @@ Prosim preverite pravice pisanja v ta direktorij.</resource> <resource name="update_found">Na voljo je nova verzija Greenshot-a! Ali želite prenesti Greenshot {0}?</resource> <resource name="wait_ie_capture">Prosimo počakajte - zajema se Internet Explorer...</resource> <resource name="warning">Opozorilo</resource> - <resource name="warning_hotkeys">Bližnjica "{0}" ne more biti registrirana. Težava je verjetno v tem, da nek drug program uporablja isto bližnjico ! Nastavite si drugo bližnjično tipko ali deaktivirajte bližnjice za ta program. - + <resource name="warning_hotkeys">Bližnjica "{0}" ne more biti registrirana. Težava je verjetno v tem, da nek drug program uporablja isto bližnjico ! Nastavite si drugo bližnjično tipko ali deaktivirajte bližnjice za ta program. + Vse funkcije Greenshota še vedno delujejo preko ikone za hitri zagon.</resource> <resource name="WindowCaptureMode.Aero">Uporabi lastne barve</resource> <resource name="WindowCaptureMode.AeroTransparent">Ohrani prosojnost</resource> diff --git a/Greenshot/Languages/language-sr-RS.xml b/Greenshot/Languages/language-sr-RS.xml index f26d84da6..6b624dd9c 100644 --- a/Greenshot/Languages/language-sr-RS.xml +++ b/Greenshot/Languages/language-sr-RS.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Ако вам се свиђа Гриншот, помозите нам:</resource> <resource name="about_host">Гриншот покреће Сорсфорџ (GitHub):</resource> <resource name="about_icons">Иконе су преузете из пакета „Fugue“ Јусуке Камијамане (лиценца Кријејтив комонс Ауторство 3.0)</resource> - <resource name="about_license">Ауторска права © 2007–2020 Томас Браун, Џенс Клинџен, Робин Кром + <resource name="about_license">Ауторска права © 2007–2021 Томас Браун, Џенс Клинџен, Робин Кром Гриншот се издаје БЕЗ ИКАКВЕ ГАРАНЦИЈЕ. Он је бесплатан програм, који можете да делите под одређеним условима. Више информација о ГНУ-овој општој јавној лиценци:</resource> <resource name="about_title">О програму</resource> diff --git a/Greenshot/Languages/language-sv-SE.xml b/Greenshot/Languages/language-sv-SE.xml index dedd0b5ef..3fe2df709 100644 --- a/Greenshot/Languages/language-sv-SE.xml +++ b/Greenshot/Languages/language-sv-SE.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Om du gillar Greenshot, så är du välkommen att stödja oss:</resource> <resource name="about_host">Greenshots hemsida tillhandahålls av GitHub på</resource> <resource name="about_icons">Ikoner från "Yusuke Kamiyamane's Fugue icon set" (Creative Commons Attribution 3.0 license)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot lämnar ABSOLUT INGA GARANTIER. Detta är ett gratisprogram, och du får vidaredistribuera programmet under vissa villkor. Detaljer om "GNU General Public License":</resource> <resource name="about_title">Om Greenshot</resource> diff --git a/Greenshot/Languages/language-tr-TR.xml b/Greenshot/Languages/language-tr-TR.xml index 16c5e94ed..b5a43f083 100644 --- a/Greenshot/Languages/language-tr-TR.xml +++ b/Greenshot/Languages/language-tr-TR.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Greenshot'ı sevdiyseniz, bizi destekleyin:</resource> <resource name="about_host">Greenshot GitHub üzerinde şu adreste barındırılmaktadır:</resource> <resource name="about_icons">Simgeler Yusuke Kamiyamane'nin Fugue simge setidir (Creative Commons Attribution 3.0 lisansı)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot HİÇ BİR GARANTİ vermez. Serbest bir yazılımdır ve belirli koşullar altında dağıtmakta serbestsiniz. GNU Genel Kamu Lisanslı hakkında daha fazla bilgi için:</resource> <resource name="about_title">Greenshot Hakkında</resource> diff --git a/Greenshot/Languages/language-uk-UA.xml b/Greenshot/Languages/language-uk-UA.xml index 041d73095..850a5ea7f 100644 --- a/Greenshot/Languages/language-uk-UA.xml +++ b/Greenshot/Languages/language-uk-UA.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Якщо Вам подобається Greenshot, можете підтримати нас:</resource> <resource name="about_host">Greenshot розташовується на GitHub</resource> <resource name="about_icons">Набір піктограм Fugue від Yusuke Kamiyamane (ліцензія Creative Commons Attribution 3.0)</resource> - <resource name="about_license">Авторство © 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Авторство © 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot постачається АБСОЛЮТНО БЕЗ ГАРАНТІЇ. Це вільне програмне забезпечення, Ви можете розповсюджувати його за певних умов. Подробиці Загальної Публічної Ліцензії GNU:</resource> <resource name="about_title">Про Greenshot</resource> diff --git a/Greenshot/Languages/language-vi-VN.xml b/Greenshot/Languages/language-vi-VN.xml index 541513466..a4b1a73c2 100644 --- a/Greenshot/Languages/language-vi-VN.xml +++ b/Greenshot/Languages/language-vi-VN.xml @@ -5,7 +5,7 @@ <resource name="about_donations">Hãy ủng hộ nếu bạn thấy Greenshot hữu dụng:</resource> <resource name="about_host">Greenshot được tài trợ bởi GitHub</resource> <resource name="about_icons">Dùng biểu tượng Fugue (Giấy phép Commons Attribution 3.0 license) :</resource> - <resource name="about_license">Bản quyền (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Bản quyền (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot không đi kèm theo đảm bảo nào và được phân phối dưới giấy phép GNU General Public License.</resource> <resource name="about_title">Giới thiệu Greenshot</resource> <resource name="application_title">Greenshot - Công cụ chụp màn hình</resource> diff --git a/Greenshot/Languages/language-zh-CN.xml b/Greenshot/Languages/language-zh-CN.xml index 77519c498..7325fff33 100644 --- a/Greenshot/Languages/language-zh-CN.xml +++ b/Greenshot/Languages/language-zh-CN.xml @@ -5,7 +5,7 @@ <resource name="about_donations">如果您喜欢这个软件,希望您可以捐助我们:</resource> <resource name="about_host">Greenshot 托管在 GitHub</resource> <resource name="about_icons">图标来源:Yusuke Kamiyamane的Fugue图标基于(Creative Commons Attribution 3.0 协议)</resource> - <resource name="about_license">版权所有 (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">版权所有 (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom 作者不会对程序进行任何担保。 此程序为自由软件,您可以在遵守 GNU 通用公共许可协议下任意传播本软件。 关于 GNU 通用公共许可协议:</resource> diff --git a/Greenshot/Languages/language-zh-TW.xml b/Greenshot/Languages/language-zh-TW.xml index 320db2614..590ec8f05 100644 --- a/Greenshot/Languages/language-zh-TW.xml +++ b/Greenshot/Languages/language-zh-TW.xml @@ -5,7 +5,7 @@ <resource name="about_donations">如果您喜歡 Greenshot,歡迎您支持我們:</resource> <resource name="about_host">Greenshot 的主機在 GitHub 網址是</resource> <resource name="about_icons">圖片來源: Yusuke Kamiyamane's Fugue 圖示集 (Creative Commons Attribution 3.0 授權)</resource> - <resource name="about_license">Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot 不對這個程式做任何擔保。 這個程式是自由軟體,您可以在 GNU General Public License 下任意散佈本軟體。 關於GNU General Public License 詳細資料:</resource> <resource name="about_title">關於 Greenshot</resource> diff --git a/Greenshot/Memento/AddElementMemento.cs b/Greenshot/Memento/AddElementMemento.cs index 980bb17b1..07b4f18d3 100644 --- a/Greenshot/Memento/AddElementMemento.cs +++ b/Greenshot/Memento/AddElementMemento.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Memento/AddElementsMemento.cs b/Greenshot/Memento/AddElementsMemento.cs index 91a4f4d56..1f73f2106 100644 --- a/Greenshot/Memento/AddElementsMemento.cs +++ b/Greenshot/Memento/AddElementsMemento.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/Memento/ChangeFieldHolderMemento.cs b/Greenshot/Memento/ChangeFieldHolderMemento.cs index fc94df076..225e8de20 100644 --- a/Greenshot/Memento/ChangeFieldHolderMemento.cs +++ b/Greenshot/Memento/ChangeFieldHolderMemento.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -55,18 +55,11 @@ namespace Greenshot.Memento public bool Merge(IMemento otherMemento) { - if (otherMemento is ChangeFieldHolderMemento other) - { - if (other._drawableContainer.Equals(_drawableContainer)) - { - if (other._fieldToBeChanged.Equals(_fieldToBeChanged)) - { - // Match, do not store anything as the initial state is what we want. - return true; - } - } - } - return false; + if (otherMemento is not ChangeFieldHolderMemento other) return false; + + if (!other._drawableContainer.Equals(_drawableContainer)) return false; + + return other._fieldToBeChanged.Equals(_fieldToBeChanged); } public IMemento Restore() diff --git a/Greenshot/Memento/DeleteElementMemento.cs b/Greenshot/Memento/DeleteElementMemento.cs index fd9e793b2..cf921713f 100644 --- a/Greenshot/Memento/DeleteElementMemento.cs +++ b/Greenshot/Memento/DeleteElementMemento.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -27,12 +27,12 @@ namespace Greenshot.Memento { /// The DeleteElementMemento makes it possible to undo deleting an element /// </summary> public class DeleteElementMemento : IMemento { - private IDrawableContainer drawableContainer; - private readonly Surface surface; + private IDrawableContainer _drawableContainer; + private readonly Surface _surface; public DeleteElementMemento(Surface surface, IDrawableContainer drawableContainer) { - this.surface = surface; - this.drawableContainer = drawableContainer; + _surface = surface; + _drawableContainer = drawableContainer; } public void Dispose() { @@ -40,12 +40,13 @@ namespace Greenshot.Memento { GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) { - if (disposing) { - if (drawableContainer != null) { - drawableContainer.Dispose(); - drawableContainer = null; - } + protected virtual void Dispose(bool disposing) + { + if (!disposing) return; + + if (_drawableContainer != null) { + _drawableContainer.Dispose(); + _drawableContainer = null; } } @@ -55,17 +56,17 @@ namespace Greenshot.Memento { public IMemento Restore() { // Before - drawableContainer.Invalidate(); + _drawableContainer.Invalidate(); - AddElementMemento oldState = new AddElementMemento(surface, drawableContainer); - surface.AddElement(drawableContainer, false); + var oldState = new AddElementMemento(_surface, _drawableContainer); + _surface.AddElement(_drawableContainer, false); // The container has a selected flag which represents the state at the moment it was deleted. - if (drawableContainer.Selected) { - surface.SelectElement(drawableContainer); + if (_drawableContainer.Selected) { + _surface.SelectElement(_drawableContainer); } // After - drawableContainer.Invalidate(); + _drawableContainer.Invalidate(); return oldState; } } diff --git a/Greenshot/Memento/DeleteElementsMemento.cs b/Greenshot/Memento/DeleteElementsMemento.cs index 98e3c63bf..33b0fe0ac 100644 --- a/Greenshot/Memento/DeleteElementsMemento.cs +++ b/Greenshot/Memento/DeleteElementsMemento.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -59,7 +59,7 @@ namespace Greenshot.Memento public IMemento Restore() { - AddElementsMemento oldState = new AddElementsMemento(_surface, _containerList); + var oldState = new AddElementsMemento(_surface, _containerList); _surface.AddElements(_containerList, false); // After _surface.Invalidate(); diff --git a/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs b/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs index 9d29ea05d..32870a88a 100644 --- a/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs +++ b/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -31,8 +31,8 @@ namespace Greenshot.Memento /// </summary> public class DrawableContainerBoundsChangeMemento : IMemento { - private readonly List<Point> _points = new List<Point>(); - private readonly List<Size> _sizes = new List<Size>(); + private readonly List<Point> _points = new(); + private readonly List<Size> _sizes = new(); private IDrawableContainerList _listOfdrawableContainer; private void StoreBounds() @@ -76,15 +76,14 @@ namespace Greenshot.Memento public bool Merge(IMemento otherMemento) { - if (otherMemento is DrawableContainerBoundsChangeMemento other) - { - if (ObjectExtensions.CompareLists(_listOfdrawableContainer, other._listOfdrawableContainer)) - { - // Lists are equal, as we have the state already we can ignore the new memento - return true; - } - } - return false; + if (otherMemento is not DrawableContainerBoundsChangeMemento other) return false; + + if (ObjectExtensions.CompareLists(_listOfdrawableContainer, other._listOfdrawableContainer)) + { + // Lists are equal, as we have the state already we can ignore the new memento + return true; + } + return false; } public IMemento Restore() diff --git a/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs b/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs index efece64d2..a20823878 100644 --- a/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs +++ b/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -45,18 +45,19 @@ namespace Greenshot.Memento { Dispose(true); } - protected virtual void Dispose(bool disposing) { - if (disposing) { - if (_matrix != null) { - _matrix.Dispose(); - _matrix = null; - } - if (_image != null) { - _image.Dispose(); - _image = null; - } - _surface = null; + protected virtual void Dispose(bool disposing) + { + if (!disposing) return; + + if (_matrix != null) { + _matrix.Dispose(); + _matrix = null; } + if (_image != null) { + _image.Dispose(); + _image = null; + } + _surface = null; } public bool Merge(IMemento otherMemento) { diff --git a/Greenshot/Memento/TextChangeMemento.cs b/Greenshot/Memento/TextChangeMemento.cs index a15907adb..4971b8ff0 100644 --- a/Greenshot/Memento/TextChangeMemento.cs +++ b/Greenshot/Memento/TextChangeMemento.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -27,12 +27,12 @@ namespace Greenshot.Memento { /// The TextChangeMemento makes it possible to undo-redo an IDrawableContainer move /// </summary> public class TextChangeMemento : IMemento { - private TextContainer textContainer; - private readonly string oldText; + private TextContainer _textContainer; + private readonly string _oldText; public TextChangeMemento(TextContainer textContainer) { - this.textContainer = textContainer; - oldText = textContainer.Text; + _textContainer = textContainer; + _oldText = textContainer.Text; } public void Dispose() { @@ -41,27 +41,23 @@ namespace Greenshot.Memento { protected virtual void Dispose(bool disposing) { if (disposing) { - textContainer = null; + _textContainer = null; } } public bool Merge(IMemento otherMemento) { - if (otherMemento is TextChangeMemento other) { - if (other.textContainer.Equals(textContainer)) { - // Match, do not store anything as the initial state is what we want. - return true; - } - } - return false; + if (otherMemento is not TextChangeMemento other) return false; + + return other._textContainer.Equals(_textContainer); } public IMemento Restore() { // Before - textContainer.Invalidate(); - TextChangeMemento oldState = new TextChangeMemento(textContainer); - textContainer.ChangeText(oldText, false); + _textContainer.Invalidate(); + TextChangeMemento oldState = new TextChangeMemento(_textContainer); + _textContainer.ChangeText(_oldText, false); // After - textContainer.Invalidate(); + _textContainer.Invalidate(); return oldState; } } diff --git a/Greenshot/Processors/TitleFixProcessor.cs b/Greenshot/Processors/TitleFixProcessor.cs index 7c44e218e..7bcc59f01 100644 --- a/Greenshot/Processors/TitleFixProcessor.cs +++ b/Greenshot/Processors/TitleFixProcessor.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/Greenshot/releases/innosetup/scripts/products.pas b/Greenshot/releases/innosetup/scripts/products.pas index 3fa140e54..3335007e7 100644 --- a/Greenshot/releases/innosetup/scripts/products.pas +++ b/Greenshot/releases/innosetup/scripts/products.pas @@ -251,7 +251,7 @@ begin //if SuppressibleMsgBox(FmtMessage(CustomMessage('depdownload_msg'), [FmtMessage(downloadMessage, [''])]), mbConfirmation, MB_YESNO, IDYES) = IDNO then // Result := false //else if - if isxdl_DownloadFiles(StrToInt(ExpandConstant('{wizardhwnd}'))) = 0 then + if isxdl_DownloadFiles(StrToInt(ExpandConstant('{wizardhWnd}'))) = 0 then Result := false; end; end; diff --git a/GreenshotBoxPlugin/BoxConfiguration.cs b/GreenshotBoxPlugin/BoxConfiguration.cs index 27ac67676..b8e9e0965 100644 --- a/GreenshotBoxPlugin/BoxConfiguration.cs +++ b/GreenshotBoxPlugin/BoxConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -22,6 +22,7 @@ using System.Windows.Forms; using GreenshotPlugin.Core; using System; +using GreenshotBoxPlugin.Forms; using GreenshotPlugin.IniFile; namespace GreenshotBoxPlugin { diff --git a/GreenshotBoxPlugin/BoxDestination.cs b/GreenshotBoxPlugin/BoxDestination.cs index 8cdd53515..06402ca89 100644 --- a/GreenshotBoxPlugin/BoxDestination.cs +++ b/GreenshotBoxPlugin/BoxDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotBoxPlugin/BoxEntities.cs b/GreenshotBoxPlugin/BoxEntities.cs index 23cc4a8c4..a1f1a5c61 100644 --- a/GreenshotBoxPlugin/BoxEntities.cs +++ b/GreenshotBoxPlugin/BoxEntities.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotBoxPlugin/BoxPlugin.cs b/GreenshotBoxPlugin/BoxPlugin.cs index 4848c4df2..b15835063 100644 --- a/GreenshotBoxPlugin/BoxPlugin.cs +++ b/GreenshotBoxPlugin/BoxPlugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -45,13 +45,14 @@ namespace GreenshotBoxPlugin { GC.SuppressFinalize(this); } - protected void Dispose(bool disposing) { - if (disposing) { - if (_itemPlugInConfig != null) { - _itemPlugInConfig.Dispose(); - _itemPlugInConfig = null; - } - } + protected void Dispose(bool disposing) + { + if (!disposing) return; + + if (_itemPlugInConfig == null) return; + + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; } /// <summary> diff --git a/GreenshotBoxPlugin/BoxUtils.cs b/GreenshotBoxPlugin/BoxUtils.cs index 0c5b2b10f..28bc90fb6 100644 --- a/GreenshotBoxPlugin/BoxUtils.cs +++ b/GreenshotBoxPlugin/BoxUtils.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotBoxPlugin/Forms/BoxForm.cs b/GreenshotBoxPlugin/Forms/BoxForm.cs index 7083d89d0..1ab7aed75 100644 --- a/GreenshotBoxPlugin/Forms/BoxForm.cs +++ b/GreenshotBoxPlugin/Forms/BoxForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs b/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs index 385452002..556cfe413 100644 --- a/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotBoxPlugin { +namespace GreenshotBoxPlugin.Forms { partial class SettingsForm { /// <summary> /// Designer variable used to keep track of non-visual components. diff --git a/GreenshotBoxPlugin/Forms/SettingsForm.cs b/GreenshotBoxPlugin/Forms/SettingsForm.cs index 954dc13de..49e62fd17 100644 --- a/GreenshotBoxPlugin/Forms/SettingsForm.cs +++ b/GreenshotBoxPlugin/Forms/SettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,9 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -using GreenshotBoxPlugin.Forms; - -namespace GreenshotBoxPlugin { +namespace GreenshotBoxPlugin.Forms { /// <summary> /// Description of PasswordRequestForm. /// </summary> diff --git a/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template b/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template index 253514e60..9ad35eced 100644 --- a/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template +++ b/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotBoxPlugin/LanguageKeys.cs b/GreenshotBoxPlugin/LanguageKeys.cs index 7019cdca2..6e757a01d 100644 --- a/GreenshotBoxPlugin/LanguageKeys.cs +++ b/GreenshotBoxPlugin/LanguageKeys.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotBoxPlugin/Properties/AssemblyInfo.cs b/GreenshotBoxPlugin/Properties/AssemblyInfo.cs index ce75d8750..b6b19f1c8 100644 --- a/GreenshotBoxPlugin/Properties/AssemblyInfo.cs +++ b/GreenshotBoxPlugin/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/Confluence.cs b/GreenshotConfluencePlugin/Confluence.cs index 69833cb77..bb803602c 100644 --- a/GreenshotConfluencePlugin/Confluence.cs +++ b/GreenshotConfluencePlugin/Confluence.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/ConfluenceConfiguration.cs b/GreenshotConfluencePlugin/ConfluenceConfiguration.cs index a62dcbf38..5a3e7019c 100644 --- a/GreenshotConfluencePlugin/ConfluenceConfiguration.cs +++ b/GreenshotConfluencePlugin/ConfluenceConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/ConfluenceDestination.cs b/GreenshotConfluencePlugin/ConfluenceDestination.cs index 7403495e2..d7794989a 100644 --- a/GreenshotConfluencePlugin/ConfluenceDestination.cs +++ b/GreenshotConfluencePlugin/ConfluenceDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/ConfluencePlugin.cs b/GreenshotConfluencePlugin/ConfluencePlugin.cs index 2f5ea3539..f0014f221 100644 --- a/GreenshotConfluencePlugin/ConfluencePlugin.cs +++ b/GreenshotConfluencePlugin/ConfluencePlugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/ConfluenceUtils.cs b/GreenshotConfluencePlugin/ConfluenceUtils.cs index 9b3394cc7..ccb808a0f 100644 --- a/GreenshotConfluencePlugin/ConfluenceUtils.cs +++ b/GreenshotConfluencePlugin/ConfluenceUtils.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/EnumDisplayer.cs b/GreenshotConfluencePlugin/EnumDisplayer.cs index 2e4ded768..84ca2925e 100644 --- a/GreenshotConfluencePlugin/EnumDisplayer.cs +++ b/GreenshotConfluencePlugin/EnumDisplayer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs b/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs index 8545d91a0..9269072d4 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs +++ b/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs b/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs index 7ce72fd4f..4f2723c89 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs +++ b/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs b/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs index e30ed9dc4..0702ddff7 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs +++ b/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs b/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs index b154ad357..1897a8f53 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs +++ b/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs b/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs index 86c5ff4e4..291581a2b 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs +++ b/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs b/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs index 85b380840..d4cbe59d4 100644 --- a/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs +++ b/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotConfluencePlugin/LanguageKeys.cs b/GreenshotConfluencePlugin/LanguageKeys.cs index 0caa382cb..9cd71ea8e 100644 --- a/GreenshotConfluencePlugin/LanguageKeys.cs +++ b/GreenshotConfluencePlugin/LanguageKeys.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotDropboxPlugin/DropboxDestination.cs b/GreenshotDropboxPlugin/DropboxDestination.cs index 261ead03d..57d0a1326 100644 --- a/GreenshotDropboxPlugin/DropboxDestination.cs +++ b/GreenshotDropboxPlugin/DropboxDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotDropboxPlugin/DropboxPlugin.cs b/GreenshotDropboxPlugin/DropboxPlugin.cs index 3ee7b73cc..0d3ca827d 100644 --- a/GreenshotDropboxPlugin/DropboxPlugin.cs +++ b/GreenshotDropboxPlugin/DropboxPlugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs b/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs index 1b189487b..52baabdef 100644 --- a/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs +++ b/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,6 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ using System.Windows.Forms; +using GreenshotDropboxPlugin.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; diff --git a/GreenshotDropboxPlugin/DropboxUtils.cs b/GreenshotDropboxPlugin/DropboxUtils.cs index 434cdcdcf..717b41fe3 100644 --- a/GreenshotDropboxPlugin/DropboxUtils.cs +++ b/GreenshotDropboxPlugin/DropboxUtils.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotDropboxPlugin/Forms/DropboxForm.cs b/GreenshotDropboxPlugin/Forms/DropboxForm.cs index 97c4b9d92..e0a96b5bf 100644 --- a/GreenshotDropboxPlugin/Forms/DropboxForm.cs +++ b/GreenshotDropboxPlugin/Forms/DropboxForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs b/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs index 80c0009b1..1baae2160 100644 --- a/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotDropboxPlugin { +namespace GreenshotDropboxPlugin.Forms { partial class SettingsForm { /// <summary> /// Designer variable used to keep track of non-visual components. diff --git a/GreenshotDropboxPlugin/Forms/SettingsForm.cs b/GreenshotDropboxPlugin/Forms/SettingsForm.cs index 5be2a25b2..98e1147ce 100644 --- a/GreenshotDropboxPlugin/Forms/SettingsForm.cs +++ b/GreenshotDropboxPlugin/Forms/SettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,9 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -using GreenshotDropboxPlugin.Forms; - -namespace GreenshotDropboxPlugin { +namespace GreenshotDropboxPlugin.Forms { /// <summary> /// Description of PasswordRequestForm. /// </summary> diff --git a/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template b/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template index 3baf9fb94..6a13eb6d7 100644 --- a/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template +++ b/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotDropboxPlugin/LanguageKeys.cs b/GreenshotDropboxPlugin/LanguageKeys.cs index 16cd587fb..d50660add 100644 --- a/GreenshotDropboxPlugin/LanguageKeys.cs +++ b/GreenshotDropboxPlugin/LanguageKeys.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs b/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs index 10b737886..9e9b18e04 100644 --- a/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs +++ b/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs b/GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs index aa5e76d98..f8981b820 100644 --- a/GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs +++ b/GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs b/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs index 74676182c..81575c947 100644 --- a/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs +++ b/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotExternalCommandPlugin/ExternalCommandForm.cs b/GreenshotExternalCommandPlugin/ExternalCommandForm.cs index dd42fbbe2..6436fc988 100644 --- a/GreenshotExternalCommandPlugin/ExternalCommandForm.cs +++ b/GreenshotExternalCommandPlugin/ExternalCommandForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs b/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs index 67a278a3a..13d1868d1 100644 --- a/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs +++ b/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotExternalCommandPlugin/IconCache.cs b/GreenshotExternalCommandPlugin/IconCache.cs index f510c0823..bf9094c7e 100644 --- a/GreenshotExternalCommandPlugin/IconCache.cs +++ b/GreenshotExternalCommandPlugin/IconCache.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ diff --git a/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs b/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs index 0a7ed7d7f..f0a000f9b 100644 --- a/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs +++ b/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotExternalCommandPlugin/SettingsForm.cs b/GreenshotExternalCommandPlugin/SettingsForm.cs index 7aecfb04e..01eea89bf 100644 --- a/GreenshotExternalCommandPlugin/SettingsForm.cs +++ b/GreenshotExternalCommandPlugin/SettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs b/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs index 028efa2cd..dd928449d 100644 --- a/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs +++ b/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotExternalCommandPlugin/SettingsFormDetail.cs b/GreenshotExternalCommandPlugin/SettingsFormDetail.cs index db154be58..8affd6976 100644 --- a/GreenshotExternalCommandPlugin/SettingsFormDetail.cs +++ b/GreenshotExternalCommandPlugin/SettingsFormDetail.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotFlickrPlugin/FlickrConfiguration.cs b/GreenshotFlickrPlugin/FlickrConfiguration.cs index 56b74432e..06f65c9fd 100644 --- a/GreenshotFlickrPlugin/FlickrConfiguration.cs +++ b/GreenshotFlickrPlugin/FlickrConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,6 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ using System.Windows.Forms; +using GreenshotFlickrPlugin.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; diff --git a/GreenshotFlickrPlugin/FlickrDestination.cs b/GreenshotFlickrPlugin/FlickrDestination.cs index 6cc874d29..ccd9392d2 100644 --- a/GreenshotFlickrPlugin/FlickrDestination.cs +++ b/GreenshotFlickrPlugin/FlickrDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotFlickrPlugin/FlickrPlugin.cs b/GreenshotFlickrPlugin/FlickrPlugin.cs index 524c6ad68..abf663625 100644 --- a/GreenshotFlickrPlugin/FlickrPlugin.cs +++ b/GreenshotFlickrPlugin/FlickrPlugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotFlickrPlugin/FlickrUtils.cs b/GreenshotFlickrPlugin/FlickrUtils.cs index 332a9c6e6..6713e3702 100644 --- a/GreenshotFlickrPlugin/FlickrUtils.cs +++ b/GreenshotFlickrPlugin/FlickrUtils.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotFlickrPlugin/Forms/FlickrForm.cs b/GreenshotFlickrPlugin/Forms/FlickrForm.cs index 897f20eef..94e161d64 100644 --- a/GreenshotFlickrPlugin/Forms/FlickrForm.cs +++ b/GreenshotFlickrPlugin/Forms/FlickrForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs b/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs index 498e37d18..18001eab2 100644 --- a/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotFlickrPlugin { +namespace GreenshotFlickrPlugin.Forms { partial class SettingsForm { /// <summary> /// Designer variable used to keep track of non-visual components. diff --git a/GreenshotFlickrPlugin/Forms/SettingsForm.cs b/GreenshotFlickrPlugin/Forms/SettingsForm.cs index eed62ee7d..59d0e3cbf 100644 --- a/GreenshotFlickrPlugin/Forms/SettingsForm.cs +++ b/GreenshotFlickrPlugin/Forms/SettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,9 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -using GreenshotFlickrPlugin.Forms; - -namespace GreenshotFlickrPlugin { +namespace GreenshotFlickrPlugin.Forms { /// <summary> /// Description of PasswordRequestForm. /// </summary> diff --git a/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template b/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template index 865c9e3e5..fb69e4460 100644 --- a/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template +++ b/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotFlickrPlugin/LanguageKeys.cs b/GreenshotFlickrPlugin/LanguageKeys.cs index aa08ff867..44320512b 100644 --- a/GreenshotFlickrPlugin/LanguageKeys.cs +++ b/GreenshotFlickrPlugin/LanguageKeys.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs b/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs index 6b06e2aa5..7cc8b4a3a 100644 --- a/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs +++ b/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotImgurPlugin/Forms/ImgurForm.cs b/GreenshotImgurPlugin/Forms/ImgurForm.cs index c379e49fe..37316ac99 100644 --- a/GreenshotImgurPlugin/Forms/ImgurForm.cs +++ b/GreenshotImgurPlugin/Forms/ImgurForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -21,7 +21,7 @@ using GreenshotPlugin.Controls; -namespace GreenshotImgurPlugin { +namespace GreenshotImgurPlugin.Forms { /// <summary> /// This class is needed for design-time resolving of the language files /// </summary> diff --git a/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs b/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs index 5b38b0e65..f8fb05dd2 100644 --- a/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs +++ b/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotImgurPlugin +namespace GreenshotImgurPlugin.Forms { partial class ImgurHistory { diff --git a/GreenshotImgurPlugin/Forms/ImgurHistory.cs b/GreenshotImgurPlugin/Forms/ImgurHistory.cs index cc5dc4cf1..359130a90 100644 --- a/GreenshotImgurPlugin/Forms/ImgurHistory.cs +++ b/GreenshotImgurPlugin/Forms/ImgurHistory.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,16 +18,16 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + using System; using System.Globalization; using System.Text; using System.Windows.Forms; - using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotImgurPlugin { +namespace GreenshotImgurPlugin.Forms { /// <summary> /// Imgur history form /// </summary> diff --git a/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs b/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs index 788597c39..79192da09 100644 --- a/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotImgurPlugin { +namespace GreenshotImgurPlugin.Forms { partial class SettingsForm { /// <summary> /// Designer variable used to keep track of non-visual components. diff --git a/GreenshotImgurPlugin/Forms/SettingsForm.cs b/GreenshotImgurPlugin/Forms/SettingsForm.cs index db7809a98..2ce863660 100644 --- a/GreenshotImgurPlugin/Forms/SettingsForm.cs +++ b/GreenshotImgurPlugin/Forms/SettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,9 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + using System; -namespace GreenshotImgurPlugin { +namespace GreenshotImgurPlugin.Forms { /// <summary> /// Description of PasswordRequestForm. /// </summary> diff --git a/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template b/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template index ea6d7c5ca..42dd7986f 100644 --- a/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template +++ b/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotImgurPlugin/ImgurConfiguration.cs b/GreenshotImgurPlugin/ImgurConfiguration.cs index 795814192..d487c2387 100644 --- a/GreenshotImgurPlugin/ImgurConfiguration.cs +++ b/GreenshotImgurPlugin/ImgurConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.Windows.Forms; +using GreenshotImgurPlugin.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; diff --git a/GreenshotImgurPlugin/ImgurDestination.cs b/GreenshotImgurPlugin/ImgurDestination.cs index c4d1ad445..5303ac295 100644 --- a/GreenshotImgurPlugin/ImgurDestination.cs +++ b/GreenshotImgurPlugin/ImgurDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotImgurPlugin/ImgurInfo.cs b/GreenshotImgurPlugin/ImgurInfo.cs index 08c454904..85ec5b39e 100644 --- a/GreenshotImgurPlugin/ImgurInfo.cs +++ b/GreenshotImgurPlugin/ImgurInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotImgurPlugin/ImgurPlugin.cs b/GreenshotImgurPlugin/ImgurPlugin.cs index 39cd8b9c0..d87c91f8e 100644 --- a/GreenshotImgurPlugin/ImgurPlugin.cs +++ b/GreenshotImgurPlugin/ImgurPlugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -24,6 +24,7 @@ using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; +using GreenshotImgurPlugin.Forms; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; diff --git a/GreenshotImgurPlugin/ImgurUtils.cs b/GreenshotImgurPlugin/ImgurUtils.cs index a38c12b95..ecbbf775b 100644 --- a/GreenshotImgurPlugin/ImgurUtils.cs +++ b/GreenshotImgurPlugin/ImgurUtils.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotImgurPlugin/LanguageKeys.cs b/GreenshotImgurPlugin/LanguageKeys.cs index c0aeb0295..25b3e311f 100644 --- a/GreenshotImgurPlugin/LanguageKeys.cs +++ b/GreenshotImgurPlugin/LanguageKeys.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotImgurPlugin/Properties/AssemblyInfo.cs b/GreenshotImgurPlugin/Properties/AssemblyInfo.cs index 19a2e1176..6818a420b 100644 --- a/GreenshotImgurPlugin/Properties/AssemblyInfo.cs +++ b/GreenshotImgurPlugin/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/AsyncMemoryCache.cs b/GreenshotJiraPlugin/AsyncMemoryCache.cs index 0242573e3..de2a61d04 100644 --- a/GreenshotJiraPlugin/AsyncMemoryCache.cs +++ b/GreenshotJiraPlugin/AsyncMemoryCache.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs b/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs index ac718241e..bcd10427a 100644 --- a/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs +++ b/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/Forms/JiraForm.cs b/GreenshotJiraPlugin/Forms/JiraForm.cs index 551fadadc..b9e4c3df8 100644 --- a/GreenshotJiraPlugin/Forms/JiraForm.cs +++ b/GreenshotJiraPlugin/Forms/JiraForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/Forms/JiraFormBase.cs b/GreenshotJiraPlugin/Forms/JiraFormBase.cs index 47266fda8..efc4d0201 100644 --- a/GreenshotJiraPlugin/Forms/JiraFormBase.cs +++ b/GreenshotJiraPlugin/Forms/JiraFormBase.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs b/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs index e3f26b571..0b0195cf4 100644 --- a/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/Forms/SettingsForm.cs b/GreenshotJiraPlugin/Forms/SettingsForm.cs index 5599da8ac..043df8f8b 100644 --- a/GreenshotJiraPlugin/Forms/SettingsForm.cs +++ b/GreenshotJiraPlugin/Forms/SettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/IssueTypeBitmapCache.cs b/GreenshotJiraPlugin/IssueTypeBitmapCache.cs index 2edc0ed3e..c37cee314 100644 --- a/GreenshotJiraPlugin/IssueTypeBitmapCache.cs +++ b/GreenshotJiraPlugin/IssueTypeBitmapCache.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/JiraConfiguration.cs b/GreenshotJiraPlugin/JiraConfiguration.cs index 89c4fcf9b..ba8cad80c 100644 --- a/GreenshotJiraPlugin/JiraConfiguration.cs +++ b/GreenshotJiraPlugin/JiraConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/JiraConnector.cs b/GreenshotJiraPlugin/JiraConnector.cs index 841a240d1..6bf5739fe 100644 --- a/GreenshotJiraPlugin/JiraConnector.cs +++ b/GreenshotJiraPlugin/JiraConnector.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/JiraDestination.cs b/GreenshotJiraPlugin/JiraDestination.cs index 76d2314b3..080ec8619 100644 --- a/GreenshotJiraPlugin/JiraDestination.cs +++ b/GreenshotJiraPlugin/JiraDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/JiraDetails.cs b/GreenshotJiraPlugin/JiraDetails.cs index 61f746f81..67bbc0f61 100644 --- a/GreenshotJiraPlugin/JiraDetails.cs +++ b/GreenshotJiraPlugin/JiraDetails.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub: https://github.com/greenshot diff --git a/GreenshotJiraPlugin/JiraEventArgs.cs b/GreenshotJiraPlugin/JiraEventArgs.cs index b1c4887d6..eb60e5fcf 100644 --- a/GreenshotJiraPlugin/JiraEventArgs.cs +++ b/GreenshotJiraPlugin/JiraEventArgs.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub: https://github.com/greenshot diff --git a/GreenshotJiraPlugin/JiraEventTypes.cs b/GreenshotJiraPlugin/JiraEventTypes.cs index 36866e863..37e62cab1 100644 --- a/GreenshotJiraPlugin/JiraEventTypes.cs +++ b/GreenshotJiraPlugin/JiraEventTypes.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub: https://github.com/greenshot diff --git a/GreenshotJiraPlugin/JiraMonitor.cs b/GreenshotJiraPlugin/JiraMonitor.cs index 4fcb083a7..65b73924a 100644 --- a/GreenshotJiraPlugin/JiraMonitor.cs +++ b/GreenshotJiraPlugin/JiraMonitor.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub: https://github.com/greenshot diff --git a/GreenshotJiraPlugin/JiraPlugin.cs b/GreenshotJiraPlugin/JiraPlugin.cs index 9448829c2..d58978328 100644 --- a/GreenshotJiraPlugin/JiraPlugin.cs +++ b/GreenshotJiraPlugin/JiraPlugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/LanguageKeys.cs b/GreenshotJiraPlugin/LanguageKeys.cs index 94f162dd6..d881be575 100644 --- a/GreenshotJiraPlugin/LanguageKeys.cs +++ b/GreenshotJiraPlugin/LanguageKeys.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotJiraPlugin/Log4NetLogger.cs b/GreenshotJiraPlugin/Log4NetLogger.cs index 186e7e75b..d7b8d601c 100644 --- a/GreenshotJiraPlugin/Log4NetLogger.cs +++ b/GreenshotJiraPlugin/Log4NetLogger.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/COMWrapper.cs b/GreenshotOCRCommand/COMWrapper.cs index e64824f8d..fd26cfeb9 100644 --- a/GreenshotOCRCommand/COMWrapper.cs +++ b/GreenshotOCRCommand/COMWrapper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + using System; using System.Diagnostics; using System.Reflection; @@ -26,7 +27,7 @@ using System.Runtime.Remoting; using System.Runtime.Remoting.Messaging; using System.Runtime.Remoting.Proxies; -namespace Greenshot.Interop { +namespace GreenshotOCRCommand { /// <summary> /// Wraps a late-bound COM server. /// </summary> diff --git a/GreenshotOCRCommand/ComProgIdAttribute.cs b/GreenshotOCRCommand/ComProgIdAttribute.cs index ae581d031..936ea34f9 100644 --- a/GreenshotOCRCommand/ComProgIdAttribute.cs +++ b/GreenshotOCRCommand/ComProgIdAttribute.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -21,7 +21,7 @@ using System; -namespace Greenshot.Interop { +namespace GreenshotOCRCommand { /// <summary> /// An attribute to specifiy the ProgID of the COM class to create. (As suggested by Kristen Wegner) /// </summary> diff --git a/GreenshotOCRCommand/Modi/CompressionLevel.cs b/GreenshotOCRCommand/Modi/CompressionLevel.cs index 87a3a2e7c..0cb9a4bc7 100644 --- a/GreenshotOCRCommand/Modi/CompressionLevel.cs +++ b/GreenshotOCRCommand/Modi/CompressionLevel.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Modi/FileFormat.cs b/GreenshotOCRCommand/Modi/FileFormat.cs index bd738cdaf..42c86a104 100644 --- a/GreenshotOCRCommand/Modi/FileFormat.cs +++ b/GreenshotOCRCommand/Modi/FileFormat.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,7 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotOCR +namespace GreenshotOCRCommand.Modi { public enum FileFormat { miFILE_FORMAT_DEFAULTVALUE = -1, diff --git a/GreenshotOCRCommand/Modi/ICommon.cs b/GreenshotOCRCommand/Modi/ICommon.cs index a8995c826..433fcd121 100644 --- a/GreenshotOCRCommand/Modi/ICommon.cs +++ b/GreenshotOCRCommand/Modi/ICommon.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Modi/IDispatch.cs b/GreenshotOCRCommand/Modi/IDispatch.cs index f2d5e9ed0..623feef72 100644 --- a/GreenshotOCRCommand/Modi/IDispatch.cs +++ b/GreenshotOCRCommand/Modi/IDispatch.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Modi/IDocument.cs b/GreenshotOCRCommand/Modi/IDocument.cs index 6b1d44e99..cd9098f61 100644 --- a/GreenshotOCRCommand/Modi/IDocument.cs +++ b/GreenshotOCRCommand/Modi/IDocument.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,9 +19,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -using Greenshot.Interop; -using GreenshotOCR; - namespace GreenshotOCRCommand.Modi { /// <summary> /// The MODI Document object represents an ordered collection of document images saved as a single file. diff --git a/GreenshotOCRCommand/Modi/IImage.cs b/GreenshotOCRCommand/Modi/IImage.cs index f53ffa089..5329c4eaf 100644 --- a/GreenshotOCRCommand/Modi/IImage.cs +++ b/GreenshotOCRCommand/Modi/IImage.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Modi/IImages.cs b/GreenshotOCRCommand/Modi/IImages.cs index 7eeeb6401..3c429c7d0 100644 --- a/GreenshotOCRCommand/Modi/IImages.cs +++ b/GreenshotOCRCommand/Modi/IImages.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Modi/ILayout.cs b/GreenshotOCRCommand/Modi/ILayout.cs index 2b8d8beb5..351724150 100644 --- a/GreenshotOCRCommand/Modi/ILayout.cs +++ b/GreenshotOCRCommand/Modi/ILayout.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Modi/IMiRect.cs b/GreenshotOCRCommand/Modi/IMiRect.cs index 060a838f9..3474a5e86 100644 --- a/GreenshotOCRCommand/Modi/IMiRect.cs +++ b/GreenshotOCRCommand/Modi/IMiRect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Modi/IMiRects.cs b/GreenshotOCRCommand/Modi/IMiRects.cs index b9ae99af5..e322b577d 100644 --- a/GreenshotOCRCommand/Modi/IMiRects.cs +++ b/GreenshotOCRCommand/Modi/IMiRects.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Modi/IWord.cs b/GreenshotOCRCommand/Modi/IWord.cs index f905c2617..6ba1a425b 100644 --- a/GreenshotOCRCommand/Modi/IWord.cs +++ b/GreenshotOCRCommand/Modi/IWord.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Modi/IWords.cs b/GreenshotOCRCommand/Modi/IWords.cs index 41acfb0fe..4e7243cdd 100644 --- a/GreenshotOCRCommand/Modi/IWords.cs +++ b/GreenshotOCRCommand/Modi/IWords.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Modi/ModiLanguage.cs b/GreenshotOCRCommand/Modi/ModiLanguage.cs index 89e49ed5b..b1af9f30c 100644 --- a/GreenshotOCRCommand/Modi/ModiLanguage.cs +++ b/GreenshotOCRCommand/Modi/ModiLanguage.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRCommand/Program.cs b/GreenshotOCRCommand/Program.cs index 2bd757e8d..7f1c81b09 100644 --- a/GreenshotOCRCommand/Program.cs +++ b/GreenshotOCRCommand/Program.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -23,7 +23,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using Greenshot.Interop; using GreenshotOCRCommand.Modi; namespace GreenshotOCRCommand { diff --git a/GreenshotOCRCommand/Properties/AssemblyInfo.cs b/GreenshotOCRCommand/Properties/AssemblyInfo.cs index ff10a1848..85d71c24d 100644 --- a/GreenshotOCRCommand/Properties/AssemblyInfo.cs +++ b/GreenshotOCRCommand/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRPlugin/ModiLanguage.cs b/GreenshotOCRPlugin/ModiLanguage.cs index ae531b6ab..3edd95d0f 100644 --- a/GreenshotOCRPlugin/ModiLanguage.cs +++ b/GreenshotOCRPlugin/ModiLanguage.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRPlugin/OCRConfiguration.cs b/GreenshotOCRPlugin/OCRConfiguration.cs index bee6c33e1..8eebcc91e 100644 --- a/GreenshotOCRPlugin/OCRConfiguration.cs +++ b/GreenshotOCRPlugin/OCRConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRPlugin/OCRDestination.cs b/GreenshotOCRPlugin/OCRDestination.cs index ee2dd975d..5c774bfc1 100644 --- a/GreenshotOCRPlugin/OCRDestination.cs +++ b/GreenshotOCRPlugin/OCRDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRPlugin/OCRForm.cs b/GreenshotOCRPlugin/OCRForm.cs index 299bd990a..5ba8fda84 100644 --- a/GreenshotOCRPlugin/OCRForm.cs +++ b/GreenshotOCRPlugin/OCRForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRPlugin/OCRPlugin.cs b/GreenshotOCRPlugin/OCRPlugin.cs index 96ad08135..677e22342 100644 --- a/GreenshotOCRPlugin/OCRPlugin.cs +++ b/GreenshotOCRPlugin/OCRPlugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRPlugin/SettingsForm.Designer.cs b/GreenshotOCRPlugin/SettingsForm.Designer.cs index 5b0dfe877..a9e57749a 100644 --- a/GreenshotOCRPlugin/SettingsForm.Designer.cs +++ b/GreenshotOCRPlugin/SettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOCRPlugin/SettingsForm.cs b/GreenshotOCRPlugin/SettingsForm.cs index b2c88629d..94805f941 100644 --- a/GreenshotOCRPlugin/SettingsForm.cs +++ b/GreenshotOCRPlugin/SettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -26,13 +26,13 @@ namespace GreenshotOCRPlugin { /// Description of SettingsForm. /// </summary> public partial class SettingsForm : OcrForm { - private readonly OCRConfiguration config; + private readonly OCRConfiguration _config; public SettingsForm(string [] languages, OCRConfiguration config) { // // The InitializeComponent() call is required for Windows Forms designer support. // - this.config = config; + this._config = config; InitializeComponent(); AcceptButton = buttonOK; CancelButton = buttonCancel; @@ -58,7 +58,7 @@ namespace GreenshotOCRPlugin { private void ButtonOKClick(object sender, EventArgs e) { string selectedString = (string) comboBox_languages.SelectedItem; if (selectedString != null) { - config.Language = selectedString.ToUpper(); + _config.Language = selectedString.ToUpper(); } } } diff --git a/GreenshotOfficePlugin/Destinations/ExcelDestination.cs b/GreenshotOfficePlugin/Destinations/ExcelDestination.cs index 93ea6ed85..dfd0ed7e0 100644 --- a/GreenshotOfficePlugin/Destinations/ExcelDestination.cs +++ b/GreenshotOfficePlugin/Destinations/ExcelDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/Destinations/OneNoteDestination.cs b/GreenshotOfficePlugin/Destinations/OneNoteDestination.cs index 77d3c0a03..df833c6a1 100644 --- a/GreenshotOfficePlugin/Destinations/OneNoteDestination.cs +++ b/GreenshotOfficePlugin/Destinations/OneNoteDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/Destinations/OutlookDestination.cs b/GreenshotOfficePlugin/Destinations/OutlookDestination.cs index ac88ec091..65ccf03be 100644 --- a/GreenshotOfficePlugin/Destinations/OutlookDestination.cs +++ b/GreenshotOfficePlugin/Destinations/OutlookDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs b/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs index 1000fb7d9..3e3700e4c 100644 --- a/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs +++ b/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/Destinations/WordDestination.cs b/GreenshotOfficePlugin/Destinations/WordDestination.cs index a8a80893d..a7d630d1d 100644 --- a/GreenshotOfficePlugin/Destinations/WordDestination.cs +++ b/GreenshotOfficePlugin/Destinations/WordDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficeConfiguration.cs b/GreenshotOfficePlugin/OfficeConfiguration.cs index 3971e5cd4..7064715fd 100644 --- a/GreenshotOfficePlugin/OfficeConfiguration.cs +++ b/GreenshotOfficePlugin/OfficeConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs b/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs index 75c2f23d3..40bf4255e 100644 --- a/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs +++ b/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs b/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs index b9fd2c4a9..6bc67084b 100644 --- a/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs +++ b/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs b/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs index e02908c11..00eafb5ae 100644 --- a/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs +++ b/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs b/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs index 71939296e..ad92c6743 100644 --- a/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs +++ b/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs b/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs index 611594334..5b0fcb8c5 100644 --- a/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs +++ b/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs b/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs index a0d0f54e0..40306ecf7 100644 --- a/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs +++ b/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs b/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs index a9d5632c4..7f87ff111 100644 --- a/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs +++ b/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficeExport/WordExporter.cs b/GreenshotOfficePlugin/OfficeExport/WordExporter.cs index 0132d86b0..b44f08161 100644 --- a/GreenshotOfficePlugin/OfficeExport/WordExporter.cs +++ b/GreenshotOfficePlugin/OfficeExport/WordExporter.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub: https://github.com/greenshot diff --git a/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs b/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs index 98969057f..2de5cbf71 100644 --- a/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs +++ b/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs b/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs index 6d8a992ba..03943e4db 100644 --- a/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs +++ b/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/OfficePlugin.cs b/GreenshotOfficePlugin/OfficePlugin.cs index 4e01b38fa..6a17626a8 100644 --- a/GreenshotOfficePlugin/OfficePlugin.cs +++ b/GreenshotOfficePlugin/OfficePlugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotOfficePlugin/Properties/AssemblyInfo.cs b/GreenshotOfficePlugin/Properties/AssemblyInfo.cs index 50c27e0ec..3e2563a07 100644 --- a/GreenshotOfficePlugin/Properties/AssemblyInfo.cs +++ b/GreenshotOfficePlugin/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs b/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs index 21c90f7d1..70971ca61 100644 --- a/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs +++ b/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,7 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotPhotobucketPlugin { +namespace GreenshotPhotobucketPlugin.Forms { /// <summary> /// This class is needed for design-time resolving of the language files /// </summary> diff --git a/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs b/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs index a7dcc758e..4a0486dd1 100644 --- a/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotPhotobucketPlugin { +namespace GreenshotPhotobucketPlugin.Forms { partial class SettingsForm { /// <summary> /// Designer variable used to keep track of non-visual components. diff --git a/GreenshotPhotobucketPlugin/Forms/SettingsForm.cs b/GreenshotPhotobucketPlugin/Forms/SettingsForm.cs index 056d696a9..1d221b2a9 100644 --- a/GreenshotPhotobucketPlugin/Forms/SettingsForm.cs +++ b/GreenshotPhotobucketPlugin/Forms/SettingsForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,7 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotPhotobucketPlugin { +namespace GreenshotPhotobucketPlugin.Forms { /// <summary> /// Description of PasswordRequestForm. /// </summary> diff --git a/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template b/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template index 20a033ea8..312099888 100644 --- a/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template +++ b/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPhotobucketPlugin/LanguageKeys.cs b/GreenshotPhotobucketPlugin/LanguageKeys.cs index 5c077c4ad..b94f13722 100644 --- a/GreenshotPhotobucketPlugin/LanguageKeys.cs +++ b/GreenshotPhotobucketPlugin/LanguageKeys.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs b/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs index 7b00ad768..8136adbff 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -19,6 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ using System.Windows.Forms; +using GreenshotPhotobucketPlugin.Forms; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; diff --git a/GreenshotPhotobucketPlugin/PhotobucketDestination.cs b/GreenshotPhotobucketPlugin/PhotobucketDestination.cs index 9a22488bf..96dc98926 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketDestination.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPhotobucketPlugin/PhotobucketInfo.cs b/GreenshotPhotobucketPlugin/PhotobucketInfo.cs index cf0fd0c54..b9759eb3c 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketInfo.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs b/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs index 971ccc0e6..a9670a6a2 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPhotobucketPlugin/PhotobucketUtils.cs b/GreenshotPhotobucketPlugin/PhotobucketUtils.cs index b681edac7..4226e57c4 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketUtils.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketUtils.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs b/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs index 9aa4884a4..99952c5c0 100644 --- a/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs +++ b/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPicasaPlugin/Forms/PicasaForm.cs b/GreenshotPicasaPlugin/Forms/PicasaForm.cs index a1d093e30..cea5a2f35 100644 --- a/GreenshotPicasaPlugin/Forms/PicasaForm.cs +++ b/GreenshotPicasaPlugin/Forms/PicasaForm.cs @@ -16,10 +16,11 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -using GreenshotPlugin.Controls; - -namespace GreenshotPicasaPlugin { - public class PicasaForm : GreenshotForm { - } -} + */ + +using GreenshotPlugin.Controls; + +namespace GreenshotPicasaPlugin.Forms { + public class PicasaForm : GreenshotForm { + } +} diff --git a/GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs b/GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs index 0d2447e41..38555c179 100644 --- a/GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotPicasaPlugin { +namespace GreenshotPicasaPlugin.Forms { partial class SettingsForm { /// <summary> /// Designer variable used to keep track of non-visual components. diff --git a/GreenshotPicasaPlugin/Forms/SettingsForm.cs b/GreenshotPicasaPlugin/Forms/SettingsForm.cs index 734559762..a6691a424 100644 --- a/GreenshotPicasaPlugin/Forms/SettingsForm.cs +++ b/GreenshotPicasaPlugin/Forms/SettingsForm.cs @@ -18,7 +18,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotPicasaPlugin { +namespace GreenshotPicasaPlugin.Forms { /// <summary> /// Description of PasswordRequestForm. /// </summary> diff --git a/GreenshotPicasaPlugin/GreenshotPicasaPlugin.Credentials.template b/GreenshotPicasaPlugin/GreenshotPicasaPlugin.Credentials.template index 5cb7a2aac..47172f2d4 100644 --- a/GreenshotPicasaPlugin/GreenshotPicasaPlugin.Credentials.template +++ b/GreenshotPicasaPlugin/GreenshotPicasaPlugin.Credentials.template @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPicasaPlugin/PicasaConfiguration.cs b/GreenshotPicasaPlugin/PicasaConfiguration.cs index a1372f598..202929459 100644 --- a/GreenshotPicasaPlugin/PicasaConfiguration.cs +++ b/GreenshotPicasaPlugin/PicasaConfiguration.cs @@ -20,6 +20,7 @@ using System.Windows.Forms; using GreenshotPlugin.Core; using System; +using GreenshotPicasaPlugin.Forms; using GreenshotPlugin.IniFile; namespace GreenshotPicasaPlugin { diff --git a/GreenshotPicasaPlugin/Properties/AssemblyInfo.cs b/GreenshotPicasaPlugin/Properties/AssemblyInfo.cs index 35cc458c3..3a917ddcd 100644 --- a/GreenshotPicasaPlugin/Properties/AssemblyInfo.cs +++ b/GreenshotPicasaPlugin/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/AnimatingForm.cs b/GreenshotPlugin/Controls/AnimatingForm.cs index 91f4762f0..55d6e1865 100644 --- a/GreenshotPlugin/Controls/AnimatingForm.cs +++ b/GreenshotPlugin/Controls/AnimatingForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/BackgroundForm.Designer.cs b/GreenshotPlugin/Controls/BackgroundForm.Designer.cs index fbfee52bd..cafbb6e18 100644 --- a/GreenshotPlugin/Controls/BackgroundForm.Designer.cs +++ b/GreenshotPlugin/Controls/BackgroundForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/BackgroundForm.cs b/GreenshotPlugin/Controls/BackgroundForm.cs index 5d90c6920..5ce737185 100644 --- a/GreenshotPlugin/Controls/BackgroundForm.cs +++ b/GreenshotPlugin/Controls/BackgroundForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/ExtendedWebBrowser.cs b/GreenshotPlugin/Controls/ExtendedWebBrowser.cs index 78a793866..c18a2071f 100644 --- a/GreenshotPlugin/Controls/ExtendedWebBrowser.cs +++ b/GreenshotPlugin/Controls/ExtendedWebBrowser.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/FormWithoutActivation.cs b/GreenshotPlugin/Controls/FormWithoutActivation.cs index 3fd3f8e30..4491bbf2b 100644 --- a/GreenshotPlugin/Controls/FormWithoutActivation.cs +++ b/GreenshotPlugin/Controls/FormWithoutActivation.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotButton.cs b/GreenshotPlugin/Controls/GreenshotButton.cs index 2cbee2916..16288ce43 100644 --- a/GreenshotPlugin/Controls/GreenshotButton.cs +++ b/GreenshotPlugin/Controls/GreenshotButton.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotCheckBox.cs b/GreenshotPlugin/Controls/GreenshotCheckBox.cs index 53300d5d7..e7e3483ab 100644 --- a/GreenshotPlugin/Controls/GreenshotCheckBox.cs +++ b/GreenshotPlugin/Controls/GreenshotCheckBox.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotColumnSorter.cs b/GreenshotPlugin/Controls/GreenshotColumnSorter.cs index 379d53883..efad46cd0 100644 --- a/GreenshotPlugin/Controls/GreenshotColumnSorter.cs +++ b/GreenshotPlugin/Controls/GreenshotColumnSorter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotComboBox.cs b/GreenshotPlugin/Controls/GreenshotComboBox.cs index e5245b5a2..c9f0b3d9e 100644 --- a/GreenshotPlugin/Controls/GreenshotComboBox.cs +++ b/GreenshotPlugin/Controls/GreenshotComboBox.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotForm.cs b/GreenshotPlugin/Controls/GreenshotForm.cs index 1f6ce5675..1375c0b7a 100644 --- a/GreenshotPlugin/Controls/GreenshotForm.cs +++ b/GreenshotPlugin/Controls/GreenshotForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotGroupBox.cs b/GreenshotPlugin/Controls/GreenshotGroupBox.cs index b61f64436..954027948 100644 --- a/GreenshotPlugin/Controls/GreenshotGroupBox.cs +++ b/GreenshotPlugin/Controls/GreenshotGroupBox.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotLabel.cs b/GreenshotPlugin/Controls/GreenshotLabel.cs index fa10711e0..887bdb2ea 100644 --- a/GreenshotPlugin/Controls/GreenshotLabel.cs +++ b/GreenshotPlugin/Controls/GreenshotLabel.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotRadioButton.cs b/GreenshotPlugin/Controls/GreenshotRadioButton.cs index 7ef3d41d7..ca68fb284 100644 --- a/GreenshotPlugin/Controls/GreenshotRadioButton.cs +++ b/GreenshotPlugin/Controls/GreenshotRadioButton.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotTabPage.cs b/GreenshotPlugin/Controls/GreenshotTabPage.cs index 189c9173a..6941a861a 100644 --- a/GreenshotPlugin/Controls/GreenshotTabPage.cs +++ b/GreenshotPlugin/Controls/GreenshotTabPage.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotTextBox.cs b/GreenshotPlugin/Controls/GreenshotTextBox.cs index e370c0b35..a4f743f25 100644 --- a/GreenshotPlugin/Controls/GreenshotTextBox.cs +++ b/GreenshotPlugin/Controls/GreenshotTextBox.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs b/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs index 585334a5f..e9a9edb7d 100644 --- a/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs +++ b/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotToolStripButton.cs b/GreenshotPlugin/Controls/GreenshotToolStripButton.cs index c5ffff3b0..06bf59597 100644 --- a/GreenshotPlugin/Controls/GreenshotToolStripButton.cs +++ b/GreenshotPlugin/Controls/GreenshotToolStripButton.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs b/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs index 2c7051c21..5bee42167 100644 --- a/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs +++ b/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs b/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs index 1adca374d..8547b65c8 100644 --- a/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs +++ b/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/HotkeyControl.cs b/GreenshotPlugin/Controls/HotkeyControl.cs index 89f0889b2..6e6557522 100644 --- a/GreenshotPlugin/Controls/HotkeyControl.cs +++ b/GreenshotPlugin/Controls/HotkeyControl.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs b/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs index 7211ed402..d20ed1cd1 100644 --- a/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs +++ b/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs b/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs index 7b5775a22..06237dcc9 100644 --- a/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs +++ b/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs b/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs index e8ca384a2..abf92060c 100644 --- a/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs +++ b/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/OAuthLoginForm.cs b/GreenshotPlugin/Controls/OAuthLoginForm.cs index 2b834d128..e2b036f97 100644 --- a/GreenshotPlugin/Controls/OAuthLoginForm.cs +++ b/GreenshotPlugin/Controls/OAuthLoginForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs b/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs index c308b4b07..a3ab2832b 100644 --- a/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs +++ b/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/PleaseWaitForm.cs b/GreenshotPlugin/Controls/PleaseWaitForm.cs index 995b0c17c..fecd1afc9 100644 --- a/GreenshotPlugin/Controls/PleaseWaitForm.cs +++ b/GreenshotPlugin/Controls/PleaseWaitForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/QualityDialog.Designer.cs b/GreenshotPlugin/Controls/QualityDialog.Designer.cs index eaf714d06..5f1c03fce 100644 --- a/GreenshotPlugin/Controls/QualityDialog.Designer.cs +++ b/GreenshotPlugin/Controls/QualityDialog.Designer.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/QualityDialog.cs b/GreenshotPlugin/Controls/QualityDialog.cs index ada7ad476..0e196f387 100644 --- a/GreenshotPlugin/Controls/QualityDialog.cs +++ b/GreenshotPlugin/Controls/QualityDialog.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/SaveImageFileDialog.cs b/GreenshotPlugin/Controls/SaveImageFileDialog.cs index 45f98118f..0245dc05e 100644 --- a/GreenshotPlugin/Controls/SaveImageFileDialog.cs +++ b/GreenshotPlugin/Controls/SaveImageFileDialog.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Controls/ThumbnailForm.cs b/GreenshotPlugin/Controls/ThumbnailForm.cs index 3e8256cf3..3578b63d3 100644 --- a/GreenshotPlugin/Controls/ThumbnailForm.cs +++ b/GreenshotPlugin/Controls/ThumbnailForm.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/AbstractDestination.cs b/GreenshotPlugin/Core/AbstractDestination.cs index ba9878c23..7efa0f570 100644 --- a/GreenshotPlugin/Core/AbstractDestination.cs +++ b/GreenshotPlugin/Core/AbstractDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/AbstractProcessor.cs b/GreenshotPlugin/Core/AbstractProcessor.cs index 1dce1ab16..f93a405fb 100644 --- a/GreenshotPlugin/Core/AbstractProcessor.cs +++ b/GreenshotPlugin/Core/AbstractProcessor.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/AccessibleHelper.cs b/GreenshotPlugin/Core/AccessibleHelper.cs index f6d5770b3..871892e64 100644 --- a/GreenshotPlugin/Core/AccessibleHelper.cs +++ b/GreenshotPlugin/Core/AccessibleHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -40,7 +40,7 @@ namespace GreenshotPlugin.Core { return num; } [DllImport("oleacc.dll")] - private static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject); + private static extern int AccessibleObjectFromWindow(IntPtr hWnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject); [DllImport("oleacc.dll")] private static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] object[] rgvarChildren, out int pcObtained); diff --git a/GreenshotPlugin/Core/AnimationHelpers.cs b/GreenshotPlugin/Core/AnimationHelpers.cs index cd96b890a..9ed92eef6 100644 --- a/GreenshotPlugin/Core/AnimationHelpers.cs +++ b/GreenshotPlugin/Core/AnimationHelpers.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/BinaryStructHelper.cs b/GreenshotPlugin/Core/BinaryStructHelper.cs index b8584c572..1d8af4700 100644 --- a/GreenshotPlugin/Core/BinaryStructHelper.cs +++ b/GreenshotPlugin/Core/BinaryStructHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/Cache.cs b/GreenshotPlugin/Core/Cache.cs index ae41d7d60..857f5327a 100644 --- a/GreenshotPlugin/Core/Cache.cs +++ b/GreenshotPlugin/Core/Cache.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/CaptureHandler.cs b/GreenshotPlugin/Core/CaptureHandler.cs index 4f832004a..7716b56c1 100644 --- a/GreenshotPlugin/Core/CaptureHandler.cs +++ b/GreenshotPlugin/Core/CaptureHandler.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/ClipboardHelper.cs b/GreenshotPlugin/Core/ClipboardHelper.cs index 3933ccf71..046838716 100644 --- a/GreenshotPlugin/Core/ClipboardHelper.cs +++ b/GreenshotPlugin/Core/ClipboardHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/CoreConfiguration.cs b/GreenshotPlugin/Core/CoreConfiguration.cs index 1db95dd93..15f408480 100644 --- a/GreenshotPlugin/Core/CoreConfiguration.cs +++ b/GreenshotPlugin/Core/CoreConfiguration.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/CredentialsHelper.cs b/GreenshotPlugin/Core/CredentialsHelper.cs index 7732c4f46..95426e934 100644 --- a/GreenshotPlugin/Core/CredentialsHelper.cs +++ b/GreenshotPlugin/Core/CredentialsHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -382,7 +382,7 @@ namespace GreenshotPlugin.Core { /// <param name="owner">The System.Windows.Forms.IWin32Window the dialog will display in front of.</param> private CredUi.INFO GetInfo(IWin32Window owner) { CredUi.INFO info = new CredUi.INFO(); - if (owner != null) info.hwndParent = owner.Handle; + if (owner != null) info.hWndParent = owner.Handle; info.pszCaptionText = Caption; info.pszMessageText = Message; if (Banner != null) { @@ -498,7 +498,7 @@ namespace GreenshotPlugin.Core { /// </summary> public struct INFO { public int cbSize; - public IntPtr hwndParent; + public IntPtr hWndParent; [MarshalAs(UnmanagedType.LPWStr)] public string pszMessageText; [MarshalAs(UnmanagedType.LPWStr)] public string pszCaptionText; public IntPtr hbmBanner; diff --git a/GreenshotPlugin/Core/DisplayKeyAttribute.cs b/GreenshotPlugin/Core/DisplayKeyAttribute.cs index d055b91ad..8f1b81b68 100644 --- a/GreenshotPlugin/Core/DisplayKeyAttribute.cs +++ b/GreenshotPlugin/Core/DisplayKeyAttribute.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/EnumExtensions.cs b/GreenshotPlugin/Core/EnumExtensions.cs index 39aff04f1..1bda1071f 100644 --- a/GreenshotPlugin/Core/EnumExtensions.cs +++ b/GreenshotPlugin/Core/EnumExtensions.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/Enums/HResult.cs b/GreenshotPlugin/Core/Enums/HResult.cs index 55f61aaf0..40bb62a7b 100644 --- a/GreenshotPlugin/Core/Enums/HResult.cs +++ b/GreenshotPlugin/Core/Enums/HResult.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/EventDelay.cs b/GreenshotPlugin/Core/EventDelay.cs index 84860f7ae..c00306309 100644 --- a/GreenshotPlugin/Core/EventDelay.cs +++ b/GreenshotPlugin/Core/EventDelay.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/FastBitmap.cs b/GreenshotPlugin/Core/FastBitmap.cs index a76045a42..0e52e04fb 100644 --- a/GreenshotPlugin/Core/FastBitmap.cs +++ b/GreenshotPlugin/Core/FastBitmap.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/FilenameHelper.cs b/GreenshotPlugin/Core/FilenameHelper.cs index 23fdbd9b4..5edf92afb 100644 --- a/GreenshotPlugin/Core/FilenameHelper.cs +++ b/GreenshotPlugin/Core/FilenameHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/GreenshotResources.cs b/GreenshotPlugin/Core/GreenshotResources.cs index 8f59dee91..6b80acf3f 100644 --- a/GreenshotPlugin/Core/GreenshotResources.cs +++ b/GreenshotPlugin/Core/GreenshotResources.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/HResultExtensions.cs b/GreenshotPlugin/Core/HResultExtensions.cs index bc0f8e4ba..a85bd7600 100644 --- a/GreenshotPlugin/Core/HResultExtensions.cs +++ b/GreenshotPlugin/Core/HResultExtensions.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/IEHelper.cs b/GreenshotPlugin/Core/IEHelper.cs index 703d42a15..2a85958fc 100644 --- a/GreenshotPlugin/Core/IEHelper.cs +++ b/GreenshotPlugin/Core/IEHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/IImage.cs b/GreenshotPlugin/Core/IImage.cs index 53fa64bd3..710a0d04d 100644 --- a/GreenshotPlugin/Core/IImage.cs +++ b/GreenshotPlugin/Core/IImage.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs index e5e5a1b60..b80879141 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/ImageOutput.cs b/GreenshotPlugin/Core/ImageOutput.cs index 97c8f8cf3..4388f2b59 100644 --- a/GreenshotPlugin/Core/ImageOutput.cs +++ b/GreenshotPlugin/Core/ImageOutput.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/InterfaceUtils.cs b/GreenshotPlugin/Core/InterfaceUtils.cs index b592474f0..89c8079f0 100644 --- a/GreenshotPlugin/Core/InterfaceUtils.cs +++ b/GreenshotPlugin/Core/InterfaceUtils.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/Language.cs b/GreenshotPlugin/Core/Language.cs index 31200d8ff..f5f2caa26 100644 --- a/GreenshotPlugin/Core/Language.cs +++ b/GreenshotPlugin/Core/Language.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/LogHelper.cs b/GreenshotPlugin/Core/LogHelper.cs index 1b5d8764b..c0849537e 100644 --- a/GreenshotPlugin/Core/LogHelper.cs +++ b/GreenshotPlugin/Core/LogHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/NetworkHelper.cs b/GreenshotPlugin/Core/NetworkHelper.cs index c3fcff8ab..c07208710 100644 --- a/GreenshotPlugin/Core/NetworkHelper.cs +++ b/GreenshotPlugin/Core/NetworkHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/OAuthHelper.cs b/GreenshotPlugin/Core/OAuthHelper.cs index ce059189f..5370697b6 100644 --- a/GreenshotPlugin/Core/OAuthHelper.cs +++ b/GreenshotPlugin/Core/OAuthHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/ObjectExtensions.cs b/GreenshotPlugin/Core/ObjectExtensions.cs index 491d24238..a948242b0 100644 --- a/GreenshotPlugin/Core/ObjectExtensions.cs +++ b/GreenshotPlugin/Core/ObjectExtensions.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/PluginUtils.cs b/GreenshotPlugin/Core/PluginUtils.cs index d7c1ce08b..0db458a3f 100644 --- a/GreenshotPlugin/Core/PluginUtils.cs +++ b/GreenshotPlugin/Core/PluginUtils.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/QuantizerHelper.cs b/GreenshotPlugin/Core/QuantizerHelper.cs index 0946b4385..f5396810f 100644 --- a/GreenshotPlugin/Core/QuantizerHelper.cs +++ b/GreenshotPlugin/Core/QuantizerHelper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/StringExtensions.cs b/GreenshotPlugin/Core/StringExtensions.cs index 6676500af..e7ee8cf81 100644 --- a/GreenshotPlugin/Core/StringExtensions.cs +++ b/GreenshotPlugin/Core/StringExtensions.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/SvgImage.cs b/GreenshotPlugin/Core/SvgImage.cs index 64111a7eb..d777d30ad 100644 --- a/GreenshotPlugin/Core/SvgImage.cs +++ b/GreenshotPlugin/Core/SvgImage.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/WindowCapture.cs b/GreenshotPlugin/Core/WindowCapture.cs index 7d2c9e4d3..828851444 100644 --- a/GreenshotPlugin/Core/WindowCapture.cs +++ b/GreenshotPlugin/Core/WindowCapture.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -305,7 +305,7 @@ namespace GreenshotPlugin.Core { } // get a .NET image object for it - // A suggestion for the "A generic error occurred in GDI+." E_FAIL/080004005 error is to re-try... + // A suggestion for the "A generic error occurred in GDI+." E_FAIL/0�80004005 error is to re-try... bool success = false; ExternalException exception = null; for (int i = 0; i < 3; i++) { diff --git a/GreenshotPlugin/Core/WindowDetails.cs b/GreenshotPlugin/Core/WindowDetails.cs index 4fff18959..0410d79c7 100644 --- a/GreenshotPlugin/Core/WindowDetails.cs +++ b/GreenshotPlugin/Core/WindowDetails.cs @@ -196,33 +196,33 @@ namespace GreenshotPlugin.Core /// <summary> /// Get the icon for a hWnd /// </summary> - /// <param name="hwnd"></param> + /// <param name="hWnd"></param> /// <returns></returns> - private static Icon GetAppIcon(IntPtr hwnd) { + private static Icon GetAppIcon(IntPtr hWnd) { IntPtr iconSmall = IntPtr.Zero; IntPtr iconBig = new IntPtr(1); IntPtr iconSmall2 = new IntPtr(2); IntPtr iconHandle; if (Conf.UseLargeIcons) { - iconHandle = User32.SendMessage(hwnd, (int)WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); + iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hwnd, (int)ClassLongIndex.GCL_HICON); + iconHandle = User32.GetClassLongWrapper(hWnd, (int)ClassLongIndex.GCL_HICON); } } else { - iconHandle = User32.SendMessage(hwnd, (int)WindowsMessages.WM_GETICON, iconSmall2, IntPtr.Zero); + iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconSmall2, IntPtr.Zero); } if (iconHandle == IntPtr.Zero) { - iconHandle = User32.SendMessage(hwnd, (int)WindowsMessages.WM_GETICON, iconSmall, IntPtr.Zero); + iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconSmall, IntPtr.Zero); } if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hwnd, (int)ClassLongIndex.GCL_HICONSM); + iconHandle = User32.GetClassLongWrapper(hWnd, (int)ClassLongIndex.GCL_HICONSM); } if (iconHandle == IntPtr.Zero) { - iconHandle = User32.SendMessage(hwnd, (int)WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); + iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); } if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hwnd, (int)ClassLongIndex.GCL_HICON); + iconHandle = User32.GetClassLongWrapper(hWnd, (int)ClassLongIndex.GCL_HICON); } if (iconHandle == IntPtr.Zero) { diff --git a/GreenshotPlugin/Core/WindowsEnumerator.cs b/GreenshotPlugin/Core/WindowsEnumerator.cs index 2df7fce54..3bc1095a5 100644 --- a/GreenshotPlugin/Core/WindowsEnumerator.cs +++ b/GreenshotPlugin/Core/WindowsEnumerator.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs b/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs index 755854616..e48062f57 100644 --- a/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs +++ b/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/AdjustEffect.cs b/GreenshotPlugin/Effects/AdjustEffect.cs index a3a542c53..a01dd16d2 100644 --- a/GreenshotPlugin/Effects/AdjustEffect.cs +++ b/GreenshotPlugin/Effects/AdjustEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/BorderEffect.cs b/GreenshotPlugin/Effects/BorderEffect.cs index 32822f4a9..4e45f920c 100644 --- a/GreenshotPlugin/Effects/BorderEffect.cs +++ b/GreenshotPlugin/Effects/BorderEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/DropShadowEffect.cs b/GreenshotPlugin/Effects/DropShadowEffect.cs index b1f23bf1e..5f05b889f 100644 --- a/GreenshotPlugin/Effects/DropShadowEffect.cs +++ b/GreenshotPlugin/Effects/DropShadowEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/GrayscaleEffect.cs b/GreenshotPlugin/Effects/GrayscaleEffect.cs index 8210be695..7c8e5c7b2 100644 --- a/GreenshotPlugin/Effects/GrayscaleEffect.cs +++ b/GreenshotPlugin/Effects/GrayscaleEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/IEffect.cs b/GreenshotPlugin/Effects/IEffect.cs index aee145ea4..1beeb1aa5 100644 --- a/GreenshotPlugin/Effects/IEffect.cs +++ b/GreenshotPlugin/Effects/IEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/InvertEffect.cs b/GreenshotPlugin/Effects/InvertEffect.cs index 64f44c4c6..f890f5dd5 100644 --- a/GreenshotPlugin/Effects/InvertEffect.cs +++ b/GreenshotPlugin/Effects/InvertEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/MonochromeEffect.cs b/GreenshotPlugin/Effects/MonochromeEffect.cs index 4ee358cba..8e0b69c7b 100644 --- a/GreenshotPlugin/Effects/MonochromeEffect.cs +++ b/GreenshotPlugin/Effects/MonochromeEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/ReduceColorsEffect.cs b/GreenshotPlugin/Effects/ReduceColorsEffect.cs index c82b10e71..a432850b6 100644 --- a/GreenshotPlugin/Effects/ReduceColorsEffect.cs +++ b/GreenshotPlugin/Effects/ReduceColorsEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/ResizeCanvasEffect.cs b/GreenshotPlugin/Effects/ResizeCanvasEffect.cs index 750dc41ea..67bbf6e7d 100644 --- a/GreenshotPlugin/Effects/ResizeCanvasEffect.cs +++ b/GreenshotPlugin/Effects/ResizeCanvasEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/ResizeEffect.cs b/GreenshotPlugin/Effects/ResizeEffect.cs index 528d1a0dc..38f997f71 100644 --- a/GreenshotPlugin/Effects/ResizeEffect.cs +++ b/GreenshotPlugin/Effects/ResizeEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/RotateEffect.cs b/GreenshotPlugin/Effects/RotateEffect.cs index dedab9a34..772a41a6a 100644 --- a/GreenshotPlugin/Effects/RotateEffect.cs +++ b/GreenshotPlugin/Effects/RotateEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Effects/TornEdgeEffect.cs b/GreenshotPlugin/Effects/TornEdgeEffect.cs index dbd5f5120..682435132 100644 --- a/GreenshotPlugin/Effects/TornEdgeEffect.cs +++ b/GreenshotPlugin/Effects/TornEdgeEffect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Hooking/WindowsEventHook.cs b/GreenshotPlugin/Hooking/WindowsEventHook.cs index 2b838008b..8893bd57e 100644 --- a/GreenshotPlugin/Hooking/WindowsEventHook.cs +++ b/GreenshotPlugin/Hooking/WindowsEventHook.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -39,12 +39,12 @@ namespace GreenshotPlugin.Hooking /// Used with Register hook /// </summary> /// <param name="eventType"></param> - /// <param name="hwnd"></param> + /// <param name="hWnd"></param> /// <param name="idObject"></param> /// <param name="idChild"></param> /// <param name="dwEventThread"></param> /// <param name="dwmsEventTime"></param> - public delegate void WinEventHandler(WinEvent eventType, IntPtr hwnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); + public delegate void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); /// <summary> /// Create a WindowsEventHook object @@ -65,12 +65,12 @@ namespace GreenshotPlugin.Hooking /// </summary> /// <param name="hWinEventHook"></param> /// <param name="eventType"></param> - /// <param name="hwnd"></param> + /// <param name="hWnd"></param> /// <param name="idObject"></param> /// <param name="idChild"></param> /// <param name="dwEventThread"></param> /// <param name="dwmsEventTime"></param> - private delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hwnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); + private delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); private readonly IDictionary<IntPtr, WinEventHandler> _winEventHandlers = new Dictionary<IntPtr, WinEventHandler>(); diff --git a/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs b/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs index e62cdf89a..97634b92f 100644 --- a/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs +++ b/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs b/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs index 2fbda9dce..c35dbf2e8 100644 --- a/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs +++ b/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs b/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs index fb344f237..0890cc628 100644 --- a/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs +++ b/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs b/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs index 4de30a205..cfbab4b3f 100644 --- a/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs +++ b/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument.cs b/GreenshotPlugin/IEInterop/IHTMLDocument.cs index 79f2b622a..5faeda803 100644 --- a/GreenshotPlugin/IEInterop/IHTMLDocument.cs +++ b/GreenshotPlugin/IEInterop/IHTMLDocument.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument2.cs b/GreenshotPlugin/IEInterop/IHTMLDocument2.cs index 2e0ab177f..6ca8d9c9b 100644 --- a/GreenshotPlugin/IEInterop/IHTMLDocument2.cs +++ b/GreenshotPlugin/IEInterop/IHTMLDocument2.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument3.cs b/GreenshotPlugin/IEInterop/IHTMLDocument3.cs index 74af3d8c9..e12344f62 100644 --- a/GreenshotPlugin/IEInterop/IHTMLDocument3.cs +++ b/GreenshotPlugin/IEInterop/IHTMLDocument3.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument4.cs b/GreenshotPlugin/IEInterop/IHTMLDocument4.cs index 308243eff..57e4a32ee 100644 --- a/GreenshotPlugin/IEInterop/IHTMLDocument4.cs +++ b/GreenshotPlugin/IEInterop/IHTMLDocument4.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument5.cs b/GreenshotPlugin/IEInterop/IHTMLDocument5.cs index 574edbefe..60b5aab8c 100644 --- a/GreenshotPlugin/IEInterop/IHTMLDocument5.cs +++ b/GreenshotPlugin/IEInterop/IHTMLDocument5.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLElement.cs b/GreenshotPlugin/IEInterop/IHTMLElement.cs index a7fcae716..aa0a54b79 100644 --- a/GreenshotPlugin/IEInterop/IHTMLElement.cs +++ b/GreenshotPlugin/IEInterop/IHTMLElement.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLElement2.cs b/GreenshotPlugin/IEInterop/IHTMLElement2.cs index a6d258b06..44ace8d30 100644 --- a/GreenshotPlugin/IEInterop/IHTMLElement2.cs +++ b/GreenshotPlugin/IEInterop/IHTMLElement2.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs b/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs index 3901edc30..d9a7211dc 100644 --- a/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs +++ b/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs b/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs index ac26be320..d9566c0cc 100644 --- a/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs +++ b/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs b/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs index 731ff60a4..2c651db26 100644 --- a/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs +++ b/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLRect.cs b/GreenshotPlugin/IEInterop/IHTMLRect.cs index ae398299b..c2d6d375a 100644 --- a/GreenshotPlugin/IEInterop/IHTMLRect.cs +++ b/GreenshotPlugin/IEInterop/IHTMLRect.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLScreen.cs b/GreenshotPlugin/IEInterop/IHTMLScreen.cs index 97f87124e..f65b77da7 100644 --- a/GreenshotPlugin/IEInterop/IHTMLScreen.cs +++ b/GreenshotPlugin/IEInterop/IHTMLScreen.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLScreen2.cs b/GreenshotPlugin/IEInterop/IHTMLScreen2.cs index e3c6fb5d2..3814da360 100644 --- a/GreenshotPlugin/IEInterop/IHTMLScreen2.cs +++ b/GreenshotPlugin/IEInterop/IHTMLScreen2.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs b/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs index ac618945b..fadb35ca0 100644 --- a/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs +++ b/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLStyle.cs b/GreenshotPlugin/IEInterop/IHTMLStyle.cs index 5541f0541..43d10fa84 100644 --- a/GreenshotPlugin/IEInterop/IHTMLStyle.cs +++ b/GreenshotPlugin/IEInterop/IHTMLStyle.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs b/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs index c45d4313b..f9ff8d690 100644 --- a/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs +++ b/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLWindow2.cs b/GreenshotPlugin/IEInterop/IHTMLWindow2.cs index c8846dfb4..02b2a756c 100644 --- a/GreenshotPlugin/IEInterop/IHTMLWindow2.cs +++ b/GreenshotPlugin/IEInterop/IHTMLWindow2.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLWindow3.cs b/GreenshotPlugin/IEInterop/IHTMLWindow3.cs index 6363d31ac..f3c872f5a 100644 --- a/GreenshotPlugin/IEInterop/IHTMLWindow3.cs +++ b/GreenshotPlugin/IEInterop/IHTMLWindow3.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IHTMLWindow4.cs b/GreenshotPlugin/IEInterop/IHTMLWindow4.cs index b267901a7..8643c88c1 100644 --- a/GreenshotPlugin/IEInterop/IHTMLWindow4.cs +++ b/GreenshotPlugin/IEInterop/IHTMLWindow4.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IEInterop/IWebBrowser2.cs b/GreenshotPlugin/IEInterop/IWebBrowser2.cs index 42b6c3fc1..36b06d6e4 100644 --- a/GreenshotPlugin/IEInterop/IWebBrowser2.cs +++ b/GreenshotPlugin/IEInterop/IWebBrowser2.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IniFile/IniAttributes.cs b/GreenshotPlugin/IniFile/IniAttributes.cs index 611661586..0b23b679e 100644 --- a/GreenshotPlugin/IniFile/IniAttributes.cs +++ b/GreenshotPlugin/IniFile/IniAttributes.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IniFile/IniConfig.cs b/GreenshotPlugin/IniFile/IniConfig.cs index 7981712f6..5ea33f6df 100644 --- a/GreenshotPlugin/IniFile/IniConfig.cs +++ b/GreenshotPlugin/IniFile/IniConfig.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IniFile/IniReader.cs b/GreenshotPlugin/IniFile/IniReader.cs index 6e399ab5e..641b5414e 100644 --- a/GreenshotPlugin/IniFile/IniReader.cs +++ b/GreenshotPlugin/IniFile/IniReader.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IniFile/IniSection.cs b/GreenshotPlugin/IniFile/IniSection.cs index 5022f5ab0..c8c9221dd 100644 --- a/GreenshotPlugin/IniFile/IniSection.cs +++ b/GreenshotPlugin/IniFile/IniSection.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/IniFile/IniValue.cs b/GreenshotPlugin/IniFile/IniValue.cs index 9a39ce995..de04c0b44 100644 --- a/GreenshotPlugin/IniFile/IniValue.cs +++ b/GreenshotPlugin/IniFile/IniValue.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/CaptureMode.cs b/GreenshotPlugin/Interfaces/CaptureMode.cs index a0aef56c4..8c9c9e268 100644 --- a/GreenshotPlugin/Interfaces/CaptureMode.cs +++ b/GreenshotPlugin/Interfaces/CaptureMode.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs b/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs index 5d729376c..db5319e2c 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/GreenshotPlugin/Interfaces/Drawing/Container.cs index 0044a0bb0..a97ff5ffc 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Container.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/Drawing/IField.cs b/GreenshotPlugin/Interfaces/Drawing/IField.cs index 54d083a3a..97c13c2d9 100644 --- a/GreenshotPlugin/Interfaces/Drawing/IField.cs +++ b/GreenshotPlugin/Interfaces/Drawing/IField.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs b/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs index fc10175c2..c67303ffb 100644 --- a/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs +++ b/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/Drawing/IMemento.cs b/GreenshotPlugin/Interfaces/Drawing/IMemento.cs index 40e1ab61c..bb64237fe 100644 --- a/GreenshotPlugin/Interfaces/Drawing/IMemento.cs +++ b/GreenshotPlugin/Interfaces/Drawing/IMemento.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/DrawingModes.cs b/GreenshotPlugin/Interfaces/DrawingModes.cs index 9ada15b2d..e6d25a359 100644 --- a/GreenshotPlugin/Interfaces/DrawingModes.cs +++ b/GreenshotPlugin/Interfaces/DrawingModes.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs b/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs index b499231a3..bd42b9aca 100644 --- a/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs +++ b/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/ICapture.cs b/GreenshotPlugin/Interfaces/ICapture.cs index 231af2d08..24f67a9f0 100644 --- a/GreenshotPlugin/Interfaces/ICapture.cs +++ b/GreenshotPlugin/Interfaces/ICapture.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/ICaptureDetails.cs b/GreenshotPlugin/Interfaces/ICaptureDetails.cs index 055cd598b..c475283da 100644 --- a/GreenshotPlugin/Interfaces/ICaptureDetails.cs +++ b/GreenshotPlugin/Interfaces/ICaptureDetails.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/ICaptureElement.cs b/GreenshotPlugin/Interfaces/ICaptureElement.cs index 36c0bbc72..fc84c1536 100644 --- a/GreenshotPlugin/Interfaces/ICaptureElement.cs +++ b/GreenshotPlugin/Interfaces/ICaptureElement.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/IDestination.cs b/GreenshotPlugin/Interfaces/IDestination.cs index e4f39d796..8bfb72ac3 100644 --- a/GreenshotPlugin/Interfaces/IDestination.cs +++ b/GreenshotPlugin/Interfaces/IDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/INotificationService.cs b/GreenshotPlugin/Interfaces/INotificationService.cs index c1342b5e4..43980a8e2 100644 --- a/GreenshotPlugin/Interfaces/INotificationService.cs +++ b/GreenshotPlugin/Interfaces/INotificationService.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/IProcessor.cs b/GreenshotPlugin/Interfaces/IProcessor.cs index 927933abf..d5f4c0ba8 100644 --- a/GreenshotPlugin/Interfaces/IProcessor.cs +++ b/GreenshotPlugin/Interfaces/IProcessor.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/ISurface.cs b/GreenshotPlugin/Interfaces/ISurface.cs index 068ab0f29..d6928b87e 100644 --- a/GreenshotPlugin/Interfaces/ISurface.cs +++ b/GreenshotPlugin/Interfaces/ISurface.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs b/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs index 451ffb403..4a9fd657e 100644 --- a/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs +++ b/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs b/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs index 73fa60653..c44d7f120 100644 --- a/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs +++ b/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs b/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs index 0a03f74c8..bdcc14d81 100644 --- a/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs +++ b/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs b/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs index cfc4f040a..b30a68828 100644 --- a/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs +++ b/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs b/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs index bada273cf..5582f77d3 100644 --- a/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs +++ b/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs b/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs index 296ca1a08..f53241447 100644 --- a/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs +++ b/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs b/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs index 1ae41be70..eef546545 100644 --- a/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs +++ b/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs b/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs index 44273f810..2908e9ffb 100644 --- a/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs +++ b/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs b/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs index 72ffa01a0..1bea86b37 100644 --- a/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs +++ b/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs b/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs index abae0d6f1..84efe7609 100644 --- a/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs +++ b/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs b/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs index 5f2dd1245..f9fe667f3 100644 --- a/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs +++ b/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interfaces/VerticalAlignment.cs b/GreenshotPlugin/Interfaces/VerticalAlignment.cs index 59e77f35e..f5cb71f0f 100644 --- a/GreenshotPlugin/Interfaces/VerticalAlignment.cs +++ b/GreenshotPlugin/Interfaces/VerticalAlignment.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interop/COMWrapper.cs b/GreenshotPlugin/Interop/COMWrapper.cs index 0a0dee361..f31392124 100644 --- a/GreenshotPlugin/Interop/COMWrapper.cs +++ b/GreenshotPlugin/Interop/COMWrapper.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interop/ComProgIdAttribute.cs b/GreenshotPlugin/Interop/ComProgIdAttribute.cs index 9138c1ce6..ed88fa7be 100644 --- a/GreenshotPlugin/Interop/ComProgIdAttribute.cs +++ b/GreenshotPlugin/Interop/ComProgIdAttribute.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interop/IAppVisibility.cs b/GreenshotPlugin/Interop/IAppVisibility.cs index ed6ceaf1f..2feb78b76 100644 --- a/GreenshotPlugin/Interop/IAppVisibility.cs +++ b/GreenshotPlugin/Interop/IAppVisibility.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interop/IDispatch.cs b/GreenshotPlugin/Interop/IDispatch.cs index eb9f4c918..b4391c621 100644 --- a/GreenshotPlugin/Interop/IDispatch.cs +++ b/GreenshotPlugin/Interop/IDispatch.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interop/IOleCommandTarget.cs b/GreenshotPlugin/Interop/IOleCommandTarget.cs index 3bab1bb5c..6207d196e 100644 --- a/GreenshotPlugin/Interop/IOleCommandTarget.cs +++ b/GreenshotPlugin/Interop/IOleCommandTarget.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interop/IOleWindow.cs b/GreenshotPlugin/Interop/IOleWindow.cs index 650bf6100..c5361dc0d 100644 --- a/GreenshotPlugin/Interop/IOleWindow.cs +++ b/GreenshotPlugin/Interop/IOleWindow.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -27,7 +27,7 @@ namespace GreenshotPlugin.Interop { // See: http://msdn.microsoft.com/en-us/library/ms680102%28v=vs.85%29.aspx [ComImport, Guid("00000114-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IOleWindow { - void GetWindow(out IntPtr phwnd); + void GetWindow(out IntPtr phWnd); void ContextSensitiveHelp([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode); } } diff --git a/GreenshotPlugin/Interop/IServiceProvider.cs b/GreenshotPlugin/Interop/IServiceProvider.cs index ea6a7d437..d058f81c3 100644 --- a/GreenshotPlugin/Interop/IServiceProvider.cs +++ b/GreenshotPlugin/Interop/IServiceProvider.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/Interop/IUnknown.cs b/GreenshotPlugin/Interop/IUnknown.cs index 323bbafa3..bee0da243 100644 --- a/GreenshotPlugin/Interop/IUnknown.cs +++ b/GreenshotPlugin/Interop/IUnknown.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/DWM.cs b/GreenshotPlugin/UnmanagedHelpers/DWM.cs index 0a801fe57..bc17f3ab2 100644 --- a/GreenshotPlugin/UnmanagedHelpers/DWM.cs +++ b/GreenshotPlugin/UnmanagedHelpers/DWM.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs b/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs index fdec7c001..db0185e07 100644 --- a/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs +++ b/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs index 0a8491806..e58bde613 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BB.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BB.cs index c794d251c..1541e9143 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BB.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BB.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BLURBEHIND.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BLURBEHIND.cs index f5629d9b4..29180d445 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BLURBEHIND.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BLURBEHIND.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs index 73dee612b..e442abfd5 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SYSCOLOR.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/SYSCOLOR.cs index a6c535462..7d6802081 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/SYSCOLOR.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/SYSCOLOR.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs index 5082f7e0b..b0045e3e5 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs index ed064e835..72f863e1a 100644 --- a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs index e0bbed83c..c8caf7700 100644 --- a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs +++ b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs b/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs index c877db6dd..9734806a1 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs b/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs index 94e230a57..8b77f8d97 100644 --- a/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs +++ b/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/Shell32.cs b/GreenshotPlugin/UnmanagedHelpers/Shell32.cs index cd53741a0..e1b7ba0b0 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Shell32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Shell32.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs b/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs index 2481a993c..be5d00bbc 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/User32.cs b/GreenshotPlugin/UnmanagedHelpers/User32.cs index d6ae3acb1..8ba05f48f 100644 --- a/GreenshotPlugin/UnmanagedHelpers/User32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/User32.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -109,7 +109,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { public static extern bool IsIconic(IntPtr hWnd); [DllImport("user32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsZoomed(IntPtr hwnd); + public static extern bool IsZoomed(IntPtr hWnd); [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] public static extern int GetClassName (IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); [DllImport("user32", SetLastError = true)] @@ -118,7 +118,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { public static extern IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex); [DllImport("user32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool PrintWindow(IntPtr hwnd, IntPtr hDc, uint nFlags); + public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, uint nFlags); [DllImport("user32", CharSet=CharSet.Unicode, SetLastError=true)] public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); [DllImport("user32", SetLastError = true)] @@ -181,7 +181,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); + public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow); /// uiFlags: 0 - Count of GDI objects /// uiFlags: 1 - Count of USER objects @@ -199,7 +199,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { [DllImport("user32", SetLastError = true)] private static extern bool GetPhysicalCursorPos(out POINT cursorLocation); [DllImport("user32", SetLastError=true)] - public static extern int MapWindowPoints(IntPtr hwndFrom, IntPtr hwndTo, ref POINT lpPoints, [MarshalAs(UnmanagedType.U4)] int cPoints); + public static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, ref POINT lpPoints, [MarshalAs(UnmanagedType.U4)] int cPoints); [DllImport("user32", SetLastError = true)] public static extern int GetSystemMetrics(SystemMetric index); @@ -281,28 +281,28 @@ namespace GreenshotPlugin.UnmanagedHelpers { /// <summary> /// Wrapper for the GetWindowLong which decides if the system is 64-bit or not and calls the right one. /// </summary> - /// <param name="hwnd"></param> + /// <param name="hWnd"></param> /// <param name="nIndex"></param> /// <returns></returns> - public static long GetWindowLongWrapper(IntPtr hwnd, int nIndex) { + public static long GetWindowLongWrapper(IntPtr hWnd, int nIndex) { if (IntPtr.Size == 8) { - return GetWindowLongPtr(hwnd, nIndex).ToInt64(); + return GetWindowLongPtr(hWnd, nIndex).ToInt64(); } else { - return GetWindowLong(hwnd, nIndex); + return GetWindowLong(hWnd, nIndex); } } /// <summary> /// Wrapper for the SetWindowLong which decides if the system is 64-bit or not and calls the right one. /// </summary> - /// <param name="hwnd"></param> + /// <param name="hWnd"></param> /// <param name="nIndex"></param> /// <param name="styleFlags"></param> - public static void SetWindowLongWrapper(IntPtr hwnd, int nIndex, IntPtr styleFlags) { + public static void SetWindowLongWrapper(IntPtr hWnd, int nIndex, IntPtr styleFlags) { if (IntPtr.Size == 8) { - SetWindowLongPtr(hwnd, nIndex, styleFlags); + SetWindowLongPtr(hWnd, nIndex, styleFlags); } else { - SetWindowLong(hwnd, nIndex, styleFlags.ToInt32()); + SetWindowLong(hWnd, nIndex, styleFlags.ToInt32()); } } diff --git a/GreenshotPlugin/UnmanagedHelpers/Win32.cs b/GreenshotPlugin/UnmanagedHelpers/Win32.cs index 471f38049..77aaf2256 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Win32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Win32.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs b/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs index e285418e7..551b75410 100644 --- a/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs +++ b/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs @@ -8,10 +8,10 @@ namespace GreenshotPlugin.UnmanagedHelpers /// </summary> /// <param name="hWinEventHook"></param> /// <param name="eventType"></param> - /// <param name="hwnd"></param> + /// <param name="hWnd"></param> /// <param name="idObject"></param> /// <param name="idChild"></param> /// <param name="dwEventThread"></param> /// <param name="dwmsEventTime"></param> - public delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hwnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); + public delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/WinMM.cs b/GreenshotPlugin/UnmanagedHelpers/WinMM.cs index c2e46eaa7..71e8f6b7b 100644 --- a/GreenshotPlugin/UnmanagedHelpers/WinMM.cs +++ b/GreenshotPlugin/UnmanagedHelpers/WinMM.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs b/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs index 617e18763..3bcad532d 100644 --- a/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs +++ b/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs b/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs index a01ae2216..fb52ef925 100644 --- a/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs +++ b/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotWin10Plugin/Internal/ShareInfo.cs b/GreenshotWin10Plugin/Internal/ShareInfo.cs index 9b06d0d47..7516de371 100644 --- a/GreenshotWin10Plugin/Internal/ShareInfo.cs +++ b/GreenshotWin10Plugin/Internal/ShareInfo.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs b/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs index a892e20f4..d47989c97 100644 --- a/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs +++ b/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs b/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs index a4cef4ce4..14fb4c8eb 100644 --- a/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs +++ b/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs @@ -1,5 +1,5 @@ // Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom +// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom // // For more information see: http://getgreenshot.org/ // The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs b/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs index 6cab7b81d..341153eab 100644 --- a/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs +++ b/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/GreenshotWin10Plugin/ToastNotificationService.cs index 4b41f6f61..4e3f6bc03 100644 --- a/GreenshotWin10Plugin/ToastNotificationService.cs +++ b/GreenshotWin10Plugin/ToastNotificationService.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot diff --git a/GreenshotWin10Plugin/Win10OcrProvider.cs b/GreenshotWin10Plugin/Win10OcrProvider.cs index e8187b35e..81fd442e8 100644 --- a/GreenshotWin10Plugin/Win10OcrProvider.cs +++ b/GreenshotWin10Plugin/Win10OcrProvider.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -115,7 +115,7 @@ namespace GreenshotWin10Plugin /// </summary> /// <param name="ocrResult">OcrResult</param> /// <returns>OcrInformation</returns> - private OcrInformation CreateOcrInformation(OcrResult ocrResult) + private static OcrInformation CreateOcrInformation(OcrResult ocrResult) { var result = new OcrInformation(); diff --git a/GreenshotWin10Plugin/Win10Plugin.cs b/GreenshotWin10Plugin/Win10Plugin.cs index 53344f391..dc5190bbe 100644 --- a/GreenshotWin10Plugin/Win10Plugin.cs +++ b/GreenshotWin10Plugin/Win10Plugin.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -39,17 +39,10 @@ namespace GreenshotWin10Plugin public void Dispose() { - Dispose(true); + // Nothing to dispose } - private void Dispose(bool disposing) - { - if (disposing) - { - } - } - - public void Configure() + public void Configure() { throw new NotImplementedException(); } @@ -81,6 +74,7 @@ namespace GreenshotWin10Plugin public void Shutdown() { + // Nothing to shutdown } } From 473de792ad9dba8670f8a1d3d92612c8b263c2f7 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Mon, 8 Mar 2021 22:32:29 +0100 Subject: [PATCH 085/232] BUG-2736: Fixed an issue where there Speechbubble tail is not moved when it's transformed. --- Greenshot/Drawing/SpeechbubbleContainer.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Greenshot/Drawing/SpeechbubbleContainer.cs b/Greenshot/Drawing/SpeechbubbleContainer.cs index f585af7aa..ee00714e9 100644 --- a/Greenshot/Drawing/SpeechbubbleContainer.cs +++ b/Greenshot/Drawing/SpeechbubbleContainer.cs @@ -329,5 +329,17 @@ namespace Greenshot.Drawing public override bool ClickableAt(int x, int y) { return Contains(x,y); } + + /// <summary> + /// Additional to the Transform of the TextContainer the bubble tail coordinates also need to be moved + /// </summary> + /// <param name="matrix">Matrix</param> + public override void Transform(Matrix matrix) + { + Point[] points = { TargetAdorner.Location }; + matrix.TransformPoints(points); + TargetAdorner.Location = points[0]; + base.Transform(matrix); + } } } From 4c509618af68fad3f3dec3ed9f71bf060068f2d1 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Mon, 8 Mar 2021 23:19:34 +0100 Subject: [PATCH 086/232] In #283 it was reported that Greenshot doesn't draw unicode icons correctly. this should solve it. --- Greenshot/Drawing/TextContainer.cs | 55 ++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index 4cc369dda..fda883f16 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -598,6 +598,41 @@ namespace Greenshot.Drawing DrawText(graphics, rect, lineThickness, lineColor, drawShadow, _stringFormat, text, _font); } + private static TextFormatFlags ConvertStringFormat(StringFormat stringFormat) + { + TextFormatFlags flags = TextFormatFlags.Default; + if (stringFormat == null) + { + return flags; + } + switch (stringFormat.LineAlignment) + { + case StringAlignment.Center: + flags |= TextFormatFlags.VerticalCenter; + break; + case StringAlignment.Far: + flags |= TextFormatFlags.Bottom; + break; + case StringAlignment.Near: + flags |= TextFormatFlags.Top; + break; + } + switch (stringFormat.Alignment) + { + case StringAlignment.Center: + flags |= TextFormatFlags.HorizontalCenter; + break; + case StringAlignment.Far: + flags |= TextFormatFlags.Right; + break; + case StringAlignment.Near: + flags |= TextFormatFlags.Left; + break; + } + + return flags; + } + /// <summary> /// This method can be used from other containers /// </summary> @@ -636,8 +671,8 @@ namespace Greenshot.Drawing shadowRect.Inflate(-textOffset, -textOffset); } - using Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100)); - graphics.DrawString(text, font, fontBrush, shadowRect, stringFormat); + TextRenderer.DrawText(graphics, text, font, shadowRect, Color.FromArgb(alpha, 100, 100, 100), ConvertStringFormat(stringFormat)); + currentStep++; alpha -= basealpha / steps; } @@ -647,16 +682,14 @@ namespace Greenshot.Drawing { drawingRectange.Inflate(-textOffset, -textOffset); } - using (Brush fontBrush = new SolidBrush(fontColor)) + + if (stringFormat != null) { - if (stringFormat != null) - { - graphics.DrawString(text, font, fontBrush, drawingRectange, stringFormat); - } - else - { - graphics.DrawString(text, font, fontBrush, drawingRectange); - } + TextRenderer.DrawText(graphics, text, font, drawingRectange, fontColor, ConvertStringFormat(stringFormat)); + } + else + { + TextRenderer.DrawText(graphics, text, font, drawingRectange, fontColor); } } From da2db5eae801b961d681390fa88846db5845717a Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Tue, 9 Mar 2021 22:05:26 +0100 Subject: [PATCH 087/232] BUG-2739: Bugfix for error handling. [skip ci] --- Greenshot/Forms/MainForm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index 8ff531ca0..ce6bd92af 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -1393,7 +1393,7 @@ namespace Greenshot.Forms { catch (Exception ex) { // Make sure we show what we tried to open in the exception - ex.Data.Add("path", path); + ex.Data["path"] = path; LOG.Warn("Couldn't open the path to the last exported file", ex); // No reason to create a bug-form, we just display the error. MessageBox.Show(this, ex.Message, "Opening " + path, MessageBoxButtons.OK, MessageBoxIcon.Error); From eae8f173d0ab7c8b00e763acb3f7d0b588300e59 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Wed, 10 Mar 2021 13:55:21 +0100 Subject: [PATCH 088/232] Fixed a copyright statement [skip ci] --- GreenshotWin10Plugin/Win10Configuration.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GreenshotWin10Plugin/Win10Configuration.cs b/GreenshotWin10Plugin/Win10Configuration.cs index 642296e94..ba3091909 100644 --- a/GreenshotWin10Plugin/Win10Configuration.cs +++ b/GreenshotWin10Plugin/Win10Configuration.cs @@ -1,8 +1,9 @@ /* - * A Picasa Plugin for Greenshot - * Copyright (C) 2011 Francis Noel + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From eadd1a7cac0a77854608350d4d17a00e3665625e Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Tue, 16 Mar 2021 15:56:03 +0100 Subject: [PATCH 089/232] BUG-2743: Made sure for the registry access that the default value not requested in the registry access itself, but returned if there is no value, as it will break the logic. Also there was a bug for 32 bit Windows versions. --- GreenshotPlugin/Core/EmailConfigHelper.cs | 7 ++- GreenshotPlugin/Core/RegistryKeyExtensions.cs | 49 +++++++++++++------ 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/GreenshotPlugin/Core/EmailConfigHelper.cs b/GreenshotPlugin/Core/EmailConfigHelper.cs index 354f02c33..9eb8a7bfe 100644 --- a/GreenshotPlugin/Core/EmailConfigHelper.cs +++ b/GreenshotPlugin/Core/EmailConfigHelper.cs @@ -28,16 +28,15 @@ namespace GreenshotPlugin.Core { /// </summary> public static class EmailConfigHelper { - public static string GetMapiClient() => Registry.LocalMachine.ReadKey64Or32(@"Clients\Mail"); + public static string GetMapiClient() => RegistryHive.LocalMachine.ReadKey64Or32(@"Clients\Mail"); public static bool HasMapi() { - var value = Registry.LocalMachine.ReadKey64Or32(@"Microsoft\Windows Messaging Subsystem", "MAPI", "0"); + var value = RegistryHive.LocalMachine.ReadKey64Or32(@"Microsoft\Windows Messaging Subsystem", "MAPI", "0"); return "1".Equals(value); - } - public static string GetOutlookExePath() => Registry.LocalMachine.ReadKey64Or32(@"Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"); + public static string GetOutlookExePath() => RegistryHive.LocalMachine.ReadKey64Or32(@"Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"); /// <summary> /// Check if Outlook is installed diff --git a/GreenshotPlugin/Core/RegistryKeyExtensions.cs b/GreenshotPlugin/Core/RegistryKeyExtensions.cs index 73fd66a47..bfdb63e10 100644 --- a/GreenshotPlugin/Core/RegistryKeyExtensions.cs +++ b/GreenshotPlugin/Core/RegistryKeyExtensions.cs @@ -32,36 +32,57 @@ namespace GreenshotPlugin.Core /// <summary> /// Retrieve a registry value /// </summary> - /// <param name="registryKey">RegistryKey like Registry.LocalMachine</param> + /// <param name="registryHive">RegistryHive like RegistryHive.LocalMachine</param> /// <param name="keyName">string with the name of the key</param> /// <param name="value">string with the name of the value below the key, null will retrieve the default</param> /// <param name="defaultValue">string with the default value to return</param> /// <returns>string with the value</returns> - public static string ReadKey64Or32(this RegistryKey registryKey, string keyName, string value = null, string defaultValue = null) + public static string ReadKey64Or32(this RegistryHive registryHive, string keyName, string value = null, string defaultValue = null) { string result = null; value ??= string.Empty; - if (Environment.Is64BitOperatingSystem) + + using var registryKey32 = RegistryKey.OpenBaseKey(registryHive, RegistryView.Registry32); + // Logic for 32-bit Windows is just reading the key + if (!Environment.Is64BitOperatingSystem) { - using var key = registryKey.OpenSubKey($@"SOFTWARE\{keyName}", false); - + using var key = registryKey32.OpenSubKey($@"SOFTWARE\{keyName}", false); + if (key != null) { - result = (string)key.GetValue(value, defaultValue); + result = (string)key.GetValue(value); + } + if (string.IsNullOrEmpty(result)) + { + result = defaultValue; + } + return result; + } + using var registryKey64 = RegistryKey.OpenBaseKey(registryHive, RegistryView.Registry64); + // Logic for 64 bit Windows, is trying the key which is 64 bit + using (var key = registryKey64.OpenSubKey($@"SOFTWARE\{keyName}", false)) + { + if (key != null) + { + result = (string)key.GetValue(value); + } + if (!string.IsNullOrEmpty(result)) return result; + } + + // if there is no value use the wow6432node key which is 32 bit + using (var key = registryKey32.OpenSubKey($@"SOFTWARE\{keyName}", false)) + { + if (key != null) + { + result = (string)key.GetValue(value); } } if (string.IsNullOrEmpty(result)) { - using var key = registryKey.OpenSubKey($@"SOFTWARE\wow6432node\{keyName}", false); - - if (key != null) - { - result = (string)key.GetValue(value, defaultValue); - } + result = defaultValue; } - return result; } } -} +} \ No newline at end of file From 3adf9e9a51bd5e485e50d0298f9d226db85c6173 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Thu, 18 Mar 2021 19:25:54 +0100 Subject: [PATCH 090/232] BUG-2743: Cleanup of MAPI & Outlook logic, removed the check on "HKEY_LOCAL_MACHINE\SOFTWARE(\WOW6432Node)\Microsoft\Windows Messaging Subsystem" with the MAPI value in favor of the HKEY_LOCAL_MACHINE\SOFTWARE(\WOW6432Node)\Clients\Mail where the default value contains the name, this should hopefully solve some issues. --- Greenshot/Destinations/EmailDestination.cs | 16 +++--- Greenshot/Helpers/MailHelper.cs | 10 +--- .../Destinations/OutlookDestination.cs | 24 +++++++-- GreenshotPlugin/Core/EmailConfigHelper.cs | 54 ------------------- 4 files changed, 28 insertions(+), 76 deletions(-) delete mode 100644 GreenshotPlugin/Core/EmailConfigHelper.cs diff --git a/Greenshot/Destinations/EmailDestination.cs b/Greenshot/Destinations/EmailDestination.cs index 0ba93ff59..326e27e9c 100644 --- a/Greenshot/Destinations/EmailDestination.cs +++ b/Greenshot/Destinations/EmailDestination.cs @@ -26,6 +26,7 @@ using Greenshot.Configuration; using Greenshot.Helpers; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; +using Microsoft.Win32; namespace Greenshot.Destinations { /// <summary> @@ -39,12 +40,9 @@ namespace Greenshot.Destinations { static EmailDestination() { // Logic to decide what email implementation we use - if (!EmailConfigHelper.HasMapi()) return; - - _isActiveFlag = false; - _mapiClient = EmailConfigHelper.GetMapiClient(); + _mapiClient = RegistryHive.LocalMachine.ReadKey64Or32(@"Clients\Mail"); if (!string.IsNullOrEmpty(_mapiClient)) { - // Active as we have a mapi client, can be disabled later + // Active as we have a MAPI client, can be disabled later _isActiveFlag = true; } } @@ -66,11 +64,9 @@ namespace Greenshot.Destinations { if (_isActiveFlag) { // Disable if the office plugin is installed and the client is outlook // TODO: Change this! It always creates an exception, as the plugin has not been loaded the type is not there :( - Type outlookdestination = Type.GetType("GreenshotOfficePlugin.OutlookDestination,GreenshotOfficePlugin"); - if (outlookdestination != null) { - if (_mapiClient.ToLower().Contains("microsoft outlook")) { - _isActiveFlag = false; - } + var outlookDestination = Type.GetType("GreenshotOfficePlugin.OutlookDestination,GreenshotOfficePlugin", false); + if (outlookDestination != null && _mapiClient.ToLower().Contains("microsoft outlook")) { + _isActiveFlag = false; } } return base.IsActive && _isActiveFlag; diff --git a/Greenshot/Helpers/MailHelper.cs b/Greenshot/Helpers/MailHelper.cs index 5111ba2cf..3bc09b5f8 100644 --- a/Greenshot/Helpers/MailHelper.cs +++ b/Greenshot/Helpers/MailHelper.cs @@ -80,15 +80,7 @@ namespace Greenshot.Helpers { // Store the list of currently active windows, so we can make sure we show the email window later! var windowsBefore = WindowDetails.GetVisibleWindows(); - //bool isEmailSend = false; - //if (EmailConfigHelper.HasOutlook() && (CoreConfig.OutputEMailFormat == EmailFormat.OUTLOOK_HTML || CoreConfig.OutputEMailFormat == EmailFormat.OUTLOOK_TXT)) { - // isEmailSend = OutlookExporter.ExportToOutlook(tmpFile, captureDetails); - //} - if (/*!isEmailSend &&*/ EmailConfigHelper.HasMapi()) { - // Fallback to MAPI - // Send the email - SendImage(tmpFile, captureDetails.Title); - } + SendImage(tmpFile, captureDetails.Title); WindowDetails.ActiveNewerWindows(windowsBefore); } diff --git a/GreenshotOfficePlugin/Destinations/OutlookDestination.cs b/GreenshotOfficePlugin/Destinations/OutlookDestination.cs index 65ccf03be..f08269c51 100644 --- a/GreenshotOfficePlugin/Destinations/OutlookDestination.cs +++ b/GreenshotOfficePlugin/Destinations/OutlookDestination.cs @@ -30,6 +30,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using Microsoft.Office.Interop.Outlook; +using Microsoft.Win32; namespace GreenshotOfficePlugin.Destinations { /// <summary> @@ -47,23 +48,40 @@ namespace GreenshotOfficePlugin.Destinations { private const string MapiClient = "Microsoft Outlook"; private readonly string _outlookInspectorCaption; private readonly OlObjectClass _outlookInspectorType; - private readonly OutlookEmailExporter _outlookEmailExporter = new OutlookEmailExporter(); + private readonly OutlookEmailExporter _outlookEmailExporter = new(); static OutlookDestination() { - if (EmailConfigHelper.HasOutlook()) { + if (HasOutlook()) { IsActiveFlag = true; } ExePath = PluginUtils.GetExePath("OUTLOOK.EXE"); if (ExePath != null && File.Exists(ExePath)) { WindowDetails.AddProcessToExcludeFromFreeze("outlook"); } else { - ExePath = null; + ExePath = GetOutlookExePath(); } if (ExePath == null) { IsActiveFlag = false; } } + + private static string GetOutlookExePath() => RegistryHive.LocalMachine.ReadKey64Or32(@"Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"); + + /// <summary> + /// Check if Outlook is installed + /// </summary> + /// <returns>Returns true if outlook is installed</returns> + private static bool HasOutlook() + { + string outlookPath = GetOutlookExePath(); + if (outlookPath == null) + { + return false; + } + return File.Exists(outlookPath); + } + public OutlookDestination() { } diff --git a/GreenshotPlugin/Core/EmailConfigHelper.cs b/GreenshotPlugin/Core/EmailConfigHelper.cs deleted file mode 100644 index 9eb8a7bfe..000000000 --- a/GreenshotPlugin/Core/EmailConfigHelper.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.IO; -using Microsoft.Win32; - -namespace GreenshotPlugin.Core { - /// <summary> - /// Description of EmailConfigHelper. - /// </summary> - public static class EmailConfigHelper { - - public static string GetMapiClient() => RegistryHive.LocalMachine.ReadKey64Or32(@"Clients\Mail"); - - public static bool HasMapi() - { - var value = RegistryHive.LocalMachine.ReadKey64Or32(@"Microsoft\Windows Messaging Subsystem", "MAPI", "0"); - return "1".Equals(value); - } - - public static string GetOutlookExePath() => RegistryHive.LocalMachine.ReadKey64Or32(@"Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"); - - /// <summary> - /// Check if Outlook is installed - /// </summary> - /// <returns>Returns true if outlook is installed</returns> - public static bool HasOutlook() { - string outlookPath = GetOutlookExePath(); - if (outlookPath == null) - { - return false; - } - return File.Exists(outlookPath); - } - } -} From 20e59ddd1ca81ba384e6608abf11b36c9aa2f4e1 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Thu, 18 Mar 2021 21:53:25 +0100 Subject: [PATCH 091/232] FEATURE-1110: A first step in enabling a hotkey for opening the clipboard contents in the editor. This is not visible nor configurable in the UI, but needs to be configured in the greenshot.ini, by specifying ClipboardHotkey=<hotkey> --- Greenshot/Forms/MainForm.cs | 19 +++++++++++++++++- Greenshot/Helpers/CaptureHelper.cs | 24 +++++++++++++++-------- GreenshotPlugin/Controls/HotkeyControl.cs | 10 +++++----- GreenshotPlugin/Core/CoreConfiguration.cs | 3 +++ 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index ce6bd92af..1a38839c8 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -608,6 +608,10 @@ namespace Greenshot.Forms { if (!RegisterWrapper(failedKeys, "CaptureLastRegion", "LastregionHotkey", _instance.CaptureLastRegion, ignoreFailedRegistration)) { success = false; } + if (!RegisterWrapper(failedKeys, "CaptureClipboard", "ClipboardHotkey", _instance.CaptureClipboard, true)) + { + success = false; + } if (_conf.IECapture) { if (!RegisterWrapper(failedKeys, "CaptureIE", "IEHotkey", _instance.CaptureIE, ignoreFailedRegistration)) { success = false; @@ -688,7 +692,12 @@ namespace Greenshot.Forms { contextmenu_capturewindow.ShortcutKeyDisplayString = HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.WindowHotkey); contextmenu_capturefullscreen.ShortcutKeyDisplayString = HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.FullscreenHotkey); contextmenu_captureie.ShortcutKeyDisplayString = HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.IEHotkey); - } + var clipboardHotkey = HotkeyControl.GetLocalizedHotkeyStringFromString(_conf.ClipboardHotkey); + if (!string.IsNullOrEmpty(clipboardHotkey) && !"None".Equals(clipboardHotkey)) + { + contextmenu_captureclipboard.ShortcutKeyDisplayString = clipboardHotkey; + } + } private void MainFormFormClosing(object sender, FormClosingEventArgs e) { @@ -728,6 +737,14 @@ namespace Greenshot.Forms { CaptureHelper.CaptureLastRegion(true); } + /// <summary> + /// This is used by the hotkey trigger + /// </summary> + private void CaptureClipboard() + { + CaptureHelper.CaptureClipboard(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); + } + private void CaptureIE() { if (_conf.IECapture) { CaptureHelper.CaptureIe(true, null); diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index 8b5d19bd7..19acda012 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -85,11 +85,23 @@ namespace Greenshot.Helpers { PsAPI.EmptyWorkingSet(); } } + public static void CaptureClipboard() + { + using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Clipboard); + captureHelper.MakeCapture(); + } + + public static void CaptureClipboard(IDestination destination) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Clipboard); + if (destination != null) + { + captureHelper.AddDestination(destination); + } captureHelper.MakeCapture(); } + public static void CaptureRegion(bool captureMouse) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Region, captureMouse); @@ -194,12 +206,8 @@ namespace Greenshot.Helpers { } public WindowDetails SelectedCaptureWindow { - get { - return _selectedCaptureWindow; - } - set { - _selectedCaptureWindow = value; - } + get => _selectedCaptureWindow; + set => _selectedCaptureWindow = value; } private void DoCaptureFeedback() { @@ -244,7 +252,7 @@ namespace Greenshot.Helpers { Log.Debug($"Capturing with mode {_captureMode} and using Cursor {_captureMouseCursor}"); _capture.CaptureDetails.CaptureMode = _captureMode; - // Get the windows details in a seperate thread, only for those captures that have a Feedback + // Get the windows details in a separate thread, only for those captures that have a Feedback // As currently the "elements" aren't used, we don't need them yet switch (_captureMode) { case CaptureMode.Region: @@ -270,7 +278,7 @@ namespace Greenshot.Helpers { CoreConfig.CaptureDelay = 0; } - // Capture Mousecursor if we are not loading from file or clipboard, only show when needed + // Capture Mouse cursor if we are not loading from file or clipboard, only show when needed if (_captureMode != CaptureMode.File && _captureMode != CaptureMode.Clipboard) { _capture = WindowCapture.CaptureCursor(_capture); diff --git a/GreenshotPlugin/Controls/HotkeyControl.cs b/GreenshotPlugin/Controls/HotkeyControl.cs index 6e6557522..cb9f4593a 100644 --- a/GreenshotPlugin/Controls/HotkeyControl.cs +++ b/GreenshotPlugin/Controls/HotkeyControl.cs @@ -463,10 +463,10 @@ namespace GreenshotPlugin.Controls { if (RegisterHotKey(_hotkeyHwnd, _hotKeyCounter, modifiers, (uint)virtualKeyCode)) { KeyHandlers.Add(_hotKeyCounter, handler); return _hotKeyCounter++; - } else { - Log.Warn($"Couldn't register hotkey modifier {modifierKeyCode} virtualKeyCode {virtualKeyCode}"); - return -1; } + + Log.Warn($"Couldn't register hotkey modifier {modifierKeyCode} virtualKeyCode {virtualKeyCode}"); + return -1; } public static void UnregisterHotkeys() { @@ -574,9 +574,9 @@ namespace GreenshotPlugin.Controls { visibleName = visibleName.Substring(0,1) + visibleName.Substring(1).ToLower(); } return visibleName; - } else { - return givenKey.ToString(); } + + return givenKey.ToString(); } } } \ No newline at end of file diff --git a/GreenshotPlugin/Core/CoreConfiguration.cs b/GreenshotPlugin/Core/CoreConfiguration.cs index 15f408480..bf2570ce9 100644 --- a/GreenshotPlugin/Core/CoreConfiguration.cs +++ b/GreenshotPlugin/Core/CoreConfiguration.cs @@ -74,6 +74,9 @@ namespace GreenshotPlugin.Core { public string LastregionHotkey { get; set; } [IniProperty("IEHotkey", Description="Hotkey for starting the IE capture", DefaultValue="Shift + Ctrl + PrintScreen")] public string IEHotkey { get; set; } + + [IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor")] + public string ClipboardHotkey { get; set; } [IniProperty("IsFirstLaunch", Description="Is this the first time launch?", DefaultValue="true")] public bool IsFirstLaunch { get; set; } From 96d04334ef68db1b700d78ae75602d082422184c Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Fri, 19 Mar 2021 08:42:40 +0100 Subject: [PATCH 092/232] BUG-2745: Fixed registering issue when a hotkey is not or wrongly configured. --- Greenshot/Forms/MainForm.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index 1a38839c8..4053b41f5 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -532,21 +532,26 @@ namespace Greenshot.Forms { private static bool RegisterWrapper(StringBuilder failedKeys, string functionName, string configurationKey, HotKeyHandler handler, bool ignoreFailedRegistration) { IniValue hotkeyValue = _conf.Values[configurationKey]; + var hotkeyStringValue = hotkeyValue.Value?.ToString(); + if (string.IsNullOrEmpty(hotkeyStringValue)) + { + return true; + } try { - bool success = RegisterHotkey(failedKeys, functionName, hotkeyValue.Value.ToString(), handler); + bool success = RegisterHotkey(failedKeys, functionName, hotkeyStringValue, handler); if (!success && ignoreFailedRegistration) { - LOG.DebugFormat("Ignoring failed hotkey registration for {0}, with value '{1}', resetting to 'None'.", functionName, hotkeyValue); + LOG.DebugFormat("Ignoring failed hotkey registration for {0}, with value '{1}', resetting to 'None'.", functionName, hotkeyStringValue); _conf.Values[configurationKey].Value = Keys.None.ToString(); _conf.IsDirty = true; } return success; } catch (Exception ex) { LOG.Warn(ex); - LOG.WarnFormat("Restoring default hotkey for {0}, stored under {1} from '{2}' to '{3}'", functionName, configurationKey, hotkeyValue.Value, hotkeyValue.Attributes.DefaultValue); + LOG.WarnFormat("Restoring default hotkey for {0}, stored under {1} from '{2}' to '{3}'", functionName, configurationKey, hotkeyStringValue, hotkeyValue.Attributes.DefaultValue); // when getting an exception the key wasn't found: reset the hotkey value hotkeyValue.UseValueOrDefault(null); hotkeyValue.ContainingIniSection.IsDirty = true; - return RegisterHotkey(failedKeys, functionName, hotkeyValue.Value.ToString(), handler); + return RegisterHotkey(failedKeys, functionName, hotkeyStringValue, handler); } } From a21abb1c7e9965f9a65f16b8c27868da0da87ab7 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Fri, 19 Mar 2021 19:43:16 +0100 Subject: [PATCH 093/232] Update Italian language @Lakritzator Please check and merge. Thanks. --- Greenshot/Languages/language-it-IT.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Greenshot/Languages/language-it-IT.xml b/Greenshot/Languages/language-it-IT.xml index a2b3db147..53fa10837 100644 --- a/Greenshot/Languages/language-it-IT.xml +++ b/Greenshot/Languages/language-it-IT.xml @@ -7,10 +7,10 @@ <resource name="about_icons">Libreria icone del set icone Fugue di Yusuke Kamiyamane (Creative Commons Attribution 3.0 license)</resource> <resource name="about_license">Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot viene fornito SENZA ALCUNA GARANZIA. -Questo software è garuitio", e potete ri-distribuirlo secondo certe condizioni. +Questo software è gratuito", e potete ri-distribuirlo secondo certe condizioni. Dettagli della General Public License GNU:</resource> <resource name="about_title">Info su Greenshot</resource> - <resource name="about_translation">Traduzione italiana (v. 16.08.2020) di bovirus e tonytogna</resource> + <resource name="about_translation">Traduzione italiana (v. 29.01.2021) di bovirus e tonytogna</resource> <resource name="application_title">Greenshot - Uno straordinario strumento per copiare immagini dallo schermo</resource> <resource name="bugreport_cancel">Chiudi</resource> <resource name="bugreport_info">Si è verificato un errore inaspettato. @@ -133,7 +133,7 @@ Controlla i permessi di accesso per '{0}'.</resource> <resource name="editor_match_capture_size">Adatta a dimensioni di cattura</resource> <resource name="editor_obfuscate">Offusca (O)</resource> <resource name="editor_obfuscate_blur">Sfuma</resource> - <resource name="editor_obfuscate_mode">Modalità di offuscamento</resource> + <resource name="editor_obfuscate_mode">Modalità offuscamento</resource> <resource name="editor_obfuscate_pixelize">Offusca/pixelizza</resource> <resource name="editor_object">Oggetti</resource> <resource name="editor_opendirinexplorer">Apri cartella su Windows Explorer</resource> @@ -185,7 +185,7 @@ Correggi la maschera noem file e riprova.</resource> <resource name="expertsettings_optimizeforrdp">Esegui ottimizzazioni per uso con desktop remoto</resource> <resource name="expertsettings_reuseeditorifpossible">Riutilizza se possibile la gestione immagini</resource> <resource name="expertsettings_suppresssavedialogatclose">Evita avviso di salvataggio in chiusura della gestione immagini</resource> - <resource name="expertsettings_thumbnailpreview">Visualizza anteprima finestra nel menù di contesto (Vista e Windows 7)</resource> + <resource name="expertsettings_thumbnailpreview">Visualizza anteprima finestra nel menù contestuale (Vista e Windows 7)</resource> <resource name="exported_to">Esportato in: {0}</resource> <resource name="exported_to_error">Si è verificato un errore durante l'esportazione in {0}:</resource> <resource name="help_title">Guida in linea Greenshot</resource> @@ -207,7 +207,7 @@ Correggi la maschera noem file e riprova.</resource> <resource name="printoptions_timestamp">Aggiungi data/ora nel piè di pagina</resource> <resource name="printoptions_title">Opzioni di stampa di Greenshot</resource> <resource name="qualitydialog_dontaskagain">Salva come qualità predefinita e non chiedere più</resource> - <resource name="qualitydialog_title">Qualità di Greenshot</resource> + <resource name="qualitydialog_title">Qualità Greenshot</resource> <resource name="quicksettings_destination_file">Salva direttamente (usando le impostazioni preferite file destinazione)</resource> <resource name="settings_alwaysshowprintoptionsdialog">Visualizza scelta opzioni di stampa ogni volta che stampi un'immagine</resource> <resource name="settings_alwaysshowqualitydialog">Visualizza scelta qualità ogni volta che si salva un'immagine</resource> From c303c073201d2e3100a64c57b7224119ee9b4144 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Fri, 19 Mar 2021 22:53:19 +0100 Subject: [PATCH 094/232] Updated Microsoft.Toolkit.Uwp.Notifications which brings a lot more to Greenshot [skip ci] --- .../GreenshotWin10Plugin.csproj | 2 +- .../Native/GreenshotNotificationActivator.cs | 44 ------ .../ToastNotificationService.cs | 142 ++++++++---------- 3 files changed, 67 insertions(+), 121 deletions(-) delete mode 100644 GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs diff --git a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj b/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj index 00229a0ab..2c8237637 100644 --- a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj +++ b/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj @@ -12,7 +12,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" version="6.1.1" /> + <PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" version="7.0.0" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\GreenshotPlugin\GreenshotPlugin.csproj" /> diff --git a/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs b/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs deleted file mode 100644 index d47989c97..000000000 --- a/GreenshotWin10Plugin/Native/GreenshotNotificationActivator.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Runtime.InteropServices; -using log4net; -using Microsoft.Toolkit.Uwp.Notifications; - -namespace GreenshotWin10Plugin.Native -{ - /// <summary> - /// This implements the NotificationActivator - /// </summary> - [ClassInterface(ClassInterfaceType.None)] - [ComSourceInterfaces(typeof(NotificationActivator.INotificationActivationCallback))] - [Guid("F48E86D3-E34C-4DB7-8F8F-9A0EA55F0D08"), ComVisible(true)] - public class GreenshotNotificationActivator : NotificationActivator - { - private static readonly ILog Log = LogManager.GetLogger(typeof(GreenshotNotificationActivator)); - - public override void OnActivated(string invokedArgs, NotificationUserInput userInput, string appUserModelId) - { - // TODO: Handle activation - Log.Info("Activated"); - } - } -} diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/GreenshotWin10Plugin/ToastNotificationService.cs index 4e3f6bc03..e7c932ab7 100644 --- a/GreenshotWin10Plugin/ToastNotificationService.cs +++ b/GreenshotWin10Plugin/ToastNotificationService.cs @@ -22,13 +22,12 @@ using System; using System.Drawing.Imaging; using System.IO; -using System.Linq; +using Windows.Foundation.Collections; using Windows.Foundation.Metadata; using Windows.UI.Notifications; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; -using GreenshotWin10Plugin.Native; using log4net; using Microsoft.Toolkit.Uwp.Notifications; @@ -45,10 +44,21 @@ namespace GreenshotWin10Plugin private readonly string _imageFilePath; public ToastNotificationService() { - // Register AUMID and COM server (for Desktop Bridge apps, this no-ops) - DesktopNotificationManagerCompat.RegisterAumidAndComServer<GreenshotNotificationActivator>("Greenshot"); - // Register COM server and activator type - DesktopNotificationManagerCompat.RegisterActivator<GreenshotNotificationActivator>(); + if (ToastNotificationManagerCompat.WasCurrentProcessToastActivated()) + { + Log.Info("Greenshot was activated due to a toast."); + } + // Listen to notification activation + ToastNotificationManagerCompat.OnActivated += toastArgs => + { + // Obtain the arguments from the notification + ToastArguments args = ToastArguments.Parse(toastArgs.Argument); + + // Obtain any user input (text boxes, menu selections) from the notification + ValueSet userInput = toastArgs.UserInput; + + Log.Info("Toast activated. Args: " + toastArgs.Argument); + }; var localAppData = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Greenshot"); if (!Directory.Exists(localAppData)) @@ -81,7 +91,7 @@ namespace GreenshotWin10Plugin return; } // Prepare the toast notifier. Be sure to specify the AppUserModelId on your application's shortcut! - var toastNotifier = DesktopNotificationManagerCompat.CreateToastNotifier(); + var toastNotifier = ToastNotificationManagerCompat.CreateToastNotifier(); // Here is an interesting article on reading the settings: https://www.rudyhuyn.com/blog/2018/02/10/toastnotifier-and-settings-careful-with-non-uwp-applications/ try @@ -97,82 +107,62 @@ namespace GreenshotWin10Plugin Log.Info("Ignoring exception as this means that there was no stored settings."); } - // Get a toast XML template - var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText01); + // Generate the toast and send it off + new ToastContentBuilder() - // Fill in the text elements - var stringElement = toastXml.GetElementsByTagName("text").First(); - stringElement.AppendChild(toastXml.CreateTextNode(message)); - - if (_imageFilePath != null && File.Exists(_imageFilePath)) - { - // Specify the absolute path to an image - var imageElement = toastXml.GetElementsByTagName("image").First(); - var imageSrcNode = imageElement.Attributes.GetNamedItem("src"); - if (imageSrcNode != null) + .AddArgument("ToastID", 100) + // Inline image + .AddText(message) + // Profile (app logo override) image + //.AddAppLogoOverride(new Uri($@"file://{_imageFilePath}"), ToastGenericAppLogoCrop.None) + .Show(toast => { - imageSrcNode.NodeValue = _imageFilePath; - } - } + // Windows 10 first with 1903: ExpiresOnReboot = true + toast.ExpirationTime = timeout.HasValue ? DateTimeOffset.Now.Add(timeout.Value) : (DateTimeOffset?) null; + void ToastActivatedHandler(ToastNotification toastNotification, object sender) + { + try + { + onClickAction?.Invoke(); + } + catch (Exception ex) + { + Log.Warn("Exception while handling the onclick action: ", ex); + } - // Create the toast and attach event listeners - var toast = new ToastNotification(toastXml) - { - // Windows 10 first with 1903: ExpiresOnReboot = true, - ExpirationTime = timeout.HasValue ? DateTimeOffset.Now.Add(timeout.Value) : (DateTimeOffset?)null - }; + toast.Activated -= ToastActivatedHandler; + } - void ToastActivatedHandler(ToastNotification toastNotification, object sender) - { - try - { - onClickAction?.Invoke(); - } - catch (Exception ex) - { - Log.Warn("Exception while handling the onclick action: ", ex); - } + if (onClickAction != null) + { + toast.Activated += ToastActivatedHandler; + } - toast.Activated -= ToastActivatedHandler; - } + void ToastDismissedHandler(ToastNotification toastNotification, ToastDismissedEventArgs eventArgs) + { + Log.Debug($"Toast closed with reason {eventArgs.Reason}"); + if (eventArgs.Reason != ToastDismissalReason.UserCanceled) + { + return; + } + try + { + onClosedAction?.Invoke(); + } + catch (Exception ex) + { + Log.Warn("Exception while handling the onClosed action: ", ex); + } - if (onClickAction != null) - { - toast.Activated += ToastActivatedHandler; - } + toast.Dismissed -= ToastDismissedHandler; + // Remove the other handler too + toast.Activated -= ToastActivatedHandler; + toast.Failed -= ToastOnFailed; - void ToastDismissedHandler(ToastNotification toastNotification, ToastDismissedEventArgs eventArgs) - { - Log.Debug($"Toast closed with reason {eventArgs.Reason}"); - if (eventArgs.Reason != ToastDismissalReason.UserCanceled) - { - return; - } - try - { - onClosedAction?.Invoke(); - } - catch (Exception ex) - { - Log.Warn("Exception while handling the onClosed action: ", ex); - } - - toast.Dismissed -= ToastDismissedHandler; - // Remove the other handler too - toast.Activated -= ToastActivatedHandler; - toast.Failed -= ToastOnFailed; - - } - toast.Dismissed += ToastDismissedHandler; - toast.Failed += ToastOnFailed; - try - { - toastNotifier.Show(toast); - } - catch (Exception ex) - { - Log.Error("Couldn't show notification.", ex); - } + } + toast.Dismissed += ToastDismissedHandler; + toast.Failed += ToastOnFailed; + }); } private void ToastOnFailed(ToastNotification sender, ToastFailedEventArgs args) From 33defa6165d462ded81e9ad1912ed50c86ec20da Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Sat, 20 Mar 2021 11:55:39 +0100 Subject: [PATCH 095/232] Update Help (IT) @Lakritzator Please check and merge. Thanks. --- Greenshot/Languages/help-it-IT.html | 332 ++++++++++++---------------- 1 file changed, 146 insertions(+), 186 deletions(-) diff --git a/Greenshot/Languages/help-it-IT.html b/Greenshot/Languages/help-it-IT.html index 1d5744287..14c135e67 100644 --- a/Greenshot/Languages/help-it-IT.html +++ b/Greenshot/Languages/help-it-IT.html @@ -1,4 +1,4 @@ -<!-- saved from url=(0022)http://internet.e-mail --> +<!-- saved from url=(0022)http://internet.e-mail --> <html> <head> @@ -35,68 +35,62 @@ <li><a href="#capture-last-region">Cattura ultima regione</a></li> <li><a href="#capture-window">Cattura finestra</a></li> <li><a href="#capture-fullscreen">Cattura schermo intero</a></li> - <li><a href="#capture-ie">Cattura Internet Explorer</a></li> + <li><a href="#capture-ie">Cattura con Internet Explorer</a></li> </ol> - <li><a href="#editor">Uso della Gestione Immagini</a></li> + <li><a href="#editor">Uso gestione immagini</a></li> <ol> - <li><a href="#editor-shapes">Disegnare forme</a></li> - <li><a href="#editor-text">Aggiungere testo</a></li> - <li><a href="#editor-highlight">Evidenziare qualcosa</a></li> - <li><a href="#editor-obfuscate">Offuscare qualcosa</a></li> - <li><a href="#editor-crop">Ritagliare l'immagine</a></li> - <li><a href="#editor-adding-graphics">Aggiungere elementi grafici all'immagine</a></li> - <li><a href="#editor-reuse-elements">Riutilizzare gli elementi disegnati</a></li> - <li><a href="#editor-export">Esportare l'immagine</a></li> + <li><a href="#editor-shapes">Disegna forme</a></li> + <li><a href="#editor-text">Aggiungi testo</a></li> + <li><a href="#editor-highlight">Evidenzia qualcosa</a></li> + <li><a href="#editor-obfuscate">Offusca qualcosa\</a></li> + <li><a href="#editor-crop">Ritaglia immagine</a></li> + <li><a href="#editor-adding-graphics">Aggiungi elementi grafici all'immagine</a></li> + <li><a href="#editor-reuse-elements">Riusa elementi disegnati</a></li> + <li><a href="#editor-export">Esporta immagine</a></li> </ol> - <li><a href="#settings">La pagina delle Impostazioni</a></li> + <li><a href="#settings">Pagina impostazioni</a></li> <ol> - <li><a href="#settings-general">Impostazioni Generali</a></li> - <li><a href="#settings-capture">Impostazioni di Cattura</a></li> - <li><a href="#settings-output">Impostazioni di Emissione</a></li> - <li><a href="#settings-printer">Impostazioni Stampante</a></li> + <li><a href="#settings-general">Impostazioni generali</a></li> + <li><a href="#settings-capture">Impostazioni cattura</a></li> + <li><a href="#settings-output">Impostazioni destinazione</a></li> + <li><a href="#settings-printer">Impostazioni stampante</a></li> </ol> <li><a href="#help">Vuoi aiutarci?</a></li> <ol> - <li><a href="#help-donate">Considera una donazione</a></li> + <li><a href="#help-donate">Fai una donazione</a></li> <li><a href="#help-spread">Spargi la parola</a></li> <li><a href="#help-translate">Invia una traduzione</a></li> </ol> </ol> <a name="screenshot"></a> - <h2>Creazione immagine dello schermo</h2> + <h2>Crea immagine dello schermo</h2> <p> - L'immagine può essere creata utilizzando il tasto <kbd>Stamp</kbd> della tastiera, - oppure cliccando il tasto destro del mouse sull'icona di Greenshot nella barra.<br> + L'immagine può essere creata usando il tasto <kbd>Stamp</kbd> della tastiera, oppure facendo clic il tasto destro del mouse sull'icona di Greenshot nella barra.<br> Ci sono varie opzioni per creare un'immagine: </p> <a name="capture-region"></a> <h3>Cattura regione <kbd>Stamp</kbd></h3> <p> - Il metodo cattura regione consente di selezionare una parte dello schermo da "fotografare".<br> - Dopo aver avviato il metodo regione, apparirà un mirino sulla posizione del mouse sullo - schermo. Cliccare e tenere premuto dove si vuole impostare un angolo della regione da - fotografare. Tenendo premuto il pulsante del mouse, muovere il mouse fino a definire il - rettangolo da fotografare. Rilasciare quindi il pulsante quando il rettangolo verde avrà - coperto l'area da catturare nell'immagine. + Il metodo cattura regione consente di selezionare una parte dello schermo da "catturare".<br> + Dopo aver attivato la cattura, apparirà un mirino sulla posizione del mouse sullo schermo.<br> + Fai clic e tieni premuto dove vuoi impostare un angolo della regione da catturare.<br> + Tenendo premuto il pulsante del mouse, sposta il mouse fino a definire il rettangolo da catturare.<br> + Rilascia quindi il pulsante quando il rettangolo verde avrà coperto l'area che vuoi catturare. </p> <p class="hint"> - Si può usare il tasto <kbd>Spazio</kbd> per cambiare da metodo regione a metodo - <a href="#capture-window">finestra</a>. + Puoi usare il tasto <kbd>Spazio</kbd> per cambiare da metodo regione a metodo <a href="#capture-window">finestra</a>. </p> <p class="hint"> - Se si vuol catturare precisamente un'area, potrebbe risultare più facile selezionare - un'area più grande e quindi <a href="#editor-crop">ritagliare</a> l'immagine in - seguito, utilizzando la Gestione Immagini di Greenshot. + Se vuoi catturare una specifica, può risultare più facile selezionare un'area più grande e quindi <a href="#editor-crop">ritagliare</a> l'immagine in seguito, usando la 'Gestione immagini' di Greenshot. </p> <a name="capture-last-region"></a> <h3>Cattura ultima regione <kbd>Maiusc</kbd> + <kbd>Stamp</kbd></h3> <p> - Usando questa opzione, se avete già eseguito un cattura <a href="#capture-region">regione</a> o <a href="#capture-window">finestra</a>, - si può ricatturare automaticamente la stessa regione. + Usando questa opzione, se hai già eseguito un cattura <a href="#capture-region">regione</a> o <a href="#capture-window">finestra</a>, puoi ricatturare automaticamente la stessa regione. </p> <a name="capture-window"></a> @@ -105,14 +99,10 @@ Crea un'immagine della finestra che è attiva in quel momento. </p> <p class="hint"> - La <a href="#settings">pagina delle impostazioni</a> offre una possibilità per non catturare - direttamente la finestra attiva, consentendo quindi di sceglierne una interattivamente. - Se si seleziona questa opzione, la finestra può essere scelta cliccandovi (come nel metodo - <a href="#capture-region">regione</a>, Greenshot evidenzierà l'area che verrà catturata). - <br>Se si vuol catturare una finestra figlia (es: una browser - viewport (senza barra strumenti, ecc...) o un singolo frame di una pagina web che usa i framesets) - si può puntare il cursore del mouse sulla finestra e premere il tasto <kbd>PgDown</kbd>. Dopo di questo, sarà - possibile selezionare elementi da catturare nella finestra figlia. + La <a href="#settings">pagina delle impostazioni</a> offre una possibilità per non catturare direttamente la finestra attiva, consentendo quindi di sceglierne una interattivamente.<br> + Se selezioni questa opzione, la finestra può essere scelta facendovi clic sopra (come nel metodo <a href="#capture-region">regione</a>, Greenshot evidenzierà l'area che verrà catturata).<br> + Se vuoi catturare una finestra figlia (es: una browser viewport (senza barra strumenti, ecc...) o un singolo frame di una pagina web che usa i frameset) puoi puntare il cursore del mouse sulla finestra e premere il tasto <kbd>PgDown</kbd>.<br> + Fatto questo, sarà possibile selezionare gli elementi da catturare nella finestra figlia. </p> <a name="capture-fullscreen"></a> @@ -122,75 +112,63 @@ <a name="capture-ie"></a> <h3>Cattura Internet Explorer <kbd>Ctrl</kbd> + <kbd>Maiusc</kbd> + <kbd>Stamp</kbd></h3> <p> - Crea facilmente un'immagine della pagina web attiva in quel momento su Internet Explorer. - Si può usare il menu sensibile al contesto di Greenshot per selezionare la tab di Internet Explorer da catturare, oppure premere - <kbd>Crtl</kbd> + <kbd>Maiusc</kbd> + <kbd>Stamp</kbd> per catturare la tab attiva. + Crea facilmente un'immagine della pagina web attiva in quel momento su Internet Explorer.<br> + Puoi usare il menu sensibile al contesto di Greenshot per selezionare la scheda di Internet Explorer da catturare, o premi <kbd>Crtl</kbd> + <kbd>Maiusc</kbd> + <kbd>Stamp</kbd> per catturare la scheda attiva. </p> <a name="editor"></a> - <h2>Uso della Gestione Immagini</h2> + <h2>Uso Gestione Immagini</h2> <p> - Greenshot fornisce anche una pratica gestione delle immagini, che include degli utili strumenti - per aggiungere note e forme alle immagini. Essa permette inoltre di evidenziare o - offuscare parti dell'immagine. + Greenshot fornisce anche una pratica gestione delle immagini, che include degli utili strumenti per aggiungere note e forme alle immagini. <br> + Essa permette inoltre di evidenziare o offuscare parti dell'immagine. </p> <p class="hint"> - La Gestioni Immagini di Greenshot non è solo per le immagini catturate. Si può usare - anche per aprire e modificare immagini da file o da Appunti. E' sufficiente premere il tasto destro - sull'icona di Greenshot nella barra, e selezionare rispettivamente <em>Apri immagine da file</em> - o <em>Apri immagine da Appunti</em>. + La Gestioni Immagini di Greenshot non serve solo per le immagini catturate. <br> + Si può usare anche per aprire e modificare immagini da file o da Appunti. <br> + E' sufficiente premere il tasto destro sull'icona di Greenshot nella barra, e selezionare rispettivamente <em>Apri immagine da file</em> o <em>Apri immagine da Appunti</em>. </p> <p class="hint"> - Come default, la gestione immagini verrà aperta ogniqualvolta un'immagine viene catturata. - Se non si vuole passare per la gestione immagini, si può disabilitare questo funzionamento - nella <a href="#settings">pagina delle impostazioni</a>. + Come impostazione predefinita, la gestione immagini verrà aperta ogni volta che un'immagine viene catturata. <br> + Se non vuoi usare la gestione immagini, puoi disabilitare questa funzionalità nella <a href="#settings">pagina delle impostazioni</a>. </p> <a name="editor-shapes"></a> - <h3>Disegnare forme</h3> + <h3>Disegna forme</h3> <p> - Selezionare uno degli strumenti di disegno dalla barra degli strumenti sul lato sinistro - della gestione immagini o dal menù <em>Oggetti</em>. Per facilitarne la selezione, ciascun - strumento è assegnato ad un tasto.<br> - Le forme disponibili sono: rettangolo <kbd>R</kbd>, ellisse <kbd>E</kbd>, linea <kbd>L</kbd> - e freccia <kbd>A</kbd>.<br> - Cliccare, tenendo premuto il pulsante del mouse e trascinare per definire la posizione e la dimensione della forma. - Completata la definizione, rilasciare il pulsante del mouse. + Seleziona uno degli strumenti di disegno dalla barra degli strumenti sul lato sinistro della gestione immagini o dal menù <em>Oggetti</em>. <br> + Per facilitarne la selezione, ciascun strumento è assegnato ad un tasto.<br> + Le forme disponibili sono: rettangolo <kbd>R</kbd>, ellisse <kbd>E</kbd>, linea <kbd>L</kbd> e freccia <kbd>A</kbd>.<br> + Fai clic, e tenendo premuto il pulsante del mouse trascina per definire la posizione e la dimensione della forma. <br> + Completata la definizione, rilascia il pulsante del mouse. </p> <p> - Le forme possono essere mosse e ridimensionate facilmente, previa selezione mediante lo strumento - <kbd>ESC</kbd> disponibile nella barra a sinistra.<br>Per ciascun tipo di elemento c'è un gruppo di - opzioni specifiche per cambiarne l'aspetto (es: spessore linea, - colore linea, colore di riempimento). Si possono modificare le opzioni di un elemento esistente, previa selezione, - e anche quelle di nuovi elementi da disegnare, previa selezione dello strumento di disegno. + Le forme possono essere mosse e ridimensionate facilmente, previa selezione mediante lo strumento <kbd>ESC</kbd> disponibile nella barra a sinistra.<br> + Per ciascun tipo di elemento c'è un gruppo di opzioni specifiche per cambiarne l'aspetto (es: spessore linea, colore linea, colore di riempimento). <br> + Si possono modificare le opzioni di un elemento esistente, previa selezione, e anche quelle di nuovi elementi da disegnare, previa selezione dello strumento di disegno. </p> <p class="hint"> - Si possono inoltre selezionare più elementi per una modifica simultanea. Per selezionare più elementi, - tenere premuto il tasto <kbd>Maiusc</kbd> mentre si clicca sugli elementi. + Si possono inoltre selezionare più elementi per una modifica simultanea. <br> + Per selezionare più elementi, tieni premuto il tasto <kbd>Maiusc</kbd> mentre si fai clic sugli elementi. </p> <a name="editor-text"></a> - <h3>Aggiungere testo</h3> + <h3>Aggiungi testo</h3> <p> - L'uso dello strumento di testo <kbd>T</kbd> è simile all'uso degli strumenti di disegno - <a href="#editor-shapes">forme</a>. E' sufficiente disegnare l'elemento di testo delle dimensioni desiderate, - e quindi digitare il testo.<br> - Per modificare il testo di un elemento esistente, premere il doppio click sull'elemento. + L'uso dello strumento di testo <kbd>T</kbd> è simile all'uso degli strumenti di disegno <a href="#editor-shapes">forme</a>. <br> + E' sufficiente disegnare l'elemento di testo delle dimensioni desiderate, e quindi digitare il testo.<br> + Per modificare il testo di un elemento esistente, fai doppio clic sull'elemento. </p> <a name="editor-highlight"></a> - <h3>Evidenziare qualcosa</h3> + <h3>Evidenzia qualcosa</h3> <p> - Dopo aver selezionato lo strumento di evidenziazione <kbd>H</kbd>, definire l'area da evidenziare esattamente - come si volesse disegnare una <a href="#editor-shapes">forma</a>.<br> - Ci sono varie opzioni per evidenziare, esse possono essere selezionate cliccando il pulsante - più in alto a sinistra nella barra degli strumenti: + Dopo aver selezionato lo strumento di evidenziazione <kbd>H</kbd>, definisci l'area da evidenziare esattamente come si volesse disegnare una <a href="#editor-shapes">forma</a>.<br> + Ci sono varie opzioni per evidenziare, esse possono essere selezionate selezionando il pulsante più in alto a sinistra nella barra degli strumenti: </p> <ul> - <li><em>Evidenzia il testo</em>: evidenzia un'area applicando un colore brillante ad essa, come un - pennarello evidenziatore</li> - <li><em>Evidenzia l'area</em>: sfuoca<a href="#hint-blur">*</a> e scurisce tutto all'esterno dell'area selezionata</li> + <li><em>Evidenzia testo</em>: evidenzia un'area applicando un colore brillante ad essa, come un pennarello evidenziatore</li> + <li><em>Evidenzia area</em>: sfuoca <a href="#hint-blur">*</a> e scurisce tutto all'esterno dell'area selezionata</li> <li><em>Scala di grigi</em>: tutto ciò che è al di fuori dell'area selezionata viene trasformato in scala di grigi</li> <li><em>Ingrandisci</em>: l'area selezionata verrà visualizzata come ingrandita da una lente</li> </ul> @@ -198,177 +176,163 @@ <a name="editor-obfuscate"></a> <h3>Offuscare qualcosa</h3> <p> - Offuscare parti di un'immagine può essere una buona idea se essa contiene dati privati che non devono essere - visti da altre persone, per esempio dati conto bancario, nomi, parole d'ordine o volti di persone.<br> - Usare lo strumento di offuscamento <kbd>O</kbd> esattamente come lo strumento di <a href="#editor-highlight">evidenziazione</a>.<br> + Offuscare parti di un'immagine può essere una buona idea se essa contiene dati privati che non devono essere visti da altre persone, per esempio dati conto bancario, nomi, parole d'ordine o volti di persone.<br> + Usa lo strumento di offuscamento <kbd>O</kbd> esattamente come lo strumento di <a href="#editor-highlight">evidenziazione</a>.<br> Le opzioni disponibili per l'offuscamento, sono: </p> <ul> - <li><em>Offusca/pixelize</em>: aumenta le dimensioni dei pixel nell'area selezionata</li> + <li><em>Offusca/pixelizza</em>: aumenta le dimensioni dei pixel nell'area selezionata</li> <li><em>Sfuma</em><a href="#hint-blur">*</a>: sfuma e sfuoca l'area selezionata</li> </ul> <a name="hint-blur"></a> <p class="hint"> - * A seconda delle prestazioni del proprio PC, applicare un effetto di sfumatura potrebbe rallentare la Gestione - Immagini di Greenshot. Se si vede che la Gestione Immagini risponde lentamente subito dopo aver eseguito una sfumatura, - è utile provare a ridurre il valore di <em>Qualità anteprima</em> nella barra strumenti di offuscamento, - o a diminuire il valore di <em>Raggio sfumatura</em>.<br> - Se le prestazioni della sfumatura sono ancora deludenti per poterci lavorare, si consiglia si usare invece - l'effetto Offusca/pixelize. + * A seconda delle prestazioni del proprio PC, applicare un effetto di sfumatura potrebbe rallentare la Gestione Immagini di Greenshot.<br> + Se si vede che la Gestione Immagini risponde lentamente subito dopo aver eseguito una sfumatura, è utile provare a ridurre il valore di <em>Qualità anteprima</em> nella barra strumenti di offuscamento, o a diminuire il valore di <em>Raggio sfumatura</em>.<br> + Se le prestazioni della sfumatura sono ancora deludenti per poterci lavorare, ti consiglia si usare invece l'effetto Offusca/pixelizza. </p> <a name="editor-crop"></a> - <h3>Ritagliare l'immagine</h3> + <h3>Ritaglia immagine</h3> <p> - Per ricavare solo una parte dell'immagine catturata, si può usare lo strumento di ritaglio <kbd>C</kbd> - per ritagliare l'area desiderata.<br> - Dopo aver selezionato lo strumento di ritaglio, disegnare un rettangolo per l'area che si vuole mantenere. + Per ricavare solo una parte dell'immagine catturata, si può usare lo strumento di ritaglio <kbd>C</kbd> per ritagliare l'area desiderata.<br> + Dopo aver selezionato lo strumento di ritaglio, disegna un rettangolo per l'area che vuoi mantenere.<br> Come per gli atri elementi, si possono facilmente modificare le dimensioni dell'area selezionata.<br> - Dopo aver impostato correttamente la selezione dell'area, premere il pulsante di conferma della barra strumenti - oppure premere il tasto <kbd>Invio</kbd>. Si può annullare l'azione di ritaglio, cliccando il pulsante di cancellazione o premendo - <kbd>ESC</kbd>. + Dopo aver impostato correttamente la selezione dell'area, seleziona il pulsante di conferma nella barra strumenti o premi il tasto <kbd>Invio</kbd>.<br> + Puoi annullare l'azione di ritaglio, selezionando il pulsante annullamento o premendo <kbd>ESC</kbd>. </p> <p class="hint"> - <em>Ritaglia Automaticamente</em>: Se si ha la necessità di ritagliare un pezzo dell'immagine lungo i bordi di uno sfondo con colore compatto, - è sufficiente scegliere <em>Ritaglia Automaticamente</em> dal menù <em>Modifica</em> e Greenshot automaticamente - selezionerà l'area di ritaglio. + <em>Ritaglia automaticamente</em>: ae si ha la necessità di ritagliare un pezzo dell'immagine lungo i bordi di uno sfondo con colore compatto, è sufficiente scegliere <em>Ritaglia automaticamente</em> dal menù <em>Modifica</em> e Greenshot automaticamente selezionerà l'area di ritaglio. </p> <a name="editor-adding-graphics"></a> <h3>Aggiunta elementi grafici all'immagine</h3> <p> - Si possono facilmente aggiungere degli elementi grafici o delle altre immagini alla immagine in lavorazione, è sufficiente trascinare un file di immagine - all'interno della finestra di gestione immagini. Inoltre, selezionando <em>Inserisci finestra</em> dal menù <em>Modifica</em>, si possono inserire - immagini prese da altre finestre. In questo caso, appare una lista con tutte le finestre aperte, consentendo quindi di scegliere quella che si - vuole inserire. + Si possono facilmente aggiungere degli elementi grafici o delle altre immagini alla immagine in lavorazione, trascinando un file immagine all'interno della finestra di gestione immagini.<br> + Inoltre, selezionando <em>Inserisci finestra</em> dal menù <em>Modifica</em>, si possono inserire immagini prese da altre finestre.<br> + In questo caso, appare un elenco con tutte le finestre aperte, consentendo quindi di scegliere quella che si vuole inserire. </p> <a name="editor-reuse-elements"></a> - <h3>Ri-utilizzare elementi disegnati</h3> + <h3>Ri-usa elementi disegnati</h3> <p> - Se ci si ritrova a utilizzare lo stesso o simile elemento nella maggior parte delle immagini, - (es: campo di testo contenente tipo browser e versione, oppure offuscamento dello stesso elemento - su più immagini), è possibile riutilizzare gli elementi in modo semplice.<br> - Selezionare <em>Salva oggetti su file</em> dal menù <em>Oggetti</em> per salvare di elementi correnti - per poterli riutilizzare poi. <em>Carica oggetti da file</em> viene invece usato per applicare su un'altra immagine - gli elementi salvati in precedenza. + Se ci si ritrova a utilizzare lo stesso o simile elemento nella maggior parte delle immagini, (es: campo di testo contenente tipo browser e versione, oppure offuscamento dello stesso elemento su più immagini), è possibile riusare gli elementi in modo semplice.<br> + Per salvare di elementi attuali seleziona <em>Salva oggetti su file</em> dal menù <em>Oggetti</em>.<br> + Per poterli riusare seleziona <em>Carica oggetti da file</em> con un'altra immagine. </p> <a name="editor-export"></a> - <h3>Esportare l'immagine</h3> + <h3>Esporta immagine</h3> <p> - Dopo aver modificato l'immagine, si può esportare il risultato per vari scopi, a seconda delle necessità. - Si può accedere a tutte le opzioni di esportazione mediante il menù <em>File</em>, - sulla barra principale, o per mezzo delle seguenti scorciatoie: + Dopo aver modificato l'immagine, si può esportare il risultato per vari scopi, a seconda delle necessità.<br> + Si può accedere a tutte le opzioni di esportazione dal menù <em>File</em>, nella barra principale, o per mezzo delle seguenti scorciatoie: </p> <ul> - <li><em>Salva</em> <kbd>Ctrl</kbd> + <kbd>S</kbd>: salva l'immagine su un file (se l'immagine è già stata salvata, altrimenti emette la finestra di <em>Salva come...</em>)</li> + <li><em>Salva</em> <kbd>Ctrl</kbd> + <kbd>S</kbd>: salva l'immagine in un file (se l'immagine è già stata salvata, altrimenti visualizza la finestra di <em>Salva come...</em>)</li> <li><em>Salva come...</em> <kbd>Ctrl</kbd> + <kbd>Maiusc</kbd> + <kbd>S</kbd>: permette di scegliere la destinazione, il nome file e il formato immagine per il file da salvare</li> - <li><em>Copia immagine sugli appunti</em> <kbd>Ctrl</kbd> + <kbd>Maiusc</kbd> + <kbd>C</kbd>: mette una copia dell'immagine sugli appunti, consentendo poi di incollarla dentro altri programmi</li> - <li><em>Stampa...</em> <kbd>Ctrl</kbd> + <kbd>P</kbd>: invia l'immagine a una stampante</li> - <li><em>E-Mail</em> <kbd>Ctrl</kbd> + <kbd>E</kbd>: apre un nuovo messaggio sul programma di e-mail di default, aggiungendo l'immagine come allegato</li> + <li><em>Copia immagine negli Appunti</em> <kbd>Ctrl</kbd> + <kbd>Maiusc</kbd> + <kbd>C</kbd>: fa una copia dell'immagine negli Appunti, consentendo poi di incollarla in altri programmi</li> + <li><em>Stampa...</em> <kbd>Ctrl</kbd> + <kbd>P</kbd>: invia l'immagine ad una stampante</li> + <li><em>Email</em> <kbd>Ctrl</kbd> + <kbd>E</kbd>: crea un nuovo messaggio nel programma email predefinito, aggiungendo l'immagine come allegato</li> </ul> <p class="hint"> - Dopo aver salvato un'immagine dalla gestione, cliccando con il tasto destro del mouse sulla barra di stato in basso sulla finestra - della gestione immagini, è possibile copiare il percorso sugli appunti, oppure aprire la cartella di destinazione con la gestione risorse. + Dopo aver salvato un'immagine dalla gestione, facendo clic con il tasto destro del mouse sulla barra di stato in basso sulla finestra della gestione immagini, è possibile copiare il percorso negli Appunti, o aprire la cartella destinazione con la Gestione risorse. </p> <a name="settings"></a> - <h2>Le Preferenze</h2> + <h2>Preferenze</h2> <a name="settings-general"></a> - <h3>Impostazioni Generali</h3> + <h3>Impostazioni generali</h3> <ul> - <li><em>Lingua</em>: La lingua che si preferisce usare.<br> - Si possono scaricare i file per le lingue aggiuntive di Greenshot <a href="#">qui</a>. </li> - <li><em>Lancia Greenshot all'avvio</em>: Avvia il programma in automatico all'accensione del sistema.</li> - <li><em>Scorciatoie di tastiera</em>: Personalizza le scorciatoie (hotkeys) da usare per catturare le immagini.</li> - <li><em>Usa il proxy di default del sistema</em>: Se selezionato, Greenshot usa il proxy di default del sistema per controllare se ci sono aggiornamenti.</li> - <li><em>Intervallo di controllo aggiornamento, in giorni</em>: Greenshot può controllare automaticamente se ci sono aggiornamenti. Questo parametro può essere - utilizzato per specificare l'intervallo (in giorni); per disabilitare il controllo aggiornamento si può usare il valore 0.</li> + <li><em>Lingua</em>: lingua dell'interfaccia utente.<br> + Si possono scaricare i file per le lingue aggiuntive di Greenshot da <a href="#">qui</a>. </li> + <li><em>Esegui Greenshot all'avvio</em>: esegue il programma Greenshot in automatico all'avvio del sistema.</li> + <li><em>Scorciatoie tastiera</em>: personalizza le scorciatoie (tasti rapidi) da usare per catturare le immagini.</li> + <li><em>Usa proxy predefinito sistema</em>: se selezionato, Greenshot per controllare se ci sono aggiornamenti usa il proxy predefinito di sistema.</li> + <li><em>Intervallo controllo aggiornamento, in giorni</em>: Greenshot può controllare automaticamente se ci sono aggiornamenti.<br> + Questo parametro può essere usato per specificare l'intervallo (in giorni); per disabilitare il controllo aggiornamento si può usare il valore 0.</li> </ul> <a name="settings-capture"></a> - <h3>Impostazioni di Cattura</h3> + <h3>Impostazioni cattura</h3> <ul> - <li><em>Cattura puntatore mouse</em>: Se selezionato, il puntatore del mouse verrà catturato. Il puntatore viene gestito come un elemento separato, in modo che possa essere spostato o rimosso in seguito.</li> - <li><em>Emetti suono fotocamera</em>: Attiva il riscontro udibile dell'azione di cattura (suono dello scatto fotografico).</li> - <li><em>Millisecondi di attesa prima di catturare</em>: Utile per aggiungere un tempo di ritardo prima dell'effettiva cattura dello schermo.</li> - <li><em>Usa la modalità di cattura via finestra interattiva</em>: Invece di catturare direttamente la finestra attiva, la modalità interattiva - consente di selezionare la finestra da catturare. E' inoltre possibile catturare le finestre figlie, vedi <a href="#capture-window">Cattura finestra</a>.</li> + <li><em>Cattura puntatore mouse</em>: se selezionato, il puntatore del mouse verrà catturato. + Il puntatore viene gestito come un elemento separato, in modo che possa essere spostato o rimosso in seguito.</li> + <li><em>Riproduci suono fotocamera</em>: attiva il riscontro udibile dell'azione di cattura (suono scatto fotografico).</li> + <li><em>Millisecondi attesa prima di catturare</em>: utile per aggiungere un tempo di ritardo prima dell'effettiva cattura dello schermo.</li> + <li><em>Usa modalità cattura via finestra interattiva</em>: invece di catturare direttamente la finestra attiva, la modalità interattiva consente di selezionare la finestra da catturare. <br> + E' inoltre possibile catturare le finestre figlie, vedi <a href="#capture-window">Cattura finestra</a>.</li> <li> - <em>Cattura in stile Aero (so Windows Vista / 7)</em>: Se si sta usando Greenshot su Windows Vista or Windows 7 con lo stile di visualizzazione Aero abilitato, è possibile - scegliere come devono essere gestiti i bordi della finestra trasparente quando vengono create le immagini in modalità finestra. Questa impostazione è da usare per evitare - la cattura di elementi dello sfondo che appaiono attraverso i bordi trasparenti. + <em>Cattura in stile Aero (so Windows Vista / 7)</em>: se si sta usando Greenshot in Windows Vista o Windows 7 con lo stile di visualizzazione Aero abilitato, è possibile scegliere come devono essere gestiti i bordi della finestra trasparenti quando vengono create le immagini in modalità finestra.<br> + Questa impostazione è da usare per evitare la cattura di elementi dello sfondo che appaiono attraverso i bordi trasparenti. <ul> <li><em>Automaticamente</em>: Greenshot deciderà come gestire la trasparenza.</li> - <li><em>Come visualizzata</em>: I bordi trasparenti verranno catturati come visualizzati sullo schermo.</li> - <li><em>Usa i colori di default</em>: Al posto della trasparenza verrà applicato un colore compatto di default.</li> - <li><em>Usa colori personalizzati</em>: Si può scegliere il colore che sarà applicato al posto della trasparenza.</li> - <li><em>Conserva la trasparenza</em>: I bordi verranno catturati conservando la trasparenza, senza però catturare gli elementi che potrebbero essere sullo sfondo. (Nota: le aree - trasparenti verrano visualizzate usando un modello selezionato nella gestione immagini. Il modello non verrà esportato se si salverà l'immagine su file. Ricordarsi di salvare - il file come PNG se si vuole conservance il pieno supporto della trasparenza.)</li> + <li><em>Come visualizzata</em>: i bordi trasparenti verranno catturati come visualizzati sullo schermo.</li> + <li><em>Usa colori predefiniti</em>: Al posto della trasparenza verrà applicato un colore compatto predefinito.</li> + <li><em>Usa colori personalizzati</em>: si può scegliere il colore che sarà applicato al posto della trasparenza.</li> + <li><em>Conserva trasparenza</em>: i bordi verranno catturati conservando la trasparenza, senza però catturare gli elementi che potrebbero essere sullo sfondo.<br> + Nota: le aree trasparenti verranno visualizzate usando un modello selezionato nella gestione immagini.<br> + Il modello non verrà esportato se si salverà l'immagine su file. <br> + Ricordarti di salvare il file come PNG se vuoi conservare il pieno supporto della trasparenza.)</li> </ul> </li> - <li><em>Cattura Internet Explorer</em>: Abilita la comoda cattura delle pagine web utilizzando Internet Explorer.</li> - <li><em>Adatta finestra Gestione a dimensioni di cattura</em>: Se selezionata, la finestra della Gestione immagini verrà automaticamente ridimensionata in base alla dimensione dell'immagine catturata.</li> + <li><em>Cattura con Internet Explorer</em>: abilita la comoda cattura delle pagine web usando Internet Explorer.</li> + <li><em>Adatta finestra Gestione a dimensioni di cattura</em>: se selezionata, la finestra della Gestione immagini verrà automaticamente ridimensionata in base alla dimensione dell'immagine catturata.</li> </ul> <a name="settings-output"></a> - <h3>Impostazioni di Emissione</h3> + <h3>Impostazioni destinazione</h3> <ul> - <li><em>Destinazione dell'immagine</em>: Consente di scegliere la destinazione/i automatiche delle immagini subito dopo l'azione di cattura.</li> - <li><em>Impostazioni Preferite per l'Emissione File</em>: Cartella e nome file da usare quando si salva automaticamente, o da suggerire quando si salva (usando la finestra "Salva come"). Cliccare il pulsante <em>?</em> per sapere di più sulle variabili che possono essere usate nel modello del nome file.</li> - <li><em>Impostazioni JPEG</em>: Qualità da usare quando si salvano file JPEG.</li> + <li><em>Destinazione immagine</em>: consente di scegliere la/le destinazione/i automatiche delle immagini subito dopo l'azione di cattura.</li> + <li><em>Impostazioni preferite destinazione file</em>: cartella e nome file da usare quando si salva automaticamente, o da suggerire quando si salva (usando la finestra "Salva come").<br> + Fai clic su <em>?</em> per sapere di più sulle variabili che possono essere usate nel modello del nome file.</li> + <li><em>Impostazioni JPEG</em>: qualità da usare quando si salvano file JPEG.</li> </ul> <a name="settings-printer"></a> <h3>Impostazioni Stampante</h3> <ul> - <li><em>Riduci alle dimensioni pagina</em>: Se l'immagine eccede le dimensioni della pagina, essa verrà ridotta e adattata alle dimensioni della pagina.</li> - <li><em>Ingrandisci fino alle dimensioni pagina</em>: Se l'immagine è più piccola delle dimensioni della pagina, essa verrà ingrandita per stamparla più grande possibile senza superare le dimensioni della pagina.</li> + <li><em>Riduci a dimensioni pagina</em>: se l'immagine eccede le dimensioni della pagina, essa verrà ridotta e adattata alle dimensioni della pagina.</li> + <li><em>Ingrandisci fino a dimensioni pagina</em>: se l'immagine è più piccola delle dimensioni della pagina, essa verrà ingrandita per stamparla più grande possibile senza superare le dimensioni della pagina.</li> <li><em>Ruota a seconda dell'orientamento pagina</em>: Ruoterà l'immagine in formato orizzontale di 90° per la stampa.</li> - <li><em>Centra nella pagina</em>: L'immagine verrà stampata al centro della pagina.</li> - <li><em>Stampa data / ora sul piede della pagina</em>: La data e l'ora di stampa verranno stampati sul piede della pagina.</li> - <li><em>Stampa con colori inverititi (negativo)</em>: Trasformerà l'immagine in negativo prima di stamparla, utile per esempio quando si stampa un'immagine con testo bianco su sfondo nero (per risparmiare toner o inchiostro).</li> - <li><em>Visualizza scelta opzioni di stampa ogni volta che si stampa un'immagine</em>: Permette di scegliere se visualizzare o meno la finestra di scelta opzioni per le stampe successive alla prima.</li> + <li><em>Centra nella pagina</em>: l'immagine verrà stampata al centro della pagina.</li> + <li><em>Stampa data/ora in piè di pagina</em>: la data e l'ora di stampa verranno stampate nel piè di pagina.</li> + <li><em>Stampa con colori invertiti (negativo)</em>: trasformerà l'immagine in negativo prima di stamparla. <br> + Utile per esempio quando si stampa un'immagine con testo bianco su sfondo nero (per risparmiare toner o inchiostro).</li> + <li><em>Visualizza scelta opzioni stampa ogni volta che si stampa un'immagine</em>: permette di scegliere se visualizzare o meno la finestra di scelta opzioni per le stampe successive alla prima.</li> </ul> <a name="settings-plugins"></a> - <h3>Impostazioni Componenti Aggiuntivi</h3> + <h3>Impostazioni componenti aggiuntivi</h3> <p> - Visualizza la lista dei componenti aggiuntivi di Greenshot che sono attualmente installati. La configurazione del singolo componente aggiuntivo è disponibile selezionando - il componente dalla lista e quindi cliccando su <em>Configura</em>. + Visualizza l'elenco dei componenti aggiuntivi di Greenshot che sono attualmente installati.<br> + La configurazione del singolo componente aggiuntivo è disponibile selezionando il componente dall'elenco e quindi selezionando <em>Configura</em>. </p> <a name="help"></a> - <h2>Desideri aiutarci?</h2> + <h2>Vuoi aiutarci?</h2> <p> - Attualmente non abbiamo bisogno di aiuto per lo sviluppo. Tuttavia, ci sono molte cose che puoi fare per - supportare Greenshot e il team di sviluppo.<br> + Attualmente non abbiamo bisogno di aiuto per lo sviluppo.<br> + Tuttavia, ci sono molte cose che puoi fare per supportare Greenshot e il team di sviluppo.<br> Grazie anticipatamente :) </p> <a name="help-donate"></a> - <h3>Considera una donazione</h3> + <h3>Fai una donazione</h3> <p> - Stiamo lavorando molto su Greenshot e stiamo spendendo molto tempo per fornire - un buon prodotto software gratuito e open source. Se ti sei reso conto che Greenshot - ti ha reso più produttivo, e se fa risparmiare a te (o alla tua società) - molto tempo e denaro, o se semplicemente ti piace Greenshot e l'idea - di software open source: per cortesia, considera di onorare i nostri sforzi con una donazione.<br> - Per cortesia dai un'occhiata alla nostra home page per vedere come puoi aiutare il team di sviluppo di Greenshot:<br> + Stiamo lavorando molto su Greenshot e stiamo spendendo molto tempo per fornire un buon prodotto software gratuito e open source.<br> + Se ti sei reso conto che Greenshot ti ha reso più produttivo, e se fa risparmiare a te (o alla tua società) molto tempo e denaro, o se semplicemente ti piace Greenshot e l'idea di software open source considera di onorare i nostri sforzi con una donazione.<br> + Dai un'occhiata alla nostra home page per vedere come puoi aiutare il team di sviluppo di Greenshot:<br> <a href="http://getgreenshot.org/support/">http://getgreenshot.org/support/</a> </p> <a name="help-spread"></a> <h3>Spargi la parola</h3> <p> - Se ti piace Greenshot, fallo sapere anche agli altri: racconta ai tuoi amici di Greenshot. + Se ti piace Greenshot, fallo sapere anche agli altri: racconta ai tuoi amici di Greenshot.<br> Anche loro, a loro volta :)<br> Commenta positivamente Greenshot sui portali di software, oppure metti un link sulla tua home page, blog o sito web. </p> @@ -376,20 +340,16 @@ <a name="help-translate"></a> <h3>Invia una traduzione</h3> <p> - Greenshot non è disponibile nella tua lingua preferita? Se ti senti in grado di tradurre un pezzo di software, - sei più che benvenuto. - Se sei un utente registrato su sourceforge.net, puoi inviare le traduzioni al nostro - <a href="https://sourceforge.net/tracker/?group_id=191585&atid=1368020">translations tracker</a>.<br> - Prima di farlo, assicurati che non esista già la traduzione sulla nostra - <a href="http://sourceforge.net/projects/greenshot/files/">pagina di download</a>. Controlla anche il nostro <a href="https://sourceforge.net/tracker/?group_id=191585&atid=1368020">translations tracker</a>, - ci potrebbe essere una traduzione in lavorazione, o almeno in discussione.<br> - Ti preghiamo di notare che forniremo una traduzione della nostra pagina di download solo se è stata inviata mediante - il tuo conto utente su sourceforge.net. Visto che molto probabilmente non siamo in grado di capire la traduzione, è opportuno - che gli altri utenti di sourceforge possano essere in grado di contattarti per revisioni o miglioramenti - in caso di nuove versioni di Greenshot. + Greenshot non è disponibile nella tua lingua preferita?<br> + Se ti senti in grado di tradurre un pezzo di software, sei più che benvenuto.<br> + Se sei un utente registrato su sourceforge.net, puoi inviare le traduzioni al nostro <a href="https://sourceforge.net/tracker/?group_id=191585&atid=1368020">translations tracker</a>.<br> + Prima di farlo, assicurati che non esista già la traduzione sulla nostra <a href="http://sourceforge.net/projects/greenshot/files/">pagina download</a>.<br> + Controlla anche il nostro <a href="https://sourceforge.net/tracker/?group_id=191585&atid=1368020">translations tracker</a>, ci potrebbe essere una traduzione in lavorazione, o almeno in discussione.<br> + Nota che forniremo una traduzione della nostra pagina di download solo se è stata inviata mediante il tuo account utente di sourceforge.net.<br> + Visto che molto probabilmente non siamo in grado di capire la traduzione, è opportuno che gli altri utenti di sourceforge possano essere in grado di contattarti per revisioni o miglioramenti in caso di nuove versioni di Greenshot. </p> </body> -</html> \ No newline at end of file +</html> From 96f26f68c24f1f19c237a490d3543e4be70609c4 Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Sat, 20 Mar 2021 17:50:52 +0300 Subject: [PATCH 096/232] Update URLs to HTTPS --- Greenshot/Forms/AboutForm.Designer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Greenshot/Forms/AboutForm.Designer.cs b/Greenshot/Forms/AboutForm.Designer.cs index 551f88671..f68fd69ee 100644 --- a/Greenshot/Forms/AboutForm.Designer.cs +++ b/Greenshot/Forms/AboutForm.Designer.cs @@ -97,7 +97,7 @@ namespace Greenshot.Forms { this.linkLblLicense.Size = new System.Drawing.Size(369, 23); this.linkLblLicense.TabIndex = 5; this.linkLblLicense.TabStop = true; - this.linkLblLicense.Text = "http://www.gnu.org/licenses/gpl.html"; + this.linkLblLicense.Text = "https://www.gnu.org/licenses/gpl.html"; this.linkLblLicense.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); // // linkLblHost @@ -117,7 +117,7 @@ namespace Greenshot.Forms { this.linkLblBugs.Size = new System.Drawing.Size(465, 23); this.linkLblBugs.TabIndex = 8; this.linkLblBugs.TabStop = true; - this.linkLblBugs.Text = "http://getgreenshot.org/tickets/?version=" + EnvironmentInfo.GetGreenshotVersion(true); + this.linkLblBugs.Text = "https://getgreenshot.org/tickets/?version=" + EnvironmentInfo.GetGreenshotVersion(true); this.linkLblBugs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); // // lblBugs @@ -135,7 +135,7 @@ namespace Greenshot.Forms { this.linkLblDonations.Size = new System.Drawing.Size(465, 23); this.linkLblDonations.TabIndex = 10; this.linkLblDonations.TabStop = true; - this.linkLblDonations.Text = "http://getgreenshot.org/support/?version=" + EnvironmentInfo.GetGreenshotVersion(true); + this.linkLblDonations.Text = "https://getgreenshot.org/support/?version=" + EnvironmentInfo.GetGreenshotVersion(true); this.linkLblDonations.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); // // lblDonations @@ -153,7 +153,7 @@ namespace Greenshot.Forms { this.linkLblIcons.Size = new System.Drawing.Size(279, 23); this.linkLblIcons.TabIndex = 12; this.linkLblIcons.TabStop = true; - this.linkLblIcons.Text = "http://p.yusukekamiyamane.com"; + this.linkLblIcons.Text = "https://p.yusukekamiyamane.com"; this.linkLblIcons.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); // // lblIcons @@ -171,7 +171,7 @@ namespace Greenshot.Forms { this.linkLabel1.Size = new System.Drawing.Size(130, 23); this.linkLabel1.TabIndex = 13; this.linkLabel1.TabStop = true; - this.linkLabel1.Text = "http://getgreenshot.org/?version=" + EnvironmentInfo.GetGreenshotVersion(true); + this.linkLabel1.Text = "https://getgreenshot.org/?version=" + EnvironmentInfo.GetGreenshotVersion(true); this.linkLabel1.TextAlign = System.Drawing.ContentAlignment.TopRight; this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); // From 93ddd56b8b1872af1a73c8b75b0ddfccd14a6bd1 Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Sat, 20 Mar 2021 17:51:20 +0300 Subject: [PATCH 097/232] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 29ef417c7..a90bfa1bb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ and a lot more options simplyfying creation of and work with screenshots every d Being easy to understand and configurable, Greenshot is an efficient tool for project managers, software developers, technical writers, testers and anyone else creating screenshots. -[If you find that Greenshot saves you a lot of time and/or money, you are very welcome to support the development of this screenshot software.](http://getgreenshot.org/support/) +[If you find that Greenshot saves you a lot of time and/or money, you are very welcome to support the development of this screenshot software.](https://getgreenshot.org/support/) About this repository From fb843fb4146d6e385a4e99cafd4c158b7e933cfa Mon Sep 17 00:00:00 2001 From: jklingen <jens@getgreenshot.org> Date: Sun, 21 Mar 2021 17:12:54 +0100 Subject: [PATCH 098/232] Fix Objects Growing near Infinity when Scaling w Aspect Ratio Maintained --- Greenshot/Helpers/ScaleHelper.cs | 93 ++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/Greenshot/Helpers/ScaleHelper.cs b/Greenshot/Helpers/ScaleHelper.cs index 76e0091c6..96840c509 100644 --- a/Greenshot/Helpers/ScaleHelper.cs +++ b/Greenshot/Helpers/ScaleHelper.cs @@ -28,8 +28,8 @@ namespace Greenshot.Helpers { /// Offers a few helper functions for scaling/aligning an element with another element /// </summary> public static class ScaleHelper { - - [Flags] + + [Flags] public enum ScaleOptions { /// <summary> /// Default scale behavior. @@ -218,59 +218,98 @@ namespace Greenshot.Helpers { } /// <summary> - /// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments + /// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments. + /// An adjustment can always be done in two ways, e.g. *in*crease width until fit or *de*crease height until fit. + /// To avoid objects growing near infinity unexpectedly in certain combinations, the adjustment will choose the + /// option resulting in the smaller rectangle. /// </summary> /// <param name="originalRectangle">bounds of the current rectangle</param> /// <param name="resizeHandlePosition">position of the handle/gripper being used for resized, see Position</param> /// <param name="resizeHandleCoords">coordinates of the used handle/gripper, adjusted coordinates will be written to this reference</param> private static void adjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) { - float originalRatio = originalRectangle.Width / originalRectangle.Height; + float originalRatio = originalRectangle.Width / originalRectangle.Height; float newWidth, newHeight, newRatio; + int flippedRatioSign; switch(resizeHandlePosition) { case Positions.TopLeft: newWidth = originalRectangle.Right - resizeHandleCoords.X; newHeight = originalRectangle.Bottom - resizeHandleCoords.Y; newRatio = newWidth / newHeight; - if(newRatio > originalRatio) { // FIXME - resizeHandleCoords.X = originalRectangle.Right - newHeight * originalRatio; - } else if(newRatio < originalRatio) { - resizeHandleCoords.Y = originalRectangle.Bottom - newWidth / originalRatio; + flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio); + if (Math.Abs(newRatio) > Math.Abs(originalRatio)) { + // scaled rectangle (ratio) would be wider than original + // keep height and tweak width to maintain aspect ratio + float tweakedWidth = newHeight * originalRatio * flippedRatioSign; + resizeHandleCoords.X = originalRectangle.Right - tweakedWidth; + } else if(Math.Abs(newRatio) < Math.Abs(originalRatio)) { + // scaled rectangle (ratio) would be taller than original + // keep width and tweak height to maintain aspect ratio + float tweakedHeight = newWidth / originalRatio * flippedRatioSign; + resizeHandleCoords.Y = originalRectangle.Bottom - tweakedHeight; } break; case Positions.TopRight: newWidth = resizeHandleCoords.X - originalRectangle.Left; newHeight = originalRectangle.Bottom - resizeHandleCoords.Y; - newRatio = newWidth / newHeight; - if(newRatio > originalRatio) { // FIXME - resizeHandleCoords.X = newHeight * originalRatio + originalRectangle.Left; - } else if(newRatio < originalRatio) { - resizeHandleCoords.Y = originalRectangle.Bottom - newWidth / originalRatio; - } - break; + newRatio = newWidth / newHeight; + flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio); + + if (Math.Abs(newRatio) > Math.Abs(originalRatio)) { + // scaled rectangle (ratio) would be wider than original + // keep height and tweak width to maintain aspect ratio + float tweakedWidth = newHeight * originalRatio * flippedRatioSign; + resizeHandleCoords.X = originalRectangle.Left + tweakedWidth; + } + else if (Math.Abs(newRatio) < Math.Abs(originalRatio)) { + // scaled rectangle (ratio) would be taller than original + // keep width and tweak height to maintain aspect ratio + float tweakedHeight = newWidth / originalRatio * flippedRatioSign; + resizeHandleCoords.Y = originalRectangle.Bottom - tweakedHeight; + } + break; case Positions.BottomLeft: newWidth = originalRectangle.Right - resizeHandleCoords.X; newHeight = resizeHandleCoords.Y - originalRectangle.Top; newRatio = newWidth / newHeight; - if(newRatio > originalRatio) { - resizeHandleCoords.X = originalRectangle.Right - newHeight * originalRatio; - } else if(newRatio < originalRatio) { - resizeHandleCoords.Y = newWidth / originalRatio + originalRectangle.Top; - } - break; + flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio); + + if (Math.Abs(newRatio) > Math.Abs(originalRatio)) { + // scaled rectangle (ratio) would be wider than original + // keep height and tweak width to maintain aspect ratio + float tweakedWidth = newHeight * originalRatio * flippedRatioSign; + resizeHandleCoords.X = originalRectangle.Right - tweakedWidth; + } + else if (Math.Abs(newRatio) < Math.Abs(originalRatio)) { + // scaled rectangle (ratio) would be taller than original + // keep width and tweak height to maintain aspect ratio + float tweakedHeight = newWidth / originalRatio * flippedRatioSign; + resizeHandleCoords.Y = originalRectangle.Top + tweakedHeight; + } + break; case Positions.BottomRight: newWidth = resizeHandleCoords.X - originalRectangle.Left; newHeight = resizeHandleCoords.Y - originalRectangle.Top; newRatio = newWidth / newHeight; - if(newRatio > originalRatio) { - resizeHandleCoords.X = newHeight * originalRatio + originalRectangle.Left; - } else if(newRatio < originalRatio) { - resizeHandleCoords.Y = newWidth / originalRatio + originalRectangle.Top; - } - break; + flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio); + + if (Math.Abs(newRatio) > Math.Abs(originalRatio)) { + // scaled rectangle (ratio) would be wider than original + // keep height and tweak width to maintain aspect ratio + float tweakedWidth = newHeight * originalRatio * flippedRatioSign; + resizeHandleCoords.X = originalRectangle.Left + tweakedWidth; + } + else if (Math.Abs(newRatio) < Math.Abs(originalRatio)) { + // TODO this is the same code as else if for topleft! + // scaled rectangle (ratio) would be taller than original + // keep width and tweak height to maintain aspect ratio + float tweakedHeight = newWidth / originalRatio * flippedRatioSign; + resizeHandleCoords.Y = originalRectangle.Top + tweakedHeight; + } + break; } } From 18794fb4ce4c7362ede0f1c5234e14abfecee384 Mon Sep 17 00:00:00 2001 From: jklingen <jens@getgreenshot.org> Date: Sun, 21 Mar 2021 17:31:17 +0100 Subject: [PATCH 099/232] Revert "Fix Objects Growing near Infinity when Scaling w Aspect Ratio Maintained" This reverts commit fb843fb, committed to this branch uninentionally --- Greenshot/Helpers/ScaleHelper.cs | 93 ++++++++++---------------------- 1 file changed, 27 insertions(+), 66 deletions(-) diff --git a/Greenshot/Helpers/ScaleHelper.cs b/Greenshot/Helpers/ScaleHelper.cs index 96840c509..76e0091c6 100644 --- a/Greenshot/Helpers/ScaleHelper.cs +++ b/Greenshot/Helpers/ScaleHelper.cs @@ -28,8 +28,8 @@ namespace Greenshot.Helpers { /// Offers a few helper functions for scaling/aligning an element with another element /// </summary> public static class ScaleHelper { - - [Flags] + + [Flags] public enum ScaleOptions { /// <summary> /// Default scale behavior. @@ -218,98 +218,59 @@ namespace Greenshot.Helpers { } /// <summary> - /// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments. - /// An adjustment can always be done in two ways, e.g. *in*crease width until fit or *de*crease height until fit. - /// To avoid objects growing near infinity unexpectedly in certain combinations, the adjustment will choose the - /// option resulting in the smaller rectangle. + /// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments /// </summary> /// <param name="originalRectangle">bounds of the current rectangle</param> /// <param name="resizeHandlePosition">position of the handle/gripper being used for resized, see Position</param> /// <param name="resizeHandleCoords">coordinates of the used handle/gripper, adjusted coordinates will be written to this reference</param> private static void adjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) { - float originalRatio = originalRectangle.Width / originalRectangle.Height; + float originalRatio = originalRectangle.Width / originalRectangle.Height; float newWidth, newHeight, newRatio; - int flippedRatioSign; switch(resizeHandlePosition) { case Positions.TopLeft: newWidth = originalRectangle.Right - resizeHandleCoords.X; newHeight = originalRectangle.Bottom - resizeHandleCoords.Y; newRatio = newWidth / newHeight; - flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio); - if (Math.Abs(newRatio) > Math.Abs(originalRatio)) { - // scaled rectangle (ratio) would be wider than original - // keep height and tweak width to maintain aspect ratio - float tweakedWidth = newHeight * originalRatio * flippedRatioSign; - resizeHandleCoords.X = originalRectangle.Right - tweakedWidth; - } else if(Math.Abs(newRatio) < Math.Abs(originalRatio)) { - // scaled rectangle (ratio) would be taller than original - // keep width and tweak height to maintain aspect ratio - float tweakedHeight = newWidth / originalRatio * flippedRatioSign; - resizeHandleCoords.Y = originalRectangle.Bottom - tweakedHeight; + if(newRatio > originalRatio) { // FIXME + resizeHandleCoords.X = originalRectangle.Right - newHeight * originalRatio; + } else if(newRatio < originalRatio) { + resizeHandleCoords.Y = originalRectangle.Bottom - newWidth / originalRatio; } break; case Positions.TopRight: newWidth = resizeHandleCoords.X - originalRectangle.Left; newHeight = originalRectangle.Bottom - resizeHandleCoords.Y; - newRatio = newWidth / newHeight; - flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio); - - if (Math.Abs(newRatio) > Math.Abs(originalRatio)) { - // scaled rectangle (ratio) would be wider than original - // keep height and tweak width to maintain aspect ratio - float tweakedWidth = newHeight * originalRatio * flippedRatioSign; - resizeHandleCoords.X = originalRectangle.Left + tweakedWidth; - } - else if (Math.Abs(newRatio) < Math.Abs(originalRatio)) { - // scaled rectangle (ratio) would be taller than original - // keep width and tweak height to maintain aspect ratio - float tweakedHeight = newWidth / originalRatio * flippedRatioSign; - resizeHandleCoords.Y = originalRectangle.Bottom - tweakedHeight; - } - break; + newRatio = newWidth / newHeight; + if(newRatio > originalRatio) { // FIXME + resizeHandleCoords.X = newHeight * originalRatio + originalRectangle.Left; + } else if(newRatio < originalRatio) { + resizeHandleCoords.Y = originalRectangle.Bottom - newWidth / originalRatio; + } + break; case Positions.BottomLeft: newWidth = originalRectangle.Right - resizeHandleCoords.X; newHeight = resizeHandleCoords.Y - originalRectangle.Top; newRatio = newWidth / newHeight; - flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio); - - if (Math.Abs(newRatio) > Math.Abs(originalRatio)) { - // scaled rectangle (ratio) would be wider than original - // keep height and tweak width to maintain aspect ratio - float tweakedWidth = newHeight * originalRatio * flippedRatioSign; - resizeHandleCoords.X = originalRectangle.Right - tweakedWidth; - } - else if (Math.Abs(newRatio) < Math.Abs(originalRatio)) { - // scaled rectangle (ratio) would be taller than original - // keep width and tweak height to maintain aspect ratio - float tweakedHeight = newWidth / originalRatio * flippedRatioSign; - resizeHandleCoords.Y = originalRectangle.Top + tweakedHeight; - } - break; + if(newRatio > originalRatio) { + resizeHandleCoords.X = originalRectangle.Right - newHeight * originalRatio; + } else if(newRatio < originalRatio) { + resizeHandleCoords.Y = newWidth / originalRatio + originalRectangle.Top; + } + break; case Positions.BottomRight: newWidth = resizeHandleCoords.X - originalRectangle.Left; newHeight = resizeHandleCoords.Y - originalRectangle.Top; newRatio = newWidth / newHeight; - flippedRatioSign = Math.Sign(newRatio) * Math.Sign(originalRatio); - - if (Math.Abs(newRatio) > Math.Abs(originalRatio)) { - // scaled rectangle (ratio) would be wider than original - // keep height and tweak width to maintain aspect ratio - float tweakedWidth = newHeight * originalRatio * flippedRatioSign; - resizeHandleCoords.X = originalRectangle.Left + tweakedWidth; - } - else if (Math.Abs(newRatio) < Math.Abs(originalRatio)) { - // TODO this is the same code as else if for topleft! - // scaled rectangle (ratio) would be taller than original - // keep width and tweak height to maintain aspect ratio - float tweakedHeight = newWidth / originalRatio * flippedRatioSign; - resizeHandleCoords.Y = originalRectangle.Top + tweakedHeight; - } - break; + if(newRatio > originalRatio) { + resizeHandleCoords.X = newHeight * originalRatio + originalRectangle.Left; + } else if(newRatio < originalRatio) { + resizeHandleCoords.Y = newWidth / originalRatio + originalRectangle.Top; + } + break; } } From 90cab1e8a3a0cdb568d01df71b25b374c7145196 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sun, 21 Mar 2021 17:48:54 +0100 Subject: [PATCH 100/232] Added CODE_OF_CONDUCT.md, CONTRIBUTING.md, .editorconfig and the LICENSE [skip ci] --- .editorconfig | 78 ++++++ CODE_OF_CONDUCT.md | 46 ++++ CONTRIBUTING.md | 18 ++ LICENSE | 674 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 816 insertions(+) create mode 100644 .editorconfig create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..f399b08bb --- /dev/null +++ b/.editorconfig @@ -0,0 +1,78 @@ +# EditorConfig is awesome:http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Don't use tabs for indentation. +[*] +indent_style = space +# (Please don't specify an indent_size here; that has too many unintended consequences.) + +# Code files +[*.{cs,csx,vb,vbx}] +indent_size = 4 + +# Xml project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# Xml config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true +# Avoid "this." and "Me." if not necessary +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# CSharp code style settings: +[*.cs] +# Prefer "var" everywhere +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion + +# Prefer method-like constructs to have a block body +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..638637e24 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at getgreenshot@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..abf5e0f03 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,18 @@ +The general rule we follow is "use Visual Studio defaults". + +1. We use [Allman style](http://en.wikipedia.org/wiki/Indent_style#Allman_style) braces, where each brace begins on a new line. A single line statement block can go without braces but the block must be properly indented on its own line and it must not be nested in other statement blocks that use braces (See issue [381](https://github.com/dotnet/corefx/issues/381) for examples). +2. We use four spaces of indentation (no tabs). +3. We use `_camelCase` for internal and private fields and use `readonly` where possible. Prefix instance fields with `_`, static fields with `s_` and thread static fields with `t_`. When used on static fields, `readonly` should come after `static` (e.g. `static readonly` not `readonly static`). +4. We avoid `this.` unless absolutely necessary. +5. We always specify the visibility, even if it's the default (e.g. `private string _foo` not `string _foo`). Visibility should be the first modifier (e.g. `public abstract` not `abstract public`). +6. Namespace imports should be specified at the top of the file, *outside* of `namespace` declarations and should be sorted alphabetically. +7. Avoid more than one empty line at any time. For example, do not have two blank lines between members of a type. +8. Avoid spurious free spaces. For example avoid `if (someVar == 0)...`, where the dots mark the spurious free spaces. Consider enabling "View White Space (Ctrl+E, S)" if using Visual Studio, to aid detection. +9. If a file happens to differ in style from these guidelines (e.g. private members are named `m_member` rather than `_member`), the existing style in that file takes precedence. +10. We only use `var` when it's obvious what the variable type is (e.g. `var stream = new FileStream(...)` not `var stream = OpenStandardInput()`). +11. We use language keywords instead of BCL types (e.g. `int, string, float` instead of `Int32, String, Single`, etc) for both type references as well as method calls (e.g. `int.Parse` instead of `Int32.Parse`). See issue [391](https://github.com/dotnet/corefx/issues/391) for examples. +12. We use PascalCasing to name all our constant local variables and fields. The only exception is for interop code where the constant value should exactly match the name and value of the code you are calling via interop. +13. We use ```nameof(...)``` instead of ```"..."``` whenever possible and relevant. +14. Fields should be specified at the top within type declarations. +15. When including non-ASCII characters in the source code use Unicode escape sequences (\uXXXX) instead of literal characters. Literal non-ASCII characters occasionally get garbled by a tool or editor. +16. Do not use labels (e.g. for goto). diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. From 26fe579d3147c228bc3b3786ae2af15bebabb149 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sun, 21 Mar 2021 22:34:17 +0100 Subject: [PATCH 101/232] Improved the support for dragging and dropping images from a website, now also parsing HTML img src information, to be able to download that image. For this we need the HtmlAgilityPack.dll (#294) Removed a lot of dead code, and remove the old OCR code as we don't even know if it still works. --- Greenshot.sln | 31 +- Greenshot/Configuration/LanguageKeys.cs | 171 +- Greenshot/Controls/MenuStripEx.cs | 2 - Greenshot/Drawing/LineContainer.cs | 4 +- Greenshot/Drawing/RoundedRectangle.cs | 23 +- Greenshot/Forms/ImageEditorForm.cs | 7 +- Greenshot/Forms/MainForm.cs | 7 +- Greenshot/Forms/ToolStripMenuSelectList.cs | 121 +- Greenshot/Helpers/EnvironmentInfo.cs | 69 - Greenshot/Helpers/GuiRectangle.cs | 21 +- Greenshot/Helpers/IECaptureHelper.cs | 10 +- Greenshot/Helpers/MailHelper.cs | 68 +- Greenshot/Helpers/ScaleHelper.cs | 61 +- Greenshot/Helpers/ToolStripItemEndisabler.cs | 12 +- Greenshot/Helpers/UpdateService.cs | 11 - Greenshot/releases/innosetup/setup.iss | 22 +- GreenshotBoxPlugin/BoxUtils.cs | 24 +- GreenshotBoxPlugin/LanguageKeys.cs | 7 +- GreenshotConfluencePlugin/LanguageKeys.cs | 7 - .../Support/TranslationManager.cs | 7 +- GreenshotDropboxPlugin/LanguageKeys.cs | 9 +- GreenshotFlickrPlugin/LanguageKeys.cs | 11 +- GreenshotImgurPlugin/LanguageKeys.cs | 8 - GreenshotJiraPlugin/AsyncMemoryCache.cs | 53 +- GreenshotJiraPlugin/JiraConfiguration.cs | 5 +- GreenshotJiraPlugin/LanguageKeys.cs | 8 - GreenshotOCRCommand/COMWrapper.cs | 513 ------ GreenshotOCRCommand/ComProgIdAttribute.cs | 78 - .../GreenshotOCRCommand.csproj | 14 - GreenshotOCRCommand/Modi/CompressionLevel.cs | 29 - GreenshotOCRCommand/Modi/FileFormat.cs | 30 - GreenshotOCRCommand/Modi/ICommon.cs | 32 - GreenshotOCRCommand/Modi/IDispatch.cs | 33 - GreenshotOCRCommand/Modi/IDocument.cs | 79 - GreenshotOCRCommand/Modi/IImage.cs | 41 - GreenshotOCRCommand/Modi/IImages.cs | 41 - GreenshotOCRCommand/Modi/ILayout.cs | 55 - GreenshotOCRCommand/Modi/IMiRect.cs | 48 - GreenshotOCRCommand/Modi/IMiRects.cs | 38 - GreenshotOCRCommand/Modi/IWord.cs | 65 - GreenshotOCRCommand/Modi/IWords.cs | 43 - GreenshotOCRCommand/Modi/ModiLanguage.cs | 48 - GreenshotOCRCommand/Program.cs | 121 -- .../Properties/AssemblyInfo.cs | 36 - GreenshotOCRCommand/app.config | 10 - GreenshotOCRPlugin/GreenshotOCRPlugin.csproj | 16 - .../Languages/language_ocrplugin-cs-CZ.xml | 8 - .../Languages/language_ocrplugin-de-DE.xml | 14 - .../Languages/language_ocrplugin-en-US.xml | 14 - .../Languages/language_ocrplugin-fr-FR.xml | 8 - .../Languages/language_ocrplugin-id-ID.xml | 8 - .../Languages/language_ocrplugin-it-IT.xml | 14 - .../Languages/language_ocrplugin-ja-JP.xml | 8 - .../Languages/language_ocrplugin-kab-DZ.xml | 8 - .../Languages/language_ocrplugin-ko-KR.xml | 14 - .../Languages/language_ocrplugin-lv-LV.xml | 15 - .../Languages/language_ocrplugin-nl-NL.xml | 14 - .../Languages/language_ocrplugin-pl-PL.xml | 8 - .../Languages/language_ocrplugin-pt-PT.xml | 8 - .../Languages/language_ocrplugin-ru-RU.xml | 8 - .../Languages/language_ocrplugin-sk-SK.xml | 14 - .../Languages/language_ocrplugin-sr-RS.xml | 8 - .../Languages/language_ocrplugin-sv-SE.xml | 14 - .../Languages/language_ocrplugin-uk-UA.xml | 8 - .../Languages/language_ocrplugin-zh-CN.xml | 14 - .../Languages/language_ocrplugin-zh-TW.xml | 8 - GreenshotOCRPlugin/ModiLanguage.cs | 50 - GreenshotOCRPlugin/OCRConfiguration.cs | 37 - GreenshotOCRPlugin/OCRDestination.cs | 60 - GreenshotOCRPlugin/OCRForm.cs | 30 - GreenshotOCRPlugin/OCRPlugin.cs | 206 --- GreenshotOCRPlugin/SettingsForm.Designer.cs | 146 -- GreenshotOCRPlugin/SettingsForm.cs | 65 - GreenshotOfficePlugin/Com/Ole32Api.cs | 24 - GreenshotPhotobucketPlugin/LanguageKeys.cs | 5 - GreenshotPlugin/Controls/BackgroundForm.cs | 18 +- GreenshotPlugin/Controls/HotkeyControl.cs | 22 +- GreenshotPlugin/Core/AccessibleHelper.cs | 90 +- GreenshotPlugin/Core/Capture.cs | 32 +- GreenshotPlugin/Core/CaptureDetails.cs | 21 + GreenshotPlugin/Core/CaptureElement.cs | 48 - GreenshotPlugin/Core/ClipboardHelper.cs | 246 +-- GreenshotPlugin/Core/CoreConfiguration.cs | 20 +- GreenshotPlugin/Core/CredentialsHelper.cs | 67 +- GreenshotPlugin/Core/DpiHelper.cs | 578 +------ GreenshotPlugin/Core/EnumExtensions.cs | 102 -- .../Core/Enums/DialogDpiChangeBehaviors.cs | 34 - .../Core/Enums/DialogScalingBehaviors.cs | 32 - GreenshotPlugin/Core/Enums/DpiAwareness.cs | 40 - .../Core/Enums/DpiAwarenessContext.cs | 46 - .../Core/Enums/DpiHostingBehavior.cs | 28 - .../Core/Enums/SystemParametersInfoActions.cs | 1390 ----------------- .../Enums/SystemParametersInfoBehaviors.cs | 28 - GreenshotPlugin/Core/FastBitmap.cs | 11 +- GreenshotPlugin/Core/HResultExtensions.cs | 17 +- GreenshotPlugin/Core/ImageWrapper.cs | 10 - GreenshotPlugin/Core/InterfaceUtils.cs | 50 +- GreenshotPlugin/Core/Language.cs | 27 +- GreenshotPlugin/Core/NetworkHelper.cs | 301 +--- GreenshotPlugin/Core/OAuthHelper.cs | 16 +- GreenshotPlugin/Core/PluginUtils.cs | 69 +- GreenshotPlugin/Core/StringExtensions.cs | 16 +- GreenshotPlugin/Core/WindowDetails.cs | 131 +- GreenshotPlugin/Core/WindowsEnumerator.cs | 22 +- GreenshotPlugin/Core/WindowsVersion.cs | 57 - GreenshotPlugin/FileDescriptorReader.cs | 192 +++ GreenshotPlugin/GreenshotPlugin.csproj | 1 + .../Interfaces/Drawing/IFieldholder.cs | 17 - .../Interfaces/Forms/ImageEditor.cs | 9 +- GreenshotPlugin/Interfaces/ICaptureElement.cs | 41 - GreenshotPlugin/Interop/COMWrapper.cs | 120 +- GreenshotPlugin/UnmanagedHelpers/DWM.cs | 15 +- .../UnmanagedHelpers/Enums/ClassLongIndex.cs | 23 +- .../Enums/DWMWINDOWATTRIBUTE.cs | 14 - .../UnmanagedHelpers/Enums/DWM_BB.cs | 34 - .../UnmanagedHelpers/Enums/DWM_BLURBEHIND.cs | 34 - .../Enums/DesktopAccessRight.cs | 23 +- .../UnmanagedHelpers/Enums/DeviceCaps.cs | 23 +- .../UnmanagedHelpers/Enums/EventObjects.cs | 23 +- .../Enums/ExtendedWindowStyleFlags.cs | 23 +- .../Enums/GetWindowCommand.cs | 23 +- .../Enums/ProcessAccessFlags.cs | 23 +- .../UnmanagedHelpers/Enums/RegionResult.cs | 23 +- .../UnmanagedHelpers/Enums/SYSCOLOR.cs | 61 - .../Enums/ScrollBarDirection.cs | 13 - .../UnmanagedHelpers/Enums/ScrollInfoMask.cs | 14 - .../Enums/ScrollbarCommand.cs | 18 - .../Enums/SendMessageTimeoutFlags.cs | 23 +- .../Enums/ShowWindowCommand.cs | 23 +- .../UnmanagedHelpers/Enums/SoundFlags.cs | 23 +- .../UnmanagedHelpers/Enums/SystemMetric.cs | 392 ----- .../UnmanagedHelpers/Enums/ThreadAccess.cs | 31 +- .../UnmanagedHelpers/Enums/Win32Error.cs | 23 +- .../UnmanagedHelpers/Enums/WinEvent.cs | 61 +- .../UnmanagedHelpers/Enums/WindowLongIndex.cs | 23 +- .../Enums/WindowPlacementFlags.cs | 23 +- .../UnmanagedHelpers/Enums/WindowPos.cs | 35 +- .../UnmanagedHelpers/Enums/WindowsMessages.cs | 920 +---------- GreenshotPlugin/UnmanagedHelpers/GDI32.cs | 38 +- GreenshotPlugin/UnmanagedHelpers/Kernel32.cs | 5 +- GreenshotPlugin/UnmanagedHelpers/Shell32.cs | 95 +- .../UnmanagedHelpers/Structs/CursorInfo.cs | 23 +- .../UnmanagedHelpers/Structs/IconInfo.cs | 23 +- .../UnmanagedHelpers/Structs/POINT.cs | 23 +- .../UnmanagedHelpers/Structs/RECT.cs | 23 +- .../UnmanagedHelpers/Structs/RECTF.cs | 23 +- .../UnmanagedHelpers/Structs/SCROLLINFO.cs | 23 +- .../UnmanagedHelpers/Structs/WindowInfo.cs | 23 +- .../Structs/WindowPlacement.cs | 23 +- GreenshotPlugin/UnmanagedHelpers/User32.cs | 76 +- GreenshotPlugin/UnmanagedHelpers/Win32.cs | 14 +- 151 files changed, 1138 insertions(+), 8174 deletions(-) delete mode 100644 GreenshotOCRCommand/COMWrapper.cs delete mode 100644 GreenshotOCRCommand/ComProgIdAttribute.cs delete mode 100644 GreenshotOCRCommand/GreenshotOCRCommand.csproj delete mode 100644 GreenshotOCRCommand/Modi/CompressionLevel.cs delete mode 100644 GreenshotOCRCommand/Modi/FileFormat.cs delete mode 100644 GreenshotOCRCommand/Modi/ICommon.cs delete mode 100644 GreenshotOCRCommand/Modi/IDispatch.cs delete mode 100644 GreenshotOCRCommand/Modi/IDocument.cs delete mode 100644 GreenshotOCRCommand/Modi/IImage.cs delete mode 100644 GreenshotOCRCommand/Modi/IImages.cs delete mode 100644 GreenshotOCRCommand/Modi/ILayout.cs delete mode 100644 GreenshotOCRCommand/Modi/IMiRect.cs delete mode 100644 GreenshotOCRCommand/Modi/IMiRects.cs delete mode 100644 GreenshotOCRCommand/Modi/IWord.cs delete mode 100644 GreenshotOCRCommand/Modi/IWords.cs delete mode 100644 GreenshotOCRCommand/Modi/ModiLanguage.cs delete mode 100644 GreenshotOCRCommand/Program.cs delete mode 100644 GreenshotOCRCommand/Properties/AssemblyInfo.cs delete mode 100644 GreenshotOCRCommand/app.config delete mode 100644 GreenshotOCRPlugin/GreenshotOCRPlugin.csproj delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-cs-CZ.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-de-DE.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-en-US.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-fr-FR.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-id-ID.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-it-IT.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-ja-JP.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-kab-DZ.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-ko-KR.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-lv-LV.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-nl-NL.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-pl-PL.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-pt-PT.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-ru-RU.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-sk-SK.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-sr-RS.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-sv-SE.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-uk-UA.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-zh-CN.xml delete mode 100644 GreenshotOCRPlugin/Languages/language_ocrplugin-zh-TW.xml delete mode 100644 GreenshotOCRPlugin/ModiLanguage.cs delete mode 100644 GreenshotOCRPlugin/OCRConfiguration.cs delete mode 100644 GreenshotOCRPlugin/OCRDestination.cs delete mode 100644 GreenshotOCRPlugin/OCRForm.cs delete mode 100644 GreenshotOCRPlugin/OCRPlugin.cs delete mode 100644 GreenshotOCRPlugin/SettingsForm.Designer.cs delete mode 100644 GreenshotOCRPlugin/SettingsForm.cs delete mode 100644 GreenshotPlugin/Core/CaptureElement.cs delete mode 100644 GreenshotPlugin/Core/EnumExtensions.cs delete mode 100644 GreenshotPlugin/Core/Enums/DialogDpiChangeBehaviors.cs delete mode 100644 GreenshotPlugin/Core/Enums/DialogScalingBehaviors.cs delete mode 100644 GreenshotPlugin/Core/Enums/DpiAwareness.cs delete mode 100644 GreenshotPlugin/Core/Enums/DpiAwarenessContext.cs delete mode 100644 GreenshotPlugin/Core/Enums/DpiHostingBehavior.cs delete mode 100644 GreenshotPlugin/Core/Enums/SystemParametersInfoActions.cs delete mode 100644 GreenshotPlugin/Core/Enums/SystemParametersInfoBehaviors.cs create mode 100644 GreenshotPlugin/FileDescriptorReader.cs delete mode 100644 GreenshotPlugin/Interfaces/ICaptureElement.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BB.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BLURBEHIND.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/Enums/SYSCOLOR.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/Enums/ScrollBarDirection.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/Enums/ScrollInfoMask.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/Enums/ScrollbarCommand.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/Enums/SystemMetric.cs diff --git a/Greenshot.sln b/Greenshot.sln index 27df62d85..1c0d74d59 100644 --- a/Greenshot.sln +++ b/Greenshot.sln @@ -14,10 +14,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Gree {697CF066-9077-4F22-99D9-D989CCE7282B} = {697CF066-9077-4F22-99D9-D989CCE7282B} {47F23C86-604E-4CC3-8767-B3D4088F30BB} = {47F23C86-604E-4CC3-8767-B3D4088F30BB} {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} = {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02} = {D61E6ECE-E0B6-4467-B492-F08A06BA8F02} {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} = {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} {1893A2E4-A78A-4713-A8E7-E70058DABEE0} = {1893A2E4-A78A-4713-A8E7-E70058DABEE0} - {C6988EE8-2FEE-4349-9F09-F9628A0D8965} = {C6988EE8-2FEE-4349-9F09-F9628A0D8965} EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPlugin", "GreenshotPlugin\GreenshotPlugin.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" @@ -30,13 +28,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotImgurPlugin", "Gre EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotJiraPlugin", "GreenshotJiraPlugin\GreenshotJiraPlugin.csproj", "{19FEEF09-313F-43C7-819D-F1BCA782B08B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotOCRPlugin", "GreenshotOCRPlugin\GreenshotOCRPlugin.csproj", "{C6988EE8-2FEE-4349-9F09-F9628A0D8965}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotOCRCommand", "GreenshotOCRCommand\GreenshotOCRCommand.csproj", "{D61E6ECE-E0B6-4467-B492-F08A06BA8F02}" - ProjectSection(ProjectDependencies) = postProject - {C6988EE8-2FEE-4349-9F09-F9628A0D8965} = {C6988EE8-2FEE-4349-9F09-F9628A0D8965} - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotBoxPlugin", "GreenshotBoxPlugin\GreenshotBoxPlugin.csproj", "{697CF066-9077-4F22-99D9-D989CCE7282B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotDropboxPlugin", "GreenshotDropboxPlugin\GreenshotDropboxPlugin.csproj", "{AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}" @@ -51,6 +42,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPhotobucketPlugin" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotWin10Plugin", "GreenshotWin10Plugin\GreenshotWin10Plugin.csproj", "{9801F62C-540F-4BFE-9211-6405DEDE563B}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{82987F1E-D7E6-4C44-B934-981D366E4672}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + azure-pipelines.yml = azure-pipelines.yml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -107,22 +104,6 @@ Global {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.Build.0 = Release|Any CPU {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.ActiveCfg = Release|Any CPU {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.Build.0 = Release|Any CPU - {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|x86.ActiveCfg = Debug|Any CPU - {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Debug|x86.Build.0 = Debug|Any CPU - {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|Any CPU.Build.0 = Release|Any CPU - {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|x86.ActiveCfg = Release|Any CPU - {C6988EE8-2FEE-4349-9F09-F9628A0D8965}.Release|x86.Build.0 = Release|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Debug|x86.ActiveCfg = Debug|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Debug|x86.Build.0 = Debug|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Release|Any CPU.Build.0 = Release|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Release|x86.ActiveCfg = Release|Any CPU - {D61E6ECE-E0B6-4467-B492-F08A06BA8F02}.Release|x86.Build.0 = Release|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.Build.0 = Debug|Any CPU {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.ActiveCfg = Debug|Any CPU diff --git a/Greenshot/Configuration/LanguageKeys.cs b/Greenshot/Configuration/LanguageKeys.cs index 022f141f1..a668218eb 100644 --- a/Greenshot/Configuration/LanguageKeys.cs +++ b/Greenshot/Configuration/LanguageKeys.cs @@ -25,219 +25,56 @@ namespace Greenshot.Configuration { [SuppressMessage("ReSharper", "InconsistentNaming")] public enum LangKey { none, - about_bugs, - about_donations, - about_host, - about_icons, - about_license, - about_title, - about_translation, - application_title, - bugreport_cancel, - bugreport_info, - bugreport_title, - clipboard_error, - clipboard_inuse, - colorpicker_alpha, - colorpicker_apply, - colorpicker_blue, - colorpicker_green, - colorpicker_htmlcolor, - colorpicker_recentcolors, - colorpicker_red, - colorpicker_title, - colorpicker_transparent, - config_unauthorizedaccess_write, - contextmenu_about, - contextmenu_capturearea, - contextmenu_captureclipboard, - contextmenu_capturefullscreen, - contextmenu_capturefullscreen_all, + contextmenu_capturefullscreen_all, contextmenu_capturefullscreen_left, contextmenu_capturefullscreen_top, contextmenu_capturefullscreen_right, contextmenu_capturefullscreen_bottom, - contextmenu_capturelastregion, - contextmenu_capturewindow, - contextmenu_donate, - contextmenu_exit, - contextmenu_help, - contextmenu_openfile, - contextmenu_quicksettings, - contextmenu_settings, - contextmenu_captureie, - contextmenu_openrecentcapture, - editor_align_bottom, - editor_align_center, - editor_align_horizontal, - editor_align_middle, - editor_align_left, - editor_align_right, - editor_align_top, - editor_align_vertical, - editor_arrange, - editor_arrowheads, - editor_arrowheads_both, - editor_arrowheads_end, - editor_arrowheads_none, - editor_arrowheads_start, - editor_backcolor, - editor_blur_radius, - editor_bold, - editor_brightness, - editor_cancel, - editor_clipboardfailed, - editor_close, + contextmenu_captureie, + editor_clipboardfailed, editor_close_on_save, editor_close_on_save_title, - editor_confirm, - editor_copyimagetoclipboard, - editor_copypathtoclipboard, editor_copytoclipboard, - editor_crop, - editor_cursortool, editor_cuttoclipboard, editor_deleteelement, editor_downonelevel, editor_downtobottom, - editor_drawarrow, - editor_drawellipse, - editor_drawhighlighter, - editor_drawline, - editor_drawfreehand, - editor_drawrectangle, - editor_drawtextbox, editor_duplicate, - editor_edit, editor_email, - editor_file, - editor_fontsize, - editor_forecolor, - editor_highlight_area, - editor_highlight_grayscale, - editor_highlight_mode, - editor_highlight_text, - editor_highlight_magnify, - editor_pixel_size, editor_imagesaved, - editor_italic, - editor_load_objects, - editor_magnification_factor, - editor_match_capture_size, - editor_obfuscate, - editor_obfuscate_blur, - editor_obfuscate_mode, - editor_obfuscate_pixelize, - editor_object, - editor_opendirinexplorer, - editor_pastefromclipboard, - editor_preview_quality, - editor_print, - editor_save, - editor_save_objects, - editor_saveas, - editor_selectall, - editor_senttoprinter, - editor_shadow, - editor_torn_edge, - editor_border, - editor_grayscale, - editor_effects, - editor_storedtoclipboard, - editor_thickness, editor_title, editor_uponelevel, editor_uptotop, - editor_autocrop, editor_undo, editor_redo, - editor_insertwindow, editor_resetsize, error, error_multipleinstances, - error_nowriteaccess, error_openfile, error_openlink, error_save, error_save_invalid_chars, - help_title, - jpegqualitydialog_choosejpegquality, - qualitydialog_dontaskagain, - qualitydialog_title, - settings_reducecolors, print_error, - printoptions_allowcenter, - printoptions_allowenlarge, - printoptions_allowrotate, - printoptions_allowshrink, - printoptions_colors, - printoptions_dontaskagain, - printoptions_pagelayout, - printoptions_printcolor, - printoptions_printgrayscale, - printoptions_printmonochrome, - printoptions_timestamp, - printoptions_inverted, - printoptions_title, quicksettings_destination_file, - settings_alwaysshowqualitydialog, - settings_alwaysshowprintoptionsdialog, - settings_applicationsettings, - settings_autostartshortcut, - settings_capture, - settings_capture_mousepointer, - settings_capture_windows_interactive, - settings_copypathtoclipboard, settings_destination, settings_destination_clipboard, settings_destination_editor, - settings_destination_email, - settings_destination_file, settings_destination_fileas, settings_destination_printer, settings_destination_picker, - settings_editor, settings_filenamepattern, - settings_general, - settings_iecapture, - settings_jpegquality, - settings_qualitysettings, - settings_language, settings_message_filenamepattern, - settings_output, - settings_playsound, - settings_plugins, - settings_plugins_name, - settings_plugins_version, - settings_plugins_createdby, - settings_plugins_dllpath, - settings_preferredfilesettings, - settings_primaryimageformat, - settings_printer, settings_printoptions, - settings_registerhotkeys, - settings_showflashlight, - settings_storagelocation, - settings_title, settings_tooltip_filenamepattern, settings_tooltip_language, settings_tooltip_primaryimageformat, - settings_tooltip_registerhotkeys, settings_tooltip_storagelocation, settings_visualization, - settings_shownotify, - settings_waittime, - settings_windowscapture, settings_window_capture_mode, - settings_network, - settings_checkperiod, - settings_usedefaultproxy, tooltip_firststart, warning, warning_hotkeys, - hotkeys, wait_ie_capture, - update_found, - exported_to + update_found } } diff --git a/Greenshot/Controls/MenuStripEx.cs b/Greenshot/Controls/MenuStripEx.cs index 31aa8f190..7dda22931 100644 --- a/Greenshot/Controls/MenuStripEx.cs +++ b/Greenshot/Controls/MenuStripEx.cs @@ -28,8 +28,6 @@ namespace Greenshot.Controls { /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx /// </summary> public class MenuStripEx : MenuStrip { - private const int WM_MOUSEACTIVATE = 0x21; - private enum NativeConstants : uint { MA_ACTIVATE = 1, MA_ACTIVATEANDEAT = 2, diff --git a/Greenshot/Drawing/LineContainer.cs b/Greenshot/Drawing/LineContainer.cs index eac855644..93b76ad89 100644 --- a/Greenshot/Drawing/LineContainer.cs +++ b/Greenshot/Drawing/LineContainer.cs @@ -34,9 +34,7 @@ namespace Greenshot.Drawing { /// </summary> [Serializable()] public class LineContainer : DrawableContainer { - public static readonly int MAX_CLICK_DISTANCE_TOLERANCE = 10; - - public LineContainer(Surface parent) : base(parent) { + public LineContainer(Surface parent) : base(parent) { Init(); } diff --git a/Greenshot/Drawing/RoundedRectangle.cs b/Greenshot/Drawing/RoundedRectangle.cs index a5d4ea6a0..ce40d6e82 100644 --- a/Greenshot/Drawing/RoundedRectangle.cs +++ b/Greenshot/Drawing/RoundedRectangle.cs @@ -20,7 +20,6 @@ */ using System; -using System.Drawing; using System.Drawing.Drawing2D; namespace Greenshot.Drawing { @@ -111,25 +110,13 @@ namespace Greenshot.Drawing { p.CloseFigure(); return p; } - - public static GraphicsPath Create(Rectangle rect, int radius, RectangleCorners corners) { - return Create(rect.X, rect.Y, rect.Width, rect.Height, radius, corners); - } - - public static GraphicsPath Create(int x, int y, int width, int height, int radius) { + + public static GraphicsPath Create(int x, int y, int width, int height, int radius) { return Create(x, y, width, height, radius, RectangleCorners.All); } - - public static GraphicsPath Create(Rectangle rect, int radius) { - return Create(rect.X, rect.Y, rect.Width, rect.Height, radius); - } - - public static GraphicsPath Create(int x, int y, int width, int height) { + + public static GraphicsPath Create(int x, int y, int width, int height) { return Create(x, y, width, height, 5); } - - public static GraphicsPath Create(Rectangle rect) { - return Create(rect.X, rect.Y, rect.Width, rect.Height); - } - } + } } diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index a9fe79239..ba72fc96c 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -73,12 +73,7 @@ namespace Greenshot.Forms { /// </summary> private readonly Fraction[] ZOOM_VALUES = new Fraction[] { (1, 4), (1, 2), (2, 3), (3, 4), (1 ,1), (2, 1), (3, 1), (4, 1), (6, 1) }; - /// <summary> - /// An Implementation for the IImageEditor, this way Plugins have access to the HWND handles wich can be used with Win32 API calls. - /// </summary> - public IWin32Window WindowHandle => this; - - public static List<IImageEditor> Editors { + public static List<IImageEditor> Editors { get { try { EditorList.Sort((e1, e2) => string.Compare(e1.Surface.CaptureDetails.Title, e2.Surface.CaptureDetails.Title, StringComparison.Ordinal)); diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index 4053b41f5..ccb6b9a4f 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -486,12 +486,7 @@ namespace Greenshot.Forms { } } - /// <summary> - /// Main context menu - /// </summary> - public ContextMenuStrip MainMenu => contextMenu; - - protected override void WndProc(ref Message m) { + protected override void WndProc(ref Message m) { if (HotkeyControl.HandleMessages(ref m)) { return; } diff --git a/Greenshot/Forms/ToolStripMenuSelectList.cs b/Greenshot/Forms/ToolStripMenuSelectList.cs index 4ddfe7cdd..e61cb58b2 100644 --- a/Greenshot/Forms/ToolStripMenuSelectList.cs +++ b/Greenshot/Forms/ToolStripMenuSelectList.cs @@ -22,7 +22,6 @@ using GreenshotPlugin.Core; using System; using System.Collections; -using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using GreenshotPlugin.IniFile; @@ -57,77 +56,8 @@ namespace Greenshot.Forms { Image = _defaultImage; } public ToolStripMenuSelectList() : this(null,false) {} - public ToolStripMenuSelectList(object identifier) : this(identifier,false) {} - /// <summary> - /// gets or sets the currently checked item - /// </summary> - public ToolStripMenuSelectListItem CheckedItem { - - get { - IEnumerator items = DropDownItems.GetEnumerator(); - while (items.MoveNext()) { - ToolStripMenuSelectListItem tsmi = (ToolStripMenuSelectListItem)items.Current; - if (tsmi != null && tsmi.Checked) { - return tsmi; - } - } - return null; - } - set { - IEnumerator items = DropDownItems.GetEnumerator(); - while (items.MoveNext()) { - ToolStripMenuSelectListItem tsmi = (ToolStripMenuSelectListItem)items.Current; - if (tsmi != null && !_multiCheckAllowed && !tsmi.Equals(value)) { - tsmi.Checked = false; - } else if (tsmi != null && tsmi.Equals(value)) { - tsmi.Checked = true; - } - } - } - } - - /// <summary> - /// gets or sets the currently checked items - /// </summary> - public ToolStripMenuSelectListItem[] CheckedItems { - get { - List<ToolStripMenuSelectListItem> sel = new List<ToolStripMenuSelectListItem>(); - IEnumerator items = DropDownItems.GetEnumerator(); - while(items.MoveNext()) { - ToolStripMenuSelectListItem tsmi = (ToolStripMenuSelectListItem)items.Current; - if (tsmi != null && tsmi.Checked) { - sel.Add(tsmi); - } - } - return sel.ToArray(); - } - set { - if (!_multiCheckAllowed) { - throw new ArgumentException("Writing to checkedItems is only allowed in multi-check mode. Either set allowMultiCheck to true or use set SelectedItem instead of SelectedItems."); - } - IEnumerator items = DropDownItems.GetEnumerator(); - IEnumerator sel = value.GetEnumerator(); - while (items.MoveNext()) { - var toolStripMenuSelectListItem = (ToolStripMenuSelectListItem)items.Current; - if (toolStripMenuSelectListItem == null) - { - continue; - } - while (sel.MoveNext()) - { - toolStripMenuSelectListItem.Checked = toolStripMenuSelectListItem.Equals(sel.Current); - if (!_multiCheckAllowed && !toolStripMenuSelectListItem.Equals(sel.Current)) { - toolStripMenuSelectListItem.Checked = false; - } else if (toolStripMenuSelectListItem.Equals(value)) { - toolStripMenuSelectListItem.Checked = true; - } - } - } - } - } - - private void ItemCheckStateChanged(object sender, EventArgs e) { + private void ItemCheckStateChanged(object sender, EventArgs e) { if (_updateInProgress) { return; } @@ -172,44 +102,8 @@ namespace Greenshot.Forms { DropDownItems.Add(toolStripMenuSelectListItem); } - /// <summary> - /// adds an item to the select list - /// </summary> - /// <param name="label">the label to be displayed</param> - /// <param name="image">the icon to be displayed</param> - public void AddItem(string label, Image image) { - AddItem(label, image, null, false); - } - /// <summary> - /// adds an item to the select list - /// </summary> - /// <param name="label">the label to be displayed</param> - /// <param name="data">the data to be returned when an item is queried</param> - public void AddItem(string label, object data) { - AddItem(label, null, data, false); - } - - /// <summary> - /// adds an item to the select list - /// </summary> - /// <param name="label">the label to be displayed</param> - public void AddItem(string label) { - AddItem(label, null, null, false); - } - - - /// <summary> - /// adds an item to the select list - /// </summary> - /// <param name="label">the label to be displayed</param> - /// <param name="image">the icon to be displayed</param> - /// <param name="isChecked">whether the item is initially checked</param> - public void AddItem(string label, Image image, bool isChecked) { - AddItem(label, image, null, isChecked); - } - - /// <summary> + /// <summary> /// adds an item to the select list /// </summary> /// <param name="label">the label to be displayed</param> @@ -219,16 +113,7 @@ namespace Greenshot.Forms { AddItem(label, null, data, isChecked); } - /// <summary> - /// adds an item to the select list - /// </summary> - /// <param name="label">the label to be displayed</param> - /// <param name="isChecked">whether the item is initially checked</param> - public void AddItem(string label, bool isChecked) { - AddItem(label, null, null, isChecked); - } - - /// <summary> + /// <summary> /// unchecks all items of the list /// </summary> public void UncheckAll() { diff --git a/Greenshot/Helpers/EnvironmentInfo.cs b/Greenshot/Helpers/EnvironmentInfo.cs index cc88802aa..9d8006416 100644 --- a/Greenshot/Helpers/EnvironmentInfo.cs +++ b/Greenshot/Helpers/EnvironmentInfo.cs @@ -647,26 +647,6 @@ namespace Greenshot.Helpers private readonly byte _wProductType; private readonly byte _wReserved; - /// <summary> - /// The major version number of the operating system. - /// </summary> - public int MajorVersion => _dwMajorVersion; - - /// <summary> - /// The minor version number of the operating system. - /// </summary> - public int MinorVersion => _dwMinorVersion; - - /// <summary> - /// The build number of the operating system. - /// </summary> - public int BuildNumber => _dwBuildNumber; - - /// <summary> - /// The operating system platform. This member can be VER_PLATFORM_WIN32_NT (2). - /// </summary> - public int PlatformId => _dwPlatformId; - /// <summary> /// A null-terminated string, such as "Service Pack 3", that indicates the latest Service Pack installed on the system. /// If no Service Pack has been installed, the string is empty. @@ -784,11 +764,6 @@ namespace Greenshot.Helpers } } - /// <summary> - /// Gets the build version number of the operating system running on this computer. - /// </summary> - public static int BuildVersion => Environment.OSVersion.Version.Build; - /// <summary> /// Gets the full version string of the operating system running on this computer. /// </summary> @@ -807,49 +782,5 @@ namespace Greenshot.Helpers return $"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor} build {Environment.OSVersion.Version.Build}"; } } - - /// <summary> - /// Gets the full version of the operating system running on this computer. - /// </summary> - public static Version Version - { - get - { - return Environment.OSVersion.Version; - } - } - - /// <summary> - /// Gets the major version number of the operating system running on this computer. - /// </summary> - public static int MajorVersion - { - get - { - return Environment.OSVersion.Version.Major; - } - } - - /// <summary> - /// Gets the minor version number of the operating system running on this computer. - /// </summary> - public static int MinorVersion - { - get - { - return Environment.OSVersion.Version.Minor; - } - } - - /// <summary> - /// Gets the revision version number of the operating system running on this computer. - /// </summary> - public static int RevisionVersion - { - get - { - return Environment.OSVersion.Version.Revision; - } - } } } \ No newline at end of file diff --git a/Greenshot/Helpers/GuiRectangle.cs b/Greenshot/Helpers/GuiRectangle.cs index c24e591ec..108c5a48e 100644 --- a/Greenshot/Helpers/GuiRectangle.cs +++ b/Greenshot/Helpers/GuiRectangle.cs @@ -28,7 +28,7 @@ namespace Greenshot.Helpers { public static class GuiRectangle { public static Rectangle GetGuiRectangle(int x, int y, int w, int h) { - Rectangle rect = new Rectangle(x, y, w, h); + var rect = new Rectangle(x, y, w, h); MakeGuiRectangle(ref rect); return rect; } @@ -43,22 +43,5 @@ namespace Greenshot.Helpers { rect.Height = -rect.Height; } } - - public static RectangleF GetGuiRectangleF(float x, float y, float w, float h) { - RectangleF rect = new RectangleF(x, y, w, h); - MakeGuiRectangleF(ref rect); - return rect; - } - - public static void MakeGuiRectangleF(ref RectangleF rect) { - if (rect.Width < 0) { - rect.X += rect.Width; - rect.Width = -rect.Width; - } - if (rect.Height < 0) { - rect.Y += rect.Height; - rect.Height = -rect.Height; - } - } - } + } } diff --git a/Greenshot/Helpers/IECaptureHelper.cs b/Greenshot/Helpers/IECaptureHelper.cs index f74403176..5922d6474 100644 --- a/Greenshot/Helpers/IECaptureHelper.cs +++ b/Greenshot/Helpers/IECaptureHelper.cs @@ -321,15 +321,7 @@ namespace Greenshot.Helpers { return returnDocumentContainer; } - /// <summary> - /// Here the logic for capturing the IE Content is located - /// </summary> - /// <param name="capture">ICapture where the capture needs to be stored</param> - /// <returns>ICapture with the content (if any)</returns> - public static ICapture CaptureIe(ICapture capture) { - return CaptureIe(capture, WindowDetails.GetActiveWindow()); - } - /// <summary> + /// <summary> /// Here the logic for capturing the IE Content is located /// </summary> /// <param name="capture">ICapture where the capture needs to be stored</param> diff --git a/Greenshot/Helpers/MailHelper.cs b/Greenshot/Helpers/MailHelper.cs index 3bc09b5f8..2ba02461e 100644 --- a/Greenshot/Helpers/MailHelper.cs +++ b/Greenshot/Helpers/MailHelper.cs @@ -126,14 +126,7 @@ namespace Greenshot.Helpers { _manualResetEvent = new ManualResetEvent(false); } - /// <summary> - /// Creates a new mail message with the specified subject. - /// </summary> - public MapiMailMessage(string subject) : this() { - Subject = subject; - } - - /// <summary> + /// <summary> /// Creates a new mail message with the specified subject and body. /// </summary> public MapiMailMessage(string subject, string body) : this() { @@ -437,21 +430,6 @@ namespace Greenshot.Helpers { public MapiMailMessage.RecipientType RecipientType = MapiMailMessage.RecipientType.To; /// <summary> - /// Creates a new recipient with the specified address. - /// </summary> - public Recipient(string address) { - Address = address; - } - - /// <summary> - /// Creates a new recipient with the specified address and display name. - /// </summary> - public Recipient(string address, string displayName) { - Address = address; - DisplayName = displayName; - } - - /// <summary> /// Creates a new recipient with the specified address and recipient type. /// </summary> public Recipient(string address, MapiMailMessage.RecipientType recipientType) { @@ -459,15 +437,6 @@ namespace Greenshot.Helpers { RecipientType = recipientType; } - /// <summary> - /// Creates a new recipient with the specified address, display name and recipient type. - /// </summary> - public Recipient(string address, string displayName, MapiMailMessage.RecipientType recipientType) { - Address = address; - DisplayName = displayName; - RecipientType = recipientType; - } - /// <summary> /// Returns an interop representation of a recepient. /// </summary> @@ -499,40 +468,7 @@ namespace Greenshot.Helpers { List.Add(value); } - /// <summary> - /// Adds a new recipient with the specified address to this collection. - /// </summary> - public void Add(string address) { - Add(new Recipient(address)); - } - - /// <summary> - /// Adds a new recipient with the specified address and display name to this collection. - /// </summary> - public void Add(string address, string displayName) { - Add(new Recipient(address, displayName)); - } - - /// <summary> - /// Adds a new recipient with the specified address and recipient type to this collection. - /// </summary> - public void Add(string address, MapiMailMessage.RecipientType recipientType) { - Add(new Recipient(address, recipientType)); - } - - /// <summary> - /// Adds a new recipient with the specified address, display name and recipient type to this collection. - /// </summary> - public void Add(string address, string displayName, MapiMailMessage.RecipientType recipientType) { - Add(new Recipient(address, displayName, recipientType)); - } - - /// <summary> - /// Returns the recipient stored in this collection at the specified index. - /// </summary> - public Recipient this[int index] => (Recipient)List[index]; - - internal InteropRecipientCollection GetInteropRepresentation() { + internal InteropRecipientCollection GetInteropRepresentation() { return new InteropRecipientCollection(this); } diff --git a/Greenshot/Helpers/ScaleHelper.cs b/Greenshot/Helpers/ScaleHelper.cs index 76e0091c6..43a2ca3e9 100644 --- a/Greenshot/Helpers/ScaleHelper.cs +++ b/Greenshot/Helpers/ScaleHelper.cs @@ -101,34 +101,8 @@ namespace Greenshot.Helpers { } return newRect; } - - /// <summary> - /// calculates the Rectangle an element must be resized an positioned to, in ordder to fit another element, keeping aspect ratio - /// </summary> - /// <param name="currentRect">the rectangle of the element to be resized/repositioned</param> - /// <param name="targetRect">the target size/position of the element</param> - /// <param name="crop">in case the aspect ratio of currentSize and targetSize differs: shall the scaled size fit into targetSize (i.e. that one of its dimensions is smaller - false) or vice versa (true)</param> - /// <param name="alignment">the System.Drawing.ContentAlignment value indicating how the element is to be aligned should the width or height differ from targetSize</param> - /// <returns>a new RectangleF object indicating the width and height the element should be scaled to and the position that should be applied to it for proper alignment</returns> - public static RectangleF GetScaledRectangle(RectangleF currentRect, RectangleF targetRect, bool crop, ContentAlignment alignment) { - SizeF newSize = GetScaledSize(currentRect.Size, targetRect.Size, crop); - RectangleF newRect = new RectangleF(new Point(0,0), newSize); - return GetAlignedRectangle(newRect, targetRect, alignment); - } - - public static void RationalScale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) { - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords, ScaleOptions.Rational); - } - - public static void CenteredScale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) { - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords, ScaleOptions.Centered); - } - - public static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) { - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords, null); - } - - /// <summary> + + /// <summary> /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) /// </summary> /// <param name="originalRectangle">bounds of the current rectangle, scaled values will be written to this reference</param> @@ -139,7 +113,7 @@ namespace Greenshot.Helpers { options ??= GetScaleOptions(); if ((options & ScaleOptions.Rational) == ScaleOptions.Rational) { - adjustCoordsForRationalScale(originalRectangle, resizeHandlePosition, ref resizeHandleCoords); + AdjustCoordsForRationalScale(originalRectangle, resizeHandlePosition, ref resizeHandleCoords); } if ((options & ScaleOptions.Centered) == ScaleOptions.Centered) { @@ -147,15 +121,15 @@ namespace Greenshot.Helpers { float rectCenterX = originalRectangle.Left + originalRectangle.Width / 2; float rectCenterY = originalRectangle.Top + originalRectangle.Height / 2; // scale rectangle using handle coordinates - scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); // mirror handle coordinates via rectangle center coordinates resizeHandleCoords.X -= 2 * (resizeHandleCoords.X - rectCenterX); resizeHandleCoords.Y -= 2 * (resizeHandleCoords.Y - rectCenterY); // scale again with opposing handle and mirrored coordinates resizeHandlePosition = (Positions)((((int)resizeHandlePosition) + 4) % 8); - scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); } else { - scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); } } @@ -166,7 +140,7 @@ namespace Greenshot.Helpers { /// <param name="originalRectangle">bounds of the current rectangle, scaled values will be written to this reference</param> /// <param name="resizeHandlePosition">position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT</param> /// <param name="resizeHandleCoords">coordinates of the used handle/gripper</param> - private static void scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) { + private static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) { switch(resizeHandlePosition) { case Positions.TopLeft: @@ -223,7 +197,7 @@ namespace Greenshot.Helpers { /// <param name="originalRectangle">bounds of the current rectangle</param> /// <param name="resizeHandlePosition">position of the handle/gripper being used for resized, see Position</param> /// <param name="resizeHandleCoords">coordinates of the used handle/gripper, adjusted coordinates will be written to this reference</param> - private static void adjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) { + private static void AdjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) { float originalRatio = originalRectangle.Width / originalRectangle.Height; float newWidth, newHeight, newRatio; switch(resizeHandlePosition) { @@ -273,12 +247,8 @@ namespace Greenshot.Helpers { break; } } - - public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize) { - Scale(boundsBeforeResize, cursorX, cursorY, ref boundsAfterResize, null); - } - - public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) { + + public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) { Scale(boundsBeforeResize, Positions.TopLeft, cursorX, cursorY, ref boundsAfterResize, angleRoundBehavior); } @@ -343,15 +313,6 @@ namespace Greenshot.Helpers { return Math.Round(angle/15)*15; } } - public class FixedAngleRoundBehavior : IDoubleProcessor { - private readonly double fixedAngle; - public FixedAngleRoundBehavior(double fixedAngle) { - this.fixedAngle = fixedAngle; - } - public double Process(double angle) { - return fixedAngle; - } - } - } + } } \ No newline at end of file diff --git a/Greenshot/Helpers/ToolStripItemEndisabler.cs b/Greenshot/Helpers/ToolStripItemEndisabler.cs index db5a5d178..0a8e13d84 100644 --- a/Greenshot/Helpers/ToolStripItemEndisabler.cs +++ b/Greenshot/Helpers/ToolStripItemEndisabler.cs @@ -54,16 +54,8 @@ namespace Greenshot.Helpers { public static void Enable(ToolStripItem tsi) { Endisable(tsi, true, PropagationMode.CHILDREN | PropagationMode.ANCESTORS); } - - /// <summary> - /// Disables the ToolStripItem, including children (ToolStripDropDownItem), - /// but NOT the ancestor (OwnerItem) - /// </summary> - public static void Disable(ToolStripItem tsi) { - Endisable(tsi, false, PropagationMode.CHILDREN); - } - - private static void Endisable(ToolStrip ts, bool enable, PropagationMode mode) + + private static void Endisable(ToolStrip ts, bool enable, PropagationMode mode) { if ((mode & PropagationMode.CHILDREN) != PropagationMode.CHILDREN) return; diff --git a/Greenshot/Helpers/UpdateService.cs b/Greenshot/Helpers/UpdateService.cs index 8c1728fb8..4ef120690 100644 --- a/Greenshot/Helpers/UpdateService.cs +++ b/Greenshot/Helpers/UpdateService.cs @@ -93,17 +93,6 @@ namespace Greenshot.Helpers _ = BackgroundTask(() => TimeSpan.FromDays(CoreConfig.UpdateCheckInterval), UpdateCheck, _cancellationTokenSource.Token); } - /// <summary> - /// Stop the update checks - /// </summary> - public void Shutdown() - { - if (!_cancellationTokenSource.IsCancellationRequested) - { - _cancellationTokenSource.Cancel(); - } - } - /// <summary> /// This runs a periodic task in the background /// </summary> diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 3195d1f55..093c71ce9 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -25,6 +25,7 @@ Source: {#ReleaseDir}\Dapplo.Http*.dll; DestDir: {app}; Components: greenshot; F Source: {#ReleaseDir}\Dapplo.Log.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\HtmlAgilityPack.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Newtonsoft.Json.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: ..\..\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion Source: {#ReleaseDir}\checksum.SHA256; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion @@ -78,11 +79,6 @@ Source: ..\..\Languages\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {ap ;Office Plugin Source: {#BaseDir}\GreenshotOfficePlugin\{#BinDir}\GreenshotOfficePlugin.dll; DestDir: {app}\Plugins\GreenshotOfficePlugin; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -;OCR Plugin -Source: {#BaseDir}\GreenshotOCRPlugin\{#BinDir}\GreenshotOCRPlugin.dll; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotOCRPlugin\Languages\language_ocr*.xml; DestDir: {app}\Languages\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotOCRCommand\{#BinDir}\GreenshotOCRCommand.exe.config; DestDir: {app}\Plugins\GreenshotOCRPlugin; Components: plugins\ocr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; ;JIRA Plugin Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\GreenshotJiraPlugin.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\Dapplo.Jira*.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; @@ -260,7 +256,6 @@ en.flickr=Flickr plug-in en.imgur=Imgur plug-in (See: http://imgur.com) en.jira=Jira plug-in en.language=Additional languages -en.ocr=OCR plug-in (needs Microsoft Office Document Imaging (MODI)) en.office=Microsoft Office plug-in en.optimize=Optimizing performance, this may take a while. en.photobucket=Photobucket plug-in @@ -278,7 +273,6 @@ de.externalcommand=Externes Kommando Plug-in de.imgur=Imgur Plug-in (Siehe: http://imgur.com) de.jira=Jira Plug-in de.language=Zusätzliche Sprachen -de.ocr=OCR Plug-in (benötigt Microsoft Office Document Imaging (MODI)) de.office=Microsoft Office Plug-in de.optimize=Optimierung der Leistung, kann etwas dauern. de.startgreenshot={#ExeName} starten @@ -291,7 +285,6 @@ es.externalcommand=Extensión para abrir con programas externos es.imgur=Extensión para Imgur (Ver http://imgur.com) es.jira=Extensión para Jira es.language=Idiomas adicionales -es.ocr=Extensión para OCR (necesita Microsoft Office Document Imaging (MODI)) es.optimize=Optimizando rendimiento; por favor, espera. es.startgreenshot=Lanzar {#ExeName} es.startup=Lanzar {#ExeName} al iniciarse Windows @@ -303,7 +296,6 @@ fi.externalcommand=Avaa Ulkoinen komento-liitännäisellä fi.imgur=Imgur-liitännäinen (Katso: http://imgur.com) fi.jira=Jira-liitännäinen fi.language=Lisäkielet -fi.ocr=OCR-liitännäinen (Tarvitaan: Microsoft Office Document Imaging (MODI)) fi.office=Microsoft-Office-liitännäinen fi.optimize=Optimoidaan suorituskykyä, tämä voi kestää hetken. fi.startgreenshot=Käynnistä {#ExeName} @@ -316,7 +308,6 @@ fr.externalcommand=Ouvrir avec le greffon de commande externe fr.imgur=Greffon Imgur (Voir: http://imgur.com) fr.jira=Greffon Jira fr.language=Langues additionnelles -fr.ocr=Greffon OCR (nécessite Document Imaging de Microsoft Office [MODI]) fr.office=Greffon Microsoft Office fr.optimize=Optimisation des performances, Ceci peut prendre un certain temps. fr.startgreenshot=Démarrer {#ExeName} @@ -332,7 +323,6 @@ it.flickr=Plugin Flickr it.imgur=Plugin Imgur (vedi: http://imgur.com) it.jira=Plugin Jira it.language=Lingue aggiuntive -it.ocr=Plugin OCR (richiede Microsoft Office Document Imaging (MODI)) it.office=Plugin Microsoft Office it.optimize=Ottimizzazione prestazioni (può richiedere tempo). it.photobucket=Plugin Photobucket @@ -386,7 +376,6 @@ lt.externalcommand=Pielāgotu darbību spraudnis lt.imgur=Imgur spraudnis (Vairāk šeit: http://imgur.com) lt.jira=Jira spraudnis lt.language=Papildus valodas -lt.ocr=OCR spraudnis (nepieciešams Microsoft Office Document Imaging (MODI)) lt.office=Microsoft Office spraudnis lt.optimize=Uzlaboju veikstpēju, tas prasīs kādu laiciņu. lt.startgreenshot=Palaist {#ExeName} @@ -399,7 +388,6 @@ lt.externalcommand=Pielāgotu darbību spraudnis lt.imgur=Imgur spraudnis (Vairāk šeit: http://imgur.com) lt.jira=Jira spraudnis lt.language=Papildus valodas -lt.ocr=OCR spraudnis (nepieciešams Microsoft Office Document Imaging (MODI)) lt.office=Microsoft Office spraudnis lt.optimize=Uzlaboju veikstpēju, tas prasīs kādu laiciņu. lt.startgreenshot=Palaist {#ExeName} @@ -412,7 +400,6 @@ nl.externalcommand=Openen met extern commando plug-in nl.imgur=Imgur plug-in (zie: http://imgur.com) nl.jira=Jira plug-in nl.language=Extra talen -nl.ocr=OCR plug-in (vereist Microsoft Office Document Imaging (MODI)) nl.office=Microsoft Office plug-in nl.optimize=Prestaties verbeteren, even geduld. nl.startgreenshot={#ExeName} starten @@ -425,7 +412,6 @@ nn.externalcommand=Tillegg for å opne med ekstern kommando nn.imgur=Imgur-tillegg (sjå http://imgur.com) nn.jira=Jira-tillegg nn.language=Andre språk -nn.ocr=OCR-tillegg (krev Microsoft Office Document Imaging (MODI)) nn.office=Microsoft Office Tillegg nn.optimize=Optimaliserar ytelse, dette kan ta litt tid... nn.startgreenshot=Start {#ExeName} @@ -438,7 +424,6 @@ ru.externalcommand=Открыть с плагином с помощью внеш ru.imgur=Плагин Imgur (смотрите https://imgur.com/) ru.jira=Плагин Jira ru.language=Дополнительные языки -ru.ocr=Плагин OCR (требуется Microsoft Office Document Imaging (MODI)) ru.office=Плагин Microsoft Office ru.optimize=Идет оптимизация производительности, это может занять некоторое время. ru.startgreenshot=Запустить {#ExeName} @@ -451,7 +436,6 @@ sr.externalcommand=Отвори са прикључком за спољне на sr.imgur=Прикључак за Имиџер (http://imgur.com) sr.jira=Прикључак за Џиру sr.language=Додатни језици -sr.ocr=OCR прикључак (захтева Microsoft Office Document Imaging (MODI)) sr.optimize=Оптимизујем перформансе… sr.startgreenshot=Покрени Гриншот sr.startup=Покрени програм са системом @@ -462,7 +446,6 @@ sv.externalcommand=Öppna med externt kommando-insticksprogram sv.imgur=Imgur-insticksprogram (Se: http://imgur.com) sv.jira=Jira-insticksprogram sv.language=Ytterligare språk -sv.ocr=OCR-insticksprogram (kräver Microsoft Office Document Imaging (MODI)) sv.optimize=Optimerar prestanda, detta kan ta en stund. sv.startgreenshot=Starta {#ExeName} sv.startup=Starta {#ExeName} med Windows @@ -474,7 +457,6 @@ uk.externalcommand=Плагін запуску зовнішньої команд uk.imgur=Плагін Imgur (див.: http://imgur.com) uk.jira=Плагін Jira uk.language=Додаткові мови -uk.ocr=Плагін OCR (потребує Microsoft Office Document Imaging (MODI)) uk.optimize=Оптимізація продуктивності, це може забрати час. uk.startgreenshot=Запустити {#ExeName} uk.startup=Запускати {#ExeName} під час запуску Windows @@ -486,7 +468,6 @@ cn.externalcommand=使用外部命令打开插件 cn.imgur=Imgur插件( (请访问: http://imgur.com)) cn.jira=Jira插件 cn.language=其它语言 -cn.ocr=OCR插件(需要Microsoft Office Document Imaging (MODI)的支持) cn.optimize=正在优化性能,这可能需要一点时间。 cn.startgreenshot=启动{#ExeName} cn.startup=让{#ExeName}随Windows一起启动 @@ -508,7 +489,6 @@ Name: "plugins\externalcommand"; Description: {cm:externalcommand}; Types: defau Name: "plugins\flickr"; Description: {cm:flickr}; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flags: disablenouninstallwarning Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\ocr"; Description: {cm:ocr}; Types: default full custom; Flags: disablenouninstallwarning Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning Name: "plugins\photobucket"; Description: {cm:photobucket}; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\picasa"; Description: {cm:picasa}; Types: full custom; Flags: disablenouninstallwarning diff --git a/GreenshotBoxPlugin/BoxUtils.cs b/GreenshotBoxPlugin/BoxUtils.cs index 28bc90fb6..ec9ef0144 100644 --- a/GreenshotBoxPlugin/BoxUtils.cs +++ b/GreenshotBoxPlugin/BoxUtils.cs @@ -29,10 +29,10 @@ using GreenshotPlugin.IniFile; namespace GreenshotBoxPlugin { - /// <summary> - /// Description of ImgurUtils. - /// </summary> - public static class BoxUtils { + /// <summary> + /// Description of BoxUtils. + /// </summary> + public static class BoxUtils { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(BoxUtils)); private static readonly BoxConfiguration Config = IniConfig.GetIniSection<BoxConfiguration>(); private const string UploadFileUri = "https://upload.box.com/api/2.0/files/content"; @@ -121,19 +121,7 @@ namespace GreenshotBoxPlugin { /// A simple helper class for the DataContractJsonSerializer /// </summary> internal static class JsonSerializer { - /// <summary> - /// Helper method to serialize object to JSON - /// </summary> - /// <param name="jsonObject">JSON object</param> - /// <returns>string</returns> - public static string Serialize(object jsonObject) { - var serializer = new DataContractJsonSerializer(jsonObject.GetType()); - using MemoryStream stream = new MemoryStream(); - serializer.WriteObject(stream, jsonObject); - return Encoding.UTF8.GetString(stream.ToArray()); - } - - /// <summary> + /// <summary> /// Helper method to parse JSON to object /// </summary> /// <typeparam name="T"></typeparam> @@ -141,7 +129,7 @@ namespace GreenshotBoxPlugin { /// <returns></returns> public static T Deserialize<T>(string jsonString) { var deserializer = new DataContractJsonSerializer(typeof(T)); - using MemoryStream stream = new MemoryStream(); + using var stream = new MemoryStream(); byte[] content = Encoding.UTF8.GetBytes(jsonString); stream.Write(content, 0, content.Length); stream.Seek(0, SeekOrigin.Begin); diff --git a/GreenshotBoxPlugin/LanguageKeys.cs b/GreenshotBoxPlugin/LanguageKeys.cs index 6e757a01d..5d2491ae3 100644 --- a/GreenshotBoxPlugin/LanguageKeys.cs +++ b/GreenshotBoxPlugin/LanguageKeys.cs @@ -21,13 +21,8 @@ namespace GreenshotBoxPlugin { public enum LangKey { upload_menu_item, - settings_title, - label_upload_format, - upload_success, upload_failure, communication_wait, - Configure, - label_AfterUpload, - label_AfterUploadLinkToClipBoard + Configure } } diff --git a/GreenshotConfluencePlugin/LanguageKeys.cs b/GreenshotConfluencePlugin/LanguageKeys.cs index 9cd71ea8e..5ba0b2cbe 100644 --- a/GreenshotConfluencePlugin/LanguageKeys.cs +++ b/GreenshotConfluencePlugin/LanguageKeys.cs @@ -22,14 +22,7 @@ namespace GreenshotConfluencePlugin { public enum LangKey { login_error, - login_title, - label_url, - label_upload_format, - OK, - CANCEL, upload_menu_item, - upload_success, - upload_failure, communication_wait } } diff --git a/GreenshotConfluencePlugin/Support/TranslationManager.cs b/GreenshotConfluencePlugin/Support/TranslationManager.cs index 241cce868..472f2e27d 100644 --- a/GreenshotConfluencePlugin/Support/TranslationManager.cs +++ b/GreenshotConfluencePlugin/Support/TranslationManager.cs @@ -29,12 +29,7 @@ namespace GreenshotConfluencePlugin.Support { public ITranslationProvider TranslationProvider { get; set; } - private void OnLanguageChanged() - { - LanguageChanged?.Invoke(this, EventArgs.Empty); - } - - public object Translate(string key) { + public object Translate(string key) { object translatedValue = TranslationProvider?.Translate(key); if( translatedValue != null) { return translatedValue; diff --git a/GreenshotDropboxPlugin/LanguageKeys.cs b/GreenshotDropboxPlugin/LanguageKeys.cs index d50660add..0b1ae489e 100644 --- a/GreenshotDropboxPlugin/LanguageKeys.cs +++ b/GreenshotDropboxPlugin/LanguageKeys.cs @@ -21,13 +21,8 @@ namespace GreenshotDropboxPlugin { public enum LangKey { upload_menu_item, - settings_title, - label_upload_format, - upload_success, upload_failure, communication_wait, - Configure, - label_AfterUpload, - label_AfterUploadLinkToClipBoard - } + Configure + } } diff --git a/GreenshotFlickrPlugin/LanguageKeys.cs b/GreenshotFlickrPlugin/LanguageKeys.cs index 44320512b..ae3a6af02 100644 --- a/GreenshotFlickrPlugin/LanguageKeys.cs +++ b/GreenshotFlickrPlugin/LanguageKeys.cs @@ -21,15 +21,8 @@ namespace GreenshotFlickrPlugin { public enum LangKey { upload_menu_item, - settings_title, - label_upload_format, - upload_success, upload_failure, communication_wait, - Configure, - label_HiddenFromSearch, - label_SafetyLevel, - label_AfterUpload, - label_AfterUploadLinkToClipBoard - } + Configure + } } diff --git a/GreenshotImgurPlugin/LanguageKeys.cs b/GreenshotImgurPlugin/LanguageKeys.cs index 25b3e311f..cfde3c940 100644 --- a/GreenshotImgurPlugin/LanguageKeys.cs +++ b/GreenshotImgurPlugin/LanguageKeys.cs @@ -22,19 +22,11 @@ namespace GreenshotImgurPlugin { public enum LangKey { upload_menu_item, - settings_title, - label_url, - label_upload_format, - label_clear, - OK, - CANCEL, - upload_success, upload_failure, communication_wait, delete_question, clear_question, delete_title, - use_page_link, history, configure } diff --git a/GreenshotJiraPlugin/AsyncMemoryCache.cs b/GreenshotJiraPlugin/AsyncMemoryCache.cs index de2a61d04..af34e769e 100644 --- a/GreenshotJiraPlugin/AsyncMemoryCache.cs +++ b/GreenshotJiraPlugin/AsyncMemoryCache.cs @@ -80,39 +80,7 @@ namespace GreenshotJiraPlugin return keyObject.ToString(); } - /// <summary> - /// Get an element from the cache, if this is not available call the create function. - /// </summary> - /// <param name="keyObject">object for the key</param> - /// <param name="cancellationToken">CancellationToken</param> - /// <returns>TResult</returns> - public async Task DeleteAsync(TKey keyObject, CancellationToken cancellationToken = default) - { - var key = CreateKey(keyObject); - await _semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - _cache.Remove(key); - } - finally - { - _semaphoreSlim.Release(); - } - } - - /// <summary> - /// Get a task element from the cache, if this is not available return null. - /// You probably want to call GetOrCreateAsync - /// </summary> - /// <param name="keyObject">object for the key</param> - /// <returns>Task with TResult, null if no value</returns> - public Task<TResult> GetAsync(TKey keyObject) - { - var key = CreateKey(keyObject); - return _cache.Get(key) as Task<TResult> ?? EmptyValueTask; - } - - /// <summary> + /// <summary> /// Get a task element from the cache, if this is not available call the create function. /// </summary> /// <param name="keyObject">object for the key</param> @@ -124,20 +92,7 @@ namespace GreenshotJiraPlugin return _cache.Get(key) as Task<TResult> ?? GetOrCreateInternalAsync(keyObject, null, cancellationToken); } - /// <summary> - /// Get a task element from the cache, if this is not available call the create function. - /// </summary> - /// <param name="keyObject">object for the key</param> - /// <param name="cacheItemPolicy">CacheItemPolicy for when you want more control over the item</param> - /// <param name="cancellationToken">CancellationToken</param> - /// <returns>Task with TResult</returns> - public Task<TResult> GetOrCreateAsync(TKey keyObject, CacheItemPolicy cacheItemPolicy, CancellationToken cancellationToken = default) - { - var key = CreateKey(keyObject); - return _cache.Get(key) as Task<TResult> ?? GetOrCreateInternalAsync(keyObject, cacheItemPolicy, cancellationToken); - } - - /// <summary> + /// <summary> /// This takes care of the real async part of the code. /// </summary> /// <param name="keyObject"></param> @@ -213,7 +168,7 @@ namespace GreenshotJiraPlugin /// Override to know when an item is removed, make sure to configure ActivateUpdateCallback / ActivateRemovedCallback /// </summary> /// <param name="cacheEntryRemovedArguments">CacheEntryRemovedArguments</param> - protected virtual void RemovedCallback(CacheEntryRemovedArguments cacheEntryRemovedArguments) + protected void RemovedCallback(CacheEntryRemovedArguments cacheEntryRemovedArguments) { _log.Verbose().WriteLine("Item {0} removed due to {1}.", cacheEntryRemovedArguments.CacheItem.Key, cacheEntryRemovedArguments.RemovedReason); if (cacheEntryRemovedArguments.CacheItem.Value is IDisposable disposable) @@ -228,7 +183,7 @@ namespace GreenshotJiraPlugin /// ActivateUpdateCallback / ActivateRemovedCallback /// </summary> /// <param name="cacheEntryUpdateArguments">CacheEntryUpdateArguments</param> - protected virtual void UpdateCallback(CacheEntryUpdateArguments cacheEntryUpdateArguments) + protected void UpdateCallback(CacheEntryUpdateArguments cacheEntryUpdateArguments) { _log.Verbose().WriteLine("Update request for {0} due to {1}.", cacheEntryUpdateArguments.Key, cacheEntryUpdateArguments.RemovedReason); } diff --git a/GreenshotJiraPlugin/JiraConfiguration.cs b/GreenshotJiraPlugin/JiraConfiguration.cs index ba8cad80c..f54132b04 100644 --- a/GreenshotJiraPlugin/JiraConfiguration.cs +++ b/GreenshotJiraPlugin/JiraConfiguration.cs @@ -34,10 +34,7 @@ namespace GreenshotJiraPlugin { [IniProperty("Url", Description="Base url to Jira system, without anything else", DefaultValue=DefaultUrl)] public string Url { get; set; } - [IniProperty("Timeout", Description="Session timeout in minutes", DefaultValue="30")] - public int Timeout { get; set; } - - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] + [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] public OutputFormat UploadFormat { get; set; } [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] diff --git a/GreenshotJiraPlugin/LanguageKeys.cs b/GreenshotJiraPlugin/LanguageKeys.cs index d881be575..6820d5d50 100644 --- a/GreenshotJiraPlugin/LanguageKeys.cs +++ b/GreenshotJiraPlugin/LanguageKeys.cs @@ -30,16 +30,8 @@ namespace GreenshotJiraPlugin { column_summary, label_comment, label_filename, - label_jira, label_jirafilter, login_error, - login_title, - settings_title, - label_url, - label_upload_format, - OK, - CANCEL, - upload_success, upload_failure, communication_wait, } diff --git a/GreenshotOCRCommand/COMWrapper.cs b/GreenshotOCRCommand/COMWrapper.cs deleted file mode 100644 index fd26cfeb9..000000000 --- a/GreenshotOCRCommand/COMWrapper.cs +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; -using System.Diagnostics; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.Remoting; -using System.Runtime.Remoting.Messaging; -using System.Runtime.Remoting.Proxies; - -namespace GreenshotOCRCommand { - /// <summary> - /// Wraps a late-bound COM server. - /// </summary> - public sealed class COMWrapper : RealProxy, IDisposable, IRemotingTypeInfo { - private const int MK_E_UNAVAILABLE = -2147221021; - private const int CO_E_CLASSSTRING = -2147221005; - - /// <summary> - /// Holds reference to the actual COM object which is wrapped by this proxy - /// </summary> - private readonly object _comObject; - - /// <summary> - /// Type of the COM object, set on constructor after getting the COM reference - /// </summary> - private readonly Type _comType; - - /// <summary> - /// The type of which method calls are intercepted and executed on the COM object. - /// </summary> - private readonly Type _interceptType; - - /// <summary> - /// Gets a COM object and returns the transparent proxy which intercepts all calls to the object - /// </summary> - /// <typeparam name="T">Interface which defines the method and properties to intercept</typeparam> - /// <returns>Transparent proxy to the real proxy for the object</returns> - /// <remarks>T must be an interface decorated with the <see cref="ComProgIdAttribute"/>attribute.</remarks> - public static T GetInstance<T>() { - Type type = typeof(T); - if (null == type) { - throw new ArgumentNullException(nameof(T)); - } - if (!type.IsInterface) { - throw new ArgumentException("The specified type must be an interface.", nameof(T)); - } - - ComProgIdAttribute progIdAttribute = ComProgIdAttribute.GetAttribute(type); - if (string.IsNullOrEmpty(progIdAttribute?.Value)) { - throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T)); - } - string progId = progIdAttribute.Value; - - object comObject = null; - try { - comObject = Marshal.GetActiveObject(progId); - } catch (COMException comE) { - if (comE.ErrorCode == MK_E_UNAVAILABLE) - { - Debug.WriteLine($"No current instance of {progId} object available."); - } - else if (comE.ErrorCode == CO_E_CLASSSTRING) - { - Debug.WriteLine($"Unknown progId {progId}"); - } - } catch (Exception ex) { - Debug.WriteLine($"Error getting active object for {progId} {ex.Message}"); - } - - if (comObject != null) { - COMWrapper wrapper = new COMWrapper(comObject, type); - return (T)wrapper.GetTransparentProxy(); - } - return default; - } - - /// <summary> - /// Gets or creates a COM object and returns the transparent proxy which intercepts all calls to the object - /// The ComProgId can be a normal ComProgId or a GUID prefixed with "clsid:" - /// </summary> - /// <typeparam name="T">Interface which defines the method and properties to intercept</typeparam> - /// <returns>Transparent proxy to the real proxy for the object</returns> - /// <remarks>The type must be an interface decorated with the <see cref="ComProgIdAttribute"/>attribute.</remarks> - public static T GetOrCreateInstance<T>() { - Type type = typeof(T); - if (null == type) { - throw new ArgumentNullException(nameof(T)); - } - if (!type.IsInterface) { - throw new ArgumentException("The specified type must be an interface.", nameof(T)); - } - - ComProgIdAttribute progIdAttribute = ComProgIdAttribute.GetAttribute(type); - if (string.IsNullOrEmpty(progIdAttribute?.Value)) { - throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T)); - } - - object comObject = null; - Type comType = null; - string progId = progIdAttribute.Value; - - try { - comObject = Marshal.GetActiveObject(progId); - } catch (COMException comE) { - if (comE.ErrorCode == MK_E_UNAVAILABLE) - { - Debug.WriteLine($"No current instance of {progId} object available."); - } - else if (comE.ErrorCode == CO_E_CLASSSTRING) - { - Debug.WriteLine($"Unknown progId {progId}"); - } - } catch (Exception ex) { - Debug.WriteLine($"Error getting active object for {progId} {ex.Message}"); - } - // Did we get the current instance? If not, try to create a new - if (comObject == null) { - try { - comType = Type.GetTypeFromProgID(progId, true); - } catch (Exception) { - Debug.WriteLine($"Error getting type for {progId}"); - } - if (comType != null) { - try { - comObject = Activator.CreateInstance(comType); - if (comObject != null) { - Debug.WriteLine($"Created new instance of {progId} object."); - } - } catch (Exception ex) { - Debug.WriteLine($"Error creating object for {progId} {ex.Message}"); - } - } - } - if (comObject != null) { - COMWrapper wrapper = new COMWrapper(comObject, type); - return (T)wrapper.GetTransparentProxy(); - } - return default; - } - - /// <summary> - /// Wrap an object and return the transparent proxy which intercepts all calls to the object - /// </summary> - /// <param name="comObject">An object to intercept</param> - /// <param name="type">Interface which defines the method and properties to intercept</param> - /// <returns>Transparent proxy to the real proxy for the object</returns> - private static object Wrap(object comObject, Type type) { - if (null == comObject) { - throw new ArgumentNullException(nameof(comObject)); - } - if (null == type) { - throw new ArgumentNullException(nameof(type)); - } - - COMWrapper wrapper = new COMWrapper(comObject, type); - return wrapper.GetTransparentProxy(); - } - - /// <summary> - /// Constructor - /// </summary> - /// <param name="comObject"> - /// The COM object to wrap. - /// </param> - /// <param name="type"> - /// The interface type to impersonate. - /// </param> - private COMWrapper(object comObject, Type type) - : base(type) { - _comObject = comObject; - _comType = comObject.GetType(); - _interceptType = type; - } - - /// <summary> - /// If <see cref="Dispose"/> is not called, we need to make - /// sure that the COM object is still cleaned up. - /// </summary> - ~COMWrapper() { - Dispose(false); - } - - /// <summary> - /// Cleans up the COM object. - /// </summary> - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Release the COM reference - /// </summary> - /// <param name="disposing"> - /// <see langword="true"/> if this was called from the - /// <see cref="IDisposable"/> interface. - /// </param> - private void Dispose(bool disposing) { - if (disposing && null != _comObject) { - if (Marshal.IsComObject(_comObject)) { - try { - while (Marshal.ReleaseComObject(_comObject) > 0) - { - } - } catch (Exception ex) { - Debug.WriteLine($"Problem releasing {_comType}"); - Debug.WriteLine("Error: " + ex); - } - } - } - } - - /// <summary> - /// Returns a string representing the wrapped object. - /// </summary> - /// <returns> - /// The full name of the intercepted type. - /// </returns> - public override string ToString() { - return _interceptType.FullName; - } - - /// <summary> - /// Returns the hash code of the wrapped object. - /// </summary> - /// <returns> - /// The hash code of the wrapped object. - /// </returns> - public override int GetHashCode() { - return _comObject.GetHashCode(); - } - - /// <summary> - /// Compares this object to another. - /// </summary> - /// <param name="value"> - /// The value to compare to. - /// </param> - /// <returns> - /// <see langword="true"/> if the objects are equal. - /// </returns> - public override bool Equals(object value) { - if (null != value && RemotingServices.IsTransparentProxy(value)) { - if (RemotingServices.GetRealProxy(value) is COMWrapper wrapper) { - return _comObject == wrapper._comObject; - } - } - - return base.Equals(value); - } - - /// <summary> - /// Returns the base type for a reference type. - /// </summary> - /// <param name="byRefType"> - /// The reference type. - /// </param> - /// <returns> - /// The base value type. - /// </returns> - /// <exception cref="ArgumentNullException"> - /// <paramref name="byRefType"/> is <see langword="null"/>. - /// </exception> - private static Type GetByValType(Type byRefType) { - if (null == byRefType) { - throw new ArgumentNullException(nameof(byRefType)); - } - - if (byRefType.IsByRef) { - string name = byRefType.FullName; - name = name.Substring(0, name.Length - 1); - byRefType = byRefType.Assembly.GetType(name, true); - } - - return byRefType; - } - - /// <summary> - /// Intercept method calls - /// </summary> - /// <param name="myMessage"> - /// Contains information about the method being called - /// </param> - /// <returns> - /// A <see cref="ReturnMessage"/>. - /// </returns> - public override IMessage Invoke(IMessage myMessage) { - IMethodCallMessage callMessage = myMessage as IMethodCallMessage; - - MethodInfo method = callMessage?.MethodBase as MethodInfo; - if (method == null) - { - if (callMessage != null) - { - Debug.WriteLine($"Unrecognized Invoke call: {callMessage.MethodBase}"); - } - return null; - } - - object returnValue = null; - object[] outArgs = null; - int outArgsCount = 0; - - string methodName = method.Name; - Type returnType = method.ReturnType; - BindingFlags flags = BindingFlags.InvokeMethod; - int argCount = callMessage.ArgCount; - - ParameterModifier[] argModifiers = null; - ParameterInfo[] parameters = null; - - if ("Dispose" == methodName && 0 == argCount && typeof(void) == returnType) { - Dispose(); - } else if ("ToString" == methodName && 0 == argCount && typeof(string) == returnType) { - returnValue = ToString(); - } else if ("GetType" == methodName && 0 == argCount && typeof(Type) == returnType) { - returnValue = _interceptType; - } else if ("GetHashCode" == methodName && 0 == argCount && typeof(int) == returnType) { - returnValue = GetHashCode(); - } else if ("Equals" == methodName && 1 == argCount && typeof(bool) == returnType) { - returnValue = Equals(callMessage.Args[0]); - } else if (1 == argCount && typeof(void) == returnType && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) { - if (!(callMessage.InArgs[0] is Delegate handler)) { - return new ReturnMessage(new ArgumentNullException(nameof(handler)), callMessage); - } - } else { - var invokeObject = _comObject; - var invokeType = _comType; - - ParameterInfo parameter; - object[] args; - if (methodName.StartsWith("get_")) { - // Property Get - methodName = methodName.Substring(4); - flags = BindingFlags.GetProperty; - args = callMessage.InArgs; - } else if (methodName.StartsWith("set_")) { - // Property Set - methodName = methodName.Substring(4); - flags = BindingFlags.SetProperty; - args = callMessage.InArgs; - } else { - args = callMessage.Args; - if (null != args && 0 != args.Length) { - // Modifiers for ref / out parameters - argModifiers = new ParameterModifier[1]; - argModifiers[0] = new ParameterModifier(args.Length); - - parameters = method.GetParameters(); - for (int i = 0; i < parameters.Length; i++) { - parameter = parameters[i]; - if (parameter.IsOut || parameter.ParameterType.IsByRef) { - argModifiers[0][i] = true; - outArgsCount++; - } - } - - if (0 == outArgsCount) { - argModifiers = null; - } - } - } - - // Un-wrap wrapped COM objects before passing to the method - COMWrapper[] originalArgs; - COMWrapper wrapper; - Type byValType; - if (null == args || 0 == args.Length) { - originalArgs = null; - } else { - originalArgs = new COMWrapper[args.Length]; - for (int i = 0; i < args.Length; i++) { - if (null != args[i] && RemotingServices.IsTransparentProxy(args[i])) { - wrapper = RemotingServices.GetRealProxy(args[i]) as COMWrapper; - if (null != wrapper) { - originalArgs[i] = wrapper; - args[i] = wrapper._comObject; - } - } else if (argModifiers != null && (0 != outArgsCount && argModifiers[0][i])) { - byValType = GetByValType(parameters[i].ParameterType); - if (byValType.IsInterface) { - // If we're passing a COM object by reference, and - // the parameter is null, we need to pass a - // DispatchWrapper to avoid a type mismatch exception. - if (null == args[i]) { - args[i] = new DispatchWrapper(null); - } - } else if (typeof(decimal) == byValType) { - // If we're passing a decimal value by reference, - // we need to pass a CurrencyWrapper to avoid a - // type mismatch exception. - // http://support.microsoft.com/?kbid=837378 - args[i] = new CurrencyWrapper(args[i]); - } - } - } - } - - try { - returnValue = invokeType.InvokeMember(methodName, flags, null, invokeObject, args, argModifiers, null, null); - } catch (Exception ex) { - return new ReturnMessage(ex, callMessage); - } - - // Handle enum and interface return types - if (null != returnValue) { - if (returnType.IsInterface) { - // Wrap the returned value in an intercepting COM wrapper - if (Marshal.IsComObject(returnValue)) { - returnValue = Wrap(returnValue, returnType); - } - } else if (returnType.IsEnum) { - // Convert to proper Enum type - returnValue = Enum.Parse(returnType, returnValue.ToString()); - } - } - - // Handle out args - if (0 != outArgsCount) { - if (args != null && parameters != null) - { - outArgs = new object[args.Length]; - for (int i = 0; i < parameters.Length; i++) { - if (argModifiers != null && !argModifiers[0][i]) { - continue; - } - - var arg = args[i]; - if (null == arg) { - continue; - } - - parameter = parameters[i]; - wrapper = null; - - byValType = GetByValType(parameter.ParameterType); - if (typeof(decimal) == byValType) { - if (arg is CurrencyWrapper) { - arg = ((CurrencyWrapper)arg).WrappedObject; - } - } else if (byValType.IsEnum) { - arg = Enum.Parse(byValType, arg.ToString()); - } else if (byValType.IsInterface) { - if (Marshal.IsComObject(arg)) { - if (originalArgs != null) - { - wrapper = originalArgs[i]; - } - if (null != wrapper && wrapper._comObject != arg) { - wrapper.Dispose(); - wrapper = null; - } - - if (null == wrapper) { - wrapper = new COMWrapper(arg, byValType); - } - arg = wrapper.GetTransparentProxy(); - } - } - outArgs[i] = arg; - } - } - } - } - - return new ReturnMessage(returnValue, outArgs, outArgsCount, callMessage.LogicalCallContext, callMessage); - } - - /// <summary> - /// Implementation for the interface IRemotingTypeInfo - /// This makes it possible to cast the COMWrapper - /// </summary> - /// <param name="toType">Type to cast to</param> - /// <param name="o">object to cast</param> - /// <returns></returns> - public bool CanCastTo(Type toType, object o) { - bool returnValue = _interceptType.IsAssignableFrom(toType); - return returnValue; - } - - /// <summary> - /// Implementation for the interface IRemotingTypeInfo - /// </summary> - public string TypeName { - get { - throw new NotSupportedException(); - } - set { - throw new NotSupportedException(); - } - } - } -} diff --git a/GreenshotOCRCommand/ComProgIdAttribute.cs b/GreenshotOCRCommand/ComProgIdAttribute.cs deleted file mode 100644 index 936ea34f9..000000000 --- a/GreenshotOCRCommand/ComProgIdAttribute.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; - -namespace GreenshotOCRCommand { - /// <summary> - /// An attribute to specifiy the ProgID of the COM class to create. (As suggested by Kristen Wegner) - /// </summary> - [AttributeUsage(AttributeTargets.Interface)] - public sealed class ComProgIdAttribute : Attribute { - /// <summary> - /// Extracts the attribute from the specified type. - /// </summary> - /// <param name="interfaceType"> - /// The interface type. - /// </param> - /// <returns> - /// The <see cref="ComProgIdAttribute"/>. - /// </returns> - /// <exception cref="ArgumentNullException"> - /// <paramref name="interfaceType"/> is <see langword="null"/>. - /// </exception> - public static ComProgIdAttribute GetAttribute(Type interfaceType) { - if (null == interfaceType) { - throw new ArgumentNullException(nameof(interfaceType)); - } - - Type attributeType = typeof(ComProgIdAttribute); - object[] attributes = interfaceType.GetCustomAttributes(attributeType, false); - - if (0 == attributes.Length) { - Type[] interfaces = interfaceType.GetInterfaces(); - for (int i = 0; i < interfaces.Length; i++) { - interfaceType = interfaces[i]; - attributes = interfaceType.GetCustomAttributes(attributeType, false); - if (0 != attributes.Length) { - break; - } - } - } - - if (0 == attributes.Length) { - return null; - } - return (ComProgIdAttribute)attributes[0]; - } - - /// <summary>Constructor</summary> - /// <param name="value">The COM ProgID.</param> - public ComProgIdAttribute(string value) { - Value = value; - } - - /// <summary> - /// Returns the COM ProgID - /// </summary> - public string Value { get; } - } -} diff --git a/GreenshotOCRCommand/GreenshotOCRCommand.csproj b/GreenshotOCRCommand/GreenshotOCRCommand.csproj deleted file mode 100644 index 4267325f2..000000000 --- a/GreenshotOCRCommand/GreenshotOCRCommand.csproj +++ /dev/null @@ -1,14 +0,0 @@ -<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> - - <PropertyGroup> - <RootNamespace>GreenshotOCRCommand</RootNamespace> - <AssemblyName>GreenshotOCRCommand</AssemblyName> - <OutputType>WinExe</OutputType> - </PropertyGroup> - <ItemGroup> - <Reference Include="CustomMarshalers" /> - </ItemGroup> - <Target Name="PostBuild" BeforeTargets="PostBuildEvent" Condition="'$(BuildingInsideVisualStudio)' == 'true'"> - <Exec Command="xcopy /q /y /d "$(TargetDir)*.exe" "$(SolutionDir)$(SolutionName)\$(OutDir)"" /> - </Target> -</Project> diff --git a/GreenshotOCRCommand/Modi/CompressionLevel.cs b/GreenshotOCRCommand/Modi/CompressionLevel.cs deleted file mode 100644 index 0cb9a4bc7..000000000 --- a/GreenshotOCRCommand/Modi/CompressionLevel.cs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotOCRCommand.Modi -{ - public enum CompressionLevel { - miCOMP_LEVEL_LOW = 0, - miCOMP_LEVEL_MEDIUM = 1, - miCOMP_LEVEL_HIGH = 2 - } -} \ No newline at end of file diff --git a/GreenshotOCRCommand/Modi/FileFormat.cs b/GreenshotOCRCommand/Modi/FileFormat.cs deleted file mode 100644 index 42c86a104..000000000 --- a/GreenshotOCRCommand/Modi/FileFormat.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotOCRCommand.Modi -{ - public enum FileFormat { - miFILE_FORMAT_DEFAULTVALUE = -1, - miFILE_FORMAT_TIFF = 1, - miFILE_FORMAT_TIFF_LOSSLESS = 2, - miFILE_FORMAT_MDI = 4 - } -} \ No newline at end of file diff --git a/GreenshotOCRCommand/Modi/ICommon.cs b/GreenshotOCRCommand/Modi/ICommon.cs deleted file mode 100644 index 433fcd121..000000000 --- a/GreenshotOCRCommand/Modi/ICommon.cs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; - -namespace GreenshotOCRCommand.Modi -{ - /// <summary> - /// Base class for the common properties of the Modi interfaces - /// </summary> - public interface ICommon : IDisposable { - IDocument Application { get; } - } -} \ No newline at end of file diff --git a/GreenshotOCRCommand/Modi/IDispatch.cs b/GreenshotOCRCommand/Modi/IDispatch.cs deleted file mode 100644 index 623feef72..000000000 --- a/GreenshotOCRCommand/Modi/IDispatch.cs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.CustomMarshalers; - -namespace GreenshotOCRCommand.Modi { - [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IDispatch { - void Reserved(); - [PreserveSig] - int GetTypeInfo(uint nInfo, int lcid, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))] out Type typeInfo); - } -} diff --git a/GreenshotOCRCommand/Modi/IDocument.cs b/GreenshotOCRCommand/Modi/IDocument.cs deleted file mode 100644 index cd9098f61..000000000 --- a/GreenshotOCRCommand/Modi/IDocument.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotOCRCommand.Modi { - /// <summary> - /// The MODI Document object represents an ordered collection of document images saved as a single file. - /// You can use the Create method to load an existing MDI or TIF file, or to create an empty document that you can populate with images from other documents. - /// The OCR method performs OCR on all pages in the document, and the OnOCRProgress event reports the status of the operation and allows the user to cancel it. - /// The Dirty property lets you know whether your document has unsaved OCR results or changes. - /// The SaveAs method allows you to specify an image file format and a compression level. - /// You can also use the PrintOut method to print the document to a printer or a file. - /// </summary> - [ComProgId("MODI.Document")] - public interface IDocument : ICommon { - /// <summary> - /// Closes the document. - /// </summary> - /// <param name="saveCall"></param> - void Close(bool saveCall); - - /// <summary> - /// The document's collection of pages. - /// </summary> - IImages Images - { - get; - } - - /// <summary> - /// Occurs periodically during an optical character recognition (OCR) operation. Returns the estimated percentage of the OCR operation that is complete, and allows the user to cancel the operation. - /// </summary> - // event OnOCRProgress { get; } - - /// <summary> - /// Indicates whether the active document has unsaved changes. - /// </summary> - bool Dirty { get; } - - /// <summary> - /// Creates a new document. - /// </summary> - /// <param name="file">Optional String. The path and filename of the optional document file that is to be loaded into the new document.</param> - void Create(string file); - - /// <summary> - /// Performs optical character recognition (OCR) on the specified document or image. - /// </summary> - /// <param name="language">ModiLanguage</param> - /// <param name="orientimage">Optional Boolean. Specifies whether the OCR engine attempts to determine the orientation of the page. Default is true.</param> - /// <param name="straightenImage">Optional Boolean. Specifies whether the OCR engine attempts to "de-skew" the page to correct for small angles of misalignment from the vertical. Default is true.</param> - void OCR(ModiLanguage language, bool orientimage, bool straightenImage); - - /// <summary> - /// - /// </summary> - /// <param name="filename"></param> - /// <param name="fileFormat"></param> - /// <param name="compressionLevel"></param> - void SaveAs(string filename, FileFormat fileFormat, CompressionLevel compressionLevel); - } -} diff --git a/GreenshotOCRCommand/Modi/IImage.cs b/GreenshotOCRCommand/Modi/IImage.cs deleted file mode 100644 index 5329c4eaf..000000000 --- a/GreenshotOCRCommand/Modi/IImage.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotOCRCommand.Modi -{ - /// <summary> - /// Describes the page in a scan - /// </summary> - public interface IImage : ICommon { - ILayout Layout { - get; - } - - long BitsPerPixel { get; } - CompressionLevel Compression { get; } - //IPictureDisp Picture { get; } - int PixelHeight { get; } - int PixelWidth { get; } - //IPictureDisp Thumbnail { get; } - int XDPI { get; } - int YDPI { get; } - } -} \ No newline at end of file diff --git a/GreenshotOCRCommand/Modi/IImages.cs b/GreenshotOCRCommand/Modi/IImages.cs deleted file mode 100644 index 3c429c7d0..000000000 --- a/GreenshotOCRCommand/Modi/IImages.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Collections; - -namespace GreenshotOCRCommand.Modi -{ - /// <summary> - /// Use the Images accessor property of the Document object to return an Images collection. - /// Use the Item property of the Images collection to return an Image object and gain access to its OCR Layout - /// (including recognized Text and Words), the properties that describe its dimensions and format (BitsPerPixel, Compression, PixelHeight, PixelWidth, XDPI, and YDPI), - /// and its Picture and Thumbnail images. - /// </summary> - public interface IImages : ICommon, IEnumerable { - int Count { - get; - } - IImage this [int index] { - get; - } - new IEnumerator GetEnumerator(); - } -} \ No newline at end of file diff --git a/GreenshotOCRCommand/Modi/ILayout.cs b/GreenshotOCRCommand/Modi/ILayout.cs deleted file mode 100644 index 351724150..000000000 --- a/GreenshotOCRCommand/Modi/ILayout.cs +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotOCRCommand.Modi -{ - /// <summary> - /// Layout of the IImage - /// </summary> - public interface ILayout : ICommon { - /// <summary> - /// Returns the recognized text as a Unicode string. - /// </summary> - string Text { - get; - } - - /// <summary> - /// An accessor property that returns the Words collection recognized in the text during an optical character recognition (OCR) operation. - /// </summary> - IWords Words { get; } - - /// <summary> - /// Returns the number of characters in the recognized text. - /// </summary> - int NumChars { get; } - - /// <summary> - /// Returns the number of words in the recognized text. - /// </summary> - int NumWords { get; } - - /// <summary> - /// Returns the language identifier for the recognized text. Read-only Long. - /// </summary> - ModiLanguage Language { get; } - } -} \ No newline at end of file diff --git a/GreenshotOCRCommand/Modi/IMiRect.cs b/GreenshotOCRCommand/Modi/IMiRect.cs deleted file mode 100644 index 3474a5e86..000000000 --- a/GreenshotOCRCommand/Modi/IMiRect.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotOCRCommand.Modi -{ - /// <summary> - /// Represents a bounding rectangle in the optical character recognition (OCR) layout. - /// </summary> - public interface IMiRect : ICommon { - /// <summary> - /// The Bottom property represent the distance in pixels from the top edge of the containing image. - /// </summary> - int Bottom { get; } - - /// <summary> - /// The Left property represent the distance in pixels from the left edge of the containing image. - /// </summary> - int Left { get; } - - /// <summary> - /// The Right property represent the distance in pixels from the left edge of the containing image. - /// </summary> - int Right { get; } - - /// <summary> - /// The Top property represent the distance in pixels from the top edge of the containing image. - /// </summary> - int Top { get; } - } -} \ No newline at end of file diff --git a/GreenshotOCRCommand/Modi/IMiRects.cs b/GreenshotOCRCommand/Modi/IMiRects.cs deleted file mode 100644 index e322b577d..000000000 --- a/GreenshotOCRCommand/Modi/IMiRects.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Collections; - -namespace GreenshotOCRCommand.Modi -{ - /// <summary> - /// Represents the collection of bounding rectangles in the optical character recognition (OCR) layout. A collection of MiRect objects. - /// </summary> - public interface IMiRects : ICommon, IEnumerable { - int Count { - get; - } - IMiRect this [int index] { - get; - } - new IEnumerator GetEnumerator(); - } -} \ No newline at end of file diff --git a/GreenshotOCRCommand/Modi/IWord.cs b/GreenshotOCRCommand/Modi/IWord.cs deleted file mode 100644 index 6ba1a425b..000000000 --- a/GreenshotOCRCommand/Modi/IWord.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotOCRCommand.Modi -{ - /// <summary> - /// Represents a word recognized in the text during an optical character recognition (OCR) operation. - /// </summary> - public interface IWord : ICommon - { - /// <summary> - /// Returns the index of the specified word in the Words collection of the Layout or IMiSelectableItem object. - /// </summary> - long Id { get; } - - /// <summary> - /// Returns the number of the region in the optical character recognition (OCR) layout where the word occurs. - /// </summary> - long RegionId { get; } - - /// <summary> - /// Returns the number of the line in the optical character recognition (OCR) layout where the word occurs. - /// </summary> - long LineId { get; } - - /// <summary> - /// Returns the recognized text as a Unicode string. - /// </summary> - string Text { get; } - - /// <summary> - /// Returns the relative confidence factor reported by the optical character recognition (OCR) engine (on a scale of 0 to 999) after recognizing the specified word. - /// </summary> - short RecognitionConfidence { get; } - - /// <summary> - /// Returns the index of the font used by the specified wordthis is the font that was recognized in the text during an optical character recognition (OCR) operation. - /// </summary> - long FontId { get; } - - /// <summary> - /// Rectangles - /// </summary> - IMiRects Rects { get; } - - } -} diff --git a/GreenshotOCRCommand/Modi/IWords.cs b/GreenshotOCRCommand/Modi/IWords.cs deleted file mode 100644 index 4e7243cdd..000000000 --- a/GreenshotOCRCommand/Modi/IWords.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Collections; - -namespace GreenshotOCRCommand.Modi -{ - /// <summary> - /// The Words collection recognized in the text during an optical character recognition (OCR) operation. - /// </summary> - public interface IWords : ICommon, IEnumerable - { - int Count - { - get; - } - - IWord this[int index] - { - get; - } - - new IEnumerator GetEnumerator(); - } -} diff --git a/GreenshotOCRCommand/Modi/ModiLanguage.cs b/GreenshotOCRCommand/Modi/ModiLanguage.cs deleted file mode 100644 index b1af9f30c..000000000 --- a/GreenshotOCRCommand/Modi/ModiLanguage.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotOCRCommand.Modi -{ - public enum ModiLanguage { - CHINESE_SIMPLIFIED = 2052, - CHINESE_TRADITIONAL = 1028, - CZECH = 5, - DANISH = 6, - DUTCH = 19, - ENGLISH = 9, - FINNISH = 11, - FRENCH = 12, - GERMAN = 7, - GREEK = 8, - HUNGARIAN = 14, - ITALIAN = 16, - JAPANESE = 17, - KOREAN = 18, - NORWEGIAN = 20, - POLISH = 21, - PORTUGUESE = 22, - RUSSIAN = 25, - SPANISH = 10, - SWEDISH = 29, - TURKISH = 31, - SYSDEFAULT = 2048 - } -} \ No newline at end of file diff --git a/GreenshotOCRCommand/Program.cs b/GreenshotOCRCommand/Program.cs deleted file mode 100644 index 7f1c81b09..000000000 --- a/GreenshotOCRCommand/Program.cs +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using GreenshotOCRCommand.Modi; - -namespace GreenshotOCRCommand { - public class Program { - private const string Usage = "<-c> | <path to image.bmp> [language] [orientimage] [straightenImage]"; - public static int Main(string[] args) { - if (args.Length == 0) { - Console.WriteLine(Usage); - return -1; - } - string filename = args[0]; - ModiLanguage language = ModiLanguage.ENGLISH; - if (args.Length >= 2) { - language = (ModiLanguage)Enum.Parse(typeof(ModiLanguage), args[1]); - } - bool orientimage = true; - if (args.Length >= 3) { - orientimage = bool.Parse(args[2]); - } - bool straightenImage = true; - if (args.Length >= 4) { - straightenImage = bool.Parse(args[3]); - } - try { - if (File.Exists(filename) || "-c".Equals(filename)) - { - using var document = COMWrapper.GetOrCreateInstance<IDocument>(); - if (document == null) { - Console.WriteLine("MODI not installed"); - return -2; - } - if ("-c".Equals(filename)) { - return 0; - } - document.Create(filename); - document.OCR(language, orientimage, straightenImage); - var modiImage = document.Images[0]; - var layout = modiImage.Layout; - if (layout != null) - { -#if DEBUG - if (layout.Words != null) - { - foreach (var word in ToEnumerable(layout.Words)) - { - if (word.Rects != null) - { - foreach (var rect in ToEnumerable(word.Rects)) - { - Debug.WriteLine($"Rect {rect.Left},{rect.Top},{rect.Right},{rect.Bottom} - Word {word.Text} : Confidence: {word.RecognitionConfidence}"); - } - } - } - } -#endif - if (layout.Text != null) - { - // For for BUG-1884: - // Although trim is done in the OCR Plugin, it does make sense in the command too. - Console.WriteLine(layout.Text.Trim()); - } - } - document.Close(false); - return 0; - } - } catch (Exception ex) { - Console.WriteLine(ex.Message); - } - return -1; - } - - /// <summary> - /// Helper method - /// </summary> - /// <returns>IEnumerable of IMiRect</returns> - private static IEnumerable<IMiRect> ToEnumerable(IMiRects rects) - { - for (int i = 0; i < rects.Count; i++) - { - yield return rects[i]; - } - } - - /// <summary> - /// Helper method - /// </summary> - /// <returns>IEnumerable of IWord</returns> - private static IEnumerable<IWord> ToEnumerable(IWords words) - { - for (int i = 0; i < words.Count; i++) - { - yield return words[i]; - } - } - } -} diff --git a/GreenshotOCRCommand/Properties/AssemblyInfo.cs b/GreenshotOCRCommand/Properties/AssemblyInfo.cs deleted file mode 100644 index 85d71c24d..000000000 --- a/GreenshotOCRCommand/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Reflection; -using System.Runtime.InteropServices; - -// Allgemeine Informationen über eine Assembly werden über die folgenden -// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, -// die mit einer Assembly verknüpft sind. -[assembly: AssemblyDescription("A small executable to OCR a bitmap")] - -// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar -// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von -// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. -[assembly: ComVisible(false)] - -// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird -[assembly: Guid("d7668e7e-3018-4d27-9aa0-21b1afade1b8")] diff --git a/GreenshotOCRCommand/app.config b/GreenshotOCRCommand/app.config deleted file mode 100644 index 2dcad202f..000000000 --- a/GreenshotOCRCommand/app.config +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<configuration> - <startup useLegacyV2RuntimeActivationPolicy="true"> - <supportedRuntime version="v4.0"/> - <supportedRuntime version="v2.0.50727"/> - </startup> - <runtime> - <loadFromRemoteSources enabled="true"/> - </runtime> -</configuration> diff --git a/GreenshotOCRPlugin/GreenshotOCRPlugin.csproj b/GreenshotOCRPlugin/GreenshotOCRPlugin.csproj deleted file mode 100644 index 42e03e628..000000000 --- a/GreenshotOCRPlugin/GreenshotOCRPlugin.csproj +++ /dev/null @@ -1,16 +0,0 @@ -<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> - - <PropertyGroup> - <RootNamespace>GreenshotOCRPlugin</RootNamespace> - <AssemblyName>GreenshotOCRPlugin</AssemblyName> - </PropertyGroup> - - <ItemGroup> - <None Include="Languages\language*.xml"> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </None> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\GreenshotPlugin\GreenshotPlugin.csproj" /> - </ItemGroup> -</Project> diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-cs-CZ.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-cs-CZ.xml deleted file mode 100644 index eb225ae3e..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-cs-CZ.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Czech" ietf="cs-CZ" version="1.1.0.2411" languagegroup=""> - <resources> - <resource name="language">Jazyk pro OCR</resource> - <resource name="orient_image">Orientaci obrázku</resource> - <resource name="straighten_image">Srovnat obrázek</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-de-DE.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-de-DE.xml deleted file mode 100644 index a5743f569..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-de-DE.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Deutsch" ietf="de-DE" version="1.0.0"> - <resources> - <resource name="language"> - Sprache für OCR - </resource> - <resource name="orient_image"> - Bild ausrichten - </resource> - <resource name="straighten_image"> - Bild glätten - </resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-en-US.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-en-US.xml deleted file mode 100644 index 6412a02f6..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-en-US.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="English" ietf="en-US" version="1.0.0"> - <resources> - <resource name="language"> - Language for OCR - </resource> - <resource name="orient_image"> - Orient image - </resource> - <resource name="straighten_image"> - Straighten image - </resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-fr-FR.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-fr-FR.xml deleted file mode 100644 index 9e3c8126d..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-fr-FR.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Français" ietf="fr-FR" version="1.0.0" languagegroup=""> - <resources> - <resource name="language">Langage pour l'OCR</resource> - <resource name="orient_image">Orienter l'image</resource> - <resource name="straighten_image">Redresser l'image</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-id-ID.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-id-ID.xml deleted file mode 100644 index e828076e2..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-id-ID.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Bahasa Indonesia" ietf="id-ID" version="1.0.0.0" languagegroup=""> - <resources> - <resource name="language">Bahasa untuk OCR</resource> - <resource name="orient_image">Orientasikan gambar</resource> - <resource name="straighten_image">Rapikan gambar</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-it-IT.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-it-IT.xml deleted file mode 100644 index 52259f004..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-it-IT.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.0.1"> - <resources> - <resource name="language"> - Lingua OCR - </resource> - <resource name="orient_image"> - Orientamento immagine - </resource> - <resource name="straighten_image"> - Raddrizza immagine - </resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-ja-JP.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-ja-JP.xml deleted file mode 100644 index c103704d4..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-ja-JP.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="日本語" ietf="ja-JP" version="1.0.0"> - <resources> - <resource name="language">OCRの言語</resource> - <resource name="orient_image">画像の向きを揃える</resource> - <resource name="straighten_image">画像の傾きを補正する</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-kab-DZ.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-kab-DZ.xml deleted file mode 100644 index 3d884a724..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-kab-DZ.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Taqbaylit" ietf="kab-DZ" version="1.0.0" languagegroup=""> - <resources> - <resource name="language">Tutlayt i OCR</resource> - <resource name="orient_image">Wehhi tugna</resource> - <resource name="straighten_image">Seggwem tugna</resource> - </resources> -</language> diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-ko-KR.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-ko-KR.xml deleted file mode 100644 index e35bfe3b8..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-ko-KR.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="korean" ietf="ko-KR" version="1.0.0"> - <resources> - <resource name="language"> - OCR 언어 - </resource> - <resource name="orient_image"> - 가로 이미지 - </resource> - <resource name="straighten_image"> - 세로 이미지 - </resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-lv-LV.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-lv-LV.xml deleted file mode 100644 index 463aa73fb..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-lv-LV.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Translated by Kārlis Kalviškis (eko@lanet.lv) 2014.12.17. --> -<language description="Latviski" ietf="lv-LV" version="0.1.0"> - <resources> - <resource name="language"> - OCR valoda - </resource> - <resource name="orient_image"> - Pagriezt attēlu - </resource> - <resource name="straighten_image"> - Iztaisnot attēlu - </resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-nl-NL.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-nl-NL.xml deleted file mode 100644 index dac711d25..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-nl-NL.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Nederlands" ietf="nl-NL" version="1.0.0"> - <resources> - <resource name="language"> - Taal voor OCR - </resource> - <resource name="orient_image"> - Beeld richten - </resource> - <resource name="straighten_image"> - Beeld vereffenen - </resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-pl-PL.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-pl-PL.xml deleted file mode 100644 index 37b40b65a..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-pl-PL.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Polski" ietf="pl-PL" version="1.1.4" languagegroup="2"> - <resources> - <resource name="language">Język dla OCR</resource> - <resource name="orient_image">Orientacja obrazu</resource> - <resource name="straighten_image">Wyprostowanie obrazów</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-pt-PT.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-pt-PT.xml deleted file mode 100644 index ee55958d8..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-pt-PT.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Portuguese (Portugal)" ietf="pt-PT" version="1.0.0"> - <resources> - <resource name="language">Idioma para OCR</resource> - <resource name="orient_image">Orientar imagem</resource> - <resource name="straighten_image">Endireitar imagem</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-ru-RU.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-ru-RU.xml deleted file mode 100644 index f2fffd34e..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-ru-RU.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Русский" ietf="ru-RU" version="1.1.4.2622" languagegroup="5"> - <resources> - <resource name="language">Язык для OCR</resource> - <resource name="orient_image">Ориентация изображения</resource> - <resource name="straighten_image">Выпрямление изображения</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-sk-SK.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-sk-SK.xml deleted file mode 100644 index 0f61ec429..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-sk-SK.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Slovenčina" ietf="sk-SK" version="1.0.0"> - <resources> - <resource name="language"> - Jazyk pre OCR - </resource> - <resource name="orient_image"> - Orientácia obrázku - </resource> - <resource name="straighten_image"> - Narovnať obrázok - </resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-sr-RS.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-sr-RS.xml deleted file mode 100644 index eaf252bd6..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-sr-RS.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Српски" ietf="sr-RS" version="1.0.0" languagegroup=""> - <resources> - <resource name="language">Језик за препознавање знакова</resource> - <resource name="orient_image">Усмери слику</resource> - <resource name="straighten_image">Исправи слику</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-sv-SE.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-sv-SE.xml deleted file mode 100644 index e59ce5e75..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-sv-SE.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Svenska" ietf="sv-SE" version="1.0.0"> - <resources> - <resource name="language"> - Språk för OCR - </resource> - <resource name="orient_image"> - Orientera bild - </resource> - <resource name="straighten_image"> - Släta ut bild - </resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-uk-UA.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-uk-UA.xml deleted file mode 100644 index 7a433eb4f..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-uk-UA.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Українська" ietf="uk-UA" version="1.0.0"> - <resources> - <resource name="language">Мова для ОРТ</resource> - <resource name="orient_image">Орієнтувати зображення</resource> - <resource name="straighten_image">Випрямлення зображення</resource> - </resources> -</language> diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-zh-CN.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-zh-CN.xml deleted file mode 100644 index ccd0e159a..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-zh-CN.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="简体中文" ietf="zh-CN" version="1.0.0"> - <resources> - <resource name="language"> - OCR语言 - </resource> - <resource name="orient_image"> - 图像定位 - </resource> - <resource name="straighten_image"> - 图像矫正 - </resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/Languages/language_ocrplugin-zh-TW.xml b/GreenshotOCRPlugin/Languages/language_ocrplugin-zh-TW.xml deleted file mode 100644 index dce00e4cf..000000000 --- a/GreenshotOCRPlugin/Languages/language_ocrplugin-zh-TW.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="正體中文" ietf="zh-TW" version="1.0.0" languagegroup="9"> - <resources> - <resource name="language">OCR 語言</resource> - <resource name="orient_image">定向圖片</resource> - <resource name="straighten_image">拉直圖片</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotOCRPlugin/ModiLanguage.cs b/GreenshotOCRPlugin/ModiLanguage.cs deleted file mode 100644 index 3edd95d0f..000000000 --- a/GreenshotOCRPlugin/ModiLanguage.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -namespace GreenshotOCRPlugin -{ - /// <summary> - /// Needed for the drop down, available languages for OCR - /// </summary> - public enum ModiLanguage { - CHINESE_SIMPLIFIED = 2052, - CHINESE_TRADITIONAL = 1028, - CZECH = 5, - DANISH = 6, - DUTCH = 19, - ENGLISH = 9, - FINNISH = 11, - FRENCH = 12, - GERMAN = 7, - GREEK = 8, - HUNGARIAN = 14, - ITALIAN = 16, - JAPANESE = 17, - KOREAN = 18, - NORWEGIAN = 20, - POLISH = 21, - PORTUGUESE = 22, - RUSSIAN = 25, - SPANISH = 10, - SWEDISH = 29, - TURKISH = 31, - SYSDEFAULT = 2048 - } -} \ No newline at end of file diff --git a/GreenshotOCRPlugin/OCRConfiguration.cs b/GreenshotOCRPlugin/OCRConfiguration.cs deleted file mode 100644 index 8eebcc91e..000000000 --- a/GreenshotOCRPlugin/OCRConfiguration.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using GreenshotPlugin.IniFile; - -namespace GreenshotOCRPlugin { - /// <summary> - /// Description of CoreConfiguration. - /// </summary> - [IniSection("OCR", Description="Greenshot OCR Plugin configuration")] - public class OCRConfiguration : IniSection { - [IniProperty("Language", Description="Language for OCR", DefaultValue="miLANG_ENGLISH")] - public string Language { get; set; } - [IniProperty("orientimage", Description="Orient image?", DefaultValue="true")] - public bool Orientimage { get; set; } - [IniProperty("straightenImage", Description="Straighten image?", DefaultValue="true")] - public bool StraightenImage { get; set; } - } -} diff --git a/GreenshotOCRPlugin/OCRDestination.cs b/GreenshotOCRPlugin/OCRDestination.cs deleted file mode 100644 index 5c774bfc1..000000000 --- a/GreenshotOCRPlugin/OCRDestination.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Drawing; -using System.IO; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; - -namespace GreenshotOCRPlugin { - /// <summary> - /// Description of OCRDestination. - /// </summary> - public class OCRDestination : AbstractDestination { - private readonly OcrPlugin _plugin; - - public override string Designation => "OCR"; - - public override string Description => "OCR"; - - public override Image DisplayIcon { - get { - string exePath = PluginUtils.GetExePath("MSPVIEW.EXE"); - if (exePath != null && File.Exists(exePath)) { - return PluginUtils.GetCachedExeIcon(exePath, 0); - } - return null; - } - } - - public OCRDestination(OcrPlugin plugin) { - _plugin = plugin; - } - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description) - { - ExportMade = _plugin.DoOcr(surface) != null - }; - return exportInformation; - } - } -} diff --git a/GreenshotOCRPlugin/OCRForm.cs b/GreenshotOCRPlugin/OCRForm.cs deleted file mode 100644 index 5ba8fda84..000000000 --- a/GreenshotOCRPlugin/OCRForm.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using GreenshotPlugin.Controls; - -namespace GreenshotOCRPlugin { - /// <summary> - /// This class is needed for design-time resolving of the language files - /// </summary> - public class OcrForm : GreenshotForm { - } -} diff --git a/GreenshotOCRPlugin/OCRPlugin.cs b/GreenshotOCRPlugin/OCRPlugin.cs deleted file mode 100644 index 677e22342..000000000 --- a/GreenshotOCRPlugin/OCRPlugin.cs +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; -using System.Diagnostics; -using System.IO; -using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; - -//using Microsoft.Win32; - -namespace GreenshotOCRPlugin { - /// <summary> - /// OCR Plugin Greenshot - /// </summary> - [Plugin("Ocr", true)] - public class OcrPlugin : IGreenshotPlugin { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(OcrPlugin)); - private string _ocrCommand; - private static OCRConfiguration _config; - private ToolStripMenuItem _ocrMenuItem = new ToolStripMenuItem(); - - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected void Dispose(bool disposing) - { - if (!disposing) return; - if (_ocrMenuItem == null) return; - _ocrMenuItem.Dispose(); - _ocrMenuItem = null; - } - - /// <summary> - /// Implementation of the IGreenshotPlugin.Initialize - /// </summary> - /// <returns>true if plugin is initialized, false if not (doesn't show)</returns> - public bool Initialize() { - Log.Debug("Initialize called"); - - var ocrDirectory = Path.GetDirectoryName(GetType().Assembly.Location); - if (ocrDirectory == null) - { - return false; - } - _ocrCommand = Path.Combine(ocrDirectory, "greenshotocrcommand.exe"); - - if (!HasModi()) { - Log.Warn("No MODI found!"); - return false; - } - // Provide the IDestination - SimpleServiceProvider.Current.AddService<IDestination>(new OCRDestination(this)); - // Load configuration - _config = IniConfig.GetIniSection<OCRConfiguration>(); - - if (_config.Language != null) { - _config.Language = _config.Language.Replace("miLANG_", string.Empty).Replace("_"," "); - } - return true; - } - - /// <summary> - /// Implementation of the IGreenshotPlugin.Shutdown - /// </summary> - public void Shutdown() { - Log.Debug("Shutdown"); - } - - /// <summary> - /// Implementation of the IPlugin.Configure - /// </summary> - public void Configure() { - if (!HasModi()) { - MessageBox.Show("Sorry, is seems that Microsoft Office Document Imaging (MODI) is not installed, therefor the OCR Plugin cannot work."); - return; - } - SettingsForm settingsForm = new SettingsForm(Enum.GetNames(typeof(ModiLanguage)), _config); - DialogResult result = settingsForm.ShowDialog(); - if (result == DialogResult.OK) { - // "Re"set hotkeys - IniConfig.Save(); - } - } - - - private const int MinWidth = 130; - private const int MinHeight = 130; - /// <summary> - /// Handling of the CaptureTaken "event" from the ICaptureHost - /// We do the OCR here! - /// </summary> - /// <param name="surface">Has the Image and the capture details</param> - public string DoOcr(ISurface surface) { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 0, true) - { - ReduceColors = true, - SaveBackgroundOnly = true - }; - // We only want the background - // Force Grayscale output - outputSettings.Effects.Add(new GrayscaleEffect()); - - // Also we need to check the size, resize if needed to 130x130 this is the minimum - if (surface.Image.Width < MinWidth || surface.Image.Height < MinHeight) { - int addedWidth = MinWidth - surface.Image.Width; - if (addedWidth < 0) { - addedWidth = 0; - } - int addedHeight = MinHeight - surface.Image.Height; - if (addedHeight < 0) { - addedHeight = 0; - } - IEffect effect = new ResizeCanvasEffect(addedWidth / 2, addedWidth / 2, addedHeight / 2, addedHeight / 2); - outputSettings.Effects.Add(effect); - } - var filePath = ImageOutput.SaveToTmpFile(surface, outputSettings, null); - - Log.Debug("Saved tmp file to: " + filePath); - - string text = ""; - try { - ProcessStartInfo processStartInfo = new ProcessStartInfo(_ocrCommand, "\"" + filePath + "\" " + _config.Language + " " + _config.Orientimage + " " + _config.StraightenImage) - { - CreateNoWindow = true, - RedirectStandardOutput = true, - UseShellExecute = false - }; - using Process process = Process.Start(processStartInfo); - if (process != null) - { - process.WaitForExit(30 * 1000); - if (process.ExitCode == 0) { - text = process.StandardOutput.ReadToEnd(); - } - } - } catch (Exception e) { - Log.Error("Error while calling Microsoft Office Document Imaging (MODI) to OCR: ", e); - } finally { - if (File.Exists(filePath)) { - Log.Debug("Cleaning up tmp file: " + filePath); - File.Delete(filePath); - } - } - - if (string.IsNullOrEmpty(text)) { - Log.Info("No text returned"); - return null; - } - - // For for BUG-1884: - text = text.Trim(); - - try { - Log.DebugFormat("Pasting OCR Text to Clipboard: {0}", text); - // Paste to Clipboard (the Plugin currently doesn't have access to the ClipboardHelper from Greenshot - IDataObject ido = new DataObject(); - ido.SetData(DataFormats.Text, true, text); - Clipboard.SetDataObject(ido, true); - } catch (Exception e) { - Log.Error("Problem pasting text to clipboard: ", e); - } - return text; - } - - private bool HasModi() { - try - { - using Process process = Process.Start(_ocrCommand, "-c"); - if (process != null) - { - process.WaitForExit(); - return process.ExitCode == 0; - } - } catch(Exception e) { - Log.DebugFormat("Error trying to initiate MODI: {0}", e.Message); - } - Log.InfoFormat("No Microsoft Office Document Imaging (MODI) found, disabling OCR"); - return false; - } - } -} \ No newline at end of file diff --git a/GreenshotOCRPlugin/SettingsForm.Designer.cs b/GreenshotOCRPlugin/SettingsForm.Designer.cs deleted file mode 100644 index a9e57749a..000000000 --- a/GreenshotOCRPlugin/SettingsForm.Designer.cs +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -namespace GreenshotOCRPlugin -{ - partial class SettingsForm - { - /// <summary> - /// Designer variable used to keep track of non-visual components. - /// </summary> - private System.ComponentModel.IContainer components = null; - - /// <summary> - /// Disposes resources used by the form. - /// </summary> - /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> - protected override void Dispose(bool disposing) - { - if (disposing) { - if (components != null) { - components.Dispose(); - } - } - base.Dispose(disposing); - } - - /// <summary> - /// This method is required for Windows Forms designer support. - /// Do not change the method contents inside the source code editor. The Forms designer might - /// not be able to load this method if it was changed manually. - /// </summary> - private void InitializeComponent() - { - this.comboBox_languages = new System.Windows.Forms.ComboBox(); - this.checkBox_orientImage = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkBox_straightenImage = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.label_language = new GreenshotPlugin.Controls.GreenshotLabel(); - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.SuspendLayout(); - // - // comboBox_languages - // - this.comboBox_languages.FormattingEnabled = true; - this.comboBox_languages.Items.AddRange(new object[] { - "English", - "Deutsch"}); - this.comboBox_languages.Location = new System.Drawing.Point(74, 12); - this.comboBox_languages.Name = "comboBox_languages"; - this.comboBox_languages.Size = new System.Drawing.Size(153, 21); - this.comboBox_languages.TabIndex = 1; - // - // checkBox_orientImage - // - this.checkBox_orientImage.LanguageKey = "ocr.orient_image"; - this.checkBox_orientImage.Location = new System.Drawing.Point(13, 68); - this.checkBox_orientImage.Name = "checkBox_orientImage"; - this.checkBox_orientImage.PropertyName = "orientimage"; - this.checkBox_orientImage.SectionName = "OCR"; - this.checkBox_orientImage.Size = new System.Drawing.Size(104, 24); - this.checkBox_orientImage.TabIndex = 3; - this.checkBox_orientImage.UseVisualStyleBackColor = true; - // - // checkBox_straightenImage - // - this.checkBox_straightenImage.LanguageKey = "ocr.straighten_image"; - this.checkBox_straightenImage.Location = new System.Drawing.Point(13, 41); - this.checkBox_straightenImage.Name = "checkBox_straightenImage"; - this.checkBox_straightenImage.PropertyName = "straightenImage"; - this.checkBox_straightenImage.SectionName = "OCR"; - this.checkBox_straightenImage.Size = new System.Drawing.Size(109, 24); - this.checkBox_straightenImage.TabIndex = 2; - this.checkBox_straightenImage.UseVisualStyleBackColor = true; - // - // label_language - // - this.label_language.LanguageKey = "ocr.language"; - this.label_language.Location = new System.Drawing.Point(13, 15); - this.label_language.Name = "label_language"; - this.label_language.Size = new System.Drawing.Size(55, 23); - this.label_language.TabIndex = 3; - // - // buttonOK - // - this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; - this.buttonOK.LanguageKey = "OK"; - this.buttonOK.Location = new System.Drawing.Point(12, 98); - this.buttonOK.Name = "buttonOK"; - this.buttonOK.Size = new System.Drawing.Size(104, 23); - this.buttonOK.TabIndex = 4; - this.buttonOK.UseVisualStyleBackColor = true; - this.buttonOK.Click += new System.EventHandler(this.ButtonOKClick); - // - // buttonCancel - // - this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonCancel.LanguageKey = "CANCEL"; - this.buttonCancel.Location = new System.Drawing.Point(128, 98); - this.buttonCancel.Name = "buttonCancel"; - this.buttonCancel.Size = new System.Drawing.Size(104, 23); - this.buttonCancel.TabIndex = 5; - this.buttonCancel.UseVisualStyleBackColor = true; - // - // SettingsForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(244, 135); - this.Controls.Add(this.buttonCancel); - this.Controls.Add(this.buttonOK); - this.Controls.Add(this.label_language); - this.Controls.Add(this.checkBox_straightenImage); - this.Controls.Add(this.checkBox_orientImage); - this.Controls.Add(this.comboBox_languages); - this.LanguageKey = "settings_title"; - this.Name = "SettingsForm"; - this.ResumeLayout(false); - - } - private GreenshotPlugin.Controls.GreenshotLabel label_language; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotCheckBox checkBox_orientImage; - private GreenshotPlugin.Controls.GreenshotCheckBox checkBox_straightenImage; - private System.Windows.Forms.ComboBox comboBox_languages; - } -} diff --git a/GreenshotOCRPlugin/SettingsForm.cs b/GreenshotOCRPlugin/SettingsForm.cs deleted file mode 100644 index 94805f941..000000000 --- a/GreenshotOCRPlugin/SettingsForm.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; - -namespace GreenshotOCRPlugin { - /// <summary> - /// Description of SettingsForm. - /// </summary> - public partial class SettingsForm : OcrForm { - private readonly OCRConfiguration _config; - - public SettingsForm(string [] languages, OCRConfiguration config) { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - this._config = config; - InitializeComponent(); - AcceptButton = buttonOK; - CancelButton = buttonCancel; - - comboBox_languages.Items.Clear(); - int index=0; - - // Preventing Tracker #3234560, although this should not happen... - string languageFromConfig = "ENGLISH"; - if (config.Language != null) { - languageFromConfig = config.Language; - } - foreach(string availableLanguage in languages) { - string displayLanguage = availableLanguage.Substring(0, 1).ToUpper() + availableLanguage.Substring(1).ToLower(); - comboBox_languages.Items.Add(displayLanguage); - if (availableLanguage.Equals(languageFromConfig, StringComparison.CurrentCultureIgnoreCase)) { - comboBox_languages.SelectedIndex = index; - } - index++; - } - } - - private void ButtonOKClick(object sender, EventArgs e) { - string selectedString = (string) comboBox_languages.SelectedItem; - if (selectedString != null) { - _config.Language = selectedString.ToUpper(); - } - } - } -} diff --git a/GreenshotOfficePlugin/Com/Ole32Api.cs b/GreenshotOfficePlugin/Com/Ole32Api.cs index 783f48d0d..d80167022 100644 --- a/GreenshotOfficePlugin/Com/Ole32Api.cs +++ b/GreenshotOfficePlugin/Com/Ole32Api.cs @@ -27,21 +27,6 @@ namespace GreenshotOfficePlugin.Com return clsId; } - /// <summary> - /// This converts a clsid (Class ID) into a ProgID (program ID) - /// </summary> - /// <param name="clsId">Guid with the clsid (Class ID)</param> - /// <returns>string with the progid</returns> - public static string ProgIdFromClassId(Guid clsId) - { - if (ProgIDFromCLSID(ref clsId, out string progId).Succeeded()) - { - return progId; - } - - return null; - } - /// <summary> /// See more <a href="https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-clsidfromprogid">here</a> /// </summary> @@ -50,14 +35,5 @@ namespace GreenshotOfficePlugin.Com /// <returns>HResult</returns> [DllImport("ole32.dll", ExactSpelling = true)] private static extern HResult CLSIDFromProgID([In] [MarshalAs(UnmanagedType.LPWStr)] string progId, [Out] out Guid clsId); - - /// <summary> - /// See more <a href="https://docs.microsoft.com/en-us/windows/desktop/api/combaseapi/nf-combaseapi-progidfromclsid">here</a> - /// </summary> - /// <param name="clsId">Guid The CLSID for which the ProgID is to be requested.</param> - /// <param name="lplpszProgId">string the ProgID string. The string that represents clsid includes enclosing braces.</param> - /// <returns>HResult</returns> - [DllImport("ole32.dll")] - private static extern HResult ProgIDFromCLSID([In] ref Guid clsId, [MarshalAs(UnmanagedType.LPWStr)] out string lplpszProgId); } } diff --git a/GreenshotPhotobucketPlugin/LanguageKeys.cs b/GreenshotPhotobucketPlugin/LanguageKeys.cs index b94f13722..010c4fda0 100644 --- a/GreenshotPhotobucketPlugin/LanguageKeys.cs +++ b/GreenshotPhotobucketPlugin/LanguageKeys.cs @@ -22,13 +22,8 @@ namespace GreenshotPhotobucketPlugin { public enum LangKey { upload_menu_item, - settings_title, - label_upload_format, - label_clear, - upload_success, upload_failure, communication_wait, - use_page_link, configure } } diff --git a/GreenshotPlugin/Controls/BackgroundForm.cs b/GreenshotPlugin/Controls/BackgroundForm.cs index 5ce737185..9ffe414e1 100644 --- a/GreenshotPlugin/Controls/BackgroundForm.cs +++ b/GreenshotPlugin/Controls/BackgroundForm.cs @@ -20,7 +20,6 @@ */ using System; using System.Drawing; -using System.Threading; using System.Windows.Forms; using GreenshotPlugin.Core; @@ -30,23 +29,8 @@ namespace GreenshotPlugin.Controls { /// </summary> public sealed partial class BackgroundForm : Form { private volatile bool _shouldClose; - - private void BackgroundShowDialog() { - ShowDialog(); - } - public static BackgroundForm ShowAndWait(string title, string text) { - BackgroundForm backgroundForm = new BackgroundForm(title, text); - // Show form in background thread - Thread backgroundTask = new Thread (backgroundForm.BackgroundShowDialog); - backgroundForm.Name = "Background form"; - backgroundTask.IsBackground = true; - backgroundTask.SetApartmentState(ApartmentState.STA); - backgroundTask.Start(); - return backgroundForm; - } - - public BackgroundForm(string title, string text){ + public BackgroundForm(string title, string text){ // // The InitializeComponent() call is required for Windows Forms designer support. // diff --git a/GreenshotPlugin/Controls/HotkeyControl.cs b/GreenshotPlugin/Controls/HotkeyControl.cs index cb9f4593a..6f1c6d8d5 100644 --- a/GreenshotPlugin/Controls/HotkeyControl.cs +++ b/GreenshotPlugin/Controls/HotkeyControl.cs @@ -426,11 +426,7 @@ namespace GreenshotPlugin.Controls { _hotkeyHwnd = hWnd; } - public static int RegisterHotKey(string hotkey, HotKeyHandler handler) { - return RegisterHotKey(HotkeyModifiersFromString(hotkey), HotkeyFromString(hotkey),handler); - } - - /// <summary> + /// <summary> /// Register a hotkey /// </summary> /// <param name="modifierKeyCode">The modifier, e.g.: Modifiers.CTRL, Modifiers.NONE or Modifiers.ALT</param> @@ -477,21 +473,7 @@ namespace GreenshotPlugin.Controls { KeyHandlers.Clear(); } - public static void UnregisterHotkey(int hotkey) { - bool removeHotkey = false; - foreach(int availableHotkey in KeyHandlers.Keys) { - if (availableHotkey == hotkey) { - UnregisterHotKey(_hotkeyHwnd, hotkey); - removeHotkey = true; - } - } - if (removeHotkey) { - // Remove key handler - KeyHandlers.Remove(hotkey); - } - } - - /// <summary> + /// <summary> /// Handle WndProc messages for the hotkey /// </summary> /// <param name="m"></param> diff --git a/GreenshotPlugin/Core/AccessibleHelper.cs b/GreenshotPlugin/Core/AccessibleHelper.cs index 871892e64..36d9e0ed5 100644 --- a/GreenshotPlugin/Core/AccessibleHelper.cs +++ b/GreenshotPlugin/Core/AccessibleHelper.cs @@ -91,35 +91,7 @@ namespace GreenshotPlugin.Core { } } - public void ActivateIETab(string tabCaptionToActivate) { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - if (tab.Name == tabCaptionToActivate) { - tab.Activate(); - return; - } - } - } - } - } - - public void CloseIETab(string tabCaptionToClose) { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - if (tab.Name == tabCaptionToClose) { - foreach (var CloseTab in tab.Children) { - CloseTab.Activate(); - } - return; - } - } - } - } - } - - public void ActivateIETab(int tabIndexToActivate) { + public void ActivateIETab(int tabIndexToActivate) { var index = 0; foreach (Accessible accessor in Children) { foreach (var child in accessor.Children) { @@ -138,50 +110,7 @@ namespace GreenshotPlugin.Core { } } - public string IEActiveTabUrl { - get { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - object tabIndex = tab.accessible.get_accState(CHILDID_SELF); - - if ((int)tabIndex == IE_ACTIVE_TAB) { - var description = tab.accessible.get_accDescription(CHILDID_SELF); - - if (!string.IsNullOrEmpty(description)) { - if (description.Contains(Environment.NewLine)) { - var url = description.Substring(description.IndexOf(Environment.NewLine)).Trim(); - return url; - } - } - } - } - } - } - return string.Empty; - } - } - - public int IEActiveTabIndex { - get { - var index = 0; - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - object tabIndex = tab.accessible.get_accState(0); - - if ((int)tabIndex == IE_ACTIVE_TAB) { - return index; - } - index++; - } - } - } - return -1; - } - } - - public string IEActiveTabCaption { + public string IEActiveTabCaption { get { foreach (Accessible accessor in Children) { foreach (var child in accessor.Children) { @@ -238,21 +167,8 @@ namespace GreenshotPlugin.Core { } } } - - public int IETabCount { - get { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - return child.ChildCount - 1; - } - } - } - return 0; - } - } - private Accessible(IAccessible acc) { + private Accessible(IAccessible acc) { accessible = acc ?? throw new Exception(); } diff --git a/GreenshotPlugin/Core/Capture.cs b/GreenshotPlugin/Core/Capture.cs index 95a7fb872..2b0180de2 100644 --- a/GreenshotPlugin/Core/Capture.cs +++ b/GreenshotPlugin/Core/Capture.cs @@ -1,5 +1,25 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + using System; -using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using GreenshotPlugin.Interfaces; @@ -14,7 +34,6 @@ namespace GreenshotPlugin.Core /// </summary> public class Capture : ICapture { private static readonly ILog Log = LogManager.GetLogger(typeof(Capture)); - private List<ICaptureElement> _elements = new List<ICaptureElement>(); private Rectangle _screenBounds; /// <summary> @@ -178,15 +197,6 @@ namespace GreenshotPlugin.Core // TODO: Remove invisible lines/words? CaptureDetails.OcrInformation?.Offset(-cropRectangle.Location.X, -cropRectangle.Location.Y); - // Remove invisible elements - var visibleElements = new List<ICaptureElement>(); - foreach(var captureElement in _elements) { - if (captureElement.Bounds.IntersectsWith(cropRectangle)) { - visibleElements.Add(captureElement); - } - } - _elements = visibleElements; - return true; } diff --git a/GreenshotPlugin/Core/CaptureDetails.cs b/GreenshotPlugin/Core/CaptureDetails.cs index f6e0474ea..c600ced26 100644 --- a/GreenshotPlugin/Core/CaptureDetails.cs +++ b/GreenshotPlugin/Core/CaptureDetails.cs @@ -1,3 +1,24 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + using System; using System.Collections.Generic; using GreenshotPlugin.Interfaces; diff --git a/GreenshotPlugin/Core/CaptureElement.cs b/GreenshotPlugin/Core/CaptureElement.cs deleted file mode 100644 index 6b0f3ab73..000000000 --- a/GreenshotPlugin/Core/CaptureElement.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; -using GreenshotPlugin.Interfaces; - -namespace GreenshotPlugin.Core -{ - /// <summary> - /// A class representing an element in the capture - /// </summary> - public class CaptureElement : ICaptureElement { - public CaptureElement(Rectangle bounds) { - Bounds = bounds; - } - public CaptureElement(string name) { - Name = name; - } - public CaptureElement(string name, Rectangle bounds) { - Name = name; - Bounds = bounds; - } - - public List<ICaptureElement> Children { get; set; } = new List<ICaptureElement>(); - - public string Name { - get; - set; - } - public Rectangle Bounds { - get; - set; - } - - // CaptureElements are regarded equal if their bounds are equal. this should be sufficient. - public override bool Equals(object obj) { - if (obj == null || GetType() != obj.GetType()) - { - return false; - } - - return obj is CaptureElement other && Bounds.Equals(other.Bounds); - } - - public override int GetHashCode() { - // TODO: Fix this, this is not right... - return Bounds.GetHashCode(); - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/ClipboardHelper.cs b/GreenshotPlugin/Core/ClipboardHelper.cs index 046838716..f5af04b9d 100644 --- a/GreenshotPlugin/Core/ClipboardHelper.cs +++ b/GreenshotPlugin/Core/ClipboardHelper.cs @@ -34,7 +34,9 @@ using System.Runtime.InteropServices; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; +using GreenshotPlugin.Interop; using log4net; +using HtmlDocument = HtmlAgilityPack.HtmlDocument; namespace GreenshotPlugin.Core { /// <summary> @@ -45,7 +47,8 @@ namespace GreenshotPlugin.Core { private static readonly object ClipboardLockObject = new object(); private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>(); private static readonly string FORMAT_FILECONTENTS = "FileContents"; - private static readonly string FORMAT_PNG = "PNG"; + private static readonly string FORMAT_HTML = "text/html"; + private static readonly string FORMAT_PNG = "PNG"; private static readonly string FORMAT_PNG_OFFICEART = "PNG+Office Art"; private static readonly string FORMAT_17 = "Format17"; private static readonly string FORMAT_JPG = "JPG"; @@ -207,17 +210,8 @@ EndSelection:<<<<<<<4 } return null; } - - /// <summary> - /// Wrapper for Clipboard.ContainsText, Created for Bug #3432313 - /// </summary> - /// <returns>boolean if there is text on the clipboard</returns> - public static bool ContainsText() { - IDataObject clipboardData = GetDataObject(); - return ContainsText(clipboardData); - } - /// <summary> + /// <summary> /// Test if the IDataObject contains Text /// </summary> /// <param name="dataObject"></param> @@ -246,41 +240,124 @@ EndSelection:<<<<<<<4 /// <param name="dataObject"></param> /// <returns>true if an image is there</returns> public static bool ContainsImage(IDataObject dataObject) { - if (dataObject != null) { - if (dataObject.GetDataPresent(DataFormats.Bitmap) - || dataObject.GetDataPresent(DataFormats.Dib) - || dataObject.GetDataPresent(DataFormats.Tiff) - || dataObject.GetDataPresent(DataFormats.EnhancedMetafile) - || dataObject.GetDataPresent(FORMAT_PNG) - || dataObject.GetDataPresent(FORMAT_17) - || dataObject.GetDataPresent(FORMAT_JPG) - || dataObject.GetDataPresent(FORMAT_JFIF) - || dataObject.GetDataPresent(FORMAT_JPEG) - || dataObject.GetDataPresent(FORMAT_GIF)) { - return true; - } - var imageFiles = GetImageFilenames(dataObject); - if (imageFiles.Any()) { - return true; - } - if (dataObject.GetDataPresent(FORMAT_FILECONTENTS)) { - try { - MemoryStream imageStream = dataObject.GetData(FORMAT_FILECONTENTS) as MemoryStream; - if (IsValidStream(imageStream)) { - using (ImageHelper.FromStream(imageStream)) - { - // If we get here, there is an image - return true; - } - } - } catch (Exception) { - // Ignore - } - } - } - return false; + if (dataObject == null) return false; + + if (dataObject.GetDataPresent(DataFormats.Bitmap) + || dataObject.GetDataPresent(DataFormats.Dib) + || dataObject.GetDataPresent(DataFormats.Tiff) + || dataObject.GetDataPresent(DataFormats.EnhancedMetafile) + || dataObject.GetDataPresent(FORMAT_PNG) + || dataObject.GetDataPresent(FORMAT_17) + || dataObject.GetDataPresent(FORMAT_JPG) + || dataObject.GetDataPresent(FORMAT_JFIF) + || dataObject.GetDataPresent(FORMAT_JPEG) + || dataObject.GetDataPresent(FORMAT_GIF)) { + return true; + } + + var imageFiles = GetImageFilenames(dataObject); + if (imageFiles.Any()) { + return true; + } + + var fileDescriptor = (MemoryStream)dataObject.GetData("FileGroupDescriptorW"); + var files = FileDescriptorReader.Read(fileDescriptor); + var fileIndex = 0; + foreach (var fileContentFile in files) + { + if ((fileContentFile.FileAttributes & FileAttributes.Directory) != 0) + { + //Do something with directories? + //Note that directories do not have FileContents + //And will throw if we try to read them + continue; + } + + var fileData = FileDescriptorReader.GetFileContents(dataObject, fileIndex); + try + { + //Do something with the fileContent Stream + if (IsValidStream(fileData)) + { + fileData.Position = 0; + using (ImageHelper.FromStream(fileData)) + { + // If we get here, there is an image + return true; + } + } + } + finally + { + fileData?.Dispose(); + } + fileIndex++; + } + + if (dataObject.GetDataPresent(FORMAT_FILECONTENTS)) + { + try + { + var clipboardContent = dataObject.GetData(FORMAT_FILECONTENTS, true); + var imageStream = clipboardContent as MemoryStream; + if (IsValidStream(imageStream)) + { + using (ImageHelper.FromStream(imageStream)) + { + // If we get here, there is an image + return true; + } + } + } + catch (Exception) + { + // Ignore + } + } + + // Try to get the image from the HTML code + var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); + if (textObject != null) + { + var doc = new HtmlDocument(); + doc.LoadHtml(textObject); + var imgNodes = doc.DocumentNode.SelectNodes("//img"); + if (imgNodes != null) + { + foreach (var imgNode in imgNodes) + { + var srcAttribute = imgNode.Attributes["src"]; + var imageUrl = srcAttribute.Value; + if (!string.IsNullOrEmpty(imageUrl)) + { + return true; + } + } + } + } + return false; } + /// <summary> + /// Get the specified IDataObject format as a string + /// </summary> + /// <param name="dataObject">IDataObject</param> + /// <param name="format">string</param> + /// <param name="encoding">Encoding</param> + /// <returns>sting</returns> + private static string ContentAsString(IDataObject dataObject, string format, Encoding encoding = null) + { + encoding ??= Encoding.Unicode; + var objectAsFormat = dataObject.GetData(format); + return objectAsFormat switch + { + null => null, + string text => text, + MemoryStream ms => encoding.GetString(ms.ToArray()), + _ => null + }; + } + /// <summary> /// Simple helper to check the stream /// </summary> @@ -348,9 +425,9 @@ EndSelection:<<<<<<<4 if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) { // Outlook ?? Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front..."); - retrieveFormats = new[] { DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF }; + retrieveFormats = new[] { DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML }; } else { - retrieveFormats = new[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF }; + retrieveFormats = new[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML }; } foreach (string currentFormat in retrieveFormats) { if (formats != null && formats.Contains(currentFormat)) { @@ -376,8 +453,32 @@ EndSelection:<<<<<<<4 /// <param name="dataObject">IDataObject</param> /// <returns>Image or null</returns> private static Image GetImageForFormat(string format, IDataObject dataObject) { + if (format == FORMAT_HTML) + { + var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); + if (textObject != null) + { + var doc = new HtmlDocument(); + doc.LoadHtml(textObject); + var imgNodes = doc.DocumentNode.SelectNodes("//img"); + if (imgNodes != null) + { + foreach (var imgNode in imgNodes) + { + var srcAttribute = imgNode.Attributes["src"]; + var imageUrl = srcAttribute.Value; + Log.Debug(imageUrl); + var image = NetworkHelper.DownloadImage(imageUrl); + if (image != null) + { + return image; + } + } + } + } + } object clipboardObject = GetFromDataObject(dataObject, format); - MemoryStream imageStream = clipboardObject as MemoryStream; + var imageStream = clipboardObject as MemoryStream; if (!IsValidStream(imageStream)) { // TODO: add "HTML Format" support here... return clipboardObject as Image; @@ -390,14 +491,14 @@ EndSelection:<<<<<<<4 { byte[] dibBuffer = new byte[imageStream.Length]; imageStream.Read(dibBuffer, 0, dibBuffer.Length); - BITMAPINFOHEADER infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADER>(dibBuffer); + var infoHeader = BinaryStructHelper.FromByteArray<BITMAPINFOHEADER>(dibBuffer); if (!infoHeader.IsDibV5) { Log.InfoFormat("Using special DIB <v5 format reader with biCompression {0}", infoHeader.biCompression); int fileHeaderSize = Marshal.SizeOf(typeof(BITMAPFILEHEADER)); uint infoHeaderSize = infoHeader.biSize; int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage); - BITMAPFILEHEADER fileHeader = new BITMAPFILEHEADER + var fileHeader = new BITMAPFILEHEADER { bfType = BITMAPFILEHEADER.BM, bfSize = fileSize, @@ -408,7 +509,7 @@ EndSelection:<<<<<<<4 byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader); - using MemoryStream bitmapStream = new MemoryStream(); + using var bitmapStream = new MemoryStream(); bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize); bitmapStream.Write(dibBuffer, 0, dibBuffer.Length); bitmapStream.Seek(0, SeekOrigin.Begin); @@ -459,6 +560,7 @@ EndSelection:<<<<<<<4 } catch (Exception streamImageEx) { Log.Error($"Problem retrieving {format} from clipboard.", streamImageEx); } + return null; } @@ -706,16 +808,8 @@ EndSelection:<<<<<<<4 // Use false to make the object disappear when the application stops. SetDataObject(dataObj, true); } - - /// <summary> - /// Retrieve a list of all formats currently on the clipboard - /// </summary> - /// <returns>List of strings with the current formats</returns> - public static List<string> GetFormats() { - return GetFormats(GetDataObject()); - } - /// <summary> + /// <summary> /// Retrieve a list of all formats currently in the IDataObject /// </summary> /// <returns>List of string with the current formats</returns> @@ -732,16 +826,7 @@ EndSelection:<<<<<<<4 return new List<string>(); } - /// <summary> - /// Check if there is currently something in the dataObject which has the supplied format - /// </summary> - /// <param name="format">string with format</param> - /// <returns>true if one the format is found</returns> - public static bool ContainsFormat(string format) { - return ContainsFormat(GetDataObject(), new[]{format}); - } - - /// <summary> + /// <summary> /// Check if there is currently something on the clipboard which has the supplied format /// </summary> /// <param name="dataObject">IDataObject</param> @@ -781,17 +866,7 @@ EndSelection:<<<<<<<4 return formatFound; } - /// <summary> - /// Get Object of type Type from the clipboard - /// </summary> - /// <param name="type">Type to get</param> - /// <returns>object from clipboard</returns> - public static object GetClipboardData(Type type) { - string format = type.FullName; - return GetClipboardData(format); - } - - /// <summary> + /// <summary> /// Get Object for format from IDataObject /// </summary> /// <param name="dataObj">IDataObject</param> @@ -837,14 +912,5 @@ EndSelection:<<<<<<<4 } return null; } - - /// <summary> - /// Get Object for format from the clipboard - /// </summary> - /// <param name="format">format to get</param> - /// <returns>object from clipboard</returns> - public static object GetClipboardData(string format) { - return GetFromDataObject(GetDataObject(), format); - } - } + } } diff --git a/GreenshotPlugin/Core/CoreConfiguration.cs b/GreenshotPlugin/Core/CoreConfiguration.cs index bf2570ce9..9a5ef5270 100644 --- a/GreenshotPlugin/Core/CoreConfiguration.cs +++ b/GreenshotPlugin/Core/CoreConfiguration.cs @@ -305,25 +305,7 @@ namespace GreenshotPlugin.Core { [IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")] public int WebRequestReadWriteTimeout { get; set; } - /// <summary> - /// Specifies what THIS build is - /// </summary> - public BuildStates BuildState { - get { - string informationalVersion = Application.ProductVersion; - if (informationalVersion != null) { - if (informationalVersion.ToLowerInvariant().Contains("-rc")) { - return BuildStates.RELEASE_CANDIDATE; - } - if (informationalVersion.ToLowerInvariant().Contains("-unstable")) { - return BuildStates.UNSTABLE; - } - } - return BuildStates.RELEASE; - } - } - - public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32; + public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32; /// <summary> /// A helper method which returns true if the supplied experimental feature is enabled diff --git a/GreenshotPlugin/Core/CredentialsHelper.cs b/GreenshotPlugin/Core/CredentialsHelper.cs index 95426e934..49b720b25 100644 --- a/GreenshotPlugin/Core/CredentialsHelper.cs +++ b/GreenshotPlugin/Core/CredentialsHelper.cs @@ -242,68 +242,14 @@ namespace GreenshotPlugin.Core { } } - /// <summary>Shows the credentials dialog.</summary> - /// <returns>Returns a DialogResult indicating the user action.</returns> - public DialogResult Show() { - return Show(null, Name, Password, SaveChecked); - } - - /// <summary>Shows the credentials dialog with the specified save checkbox status.</summary> - /// <param name="saveChecked">True if the save checkbox is checked.</param> - /// <returns>Returns a DialogResult indicating the user action.</returns> - public DialogResult Show(bool saveChecked) { - return Show(null, Name, Password, saveChecked); - } - - /// <summary>Shows the credentials dialog with the specified name.</summary> + /// <summary>Shows the credentials dialog with the specified name.</summary> /// <param name="name">The name for the credentials.</param> /// <returns>Returns a DialogResult indicating the user action.</returns> public DialogResult Show(string name) { return Show(null, name, Password, SaveChecked); } - /// <summary>Shows the credentials dialog with the specified name and password.</summary> - /// <param name="name">The name for the credentials.</param> - /// <param name="password">The password for the credentials.</param> - /// <returns>Returns a DialogResult indicating the user action.</returns> - public DialogResult Show(string name, string password) { - return Show(null, name, password, SaveChecked); - } - - /// <summary>Shows the credentials dialog with the specified name, password and save checkbox status.</summary> - /// <param name="name">The name for the credentials.</param> - /// <param name="password">The password for the credentials.</param> - /// <param name="saveChecked">True if the save checkbox is checked.</param> - /// <returns>Returns a DialogResult indicating the user action.</returns> - public DialogResult Show(string name, string password, bool saveChecked) { - return Show(null, name, password, saveChecked); - } - - /// <summary>Shows the credentials dialog with the specified owner.</summary> - /// <param name="owner">The System.Windows.Forms.IWin32Window the dialog will display in front of.</param> - /// <returns>Returns a DialogResult indicating the user action.</returns> - public DialogResult Show(IWin32Window owner) { - return Show(owner, Name, Password, SaveChecked); - } - - /// <summary>Shows the credentials dialog with the specified owner and save checkbox status.</summary> - /// <param name="owner">The System.Windows.Forms.IWin32Window the dialog will display in front of.</param> - /// <param name="saveChecked">True if the save checkbox is checked.</param> - /// <returns>Returns a DialogResult indicating the user action.</returns> - public DialogResult Show(IWin32Window owner, bool saveChecked) { - return Show(owner, Name, Password, saveChecked); - } - - /// <summary>Shows the credentials dialog with the specified owner, name and password.</summary> - /// <param name="owner">The System.Windows.Forms.IWin32Window the dialog will display in front of.</param> - /// <param name="name">The name for the credentials.</param> - /// <param name="password">The password for the credentials.</param> - /// <returns>Returns a DialogResult indicating the user action.</returns> - public DialogResult Show(IWin32Window owner, string name, string password) { - return Show(owner, name, password, SaveChecked); - } - - /// <summary>Shows the credentials dialog with the specified owner, name, password and save checkbox status.</summary> + /// <summary>Shows the credentials dialog with the specified owner, name, password and save checkbox status.</summary> /// <param name="owner">The System.Windows.Forms.IWin32Window the dialog will display in front of.</param> /// <param name="name">The name for the credentials.</param> /// <param name="password">The password for the credentials.</param> @@ -450,7 +396,6 @@ namespace GreenshotPlugin.Core { public const int MAX_MESSAGE_LENGTH = 100; public const int MAX_CAPTION_LENGTH = 100; public const int MAX_GENERIC_TARGET_LENGTH = 100; - public const int MAX_DOMAIN_TARGET_LENGTH = 100; public const int MAX_USERNAME_LENGTH = 100; public const int MAX_PASSWORD_LENGTH = 100; @@ -463,20 +408,12 @@ namespace GreenshotPlugin.Core { public enum CredFlags { INCORRECT_PASSWORD = 0x1, DO_NOT_PERSIST = 0x2, - REQUEST_ADMINISTRATOR = 0x4, EXCLUDE_CERTIFICATES = 0x8, - REQUIRE_CERTIFICATE = 0x10, SHOW_SAVE_CHECK_BOX = 0x40, ALWAYS_SHOW_UI = 0x80, - REQUIRE_SMARTCARD = 0x100, - PASSWORD_ONLY_OK = 0x200, - VALIDATE_USERNAME = 0x400, - COMPLETE_USERNAME = 0x800, PERSIST = 0x1000, - SERVER_CREDENTIAL = 0x4000, EXPECT_CONFIRMATION = 0x20000, GENERIC_CREDENTIALS = 0x40000, - USERNAME_TARGET_CREDENTIALS = 0x80000, KEEP_USERNAME = 0x100000, } diff --git a/GreenshotPlugin/Core/DpiHelper.cs b/GreenshotPlugin/Core/DpiHelper.cs index 991f2897e..a0c4db3ff 100644 --- a/GreenshotPlugin/Core/DpiHelper.cs +++ b/GreenshotPlugin/Core/DpiHelper.cs @@ -1,8 +1,28 @@ -using GreenshotPlugin.Core.Enums; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using GreenshotPlugin.Core.Enums; using GreenshotPlugin.UnmanagedHelpers; using log4net; using System; -using System.Diagnostics; using System.Drawing; using System.Runtime.InteropServices; using GreenshotPlugin.UnmanagedHelpers.Enums; @@ -59,23 +79,6 @@ namespace GreenshotPlugin.Core return dpiScaleFactor * someNumber; } - /// <summary> - /// Scale the supplied number according to the supplied dpi - /// </summary> - /// <param name="number">int with e.g. 16 for 16x16 images</param> - /// <param name="dpi">current dpi, normal is 96.</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>Scaled width</returns> - public static int ScaleWithDpi(int number, uint dpi, Func<float, float> scaleModifier = null) - { - var dpiScaleFactor = DpiScaleFactor(dpi); - if (scaleModifier != null) - { - dpiScaleFactor = scaleModifier(dpiScaleFactor); - } - return (int)(dpiScaleFactor * number); - } - /// <summary> /// Scale the supplied Size according to the supplied dpi /// </summary> @@ -93,79 +96,6 @@ namespace GreenshotPlugin.Core return new Size((int)(dpiScaleFactor * size.Width), (int)(dpiScaleFactor * size.Height)); } - /// <summary> - /// Scale the supplied NativePoint according to the supplied dpi - /// </summary> - /// <param name="size">NativePoint to resize</param> - /// <param name="dpi">current dpi, normal is 96.</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>NativePoint scaled</returns> - public static Point ScaleWithDpi(Point size, uint dpi, Func<float, float> scaleModifier = null) - { - var dpiScaleFactor = DpiScaleFactor(dpi); - if (scaleModifier != null) - { - dpiScaleFactor = scaleModifier(dpiScaleFactor); - } - return new Point((int)(dpiScaleFactor * size.X), (int)(dpiScaleFactor * size.Y)); - } - - /// <summary> - /// Scale the supplied NativeSizeFloat according to the supplied dpi - /// </summary> - /// <param name="point">PointF</param> - /// <param name="dpi">current dpi, normal is 96.</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>PointF</returns> - public static PointF ScaleWithDpi(PointF point, uint dpi, Func<float, float> scaleModifier = null) - { - var dpiScaleFactor = DpiScaleFactor(dpi); - if (scaleModifier != null) - { - dpiScaleFactor = scaleModifier(dpiScaleFactor); - } - return new PointF(dpiScaleFactor * point.X, dpiScaleFactor * point.Y); - } - - /// <summary> - /// Scale the supplied NativeSizeFloat according to the supplied dpi - /// </summary> - /// <param name="size">NativeSizeFloat to resize</param> - /// <param name="dpi">current dpi, normal is 96.</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>NativeSize scaled</returns> - public static SizeF ScaleWithDpi(SizeF size, uint dpi, Func<float, float> scaleModifier = null) - { - var dpiScaleFactor = DpiScaleFactor(dpi); - if (scaleModifier != null) - { - dpiScaleFactor = scaleModifier(dpiScaleFactor); - } - return new SizeF(dpiScaleFactor * size.Width, dpiScaleFactor * size.Height); - } - - /// <summary> - /// Scale the supplied number to the current dpi - /// </summary> - /// <param name="someNumber">double with e.g. a width like 16 for 16x16 images</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>double with scaled number</returns> - public static float ScaleWithCurrentDpi(float someNumber, Func<float, float> scaleModifier = null) - { - return ScaleWithDpi(someNumber, Dpi, scaleModifier); - } - - /// <summary> - /// Scale the supplied number to the current dpi - /// </summary> - /// <param name="someNumber">int with e.g. a width like 16 for 16x16 images</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>int with scaled number</returns> - public static int ScaleWithCurrentDpi(int someNumber, Func<float, float> scaleModifier = null) - { - return ScaleWithDpi(someNumber, Dpi, scaleModifier); - } - /// <summary> /// Scale the supplied NativeSize to the current dpi /// </summary> @@ -177,282 +107,6 @@ namespace GreenshotPlugin.Core return ScaleWithDpi(size, Dpi, scaleModifier); } - /// <summary> - /// Scale the supplied NativeSizeFloat to the current dpi - /// </summary> - /// <param name="size">NativeSizeFloat to scale</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>NativeSizeFloat scaled</returns> - public static SizeF ScaleWithCurrentDpi(SizeF size, Func<float, float> scaleModifier = null) - { - return ScaleWithDpi(size, Dpi, scaleModifier); - } - - /// <summary> - /// Scale the supplied NativePoint to the current dpi - /// </summary> - /// <param name="point">NativePoint to scale</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>NativePoint scaled</returns> - public static Point ScaleWithCurrentDpi(Point point, Func<float, float> scaleModifier = null) - { - return ScaleWithDpi(point, Dpi, scaleModifier); - } - - /// <summary> - /// Scale the supplied PointF to the current dpi - /// </summary> - /// <param name="point">PointF to scale</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>PointF scaled</returns> - public static PointF ScaleWithCurrentDpi(PointF point, Func<float, float> scaleModifier = null) - { - return ScaleWithDpi(point, Dpi, scaleModifier); - } - - /// <summary> - /// Calculate a DPI unscale factor - /// </summary> - /// <param name="dpi">uint</param> - /// <returns>float</returns> - public static float DpiUnscaleFactor(uint dpi) - { - return (float)DefaultScreenDpi / dpi; - } - - /// <summary> - /// Unscale the supplied number according to the supplied dpi - /// </summary> - /// <param name="someNumber">double with e.g. the scaled width</param> - /// <param name="dpi">current dpi, normal is 96.</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>double with the unscaled number</returns> - public static float UnscaleWithDpi(float someNumber, uint dpi, Func<float, float> scaleModifier = null) - { - var dpiUnscaleFactor = DpiUnscaleFactor(dpi); - if (scaleModifier != null) - { - dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor); - } - return dpiUnscaleFactor * someNumber; - } - - /// <summary> - /// Unscale the supplied number according to the supplied dpi - /// </summary> - /// <param name="number">int with a scaled width</param> - /// <param name="dpi">current dpi, normal is 96.</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>Unscaled width</returns> - public static int UnscaleWithDpi(int number, uint dpi, Func<float, float> scaleModifier = null) - { - var dpiUnscaleFactor = DpiUnscaleFactor(dpi); - if (scaleModifier != null) - { - dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor); - } - return (int)(dpiUnscaleFactor * number); - } - - /// <summary> - /// Unscale the supplied NativeSize according to the supplied dpi - /// </summary> - /// <param name="size">NativeSize to unscale</param> - /// <param name="dpi">current dpi, normal is 96.</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>Size unscaled</returns> - public static Size UnscaleWithDpi(Size size, uint dpi, Func<float, float> scaleModifier = null) - { - var dpiUnscaleFactor = DpiUnscaleFactor(dpi); - if (scaleModifier != null) - { - dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor); - } - return new Size((int)(dpiUnscaleFactor * size.Width), (int)(dpiUnscaleFactor * size.Height)); - } - - /// <summary> - /// Unscale the supplied Point according to the supplied dpi - /// </summary> - /// <param name="size">Point to unscale</param> - /// <param name="dpi">current dpi, normal is 96.</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>Point unscaled</returns> - public static Point UnscaleWithDpi(Point point, uint dpi, Func<float, float> scaleModifier = null) - { - var dpiUnscaleFactor = DpiUnscaleFactor(dpi); - if (scaleModifier != null) - { - dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor); - } - return new Point((int)(dpiUnscaleFactor * point.X), (int)(dpiUnscaleFactor * point.Y)); - } - - /// <summary> - /// unscale the supplied NativeSizeFloat according to the supplied dpi - /// </summary> - /// <param name="size">NativeSizeFloat to resize</param> - /// <param name="dpi">current dpi, normal is 96.</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>SizeF unscaled</returns> - public static SizeF UnscaleWithDpi(SizeF size, uint dpi, Func<float, float> scaleModifier = null) - { - float dpiUnscaleFactor = DpiUnscaleFactor(dpi); - if (scaleModifier != null) - { - dpiUnscaleFactor = scaleModifier(dpiUnscaleFactor); - } - return new SizeF(dpiUnscaleFactor * size.Width, dpiUnscaleFactor * size.Height); - } - - /// <summary> - /// Unscale the supplied number to the current dpi - /// </summary> - /// <param name="someNumber">double with e.g. a width like 16 for 16x16 images</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>double with unscaled number</returns> - public static float UnscaleWithCurrentDpi(float someNumber, Func<float, float> scaleModifier = null) - { - return UnscaleWithDpi(someNumber, Dpi, scaleModifier); - } - - /// <summary> - /// Unscale the supplied number to the current dpi - /// </summary> - /// <param name="someNumber">int with e.g. a width like 16 for 16x16 images</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>int with unscaled number</returns> - public static int UnscaleWithCurrentDpi(int someNumber, Func<float, float> scaleModifier = null) - { - return UnscaleWithDpi(someNumber, Dpi, scaleModifier); - } - - /// <summary> - /// Unscale the supplied NativeSize to the current dpi - /// </summary> - /// <param name="size">Size to unscale</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>Size unscaled</returns> - public static Size UnscaleWithCurrentDpi(Size size, Func<float, float> scaleModifier = null) - { - return UnscaleWithDpi(size, Dpi, scaleModifier); - } - - /// <summary> - /// Unscale the supplied NativeSizeFloat to the current dpi - /// </summary> - /// <param name="size">NativeSizeFloat to unscale</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>NativeSizeFloat unscaled</returns> - public static SizeF UnscaleWithCurrentDpi(SizeF size, Func<float, float> scaleModifier = null) - { - return UnscaleWithDpi(size, Dpi, scaleModifier); - } - - /// <summary> - /// Unscale the supplied NativePoint to the current dpi - /// </summary> - /// <param name="point">NativePoint to unscale</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>NativePoint unscaled</returns> - public static Point UnscaleWithCurrentDpi(Point point, Func<float, float> scaleModifier = null) - { - return UnscaleWithDpi(point, Dpi, scaleModifier); - } - - /// <summary> - /// Unscale the supplied NativePointFloat to the current dpi - /// </summary> - /// <param name="point">NativePointFloat to unscale</param> - /// <param name="scaleModifier">A function which can modify the scale factor</param> - /// <returns>NativePointFloat unscaled</returns> - public static PointF UnscaleWithCurrentDpi(PointF point, Func<float, float> scaleModifier = null) - { - return ScaleWithDpi(point, Dpi, scaleModifier); - } - - /// <summary> - /// public wrapper for EnableNonClientDpiScaling, this also checks if the function is available. - /// </summary> - /// <param name="hWnd">IntPtr</param> - /// <returns>true if it worked</returns> - public static bool TryEnableNonClientDpiScaling(IntPtr hWnd) - { - // EnableNonClientDpiScaling is only available on Windows 10 and later - if (!WindowsVersion.IsWindows10OrLater) - { - return false; - } - - var result = EnableNonClientDpiScaling(hWnd); - if (result.Succeeded()) - { - return true; - } - - var error = Win32.GetLastErrorCode(); - if (Log.IsDebugEnabled) - { - Log.DebugFormat("Error enabling non client dpi scaling : {0}", Win32.GetMessage(error)); - } - - return false; - } - - /// <summary> - /// Make the current process DPI Aware, this should be done via the manifest but sometimes this is not possible. - /// </summary> - /// <returns>bool true if it was possible to change the DPI awareness</returns> - public static bool EnableDpiAware() - { - // We can only test this for Windows 8.1 or later - if (!WindowsVersion.IsWindows81OrLater) - { - Log.Debug("An application can only be DPI aware starting with Window 8.1 and later."); - return false; - } - - if (WindowsVersion.IsWindows10BuildOrLater(15063)) - { - if (IsValidDpiAwarenessContext(DpiAwarenessContext.PerMonitorAwareV2)) - { - SetProcessDpiAwarenessContext(DpiAwarenessContext.PerMonitorAwareV2); - } - else - { - SetProcessDpiAwarenessContext(DpiAwarenessContext.PerMonitorAwareV2); - } - - return true; - } - return SetProcessDpiAwareness(DpiAwareness.PerMonitorAware).Succeeded(); - } - - /// <summary> - /// Check if the process is DPI Aware, an DpiHandler doesn't make sense if not. - /// </summary> - public static bool IsDpiAware - { - get - { - // We can only test this for Windows 8.1 or later - if (!WindowsVersion.IsWindows81OrLater) - { - Log.Debug("An application can only be DPI aware starting with Window 8.1 and later."); - return false; - } - - using var process = Process.GetCurrentProcess(); - GetProcessDpiAwareness(process.Handle, out var dpiAwareness); - if (Log.IsDebugEnabled) - { - Log.DebugFormat("Process {0} has a Dpi awareness {1}", process.ProcessName, dpiAwareness); - } - - return dpiAwareness != DpiAwareness.Unaware && dpiAwareness != DpiAwareness.Invalid; - } - } - /// <summary> /// Return the DPI for the screen which the location is located on /// </summary> @@ -510,40 +164,6 @@ namespace GreenshotPlugin.Core return (uint)GDI32.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX); } - /// <summary> - /// See details <a hef="https://msdn.microsoft.com/en-us/library/windows/desktop/dn302113(v=vs.85).aspx">GetProcessDpiAwareness function</a> - /// Retrieves the dots per inch (dpi) awareness of the specified process. - /// </summary> - /// <param name="processHandle">IntPtr with handle of the process that is being queried. If this parameter is NULL, the current process is queried.</param> - /// <param name="value">out DpiAwareness - The DPI awareness of the specified process. Possible values are from the PROCESS_DPI_AWARENESS enumeration.</param> - /// <returns>HResult</returns> - [DllImport("shcore")] - private static extern HResult GetProcessDpiAwareness(IntPtr processHandle, out DpiAwareness value); - - /// <summary> - /// Sets the current process to a specified dots per inch (dpi) awareness level. The DPI awareness levels are from the PROCESS_DPI_AWARENESS enumeration. - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn302122(v=vs.85).aspx">SetProcessDpiAwareness function</a> - /// </summary> - /// <param name="dpiAwareness">DpiAwareness</param> - /// <returns>HResult</returns> - [DllImport("shcore")] - private static extern HResult SetProcessDpiAwareness(DpiAwareness dpiAwareness); - - /// <summary> - /// It is recommended that you set the process-default DPI awareness via application manifest. See Setting the default DPI awareness for a process for more information. Setting the process-default DPI awareness via API call can lead to unexpected application behavior. - /// - /// Sets the current process to a specified dots per inch (dpi) awareness context. The DPI awareness contexts are from the DPI_AWARENESS_CONTEXT value. - /// Remarks: - /// This API is a more advanced version of the previously existing SetProcessDpiAwareness API, allowing for the process default to be set to the finer-grained DPI_AWARENESS_CONTEXT values. Most importantly, this allows you to programmatically set Per Monitor v2 as the process default value, which is not possible with the previous API. - /// - /// This method sets the default DPI_AWARENESS_CONTEXT for all threads within an application. Individual threads can have their DPI awareness changed from the default with the SetThreadDpiAwarenessContext method. - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt807676(v=vs.85).aspx">SetProcessDpiAwarenessContext function</a> - /// </summary> - /// <param name="dpiAwarenessContext">DpiAwarenessContext</param> - /// <returns>bool</returns> - [DllImport("User32.dll", SetLastError = true)] - private static extern bool SetProcessDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext); - /// <summary> /// See more at <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748624(v=vs.85).aspx">GetDpiForWindow function</a> /// Returns the dots per inch (dpi) value for the associated window. @@ -566,14 +186,6 @@ namespace GreenshotPlugin.Core [DllImport("shcore.dll", SetLastError = true)] private static extern HResult GetDpiForMonitor(IntPtr hMonitor, MonitorDpiType dpiType, out uint dpiX, out uint dpiY); - /// <summary> - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748621(v=vs.85).aspx">EnableNonClientDpiScaling function</a> - /// </summary> - /// <param name="hWnd">IntPtr</param> - /// <returns>bool</returns> - [DllImport("User32.dll", SetLastError = true)] - private static extern HResult EnableNonClientDpiScaling(IntPtr hWnd); - /// <summary> /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748623(v=vs.85).aspx">GetDpiForSystem function</a> /// Returns the system DPI. @@ -581,151 +193,5 @@ namespace GreenshotPlugin.Core /// <returns>uint with the system DPI</returns> [DllImport("User32.dll")] private static extern uint GetDpiForSystem(); - - /// <summary> - /// Converts a point in a window from logical coordinates into physical coordinates, regardless of the dots per inch (dpi) awareness of the caller. For more information about DPI awareness levels, see PROCESS_DPI_AWARENESS. - /// See more at <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn384110(v=vs.85).aspx">LogicalToPhysicalPointForPerMonitorDPI function</a> - /// </summary> - /// <param name="hWnd">IntPtr A handle to the window whose transform is used for the conversion.</param> - /// <param name="point">A pointer to a POINT structure that specifies the logical coordinates to be converted. The new physical coordinates are copied into this structure if the function succeeds.</param> - /// <returns>bool</returns> - [DllImport("User32.dll")] - private static extern bool LogicalToPhysicalPointForPerMonitorDPI(IntPtr hWnd, ref POINT point); - - /// <summary> - /// Converts a point in a window from logical coordinates into physical coordinates, regardless of the dots per inch (dpi) awareness of the caller. For more information about DPI awareness levels, see PROCESS_DPI_AWARENESS. - /// See more at <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn384112(v=vs.85).aspx">PhysicalToLogicalPointForPerMonitorDPI function</a> - /// </summary> - /// <param name="hWnd">IntPtr A handle to the window whose transform is used for the conversion.</param> - /// <param name="point">NativePoint A pointer to a POINT structure that specifies the physical/screen coordinates to be converted. The new logical coordinates are copied into this structure if the function succeeds.</param> - /// <returns>bool</returns> - [DllImport("User32.dll")] - private static extern bool PhysicalToLogicalPointForPerMonitorDPI(IntPtr hWnd, ref POINT point); - - /// <summary> - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947(v=vs.85).aspx">SystemParametersInfo function</a> - /// Retrieves the value of one of the system-wide parameters, taking into account the provided DPI value. - /// </summary> - /// <param name="uiAction"> - /// SystemParametersInfoActions The system-wide parameter to be retrieved. - /// This function is only intended for use with SPI_GETICONTITLELOGFONT, SPI_GETICONMETRICS, or SPI_GETNONCLIENTMETRICS. See SystemParametersInfo for more information on these values. - /// </param> - /// <param name="uiParam"> - /// A parameter whose usage and format depends on the system parameter being queried or set. For more - /// information about system-wide parameters, see the uiAction parameter. If not otherwise indicated, you must specify - /// zero for this parameter. - /// </param> - /// <param name="pvParam">IntPtr</param> - /// <param name="fWinIni">SystemParametersInfoBehaviors</param> - /// <param name="dpi">uint with dpi value</param> - /// <returns>bool</returns> - [DllImport("User32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool SystemParametersInfoForDpi(SystemParametersInfoActions uiAction, uint uiParam, IntPtr pvParam, SystemParametersInfoBehaviors fWinIni, uint dpi); - - /// <summary> - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt748626(v=vs.85).aspx">GetThreadDpiAwarenessContext function</a> - /// Gets the DPI_AWARENESS_CONTEXT for the current thread. - /// - /// This method will return the latest DPI_AWARENESS_CONTEXT sent to SetThreadDpiAwarenessContext. If SetThreadDpiAwarenessContext was never called for this thread, then the return value will equal the default DPI_AWARENESS_CONTEXT for the process. - /// </summary> - /// <returns>DpiAwarenessContext</returns> - [DllImport("User32.dll")] - private static extern DpiAwarenessContext GetThreadDpiAwarenessContext(); - - /// <summary> - /// Set the DPI awareness for the current thread to the provided value. - /// </summary> - /// <param name="dpiAwarenessContext">DpiAwarenessContext the new value for the current thread</param> - /// <returns>DpiAwarenessContext previous value</returns> - [DllImport("User32.dll")] - private static extern DpiAwarenessContext SetThreadDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext); - - /// <summary> - /// Retrieves the DpiAwareness value from a DpiAwarenessContext. - /// </summary> - /// <param name="dpiAwarenessContext">DpiAwarenessContext</param> - /// <returns>DpiAwareness</returns> - [DllImport("User32.dll")] - private static extern DpiAwareness GetAwarenessFromDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext); - - /// <summary> - /// Retrieves the DPI from a given DPI_AWARENESS_CONTEXT handle. This enables you to determine the DPI of a thread without needed to examine a window created within that thread. - /// </summary> - /// <param name="dpiAwarenessContext">DpiAwarenessContext</param> - /// <returns>uint with dpi value</returns> - [DllImport("User32.dll")] - private static extern uint GetDpiFromDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext); - - /// <summary> - /// Determines if a specified DPI_AWARENESS_CONTEXT is valid and supported by the current system. - /// </summary> - /// <param name="dpiAwarenessContext">DpiAwarenessContext The context that you want to determine if it is supported.</param> - /// <returns>bool true if supported otherwise false</returns> - [DllImport("User32.dll")] - private static extern bool IsValidDpiAwarenessContext(DpiAwarenessContext dpiAwarenessContext); - - /// <summary> - /// Returns the DPI_HOSTING_BEHAVIOR of the specified window. - /// - /// This API allows you to examine the hosting behavior of a window after it has been created. A window's hosting behavior is the hosting behavior of the thread in which the window was created, as set by a call to SetThreadDpiHostingBehavior. This is a permanent value and cannot be changed after the window is created, even if the thread's hosting behavior is changed. - /// </summary> - /// <returns>DpiHostingBehavior</returns> - [DllImport("User32.dll")] - private static extern DpiHostingBehavior GetWindowDpiHostingBehavior(); - - /// <summary> - /// See more at <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt845775.aspx">SetThreadDpiHostingBehavior function</a> - /// Sets the thread's DPI_HOSTING_BEHAVIOR. This behavior allows windows created in the thread to host child windows with a different DPI_AWARENESS_CONTEXT. - /// - /// DPI_HOSTING_BEHAVIOR enables a mixed content hosting behavior, which allows parent windows created in the thread to host child windows with a different DPI_AWARENESS_CONTEXT value. This property only effects new windows created within this thread while the mixed hosting behavior is active. A parent window with this hosting behavior is able to host child windows with different DPI_AWARENESS_CONTEXT values, regardless of whether the child windows have mixed hosting behavior enabled. - /// - /// This hosting behavior does not allow for windows with per-monitor DPI_AWARENESS_CONTEXT values to be hosted until windows with DPI_AWARENESS_CONTEXT values of system or unaware. - /// - /// To avoid unexpected outcomes, a thread's DPI_HOSTING_BEHAVIOR should be changed to support mixed hosting behaviors only when creating a new window which needs to support those behaviors. Once that window is created, the hosting behavior should be switched back to its default value. - /// - /// This API is used to change the thread's DPI_HOSTING_BEHAVIOR from its default value. This is only necessary if your app needs to host child windows from plugins and third-party components that do not support per-monitor-aware context. This is most likely to occur if you are updating complex applications to support per-monitor DPI_AWARENESS_CONTEXT behaviors. - /// - /// Enabling mixed hosting behavior will not automatically adjust the thread's DPI_AWARENESS_CONTEXT to be compatible with legacy content. The thread's awareness context must still be manually changed before new windows are created to host such content. - /// </summary> - /// <param name="dpiHostingBehavior">DpiHostingBehavior</param> - /// <returns>previous DpiHostingBehavior</returns> - [DllImport("User32.dll")] - private static extern DpiHostingBehavior SetThreadDpiHostingBehavior(DpiHostingBehavior dpiHostingBehavior); - - /// <summary> - ///Retrieves the DPI_HOSTING_BEHAVIOR from the current thread. - /// </summary> - /// <returns>DpiHostingBehavior</returns> - [DllImport("User32.dll")] - private static extern DpiHostingBehavior GetThreadDpiHostingBehavior(); - - /// <summary> - /// Overrides the default per-monitor DPI scaling behavior of a child window in a dialog. - /// This function returns TRUE if the operation was successful, and FALSE otherwise. To get extended error information, call GetLastError. - /// - /// Possible errors are ERROR_INVALID_HANDLE if passed an invalid HWND, and ERROR_ACCESS_DENIED if the windows belongs to another process. - /// - /// The behaviors are specified as values from the DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS enum. This function follows the typical two-parameter approach to setting flags, where a mask specifies the subset of the flags to be changed. - /// - /// It is valid to set these behaviors on any window. It does not matter if the window is currently a child of a dialog at the point in time that SetDialogControlDpiChangeBehavior is called. The behaviors are retained and will take effect only when the window is an immediate child of a dialog that has per-monitor DPI scaling enabled. - /// - /// This API influences individual controls within dialogs. The dialog-wide per-monitor DPI scaling behavior is controlled by SetDialogDpiChangeBehavior. - /// </summary> - /// <param name="hWnd">IntPtr A handle for the window whose behavior will be modified.</param> - /// <param name="mask">DialogScalingBehaviors A mask specifying the subset of flags to be changed.</param> - /// <param name="values">DialogScalingBehaviors The desired value to be set for the specified subset of flags.</param> - /// <returns>bool</returns> - [DllImport("User32.dll")] - private static extern bool SetDialogControlDpiChangeBehavior(IntPtr hWnd, DialogScalingBehaviors mask, DialogScalingBehaviors values); - - /// <summary> - /// Retrieves and per-monitor DPI scaling behavior overrides of a child window in a dialog. - /// The flags set on the given window. If passed an invalid handle, this function will return zero, and set its last error to ERROR_INVALID_HANDLE. - /// </summary> - /// <param name="hWnd">IntPtr A handle for the window whose behavior will be modified.</param> - /// <returns>DialogScalingBehaviors</returns> - [DllImport("User32.dll")] - private static extern DialogScalingBehaviors GetDialogControlDpiChangeBehavior(IntPtr hWnd); } } diff --git a/GreenshotPlugin/Core/EnumExtensions.cs b/GreenshotPlugin/Core/EnumExtensions.cs deleted file mode 100644 index 1bda1071f..000000000 --- a/GreenshotPlugin/Core/EnumExtensions.cs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -using System; -namespace GreenshotPlugin.Core { - public static class EnumerationExtensions { - public static bool Has<T>(this Enum type, T value) { - Type underlyingType = Enum.GetUnderlyingType(value.GetType()); - try { - if (underlyingType == typeof(int)) { - return (((int)(object)type & (int)(object)value) == (int)(object)value); - } else if (underlyingType == typeof(uint)) { - return (((uint)(object)type & (uint)(object)value) == (uint)(object)value); - } - } - catch - { - // ignored - } - return false; - } - - public static bool Is<T>(this Enum type, T value) { - Type underlyingType = Enum.GetUnderlyingType(value.GetType()); - try - { - if (underlyingType == typeof(int)) { - return (int)(object)type == (int)(object)value; - } - if (underlyingType == typeof(uint)) { - return (uint)(object)type == (uint)(object)value; - } - } - catch - { - // ignored - } - return false; - } - - /// <summary> - /// Add a flag to an enum - /// </summary> - /// <param name="type"></param> - /// <param name="value"></param> - /// <returns></returns> - public static T Add<T>(this Enum type, T value) { - Type underlyingType = Enum.GetUnderlyingType(value.GetType()); - try - { - if (underlyingType == typeof(int)) { - return (T)(object)(((int)(object)type | (int)(object)value)); - } - if (underlyingType == typeof(uint)) { - return (T)(object)(((uint)(object)type | (uint)(object)value)); - } - } catch(Exception ex) { - throw new ArgumentException($"Could not append value '{value}' to enumerated type '{typeof(T).Name}'.", ex); - } - throw new ArgumentException($"Could not append value '{value}' to enumerated type '{typeof(T).Name}'."); - } - - /// <summary> - /// Remove a flag from an enum type - /// </summary> - /// <param name="type"></param> - /// <param name="value"></param> - /// <returns></returns> - public static T Remove<T>(this Enum type, T value) { - Type underlyingType = Enum.GetUnderlyingType(value.GetType()); - try - { - if (underlyingType == typeof(int)) { - return (T)(object)(((int)(object)type & ~(int)(object)value)); - } - if (underlyingType == typeof(uint)) { - return (T)(object)(((uint)(object)type & ~(uint)(object)value)); - } - } catch(Exception ex) { - throw new ArgumentException($"Could not remove value '{value}' from enumerated type '{typeof(T).Name}'.", ex); - } - throw new ArgumentException($"Could not remove value '{value}' from enumerated type '{typeof(T).Name}'."); - } - } -} diff --git a/GreenshotPlugin/Core/Enums/DialogDpiChangeBehaviors.cs b/GreenshotPlugin/Core/Enums/DialogDpiChangeBehaviors.cs deleted file mode 100644 index fa5b61635..000000000 --- a/GreenshotPlugin/Core/Enums/DialogDpiChangeBehaviors.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Dapplo and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; - -namespace GreenshotPlugin.Core.Enums -{ - /// <summary> - /// In Per Monitor v2 contexts, dialogs will automatically respond to DPI changes by resizing themselves and re-computing the positions of their child windows (here referred to as re-layouting). This enum works in conjunction with SetDialogDpiChangeBehavior in order to override the default DPI scaling behavior for dialogs. - /// This does not affect DPI scaling behavior for the child windows of dialogs(beyond re-layouting), which is controlled by DIALOG_CONTROL_DPI_CHANGE_BEHAVIORS. - /// </summary> - [Flags] - public enum DialogDpiChangeBehaviors - { - /// <summary> - /// The default behavior of the dialog manager. In response to a DPI change, the dialog manager will re-layout each control, update the font on each control, resize the dialog, and update the dialog's own font. - /// </summary> - Default = 0, - - /// <summary> - /// Prevents the dialog manager from responding to WM_GETDPISCALEDSIZE and WM_DPICHANGED, disabling all default DPI scaling behavior. - /// </summary> - DisableAll = 1, - - /// <summary> - /// Prevents the dialog manager from resizing the dialog in response to a DPI change. - /// </summary> - DisableResize = 2, - - /// <summary> - /// Prevents the dialog manager from re-layouting all of the dialogue's immediate children HWNDs in response to a DPI change. - /// </summary> - DisableControlRelayout = 3 - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/Enums/DialogScalingBehaviors.cs b/GreenshotPlugin/Core/Enums/DialogScalingBehaviors.cs deleted file mode 100644 index 4de8e4c35..000000000 --- a/GreenshotPlugin/Core/Enums/DialogScalingBehaviors.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Dapplo and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; - -namespace GreenshotPlugin.Core.Enums -{ - /// <summary> - /// Describes per-monitor DPI scaling behavior overrides for child windows within dialogs. The values in this enumeration are bitfields and can be combined. - /// - /// This enum is used with SetDialogControlDpiChangeBehavior in order to override the default per-monitor DPI scaling behavior for a child window within a dialog. - /// - /// These settings only apply to individual controls within dialogs. The dialog-wide per-monitor DPI scaling behavior of a dialog is controlled by DIALOG_DPI_CHANGE_BEHAVIORS. - /// </summary> - [Flags] - public enum DialogScalingBehaviors - { - /// <summary> - /// The default behavior of the dialog manager. The dialog managed will update the font, size, and position of the child window on DPI changes. - /// </summary> - Default = 0, - - /// <summary> - /// Prevents the dialog manager from sending an updated font to the child window via WM_SETFONT in response to a DPI change. - /// </summary> - DisableFontUpdate = 1, - - /// <summary> - /// Prevents the dialog manager from resizing and repositioning the child window in response to a DPI change. - /// </summary> - DisableRelayout = 2 - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/Enums/DpiAwareness.cs b/GreenshotPlugin/Core/Enums/DpiAwareness.cs deleted file mode 100644 index 7dd22431e..000000000 --- a/GreenshotPlugin/Core/Enums/DpiAwareness.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Dapplo and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace GreenshotPlugin.Core.Enums -{ - /// <summary> - /// Identifies the dots per inch (dpi) setting for a thread, process, or window. - /// Can be used everywhere ProcessDpiAwareness is passed. - /// </summary> - public enum DpiAwareness - { - /// <summary> - /// Invalid DPI awareness. This is an invalid DPI awareness value. - /// </summary> - Invalid = -1, - - /// <summary> - /// DPI unaware. - /// This process does not scale for DPI changes and is always assumed to have a scale factor of 100% (96 DPI). - /// It will be automatically scaled by the system on any other DPI setting. - /// </summary> - Unaware = 0, - - /// <summary> - /// System DPI aware. - /// This process does not scale for DPI changes. - /// It will query for the DPI once and use that value for the lifetime of the process. - /// If the DPI changes, the process will not adjust to the new DPI value. - /// It will be automatically scaled up or down by the system when the DPI changes from the system value. - /// </summary> - SystemAware = 1, - - /// <summary> - /// Per monitor DPI aware. - /// This process checks for the DPI when it is created and adjusts the scale factor whenever the DPI changes. - /// These processes are not automatically scaled by the system. - /// </summary> - PerMonitorAware = 2 - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/Enums/DpiAwarenessContext.cs b/GreenshotPlugin/Core/Enums/DpiAwarenessContext.cs deleted file mode 100644 index 276d73550..000000000 --- a/GreenshotPlugin/Core/Enums/DpiAwarenessContext.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Dapplo and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace GreenshotPlugin.Core.Enums -{ - /// <summary> - /// </summary> - public enum DpiAwarenessContext - { - /// <summary> - /// DPI unaware. - /// This window does not scale for DPI changes and is always assumed to have a scale factor of 100% (96 DPI). - /// It will be automatically scaled by the system on any other DPI setting. - /// </summary> - Unaware = -1, - - /// <summary> - /// System DPI aware. - /// This window does not scale for DPI changes. - /// It will query for the DPI once and use that value for the lifetime of the process. - /// If the DPI changes, the process will not adjust to the new DPI value. - /// It will be automatically scaled up or down by the system when the DPI changes from the system value. - /// </summary> - SystemAware = -2, - - /// <summary> - /// Per monitor DPI aware. - /// This window checks for the DPI when it is created and adjusts the scale factor whenever the DPI changes. - /// These processes are not automatically scaled by the system. - /// </summary> - PerMonitorAware = -3, - - /// <summary> - /// Also known as Per Monitor v2. An advancement over the original per-monitor DPI awareness mode, which enables applications to access new DPI-related scaling behaviors on a per top-level window basis. - /// Per Monitor v2 was made available in the Creators Update of Windows 10, and is not available on earlier versions of the operating system. - /// The additional behaviors introduced are as follows: - /// * Child window DPI change notifications - In Per Monitor v2 contexts, the entire window tree is notified of any DPI changes that occur. - /// * Scaling of non-client area - All windows will automatically have their non-client area drawn in a DPI sensitive fashion. Calls to EnableNonClientDpiScaling are unnecessary. - /// * Scaling of Win32 menus - All NTUSER menus created in Per Monitor v2 contexts will be scaling in a per-monitor fashion. - /// * Dialog Scaling - Win32 dialogs created in Per Monitor v2 contexts will automatically respond to DPI changes. - /// * Improved scaling of comctl32 controls - Various comctl32 controls have improved DPI scaling behavior in Per Monitor v2 contexts. - /// * Improved theming behavior - UxTheme handles opened in the context of a Per Monitor v2 window will operate in terms of the DPI associated with that window. - /// </summary> - PerMonitorAwareV2 = -4 - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/Enums/DpiHostingBehavior.cs b/GreenshotPlugin/Core/Enums/DpiHostingBehavior.cs deleted file mode 100644 index 0b0abf686..000000000 --- a/GreenshotPlugin/Core/Enums/DpiHostingBehavior.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dapplo and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace GreenshotPlugin.Core.Enums -{ - /// <summary> - /// Identifies the DPI hosting behavior for a window. - /// This behavior allows windows created in the thread to host child windows with a different DPI_AWARENESS_CONTEXT - /// </summary> - public enum DpiHostingBehavior - { - /// <summary> - /// Invalid DPI hosting behavior. This usually occurs if the previous SetThreadDpiHostingBehavior call used an invalid parameter. - /// </summary> - Invalid = -1, - - /// <summary> - /// Default DPI hosting behavior. The associated window behaves as normal, and cannot create or re-parent child windows with a different DPI_AWARENESS_CONTEXT. - /// </summary> - Default = 0, - - /// <summary> - /// Mixed DPI hosting behavior. This enables the creation and re-parenting of child windows with different DPI_AWARENESS_CONTEXT. These child windows will be independently scaled by the OS. - /// </summary> - Mixed = 1 - - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/Enums/SystemParametersInfoActions.cs b/GreenshotPlugin/Core/Enums/SystemParametersInfoActions.cs deleted file mode 100644 index 62a4eb5f4..000000000 --- a/GreenshotPlugin/Core/Enums/SystemParametersInfoActions.cs +++ /dev/null @@ -1,1390 +0,0 @@ -// Copyright (c) Dapplo and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.Core.Enums -{ - /// <summary> - /// SPI_ System-wide parameter - Used in SystemParametersInfo function - /// </summary> - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SystemParametersInfoActions : uint - { - /// <summary> - /// No value - /// </summary> - SPI_NONE = 0, - - /// <summary> - /// Determines whether the warning beeper is on. - /// The pvParam parameter must point to a BOOL variable that receives TRUE if the beeper is on, or FALSE if it is off. - /// </summary> - SPI_GETBEEP = 0x0001, - - /// <summary> - /// Turns the warning beeper on or off. The uiParam parameter specifies TRUE for on, or FALSE for off. - /// </summary> - SPI_SETBEEP = 0x0002, - - /// <summary> - /// Retrieves the two mouse threshold values and the mouse speed. - /// </summary> - SPI_GETMOUSE = 0x0003, - - /// <summary> - /// Sets the two mouse threshold values and the mouse speed. - /// </summary> - SPI_SETMOUSE = 0x0004, - - /// <summary> - /// Retrieves the border multiplier factor that determines the width of a window's sizing border. - /// The pvParam parameter must point to an integer variable that receives this value. - /// </summary> - SPI_GETBORDER = 0x0005, - - /// <summary> - /// Sets the border multiplier factor that determines the width of a window's sizing border. - /// The uiParam parameter specifies the new value. - /// </summary> - SPI_SETBORDER = 0x0006, - - /// <summary> - /// Retrieves the keyboard repeat-speed setting, which is a value in the range from 0 (approximately 2.5 repetitions - /// per second) - /// through 31 (approximately 30 repetitions per second). The actual repeat rates are hardware-dependent and may vary - /// from - /// a linear scale by as much as 20%. The pvParam parameter must point to a DWORD variable that receives the setting - /// </summary> - SPI_GETKEYBOARDSPEED = 0x000A, - - /// <summary> - /// Sets the keyboard repeat-speed setting. The uiParam parameter must specify a value in the range from 0 - /// (approximately 2.5 repetitions per second) through 31 (approximately 30 repetitions per second). - /// The actual repeat rates are hardware-dependent and may vary from a linear scale by as much as 20%. - /// If uiParam is greater than 31, the parameter is set to 31. - /// </summary> - SPI_SETKEYBOARDSPEED = 0x000B, - - /// <summary> - /// Not implemented. - /// </summary> - SPI_LANGDRIVER = 0x000C, - - /// <summary> - /// Sets or retrieves the width, in pixels, of an icon cell. The system uses this rectangle to arrange icons in large - /// icon view. - /// To set this value, set uiParam to the new value and set pvParam to null. You cannot set this value to less than - /// SM_CXICON. - /// To retrieve this value, pvParam must point to an integer that receives the current value. - /// </summary> - SPI_ICONHORIZONTALSPACING = 0x000D, - - /// <summary> - /// Retrieves the screen saver time-out value, in seconds. The pvParam parameter must point to an integer variable that - /// receives the value. - /// </summary> - SPI_GETSCREENSAVETIMEOUT = 0x000E, - - /// <summary> - /// Sets the screen saver time-out value to the value of the uiParam parameter. This value is the amount of time, in - /// seconds, - /// that the system must be idle before the screen saver activates. - /// </summary> - SPI_SETSCREENSAVETIMEOUT = 0x000F, - - /// <summary> - /// Determines whether screen saving is enabled. The pvParam parameter must point to a bool variable that receives TRUE - /// if screen saving is enabled, or FALSE otherwise. - /// Does not work for Windows 7: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724947(v=vs.85).aspx - /// </summary> - SPI_GETSCREENSAVEACTIVE = 0x0010, - - /// <summary> - /// Sets the state of the screen saver. The uiParam parameter specifies TRUE to activate screen saving, or FALSE to - /// deactivate it. - /// </summary> - SPI_SETSCREENSAVEACTIVE = 0x0011, - - /// <summary> - /// Retrieves the current granularity value of the desktop sizing grid. The pvParam parameter must point to an integer - /// variable - /// that receives the granularity. - /// </summary> - SPI_GETGRIDGRANULARITY = 0x0012, - - /// <summary> - /// Sets the granularity of the desktop sizing grid to the value of the uiParam parameter. - /// </summary> - SPI_SETGRIDGRANULARITY = 0x0013, - - /// <summary> - /// Sets the desktop wallpaper. The value of the pvParam parameter determines the new wallpaper. To specify a wallpaper - /// bitmap, - /// set pvParam to point to a null-terminated string containing the name of a bitmap file. Setting pvParam to "" - /// removes the wallpaper. - /// Setting pvParam to SETWALLPAPER_DEFAULT or null reverts to the default wallpaper. - /// </summary> - SPI_SETDESKWALLPAPER = 0x0014, - - /// <summary> - /// Sets the current desktop pattern by causing Windows to read the Pattern= setting from the WIN.INI file. - /// </summary> - SPI_SETDESKPATTERN = 0x0015, - - /// <summary> - /// Retrieves the keyboard repeat-delay setting, which is a value in the range from 0 (approximately 250 ms delay) - /// through 3 - /// (approximately 1 second delay). The actual delay associated with each value may vary depending on the hardware. The - /// pvParam parameter must point to an integer variable that receives the setting. - /// </summary> - SPI_GETKEYBOARDDELAY = 0x0016, - - /// <summary> - /// Sets the keyboard repeat-delay setting. The uiParam parameter must specify 0, 1, 2, or 3, where zero sets the - /// shortest delay - /// (approximately 250 ms) and 3 sets the longest delay (approximately 1 second). The actual delay associated with each - /// value may - /// vary depending on the hardware. - /// </summary> - SPI_SETKEYBOARDDELAY = 0x0017, - - /// <summary> - /// Sets or retrieves the height, in pixels, of an icon cell. - /// To set this value, set uiParam to the new value and set pvParam to null. You cannot set this value to less than - /// SM_CYICON. - /// To retrieve this value, pvParam must point to an integer that receives the current value. - /// </summary> - SPI_ICONVERTICALSPACING = 0x0018, - - /// <summary> - /// Determines whether icon-title wrapping is enabled. The pvParam parameter must point to a bool variable that - /// receives TRUE - /// if enabled, or FALSE otherwise. - /// </summary> - SPI_GETICONTITLEWRAP = 0x0019, - - /// <summary> - /// Turns icon-title wrapping on or off. The uiParam parameter specifies TRUE for on, or FALSE for off. - /// </summary> - SPI_SETICONTITLEWRAP = 0x001A, - - /// <summary> - /// Determines whether pop-up menus are left-aligned or right-aligned, relative to the corresponding menu-bar item. - /// The pvParam parameter must point to a bool variable that receives TRUE if left-aligned, or FALSE otherwise. - /// </summary> - SPI_GETMENUDROPALIGNMENT = 0x001B, - - /// <summary> - /// Sets the alignment value of pop-up menus. The uiParam parameter specifies TRUE for right alignment, or FALSE for - /// left alignment. - /// </summary> - SPI_SETMENUDROPALIGNMENT = 0x001C, - - /// <summary> - /// Sets the width of the double-click rectangle to the value of the uiParam parameter. - /// The double-click rectangle is the rectangle within which the second click of a double-click must fall for it to be - /// registered - /// as a double-click. - /// To retrieve the width of the double-click rectangle, call GetSystemMetrics with the SM_CXDOUBLECLK flag. - /// </summary> - SPI_SETDOUBLECLKWIDTH = 0x001D, - - /// <summary> - /// Sets the height of the double-click rectangle to the value of the uiParam parameter. - /// The double-click rectangle is the rectangle within which the second click of a double-click must fall for it to be - /// registered - /// as a double-click. - /// To retrieve the height of the double-click rectangle, call GetSystemMetrics with the SM_CYDOUBLECLK flag. - /// </summary> - SPI_SETDOUBLECLKHEIGHT = 0x001E, - - /// <summary> - /// Retrieves the logical font information for the current icon-title font. The uiParam parameter specifies the size of - /// a LOGFONT structure, - /// and the pvParam parameter must point to the LOGFONT structure to fill in. - /// </summary> - SPI_GETICONTITLELOGFONT = 0x001F, - - /// <summary> - /// Sets the double-click time for the mouse to the value of the uiParam parameter. The double-click time is the - /// maximum number - /// of milliseconds that can occur between the first and second clicks of a double-click. You can also call the - /// SetDoubleClickTime - /// function to set the double-click time. To get the current double-click time, call the GetDoubleClickTime function. - /// </summary> - SPI_SETDOUBLECLICKTIME = 0x0020, - - /// <summary> - /// Swaps or restores the meaning of the left and right mouse buttons. The uiParam parameter specifies TRUE to swap the - /// meanings - /// of the buttons, or FALSE to restore their original meanings. - /// </summary> - SPI_SETMOUSEBUTTONSWAP = 0x0021, - - /// <summary> - /// Sets the font that is used for icon titles. The uiParam parameter specifies the size of a LOGFONT structure, - /// and the pvParam parameter must point to a LOGFONT structure. - /// </summary> - SPI_SETICONTITLELOGFONT = 0x0022, - - /// <summary> - /// This flag is obsolete. Previous versions of the system use this flag to determine whether ALT+TAB fast task - /// switching is enabled. - /// For Windows 95, Windows 98, and Windows NT version 4.0 and later, fast task switching is always enabled. - /// </summary> - SPI_GETFASTTASKSWITCH = 0x0023, - - /// <summary> - /// This flag is obsolete. Previous versions of the system use this flag to enable or disable ALT+TAB fast task - /// switching. - /// For Windows 95, Windows 98, and Windows NT version 4.0 and later, fast task switching is always enabled. - /// </summary> - SPI_SETFASTTASKSWITCH = 0x0024, - - /// <summary> - /// Sets dragging of full windows either on or off. The uiParam parameter specifies TRUE for on, or FALSE for off. - /// Windows 95: This flag is supported only if Windows Plus! is installed. See SPI_GETWINDOWSEXTENSION. - /// </summary> - SPI_SETDRAGFULLWINDOWS = 0x0025, - - /// <summary> - /// Determines whether dragging of full windows is enabled. The pvParam parameter must point to a BOOL variable that - /// receives TRUE - /// if enabled, or FALSE otherwise. - /// Windows 95: This flag is supported only if Windows Plus! is installed. See SPI_GETWINDOWSEXTENSION. - /// </summary> - SPI_GETDRAGFULLWINDOWS = 0x0026, - - /// <summary> - /// Retrieves the metrics associated with the nonclient area of nonminimized windows. The pvParam parameter must point - /// to a NONCLIENTMETRICS structure that receives the information. Set the cbSize member of this structure and the - /// uiParam parameter - /// to sizeof(NONCLIENTMETRICS). - /// </summary> - SPI_GETNONCLIENTMETRICS = 0x0029, - - /// <summary> - /// Sets the metrics associated with the nonclient area of nonminimized windows. The pvParam parameter must point - /// to a NONCLIENTMETRICS structure that contains the new parameters. Set the cbSize member of this structure - /// and the uiParam parameter to sizeof(NONCLIENTMETRICS). Also, the lfHeight member of the LOGFONT structure must be a - /// negative value. - /// </summary> - SPI_SETNONCLIENTMETRICS = 0x002A, - - /// <summary> - /// Retrieves the metrics associated with minimized windows. The pvParam parameter must point to a MINIMIZEDMETRICS - /// structure - /// that receives the information. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(MINIMIZEDMETRICS). - /// </summary> - SPI_GETMINIMIZEDMETRICS = 0x002B, - - /// <summary> - /// Sets the metrics associated with minimized windows. The pvParam parameter must point to a MINIMIZEDMETRICS - /// structure - /// that contains the new parameters. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(MINIMIZEDMETRICS). - /// </summary> - SPI_SETMINIMIZEDMETRICS = 0x002C, - - /// <summary> - /// Retrieves the metrics associated with icons. The pvParam parameter must point to an ICONMETRICS structure that - /// receives - /// the information. Set the cbSize member of this structure and the uiParam parameter to sizeof(ICONMETRICS). - /// </summary> - SPI_GETICONMETRICS = 0x002D, - - /// <summary> - /// Sets the metrics associated with icons. The pvParam parameter must point to an ICONMETRICS structure that contains - /// the new parameters. Set the cbSize member of this structure and the uiParam parameter to sizeof(ICONMETRICS). - /// </summary> - SPI_SETICONMETRICS = 0x002E, - - /// <summary> - /// Sets the size of the work area. The work area is the portion of the screen not obscured by the system taskbar - /// or by application desktop toolbars. The pvParam parameter is a pointer to a RECT structure that specifies the new - /// work area rectangle, - /// expressed in virtual screen coordinates. In a system with multiple display monitors, the function sets the work - /// area - /// of the monitor that contains the specified rectangle. - /// </summary> - SPI_SETWORKAREA = 0x002F, - - /// <summary> - /// Retrieves the size of the work area on the primary display monitor. The work area is the portion of the screen not - /// obscured - /// by the system taskbar or by application desktop toolbars. The pvParam parameter must point to a RECT structure that - /// receives - /// the coordinates of the work area, expressed in virtual screen coordinates. - /// To get the work area of a monitor other than the primary display monitor, call the GetMonitorInfo function. - /// </summary> - SPI_GETWORKAREA = 0x0030, - - /// <summary> - /// Windows Me/98/95: Pen windows is being loaded or unloaded. The uiParam parameter is TRUE when loading and FALSE - /// when unloading pen windows. The pvParam parameter is null. - /// </summary> - SPI_SETPENWINDOWS = 0x0031, - - /// <summary> - /// Retrieves information about the HighContrast accessibility feature. The pvParam parameter must point to a - /// HIGHCONTRAST structure - /// that receives the information. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(HIGHCONTRAST). - /// For a general discussion, see remarks. - /// Windows NT: This value is not supported. - /// </summary> - /// <remarks> - /// There is a difference between the High Contrast color scheme and the High Contrast Mode. The High Contrast color - /// scheme changes - /// the system colors to colors that have obvious contrast; you switch to this color scheme by using the Display - /// Options in the control panel. - /// The High Contrast Mode, which uses SPI_GETHIGHCONTRAST and SPI_SETHIGHCONTRAST, advises applications to modify - /// their appearance - /// for visually-impaired users. It involves such things as audible warning to users and customized color scheme - /// (using the Accessibility Options in the control panel). For more information, see HIGHCONTRAST on MSDN. - /// For more information on general accessibility features, see Accessibility on MSDN. - /// </remarks> - SPI_GETHIGHCONTRAST = 0x0042, - - /// <summary> - /// Sets the parameters of the HighContrast accessibility feature. The pvParam parameter must point to a HIGHCONTRAST - /// structure - /// that contains the new parameters. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(HIGHCONTRAST). - /// Windows NT: This value is not supported. - /// </summary> - SPI_SETHIGHCONTRAST = 0x0043, - - /// <summary> - /// Determines whether the user relies on the keyboard instead of the mouse, and wants applications to display keyboard - /// interfaces - /// that would otherwise be hidden. The pvParam parameter must point to a BOOL variable that receives TRUE - /// if the user relies on the keyboard; or FALSE otherwise. - /// Windows NT: This value is not supported. - /// </summary> - SPI_GETKEYBOARDPREF = 0x0044, - - /// <summary> - /// Sets the keyboard preference. The uiParam parameter specifies TRUE if the user relies on the keyboard instead of - /// the mouse, - /// and wants applications to display keyboard interfaces that would otherwise be hidden; uiParam is FALSE otherwise. - /// Windows NT: This value is not supported. - /// </summary> - SPI_SETKEYBOARDPREF = 0x0045, - - /// <summary> - /// Determines whether a screen reviewer utility is running. A screen reviewer utility directs textual information to - /// an output device, - /// such as a speech synthesizer or Braille display. When this flag is set, an application should provide textual - /// information - /// in situations where it would otherwise present the information graphically. - /// The pvParam parameter is a pointer to a BOOL variable that receives TRUE if a screen reviewer utility is running, - /// or FALSE otherwise. - /// Windows NT: This value is not supported. - /// </summary> - SPI_GETSCREENREADER = 0x0046, - - /// <summary> - /// Determines whether a screen review utility is running. The uiParam parameter specifies TRUE for on, or FALSE for - /// off. - /// Windows NT: This value is not supported. - /// </summary> - SPI_SETSCREENREADER = 0x0047, - - /// <summary> - /// Retrieves the animation effects associated with user actions. The pvParam parameter must point to an ANIMATIONINFO - /// structure - /// that receives the information. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(ANIMATIONINFO). - /// </summary> - SPI_GETANIMATION = 0x0048, - - /// <summary> - /// Sets the animation effects associated with user actions. The pvParam parameter must point to an ANIMATIONINFO - /// structure - /// that contains the new parameters. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(ANIMATIONINFO). - /// </summary> - SPI_SETANIMATION = 0x0049, - - /// <summary> - /// Determines whether the font smoothing feature is enabled. This feature uses font antialiasing to make font curves - /// appear smoother - /// by painting pixels at different gray levels. - /// The pvParam parameter must point to a BOOL variable that receives TRUE if the feature is enabled, or FALSE if it is - /// not. - /// Windows 95: This flag is supported only if Windows Plus! is installed. See SPI_GETWINDOWSEXTENSION. - /// </summary> - SPI_GETFONTSMOOTHING = 0x004A, - - /// <summary> - /// Enables or disables the font smoothing feature, which uses font antialiasing to make font curves appear smoother - /// by painting pixels at different gray levels. - /// To enable the feature, set the uiParam parameter to TRUE. To disable the feature, set uiParam to FALSE. - /// Windows 95: This flag is supported only if Windows Plus! is installed. See SPI_GETWINDOWSEXTENSION. - /// </summary> - SPI_SETFONTSMOOTHING = 0x004B, - - /// <summary> - /// Sets the width, in pixels, of the rectangle used to detect the start of a drag operation. Set uiParam to the new - /// value. - /// To retrieve the drag width, call GetSystemMetrics with the SM_CXDRAG flag. - /// </summary> - SPI_SETDRAGWIDTH = 0x004C, - - /// <summary> - /// Sets the height, in pixels, of the rectangle used to detect the start of a drag operation. Set uiParam to the new - /// value. - /// To retrieve the drag height, call GetSystemMetrics with the SM_CYDRAG flag. - /// </summary> - SPI_SETDRAGHEIGHT = 0x004D, - - /// <summary> - /// Used internally; applications should not use this value. - /// </summary> - SPI_SETHANDHELD = 0x004E, - - /// <summary> - /// Retrieves the time-out value for the low-power phase of screen saving. The pvParam parameter must point to an - /// integer variable - /// that receives the value. This flag is supported for 32-bit applications only. - /// Windows NT, Windows Me/98: This flag is supported for 16-bit and 32-bit applications. - /// Windows 95: This flag is supported for 16-bit applications only. - /// </summary> - SPI_GETLOWPOWERTIMEOUT = 0x004F, - - /// <summary> - /// Retrieves the time-out value for the power-off phase of screen saving. The pvParam parameter must point to an - /// integer variable - /// that receives the value. This flag is supported for 32-bit applications only. - /// Windows NT, Windows Me/98: This flag is supported for 16-bit and 32-bit applications. - /// Windows 95: This flag is supported for 16-bit applications only. - /// </summary> - SPI_GETPOWEROFFTIMEOUT = 0x0050, - - /// <summary> - /// Sets the time-out value, in seconds, for the low-power phase of screen saving. The uiParam parameter specifies the - /// new value. - /// The pvParam parameter must be null. This flag is supported for 32-bit applications only. - /// Windows NT, Windows Me/98: This flag is supported for 16-bit and 32-bit applications. - /// Windows 95: This flag is supported for 16-bit applications only. - /// </summary> - SPI_SETLOWPOWERTIMEOUT = 0x0051, - - /// <summary> - /// Sets the time-out value, in seconds, for the power-off phase of screen saving. The uiParam parameter specifies the - /// new value. - /// The pvParam parameter must be null. This flag is supported for 32-bit applications only. - /// Windows NT, Windows Me/98: This flag is supported for 16-bit and 32-bit applications. - /// Windows 95: This flag is supported for 16-bit applications only. - /// </summary> - SPI_SETPOWEROFFTIMEOUT = 0x0052, - - /// <summary> - /// Determines whether the low-power phase of screen saving is enabled. The pvParam parameter must point to a BOOL - /// variable - /// that receives TRUE if enabled, or FALSE if disabled. This flag is supported for 32-bit applications only. - /// Windows NT, Windows Me/98: This flag is supported for 16-bit and 32-bit applications. - /// Windows 95: This flag is supported for 16-bit applications only. - /// </summary> - SPI_GETLOWPOWERACTIVE = 0x0053, - - /// <summary> - /// Determines whether the power-off phase of screen saving is enabled. The pvParam parameter must point to a BOOL - /// variable - /// that receives TRUE if enabled, or FALSE if disabled. This flag is supported for 32-bit applications only. - /// Windows NT, Windows Me/98: This flag is supported for 16-bit and 32-bit applications. - /// Windows 95: This flag is supported for 16-bit applications only. - /// </summary> - SPI_GETPOWEROFFACTIVE = 0x0054, - - /// <summary> - /// Activates or deactivates the low-power phase of screen saving. Set uiParam to 1 to activate, or zero to deactivate. - /// The pvParam parameter must be null. This flag is supported for 32-bit applications only. - /// Windows NT, Windows Me/98: This flag is supported for 16-bit and 32-bit applications. - /// Windows 95: This flag is supported for 16-bit applications only. - /// </summary> - SPI_SETLOWPOWERACTIVE = 0x0055, - - /// <summary> - /// Activates or deactivates the power-off phase of screen saving. Set uiParam to 1 to activate, or zero to deactivate. - /// The pvParam parameter must be null. This flag is supported for 32-bit applications only. - /// Windows NT, Windows Me/98: This flag is supported for 16-bit and 32-bit applications. - /// Windows 95: This flag is supported for 16-bit applications only. - /// </summary> - SPI_SETPOWEROFFACTIVE = 0x0056, - - /// <summary> - /// Reloads the system cursors. Set the uiParam parameter to zero and the pvParam parameter to null. - /// </summary> - SPI_SETCURSORS = 0x0057, - - /// <summary> - /// Reloads the system icons. Set the uiParam parameter to zero and the pvParam parameter to null. - /// </summary> - SPI_SETICONS = 0x0058, - - /// <summary> - /// Retrieves the input locale identifier for the system default input language. The pvParam parameter must point - /// to an HKL variable that receives this value. For more information, see Languages, Locales, and Keyboard Layouts on - /// MSDN. - /// </summary> - SPI_GETDEFAULTINPUTLANG = 0x0059, - - /// <summary> - /// Sets the default input language for the system shell and applications. The specified language must be displayable - /// using the current system character set. The pvParam parameter must point to an HKL variable that contains - /// the input locale identifier for the default language. For more information, see Languages, Locales, and Keyboard - /// Layouts on MSDN. - /// </summary> - SPI_SETDEFAULTINPUTLANG = 0x005A, - - /// <summary> - /// Sets the hot key set for switching between input languages. The uiParam and pvParam parameters are not used. - /// The value sets the shortcut keys in the keyboard property sheets by reading the registry again. The registry must - /// be set before this flag is used. the path in the registry is \HKEY_CURRENT_USER\keyboard layout\toggle. Valid - /// values are "1" = ALT+SHIFT, "2" = CTRL+SHIFT, and "3" = none. - /// </summary> - SPI_SETLANGTOGGLE = 0x005B, - - /// <summary> - /// Windows 95: Determines whether the Windows extension, Windows Plus!, is installed. Set the uiParam parameter to 1. - /// The pvParam parameter is not used. The function returns TRUE if the extension is installed, or FALSE if it is not. - /// </summary> - SPI_GETWINDOWSEXTENSION = 0x005C, - - /// <summary> - /// Enables or disables the Mouse Trails feature, which improves the visibility of mouse cursor movements by briefly - /// showing - /// a trail of cursors and quickly erasing them. - /// To disable the feature, set the uiParam parameter to zero or 1. To enable the feature, set uiParam to a value - /// greater than 1 - /// to indicate the number of cursors drawn in the trail. - /// Windows 2000/NT: This value is not supported. - /// </summary> - SPI_SETMOUSETRAILS = 0x005D, - - /// <summary> - /// Determines whether the Mouse Trails feature is enabled. This feature improves the visibility of mouse cursor - /// movements - /// by briefly showing a trail of cursors and quickly erasing them. - /// The pvParam parameter must point to an integer variable that receives a value. If the value is zero or 1, the - /// feature is disabled. - /// If the value is greater than 1, the feature is enabled and the value indicates the number of cursors drawn in the - /// trail. - /// The uiParam parameter is not used. - /// Windows 2000/NT: This value is not supported. - /// </summary> - SPI_GETMOUSETRAILS = 0x005E, - - /// <summary> - /// Windows Me/98: Used internally; applications should not use this flag. - /// </summary> - SPI_SETSCREENSAVERRUNNING = 0x0061, - - /// <summary> - /// Same as SPI_SETSCREENSAVERRUNNING. - /// </summary> - SPI_SCREENSAVERRUNNING = SPI_SETSCREENSAVERRUNNING, - //#endif /* WINVER >= 0x0400 */ - - /// <summary> - /// Retrieves information about the FilterKeys accessibility feature. The pvParam parameter must point to a FILTERKEYS - /// structure - /// that receives the information. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(FILTERKEYS). - /// </summary> - SPI_GETFILTERKEYS = 0x0032, - - /// <summary> - /// Sets the parameters of the FilterKeys accessibility feature. The pvParam parameter must point to a FILTERKEYS - /// structure - /// that contains the new parameters. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(FILTERKEYS). - /// </summary> - SPI_SETFILTERKEYS = 0x0033, - - /// <summary> - /// Retrieves information about the ToggleKeys accessibility feature. The pvParam parameter must point to a TOGGLEKEYS - /// structure - /// that receives the information. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(TOGGLEKEYS). - /// </summary> - SPI_GETTOGGLEKEYS = 0x0034, - - /// <summary> - /// Sets the parameters of the ToggleKeys accessibility feature. The pvParam parameter must point to a TOGGLEKEYS - /// structure - /// that contains the new parameters. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(TOGGLEKEYS). - /// </summary> - SPI_SETTOGGLEKEYS = 0x0035, - - /// <summary> - /// Retrieves information about the MouseKeys accessibility feature. The pvParam parameter must point to a MOUSEKEYS - /// structure - /// that receives the information. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(MOUSEKEYS). - /// </summary> - SPI_GETMOUSEKEYS = 0x0036, - - /// <summary> - /// Sets the parameters of the MouseKeys accessibility feature. The pvParam parameter must point to a MOUSEKEYS - /// structure - /// that contains the new parameters. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(MOUSEKEYS). - /// </summary> - SPI_SETMOUSEKEYS = 0x0037, - - /// <summary> - /// Determines whether the Show Sounds accessibility flag is on or off. If it is on, the user requires an application - /// to present information visually in situations where it would otherwise present the information only in audible - /// form. - /// The pvParam parameter must point to a BOOL variable that receives TRUE if the feature is on, or FALSE if it is off. - /// Using this value is equivalent to calling GetSystemMetrics (SM_SHOWSOUNDS). That is the recommended call. - /// </summary> - SPI_GETSHOWSOUNDS = 0x0038, - - /// <summary> - /// Sets the parameters of the SoundSentry accessibility feature. The pvParam parameter must point to a SOUNDSENTRY - /// structure - /// that contains the new parameters. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(SOUNDSENTRY). - /// </summary> - SPI_SETSHOWSOUNDS = 0x0039, - - /// <summary> - /// Retrieves information about the StickyKeys accessibility feature. The pvParam parameter must point to a STICKYKEYS - /// structure - /// that receives the information. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(STICKYKEYS). - /// </summary> - SPI_GETSTICKYKEYS = 0x003A, - - /// <summary> - /// Sets the parameters of the StickyKeys accessibility feature. The pvParam parameter must point to a STICKYKEYS - /// structure - /// that contains the new parameters. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(STICKYKEYS). - /// </summary> - SPI_SETSTICKYKEYS = 0x003B, - - /// <summary> - /// Retrieves information about the time-out period associated with the accessibility features. The pvParam parameter - /// must point - /// to an ACCESSTIMEOUT structure that receives the information. Set the cbSize member of this structure and the - /// uiParam parameter - /// to sizeof(ACCESSTIMEOUT). - /// </summary> - SPI_GETACCESSTIMEOUT = 0x003C, - - /// <summary> - /// Sets the time-out period associated with the accessibility features. The pvParam parameter must point to an - /// ACCESSTIMEOUT - /// structure that contains the new parameters. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(ACCESSTIMEOUT). - /// </summary> - SPI_SETACCESSTIMEOUT = 0x003D, - - /// <summary> - /// Windows Me/98/95: Retrieves information about the SerialKeys accessibility feature. The pvParam parameter must - /// point - /// to a SERIALKEYS structure that receives the information. Set the cbSize member of this structure and the uiParam - /// parameter - /// to sizeof(SERIALKEYS). - /// Windows Server 2003, Windows XP/2000/NT: Not supported. The user controls this feature through the control panel. - /// </summary> - SPI_GETSERIALKEYS = 0x003E, - - /// <summary> - /// Windows Me/98/95: Sets the parameters of the SerialKeys accessibility feature. The pvParam parameter must point - /// to a SERIALKEYS structure that contains the new parameters. Set the cbSize member of this structure and the uiParam - /// parameter - /// to sizeof(SERIALKEYS). - /// Windows Server 2003, Windows XP/2000/NT: Not supported. The user controls this feature through the control panel. - /// </summary> - SPI_SETSERIALKEYS = 0x003F, - //#endif /* WINVER >= 0x0400 */ - - /// <summary> - /// Retrieves information about the SoundSentry accessibility feature. The pvParam parameter must point to a - /// SOUNDSENTRY structure - /// that receives the information. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(SOUNDSENTRY). - /// </summary> - SPI_GETSOUNDSENTRY = 0x0040, - - /// <summary> - /// Sets the parameters of the SoundSentry accessibility feature. The pvParam parameter must point to a SOUNDSENTRY - /// structure - /// that contains the new parameters. Set the cbSize member of this structure and the uiParam parameter to - /// sizeof(SOUNDSENTRY). - /// </summary> - SPI_SETSOUNDSENTRY = 0x0041, - - /// <summary> - /// Determines whether the snap-to-default-button feature is enabled. If enabled, the mouse cursor automatically moves - /// to the default button, such as OK or Apply, of a dialog box. The pvParam parameter must point to a BOOL variable - /// that receives TRUE if the feature is on, or FALSE if it is off. - /// Windows 95: Not supported. - /// </summary> - SPI_GETSNAPTODEFBUTTON = 0x005F, - - /// <summary> - /// Enables or disables the snap-to-default-button feature. If enabled, the mouse cursor automatically moves to the - /// default button, - /// such as OK or Apply, of a dialog box. Set the uiParam parameter to TRUE to enable the feature, or FALSE to disable - /// it. - /// Applications should use the ShowWindow function when displaying a dialog box so the dialog manager can position the - /// mouse cursor. - /// Windows 95: Not supported. - /// </summary> - SPI_SETSNAPTODEFBUTTON = 0x0060, - - /// <summary> - /// Retrieves the width, in pixels, of the rectangle within which the mouse pointer has to stay for TrackMouseEvent - /// to generate a WM_MOUSEHOVER message. The pvParam parameter must point to a UINT variable that receives the width. - /// Windows 95: Not supported. - /// </summary> - SPI_GETMOUSEHOVERWIDTH = 0x0062, - - /// <summary> - /// Retrieves the width, in pixels, of the rectangle within which the mouse pointer has to stay for TrackMouseEvent - /// to generate a WM_MOUSEHOVER message. The pvParam parameter must point to a UINT variable that receives the width. - /// Windows 95: Not supported. - /// </summary> - SPI_SETMOUSEHOVERWIDTH = 0x0063, - - /// <summary> - /// Retrieves the height, in pixels, of the rectangle within which the mouse pointer has to stay for TrackMouseEvent - /// to generate a WM_MOUSEHOVER message. The pvParam parameter must point to a UINT variable that receives the height. - /// Windows 95: Not supported. - /// </summary> - SPI_GETMOUSEHOVERHEIGHT = 0x0064, - - /// <summary> - /// Sets the height, in pixels, of the rectangle within which the mouse pointer has to stay for TrackMouseEvent - /// to generate a WM_MOUSEHOVER message. Set the uiParam parameter to the new height. - /// Windows 95: Not supported. - /// </summary> - SPI_SETMOUSEHOVERHEIGHT = 0x0065, - - /// <summary> - /// Retrieves the time, in milliseconds, that the mouse pointer has to stay in the hover rectangle for TrackMouseEvent - /// to generate a WM_MOUSEHOVER message. The pvParam parameter must point to a UINT variable that receives the time. - /// Windows 95: Not supported. - /// </summary> - SPI_GETMOUSEHOVERTIME = 0x0066, - - /// <summary> - /// Sets the time, in milliseconds, that the mouse pointer has to stay in the hover rectangle for TrackMouseEvent - /// to generate a WM_MOUSEHOVER message. This is used only if you pass HOVER_DEFAULT in the dwHoverTime parameter in - /// the call to TrackMouseEvent. Set the uiParam parameter to the new time. - /// Windows 95: Not supported. - /// </summary> - SPI_SETMOUSEHOVERTIME = 0x0067, - - /// <summary> - /// Retrieves the number of lines to scroll when the mouse wheel is rotated. The pvParam parameter must point - /// to a UINT variable that receives the number of lines. The default value is 3. - /// Windows 95: Not supported. - /// </summary> - SPI_GETWHEELSCROLLLINES = 0x0068, - - /// <summary> - /// Sets the number of lines to scroll when the mouse wheel is rotated. The number of lines is set from the uiParam - /// parameter. - /// The number of lines is the suggested number of lines to scroll when the mouse wheel is rolled without using - /// modifier keys. - /// If the number is 0, then no scrolling should occur. If the number of lines to scroll is greater than the number of - /// lines viewable, - /// and in particular if it is WHEEL_PAGESCROLL (#defined as UINT_MAX), the scroll operation should be interpreted - /// as clicking once in the page down or page up regions of the scroll bar. - /// Windows 95: Not supported. - /// </summary> - SPI_SETWHEELSCROLLLINES = 0x0069, - - /// <summary> - /// Retrieves the time, in milliseconds, that the system waits before displaying a shortcut menu when the mouse cursor - /// is - /// over a submenu item. The pvParam parameter must point to a DWORD variable that receives the time of the delay. - /// Windows 95: Not supported. - /// </summary> - SPI_GETMENUSHOWDELAY = 0x006A, - - /// <summary> - /// Sets uiParam to the time, in milliseconds, that the system waits before displaying a shortcut menu when the mouse - /// cursor is - /// over a submenu item. - /// Windows 95: Not supported. - /// </summary> - SPI_SETMENUSHOWDELAY = 0x006B, - - /// <summary> - /// Determines whether the IME status window is visible (on a per-user basis). The pvParam parameter must point to a - /// BOOL variable - /// that receives TRUE if the status window is visible, or FALSE if it is not. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETSHOWIMEUI = 0x006E, - - /// <summary> - /// Sets whether the IME status window is visible or not on a per-user basis. The uiParam parameter specifies TRUE for - /// on or FALSE for off. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETSHOWIMEUI = 0x006F, - - /// <summary> - /// Retrieves the current mouse speed. The mouse speed determines how far the pointer will move based on the distance - /// the mouse moves. - /// The pvParam parameter must point to an integer that receives a value which ranges between 1 (slowest) and 20 - /// (fastest). - /// A value of 10 is the default. The value can be set by an end user using the mouse control panel application or - /// by an application using SPI_SETMOUSESPEED. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETMOUSESPEED = 0x0070, - - /// <summary> - /// Sets the current mouse speed. The pvParam parameter is an integer between 1 (slowest) and 20 (fastest). A value of - /// 10 is the default. - /// This value is typically set using the mouse control panel application. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETMOUSESPEED = 0x0071, - - /// <summary> - /// Determines whether a screen saver is currently running on the window station of the calling process. - /// The pvParam parameter must point to a BOOL variable that receives TRUE if a screen saver is currently running, or - /// FALSE otherwise. - /// Note that only the interactive window station, "WinSta0", can have a screen saver running. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETSCREENSAVERRUNNING = 0x0072, - - /// <summary> - /// Retrieves the full path of the bitmap file for the desktop wallpaper. The pvParam parameter must point to a buffer - /// that receives a null-terminated path string. Set the uiParam parameter to the size, in characters, of the pvParam - /// buffer. The returned string will not exceed MAX_PATH characters. If there is no desktop wallpaper, the returned - /// string is empty. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETDESKWALLPAPER = 0x0073, - - /// <summary> - /// Determines whether active window tracking (activating the window the mouse is on) is on or off. The pvParam - /// parameter must point - /// to a BOOL variable that receives TRUE for on, or FALSE for off. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETACTIVEWINDOWTRACKING = 0x1000, - - /// <summary> - /// Sets active window tracking (activating the window the mouse is on) either on or off. Set pvParam to TRUE for on or - /// FALSE for off. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETACTIVEWINDOWTRACKING = 0x1001, - - /// <summary> - /// Determines whether the menu animation feature is enabled. This master switch must be on to enable menu animation - /// effects. - /// The pvParam parameter must point to a BOOL variable that receives TRUE if animation is enabled and FALSE if it is - /// disabled. - /// If animation is enabled, SPI_GETMENUFADE indicates whether menus use fade or slide animation. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETMENUANIMATION = 0x1002, - - /// <summary> - /// Enables or disables menu animation. This master switch must be on for any menu animation to occur. - /// The pvParam parameter is a BOOL variable; set pvParam to TRUE to enable animation and FALSE to disable animation. - /// If animation is enabled, SPI_GETMENUFADE indicates whether menus use fade or slide animation. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETMENUANIMATION = 0x1003, - - /// <summary> - /// Determines whether the slide-open effect for combo boxes is enabled. The pvParam parameter must point to a BOOL - /// variable - /// that receives TRUE for enabled, or FALSE for disabled. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETCOMBOBOXANIMATION = 0x1004, - - /// <summary> - /// Enables or disables the slide-open effect for combo boxes. Set the pvParam parameter to TRUE to enable the gradient - /// effect, - /// or FALSE to disable it. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETCOMBOBOXANIMATION = 0x1005, - - /// <summary> - /// Determines whether the smooth-scrolling effect for list boxes is enabled. The pvParam parameter must point to a - /// BOOL variable - /// that receives TRUE for enabled, or FALSE for disabled. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETLISTBOXSMOOTHSCROLLING = 0x1006, - - /// <summary> - /// Enables or disables the smooth-scrolling effect for list boxes. Set the pvParam parameter to TRUE to enable the - /// smooth-scrolling effect, - /// or FALSE to disable it. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETLISTBOXSMOOTHSCROLLING = 0x1007, - - /// <summary> - /// Determines whether the gradient effect for window title bars is enabled. The pvParam parameter must point to a BOOL - /// variable - /// that receives TRUE for enabled, or FALSE for disabled. For more information about the gradient effect, see the - /// GetSysColor function. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETGRADIENTCAPTIONS = 0x1008, - - /// <summary> - /// Enables or disables the gradient effect for window title bars. Set the pvParam parameter to TRUE to enable it, or - /// FALSE to disable it. - /// The gradient effect is possible only if the system has a color depth of more than 256 colors. For more information - /// about - /// the gradient effect, see the GetSysColor function. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETGRADIENTCAPTIONS = 0x1009, - - /// <summary> - /// Determines whether menu access keys are always underlined. The pvParam parameter must point to a BOOL variable that - /// receives TRUE - /// if menu access keys are always underlined, and FALSE if they are underlined only when the menu is activated by the - /// keyboard. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETKEYBOARDCUES = 0x100A, - - /// <summary> - /// Sets the underlining of menu access key letters. The pvParam parameter is a BOOL variable. Set pvParam to TRUE to - /// always underline menu - /// access keys, or FALSE to underline menu access keys only when the menu is activated from the keyboard. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETKEYBOARDCUES = 0x100B, - - /// <summary> - /// Same as SPI_GETKEYBOARDCUES. - /// </summary> - SPI_GETMENUUNDERLINES = SPI_GETKEYBOARDCUES, - - /// <summary> - /// Same as SPI_SETKEYBOARDCUES. - /// </summary> - SPI_SETMENUUNDERLINES = SPI_SETKEYBOARDCUES, - - /// <summary> - /// Determines whether windows activated through active window tracking will be brought to the top. The pvParam - /// parameter must point - /// to a BOOL variable that receives TRUE for on, or FALSE for off. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETACTIVEWNDTRKZORDER = 0x100C, - - /// <summary> - /// Determines whether or not windows activated through active window tracking should be brought to the top. Set - /// pvParam to TRUE - /// for on or FALSE for off. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETACTIVEWNDTRKZORDER = 0x100D, - - /// <summary> - /// Determines whether hot tracking of user-interface elements, such as menu names on menu bars, is enabled. The - /// pvParam parameter - /// must point to a BOOL variable that receives TRUE for enabled, or FALSE for disabled. - /// Hot tracking means that when the cursor moves over an item, it is highlighted but not selected. You can query this - /// value to decide - /// whether to use hot tracking in the user interface of your application. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETHOTTRACKING = 0x100E, - - /// <summary> - /// Enables or disables hot tracking of user-interface elements such as menu names on menu bars. Set the pvParam - /// parameter to TRUE - /// to enable it, or FALSE to disable it. - /// Hot-tracking means that when the cursor moves over an item, it is highlighted but not selected. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETHOTTRACKING = 0x100F, - - /// <summary> - /// Determines whether menu fade animation is enabled. The pvParam parameter must point to a BOOL variable that - /// receives TRUE - /// when fade animation is enabled and FALSE when it is disabled. If fade animation is disabled, menus use slide - /// animation. - /// This flag is ignored unless menu animation is enabled, which you can do using the SPI_SETMENUANIMATION flag. - /// For more information, see AnimateWindow. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETMENUFADE = 0x1012, - - /// <summary> - /// Enables or disables menu fade animation. Set pvParam to TRUE to enable the menu fade effect or FALSE to disable it. - /// If fade animation is disabled, menus use slide animation. he The menu fade effect is possible only if the system - /// has a color depth of more than 256 colors. This flag is ignored unless SPI_MENUANIMATION is also set. For more - /// information, - /// see AnimateWindow. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETMENUFADE = 0x1013, - - /// <summary> - /// Determines whether the selection fade effect is enabled. The pvParam parameter must point to a BOOL variable that - /// receives TRUE - /// if enabled or FALSE if disabled. - /// The selection fade effect causes the menu item selected by the user to remain on the screen briefly while fading - /// out - /// after the menu is dismissed. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETSELECTIONFADE = 0x1014, - - /// <summary> - /// Set pvParam to TRUE to enable the selection fade effect or FALSE to disable it. - /// The selection fade effect causes the menu item selected by the user to remain on the screen briefly while fading - /// out - /// after the menu is dismissed. The selection fade effect is possible only if the system has a color depth of more - /// than 256 colors. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETSELECTIONFADE = 0x1015, - - /// <summary> - /// Determines whether ToolTip animation is enabled. The pvParam parameter must point to a BOOL variable that receives - /// TRUE - /// if enabled or FALSE if disabled. If ToolTip animation is enabled, SPI_GETTOOLTIPFADE indicates whether ToolTips use - /// fade or slide animation. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETTOOLTIPANIMATION = 0x1016, - - /// <summary> - /// Set pvParam to TRUE to enable ToolTip animation or FALSE to disable it. If enabled, you can use SPI_SETTOOLTIPFADE - /// to specify fade or slide animation. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETTOOLTIPANIMATION = 0x1017, - - /// <summary> - /// If SPI_SETTOOLTIPANIMATION is enabled, SPI_GETTOOLTIPFADE indicates whether ToolTip animation uses a fade effect or - /// a slide effect. - /// The pvParam parameter must point to a BOOL variable that receives TRUE for fade animation or FALSE for slide - /// animation. - /// For more information on slide and fade effects, see AnimateWindow. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETTOOLTIPFADE = 0x1018, - - /// <summary> - /// If the SPI_SETTOOLTIPANIMATION flag is enabled, use SPI_SETTOOLTIPFADE to indicate whether ToolTip animation uses a - /// fade effect - /// or a slide effect. Set pvParam to TRUE for fade animation or FALSE for slide animation. The tooltip fade effect is - /// possible only - /// if the system has a color depth of more than 256 colors. For more information on the slide and fade effects, - /// see the AnimateWindow function. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETTOOLTIPFADE = 0x1019, - - /// <summary> - /// Determines whether the cursor has a shadow around it. The pvParam parameter must point to a BOOL variable that - /// receives TRUE - /// if the shadow is enabled, FALSE if it is disabled. This effect appears only if the system has a color depth of more - /// than 256 colors. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETCURSORSHADOW = 0x101A, - - /// <summary> - /// Enables or disables a shadow around the cursor. The pvParam parameter is a BOOL variable. Set pvParam to TRUE to - /// enable the shadow - /// or FALSE to disable the shadow. This effect appears only if the system has a color depth of more than 256 colors. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETCURSORSHADOW = 0x101B, - - /// <summary> - /// Retrieves the state of the Mouse Sonar feature. The pvParam parameter must point to a BOOL variable that receives - /// TRUE - /// if enabled or FALSE otherwise. For more information, see About Mouse Input on MSDN. - /// Windows 2000/NT, Windows 98/95: This value is not supported. - /// </summary> - SPI_GETMOUSESONAR = 0x101C, - - /// <summary> - /// Turns the Sonar accessibility feature on or off. This feature briefly shows several concentric circles around the - /// mouse pointer when the user presses and releases the CTRL key. The pvParam parameter specifies TRUE for on and FALSE for off. - /// The default is off. - /// For more information, see About Mouse Input. - /// Windows 2000/NT, Windows 98/95: This value is not supported. - /// </summary> - SPI_SETMOUSESONAR = 0x101D, - - /// <summary> - /// Retrieves the state of the Mouse ClickLock feature. The pvParam parameter must point to a BOOL variable that - /// receives TRUE - /// if enabled, or FALSE otherwise. For more information, see About Mouse Input. - /// Windows 2000/NT, Windows 98/95: This value is not supported. - /// </summary> - SPI_GETMOUSECLICKLOCK = 0x101E, - - /// <summary> - /// Turns the Mouse ClickLock accessibility feature on or off. This feature temporarily locks down the primary mouse - /// button - /// when that button is clicked and held down for the time specified by SPI_SETMOUSECLICKLOCKTIME. The uiParam - /// parameter specifies - /// TRUE for on, - /// or FALSE for off. The default is off. For more information, see Remarks and About Mouse Input on MSDN. - /// Windows 2000/NT, Windows 98/95: This value is not supported. - /// </summary> - SPI_SETMOUSECLICKLOCK = 0x101F, - - /// <summary> - /// Retrieves the state of the Mouse Vanish feature. The pvParam parameter must point to a BOOL variable that receives - /// TRUE - /// if enabled or FALSE otherwise. For more information, see About Mouse Input on MSDN. - /// Windows 2000/NT, Windows 98/95: This value is not supported. - /// </summary> - SPI_GETMOUSEVANISH = 0x1020, - - /// <summary> - /// Turns the Vanish feature on or off. This feature hides the mouse pointer when the user types; the pointer reappears - /// when the user moves the mouse. The pvParam parameter specifies TRUE for on and FALSE for off. The default is off. - /// For more information, see About Mouse Input on MSDN. - /// Windows 2000/NT, Windows 98/95: This value is not supported. - /// </summary> - SPI_SETMOUSEVANISH = 0x1021, - - /// <summary> - /// Determines whether native User menus have flat menu appearance. The pvParam parameter must point to a BOOL variable - /// that returns TRUE if the flat menu appearance is set, or FALSE otherwise. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETFLATMENU = 0x1022, - - /// <summary> - /// Enables or disables flat menu appearance for native User menus. Set pvParam to TRUE to enable flat menu appearance - /// or FALSE to disable it. - /// When enabled, the menu bar uses COLOR_MENUBAR for the menubar background, COLOR_MENU for the menu-popup background, - /// COLOR_MENUHILIGHT - /// for the fill of the current menu selection, and COLOR_HILIGHT for the outline of the current menu selection. - /// If disabled, menus are drawn using the same metrics and colors as in Windows 2000 and earlier. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETFLATMENU = 0x1023, - - /// <summary> - /// Determines whether the drop shadow effect is enabled. The pvParam parameter must point to a BOOL variable that - /// returns TRUE - /// if enabled or FALSE if disabled. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETDROPSHADOW = 0x1024, - - /// <summary> - /// Enables or disables the drop shadow effect. Set pvParam to TRUE to enable the drop shadow effect or FALSE to - /// disable it. - /// You must also have CS_DROPSHADOW in the window class style. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETDROPSHADOW = 0x1025, - - /// <summary> - /// Retrieves a BOOL indicating whether an application can reset the screensaver's timer by calling the SendInput - /// function - /// to simulate keyboard or mouse input. The pvParam parameter must point to a BOOL variable that receives TRUE - /// if the simulated input will be blocked, or FALSE otherwise. - /// </summary> - SPI_GETBLOCKSENDINPUTRESETS = 0x1026, - - /// <summary> - /// Determines whether an application can reset the screensaver's timer by calling the SendInput function to simulate - /// keyboard - /// or mouse input. The uiParam parameter specifies TRUE if the screensaver will not be deactivated by simulated input, - /// or FALSE if the screensaver will be deactivated by simulated input. - /// </summary> - SPI_SETBLOCKSENDINPUTRESETS = 0x1027, - //#endif /* _WIN32_WINNT >= 0x0501 */ - - /// <summary> - /// Determines whether UI effects are enabled or disabled. The pvParam parameter must point to a BOOL variable that - /// receives TRUE - /// if all UI effects are enabled, or FALSE if they are disabled. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETUIEFFECTS = 0x103E, - - /// <summary> - /// Enables or disables UI effects. Set the pvParam parameter to TRUE to enable all UI effects or FALSE to disable all - /// UI effects. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETUIEFFECTS = 0x103F, - - /// <summary> - /// Retrieves the amount of time following user input, in milliseconds, during which the system will not allow - /// applications - /// to force themselves into the foreground. The pvParam parameter must point to a DWORD variable that receives the - /// time. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000, - - /// <summary> - /// Sets the amount of time following user input, in milliseconds, during which the system does not allow applications - /// to force themselves into the foreground. Set pvParam to the new timeout value. - /// The calling thread must be able to change the foreground window, otherwise the call fails. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001, - - /// <summary> - /// Retrieves the active window tracking delay, in milliseconds. The pvParam parameter must point to a DWORD variable - /// that receives the time. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETACTIVEWNDTRKTIMEOUT = 0x2002, - - /// <summary> - /// Sets the active window tracking delay. Set pvParam to the number of milliseconds to delay before activating the - /// window - /// under the mouse pointer. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETACTIVEWNDTRKTIMEOUT = 0x2003, - - /// <summary> - /// Retrieves the number of times SetForegroundWindow will flash the taskbar button when rejecting a foreground switch - /// request. - /// The pvParam parameter must point to a DWORD variable that receives the value. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_GETFOREGROUNDFLASHCOUNT = 0x2004, - - /// <summary> - /// Sets the number of times SetForegroundWindow will flash the taskbar button when rejecting a foreground switch - /// request. - /// Set pvParam to the number of times to flash. - /// Windows NT, Windows 95: This value is not supported. - /// </summary> - SPI_SETFOREGROUNDFLASHCOUNT = 0x2005, - - /// <summary> - /// Retrieves the caret width in edit controls, in pixels. The pvParam parameter must point to a DWORD that receives - /// this value. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETCARETWIDTH = 0x2006, - - /// <summary> - /// Sets the caret width in edit controls. Set pvParam to the desired width, in pixels. The default and minimum value - /// is 1. - /// Windows NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETCARETWIDTH = 0x2007, - - /// <summary> - /// Retrieves the time delay before the primary mouse button is locked. The pvParam parameter must point to DWORD that - /// receives - /// the time delay. This is only enabled if SPI_SETMOUSECLICKLOCK is set to TRUE. For more information, see About Mouse - /// Input on MSDN. - /// Windows 2000/NT, Windows 98/95: This value is not supported. - /// </summary> - SPI_GETMOUSECLICKLOCKTIME = 0x2008, - - /// <summary> - /// Turns the Mouse ClickLock accessibility feature on or off. This feature temporarily locks down the primary mouse - /// button - /// when that button is clicked and held down for the time specified by SPI_SETMOUSECLICKLOCKTIME. The uiParam - /// parameter - /// specifies TRUE for on, or FALSE for off. The default is off. For more information, see Remarks and About Mouse - /// Input on MSDN. - /// Windows 2000/NT, Windows 98/95: This value is not supported. - /// </summary> - SPI_SETMOUSECLICKLOCKTIME = 0x2009, - - /// <summary> - /// Retrieves the type of font smoothing. The pvParam parameter must point to a UINT that receives the information. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETFONTSMOOTHINGTYPE = 0x200A, - - /// <summary> - /// Sets the font smoothing type. The pvParam parameter points to a UINT that contains either FE_FONTSMOOTHINGSTANDARD, - /// if standard anti-aliasing is used, or FE_FONTSMOOTHINGCLEARTYPE, if ClearType is used. The default is - /// FE_FONTSMOOTHINGSTANDARD. - /// When using this option, the fWinIni parameter must be set to SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE; otherwise, - /// SystemParametersInfo fails. - /// </summary> - SPI_SETFONTSMOOTHINGTYPE = 0x200B, - - /// <summary> - /// Retrieves a contrast value that is used in ClearType™ smoothing. The pvParam parameter must point to a UINT - /// that receives the information. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETFONTSMOOTHINGCONTRAST = 0x200C, - - /// <summary> - /// Sets the contrast value used in ClearType smoothing. The pvParam parameter points to a UINT that holds the contrast - /// value. - /// Valid contrast values are from 1000 to 2200. The default value is 1400. - /// When using this option, the fWinIni parameter must be set to SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE; otherwise, - /// SystemParametersInfo fails. - /// SPI_SETFONTSMOOTHINGTYPE must also be set to FE_FONTSMOOTHINGCLEARTYPE. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETFONTSMOOTHINGCONTRAST = 0x200D, - - /// <summary> - /// Retrieves the width, in pixels, of the left and right edges of the focus rectangle drawn with DrawFocusRect. - /// The pvParam parameter must point to a UINT. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETFOCUSBORDERWIDTH = 0x200E, - - /// <summary> - /// Sets the height of the left and right edges of the focus rectangle drawn with DrawFocusRect to the value of the - /// pvParam parameter. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETFOCUSBORDERWIDTH = 0x200F, - - /// <summary> - /// Retrieves the height, in pixels, of the top and bottom edges of the focus rectangle drawn with DrawFocusRect. - /// The pvParam parameter must point to a UINT. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_GETFOCUSBORDERHEIGHT = 0x2010, - - /// <summary> - /// Sets the height of the top and bottom edges of the focus rectangle drawn with DrawFocusRect to the value of the - /// pvParam parameter. - /// Windows 2000/NT, Windows Me/98/95: This value is not supported. - /// </summary> - SPI_SETFOCUSBORDERHEIGHT = 0x2011, - - /// <summary> - /// Not implemented. - /// </summary> - SPI_GETFONTSMOOTHINGORIENTATION = 0x2012, - - /// <summary> - /// Not implemented. - /// </summary> - SPI_SETFONTSMOOTHINGORIENTATION = 0x2013 - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/Enums/SystemParametersInfoBehaviors.cs b/GreenshotPlugin/Core/Enums/SystemParametersInfoBehaviors.cs deleted file mode 100644 index 4b5872ae5..000000000 --- a/GreenshotPlugin/Core/Enums/SystemParametersInfoBehaviors.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Dapplo and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace GreenshotPlugin.Core.Enums -{ - /// <summary> - /// If a system parameter is being set, specifies whether the user profile is to be updated, and if so, whether the - /// WM_SETTINGCHANGE message is to be broadcast to all top-level windows to notify them of the change. - /// This parameter can be zero if you do not want to update the user profile or broadcast the WM_SETTINGCHANGE message, - /// or it can be one or more of the following values. - /// </summary> - public enum SystemParametersInfoBehaviors : uint - { - /// <summary> - /// Do nothing - /// </summary> - None = 0x00, - - /// <summary>Writes the new system-wide parameter setting to the user profile.</summary> - UpdateIniFile = 0x01, - - /// <summary>Broadcasts the WM_SETTINGCHANGE message after updating the user profile.</summary> - SendChange = 0x02, - - /// <summary>Same as SPIF_SENDCHANGE.</summary> - SendWinIniChange = SendChange - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/FastBitmap.cs b/GreenshotPlugin/Core/FastBitmap.cs index 0e52e04fb..54b11e5ce 100644 --- a/GreenshotPlugin/Core/FastBitmap.cs +++ b/GreenshotPlugin/Core/FastBitmap.cs @@ -355,16 +355,7 @@ namespace GreenshotPlugin.Core { } } - /// <summary> - /// Factory for creating a FastBitmap as a destination for the source - /// </summary> - /// <param name="source">Bitmap to clone</param> - /// <returns>IFastBitmap</returns> - public static IFastBitmap CreateCloneOf(Image source) { - return CreateCloneOf(source, source.PixelFormat, Rectangle.Empty); - } - - /// <summary> + /// <summary> /// Factory for creating a FastBitmap as a destination for the source /// </summary> /// <param name="source">Bitmap to clone</param> diff --git a/GreenshotPlugin/Core/HResultExtensions.cs b/GreenshotPlugin/Core/HResultExtensions.cs index a85bd7600..450636ef7 100644 --- a/GreenshotPlugin/Core/HResultExtensions.cs +++ b/GreenshotPlugin/Core/HResultExtensions.cs @@ -19,7 +19,6 @@ using GreenshotPlugin.Core.Enums; using System.Diagnostics.Contracts; -using System.Runtime.InteropServices; namespace GreenshotPlugin.Core { @@ -29,7 +28,7 @@ namespace GreenshotPlugin.Core public static class HResultExtensions { /// <summary> - /// Test if the HResult respresents a fail + /// Test if the HResult represents a fail /// </summary> /// <param name="hResult">HResult</param> /// <returns>bool</returns> @@ -40,7 +39,7 @@ namespace GreenshotPlugin.Core } /// <summary> - /// Test if the HResult respresents a success + /// Test if the HResult represents a success /// </summary> /// <param name="hResult">HResult</param> /// <returns>bool</returns> @@ -49,17 +48,5 @@ namespace GreenshotPlugin.Core { return hResult >= HResult.S_OK; } - - /// <summary> - /// Throw an exception on Failure - /// </summary> - /// <param name="hResult">HResult</param> - public static void ThrowOnFailure(this HResult hResult) - { - if (hResult.Failed()) - { - throw Marshal.GetExceptionForHR((int)hResult); - } - } } } diff --git a/GreenshotPlugin/Core/ImageWrapper.cs b/GreenshotPlugin/Core/ImageWrapper.cs index f4cc03247..270164cb7 100644 --- a/GreenshotPlugin/Core/ImageWrapper.cs +++ b/GreenshotPlugin/Core/ImageWrapper.cs @@ -12,16 +12,6 @@ namespace GreenshotPlugin.Core private readonly Image _image; private Image _imageClone; - /// <summary> - /// Factory method - /// </summary> - /// <param name="image">Image</param> - /// <returns>IImage</returns> - public static IImage FromImage(Image image) - { - return image == null ? null : new ImageWrapper(image); - } - public ImageWrapper(Image image) { // Make sure the orientation is set correctly so Greenshot can process the image correctly diff --git a/GreenshotPlugin/Core/InterfaceUtils.cs b/GreenshotPlugin/Core/InterfaceUtils.cs index 89c8079f0..7dca0f172 100644 --- a/GreenshotPlugin/Core/InterfaceUtils.cs +++ b/GreenshotPlugin/Core/InterfaceUtils.cs @@ -20,9 +20,7 @@ */ using System; using System.Collections.Generic; -using System.Reflection; using System.Threading; -using GreenshotPlugin.Interfaces; using log4net; namespace GreenshotPlugin.Core { @@ -33,42 +31,28 @@ namespace GreenshotPlugin.Core { private static readonly ILog LOG = LogManager.GetLogger(typeof(InterfaceUtils)); public static List<Type> GetSubclassesOf(Type type, bool excludeSystemTypes) { - List<Type> list = new List<Type>(); - foreach(Assembly currentAssembly in Thread.GetDomain().GetAssemblies()) { + var list = new List<Type>(); + foreach(var currentAssembly in Thread.GetDomain().GetAssemblies()) { try { Type[] types = currentAssembly.GetTypes(); - if (!excludeSystemTypes || (excludeSystemTypes && !currentAssembly.FullName.StartsWith("System."))) { - foreach(Type currentType in types) { - if (type.IsInterface) { - if (currentType.GetInterface(type.FullName) != null) { - list.Add(currentType); - } - } else if (currentType.IsSubclassOf(type)) { - list.Add(currentType); - } - } - } - } catch (Exception ex) { + if (excludeSystemTypes && (!excludeSystemTypes || currentAssembly.FullName.StartsWith("System."))) + { + continue; + } + foreach(var currentType in types) { + if (type.IsInterface) { + if (currentType.GetInterface(type.FullName) != null) { + list.Add(currentType); + } + } else if (currentType.IsSubclassOf(type)) { + list.Add(currentType); + } + } + } catch (Exception ex) { LOG.WarnFormat("Problem getting subclasses of type: {0}, message: {1}", type.FullName, ex.Message); } } return list; } - - public static List<IProcessor> GetProcessors() { - List<IProcessor> processors = new List<IProcessor>(); - foreach(Type processorType in GetSubclassesOf(typeof(IProcessor), true)) { - if (!processorType.IsAbstract) { - IProcessor processor = (IProcessor)Activator.CreateInstance(processorType); - if (processor.isActive) { - LOG.DebugFormat("Found processor {0} with designation {1}", processorType.Name, processor.Designation); - processors.Add(processor); - } else { - LOG.DebugFormat("Ignoring processor {0} with designation {1}", processorType.Name, processor.Designation); - } - } - } - return processors; - } - } + } } diff --git a/GreenshotPlugin/Core/Language.cs b/GreenshotPlugin/Core/Language.cs index f5f2caa26..1b60b6dc8 100644 --- a/GreenshotPlugin/Core/Language.cs +++ b/GreenshotPlugin/Core/Language.cs @@ -476,32 +476,7 @@ namespace GreenshotPlugin.Core { } } - /// <summary> - /// Check if a resource with prefix.key exists - /// </summary> - /// <param name="prefix"></param> - /// <param name="key"></param> - /// <returns>true if available</returns> - public static bool HasKey(string prefix, Enum key) { - if (key == null) { - return false; - } - return HasKey(prefix + "." + key); - } - - /// <summary> - /// Check if a resource with key exists - /// </summary> - /// <param name="key"></param> - /// <returns>true if available</returns> - public static bool HasKey(Enum key) { - if (key == null) { - return false; - } - return HasKey(key.ToString()); - } - - /// <summary> + /// <summary> /// Check if a resource with prefix.key exists /// </summary> /// <param name="prefix"></param> diff --git a/GreenshotPlugin/Core/NetworkHelper.cs b/GreenshotPlugin/Core/NetworkHelper.cs index c07208710..9b7186d16 100644 --- a/GreenshotPlugin/Core/NetworkHelper.cs +++ b/GreenshotPlugin/Core/NetworkHelper.cs @@ -40,9 +40,8 @@ namespace GreenshotPlugin.Core { GET, POST, PUT, - DELETE, - HEAD - }; + DELETE + }; /// <summary> /// Description of NetworkHelper. @@ -61,54 +60,21 @@ namespace GreenshotPlugin.Core { } catch (Exception ex) { - Log.Warn("An error has occured while allowing self-signed certificates:", ex); + Log.Warn("An error has occurred while allowing self-signed certificates:", ex); } } - /// <summary> - /// Download a uri response as string - /// </summary> - /// <param name="uri">An Uri to specify the download location</param> - /// <returns>string with the file content</returns> - public static string GetAsString(Uri uri) { - return GetResponseAsString(CreateWebRequest(uri)); - } - /// <summary> - /// Download the FavIcon as a Bitmap - /// </summary> - /// <param name="baseUri"></param> - /// <returns>Bitmap with the FavIcon</returns> - public static Bitmap DownloadFavIcon(Uri baseUri) { - Uri url = new Uri(baseUri, new Uri("favicon.ico")); - try { - HttpWebRequest request = CreateWebRequest(url); - using HttpWebResponse response = (HttpWebResponse)request.GetResponse(); - if (request.HaveResponse) - { - using Stream responseStream = response.GetResponseStream(); - if (responseStream != null) - { - using Image image = ImageHelper.FromStream(responseStream); - return image.Height > 16 && image.Width > 16 ? new Bitmap(image, 16, 16) : new Bitmap(image); - } - } - } catch (Exception e) { - Log.Error("Problem downloading the FavIcon from: " + baseUri, e); - } - return null; - } - - /// <summary> + /// <summary> /// Download the uri into a memory stream, without catching exceptions /// </summary> /// <param name="url">Of an image</param> /// <returns>MemoryStream which is already seek-ed to 0</returns> public static MemoryStream GetAsMemoryStream(string url) { - HttpWebRequest request = CreateWebRequest(url); - using HttpWebResponse response = (HttpWebResponse)request.GetResponse(); - MemoryStream memoryStream = new MemoryStream(); - using (Stream responseStream = response.GetResponseStream()) { + var request = CreateWebRequest(url); + using var response = (HttpWebResponse)request.GetResponse(); + var memoryStream = new MemoryStream(); + using (var responseStream = response.GetResponseStream()) { responseStream?.CopyTo(memoryStream); // Make sure it can be used directly memoryStream.Seek(0, SeekOrigin.Begin); @@ -123,7 +89,7 @@ namespace GreenshotPlugin.Core { /// <returns>Bitmap</returns> public static Image DownloadImage(string url) { - StringBuilder extensions = new StringBuilder(); + var extensions = new StringBuilder(); foreach (var extension in ImageHelper.StreamConverters.Keys) { if (string.IsNullOrEmpty(extension)) @@ -147,7 +113,7 @@ namespace GreenshotPlugin.Core { { // If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead. string content; - using (StreamReader streamReader = new StreamReader(memoryStream, Encoding.UTF8, true)) + using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true)) { content = streamReader.ReadLine(); } @@ -198,7 +164,7 @@ namespace GreenshotPlugin.Core { /// <param name="method">Method to use</param> /// <returns>WebRequest</returns> public static HttpWebRequest CreateWebRequest(Uri uri, HTTPMethod method) { - HttpWebRequest webRequest = CreateWebRequest(uri); + var webRequest = CreateWebRequest(uri); webRequest.Method = method.ToString(); return webRequest; } @@ -209,7 +175,7 @@ namespace GreenshotPlugin.Core { /// <param name="uri">Uri with uri to connect to</param> /// <returns>WebRequest</returns> public static HttpWebRequest CreateWebRequest(Uri uri) { - HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); + var webRequest = (HttpWebRequest)WebRequest.Create(uri); webRequest.Proxy = Config.UseProxy ? CreateProxy(uri) : null; // Make sure the default credentials are available webRequest.Credentials = CredentialCache.DefaultCredentials; @@ -231,28 +197,32 @@ namespace GreenshotPlugin.Core { /// <returns>IWebProxy filled with all the proxy details or null if none is set/wanted</returns> public static IWebProxy CreateProxy(Uri uri) { IWebProxy proxyToUse = null; - if (Config.UseProxy) { - proxyToUse = WebRequest.DefaultWebProxy; - if (proxyToUse != null) { - proxyToUse.Credentials = CredentialCache.DefaultCredentials; - if (Log.IsDebugEnabled) { - // check the proxy for the Uri - if (!proxyToUse.IsBypassed(uri)) { - Uri proxyUri = proxyToUse.GetProxy(uri); - if (proxyUri != null) { - Log.Debug("Using proxy: " + proxyUri + " for " + uri); - } else { - Log.Debug("No proxy found!"); - } - } else { - Log.Debug("Proxy bypass for: " + uri); - } - } - } else { - Log.Debug("No proxy found!"); - } - } - return proxyToUse; + if (!Config.UseProxy) + { + return proxyToUse; + } + proxyToUse = WebRequest.DefaultWebProxy; + if (proxyToUse != null) { + proxyToUse.Credentials = CredentialCache.DefaultCredentials; + if (!Log.IsDebugEnabled) + { + return proxyToUse; + } + // check the proxy for the Uri + if (!proxyToUse.IsBypassed(uri)) { + var proxyUri = proxyToUse.GetProxy(uri); + if (proxyUri != null) { + Log.Debug("Using proxy: " + proxyUri + " for " + uri); + } else { + Log.Debug("No proxy found!"); + } + } else { + Log.Debug("Proxy bypass for: " + uri); + } + } else { + Log.Debug("No proxy found!"); + } + return proxyToUse; } /// <summary> @@ -263,7 +233,7 @@ namespace GreenshotPlugin.Core { // [Obsolete("Use System.Uri.EscapeDataString instead")] public static string UrlEncode(string text) { if (!string.IsNullOrEmpty(text)) { - // Sytem.Uri provides reliable parsing, but doesn't encode spaces. + // System.Uri provides reliable parsing, but doesn't encode spaces. return Uri.EscapeDataString(text).Replace("%20", "+"); } return null; @@ -277,7 +247,7 @@ namespace GreenshotPlugin.Core { /// <returns>escaped data string</returns> public static string EscapeDataString(string text) { if (!string.IsNullOrEmpty(text)) { - StringBuilder result = new StringBuilder(); + var result = new StringBuilder(); int currentLocation = 0; while (currentLocation < text.Length) { string process = text.Substring(currentLocation, Math.Min(16384, text.Length - currentLocation)); @@ -326,7 +296,7 @@ namespace GreenshotPlugin.Core { } /// <summary> - /// Generate the query paramters + /// Generate the query parameters /// </summary> /// <param name="queryParameters">the list of query parameters</param> /// <returns>a string with the query parameters</returns> @@ -337,7 +307,7 @@ namespace GreenshotPlugin.Core { queryParameters = new SortedDictionary<string, object>(queryParameters); - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); foreach(string key in queryParameters.Keys) { sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode($"{queryParameters[key]}")); } @@ -358,18 +328,8 @@ namespace GreenshotPlugin.Core { WriteMultipartFormData(formDataStream, boundary, postParameters); } - /// <summary> - /// Write Multipart Form Data to the HttpListenerResponse - /// </summary> - /// <param name="response">HttpListenerResponse</param> - /// <param name="postParameters">Parameters to include in the multipart form data</param> - public static void WriteMultipartFormData(HttpListenerResponse response, IDictionary<string, object> postParameters) { - string boundary = $"----------{Guid.NewGuid():N}"; - response.ContentType = "multipart/form-data; boundary=" + boundary; - WriteMultipartFormData(response.OutputStream, boundary, postParameters); - } - /// <summary> + /// <summary> /// Write Multipart Form Data to a Stream, content-type should be set before this! /// </summary> /// <param name="formDataStream">Stream to write the multipart form data to</param> @@ -519,27 +479,7 @@ namespace GreenshotPlugin.Core { } return responseData; } - - /// <summary> - /// Get LastModified for a URI - /// </summary> - /// <param name="uri">Uri</param> - /// <returns>DateTime</returns> - public static DateTime GetLastModified(Uri uri) { - try { - HttpWebRequest webRequest = CreateWebRequest(uri); - webRequest.Method = HTTPMethod.HEAD.ToString(); - using HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse(); - Log.DebugFormat("RSS feed was updated at {0}", webResponse.LastModified); - return webResponse.LastModified; - } catch (Exception wE) { - Log.WarnFormat("Problem requesting HTTP - HEAD on uri {0}", uri); - Log.Warn(wE.Message); - // Pretend it is old - return DateTime.MinValue; - } - } - } + } /// <summary> /// This interface can be used to pass binary information around, like byte[] or Image @@ -555,158 +495,7 @@ namespace GreenshotPlugin.Core { string Filename { get; set; } } - /// <summary> - /// A container to supply files to a Multi-part form data upload - /// </summary> - public class ByteContainer : IBinaryContainer { - private readonly byte[] _file; - private readonly string _contentType; - private readonly int _fileSize; - public ByteContainer(byte[] file) : this(file, null) { - } - public ByteContainer(byte[] file, string filename) : this(file, filename, null) { - } - public ByteContainer(byte[] file, string filename, string contenttype) : this(file, filename, contenttype, 0) { - } - public ByteContainer(byte[] file, string filename, string contenttype, int filesize) { - _file = file; - Filename = filename; - _contentType = contenttype; - _fileSize = filesize == 0 ? file.Length : filesize; - } - - /// <summary> - /// Create a Base64String from the byte[] - /// </summary> - /// <returns>string</returns> - public string ToBase64String(Base64FormattingOptions formattingOptions) { - return Convert.ToBase64String(_file, 0, _fileSize, formattingOptions); - } - - /// <summary> - /// Returns the initial byte-array which was supplied when creating the FileParameter - /// </summary> - /// <returns>byte[]</returns> - public byte[] ToByteArray() { - return _file; - } - - /// <summary> - /// Write Multipart Form Data directly to the HttpWebRequest response stream - /// </summary> - /// <param name="boundary">Separator</param> - /// <param name="name">name</param> - /// <param name="formDataStream">Stream to write to</param> - public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) { - // Add just the first part of this param, since we will write the file data directly to the Stream - string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {_contentType ?? "application/octet-stream"}\r\n\r\n"; - - formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header)); - - // Write the file data directly to the Stream, rather than serializing it to a string. - formDataStream.Write(_file, 0, _fileSize); - } - - /// <summary> - /// A plain "write data to stream" - /// </summary> - /// <param name="dataStream">Stream to write to</param> - public void WriteToStream(Stream dataStream) { - // Write the file data directly to the Stream, rather than serializing it to a string. - dataStream.Write(_file, 0, _fileSize); - } - - /// <summary> - /// Upload the file to the webrequest - /// </summary> - /// <param name="webRequest"></param> - public void Upload(HttpWebRequest webRequest) { - webRequest.ContentType = _contentType; - webRequest.ContentLength = _fileSize; - using var requestStream = webRequest.GetRequestStream(); - WriteToStream(requestStream); - } - - public string ContentType => _contentType; - public string Filename { get; set; } - } - - /// <summary> - /// A container to supply images to a Multi-part form data upload - /// </summary> - public class BitmapContainer : IBinaryContainer { - private readonly Bitmap _bitmap; - private readonly SurfaceOutputSettings _outputSettings; - - public BitmapContainer(Bitmap bitmap, SurfaceOutputSettings outputSettings, string filename) { - _bitmap = bitmap; - _outputSettings = outputSettings; - Filename = filename; - } - - /// <summary> - /// Create a Base64String from the image by saving it to a memory stream and converting it. - /// Should be avoided if possible, as this uses a lot of memory. - /// </summary> - /// <returns>string</returns> - public string ToBase64String(Base64FormattingOptions formattingOptions) - { - using MemoryStream stream = new MemoryStream(); - ImageOutput.SaveToStream(_bitmap, null, stream, _outputSettings); - return Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length, formattingOptions); - } - - /// <summary> - /// Create a byte[] from the image by saving it to a memory stream. - /// Should be avoided if possible, as this uses a lot of memory. - /// </summary> - /// <returns>byte[]</returns> - public byte[] ToByteArray() - { - using MemoryStream stream = new MemoryStream(); - ImageOutput.SaveToStream(_bitmap, null, stream, _outputSettings); - return stream.ToArray(); - } - - /// <summary> - /// Write Multipart Form Data directly to the HttpWebRequest response stream - /// </summary> - /// <param name="boundary">Separator</param> - /// <param name="name">Name of the thing/file</param> - /// <param name="formDataStream">Stream to write to</param> - public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) { - // Add just the first part of this param, since we will write the file data directly to the Stream - string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n"; - - formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header)); - ImageOutput.SaveToStream(_bitmap, null, formDataStream, _outputSettings); - } - - /// <summary> - /// A plain "write data to stream" - /// </summary> - /// <param name="dataStream"></param> - public void WriteToStream(Stream dataStream) { - // Write the file data directly to the Stream, rather than serializing it to a string. - ImageOutput.SaveToStream(_bitmap, null, dataStream, _outputSettings); - } - - /// <summary> - /// Upload the image to the webrequest - /// </summary> - /// <param name="webRequest"></param> - public void Upload(HttpWebRequest webRequest) { - webRequest.ContentType = "image/" + _outputSettings.Format; - using var requestStream = webRequest.GetRequestStream(); - WriteToStream(requestStream); - } - - public string ContentType => "image/" + _outputSettings.Format; - - public string Filename { get; set; } - } - - /// <summary> + /// <summary> /// A container to supply surfaces to a Multi-part form data upload /// </summary> public class SurfaceContainer : IBinaryContainer { diff --git a/GreenshotPlugin/Core/OAuthHelper.cs b/GreenshotPlugin/Core/OAuthHelper.cs index 5370697b6..555c37c7a 100644 --- a/GreenshotPlugin/Core/OAuthHelper.cs +++ b/GreenshotPlugin/Core/OAuthHelper.cs @@ -549,21 +549,7 @@ namespace GreenshotPlugin.Core { return MakeOAuthRequest(method, requestUrl, requestUrl, null, parametersToSign, additionalParameters, postData); } - /// <summary> - /// Submit a web request using oAuth. - /// </summary> - /// <param name="method">GET or POST</param> - /// <param name="requestUrl">The full url, including the querystring for the signing/request</param> - /// <param name="headers">Header values</param> - /// <param name="parametersToSign">Parameters for the request, which need to be signed</param> - /// <param name="additionalParameters">Parameters for the request, which do not need to be signed</param> - /// <param name="postData">Data to post (MemoryStream)</param> - /// <returns>The web server response.</returns> - public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary<string, string> headers, IDictionary<string, object> parametersToSign, IDictionary<string, object> additionalParameters, IBinaryContainer postData) { - return MakeOAuthRequest(method, requestUrl, requestUrl, headers, parametersToSign, additionalParameters, postData); - } - - /// <summary> + /// <summary> /// Submit a web request using oAuth. /// </summary> /// <param name="method">GET or POST</param> diff --git a/GreenshotPlugin/Core/PluginUtils.cs b/GreenshotPlugin/Core/PluginUtils.cs index 0db458a3f..51edfffa8 100644 --- a/GreenshotPlugin/Core/PluginUtils.cs +++ b/GreenshotPlugin/Core/PluginUtils.cs @@ -29,7 +29,6 @@ using System.Drawing; using System.IO; using System.Windows.Forms; using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces.Forms; namespace GreenshotPlugin.Core { /// <summary> @@ -52,7 +51,7 @@ namespace GreenshotPlugin.Core { /// <param name="e"></param> private static void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName != "IconSize") return; - List<Image> cachedImages = new List<Image>(); + var cachedImages = new List<Image>(); lock (ExeIconCache) { foreach (string key in ExeIconCache.Keys) { cachedImages.Add(ExeIconCache[key]); @@ -71,7 +70,7 @@ namespace GreenshotPlugin.Core { /// <param name="exeName">e.g. cmd.exe</param> /// <returns>Path to file</returns> public static string GetExePath(string exeName) { - using (RegistryKey key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) { + using (var key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) { if (key != null) { // "" is the default key, which should point to the requested location return (string)key.GetValue(string.Empty); @@ -147,69 +146,7 @@ namespace GreenshotPlugin.Core { return null; } - /// <summary> - /// Helper method to add a MenuItem to the File MenuItem of an ImageEditor - /// </summary> - /// <param name="imageEditor"></param> - /// <param name="image">Image to display in the menu</param> - /// <param name="text">Text to display in the menu</param> - /// <param name="tag">The TAG value</param> - /// <param name="shortcutKeys">Keys which can be used as shortcut</param> - /// <param name="handler">The onclick handler</param> - public static void AddToFileMenu(IImageEditor imageEditor, Image image, string text, object tag, Keys? shortcutKeys, EventHandler handler) { - var item = new ToolStripMenuItem - { - Image = image, - Text = text, - Tag = tag - }; - if (shortcutKeys.HasValue) { - item.ShortcutKeys = shortcutKeys.Value; - } - item.Click += handler; - AddToFileMenu(imageEditor, item); - } - - /// <summary> - /// Helper method to add a MenuItem to the File MenuItem of an ImageEditor - /// </summary> - /// <param name="imageEditor"></param> - /// <param name="item"></param> - public static void AddToFileMenu(IImageEditor imageEditor, ToolStripMenuItem item) { - ToolStripMenuItem toolStripMenuItem = imageEditor.GetFileMenuItem(); - bool added = false; - for(int i = 0; i< toolStripMenuItem.DropDownItems.Count; i++) { - if (toolStripMenuItem.DropDownItems[i].GetType() == typeof(ToolStripSeparator)) { - toolStripMenuItem.DropDownItems.Insert(i, item); - added = true; - break; - } - } - if (!added) { - toolStripMenuItem.DropDownItems.Add(item); - } - } - - /// <summary> - /// Helper method to add a MenuItem to the Plugin MenuItem of an ImageEditor - /// </summary> - /// <param name="imageEditor"></param> - /// <param name="item"></param> - public static void AddToPluginMenu(IImageEditor imageEditor, ToolStripMenuItem item) { - ToolStripMenuItem toolStripMenuItem = imageEditor.GetPluginMenuItem(); - bool added = false; - for(int i = 0; i< toolStripMenuItem.DropDownItems.Count; i++) { - if (toolStripMenuItem.DropDownItems[i].GetType() == typeof(ToolStripSeparator)) { - toolStripMenuItem.DropDownItems.Insert(i, item); - added = true; - break; - } - } - if (!added) { - toolStripMenuItem.DropDownItems.Add(item); - } - } - /// <summary> + /// <summary> /// Helper method to add a plugin MenuItem to the Greenshot context menu /// </summary> /// <param name="item">ToolStripMenuItem</param> diff --git a/GreenshotPlugin/Core/StringExtensions.cs b/GreenshotPlugin/Core/StringExtensions.cs index e7ee8cf81..cd957c543 100644 --- a/GreenshotPlugin/Core/StringExtensions.cs +++ b/GreenshotPlugin/Core/StringExtensions.cs @@ -137,19 +137,5 @@ namespace GreenshotPlugin.Core { return returnValue; } - - /// <summary> - /// Read "streamextensions" :) - /// </summary> - /// <param name="input">Stream</param> - /// <param name="output">Stream</param> - public static void CopyTo(this Stream input, Stream output) { - byte[] buffer = new byte[16 * 1024]; // Fairly arbitrary size - int bytesRead; - - while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0) { - output.Write(buffer, 0, bytesRead); - } - } - } + } } diff --git a/GreenshotPlugin/Core/WindowDetails.cs b/GreenshotPlugin/Core/WindowDetails.cs index 0410d79c7..28408051a 100644 --- a/GreenshotPlugin/Core/WindowDetails.cs +++ b/GreenshotPlugin/Core/WindowDetails.cs @@ -298,17 +298,6 @@ namespace GreenshotPlugin.Core return null; } - /// <summary> - /// Retrieve the children with matching classname - /// </summary> - public IEnumerable<WindowDetails> GetChilden(string childClassname) { - foreach (var child in Children) { - if (childClassname.Equals(child.ClassName)) { - yield return child; - } - } - } - public IntPtr ParentHandle { get { if (_parentHandle == IntPtr.Zero) { @@ -379,92 +368,6 @@ namespace GreenshotPlugin.Core return FindWindow(Children, titlePattern, classnamePattern); } - /// <summary> - /// Recurse-ing helper method for the FindPath - /// </summary> - /// <param name="classNames">List string with classNames</param> - /// <param name="index">The index in the list to look for</param> - /// <returns>WindowDetails if a match was found</returns> - private WindowDetails FindPath(IList<string> classNames, int index) { - if (index == classNames.Count - 1) { - foreach (var foundWindow in FindChildren(null, classNames[index])) - { - return foundWindow; - } - } else { - foreach(var foundWindow in FindChildren(null, classNames[index])) - { - var resultWindow = foundWindow.FindPath(classNames, index+1); - if (resultWindow != null) - { - return resultWindow; - } - } - } - return null; - } - - /// <summary> - /// This method will find the child window according to a path of classNames. - /// Usually used for finding a certain "content" window like for the IE Browser - /// </summary> - /// <param name="classNames">List of string with classname "path"</param> - /// <param name="allowSkip">true allows the search to skip a classname of the path</param> - /// <returns>WindowDetails if found</returns> - public WindowDetails FindPath(IList<string> classNames, bool allowSkip) { - int index = 0; - var resultWindow = FindPath(classNames, index++); - if (resultWindow == null && allowSkip) { - while(resultWindow == null && index < classNames.Count) { - resultWindow = FindPath(classNames, index); - } - } - return resultWindow; - } - - /// <summary> - /// Deep scan for a certain classname pattern - /// </summary> - /// <param name="windowDetails">Window to scan into</param> - /// <param name="classnamePattern">Classname regexp pattern</param> - /// <returns>The first WindowDetails found</returns> - public static WindowDetails DeepScan(WindowDetails windowDetails, Regex classnamePattern) { - if (classnamePattern.IsMatch(windowDetails.ClassName)) { - return windowDetails; - } - // First loop through this level - foreach(var child in windowDetails.Children) { - if (classnamePattern.IsMatch(child.ClassName)) { - return child; - } - } - // Go into all children - foreach(var child in windowDetails.Children) { - var deepWindow = DeepScan(child, classnamePattern); - if (deepWindow != null) { - return deepWindow; - } - } - return null; - } - - /// <summary> - /// GetWindow - /// </summary> - /// <param name="gwCommand">The GetWindowCommand to use</param> - /// <returns>null if nothing found, otherwise the WindowDetails instance of the "child"</returns> - public WindowDetails GetWindow(GetWindowCommand gwCommand) { - var tmphWnd = User32.GetWindow(Handle, gwCommand); - if (IntPtr.Zero == tmphWnd) { - return null; - } - var windowDetails = new WindowDetails(tmphWnd) - { - _parent = this - }; - return windowDetails; - } - /// <summary> /// Gets the window's handle /// </summary> @@ -512,7 +415,7 @@ namespace GreenshotPlugin.Core } /// <summary> - /// Gets/Sets whether the window is maximised or not. + /// Gets/Sets whether the window is maximized or not. /// </summary> public bool Maximised { get { @@ -541,13 +444,6 @@ namespace GreenshotPlugin.Core } } - /// <summary> - /// This doesn't work as good as is should, but does move the App out of the way... - /// </summary> - public void HideApp() { - User32.ShowWindow(Handle, ShowWindowCommand.Hide); - } - /// <summary> /// Returns if this window is cloaked /// </summary> @@ -627,13 +523,6 @@ namespace GreenshotPlugin.Core } } - /// <summary> - /// Make sure the next call of a cached value is guaranteed the real value - /// </summary> - public void Reset() { - _previousWindowRectangle = Rectangle.Empty; - } - private Rectangle _previousWindowRectangle = Rectangle.Empty; private long _lastWindowRectangleRetrieveTime; private const long CacheTime = TimeSpan.TicksPerSecond * 2; @@ -1354,24 +1243,6 @@ namespace GreenshotPlugin.Core return null; } - /// <summary> - /// Check if this window is Greenshot - /// </summary> - public bool IsGreenshot { - get { - try { - if (!IsMetroApp) - { - using Process thisWindowProcess = Process; - return "Greenshot".Equals(thisWindowProcess.MainModule.FileVersionInfo.ProductName); - } - } catch (Exception ex) { - Log.Warn(ex); - } - return false; - } - } - /// <summary> /// Gets the Desktop window /// </summary> diff --git a/GreenshotPlugin/Core/WindowsEnumerator.cs b/GreenshotPlugin/Core/WindowsEnumerator.cs index 3bc1095a5..9025cd7b8 100644 --- a/GreenshotPlugin/Core/WindowsEnumerator.cs +++ b/GreenshotPlugin/Core/WindowsEnumerator.cs @@ -34,25 +34,7 @@ namespace GreenshotPlugin.Core { /// </summary> public IList<WindowDetails> Items { get; private set; } - /// <summary> - /// Gets all top level windows on the system. - /// </summary> - public WindowsEnumerator GetWindows() { - GetWindows(IntPtr.Zero, null); - return this; - } - - /// <summary> - /// Gets all child windows of the specified window - /// </summary> - /// <param name="parent">Window Handle to get children for</param> - public WindowsEnumerator GetWindows(WindowDetails parent) - { - GetWindows(parent?.Handle ?? IntPtr.Zero, null); - return this; - } - - /// <summary> + /// <summary> /// Gets all child windows of the specified window /// </summary> /// <param name="hWndParent">Window Handle to get children for</param> @@ -69,7 +51,7 @@ namespace GreenshotPlugin.Core { parentText = title.ToString(); } - List<WindowDetails> windows = new List<WindowDetails>(); + var windows = new List<WindowDetails>(); foreach (var window in Items) { if (hasParent) { window.Text = parentText; diff --git a/GreenshotPlugin/Core/WindowsVersion.cs b/GreenshotPlugin/Core/WindowsVersion.cs index cd263d518..703fcd206 100644 --- a/GreenshotPlugin/Core/WindowsVersion.cs +++ b/GreenshotPlugin/Core/WindowsVersion.cs @@ -15,51 +15,18 @@ namespace GreenshotPlugin.Core /// </summary> public static Version WinVersion { get; } = Environment.OSVersion.Version; - public static double WinVersionTotal = WinVersion.Major + (double)WinVersion.Minor / 10; /// <summary> /// Test if the current OS is Windows 10 /// </summary> /// <returns>true if we are running on Windows 10</returns> public static bool IsWindows10 { get; } = WinVersion.Major == 10; - /// <summary> - /// Test if the current OS is before Windows 10 - /// </summary> - /// <returns>true if we are running on Windows before 10</returns> - public static bool IsBeforeWindows10 { get; } = WinVersion.Major < 10; - /// <summary> /// Test if the current OS is Windows 10 or later /// </summary> /// <returns>true if we are running on Windows 10 or later</returns> public static bool IsWindows10OrLater { get; } = WinVersion.Major >= 10; - /// <summary> - /// Test if the current OS is Windows 7 or later - /// </summary> - /// <returns>true if we are running on Windows 7 or later</returns> - public static bool IsWindows7OrLater { get; } = WinVersion.Major == 6 && WinVersion.Minor >= 1 || WinVersion.Major > 6; - - public static bool IsWindows7OrLower { get; } = WinVersionTotal <= 6.1; - - /// <summary> - /// Test if the current OS is Windows 8.0 - /// </summary> - /// <returns>true if we are running on Windows 8.0</returns> - public static bool IsWindows8 { get; } = WinVersion.Major == 6 && WinVersion.Minor == 2; - - /// <summary> - /// Test if the current OS is Windows 8(.1) - /// </summary> - /// <returns>true if we are running on Windows 8(.1)</returns> - public static bool IsWindows81 { get; } = WinVersion.Major == 6 && WinVersion.Minor == 3; - - /// <summary> - /// Test if the current OS is Windows 8.0 or 8.1 - /// </summary> - /// <returns>true if we are running on Windows 8.1 or 8.0</returns> - public static bool IsWindows8X { get; } = IsWindows8 || IsWindows81; - /// <summary> /// Test if the current OS is Windows 8.1 or later /// </summary> @@ -72,36 +39,12 @@ namespace GreenshotPlugin.Core /// <returns>true if we are running on Windows 8 or later</returns> public static bool IsWindows8OrLater { get; } = WinVersion.Major == 6 && WinVersion.Minor >= 2 || WinVersion.Major > 6; - /// <summary> - /// Test if the current OS is Windows Vista - /// </summary> - /// <returns>true if we are running on Windows Vista or later</returns> - public static bool IsWindowsVista { get; } = WinVersion.Major >= 6 && WinVersion.Minor == 0; - /// <summary> /// Test if the current OS is Windows Vista or later /// </summary> /// <returns>true if we are running on Windows Vista or later</returns> public static bool IsWindowsVistaOrLater { get; } = WinVersion.Major >= 6; - /// <summary> - /// Test if the current OS is from before Windows Vista (e.g. Windows XP) - /// </summary> - /// <returns>true if we are running on Windows from before Vista</returns> - public static bool IsWindowsBeforeVista { get; } = WinVersion.Major < 6; - - /// <summary> - /// Test if the current OS is Windows XP - /// </summary> - /// <returns>true if we are running on Windows XP or later</returns> - public static bool IsWindowsXp { get; } = WinVersion.Major == 5 && WinVersion.Minor >= 1; - - /// <summary> - /// Test if the current OS is Windows XP or later - /// </summary> - /// <returns>true if we are running on Windows XP or later</returns> - public static bool IsWindowsXpOrLater { get; } = WinVersion.Major >= 5 || WinVersion.Major == 5 && WinVersion.Minor >= 1; - /// <summary> /// Returns the windows build number /// </summary> diff --git a/GreenshotPlugin/FileDescriptorReader.cs b/GreenshotPlugin/FileDescriptorReader.cs new file mode 100644 index 000000000..7fb7069c0 --- /dev/null +++ b/GreenshotPlugin/FileDescriptorReader.cs @@ -0,0 +1,192 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using System.Text; +using GreenshotPlugin.UnmanagedHelpers.Structs; + +namespace GreenshotPlugin.Interop +{ + + /// <summary> + /// Specifies which fields are valid in a FileDescriptor Structure + /// </summary> + [Flags] + internal enum FileDescriptorFlags : uint + { + ClsId = 0x00000001, + SizePoint = 0x00000002, + Attributes = 0x00000004, + CreateTime = 0x00000008, + AccessTime = 0x00000010, + WritesTime = 0x00000020, + FileSize = 0x00000040, + ProgressUI = 0x00004000, + LinkUI = 0x00008000, + Unicode = 0x80000000, + } + + internal static class FileDescriptorReader + { + internal sealed class FileDescriptor + { + public FileDescriptorFlags Flags { get; set; } + public Guid ClassId { get; set; } + public SIZE Size { get; set; } + public POINT Point { get; set; } + public FileAttributes FileAttributes { get; set; } + public DateTime CreationTime { get; set; } + public DateTime LastAccessTime { get; set; } + public DateTime LastWriteTime { get; set; } + public Int64 FileSize { get; set; } + public string FileName { get; set; } + + public FileDescriptor(BinaryReader reader) + { + //Flags + Flags = (FileDescriptorFlags) reader.ReadUInt32(); + //ClassID + ClassId = new Guid(reader.ReadBytes(16)); + //Size + Size = new SIZE(reader.ReadInt32(), reader.ReadInt32()); + //Point + Point = new POINT(reader.ReadInt32(), reader.ReadInt32()); + //FileAttributes + FileAttributes = (FileAttributes) reader.ReadUInt32(); + //CreationTime + CreationTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64()); + //LastAccessTime + LastAccessTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64()); + //LastWriteTime + LastWriteTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64()); + //FileSize + FileSize = reader.ReadInt64(); + //FileName + byte[] nameBytes = reader.ReadBytes(520); + int i = 0; + while (i < nameBytes.Length) + { + if (nameBytes[i] == 0 && nameBytes[i + 1] == 0) + break; + i++; + i++; + } + + FileName = Encoding.Unicode.GetString(nameBytes, 0, i); + } + } + + public static IEnumerable<FileDescriptor> Read(Stream fileDescriptorStream) + { + if (fileDescriptorStream == null) + { + yield break; + } + + var reader = new BinaryReader(fileDescriptorStream); + var count = reader.ReadUInt32(); + while (count > 0) + { + var descriptor = new FileDescriptor(reader); + + yield return descriptor; + + count--; + } + } + + public static IEnumerable<string> ReadFileNames(Stream fileDescriptorStream) + { + if (fileDescriptorStream == null) + { + yield break; + } + var reader = new BinaryReader(fileDescriptorStream); + var count = reader.ReadUInt32(); + while (count > 0) + { + FileDescriptor descriptor = new FileDescriptor(reader); + + yield return descriptor.FileName; + + count--; + } + } + + internal static MemoryStream GetFileContents(System.Windows.Forms.IDataObject dataObject, int index) + { + //cast the default IDataObject to a com IDataObject + var comDataObject = (IDataObject)dataObject; + + var format = System.Windows.DataFormats.GetDataFormat("FileContents"); + if (format == null) + { + return null; + } + + //create STGMEDIUM to output request results into + var medium = new STGMEDIUM(); + + unchecked + { + var formatetc = new FORMATETC + { + cfFormat = (short)format.Id, + dwAspect = DVASPECT.DVASPECT_CONTENT, + lindex = index, + tymed = TYMED.TYMED_ISTREAM | TYMED.TYMED_HGLOBAL + }; + + //using the com IDataObject interface get the data using the defined FORMATETC + comDataObject.GetData(ref formatetc, out medium); + } + + return medium.tymed switch + { + TYMED.TYMED_ISTREAM => GetIStream(medium), + _ => null + }; + } + + private static MemoryStream GetIStream(STGMEDIUM medium) + { + //marshal the returned pointer to a IStream object + IStream iStream = (IStream)Marshal.GetObjectForIUnknown(medium.unionmember); + Marshal.Release(medium.unionmember); + + //get the STATSTG of the IStream to determine how many bytes are in it + var iStreamStat = new System.Runtime.InteropServices.ComTypes.STATSTG(); + iStream.Stat(out iStreamStat, 0); + int iStreamSize = (int)iStreamStat.cbSize; + + //read the data from the IStream into a managed byte array + byte[] iStreamContent = new byte[iStreamSize]; + iStream.Read(iStreamContent, iStreamContent.Length, IntPtr.Zero); + + //wrapped the managed byte array into a memory stream + return new MemoryStream(iStreamContent); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/GreenshotPlugin/GreenshotPlugin.csproj index 29371bcfd..db8b82b57 100644 --- a/GreenshotPlugin/GreenshotPlugin.csproj +++ b/GreenshotPlugin/GreenshotPlugin.csproj @@ -14,6 +14,7 @@ <ItemGroup> <PackageReference Include="Dapplo.HttpExtensions.JsonNet" Version="1.0.8" /> + <PackageReference Include="HtmlAgilityPack" Version="1.11.31" /> <PackageReference Include="log4net" version="2.0.12" /> <PackageReference Include="Svg" Version="3.2.3" /> <Reference Include="Accessibility" /> diff --git a/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs b/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs index c67303ffb..df0f779d5 100644 --- a/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs +++ b/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs @@ -31,26 +31,9 @@ namespace GreenshotPlugin.Interfaces.Drawing /// </summary> public interface IFieldHolder { - event FieldChangedEventHandler FieldChanged; - - void AddField(IField field); - void RemoveField(IField field); IList<IField> GetFields(); IField GetField(IFieldType fieldType); bool HasField(IFieldType fieldType); - void SetFieldValue(IFieldType fieldType, object value); - } - - /// <summary> - /// Extended fieldHolder which has fieldHolder children. - /// Implementations should pass field values to and from - /// their children. - /// AbstractFieldHolderWithChildren is the basic implementation. - /// </summary> - public interface IFieldHolderWithChildren : IFieldHolder - { - void AddChild(IFieldHolder fieldHolder); - void RemoveChild(IFieldHolder fieldHolder); } } diff --git a/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs b/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs index bd42b9aca..c613823fa 100644 --- a/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs +++ b/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs @@ -27,14 +27,7 @@ namespace GreenshotPlugin.Interfaces.Forms { /// The IImageEditor is the Interface that the Greenshot ImageEditor has to implement /// </summary> public interface IImageEditor { - /// <summary> - /// Return the IWin32Window, this way Plugins have access to the HWND handles wich can be used with Win32 API calls. - /// </summary> - IWin32Window WindowHandle { - get; - } - - /// <summary> + /// <summary> /// Get the current Image from the Editor for Exporting (save/upload etc) /// This is actually a wrapper which calls Surface.GetImageForExport(). /// Don't forget to call image.Dispose() when finished!!! diff --git a/GreenshotPlugin/Interfaces/ICaptureElement.cs b/GreenshotPlugin/Interfaces/ICaptureElement.cs deleted file mode 100644 index fc84c1536..000000000 --- a/GreenshotPlugin/Interfaces/ICaptureElement.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Collections.Generic; -using System.Drawing; - -namespace GreenshotPlugin.Interfaces -{ - public interface ICaptureElement { - List<ICaptureElement> Children { - get; - set; - } - Rectangle Bounds { - get; - set; - } - string Name { - get; - set; - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Interop/COMWrapper.cs b/GreenshotPlugin/Interop/COMWrapper.cs index f31392124..c2bcbccf0 100644 --- a/GreenshotPlugin/Interop/COMWrapper.cs +++ b/GreenshotPlugin/Interop/COMWrapper.cs @@ -188,125 +188,7 @@ namespace GreenshotPlugin.Interop { return default; } - /// <summary> - /// Gets or creates a COM object and returns the transparent proxy which intercepts all calls to the object - /// The ComProgId can be a normal ComProgId or a GUID prefixed with "clsid:" - /// </summary> - /// <typeparam name="T">Interface which defines the method and properties to intercept</typeparam> - /// <returns>Transparent proxy to the real proxy for the object</returns> - /// <remarks>T must be an interface decorated with the <see cref="ComProgIdAttribute"/>attribute.</remarks> - public static T GetOrCreateInstance<T>() { - Type type = typeof(T); - if (null == type) { - throw new ArgumentNullException(nameof(T)); - } - if (!type.IsInterface) { - throw new ArgumentException("The specified type must be an interface.", nameof(T)); - } - - var progIdAttribute = ComProgIdAttribute.GetAttribute(type); - if (string.IsNullOrEmpty(progIdAttribute?.Value)) { - throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T)); - } - - object comObject = null; - Type comType = null; - string progId = progIdAttribute.Value; - Guid guid = Guid.Empty; - - // Convert from clsid to Prog ID, if needed - if (progId.StartsWith("clsid:")) { - guid = new Guid(progId.Substring(6)); - int result = ProgIDFromCLSID(ref guid, out progId); - if (result != 0) { - // Restore progId, as it's overwritten - progId = progIdAttribute.Value; - try { - GetActiveObject(ref guid, IntPtr.Zero, out comObject); - } catch (Exception) { - Log.WarnFormat("Error {0} getting instance for class id {1}", result, progIdAttribute.Value); - } - if (comObject == null) { - Log.WarnFormat("Error {0} getting progId {1}", result, progIdAttribute.Value); - } - } else { - Log.InfoFormat("Mapped {0} to progId {1}", progIdAttribute.Value, progId); - } - } - - if (comObject == null) { - if (!progId.StartsWith("clsid:")) { - try { - comObject = Marshal.GetActiveObject(progId); - } catch (COMException comE) { - if (comE.ErrorCode == MK_E_UNAVAILABLE) { - Log.DebugFormat("No current instance of {0} object available.", progId); - } else if (comE.ErrorCode == CO_E_CLASSSTRING) { - Log.WarnFormat("Unknown progId {0} (application not installed)", progId); - return default; - } else { - Log.Warn("Error getting active object for " + progId, comE); - } - } catch (Exception e) { - Log.Warn("Error getting active object for " + progId, e); - } - } - } - - // Did we get the current instance? If not, try to create a new - if (comObject == null) { - try { - comType = Type.GetTypeFromProgID(progId, true); - } catch (Exception ex) { - if (Guid.Empty != guid) { - comType = Type.GetTypeFromCLSID(guid); - } else { - Log.Warn("Error type for " + progId, ex); - } - } - - if (comType != null) { - try { - comObject = Activator.CreateInstance(comType); - if (comObject != null) { - Log.DebugFormat("Created new instance of {0} object.", progId); - } - } catch (Exception e) { - Log.Warn("Error creating object for " + progId, e); - } - } - } - if (comObject != null) { - if (comObject is IDispatch) { - COMWrapper wrapper = new COMWrapper(comObject, type, progIdAttribute.Value); - return (T)wrapper.GetTransparentProxy(); - } else { - return (T)comObject; - } - } - return default; - } - - /// <summary> - /// Wrap a com object as COMWrapper - /// </summary> - /// <typeparam name="T">Interface which defines the method and properties to intercept</typeparam> - /// <param name="comObject">An object to intercept</param> - /// <returns>Transparent proxy to the real proxy for the object</returns> - public static T Wrap<T>(object comObject) { - Type type = typeof (T); - if (null == comObject) { - throw new ArgumentNullException(nameof(comObject)); - } - if (null == type) { - throw new ArgumentNullException(nameof(T)); - } - - COMWrapper wrapper = new COMWrapper(comObject, type, type.FullName); - return (T)wrapper.GetTransparentProxy(); - } - - /// <summary> + /// <summary> /// Wrap an object and return the transparent proxy which intercepts all calls to the object /// </summary> /// <param name="comObject">An object to intercept</param> diff --git a/GreenshotPlugin/UnmanagedHelpers/DWM.cs b/GreenshotPlugin/UnmanagedHelpers/DWM.cs index bc17f3ab2..b95a766ba 100644 --- a/GreenshotPlugin/UnmanagedHelpers/DWM.cs +++ b/GreenshotPlugin/UnmanagedHelpers/DWM.cs @@ -33,8 +33,6 @@ namespace GreenshotPlugin.UnmanagedHelpers { /// Desktop Window Manager helper code /// </summary> public static class DWM { - public static readonly uint DWM_EC_DISABLECOMPOSITION = 0; - public static readonly uint DWM_EC_ENABLECOMPOSITION = 1; // DWM [DllImport("dwmapi", SetLastError = true)] @@ -53,19 +51,8 @@ namespace GreenshotPlugin.UnmanagedHelpers { public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT lpRect, int size); [DllImport("dwmapi", SetLastError = true)] public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool pvAttribute, int cbAttribute); - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmEnableBlurBehindWindow(IntPtr hWnd, ref DWM_BLURBEHIND blurBehind); - [DllImport("dwmapi", SetLastError = true)] - public static extern uint DwmEnableComposition(uint uCompositionAction); - public static void EnableComposition() { - DwmEnableComposition(DWM_EC_ENABLECOMPOSITION); - } - public static void DisableComposition() { - DwmEnableComposition(DWM_EC_DISABLECOMPOSITION); - } - - // Key to ColorizationColor for DWM + // Key to ColorizationColor for DWM private const string COLORIZATION_COLOR_KEY = @"SOFTWARE\Microsoft\Windows\DWM"; /// <summary> diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs index 23c1d0b6f..ee54635c5 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs @@ -1,4 +1,25 @@ -using System.Diagnostics.CodeAnalysis; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums { diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs index e58bde613..04490cd17 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs @@ -26,21 +26,7 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum DWMWINDOWATTRIBUTE : uint { - DWMWA_NCRENDERING_ENABLED = 1, - DWMWA_NCRENDERING_POLICY, - DWMWA_TRANSITIONS_FORCEDISABLED, - DWMWA_ALLOW_NCPAINT, - DWMWA_CAPTION_BUTTON_BOUNDS, - DWMWA_NONCLIENT_RTL_LAYOUT, - DWMWA_FORCE_ICONIC_REPRESENTATION, - DWMWA_FLIP3D_POLICY, DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista - DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7 - DWMWA_DISALLOW_PEEK, // Since Windows 7 - DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7 - DWMWA_CLOAK, // Since Windows 8 DWMWA_CLOAKED, // Since Windows 8 - DWMWA_FREEZE_REPRESENTATION, // Since Windows 8 - DWMWA_LAST } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BB.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BB.cs deleted file mode 100644 index 1541e9143..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BB.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DWM_BB { - Enable = 1, - BlurRegion = 2, - TransitionMaximized = 4 - } -} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BLURBEHIND.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BLURBEHIND.cs deleted file mode 100644 index 29180d445..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_BLURBEHIND.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [StructLayout(LayoutKind.Sequential)] - public struct DWM_BLURBEHIND { - public DWM_BB dwFlags; - public bool fEnable; - public IntPtr hRgnBlur; - public bool fTransitionOnMaximized; - } -} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs index abd70937b..a52871fa4 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs index 7e40cf277..cc9b04573 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs @@ -1,4 +1,25 @@ -using System.Diagnostics.CodeAnalysis; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums { diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs index 61d890354..641b1e012 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs @@ -1,4 +1,25 @@ -using System.Diagnostics.CodeAnalysis; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums { diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs index a8897d5bc..3a32bf814 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/GetWindowCommand.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/GetWindowCommand.cs index 51ce444ca..64f1dd041 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/GetWindowCommand.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/GetWindowCommand.cs @@ -1,4 +1,25 @@ -using System.Diagnostics.CodeAnalysis; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums { diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs index 79623ec8e..4b1c80e90 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs index fd07afb1d..142c58ee9 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs @@ -1,4 +1,25 @@ -using System.Diagnostics.CodeAnalysis; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums { diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SYSCOLOR.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/SYSCOLOR.cs deleted file mode 100644 index 7d6802081..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/SYSCOLOR.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SYSCOLOR - { - SCROLLBAR = 0, - BACKGROUND = 1, - DESKTOP = 1, - ACTIVECAPTION = 2, - INACTIVECAPTION = 3, - MENU = 4, - WINDOW = 5, - WINDOWFRAME = 6, - MENUTEXT = 7, - WINDOWTEXT = 8, - CAPTIONTEXT = 9, - ACTIVEBORDER = 10, - INACTIVEBORDER = 11, - APPWORKSPACE = 12, - HIGHLIGHT = 13, - HIGHLIGHTTEXT = 14, - BTNFACE = 15, - THREEDFACE = 15, - BTNSHADOW = 16, - THREEDSHADOW = 16, - GRAYTEXT = 17, - BTNTEXT = 18, - INACTIVECAPTIONTEXT = 19, - BTNHIGHLIGHT = 20, - TREEDHIGHLIGHT = 20, - THREEDHILIGHT = 20, - BTNHILIGHT = 20, - THREEDDKSHADOW = 21, - THREEDLIGHT = 22, - INFOTEXT = 23, - INFOBK = 24 - } -} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ScrollBarDirection.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ScrollBarDirection.cs deleted file mode 100644 index 3a76ae2ae..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ScrollBarDirection.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ScrollBarDirection - { - SB_HORZ = 0, - SB_VERT = 1, - SB_CTL = 2, - SB_BOTH = 3 - } -} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ScrollInfoMask.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ScrollInfoMask.cs deleted file mode 100644 index e7b0d32b2..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ScrollInfoMask.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ScrollInfoMask { - SIF_RANGE = 0x1, - SIF_PAGE = 0x2, - SIF_POS = 0x4, - SIF_DISABLENOSCROLL = 0x8, - SIF_TRACKPOS = 0x10, - SIF_ALL = SIF_RANGE + SIF_PAGE + SIF_POS + SIF_TRACKPOS - } -} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ScrollbarCommand.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ScrollbarCommand.cs deleted file mode 100644 index 66e1392f2..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ScrollbarCommand.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ScrollbarCommand - { - SB_LINEUP = 0, // Scrolls one line up. - SB_LINEDOWN = 1, // Scrolls one line down. - SB_PAGEUP = 2, // Scrolls one page up. - SB_PAGEDOWN = 3, // Scrolls one page down. - SB_THUMBPOSITION = 4, // The user has dragged the scroll box (thumb) and released the mouse button. The high-order word indicates the position of the scroll box at the end of the drag operation. - SB_THUMBTRACK = 5, // The user is dragging the scroll box. This message is sent repeatedly until the user releases the mouse button. The high-order word indicates the position that the scroll box has been dragged to. - SB_TOP = 6, // Scrolls to the upper left. - SB_BOTTOM = 7, // Scrolls to the lower right. - SB_ENDSCROLL = 8 // Ends scroll. - } -} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs index 0b9cc24ca..df1b55a8d 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs index 0c69e7ea3..7962650d3 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs @@ -1,4 +1,25 @@ -using System.Diagnostics.CodeAnalysis; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums { diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs index 67c961381..b61a82395 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SystemMetric.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/SystemMetric.cs deleted file mode 100644 index 371cf90a3..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/SystemMetric.cs +++ /dev/null @@ -1,392 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// <summary> - /// Flags used with the Windows API (User32.dll):GetSystemMetrics(SystemMetric smIndex) - /// - /// This Enum and declaration signature was written by Gabriel T. Sharp - /// ai_productions@verizon.net or osirisgothra@hotmail.com - /// Obtained on pinvoke.net, please contribute your code to support the wiki! - /// </summary> - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SystemMetric - { - /// <summary> - /// Width of the screen of the primary display monitor, in pixels. This is the same values obtained by calling GetDeviceCaps as follows: GetDeviceCaps( hdcPrimaryMonitor, HORZRES). - /// </summary> - SM_CXSCREEN=0, - /// <summary> - /// Height of the screen of the primary display monitor, in pixels. This is the same values obtained by calling GetDeviceCaps as follows: GetDeviceCaps( hdcPrimaryMonitor, VERTRES). - /// </summary> - SM_CYSCREEN=1, - /// <summary> - /// Width of a horizontal scroll bar, in pixels. - /// </summary> - SM_CYVSCROLL=2, - /// <summary> - /// Height of a horizontal scroll bar, in pixels. - /// </summary> - SM_CXVSCROLL=3, - /// <summary> - /// Height of a caption area, in pixels. - /// </summary> - SM_CYCAPTION=4, - /// <summary> - /// Width of a window border, in pixels. This is equivalent to the SM_CXEDGE value for windows with the 3-D look. - /// </summary> - SM_CXBORDER=5, - /// <summary> - /// Height of a window border, in pixels. This is equivalent to the SM_CYEDGE value for windows with the 3-D look. - /// </summary> - SM_CYBORDER=6, - /// <summary> - /// Thickness of the frame around the perimeter of a window that has a caption but is not sizable, in pixels. SM_CXFIXEDFRAME is the height of the horizontal border and SM_CYFIXEDFRAME is the width of the vertical border. - /// </summary> - SM_CXDLGFRAME=7, - /// <summary> - /// Thickness of the frame around the perimeter of a window that has a caption but is not sizable, in pixels. SM_CXFIXEDFRAME is the height of the horizontal border and SM_CYFIXEDFRAME is the width of the vertical border. - /// </summary> - SM_CYDLGFRAME=8, - /// <summary> - /// Height of the thumb box in a vertical scroll bar, in pixels - /// </summary> - SM_CYVTHUMB=9, - /// <summary> - /// Width of the thumb box in a horizontal scroll bar, in pixels. - /// </summary> - SM_CXHTHUMB=10, - /// <summary> - /// Default width of an icon, in pixels. The LoadIcon function can load only icons with the dimensions specified by SM_CXICON and SM_CYICON - /// </summary> - SM_CXICON=11, - /// <summary> - /// Default height of an icon, in pixels. The LoadIcon function can load only icons with the dimensions SM_CXICON and SM_CYICON. - /// </summary> - SM_CYICON=12, - /// <summary> - /// Width of a cursor, in pixels. The system cannot create cursors of other sizes. - /// </summary> - SM_CXCURSOR=13, - /// <summary> - /// Height of a cursor, in pixels. The system cannot create cursors of other sizes. - /// </summary> - SM_CYCURSOR=14, - /// <summary> - /// Height of a single-line menu bar, in pixels. - /// </summary> - SM_CYMENU=15, - /// <summary> - /// Width of the client area for a full-screen window on the primary display monitor, in pixels. To get the coordinates of the portion of the screen not obscured by the system taskbar or by application desktop toolbars, call the SystemParametersInfo function with the SPI_GETWORKAREA value. - /// </summary> - SM_CXFULLSCREEN=16, - /// <summary> - /// Height of the client area for a full-screen window on the primary display monitor, in pixels. To get the coordinates of the portion of the screen not obscured by the system taskbar or by application desktop toolbars, call the SystemParametersInfo function with the SPI_GETWORKAREA value. - /// </summary> - SM_CYFULLSCREEN=17, - /// <summary> - /// For double byte character set versions of the system, this is the height of the Kanji window at the bottom of the screen, in pixels - /// </summary> - SM_CYKANJIWINDOW=18, - /// <summary> - /// Nonzero if a mouse with a wheel is installed; zero otherwise - /// </summary> - SM_MOUSEWHEELPRESENT=75, - /// <summary> - /// Height of the arrow bitmap on a vertical scroll bar, in pixels. - /// </summary> - SM_CYHSCROLL=20, - /// <summary> - /// Width of the arrow bitmap on a horizontal scroll bar, in pixels. - /// </summary> - SM_CXHSCROLL=21, - /// <summary> - /// Nonzero if the debug version of User.exe is installed; zero otherwise. - /// </summary> - SM_DEBUG=22, - /// <summary> - /// Nonzero if the left and right mouse buttons are reversed; zero otherwise. - /// </summary> - SM_SWAPBUTTON=23, - /// <summary> - /// Reserved for future use - /// </summary> - SM_RESERVED1=24, - /// <summary> - /// Reserved for future use - /// </summary> - SM_RESERVED2=25, - /// <summary> - /// Reserved for future use - /// </summary> - SM_RESERVED3=26, - /// <summary> - /// Reserved for future use - /// </summary> - SM_RESERVED4=27, - /// <summary> - /// Minimum width of a window, in pixels. - /// </summary> - SM_CXMIN=28, - /// <summary> - /// Minimum height of a window, in pixels. - /// </summary> - SM_CYMIN=29, - /// <summary> - /// Width of a button in a window's caption or title bar, in pixels. - /// </summary> - SM_CXSIZE=30, - /// <summary> - /// Height of a button in a window's caption or title bar, in pixels. - /// </summary> - SM_CYSIZE=31, - /// <summary> - /// Thickness of the sizing border around the perimeter of a window that can be resized, in pixels. SM_CXSIZEFRAME is the width of the horizontal border, and SM_CYSIZEFRAME is the height of the vertical border. - /// </summary> - SM_CXFRAME=32, - /// <summary> - /// Thickness of the sizing border around the perimeter of a window that can be resized, in pixels. SM_CXSIZEFRAME is the width of the horizontal border, and SM_CYSIZEFRAME is the height of the vertical border. - /// </summary> - SM_CYFRAME=33, - /// <summary> - /// Minimum tracking width of a window, in pixels. The user cannot drag the window frame to a size smaller than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message. - /// </summary> - SM_CXMINTRACK=34, - /// <summary> - /// Minimum tracking height of a window, in pixels. The user cannot drag the window frame to a size smaller than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message - /// </summary> - SM_CYMINTRACK=35, - /// <summary> - /// Width of the rectangle around the location of a first click in a double-click sequence, in pixels. The second click must occur within the rectangle defined by SM_CXDOUBLECLK and SM_CYDOUBLECLK for the system to consider the two clicks a double-click - /// </summary> - SM_CXDOUBLECLK=36, - /// <summary> - /// Height of the rectangle around the location of a first click in a double-click sequence, in pixels. The second click must occur within the rectangle defined by SM_CXDOUBLECLK and SM_CYDOUBLECLK for the system to consider the two clicks a double-click. (The two clicks must also occur within a specified time.) - /// </summary> - SM_CYDOUBLECLK=37, - /// <summary> - /// Width of a grid cell for items in large icon view, in pixels. Each item fits into a rectangle of size SM_CXICONSPACING by SM_CYICONSPACING when arranged. This value is always greater than or equal to SM_CXICON - /// </summary> - SM_CXICONSPACING=38, - /// <summary> - /// Height of a grid cell for items in large icon view, in pixels. Each item fits into a rectangle of size SM_CXICONSPACING by SM_CYICONSPACING when arranged. This value is always greater than or equal to SM_CYICON. - /// </summary> - SM_CYICONSPACING=39, - /// <summary> - /// Nonzero if drop-down menus are right-aligned with the corresponding menu-bar item; zero if the menus are left-aligned. - /// </summary> - SM_MENUDROPALIGNMENT=40, - /// <summary> - /// Nonzero if the Microsoft Windows for Pen computing extensions are installed; zero otherwise. - /// </summary> - SM_PENWINDOWS=41, - /// <summary> - /// Nonzero if User32.dll supports DBCS; zero otherwise. (WinMe/95/98): Unicode - /// </summary> - SM_DBCSENABLED=42, - /// <summary> - /// Number of buttons on mouse, or zero if no mouse is installed. - /// </summary> - SM_CMOUSEBUTTONS=43, - /// <summary> - /// Identical Values Changed After Windows NT 4.0 - /// </summary> - SM_CXFIXEDFRAME=SM_CXDLGFRAME, - /// <summary> - /// Identical Values Changed After Windows NT 4.0 - /// </summary> - SM_CYFIXEDFRAME=SM_CYDLGFRAME, - /// <summary> - /// Identical Values Changed After Windows NT 4.0 - /// </summary> - SM_CXSIZEFRAME=SM_CXFRAME, - /// <summary> - /// Identical Values Changed After Windows NT 4.0 - /// </summary> - SM_CYSIZEFRAME=SM_CYFRAME, - /// <summary> - /// Nonzero if security is present; zero otherwise. - /// </summary> - SM_SECURE=44, - /// <summary> - /// Width of a 3-D border, in pixels. This is the 3-D counterpart of SM_CXBORDER - /// </summary> - SM_CXEDGE=45, - /// <summary> - /// Height of a 3-D border, in pixels. This is the 3-D counterpart of SM_CYBORDER - /// </summary> - SM_CYEDGE=46, - /// <summary> - /// Width of a grid cell for a minimized window, in pixels. Each minimized window fits into a rectangle this size when arranged. This value is always greater than or equal to SM_CXMINIMIZED. - /// </summary> - SM_CXMINSPACING=47, - /// <summary> - /// Height of a grid cell for a minimized window, in pixels. Each minimized window fits into a rectangle this size when arranged. This value is always greater than or equal to SM_CYMINIMIZED. - /// </summary> - SM_CYMINSPACING=48, - /// <summary> - /// Recommended width of a small icon, in pixels. Small icons typically appear in window captions and in small icon view - /// </summary> - SM_CXSMICON=49, - /// <summary> - /// Recommended height of a small icon, in pixels. Small icons typically appear in window captions and in small icon view. - /// </summary> - SM_CYSMICON=50, - /// <summary> - /// Height of a small caption, in pixels - /// </summary> - SM_CYSMCAPTION=51, - /// <summary> - /// Width of small caption buttons, in pixels. - /// </summary> - SM_CXSMSIZE=52, - /// <summary> - /// Height of small caption buttons, in pixels. - /// </summary> - SM_CYSMSIZE=53, - /// <summary> - /// Width of menu bar buttons, such as the child window close button used in the multiple document interface, in pixels. - /// </summary> - SM_CXMENUSIZE=54, - /// <summary> - /// Height of menu bar buttons, such as the child window close button used in the multiple document interface, in pixels. - /// </summary> - SM_CYMENUSIZE=55, - /// <summary> - /// Flags specifying how the system arranged minimized windows - /// </summary> - SM_ARRANGE=56, - /// <summary> - /// Width of a minimized window, in pixels. - /// </summary> - SM_CXMINIMIZED=57, - /// <summary> - /// Height of a minimized window, in pixels. - /// </summary> - SM_CYMINIMIZED=58, - /// <summary> - /// Default maximum width of a window that has a caption and sizing borders, in pixels. This metric refers to the entire desktop. The user cannot drag the window frame to a size larger than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message. - /// </summary> - SM_CXMAXTRACK=59, - /// <summary> - /// Default maximum height of a window that has a caption and sizing borders, in pixels. This metric refers to the entire desktop. The user cannot drag the window frame to a size larger than these dimensions. A window can override this value by processing the WM_GETMINMAXINFO message. - /// </summary> - SM_CYMAXTRACK=60, - /// <summary> - /// Default width, in pixels, of a maximized top-level window on the primary display monitor. - /// </summary> - SM_CXMAXIMIZED=61, - /// <summary> - /// Default height, in pixels, of a maximized top-level window on the primary display monitor. - /// </summary> - SM_CYMAXIMIZED=62, - /// <summary> - /// Least significant bit is set if a network is present; otherwise, it is cleared. The other bits are reserved for future use - /// </summary> - SM_NETWORK=63, - /// <summary> - /// Value that specifies how the system was started: 0-normal, 1-failsafe, 2-failsafe /w net - /// </summary> - SM_CLEANBOOT=67, - /// <summary> - /// Width of a rectangle centered on a drag point to allow for limited movement of the mouse pointer before a drag operation begins, in pixels. - /// </summary> - SM_CXDRAG=68, - /// <summary> - /// Height of a rectangle centered on a drag point to allow for limited movement of the mouse pointer before a drag operation begins. This value is in pixels. It allows the user to click and release the mouse button easily without unintentionally starting a drag operation. - /// </summary> - SM_CYDRAG=69, - /// <summary> - /// Nonzero if the user requires an application to present information visually in situations where it would otherwise present the information only in audible form; zero otherwise. - /// </summary> - SM_SHOWSOUNDS=70, - /// <summary> - /// Width of the default menu check-mark bitmap, in pixels. - /// </summary> - SM_CXMENUCHECK=71, - /// <summary> - /// Height of the default menu check-mark bitmap, in pixels. - /// </summary> - SM_CYMENUCHECK=72, - /// <summary> - /// Nonzero if the computer has a low-end (slow) processor; zero otherwise - /// </summary> - SM_SLOWMACHINE=73, - /// <summary> - /// Nonzero if the system is enabled for Hebrew and Arabic languages, zero if not. - /// </summary> - SM_MIDEASTENABLED=74, - /// <summary> - /// Nonzero if a mouse is installed; zero otherwise. This value is rarely zero, because of support for virtual mice and because some systems detect the presence of the port instead of the presence of a mouse. - /// </summary> - SM_MOUSEPRESENT=19, - /// <summary> - /// Windows 2000 (v5.0+) Coordinate of the top of the virtual screen - /// </summary> - SM_XVIRTUALSCREEN=76, - /// <summary> - /// Windows 2000 (v5.0+) Coordinate of the left of the virtual screen - /// </summary> - SM_YVIRTUALSCREEN=77, - /// <summary> - /// Windows 2000 (v5.0+) Width of the virtual screen - /// </summary> - SM_CXVIRTUALSCREEN=78, - /// <summary> - /// Windows 2000 (v5.0+) Height of the virtual screen - /// </summary> - SM_CYVIRTUALSCREEN=79, - /// <summary> - /// Number of display monitors on the desktop - /// </summary> - SM_CMONITORS=80, - /// <summary> - /// Windows XP (v5.1+) Nonzero if all the display monitors have the same color format, zero otherwise. Note that two displays can have the same bit depth, but different color formats. For example, the red, green, and blue pixels can be encoded with different numbers of bits, or those bits can be located in different places in a pixel's color value. - /// </summary> - SM_SAMEDISPLAYFORMAT=81, - /// <summary> - /// Windows XP (v5.1+) Nonzero if Input Method Manager/Input Method Editor features are enabled; zero otherwise - /// </summary> - SM_IMMENABLED=82, - /// <summary> - /// Windows XP (v5.1+) Width of the left and right edges of the focus rectangle drawn by DrawFocusRect. This value is in pixels. - /// </summary> - SM_CXFOCUSBORDER=83, - /// <summary> - /// Windows XP (v5.1+) Height of the top and bottom edges of the focus rectangle drawn by DrawFocusRect. This value is in pixels. - /// </summary> - SM_CYFOCUSBORDER=84, - /// <summary> - /// Nonzero if the current operating system is the Windows XP Tablet PC edition, zero if not. - /// </summary> - SM_TABLETPC=86, - /// <summary> - /// Nonzero if the current operating system is the Windows XP, Media Center Edition, zero if not. - /// </summary> - SM_MEDIACENTER=87, - /// <summary> - /// Metrics Other - /// </summary> - SM_CMETRICS_OTHER=76, - /// <summary> - /// Metrics Windows 2000 - /// </summary> - SM_CMETRICS_2000=83, - /// <summary> - /// Metrics Windows NT - /// </summary> - SM_CMETRICS_NT=88, - /// <summary> - /// Windows XP (v5.1+) This system metric is used in a Terminal Services environment. If the calling process is associated with a Terminal Services client session, the return value is nonzero. If the calling process is associated with the Terminal Server console session, the return value is zero. The console session is not necessarily the physical console - see WTSGetActiveConsoleSessionId for more information. - /// </summary> - SM_REMOTESESSION=0x1000, - /// <summary> - /// Windows XP (v5.1+) Nonzero if the current session is shutting down; zero otherwise - /// </summary> - SM_SHUTTINGDOWN=0x2000, - /// <summary> - /// Windows XP (v5.1+) This system metric is used in a Terminal Services environment. Its value is nonzero if the current session is remotely controlled; zero otherwise - /// </summary> - SM_REMOTECONTROL=0x2001 - } -} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs index 14256ad13..fc5495304 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs @@ -1,17 +1,30 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; namespace GreenshotPlugin.UnmanagedHelpers.Enums { [Flags] public enum ThreadAccess : int { - TERMINATE = (0x0001), SUSPEND_RESUME = (0x0002), - GET_CONTEXT = (0x0008), - SET_CONTEXT = (0x0010), - SET_INFORMATION = (0x0020), - QUERY_INFORMATION = (0x0040), - SET_THREAD_TOKEN = (0x0080), - IMPERSONATE = (0x0100), - DIRECT_IMPERSONATION = (0x0200) } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs index cf5d43850..987bc5654 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs @@ -1,4 +1,25 @@ -namespace GreenshotPlugin.UnmanagedHelpers.Enums +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace GreenshotPlugin.UnmanagedHelpers.Enums { /// <summary> /// A Win32 error code. diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs index 882796a8b..a170af781 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs @@ -1,4 +1,24 @@ -using System.Diagnostics.CodeAnalysis; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums { @@ -8,47 +28,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums /// </summary> [SuppressMessage("ReSharper", "InconsistentNaming")] public enum WinEvent : uint { - EVENT_OBJECT_ACCELERATORCHANGE = 32786, EVENT_OBJECT_CREATE = 32768, EVENT_OBJECT_DESTROY = 32769, - EVENT_OBJECT_DEFACTIONCHANGE = 32785, - EVENT_OBJECT_DESCRIPTIONCHANGE = 32781, - EVENT_OBJECT_FOCUS = 32773, - EVENT_OBJECT_HELPCHANGE = 32784, - EVENT_OBJECT_SHOW = 32770, - EVENT_OBJECT_HIDE = 32771, - EVENT_OBJECT_LOCATIONCHANGE = 32779, EVENT_OBJECT_NAMECHANGE = 32780, - EVENT_OBJECT_PARENTCHANGE = 32783, - EVENT_OBJECT_REORDER = 32772, - EVENT_OBJECT_SELECTION = 32774, - EVENT_OBJECT_SELECTIONADD = 32775, - EVENT_OBJECT_SELECTIONREMOVE = 32776, - EVENT_OBJECT_SELECTIONWITHIN = 32777, - EVENT_OBJECT_STATECHANGE = 32778, - EVENT_OBJECT_VALUECHANGE = 32782, - EVENT_SYSTEM_ALERT = 2, - EVENT_SYSTEM_CAPTUREEND = 9, - EVENT_SYSTEM_CAPTURESTART = 8, - EVENT_SYSTEM_CONTEXTHELPEND = 13, - EVENT_SYSTEM_CONTEXTHELPSTART = 12, - EVENT_SYSTEM_DIALOGEND = 17, - EVENT_SYSTEM_DIALOGSTART = 16, - EVENT_SYSTEM_DRAGDROPEND = 15, - EVENT_SYSTEM_DRAGDROPSTART = 14, - EVENT_SYSTEM_FOREGROUND = 3, - EVENT_SYSTEM_MENUEND = 5, - EVENT_SYSTEM_MENUPOPUPEND = 7, - EVENT_SYSTEM_MENUPOPUPSTART = 6, - EVENT_SYSTEM_MENUSTART = 4, - EVENT_SYSTEM_MINIMIZEEND = 23, - EVENT_SYSTEM_MINIMIZESTART = 22, - EVENT_SYSTEM_MOVESIZEEND = 11, - EVENT_SYSTEM_MOVESIZESTART = 10, - EVENT_SYSTEM_SCROLLINGEND = 19, - EVENT_SYSTEM_SCROLLINGSTART = 18, - EVENT_SYSTEM_SOUND = 1, - EVENT_SYSTEM_SWITCHEND = 21, - EVENT_SYSTEM_SWITCHSTART = 20 } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs index 55622990e..010950e51 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs @@ -1,4 +1,25 @@ -using System.Diagnostics.CodeAnalysis; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums { diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs index 7c39ab336..ecdc92fe4 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs index 2ae2d248d..d343962ae 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums @@ -7,20 +28,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum WindowPos { - SWP_ASYNCWINDOWPOS = 0x4000, // If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. - SWP_DEFERERASE = 0x2000, // Prevents generation of the WM_SYNCPAINT message. - SWP_DRAWFRAME = 0x0020, // Draws a frame (defined in the window's class description) around the window. - SWP_FRAMECHANGED = 0x0020, //Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE is sent only when the window's size is being changed. - SWP_HIDEWINDOW = 0x0080, // Hides the window. SWP_NOACTIVATE = 0x0010, // Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). - SWP_NOCOPYBITS = 0x0100, // Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client area are saved and copied back into the client area after the window is sized or repositioned. SWP_NOMOVE = 0x0002, //Retains the current position (ignores X and Y parameters). - SWP_NOOWNERZORDER = 0x0200, //Does not change the owner window's position in the Z order. - SWP_NOREDRAW = 0x0008, //Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any parts of the window and parent window that need redrawing. - SWP_NOREPOSITION = 0x0200, // Same as the SWP_NOOWNERZORDER flag. - SWP_NOSENDCHANGING = 0x0400, //Prevents the window from receiving the WM_WINDOWPOSCHANGING message. SWP_NOSIZE = 0x0001, // Retains the current size (ignores the cx and cy parameters). - SWP_NOZORDER = 0x0004, // Retains the current Z order (ignores the hWndInsertAfter parameter). - SWP_SHOWWINDOW = 0x0040 //Displays the window. } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs index c7c4d98b4..8029ccd30 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs @@ -9,934 +9,18 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum WindowsMessages : uint { - WM_NULL = 0x0000, - /// <summary> - /// Sent when an application requests that a window be created by calling the CreateWindowEx or CreateWindow function. (The message is sent before the function returns.) The window procedure of the new window receives this message after the window is created, but before the window becomes visible. - /// A window receives this message through its WindowProc function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms632619.aspx">WM_CREATE message</a> - /// </summary> - WM_CREATE = 0x0001, - - /// <summary> - /// Sent when a window is being destroyed. It is sent to the window procedure of the window being destroyed after the window is removed from the screen. - /// This message is sent first to the window being destroyed and then to the child windows (if any) as they are destroyed. During the processing of the message, it can be assumed that all child windows still exist. - /// A window receives this message through its WindowProc function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms632620(v=vs.85).aspx">WM_DESTROY message</a> - /// </summary> - WM_DESTROY = 0x0002, - WM_MOVE = 0x0003, - WM_SIZE = 0x0005, - WM_ACTIVATE = 0x0006, - WM_SETFOCUS = 0x0007, - WM_KILLFOCUS = 0x0008, - - /// <summary> - /// Sent when an application changes the enabled state of a window. It is sent to the window whose enabled state is changing. This message is sent before the EnableWindow function returns, but after the enabled state (WS_DISABLED style bit) of the window has changed. - /// A window receives this message through its WindowProc function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms632621(v=vs.85).aspx">WM_ENABLE message</a> - /// </summary> - WM_ENABLE = 0x000A, - WM_SETREDRAW = 0x000B, - WM_SETTEXT = 0x000C, - WM_GETTEXT = 0x000D, - WM_GETTEXTLENGTH = 0x000E, - - /// <summary> - /// The WM_PAINT message is sent when the system or another application makes a request to paint a portion of an application's window. The message is sent when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage function when the application obtains a WM_PAINT message by using the GetMessage or PeekMessage function. - /// A window receives this message through its WindowProc function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd145213(v=vs.85).aspx">WM_PAINT message</a> - /// </summary> - WM_PAINT = 0x000F, - - WM_CLOSE = 0x0010, - WM_QUERYENDSESSION = 0x0011, - WM_QUIT = 0x0012, - WM_QUERYOPEN = 0x0013, - WM_ERASEBKGND = 0x0014, - WM_SYSCOLORCHANGE = 0x0015, - WM_ENDSESSION = 0x0016, - WM_SHOWWINDOW = 0x0018, - - /// <summary> - /// An application sends the WM_WININICHANGE message to all top-level windows after making a change to the WIN.INI file. The SystemParametersInfo function sends this message after an application uses the function to change a setting in WIN.INI. - /// Note: The WM_WININICHANGE message is provided only for compatibility with earlier versions of the system. Applications should use the WM_SETTINGCHANGE message. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms725499(v=vs.85).aspx">M_WININICHANGE message</a> - /// </summary> - WM_WININICHANGE = 0x001A, - - /// <summary> - /// A message that is sent to all top-level windows when the SystemParametersInfo function changes a system-wide setting or when policy settings have changed. - /// Applications should send WM_SETTINGCHANGE to all top-level windows when they make changes to system parameters. (This message cannot be sent directly to a window.) To send the WM_SETTINGCHANGE message to all top-level windows, use the SendMessageTimeout function with the hWnd parameter set to HWND_BROADCAST. - /// A window receives this message through its WindowProc function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms725497(v=vs.85).aspx">WM_SETTINGCHANGE message</a> - /// </summary> - WM_SETTINGCHANGE = WM_WININICHANGE, - WM_DEVMODECHANGE = 0x001B, - WM_ACTIVATEAPP = 0x001C, - WM_FONTCHANGE = 0x001D, - WM_TIMECHANGE = 0x001E, - WM_CANCELMODE = 0x001F, - WM_SETCURSOR = 0x0020, WM_MOUSEACTIVATE = 0x0021, - WM_CHILDACTIVATE = 0x0022, - WM_QUEUESYNC = 0x0023, - WM_GETMINMAXINFO = 0x0024, - WM_PAINTICON = 0x0026, - WM_ICONERASEBKGND = 0x0027, - WM_NEXTDLGCTL = 0x0028, - WM_SPOOLERSTATUS = 0x002A, - WM_DRAWITEM = 0x002B, - WM_MEASUREITEM = 0x002C, - WM_DELETEITEM = 0x002D, - WM_VKEYTOITEM = 0x002E, - WM_CHARTOITEM = 0x002F, - WM_SETFONT = 0x0030, - WM_GETFONT = 0x0031, - WM_SETHOTKEY = 0x0032, - WM_GETHOTKEY = 0x0033, - WM_QUERYDRAGICON = 0x0037, - WM_COMPAREITEM = 0x0039, - WM_GETOBJECT = 0x003D, - WM_COMPACTING = 0x0041, - WM_COMMNOTIFY = 0x0044, - WM_WINDOWPOSCHANGING = 0x0046, - WM_WINDOWPOSCHANGED = 0x0047, - WM_POWER = 0x0048, - WM_COPYDATA = 0x004A, - WM_CANCELJOURNAL = 0x004B, - WM_NOTIFY = 0x004E, WM_INPUTLANGCHANGEREQUEST = 0x0050, WM_INPUTLANGCHANGE = 0x0051, - WM_TCARD = 0x0052, - WM_HELP = 0x0053, - WM_USERCHANGED = 0x0054, - WM_NOTIFYFORMAT = 0x0055, - - /// <summary> - /// Notifies a window that the user clicked the right mouse button (right-clicked) in the window. - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/menurc/wm-contextmenu">WM_CONTEXTMENU message</a> - /// - /// In case of a notify icon: - /// If a user selects a notify icon's shortcut menu with the keyboard, the Shell now sends the associated application a WM_CONTEXTMENU message. Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages. - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a> - /// </summary> - WM_CONTEXTMENU = 0x007B, - - WM_STYLECHANGING = 0x007C, - WM_STYLECHANGED = 0x007D, - - /// <summary> - /// See - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd145210.aspx">WM_DISPLAYCHANGE message</a> - /// </summary> - WM_DISPLAYCHANGE = 0x007E, + /// <summary> /// Sent to a window to retrieve a handle to the large or small icon associated with a window. The system displays the large icon in the ALT+TAB dialog, and the small icon in the window caption. /// A window receives this message through its WindowProc function. /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms632625.aspx">WM_GETICON message</a> /// </summary> WM_GETICON = 0x007F, - WM_SETICON = 0x0080, - - /// <summary> - /// Sent prior to the WM_CREATE message when a window is first created. - /// A window receives this message through its WindowProc function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms632635.aspx">WM_NCCREATE message</a> - /// </summary> - WM_NCCREATE = 0x0081, - - WM_NCDESTROY = 0x0082, - WM_NCCALCSIZE = 0x0083, - WM_NCHITTEST = 0x0084, - WM_NCPAINT = 0x0085, - WM_NCACTIVATE = 0x0086, - WM_GETDLGCODE = 0x0087, - WM_SYNCPAINT = 0x0088, - WM_SYNCTASK = 0x0089, - WM_KLUDGEMINRECT = 0x008b, - WM_LPKDRAWSWITCHWND = 0x008c, - - WM_UAHDESTROYWINDOW = 0x0090, - WM_UAHDRAWMENU = 0x0091, - WM_UAHDRAWMENUITEM = 0x0092, - WM_UAHINITMENU = 0x0093, - WM_UAHMEASUREMENUITEM = 0x0094, - WM_UAHNCPAINTMENUPOPUP = 0x0095, - WM_UAHUPDATE = 0x0096, - - /// <summary> - /// Posted to a window when the cursor is moved within the nonclient area of the window. - /// This message is posted to the window that contains the cursor. - /// If a window has captured the mouse, this message is not posted. - /// </summary> - WM_NCMOUSEMOVE = 0x00A0, - /// <summary> - /// Posted when the user presses the left mouse button while the cursor is within the nonclient area of a window. - /// This message is posted to the window that contains the cursor. - /// If a window has captured the mouse, this message is not posted. - /// </summary> - WM_NCLBUTTONDOWN = 0x00A1, - /// <summary> - /// Posted when the user releases the left mouse button while the cursor is within the nonclient area of a window. - /// This message is posted to the window that contains the cursor. - /// If a window has captured the mouse, this message is not posted. - /// </summary> - WM_NCLBUTTONUP = 0x00A2, - WM_NCLBUTTONDBLCLK = 0x00A3, - /// <summary> - /// Posted when the user presses the right mouse button while the cursor is within the nonclient area of a window. - /// This message is posted to the window that contains the cursor. - /// If a window has captured the mouse, this message is not posted. - /// </summary> - WM_NCRBUTTONDOWN = 0x00A4, - /// <summary> - /// Posted when the user releases the right mouse button while the cursor is within the nonclient area of a window. - /// This message is posted to the window that contains the cursor. - /// If a window has captured the mouse, this message is not posted. - /// </summary> - WM_NCRBUTTONUP = 0x00A5, - WM_NCRBUTTONDBLCLK = 0x00A6, - /// <summary> - /// Posted when the user presses the middle mouse button while the cursor is within the nonclient area of a window. - /// This message is posted to the window that contains the cursor. - /// If a window has captured the mouse, this message is not posted. - /// </summary> - WM_NCMBUTTONDOWN = 0x00A7, - /// <summary> - /// Posted when the user releases the middle mouse button while the cursor is within the nonclient area of a window. - /// This message is posted to the window that contains the cursor. - /// If a window has captured the mouse, this message is not posted. - /// </summary> - WM_NCMBUTTONUP = 0x00A8, - WM_NCMBUTTONDBLCLK = 0x00A9, - WM_NCXBUTTONDOWN = 0x00AB, - WM_NCXBUTTONUP = 0x00AC, - WM_NCXBUTTONDBLCLK = 0x00AD, - WM_NCUAHDRAWCAPTION = 0x00ae, - WM_NCUAHDRAWFRAME = 0x00af, - - // Edit controls - EM_GETSEL = 0x00b0, - EM_SETSEL = 0x00b1, - EM_GETRECT = 0x00b2, - EM_SETRECT = 0x00b3, - EM_SETRECTNP = 0x00b4, - EM_SCROLL = 0x00b5, - EM_LINESCROLL = 0x00b6, - EM_SCROLLCARET = 0x00b7, - EM_GETMODIFY = 0x00b8, - EM_SETMODIFY = 0x00b9, - EM_GETLINECOUNT = 0x00ba, - EM_LINEINDEX = 0x00bb, - EM_SETHANDLE = 0x00bc, - EM_GETHANDLE = 0x00bd, - EM_GETTHUMB = 0x00be, - EM_LINELENGTH = 0x00c1, - EM_REPLACESEL = 0x00c2, - EM_SETFONT = 0x00c3, - EM_GETLINE = 0x00c4, - EM_LIMITTEXT = 0x00c5, - EM_CANUNDO = 0x00c6, - EM_UNDO = 0x00c7, - EM_FMTLINES = 0x00c8, - EM_LINEFROMCHAR = 0x00c9, - EM_SETWORDBREAK = 0x00ca, - EM_SETTABSTOPS = 0x00cb, - EM_SETPASSWORDCHAR = 0x00cc, - EM_EMPTYUNDOBUFFER = 0x00cd, - EM_GETFIRSTVISIBLELINE = 0x00ce, - EM_SETREADONLY = 0x00cf, - EM_SETWORDBREAKPROC = 0x00d0, - EM_GETWORDBREAKPROC = 0x00d1, - EM_GETPASSWORDCHAR = 0x00d2, - EM_SETMARGINS = 0x00d3, - EM_GETMARGINS = 0x00d4, - EM_GETLIMITTEXT = 0x00d5, - EM_POSFROMCHAR = 0x00d6, - EM_CHARFROMPOS = 0x00d7, - EM_SETIMESTATUS = 0x00d8, - EM_GETIMESTATUS = 0x00d9, - EM_MSGMAX = 0x00da, - - /// <summary> - /// Sent to the window that registered to receive raw input. - /// A window receives this message through its WindowProc function. - /// wParam - This parameter can be one of the following values: - /// GIDC_ARRIVAL (1) : A new device has been added to the system. - /// GIDC_REMOVAL (2) : A device has been removed from the system. - /// lParam - The handle to the raw input device. Call GetRawInputDeviceInfo to get more information regarding the device. - /// Return value - /// If an application processes this message, it should return zero. - /// </summary> - WM_INPUT_DEVICE_CHANGE = 0x00FE, - - /// <summary> - /// Sent to the window that is getting raw input. - /// Raw input is available only when the application calls RegisterRawInputDevices with valid device specifications - /// A window receives this message through its WindowProc function. - /// wParam - The input code. This parameter can be one of the following values: - /// RIM_INPUT (0) - Input occurred while the application was in the foreground. The application must call DefWindowProc so the system can perform cleanup. - /// RIM_INPUTSINK (1) - Input occurred while the application was not in the foreground. The application must call DefWindowProc so the system can perform the cleanup. - /// lParam - A handle to the RAWINPUT structure that contains the raw input from the device. - /// Return value - /// If an application processes this message, it should return zero. - /// </summary> - WM_INPUT = 0x00FF, - - WM_KEYFIRST = 0x0100, - WM_KEYDOWN = 0x0100, - WM_KEYUP = 0x0101, WM_CHAR = 0x0102, - WM_DEADCHAR = 0x0103, - WM_SYSKEYDOWN = 0x0104, - WM_SYSKEYUP = 0x0105, - WM_SYSCHAR = 0x0106, - WM_SYSDEADCHAR = 0x0107, - WM_UNICHAR = 0x0109, - WM_KEYLAST = 0x0109, - - WM_IME_STARTCOMPOSITION = 0x010D, - WM_IME_ENDCOMPOSITION = 0x010E, - WM_IME_COMPOSITION = 0x010F, - WM_IME_KEYLAST = 0x010F, - - WM_INITDIALOG = 0x0110, - WM_COMMAND = 0x0111, - WM_SYSCOMMAND = 0x0112, - WM_TIMER = 0x0113, - WM_HSCROLL = 0x0114, - WM_VSCROLL = 0x0115, - WM_INITMENU = 0x0116, - WM_INITMENUPOPUP = 0x0117, - WM_MENUSELECT = 0x011F, - WM_MENUCHAR = 0x0120, - WM_ENTERIDLE = 0x0121, - WM_MENURBUTTONUP = 0x0122, - WM_MENUDRAG = 0x0123, - WM_MENUGETOBJECT = 0x0124, - WM_UNINITMENUPOPUP = 0x0125, - WM_MENUCOMMAND = 0x0126, - - WM_CHANGEUISTATE = 0x0127, - WM_UPDATEUISTATE = 0x0128, - WM_QUERYUISTATE = 0x0129, - - WM_CTLCOLORMSGBOX = 0x0132, - WM_CTLCOLOREDIT = 0x0133, - WM_CTLCOLORLISTBOX = 0x0134, - WM_CTLCOLORBTN = 0x0135, - WM_CTLCOLORDLG = 0x0136, - WM_CTLCOLORSCROLLBAR = 0x0137, - WM_CTLCOLORSTATIC = 0x0138, - - // Combo Box - CB_GETEDITSEL = 0x00140, - CB_LIMITTEXT = 0x00141, - CB_SETEDITSEL = 0x00142, - CB_ADDSTRING = 0x00143, - CB_DELETESTRING = 0x00144, - CB_DIR = 0x00145, - CB_GETCOUNT = 0x00146, - CB_GETCURSEL = 0x00147, - CB_GETLBTEXT = 0x00148, - CB_GETLBTEXTLEN = 0x00149, - CB_INSERTSTRING = 0x0014a, - CB_RESETCONTENT = 0x0014b, - CB_FINDSTRING = 0x0014c, - CB_SELECTSTRING = 0x0014d, - CB_SETCURSEL = 0x0014e, - CB_SHOWDROPDOWN = 0x0014f, - CB_GETITEMDATA = 0x00150, - CB_SETITEMDATA = 0x00151, - CB_GETDROPPEDCONTROLRECT = 0x00152, - CB_SETITEMHEIGHT = 0x00153, - CB_GETITEMHEIGHT = 0x00154, - CB_SETEXTENDEDUI = 0x00155, - CB_GETEXTENDEDUI = 0x00156, - CB_GETDROPPEDSTATE = 0x00157, - CB_FINDSTRINGEXACT = 0x00158, - CB_SETLOCALE = 0x00159, - CB_GETLOCALE = 0x0015a, - CB_GETTOPINDEX = 0x0015b, - CB_SETTOPINDEX = 0x0015c, - CB_GETHORIZONTALEXTENT = 0x0015d, - CB_SETHORIZONTALEXTENT = 0x0015e, - CB_GETDROPPEDWIDTH = 0x0015f, - CB_SETDROPPEDWIDTH = 0x00160, - CB_INITSTORAGE = 0x00161, - CB_MSGMAX_OLD = 0x00162, - CB_MULTIPLEADDSTRING = 0x00163, - CB_GETCOMBOBOXINFO = 0x00164, - CB_MSGMAX = 0x00165, - - - LB_ADDSTRING = 0x00180, - LB_INSERTSTRING = 0x00181, - LB_DELETESTRING = 0x00182, - LB_SELITEMRANGEEX = 0x00183, - LB_RESETCONTENT = 0x00184, - LB_SETSEL = 0x00185, - LB_SETCURSEL = 0x00186, - LB_GETSEL = 0x00187, - LB_GETCURSEL = 0x00188, - LB_GETTEXT = 0x00189, - LB_GETTEXTLEN = 0x0018a, - LB_GETCOUNT = 0x0018b, - LB_SELECTSTRING = 0x0018c, - LB_DIR = 0x0018d, - LB_GETTOPINDEX = 0x0018e, - LB_FINDSTRING = 0x0018f, - LB_GETSELCOUNT = 0x00190, - LB_GETSELITEMS = 0x00191, - LB_SETTABSTOPS = 0x00192, - LB_GETHORIZONTALEXTENT = 0x00193, - LB_SETHORIZONTALEXTENT = 0x00194, - LB_SETCOLUMNWIDTH = 0x00195, - LB_ADDFILE = 0x00196, - LB_SETTOPINDEX = 0x00197, - LB_GETITEMRECT = 0x00198, - LB_GETITEMDATA = 0x00199, - LB_SETITEMDATA = 0x0019a, - LB_SELITEMRANGE = 0x0019b, - LB_SETANCHORINDEX = 0x0019c, - LB_GETANCHORINDEX = 0x0019d, - LB_SETCARETINDEX = 0x0019e, - LB_GETCARETINDEX = 0x0019f, - LB_SETITEMHEIGHT = 0x001a0, - LB_GETITEMHEIGHT = 0x001a1, - LB_FINDSTRINGEXACT = 0x001a2, - LBCB_CARETON = 0x001a3, - LBCB_CARETOFF = 0x001a4, - LB_SETLOCALE = 0x001a5, - LB_GETLOCALE = 0x001a6, - LB_SETCOUNT = 0x001a7, - LB_INITSTORAGE = 0x001a8, - LB_ITEMFROMPOINT = 0x001a9, - LB_INSERTSTRINGUPPER = 0x001aa, - LB_INSERTSTRINGLOWER = 0x001ab, - LB_ADDSTRINGUPPER = 0x001ac, - LB_ADDSTRINGLOWER = 0x001ad, - LBCB_STARTTRACK = 0x001ae, - LBCB_ENDTRACK = 0x001af, - LB_MSGMAX_OLD = 0x001b0, - LB_MULTIPLEADDSTRING = 0x001b1, - LB_GETLISTBOXINFO = 0x001b2, - LB_MSGMAX = 0x001b3, - - MN_FIRST = 0x01e0, - WM_GETHMENU = 0x01E1, - - /// <summary> - /// Defines the start of the mouse related messages - /// </summary> - WM_MOUSEFIRST = 0x0200, - - /// <summary> - /// Posted to a window when the cursor moves. - /// If the mouse is not captured, the message is posted to the window that contains the cursor. - /// Otherwise, the message is posted to the window that has captured the mouse. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mousemove">WM_MOUSEMOVE message</a> - /// </summary> - WM_MOUSEMOVE = 0x0200, - - /// <summary> - /// Posted when the user presses the left mouse button while the cursor is in the client area of a window. - /// If the mouse is not captured, the message is posted to the window beneath the cursor. - /// Otherwise, the message is posted to the window that has captured the mouse. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttondown">WM_LBUTTONDOWN message</a> - /// </summary> - WM_LBUTTONDOWN = 0x0201, - - /// <summary> - /// Posted when the user releases the left mouse button while the cursor is in the client area of a window. - /// If the mouse is not captured, the message is posted to the window beneath the cursor. - /// Otherwise, the message is posted to the window that has captured the mouse. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttonup">WM_LBUTTONUP message</a> - /// </summary> - WM_LBUTTONUP = 0x0202, - - /// <summary> - /// Posted when the user double-clicks the left mouse button while the cursor is in the client area of a window. - /// If the mouse is not captured, the message is posted to the window beneath the cursor. - /// Otherwise, the message is posted to the window that has captured the mouse. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttondblclk">WM_LBUTTONDBLCLK message</a> - /// </summary> - WM_LBUTTONDBLCLK = 0x0203, - - /// <summary> - /// Posted when the user presses the right mouse button while the cursor is in the client area of a window. - /// If the mouse is not captured, the message is posted to the window beneath the cursor. - /// Otherwise, the message is posted to the window that has captured the mouse. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-rbuttondown">WM_RBUTTONDOWN message</a> - /// </summary> - WM_RBUTTONDOWN = 0x0204, - - /// <summary> - /// Posted when the user releases the right mouse button while the cursor is in the client area of a window. - /// If the mouse is not captured, the message is posted to the window beneath the cursor. - /// Otherwise, the message is posted to the window that has captured the mouse. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-rbuttonup">WM_RBUTTONUP message</a> - /// </summary> - WM_RBUTTONUP = 0x0205, - - /// <summary> - /// Posted when the user double-clicks the right mouse button while the cursor is in the client area of a window. - /// If the mouse is not captured, the message is posted to the window beneath the cursor. - /// Otherwise, the message is posted to the window that has captured the mouse. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-rbuttondblclk">WM_RBUTTONDBLCLK message</a> - /// </summary> - WM_RBUTTONDBLCLK = 0x0206, - - /// <summary> - /// Posted when the user presses the middle mouse button while the cursor is in the client area of a window. - /// If the mouse is not captured, the message is posted to the window beneath the cursor. - /// Otherwise, the message is posted to the window that has captured the mouse. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mbuttondown">WM_MBUTTONDOWN message</a> - /// </summary> - WM_MBUTTONDOWN = 0x0207, - - /// <summary> - /// Posted when the user releases the middle mouse button while the cursor is in the client area of a window. - /// If the mouse is not captured, the message is posted to the window beneath the cursor. - /// Otherwise, the message is posted to the window that has captured the mouse. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mbuttonup">WM_MBUTTONUP message</a> - /// </summary> - WM_MBUTTONUP = 0x0208, - - /// <summary> - /// Posted when the user double-clicks the middle mouse button while the cursor is in the client area of a window. - /// If the mouse is not captured, the message is posted to the window beneath the cursor. - /// Otherwise, the message is posted to the window that has captured the mouse. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mbuttondblclk">WM_MBUTTONDBLCLK message</a> - /// </summary> - WM_MBUTTONDBLCLK = 0x0209, - - WM_MOUSEWHEEL = 0x020A, - WM_XBUTTONDOWN = 0x020B, - WM_XBUTTONUP = 0x020C, - WM_XBUTTONDBLCLK = 0x020D, - WM_MOUSEHWHEEL = 0x020E, - - WM_PARENTNOTIFY = 0x0210, - WM_ENTERMENULOOP = 0x0211, - WM_EXITMENULOOP = 0x0212, - - WM_NEXTMENU = 0x0213, - WM_SIZING = 0x0214, - WM_CAPTURECHANGED = 0x0215, - WM_MOVING = 0x0216, - - WM_POWERBROADCAST = 0x0218, - - /// <summary> - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/devio/wm-devicechange">WM_DEVICECHANGE message</a> - /// Notifies an application of a change to the hardware configuration of a device or the computer. - /// wParam - The event that has occurred (DeviceChangeEvent) - /// lParam - A pointer to a structure that contains event-specific data. Its format depends on the value of the wParam parameter. For more information, refer to the documentation for each event - /// - /// Return TRUE to grant the request, return BROADCAST_QUERY_DENY to deny the request. - /// </summary> - WM_DEVICECHANGE = 0x0219, - - WM_MDICREATE = 0x0220, - WM_MDIDESTROY = 0x0221, - WM_MDIACTIVATE = 0x0222, - WM_MDIRESTORE = 0x0223, - WM_MDINEXT = 0x0224, - WM_MDIMAXIMIZE = 0x0225, - WM_MDITILE = 0x0226, - WM_MDICASCADE = 0x0227, - WM_MDIICONARRANGE = 0x0228, - WM_MDIGETACTIVE = 0x0229, - - - WM_MDISETMENU = 0x0230, - WM_ENTERSIZEMOVE = 0x0231, - WM_EXITSIZEMOVE = 0x0232, - WM_DROPFILES = 0x0233, - WM_MDIREFRESHMENU = 0x0234, - - WM_IME_REPORT = 0x0280, - WM_IME_SETCONTEXT = 0x0281, - WM_IME_NOTIFY = 0x0282, - WM_IME_CONTROL = 0x0283, - WM_IME_COMPOSITIONFULL = 0x0284, - WM_IME_SELECT = 0x0285, - WM_IME_CHAR = 0x0286, - WM_IME_REQUEST = 0x0288, - WM_IME_KEYDOWN = 0x0290, - WM_IME_KEYUP = 0x0291, - - WM_NCMOUSEHOVER = 0x02A0, - WM_MOUSEHOVER = 0x02A1, - WM_NCMOUSELEAVE = 0x02A2, - WM_MOUSELEAVE = 0x02A3, - - WM_WTSSESSION_CHANGE = 0x02B1, - - WM_TABLET_FIRST = 0x02C0, - WM_POINTERDEVICEADDED = 0x02c8, - WM_POINTERDEVICEDELETED = 0x02c9, - WM_FLICK = 0x02cb, - WM_FLICKINTERNAL = 0x02cd, - WM_BRIGHTNESSCHANGED = 0x02ce, - WM_TABLET_LAST = 0x02DF, - - /// <summary> - /// Sent when the effective dots per inch (dpi) for a window has changed. The DPI is the scale factor for a window. There are multiple events that can cause the DPI to change. The following list indicates the possible causes for the change in DPI. - /// * The window is moved to a new monitor that has a different DPI. - /// * The DPI of the monitor hosting the window changes. - /// The current DPI for a window always equals the last DPI sent by WM_DPICHANGED. - /// This is the scale factor that the window should be scaling to for threads that are aware of DPI changes. - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dn312083.aspx">WM_DPICHANGED message</a> - /// </summary> - WM_DPICHANGED = 0x02E0, - - /// <summary> - /// For Per Monitor v2 top-level windows, this message is sent to all HWNDs in the child HWDN tree of the window that is undergoing a DPI change. - /// This message occurs before the top-level window receives WM_DPICHANGED, and traverses the child tree from the bottom up. - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt807678.aspx">WM_DPICHANGED_BEFOREPARENT message</a> - /// </summary> - WM_DPICHANGED_BEFOREPARENT = 0x02E2, - - /// <summary> - /// For Per Monitor v2 top-level windows, this message is sent to all HWNDs in the child HWDN tree of the window that is undergoing a DPI change. - /// This message occurs after the top-level window receives WM_DPICHANGED, and traverses the child tree from the top down. - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt807677.aspx">WM_DPICHANGED_AFTERPARENT message</a> - /// </summary> - WM_DPICHANGED_AFTERPARENT = 0x02E3, - - /// <summary> - /// This message tells the operating system that the window will be sized to dimensions other than the default. - /// This message is sent to top-level windows with a DPI_AWARENESS_CONTEXT of Per Monitor v2 before a WM_DPICHANGED message is sent, and allows the window to compute its desired size for the pending DPI change. - /// As linear DPI scaling is the default behavior, this is only useful in scenarios where the window wants to scale non-linearly. - /// If the application responds to this message, the resulting size will be the candidate rectangle send to WM_DPICHANGED. - /// Use this message to alter the size of the rect that is provided with WM_DPICHANGED. - /// - /// wParam - /// The WPARAM contains a DPI value. The scaled window size that the application would set needs to be computed as if the window were to switch to this DPI. - /// - /// lParam - /// The LPARAM is an in/out pointer to a SIZE struct. The _In_ value in the LPARAM is the pending size of the window after a user-initiated move or a call to SetWindowPos. If the window is being resized, this size is not necessarily the same as the window's current size at the time this message is received. - /// - /// The _Out_ value in the LPARAM should be written to by the application to specify the desired scaled window size corresponding to the provided DPI value in the WPARAM. - /// - /// The function returns a BOOL. Returning TRUE indicates that a new size has been computed. Returning FALSE indicates that the message will not be handled, and the default linear DPI scaling will apply to the window. - /// - /// Remarks: - /// This message is only sent to top-level windows which have a DPI awareness context of Per Monitor v2. - /// This event is necessary to facilitate graceful non-linear scaling, and ensures that the windows's position remains constant in relationship to the cursor and when moving back and forth across monitors. - /// There is no specific default handling of this message in DefWindowProc. As for all messages it does not explicitly handle, DefWindowProc will return zero for this message. As noted above, this return tells the system to use the default linear behavior. - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/mt807679.aspx">WM_GETDPISCALEDSIZE message</a> - /// </summary> - WM_GETDPISCALEDSIZE = 0x02E4, - - /// <summary> - /// An application sends a WM_CUT message to an edit control or combo box to delete (cut) the current selection, if any, in the edit control and copy the deleted text to the clipboard in CF_TEXT format. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649023.aspx">WM_CUT message</a> - /// </summary> - WM_CUT = 0x0300, - - /// <summary> - /// An application sends the WM_COPY message to an edit control or combo box to copy the current selection to the clipboard in CF_TEXT format. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649022.aspx">WM_COPY message</a> - /// </summary> - WM_COPY = 0x0301, - - /// <summary> - /// An application sends a WM_PASTE message to an edit control or combo box to copy the current content of the clipboard to the edit control at the current caret position. Data is inserted only if the clipboard contains data in CF_TEXT format. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649028.aspx">WM_PASTE message</a> - /// </summary> - WM_PASTE = 0x0302, - - /// <summary> - /// An application sends a WM_CLEAR message to an edit control or combo box to delete (clear) the current selection, if any, from the edit control. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649020.aspx">WM_CLEAR message</a> - /// </summary> - WM_CLEAR = 0x0303, - - /// <summary> - /// An application sends a WM_UNDO message to an edit control to undo the last operation. When this message is sent to an edit control, the previously deleted text is restored or the previously added text is deleted. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb761693.aspx">WM_UNDO message</a> - /// </summary> - WM_UNDO = 0x0304, - - /// <summary> - /// Sent to the clipboard owner if it has delayed rendering a specific clipboard format and if an application has requested data in that format. The clipboard owner must render data in the specified format and place it on the clipboard by calling the SetClipboardData function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649030.aspx">WM_RENDERFORMAT message</a> - /// </summary> - WM_RENDERFORMAT = 0x0305, - - /// <summary> - /// Sent to the clipboard owner before it is destroyed, if the clipboard owner has delayed rendering one or more clipboard formats. For the content of the clipboard to remain available to other applications, the clipboard owner must render data in all the formats it is capable of generating, and place the data on the clipboard by calling the SetClipboardData function. - /// A window receives this message through its WindowProc function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649029.aspx">WM_RENDERALLFORMATS message</a> - /// </summary> - WM_RENDERALLFORMATS = 0x0306, - - /// <summary> - /// Sent to the clipboard owner when a call to the EmptyClipboard function empties the clipboard. - ///A window receives this message through its WindowProc function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649024.aspx">WM_DESTROYCLIPBOARD message</a> - /// </summary> - WM_DESTROYCLIPBOARD = 0x0307, - - /// <summary> - /// Sent to the first window in the clipboard viewer chain when the content of the clipboard changes. This enables a clipboard viewer window to display the new content of the clipboard. - /// A window receives this message through its WindowProc function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649025.aspx">WM_DRAWCLIPBOARD message</a> - /// </summary> - WM_DRAWCLIPBOARD = 0x0308, - - /// <summary> - /// Sent to the clipboard owner by a clipboard viewer window when the clipboard contains data in the CF_OWNERDISPLAY format and the clipboard viewer's client area needs repainting. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649027.aspx">WM_PAINTCLIPBOARD message</a> - /// </summary> - WM_PAINTCLIPBOARD = 0x0309, - - /// <summary> - /// Sent to the clipboard owner by a clipboard viewer window when the clipboard contains data in the CF_OWNERDISPLAY format and an event occurs in the clipboard viewer's vertical scroll bar. The owner should scroll the clipboard image and update the scroll bar values. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649032.aspx">WM_VSCROLLCLIPBOARD message</a> - /// </summary> - WM_VSCROLLCLIPBOARD = 0x030A, - - /// <summary> - /// Sent to the clipboard owner by a clipboard viewer window when the clipboard contains data in the CF_OWNERDISPLAY format and the clipboard viewer's client area has changed size. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649031.aspx">WM_SIZECLIPBOARD message</a> - /// </summary> - WM_SIZECLIPBOARD = 0x030B, - - /// <summary> - /// Sent to the clipboard owner by a clipboard viewer window to request the name of a CF_OWNERDISPLAY clipboard format. - /// A window receives this message through its WindowProc function. - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649018.aspx">WM_ASKCBFORMATNAME message</a> - /// </summary> - WM_ASKCBFORMATNAME = 0x030C, - - /// <summary> - /// Sent to the first window in the clipboard viewer chain when a window is being removed from the chain. - /// A window receives this message through its WindowProc function. - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649019.aspx">WM_CHANGECBCHAIN message</a> - /// </summary> - WM_CHANGECBCHAIN = 0x030D, - - /// <summary> - /// Sent to the clipboard owner by a clipboard viewer window. This occurs when the clipboard contains data in the CF_OWNERDISPLAY format and an event occurs in the clipboard viewer's horizontal scroll bar. The owner should scroll the clipboard image and update the scroll bar values. - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649026.aspx">WM_HSCROLLCLIPBOARD message</a> - /// </summary> - WM_HSCROLLCLIPBOARD = 0x030E, - - WM_QUERYNEWPALETTE = 0x030F, - WM_PALETTEISCHANGING = 0x0310, - - - WM_PALETTECHANGED = 0x0311, - WM_HOTKEY = 0x0312, - - WM_SYSMENU = 0x313, - WM_HOOKMSG = 0x314, - WM_EXITPROCESS = 0x315, - WM_WAKETHREAD = 0x316, - - /// <summary> - /// The WM_PRINT message is sent to a window to request that it draw itself in the specified device context, most commonly in a printer device context. - ///A window receives this message through its WindowProc function. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd145216.aspx">WM_PRINT message</a> - /// </summary> - WM_PRINT = 0x0317, - - /// <summary> - /// The WM_PRINTCLIENT message is sent to a window to request that it draw its client area in the specified device context, most commonly in a printer device context. - /// Unlike WM_PRINT, WM_PRINTCLIENT is not processed by DefWindowProc. A window should process the WM_PRINTCLIENT message through an application-defined WindowProc function for it to be used properly. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd145217.aspx">WM_PRINTCLIENT message</a> - /// </summary> - WM_PRINTCLIENT = 0x0318, - - /// <summary> - /// Notifies a window that the user generated an application command event, for example, by clicking an application command button using the mouse or typing an application command key on the keyboard. - /// <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms646275.aspx">WM_APPCOMMAND message</a> - /// </summary> - WM_APPCOMMAND = 0x0319, - - WM_THEMECHANGED = 0x031A, - WM_UAHINIT = 0x031b, - WM_DESKTOPNOTIFY = 0x031c, - - /// <summary> - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms649021.aspx">WM_CLIPBOARDUPDATE message</a> - /// </summary> - WM_CLIPBOARDUPDATE = 0x031D, - - WM_DWMCOMPOSITIONCHANGED = 0x031E, - WM_DWMNCRENDERINGCHANGED = 0x031F, - WM_DWMCOLORIZATIONCOLORCHANGED = 0x0320, - WM_DWMWINDOWMAXIMIZEDCHANGE = 0x0321, - - WM_DWMEXILEFRAME = 0x0322, - WM_DWMSENDICONICTHUMBNAIL = 0x0323, - WM_MAGNIFICATION_STARTED = 0x0324, - WM_MAGNIFICATION_ENDED = 0x0325, - WM_DWMSENDICONICLIVEPREVIEWBITMAP = 0x0326, - WM_DWMTHUMBNAILSIZECHANGED = 0x0327, - WM_MAGNIFICATION_OUTPUT = 0x0328, - WM_BSDRDATA = 0x0329, - WM_DWMTRANSITIONSTATECHANGED = 0x032a, - WM_KEYBOARDCORRECTIONCALLOUT = 0x032c, - WM_KEYBOARDCORRECTIONACTION = 0x032d, - WM_UIACTION = 0x032e, - WM_ROUTED_UI_EVENT = 0x032f, - WM_MEASURECONTROL = 0x0330, - WM_GETACTIONTEXT = 0x0331, - WM_FORWARDKEYDOWN = 0x0333, - WM_FORWARDKEYUP = 0x0334, - - - WM_GETTITLEBARINFOEX = 0x033F, - WM_NOTIFYWOW = 0x0340, - WM_HANDHELDFIRST = 0x0358, - WM_HANDHELDLAST = 0x035F, - - WM_AFXFIRST = 0x0360, - WM_AFXLAST = 0x037F, - - WM_PENWINFIRST = 0x0380, - WM_PENWINLAST = 0x038F, - - /// <summary> - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd757352.aspx">MM_JOY1MOVE message</a> - /// </summary> - MM_JOY1MOVE = 0x03A0, - MM_JOY2MOVE = 0x03A1, - MM_JOY1ZMOVE = 0x03A2, - MM_JOY2ZMOVE = 0x03A3, - MM_JOY1BUTTONDOWN = 0x03B5, - MM_JOY2BUTTONDOWN = 0x03B6, - MM_JOY1BUTTONUP = 0x03B7, - MM_JOY2BUTTONUP = 0x03B8, - /// <summary> - /// See <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd757358.aspx">MM_MCINOTIFY message</a> - /// </summary> - MM_MCINOTIFY = 0x3B9, - MM_WOM_OPEN = 0x03BB, - MM_WOM_CLOSE = 0x03BC, - MM_WOM_DONE = 0x03BD, - MM_WIM_OPEN = 0x03BE, - MM_WIM_CLOSE = 0x03BF, - MM_WIM_DATA = 0x03C0, - MM_MIM_OPEN = 0x03C1, - MM_MIM_CLOSE = 0x03C2, - MM_MIM_DATA = 0x03C3, - MM_MIM_LONGDATA = 0x03C4, - MM_MIM_ERROR = 0x03C5, - MM_MIM_LONGERROR = 0x03C6, - MM_MOM_OPEN = 0x03C7, - MM_MOM_CLOSE = 0x03C8, - MM_MOM_DONE = 0x03C9, - MM_DRVM_OPEN = 0x03D0, - MM_DRVM_CLOSE = 0x03D1, - MM_DRVM_DATA = 0x03D2, - MM_DRVM_ERROR = 0x03D3, - MM_STREAM_OPEN = 0x3D4, - MM_STREAM_CLOSE = 0x3D5, - MM_STREAM_DONE = 0x3D6, - MM_STREAM_ERROR = 0x3D7, - MM_MOM_POSITIONCB = 0x03CA, - MM_MCISIGNAL = 0x03CB, - MM_MIM_MOREDATA = 0x03CC, - MM_MIXM_LINE_CHANGE = 0x03D0, - MM_MIXM_CONTROL_CHANGE = 0x03D1, - - /// <summary> - /// Used to define private messages for use by private window classes, usually of the form WM_USER+x, where x is an integer value. - /// </summary> - WM_USER = 0x0400, - - /// <summary> - /// This message is only send when using NOTIFYICON_VERSION_4, the Shell now sends the associated application an NIN_SELECT notification. - /// Send when a notify icon is activated with mouse or ENTER key. - /// Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a> - /// </summary> - NIN_SELECT = WM_USER, - - /// <summary> - /// This message is only send when using NOTIFYICON_VERSION_4, the Shell now sends the associated application an NIN_SELECT notification. - /// Send when a notify icon is activated with SPACEBAR or ENTER key. - /// Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages. - /// - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a> - /// </summary> - NIN_KEYSELECT = WM_USER + 1, - - /// <summary> - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a> - /// - /// Sent when the balloon is shown (balloons are queued). - /// </summary> - NIN_BALLOONSHOW = WM_USER + 2, - - /// <summary> - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a> - /// - /// Sent when the balloon disappears. For example, when the icon is deleted. - /// This message is not sent if the balloon is dismissed because of a timeout or if the user clicks the mouse. - /// - /// As of Windows 7, NIN_BALLOONHIDE is also sent when a notification with the NIIF_RESPECT_QUIET_TIME flag set attempts to display during quiet time (a user's first hour on a new computer). - /// In that case, the balloon is never displayed at all. - /// </summary> - NIN_BALLOONHIDE = WM_USER + 3, - - /// <summary> - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a> - /// - /// Sent when the balloon is dismissed because of a timeout. - /// </summary> - NIN_BALLOONTIMEOUT = WM_USER + 4, - - /// <summary> - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a> - /// - /// Sent when the balloon is dismissed because the user clicked the mouse. - /// </summary> - NIN_BALLOONUSERCLICK = WM_USER + 5, - - /// <summary> - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a> - /// - /// Sent when the user hovers the cursor over an icon to indicate that the richer pop-up UI should be used in place of a standard textual tooltip. - /// </summary> - NIN_POPUPOPEN = WM_USER + 6, - - /// <summary> - /// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a> - /// - /// Sent when a cursor no longer hovers over an icon to indicate that the rich pop-up UI should be closed. - /// </summary> - NIN_POPUPCLOSE = WM_USER + 7, - - /// <summary> - /// The WM_APP constant is used to distinguish between message values that are reserved for use by the system and values that can be used by an application to send messages within a private window class. - /// </summary> - WM_APP = 0x8000, - - OCM__BASE = WM_USER + 0x1C00, - WM_REFLECT = WM_USER + 0x1C00, - /// <summary> - /// From this value to - /// </summary> - WM_APPLICATION_STRING = 0xc000, - WM_RASDIALEVENT = 0xCCCD + WM_SYSCOMMAND = 0x0112 } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs index 72f863e1a..0138d9faa 100644 --- a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs @@ -218,11 +218,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { return true; } - public SafeSelectObjectHandle SelectObject(SafeHandle newHandle) { - return new SafeSelectObjectHandle(this, newHandle); - } - - public static SafeDeviceContextHandle FromGraphics(Graphics graphics) { + public static SafeDeviceContextHandle FromGraphics(Graphics graphics) { return new SafeDeviceContextHandle(graphics, graphics.GetHdc()); } } @@ -233,13 +229,11 @@ namespace GreenshotPlugin.UnmanagedHelpers { public static class GDI32 { [DllImport("gdi32", SetLastError=true)] public static extern bool BitBlt(SafeHandle hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, SafeHandle hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop); - [DllImport("gdi32", SetLastError=true)] - private static extern bool StretchBlt(SafeHandle hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, SafeHandle hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, CopyPixelOperation dwRop); - [DllImport("gdi32", SetLastError=true)] + + [DllImport("gdi32", SetLastError=true)] public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC); - [DllImport("gdi32", SetLastError=true)] - public static extern IntPtr SelectObject(SafeHandle hDC, SafeHandle hObject); - [DllImport("gdi32", SetLastError=true)] + + [DllImport("gdi32", SetLastError=true)] public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADER bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset); [DllImport("gdi32", SetLastError=true)] public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); @@ -401,26 +395,4 @@ namespace GreenshotPlugin.UnmanagedHelpers { } } } - - [StructLayout(LayoutKind.Sequential)] - public struct BITMAPINFO { - /// <summary> - /// A BITMAPINFOHEADER structure that contains information about the dimensions of color format. - /// </summary> - public BITMAPINFOHEADER bmiHeader; - - /// <summary> - /// An array of RGBQUAD. The elements of the array that make up the color table. - /// </summary> - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1, ArraySubType = UnmanagedType.Struct)] - public RGBQUAD[] bmiColors; - } - - [StructLayout(LayoutKind.Sequential)] - public struct RGBQUAD { - public byte rgbBlue; - public byte rgbGreen; - public byte rgbRed; - public byte rgbReserved; - } } diff --git a/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs b/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs index 9734806a1..101d74bbf 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs @@ -51,9 +51,8 @@ namespace GreenshotPlugin.UnmanagedHelpers { public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize); [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, uint uuchMax); - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr GetModuleHandle(string lpModuleName); - [DllImport("kernel32", SetLastError = true)] + + [DllImport("kernel32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CloseHandle(IntPtr hObject); diff --git a/GreenshotPlugin/UnmanagedHelpers/Shell32.cs b/GreenshotPlugin/UnmanagedHelpers/Shell32.cs index e1b7ba0b0..f16d46cec 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Shell32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Shell32.cs @@ -21,7 +21,6 @@ using System; using System.Drawing; using System.Runtime.InteropServices; -using System.Text; using System.IO; namespace GreenshotPlugin.UnmanagedHelpers { @@ -31,9 +30,8 @@ namespace GreenshotPlugin.UnmanagedHelpers { public static class Shell32 { [DllImport("shell32", CharSet = CharSet.Unicode)] public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons); - [DllImport("shell32", CharSet = CharSet.Unicode)] - internal static extern IntPtr ExtractAssociatedIcon(HandleRef hInst, StringBuilder iconPath, ref int index); - [DllImport("shell32", CharSet = CharSet.Unicode)] + + [DllImport("shell32", CharSet = CharSet.Unicode)] private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] @@ -53,10 +51,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon private const uint SHGFI_LARGEICON = 0x000000000; // get large icon private const uint SHGFI_SMALLICON = 0x000000001; // get small icon - private const uint SHGFI_OPENICON = 0x000000002; // get open icon private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute - - private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010; private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; /// <summary> @@ -73,21 +68,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { Small = 1 } - /// <summary> - /// Options to specify whether folders should be in the open or closed state. - /// </summary> - public enum FolderType { - /// <summary> - /// Specify open folder. - /// </summary> - Open = 0, - /// <summary> - /// Specify closed folder. - /// </summary> - Closed = 1 - } - - /// <summary> + /// <summary> /// Returns an icon for a given file extension - indicated by the name parameter. /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx /// </summary> @@ -123,73 +104,5 @@ namespace GreenshotPlugin.UnmanagedHelpers { } return null; } - - /// <summary> - /// Used to access system folder icons. - /// </summary> - /// <param name="size">Specify large or small icons.</param> - /// <param name="folderType">Specify open or closed FolderType.</param> - /// <returns>System.Drawing.Icon</returns> - public static Icon GetFolderIcon(IconSize size, FolderType folderType) { - // Need to add size check, although errors generated at present! - uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; - - if (FolderType.Open == folderType) { - flags += SHGFI_OPENICON; - } - - if (IconSize.Small == size) { - flags += SHGFI_SMALLICON; - } else { - flags += SHGFI_LARGEICON; - } - - // Get the folder icon - SHFILEINFO shfi = new SHFILEINFO(); - SHGetFileInfo(null, FILE_ATTRIBUTE_DIRECTORY, ref shfi, (uint)Marshal.SizeOf(shfi), flags); - - //Icon.FromHandle(shfi.hIcon); // Load the icon from an HICON handle - // Now clone the icon, so that it can be successfully stored in an ImageList - Icon icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone(); - - // Cleanup - User32.DestroyIcon(shfi.hIcon); - return icon; - } - - /// <summary> - /// Returns an icon representation of an image contained in the specified file. - /// This function is identical to System.Drawing.Icon.ExtractAssociatedIcon, xcept this version works. - /// See: http://stackoverflow.com/questions/1842226/how-to-get-the-associated-icon-from-a-network-share-file - /// </summary> - /// <param name="filePath">The path to the file that contains an image.</param> - /// <returns>The System.Drawing.Icon representation of the image contained in the specified file.</returns> - public static Icon ExtractAssociatedIcon(string filePath) { - int index = 0; - - Uri uri; - if (filePath == null) { - throw new ArgumentException("Null is not valid for filePath", nameof(filePath)); - } - try { - uri = new Uri(filePath); - } catch (UriFormatException) { - filePath = Path.GetFullPath(filePath); - uri = new Uri(filePath); - } - - if (uri.IsFile) { - if (File.Exists(filePath)) { - StringBuilder iconPath = new StringBuilder(1024); - iconPath.Append(filePath); - - IntPtr handle = ExtractAssociatedIcon(new HandleRef(null, IntPtr.Zero), iconPath, ref index); - if (handle != IntPtr.Zero) { - return Icon.FromHandle(handle); - } - } - } - return null; - } - } + } } diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs b/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs index 9b818288d..7f18bf9ec 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers.Structs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs b/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs index 5808f4883..ae8629b4d 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers.Structs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs b/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs index 9b78ab9a7..b94be1de4 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Drawing; using System.Runtime.InteropServices; diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs b/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs index a403cea9b..5186f072b 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Drawing; using System.Runtime.InteropServices; diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs b/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs index 5fa193343..471d0c4cb 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs @@ -1,4 +1,25 @@ -using System.Drawing; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System.Drawing; using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers.Structs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs b/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs index fec30ca08..0a6451b23 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers.Structs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs b/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs index 8f0405125..532d597a3 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers.Structs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs b/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs index f54baac86..1a7de8ebb 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; using System.Runtime.InteropServices; using GreenshotPlugin.UnmanagedHelpers.Enums; diff --git a/GreenshotPlugin/UnmanagedHelpers/User32.cs b/GreenshotPlugin/UnmanagedHelpers/User32.cs index 8ba05f48f..818e7c64d 100644 --- a/GreenshotPlugin/UnmanagedHelpers/User32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/User32.cs @@ -39,16 +39,11 @@ namespace GreenshotPlugin.UnmanagedHelpers { private static readonly ILog LOG = LogManager.GetLogger(typeof(User32)); private static bool _CanCallGetPhysicalCursorPos = true; public const int SC_RESTORE = 0xF120; - public const int SC_CLOSE = 0xF060; public const int SC_MAXIMIZE = 0xF030; public const int SC_MINIMIZE = 0xF020; - public const int PW_DEFAULT = 0x00; - public const int PW_CLIENTONLY = 0x01; - - // For MonitorFromWindow + // For MonitorFromWindow public const int MONITOR_DEFAULTTONULL = 0; - public const int MONITOR_DEFAULTTOPRIMARY = 1; public const int MONITOR_DEFAULTTONEAREST = 2; public const int CURSOR_SHOWING = 0x00000001; @@ -76,19 +71,15 @@ namespace GreenshotPlugin.UnmanagedHelpers { [DllImport("user32", SetLastError = true)] public static extern IntPtr GetParent(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - public static extern int SetParent(IntPtr hWndChild, IntPtr hWndNewParent); - [DllImport("user32", SetLastError = true)] + + [DllImport("user32", SetLastError = true)] public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowCommand uCmd); [DllImport("user32", SetLastError = true)] public static extern int ShowWindow(IntPtr hWnd, ShowWindowCommand nCmdShow); [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int cch); - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetWindowTextLength(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - public static extern uint GetSysColor(int nIndex); - [DllImport("user32", SetLastError = true)] + + [DllImport("user32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool BringWindowToTop(IntPtr hWnd); [DllImport("user32", SetLastError = true)] @@ -121,9 +112,8 @@ namespace GreenshotPlugin.UnmanagedHelpers { public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, uint nFlags); [DllImport("user32", CharSet=CharSet.Unicode, SetLastError=true)] public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam); - [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")] + + [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")] public static extern int GetWindowLong(IntPtr hWnd, int index); [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")] public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); @@ -138,46 +128,20 @@ namespace GreenshotPlugin.UnmanagedHelpers { [DllImport("user32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetWindowInfo(IntPtr hWnd, ref WindowInfo pwi); - [DllImport("user32", SetLastError = true)] - public static extern int EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); - [DllImport("user32", SetLastError = true)] + + [DllImport("user32", SetLastError = true)] public static extern int EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetScrollInfo(IntPtr hWnd, int fnBar, ref SCROLLINFO lpsi); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool ShowScrollBar(IntPtr hWnd, ScrollBarDirection scrollBar, [MarshalAs(UnmanagedType.Bool)] bool show); - [DllImport("user32", SetLastError = true)] - public static extern int SetScrollPos(IntPtr hWnd, Orientation nBar, int nPos, [MarshalAs(UnmanagedType.Bool)] bool bRedraw); - [DllImport("user32", SetLastError = true)] + + [DllImport("user32", SetLastError = true)] public static extern RegionResult GetWindowRgn(IntPtr hWnd, SafeHandle hRgn); [DllImport("user32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, WindowPos uFlags); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetTopWindow(IntPtr hWnd); + public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, WindowPos uFlags); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetDC(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDc); - - [DllImport("user32", SetLastError = true)] + [DllImport("user32", SetLastError = true)] public static extern IntPtr GetClipboardOwner(); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer); - [DllImport("user32", SetLastError = true)] - public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext); - // Added for WinEventHook logic, Greenshot 1.2 - [DllImport("user32", SetLastError = true)] - public static extern bool UnhookWinEvent(IntPtr hWinEventHook); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr SetWinEventHook(WinEvent eventMin, WinEvent eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, int idProcess, int idThread, WinEventHookFlags dwFlags); - - // Added for finding Metro apps, Greenshot 1.1 + // Added for finding Metro apps, Greenshot 1.1 [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] @@ -198,12 +162,8 @@ namespace GreenshotPlugin.UnmanagedHelpers { public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult); [DllImport("user32", SetLastError = true)] private static extern bool GetPhysicalCursorPos(out POINT cursorLocation); - [DllImport("user32", SetLastError=true)] - public static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, ref POINT lpPoints, [MarshalAs(UnmanagedType.U4)] int cPoints); - [DllImport("user32", SetLastError = true)] - public static extern int GetSystemMetrics(SystemMetric index); - /// <summary> + /// <summary> /// The following is used for Icon handling /// </summary> /// <param name="hIcon"></param> @@ -308,13 +268,13 @@ namespace GreenshotPlugin.UnmanagedHelpers { public static uint GetGuiResourcesGDICount() { - using Process currentProcess = Process.GetCurrentProcess(); + using var currentProcess = Process.GetCurrentProcess(); return GetGuiResources(currentProcess.Handle, 0); } public static uint GetGuiResourcesUserCount() { - using Process currentProcess = Process.GetCurrentProcess(); + using var currentProcess = Process.GetCurrentProcess(); return GetGuiResources(currentProcess.Handle, 1); } @@ -324,7 +284,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { /// <param name="method">string with current method</param> /// <returns>Exception</returns> public static Exception CreateWin32Exception(string method) { - Win32Exception exceptionToThrow = new Win32Exception(); + var exceptionToThrow = new Win32Exception(); exceptionToThrow.Data.Add("Method", method); return exceptionToThrow; } diff --git a/GreenshotPlugin/UnmanagedHelpers/Win32.cs b/GreenshotPlugin/UnmanagedHelpers/Win32.cs index 77aaf2256..7efb73292 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Win32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Win32.cs @@ -35,24 +35,14 @@ namespace GreenshotPlugin.UnmanagedHelpers { return (Win32Error)Marshal.GetLastWin32Error(); } - public static long GetHResult(Win32Error errorCode) { - int error = (int)errorCode; - - if ((error & 0x80000000) == 0x80000000) { - return error; - } - - return 0x80070000 | (uint)(error & 0xffff); - } - public static string GetMessage(Win32Error errorCode) { - StringBuilder buffer = new StringBuilder(0x100); + var buffer = new StringBuilder(0x100); if (FormatMessage(0x3200, IntPtr.Zero, (uint)errorCode, 0, buffer, buffer.Capacity, IntPtr.Zero) == 0) { return "Unknown error (0x" + ((int)errorCode).ToString("x") + ")"; } - StringBuilder result = new StringBuilder(); + var result = new StringBuilder(); int i = 0; while (i < buffer.Length) { From 601236833bc1ee7be63c89cfa8b3a89e8f6339dd Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sun, 21 Mar 2021 23:10:05 +0100 Subject: [PATCH 102/232] Fixed #279, all ExternalCommands where duplicated due to creating them in the wrong place. --- .../ExternalCommandPlugin.cs | 242 ++++++++++-------- 1 file changed, 133 insertions(+), 109 deletions(-) diff --git a/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs b/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs index 13d1868d1..9389705b8 100644 --- a/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs +++ b/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs @@ -29,134 +29,158 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotExternalCommandPlugin { - /// <summary> - /// An Plugin to run commands after an image was written - /// </summary> +namespace GreenshotExternalCommandPlugin +{ + /// <summary> + /// An Plugin to run commands after an image was written + /// </summary> [Plugin("ExternalCommand", true)] - public class ExternalCommandPlugin : IGreenshotPlugin { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ExternalCommandPlugin)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>(); - private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection<ExternalCommandConfiguration>(); - private ToolStripMenuItem _itemPlugInRoot; + public class ExternalCommandPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ExternalCommandPlugin)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection<CoreConfiguration>(); + private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection<ExternalCommandConfiguration>(); + private ToolStripMenuItem _itemPlugInRoot; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected virtual void Dispose(bool disposing) + protected virtual void Dispose(bool disposing) { if (!disposing) return; if (_itemPlugInRoot == null) return; _itemPlugInRoot.Dispose(); _itemPlugInRoot = null; } - private IEnumerable<IDestination> Destinations() { - foreach(string command in ExternalCommandConfig.Commands) { - yield return new ExternalCommandDestination(command); - } - } + private IEnumerable<IDestination> Destinations() + { + foreach (string command in ExternalCommandConfig.Commands) + { + yield return new ExternalCommandDestination(command); + } + } - /// <summary> - /// Check and eventually fix the command settings - /// </summary> - /// <param name="command"></param> - /// <returns>false if the command is not correctly configured</returns> - private bool IsCommandValid(string command) { - if (!ExternalCommandConfig.RunInbackground.ContainsKey(command)) { - Log.WarnFormat("Found missing runInbackground for {0}", command); - // Fix it - ExternalCommandConfig.RunInbackground.Add(command, true); - } - if (!ExternalCommandConfig.Argument.ContainsKey(command)) { - Log.WarnFormat("Found missing argument for {0}", command); - // Fix it - ExternalCommandConfig.Argument.Add(command, "{0}"); - } - if (!ExternalCommandConfig.Commandline.ContainsKey(command)) { - Log.WarnFormat("Found missing commandline for {0}", command); - return false; - } - string commandline = FilenameHelper.FillVariables(ExternalCommandConfig.Commandline[command], true); - commandline = FilenameHelper.FillCmdVariables(commandline, true); + /// <summary> + /// Check and eventually fix the command settings + /// </summary> + /// <param name="command"></param> + /// <returns>false if the command is not correctly configured</returns> + private bool IsCommandValid(string command) + { + if (!ExternalCommandConfig.RunInbackground.ContainsKey(command)) + { + Log.WarnFormat("Found missing runInbackground for {0}", command); + // Fix it + ExternalCommandConfig.RunInbackground.Add(command, true); + } + if (!ExternalCommandConfig.Argument.ContainsKey(command)) + { + Log.WarnFormat("Found missing argument for {0}", command); + // Fix it + ExternalCommandConfig.Argument.Add(command, "{0}"); + } + if (!ExternalCommandConfig.Commandline.ContainsKey(command)) + { + Log.WarnFormat("Found missing commandline for {0}", command); + return false; + } + string commandline = FilenameHelper.FillVariables(ExternalCommandConfig.Commandline[command], true); + commandline = FilenameHelper.FillCmdVariables(commandline, true); - if (!File.Exists(commandline)) { - Log.WarnFormat("Found 'invalid' commandline {0} for command {1}", ExternalCommandConfig.Commandline[command], command); - return false; - } + if (!File.Exists(commandline)) + { + Log.WarnFormat("Found 'invalid' commandline {0} for command {1}", ExternalCommandConfig.Commandline[command], command); + return false; + } + return true; + } + /// <summary> + /// Implementation of the IGreenshotPlugin.Initialize + /// </summary> + public virtual bool Initialize() + { + Log.DebugFormat("Initialize called"); + + var commandsToDelete = new List<string>(); + // Check configuration + foreach (string command in ExternalCommandConfig.Commands) + { + if (!IsCommandValid(command)) + { + commandsToDelete.Add(command); + } + } + // cleanup + foreach (string command in commandsToDelete) + { + ExternalCommandConfig.Delete(command); + } SimpleServiceProvider.Current.AddService(Destinations()); - return true; - } - /// <summary> - /// Implementation of the IGreenshotPlugin.Initialize - /// </summary> - public virtual bool Initialize() { - Log.DebugFormat("Initialize called"); - List<string> commandsToDelete = new List<string>(); - // Check configuration - foreach(string command in ExternalCommandConfig.Commands) { - if (!IsCommandValid(command)) { - commandsToDelete.Add(command); - } - } - - // cleanup - foreach (string command in commandsToDelete) { - ExternalCommandConfig.Delete(command); - } - - _itemPlugInRoot = new ToolStripMenuItem(); + _itemPlugInRoot = new ToolStripMenuItem(); _itemPlugInRoot.Click += ConfigMenuClick; - OnIconSizeChanged(this, new PropertyChangedEventArgs("IconSize")); - OnLanguageChanged(this, null); + OnIconSizeChanged(this, new PropertyChangedEventArgs("IconSize")); + OnLanguageChanged(this, null); - PluginUtils.AddToContextMenu(_itemPlugInRoot); - Language.LanguageChanged += OnLanguageChanged; - CoreConfig.PropertyChanged += OnIconSizeChanged; - return true; - } + PluginUtils.AddToContextMenu(_itemPlugInRoot); + Language.LanguageChanged += OnLanguageChanged; + CoreConfig.PropertyChanged += OnIconSizeChanged; + return true; + } - /// <summary> - /// Fix icon reference - /// </summary> - /// <param name="sender"></param> - /// <param name="e"></param> - private void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == "IconSize") { - try { - string exePath = PluginUtils.GetExePath("cmd.exe"); - if (exePath != null && File.Exists(exePath)) { - _itemPlugInRoot.Image = PluginUtils.GetCachedExeIcon(exePath, 0); - } - } catch (Exception ex) { - Log.Warn("Couldn't get the cmd.exe image", ex); - } - } - } + /// <summary> + /// Fix icon reference + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + private void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "IconSize") + { + try + { + string exePath = PluginUtils.GetExePath("cmd.exe"); + if (exePath != null && File.Exists(exePath)) + { + _itemPlugInRoot.Image = PluginUtils.GetCachedExeIcon(exePath, 0); + } + } + catch (Exception ex) + { + Log.Warn("Couldn't get the cmd.exe image", ex); + } + } + } - private void OnLanguageChanged(object sender, EventArgs e) { - if (_itemPlugInRoot != null) { - _itemPlugInRoot.Text = Language.GetString("externalcommand", "contextmenu_configure"); - } - } + private void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInRoot != null) + { + _itemPlugInRoot.Text = Language.GetString("externalcommand", "contextmenu_configure"); + } + } - public virtual void Shutdown() { - Log.Debug("Shutdown"); - } + public virtual void Shutdown() + { + Log.Debug("Shutdown"); + } - private void ConfigMenuClick(object sender, EventArgs eventArgs) { - Configure(); - } + private void ConfigMenuClick(object sender, EventArgs eventArgs) + { + Configure(); + } - /// <summary> - /// Implementation of the IPlugin.Configure - /// </summary> - public virtual void Configure() { - Log.Debug("Configure called"); - new SettingsForm().ShowDialog(); - } - } + /// <summary> + /// Implementation of the IPlugin.Configure + /// </summary> + public virtual void Configure() + { + Log.Debug("Configure called"); + new SettingsForm().ShowDialog(); + } + } } \ No newline at end of file From 2bbaa4a9a74598c747ecdbc09ea42342133d26ec Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sun, 21 Mar 2021 23:44:25 +0100 Subject: [PATCH 103/232] Removed more dead code --- Greenshot/Destinations/EditorDestination.cs | 5 +- Greenshot/Drawing/FilterContainer.cs | 10 +- Greenshot/Drawing/RoundedRectangle.cs | 122 -------------- Greenshot/Forms/CaptureForm.cs | 22 ++- Greenshot/Forms/ColorDialog.cs | 2 - Greenshot/Forms/ImageEditorForm.cs | 8 - Greenshot/Helpers/IECaptureHelper.cs | 22 +-- GreenshotConfluencePlugin/EnumDisplayer.cs | 11 +- .../Forms/ListViewColumnSorter.cs | 113 ------------- .../OfficeInterop/OfficeVersions.cs | 8 - .../PhotobucketConfiguration.cs | 7 +- GreenshotPicasaPlugin/LanguageKeys.cs | 59 +++---- .../Controls/SaveImageFileDialog.cs | 6 +- GreenshotPlugin/Core/ClipboardHelper.cs | 10 +- GreenshotPlugin/Core/DpiHelper.cs | 3 - GreenshotPlugin/Core/Enums/HResult.cs | 23 --- GreenshotPlugin/Core/ImageHelper.cs | 62 +------ GreenshotPlugin/Core/OAuthHelper.cs | 2 - GreenshotPlugin/Core/WindowDetails.cs | 10 -- GreenshotPlugin/FileDescriptorReader.cs | 10 -- .../Interfaces/Drawing/Container.cs | 11 -- .../Interfaces/Forms/ImageEditor.cs | 15 +- .../Interfaces/VerticalAlignment.cs | 34 ---- GreenshotPlugin/Interop/COMWrapper.cs | 79 --------- GreenshotPlugin/Interop/IAppVisibility.cs | 2 - .../UnmanagedHelpers/Enums/ClassLongIndex.cs | 8 - .../UnmanagedHelpers/Enums/DeviceCaps.cs | 155 +----------------- .../UnmanagedHelpers/Enums/EventObjects.cs | 11 -- .../Enums/ExtendedWindowStyleFlags.cs | 31 ---- .../Enums/GetWindowCommand.cs | 36 ---- .../Enums/ProcessAccessFlags.cs | 8 - .../UnmanagedHelpers/Enums/RegionResult.cs | 2 - .../Enums/SendMessageTimeoutFlags.cs | 5 +- .../UnmanagedHelpers/Enums/SoundFlags.cs | 6 - .../UnmanagedHelpers/Enums/WindowLongIndex.cs | 4 - .../Enums/WindowStyleFlags.cs | 52 ------ GreenshotPlugin/UnmanagedHelpers/User32.cs | 19 +-- .../Internal/MemoryRandomAccessStream.cs | 16 -- 38 files changed, 66 insertions(+), 943 deletions(-) delete mode 100644 Greenshot/Drawing/RoundedRectangle.cs delete mode 100644 GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs delete mode 100644 GreenshotPlugin/Interfaces/VerticalAlignment.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/Enums/GetWindowCommand.cs diff --git a/Greenshot/Destinations/EditorDestination.cs b/Greenshot/Destinations/EditorDestination.cs index 415607640..dda45ed37 100644 --- a/Greenshot/Destinations/EditorDestination.cs +++ b/Greenshot/Destinations/EditorDestination.cs @@ -40,10 +40,7 @@ namespace Greenshot.Destinations { private readonly IImageEditor editor; private static readonly Image greenshotIcon = GreenshotResources.GetGreenshotIcon().ToBitmap(); - public EditorDestination() { - } - - public EditorDestination(IImageEditor editor) { + public EditorDestination(IImageEditor editor) { this.editor = editor; } diff --git a/Greenshot/Drawing/FilterContainer.cs b/Greenshot/Drawing/FilterContainer.cs index 9ea6bc1a1..631cbed33 100644 --- a/Greenshot/Drawing/FilterContainer.cs +++ b/Greenshot/Drawing/FilterContainer.cs @@ -30,17 +30,13 @@ namespace Greenshot.Drawing { /// <summary> /// empty container for filter-only elements /// </summary> - [Serializable()] + [Serializable] public abstract class FilterContainer : DrawableContainer { public enum PreparedFilterMode {OBFUSCATE, HIGHLIGHT}; public enum PreparedFilter {BLUR, PIXELIZE, TEXT_HIGHTLIGHT, AREA_HIGHLIGHT, GRAYSCALE, MAGNIFICATION}; - - public PreparedFilter Filter { - get { return (PreparedFilter)GetFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); } - } - - public FilterContainer(Surface parent) : base(parent) { + + public FilterContainer(Surface parent) : base(parent) { Init(); } diff --git a/Greenshot/Drawing/RoundedRectangle.cs b/Greenshot/Drawing/RoundedRectangle.cs deleted file mode 100644 index ce40d6e82..000000000 --- a/Greenshot/Drawing/RoundedRectangle.cs +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; -using System.Drawing.Drawing2D; - -namespace Greenshot.Drawing { - /// <summary> - /// TODO: currently this is only used in the capture form, we might move this code directly to there! - /// </summary> - public abstract class RoundedRectangle { - [Flags] - public enum RectangleCorners { - None = 0, TopLeft = 1, TopRight = 2, - BottomLeft = 4, BottomRight = 8, - All = TopLeft | TopRight | BottomLeft | BottomRight - } - - public static GraphicsPath Create2(int x, int y, int width, int height, int radius) { - GraphicsPath gp = new GraphicsPath(); - gp.AddLine(x + radius, y, x + width - radius * 2, y); // Line - gp.AddArc(x + width - radius * 2, y, radius * 2, radius * 2, 270, 90); // Corner - gp.AddLine(x + width, y + radius, x + width, y + height - radius * 2); // Line - gp.AddArc(x + width - radius * 2, y + height - radius * 2, radius * 2, radius * 2, 0, 90); // Corner - gp.AddLine(x + width - radius * 2, y + height, x + radius, y + height); // Line - gp.AddArc(x, y + height - radius * 2, radius * 2, radius * 2, 90, 90); // Corner - gp.AddLine(x, y + height - radius * 2, x, y + radius); // Line - gp.AddArc(x, y, radius * 2, radius * 2, 180, 90); // Corner - gp.CloseFigure(); - - return gp; - } - - public static GraphicsPath Create(int x, int y, int width, int height, int radius, RectangleCorners corners) { - int xw = x + width; - int yh = y + height; - int xwr = xw - radius; - int yhr = yh - radius; - int xr = x + radius; - int yr = y + radius; - int r2 = radius * 2; - int xwr2 = xw - r2; - int yhr2 = yh - r2; - - GraphicsPath p = new GraphicsPath(); - p.StartFigure(); - - //Top Left Corner - if ((RectangleCorners.TopLeft & corners) == RectangleCorners.TopLeft) { - p.AddArc(x, y, r2, r2, 180, 90); - } else { - p.AddLine(x, yr, x, y); - p.AddLine(x, y, xr, y); - } - - //Top Edge - p.AddLine(xr, y, xwr, y); - - //Top Right Corner - if ((RectangleCorners.TopRight & corners) == RectangleCorners.TopRight) { - p.AddArc(xwr2, y, r2, r2, 270, 90); - } else { - p.AddLine(xwr, y, xw, y); - p.AddLine(xw, y, xw, yr); - } - - //Right Edge - p.AddLine(xw, yr, xw, yhr); - - //Bottom Right Corner - if ((RectangleCorners.BottomRight & corners) == RectangleCorners.BottomRight) { - p.AddArc(xwr2, yhr2, r2, r2, 0, 90); - } else { - p.AddLine(xw, yhr, xw, yh); - p.AddLine(xw, yh, xwr, yh); - } - - //Bottom Edge - p.AddLine(xwr, yh, xr, yh); - - //Bottom Left Corner - if ((RectangleCorners.BottomLeft & corners) == RectangleCorners.BottomLeft) { - p.AddArc(x, yhr2, r2, r2, 90, 90); - } else { - p.AddLine(xr, yh, x, yh); - p.AddLine(x, yh, x, yhr); - } - - //Left Edge - p.AddLine(x, yhr, x, yr); - - p.CloseFigure(); - return p; - } - - public static GraphicsPath Create(int x, int y, int width, int height, int radius) { - return Create(x, y, width, height, radius, RectangleCorners.All); - } - - public static GraphicsPath Create(int x, int y, int width, int height) { - return Create(x, y, width, height, 5); - } - } -} diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs index bf21382e8..3cc04ebf6 100644 --- a/Greenshot/Forms/CaptureForm.cs +++ b/Greenshot/Forms/CaptureForm.cs @@ -905,7 +905,7 @@ namespace Greenshot.Forms { // horizontal ruler if (fixedRect.Width > hSpace + 3) { - using GraphicsPath p = RoundedRectangle.Create2( + using GraphicsPath p = CreateRoundedRectangle( fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, fixedRect.Y - dist - 7, measureWidth.Width - 3, @@ -923,7 +923,7 @@ namespace Greenshot.Forms { // vertical ruler if (fixedRect.Height > vSpace + 3) { - using GraphicsPath p = RoundedRectangle.Create2( + using GraphicsPath p = CreateRoundedRectangle( fixedRect.X - measureHeight.Width + 1, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2, measureHeight.Width - 3, @@ -990,7 +990,7 @@ namespace Greenshot.Forms { string xy = _cursorPos.X + " x " + _cursorPos.Y; using Font f = new Font(FontFamily.GenericSansSerif, 8); Size xySize = TextRenderer.MeasureText(xy, f); - using GraphicsPath gp = RoundedRectangle.Create2(_cursorPos.X + 5, _cursorPos.Y + 5, xySize.Width - 3, xySize.Height, 3); + using GraphicsPath gp = CreateRoundedRectangle(_cursorPos.X + 5, _cursorPos.Y + 5, xySize.Width - 3, xySize.Height, 3); using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227))) { graphics.FillPath(bgBrush, gp); } @@ -1014,5 +1014,21 @@ namespace Greenshot.Forms { DrawZoom(graphics, sourceRectangle, destinationRectangle); } } + + private static GraphicsPath CreateRoundedRectangle(int x, int y, int width, int height, int radius) + { + var gp = new GraphicsPath(); + gp.AddLine(x + radius, y, x + width - radius * 2, y); // Line + gp.AddArc(x + width - radius * 2, y, radius * 2, radius * 2, 270, 90); // Corner + gp.AddLine(x + width, y + radius, x + width, y + height - radius * 2); // Line + gp.AddArc(x + width - radius * 2, y + height - radius * 2, radius * 2, radius * 2, 0, 90); // Corner + gp.AddLine(x + width - radius * 2, y + height, x + radius, y + height); // Line + gp.AddArc(x, y + height - radius * 2, radius * 2, radius * 2, 90, 90); // Corner + gp.AddLine(x, y + height - radius * 2, x, y + radius); // Line + gp.AddArc(x, y, radius * 2, radius * 2, 180, 90); // Corner + gp.CloseFigure(); + + return gp; + } } } diff --git a/Greenshot/Forms/ColorDialog.cs b/Greenshot/Forms/ColorDialog.cs index f69c8f2fc..b93c01258 100644 --- a/Greenshot/Forms/ColorDialog.cs +++ b/Greenshot/Forms/ColorDialog.cs @@ -59,8 +59,6 @@ namespace Greenshot.Forms { set { PreviewColor(value, this); } } - public IList<Color> RecentColors => EditorConfig.RecentColors; - private void CreateColorPalette(int x, int y, int w, int h) { CreateColorButtonColumn(255, 0, 0, x, y, w, h, 11); x += w; diff --git a/Greenshot/Forms/ImageEditorForm.cs b/Greenshot/Forms/ImageEditorForm.cs index ba72fc96c..de5022634 100644 --- a/Greenshot/Forms/ImageEditorForm.cs +++ b/Greenshot/Forms/ImageEditorForm.cs @@ -512,14 +512,6 @@ namespace Greenshot.Forms { public ICaptureDetails CaptureDetails => _surface.CaptureDetails; - public ToolStripMenuItem GetPluginMenuItem() { - return pluginToolStripMenuItem; - } - - public ToolStripMenuItem GetFileMenuItem() { - return fileStripMenuItem; - } - private void BtnSaveClick(object sender, EventArgs e) { string destinationDesignation = FileDestination.DESIGNATION; if (_surface.LastSaveFullPath == null) { diff --git a/Greenshot/Helpers/IECaptureHelper.cs b/Greenshot/Helpers/IECaptureHelper.cs index 5922d6474..24b5136cf 100644 --- a/Greenshot/Helpers/IECaptureHelper.cs +++ b/Greenshot/Helpers/IECaptureHelper.cs @@ -60,27 +60,7 @@ namespace Greenshot.Helpers { ieAccessible.ActivateIETab(tabIndex); } - /// <summary> - /// Return true if the supplied window has a sub-window which covers more than the supplied percentage - /// </summary> - /// <param name="someWindow">WindowDetails to check</param> - /// <param name="minimumPercentage">min percentage</param> - /// <returns></returns> - public static bool IsMostlyIeWindow(WindowDetails someWindow, int minimumPercentage) { - WindowDetails ieWindow = someWindow.GetChild("Internet Explorer_Server"); - if (ieWindow == null) return false; - - Rectangle wholeClient = someWindow.ClientRectangle; - Rectangle partClient = ieWindow.ClientRectangle; - int percentage = (int)(100*(float)(partClient.Width * partClient.Height) / (wholeClient.Width * wholeClient.Height)); - Log.InfoFormat("Window {0}, ie part {1}, percentage {2}", wholeClient, partClient, percentage); - if (percentage > minimumPercentage) { - return true; - } - return false; - } - - /// <summary> + /// <summary> /// Does the supplied window have a IE part? /// </summary> /// <param name="someWindow"></param> diff --git a/GreenshotConfluencePlugin/EnumDisplayer.cs b/GreenshotConfluencePlugin/EnumDisplayer.cs index 84ca2925e..5358362ef 100644 --- a/GreenshotConfluencePlugin/EnumDisplayer.cs +++ b/GreenshotConfluencePlugin/EnumDisplayer.cs @@ -33,15 +33,8 @@ namespace GreenshotConfluencePlugin { private Type _type; private IDictionary _displayValues; private IDictionary _reverseValues; - - public EnumDisplayer() { - } - - public EnumDisplayer(Type type) { - Type = type; - } - - public Type Type { + + public Type Type { get { return _type; } set { if (!value.IsEnum) { diff --git a/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs b/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs deleted file mode 100644 index d4cbe59d4..000000000 --- a/GreenshotConfluencePlugin/Forms/ListViewColumnSorter.cs +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Collections; -using System.Windows.Forms; - -namespace GreenshotConfluencePlugin.Forms -{ - /// <summary> - /// This class is an implementation of the 'IComparer' interface. - /// </summary> - public class ListViewColumnSorter : IComparer { - /// <summary> - /// Specifies the column to be sorted - /// </summary> - private int _columnToSort; - /// <summary> - /// Specifies the order in which to sort (i.e. 'Ascending'). - /// </summary> - private SortOrder _orderOfSort; - /// <summary> - /// Case insensitive comparer object - /// </summary> - private readonly CaseInsensitiveComparer _objectCompare; - - /// <summary> - /// Class constructor. Initializes various elements - /// </summary> - public ListViewColumnSorter() { - // Initialize the column to '0' - _columnToSort = 0; - - // Initialize the sort order to 'none' - _orderOfSort = SortOrder.None; - - // Initialize the CaseInsensitiveComparer object - _objectCompare = new CaseInsensitiveComparer(); - } - - /// <summary> - /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison. - /// </summary> - /// <param name="x">First object to be compared</param> - /// <param name="y">Second object to be compared</param> - /// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns> - public int Compare(object x, object y) { - int compareResult; - ListViewItem listviewX, listviewY; - - // Cast the objects to be compared to ListViewItem objects - listviewX = (ListViewItem)x; - listviewY = (ListViewItem)y; - - // Compare the two items - compareResult = _objectCompare.Compare(listviewX.SubItems[_columnToSort].Text, listviewY.SubItems[_columnToSort].Text); - - // Calculate correct return value based on object comparison - if (_orderOfSort == SortOrder.Ascending) { - // Ascending sort is selected, return normal result of compare operation - return compareResult; - } else if (_orderOfSort == SortOrder.Descending) { - // Descending sort is selected, return negative result of compare operation - return (-compareResult); - } else { - // Return '0' to indicate they are equal - return 0; - } - } - - /// <summary> - /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0'). - /// </summary> - public int SortColumn { - set { - _columnToSort = value; - } - get { - return _columnToSort; - } - } - - /// <summary> - /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending'). - /// </summary> - public SortOrder Order { - set { - _orderOfSort = value; - } - get { - return _orderOfSort; - } - } - - } -} diff --git a/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs b/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs index 03943e4db..3988148c5 100644 --- a/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs +++ b/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs @@ -29,14 +29,6 @@ namespace GreenshotOfficePlugin.OfficeInterop /// </summary> Office97 = 8, /// <summary> - /// Office 2000 - /// </summary> - Office2000 = 9, - /// <summary> - /// Office 2002 - /// </summary> - Office2002 = 10, - /// <summary> /// Office 2003 /// </summary> Office2003 = 11, diff --git a/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs b/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs index 8136adbff..c852c0c81 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs @@ -47,12 +47,7 @@ namespace GreenshotPhotobucketPlugin { [IniProperty("Username", Description = "The Photobucket api username", ExcludeIfNull = true)] public string Username { get; set; } - public int Credits { - get; - set; - } - - /// <summary> + /// <summary> /// A form for username/password /// </summary> /// <returns>bool true if OK was pressed, false if cancel</returns> diff --git a/GreenshotPicasaPlugin/LanguageKeys.cs b/GreenshotPicasaPlugin/LanguageKeys.cs index 58a488db5..c22e4c404 100644 --- a/GreenshotPicasaPlugin/LanguageKeys.cs +++ b/GreenshotPicasaPlugin/LanguageKeys.cs @@ -1,34 +1,29 @@ -/* - * A Picasa Plugin for Greenshot - * Copyright (C) 2011 Francis Noel - * - * For more information see: http://getgreenshot.org/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. +/* + * A Picasa Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotPicasaPlugin { - public enum LangKey - { - upload_menu_item, - settings_title, - label_upload_format, - upload_success, - upload_failure, - communication_wait, - Configure, - label_AfterUpload, - label_AfterUploadLinkToClipBoard - } -} +namespace GreenshotPicasaPlugin { + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + Configure + } +} diff --git a/GreenshotPlugin/Controls/SaveImageFileDialog.cs b/GreenshotPlugin/Controls/SaveImageFileDialog.cs index 0245dc05e..a27eccd15 100644 --- a/GreenshotPlugin/Controls/SaveImageFileDialog.cs +++ b/GreenshotPlugin/Controls/SaveImageFileDialog.cs @@ -53,11 +53,7 @@ namespace GreenshotPlugin.Controls { } } - public SaveImageFileDialog() { - Init(); - } - - public SaveImageFileDialog(ICaptureDetails captureDetails) { + public SaveImageFileDialog(ICaptureDetails captureDetails) { _captureDetails = captureDetails; Init(); } diff --git a/GreenshotPlugin/Core/ClipboardHelper.cs b/GreenshotPlugin/Core/ClipboardHelper.cs index f5af04b9d..2d675d24e 100644 --- a/GreenshotPlugin/Core/ClipboardHelper.cs +++ b/GreenshotPlugin/Core/ClipboardHelper.cs @@ -564,15 +564,7 @@ EndSelection:<<<<<<<4 return null; } - /// <summary> - /// Wrapper for Clipboard.GetText created for Bug #3432313 - /// </summary> - /// <returns>string if there is text on the clipboard</returns> - public static string GetText() { - return GetText(GetDataObject()); - } - - /// <summary> + /// <summary> /// Get Text from the DataObject /// </summary> /// <returns>string if there is text on the clipboard</returns> diff --git a/GreenshotPlugin/Core/DpiHelper.cs b/GreenshotPlugin/Core/DpiHelper.cs index a0c4db3ff..7f98f69a6 100644 --- a/GreenshotPlugin/Core/DpiHelper.cs +++ b/GreenshotPlugin/Core/DpiHelper.cs @@ -21,7 +21,6 @@ using GreenshotPlugin.Core.Enums; using GreenshotPlugin.UnmanagedHelpers; -using log4net; using System; using System.Drawing; using System.Runtime.InteropServices; @@ -36,8 +35,6 @@ namespace GreenshotPlugin.Core /// </summary> public static class DpiHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(DpiHelper)); - /// <summary> /// This is the default DPI for the screen /// </summary> diff --git a/GreenshotPlugin/Core/Enums/HResult.cs b/GreenshotPlugin/Core/Enums/HResult.cs index 40bb62a7b..a1d2036d7 100644 --- a/GreenshotPlugin/Core/Enums/HResult.cs +++ b/GreenshotPlugin/Core/Enums/HResult.cs @@ -28,29 +28,6 @@ namespace GreenshotPlugin.Core.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum HResult { -#pragma warning disable 1591 S_OK = 0, - S_FALSE = 1, - E_FAIL = unchecked((int)0x80004005), - E_INVALIDARG = unchecked((int)0x80070057), - E_NOTIMPL = unchecked((int)0x80004001), - E_POINTER = unchecked((int)0x80004003), - E_PENDING = unchecked((int)0x8000000A), - E_NOINTERFACE = unchecked((int)0x80004002), - E_ABORT = unchecked((int)0x80004004), - E_ACCESSDENIED = unchecked((int)0x80070006), - E_HANDLE = unchecked((int)0x80070006), - E_UNEXPECTED = unchecked((int)0x8000FFFF), - E_FILENOTFOUND = unchecked((int)0x80070002), - E_PATHNOTFOUND = unchecked((int)0x80070003), - E_INVALID_DATA = unchecked((int)0x8007000D), - E_OUTOFMEMORY = unchecked((int)0x8007000E), - E_INSUFFICIENT_BUFFER = unchecked((int)0x8007007A), - WSAECONNABORTED = unchecked((int)0x80072745), - WSAECONNRESET = unchecked((int)0x80072746), - ERROR_TOO_MANY_CMDS = unchecked((int)0x80070038), - ERROR_NOT_SUPPORTED = unchecked((int)0x80070032), - TYPE_E_ELEMENTNOTFOUND = unchecked((int)0x8002802B) -#pragma warning restore 1591 } } diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs index b80879141..0f19462bd 100644 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ b/GreenshotPlugin/Core/ImageHelper.cs @@ -467,17 +467,7 @@ namespace GreenshotPlugin.Core { return returnIcon; } - /// <summary> - /// Get the number of icon in the file - /// </summary> - /// <param name="location">Location of the EXE or DLL</param> - /// <returns></returns> - public static int CountAssociatedIcons(string location) - { - return Shell32.ExtractIconEx(location, -1, out _, out _, 0); - } - - /// <summary> + /// <summary> /// Apply the effect to the bitmap /// </summary> /// <param name="sourceImage">Bitmap</param> @@ -1063,17 +1053,7 @@ namespace GreenshotPlugin.Core { ApplyImageAttributes(source, sourceRect, dest, destRect, imageAttributes); } - /// <summary> - /// Apply image attributes to the image - /// </summary> - /// <param name="source">Image to apply matrix to</param> - /// <param name="imageAttributes">ImageAttributes to apply</param> - public static void ApplyColorMatrix(Bitmap source, ImageAttributes imageAttributes) - { - ApplyImageAttributes(source, Rectangle.Empty, source, Rectangle.Empty, imageAttributes); - } - - /// <summary> + /// <summary> /// Apply a color matrix by copying from the source to the destination /// </summary> /// <param name="source">Image to copy from</param> @@ -1242,17 +1222,7 @@ namespace GreenshotPlugin.Core { return clone; } - /// <summary> - /// Checks if the supplied Bitmap has a PixelFormat we support - /// </summary> - /// <param name="image">bitmap to check</param> - /// <returns>bool if we support it</returns> - public static bool SupportsPixelFormat(Image image) - { - return SupportsPixelFormat(image.PixelFormat); - } - - /// <summary> + /// <summary> /// Checks if we support the pixel format /// </summary> /// <param name="pixelformat">PixelFormat to check</param> @@ -1462,31 +1432,7 @@ namespace GreenshotPlugin.Core { return newImage; } - /// <summary> - /// Get a scaled version of the sourceBitmap - /// </summary> - /// <param name="sourceBitmap"></param> - /// <param name="percent">1-99 to make smaller, use 101 and more to make the picture bigger</param> - /// <returns></returns> - public static Bitmap ScaleByPercent(Bitmap sourceBitmap, int percent) - { - float nPercent = (float)percent / 100; - - int sourceWidth = sourceBitmap.Width; - int sourceHeight = sourceBitmap.Height; - int destWidth = (int)(sourceWidth * nPercent); - int destHeight = (int)(sourceHeight * nPercent); - - Bitmap scaledBitmap = CreateEmpty(destWidth, destHeight, sourceBitmap.PixelFormat, Color.Empty, sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); - using (Graphics graphics = Graphics.FromImage(scaledBitmap)) - { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.DrawImage(sourceBitmap, new Rectangle(0, 0, destWidth, destHeight), new Rectangle(0, 0, sourceWidth, sourceHeight), GraphicsUnit.Pixel); - } - return scaledBitmap; - } - - /// <summary> + /// <summary> /// Resize canvas with pixel to the left, right, top and bottom /// </summary> /// <param name="sourceImage"></param> diff --git a/GreenshotPlugin/Core/OAuthHelper.cs b/GreenshotPlugin/Core/OAuthHelper.cs index 555c37c7a..352934ef8 100644 --- a/GreenshotPlugin/Core/OAuthHelper.cs +++ b/GreenshotPlugin/Core/OAuthHelper.cs @@ -50,8 +50,6 @@ namespace GreenshotPlugin.Core { public enum OAuth2AuthorizeMode { Unknown, // Will give an exception, caller needs to specify another value LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener - MonitorTitle, // Not implemented yet: Will monitor for title changes - Pin, // Not implemented yet: Will ask the user to enter the shown PIN EmbeddedBrowser, // Will open into an embedded _browser (OAuthLoginForm), and catch the redirect OutOfBoundAuto } diff --git a/GreenshotPlugin/Core/WindowDetails.cs b/GreenshotPlugin/Core/WindowDetails.cs index 28408051a..a2d3d9a63 100644 --- a/GreenshotPlugin/Core/WindowDetails.cs +++ b/GreenshotPlugin/Core/WindowDetails.cs @@ -358,16 +358,6 @@ namespace GreenshotPlugin.Core return _childWindows; } - /// <summary> - /// Retrieve children with a certain title or classname - /// </summary> - /// <param name="titlePattern">The regexp to look for in the title</param> - /// <param name="classnamePattern">The regexp to look for in the classname</param> - /// <returns>List WindowDetails with all the found windows, or an empty list</returns> - public IEnumerable<WindowDetails> FindChildren(string titlePattern, string classnamePattern) { - return FindWindow(Children, titlePattern, classnamePattern); - } - /// <summary> /// Gets the window's handle /// </summary> diff --git a/GreenshotPlugin/FileDescriptorReader.cs b/GreenshotPlugin/FileDescriptorReader.cs index 7fb7069c0..93b94f834 100644 --- a/GreenshotPlugin/FileDescriptorReader.cs +++ b/GreenshotPlugin/FileDescriptorReader.cs @@ -36,16 +36,6 @@ namespace GreenshotPlugin.Interop [Flags] internal enum FileDescriptorFlags : uint { - ClsId = 0x00000001, - SizePoint = 0x00000002, - Attributes = 0x00000004, - CreateTime = 0x00000008, - AccessTime = 0x00000010, - WritesTime = 0x00000020, - FileSize = 0x00000040, - ProgressUI = 0x00004000, - LinkUI = 0x00008000, - Unicode = 0x80000000, } internal static class FileDescriptorReader diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/GreenshotPlugin/Interfaces/Drawing/Container.cs index a97ff5ffc..7b999565a 100644 --- a/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ b/GreenshotPlugin/Interfaces/Drawing/Container.cs @@ -24,7 +24,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; -using System.Drawing.Imaging; using System.Windows.Forms; using GreenshotPlugin.Interfaces.Drawing.Adorners; @@ -213,14 +212,4 @@ namespace GreenshotPlugin.Interfaces.Drawing } void Load(string filename); } - - public interface IMetafileContainer : IDrawableContainer - { - Metafile Metafile - { - get; - set; - } - void Load(string filename); - } } diff --git a/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs b/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs index c613823fa..808951234 100644 --- a/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs +++ b/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs @@ -20,7 +20,6 @@ */ using System.Drawing; -using System.Windows.Forms; namespace GreenshotPlugin.Interfaces.Forms { /// <summary> @@ -34,20 +33,8 @@ namespace GreenshotPlugin.Interfaces.Forms { /// </summary> /// <returns>Bitmap</returns> Image GetImageForExport(); - - /// <summary> - /// Get the ToolStripMenuItem where plugins can place their Menu entrys - /// </summary> - /// <returns>ToolStripMenuItem</returns> - ToolStripMenuItem GetPluginMenuItem(); - /// <summary> - /// Get the File ToolStripMenuItem - /// </summary> - /// <returns>ToolStripMenuItem</returns> - ToolStripMenuItem GetFileMenuItem(); - - /// <summary> + /// <summary> /// Make the ICaptureDetails from the current Surface in the EditorForm available. /// </summary> ICaptureDetails CaptureDetails { diff --git a/GreenshotPlugin/Interfaces/VerticalAlignment.cs b/GreenshotPlugin/Interfaces/VerticalAlignment.cs deleted file mode 100644 index f5cb71f0f..000000000 --- a/GreenshotPlugin/Interfaces/VerticalAlignment.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotPlugin.Interfaces -{ - /// <summary> - /// Alignment Enums for positioning - /// </summary> - //public enum HorizontalAlignment {LEFT, CENTER, RIGHT}; - public enum VerticalAlignment - { - TOP, - CENTER, - BOTTOM - }; -} \ No newline at end of file diff --git a/GreenshotPlugin/Interop/COMWrapper.cs b/GreenshotPlugin/Interop/COMWrapper.cs index c2bcbccf0..c96033de3 100644 --- a/GreenshotPlugin/Interop/COMWrapper.cs +++ b/GreenshotPlugin/Interop/COMWrapper.cs @@ -35,8 +35,6 @@ namespace GreenshotPlugin.Interop { /// </summary> public sealed class COMWrapper : RealProxy, IDisposable, IRemotingTypeInfo { private static readonly ILog Log = LogManager.GetLogger(typeof(COMWrapper)); - private const int MK_E_UNAVAILABLE = -2147221021; - private const int CO_E_CLASSSTRING = -2147221005; public const int RPC_E_CALL_REJECTED = unchecked((int)0x80010001); public const int RPC_E_FAIL = unchecked((int)0x80004005); @@ -60,84 +58,7 @@ namespace GreenshotPlugin.Interop { /// </summary> private readonly string _targetName; - [DllImport("ole32.dll")] - private static extern int ProgIDFromCLSID([In] ref Guid clsid, [MarshalAs(UnmanagedType.LPWStr)] out string lplpszProgId); - // Converts failure HRESULTs to exceptions: - [DllImport("oleaut32", PreserveSig=false)] - private static extern void GetActiveObject(ref Guid rclsid, IntPtr pvReserved, [MarshalAs(UnmanagedType.IUnknown)] out object ppunk); - /// <summary> - /// Gets a COM object and returns the transparent proxy which intercepts all calls to the object - /// </summary> - /// <typeparam name="T">Interface which defines the method and properties to intercept</typeparam> - /// <returns>Transparent proxy to the real proxy for the object</returns> - /// <remarks>T must be an interface decorated with the <see cref="ComProgIdAttribute"/>attribute.</remarks> - public static T GetInstance<T>() { - Type type = typeof(T); - if (null == type) { - throw new ArgumentNullException(nameof(T)); - } - if (!type.IsInterface) { - throw new ArgumentException("The specified type must be an interface.", nameof(T)); - } - - var progIdAttribute = ComProgIdAttribute.GetAttribute(type); - if (string.IsNullOrEmpty(progIdAttribute?.Value)) { - throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T)); - } - string progId = progIdAttribute.Value; - - object comObject = null; - - // Convert from clsid to Prog ID, if needed - if (progId.StartsWith("clsid:")) { - Guid guid = new Guid(progId.Substring(6)); - int result = ProgIDFromCLSID(ref guid, out progId); - if (result != 0) { - // Restore progId, as it's overwritten - progId = progIdAttribute.Value; - - try { - GetActiveObject(ref guid, IntPtr.Zero, out comObject); - } catch (Exception) { - Log.WarnFormat("Error {0} getting instance for class id {1}", result, progIdAttribute.Value); - } - if (comObject == null) { - Log.WarnFormat("Error {0} getting progId {1}", result, progIdAttribute.Value); - } - } else { - Log.InfoFormat("Mapped {0} to progId {1}", progIdAttribute.Value, progId); - } - } - - if (comObject == null) { - try { - comObject = Marshal.GetActiveObject(progId); - } catch (COMException comE) { - if (comE.ErrorCode == MK_E_UNAVAILABLE) { - Log.DebugFormat("No current instance of {0} object available.", progId); - } else if (comE.ErrorCode == CO_E_CLASSSTRING) { - Log.WarnFormat("Unknown progId {0}", progId); - } else { - Log.Warn("Error getting active object for " + progIdAttribute.Value, comE); - } - } catch (Exception e) { - Log.Warn("Error getting active object for " + progIdAttribute.Value, e); - } - } - - if (comObject != null) { - if (comObject is IDispatch) { - COMWrapper wrapper = new COMWrapper(comObject, type, progIdAttribute.Value); - return (T)wrapper.GetTransparentProxy(); - } else { - return (T)comObject; - } - } - return default; - } - - /// <summary> /// A simple create instance, doesn't create a wrapper!! /// </summary> /// <returns>T</returns> diff --git a/GreenshotPlugin/Interop/IAppVisibility.cs b/GreenshotPlugin/Interop/IAppVisibility.cs index 2feb78b76..58fddc8b8 100644 --- a/GreenshotPlugin/Interop/IAppVisibility.cs +++ b/GreenshotPlugin/Interop/IAppVisibility.cs @@ -35,8 +35,6 @@ namespace GreenshotPlugin.Interop { } public enum MONITOR_APP_VISIBILITY { - MAV_UNKNOWN = 0, // The mode for the monitor is unknown - MAV_NO_APP_VISIBLE = 1, MAV_APP_VISIBLE = 2 } } diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs index ee54635c5..d862d0ee8 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs @@ -26,15 +26,7 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum ClassLongIndex { - GCL_CBCLSEXTRA = -20, // the size, in bytes, of the extra memory associated with the class. Setting this value does not change the number of extra bytes already allocated. - GCL_CBWNDEXTRA = -18, // the size, in bytes, of the extra window memory associated with each window in the class. Setting this value does not change the number of extra bytes already allocated. For information on how to access this memory, see SetWindowLong. - GCL_HBRBACKGROUND = -10, // a handle to the background brush associated with the class. - GCL_HCURSOR = -12, // a handle to the cursor associated with the class. GCL_HICON = -14, // a handle to the icon associated with the class. GCL_HICONSM = -34, // a handle to the small icon associated with the class. - GCL_HMODULE = -16, // a handle to the module that registered the class. - GCL_MENUNAME = -8, // the address of the menu name string. The string identifies the menu resource associated with the class. - GCL_STYLE = -26, // the window-class style bits. - GCL_WNDPROC = -24, // the address of the window procedure, or a handle representing the address of the window procedure. You must use the CallWindowProc function to call the window procedure. } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs index cc9b04573..d83bf89a0 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs @@ -29,166 +29,15 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums /// </summary> [SuppressMessage("ReSharper", "InconsistentNaming")] public enum DeviceCaps { - /// <summary> - /// Device driver version - /// </summary> - DRIVERVERSION = 0, - /// <summary> - /// Device classification - /// </summary> - TECHNOLOGY = 2, - /// <summary> - /// Horizontal size in millimeters - /// </summary> - HORZSIZE = 4, - /// <summary> - /// Vertical size in millimeters - /// </summary> - VERTSIZE = 6, - /// <summary> - /// Horizontal width in pixels - /// </summary> - HORZRES = 8, - /// <summary> - /// Vertical height in pixels - /// </summary> - VERTRES = 10, - /// <summary> - /// Number of bits per pixel - /// </summary> - BITSPIXEL = 12, - /// <summary> - /// Number of planes - /// </summary> - PLANES = 14, - /// <summary> - /// Number of brushes the device has - /// </summary> - NUMBRUSHES = 16, - /// <summary> - /// Number of pens the device has - /// </summary> - NUMPENS = 18, - /// <summary> - /// Number of markers the device has - /// </summary> - NUMMARKERS = 20, - /// <summary> - /// Number of fonts the device has - /// </summary> - NUMFONTS = 22, - /// <summary> - /// Number of colors the device supports - /// </summary> - NUMCOLORS = 24, - /// <summary> - /// Size required for device descriptor - /// </summary> - PDEVICESIZE = 26, - /// <summary> - /// Curve capabilities - /// </summary> - CURVECAPS = 28, - /// <summary> - /// Line capabilities - /// </summary> - LINECAPS = 30, - /// <summary> - /// Polygonal capabilities - /// </summary> - POLYGONALCAPS = 32, - /// <summary> - /// Text capabilities - /// </summary> - TEXTCAPS = 34, - /// <summary> - /// Clipping capabilities - /// </summary> - CLIPCAPS = 36, - /// <summary> - /// Bitblt capabilities - /// </summary> - RASTERCAPS = 38, - /// <summary> - /// Length of the X leg - /// </summary> - ASPECTX = 40, - /// <summary> - /// Length of the Y leg - /// </summary> - ASPECTY = 42, - /// <summary> - /// Length of the hypotenuse - /// </summary> - ASPECTXY = 44, - /// <summary> - /// Shading and Blending caps - /// </summary> - SHADEBLENDCAPS = 45, - + /// <summary> /// Logical pixels inch in X /// </summary> LOGPIXELSX = 88, - /// <summary> - /// Logical pixels inch in Y - /// </summary> - LOGPIXELSY = 90, - - /// <summary> - /// Number of entries in physical palette - /// </summary> - SIZEPALETTE = 104, - /// <summary> - /// Number of reserved entries in palette - /// </summary> - NUMRESERVED = 106, - /// <summary> - /// Actual color resolution - /// </summary> - COLORRES = 108, - - // Printing related DeviceCaps. These replace the appropriate Escapes - /// <summary> - /// Physical Width in device units - /// </summary> - PHYSICALWIDTH = 110, - /// <summary> - /// Physical Height in device units - /// </summary> - PHYSICALHEIGHT = 111, - /// <summary> - /// Physical Printable Area x margin - /// </summary> - PHYSICALOFFSETX = 112, - /// <summary> - /// Physical Printable Area y margin - /// </summary> - PHYSICALOFFSETY = 113, - /// <summary> - /// Scaling factor x - /// </summary> - SCALINGFACTORX = 114, - /// <summary> - /// Scaling factor y - /// </summary> - SCALINGFACTORY = 115, /// <summary> /// Current vertical refresh rate of the display device (for displays only) in Hz /// </summary> - VREFRESH = 116, - /// <summary> - /// Horizontal width of entire desktop in pixels - /// </summary> - DESKTOPVERTRES = 117, - /// <summary> - /// Vertical height of entire desktop in pixels - /// </summary> - DESKTOPHORZRES = 118, - /// <summary> - /// Preferred blt alignment - /// </summary> - BLTALIGNMENT = 119 + VREFRESH = 116 } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs index 641b1e012..a1981e644 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs @@ -30,17 +30,6 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum EventObjects { - OBJID_ALERT = -10, - OBJID_CARET = -8, - OBJID_CLIENT = -4, - OBJID_CURSOR = -9, - OBJID_HSCROLL = -6, - OBJID_MENU = -3, - OBJID_SIZEGRIP = -7, - OBJID_SOUND = -11, - OBJID_SYSMENU = -1, - OBJID_TITLEBAR = -2, - OBJID_VSCROLL = -5, OBJID_WINDOW = 0 } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs index 3a32bf814..6bc87e3f7 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs @@ -27,38 +27,7 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [Flags] [SuppressMessage("ReSharper", "InconsistentNaming")] public enum ExtendedWindowStyleFlags : uint { - WS_EX_DLGMODALFRAME = 0x00000001, - WS_EX_NOPARENTNOTIFY = 0x00000004, - WS_EX_TOPMOST = 0x00000008, - WS_EX_ACCEPTFILES = 0x00000010, - WS_EX_TRANSPARENT = 0x00000020, - - //#if(WINVER >= 0x0400) - WS_EX_MDICHILD = 0x00000040, WS_EX_TOOLWINDOW = 0x00000080, - WS_EX_WINDOWEDGE = 0x00000100, - WS_EX_CLIENTEDGE = 0x00000200, - WS_EX_CONTEXTHELP = 0x00000400, - - WS_EX_RIGHT = 0x00001000, - WS_EX_LEFT = 0x00000000, - WS_EX_RTLREADING = 0x00002000, - WS_EX_LTRREADING = 0x00000000, - WS_EX_LEFTSCROLLBAR = 0x00004000, - WS_EX_RIGHTSCROLLBAR = 0x00000000, - - WS_EX_CONTROLPARENT = 0x00010000, - WS_EX_STATICEDGE = 0x00020000, - WS_EX_APPWINDOW = 0x00040000, - - //WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE), - //WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST), - - WS_EX_LAYERED = 0x00080000, - WS_EX_NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children WS_EX_NOREDIRECTIONBITMAP = 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual. - WS_EX_LAYOUTRTL = 0x00400000, // Right to left mirroring - WS_EX_COMPOSITED = 0x02000000, - WS_EX_NOACTIVATE = 0x08000000 // A top-level window created with this style does not become the foreground window when the user clicks it. The system does not bring this window to the foreground when the user minimizes or closes the foreground window. } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/GetWindowCommand.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/GetWindowCommand.cs deleted file mode 100644 index 64f1dd041..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/GetWindowCommand.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum GetWindowCommand : uint { - GW_HWNDFIRST = 0, - GW_HWNDLAST = 1, - GW_HWNDNEXT = 2, - GW_HWNDPREV = 3, - GW_OWNER = 4, - GW_CHILD = 5, - GW_ENABLEDPOPUP = 6 - } -} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs index 4b1c80e90..063623e25 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs @@ -27,15 +27,7 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [Flags] [SuppressMessage("ReSharper", "InconsistentNaming")] public enum ProcessAccessFlags : uint { - All = 0x001F0FFF, - Terminate = 0x00000001, - CreateThread = 0x00000002, - VMOperation = 0x00000008, VMRead = 0x00000010, - VMWrite = 0x00000020, - DupHandle = 0x00000040, - SetInformation = 0x00000200, QueryInformation = 0x00000400, - Synchronize = 0x00100000 } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs index 142c58ee9..b9ef9536f 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs @@ -27,7 +27,5 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums public enum RegionResult { REGION_ERROR = 0, REGION_NULLREGION = 1, - REGION_SIMPLEREGION = 2, - REGION_COMPLEXREGION = 3 } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs index df1b55a8d..e8cbd4390 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs @@ -30,9 +30,6 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [Flags] [SuppressMessage("ReSharper", "InconsistentNaming")] public enum SendMessageTimeoutFlags : uint { - SMTO_NORMAL = 0x0, - SMTO_BLOCK = 0x1, - SMTO_ABORTIFHUNG = 0x2, - SMTO_NOTIMEOUTIFNOTHUNG = 0x8 + SMTO_NORMAL = 0x0 } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs index b61a82395..8104a5dea 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs @@ -31,15 +31,9 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum SoundFlags { - SND_SYNC = 0x0000, // play synchronously (default) SND_ASYNC = 0x0001, // play asynchronously - SND_NODEFAULT = 0x0002, // silence (!default) if sound not found SND_MEMORY = 0x0004, // pszSound points to a memory file - SND_LOOP = 0x0008, // loop the sound until next sndPlaySound SND_NOSTOP = 0x0010, // don't stop any currently playing sound SND_NOWAIT = 0x00002000, // don't wait if the driver is busy - SND_ALIAS = 0x00010000, // name is a registry alias - SND_ALIAS_ID = 0x00110000, // alias is a predefined id - SND_FILENAME = 0x00020000, // name is file name } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs index 010950e51..d71a3803e 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs @@ -27,10 +27,6 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums public enum WindowLongIndex { GWL_EXSTYLE = -20, // Sets a new extended window style. - GWL_HINSTANCE = -6, // Sets a new application instance handle. - GWL_ID = -12, // Sets a new identifier of the child window. The window cannot be a top-level window. GWL_STYLE = -16, // Sets a new window style. - GWL_USERDATA = -21, // Sets the user data associated with the window. This data is intended for use by the application that created the window. Its value is initially zero. - GWL_WNDPROC = -4 // Sets a new address for the window procedure. You cannot change this attribute if the window does not belong to the same process as the calling thread. } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs index b0045e3e5..48988c643 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs @@ -29,58 +29,6 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums { [Flags] [SuppressMessage("ReSharper", "InconsistentNaming")] public enum WindowStyleFlags : long { - //WS_OVERLAPPED = 0x00000000, - WS_POPUP = 0x80000000, - WS_CHILD = 0x40000000, - WS_MINIMIZE = 0x20000000, WS_VISIBLE = 0x10000000, - WS_DISABLED = 0x08000000, - WS_CLIPSIBLINGS = 0x04000000, - WS_CLIPCHILDREN = 0x02000000, - WS_MAXIMIZE = 0x01000000, - WS_BORDER = 0x00800000, - WS_DLGFRAME = 0x00400000, - WS_VSCROLL = 0x00200000, - WS_HSCROLL = 0x00100000, - WS_SYSMENU = 0x00080000, - WS_THICKFRAME = 0x00040000, - WS_GROUP = 0x00020000, - WS_TABSTOP = 0x00010000, - - WS_UNK8000 = 0x00008000, - WS_UNK4000 = 0x00004000, - WS_UNK2000 = 0x00002000, - WS_UNK1000 = 0x00001000, - WS_UNK800 = 0x00000800, - WS_UNK400 = 0x00000400, - WS_UNK200 = 0x00000200, - WS_UNK100 = 0x00000100, - WS_UNK80 = 0x00000080, - WS_UNK40 = 0x00000040, - WS_UNK20 = 0x00000020, - WS_UNK10 = 0x00000010, - WS_UNK8 = 0x00000008, - WS_UNK4 = 0x00000004, - WS_UNK2 = 0x00000002, - WS_UNK1 = 0x00000001, - - //WS_MINIMIZEBOX = 0x00020000, - //WS_MAXIMIZEBOX = 0x00010000, - - //WS_CAPTION = WS_BORDER | WS_DLGFRAME, - //WS_TILED = WS_OVERLAPPED, - //WS_ICONIC = WS_MINIMIZE, - //WS_SIZEBOX = WS_THICKFRAME, - //WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW, - - //WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, - //WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU - //WS_CHILDWINDOW = WS_CHILD } - - // See http://msdn.microsoft.com/en-us/library/aa969530(v=vs.85).aspx - - // Get/Set WindowLong Enum See: http://msdn.microsoft.com/en-us/library/ms633591.aspx - - // See: http://msdn.microsoft.com/en-us/library/ms633545.aspx } diff --git a/GreenshotPlugin/UnmanagedHelpers/User32.cs b/GreenshotPlugin/UnmanagedHelpers/User32.cs index 818e7c64d..784b7d129 100644 --- a/GreenshotPlugin/UnmanagedHelpers/User32.cs +++ b/GreenshotPlugin/UnmanagedHelpers/User32.cs @@ -72,11 +72,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { [DllImport("user32", SetLastError = true)] public static extern IntPtr GetParent(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowCommand uCmd); - [DllImport("user32", SetLastError = true)] - public static extern int ShowWindow(IntPtr hWnd, ShowWindowCommand nCmdShow); - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int cch); [DllImport("user32", SetLastError = true)] @@ -191,18 +187,7 @@ namespace GreenshotPlugin.UnmanagedHelpers { [DllImport("user32", SetLastError = true)] public static extern bool CloseDesktop(IntPtr hDesktop); - /// <summary> - /// The GetWindowDC function retrieves the device context (DC) for the entire window, including title bar, menus, and scroll bars. A window device context permits painting anywhere in a window, because the origin of the device context is the upper-left corner of the window instead of the client area. - /// GetWindowDC assigns default attributes to the window device context each time it retrieves the device context.Previous attributes are lost. - /// See <a href="https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowdc">GetWindowDC function</a> - /// </summary> - /// <param name="hWnd">A handle to the window whose DC is to be retrieved. If this value is NULL, GetWindowDC retrieves the DC for the entire screen.</param> - /// <returns>If the function succeeds, the return value is a handle to a device context for the specified window.</returns> - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetWindowDC(IntPtr hWnd); - - - /// <summary> + /// <summary> /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. /// </summary> /// <returns>Point with cursor location, relative to the origin of the monitor setup diff --git a/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs b/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs index fb48f4a5b..e342f87ae 100644 --- a/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs +++ b/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs @@ -29,22 +29,6 @@ namespace GreenshotWin10Plugin.Internal /// </summary> internal sealed class MemoryRandomAccessStream : MemoryStream, IRandomAccessStream { - /// <summary> - /// Default constructor - /// </summary> - public MemoryRandomAccessStream() - { - } - - /// <summary> - /// Constructor where also bytes are already passed - /// </summary> - /// <param name="bytes">byte array</param> - public MemoryRandomAccessStream(byte[] bytes) - { - Write(bytes, 0, bytes.Length); - } - /// <inheritdoc /> public IInputStream GetInputStreamAt(ulong position) { From d637efbb70459f7280cef28cc97377c8d6069300 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Mon, 22 Mar 2021 00:09:16 +0100 Subject: [PATCH 104/232] BUG-2748 and fixed #295 - Do not remove the default constructor on a destination... --- Greenshot/Destinations/EditorDestination.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Greenshot/Destinations/EditorDestination.cs b/Greenshot/Destinations/EditorDestination.cs index dda45ed37..220359238 100644 --- a/Greenshot/Destinations/EditorDestination.cs +++ b/Greenshot/Destinations/EditorDestination.cs @@ -40,6 +40,11 @@ namespace Greenshot.Destinations { private readonly IImageEditor editor; private static readonly Image greenshotIcon = GreenshotResources.GetGreenshotIcon().ToBitmap(); + public EditorDestination() + { + // Do not remove, is needed for the framework + } + public EditorDestination(IImageEditor editor) { this.editor = editor; } From e9d12dbe4e85d167869a16e99cdc4b72c3ce53ef Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Tue, 23 Mar 2021 09:05:46 +0100 Subject: [PATCH 105/232] When moving from graphics.DrawString to TextRenderer.DrawText, to fix #283, the line wrapping was broken. This should fix it. (#297) --- Greenshot/Drawing/TextContainer.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Greenshot/Drawing/TextContainer.cs b/Greenshot/Drawing/TextContainer.cs index fda883f16..9d3838580 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/Greenshot/Drawing/TextContainer.cs @@ -598,9 +598,15 @@ namespace Greenshot.Drawing DrawText(graphics, rect, lineThickness, lineColor, drawShadow, _stringFormat, text, _font); } + /// <summary> + /// Convert the StringFormat information into a TextFormatFlags + /// This is important for the rending to work, have it aligned to the correct place + /// </summary> + /// <param name="stringFormat">StringFormat</param> + /// <returns>TextFormatFlags</returns> private static TextFormatFlags ConvertStringFormat(StringFormat stringFormat) { - TextFormatFlags flags = TextFormatFlags.Default; + var flags = TextFormatFlags.TextBoxControl | TextFormatFlags.WordBreak; if (stringFormat == null) { return flags; @@ -683,14 +689,7 @@ namespace Greenshot.Drawing drawingRectange.Inflate(-textOffset, -textOffset); } - if (stringFormat != null) - { - TextRenderer.DrawText(graphics, text, font, drawingRectange, fontColor, ConvertStringFormat(stringFormat)); - } - else - { - TextRenderer.DrawText(graphics, text, font, drawingRectange, fontColor); - } + TextRenderer.DrawText(graphics, text, font, drawingRectange, fontColor, ConvertStringFormat(stringFormat)); } public override bool ClickableAt(int x, int y) From b22d982f367633382cdb74252db60566abe417ff Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Fri, 26 Mar 2021 22:30:28 +0100 Subject: [PATCH 106/232] Revert of the change to the DWMWINDOWATTRIBUTE, as the enum values were not fixed we lost some functionality. Also fixed some potential issues with the ThumbnailForm, and aligned a bit of code with Dapplo.Window [skip ci] --- Greenshot/Forms/MainForm.cs | 46 +++++--- Greenshot/Helpers/CaptureHelper.cs | 2 +- GreenshotPlugin/Controls/ThumbnailForm.cs | 99 +++++++++------- GreenshotPlugin/Core/WindowDetails.cs | 108 +++++++++++------- GreenshotPlugin/UnmanagedHelpers/DWM.cs | 5 +- .../Enums/DWMWINDOWATTRIBUTE.cs | 14 +++ .../UnmanagedHelpers/Structs/SIZE.cs | 2 + 7 files changed, 174 insertions(+), 102 deletions(-) diff --git a/Greenshot/Forms/MainForm.cs b/Greenshot/Forms/MainForm.cs index ccb6b9a4f..fb35500b6 100644 --- a/Greenshot/Forms/MainForm.cs +++ b/Greenshot/Forms/MainForm.cs @@ -918,7 +918,7 @@ namespace Greenshot.Forms { private void ShowThumbnailOnEnter(object sender, EventArgs e) { if (sender is not ToolStripMenuItem captureWindowItem) return; - WindowDetails window = captureWindowItem.Tag as WindowDetails; + var window = captureWindowItem.Tag as WindowDetails; if (_thumbnailForm == null) { _thumbnailForm = new ThumbnailForm(); } @@ -939,29 +939,39 @@ namespace Greenshot.Forms { _thumbnailForm = null; } + /// <summary> + /// Create the "capture window from list" list + /// </summary> + /// <param name="menuItem">ToolStripMenuItem</param> + /// <param name="eventHandler">EventHandler</param> public void AddCaptureWindowMenuItems(ToolStripMenuItem menuItem, EventHandler eventHandler) { menuItem.DropDownItems.Clear(); // check if thumbnailPreview is enabled and DWM is enabled bool thumbnailPreview = _conf.ThumnailPreview && DWM.IsDwmEnabled; - foreach(WindowDetails window in WindowDetails.GetTopLevelWindows()) { - + foreach(var window in WindowDetails.GetTopLevelWindows()) { + if (LOG.IsDebugEnabled) + { + LOG.Debug(window.ToString()); + } string title = window.Text; - if (title != null) { - if (title.Length > _conf.MaxMenuItemLength) { - title = title.Substring(0, Math.Min(title.Length, _conf.MaxMenuItemLength)); - } - ToolStripItem captureWindowItem = menuItem.DropDownItems.Add(title); - captureWindowItem.Tag = window; - captureWindowItem.Image = window.DisplayIcon; - captureWindowItem.Click += eventHandler; - // Only show preview when enabled - if (thumbnailPreview) { - captureWindowItem.MouseEnter += ShowThumbnailOnEnter; - captureWindowItem.MouseLeave += HideThumbnailOnLeave; - } - } - } + if (string.IsNullOrEmpty(title)) + { + continue; + } + if (title.Length > _conf.MaxMenuItemLength) { + title = title.Substring(0, Math.Min(title.Length, _conf.MaxMenuItemLength)); + } + ToolStripItem captureWindowItem = menuItem.DropDownItems.Add(title); + captureWindowItem.Tag = window; + captureWindowItem.Image = window.DisplayIcon; + captureWindowItem.Click += eventHandler; + // Only show preview when enabled + if (thumbnailPreview) { + captureWindowItem.MouseEnter += ShowThumbnailOnEnter; + captureWindowItem.MouseLeave += HideThumbnailOnLeave; + } + } } private void CaptureAreaToolStripMenuItemClick(object sender, EventArgs e) { diff --git a/Greenshot/Helpers/CaptureHelper.cs b/Greenshot/Helpers/CaptureHelper.cs index 19acda012..813a18b4f 100644 --- a/Greenshot/Helpers/CaptureHelper.cs +++ b/Greenshot/Helpers/CaptureHelper.cs @@ -970,7 +970,7 @@ namespace Greenshot.Helpers { // The following, to be precise the HideApp, causes the app to close as described in BUG-1620 // Added check for metro (Modern UI) apps, which might be maximized and cover the screen. - //foreach(WindowDetails app in WindowDetails.GetMetroApps()) { + //foreach(WindowDetails app in WindowDetails.GetAppWindows()) { // if (app.Maximised) { // app.HideApp(); // } diff --git a/GreenshotPlugin/Controls/ThumbnailForm.cs b/GreenshotPlugin/Controls/ThumbnailForm.cs index 3578b63d3..aae16b46c 100644 --- a/GreenshotPlugin/Controls/ThumbnailForm.cs +++ b/GreenshotPlugin/Controls/ThumbnailForm.cs @@ -22,6 +22,7 @@ using System; using System.Windows.Forms; using GreenshotPlugin.Core; using System.Drawing; +using GreenshotPlugin.Core.Enums; using GreenshotPlugin.IniFile; using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.UnmanagedHelpers.Enums; @@ -32,7 +33,7 @@ namespace GreenshotPlugin.Controls { /// This form allows us to show a Thumbnail preview of a window near the context menu when selecting a window to capture. /// Didn't make it completely "generic" yet, but at least most logic is in here so we don't have it in the mainform. /// </summary> - public class ThumbnailForm : FormWithoutActivation { + public sealed class ThumbnailForm : FormWithoutActivation { private static readonly CoreConfiguration conf = IniConfig.GetIniSection<CoreConfiguration>(); private IntPtr _thumbnailHandle = IntPtr.Zero; @@ -59,12 +60,13 @@ namespace GreenshotPlugin.Controls { base.Hide(); } - private void UnregisterThumbnail() { - if (_thumbnailHandle != IntPtr.Zero) { - DWM.DwmUnregisterThumbnail(_thumbnailHandle); - _thumbnailHandle = IntPtr.Zero; - } - } + private void UnregisterThumbnail() + { + if (_thumbnailHandle == IntPtr.Zero) return; + + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + _thumbnailHandle = IntPtr.Zero; + } /// <summary> /// Show the thumbnail of the supplied window above (or under) the parent Control @@ -75,41 +77,60 @@ namespace GreenshotPlugin.Controls { UnregisterThumbnail(); DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle); - if (_thumbnailHandle != IntPtr.Zero) { - DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize); - int thumbnailHeight = 200; - int thumbnailWidth = (int)(thumbnailHeight * (sourceSize.Width / (float)sourceSize.Height)); - if (parentControl != null && thumbnailWidth > parentControl.Width) { - thumbnailWidth = parentControl.Width; - thumbnailHeight = (int)(thumbnailWidth * (sourceSize.Height / (float)sourceSize.Width)); - } - Width = thumbnailWidth; - Height = thumbnailHeight; - // Prepare the displaying of the Thumbnail - DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES - { - Opacity = 255, - Visible = true, - SourceClientAreaOnly = false, - Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight) - }; - DWM.DwmUpdateThumbnailProperties(_thumbnailHandle, ref props); - if (parentControl != null) { - AlignToControl(parentControl); - } + if (_thumbnailHandle == IntPtr.Zero) return; - if (!Visible) { - Show(); - } - // Make sure it's on "top"! - if (parentControl != null) { - User32.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE); - } - } - } + var result = DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize); + if (result.Failed()) + { + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + return; + } + + if (sourceSize.IsEmpty) + { + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + return; + } + + int thumbnailHeight = 200; + int thumbnailWidth = (int)(thumbnailHeight * (sourceSize.Width / (float)sourceSize.Height)); + if (parentControl != null && thumbnailWidth > parentControl.Width) + { + thumbnailWidth = parentControl.Width; + thumbnailHeight = (int)(thumbnailWidth * (sourceSize.Height / (float)sourceSize.Width)); + } + Width = thumbnailWidth; + Height = thumbnailHeight; + // Prepare the displaying of the Thumbnail + var dwmThumbnailProperties = new DWM_THUMBNAIL_PROPERTIES + { + Opacity = 255, + Visible = true, + SourceClientAreaOnly = false, + Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight) + }; + result = DWM.DwmUpdateThumbnailProperties(_thumbnailHandle, ref dwmThumbnailProperties); + if (result.Failed()) + { + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + return; + } + + if (parentControl != null) { + AlignToControl(parentControl); + } + + if (!Visible) { + Show(); + } + // Make sure it's on "top"! + if (parentControl != null) { + User32.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE); + } + } public void AlignToControl(Control alignTo) { - Rectangle screenBounds = WindowCapture.GetScreenBounds(); + var screenBounds = WindowCapture.GetScreenBounds(); if (screenBounds.Contains(alignTo.Left, alignTo.Top - Height)) { Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Top - Height); } else { diff --git a/GreenshotPlugin/Core/WindowDetails.cs b/GreenshotPlugin/Core/WindowDetails.cs index a2d3d9a63..903483c0c 100644 --- a/GreenshotPlugin/Core/WindowDetails.cs +++ b/GreenshotPlugin/Core/WindowDetails.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Drawing; +using System.Drawing.Drawing2D; using System.Drawing.Imaging; +using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; @@ -25,11 +27,11 @@ namespace GreenshotPlugin.Core /// /// Provides details about a Window returned by the enumeration /// </summary> - public class WindowDetails : IEquatable<WindowDetails>{ - private const string MetroWindowsClass = "Windows.UI.Core.CoreWindow"; //Used for Windows 8(.1) - private const string FramedAppClass = "ApplicationFrameWindow"; // Windows 10 uses ApplicationFrameWindow - private const string MetroApplauncherClass = "ImmersiveLauncher"; - private const string MetroGutterClass = "ImmersiveGutter"; + public class WindowDetails : IEquatable<WindowDetails> { + private const string AppWindowClass = "Windows.UI.Core.CoreWindow"; //Used for Windows 8(.1) + private const string AppFrameWindowClass = "ApplicationFrameWindow"; // Windows 10 uses ApplicationFrameWindow + private const string ApplauncherClass = "ImmersiveLauncher"; + private const string GutterClass = "ImmersiveGutter"; private static readonly IList<string> IgnoreClasses = new List<string>(new[] { "Progman", "Button", "Dwm" }); //"MS-SDIa" private static readonly ILog Log = LogManager.GetLogger(typeof(WindowDetails)); @@ -72,23 +74,28 @@ namespace GreenshotPlugin.Core /// This checks if the window is a Windows 8 App /// For Windows 10 most normal code works, as it's hosted inside "ApplicationFrameWindow" /// </summary> - public bool IsApp => MetroWindowsClass.Equals(ClassName); + public bool IsApp => AppWindowClass.Equals(ClassName); /// <summary> /// This checks if the window is a Windows 10 App /// For Windows 10 apps are hosted inside "ApplicationFrameWindow" /// </summary> - public bool IsWin10App => FramedAppClass.Equals(ClassName); + public bool IsWin10App => AppFrameWindowClass.Equals(ClassName); + /// <summary> + /// Check if this window belongs to a background app + /// </summary> + public bool IsBackgroundWin10App => WindowsVersion.IsWindows10OrLater && AppFrameWindowClass.Equals(ClassName) && !Children.Any(window => string.Equals(window.ClassName, AppWindowClass)); + /// <summary> /// Check if the window is the metro gutter (sizeable separator) /// </summary> - public bool IsGutter => MetroGutterClass.Equals(ClassName); + public bool IsGutter => GutterClass.Equals(ClassName); /// <summary> /// Test if this window is for the App-Launcher /// </summary> - public bool IsAppLauncher => MetroApplauncherClass.Equals(ClassName); + public bool IsAppLauncher => ApplauncherClass.Equals(ClassName); /// <summary> /// Check if this window is the window of a metro app @@ -447,7 +454,7 @@ namespace GreenshotPlugin.Core /// </summary> public bool Visible { get { - // Tip from Raymond Chen + // Tip from Raymond Chen https://devblogs.microsoft.com/oldnewthing/20200302-00/?p=103507 if (IsCloaked) { return false; @@ -1337,7 +1344,7 @@ namespace GreenshotPlugin.Core /// <returns>List WindowDetails with all the visible top level windows</returns> public static IEnumerable<WindowDetails> GetVisibleWindows() { Rectangle screenBounds = WindowCapture.GetScreenBounds(); - foreach(var window in GetMetroApps()) { + foreach(var window in GetAppWindows()) { if (IsVisible(window, screenBounds)) { yield return window; @@ -1357,37 +1364,24 @@ namespace GreenshotPlugin.Core /// These are all Windows with Classname "Windows.UI.Core.CoreWindow" /// </summary> /// <returns>List WindowDetails with visible metro apps</returns> - public static IEnumerable<WindowDetails> GetMetroApps() { + public static IEnumerable<WindowDetails> GetAppWindows() { // if the appVisibility != null we have Windows 8. if (AppVisibility == null) { yield break; } - //string[] wcs = {"ImmersiveGutter", "Snapped Desktop", "ImmersiveBackgroundWindow","ImmersiveLauncher","Windows.UI.Core.CoreWindow","ApplicationManager_ImmersiveShellWindow","SearchPane","MetroGhostWindow","EdgeUiInputWndClass", "NativeHWNDHost", "Shell_CharmWindow"}; - //List<WindowDetails> specials = new List<WindowDetails>(); - //foreach(string wc in wcs) { - // IntPtr wcHandle = User32.FindWindow(null, null); - // while (wcHandle != IntPtr.Zero) { - // WindowDetails special = new WindowDetails(wcHandle); - // if (special.WindowRectangle.Left >= 1920 && special.WindowRectangle.Size != Size.Empty) { - // specials.Add(special); - // LOG.DebugFormat("Found special {0} : {1} at {2} visible: {3} {4} {5}", special.ClassName, special.Text, special.WindowRectangle, special.Visible, special.ExtendedWindowStyle, special.WindowStyle); - // } - // wcHandle = User32.FindWindowEx(IntPtr.Zero, wcHandle, null, null); - // }; - //} - IntPtr nextHandle = User32.FindWindow(MetroWindowsClass, null); + var nextHandle = User32.FindWindow(AppWindowClass, null); while (nextHandle != IntPtr.Zero) { var metroApp = new WindowDetails(nextHandle); yield return metroApp; // Check if we have a gutter! if (metroApp.Visible && !metroApp.Maximised) { - var gutterHandle = User32.FindWindow(MetroGutterClass, null); + var gutterHandle = User32.FindWindow(GutterClass, null); if (gutterHandle != IntPtr.Zero) { yield return new WindowDetails(gutterHandle); } } - nextHandle = User32.FindWindowEx(IntPtr.Zero, nextHandle, MetroWindowsClass, null); + nextHandle = User32.FindWindowEx(IntPtr.Zero, nextHandle, AppWindowClass, null); } } @@ -1398,21 +1392,10 @@ namespace GreenshotPlugin.Core /// <returns>bool</returns> private static bool IsTopLevel(WindowDetails window) { - // Window is not on this desktop if (window.IsCloaked) { return false; } - - // Ignore windows without title - if (window.Text.Length == 0) - { - return false; - } - if (IgnoreClasses.Contains(window.ClassName)) - { - return false; - } // Windows without size if (window.WindowRectangle.Size.Width * window.WindowRectangle.Size.Height == 0) { @@ -1437,7 +1420,21 @@ namespace GreenshotPlugin.Core { return false; } - return window.Visible || window.Iconic; + // Ignore windows without title + if (window.Text.Length == 0) + { + return false; + } + if (IgnoreClasses.Contains(window.ClassName)) + { + return false; + } + if (!(window.Visible || window.Iconic)) + { + return false; + } + + return !window.IsBackgroundWin10App; } /// <summary> @@ -1445,7 +1442,7 @@ namespace GreenshotPlugin.Core /// </summary> /// <returns>List WindowDetails with all the top level windows</returns> public static IEnumerable<WindowDetails> GetTopLevelWindows() { - foreach (var possibleTopLevel in GetMetroApps()) + foreach (var possibleTopLevel in GetAppWindows()) { if (IsTopLevel(possibleTopLevel)) { @@ -1523,7 +1520,7 @@ namespace GreenshotPlugin.Core if (AppVisibility == null) { return null; } - IntPtr appLauncher = User32.FindWindow(MetroApplauncherClass, null); + IntPtr appLauncher = User32.FindWindow(ApplauncherClass, null); if (appLauncher != IntPtr.Zero) { return new WindowDetails (appLauncher); } @@ -1542,5 +1539,32 @@ namespace GreenshotPlugin.Core return false; } } + + /// <summary> + /// Make a string representation of the window details + /// </summary> + /// <returns>string</returns> + public override string ToString() + { + var result = new StringBuilder(); + result.AppendLine($"Text: {Text}"); + result.AppendLine($"ClassName: {ClassName}"); + result.AppendLine($"ExtendedWindowStyle: {ExtendedWindowStyle}"); + result.AppendLine($"WindowStyle: {WindowStyle}"); + result.AppendLine($"Size: {WindowRectangle.Size}"); + result.AppendLine($"HasParent: {HasParent}"); + result.AppendLine($"IsWin10App: {IsWin10App}"); + result.AppendLine($"IsApp: {IsApp}"); + result.AppendLine($"Visible: {Visible}"); + result.AppendLine($"IsWindowVisible: {User32.IsWindowVisible(Handle)}"); + result.AppendLine($"IsCloaked: {IsCloaked}"); + result.AppendLine($"Iconic: {Iconic}"); + result.AppendLine($"IsBackgroundWin10App: {IsBackgroundWin10App}"); + if (HasChildren) + { + result.AppendLine($"Children classes: {string.Join(",", Children.Select(c => c.ClassName))}"); + } + return result.ToString(); + } } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/DWM.cs b/GreenshotPlugin/UnmanagedHelpers/DWM.cs index b95a766ba..eed7c71e5 100644 --- a/GreenshotPlugin/UnmanagedHelpers/DWM.cs +++ b/GreenshotPlugin/UnmanagedHelpers/DWM.cs @@ -23,6 +23,7 @@ using System; using System.Drawing; using System.Runtime.InteropServices; using GreenshotPlugin.Core; +using GreenshotPlugin.Core.Enums; using GreenshotPlugin.UnmanagedHelpers.Enums; using GreenshotPlugin.UnmanagedHelpers.Structs; using Microsoft.Win32; @@ -40,9 +41,9 @@ namespace GreenshotPlugin.UnmanagedHelpers { [DllImport("dwmapi", SetLastError = true)] public static extern int DwmUnregisterThumbnail(IntPtr thumb); [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size); + public static extern HResult DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size); [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); + public static extern HResult DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); // Deprecated as of Windows 8 Release Preview [DllImport("dwmapi", SetLastError = true)] diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs b/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs index 04490cd17..e58bde613 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs @@ -26,7 +26,21 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum DWMWINDOWATTRIBUTE : uint { + DWMWA_NCRENDERING_ENABLED = 1, + DWMWA_NCRENDERING_POLICY, + DWMWA_TRANSITIONS_FORCEDISABLED, + DWMWA_ALLOW_NCPAINT, + DWMWA_CAPTION_BUTTON_BOUNDS, + DWMWA_NONCLIENT_RTL_LAYOUT, + DWMWA_FORCE_ICONIC_REPRESENTATION, + DWMWA_FLIP3D_POLICY, DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista + DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7 + DWMWA_DISALLOW_PEEK, // Since Windows 7 + DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7 + DWMWA_CLOAK, // Since Windows 8 DWMWA_CLOAKED, // Since Windows 8 + DWMWA_FREEZE_REPRESENTATION, // Since Windows 8 + DWMWA_LAST } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs b/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs index be5d00bbc..bd1b78699 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs +++ b/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs @@ -40,5 +40,7 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs { public Size ToSize() { return new Size(Width, Height); } + + public bool IsEmpty => Width * Height == 0; } } From 19fb98ae5547c22f792f4878083960e2b2b91337 Mon Sep 17 00:00:00 2001 From: Robin Krom <robin@getgreenshot.org> Date: Sat, 27 Mar 2021 00:11:06 +0100 Subject: [PATCH 107/232] Get rid of embedded browser (#255) This change makes it possible to use Box, DropBox and Imgur with the default browser, instead of the embedded which causes many issues. Other plugins need to follow. --- Directory.Build.props | 24 +- Greenshot.sln | 2 +- Greenshot/Drawing/CursorContainer.cs | 6 +- Greenshot/Drawing/DrawableContainer.cs | 18 +- Greenshot/Drawing/IconContainer.cs | 37 +- Greenshot/Drawing/ImageContainer.cs | 58 +- Greenshot/Forms/AboutForm.Designer.cs | 1 + Greenshot/Helpers/EnvironmentInfo.cs | 786 ----------- Greenshot/releases/innosetup/setup.iss | 6 +- GreenshotBoxPlugin/BoxDestination.cs | 12 +- GreenshotBoxPlugin/BoxUtils.cs | 7 +- .../GreenshotBoxPlugin.Credentials.template | 4 +- GreenshotDropboxPlugin/DropboxDestination.cs | 16 +- GreenshotDropboxPlugin/DropboxPlugin.cs | 38 +- .../DropboxPluginConfiguration.cs | 26 +- GreenshotDropboxPlugin/DropboxUtils.cs | 93 +- ...reenshotDropboxPlugin.Credentials.template | 4 +- GreenshotFlickrPlugin/FlickrUtils.cs | 1 + .../Forms/GooglePhotosForm.cs | 6 +- .../Forms/SettingsForm.Designer.cs | 294 ++-- .../Forms/SettingsForm.cs | 76 +- GreenshotGooglePhotosPlugin/GooglePhotos.png | Bin 0 -> 12803 bytes .../GooglePhotosConfiguration.cs | 186 +-- .../GooglePhotosDestination.cs | 108 +- .../GooglePhotosPlugin.cs | 249 ++-- .../GooglePhotosPlugin.resx | 4 +- .../GooglePhotosUtils.cs | 239 ++-- ...hotGooglePhotosPlugin.Credentials.template | 8 +- .../GreenshotGooglePhotosPlugin.csproj | 34 +- .../LanguageKeys.cs | 58 +- .../language_googlephotosplugin-cs-CZ.xml | 56 +- .../language_googlephotosplugin-de-DE.xml | 12 +- .../language_googlephotosplugin-en-US.xml | 12 +- .../language_googlephotosplugin-fr-FR.xml | 26 +- .../language_googlephotosplugin-id-ID.xml | 26 +- .../language_googlephotosplugin-it-IT.xml | 64 +- .../language_googlephotosplugin-ja-JP.xml | 14 + .../language_googlephotosplugin-kab-DZ.xml | 12 +- .../language_googlephotosplugin-ko-KR.xml | 12 +- .../language_googlephotosplugin-lv-LV.xml | 12 +- .../language_googlephotosplugin-pl-PL.xml | 14 + .../language_googlephotosplugin-pt-PT.xml | 12 +- .../language_googlephotosplugin-ru-RU.xml | 26 +- .../language_googlephotosplugin-sr-RS.xml | 26 +- .../language_googlephotosplugin-sv-SE.xml | 12 +- .../language_googlephotosplugin-uk-UA.xml | 28 +- .../language_googlephotosplugin-zh-CN.xml | 14 + .../language_googlephotosplugin-zh-TW.xml | 14 + .../Properties/AssemblyInfo.cs | 2 +- .../README | 0 .../GreenshotImgurPlugin.Credentials.template | 4 +- GreenshotImgurPlugin/ImgurUtils.cs | 20 +- .../PhotobucketUtils.cs | 1 + .../Languages/language_picasaplugin-ja-JP.xml | 14 - .../Languages/language_picasaplugin-pl-PL.xml | 14 - .../Languages/language_picasaplugin-zh-CN.xml | 14 - .../Languages/language_picasaplugin-zh-TW.xml | 14 - GreenshotPicasaPlugin/Picasa.png | Bin 4954 -> 0 bytes GreenshotPlugin/Controls/OAuthLoginForm.cs | 17 +- GreenshotPlugin/Core/EnvironmentInfo.cs | 793 +++++++++++ GreenshotPlugin/Core/NetworkHelper.cs | 981 +++++++------ .../Core/OAuth/LocalJsonReceiver.cs | 191 +++ .../Core/OAuth/LocalServerCodeReceiver.cs | 183 +++ .../Core/OAuth/OAuth2AuthorizeMode.cs | 33 + GreenshotPlugin/Core/OAuth/OAuth2Helper.cs | 372 +++++ GreenshotPlugin/Core/OAuth/OAuth2Settings.cs | 181 +++ GreenshotPlugin/Core/OAuth/OAuthSession.cs | 629 +++++++++ .../Core/OAuth/OAuthSignatureTypes.cs | 31 + GreenshotPlugin/Core/OAuthHelper.cs | 1253 ----------------- GreenshotPlugin/Core/WindowDetails.cs | 27 - azure-pipelines.yml | 12 +- 71 files changed, 4037 insertions(+), 3542 deletions(-) delete mode 100644 Greenshot/Helpers/EnvironmentInfo.cs rename GreenshotPicasaPlugin/Forms/PicasaForm.cs => GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs (85%) rename {GreenshotPicasaPlugin => GreenshotGooglePhotosPlugin}/Forms/SettingsForm.Designer.cs (91%) rename {GreenshotPicasaPlugin => GreenshotGooglePhotosPlugin}/Forms/SettingsForm.cs (86%) create mode 100644 GreenshotGooglePhotosPlugin/GooglePhotos.png rename GreenshotPicasaPlugin/PicasaConfiguration.cs => GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs (72%) rename GreenshotPicasaPlugin/PicasaDestination.cs => GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs (75%) rename GreenshotPicasaPlugin/PicasaPlugin.cs => GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs (68%) rename GreenshotPicasaPlugin/PicasaPlugin.resx => GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx (96%) rename GreenshotPicasaPlugin/PicasaUtils.cs => GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs (74%) rename GreenshotPicasaPlugin/GreenshotPicasaPlugin.Credentials.template => GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template (83%) rename GreenshotPicasaPlugin/GreenshotPicasaPlugin.csproj => GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj (62%) rename {GreenshotPicasaPlugin => GreenshotGooglePhotosPlugin}/LanguageKeys.cs (89%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-cs-CZ.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml (74%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-de-DE.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml (74%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-en-US.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml (73%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-fr-FR.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml (62%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-id-ID.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml (58%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-it-IT.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml (73%) create mode 100644 GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml rename GreenshotPicasaPlugin/Languages/language_picasaplugin-kab-DZ.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml (59%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-ko-KR.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml (74%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-lv-LV.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml (75%) create mode 100644 GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml rename GreenshotPicasaPlugin/Languages/language_picasaplugin-pt-PT.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml (73%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-ru-RU.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml (61%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-sr-RS.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml (98%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-sv-SE.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml (73%) rename GreenshotPicasaPlugin/Languages/language_picasaplugin-uk-UA.xml => GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml (53%) create mode 100644 GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml create mode 100644 GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml rename {GreenshotPicasaPlugin => GreenshotGooglePhotosPlugin}/Properties/AssemblyInfo.cs (94%) rename {GreenshotPicasaPlugin => GreenshotGooglePhotosPlugin}/README (100%) delete mode 100644 GreenshotPicasaPlugin/Languages/language_picasaplugin-ja-JP.xml delete mode 100644 GreenshotPicasaPlugin/Languages/language_picasaplugin-pl-PL.xml delete mode 100644 GreenshotPicasaPlugin/Languages/language_picasaplugin-zh-CN.xml delete mode 100644 GreenshotPicasaPlugin/Languages/language_picasaplugin-zh-TW.xml delete mode 100644 GreenshotPicasaPlugin/Picasa.png create mode 100644 GreenshotPlugin/Core/EnvironmentInfo.cs create mode 100644 GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs create mode 100644 GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs create mode 100644 GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs create mode 100644 GreenshotPlugin/Core/OAuth/OAuth2Helper.cs create mode 100644 GreenshotPlugin/Core/OAuth/OAuth2Settings.cs create mode 100644 GreenshotPlugin/Core/OAuth/OAuthSession.cs create mode 100644 GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs delete mode 100644 GreenshotPlugin/Core/OAuthHelper.cs diff --git a/Directory.Build.props b/Directory.Build.props index 1a2e9d3a4..a15044b52 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -65,17 +65,17 @@ </ItemGroup> <ItemGroup> - <Tokens Include="Box_ClientId"> - <ReplacementValue>$(Box_ClientId)</ReplacementValue> + <Tokens Include="Box13_ClientId"> + <ReplacementValue>$(Box13_ClientId)</ReplacementValue> </Tokens> - <Tokens Include="Box_ClientSecret"> - <ReplacementValue>$(Box_ClientSecret)</ReplacementValue> + <Tokens Include="Box13_ClientSecret"> + <ReplacementValue>$(Box13_ClientSecret)</ReplacementValue> </Tokens> - <Tokens Include="DropBox_ClientId"> - <ReplacementValue>$(DropBox_ClientId)</ReplacementValue> + <Tokens Include="DropBox13_ClientId"> + <ReplacementValue>$(DropBox13_ClientId)</ReplacementValue> </Tokens> - <Tokens Include="DropBox_ClientSecret"> - <ReplacementValue>$(DropBox_ClientSecret)</ReplacementValue> + <Tokens Include="DropBox13_ClientSecret"> + <ReplacementValue>$(DropBox13_ClientSecret)</ReplacementValue> </Tokens> <Tokens Include="Flickr_ClientId"> <ReplacementValue>$(Flickr_ClientId)</ReplacementValue> @@ -83,11 +83,11 @@ <Tokens Include="Flickr_ClientSecret"> <ReplacementValue>$(Flickr_ClientSecret)</ReplacementValue> </Tokens> - <Tokens Include="Imgur_ClientId"> - <ReplacementValue>$(Imgur_ClientId)</ReplacementValue> + <Tokens Include="Imgur13_ClientId"> + <ReplacementValue>$(Imgur13_ClientId)</ReplacementValue> </Tokens> - <Tokens Include="Imgur_ClientSecret"> - <ReplacementValue>$(Imgur_ClientSecret)</ReplacementValue> + <Tokens Include="Imgur13_ClientSecret"> + <ReplacementValue>$(Imgur13_ClientSecret)</ReplacementValue> </Tokens> <Tokens Include="Photobucket_ClientId"> <ReplacementValue>$(Photobucket_ClientId)</ReplacementValue> diff --git a/Greenshot.sln b/Greenshot.sln index 1c0d74d59..f815631e2 100644 --- a/Greenshot.sln +++ b/Greenshot.sln @@ -34,7 +34,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotDropboxPlugin", "G EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotFlickrPlugin", "GreenshotFlickrPlugin\GreenshotFlickrPlugin.csproj", "{7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPicasaPlugin", "GreenshotPicasaPlugin\GreenshotPicasaPlugin.csproj", "{1893A2E4-A78A-4713-A8E7-E70058DABEE0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotGooglePhotosPlugin", "GreenshotGooglePhotosPlugin\GreenshotGooglePhotosPlugin.csproj", "{1893A2E4-A78A-4713-A8E7-E70058DABEE0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotOfficePlugin", "GreenshotOfficePlugin\GreenshotOfficePlugin.csproj", "{92599C09-FF29-4ABD-B6E6-C48ECD781BAB}" EndProject diff --git a/Greenshot/Drawing/CursorContainer.cs b/Greenshot/Drawing/CursorContainer.cs index 15078bd76..7b3078510 100644 --- a/Greenshot/Drawing/CursorContainer.cs +++ b/Greenshot/Drawing/CursorContainer.cs @@ -105,10 +105,6 @@ namespace Greenshot.Drawing { cursor.DrawStretched(graphics, Bounds); } - public override Size DefaultSize { - get { - return cursor.Size; - } - } + public override Size DefaultSize => cursor?.Size ?? new Size(16, 16); } } diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs index 60eb1e98d..bc0973300 100644 --- a/Greenshot/Drawing/DrawableContainer.cs +++ b/Greenshot/Drawing/DrawableContainer.cs @@ -548,23 +548,11 @@ namespace Greenshot.Drawing return ScaleHelper.ShapeAngleRoundBehavior.Instance; } - public virtual bool HasContextMenu { - get { - return true; - } - } + public virtual bool HasContextMenu => true; - public virtual bool HasDefaultSize { - get { - return false; - } - } + public virtual bool HasDefaultSize => false; - public virtual Size DefaultSize { - get { - throw new NotSupportedException("Object doesn't have a default size"); - } - } + public virtual Size DefaultSize => throw new NotSupportedException("Object doesn't have a default size"); /// <summary> /// Allows to override the initializing of the fields, so we can actually have our own defaults diff --git a/Greenshot/Drawing/IconContainer.cs b/Greenshot/Drawing/IconContainer.cs index b35ce28ff..6d5c90986 100644 --- a/Greenshot/Drawing/IconContainer.cs +++ b/Greenshot/Drawing/IconContainer.cs @@ -62,7 +62,7 @@ namespace Greenshot.Drawing { Width = value.Width; Height = value.Height; } - get { return icon; } + get => icon; } /** @@ -78,27 +78,32 @@ namespace Greenshot.Drawing { base.Dispose(disposing); } - public void Load(string filename) { - if (File.Exists(filename)) - { - using Icon fileIcon = new Icon(filename); - Icon = fileIcon; - Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); - } + public void Load(string filename) + { + if (!File.Exists(filename)) + { + return; + } + using Icon fileIcon = new Icon(filename); + Icon = fileIcon; + Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); } - public override void Draw(Graphics graphics, RenderMode rm) { - if (icon != null) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.Default; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.DrawIcon(icon, Bounds); + public override void Draw(Graphics graphics, RenderMode rm) + { + if (icon == null) + { + return; } + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.CompositingQuality = CompositingQuality.Default; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.DrawIcon(icon, Bounds); } public override bool HasDefaultSize => true; - public override Size DefaultSize => icon.Size; + public override Size DefaultSize => icon?.Size ?? new Size(16,16); } } diff --git a/Greenshot/Drawing/ImageContainer.cs b/Greenshot/Drawing/ImageContainer.cs index fee072aa1..5840c9507 100644 --- a/Greenshot/Drawing/ImageContainer.cs +++ b/Greenshot/Drawing/ImageContainer.cs @@ -77,11 +77,14 @@ namespace Greenshot.Drawing { AddField(GetType(), FieldType.SHADOW, false); } - protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { - if (sender.Equals(this)) { - if (FieldType.SHADOW.Equals(e.Field.FieldType)) { - ChangeShadowField(); - } + protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) + { + if (!sender.Equals(this)) + { + return; + } + if (FieldType.SHADOW.Equals(e.Field.FieldType)) { + ChangeShadowField(); } } @@ -189,12 +192,14 @@ namespace Greenshot.Drawing { /// This checks if a shadow is already generated /// </summary> /// <param name="shadow"></param> - private void CheckShadow(bool shadow) { - if (shadow && _shadowBitmap == null) - { - using var matrix = new Matrix(); - _shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix); - } + private void CheckShadow(bool shadow) + { + if (!shadow || _shadowBitmap != null) + { + return; + } + using var matrix = new Matrix(); + _shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix); } /// <summary> @@ -202,25 +207,28 @@ namespace Greenshot.Drawing { /// </summary> /// <param name="graphics"></param> /// <param name="rm"></param> - public override void Draw(Graphics graphics, RenderMode rm) { - if (image != null) { - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + public override void Draw(Graphics graphics, RenderMode rm) + { + if (image == null) + { + return; + } + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - if (shadow) { - CheckShadow(true); - graphics.DrawImage(_shadowBitmap, Bounds); - } else { - graphics.DrawImage(image, Bounds); - } + if (shadow) { + CheckShadow(true); + graphics.DrawImage(_shadowBitmap, Bounds); + } else { + graphics.DrawImage(image, Bounds); } } public override bool HasDefaultSize => true; - public override Size DefaultSize => image.Size; + public override Size DefaultSize => image?.Size ?? new Size(32, 32); } } diff --git a/Greenshot/Forms/AboutForm.Designer.cs b/Greenshot/Forms/AboutForm.Designer.cs index f68fd69ee..4112df177 100644 --- a/Greenshot/Forms/AboutForm.Designer.cs +++ b/Greenshot/Forms/AboutForm.Designer.cs @@ -21,6 +21,7 @@ using System.Windows.Forms; using Greenshot.Helpers; +using GreenshotPlugin.Core; namespace Greenshot.Forms { partial class AboutForm { diff --git a/Greenshot/Helpers/EnvironmentInfo.cs b/Greenshot/Helpers/EnvironmentInfo.cs deleted file mode 100644 index 9d8006416..000000000 --- a/Greenshot/Helpers/EnvironmentInfo.cs +++ /dev/null @@ -1,786 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using System; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.UnmanagedHelpers; -using Microsoft.Win32; - -namespace Greenshot.Helpers -{ - /// <summary> - /// Description of EnvironmentInfo. - /// </summary> - public static class EnvironmentInfo - { - private static bool? _isWindows; - - public static bool IsWindows - { - get - { - if (_isWindows.HasValue) - { - return _isWindows.Value; - } - _isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win"); - return _isWindows.Value; - } - } - - public static bool IsNet45OrNewer() - { - // Class "ReflectionContext" exists from .NET 4.5 onwards. - return Type.GetType("System.Reflection.ReflectionContext", false) != null; - } - - public static string GetGreenshotVersion(bool shortVersion = false) - { - var executingAssembly = Assembly.GetExecutingAssembly(); - - // Use assembly version - string greenshotVersion = executingAssembly.GetName().Version.ToString(); - - // Use AssemblyFileVersion if available - var assemblyFileVersionAttribute = executingAssembly.GetCustomAttribute<AssemblyFileVersionAttribute>(); - if (!string.IsNullOrEmpty(assemblyFileVersionAttribute?.Version)) - { - var assemblyFileVersion = new Version(assemblyFileVersionAttribute.Version); - greenshotVersion = assemblyFileVersion.ToString(3); - } - - if (!shortVersion) - { - // Use AssemblyInformationalVersion if available - var informationalVersionAttribute = executingAssembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>(); - if (!string.IsNullOrEmpty(informationalVersionAttribute?.InformationalVersion)) - { - greenshotVersion = informationalVersionAttribute.InformationalVersion; - } - } - - return greenshotVersion.Replace("+", " - "); - } - - public static string EnvironmentToString(bool newline) - { - StringBuilder environment = new StringBuilder(); - environment.Append("Software version: " + GetGreenshotVersion()); - if (IniConfig.IsPortable) { - environment.Append(" Portable"); - } - environment.Append(" (" + OsInfo.Bits + " bit)"); - - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.Append(".NET runtime version: " + Environment.Version); - if (IsNet45OrNewer()) - { - environment.Append("+"); - - } - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.Append("Time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz")); - - if (IsWindows) - { - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - - environment.Append($"OS: {OsInfo.Name}"); - if (!string.IsNullOrEmpty(OsInfo.Edition)) - { - environment.Append($" {OsInfo.Edition}"); - - } - if (!string.IsNullOrEmpty(OsInfo.ServicePack)) - { - environment.Append($" {OsInfo.ServicePack}"); - - } - environment.Append($" x{OsInfo.Bits}"); - environment.Append($" {OsInfo.VersionString}"); - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - // Get some important information for fixing GDI related Problems - environment.AppendFormat("GDI object count: {0}", User32.GetGuiResourcesGDICount()); - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.AppendFormat("User object count: {0}", User32.GetGuiResourcesUserCount()); - } - else - { - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.AppendFormat("OS: {0}", Environment.OSVersion.Platform); - } - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - // TODO: Is this needed? - // environment.AppendFormat("Surface count: {0}", Surface.Count); - - return environment.ToString(); - } - - public static string ExceptionToString(Exception ex) - { - if (ex == null) - return "null\r\n"; - - StringBuilder report = new StringBuilder(); - - report.AppendLine("Exception: " + ex.GetType()); - report.AppendLine("Message: " + ex.Message); - if (ex.Data.Count > 0) - { - report.AppendLine(); - report.AppendLine("Additional Information:"); - foreach (object key in ex.Data.Keys) - { - object data = ex.Data[key]; - if (data != null) - { - report.AppendLine(key + " : " + data); - } - } - } - if (ex is ExternalException externalException) - { - // e.g. COMException - report.AppendLine().AppendLine("ErrorCode: 0x" + externalException.ErrorCode.ToString("X")); - } - - report.AppendLine().AppendLine("Stack:").AppendLine(ex.StackTrace); - - if (ex is ReflectionTypeLoadException reflectionTypeLoadException) - { - report.AppendLine().AppendLine("LoaderExceptions: "); - foreach (Exception cbE in reflectionTypeLoadException.LoaderExceptions) - { - report.AppendLine(cbE.Message); - } - } - - if (ex.InnerException != null) - { - report.AppendLine("--- InnerException: ---"); - report.AppendLine(ExceptionToString(ex.InnerException)); - } - return report.ToString(); - } - - public static string BuildReport(Exception exception) - { - StringBuilder exceptionText = new StringBuilder(); - exceptionText.AppendLine(EnvironmentToString(true)); - exceptionText.AppendLine(ExceptionToString(exception)); - exceptionText.AppendLine("Configuration dump:"); - - return exceptionText.ToString(); - } - } - - /// <summary> - /// Provides detailed information about the host operating system. - /// Code is available at: http://www.csharp411.com/determine-windows-version-and-edition-with-c/ - /// </summary> - public static class OsInfo - { - /// <summary> - /// Determines if the current application is 32 or 64-bit. - /// </summary> - public static int Bits => IntPtr.Size * 8; - - private static string _sEdition; - - /// <summary> - /// Gets the edition of the operating system running on this computer. - /// </summary> - public static string Edition - { - get - { - if (_sEdition != null) - { - return _sEdition; //***** RETURN *****// - } - - string edition = string.Empty; - - OperatingSystem osVersion = Environment.OSVersion; - OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create(); - - if (GetVersionEx(ref osVersionInfo)) - { - int majorVersion = osVersion.Version.Major; - int minorVersion = osVersion.Version.Minor; - byte productType = osVersionInfo.ProductType; - ushort suiteMask = osVersionInfo.SuiteMask; - - if (majorVersion == 4) - { - if (productType == VER_NT_WORKSTATION) - { - // Windows NT 4.0 Workstation - edition = "Workstation"; - } - else if (productType == VER_NT_SERVER) - { - edition = (suiteMask & VER_SUITE_ENTERPRISE) != 0 ? "Enterprise Server" : "Standard Server"; - } - } - - else if (majorVersion == 5) - { - if (productType == VER_NT_WORKSTATION) - { - if ((suiteMask & VER_SUITE_PERSONAL) != 0) - { - // Windows XP Home Edition - edition = "Home"; - } - else - { - // Windows XP / Windows 2000 Professional - edition = "Professional"; - } - } - else if (productType == VER_NT_SERVER) - { - if (minorVersion == 0) - { - if ((suiteMask & VER_SUITE_DATACENTER) != 0) - { - // Windows 2000 Datacenter Server - edition = "Datacenter Server"; - } - else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0) - { - // Windows 2000 Advanced Server - edition = "Advanced Server"; - } - else - { - // Windows 2000 Server - edition = "Server"; - } - } - else - { - if ((suiteMask & VER_SUITE_DATACENTER) != 0) - { - // Windows Server 2003 Datacenter Edition - edition = "Datacenter"; - } - else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0) - { - // Windows Server 2003 Enterprise Edition - edition = "Enterprise"; - } - else if ((suiteMask & VER_SUITE_BLADE) != 0) - { - // Windows Server 2003 Web Edition - edition = "Web Edition"; - } - else - { - // Windows Server 2003 Standard Edition - edition = "Standard"; - } - } - } - } - - else if (majorVersion == 6) - { - if (GetProductInfo(majorVersion, minorVersion, osVersionInfo.ServicePackMajor, osVersionInfo.ServicePackMinor, out var ed)) - { - switch (ed) - { - case PRODUCT_BUSINESS: - edition = "Business"; - break; - case PRODUCT_BUSINESS_N: - edition = "Business N"; - break; - case PRODUCT_CLUSTER_SERVER: - edition = "HPC Edition"; - break; - case PRODUCT_DATACENTER_SERVER: - edition = "Datacenter Server"; - break; - case PRODUCT_DATACENTER_SERVER_CORE: - edition = "Datacenter Server (core installation)"; - break; - case PRODUCT_ENTERPRISE: - edition = "Enterprise"; - break; - case PRODUCT_ENTERPRISE_N: - edition = "Enterprise N"; - break; - case PRODUCT_ENTERPRISE_SERVER: - edition = "Enterprise Server"; - break; - case PRODUCT_ENTERPRISE_SERVER_CORE: - edition = "Enterprise Server (core installation)"; - break; - case PRODUCT_ENTERPRISE_SERVER_CORE_V: - edition = "Enterprise Server without Hyper-V (core installation)"; - break; - case PRODUCT_ENTERPRISE_SERVER_IA64: - edition = "Enterprise Server for Itanium-based Systems"; - break; - case PRODUCT_ENTERPRISE_SERVER_V: - edition = "Enterprise Server without Hyper-V"; - break; - case PRODUCT_HOME_BASIC: - edition = "Home Basic"; - break; - case PRODUCT_HOME_BASIC_N: - edition = "Home Basic N"; - break; - case PRODUCT_HOME_PREMIUM: - edition = "Home Premium"; - break; - case PRODUCT_HOME_PREMIUM_N: - edition = "Home Premium N"; - break; - case PRODUCT_HYPERV: - edition = "Microsoft Hyper-V Server"; - break; - case PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT: - edition = "Windows Essential Business Management Server"; - break; - case PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING: - edition = "Windows Essential Business Messaging Server"; - break; - case PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY: - edition = "Windows Essential Business Security Server"; - break; - case PRODUCT_SERVER_FOR_SMALLBUSINESS: - edition = "Windows Essential Server Solutions"; - break; - case PRODUCT_SERVER_FOR_SMALLBUSINESS_V: - edition = "Windows Essential Server Solutions without Hyper-V"; - break; - case PRODUCT_SMALLBUSINESS_SERVER: - edition = "Windows Small Business Server"; - break; - case PRODUCT_STANDARD_SERVER: - edition = "Standard Server"; - break; - case PRODUCT_STANDARD_SERVER_CORE: - edition = "Standard Server (core installation)"; - break; - case PRODUCT_STANDARD_SERVER_CORE_V: - edition = "Standard Server without Hyper-V (core installation)"; - break; - case PRODUCT_STANDARD_SERVER_V: - edition = "Standard Server without Hyper-V"; - break; - case PRODUCT_STARTER: - edition = "Starter"; - break; - case PRODUCT_STORAGE_ENTERPRISE_SERVER: - edition = "Enterprise Storage Server"; - break; - case PRODUCT_STORAGE_EXPRESS_SERVER: - edition = "Express Storage Server"; - break; - case PRODUCT_STORAGE_STANDARD_SERVER: - edition = "Standard Storage Server"; - break; - case PRODUCT_STORAGE_WORKGROUP_SERVER: - edition = "Workgroup Storage Server"; - break; - case PRODUCT_UNDEFINED: - edition = "Unknown product"; - break; - case PRODUCT_ULTIMATE: - edition = "Ultimate"; - break; - case PRODUCT_ULTIMATE_N: - edition = "Ultimate N"; - break; - case PRODUCT_WEB_SERVER: - edition = "Web Server"; - break; - case PRODUCT_WEB_SERVER_CORE: - edition = "Web Server (core installation)"; - break; - } - } - } - } - - _sEdition = edition; - return edition; - } - } - - private static string _name; - /// <summary> - /// Gets the name of the operating system running on this computer. - /// </summary> - public static string Name - { - get - { - if (_name != null) - { - return _name; //***** RETURN *****// - } - - string name = "unknown"; - - OperatingSystem osVersion = Environment.OSVersion; - OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create(); - if (GetVersionEx(ref osVersionInfo)) - { - int majorVersion = osVersion.Version.Major; - int minorVersion = osVersion.Version.Minor; - byte productType = osVersionInfo.ProductType; - ushort suiteMask = osVersionInfo.SuiteMask; - switch (osVersion.Platform) - { - case PlatformID.Win32Windows: - if (majorVersion == 4) - { - string csdVersion = osVersionInfo.ServicePackVersion; - switch (minorVersion) - { - case 0: - if (csdVersion == "B" || csdVersion == "C") - { - name = "Windows 95 OSR2"; - } - else - { - name = "Windows 95"; - } - break; - case 10: - name = csdVersion == "A" ? "Windows 98 Second Edition" : "Windows 98"; - break; - case 90: - name = "Windows Me"; - break; - } - } - break; - case PlatformID.Win32NT: - switch (majorVersion) - { - case 3: - name = "Windows NT 3.51"; - break; - case 4: - switch (productType) - { - case 1: - name = "Windows NT 4.0"; - break; - case 3: - name = "Windows NT 4.0 Server"; - break; - } - break; - case 5: - switch (minorVersion) - { - case 0: - name = "Windows 2000"; - break; - case 1: - name = suiteMask switch - { - 0x0200 => "Windows XP Professional", - _ => "Windows XP" - }; - break; - case 2: - name = suiteMask switch - { - 0x0200 => "Windows XP Professional x64", - 0x0002 => "Windows Server 2003 Enterprise", - 0x0080 => "Windows Server 2003 Data Center", - 0x0400 => "Windows Server 2003 Web Edition", - 0x8000 => "Windows Home Server", - _ => "Windows Server 2003" - }; - break; - } - break; - case 6: - switch (minorVersion) - { - case 0: - name = productType switch - { - 3 => "Windows Server 2008", - _ => "Windows Vista" - }; - break; - case 1: - name = productType switch - { - 3 => "Windows Server 2008 R2", - _ => "Windows 7" - }; - break; - case 2: - name = "Windows 8"; - break; - case 3: - name = "Windows 8.1"; - break; - } - break; - case 10: - string releaseId = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", "").ToString(); - name = $"Windows 10 {releaseId}"; - break; - } - break; - } - } - - _name = name; - return name; - } - } - - [DllImport("Kernel32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool GetProductInfo( - int osMajorVersion, - int osMinorVersion, - int spMajorVersion, - int spMinorVersion, - out int edition); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetVersionEx(ref OSVERSIONINFOEX osVersionInfo); - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - private unsafe struct OSVERSIONINFOEX - { - /// <summary> - /// The size of this data structure, in bytes. Set this member to sizeof(OSVERSIONINFOEX). - /// </summary> - private int _dwOSVersionInfoSize; - - private readonly int _dwMajorVersion; - private readonly int _dwMinorVersion; - private readonly int _dwBuildNumber; - private readonly int _dwPlatformId; - private fixed char _szCSDVersion[128]; - private readonly short _wServicePackMajor; - private readonly short _wServicePackMinor; - private readonly ushort _wSuiteMask; - private readonly byte _wProductType; - private readonly byte _wReserved; - - /// <summary> - /// A null-terminated string, such as "Service Pack 3", that indicates the latest Service Pack installed on the system. - /// If no Service Pack has been installed, the string is empty. - /// </summary> - public string ServicePackVersion - { - get - { - fixed (char* servicePackVersion = _szCSDVersion) - { - return new string(servicePackVersion); - } - - } - } - - /// <summary> - /// The major version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the - /// major version number is 3. - /// If no Service Pack has been installed, the value is zero. - /// </summary> - public short ServicePackMajor => _wServicePackMajor; - - /// <summary> - /// The minor version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the - /// minor version number is 0. - /// </summary> - public short ServicePackMinor => _wServicePackMinor; - - /// <summary> - /// A bit mask that identifies the product suites available on the system. This member can be a combination of the - /// following values. - /// </summary> - public ushort SuiteMask => _wSuiteMask; - - /// <summary> - /// Any additional information about the system. - /// </summary> - public byte ProductType => _wProductType; - - /// <summary> - /// Factory for an empty OsVersionInfoEx - /// </summary> - /// <returns>OSVERSIONINFOEX</returns> - public static OSVERSIONINFOEX Create() - { - return new OSVERSIONINFOEX - { - _dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX)) - }; - } - } - - private const int PRODUCT_UNDEFINED = 0x00000000; - private const int PRODUCT_ULTIMATE = 0x00000001; - private const int PRODUCT_HOME_BASIC = 0x00000002; - private const int PRODUCT_HOME_PREMIUM = 0x00000003; - private const int PRODUCT_ENTERPRISE = 0x00000004; - private const int PRODUCT_HOME_BASIC_N = 0x00000005; - private const int PRODUCT_BUSINESS = 0x00000006; - private const int PRODUCT_STANDARD_SERVER = 0x00000007; - private const int PRODUCT_DATACENTER_SERVER = 0x00000008; - private const int PRODUCT_SMALLBUSINESS_SERVER = 0x00000009; - private const int PRODUCT_ENTERPRISE_SERVER = 0x0000000A; - private const int PRODUCT_STARTER = 0x0000000B; - private const int PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C; - private const int PRODUCT_STANDARD_SERVER_CORE = 0x0000000D; - private const int PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E; - private const int PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F; - private const int PRODUCT_BUSINESS_N = 0x00000010; - private const int PRODUCT_WEB_SERVER = 0x00000011; - private const int PRODUCT_CLUSTER_SERVER = 0x00000012; - private const int PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014; - private const int PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015; - private const int PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016; - private const int PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017; - private const int PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018; - private const int PRODUCT_HOME_PREMIUM_N = 0x0000001A; - private const int PRODUCT_ENTERPRISE_N = 0x0000001B; - private const int PRODUCT_ULTIMATE_N = 0x0000001C; - private const int PRODUCT_WEB_SERVER_CORE = 0x0000001D; - private const int PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E; - private const int PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F; - private const int PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020; - private const int PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023; - private const int PRODUCT_STANDARD_SERVER_V = 0x00000024; - private const int PRODUCT_ENTERPRISE_SERVER_V = 0x00000026; - private const int PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028; - private const int PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029; - private const int PRODUCT_HYPERV = 0x0000002A; - - private const int VER_NT_WORKSTATION = 1; - private const int VER_NT_SERVER = 3; - private const int VER_SUITE_ENTERPRISE = 2; - private const int VER_SUITE_DATACENTER = 128; - private const int VER_SUITE_PERSONAL = 512; - private const int VER_SUITE_BLADE = 1024; - - /// <summary> - /// Gets the service pack information of the operating system running on this computer. - /// </summary> - public static string ServicePack - { - get - { - string servicePack = string.Empty; - OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create(); - - if (GetVersionEx(ref osVersionInfo)) - { - servicePack = osVersionInfo.ServicePackVersion; - } - - return servicePack; - } - } - - /// <summary> - /// Gets the full version string of the operating system running on this computer. - /// </summary> - public static string VersionString - { - get - { - if (WindowsVersion.IsWindows10OrLater) - { - return $"build {Environment.OSVersion.Version.Build}"; - } - if (Environment.OSVersion.Version.Revision != 0) - { - return $"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor} build {Environment.OSVersion.Version.Build} revision {Environment.OSVersion.Version.Revision:X}"; - } - return $"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor} build {Environment.OSVersion.Version.Build}"; - } - } - } -} \ No newline at end of file diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 093c71ce9..91ab88e3c 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -99,8 +99,8 @@ Source: {#BaseDir}\GreenshotFlickrPlugin\Languages\language_flickr*.xml; DestDir Source: {#BaseDir}\GreenshotPhotobucketPlugin\{#BinDir}\GreenshotPhotobucketPlugin.dll; DestDir: {app}\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\GreenshotPhotobucketPlugin\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion; ;Picasa Plugin -Source: {#BaseDir}\GreenshotPicasaPlugin\{#BinDir}\GreenshotPicasaPlugin.dll; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotPicasaPlugin\Languages\language_picasa*.xml; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion; +;Source: {#BaseDir}\GreenshotPicasaPlugin\{#BinDir}\GreenshotPicasaPlugin.dll; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +;Source: {#BaseDir}\GreenshotPicasaPlugin\Languages\language_picasa*.xml; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion; ;Confluence Plugin Source: {#BaseDir}\GreenshotConfluencePlugin\{#BinDir}\GreenshotConfluencePlugin.dll; DestDir: {app}\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\GreenshotConfluencePlugin\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; @@ -491,7 +491,7 @@ Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flag Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning Name: "plugins\photobucket"; Description: {cm:photobucket}; Types: full custom; Flags: disablenouninstallwarning -Name: "plugins\picasa"; Description: {cm:picasa}; Types: full custom; Flags: disablenouninstallwarning +;Name: "plugins\picasa"; Description: {cm:picasa}; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\win10"; Description: {cm:win10}; Types: default full custom; Flags: disablenouninstallwarning; Check: IsWindows10OrNewer() Name: "languages"; Description: {cm:language}; Types: full custom; Flags: disablenouninstallwarning Name: "languages\arSY"; Description: {cm:arSY}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') diff --git a/GreenshotBoxPlugin/BoxDestination.cs b/GreenshotBoxPlugin/BoxDestination.cs index 06402ca89..4283a178c 100644 --- a/GreenshotBoxPlugin/BoxDestination.cs +++ b/GreenshotBoxPlugin/BoxDestination.cs @@ -30,17 +30,9 @@ namespace GreenshotBoxPlugin { _plugin = plugin; } - public override string Designation { - get { - return "Box"; - } - } + public override string Designation => "Box"; - public override string Description { - get { - return Language.GetString("box", LangKey.upload_menu_item); - } - } + public override string Description => Language.GetString("box", LangKey.upload_menu_item); public override Image DisplayIcon { get { diff --git a/GreenshotBoxPlugin/BoxUtils.cs b/GreenshotBoxPlugin/BoxUtils.cs index ec9ef0144..a20447c86 100644 --- a/GreenshotBoxPlugin/BoxUtils.cs +++ b/GreenshotBoxPlugin/BoxUtils.cs @@ -21,10 +21,10 @@ using GreenshotPlugin.Core; using System.Collections.Generic; -using System.Drawing; using System.IO; using System.Runtime.Serialization.Json; using System.Text; +using GreenshotPlugin.Core.OAuth; using GreenshotPlugin.IniFile; namespace GreenshotBoxPlugin { @@ -73,9 +73,8 @@ namespace GreenshotBoxPlugin { CloudServiceName = "Box", ClientId = BoxCredentials.ClientId, ClientSecret = BoxCredentials.ClientSecret, - RedirectUrl = "https://www.box.com/home/", - BrowserSize = new Size(1060, 600), - AuthorizeMode = OAuth2AuthorizeMode.EmbeddedBrowser, + RedirectUrl = "https://getgreenshot.org/authorize/box", + AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, RefreshToken = Config.RefreshToken, AccessToken = Config.AccessToken, AccessTokenExpires = Config.AccessTokenExpires diff --git a/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template b/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template index 9ad35eced..72cfa4b79 100644 --- a/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template +++ b/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template @@ -25,7 +25,7 @@ namespace GreenshotBoxPlugin { /// You can set your own values here /// </summary> public static class BoxCredentials { - public static string ClientId = "${Box_ClientId}"; - public static string ClientSecret = "${Box_ClientSecret}"; + public static string ClientId = "${Box13_ClientId}"; + public static string ClientSecret = "${Box13_ClientSecret}"; } } diff --git a/GreenshotDropboxPlugin/DropboxDestination.cs b/GreenshotDropboxPlugin/DropboxDestination.cs index 57d0a1326..9762652c4 100644 --- a/GreenshotDropboxPlugin/DropboxDestination.cs +++ b/GreenshotDropboxPlugin/DropboxDestination.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * + * (at your option) any later version. + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -32,7 +32,7 @@ namespace GreenshotDropboxPlugin { public DropboxDestination(DropboxPlugin plugin) { _plugin = plugin; } - + public override string Designation => "Dropbox"; public override string Description => Language.GetString("dropbox", LangKey.upload_menu_item); @@ -43,10 +43,10 @@ namespace GreenshotDropboxPlugin { return (Image)resources.GetObject("Dropbox"); } } - + public override ExportInformation ExportCapture(bool manually, ISurface surface, ICaptureDetails captureDetails) { ExportInformation exportInformation = new ExportInformation(Designation, Description); - bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); + bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); if (uploaded) { exportInformation.Uri = uploadUrl; exportInformation.ExportMade = true; diff --git a/GreenshotDropboxPlugin/DropboxPlugin.cs b/GreenshotDropboxPlugin/DropboxPlugin.cs index 0d3ca827d..2977c2d36 100644 --- a/GreenshotDropboxPlugin/DropboxPlugin.cs +++ b/GreenshotDropboxPlugin/DropboxPlugin.cs @@ -1,27 +1,26 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ using System; using System.ComponentModel; using System.Drawing; -using System.IO; using System.Windows.Forms; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; @@ -45,13 +44,12 @@ namespace GreenshotDropboxPlugin { GC.SuppressFinalize(this); } - protected void Dispose(bool disposing) { - if (disposing) { - if (_itemPlugInConfig != null) { - _itemPlugInConfig.Dispose(); - _itemPlugInConfig = null; - } - } + private void Dispose(bool disposing) + { + if (!disposing) return; + if (_itemPlugInConfig == null) return; + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; } /// <summary> @@ -102,20 +100,16 @@ namespace GreenshotDropboxPlugin { public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) { uploadUrl = null; SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); - try { - string dropboxUrl = null; - new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait), + try + { + bool result = false; + new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait), delegate { - string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); - dropboxUrl = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, filename); + result = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, captureDetails); } ); - if (dropboxUrl == null) { - return false; - } - uploadUrl = dropboxUrl; - return true; + return result; } catch (Exception e) { Log.Error(e); MessageBox.Show(Language.GetString("dropbox", LangKey.upload_failure) + " " + e.Message); diff --git a/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs b/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs index 52baabdef..b13622db2 100644 --- a/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs +++ b/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs @@ -1,23 +1,25 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +using System; using System.Windows.Forms; using GreenshotDropboxPlugin.Forms; using GreenshotPlugin.Core; @@ -39,10 +41,18 @@ namespace GreenshotDropboxPlugin { [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Dropbox link to clipboard.", DefaultValue = "true")] public bool AfterUploadLinkToClipBoard { get; set; } - [IniProperty("DropboxToken", Description = "The Dropbox token", Encrypted = true, ExcludeIfNull = true)] - public string DropboxToken { get; set; } - [IniProperty("DropboxTokenSecret", Description = "The Dropbox token secret", Encrypted = true, ExcludeIfNull = true)] - public string DropboxTokenSecret { get; set; } + [IniProperty("RefreshToken", Description = "Dropbox refresh Token", Encrypted = true, ExcludeIfNull = true)] + public string RefreshToken { get; set; } + + /// <summary> + /// AccessToken, not stored + /// </summary> + public string AccessToken { get; set; } + + /// <summary> + /// AccessTokenExpires, not stored + /// </summary> + public DateTimeOffset AccessTokenExpires { get; set; } /// <summary> /// A form for token diff --git a/GreenshotDropboxPlugin/DropboxUtils.cs b/GreenshotDropboxPlugin/DropboxUtils.cs index 717b41fe3..8bf1d57b5 100644 --- a/GreenshotDropboxPlugin/DropboxUtils.cs +++ b/GreenshotDropboxPlugin/DropboxUtils.cs @@ -1,30 +1,32 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ using System; using System.Collections.Generic; -using System.Drawing; +using System.IO; using GreenshotPlugin.Core; +using GreenshotPlugin.Core.OAuth; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; +using Newtonsoft.Json; namespace GreenshotDropboxPlugin { /// <summary> @@ -37,49 +39,54 @@ namespace GreenshotDropboxPlugin { private DropboxUtils() { } - public static string UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string filename) { - var oAuth = new OAuthSession(DropBoxCredentials.CONSUMER_KEY, DropBoxCredentials.CONSUMER_SECRET) - { - BrowserSize = new Size(1080, 650), - CheckVerifier = false, - AccessTokenUrl = "https://api.dropbox.com/1/oauth/access_token", - AuthorizeUrl = "https://api.dropbox.com/1/oauth/authorize", - RequestTokenUrl = "https://api.dropbox.com/1/oauth/request_token", - LoginTitle = "Dropbox authorization", - Token = DropboxConfig.DropboxToken, - TokenSecret = DropboxConfig.DropboxTokenSecret + public static bool UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, ICaptureDetails captureDetails) + { + var oauth2Settings = new OAuth2Settings + { + AuthUrlPattern = "https://api.dropbox.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}&redirect_uri={RedirectUrl}", + TokenUrl = "https://api.dropbox.com/oauth2/token", + RedirectUrl = "https://getgreenshot.org/authorize/dropbox", + CloudServiceName = "Dropbox", + ClientId = DropBoxCredentials.CONSUMER_KEY, + ClientSecret = DropBoxCredentials.CONSUMER_SECRET, + AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, + RefreshToken = DropboxConfig.RefreshToken, + AccessToken = DropboxConfig.AccessToken, + AccessTokenExpires = DropboxConfig.AccessTokenExpires }; + try + { + string filename = Path.GetFileName(FilenameHelper.GetFilename(DropboxConfig.UploadFormat, captureDetails)); + SurfaceContainer image = new SurfaceContainer(surfaceToUpload, outputSettings, filename); - try { - SurfaceContainer imageToUpload = new SurfaceContainer(surfaceToUpload, outputSettings, filename); - string uploadResponse = oAuth.MakeOAuthRequest(HTTPMethod.POST, "https://api-content.dropbox.com/1/files_put/sandbox/" + OAuthSession.UrlEncode3986(filename), null, null, imageToUpload); - Log.DebugFormat("Upload response: {0}", uploadResponse); - } catch (Exception ex) { + IDictionary<string, object> arguments = new Dictionary<string, object> + { + { "autorename", true }, + { "mute", true }, + { "path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\')} + }; + IDictionary<string, object> headers = new Dictionary<string, object> + { + { "Dropbox-API-Arg", JsonConvert.SerializeObject(arguments)} + }; + var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, "https://content.dropboxapi.com/2/files/upload", oauth2Settings); + + NetworkHelper.Post(webRequest, headers, image); + var responseString = NetworkHelper.GetResponseAsString(webRequest); + Log.DebugFormat("Upload response: {0}", responseString); + var response = JsonConvert.DeserializeObject<IDictionary<string, string>>(responseString); + return response.ContainsKey("id"); + } + catch (Exception ex) { Log.Error("Upload error: ", ex); throw; } finally { - if (!string.IsNullOrEmpty(oAuth.Token)) { - DropboxConfig.DropboxToken = oAuth.Token; - } - if (!string.IsNullOrEmpty(oAuth.TokenSecret)) { - DropboxConfig.DropboxTokenSecret = oAuth.TokenSecret; - } - } - - // Try to get a URL to the uploaded image - try { - string responseString = oAuth.MakeOAuthRequest(HTTPMethod.GET, "https://api.dropbox.com/1/shares/sandbox/" + OAuthSession.UrlEncode3986(filename), null, null, null); - if (responseString != null) { - Log.DebugFormat("Parsing output: {0}", responseString); - IDictionary<string, object> returnValues = JSONHelper.JsonDecode(responseString); - if (returnValues.ContainsKey("url")) { - return returnValues["url"] as string; - } - } - } catch (Exception ex) { - Log.Error("Can't parse response.", ex); - } - return null; + DropboxConfig.RefreshToken = oauth2Settings.RefreshToken; + DropboxConfig.AccessToken = oauth2Settings.AccessToken; + DropboxConfig.AccessTokenExpires = oauth2Settings.AccessTokenExpires; + DropboxConfig.IsDirty = true; + IniConfig.Save(); + } } } } diff --git a/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template b/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template index 6a13eb6d7..f674f1bb7 100644 --- a/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template +++ b/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template @@ -25,7 +25,7 @@ namespace GreenshotDropboxPlugin { /// You can set your own values here /// </summary> public static class DropBoxCredentials { - public static string CONSUMER_KEY = "${DropBox_ClientId}"; - public static string CONSUMER_SECRET = "${DropBox_ClientSecret}"; + public static string CONSUMER_KEY = "${DropBox13_ClientId}"; + public static string CONSUMER_SECRET = "${DropBox13_ClientSecret}"; } } diff --git a/GreenshotFlickrPlugin/FlickrUtils.cs b/GreenshotFlickrPlugin/FlickrUtils.cs index 6713e3702..9337c51f6 100644 --- a/GreenshotFlickrPlugin/FlickrUtils.cs +++ b/GreenshotFlickrPlugin/FlickrUtils.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.Drawing; using System.Xml; using GreenshotPlugin.Core; +using GreenshotPlugin.Core.OAuth; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; diff --git a/GreenshotPicasaPlugin/Forms/PicasaForm.cs b/GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs similarity index 85% rename from GreenshotPicasaPlugin/Forms/PicasaForm.cs rename to GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs index cea5a2f35..10b18bebe 100644 --- a/GreenshotPicasaPlugin/Forms/PicasaForm.cs +++ b/GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs @@ -1,5 +1,5 @@ /* - * A Picasa Plugin for Greenshot + * A GooglePhotos Plugin for Greenshot * Copyright (C) 2011 Francis Noel * * For more information see: http://getgreenshot.org/ @@ -20,7 +20,7 @@ using GreenshotPlugin.Controls; -namespace GreenshotPicasaPlugin.Forms { - public class PicasaForm : GreenshotForm { +namespace GreenshotGooglePhotosPlugin.Forms { + public class GooglePhotosForm : GreenshotForm { } } diff --git a/GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs b/GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs similarity index 91% rename from GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs rename to GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs index 38555c179..cea2b6acf 100644 --- a/GreenshotPicasaPlugin/Forms/SettingsForm.Designer.cs +++ b/GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs @@ -1,147 +1,147 @@ -/* - * A Picasa Plugin for Greenshot - * Copyright (C) 2011 Francis Noel - * - * For more information see: http://getgreenshot.org/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -namespace GreenshotPicasaPlugin.Forms { - partial class SettingsForm { - /// <summary> - /// Designer variable used to keep track of non-visual components. - /// </summary> - private System.ComponentModel.IContainer components = null; - - /// <summary> - /// Disposes resources used by the form. - /// </summary> - /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> - protected override void Dispose(bool disposing) - { - if (disposing) { - if (components != null) { - components.Dispose(); - } - } - base.Dispose(disposing); - } - - /// <summary> - /// This method is required for Windows Forms designer support. - /// Do not change the method contents inside the source code editor. The Forms designer might - /// not be able to load this method if it was changed manually. - /// </summary> - private void InitializeComponent() - { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.SuspendLayout(); - // - // buttonOK - // - this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; - this.buttonOK.LanguageKey = "OK"; - this.buttonOK.Location = new System.Drawing.Point(267, 78); - this.buttonOK.Name = "buttonOK"; - this.buttonOK.Size = new System.Drawing.Size(75, 23); - this.buttonOK.TabIndex = 10; - this.buttonOK.UseVisualStyleBackColor = true; - // - // buttonCancel - // - this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonCancel.LanguageKey = "CANCEL"; - this.buttonCancel.Location = new System.Drawing.Point(348, 78); - this.buttonCancel.Name = "buttonCancel"; - this.buttonCancel.Size = new System.Drawing.Size(75, 23); - this.buttonCancel.TabIndex = 11; - this.buttonCancel.UseVisualStyleBackColor = true; - // - // combobox_uploadimageformat - // - this.combobox_uploadimageformat.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.combobox_uploadimageformat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.combobox_uploadimageformat.FormattingEnabled = true; - this.combobox_uploadimageformat.Location = new System.Drawing.Point(197, 12); - this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; - this.combobox_uploadimageformat.PropertyName = "UploadFormat"; - this.combobox_uploadimageformat.SectionName = "Picasa"; - this.combobox_uploadimageformat.Size = new System.Drawing.Size(225, 21); - this.combobox_uploadimageformat.TabIndex = 1; - // - // label_upload_format - // - this.label_upload_format.LanguageKey = "picasa.label_upload_format"; - this.label_upload_format.Location = new System.Drawing.Point(10, 18); - this.label_upload_format.Name = "label_upload_format"; - this.label_upload_format.Size = new System.Drawing.Size(181, 33); - this.label_upload_format.TabIndex = 4; - // - // label_AfterUpload - // - this.label_AfterUpload.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.label_AfterUpload.LanguageKey = "picasa.label_AfterUpload"; - this.label_AfterUpload.Location = new System.Drawing.Point(10, 51); - this.label_AfterUpload.Name = "label_AfterUpload"; - this.label_AfterUpload.Size = new System.Drawing.Size(181, 29); - this.label_AfterUpload.TabIndex = 8; - // - // checkboxAfterUploadLinkToClipBoard - // - this.checkboxAfterUploadLinkToClipBoard.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "picasa.label_AfterUploadLinkToClipBoard"; - this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(197, 50); - this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; - this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard"; - this.checkboxAfterUploadLinkToClipBoard.SectionName = "Picasa"; - this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17); - this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2; - this.checkboxAfterUploadLinkToClipBoard.UseVisualStyleBackColor = true; - // - // SettingsForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(432, 110); - this.Controls.Add(this.checkboxAfterUploadLinkToClipBoard); - this.Controls.Add(this.label_AfterUpload); - this.Controls.Add(this.label_upload_format); - this.Controls.Add(this.combobox_uploadimageformat); - this.Controls.Add(this.buttonCancel); - this.Controls.Add(this.buttonOK); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.LanguageKey = "picasa.settings_title"; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "SettingsForm"; - this.ResumeLayout(false); - this.PerformLayout(); - - } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; - } -} +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +namespace GreenshotGooglePhotosPlugin.Forms { + partial class SettingsForm { + /// <summary> + /// Designer variable used to keep track of non-visual components. + /// </summary> + private System.ComponentModel.IContainer components = null; + + /// <summary> + /// Disposes resources used by the form. + /// </summary> + /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> + protected override void Dispose(bool disposing) + { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// <summary> + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// </summary> + private void InitializeComponent() + { + this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); + this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); + this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); + this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel(); + this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.SuspendLayout(); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.buttonOK.LanguageKey = "OK"; + this.buttonOK.Location = new System.Drawing.Point(267, 78); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 10; + this.buttonOK.UseVisualStyleBackColor = true; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.LanguageKey = "CANCEL"; + this.buttonCancel.Location = new System.Drawing.Point(348, 78); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 11; + this.buttonCancel.UseVisualStyleBackColor = true; + // + // combobox_uploadimageformat + // + this.combobox_uploadimageformat.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.combobox_uploadimageformat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.combobox_uploadimageformat.FormattingEnabled = true; + this.combobox_uploadimageformat.Location = new System.Drawing.Point(197, 12); + this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; + this.combobox_uploadimageformat.PropertyName = "UploadFormat"; + this.combobox_uploadimageformat.SectionName = "GooglePhotos"; + this.combobox_uploadimageformat.Size = new System.Drawing.Size(225, 21); + this.combobox_uploadimageformat.TabIndex = 1; + // + // label_upload_format + // + this.label_upload_format.LanguageKey = "googlephotos.label_upload_format"; + this.label_upload_format.Location = new System.Drawing.Point(10, 18); + this.label_upload_format.Name = "label_upload_format"; + this.label_upload_format.Size = new System.Drawing.Size(181, 33); + this.label_upload_format.TabIndex = 4; + // + // label_AfterUpload + // + this.label_AfterUpload.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label_AfterUpload.LanguageKey = "googlephotos.label_AfterUpload"; + this.label_AfterUpload.Location = new System.Drawing.Point(10, 51); + this.label_AfterUpload.Name = "label_AfterUpload"; + this.label_AfterUpload.Size = new System.Drawing.Size(181, 29); + this.label_AfterUpload.TabIndex = 8; + // + // checkboxAfterUploadLinkToClipBoard + // + this.checkboxAfterUploadLinkToClipBoard.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "googlephotos.label_AfterUploadLinkToClipBoard"; + this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(197, 50); + this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; + this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard"; + this.checkboxAfterUploadLinkToClipBoard.SectionName = "GooglePhotos"; + this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17); + this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2; + this.checkboxAfterUploadLinkToClipBoard.UseVisualStyleBackColor = true; + // + // SettingsForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(432, 110); + this.Controls.Add(this.checkboxAfterUploadLinkToClipBoard); + this.Controls.Add(this.label_AfterUpload); + this.Controls.Add(this.label_upload_format); + this.Controls.Add(this.combobox_uploadimageformat); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.LanguageKey = "googlephotos.settings_title"; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "SettingsForm"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; + private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; + private GreenshotPlugin.Controls.GreenshotButton buttonCancel; + private GreenshotPlugin.Controls.GreenshotButton buttonOK; + private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload; + private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; + } +} diff --git a/GreenshotPicasaPlugin/Forms/SettingsForm.cs b/GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs similarity index 86% rename from GreenshotPicasaPlugin/Forms/SettingsForm.cs rename to GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs index a6691a424..be31f1d44 100644 --- a/GreenshotPicasaPlugin/Forms/SettingsForm.cs +++ b/GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs @@ -1,38 +1,38 @@ -/* - * A Picasa Plugin for Greenshot - * Copyright (C) 2011 Francis Noel - * - * For more information see: http://getgreenshot.org/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotPicasaPlugin.Forms { - /// <summary> - /// Description of PasswordRequestForm. - /// </summary> - public partial class SettingsForm : PicasaForm { - - public SettingsForm() - { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - CancelButton = buttonCancel; - AcceptButton = buttonOK; - } - - } -} +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace GreenshotGooglePhotosPlugin.Forms { + /// <summary> + /// Description of PasswordRequestForm. + /// </summary> + public partial class SettingsForm : GooglePhotosForm { + + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + CancelButton = buttonCancel; + AcceptButton = buttonOK; + } + + } +} diff --git a/GreenshotGooglePhotosPlugin/GooglePhotos.png b/GreenshotGooglePhotosPlugin/GooglePhotos.png new file mode 100644 index 0000000000000000000000000000000000000000..ea7824f9d4fa04499fc4f37b05503b3c5ab2e503 GIT binary patch literal 12803 zcmZ{LcRZEvANM(jLrz3Sq-33A?^(98jy+SEnO{45bBK`HF^?SwAtNJuBxN0htjr`M zduKoQ(eL@=`Qv$cdAYCq`i%GI{kisiiPF|oCWFz#Kp+qqQbj=*1Om_Ff3Fb%Zvwx! zCIf#6ZRIuOL7)%u*Uz3qfijb&imnC-<i`dAp~66*6W|qU1qAXG0D=CPgFq5#AQ0_~ z%tjq4pn}LkO<4hSiT}xMDM|!^1nH3q^7=kMHfDS?4Z;JDcDA;rt;4PhlYTDLVO0N4 zSEull`o*Ic(f#&H0vaN()iiW1(I2bm+@11<#ER9Xq!htrPAt)OdbKP#dZ@UZYZqd) zzFL^68z+5qmMxnrBgj*Q%WPPl9XzEmZDr}6K9%k}IvbEax=V$s+FQEKdScVDV2C@5 zc4J^$r9!)*Tln`v;XSopYm9UM?HV|LRDJUpQzL<{NU53T@sU=cHQSPP>1o2kJos24 zxiPQ3J0tI5?tNiQJDyW1+3aldtL`y#pIqC#D1rEou?GJbW*8(-zr-n_i8;)3Ey^T3 zJK0~$|21<Xi`wZ@5;|pUklk?BD$s4st<<XdukAF&(IN^&Euek-x5H0M^dWyps$Rl= z66T)kaj3;g+f;>T4_6AM9GJlRcmGXRKP&g2p9QsAn<NqZ=>1&UXm{f5W~(>9X+A6h zA}TdUnhY{uaKY)=5R+l4hI1Re@9vxOWn~#pU+1F0aEB9VONBW{y4J#hmU%ACHN?zX z`Q)9Fu>o1D&C(4X1MPN@>g?+ekNDl{R;_ov#xNdQL+6Kq8MLyWhM`c>Tq|Bi$@R9y z6N}>(;oz^vb+&oia}GwS<(9~o5F+hoP$`><KJ*RFUv+;&u#>k|mcV4uDOH{FU;>Ue zkbAB2yQVZdHYV3i8ePrz@=i6}Qe-&HK{F4)h88!aUCPbgzn|JKWnGe*`}7P1qXR+j zR)||QI?JVHJTEI_b|65rF+o5ip1H<)hFG!Is(|%MwU$;HMK}-`lg!KC>5Xpv4ugD* z!e@P*A=r6pkpy#^AebMqq^Qdd$KQ+g6!vU3G667woVu~tvk=*afc5RBS;@df5G5E& z3Ub|?nr^fE(xJxvmGnGrd2;;i{tFnrih!p4R+TafG<AJy|L=7LFq=6ja<E%&X!y5f z#LRZ@Q)0uLK$1a`T1w@mB~uQx6?X%tDHcF@gF+0qp+lB^T{i~zW}XAYQdHDT2RB>v zuaUQTpKQO3B%l@mbvlG8wpx8D{=60i!54cB)|RSM<8O-{9G|dO5kdeK7Ci0RL>mf| zZAm9nIe-+)HUHWs(V^oB^v1d7_grZ?$mOnl0sxt)QscQWecDjiDsD5uJN=asZxn~+ zek>*8IFP}rw9iC_N8)llSaeF*aj8cYFCWxp^kI8j(lX+%%0K;xLMb1gFLqrF5C4^k z{ivnSW+#}HZ$k00j?3w7HytUFKZv`+lWAOgi;%or%Cq}J7#I(Dl)cJ)wkbb?LH?im zd8k}Jw=(&;hz<%ugz_QdAR61=<m@76gW<8TCf>NF`^9%FQwYmwcO}4(t_r<8AE14; z55JPA_*qOID(Q<Nz&p<<4LW}Gxt#SHURPLHBfte{1}axHm~@l}n+n?eje=jnNOnD5 zPcCApX8fPq*LnMy%WLu7l>dV04k~pQr}$^{_$W1=;m{xypSPWi!+{BAV#=$U#8R=y z(58CiRgN(jP1Bukm5d35cpxp|o-;sCiD$k-Qt`g&yp;Slni&Q#Kv9vOa`d5%jR^lN zoM^H)F!4+F5k418rUsn+7tv};)K>-eviV{p@RVyby*-xp)3X!EFKA)0M5C{Q`Px6_ z*7MobNAYlyE3-A>Uc!Pv;HbY{^Mc%6H)J!I04Q>}yl$8I=VW-37o2~)ldr!DjQv+J zeLyAqJ4pnI*YRO!WT|zPy3()5oTqW7L5M(|{pa&E#j(Gxh2jfy9l@Vp(&J68udn<r zB9lzMi!V&m++B^pUSabd+a3BWt450VwaIyZdkYN#IE%#eeXWpLtG7o3?FqE=_(jD- z<^^tiWK4$)wQH2R_}8w3?ZcHcmJ#><F=6v2G+HGD?-e)Q<sSSWKESphZr!c;f4m)0 z^SFwN;EiWw1YUIqI53WYES$_o56xyQN#*e|r77MDh^4;bKt1TzAW0$K{gn5Ym7mH~ z1bAJ4m{=APh6iHv=8WeG$BtHe{#Xoy?*9_9dP6Hq<tiTM&HQWs0I5?80Lm*wpUobu z&2w2?1y%CL<elUzx+`BeR?SCxfcuGtI0PXcxU4f0i3evZ5p(?mUgT_eG~@K1(v{sq z&ie}@SCO=#UjENT|G8cmo=}S%lqUuARZ6e>2wXkXH`tG7?>5K~UWNO(+bS)T6Q7Ys zFNXf!#plf9Wr#w8lpTvo`;b%qAJ`Y%JX7T*6^2~MH;ZL$xlkf;6luy{T!(y$bSsWm zXPavb(0FU?Jlt5;HpguD(yDYOAQ@STFx#ja4Vm)SnXj;gg^zEjmoW!2flsd$#{qP% zuM+K}N?-;UR{ifow^mdd7+EIGkuM(^)<V&J)~y9Pbr&vug-4g-51o!K|3+M{oEBx2 z1^!)DFD#Q~MR({cg%g#f?l&%0AU|>2To^C<vFUL%o97rxs*!P!DS`FcCl0E}MpoYn z#d=IqB*wuC9`Wk>Ib8n}yjGiGpeFIGDj$)0nqo*}BlP^OJb%;v`yN{EZ>+0_FGvbV zJrd>4fi!(RgdGKq-YTtPZxB)4%zrpSfiytqRr`OOz3V*u6CJAu567tczm<>v{qdXC zbv?{sgyVjS-Ylrmhw(F^I{4S6gUi6Zn_)vaJ&ukXSv<Z<B+k<&+6cQOoN|Nl^EA#| z^tJj`O1>V!e$W3#0<)_PC~I&UgG#KQj?7JrlVj925H#^rvKo58mc?lYDh}v$6YfvW zo5PM#FHbf6VM1$O^TY|TL%R>A+m{rjl0r!8L&uIMRl{pnZ@QI|YnY|x1>GH5|0d@h zs0M4L86#Sgp!YDNfV%5CZR~ManpY?nb3M#OaX;)j!+n!$ye~4U_NUJ`Y-X$r>*7Zd zDEz+v{f#>!k}wfo$--^;5Xe6aQi$sF`4K2L8t!P*+`yOU!LxiWp^>GQYJ}~(PKKdf z3^J5}xhzX|w>$Sx%I^v^1;!kHT_55++G-Hd)QwZH_%LKF9BoslpEb6_<GN0l1GZet z4%le_su)PZ^0c1j_YG?LVRmZzsw3#8nn`2iZmhw81{LI3IQ$hZ^o8jt?ev2ugkIeb zpjir;p%=eAeLhx&%U~)pR*BJZCyD-QZ~bF-nHt3%d!-l##`$#vuM0c9gLOhsB=vV+ zi&rpZ=9KY|*<_24Fc|gHBD}&bpNh{IJjw7a$QN`ku6wb4Eug#pIs-KG+X9)gwW-J6 zBp(BgOXtt&?Q=$V4c=FnR7rZ_)Dy=773keu-FE61p<!f`{NedRgN?_I$cQQ~xKnWc zOPr|a`+gp>WrM&F1?``I`J|!7CqI_0$+>ZZGV{B0suGz7OgnM=OpSHl((LSAaQ8Is zzSC9*tdVG`lb5(W4_ZoL+P1Y0x)t5JuC$;>aD;gN$fjiQmssw*`hy%G18Of?aNH~Z zbq9#6TL<xv&@A+Bxutlm4hwWQPYBBH(FS;uBv-T7#R7dlHK~8E^ahEtb-MbAGBWVV zG);a5=E7wn&9}aV`SkXJ+$1^uy)qUktX|~t*Dt-)OGOo`Pxs$r^`78p9Q2uj8^5Ks ze6n>fl}X}He4Ge@PH#vo*}i(^Af(l^PUQO1P33lj8O@l@EpHL)IK+)4PBwE`{hcDy zR8QPsz@YkdYl%?BXj#`JMZe~63H|=rcfRE|-=`9QPCIeWHQyr+i^bRo&+uf!LK)Q5 zE`GhxFB~%RTi3eFL7N#`h-y-tNMoQS`YF6nZMxn#^qfwHLCk898J5&j9`N9{cKeP- z3$H3IeYJS~sk&>pu$P%x>Kv7rRpE(+btFMlHi{rPi<)EJr`J21DD1gS>vV<1O^b># z#Om-1r@~3b@2%JnY%eu1YD1?FV0$C^9ZXI7!~fl4l;|OO&ec-?E$JSTT4nZcX>Dzp z+W1XE=yZVuy-;f3dquZG8jnL$M_I+O;h}_vFrEaC@^N6S*laxLvkrgdIEyt?4KR)1 zOB7xG*l~vA4KN@f;hG;O0VL8r*T4oe^g?YZXI(seox-GRuV3i<eU#0+7Zx&XW_E4> zbVkXxfI9}XHbSvB^n-a1asIXL9RN$&@52b+mkuU?q0_}OX-$LkdA9cwJs{B}GmC!( zx~101q;J4sN$a^5H=*ia@9h3qgNVZ6FA>HPX^LUaUjNDe{G73D2&}X?<ikg6Gt5|s zVD)-6;#RVWyB5(%;z}QFn7V|3_0Z=HvdMfE0)*IQt50Vp(2YYNvknXz7)yfVN9c{N zJo%{GbZM96mZnSh^W;bv?#ZYTQE$(tZk^$@qrdYMGe$!T9yq=mgGhH<lIc9mW`V$b zDgZa}LL)EH_D|p(u7Nzm&4)`o@y!ZHj8sZP5MZu6nph$(y>SEUi~jTEu1aK({7}Xe z&|6qx9{J>tkEU?IIJ)(7XbNa9gsbmDjMP{{h@Q;v$pR#p=gHNr%bIAt0N;W(NBk}Y ze_?VIq?HtaqmjhekuScp9iG=$US)aDX9g9bj&cJSb>aoO&&CS0K3q$95%DS<7knD{ z2T2`ifDH$_%9iQz5>42hkxM>1!kv6|rJp~a$K$f3+QEWcSc2d%I*$1n$~fFvi<KF| zFNwx5(C6WyU#Of^SHQE0I#=W!VD;1VK3{Op2@@o@&M`=NSSkUG6_kXH7e0ea!1|@R z52msDW~ni%TW2gWYApvAyGn(Gm^^ELj74$In;1WRCZh6YNu`(aL9emWJ>223bVC+b zV{a3|om44hQtIul)GZ6^4gukeQ_1|$r9}C+F!um4;>?u*w%~R+I|=NsCC#{vb4n-Y z1N|SSZdMcGd)|a0nzGH+<~KOC+ZnkXadF<OQ=Kur(|UjWpIaU}0JSyt?LRE=Ydy)i zqniDRx!-MY3w;mbrnyagdm`~bUsfX2V4VOrK1GR!6t8}^^%$sizIze)@cL!HEw>`| z#9E+3?j#lv(7(?mjU49eysqMwMSZAonZQ(;x;E4s5<a~Jtoml(#(l*J^aQEbv@>o= zZLs5;6bZzCwoPW_nb9L)Jy+KjihDf9GQ-UIsHR=nig!3GK$OJ4xmt6Q6lfye9P1fb zEF(8NVUFWE&z(+OBEe1l>pS>;A0;8Q*<@p{Dx&9{iv{Y{$llV}BItkrfw{L2)(!yX z68yWH`x>rDt%OC_yr=|nWGB@~(d7E=FsMXYIQlNf{03KM!g0AeYZTQ4f)&Q<YftIr z*|F1f%5PjB!o)G}G#=|qZ(iPpP&F5~NtYY<k3M-rDC10fr@@(-2<FrDT7IbrZ68TF zku_6dAN@r=o2hbdw3Bh7&U$DMSW3F&|N4Zp1tv1O5b24A#*4fbW`Am=dBj@e>M|Z( zYQesHl+ilapMxfCPMvh(;>KgOLnq^DRSN2Dv5r^khKN|iLvt6UyIJ%D6(=n6<{1W` zvsP0fvjeXMjW|;;lm4OxR_0gyT2sPgcY50`D*PjXF01sxW$6xD=23tgy8wgET?~UV z#oz5*9M5224(Gg+Va%7_?gQ350txqswQ;}bVK^AcPb&2@3Ik-?CBIT^k2h6D(L=6C z0{aAa_CT<GQTAgq3y>sPza$x>Nx5_dN4e!_tdy2oiO=Antm{rN1p%~qW8WyFp}pW` zB-u)6PnT%@gt+@Xr2ekNyrJN^Zu^vG8=vs1DhoklT+>Cbi4rAE{rc}q>0I9(V|?~? z9MuC&DdTkr8pqx|w><H%cy~WsAInGy*nOE_jY=knw5AsNSler~ayijvy`#2>2a0DF z5zEHML{vBe49#5>3I!e&k8PrVYT;X4Yf_M$zFf?m!c~~=yM$k5?d)S8`An24skc88 z+w%Ug93GE^MY?jh#qQlYV2%>vH!H3U{<R>f0;rZh6m)OJW-CBDOO%-xxsleJ1T@j9 zX^RT-;H{NwvCHR>8DWNVC}+~nu4j{%+*)D<8s7>T$S}WtpYRBRXBJlCd@;<O+Hq%? z3#Tu^OvErB+csa4o8X!H5c(<e+xCXknJ#K6)RBO*i=9b=61Ua6ERaT5P2lY3D1xur z+Fr)aypKvNk<jZ&`xnPU9;B!Op~v#<v)V5*#UBWD#OR5{_*yY^l_QY2=|RN3+*3u^ z#I3&1B}@z^?FNGrc3}VLL%~(Y1#n{yrgee$M+BU*UwW71e3{obl>^Y?do@{&FrXsW zrYwmL=eqYTVg2I#RGv3_3qc&<2v&CEYlWz)Sl#r_SK~;mBjq?ue@OXv0&+O1is>8@ z)7F)A&00M+3HH0KYPFd>%VQJ$>wT>#oD5Kn2psv07`;iRt$RYNWD|#YrNH@Qad|`X zs5n_6#DvS7^M2wJ6lG>;|D;%AZS#eNdEY`fJj8_G{HQt-$|3LUn1SRp8`mNh;mek% zocIknymgS+*<u@lo-SRx@3Q#oEm~I7t$%Z_d4(R`?o9LILjnV@>sw;&Jl!uG{*;1A zH4)<aWzsnrPUc7K^X<wvNwhmgXr}(-)N1XM7+&RP6gnF98g4IF3HBhPyd$nX?C<+= zi1I)QyNx4Q;(hjrdSZiQVwsbDXWcBflWgbodm^1`ucT1yY{hZ0ECuxN9qO~bUp<!e z4G6(YWi#?9>aErL*VLI}m99gVKy^LpH$C#M90Yrx%!FkObG&*gCVc_XG2ens{5`pu zaP3V!>*FIMs)iiFT-O~vg%Ih3pNdbGyhO(P2}sPnM3_BFkEZiRj+~zD^5~dXu$$); zWvUV1Bu=<S?9%cd<qqTd*{9cEsE9>%TUW4<8+xnxU&!vGIvwl6^_N~)M5Z>S6hwP< zpvKtE5M&;+gglb3IZz5eMLe4C9h7Wi8^^llSYRIZVB&JtD2U1p%Zymz4Sxx-g0Af+ z@*bmv0oQauQC#6KdvezrJl0TDIdtCb`SC$=^ec`=6`_Zp6u|J}+nLd9O^=)UT7}=O zMy=Yjka`Ret^>OOCLIux9`!}uecX47_rA6E2-Qdwer`)IlBYaMfl{(9lfRP{^k|HD z|L*NeddA=wj&GyG&n2YO*bN~)dhdE)&^Nlzh?$%0n;2DL<)|YIP`ogrrlEGZVM1r> z7t2o&lL&&0?7zG^Ok<EZ9P#Z3peU*yVswY8n`l8&Yp&T|z6%wRg>0nQQwBj$&*zU# zhA^QfuXbd#W>LV96IEryk-L&PlP`3AHlF&hd*s%N5dnSnlM<y4IdRQ)zGV)2m0T5z zsTt`EYp;!x){Ix=|2?Tmy8ms1suFkqH4*wgSk1AiDSIqbzr+XGcC4222C7<wDroHl z!6~V>yNospkpy>g(rgy4r*iOyAX_5AD)4NQX3MwOsXWKO82Q*}=b``|G*xAjt+jDD z6dtQ)fUTS{PnX&-ypi7a_d$molC~081(=JEayrtITC3`LnVwUh!;wH30{Ex=(LV5z zyT_!@%Ig!V^=16+?+V8(NUF+C9g&3YrQ*LYm&dJ7CfhBXUy0Ve8m4+r1so-G=IPeW z6#c%420O_l60<X{LeE0#Dd|=I92z01E+3{k-<@b)2`aZ&YH)1dQk4kf043#WIHz0R zo0h6P-m#4&uzuWr5o$#(fYRL!ZI~I&M$QDaH!F`*5cgK0OuQ<PW-Kt!jAN~FHG$&D zi8#M6`o8udG}Dg%%=St0F)>oK6U=0@X62QmEMx0AQ|POV^KE^pqAdt@3@)q<S8CI7 z9;YHk(eb42=QagZzqQ{ud$iR0Llge48<K+c;A-Y16*hY#5~Bk0sLE4ULx`s5ou1}Y zF5c|pX1S%`NbUmJ(2$n7dFy(7k7KX}82!ATEQk9`>L{~al=^j(R`Z<xQ>pK^pF(SS zc+DlLD&do9<g>t%D*k%Qc8(AkJ3XjLWJa|ub=590J87yT_Dgp34SS~<b&+<yTY&It z#_Z0mth=vPxe*y0d^kwu7dB)CW<R~D#X^2R^XWEj=}2#oaeF17k%GMP)a&ovhizuH z;U&0KjSEDN4DTvv=S(LTyZ(uDg-j^ijRsM6xjonL7-LtUR*EPSv-5=WdLNDRWCaF( zJ5zp~AV#4FCYW%SE()@o({H>#F-;D`5p_2Yu#Wb8H!BQst4QRj^W=U%<MzFDee>Sp z4PO`f=L7}T`Pe%3Rvz6KF3cQf%c01?G2M1K_CJ?{2Q5GRv2g<9LpBmWOmfg33D{5Q z!>C`P+U;^Z4(_W;{EN=^{ZlqDx(SU_jq`_t8uHFQRuZ2e46NfrXqjT(!S9=5)B*{l zY`nGlf7D{B{F{LzBFP~KrNB#l>dXasf!=9lRS6};-+g8nok~*O;-{T{!=r!<2+@V1 z4CD8Jh2NG|Lr*ZV$!FAvdDmdT)cxqZhnv{3W+%-=DA(vk^_qY4+^x*tA%Pmtyc)5M zyltQJZNMIw=P8qa1Cg?p5GCt|gZCvrvI8}}_x$E|sVo1$+Zfo)ncn=62;F94GuIFM zGu6f5!r7!y?#}W+JPrIU%f2f6LI@gDWguDG%GQhh%DLNTefVI2hk)burWqEc<8`8b zCs^Ie%NkyhS{f0f^$e6me@Y6C5qglGG&=3NNw+ue&zI%o_Ka4JlXjb(!yG=fe&X1F zy1M7|s&#AkGxs)+yN>Q_8nDXr_eyeTj8(dyU7=RvhSZ$7Y|2?8&DoA~1oqy03c1~n zCNR1l^dPb5X`4@+<GClFWSAU>In&!8oaS()oT;wB(U;caNH01&M{E1#Kh8`cnGhw& zeq-RYt!{|3+vIKRhkm7L`D=14<k=6PvBRUMW`h-K;SA&T`wXschvMk#Um7(MM0FCz zP$mr$j}r5pmWMM0uTgrJ{WyNUe`*DSyMo4)V04IrEvID$9d-T;w(%Y82erpk-~_2R zb~MnKVS$5Tbq)J-^4Ck_y#|U*O@4GvrHlAs$$7*RP|Q7vbNw9p-{&ko22J{=p8U}O zB2xH^k>s))k>HsIqC<?>rvI%;NUC0|f67m;hak%PU~UVD($TxDXTjzote&YEnryKx zKVpta=~UR*%sVUmzWOdJuFl&<?QRhEMS)c2-&Q+7sRR}hWf3Os^SL>_=Ug&%>)6=) z*G#?RuR&Dk4F8D2=sv872c8AJ73nfzMdt5Oj|@4;hulSBISIdv--pKX8A_fvQ$4i% z5WTzMSQeaR#Aio^1VvTt{OoBl)NNnU9UU1s^@6*2*_jQmKy3I{$wEPtzeSOGs3B3~ zG24^B&6vw-ENO_x`BzdV!PBmBMART^=-64hw8Ta!N76(lTfpM>OEa25I3b$#TPd}G zgvnO0blX5j+?;9<#IAF+%`fEwO8NUXj4rEWkl`1x|J!_>LajGS0mg?hz`W)5@oBZ~ zN74>CTlLnuSjq3K(hA34`4d-nGU2VHr0_?s?goRj9OfRcP3z)MV+!6Y4ui2b+m3^s z?jX*y;V1>4-$RTO#MA<Z&-!Cry9y!x-Pm)L{L{3LnZpq6U76{}oaXDk$C`|?`p*66 zlQ&9r;@gQ~Ah?B5;A_ZN)8Z_#O%)`$Y6)}fCN1YP6`0)W^}PSU&=~2*(q$Ls;u-wK zaU!apmjeBynTub-QRuOIuUcq<15?&O+Zfq)p3(L)gj(NNv_uM;P`ft(=`bq>R64cT zd_UrEOh=Hh#iBdy{>u%+tg}vWKx0g*F4s@)*=e0W9{z;Y$-7f`%!&mi?JJ#JgT~DK zsv^6iJK~#ZZpZEAQ(DhVtX-AyUn6TkB;>1eF-CB63z4NvSx_cw)}lIWfd;9%odr6Y zw%U*Zs+@Cuh*M@HJbVyAkPCOJcG7L1csn~Xc!#+z1IZ$P;J^u^%SFAhYLNUxj5)i9 zd^)TWmniASgRVgXF;(qi9}X5!3&_lVR}(I_uopY>*31r=WfAXZC&~4wUkd@AVRVe8 zT7KsmHWF{(=$^cJaR7H5Q>FjM)2%3?;P*CP|GM%8M!?bBFn?U~cO^<W<df8m(Q4pe zSo5IeeDElBEfxO8(a6Qqn-K{@v>)WSS5$hz=p<7HiN7#4s_B|_a74t;+E78XVHtTg z8!JZ~<|=6W!{Ak}9_2&@-*?yj2NG*u!BNh&_JM82!q6Co)UExUN7g~S$fWoOzH13* zvMP`jO)=XZ>&LmM4}sNd)y|E2x~~L!qmAt8IYBe_MN>>r<DVtsST@YsH8h7TZ=%19 zvlJ`c3ZGhf(PB0h^}(d2Xgv4_HVUruRj=~YLl@L&`Kvl!nm`e3SP~#3P*8~c5h2iP zn80_Ifz^P6JO8}oSWiQOEt^WnpLjJO*%K6e9Wp2C`c2$bAd&7Tqqwnv4G9?CRLWM( zNh{kqFH*mo+VO-KsYxj(#WGUXRO3Wx@LN#Lgx$GbM=-r`-%m+b7zq+wH!JWh)AQpk zKz)cc75+n>>LG~KpLYI9YX$18EKoc-F28sRtM9-{c_v~-koqZ0oDB_b(i)U<seXk! ze~hW1F;4qHb5TQUvPZ#aR&G56HNH4WzA&|EUCV%TJ(6LpUt=fKY54KS?Q(P20S@*+ zo?ir+v`xRCkz`X+d?z#iWe+a-8qPJ2?t4#>25bc74EHO{nyOD_^xBi{y#jlw&mx(= z9nEKZtNKO3QJM#C-`_O(dtb7`>LL42a~kD#f$i8*rh{T)kSe8|?Txk|4Tsr>Km!sz z7>>y(q#%^Z3?=WG;ayckgCz0;56+^VS4cNb-Gv%&j<^(V0NZgS<zIj)F$^5ovYTb3 z4H_wcE$?g|O6#`g*r#WnmKpCMArsN(rNtlY+%_+y&$l?|g&s@)nihr!roby_SdZG< z_&MPu=J8>h7w0X<*E#0hW<PQLW#%;R(tEK*3vbGTqoj8S0g`2v0n4@CXU95ju?UiN z^+F0$UOQ1FsL49^Y0bE}SRSfRfAI@9;x^LUcImgnSpBIe9K23c9i@?2dUVpB4B_iq z^|lX;HU6anX<AsU9B-?41Ow`e-u;Pwnrks_k$4GlssIz+ICv%Zu5UCo4Sz}vMg)~* zPtMX7;C-)N4s1v-o_!QOGrXJsCl%fl0!L-7KPzy!6a2kt#M$BzI2Dt=`YS?J0tl_? z4@^3kZDbD)c8pk^JUDlg-NLn@A$(2AotU5x%1eu7pZoa|zRT0ME7vHO?|C2DDO0~d zVEpWqoDT>?q(_A~>l6wZ6A8DwK35dhXs*`QR9~9H>SOea#&Y<I`H|)>ncv@>N@CKH zkOa7B=9BK3?=-=JP~*oDc3ynU<}OYRToU)qhUtgp!i_Qx%{#JX977=G)OFbg*1P;S z2_+uwjY`jn?e(cZXmI`OdB?zNr@Ax<1T|(m*)NgN(<MXZR*PtC2F7EJR3ORS*c@?< zf%A{t!9;)r3wf(5Y-RtTB;k}B*~UtupO#|5JpOwS2Yg78mtjmhBMp_ab?7(xZ}>ja zC6S2BYB#Ws>2z<b+4DGG0%!o*?(J2U2r}R>F1(PlB}MsOfJT5U-R}yDr}~%MNz+ZP zX9BQ#()u-ZUAa`v4geX>Iv7dGv9>zCzMIlBdi~dlFZGMt*VJv_KpLO*B~3eRo=BqQ zFmXcTq8bAl@t$)UD?N|*`YOg7MKa+OdL&v&`wl=oW=5)EJl=vayIXpaXN_G=HIZ=P z=}%n#L+8-NcnYFki_K)-NLa&liM5+Afn1bHg~YQ!JBvkKGV()%k;B~BkT9cLPj>ps zeAiNJpX;^v$Oh!2hR6`cEnKR^MXG*TA_>|q-FmiS8s(-lCj2OfW|h%k3FY90qIdGP zf%M$#&;>j6EHfD#=N6wgl2Ng_6R{a^6ZqgVx^zOCsIN%5@{uxIf3HM&s2H7+NJMFo zjLG?dZ)uIE;o9vaw=ha*NaIur118XPSYlW%%IFTEm*2?ZEPql*^jj3wO#8s9ZBiI8 z#<0I^*G#TKi)iPKJu$Zx(d?Br;Np*jXbO!Cg`sqZ?sFdLTMZ!>T8B79%a2%&do&W= zqE%O|b=r}&zaj4*U4s;0J>3qfI8?HjjxQ64R67~-^mjVPI9qbKYiX6h?D`t<KUjfn zy7p^?RB_juJeTyd;XZ7L^G6<4V)h!%65m>Cv%Ant?G!GzliP?=SBrRYq40%kNb)yC zjS;fX1Z0a3O0r#&|8QebR9w6BD!Ou<8L1Ud^+qMV8|%GAEON9R2Z*KpVtswww$QB{ z2@uWAp_xxsC|&U*n1f4p=IN`&aWv7ws_BfMuJYhc{6)JA$H927Z6wm92m1+&3R}O~ z^0YU{@BC}s?+Yz-RahwBx6LXSajk*=|5UrL+dwq=V02N#QV+bFh{be=8C3|f*2}tI z>OCu5w1KZG>a~-6$FEQm^))C}(o>KP2pwj6uHq<>Z^(N>cK@x7N;9hcxL$;!;#j$c z33~IS?D&s?4zqV5_737flsS0=#@T5t_0E(?fg#J5;(%>?l%shO>diLgNA2Oxp>Y?V zj%nvaePyl*GVYo6g{7Vbf2tO4+Xrmhm0B{9)Y><mu^nBIC&nd+q>5BJSXR*M*_|4z zb@Zh|G`ZXhp-Hj$E(3&;<usg({(&Tv{KjXu(8JImOkduc{6+X3@ENf)pRG<p=KdpJ z2K{t#WL?bp<kyJ2?yV%BZ`UsVJ4i@T;tVXcwx}q|=(95$$kVtde!vP%%KwUND9U^2 z+&yOJ!y2XEOb&1R=)&x6+}CNUl{%GS3DLA7@XxYZL{-%sK+23X&wCnAX|P4A^pCh` zR)2QqsTr{w@^g=itAN?jJGTXTP50tY&P+FpVq1eo5NvIx#+)Xcj~g8=`WCajyWhW; zb^1l^A@n;El<fN6ZdM54ZKO<bFOPTb&L&e*m4U#qlMb^)v$d+TQbQ^~)eGH*s>~22 z#8ZLd!DmRSF5|YKSIVFGtxkk>IrB}@i*??bO$KOeEpx91>a|B@!t@ody;A_jeY2GP z@S$-hDgQM)yYdvxLxG)|0+A2Cx)sFSI~(pW35-uVDHnbO2?hua)O0pWTC<}>X40B8 z&SM3<9reOf_@SB8pMkB1z}`}+`%xD4Qe5(B1KN}=Nte;*Aia;TR1)s3-<M?S{d@10 z!9Ev`>y4D?NS8~}_eA(NvFB`4+mDMDrL$CB?k*3LTT8rBQ0=8`2)Y^G@W80eh6tbu zCG^3w>jD@>=}$)v*cD*q=v7CeSm&&rTfLr^d!r4f-JuXZs#)gSR05R*v4)2H2{rRc zYhrhAtIQ>a?x2rYFi#v4PSxW*)cQnQvf1OZ?q*ZS?|xTjY%?APp+QBt-u>_H7#<G1 zl5S-g5$_jGQE2R>Or05fGwX5GQF`LSbc1c)?MweP)J$b9#U|QgeC5vU<$Fc157S-9 zKUxz0q8()kQ#^@U4(Y>dw;^v)eL1CB?zHXMlYV-aZSQk749f$3KVKsc^-KNQ_n@>U zdaT#8&C319$w9yiV0p(x39CoPNnlVREh5Xt+^Wx*>^>zFUl@*-if7%b&-pcsK_9Zd zjrW-{At&OTsV;XZj~XsOaZjEqfIPCx!gt%p%;-<6`*Zd=&K?5EcF)50HXUo|4D0r6 z9Wm8cSX&ITbN`&h?F{OwWCAnqvVEV91lL{K=bkOqyQQU)Ri~Noqc?n6Om^?E_pA@a zWD{z-XK1@al_iEV?kzmzVl#I<de`%~={_BFK|tKB&UE<PD7aW=Yf^NQ{8e}U8)tf! zaUHY_FK1#xoqmEH#&|H@0jcwe_0GxBlMXv;7+n*SP}zbN#W!hSI)5~rZxp;5tmbQN z^Xn()stQuM>CC)=EM=7m8Q8d5P@cTziD_BdtRO11%}>hSsC#g<Fm?o7)@$ky6lDe> z413k;E>0r#b{$T!rB%c<(GuUVfi&-O7Cm3<vlnX?N?`nY1J~SJ%bw}}i9Z~Ci_KeH zt2_JXl;n_T3>?5b&K-3#LX6v|&U)_2zSH(;5jAUyLp%cKk6fR49DS2cC9F*G@AomY z_6Q$(T}s+?<*hdmkal~dKj`rvax4hAM7h9c&fTm81Id9|ZPxg+tCe)`AVDB#%wJb} zdJu<sXTM42D<S}|tMHy75{!Ri(tb}$?MlIG;By5S1yPzFbF%lBrxe#B1_VDeS~xfL zm@;1j<)Us1r`{(c!+W8XMiSwDY@Uc3sr>VHXV%4t#SU0c1K#eN2-eMD5rkks)?#V% z|GJbR#=D;RKzQV<qN_rIH=wk}*X*8!j87!Q$AQThL_qP5WPwXX0JgG?j;C6feZGH2 zF;YVP?Ek|t_vn9KVWNBRGG-FIQc<5XcfAKca7z~&Q{T|fLWqA^ec;kE#bJl|XX3Zf zBV^nEVoAKb&WRUIE6WgAvqNg3uOQ5ADByXtNEs?LLw*c_g8)Ke9&6Nlzg(<FLhztk z%x7Fu7U5U1)f_H79YhWg(Bs9{^X6&8u9U~TdS=Mn%v33_@?g^#MUAh=jfIPP_Z|47 zLHGnTu73>e33_<N!X{_E#F;k|SjOQUtWG~r6hAcz#fu3VU4AXHMf$zE0+P9V%<-Zr zo#~%7(}1Hu^dRe1?9~?7Ej6x$s}P1xQ*nMn>U#g+;>3x^Ri0^FK~Zv=yEu4;G){ox zL*)M{PTtgSLjI3?JsC#dMOw8V>U39mxx<%rP}NlaKkERA-Y>C5|L}3n(f6KNAQ{50 zDERI*^q$@Nko8|wsoQsQE*h|G|4O~f`5uivA@%aa`0S4VxxUoQJ8Auox-qezn{)MR z|0IDh$NYm?SG}+57Lr`ZK6igb`b7&|(JyA|cH|b{Y^p11hff$?S)0|ECHew=#R={Q z8?M=;@Xo(zO*&`?GOeo2-dr(}*fS0_pv|aBxU!Q8G&Og@8h$lD%>V2fdmWYNC(*O6 zdJbQa{mi|mV%Cj6dudn_`!By23lAz9Ul*x9)1?1L3meWCxs;O{!0-=Bt%=AQ(p}PE zSoMDvymxR#dF`6$eX)N6PW9WH)~{c)tDZ3aldx~H8gP(*a+kN2ofO}dY7eU(xYW}s zs~l4N-{^b>(m%$oX{N4@U!hp=_%eO?@w#o$XRHGW0ltOwEUvNPaD5&a><tJQ-%9M8 z{#$ZFEA{LXUD>#==F@@uqDT{=YR^K3?*;is{OQ$I8~sNENvlc#j-E)6Ybi$X!of`= z`FpC!q2^Q=#_=-<n4Y2wT!(P}9l1VXSYjjra3QqwzhB|*vkriR<^FS3*JKgEU*wyf zaTBSvTbTHSv!@U+aFGv>U@Xzeg-`Zzc@$bK@fxZ(O&&$5i$Bz<{;rQKLVxAE+x+6@ zt#(3Ek5>n@gTA#J{hu`xJsPm0aNrUYUF6e#{x(ww1D)9d7hp|)jY<G-^^bJR#YhP8 zB~$faA`z4{>AI$T{-RTwz;eOIXj@?IlsdgH6$JzsLI-r>z1ahoyIwWZgURa%N^pWz zX6r+t-+S`?7yQ|*)oXAD-C{xDN;4q5DF~c1=6ruu(WEGww9WyHH9(l}y-s}D>(97S z2g+kSr^ISB>YLIL<Z!ASaK7XFtQSY2o>VqLpBB67J&Ldz))y&r&x?T@%-TX@8fgdn zCnUoBq#X-En}-ZYt>k6N1KKA)<lJ0g^fYg6PX4|XYJ1{*z?Ha6k>T;PkwkdQY8AM! zt9?>vnqEB68k{aAF>Y*@qM!I})jR8lUXJ7GVa0frHgJhoB?Z`e{7Ec*z>3bY+!aQU zsSKnz7}lD29L;^8z}J5aka_pOeDVWd7LAH+qemuIKdSWy`;X8-&9QLr-4!L^K5?(w z0dN`;GR&@6NTnh3aF_x)N$F$fVuSr<sFBt~^9_hSsqNf${KzM`h0MJ`spsqoQd#Xp zAE&oVb$gXNi66)VjZ<5(*-C?8mZb5ptx1p-ljMCN2CMRy@PqZ{oW(V(PlG>Z&Ag+_ z)21|c0ej}eelrLCVEHHayRo16$VgdA6MeIqPJnL)x>?v+qf4J!b<TzY#1^kzK2{uI zW>a;!dpO@#|Km1?>?Ju8`upY(-yS0f1VVTyKJl=6?qMxq>1GZ50SO5R3GfPt@d}CQ y3yMn!ibx2Ga|;Ma2ndKD3n~3S3QjIob~e8Me+4D%Yy7`#fRKus3gr*YL;nwKka6Vz literal 0 HcmV?d00001 diff --git a/GreenshotPicasaPlugin/PicasaConfiguration.cs b/GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs similarity index 72% rename from GreenshotPicasaPlugin/PicasaConfiguration.cs rename to GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs index 202929459..7e1b614b2 100644 --- a/GreenshotPicasaPlugin/PicasaConfiguration.cs +++ b/GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs @@ -1,93 +1,93 @@ -/* - * A Picasa Plugin for Greenshot - * Copyright (C) 2011 Francis Noel - * - * For more information see: http://getgreenshot.org/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -using System.Windows.Forms; -using GreenshotPlugin.Core; -using System; -using GreenshotPicasaPlugin.Forms; -using GreenshotPlugin.IniFile; - -namespace GreenshotPicasaPlugin { - /// <summary> - /// Description of PicasaConfiguration. - /// </summary> - [IniSection("Picasa", Description = "Greenshot Picasa Plugin configuration")] - public class PicasaConfiguration : IniSection { - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat { get; set; } - - [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality { get; set; } - - [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Picasa link to clipboard.", DefaultValue = "true")] - public bool AfterUploadLinkToClipBoard { get; set; } - [IniProperty("AddFilename", Description = "Is the filename passed on to Picasa", DefaultValue = "False")] - public bool AddFilename { - get; - set; - } - - [IniProperty("UploadUser", Description = "The Picasa user to upload to", DefaultValue = "default")] - public string UploadUser { - get; - set; - } - - [IniProperty("UploadAlbum", Description = "The Picasa album to upload to", DefaultValue = "default")] - public string UploadAlbum { - get; - set; - } - - [IniProperty("RefreshToken", Description = "Picasa authorization refresh Token", Encrypted = true)] - public string RefreshToken { - get; - set; - } - - /// <summary> - /// Not stored - /// </summary> - public string AccessToken { - get; - set; - } - - /// <summary> - /// Not stored - /// </summary> - public DateTimeOffset AccessTokenExpires { - get; - set; - } - - /// <summary> - /// A form for token - /// </summary> - /// <returns>bool true if OK was pressed, false if cancel</returns> - public bool ShowConfigDialog() { - DialogResult result = new SettingsForm().ShowDialog(); - if (result == DialogResult.OK) { - return true; - } - return false; - } - - } -} +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +using System.Windows.Forms; +using GreenshotPlugin.Core; +using System; +using GreenshotGooglePhotosPlugin.Forms; +using GreenshotPlugin.IniFile; + +namespace GreenshotGooglePhotosPlugin { + /// <summary> + /// Description of GooglePhotosConfiguration. + /// </summary> + [IniSection("GooglePhotos", Description = "Greenshot GooglePhotos Plugin configuration")] + public class GooglePhotosConfiguration : IniSection { + [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send GooglePhotos link to clipboard.", DefaultValue = "true")] + public bool AfterUploadLinkToClipBoard { get; set; } + [IniProperty("AddFilename", Description = "Is the filename passed on to GooglePhotos", DefaultValue = "False")] + public bool AddFilename { + get; + set; + } + + [IniProperty("UploadUser", Description = "The GooglePhotos user to upload to", DefaultValue = "default")] + public string UploadUser { + get; + set; + } + + [IniProperty("UploadAlbum", Description = "The GooglePhotos album to upload to", DefaultValue = "default")] + public string UploadAlbum { + get; + set; + } + + [IniProperty("RefreshToken", Description = "GooglePhotos authorization refresh Token", Encrypted = true)] + public string RefreshToken { + get; + set; + } + + /// <summary> + /// Not stored + /// </summary> + public string AccessToken { + get; + set; + } + + /// <summary> + /// Not stored + /// </summary> + public DateTimeOffset AccessTokenExpires { + get; + set; + } + + /// <summary> + /// A form for token + /// </summary> + /// <returns>bool true if OK was pressed, false if cancel</returns> + public bool ShowConfigDialog() { + DialogResult result = new SettingsForm().ShowDialog(); + if (result == DialogResult.OK) { + return true; + } + return false; + } + + } +} diff --git a/GreenshotPicasaPlugin/PicasaDestination.cs b/GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs similarity index 75% rename from GreenshotPicasaPlugin/PicasaDestination.cs rename to GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs index 4107ecd48..586a6e842 100644 --- a/GreenshotPicasaPlugin/PicasaDestination.cs +++ b/GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs @@ -1,54 +1,54 @@ -/* - * A Picasa Plugin for Greenshot - * Copyright (C) 2011 Francis Noel - * - * For more information see: http://getgreenshot.org/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -using System.ComponentModel; -using System.Drawing; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; - -namespace GreenshotPicasaPlugin { - public class PicasaDestination : AbstractDestination { - private readonly PicasaPlugin _plugin; - public PicasaDestination(PicasaPlugin plugin) { - _plugin = plugin; - } - - public override string Designation => "Picasa"; - - public override string Description => Language.GetString("picasa", LangKey.upload_menu_item); - - public override Image DisplayIcon { - get { - ComponentResourceManager resources = new ComponentResourceManager(typeof(PicasaPlugin)); - return (Image)resources.GetObject("Picasa"); - } - } - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); - if (uploaded) { - exportInformation.ExportMade = true; - exportInformation.Uri = uploadUrl; - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +using System.ComponentModel; +using System.Drawing; +using GreenshotPlugin.Core; +using GreenshotPlugin.Interfaces; + +namespace GreenshotGooglePhotosPlugin { + public class GooglePhotosDestination : AbstractDestination { + private readonly GooglePhotosPlugin _plugin; + public GooglePhotosDestination(GooglePhotosPlugin plugin) { + _plugin = plugin; + } + + public override string Designation => "GooglePhotos"; + + public override string Description => Language.GetString("googlephotos", LangKey.upload_menu_item); + + public override Image DisplayIcon { + get { + ComponentResourceManager resources = new ComponentResourceManager(typeof(GooglePhotosPlugin)); + return (Image)resources.GetObject("GooglePhotos"); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); + if (uploaded) { + exportInformation.ExportMade = true; + exportInformation.Uri = uploadUrl; + } + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} diff --git a/GreenshotPicasaPlugin/PicasaPlugin.cs b/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs similarity index 68% rename from GreenshotPicasaPlugin/PicasaPlugin.cs rename to GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs index a8f312484..b5d37f62c 100644 --- a/GreenshotPicasaPlugin/PicasaPlugin.cs +++ b/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs @@ -1,125 +1,124 @@ -/* - * A Picasa Plugin for Greenshot - * Copyright (C) 2011 Francis Noel - * - * For more information see: http://getgreenshot.org/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -using System; -using System.ComponentModel; -using System.Drawing; -using System.IO; -using System.Windows.Forms; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; - -namespace GreenshotPicasaPlugin { - /// <summary> - /// This is the Picasa base code - /// </summary> - [Plugin("Picasa", true)] - public class PicasaPlugin : IGreenshotPlugin { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PicasaPlugin)); - private static PicasaConfiguration _config; - private ComponentResourceManager _resources; - private ToolStripMenuItem _itemPlugInRoot; - - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected void Dispose(bool disposing) { - if (disposing) { - if (_itemPlugInRoot != null) { - _itemPlugInRoot.Dispose(); - _itemPlugInRoot = null; - } - } - } - - /// <summary> - /// Implementation of the IGreenshotPlugin.Initialize - /// </summary> - public bool Initialize() { - SimpleServiceProvider.Current.AddService<IDestination>(new PicasaDestination(this)); - - // Get configuration - _config = IniConfig.GetIniSection<PicasaConfiguration>(); - _resources = new ComponentResourceManager(typeof(PicasaPlugin)); - - _itemPlugInRoot = new ToolStripMenuItem - { - Text = Language.GetString("picasa", LangKey.Configure), - Image = (Image) _resources.GetObject("Picasa") - }; - _itemPlugInRoot.Click += ConfigMenuClick; - PluginUtils.AddToContextMenu(_itemPlugInRoot); - Language.LanguageChanged += OnLanguageChanged; - return true; - } - - public void OnLanguageChanged(object sender, EventArgs e) { - if (_itemPlugInRoot != null) { - _itemPlugInRoot.Text = Language.GetString("picasa", LangKey.Configure); - } - } - - public void Shutdown() { - Log.Debug("Picasa Plugin shutdown."); - Language.LanguageChanged -= OnLanguageChanged; - //host.OnImageEditorOpen -= new OnImageEditorOpenHandler(ImageEditorOpened); - } - - /// <summary> - /// Implementation of the IPlugin.Configure - /// </summary> - public void Configure() { - _config.ShowConfigDialog(); - } - - public void ConfigMenuClick(object sender, EventArgs eventArgs) { - Configure(); - } - - public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality); - try { - string url = null; - new PleaseWaitForm().ShowAndWait("Picasa", Language.GetString("picasa", LangKey.communication_wait), - delegate - { - string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); - url = PicasaUtils.UploadToPicasa(surfaceToUpload, outputSettings, captureDetails.Title, filename); - } - ); - uploadUrl = url; - - if (uploadUrl != null && _config.AfterUploadLinkToClipBoard) { - ClipboardHelper.SetClipboardData(uploadUrl); - } - return true; - } catch (Exception e) { - Log.Error("Error uploading.", e); - MessageBox.Show(Language.GetString("picasa", LangKey.upload_failure) + " " + e.Message); - } - uploadUrl = null; - return false; - } - } -} +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +using System; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using GreenshotPlugin.Controls; +using GreenshotPlugin.Core; +using GreenshotPlugin.IniFile; +using GreenshotPlugin.Interfaces; +using GreenshotPlugin.Interfaces.Plugin; + +namespace GreenshotGooglePhotosPlugin { + /// <summary> + /// This is the GooglePhotos base code + /// </summary> + [Plugin("GooglePhotos", true)] + public class GooglePhotosPlugin : IGreenshotPlugin { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosPlugin)); + private static GooglePhotosConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInRoot; + + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (!disposing) return; + if (_itemPlugInRoot == null) return; + _itemPlugInRoot.Dispose(); + _itemPlugInRoot = null; + } + + /// <summary> + /// Implementation of the IGreenshotPlugin.Initialize + /// </summary> + public bool Initialize() { + SimpleServiceProvider.Current.AddService<IDestination>(new GooglePhotosDestination(this)); + + // Get configuration + _config = IniConfig.GetIniSection<GooglePhotosConfiguration>(); + _resources = new ComponentResourceManager(typeof(GooglePhotosPlugin)); + + _itemPlugInRoot = new ToolStripMenuItem + { + Text = Language.GetString("googlephotos", LangKey.Configure), + Image = (Image) _resources.GetObject("GooglePhotos") + }; + _itemPlugInRoot.Click += ConfigMenuClick; + PluginUtils.AddToContextMenu(_itemPlugInRoot); + Language.LanguageChanged += OnLanguageChanged; + return true; + } + + public void OnLanguageChanged(object sender, EventArgs e) { + if (_itemPlugInRoot != null) { + _itemPlugInRoot.Text = Language.GetString("googlephotos", LangKey.Configure); + } + } + + public void Shutdown() { + Log.Debug("GooglePhotos Plugin shutdown."); + Language.LanguageChanged -= OnLanguageChanged; + //host.OnImageEditorOpen -= new OnImageEditorOpenHandler(ImageEditorOpened); + } + + /// <summary> + /// Implementation of the IPlugin.Configure + /// </summary> + public void Configure() { + _config.ShowConfigDialog(); + } + + public void ConfigMenuClick(object sender, EventArgs eventArgs) { + Configure(); + } + + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality); + try { + string url = null; + new PleaseWaitForm().ShowAndWait("GooglePhotos", Language.GetString("googlephotos", LangKey.communication_wait), + delegate + { + string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); + url = GooglePhotosUtils.UploadToGooglePhotos(surfaceToUpload, outputSettings, captureDetails.Title, filename); + } + ); + uploadUrl = url; + + if (uploadUrl != null && _config.AfterUploadLinkToClipBoard) { + ClipboardHelper.SetClipboardData(uploadUrl); + } + return true; + } catch (Exception e) { + Log.Error("Error uploading.", e); + MessageBox.Show(Language.GetString("googlephotos", LangKey.upload_failure) + " " + e.Message); + } + uploadUrl = null; + return false; + } + } +} diff --git a/GreenshotPicasaPlugin/PicasaPlugin.resx b/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx similarity index 96% rename from GreenshotPicasaPlugin/PicasaPlugin.resx rename to GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx index de5045226..240e4a53e 100644 --- a/GreenshotPicasaPlugin/PicasaPlugin.resx +++ b/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx @@ -118,7 +118,7 @@ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> - <data name="Picasa" type="System.Resources.ResXFileRef, System.Windows.Forms"> - <value>picasa.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> + <data name="GooglePhotos" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>GooglePhotos.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> </root> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/PicasaUtils.cs b/GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs similarity index 74% rename from GreenshotPicasaPlugin/PicasaUtils.cs rename to GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs index eb2b2be2e..27aa13d8f 100644 --- a/GreenshotPicasaPlugin/PicasaUtils.cs +++ b/GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs @@ -1,119 +1,120 @@ -/* - * A Picasa Plugin for Greenshot - * Copyright (C) 2011 Francis Noel - * - * For more information see: http://getgreenshot.org/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -using GreenshotPlugin.Core; -using System; -using System.Xml; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; - -namespace GreenshotPicasaPlugin { - /// <summary> - /// Description of PicasaUtils. - /// </summary> - public static class PicasaUtils { - private const string PicasaScope = "https://picasaweb.google.com/data/"; - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PicasaUtils)); - private static readonly PicasaConfiguration Config = IniConfig.GetIniSection<PicasaConfiguration>(); - private const string AuthUrl = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}&scope=" + PicasaScope; - private const string TokenUrl = "https://www.googleapis.com/oauth2/v3/token"; - private const string UploadUrl = "https://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}"; - - /// <summary> - /// Do the actual upload to Picasa - /// </summary> - /// <param name="surfaceToUpload">Image to upload</param> - /// <param name="outputSettings"></param> - /// <param name="title"></param> - /// <param name="filename"></param> - /// <returns>PicasaResponse</returns> - public static string UploadToPicasa(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) { - // Fill the OAuth2Settings - var settings = new OAuth2Settings - { - AuthUrlPattern = AuthUrl, - TokenUrl = TokenUrl, - CloudServiceName = "Picasa", - ClientId = PicasaCredentials.ClientId, - ClientSecret = PicasaCredentials.ClientSecret, - AuthorizeMode = OAuth2AuthorizeMode.LocalServer, - RefreshToken = Config.RefreshToken, - AccessToken = Config.AccessToken, - AccessTokenExpires = Config.AccessTokenExpires - }; - - // Copy the settings from the config, which is kept in memory and on the disk - - try { - var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum), settings); - if (Config.AddFilename) { - webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename)); - } - SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename); - container.Upload(webRequest); - - string response = NetworkHelper.GetResponseAsString(webRequest); - - return ParseResponse(response); - } finally { - // Copy the settings back to the config, so they are stored. - Config.RefreshToken = settings.RefreshToken; - Config.AccessToken = settings.AccessToken; - Config.AccessTokenExpires = settings.AccessTokenExpires; - Config.IsDirty = true; - IniConfig.Save(); - } - } - - /// <summary> - /// Parse the upload URL from the response - /// </summary> - /// <param name="response"></param> - /// <returns></returns> - public static string ParseResponse(string response) { - if (response == null) { - return null; - } - try { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(response); - XmlNodeList nodes = doc.GetElementsByTagName("link", "*"); - if(nodes.Count > 0) { - string url = null; - foreach(XmlNode node in nodes) { - if (node.Attributes != null) { - url = node.Attributes["href"].Value; - string rel = node.Attributes["rel"].Value; - // Pictures with rel="http://schemas.google.com/photos/2007#canonical" are the direct link - if (rel != null && rel.EndsWith("canonical")) { - break; - } - } - } - return url; - } - } catch(Exception e) { - Log.ErrorFormat("Could not parse Picasa response due to error {0}, response was: {1}", e.Message, response); - } - return null; - } - } -} +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using GreenshotPlugin.Core; +using System; +using System.Xml; +using GreenshotPlugin.Core.OAuth; +using GreenshotPlugin.IniFile; +using GreenshotPlugin.Interfaces; +using GreenshotPlugin.Interfaces.Plugin; + +namespace GreenshotGooglePhotosPlugin { + /// <summary> + /// Description of GooglePhotosUtils. + /// </summary> + public static class GooglePhotosUtils { + private const string GooglePhotosScope = "https://picasaweb.google.com/data/"; + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosUtils)); + private static readonly GooglePhotosConfiguration Config = IniConfig.GetIniSection<GooglePhotosConfiguration>(); + private const string AuthUrl = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}&scope=" + GooglePhotosScope; + private const string TokenUrl = "https://www.googleapis.com/oauth2/v3/token"; + private const string UploadUrl = "https://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}"; + + /// <summary> + /// Do the actual upload to GooglePhotos + /// </summary> + /// <param name="surfaceToUpload">Image to upload</param> + /// <param name="outputSettings">SurfaceOutputSettings</param> + /// <param name="title">string</param> + /// <param name="filename">string</param> + /// <returns>GooglePhotosResponse</returns> + public static string UploadToGooglePhotos(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) { + // Fill the OAuth2Settings + var settings = new OAuth2Settings + { + AuthUrlPattern = AuthUrl, + TokenUrl = TokenUrl, + CloudServiceName = "GooglePhotos", + ClientId = GooglePhotosCredentials.ClientId, + ClientSecret = GooglePhotosCredentials.ClientSecret, + AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, + RefreshToken = Config.RefreshToken, + AccessToken = Config.AccessToken, + AccessTokenExpires = Config.AccessTokenExpires + }; + + // Copy the settings from the config, which is kept in memory and on the disk + + try { + var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum), settings); + if (Config.AddFilename) { + webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename)); + } + SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename); + container.Upload(webRequest); + + string response = NetworkHelper.GetResponseAsString(webRequest); + + return ParseResponse(response); + } finally { + // Copy the settings back to the config, so they are stored. + Config.RefreshToken = settings.RefreshToken; + Config.AccessToken = settings.AccessToken; + Config.AccessTokenExpires = settings.AccessTokenExpires; + Config.IsDirty = true; + IniConfig.Save(); + } + } + + /// <summary> + /// Parse the upload URL from the response + /// </summary> + /// <param name="response"></param> + /// <returns></returns> + public static string ParseResponse(string response) { + if (response == null) { + return null; + } + try { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + XmlNodeList nodes = doc.GetElementsByTagName("link", "*"); + if(nodes.Count > 0) { + string url = null; + foreach(XmlNode node in nodes) { + if (node.Attributes != null) { + url = node.Attributes["href"].Value; + string rel = node.Attributes["rel"].Value; + // Pictures with rel="http://schemas.google.com/photos/2007#canonical" are the direct link + if (rel != null && rel.EndsWith("canonical")) { + break; + } + } + } + return url; + } + } catch(Exception e) { + Log.ErrorFormat("Could not parse GooglePhotos response due to error {0}, response was: {1}", e.Message, response); + } + return null; + } + } +} diff --git a/GreenshotPicasaPlugin/GreenshotPicasaPlugin.Credentials.template b/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template similarity index 83% rename from GreenshotPicasaPlugin/GreenshotPicasaPlugin.Credentials.template rename to GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template index 47172f2d4..452922112 100644 --- a/GreenshotPicasaPlugin/GreenshotPicasaPlugin.Credentials.template +++ b/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template @@ -19,13 +19,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -namespace GreenshotPicasaPlugin { +namespace GreenshotGooglePhotosPlugin { /// <summary> /// This class is merely a placeholder for the file keeping the API key and secret for dropbox integration. /// You can set your own values here /// </summary> - public static class PicasaCredentials { - public static string ClientId = "${Picasa_ClientId}"; - public static string ClientSecret = "${Picasa_ClientSecret}"; + public static class GooglePhotosCredentials { + public static string ClientId = "${GooglePhotos_ClientId}"; + public static string ClientSecret = "${GooglePhotos_ClientSecret}"; } } diff --git a/GreenshotPicasaPlugin/GreenshotPicasaPlugin.csproj b/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj similarity index 62% rename from GreenshotPicasaPlugin/GreenshotPicasaPlugin.csproj rename to GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj index ac827cfec..3fb62aa99 100644 --- a/GreenshotPicasaPlugin/GreenshotPicasaPlugin.csproj +++ b/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj @@ -1,21 +1,15 @@ -<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> - - <PropertyGroup> - <RootNamespace>GreenshotPicasaPlugin</RootNamespace> - <AssemblyName>GreenshotPicasaPlugin</AssemblyName> - </PropertyGroup> - - <ItemGroup> - <None Include="Languages\language*.xml"> - <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> - </None> - </ItemGroup> - - <ItemGroup> - <EmbeddedResource Include="Picasa.png" /> - </ItemGroup> - - <ItemGroup> - <ProjectReference Include="..\GreenshotPlugin\GreenshotPlugin.csproj" /> - </ItemGroup> +<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> + <ItemGroup> + <None Include="Languages\language*.xml"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + </ItemGroup> + + <ItemGroup> + <EmbeddedResource Include="GooglePhotos.png" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\GreenshotPlugin\GreenshotPlugin.csproj" /> + </ItemGroup> </Project> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/LanguageKeys.cs b/GreenshotGooglePhotosPlugin/LanguageKeys.cs similarity index 89% rename from GreenshotPicasaPlugin/LanguageKeys.cs rename to GreenshotGooglePhotosPlugin/LanguageKeys.cs index c22e4c404..1a7a73996 100644 --- a/GreenshotPicasaPlugin/LanguageKeys.cs +++ b/GreenshotGooglePhotosPlugin/LanguageKeys.cs @@ -1,29 +1,29 @@ -/* - * A Picasa Plugin for Greenshot - * Copyright (C) 2011 Francis Noel - * - * For more information see: http://getgreenshot.org/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -namespace GreenshotPicasaPlugin { - public enum LangKey - { - upload_menu_item, - upload_failure, - communication_wait, - Configure - } -} +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +namespace GreenshotGooglePhotosPlugin { + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + Configure + } +} diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-cs-CZ.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml similarity index 74% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-cs-CZ.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml index 4fe14494b..7168b569c 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-cs-CZ.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml @@ -1,29 +1,29 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Czech" ietf="cs-CZ" version="1.1.0.2411" languagegroup=""> - <resources> - <resource name="CANCEL">Zrušit</resource> - <resource name="communication_wait">Probíhá komunikace s Picasem. Prosím počkejte ...</resource> - <resource name="Configure">Konfigurace</resource> - <resource name="delete_question">Opravdu chcete odstranit obrázek {0} z Picasa?</resource> - <resource name="delete_title">Odstranit Picasa {0}</resource> - <resource name="History">Historie</resource> - <resource name="InvalidCredentials">Neplatná oprávnění. Otevřít nastavení pro provedené změn.</resource> - <resource name="label_AfterUpload">Po odeslání</resource> - <resource name="label_AfterUploadLinkToClipBoard">Kopírovat odkaz do schránky</resource> - <resource name="label_AfterUploadOpenHistory">Zobrazit historii</resource> - <resource name="label_DefaultSize">Výchozí velikost</resource> - <resource name="label_Password">Heslo</resource> - <resource name="label_upload_format">Formát obrázku</resource> - <resource name="label_Username">Jméno</resource> - <resource name="OK">OK</resource> - <resource name="PictureDisplaySize.OriginalUrl">Originál URL</resource> - <resource name="PictureDisplaySize.SquareThumbnailUrl">Čtvercové náhledy URL ???</resource> - <resource name="PictureDisplaySize.WebUrl">Webová adresa URL</resource> - <resource name="settings_title">Nastavení Picasa</resource> - <resource name="Upload">Nahrát</resource> - <resource name="upload_failure">Nahrání obrázku do Picasa se nezdařilo:</resource> - <resource name="upload_menu_item">Nahrát do Picasa</resource> - <resource name="upload_success">Úspěšně odeslaný obrázek do Picasa!</resource> - <resource name="UsernameNotSet">Prosím ověřit aplikaci Picasa. Otevřít nastavení obrazovky. ???</resource> - </resources> +<?xml version="1.0" encoding="utf-8"?> +<language description="Czech" ietf="cs-CZ" version="1.1.0.2411" languagegroup=""> + <resources> + <resource name="CANCEL">Zrušit</resource> + <resource name="communication_wait">Probíhá komunikace s Picasem. Prosím počkejte ...</resource> + <resource name="Configure">Konfigurace</resource> + <resource name="delete_question">Opravdu chcete odstranit obrázek {0} z GooglePhotos?</resource> + <resource name="delete_title">Odstranit GooglePhotos {0}</resource> + <resource name="History">Historie</resource> + <resource name="InvalidCredentials">Neplatná oprávnění. Otevřít nastavení pro provedené změn.</resource> + <resource name="label_AfterUpload">Po odeslání</resource> + <resource name="label_AfterUploadLinkToClipBoard">Kopírovat odkaz do schránky</resource> + <resource name="label_AfterUploadOpenHistory">Zobrazit historii</resource> + <resource name="label_DefaultSize">Výchozí velikost</resource> + <resource name="label_Password">Heslo</resource> + <resource name="label_upload_format">Formát obrázku</resource> + <resource name="label_Username">Jméno</resource> + <resource name="OK">OK</resource> + <resource name="PictureDisplaySize.OriginalUrl">Originál URL</resource> + <resource name="PictureDisplaySize.SquareThumbnailUrl">Čtvercové náhledy URL ???</resource> + <resource name="PictureDisplaySize.WebUrl">Webová adresa URL</resource> + <resource name="settings_title">Nastavení GooglePhotos</resource> + <resource name="Upload">Nahrát</resource> + <resource name="upload_failure">Nahrání obrázku do GooglePhotos se nezdařilo:</resource> + <resource name="upload_menu_item">Nahrát do GooglePhotos</resource> + <resource name="upload_success">Úspěšně odeslaný obrázek do GooglePhotos!</resource> + <resource name="UsernameNotSet">Prosím ověřit aplikaci GooglePhotos. Otevřít nastavení obrazovky. ???</resource> + </resources> </language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-de-DE.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml similarity index 74% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-de-DE.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml index 6b30f0214..0a437a443 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-de-DE.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml @@ -8,25 +8,25 @@ Anschliessend </resource> <resource name="Configure"> - Picasa konfigurieren + GooglePhotos konfigurieren </resource> <resource name="upload_menu_item"> - Hochladen zu Picasa + Hochladen zu GooglePhotos </resource> <resource name="settings_title"> - Picasa Einstellungen + GooglePhotos Einstellungen </resource> <resource name="upload_success"> - Hochladen zu Picasa war erfolgreich ! + Hochladen zu GooglePhotos war erfolgreich ! </resource> <resource name="upload_failure"> - Fehler beim Hochladen zu Picasa: + Fehler beim Hochladen zu GooglePhotos: </resource> <resource name="label_upload_format"> Grafikformat </resource> <resource name="communication_wait"> - Übermittle Daten zu Picasa. Bitte warten... + Übermittle Daten zu GooglePhotos. Bitte warten... </resource> </resources> </language> diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-en-US.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml similarity index 73% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-en-US.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml index e99c84ed7..70ec9f14a 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-en-US.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml @@ -8,25 +8,25 @@ After upload </resource> <resource name="Configure"> - Configure Picasa + Configure GooglePhotos </resource> <resource name="upload_menu_item"> - Upload to Picasa + Upload to GooglePhotos </resource> <resource name="settings_title"> - Picasa settings + GooglePhotos settings </resource> <resource name="upload_success"> - Successfully uploaded image to Picasa! + Successfully uploaded image to GooglePhotos! </resource> <resource name="upload_failure"> - An error occured while uploading to Picasa: + An error occured while uploading to GooglePhotos: </resource> <resource name="label_upload_format"> Image format </resource> <resource name="communication_wait"> - Communicating with Picasa. Please wait... + Communicating with GooglePhotos. Please wait... </resource> </resources> </language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-fr-FR.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml similarity index 62% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-fr-FR.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml index 589d55613..553d5725e 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-fr-FR.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml @@ -1,14 +1,14 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Français" ietf="fr-FR" version="1.0.0" languagegroup=""> - <resources> - <resource name="communication_wait">Communication en cours avec Picasa. Veuillez patientez...</resource> - <resource name="Configure">Configurer Picasa</resource> - <resource name="label_AfterUpload">Après téléversement</resource> - <resource name="label_AfterUploadLinkToClipBoard">Copier le lien dans le presse-papier</resource> - <resource name="label_upload_format">Format image</resource> - <resource name="settings_title">Paramètres Picasa</resource> - <resource name="upload_failure">Une erreur s'est produite lors du téléversement vers Picasa :</resource> - <resource name="upload_menu_item">Téléverser vers Picasa</resource> - <resource name="upload_success">Image téléversée avec succès vers Picasa !</resource> - </resources> +<?xml version="1.0" encoding="utf-8"?> +<language description="Français" ietf="fr-FR" version="1.0.0" languagegroup=""> + <resources> + <resource name="communication_wait">Communication en cours avec GooglePhotos. Veuillez patientez...</resource> + <resource name="Configure">Configurer GooglePhotos</resource> + <resource name="label_AfterUpload">Après téléversement</resource> + <resource name="label_AfterUploadLinkToClipBoard">Copier le lien dans le presse-papier</resource> + <resource name="label_upload_format">Format image</resource> + <resource name="settings_title">Paramètres GooglePhotos</resource> + <resource name="upload_failure">Une erreur s'est produite lors du téléversement vers GooglePhotos :</resource> + <resource name="upload_menu_item">Téléverser vers GooglePhotos</resource> + <resource name="upload_success">Image téléversée avec succès vers GooglePhotos !</resource> + </resources> </language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-id-ID.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml similarity index 58% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-id-ID.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml index 5632a3daa..c906bb08e 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-id-ID.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml @@ -1,14 +1,14 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Bahasa Indonesia" ietf="id-ID" version="1.0.0.0" languagegroup=""> - <resources> - <resource name="communication_wait">Menyambungkan ke Picasa. Tunggu sebentar...</resource> - <resource name="Configure">Konfigurasi Picasa</resource> - <resource name="label_AfterUpload">Sesudah mengunggah</resource> - <resource name="label_AfterUploadLinkToClipBoard">Sambung ke papanklip</resource> - <resource name="label_upload_format">Format gambar</resource> - <resource name="settings_title">Pengaturan Picasa</resource> - <resource name="upload_failure">Kesalahan terjadi ketika mengunggah ke Picasa:</resource> - <resource name="upload_menu_item">Unggah ke Picasa</resource> - <resource name="upload_success">Berhasil mengunggah gambar ke Picasa!</resource> - </resources> +<?xml version="1.0" encoding="utf-8"?> +<language description="Bahasa Indonesia" ietf="id-ID" version="1.0.0.0" languagegroup=""> + <resources> + <resource name="communication_wait">Menyambungkan ke GooglePhotos. Tunggu sebentar...</resource> + <resource name="Configure">Konfigurasi GooglePhotos</resource> + <resource name="label_AfterUpload">Sesudah mengunggah</resource> + <resource name="label_AfterUploadLinkToClipBoard">Sambung ke papanklip</resource> + <resource name="label_upload_format">Format gambar</resource> + <resource name="settings_title">Pengaturan GooglePhotos</resource> + <resource name="upload_failure">Kesalahan terjadi ketika mengunggah ke GooglePhotos:</resource> + <resource name="upload_menu_item">Unggah ke GooglePhotos</resource> + <resource name="upload_success">Berhasil mengunggah gambar ke GooglePhotos!</resource> + </resources> </language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-it-IT.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml similarity index 73% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-it-IT.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml index 6f0b76c78..801e57cfd 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-it-IT.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml @@ -1,32 +1,32 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Italiano" ietf="it-IT" version="1.1.5"> - <resources> - <resource name="label_AfterUploadLinkToClipBoard"> - Collegamento agli Appunti - </resource> - <resource name="label_AfterUpload"> - Dopo il caricamento - </resource> - <resource name="Configure"> - Impostazioni Picasa - </resource> - <resource name="upload_menu_item"> - Carica su Picasa - </resource> - <resource name="settings_title"> - Impostazioni Picasa - </resource> - <resource name="upload_success"> - Caricamento immagine su Picasa completato! - </resource> - <resource name="upload_failure"> - Si è verificato un errore durante il caricamento su Picasa: - </resource> - <resource name="label_upload_format"> - Formato immagine - </resource> - <resource name="communication_wait"> - Comunicazione con Picasa... - </resource> - </resources> -</language> +<?xml version="1.0" encoding="utf-8"?> +<language description="Italiano" ietf="it-IT" version="1.1.5"> + <resources> + <resource name="label_AfterUploadLinkToClipBoard"> + Collegamento agli Appunti + </resource> + <resource name="label_AfterUpload"> + Dopo il caricamento + </resource> + <resource name="Configure"> + Impostazioni GooglePhotos + </resource> + <resource name="upload_menu_item"> + Carica su GooglePhotos + </resource> + <resource name="settings_title"> + Impostazioni GooglePhotos + </resource> + <resource name="upload_success"> + Caricamento immagine su GooglePhotos completato! + </resource> + <resource name="upload_failure"> + Si è verificato un errore durante il caricamento su GooglePhotos: + </resource> + <resource name="label_upload_format"> + Formato immagine + </resource> + <resource name="communication_wait"> + Comunicazione con GooglePhotos... + </resource> + </resources> +</language> diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml new file mode 100644 index 000000000..19c1ffc6c --- /dev/null +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<language description="日本語" ietf="ja-JP" version="1.0.0"> + <resources> + <resource name="label_AfterUploadLinkToClipBoard">リンクをクリップボードへコピー</resource> + <resource name="label_AfterUpload">アップロード後</resource> + <resource name="Configure">GooglePhotos の設定</resource> + <resource name="upload_menu_item">GooglePhotos にアップロード</resource> + <resource name="settings_title">GooglePhotos の設定</resource> + <resource name="upload_success">GooglePhotos へのアップロードに成功しました!</resource> + <resource name="upload_failure">GooglePhotos へのアップロード中にエラーが発生しました:</resource> + <resource name="label_upload_format">画像フォーマット</resource> + <resource name="communication_wait">GooglePhotos に接続中です。しばらくお待ち下さい...</resource> + </resources> +</language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-kab-DZ.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml similarity index 59% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-kab-DZ.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml index 367287108..dd5c784d4 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-kab-DZ.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml @@ -1,14 +1,14 @@ <?xml version="1.0" encoding="utf-8"?> <language description="Taqbaylit" ietf="kab-DZ" version="1.0.0" languagegroup=""> <resources> - <resource name="communication_wait">S tidett tebɣiḍ ad tekkseḍ amazray adigan n Picasa ?...</resource> - <resource name="Configure">Swel Picasa</resource> + <resource name="communication_wait">S tidett tebɣiḍ ad tekkseḍ amazray adigan n GooglePhotos ?...</resource> + <resource name="Configure">Swel GooglePhotos</resource> <resource name="label_AfterUpload">Ticki yemmed usali</resource> <resource name="label_AfterUploadLinkToClipBoard">Nɣel aseɣwen ɣef afus</resource> <resource name="label_upload_format">Amsal n tugna</resource> - <resource name="settings_title">Iɣewwaṛen Picasa</resource> - <resource name="upload_failure">Teḍra-d tuccḍa deg usali ɣer Picasa :</resource> - <resource name="upload_menu_item">Sali ɣer Picasa</resource> - <resource name="upload_success">Tugna tuli ɣer Picasa !</resource> + <resource name="settings_title">Iɣewwaṛen GooglePhotos</resource> + <resource name="upload_failure">Teḍra-d tuccḍa deg usali ɣer GooglePhotos :</resource> + <resource name="upload_menu_item">Sali ɣer GooglePhotos</resource> + <resource name="upload_success">Tugna tuli ɣer GooglePhotos !</resource> </resources> </language> diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-ko-KR.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml similarity index 74% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-ko-KR.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml index f452a9618..d095f9f72 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-ko-KR.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml @@ -8,25 +8,25 @@ 얼로드 후 </resource> <resource name="Configure"> - Picasa 설정 + GooglePhotos 설정 </resource> <resource name="upload_menu_item"> - Picasa로 업로드 + GooglePhotos로 업로드 </resource> <resource name="settings_title"> - Picasa 설정 + GooglePhotos 설정 </resource> <resource name="upload_success"> - Picasa로 이미지 업로드 성공! + GooglePhotos로 이미지 업로드 성공! </resource> <resource name="upload_failure"> - Picasa로 업로드시 오류 발생: + GooglePhotos로 업로드시 오류 발생: </resource> <resource name="label_upload_format"> 이미지 형식 </resource> <resource name="communication_wait"> - Picasa와 연결 중 잠시 기다리세요... + GooglePhotos와 연결 중 잠시 기다리세요... </resource> </resources> </language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-lv-LV.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml similarity index 75% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-lv-LV.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml index c33bdc519..7e0e0b8ca 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-lv-LV.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml @@ -9,25 +9,25 @@ Pēc augšupielādes </resource> <resource name="Configure"> - Picasa iestatījumi + GooglePhotos iestatījumi </resource> <resource name="upload_menu_item"> - Augšupieladēt uz Picasa + Augšupieladēt uz GooglePhotos </resource> <resource name="settings_title"> - Picasa iestatījumi + GooglePhotos iestatījumi </resource> <resource name="upload_success"> - Attēls veiksmīgi augšupielādēts uz Picasa! + Attēls veiksmīgi augšupielādēts uz GooglePhotos! </resource> <resource name="upload_failure"> - Kļūda augšuplādējot uz Picasa: + Kļūda augšuplādējot uz GooglePhotos: </resource> <resource name="label_upload_format"> Attēla formāts </resource> <resource name="communication_wait"> - Savienojos ar Picasa. Lūdzu uzgaidiet... + Savienojos ar GooglePhotos. Lūdzu uzgaidiet... </resource> </resources> </language> diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml new file mode 100644 index 000000000..be521cb06 --- /dev/null +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<language description="Polski" ietf="pl-PL" version="1.1.4" languagegroup="2"> + <resources> + <resource name="communication_wait">Trwa komunikacja z GooglePhotos. Proszę czekać...</resource> + <resource name="Configure">Konfiguruj GooglePhotos</resource> + <resource name="label_AfterUpload">Po wysłaniu</resource> + <resource name="label_AfterUploadLinkToClipBoard">Link do schowka</resource> + <resource name="label_upload_format">Format obrazów</resource> + <resource name="settings_title">Ustawienia GooglePhotos</resource> + <resource name="upload_failure">Wystąpił błąd przy wysyłaniu do GooglePhotos:</resource> + <resource name="upload_menu_item">Wyślij do GooglePhotos</resource> + <resource name="upload_success">Wysyłanie obrazu do GooglePhotos powiodło się!</resource> + </resources> +</language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-pt-PT.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml similarity index 73% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-pt-PT.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml index 4649e8005..c3194dad0 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-pt-PT.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml @@ -8,25 +8,25 @@ Após enviar </resource> <resource name="Configure"> - Configurar o Picasa + Configurar o GooglePhotos </resource> <resource name="upload_menu_item"> - enviar para o Picasa + enviar para o GooglePhotos </resource> <resource name="settings_title"> - Definições Picasa + Definições GooglePhotos </resource> <resource name="upload_success"> - Imagem enviada com êxito para o Picasa! + Imagem enviada com êxito para o GooglePhotos! </resource> <resource name="upload_failure"> - Ocorreu um erro ao enviar para o Picasa: + Ocorreu um erro ao enviar para o GooglePhotos: </resource> <resource name="label_upload_format"> Formato da imagem </resource> <resource name="communication_wait"> - A comunicar com o Picasa. Por favor aguarde... + A comunicar com o GooglePhotos. Por favor aguarde... </resource> </resources> </language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-ru-RU.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml similarity index 61% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-ru-RU.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml index 7a273bce7..c7aa0317d 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-ru-RU.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml @@ -1,14 +1,14 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Русский" ietf="ru-RU" version="1.1.0.2515" languagegroup="5"> - <resources> - <resource name="communication_wait">Обмен данными с Picasa. Подождите...</resource> - <resource name="Configure">Настройка Picasa</resource> - <resource name="label_AfterUpload">После загрузки</resource> - <resource name="label_AfterUploadLinkToClipBoard">Ссылки в буфер обмена</resource> - <resource name="label_upload_format">Формат изображения</resource> - <resource name="settings_title">Настройки Picasa</resource> - <resource name="upload_failure">Произошла ошибка при загрузке на Picasa:</resource> - <resource name="upload_menu_item">Загрузить на Picasa</resource> - <resource name="upload_success">Изображение успешно загружено на Picasa!</resource> - </resources> +<?xml version="1.0" encoding="utf-8"?> +<language description="Русский" ietf="ru-RU" version="1.1.0.2515" languagegroup="5"> + <resources> + <resource name="communication_wait">Обмен данными с GooglePhotos. Подождите...</resource> + <resource name="Configure">Настройка GooglePhotos</resource> + <resource name="label_AfterUpload">После загрузки</resource> + <resource name="label_AfterUploadLinkToClipBoard">Ссылки в буфер обмена</resource> + <resource name="label_upload_format">Формат изображения</resource> + <resource name="settings_title">Настройки GooglePhotos</resource> + <resource name="upload_failure">Произошла ошибка при загрузке на GooglePhotos:</resource> + <resource name="upload_menu_item">Загрузить на GooglePhotos</resource> + <resource name="upload_success">Изображение успешно загружено на GooglePhotos!</resource> + </resources> </language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-sr-RS.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml similarity index 98% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-sr-RS.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml index f43494f01..88c045edd 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-sr-RS.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml @@ -1,14 +1,14 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Српски" ietf="sr-RS" version="1.0.5" languagegroup=""> - <resources> - <resource name="communication_wait">Комуницирам с Пикасом. Сачекајте…</resource> - <resource name="Configure">Поставке Пикасе</resource> - <resource name="label_AfterUpload">Након отпремања:</resource> - <resource name="label_AfterUploadLinkToClipBoard">Веза ка остави</resource> - <resource name="label_upload_format">Формат слике:</resource> - <resource name="settings_title">Поставке Пикасе</resource> - <resource name="upload_failure">Дошло је до грешке при отпремању на Пикасу:</resource> - <resource name="upload_menu_item">Отпреми на Пикасу</resource> - <resource name="upload_success">Слика је успешно отпремљена на Пикасу.</resource> - </resources> +<?xml version="1.0" encoding="utf-8"?> +<language description="Српски" ietf="sr-RS" version="1.0.5" languagegroup=""> + <resources> + <resource name="communication_wait">Комуницирам с Пикасом. Сачекајте…</resource> + <resource name="Configure">Поставке Пикасе</resource> + <resource name="label_AfterUpload">Након отпремања:</resource> + <resource name="label_AfterUploadLinkToClipBoard">Веза ка остави</resource> + <resource name="label_upload_format">Формат слике:</resource> + <resource name="settings_title">Поставке Пикасе</resource> + <resource name="upload_failure">Дошло је до грешке при отпремању на Пикасу:</resource> + <resource name="upload_menu_item">Отпреми на Пикасу</resource> + <resource name="upload_success">Слика је успешно отпремљена на Пикасу.</resource> + </resources> </language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-sv-SE.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml similarity index 73% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-sv-SE.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml index d3469d802..86a0aec4c 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-sv-SE.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml @@ -8,25 +8,25 @@ Vid uppladdning </resource> <resource name="Configure"> - Konfigurera Picasa + Konfigurera GooglePhotos </resource> <resource name="upload_menu_item"> - Ladda upp till Picasa + Ladda upp till GooglePhotos </resource> <resource name="settings_title"> - Picasa-inställningar + GooglePhotos-inställningar </resource> <resource name="upload_success"> - Skärmdumpen laddades upp till Picasa! + Skärmdumpen laddades upp till GooglePhotos! </resource> <resource name="upload_failure"> - Ett fel uppstod vid uppladdning till Picasa: + Ett fel uppstod vid uppladdning till GooglePhotos: </resource> <resource name="label_upload_format"> Bildformat </resource> <resource name="communication_wait"> - Kommunicerar med Picasa. Vänta... + Kommunicerar med GooglePhotos. Vänta... </resource> </resources> </language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-uk-UA.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml similarity index 53% rename from GreenshotPicasaPlugin/Languages/language_picasaplugin-uk-UA.xml rename to GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml index c1ecd0a4c..9be4ab5b6 100644 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-uk-UA.xml +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml @@ -1,14 +1,14 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Українська" ietf="uk-UA" version="1.0.0"> - <resources> - <resource name="label_AfterUploadLinkToClipBoard">Посилання в буфер обміну</resource> - <resource name="label_AfterUpload">Після вивантаження</resource> - <resource name="Configure">Налаштувати Picasa</resource> - <resource name="upload_menu_item">Вивантажити на Picasa</resource> - <resource name="settings_title">Параметри Picasa</resource> - <resource name="upload_success">Зображення вдало вивантажено на Picasa!</resource> - <resource name="upload_failure">Відбулась помилка під час вивантаження на Picasa:</resource> - <resource name="label_upload_format">Формат зображення</resource> - <resource name="communication_wait">З’єднання з Picasa. Будь ласка, зачекайте...</resource> - </resources> -</language> +<?xml version="1.0" encoding="utf-8"?> +<language description="Українська" ietf="uk-UA" version="1.0.0"> + <resources> + <resource name="label_AfterUploadLinkToClipBoard">Посилання в буфер обміну</resource> + <resource name="label_AfterUpload">Після вивантаження</resource> + <resource name="Configure">Налаштувати GooglePhotos</resource> + <resource name="upload_menu_item">Вивантажити на GooglePhotos</resource> + <resource name="settings_title">Параметри GooglePhotos</resource> + <resource name="upload_success">Зображення вдало вивантажено на GooglePhotos!</resource> + <resource name="upload_failure">Відбулась помилка під час вивантаження на GooglePhotos:</resource> + <resource name="label_upload_format">Формат зображення</resource> + <resource name="communication_wait">З’єднання з GooglePhotos. Будь ласка, зачекайте...</resource> + </resources> +</language> diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml new file mode 100644 index 000000000..0323ba38d --- /dev/null +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<language description="简体中文" ietf="zh-CN" version="1.0.3" languagegroup="a"> + <resources> + <resource name="communication_wait">正在连接到GooglePhotos。请稍后...</resource> + <resource name="Configure">配置 GooglePhotos</resource> + <resource name="label_AfterUpload">上传之后</resource> + <resource name="label_AfterUploadLinkToClipBoard">复制链接到剪贴板</resource> + <resource name="label_upload_format">图片格式</resource> + <resource name="settings_title">GooglePhotos设置</resource> + <resource name="upload_failure">上传到GooglePhotos时发生错误:</resource> + <resource name="upload_menu_item">上传到GooglePhotos</resource> + <resource name="upload_success">图片已成功上传到了GooglePhotos!</resource> + </resources> +</language> \ No newline at end of file diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml new file mode 100644 index 000000000..34fa14d3f --- /dev/null +++ b/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<language description="正體中文" ietf="zh-TW" version="1.0.0" languagegroup="9"> + <resources> + <resource name="communication_wait">正在與 GooglePhotos 通訊,請稍候...</resource> + <resource name="Configure">組態 GooglePhotos</resource> + <resource name="label_AfterUpload">上傳後</resource> + <resource name="label_AfterUploadLinkToClipBoard">連結到剪貼簿</resource> + <resource name="label_upload_format">圖片格式</resource> + <resource name="settings_title">GooglePhotos 設定</resource> + <resource name="upload_failure">上傳到 GooglePhotos 時發生錯誤:</resource> + <resource name="upload_menu_item">上傳到 GooglePhotos</resource> + <resource name="upload_success">上傳圖片到 GooglePhotos 成功!</resource> + </resources> +</language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Properties/AssemblyInfo.cs b/GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs similarity index 94% rename from GreenshotPicasaPlugin/Properties/AssemblyInfo.cs rename to GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs index 3a917ddcd..d4fa2878a 100644 --- a/GreenshotPicasaPlugin/Properties/AssemblyInfo.cs +++ b/GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs @@ -25,7 +25,7 @@ using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyDescription("A plugin to upload images to Picasa")] +[assembly: AssemblyDescription("A plugin to upload images to GooglePhotos")] // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. diff --git a/GreenshotPicasaPlugin/README b/GreenshotGooglePhotosPlugin/README similarity index 100% rename from GreenshotPicasaPlugin/README rename to GreenshotGooglePhotosPlugin/README diff --git a/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template b/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template index 42dd7986f..4c6948fea 100644 --- a/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template +++ b/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template @@ -25,7 +25,7 @@ namespace GreenshotImgurPlugin { /// You can set your own values here /// </summary> public static class ImgurCredentials { - public static string CONSUMER_KEY = "${Imgur_ClientId}"; - public static string CONSUMER_SECRET = "${Imgur_ClientSecret}"; + public static string CONSUMER_KEY = "${Imgur13_ClientId}"; + public static string CONSUMER_SECRET = "${Imgur13_ClientSecret}"; } } diff --git a/GreenshotImgurPlugin/ImgurUtils.cs b/GreenshotImgurPlugin/ImgurUtils.cs index ecbbf775b..6c4b06674 100644 --- a/GreenshotImgurPlugin/ImgurUtils.cs +++ b/GreenshotImgurPlugin/ImgurUtils.cs @@ -20,11 +20,11 @@ */ using System; using System.Collections.Generic; -using System.Drawing; using System.IO; using System.Linq; using System.Net; using GreenshotPlugin.Core; +using GreenshotPlugin.Core.OAuth; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; @@ -37,10 +37,8 @@ namespace GreenshotImgurPlugin { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurUtils)); private const string SmallUrlPattern = "http://i.imgur.com/{0}s.jpg"; private static readonly ImgurConfiguration Config = IniConfig.GetIniSection<ImgurConfiguration>(); - private const string AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}"; - private const string TokenUrl = "https://api.imgur.com/oauth2/token"; - /// <summary> + /// <summary> /// Check if we need to load the history /// </summary> /// <returns></returns> @@ -162,20 +160,20 @@ namespace GreenshotImgurPlugin { responseString = reader.ReadToEnd(); } } catch (Exception ex) { - Log.Error("Upload to imgur gave an exeption: ", ex); + Log.Error("Upload to imgur gave an exception: ", ex); throw; } } else { var oauth2Settings = new OAuth2Settings { - AuthUrlPattern = AuthUrlPattern, - TokenUrl = TokenUrl, - RedirectUrl = "https://getgreenshot.org/oauth/imgur", + AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}", + TokenUrl = "https://api.imgur.com/oauth2/token", + RedirectUrl = "https://getgreenshot.org/authorize/imgur", CloudServiceName = "Imgur", ClientId = ImgurCredentials.CONSUMER_KEY, ClientSecret = ImgurCredentials.CONSUMER_SECRET, - AuthorizeMode = OAuth2AuthorizeMode.OutOfBoundAuto, + AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, RefreshToken = Config.RefreshToken, AccessToken = Config.AccessToken, AccessTokenExpires = Config.AccessTokenExpires @@ -221,7 +219,7 @@ namespace GreenshotImgurPlugin { Log.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare); HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(string.Format(SmallUrlPattern, imgurInfo.Hash), HTTPMethod.GET); webRequest.ServicePoint.Expect100Continue = false; - // Not for getting the thumbnail, in anonymous modus + // Not for getting the thumbnail, in anonymous mode //SetClientId(webRequest); using WebResponse response = webRequest.GetResponse(); LogRateLimitInfo(response); @@ -304,7 +302,7 @@ namespace GreenshotImgurPlugin { } } } - // Make sure we remove it from the history, if no error occured + // Make sure we remove it from the history, if no error occurred Config.runtimeImgurHistory.Remove(imgurInfo.Hash); Config.ImgurUploadHistory.Remove(imgurInfo.Hash); imgurInfo.Image = null; diff --git a/GreenshotPhotobucketPlugin/PhotobucketUtils.cs b/GreenshotPhotobucketPlugin/PhotobucketUtils.cs index 4226e57c4..bb59ff09a 100644 --- a/GreenshotPhotobucketPlugin/PhotobucketUtils.cs +++ b/GreenshotPhotobucketPlugin/PhotobucketUtils.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.Drawing; using System.Xml; using GreenshotPlugin.Core; +using GreenshotPlugin.Core.OAuth; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-ja-JP.xml b/GreenshotPicasaPlugin/Languages/language_picasaplugin-ja-JP.xml deleted file mode 100644 index ac8216e96..000000000 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-ja-JP.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="日本語" ietf="ja-JP" version="1.0.0"> - <resources> - <resource name="label_AfterUploadLinkToClipBoard">リンクをクリップボードへコピー</resource> - <resource name="label_AfterUpload">アップロード後</resource> - <resource name="Configure">Picasa の設定</resource> - <resource name="upload_menu_item">Picasa にアップロード</resource> - <resource name="settings_title">Picasa の設定</resource> - <resource name="upload_success">Picasa へのアップロードに成功しました!</resource> - <resource name="upload_failure">Picasa へのアップロード中にエラーが発生しました:</resource> - <resource name="label_upload_format">画像フォーマット</resource> - <resource name="communication_wait">Picasa に接続中です。しばらくお待ち下さい...</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-pl-PL.xml b/GreenshotPicasaPlugin/Languages/language_picasaplugin-pl-PL.xml deleted file mode 100644 index c4be12b84..000000000 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-pl-PL.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="Polski" ietf="pl-PL" version="1.1.4" languagegroup="2"> - <resources> - <resource name="communication_wait">Trwa komunikacja z Picasa. Proszę czekać...</resource> - <resource name="Configure">Konfiguruj Picasa</resource> - <resource name="label_AfterUpload">Po wysłaniu</resource> - <resource name="label_AfterUploadLinkToClipBoard">Link do schowka</resource> - <resource name="label_upload_format">Format obrazów</resource> - <resource name="settings_title">Ustawienia Picasa</resource> - <resource name="upload_failure">Wystąpił błąd przy wysyłaniu do Picasa:</resource> - <resource name="upload_menu_item">Wyślij do Picasa</resource> - <resource name="upload_success">Wysyłanie obrazu do Picasa powiodło się!</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-zh-CN.xml b/GreenshotPicasaPlugin/Languages/language_picasaplugin-zh-CN.xml deleted file mode 100644 index 38601fc93..000000000 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-zh-CN.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="简体中文" ietf="zh-CN" version="1.0.3" languagegroup="a"> - <resources> - <resource name="communication_wait">正在连接到Picasa。请稍后...</resource> - <resource name="Configure">配置 Picasa</resource> - <resource name="label_AfterUpload">上传之后</resource> - <resource name="label_AfterUploadLinkToClipBoard">复制链接到剪贴板</resource> - <resource name="label_upload_format">图片格式</resource> - <resource name="settings_title">Picasa设置</resource> - <resource name="upload_failure">上传到Picasa时发生错误:</resource> - <resource name="upload_menu_item">上传到Picasa</resource> - <resource name="upload_success">图片已成功上传到了Picasa!</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Languages/language_picasaplugin-zh-TW.xml b/GreenshotPicasaPlugin/Languages/language_picasaplugin-zh-TW.xml deleted file mode 100644 index a818bc748..000000000 --- a/GreenshotPicasaPlugin/Languages/language_picasaplugin-zh-TW.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<language description="正體中文" ietf="zh-TW" version="1.0.0" languagegroup="9"> - <resources> - <resource name="communication_wait">正在與 Picasa 通訊,請稍候...</resource> - <resource name="Configure">組態 Picasa</resource> - <resource name="label_AfterUpload">上傳後</resource> - <resource name="label_AfterUploadLinkToClipBoard">連結到剪貼簿</resource> - <resource name="label_upload_format">圖片格式</resource> - <resource name="settings_title">Picasa 設定</resource> - <resource name="upload_failure">上傳到 Picasa 時發生錯誤:</resource> - <resource name="upload_menu_item">上傳到 Picasa</resource> - <resource name="upload_success">上傳圖片到 Picasa 成功!</resource> - </resources> -</language> \ No newline at end of file diff --git a/GreenshotPicasaPlugin/Picasa.png b/GreenshotPicasaPlugin/Picasa.png deleted file mode 100644 index 97b70cf86c92763dda7b6b2f4eba92058c4d60e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4954 zcmV-g6Q%5lP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800009a7bBm000XU z000XU0RWnu7ytkYPiaF#P*7-ZbZ>KLZ*U+<Lqi~Na&Km7Y-Iodc-oy)XH-+^7Crag z^g>IBfRsybQWXdwQbLP>6p<z>Aqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uh<iVD~V z<RPMtgQJLw%KPDaqifc@_vX$1wbwr9tn;0-&j-K=43<bUQ8j=JsX`tR;Dg7+#^K~H zK!FM*Z~zbpvt%K2{UZSY_<lS*D<Z%Lz5oGu(+dayz)hRLFdT>f59&ghTmgWD0l;*T zI7<kC6aYYajzXpYKt=(8otP$50H6c_V9R4-;{Z@C0AMG7=F<Rxo%or10RUT+Ar%3j zkpLhQWr#!oXgdI`&sK^>09Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-<?i z0%4j!F2Z@488U%158(66005wo6%pWr^Zj_v4zAA5HjcIqUoGmt2LB>rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_<lS*MWK+n+1cgf z<k(8YLR(?VSAG6x!e78w{cQPuJpA|d;J)G{fihizM+Erb!p!tcr5w+a34~(Y=8s4G zw+sLL9n&JjNn*KJDiq^U5^;`1nvC-@r6P$!k}1U{(*I=Q-z@tBKHoI}uxdU5dyy@u zU1J0GOD7Ombim^G008p4Z^6_k2m^p<gW=D2|L;HjN1!DDfM!XOaR2~bL?kX$%CkSm z2mk;?pn)o|K^yeJ7%adB9Ki+L!3+FgHiSYX#KJ-lLJDMn9CBbOtb#%)hRv`YDqt_v zKpix|QD}yfa1JiQRk#j4a1Z)n2%f<xynzV>LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_Ifq<Ex{*7`05XF7hP+2Hl!3BQJ=6@fL%FCo z8iYoo3(#bAF`ADSpqtQgv>H8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ<AYmRsNLWl*PS{AOARHt#5!wki2?K;t z!Y3k=s7tgax)J%r7-BLphge7~Bi0g+6E6^Zh(p9TBoc{3GAFr^0!gu?RMHaCM$&Fl zBk3%un>0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 z<uv66WtcKSRim0x-Ke2d5jBrmLam{;Qm;{ms1r1GnmNsb7D-E`t)i9F8fX`2_i3-_ zbh;7Ul^#x)&{xvS=|||7=mYe33=M`AgU5(xC>fg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vF<Q0r40Q)j6=sE4X&sBct1q<&fbi3VB2Ov6t@q*0);U*o*SAPZv|vv@2aYYnT0 zb%8a+Cb7-ge0D0knEf5Qi#@8Tp*ce{N;6lpQuCB%KL_KOarm5cP6_8Ir<e17iry6O zDdH&`rZh~sF=bq9s+O0QSgS~@QL9Jmy*94xr=6y~MY~!1fet~(N+(<=M`w@D1)b+p z*;C!83a1uLJv#NSE~;y#8=<>IcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a<fJbF^|4I#xQ~n$Dc= zKYhjYmgz5NSkDm8*fZm{6U!;YX`NG>(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-k<Mujg;0Lz*3buG=3$G&ehepthlN*$KaOySSQ^nWmo<0M+(UEUMEXRQ zMBbZcF;6+KElM>iKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BK<z=<L*0kfKU@CX*zeqbYQT4(^U>T#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot<a{81DF0~rvGr5Xr~8u`lav1h z1DNytV>2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000PqNkl<Zc-pL&dvI079mhX=?oDoz8w{9`1TcXR!mA)kG%%>GIux}n<)MtIRP0nO zqM&Up<BWe+$Fbwok-m`9s%1oCTPcpURoVe<3JNL`h#}z-NCHVnLUMB-x#yhS{q>J~ zNkfPVPIu-zXU{o1`~Ci2`%qk33lxtXTV7F7F=c#NS!r%=?kE(*qOqQnO-;>5jvQ%d zKYjWbVEBKw!otF`)vH%OvE!Y0cAxF+jEd)p#Nr~|-6_OkBCac4Jw4GK@4dHs^_n$L z6c!bgUCi9-i++Z~;n9!%=&{GwJo?BFiVBMJ0eUuWVpPq05Q{^<3)Vtr2IS|%v}rJJ z9#maRTW?SIuh#$a_b<Hg!gKL>yz`Q+o-?Ov!GYRO4~vMj)^tnPv0f1o>D;$Zn!bLc zm?=|4uAVJ2YqrSOW{OOmE;4Dd$n+Uvzw=!&|JfrVBA@L4^l(+xoNs<^Oo#h;$Fe&f z-1gTuUMWyxi$8tk2u-^>=s0ke+;JfaXH9~eZ=&s^1B~cw$H@*uKtV7g<q4&bqsNHk z7m)pp8yHiNU9kL~`<5L!daU!a&+0z@QUObEU;1Em_0|{r8ob~qn;VI?B?)E)u)d;g ze-EL807cWr5xn^(PS@5FKG8xjD}*ReC{Q5A;#F0Vb^SbgcRod)J`r5<(6bBc>gw9+ z>pweBgfsZ1va)jiOE15)zN<FIf$HP<2}3YDfN~rHnGT8o2REPOL`@qb3P&^M*T13l z#vAC5Mo=n{$|$8kDU_2+FG-xi`}-O)8vn>2UV3@`?8<BA4=W%X4v*fjal;1N9t_oO zZ$h+9ktzj9YH(1I?PT-G%SUM3(?rf?BN+GmFF3Vu39)D&r~u+P;5Y;Mt%6x7t?_oO zCGYI6&~IPdv>_)P9({p;RS&OPH?wS3dEHyb(ft-DBTcSIS>u4?IK=v+<joE;c6uQI zS)mZ)pLvRo6?YSfMN!HDM<GhmWu{O;AQ_>5$B(Hh&no}n>b2|66Odn!Uv~d}_djrC zXDji}B!N(x+(~=XQ3MDOi}o?{x**?JRYh)Ic)*Prj>Ci}pXBVrtLaX}aYRx=I2RHi zBLnGfBvJD;4}O2e1NjA`%LW82TC(V_JT*G6y}lb2R49k@$Q>M_i3nrn=W_juYX~~Q zVasX!BM%c@w~h|i!_j)+p8$e`1RT7EHz;wA=Pg{k?5=YHg10WXWl_hWZj5VDft2cV z<O)S!vX|0tUryDMt5E0XEkhG(!oA-k`Sj1|%*;G*trHxC48)D&)@|X|TjnnUl@Tl~ zDx6q0wtPnS?no+DDm7dwg`*uJ-dQFsEoS<>$rrtdjlbt^;*mZCuu35cL^-KvAV{)l z7nA3%oH4p+Oqnxb;)H2Iotcx2c_|ZA3f4fM>0$bvrI$oLP*r)Cr7SlZt3kAjH9pn| zex#jj?{v<DiIb)Vi;Ig&{e(fpB1%w7u%6KG^l;^ha>h?BK_s2gN?jEBx$&YDVl<+` zDvdFq4Oky+w1uMLv8BPx%*;Hm-y5)8dj>Zv%GJv%C@H@JYfL&P6e9AaBF>RpD@Z^g z0!F~t6m+`p$9u>Og+@ABYdq~k0JP`hj)-#g@(N1Ii)rub#q~8Jash@TJ_l<pA{HxP ztfYwT|3nx8*VAZU<3yv;h(V)0A2TY>tfdu<8#jvg>$-X7?G}tSSZgrGV69D0E(86~ z`(}(m8_-tJ7JQR}HsBdZN;a`rUvIFzt)n^aN1-^t%-g0?kRRqB`_J(F`w8;1EJnL% z2bAOBIL<%_hK6Dw?r9;$7>v!tH$uRGuTsRm1=m81Jlfk%HwRmqTkB&sl9+o-RnBF( znQZ^)3|scQwDt&RO$661LOBjfr34HoVkr550LR1EmVhPgjZ}5HfgH{xvlFLUP9App zB9Y?_jSYvaz@PVZQN2G#Yj={vCwfS@9@_WuJP*(F@O^&(TI*r^etNv``*^-jJdvO` z0)5dmdZ90?oW@gqhax>)O+i5Ksd;~U>5S{D-fg*zmQI)26MY~VIM(2K9w;ZZB?kf* zcwuk|&a>VaEIx_i`9!8(j#Yv-7VR5kR0VrpeRn(H2LV3VyYIEz7S^xp>z<gm|ELe? zz1$j2(oGUjL9&851SEjt1aQ)2IXDC&f)&A9gE9)G720U7m~tCqCVvZGYqZhC+$ekZ z?vCvJpyoAzAV4ghXxg>o?M)M|z2hhJXF@m^jE`u8(uzH&KIAW5+i)@isjWG^R}36! z1w;T5#HL_VHHa9&8o`RiPx#y#TEO47z4g09qQ7ZC0Khx{+V$*DXI-_pa_ofik2^9T zn1L7{tA)d78+g5SD`XGaUxuznG6;4E1n^<1JC&2&laKA(we#l}97sIR@7(<AmWLLO zkGLgS-Qa3OEWYQVv>JZmFM<pbYoR1j!g5*ezP|PKRj%)L4tpkSZaKAMTlMC(D`&)I zOy~^#Nf%#hj4_}=X+Wo}85VjFOj?KsC6N+VIxE@s>bAAbr<(scnDc^@#eqZh8$~vA z*TUP^HziES^$lWeYBDp#vY{au`W}NyUC9EyAo=FjHy^F7uibc2_kxbju8*6KHSV1= zrLd|Xzo?)!(MnCvzae7~xeS3C6#srG>MLR~i>WwW(NMjm`re}_j{fPAuV#UOQ*ce? zwU5uee(wEk;kNvP9HiN4CY}*bNk11rn{s<thbgtC%w#4-eMQ{|_Z{3+^I^?%+UTyY zbT>TLva_-$UODZ`J10+>yfCLQXJ#@dnHzIrxQ+`z$cD%@xn%Wc#S&){2OAq2->j{# zt?o~zO6@COPKR?!Zcc7_!Ki{MBlAX<hB8AV0bI}R?Tz#{clC5N#1gSfx}N`c0AE(w Y95$I(#sB~S07*qoM6N<$f;2fbFm?D+;s5{u diff --git a/GreenshotPlugin/Controls/OAuthLoginForm.cs b/GreenshotPlugin/Controls/OAuthLoginForm.cs index e2b036f97..998b938bb 100644 --- a/GreenshotPlugin/Controls/OAuthLoginForm.cs +++ b/GreenshotPlugin/Controls/OAuthLoginForm.cs @@ -1,20 +1,20 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -32,9 +32,8 @@ namespace GreenshotPlugin.Controls { public sealed partial class OAuthLoginForm : Form { private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthLoginForm)); private readonly string _callbackUrl; - private IDictionary<string, string> _callbackParameters; - - public IDictionary<string, string> CallbackParameters => _callbackParameters; + + public IDictionary<string, string> CallbackParameters { get; private set; } public bool IsOk => DialogResult == DialogResult.OK; @@ -94,7 +93,7 @@ namespace GreenshotPlugin.Controls { if (queryParams.Length > 0) { queryParams = NetworkHelper.UrlDecode(queryParams); //Store the Token and Token Secret - _callbackParameters = NetworkHelper.ParseQueryString(queryParams); + CallbackParameters = NetworkHelper.ParseQueryString(queryParams); } DialogResult = DialogResult.OK; } @@ -102,7 +101,7 @@ namespace GreenshotPlugin.Controls { private void AddressTextBox_KeyPress(object sender, KeyPressEventArgs e) { //Cancel the key press so the user can't enter a new url - e.Handled = true; + e.Handled = true; } } } diff --git a/GreenshotPlugin/Core/EnvironmentInfo.cs b/GreenshotPlugin/Core/EnvironmentInfo.cs new file mode 100644 index 000000000..01eb11772 --- /dev/null +++ b/GreenshotPlugin/Core/EnvironmentInfo.cs @@ -0,0 +1,793 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using GreenshotPlugin.IniFile; +using GreenshotPlugin.UnmanagedHelpers; +using Microsoft.Win32; + +namespace GreenshotPlugin.Core +{ + /// <summary> + /// Description of EnvironmentInfo. + /// </summary> + public static class EnvironmentInfo + { + private static bool? _isWindows; + + public static bool IsWindows + { + get + { + if (_isWindows.HasValue) + { + return _isWindows.Value; + } + _isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win"); + return _isWindows.Value; + } + } + + public static bool IsNet45OrNewer() + { + // Class "ReflectionContext" exists from .NET 4.5 onwards. + return Type.GetType("System.Reflection.ReflectionContext", false) != null; + } + + public static string GetGreenshotVersion(bool shortVersion = false) + { + var executingAssembly = Assembly.GetExecutingAssembly(); + + // Use assembly version + string greenshotVersion = executingAssembly.GetName().Version.ToString(); + + // Use AssemblyFileVersion if available + var assemblyFileVersionAttribute = executingAssembly.GetCustomAttribute<AssemblyFileVersionAttribute>(); + if (!string.IsNullOrEmpty(assemblyFileVersionAttribute?.Version)) + { + var assemblyFileVersion = new Version(assemblyFileVersionAttribute.Version); + greenshotVersion = assemblyFileVersion.ToString(3); + } + + if (!shortVersion) + { + // Use AssemblyInformationalVersion if available + var informationalVersionAttribute = executingAssembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>(); + if (!string.IsNullOrEmpty(informationalVersionAttribute?.InformationalVersion)) + { + greenshotVersion = informationalVersionAttribute.InformationalVersion; + } + } + + return greenshotVersion.Replace("+", " - "); + } + + public static string EnvironmentToString(bool newline) + { + StringBuilder environment = new StringBuilder(); + environment.Append("Software version: " + GetGreenshotVersion()); + if (IniConfig.IsPortable) { + environment.Append(" Portable"); + } + environment.Append(" (" + OsInfo.Bits + " bit)"); + + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + environment.Append(".NET runtime version: " + Environment.Version); + if (IsNet45OrNewer()) + { + environment.Append("+"); + + } + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + environment.Append("Time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz")); + + if (IsWindows) + { + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + + environment.Append($"OS: {OsInfo.Name}"); + if (!string.IsNullOrEmpty(OsInfo.Edition)) + { + environment.Append($" {OsInfo.Edition}"); + + } + if (!string.IsNullOrEmpty(OsInfo.ServicePack)) + { + environment.Append($" {OsInfo.ServicePack}"); + + } + environment.Append($" x{OsInfo.Bits}"); + environment.Append($" {OsInfo.VersionString}"); + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + // Get some important information for fixing GDI related Problems + environment.AppendFormat("GDI object count: {0}", User32.GetGuiResourcesGDICount()); + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + environment.AppendFormat("User object count: {0}", User32.GetGuiResourcesUserCount()); + } + else + { + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + environment.AppendFormat("OS: {0}", Environment.OSVersion.Platform); + } + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + // TODO: Is this needed? + // environment.AppendFormat("Surface count: {0}", Surface.Count); + + return environment.ToString(); + } + + public static string ExceptionToString(Exception ex) + { + if (ex == null) + return "null\r\n"; + + StringBuilder report = new StringBuilder(); + + report.AppendLine("Exception: " + ex.GetType()); + report.AppendLine("Message: " + ex.Message); + if (ex.Data.Count > 0) + { + report.AppendLine(); + report.AppendLine("Additional Information:"); + foreach (object key in ex.Data.Keys) + { + object data = ex.Data[key]; + if (data != null) + { + report.AppendLine(key + " : " + data); + } + } + } + if (ex is ExternalException externalException) + { + // e.g. COMException + report.AppendLine().AppendLine("ErrorCode: 0x" + externalException.ErrorCode.ToString("X")); + } + + report.AppendLine().AppendLine("Stack:").AppendLine(ex.StackTrace); + + if (ex is ReflectionTypeLoadException reflectionTypeLoadException) + { + report.AppendLine().AppendLine("LoaderExceptions: "); + foreach (Exception cbE in reflectionTypeLoadException.LoaderExceptions) + { + report.AppendLine(cbE.Message); + } + } + + if (ex.InnerException != null) + { + report.AppendLine("--- InnerException: ---"); + report.AppendLine(ExceptionToString(ex.InnerException)); + } + return report.ToString(); + } + + public static string BuildReport(Exception exception) + { + StringBuilder exceptionText = new StringBuilder(); + exceptionText.AppendLine(EnvironmentToString(true)); + exceptionText.AppendLine(ExceptionToString(exception)); + exceptionText.AppendLine("Configuration dump:"); + + return exceptionText.ToString(); + } + } + + /// <summary> + /// Provides detailed information about the host operating system. + /// Code is available at: http://www.csharp411.com/determine-windows-version-and-edition-with-c/ + /// </summary> + public static class OsInfo + { + /// <summary> + /// Determines if the current application is 32 or 64-bit. + /// </summary> + public static int Bits => IntPtr.Size * 8; + + private static string _sEdition; + + /// <summary> + /// Gets the edition of the operating system running on this computer. + /// </summary> + public static string Edition + { + get + { + if (_sEdition != null) + { + return _sEdition; //***** RETURN *****// + } + + string edition = string.Empty; + + OperatingSystem osVersion = Environment.OSVersion; + OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create(); + + if (GetVersionEx(ref osVersionInfo)) + { + int majorVersion = osVersion.Version.Major; + int minorVersion = osVersion.Version.Minor; + byte productType = osVersionInfo.ProductType; + ushort suiteMask = osVersionInfo.SuiteMask; + + if (majorVersion == 4) + { + if (productType == VER_NT_WORKSTATION) + { + // Windows NT 4.0 Workstation + edition = "Workstation"; + } + else if (productType == VER_NT_SERVER) + { + edition = (suiteMask & VER_SUITE_ENTERPRISE) != 0 ? "Enterprise Server" : "Standard Server"; + } + } + + else if (majorVersion == 5) + { + if (productType == VER_NT_WORKSTATION) + { + if ((suiteMask & VER_SUITE_PERSONAL) != 0) + { + // Windows XP Home Edition + edition = "Home"; + } + else + { + // Windows XP / Windows 2000 Professional + edition = "Professional"; + } + } + else if (productType == VER_NT_SERVER) + { + if (minorVersion == 0) + { + if ((suiteMask & VER_SUITE_DATACENTER) != 0) + { + // Windows 2000 Datacenter Server + edition = "Datacenter Server"; + } + else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0) + { + // Windows 2000 Advanced Server + edition = "Advanced Server"; + } + else + { + // Windows 2000 Server + edition = "Server"; + } + } + else + { + if ((suiteMask & VER_SUITE_DATACENTER) != 0) + { + // Windows Server 2003 Datacenter Edition + edition = "Datacenter"; + } + else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0) + { + // Windows Server 2003 Enterprise Edition + edition = "Enterprise"; + } + else if ((suiteMask & VER_SUITE_BLADE) != 0) + { + // Windows Server 2003 Web Edition + edition = "Web Edition"; + } + else + { + // Windows Server 2003 Standard Edition + edition = "Standard"; + } + } + } + } + + else if (majorVersion == 6) + { + if (GetProductInfo(majorVersion, minorVersion, osVersionInfo.ServicePackMajor, osVersionInfo.ServicePackMinor, out var ed)) + { + switch (ed) + { + case PRODUCT_BUSINESS: + edition = "Business"; + break; + case PRODUCT_BUSINESS_N: + edition = "Business N"; + break; + case PRODUCT_CLUSTER_SERVER: + edition = "HPC Edition"; + break; + case PRODUCT_DATACENTER_SERVER: + edition = "Datacenter Server"; + break; + case PRODUCT_DATACENTER_SERVER_CORE: + edition = "Datacenter Server (core installation)"; + break; + case PRODUCT_ENTERPRISE: + edition = "Enterprise"; + break; + case PRODUCT_ENTERPRISE_N: + edition = "Enterprise N"; + break; + case PRODUCT_ENTERPRISE_SERVER: + edition = "Enterprise Server"; + break; + case PRODUCT_ENTERPRISE_SERVER_CORE: + edition = "Enterprise Server (core installation)"; + break; + case PRODUCT_ENTERPRISE_SERVER_CORE_V: + edition = "Enterprise Server without Hyper-V (core installation)"; + break; + case PRODUCT_ENTERPRISE_SERVER_IA64: + edition = "Enterprise Server for Itanium-based Systems"; + break; + case PRODUCT_ENTERPRISE_SERVER_V: + edition = "Enterprise Server without Hyper-V"; + break; + case PRODUCT_HOME_BASIC: + edition = "Home Basic"; + break; + case PRODUCT_HOME_BASIC_N: + edition = "Home Basic N"; + break; + case PRODUCT_HOME_PREMIUM: + edition = "Home Premium"; + break; + case PRODUCT_HOME_PREMIUM_N: + edition = "Home Premium N"; + break; + case PRODUCT_HYPERV: + edition = "Microsoft Hyper-V Server"; + break; + case PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT: + edition = "Windows Essential Business Management Server"; + break; + case PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING: + edition = "Windows Essential Business Messaging Server"; + break; + case PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY: + edition = "Windows Essential Business Security Server"; + break; + case PRODUCT_SERVER_FOR_SMALLBUSINESS: + edition = "Windows Essential Server Solutions"; + break; + case PRODUCT_SERVER_FOR_SMALLBUSINESS_V: + edition = "Windows Essential Server Solutions without Hyper-V"; + break; + case PRODUCT_SMALLBUSINESS_SERVER: + edition = "Windows Small Business Server"; + break; + case PRODUCT_STANDARD_SERVER: + edition = "Standard Server"; + break; + case PRODUCT_STANDARD_SERVER_CORE: + edition = "Standard Server (core installation)"; + break; + case PRODUCT_STANDARD_SERVER_CORE_V: + edition = "Standard Server without Hyper-V (core installation)"; + break; + case PRODUCT_STANDARD_SERVER_V: + edition = "Standard Server without Hyper-V"; + break; + case PRODUCT_STARTER: + edition = "Starter"; + break; + case PRODUCT_STORAGE_ENTERPRISE_SERVER: + edition = "Enterprise Storage Server"; + break; + case PRODUCT_STORAGE_EXPRESS_SERVER: + edition = "Express Storage Server"; + break; + case PRODUCT_STORAGE_STANDARD_SERVER: + edition = "Standard Storage Server"; + break; + case PRODUCT_STORAGE_WORKGROUP_SERVER: + edition = "Workgroup Storage Server"; + break; + case PRODUCT_UNDEFINED: + edition = "Unknown product"; + break; + case PRODUCT_ULTIMATE: + edition = "Ultimate"; + break; + case PRODUCT_ULTIMATE_N: + edition = "Ultimate N"; + break; + case PRODUCT_WEB_SERVER: + edition = "Web Server"; + break; + case PRODUCT_WEB_SERVER_CORE: + edition = "Web Server (core installation)"; + break; + } + } + } + } + + _sEdition = edition; + return edition; + } + } + + private static string _name; + + /// <summary> + /// Gets the name of the operating system running on this computer. + /// </summary> + public static string Name + { + get + { + if (_name != null) + { + return _name; //***** RETURN *****// + } + + string name = "unknown"; + + OperatingSystem osVersion = Environment.OSVersion; + OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create(); + if (GetVersionEx(ref osVersionInfo)) + { + int majorVersion = osVersion.Version.Major; + int minorVersion = osVersion.Version.Minor; + byte productType = osVersionInfo.ProductType; + ushort suiteMask = osVersionInfo.SuiteMask; + switch (osVersion.Platform) + { + case PlatformID.Win32Windows: + if (majorVersion == 4) + { + string csdVersion = osVersionInfo.ServicePackVersion; + switch (minorVersion) + { + case 0: + if (csdVersion == "B" || csdVersion == "C") + { + name = "Windows 95 OSR2"; + } + else + { + name = "Windows 95"; + } + + break; + case 10: + name = csdVersion == "A" ? "Windows 98 Second Edition" : "Windows 98"; + break; + case 90: + name = "Windows Me"; + break; + } + } + + break; + case PlatformID.Win32NT: + switch (majorVersion) + { + case 3: + name = "Windows NT 3.51"; + break; + case 4: + switch (productType) + { + case 1: + name = "Windows NT 4.0"; + break; + case 3: + name = "Windows NT 4.0 Server"; + break; + } + + break; + case 5: + switch (minorVersion) + { + case 0: + name = "Windows 2000"; + break; + case 1: + name = suiteMask switch + { + 0x0200 => "Windows XP Professional", + _ => "Windows XP" + }; + break; + case 2: + name = suiteMask switch + { + 0x0200 => "Windows XP Professional x64", + 0x0002 => "Windows Server 2003 Enterprise", + 0x0080 => "Windows Server 2003 Data Center", + 0x0400 => "Windows Server 2003 Web Edition", + 0x8000 => "Windows Home Server", + _ => "Windows Server 2003" + }; + break; + } + + break; + case 6: + switch (minorVersion) + { + case 0: + name = productType switch + { + 3 => "Windows Server 2008", + _ => "Windows Vista" + }; + break; + case 1: + name = productType switch + { + 3 => "Windows Server 2008 R2", + _ => "Windows 7" + }; + break; + case 2: + name = "Windows 8"; + break; + case 3: + name = "Windows 8.1"; + break; + } + + break; + case 10: + string releaseId = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", "").ToString(); + name = $"Windows 10 {releaseId}"; + break; + } + + break; + } + } + + _name = name; + return name; + } + } + + [DllImport("Kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool GetProductInfo( + int osMajorVersion, + int osMinorVersion, + int spMajorVersion, + int spMinorVersion, + out int edition); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetVersionEx(ref OSVERSIONINFOEX osVersionInfo); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private unsafe struct OSVERSIONINFOEX + { + /// <summary> + /// The size of this data structure, in bytes. Set this member to sizeof(OSVERSIONINFOEX). + /// </summary> + private int _dwOSVersionInfoSize; + + private readonly int _dwMajorVersion; + private readonly int _dwMinorVersion; + private readonly int _dwBuildNumber; + private readonly int _dwPlatformId; + private fixed char _szCSDVersion[128]; + private readonly short _wServicePackMajor; + private readonly short _wServicePackMinor; + private readonly ushort _wSuiteMask; + private readonly byte _wProductType; + private readonly byte _wReserved; + + /// A null-terminated string, such as "Service Pack 3", that indicates the latest Service Pack installed on the system. + /// If no Service Pack has been installed, the string is empty. + /// </summary> + public string ServicePackVersion + { + get + { + fixed (char* servicePackVersion = _szCSDVersion) + { + return new string(servicePackVersion); + } + + } + } + + /// <summary> + /// The major version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the + /// major version number is 3. + /// If no Service Pack has been installed, the value is zero. + /// </summary> + public short ServicePackMajor => _wServicePackMajor; + + /// <summary> + /// The minor version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the + /// minor version number is 0. + /// </summary> + public short ServicePackMinor => _wServicePackMinor; + + /// <summary> + /// A bit mask that identifies the product suites available on the system. This member can be a combination of the + /// following values. + /// </summary> + public ushort SuiteMask => _wSuiteMask; + + /// <summary> + /// Any additional information about the system. + /// </summary> + public byte ProductType => _wProductType; + + /// <summary> + /// Factory for an empty OsVersionInfoEx + /// </summary> + /// <returns>OSVERSIONINFOEX</returns> + public static OSVERSIONINFOEX Create() + { + return new OSVERSIONINFOEX + { + _dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX)) + }; + } + } + + private const int PRODUCT_UNDEFINED = 0x00000000; + private const int PRODUCT_ULTIMATE = 0x00000001; + private const int PRODUCT_HOME_BASIC = 0x00000002; + private const int PRODUCT_HOME_PREMIUM = 0x00000003; + private const int PRODUCT_ENTERPRISE = 0x00000004; + private const int PRODUCT_HOME_BASIC_N = 0x00000005; + private const int PRODUCT_BUSINESS = 0x00000006; + private const int PRODUCT_STANDARD_SERVER = 0x00000007; + private const int PRODUCT_DATACENTER_SERVER = 0x00000008; + private const int PRODUCT_SMALLBUSINESS_SERVER = 0x00000009; + private const int PRODUCT_ENTERPRISE_SERVER = 0x0000000A; + private const int PRODUCT_STARTER = 0x0000000B; + private const int PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C; + private const int PRODUCT_STANDARD_SERVER_CORE = 0x0000000D; + private const int PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E; + private const int PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F; + private const int PRODUCT_BUSINESS_N = 0x00000010; + private const int PRODUCT_WEB_SERVER = 0x00000011; + private const int PRODUCT_CLUSTER_SERVER = 0x00000012; + private const int PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014; + private const int PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015; + private const int PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016; + private const int PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017; + private const int PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018; + private const int PRODUCT_HOME_PREMIUM_N = 0x0000001A; + private const int PRODUCT_ENTERPRISE_N = 0x0000001B; + private const int PRODUCT_ULTIMATE_N = 0x0000001C; + private const int PRODUCT_WEB_SERVER_CORE = 0x0000001D; + private const int PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E; + private const int PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F; + private const int PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020; + private const int PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023; + private const int PRODUCT_STANDARD_SERVER_V = 0x00000024; + private const int PRODUCT_ENTERPRISE_SERVER_V = 0x00000026; + private const int PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028; + private const int PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029; + private const int PRODUCT_HYPERV = 0x0000002A; + + private const int VER_NT_WORKSTATION = 1; + private const int VER_NT_SERVER = 3; + private const int VER_SUITE_ENTERPRISE = 2; + private const int VER_SUITE_DATACENTER = 128; + private const int VER_SUITE_PERSONAL = 512; + private const int VER_SUITE_BLADE = 1024; + + /// <summary> + /// Gets the service pack information of the operating system running on this computer. + /// </summary> + public static string ServicePack + { + get + { + string servicePack = string.Empty; + OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create(); + + if (GetVersionEx(ref osVersionInfo)) + { + servicePack = osVersionInfo.ServicePackVersion; + } + + return servicePack; + } + } + + /// Gets the full version string of the operating system running on this computer. + /// </summary> + public static string VersionString + { + get + { + if (WindowsVersion.IsWindows10OrLater) + { + return $"build {Environment.OSVersion.Version.Build}"; + } + + if (Environment.OSVersion.Version.Revision != 0) + { + return + $"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor} build {Environment.OSVersion.Version.Build} revision {Environment.OSVersion.Version.Revision:X}"; + } + + return $"{Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor} build {Environment.OSVersion.Version.Build}"; + } + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/NetworkHelper.cs b/GreenshotPlugin/Core/NetworkHelper.cs index 9b7186d16..3159c9dcc 100644 --- a/GreenshotPlugin/Core/NetworkHelper.cs +++ b/GreenshotPlugin/Core/NetworkHelper.cs @@ -32,77 +32,83 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotPlugin.Core { - /// <summary> - /// HTTP Method to make sure we have the correct method - /// </summary> - public enum HTTPMethod { - GET, - POST, - PUT, - DELETE +namespace GreenshotPlugin.Core +{ + /// <summary> + /// HTTP Method to make sure we have the correct method + /// </summary> + public enum HTTPMethod + { + GET, + POST, + PUT, + DELETE }; - /// <summary> - /// Description of NetworkHelper. - /// </summary> - public static class NetworkHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(NetworkHelper)); - private static readonly CoreConfiguration Config = IniConfig.GetIniSection<CoreConfiguration>(); - - static NetworkHelper() { - try - { - // Disable certificate checking - ServicePointManager.ServerCertificateValidationCallback += delegate { - return true; - }; - } - catch (Exception ex) - { - Log.Warn("An error has occurred while allowing self-signed certificates:", ex); - } - } + /// <summary> + /// Description of NetworkHelper. + /// </summary> + public static class NetworkHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(NetworkHelper)); + private static readonly CoreConfiguration Config = IniConfig.GetIniSection<CoreConfiguration>(); + static NetworkHelper() + { + try + { + // Disable certificate checking + ServicePointManager.ServerCertificateValidationCallback += delegate { return true; }; + } + catch (Exception ex) + { + Log.Warn("An error has occurred while allowing self-signed certificates:", ex); + } + } /// <summary> - /// Download the uri into a memory stream, without catching exceptions - /// </summary> - /// <param name="url">Of an image</param> - /// <returns>MemoryStream which is already seek-ed to 0</returns> - public static MemoryStream GetAsMemoryStream(string url) { - var request = CreateWebRequest(url); + /// Download the uri into a memory stream, without catching exceptions + /// </summary> + /// <param name="url">Of an image</param> + /// <returns>MemoryStream which is already seek-ed to 0</returns> + public static MemoryStream GetAsMemoryStream(string url) + { + var request = CreateWebRequest(url); using var response = (HttpWebResponse)request.GetResponse(); var memoryStream = new MemoryStream(); - using (var responseStream = response.GetResponseStream()) { + using (var responseStream = response.GetResponseStream()) + { responseStream?.CopyTo(memoryStream); // Make sure it can be used directly memoryStream.Seek(0, SeekOrigin.Begin); } + return memoryStream; } - /// <summary> - /// Download the uri to Bitmap - /// </summary> - /// <param name="url">Of an image</param> - /// <returns>Bitmap</returns> - public static Image DownloadImage(string url) - { - var extensions = new StringBuilder(); - foreach (var extension in ImageHelper.StreamConverters.Keys) - { - if (string.IsNullOrEmpty(extension)) - { - continue; - } - extensions.AppendFormat(@"\.{0}|", extension); - } - extensions.Length--; + /// <summary> + /// Download the uri to Bitmap + /// </summary> + /// <param name="url">Of an image</param> + /// <returns>Bitmap</returns> + public static Image DownloadImage(string url) + { + var extensions = new StringBuilder(); + foreach (var extension in ImageHelper.StreamConverters.Keys) + { + if (string.IsNullOrEmpty(extension)) + { + continue; + } + + extensions.AppendFormat(@"\.{0}|", extension); + } + + extensions.Length--; var imageUrlRegex = new Regex($@"(http|https)://.*(?<extension>{extensions})"); - var match = imageUrlRegex.Match(url); - try + var match = imageUrlRegex.Match(url); + try { using var memoryStream = GetAsMemoryStream(url); try @@ -117,10 +123,12 @@ namespace GreenshotPlugin.Core { { content = streamReader.ReadLine(); } + if (string.IsNullOrEmpty(content)) { throw; } + match = imageUrlRegex.Match(content); if (!match.Success) { @@ -131,441 +139,588 @@ namespace GreenshotPlugin.Core { return ImageHelper.FromStream(memoryStream2, match.Groups["extension"]?.Value); } } - catch (Exception e) - { - Log.Error("Problem downloading the image from: " + url, e); - } - return null; - } + catch (Exception e) + { + Log.Error("Problem downloading the image from: " + url, e); + } - /// <summary> - /// Helper method to create a web request with a lot of default settings - /// </summary> - /// <param name="uri">string with uri to connect to</param> - /// <returns>WebRequest</returns> - public static HttpWebRequest CreateWebRequest(string uri) { - return CreateWebRequest(new Uri(uri)); - } + return null; + } - /// <summary> - /// Helper method to create a web request with a lot of default settings - /// </summary> - /// <param name="uri">string with uri to connect to</param> - /// /// <param name="method">Method to use</param> - /// <returns>WebRequest</returns> - public static HttpWebRequest CreateWebRequest(string uri, HTTPMethod method) { - return CreateWebRequest(new Uri(uri), method); - } + /// <summary> + /// Helper method to create a web request with a lot of default settings + /// </summary> + /// <param name="uri">string with uri to connect to</param> + /// <returns>WebRequest</returns> + public static HttpWebRequest CreateWebRequest(string uri) + { + return CreateWebRequest(new Uri(uri)); + } - /// <summary> - /// Helper method to create a web request with a lot of default settings - /// </summary> - /// <param name="uri">Uri with uri to connect to</param> - /// <param name="method">Method to use</param> - /// <returns>WebRequest</returns> - public static HttpWebRequest CreateWebRequest(Uri uri, HTTPMethod method) { - var webRequest = CreateWebRequest(uri); - webRequest.Method = method.ToString(); - return webRequest; - } + /// <summary> + /// Helper method to create a web request with a lot of default settings + /// </summary> + /// <param name="uri">string with uri to connect to</param> + /// /// <param name="method">Method to use</param> + /// <returns>WebRequest</returns> + public static HttpWebRequest CreateWebRequest(string uri, HTTPMethod method) + { + return CreateWebRequest(new Uri(uri), method); + } - /// <summary> - /// Helper method to create a web request, eventually with proxy - /// </summary> - /// <param name="uri">Uri with uri to connect to</param> - /// <returns>WebRequest</returns> - public static HttpWebRequest CreateWebRequest(Uri uri) { - var webRequest = (HttpWebRequest)WebRequest.Create(uri); - webRequest.Proxy = Config.UseProxy ? CreateProxy(uri) : null; - // Make sure the default credentials are available - webRequest.Credentials = CredentialCache.DefaultCredentials; + /// <summary> + /// Helper method to create a web request with a lot of default settings + /// </summary> + /// <param name="uri">Uri with uri to connect to</param> + /// <param name="method">Method to use</param> + /// <returns>WebRequest</returns> + public static HttpWebRequest CreateWebRequest(Uri uri, HTTPMethod method) + { + var webRequest = CreateWebRequest(uri); + webRequest.Method = method.ToString(); + return webRequest; + } - // Allow redirect, this is usually needed so that we don't get a problem when a service moves - webRequest.AllowAutoRedirect = true; - // Set default timeouts - webRequest.Timeout = Config.WebRequestTimeout*1000; - webRequest.ReadWriteTimeout = Config.WebRequestReadWriteTimeout*1000; - return webRequest; - } + /// <summary> + /// Helper method to create a web request, eventually with proxy + /// </summary> + /// <param name="uri">Uri with uri to connect to</param> + /// <returns>WebRequest</returns> + public static HttpWebRequest CreateWebRequest(Uri uri) + { + var webRequest = (HttpWebRequest)WebRequest.Create(uri); + webRequest.Proxy = Config.UseProxy ? CreateProxy(uri) : null; + // Make sure the default credentials are available + webRequest.Credentials = CredentialCache.DefaultCredentials; - /// <summary> - /// Create a IWebProxy Object which can be used to access the Internet - /// This method will check the configuration if the proxy is allowed to be used. - /// Usages can be found in the DownloadFavIcon or Jira and Confluence plugins - /// </summary> - /// <param name="uri"></param> - /// <returns>IWebProxy filled with all the proxy details or null if none is set/wanted</returns> - public static IWebProxy CreateProxy(Uri uri) { - IWebProxy proxyToUse = null; + // Allow redirect, this is usually needed so that we don't get a problem when a service moves + webRequest.AllowAutoRedirect = true; + // Set default timeouts + webRequest.Timeout = Config.WebRequestTimeout * 1000; + webRequest.ReadWriteTimeout = Config.WebRequestReadWriteTimeout * 1000; + return webRequest; + } + + /// <summary> + /// Create a IWebProxy Object which can be used to access the Internet + /// This method will check the configuration if the proxy is allowed to be used. + /// Usages can be found in the DownloadFavIcon or Jira and Confluence plugins + /// </summary> + /// <param name="uri"></param> + /// <returns>IWebProxy filled with all the proxy details or null if none is set/wanted</returns> + public static IWebProxy CreateProxy(Uri uri) + { + IWebProxy proxyToUse = null; if (!Config.UseProxy) { return proxyToUse; } + proxyToUse = WebRequest.DefaultWebProxy; - if (proxyToUse != null) { + if (proxyToUse != null) + { proxyToUse.Credentials = CredentialCache.DefaultCredentials; if (!Log.IsDebugEnabled) { return proxyToUse; } + // check the proxy for the Uri - if (!proxyToUse.IsBypassed(uri)) { + if (!proxyToUse.IsBypassed(uri)) + { var proxyUri = proxyToUse.GetProxy(uri); - if (proxyUri != null) { + if (proxyUri != null) + { Log.Debug("Using proxy: " + proxyUri + " for " + uri); - } else { + } + else + { Log.Debug("No proxy found!"); } - } else { + } + else + { Log.Debug("Proxy bypass for: " + uri); } - } else { + } + else + { Log.Debug("No proxy found!"); } + return proxyToUse; - } + } - /// <summary> - /// UrlEncodes a string without the requirement for System.Web - /// </summary> - /// <param name="text"></param> - /// <returns></returns> - // [Obsolete("Use System.Uri.EscapeDataString instead")] - public static string UrlEncode(string text) { - if (!string.IsNullOrEmpty(text)) { - // System.Uri provides reliable parsing, but doesn't encode spaces. - return Uri.EscapeDataString(text).Replace("%20", "+"); - } - return null; - } + /// <summary> + /// UrlEncodes a string without the requirement for System.Web + /// </summary> + /// <param name="text"></param> + /// <returns></returns> + // [Obsolete("Use System.Uri.EscapeDataString instead")] + public static string UrlEncode(string text) + { + if (!string.IsNullOrEmpty(text)) + { + // System.Uri provides reliable parsing, but doesn't encode spaces. + return Uri.EscapeDataString(text).Replace("%20", "+"); + } - /// <summary> - /// A wrapper around the EscapeDataString, as the limit is 32766 characters - /// See: http://msdn.microsoft.com/en-us/library/system.uri.escapedatastring%28v=vs.110%29.aspx - /// </summary> - /// <param name="text"></param> - /// <returns>escaped data string</returns> - public static string EscapeDataString(string text) { - if (!string.IsNullOrEmpty(text)) { - var result = new StringBuilder(); - int currentLocation = 0; - while (currentLocation < text.Length) { - string process = text.Substring(currentLocation, Math.Min(16384, text.Length - currentLocation)); - result.Append(Uri.EscapeDataString(process)); - currentLocation += 16384; - } - return result.ToString(); - } - return null; - } + return null; + } - /// <summary> - /// UrlDecodes a string without requiring System.Web - /// </summary> - /// <param name="text">String to decode.</param> - /// <returns>decoded string</returns> - public static string UrlDecode(string text) { - // pre-process for + sign space formatting since System.Uri doesn't handle it - // plus literals are encoded as %2b normally so this should be safe - text = text.Replace("+", " "); - return Uri.UnescapeDataString(text); - } + /// <summary> + /// A wrapper around the EscapeDataString, as the limit is 32766 characters + /// See: http://msdn.microsoft.com/en-us/library/system.uri.escapedatastring%28v=vs.110%29.aspx + /// </summary> + /// <param name="text"></param> + /// <returns>escaped data string</returns> + public static string EscapeDataString(string text) + { + if (!string.IsNullOrEmpty(text)) + { + var result = new StringBuilder(); + int currentLocation = 0; + while (currentLocation < text.Length) + { + string process = text.Substring(currentLocation, Math.Min(16384, text.Length - currentLocation)); + result.Append(Uri.EscapeDataString(process)); + currentLocation += 16384; + } - /// <summary> - /// ParseQueryString without the requirement for System.Web - /// </summary> - /// <param name="queryString"></param> - /// <returns>IDictionary string, string</returns> - public static IDictionary<string, string> ParseQueryString(string queryString) { - IDictionary<string, string> parameters = new SortedDictionary<string, string>(); - // remove anything other than query string from uri - if (queryString.Contains("?")) { - queryString = queryString.Substring(queryString.IndexOf('?') + 1); - } - foreach (string vp in Regex.Split(queryString, "&")) { - if (string.IsNullOrEmpty(vp)) { - continue; - } - string[] singlePair = Regex.Split(vp, "="); - if (parameters.ContainsKey(singlePair[0])) { - parameters.Remove(singlePair[0]); - } - parameters.Add(singlePair[0], singlePair.Length == 2 ? singlePair[1] : string.Empty); - } - return parameters; - } + return result.ToString(); + } - /// <summary> - /// Generate the query parameters - /// </summary> - /// <param name="queryParameters">the list of query parameters</param> - /// <returns>a string with the query parameters</returns> - public static string GenerateQueryParameters(IDictionary<string, object> queryParameters) { - if (queryParameters == null || queryParameters.Count == 0) { - return string.Empty; - } + return null; + } - queryParameters = new SortedDictionary<string, object>(queryParameters); + /// <summary> + /// UrlDecodes a string without requiring System.Web + /// </summary> + /// <param name="text">String to decode.</param> + /// <returns>decoded string</returns> + public static string UrlDecode(string text) + { + // pre-process for + sign space formatting since System.Uri doesn't handle it + // plus literals are encoded as %2b normally so this should be safe + text = text.Replace("+", " "); + return Uri.UnescapeDataString(text); + } - var sb = new StringBuilder(); - foreach(string key in queryParameters.Keys) { - sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode($"{queryParameters[key]}")); - } - sb.Remove(sb.Length-1,1); + /// <summary> + /// ParseQueryString without the requirement for System.Web + /// </summary> + /// <param name="queryString"></param> + /// <returns>IDictionary string, string</returns> + public static IDictionary<string, string> ParseQueryString(string queryString) + { + IDictionary<string, string> parameters = new SortedDictionary<string, string>(); + // remove anything other than query string from uri + if (queryString.Contains("?")) + { + queryString = queryString.Substring(queryString.IndexOf('?') + 1); + } - return sb.ToString(); - } + foreach (string vp in Regex.Split(queryString, "&")) + { + if (string.IsNullOrEmpty(vp)) + { + continue; + } - /// <summary> - /// Write Multipart Form Data directly to the HttpWebRequest - /// </summary> - /// <param name="webRequest">HttpWebRequest to write the multipart form data to</param> - /// <param name="postParameters">Parameters to include in the multipart form data</param> - public static void WriteMultipartFormData(HttpWebRequest webRequest, IDictionary<string, object> postParameters) { - string boundary = $"----------{Guid.NewGuid():N}"; - webRequest.ContentType = "multipart/form-data; boundary=" + boundary; + string[] singlePair = Regex.Split(vp, "="); + if (parameters.ContainsKey(singlePair[0])) + { + parameters.Remove(singlePair[0]); + } + + parameters.Add(singlePair[0], singlePair.Length == 2 ? singlePair[1] : string.Empty); + } + + return parameters; + } + + /// <summary> + /// Generate the query parameters + /// </summary> + /// <param name="queryParameters">the list of query parameters</param> + /// <returns>a string with the query parameters</returns> + public static string GenerateQueryParameters(IDictionary<string, object> queryParameters) + { + if (queryParameters == null || queryParameters.Count == 0) + { + return string.Empty; + } + + queryParameters = new SortedDictionary<string, object>(queryParameters); + + var sb = new StringBuilder(); + foreach (string key in queryParameters.Keys) + { + sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode($"{queryParameters[key]}")); + } + + sb.Remove(sb.Length - 1, 1); + + return sb.ToString(); + } + + /// <summary> + /// Write Multipart Form Data directly to the HttpWebRequest + /// </summary> + /// <param name="webRequest">HttpWebRequest to write the multipart form data to</param> + /// <param name="postParameters">Parameters to include in the multipart form data</param> + public static void WriteMultipartFormData(HttpWebRequest webRequest, IDictionary<string, object> postParameters) + { + string boundary = $"----------{Guid.NewGuid():N}"; + webRequest.ContentType = "multipart/form-data; boundary=" + boundary; using Stream formDataStream = webRequest.GetRequestStream(); WriteMultipartFormData(formDataStream, boundary, postParameters); } + /// <summary> + /// Write Multipart Form Data to a Stream, content-type should be set before this! + /// </summary> + /// <param name="formDataStream">Stream to write the multipart form data to</param> + /// <param name="boundary">String boundary for the multipart/form-data</param> + /// <param name="postParameters">Parameters to include in the multipart form data</param> + public static void WriteMultipartFormData(Stream formDataStream, string boundary, IDictionary<string, object> postParameters) + { + bool needsClrf = false; + foreach (var param in postParameters) + { + // Add a CRLF to allow multiple parameters to be added. + // Skip it on the first parameter, add it to subsequent parameters. + if (needsClrf) + { + formDataStream.Write(Encoding.UTF8.GetBytes("\r\n"), 0, Encoding.UTF8.GetByteCount("\r\n")); + } + + needsClrf = true; + + if (param.Value is IBinaryContainer binaryContainer) + { + binaryContainer.WriteFormDataToStream(boundary, param.Key, formDataStream); + } + else + { + string postData = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{param.Key}\"\r\n\r\n{param.Value}"; + formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData)); + } + } + + // Add the end of the request. Start with a newline + string footer = "\r\n--" + boundary + "--\r\n"; + formDataStream.Write(Encoding.UTF8.GetBytes(footer), 0, Encoding.UTF8.GetByteCount(footer)); + } /// <summary> - /// Write Multipart Form Data to a Stream, content-type should be set before this! - /// </summary> - /// <param name="formDataStream">Stream to write the multipart form data to</param> - /// <param name="boundary">String boundary for the multipart/form-data</param> - /// <param name="postParameters">Parameters to include in the multipart form data</param> - public static void WriteMultipartFormData(Stream formDataStream, string boundary, IDictionary<string, object> postParameters) { - bool needsClrf = false; - foreach (var param in postParameters) { - // Add a CRLF to allow multiple parameters to be added. - // Skip it on the first parameter, add it to subsequent parameters. - if (needsClrf) { - formDataStream.Write(Encoding.UTF8.GetBytes("\r\n"), 0, Encoding.UTF8.GetByteCount("\r\n")); - } + /// Post content HttpWebRequest + /// </summary> + /// <param name="webRequest">HttpWebRequest to write the multipart form data to</param> + /// <param name="headers">IDictionary with the headers</param> + /// <param name="binaryContainer">IBinaryContainer</param> + public static void Post(HttpWebRequest webRequest, IDictionary<string, object> headers, IBinaryContainer binaryContainer = null) + { + foreach (var header in headers) + { + switch (header.Key) + { + case "Content-Type": + webRequest.ContentType = header.Value as string; + break; + case "Accept": + webRequest.Accept = header.Value as string; + break; + default: + webRequest.Headers.Add(header.Key, Convert.ToString(header.Value)); + break; + } + } + if (!headers.ContainsKey("Content-Type")) + { + webRequest.ContentType = "application/octet-stream"; + } - needsClrf = true; + if (binaryContainer != null) + { + using var requestStream = webRequest.GetRequestStream(); + binaryContainer.WriteToStream(requestStream); + } + } - if (param.Value is IBinaryContainer binaryContainer) { - binaryContainer.WriteFormDataToStream(boundary, param.Key, formDataStream); - } else { - string postData = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{param.Key}\"\r\n\r\n{param.Value}"; - formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData)); - } - } + /// <summary> + /// Post content HttpWebRequest + /// </summary> + /// <param name="webRequest">HttpWebRequest to write the multipart form data to</param> + /// <param name="headers">IDictionary with the headers</param> + /// <param name="jsonString">string</param> + public static void Post(HttpWebRequest webRequest, IDictionary<string, object> headers, string jsonString) + { + if (headers != null) + { + foreach (var header in headers) + { + switch (header.Key) + { + case "Content-Type": + webRequest.ContentType = header.Value as string; + break; + case "Accept": + webRequest.Accept = header.Value as string; + break; + default: + webRequest.Headers.Add(header.Key, Convert.ToString(header.Value)); + break; + } + } + if (!headers.ContainsKey("Content-Type")) + { + webRequest.ContentType = "application/json"; + } + } + else + { + webRequest.ContentType = "application/json"; + } - // Add the end of the request. Start with a newline - string footer = "\r\n--" + boundary + "--\r\n"; - formDataStream.Write(Encoding.UTF8.GetBytes(footer), 0, Encoding.UTF8.GetByteCount(footer)); - } + if (jsonString != null) + { + using var requestStream = webRequest.GetRequestStream(); + using var streamWriter = new StreamWriter(requestStream); + streamWriter.Write(jsonString); + } + } - /// <summary> - /// Post the parameters "x-www-form-urlencoded" - /// </summary> - /// <param name="webRequest"></param> - /// <param name="parameters"></param> - public static void UploadFormUrlEncoded(HttpWebRequest webRequest, IDictionary<string, object> parameters) { - webRequest.ContentType = "application/x-www-form-urlencoded"; - string urlEncoded = GenerateQueryParameters(parameters); + /// <summary> + /// Post the parameters "x-www-form-urlencoded" + /// </summary> + /// <param name="webRequest"></param> + /// <param name="parameters"></param> + public static void UploadFormUrlEncoded(HttpWebRequest webRequest, IDictionary<string, object> parameters) + { + webRequest.ContentType = "application/x-www-form-urlencoded"; + string urlEncoded = GenerateQueryParameters(parameters); - byte[] data = Encoding.UTF8.GetBytes(urlEncoded); + byte[] data = Encoding.UTF8.GetBytes(urlEncoded); using var requestStream = webRequest.GetRequestStream(); requestStream.Write(data, 0, data.Length); } - /// <summary> - /// Log the headers of the WebResponse, if IsDebugEnabled - /// </summary> - /// <param name="response">WebResponse</param> - private static void DebugHeaders(WebResponse response) { - if (!Log.IsDebugEnabled) { - return; - } - Log.DebugFormat("Debug information on the response from {0} :", response.ResponseUri); - foreach (string key in response.Headers.AllKeys) { - Log.DebugFormat("Reponse-header: {0}={1}", key, response.Headers[key]); - } - } + /// <summary> + /// Log the headers of the WebResponse, if IsDebugEnabled + /// </summary> + /// <param name="response">WebResponse</param> + private static void DebugHeaders(WebResponse response) + { + if (!Log.IsDebugEnabled) + { + return; + } - /// <summary> - /// Process the web response. - /// </summary> - /// <param name="webRequest">The request object.</param> - /// <returns>The response data.</returns> - /// TODO: This method should handle the StatusCode better! - public static string GetResponseAsString(HttpWebRequest webRequest) { - return GetResponseAsString(webRequest, false); - } + Log.DebugFormat("Debug information on the response from {0} :", response.ResponseUri); + foreach (string key in response.Headers.AllKeys) + { + Log.DebugFormat("Reponse-header: {0}={1}", key, response.Headers[key]); + } + } - /// <summary> - /// Read the response as string - /// </summary> - /// <param name="response"></param> - /// <returns>string or null</returns> - private static string GetResponseAsString(HttpWebResponse response) - { - string responseData = null; - if (response == null) - { - return null; - } - using (response) - { - Stream responseStream = response.GetResponseStream(); - if (responseStream != null) + /// <summary> + /// Process the web response. + /// </summary> + /// <param name="webRequest">The request object.</param> + /// <returns>The response data.</returns> + /// TODO: This method should handle the StatusCode better! + public static string GetResponseAsString(HttpWebRequest webRequest) + { + return GetResponseAsString(webRequest, false); + } + + /// <summary> + /// Read the response as string + /// </summary> + /// <param name="response"></param> + /// <returns>string or null</returns> + private static string GetResponseAsString(HttpWebResponse response) + { + string responseData = null; + if (response == null) + { + return null; + } + + using (response) + { + Stream responseStream = response.GetResponseStream(); + if (responseStream != null) { using StreamReader reader = new StreamReader(responseStream, true); responseData = reader.ReadToEnd(); } - } - return responseData; - } + } - /// <summary> - /// - /// </summary> - /// <param name="webRequest"></param> - /// <param name="alsoReturnContentOnError"></param> - /// <returns></returns> - public static string GetResponseAsString(HttpWebRequest webRequest, bool alsoReturnContentOnError) { - string responseData = null; - HttpWebResponse response = null; - bool isHttpError = false; - try { - response = (HttpWebResponse)webRequest.GetResponse(); - Log.InfoFormat("Response status: {0}", response.StatusCode); - isHttpError = (int)response.StatusCode >= 300; - if (isHttpError) - { - Log.ErrorFormat("HTTP error {0}", response.StatusCode); - } - DebugHeaders(response); - responseData = GetResponseAsString(response); - if (isHttpError) - { - Log.ErrorFormat("HTTP response {0}", responseData); - } - } - catch (WebException e) { - response = (HttpWebResponse) e.Response; - HttpStatusCode statusCode = HttpStatusCode.Unused; - if (response != null) { - statusCode = response.StatusCode; - Log.ErrorFormat("HTTP error {0}", statusCode); - string errorContent = GetResponseAsString(response); - if (alsoReturnContentOnError) - { - return errorContent; - } - Log.ErrorFormat("Content: {0}", errorContent); - } - Log.Error("WebException: ", e); - if (statusCode == HttpStatusCode.Unauthorized) - { - throw new UnauthorizedAccessException(e.Message); - } - throw; - } - finally - { - if (response != null) - { - if (isHttpError) - { - Log.ErrorFormat("HTTP error {0} with content: {1}", response.StatusCode, responseData); - } - response.Close(); - } - } - return responseData; - } + return responseData; + } + + /// <summary> + /// + /// </summary> + /// <param name="webRequest"></param> + /// <param name="alsoReturnContentOnError"></param> + /// <returns></returns> + public static string GetResponseAsString(HttpWebRequest webRequest, bool alsoReturnContentOnError) + { + string responseData = null; + HttpWebResponse response = null; + bool isHttpError = false; + try + { + response = (HttpWebResponse)webRequest.GetResponse(); + Log.InfoFormat("Response status: {0}", response.StatusCode); + isHttpError = (int)response.StatusCode >= 300; + if (isHttpError) + { + Log.ErrorFormat("HTTP error {0}", response.StatusCode); + } + + DebugHeaders(response); + responseData = GetResponseAsString(response); + if (isHttpError) + { + Log.ErrorFormat("HTTP response {0}", responseData); + } + } + catch (WebException e) + { + response = (HttpWebResponse)e.Response; + HttpStatusCode statusCode = HttpStatusCode.Unused; + if (response != null) + { + statusCode = response.StatusCode; + Log.ErrorFormat("HTTP error {0}", statusCode); + string errorContent = GetResponseAsString(response); + if (alsoReturnContentOnError) + { + return errorContent; + } + + Log.ErrorFormat("Content: {0}", errorContent); + } + + Log.Error("WebException: ", e); + if (statusCode == HttpStatusCode.Unauthorized) + { + throw new UnauthorizedAccessException(e.Message); + } + + throw; + } + finally + { + if (response != null) + { + if (isHttpError) + { + Log.ErrorFormat("HTTP error {0} with content: {1}", response.StatusCode, responseData); + } + + response.Close(); + } + } + + return responseData; + } + + } + /// <summary> + /// This interface can be used to pass binary information around, like byte[] or Image + /// </summary> + public interface IBinaryContainer + { + void WriteFormDataToStream(string boundary, string name, Stream formDataStream); + void WriteToStream(Stream formDataStream); + string ToBase64String(Base64FormattingOptions formattingOptions); + byte[] ToByteArray(); + void Upload(HttpWebRequest webRequest); + + string ContentType { get; } + string Filename { get; set; } } - /// <summary> - /// This interface can be used to pass binary information around, like byte[] or Image - /// </summary> - public interface IBinaryContainer { - void WriteFormDataToStream(string boundary, string name, Stream formDataStream); - void WriteToStream(Stream formDataStream); - string ToBase64String(Base64FormattingOptions formattingOptions); - byte[] ToByteArray(); - void Upload(HttpWebRequest webRequest); + /// A container to supply surfaces to a Multi-part form data upload + /// </summary> + public class SurfaceContainer : IBinaryContainer + { + private readonly ISurface _surface; + private readonly SurfaceOutputSettings _outputSettings; - string ContentType { get; } - string Filename { get; set; } - } + public SurfaceContainer(ISurface surface, SurfaceOutputSettings outputSettings, string filename) + { + _surface = surface; + _outputSettings = outputSettings; + Filename = filename; + } - /// <summary> - /// A container to supply surfaces to a Multi-part form data upload - /// </summary> - public class SurfaceContainer : IBinaryContainer { - private readonly ISurface _surface; - private readonly SurfaceOutputSettings _outputSettings; - - public SurfaceContainer(ISurface surface, SurfaceOutputSettings outputSettings, string filename) { - _surface = surface; - _outputSettings = outputSettings; - Filename = filename; - } - - /// <summary> - /// Create a Base64String from the Surface by saving it to a memory stream and converting it. - /// Should be avoided if possible, as this uses a lot of memory. - /// </summary> - /// <returns>string</returns> - public string ToBase64String(Base64FormattingOptions formattingOptions) + /// <summary> + /// Create a Base64String from the Surface by saving it to a memory stream and converting it. + /// Should be avoided if possible, as this uses a lot of memory. + /// </summary> + /// <returns>string</returns> + public string ToBase64String(Base64FormattingOptions formattingOptions) { using MemoryStream stream = new MemoryStream(); ImageOutput.SaveToStream(_surface, stream, _outputSettings); return Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length, formattingOptions); } - /// <summary> - /// Create a byte[] from the image by saving it to a memory stream. - /// Should be avoided if possible, as this uses a lot of memory. - /// </summary> - /// <returns>byte[]</returns> - public byte[] ToByteArray() + /// <summary> + /// Create a byte[] from the image by saving it to a memory stream. + /// Should be avoided if possible, as this uses a lot of memory. + /// </summary> + /// <returns>byte[]</returns> + public byte[] ToByteArray() { using MemoryStream stream = new MemoryStream(); ImageOutput.SaveToStream(_surface, stream, _outputSettings); return stream.ToArray(); } - /// <summary> - /// Write Multipart Form Data directly to the HttpWebRequest response stream - /// </summary> - /// <param name="boundary">Multipart separator</param> - /// <param name="name">Name of the thing</param> - /// <param name="formDataStream">Stream to write to</param> - public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) { - // Add just the first part of this param, since we will write the file data directly to the Stream - string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n"; + /// <summary> + /// Write Multipart Form Data directly to the HttpWebRequest response stream + /// </summary> + /// <param name="boundary">Multipart separator</param> + /// <param name="name">Name of the thing</param> + /// <param name="formDataStream">Stream to write to</param> + public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) + { + // Add just the first part of this param, since we will write the file data directly to the Stream + string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n"; - formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header)); - ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings); - } + formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header)); + ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings); + } - /// <summary> - /// A plain "write data to stream" - /// </summary> - /// <param name="dataStream"></param> - public void WriteToStream(Stream dataStream) { - // Write the file data directly to the Stream, rather than serializing it to a string. - ImageOutput.SaveToStream(_surface, dataStream, _outputSettings); - } + /// <summary> + /// A plain "write data to stream" + /// </summary> + /// <param name="dataStream"></param> + public void WriteToStream(Stream dataStream) + { + // Write the file data directly to the Stream, rather than serializing it to a string. + ImageOutput.SaveToStream(_surface, dataStream, _outputSettings); + } - /// <summary> - /// Upload the Surface as image to the webrequest - /// </summary> - /// <param name="webRequest"></param> - public void Upload(HttpWebRequest webRequest) { - webRequest.ContentType = ContentType; + /// <summary> + /// Upload the Surface as image to the webrequest + /// </summary> + /// <param name="webRequest"></param> + public void Upload(HttpWebRequest webRequest) + { + webRequest.ContentType = ContentType; using var requestStream = webRequest.GetRequestStream(); WriteToStream(requestStream); } - public string ContentType => "image/" + _outputSettings.Format; - public string Filename { get; set; } - } -} + public string ContentType => "image/" + _outputSettings.Format; + public string Filename { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs b/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs new file mode 100644 index 000000000..7b363b2fa --- /dev/null +++ b/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs @@ -0,0 +1,191 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using log4net; +using Newtonsoft.Json; + +namespace GreenshotPlugin.Core.OAuth +{ + /// <summary> + /// OAuth 2.0 verification code receiver that runs a local server on a free port + /// and waits for a call with the authorization verification code. + /// </summary> + public class LocalJsonReceiver + { + private static readonly ILog Log = LogManager.GetLogger(typeof(LocalJsonReceiver)); + private readonly ManualResetEvent _ready = new ManualResetEvent(true); + private IDictionary<string, string> _returnValues; + + /// <summary> + /// The url format for the website to post to. Expects one port parameter. + /// Default: http://localhost:{0}/authorize/ + /// </summary> + public string ListeningUrlFormat { get; set; } = "http://localhost:{0}/authorize/"; + + private string _listeningUri; + /// <summary> + /// The URL where the server is listening + /// </summary> + public string ListeningUri { + get { + if (string.IsNullOrEmpty(_listeningUri)) + { + _listeningUri = string.Format(ListeningUrlFormat, GetRandomUnusedPort()); + } + return _listeningUri; + } + set => _listeningUri = value; + } + + /// <summary> + /// This action is called when the URI must be opened, default is just to run Process.Start + /// </summary> + public Action<string> OpenUriAction + { + set; + get; + } = authorizationUrl => + { + Log.DebugFormat("Open a browser with: {0}", authorizationUrl); + using var process = Process.Start(authorizationUrl); + }; + + /// <summary> + /// Timeout for waiting for the website to respond + /// </summary> + public TimeSpan Timeout { get; set; } = TimeSpan.FromMinutes(4); + + /// <summary> + /// The OAuth code receiver + /// </summary> + /// <param name="oauth2Settings">OAuth2Settings</param> + /// <returns>Dictionary with values</returns> + public IDictionary<string, string> ReceiveCode(OAuth2Settings oauth2Settings) { + using var listener = new HttpListener(); + // Make sure the port is stored in the state, so the website can process this. + oauth2Settings.State = new Uri(ListeningUri).Port.ToString(); + listener.Prefixes.Add(ListeningUri); + try { + listener.Start(); + _ready.Reset(); + + listener.BeginGetContext(ListenerCallback, listener); + OpenUriAction(oauth2Settings.FormattedAuthUrl); + _ready.WaitOne(Timeout, true); + } catch (Exception) { + // Make sure we can clean up, also if the thead is aborted + _ready.Set(); + throw; + } finally { + listener.Close(); + } + + return _returnValues; + } + + /// <summary> + /// Handle a connection async, this allows us to break the waiting + /// </summary> + /// <param name="result">IAsyncResult</param> + private void ListenerCallback(IAsyncResult result) { + HttpListener listener = (HttpListener)result.AsyncState; + + //If not listening return immediately as this method is called one last time after Close() + if (!listener.IsListening) { + return; + } + + // Use EndGetContext to complete the asynchronous operation. + HttpListenerContext context = listener.EndGetContext(result); + + // Handle request + HttpListenerRequest request = context.Request; + + if (request.HasEntityBody) + { + // Process the body + using var body = request.InputStream; + using var reader = new StreamReader(body, request.ContentEncoding); + using var jsonTextReader = new JsonTextReader(reader); + var serializer = new JsonSerializer(); + _returnValues = serializer.Deserialize<Dictionary<string, string>>(jsonTextReader); + } + + // Create the response. + using (HttpListenerResponse response = context.Response) + { + if (request.HttpMethod == "OPTIONS") + { + response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With"); + response.AddHeader("Access-Control-Allow-Methods", "POST"); + response.AddHeader("Access-Control-Max-Age", "1728000"); + } + + response.AppendHeader("Access-Control-Allow-Origin", "*"); + if (request.HasEntityBody) + { + response.ContentType = "application/json"; + // currently only return the version, more can be added later + string jsonContent = "{\"version\": \"" + EnvironmentInfo.GetGreenshotVersion(true) + "\"}"; + + // Write a "close" response. + byte[] buffer = Encoding.UTF8.GetBytes(jsonContent); + // Write to response stream. + response.ContentLength64 = buffer.Length; + using var stream = response.OutputStream; + stream.Write(buffer, 0, buffer.Length); + } + } + + if (_returnValues != null) + { + _ready.Set(); + } + else + { + // Make sure the next request is processed + listener.BeginGetContext(ListenerCallback, listener); + } + } + + /// <summary> + /// Returns a random, unused port. + /// </summary> + /// <returns>port to use</returns> + private static int GetRandomUnusedPort() { + var listener = new TcpListener(IPAddress.Loopback, 0); + try { + listener.Start(); + return ((IPEndPoint)listener.LocalEndpoint).Port; + } finally { + listener.Stop(); + } + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs b/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs new file mode 100644 index 000000000..a4915e8b6 --- /dev/null +++ b/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs @@ -0,0 +1,183 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using log4net; + +namespace GreenshotPlugin.Core.OAuth +{ + /// <summary> + /// OAuth 2.0 verification code receiver that runs a local server on a free port + /// and waits for a call with the authorization verification code. + /// </summary> + public class LocalServerCodeReceiver { + private static readonly ILog Log = LogManager.GetLogger(typeof(LocalServerCodeReceiver)); + private readonly ManualResetEvent _ready = new ManualResetEvent(true); + + /// <summary> + /// The call back format. Expects one port parameter. + /// Default: http://localhost:{0}/authorize/ + /// </summary> + public string LoopbackCallbackUrl { get; set; } = "http://localhost:{0}/authorize/"; + + /// <summary> + /// HTML code to to return the _browser, default it will try to close the _browser / tab, this won't always work. + /// You can use CloudServiceName where you want to show the CloudServiceName from your OAuth2 settings + /// </summary> + public string ClosePageResponse { get; set; } = @"<html> +<head><title>OAuth 2.0 Authentication CloudServiceName + +Greenshot received information from CloudServiceName. You can close this browser / tab if it is not closed itself... + + +"; + + private string _redirectUri; + /// + /// The URL to redirect to + /// + protected string RedirectUri { + get { + if (!string.IsNullOrEmpty(_redirectUri)) { + return _redirectUri; + } + + return _redirectUri = string.Format(LoopbackCallbackUrl, GetRandomUnusedPort()); + } + } + + private string _cloudServiceName; + + private readonly IDictionary _returnValues = new Dictionary(); + + + /// + /// The OAuth code receiver + /// + /// + /// Dictionary with values + public IDictionary ReceiveCode(OAuth2Settings oauth2Settings) { + // Set the redirect URL on the settings + oauth2Settings.RedirectUrl = RedirectUri; + _cloudServiceName = oauth2Settings.CloudServiceName; + using (var listener = new HttpListener()) { + listener.Prefixes.Add(oauth2Settings.RedirectUrl); + try { + listener.Start(); + + // Get the formatted FormattedAuthUrl + string authorizationUrl = oauth2Settings.FormattedAuthUrl; + Log.DebugFormat("Open a browser with: {0}", authorizationUrl); + Process.Start(authorizationUrl); + + // Wait to get the authorization code response. + var context = listener.BeginGetContext(ListenerCallback, listener); + _ready.Reset(); + + while (!context.AsyncWaitHandle.WaitOne(1000, true)) { + Log.Debug("Waiting for response"); + } + } catch (Exception) { + // Make sure we can clean up, also if the thead is aborted + _ready.Set(); + throw; + } finally { + _ready.WaitOne(); + listener.Close(); + } + } + return _returnValues; + } + + /// + /// Handle a connection async, this allows us to break the waiting + /// + /// IAsyncResult + private void ListenerCallback(IAsyncResult result) { + HttpListener listener = (HttpListener)result.AsyncState; + + //If not listening return immediately as this method is called one last time after Close() + if (!listener.IsListening) { + return; + } + + // Use EndGetContext to complete the asynchronous operation. + HttpListenerContext context = listener.EndGetContext(result); + + + // Handle request + HttpListenerRequest request = context.Request; + try { + NameValueCollection nameValueCollection = request.QueryString; + + // Get response object. + using (HttpListenerResponse response = context.Response) { + // Write a "close" response. + byte[] buffer = Encoding.UTF8.GetBytes(ClosePageResponse.Replace("CloudServiceName", _cloudServiceName)); + // Write to response stream. + response.ContentLength64 = buffer.Length; + using var stream = response.OutputStream; + stream.Write(buffer, 0, buffer.Length); + } + + // Create a new response URL with a dictionary that contains all the response query parameters. + foreach (var name in nameValueCollection.AllKeys) { + if (!_returnValues.ContainsKey(name)) { + _returnValues.Add(name, nameValueCollection[name]); + } + } + } catch (Exception) { + context.Response.OutputStream.Close(); + throw; + } + _ready.Set(); + } + + /// + /// Returns a random, unused port. + /// + /// port to use + private static int GetRandomUnusedPort() { + var listener = new TcpListener(IPAddress.Loopback, 0); + try { + listener.Start(); + return ((IPEndPoint)listener.LocalEndpoint).Port; + } finally { + listener.Stop(); + } + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs b/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs new file mode 100644 index 000000000..98d4515f9 --- /dev/null +++ b/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs @@ -0,0 +1,33 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace GreenshotPlugin.Core.OAuth +{ + /// + /// Specify the authorize mode that is used to get the token from the cloud service. + /// + public enum OAuth2AuthorizeMode { + Unknown, // Will give an exception, caller needs to specify another value + LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener + JsonReceiver, // Will start a local HttpListener and wait for a Json post + EmbeddedBrowser // Will open into an embedded _browser (OAuthLoginForm), and catch the redirect + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs b/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs new file mode 100644 index 000000000..b80d62b3d --- /dev/null +++ b/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs @@ -0,0 +1,372 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Net; +using GreenshotPlugin.Controls; + +namespace GreenshotPlugin.Core.OAuth { + /// + /// Code to simplify OAuth 2 + /// + public static class OAuth2Helper { + private const string RefreshToken = "refresh_token"; + private const string AccessToken = "access_token"; + private const string Code = "code"; + private const string Error = "error"; + private const string ClientId = "client_id"; + private const string ClientSecret = "client_secret"; + private const string GrantType = "grant_type"; + private const string AuthorizationCode = "authorization_code"; + private const string RedirectUri = "redirect_uri"; + private const string ExpiresIn = "expires_in"; + + /// + /// Generate an OAuth 2 Token by using the supplied code + /// + /// OAuth2Settings to update with the information that was retrieved + public static void GenerateRefreshToken(OAuth2Settings settings) { + IDictionary data = new Dictionary + { + // Use the returned code to get a refresh code + { Code, settings.Code }, + { ClientId, settings.ClientId }, + { ClientSecret, settings.ClientSecret }, + { GrantType, AuthorizationCode } + }; + foreach (string key in settings.AdditionalAttributes.Keys) { + data.Add(key, settings.AdditionalAttributes[key]); + } + + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); + NetworkHelper.UploadFormUrlEncoded(webRequest, data); + string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); + + IDictionary refreshTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); + if (refreshTokenResult.ContainsKey("error")) + { + if (refreshTokenResult.ContainsKey("error_description")) { + throw new Exception($"{refreshTokenResult["error"]} - {refreshTokenResult["error_description"]}"); + } + throw new Exception((string)refreshTokenResult["error"]); + } + + // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp + // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", + // "expires_in":3920, + // "token_type":"Bearer", + // "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" + if (refreshTokenResult.ContainsKey(AccessToken)) + { + settings.AccessToken = (string)refreshTokenResult[AccessToken]; + } + if (refreshTokenResult.ContainsKey(RefreshToken)) + { + settings.RefreshToken = (string)refreshTokenResult[RefreshToken]; + } + if (refreshTokenResult.ContainsKey(ExpiresIn)) + { + object seconds = refreshTokenResult[ExpiresIn]; + if (seconds != null) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double)seconds); + } + } + settings.Code = null; + } + + /// + /// Used to update the settings with the callback information + /// + /// OAuth2Settings + /// IDictionary + /// true if the access token is already in the callback + private static bool UpdateFromCallback(OAuth2Settings settings, IDictionary callbackParameters) + { + if (!callbackParameters.ContainsKey(AccessToken)) + { + return false; + } + if (callbackParameters.ContainsKey(RefreshToken)) + { + // Refresh the refresh token :) + settings.RefreshToken = callbackParameters[RefreshToken]; + } + if (callbackParameters.ContainsKey(ExpiresIn)) + { + var expiresIn = callbackParameters[ExpiresIn]; + settings.AccessTokenExpires = DateTimeOffset.MaxValue; + if (expiresIn != null) + { + if (double.TryParse(expiresIn, out var seconds)) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); + } + } + } + settings.AccessToken = callbackParameters[AccessToken]; + return true; + } + + /// + /// Go out and retrieve a new access token via refresh-token with the TokenUrl in the settings + /// Will update the access token, refresh token, expire date + /// + /// + public static void GenerateAccessToken(OAuth2Settings settings) { + IDictionary data = new Dictionary + { + { RefreshToken, settings.RefreshToken }, + { ClientId, settings.ClientId }, + { ClientSecret, settings.ClientSecret }, + { GrantType, RefreshToken } + }; + foreach (string key in settings.AdditionalAttributes.Keys) { + data.Add(key, settings.AdditionalAttributes[key]); + } + + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); + NetworkHelper.UploadFormUrlEncoded(webRequest, data); + string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); + + // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp + // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", + // "expires_in":3920, + // "token_type":"Bearer", + + IDictionary accessTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); + if (accessTokenResult.ContainsKey("error")) + { + if ("invalid_grant" == (string)accessTokenResult["error"]) { + // Refresh token has also expired, we need a new one! + settings.RefreshToken = null; + settings.AccessToken = null; + settings.AccessTokenExpires = DateTimeOffset.MinValue; + settings.Code = null; + return; + } + + if (accessTokenResult.ContainsKey("error_description")) { + throw new Exception($"{accessTokenResult["error"]} - {accessTokenResult["error_description"]}"); + } + + throw new Exception((string)accessTokenResult["error"]); + } + + if (accessTokenResult.ContainsKey(AccessToken)) + { + settings.AccessToken = (string) accessTokenResult[AccessToken]; + settings.AccessTokenExpires = DateTimeOffset.MaxValue; + } + if (accessTokenResult.ContainsKey(RefreshToken)) { + // Refresh the refresh token :) + settings.RefreshToken = (string)accessTokenResult[RefreshToken]; + } + if (accessTokenResult.ContainsKey(ExpiresIn)) + { + object seconds = accessTokenResult[ExpiresIn]; + if (seconds != null) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double) seconds); + } + } + } + + /// + /// Authorize by using the mode specified in the settings + /// + /// OAuth2Settings + /// false if it was canceled, true if it worked, exception if not + public static bool Authorize(OAuth2Settings settings) { + var completed = settings.AuthorizeMode switch + { + OAuth2AuthorizeMode.LocalServer => AuthorizeViaLocalServer(settings), + OAuth2AuthorizeMode.EmbeddedBrowser => AuthorizeViaEmbeddedBrowser(settings), + OAuth2AuthorizeMode.JsonReceiver => AuthorizeViaDefaultBrowser(settings), + _ => throw new NotImplementedException($"Authorize mode '{settings.AuthorizeMode}' is not 'yet' implemented."), + }; + return completed; + } + + /// + /// Authorize via the default browser, via the Greenshot website. + /// It will wait for a Json post. + /// If this works, return the code + /// + /// OAuth2Settings with the Auth / Token url etc + /// true if completed, false if canceled + private static bool AuthorizeViaDefaultBrowser(OAuth2Settings settings) + { + var codeReceiver = new LocalJsonReceiver(); + IDictionary result = codeReceiver.ReceiveCode(settings); + + if (result == null || result.Count == 0) + { + return false; + } + foreach (var key in result.Keys) + { + switch (key) + { + case AccessToken: + settings.AccessToken = result[key]; + break; + case ExpiresIn: + if (int.TryParse(result[key], out var seconds)) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); + } + break; + case RefreshToken: + settings.RefreshToken = result[key]; + break; + } + } + + if (result.TryGetValue("error", out var error)) + { + if (result.TryGetValue("error_description", out var errorDescription)) + { + throw new Exception(errorDescription); + } + if ("access_denied" == error) + { + throw new UnauthorizedAccessException("Access denied"); + } + throw new Exception(error); + } + if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) + { + settings.Code = code; + GenerateRefreshToken(settings); + return !string.IsNullOrEmpty(settings.AccessToken); + } + + return true; + } + + /// + /// Authorize via an embedded browser + /// If this works, return the code + /// + /// OAuth2Settings with the Auth / Token url etc + /// true if completed, false if canceled + private static bool AuthorizeViaEmbeddedBrowser(OAuth2Settings settings) { + if (string.IsNullOrEmpty(settings.CloudServiceName)) { + throw new ArgumentNullException(nameof(settings.CloudServiceName)); + } + if (settings.BrowserSize == Size.Empty) { + throw new ArgumentNullException(nameof(settings.BrowserSize)); + } + OAuthLoginForm loginForm = new OAuthLoginForm($"Authorize {settings.CloudServiceName}", settings.BrowserSize, settings.FormattedAuthUrl, settings.RedirectUrl); + loginForm.ShowDialog(); + if (!loginForm.IsOk) return false; + if (loginForm.CallbackParameters.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) { + settings.Code = code; + GenerateRefreshToken(settings); + return true; + } + return UpdateFromCallback(settings, loginForm.CallbackParameters); + } + + /// + /// Authorize via a local server by using the LocalServerCodeReceiver + /// If this works, return the code + /// + /// OAuth2Settings with the Auth / Token url etc + /// true if completed + private static bool AuthorizeViaLocalServer(OAuth2Settings settings) { + var codeReceiver = new LocalServerCodeReceiver(); + IDictionary result = codeReceiver.ReceiveCode(settings); + + if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) { + settings.Code = code; + GenerateRefreshToken(settings); + return true; + } + + if (result.TryGetValue("error", out var error)) { + if (result.TryGetValue("error_description", out var errorDescription)) { + throw new Exception(errorDescription); + } + if ("access_denied" == error) { + throw new UnauthorizedAccessException("Access denied"); + } + throw new Exception(error); + } + return false; + } + + /// + /// Simple helper to add the Authorization Bearer header + /// + /// WebRequest + /// OAuth2Settings + public static void AddOAuth2Credentials(HttpWebRequest webRequest, OAuth2Settings settings) { + if (!string.IsNullOrEmpty(settings.AccessToken)) { + webRequest.Headers.Add("Authorization", "Bearer " + settings.AccessToken); + } + } + + /// + /// Check and authenticate or refresh tokens + /// + /// OAuth2Settings + public static void CheckAndAuthenticateOrRefresh(OAuth2Settings settings) { + // Get Refresh / Access token + if (string.IsNullOrEmpty(settings.RefreshToken)) { + if (!Authorize(settings)) { + throw new Exception("Authentication cancelled"); + } + } + if (settings.IsAccessTokenExpired) { + GenerateAccessToken(settings); + // Get Refresh / Access token + if (string.IsNullOrEmpty(settings.RefreshToken)) { + if (!Authorize(settings)) { + throw new Exception("Authentication cancelled"); + } + GenerateAccessToken(settings); + } + } + if (settings.IsAccessTokenExpired) { + throw new Exception("Authentication failed"); + } + } + + /// + /// CreateWebRequest ready for OAuth 2 access + /// + /// HTTPMethod + /// + /// OAuth2Settings + /// HttpWebRequest + public static HttpWebRequest CreateOAuth2WebRequest(HTTPMethod method, string url, OAuth2Settings settings) { + CheckAndAuthenticateOrRefresh(settings); + + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, method); + AddOAuth2Credentials(webRequest, settings); + return webRequest; + } + } +} diff --git a/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs b/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs new file mode 100644 index 000000000..57b566aaa --- /dev/null +++ b/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs @@ -0,0 +1,181 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace GreenshotPlugin.Core.OAuth +{ + /// + /// Settings for the OAuth 2 protocol + /// + public class OAuth2Settings { + public OAuth2Settings() { + AdditionalAttributes = new Dictionary(); + // Create a default state + var state = Guid.NewGuid().ToString(); + // Only store a small part of the GUID + State = state.Substring(0, state.IndexOf('-')-1); + AuthorizeMode = OAuth2AuthorizeMode.Unknown; + } + + public OAuth2AuthorizeMode AuthorizeMode { + get; + set; + } + + /// + /// Specify the name of the cloud service, so it can be used in window titles, logs etc + /// + public string CloudServiceName { + get; + set; + } + + /// + /// Specify the size of the embedded Browser, if using this + /// + public Size BrowserSize { + get; + set; + } + + /// + /// The OAuth 2 client id + /// + public string ClientId { + get; + set; + } + + /// + /// The OAuth 2 client secret + /// + public string ClientSecret { + get; + set; + } + + /// + /// The OAuth 2 state, this is something that is passed to the server, is not processed but returned back to the client. + /// e.g. a correlation ID + /// Default this is filled with a new Guid + /// + public string State { + get; + set; + } + + /// + /// The authorization URL where the values of this class can be "injected" + /// + public string AuthUrlPattern { + get; + set; + } + + /// + /// Get formatted Auth url (this will call a FormatWith(this) on the AuthUrlPattern + /// + public string FormattedAuthUrl => AuthUrlPattern.FormatWith(this); + + /// + /// The URL to get a Token + /// + public string TokenUrl { + get; + set; + } + + /// + /// This is the redirect URL, in some implementations this is automatically set (LocalServerCodeReceiver) + /// In some implementations this could be e.g. urn:ietf:wg:oauth:2.0:oob or urn:ietf:wg:oauth:2.0:oob:auto + /// + public string RedirectUrl { + get; + set; + } + + /// + /// Bearer token for accessing OAuth 2 services + /// + public string AccessToken { + get; + set; + } + + /// + /// Expire time for the AccessToken, this this time (-60 seconds) is passed a new AccessToken needs to be generated with the RefreshToken + /// + public DateTimeOffset AccessTokenExpires { + get; + set; + } + + /// + /// Return true if the access token is expired. + /// Important "side-effect": if true is returned the AccessToken will be set to null! + /// + public bool IsAccessTokenExpired { + get { + if (AccessTokenExpires == default) + { + return false; + } + bool expired = true; + if (!string.IsNullOrEmpty(AccessToken)) { + expired = DateTimeOffset.Now.AddSeconds(60) > AccessTokenExpires; + } + // Make sure the token is not usable + if (expired) { + AccessToken = null; + } + return expired; + } + } + + /// + /// Token used to get a new Access Token + /// + public string RefreshToken { + get; + set; + } + + /// + /// Put anything in here which is needed for the OAuth 2 implementation of this specific service but isn't generic, e.g. for Google there is a "scope" + /// + public IDictionary AdditionalAttributes { + get; + set; + } + + /// + /// This contains the code returned from the authorization, but only shortly after it was received. + /// It will be cleared as soon as it was used. + /// + public string Code { + get; + set; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/OAuth/OAuthSession.cs b/GreenshotPlugin/Core/OAuth/OAuthSession.cs new file mode 100644 index 000000000..9a40c0b8d --- /dev/null +++ b/GreenshotPlugin/Core/OAuth/OAuthSession.cs @@ -0,0 +1,629 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.Net; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using GreenshotPlugin.Controls; +using log4net; + +namespace GreenshotPlugin.Core.OAuth +{ + /// + /// An OAuth 1 session object + /// + public class OAuthSession { + private static readonly ILog Log = LogManager.GetLogger(typeof(OAuthSession)); + protected const string OAUTH_VERSION = "1.0"; + protected const string OAUTH_PARAMETER_PREFIX = "oauth_"; + + // + // List of know and used oauth parameters' names + // + protected const string OAUTH_CONSUMER_KEY_KEY = "oauth_consumer_key"; + protected const string OAUTH_CALLBACK_KEY = "oauth_callback"; + protected const string OAUTH_VERSION_KEY = "oauth_version"; + protected const string OAUTH_SIGNATURE_METHOD_KEY = "oauth_signature_method"; + protected const string OAUTH_TIMESTAMP_KEY = "oauth_timestamp"; + protected const string OAUTH_NONCE_KEY = "oauth_nonce"; + protected const string OAUTH_TOKEN_KEY = "oauth_token"; + protected const string OAUTH_VERIFIER_KEY = "oauth_verifier"; + protected const string OAUTH_TOKEN_SECRET_KEY = "oauth_token_secret"; + protected const string OAUTH_SIGNATURE_KEY = "oauth_signature"; + + protected const string HMACSHA1SignatureType = "HMAC-SHA1"; + protected const string PlainTextSignatureType = "PLAINTEXT"; + + protected static Random random = new Random(); + + protected const string UnreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"; + + private string _userAgent = "Greenshot"; + private IDictionary _requestTokenResponseParameters; + + public IDictionary RequestTokenParameters { get; } = new Dictionary(); + + /// + /// Parameters of the last called getAccessToken + /// + public IDictionary AccessTokenResponseParameters { get; private set; } + + /// + /// Parameters of the last called getRequestToken + /// + public IDictionary RequestTokenResponseParameters => _requestTokenResponseParameters; + + private readonly string _consumerKey; + private readonly string _consumerSecret; + + // default _browser size + + public HTTPMethod RequestTokenMethod { + get; + set; + } + public HTTPMethod AccessTokenMethod { + get; + set; + } + public string RequestTokenUrl { + get; + set; + } + public string AuthorizeUrl { + get; + set; + } + public string AccessTokenUrl { + get; + set; + } + public string Token { + get; + set; + } + public string TokenSecret { + get; + set; + } + public string Verifier { + get; + set; + } + public OAuthSignatureTypes SignatureType { + get; + set; + } + + public bool UseMultipartFormData { get; set; } + public string UserAgent { + get { + return _userAgent; + } + set { + _userAgent = value; + } + } + public string CallbackUrl { get; set; } = "http://getgreenshot.org"; + + public bool CheckVerifier { get; set; } = true; + + public Size BrowserSize { get; set; } = new Size(864, 587); + + public string LoginTitle { get; set; } = "Authorize Greenshot access"; + + public bool UseHttpHeadersForAuthorization { get; set; } = true; + + public bool AutoLogin { + get; + set; + } + + /// + /// Create an OAuthSession with the consumerKey / consumerSecret + /// + /// "Public" key for the encoding. When using RSASHA1 this is the path to the private key file + /// "Private" key for the encoding. when usin RSASHA1 this is the password for the private key file + public OAuthSession(string consumerKey, string consumerSecret) { + _consumerKey = consumerKey; + _consumerSecret = consumerSecret; + UseMultipartFormData = true; + RequestTokenMethod = HTTPMethod.GET; + AccessTokenMethod = HTTPMethod.GET; + SignatureType = OAuthSignatureTypes.HMACSHA1; + AutoLogin = true; + } + + /// + /// Helper function to compute a hash value + /// + /// The hashing algorithm used. If that algorithm needs some initialization, like HMAC and its derivatives, they should be initialized prior to passing it to this function + /// The data to hash + /// a Base64 string of the hash value + private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) { + if (hashAlgorithm == null) { + throw new ArgumentNullException(nameof(hashAlgorithm)); + } + + if (string.IsNullOrEmpty(data)) { + throw new ArgumentNullException(nameof(data)); + } + + byte[] dataBuffer = Encoding.UTF8.GetBytes(data); + byte[] hashBytes = hashAlgorithm.ComputeHash(dataBuffer); + + return Convert.ToBase64String(hashBytes); + } + + /// + /// Generate the normalized paramter string + /// + /// the list of query parameters + /// a string with the normalized query parameters + private static string GenerateNormalizedParametersString(IDictionary queryParameters) { + if (queryParameters == null || queryParameters.Count == 0) { + return string.Empty; + } + + queryParameters = new SortedDictionary(queryParameters); + + StringBuilder sb = new StringBuilder(); + foreach (string key in queryParameters.Keys) { + if (queryParameters[key] is string) { + sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode3986($"{queryParameters[key]}")); + } + } + sb.Remove(sb.Length - 1, 1); + + return sb.ToString(); + } + + /// + /// This is a different Url Encode implementation since the default .NET one outputs the percent encoding in lower case. + /// While this is not a problem with the percent encoding spec, it is used in upper case throughout OAuth + /// The resulting string is for UTF-8 encoding! + /// + /// The value to Url encode + /// Returns a Url encoded string (unicode) with UTF-8 encoded % values + public static string UrlEncode3986(string value) { + StringBuilder result = new StringBuilder(); + + foreach (char symbol in value) { + if (UnreservedChars.IndexOf(symbol) != -1) { + result.Append(symbol); + } else { + byte[] utf8Bytes = Encoding.UTF8.GetBytes(symbol.ToString()); + foreach(byte utf8Byte in utf8Bytes) { + result.AppendFormat("%{0:X2}", utf8Byte); + } + } + } + + return result.ToString(); + } + + /// + /// Generate the timestamp for the signature + /// + /// + public static string GenerateTimeStamp() { + // Default implementation of UNIX time of the current UTC time + TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); + return Convert.ToInt64(ts.TotalSeconds).ToString(); + } + + /// + /// Generate a nonce + /// + /// + public static string GenerateNonce() { + // Just a simple implementation of a random number between 123400 and 9999999 + return random.Next(123400, 9999999).ToString(); + } + + /// + /// Get the request token using the consumer key and secret. Also initializes tokensecret + /// + /// response, this doesn't need to be used!! + private string GetRequestToken() { + IDictionary parameters = new Dictionary(); + foreach(var value in RequestTokenParameters) { + parameters.Add(value); + } + Sign(RequestTokenMethod, RequestTokenUrl, parameters); + string response = MakeRequest(RequestTokenMethod, RequestTokenUrl, null, parameters, null); + if (!string.IsNullOrEmpty(response)) { + response = NetworkHelper.UrlDecode(response); + Log.DebugFormat("Request token response: {0}", response); + _requestTokenResponseParameters = NetworkHelper.ParseQueryString(response); + if (_requestTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var value)) { + Token = value; + TokenSecret = _requestTokenResponseParameters[OAUTH_TOKEN_SECRET_KEY]; + } + } + return response; + } + + /// + /// Authorize the token by showing the dialog + /// + /// Pass the response from the server's request token, so if there is something wrong we can show it. + /// The request token. + private string GetAuthorizeToken(string requestTokenResponse) { + if (string.IsNullOrEmpty(Token)) { + Exception e = new Exception("The request token is not set, service responded with: " + requestTokenResponse); + throw e; + } + Log.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink); + OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(LoginTitle, BrowserSize, AuthorizationLink, CallbackUrl); + oAuthLoginForm.ShowDialog(); + if (oAuthLoginForm.IsOk) { + if (oAuthLoginForm.CallbackParameters != null) { + if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue)) { + Token = tokenValue; + } + + if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_VERIFIER_KEY, out var verifierValue)) { + Verifier = verifierValue; + } + } + } + if (CheckVerifier) { + if (!string.IsNullOrEmpty(Verifier)) { + return Token; + } + return null; + } + return Token; + } + + /// + /// Get the access token + /// + /// The access token. + private string GetAccessToken() { + if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) { + Exception e = new Exception("The request token and verifier were not set"); + throw e; + } + + IDictionary parameters = new Dictionary(); + Sign(AccessTokenMethod, AccessTokenUrl, parameters); + string response = MakeRequest(AccessTokenMethod, AccessTokenUrl, null, parameters, null); + if (!string.IsNullOrEmpty(response)) { + response = NetworkHelper.UrlDecode(response); + Log.DebugFormat("Access token response: {0}", response); + AccessTokenResponseParameters = NetworkHelper.ParseQueryString(response); + if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue) && tokenValue != null) { + Token = tokenValue; + } + + if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_SECRET_KEY, out var secretValue) && secretValue != null) { + TokenSecret = secretValue; + } + } + + return Token; + } + + /// + /// This method goes through the whole authorize process, including a Authorization window. + /// + /// true if the process is completed + public bool Authorize() { + Token = null; + TokenSecret = null; + Verifier = null; + Log.Debug("Creating Token"); + string requestTokenResponse; + try { + requestTokenResponse = GetRequestToken(); + } catch (Exception ex) { + Log.Error(ex); + throw new NotSupportedException("Service is not available: " + ex.Message); + } + if (string.IsNullOrEmpty(GetAuthorizeToken(requestTokenResponse))) { + Log.Debug("User didn't authenticate!"); + return false; + } + try { + Thread.Sleep(1000); + return GetAccessToken() != null; + } catch (Exception ex) { + Log.Error(ex); + throw; + } + } + + /// + /// Get the link to the authorization page for this application. + /// + /// The url with a valid request token, or a null string. + private string AuthorizationLink => AuthorizeUrl + "?" + OAUTH_TOKEN_KEY + "=" + Token + "&" + OAUTH_CALLBACK_KEY + "=" + UrlEncode3986(CallbackUrl); + + /// + /// Submit a web request using oAuth. + /// + /// GET or POST + /// The full url, including the querystring for the signing/request + /// Parameters for the request, which need to be signed + /// Parameters for the request, which do not need to be signed + /// Data to post (MemoryStream) + /// The web server response. + public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { + return MakeOAuthRequest(method, requestUrl, requestUrl, null, parametersToSign, additionalParameters, postData); + } + + /// + /// Submit a web request using oAuth. + /// + /// GET or POST + /// The full url, including the querystring for the signing/request + /// Header values + /// Parameters for the request, which need to be signed + /// Parameters for the request, which do not need to be signed + /// Data to post (MemoryStream) + /// The web server response. + public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { + return MakeOAuthRequest(method, requestUrl, requestUrl, headers, parametersToSign, additionalParameters, postData); + } + + /// + /// Submit a web request using oAuth. + /// + /// GET or POST + /// The full url, including the querystring for the signing + /// The full url, including the querystring for the request + /// Parameters for the request, which need to be signed + /// Parameters for the request, which do not need to be signed + /// Data to post (MemoryStream) + /// The web server response. + public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { + return MakeOAuthRequest(method, signUrl, requestUrl, null, parametersToSign, additionalParameters, postData); + } + + /// + /// Submit a web request using oAuth. + /// + /// GET or POST + /// The full url, including the querystring for the signing + /// The full url, including the querystring for the request + /// Headers for the request + /// Parameters for the request, which need to be signed + /// Parameters for the request, which do not need to be signed + /// Data to post (MemoryStream) + /// The web server response. + public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary headers, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { + if (parametersToSign == null) { + parametersToSign = new Dictionary(); + } + int retries = 2; + Exception lastException = null; + while (retries-- > 0) { + // If we are not trying to get a Authorization or Accestoken, and we don't have a token, create one + if (string.IsNullOrEmpty(Token)) { + if (!AutoLogin || !Authorize()) { + throw new Exception("Not authorized"); + } + } + try { + Sign(method, signUrl, parametersToSign); + + // Join all parameters + IDictionary newParameters = new Dictionary(); + foreach (var parameter in parametersToSign) { + newParameters.Add(parameter); + } + if (additionalParameters != null) { + foreach (var parameter in additionalParameters) { + newParameters.Add(parameter); + } + } + return MakeRequest(method, requestUrl, headers, newParameters, postData); + } catch (UnauthorizedAccessException uaEx) { + lastException = uaEx; + Token = null; + TokenSecret = null; + // Remove oauth keys, so they aren't added double + List keysToDelete = new List(); + foreach (string parameterKey in parametersToSign.Keys) + { + if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) + { + keysToDelete.Add(parameterKey); + } + } + foreach (string keyToDelete in keysToDelete) + { + parametersToSign.Remove(keyToDelete); + } + } + } + if (lastException != null) { + throw lastException; + } + throw new Exception("Not authorized"); + } + + /// + /// OAuth sign the parameters, meaning all oauth parameters are added to the supplied dictionary. + /// And additionally a signature is added. + /// + /// Method (POST,PUT,GET) + /// Url to call + /// IDictionary of string and string + private void Sign(HTTPMethod method, string requestUrl, IDictionary parameters) { + if (parameters == null) { + throw new ArgumentNullException(nameof(parameters)); + } + // Build the signature base + StringBuilder signatureBase = new StringBuilder(); + + // Add Method to signature base + signatureBase.Append(method).Append("&"); + + // Add normalized URL + Uri url = new Uri(requestUrl); + string normalizedUrl = string.Format(CultureInfo.InvariantCulture, "{0}://{1}", url.Scheme, url.Host); + if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) { + normalizedUrl += ":" + url.Port; + } + normalizedUrl += url.AbsolutePath; + signatureBase.Append(UrlEncode3986(normalizedUrl)).Append("&"); + + // Add normalized parameters + parameters.Add(OAUTH_VERSION_KEY, OAUTH_VERSION); + parameters.Add(OAUTH_NONCE_KEY, GenerateNonce()); + parameters.Add(OAUTH_TIMESTAMP_KEY, GenerateTimeStamp()); + switch(SignatureType) { + case OAuthSignatureTypes.PLAINTEXT: + parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, PlainTextSignatureType); + break; + default: + parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, HMACSHA1SignatureType); + break; + } + parameters.Add(OAUTH_CONSUMER_KEY_KEY, _consumerKey); + if (CallbackUrl != null && RequestTokenUrl != null && requestUrl.StartsWith(RequestTokenUrl)) { + parameters.Add(OAUTH_CALLBACK_KEY, CallbackUrl); + } + if (!string.IsNullOrEmpty(Verifier)) { + parameters.Add(OAUTH_VERIFIER_KEY, Verifier); + } + if (!string.IsNullOrEmpty(Token)) { + parameters.Add(OAUTH_TOKEN_KEY, Token); + } + signatureBase.Append(UrlEncode3986(GenerateNormalizedParametersString(parameters))); + Log.DebugFormat("Signature base: {0}", signatureBase); + string key = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", UrlEncode3986(_consumerSecret), string.IsNullOrEmpty(TokenSecret) ? string.Empty : UrlEncode3986(TokenSecret)); + switch (SignatureType) { + case OAuthSignatureTypes.PLAINTEXT: + parameters.Add(OAUTH_SIGNATURE_KEY, key); + break; + default: + // Generate Signature and add it to the parameters + HMACSHA1 hmacsha1 = new HMACSHA1 {Key = Encoding.UTF8.GetBytes(key)}; + string signature = ComputeHash(hmacsha1, signatureBase.ToString()); + parameters.Add(OAUTH_SIGNATURE_KEY, signature); + break; + } + } + + /// + /// Make the actual OAuth request, all oauth parameters are passed as header (default) and the others are placed in the url or post data. + /// Any additional parameters added after the Sign call are not in the signature, this could be by design! + /// + /// + /// + /// + /// + /// IBinaryParameter + /// Response from server + private string MakeRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parameters, IBinaryContainer postData) { + if (parameters == null) { + throw new ArgumentNullException(nameof(parameters)); + } + IDictionary requestParameters; + // Add oAuth values as HTTP headers, if this is allowed + StringBuilder authHeader = null; + if (UseHttpHeadersForAuthorization) { + authHeader = new StringBuilder(); + requestParameters = new Dictionary(); + foreach (string parameterKey in parameters.Keys) { + if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) { + authHeader.AppendFormat(CultureInfo.InvariantCulture, "{0}=\"{1}\", ", parameterKey, UrlEncode3986($"{parameters[parameterKey]}")); + } else if (!requestParameters.ContainsKey(parameterKey)) { + requestParameters.Add(parameterKey, parameters[parameterKey]); + } + } + // Remove trailing comma and space and add it to the headers + if (authHeader.Length > 0) { + authHeader.Remove(authHeader.Length - 2, 2); + } + } else { + requestParameters = parameters; + } + + if (HTTPMethod.GET == method || postData != null) { + if (requestParameters.Count > 0) { + // Add the parameters to the request + requestUrl += "?" + NetworkHelper.GenerateQueryParameters(requestParameters); + } + } + // Create webrequest + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(requestUrl, method); + webRequest.ServicePoint.Expect100Continue = false; + webRequest.UserAgent = _userAgent; + + if (UseHttpHeadersForAuthorization && authHeader != null) { + Log.DebugFormat("Authorization: OAuth {0}", authHeader); + webRequest.Headers.Add("Authorization: OAuth " + authHeader); + } + + if (headers != null) { + foreach(string key in headers.Keys) { + webRequest.Headers.Add(key, headers[key]); + } + } + + if ((HTTPMethod.POST == method || HTTPMethod.PUT == method) && postData == null && requestParameters.Count > 0) { + if (UseMultipartFormData) { + NetworkHelper.WriteMultipartFormData(webRequest, requestParameters); + } else { + StringBuilder form = new StringBuilder(); + foreach (string parameterKey in requestParameters.Keys) + { + var binaryParameter = parameters[parameterKey] as IBinaryContainer; + form.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), binaryParameter != null ? UrlEncode3986(binaryParameter.ToBase64String(Base64FormattingOptions.None)) : UrlEncode3986($"{parameters[parameterKey]}")); + } + // Remove trailing & + if (form.Length > 0) { + form.Remove(form.Length - 1, 1); + } + webRequest.ContentType = "application/x-www-form-urlencoded"; + byte[] data = Encoding.UTF8.GetBytes(form.ToString()); + using var requestStream = webRequest.GetRequestStream(); + requestStream.Write(data, 0, data.Length); + } + } else if (postData != null) { + postData.Upload(webRequest); + } else { + webRequest.ContentLength = 0; + } + + string responseData; + try { + responseData = NetworkHelper.GetResponseAsString(webRequest); + Log.DebugFormat("Response: {0}", responseData); + } catch (Exception ex) { + Log.Error("Couldn't retrieve response: ", ex); + throw; + } + + return responseData; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs b/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs new file mode 100644 index 000000000..af2bfc710 --- /dev/null +++ b/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs @@ -0,0 +1,31 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace GreenshotPlugin.Core.OAuth +{ + /// + /// Provides a predefined set of algorithms that are supported officially by the OAuth 1.x protocol + /// + public enum OAuthSignatureTypes { + HMACSHA1, + PLAINTEXT, + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/OAuthHelper.cs b/GreenshotPlugin/Core/OAuthHelper.cs deleted file mode 100644 index 352934ef8..000000000 --- a/GreenshotPlugin/Core/OAuthHelper.cs +++ /dev/null @@ -1,1253 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.Controls; -using log4net; -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Diagnostics; -using System.Drawing; -using System.Globalization; -using System.Net; -using System.Net.Sockets; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using System.Windows.Forms; -using GreenshotPlugin.Hooking; - -namespace GreenshotPlugin.Core { - /// - /// Provides a predefined set of algorithms that are supported officially by the OAuth 1.x protocol - /// - public enum OAuthSignatureTypes { - HMACSHA1, - PLAINTEXT, - } - - /// - /// Specify the authorize mode that is used to get the token from the cloud service. - /// - public enum OAuth2AuthorizeMode { - Unknown, // Will give an exception, caller needs to specify another value - LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener - EmbeddedBrowser, // Will open into an embedded _browser (OAuthLoginForm), and catch the redirect - OutOfBoundAuto - } - - /// - /// Settings for the OAuth 2 protocol - /// - public class OAuth2Settings { - public OAuth2Settings() { - AdditionalAttributes = new Dictionary(); - // Create a default state - State = Guid.NewGuid().ToString(); - AuthorizeMode = OAuth2AuthorizeMode.Unknown; - } - - public OAuth2AuthorizeMode AuthorizeMode { - get; - set; - } - - /// - /// Specify the name of the cloud service, so it can be used in window titles, logs etc - /// - public string CloudServiceName { - get; - set; - } - - /// - /// Specify the size of the embedded Browser, if using this - /// - public Size BrowserSize { - get; - set; - } - - /// - /// The OAuth 2 client id - /// - public string ClientId { - get; - set; - } - - /// - /// The OAuth 2 client secret - /// - public string ClientSecret { - get; - set; - } - - /// - /// The OAuth 2 state, this is something that is passed to the server, is not processed but returned back to the client. - /// e.g. a correlation ID - /// Default this is filled with a new Guid - /// - public string State { - get; - set; - } - - /// - /// The autorization URL where the values of this class can be "injected" - /// - public string AuthUrlPattern { - get; - set; - } - - /// - /// Get formatted Auth url (this will call a FormatWith(this) on the AuthUrlPattern - /// - public string FormattedAuthUrl => AuthUrlPattern.FormatWith(this); - - /// - /// The URL to get a Token - /// - public string TokenUrl { - get; - set; - } - - /// - /// This is the redirect URL, in some implementations this is automatically set (LocalServerCodeReceiver) - /// In some implementations this could be e.g. urn:ietf:wg:oauth:2.0:oob or urn:ietf:wg:oauth:2.0:oob:auto - /// - public string RedirectUrl { - get; - set; - } - - /// - /// Bearer token for accessing OAuth 2 services - /// - public string AccessToken { - get; - set; - } - - /// - /// Expire time for the AccessToken, this this time (-60 seconds) is passed a new AccessToken needs to be generated with the RefreshToken - /// - public DateTimeOffset AccessTokenExpires { - get; - set; - } - - /// - /// Return true if the access token is expired. - /// Important "side-effect": if true is returned the AccessToken will be set to null! - /// - public bool IsAccessTokenExpired { - get { - bool expired = true; - if (!string.IsNullOrEmpty(AccessToken)) { - expired = DateTimeOffset.Now.AddSeconds(60) > AccessTokenExpires; - } - // Make sure the token is not usable - if (expired) { - AccessToken = null; - } - return expired; - } - } - - /// - /// Token used to get a new Access Token - /// - public string RefreshToken { - get; - set; - } - - /// - /// Put anything in here which is needed for the OAuth 2 implementation of this specific service but isn't generic, e.g. for Google there is a "scope" - /// - public IDictionary AdditionalAttributes { - get; - set; - } - - /// - /// This contains the code returned from the authorization, but only shortly after it was received. - /// It will be cleared as soon as it was used. - /// - public string Code { - get; - set; - } - } - - /// - /// An OAuth 1 session object - /// - public class OAuthSession { - private static readonly ILog Log = LogManager.GetLogger(typeof(OAuthSession)); - protected const string OAUTH_VERSION = "1.0"; - protected const string OAUTH_PARAMETER_PREFIX = "oauth_"; - - // - // List of know and used oauth parameters' names - // - protected const string OAUTH_CONSUMER_KEY_KEY = "oauth_consumer_key"; - protected const string OAUTH_CALLBACK_KEY = "oauth_callback"; - protected const string OAUTH_VERSION_KEY = "oauth_version"; - protected const string OAUTH_SIGNATURE_METHOD_KEY = "oauth_signature_method"; - protected const string OAUTH_TIMESTAMP_KEY = "oauth_timestamp"; - protected const string OAUTH_NONCE_KEY = "oauth_nonce"; - protected const string OAUTH_TOKEN_KEY = "oauth_token"; - protected const string OAUTH_VERIFIER_KEY = "oauth_verifier"; - protected const string OAUTH_TOKEN_SECRET_KEY = "oauth_token_secret"; - protected const string OAUTH_SIGNATURE_KEY = "oauth_signature"; - - protected const string HMACSHA1SignatureType = "HMAC-SHA1"; - protected const string PlainTextSignatureType = "PLAINTEXT"; - - protected static Random random = new Random(); - - protected const string UnreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~"; - - private string _userAgent = "Greenshot"; - private IDictionary _requestTokenResponseParameters; - - public IDictionary RequestTokenParameters { get; } = new Dictionary(); - - /// - /// Parameters of the last called getAccessToken - /// - public IDictionary AccessTokenResponseParameters { get; private set; } - - /// - /// Parameters of the last called getRequestToken - /// - public IDictionary RequestTokenResponseParameters => _requestTokenResponseParameters; - - private readonly string _consumerKey; - private readonly string _consumerSecret; - - // default _browser size - - public HTTPMethod RequestTokenMethod { - get; - set; - } - public HTTPMethod AccessTokenMethod { - get; - set; - } - public string RequestTokenUrl { - get; - set; - } - public string AuthorizeUrl { - get; - set; - } - public string AccessTokenUrl { - get; - set; - } - public string Token { - get; - set; - } - public string TokenSecret { - get; - set; - } - public string Verifier { - get; - set; - } - public OAuthSignatureTypes SignatureType { - get; - set; - } - - public bool UseMultipartFormData { get; set; } - public string UserAgent { - get { - return _userAgent; - } - set { - _userAgent = value; - } - } - public string CallbackUrl { get; set; } = "http://getgreenshot.org"; - - public bool CheckVerifier { get; set; } = true; - - public Size BrowserSize { get; set; } = new Size(864, 587); - - public string LoginTitle { get; set; } = "Authorize Greenshot access"; - - public bool UseHttpHeadersForAuthorization { get; set; } = true; - - public bool AutoLogin { - get; - set; - } - - /// - /// Create an OAuthSession with the consumerKey / consumerSecret - /// - /// "Public" key for the encoding. When using RSASHA1 this is the path to the private key file - /// "Private" key for the encoding. when usin RSASHA1 this is the password for the private key file - public OAuthSession(string consumerKey, string consumerSecret) { - _consumerKey = consumerKey; - _consumerSecret = consumerSecret; - UseMultipartFormData = true; - RequestTokenMethod = HTTPMethod.GET; - AccessTokenMethod = HTTPMethod.GET; - SignatureType = OAuthSignatureTypes.HMACSHA1; - AutoLogin = true; - } - - /// - /// Helper function to compute a hash value - /// - /// The hashing algorithm used. If that algorithm needs some initialization, like HMAC and its derivatives, they should be initialized prior to passing it to this function - /// The data to hash - /// a Base64 string of the hash value - private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) { - if (hashAlgorithm == null) { - throw new ArgumentNullException(nameof(hashAlgorithm)); - } - - if (string.IsNullOrEmpty(data)) { - throw new ArgumentNullException(nameof(data)); - } - - byte[] dataBuffer = Encoding.UTF8.GetBytes(data); - byte[] hashBytes = hashAlgorithm.ComputeHash(dataBuffer); - - return Convert.ToBase64String(hashBytes); - } - - /// - /// Generate the normalized paramter string - /// - /// the list of query parameters - /// a string with the normalized query parameters - private static string GenerateNormalizedParametersString(IDictionary queryParameters) { - if (queryParameters == null || queryParameters.Count == 0) { - return string.Empty; - } - - queryParameters = new SortedDictionary(queryParameters); - - StringBuilder sb = new StringBuilder(); - foreach (string key in queryParameters.Keys) { - if (queryParameters[key] is string) { - sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode3986($"{queryParameters[key]}")); - } - } - sb.Remove(sb.Length - 1, 1); - - return sb.ToString(); - } - - /// - /// This is a different Url Encode implementation since the default .NET one outputs the percent encoding in lower case. - /// While this is not a problem with the percent encoding spec, it is used in upper case throughout OAuth - /// The resulting string is for UTF-8 encoding! - /// - /// The value to Url encode - /// Returns a Url encoded string (unicode) with UTF-8 encoded % values - public static string UrlEncode3986(string value) { - StringBuilder result = new StringBuilder(); - - foreach (char symbol in value) { - if (UnreservedChars.IndexOf(symbol) != -1) { - result.Append(symbol); - } else { - byte[] utf8Bytes = Encoding.UTF8.GetBytes(symbol.ToString()); - foreach(byte utf8Byte in utf8Bytes) { - result.AppendFormat("%{0:X2}", utf8Byte); - } - } - } - - return result.ToString(); - } - - /// - /// Generate the timestamp for the signature - /// - /// - public static string GenerateTimeStamp() { - // Default implementation of UNIX time of the current UTC time - TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); - return Convert.ToInt64(ts.TotalSeconds).ToString(); - } - - /// - /// Generate a nonce - /// - /// - public static string GenerateNonce() { - // Just a simple implementation of a random number between 123400 and 9999999 - return random.Next(123400, 9999999).ToString(); - } - - /// - /// Get the request token using the consumer key and secret. Also initializes tokensecret - /// - /// response, this doesn't need to be used!! - private string GetRequestToken() { - IDictionary parameters = new Dictionary(); - foreach(var value in RequestTokenParameters) { - parameters.Add(value); - } - Sign(RequestTokenMethod, RequestTokenUrl, parameters); - string response = MakeRequest(RequestTokenMethod, RequestTokenUrl, null, parameters, null); - if (!string.IsNullOrEmpty(response)) { - response = NetworkHelper.UrlDecode(response); - Log.DebugFormat("Request token response: {0}", response); - _requestTokenResponseParameters = NetworkHelper.ParseQueryString(response); - if (_requestTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var value)) { - Token = value; - TokenSecret = _requestTokenResponseParameters[OAUTH_TOKEN_SECRET_KEY]; - } - } - return response; - } - - /// - /// Authorize the token by showing the dialog - /// - /// Pass the response from the server's request token, so if there is something wrong we can show it. - /// The request token. - private string GetAuthorizeToken(string requestTokenResponse) { - if (string.IsNullOrEmpty(Token)) { - Exception e = new Exception("The request token is not set, service responded with: " + requestTokenResponse); - throw e; - } - Log.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink); - OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(LoginTitle, BrowserSize, AuthorizationLink, CallbackUrl); - oAuthLoginForm.ShowDialog(); - if (oAuthLoginForm.IsOk) { - if (oAuthLoginForm.CallbackParameters != null) { - if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue)) { - Token = tokenValue; - } - - if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_VERIFIER_KEY, out var verifierValue)) { - Verifier = verifierValue; - } - } - } - if (CheckVerifier) { - if (!string.IsNullOrEmpty(Verifier)) { - return Token; - } - return null; - } - return Token; - } - - /// - /// Get the access token - /// - /// The access token. - private string GetAccessToken() { - if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) { - Exception e = new Exception("The request token and verifier were not set"); - throw e; - } - - IDictionary parameters = new Dictionary(); - Sign(AccessTokenMethod, AccessTokenUrl, parameters); - string response = MakeRequest(AccessTokenMethod, AccessTokenUrl, null, parameters, null); - if (!string.IsNullOrEmpty(response)) { - response = NetworkHelper.UrlDecode(response); - Log.DebugFormat("Access token response: {0}", response); - AccessTokenResponseParameters = NetworkHelper.ParseQueryString(response); - if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue) && tokenValue != null) { - Token = tokenValue; - } - - if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_SECRET_KEY, out var secretValue) && secretValue != null) { - TokenSecret = secretValue; - } - } - - return Token; - } - - /// - /// This method goes through the whole authorize process, including a Authorization window. - /// - /// true if the process is completed - public bool Authorize() { - Token = null; - TokenSecret = null; - Verifier = null; - Log.Debug("Creating Token"); - string requestTokenResponse; - try { - requestTokenResponse = GetRequestToken(); - } catch (Exception ex) { - Log.Error(ex); - throw new NotSupportedException("Service is not available: " + ex.Message); - } - if (string.IsNullOrEmpty(GetAuthorizeToken(requestTokenResponse))) { - Log.Debug("User didn't authenticate!"); - return false; - } - try { - Thread.Sleep(1000); - return GetAccessToken() != null; - } catch (Exception ex) { - Log.Error(ex); - throw; - } - } - - /// - /// Get the link to the authorization page for this application. - /// - /// The url with a valid request token, or a null string. - private string AuthorizationLink => AuthorizeUrl + "?" + OAUTH_TOKEN_KEY + "=" + Token + "&" + OAUTH_CALLBACK_KEY + "=" + UrlEncode3986(CallbackUrl); - - /// - /// Submit a web request using oAuth. - /// - /// GET or POST - /// The full url, including the querystring for the signing/request - /// Parameters for the request, which need to be signed - /// Parameters for the request, which do not need to be signed - /// Data to post (MemoryStream) - /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { - return MakeOAuthRequest(method, requestUrl, requestUrl, null, parametersToSign, additionalParameters, postData); - } - - /// - /// Submit a web request using oAuth. - /// - /// GET or POST - /// The full url, including the querystring for the signing - /// The full url, including the querystring for the request - /// Parameters for the request, which need to be signed - /// Parameters for the request, which do not need to be signed - /// Data to post (MemoryStream) - /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { - return MakeOAuthRequest(method, signUrl, requestUrl, null, parametersToSign, additionalParameters, postData); - } - - /// - /// Submit a web request using oAuth. - /// - /// GET or POST - /// The full url, including the querystring for the signing - /// The full url, including the querystring for the request - /// Headers for the request - /// Parameters for the request, which need to be signed - /// Parameters for the request, which do not need to be signed - /// Data to post (MemoryStream) - /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary headers, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { - if (parametersToSign == null) { - parametersToSign = new Dictionary(); - } - int retries = 2; - Exception lastException = null; - while (retries-- > 0) { - // If we are not trying to get a Authorization or Accestoken, and we don't have a token, create one - if (string.IsNullOrEmpty(Token)) { - if (!AutoLogin || !Authorize()) { - throw new Exception("Not authorized"); - } - } - try { - Sign(method, signUrl, parametersToSign); - - // Join all parameters - IDictionary newParameters = new Dictionary(); - foreach (var parameter in parametersToSign) { - newParameters.Add(parameter); - } - if (additionalParameters != null) { - foreach (var parameter in additionalParameters) { - newParameters.Add(parameter); - } - } - return MakeRequest(method, requestUrl, headers, newParameters, postData); - } catch (UnauthorizedAccessException uaEx) { - lastException = uaEx; - Token = null; - TokenSecret = null; - // Remove oauth keys, so they aren't added double - List keysToDelete = new List(); - foreach (string parameterKey in parametersToSign.Keys) - { - if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) - { - keysToDelete.Add(parameterKey); - } - } - foreach (string keyToDelete in keysToDelete) - { - parametersToSign.Remove(keyToDelete); - } - } - } - if (lastException != null) { - throw lastException; - } - throw new Exception("Not authorized"); - } - - /// - /// OAuth sign the parameters, meaning all oauth parameters are added to the supplied dictionary. - /// And additionally a signature is added. - /// - /// Method (POST,PUT,GET) - /// Url to call - /// IDictionary of string and string - private void Sign(HTTPMethod method, string requestUrl, IDictionary parameters) { - if (parameters == null) { - throw new ArgumentNullException(nameof(parameters)); - } - // Build the signature base - StringBuilder signatureBase = new StringBuilder(); - - // Add Method to signature base - signatureBase.Append(method).Append("&"); - - // Add normalized URL - Uri url = new Uri(requestUrl); - string normalizedUrl = string.Format(CultureInfo.InvariantCulture, "{0}://{1}", url.Scheme, url.Host); - if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) { - normalizedUrl += ":" + url.Port; - } - normalizedUrl += url.AbsolutePath; - signatureBase.Append(UrlEncode3986(normalizedUrl)).Append("&"); - - // Add normalized parameters - parameters.Add(OAUTH_VERSION_KEY, OAUTH_VERSION); - parameters.Add(OAUTH_NONCE_KEY, GenerateNonce()); - parameters.Add(OAUTH_TIMESTAMP_KEY, GenerateTimeStamp()); - switch(SignatureType) { - case OAuthSignatureTypes.PLAINTEXT: - parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, PlainTextSignatureType); - break; - default: - parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, HMACSHA1SignatureType); - break; - } - parameters.Add(OAUTH_CONSUMER_KEY_KEY, _consumerKey); - if (CallbackUrl != null && RequestTokenUrl != null && requestUrl.StartsWith(RequestTokenUrl)) { - parameters.Add(OAUTH_CALLBACK_KEY, CallbackUrl); - } - if (!string.IsNullOrEmpty(Verifier)) { - parameters.Add(OAUTH_VERIFIER_KEY, Verifier); - } - if (!string.IsNullOrEmpty(Token)) { - parameters.Add(OAUTH_TOKEN_KEY, Token); - } - signatureBase.Append(UrlEncode3986(GenerateNormalizedParametersString(parameters))); - Log.DebugFormat("Signature base: {0}", signatureBase); - string key = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", UrlEncode3986(_consumerSecret), string.IsNullOrEmpty(TokenSecret) ? string.Empty : UrlEncode3986(TokenSecret)); - switch (SignatureType) { - case OAuthSignatureTypes.PLAINTEXT: - parameters.Add(OAUTH_SIGNATURE_KEY, key); - break; - default: - // Generate Signature and add it to the parameters - HMACSHA1 hmacsha1 = new HMACSHA1 {Key = Encoding.UTF8.GetBytes(key)}; - string signature = ComputeHash(hmacsha1, signatureBase.ToString()); - parameters.Add(OAUTH_SIGNATURE_KEY, signature); - break; - } - } - - /// - /// Make the actual OAuth request, all oauth parameters are passed as header (default) and the others are placed in the url or post data. - /// Any additional parameters added after the Sign call are not in the signature, this could be by design! - /// - /// - /// - /// - /// - /// IBinaryParameter - /// Response from server - private string MakeRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parameters, IBinaryContainer postData) { - if (parameters == null) { - throw new ArgumentNullException(nameof(parameters)); - } - IDictionary requestParameters; - // Add oAuth values as HTTP headers, if this is allowed - StringBuilder authHeader = null; - if (UseHttpHeadersForAuthorization) { - authHeader = new StringBuilder(); - requestParameters = new Dictionary(); - foreach (string parameterKey in parameters.Keys) { - if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) { - authHeader.AppendFormat(CultureInfo.InvariantCulture, "{0}=\"{1}\", ", parameterKey, UrlEncode3986($"{parameters[parameterKey]}")); - } else if (!requestParameters.ContainsKey(parameterKey)) { - requestParameters.Add(parameterKey, parameters[parameterKey]); - } - } - // Remove trailing comma and space and add it to the headers - if (authHeader.Length > 0) { - authHeader.Remove(authHeader.Length - 2, 2); - } - } else { - requestParameters = parameters; - } - - if (HTTPMethod.GET == method || postData != null) { - if (requestParameters.Count > 0) { - // Add the parameters to the request - requestUrl += "?" + NetworkHelper.GenerateQueryParameters(requestParameters); - } - } - // Create webrequest - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(requestUrl, method); - webRequest.ServicePoint.Expect100Continue = false; - webRequest.UserAgent = _userAgent; - - if (UseHttpHeadersForAuthorization && authHeader != null) { - Log.DebugFormat("Authorization: OAuth {0}", authHeader); - webRequest.Headers.Add("Authorization: OAuth " + authHeader); - } - - if (headers != null) { - foreach(string key in headers.Keys) { - webRequest.Headers.Add(key, headers[key]); - } - } - - if ((HTTPMethod.POST == method || HTTPMethod.PUT == method) && postData == null && requestParameters.Count > 0) { - if (UseMultipartFormData) { - NetworkHelper.WriteMultipartFormData(webRequest, requestParameters); - } else { - StringBuilder form = new StringBuilder(); - foreach (string parameterKey in requestParameters.Keys) - { - var binaryParameter = parameters[parameterKey] as IBinaryContainer; - form.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), binaryParameter != null ? UrlEncode3986(binaryParameter.ToBase64String(Base64FormattingOptions.None)) : UrlEncode3986($"{parameters[parameterKey]}")); - } - // Remove trailing & - if (form.Length > 0) { - form.Remove(form.Length - 1, 1); - } - webRequest.ContentType = "application/x-www-form-urlencoded"; - byte[] data = Encoding.UTF8.GetBytes(form.ToString()); - using var requestStream = webRequest.GetRequestStream(); - requestStream.Write(data, 0, data.Length); - } - } else if (postData != null) { - postData.Upload(webRequest); - } else { - webRequest.ContentLength = 0; - } - - string responseData; - try { - responseData = NetworkHelper.GetResponseAsString(webRequest); - Log.DebugFormat("Response: {0}", responseData); - } catch (Exception ex) { - Log.Error("Couldn't retrieve response: ", ex); - throw; - } - - return responseData; - } - } - - /// - /// OAuth 2.0 verification code receiver that runs a local server on a free port - /// and waits for a call with the authorization verification code. - /// - public class LocalServerCodeReceiver { - private static readonly ILog Log = LogManager.GetLogger(typeof(LocalServerCodeReceiver)); - private readonly ManualResetEvent _ready = new ManualResetEvent(true); - - /// - /// The call back format. Expects one port parameter. - /// Default: http://localhost:{0}/authorize/ - /// - public string LoopbackCallbackUrl { get; set; } = "http://localhost:{0}/authorize/"; - - /// - /// HTML code to to return the _browser, default it will try to close the _browser / tab, this won't always work. - /// You can use CloudServiceName where you want to show the CloudServiceName from your OAuth2 settings - /// - public string ClosePageResponse { get; set; } = @" -OAuth 2.0 Authentication CloudServiceName - -Greenshot received information from CloudServiceName. You can close this browser / tab if it is not closed itself... - - -"; - - private string _redirectUri; - /// - /// The URL to redirect to - /// - protected string RedirectUri { - get { - if (!string.IsNullOrEmpty(_redirectUri)) { - return _redirectUri; - } - - return _redirectUri = string.Format(LoopbackCallbackUrl, GetRandomUnusedPort()); - } - } - - private string _cloudServiceName; - - private readonly IDictionary _returnValues = new Dictionary(); - - - /// - /// The OAuth code receiver - /// - /// - /// Dictionary with values - public IDictionary ReceiveCode(OAuth2Settings oauth2Settings) { - // Set the redirect URL on the settings - oauth2Settings.RedirectUrl = RedirectUri; - _cloudServiceName = oauth2Settings.CloudServiceName; - using (var listener = new HttpListener()) { - listener.Prefixes.Add(oauth2Settings.RedirectUrl); - try { - listener.Start(); - - // Get the formatted FormattedAuthUrl - string authorizationUrl = oauth2Settings.FormattedAuthUrl; - Log.DebugFormat("Open a browser with: {0}", authorizationUrl); - Process.Start(authorizationUrl); - - // Wait to get the authorization code response. - var context = listener.BeginGetContext(ListenerCallback, listener); - _ready.Reset(); - - while (!context.AsyncWaitHandle.WaitOne(1000, true)) { - Log.Debug("Waiting for response"); - } - } catch (Exception) { - // Make sure we can clean up, also if the thead is aborted - _ready.Set(); - throw; - } finally { - _ready.WaitOne(); - listener.Close(); - } - } - return _returnValues; - } - - /// - /// Handle a connection async, this allows us to break the waiting - /// - /// IAsyncResult - private void ListenerCallback(IAsyncResult result) { - HttpListener listener = (HttpListener)result.AsyncState; - - //If not listening return immediately as this method is called one last time after Close() - if (!listener.IsListening) { - return; - } - - // Use EndGetContext to complete the asynchronous operation. - HttpListenerContext context = listener.EndGetContext(result); - - - // Handle request - HttpListenerRequest request = context.Request; - try { - NameValueCollection nameValueCollection = request.QueryString; - - // Get response object. - using (HttpListenerResponse response = context.Response) { - // Write a "close" response. - byte[] buffer = Encoding.UTF8.GetBytes(ClosePageResponse.Replace("CloudServiceName", _cloudServiceName)); - // Write to response stream. - response.ContentLength64 = buffer.Length; - using var stream = response.OutputStream; - stream.Write(buffer, 0, buffer.Length); - } - - // Create a new response URL with a dictionary that contains all the response query parameters. - foreach (var name in nameValueCollection.AllKeys) { - if (!_returnValues.ContainsKey(name)) { - _returnValues.Add(name, nameValueCollection[name]); - } - } - } catch (Exception) { - context.Response.OutputStream.Close(); - throw; - } - _ready.Set(); - } - - /// - /// Returns a random, unused port. - /// - /// port to use - private static int GetRandomUnusedPort() { - var listener = new TcpListener(IPAddress.Loopback, 0); - try { - listener.Start(); - return ((IPEndPoint)listener.LocalEndpoint).Port; - } finally { - listener.Stop(); - } - } - } - - /// - /// Code to simplify OAuth 2 - /// - public static class OAuth2Helper { - private const string RefreshToken = "refresh_token"; - private const string AccessToken = "access_token"; - private const string Code = "code"; - private const string ClientId = "client_id"; - private const string ClientSecret = "client_secret"; - private const string GrantType = "grant_type"; - private const string AuthorizationCode = "authorization_code"; - private const string RedirectUri = "redirect_uri"; - private const string ExpiresIn = "expires_in"; - - /// - /// Generate an OAuth 2 Token by using the supplied code - /// - /// OAuth2Settings to update with the information that was retrieved - public static void GenerateRefreshToken(OAuth2Settings settings) { - IDictionary data = new Dictionary - { - // Use the returned code to get a refresh code - { Code, settings.Code }, - { ClientId, settings.ClientId }, - { RedirectUri, settings.RedirectUrl }, - { ClientSecret, settings.ClientSecret }, - { GrantType, AuthorizationCode } - }; - foreach (string key in settings.AdditionalAttributes.Keys) { - data.Add(key, settings.AdditionalAttributes[key]); - } - - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); - NetworkHelper.UploadFormUrlEncoded(webRequest, data); - string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); - - IDictionary refreshTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); - if (refreshTokenResult.ContainsKey("error")) - { - if (refreshTokenResult.ContainsKey("error_description")) { - throw new Exception($"{refreshTokenResult["error"]} - {refreshTokenResult["error_description"]}"); - } - throw new Exception((string)refreshTokenResult["error"]); - } - - // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp - // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", - // "expires_in":3920, - // "token_type":"Bearer", - // "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" - if (refreshTokenResult.ContainsKey(AccessToken)) - { - settings.AccessToken = (string)refreshTokenResult[AccessToken]; - } - if (refreshTokenResult.ContainsKey(RefreshToken)) - { - settings.RefreshToken = (string)refreshTokenResult[RefreshToken]; - } - if (refreshTokenResult.ContainsKey(ExpiresIn)) - { - object seconds = refreshTokenResult[ExpiresIn]; - if (seconds != null) - { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double)seconds); - } - } - settings.Code = null; - } - - /// - /// Used to update the settings with the callback information - /// - /// OAuth2Settings - /// IDictionary - /// true if the access token is already in the callback - private static bool UpdateFromCallback(OAuth2Settings settings, IDictionary callbackParameters) - { - if (!callbackParameters.ContainsKey(AccessToken)) - { - return false; - } - if (callbackParameters.ContainsKey(RefreshToken)) - { - // Refresh the refresh token :) - settings.RefreshToken = callbackParameters[RefreshToken]; - } - if (callbackParameters.ContainsKey(ExpiresIn)) - { - var expiresIn = callbackParameters[ExpiresIn]; - settings.AccessTokenExpires = DateTimeOffset.MaxValue; - if (expiresIn != null) - { - if (double.TryParse(expiresIn, out var seconds)) - { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); - } - } - } - settings.AccessToken = callbackParameters[AccessToken]; - return true; - } - - /// - /// Go out and retrieve a new access token via refresh-token with the TokenUrl in the settings - /// Will upate the access token, refresh token, expire date - /// - /// - public static void GenerateAccessToken(OAuth2Settings settings) { - IDictionary data = new Dictionary - { - { RefreshToken, settings.RefreshToken }, - { ClientId, settings.ClientId }, - { ClientSecret, settings.ClientSecret }, - { GrantType, RefreshToken } - }; - foreach (string key in settings.AdditionalAttributes.Keys) { - data.Add(key, settings.AdditionalAttributes[key]); - } - - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); - NetworkHelper.UploadFormUrlEncoded(webRequest, data); - string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); - - // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp - // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", - // "expires_in":3920, - // "token_type":"Bearer", - - IDictionary accessTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); - if (accessTokenResult.ContainsKey("error")) { - if ("invalid_grant" == (string)accessTokenResult["error"]) { - // Refresh token has also expired, we need a new one! - settings.RefreshToken = null; - settings.AccessToken = null; - settings.AccessTokenExpires = DateTimeOffset.MinValue; - settings.Code = null; - return; - } else { - if (accessTokenResult.ContainsKey("error_description")) { - throw new Exception($"{accessTokenResult["error"]} - {accessTokenResult["error_description"]}"); - } else { - throw new Exception((string)accessTokenResult["error"]); - } - } - } - - if (accessTokenResult.ContainsKey(AccessToken)) - { - settings.AccessToken = (string) accessTokenResult[AccessToken]; - settings.AccessTokenExpires = DateTimeOffset.MaxValue; - } - if (accessTokenResult.ContainsKey(RefreshToken)) { - // Refresh the refresh token :) - settings.RefreshToken = (string)accessTokenResult[RefreshToken]; - } - if (accessTokenResult.ContainsKey(ExpiresIn)) - { - object seconds = accessTokenResult[ExpiresIn]; - if (seconds != null) - { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double) seconds); - } - } - } - - /// - /// Authenticate by using the mode specified in the settings - /// - /// OAuth2Settings - /// false if it was canceled, true if it worked, exception if not - public static bool Authenticate(OAuth2Settings settings) { - var completed = settings.AuthorizeMode switch - { - OAuth2AuthorizeMode.LocalServer => AuthenticateViaLocalServer(settings), - OAuth2AuthorizeMode.EmbeddedBrowser => AuthenticateViaEmbeddedBrowser(settings), - OAuth2AuthorizeMode.OutOfBoundAuto => AuthenticateViaDefaultBrowser(settings), - _ => throw new NotImplementedException($"Authorize mode '{settings.AuthorizeMode}' is not 'yet' implemented."), - }; - return completed; - } - - /// - /// Authenticate via the default browser - /// If this works, return the code - /// - /// OAuth2Settings with the Auth / Token url etc - /// true if completed, false if canceled - private static bool AuthenticateViaDefaultBrowser(OAuth2Settings settings) - { - var monitor = new WindowsTitleMonitor(); - - string[] code = new string[1]; - monitor.TitleChangeEvent += args => - { - if (args.Title.Contains(settings.State)) - { - code[0] = args.Title; - settings.Code = args.Title; - } - }; - using (var process = Process.Start(settings.FormattedAuthUrl)) - { - while (string.IsNullOrEmpty(code[0])) - { - Application.DoEvents(); - } - }; - - return true; - } - - /// - /// Authenticate via an embedded browser - /// If this works, return the code - /// - /// OAuth2Settings with the Auth / Token url etc - /// true if completed, false if canceled - private static bool AuthenticateViaEmbeddedBrowser(OAuth2Settings settings) { - if (string.IsNullOrEmpty(settings.CloudServiceName)) { - throw new ArgumentNullException(nameof(settings.CloudServiceName)); - } - if (settings.BrowserSize == Size.Empty) { - throw new ArgumentNullException(nameof(settings.BrowserSize)); - } - OAuthLoginForm loginForm = new OAuthLoginForm($"Authorize {settings.CloudServiceName}", settings.BrowserSize, settings.FormattedAuthUrl, settings.RedirectUrl); - loginForm.ShowDialog(); - if (loginForm.IsOk) { - if (loginForm.CallbackParameters.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) { - settings.Code = code; - GenerateRefreshToken(settings); - return true; - } - return UpdateFromCallback(settings, loginForm.CallbackParameters); - } - return false; - } - - /// - /// Authenticate via a local server by using the LocalServerCodeReceiver - /// If this works, return the code - /// - /// OAuth2Settings with the Auth / Token url etc - /// true if completed - private static bool AuthenticateViaLocalServer(OAuth2Settings settings) { - var codeReceiver = new LocalServerCodeReceiver(); - IDictionary result = codeReceiver.ReceiveCode(settings); - - if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) { - settings.Code = code; - GenerateRefreshToken(settings); - return true; - } - - if (result.TryGetValue("error", out var error)) { - if (result.TryGetValue("error_description", out var errorDescription)) { - throw new Exception(errorDescription); - } - if ("access_denied" == error) { - throw new UnauthorizedAccessException("Access denied"); - } - throw new Exception(error); - } - return false; - } - - /// - /// Simple helper to add the Authorization Bearer header - /// - /// WebRequest - /// OAuth2Settings - public static void AddOAuth2Credentials(HttpWebRequest webRequest, OAuth2Settings settings) { - if (!string.IsNullOrEmpty(settings.AccessToken)) { - webRequest.Headers.Add("Authorization", "Bearer " + settings.AccessToken); - } - } - - /// - /// Check and authenticate or refresh tokens - /// - /// OAuth2Settings - public static void CheckAndAuthenticateOrRefresh(OAuth2Settings settings) { - // Get Refresh / Access token - if (string.IsNullOrEmpty(settings.RefreshToken)) { - if (!Authenticate(settings)) { - throw new Exception("Authentication cancelled"); - } - } - if (settings.IsAccessTokenExpired) { - GenerateAccessToken(settings); - // Get Refresh / Access token - if (string.IsNullOrEmpty(settings.RefreshToken)) { - if (!Authenticate(settings)) { - throw new Exception("Authentication cancelled"); - } - GenerateAccessToken(settings); - } - } - if (settings.IsAccessTokenExpired) { - throw new Exception("Authentication failed"); - } - } - - /// - /// CreateWebRequest ready for OAuth 2 access - /// - /// HTTPMethod - /// - /// OAuth2Settings - /// HttpWebRequest - public static HttpWebRequest CreateOAuth2WebRequest(HTTPMethod method, string url, OAuth2Settings settings) { - CheckAndAuthenticateOrRefresh(settings); - - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, method); - AddOAuth2Credentials(webRequest, settings); - return webRequest; - } - } -} diff --git a/GreenshotPlugin/Core/WindowDetails.cs b/GreenshotPlugin/Core/WindowDetails.cs index 903483c0c..7c9a2b905 100644 --- a/GreenshotPlugin/Core/WindowDetails.cs +++ b/GreenshotPlugin/Core/WindowDetails.cs @@ -266,33 +266,6 @@ namespace GreenshotPlugin.Core } } - /// - /// Retrieve all windows with a certain title or classname - /// - /// IEnumerable - /// The regexp to look for in the title - /// The regexp to look for in the classname - /// IEnumerable WindowDetails with all the found windows - private static IEnumerable FindWindow(IEnumerable windows, string titlePattern, string classnamePattern) { - Regex titleRegexp = null; - Regex classnameRegexp = null; - - if (titlePattern != null && titlePattern.Trim().Length > 0) { - titleRegexp = new Regex(titlePattern); - } - if (classnamePattern != null && classnamePattern.Trim().Length > 0) { - classnameRegexp = new Regex(classnamePattern); - } - - foreach(WindowDetails window in windows) { - if (titleRegexp != null && titleRegexp.IsMatch(window.Text)) { - yield return window; - } else if (classnameRegexp != null && classnameRegexp.IsMatch(window.ClassName)) { - yield return window; - } - } - } - /// /// Retrieve the child with matching classname /// diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 21d640496..369e584cb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -43,14 +43,14 @@ stages: platform: $(buildPlatform) configuration: $(buildConfiguration) env: - Box_ClientId: $(Box_ClientId) - Box_ClientSecret: $(Box_ClientSecret) - DropBox_ClientId: $(DropBox_ClientId) - DropBox_ClientSecret: $(DropBox_ClientSecret) + Box13_ClientId: $(Box13_ClientId) + Box13_ClientSecret: $(Box13_ClientSecret) + DropBox13_ClientId: $(DropBox13_ClientId) + DropBox13_ClientSecret: $(DropBox13_ClientSecret) Flickr_ClientId: $(Flickr_ClientId) Flickr_ClientSecret: $(Flickr_ClientSecret) - Imgur_ClientId: $(Imgur_ClientId) - Imgur_ClientSecret: $(Imgur_ClientSecret) + Imgur13_ClientId: $(Imgur13_ClientId) + Imgur13_ClientSecret: $(Imgur13_ClientSecret) Photobucket_ClientId: $(Photobucket_ClientId) Photobucket_ClientSecret: $(Photobucket_ClientSecret) Picasa_ClientId: $(Picasa_ClientId) From 56df0dbca593d84ddfcb0c92a72cf87e70131e65 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 27 Mar 2021 00:34:50 +0100 Subject: [PATCH 108/232] Added a missing file in the installer for the windows 10 plugin. [skip ci] --- Greenshot/releases/innosetup/setup.iss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 91ab88e3c..b4ddf605b 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -109,6 +109,8 @@ Source: {#BaseDir}\GreenshotExternalCommandPlugin\{#BinDir}\GreenshotExternalCom Source: {#BaseDir}\GreenshotExternalCommandPlugin\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion; ;Win 10 Plugin Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\GreenshotWin10Plugin.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\Microsoft.Toolkit.Uwp.Notifications; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; + [Setup] ; changes associations is used when the installer installs new extensions, it clears the explorer icon cache ChangesAssociations=yes From 4a959621ffe7c3f8ef63dfdbaaabfc9480a2fe44 Mon Sep 17 00:00:00 2001 From: jklingen Date: Sat, 27 Mar 2021 19:54:31 +0100 Subject: [PATCH 109/232] Fix Inconsistent Scale Behavior when Scaling Objects with Shift Modifier (#300) * Fix Objects Growing near Infinity when Scaling w Aspect Ratio Maintained * Refactor adjustCoordsForRationalScale to Get Rid of Code Duplication and Improve Comprehensibility * Rename getNewSizeForRationalScale to GetNewSizeForRationalScale for Consistency --- Greenshot/Helpers/ScaleHelper.cs | 655 ++++++++++++++++--------------- 1 file changed, 338 insertions(+), 317 deletions(-) diff --git a/Greenshot/Helpers/ScaleHelper.cs b/Greenshot/Helpers/ScaleHelper.cs index 43a2ca3e9..08956a5c5 100644 --- a/Greenshot/Helpers/ScaleHelper.cs +++ b/Greenshot/Helpers/ScaleHelper.cs @@ -1,318 +1,339 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Windows.Forms; -using Greenshot.Drawing; - -namespace Greenshot.Helpers { - /// - /// Offers a few helper functions for scaling/aligning an element with another element - /// - public static class ScaleHelper { - - [Flags] - public enum ScaleOptions { - /// - /// Default scale behavior. - /// - Default = 0x00, - /// - /// Scale a rectangle in two our four directions, mirrored at it's center coordinates - /// - Centered = 0x01, - /// - /// Scale a rectangle maintaining it's aspect ratio - /// - Rational = 0x02 - } - - /// - /// calculates the Size an element must be resized to, in order to fit another element, keeping aspect ratio - /// - /// the size of the element to be resized - /// the target size of the element - /// in case the aspect ratio of currentSize and targetSize differs: shall the scaled size fit into targetSize (i.e. that one of its dimensions is smaller - false) or vice versa (true) - /// a new SizeF object indicating the width and height the element should be scaled to - public static SizeF GetScaledSize(SizeF currentSize, SizeF targetSize, bool crop) { - float wFactor = targetSize.Width/currentSize.Width; - float hFactor = targetSize.Height/currentSize.Height; - - float factor = crop ? Math.Max(wFactor, hFactor) : Math.Min(wFactor, hFactor); - return new SizeF(currentSize.Width * factor, currentSize.Height * factor); - } - - /// - /// calculates the position of an element depending on the desired alignment within a RectangleF - /// - /// the bounds of the element to be aligned - /// the rectangle reference for alignment of the element - /// the System.Drawing.ContentAlignment value indicating how the element is to be aligned should the width or height differ from targetSize - /// a new RectangleF object with Location aligned aligned to targetRect - public static RectangleF GetAlignedRectangle(RectangleF currentRect, RectangleF targetRect, ContentAlignment alignment) { - RectangleF newRect = new RectangleF(targetRect.Location, currentRect.Size); - switch(alignment) { - case ContentAlignment.TopCenter: - newRect.X = (targetRect.Width - currentRect.Width) / 2; - break; - case ContentAlignment.TopRight: - newRect.X = targetRect.Width - currentRect.Width; - break; - case ContentAlignment.MiddleLeft: - newRect.Y = (targetRect.Height - currentRect.Height) / 2; - break; - case ContentAlignment.MiddleCenter: - newRect.Y = (targetRect.Height - currentRect.Height) / 2; - newRect.X = (targetRect.Width - currentRect.Width) / 2; - break; - case ContentAlignment.MiddleRight: - newRect.Y = (targetRect.Height - currentRect.Height) / 2; - newRect.X = targetRect.Width - currentRect.Width; - break; - case ContentAlignment.BottomLeft: - newRect.Y = targetRect.Height - currentRect.Height; - break; - case ContentAlignment.BottomCenter: - newRect.Y = targetRect.Height - currentRect.Height; - newRect.X = (targetRect.Width - currentRect.Width) / 2; - break; - case ContentAlignment.BottomRight: - newRect.Y = targetRect.Height - currentRect.Height; - newRect.X = targetRect.Width - currentRect.Width; - break; - } - return newRect; - } - - /// - /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) - /// - /// bounds of the current rectangle, scaled values will be written to this reference - /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT - /// coordinates of the used handle/gripper - /// ScaleOptions to use when scaling - public static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords, ScaleOptions? options) { - options ??= GetScaleOptions(); - - if ((options & ScaleOptions.Rational) == ScaleOptions.Rational) { - AdjustCoordsForRationalScale(originalRectangle, resizeHandlePosition, ref resizeHandleCoords); - } - - if ((options & ScaleOptions.Centered) == ScaleOptions.Centered) { - // store center coordinates of rectangle - float rectCenterX = originalRectangle.Left + originalRectangle.Width / 2; - float rectCenterY = originalRectangle.Top + originalRectangle.Height / 2; - // scale rectangle using handle coordinates - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); - // mirror handle coordinates via rectangle center coordinates - resizeHandleCoords.X -= 2 * (resizeHandleCoords.X - rectCenterX); - resizeHandleCoords.Y -= 2 * (resizeHandleCoords.Y - rectCenterY); - // scale again with opposing handle and mirrored coordinates - resizeHandlePosition = (Positions)((((int)resizeHandlePosition) + 4) % 8); - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); - } else { - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); - } - - } - - /// - /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) - /// - /// bounds of the current rectangle, scaled values will be written to this reference - /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT - /// coordinates of the used handle/gripper - private static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) { - switch(resizeHandlePosition) { - - case Positions.TopLeft: - originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; - originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; - originalRectangle.X = resizeHandleCoords.X; - originalRectangle.Y = resizeHandleCoords.Y; - break; - - case Positions.TopCenter: - originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; - originalRectangle.Y = resizeHandleCoords.Y; - break; - - case Positions.TopRight: - originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; - originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; - originalRectangle.Y = resizeHandleCoords.Y; - break; - - case Positions.MiddleLeft: - originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; - originalRectangle.X = resizeHandleCoords.X; - break; - - case Positions.MiddleRight: - originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; - break; - - case Positions.BottomLeft: - originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; - originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; - originalRectangle.X = resizeHandleCoords.X; - break; - - case Positions.BottomCenter: - originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; - break; - - case Positions.BottomRight: - originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; - originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; - break; - - default: - throw new ArgumentException("Position cannot be handled: "+resizeHandlePosition); - - } - } - - /// - /// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments - /// - /// bounds of the current rectangle - /// position of the handle/gripper being used for resized, see Position - /// coordinates of the used handle/gripper, adjusted coordinates will be written to this reference - private static void AdjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) { - float originalRatio = originalRectangle.Width / originalRectangle.Height; - float newWidth, newHeight, newRatio; - switch(resizeHandlePosition) { - - case Positions.TopLeft: - newWidth = originalRectangle.Right - resizeHandleCoords.X; - newHeight = originalRectangle.Bottom - resizeHandleCoords.Y; - newRatio = newWidth / newHeight; - if(newRatio > originalRatio) { // FIXME - resizeHandleCoords.X = originalRectangle.Right - newHeight * originalRatio; - } else if(newRatio < originalRatio) { - resizeHandleCoords.Y = originalRectangle.Bottom - newWidth / originalRatio; - } - break; - - case Positions.TopRight: - newWidth = resizeHandleCoords.X - originalRectangle.Left; - newHeight = originalRectangle.Bottom - resizeHandleCoords.Y; - newRatio = newWidth / newHeight; - if(newRatio > originalRatio) { // FIXME - resizeHandleCoords.X = newHeight * originalRatio + originalRectangle.Left; - } else if(newRatio < originalRatio) { - resizeHandleCoords.Y = originalRectangle.Bottom - newWidth / originalRatio; - } - break; - - case Positions.BottomLeft: - newWidth = originalRectangle.Right - resizeHandleCoords.X; - newHeight = resizeHandleCoords.Y - originalRectangle.Top; - newRatio = newWidth / newHeight; - if(newRatio > originalRatio) { - resizeHandleCoords.X = originalRectangle.Right - newHeight * originalRatio; - } else if(newRatio < originalRatio) { - resizeHandleCoords.Y = newWidth / originalRatio + originalRectangle.Top; - } - break; - - case Positions.BottomRight: - newWidth = resizeHandleCoords.X - originalRectangle.Left; - newHeight = resizeHandleCoords.Y - originalRectangle.Top; - newRatio = newWidth / newHeight; - if(newRatio > originalRatio) { - resizeHandleCoords.X = newHeight * originalRatio + originalRectangle.Left; - } else if(newRatio < originalRatio) { - resizeHandleCoords.Y = newWidth / originalRatio + originalRectangle.Top; - } - break; - } - } - - public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) { - - Scale(boundsBeforeResize, Positions.TopLeft, cursorX, cursorY, ref boundsAfterResize, angleRoundBehavior); - } - - public static void Scale(Rectangle boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) { - - ScaleOptions opts = GetScaleOptions(); - - bool rationalScale = (opts & ScaleOptions.Rational) == ScaleOptions.Rational; - bool centeredScale = (opts & ScaleOptions.Centered) == ScaleOptions.Centered; - - if(rationalScale) { - double angle = GeometryHelper.Angle2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); - - if(angleRoundBehavior != null) { - angle = angleRoundBehavior.Process(angle); - } - - int dist = GeometryHelper.Distance2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); - - boundsAfterResize.Width = (int)Math.Round(dist * Math.Cos(angle / 180 * Math.PI)); - boundsAfterResize.Height = (int)Math.Round(dist * Math.Sin(angle / 180 * Math.PI)); - } - - if(centeredScale) { - float wdiff = boundsAfterResize.Width - boundsBeforeResize.Width; - float hdiff = boundsAfterResize.Height - boundsBeforeResize.Height; - boundsAfterResize.Width += wdiff; - boundsAfterResize.Height += hdiff; - boundsAfterResize.X -= wdiff; - boundsAfterResize.Y -= hdiff; - } - - - } - - /// the current ScaleOptions depending on modifier keys held down - public static ScaleOptions GetScaleOptions() { - bool anchorAtCenter = (Control.ModifierKeys & Keys.Control) != 0; - bool maintainAspectRatio = (Control.ModifierKeys & Keys.Shift) != 0; - ScaleOptions opts = ScaleOptions.Default; - if(anchorAtCenter) opts |= ScaleOptions.Centered; - if(maintainAspectRatio) opts |= ScaleOptions.Rational; - return opts; - } - - public interface IDoubleProcessor { - double Process(double d); - } - - public class ShapeAngleRoundBehavior : IDoubleProcessor { - public static ShapeAngleRoundBehavior Instance = new(); - private ShapeAngleRoundBehavior() {} - public double Process(double angle) { - return Math.Round((angle+45)/90)*90 - 45; - } - } - public class LineAngleRoundBehavior : IDoubleProcessor { - public static LineAngleRoundBehavior Instance = new(); - private LineAngleRoundBehavior() {} - public double Process(double angle) { - return Math.Round(angle/15)*15; - } - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +using System; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Drawing; + +namespace Greenshot.Helpers { + /// + /// Offers a few helper functions for scaling/aligning an element with another element + /// + public static class ScaleHelper { + + [Flags] + public enum ScaleOptions { + /// + /// Default scale behavior. + /// + Default = 0x00, + /// + /// Scale a rectangle in two our four directions, mirrored at it's center coordinates + /// + Centered = 0x01, + /// + /// Scale a rectangle maintaining it's aspect ratio + /// + Rational = 0x02 + } + + /// + /// calculates the Size an element must be resized to, in order to fit another element, keeping aspect ratio + /// + /// the size of the element to be resized + /// the target size of the element + /// in case the aspect ratio of currentSize and targetSize differs: shall the scaled size fit into targetSize (i.e. that one of its dimensions is smaller - false) or vice versa (true) + /// a new SizeF object indicating the width and height the element should be scaled to + public static SizeF GetScaledSize(SizeF currentSize, SizeF targetSize, bool crop) { + float wFactor = targetSize.Width/currentSize.Width; + float hFactor = targetSize.Height/currentSize.Height; + + float factor = crop ? Math.Max(wFactor, hFactor) : Math.Min(wFactor, hFactor); + return new SizeF(currentSize.Width * factor, currentSize.Height * factor); + } + + /// + /// calculates the position of an element depending on the desired alignment within a RectangleF + /// + /// the bounds of the element to be aligned + /// the rectangle reference for alignment of the element + /// the System.Drawing.ContentAlignment value indicating how the element is to be aligned should the width or height differ from targetSize + /// a new RectangleF object with Location aligned aligned to targetRect + public static RectangleF GetAlignedRectangle(RectangleF currentRect, RectangleF targetRect, ContentAlignment alignment) { + RectangleF newRect = new RectangleF(targetRect.Location, currentRect.Size); + switch(alignment) { + case ContentAlignment.TopCenter: + newRect.X = (targetRect.Width - currentRect.Width) / 2; + break; + case ContentAlignment.TopRight: + newRect.X = targetRect.Width - currentRect.Width; + break; + case ContentAlignment.MiddleLeft: + newRect.Y = (targetRect.Height - currentRect.Height) / 2; + break; + case ContentAlignment.MiddleCenter: + newRect.Y = (targetRect.Height - currentRect.Height) / 2; + newRect.X = (targetRect.Width - currentRect.Width) / 2; + break; + case ContentAlignment.MiddleRight: + newRect.Y = (targetRect.Height - currentRect.Height) / 2; + newRect.X = targetRect.Width - currentRect.Width; + break; + case ContentAlignment.BottomLeft: + newRect.Y = targetRect.Height - currentRect.Height; + break; + case ContentAlignment.BottomCenter: + newRect.Y = targetRect.Height - currentRect.Height; + newRect.X = (targetRect.Width - currentRect.Width) / 2; + break; + case ContentAlignment.BottomRight: + newRect.Y = targetRect.Height - currentRect.Height; + newRect.X = targetRect.Width - currentRect.Width; + break; + } + return newRect; + } + + /// + /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) + /// + /// bounds of the current rectangle, scaled values will be written to this reference + /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT + /// coordinates of the used handle/gripper + /// ScaleOptions to use when scaling + public static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords, ScaleOptions? options) { + options ??= GetScaleOptions(); + + if ((options & ScaleOptions.Rational) == ScaleOptions.Rational) { + AdjustCoordsForRationalScale(originalRectangle, resizeHandlePosition, ref resizeHandleCoords); + } + + if ((options & ScaleOptions.Centered) == ScaleOptions.Centered) { + // store center coordinates of rectangle + float rectCenterX = originalRectangle.Left + originalRectangle.Width / 2; + float rectCenterY = originalRectangle.Top + originalRectangle.Height / 2; + // scale rectangle using handle coordinates + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + // mirror handle coordinates via rectangle center coordinates + resizeHandleCoords.X -= 2 * (resizeHandleCoords.X - rectCenterX); + resizeHandleCoords.Y -= 2 * (resizeHandleCoords.Y - rectCenterY); + // scale again with opposing handle and mirrored coordinates + resizeHandlePosition = (Positions)((((int)resizeHandlePosition) + 4) % 8); + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + } else { + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + } + + } + + /// + /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) + /// + /// bounds of the current rectangle, scaled values will be written to this reference + /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT + /// coordinates of the used handle/gripper + private static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) { + switch(resizeHandlePosition) { + + case Positions.TopLeft: + originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; + originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; + originalRectangle.X = resizeHandleCoords.X; + originalRectangle.Y = resizeHandleCoords.Y; + break; + + case Positions.TopCenter: + originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; + originalRectangle.Y = resizeHandleCoords.Y; + break; + + case Positions.TopRight: + originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; + originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; + originalRectangle.Y = resizeHandleCoords.Y; + break; + + case Positions.MiddleLeft: + originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; + originalRectangle.X = resizeHandleCoords.X; + break; + + case Positions.MiddleRight: + originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; + break; + + case Positions.BottomLeft: + originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; + originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + originalRectangle.X = resizeHandleCoords.X; + break; + + case Positions.BottomCenter: + originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + break; + + case Positions.BottomRight: + originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; + originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + break; + + default: + throw new ArgumentException("Position cannot be handled: "+resizeHandlePosition); + + } + } + + /// + /// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments. + /// An adjustment can always be done in two ways, e.g. *in*crease width until fit or *de*crease height until fit. + /// To avoid objects growing near infinity unexpectedly in certain combinations, the adjustment will choose the + /// option resulting in the smaller rectangle. + /// + /// bounds of the current rectangle + /// position of the handle/gripper being used for resized, see Position + /// coordinates of the used handle/gripper, adjusted coordinates will be written to this reference + private static void AdjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) { + SizeF selectedRectangle, newSize; + + switch(resizeHandlePosition) { + + case Positions.TopLeft: + selectedRectangle = new SizeF(originalRectangle.Right - resizeHandleCoords.X, originalRectangle.Bottom - resizeHandleCoords.Y); + newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); + resizeHandleCoords.X = originalRectangle.Right - newSize.Width; + resizeHandleCoords.Y = originalRectangle.Bottom - newSize.Height; + break; + + case Positions.TopRight: + selectedRectangle = new SizeF(resizeHandleCoords.X - originalRectangle.Left, originalRectangle.Bottom - resizeHandleCoords.Y); + newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); + resizeHandleCoords.X = originalRectangle.Left + newSize.Width; + resizeHandleCoords.Y = originalRectangle.Bottom - newSize.Height; + break; + + case Positions.BottomLeft: + selectedRectangle = new SizeF(originalRectangle.Right - resizeHandleCoords.X, resizeHandleCoords.Y - originalRectangle.Top); + newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); + resizeHandleCoords.X = originalRectangle.Right - newSize.Width; + resizeHandleCoords.Y = originalRectangle.Top + newSize.Height; + break; + + case Positions.BottomRight: + selectedRectangle = new SizeF(resizeHandleCoords.X - originalRectangle.Left, resizeHandleCoords.Y - originalRectangle.Top); + newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); + resizeHandleCoords.X = originalRectangle.Left + newSize.Width; + resizeHandleCoords.Y = originalRectangle.Top + newSize.Height; + break; + } + } + + /// + /// For an original size, and a selected size, returns the the largest possible size that + /// * has the same aspect ratio as the original + /// * fits into selected size + /// + /// size to be considered for keeping aspect ratio + /// selection size (i.e. the size we'd produce if we wouldn't keep aspect ratio) + /// + private static SizeF GetNewSizeForRationalScale(SizeF originalSize, SizeF selectedSize) + { + SizeF newSize = selectedSize; + float originalRatio = originalSize.Width / originalSize.Height; + float selectedRatio = selectedSize.Width / selectedSize.Height; + // will fix orientation if the scaling causes size to be flipped in any direction + int flippedRatioSign = Math.Sign(selectedRatio) * Math.Sign(originalRatio); + if (Math.Abs(selectedRatio) > Math.Abs(originalRatio)) + { + // scaled rectangle (ratio) would be wider than original + // keep height and tweak width to maintain aspect ratio + newSize.Width = selectedSize.Height * originalRatio * flippedRatioSign; + } + else if (Math.Abs(selectedRatio) < Math.Abs(originalRatio)) + { + // scaled rectangle (ratio) would be taller than original + // keep width and tweak height to maintain aspect ratio + newSize.Height = selectedSize.Width / originalRatio * flippedRatioSign; + } + return newSize; + } + + public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize) { + Scale(boundsBeforeResize, cursorX, cursorY, ref boundsAfterResize, null); + } + + public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) { + + Scale(boundsBeforeResize, Positions.TopLeft, cursorX, cursorY, ref boundsAfterResize, angleRoundBehavior); + } + + public static void Scale(Rectangle boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) { + + ScaleOptions opts = GetScaleOptions(); + + bool rationalScale = (opts & ScaleOptions.Rational) == ScaleOptions.Rational; + bool centeredScale = (opts & ScaleOptions.Centered) == ScaleOptions.Centered; + + if(rationalScale) { + double angle = GeometryHelper.Angle2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); + + if(angleRoundBehavior != null) { + angle = angleRoundBehavior.Process(angle); + } + + int dist = GeometryHelper.Distance2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); + + boundsAfterResize.Width = (int)Math.Round(dist * Math.Cos(angle / 180 * Math.PI)); + boundsAfterResize.Height = (int)Math.Round(dist * Math.Sin(angle / 180 * Math.PI)); + } + + if(centeredScale) { + float wdiff = boundsAfterResize.Width - boundsBeforeResize.Width; + float hdiff = boundsAfterResize.Height - boundsBeforeResize.Height; + boundsAfterResize.Width += wdiff; + boundsAfterResize.Height += hdiff; + boundsAfterResize.X -= wdiff; + boundsAfterResize.Y -= hdiff; + } + + + } + + /// the current ScaleOptions depending on modifier keys held down + public static ScaleOptions GetScaleOptions() { + bool anchorAtCenter = (Control.ModifierKeys & Keys.Control) != 0; + bool maintainAspectRatio = (Control.ModifierKeys & Keys.Shift) != 0; + ScaleOptions opts = ScaleOptions.Default; + if(anchorAtCenter) opts |= ScaleOptions.Centered; + if(maintainAspectRatio) opts |= ScaleOptions.Rational; + return opts; + } + + public interface IDoubleProcessor { + double Process(double d); + } + + public class ShapeAngleRoundBehavior : IDoubleProcessor { + public static ShapeAngleRoundBehavior Instance = new(); + private ShapeAngleRoundBehavior() {} + public double Process(double angle) { + return Math.Round((angle+45)/90)*90 - 45; + } + } + public class LineAngleRoundBehavior : IDoubleProcessor { + public static LineAngleRoundBehavior Instance = new(); + private LineAngleRoundBehavior() {} + public double Process(double angle) { + return Math.Round(angle/15)*15; + } + } + } +} \ No newline at end of file From 2fdb667d708260c0530328be5949107bf4b5149d Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 27 Mar 2021 20:11:14 +0100 Subject: [PATCH 110/232] Fix for build error --- Greenshot/releases/innosetup/setup.iss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index b4ddf605b..4eff93b45 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -109,7 +109,7 @@ Source: {#BaseDir}\GreenshotExternalCommandPlugin\{#BinDir}\GreenshotExternalCom Source: {#BaseDir}\GreenshotExternalCommandPlugin\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion; ;Win 10 Plugin Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\GreenshotWin10Plugin.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\Microsoft.Toolkit.Uwp.Notifications; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\Microsoft.Toolkit.Uwp.Notifications.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; [Setup] ; changes associations is used when the installer installs new extensions, it clears the explorer icon cache From 11f586ab36d48e46d1b4f0b9825bf6d823bdadaf Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 27 Mar 2021 22:30:25 +0100 Subject: [PATCH 111/232] Restructuring the project, first steps. --- src/.editorconfig | 78 ++++++++ src/Directory.Build.props | 122 +++++++++++++ src/Directory.Build.targets | 13 ++ src/Greenshot.sln | 170 ++++++++++++++++++ src/Greenshot.sln.DotSettings | 4 + {Greenshot => src/Greenshot}/App.config | 0 .../Configuration/EditorConfiguration.cs | 0 .../Greenshot}/Configuration/LanguageKeys.cs | 0 .../Controls/BindableToolStripButton.cs | 0 .../Controls/BindableToolStripComboBox.cs | 0 .../BindableToolStripDropDownButton.cs | 0 .../Greenshot}/Controls/ColorButton.cs | 0 ...ontextMenuToolStripProfessionalRenderer.cs | 0 .../CustomToolStripProfessionalRenderer.cs | 0 .../Greenshot}/Controls/FontFamilyComboBox.cs | 0 .../Greenshot}/Controls/MenuStripEx.cs | 0 .../Greenshot}/Controls/NonJumpingPanel.cs | 0 .../Greenshot}/Controls/Pipette.cs | 0 .../Controls/ToolStripColorButton.cs | 0 .../Greenshot}/Controls/ToolStripEx.cs | 0 .../Controls/ToolStripNumericUpDown.cs | 0 .../Destinations/ClipboardDestination.cs | 0 .../Destinations/EditorDestination.cs | 0 .../Destinations/EmailDestination.cs | 0 .../Destinations/FileDestination.cs | 0 .../Destinations/FileWithDialogDestination.cs | 0 .../Destinations/PickerDestination.cs | 0 .../Destinations/PrinterDestination.cs | 0 .../Drawing/Adorners/AbstractAdorner.cs | 0 .../Drawing/Adorners/MoveAdorner.cs | 0 .../Drawing/Adorners/ResizeAdorner.cs | 0 .../Drawing/Adorners/TargetAdorner.cs | 0 .../Greenshot}/Drawing/ArrowContainer.cs | 0 .../Greenshot}/Drawing/CropContainer.cs | 0 .../Greenshot}/Drawing/CursorContainer.cs | 0 .../Greenshot}/Drawing/DrawableContainer.cs | 0 .../Drawing/DrawableContainerList.cs | 0 .../Greenshot}/Drawing/EllipseContainer.cs | 0 .../Drawing/Fields/AbstractFieldHolder.cs | 0 .../Fields/AbstractFieldHolderWithChildren.cs | 0 .../Binding/AbstractBindingConverter.cs | 0 .../Fields/Binding/BidirectionalBinding.cs | 0 .../DecimalDoublePercentageConverter.cs | 0 .../Fields/Binding/DecimalFloatConverter.cs | 0 .../Fields/Binding/DecimalIntConverter.cs | 0 .../Fields/Binding/IBindingConverter.cs | 0 .../Fields/Binding/IBindingValidator.cs | 0 .../Fields/Binding/NotNullValidator.cs | 0 .../Greenshot}/Drawing/Fields/Field.cs | 0 .../Drawing/Fields/FieldAggregator.cs | 0 .../Greenshot}/Drawing/Fields/FieldType.cs | 0 .../Greenshot}/Drawing/FilterContainer.cs | 0 .../Drawing/Filters/AbstractFilter.cs | 0 .../Greenshot}/Drawing/Filters/BlurFilter.cs | 0 .../Drawing/Filters/BrightnessFilter.cs | 0 .../Drawing/Filters/GrayscaleFilter.cs | 0 .../Drawing/Filters/HighlightFilter.cs | 0 .../Greenshot}/Drawing/Filters/IFilter.cs | 0 .../Drawing/Filters/MagnifierFilter.cs | 0 .../Drawing/Filters/PixelizationFilter.cs | 0 .../Greenshot}/Drawing/FreehandContainer.cs | 0 .../Greenshot}/Drawing/HighlightContainer.cs | 0 .../Greenshot}/Drawing/IconContainer.cs | 0 .../Greenshot}/Drawing/ImageContainer.cs | 0 .../Greenshot}/Drawing/LineContainer.cs | 0 .../Greenshot}/Drawing/ObfuscateContainer.cs | 0 .../Greenshot}/Drawing/Positions.cs | 0 .../Greenshot}/Drawing/RectangleContainer.cs | 0 .../Drawing/SpeechbubbleContainer.cs | 0 .../Greenshot}/Drawing/StepLabelContainer.cs | 0 .../Greenshot}/Drawing/Surface.cs | 0 .../Greenshot}/Drawing/TextContainer.cs | 0 .../Greenshot}/Forms/AboutForm.Designer.cs | 0 .../Greenshot}/Forms/AboutForm.cs | 0 .../Greenshot}/Forms/AnimatingBaseForm.cs | 0 .../Greenshot}/Forms/BaseForm.cs | 0 .../Forms/BugReportForm.Designer.cs | 0 .../Greenshot}/Forms/BugReportForm.cs | 0 .../Greenshot}/Forms/CaptureForm.Designer.cs | 0 .../Greenshot}/Forms/CaptureForm.cs | 0 .../Greenshot}/Forms/ColorDialog.Designer.cs | 0 .../Greenshot}/Forms/ColorDialog.cs | 0 .../Greenshot}/Forms/ColorDialog.resx | 0 .../Forms/ColorPickerToolStripButton.cs | 0 .../Forms/DropShadowSettingsForm.Designer.cs | 0 .../Forms/DropShadowSettingsForm.cs | 0 .../Forms/ImageEditorForm.Designer.cs | 0 .../Greenshot}/Forms/ImageEditorForm.cs | 0 .../Greenshot}/Forms/ImageEditorForm.resx | 0 .../Forms/LanguageDialog.Designer.cs | 0 .../Greenshot}/Forms/LanguageDialog.cs | 0 .../Greenshot}/Forms/MainForm.Designer.cs | 0 .../Greenshot}/Forms/MainForm.cs | 0 .../Greenshot}/Forms/MainForm.resx | 0 .../Forms/MovableShowColorForm.Designer.cs | 0 .../Greenshot}/Forms/MovableShowColorForm.cs | 0 .../Forms/PrintOptionsDialog.Designer.cs | 0 .../Greenshot}/Forms/PrintOptionsDialog.cs | 0 .../Forms/ResizeSettingsForm.Designer.cs | 0 .../Greenshot}/Forms/ResizeSettingsForm.cs | 0 .../Greenshot}/Forms/SettingsForm.Designer.cs | 0 .../Greenshot}/Forms/SettingsForm.cs | 0 .../Greenshot}/Forms/SettingsForm.resx | 0 .../Forms/ToolStripMenuSelectList.cs | 0 .../Forms/TornEdgeSettingsForm.Designer.cs | 0 .../Greenshot}/Forms/TornEdgeSettingsForm.cs | 0 {Greenshot => src/Greenshot}/Greenshot.csproj | 0 {Greenshot => src/Greenshot}/GreenshotMain.cs | 0 .../Greenshot}/Help/HelpFileLoader.cs | 0 .../Greenshot}/Helpers/CaptureHelper.cs | 0 .../Greenshot}/Helpers/Colors.cs | 0 .../Greenshot}/Helpers/CopyData.cs | 0 .../Greenshot}/Helpers/DestinationHelper.cs | 0 .../Greenshot}/Helpers/Entities/UpdateFeed.cs | 0 .../Greenshot}/Helpers/GeometryHelper.cs | 0 .../Greenshot}/Helpers/GuiRectangle.cs | 0 .../Greenshot}/Helpers/IECaptureHelper.cs | 0 .../Helpers/IEInterop/IEContainer.cs | 0 .../Greenshot}/Helpers/MailHelper.cs | 0 .../Helpers/NotifyIconNotificationService.cs | 0 .../Greenshot}/Helpers/PluginHelper.cs | 0 .../Greenshot}/Helpers/PrintHelper.cs | 0 .../Greenshot}/Helpers/ProcessorHelper.cs | 0 .../Greenshot}/Helpers/ResourceMutex.cs | 0 .../Greenshot}/Helpers/ScaleHelper.cs | 0 .../Greenshot}/Helpers/SoundHelper.cs | 0 .../Greenshot}/Helpers/StartupHelper.cs | 0 .../Helpers/ToolStripItemEndisabler.cs | 0 .../Greenshot}/Helpers/UpdateService.cs | 0 .../Greenshot}/Languages/help-de-DE.html | 0 .../Greenshot}/Languages/help-en-US.html | 0 .../Greenshot}/Languages/help-es-ES.html | 0 .../Greenshot}/Languages/help-fr-FR.html | 0 .../Greenshot}/Languages/help-hu-HU.html | 0 .../Greenshot}/Languages/help-it-IT.html | 0 .../Greenshot}/Languages/help-ko-KR.html | 0 .../Greenshot}/Languages/help-nl-NL.html | 0 .../Greenshot}/Languages/help-nn-NO.html | 0 .../Greenshot}/Languages/help-pl-PL.html | 0 .../Greenshot}/Languages/help-pt-BR.html | 0 .../Greenshot}/Languages/help-pt-PT.html | 0 .../Greenshot}/Languages/help-ru-RU.html | 0 .../Greenshot}/Languages/help-sv-SE.html | 0 .../Greenshot}/Languages/help-tr-TR.html | 0 .../Greenshot}/Languages/help-zh-CN.html | 0 .../installer/language-installer-de-DE.xml | 0 .../installer/language-installer-en-US.xml | 0 .../installer/language-installer-es-ES.xml | 0 .../installer/language-installer-fi-FI.xml | 0 .../installer/language-installer-fr-FR.xml | 0 .../installer/language-installer-it-IT.xml | 0 .../installer/language-installer-lv-LV.xml | 0 .../installer/language-installer-nl-NL.xml | 0 .../installer/language-installer-nn-NO.xml | 0 .../installer/language-installer-sr-RS.xml | 0 .../installer/language-installer-sv-SE.xml | 0 .../installer/language-installer-uk-UA.xml | 0 .../installer/language-installer-zh-CN.xml | 0 .../Greenshot}/Languages/language-ar-SY.xml | 0 .../Greenshot}/Languages/language-ca-CA.xml | 0 .../Greenshot}/Languages/language-cs-CZ.xml | 0 .../Greenshot}/Languages/language-da-DK.xml | 0 .../Greenshot}/Languages/language-de-DE.xml | 0 .../Languages/language-de-x-franconia.xml | 0 .../Greenshot}/Languages/language-el-GR.xml | 0 .../Greenshot}/Languages/language-en-US.xml | 0 .../Greenshot}/Languages/language-es-ES.xml | 0 .../Greenshot}/Languages/language-et-EE.xml | 0 .../Greenshot}/Languages/language-fa-IR.xml | 0 .../Greenshot}/Languages/language-fi-FI.xml | 0 .../Greenshot}/Languages/language-fr-FR.xml | 0 .../Greenshot}/Languages/language-fr-QC.xml | 0 .../Greenshot}/Languages/language-he-IL.xml | 0 .../Greenshot}/Languages/language-hu-HU.xml | 0 .../Greenshot}/Languages/language-id-ID.xml | 0 .../Greenshot}/Languages/language-it-IT.xml | 0 .../Greenshot}/Languages/language-ja-JP.xml | 0 .../Greenshot}/Languages/language-kab-DZ.xml | 0 .../Greenshot}/Languages/language-ko-KR.xml | 0 .../Greenshot}/Languages/language-lt-LT.xml | 0 .../Greenshot}/Languages/language-lv-LV.xml | 0 .../Greenshot}/Languages/language-nl-NL.xml | 0 .../Greenshot}/Languages/language-nn-NO.xml | 0 .../Greenshot}/Languages/language-pl-PL.xml | 0 .../Greenshot}/Languages/language-pt-BR.xml | 0 .../Greenshot}/Languages/language-pt-PT.xml | 0 .../Greenshot}/Languages/language-ro-RO.xml | 0 .../Greenshot}/Languages/language-ru-RU.xml | 0 .../Greenshot}/Languages/language-sk-SK.xml | 0 .../Greenshot}/Languages/language-sl-SI.xml | 0 .../Greenshot}/Languages/language-sr-RS.xml | 0 .../Greenshot}/Languages/language-sv-SE.xml | 0 .../Greenshot}/Languages/language-tr-TR.xml | 0 .../Greenshot}/Languages/language-uk-UA.xml | 0 .../Greenshot}/Languages/language-vi-VN.xml | 0 .../Greenshot}/Languages/language-zh-CN.xml | 0 .../Greenshot}/Languages/language-zh-TW.xml | 0 .../website/language-website-de-DE.xml | 0 .../website/language-website-en-US.xml | 0 .../website/language-website-es-ES.xml | 0 .../website/language-website-fr-FR.xml | 0 .../website/language-website-it-IT.xml | 0 .../website/language-website-lv-LV.xml | 0 .../website/language-website-nn-NO.xml | 0 .../website/language-website-pt-BR.xml | 0 .../website/language-website-sv-SE.xml | 0 .../website/language-website-uk-UA.xml | 0 .../Greenshot}/Memento/AddElementMemento.cs | 0 .../Greenshot}/Memento/AddElementsMemento.cs | 0 .../Memento/ChangeFieldHolderMemento.cs | 0 .../Memento/DeleteElementMemento.cs | 0 .../Memento/DeleteElementsMemento.cs | 0 .../DrawableContainerBoundsChangeMemento.cs | 0 .../Memento/SurfaceBackgroundChangeMemento.cs | 0 .../Greenshot}/Memento/TextChangeMemento.cs | 0 .../Processors/TitleFixProcessor.cs | 0 {Greenshot => src/Greenshot}/Sounds.resx | 0 .../Greenshot}/greenshot.manifest | 0 .../Greenshot}/icons/applicationIcon/16.ico | Bin .../Greenshot}/icons/applicationIcon/16.png | Bin .../Greenshot}/icons/applicationIcon/32.ico | Bin .../Greenshot}/icons/applicationIcon/32.png | Bin .../Greenshot}/icons/applicationIcon/48.ico | Bin .../Greenshot}/icons/applicationIcon/48.png | Bin .../Greenshot}/icons/applicationIcon/90.png | Bin .../Greenshot}/icons/applicationIcon/icon.ico | Bin .../Greenshot}/icons/arrow_redo.png | Bin .../Greenshot}/icons/arrow_rollback.png | Bin .../Greenshot}/icons/arrow_undo.png | Bin .../Greenshot}/icons/balloon.png | Bin {Greenshot => src/Greenshot}/icons/cancel.png | Bin {Greenshot => src/Greenshot}/icons/cross.png | Bin {Greenshot => src/Greenshot}/icons/cut.png | Bin {Greenshot => src/Greenshot}/icons/delete.png | Bin .../Greenshot}/icons/filter_blur.png | Bin .../Greenshot}/icons/filter_pixelate.png | Bin .../Greenshot}/icons/folder-open-image.png | Bin .../Greenshot}/icons/folder_explore.png | Bin .../Greenshot}/icons/font_color.png | Bin .../Greenshot}/icons/freehand.png | Bin .../Greenshot}/icons/fugue/arrow-resize.png | Bin .../icons/fugue/clipboard-paste-image.png | Bin .../Greenshot}/icons/fugue/clipboard.png | Bin .../Greenshot}/icons/fugue/color-swatch.png | Bin .../Greenshot}/icons/fugue/cross.png | Bin .../Greenshot}/icons/fugue/cursor.png | Bin .../Greenshot}/icons/fugue/disk-black.png | Bin .../icons/fugue/edit-alignment-center.png | Bin .../icons/fugue/edit-alignment-right.png | Bin .../Greenshot}/icons/fugue/edit-alignment.png | Bin .../Greenshot}/icons/fugue/edit-blur.png | Bin .../Greenshot}/icons/fugue/edit-bold.png | Bin .../Greenshot}/icons/fugue/edit-italic.png | Bin .../Greenshot}/icons/fugue/edit-pixelate.png | Bin .../Greenshot}/icons/fugue/edit-underline.png | Bin .../fugue/edit-vertical-alignment-middle.png | Bin .../fugue/edit-vertical-alignment-top.png | Bin .../icons/fugue/edit-vertical-alignment.png | Bin .../Greenshot}/icons/fugue/filter_base.pdn | Bin .../icons/fugue/filter_highlight_area.png | Bin .../fugue/filter_highlight_grayscale.png | Bin .../icons/fugue/filter_highlight_text.png | Bin .../Greenshot}/icons/fugue/gear.png | Bin .../icons/fugue/highlighter-color.png | Bin .../icons/fugue/highlighter-text.png | Bin .../Greenshot}/icons/fugue/image-blur.png | Bin .../Greenshot}/icons/fugue/image-pixelate.png | Bin .../Greenshot}/icons/fugue/images.png | Bin .../icons/fugue/layer-shape-arrow.png | Bin .../icons/fugue/layer-shape-ellipse.png | Bin .../icons/fugue/layer-shape-line.png | Bin .../icons/fugue/layer-shape-text.png | Bin .../Greenshot}/icons/fugue/layer-shape.png | Bin .../icons/fugue/magnifier-zoom-actual.png | Bin .../icons/fugue/magnifier-zoom-fit.png | Bin .../icons/fugue/magnifier-zoom-in.png | Bin .../icons/fugue/magnifier-zoom-out.png | Bin .../Greenshot}/icons/fugue/magnifier-zoom.png | Bin .../Greenshot}/icons/fugue/magnifier.png | Bin .../icons/fugue/mail-open-image.png | Bin .../Greenshot}/icons/fugue/minus-circle.png | Bin .../Greenshot}/icons/fugue/money-coin.png | Bin .../icons/fugue/paint-can-color-bg.png | Bin .../icons/fugue/paint-can-color.png | Bin .../icons/fugue/pencil-color-bg.png | Bin .../Greenshot}/icons/fugue/pencil-color.png | Bin .../Greenshot}/icons/fugue/printer.png | Bin .../Greenshot}/icons/fugue/question.png | Bin .../Greenshot}/icons/fugue/ruler-crop.png | Bin .../Greenshot}/icons/fugue/scissors.png | Bin .../Greenshot}/icons/fugue/slash.png | Bin .../Greenshot}/icons/fugue/tick.png | Bin {Greenshot => src/Greenshot}/icons/heart.png | Bin {Greenshot => src/Greenshot}/icons/help.png | Bin .../Greenshot}/icons/highlighter.png | Bin .../Greenshot}/icons/layer-rotate-left.png | Bin .../Greenshot}/icons/layer-rotate.png | Bin .../icons/notification-counter-01.png | Bin .../icons/notification-counter-02.png | Bin .../icons/notification-counter-03.png | Bin .../icons/notification-counter-04.png | Bin .../icons/notification-counter-05.png | Bin .../icons/notification-counter-06.png | Bin .../icons/notification-counter-07.png | Bin .../icons/notification-counter-08.png | Bin .../icons/notification-counter-09.png | Bin .../icons/notification-counter-10.png | Bin .../icons/notification-counter-11.png | Bin .../icons/notification-counter-12.png | Bin .../icons/notification-counter-13.png | Bin .../icons/notification-counter-14.png | Bin .../icons/notification-counter-15.png | Bin .../icons/notification-counter-16.png | Bin .../icons/notification-counter-17.png | Bin .../icons/notification-counter-18.png | Bin .../icons/notification-counter-19.png | Bin .../icons/notification-counter-20-plus.png | Bin .../icons/notification-counter-20.png | Bin .../Greenshot}/icons/page_copy.png | Bin .../Greenshot}/icons/palette.png | Bin .../Greenshot}/icons/picture_save.png | Bin .../Greenshot}/icons/picture_saveas.png | Bin .../Greenshot}/icons/picture_to_clipboard.png | Bin .../Greenshot}/icons/pipette.png | Bin .../Greenshot}/icons/printer.png | Bin .../icons/propertyitemcontainer.gif | Bin {Greenshot => src/Greenshot}/icons/redo.png | Bin {Greenshot => src/Greenshot}/icons/resize.png | Bin .../Greenshot}/icons/ruler-crop.png | Bin {Greenshot => src/Greenshot}/icons/shadow.png | Bin .../Greenshot}/icons/shape_arrow_add.png | Bin .../Greenshot}/icons/shape_arrowheads.png | Bin .../Greenshot}/icons/shape_copy.png | Bin .../Greenshot}/icons/shape_ellipse_add.png | Bin .../Greenshot}/icons/shape_ellipse_delete.png | Bin .../Greenshot}/icons/shape_line.png | Bin .../Greenshot}/icons/shape_paste.png | Bin .../Greenshot}/icons/shape_square_add.png | Bin .../icons/shape_square_bordercolor.png | Bin .../Greenshot}/icons/shape_square_delete.png | Bin .../icons/shape_square_fillcolor.png | Bin .../Greenshot}/icons/text_bold.png | Bin .../Greenshot}/icons/text_dropcaps.png | Bin .../Greenshot}/icons/text_italic.png | Bin .../Greenshot}/icons/text_underline.png | Bin .../Greenshot}/icons/textfield_delete.png | Bin {Greenshot => src/Greenshot}/icons/undo.png | Bin .../Greenshot}/icons/wand-hat.png | Bin {Greenshot => src/Greenshot}/icons/wrench.png | Bin .../Greenshot}/icons/wrench_orange.png | Bin {Greenshot => src/Greenshot}/icons/zoom.png | Bin .../Greenshot}/log4net-debug.xml | 0 .../Greenshot}/log4net-portable.xml | 0 {Greenshot => src/Greenshot}/log4net-zip.xml | 0 {Greenshot => src/Greenshot}/log4net.xml | 0 .../releases/additional_files/installer.txt | 0 .../releases/additional_files/license.txt | 0 .../releases/additional_files/readme.txt | 0 .../Greenshot}/releases/appinfo.ini.template | 0 .../releases/innosetup/IssProc/IssProc.dll | Bin .../innosetup/IssProc/IssProcLanguage.ini | Bin .../innosetup/Languages/Afrikaans.isl | 0 .../releases/innosetup/Languages/Albanian.isl | 0 .../releases/innosetup/Languages/Arabic.isl | 0 .../releases/innosetup/Languages/Asturian.isl | 0 .../releases/innosetup/Languages/Basque.isl | 0 .../innosetup/Languages/Belarusian.isl | 0 .../releases/innosetup/Languages/Bengali.islu | 0 .../releases/innosetup/Languages/Bosnian.isl | 0 .../innosetup/Languages/Bulgarian.isl | 0 .../innosetup/Languages/ChineseSimplified.isl | 0 .../Languages/ChineseTraditional.isl | 0 .../releases/innosetup/Languages/Croatian.isl | 0 .../innosetup/Languages/EnglishBritish.isl | 0 .../innosetup/Languages/Esperanto.isl | 0 .../releases/innosetup/Languages/Estonian.isl | 0 .../releases/innosetup/Languages/Farsi.isl | 0 .../releases/innosetup/Languages/Galician.isl | 0 .../innosetup/Languages/Georgian.islu | 0 .../releases/innosetup/Languages/Greek.isl | 0 .../releases/innosetup/Languages/Hindi.islu | 0 .../innosetup/Languages/Hungarian.isl | 0 .../innosetup/Languages/Indonesian.isl | 0 .../releases/innosetup/Languages/Kazakh.islu | 0 .../releases/innosetup/Languages/Korean.isl | 0 .../releases/innosetup/Languages/Kurdish.isl | 0 .../releases/innosetup/Languages/Latvian.isl | 0 .../releases/innosetup/Languages/Ligurian.isl | 0 .../innosetup/Languages/Lithuanian.isl | 0 .../innosetup/Languages/Luxemburgish.isl | 0 .../innosetup/Languages/Macedonian.isl | 0 .../innosetup/Languages/Malaysian.isl | 0 .../releases/innosetup/Languages/Marathi.islu | 0 .../innosetup/Languages/Mongolian.isl | 0 .../innosetup/Languages/Montenegrian.isl | 0 .../releases/innosetup/Languages/Nepali.islu | 0 .../innosetup/Languages/NorwegianNynorsk.isl | 0 .../releases/innosetup/Languages/Occitan.isl | 0 .../releases/innosetup/Languages/Romanian.isl | 0 .../innosetup/Languages/ScottishGaelic.isl | 0 .../innosetup/Languages/SerbianCyrillic.isl | 0 .../innosetup/Languages/SerbianLatin.isl | 0 .../releases/innosetup/Languages/Sinhala.islu | 0 .../releases/innosetup/Languages/Swedish.isl | 0 .../releases/innosetup/Languages/Tatar.isl | 0 .../releases/innosetup/Languages/Thai.isl | 0 .../releases/innosetup/Languages/Uyghur.islu | 0 .../releases/innosetup/Languages/Uzbek.isl | 0 .../innosetup/Languages/Valencian.isl | 0 .../innosetup/Languages/Vietnamese.isl | 0 .../releases/innosetup/installer-large.bmp | Bin .../releases/innosetup/installer-small.bmp | Bin .../innosetup/scripts/isxdl/chinese.ini | 0 .../innosetup/scripts/isxdl/czech.ini | 0 .../innosetup/scripts/isxdl/dutch.ini | 0 .../innosetup/scripts/isxdl/english.ini | 0 .../innosetup/scripts/isxdl/french.ini | 0 .../innosetup/scripts/isxdl/french2.ini | 0 .../innosetup/scripts/isxdl/french3.ini | 0 .../innosetup/scripts/isxdl/german.ini | 0 .../innosetup/scripts/isxdl/isxdl.dll | Bin .../innosetup/scripts/isxdl/isxdl.iss | 0 .../innosetup/scripts/isxdl/italian.ini | 0 .../innosetup/scripts/isxdl/japanese.ini | 0 .../innosetup/scripts/isxdl/korean.ini | 0 .../innosetup/scripts/isxdl/norwegian.ini | 0 .../innosetup/scripts/isxdl/polish.ini | 0 .../innosetup/scripts/isxdl/portugues.ini | 0 .../innosetup/scripts/isxdl/portuguese.ini | 0 .../innosetup/scripts/isxdl/russian.ini | 0 .../innosetup/scripts/isxdl/spanish.ini | 0 .../innosetup/scripts/isxdl/swedish.ini | 0 .../innosetup/scripts/lang/chinese.iss | 0 .../releases/innosetup/scripts/lang/dutch.iss | 0 .../innosetup/scripts/lang/english.iss | 0 .../innosetup/scripts/lang/french.iss | 0 .../innosetup/scripts/lang/german.iss | 0 .../innosetup/scripts/lang/italian.iss | 0 .../innosetup/scripts/lang/japanese.iss | 0 .../innosetup/scripts/lang/polish.iss | 0 .../innosetup/scripts/lang/russian.iss | 0 .../releases/innosetup/scripts/products.iss | 0 .../releases/innosetup/scripts/products.pas | 0 .../scripts/products/directxruntime.iss | 0 .../innosetup/scripts/products/dotnetfx11.iss | 0 .../scripts/products/dotnetfx11lp.iss | 0 .../scripts/products/dotnetfx11sp1.iss | 0 .../innosetup/scripts/products/dotnetfx20.iss | 0 .../scripts/products/dotnetfx20lp.iss | 0 .../scripts/products/dotnetfx20sp1.iss | 0 .../scripts/products/dotnetfx20sp1lp.iss | 0 .../scripts/products/dotnetfx20sp2.iss | 0 .../scripts/products/dotnetfx20sp2lp.iss | 0 .../innosetup/scripts/products/dotnetfx35.iss | 0 .../scripts/products/dotnetfx35lp.iss | 0 .../scripts/products/dotnetfx35sp1.iss | 0 .../scripts/products/dotnetfx35sp1lp.iss | 0 .../scripts/products/dotnetfx40client.iss | 0 .../scripts/products/dotnetfx40full.iss | 0 .../innosetup/scripts/products/dotnetfx45.iss | 0 .../innosetup/scripts/products/dotnetfx46.iss | 0 .../innosetup/scripts/products/dotnetfx47.iss | 0 .../innosetup/scripts/products/dotnetfx48.iss | 0 .../scripts/products/dotnetfxversion.iss | 0 .../scripts/products/fileversion.iss | 0 .../innosetup/scripts/products/ie6.iss | 0 .../innosetup/scripts/products/iis.iss | 0 .../innosetup/scripts/products/jet4sp8.iss | 0 .../innosetup/scripts/products/kb835732.iss | 0 .../innosetup/scripts/products/mdac28.iss | 0 .../innosetup/scripts/products/msi20.iss | 0 .../innosetup/scripts/products/msi31.iss | 0 .../innosetup/scripts/products/msi45.iss | 0 .../innosetup/scripts/products/msiproduct.iss | 0 .../scripts/products/sql2005express.iss | 0 .../scripts/products/sql2008express.iss | 0 .../scripts/products/sqlcompact35sp2.iss | 0 .../scripts/products/stringversion.iss | 0 .../scripts/products/vcredist2005.iss | 0 .../scripts/products/vcredist2008.iss | 0 .../scripts/products/vcredist2010.iss | 0 .../scripts/products/vcredist2012.iss | 0 .../scripts/products/vcredist2013.iss | 0 .../scripts/products/vcredist2015.iss | 0 .../scripts/products/vcredist2017.iss | 0 .../innosetup/scripts/products/wic.iss | 0 .../innosetup/scripts/products/winversion.iss | 0 .../Greenshot}/releases/innosetup/setup.iss | 0 .../releases/portable/App/AppInfo/appicon.ico | Bin .../portable/App/AppInfo/appicon_16.png | Bin .../portable/App/AppInfo/appicon_32.png | Bin .../App/DefaultData/Greenshots/dummy.txt | 0 .../App/DefaultData/Settings/dummy.txt | 0 .../portable/Data/Greenshot/dummy.txt | 0 .../releases/portable/Data/Settings/dummy.txt | 0 .../PortableApps.comInstallerCustom.nsh | 0 .../Greenshot}/sounds/camera.wav | Bin .../web/htdocs/Help/index.de-DE.html | 0 .../web/htdocs/Help/index.en-US.html | 0 .../Greenshot}/web/htdocs/favicon.ico | Bin .../Greenshot}/web/htdocs/index.html | 0 .../GreenshotBoxPlugin}/Box.png | Bin .../GreenshotBoxPlugin}/BoxConfiguration.cs | 0 .../GreenshotBoxPlugin}/BoxDestination.cs | 0 .../GreenshotBoxPlugin}/BoxEntities.cs | 0 .../GreenshotBoxPlugin}/BoxPlugin.cs | 0 .../GreenshotBoxPlugin}/BoxPlugin.resx | 0 .../GreenshotBoxPlugin}/BoxUtils.cs | 0 .../GreenshotBoxPlugin}/Forms/BoxForm.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../GreenshotBoxPlugin}/Forms/SettingsForm.cs | 0 .../GreenshotBoxPlugin.Credentials.template | 0 .../GreenshotBoxPlugin.csproj | 0 .../GreenshotBoxPlugin}/LanguageKeys.cs | 0 .../Languages/language_boxplugin-cs-CZ.xml | 0 .../Languages/language_boxplugin-de-DE.xml | 0 .../Languages/language_boxplugin-en-US.xml | 0 .../Languages/language_boxplugin-fr-FR.xml | 0 .../Languages/language_boxplugin-id-ID.xml | 0 .../Languages/language_boxplugin-it-IT.xml | 0 .../Languages/language_boxplugin-ja-JP.xml | 0 .../Languages/language_boxplugin-kab-DZ.xml | 0 .../Languages/language_boxplugin-ko-KR.xml | 0 .../Languages/language_boxplugin-lv-LV.xml | 0 .../Languages/language_boxplugin-pl-PL.xml | 0 .../Languages/language_boxplugin-pt-PT.xml | 0 .../Languages/language_boxplugin-ru-RU.xml | 0 .../Languages/language_boxplugin-sr-RS.xml | 0 .../Languages/language_boxplugin-sv-SE.xml | 0 .../Languages/language_boxplugin-uk-UA.xml | 0 .../Languages/language_boxplugin-zh-CN.xml | 0 .../Languages/language_boxplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../GreenshotConfluencePlugin}/Confluence.cs | 0 .../ConfluenceConfiguration.cs | 0 .../ConfluenceDestination.cs | 0 .../ConfluencePlugin.cs | 0 .../ConfluenceUtils.cs | 0 .../EnumDisplayer.cs | 0 .../Forms/ConfluenceConfigurationForm.xaml | 0 .../Forms/ConfluenceConfigurationForm.xaml.cs | 0 .../Forms/ConfluencePagePicker.xaml | 0 .../Forms/ConfluencePagePicker.xaml.cs | 0 .../Forms/ConfluenceSearch.xaml | 0 .../Forms/ConfluenceSearch.xaml.cs | 0 .../Forms/ConfluenceTreePicker.xaml | 0 .../Forms/ConfluenceTreePicker.xaml.cs | 0 .../Forms/ConfluenceUpload.xaml | 0 .../Forms/ConfluenceUpload.xaml.cs | 0 .../GreenshotConfluencePlugin.csproj | 0 .../Images/Confluence.ico | Bin .../LanguageKeys.cs | 0 .../language_confluenceplugin-cs-CZ.xml | 0 .../language_confluenceplugin-de-DE.xml | 0 .../language_confluenceplugin-en-US.xml | 0 .../language_confluenceplugin-fr-FR.xml | 0 .../language_confluenceplugin-id-ID.xml | 0 .../language_confluenceplugin-it-IT.xml | 0 .../language_confluenceplugin-ja-JP.xml | 0 .../language_confluenceplugin-kab-DZ.xml | 0 .../language_confluenceplugin-ko-KR.xml | 0 .../language_confluenceplugin-lv-LV.xml | 0 .../language_confluenceplugin-nl-NL.xml | 0 .../language_confluenceplugin-pl-PL.xml | 0 .../language_confluenceplugin-pt-PT.xml | 0 .../language_confluenceplugin-ru-RU.xml | 0 .../language_confluenceplugin-sr-RS.xml | 0 .../language_confluenceplugin-sv-SE.xml | 0 .../language_confluenceplugin-uk-UA.xml | 0 .../language_confluenceplugin-zh-CN.xml | 0 .../language_confluenceplugin-zh-TW.xml | 0 .../Support/ITranslationProvider.cs | 0 .../Support/LanguageChangedEventManager.cs | 0 .../Support/LanguageXMLTranslationProvider.cs | 0 .../Support/TranslateExtension.cs | 0 .../Support/TranslationData.cs | 0 .../Support/TranslationManager.cs | 0 .../Web References/confluence/Reference.cs | 0 .../Web References/confluence/Reference.map | 0 .../confluence/confluenceservice-v1.wsdl | 0 .../GreenshotDropboxPlugin}/Dropbox.gif | Bin .../DropboxDestination.cs | 0 .../GreenshotDropboxPlugin}/DropboxPlugin.cs | 0 .../DropboxPlugin.resx | 0 .../DropboxPluginConfiguration.cs | 0 .../GreenshotDropboxPlugin}/DropboxUtils.cs | 0 .../Forms/DropboxForm.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 ...reenshotDropboxPlugin.Credentials.template | 0 .../GreenshotDropboxPlugin.csproj | 0 .../GreenshotDropboxPlugin}/LanguageKeys.cs | 0 .../language_dropboxplugin-cs-CZ.xml | 0 .../language_dropboxplugin-de-DE.xml | 0 .../language_dropboxplugin-en-US.xml | 0 .../language_dropboxplugin-fr-FR.xml | 0 .../language_dropboxplugin-id-ID.xml | 0 .../language_dropboxplugin-it-IT.xml | 0 .../language_dropboxplugin-ja-JP.xml | 0 .../language_dropboxplugin-kab-DZ.xml | 0 .../language_dropboxplugin-ko-KR.xml | 0 .../language_dropboxplugin-lv-LV.xml | 0 .../language_dropboxplugin-pl-PL.xml | 0 .../language_dropboxplugin-pt-PT.xml | 0 .../language_dropboxplugin-ru-RU.xml | 0 .../language_dropboxplugin-sr-RS.xml | 0 .../language_dropboxplugin-sv-SE.xml | 0 .../language_dropboxplugin-uk-UA.xml | 0 .../language_dropboxplugin-zh-CN.xml | 0 .../language_dropboxplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../ExternalCommandConfiguration.cs | 0 .../ExternalCommandDestination.cs | 0 .../ExternalCommandForm.cs | 0 .../ExternalCommandPlugin.cs | 0 .../GreenshotExternalCommandPlugin.csproj | 0 .../IconCache.cs | 0 .../language_externalcommandplugin-cs-CZ.xml | 0 .../language_externalcommandplugin-de-DE.xml | 0 .../language_externalcommandplugin-en-US.xml | 0 .../language_externalcommandplugin-fr-FR.xml | 0 .../language_externalcommandplugin-id-ID.xml | 0 .../language_externalcommandplugin-it-IT.xml | 0 .../language_externalcommandplugin-ja-JP.xml | 0 .../language_externalcommandplugin-kab-DZ.xml | 0 .../language_externalcommandplugin-ko-KR.xml | 0 .../language_externalcommandplugin-lv-LV.xml | 0 .../language_externalcommandplugin-pl-PL.xml | 0 .../language_externalcommandplugin-pt-PT.xml | 0 .../language_externalcommandplugin-ru-RU.xml | 0 .../language_externalcommandplugin-sk-SK.xml | 0 .../language_externalcommandplugin-sr-RS.xml | 0 .../language_externalcommandplugin-sv-SE.xml | 0 .../language_externalcommandplugin-uk-UA.xml | 0 .../language_externalcommandplugin-zh-CN.xml | 0 .../language_externalcommandplugin-zh-TW.xml | 0 .../SettingsForm.Designer.cs | 0 .../SettingsForm.cs | 0 .../SettingsFormDetail.Designer.cs | 0 .../SettingsFormDetail.cs | 0 .../FlickrConfiguration.cs | 0 .../FlickrDestination.cs | 0 .../GreenshotFlickrPlugin}/FlickrPlugin.cs | 0 .../GreenshotFlickrPlugin}/FlickrPlugin.resx | 0 .../GreenshotFlickrPlugin}/FlickrUtils.cs | 0 .../Forms/FlickrForm.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 ...GreenshotFlickrPlugin.Credentials.template | 0 .../GreenshotFlickrPlugin.csproj | 0 .../GreenshotFlickrPlugin}/LanguageKeys.cs | 0 .../Languages/language_flickrplugin-cs-CZ.xml | 0 .../Languages/language_flickrplugin-de-DE.xml | 0 .../Languages/language_flickrplugin-en-US.xml | 0 .../Languages/language_flickrplugin-fr-FR.xml | 0 .../Languages/language_flickrplugin-id-ID.xml | 0 .../Languages/language_flickrplugin-it-IT.xml | 0 .../Languages/language_flickrplugin-ja-JP.xml | 0 .../language_flickrplugin-kab-DZ.xml | 0 .../Languages/language_flickrplugin-ko-KR.xml | 0 .../Languages/language_flickrplugin-lv-LV.xml | 0 .../Languages/language_flickrplugin-pl-PL.xml | 0 .../Languages/language_flickrplugin-pt-PT.xml | 0 .../Languages/language_flickrplugin-ru-RU.xml | 0 .../Languages/language_flickrplugin-sr-RS.xml | 0 .../Languages/language_flickrplugin-sv-SE.xml | 0 .../Languages/language_flickrplugin-uk-UA.xml | 0 .../Languages/language_flickrplugin-zh-CN.xml | 0 .../Languages/language_flickrplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../GreenshotFlickrPlugin}/flickr.png | Bin .../Forms/GooglePhotosForm.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 .../GooglePhotos.png | Bin .../GooglePhotosConfiguration.cs | 0 .../GooglePhotosDestination.cs | 0 .../GooglePhotosPlugin.cs | 0 .../GooglePhotosPlugin.resx | 0 .../GooglePhotosUtils.cs | 0 ...hotGooglePhotosPlugin.Credentials.template | 0 .../GreenshotGooglePhotosPlugin.csproj | 0 .../LanguageKeys.cs | 0 .../language_googlephotosplugin-cs-CZ.xml | 0 .../language_googlephotosplugin-de-DE.xml | 0 .../language_googlephotosplugin-en-US.xml | 0 .../language_googlephotosplugin-fr-FR.xml | 0 .../language_googlephotosplugin-id-ID.xml | 0 .../language_googlephotosplugin-it-IT.xml | 0 .../language_googlephotosplugin-ja-JP.xml | 0 .../language_googlephotosplugin-kab-DZ.xml | 0 .../language_googlephotosplugin-ko-KR.xml | 0 .../language_googlephotosplugin-lv-LV.xml | 0 .../language_googlephotosplugin-pl-PL.xml | 0 .../language_googlephotosplugin-pt-PT.xml | 0 .../language_googlephotosplugin-ru-RU.xml | 0 .../language_googlephotosplugin-sr-RS.xml | 0 .../language_googlephotosplugin-sv-SE.xml | 0 .../language_googlephotosplugin-uk-UA.xml | 0 .../language_googlephotosplugin-zh-CN.xml | 0 .../language_googlephotosplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../GreenshotGooglePhotosPlugin}/README | 0 .../GreenshotImgurPlugin}/Forms/ImgurForm.cs | 0 .../Forms/ImgurHistory.Designer.cs | 0 .../Forms/ImgurHistory.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 .../GreenshotImgurPlugin.Credentials.template | 0 .../GreenshotImgurPlugin.csproj | 0 .../ImgurConfiguration.cs | 0 .../GreenshotImgurPlugin}/ImgurDestination.cs | 0 .../GreenshotImgurPlugin}/ImgurInfo.cs | 0 .../GreenshotImgurPlugin}/ImgurPlugin.cs | 0 .../GreenshotImgurPlugin}/ImgurPlugin.resx | 0 .../GreenshotImgurPlugin}/ImgurUtils.cs | 0 .../GreenshotImgurPlugin}/LanguageKeys.cs | 0 .../Languages/language_imgurplugin-cs-CZ.xml | 0 .../Languages/language_imgurplugin-de-DE.xml | 0 .../Languages/language_imgurplugin-en-US.xml | 0 .../Languages/language_imgurplugin-fr-FR.xml | 0 .../Languages/language_imgurplugin-id-ID.xml | 0 .../Languages/language_imgurplugin-it-IT.xml | 0 .../Languages/language_imgurplugin-ja-JP.xml | 0 .../Languages/language_imgurplugin-kab-DZ.xml | 0 .../Languages/language_imgurplugin-ko-KR.xml | 0 .../Languages/language_imgurplugin-lv-LV.xml | 0 .../Languages/language_imgurplugin-nl-NL.xml | 0 .../Languages/language_imgurplugin-pl-PL.xml | 0 .../Languages/language_imgurplugin-pt-PT.xml | 0 .../Languages/language_imgurplugin-ru-RU.xml | 0 .../Languages/language_imgurplugin-sk-SK.xml | 0 .../Languages/language_imgurplugin-sr-RS.xml | 0 .../Languages/language_imgurplugin-sv-SE.xml | 0 .../Languages/language_imgurplugin-uk-UA.xml | 0 .../Languages/language_imgurplugin-zh-CN.xml | 0 .../Languages/language_imgurplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../GreenshotJiraPlugin}/AsyncMemoryCache.cs | 0 .../Forms/JiraForm.Designer.cs | 0 .../GreenshotJiraPlugin}/Forms/JiraForm.cs | 0 .../Forms/JiraFormBase.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 .../GreenshotJiraPlugin.csproj | 0 .../IssueTypeBitmapCache.cs | 0 .../GreenshotJiraPlugin}/JiraConfiguration.cs | 0 .../GreenshotJiraPlugin}/JiraConnector.cs | 0 .../GreenshotJiraPlugin}/JiraDestination.cs | 0 .../GreenshotJiraPlugin}/JiraDetails.cs | 0 .../GreenshotJiraPlugin}/JiraEventArgs.cs | 0 .../GreenshotJiraPlugin}/JiraEventTypes.cs | 0 .../GreenshotJiraPlugin}/JiraMonitor.cs | 0 .../GreenshotJiraPlugin}/JiraPlugin.cs | 0 .../GreenshotJiraPlugin}/JiraPlugin.resx | 0 .../GreenshotJiraPlugin}/LanguageKeys.cs | 0 .../Languages/language_jiraplugin-cs-CZ.xml | 0 .../Languages/language_jiraplugin-de-DE.xml | 0 .../Languages/language_jiraplugin-en-US.xml | 0 .../Languages/language_jiraplugin-fr-FR.xml | 0 .../Languages/language_jiraplugin-id-ID.xml | 0 .../Languages/language_jiraplugin-it-IT.xml | 0 .../Languages/language_jiraplugin-ja-JP.xml | 0 .../Languages/language_jiraplugin-kab-DZ.xml | 0 .../Languages/language_jiraplugin-ko-KR.xml | 0 .../Languages/language_jiraplugin-lv-LV.xml | 0 .../Languages/language_jiraplugin-nl-NL.xml | 0 .../Languages/language_jiraplugin-pl-PL.xml | 0 .../Languages/language_jiraplugin-pt-PT.xml | 0 .../Languages/language_jiraplugin-ru-RU.xml | 0 .../Languages/language_jiraplugin-sr-RS.xml | 0 .../Languages/language_jiraplugin-sv-SE.xml | 0 .../Languages/language_jiraplugin-uk-UA.xml | 0 .../Languages/language_jiraplugin-zh-CN.xml | 0 .../Languages/language_jiraplugin-zh-TW.xml | 0 .../GreenshotJiraPlugin}/Log4NetLogger.cs | 0 .../Com/DisposableCom.cs | 0 .../Com/DisposableComImplementation.cs | 0 .../Com/IDisposableCom.cs | 0 .../GreenshotOfficePlugin}/Com/Ole32Api.cs | 0 .../GreenshotOfficePlugin}/Com/OleAut32Api.cs | 0 .../Destinations/ExcelDestination.cs | 0 .../Destinations/OneNoteDestination.cs | 0 .../Destinations/OutlookDestination.cs | 0 .../Destinations/PowerpointDestination.cs | 0 .../Destinations/WordDestination.cs | 0 .../GlobalSuppressions.cs | Bin .../GreenshotOfficePlugin.csproj | 0 .../Languages/language_officeplugin-fr-FR.ini | 0 .../OfficeConfiguration.cs | 0 .../OfficeExport/Entities/OneNoteNotebook.cs | 0 .../OfficeExport/Entities/OneNotePage.cs | 0 .../OfficeExport/Entities/OneNoteSection.cs | 0 .../OfficeExport/ExcelExporter.cs | 0 .../OfficeExport/OneNoteExporter.cs | 0 .../OfficeExport/OutlookEmailExporter.cs | 0 .../OfficeExport/PowerpointExporter.cs | 0 .../OfficeExport/WordExporter.cs | 0 .../OfficeInterop/EmailFormat.cs | 0 .../OfficeInterop/OfficeVersions.cs | 0 .../GreenshotOfficePlugin}/OfficePlugin.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../Forms/PhotobucketForm.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 ...shotPhotobucketPlugin.Credentials.template | 0 .../GreenshotPhotobucketPlugin.csproj | 0 .../LanguageKeys.cs | 0 .../language_photobucketplugin-cs-CZ.xml | 0 .../language_photobucketplugin-de-DE.xml | 0 .../language_photobucketplugin-en-US.xml | 0 .../language_photobucketplugin-fr_FR.xml | 0 .../language_photobucketplugin-id-ID.xml | 0 .../language_photobucketplugin-it-IT.xml | 0 .../language_photobucketplugin-ja-JP.xml | 0 .../language_photobucketplugin-kab-DZ.xml | 0 .../language_photobucketplugin-ko-KR.xml | 0 .../language_photobucketplugin-lv-LV.xml | 0 .../language_photobucketplugin-nl-NL.xml | 0 .../language_photobucketplugin-pl-PL.xml | 0 .../language_photobucketplugin-pt-PT.xml | 0 .../language_photobucketplugin-ru-RU.xml | 0 .../language_photobucketplugin-sv-SE.xml | 0 .../language_photobucketplugin-uk-UA.xml | 0 .../language_photobucketplugin-zh-CN.xml | 0 .../language_photobucketplugin-zh-TW.xml | 0 .../PhotobucketConfiguration.cs | 0 .../PhotobucketDestination.cs | 0 .../PhotobucketInfo.cs | 0 .../PhotobucketPlugin.cs | 0 .../PhotobucketPlugin.resx | 0 .../PhotobucketUtils.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../Controls/AnimatingForm.cs | 0 .../Controls/BackgroundForm.Designer.cs | 0 .../Controls/BackgroundForm.cs | 0 .../Controls/ExtendedWebBrowser.cs | 0 .../Controls/FormWithoutActivation.cs | 0 .../Controls/GreenshotButton.cs | 0 .../Controls/GreenshotCheckBox.cs | 0 .../Controls/GreenshotColumnSorter.cs | 0 .../Controls/GreenshotComboBox.cs | 0 .../Controls/GreenshotForm.cs | 0 .../Controls/GreenshotGroupBox.cs | 0 .../Controls/GreenshotLabel.cs | 0 .../Controls/GreenshotRadioButton.cs | 0 .../Controls/GreenshotTabPage.cs | 0 .../Controls/GreenshotTextBox.cs | 0 .../Controls/GreenshotToolDropDownButton.cs | 0 .../Controls/GreenshotToolStripButton.cs | 0 .../Controls/GreenshotToolStripLabel.cs | 0 .../Controls/GreenshotToolStripMenuItem.cs | 0 .../Controls/HotkeyControl.cs | 0 .../Controls/IGreenshotConfigBindable.cs | 0 .../Controls/IGreenshotLanguageBindable.cs | 0 .../Controls/OAuthLoginForm.Designer.cs | 0 .../Controls/OAuthLoginForm.cs | 0 .../Controls/PleaseWaitForm.Designer.cs | 0 .../Controls/PleaseWaitForm.cs | 0 .../Controls/QualityDialog.Designer.cs | 0 .../Controls/QualityDialog.cs | 0 .../Controls/SaveImageFileDialog.cs | 0 .../Controls/ThumbnailForm.cs | 0 .../Core/AbstractDestination.cs | 0 .../Core/AbstractProcessor.cs | 0 .../GreenshotPlugin}/Core/AccessibleHelper.cs | 0 .../GreenshotPlugin}/Core/AnimationHelpers.cs | 0 .../Core/BinaryStructHelper.cs | 0 .../GreenshotPlugin}/Core/Cache.cs | 0 .../GreenshotPlugin}/Core/Capture.cs | 0 .../GreenshotPlugin}/Core/CaptureDetails.cs | 0 .../GreenshotPlugin}/Core/CaptureHandler.cs | 0 .../GreenshotPlugin}/Core/ClipboardHelper.cs | 0 .../Core/CoreConfiguration.cs | 0 .../Core/CredentialsHelper.cs | 0 .../Core/DisplayKeyAttribute.cs | 0 .../GreenshotPlugin}/Core/DpiHelper.cs | 0 .../GreenshotPlugin}/Core/EffectConverter.cs | 0 .../GreenshotPlugin}/Core/Enums/HResult.cs | 0 .../Core/Enums/MonitorDpiType.cs | 0 .../Core/Enums/MonitorFrom.cs | 0 .../GreenshotPlugin}/Core/EnvironmentInfo.cs | 0 .../GreenshotPlugin}/Core/EventDelay.cs | 0 .../GreenshotPlugin}/Core/ExplorerHelper.cs | 0 .../GreenshotPlugin}/Core/FastBitmap.cs | 0 .../GreenshotPlugin}/Core/FilenameHelper.cs | 0 .../GreenshotPlugin}/Core/Fraction.cs | 0 .../Core/GreenshotResources.cs | 0 .../Core/GreenshotResources.resx | 0 .../Core/HResultExtensions.cs | 0 .../GreenshotPlugin}/Core/IEHelper.cs | 0 .../GreenshotPlugin}/Core/IImage.cs | 0 .../GreenshotPlugin}/Core/ImageHelper.cs | 0 .../GreenshotPlugin}/Core/ImageOutput.cs | 0 .../GreenshotPlugin}/Core/ImageWrapper.cs | 0 .../GreenshotPlugin}/Core/InterfaceUtils.cs | 0 .../GreenshotPlugin}/Core/JSONHelper.cs | 0 .../GreenshotPlugin}/Core/Language.cs | 0 .../Core/LanguageChangedHandler.cs | 0 .../GreenshotPlugin}/Core/LanguageFile.cs | 0 .../GreenshotPlugin}/Core/LogHelper.cs | 0 .../GreenshotPlugin}/Core/NetworkHelper.cs | 0 .../Core/OAuth/LocalJsonReceiver.cs | 0 .../Core/OAuth/LocalServerCodeReceiver.cs | 0 .../Core/OAuth/OAuth2AuthorizeMode.cs | 0 .../Core/OAuth/OAuth2Helper.cs | 0 .../Core/OAuth/OAuth2Settings.cs | 0 .../Core/OAuth/OAuthSession.cs | 0 .../Core/OAuth/OAuthSignatureTypes.cs | 0 .../GreenshotPlugin}/Core/ObjectExtensions.cs | 0 .../GreenshotPlugin}/Core/PluginUtils.cs | 0 .../GreenshotPlugin}/Core/QuantizerHelper.cs | 0 .../Core/RegistryKeyExtensions.cs | 0 .../Core/SimpleServiceProvider.cs | 0 .../GreenshotPlugin}/Core/StringExtensions.cs | 0 .../GreenshotPlugin}/Core/SvgImage.cs | 0 .../GreenshotPlugin}/Core/WindowCapture.cs | 0 .../GreenshotPlugin}/Core/WindowDetails.cs | 0 .../Core/WindowsEnumerator.cs | 0 .../GreenshotPlugin}/Core/WindowsVersion.cs | 0 .../Core/WmInputLangChangeRequestFilter.cs | 0 .../GreenshotPlugin}/Effects/AdjustEffect.cs | 0 .../GreenshotPlugin}/Effects/BorderEffect.cs | 0 .../Effects/DropShadowEffect.cs | 0 .../Effects/GrayscaleEffect.cs | 0 .../GreenshotPlugin}/Effects/IEffect.cs | 0 .../GreenshotPlugin}/Effects/InvertEffect.cs | 0 .../Effects/MonochromeEffect.cs | 0 .../Effects/ReduceColorsEffect.cs | 0 .../Effects/ResizeCanvasEffect.cs | 0 .../GreenshotPlugin}/Effects/ResizeEffect.cs | 0 .../GreenshotPlugin}/Effects/RotateEffect.cs | 0 .../Effects/TornEdgeEffect.cs | 0 .../GreenshotPlugin}/FileDescriptorReader.cs | 0 .../GreenshotPlugin}/GlobalSuppressions.cs | Bin .../GreenshotPlugin}/GreenshotPlugin.csproj | 0 .../Hooking/WindowsEventHook.cs | 0 .../Hooking/WindowsOpenCloseMonitor.cs | 0 .../Hooking/WindowsTitleMonitor.cs | 0 .../IEInterop/IHTMLBodyElement.cs | 0 .../IEInterop/IHTMLCurrentStyle.cs | 0 .../IEInterop/IHTMLDocument.cs | 0 .../IEInterop/IHTMLDocument2.cs | 0 .../IEInterop/IHTMLDocument3.cs | 0 .../IEInterop/IHTMLDocument4.cs | 0 .../IEInterop/IHTMLDocument5.cs | 0 .../IEInterop/IHTMLElement.cs | 0 .../IEInterop/IHTMLElement2.cs | 0 .../IEInterop/IHTMLElementCollection.cs | 0 .../IEInterop/IHTMLFrameBase.cs | 0 .../IEInterop/IHTMLFramesCollection2.cs | 0 .../GreenshotPlugin}/IEInterop/IHTMLRect.cs | 0 .../GreenshotPlugin}/IEInterop/IHTMLScreen.cs | 0 .../IEInterop/IHTMLScreen2.cs | 0 .../IEInterop/IHTMLSelectionObject.cs | 0 .../GreenshotPlugin}/IEInterop/IHTMLStyle.cs | 0 .../IEInterop/IHTMLTxtRange.cs | 0 .../IEInterop/IHTMLWindow2.cs | 0 .../IEInterop/IHTMLWindow3.cs | 0 .../IEInterop/IHTMLWindow4.cs | 0 .../IEInterop/IWebBrowser2.cs | 0 .../GreenshotPlugin}/IniFile/IniAttributes.cs | 0 .../GreenshotPlugin}/IniFile/IniConfig.cs | 0 .../GreenshotPlugin}/IniFile/IniReader.cs | 0 .../GreenshotPlugin}/IniFile/IniSection.cs | 0 .../GreenshotPlugin}/IniFile/IniValue.cs | 0 .../Interfaces/CaptureMode.cs | 0 .../Interfaces/Drawing/Adorners/IAdorner.cs | 0 .../Interfaces/Drawing/Container.cs | 0 .../Interfaces/Drawing/IField.cs | 0 .../Interfaces/Drawing/IFieldholder.cs | 0 .../Interfaces/Drawing/IMemento.cs | 0 .../Interfaces/DrawingModes.cs | 0 .../Interfaces/Forms/ImageEditor.cs | 0 .../GreenshotPlugin}/Interfaces/ICapture.cs | 0 .../Interfaces/ICaptureDetails.cs | 0 .../Interfaces/IDestination.cs | 0 .../Interfaces/INotificationService.cs | 0 .../GreenshotPlugin}/Interfaces/IProcessor.cs | 0 .../Interfaces/IServiceLocator.cs | 0 .../GreenshotPlugin}/Interfaces/ISurface.cs | 0 .../Interfaces/Ocr/IOcrProvider.cs | 0 .../GreenshotPlugin}/Interfaces/Ocr/Line.cs | 0 .../Interfaces/Ocr/OcrInformation.cs | 0 .../GreenshotPlugin}/Interfaces/Ocr/Word.cs | 0 .../Interfaces/Plugin/HotKeyHandler.cs | 0 .../Interfaces/Plugin/IGreenshotHost.cs | 0 .../Interfaces/Plugin/IGreenshotPlugin.cs | 0 .../Interfaces/Plugin/PluginAttribute.cs | 0 .../Plugin/SurfaceOutputSettings.cs | 0 .../Interfaces/ScreenCaptureMode.cs | 0 .../Interfaces/SurfaceDrawingModeEventArgs.cs | 0 .../SurfaceDrawingModeEventHandler.cs | 0 .../Interfaces/SurfaceElementEventArgs.cs | 0 .../Interfaces/SurfaceElementEventHandler.cs | 0 .../Interfaces/SurfaceMessageEventArgs.cs | 0 .../Interfaces/SurfaceMessageEventHandler.cs | 0 .../Interfaces/SurfaceMessageTyp.cs | 0 .../SurfaceSizeChangeEventHandler.cs | 0 .../GreenshotPlugin}/Interop/Base.cs | 0 .../GreenshotPlugin}/Interop/COMWrapper.cs | 0 .../Interop/ComProgIdAttribute.cs | 0 .../Interop/IAppVisibility.cs | 0 .../GreenshotPlugin}/Interop/IDispatch.cs | 0 .../Interop/IOleCommandTarget.cs | 0 .../GreenshotPlugin}/Interop/IOleWindow.cs | 0 .../Interop/IServiceProvider.cs | 0 .../GreenshotPlugin}/Interop/IUnknown.cs | 0 .../GreenshotPlugin}/UnmanagedHelpers/DWM.cs | 0 .../UnmanagedHelpers/EnumWindowsProc.cs | 0 .../UnmanagedHelpers/Enums/ClassLongIndex.cs | 0 .../Enums/DWMWINDOWATTRIBUTE.cs | 0 .../Enums/DWM_THUMBNAIL_PROPERTIES.cs | 0 .../Enums/DesktopAccessRight.cs | 0 .../UnmanagedHelpers/Enums/DeviceCaps.cs | 0 .../UnmanagedHelpers/Enums/EventObjects.cs | 0 .../Enums/ExtendedWindowStyleFlags.cs | 0 .../Enums/ProcessAccessFlags.cs | 0 .../UnmanagedHelpers/Enums/RegionResult.cs | 0 .../Enums/SendMessageTimeoutFlags.cs | 0 .../Enums/ShowWindowCommand.cs | 0 .../UnmanagedHelpers/Enums/SoundFlags.cs | 0 .../UnmanagedHelpers/Enums/ThreadAccess.cs | 0 .../UnmanagedHelpers/Enums/Win32Error.cs | 0 .../UnmanagedHelpers/Enums/WinEvent.cs | 0 .../Enums/WinEventHookFlags.cs | 0 .../UnmanagedHelpers/Enums/WindowLongIndex.cs | 0 .../Enums/WindowPlacementFlags.cs | 0 .../UnmanagedHelpers/Enums/WindowPos.cs | 0 .../Enums/WindowStyleFlags.cs | 0 .../UnmanagedHelpers/Enums/WindowsMessages.cs | 0 .../UnmanagedHelpers/GDI32.cs | 0 .../UnmanagedHelpers/GDIplus.cs | 0 .../UnmanagedHelpers/Kernel32.cs | 0 .../UnmanagedHelpers/PsAPI.cs | 0 .../SafeCurrentInputDesktopHandle.cs | 0 .../UnmanagedHelpers/SafeIconHandle.cs | 0 .../UnmanagedHelpers/SafeWindowDcHandle.cs | 0 .../UnmanagedHelpers/Shell32.cs | 0 .../UnmanagedHelpers/Structs/CursorInfo.cs | 0 .../UnmanagedHelpers/Structs/IconInfo.cs | 0 .../UnmanagedHelpers/Structs/POINT.cs | 0 .../UnmanagedHelpers/Structs/RECT.cs | 0 .../UnmanagedHelpers/Structs/RECTF.cs | 0 .../UnmanagedHelpers/Structs/SCROLLINFO.cs | 0 .../UnmanagedHelpers/Structs/SIZE.cs | 0 .../UnmanagedHelpers/Structs/WindowInfo.cs | 0 .../Structs/WindowPlacement.cs | 0 .../UnmanagedHelpers/User32.cs | 0 .../UnmanagedHelpers/Win32.cs | 0 .../UnmanagedHelpers/WinEventDelegate.cs | 0 .../UnmanagedHelpers/WinMM.cs | 0 .../GreenshotPlugin}/log4net-embedded.xml | 0 .../Destinations/Win10OcrDestination.cs | 0 .../Destinations/Win10ShareDestination.cs | 0 .../GreenshotWin10Plugin.csproj | 0 .../Internal/MemoryRandomAccessStream.cs | 0 .../Internal/ShareInfo.cs | 0 .../Native/DataTransferManagerHelper.cs | 0 .../Native/IDataTransferManagerInterOp.cs | 0 .../Processors/Win10OcrProcessor.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ToastNotificationService.cs | 0 .../Win10Configuration.cs | 0 .../GreenshotWin10Plugin}/Win10OcrProvider.cs | 0 .../GreenshotWin10Plugin}/Win10Plugin.cs | 0 src/version.json | 21 +++ 1067 files changed, 408 insertions(+) create mode 100644 src/.editorconfig create mode 100644 src/Directory.Build.props create mode 100644 src/Directory.Build.targets create mode 100644 src/Greenshot.sln create mode 100644 src/Greenshot.sln.DotSettings rename {Greenshot => src/Greenshot}/App.config (100%) rename {Greenshot => src/Greenshot}/Configuration/EditorConfiguration.cs (100%) rename {Greenshot => src/Greenshot}/Configuration/LanguageKeys.cs (100%) rename {Greenshot => src/Greenshot}/Controls/BindableToolStripButton.cs (100%) rename {Greenshot => src/Greenshot}/Controls/BindableToolStripComboBox.cs (100%) rename {Greenshot => src/Greenshot}/Controls/BindableToolStripDropDownButton.cs (100%) rename {Greenshot => src/Greenshot}/Controls/ColorButton.cs (100%) rename {Greenshot => src/Greenshot}/Controls/ContextMenuToolStripProfessionalRenderer.cs (100%) rename {Greenshot => src/Greenshot}/Controls/CustomToolStripProfessionalRenderer.cs (100%) rename {Greenshot => src/Greenshot}/Controls/FontFamilyComboBox.cs (100%) rename {Greenshot => src/Greenshot}/Controls/MenuStripEx.cs (100%) rename {Greenshot => src/Greenshot}/Controls/NonJumpingPanel.cs (100%) rename {Greenshot => src/Greenshot}/Controls/Pipette.cs (100%) rename {Greenshot => src/Greenshot}/Controls/ToolStripColorButton.cs (100%) rename {Greenshot => src/Greenshot}/Controls/ToolStripEx.cs (100%) rename {Greenshot => src/Greenshot}/Controls/ToolStripNumericUpDown.cs (100%) rename {Greenshot => src/Greenshot}/Destinations/ClipboardDestination.cs (100%) rename {Greenshot => src/Greenshot}/Destinations/EditorDestination.cs (100%) rename {Greenshot => src/Greenshot}/Destinations/EmailDestination.cs (100%) rename {Greenshot => src/Greenshot}/Destinations/FileDestination.cs (100%) rename {Greenshot => src/Greenshot}/Destinations/FileWithDialogDestination.cs (100%) rename {Greenshot => src/Greenshot}/Destinations/PickerDestination.cs (100%) rename {Greenshot => src/Greenshot}/Destinations/PrinterDestination.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Adorners/AbstractAdorner.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Adorners/MoveAdorner.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Adorners/ResizeAdorner.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Adorners/TargetAdorner.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/ArrowContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/CropContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/CursorContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/DrawableContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/DrawableContainerList.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/EllipseContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/AbstractFieldHolder.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/AbstractFieldHolderWithChildren.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/AbstractBindingConverter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/BidirectionalBinding.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/DecimalFloatConverter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/DecimalIntConverter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/IBindingConverter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/IBindingValidator.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/NotNullValidator.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/Field.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/FieldAggregator.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Fields/FieldType.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/FilterContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Filters/AbstractFilter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Filters/BlurFilter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Filters/BrightnessFilter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Filters/GrayscaleFilter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Filters/HighlightFilter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Filters/IFilter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Filters/MagnifierFilter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Filters/PixelizationFilter.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/FreehandContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/HighlightContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/IconContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/ImageContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/LineContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/ObfuscateContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Positions.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/RectangleContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/SpeechbubbleContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/StepLabelContainer.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/Surface.cs (100%) rename {Greenshot => src/Greenshot}/Drawing/TextContainer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/AboutForm.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/AboutForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/AnimatingBaseForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/BaseForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/BugReportForm.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/BugReportForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/CaptureForm.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/CaptureForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/ColorDialog.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/ColorDialog.cs (100%) rename {Greenshot => src/Greenshot}/Forms/ColorDialog.resx (100%) rename {Greenshot => src/Greenshot}/Forms/ColorPickerToolStripButton.cs (100%) rename {Greenshot => src/Greenshot}/Forms/DropShadowSettingsForm.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/DropShadowSettingsForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/ImageEditorForm.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/ImageEditorForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/ImageEditorForm.resx (100%) rename {Greenshot => src/Greenshot}/Forms/LanguageDialog.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/LanguageDialog.cs (100%) rename {Greenshot => src/Greenshot}/Forms/MainForm.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/MainForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/MainForm.resx (100%) rename {Greenshot => src/Greenshot}/Forms/MovableShowColorForm.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/MovableShowColorForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/PrintOptionsDialog.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/PrintOptionsDialog.cs (100%) rename {Greenshot => src/Greenshot}/Forms/ResizeSettingsForm.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/ResizeSettingsForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/SettingsForm.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/SettingsForm.cs (100%) rename {Greenshot => src/Greenshot}/Forms/SettingsForm.resx (100%) rename {Greenshot => src/Greenshot}/Forms/ToolStripMenuSelectList.cs (100%) rename {Greenshot => src/Greenshot}/Forms/TornEdgeSettingsForm.Designer.cs (100%) rename {Greenshot => src/Greenshot}/Forms/TornEdgeSettingsForm.cs (100%) rename {Greenshot => src/Greenshot}/Greenshot.csproj (100%) rename {Greenshot => src/Greenshot}/GreenshotMain.cs (100%) rename {Greenshot => src/Greenshot}/Help/HelpFileLoader.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/CaptureHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/Colors.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/CopyData.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/DestinationHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/Entities/UpdateFeed.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/GeometryHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/GuiRectangle.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/IECaptureHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/IEInterop/IEContainer.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/MailHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/NotifyIconNotificationService.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/PluginHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/PrintHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/ProcessorHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/ResourceMutex.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/ScaleHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/SoundHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/StartupHelper.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/ToolStripItemEndisabler.cs (100%) rename {Greenshot => src/Greenshot}/Helpers/UpdateService.cs (100%) rename {Greenshot => src/Greenshot}/Languages/help-de-DE.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-en-US.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-es-ES.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-fr-FR.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-hu-HU.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-it-IT.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-ko-KR.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-nl-NL.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-nn-NO.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-pl-PL.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-pt-BR.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-pt-PT.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-ru-RU.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-sv-SE.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-tr-TR.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-zh-CN.html (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-de-DE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-en-US.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-es-ES.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-fi-FI.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-fr-FR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-it-IT.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-lv-LV.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-nl-NL.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-nn-NO.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-sr-RS.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-sv-SE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-uk-UA.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-zh-CN.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ar-SY.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ca-CA.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-cs-CZ.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-da-DK.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-de-DE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-de-x-franconia.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-el-GR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-en-US.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-es-ES.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-et-EE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-fa-IR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-fi-FI.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-fr-FR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-fr-QC.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-he-IL.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-hu-HU.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-id-ID.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-it-IT.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ja-JP.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-kab-DZ.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ko-KR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-lt-LT.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-lv-LV.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-nl-NL.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-nn-NO.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-pl-PL.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-pt-BR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-pt-PT.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ro-RO.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ru-RU.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-sk-SK.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-sl-SI.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-sr-RS.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-sv-SE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-tr-TR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-uk-UA.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-vi-VN.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-zh-CN.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-zh-TW.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-de-DE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-en-US.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-es-ES.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-fr-FR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-it-IT.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-lv-LV.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-nn-NO.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-pt-BR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-sv-SE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-uk-UA.xml (100%) rename {Greenshot => src/Greenshot}/Memento/AddElementMemento.cs (100%) rename {Greenshot => src/Greenshot}/Memento/AddElementsMemento.cs (100%) rename {Greenshot => src/Greenshot}/Memento/ChangeFieldHolderMemento.cs (100%) rename {Greenshot => src/Greenshot}/Memento/DeleteElementMemento.cs (100%) rename {Greenshot => src/Greenshot}/Memento/DeleteElementsMemento.cs (100%) rename {Greenshot => src/Greenshot}/Memento/DrawableContainerBoundsChangeMemento.cs (100%) rename {Greenshot => src/Greenshot}/Memento/SurfaceBackgroundChangeMemento.cs (100%) rename {Greenshot => src/Greenshot}/Memento/TextChangeMemento.cs (100%) rename {Greenshot => src/Greenshot}/Processors/TitleFixProcessor.cs (100%) rename {Greenshot => src/Greenshot}/Sounds.resx (100%) rename {Greenshot => src/Greenshot}/greenshot.manifest (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/16.ico (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/16.png (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/32.ico (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/32.png (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/48.ico (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/48.png (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/90.png (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/icon.ico (100%) rename {Greenshot => src/Greenshot}/icons/arrow_redo.png (100%) rename {Greenshot => src/Greenshot}/icons/arrow_rollback.png (100%) rename {Greenshot => src/Greenshot}/icons/arrow_undo.png (100%) rename {Greenshot => src/Greenshot}/icons/balloon.png (100%) rename {Greenshot => src/Greenshot}/icons/cancel.png (100%) rename {Greenshot => src/Greenshot}/icons/cross.png (100%) rename {Greenshot => src/Greenshot}/icons/cut.png (100%) rename {Greenshot => src/Greenshot}/icons/delete.png (100%) rename {Greenshot => src/Greenshot}/icons/filter_blur.png (100%) rename {Greenshot => src/Greenshot}/icons/filter_pixelate.png (100%) rename {Greenshot => src/Greenshot}/icons/folder-open-image.png (100%) rename {Greenshot => src/Greenshot}/icons/folder_explore.png (100%) rename {Greenshot => src/Greenshot}/icons/font_color.png (100%) rename {Greenshot => src/Greenshot}/icons/freehand.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/arrow-resize.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/clipboard-paste-image.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/clipboard.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/color-swatch.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/cross.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/cursor.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/disk-black.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-alignment-center.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-alignment-right.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-alignment.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-blur.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-bold.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-italic.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-pixelate.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-underline.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-vertical-alignment-middle.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-vertical-alignment-top.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-vertical-alignment.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/filter_base.pdn (100%) rename {Greenshot => src/Greenshot}/icons/fugue/filter_highlight_area.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/filter_highlight_grayscale.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/filter_highlight_text.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/gear.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/highlighter-color.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/highlighter-text.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/image-blur.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/image-pixelate.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/images.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/layer-shape-arrow.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/layer-shape-ellipse.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/layer-shape-line.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/layer-shape-text.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/layer-shape.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier-zoom-actual.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier-zoom-fit.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier-zoom-in.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier-zoom-out.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier-zoom.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/mail-open-image.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/minus-circle.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/money-coin.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/paint-can-color-bg.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/paint-can-color.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/pencil-color-bg.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/pencil-color.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/printer.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/question.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/ruler-crop.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/scissors.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/slash.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/tick.png (100%) rename {Greenshot => src/Greenshot}/icons/heart.png (100%) rename {Greenshot => src/Greenshot}/icons/help.png (100%) rename {Greenshot => src/Greenshot}/icons/highlighter.png (100%) rename {Greenshot => src/Greenshot}/icons/layer-rotate-left.png (100%) rename {Greenshot => src/Greenshot}/icons/layer-rotate.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-01.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-02.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-03.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-04.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-05.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-06.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-07.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-08.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-09.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-10.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-11.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-12.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-13.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-14.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-15.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-16.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-17.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-18.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-19.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-20-plus.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-20.png (100%) rename {Greenshot => src/Greenshot}/icons/page_copy.png (100%) rename {Greenshot => src/Greenshot}/icons/palette.png (100%) rename {Greenshot => src/Greenshot}/icons/picture_save.png (100%) rename {Greenshot => src/Greenshot}/icons/picture_saveas.png (100%) rename {Greenshot => src/Greenshot}/icons/picture_to_clipboard.png (100%) rename {Greenshot => src/Greenshot}/icons/pipette.png (100%) rename {Greenshot => src/Greenshot}/icons/printer.png (100%) rename {Greenshot => src/Greenshot}/icons/propertyitemcontainer.gif (100%) rename {Greenshot => src/Greenshot}/icons/redo.png (100%) rename {Greenshot => src/Greenshot}/icons/resize.png (100%) rename {Greenshot => src/Greenshot}/icons/ruler-crop.png (100%) rename {Greenshot => src/Greenshot}/icons/shadow.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_arrow_add.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_arrowheads.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_copy.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_ellipse_add.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_ellipse_delete.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_line.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_paste.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_square_add.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_square_bordercolor.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_square_delete.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_square_fillcolor.png (100%) rename {Greenshot => src/Greenshot}/icons/text_bold.png (100%) rename {Greenshot => src/Greenshot}/icons/text_dropcaps.png (100%) rename {Greenshot => src/Greenshot}/icons/text_italic.png (100%) rename {Greenshot => src/Greenshot}/icons/text_underline.png (100%) rename {Greenshot => src/Greenshot}/icons/textfield_delete.png (100%) rename {Greenshot => src/Greenshot}/icons/undo.png (100%) rename {Greenshot => src/Greenshot}/icons/wand-hat.png (100%) rename {Greenshot => src/Greenshot}/icons/wrench.png (100%) rename {Greenshot => src/Greenshot}/icons/wrench_orange.png (100%) rename {Greenshot => src/Greenshot}/icons/zoom.png (100%) rename {Greenshot => src/Greenshot}/log4net-debug.xml (100%) rename {Greenshot => src/Greenshot}/log4net-portable.xml (100%) rename {Greenshot => src/Greenshot}/log4net-zip.xml (100%) rename {Greenshot => src/Greenshot}/log4net.xml (100%) rename {Greenshot => src/Greenshot}/releases/additional_files/installer.txt (100%) rename {Greenshot => src/Greenshot}/releases/additional_files/license.txt (100%) rename {Greenshot => src/Greenshot}/releases/additional_files/readme.txt (100%) rename {Greenshot => src/Greenshot}/releases/appinfo.ini.template (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/IssProc/IssProc.dll (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/IssProc/IssProcLanguage.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Afrikaans.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Albanian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Arabic.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Asturian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Basque.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Belarusian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Bengali.islu (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Bosnian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Bulgarian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/ChineseSimplified.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/ChineseTraditional.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Croatian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/EnglishBritish.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Esperanto.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Estonian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Farsi.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Galician.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Georgian.islu (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Greek.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Hindi.islu (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Hungarian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Indonesian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Kazakh.islu (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Korean.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Kurdish.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Latvian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Ligurian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Lithuanian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Luxemburgish.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Macedonian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Malaysian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Marathi.islu (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Mongolian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Montenegrian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Nepali.islu (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/NorwegianNynorsk.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Occitan.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Romanian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/ScottishGaelic.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/SerbianCyrillic.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/SerbianLatin.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Sinhala.islu (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Swedish.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Tatar.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Thai.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Uyghur.islu (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Uzbek.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Valencian.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/Languages/Vietnamese.isl (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/installer-large.bmp (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/installer-small.bmp (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/chinese.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/czech.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/dutch.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/english.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/french.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/french2.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/french3.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/german.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/isxdl.dll (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/isxdl.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/italian.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/japanese.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/korean.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/norwegian.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/polish.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/portugues.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/portuguese.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/russian.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/spanish.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/isxdl/swedish.ini (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/lang/chinese.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/lang/dutch.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/lang/english.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/lang/french.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/lang/german.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/lang/italian.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/lang/japanese.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/lang/polish.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/lang/russian.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products.pas (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/directxruntime.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx11.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx11lp.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx11sp1.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx20.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx20lp.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx20sp1.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx20sp1lp.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx20sp2.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx20sp2lp.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx35.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx35lp.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx35sp1.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx35sp1lp.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx40client.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx40full.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx45.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx46.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx47.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfx48.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/dotnetfxversion.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/fileversion.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/ie6.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/iis.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/jet4sp8.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/kb835732.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/mdac28.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/msi20.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/msi31.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/msi45.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/msiproduct.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/sql2005express.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/sql2008express.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/sqlcompact35sp2.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/stringversion.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/vcredist2005.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/vcredist2008.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/vcredist2010.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/vcredist2012.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/vcredist2013.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/vcredist2015.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/vcredist2017.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/wic.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/scripts/products/winversion.iss (100%) rename {Greenshot => src/Greenshot}/releases/innosetup/setup.iss (100%) rename {Greenshot => src/Greenshot}/releases/portable/App/AppInfo/appicon.ico (100%) rename {Greenshot => src/Greenshot}/releases/portable/App/AppInfo/appicon_16.png (100%) rename {Greenshot => src/Greenshot}/releases/portable/App/AppInfo/appicon_32.png (100%) rename {Greenshot => src/Greenshot}/releases/portable/App/DefaultData/Greenshots/dummy.txt (100%) rename {Greenshot => src/Greenshot}/releases/portable/App/DefaultData/Settings/dummy.txt (100%) rename {Greenshot => src/Greenshot}/releases/portable/Data/Greenshot/dummy.txt (100%) rename {Greenshot => src/Greenshot}/releases/portable/Data/Settings/dummy.txt (100%) rename {Greenshot => src/Greenshot}/releases/portable/Other/Source/PortableApps.comInstallerCustom.nsh (100%) rename {Greenshot => src/Greenshot}/sounds/camera.wav (100%) rename {Greenshot => src/Greenshot}/web/htdocs/Help/index.de-DE.html (100%) rename {Greenshot => src/Greenshot}/web/htdocs/Help/index.en-US.html (100%) rename {Greenshot => src/Greenshot}/web/htdocs/favicon.ico (100%) rename {Greenshot => src/Greenshot}/web/htdocs/index.html (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Box.png (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/BoxConfiguration.cs (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/BoxDestination.cs (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/BoxEntities.cs (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/BoxPlugin.cs (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/BoxPlugin.resx (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/BoxUtils.cs (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Forms/BoxForm.cs (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Forms/SettingsForm.Designer.cs (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Forms/SettingsForm.cs (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/GreenshotBoxPlugin.Credentials.template (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/GreenshotBoxPlugin.csproj (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/LanguageKeys.cs (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-cs-CZ.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-de-DE.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-en-US.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-fr-FR.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-id-ID.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-it-IT.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-ja-JP.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-kab-DZ.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-ko-KR.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-lv-LV.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-pl-PL.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-pt-PT.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-ru-RU.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-sr-RS.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-sv-SE.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-uk-UA.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-zh-CN.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Languages/language_boxplugin-zh-TW.xml (100%) rename {GreenshotBoxPlugin => src/GreenshotBoxPlugin}/Properties/AssemblyInfo.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Confluence.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/ConfluenceConfiguration.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/ConfluenceDestination.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/ConfluencePlugin.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/ConfluenceUtils.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/EnumDisplayer.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Forms/ConfluenceConfigurationForm.xaml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Forms/ConfluenceConfigurationForm.xaml.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Forms/ConfluencePagePicker.xaml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Forms/ConfluencePagePicker.xaml.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Forms/ConfluenceSearch.xaml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Forms/ConfluenceSearch.xaml.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Forms/ConfluenceTreePicker.xaml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Forms/ConfluenceTreePicker.xaml.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Forms/ConfluenceUpload.xaml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Forms/ConfluenceUpload.xaml.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/GreenshotConfluencePlugin.csproj (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Images/Confluence.ico (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/LanguageKeys.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-cs-CZ.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-de-DE.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-en-US.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-fr-FR.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-id-ID.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-it-IT.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-ja-JP.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-kab-DZ.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-ko-KR.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-lv-LV.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-nl-NL.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-pl-PL.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-pt-PT.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-ru-RU.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-sr-RS.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-sv-SE.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-uk-UA.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-zh-CN.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Languages/language_confluenceplugin-zh-TW.xml (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Support/ITranslationProvider.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Support/LanguageChangedEventManager.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Support/LanguageXMLTranslationProvider.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Support/TranslateExtension.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Support/TranslationData.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Support/TranslationManager.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Web References/confluence/Reference.cs (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Web References/confluence/Reference.map (100%) rename {GreenshotConfluencePlugin => src/GreenshotConfluencePlugin}/Web References/confluence/confluenceservice-v1.wsdl (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Dropbox.gif (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/DropboxDestination.cs (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/DropboxPlugin.cs (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/DropboxPlugin.resx (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/DropboxPluginConfiguration.cs (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/DropboxUtils.cs (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Forms/DropboxForm.cs (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Forms/SettingsForm.Designer.cs (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Forms/SettingsForm.cs (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/GreenshotDropboxPlugin.Credentials.template (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/GreenshotDropboxPlugin.csproj (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/LanguageKeys.cs (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-cs-CZ.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-de-DE.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-en-US.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-fr-FR.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-id-ID.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-it-IT.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-ja-JP.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-kab-DZ.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-ko-KR.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-lv-LV.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-pl-PL.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-pt-PT.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-ru-RU.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-sr-RS.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-sv-SE.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-uk-UA.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-zh-CN.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Languages/language_dropboxplugin-zh-TW.xml (100%) rename {GreenshotDropboxPlugin => src/GreenshotDropboxPlugin}/Properties/AssemblyInfo.cs (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/ExternalCommandConfiguration.cs (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/ExternalCommandDestination.cs (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/ExternalCommandForm.cs (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/ExternalCommandPlugin.cs (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/GreenshotExternalCommandPlugin.csproj (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/IconCache.cs (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-cs-CZ.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-de-DE.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-en-US.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-fr-FR.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-id-ID.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-it-IT.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-ja-JP.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-kab-DZ.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-ko-KR.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-lv-LV.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-pl-PL.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-pt-PT.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-ru-RU.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-sk-SK.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-sr-RS.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-sv-SE.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-uk-UA.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-zh-CN.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/Languages/language_externalcommandplugin-zh-TW.xml (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/SettingsForm.Designer.cs (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/SettingsForm.cs (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/SettingsFormDetail.Designer.cs (100%) rename {GreenshotExternalCommandPlugin => src/GreenshotExternalCommandPlugin}/SettingsFormDetail.cs (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/FlickrConfiguration.cs (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/FlickrDestination.cs (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/FlickrPlugin.cs (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/FlickrPlugin.resx (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/FlickrUtils.cs (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Forms/FlickrForm.cs (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Forms/SettingsForm.Designer.cs (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Forms/SettingsForm.cs (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/GreenshotFlickrPlugin.Credentials.template (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/GreenshotFlickrPlugin.csproj (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/LanguageKeys.cs (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-cs-CZ.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-de-DE.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-en-US.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-fr-FR.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-id-ID.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-it-IT.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-ja-JP.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-kab-DZ.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-ko-KR.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-lv-LV.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-pl-PL.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-pt-PT.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-ru-RU.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-sr-RS.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-sv-SE.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-uk-UA.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-zh-CN.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Languages/language_flickrplugin-zh-TW.xml (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/Properties/AssemblyInfo.cs (100%) rename {GreenshotFlickrPlugin => src/GreenshotFlickrPlugin}/flickr.png (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Forms/GooglePhotosForm.cs (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Forms/SettingsForm.Designer.cs (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Forms/SettingsForm.cs (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/GooglePhotos.png (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/GooglePhotosConfiguration.cs (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/GooglePhotosDestination.cs (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/GooglePhotosPlugin.cs (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/GooglePhotosPlugin.resx (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/GooglePhotosUtils.cs (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/GreenshotGooglePhotosPlugin.Credentials.template (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/GreenshotGooglePhotosPlugin.csproj (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/LanguageKeys.cs (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-cs-CZ.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-de-DE.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-en-US.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-fr-FR.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-id-ID.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-it-IT.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-ja-JP.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-kab-DZ.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-ko-KR.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-lv-LV.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-pl-PL.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-pt-PT.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-ru-RU.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-sr-RS.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-sv-SE.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-uk-UA.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-zh-CN.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Languages/language_googlephotosplugin-zh-TW.xml (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/Properties/AssemblyInfo.cs (100%) rename {GreenshotGooglePhotosPlugin => src/GreenshotGooglePhotosPlugin}/README (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Forms/ImgurForm.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Forms/ImgurHistory.Designer.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Forms/ImgurHistory.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Forms/SettingsForm.Designer.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Forms/SettingsForm.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/GreenshotImgurPlugin.Credentials.template (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/GreenshotImgurPlugin.csproj (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/ImgurConfiguration.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/ImgurDestination.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/ImgurInfo.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/ImgurPlugin.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/ImgurPlugin.resx (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/ImgurUtils.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/LanguageKeys.cs (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-cs-CZ.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-de-DE.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-en-US.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-fr-FR.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-id-ID.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-it-IT.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-ja-JP.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-kab-DZ.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-ko-KR.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-lv-LV.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-nl-NL.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-pl-PL.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-pt-PT.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-ru-RU.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-sk-SK.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-sr-RS.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-sv-SE.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-uk-UA.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-zh-CN.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Languages/language_imgurplugin-zh-TW.xml (100%) rename {GreenshotImgurPlugin => src/GreenshotImgurPlugin}/Properties/AssemblyInfo.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/AsyncMemoryCache.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Forms/JiraForm.Designer.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Forms/JiraForm.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Forms/JiraFormBase.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Forms/SettingsForm.Designer.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Forms/SettingsForm.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/GreenshotJiraPlugin.csproj (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/IssueTypeBitmapCache.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/JiraConfiguration.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/JiraConnector.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/JiraDestination.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/JiraDetails.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/JiraEventArgs.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/JiraEventTypes.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/JiraMonitor.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/JiraPlugin.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/JiraPlugin.resx (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/LanguageKeys.cs (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-cs-CZ.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-de-DE.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-en-US.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-fr-FR.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-id-ID.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-it-IT.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-ja-JP.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-kab-DZ.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-ko-KR.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-lv-LV.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-nl-NL.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-pl-PL.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-pt-PT.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-ru-RU.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-sr-RS.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-sv-SE.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-uk-UA.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-zh-CN.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Languages/language_jiraplugin-zh-TW.xml (100%) rename {GreenshotJiraPlugin => src/GreenshotJiraPlugin}/Log4NetLogger.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Com/DisposableCom.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Com/DisposableComImplementation.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Com/IDisposableCom.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Com/Ole32Api.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Com/OleAut32Api.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Destinations/ExcelDestination.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Destinations/OneNoteDestination.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Destinations/OutlookDestination.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Destinations/PowerpointDestination.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Destinations/WordDestination.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/GlobalSuppressions.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/GreenshotOfficePlugin.csproj (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Languages/language_officeplugin-fr-FR.ini (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeConfiguration.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeExport/Entities/OneNoteNotebook.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeExport/Entities/OneNotePage.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeExport/Entities/OneNoteSection.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeExport/ExcelExporter.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeExport/OneNoteExporter.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeExport/OutlookEmailExporter.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeExport/PowerpointExporter.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeExport/WordExporter.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeInterop/EmailFormat.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficeInterop/OfficeVersions.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/OfficePlugin.cs (100%) rename {GreenshotOfficePlugin => src/GreenshotOfficePlugin}/Properties/AssemblyInfo.cs (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Forms/PhotobucketForm.cs (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Forms/SettingsForm.Designer.cs (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Forms/SettingsForm.cs (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/GreenshotPhotobucketPlugin.Credentials.template (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/GreenshotPhotobucketPlugin.csproj (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/LanguageKeys.cs (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-cs-CZ.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-de-DE.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-en-US.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-fr_FR.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-id-ID.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-it-IT.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-ja-JP.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-kab-DZ.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-ko-KR.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-lv-LV.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-nl-NL.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-pl-PL.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-pt-PT.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-ru-RU.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-sv-SE.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-uk-UA.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-zh-CN.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Languages/language_photobucketplugin-zh-TW.xml (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/PhotobucketConfiguration.cs (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/PhotobucketDestination.cs (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/PhotobucketInfo.cs (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/PhotobucketPlugin.cs (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/PhotobucketPlugin.resx (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/PhotobucketUtils.cs (100%) rename {GreenshotPhotobucketPlugin => src/GreenshotPhotobucketPlugin}/Properties/AssemblyInfo.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/AnimatingForm.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/BackgroundForm.Designer.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/BackgroundForm.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/ExtendedWebBrowser.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/FormWithoutActivation.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotButton.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotCheckBox.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotColumnSorter.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotComboBox.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotForm.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotGroupBox.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotLabel.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotRadioButton.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotTabPage.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotTextBox.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotToolDropDownButton.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotToolStripButton.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotToolStripLabel.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/GreenshotToolStripMenuItem.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/HotkeyControl.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/IGreenshotConfigBindable.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/IGreenshotLanguageBindable.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/OAuthLoginForm.Designer.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/OAuthLoginForm.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/PleaseWaitForm.Designer.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/PleaseWaitForm.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/QualityDialog.Designer.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/QualityDialog.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/SaveImageFileDialog.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Controls/ThumbnailForm.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/AbstractDestination.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/AbstractProcessor.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/AccessibleHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/AnimationHelpers.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/BinaryStructHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/Cache.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/Capture.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/CaptureDetails.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/CaptureHandler.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/ClipboardHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/CoreConfiguration.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/CredentialsHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/DisplayKeyAttribute.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/DpiHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/EffectConverter.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/Enums/HResult.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/Enums/MonitorDpiType.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/Enums/MonitorFrom.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/EnvironmentInfo.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/EventDelay.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/ExplorerHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/FastBitmap.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/FilenameHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/Fraction.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/GreenshotResources.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/GreenshotResources.resx (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/HResultExtensions.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/IEHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/IImage.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/ImageHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/ImageOutput.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/ImageWrapper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/InterfaceUtils.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/JSONHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/Language.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/LanguageChangedHandler.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/LanguageFile.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/LogHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/NetworkHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/OAuth/LocalJsonReceiver.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/OAuth/LocalServerCodeReceiver.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/OAuth/OAuth2AuthorizeMode.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/OAuth/OAuth2Helper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/OAuth/OAuth2Settings.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/OAuth/OAuthSession.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/OAuth/OAuthSignatureTypes.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/ObjectExtensions.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/PluginUtils.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/QuantizerHelper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/RegistryKeyExtensions.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/SimpleServiceProvider.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/StringExtensions.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/SvgImage.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/WindowCapture.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/WindowDetails.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/WindowsEnumerator.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/WindowsVersion.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Core/WmInputLangChangeRequestFilter.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/AdjustEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/BorderEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/DropShadowEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/GrayscaleEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/IEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/InvertEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/MonochromeEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/ReduceColorsEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/ResizeCanvasEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/ResizeEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/RotateEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Effects/TornEdgeEffect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/FileDescriptorReader.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/GlobalSuppressions.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/GreenshotPlugin.csproj (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Hooking/WindowsEventHook.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Hooking/WindowsOpenCloseMonitor.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Hooking/WindowsTitleMonitor.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLBodyElement.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLCurrentStyle.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLDocument.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLDocument2.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLDocument3.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLDocument4.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLDocument5.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLElement.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLElement2.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLElementCollection.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLFrameBase.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLFramesCollection2.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLRect.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLScreen.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLScreen2.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLSelectionObject.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLStyle.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLTxtRange.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLWindow2.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLWindow3.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IHTMLWindow4.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IEInterop/IWebBrowser2.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IniFile/IniAttributes.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IniFile/IniConfig.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IniFile/IniReader.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IniFile/IniSection.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/IniFile/IniValue.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/CaptureMode.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Drawing/Adorners/IAdorner.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Drawing/Container.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Drawing/IField.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Drawing/IFieldholder.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Drawing/IMemento.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/DrawingModes.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Forms/ImageEditor.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/ICapture.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/ICaptureDetails.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/IDestination.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/INotificationService.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/IProcessor.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/IServiceLocator.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/ISurface.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Ocr/IOcrProvider.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Ocr/Line.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Ocr/OcrInformation.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Ocr/Word.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Plugin/HotKeyHandler.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Plugin/IGreenshotHost.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Plugin/IGreenshotPlugin.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Plugin/PluginAttribute.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/Plugin/SurfaceOutputSettings.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/ScreenCaptureMode.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/SurfaceDrawingModeEventArgs.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/SurfaceDrawingModeEventHandler.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/SurfaceElementEventArgs.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/SurfaceElementEventHandler.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/SurfaceMessageEventArgs.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/SurfaceMessageEventHandler.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/SurfaceMessageTyp.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interfaces/SurfaceSizeChangeEventHandler.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interop/Base.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interop/COMWrapper.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interop/ComProgIdAttribute.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interop/IAppVisibility.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interop/IDispatch.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interop/IOleCommandTarget.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interop/IOleWindow.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interop/IServiceProvider.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/Interop/IUnknown.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/DWM.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/EnumWindowsProc.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/ClassLongIndex.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/DesktopAccessRight.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/DeviceCaps.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/EventObjects.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/ProcessAccessFlags.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/RegionResult.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/ShowWindowCommand.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/SoundFlags.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/ThreadAccess.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/Win32Error.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/WinEvent.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/WinEventHookFlags.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/WindowLongIndex.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/WindowPlacementFlags.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/WindowPos.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/WindowStyleFlags.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Enums/WindowsMessages.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/GDI32.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/GDIplus.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Kernel32.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/PsAPI.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/SafeIconHandle.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/SafeWindowDcHandle.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Shell32.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Structs/CursorInfo.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Structs/IconInfo.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Structs/POINT.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Structs/RECT.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Structs/RECTF.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Structs/SCROLLINFO.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Structs/SIZE.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Structs/WindowInfo.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Structs/WindowPlacement.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/User32.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/Win32.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/WinEventDelegate.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/UnmanagedHelpers/WinMM.cs (100%) rename {GreenshotPlugin => src/GreenshotPlugin}/log4net-embedded.xml (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Destinations/Win10OcrDestination.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Destinations/Win10ShareDestination.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/GreenshotWin10Plugin.csproj (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Internal/MemoryRandomAccessStream.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Internal/ShareInfo.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Native/DataTransferManagerHelper.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Native/IDataTransferManagerInterOp.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Processors/Win10OcrProcessor.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Properties/AssemblyInfo.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/ToastNotificationService.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Win10Configuration.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Win10OcrProvider.cs (100%) rename {GreenshotWin10Plugin => src/GreenshotWin10Plugin}/Win10Plugin.cs (100%) create mode 100644 src/version.json diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 000000000..f399b08bb --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,78 @@ +# EditorConfig is awesome:http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Don't use tabs for indentation. +[*] +indent_style = space +# (Please don't specify an indent_size here; that has too many unintended consequences.) + +# Code files +[*.{cs,csx,vb,vbx}] +indent_size = 4 + +# Xml project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# Xml config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true +# Avoid "this." and "Me." if not necessary +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# CSharp code style settings: +[*.cs] +# Prefer "var" everywhere +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion + +# Prefer method-like constructs to have a block body +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 000000000..77faddc33 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,122 @@ + + + Copyright © Greenshot 2004-2021 + Greenshot + https://getgreenshot.org/favicon.ico + https://github.com/greenshot/greenshot + git + https://github.com/greenshot/greenshot + https://www.gnu.org/licenses/gpl.html + GPL + 9 + true + true + win10-x64;win10-x86;win-x64;win-x86 + + true + + true + net472 + Off + true + + + + + + + + + false + true + + + + false + true + false + + + + false + false + + + + DEBUG;TRACE + True + true + embedded + false + + + + true + embedded + True + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + $(Box13_ClientId) + + + $(Box13_ClientSecret) + + + $(DropBox13_ClientId) + + + $(DropBox13_ClientSecret) + + + $(Flickr_ClientId) + + + $(Flickr_ClientSecret) + + + $(Imgur13_ClientId) + + + $(Imgur13_ClientSecret) + + + $(Photobucket_ClientId) + + + $(Photobucket_ClientSecret) + + + $(Picasa_ClientId) + + + $(Picasa_ClientSecret) + + + + + + + + + + + + diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets new file mode 100644 index 000000000..f2ce406a1 --- /dev/null +++ b/src/Directory.Build.targets @@ -0,0 +1,13 @@ + + + + $(PkgMSBuildTasks)\tools\ + + + + + + + + + \ No newline at end of file diff --git a/src/Greenshot.sln b/src/Greenshot.sln new file mode 100644 index 000000000..1f119321e --- /dev/null +++ b/src/Greenshot.sln @@ -0,0 +1,170 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29728.190 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Greenshot.csproj", "{CD642BF4-D815-4D67-A0B5-C69F0B8231AF}" + ProjectSection(ProjectDependencies) = postProject + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} = {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} + {19FEEF09-313F-43C7-819D-F1BCA782B08B} = {19FEEF09-313F-43C7-819D-F1BCA782B08B} + {9801F62C-540F-4BFE-9211-6405DEDE563B} = {9801F62C-540F-4BFE-9211-6405DEDE563B} + {9C0ECC4C-7807-4111-916A-4F57BB29788A} = {9C0ECC4C-7807-4111-916A-4F57BB29788A} + {C3052651-598A-44E2-AAB3-2E41311D50F9} = {C3052651-598A-44E2-AAB3-2E41311D50F9} + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} = {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} + {697CF066-9077-4F22-99D9-D989CCE7282B} = {697CF066-9077-4F22-99D9-D989CCE7282B} + {47F23C86-604E-4CC3-8767-B3D4088F30BB} = {47F23C86-604E-4CC3-8767-B3D4088F30BB} + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} = {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} = {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} + {1893A2E4-A78A-4713-A8E7-E70058DABEE0} = {1893A2E4-A78A-4713-A8E7-E70058DABEE0} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPlugin", "GreenshotPlugin\GreenshotPlugin.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotExternalCommandPlugin", "GreenshotExternalCommandPlugin\GreenshotExternalCommandPlugin.csproj", "{47F23C86-604E-4CC3-8767-B3D4088F30BB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotConfluencePlugin", "GreenshotConfluencePlugin\GreenshotConfluencePlugin.csproj", "{C3052651-598A-44E2-AAB3-2E41311D50F9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotImgurPlugin", "GreenshotImgurPlugin\GreenshotImgurPlugin.csproj", "{80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotJiraPlugin", "GreenshotJiraPlugin\GreenshotJiraPlugin.csproj", "{19FEEF09-313F-43C7-819D-F1BCA782B08B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotBoxPlugin", "GreenshotBoxPlugin\GreenshotBoxPlugin.csproj", "{697CF066-9077-4F22-99D9-D989CCE7282B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotDropboxPlugin", "GreenshotDropboxPlugin\GreenshotDropboxPlugin.csproj", "{AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotFlickrPlugin", "GreenshotFlickrPlugin\GreenshotFlickrPlugin.csproj", "{7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotGooglePhotosPlugin", "GreenshotGooglePhotosPlugin\GreenshotGooglePhotosPlugin.csproj", "{1893A2E4-A78A-4713-A8E7-E70058DABEE0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotOfficePlugin", "GreenshotOfficePlugin\GreenshotOfficePlugin.csproj", "{92599C09-FF29-4ABD-B6E6-C48ECD781BAB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPhotobucketPlugin", "GreenshotPhotobucketPlugin\GreenshotPhotobucketPlugin.csproj", "{9C0ECC4C-7807-4111-916A-4F57BB29788A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotWin10Plugin", "GreenshotWin10Plugin\GreenshotWin10Plugin.csproj", "{9801F62C-540F-4BFE-9211-6405DEDE563B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{82987F1E-D7E6-4C44-B934-981D366E4672}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + azure-pipelines.yml = azure-pipelines.yml + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|x86.ActiveCfg = Debug|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|x86.Build.0 = Debug|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Any CPU.Build.0 = Release|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|x86.ActiveCfg = Release|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|x86.Build.0 = Release|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.ActiveCfg = Debug|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.Build.0 = Debug|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Any CPU.Build.0 = Release|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.ActiveCfg = Release|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.Build.0 = Release|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.ActiveCfg = Debug|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.Build.0 = Debug|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.Build.0 = Release|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.ActiveCfg = Release|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.Build.0 = Release|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.ActiveCfg = Debug|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.Build.0 = Debug|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.Build.0 = Release|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.ActiveCfg = Release|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.Build.0 = Release|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.ActiveCfg = Debug|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.Build.0 = Debug|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.ActiveCfg = Release|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.Build.0 = Release|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.ActiveCfg = Release|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.Build.0 = Release|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.ActiveCfg = Debug|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.Build.0 = Debug|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.Build.0 = Release|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.ActiveCfg = Release|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.Build.0 = Release|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.ActiveCfg = Debug|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.Build.0 = Debug|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Any CPU.Build.0 = Release|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|x86.ActiveCfg = Release|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|x86.Build.0 = Release|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|x86.ActiveCfg = Debug|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|x86.Build.0 = Debug|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Any CPU.Build.0 = Release|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|x86.ActiveCfg = Release|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|x86.Build.0 = Release|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|x86.ActiveCfg = Debug|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|x86.Build.0 = Debug|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Any CPU.Build.0 = Release|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|x86.ActiveCfg = Release|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|x86.Build.0 = Release|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|x86.ActiveCfg = Debug|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|x86.Build.0 = Debug|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Any CPU.Build.0 = Release|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|x86.ActiveCfg = Release|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|x86.Build.0 = Release|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|x86.ActiveCfg = Debug|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|x86.Build.0 = Debug|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Any CPU.Build.0 = Release|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|x86.ActiveCfg = Release|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|x86.Build.0 = Release|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|x86.ActiveCfg = Debug|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|x86.Build.0 = Debug|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Any CPU.Build.0 = Release|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|x86.ActiveCfg = Release|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|x86.Build.0 = Release|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|x86.ActiveCfg = Debug|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|x86.Build.0 = Debug|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Any CPU.Build.0 = Release|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|x86.ActiveCfg = Release|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {970967C0-60BE-4F70-9332-9ACC04B93A15} + EndGlobalSection +EndGlobal diff --git a/src/Greenshot.sln.DotSettings b/src/Greenshot.sln.DotSettings new file mode 100644 index 000000000..aecc39af3 --- /dev/null +++ b/src/Greenshot.sln.DotSettings @@ -0,0 +1,4 @@ + + True + True + True \ No newline at end of file diff --git a/Greenshot/App.config b/src/Greenshot/App.config similarity index 100% rename from Greenshot/App.config rename to src/Greenshot/App.config diff --git a/Greenshot/Configuration/EditorConfiguration.cs b/src/Greenshot/Configuration/EditorConfiguration.cs similarity index 100% rename from Greenshot/Configuration/EditorConfiguration.cs rename to src/Greenshot/Configuration/EditorConfiguration.cs diff --git a/Greenshot/Configuration/LanguageKeys.cs b/src/Greenshot/Configuration/LanguageKeys.cs similarity index 100% rename from Greenshot/Configuration/LanguageKeys.cs rename to src/Greenshot/Configuration/LanguageKeys.cs diff --git a/Greenshot/Controls/BindableToolStripButton.cs b/src/Greenshot/Controls/BindableToolStripButton.cs similarity index 100% rename from Greenshot/Controls/BindableToolStripButton.cs rename to src/Greenshot/Controls/BindableToolStripButton.cs diff --git a/Greenshot/Controls/BindableToolStripComboBox.cs b/src/Greenshot/Controls/BindableToolStripComboBox.cs similarity index 100% rename from Greenshot/Controls/BindableToolStripComboBox.cs rename to src/Greenshot/Controls/BindableToolStripComboBox.cs diff --git a/Greenshot/Controls/BindableToolStripDropDownButton.cs b/src/Greenshot/Controls/BindableToolStripDropDownButton.cs similarity index 100% rename from Greenshot/Controls/BindableToolStripDropDownButton.cs rename to src/Greenshot/Controls/BindableToolStripDropDownButton.cs diff --git a/Greenshot/Controls/ColorButton.cs b/src/Greenshot/Controls/ColorButton.cs similarity index 100% rename from Greenshot/Controls/ColorButton.cs rename to src/Greenshot/Controls/ColorButton.cs diff --git a/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs b/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs similarity index 100% rename from Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs rename to src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs diff --git a/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs b/src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs similarity index 100% rename from Greenshot/Controls/CustomToolStripProfessionalRenderer.cs rename to src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs diff --git a/Greenshot/Controls/FontFamilyComboBox.cs b/src/Greenshot/Controls/FontFamilyComboBox.cs similarity index 100% rename from Greenshot/Controls/FontFamilyComboBox.cs rename to src/Greenshot/Controls/FontFamilyComboBox.cs diff --git a/Greenshot/Controls/MenuStripEx.cs b/src/Greenshot/Controls/MenuStripEx.cs similarity index 100% rename from Greenshot/Controls/MenuStripEx.cs rename to src/Greenshot/Controls/MenuStripEx.cs diff --git a/Greenshot/Controls/NonJumpingPanel.cs b/src/Greenshot/Controls/NonJumpingPanel.cs similarity index 100% rename from Greenshot/Controls/NonJumpingPanel.cs rename to src/Greenshot/Controls/NonJumpingPanel.cs diff --git a/Greenshot/Controls/Pipette.cs b/src/Greenshot/Controls/Pipette.cs similarity index 100% rename from Greenshot/Controls/Pipette.cs rename to src/Greenshot/Controls/Pipette.cs diff --git a/Greenshot/Controls/ToolStripColorButton.cs b/src/Greenshot/Controls/ToolStripColorButton.cs similarity index 100% rename from Greenshot/Controls/ToolStripColorButton.cs rename to src/Greenshot/Controls/ToolStripColorButton.cs diff --git a/Greenshot/Controls/ToolStripEx.cs b/src/Greenshot/Controls/ToolStripEx.cs similarity index 100% rename from Greenshot/Controls/ToolStripEx.cs rename to src/Greenshot/Controls/ToolStripEx.cs diff --git a/Greenshot/Controls/ToolStripNumericUpDown.cs b/src/Greenshot/Controls/ToolStripNumericUpDown.cs similarity index 100% rename from Greenshot/Controls/ToolStripNumericUpDown.cs rename to src/Greenshot/Controls/ToolStripNumericUpDown.cs diff --git a/Greenshot/Destinations/ClipboardDestination.cs b/src/Greenshot/Destinations/ClipboardDestination.cs similarity index 100% rename from Greenshot/Destinations/ClipboardDestination.cs rename to src/Greenshot/Destinations/ClipboardDestination.cs diff --git a/Greenshot/Destinations/EditorDestination.cs b/src/Greenshot/Destinations/EditorDestination.cs similarity index 100% rename from Greenshot/Destinations/EditorDestination.cs rename to src/Greenshot/Destinations/EditorDestination.cs diff --git a/Greenshot/Destinations/EmailDestination.cs b/src/Greenshot/Destinations/EmailDestination.cs similarity index 100% rename from Greenshot/Destinations/EmailDestination.cs rename to src/Greenshot/Destinations/EmailDestination.cs diff --git a/Greenshot/Destinations/FileDestination.cs b/src/Greenshot/Destinations/FileDestination.cs similarity index 100% rename from Greenshot/Destinations/FileDestination.cs rename to src/Greenshot/Destinations/FileDestination.cs diff --git a/Greenshot/Destinations/FileWithDialogDestination.cs b/src/Greenshot/Destinations/FileWithDialogDestination.cs similarity index 100% rename from Greenshot/Destinations/FileWithDialogDestination.cs rename to src/Greenshot/Destinations/FileWithDialogDestination.cs diff --git a/Greenshot/Destinations/PickerDestination.cs b/src/Greenshot/Destinations/PickerDestination.cs similarity index 100% rename from Greenshot/Destinations/PickerDestination.cs rename to src/Greenshot/Destinations/PickerDestination.cs diff --git a/Greenshot/Destinations/PrinterDestination.cs b/src/Greenshot/Destinations/PrinterDestination.cs similarity index 100% rename from Greenshot/Destinations/PrinterDestination.cs rename to src/Greenshot/Destinations/PrinterDestination.cs diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs similarity index 100% rename from Greenshot/Drawing/Adorners/AbstractAdorner.cs rename to src/Greenshot/Drawing/Adorners/AbstractAdorner.cs diff --git a/Greenshot/Drawing/Adorners/MoveAdorner.cs b/src/Greenshot/Drawing/Adorners/MoveAdorner.cs similarity index 100% rename from Greenshot/Drawing/Adorners/MoveAdorner.cs rename to src/Greenshot/Drawing/Adorners/MoveAdorner.cs diff --git a/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs similarity index 100% rename from Greenshot/Drawing/Adorners/ResizeAdorner.cs rename to src/Greenshot/Drawing/Adorners/ResizeAdorner.cs diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/src/Greenshot/Drawing/Adorners/TargetAdorner.cs similarity index 100% rename from Greenshot/Drawing/Adorners/TargetAdorner.cs rename to src/Greenshot/Drawing/Adorners/TargetAdorner.cs diff --git a/Greenshot/Drawing/ArrowContainer.cs b/src/Greenshot/Drawing/ArrowContainer.cs similarity index 100% rename from Greenshot/Drawing/ArrowContainer.cs rename to src/Greenshot/Drawing/ArrowContainer.cs diff --git a/Greenshot/Drawing/CropContainer.cs b/src/Greenshot/Drawing/CropContainer.cs similarity index 100% rename from Greenshot/Drawing/CropContainer.cs rename to src/Greenshot/Drawing/CropContainer.cs diff --git a/Greenshot/Drawing/CursorContainer.cs b/src/Greenshot/Drawing/CursorContainer.cs similarity index 100% rename from Greenshot/Drawing/CursorContainer.cs rename to src/Greenshot/Drawing/CursorContainer.cs diff --git a/Greenshot/Drawing/DrawableContainer.cs b/src/Greenshot/Drawing/DrawableContainer.cs similarity index 100% rename from Greenshot/Drawing/DrawableContainer.cs rename to src/Greenshot/Drawing/DrawableContainer.cs diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/src/Greenshot/Drawing/DrawableContainerList.cs similarity index 100% rename from Greenshot/Drawing/DrawableContainerList.cs rename to src/Greenshot/Drawing/DrawableContainerList.cs diff --git a/Greenshot/Drawing/EllipseContainer.cs b/src/Greenshot/Drawing/EllipseContainer.cs similarity index 100% rename from Greenshot/Drawing/EllipseContainer.cs rename to src/Greenshot/Drawing/EllipseContainer.cs diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs similarity index 100% rename from Greenshot/Drawing/Fields/AbstractFieldHolder.cs rename to src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs similarity index 100% rename from Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs rename to src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs diff --git a/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs b/src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs similarity index 100% rename from Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs rename to src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs diff --git a/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs b/src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs similarity index 100% rename from Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs rename to src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs diff --git a/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs b/src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs similarity index 100% rename from Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs rename to src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs diff --git a/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs b/src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs similarity index 100% rename from Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs rename to src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs diff --git a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs b/src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs similarity index 100% rename from Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs rename to src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs diff --git a/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs b/src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs similarity index 100% rename from Greenshot/Drawing/Fields/Binding/IBindingConverter.cs rename to src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs diff --git a/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs b/src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs similarity index 100% rename from Greenshot/Drawing/Fields/Binding/IBindingValidator.cs rename to src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs diff --git a/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs b/src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs similarity index 100% rename from Greenshot/Drawing/Fields/Binding/NotNullValidator.cs rename to src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs diff --git a/Greenshot/Drawing/Fields/Field.cs b/src/Greenshot/Drawing/Fields/Field.cs similarity index 100% rename from Greenshot/Drawing/Fields/Field.cs rename to src/Greenshot/Drawing/Fields/Field.cs diff --git a/Greenshot/Drawing/Fields/FieldAggregator.cs b/src/Greenshot/Drawing/Fields/FieldAggregator.cs similarity index 100% rename from Greenshot/Drawing/Fields/FieldAggregator.cs rename to src/Greenshot/Drawing/Fields/FieldAggregator.cs diff --git a/Greenshot/Drawing/Fields/FieldType.cs b/src/Greenshot/Drawing/Fields/FieldType.cs similarity index 100% rename from Greenshot/Drawing/Fields/FieldType.cs rename to src/Greenshot/Drawing/Fields/FieldType.cs diff --git a/Greenshot/Drawing/FilterContainer.cs b/src/Greenshot/Drawing/FilterContainer.cs similarity index 100% rename from Greenshot/Drawing/FilterContainer.cs rename to src/Greenshot/Drawing/FilterContainer.cs diff --git a/Greenshot/Drawing/Filters/AbstractFilter.cs b/src/Greenshot/Drawing/Filters/AbstractFilter.cs similarity index 100% rename from Greenshot/Drawing/Filters/AbstractFilter.cs rename to src/Greenshot/Drawing/Filters/AbstractFilter.cs diff --git a/Greenshot/Drawing/Filters/BlurFilter.cs b/src/Greenshot/Drawing/Filters/BlurFilter.cs similarity index 100% rename from Greenshot/Drawing/Filters/BlurFilter.cs rename to src/Greenshot/Drawing/Filters/BlurFilter.cs diff --git a/Greenshot/Drawing/Filters/BrightnessFilter.cs b/src/Greenshot/Drawing/Filters/BrightnessFilter.cs similarity index 100% rename from Greenshot/Drawing/Filters/BrightnessFilter.cs rename to src/Greenshot/Drawing/Filters/BrightnessFilter.cs diff --git a/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs similarity index 100% rename from Greenshot/Drawing/Filters/GrayscaleFilter.cs rename to src/Greenshot/Drawing/Filters/GrayscaleFilter.cs diff --git a/Greenshot/Drawing/Filters/HighlightFilter.cs b/src/Greenshot/Drawing/Filters/HighlightFilter.cs similarity index 100% rename from Greenshot/Drawing/Filters/HighlightFilter.cs rename to src/Greenshot/Drawing/Filters/HighlightFilter.cs diff --git a/Greenshot/Drawing/Filters/IFilter.cs b/src/Greenshot/Drawing/Filters/IFilter.cs similarity index 100% rename from Greenshot/Drawing/Filters/IFilter.cs rename to src/Greenshot/Drawing/Filters/IFilter.cs diff --git a/Greenshot/Drawing/Filters/MagnifierFilter.cs b/src/Greenshot/Drawing/Filters/MagnifierFilter.cs similarity index 100% rename from Greenshot/Drawing/Filters/MagnifierFilter.cs rename to src/Greenshot/Drawing/Filters/MagnifierFilter.cs diff --git a/Greenshot/Drawing/Filters/PixelizationFilter.cs b/src/Greenshot/Drawing/Filters/PixelizationFilter.cs similarity index 100% rename from Greenshot/Drawing/Filters/PixelizationFilter.cs rename to src/Greenshot/Drawing/Filters/PixelizationFilter.cs diff --git a/Greenshot/Drawing/FreehandContainer.cs b/src/Greenshot/Drawing/FreehandContainer.cs similarity index 100% rename from Greenshot/Drawing/FreehandContainer.cs rename to src/Greenshot/Drawing/FreehandContainer.cs diff --git a/Greenshot/Drawing/HighlightContainer.cs b/src/Greenshot/Drawing/HighlightContainer.cs similarity index 100% rename from Greenshot/Drawing/HighlightContainer.cs rename to src/Greenshot/Drawing/HighlightContainer.cs diff --git a/Greenshot/Drawing/IconContainer.cs b/src/Greenshot/Drawing/IconContainer.cs similarity index 100% rename from Greenshot/Drawing/IconContainer.cs rename to src/Greenshot/Drawing/IconContainer.cs diff --git a/Greenshot/Drawing/ImageContainer.cs b/src/Greenshot/Drawing/ImageContainer.cs similarity index 100% rename from Greenshot/Drawing/ImageContainer.cs rename to src/Greenshot/Drawing/ImageContainer.cs diff --git a/Greenshot/Drawing/LineContainer.cs b/src/Greenshot/Drawing/LineContainer.cs similarity index 100% rename from Greenshot/Drawing/LineContainer.cs rename to src/Greenshot/Drawing/LineContainer.cs diff --git a/Greenshot/Drawing/ObfuscateContainer.cs b/src/Greenshot/Drawing/ObfuscateContainer.cs similarity index 100% rename from Greenshot/Drawing/ObfuscateContainer.cs rename to src/Greenshot/Drawing/ObfuscateContainer.cs diff --git a/Greenshot/Drawing/Positions.cs b/src/Greenshot/Drawing/Positions.cs similarity index 100% rename from Greenshot/Drawing/Positions.cs rename to src/Greenshot/Drawing/Positions.cs diff --git a/Greenshot/Drawing/RectangleContainer.cs b/src/Greenshot/Drawing/RectangleContainer.cs similarity index 100% rename from Greenshot/Drawing/RectangleContainer.cs rename to src/Greenshot/Drawing/RectangleContainer.cs diff --git a/Greenshot/Drawing/SpeechbubbleContainer.cs b/src/Greenshot/Drawing/SpeechbubbleContainer.cs similarity index 100% rename from Greenshot/Drawing/SpeechbubbleContainer.cs rename to src/Greenshot/Drawing/SpeechbubbleContainer.cs diff --git a/Greenshot/Drawing/StepLabelContainer.cs b/src/Greenshot/Drawing/StepLabelContainer.cs similarity index 100% rename from Greenshot/Drawing/StepLabelContainer.cs rename to src/Greenshot/Drawing/StepLabelContainer.cs diff --git a/Greenshot/Drawing/Surface.cs b/src/Greenshot/Drawing/Surface.cs similarity index 100% rename from Greenshot/Drawing/Surface.cs rename to src/Greenshot/Drawing/Surface.cs diff --git a/Greenshot/Drawing/TextContainer.cs b/src/Greenshot/Drawing/TextContainer.cs similarity index 100% rename from Greenshot/Drawing/TextContainer.cs rename to src/Greenshot/Drawing/TextContainer.cs diff --git a/Greenshot/Forms/AboutForm.Designer.cs b/src/Greenshot/Forms/AboutForm.Designer.cs similarity index 100% rename from Greenshot/Forms/AboutForm.Designer.cs rename to src/Greenshot/Forms/AboutForm.Designer.cs diff --git a/Greenshot/Forms/AboutForm.cs b/src/Greenshot/Forms/AboutForm.cs similarity index 100% rename from Greenshot/Forms/AboutForm.cs rename to src/Greenshot/Forms/AboutForm.cs diff --git a/Greenshot/Forms/AnimatingBaseForm.cs b/src/Greenshot/Forms/AnimatingBaseForm.cs similarity index 100% rename from Greenshot/Forms/AnimatingBaseForm.cs rename to src/Greenshot/Forms/AnimatingBaseForm.cs diff --git a/Greenshot/Forms/BaseForm.cs b/src/Greenshot/Forms/BaseForm.cs similarity index 100% rename from Greenshot/Forms/BaseForm.cs rename to src/Greenshot/Forms/BaseForm.cs diff --git a/Greenshot/Forms/BugReportForm.Designer.cs b/src/Greenshot/Forms/BugReportForm.Designer.cs similarity index 100% rename from Greenshot/Forms/BugReportForm.Designer.cs rename to src/Greenshot/Forms/BugReportForm.Designer.cs diff --git a/Greenshot/Forms/BugReportForm.cs b/src/Greenshot/Forms/BugReportForm.cs similarity index 100% rename from Greenshot/Forms/BugReportForm.cs rename to src/Greenshot/Forms/BugReportForm.cs diff --git a/Greenshot/Forms/CaptureForm.Designer.cs b/src/Greenshot/Forms/CaptureForm.Designer.cs similarity index 100% rename from Greenshot/Forms/CaptureForm.Designer.cs rename to src/Greenshot/Forms/CaptureForm.Designer.cs diff --git a/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs similarity index 100% rename from Greenshot/Forms/CaptureForm.cs rename to src/Greenshot/Forms/CaptureForm.cs diff --git a/Greenshot/Forms/ColorDialog.Designer.cs b/src/Greenshot/Forms/ColorDialog.Designer.cs similarity index 100% rename from Greenshot/Forms/ColorDialog.Designer.cs rename to src/Greenshot/Forms/ColorDialog.Designer.cs diff --git a/Greenshot/Forms/ColorDialog.cs b/src/Greenshot/Forms/ColorDialog.cs similarity index 100% rename from Greenshot/Forms/ColorDialog.cs rename to src/Greenshot/Forms/ColorDialog.cs diff --git a/Greenshot/Forms/ColorDialog.resx b/src/Greenshot/Forms/ColorDialog.resx similarity index 100% rename from Greenshot/Forms/ColorDialog.resx rename to src/Greenshot/Forms/ColorDialog.resx diff --git a/Greenshot/Forms/ColorPickerToolStripButton.cs b/src/Greenshot/Forms/ColorPickerToolStripButton.cs similarity index 100% rename from Greenshot/Forms/ColorPickerToolStripButton.cs rename to src/Greenshot/Forms/ColorPickerToolStripButton.cs diff --git a/Greenshot/Forms/DropShadowSettingsForm.Designer.cs b/src/Greenshot/Forms/DropShadowSettingsForm.Designer.cs similarity index 100% rename from Greenshot/Forms/DropShadowSettingsForm.Designer.cs rename to src/Greenshot/Forms/DropShadowSettingsForm.Designer.cs diff --git a/Greenshot/Forms/DropShadowSettingsForm.cs b/src/Greenshot/Forms/DropShadowSettingsForm.cs similarity index 100% rename from Greenshot/Forms/DropShadowSettingsForm.cs rename to src/Greenshot/Forms/DropShadowSettingsForm.cs diff --git a/Greenshot/Forms/ImageEditorForm.Designer.cs b/src/Greenshot/Forms/ImageEditorForm.Designer.cs similarity index 100% rename from Greenshot/Forms/ImageEditorForm.Designer.cs rename to src/Greenshot/Forms/ImageEditorForm.Designer.cs diff --git a/Greenshot/Forms/ImageEditorForm.cs b/src/Greenshot/Forms/ImageEditorForm.cs similarity index 100% rename from Greenshot/Forms/ImageEditorForm.cs rename to src/Greenshot/Forms/ImageEditorForm.cs diff --git a/Greenshot/Forms/ImageEditorForm.resx b/src/Greenshot/Forms/ImageEditorForm.resx similarity index 100% rename from Greenshot/Forms/ImageEditorForm.resx rename to src/Greenshot/Forms/ImageEditorForm.resx diff --git a/Greenshot/Forms/LanguageDialog.Designer.cs b/src/Greenshot/Forms/LanguageDialog.Designer.cs similarity index 100% rename from Greenshot/Forms/LanguageDialog.Designer.cs rename to src/Greenshot/Forms/LanguageDialog.Designer.cs diff --git a/Greenshot/Forms/LanguageDialog.cs b/src/Greenshot/Forms/LanguageDialog.cs similarity index 100% rename from Greenshot/Forms/LanguageDialog.cs rename to src/Greenshot/Forms/LanguageDialog.cs diff --git a/Greenshot/Forms/MainForm.Designer.cs b/src/Greenshot/Forms/MainForm.Designer.cs similarity index 100% rename from Greenshot/Forms/MainForm.Designer.cs rename to src/Greenshot/Forms/MainForm.Designer.cs diff --git a/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs similarity index 100% rename from Greenshot/Forms/MainForm.cs rename to src/Greenshot/Forms/MainForm.cs diff --git a/Greenshot/Forms/MainForm.resx b/src/Greenshot/Forms/MainForm.resx similarity index 100% rename from Greenshot/Forms/MainForm.resx rename to src/Greenshot/Forms/MainForm.resx diff --git a/Greenshot/Forms/MovableShowColorForm.Designer.cs b/src/Greenshot/Forms/MovableShowColorForm.Designer.cs similarity index 100% rename from Greenshot/Forms/MovableShowColorForm.Designer.cs rename to src/Greenshot/Forms/MovableShowColorForm.Designer.cs diff --git a/Greenshot/Forms/MovableShowColorForm.cs b/src/Greenshot/Forms/MovableShowColorForm.cs similarity index 100% rename from Greenshot/Forms/MovableShowColorForm.cs rename to src/Greenshot/Forms/MovableShowColorForm.cs diff --git a/Greenshot/Forms/PrintOptionsDialog.Designer.cs b/src/Greenshot/Forms/PrintOptionsDialog.Designer.cs similarity index 100% rename from Greenshot/Forms/PrintOptionsDialog.Designer.cs rename to src/Greenshot/Forms/PrintOptionsDialog.Designer.cs diff --git a/Greenshot/Forms/PrintOptionsDialog.cs b/src/Greenshot/Forms/PrintOptionsDialog.cs similarity index 100% rename from Greenshot/Forms/PrintOptionsDialog.cs rename to src/Greenshot/Forms/PrintOptionsDialog.cs diff --git a/Greenshot/Forms/ResizeSettingsForm.Designer.cs b/src/Greenshot/Forms/ResizeSettingsForm.Designer.cs similarity index 100% rename from Greenshot/Forms/ResizeSettingsForm.Designer.cs rename to src/Greenshot/Forms/ResizeSettingsForm.Designer.cs diff --git a/Greenshot/Forms/ResizeSettingsForm.cs b/src/Greenshot/Forms/ResizeSettingsForm.cs similarity index 100% rename from Greenshot/Forms/ResizeSettingsForm.cs rename to src/Greenshot/Forms/ResizeSettingsForm.cs diff --git a/Greenshot/Forms/SettingsForm.Designer.cs b/src/Greenshot/Forms/SettingsForm.Designer.cs similarity index 100% rename from Greenshot/Forms/SettingsForm.Designer.cs rename to src/Greenshot/Forms/SettingsForm.Designer.cs diff --git a/Greenshot/Forms/SettingsForm.cs b/src/Greenshot/Forms/SettingsForm.cs similarity index 100% rename from Greenshot/Forms/SettingsForm.cs rename to src/Greenshot/Forms/SettingsForm.cs diff --git a/Greenshot/Forms/SettingsForm.resx b/src/Greenshot/Forms/SettingsForm.resx similarity index 100% rename from Greenshot/Forms/SettingsForm.resx rename to src/Greenshot/Forms/SettingsForm.resx diff --git a/Greenshot/Forms/ToolStripMenuSelectList.cs b/src/Greenshot/Forms/ToolStripMenuSelectList.cs similarity index 100% rename from Greenshot/Forms/ToolStripMenuSelectList.cs rename to src/Greenshot/Forms/ToolStripMenuSelectList.cs diff --git a/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs b/src/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs similarity index 100% rename from Greenshot/Forms/TornEdgeSettingsForm.Designer.cs rename to src/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs diff --git a/Greenshot/Forms/TornEdgeSettingsForm.cs b/src/Greenshot/Forms/TornEdgeSettingsForm.cs similarity index 100% rename from Greenshot/Forms/TornEdgeSettingsForm.cs rename to src/Greenshot/Forms/TornEdgeSettingsForm.cs diff --git a/Greenshot/Greenshot.csproj b/src/Greenshot/Greenshot.csproj similarity index 100% rename from Greenshot/Greenshot.csproj rename to src/Greenshot/Greenshot.csproj diff --git a/Greenshot/GreenshotMain.cs b/src/Greenshot/GreenshotMain.cs similarity index 100% rename from Greenshot/GreenshotMain.cs rename to src/Greenshot/GreenshotMain.cs diff --git a/Greenshot/Help/HelpFileLoader.cs b/src/Greenshot/Help/HelpFileLoader.cs similarity index 100% rename from Greenshot/Help/HelpFileLoader.cs rename to src/Greenshot/Help/HelpFileLoader.cs diff --git a/Greenshot/Helpers/CaptureHelper.cs b/src/Greenshot/Helpers/CaptureHelper.cs similarity index 100% rename from Greenshot/Helpers/CaptureHelper.cs rename to src/Greenshot/Helpers/CaptureHelper.cs diff --git a/Greenshot/Helpers/Colors.cs b/src/Greenshot/Helpers/Colors.cs similarity index 100% rename from Greenshot/Helpers/Colors.cs rename to src/Greenshot/Helpers/Colors.cs diff --git a/Greenshot/Helpers/CopyData.cs b/src/Greenshot/Helpers/CopyData.cs similarity index 100% rename from Greenshot/Helpers/CopyData.cs rename to src/Greenshot/Helpers/CopyData.cs diff --git a/Greenshot/Helpers/DestinationHelper.cs b/src/Greenshot/Helpers/DestinationHelper.cs similarity index 100% rename from Greenshot/Helpers/DestinationHelper.cs rename to src/Greenshot/Helpers/DestinationHelper.cs diff --git a/Greenshot/Helpers/Entities/UpdateFeed.cs b/src/Greenshot/Helpers/Entities/UpdateFeed.cs similarity index 100% rename from Greenshot/Helpers/Entities/UpdateFeed.cs rename to src/Greenshot/Helpers/Entities/UpdateFeed.cs diff --git a/Greenshot/Helpers/GeometryHelper.cs b/src/Greenshot/Helpers/GeometryHelper.cs similarity index 100% rename from Greenshot/Helpers/GeometryHelper.cs rename to src/Greenshot/Helpers/GeometryHelper.cs diff --git a/Greenshot/Helpers/GuiRectangle.cs b/src/Greenshot/Helpers/GuiRectangle.cs similarity index 100% rename from Greenshot/Helpers/GuiRectangle.cs rename to src/Greenshot/Helpers/GuiRectangle.cs diff --git a/Greenshot/Helpers/IECaptureHelper.cs b/src/Greenshot/Helpers/IECaptureHelper.cs similarity index 100% rename from Greenshot/Helpers/IECaptureHelper.cs rename to src/Greenshot/Helpers/IECaptureHelper.cs diff --git a/Greenshot/Helpers/IEInterop/IEContainer.cs b/src/Greenshot/Helpers/IEInterop/IEContainer.cs similarity index 100% rename from Greenshot/Helpers/IEInterop/IEContainer.cs rename to src/Greenshot/Helpers/IEInterop/IEContainer.cs diff --git a/Greenshot/Helpers/MailHelper.cs b/src/Greenshot/Helpers/MailHelper.cs similarity index 100% rename from Greenshot/Helpers/MailHelper.cs rename to src/Greenshot/Helpers/MailHelper.cs diff --git a/Greenshot/Helpers/NotifyIconNotificationService.cs b/src/Greenshot/Helpers/NotifyIconNotificationService.cs similarity index 100% rename from Greenshot/Helpers/NotifyIconNotificationService.cs rename to src/Greenshot/Helpers/NotifyIconNotificationService.cs diff --git a/Greenshot/Helpers/PluginHelper.cs b/src/Greenshot/Helpers/PluginHelper.cs similarity index 100% rename from Greenshot/Helpers/PluginHelper.cs rename to src/Greenshot/Helpers/PluginHelper.cs diff --git a/Greenshot/Helpers/PrintHelper.cs b/src/Greenshot/Helpers/PrintHelper.cs similarity index 100% rename from Greenshot/Helpers/PrintHelper.cs rename to src/Greenshot/Helpers/PrintHelper.cs diff --git a/Greenshot/Helpers/ProcessorHelper.cs b/src/Greenshot/Helpers/ProcessorHelper.cs similarity index 100% rename from Greenshot/Helpers/ProcessorHelper.cs rename to src/Greenshot/Helpers/ProcessorHelper.cs diff --git a/Greenshot/Helpers/ResourceMutex.cs b/src/Greenshot/Helpers/ResourceMutex.cs similarity index 100% rename from Greenshot/Helpers/ResourceMutex.cs rename to src/Greenshot/Helpers/ResourceMutex.cs diff --git a/Greenshot/Helpers/ScaleHelper.cs b/src/Greenshot/Helpers/ScaleHelper.cs similarity index 100% rename from Greenshot/Helpers/ScaleHelper.cs rename to src/Greenshot/Helpers/ScaleHelper.cs diff --git a/Greenshot/Helpers/SoundHelper.cs b/src/Greenshot/Helpers/SoundHelper.cs similarity index 100% rename from Greenshot/Helpers/SoundHelper.cs rename to src/Greenshot/Helpers/SoundHelper.cs diff --git a/Greenshot/Helpers/StartupHelper.cs b/src/Greenshot/Helpers/StartupHelper.cs similarity index 100% rename from Greenshot/Helpers/StartupHelper.cs rename to src/Greenshot/Helpers/StartupHelper.cs diff --git a/Greenshot/Helpers/ToolStripItemEndisabler.cs b/src/Greenshot/Helpers/ToolStripItemEndisabler.cs similarity index 100% rename from Greenshot/Helpers/ToolStripItemEndisabler.cs rename to src/Greenshot/Helpers/ToolStripItemEndisabler.cs diff --git a/Greenshot/Helpers/UpdateService.cs b/src/Greenshot/Helpers/UpdateService.cs similarity index 100% rename from Greenshot/Helpers/UpdateService.cs rename to src/Greenshot/Helpers/UpdateService.cs diff --git a/Greenshot/Languages/help-de-DE.html b/src/Greenshot/Languages/help-de-DE.html similarity index 100% rename from Greenshot/Languages/help-de-DE.html rename to src/Greenshot/Languages/help-de-DE.html diff --git a/Greenshot/Languages/help-en-US.html b/src/Greenshot/Languages/help-en-US.html similarity index 100% rename from Greenshot/Languages/help-en-US.html rename to src/Greenshot/Languages/help-en-US.html diff --git a/Greenshot/Languages/help-es-ES.html b/src/Greenshot/Languages/help-es-ES.html similarity index 100% rename from Greenshot/Languages/help-es-ES.html rename to src/Greenshot/Languages/help-es-ES.html diff --git a/Greenshot/Languages/help-fr-FR.html b/src/Greenshot/Languages/help-fr-FR.html similarity index 100% rename from Greenshot/Languages/help-fr-FR.html rename to src/Greenshot/Languages/help-fr-FR.html diff --git a/Greenshot/Languages/help-hu-HU.html b/src/Greenshot/Languages/help-hu-HU.html similarity index 100% rename from Greenshot/Languages/help-hu-HU.html rename to src/Greenshot/Languages/help-hu-HU.html diff --git a/Greenshot/Languages/help-it-IT.html b/src/Greenshot/Languages/help-it-IT.html similarity index 100% rename from Greenshot/Languages/help-it-IT.html rename to src/Greenshot/Languages/help-it-IT.html diff --git a/Greenshot/Languages/help-ko-KR.html b/src/Greenshot/Languages/help-ko-KR.html similarity index 100% rename from Greenshot/Languages/help-ko-KR.html rename to src/Greenshot/Languages/help-ko-KR.html diff --git a/Greenshot/Languages/help-nl-NL.html b/src/Greenshot/Languages/help-nl-NL.html similarity index 100% rename from Greenshot/Languages/help-nl-NL.html rename to src/Greenshot/Languages/help-nl-NL.html diff --git a/Greenshot/Languages/help-nn-NO.html b/src/Greenshot/Languages/help-nn-NO.html similarity index 100% rename from Greenshot/Languages/help-nn-NO.html rename to src/Greenshot/Languages/help-nn-NO.html diff --git a/Greenshot/Languages/help-pl-PL.html b/src/Greenshot/Languages/help-pl-PL.html similarity index 100% rename from Greenshot/Languages/help-pl-PL.html rename to src/Greenshot/Languages/help-pl-PL.html diff --git a/Greenshot/Languages/help-pt-BR.html b/src/Greenshot/Languages/help-pt-BR.html similarity index 100% rename from Greenshot/Languages/help-pt-BR.html rename to src/Greenshot/Languages/help-pt-BR.html diff --git a/Greenshot/Languages/help-pt-PT.html b/src/Greenshot/Languages/help-pt-PT.html similarity index 100% rename from Greenshot/Languages/help-pt-PT.html rename to src/Greenshot/Languages/help-pt-PT.html diff --git a/Greenshot/Languages/help-ru-RU.html b/src/Greenshot/Languages/help-ru-RU.html similarity index 100% rename from Greenshot/Languages/help-ru-RU.html rename to src/Greenshot/Languages/help-ru-RU.html diff --git a/Greenshot/Languages/help-sv-SE.html b/src/Greenshot/Languages/help-sv-SE.html similarity index 100% rename from Greenshot/Languages/help-sv-SE.html rename to src/Greenshot/Languages/help-sv-SE.html diff --git a/Greenshot/Languages/help-tr-TR.html b/src/Greenshot/Languages/help-tr-TR.html similarity index 100% rename from Greenshot/Languages/help-tr-TR.html rename to src/Greenshot/Languages/help-tr-TR.html diff --git a/Greenshot/Languages/help-zh-CN.html b/src/Greenshot/Languages/help-zh-CN.html similarity index 100% rename from Greenshot/Languages/help-zh-CN.html rename to src/Greenshot/Languages/help-zh-CN.html diff --git a/Greenshot/Languages/installer/language-installer-de-DE.xml b/src/Greenshot/Languages/installer/language-installer-de-DE.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-de-DE.xml rename to src/Greenshot/Languages/installer/language-installer-de-DE.xml diff --git a/Greenshot/Languages/installer/language-installer-en-US.xml b/src/Greenshot/Languages/installer/language-installer-en-US.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-en-US.xml rename to src/Greenshot/Languages/installer/language-installer-en-US.xml diff --git a/Greenshot/Languages/installer/language-installer-es-ES.xml b/src/Greenshot/Languages/installer/language-installer-es-ES.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-es-ES.xml rename to src/Greenshot/Languages/installer/language-installer-es-ES.xml diff --git a/Greenshot/Languages/installer/language-installer-fi-FI.xml b/src/Greenshot/Languages/installer/language-installer-fi-FI.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-fi-FI.xml rename to src/Greenshot/Languages/installer/language-installer-fi-FI.xml diff --git a/Greenshot/Languages/installer/language-installer-fr-FR.xml b/src/Greenshot/Languages/installer/language-installer-fr-FR.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-fr-FR.xml rename to src/Greenshot/Languages/installer/language-installer-fr-FR.xml diff --git a/Greenshot/Languages/installer/language-installer-it-IT.xml b/src/Greenshot/Languages/installer/language-installer-it-IT.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-it-IT.xml rename to src/Greenshot/Languages/installer/language-installer-it-IT.xml diff --git a/Greenshot/Languages/installer/language-installer-lv-LV.xml b/src/Greenshot/Languages/installer/language-installer-lv-LV.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-lv-LV.xml rename to src/Greenshot/Languages/installer/language-installer-lv-LV.xml diff --git a/Greenshot/Languages/installer/language-installer-nl-NL.xml b/src/Greenshot/Languages/installer/language-installer-nl-NL.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-nl-NL.xml rename to src/Greenshot/Languages/installer/language-installer-nl-NL.xml diff --git a/Greenshot/Languages/installer/language-installer-nn-NO.xml b/src/Greenshot/Languages/installer/language-installer-nn-NO.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-nn-NO.xml rename to src/Greenshot/Languages/installer/language-installer-nn-NO.xml diff --git a/Greenshot/Languages/installer/language-installer-sr-RS.xml b/src/Greenshot/Languages/installer/language-installer-sr-RS.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-sr-RS.xml rename to src/Greenshot/Languages/installer/language-installer-sr-RS.xml diff --git a/Greenshot/Languages/installer/language-installer-sv-SE.xml b/src/Greenshot/Languages/installer/language-installer-sv-SE.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-sv-SE.xml rename to src/Greenshot/Languages/installer/language-installer-sv-SE.xml diff --git a/Greenshot/Languages/installer/language-installer-uk-UA.xml b/src/Greenshot/Languages/installer/language-installer-uk-UA.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-uk-UA.xml rename to src/Greenshot/Languages/installer/language-installer-uk-UA.xml diff --git a/Greenshot/Languages/installer/language-installer-zh-CN.xml b/src/Greenshot/Languages/installer/language-installer-zh-CN.xml similarity index 100% rename from Greenshot/Languages/installer/language-installer-zh-CN.xml rename to src/Greenshot/Languages/installer/language-installer-zh-CN.xml diff --git a/Greenshot/Languages/language-ar-SY.xml b/src/Greenshot/Languages/language-ar-SY.xml similarity index 100% rename from Greenshot/Languages/language-ar-SY.xml rename to src/Greenshot/Languages/language-ar-SY.xml diff --git a/Greenshot/Languages/language-ca-CA.xml b/src/Greenshot/Languages/language-ca-CA.xml similarity index 100% rename from Greenshot/Languages/language-ca-CA.xml rename to src/Greenshot/Languages/language-ca-CA.xml diff --git a/Greenshot/Languages/language-cs-CZ.xml b/src/Greenshot/Languages/language-cs-CZ.xml similarity index 100% rename from Greenshot/Languages/language-cs-CZ.xml rename to src/Greenshot/Languages/language-cs-CZ.xml diff --git a/Greenshot/Languages/language-da-DK.xml b/src/Greenshot/Languages/language-da-DK.xml similarity index 100% rename from Greenshot/Languages/language-da-DK.xml rename to src/Greenshot/Languages/language-da-DK.xml diff --git a/Greenshot/Languages/language-de-DE.xml b/src/Greenshot/Languages/language-de-DE.xml similarity index 100% rename from Greenshot/Languages/language-de-DE.xml rename to src/Greenshot/Languages/language-de-DE.xml diff --git a/Greenshot/Languages/language-de-x-franconia.xml b/src/Greenshot/Languages/language-de-x-franconia.xml similarity index 100% rename from Greenshot/Languages/language-de-x-franconia.xml rename to src/Greenshot/Languages/language-de-x-franconia.xml diff --git a/Greenshot/Languages/language-el-GR.xml b/src/Greenshot/Languages/language-el-GR.xml similarity index 100% rename from Greenshot/Languages/language-el-GR.xml rename to src/Greenshot/Languages/language-el-GR.xml diff --git a/Greenshot/Languages/language-en-US.xml b/src/Greenshot/Languages/language-en-US.xml similarity index 100% rename from Greenshot/Languages/language-en-US.xml rename to src/Greenshot/Languages/language-en-US.xml diff --git a/Greenshot/Languages/language-es-ES.xml b/src/Greenshot/Languages/language-es-ES.xml similarity index 100% rename from Greenshot/Languages/language-es-ES.xml rename to src/Greenshot/Languages/language-es-ES.xml diff --git a/Greenshot/Languages/language-et-EE.xml b/src/Greenshot/Languages/language-et-EE.xml similarity index 100% rename from Greenshot/Languages/language-et-EE.xml rename to src/Greenshot/Languages/language-et-EE.xml diff --git a/Greenshot/Languages/language-fa-IR.xml b/src/Greenshot/Languages/language-fa-IR.xml similarity index 100% rename from Greenshot/Languages/language-fa-IR.xml rename to src/Greenshot/Languages/language-fa-IR.xml diff --git a/Greenshot/Languages/language-fi-FI.xml b/src/Greenshot/Languages/language-fi-FI.xml similarity index 100% rename from Greenshot/Languages/language-fi-FI.xml rename to src/Greenshot/Languages/language-fi-FI.xml diff --git a/Greenshot/Languages/language-fr-FR.xml b/src/Greenshot/Languages/language-fr-FR.xml similarity index 100% rename from Greenshot/Languages/language-fr-FR.xml rename to src/Greenshot/Languages/language-fr-FR.xml diff --git a/Greenshot/Languages/language-fr-QC.xml b/src/Greenshot/Languages/language-fr-QC.xml similarity index 100% rename from Greenshot/Languages/language-fr-QC.xml rename to src/Greenshot/Languages/language-fr-QC.xml diff --git a/Greenshot/Languages/language-he-IL.xml b/src/Greenshot/Languages/language-he-IL.xml similarity index 100% rename from Greenshot/Languages/language-he-IL.xml rename to src/Greenshot/Languages/language-he-IL.xml diff --git a/Greenshot/Languages/language-hu-HU.xml b/src/Greenshot/Languages/language-hu-HU.xml similarity index 100% rename from Greenshot/Languages/language-hu-HU.xml rename to src/Greenshot/Languages/language-hu-HU.xml diff --git a/Greenshot/Languages/language-id-ID.xml b/src/Greenshot/Languages/language-id-ID.xml similarity index 100% rename from Greenshot/Languages/language-id-ID.xml rename to src/Greenshot/Languages/language-id-ID.xml diff --git a/Greenshot/Languages/language-it-IT.xml b/src/Greenshot/Languages/language-it-IT.xml similarity index 100% rename from Greenshot/Languages/language-it-IT.xml rename to src/Greenshot/Languages/language-it-IT.xml diff --git a/Greenshot/Languages/language-ja-JP.xml b/src/Greenshot/Languages/language-ja-JP.xml similarity index 100% rename from Greenshot/Languages/language-ja-JP.xml rename to src/Greenshot/Languages/language-ja-JP.xml diff --git a/Greenshot/Languages/language-kab-DZ.xml b/src/Greenshot/Languages/language-kab-DZ.xml similarity index 100% rename from Greenshot/Languages/language-kab-DZ.xml rename to src/Greenshot/Languages/language-kab-DZ.xml diff --git a/Greenshot/Languages/language-ko-KR.xml b/src/Greenshot/Languages/language-ko-KR.xml similarity index 100% rename from Greenshot/Languages/language-ko-KR.xml rename to src/Greenshot/Languages/language-ko-KR.xml diff --git a/Greenshot/Languages/language-lt-LT.xml b/src/Greenshot/Languages/language-lt-LT.xml similarity index 100% rename from Greenshot/Languages/language-lt-LT.xml rename to src/Greenshot/Languages/language-lt-LT.xml diff --git a/Greenshot/Languages/language-lv-LV.xml b/src/Greenshot/Languages/language-lv-LV.xml similarity index 100% rename from Greenshot/Languages/language-lv-LV.xml rename to src/Greenshot/Languages/language-lv-LV.xml diff --git a/Greenshot/Languages/language-nl-NL.xml b/src/Greenshot/Languages/language-nl-NL.xml similarity index 100% rename from Greenshot/Languages/language-nl-NL.xml rename to src/Greenshot/Languages/language-nl-NL.xml diff --git a/Greenshot/Languages/language-nn-NO.xml b/src/Greenshot/Languages/language-nn-NO.xml similarity index 100% rename from Greenshot/Languages/language-nn-NO.xml rename to src/Greenshot/Languages/language-nn-NO.xml diff --git a/Greenshot/Languages/language-pl-PL.xml b/src/Greenshot/Languages/language-pl-PL.xml similarity index 100% rename from Greenshot/Languages/language-pl-PL.xml rename to src/Greenshot/Languages/language-pl-PL.xml diff --git a/Greenshot/Languages/language-pt-BR.xml b/src/Greenshot/Languages/language-pt-BR.xml similarity index 100% rename from Greenshot/Languages/language-pt-BR.xml rename to src/Greenshot/Languages/language-pt-BR.xml diff --git a/Greenshot/Languages/language-pt-PT.xml b/src/Greenshot/Languages/language-pt-PT.xml similarity index 100% rename from Greenshot/Languages/language-pt-PT.xml rename to src/Greenshot/Languages/language-pt-PT.xml diff --git a/Greenshot/Languages/language-ro-RO.xml b/src/Greenshot/Languages/language-ro-RO.xml similarity index 100% rename from Greenshot/Languages/language-ro-RO.xml rename to src/Greenshot/Languages/language-ro-RO.xml diff --git a/Greenshot/Languages/language-ru-RU.xml b/src/Greenshot/Languages/language-ru-RU.xml similarity index 100% rename from Greenshot/Languages/language-ru-RU.xml rename to src/Greenshot/Languages/language-ru-RU.xml diff --git a/Greenshot/Languages/language-sk-SK.xml b/src/Greenshot/Languages/language-sk-SK.xml similarity index 100% rename from Greenshot/Languages/language-sk-SK.xml rename to src/Greenshot/Languages/language-sk-SK.xml diff --git a/Greenshot/Languages/language-sl-SI.xml b/src/Greenshot/Languages/language-sl-SI.xml similarity index 100% rename from Greenshot/Languages/language-sl-SI.xml rename to src/Greenshot/Languages/language-sl-SI.xml diff --git a/Greenshot/Languages/language-sr-RS.xml b/src/Greenshot/Languages/language-sr-RS.xml similarity index 100% rename from Greenshot/Languages/language-sr-RS.xml rename to src/Greenshot/Languages/language-sr-RS.xml diff --git a/Greenshot/Languages/language-sv-SE.xml b/src/Greenshot/Languages/language-sv-SE.xml similarity index 100% rename from Greenshot/Languages/language-sv-SE.xml rename to src/Greenshot/Languages/language-sv-SE.xml diff --git a/Greenshot/Languages/language-tr-TR.xml b/src/Greenshot/Languages/language-tr-TR.xml similarity index 100% rename from Greenshot/Languages/language-tr-TR.xml rename to src/Greenshot/Languages/language-tr-TR.xml diff --git a/Greenshot/Languages/language-uk-UA.xml b/src/Greenshot/Languages/language-uk-UA.xml similarity index 100% rename from Greenshot/Languages/language-uk-UA.xml rename to src/Greenshot/Languages/language-uk-UA.xml diff --git a/Greenshot/Languages/language-vi-VN.xml b/src/Greenshot/Languages/language-vi-VN.xml similarity index 100% rename from Greenshot/Languages/language-vi-VN.xml rename to src/Greenshot/Languages/language-vi-VN.xml diff --git a/Greenshot/Languages/language-zh-CN.xml b/src/Greenshot/Languages/language-zh-CN.xml similarity index 100% rename from Greenshot/Languages/language-zh-CN.xml rename to src/Greenshot/Languages/language-zh-CN.xml diff --git a/Greenshot/Languages/language-zh-TW.xml b/src/Greenshot/Languages/language-zh-TW.xml similarity index 100% rename from Greenshot/Languages/language-zh-TW.xml rename to src/Greenshot/Languages/language-zh-TW.xml diff --git a/Greenshot/Languages/website/language-website-de-DE.xml b/src/Greenshot/Languages/website/language-website-de-DE.xml similarity index 100% rename from Greenshot/Languages/website/language-website-de-DE.xml rename to src/Greenshot/Languages/website/language-website-de-DE.xml diff --git a/Greenshot/Languages/website/language-website-en-US.xml b/src/Greenshot/Languages/website/language-website-en-US.xml similarity index 100% rename from Greenshot/Languages/website/language-website-en-US.xml rename to src/Greenshot/Languages/website/language-website-en-US.xml diff --git a/Greenshot/Languages/website/language-website-es-ES.xml b/src/Greenshot/Languages/website/language-website-es-ES.xml similarity index 100% rename from Greenshot/Languages/website/language-website-es-ES.xml rename to src/Greenshot/Languages/website/language-website-es-ES.xml diff --git a/Greenshot/Languages/website/language-website-fr-FR.xml b/src/Greenshot/Languages/website/language-website-fr-FR.xml similarity index 100% rename from Greenshot/Languages/website/language-website-fr-FR.xml rename to src/Greenshot/Languages/website/language-website-fr-FR.xml diff --git a/Greenshot/Languages/website/language-website-it-IT.xml b/src/Greenshot/Languages/website/language-website-it-IT.xml similarity index 100% rename from Greenshot/Languages/website/language-website-it-IT.xml rename to src/Greenshot/Languages/website/language-website-it-IT.xml diff --git a/Greenshot/Languages/website/language-website-lv-LV.xml b/src/Greenshot/Languages/website/language-website-lv-LV.xml similarity index 100% rename from Greenshot/Languages/website/language-website-lv-LV.xml rename to src/Greenshot/Languages/website/language-website-lv-LV.xml diff --git a/Greenshot/Languages/website/language-website-nn-NO.xml b/src/Greenshot/Languages/website/language-website-nn-NO.xml similarity index 100% rename from Greenshot/Languages/website/language-website-nn-NO.xml rename to src/Greenshot/Languages/website/language-website-nn-NO.xml diff --git a/Greenshot/Languages/website/language-website-pt-BR.xml b/src/Greenshot/Languages/website/language-website-pt-BR.xml similarity index 100% rename from Greenshot/Languages/website/language-website-pt-BR.xml rename to src/Greenshot/Languages/website/language-website-pt-BR.xml diff --git a/Greenshot/Languages/website/language-website-sv-SE.xml b/src/Greenshot/Languages/website/language-website-sv-SE.xml similarity index 100% rename from Greenshot/Languages/website/language-website-sv-SE.xml rename to src/Greenshot/Languages/website/language-website-sv-SE.xml diff --git a/Greenshot/Languages/website/language-website-uk-UA.xml b/src/Greenshot/Languages/website/language-website-uk-UA.xml similarity index 100% rename from Greenshot/Languages/website/language-website-uk-UA.xml rename to src/Greenshot/Languages/website/language-website-uk-UA.xml diff --git a/Greenshot/Memento/AddElementMemento.cs b/src/Greenshot/Memento/AddElementMemento.cs similarity index 100% rename from Greenshot/Memento/AddElementMemento.cs rename to src/Greenshot/Memento/AddElementMemento.cs diff --git a/Greenshot/Memento/AddElementsMemento.cs b/src/Greenshot/Memento/AddElementsMemento.cs similarity index 100% rename from Greenshot/Memento/AddElementsMemento.cs rename to src/Greenshot/Memento/AddElementsMemento.cs diff --git a/Greenshot/Memento/ChangeFieldHolderMemento.cs b/src/Greenshot/Memento/ChangeFieldHolderMemento.cs similarity index 100% rename from Greenshot/Memento/ChangeFieldHolderMemento.cs rename to src/Greenshot/Memento/ChangeFieldHolderMemento.cs diff --git a/Greenshot/Memento/DeleteElementMemento.cs b/src/Greenshot/Memento/DeleteElementMemento.cs similarity index 100% rename from Greenshot/Memento/DeleteElementMemento.cs rename to src/Greenshot/Memento/DeleteElementMemento.cs diff --git a/Greenshot/Memento/DeleteElementsMemento.cs b/src/Greenshot/Memento/DeleteElementsMemento.cs similarity index 100% rename from Greenshot/Memento/DeleteElementsMemento.cs rename to src/Greenshot/Memento/DeleteElementsMemento.cs diff --git a/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs b/src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs similarity index 100% rename from Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs rename to src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs diff --git a/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs b/src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs similarity index 100% rename from Greenshot/Memento/SurfaceBackgroundChangeMemento.cs rename to src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs diff --git a/Greenshot/Memento/TextChangeMemento.cs b/src/Greenshot/Memento/TextChangeMemento.cs similarity index 100% rename from Greenshot/Memento/TextChangeMemento.cs rename to src/Greenshot/Memento/TextChangeMemento.cs diff --git a/Greenshot/Processors/TitleFixProcessor.cs b/src/Greenshot/Processors/TitleFixProcessor.cs similarity index 100% rename from Greenshot/Processors/TitleFixProcessor.cs rename to src/Greenshot/Processors/TitleFixProcessor.cs diff --git a/Greenshot/Sounds.resx b/src/Greenshot/Sounds.resx similarity index 100% rename from Greenshot/Sounds.resx rename to src/Greenshot/Sounds.resx diff --git a/Greenshot/greenshot.manifest b/src/Greenshot/greenshot.manifest similarity index 100% rename from Greenshot/greenshot.manifest rename to src/Greenshot/greenshot.manifest diff --git a/Greenshot/icons/applicationIcon/16.ico b/src/Greenshot/icons/applicationIcon/16.ico similarity index 100% rename from Greenshot/icons/applicationIcon/16.ico rename to src/Greenshot/icons/applicationIcon/16.ico diff --git a/Greenshot/icons/applicationIcon/16.png b/src/Greenshot/icons/applicationIcon/16.png similarity index 100% rename from Greenshot/icons/applicationIcon/16.png rename to src/Greenshot/icons/applicationIcon/16.png diff --git a/Greenshot/icons/applicationIcon/32.ico b/src/Greenshot/icons/applicationIcon/32.ico similarity index 100% rename from Greenshot/icons/applicationIcon/32.ico rename to src/Greenshot/icons/applicationIcon/32.ico diff --git a/Greenshot/icons/applicationIcon/32.png b/src/Greenshot/icons/applicationIcon/32.png similarity index 100% rename from Greenshot/icons/applicationIcon/32.png rename to src/Greenshot/icons/applicationIcon/32.png diff --git a/Greenshot/icons/applicationIcon/48.ico b/src/Greenshot/icons/applicationIcon/48.ico similarity index 100% rename from Greenshot/icons/applicationIcon/48.ico rename to src/Greenshot/icons/applicationIcon/48.ico diff --git a/Greenshot/icons/applicationIcon/48.png b/src/Greenshot/icons/applicationIcon/48.png similarity index 100% rename from Greenshot/icons/applicationIcon/48.png rename to src/Greenshot/icons/applicationIcon/48.png diff --git a/Greenshot/icons/applicationIcon/90.png b/src/Greenshot/icons/applicationIcon/90.png similarity index 100% rename from Greenshot/icons/applicationIcon/90.png rename to src/Greenshot/icons/applicationIcon/90.png diff --git a/Greenshot/icons/applicationIcon/icon.ico b/src/Greenshot/icons/applicationIcon/icon.ico similarity index 100% rename from Greenshot/icons/applicationIcon/icon.ico rename to src/Greenshot/icons/applicationIcon/icon.ico diff --git a/Greenshot/icons/arrow_redo.png b/src/Greenshot/icons/arrow_redo.png similarity index 100% rename from Greenshot/icons/arrow_redo.png rename to src/Greenshot/icons/arrow_redo.png diff --git a/Greenshot/icons/arrow_rollback.png b/src/Greenshot/icons/arrow_rollback.png similarity index 100% rename from Greenshot/icons/arrow_rollback.png rename to src/Greenshot/icons/arrow_rollback.png diff --git a/Greenshot/icons/arrow_undo.png b/src/Greenshot/icons/arrow_undo.png similarity index 100% rename from Greenshot/icons/arrow_undo.png rename to src/Greenshot/icons/arrow_undo.png diff --git a/Greenshot/icons/balloon.png b/src/Greenshot/icons/balloon.png similarity index 100% rename from Greenshot/icons/balloon.png rename to src/Greenshot/icons/balloon.png diff --git a/Greenshot/icons/cancel.png b/src/Greenshot/icons/cancel.png similarity index 100% rename from Greenshot/icons/cancel.png rename to src/Greenshot/icons/cancel.png diff --git a/Greenshot/icons/cross.png b/src/Greenshot/icons/cross.png similarity index 100% rename from Greenshot/icons/cross.png rename to src/Greenshot/icons/cross.png diff --git a/Greenshot/icons/cut.png b/src/Greenshot/icons/cut.png similarity index 100% rename from Greenshot/icons/cut.png rename to src/Greenshot/icons/cut.png diff --git a/Greenshot/icons/delete.png b/src/Greenshot/icons/delete.png similarity index 100% rename from Greenshot/icons/delete.png rename to src/Greenshot/icons/delete.png diff --git a/Greenshot/icons/filter_blur.png b/src/Greenshot/icons/filter_blur.png similarity index 100% rename from Greenshot/icons/filter_blur.png rename to src/Greenshot/icons/filter_blur.png diff --git a/Greenshot/icons/filter_pixelate.png b/src/Greenshot/icons/filter_pixelate.png similarity index 100% rename from Greenshot/icons/filter_pixelate.png rename to src/Greenshot/icons/filter_pixelate.png diff --git a/Greenshot/icons/folder-open-image.png b/src/Greenshot/icons/folder-open-image.png similarity index 100% rename from Greenshot/icons/folder-open-image.png rename to src/Greenshot/icons/folder-open-image.png diff --git a/Greenshot/icons/folder_explore.png b/src/Greenshot/icons/folder_explore.png similarity index 100% rename from Greenshot/icons/folder_explore.png rename to src/Greenshot/icons/folder_explore.png diff --git a/Greenshot/icons/font_color.png b/src/Greenshot/icons/font_color.png similarity index 100% rename from Greenshot/icons/font_color.png rename to src/Greenshot/icons/font_color.png diff --git a/Greenshot/icons/freehand.png b/src/Greenshot/icons/freehand.png similarity index 100% rename from Greenshot/icons/freehand.png rename to src/Greenshot/icons/freehand.png diff --git a/Greenshot/icons/fugue/arrow-resize.png b/src/Greenshot/icons/fugue/arrow-resize.png similarity index 100% rename from Greenshot/icons/fugue/arrow-resize.png rename to src/Greenshot/icons/fugue/arrow-resize.png diff --git a/Greenshot/icons/fugue/clipboard-paste-image.png b/src/Greenshot/icons/fugue/clipboard-paste-image.png similarity index 100% rename from Greenshot/icons/fugue/clipboard-paste-image.png rename to src/Greenshot/icons/fugue/clipboard-paste-image.png diff --git a/Greenshot/icons/fugue/clipboard.png b/src/Greenshot/icons/fugue/clipboard.png similarity index 100% rename from Greenshot/icons/fugue/clipboard.png rename to src/Greenshot/icons/fugue/clipboard.png diff --git a/Greenshot/icons/fugue/color-swatch.png b/src/Greenshot/icons/fugue/color-swatch.png similarity index 100% rename from Greenshot/icons/fugue/color-swatch.png rename to src/Greenshot/icons/fugue/color-swatch.png diff --git a/Greenshot/icons/fugue/cross.png b/src/Greenshot/icons/fugue/cross.png similarity index 100% rename from Greenshot/icons/fugue/cross.png rename to src/Greenshot/icons/fugue/cross.png diff --git a/Greenshot/icons/fugue/cursor.png b/src/Greenshot/icons/fugue/cursor.png similarity index 100% rename from Greenshot/icons/fugue/cursor.png rename to src/Greenshot/icons/fugue/cursor.png diff --git a/Greenshot/icons/fugue/disk-black.png b/src/Greenshot/icons/fugue/disk-black.png similarity index 100% rename from Greenshot/icons/fugue/disk-black.png rename to src/Greenshot/icons/fugue/disk-black.png diff --git a/Greenshot/icons/fugue/edit-alignment-center.png b/src/Greenshot/icons/fugue/edit-alignment-center.png similarity index 100% rename from Greenshot/icons/fugue/edit-alignment-center.png rename to src/Greenshot/icons/fugue/edit-alignment-center.png diff --git a/Greenshot/icons/fugue/edit-alignment-right.png b/src/Greenshot/icons/fugue/edit-alignment-right.png similarity index 100% rename from Greenshot/icons/fugue/edit-alignment-right.png rename to src/Greenshot/icons/fugue/edit-alignment-right.png diff --git a/Greenshot/icons/fugue/edit-alignment.png b/src/Greenshot/icons/fugue/edit-alignment.png similarity index 100% rename from Greenshot/icons/fugue/edit-alignment.png rename to src/Greenshot/icons/fugue/edit-alignment.png diff --git a/Greenshot/icons/fugue/edit-blur.png b/src/Greenshot/icons/fugue/edit-blur.png similarity index 100% rename from Greenshot/icons/fugue/edit-blur.png rename to src/Greenshot/icons/fugue/edit-blur.png diff --git a/Greenshot/icons/fugue/edit-bold.png b/src/Greenshot/icons/fugue/edit-bold.png similarity index 100% rename from Greenshot/icons/fugue/edit-bold.png rename to src/Greenshot/icons/fugue/edit-bold.png diff --git a/Greenshot/icons/fugue/edit-italic.png b/src/Greenshot/icons/fugue/edit-italic.png similarity index 100% rename from Greenshot/icons/fugue/edit-italic.png rename to src/Greenshot/icons/fugue/edit-italic.png diff --git a/Greenshot/icons/fugue/edit-pixelate.png b/src/Greenshot/icons/fugue/edit-pixelate.png similarity index 100% rename from Greenshot/icons/fugue/edit-pixelate.png rename to src/Greenshot/icons/fugue/edit-pixelate.png diff --git a/Greenshot/icons/fugue/edit-underline.png b/src/Greenshot/icons/fugue/edit-underline.png similarity index 100% rename from Greenshot/icons/fugue/edit-underline.png rename to src/Greenshot/icons/fugue/edit-underline.png diff --git a/Greenshot/icons/fugue/edit-vertical-alignment-middle.png b/src/Greenshot/icons/fugue/edit-vertical-alignment-middle.png similarity index 100% rename from Greenshot/icons/fugue/edit-vertical-alignment-middle.png rename to src/Greenshot/icons/fugue/edit-vertical-alignment-middle.png diff --git a/Greenshot/icons/fugue/edit-vertical-alignment-top.png b/src/Greenshot/icons/fugue/edit-vertical-alignment-top.png similarity index 100% rename from Greenshot/icons/fugue/edit-vertical-alignment-top.png rename to src/Greenshot/icons/fugue/edit-vertical-alignment-top.png diff --git a/Greenshot/icons/fugue/edit-vertical-alignment.png b/src/Greenshot/icons/fugue/edit-vertical-alignment.png similarity index 100% rename from Greenshot/icons/fugue/edit-vertical-alignment.png rename to src/Greenshot/icons/fugue/edit-vertical-alignment.png diff --git a/Greenshot/icons/fugue/filter_base.pdn b/src/Greenshot/icons/fugue/filter_base.pdn similarity index 100% rename from Greenshot/icons/fugue/filter_base.pdn rename to src/Greenshot/icons/fugue/filter_base.pdn diff --git a/Greenshot/icons/fugue/filter_highlight_area.png b/src/Greenshot/icons/fugue/filter_highlight_area.png similarity index 100% rename from Greenshot/icons/fugue/filter_highlight_area.png rename to src/Greenshot/icons/fugue/filter_highlight_area.png diff --git a/Greenshot/icons/fugue/filter_highlight_grayscale.png b/src/Greenshot/icons/fugue/filter_highlight_grayscale.png similarity index 100% rename from Greenshot/icons/fugue/filter_highlight_grayscale.png rename to src/Greenshot/icons/fugue/filter_highlight_grayscale.png diff --git a/Greenshot/icons/fugue/filter_highlight_text.png b/src/Greenshot/icons/fugue/filter_highlight_text.png similarity index 100% rename from Greenshot/icons/fugue/filter_highlight_text.png rename to src/Greenshot/icons/fugue/filter_highlight_text.png diff --git a/Greenshot/icons/fugue/gear.png b/src/Greenshot/icons/fugue/gear.png similarity index 100% rename from Greenshot/icons/fugue/gear.png rename to src/Greenshot/icons/fugue/gear.png diff --git a/Greenshot/icons/fugue/highlighter-color.png b/src/Greenshot/icons/fugue/highlighter-color.png similarity index 100% rename from Greenshot/icons/fugue/highlighter-color.png rename to src/Greenshot/icons/fugue/highlighter-color.png diff --git a/Greenshot/icons/fugue/highlighter-text.png b/src/Greenshot/icons/fugue/highlighter-text.png similarity index 100% rename from Greenshot/icons/fugue/highlighter-text.png rename to src/Greenshot/icons/fugue/highlighter-text.png diff --git a/Greenshot/icons/fugue/image-blur.png b/src/Greenshot/icons/fugue/image-blur.png similarity index 100% rename from Greenshot/icons/fugue/image-blur.png rename to src/Greenshot/icons/fugue/image-blur.png diff --git a/Greenshot/icons/fugue/image-pixelate.png b/src/Greenshot/icons/fugue/image-pixelate.png similarity index 100% rename from Greenshot/icons/fugue/image-pixelate.png rename to src/Greenshot/icons/fugue/image-pixelate.png diff --git a/Greenshot/icons/fugue/images.png b/src/Greenshot/icons/fugue/images.png similarity index 100% rename from Greenshot/icons/fugue/images.png rename to src/Greenshot/icons/fugue/images.png diff --git a/Greenshot/icons/fugue/layer-shape-arrow.png b/src/Greenshot/icons/fugue/layer-shape-arrow.png similarity index 100% rename from Greenshot/icons/fugue/layer-shape-arrow.png rename to src/Greenshot/icons/fugue/layer-shape-arrow.png diff --git a/Greenshot/icons/fugue/layer-shape-ellipse.png b/src/Greenshot/icons/fugue/layer-shape-ellipse.png similarity index 100% rename from Greenshot/icons/fugue/layer-shape-ellipse.png rename to src/Greenshot/icons/fugue/layer-shape-ellipse.png diff --git a/Greenshot/icons/fugue/layer-shape-line.png b/src/Greenshot/icons/fugue/layer-shape-line.png similarity index 100% rename from Greenshot/icons/fugue/layer-shape-line.png rename to src/Greenshot/icons/fugue/layer-shape-line.png diff --git a/Greenshot/icons/fugue/layer-shape-text.png b/src/Greenshot/icons/fugue/layer-shape-text.png similarity index 100% rename from Greenshot/icons/fugue/layer-shape-text.png rename to src/Greenshot/icons/fugue/layer-shape-text.png diff --git a/Greenshot/icons/fugue/layer-shape.png b/src/Greenshot/icons/fugue/layer-shape.png similarity index 100% rename from Greenshot/icons/fugue/layer-shape.png rename to src/Greenshot/icons/fugue/layer-shape.png diff --git a/Greenshot/icons/fugue/magnifier-zoom-actual.png b/src/Greenshot/icons/fugue/magnifier-zoom-actual.png similarity index 100% rename from Greenshot/icons/fugue/magnifier-zoom-actual.png rename to src/Greenshot/icons/fugue/magnifier-zoom-actual.png diff --git a/Greenshot/icons/fugue/magnifier-zoom-fit.png b/src/Greenshot/icons/fugue/magnifier-zoom-fit.png similarity index 100% rename from Greenshot/icons/fugue/magnifier-zoom-fit.png rename to src/Greenshot/icons/fugue/magnifier-zoom-fit.png diff --git a/Greenshot/icons/fugue/magnifier-zoom-in.png b/src/Greenshot/icons/fugue/magnifier-zoom-in.png similarity index 100% rename from Greenshot/icons/fugue/magnifier-zoom-in.png rename to src/Greenshot/icons/fugue/magnifier-zoom-in.png diff --git a/Greenshot/icons/fugue/magnifier-zoom-out.png b/src/Greenshot/icons/fugue/magnifier-zoom-out.png similarity index 100% rename from Greenshot/icons/fugue/magnifier-zoom-out.png rename to src/Greenshot/icons/fugue/magnifier-zoom-out.png diff --git a/Greenshot/icons/fugue/magnifier-zoom.png b/src/Greenshot/icons/fugue/magnifier-zoom.png similarity index 100% rename from Greenshot/icons/fugue/magnifier-zoom.png rename to src/Greenshot/icons/fugue/magnifier-zoom.png diff --git a/Greenshot/icons/fugue/magnifier.png b/src/Greenshot/icons/fugue/magnifier.png similarity index 100% rename from Greenshot/icons/fugue/magnifier.png rename to src/Greenshot/icons/fugue/magnifier.png diff --git a/Greenshot/icons/fugue/mail-open-image.png b/src/Greenshot/icons/fugue/mail-open-image.png similarity index 100% rename from Greenshot/icons/fugue/mail-open-image.png rename to src/Greenshot/icons/fugue/mail-open-image.png diff --git a/Greenshot/icons/fugue/minus-circle.png b/src/Greenshot/icons/fugue/minus-circle.png similarity index 100% rename from Greenshot/icons/fugue/minus-circle.png rename to src/Greenshot/icons/fugue/minus-circle.png diff --git a/Greenshot/icons/fugue/money-coin.png b/src/Greenshot/icons/fugue/money-coin.png similarity index 100% rename from Greenshot/icons/fugue/money-coin.png rename to src/Greenshot/icons/fugue/money-coin.png diff --git a/Greenshot/icons/fugue/paint-can-color-bg.png b/src/Greenshot/icons/fugue/paint-can-color-bg.png similarity index 100% rename from Greenshot/icons/fugue/paint-can-color-bg.png rename to src/Greenshot/icons/fugue/paint-can-color-bg.png diff --git a/Greenshot/icons/fugue/paint-can-color.png b/src/Greenshot/icons/fugue/paint-can-color.png similarity index 100% rename from Greenshot/icons/fugue/paint-can-color.png rename to src/Greenshot/icons/fugue/paint-can-color.png diff --git a/Greenshot/icons/fugue/pencil-color-bg.png b/src/Greenshot/icons/fugue/pencil-color-bg.png similarity index 100% rename from Greenshot/icons/fugue/pencil-color-bg.png rename to src/Greenshot/icons/fugue/pencil-color-bg.png diff --git a/Greenshot/icons/fugue/pencil-color.png b/src/Greenshot/icons/fugue/pencil-color.png similarity index 100% rename from Greenshot/icons/fugue/pencil-color.png rename to src/Greenshot/icons/fugue/pencil-color.png diff --git a/Greenshot/icons/fugue/printer.png b/src/Greenshot/icons/fugue/printer.png similarity index 100% rename from Greenshot/icons/fugue/printer.png rename to src/Greenshot/icons/fugue/printer.png diff --git a/Greenshot/icons/fugue/question.png b/src/Greenshot/icons/fugue/question.png similarity index 100% rename from Greenshot/icons/fugue/question.png rename to src/Greenshot/icons/fugue/question.png diff --git a/Greenshot/icons/fugue/ruler-crop.png b/src/Greenshot/icons/fugue/ruler-crop.png similarity index 100% rename from Greenshot/icons/fugue/ruler-crop.png rename to src/Greenshot/icons/fugue/ruler-crop.png diff --git a/Greenshot/icons/fugue/scissors.png b/src/Greenshot/icons/fugue/scissors.png similarity index 100% rename from Greenshot/icons/fugue/scissors.png rename to src/Greenshot/icons/fugue/scissors.png diff --git a/Greenshot/icons/fugue/slash.png b/src/Greenshot/icons/fugue/slash.png similarity index 100% rename from Greenshot/icons/fugue/slash.png rename to src/Greenshot/icons/fugue/slash.png diff --git a/Greenshot/icons/fugue/tick.png b/src/Greenshot/icons/fugue/tick.png similarity index 100% rename from Greenshot/icons/fugue/tick.png rename to src/Greenshot/icons/fugue/tick.png diff --git a/Greenshot/icons/heart.png b/src/Greenshot/icons/heart.png similarity index 100% rename from Greenshot/icons/heart.png rename to src/Greenshot/icons/heart.png diff --git a/Greenshot/icons/help.png b/src/Greenshot/icons/help.png similarity index 100% rename from Greenshot/icons/help.png rename to src/Greenshot/icons/help.png diff --git a/Greenshot/icons/highlighter.png b/src/Greenshot/icons/highlighter.png similarity index 100% rename from Greenshot/icons/highlighter.png rename to src/Greenshot/icons/highlighter.png diff --git a/Greenshot/icons/layer-rotate-left.png b/src/Greenshot/icons/layer-rotate-left.png similarity index 100% rename from Greenshot/icons/layer-rotate-left.png rename to src/Greenshot/icons/layer-rotate-left.png diff --git a/Greenshot/icons/layer-rotate.png b/src/Greenshot/icons/layer-rotate.png similarity index 100% rename from Greenshot/icons/layer-rotate.png rename to src/Greenshot/icons/layer-rotate.png diff --git a/Greenshot/icons/notification-counter-01.png b/src/Greenshot/icons/notification-counter-01.png similarity index 100% rename from Greenshot/icons/notification-counter-01.png rename to src/Greenshot/icons/notification-counter-01.png diff --git a/Greenshot/icons/notification-counter-02.png b/src/Greenshot/icons/notification-counter-02.png similarity index 100% rename from Greenshot/icons/notification-counter-02.png rename to src/Greenshot/icons/notification-counter-02.png diff --git a/Greenshot/icons/notification-counter-03.png b/src/Greenshot/icons/notification-counter-03.png similarity index 100% rename from Greenshot/icons/notification-counter-03.png rename to src/Greenshot/icons/notification-counter-03.png diff --git a/Greenshot/icons/notification-counter-04.png b/src/Greenshot/icons/notification-counter-04.png similarity index 100% rename from Greenshot/icons/notification-counter-04.png rename to src/Greenshot/icons/notification-counter-04.png diff --git a/Greenshot/icons/notification-counter-05.png b/src/Greenshot/icons/notification-counter-05.png similarity index 100% rename from Greenshot/icons/notification-counter-05.png rename to src/Greenshot/icons/notification-counter-05.png diff --git a/Greenshot/icons/notification-counter-06.png b/src/Greenshot/icons/notification-counter-06.png similarity index 100% rename from Greenshot/icons/notification-counter-06.png rename to src/Greenshot/icons/notification-counter-06.png diff --git a/Greenshot/icons/notification-counter-07.png b/src/Greenshot/icons/notification-counter-07.png similarity index 100% rename from Greenshot/icons/notification-counter-07.png rename to src/Greenshot/icons/notification-counter-07.png diff --git a/Greenshot/icons/notification-counter-08.png b/src/Greenshot/icons/notification-counter-08.png similarity index 100% rename from Greenshot/icons/notification-counter-08.png rename to src/Greenshot/icons/notification-counter-08.png diff --git a/Greenshot/icons/notification-counter-09.png b/src/Greenshot/icons/notification-counter-09.png similarity index 100% rename from Greenshot/icons/notification-counter-09.png rename to src/Greenshot/icons/notification-counter-09.png diff --git a/Greenshot/icons/notification-counter-10.png b/src/Greenshot/icons/notification-counter-10.png similarity index 100% rename from Greenshot/icons/notification-counter-10.png rename to src/Greenshot/icons/notification-counter-10.png diff --git a/Greenshot/icons/notification-counter-11.png b/src/Greenshot/icons/notification-counter-11.png similarity index 100% rename from Greenshot/icons/notification-counter-11.png rename to src/Greenshot/icons/notification-counter-11.png diff --git a/Greenshot/icons/notification-counter-12.png b/src/Greenshot/icons/notification-counter-12.png similarity index 100% rename from Greenshot/icons/notification-counter-12.png rename to src/Greenshot/icons/notification-counter-12.png diff --git a/Greenshot/icons/notification-counter-13.png b/src/Greenshot/icons/notification-counter-13.png similarity index 100% rename from Greenshot/icons/notification-counter-13.png rename to src/Greenshot/icons/notification-counter-13.png diff --git a/Greenshot/icons/notification-counter-14.png b/src/Greenshot/icons/notification-counter-14.png similarity index 100% rename from Greenshot/icons/notification-counter-14.png rename to src/Greenshot/icons/notification-counter-14.png diff --git a/Greenshot/icons/notification-counter-15.png b/src/Greenshot/icons/notification-counter-15.png similarity index 100% rename from Greenshot/icons/notification-counter-15.png rename to src/Greenshot/icons/notification-counter-15.png diff --git a/Greenshot/icons/notification-counter-16.png b/src/Greenshot/icons/notification-counter-16.png similarity index 100% rename from Greenshot/icons/notification-counter-16.png rename to src/Greenshot/icons/notification-counter-16.png diff --git a/Greenshot/icons/notification-counter-17.png b/src/Greenshot/icons/notification-counter-17.png similarity index 100% rename from Greenshot/icons/notification-counter-17.png rename to src/Greenshot/icons/notification-counter-17.png diff --git a/Greenshot/icons/notification-counter-18.png b/src/Greenshot/icons/notification-counter-18.png similarity index 100% rename from Greenshot/icons/notification-counter-18.png rename to src/Greenshot/icons/notification-counter-18.png diff --git a/Greenshot/icons/notification-counter-19.png b/src/Greenshot/icons/notification-counter-19.png similarity index 100% rename from Greenshot/icons/notification-counter-19.png rename to src/Greenshot/icons/notification-counter-19.png diff --git a/Greenshot/icons/notification-counter-20-plus.png b/src/Greenshot/icons/notification-counter-20-plus.png similarity index 100% rename from Greenshot/icons/notification-counter-20-plus.png rename to src/Greenshot/icons/notification-counter-20-plus.png diff --git a/Greenshot/icons/notification-counter-20.png b/src/Greenshot/icons/notification-counter-20.png similarity index 100% rename from Greenshot/icons/notification-counter-20.png rename to src/Greenshot/icons/notification-counter-20.png diff --git a/Greenshot/icons/page_copy.png b/src/Greenshot/icons/page_copy.png similarity index 100% rename from Greenshot/icons/page_copy.png rename to src/Greenshot/icons/page_copy.png diff --git a/Greenshot/icons/palette.png b/src/Greenshot/icons/palette.png similarity index 100% rename from Greenshot/icons/palette.png rename to src/Greenshot/icons/palette.png diff --git a/Greenshot/icons/picture_save.png b/src/Greenshot/icons/picture_save.png similarity index 100% rename from Greenshot/icons/picture_save.png rename to src/Greenshot/icons/picture_save.png diff --git a/Greenshot/icons/picture_saveas.png b/src/Greenshot/icons/picture_saveas.png similarity index 100% rename from Greenshot/icons/picture_saveas.png rename to src/Greenshot/icons/picture_saveas.png diff --git a/Greenshot/icons/picture_to_clipboard.png b/src/Greenshot/icons/picture_to_clipboard.png similarity index 100% rename from Greenshot/icons/picture_to_clipboard.png rename to src/Greenshot/icons/picture_to_clipboard.png diff --git a/Greenshot/icons/pipette.png b/src/Greenshot/icons/pipette.png similarity index 100% rename from Greenshot/icons/pipette.png rename to src/Greenshot/icons/pipette.png diff --git a/Greenshot/icons/printer.png b/src/Greenshot/icons/printer.png similarity index 100% rename from Greenshot/icons/printer.png rename to src/Greenshot/icons/printer.png diff --git a/Greenshot/icons/propertyitemcontainer.gif b/src/Greenshot/icons/propertyitemcontainer.gif similarity index 100% rename from Greenshot/icons/propertyitemcontainer.gif rename to src/Greenshot/icons/propertyitemcontainer.gif diff --git a/Greenshot/icons/redo.png b/src/Greenshot/icons/redo.png similarity index 100% rename from Greenshot/icons/redo.png rename to src/Greenshot/icons/redo.png diff --git a/Greenshot/icons/resize.png b/src/Greenshot/icons/resize.png similarity index 100% rename from Greenshot/icons/resize.png rename to src/Greenshot/icons/resize.png diff --git a/Greenshot/icons/ruler-crop.png b/src/Greenshot/icons/ruler-crop.png similarity index 100% rename from Greenshot/icons/ruler-crop.png rename to src/Greenshot/icons/ruler-crop.png diff --git a/Greenshot/icons/shadow.png b/src/Greenshot/icons/shadow.png similarity index 100% rename from Greenshot/icons/shadow.png rename to src/Greenshot/icons/shadow.png diff --git a/Greenshot/icons/shape_arrow_add.png b/src/Greenshot/icons/shape_arrow_add.png similarity index 100% rename from Greenshot/icons/shape_arrow_add.png rename to src/Greenshot/icons/shape_arrow_add.png diff --git a/Greenshot/icons/shape_arrowheads.png b/src/Greenshot/icons/shape_arrowheads.png similarity index 100% rename from Greenshot/icons/shape_arrowheads.png rename to src/Greenshot/icons/shape_arrowheads.png diff --git a/Greenshot/icons/shape_copy.png b/src/Greenshot/icons/shape_copy.png similarity index 100% rename from Greenshot/icons/shape_copy.png rename to src/Greenshot/icons/shape_copy.png diff --git a/Greenshot/icons/shape_ellipse_add.png b/src/Greenshot/icons/shape_ellipse_add.png similarity index 100% rename from Greenshot/icons/shape_ellipse_add.png rename to src/Greenshot/icons/shape_ellipse_add.png diff --git a/Greenshot/icons/shape_ellipse_delete.png b/src/Greenshot/icons/shape_ellipse_delete.png similarity index 100% rename from Greenshot/icons/shape_ellipse_delete.png rename to src/Greenshot/icons/shape_ellipse_delete.png diff --git a/Greenshot/icons/shape_line.png b/src/Greenshot/icons/shape_line.png similarity index 100% rename from Greenshot/icons/shape_line.png rename to src/Greenshot/icons/shape_line.png diff --git a/Greenshot/icons/shape_paste.png b/src/Greenshot/icons/shape_paste.png similarity index 100% rename from Greenshot/icons/shape_paste.png rename to src/Greenshot/icons/shape_paste.png diff --git a/Greenshot/icons/shape_square_add.png b/src/Greenshot/icons/shape_square_add.png similarity index 100% rename from Greenshot/icons/shape_square_add.png rename to src/Greenshot/icons/shape_square_add.png diff --git a/Greenshot/icons/shape_square_bordercolor.png b/src/Greenshot/icons/shape_square_bordercolor.png similarity index 100% rename from Greenshot/icons/shape_square_bordercolor.png rename to src/Greenshot/icons/shape_square_bordercolor.png diff --git a/Greenshot/icons/shape_square_delete.png b/src/Greenshot/icons/shape_square_delete.png similarity index 100% rename from Greenshot/icons/shape_square_delete.png rename to src/Greenshot/icons/shape_square_delete.png diff --git a/Greenshot/icons/shape_square_fillcolor.png b/src/Greenshot/icons/shape_square_fillcolor.png similarity index 100% rename from Greenshot/icons/shape_square_fillcolor.png rename to src/Greenshot/icons/shape_square_fillcolor.png diff --git a/Greenshot/icons/text_bold.png b/src/Greenshot/icons/text_bold.png similarity index 100% rename from Greenshot/icons/text_bold.png rename to src/Greenshot/icons/text_bold.png diff --git a/Greenshot/icons/text_dropcaps.png b/src/Greenshot/icons/text_dropcaps.png similarity index 100% rename from Greenshot/icons/text_dropcaps.png rename to src/Greenshot/icons/text_dropcaps.png diff --git a/Greenshot/icons/text_italic.png b/src/Greenshot/icons/text_italic.png similarity index 100% rename from Greenshot/icons/text_italic.png rename to src/Greenshot/icons/text_italic.png diff --git a/Greenshot/icons/text_underline.png b/src/Greenshot/icons/text_underline.png similarity index 100% rename from Greenshot/icons/text_underline.png rename to src/Greenshot/icons/text_underline.png diff --git a/Greenshot/icons/textfield_delete.png b/src/Greenshot/icons/textfield_delete.png similarity index 100% rename from Greenshot/icons/textfield_delete.png rename to src/Greenshot/icons/textfield_delete.png diff --git a/Greenshot/icons/undo.png b/src/Greenshot/icons/undo.png similarity index 100% rename from Greenshot/icons/undo.png rename to src/Greenshot/icons/undo.png diff --git a/Greenshot/icons/wand-hat.png b/src/Greenshot/icons/wand-hat.png similarity index 100% rename from Greenshot/icons/wand-hat.png rename to src/Greenshot/icons/wand-hat.png diff --git a/Greenshot/icons/wrench.png b/src/Greenshot/icons/wrench.png similarity index 100% rename from Greenshot/icons/wrench.png rename to src/Greenshot/icons/wrench.png diff --git a/Greenshot/icons/wrench_orange.png b/src/Greenshot/icons/wrench_orange.png similarity index 100% rename from Greenshot/icons/wrench_orange.png rename to src/Greenshot/icons/wrench_orange.png diff --git a/Greenshot/icons/zoom.png b/src/Greenshot/icons/zoom.png similarity index 100% rename from Greenshot/icons/zoom.png rename to src/Greenshot/icons/zoom.png diff --git a/Greenshot/log4net-debug.xml b/src/Greenshot/log4net-debug.xml similarity index 100% rename from Greenshot/log4net-debug.xml rename to src/Greenshot/log4net-debug.xml diff --git a/Greenshot/log4net-portable.xml b/src/Greenshot/log4net-portable.xml similarity index 100% rename from Greenshot/log4net-portable.xml rename to src/Greenshot/log4net-portable.xml diff --git a/Greenshot/log4net-zip.xml b/src/Greenshot/log4net-zip.xml similarity index 100% rename from Greenshot/log4net-zip.xml rename to src/Greenshot/log4net-zip.xml diff --git a/Greenshot/log4net.xml b/src/Greenshot/log4net.xml similarity index 100% rename from Greenshot/log4net.xml rename to src/Greenshot/log4net.xml diff --git a/Greenshot/releases/additional_files/installer.txt b/src/Greenshot/releases/additional_files/installer.txt similarity index 100% rename from Greenshot/releases/additional_files/installer.txt rename to src/Greenshot/releases/additional_files/installer.txt diff --git a/Greenshot/releases/additional_files/license.txt b/src/Greenshot/releases/additional_files/license.txt similarity index 100% rename from Greenshot/releases/additional_files/license.txt rename to src/Greenshot/releases/additional_files/license.txt diff --git a/Greenshot/releases/additional_files/readme.txt b/src/Greenshot/releases/additional_files/readme.txt similarity index 100% rename from Greenshot/releases/additional_files/readme.txt rename to src/Greenshot/releases/additional_files/readme.txt diff --git a/Greenshot/releases/appinfo.ini.template b/src/Greenshot/releases/appinfo.ini.template similarity index 100% rename from Greenshot/releases/appinfo.ini.template rename to src/Greenshot/releases/appinfo.ini.template diff --git a/Greenshot/releases/innosetup/IssProc/IssProc.dll b/src/Greenshot/releases/innosetup/IssProc/IssProc.dll similarity index 100% rename from Greenshot/releases/innosetup/IssProc/IssProc.dll rename to src/Greenshot/releases/innosetup/IssProc/IssProc.dll diff --git a/Greenshot/releases/innosetup/IssProc/IssProcLanguage.ini b/src/Greenshot/releases/innosetup/IssProc/IssProcLanguage.ini similarity index 100% rename from Greenshot/releases/innosetup/IssProc/IssProcLanguage.ini rename to src/Greenshot/releases/innosetup/IssProc/IssProcLanguage.ini diff --git a/Greenshot/releases/innosetup/Languages/Afrikaans.isl b/src/Greenshot/releases/innosetup/Languages/Afrikaans.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Afrikaans.isl rename to src/Greenshot/releases/innosetup/Languages/Afrikaans.isl diff --git a/Greenshot/releases/innosetup/Languages/Albanian.isl b/src/Greenshot/releases/innosetup/Languages/Albanian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Albanian.isl rename to src/Greenshot/releases/innosetup/Languages/Albanian.isl diff --git a/Greenshot/releases/innosetup/Languages/Arabic.isl b/src/Greenshot/releases/innosetup/Languages/Arabic.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Arabic.isl rename to src/Greenshot/releases/innosetup/Languages/Arabic.isl diff --git a/Greenshot/releases/innosetup/Languages/Asturian.isl b/src/Greenshot/releases/innosetup/Languages/Asturian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Asturian.isl rename to src/Greenshot/releases/innosetup/Languages/Asturian.isl diff --git a/Greenshot/releases/innosetup/Languages/Basque.isl b/src/Greenshot/releases/innosetup/Languages/Basque.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Basque.isl rename to src/Greenshot/releases/innosetup/Languages/Basque.isl diff --git a/Greenshot/releases/innosetup/Languages/Belarusian.isl b/src/Greenshot/releases/innosetup/Languages/Belarusian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Belarusian.isl rename to src/Greenshot/releases/innosetup/Languages/Belarusian.isl diff --git a/Greenshot/releases/innosetup/Languages/Bengali.islu b/src/Greenshot/releases/innosetup/Languages/Bengali.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Bengali.islu rename to src/Greenshot/releases/innosetup/Languages/Bengali.islu diff --git a/Greenshot/releases/innosetup/Languages/Bosnian.isl b/src/Greenshot/releases/innosetup/Languages/Bosnian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Bosnian.isl rename to src/Greenshot/releases/innosetup/Languages/Bosnian.isl diff --git a/Greenshot/releases/innosetup/Languages/Bulgarian.isl b/src/Greenshot/releases/innosetup/Languages/Bulgarian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Bulgarian.isl rename to src/Greenshot/releases/innosetup/Languages/Bulgarian.isl diff --git a/Greenshot/releases/innosetup/Languages/ChineseSimplified.isl b/src/Greenshot/releases/innosetup/Languages/ChineseSimplified.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/ChineseSimplified.isl rename to src/Greenshot/releases/innosetup/Languages/ChineseSimplified.isl diff --git a/Greenshot/releases/innosetup/Languages/ChineseTraditional.isl b/src/Greenshot/releases/innosetup/Languages/ChineseTraditional.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/ChineseTraditional.isl rename to src/Greenshot/releases/innosetup/Languages/ChineseTraditional.isl diff --git a/Greenshot/releases/innosetup/Languages/Croatian.isl b/src/Greenshot/releases/innosetup/Languages/Croatian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Croatian.isl rename to src/Greenshot/releases/innosetup/Languages/Croatian.isl diff --git a/Greenshot/releases/innosetup/Languages/EnglishBritish.isl b/src/Greenshot/releases/innosetup/Languages/EnglishBritish.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/EnglishBritish.isl rename to src/Greenshot/releases/innosetup/Languages/EnglishBritish.isl diff --git a/Greenshot/releases/innosetup/Languages/Esperanto.isl b/src/Greenshot/releases/innosetup/Languages/Esperanto.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Esperanto.isl rename to src/Greenshot/releases/innosetup/Languages/Esperanto.isl diff --git a/Greenshot/releases/innosetup/Languages/Estonian.isl b/src/Greenshot/releases/innosetup/Languages/Estonian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Estonian.isl rename to src/Greenshot/releases/innosetup/Languages/Estonian.isl diff --git a/Greenshot/releases/innosetup/Languages/Farsi.isl b/src/Greenshot/releases/innosetup/Languages/Farsi.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Farsi.isl rename to src/Greenshot/releases/innosetup/Languages/Farsi.isl diff --git a/Greenshot/releases/innosetup/Languages/Galician.isl b/src/Greenshot/releases/innosetup/Languages/Galician.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Galician.isl rename to src/Greenshot/releases/innosetup/Languages/Galician.isl diff --git a/Greenshot/releases/innosetup/Languages/Georgian.islu b/src/Greenshot/releases/innosetup/Languages/Georgian.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Georgian.islu rename to src/Greenshot/releases/innosetup/Languages/Georgian.islu diff --git a/Greenshot/releases/innosetup/Languages/Greek.isl b/src/Greenshot/releases/innosetup/Languages/Greek.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Greek.isl rename to src/Greenshot/releases/innosetup/Languages/Greek.isl diff --git a/Greenshot/releases/innosetup/Languages/Hindi.islu b/src/Greenshot/releases/innosetup/Languages/Hindi.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Hindi.islu rename to src/Greenshot/releases/innosetup/Languages/Hindi.islu diff --git a/Greenshot/releases/innosetup/Languages/Hungarian.isl b/src/Greenshot/releases/innosetup/Languages/Hungarian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Hungarian.isl rename to src/Greenshot/releases/innosetup/Languages/Hungarian.isl diff --git a/Greenshot/releases/innosetup/Languages/Indonesian.isl b/src/Greenshot/releases/innosetup/Languages/Indonesian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Indonesian.isl rename to src/Greenshot/releases/innosetup/Languages/Indonesian.isl diff --git a/Greenshot/releases/innosetup/Languages/Kazakh.islu b/src/Greenshot/releases/innosetup/Languages/Kazakh.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Kazakh.islu rename to src/Greenshot/releases/innosetup/Languages/Kazakh.islu diff --git a/Greenshot/releases/innosetup/Languages/Korean.isl b/src/Greenshot/releases/innosetup/Languages/Korean.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Korean.isl rename to src/Greenshot/releases/innosetup/Languages/Korean.isl diff --git a/Greenshot/releases/innosetup/Languages/Kurdish.isl b/src/Greenshot/releases/innosetup/Languages/Kurdish.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Kurdish.isl rename to src/Greenshot/releases/innosetup/Languages/Kurdish.isl diff --git a/Greenshot/releases/innosetup/Languages/Latvian.isl b/src/Greenshot/releases/innosetup/Languages/Latvian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Latvian.isl rename to src/Greenshot/releases/innosetup/Languages/Latvian.isl diff --git a/Greenshot/releases/innosetup/Languages/Ligurian.isl b/src/Greenshot/releases/innosetup/Languages/Ligurian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Ligurian.isl rename to src/Greenshot/releases/innosetup/Languages/Ligurian.isl diff --git a/Greenshot/releases/innosetup/Languages/Lithuanian.isl b/src/Greenshot/releases/innosetup/Languages/Lithuanian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Lithuanian.isl rename to src/Greenshot/releases/innosetup/Languages/Lithuanian.isl diff --git a/Greenshot/releases/innosetup/Languages/Luxemburgish.isl b/src/Greenshot/releases/innosetup/Languages/Luxemburgish.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Luxemburgish.isl rename to src/Greenshot/releases/innosetup/Languages/Luxemburgish.isl diff --git a/Greenshot/releases/innosetup/Languages/Macedonian.isl b/src/Greenshot/releases/innosetup/Languages/Macedonian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Macedonian.isl rename to src/Greenshot/releases/innosetup/Languages/Macedonian.isl diff --git a/Greenshot/releases/innosetup/Languages/Malaysian.isl b/src/Greenshot/releases/innosetup/Languages/Malaysian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Malaysian.isl rename to src/Greenshot/releases/innosetup/Languages/Malaysian.isl diff --git a/Greenshot/releases/innosetup/Languages/Marathi.islu b/src/Greenshot/releases/innosetup/Languages/Marathi.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Marathi.islu rename to src/Greenshot/releases/innosetup/Languages/Marathi.islu diff --git a/Greenshot/releases/innosetup/Languages/Mongolian.isl b/src/Greenshot/releases/innosetup/Languages/Mongolian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Mongolian.isl rename to src/Greenshot/releases/innosetup/Languages/Mongolian.isl diff --git a/Greenshot/releases/innosetup/Languages/Montenegrian.isl b/src/Greenshot/releases/innosetup/Languages/Montenegrian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Montenegrian.isl rename to src/Greenshot/releases/innosetup/Languages/Montenegrian.isl diff --git a/Greenshot/releases/innosetup/Languages/Nepali.islu b/src/Greenshot/releases/innosetup/Languages/Nepali.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Nepali.islu rename to src/Greenshot/releases/innosetup/Languages/Nepali.islu diff --git a/Greenshot/releases/innosetup/Languages/NorwegianNynorsk.isl b/src/Greenshot/releases/innosetup/Languages/NorwegianNynorsk.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/NorwegianNynorsk.isl rename to src/Greenshot/releases/innosetup/Languages/NorwegianNynorsk.isl diff --git a/Greenshot/releases/innosetup/Languages/Occitan.isl b/src/Greenshot/releases/innosetup/Languages/Occitan.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Occitan.isl rename to src/Greenshot/releases/innosetup/Languages/Occitan.isl diff --git a/Greenshot/releases/innosetup/Languages/Romanian.isl b/src/Greenshot/releases/innosetup/Languages/Romanian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Romanian.isl rename to src/Greenshot/releases/innosetup/Languages/Romanian.isl diff --git a/Greenshot/releases/innosetup/Languages/ScottishGaelic.isl b/src/Greenshot/releases/innosetup/Languages/ScottishGaelic.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/ScottishGaelic.isl rename to src/Greenshot/releases/innosetup/Languages/ScottishGaelic.isl diff --git a/Greenshot/releases/innosetup/Languages/SerbianCyrillic.isl b/src/Greenshot/releases/innosetup/Languages/SerbianCyrillic.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/SerbianCyrillic.isl rename to src/Greenshot/releases/innosetup/Languages/SerbianCyrillic.isl diff --git a/Greenshot/releases/innosetup/Languages/SerbianLatin.isl b/src/Greenshot/releases/innosetup/Languages/SerbianLatin.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/SerbianLatin.isl rename to src/Greenshot/releases/innosetup/Languages/SerbianLatin.isl diff --git a/Greenshot/releases/innosetup/Languages/Sinhala.islu b/src/Greenshot/releases/innosetup/Languages/Sinhala.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Sinhala.islu rename to src/Greenshot/releases/innosetup/Languages/Sinhala.islu diff --git a/Greenshot/releases/innosetup/Languages/Swedish.isl b/src/Greenshot/releases/innosetup/Languages/Swedish.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Swedish.isl rename to src/Greenshot/releases/innosetup/Languages/Swedish.isl diff --git a/Greenshot/releases/innosetup/Languages/Tatar.isl b/src/Greenshot/releases/innosetup/Languages/Tatar.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Tatar.isl rename to src/Greenshot/releases/innosetup/Languages/Tatar.isl diff --git a/Greenshot/releases/innosetup/Languages/Thai.isl b/src/Greenshot/releases/innosetup/Languages/Thai.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Thai.isl rename to src/Greenshot/releases/innosetup/Languages/Thai.isl diff --git a/Greenshot/releases/innosetup/Languages/Uyghur.islu b/src/Greenshot/releases/innosetup/Languages/Uyghur.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Uyghur.islu rename to src/Greenshot/releases/innosetup/Languages/Uyghur.islu diff --git a/Greenshot/releases/innosetup/Languages/Uzbek.isl b/src/Greenshot/releases/innosetup/Languages/Uzbek.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Uzbek.isl rename to src/Greenshot/releases/innosetup/Languages/Uzbek.isl diff --git a/Greenshot/releases/innosetup/Languages/Valencian.isl b/src/Greenshot/releases/innosetup/Languages/Valencian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Valencian.isl rename to src/Greenshot/releases/innosetup/Languages/Valencian.isl diff --git a/Greenshot/releases/innosetup/Languages/Vietnamese.isl b/src/Greenshot/releases/innosetup/Languages/Vietnamese.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Vietnamese.isl rename to src/Greenshot/releases/innosetup/Languages/Vietnamese.isl diff --git a/Greenshot/releases/innosetup/installer-large.bmp b/src/Greenshot/releases/innosetup/installer-large.bmp similarity index 100% rename from Greenshot/releases/innosetup/installer-large.bmp rename to src/Greenshot/releases/innosetup/installer-large.bmp diff --git a/Greenshot/releases/innosetup/installer-small.bmp b/src/Greenshot/releases/innosetup/installer-small.bmp similarity index 100% rename from Greenshot/releases/innosetup/installer-small.bmp rename to src/Greenshot/releases/innosetup/installer-small.bmp diff --git a/Greenshot/releases/innosetup/scripts/isxdl/chinese.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/chinese.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/chinese.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/chinese.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/czech.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/czech.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/czech.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/czech.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/dutch.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/dutch.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/dutch.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/dutch.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/english.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/english.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/english.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/english.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/french.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/french.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/french.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/french.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/french2.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/french2.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/french2.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/french2.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/french3.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/french3.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/french3.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/french3.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/german.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/german.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/german.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/german.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/isxdl.dll b/src/Greenshot/releases/innosetup/scripts/isxdl/isxdl.dll similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/isxdl.dll rename to src/Greenshot/releases/innosetup/scripts/isxdl/isxdl.dll diff --git a/Greenshot/releases/innosetup/scripts/isxdl/isxdl.iss b/src/Greenshot/releases/innosetup/scripts/isxdl/isxdl.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/isxdl.iss rename to src/Greenshot/releases/innosetup/scripts/isxdl/isxdl.iss diff --git a/Greenshot/releases/innosetup/scripts/isxdl/italian.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/italian.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/italian.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/italian.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/japanese.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/japanese.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/japanese.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/japanese.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/korean.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/korean.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/korean.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/korean.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/norwegian.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/norwegian.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/norwegian.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/norwegian.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/polish.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/polish.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/polish.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/polish.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/portugues.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/portugues.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/portugues.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/portugues.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/portuguese.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/portuguese.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/portuguese.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/portuguese.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/russian.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/russian.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/russian.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/russian.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/spanish.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/spanish.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/spanish.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/spanish.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/swedish.ini b/src/Greenshot/releases/innosetup/scripts/isxdl/swedish.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/swedish.ini rename to src/Greenshot/releases/innosetup/scripts/isxdl/swedish.ini diff --git a/Greenshot/releases/innosetup/scripts/lang/chinese.iss b/src/Greenshot/releases/innosetup/scripts/lang/chinese.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/chinese.iss rename to src/Greenshot/releases/innosetup/scripts/lang/chinese.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/dutch.iss b/src/Greenshot/releases/innosetup/scripts/lang/dutch.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/dutch.iss rename to src/Greenshot/releases/innosetup/scripts/lang/dutch.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/english.iss b/src/Greenshot/releases/innosetup/scripts/lang/english.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/english.iss rename to src/Greenshot/releases/innosetup/scripts/lang/english.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/french.iss b/src/Greenshot/releases/innosetup/scripts/lang/french.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/french.iss rename to src/Greenshot/releases/innosetup/scripts/lang/french.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/german.iss b/src/Greenshot/releases/innosetup/scripts/lang/german.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/german.iss rename to src/Greenshot/releases/innosetup/scripts/lang/german.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/italian.iss b/src/Greenshot/releases/innosetup/scripts/lang/italian.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/italian.iss rename to src/Greenshot/releases/innosetup/scripts/lang/italian.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/japanese.iss b/src/Greenshot/releases/innosetup/scripts/lang/japanese.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/japanese.iss rename to src/Greenshot/releases/innosetup/scripts/lang/japanese.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/polish.iss b/src/Greenshot/releases/innosetup/scripts/lang/polish.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/polish.iss rename to src/Greenshot/releases/innosetup/scripts/lang/polish.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/russian.iss b/src/Greenshot/releases/innosetup/scripts/lang/russian.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/russian.iss rename to src/Greenshot/releases/innosetup/scripts/lang/russian.iss diff --git a/Greenshot/releases/innosetup/scripts/products.iss b/src/Greenshot/releases/innosetup/scripts/products.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products.iss rename to src/Greenshot/releases/innosetup/scripts/products.iss diff --git a/Greenshot/releases/innosetup/scripts/products.pas b/src/Greenshot/releases/innosetup/scripts/products.pas similarity index 100% rename from Greenshot/releases/innosetup/scripts/products.pas rename to src/Greenshot/releases/innosetup/scripts/products.pas diff --git a/Greenshot/releases/innosetup/scripts/products/directxruntime.iss b/src/Greenshot/releases/innosetup/scripts/products/directxruntime.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/directxruntime.iss rename to src/Greenshot/releases/innosetup/scripts/products/directxruntime.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx11.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx11.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx11.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx11.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx11lp.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx11lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx11lp.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx11lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx11sp1.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx11sp1.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx11sp1.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx11sp1.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx20.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20lp.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20lp.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx20lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1lp.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1lp.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2lp.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2lp.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx35.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx35.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx35.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx35.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx35lp.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx35lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx35lp.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx35lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1lp.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1lp.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx40client.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx40client.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx40client.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx40client.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx40full.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx40full.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx40full.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx40full.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx45.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx45.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx45.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx45.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx46.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx46.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx46.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx46.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx47.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx47.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx47.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx47.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx48.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfx48.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx48.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfx48.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfxversion.iss b/src/Greenshot/releases/innosetup/scripts/products/dotnetfxversion.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfxversion.iss rename to src/Greenshot/releases/innosetup/scripts/products/dotnetfxversion.iss diff --git a/Greenshot/releases/innosetup/scripts/products/fileversion.iss b/src/Greenshot/releases/innosetup/scripts/products/fileversion.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/fileversion.iss rename to src/Greenshot/releases/innosetup/scripts/products/fileversion.iss diff --git a/Greenshot/releases/innosetup/scripts/products/ie6.iss b/src/Greenshot/releases/innosetup/scripts/products/ie6.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/ie6.iss rename to src/Greenshot/releases/innosetup/scripts/products/ie6.iss diff --git a/Greenshot/releases/innosetup/scripts/products/iis.iss b/src/Greenshot/releases/innosetup/scripts/products/iis.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/iis.iss rename to src/Greenshot/releases/innosetup/scripts/products/iis.iss diff --git a/Greenshot/releases/innosetup/scripts/products/jet4sp8.iss b/src/Greenshot/releases/innosetup/scripts/products/jet4sp8.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/jet4sp8.iss rename to src/Greenshot/releases/innosetup/scripts/products/jet4sp8.iss diff --git a/Greenshot/releases/innosetup/scripts/products/kb835732.iss b/src/Greenshot/releases/innosetup/scripts/products/kb835732.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/kb835732.iss rename to src/Greenshot/releases/innosetup/scripts/products/kb835732.iss diff --git a/Greenshot/releases/innosetup/scripts/products/mdac28.iss b/src/Greenshot/releases/innosetup/scripts/products/mdac28.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/mdac28.iss rename to src/Greenshot/releases/innosetup/scripts/products/mdac28.iss diff --git a/Greenshot/releases/innosetup/scripts/products/msi20.iss b/src/Greenshot/releases/innosetup/scripts/products/msi20.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/msi20.iss rename to src/Greenshot/releases/innosetup/scripts/products/msi20.iss diff --git a/Greenshot/releases/innosetup/scripts/products/msi31.iss b/src/Greenshot/releases/innosetup/scripts/products/msi31.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/msi31.iss rename to src/Greenshot/releases/innosetup/scripts/products/msi31.iss diff --git a/Greenshot/releases/innosetup/scripts/products/msi45.iss b/src/Greenshot/releases/innosetup/scripts/products/msi45.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/msi45.iss rename to src/Greenshot/releases/innosetup/scripts/products/msi45.iss diff --git a/Greenshot/releases/innosetup/scripts/products/msiproduct.iss b/src/Greenshot/releases/innosetup/scripts/products/msiproduct.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/msiproduct.iss rename to src/Greenshot/releases/innosetup/scripts/products/msiproduct.iss diff --git a/Greenshot/releases/innosetup/scripts/products/sql2005express.iss b/src/Greenshot/releases/innosetup/scripts/products/sql2005express.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/sql2005express.iss rename to src/Greenshot/releases/innosetup/scripts/products/sql2005express.iss diff --git a/Greenshot/releases/innosetup/scripts/products/sql2008express.iss b/src/Greenshot/releases/innosetup/scripts/products/sql2008express.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/sql2008express.iss rename to src/Greenshot/releases/innosetup/scripts/products/sql2008express.iss diff --git a/Greenshot/releases/innosetup/scripts/products/sqlcompact35sp2.iss b/src/Greenshot/releases/innosetup/scripts/products/sqlcompact35sp2.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/sqlcompact35sp2.iss rename to src/Greenshot/releases/innosetup/scripts/products/sqlcompact35sp2.iss diff --git a/Greenshot/releases/innosetup/scripts/products/stringversion.iss b/src/Greenshot/releases/innosetup/scripts/products/stringversion.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/stringversion.iss rename to src/Greenshot/releases/innosetup/scripts/products/stringversion.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2005.iss b/src/Greenshot/releases/innosetup/scripts/products/vcredist2005.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2005.iss rename to src/Greenshot/releases/innosetup/scripts/products/vcredist2005.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2008.iss b/src/Greenshot/releases/innosetup/scripts/products/vcredist2008.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2008.iss rename to src/Greenshot/releases/innosetup/scripts/products/vcredist2008.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2010.iss b/src/Greenshot/releases/innosetup/scripts/products/vcredist2010.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2010.iss rename to src/Greenshot/releases/innosetup/scripts/products/vcredist2010.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2012.iss b/src/Greenshot/releases/innosetup/scripts/products/vcredist2012.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2012.iss rename to src/Greenshot/releases/innosetup/scripts/products/vcredist2012.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2013.iss b/src/Greenshot/releases/innosetup/scripts/products/vcredist2013.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2013.iss rename to src/Greenshot/releases/innosetup/scripts/products/vcredist2013.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2015.iss b/src/Greenshot/releases/innosetup/scripts/products/vcredist2015.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2015.iss rename to src/Greenshot/releases/innosetup/scripts/products/vcredist2015.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2017.iss b/src/Greenshot/releases/innosetup/scripts/products/vcredist2017.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2017.iss rename to src/Greenshot/releases/innosetup/scripts/products/vcredist2017.iss diff --git a/Greenshot/releases/innosetup/scripts/products/wic.iss b/src/Greenshot/releases/innosetup/scripts/products/wic.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/wic.iss rename to src/Greenshot/releases/innosetup/scripts/products/wic.iss diff --git a/Greenshot/releases/innosetup/scripts/products/winversion.iss b/src/Greenshot/releases/innosetup/scripts/products/winversion.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/winversion.iss rename to src/Greenshot/releases/innosetup/scripts/products/winversion.iss diff --git a/Greenshot/releases/innosetup/setup.iss b/src/Greenshot/releases/innosetup/setup.iss similarity index 100% rename from Greenshot/releases/innosetup/setup.iss rename to src/Greenshot/releases/innosetup/setup.iss diff --git a/Greenshot/releases/portable/App/AppInfo/appicon.ico b/src/Greenshot/releases/portable/App/AppInfo/appicon.ico similarity index 100% rename from Greenshot/releases/portable/App/AppInfo/appicon.ico rename to src/Greenshot/releases/portable/App/AppInfo/appicon.ico diff --git a/Greenshot/releases/portable/App/AppInfo/appicon_16.png b/src/Greenshot/releases/portable/App/AppInfo/appicon_16.png similarity index 100% rename from Greenshot/releases/portable/App/AppInfo/appicon_16.png rename to src/Greenshot/releases/portable/App/AppInfo/appicon_16.png diff --git a/Greenshot/releases/portable/App/AppInfo/appicon_32.png b/src/Greenshot/releases/portable/App/AppInfo/appicon_32.png similarity index 100% rename from Greenshot/releases/portable/App/AppInfo/appicon_32.png rename to src/Greenshot/releases/portable/App/AppInfo/appicon_32.png diff --git a/Greenshot/releases/portable/App/DefaultData/Greenshots/dummy.txt b/src/Greenshot/releases/portable/App/DefaultData/Greenshots/dummy.txt similarity index 100% rename from Greenshot/releases/portable/App/DefaultData/Greenshots/dummy.txt rename to src/Greenshot/releases/portable/App/DefaultData/Greenshots/dummy.txt diff --git a/Greenshot/releases/portable/App/DefaultData/Settings/dummy.txt b/src/Greenshot/releases/portable/App/DefaultData/Settings/dummy.txt similarity index 100% rename from Greenshot/releases/portable/App/DefaultData/Settings/dummy.txt rename to src/Greenshot/releases/portable/App/DefaultData/Settings/dummy.txt diff --git a/Greenshot/releases/portable/Data/Greenshot/dummy.txt b/src/Greenshot/releases/portable/Data/Greenshot/dummy.txt similarity index 100% rename from Greenshot/releases/portable/Data/Greenshot/dummy.txt rename to src/Greenshot/releases/portable/Data/Greenshot/dummy.txt diff --git a/Greenshot/releases/portable/Data/Settings/dummy.txt b/src/Greenshot/releases/portable/Data/Settings/dummy.txt similarity index 100% rename from Greenshot/releases/portable/Data/Settings/dummy.txt rename to src/Greenshot/releases/portable/Data/Settings/dummy.txt diff --git a/Greenshot/releases/portable/Other/Source/PortableApps.comInstallerCustom.nsh b/src/Greenshot/releases/portable/Other/Source/PortableApps.comInstallerCustom.nsh similarity index 100% rename from Greenshot/releases/portable/Other/Source/PortableApps.comInstallerCustom.nsh rename to src/Greenshot/releases/portable/Other/Source/PortableApps.comInstallerCustom.nsh diff --git a/Greenshot/sounds/camera.wav b/src/Greenshot/sounds/camera.wav similarity index 100% rename from Greenshot/sounds/camera.wav rename to src/Greenshot/sounds/camera.wav diff --git a/Greenshot/web/htdocs/Help/index.de-DE.html b/src/Greenshot/web/htdocs/Help/index.de-DE.html similarity index 100% rename from Greenshot/web/htdocs/Help/index.de-DE.html rename to src/Greenshot/web/htdocs/Help/index.de-DE.html diff --git a/Greenshot/web/htdocs/Help/index.en-US.html b/src/Greenshot/web/htdocs/Help/index.en-US.html similarity index 100% rename from Greenshot/web/htdocs/Help/index.en-US.html rename to src/Greenshot/web/htdocs/Help/index.en-US.html diff --git a/Greenshot/web/htdocs/favicon.ico b/src/Greenshot/web/htdocs/favicon.ico similarity index 100% rename from Greenshot/web/htdocs/favicon.ico rename to src/Greenshot/web/htdocs/favicon.ico diff --git a/Greenshot/web/htdocs/index.html b/src/Greenshot/web/htdocs/index.html similarity index 100% rename from Greenshot/web/htdocs/index.html rename to src/Greenshot/web/htdocs/index.html diff --git a/GreenshotBoxPlugin/Box.png b/src/GreenshotBoxPlugin/Box.png similarity index 100% rename from GreenshotBoxPlugin/Box.png rename to src/GreenshotBoxPlugin/Box.png diff --git a/GreenshotBoxPlugin/BoxConfiguration.cs b/src/GreenshotBoxPlugin/BoxConfiguration.cs similarity index 100% rename from GreenshotBoxPlugin/BoxConfiguration.cs rename to src/GreenshotBoxPlugin/BoxConfiguration.cs diff --git a/GreenshotBoxPlugin/BoxDestination.cs b/src/GreenshotBoxPlugin/BoxDestination.cs similarity index 100% rename from GreenshotBoxPlugin/BoxDestination.cs rename to src/GreenshotBoxPlugin/BoxDestination.cs diff --git a/GreenshotBoxPlugin/BoxEntities.cs b/src/GreenshotBoxPlugin/BoxEntities.cs similarity index 100% rename from GreenshotBoxPlugin/BoxEntities.cs rename to src/GreenshotBoxPlugin/BoxEntities.cs diff --git a/GreenshotBoxPlugin/BoxPlugin.cs b/src/GreenshotBoxPlugin/BoxPlugin.cs similarity index 100% rename from GreenshotBoxPlugin/BoxPlugin.cs rename to src/GreenshotBoxPlugin/BoxPlugin.cs diff --git a/GreenshotBoxPlugin/BoxPlugin.resx b/src/GreenshotBoxPlugin/BoxPlugin.resx similarity index 100% rename from GreenshotBoxPlugin/BoxPlugin.resx rename to src/GreenshotBoxPlugin/BoxPlugin.resx diff --git a/GreenshotBoxPlugin/BoxUtils.cs b/src/GreenshotBoxPlugin/BoxUtils.cs similarity index 100% rename from GreenshotBoxPlugin/BoxUtils.cs rename to src/GreenshotBoxPlugin/BoxUtils.cs diff --git a/GreenshotBoxPlugin/Forms/BoxForm.cs b/src/GreenshotBoxPlugin/Forms/BoxForm.cs similarity index 100% rename from GreenshotBoxPlugin/Forms/BoxForm.cs rename to src/GreenshotBoxPlugin/Forms/BoxForm.cs diff --git a/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs b/src/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs similarity index 100% rename from GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs rename to src/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs diff --git a/GreenshotBoxPlugin/Forms/SettingsForm.cs b/src/GreenshotBoxPlugin/Forms/SettingsForm.cs similarity index 100% rename from GreenshotBoxPlugin/Forms/SettingsForm.cs rename to src/GreenshotBoxPlugin/Forms/SettingsForm.cs diff --git a/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template b/src/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template similarity index 100% rename from GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template rename to src/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template diff --git a/GreenshotBoxPlugin/GreenshotBoxPlugin.csproj b/src/GreenshotBoxPlugin/GreenshotBoxPlugin.csproj similarity index 100% rename from GreenshotBoxPlugin/GreenshotBoxPlugin.csproj rename to src/GreenshotBoxPlugin/GreenshotBoxPlugin.csproj diff --git a/GreenshotBoxPlugin/LanguageKeys.cs b/src/GreenshotBoxPlugin/LanguageKeys.cs similarity index 100% rename from GreenshotBoxPlugin/LanguageKeys.cs rename to src/GreenshotBoxPlugin/LanguageKeys.cs diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-cs-CZ.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-cs-CZ.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-cs-CZ.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-cs-CZ.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-de-DE.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-de-DE.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-de-DE.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-de-DE.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-en-US.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-en-US.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-en-US.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-en-US.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-fr-FR.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-fr-FR.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-fr-FR.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-fr-FR.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-id-ID.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-id-ID.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-id-ID.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-id-ID.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-ja-JP.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-ja-JP.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-ja-JP.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-ja-JP.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-kab-DZ.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-kab-DZ.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-kab-DZ.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-kab-DZ.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-ko-KR.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-ko-KR.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-ko-KR.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-ko-KR.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-lv-LV.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-lv-LV.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-lv-LV.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-lv-LV.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-pl-PL.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-pl-PL.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-pl-PL.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-pl-PL.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-pt-PT.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-pt-PT.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-pt-PT.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-pt-PT.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-ru-RU.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-ru-RU.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-ru-RU.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-ru-RU.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-sr-RS.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-sr-RS.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-sr-RS.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-sr-RS.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-sv-SE.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-sv-SE.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-sv-SE.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-sv-SE.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-uk-UA.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-uk-UA.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-uk-UA.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-uk-UA.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-zh-CN.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-zh-CN.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-zh-CN.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-zh-CN.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-zh-TW.xml b/src/GreenshotBoxPlugin/Languages/language_boxplugin-zh-TW.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-zh-TW.xml rename to src/GreenshotBoxPlugin/Languages/language_boxplugin-zh-TW.xml diff --git a/GreenshotBoxPlugin/Properties/AssemblyInfo.cs b/src/GreenshotBoxPlugin/Properties/AssemblyInfo.cs similarity index 100% rename from GreenshotBoxPlugin/Properties/AssemblyInfo.cs rename to src/GreenshotBoxPlugin/Properties/AssemblyInfo.cs diff --git a/GreenshotConfluencePlugin/Confluence.cs b/src/GreenshotConfluencePlugin/Confluence.cs similarity index 100% rename from GreenshotConfluencePlugin/Confluence.cs rename to src/GreenshotConfluencePlugin/Confluence.cs diff --git a/GreenshotConfluencePlugin/ConfluenceConfiguration.cs b/src/GreenshotConfluencePlugin/ConfluenceConfiguration.cs similarity index 100% rename from GreenshotConfluencePlugin/ConfluenceConfiguration.cs rename to src/GreenshotConfluencePlugin/ConfluenceConfiguration.cs diff --git a/GreenshotConfluencePlugin/ConfluenceDestination.cs b/src/GreenshotConfluencePlugin/ConfluenceDestination.cs similarity index 100% rename from GreenshotConfluencePlugin/ConfluenceDestination.cs rename to src/GreenshotConfluencePlugin/ConfluenceDestination.cs diff --git a/GreenshotConfluencePlugin/ConfluencePlugin.cs b/src/GreenshotConfluencePlugin/ConfluencePlugin.cs similarity index 100% rename from GreenshotConfluencePlugin/ConfluencePlugin.cs rename to src/GreenshotConfluencePlugin/ConfluencePlugin.cs diff --git a/GreenshotConfluencePlugin/ConfluenceUtils.cs b/src/GreenshotConfluencePlugin/ConfluenceUtils.cs similarity index 100% rename from GreenshotConfluencePlugin/ConfluenceUtils.cs rename to src/GreenshotConfluencePlugin/ConfluenceUtils.cs diff --git a/GreenshotConfluencePlugin/EnumDisplayer.cs b/src/GreenshotConfluencePlugin/EnumDisplayer.cs similarity index 100% rename from GreenshotConfluencePlugin/EnumDisplayer.cs rename to src/GreenshotConfluencePlugin/EnumDisplayer.cs diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml b/src/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml similarity index 100% rename from GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml rename to src/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs b/src/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs similarity index 100% rename from GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs rename to src/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs diff --git a/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml b/src/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml similarity index 100% rename from GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml rename to src/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml diff --git a/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs b/src/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs similarity index 100% rename from GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs rename to src/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml b/src/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml similarity index 100% rename from GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml rename to src/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs b/src/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs similarity index 100% rename from GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs rename to src/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml b/src/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml similarity index 100% rename from GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml rename to src/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs b/src/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs similarity index 100% rename from GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs rename to src/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml b/src/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml similarity index 100% rename from GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml rename to src/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs b/src/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs similarity index 100% rename from GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs rename to src/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs diff --git a/GreenshotConfluencePlugin/GreenshotConfluencePlugin.csproj b/src/GreenshotConfluencePlugin/GreenshotConfluencePlugin.csproj similarity index 100% rename from GreenshotConfluencePlugin/GreenshotConfluencePlugin.csproj rename to src/GreenshotConfluencePlugin/GreenshotConfluencePlugin.csproj diff --git a/GreenshotConfluencePlugin/Images/Confluence.ico b/src/GreenshotConfluencePlugin/Images/Confluence.ico similarity index 100% rename from GreenshotConfluencePlugin/Images/Confluence.ico rename to src/GreenshotConfluencePlugin/Images/Confluence.ico diff --git a/GreenshotConfluencePlugin/LanguageKeys.cs b/src/GreenshotConfluencePlugin/LanguageKeys.cs similarity index 100% rename from GreenshotConfluencePlugin/LanguageKeys.cs rename to src/GreenshotConfluencePlugin/LanguageKeys.cs diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-cs-CZ.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-cs-CZ.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-cs-CZ.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-cs-CZ.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-de-DE.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-de-DE.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-de-DE.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-de-DE.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-en-US.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-en-US.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-en-US.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-en-US.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-fr-FR.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-fr-FR.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-fr-FR.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-fr-FR.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-id-ID.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-id-ID.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-id-ID.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-id-ID.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ja-JP.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ja-JP.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-ja-JP.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ja-JP.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-kab-DZ.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-kab-DZ.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-kab-DZ.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-kab-DZ.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ko-KR.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ko-KR.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-ko-KR.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ko-KR.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-lv-LV.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-lv-LV.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-lv-LV.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-lv-LV.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-nl-NL.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-nl-NL.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-nl-NL.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-nl-NL.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pl-PL.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pl-PL.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-pl-PL.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pl-PL.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pt-PT.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pt-PT.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-pt-PT.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pt-PT.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ru-RU.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ru-RU.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-ru-RU.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ru-RU.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sr-RS.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sr-RS.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-sr-RS.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sr-RS.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sv-SE.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sv-SE.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-sv-SE.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sv-SE.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-uk-UA.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-uk-UA.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-uk-UA.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-uk-UA.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-CN.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-CN.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-CN.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-CN.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-TW.xml b/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-TW.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-TW.xml rename to src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-TW.xml diff --git a/GreenshotConfluencePlugin/Support/ITranslationProvider.cs b/src/GreenshotConfluencePlugin/Support/ITranslationProvider.cs similarity index 100% rename from GreenshotConfluencePlugin/Support/ITranslationProvider.cs rename to src/GreenshotConfluencePlugin/Support/ITranslationProvider.cs diff --git a/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs b/src/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs similarity index 100% rename from GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs rename to src/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs diff --git a/GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs b/src/GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs similarity index 100% rename from GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs rename to src/GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs diff --git a/GreenshotConfluencePlugin/Support/TranslateExtension.cs b/src/GreenshotConfluencePlugin/Support/TranslateExtension.cs similarity index 100% rename from GreenshotConfluencePlugin/Support/TranslateExtension.cs rename to src/GreenshotConfluencePlugin/Support/TranslateExtension.cs diff --git a/GreenshotConfluencePlugin/Support/TranslationData.cs b/src/GreenshotConfluencePlugin/Support/TranslationData.cs similarity index 100% rename from GreenshotConfluencePlugin/Support/TranslationData.cs rename to src/GreenshotConfluencePlugin/Support/TranslationData.cs diff --git a/GreenshotConfluencePlugin/Support/TranslationManager.cs b/src/GreenshotConfluencePlugin/Support/TranslationManager.cs similarity index 100% rename from GreenshotConfluencePlugin/Support/TranslationManager.cs rename to src/GreenshotConfluencePlugin/Support/TranslationManager.cs diff --git a/GreenshotConfluencePlugin/Web References/confluence/Reference.cs b/src/GreenshotConfluencePlugin/Web References/confluence/Reference.cs similarity index 100% rename from GreenshotConfluencePlugin/Web References/confluence/Reference.cs rename to src/GreenshotConfluencePlugin/Web References/confluence/Reference.cs diff --git a/GreenshotConfluencePlugin/Web References/confluence/Reference.map b/src/GreenshotConfluencePlugin/Web References/confluence/Reference.map similarity index 100% rename from GreenshotConfluencePlugin/Web References/confluence/Reference.map rename to src/GreenshotConfluencePlugin/Web References/confluence/Reference.map diff --git a/GreenshotConfluencePlugin/Web References/confluence/confluenceservice-v1.wsdl b/src/GreenshotConfluencePlugin/Web References/confluence/confluenceservice-v1.wsdl similarity index 100% rename from GreenshotConfluencePlugin/Web References/confluence/confluenceservice-v1.wsdl rename to src/GreenshotConfluencePlugin/Web References/confluence/confluenceservice-v1.wsdl diff --git a/GreenshotDropboxPlugin/Dropbox.gif b/src/GreenshotDropboxPlugin/Dropbox.gif similarity index 100% rename from GreenshotDropboxPlugin/Dropbox.gif rename to src/GreenshotDropboxPlugin/Dropbox.gif diff --git a/GreenshotDropboxPlugin/DropboxDestination.cs b/src/GreenshotDropboxPlugin/DropboxDestination.cs similarity index 100% rename from GreenshotDropboxPlugin/DropboxDestination.cs rename to src/GreenshotDropboxPlugin/DropboxDestination.cs diff --git a/GreenshotDropboxPlugin/DropboxPlugin.cs b/src/GreenshotDropboxPlugin/DropboxPlugin.cs similarity index 100% rename from GreenshotDropboxPlugin/DropboxPlugin.cs rename to src/GreenshotDropboxPlugin/DropboxPlugin.cs diff --git a/GreenshotDropboxPlugin/DropboxPlugin.resx b/src/GreenshotDropboxPlugin/DropboxPlugin.resx similarity index 100% rename from GreenshotDropboxPlugin/DropboxPlugin.resx rename to src/GreenshotDropboxPlugin/DropboxPlugin.resx diff --git a/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs b/src/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs similarity index 100% rename from GreenshotDropboxPlugin/DropboxPluginConfiguration.cs rename to src/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs diff --git a/GreenshotDropboxPlugin/DropboxUtils.cs b/src/GreenshotDropboxPlugin/DropboxUtils.cs similarity index 100% rename from GreenshotDropboxPlugin/DropboxUtils.cs rename to src/GreenshotDropboxPlugin/DropboxUtils.cs diff --git a/GreenshotDropboxPlugin/Forms/DropboxForm.cs b/src/GreenshotDropboxPlugin/Forms/DropboxForm.cs similarity index 100% rename from GreenshotDropboxPlugin/Forms/DropboxForm.cs rename to src/GreenshotDropboxPlugin/Forms/DropboxForm.cs diff --git a/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs b/src/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs similarity index 100% rename from GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs rename to src/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs diff --git a/GreenshotDropboxPlugin/Forms/SettingsForm.cs b/src/GreenshotDropboxPlugin/Forms/SettingsForm.cs similarity index 100% rename from GreenshotDropboxPlugin/Forms/SettingsForm.cs rename to src/GreenshotDropboxPlugin/Forms/SettingsForm.cs diff --git a/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template b/src/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template similarity index 100% rename from GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template rename to src/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template diff --git a/GreenshotDropboxPlugin/GreenshotDropboxPlugin.csproj b/src/GreenshotDropboxPlugin/GreenshotDropboxPlugin.csproj similarity index 100% rename from GreenshotDropboxPlugin/GreenshotDropboxPlugin.csproj rename to src/GreenshotDropboxPlugin/GreenshotDropboxPlugin.csproj diff --git a/GreenshotDropboxPlugin/LanguageKeys.cs b/src/GreenshotDropboxPlugin/LanguageKeys.cs similarity index 100% rename from GreenshotDropboxPlugin/LanguageKeys.cs rename to src/GreenshotDropboxPlugin/LanguageKeys.cs diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-cs-CZ.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-cs-CZ.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-cs-CZ.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-cs-CZ.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-de-DE.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-de-DE.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-de-DE.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-de-DE.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-en-US.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-en-US.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-en-US.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-en-US.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-fr-FR.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-fr-FR.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-fr-FR.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-fr-FR.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-id-ID.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-id-ID.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-id-ID.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-id-ID.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ja-JP.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ja-JP.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-ja-JP.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ja-JP.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-kab-DZ.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-kab-DZ.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-kab-DZ.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-kab-DZ.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ko-KR.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ko-KR.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-ko-KR.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ko-KR.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-lv-LV.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-lv-LV.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-lv-LV.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-lv-LV.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pl-PL.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pl-PL.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-pl-PL.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pl-PL.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pt-PT.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pt-PT.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-pt-PT.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pt-PT.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ru-RU.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ru-RU.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-ru-RU.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ru-RU.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sr-RS.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sr-RS.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-sr-RS.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sr-RS.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sv-SE.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sv-SE.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-sv-SE.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sv-SE.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-uk-UA.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-uk-UA.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-uk-UA.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-uk-UA.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-CN.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-CN.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-CN.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-CN.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-TW.xml b/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-TW.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-TW.xml rename to src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-TW.xml diff --git a/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs b/src/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs similarity index 100% rename from GreenshotDropboxPlugin/Properties/AssemblyInfo.cs rename to src/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs diff --git a/GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs b/src/GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs similarity index 100% rename from GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs rename to src/GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs diff --git a/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs b/src/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs similarity index 100% rename from GreenshotExternalCommandPlugin/ExternalCommandDestination.cs rename to src/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs diff --git a/GreenshotExternalCommandPlugin/ExternalCommandForm.cs b/src/GreenshotExternalCommandPlugin/ExternalCommandForm.cs similarity index 100% rename from GreenshotExternalCommandPlugin/ExternalCommandForm.cs rename to src/GreenshotExternalCommandPlugin/ExternalCommandForm.cs diff --git a/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs b/src/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs similarity index 100% rename from GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs rename to src/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs diff --git a/GreenshotExternalCommandPlugin/GreenshotExternalCommandPlugin.csproj b/src/GreenshotExternalCommandPlugin/GreenshotExternalCommandPlugin.csproj similarity index 100% rename from GreenshotExternalCommandPlugin/GreenshotExternalCommandPlugin.csproj rename to src/GreenshotExternalCommandPlugin/GreenshotExternalCommandPlugin.csproj diff --git a/GreenshotExternalCommandPlugin/IconCache.cs b/src/GreenshotExternalCommandPlugin/IconCache.cs similarity index 100% rename from GreenshotExternalCommandPlugin/IconCache.cs rename to src/GreenshotExternalCommandPlugin/IconCache.cs diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-cs-CZ.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-cs-CZ.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-cs-CZ.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-cs-CZ.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-de-DE.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-de-DE.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-de-DE.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-de-DE.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-en-US.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-en-US.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-en-US.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-en-US.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-fr-FR.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-fr-FR.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-fr-FR.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-fr-FR.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-id-ID.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-id-ID.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-id-ID.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-id-ID.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ja-JP.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ja-JP.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ja-JP.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ja-JP.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-kab-DZ.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-kab-DZ.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-kab-DZ.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-kab-DZ.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ko-KR.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ko-KR.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ko-KR.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ko-KR.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-lv-LV.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-lv-LV.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-lv-LV.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-lv-LV.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pl-PL.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pl-PL.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pl-PL.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pl-PL.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pt-PT.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pt-PT.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pt-PT.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pt-PT.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ru-RU.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ru-RU.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ru-RU.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ru-RU.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sk-SK.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sk-SK.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sk-SK.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sk-SK.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sr-RS.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sr-RS.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sr-RS.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sr-RS.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sv-SE.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sv-SE.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sv-SE.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sv-SE.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-uk-UA.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-uk-UA.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-uk-UA.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-uk-UA.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-CN.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-CN.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-CN.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-CN.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-TW.xml b/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-TW.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-TW.xml rename to src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-TW.xml diff --git a/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs b/src/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs similarity index 100% rename from GreenshotExternalCommandPlugin/SettingsForm.Designer.cs rename to src/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs diff --git a/GreenshotExternalCommandPlugin/SettingsForm.cs b/src/GreenshotExternalCommandPlugin/SettingsForm.cs similarity index 100% rename from GreenshotExternalCommandPlugin/SettingsForm.cs rename to src/GreenshotExternalCommandPlugin/SettingsForm.cs diff --git a/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs b/src/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs similarity index 100% rename from GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs rename to src/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs diff --git a/GreenshotExternalCommandPlugin/SettingsFormDetail.cs b/src/GreenshotExternalCommandPlugin/SettingsFormDetail.cs similarity index 100% rename from GreenshotExternalCommandPlugin/SettingsFormDetail.cs rename to src/GreenshotExternalCommandPlugin/SettingsFormDetail.cs diff --git a/GreenshotFlickrPlugin/FlickrConfiguration.cs b/src/GreenshotFlickrPlugin/FlickrConfiguration.cs similarity index 100% rename from GreenshotFlickrPlugin/FlickrConfiguration.cs rename to src/GreenshotFlickrPlugin/FlickrConfiguration.cs diff --git a/GreenshotFlickrPlugin/FlickrDestination.cs b/src/GreenshotFlickrPlugin/FlickrDestination.cs similarity index 100% rename from GreenshotFlickrPlugin/FlickrDestination.cs rename to src/GreenshotFlickrPlugin/FlickrDestination.cs diff --git a/GreenshotFlickrPlugin/FlickrPlugin.cs b/src/GreenshotFlickrPlugin/FlickrPlugin.cs similarity index 100% rename from GreenshotFlickrPlugin/FlickrPlugin.cs rename to src/GreenshotFlickrPlugin/FlickrPlugin.cs diff --git a/GreenshotFlickrPlugin/FlickrPlugin.resx b/src/GreenshotFlickrPlugin/FlickrPlugin.resx similarity index 100% rename from GreenshotFlickrPlugin/FlickrPlugin.resx rename to src/GreenshotFlickrPlugin/FlickrPlugin.resx diff --git a/GreenshotFlickrPlugin/FlickrUtils.cs b/src/GreenshotFlickrPlugin/FlickrUtils.cs similarity index 100% rename from GreenshotFlickrPlugin/FlickrUtils.cs rename to src/GreenshotFlickrPlugin/FlickrUtils.cs diff --git a/GreenshotFlickrPlugin/Forms/FlickrForm.cs b/src/GreenshotFlickrPlugin/Forms/FlickrForm.cs similarity index 100% rename from GreenshotFlickrPlugin/Forms/FlickrForm.cs rename to src/GreenshotFlickrPlugin/Forms/FlickrForm.cs diff --git a/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs b/src/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs similarity index 100% rename from GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs rename to src/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs diff --git a/GreenshotFlickrPlugin/Forms/SettingsForm.cs b/src/GreenshotFlickrPlugin/Forms/SettingsForm.cs similarity index 100% rename from GreenshotFlickrPlugin/Forms/SettingsForm.cs rename to src/GreenshotFlickrPlugin/Forms/SettingsForm.cs diff --git a/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template b/src/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template similarity index 100% rename from GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template rename to src/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template diff --git a/GreenshotFlickrPlugin/GreenshotFlickrPlugin.csproj b/src/GreenshotFlickrPlugin/GreenshotFlickrPlugin.csproj similarity index 100% rename from GreenshotFlickrPlugin/GreenshotFlickrPlugin.csproj rename to src/GreenshotFlickrPlugin/GreenshotFlickrPlugin.csproj diff --git a/GreenshotFlickrPlugin/LanguageKeys.cs b/src/GreenshotFlickrPlugin/LanguageKeys.cs similarity index 100% rename from GreenshotFlickrPlugin/LanguageKeys.cs rename to src/GreenshotFlickrPlugin/LanguageKeys.cs diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-cs-CZ.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-cs-CZ.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-cs-CZ.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-cs-CZ.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-de-DE.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-de-DE.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-de-DE.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-de-DE.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-en-US.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-en-US.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-en-US.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-en-US.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-fr-FR.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-fr-FR.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-fr-FR.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-fr-FR.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-id-ID.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-id-ID.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-id-ID.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-id-ID.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-ja-JP.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ja-JP.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-ja-JP.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ja-JP.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-kab-DZ.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-kab-DZ.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-kab-DZ.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-kab-DZ.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-ko-KR.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ko-KR.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-ko-KR.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ko-KR.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-lv-LV.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-lv-LV.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-lv-LV.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-lv-LV.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-pl-PL.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-pl-PL.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-pl-PL.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-pl-PL.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-pt-PT.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-pt-PT.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-pt-PT.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-pt-PT.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-ru-RU.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ru-RU.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-ru-RU.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ru-RU.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-sr-RS.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-sr-RS.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-sr-RS.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-sr-RS.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-sv-SE.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-sv-SE.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-sv-SE.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-sv-SE.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-uk-UA.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-uk-UA.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-uk-UA.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-uk-UA.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-CN.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-CN.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-CN.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-CN.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-TW.xml b/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-TW.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-TW.xml rename to src/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-TW.xml diff --git a/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs b/src/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs similarity index 100% rename from GreenshotFlickrPlugin/Properties/AssemblyInfo.cs rename to src/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs diff --git a/GreenshotFlickrPlugin/flickr.png b/src/GreenshotFlickrPlugin/flickr.png similarity index 100% rename from GreenshotFlickrPlugin/flickr.png rename to src/GreenshotFlickrPlugin/flickr.png diff --git a/GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs b/src/GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs similarity index 100% rename from GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs rename to src/GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs diff --git a/GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs b/src/GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs similarity index 100% rename from GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs rename to src/GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs diff --git a/GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs b/src/GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs similarity index 100% rename from GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs rename to src/GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs diff --git a/GreenshotGooglePhotosPlugin/GooglePhotos.png b/src/GreenshotGooglePhotosPlugin/GooglePhotos.png similarity index 100% rename from GreenshotGooglePhotosPlugin/GooglePhotos.png rename to src/GreenshotGooglePhotosPlugin/GooglePhotos.png diff --git a/GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs b/src/GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs similarity index 100% rename from GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs rename to src/GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs diff --git a/GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs b/src/GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs similarity index 100% rename from GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs rename to src/GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs diff --git a/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs b/src/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs similarity index 100% rename from GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs rename to src/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs diff --git a/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx b/src/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx similarity index 100% rename from GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx rename to src/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx diff --git a/GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs b/src/GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs similarity index 100% rename from GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs rename to src/GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs diff --git a/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template b/src/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template similarity index 100% rename from GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template rename to src/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template diff --git a/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj b/src/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj similarity index 100% rename from GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj rename to src/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj diff --git a/GreenshotGooglePhotosPlugin/LanguageKeys.cs b/src/GreenshotGooglePhotosPlugin/LanguageKeys.cs similarity index 100% rename from GreenshotGooglePhotosPlugin/LanguageKeys.cs rename to src/GreenshotGooglePhotosPlugin/LanguageKeys.cs diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml b/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml rename to src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml diff --git a/GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs b/src/GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs similarity index 100% rename from GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs rename to src/GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs diff --git a/GreenshotGooglePhotosPlugin/README b/src/GreenshotGooglePhotosPlugin/README similarity index 100% rename from GreenshotGooglePhotosPlugin/README rename to src/GreenshotGooglePhotosPlugin/README diff --git a/GreenshotImgurPlugin/Forms/ImgurForm.cs b/src/GreenshotImgurPlugin/Forms/ImgurForm.cs similarity index 100% rename from GreenshotImgurPlugin/Forms/ImgurForm.cs rename to src/GreenshotImgurPlugin/Forms/ImgurForm.cs diff --git a/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs b/src/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs similarity index 100% rename from GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs rename to src/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs diff --git a/GreenshotImgurPlugin/Forms/ImgurHistory.cs b/src/GreenshotImgurPlugin/Forms/ImgurHistory.cs similarity index 100% rename from GreenshotImgurPlugin/Forms/ImgurHistory.cs rename to src/GreenshotImgurPlugin/Forms/ImgurHistory.cs diff --git a/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs b/src/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs similarity index 100% rename from GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs rename to src/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs diff --git a/GreenshotImgurPlugin/Forms/SettingsForm.cs b/src/GreenshotImgurPlugin/Forms/SettingsForm.cs similarity index 100% rename from GreenshotImgurPlugin/Forms/SettingsForm.cs rename to src/GreenshotImgurPlugin/Forms/SettingsForm.cs diff --git a/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template b/src/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template similarity index 100% rename from GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template rename to src/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template diff --git a/GreenshotImgurPlugin/GreenshotImgurPlugin.csproj b/src/GreenshotImgurPlugin/GreenshotImgurPlugin.csproj similarity index 100% rename from GreenshotImgurPlugin/GreenshotImgurPlugin.csproj rename to src/GreenshotImgurPlugin/GreenshotImgurPlugin.csproj diff --git a/GreenshotImgurPlugin/ImgurConfiguration.cs b/src/GreenshotImgurPlugin/ImgurConfiguration.cs similarity index 100% rename from GreenshotImgurPlugin/ImgurConfiguration.cs rename to src/GreenshotImgurPlugin/ImgurConfiguration.cs diff --git a/GreenshotImgurPlugin/ImgurDestination.cs b/src/GreenshotImgurPlugin/ImgurDestination.cs similarity index 100% rename from GreenshotImgurPlugin/ImgurDestination.cs rename to src/GreenshotImgurPlugin/ImgurDestination.cs diff --git a/GreenshotImgurPlugin/ImgurInfo.cs b/src/GreenshotImgurPlugin/ImgurInfo.cs similarity index 100% rename from GreenshotImgurPlugin/ImgurInfo.cs rename to src/GreenshotImgurPlugin/ImgurInfo.cs diff --git a/GreenshotImgurPlugin/ImgurPlugin.cs b/src/GreenshotImgurPlugin/ImgurPlugin.cs similarity index 100% rename from GreenshotImgurPlugin/ImgurPlugin.cs rename to src/GreenshotImgurPlugin/ImgurPlugin.cs diff --git a/GreenshotImgurPlugin/ImgurPlugin.resx b/src/GreenshotImgurPlugin/ImgurPlugin.resx similarity index 100% rename from GreenshotImgurPlugin/ImgurPlugin.resx rename to src/GreenshotImgurPlugin/ImgurPlugin.resx diff --git a/GreenshotImgurPlugin/ImgurUtils.cs b/src/GreenshotImgurPlugin/ImgurUtils.cs similarity index 100% rename from GreenshotImgurPlugin/ImgurUtils.cs rename to src/GreenshotImgurPlugin/ImgurUtils.cs diff --git a/GreenshotImgurPlugin/LanguageKeys.cs b/src/GreenshotImgurPlugin/LanguageKeys.cs similarity index 100% rename from GreenshotImgurPlugin/LanguageKeys.cs rename to src/GreenshotImgurPlugin/LanguageKeys.cs diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-cs-CZ.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-cs-CZ.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-cs-CZ.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-cs-CZ.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-de-DE.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-de-DE.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-de-DE.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-de-DE.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-en-US.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-en-US.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-en-US.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-en-US.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-fr-FR.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-fr-FR.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-fr-FR.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-fr-FR.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-id-ID.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-id-ID.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-id-ID.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-id-ID.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-ja-JP.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-ja-JP.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-ja-JP.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-ja-JP.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-kab-DZ.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-kab-DZ.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-kab-DZ.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-kab-DZ.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-ko-KR.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-ko-KR.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-ko-KR.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-ko-KR.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-lv-LV.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-lv-LV.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-lv-LV.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-lv-LV.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-nl-NL.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-nl-NL.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-nl-NL.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-nl-NL.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-pl-PL.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-pl-PL.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-pl-PL.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-pl-PL.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-pt-PT.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-pt-PT.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-pt-PT.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-pt-PT.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-ru-RU.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-ru-RU.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-ru-RU.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-ru-RU.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-sk-SK.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-sk-SK.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-sk-SK.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-sk-SK.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-sr-RS.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-sr-RS.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-sr-RS.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-sr-RS.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-sv-SE.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-sv-SE.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-sv-SE.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-sv-SE.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-uk-UA.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-uk-UA.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-uk-UA.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-uk-UA.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-CN.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-CN.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-zh-CN.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-CN.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-TW.xml b/src/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-TW.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-zh-TW.xml rename to src/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-TW.xml diff --git a/GreenshotImgurPlugin/Properties/AssemblyInfo.cs b/src/GreenshotImgurPlugin/Properties/AssemblyInfo.cs similarity index 100% rename from GreenshotImgurPlugin/Properties/AssemblyInfo.cs rename to src/GreenshotImgurPlugin/Properties/AssemblyInfo.cs diff --git a/GreenshotJiraPlugin/AsyncMemoryCache.cs b/src/GreenshotJiraPlugin/AsyncMemoryCache.cs similarity index 100% rename from GreenshotJiraPlugin/AsyncMemoryCache.cs rename to src/GreenshotJiraPlugin/AsyncMemoryCache.cs diff --git a/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs b/src/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs similarity index 100% rename from GreenshotJiraPlugin/Forms/JiraForm.Designer.cs rename to src/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs diff --git a/GreenshotJiraPlugin/Forms/JiraForm.cs b/src/GreenshotJiraPlugin/Forms/JiraForm.cs similarity index 100% rename from GreenshotJiraPlugin/Forms/JiraForm.cs rename to src/GreenshotJiraPlugin/Forms/JiraForm.cs diff --git a/GreenshotJiraPlugin/Forms/JiraFormBase.cs b/src/GreenshotJiraPlugin/Forms/JiraFormBase.cs similarity index 100% rename from GreenshotJiraPlugin/Forms/JiraFormBase.cs rename to src/GreenshotJiraPlugin/Forms/JiraFormBase.cs diff --git a/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs b/src/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs similarity index 100% rename from GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs rename to src/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs diff --git a/GreenshotJiraPlugin/Forms/SettingsForm.cs b/src/GreenshotJiraPlugin/Forms/SettingsForm.cs similarity index 100% rename from GreenshotJiraPlugin/Forms/SettingsForm.cs rename to src/GreenshotJiraPlugin/Forms/SettingsForm.cs diff --git a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj b/src/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj similarity index 100% rename from GreenshotJiraPlugin/GreenshotJiraPlugin.csproj rename to src/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj diff --git a/GreenshotJiraPlugin/IssueTypeBitmapCache.cs b/src/GreenshotJiraPlugin/IssueTypeBitmapCache.cs similarity index 100% rename from GreenshotJiraPlugin/IssueTypeBitmapCache.cs rename to src/GreenshotJiraPlugin/IssueTypeBitmapCache.cs diff --git a/GreenshotJiraPlugin/JiraConfiguration.cs b/src/GreenshotJiraPlugin/JiraConfiguration.cs similarity index 100% rename from GreenshotJiraPlugin/JiraConfiguration.cs rename to src/GreenshotJiraPlugin/JiraConfiguration.cs diff --git a/GreenshotJiraPlugin/JiraConnector.cs b/src/GreenshotJiraPlugin/JiraConnector.cs similarity index 100% rename from GreenshotJiraPlugin/JiraConnector.cs rename to src/GreenshotJiraPlugin/JiraConnector.cs diff --git a/GreenshotJiraPlugin/JiraDestination.cs b/src/GreenshotJiraPlugin/JiraDestination.cs similarity index 100% rename from GreenshotJiraPlugin/JiraDestination.cs rename to src/GreenshotJiraPlugin/JiraDestination.cs diff --git a/GreenshotJiraPlugin/JiraDetails.cs b/src/GreenshotJiraPlugin/JiraDetails.cs similarity index 100% rename from GreenshotJiraPlugin/JiraDetails.cs rename to src/GreenshotJiraPlugin/JiraDetails.cs diff --git a/GreenshotJiraPlugin/JiraEventArgs.cs b/src/GreenshotJiraPlugin/JiraEventArgs.cs similarity index 100% rename from GreenshotJiraPlugin/JiraEventArgs.cs rename to src/GreenshotJiraPlugin/JiraEventArgs.cs diff --git a/GreenshotJiraPlugin/JiraEventTypes.cs b/src/GreenshotJiraPlugin/JiraEventTypes.cs similarity index 100% rename from GreenshotJiraPlugin/JiraEventTypes.cs rename to src/GreenshotJiraPlugin/JiraEventTypes.cs diff --git a/GreenshotJiraPlugin/JiraMonitor.cs b/src/GreenshotJiraPlugin/JiraMonitor.cs similarity index 100% rename from GreenshotJiraPlugin/JiraMonitor.cs rename to src/GreenshotJiraPlugin/JiraMonitor.cs diff --git a/GreenshotJiraPlugin/JiraPlugin.cs b/src/GreenshotJiraPlugin/JiraPlugin.cs similarity index 100% rename from GreenshotJiraPlugin/JiraPlugin.cs rename to src/GreenshotJiraPlugin/JiraPlugin.cs diff --git a/GreenshotJiraPlugin/JiraPlugin.resx b/src/GreenshotJiraPlugin/JiraPlugin.resx similarity index 100% rename from GreenshotJiraPlugin/JiraPlugin.resx rename to src/GreenshotJiraPlugin/JiraPlugin.resx diff --git a/GreenshotJiraPlugin/LanguageKeys.cs b/src/GreenshotJiraPlugin/LanguageKeys.cs similarity index 100% rename from GreenshotJiraPlugin/LanguageKeys.cs rename to src/GreenshotJiraPlugin/LanguageKeys.cs diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-cs-CZ.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-cs-CZ.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-cs-CZ.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-cs-CZ.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-de-DE.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-de-DE.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-de-DE.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-de-DE.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-en-US.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-en-US.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-en-US.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-en-US.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-fr-FR.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-fr-FR.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-fr-FR.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-fr-FR.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-id-ID.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-id-ID.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-id-ID.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-id-ID.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-ja-JP.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-ja-JP.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-ja-JP.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-ja-JP.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-kab-DZ.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-kab-DZ.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-kab-DZ.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-kab-DZ.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-ko-KR.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-ko-KR.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-ko-KR.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-ko-KR.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-lv-LV.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-lv-LV.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-lv-LV.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-lv-LV.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-nl-NL.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-nl-NL.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-nl-NL.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-nl-NL.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-pl-PL.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-pl-PL.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-pl-PL.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-pl-PL.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-pt-PT.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-pt-PT.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-pt-PT.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-pt-PT.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-ru-RU.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-ru-RU.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-ru-RU.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-ru-RU.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-sr-RS.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-sr-RS.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-sr-RS.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-sr-RS.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-sv-SE.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-sv-SE.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-sv-SE.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-sv-SE.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-uk-UA.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-uk-UA.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-uk-UA.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-uk-UA.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-CN.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-CN.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-zh-CN.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-CN.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-TW.xml b/src/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-TW.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-zh-TW.xml rename to src/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-TW.xml diff --git a/GreenshotJiraPlugin/Log4NetLogger.cs b/src/GreenshotJiraPlugin/Log4NetLogger.cs similarity index 100% rename from GreenshotJiraPlugin/Log4NetLogger.cs rename to src/GreenshotJiraPlugin/Log4NetLogger.cs diff --git a/GreenshotOfficePlugin/Com/DisposableCom.cs b/src/GreenshotOfficePlugin/Com/DisposableCom.cs similarity index 100% rename from GreenshotOfficePlugin/Com/DisposableCom.cs rename to src/GreenshotOfficePlugin/Com/DisposableCom.cs diff --git a/GreenshotOfficePlugin/Com/DisposableComImplementation.cs b/src/GreenshotOfficePlugin/Com/DisposableComImplementation.cs similarity index 100% rename from GreenshotOfficePlugin/Com/DisposableComImplementation.cs rename to src/GreenshotOfficePlugin/Com/DisposableComImplementation.cs diff --git a/GreenshotOfficePlugin/Com/IDisposableCom.cs b/src/GreenshotOfficePlugin/Com/IDisposableCom.cs similarity index 100% rename from GreenshotOfficePlugin/Com/IDisposableCom.cs rename to src/GreenshotOfficePlugin/Com/IDisposableCom.cs diff --git a/GreenshotOfficePlugin/Com/Ole32Api.cs b/src/GreenshotOfficePlugin/Com/Ole32Api.cs similarity index 100% rename from GreenshotOfficePlugin/Com/Ole32Api.cs rename to src/GreenshotOfficePlugin/Com/Ole32Api.cs diff --git a/GreenshotOfficePlugin/Com/OleAut32Api.cs b/src/GreenshotOfficePlugin/Com/OleAut32Api.cs similarity index 100% rename from GreenshotOfficePlugin/Com/OleAut32Api.cs rename to src/GreenshotOfficePlugin/Com/OleAut32Api.cs diff --git a/GreenshotOfficePlugin/Destinations/ExcelDestination.cs b/src/GreenshotOfficePlugin/Destinations/ExcelDestination.cs similarity index 100% rename from GreenshotOfficePlugin/Destinations/ExcelDestination.cs rename to src/GreenshotOfficePlugin/Destinations/ExcelDestination.cs diff --git a/GreenshotOfficePlugin/Destinations/OneNoteDestination.cs b/src/GreenshotOfficePlugin/Destinations/OneNoteDestination.cs similarity index 100% rename from GreenshotOfficePlugin/Destinations/OneNoteDestination.cs rename to src/GreenshotOfficePlugin/Destinations/OneNoteDestination.cs diff --git a/GreenshotOfficePlugin/Destinations/OutlookDestination.cs b/src/GreenshotOfficePlugin/Destinations/OutlookDestination.cs similarity index 100% rename from GreenshotOfficePlugin/Destinations/OutlookDestination.cs rename to src/GreenshotOfficePlugin/Destinations/OutlookDestination.cs diff --git a/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs b/src/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs similarity index 100% rename from GreenshotOfficePlugin/Destinations/PowerpointDestination.cs rename to src/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs diff --git a/GreenshotOfficePlugin/Destinations/WordDestination.cs b/src/GreenshotOfficePlugin/Destinations/WordDestination.cs similarity index 100% rename from GreenshotOfficePlugin/Destinations/WordDestination.cs rename to src/GreenshotOfficePlugin/Destinations/WordDestination.cs diff --git a/GreenshotOfficePlugin/GlobalSuppressions.cs b/src/GreenshotOfficePlugin/GlobalSuppressions.cs similarity index 100% rename from GreenshotOfficePlugin/GlobalSuppressions.cs rename to src/GreenshotOfficePlugin/GlobalSuppressions.cs diff --git a/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj b/src/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj similarity index 100% rename from GreenshotOfficePlugin/GreenshotOfficePlugin.csproj rename to src/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj diff --git a/GreenshotOfficePlugin/Languages/language_officeplugin-fr-FR.ini b/src/GreenshotOfficePlugin/Languages/language_officeplugin-fr-FR.ini similarity index 100% rename from GreenshotOfficePlugin/Languages/language_officeplugin-fr-FR.ini rename to src/GreenshotOfficePlugin/Languages/language_officeplugin-fr-FR.ini diff --git a/GreenshotOfficePlugin/OfficeConfiguration.cs b/src/GreenshotOfficePlugin/OfficeConfiguration.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeConfiguration.cs rename to src/GreenshotOfficePlugin/OfficeConfiguration.cs diff --git a/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs b/src/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs rename to src/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs diff --git a/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs b/src/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs rename to src/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs diff --git a/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs b/src/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs rename to src/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs diff --git a/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs b/src/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs rename to src/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs diff --git a/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs b/src/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs rename to src/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs diff --git a/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs b/src/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs rename to src/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs diff --git a/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs b/src/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs rename to src/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs diff --git a/GreenshotOfficePlugin/OfficeExport/WordExporter.cs b/src/GreenshotOfficePlugin/OfficeExport/WordExporter.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeExport/WordExporter.cs rename to src/GreenshotOfficePlugin/OfficeExport/WordExporter.cs diff --git a/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs b/src/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs rename to src/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs diff --git a/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs b/src/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs similarity index 100% rename from GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs rename to src/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs diff --git a/GreenshotOfficePlugin/OfficePlugin.cs b/src/GreenshotOfficePlugin/OfficePlugin.cs similarity index 100% rename from GreenshotOfficePlugin/OfficePlugin.cs rename to src/GreenshotOfficePlugin/OfficePlugin.cs diff --git a/GreenshotOfficePlugin/Properties/AssemblyInfo.cs b/src/GreenshotOfficePlugin/Properties/AssemblyInfo.cs similarity index 100% rename from GreenshotOfficePlugin/Properties/AssemblyInfo.cs rename to src/GreenshotOfficePlugin/Properties/AssemblyInfo.cs diff --git a/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs b/src/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs similarity index 100% rename from GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs rename to src/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs diff --git a/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs b/src/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs similarity index 100% rename from GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs rename to src/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs diff --git a/GreenshotPhotobucketPlugin/Forms/SettingsForm.cs b/src/GreenshotPhotobucketPlugin/Forms/SettingsForm.cs similarity index 100% rename from GreenshotPhotobucketPlugin/Forms/SettingsForm.cs rename to src/GreenshotPhotobucketPlugin/Forms/SettingsForm.cs diff --git a/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template b/src/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template similarity index 100% rename from GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template rename to src/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template diff --git a/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.csproj b/src/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.csproj similarity index 100% rename from GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.csproj rename to src/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.csproj diff --git a/GreenshotPhotobucketPlugin/LanguageKeys.cs b/src/GreenshotPhotobucketPlugin/LanguageKeys.cs similarity index 100% rename from GreenshotPhotobucketPlugin/LanguageKeys.cs rename to src/GreenshotPhotobucketPlugin/LanguageKeys.cs diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-cs-CZ.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-cs-CZ.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-cs-CZ.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-cs-CZ.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-de-DE.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-de-DE.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-de-DE.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-de-DE.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-en-US.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-en-US.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-en-US.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-en-US.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-fr_FR.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-fr_FR.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-fr_FR.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-fr_FR.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-id-ID.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-id-ID.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-id-ID.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-id-ID.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ja-JP.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ja-JP.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ja-JP.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ja-JP.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-kab-DZ.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-kab-DZ.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-kab-DZ.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-kab-DZ.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ko-KR.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ko-KR.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ko-KR.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ko-KR.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-lv-LV.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-lv-LV.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-lv-LV.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-lv-LV.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-nl-NL.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-nl-NL.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-nl-NL.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-nl-NL.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pl-PL.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pl-PL.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pl-PL.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pl-PL.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pt-PT.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pt-PT.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pt-PT.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pt-PT.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ru-RU.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ru-RU.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ru-RU.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ru-RU.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-sv-SE.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-sv-SE.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-sv-SE.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-sv-SE.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-uk-UA.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-uk-UA.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-uk-UA.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-uk-UA.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-CN.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-CN.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-CN.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-CN.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-TW.xml b/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-TW.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-TW.xml rename to src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-TW.xml diff --git a/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs b/src/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs similarity index 100% rename from GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs rename to src/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs diff --git a/GreenshotPhotobucketPlugin/PhotobucketDestination.cs b/src/GreenshotPhotobucketPlugin/PhotobucketDestination.cs similarity index 100% rename from GreenshotPhotobucketPlugin/PhotobucketDestination.cs rename to src/GreenshotPhotobucketPlugin/PhotobucketDestination.cs diff --git a/GreenshotPhotobucketPlugin/PhotobucketInfo.cs b/src/GreenshotPhotobucketPlugin/PhotobucketInfo.cs similarity index 100% rename from GreenshotPhotobucketPlugin/PhotobucketInfo.cs rename to src/GreenshotPhotobucketPlugin/PhotobucketInfo.cs diff --git a/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs b/src/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs similarity index 100% rename from GreenshotPhotobucketPlugin/PhotobucketPlugin.cs rename to src/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs diff --git a/GreenshotPhotobucketPlugin/PhotobucketPlugin.resx b/src/GreenshotPhotobucketPlugin/PhotobucketPlugin.resx similarity index 100% rename from GreenshotPhotobucketPlugin/PhotobucketPlugin.resx rename to src/GreenshotPhotobucketPlugin/PhotobucketPlugin.resx diff --git a/GreenshotPhotobucketPlugin/PhotobucketUtils.cs b/src/GreenshotPhotobucketPlugin/PhotobucketUtils.cs similarity index 100% rename from GreenshotPhotobucketPlugin/PhotobucketUtils.cs rename to src/GreenshotPhotobucketPlugin/PhotobucketUtils.cs diff --git a/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs b/src/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs similarity index 100% rename from GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs rename to src/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs diff --git a/GreenshotPlugin/Controls/AnimatingForm.cs b/src/GreenshotPlugin/Controls/AnimatingForm.cs similarity index 100% rename from GreenshotPlugin/Controls/AnimatingForm.cs rename to src/GreenshotPlugin/Controls/AnimatingForm.cs diff --git a/GreenshotPlugin/Controls/BackgroundForm.Designer.cs b/src/GreenshotPlugin/Controls/BackgroundForm.Designer.cs similarity index 100% rename from GreenshotPlugin/Controls/BackgroundForm.Designer.cs rename to src/GreenshotPlugin/Controls/BackgroundForm.Designer.cs diff --git a/GreenshotPlugin/Controls/BackgroundForm.cs b/src/GreenshotPlugin/Controls/BackgroundForm.cs similarity index 100% rename from GreenshotPlugin/Controls/BackgroundForm.cs rename to src/GreenshotPlugin/Controls/BackgroundForm.cs diff --git a/GreenshotPlugin/Controls/ExtendedWebBrowser.cs b/src/GreenshotPlugin/Controls/ExtendedWebBrowser.cs similarity index 100% rename from GreenshotPlugin/Controls/ExtendedWebBrowser.cs rename to src/GreenshotPlugin/Controls/ExtendedWebBrowser.cs diff --git a/GreenshotPlugin/Controls/FormWithoutActivation.cs b/src/GreenshotPlugin/Controls/FormWithoutActivation.cs similarity index 100% rename from GreenshotPlugin/Controls/FormWithoutActivation.cs rename to src/GreenshotPlugin/Controls/FormWithoutActivation.cs diff --git a/GreenshotPlugin/Controls/GreenshotButton.cs b/src/GreenshotPlugin/Controls/GreenshotButton.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotButton.cs rename to src/GreenshotPlugin/Controls/GreenshotButton.cs diff --git a/GreenshotPlugin/Controls/GreenshotCheckBox.cs b/src/GreenshotPlugin/Controls/GreenshotCheckBox.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotCheckBox.cs rename to src/GreenshotPlugin/Controls/GreenshotCheckBox.cs diff --git a/GreenshotPlugin/Controls/GreenshotColumnSorter.cs b/src/GreenshotPlugin/Controls/GreenshotColumnSorter.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotColumnSorter.cs rename to src/GreenshotPlugin/Controls/GreenshotColumnSorter.cs diff --git a/GreenshotPlugin/Controls/GreenshotComboBox.cs b/src/GreenshotPlugin/Controls/GreenshotComboBox.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotComboBox.cs rename to src/GreenshotPlugin/Controls/GreenshotComboBox.cs diff --git a/GreenshotPlugin/Controls/GreenshotForm.cs b/src/GreenshotPlugin/Controls/GreenshotForm.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotForm.cs rename to src/GreenshotPlugin/Controls/GreenshotForm.cs diff --git a/GreenshotPlugin/Controls/GreenshotGroupBox.cs b/src/GreenshotPlugin/Controls/GreenshotGroupBox.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotGroupBox.cs rename to src/GreenshotPlugin/Controls/GreenshotGroupBox.cs diff --git a/GreenshotPlugin/Controls/GreenshotLabel.cs b/src/GreenshotPlugin/Controls/GreenshotLabel.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotLabel.cs rename to src/GreenshotPlugin/Controls/GreenshotLabel.cs diff --git a/GreenshotPlugin/Controls/GreenshotRadioButton.cs b/src/GreenshotPlugin/Controls/GreenshotRadioButton.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotRadioButton.cs rename to src/GreenshotPlugin/Controls/GreenshotRadioButton.cs diff --git a/GreenshotPlugin/Controls/GreenshotTabPage.cs b/src/GreenshotPlugin/Controls/GreenshotTabPage.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotTabPage.cs rename to src/GreenshotPlugin/Controls/GreenshotTabPage.cs diff --git a/GreenshotPlugin/Controls/GreenshotTextBox.cs b/src/GreenshotPlugin/Controls/GreenshotTextBox.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotTextBox.cs rename to src/GreenshotPlugin/Controls/GreenshotTextBox.cs diff --git a/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs b/src/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs rename to src/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs diff --git a/GreenshotPlugin/Controls/GreenshotToolStripButton.cs b/src/GreenshotPlugin/Controls/GreenshotToolStripButton.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotToolStripButton.cs rename to src/GreenshotPlugin/Controls/GreenshotToolStripButton.cs diff --git a/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs b/src/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotToolStripLabel.cs rename to src/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs diff --git a/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs b/src/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs similarity index 100% rename from GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs rename to src/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs diff --git a/GreenshotPlugin/Controls/HotkeyControl.cs b/src/GreenshotPlugin/Controls/HotkeyControl.cs similarity index 100% rename from GreenshotPlugin/Controls/HotkeyControl.cs rename to src/GreenshotPlugin/Controls/HotkeyControl.cs diff --git a/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs b/src/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs similarity index 100% rename from GreenshotPlugin/Controls/IGreenshotConfigBindable.cs rename to src/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs diff --git a/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs b/src/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs similarity index 100% rename from GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs rename to src/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs diff --git a/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs b/src/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs similarity index 100% rename from GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs rename to src/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs diff --git a/GreenshotPlugin/Controls/OAuthLoginForm.cs b/src/GreenshotPlugin/Controls/OAuthLoginForm.cs similarity index 100% rename from GreenshotPlugin/Controls/OAuthLoginForm.cs rename to src/GreenshotPlugin/Controls/OAuthLoginForm.cs diff --git a/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs b/src/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs similarity index 100% rename from GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs rename to src/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs diff --git a/GreenshotPlugin/Controls/PleaseWaitForm.cs b/src/GreenshotPlugin/Controls/PleaseWaitForm.cs similarity index 100% rename from GreenshotPlugin/Controls/PleaseWaitForm.cs rename to src/GreenshotPlugin/Controls/PleaseWaitForm.cs diff --git a/GreenshotPlugin/Controls/QualityDialog.Designer.cs b/src/GreenshotPlugin/Controls/QualityDialog.Designer.cs similarity index 100% rename from GreenshotPlugin/Controls/QualityDialog.Designer.cs rename to src/GreenshotPlugin/Controls/QualityDialog.Designer.cs diff --git a/GreenshotPlugin/Controls/QualityDialog.cs b/src/GreenshotPlugin/Controls/QualityDialog.cs similarity index 100% rename from GreenshotPlugin/Controls/QualityDialog.cs rename to src/GreenshotPlugin/Controls/QualityDialog.cs diff --git a/GreenshotPlugin/Controls/SaveImageFileDialog.cs b/src/GreenshotPlugin/Controls/SaveImageFileDialog.cs similarity index 100% rename from GreenshotPlugin/Controls/SaveImageFileDialog.cs rename to src/GreenshotPlugin/Controls/SaveImageFileDialog.cs diff --git a/GreenshotPlugin/Controls/ThumbnailForm.cs b/src/GreenshotPlugin/Controls/ThumbnailForm.cs similarity index 100% rename from GreenshotPlugin/Controls/ThumbnailForm.cs rename to src/GreenshotPlugin/Controls/ThumbnailForm.cs diff --git a/GreenshotPlugin/Core/AbstractDestination.cs b/src/GreenshotPlugin/Core/AbstractDestination.cs similarity index 100% rename from GreenshotPlugin/Core/AbstractDestination.cs rename to src/GreenshotPlugin/Core/AbstractDestination.cs diff --git a/GreenshotPlugin/Core/AbstractProcessor.cs b/src/GreenshotPlugin/Core/AbstractProcessor.cs similarity index 100% rename from GreenshotPlugin/Core/AbstractProcessor.cs rename to src/GreenshotPlugin/Core/AbstractProcessor.cs diff --git a/GreenshotPlugin/Core/AccessibleHelper.cs b/src/GreenshotPlugin/Core/AccessibleHelper.cs similarity index 100% rename from GreenshotPlugin/Core/AccessibleHelper.cs rename to src/GreenshotPlugin/Core/AccessibleHelper.cs diff --git a/GreenshotPlugin/Core/AnimationHelpers.cs b/src/GreenshotPlugin/Core/AnimationHelpers.cs similarity index 100% rename from GreenshotPlugin/Core/AnimationHelpers.cs rename to src/GreenshotPlugin/Core/AnimationHelpers.cs diff --git a/GreenshotPlugin/Core/BinaryStructHelper.cs b/src/GreenshotPlugin/Core/BinaryStructHelper.cs similarity index 100% rename from GreenshotPlugin/Core/BinaryStructHelper.cs rename to src/GreenshotPlugin/Core/BinaryStructHelper.cs diff --git a/GreenshotPlugin/Core/Cache.cs b/src/GreenshotPlugin/Core/Cache.cs similarity index 100% rename from GreenshotPlugin/Core/Cache.cs rename to src/GreenshotPlugin/Core/Cache.cs diff --git a/GreenshotPlugin/Core/Capture.cs b/src/GreenshotPlugin/Core/Capture.cs similarity index 100% rename from GreenshotPlugin/Core/Capture.cs rename to src/GreenshotPlugin/Core/Capture.cs diff --git a/GreenshotPlugin/Core/CaptureDetails.cs b/src/GreenshotPlugin/Core/CaptureDetails.cs similarity index 100% rename from GreenshotPlugin/Core/CaptureDetails.cs rename to src/GreenshotPlugin/Core/CaptureDetails.cs diff --git a/GreenshotPlugin/Core/CaptureHandler.cs b/src/GreenshotPlugin/Core/CaptureHandler.cs similarity index 100% rename from GreenshotPlugin/Core/CaptureHandler.cs rename to src/GreenshotPlugin/Core/CaptureHandler.cs diff --git a/GreenshotPlugin/Core/ClipboardHelper.cs b/src/GreenshotPlugin/Core/ClipboardHelper.cs similarity index 100% rename from GreenshotPlugin/Core/ClipboardHelper.cs rename to src/GreenshotPlugin/Core/ClipboardHelper.cs diff --git a/GreenshotPlugin/Core/CoreConfiguration.cs b/src/GreenshotPlugin/Core/CoreConfiguration.cs similarity index 100% rename from GreenshotPlugin/Core/CoreConfiguration.cs rename to src/GreenshotPlugin/Core/CoreConfiguration.cs diff --git a/GreenshotPlugin/Core/CredentialsHelper.cs b/src/GreenshotPlugin/Core/CredentialsHelper.cs similarity index 100% rename from GreenshotPlugin/Core/CredentialsHelper.cs rename to src/GreenshotPlugin/Core/CredentialsHelper.cs diff --git a/GreenshotPlugin/Core/DisplayKeyAttribute.cs b/src/GreenshotPlugin/Core/DisplayKeyAttribute.cs similarity index 100% rename from GreenshotPlugin/Core/DisplayKeyAttribute.cs rename to src/GreenshotPlugin/Core/DisplayKeyAttribute.cs diff --git a/GreenshotPlugin/Core/DpiHelper.cs b/src/GreenshotPlugin/Core/DpiHelper.cs similarity index 100% rename from GreenshotPlugin/Core/DpiHelper.cs rename to src/GreenshotPlugin/Core/DpiHelper.cs diff --git a/GreenshotPlugin/Core/EffectConverter.cs b/src/GreenshotPlugin/Core/EffectConverter.cs similarity index 100% rename from GreenshotPlugin/Core/EffectConverter.cs rename to src/GreenshotPlugin/Core/EffectConverter.cs diff --git a/GreenshotPlugin/Core/Enums/HResult.cs b/src/GreenshotPlugin/Core/Enums/HResult.cs similarity index 100% rename from GreenshotPlugin/Core/Enums/HResult.cs rename to src/GreenshotPlugin/Core/Enums/HResult.cs diff --git a/GreenshotPlugin/Core/Enums/MonitorDpiType.cs b/src/GreenshotPlugin/Core/Enums/MonitorDpiType.cs similarity index 100% rename from GreenshotPlugin/Core/Enums/MonitorDpiType.cs rename to src/GreenshotPlugin/Core/Enums/MonitorDpiType.cs diff --git a/GreenshotPlugin/Core/Enums/MonitorFrom.cs b/src/GreenshotPlugin/Core/Enums/MonitorFrom.cs similarity index 100% rename from GreenshotPlugin/Core/Enums/MonitorFrom.cs rename to src/GreenshotPlugin/Core/Enums/MonitorFrom.cs diff --git a/GreenshotPlugin/Core/EnvironmentInfo.cs b/src/GreenshotPlugin/Core/EnvironmentInfo.cs similarity index 100% rename from GreenshotPlugin/Core/EnvironmentInfo.cs rename to src/GreenshotPlugin/Core/EnvironmentInfo.cs diff --git a/GreenshotPlugin/Core/EventDelay.cs b/src/GreenshotPlugin/Core/EventDelay.cs similarity index 100% rename from GreenshotPlugin/Core/EventDelay.cs rename to src/GreenshotPlugin/Core/EventDelay.cs diff --git a/GreenshotPlugin/Core/ExplorerHelper.cs b/src/GreenshotPlugin/Core/ExplorerHelper.cs similarity index 100% rename from GreenshotPlugin/Core/ExplorerHelper.cs rename to src/GreenshotPlugin/Core/ExplorerHelper.cs diff --git a/GreenshotPlugin/Core/FastBitmap.cs b/src/GreenshotPlugin/Core/FastBitmap.cs similarity index 100% rename from GreenshotPlugin/Core/FastBitmap.cs rename to src/GreenshotPlugin/Core/FastBitmap.cs diff --git a/GreenshotPlugin/Core/FilenameHelper.cs b/src/GreenshotPlugin/Core/FilenameHelper.cs similarity index 100% rename from GreenshotPlugin/Core/FilenameHelper.cs rename to src/GreenshotPlugin/Core/FilenameHelper.cs diff --git a/GreenshotPlugin/Core/Fraction.cs b/src/GreenshotPlugin/Core/Fraction.cs similarity index 100% rename from GreenshotPlugin/Core/Fraction.cs rename to src/GreenshotPlugin/Core/Fraction.cs diff --git a/GreenshotPlugin/Core/GreenshotResources.cs b/src/GreenshotPlugin/Core/GreenshotResources.cs similarity index 100% rename from GreenshotPlugin/Core/GreenshotResources.cs rename to src/GreenshotPlugin/Core/GreenshotResources.cs diff --git a/GreenshotPlugin/Core/GreenshotResources.resx b/src/GreenshotPlugin/Core/GreenshotResources.resx similarity index 100% rename from GreenshotPlugin/Core/GreenshotResources.resx rename to src/GreenshotPlugin/Core/GreenshotResources.resx diff --git a/GreenshotPlugin/Core/HResultExtensions.cs b/src/GreenshotPlugin/Core/HResultExtensions.cs similarity index 100% rename from GreenshotPlugin/Core/HResultExtensions.cs rename to src/GreenshotPlugin/Core/HResultExtensions.cs diff --git a/GreenshotPlugin/Core/IEHelper.cs b/src/GreenshotPlugin/Core/IEHelper.cs similarity index 100% rename from GreenshotPlugin/Core/IEHelper.cs rename to src/GreenshotPlugin/Core/IEHelper.cs diff --git a/GreenshotPlugin/Core/IImage.cs b/src/GreenshotPlugin/Core/IImage.cs similarity index 100% rename from GreenshotPlugin/Core/IImage.cs rename to src/GreenshotPlugin/Core/IImage.cs diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/src/GreenshotPlugin/Core/ImageHelper.cs similarity index 100% rename from GreenshotPlugin/Core/ImageHelper.cs rename to src/GreenshotPlugin/Core/ImageHelper.cs diff --git a/GreenshotPlugin/Core/ImageOutput.cs b/src/GreenshotPlugin/Core/ImageOutput.cs similarity index 100% rename from GreenshotPlugin/Core/ImageOutput.cs rename to src/GreenshotPlugin/Core/ImageOutput.cs diff --git a/GreenshotPlugin/Core/ImageWrapper.cs b/src/GreenshotPlugin/Core/ImageWrapper.cs similarity index 100% rename from GreenshotPlugin/Core/ImageWrapper.cs rename to src/GreenshotPlugin/Core/ImageWrapper.cs diff --git a/GreenshotPlugin/Core/InterfaceUtils.cs b/src/GreenshotPlugin/Core/InterfaceUtils.cs similarity index 100% rename from GreenshotPlugin/Core/InterfaceUtils.cs rename to src/GreenshotPlugin/Core/InterfaceUtils.cs diff --git a/GreenshotPlugin/Core/JSONHelper.cs b/src/GreenshotPlugin/Core/JSONHelper.cs similarity index 100% rename from GreenshotPlugin/Core/JSONHelper.cs rename to src/GreenshotPlugin/Core/JSONHelper.cs diff --git a/GreenshotPlugin/Core/Language.cs b/src/GreenshotPlugin/Core/Language.cs similarity index 100% rename from GreenshotPlugin/Core/Language.cs rename to src/GreenshotPlugin/Core/Language.cs diff --git a/GreenshotPlugin/Core/LanguageChangedHandler.cs b/src/GreenshotPlugin/Core/LanguageChangedHandler.cs similarity index 100% rename from GreenshotPlugin/Core/LanguageChangedHandler.cs rename to src/GreenshotPlugin/Core/LanguageChangedHandler.cs diff --git a/GreenshotPlugin/Core/LanguageFile.cs b/src/GreenshotPlugin/Core/LanguageFile.cs similarity index 100% rename from GreenshotPlugin/Core/LanguageFile.cs rename to src/GreenshotPlugin/Core/LanguageFile.cs diff --git a/GreenshotPlugin/Core/LogHelper.cs b/src/GreenshotPlugin/Core/LogHelper.cs similarity index 100% rename from GreenshotPlugin/Core/LogHelper.cs rename to src/GreenshotPlugin/Core/LogHelper.cs diff --git a/GreenshotPlugin/Core/NetworkHelper.cs b/src/GreenshotPlugin/Core/NetworkHelper.cs similarity index 100% rename from GreenshotPlugin/Core/NetworkHelper.cs rename to src/GreenshotPlugin/Core/NetworkHelper.cs diff --git a/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs b/src/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs similarity index 100% rename from GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs rename to src/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs diff --git a/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs b/src/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs similarity index 100% rename from GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs rename to src/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs diff --git a/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs b/src/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs similarity index 100% rename from GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs rename to src/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs diff --git a/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs b/src/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs similarity index 100% rename from GreenshotPlugin/Core/OAuth/OAuth2Helper.cs rename to src/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs diff --git a/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs b/src/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs similarity index 100% rename from GreenshotPlugin/Core/OAuth/OAuth2Settings.cs rename to src/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs diff --git a/GreenshotPlugin/Core/OAuth/OAuthSession.cs b/src/GreenshotPlugin/Core/OAuth/OAuthSession.cs similarity index 100% rename from GreenshotPlugin/Core/OAuth/OAuthSession.cs rename to src/GreenshotPlugin/Core/OAuth/OAuthSession.cs diff --git a/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs b/src/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs similarity index 100% rename from GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs rename to src/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs diff --git a/GreenshotPlugin/Core/ObjectExtensions.cs b/src/GreenshotPlugin/Core/ObjectExtensions.cs similarity index 100% rename from GreenshotPlugin/Core/ObjectExtensions.cs rename to src/GreenshotPlugin/Core/ObjectExtensions.cs diff --git a/GreenshotPlugin/Core/PluginUtils.cs b/src/GreenshotPlugin/Core/PluginUtils.cs similarity index 100% rename from GreenshotPlugin/Core/PluginUtils.cs rename to src/GreenshotPlugin/Core/PluginUtils.cs diff --git a/GreenshotPlugin/Core/QuantizerHelper.cs b/src/GreenshotPlugin/Core/QuantizerHelper.cs similarity index 100% rename from GreenshotPlugin/Core/QuantizerHelper.cs rename to src/GreenshotPlugin/Core/QuantizerHelper.cs diff --git a/GreenshotPlugin/Core/RegistryKeyExtensions.cs b/src/GreenshotPlugin/Core/RegistryKeyExtensions.cs similarity index 100% rename from GreenshotPlugin/Core/RegistryKeyExtensions.cs rename to src/GreenshotPlugin/Core/RegistryKeyExtensions.cs diff --git a/GreenshotPlugin/Core/SimpleServiceProvider.cs b/src/GreenshotPlugin/Core/SimpleServiceProvider.cs similarity index 100% rename from GreenshotPlugin/Core/SimpleServiceProvider.cs rename to src/GreenshotPlugin/Core/SimpleServiceProvider.cs diff --git a/GreenshotPlugin/Core/StringExtensions.cs b/src/GreenshotPlugin/Core/StringExtensions.cs similarity index 100% rename from GreenshotPlugin/Core/StringExtensions.cs rename to src/GreenshotPlugin/Core/StringExtensions.cs diff --git a/GreenshotPlugin/Core/SvgImage.cs b/src/GreenshotPlugin/Core/SvgImage.cs similarity index 100% rename from GreenshotPlugin/Core/SvgImage.cs rename to src/GreenshotPlugin/Core/SvgImage.cs diff --git a/GreenshotPlugin/Core/WindowCapture.cs b/src/GreenshotPlugin/Core/WindowCapture.cs similarity index 100% rename from GreenshotPlugin/Core/WindowCapture.cs rename to src/GreenshotPlugin/Core/WindowCapture.cs diff --git a/GreenshotPlugin/Core/WindowDetails.cs b/src/GreenshotPlugin/Core/WindowDetails.cs similarity index 100% rename from GreenshotPlugin/Core/WindowDetails.cs rename to src/GreenshotPlugin/Core/WindowDetails.cs diff --git a/GreenshotPlugin/Core/WindowsEnumerator.cs b/src/GreenshotPlugin/Core/WindowsEnumerator.cs similarity index 100% rename from GreenshotPlugin/Core/WindowsEnumerator.cs rename to src/GreenshotPlugin/Core/WindowsEnumerator.cs diff --git a/GreenshotPlugin/Core/WindowsVersion.cs b/src/GreenshotPlugin/Core/WindowsVersion.cs similarity index 100% rename from GreenshotPlugin/Core/WindowsVersion.cs rename to src/GreenshotPlugin/Core/WindowsVersion.cs diff --git a/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs b/src/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs similarity index 100% rename from GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs rename to src/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs diff --git a/GreenshotPlugin/Effects/AdjustEffect.cs b/src/GreenshotPlugin/Effects/AdjustEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/AdjustEffect.cs rename to src/GreenshotPlugin/Effects/AdjustEffect.cs diff --git a/GreenshotPlugin/Effects/BorderEffect.cs b/src/GreenshotPlugin/Effects/BorderEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/BorderEffect.cs rename to src/GreenshotPlugin/Effects/BorderEffect.cs diff --git a/GreenshotPlugin/Effects/DropShadowEffect.cs b/src/GreenshotPlugin/Effects/DropShadowEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/DropShadowEffect.cs rename to src/GreenshotPlugin/Effects/DropShadowEffect.cs diff --git a/GreenshotPlugin/Effects/GrayscaleEffect.cs b/src/GreenshotPlugin/Effects/GrayscaleEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/GrayscaleEffect.cs rename to src/GreenshotPlugin/Effects/GrayscaleEffect.cs diff --git a/GreenshotPlugin/Effects/IEffect.cs b/src/GreenshotPlugin/Effects/IEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/IEffect.cs rename to src/GreenshotPlugin/Effects/IEffect.cs diff --git a/GreenshotPlugin/Effects/InvertEffect.cs b/src/GreenshotPlugin/Effects/InvertEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/InvertEffect.cs rename to src/GreenshotPlugin/Effects/InvertEffect.cs diff --git a/GreenshotPlugin/Effects/MonochromeEffect.cs b/src/GreenshotPlugin/Effects/MonochromeEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/MonochromeEffect.cs rename to src/GreenshotPlugin/Effects/MonochromeEffect.cs diff --git a/GreenshotPlugin/Effects/ReduceColorsEffect.cs b/src/GreenshotPlugin/Effects/ReduceColorsEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/ReduceColorsEffect.cs rename to src/GreenshotPlugin/Effects/ReduceColorsEffect.cs diff --git a/GreenshotPlugin/Effects/ResizeCanvasEffect.cs b/src/GreenshotPlugin/Effects/ResizeCanvasEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/ResizeCanvasEffect.cs rename to src/GreenshotPlugin/Effects/ResizeCanvasEffect.cs diff --git a/GreenshotPlugin/Effects/ResizeEffect.cs b/src/GreenshotPlugin/Effects/ResizeEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/ResizeEffect.cs rename to src/GreenshotPlugin/Effects/ResizeEffect.cs diff --git a/GreenshotPlugin/Effects/RotateEffect.cs b/src/GreenshotPlugin/Effects/RotateEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/RotateEffect.cs rename to src/GreenshotPlugin/Effects/RotateEffect.cs diff --git a/GreenshotPlugin/Effects/TornEdgeEffect.cs b/src/GreenshotPlugin/Effects/TornEdgeEffect.cs similarity index 100% rename from GreenshotPlugin/Effects/TornEdgeEffect.cs rename to src/GreenshotPlugin/Effects/TornEdgeEffect.cs diff --git a/GreenshotPlugin/FileDescriptorReader.cs b/src/GreenshotPlugin/FileDescriptorReader.cs similarity index 100% rename from GreenshotPlugin/FileDescriptorReader.cs rename to src/GreenshotPlugin/FileDescriptorReader.cs diff --git a/GreenshotPlugin/GlobalSuppressions.cs b/src/GreenshotPlugin/GlobalSuppressions.cs similarity index 100% rename from GreenshotPlugin/GlobalSuppressions.cs rename to src/GreenshotPlugin/GlobalSuppressions.cs diff --git a/GreenshotPlugin/GreenshotPlugin.csproj b/src/GreenshotPlugin/GreenshotPlugin.csproj similarity index 100% rename from GreenshotPlugin/GreenshotPlugin.csproj rename to src/GreenshotPlugin/GreenshotPlugin.csproj diff --git a/GreenshotPlugin/Hooking/WindowsEventHook.cs b/src/GreenshotPlugin/Hooking/WindowsEventHook.cs similarity index 100% rename from GreenshotPlugin/Hooking/WindowsEventHook.cs rename to src/GreenshotPlugin/Hooking/WindowsEventHook.cs diff --git a/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs b/src/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs similarity index 100% rename from GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs rename to src/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs diff --git a/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs b/src/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs similarity index 100% rename from GreenshotPlugin/Hooking/WindowsTitleMonitor.cs rename to src/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs b/src/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLBodyElement.cs rename to src/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs b/src/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs rename to src/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument.cs b/src/GreenshotPlugin/IEInterop/IHTMLDocument.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLDocument.cs rename to src/GreenshotPlugin/IEInterop/IHTMLDocument.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument2.cs b/src/GreenshotPlugin/IEInterop/IHTMLDocument2.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLDocument2.cs rename to src/GreenshotPlugin/IEInterop/IHTMLDocument2.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument3.cs b/src/GreenshotPlugin/IEInterop/IHTMLDocument3.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLDocument3.cs rename to src/GreenshotPlugin/IEInterop/IHTMLDocument3.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument4.cs b/src/GreenshotPlugin/IEInterop/IHTMLDocument4.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLDocument4.cs rename to src/GreenshotPlugin/IEInterop/IHTMLDocument4.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument5.cs b/src/GreenshotPlugin/IEInterop/IHTMLDocument5.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLDocument5.cs rename to src/GreenshotPlugin/IEInterop/IHTMLDocument5.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLElement.cs b/src/GreenshotPlugin/IEInterop/IHTMLElement.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLElement.cs rename to src/GreenshotPlugin/IEInterop/IHTMLElement.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLElement2.cs b/src/GreenshotPlugin/IEInterop/IHTMLElement2.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLElement2.cs rename to src/GreenshotPlugin/IEInterop/IHTMLElement2.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs b/src/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLElementCollection.cs rename to src/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs b/src/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLFrameBase.cs rename to src/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs b/src/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs rename to src/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLRect.cs b/src/GreenshotPlugin/IEInterop/IHTMLRect.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLRect.cs rename to src/GreenshotPlugin/IEInterop/IHTMLRect.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLScreen.cs b/src/GreenshotPlugin/IEInterop/IHTMLScreen.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLScreen.cs rename to src/GreenshotPlugin/IEInterop/IHTMLScreen.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLScreen2.cs b/src/GreenshotPlugin/IEInterop/IHTMLScreen2.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLScreen2.cs rename to src/GreenshotPlugin/IEInterop/IHTMLScreen2.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs b/src/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs rename to src/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLStyle.cs b/src/GreenshotPlugin/IEInterop/IHTMLStyle.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLStyle.cs rename to src/GreenshotPlugin/IEInterop/IHTMLStyle.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs b/src/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLTxtRange.cs rename to src/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLWindow2.cs b/src/GreenshotPlugin/IEInterop/IHTMLWindow2.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLWindow2.cs rename to src/GreenshotPlugin/IEInterop/IHTMLWindow2.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLWindow3.cs b/src/GreenshotPlugin/IEInterop/IHTMLWindow3.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLWindow3.cs rename to src/GreenshotPlugin/IEInterop/IHTMLWindow3.cs diff --git a/GreenshotPlugin/IEInterop/IHTMLWindow4.cs b/src/GreenshotPlugin/IEInterop/IHTMLWindow4.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IHTMLWindow4.cs rename to src/GreenshotPlugin/IEInterop/IHTMLWindow4.cs diff --git a/GreenshotPlugin/IEInterop/IWebBrowser2.cs b/src/GreenshotPlugin/IEInterop/IWebBrowser2.cs similarity index 100% rename from GreenshotPlugin/IEInterop/IWebBrowser2.cs rename to src/GreenshotPlugin/IEInterop/IWebBrowser2.cs diff --git a/GreenshotPlugin/IniFile/IniAttributes.cs b/src/GreenshotPlugin/IniFile/IniAttributes.cs similarity index 100% rename from GreenshotPlugin/IniFile/IniAttributes.cs rename to src/GreenshotPlugin/IniFile/IniAttributes.cs diff --git a/GreenshotPlugin/IniFile/IniConfig.cs b/src/GreenshotPlugin/IniFile/IniConfig.cs similarity index 100% rename from GreenshotPlugin/IniFile/IniConfig.cs rename to src/GreenshotPlugin/IniFile/IniConfig.cs diff --git a/GreenshotPlugin/IniFile/IniReader.cs b/src/GreenshotPlugin/IniFile/IniReader.cs similarity index 100% rename from GreenshotPlugin/IniFile/IniReader.cs rename to src/GreenshotPlugin/IniFile/IniReader.cs diff --git a/GreenshotPlugin/IniFile/IniSection.cs b/src/GreenshotPlugin/IniFile/IniSection.cs similarity index 100% rename from GreenshotPlugin/IniFile/IniSection.cs rename to src/GreenshotPlugin/IniFile/IniSection.cs diff --git a/GreenshotPlugin/IniFile/IniValue.cs b/src/GreenshotPlugin/IniFile/IniValue.cs similarity index 100% rename from GreenshotPlugin/IniFile/IniValue.cs rename to src/GreenshotPlugin/IniFile/IniValue.cs diff --git a/GreenshotPlugin/Interfaces/CaptureMode.cs b/src/GreenshotPlugin/Interfaces/CaptureMode.cs similarity index 100% rename from GreenshotPlugin/Interfaces/CaptureMode.cs rename to src/GreenshotPlugin/Interfaces/CaptureMode.cs diff --git a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs b/src/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs rename to src/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/src/GreenshotPlugin/Interfaces/Drawing/Container.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Drawing/Container.cs rename to src/GreenshotPlugin/Interfaces/Drawing/Container.cs diff --git a/GreenshotPlugin/Interfaces/Drawing/IField.cs b/src/GreenshotPlugin/Interfaces/Drawing/IField.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Drawing/IField.cs rename to src/GreenshotPlugin/Interfaces/Drawing/IField.cs diff --git a/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs b/src/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs rename to src/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs diff --git a/GreenshotPlugin/Interfaces/Drawing/IMemento.cs b/src/GreenshotPlugin/Interfaces/Drawing/IMemento.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Drawing/IMemento.cs rename to src/GreenshotPlugin/Interfaces/Drawing/IMemento.cs diff --git a/GreenshotPlugin/Interfaces/DrawingModes.cs b/src/GreenshotPlugin/Interfaces/DrawingModes.cs similarity index 100% rename from GreenshotPlugin/Interfaces/DrawingModes.cs rename to src/GreenshotPlugin/Interfaces/DrawingModes.cs diff --git a/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs b/src/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Forms/ImageEditor.cs rename to src/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs diff --git a/GreenshotPlugin/Interfaces/ICapture.cs b/src/GreenshotPlugin/Interfaces/ICapture.cs similarity index 100% rename from GreenshotPlugin/Interfaces/ICapture.cs rename to src/GreenshotPlugin/Interfaces/ICapture.cs diff --git a/GreenshotPlugin/Interfaces/ICaptureDetails.cs b/src/GreenshotPlugin/Interfaces/ICaptureDetails.cs similarity index 100% rename from GreenshotPlugin/Interfaces/ICaptureDetails.cs rename to src/GreenshotPlugin/Interfaces/ICaptureDetails.cs diff --git a/GreenshotPlugin/Interfaces/IDestination.cs b/src/GreenshotPlugin/Interfaces/IDestination.cs similarity index 100% rename from GreenshotPlugin/Interfaces/IDestination.cs rename to src/GreenshotPlugin/Interfaces/IDestination.cs diff --git a/GreenshotPlugin/Interfaces/INotificationService.cs b/src/GreenshotPlugin/Interfaces/INotificationService.cs similarity index 100% rename from GreenshotPlugin/Interfaces/INotificationService.cs rename to src/GreenshotPlugin/Interfaces/INotificationService.cs diff --git a/GreenshotPlugin/Interfaces/IProcessor.cs b/src/GreenshotPlugin/Interfaces/IProcessor.cs similarity index 100% rename from GreenshotPlugin/Interfaces/IProcessor.cs rename to src/GreenshotPlugin/Interfaces/IProcessor.cs diff --git a/GreenshotPlugin/Interfaces/IServiceLocator.cs b/src/GreenshotPlugin/Interfaces/IServiceLocator.cs similarity index 100% rename from GreenshotPlugin/Interfaces/IServiceLocator.cs rename to src/GreenshotPlugin/Interfaces/IServiceLocator.cs diff --git a/GreenshotPlugin/Interfaces/ISurface.cs b/src/GreenshotPlugin/Interfaces/ISurface.cs similarity index 100% rename from GreenshotPlugin/Interfaces/ISurface.cs rename to src/GreenshotPlugin/Interfaces/ISurface.cs diff --git a/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs b/src/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs rename to src/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs diff --git a/GreenshotPlugin/Interfaces/Ocr/Line.cs b/src/GreenshotPlugin/Interfaces/Ocr/Line.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Ocr/Line.cs rename to src/GreenshotPlugin/Interfaces/Ocr/Line.cs diff --git a/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs b/src/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs rename to src/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs diff --git a/GreenshotPlugin/Interfaces/Ocr/Word.cs b/src/GreenshotPlugin/Interfaces/Ocr/Word.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Ocr/Word.cs rename to src/GreenshotPlugin/Interfaces/Ocr/Word.cs diff --git a/GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs b/src/GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs rename to src/GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs diff --git a/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs b/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs rename to src/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs diff --git a/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs b/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs rename to src/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs diff --git a/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs b/src/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs rename to src/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs diff --git a/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs b/src/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs similarity index 100% rename from GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs rename to src/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs diff --git a/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs b/src/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs similarity index 100% rename from GreenshotPlugin/Interfaces/ScreenCaptureMode.cs rename to src/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs diff --git a/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs b/src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs similarity index 100% rename from GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs rename to src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs diff --git a/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs b/src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs similarity index 100% rename from GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs rename to src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs diff --git a/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs b/src/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs similarity index 100% rename from GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs rename to src/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs diff --git a/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs b/src/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs similarity index 100% rename from GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs rename to src/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs diff --git a/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs b/src/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs similarity index 100% rename from GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs rename to src/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs diff --git a/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs b/src/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs similarity index 100% rename from GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs rename to src/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs diff --git a/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs b/src/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs similarity index 100% rename from GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs rename to src/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs diff --git a/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs b/src/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs similarity index 100% rename from GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs rename to src/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs diff --git a/GreenshotPlugin/Interop/Base.cs b/src/GreenshotPlugin/Interop/Base.cs similarity index 100% rename from GreenshotPlugin/Interop/Base.cs rename to src/GreenshotPlugin/Interop/Base.cs diff --git a/GreenshotPlugin/Interop/COMWrapper.cs b/src/GreenshotPlugin/Interop/COMWrapper.cs similarity index 100% rename from GreenshotPlugin/Interop/COMWrapper.cs rename to src/GreenshotPlugin/Interop/COMWrapper.cs diff --git a/GreenshotPlugin/Interop/ComProgIdAttribute.cs b/src/GreenshotPlugin/Interop/ComProgIdAttribute.cs similarity index 100% rename from GreenshotPlugin/Interop/ComProgIdAttribute.cs rename to src/GreenshotPlugin/Interop/ComProgIdAttribute.cs diff --git a/GreenshotPlugin/Interop/IAppVisibility.cs b/src/GreenshotPlugin/Interop/IAppVisibility.cs similarity index 100% rename from GreenshotPlugin/Interop/IAppVisibility.cs rename to src/GreenshotPlugin/Interop/IAppVisibility.cs diff --git a/GreenshotPlugin/Interop/IDispatch.cs b/src/GreenshotPlugin/Interop/IDispatch.cs similarity index 100% rename from GreenshotPlugin/Interop/IDispatch.cs rename to src/GreenshotPlugin/Interop/IDispatch.cs diff --git a/GreenshotPlugin/Interop/IOleCommandTarget.cs b/src/GreenshotPlugin/Interop/IOleCommandTarget.cs similarity index 100% rename from GreenshotPlugin/Interop/IOleCommandTarget.cs rename to src/GreenshotPlugin/Interop/IOleCommandTarget.cs diff --git a/GreenshotPlugin/Interop/IOleWindow.cs b/src/GreenshotPlugin/Interop/IOleWindow.cs similarity index 100% rename from GreenshotPlugin/Interop/IOleWindow.cs rename to src/GreenshotPlugin/Interop/IOleWindow.cs diff --git a/GreenshotPlugin/Interop/IServiceProvider.cs b/src/GreenshotPlugin/Interop/IServiceProvider.cs similarity index 100% rename from GreenshotPlugin/Interop/IServiceProvider.cs rename to src/GreenshotPlugin/Interop/IServiceProvider.cs diff --git a/GreenshotPlugin/Interop/IUnknown.cs b/src/GreenshotPlugin/Interop/IUnknown.cs similarity index 100% rename from GreenshotPlugin/Interop/IUnknown.cs rename to src/GreenshotPlugin/Interop/IUnknown.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/DWM.cs b/src/GreenshotPlugin/UnmanagedHelpers/DWM.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/DWM.cs rename to src/GreenshotPlugin/UnmanagedHelpers/DWM.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs b/src/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs rename to src/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WinEventHookFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEventHookFlags.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WinEventHookFlags.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEventHookFlags.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs b/src/GreenshotPlugin/UnmanagedHelpers/GDI32.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/GDI32.cs rename to src/GreenshotPlugin/UnmanagedHelpers/GDI32.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs b/src/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/GDIplus.cs rename to src/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs b/src/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Kernel32.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs b/src/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/PsAPI.cs rename to src/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs b/src/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs rename to src/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs b/src/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs rename to src/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs b/src/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs rename to src/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Shell32.cs b/src/GreenshotPlugin/UnmanagedHelpers/Shell32.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Shell32.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Shell32.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/User32.cs b/src/GreenshotPlugin/UnmanagedHelpers/User32.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/User32.cs rename to src/GreenshotPlugin/UnmanagedHelpers/User32.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/Win32.cs b/src/GreenshotPlugin/UnmanagedHelpers/Win32.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/Win32.cs rename to src/GreenshotPlugin/UnmanagedHelpers/Win32.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs b/src/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs rename to src/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs diff --git a/GreenshotPlugin/UnmanagedHelpers/WinMM.cs b/src/GreenshotPlugin/UnmanagedHelpers/WinMM.cs similarity index 100% rename from GreenshotPlugin/UnmanagedHelpers/WinMM.cs rename to src/GreenshotPlugin/UnmanagedHelpers/WinMM.cs diff --git a/GreenshotPlugin/log4net-embedded.xml b/src/GreenshotPlugin/log4net-embedded.xml similarity index 100% rename from GreenshotPlugin/log4net-embedded.xml rename to src/GreenshotPlugin/log4net-embedded.xml diff --git a/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs b/src/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs similarity index 100% rename from GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs rename to src/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs diff --git a/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs b/src/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs similarity index 100% rename from GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs rename to src/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs diff --git a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj b/src/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj similarity index 100% rename from GreenshotWin10Plugin/GreenshotWin10Plugin.csproj rename to src/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj diff --git a/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs b/src/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs similarity index 100% rename from GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs rename to src/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs diff --git a/GreenshotWin10Plugin/Internal/ShareInfo.cs b/src/GreenshotWin10Plugin/Internal/ShareInfo.cs similarity index 100% rename from GreenshotWin10Plugin/Internal/ShareInfo.cs rename to src/GreenshotWin10Plugin/Internal/ShareInfo.cs diff --git a/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs b/src/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs similarity index 100% rename from GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs rename to src/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs diff --git a/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs b/src/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs similarity index 100% rename from GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs rename to src/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs diff --git a/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs b/src/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs similarity index 100% rename from GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs rename to src/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs diff --git a/GreenshotWin10Plugin/Properties/AssemblyInfo.cs b/src/GreenshotWin10Plugin/Properties/AssemblyInfo.cs similarity index 100% rename from GreenshotWin10Plugin/Properties/AssemblyInfo.cs rename to src/GreenshotWin10Plugin/Properties/AssemblyInfo.cs diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/src/GreenshotWin10Plugin/ToastNotificationService.cs similarity index 100% rename from GreenshotWin10Plugin/ToastNotificationService.cs rename to src/GreenshotWin10Plugin/ToastNotificationService.cs diff --git a/GreenshotWin10Plugin/Win10Configuration.cs b/src/GreenshotWin10Plugin/Win10Configuration.cs similarity index 100% rename from GreenshotWin10Plugin/Win10Configuration.cs rename to src/GreenshotWin10Plugin/Win10Configuration.cs diff --git a/GreenshotWin10Plugin/Win10OcrProvider.cs b/src/GreenshotWin10Plugin/Win10OcrProvider.cs similarity index 100% rename from GreenshotWin10Plugin/Win10OcrProvider.cs rename to src/GreenshotWin10Plugin/Win10OcrProvider.cs diff --git a/GreenshotWin10Plugin/Win10Plugin.cs b/src/GreenshotWin10Plugin/Win10Plugin.cs similarity index 100% rename from GreenshotWin10Plugin/Win10Plugin.cs rename to src/GreenshotWin10Plugin/Win10Plugin.cs diff --git a/src/version.json b/src/version.json new file mode 100644 index 000000000..5138f352c --- /dev/null +++ b/src/version.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "version": "1.3", + "publicReleaseRefSpec": [ + ".*/release/*$" + ], + "nugetPackageVersion": { + "semVer": 2 + }, + "cloudBuild": { + "setVersionVariables": true, + "setAllVariables": true, + "buildNumber": { + "enabled": true, + "includeCommitId": { + "when": "never" + } + } + }, + "inherit": false +} \ No newline at end of file From d25993f91e5b6c9f96cb75cf934d0b9486890264 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 27 Mar 2021 22:36:03 +0100 Subject: [PATCH 112/232] Renamed the projects --- .../Box.png | Bin .../BoxConfiguration.cs | 0 .../BoxDestination.cs | 0 .../BoxEntities.cs | 0 .../BoxPlugin.cs | 0 .../BoxPlugin.resx | 0 .../BoxUtils.cs | 0 .../Forms/BoxForm.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 .../GreenshotBoxPlugin.Credentials.template | 0 .../GreenshotBoxPlugin.csproj | 0 .../LanguageKeys.cs | 0 .../Languages/language_boxplugin-cs-CZ.xml | 0 .../Languages/language_boxplugin-de-DE.xml | 0 .../Languages/language_boxplugin-en-US.xml | 0 .../Languages/language_boxplugin-fr-FR.xml | 0 .../Languages/language_boxplugin-id-ID.xml | 0 .../Languages/language_boxplugin-it-IT.xml | 0 .../Languages/language_boxplugin-ja-JP.xml | 0 .../Languages/language_boxplugin-kab-DZ.xml | 0 .../Languages/language_boxplugin-ko-KR.xml | 0 .../Languages/language_boxplugin-lv-LV.xml | 0 .../Languages/language_boxplugin-pl-PL.xml | 0 .../Languages/language_boxplugin-pt-PT.xml | 0 .../Languages/language_boxplugin-ru-RU.xml | 0 .../Languages/language_boxplugin-sr-RS.xml | 0 .../Languages/language_boxplugin-sv-SE.xml | 0 .../Languages/language_boxplugin-uk-UA.xml | 0 .../Languages/language_boxplugin-zh-CN.xml | 0 .../Languages/language_boxplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../Confluence.cs | 0 .../ConfluenceConfiguration.cs | 0 .../ConfluenceDestination.cs | 0 .../ConfluencePlugin.cs | 0 .../ConfluenceUtils.cs | 0 .../EnumDisplayer.cs | 0 .../Forms/ConfluenceConfigurationForm.xaml | 0 .../Forms/ConfluenceConfigurationForm.xaml.cs | 0 .../Forms/ConfluencePagePicker.xaml | 0 .../Forms/ConfluencePagePicker.xaml.cs | 0 .../Forms/ConfluenceSearch.xaml | 0 .../Forms/ConfluenceSearch.xaml.cs | 0 .../Forms/ConfluenceTreePicker.xaml | 0 .../Forms/ConfluenceTreePicker.xaml.cs | 0 .../Forms/ConfluenceUpload.xaml | 0 .../Forms/ConfluenceUpload.xaml.cs | 0 .../GreenshotConfluencePlugin.csproj | 0 .../Images/Confluence.ico | Bin .../LanguageKeys.cs | 0 .../Languages/language_confluenceplugin-cs-CZ.xml | 0 .../Languages/language_confluenceplugin-de-DE.xml | 0 .../Languages/language_confluenceplugin-en-US.xml | 0 .../Languages/language_confluenceplugin-fr-FR.xml | 0 .../Languages/language_confluenceplugin-id-ID.xml | 0 .../Languages/language_confluenceplugin-it-IT.xml | 0 .../Languages/language_confluenceplugin-ja-JP.xml | 0 .../Languages/language_confluenceplugin-kab-DZ.xml | 0 .../Languages/language_confluenceplugin-ko-KR.xml | 0 .../Languages/language_confluenceplugin-lv-LV.xml | 0 .../Languages/language_confluenceplugin-nl-NL.xml | 0 .../Languages/language_confluenceplugin-pl-PL.xml | 0 .../Languages/language_confluenceplugin-pt-PT.xml | 0 .../Languages/language_confluenceplugin-ru-RU.xml | 0 .../Languages/language_confluenceplugin-sr-RS.xml | 0 .../Languages/language_confluenceplugin-sv-SE.xml | 0 .../Languages/language_confluenceplugin-uk-UA.xml | 0 .../Languages/language_confluenceplugin-zh-CN.xml | 0 .../Languages/language_confluenceplugin-zh-TW.xml | 0 .../Support/ITranslationProvider.cs | 0 .../Support/LanguageChangedEventManager.cs | 0 .../Support/LanguageXMLTranslationProvider.cs | 0 .../Support/TranslateExtension.cs | 0 .../Support/TranslationData.cs | 0 .../Support/TranslationManager.cs | 0 .../Web References/confluence/Reference.cs | 0 .../Web References/confluence/Reference.map | 0 .../confluence/confluenceservice-v1.wsdl | 0 .../Dropbox.gif | Bin .../DropboxDestination.cs | 0 .../DropboxPlugin.cs | 0 .../DropboxPlugin.resx | 0 .../DropboxPluginConfiguration.cs | 0 .../DropboxUtils.cs | 0 .../Forms/DropboxForm.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 .../GreenshotDropboxPlugin.Credentials.template | 0 .../GreenshotDropboxPlugin.csproj | 0 .../LanguageKeys.cs | 0 .../Languages/language_dropboxplugin-cs-CZ.xml | 0 .../Languages/language_dropboxplugin-de-DE.xml | 0 .../Languages/language_dropboxplugin-en-US.xml | 0 .../Languages/language_dropboxplugin-fr-FR.xml | 0 .../Languages/language_dropboxplugin-id-ID.xml | 0 .../Languages/language_dropboxplugin-it-IT.xml | 0 .../Languages/language_dropboxplugin-ja-JP.xml | 0 .../Languages/language_dropboxplugin-kab-DZ.xml | 0 .../Languages/language_dropboxplugin-ko-KR.xml | 0 .../Languages/language_dropboxplugin-lv-LV.xml | 0 .../Languages/language_dropboxplugin-pl-PL.xml | 0 .../Languages/language_dropboxplugin-pt-PT.xml | 0 .../Languages/language_dropboxplugin-ru-RU.xml | 0 .../Languages/language_dropboxplugin-sr-RS.xml | 0 .../Languages/language_dropboxplugin-sv-SE.xml | 0 .../Languages/language_dropboxplugin-uk-UA.xml | 0 .../Languages/language_dropboxplugin-zh-CN.xml | 0 .../Languages/language_dropboxplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../ExternalCommandConfiguration.cs | 0 .../ExternalCommandDestination.cs | 0 .../ExternalCommandForm.cs | 0 .../ExternalCommandPlugin.cs | 0 .../GreenshotExternalCommandPlugin.csproj | 0 .../IconCache.cs | 0 .../language_externalcommandplugin-cs-CZ.xml | 0 .../language_externalcommandplugin-de-DE.xml | 0 .../language_externalcommandplugin-en-US.xml | 0 .../language_externalcommandplugin-fr-FR.xml | 0 .../language_externalcommandplugin-id-ID.xml | 0 .../language_externalcommandplugin-it-IT.xml | 0 .../language_externalcommandplugin-ja-JP.xml | 0 .../language_externalcommandplugin-kab-DZ.xml | 0 .../language_externalcommandplugin-ko-KR.xml | 0 .../language_externalcommandplugin-lv-LV.xml | 0 .../language_externalcommandplugin-pl-PL.xml | 0 .../language_externalcommandplugin-pt-PT.xml | 0 .../language_externalcommandplugin-ru-RU.xml | 0 .../language_externalcommandplugin-sk-SK.xml | 0 .../language_externalcommandplugin-sr-RS.xml | 0 .../language_externalcommandplugin-sv-SE.xml | 0 .../language_externalcommandplugin-uk-UA.xml | 0 .../language_externalcommandplugin-zh-CN.xml | 0 .../language_externalcommandplugin-zh-TW.xml | 0 .../SettingsForm.Designer.cs | 0 .../SettingsForm.cs | 0 .../SettingsFormDetail.Designer.cs | 0 .../SettingsFormDetail.cs | 0 .../FlickrConfiguration.cs | 0 .../FlickrDestination.cs | 0 .../FlickrPlugin.cs | 0 .../FlickrPlugin.resx | 0 .../FlickrUtils.cs | 0 .../Forms/FlickrForm.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 .../GreenshotFlickrPlugin.Credentials.template | 0 .../GreenshotFlickrPlugin.csproj | 0 .../LanguageKeys.cs | 0 .../Languages/language_flickrplugin-cs-CZ.xml | 0 .../Languages/language_flickrplugin-de-DE.xml | 0 .../Languages/language_flickrplugin-en-US.xml | 0 .../Languages/language_flickrplugin-fr-FR.xml | 0 .../Languages/language_flickrplugin-id-ID.xml | 0 .../Languages/language_flickrplugin-it-IT.xml | 0 .../Languages/language_flickrplugin-ja-JP.xml | 0 .../Languages/language_flickrplugin-kab-DZ.xml | 0 .../Languages/language_flickrplugin-ko-KR.xml | 0 .../Languages/language_flickrplugin-lv-LV.xml | 0 .../Languages/language_flickrplugin-pl-PL.xml | 0 .../Languages/language_flickrplugin-pt-PT.xml | 0 .../Languages/language_flickrplugin-ru-RU.xml | 0 .../Languages/language_flickrplugin-sr-RS.xml | 0 .../Languages/language_flickrplugin-sv-SE.xml | 0 .../Languages/language_flickrplugin-uk-UA.xml | 0 .../Languages/language_flickrplugin-zh-CN.xml | 0 .../Languages/language_flickrplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../flickr.png | Bin .../Forms/GooglePhotosForm.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 .../GooglePhotos.png | Bin .../GooglePhotosConfiguration.cs | 0 .../GooglePhotosDestination.cs | 0 .../GooglePhotosPlugin.cs | 0 .../GooglePhotosPlugin.resx | 0 .../GooglePhotosUtils.cs | 0 ...GreenshotGooglePhotosPlugin.Credentials.template | 0 .../GreenshotGooglePhotosPlugin.csproj | 0 .../LanguageKeys.cs | 0 .../Languages/language_googlephotosplugin-cs-CZ.xml | 0 .../Languages/language_googlephotosplugin-de-DE.xml | 0 .../Languages/language_googlephotosplugin-en-US.xml | 0 .../Languages/language_googlephotosplugin-fr-FR.xml | 0 .../Languages/language_googlephotosplugin-id-ID.xml | 0 .../Languages/language_googlephotosplugin-it-IT.xml | 0 .../Languages/language_googlephotosplugin-ja-JP.xml | 0 .../language_googlephotosplugin-kab-DZ.xml | 0 .../Languages/language_googlephotosplugin-ko-KR.xml | 0 .../Languages/language_googlephotosplugin-lv-LV.xml | 0 .../Languages/language_googlephotosplugin-pl-PL.xml | 0 .../Languages/language_googlephotosplugin-pt-PT.xml | 0 .../Languages/language_googlephotosplugin-ru-RU.xml | 0 .../Languages/language_googlephotosplugin-sr-RS.xml | 0 .../Languages/language_googlephotosplugin-sv-SE.xml | 0 .../Languages/language_googlephotosplugin-uk-UA.xml | 0 .../Languages/language_googlephotosplugin-zh-CN.xml | 0 .../Languages/language_googlephotosplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../README | 0 .../Forms/ImgurForm.cs | 0 .../Forms/ImgurHistory.Designer.cs | 0 .../Forms/ImgurHistory.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 .../GreenshotImgurPlugin.Credentials.template | 0 .../GreenshotImgurPlugin.csproj | 0 .../ImgurConfiguration.cs | 0 .../ImgurDestination.cs | 0 .../ImgurInfo.cs | 0 .../ImgurPlugin.cs | 0 .../ImgurPlugin.resx | 0 .../ImgurUtils.cs | 0 .../LanguageKeys.cs | 0 .../Languages/language_imgurplugin-cs-CZ.xml | 0 .../Languages/language_imgurplugin-de-DE.xml | 0 .../Languages/language_imgurplugin-en-US.xml | 0 .../Languages/language_imgurplugin-fr-FR.xml | 0 .../Languages/language_imgurplugin-id-ID.xml | 0 .../Languages/language_imgurplugin-it-IT.xml | 0 .../Languages/language_imgurplugin-ja-JP.xml | 0 .../Languages/language_imgurplugin-kab-DZ.xml | 0 .../Languages/language_imgurplugin-ko-KR.xml | 0 .../Languages/language_imgurplugin-lv-LV.xml | 0 .../Languages/language_imgurplugin-nl-NL.xml | 0 .../Languages/language_imgurplugin-pl-PL.xml | 0 .../Languages/language_imgurplugin-pt-PT.xml | 0 .../Languages/language_imgurplugin-ru-RU.xml | 0 .../Languages/language_imgurplugin-sk-SK.xml | 0 .../Languages/language_imgurplugin-sr-RS.xml | 0 .../Languages/language_imgurplugin-sv-SE.xml | 0 .../Languages/language_imgurplugin-uk-UA.xml | 0 .../Languages/language_imgurplugin-zh-CN.xml | 0 .../Languages/language_imgurplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 0 .../AsyncMemoryCache.cs | 0 .../Forms/JiraForm.Designer.cs | 0 .../Forms/JiraForm.cs | 0 .../Forms/JiraFormBase.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 .../GreenshotJiraPlugin.csproj | 0 .../IssueTypeBitmapCache.cs | 0 .../JiraConfiguration.cs | 0 .../JiraConnector.cs | 0 .../JiraDestination.cs | 0 .../JiraDetails.cs | 0 .../JiraEventArgs.cs | 0 .../JiraEventTypes.cs | 0 .../JiraMonitor.cs | 0 .../JiraPlugin.cs | 0 .../JiraPlugin.resx | 0 .../LanguageKeys.cs | 0 .../Languages/language_jiraplugin-cs-CZ.xml | 0 .../Languages/language_jiraplugin-de-DE.xml | 0 .../Languages/language_jiraplugin-en-US.xml | 0 .../Languages/language_jiraplugin-fr-FR.xml | 0 .../Languages/language_jiraplugin-id-ID.xml | 0 .../Languages/language_jiraplugin-it-IT.xml | 0 .../Languages/language_jiraplugin-ja-JP.xml | 0 .../Languages/language_jiraplugin-kab-DZ.xml | 0 .../Languages/language_jiraplugin-ko-KR.xml | 0 .../Languages/language_jiraplugin-lv-LV.xml | 0 .../Languages/language_jiraplugin-nl-NL.xml | 0 .../Languages/language_jiraplugin-pl-PL.xml | 0 .../Languages/language_jiraplugin-pt-PT.xml | 0 .../Languages/language_jiraplugin-ru-RU.xml | 0 .../Languages/language_jiraplugin-sr-RS.xml | 0 .../Languages/language_jiraplugin-sv-SE.xml | 0 .../Languages/language_jiraplugin-uk-UA.xml | 0 .../Languages/language_jiraplugin-zh-CN.xml | 0 .../Languages/language_jiraplugin-zh-TW.xml | 0 .../Log4NetLogger.cs | 0 .../Com/DisposableCom.cs | 0 .../Com/DisposableComImplementation.cs | 0 .../Com/IDisposableCom.cs | 0 .../Com/Ole32Api.cs | 0 .../Com/OleAut32Api.cs | 0 .../Destinations/ExcelDestination.cs | 0 .../Destinations/OneNoteDestination.cs | 0 .../Destinations/OutlookDestination.cs | 0 .../Destinations/PowerpointDestination.cs | 0 .../Destinations/WordDestination.cs | 0 .../GlobalSuppressions.cs | Bin .../GreenshotOfficePlugin.csproj | 0 .../Languages/language_officeplugin-fr-FR.ini | 0 .../OfficeConfiguration.cs | 0 .../OfficeExport/Entities/OneNoteNotebook.cs | 0 .../OfficeExport/Entities/OneNotePage.cs | 0 .../OfficeExport/Entities/OneNoteSection.cs | 0 .../OfficeExport/ExcelExporter.cs | 0 .../OfficeExport/OneNoteExporter.cs | 0 .../OfficeExport/OutlookEmailExporter.cs | 0 .../OfficeExport/PowerpointExporter.cs | 0 .../OfficeExport/WordExporter.cs | 0 .../OfficeInterop/EmailFormat.cs | 0 .../OfficeInterop/OfficeVersions.cs | 0 .../OfficePlugin.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../Forms/PhotobucketForm.cs | 0 .../Forms/SettingsForm.Designer.cs | 0 .../Forms/SettingsForm.cs | 0 .../GreenshotPhotobucketPlugin.Credentials.template | 0 .../GreenshotPhotobucketPlugin.csproj | 0 .../LanguageKeys.cs | 0 .../Languages/language_photobucketplugin-cs-CZ.xml | 0 .../Languages/language_photobucketplugin-de-DE.xml | 0 .../Languages/language_photobucketplugin-en-US.xml | 0 .../Languages/language_photobucketplugin-fr_FR.xml | 0 .../Languages/language_photobucketplugin-id-ID.xml | 0 .../Languages/language_photobucketplugin-it-IT.xml | 0 .../Languages/language_photobucketplugin-ja-JP.xml | 0 .../Languages/language_photobucketplugin-kab-DZ.xml | 0 .../Languages/language_photobucketplugin-ko-KR.xml | 0 .../Languages/language_photobucketplugin-lv-LV.xml | 0 .../Languages/language_photobucketplugin-nl-NL.xml | 0 .../Languages/language_photobucketplugin-pl-PL.xml | 0 .../Languages/language_photobucketplugin-pt-PT.xml | 0 .../Languages/language_photobucketplugin-ru-RU.xml | 0 .../Languages/language_photobucketplugin-sv-SE.xml | 0 .../Languages/language_photobucketplugin-uk-UA.xml | 0 .../Languages/language_photobucketplugin-zh-CN.xml | 0 .../Languages/language_photobucketplugin-zh-TW.xml | 0 .../PhotobucketConfiguration.cs | 0 .../PhotobucketDestination.cs | 0 .../PhotobucketInfo.cs | 0 .../PhotobucketPlugin.cs | 0 .../PhotobucketPlugin.resx | 0 .../PhotobucketUtils.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../Destinations/Win10OcrDestination.cs | 0 .../Destinations/Win10ShareDestination.cs | 0 .../GreenshotWin10Plugin.csproj | 0 .../Internal/MemoryRandomAccessStream.cs | 0 .../Internal/ShareInfo.cs | 0 .../Native/DataTransferManagerHelper.cs | 0 .../Native/IDataTransferManagerInterOp.cs | 0 .../Processors/Win10OcrProcessor.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../ToastNotificationService.cs | 0 .../Win10Configuration.cs | 0 .../Win10OcrProvider.cs | 0 .../Win10Plugin.cs | 0 345 files changed, 0 insertions(+), 0 deletions(-) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Box.png (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/BoxConfiguration.cs (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/BoxDestination.cs (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/BoxEntities.cs (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/BoxPlugin.cs (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/BoxPlugin.resx (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/BoxUtils.cs (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Forms/BoxForm.cs (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Forms/SettingsForm.Designer.cs (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Forms/SettingsForm.cs (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/GreenshotBoxPlugin.Credentials.template (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/GreenshotBoxPlugin.csproj (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/LanguageKeys.cs (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-cs-CZ.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-de-DE.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-en-US.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-fr-FR.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-id-ID.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-it-IT.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-ja-JP.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-kab-DZ.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-ko-KR.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-lv-LV.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-pl-PL.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-pt-PT.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-ru-RU.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-sr-RS.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-sv-SE.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-uk-UA.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-zh-CN.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Languages/language_boxplugin-zh-TW.xml (100%) rename src/{GreenshotBoxPlugin => Greenshot.Plugin.Box}/Properties/AssemblyInfo.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Confluence.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/ConfluenceConfiguration.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/ConfluenceDestination.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/ConfluencePlugin.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/ConfluenceUtils.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/EnumDisplayer.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Forms/ConfluenceConfigurationForm.xaml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Forms/ConfluenceConfigurationForm.xaml.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Forms/ConfluencePagePicker.xaml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Forms/ConfluencePagePicker.xaml.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Forms/ConfluenceSearch.xaml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Forms/ConfluenceSearch.xaml.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Forms/ConfluenceTreePicker.xaml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Forms/ConfluenceTreePicker.xaml.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Forms/ConfluenceUpload.xaml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Forms/ConfluenceUpload.xaml.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/GreenshotConfluencePlugin.csproj (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Images/Confluence.ico (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/LanguageKeys.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-cs-CZ.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-de-DE.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-en-US.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-fr-FR.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-id-ID.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-it-IT.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-ja-JP.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-kab-DZ.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-ko-KR.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-lv-LV.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-nl-NL.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-pl-PL.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-pt-PT.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-ru-RU.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-sr-RS.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-sv-SE.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-uk-UA.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-zh-CN.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-zh-TW.xml (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Support/ITranslationProvider.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Support/LanguageChangedEventManager.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Support/LanguageXMLTranslationProvider.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Support/TranslateExtension.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Support/TranslationData.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Support/TranslationManager.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Web References/confluence/Reference.cs (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Web References/confluence/Reference.map (100%) rename src/{GreenshotConfluencePlugin => Greenshot.Plugin.Confluence}/Web References/confluence/confluenceservice-v1.wsdl (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Dropbox.gif (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/DropboxDestination.cs (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/DropboxPlugin.cs (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/DropboxPlugin.resx (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/DropboxPluginConfiguration.cs (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/DropboxUtils.cs (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Forms/DropboxForm.cs (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Forms/SettingsForm.Designer.cs (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Forms/SettingsForm.cs (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/GreenshotDropboxPlugin.Credentials.template (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/GreenshotDropboxPlugin.csproj (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/LanguageKeys.cs (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-cs-CZ.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-de-DE.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-en-US.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-fr-FR.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-id-ID.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-it-IT.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-ja-JP.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-kab-DZ.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-ko-KR.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-lv-LV.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-pl-PL.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-pt-PT.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-ru-RU.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-sr-RS.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-sv-SE.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-uk-UA.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-zh-CN.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-zh-TW.xml (100%) rename src/{GreenshotDropboxPlugin => Greenshot.Plugin.Dropbox}/Properties/AssemblyInfo.cs (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/ExternalCommandConfiguration.cs (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/ExternalCommandDestination.cs (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/ExternalCommandForm.cs (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/ExternalCommandPlugin.cs (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/GreenshotExternalCommandPlugin.csproj (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/IconCache.cs (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-cs-CZ.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-de-DE.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-en-US.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-fr-FR.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-id-ID.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-it-IT.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-ja-JP.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-kab-DZ.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-ko-KR.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-lv-LV.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-pl-PL.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-pt-PT.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-ru-RU.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-sk-SK.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-sr-RS.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-sv-SE.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-uk-UA.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-zh-CN.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-zh-TW.xml (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/SettingsForm.Designer.cs (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/SettingsForm.cs (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/SettingsFormDetail.Designer.cs (100%) rename src/{GreenshotExternalCommandPlugin => Greenshot.Plugin.ExternalCommand}/SettingsFormDetail.cs (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/FlickrConfiguration.cs (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/FlickrDestination.cs (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/FlickrPlugin.cs (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/FlickrPlugin.resx (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/FlickrUtils.cs (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Forms/FlickrForm.cs (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Forms/SettingsForm.Designer.cs (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Forms/SettingsForm.cs (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/GreenshotFlickrPlugin.Credentials.template (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/GreenshotFlickrPlugin.csproj (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/LanguageKeys.cs (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-cs-CZ.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-de-DE.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-en-US.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-fr-FR.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-id-ID.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-it-IT.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-ja-JP.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-kab-DZ.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-ko-KR.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-lv-LV.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-pl-PL.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-pt-PT.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-ru-RU.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-sr-RS.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-sv-SE.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-uk-UA.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-zh-CN.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-zh-TW.xml (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/Properties/AssemblyInfo.cs (100%) rename src/{GreenshotFlickrPlugin => Greenshot.Plugin.Flickr}/flickr.png (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Forms/GooglePhotosForm.cs (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Forms/SettingsForm.Designer.cs (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Forms/SettingsForm.cs (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/GooglePhotos.png (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/GooglePhotosConfiguration.cs (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/GooglePhotosDestination.cs (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/GooglePhotosPlugin.cs (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/GooglePhotosPlugin.resx (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/GooglePhotosUtils.cs (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/GreenshotGooglePhotosPlugin.Credentials.template (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/GreenshotGooglePhotosPlugin.csproj (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/LanguageKeys.cs (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-cs-CZ.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-de-DE.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-en-US.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-fr-FR.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-id-ID.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-it-IT.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-ja-JP.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-kab-DZ.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-ko-KR.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-lv-LV.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-pl-PL.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-pt-PT.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-ru-RU.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-sr-RS.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-sv-SE.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-uk-UA.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-zh-CN.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-zh-TW.xml (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/Properties/AssemblyInfo.cs (100%) rename src/{GreenshotGooglePhotosPlugin => Greenshot.Plugin.GooglePhotos}/README (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Forms/ImgurForm.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Forms/ImgurHistory.Designer.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Forms/ImgurHistory.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Forms/SettingsForm.Designer.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Forms/SettingsForm.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/GreenshotImgurPlugin.Credentials.template (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/GreenshotImgurPlugin.csproj (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/ImgurConfiguration.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/ImgurDestination.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/ImgurInfo.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/ImgurPlugin.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/ImgurPlugin.resx (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/ImgurUtils.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/LanguageKeys.cs (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-cs-CZ.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-de-DE.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-en-US.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-fr-FR.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-id-ID.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-it-IT.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-ja-JP.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-kab-DZ.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-ko-KR.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-lv-LV.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-nl-NL.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-pl-PL.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-pt-PT.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-ru-RU.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-sk-SK.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-sr-RS.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-sv-SE.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-uk-UA.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-zh-CN.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-zh-TW.xml (100%) rename src/{GreenshotImgurPlugin => Greenshot.Plugin.Imgur}/Properties/AssemblyInfo.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/AsyncMemoryCache.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Forms/JiraForm.Designer.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Forms/JiraForm.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Forms/JiraFormBase.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Forms/SettingsForm.Designer.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Forms/SettingsForm.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/GreenshotJiraPlugin.csproj (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/IssueTypeBitmapCache.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/JiraConfiguration.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/JiraConnector.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/JiraDestination.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/JiraDetails.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/JiraEventArgs.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/JiraEventTypes.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/JiraMonitor.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/JiraPlugin.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/JiraPlugin.resx (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/LanguageKeys.cs (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-cs-CZ.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-de-DE.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-en-US.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-fr-FR.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-id-ID.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-it-IT.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-ja-JP.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-kab-DZ.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-ko-KR.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-lv-LV.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-nl-NL.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-pl-PL.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-pt-PT.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-ru-RU.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-sr-RS.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-sv-SE.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-uk-UA.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-zh-CN.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Languages/language_jiraplugin-zh-TW.xml (100%) rename src/{GreenshotJiraPlugin => Greenshot.Plugin.Jira}/Log4NetLogger.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Com/DisposableCom.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Com/DisposableComImplementation.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Com/IDisposableCom.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Com/Ole32Api.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Com/OleAut32Api.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Destinations/ExcelDestination.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Destinations/OneNoteDestination.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Destinations/OutlookDestination.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Destinations/PowerpointDestination.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Destinations/WordDestination.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/GlobalSuppressions.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/GreenshotOfficePlugin.csproj (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Languages/language_officeplugin-fr-FR.ini (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeConfiguration.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeExport/Entities/OneNoteNotebook.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeExport/Entities/OneNotePage.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeExport/Entities/OneNoteSection.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeExport/ExcelExporter.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeExport/OneNoteExporter.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeExport/OutlookEmailExporter.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeExport/PowerpointExporter.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeExport/WordExporter.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeInterop/EmailFormat.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficeInterop/OfficeVersions.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/OfficePlugin.cs (100%) rename src/{GreenshotOfficePlugin => Greenshot.Plugin.Office}/Properties/AssemblyInfo.cs (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Forms/PhotobucketForm.cs (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Forms/SettingsForm.Designer.cs (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Forms/SettingsForm.cs (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/GreenshotPhotobucketPlugin.Credentials.template (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/GreenshotPhotobucketPlugin.csproj (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/LanguageKeys.cs (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-cs-CZ.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-de-DE.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-en-US.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-fr_FR.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-id-ID.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-it-IT.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-ja-JP.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-kab-DZ.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-ko-KR.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-lv-LV.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-nl-NL.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-pl-PL.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-pt-PT.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-ru-RU.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-sv-SE.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-uk-UA.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-zh-CN.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-zh-TW.xml (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/PhotobucketConfiguration.cs (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/PhotobucketDestination.cs (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/PhotobucketInfo.cs (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/PhotobucketPlugin.cs (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/PhotobucketPlugin.resx (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/PhotobucketUtils.cs (100%) rename src/{GreenshotPhotobucketPlugin => Greenshot.Plugin.Photobucket}/Properties/AssemblyInfo.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Destinations/Win10OcrDestination.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Destinations/Win10ShareDestination.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/GreenshotWin10Plugin.csproj (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Internal/MemoryRandomAccessStream.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Internal/ShareInfo.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Native/DataTransferManagerHelper.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Native/IDataTransferManagerInterOp.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Processors/Win10OcrProcessor.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Properties/AssemblyInfo.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/ToastNotificationService.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Win10Configuration.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Win10OcrProvider.cs (100%) rename src/{GreenshotWin10Plugin => Greenshot.Plugin.Win10}/Win10Plugin.cs (100%) diff --git a/src/GreenshotBoxPlugin/Box.png b/src/Greenshot.Plugin.Box/Box.png similarity index 100% rename from src/GreenshotBoxPlugin/Box.png rename to src/Greenshot.Plugin.Box/Box.png diff --git a/src/GreenshotBoxPlugin/BoxConfiguration.cs b/src/Greenshot.Plugin.Box/BoxConfiguration.cs similarity index 100% rename from src/GreenshotBoxPlugin/BoxConfiguration.cs rename to src/Greenshot.Plugin.Box/BoxConfiguration.cs diff --git a/src/GreenshotBoxPlugin/BoxDestination.cs b/src/Greenshot.Plugin.Box/BoxDestination.cs similarity index 100% rename from src/GreenshotBoxPlugin/BoxDestination.cs rename to src/Greenshot.Plugin.Box/BoxDestination.cs diff --git a/src/GreenshotBoxPlugin/BoxEntities.cs b/src/Greenshot.Plugin.Box/BoxEntities.cs similarity index 100% rename from src/GreenshotBoxPlugin/BoxEntities.cs rename to src/Greenshot.Plugin.Box/BoxEntities.cs diff --git a/src/GreenshotBoxPlugin/BoxPlugin.cs b/src/Greenshot.Plugin.Box/BoxPlugin.cs similarity index 100% rename from src/GreenshotBoxPlugin/BoxPlugin.cs rename to src/Greenshot.Plugin.Box/BoxPlugin.cs diff --git a/src/GreenshotBoxPlugin/BoxPlugin.resx b/src/Greenshot.Plugin.Box/BoxPlugin.resx similarity index 100% rename from src/GreenshotBoxPlugin/BoxPlugin.resx rename to src/Greenshot.Plugin.Box/BoxPlugin.resx diff --git a/src/GreenshotBoxPlugin/BoxUtils.cs b/src/Greenshot.Plugin.Box/BoxUtils.cs similarity index 100% rename from src/GreenshotBoxPlugin/BoxUtils.cs rename to src/Greenshot.Plugin.Box/BoxUtils.cs diff --git a/src/GreenshotBoxPlugin/Forms/BoxForm.cs b/src/Greenshot.Plugin.Box/Forms/BoxForm.cs similarity index 100% rename from src/GreenshotBoxPlugin/Forms/BoxForm.cs rename to src/Greenshot.Plugin.Box/Forms/BoxForm.cs diff --git a/src/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs similarity index 100% rename from src/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs diff --git a/src/GreenshotBoxPlugin/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs similarity index 100% rename from src/GreenshotBoxPlugin/Forms/SettingsForm.cs rename to src/Greenshot.Plugin.Box/Forms/SettingsForm.cs diff --git a/src/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template b/src/Greenshot.Plugin.Box/GreenshotBoxPlugin.Credentials.template similarity index 100% rename from src/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template rename to src/Greenshot.Plugin.Box/GreenshotBoxPlugin.Credentials.template diff --git a/src/GreenshotBoxPlugin/GreenshotBoxPlugin.csproj b/src/Greenshot.Plugin.Box/GreenshotBoxPlugin.csproj similarity index 100% rename from src/GreenshotBoxPlugin/GreenshotBoxPlugin.csproj rename to src/Greenshot.Plugin.Box/GreenshotBoxPlugin.csproj diff --git a/src/GreenshotBoxPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Box/LanguageKeys.cs similarity index 100% rename from src/GreenshotBoxPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Box/LanguageKeys.cs diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-cs-CZ.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-cs-CZ.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-cs-CZ.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-de-DE.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-de-DE.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-de-DE.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-de-DE.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-en-US.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-en-US.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-en-US.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-en-US.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-fr-FR.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-fr-FR.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-fr-FR.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-fr-FR.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-id-ID.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-id-ID.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-id-ID.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-id-ID.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-it-IT.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-it-IT.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-ja-JP.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-ja-JP.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-ja-JP.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-ja-JP.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-kab-DZ.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-kab-DZ.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-kab-DZ.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-ko-KR.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-ko-KR.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-ko-KR.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-ko-KR.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-lv-LV.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-lv-LV.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-lv-LV.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-lv-LV.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-pl-PL.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-pl-PL.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-pl-PL.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-pl-PL.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-pt-PT.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-pt-PT.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-pt-PT.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-pt-PT.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-ru-RU.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-ru-RU.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-ru-RU.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-ru-RU.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-sr-RS.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-sr-RS.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-sr-RS.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-sr-RS.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-sv-SE.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-sv-SE.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-sv-SE.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-sv-SE.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-uk-UA.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-uk-UA.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-uk-UA.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-uk-UA.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-zh-CN.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-zh-CN.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-zh-CN.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-zh-CN.xml diff --git a/src/GreenshotBoxPlugin/Languages/language_boxplugin-zh-TW.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-zh-TW.xml similarity index 100% rename from src/GreenshotBoxPlugin/Languages/language_boxplugin-zh-TW.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-zh-TW.xml diff --git a/src/GreenshotBoxPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs similarity index 100% rename from src/GreenshotBoxPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs diff --git a/src/GreenshotConfluencePlugin/Confluence.cs b/src/Greenshot.Plugin.Confluence/Confluence.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Confluence.cs rename to src/Greenshot.Plugin.Confluence/Confluence.cs diff --git a/src/GreenshotConfluencePlugin/ConfluenceConfiguration.cs b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs similarity index 100% rename from src/GreenshotConfluencePlugin/ConfluenceConfiguration.cs rename to src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs diff --git a/src/GreenshotConfluencePlugin/ConfluenceDestination.cs b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs similarity index 100% rename from src/GreenshotConfluencePlugin/ConfluenceDestination.cs rename to src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs diff --git a/src/GreenshotConfluencePlugin/ConfluencePlugin.cs b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs similarity index 100% rename from src/GreenshotConfluencePlugin/ConfluencePlugin.cs rename to src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs diff --git a/src/GreenshotConfluencePlugin/ConfluenceUtils.cs b/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs similarity index 100% rename from src/GreenshotConfluencePlugin/ConfluenceUtils.cs rename to src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs diff --git a/src/GreenshotConfluencePlugin/EnumDisplayer.cs b/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs similarity index 100% rename from src/GreenshotConfluencePlugin/EnumDisplayer.cs rename to src/Greenshot.Plugin.Confluence/EnumDisplayer.cs diff --git a/src/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml similarity index 100% rename from src/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml diff --git a/src/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs diff --git a/src/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml similarity index 100% rename from src/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml rename to src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml diff --git a/src/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs rename to src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs diff --git a/src/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml similarity index 100% rename from src/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml diff --git a/src/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs diff --git a/src/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml similarity index 100% rename from src/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml diff --git a/src/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml.cs diff --git a/src/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml similarity index 100% rename from src/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml diff --git a/src/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs diff --git a/src/GreenshotConfluencePlugin/GreenshotConfluencePlugin.csproj b/src/Greenshot.Plugin.Confluence/GreenshotConfluencePlugin.csproj similarity index 100% rename from src/GreenshotConfluencePlugin/GreenshotConfluencePlugin.csproj rename to src/Greenshot.Plugin.Confluence/GreenshotConfluencePlugin.csproj diff --git a/src/GreenshotConfluencePlugin/Images/Confluence.ico b/src/Greenshot.Plugin.Confluence/Images/Confluence.ico similarity index 100% rename from src/GreenshotConfluencePlugin/Images/Confluence.ico rename to src/Greenshot.Plugin.Confluence/Images/Confluence.ico diff --git a/src/GreenshotConfluencePlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Confluence/LanguageKeys.cs similarity index 100% rename from src/GreenshotConfluencePlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Confluence/LanguageKeys.cs diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-cs-CZ.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-cs-CZ.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-cs-CZ.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-de-DE.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-de-DE.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-de-DE.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-de-DE.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-en-US.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-en-US.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-en-US.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-en-US.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-fr-FR.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-fr-FR.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-fr-FR.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-fr-FR.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-id-ID.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-id-ID.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-id-ID.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-id-ID.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-it-IT.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-it-IT.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ja-JP.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ja-JP.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ja-JP.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ja-JP.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-kab-DZ.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-kab-DZ.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-kab-DZ.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ko-KR.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ko-KR.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ko-KR.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ko-KR.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-lv-LV.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-lv-LV.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-lv-LV.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-lv-LV.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-nl-NL.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-nl-NL.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-nl-NL.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-nl-NL.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pl-PL.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-pl-PL.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pl-PL.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-pl-PL.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pt-PT.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-pt-PT.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pt-PT.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-pt-PT.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ru-RU.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ru-RU.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ru-RU.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ru-RU.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sr-RS.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-sr-RS.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sr-RS.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-sr-RS.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sv-SE.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-sv-SE.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sv-SE.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-sv-SE.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-uk-UA.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-uk-UA.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-uk-UA.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-uk-UA.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-CN.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-zh-CN.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-CN.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-zh-CN.xml diff --git a/src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-TW.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-zh-TW.xml similarity index 100% rename from src/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-TW.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-zh-TW.xml diff --git a/src/GreenshotConfluencePlugin/Support/ITranslationProvider.cs b/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Support/ITranslationProvider.cs rename to src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs diff --git a/src/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs b/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs rename to src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs diff --git a/src/GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs b/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs rename to src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs diff --git a/src/GreenshotConfluencePlugin/Support/TranslateExtension.cs b/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Support/TranslateExtension.cs rename to src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs diff --git a/src/GreenshotConfluencePlugin/Support/TranslationData.cs b/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Support/TranslationData.cs rename to src/Greenshot.Plugin.Confluence/Support/TranslationData.cs diff --git a/src/GreenshotConfluencePlugin/Support/TranslationManager.cs b/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Support/TranslationManager.cs rename to src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs diff --git a/src/GreenshotConfluencePlugin/Web References/confluence/Reference.cs b/src/Greenshot.Plugin.Confluence/Web References/confluence/Reference.cs similarity index 100% rename from src/GreenshotConfluencePlugin/Web References/confluence/Reference.cs rename to src/Greenshot.Plugin.Confluence/Web References/confluence/Reference.cs diff --git a/src/GreenshotConfluencePlugin/Web References/confluence/Reference.map b/src/Greenshot.Plugin.Confluence/Web References/confluence/Reference.map similarity index 100% rename from src/GreenshotConfluencePlugin/Web References/confluence/Reference.map rename to src/Greenshot.Plugin.Confluence/Web References/confluence/Reference.map diff --git a/src/GreenshotConfluencePlugin/Web References/confluence/confluenceservice-v1.wsdl b/src/Greenshot.Plugin.Confluence/Web References/confluence/confluenceservice-v1.wsdl similarity index 100% rename from src/GreenshotConfluencePlugin/Web References/confluence/confluenceservice-v1.wsdl rename to src/Greenshot.Plugin.Confluence/Web References/confluence/confluenceservice-v1.wsdl diff --git a/src/GreenshotDropboxPlugin/Dropbox.gif b/src/Greenshot.Plugin.Dropbox/Dropbox.gif similarity index 100% rename from src/GreenshotDropboxPlugin/Dropbox.gif rename to src/Greenshot.Plugin.Dropbox/Dropbox.gif diff --git a/src/GreenshotDropboxPlugin/DropboxDestination.cs b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs similarity index 100% rename from src/GreenshotDropboxPlugin/DropboxDestination.cs rename to src/Greenshot.Plugin.Dropbox/DropboxDestination.cs diff --git a/src/GreenshotDropboxPlugin/DropboxPlugin.cs b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs similarity index 100% rename from src/GreenshotDropboxPlugin/DropboxPlugin.cs rename to src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs diff --git a/src/GreenshotDropboxPlugin/DropboxPlugin.resx b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.resx similarity index 100% rename from src/GreenshotDropboxPlugin/DropboxPlugin.resx rename to src/Greenshot.Plugin.Dropbox/DropboxPlugin.resx diff --git a/src/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs b/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs similarity index 100% rename from src/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs rename to src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs diff --git a/src/GreenshotDropboxPlugin/DropboxUtils.cs b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs similarity index 100% rename from src/GreenshotDropboxPlugin/DropboxUtils.cs rename to src/Greenshot.Plugin.Dropbox/DropboxUtils.cs diff --git a/src/GreenshotDropboxPlugin/Forms/DropboxForm.cs b/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs similarity index 100% rename from src/GreenshotDropboxPlugin/Forms/DropboxForm.cs rename to src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs diff --git a/src/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs similarity index 100% rename from src/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs diff --git a/src/GreenshotDropboxPlugin/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs similarity index 100% rename from src/GreenshotDropboxPlugin/Forms/SettingsForm.cs rename to src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs diff --git a/src/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template b/src/Greenshot.Plugin.Dropbox/GreenshotDropboxPlugin.Credentials.template similarity index 100% rename from src/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template rename to src/Greenshot.Plugin.Dropbox/GreenshotDropboxPlugin.Credentials.template diff --git a/src/GreenshotDropboxPlugin/GreenshotDropboxPlugin.csproj b/src/Greenshot.Plugin.Dropbox/GreenshotDropboxPlugin.csproj similarity index 100% rename from src/GreenshotDropboxPlugin/GreenshotDropboxPlugin.csproj rename to src/Greenshot.Plugin.Dropbox/GreenshotDropboxPlugin.csproj diff --git a/src/GreenshotDropboxPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs similarity index 100% rename from src/GreenshotDropboxPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Dropbox/LanguageKeys.cs diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-cs-CZ.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-cs-CZ.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-cs-CZ.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-de-DE.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-de-DE.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-de-DE.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-de-DE.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-en-US.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-en-US.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-en-US.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-en-US.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-fr-FR.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-fr-FR.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-fr-FR.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-fr-FR.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-id-ID.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-id-ID.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-id-ID.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-id-ID.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-it-IT.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-it-IT.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ja-JP.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ja-JP.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ja-JP.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ja-JP.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-kab-DZ.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-kab-DZ.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-kab-DZ.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ko-KR.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ko-KR.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ko-KR.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ko-KR.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-lv-LV.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-lv-LV.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-lv-LV.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-lv-LV.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pl-PL.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-pl-PL.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pl-PL.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-pl-PL.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pt-PT.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-pt-PT.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pt-PT.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-pt-PT.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ru-RU.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ru-RU.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ru-RU.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ru-RU.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sr-RS.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-sr-RS.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sr-RS.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-sr-RS.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sv-SE.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-sv-SE.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sv-SE.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-sv-SE.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-uk-UA.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-uk-UA.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-uk-UA.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-uk-UA.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-CN.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-zh-CN.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-CN.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-zh-CN.xml diff --git a/src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-TW.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-zh-TW.xml similarity index 100% rename from src/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-TW.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-zh-TW.xml diff --git a/src/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs similarity index 100% rename from src/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs diff --git a/src/GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs similarity index 100% rename from src/GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs rename to src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs diff --git a/src/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs similarity index 100% rename from src/GreenshotExternalCommandPlugin/ExternalCommandDestination.cs rename to src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs diff --git a/src/GreenshotExternalCommandPlugin/ExternalCommandForm.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs similarity index 100% rename from src/GreenshotExternalCommandPlugin/ExternalCommandForm.cs rename to src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs diff --git a/src/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs similarity index 100% rename from src/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs rename to src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs diff --git a/src/GreenshotExternalCommandPlugin/GreenshotExternalCommandPlugin.csproj b/src/Greenshot.Plugin.ExternalCommand/GreenshotExternalCommandPlugin.csproj similarity index 100% rename from src/GreenshotExternalCommandPlugin/GreenshotExternalCommandPlugin.csproj rename to src/Greenshot.Plugin.ExternalCommand/GreenshotExternalCommandPlugin.csproj diff --git a/src/GreenshotExternalCommandPlugin/IconCache.cs b/src/Greenshot.Plugin.ExternalCommand/IconCache.cs similarity index 100% rename from src/GreenshotExternalCommandPlugin/IconCache.cs rename to src/Greenshot.Plugin.ExternalCommand/IconCache.cs diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-cs-CZ.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-cs-CZ.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-cs-CZ.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-cs-CZ.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-de-DE.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-de-DE.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-de-DE.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-de-DE.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-en-US.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-en-US.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-en-US.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-en-US.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-fr-FR.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-fr-FR.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-fr-FR.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-fr-FR.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-id-ID.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-id-ID.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-id-ID.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-id-ID.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-it-IT.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-it-IT.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ja-JP.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ja-JP.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ja-JP.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ja-JP.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-kab-DZ.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-kab-DZ.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-kab-DZ.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-kab-DZ.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ko-KR.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ko-KR.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ko-KR.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ko-KR.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-lv-LV.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-lv-LV.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-lv-LV.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-lv-LV.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pl-PL.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-pl-PL.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pl-PL.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-pl-PL.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pt-PT.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-pt-PT.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pt-PT.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-pt-PT.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ru-RU.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ru-RU.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ru-RU.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ru-RU.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sk-SK.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sk-SK.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sk-SK.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sk-SK.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sr-RS.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sr-RS.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sr-RS.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sr-RS.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sv-SE.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sv-SE.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sv-SE.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sv-SE.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-uk-UA.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-uk-UA.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-uk-UA.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-uk-UA.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-CN.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-zh-CN.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-CN.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-zh-CN.xml diff --git a/src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-TW.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-zh-TW.xml similarity index 100% rename from src/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-TW.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-zh-TW.xml diff --git a/src/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs similarity index 100% rename from src/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs diff --git a/src/GreenshotExternalCommandPlugin/SettingsForm.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs similarity index 100% rename from src/GreenshotExternalCommandPlugin/SettingsForm.cs rename to src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs diff --git a/src/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs similarity index 100% rename from src/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs rename to src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs diff --git a/src/GreenshotExternalCommandPlugin/SettingsFormDetail.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs similarity index 100% rename from src/GreenshotExternalCommandPlugin/SettingsFormDetail.cs rename to src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs diff --git a/src/GreenshotFlickrPlugin/FlickrConfiguration.cs b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs similarity index 100% rename from src/GreenshotFlickrPlugin/FlickrConfiguration.cs rename to src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs diff --git a/src/GreenshotFlickrPlugin/FlickrDestination.cs b/src/Greenshot.Plugin.Flickr/FlickrDestination.cs similarity index 100% rename from src/GreenshotFlickrPlugin/FlickrDestination.cs rename to src/Greenshot.Plugin.Flickr/FlickrDestination.cs diff --git a/src/GreenshotFlickrPlugin/FlickrPlugin.cs b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs similarity index 100% rename from src/GreenshotFlickrPlugin/FlickrPlugin.cs rename to src/Greenshot.Plugin.Flickr/FlickrPlugin.cs diff --git a/src/GreenshotFlickrPlugin/FlickrPlugin.resx b/src/Greenshot.Plugin.Flickr/FlickrPlugin.resx similarity index 100% rename from src/GreenshotFlickrPlugin/FlickrPlugin.resx rename to src/Greenshot.Plugin.Flickr/FlickrPlugin.resx diff --git a/src/GreenshotFlickrPlugin/FlickrUtils.cs b/src/Greenshot.Plugin.Flickr/FlickrUtils.cs similarity index 100% rename from src/GreenshotFlickrPlugin/FlickrUtils.cs rename to src/Greenshot.Plugin.Flickr/FlickrUtils.cs diff --git a/src/GreenshotFlickrPlugin/Forms/FlickrForm.cs b/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs similarity index 100% rename from src/GreenshotFlickrPlugin/Forms/FlickrForm.cs rename to src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs diff --git a/src/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs similarity index 100% rename from src/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs diff --git a/src/GreenshotFlickrPlugin/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs similarity index 100% rename from src/GreenshotFlickrPlugin/Forms/SettingsForm.cs rename to src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs diff --git a/src/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template b/src/Greenshot.Plugin.Flickr/GreenshotFlickrPlugin.Credentials.template similarity index 100% rename from src/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template rename to src/Greenshot.Plugin.Flickr/GreenshotFlickrPlugin.Credentials.template diff --git a/src/GreenshotFlickrPlugin/GreenshotFlickrPlugin.csproj b/src/Greenshot.Plugin.Flickr/GreenshotFlickrPlugin.csproj similarity index 100% rename from src/GreenshotFlickrPlugin/GreenshotFlickrPlugin.csproj rename to src/Greenshot.Plugin.Flickr/GreenshotFlickrPlugin.csproj diff --git a/src/GreenshotFlickrPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Flickr/LanguageKeys.cs similarity index 100% rename from src/GreenshotFlickrPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Flickr/LanguageKeys.cs diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-cs-CZ.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-cs-CZ.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-cs-CZ.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-de-DE.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-de-DE.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-de-DE.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-de-DE.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-en-US.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-en-US.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-en-US.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-en-US.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-fr-FR.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-fr-FR.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-fr-FR.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-fr-FR.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-id-ID.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-id-ID.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-id-ID.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-id-ID.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-it-IT.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-it-IT.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ja-JP.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ja-JP.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ja-JP.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ja-JP.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-kab-DZ.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-kab-DZ.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-kab-DZ.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ko-KR.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ko-KR.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ko-KR.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ko-KR.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-lv-LV.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-lv-LV.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-lv-LV.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-lv-LV.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-pl-PL.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-pl-PL.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-pl-PL.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-pl-PL.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-pt-PT.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-pt-PT.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-pt-PT.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-pt-PT.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ru-RU.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ru-RU.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-ru-RU.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ru-RU.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-sr-RS.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-sr-RS.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-sr-RS.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-sr-RS.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-sv-SE.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-sv-SE.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-sv-SE.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-sv-SE.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-uk-UA.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-uk-UA.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-uk-UA.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-uk-UA.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-CN.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-zh-CN.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-CN.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-zh-CN.xml diff --git a/src/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-TW.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-zh-TW.xml similarity index 100% rename from src/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-TW.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-zh-TW.xml diff --git a/src/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs similarity index 100% rename from src/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs diff --git a/src/GreenshotFlickrPlugin/flickr.png b/src/Greenshot.Plugin.Flickr/flickr.png similarity index 100% rename from src/GreenshotFlickrPlugin/flickr.png rename to src/Greenshot.Plugin.Flickr/flickr.png diff --git a/src/GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs rename to src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs diff --git a/src/GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs diff --git a/src/GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs rename to src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs diff --git a/src/GreenshotGooglePhotosPlugin/GooglePhotos.png b/src/Greenshot.Plugin.GooglePhotos/GooglePhotos.png similarity index 100% rename from src/GreenshotGooglePhotosPlugin/GooglePhotos.png rename to src/Greenshot.Plugin.GooglePhotos/GooglePhotos.png diff --git a/src/GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs similarity index 100% rename from src/GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs rename to src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs diff --git a/src/GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs similarity index 100% rename from src/GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs rename to src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs diff --git a/src/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs similarity index 100% rename from src/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs rename to src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs diff --git a/src/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.resx similarity index 100% rename from src/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx rename to src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.resx diff --git a/src/GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs similarity index 100% rename from src/GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs rename to src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs diff --git a/src/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template b/src/Greenshot.Plugin.GooglePhotos/GreenshotGooglePhotosPlugin.Credentials.template similarity index 100% rename from src/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template rename to src/Greenshot.Plugin.GooglePhotos/GreenshotGooglePhotosPlugin.Credentials.template diff --git a/src/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj b/src/Greenshot.Plugin.GooglePhotos/GreenshotGooglePhotosPlugin.csproj similarity index 100% rename from src/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj rename to src/Greenshot.Plugin.GooglePhotos/GreenshotGooglePhotosPlugin.csproj diff --git a/src/GreenshotGooglePhotosPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs similarity index 100% rename from src/GreenshotGooglePhotosPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-cs-CZ.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-cs-CZ.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-de-DE.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-de-DE.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-en-US.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-en-US.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-fr-FR.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-fr-FR.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-id-ID.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-id-ID.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-it-IT.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-it-IT.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ja-JP.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ja-JP.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-kab-DZ.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-kab-DZ.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ko-KR.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ko-KR.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-lv-LV.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-lv-LV.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-pl-PL.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-pl-PL.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-pt-PT.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-pt-PT.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ru-RU.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ru-RU.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-sr-RS.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-sr-RS.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-sv-SE.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-sv-SE.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-uk-UA.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-uk-UA.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-zh-CN.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-zh-CN.xml diff --git a/src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-zh-TW.xml similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-zh-TW.xml diff --git a/src/GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs similarity index 100% rename from src/GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs diff --git a/src/GreenshotGooglePhotosPlugin/README b/src/Greenshot.Plugin.GooglePhotos/README similarity index 100% rename from src/GreenshotGooglePhotosPlugin/README rename to src/Greenshot.Plugin.GooglePhotos/README diff --git a/src/GreenshotImgurPlugin/Forms/ImgurForm.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs similarity index 100% rename from src/GreenshotImgurPlugin/Forms/ImgurForm.cs rename to src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs diff --git a/src/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.Designer.cs similarity index 100% rename from src/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs rename to src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.Designer.cs diff --git a/src/GreenshotImgurPlugin/Forms/ImgurHistory.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs similarity index 100% rename from src/GreenshotImgurPlugin/Forms/ImgurHistory.cs rename to src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs diff --git a/src/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs similarity index 100% rename from src/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs diff --git a/src/GreenshotImgurPlugin/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs similarity index 100% rename from src/GreenshotImgurPlugin/Forms/SettingsForm.cs rename to src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs diff --git a/src/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template b/src/Greenshot.Plugin.Imgur/GreenshotImgurPlugin.Credentials.template similarity index 100% rename from src/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template rename to src/Greenshot.Plugin.Imgur/GreenshotImgurPlugin.Credentials.template diff --git a/src/GreenshotImgurPlugin/GreenshotImgurPlugin.csproj b/src/Greenshot.Plugin.Imgur/GreenshotImgurPlugin.csproj similarity index 100% rename from src/GreenshotImgurPlugin/GreenshotImgurPlugin.csproj rename to src/Greenshot.Plugin.Imgur/GreenshotImgurPlugin.csproj diff --git a/src/GreenshotImgurPlugin/ImgurConfiguration.cs b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs similarity index 100% rename from src/GreenshotImgurPlugin/ImgurConfiguration.cs rename to src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs diff --git a/src/GreenshotImgurPlugin/ImgurDestination.cs b/src/Greenshot.Plugin.Imgur/ImgurDestination.cs similarity index 100% rename from src/GreenshotImgurPlugin/ImgurDestination.cs rename to src/Greenshot.Plugin.Imgur/ImgurDestination.cs diff --git a/src/GreenshotImgurPlugin/ImgurInfo.cs b/src/Greenshot.Plugin.Imgur/ImgurInfo.cs similarity index 100% rename from src/GreenshotImgurPlugin/ImgurInfo.cs rename to src/Greenshot.Plugin.Imgur/ImgurInfo.cs diff --git a/src/GreenshotImgurPlugin/ImgurPlugin.cs b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs similarity index 100% rename from src/GreenshotImgurPlugin/ImgurPlugin.cs rename to src/Greenshot.Plugin.Imgur/ImgurPlugin.cs diff --git a/src/GreenshotImgurPlugin/ImgurPlugin.resx b/src/Greenshot.Plugin.Imgur/ImgurPlugin.resx similarity index 100% rename from src/GreenshotImgurPlugin/ImgurPlugin.resx rename to src/Greenshot.Plugin.Imgur/ImgurPlugin.resx diff --git a/src/GreenshotImgurPlugin/ImgurUtils.cs b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs similarity index 100% rename from src/GreenshotImgurPlugin/ImgurUtils.cs rename to src/Greenshot.Plugin.Imgur/ImgurUtils.cs diff --git a/src/GreenshotImgurPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Imgur/LanguageKeys.cs similarity index 100% rename from src/GreenshotImgurPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Imgur/LanguageKeys.cs diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-cs-CZ.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-cs-CZ.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-cs-CZ.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-de-DE.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-de-DE.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-de-DE.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-de-DE.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-en-US.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-en-US.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-en-US.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-en-US.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-fr-FR.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-fr-FR.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-fr-FR.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-fr-FR.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-id-ID.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-id-ID.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-id-ID.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-id-ID.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-it-IT.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-it-IT.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-ja-JP.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ja-JP.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-ja-JP.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ja-JP.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-kab-DZ.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-kab-DZ.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-kab-DZ.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-ko-KR.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ko-KR.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-ko-KR.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ko-KR.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-lv-LV.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-lv-LV.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-lv-LV.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-lv-LV.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-nl-NL.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-nl-NL.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-nl-NL.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-nl-NL.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-pl-PL.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-pl-PL.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-pl-PL.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-pl-PL.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-pt-PT.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-pt-PT.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-pt-PT.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-pt-PT.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-ru-RU.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ru-RU.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-ru-RU.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ru-RU.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-sk-SK.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sk-SK.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-sk-SK.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sk-SK.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-sr-RS.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sr-RS.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-sr-RS.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sr-RS.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-sv-SE.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sv-SE.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-sv-SE.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sv-SE.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-uk-UA.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-uk-UA.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-uk-UA.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-uk-UA.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-CN.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-zh-CN.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-CN.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-zh-CN.xml diff --git a/src/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-TW.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-zh-TW.xml similarity index 100% rename from src/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-TW.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-zh-TW.xml diff --git a/src/GreenshotImgurPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs similarity index 100% rename from src/GreenshotImgurPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs diff --git a/src/GreenshotJiraPlugin/AsyncMemoryCache.cs b/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs similarity index 100% rename from src/GreenshotJiraPlugin/AsyncMemoryCache.cs rename to src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs diff --git a/src/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs b/src/Greenshot.Plugin.Jira/Forms/JiraForm.Designer.cs similarity index 100% rename from src/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs rename to src/Greenshot.Plugin.Jira/Forms/JiraForm.Designer.cs diff --git a/src/GreenshotJiraPlugin/Forms/JiraForm.cs b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs similarity index 100% rename from src/GreenshotJiraPlugin/Forms/JiraForm.cs rename to src/Greenshot.Plugin.Jira/Forms/JiraForm.cs diff --git a/src/GreenshotJiraPlugin/Forms/JiraFormBase.cs b/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs similarity index 100% rename from src/GreenshotJiraPlugin/Forms/JiraFormBase.cs rename to src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs diff --git a/src/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs similarity index 100% rename from src/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs diff --git a/src/GreenshotJiraPlugin/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs similarity index 100% rename from src/GreenshotJiraPlugin/Forms/SettingsForm.cs rename to src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs diff --git a/src/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj b/src/Greenshot.Plugin.Jira/GreenshotJiraPlugin.csproj similarity index 100% rename from src/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj rename to src/Greenshot.Plugin.Jira/GreenshotJiraPlugin.csproj diff --git a/src/GreenshotJiraPlugin/IssueTypeBitmapCache.cs b/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs similarity index 100% rename from src/GreenshotJiraPlugin/IssueTypeBitmapCache.cs rename to src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs diff --git a/src/GreenshotJiraPlugin/JiraConfiguration.cs b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs similarity index 100% rename from src/GreenshotJiraPlugin/JiraConfiguration.cs rename to src/Greenshot.Plugin.Jira/JiraConfiguration.cs diff --git a/src/GreenshotJiraPlugin/JiraConnector.cs b/src/Greenshot.Plugin.Jira/JiraConnector.cs similarity index 100% rename from src/GreenshotJiraPlugin/JiraConnector.cs rename to src/Greenshot.Plugin.Jira/JiraConnector.cs diff --git a/src/GreenshotJiraPlugin/JiraDestination.cs b/src/Greenshot.Plugin.Jira/JiraDestination.cs similarity index 100% rename from src/GreenshotJiraPlugin/JiraDestination.cs rename to src/Greenshot.Plugin.Jira/JiraDestination.cs diff --git a/src/GreenshotJiraPlugin/JiraDetails.cs b/src/Greenshot.Plugin.Jira/JiraDetails.cs similarity index 100% rename from src/GreenshotJiraPlugin/JiraDetails.cs rename to src/Greenshot.Plugin.Jira/JiraDetails.cs diff --git a/src/GreenshotJiraPlugin/JiraEventArgs.cs b/src/Greenshot.Plugin.Jira/JiraEventArgs.cs similarity index 100% rename from src/GreenshotJiraPlugin/JiraEventArgs.cs rename to src/Greenshot.Plugin.Jira/JiraEventArgs.cs diff --git a/src/GreenshotJiraPlugin/JiraEventTypes.cs b/src/Greenshot.Plugin.Jira/JiraEventTypes.cs similarity index 100% rename from src/GreenshotJiraPlugin/JiraEventTypes.cs rename to src/Greenshot.Plugin.Jira/JiraEventTypes.cs diff --git a/src/GreenshotJiraPlugin/JiraMonitor.cs b/src/Greenshot.Plugin.Jira/JiraMonitor.cs similarity index 100% rename from src/GreenshotJiraPlugin/JiraMonitor.cs rename to src/Greenshot.Plugin.Jira/JiraMonitor.cs diff --git a/src/GreenshotJiraPlugin/JiraPlugin.cs b/src/Greenshot.Plugin.Jira/JiraPlugin.cs similarity index 100% rename from src/GreenshotJiraPlugin/JiraPlugin.cs rename to src/Greenshot.Plugin.Jira/JiraPlugin.cs diff --git a/src/GreenshotJiraPlugin/JiraPlugin.resx b/src/Greenshot.Plugin.Jira/JiraPlugin.resx similarity index 100% rename from src/GreenshotJiraPlugin/JiraPlugin.resx rename to src/Greenshot.Plugin.Jira/JiraPlugin.resx diff --git a/src/GreenshotJiraPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Jira/LanguageKeys.cs similarity index 100% rename from src/GreenshotJiraPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Jira/LanguageKeys.cs diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-cs-CZ.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-cs-CZ.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-cs-CZ.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-de-DE.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-de-DE.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-de-DE.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-de-DE.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-en-US.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-en-US.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-en-US.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-en-US.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-fr-FR.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-fr-FR.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-fr-FR.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-fr-FR.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-id-ID.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-id-ID.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-id-ID.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-id-ID.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-it-IT.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-it-IT.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-ja-JP.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ja-JP.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-ja-JP.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ja-JP.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-kab-DZ.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-kab-DZ.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-kab-DZ.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-ko-KR.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ko-KR.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-ko-KR.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ko-KR.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-lv-LV.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-lv-LV.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-lv-LV.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-lv-LV.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-nl-NL.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-nl-NL.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-nl-NL.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-nl-NL.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-pl-PL.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-pl-PL.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-pl-PL.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-pl-PL.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-pt-PT.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-pt-PT.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-pt-PT.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-pt-PT.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-ru-RU.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ru-RU.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-ru-RU.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ru-RU.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-sr-RS.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-sr-RS.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-sr-RS.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-sr-RS.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-sv-SE.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-sv-SE.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-sv-SE.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-sv-SE.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-uk-UA.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-uk-UA.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-uk-UA.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-uk-UA.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-CN.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-zh-CN.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-CN.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-zh-CN.xml diff --git a/src/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-TW.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-zh-TW.xml similarity index 100% rename from src/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-TW.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-zh-TW.xml diff --git a/src/GreenshotJiraPlugin/Log4NetLogger.cs b/src/Greenshot.Plugin.Jira/Log4NetLogger.cs similarity index 100% rename from src/GreenshotJiraPlugin/Log4NetLogger.cs rename to src/Greenshot.Plugin.Jira/Log4NetLogger.cs diff --git a/src/GreenshotOfficePlugin/Com/DisposableCom.cs b/src/Greenshot.Plugin.Office/Com/DisposableCom.cs similarity index 100% rename from src/GreenshotOfficePlugin/Com/DisposableCom.cs rename to src/Greenshot.Plugin.Office/Com/DisposableCom.cs diff --git a/src/GreenshotOfficePlugin/Com/DisposableComImplementation.cs b/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs similarity index 100% rename from src/GreenshotOfficePlugin/Com/DisposableComImplementation.cs rename to src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs diff --git a/src/GreenshotOfficePlugin/Com/IDisposableCom.cs b/src/Greenshot.Plugin.Office/Com/IDisposableCom.cs similarity index 100% rename from src/GreenshotOfficePlugin/Com/IDisposableCom.cs rename to src/Greenshot.Plugin.Office/Com/IDisposableCom.cs diff --git a/src/GreenshotOfficePlugin/Com/Ole32Api.cs b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs similarity index 100% rename from src/GreenshotOfficePlugin/Com/Ole32Api.cs rename to src/Greenshot.Plugin.Office/Com/Ole32Api.cs diff --git a/src/GreenshotOfficePlugin/Com/OleAut32Api.cs b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs similarity index 100% rename from src/GreenshotOfficePlugin/Com/OleAut32Api.cs rename to src/Greenshot.Plugin.Office/Com/OleAut32Api.cs diff --git a/src/GreenshotOfficePlugin/Destinations/ExcelDestination.cs b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs similarity index 100% rename from src/GreenshotOfficePlugin/Destinations/ExcelDestination.cs rename to src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs diff --git a/src/GreenshotOfficePlugin/Destinations/OneNoteDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs similarity index 100% rename from src/GreenshotOfficePlugin/Destinations/OneNoteDestination.cs rename to src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs diff --git a/src/GreenshotOfficePlugin/Destinations/OutlookDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs similarity index 100% rename from src/GreenshotOfficePlugin/Destinations/OutlookDestination.cs rename to src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs diff --git a/src/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs similarity index 100% rename from src/GreenshotOfficePlugin/Destinations/PowerpointDestination.cs rename to src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs diff --git a/src/GreenshotOfficePlugin/Destinations/WordDestination.cs b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs similarity index 100% rename from src/GreenshotOfficePlugin/Destinations/WordDestination.cs rename to src/Greenshot.Plugin.Office/Destinations/WordDestination.cs diff --git a/src/GreenshotOfficePlugin/GlobalSuppressions.cs b/src/Greenshot.Plugin.Office/GlobalSuppressions.cs similarity index 100% rename from src/GreenshotOfficePlugin/GlobalSuppressions.cs rename to src/Greenshot.Plugin.Office/GlobalSuppressions.cs diff --git a/src/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj b/src/Greenshot.Plugin.Office/GreenshotOfficePlugin.csproj similarity index 100% rename from src/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj rename to src/Greenshot.Plugin.Office/GreenshotOfficePlugin.csproj diff --git a/src/GreenshotOfficePlugin/Languages/language_officeplugin-fr-FR.ini b/src/Greenshot.Plugin.Office/Languages/language_officeplugin-fr-FR.ini similarity index 100% rename from src/GreenshotOfficePlugin/Languages/language_officeplugin-fr-FR.ini rename to src/Greenshot.Plugin.Office/Languages/language_officeplugin-fr-FR.ini diff --git a/src/GreenshotOfficePlugin/OfficeConfiguration.cs b/src/Greenshot.Plugin.Office/OfficeConfiguration.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeConfiguration.cs rename to src/Greenshot.Plugin.Office/OfficeConfiguration.cs diff --git a/src/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteNotebook.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs rename to src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteNotebook.cs diff --git a/src/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs rename to src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs diff --git a/src/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteSection.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs rename to src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteSection.cs diff --git a/src/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs rename to src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs diff --git a/src/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs rename to src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs diff --git a/src/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs rename to src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs diff --git a/src/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs rename to src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs diff --git a/src/GreenshotOfficePlugin/OfficeExport/WordExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeExport/WordExporter.cs rename to src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs diff --git a/src/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs b/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs rename to src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs diff --git a/src/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs b/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs rename to src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs diff --git a/src/GreenshotOfficePlugin/OfficePlugin.cs b/src/Greenshot.Plugin.Office/OfficePlugin.cs similarity index 100% rename from src/GreenshotOfficePlugin/OfficePlugin.cs rename to src/Greenshot.Plugin.Office/OfficePlugin.cs diff --git a/src/GreenshotOfficePlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs similarity index 100% rename from src/GreenshotOfficePlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs diff --git a/src/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs b/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs similarity index 100% rename from src/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs rename to src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs diff --git a/src/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs similarity index 100% rename from src/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs diff --git a/src/GreenshotPhotobucketPlugin/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs similarity index 100% rename from src/GreenshotPhotobucketPlugin/Forms/SettingsForm.cs rename to src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs diff --git a/src/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template b/src/Greenshot.Plugin.Photobucket/GreenshotPhotobucketPlugin.Credentials.template similarity index 100% rename from src/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template rename to src/Greenshot.Plugin.Photobucket/GreenshotPhotobucketPlugin.Credentials.template diff --git a/src/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.csproj b/src/Greenshot.Plugin.Photobucket/GreenshotPhotobucketPlugin.csproj similarity index 100% rename from src/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.csproj rename to src/Greenshot.Plugin.Photobucket/GreenshotPhotobucketPlugin.csproj diff --git a/src/GreenshotPhotobucketPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs similarity index 100% rename from src/GreenshotPhotobucketPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Photobucket/LanguageKeys.cs diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-cs-CZ.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-cs-CZ.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-cs-CZ.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-de-DE.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-de-DE.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-de-DE.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-de-DE.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-en-US.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-en-US.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-en-US.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-en-US.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-fr_FR.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-fr_FR.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-fr_FR.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-fr_FR.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-id-ID.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-id-ID.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-id-ID.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-id-ID.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-it-IT.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-it-IT.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ja-JP.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ja-JP.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ja-JP.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ja-JP.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-kab-DZ.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-kab-DZ.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-kab-DZ.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ko-KR.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ko-KR.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ko-KR.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ko-KR.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-lv-LV.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-lv-LV.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-lv-LV.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-lv-LV.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-nl-NL.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-nl-NL.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-nl-NL.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-nl-NL.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pl-PL.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-pl-PL.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pl-PL.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-pl-PL.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pt-PT.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-pt-PT.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pt-PT.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-pt-PT.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ru-RU.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ru-RU.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ru-RU.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ru-RU.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-sv-SE.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-sv-SE.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-sv-SE.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-sv-SE.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-uk-UA.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-uk-UA.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-uk-UA.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-uk-UA.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-CN.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-zh-CN.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-CN.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-zh-CN.xml diff --git a/src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-TW.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-zh-TW.xml similarity index 100% rename from src/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-TW.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-zh-TW.xml diff --git a/src/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs similarity index 100% rename from src/GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs rename to src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs diff --git a/src/GreenshotPhotobucketPlugin/PhotobucketDestination.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs similarity index 100% rename from src/GreenshotPhotobucketPlugin/PhotobucketDestination.cs rename to src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs diff --git a/src/GreenshotPhotobucketPlugin/PhotobucketInfo.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs similarity index 100% rename from src/GreenshotPhotobucketPlugin/PhotobucketInfo.cs rename to src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs diff --git a/src/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs similarity index 100% rename from src/GreenshotPhotobucketPlugin/PhotobucketPlugin.cs rename to src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs diff --git a/src/GreenshotPhotobucketPlugin/PhotobucketPlugin.resx b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.resx similarity index 100% rename from src/GreenshotPhotobucketPlugin/PhotobucketPlugin.resx rename to src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.resx diff --git a/src/GreenshotPhotobucketPlugin/PhotobucketUtils.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs similarity index 100% rename from src/GreenshotPhotobucketPlugin/PhotobucketUtils.cs rename to src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs diff --git a/src/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs similarity index 100% rename from src/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs diff --git a/src/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs similarity index 100% rename from src/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs rename to src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs diff --git a/src/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs similarity index 100% rename from src/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs rename to src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs diff --git a/src/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj b/src/Greenshot.Plugin.Win10/GreenshotWin10Plugin.csproj similarity index 100% rename from src/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj rename to src/Greenshot.Plugin.Win10/GreenshotWin10Plugin.csproj diff --git a/src/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs b/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs similarity index 100% rename from src/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs rename to src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs diff --git a/src/GreenshotWin10Plugin/Internal/ShareInfo.cs b/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs similarity index 100% rename from src/GreenshotWin10Plugin/Internal/ShareInfo.cs rename to src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs diff --git a/src/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs similarity index 100% rename from src/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs rename to src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs diff --git a/src/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs similarity index 100% rename from src/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs rename to src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs diff --git a/src/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs b/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs similarity index 100% rename from src/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs rename to src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs diff --git a/src/GreenshotWin10Plugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs similarity index 100% rename from src/GreenshotWin10Plugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs diff --git a/src/GreenshotWin10Plugin/ToastNotificationService.cs b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs similarity index 100% rename from src/GreenshotWin10Plugin/ToastNotificationService.cs rename to src/Greenshot.Plugin.Win10/ToastNotificationService.cs diff --git a/src/GreenshotWin10Plugin/Win10Configuration.cs b/src/Greenshot.Plugin.Win10/Win10Configuration.cs similarity index 100% rename from src/GreenshotWin10Plugin/Win10Configuration.cs rename to src/Greenshot.Plugin.Win10/Win10Configuration.cs diff --git a/src/GreenshotWin10Plugin/Win10OcrProvider.cs b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs similarity index 100% rename from src/GreenshotWin10Plugin/Win10OcrProvider.cs rename to src/Greenshot.Plugin.Win10/Win10OcrProvider.cs diff --git a/src/GreenshotWin10Plugin/Win10Plugin.cs b/src/Greenshot.Plugin.Win10/Win10Plugin.cs similarity index 100% rename from src/GreenshotWin10Plugin/Win10Plugin.cs rename to src/Greenshot.Plugin.Win10/Win10Plugin.cs From b51fa383137e39cea905ff8903004f37af44a093 Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Sun, 28 Mar 2021 12:19:43 +0300 Subject: [PATCH 113/232] Fix typos (#301) [skip ci] * Fix typos * Update URL to HTTPS --- Greenshot/Forms/BugReportForm.Designer.cs | 2 +- Greenshot/releases/innosetup/setup.iss | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Greenshot/Forms/BugReportForm.Designer.cs b/Greenshot/Forms/BugReportForm.Designer.cs index 2c5a7ae52..da6da4963 100644 --- a/Greenshot/Forms/BugReportForm.Designer.cs +++ b/Greenshot/Forms/BugReportForm.Designer.cs @@ -91,7 +91,7 @@ namespace Greenshot.Forms { this.linkLblBugs.Size = new System.Drawing.Size(465, 23); this.linkLblBugs.TabIndex = 9; this.linkLblBugs.TabStop = true; - this.linkLblBugs.Text = "http://getgreenshot.org/tickets/"; + this.linkLblBugs.Text = "https://getgreenshot.org/tickets/"; this.linkLblBugs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLblBugsLinkClicked); // // BugReportForm diff --git a/Greenshot/releases/innosetup/setup.iss b/Greenshot/releases/innosetup/setup.iss index 4eff93b45..d055b7151 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/Greenshot/releases/innosetup/setup.iss @@ -266,8 +266,8 @@ en.startgreenshot=Start {#ExeName} en.startup=Start {#ExeName} with Windows start en.win10=Windows 10 plug-in en.UninstallIconDescription=Uninstall -en.ShowLicense=Show licenze -en.ShowReadme=how Readme +en.ShowLicense=Show license +en.ShowReadme=Show Readme de.confluence=Confluence Plug-in de.default=Standard installation From c6bdaa8a87aa63e05c1fa7d05e48d0aedfc22c32 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 28 Mar 2021 11:31:05 +0200 Subject: [PATCH 114/232] More file renaming for a more clear project structure. --- .editorconfig | 78 -------- Directory.Build.props | 122 ------------- Directory.Build.targets | 13 -- Greenshot.sln | 170 ------------------ Greenshot.sln.DotSettings | 4 - ...Greenshot.Plugin.Box.Credentials.template} | 0 ...gin.csproj => Greenshot.Plugin.Box.csproj} | 0 ...roj => Greenshot.Plugin.Confluence.csproj} | 0 ...nshot.Plugin.Dropbox.Credentials.template} | 0 ...csproj => Greenshot.Plugin.Dropbox.csproj} | 0 ...> Greenshot.Plugin.ExternalCommand.csproj} | 0 ...enshot.Plugin.Flickr.Credentials.template} | 0 ....csproj => Greenshot.Plugin.Flickr.csproj} | 0 ....Plugin.GooglePhotos.Credentials.template} | 0 ...j => Greenshot.Plugin.GooglePhotos.csproj} | 0 ...eenshot.Plugin.Imgur.Credentials.template} | 0 ...n.csproj => Greenshot.Plugin.Imgur.csproj} | 0 ...in.csproj => Greenshot.Plugin.Jira.csproj} | 0 ....csproj => Greenshot.Plugin.Office.csproj} | 0 ...t.Plugin.Photobucket.Credentials.template} | 0 ...oj => Greenshot.Plugin.Photobucket.csproj} | 0 ...n.csproj => Greenshot.Plugin.Win10.csproj} | 0 src/Greenshot.sln | 22 +-- version.json | 21 --- 24 files changed, 11 insertions(+), 419 deletions(-) delete mode 100644 .editorconfig delete mode 100644 Directory.Build.props delete mode 100644 Directory.Build.targets delete mode 100644 Greenshot.sln delete mode 100644 Greenshot.sln.DotSettings rename src/Greenshot.Plugin.Box/{GreenshotBoxPlugin.Credentials.template => Greenshot.Plugin.Box.Credentials.template} (100%) rename src/Greenshot.Plugin.Box/{GreenshotBoxPlugin.csproj => Greenshot.Plugin.Box.csproj} (100%) rename src/Greenshot.Plugin.Confluence/{GreenshotConfluencePlugin.csproj => Greenshot.Plugin.Confluence.csproj} (100%) rename src/Greenshot.Plugin.Dropbox/{GreenshotDropboxPlugin.Credentials.template => Greenshot.Plugin.Dropbox.Credentials.template} (100%) rename src/Greenshot.Plugin.Dropbox/{GreenshotDropboxPlugin.csproj => Greenshot.Plugin.Dropbox.csproj} (100%) rename src/Greenshot.Plugin.ExternalCommand/{GreenshotExternalCommandPlugin.csproj => Greenshot.Plugin.ExternalCommand.csproj} (100%) rename src/Greenshot.Plugin.Flickr/{GreenshotFlickrPlugin.Credentials.template => Greenshot.Plugin.Flickr.Credentials.template} (100%) rename src/Greenshot.Plugin.Flickr/{GreenshotFlickrPlugin.csproj => Greenshot.Plugin.Flickr.csproj} (100%) rename src/Greenshot.Plugin.GooglePhotos/{GreenshotGooglePhotosPlugin.Credentials.template => Greenshot.Plugin.GooglePhotos.Credentials.template} (100%) rename src/Greenshot.Plugin.GooglePhotos/{GreenshotGooglePhotosPlugin.csproj => Greenshot.Plugin.GooglePhotos.csproj} (100%) rename src/Greenshot.Plugin.Imgur/{GreenshotImgurPlugin.Credentials.template => Greenshot.Plugin.Imgur.Credentials.template} (100%) rename src/Greenshot.Plugin.Imgur/{GreenshotImgurPlugin.csproj => Greenshot.Plugin.Imgur.csproj} (100%) rename src/Greenshot.Plugin.Jira/{GreenshotJiraPlugin.csproj => Greenshot.Plugin.Jira.csproj} (100%) rename src/Greenshot.Plugin.Office/{GreenshotOfficePlugin.csproj => Greenshot.Plugin.Office.csproj} (100%) rename src/Greenshot.Plugin.Photobucket/{GreenshotPhotobucketPlugin.Credentials.template => Greenshot.Plugin.Photobucket.Credentials.template} (100%) rename src/Greenshot.Plugin.Photobucket/{GreenshotPhotobucketPlugin.csproj => Greenshot.Plugin.Photobucket.csproj} (100%) rename src/Greenshot.Plugin.Win10/{GreenshotWin10Plugin.csproj => Greenshot.Plugin.Win10.csproj} (100%) delete mode 100644 version.json diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index f399b08bb..000000000 --- a/.editorconfig +++ /dev/null @@ -1,78 +0,0 @@ -# EditorConfig is awesome:http://EditorConfig.org - -# top-most EditorConfig file -root = true - -# Don't use tabs for indentation. -[*] -indent_style = space -# (Please don't specify an indent_size here; that has too many unintended consequences.) - -# Code files -[*.{cs,csx,vb,vbx}] -indent_size = 4 - -# Xml project files -[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] -indent_size = 2 - -# Xml config files -[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] -indent_size = 2 - -# JSON files -[*.json] -indent_size = 2 - -# Dotnet code style settings: -[*.{cs,vb}] -# Sort using and Import directives with System.* appearing first -dotnet_sort_system_directives_first = true -# Avoid "this." and "Me." if not necessary -dotnet_style_qualification_for_field = false:suggestion -dotnet_style_qualification_for_property = false:suggestion -dotnet_style_qualification_for_method = false:suggestion -dotnet_style_qualification_for_event = false:suggestion - -# Use language keywords instead of framework type names for type references -dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion -dotnet_style_predefined_type_for_member_access = true:suggestion - -# Suggest more modern language features when available -dotnet_style_object_initializer = true:suggestion -dotnet_style_collection_initializer = true:suggestion -dotnet_style_coalesce_expression = true:suggestion -dotnet_style_null_propagation = true:suggestion -dotnet_style_explicit_tuple_names = true:suggestion - -# CSharp code style settings: -[*.cs] -# Prefer "var" everywhere -csharp_style_var_for_built_in_types = true:suggestion -csharp_style_var_when_type_is_apparent = true:suggestion -csharp_style_var_elsewhere = true:suggestion - -# Prefer method-like constructs to have a block body -csharp_style_expression_bodied_methods = false:none -csharp_style_expression_bodied_constructors = false:none -csharp_style_expression_bodied_operators = false:none - -# Prefer property-like constructs to have an expression-body -csharp_style_expression_bodied_properties = true:none -csharp_style_expression_bodied_indexers = true:none -csharp_style_expression_bodied_accessors = true:none - -# Suggest more modern language features when available -csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion -csharp_style_pattern_matching_over_as_with_null_check = true:suggestion -csharp_style_inlined_variable_declaration = true:suggestion -csharp_style_throw_expression = true:suggestion -csharp_style_conditional_delegate_call = true:suggestion - -# Newline settings -csharp_new_line_before_open_brace = all -csharp_new_line_before_else = true -csharp_new_line_before_catch = true -csharp_new_line_before_finally = true -csharp_new_line_before_members_in_object_initializers = true -csharp_new_line_before_members_in_anonymous_types = true \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index a15044b52..000000000 --- a/Directory.Build.props +++ /dev/null @@ -1,122 +0,0 @@ - - - Copyright © Greenshot 2004-2021 - Greenshot - https://getgreenshot.org/favicon.ico - https://github.com/greenshot/greenshot - git - https://github.com/greenshot/greenshot - https://www.gnu.org/licenses/gpl.html - GPL - 9 - true - true - win10-x64;win10-x86;win-x64;win-x86 - - true - - true - net472 - Off - true - - - - - - - - - false - true - - - - false - true - false - - - - false - false - - - - DEBUG;TRACE - True - true - embedded - false - - - - true - embedded - True - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - $(Box13_ClientId) - - - $(Box13_ClientSecret) - - - $(DropBox13_ClientId) - - - $(DropBox13_ClientSecret) - - - $(Flickr_ClientId) - - - $(Flickr_ClientSecret) - - - $(Imgur13_ClientId) - - - $(Imgur13_ClientSecret) - - - $(Photobucket_ClientId) - - - $(Photobucket_ClientSecret) - - - $(Picasa_ClientId) - - - $(Picasa_ClientSecret) - - - - - - - - - - - - diff --git a/Directory.Build.targets b/Directory.Build.targets deleted file mode 100644 index f2ce406a1..000000000 --- a/Directory.Build.targets +++ /dev/null @@ -1,13 +0,0 @@ - - - - $(PkgMSBuildTasks)\tools\ - - - - - - - - - \ No newline at end of file diff --git a/Greenshot.sln b/Greenshot.sln deleted file mode 100644 index f815631e2..000000000 --- a/Greenshot.sln +++ /dev/null @@ -1,170 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29728.190 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Greenshot.csproj", "{CD642BF4-D815-4D67-A0B5-C69F0B8231AF}" - ProjectSection(ProjectDependencies) = postProject - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} = {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} - {19FEEF09-313F-43C7-819D-F1BCA782B08B} = {19FEEF09-313F-43C7-819D-F1BCA782B08B} - {9801F62C-540F-4BFE-9211-6405DEDE563B} = {9801F62C-540F-4BFE-9211-6405DEDE563B} - {9C0ECC4C-7807-4111-916A-4F57BB29788A} = {9C0ECC4C-7807-4111-916A-4F57BB29788A} - {C3052651-598A-44E2-AAB3-2E41311D50F9} = {C3052651-598A-44E2-AAB3-2E41311D50F9} - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} = {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} - {697CF066-9077-4F22-99D9-D989CCE7282B} = {697CF066-9077-4F22-99D9-D989CCE7282B} - {47F23C86-604E-4CC3-8767-B3D4088F30BB} = {47F23C86-604E-4CC3-8767-B3D4088F30BB} - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} = {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} = {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} - {1893A2E4-A78A-4713-A8E7-E70058DABEE0} = {1893A2E4-A78A-4713-A8E7-E70058DABEE0} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPlugin", "GreenshotPlugin\GreenshotPlugin.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotExternalCommandPlugin", "GreenshotExternalCommandPlugin\GreenshotExternalCommandPlugin.csproj", "{47F23C86-604E-4CC3-8767-B3D4088F30BB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotConfluencePlugin", "GreenshotConfluencePlugin\GreenshotConfluencePlugin.csproj", "{C3052651-598A-44E2-AAB3-2E41311D50F9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotImgurPlugin", "GreenshotImgurPlugin\GreenshotImgurPlugin.csproj", "{80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotJiraPlugin", "GreenshotJiraPlugin\GreenshotJiraPlugin.csproj", "{19FEEF09-313F-43C7-819D-F1BCA782B08B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotBoxPlugin", "GreenshotBoxPlugin\GreenshotBoxPlugin.csproj", "{697CF066-9077-4F22-99D9-D989CCE7282B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotDropboxPlugin", "GreenshotDropboxPlugin\GreenshotDropboxPlugin.csproj", "{AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotFlickrPlugin", "GreenshotFlickrPlugin\GreenshotFlickrPlugin.csproj", "{7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotGooglePhotosPlugin", "GreenshotGooglePhotosPlugin\GreenshotGooglePhotosPlugin.csproj", "{1893A2E4-A78A-4713-A8E7-E70058DABEE0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotOfficePlugin", "GreenshotOfficePlugin\GreenshotOfficePlugin.csproj", "{92599C09-FF29-4ABD-B6E6-C48ECD781BAB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPhotobucketPlugin", "GreenshotPhotobucketPlugin\GreenshotPhotobucketPlugin.csproj", "{9C0ECC4C-7807-4111-916A-4F57BB29788A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotWin10Plugin", "GreenshotWin10Plugin\GreenshotWin10Plugin.csproj", "{9801F62C-540F-4BFE-9211-6405DEDE563B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{82987F1E-D7E6-4C44-B934-981D366E4672}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - azure-pipelines.yml = azure-pipelines.yml - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|x86.ActiveCfg = Debug|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|x86.Build.0 = Debug|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Any CPU.Build.0 = Release|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|x86.ActiveCfg = Release|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|x86.Build.0 = Release|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.ActiveCfg = Debug|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.Build.0 = Debug|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Any CPU.Build.0 = Release|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.ActiveCfg = Release|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.Build.0 = Release|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.ActiveCfg = Debug|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.Build.0 = Debug|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.Build.0 = Release|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.ActiveCfg = Release|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.Build.0 = Release|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.ActiveCfg = Debug|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.Build.0 = Debug|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.Build.0 = Release|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.ActiveCfg = Release|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.Build.0 = Release|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.Build.0 = Debug|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.ActiveCfg = Debug|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.Build.0 = Debug|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.ActiveCfg = Release|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.Build.0 = Release|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.ActiveCfg = Release|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.Build.0 = Release|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.ActiveCfg = Debug|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.Build.0 = Debug|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.Build.0 = Release|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.ActiveCfg = Release|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.Build.0 = Release|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.ActiveCfg = Debug|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.Build.0 = Debug|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Any CPU.Build.0 = Release|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|x86.ActiveCfg = Release|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|x86.Build.0 = Release|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|x86.ActiveCfg = Debug|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|x86.Build.0 = Debug|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Any CPU.Build.0 = Release|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|x86.ActiveCfg = Release|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|x86.Build.0 = Release|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|x86.ActiveCfg = Debug|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|x86.Build.0 = Debug|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Any CPU.Build.0 = Release|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|x86.ActiveCfg = Release|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|x86.Build.0 = Release|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|x86.ActiveCfg = Debug|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|x86.Build.0 = Debug|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Any CPU.Build.0 = Release|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|x86.ActiveCfg = Release|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|x86.Build.0 = Release|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|x86.ActiveCfg = Debug|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|x86.Build.0 = Debug|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Any CPU.Build.0 = Release|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|x86.ActiveCfg = Release|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|x86.Build.0 = Release|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|x86.ActiveCfg = Debug|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|x86.Build.0 = Debug|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Any CPU.Build.0 = Release|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|x86.ActiveCfg = Release|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|x86.Build.0 = Release|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|x86.ActiveCfg = Debug|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|x86.Build.0 = Debug|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Any CPU.Build.0 = Release|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|x86.ActiveCfg = Release|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {970967C0-60BE-4F70-9332-9ACC04B93A15} - EndGlobalSection -EndGlobal diff --git a/Greenshot.sln.DotSettings b/Greenshot.sln.DotSettings deleted file mode 100644 index aecc39af3..000000000 --- a/Greenshot.sln.DotSettings +++ /dev/null @@ -1,4 +0,0 @@ - - True - True - True \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/GreenshotBoxPlugin.Credentials.template b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template similarity index 100% rename from src/Greenshot.Plugin.Box/GreenshotBoxPlugin.Credentials.template rename to src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template diff --git a/src/Greenshot.Plugin.Box/GreenshotBoxPlugin.csproj b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj similarity index 100% rename from src/Greenshot.Plugin.Box/GreenshotBoxPlugin.csproj rename to src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj diff --git a/src/Greenshot.Plugin.Confluence/GreenshotConfluencePlugin.csproj b/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj similarity index 100% rename from src/Greenshot.Plugin.Confluence/GreenshotConfluencePlugin.csproj rename to src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj diff --git a/src/Greenshot.Plugin.Dropbox/GreenshotDropboxPlugin.Credentials.template b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.Credentials.template similarity index 100% rename from src/Greenshot.Plugin.Dropbox/GreenshotDropboxPlugin.Credentials.template rename to src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.Credentials.template diff --git a/src/Greenshot.Plugin.Dropbox/GreenshotDropboxPlugin.csproj b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj similarity index 100% rename from src/Greenshot.Plugin.Dropbox/GreenshotDropboxPlugin.csproj rename to src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj diff --git a/src/Greenshot.Plugin.ExternalCommand/GreenshotExternalCommandPlugin.csproj b/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj similarity index 100% rename from src/Greenshot.Plugin.ExternalCommand/GreenshotExternalCommandPlugin.csproj rename to src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj diff --git a/src/Greenshot.Plugin.Flickr/GreenshotFlickrPlugin.Credentials.template b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.Credentials.template similarity index 100% rename from src/Greenshot.Plugin.Flickr/GreenshotFlickrPlugin.Credentials.template rename to src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.Credentials.template diff --git a/src/Greenshot.Plugin.Flickr/GreenshotFlickrPlugin.csproj b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj similarity index 100% rename from src/Greenshot.Plugin.Flickr/GreenshotFlickrPlugin.csproj rename to src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj diff --git a/src/Greenshot.Plugin.GooglePhotos/GreenshotGooglePhotosPlugin.Credentials.template b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.Credentials.template similarity index 100% rename from src/Greenshot.Plugin.GooglePhotos/GreenshotGooglePhotosPlugin.Credentials.template rename to src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.Credentials.template diff --git a/src/Greenshot.Plugin.GooglePhotos/GreenshotGooglePhotosPlugin.csproj b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj similarity index 100% rename from src/Greenshot.Plugin.GooglePhotos/GreenshotGooglePhotosPlugin.csproj rename to src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj diff --git a/src/Greenshot.Plugin.Imgur/GreenshotImgurPlugin.Credentials.template b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.Credentials.template similarity index 100% rename from src/Greenshot.Plugin.Imgur/GreenshotImgurPlugin.Credentials.template rename to src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.Credentials.template diff --git a/src/Greenshot.Plugin.Imgur/GreenshotImgurPlugin.csproj b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj similarity index 100% rename from src/Greenshot.Plugin.Imgur/GreenshotImgurPlugin.csproj rename to src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj diff --git a/src/Greenshot.Plugin.Jira/GreenshotJiraPlugin.csproj b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj similarity index 100% rename from src/Greenshot.Plugin.Jira/GreenshotJiraPlugin.csproj rename to src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj diff --git a/src/Greenshot.Plugin.Office/GreenshotOfficePlugin.csproj b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj similarity index 100% rename from src/Greenshot.Plugin.Office/GreenshotOfficePlugin.csproj rename to src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj diff --git a/src/Greenshot.Plugin.Photobucket/GreenshotPhotobucketPlugin.Credentials.template b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.Credentials.template similarity index 100% rename from src/Greenshot.Plugin.Photobucket/GreenshotPhotobucketPlugin.Credentials.template rename to src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.Credentials.template diff --git a/src/Greenshot.Plugin.Photobucket/GreenshotPhotobucketPlugin.csproj b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj similarity index 100% rename from src/Greenshot.Plugin.Photobucket/GreenshotPhotobucketPlugin.csproj rename to src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj diff --git a/src/Greenshot.Plugin.Win10/GreenshotWin10Plugin.csproj b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj similarity index 100% rename from src/Greenshot.Plugin.Win10/GreenshotWin10Plugin.csproj rename to src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj diff --git a/src/Greenshot.sln b/src/Greenshot.sln index 1f119321e..40b3169b4 100644 --- a/src/Greenshot.sln +++ b/src/Greenshot.sln @@ -20,27 +20,27 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Gree EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPlugin", "GreenshotPlugin\GreenshotPlugin.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotExternalCommandPlugin", "GreenshotExternalCommandPlugin\GreenshotExternalCommandPlugin.csproj", "{47F23C86-604E-4CC3-8767-B3D4088F30BB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.ExternalCommand", "Greenshot.Plugin.ExternalCommand\Greenshot.Plugin.ExternalCommand.csproj", "{47F23C86-604E-4CC3-8767-B3D4088F30BB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotConfluencePlugin", "GreenshotConfluencePlugin\GreenshotConfluencePlugin.csproj", "{C3052651-598A-44E2-AAB3-2E41311D50F9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Confluence", "Greenshot.Plugin.Confluence\Greenshot.Plugin.Confluence.csproj", "{C3052651-598A-44E2-AAB3-2E41311D50F9}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotImgurPlugin", "GreenshotImgurPlugin\GreenshotImgurPlugin.csproj", "{80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Imgur", "Greenshot.Plugin.Imgur\Greenshot.Plugin.Imgur.csproj", "{80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotJiraPlugin", "GreenshotJiraPlugin\GreenshotJiraPlugin.csproj", "{19FEEF09-313F-43C7-819D-F1BCA782B08B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Jira", "Greenshot.Plugin.Jira\Greenshot.Plugin.Jira.csproj", "{19FEEF09-313F-43C7-819D-F1BCA782B08B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotBoxPlugin", "GreenshotBoxPlugin\GreenshotBoxPlugin.csproj", "{697CF066-9077-4F22-99D9-D989CCE7282B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Box", "Greenshot.Plugin.Box\Greenshot.Plugin.Box.csproj", "{697CF066-9077-4F22-99D9-D989CCE7282B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotDropboxPlugin", "GreenshotDropboxPlugin\GreenshotDropboxPlugin.csproj", "{AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Dropbox", "Greenshot.Plugin.Dropbox\Greenshot.Plugin.Dropbox.csproj", "{AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotFlickrPlugin", "GreenshotFlickrPlugin\GreenshotFlickrPlugin.csproj", "{7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Flickr", "Greenshot.Plugin.Flickr\Greenshot.Plugin.Flickr.csproj", "{7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotGooglePhotosPlugin", "GreenshotGooglePhotosPlugin\GreenshotGooglePhotosPlugin.csproj", "{1893A2E4-A78A-4713-A8E7-E70058DABEE0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.GooglePhotos", "Greenshot.Plugin.GooglePhotos\Greenshot.Plugin.GooglePhotos.csproj", "{1893A2E4-A78A-4713-A8E7-E70058DABEE0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotOfficePlugin", "GreenshotOfficePlugin\GreenshotOfficePlugin.csproj", "{92599C09-FF29-4ABD-B6E6-C48ECD781BAB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Office", "Greenshot.Plugin.Office\Greenshot.Plugin.Office.csproj", "{92599C09-FF29-4ABD-B6E6-C48ECD781BAB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPhotobucketPlugin", "GreenshotPhotobucketPlugin\GreenshotPhotobucketPlugin.csproj", "{9C0ECC4C-7807-4111-916A-4F57BB29788A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Photobucket", "Greenshot.Plugin.Photobucket\Greenshot.Plugin.Photobucket.csproj", "{9C0ECC4C-7807-4111-916A-4F57BB29788A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotWin10Plugin", "GreenshotWin10Plugin\GreenshotWin10Plugin.csproj", "{9801F62C-540F-4BFE-9211-6405DEDE563B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Win10", "Greenshot.Plugin.Win10\Greenshot.Plugin.Win10.csproj", "{9801F62C-540F-4BFE-9211-6405DEDE563B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{82987F1E-D7E6-4C44-B934-981D366E4672}" ProjectSection(SolutionItems) = preProject diff --git a/version.json b/version.json deleted file mode 100644 index 246019952..000000000 --- a/version.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "1.3", - "publicReleaseRefSpec": [ - ".*/release/*$" - ], - "nugetPackageVersion": { - "semVer": 2 - }, - "cloudBuild": { - "setVersionVariables": true, - "setAllVariables": true, - "buildNumber": { - "enabled": true, - "includeCommitId": { - "when": "never" - } - } - }, - "inherit": false -} \ No newline at end of file From 62bd0fe256a7f49cf5b3c5532faa08e47a700d82 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 28 Mar 2021 12:53:01 +0200 Subject: [PATCH 115/232] Refactoring of the namespaces --- src/Greenshot.Plugin.Box/BoxConfiguration.cs | 8 ++++---- src/Greenshot.Plugin.Box/BoxDestination.cs | 3 ++- src/Greenshot.Plugin.Box/BoxEntities.cs | 3 ++- src/Greenshot.Plugin.Box/BoxPlugin.cs | 3 ++- src/Greenshot.Plugin.Box/BoxUtils.cs | 4 ++-- src/Greenshot.Plugin.Box/Forms/BoxForm.cs | 3 ++- .../Forms/SettingsForm.Designer.cs | 2 +- src/Greenshot.Plugin.Box/Forms/SettingsForm.cs | 2 +- .../Greenshot.Plugin.Box.Credentials.template | 2 +- src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj | 6 ------ src/Greenshot.Plugin.Box/LanguageKeys.cs | 2 +- src/Greenshot.Plugin.Confluence/Confluence.cs | 2 +- .../ConfluenceConfiguration.cs | 3 ++- .../ConfluenceDestination.cs | 3 ++- src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs | 8 ++++---- src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs | 4 ++-- src/Greenshot.Plugin.Confluence/EnumDisplayer.cs | 4 ++-- .../Forms/ConfluenceConfigurationForm.xaml | 7 ++++--- .../Forms/ConfluenceConfigurationForm.xaml.cs | 2 +- .../Forms/ConfluencePagePicker.xaml | 2 +- .../Forms/ConfluencePagePicker.xaml.cs | 2 +- .../Forms/ConfluenceSearch.xaml | 4 ++-- .../Forms/ConfluenceSearch.xaml.cs | 2 +- .../Forms/ConfluenceTreePicker.xaml | 4 ++-- .../Forms/ConfluenceTreePicker.xaml.cs | 2 +- .../Forms/ConfluenceUpload.xaml | 4 ++-- .../Forms/ConfluenceUpload.xaml.cs | 2 +- .../Greenshot.Plugin.Confluence.csproj | 6 ------ src/Greenshot.Plugin.Confluence/LanguageKeys.cs | 2 +- .../Support/ITranslationProvider.cs | 2 +- .../Support/LanguageChangedEventManager.cs | 2 +- .../Support/LanguageXMLTranslationProvider.cs | 2 +- .../Support/TranslateExtension.cs | 2 +- .../Support/TranslationData.cs | 2 +- .../Support/TranslationManager.cs | 2 +- src/Greenshot.Plugin.Dropbox/DropboxDestination.cs | 3 ++- src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs | 3 ++- .../DropboxPluginConfiguration.cs | 5 ++--- src/Greenshot.Plugin.Dropbox/DropboxUtils.cs | 3 ++- src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 2 +- src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs | 2 +- .../Greenshot.Plugin.Dropbox.Credentials.template | 2 +- .../Greenshot.Plugin.Dropbox.csproj | 6 ------ src/Greenshot.Plugin.Dropbox/LanguageKeys.cs | 2 +- .../ExternalCommandConfiguration.cs | 2 +- .../ExternalCommandDestination.cs | 2 +- .../ExternalCommandForm.cs | 2 +- .../ExternalCommandPlugin.cs | 2 +- .../Greenshot.Plugin.ExternalCommand.csproj | 6 ------ src/Greenshot.Plugin.ExternalCommand/IconCache.cs | 2 +- .../SettingsForm.Designer.cs | 2 +- src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs | 2 +- .../SettingsFormDetail.Designer.cs | 2 +- .../SettingsFormDetail.cs | 2 +- src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs | 5 +++-- src/Greenshot.Plugin.Flickr/FlickrDestination.cs | 3 ++- src/Greenshot.Plugin.Flickr/FlickrPlugin.cs | 2 +- src/Greenshot.Plugin.Flickr/FlickrUtils.cs | 2 +- src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 2 +- src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs | 2 +- .../Greenshot.Plugin.Flickr.Credentials.template | 2 +- .../Greenshot.Plugin.Flickr.csproj | 6 ------ src/Greenshot.Plugin.Flickr/LanguageKeys.cs | 2 +- .../Forms/GooglePhotosForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 2 +- .../Forms/SettingsForm.cs | 2 +- .../GooglePhotosConfiguration.cs | 9 +++++---- .../GooglePhotosDestination.cs | 3 ++- .../GooglePhotosPlugin.cs | 3 ++- src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs | 4 ++-- .../Greenshot.Plugin.GooglePhotos.Credentials.template | 2 +- .../Greenshot.Plugin.GooglePhotos.csproj | 2 +- src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs | 2 +- src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs | 2 +- .../Forms/ImgurHistory.Designer.cs | 2 +- src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 2 +- src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs | 2 +- .../Greenshot.Plugin.Imgur.Credentials.template | 2 +- .../Greenshot.Plugin.Imgur.csproj | 6 ------ src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs | 4 ++-- src/Greenshot.Plugin.Imgur/ImgurDestination.cs | 3 ++- src/Greenshot.Plugin.Imgur/ImgurInfo.cs | 3 ++- src/Greenshot.Plugin.Imgur/ImgurPlugin.cs | 5 +++-- src/Greenshot.Plugin.Imgur/ImgurUtils.cs | 3 ++- src/Greenshot.Plugin.Imgur/LanguageKeys.cs | 2 +- src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs | 3 +-- src/Greenshot.Plugin.Jira/Forms/JiraForm.Designer.cs | 2 +- src/Greenshot.Plugin.Jira/Forms/JiraForm.cs | 10 +++++----- src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 2 +- src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs | 2 +- src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj | 6 ------ src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs | 2 +- src/Greenshot.Plugin.Jira/JiraConfiguration.cs | 2 +- src/Greenshot.Plugin.Jira/JiraConnector.cs | 2 +- src/Greenshot.Plugin.Jira/JiraDestination.cs | 4 ++-- src/Greenshot.Plugin.Jira/JiraDetails.cs | 2 +- src/Greenshot.Plugin.Jira/JiraEventArgs.cs | 2 +- src/Greenshot.Plugin.Jira/JiraEventTypes.cs | 2 +- src/Greenshot.Plugin.Jira/JiraMonitor.cs | 2 +- src/Greenshot.Plugin.Jira/JiraPlugin.cs | 6 +++--- src/Greenshot.Plugin.Jira/LanguageKeys.cs | 2 +- src/Greenshot.Plugin.Jira/Log4NetLogger.cs | 2 +- src/Greenshot.Plugin.Office/Com/DisposableCom.cs | 2 +- .../Com/DisposableComImplementation.cs | 2 +- src/Greenshot.Plugin.Office/Com/IDisposableCom.cs | 2 +- src/Greenshot.Plugin.Office/Com/Ole32Api.cs | 2 +- src/Greenshot.Plugin.Office/Com/OleAut32Api.cs | 2 +- .../Destinations/ExcelDestination.cs | 4 ++-- .../Destinations/OneNoteDestination.cs | 6 +++--- .../Destinations/OutlookDestination.cs | 4 ++-- .../Destinations/PowerpointDestination.cs | 4 ++-- .../Destinations/WordDestination.cs | 4 ++-- .../Greenshot.Plugin.Office.csproj | 6 ------ src/Greenshot.Plugin.Office/OfficeConfiguration.cs | 4 ++-- .../OfficeExport/Entities/OneNoteNotebook.cs | 2 +- .../OfficeExport/Entities/OneNotePage.cs | 2 +- .../OfficeExport/Entities/OneNoteSection.cs | 2 +- .../OfficeExport/ExcelExporter.cs | 6 +++--- .../OfficeExport/OneNoteExporter.cs | 6 +++--- .../OfficeExport/OutlookEmailExporter.cs | 6 +++--- .../OfficeExport/PowerpointExporter.cs | 6 +++--- .../OfficeExport/WordExporter.cs | 6 +++--- .../OfficeInterop/EmailFormat.cs | 2 +- .../OfficeInterop/OfficeVersions.cs | 2 +- src/Greenshot.Plugin.Office/OfficePlugin.cs | 5 +++-- .../Forms/PhotobucketForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 2 +- src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs | 2 +- .../Greenshot.Plugin.Photobucket.Credentials.template | 2 +- .../Greenshot.Plugin.Photobucket.csproj | 6 ------ src/Greenshot.Plugin.Photobucket/LanguageKeys.cs | 2 +- .../PhotobucketConfiguration.cs | 5 +++-- .../PhotobucketDestination.cs | 5 +++-- src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs | 3 ++- src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs | 3 ++- src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs | 3 ++- .../Destinations/Win10OcrDestination.cs | 2 +- .../Destinations/Win10ShareDestination.cs | 6 +++--- .../Greenshot.Plugin.Win10.csproj | 6 ------ .../Internal/MemoryRandomAccessStream.cs | 2 +- src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs | 2 +- .../Native/DataTransferManagerHelper.cs | 4 ++-- .../Native/IDataTransferManagerInterOp.cs | 4 ++-- .../Processors/Win10OcrProcessor.cs | 2 +- src/Greenshot.Plugin.Win10/ToastNotificationService.cs | 2 +- src/Greenshot.Plugin.Win10/Win10Configuration.cs | 2 +- src/Greenshot.Plugin.Win10/Win10OcrProvider.cs | 2 +- src/Greenshot.Plugin.Win10/Win10Plugin.cs | 6 +++--- src/GreenshotPlugin/FileDescriptorReader.cs | 2 +- 153 files changed, 223 insertions(+), 260 deletions(-) diff --git a/src/Greenshot.Plugin.Box/BoxConfiguration.cs b/src/Greenshot.Plugin.Box/BoxConfiguration.cs index b8e9e0965..a940b319e 100644 --- a/src/Greenshot.Plugin.Box/BoxConfiguration.cs +++ b/src/Greenshot.Plugin.Box/BoxConfiguration.cs @@ -19,13 +19,13 @@ * along with this program. If not, see . */ -using System.Windows.Forms; -using GreenshotPlugin.Core; using System; -using GreenshotBoxPlugin.Forms; +using System.Windows.Forms; +using Greenshot.Plugin.Box.Forms; +using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotBoxPlugin { +namespace Greenshot.Plugin.Box { /// /// Description of ImgurConfiguration. /// diff --git a/src/Greenshot.Plugin.Box/BoxDestination.cs b/src/Greenshot.Plugin.Box/BoxDestination.cs index 4283a178c..3c1a0622d 100644 --- a/src/Greenshot.Plugin.Box/BoxDestination.cs +++ b/src/Greenshot.Plugin.Box/BoxDestination.cs @@ -18,12 +18,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.ComponentModel; using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace GreenshotBoxPlugin { +namespace Greenshot.Plugin.Box { public class BoxDestination : AbstractDestination { private readonly BoxPlugin _plugin; public BoxDestination(BoxPlugin plugin) { diff --git a/src/Greenshot.Plugin.Box/BoxEntities.cs b/src/Greenshot.Plugin.Box/BoxEntities.cs index a1f1a5c61..bf5476f4e 100644 --- a/src/Greenshot.Plugin.Box/BoxEntities.cs +++ b/src/Greenshot.Plugin.Box/BoxEntities.cs @@ -18,10 +18,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.Collections.Generic; using System.Runtime.Serialization; -namespace GreenshotBoxPlugin { +namespace Greenshot.Plugin.Box { [DataContract] public class Authorization { [DataMember(Name = "access_token")] diff --git a/src/Greenshot.Plugin.Box/BoxPlugin.cs b/src/Greenshot.Plugin.Box/BoxPlugin.cs index b15835063..6a01dda9e 100644 --- a/src/Greenshot.Plugin.Box/BoxPlugin.cs +++ b/src/Greenshot.Plugin.Box/BoxPlugin.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Drawing; @@ -29,7 +30,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotBoxPlugin { +namespace Greenshot.Plugin.Box { /// /// This is the Box base code /// diff --git a/src/Greenshot.Plugin.Box/BoxUtils.cs b/src/Greenshot.Plugin.Box/BoxUtils.cs index a20447c86..22e8acf49 100644 --- a/src/Greenshot.Plugin.Box/BoxUtils.cs +++ b/src/Greenshot.Plugin.Box/BoxUtils.cs @@ -19,15 +19,15 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization.Json; using System.Text; +using GreenshotPlugin.Core; using GreenshotPlugin.Core.OAuth; using GreenshotPlugin.IniFile; -namespace GreenshotBoxPlugin { +namespace Greenshot.Plugin.Box { /// /// Description of BoxUtils. diff --git a/src/Greenshot.Plugin.Box/Forms/BoxForm.cs b/src/Greenshot.Plugin.Box/Forms/BoxForm.cs index 1ab7aed75..5bb895823 100644 --- a/src/Greenshot.Plugin.Box/Forms/BoxForm.cs +++ b/src/Greenshot.Plugin.Box/Forms/BoxForm.cs @@ -18,9 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using GreenshotPlugin.Controls; -namespace GreenshotBoxPlugin.Forms { +namespace Greenshot.Plugin.Box.Forms { public class BoxForm : GreenshotForm { } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs index 556cfe413..6b8f68242 100644 --- a/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotBoxPlugin.Forms { +namespace Greenshot.Plugin.Box.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. diff --git a/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs index 49e62fd17..1de1e7b32 100644 --- a/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotBoxPlugin.Forms { +namespace Greenshot.Plugin.Box.Forms { /// /// Description of PasswordRequestForm. /// diff --git a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template index 72cfa4b79..df6eaa0bd 100644 --- a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template +++ b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotBoxPlugin { +namespace Greenshot.Plugin.Box { /// /// This class is merely a placeholder for the file keeping the API key and secret for Box integration. /// You can set your own values here diff --git a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj index 47724aa87..990e9ddc4 100644 --- a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj +++ b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj @@ -1,10 +1,4 @@  - - - GreenshotBoxPlugin - GreenshotBoxPlugin - - PreserveNewest diff --git a/src/Greenshot.Plugin.Box/LanguageKeys.cs b/src/Greenshot.Plugin.Box/LanguageKeys.cs index 5d2491ae3..32230ebd1 100644 --- a/src/Greenshot.Plugin.Box/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Box/LanguageKeys.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotBoxPlugin { +namespace Greenshot.Plugin.Box { public enum LangKey { upload_menu_item, upload_failure, diff --git a/src/Greenshot.Plugin.Confluence/Confluence.cs b/src/Greenshot.Plugin.Confluence/Confluence.cs index bb803602c..13f5d0ab3 100644 --- a/src/Greenshot.Plugin.Confluence/Confluence.cs +++ b/src/Greenshot.Plugin.Confluence/Confluence.cs @@ -26,7 +26,7 @@ using GreenshotConfluencePlugin.confluence; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotConfluencePlugin { +namespace Greenshot.Plugin.Confluence { public class Page { public Page(RemotePage page) { Id = page.id; diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs index 5a3e7019c..a742fc45b 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs @@ -18,11 +18,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotConfluencePlugin { +namespace Greenshot.Plugin.Confluence { /// /// Description of ConfluenceConfiguration. /// diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs index d7794989a..d2661d141 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Diagnostics; @@ -31,7 +32,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotConfluencePlugin { +namespace Greenshot.Plugin.Confluence { /// /// Description of ConfluenceDestination. /// diff --git a/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs index f0014f221..4cca23c8f 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs @@ -19,16 +19,16 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core; using System; using System.Windows; -using GreenshotConfluencePlugin.Forms; -using GreenshotConfluencePlugin.Support; +using Greenshot.Plugin.Confluence.Forms; +using Greenshot.Plugin.Confluence.Support; +using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotConfluencePlugin { +namespace Greenshot.Plugin.Confluence { /// /// This is the ConfluencePlugin base code /// diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs b/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs index ccb808a0f..55a40fa8c 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs @@ -18,15 +18,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Automation; - using GreenshotPlugin.Core; -namespace GreenshotConfluencePlugin { +namespace Greenshot.Plugin.Confluence { /// /// Description of ConfluenceUtils. /// diff --git a/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs b/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs index 5358362ef..185593c87 100644 --- a/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs +++ b/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections; using System.Collections.Generic; @@ -25,10 +26,9 @@ using System.Collections.ObjectModel; using System.Globalization; using System.Reflection; using System.Windows.Data; - using GreenshotPlugin.Core; -namespace GreenshotConfluencePlugin { +namespace Greenshot.Plugin.Confluence { public class EnumDisplayer : IValueConverter { private Type _type; private IDictionary _displayValues; diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml index c6b6b48a6..2b747d831 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml @@ -1,12 +1,13 @@ - - + diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs index 9269072d4..cd31165ba 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs @@ -21,7 +21,7 @@ using System.Windows; -namespace GreenshotConfluencePlugin.Forms { +namespace Greenshot.Plugin.Confluence.Forms { /// /// Interaction logic for ConfluenceConfigurationForm.xaml /// diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml index e9ae3f97b..194d31080 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml @@ -1,4 +1,4 @@ - diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs index 4f2723c89..55ca76659 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs @@ -21,7 +21,7 @@ using System.Collections.Generic; -namespace GreenshotConfluencePlugin.Forms { +namespace Greenshot.Plugin.Confluence.Forms { /// /// Interaction logic for ConfluencePagePicker.xaml /// diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml index 073a437fe..f63185d34 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml @@ -1,8 +1,8 @@  - diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs index 0702ddff7..a39c36a39 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs @@ -25,7 +25,7 @@ using System.Linq; using System.Windows; using GreenshotPlugin.IniFile; -namespace GreenshotConfluencePlugin.Forms { +namespace Greenshot.Plugin.Confluence.Forms { public partial class ConfluenceSearch { private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection(); diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml index 4ca2a11ad..27e2a0004 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml @@ -1,8 +1,8 @@  - /// Interaction logic for ConfluenceTreePicker.xaml /// diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml index f6ec6f13a..e53ae07ac 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml @@ -1,7 +1,7 @@ - diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs index 291581a2b..276788579 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs @@ -25,7 +25,7 @@ using System.Linq; using System.Threading; using System.Windows; -namespace GreenshotConfluencePlugin.Forms { +namespace Greenshot.Plugin.Confluence.Forms { /// /// Interaction logic for ConfluenceUpload.xaml /// diff --git a/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj b/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj index 259eb96b2..79b55313a 100644 --- a/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj +++ b/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj @@ -1,10 +1,4 @@  - - - GreenshotConfluencePlugin - GreenshotConfluencePlugin - - PreserveNewest diff --git a/src/Greenshot.Plugin.Confluence/LanguageKeys.cs b/src/Greenshot.Plugin.Confluence/LanguageKeys.cs index 5ba0b2cbe..bdbd039a7 100644 --- a/src/Greenshot.Plugin.Confluence/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Confluence/LanguageKeys.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotConfluencePlugin { +namespace Greenshot.Plugin.Confluence { public enum LangKey { login_error, upload_menu_item, diff --git a/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs b/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs index 02180f036..bbabf3a0b 100644 --- a/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs +++ b/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs @@ -1,4 +1,4 @@ -namespace GreenshotConfluencePlugin.Support { +namespace Greenshot.Plugin.Confluence.Support { public interface ITranslationProvider { /// /// Translates the specified key. diff --git a/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs b/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs index c9fb55704..64cc4b0a3 100644 --- a/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs +++ b/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs @@ -1,7 +1,7 @@ using System; using System.Windows; -namespace GreenshotConfluencePlugin.Support +namespace Greenshot.Plugin.Confluence.Support { public class LanguageChangedEventManager : WeakEventManager { diff --git a/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs b/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs index 23dbc4fc1..4c98fd1b9 100644 --- a/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs +++ b/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs @@ -1,6 +1,6 @@ using GreenshotPlugin.Core; -namespace GreenshotConfluencePlugin.Support { +namespace Greenshot.Plugin.Confluence.Support { /// /// /// diff --git a/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs b/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs index 3730e7baa..8d9a6e230 100644 --- a/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs +++ b/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs @@ -2,7 +2,7 @@ using System.Windows.Data; using System.Windows.Markup; -namespace GreenshotConfluencePlugin.Support +namespace Greenshot.Plugin.Confluence.Support { /// /// The Translate Markup extension returns a binding to a TranslationData diff --git a/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs b/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs index 0b6371505..0f920efc4 100644 --- a/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs +++ b/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs @@ -2,7 +2,7 @@ using System.ComponentModel; using System.Windows; -namespace GreenshotConfluencePlugin.Support { +namespace Greenshot.Plugin.Confluence.Support { public class TranslationData : IWeakEventListener, INotifyPropertyChanged { private readonly string _key; diff --git a/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs b/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs index 472f2e27d..c9af13a4f 100644 --- a/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs +++ b/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs @@ -1,6 +1,6 @@ using System; -namespace GreenshotConfluencePlugin.Support { +namespace Greenshot.Plugin.Confluence.Support { public class TranslationManager { private static TranslationManager _translationManager; diff --git a/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs index 9762652c4..7de974307 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs @@ -18,13 +18,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.ComponentModel; using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; -namespace GreenshotDropboxPlugin { +namespace Greenshot.Plugin.Dropbox { internal class DropboxDestination : AbstractDestination { private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection(); diff --git a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs index 2977c2d36..abd83112f 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Drawing; @@ -28,7 +29,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotDropboxPlugin { +namespace Greenshot.Plugin.Dropbox { /// /// This is the Dropbox base code /// diff --git a/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs b/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs index b13622db2..1b738cdeb 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs @@ -21,12 +21,11 @@ using System; using System.Windows.Forms; -using GreenshotDropboxPlugin.Forms; +using Greenshot.Plugin.Dropbox.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; - -namespace GreenshotDropboxPlugin { +namespace Greenshot.Plugin.Dropbox { /// /// Description of ImgurConfiguration. /// diff --git a/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs index 8bf1d57b5..dd130c9bc 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.IO; @@ -28,7 +29,7 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using Newtonsoft.Json; -namespace GreenshotDropboxPlugin { +namespace Greenshot.Plugin.Dropbox { /// /// Description of DropboxUtils. /// diff --git a/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs b/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs index e0a96b5bf..c7aaecb1d 100644 --- a/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs +++ b/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs @@ -21,7 +21,7 @@ using GreenshotPlugin.Controls; -namespace GreenshotDropboxPlugin.Forms { +namespace Greenshot.Plugin.Dropbox.Forms { public class DropboxForm : GreenshotForm { } } diff --git a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs index 1baae2160..c7f21fd24 100644 --- a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotDropboxPlugin.Forms { +namespace Greenshot.Plugin.Dropbox.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. diff --git a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs index 98e1147ce..9586c9ca7 100644 --- a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotDropboxPlugin.Forms { +namespace Greenshot.Plugin.Dropbox.Forms { /// /// Description of PasswordRequestForm. /// diff --git a/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.Credentials.template b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.Credentials.template index f674f1bb7..56cde680f 100644 --- a/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.Credentials.template +++ b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotDropboxPlugin { +namespace Greenshot.Plugin.Dropbox { /// /// This class is merely a placeholder for the file keeping the API key and secret for dropbox integration. /// You can set your own values here diff --git a/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj index b24217779..0ecbf3fec 100644 --- a/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj +++ b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj @@ -1,10 +1,4 @@  - - - GreenshotDropboxPlugin - GreenshotDropboxPlugin - - PreserveNewest diff --git a/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs b/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs index 0b1ae489e..9b42f6c75 100644 --- a/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotDropboxPlugin { +namespace Greenshot.Plugin.Dropbox { public enum LangKey { upload_menu_item, upload_failure, diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs index f8981b820..e4f345f47 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs @@ -25,7 +25,7 @@ using System.IO; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotExternalCommandPlugin { +namespace Greenshot.Plugin.ExternalCommand { /// /// Description of FlickrConfiguration. /// diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs index 81575c947..df9b25352 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs @@ -31,7 +31,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotExternalCommandPlugin { +namespace Greenshot.Plugin.ExternalCommand { /// /// Description of OCRDestination. /// diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs index 6436fc988..7167b954b 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs @@ -21,7 +21,7 @@ using GreenshotPlugin.Controls; -namespace GreenshotExternalCommandPlugin { +namespace Greenshot.Plugin.ExternalCommand { /// /// This class is needed for design-time resolving of the language files /// diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs index 9389705b8..eeb99ed41 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs @@ -29,7 +29,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotExternalCommandPlugin +namespace Greenshot.Plugin.ExternalCommand { /// /// An Plugin to run commands after an image was written diff --git a/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj b/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj index 761d1278f..bb0b57ef0 100644 --- a/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj +++ b/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj @@ -1,10 +1,4 @@  - - - GreenshotExternalCommandPlugin - GreenshotExternalCommandPlugin - - PreserveNewest diff --git a/src/Greenshot.Plugin.ExternalCommand/IconCache.cs b/src/Greenshot.Plugin.ExternalCommand/IconCache.cs index bf9094c7e..44ea0a84d 100644 --- a/src/Greenshot.Plugin.ExternalCommand/IconCache.cs +++ b/src/Greenshot.Plugin.ExternalCommand/IconCache.cs @@ -25,7 +25,7 @@ using System.IO; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotExternalCommandPlugin { +namespace Greenshot.Plugin.ExternalCommand { public static class IconCache { private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection(); private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(IconCache)); diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs index f0a000f9b..9795bd93f 100644 --- a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotExternalCommandPlugin { +namespace Greenshot.Plugin.ExternalCommand { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs index 01eea89bf..c4cf9ca2b 100644 --- a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs @@ -24,7 +24,7 @@ using System.Drawing; using System.Windows.Forms; using GreenshotPlugin.IniFile; -namespace GreenshotExternalCommandPlugin { +namespace Greenshot.Plugin.ExternalCommand { /// /// Description of SettingsForm. /// diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs index dd928449d..11d8dc346 100644 --- a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotExternalCommandPlugin { +namespace Greenshot.Plugin.ExternalCommand { partial class SettingsFormDetail { /// /// Designer variable used to keep track of non-visual components. diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs index 8affd6976..9c353b197 100644 --- a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs @@ -26,7 +26,7 @@ using System.Windows.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotExternalCommandPlugin { +namespace Greenshot.Plugin.ExternalCommand { /// /// Description of SettingsFormDetail. /// diff --git a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs index 06f65c9fd..600e61a47 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs @@ -18,12 +18,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.Windows.Forms; -using GreenshotFlickrPlugin.Forms; +using Greenshot.Plugin.Flickr.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotFlickrPlugin { +namespace Greenshot.Plugin.Flickr { public enum SafetyLevel { Safe = 1, Moderate = 2, diff --git a/src/Greenshot.Plugin.Flickr/FlickrDestination.cs b/src/Greenshot.Plugin.Flickr/FlickrDestination.cs index ccd9392d2..340cf3c09 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrDestination.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrDestination.cs @@ -18,12 +18,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.ComponentModel; using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace GreenshotFlickrPlugin { +namespace Greenshot.Plugin.Flickr { public class FlickrDestination : AbstractDestination { private readonly FlickrPlugin _plugin; public FlickrDestination(FlickrPlugin plugin) { diff --git a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs index abf663625..62f21a509 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs @@ -31,7 +31,7 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using log4net; -namespace GreenshotFlickrPlugin +namespace Greenshot.Plugin.Flickr { /// /// This is the Flickr base code diff --git a/src/Greenshot.Plugin.Flickr/FlickrUtils.cs b/src/Greenshot.Plugin.Flickr/FlickrUtils.cs index 9337c51f6..c6978a17d 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrUtils.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrUtils.cs @@ -30,7 +30,7 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using log4net; -namespace GreenshotFlickrPlugin { +namespace Greenshot.Plugin.Flickr { /// /// Description of FlickrUtils. /// diff --git a/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs b/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs index 94e161d64..74e032708 100644 --- a/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs @@ -21,7 +21,7 @@ using GreenshotPlugin.Controls; -namespace GreenshotFlickrPlugin.Forms { +namespace Greenshot.Plugin.Flickr.Forms { public class FlickrForm : GreenshotForm { } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs index 18001eab2..c58fe2720 100644 --- a/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotFlickrPlugin.Forms { +namespace Greenshot.Plugin.Flickr.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. diff --git a/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs index 59d0e3cbf..eba638160 100644 --- a/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotFlickrPlugin.Forms { +namespace Greenshot.Plugin.Flickr.Forms { /// /// Description of PasswordRequestForm. /// diff --git a/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.Credentials.template b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.Credentials.template index fb69e4460..0d7c50529 100644 --- a/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.Credentials.template +++ b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotFlickrPlugin { +namespace Greenshot.Plugin.Flickr { /// /// This class is merely a placeholder for the file keeping the API key and secret for dropbox integration. /// You can set your own values here diff --git a/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj index 9c7a8c597..b0acd56db 100644 --- a/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj +++ b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj @@ -1,10 +1,4 @@  - - - GreenshotFlickrPlugin - GreenshotFlickrPlugin - - PreserveNewest diff --git a/src/Greenshot.Plugin.Flickr/LanguageKeys.cs b/src/Greenshot.Plugin.Flickr/LanguageKeys.cs index ae3a6af02..d347faa0a 100644 --- a/src/Greenshot.Plugin.Flickr/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Flickr/LanguageKeys.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotFlickrPlugin { +namespace Greenshot.Plugin.Flickr { public enum LangKey { upload_menu_item, upload_failure, diff --git a/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs index 10b18bebe..1b3c76816 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs @@ -20,7 +20,7 @@ using GreenshotPlugin.Controls; -namespace GreenshotGooglePhotosPlugin.Forms { +namespace Greenshot.Plugin.GooglePhotos.Forms { public class GooglePhotosForm : GreenshotForm { } } diff --git a/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs index cea2b6acf..6b95cbc46 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs @@ -17,7 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotGooglePhotosPlugin.Forms { +namespace Greenshot.Plugin.GooglePhotos.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. diff --git a/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs index be31f1d44..3946baf1b 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -namespace GreenshotGooglePhotosPlugin.Forms { +namespace Greenshot.Plugin.GooglePhotos.Forms { /// /// Description of PasswordRequestForm. /// diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs index 7e1b614b2..d11d797d1 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs @@ -17,13 +17,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -using System.Windows.Forms; -using GreenshotPlugin.Core; + using System; -using GreenshotGooglePhotosPlugin.Forms; +using System.Windows.Forms; +using Greenshot.Plugin.GooglePhotos.Forms; +using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotGooglePhotosPlugin { +namespace Greenshot.Plugin.GooglePhotos { /// /// Description of GooglePhotosConfiguration. /// diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs index 586a6e842..2948773ce 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs @@ -17,12 +17,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.ComponentModel; using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace GreenshotGooglePhotosPlugin { +namespace Greenshot.Plugin.GooglePhotos { public class GooglePhotosDestination : AbstractDestination { private readonly GooglePhotosPlugin _plugin; public GooglePhotosDestination(GooglePhotosPlugin plugin) { diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs index b5d37f62c..ed1727c05 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs @@ -17,6 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Drawing; @@ -28,7 +29,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotGooglePhotosPlugin { +namespace Greenshot.Plugin.GooglePhotos { /// /// This is the GooglePhotos base code /// diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs index 27aa13d8f..a11edf090 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs @@ -18,15 +18,15 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core; using System; using System.Xml; +using GreenshotPlugin.Core; using GreenshotPlugin.Core.OAuth; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotGooglePhotosPlugin { +namespace Greenshot.Plugin.GooglePhotos { /// /// Description of GooglePhotosUtils. /// diff --git a/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.Credentials.template b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.Credentials.template index 452922112..c4ff6bfc6 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.Credentials.template +++ b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotGooglePhotosPlugin { +namespace Greenshot.Plugin.GooglePhotos { /// /// This class is merely a placeholder for the file keeping the API key and secret for dropbox integration. /// You can set your own values here diff --git a/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj index 3fb62aa99..b15368c8e 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj +++ b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs b/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs index 1a7a73996..34feda885 100644 --- a/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs +++ b/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -namespace GreenshotGooglePhotosPlugin { +namespace Greenshot.Plugin.GooglePhotos { public enum LangKey { upload_menu_item, diff --git a/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs index 37316ac99..c4fb88791 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs @@ -21,7 +21,7 @@ using GreenshotPlugin.Controls; -namespace GreenshotImgurPlugin.Forms { +namespace Greenshot.Plugin.Imgur.Forms { /// /// This class is needed for design-time resolving of the language files /// diff --git a/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.Designer.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.Designer.cs index f8fb05dd2..9b0b5d923 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.Designer.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotImgurPlugin.Forms +namespace Greenshot.Plugin.Imgur.Forms { partial class ImgurHistory { diff --git a/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs index 359130a90..3b2efcd48 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs @@ -27,7 +27,7 @@ using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotImgurPlugin.Forms { +namespace Greenshot.Plugin.Imgur.Forms { /// /// Imgur history form /// diff --git a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs index 79192da09..175c55bb4 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotImgurPlugin.Forms { +namespace Greenshot.Plugin.Imgur.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. diff --git a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs index 2ce863660..1ece15fb9 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs @@ -21,7 +21,7 @@ using System; -namespace GreenshotImgurPlugin.Forms { +namespace Greenshot.Plugin.Imgur.Forms { /// /// Description of PasswordRequestForm. /// diff --git a/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.Credentials.template b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.Credentials.template index 4c6948fea..eaf70d311 100644 --- a/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.Credentials.template +++ b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotImgurPlugin { +namespace Greenshot.Plugin.Imgur { /// /// This class is merely a placeholder for the file keeping the API key and secret for imgur integration. /// You can set your own values here diff --git a/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj index 9e75ecc5b..170d0aedf 100644 --- a/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj +++ b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj @@ -1,10 +1,4 @@  - - - GreenshotImgurPlugin - GreenshotImgurPlugin - - PreserveNewest diff --git a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs index d487c2387..e9725a2d2 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs @@ -22,11 +22,11 @@ using System; using System.Collections.Generic; using System.Windows.Forms; -using GreenshotImgurPlugin.Forms; +using Greenshot.Plugin.Imgur.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotImgurPlugin { +namespace Greenshot.Plugin.Imgur { /// /// Description of ImgurConfiguration. /// diff --git a/src/Greenshot.Plugin.Imgur/ImgurDestination.cs b/src/Greenshot.Plugin.Imgur/ImgurDestination.cs index 5303ac295..aa24ad68c 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurDestination.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurDestination.cs @@ -18,12 +18,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.ComponentModel; using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace GreenshotImgurPlugin { +namespace Greenshot.Plugin.Imgur { /// /// Description of ImgurDestination. /// diff --git a/src/Greenshot.Plugin.Imgur/ImgurInfo.cs b/src/Greenshot.Plugin.Imgur/ImgurInfo.cs index 85ec5b39e..5dc82ec2a 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurInfo.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurInfo.cs @@ -18,11 +18,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Xml; -namespace GreenshotImgurPlugin +namespace Greenshot.Plugin.Imgur { /// /// Description of ImgurInfo. diff --git a/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs index d87c91f8e..ef2edfe4b 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs @@ -18,20 +18,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; -using GreenshotImgurPlugin.Forms; +using Greenshot.Plugin.Imgur.Forms; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotImgurPlugin { +namespace Greenshot.Plugin.Imgur { /// /// This is the ImgurPlugin code /// diff --git a/src/Greenshot.Plugin.Imgur/ImgurUtils.cs b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs index 6c4b06674..e80aa0f49 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurUtils.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.IO; @@ -29,7 +30,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotImgurPlugin { +namespace Greenshot.Plugin.Imgur { /// /// A collection of Imgur helper methods /// diff --git a/src/Greenshot.Plugin.Imgur/LanguageKeys.cs b/src/Greenshot.Plugin.Imgur/LanguageKeys.cs index cfde3c940..9643fb92c 100644 --- a/src/Greenshot.Plugin.Imgur/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Imgur/LanguageKeys.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotImgurPlugin { +namespace Greenshot.Plugin.Imgur { public enum LangKey { upload_menu_item, upload_failure, diff --git a/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs b/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs index af34e769e..382e61c87 100644 --- a/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs +++ b/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs @@ -25,8 +25,7 @@ using System.Threading; using System.Threading.Tasks; using Dapplo.Log; - -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { /// /// This abstract class builds a base for a simple async memory cache. diff --git a/src/Greenshot.Plugin.Jira/Forms/JiraForm.Designer.cs b/src/Greenshot.Plugin.Jira/Forms/JiraForm.Designer.cs index bcd10427a..d63fea453 100644 --- a/src/Greenshot.Plugin.Jira/Forms/JiraForm.Designer.cs +++ b/src/Greenshot.Plugin.Jira/Forms/JiraForm.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotJiraPlugin.Forms { +namespace Greenshot.Plugin.Jira.Forms { partial class JiraForm { /// /// Required designer variable. diff --git a/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs index b9e4c3df8..3c3cad44d 100644 --- a/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs +++ b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs @@ -20,17 +20,17 @@ */ using System; -using System.Windows.Forms; -using Dapplo.Jira.Entities; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; +using System.Windows.Forms; +using Dapplo.Jira.Entities; +using GreenshotPlugin.Controls; +using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotJiraPlugin.Forms { +namespace Greenshot.Plugin.Jira.Forms { public partial class JiraForm : Form { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraForm)); private readonly JiraConnector _jiraConnector; diff --git a/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs b/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs index efc4d0201..caf947779 100644 --- a/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs +++ b/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs @@ -21,7 +21,7 @@ using GreenshotPlugin.Controls; -namespace GreenshotJiraPlugin.Forms { +namespace Greenshot.Plugin.Jira.Forms { public class JiraFormBase : GreenshotForm { } } diff --git a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs index 0b0195cf4..3e18edb8e 100644 --- a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotJiraPlugin.Forms { +namespace Greenshot.Plugin.Jira.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. diff --git a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs index 043df8f8b..9871fd74f 100644 --- a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotJiraPlugin.Forms { +namespace Greenshot.Plugin.Jira.Forms { /// /// Description of PasswordRequestForm. /// diff --git a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj index d37465111..cda65dc2f 100644 --- a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj +++ b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj @@ -1,10 +1,4 @@  - - - GreenshotJiraPlugin - GreenshotJiraPlugin - - PreserveNewest diff --git a/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs b/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs index c37cee314..a1eab6112 100644 --- a/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs +++ b/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs @@ -26,7 +26,7 @@ using System.Threading.Tasks; using Dapplo.Jira; using Dapplo.Jira.Entities; -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { /// /// This is the bach for the IssueType bitmaps diff --git a/src/Greenshot.Plugin.Jira/JiraConfiguration.cs b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs index f54132b04..50a521bef 100644 --- a/src/Greenshot.Plugin.Jira/JiraConfiguration.cs +++ b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs @@ -22,7 +22,7 @@ using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotJiraPlugin { +namespace Greenshot.Plugin.Jira { /// /// Description of JiraConfiguration. /// diff --git a/src/Greenshot.Plugin.Jira/JiraConnector.cs b/src/Greenshot.Plugin.Jira/JiraConnector.cs index 6bf5739fe..d16a4b235 100644 --- a/src/Greenshot.Plugin.Jira/JiraConnector.cs +++ b/src/Greenshot.Plugin.Jira/JiraConnector.cs @@ -34,7 +34,7 @@ using Dapplo.Jira.SvgWinForms.Converters; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotJiraPlugin { +namespace Greenshot.Plugin.Jira { /// /// This encapsulates the JiraClient to make it possible to change as less old Greenshot code as needed /// diff --git a/src/Greenshot.Plugin.Jira/JiraDestination.cs b/src/Greenshot.Plugin.Jira/JiraDestination.cs index 080ec8619..9bc66dd1b 100644 --- a/src/Greenshot.Plugin.Jira/JiraDestination.cs +++ b/src/Greenshot.Plugin.Jira/JiraDestination.cs @@ -27,14 +27,14 @@ using System.IO; using System.Windows.Forms; using Dapplo.HttpExtensions; using Dapplo.Jira.Entities; -using GreenshotJiraPlugin.Forms; +using Greenshot.Plugin.Jira.Forms; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotJiraPlugin { +namespace Greenshot.Plugin.Jira { /// /// Description of JiraDestination. /// diff --git a/src/Greenshot.Plugin.Jira/JiraDetails.cs b/src/Greenshot.Plugin.Jira/JiraDetails.cs index 67bbc0f61..c0ce97a50 100644 --- a/src/Greenshot.Plugin.Jira/JiraDetails.cs +++ b/src/Greenshot.Plugin.Jira/JiraDetails.cs @@ -22,7 +22,7 @@ using System; using Dapplo.Jira.Entities; -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { public class JiraDetails : IComparable { diff --git a/src/Greenshot.Plugin.Jira/JiraEventArgs.cs b/src/Greenshot.Plugin.Jira/JiraEventArgs.cs index eb60e5fcf..a3b5bdeb9 100644 --- a/src/Greenshot.Plugin.Jira/JiraEventArgs.cs +++ b/src/Greenshot.Plugin.Jira/JiraEventArgs.cs @@ -21,7 +21,7 @@ using System; -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { public class JiraEventArgs : EventArgs { diff --git a/src/Greenshot.Plugin.Jira/JiraEventTypes.cs b/src/Greenshot.Plugin.Jira/JiraEventTypes.cs index 37e62cab1..704fa182a 100644 --- a/src/Greenshot.Plugin.Jira/JiraEventTypes.cs +++ b/src/Greenshot.Plugin.Jira/JiraEventTypes.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { public enum JiraEventTypes { diff --git a/src/Greenshot.Plugin.Jira/JiraMonitor.cs b/src/Greenshot.Plugin.Jira/JiraMonitor.cs index 65b73924a..9a4ff1c7e 100644 --- a/src/Greenshot.Plugin.Jira/JiraMonitor.cs +++ b/src/Greenshot.Plugin.Jira/JiraMonitor.cs @@ -29,7 +29,7 @@ using Dapplo.Jira; using Dapplo.Log; using GreenshotPlugin.Hooking; -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { /// diff --git a/src/Greenshot.Plugin.Jira/JiraPlugin.cs b/src/Greenshot.Plugin.Jira/JiraPlugin.cs index d58978328..8ab273768 100644 --- a/src/Greenshot.Plugin.Jira/JiraPlugin.cs +++ b/src/Greenshot.Plugin.Jira/JiraPlugin.cs @@ -19,18 +19,18 @@ * along with this program. If not, see . */ -using System.Windows.Forms; using System; using System.Threading.Tasks; +using System.Windows.Forms; using Dapplo.Log; -using GreenshotJiraPlugin.Forms; +using Greenshot.Plugin.Jira.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using log4net; -namespace GreenshotJiraPlugin { +namespace Greenshot.Plugin.Jira { /// /// This is the JiraPlugin base code /// diff --git a/src/Greenshot.Plugin.Jira/LanguageKeys.cs b/src/Greenshot.Plugin.Jira/LanguageKeys.cs index 6820d5d50..a387b44d0 100644 --- a/src/Greenshot.Plugin.Jira/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Jira/LanguageKeys.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotJiraPlugin { +namespace Greenshot.Plugin.Jira { public enum LangKey { upload_menu_item, column_assignee, diff --git a/src/Greenshot.Plugin.Jira/Log4NetLogger.cs b/src/Greenshot.Plugin.Jira/Log4NetLogger.cs index d7b8d601c..12a4ac01a 100644 --- a/src/Greenshot.Plugin.Jira/Log4NetLogger.cs +++ b/src/Greenshot.Plugin.Jira/Log4NetLogger.cs @@ -22,7 +22,7 @@ using Dapplo.Log; using log4net; -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { /// /// Used to make Dapplo.Log, used in Dapplo.Jira, write to Log4net diff --git a/src/Greenshot.Plugin.Office/Com/DisposableCom.cs b/src/Greenshot.Plugin.Office/Com/DisposableCom.cs index 1fc17a78b..5d969d0be 100644 --- a/src/Greenshot.Plugin.Office/Com/DisposableCom.cs +++ b/src/Greenshot.Plugin.Office/Com/DisposableCom.cs @@ -1,6 +1,6 @@ // Copyright (c) Dapplo and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace GreenshotOfficePlugin.Com +namespace Greenshot.Plugin.Office.Com { /// /// A factory for IDisposableCom diff --git a/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs b/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs index e7a52baac..3f721fc38 100644 --- a/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs +++ b/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.InteropServices; -namespace GreenshotOfficePlugin.Com +namespace Greenshot.Plugin.Office.Com { /// /// Implementation of the IDisposableCom, this is internal to prevent other code to use it directly diff --git a/src/Greenshot.Plugin.Office/Com/IDisposableCom.cs b/src/Greenshot.Plugin.Office/Com/IDisposableCom.cs index 6bf1327c7..d99b6f4c6 100644 --- a/src/Greenshot.Plugin.Office/Com/IDisposableCom.cs +++ b/src/Greenshot.Plugin.Office/Com/IDisposableCom.cs @@ -3,7 +3,7 @@ using System; -namespace GreenshotOfficePlugin.Com +namespace Greenshot.Plugin.Office.Com { /// /// A simple com wrapper which helps with "using" diff --git a/src/Greenshot.Plugin.Office/Com/Ole32Api.cs b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs index d80167022..60167897e 100644 --- a/src/Greenshot.Plugin.Office/Com/Ole32Api.cs +++ b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; using GreenshotPlugin.Core; using GreenshotPlugin.Core.Enums; -namespace GreenshotOfficePlugin.Com +namespace Greenshot.Plugin.Office.Com { /// /// This provides an API for OLE32 diff --git a/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs index 6a3e4284c..1c38477b9 100644 --- a/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs +++ b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; using GreenshotPlugin.Core; using GreenshotPlugin.Core.Enums; -namespace GreenshotOfficePlugin.Com +namespace Greenshot.Plugin.Office.Com { /// /// API for OLEAUT32 diff --git a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs index dfd0ed7e0..571ebc7c4 100644 --- a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs @@ -23,12 +23,12 @@ using System.Collections.Generic; using System.Drawing; using System.IO; using System.Text.RegularExpressions; -using GreenshotOfficePlugin.OfficeExport; +using Greenshot.Plugin.Office.OfficeExport; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotOfficePlugin.Destinations { +namespace Greenshot.Plugin.Office.Destinations { /// /// Description of PowerpointDestination. /// diff --git a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs index df833c6a1..d638682f7 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs @@ -23,12 +23,12 @@ using System; using System.Collections.Generic; using System.Drawing; using System.IO; -using GreenshotOfficePlugin.OfficeExport; -using GreenshotOfficePlugin.OfficeExport.Entities; +using Greenshot.Plugin.Office.OfficeExport; +using Greenshot.Plugin.Office.OfficeExport.Entities; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace GreenshotOfficePlugin.Destinations { +namespace Greenshot.Plugin.Office.Destinations { public class OneNoteDestination : AbstractDestination { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WordDestination)); private const int ICON_APPLICATION = 0; diff --git a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs index f08269c51..5f5182235 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs @@ -24,7 +24,7 @@ using System.Drawing; using System.IO; using System.Text.RegularExpressions; using System.Windows.Forms; -using GreenshotOfficePlugin.OfficeExport; +using Greenshot.Plugin.Office.OfficeExport; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; @@ -32,7 +32,7 @@ using GreenshotPlugin.Interfaces.Plugin; using Microsoft.Office.Interop.Outlook; using Microsoft.Win32; -namespace GreenshotOfficePlugin.Destinations { +namespace Greenshot.Plugin.Office.Destinations { /// /// Description of OutlookDestination. /// diff --git a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs index 3e3700e4c..1382a316a 100644 --- a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs @@ -24,12 +24,12 @@ using System.Drawing; using System.IO; using System.Linq; using System.Text.RegularExpressions; -using GreenshotOfficePlugin.OfficeExport; +using Greenshot.Plugin.Office.OfficeExport; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotOfficePlugin.Destinations { +namespace Greenshot.Plugin.Office.Destinations { /// /// Description of PowerpointDestination. /// diff --git a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs index a7d630d1d..4f85dd99e 100644 --- a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs @@ -25,12 +25,12 @@ using System.Drawing; using System.IO; using System.Linq; using System.Text.RegularExpressions; -using GreenshotOfficePlugin.OfficeExport; +using Greenshot.Plugin.Office.OfficeExport; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotOfficePlugin.Destinations { +namespace Greenshot.Plugin.Office.Destinations { /// /// Description of EmailDestination. /// diff --git a/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj index f6f07e98d..2ca43d6fe 100644 --- a/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj +++ b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj @@ -1,10 +1,4 @@  - - - GreenshotOfficePlugin - GreenshotOfficePlugin - - PreserveNewest diff --git a/src/Greenshot.Plugin.Office/OfficeConfiguration.cs b/src/Greenshot.Plugin.Office/OfficeConfiguration.cs index 7064715fd..eaf118d6a 100644 --- a/src/Greenshot.Plugin.Office/OfficeConfiguration.cs +++ b/src/Greenshot.Plugin.Office/OfficeConfiguration.cs @@ -19,11 +19,11 @@ * along with this program. If not, see . */ -using GreenshotOfficePlugin.OfficeInterop; +using Greenshot.Plugin.Office.OfficeInterop; using GreenshotPlugin.IniFile; using Microsoft.Office.Interop.PowerPoint; -namespace GreenshotOfficePlugin { +namespace Greenshot.Plugin.Office { /// /// Description of CoreConfiguration. diff --git a/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteNotebook.cs b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteNotebook.cs index 40bf4255e..861ad8927 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteNotebook.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteNotebook.cs @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -namespace GreenshotOfficePlugin.OfficeExport.Entities +namespace Greenshot.Plugin.Office.OfficeExport.Entities { /// /// Container for transporting notebook information diff --git a/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs index 6bc67084b..685fc4e18 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -namespace GreenshotOfficePlugin.OfficeExport.Entities +namespace Greenshot.Plugin.Office.OfficeExport.Entities { /// /// Container for transporting Page information diff --git a/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteSection.cs b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteSection.cs index 00eafb5ae..6464ee2c4 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteSection.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteSection.cs @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -namespace GreenshotOfficePlugin.OfficeExport.Entities +namespace Greenshot.Plugin.Office.OfficeExport.Entities { /// /// Container for transporting section information diff --git a/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs index ad92c6743..f508208f7 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs @@ -20,14 +20,14 @@ using System; using System.Collections.Generic; using System.Drawing; -using GreenshotOfficePlugin.Com; -using GreenshotOfficePlugin.OfficeInterop; +using Greenshot.Plugin.Office.Com; +using Greenshot.Plugin.Office.OfficeInterop; using GreenshotPlugin.UnmanagedHelpers; using Microsoft.Office.Core; using Microsoft.Office.Interop.Excel; using Version = System.Version; -namespace GreenshotOfficePlugin.OfficeExport +namespace Greenshot.Plugin.Office.OfficeExport { /// /// Excel exporter diff --git a/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs index 5b0fcb8c5..4936315bc 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs @@ -22,14 +22,14 @@ using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Xml; -using GreenshotOfficePlugin.Com; -using GreenshotOfficePlugin.OfficeExport.Entities; +using Greenshot.Plugin.Office.Com; +using Greenshot.Plugin.Office.OfficeExport.Entities; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using Microsoft.Office.Interop.OneNote; -namespace GreenshotOfficePlugin.OfficeExport +namespace Greenshot.Plugin.Office.OfficeExport { /// /// OneNote exporter diff --git a/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs index 40306ecf7..93fc68567 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs @@ -21,8 +21,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; -using GreenshotOfficePlugin.Com; -using GreenshotOfficePlugin.OfficeInterop; +using Greenshot.Plugin.Office.Com; +using Greenshot.Plugin.Office.OfficeInterop; using GreenshotPlugin.IniFile; using Microsoft.Office.Interop.Outlook; using Microsoft.Office.Interop.Word; @@ -32,7 +32,7 @@ using Application = Microsoft.Office.Interop.Outlook.Application; using Exception = System.Exception; using Version = System.Version; -namespace GreenshotOfficePlugin.OfficeExport +namespace Greenshot.Plugin.Office.OfficeExport { /// /// Outlook exporter has all the functionality to export to outlook diff --git a/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs index 7f87ff111..aaa473ddf 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs @@ -20,14 +20,14 @@ using System; using System.Collections.Generic; using System.Drawing; -using GreenshotOfficePlugin.Com; -using GreenshotOfficePlugin.OfficeInterop; +using Greenshot.Plugin.Office.Com; +using Greenshot.Plugin.Office.OfficeInterop; using GreenshotPlugin.IniFile; using Microsoft.Office.Core; using Microsoft.Office.Interop.PowerPoint; using Shape = Microsoft.Office.Interop.PowerPoint.Shape; -namespace GreenshotOfficePlugin.OfficeExport +namespace Greenshot.Plugin.Office.OfficeExport { /// /// Export logic for powerpoint diff --git a/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs index b44f08161..ce4da64d2 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs @@ -19,14 +19,14 @@ using System; using System.Collections.Generic; -using GreenshotOfficePlugin.Com; -using GreenshotOfficePlugin.OfficeInterop; +using Greenshot.Plugin.Office.Com; +using Greenshot.Plugin.Office.OfficeInterop; using GreenshotPlugin.IniFile; using Microsoft.Office.Core; using Microsoft.Office.Interop.Word; using Version = System.Version; -namespace GreenshotOfficePlugin.OfficeExport +namespace Greenshot.Plugin.Office.OfficeExport { /// /// This makes it possible to export to word diff --git a/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs b/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs index 2de5cbf71..55c347c5e 100644 --- a/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs +++ b/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -namespace GreenshotOfficePlugin.OfficeInterop +namespace Greenshot.Plugin.Office.OfficeInterop { /// /// Specifies which EmailFormat the email needs to use diff --git a/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs b/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs index 3988148c5..ef74d6f9a 100644 --- a/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs +++ b/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -namespace GreenshotOfficePlugin.OfficeInterop +namespace Greenshot.Plugin.Office.OfficeInterop { /// /// A mapping between the version and a usable name diff --git a/src/Greenshot.Plugin.Office/OfficePlugin.cs b/src/Greenshot.Plugin.Office/OfficePlugin.cs index 6a17626a8..7abdecf02 100644 --- a/src/Greenshot.Plugin.Office/OfficePlugin.cs +++ b/src/Greenshot.Plugin.Office/OfficePlugin.cs @@ -18,14 +18,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; -using GreenshotOfficePlugin.Destinations; +using Greenshot.Plugin.Office.Destinations; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotOfficePlugin { +namespace Greenshot.Plugin.Office { /// /// This is the OfficePlugin base code /// diff --git a/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs b/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs index 70971ca61..09e3bc3ca 100644 --- a/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs +++ b/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPhotobucketPlugin.Forms { +namespace Greenshot.Plugin.Photobucket.Forms { /// /// This class is needed for design-time resolving of the language files /// diff --git a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs index 4a0486dd1..85d3a588b 100644 --- a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotPhotobucketPlugin.Forms { +namespace Greenshot.Plugin.Photobucket.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. diff --git a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs index 1d221b2a9..9d380bdd8 100644 --- a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPhotobucketPlugin.Forms { +namespace Greenshot.Plugin.Photobucket.Forms { /// /// Description of PasswordRequestForm. /// diff --git a/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.Credentials.template b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.Credentials.template index 312099888..8895f5a73 100644 --- a/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.Credentials.template +++ b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPhotobucketPlugin { +namespace Greenshot.Plugin.Photobucket { /// /// This class is merely a placeholder for the file keeping the API key and secret for photobucket integration. /// You can set your own values here diff --git a/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj index bab11d46e..bb0b57ef0 100644 --- a/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj +++ b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj @@ -1,10 +1,4 @@  - - - GreenshotPhotobucketPlugin - GreenshotPhotobucketPlugin - - PreserveNewest diff --git a/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs b/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs index 010c4fda0..8795b92f0 100644 --- a/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPhotobucketPlugin { +namespace Greenshot.Plugin.Photobucket { public enum LangKey { upload_menu_item, upload_failure, diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs index c852c0c81..cf2501cd0 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs @@ -18,13 +18,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.Windows.Forms; -using GreenshotPhotobucketPlugin.Forms; +using Greenshot.Plugin.Photobucket.Forms; using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace GreenshotPhotobucketPlugin { +namespace Greenshot.Plugin.Photobucket { /// /// Description of PhotobucketConfiguration. /// diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs index 96dc98926..564e64511 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs @@ -18,13 +18,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -using System.ComponentModel; + using System.Collections.Generic; +using System.ComponentModel; using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace GreenshotPhotobucketPlugin { +namespace Greenshot.Plugin.Photobucket { /// /// Description of PhotobucketDestination. /// diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs index b9759eb3c..98b3b7517 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs @@ -18,10 +18,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Xml; -namespace GreenshotPhotobucketPlugin +namespace Greenshot.Plugin.Photobucket { /// /// Description of PhotobucketInfo. diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs index a9670a6a2..b45f563e0 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Drawing; @@ -29,7 +30,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotPhotobucketPlugin { +namespace Greenshot.Plugin.Photobucket { /// /// This is the GreenshotPhotobucketPlugin base code /// diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs index bb59ff09a..eeda1ae74 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections; using System.Collections.Generic; @@ -29,7 +30,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotPhotobucketPlugin { +namespace Greenshot.Plugin.Photobucket { /// /// Description of PhotobucketUtils. /// diff --git a/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs index 3bcad532d..616960615 100644 --- a/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs +++ b/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs @@ -27,7 +27,7 @@ using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; -namespace GreenshotWin10Plugin.Destinations +namespace Greenshot.Plugin.Win10.Destinations { /// /// This uses the OcrEngine from Windows 10 to perform OCR on the captured image. diff --git a/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs index fb52ef925..2581dc586 100644 --- a/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs +++ b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs @@ -29,15 +29,15 @@ using System.Windows.Interop; using System.Windows.Media; using Windows.Storage; using Windows.Storage.Streams; +using Greenshot.Plugin.Win10.Internal; +using Greenshot.Plugin.Win10.Native; using GreenshotPlugin.Core; using GreenshotPlugin.Hooking; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -using GreenshotWin10Plugin.Internal; -using GreenshotWin10Plugin.Native; using Color = Windows.UI.Color; -namespace GreenshotWin10Plugin.Destinations +namespace Greenshot.Plugin.Win10.Destinations { /// /// This uses the Share from Windows 10 to make the capture available to apps. diff --git a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj index 2c8237637..bd79af992 100644 --- a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj +++ b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj @@ -1,10 +1,4 @@  - - - GreenshotWin10Plugin - GreenshotWin10Plugin - - PreserveNewest diff --git a/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs b/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs index e342f87ae..e4a49c64e 100644 --- a/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs +++ b/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs @@ -22,7 +22,7 @@ using System.IO; using Windows.Storage.Streams; -namespace GreenshotWin10Plugin.Internal +namespace Greenshot.Plugin.Win10.Internal { /// /// This is an IRandomAccessStream implementation which uses a MemoryStream diff --git a/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs b/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs index 7516de371..44b0d529b 100644 --- a/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs +++ b/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs @@ -23,7 +23,7 @@ using System; using System.Threading.Tasks; using Windows.ApplicationModel.DataTransfer; -namespace GreenshotWin10Plugin.Internal +namespace Greenshot.Plugin.Win10.Internal { internal class ShareInfo { diff --git a/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs index 2594b4338..192e818ec 100644 --- a/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs +++ b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs @@ -19,12 +19,12 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core; using System; using System.Runtime.InteropServices.WindowsRuntime; using Windows.ApplicationModel.DataTransfer; +using GreenshotPlugin.Core; -namespace GreenshotWin10Plugin.Native +namespace Greenshot.Plugin.Win10.Native { /// /// Wraps the interop for calling the ShareUI diff --git a/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs index 14fb4c8eb..dc477aac8 100644 --- a/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs +++ b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs @@ -17,12 +17,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using GreenshotPlugin.Core.Enums; using System; using System.Runtime.InteropServices; using Windows.ApplicationModel.DataTransfer; +using GreenshotPlugin.Core.Enums; -namespace GreenshotWin10Plugin.Native +namespace Greenshot.Plugin.Win10.Native { /// /// The IDataTransferManagerInterOp is documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/jj542488(v=vs.85).aspx. diff --git a/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs b/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs index 341153eab..c70c6fb27 100644 --- a/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs +++ b/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs @@ -25,7 +25,7 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; -namespace GreenshotWin10Plugin.Processors { +namespace Greenshot.Plugin.Win10.Processors { /// /// This processor processes a capture to see if there is text on it /// diff --git a/src/Greenshot.Plugin.Win10/ToastNotificationService.cs b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs index e7c932ab7..444d397ef 100644 --- a/src/Greenshot.Plugin.Win10/ToastNotificationService.cs +++ b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs @@ -31,7 +31,7 @@ using GreenshotPlugin.Interfaces; using log4net; using Microsoft.Toolkit.Uwp.Notifications; -namespace GreenshotWin10Plugin +namespace Greenshot.Plugin.Win10 { /// /// This service provides a way to inform (notify) the user. diff --git a/src/Greenshot.Plugin.Win10/Win10Configuration.cs b/src/Greenshot.Plugin.Win10/Win10Configuration.cs index ba3091909..9c24787bf 100644 --- a/src/Greenshot.Plugin.Win10/Win10Configuration.cs +++ b/src/Greenshot.Plugin.Win10/Win10Configuration.cs @@ -21,7 +21,7 @@ using GreenshotPlugin.IniFile; -namespace GreenshotWin10Plugin +namespace Greenshot.Plugin.Win10 { /// /// Description of Win10Configuration. diff --git a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs index 81fd442e8..5ade2f329 100644 --- a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs +++ b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs @@ -31,7 +31,7 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotWin10Plugin +namespace Greenshot.Plugin.Win10 { /// /// This uses the OcrEngine from Windows 10 to perform OCR on the captured image. diff --git a/src/Greenshot.Plugin.Win10/Win10Plugin.cs b/src/Greenshot.Plugin.Win10/Win10Plugin.cs index dc5190bbe..b70a417cb 100644 --- a/src/Greenshot.Plugin.Win10/Win10Plugin.cs +++ b/src/Greenshot.Plugin.Win10/Win10Plugin.cs @@ -20,14 +20,14 @@ */ using System; +using Greenshot.Plugin.Win10.Destinations; +using Greenshot.Plugin.Win10.Processors; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; using GreenshotPlugin.Interfaces.Plugin; -using GreenshotWin10Plugin.Destinations; -using GreenshotWin10Plugin.Processors; -namespace GreenshotWin10Plugin +namespace Greenshot.Plugin.Win10 { /// /// This is the Win10Plugin diff --git a/src/GreenshotPlugin/FileDescriptorReader.cs b/src/GreenshotPlugin/FileDescriptorReader.cs index 93b94f834..7e0f3b9ab 100644 --- a/src/GreenshotPlugin/FileDescriptorReader.cs +++ b/src/GreenshotPlugin/FileDescriptorReader.cs @@ -27,7 +27,7 @@ using System.Runtime.InteropServices.ComTypes; using System.Text; using GreenshotPlugin.UnmanagedHelpers.Structs; -namespace GreenshotPlugin.Interop +namespace GreenshotPlugin { /// From 726644de99974494f883acb5e303caa1c01ca787 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 28 Mar 2021 19:17:35 +0200 Subject: [PATCH 116/232] Moving the Inno-Setup files away from the application project. --- .../additional_files/installer.txt | 0 .../additional_files/license.txt | 0 .../additional_files/readme.txt | 0 .../appinfo.ini.template | 0 .../innosetup/IssProc/IssProc.dll | Bin .../innosetup/IssProc/IssProcLanguage.ini | Bin .../innosetup/Languages/Afrikaans.isl | 0 .../innosetup/Languages/Albanian.isl | 0 .../innosetup/Languages/Arabic.isl | 0 .../innosetup/Languages/Asturian.isl | 0 .../innosetup/Languages/Basque.isl | 0 .../innosetup/Languages/Belarusian.isl | 0 .../innosetup/Languages/Bengali.islu | 0 .../innosetup/Languages/Bosnian.isl | 0 .../innosetup/Languages/Bulgarian.isl | 0 .../innosetup/Languages/ChineseSimplified.isl | 0 .../Languages/ChineseTraditional.isl | 0 .../innosetup/Languages/Croatian.isl | 0 .../innosetup/Languages/EnglishBritish.isl | 0 .../innosetup/Languages/Esperanto.isl | 0 .../innosetup/Languages/Estonian.isl | 0 .../innosetup/Languages/Farsi.isl | 0 .../innosetup/Languages/Galician.isl | 0 .../innosetup/Languages/Georgian.islu | 0 .../innosetup/Languages/Greek.isl | 0 .../innosetup/Languages/Hindi.islu | 0 .../innosetup/Languages/Hungarian.isl | 0 .../innosetup/Languages/Indonesian.isl | 0 .../innosetup/Languages/Kazakh.islu | 0 .../innosetup/Languages/Korean.isl | 0 .../innosetup/Languages/Kurdish.isl | 0 .../innosetup/Languages/Latvian.isl | 0 .../innosetup/Languages/Ligurian.isl | 0 .../innosetup/Languages/Lithuanian.isl | 0 .../innosetup/Languages/Luxemburgish.isl | 0 .../innosetup/Languages/Macedonian.isl | 0 .../innosetup/Languages/Malaysian.isl | 0 .../innosetup/Languages/Marathi.islu | 0 .../innosetup/Languages/Mongolian.isl | 0 .../innosetup/Languages/Montenegrian.isl | 0 .../innosetup/Languages/Nepali.islu | 0 .../innosetup/Languages/NorwegianNynorsk.isl | 0 .../innosetup/Languages/Occitan.isl | 0 .../innosetup/Languages/Romanian.isl | 0 .../innosetup/Languages/ScottishGaelic.isl | 0 .../innosetup/Languages/SerbianCyrillic.isl | 0 .../innosetup/Languages/SerbianLatin.isl | 0 .../innosetup/Languages/Sinhala.islu | 0 .../innosetup/Languages/Swedish.isl | 0 .../innosetup/Languages/Tatar.isl | 0 .../innosetup/Languages/Thai.isl | 0 .../innosetup/Languages/Uyghur.islu | 0 .../innosetup/Languages/Uzbek.isl | 0 .../innosetup/Languages/Valencian.isl | 0 .../innosetup/Languages/Vietnamese.isl | 0 .../innosetup/installer-large.bmp | Bin .../innosetup/installer-small.bmp | Bin .../innosetup/scripts/isxdl/chinese.ini | 0 .../innosetup/scripts/isxdl/czech.ini | 0 .../innosetup/scripts/isxdl/dutch.ini | 0 .../innosetup/scripts/isxdl/english.ini | 0 .../innosetup/scripts/isxdl/french.ini | 0 .../innosetup/scripts/isxdl/french2.ini | 0 .../innosetup/scripts/isxdl/french3.ini | 0 .../innosetup/scripts/isxdl/german.ini | 0 .../innosetup/scripts/isxdl/isxdl.dll | Bin .../innosetup/scripts/isxdl/isxdl.iss | 0 .../innosetup/scripts/isxdl/italian.ini | 0 .../innosetup/scripts/isxdl/japanese.ini | 0 .../innosetup/scripts/isxdl/korean.ini | 0 .../innosetup/scripts/isxdl/norwegian.ini | 0 .../innosetup/scripts/isxdl/polish.ini | 0 .../innosetup/scripts/isxdl/portugues.ini | 0 .../innosetup/scripts/isxdl/portuguese.ini | 0 .../innosetup/scripts/isxdl/russian.ini | 0 .../innosetup/scripts/isxdl/spanish.ini | 0 .../innosetup/scripts/isxdl/swedish.ini | 0 .../innosetup/scripts/lang/chinese.iss | 0 .../innosetup/scripts/lang/dutch.iss | 0 .../innosetup/scripts/lang/english.iss | 0 .../innosetup/scripts/lang/french.iss | 0 .../innosetup/scripts/lang/german.iss | 0 .../innosetup/scripts/lang/italian.iss | 0 .../innosetup/scripts/lang/japanese.iss | 0 .../innosetup/scripts/lang/polish.iss | 0 .../innosetup/scripts/lang/russian.iss | 0 .../innosetup/scripts/products.iss | 0 .../innosetup/scripts/products.pas | 0 .../scripts/products/directxruntime.iss | 0 .../innosetup/scripts/products/dotnetfx11.iss | 0 .../scripts/products/dotnetfx11lp.iss | 0 .../scripts/products/dotnetfx11sp1.iss | 0 .../innosetup/scripts/products/dotnetfx20.iss | 0 .../scripts/products/dotnetfx20lp.iss | 0 .../scripts/products/dotnetfx20sp1.iss | 0 .../scripts/products/dotnetfx20sp1lp.iss | 0 .../scripts/products/dotnetfx20sp2.iss | 0 .../scripts/products/dotnetfx20sp2lp.iss | 0 .../innosetup/scripts/products/dotnetfx35.iss | 0 .../scripts/products/dotnetfx35lp.iss | 0 .../scripts/products/dotnetfx35sp1.iss | 0 .../scripts/products/dotnetfx35sp1lp.iss | 0 .../scripts/products/dotnetfx40client.iss | 0 .../scripts/products/dotnetfx40full.iss | 0 .../innosetup/scripts/products/dotnetfx45.iss | 0 .../innosetup/scripts/products/dotnetfx46.iss | 0 .../innosetup/scripts/products/dotnetfx47.iss | 0 .../innosetup/scripts/products/dotnetfx48.iss | 0 .../scripts/products/dotnetfxversion.iss | 0 .../scripts/products/fileversion.iss | 0 .../innosetup/scripts/products/ie6.iss | 0 .../innosetup/scripts/products/iis.iss | 0 .../innosetup/scripts/products/jet4sp8.iss | 0 .../innosetup/scripts/products/kb835732.iss | 0 .../innosetup/scripts/products/mdac28.iss | 0 .../innosetup/scripts/products/msi20.iss | 0 .../innosetup/scripts/products/msi31.iss | 0 .../innosetup/scripts/products/msi45.iss | 0 .../innosetup/scripts/products/msiproduct.iss | 0 .../scripts/products/sql2005express.iss | 0 .../scripts/products/sql2008express.iss | 0 .../scripts/products/sqlcompact35sp2.iss | 0 .../scripts/products/stringversion.iss | 0 .../scripts/products/vcredist2005.iss | 0 .../scripts/products/vcredist2008.iss | 0 .../scripts/products/vcredist2010.iss | 0 .../scripts/products/vcredist2012.iss | 0 .../scripts/products/vcredist2013.iss | 0 .../scripts/products/vcredist2015.iss | 0 .../scripts/products/vcredist2017.iss | 0 .../innosetup/scripts/products/wic.iss | 0 .../innosetup/scripts/products/winversion.iss | 0 .../innosetup/setup.iss | 136 +++++++++--------- .../portable/App/AppInfo/appicon.ico | Bin .../portable/App/AppInfo/appicon_16.png | Bin .../portable/App/AppInfo/appicon_32.png | Bin .../App/DefaultData/Greenshots/dummy.txt | 0 .../App/DefaultData/Settings/dummy.txt | 0 .../portable/Data/Greenshot/dummy.txt | 0 .../portable/Data/Settings/dummy.txt | 0 .../PortableApps.comInstallerCustom.nsh | 0 src/Greenshot/Greenshot.csproj | 2 +- src/Greenshot/GreenshotMain.cs | 7 +- .../web/htdocs/Help/index.de-DE.html | 106 -------------- .../web/htdocs/Help/index.en-US.html | 100 ------------- src/Greenshot/web/htdocs/favicon.ico | Bin 2550 -> 0 bytes src/Greenshot/web/htdocs/index.html | 44 ------ 147 files changed, 72 insertions(+), 323 deletions(-) rename {src/Greenshot/releases => installer}/additional_files/installer.txt (100%) rename {src/Greenshot/releases => installer}/additional_files/license.txt (100%) rename {src/Greenshot/releases => installer}/additional_files/readme.txt (100%) rename {src/Greenshot/releases => installer}/appinfo.ini.template (100%) rename {src/Greenshot/releases => installer}/innosetup/IssProc/IssProc.dll (100%) rename {src/Greenshot/releases => installer}/innosetup/IssProc/IssProcLanguage.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Afrikaans.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Albanian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Arabic.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Asturian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Basque.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Belarusian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Bengali.islu (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Bosnian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Bulgarian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/ChineseSimplified.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/ChineseTraditional.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Croatian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/EnglishBritish.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Esperanto.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Estonian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Farsi.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Galician.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Georgian.islu (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Greek.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Hindi.islu (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Hungarian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Indonesian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Kazakh.islu (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Korean.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Kurdish.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Latvian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Ligurian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Lithuanian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Luxemburgish.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Macedonian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Malaysian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Marathi.islu (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Mongolian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Montenegrian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Nepali.islu (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/NorwegianNynorsk.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Occitan.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Romanian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/ScottishGaelic.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/SerbianCyrillic.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/SerbianLatin.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Sinhala.islu (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Swedish.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Tatar.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Thai.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Uyghur.islu (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Uzbek.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Valencian.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/Languages/Vietnamese.isl (100%) rename {src/Greenshot/releases => installer}/innosetup/installer-large.bmp (100%) rename {src/Greenshot/releases => installer}/innosetup/installer-small.bmp (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/chinese.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/czech.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/dutch.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/english.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/french.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/french2.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/french3.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/german.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/isxdl.dll (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/isxdl.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/italian.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/japanese.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/korean.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/norwegian.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/polish.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/portugues.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/portuguese.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/russian.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/spanish.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/isxdl/swedish.ini (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/lang/chinese.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/lang/dutch.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/lang/english.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/lang/french.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/lang/german.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/lang/italian.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/lang/japanese.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/lang/polish.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/lang/russian.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products.pas (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/directxruntime.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx11.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx11lp.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx11sp1.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20lp.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20sp1.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20sp1lp.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20sp2.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20sp2lp.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx35.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx35lp.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx35sp1.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx35sp1lp.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx40client.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx40full.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx45.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx46.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx47.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx48.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/dotnetfxversion.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/fileversion.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/ie6.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/iis.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/jet4sp8.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/kb835732.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/mdac28.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/msi20.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/msi31.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/msi45.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/msiproduct.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/sql2005express.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/sql2008express.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/sqlcompact35sp2.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/stringversion.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/vcredist2005.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/vcredist2008.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/vcredist2010.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/vcredist2012.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/vcredist2013.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/vcredist2015.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/vcredist2017.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/wic.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/scripts/products/winversion.iss (100%) rename {src/Greenshot/releases => installer}/innosetup/setup.iss (82%) rename {src/Greenshot/releases => installer}/portable/App/AppInfo/appicon.ico (100%) rename {src/Greenshot/releases => installer}/portable/App/AppInfo/appicon_16.png (100%) rename {src/Greenshot/releases => installer}/portable/App/AppInfo/appicon_32.png (100%) rename {src/Greenshot/releases => installer}/portable/App/DefaultData/Greenshots/dummy.txt (100%) rename {src/Greenshot/releases => installer}/portable/App/DefaultData/Settings/dummy.txt (100%) rename {src/Greenshot/releases => installer}/portable/Data/Greenshot/dummy.txt (100%) rename {src/Greenshot/releases => installer}/portable/Data/Settings/dummy.txt (100%) rename {src/Greenshot/releases => installer}/portable/Other/Source/PortableApps.comInstallerCustom.nsh (100%) delete mode 100644 src/Greenshot/web/htdocs/Help/index.de-DE.html delete mode 100644 src/Greenshot/web/htdocs/Help/index.en-US.html delete mode 100644 src/Greenshot/web/htdocs/favicon.ico delete mode 100644 src/Greenshot/web/htdocs/index.html diff --git a/src/Greenshot/releases/additional_files/installer.txt b/installer/additional_files/installer.txt similarity index 100% rename from src/Greenshot/releases/additional_files/installer.txt rename to installer/additional_files/installer.txt diff --git a/src/Greenshot/releases/additional_files/license.txt b/installer/additional_files/license.txt similarity index 100% rename from src/Greenshot/releases/additional_files/license.txt rename to installer/additional_files/license.txt diff --git a/src/Greenshot/releases/additional_files/readme.txt b/installer/additional_files/readme.txt similarity index 100% rename from src/Greenshot/releases/additional_files/readme.txt rename to installer/additional_files/readme.txt diff --git a/src/Greenshot/releases/appinfo.ini.template b/installer/appinfo.ini.template similarity index 100% rename from src/Greenshot/releases/appinfo.ini.template rename to installer/appinfo.ini.template diff --git a/src/Greenshot/releases/innosetup/IssProc/IssProc.dll b/installer/innosetup/IssProc/IssProc.dll similarity index 100% rename from src/Greenshot/releases/innosetup/IssProc/IssProc.dll rename to installer/innosetup/IssProc/IssProc.dll diff --git a/src/Greenshot/releases/innosetup/IssProc/IssProcLanguage.ini b/installer/innosetup/IssProc/IssProcLanguage.ini similarity index 100% rename from src/Greenshot/releases/innosetup/IssProc/IssProcLanguage.ini rename to installer/innosetup/IssProc/IssProcLanguage.ini diff --git a/src/Greenshot/releases/innosetup/Languages/Afrikaans.isl b/installer/innosetup/Languages/Afrikaans.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Afrikaans.isl rename to installer/innosetup/Languages/Afrikaans.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Albanian.isl b/installer/innosetup/Languages/Albanian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Albanian.isl rename to installer/innosetup/Languages/Albanian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Arabic.isl b/installer/innosetup/Languages/Arabic.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Arabic.isl rename to installer/innosetup/Languages/Arabic.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Asturian.isl b/installer/innosetup/Languages/Asturian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Asturian.isl rename to installer/innosetup/Languages/Asturian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Basque.isl b/installer/innosetup/Languages/Basque.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Basque.isl rename to installer/innosetup/Languages/Basque.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Belarusian.isl b/installer/innosetup/Languages/Belarusian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Belarusian.isl rename to installer/innosetup/Languages/Belarusian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Bengali.islu b/installer/innosetup/Languages/Bengali.islu similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Bengali.islu rename to installer/innosetup/Languages/Bengali.islu diff --git a/src/Greenshot/releases/innosetup/Languages/Bosnian.isl b/installer/innosetup/Languages/Bosnian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Bosnian.isl rename to installer/innosetup/Languages/Bosnian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Bulgarian.isl b/installer/innosetup/Languages/Bulgarian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Bulgarian.isl rename to installer/innosetup/Languages/Bulgarian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/ChineseSimplified.isl b/installer/innosetup/Languages/ChineseSimplified.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/ChineseSimplified.isl rename to installer/innosetup/Languages/ChineseSimplified.isl diff --git a/src/Greenshot/releases/innosetup/Languages/ChineseTraditional.isl b/installer/innosetup/Languages/ChineseTraditional.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/ChineseTraditional.isl rename to installer/innosetup/Languages/ChineseTraditional.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Croatian.isl b/installer/innosetup/Languages/Croatian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Croatian.isl rename to installer/innosetup/Languages/Croatian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/EnglishBritish.isl b/installer/innosetup/Languages/EnglishBritish.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/EnglishBritish.isl rename to installer/innosetup/Languages/EnglishBritish.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Esperanto.isl b/installer/innosetup/Languages/Esperanto.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Esperanto.isl rename to installer/innosetup/Languages/Esperanto.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Estonian.isl b/installer/innosetup/Languages/Estonian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Estonian.isl rename to installer/innosetup/Languages/Estonian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Farsi.isl b/installer/innosetup/Languages/Farsi.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Farsi.isl rename to installer/innosetup/Languages/Farsi.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Galician.isl b/installer/innosetup/Languages/Galician.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Galician.isl rename to installer/innosetup/Languages/Galician.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Georgian.islu b/installer/innosetup/Languages/Georgian.islu similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Georgian.islu rename to installer/innosetup/Languages/Georgian.islu diff --git a/src/Greenshot/releases/innosetup/Languages/Greek.isl b/installer/innosetup/Languages/Greek.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Greek.isl rename to installer/innosetup/Languages/Greek.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Hindi.islu b/installer/innosetup/Languages/Hindi.islu similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Hindi.islu rename to installer/innosetup/Languages/Hindi.islu diff --git a/src/Greenshot/releases/innosetup/Languages/Hungarian.isl b/installer/innosetup/Languages/Hungarian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Hungarian.isl rename to installer/innosetup/Languages/Hungarian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Indonesian.isl b/installer/innosetup/Languages/Indonesian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Indonesian.isl rename to installer/innosetup/Languages/Indonesian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Kazakh.islu b/installer/innosetup/Languages/Kazakh.islu similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Kazakh.islu rename to installer/innosetup/Languages/Kazakh.islu diff --git a/src/Greenshot/releases/innosetup/Languages/Korean.isl b/installer/innosetup/Languages/Korean.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Korean.isl rename to installer/innosetup/Languages/Korean.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Kurdish.isl b/installer/innosetup/Languages/Kurdish.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Kurdish.isl rename to installer/innosetup/Languages/Kurdish.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Latvian.isl b/installer/innosetup/Languages/Latvian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Latvian.isl rename to installer/innosetup/Languages/Latvian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Ligurian.isl b/installer/innosetup/Languages/Ligurian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Ligurian.isl rename to installer/innosetup/Languages/Ligurian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Lithuanian.isl b/installer/innosetup/Languages/Lithuanian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Lithuanian.isl rename to installer/innosetup/Languages/Lithuanian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Luxemburgish.isl b/installer/innosetup/Languages/Luxemburgish.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Luxemburgish.isl rename to installer/innosetup/Languages/Luxemburgish.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Macedonian.isl b/installer/innosetup/Languages/Macedonian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Macedonian.isl rename to installer/innosetup/Languages/Macedonian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Malaysian.isl b/installer/innosetup/Languages/Malaysian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Malaysian.isl rename to installer/innosetup/Languages/Malaysian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Marathi.islu b/installer/innosetup/Languages/Marathi.islu similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Marathi.islu rename to installer/innosetup/Languages/Marathi.islu diff --git a/src/Greenshot/releases/innosetup/Languages/Mongolian.isl b/installer/innosetup/Languages/Mongolian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Mongolian.isl rename to installer/innosetup/Languages/Mongolian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Montenegrian.isl b/installer/innosetup/Languages/Montenegrian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Montenegrian.isl rename to installer/innosetup/Languages/Montenegrian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Nepali.islu b/installer/innosetup/Languages/Nepali.islu similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Nepali.islu rename to installer/innosetup/Languages/Nepali.islu diff --git a/src/Greenshot/releases/innosetup/Languages/NorwegianNynorsk.isl b/installer/innosetup/Languages/NorwegianNynorsk.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/NorwegianNynorsk.isl rename to installer/innosetup/Languages/NorwegianNynorsk.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Occitan.isl b/installer/innosetup/Languages/Occitan.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Occitan.isl rename to installer/innosetup/Languages/Occitan.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Romanian.isl b/installer/innosetup/Languages/Romanian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Romanian.isl rename to installer/innosetup/Languages/Romanian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/ScottishGaelic.isl b/installer/innosetup/Languages/ScottishGaelic.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/ScottishGaelic.isl rename to installer/innosetup/Languages/ScottishGaelic.isl diff --git a/src/Greenshot/releases/innosetup/Languages/SerbianCyrillic.isl b/installer/innosetup/Languages/SerbianCyrillic.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/SerbianCyrillic.isl rename to installer/innosetup/Languages/SerbianCyrillic.isl diff --git a/src/Greenshot/releases/innosetup/Languages/SerbianLatin.isl b/installer/innosetup/Languages/SerbianLatin.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/SerbianLatin.isl rename to installer/innosetup/Languages/SerbianLatin.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Sinhala.islu b/installer/innosetup/Languages/Sinhala.islu similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Sinhala.islu rename to installer/innosetup/Languages/Sinhala.islu diff --git a/src/Greenshot/releases/innosetup/Languages/Swedish.isl b/installer/innosetup/Languages/Swedish.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Swedish.isl rename to installer/innosetup/Languages/Swedish.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Tatar.isl b/installer/innosetup/Languages/Tatar.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Tatar.isl rename to installer/innosetup/Languages/Tatar.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Thai.isl b/installer/innosetup/Languages/Thai.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Thai.isl rename to installer/innosetup/Languages/Thai.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Uyghur.islu b/installer/innosetup/Languages/Uyghur.islu similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Uyghur.islu rename to installer/innosetup/Languages/Uyghur.islu diff --git a/src/Greenshot/releases/innosetup/Languages/Uzbek.isl b/installer/innosetup/Languages/Uzbek.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Uzbek.isl rename to installer/innosetup/Languages/Uzbek.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Valencian.isl b/installer/innosetup/Languages/Valencian.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Valencian.isl rename to installer/innosetup/Languages/Valencian.isl diff --git a/src/Greenshot/releases/innosetup/Languages/Vietnamese.isl b/installer/innosetup/Languages/Vietnamese.isl similarity index 100% rename from src/Greenshot/releases/innosetup/Languages/Vietnamese.isl rename to installer/innosetup/Languages/Vietnamese.isl diff --git a/src/Greenshot/releases/innosetup/installer-large.bmp b/installer/innosetup/installer-large.bmp similarity index 100% rename from src/Greenshot/releases/innosetup/installer-large.bmp rename to installer/innosetup/installer-large.bmp diff --git a/src/Greenshot/releases/innosetup/installer-small.bmp b/installer/innosetup/installer-small.bmp similarity index 100% rename from src/Greenshot/releases/innosetup/installer-small.bmp rename to installer/innosetup/installer-small.bmp diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/chinese.ini b/installer/innosetup/scripts/isxdl/chinese.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/chinese.ini rename to installer/innosetup/scripts/isxdl/chinese.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/czech.ini b/installer/innosetup/scripts/isxdl/czech.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/czech.ini rename to installer/innosetup/scripts/isxdl/czech.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/dutch.ini b/installer/innosetup/scripts/isxdl/dutch.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/dutch.ini rename to installer/innosetup/scripts/isxdl/dutch.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/english.ini b/installer/innosetup/scripts/isxdl/english.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/english.ini rename to installer/innosetup/scripts/isxdl/english.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/french.ini b/installer/innosetup/scripts/isxdl/french.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/french.ini rename to installer/innosetup/scripts/isxdl/french.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/french2.ini b/installer/innosetup/scripts/isxdl/french2.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/french2.ini rename to installer/innosetup/scripts/isxdl/french2.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/french3.ini b/installer/innosetup/scripts/isxdl/french3.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/french3.ini rename to installer/innosetup/scripts/isxdl/french3.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/german.ini b/installer/innosetup/scripts/isxdl/german.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/german.ini rename to installer/innosetup/scripts/isxdl/german.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/isxdl.dll b/installer/innosetup/scripts/isxdl/isxdl.dll similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/isxdl.dll rename to installer/innosetup/scripts/isxdl/isxdl.dll diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/isxdl.iss b/installer/innosetup/scripts/isxdl/isxdl.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/isxdl.iss rename to installer/innosetup/scripts/isxdl/isxdl.iss diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/italian.ini b/installer/innosetup/scripts/isxdl/italian.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/italian.ini rename to installer/innosetup/scripts/isxdl/italian.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/japanese.ini b/installer/innosetup/scripts/isxdl/japanese.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/japanese.ini rename to installer/innosetup/scripts/isxdl/japanese.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/korean.ini b/installer/innosetup/scripts/isxdl/korean.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/korean.ini rename to installer/innosetup/scripts/isxdl/korean.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/norwegian.ini b/installer/innosetup/scripts/isxdl/norwegian.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/norwegian.ini rename to installer/innosetup/scripts/isxdl/norwegian.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/polish.ini b/installer/innosetup/scripts/isxdl/polish.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/polish.ini rename to installer/innosetup/scripts/isxdl/polish.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/portugues.ini b/installer/innosetup/scripts/isxdl/portugues.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/portugues.ini rename to installer/innosetup/scripts/isxdl/portugues.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/portuguese.ini b/installer/innosetup/scripts/isxdl/portuguese.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/portuguese.ini rename to installer/innosetup/scripts/isxdl/portuguese.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/russian.ini b/installer/innosetup/scripts/isxdl/russian.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/russian.ini rename to installer/innosetup/scripts/isxdl/russian.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/spanish.ini b/installer/innosetup/scripts/isxdl/spanish.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/spanish.ini rename to installer/innosetup/scripts/isxdl/spanish.ini diff --git a/src/Greenshot/releases/innosetup/scripts/isxdl/swedish.ini b/installer/innosetup/scripts/isxdl/swedish.ini similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/isxdl/swedish.ini rename to installer/innosetup/scripts/isxdl/swedish.ini diff --git a/src/Greenshot/releases/innosetup/scripts/lang/chinese.iss b/installer/innosetup/scripts/lang/chinese.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/lang/chinese.iss rename to installer/innosetup/scripts/lang/chinese.iss diff --git a/src/Greenshot/releases/innosetup/scripts/lang/dutch.iss b/installer/innosetup/scripts/lang/dutch.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/lang/dutch.iss rename to installer/innosetup/scripts/lang/dutch.iss diff --git a/src/Greenshot/releases/innosetup/scripts/lang/english.iss b/installer/innosetup/scripts/lang/english.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/lang/english.iss rename to installer/innosetup/scripts/lang/english.iss diff --git a/src/Greenshot/releases/innosetup/scripts/lang/french.iss b/installer/innosetup/scripts/lang/french.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/lang/french.iss rename to installer/innosetup/scripts/lang/french.iss diff --git a/src/Greenshot/releases/innosetup/scripts/lang/german.iss b/installer/innosetup/scripts/lang/german.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/lang/german.iss rename to installer/innosetup/scripts/lang/german.iss diff --git a/src/Greenshot/releases/innosetup/scripts/lang/italian.iss b/installer/innosetup/scripts/lang/italian.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/lang/italian.iss rename to installer/innosetup/scripts/lang/italian.iss diff --git a/src/Greenshot/releases/innosetup/scripts/lang/japanese.iss b/installer/innosetup/scripts/lang/japanese.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/lang/japanese.iss rename to installer/innosetup/scripts/lang/japanese.iss diff --git a/src/Greenshot/releases/innosetup/scripts/lang/polish.iss b/installer/innosetup/scripts/lang/polish.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/lang/polish.iss rename to installer/innosetup/scripts/lang/polish.iss diff --git a/src/Greenshot/releases/innosetup/scripts/lang/russian.iss b/installer/innosetup/scripts/lang/russian.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/lang/russian.iss rename to installer/innosetup/scripts/lang/russian.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products.iss b/installer/innosetup/scripts/products.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products.iss rename to installer/innosetup/scripts/products.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products.pas b/installer/innosetup/scripts/products.pas similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products.pas rename to installer/innosetup/scripts/products.pas diff --git a/src/Greenshot/releases/innosetup/scripts/products/directxruntime.iss b/installer/innosetup/scripts/products/directxruntime.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/directxruntime.iss rename to installer/innosetup/scripts/products/directxruntime.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx11.iss b/installer/innosetup/scripts/products/dotnetfx11.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx11.iss rename to installer/innosetup/scripts/products/dotnetfx11.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx11lp.iss b/installer/innosetup/scripts/products/dotnetfx11lp.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx11lp.iss rename to installer/innosetup/scripts/products/dotnetfx11lp.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx11sp1.iss b/installer/innosetup/scripts/products/dotnetfx11sp1.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx11sp1.iss rename to installer/innosetup/scripts/products/dotnetfx11sp1.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20.iss b/installer/innosetup/scripts/products/dotnetfx20.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx20.iss rename to installer/innosetup/scripts/products/dotnetfx20.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20lp.iss b/installer/innosetup/scripts/products/dotnetfx20lp.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx20lp.iss rename to installer/innosetup/scripts/products/dotnetfx20lp.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1.iss b/installer/innosetup/scripts/products/dotnetfx20sp1.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1.iss rename to installer/innosetup/scripts/products/dotnetfx20sp1.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1lp.iss b/installer/innosetup/scripts/products/dotnetfx20sp1lp.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1lp.iss rename to installer/innosetup/scripts/products/dotnetfx20sp1lp.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2.iss b/installer/innosetup/scripts/products/dotnetfx20sp2.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2.iss rename to installer/innosetup/scripts/products/dotnetfx20sp2.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2lp.iss b/installer/innosetup/scripts/products/dotnetfx20sp2lp.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2lp.iss rename to installer/innosetup/scripts/products/dotnetfx20sp2lp.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx35.iss b/installer/innosetup/scripts/products/dotnetfx35.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx35.iss rename to installer/innosetup/scripts/products/dotnetfx35.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx35lp.iss b/installer/innosetup/scripts/products/dotnetfx35lp.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx35lp.iss rename to installer/innosetup/scripts/products/dotnetfx35lp.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1.iss b/installer/innosetup/scripts/products/dotnetfx35sp1.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1.iss rename to installer/innosetup/scripts/products/dotnetfx35sp1.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1lp.iss b/installer/innosetup/scripts/products/dotnetfx35sp1lp.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1lp.iss rename to installer/innosetup/scripts/products/dotnetfx35sp1lp.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx40client.iss b/installer/innosetup/scripts/products/dotnetfx40client.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx40client.iss rename to installer/innosetup/scripts/products/dotnetfx40client.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx40full.iss b/installer/innosetup/scripts/products/dotnetfx40full.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx40full.iss rename to installer/innosetup/scripts/products/dotnetfx40full.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx45.iss b/installer/innosetup/scripts/products/dotnetfx45.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx45.iss rename to installer/innosetup/scripts/products/dotnetfx45.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx46.iss b/installer/innosetup/scripts/products/dotnetfx46.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx46.iss rename to installer/innosetup/scripts/products/dotnetfx46.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx47.iss b/installer/innosetup/scripts/products/dotnetfx47.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx47.iss rename to installer/innosetup/scripts/products/dotnetfx47.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfx48.iss b/installer/innosetup/scripts/products/dotnetfx48.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfx48.iss rename to installer/innosetup/scripts/products/dotnetfx48.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/dotnetfxversion.iss b/installer/innosetup/scripts/products/dotnetfxversion.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/dotnetfxversion.iss rename to installer/innosetup/scripts/products/dotnetfxversion.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/fileversion.iss b/installer/innosetup/scripts/products/fileversion.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/fileversion.iss rename to installer/innosetup/scripts/products/fileversion.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/ie6.iss b/installer/innosetup/scripts/products/ie6.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/ie6.iss rename to installer/innosetup/scripts/products/ie6.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/iis.iss b/installer/innosetup/scripts/products/iis.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/iis.iss rename to installer/innosetup/scripts/products/iis.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/jet4sp8.iss b/installer/innosetup/scripts/products/jet4sp8.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/jet4sp8.iss rename to installer/innosetup/scripts/products/jet4sp8.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/kb835732.iss b/installer/innosetup/scripts/products/kb835732.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/kb835732.iss rename to installer/innosetup/scripts/products/kb835732.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/mdac28.iss b/installer/innosetup/scripts/products/mdac28.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/mdac28.iss rename to installer/innosetup/scripts/products/mdac28.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/msi20.iss b/installer/innosetup/scripts/products/msi20.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/msi20.iss rename to installer/innosetup/scripts/products/msi20.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/msi31.iss b/installer/innosetup/scripts/products/msi31.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/msi31.iss rename to installer/innosetup/scripts/products/msi31.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/msi45.iss b/installer/innosetup/scripts/products/msi45.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/msi45.iss rename to installer/innosetup/scripts/products/msi45.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/msiproduct.iss b/installer/innosetup/scripts/products/msiproduct.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/msiproduct.iss rename to installer/innosetup/scripts/products/msiproduct.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/sql2005express.iss b/installer/innosetup/scripts/products/sql2005express.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/sql2005express.iss rename to installer/innosetup/scripts/products/sql2005express.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/sql2008express.iss b/installer/innosetup/scripts/products/sql2008express.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/sql2008express.iss rename to installer/innosetup/scripts/products/sql2008express.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/sqlcompact35sp2.iss b/installer/innosetup/scripts/products/sqlcompact35sp2.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/sqlcompact35sp2.iss rename to installer/innosetup/scripts/products/sqlcompact35sp2.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/stringversion.iss b/installer/innosetup/scripts/products/stringversion.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/stringversion.iss rename to installer/innosetup/scripts/products/stringversion.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/vcredist2005.iss b/installer/innosetup/scripts/products/vcredist2005.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/vcredist2005.iss rename to installer/innosetup/scripts/products/vcredist2005.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/vcredist2008.iss b/installer/innosetup/scripts/products/vcredist2008.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/vcredist2008.iss rename to installer/innosetup/scripts/products/vcredist2008.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/vcredist2010.iss b/installer/innosetup/scripts/products/vcredist2010.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/vcredist2010.iss rename to installer/innosetup/scripts/products/vcredist2010.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/vcredist2012.iss b/installer/innosetup/scripts/products/vcredist2012.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/vcredist2012.iss rename to installer/innosetup/scripts/products/vcredist2012.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/vcredist2013.iss b/installer/innosetup/scripts/products/vcredist2013.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/vcredist2013.iss rename to installer/innosetup/scripts/products/vcredist2013.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/vcredist2015.iss b/installer/innosetup/scripts/products/vcredist2015.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/vcredist2015.iss rename to installer/innosetup/scripts/products/vcredist2015.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/vcredist2017.iss b/installer/innosetup/scripts/products/vcredist2017.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/vcredist2017.iss rename to installer/innosetup/scripts/products/vcredist2017.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/wic.iss b/installer/innosetup/scripts/products/wic.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/wic.iss rename to installer/innosetup/scripts/products/wic.iss diff --git a/src/Greenshot/releases/innosetup/scripts/products/winversion.iss b/installer/innosetup/scripts/products/winversion.iss similarity index 100% rename from src/Greenshot/releases/innosetup/scripts/products/winversion.iss rename to installer/innosetup/scripts/products/winversion.iss diff --git a/src/Greenshot/releases/innosetup/setup.iss b/installer/innosetup/setup.iss similarity index 82% rename from src/Greenshot/releases/innosetup/setup.iss rename to installer/innosetup/setup.iss index d055b7151..977f4cf8b 100644 --- a/src/Greenshot/releases/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -1,9 +1,11 @@ #define ExeName "Greenshot" #define Version GetEnv('BuildVersionSimple') #define FileVersion GetEnv('AssemblyInformationalVersion') -#define BaseDir "..\..\.." -#define ReleaseDir "..\..\bin\Release\net472" +#define BaseDir "..\..\src" +#define GreenshotProjectDir "..\..\src\Greenshot" +#define LanguagesDir "..\..\src\Greenshot\Languages" #define BinDir "bin\Release\net472" +#define ReleaseDir "..\..\src\Greenshot\bin\Release\net472" ; Include the scripts to install .NET Framework ; See http://www.codeproject.com/KB/install/dotnetfx_innosetup_instal.aspx @@ -27,7 +29,7 @@ Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: ove Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\HtmlAgilityPack.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Newtonsoft.Json.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: ..\..\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion +Source: {#GreenshotProjectDir}\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion Source: {#ReleaseDir}\checksum.SHA256; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion ;Source: ..\greenshot-defaults.ini; DestDir: {app}; Flags: overwritereadonly ignoreversion replacesameversion Source: ..\additional_files\installer.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion @@ -35,81 +37,78 @@ Source: ..\additional_files\license.txt; DestDir: {app}; Components: greenshot; Source: ..\additional_files\readme.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion ; Core language files -Source: ..\..\Languages\*nl-NL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*en-US*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*de-DE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*nl-NL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*en-US*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*de-DE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; ; Additional language files -Source: ..\..\Languages\*ar-SY*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\arSY; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ca-CA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\caCA; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*cs-CZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\csCZ; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*da-DK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\daDK; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*de-x-franconia*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\dexfranconia; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*el-GR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\elGR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*es-ES*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\esES; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*et-EE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\etEE; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fa-IR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\faIR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fi-FI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\fiFI; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fr-FR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frFR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fr-QC*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frQC; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*he-IL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\heIL; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*hu-HU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\huHU; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*id-ID*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\idID; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*it-IT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\itIT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ja-JP*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\jaJP; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ko-KR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\koKR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*kab-DZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\kabDZ; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*lt-LT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ltLT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*lv-LV*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\lvLV; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*nn-NO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\nnNO; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*pl-PL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\plPL; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*pt-BR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptBR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*pt-PT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptPT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ro-RO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\roRO; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ru-RU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ruRU; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sk-SK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\skSK; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sl-SI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\slSI; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sr-RS*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\srRS; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sv-SE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\svSE; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*tr-TR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\trTR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*uk-UA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ukUA; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*vi-VN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\viVN; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhCN; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ar-SY*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\arSY; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ca-CA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\caCA; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*cs-CZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\csCZ; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*da-DK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\daDK; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*de-x-franconia*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\dexfranconia; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*el-GR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\elGR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*es-ES*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\esES; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*et-EE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\etEE; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*fa-IR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\faIR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*fi-FI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\fiFI; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*fr-FR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frFR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*fr-QC*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frQC; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*he-IL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\heIL; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*hu-HU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\huHU; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*id-ID*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\idID; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*it-IT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\itIT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ja-JP*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\jaJP; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ko-KR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\koKR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*kab-DZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\kabDZ; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*lt-LT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ltLT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*lv-LV*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\lvLV; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*nn-NO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\nnNO; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*pl-PL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\plPL; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*pt-BR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptBR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*pt-PT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptPT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ro-RO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\roRO; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ru-RU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ruRU; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*sk-SK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\skSK; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*sl-SI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\slSI; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*sr-RS*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\srRS; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*sv-SE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\svSE; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*tr-TR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\trTR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*uk-UA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ukUA; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*vi-VN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\viVN; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhCN; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion; ;Office Plugin -Source: {#BaseDir}\GreenshotOfficePlugin\{#BinDir}\GreenshotOfficePlugin.dll; DestDir: {app}\Plugins\GreenshotOfficePlugin; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Office\{#BinDir}\Greenshot.Plugin.Office.dll; DestDir: {app}\Plugins\Office; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; ;JIRA Plugin -Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\GreenshotJiraPlugin.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\Dapplo.Jira*.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotJiraPlugin\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Jira\{#BinDir}\Greenshot.Plugin.Jira.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Jira\{#BinDir}\Dapplo.Jira*.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Jira\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion; ;Imgur Plugin -Source: {#BaseDir}\GreenshotImgurPlugin\{#BinDir}\GreenshotImgurPlugin.dll; DestDir: {app}\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotImgurPlugin\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Imgur\{#BinDir}\Greenshot.Plugin.Imgur.dll; DestDir: {app}\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Imgur\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion; ;Box Plugin -Source: {#BaseDir}\GreenshotBoxPlugin\{#BinDir}\GreenshotBoxPlugin.dll; DestDir: {app}\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotBoxPlugin\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Box\{#BinDir}\Greenshot.Plugin.Box.dll; DestDir: {app}\Plugins\Box; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Box\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\Box; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion; ;DropBox Plugin -Source: {#BaseDir}\GreenshotDropBoxPlugin\{#BinDir}\GreenshotDropboxPlugin.dll; DestDir: {app}\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotDropBoxPlugin\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.DropBox\{#BinDir}\Greenshot.Plugin.DropBox.dll; DestDir: {app}\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.DropBox\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion; ;Flickr Plugin -Source: {#BaseDir}\GreenshotFlickrPlugin\{#BinDir}\GreenshotFlickrPlugin.dll; DestDir: {app}\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotFlickrPlugin\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Flickr\{#BinDir}\Greenshot.Plugin.Flickr.dll; DestDir: {app}\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Flickr\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion; ;Photobucket Plugin -Source: {#BaseDir}\GreenshotPhotobucketPlugin\{#BinDir}\GreenshotPhotobucketPlugin.dll; DestDir: {app}\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotPhotobucketPlugin\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion; -;Picasa Plugin -;Source: {#BaseDir}\GreenshotPicasaPlugin\{#BinDir}\GreenshotPicasaPlugin.dll; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -;Source: {#BaseDir}\GreenshotPicasaPlugin\Languages\language_picasa*.xml; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Photobucket\{#BinDir}\\Greenshot.Plugin.Photobucket.dll; DestDir: {app}\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Photobucket\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion; ;Confluence Plugin -Source: {#BaseDir}\GreenshotConfluencePlugin\{#BinDir}\GreenshotConfluencePlugin.dll; DestDir: {app}\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotConfluencePlugin\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Confluence\{#BinDir}\Greenshot.Plugin.Confluence.dll; DestDir: {app}\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Confluence\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; ;ExternalCommand Plugin -Source: {#BaseDir}\GreenshotExternalCommandPlugin\{#BinDir}\GreenshotExternalCommandPlugin.dll; DestDir: {app}\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotExternalCommandPlugin\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.ExternalCommand\{#BinDir}\Greenshot.Plugin.ExternalCommand.dll; DestDir: {app}\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.ExternalCommand\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion; ;Win 10 Plugin -Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\GreenshotWin10Plugin.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\Microsoft.Toolkit.Uwp.Notifications.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Win10\{#BinDir}\Greenshot.Plugin.Win10.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Win10\{#BinDir}\Microsoft.Toolkit.Uwp.Notifications.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; [Setup] ; changes associations is used when the installer installs new extensions, it clears the explorer icon cache @@ -135,7 +134,7 @@ MinVersion=6.1sp1 OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE OutputDir=..\ PrivilegesRequired=lowest -SetupIconFile=..\..\icons\applicationIcon\icon.ico +SetupIconFile=..\..\src\Greenshot\icons\applicationIcon\icon.ico ; Create a SHA1 signature ; SignTool=SignTool sign /debug /fd sha1 /tr http://time.certum.pl /td sha1 $f ; Append a SHA256 to the previous SHA1 signature (this is what as does) @@ -158,6 +157,8 @@ Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: no Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Root: HKCU32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() Root: HKLM32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() +Root: HKCU64; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() +Root: HKLM64; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() ; delete filetype mappings ; HKEY_LOCAL_USER - for current user only @@ -261,7 +262,6 @@ en.language=Additional languages en.office=Microsoft Office plug-in en.optimize=Optimizing performance, this may take a while. en.photobucket=Photobucket plug-in -en.picasa=Picasa plug-in en.startgreenshot=Start {#ExeName} en.startup=Start {#ExeName} with Windows start en.win10=Windows 10 plug-in @@ -328,7 +328,6 @@ it.language=Lingue aggiuntive it.office=Plugin Microsoft Office it.optimize=Ottimizzazione prestazioni (può richiedere tempo). it.photobucket=Plugin Photobucket -it.picasa=Plugin Picasa it.startgreenshot=Esegui {#ExeName} it.startup=Esegui {#ExeName} all''avvio di Windows it.win10=Plugin Windows 10 @@ -493,7 +492,6 @@ Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flag Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning Name: "plugins\photobucket"; Description: {cm:photobucket}; Types: full custom; Flags: disablenouninstallwarning -;Name: "plugins\picasa"; Description: {cm:picasa}; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\win10"; Description: {cm:win10}; Types: default full custom; Flags: disablenouninstallwarning; Check: IsWindows10OrNewer() Name: "languages"; Description: {cm:language}; Types: full custom; Flags: disablenouninstallwarning Name: "languages\arSY"; Description: {cm:arSY}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') diff --git a/src/Greenshot/releases/portable/App/AppInfo/appicon.ico b/installer/portable/App/AppInfo/appicon.ico similarity index 100% rename from src/Greenshot/releases/portable/App/AppInfo/appicon.ico rename to installer/portable/App/AppInfo/appicon.ico diff --git a/src/Greenshot/releases/portable/App/AppInfo/appicon_16.png b/installer/portable/App/AppInfo/appicon_16.png similarity index 100% rename from src/Greenshot/releases/portable/App/AppInfo/appicon_16.png rename to installer/portable/App/AppInfo/appicon_16.png diff --git a/src/Greenshot/releases/portable/App/AppInfo/appicon_32.png b/installer/portable/App/AppInfo/appicon_32.png similarity index 100% rename from src/Greenshot/releases/portable/App/AppInfo/appicon_32.png rename to installer/portable/App/AppInfo/appicon_32.png diff --git a/src/Greenshot/releases/portable/App/DefaultData/Greenshots/dummy.txt b/installer/portable/App/DefaultData/Greenshots/dummy.txt similarity index 100% rename from src/Greenshot/releases/portable/App/DefaultData/Greenshots/dummy.txt rename to installer/portable/App/DefaultData/Greenshots/dummy.txt diff --git a/src/Greenshot/releases/portable/App/DefaultData/Settings/dummy.txt b/installer/portable/App/DefaultData/Settings/dummy.txt similarity index 100% rename from src/Greenshot/releases/portable/App/DefaultData/Settings/dummy.txt rename to installer/portable/App/DefaultData/Settings/dummy.txt diff --git a/src/Greenshot/releases/portable/Data/Greenshot/dummy.txt b/installer/portable/Data/Greenshot/dummy.txt similarity index 100% rename from src/Greenshot/releases/portable/Data/Greenshot/dummy.txt rename to installer/portable/Data/Greenshot/dummy.txt diff --git a/src/Greenshot/releases/portable/Data/Settings/dummy.txt b/installer/portable/Data/Settings/dummy.txt similarity index 100% rename from src/Greenshot/releases/portable/Data/Settings/dummy.txt rename to installer/portable/Data/Settings/dummy.txt diff --git a/src/Greenshot/releases/portable/Other/Source/PortableApps.comInstallerCustom.nsh b/installer/portable/Other/Source/PortableApps.comInstallerCustom.nsh similarity index 100% rename from src/Greenshot/releases/portable/Other/Source/PortableApps.comInstallerCustom.nsh rename to installer/portable/Other/Source/PortableApps.comInstallerCustom.nsh diff --git a/src/Greenshot/Greenshot.csproj b/src/Greenshot/Greenshot.csproj index 630501ce8..a93eff8fc 100644 --- a/src/Greenshot/Greenshot.csproj +++ b/src/Greenshot/Greenshot.csproj @@ -80,7 +80,7 @@ - + diff --git a/src/Greenshot/GreenshotMain.cs b/src/Greenshot/GreenshotMain.cs index 045478d6d..753133f8e 100644 --- a/src/Greenshot/GreenshotMain.cs +++ b/src/Greenshot/GreenshotMain.cs @@ -24,8 +24,6 @@ using System.Net; using System.Reflection; using Greenshot.Forms; -// Remove AppendPrivatePath warning: -#pragma warning disable 0618 namespace Greenshot { /// /// Description of Main. @@ -41,7 +39,10 @@ namespace Greenshot { Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly ayAssembly in ayAssemblies) { - if (sShortAssemblyName != ayAssembly.FullName.Split(',')[0]) continue; + if (sShortAssemblyName != ayAssembly.FullName.Split(',')[0]) + { + continue; + } ayResult = ayAssembly; break; } diff --git a/src/Greenshot/web/htdocs/Help/index.de-DE.html b/src/Greenshot/web/htdocs/Help/index.de-DE.html deleted file mode 100644 index 9f28a117d..000000000 --- a/src/Greenshot/web/htdocs/Help/index.de-DE.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - Greenshot Hilfe - - - - - - SourceForge.net Logo - -

Greenshot Hilfe

- -

Modi

- -

Bereichsmodus

- -

- Aktivieren Sie den Bereichsmodus, indem Sie die Druck-Taste auf - Ihrer Tastatur betätigen oder Bereich abfotografieren aus dem - Kontextmenü wählen.
- Drücken und halten Sie die linke Maustaste gedrückt, um einen rechteckigen - Bereich zu definieren, der abfotografiert werden soll.
- Nach dem Loslassen der Maustaste öffnet sich das Bildbearbeitungsfenster - zur weiteren Bearbeitung Ihres Screenshots.

- Um den Bereich später noch einmal abzufotografieren, wählen Sie Zuletzt - gewählten Bereich abfotografieren. -

- -

Fenstermodus

- -

- Aktivieren Sie den FensterModus, indem Sie Alt + Druck auf - Ihrer Tastatur betätigen oder Fenster abfotografieren aus dem - Kontextmenü wählen.
- Klicken Sie auf das Fenster, dass abfotografiern werden soll.
- Nachdem Sie geklickt haben öffnet sich das Bildbearbeitungsfenster - zur weiteren Bearbeitung Ihres Screenshots. -

- -

Bildschirmmodus

- -

- Wenn Sie den gesamten Bildschirm abfotografieren wollen, drücken Sie einfach - Ctrl + Print auf Ihrer Tastatur oder wählen Sie Kompletten - Bildschirm abfotografieren.
- Der komplette Bildschirm wird sofort abfotografiert, das Bildbearbeitungsfenster - öffnet sich zur weiteren Bearbeitung Ihres Screenshots. -

- -

Bildbearbeitungsfenster

- -

- Wenn Sie das Bildbearbeitungsfenster nicht nutzen wollen knnen Sie im - Kontextmen oder im Einstellungsdialog festlegen, dass es nicht angezeigt - werden soll. In diesem Fall wird der Screenshot sofort in eine Datei - gespeichert. Speicherort, Dateiname und Bildformat sind dann abhngig von - den bevorzugten Ausgabedatei-Einstellungen im Einstellungsdialog. -

- -

Datei-Menü

- -
    -
  • Speichern: speichert die Grafik unter dem Pfad der beim letzten Speichern unter... Dialog gewählt wurde
  • -
  • Speichern unter...: öffnet einen Dialog zur Auswahl des Pfads und Dateinamens unter dem die Grafik gespeichert werden soll
  • -
  • Grafik in die Zwischenablage kopieren: kopiert die Grafik in die Zwischenablage, so dass sie in anderer Software verwendet werden kann
  • -
- -

Bearbeiten-Menü

- -
    -
  • Gewähltes Element in die Zwischenablage ausschneiden: entfernt das ausgewähltes Element und kopiert es in die Zwischenablage, so dass es in ein anderes Bildbearbeitungsfenster eingefügt werden kann
  • -
  • Gewähltes Element in die Zwischenablage kopieren: kopiert das ausgewähltes Element in die Zwischenablage, so dass es in ein anderes Bildbearbeitungsfenster eingefügt werden kann
  • -
  • Element aus der Zwischenablage einfügen: fügt ein vorher ausgeschnittenes/kopiertes Element in das Bildbearbeitungsfenster ein
  • -
  • Gewähltes Element duplizieren: dupliziert das gewählte Element
  • -
- -

Objekt-Menü

- -
    -
  • Rechteck hinzufügen: fügt ein Rechteck zur Grafik hinzu
  • -
  • Ellipse hinzufügen: fügt eine Ellipse zur Grafik hinzu
  • -
  • Textfeld hinzufügen: fügt ein Textfeld zur Grafik hinzu
  • -
  • Gewähltes Element löschen: entfernt das gewählte Element aus der Grafik
  • -
- -

- Klicken Sie ein Element an um es auszuwählen. Anschließend können Sie die Größe oder - Position verändern, oder es kopieren, ausschneiden oder entfernen. Die Größe - eines Elements kann durch Klicken und Ziehen der Anfasser (kleine schwarze - Quadrate) an der linken oberen oder der rechten unteren Ecke geändert werden. -

- - - - diff --git a/src/Greenshot/web/htdocs/Help/index.en-US.html b/src/Greenshot/web/htdocs/Help/index.en-US.html deleted file mode 100644 index 16bb57bc7..000000000 --- a/src/Greenshot/web/htdocs/Help/index.en-US.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - Greenshot Help - - - - - - SourceForge.net Logo - -

Greenshot Help

- -

Modes

- -

Region mode

- -

- Activate region mode by hitting the Print key on your keyboard - or by choosing Capture region from the context menu.
- Left-click and drag to define a rectangular area you want to be shot.
- After releasing the mouse button, the image editor window will open for - further editing of your screenshot.

- For shooting the region again later, choose Capture last region from - the context menu. -

- -

Window mode

- -

- Activate window mode by hitting Alt + Print on your keyboard - or by choosing Capture window from the context menu.
- Click the window you want to be shot.
- After clicking, the image editor window will open for - further editing of your screenshot. -

- -

Fullscreen mode

- -

- If you want to shoot the complete screen, just press Ctrl + Print on - your keyboard or choose Capture full screen from the context menu.
- The complete screen will be shot instantly, the image editor window will open for - further editing of your screenshot. -

- -

Image Editor

- -

- If you do not want to use the image editor window you can choose to skip - in in the context menu or in the settings dialog. The screenshot will be - saved directly to a file then. Storage location, filename and image format - are defined by your preferred output file settings in the settings dialog. -

- -

File menu

- -
    -
  • Save: saves the image to the file specified in the last Save as... dialog
  • -
  • Save as...: lets you choose a path and filename to save the image to
  • -
  • Copy image to clipboard: copies the image to the clipboard, for pasting it to other software
  • -
- -

Edit menu

- -
    -
  • Cut selected element to clipboard: removes the selected element and copies it to the clipboard, so that it can be pasted into another image editor window
  • -
  • Copy selected element to clipboard: copies it to the clipboard, so that it can be pasted into another image editor window
  • -
  • Paste element from clipboard: pastes a previously cut/copied element into the image editor window
  • -
  • Duplicate selected element: duplicates the selected element
  • -
- -

Object menu

- -
    -
  • Add rectangle: adds a rectangle to the image
  • -
  • Add ellipse: adds an ellipse to the image
  • -
  • Add textbox: adds a textbox to the image
  • -
  • Delete selected element: removes the selected element from the image
  • -
- -

- Click an element to select it for resizing, moving, copying, cutting, or removal. The size of an - element can be defined by dragging the grippers (small black squares) at the top-left and the - bottom-right corner of the selected element. -

- - - - diff --git a/src/Greenshot/web/htdocs/favicon.ico b/src/Greenshot/web/htdocs/favicon.ico deleted file mode 100644 index 0a2ab97c1c3eebda21de589c2bc36cb06319cb7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2550 zcmeHJYfx2H6#lHVQtmkyh#}F8Y7DK$an#WvK};YN6$C{=ke3FeqHvFd$vyXsBQuJS zFVt{I1SfeJ1TqRf67zvFltdV2W+0-F6>kxUM{DnUAq*IQ^w&MJ?s|P|?X~yXd!Gx8 zz;jTmLHs3zj0D~W47w#kUI2EHZ4$E)SrReaaHF@k7u`MG=<4o5XICdWx;oJQcRL<+ zwxO-_F@!5)Kq6Vt3I fI;?B#ukxwHq{FYdzD!X40l6OG6-3L;L+*mPP8sUQlPf-MNk z-;9l?BC&yJ{mBS~SiOh9WR$9Rjk~!Z$k@UYV=mc{~uyGySn5BLE&5eps6B z1NSs!F=aLn8myWb@X@$+bl39 z+8iUdzJgJT8Ad47X`MJ+i=Ww_?ZB`*APq6xoLxP9JniQgTf$wFeblI_|J8@V8@Vwex4 zHJXLqlH{;JS{zI|O-d<3y_QMRvX8i*p#s^De)w`0VCU?o*BuRYhV+%|ZvYO-==nn< zU7dSZf%aOU$BwuHOeHei4%p`dDe=Im>A-oyRucAVDbPSNi+%E)wH$Vzhjb{TUxgyf zfUKH@DDe#hfnM&X3`H=3EQV1`7IZ=i-TO?U0-_?a6%yY|_E;kCAv4KpTf#gf>LJWw zD55(Q;|Yi~7NMx#=Qf?#OS#UHk9|T04_<@dNZ3TmQvt223|h4>6#6hJ7zJ7QmTFAE zX3=OU4ZES32o(1-Q7@lE7A{fW7IBs`v>%5`?WSWhENRg}kz$8#>M zAY2pKE>JDGyl49U<`U)?DC#NwHL&?*F^KD0VL23|cli2s!VQWK=DlZ5#nb}f<6lOU z@oW7yZa039a(>76K@s2NdDstI8#_a?5J!1ZNd6vMOvd&52MRjzb6z`J%fS1>?vN~O xCf@`7*;TQ>MS};cQ>!W^oHWSE&JODb+vDMeVrIn8Xx}*;4)-5Bdn^7A{R5>T7|Z|w diff --git a/src/Greenshot/web/htdocs/index.html b/src/Greenshot/web/htdocs/index.html deleted file mode 100644 index 3ff31a08e..000000000 --- a/src/Greenshot/web/htdocs/index.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - Greenshot - Screenshot Tool - - - - - - - - - - - -
- SourceForge.net Logo -
- - - - -
-

Greenshot

- Revolutionary screenshot tool optimized for productivity. Save a screenshot or a part of the screen to a file within a second. Apply text and shapes to the screenshot. Offers capture of window, region or full screenshot. Supports several image formats. -

- Greenshot's project homepage on sourceforge.net
- Download Greenshot

- Greenshot Help (en)
- Greenshot Hilfe (de)
-


  -
-
- - - - From e8c0b307ee68f42661c072d21f529adcf2f854dc Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 28 Mar 2021 19:24:26 +0200 Subject: [PATCH 117/232] Code formatting (indents etc.) to get it consistent, simplify it for contributors. --- src/Greenshot.Plugin.Box/BoxConfiguration.cs | 89 +- src/Greenshot.Plugin.Box/BoxDestination.cs | 63 +- src/Greenshot.Plugin.Box/BoxEntities.cs | 64 +- src/Greenshot.Plugin.Box/BoxPlugin.cs | 174 +- src/Greenshot.Plugin.Box/BoxUtils.cs | 214 +- src/Greenshot.Plugin.Box/Forms/BoxForm.cs | 8 +- .../Forms/SettingsForm.cs | 33 +- src/Greenshot.Plugin.Box/LanguageKeys.cs | 19 +- .../Properties/AssemblyInfo.cs | 2 +- src/Greenshot.Plugin.Confluence/Confluence.cs | 576 +-- .../ConfluenceConfiguration.cs | 98 +- .../ConfluenceDestination.cs | 365 +- .../ConfluencePlugin.cs | 221 +- .../ConfluenceUtils.cs | 278 +- .../EnumDisplayer.cs | 143 +- .../Forms/ConfluenceConfigurationForm.xaml.cs | 34 +- .../Forms/ConfluencePagePicker.xaml.cs | 64 +- .../Forms/ConfluenceSearch.xaml.cs | 131 +- .../Forms/ConfluenceTreePicker.xaml.cs | 216 +- .../Forms/ConfluenceUpload.xaml.cs | 187 +- .../LanguageKeys.cs | 16 +- .../Support/ITranslationProvider.cs | 8 +- .../Support/LanguageChangedEventManager.cs | 12 +- .../Support/LanguageXMLTranslationProvider.cs | 33 +- .../Support/TranslateExtension.cs | 10 +- .../Support/TranslationData.cs | 65 +- .../Support/TranslationManager.cs | 69 +- .../DropboxDestination.cs | 70 +- src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs | 160 +- .../DropboxPluginConfiguration.cs | 57 +- src/Greenshot.Plugin.Dropbox/DropboxUtils.cs | 64 +- .../Forms/DropboxForm.cs | 10 +- .../Forms/SettingsForm.cs | 34 +- src/Greenshot.Plugin.Dropbox/LanguageKeys.cs | 17 +- .../Properties/AssemblyInfo.cs | 2 +- .../ExternalCommandConfiguration.cs | 218 +- .../ExternalCommandDestination.cs | 339 +- .../ExternalCommandForm.cs | 14 +- .../ExternalCommandPlugin.cs | 8 + .../IconCache.cs | 47 +- .../SettingsForm.cs | 198 +- .../SettingsFormDetail.cs | 278 +- .../FlickrConfiguration.cs | 100 +- .../FlickrDestination.cs | 59 +- src/Greenshot.Plugin.Flickr/FlickrPlugin.cs | 191 +- src/Greenshot.Plugin.Flickr/FlickrUtils.cs | 329 +- .../Forms/FlickrForm.cs | 8 +- .../Forms/SettingsForm.cs | 34 +- src/Greenshot.Plugin.Flickr/LanguageKeys.cs | 17 +- .../Properties/AssemblyInfo.cs | 2 +- .../Forms/GooglePhotosForm.cs | 10 +- .../Forms/SettingsForm.cs | 36 +- .../GooglePhotosConfiguration.cs | 105 +- .../GooglePhotosDestination.cs | 61 +- .../GooglePhotosPlugin.cs | 182 +- .../GooglePhotosUtils.cs | 199 +- .../LanguageKeys.cs | 19 +- .../Properties/AssemblyInfo.cs | 2 +- src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs | 16 +- .../Forms/ImgurHistory.cs | 402 +- .../Forms/SettingsForm.cs | 45 +- .../ImgurConfiguration.cs | 127 +- .../ImgurDestination.cs | 55 +- src/Greenshot.Plugin.Imgur/ImgurInfo.cs | 330 +- src/Greenshot.Plugin.Imgur/ImgurPlugin.cs | 332 +- src/Greenshot.Plugin.Imgur/ImgurUtils.cs | 590 +-- src/Greenshot.Plugin.Imgur/LanguageKeys.cs | 26 +- .../Properties/AssemblyInfo.cs | 2 +- src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs | 297 +- src/Greenshot.Plugin.Jira/Forms/JiraForm.cs | 389 +- .../Forms/JiraFormBase.cs | 10 +- .../Forms/SettingsForm.cs | 34 +- .../IssueTypeBitmapCache.cs | 44 +- .../JiraConfiguration.cs | 38 +- src/Greenshot.Plugin.Jira/JiraConnector.cs | 447 +- src/Greenshot.Plugin.Jira/JiraDestination.cs | 251 +- src/Greenshot.Plugin.Jira/JiraDetails.cs | 54 +- src/Greenshot.Plugin.Jira/JiraEventArgs.cs | 20 +- src/Greenshot.Plugin.Jira/JiraEventTypes.cs | 10 +- src/Greenshot.Plugin.Jira/JiraMonitor.cs | 333 +- src/Greenshot.Plugin.Jira/JiraPlugin.cs | 182 +- src/Greenshot.Plugin.Jira/LanguageKeys.cs | 36 +- src/Greenshot.Plugin.Jira/Log4NetLogger.cs | 181 +- .../Com/DisposableCom.cs | 1 + .../Com/DisposableComImplementation.cs | 2 + src/Greenshot.Plugin.Office/Com/Ole32Api.cs | 3 +- .../Com/OleAut32Api.cs | 4 +- .../Destinations/ExcelDestination.cs | 131 +- .../Destinations/OneNoteDestination.cs | 182 +- .../Destinations/OutlookDestination.cs | 300 +- .../Destinations/PowerpointDestination.cs | 192 +- .../Destinations/WordDestination.cs | 202 +- .../GlobalSuppressions.cs | Bin 3260 -> 3396 bytes .../OfficeConfiguration.cs | 58 +- .../OfficeExport/Entities/OneNotePage.cs | 1 + .../OfficeExport/ExcelExporter.cs | 11 +- .../OfficeExport/OneNoteExporter.cs | 22 +- .../OfficeExport/OutlookEmailExporter.cs | 94 +- .../OfficeExport/PowerpointExporter.cs | 25 +- .../OfficeExport/WordExporter.cs | 26 +- .../OfficeInterop/EmailFormat.cs | 17 +- .../OfficeInterop/OfficeVersions.cs | 28 +- src/Greenshot.Plugin.Office/OfficePlugin.cs | 178 +- .../Properties/AssemblyInfo.cs | 2 +- .../Forms/PhotobucketForm.cs | 16 +- .../Forms/SettingsForm.cs | 34 +- .../LanguageKeys.cs | 18 +- .../PhotobucketConfiguration.cs | 90 +- .../PhotobucketDestination.cs | 153 +- .../PhotobucketInfo.cs | 87 +- .../PhotobucketPlugin.cs | 202 +- .../PhotobucketUtils.cs | 445 +- .../Properties/AssemblyInfo.cs | 3 +- .../Destinations/Win10OcrDestination.cs | 114 +- .../Destinations/Win10ShareDestination.cs | 19 +- .../Internal/MemoryRandomAccessStream.cs | 74 +- .../Internal/ShareInfo.cs | 2 +- .../Native/DataTransferManagerHelper.cs | 89 +- .../Native/IDataTransferManagerInterOp.cs | 45 +- .../Processors/Win10OcrProcessor.cs | 18 +- .../Properties/AssemblyInfo.cs | 2 +- .../ToastNotificationService.cs | 12 +- .../Win10Configuration.cs | 19 +- .../Win10OcrProvider.cs | 79 +- src/Greenshot.Plugin.Win10/Win10Plugin.cs | 61 +- src/Greenshot/App.config | 33 +- .../Configuration/EditorConfiguration.cs | 252 +- src/Greenshot/Configuration/LanguageKeys.cs | 106 +- .../Controls/BindableToolStripButton.cs | 42 +- .../Controls/BindableToolStripComboBox.cs | 42 +- .../BindableToolStripDropDownButton.cs | 100 +- src/Greenshot/Controls/ColorButton.cs | 117 +- ...ontextMenuToolStripProfessionalRenderer.cs | 41 +- .../CustomToolStripProfessionalRenderer.cs | 101 +- src/Greenshot/Controls/FontFamilyComboBox.cs | 189 +- src/Greenshot/Controls/MenuStripEx.cs | 69 +- src/Greenshot/Controls/NonJumpingPanel.cs | 2 +- src/Greenshot/Controls/Pipette.cs | 280 +- .../Controls/ToolStripColorButton.cs | 111 +- src/Greenshot/Controls/ToolStripEx.cs | 72 +- .../Controls/ToolStripNumericUpDown.cs | 113 +- .../Destinations/ClipboardDestination.cs | 97 +- .../Destinations/EditorDestination.cs | 173 +- .../Destinations/EmailDestination.cs | 95 +- src/Greenshot/Destinations/FileDestination.cs | 223 +- .../Destinations/FileWithDialogDestination.cs | 97 +- .../Destinations/PickerDestination.cs | 72 +- .../Destinations/PrinterDestination.cs | 157 +- .../Drawing/Adorners/AbstractAdorner.cs | 236 +- src/Greenshot/Drawing/Adorners/MoveAdorner.cs | 242 +- .../Drawing/Adorners/ResizeAdorner.cs | 282 +- .../Drawing/Adorners/TargetAdorner.cs | 170 +- src/Greenshot/Drawing/ArrowContainer.cs | 182 +- src/Greenshot/Drawing/CropContainer.cs | 110 +- src/Greenshot/Drawing/CursorContainer.cs | 150 +- src/Greenshot/Drawing/DrawableContainer.cs | 1013 ++-- .../Drawing/DrawableContainerList.cs | 1214 ++--- src/Greenshot/Drawing/EllipseContainer.cs | 193 +- .../Drawing/Fields/AbstractFieldHolder.cs | 274 +- .../Fields/AbstractFieldHolderWithChildren.cs | 215 +- .../Binding/AbstractBindingConverter.cs | 54 +- .../Fields/Binding/BidirectionalBinding.cs | 292 +- .../DecimalDoublePercentageConverter.cs | 49 +- .../Fields/Binding/DecimalFloatConverter.cs | 55 +- .../Fields/Binding/DecimalIntConverter.cs | 55 +- .../Fields/Binding/IBindingConverter.cs | 24 +- .../Fields/Binding/IBindingValidator.cs | 26 +- .../Fields/Binding/NotNullValidator.cs | 38 +- src/Greenshot/Drawing/Fields/Field.cs | 190 +- .../Drawing/Fields/FieldAggregator.cs | 310 +- src/Greenshot/Drawing/Fields/FieldType.cs | 167 +- src/Greenshot/Drawing/FilterContainer.cs | 123 +- .../Drawing/Filters/AbstractFilter.cs | 107 +- src/Greenshot/Drawing/Filters/BlurFilter.cs | 79 +- .../Drawing/Filters/BrightnessFilter.cs | 75 +- .../Drawing/Filters/GrayscaleFilter.cs | 94 +- .../Drawing/Filters/HighlightFilter.cs | 92 +- src/Greenshot/Drawing/Filters/IFilter.cs | 15 +- .../Drawing/Filters/MagnifierFilter.cs | 73 +- .../Drawing/Filters/PixelizationFilter.cs | 91 +- src/Greenshot/Drawing/FreehandContainer.cs | 376 +- src/Greenshot/Drawing/HighlightContainer.cs | 143 +- src/Greenshot/Drawing/IconContainer.cs | 147 +- src/Greenshot/Drawing/ImageContainer.cs | 385 +- src/Greenshot/Drawing/LineContainer.cs | 115 +- src/Greenshot/Drawing/ObfuscateContainer.cs | 109 +- src/Greenshot/Drawing/Positions.cs | 30 +- src/Greenshot/Drawing/RectangleContainer.cs | 180 +- .../Drawing/SpeechbubbleContainer.cs | 534 ++- src/Greenshot/Drawing/StepLabelContainer.cs | 315 +- src/Greenshot/Drawing/Surface.cs | 4143 +++++++++-------- src/Greenshot/Drawing/TextContainer.cs | 55 +- src/Greenshot/Forms/AboutForm.cs | 538 ++- src/Greenshot/Forms/AnimatingBaseForm.cs | 16 +- src/Greenshot/Forms/BaseForm.cs | 16 +- src/Greenshot/Forms/BugReportForm.cs | 60 +- src/Greenshot/Forms/CaptureForm.cs | 1577 ++++--- src/Greenshot/Forms/ColorDialog.cs | 396 +- .../Forms/ColorPickerToolStripButton.cs | 140 +- src/Greenshot/Forms/DropShadowSettingsForm.cs | 56 +- src/Greenshot/Forms/ImageEditorForm.cs | 3026 ++++++------ src/Greenshot/Forms/LanguageDialog.cs | 124 +- src/Greenshot/Forms/MainForm.cs | 2768 ++++++----- src/Greenshot/Forms/MovableShowColorForm.cs | 139 +- src/Greenshot/Forms/PrintOptionsDialog.cs | 51 +- src/Greenshot/Forms/ResizeSettingsForm.cs | 304 +- src/Greenshot/Forms/SettingsForm.cs | 1316 +++--- .../Forms/ToolStripMenuSelectList.cs | 248 +- src/Greenshot/Forms/TornEdgeSettingsForm.cs | 149 +- src/Greenshot/Help/HelpFileLoader.cs | 127 +- src/Greenshot/Helpers/CaptureHelper.cs | 1688 ++++--- src/Greenshot/Helpers/Colors.cs | 65 +- src/Greenshot/Helpers/CopyData.cs | 1005 ++-- src/Greenshot/Helpers/DestinationHelper.cs | 141 +- src/Greenshot/Helpers/Entities/UpdateFeed.cs | 8 +- src/Greenshot/Helpers/GeometryHelper.cs | 79 +- src/Greenshot/Helpers/GuiRectangle.cs | 52 +- src/Greenshot/Helpers/IECaptureHelper.cs | 1290 ++--- .../Helpers/IEInterop/IEContainer.cs | 914 ++-- src/Greenshot/Helpers/MailHelper.cs | 844 ++-- .../Helpers/NotifyIconNotificationService.cs | 8 +- src/Greenshot/Helpers/PluginHelper.cs | 292 +- src/Greenshot/Helpers/PrintHelper.cs | 370 +- src/Greenshot/Helpers/ProcessorHelper.cs | 96 +- src/Greenshot/Helpers/ResourceMutex.cs | 266 +- src/Greenshot/Helpers/ScaleHelper.cs | 628 +-- src/Greenshot/Helpers/SoundHelper.cs | 148 +- src/Greenshot/Helpers/StartupHelper.cs | 466 +- .../Helpers/ToolStripItemEndisabler.cs | 144 +- src/Greenshot/Helpers/UpdateService.cs | 6 +- src/Greenshot/Memento/AddElementMemento.cs | 82 +- src/Greenshot/Memento/AddElementsMemento.cs | 80 +- .../Memento/ChangeFieldHolderMemento.cs | 91 +- src/Greenshot/Memento/DeleteElementMemento.cs | 93 +- .../Memento/DeleteElementsMemento.cs | 80 +- .../DrawableContainerBoundsChangeMemento.cs | 156 +- .../Memento/SurfaceBackgroundChangeMemento.cs | 100 +- src/Greenshot/Memento/TextChangeMemento.cs | 80 +- src/Greenshot/Processors/TitleFixProcessor.cs | 60 +- src/GreenshotPlugin/Controls/AnimatingForm.cs | 188 +- .../Controls/BackgroundForm.cs | 125 +- .../Controls/ExtendedWebBrowser.cs | 60 +- .../Controls/FormWithoutActivation.cs | 11 +- .../Controls/GreenshotButton.cs | 17 +- .../Controls/GreenshotCheckBox.cs | 32 +- .../Controls/GreenshotColumnSorter.cs | 179 +- .../Controls/GreenshotComboBox.cs | 150 +- src/GreenshotPlugin/Controls/GreenshotForm.cs | 925 ++-- .../Controls/GreenshotGroupBox.cs | 17 +- .../Controls/GreenshotLabel.cs | 17 +- .../Controls/GreenshotRadioButton.cs | 32 +- .../Controls/GreenshotTabPage.cs | 17 +- .../Controls/GreenshotTextBox.cs | 21 +- .../Controls/GreenshotToolDropDownButton.cs | 17 +- .../Controls/GreenshotToolStripButton.cs | 17 +- .../Controls/GreenshotToolStripLabel.cs | 17 +- .../Controls/GreenshotToolStripMenuItem.cs | 17 +- src/GreenshotPlugin/Controls/HotkeyControl.cs | 1138 +++-- .../Controls/IGreenshotConfigBindable.cs | 32 +- .../Controls/IGreenshotLanguageBindable.cs | 28 +- .../Controls/OAuthLoginForm.cs | 148 +- .../Controls/PleaseWaitForm.cs | 213 +- src/GreenshotPlugin/Controls/QualityDialog.cs | 80 +- .../Controls/SaveImageFileDialog.cs | 366 +- src/GreenshotPlugin/Controls/ThumbnailForm.cs | 118 +- .../Core/AbstractDestination.cs | 664 +-- src/GreenshotPlugin/Core/AbstractProcessor.cs | 67 +- src/GreenshotPlugin/Core/AccessibleHelper.cs | 343 +- src/GreenshotPlugin/Core/AnimationHelpers.cs | 949 ++-- .../Core/BinaryStructHelper.cs | 149 +- src/GreenshotPlugin/Core/Cache.cs | 387 +- src/GreenshotPlugin/Core/Capture.cs | 93 +- src/GreenshotPlugin/Core/CaptureDetails.cs | 74 +- src/GreenshotPlugin/Core/CaptureHandler.cs | 39 +- src/GreenshotPlugin/Core/ClipboardHelper.cs | 1441 +++--- src/GreenshotPlugin/Core/CoreConfiguration.cs | 1085 +++-- src/GreenshotPlugin/Core/CredentialsHelper.cs | 818 ++-- .../Core/DisplayKeyAttribute.cs | 29 +- src/GreenshotPlugin/Core/DpiHelper.cs | 15 +- src/GreenshotPlugin/Core/EffectConverter.cs | 363 +- src/GreenshotPlugin/Core/Enums/HResult.cs | 2 +- .../Core/Enums/MonitorDpiType.cs | 1 + src/GreenshotPlugin/Core/Enums/MonitorFrom.cs | 1 + src/GreenshotPlugin/Core/EnvironmentInfo.cs | 340 +- src/GreenshotPlugin/Core/EventDelay.cs | 40 +- src/GreenshotPlugin/Core/ExplorerHelper.cs | 83 +- src/GreenshotPlugin/Core/FastBitmap.cs | 1941 ++++---- src/GreenshotPlugin/Core/FilenameHelper.cs | 1142 +++-- src/GreenshotPlugin/Core/Fraction.cs | 8 +- .../Core/GreenshotResources.cs | 40 +- src/GreenshotPlugin/Core/HResultExtensions.cs | 2 +- src/GreenshotPlugin/Core/IEHelper.cs | 302 +- src/GreenshotPlugin/Core/IImage.cs | 70 +- src/GreenshotPlugin/Core/ImageHelper.cs | 2964 ++++++------ src/GreenshotPlugin/Core/ImageOutput.cs | 1213 ++--- src/GreenshotPlugin/Core/ImageWrapper.cs | 125 +- src/GreenshotPlugin/Core/InterfaceUtils.cs | 59 +- src/GreenshotPlugin/Core/JSONHelper.cs | 677 +-- src/GreenshotPlugin/Core/Language.cs | 1357 +++--- src/GreenshotPlugin/Core/LanguageFile.cs | 80 +- src/GreenshotPlugin/Core/LogHelper.cs | 150 +- src/GreenshotPlugin/Core/NetworkHelper.cs | 16 +- .../Core/OAuth/LocalJsonReceiver.cs | 48 +- .../Core/OAuth/LocalServerCodeReceiver.cs | 71 +- .../Core/OAuth/OAuth2AuthorizeMode.cs | 9 +- .../Core/OAuth/OAuth2Helper.cs | 595 +-- .../Core/OAuth/OAuth2Settings.cs | 93 +- .../Core/OAuth/OAuthSession.cs | 361 +- .../Core/OAuth/OAuthSignatureTypes.cs | 3 +- src/GreenshotPlugin/Core/ObjectExtensions.cs | 150 +- src/GreenshotPlugin/Core/PluginUtils.cs | 305 +- src/GreenshotPlugin/Core/QuantizerHelper.cs | 1000 ++-- .../Core/RegistryKeyExtensions.cs | 11 +- .../Core/SimpleServiceProvider.cs | 4 +- src/GreenshotPlugin/Core/StringExtensions.cs | 186 +- src/GreenshotPlugin/Core/SvgImage.cs | 154 +- src/GreenshotPlugin/Core/WindowCapture.cs | 483 +- src/GreenshotPlugin/Core/WindowDetails.cs | 863 ++-- src/GreenshotPlugin/Core/WindowsEnumerator.cs | 126 +- .../Core/WmInputLangChangeRequestFilter.cs | 67 +- src/GreenshotPlugin/Effects/AdjustEffect.cs | 55 +- src/GreenshotPlugin/Effects/BorderEffect.cs | 47 +- .../Effects/DropShadowEffect.cs | 56 +- .../Effects/GrayscaleEffect.cs | 26 +- src/GreenshotPlugin/Effects/IEffect.cs | 35 +- src/GreenshotPlugin/Effects/InvertEffect.cs | 26 +- .../Effects/MonochromeEffect.cs | 39 +- .../Effects/ReduceColorsEffect.cs | 70 +- .../Effects/ResizeCanvasEffect.cs | 68 +- src/GreenshotPlugin/Effects/ResizeEffect.cs | 54 +- src/GreenshotPlugin/Effects/RotateEffect.cs | 70 +- src/GreenshotPlugin/Effects/TornEdgeEffect.cs | 92 +- src/GreenshotPlugin/FileDescriptorReader.cs | 12 +- src/GreenshotPlugin/GlobalSuppressions.cs | Bin 112958 -> 119362 bytes .../Hooking/WindowsEventHook.cs | 218 +- .../Hooking/WindowsOpenCloseMonitor.cs | 277 +- .../Hooking/WindowsTitleMonitor.cs | 257 +- .../IEInterop/IHTMLBodyElement.cs | 27 +- .../IEInterop/IHTMLCurrentStyle.cs | 80 +- .../IEInterop/IHTMLDocument.cs | 27 +- .../IEInterop/IHTMLDocument2.cs | 110 +- .../IEInterop/IHTMLDocument3.cs | 43 +- .../IEInterop/IHTMLDocument4.cs | 6 +- .../IEInterop/IHTMLDocument5.cs | 24 +- src/GreenshotPlugin/IEInterop/IHTMLElement.cs | 158 +- .../IEInterop/IHTMLElement2.cs | 31 +- .../IEInterop/IHTMLElementCollection.cs | 18 +- .../IEInterop/IHTMLFrameBase.cs | 72 +- .../IEInterop/IHTMLFramesCollection2.cs | 27 +- src/GreenshotPlugin/IEInterop/IHTMLRect.cs | 34 +- src/GreenshotPlugin/IEInterop/IHTMLScreen.cs | 26 +- src/GreenshotPlugin/IEInterop/IHTMLScreen2.cs | 34 +- .../IEInterop/IHTMLSelectionObject.cs | 43 +- src/GreenshotPlugin/IEInterop/IHTMLStyle.cs | 463 +- .../IEInterop/IHTMLTxtRange.cs | 177 +- src/GreenshotPlugin/IEInterop/IHTMLWindow2.cs | 48 +- src/GreenshotPlugin/IEInterop/IHTMLWindow3.cs | 22 +- src/GreenshotPlugin/IEInterop/IHTMLWindow4.cs | 19 +- src/GreenshotPlugin/IEInterop/IWebBrowser2.cs | 238 +- src/GreenshotPlugin/IniFile/IniAttributes.cs | 106 +- src/GreenshotPlugin/IniFile/IniConfig.cs | 856 ++-- src/GreenshotPlugin/IniFile/IniReader.cs | 81 +- src/GreenshotPlugin/IniFile/IniSection.cs | 345 +- src/GreenshotPlugin/IniFile/IniValue.cs | 981 ++-- src/GreenshotPlugin/Interfaces/CaptureMode.cs | 1 + .../Interfaces/Drawing/Adorners/IAdorner.cs | 128 +- .../Interfaces/Drawing/Container.cs | 264 +- .../Interfaces/Drawing/IField.cs | 94 +- .../Interfaces/Drawing/IFieldholder.cs | 28 +- .../Interfaces/Drawing/IMemento.cs | 44 +- .../Interfaces/Forms/ImageEditor.cs | 41 +- src/GreenshotPlugin/Interfaces/ICapture.cs | 38 +- .../Interfaces/ICaptureDetails.cs | 102 +- .../Interfaces/IDestination.cs | 204 +- src/GreenshotPlugin/Interfaces/IProcessor.cs | 70 +- .../Interfaces/IServiceLocator.cs | 2 +- src/GreenshotPlugin/Interfaces/ISurface.cs | 66 +- .../Interfaces/Ocr/IOcrProvider.cs | 4 +- src/GreenshotPlugin/Interfaces/Ocr/Line.cs | 2 +- .../Interfaces/Ocr/OcrInformation.cs | 99 +- .../Interfaces/Plugin/IGreenshotHost.cs | 3 +- .../Interfaces/Plugin/IGreenshotPlugin.cs | 3 +- .../Interfaces/Plugin/PluginAttribute.cs | 45 +- .../Plugin/SurfaceOutputSettings.cs | 58 +- .../Interfaces/SurfaceDrawingModeEventArgs.cs | 6 +- .../Interfaces/SurfaceElementEventArgs.cs | 6 +- .../Interfaces/SurfaceMessageEventArgs.cs | 22 +- src/GreenshotPlugin/Interop/Base.cs | 16 +- src/GreenshotPlugin/Interop/COMWrapper.cs | 977 ++-- .../Interop/ComProgIdAttribute.cs | 112 +- src/GreenshotPlugin/Interop/IAppVisibility.cs | 31 +- src/GreenshotPlugin/Interop/IDispatch.cs | 32 +- .../Interop/IOleCommandTarget.cs | 26 +- src/GreenshotPlugin/Interop/IOleWindow.cs | 20 +- .../Interop/IServiceProvider.cs | 21 +- src/GreenshotPlugin/Interop/IUnknown.cs | 22 +- src/GreenshotPlugin/UnmanagedHelpers/DWM.cs | 109 +- .../Enums/DWMWINDOWATTRIBUTE.cs | 12 +- .../Enums/DWM_THUMBNAIL_PROPERTIES.cs | 48 +- .../Enums/DesktopAccessRight.cs | 3 +- .../UnmanagedHelpers/Enums/DeviceCaps.cs | 4 +- .../Enums/ExtendedWindowStyleFlags.cs | 9 +- .../Enums/ProcessAccessFlags.cs | 3 +- .../UnmanagedHelpers/Enums/RegionResult.cs | 3 +- .../Enums/SendMessageTimeoutFlags.cs | 5 +- .../Enums/ShowWindowCommand.cs | 15 +- .../UnmanagedHelpers/Enums/SoundFlags.cs | 8 +- .../UnmanagedHelpers/Enums/ThreadAccess.cs | 3 +- .../UnmanagedHelpers/Enums/Win32Error.cs | 3 +- .../UnmanagedHelpers/Enums/WinEvent.cs | 4 +- .../UnmanagedHelpers/Enums/WindowLongIndex.cs | 4 +- .../Enums/WindowPlacementFlags.cs | 5 +- .../UnmanagedHelpers/Enums/WindowPos.cs | 7 +- .../Enums/WindowStyleFlags.cs | 22 +- .../UnmanagedHelpers/Enums/WindowsMessages.cs | 2 +- src/GreenshotPlugin/UnmanagedHelpers/GDI32.cs | 693 +-- .../UnmanagedHelpers/GDIplus.cs | 588 +-- .../UnmanagedHelpers/Kernel32.cs | 175 +- src/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs | 45 +- .../SafeCurrentInputDesktopHandle.cs | 23 +- .../UnmanagedHelpers/SafeIconHandle.cs | 10 +- .../UnmanagedHelpers/SafeWindowDcHandle.cs | 16 +- .../UnmanagedHelpers/Shell32.cs | 151 +- .../UnmanagedHelpers/Structs/CursorInfo.cs | 3 +- .../UnmanagedHelpers/Structs/IconInfo.cs | 3 +- .../UnmanagedHelpers/Structs/POINT.cs | 22 +- .../UnmanagedHelpers/Structs/RECT.cs | 173 +- .../UnmanagedHelpers/Structs/RECTF.cs | 24 +- .../UnmanagedHelpers/Structs/SCROLLINFO.cs | 3 +- .../UnmanagedHelpers/Structs/SIZE.cs | 41 +- .../UnmanagedHelpers/Structs/WindowInfo.cs | 10 +- .../Structs/WindowPlacement.cs | 9 +- .../UnmanagedHelpers/User32.cs | 450 +- src/GreenshotPlugin/UnmanagedHelpers/Win32.cs | 38 +- src/GreenshotPlugin/UnmanagedHelpers/WinMM.cs | 27 +- 435 files changed, 46647 insertions(+), 39014 deletions(-) diff --git a/src/Greenshot.Plugin.Box/BoxConfiguration.cs b/src/Greenshot.Plugin.Box/BoxConfiguration.cs index a940b319e..a4d83ef68 100644 --- a/src/Greenshot.Plugin.Box/BoxConfiguration.cs +++ b/src/Greenshot.Plugin.Box/BoxConfiguration.cs @@ -25,56 +25,55 @@ using Greenshot.Plugin.Box.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Box { - /// - /// Description of ImgurConfiguration. - /// - [IniSection("Box", Description = "Greenshot Box Plugin configuration")] - public class BoxConfiguration : IniSection { - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat { get; set; } +namespace Greenshot.Plugin.Box +{ + /// + /// Description of ImgurConfiguration. + /// + [IniSection("Box", Description = "Greenshot Box Plugin configuration")] + public class BoxConfiguration : IniSection + { + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } - [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality { get; set; } + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } - [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Box link to clipboard.", DefaultValue = "true")] - public bool AfterUploadLinkToClipBoard { get; set; } + [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Box link to clipboard.", DefaultValue = "true")] + public bool AfterUploadLinkToClipBoard { get; set; } - [IniProperty("UseSharedLink", Description = "Use the shared link, instead of the private, on the clipboard", DefaultValue = "True")] - public bool UseSharedLink { get; set; } - [IniProperty("FolderId", Description = "Folder ID to upload to, only change if you know what you are doing!", DefaultValue = "0")] - public string FolderId { get; set; } + [IniProperty("UseSharedLink", Description = "Use the shared link, instead of the private, on the clipboard", DefaultValue = "True")] + public bool UseSharedLink { get; set; } - [IniProperty("RefreshToken", Description = "Box authorization refresh Token", Encrypted = true)] - public string RefreshToken { get; set; } + [IniProperty("FolderId", Description = "Folder ID to upload to, only change if you know what you are doing!", DefaultValue = "0")] + public string FolderId { get; set; } - /// - /// Not stored - /// - public string AccessToken { - get; - set; - } + [IniProperty("RefreshToken", Description = "Box authorization refresh Token", Encrypted = true)] + public string RefreshToken { get; set; } - /// - /// Not stored - /// - public DateTimeOffset AccessTokenExpires { - get; - set; - } + /// + /// Not stored + /// + public string AccessToken { get; set; } - /// - /// A form for token - /// - /// bool true if OK was pressed, false if cancel - public bool ShowConfigDialog() { - DialogResult result = new SettingsForm().ShowDialog(); - if (result == DialogResult.OK) { - return true; - } - return false; - } + /// + /// Not stored + /// + public DateTimeOffset AccessTokenExpires { get; set; } - } -} + /// + /// A form for token + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + DialogResult result = new SettingsForm().ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/BoxDestination.cs b/src/Greenshot.Plugin.Box/BoxDestination.cs index 3c1a0622d..0bc547b88 100644 --- a/src/Greenshot.Plugin.Box/BoxDestination.cs +++ b/src/Greenshot.Plugin.Box/BoxDestination.cs @@ -24,33 +24,42 @@ using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace Greenshot.Plugin.Box { - public class BoxDestination : AbstractDestination { - private readonly BoxPlugin _plugin; - public BoxDestination(BoxPlugin plugin) { - _plugin = plugin; - } - - public override string Designation => "Box"; +namespace Greenshot.Plugin.Box +{ + public class BoxDestination : AbstractDestination + { + private readonly BoxPlugin _plugin; - public override string Description => Language.GetString("box", LangKey.upload_menu_item); + public BoxDestination(BoxPlugin plugin) + { + _plugin = plugin; + } - public override Image DisplayIcon { - get { - ComponentResourceManager resources = new ComponentResourceManager(typeof(BoxPlugin)); - return (Image)resources.GetObject("Box"); - } - } + public override string Designation => "Box"; - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - string uploadUrl = _plugin.Upload(captureDetails, surface); - if (uploadUrl != null) { - exportInformation.ExportMade = true; - exportInformation.Uri = uploadUrl; - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + public override string Description => Language.GetString("box", LangKey.upload_menu_item); + + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(BoxPlugin)); + return (Image) resources.GetObject("Box"); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + string uploadUrl = _plugin.Upload(captureDetails, surface); + if (uploadUrl != null) + { + exportInformation.ExportMade = true; + exportInformation.Uri = uploadUrl; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/BoxEntities.cs b/src/Greenshot.Plugin.Box/BoxEntities.cs index bf5476f4e..d99612377 100644 --- a/src/Greenshot.Plugin.Box/BoxEntities.cs +++ b/src/Greenshot.Plugin.Box/BoxEntities.cs @@ -22,39 +22,35 @@ using System.Collections.Generic; using System.Runtime.Serialization; -namespace Greenshot.Plugin.Box { - [DataContract] - public class Authorization { - [DataMember(Name = "access_token")] - public string AccessToken { get; set; } - [DataMember(Name = "expires_in")] - public int ExpiresIn { get; set; } - [DataMember(Name = "refresh_token")] - public string RefreshToken { get; set; } - [DataMember(Name = "token_type")] - public string TokenType { get; set; } - } - [DataContract] - public class SharedLink { - [DataMember(Name = "url")] - public string Url { get; set; } - [DataMember(Name = "download_url")] - public string DownloadUrl { get; set; } - } +namespace Greenshot.Plugin.Box +{ + [DataContract] + public class Authorization + { + [DataMember(Name = "access_token")] public string AccessToken { get; set; } + [DataMember(Name = "expires_in")] public int ExpiresIn { get; set; } + [DataMember(Name = "refresh_token")] public string RefreshToken { get; set; } + [DataMember(Name = "token_type")] public string TokenType { get; set; } + } - [DataContract] - public class FileEntry { - [DataMember(Name = "id")] - public string Id { get; set; } - [DataMember(Name = "name")] - public string Name { get; set; } - [DataMember(Name = "shared_link")] - public SharedLink SharedLink { get; set; } - } + [DataContract] + public class SharedLink + { + [DataMember(Name = "url")] public string Url { get; set; } + [DataMember(Name = "download_url")] public string DownloadUrl { get; set; } + } - [DataContract] - public class Upload { - [DataMember(Name = "entries")] - public List Entries { get; set; } - } -} + [DataContract] + public class FileEntry + { + [DataMember(Name = "id")] public string Id { get; set; } + [DataMember(Name = "name")] public string Name { get; set; } + [DataMember(Name = "shared_link")] public SharedLink SharedLink { get; set; } + } + + [DataContract] + public class Upload + { + [DataMember(Name = "entries")] public List Entries { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/BoxPlugin.cs b/src/Greenshot.Plugin.Box/BoxPlugin.cs index 6a01dda9e..9918b5e93 100644 --- a/src/Greenshot.Plugin.Box/BoxPlugin.cs +++ b/src/Greenshot.Plugin.Box/BoxPlugin.cs @@ -30,99 +30,111 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Box { - /// - /// This is the Box base code - /// +namespace Greenshot.Plugin.Box +{ + /// + /// This is the Box base code + /// [Plugin("Box", true)] - public class BoxPlugin : IGreenshotPlugin { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BoxPlugin)); - private static BoxConfiguration _config; - private ComponentResourceManager _resources; - private ToolStripMenuItem _itemPlugInConfig; + public class BoxPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BoxPlugin)); + private static BoxConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInConfig; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected void Dispose(bool disposing) - { - if (!disposing) return; + protected void Dispose(bool disposing) + { + if (!disposing) return; - if (_itemPlugInConfig == null) return; - - _itemPlugInConfig.Dispose(); - _itemPlugInConfig = null; - } + if (_itemPlugInConfig == null) return; - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - public bool Initialize() { + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; + } - // Register configuration (don't need the configuration itself) - _config = IniConfig.GetIniSection(); - _resources = new ComponentResourceManager(typeof(BoxPlugin)); + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + public bool Initialize() + { + // Register configuration (don't need the configuration itself) + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(BoxPlugin)); SimpleServiceProvider.Current.AddService(new BoxDestination(this)); - _itemPlugInConfig = new ToolStripMenuItem { - Image = (Image) _resources.GetObject("Box"), - Text = Language.GetString("box", LangKey.Configure) - }; - _itemPlugInConfig.Click += ConfigMenuClick; + _itemPlugInConfig = new ToolStripMenuItem + { + Image = (Image) _resources.GetObject("Box"), + Text = Language.GetString("box", LangKey.Configure) + }; + _itemPlugInConfig.Click += ConfigMenuClick; - PluginUtils.AddToContextMenu(_itemPlugInConfig); - Language.LanguageChanged += OnLanguageChanged; - return true; - } + PluginUtils.AddToContextMenu(_itemPlugInConfig); + Language.LanguageChanged += OnLanguageChanged; + return true; + } - public void OnLanguageChanged(object sender, EventArgs e) { - if (_itemPlugInConfig != null) { - _itemPlugInConfig.Text = Language.GetString("box", LangKey.Configure); - } - } + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Text = Language.GetString("box", LangKey.Configure); + } + } - public void Shutdown() { - LOG.Debug("Box Plugin shutdown."); - } + public void Shutdown() + { + LOG.Debug("Box Plugin shutdown."); + } - /// - /// Implementation of the IPlugin.Configure - /// - public void Configure() { - _config.ShowConfigDialog(); - } + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + _config.ShowConfigDialog(); + } - public void ConfigMenuClick(object sender, EventArgs eventArgs) { - _config.ShowConfigDialog(); - } + public void ConfigMenuClick(object sender, EventArgs eventArgs) + { + _config.ShowConfigDialog(); + } - /// - /// This will be called when the menu item in the Editor is clicked - /// - public string Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload) { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); - try { - string url = null; - string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); - SurfaceContainer imageToUpload = new SurfaceContainer(surfaceToUpload, outputSettings, filename); - - new PleaseWaitForm().ShowAndWait("Box", Language.GetString("box", LangKey.communication_wait), - delegate { - url = BoxUtils.UploadToBox(imageToUpload, captureDetails.Title, filename); - } - ); + /// + /// This will be called when the menu item in the Editor is clicked + /// + public string Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload) + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); + try + { + string url = null; + string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); + SurfaceContainer imageToUpload = new SurfaceContainer(surfaceToUpload, outputSettings, filename); - if (url != null && _config.AfterUploadLinkToClipBoard) { - ClipboardHelper.SetClipboardData(url); - } + new PleaseWaitForm().ShowAndWait("Box", Language.GetString("box", LangKey.communication_wait), + delegate { url = BoxUtils.UploadToBox(imageToUpload, captureDetails.Title, filename); } + ); - return url; - } catch (Exception ex) { - LOG.Error("Error uploading.", ex); - MessageBox.Show(Language.GetString("box", LangKey.upload_failure) + " " + ex.Message); - return null; - } - } - } -} + if (url != null && _config.AfterUploadLinkToClipBoard) + { + ClipboardHelper.SetClipboardData(url); + } + + return url; + } + catch (Exception ex) + { + LOG.Error("Error uploading.", ex); + MessageBox.Show(Language.GetString("box", LangKey.upload_failure) + " " + ex.Message); + return null; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/BoxUtils.cs b/src/Greenshot.Plugin.Box/BoxUtils.cs index 22e8acf49..37a0eac53 100644 --- a/src/Greenshot.Plugin.Box/BoxUtils.cs +++ b/src/Greenshot.Plugin.Box/BoxUtils.cs @@ -27,112 +27,128 @@ using GreenshotPlugin.Core; using GreenshotPlugin.Core.OAuth; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Box { - +namespace Greenshot.Plugin.Box +{ /// /// Description of BoxUtils. /// - public static class BoxUtils { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(BoxUtils)); - private static readonly BoxConfiguration Config = IniConfig.GetIniSection(); - private const string UploadFileUri = "https://upload.box.com/api/2.0/files/content"; - private const string FilesUri = "https://www.box.com/api/2.0/files/{0}"; + public static class BoxUtils + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(BoxUtils)); + private static readonly BoxConfiguration Config = IniConfig.GetIniSection(); + private const string UploadFileUri = "https://upload.box.com/api/2.0/files/content"; + private const string FilesUri = "https://www.box.com/api/2.0/files/{0}"; - /// - /// Put string - /// - /// - /// - /// OAuth2Settings - /// response - public static string HttpPut(string url, string content, OAuth2Settings settings) { - var webRequest= OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.PUT, url, settings); - - byte[] data = Encoding.UTF8.GetBytes(content); - using (var requestStream = webRequest.GetRequestStream()) { - requestStream.Write(data, 0, data.Length); - } - return NetworkHelper.GetResponseAsString(webRequest); - } - - /// - /// Do the actual upload to Box - /// For more details on the available parameters, see: http://developers.box.net/w/page/12923951/ApiFunction_Upload%20and%20Download - /// - /// Image for box upload - /// Title of box upload - /// Filename of box upload - /// url to uploaded image - public static string UploadToBox(SurfaceContainer image, string title, string filename) { - - // Fill the OAuth2Settings - var settings = new OAuth2Settings - { - AuthUrlPattern = "https://app.box.com/api/oauth2/authorize?client_id={ClientId}&response_type=code&state={State}&redirect_uri={RedirectUrl}", - TokenUrl = "https://api.box.com/oauth2/token", - CloudServiceName = "Box", - ClientId = BoxCredentials.ClientId, - ClientSecret = BoxCredentials.ClientSecret, - RedirectUrl = "https://getgreenshot.org/authorize/box", - AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, - RefreshToken = Config.RefreshToken, - AccessToken = Config.AccessToken, - AccessTokenExpires = Config.AccessTokenExpires - }; - - - // Copy the settings from the config, which is kept in memory and on the disk - - try { - var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, UploadFileUri, settings); - IDictionary parameters = new Dictionary - { - { "file", image }, - { "parent_id", Config.FolderId } - }; - - NetworkHelper.WriteMultipartFormData(webRequest, parameters); - - var response = NetworkHelper.GetResponseAsString(webRequest); - - Log.DebugFormat("Box response: {0}", response); - - var upload = JsonSerializer.Deserialize(response); - if (upload?.Entries == null || upload.Entries.Count == 0) return null; - - if (Config.UseSharedLink) { - string filesResponse = HttpPut(string.Format(FilesUri, upload.Entries[0].Id), "{\"shared_link\": {\"access\": \"open\"}}", settings); - var file = JsonSerializer.Deserialize(filesResponse); - return file.SharedLink.Url; - } - return $"http://www.box.com/files/0/f/0/1/f_{upload.Entries[0].Id}"; - } finally { - // Copy the settings back to the config, so they are stored. - Config.RefreshToken = settings.RefreshToken; - Config.AccessToken = settings.AccessToken; - Config.AccessTokenExpires = settings.AccessTokenExpires; - Config.IsDirty = true; - IniConfig.Save(); - } - } - } - /// - /// A simple helper class for the DataContractJsonSerializer - /// - internal static class JsonSerializer { /// - /// Helper method to parse JSON to object - /// - /// - /// - /// - public static T Deserialize(string jsonString) { - var deserializer = new DataContractJsonSerializer(typeof(T)); + /// Put string + ///
+ /// + /// + /// OAuth2Settings + /// response + public static string HttpPut(string url, string content, OAuth2Settings settings) + { + var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.PUT, url, settings); + + byte[] data = Encoding.UTF8.GetBytes(content); + using (var requestStream = webRequest.GetRequestStream()) + { + requestStream.Write(data, 0, data.Length); + } + + return NetworkHelper.GetResponseAsString(webRequest); + } + + /// + /// Do the actual upload to Box + /// For more details on the available parameters, see: http://developers.box.net/w/page/12923951/ApiFunction_Upload%20and%20Download + /// + /// Image for box upload + /// Title of box upload + /// Filename of box upload + /// url to uploaded image + public static string UploadToBox(SurfaceContainer image, string title, string filename) + { + // Fill the OAuth2Settings + var settings = new OAuth2Settings + { + AuthUrlPattern = "https://app.box.com/api/oauth2/authorize?client_id={ClientId}&response_type=code&state={State}&redirect_uri={RedirectUrl}", + TokenUrl = "https://api.box.com/oauth2/token", + CloudServiceName = "Box", + ClientId = BoxCredentials.ClientId, + ClientSecret = BoxCredentials.ClientSecret, + RedirectUrl = "https://getgreenshot.org/authorize/box", + AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, + RefreshToken = Config.RefreshToken, + AccessToken = Config.AccessToken, + AccessTokenExpires = Config.AccessTokenExpires + }; + + + // Copy the settings from the config, which is kept in memory and on the disk + + try + { + var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, UploadFileUri, settings); + IDictionary parameters = new Dictionary + { + { + "file", image + }, + { + "parent_id", Config.FolderId + } + }; + + NetworkHelper.WriteMultipartFormData(webRequest, parameters); + + var response = NetworkHelper.GetResponseAsString(webRequest); + + Log.DebugFormat("Box response: {0}", response); + + var upload = JsonSerializer.Deserialize(response); + if (upload?.Entries == null || upload.Entries.Count == 0) return null; + + if (Config.UseSharedLink) + { + string filesResponse = HttpPut(string.Format(FilesUri, upload.Entries[0].Id), "{\"shared_link\": {\"access\": \"open\"}}", settings); + var file = JsonSerializer.Deserialize(filesResponse); + return file.SharedLink.Url; + } + + return $"http://www.box.com/files/0/f/0/1/f_{upload.Entries[0].Id}"; + } + finally + { + // Copy the settings back to the config, so they are stored. + Config.RefreshToken = settings.RefreshToken; + Config.AccessToken = settings.AccessToken; + Config.AccessTokenExpires = settings.AccessTokenExpires; + Config.IsDirty = true; + IniConfig.Save(); + } + } + } + + /// + /// A simple helper class for the DataContractJsonSerializer + /// + internal static class JsonSerializer + { + /// + /// Helper method to parse JSON to object + /// + /// + /// + /// + public static T Deserialize(string jsonString) + { + var deserializer = new DataContractJsonSerializer(typeof(T)); using var stream = new MemoryStream(); byte[] content = Encoding.UTF8.GetBytes(jsonString); stream.Write(content, 0, content.Length); stream.Seek(0, SeekOrigin.Begin); - return (T)deserializer.ReadObject(stream); + return (T) deserializer.ReadObject(stream); } - } -} + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/Forms/BoxForm.cs b/src/Greenshot.Plugin.Box/Forms/BoxForm.cs index 5bb895823..646bdf87b 100644 --- a/src/Greenshot.Plugin.Box/Forms/BoxForm.cs +++ b/src/Greenshot.Plugin.Box/Forms/BoxForm.cs @@ -21,7 +21,9 @@ using GreenshotPlugin.Controls; -namespace Greenshot.Plugin.Box.Forms { - public class BoxForm : GreenshotForm { - } +namespace Greenshot.Plugin.Box.Forms +{ + public class BoxForm : GreenshotForm + { + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs index 1de1e7b32..588350c76 100644 --- a/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs @@ -19,18 +19,21 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.Box.Forms { - /// - /// Description of PasswordRequestForm. - /// - public partial class SettingsForm : BoxForm { - public SettingsForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - AcceptButton = buttonOK; - CancelButton = buttonCancel; - } - } -} +namespace Greenshot.Plugin.Box.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : BoxForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = buttonOK; + CancelButton = buttonCancel; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/LanguageKeys.cs b/src/Greenshot.Plugin.Box/LanguageKeys.cs index 32230ebd1..c6c64bfdf 100644 --- a/src/Greenshot.Plugin.Box/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Box/LanguageKeys.cs @@ -18,11 +18,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace Greenshot.Plugin.Box { - public enum LangKey { - upload_menu_item, - upload_failure, - communication_wait, - Configure - } -} + +namespace Greenshot.Plugin.Box +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + Configure + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs index b6b19f1c8..8af36d000 100644 --- a/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Confluence.cs b/src/Greenshot.Plugin.Confluence/Confluence.cs index 13f5d0ab3..79d11a034 100644 --- a/src/Greenshot.Plugin.Confluence/Confluence.cs +++ b/src/Greenshot.Plugin.Confluence/Confluence.cs @@ -26,283 +26,333 @@ using GreenshotConfluencePlugin.confluence; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Confluence { - public class Page { - public Page(RemotePage page) { - Id = page.id; - Title = page.title; - SpaceKey = page.space; - Url = page.url; - Content = page.content; - } - public Page(RemoteSearchResult searchResult, string space) { - Id = searchResult.id; - Title = searchResult.title; - SpaceKey = space; - Url = searchResult.url; - Content = searchResult.excerpt; - } - - public Page(RemotePageSummary pageSummary) { - Id = pageSummary.id; - Title = pageSummary.title; - SpaceKey = pageSummary.space; - Url =pageSummary.url; - } - public long Id { - get; - set; - } - public string Title { - get; - set; - } - public string Url { - get; - set; - } - public string Content { - get; - set; - } - public string SpaceKey { - get; - set; - } - } - public class Space { - public Space(RemoteSpaceSummary space) { - Key = space.key; - Name = space.name; - } - public string Key { - get; - set; - } - public string Name { - get; - set; - } - } +namespace Greenshot.Plugin.Confluence +{ + public class Page + { + public Page(RemotePage page) + { + Id = page.id; + Title = page.title; + SpaceKey = page.space; + Url = page.url; + Content = page.content; + } + + public Page(RemoteSearchResult searchResult, string space) + { + Id = searchResult.id; + Title = searchResult.title; + SpaceKey = space; + Url = searchResult.url; + Content = searchResult.excerpt; + } + + public Page(RemotePageSummary pageSummary) + { + Id = pageSummary.id; + Title = pageSummary.title; + SpaceKey = pageSummary.space; + Url = pageSummary.url; + } + + public long Id { get; set; } + public string Title { get; set; } + public string Url { get; set; } + public string Content { get; set; } + public string SpaceKey { get; set; } + } + + public class Space + { + public Space(RemoteSpaceSummary space) + { + Key = space.key; + Name = space.name; + } + + public string Key { get; set; } + public string Name { get; set; } + } /// - /// For details see the Confluence API site - /// See: http://confluence.atlassian.com/display/CONFDEV/Remote+API+Specification - /// - public class ConfluenceConnector : IDisposable { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceConnector)); - private const string AuthFailedExceptionName = "com.atlassian.confluence.rpc.AuthenticationFailedException"; - private const string V2Failed = "AXIS"; - private static readonly ConfluenceConfiguration Config = IniConfig.GetIniSection(); - private string _credentials; - private DateTime _loggedInTime = DateTime.Now; - private bool _loggedIn; - private ConfluenceSoapServiceService _confluence; - private readonly int _timeout; - private string _url; - private readonly Cache _pageCache = new Cache(60 * Config.Timeout); + /// For details see the Confluence API site + /// See: http://confluence.atlassian.com/display/CONFDEV/Remote+API+Specification + ///
+ public class ConfluenceConnector : IDisposable + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceConnector)); + private const string AuthFailedExceptionName = "com.atlassian.confluence.rpc.AuthenticationFailedException"; + private const string V2Failed = "AXIS"; + private static readonly ConfluenceConfiguration Config = IniConfig.GetIniSection(); + private string _credentials; + private DateTime _loggedInTime = DateTime.Now; + private bool _loggedIn; + private ConfluenceSoapServiceService _confluence; + private readonly int _timeout; + private string _url; + private readonly Cache _pageCache = new Cache(60 * Config.Timeout); - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected void Dispose(bool disposing) { - if (_confluence != null) { - Logout(); - } - if (disposing) { - if (_confluence != null) { - _confluence.Dispose(); - _confluence = null; - } - } - } + protected void Dispose(bool disposing) + { + if (_confluence != null) + { + Logout(); + } - public ConfluenceConnector(string url, int timeout) { - _timeout = timeout; - Init(url); - } + if (disposing) + { + if (_confluence != null) + { + _confluence.Dispose(); + _confluence = null; + } + } + } - private void Init(string url) { - _url = url; - _confluence = new ConfluenceSoapServiceService - { - Url = url, - Proxy = NetworkHelper.CreateProxy(new Uri(url)) - }; - } + public ConfluenceConnector(string url, int timeout) + { + _timeout = timeout; + Init(url); + } - ~ConfluenceConnector() { - Dispose(false); - } + private void Init(string url) + { + _url = url; + _confluence = new ConfluenceSoapServiceService + { + Url = url, + Proxy = NetworkHelper.CreateProxy(new Uri(url)) + }; + } - /// - /// Internal login which catches the exceptions - /// - /// true if login was done sucessfully - private bool DoLogin(string user, string password) { - try { - _credentials = _confluence.login(user, password); - _loggedInTime = DateTime.Now; - _loggedIn = true; - } catch (Exception e) { - // Check if confluence-v2 caused an error, use v1 instead - if (e.Message.Contains(V2Failed) && _url.Contains("v2")) { - Init(_url.Replace("v2", "v1")); - return DoLogin(user, password); - } - // check if auth failed - if (e.Message.Contains(AuthFailedExceptionName)) { - return false; - } - // Not an authentication issue - _loggedIn = false; - _credentials = null; - e.Data.Add("user", user); - e.Data.Add("url", _url); - throw; - } - return true; - } + ~ConfluenceConnector() + { + Dispose(false); + } - public void Login() { - Logout(); - try { - // Get the system name, so the user knows where to login to - string systemName = _url.Replace(ConfluenceConfiguration.DEFAULT_POSTFIX1,""); - systemName = systemName.Replace(ConfluenceConfiguration.DEFAULT_POSTFIX2, ""); - CredentialsDialog dialog = new CredentialsDialog(systemName) - { - Name = null - }; - while (dialog.Show(dialog.Name) == DialogResult.OK) { - if (DoLogin(dialog.Name, dialog.Password)) { - if (dialog.SaveChecked) { - dialog.Confirm(true); - } - return; - } else { - try { - dialog.Confirm(false); - } catch (ApplicationException e) { - // exception handling ... - Log.Error("Problem using the credentials dialog", e); - } - // For every windows version after XP show an incorrect password baloon - dialog.IncorrectPassword = true; - // Make sure the dialog is display, the password was false! - dialog.AlwaysDisplay = true; - } - } - } catch (ApplicationException e) { - // exception handling ... - Log.Error("Problem using the credentials dialog", e); - } - } + /// + /// Internal login which catches the exceptions + /// + /// true if login was done sucessfully + private bool DoLogin(string user, string password) + { + try + { + _credentials = _confluence.login(user, password); + _loggedInTime = DateTime.Now; + _loggedIn = true; + } + catch (Exception e) + { + // Check if confluence-v2 caused an error, use v1 instead + if (e.Message.Contains(V2Failed) && _url.Contains("v2")) + { + Init(_url.Replace("v2", "v1")); + return DoLogin(user, password); + } - public void Logout() { - if (_credentials != null) { - _confluence.logout(_credentials); - _credentials = null; - _loggedIn = false; - } - } + // check if auth failed + if (e.Message.Contains(AuthFailedExceptionName)) + { + return false; + } - private void CheckCredentials() { - if (_loggedIn) { - if (_loggedInTime.AddMinutes(_timeout-1).CompareTo(DateTime.Now) < 0) { - Logout(); - Login(); - } - } else { - Login(); - } - } + // Not an authentication issue + _loggedIn = false; + _credentials = null; + e.Data.Add("user", user); + e.Data.Add("url", _url); + throw; + } - public bool IsLoggedIn => _loggedIn; + return true; + } - public void AddAttachment(long pageId, string mime, string comment, string filename, IBinaryContainer image) { - CheckCredentials(); - // Comment is ignored, see: http://jira.atlassian.com/browse/CONF-9395 - var attachment = new RemoteAttachment - { - comment = comment, - fileName = filename, - contentType = mime - }; - _confluence.addAttachment(_credentials, pageId, attachment, image.ToByteArray()); - } - - public Page GetPage(string spaceKey, string pageTitle) { - RemotePage page = null; - string cacheKey = spaceKey + pageTitle; - if (_pageCache.Contains(cacheKey)) { - page = _pageCache[cacheKey]; - } - if (page == null) { - CheckCredentials(); - page = _confluence.getPage(_credentials, spaceKey, pageTitle); - _pageCache.Add(cacheKey, page); - } - return new Page(page); - } + public void Login() + { + Logout(); + try + { + // Get the system name, so the user knows where to login to + string systemName = _url.Replace(ConfluenceConfiguration.DEFAULT_POSTFIX1, ""); + systemName = systemName.Replace(ConfluenceConfiguration.DEFAULT_POSTFIX2, ""); + CredentialsDialog dialog = new CredentialsDialog(systemName) + { + Name = null + }; + while (dialog.Show(dialog.Name) == DialogResult.OK) + { + if (DoLogin(dialog.Name, dialog.Password)) + { + if (dialog.SaveChecked) + { + dialog.Confirm(true); + } - public Page GetPage(long pageId) { - RemotePage page = null; - string cacheKey = pageId.ToString(); - - if (_pageCache.Contains(cacheKey)) { - page = _pageCache[cacheKey]; - } - if (page == null) { - CheckCredentials(); - page = _confluence.getPage(_credentials, pageId); - _pageCache.Add(cacheKey, page); - } - return new Page(page); - } + return; + } + else + { + try + { + dialog.Confirm(false); + } + catch (ApplicationException e) + { + // exception handling ... + Log.Error("Problem using the credentials dialog", e); + } - public Page GetSpaceHomepage(Space spaceSummary) { - CheckCredentials(); - RemoteSpace spaceDetail = _confluence.getSpace(_credentials, spaceSummary.Key); - RemotePage page = _confluence.getPage(_credentials, spaceDetail.homePage); - return new Page(page); - } + // For every windows version after XP show an incorrect password baloon + dialog.IncorrectPassword = true; + // Make sure the dialog is display, the password was false! + dialog.AlwaysDisplay = true; + } + } + } + catch (ApplicationException e) + { + // exception handling ... + Log.Error("Problem using the credentials dialog", e); + } + } - public IEnumerable GetSpaceSummaries() { - CheckCredentials(); - RemoteSpaceSummary [] spaces = _confluence.getSpaces(_credentials); - foreach(RemoteSpaceSummary space in spaces) { - yield return new Space(space); - } - } - - public IEnumerable GetPageChildren(Page parentPage) { - CheckCredentials(); - RemotePageSummary[] pages = _confluence.getChildren(_credentials, parentPage.Id); - foreach(RemotePageSummary page in pages) { - yield return new Page(page); - } - } + public void Logout() + { + if (_credentials != null) + { + _confluence.logout(_credentials); + _credentials = null; + _loggedIn = false; + } + } - public IEnumerable GetPageSummaries(Space space) { - CheckCredentials(); - RemotePageSummary[] pages = _confluence.getPages(_credentials, space.Key); - foreach(RemotePageSummary page in pages) { - yield return new Page(page); - } - } - - public IEnumerable SearchPages(string query, string space) { - CheckCredentials(); - foreach(var searchResult in _confluence.search(_credentials, query, 20)) { - Log.DebugFormat("Got result of type {0}", searchResult.type); - if ("page".Equals(searchResult.type)) - { - yield return new Page(searchResult, space); - } - } - } - } -} + private void CheckCredentials() + { + if (_loggedIn) + { + if (_loggedInTime.AddMinutes(_timeout - 1).CompareTo(DateTime.Now) < 0) + { + Logout(); + Login(); + } + } + else + { + Login(); + } + } + + public bool IsLoggedIn => _loggedIn; + + public void AddAttachment(long pageId, string mime, string comment, string filename, IBinaryContainer image) + { + CheckCredentials(); + // Comment is ignored, see: http://jira.atlassian.com/browse/CONF-9395 + var attachment = new RemoteAttachment + { + comment = comment, + fileName = filename, + contentType = mime + }; + _confluence.addAttachment(_credentials, pageId, attachment, image.ToByteArray()); + } + + public Page GetPage(string spaceKey, string pageTitle) + { + RemotePage page = null; + string cacheKey = spaceKey + pageTitle; + if (_pageCache.Contains(cacheKey)) + { + page = _pageCache[cacheKey]; + } + + if (page == null) + { + CheckCredentials(); + page = _confluence.getPage(_credentials, spaceKey, pageTitle); + _pageCache.Add(cacheKey, page); + } + + return new Page(page); + } + + public Page GetPage(long pageId) + { + RemotePage page = null; + string cacheKey = pageId.ToString(); + + if (_pageCache.Contains(cacheKey)) + { + page = _pageCache[cacheKey]; + } + + if (page == null) + { + CheckCredentials(); + page = _confluence.getPage(_credentials, pageId); + _pageCache.Add(cacheKey, page); + } + + return new Page(page); + } + + public Page GetSpaceHomepage(Space spaceSummary) + { + CheckCredentials(); + RemoteSpace spaceDetail = _confluence.getSpace(_credentials, spaceSummary.Key); + RemotePage page = _confluence.getPage(_credentials, spaceDetail.homePage); + return new Page(page); + } + + public IEnumerable GetSpaceSummaries() + { + CheckCredentials(); + RemoteSpaceSummary[] spaces = _confluence.getSpaces(_credentials); + foreach (RemoteSpaceSummary space in spaces) + { + yield return new Space(space); + } + } + + public IEnumerable GetPageChildren(Page parentPage) + { + CheckCredentials(); + RemotePageSummary[] pages = _confluence.getChildren(_credentials, parentPage.Id); + foreach (RemotePageSummary page in pages) + { + yield return new Page(page); + } + } + + public IEnumerable GetPageSummaries(Space space) + { + CheckCredentials(); + RemotePageSummary[] pages = _confluence.getPages(_credentials, space.Key); + foreach (RemotePageSummary page in pages) + { + yield return new Page(page); + } + } + + public IEnumerable SearchPages(string query, string space) + { + CheckCredentials(); + foreach (var searchResult in _confluence.search(_credentials, query, 20)) + { + Log.DebugFormat("Got result of type {0}", searchResult.type); + if ("page".Equals(searchResult.type)) + { + yield return new Page(searchResult, space); + } + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs index a742fc45b..df23e7768 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs @@ -23,63 +23,45 @@ using System; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Confluence { - /// - /// Description of ConfluenceConfiguration. - /// - [Serializable] - [IniSection("Confluence", Description="Greenshot Confluence Plugin configuration")] - public class ConfluenceConfiguration : IniSection { - public const string DEFAULT_POSTFIX1 = "/rpc/soap-axis/confluenceservice-v1?wsdl"; - public const string DEFAULT_POSTFIX2 = "/rpc/soap-axis/confluenceservice-v2?wsdl"; - public const string DEFAULT_PREFIX = "http://"; - private const string DEFAULT_URL = DEFAULT_PREFIX + "confluence"; +namespace Greenshot.Plugin.Confluence +{ + /// + /// Description of ConfluenceConfiguration. + /// + [Serializable] + [IniSection("Confluence", Description = "Greenshot Confluence Plugin configuration")] + public class ConfluenceConfiguration : IniSection + { + public const string DEFAULT_POSTFIX1 = "/rpc/soap-axis/confluenceservice-v1?wsdl"; + public const string DEFAULT_POSTFIX2 = "/rpc/soap-axis/confluenceservice-v2?wsdl"; + public const string DEFAULT_PREFIX = "http://"; + private const string DEFAULT_URL = DEFAULT_PREFIX + "confluence"; - [IniProperty("Url", Description="Url to Confluence system, including wsdl.", DefaultValue=DEFAULT_URL)] - public string Url { - get; - set; - } - [IniProperty("Timeout", Description="Session timeout in minutes", DefaultValue="30")] - public int Timeout { - get; - set; - } + [IniProperty("Url", Description = "Url to Confluence system, including wsdl.", DefaultValue = DEFAULT_URL)] + public string Url { get; set; } - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat { - get; - set; - } - [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality { - get; - set; - } - [IniProperty("UploadReduceColors", Description="Reduce color amount of the uploaded image to 256", DefaultValue="False")] - public bool UploadReduceColors { - get; - set; - } - [IniProperty("OpenPageAfterUpload", Description="Open the page where the picture is uploaded after upload", DefaultValue="True")] - public bool OpenPageAfterUpload { - get; - set; - } - [IniProperty("CopyWikiMarkupForImageToClipboard", Description="Copy the Wikimarkup for the recently uploaded image to the Clipboard", DefaultValue="True")] - public bool CopyWikiMarkupForImageToClipboard { - get; - set; - } - [IniProperty("SearchSpaceKey", Description="Key of last space that was searched for")] - public string SearchSpaceKey { - get; - set; - } - [IniProperty("IncludePersonSpaces", Description = "Include personal spaces in the search & browse spaces list", DefaultValue = "False")] - public bool IncludePersonSpaces { - get; - set; - } - } -} + [IniProperty("Timeout", Description = "Session timeout in minutes", DefaultValue = "30")] + public int Timeout { get; set; } + + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] + public bool UploadReduceColors { get; set; } + + [IniProperty("OpenPageAfterUpload", Description = "Open the page where the picture is uploaded after upload", DefaultValue = "True")] + public bool OpenPageAfterUpload { get; set; } + + [IniProperty("CopyWikiMarkupForImageToClipboard", Description = "Copy the Wikimarkup for the recently uploaded image to the Clipboard", DefaultValue = "True")] + public bool CopyWikiMarkupForImageToClipboard { get; set; } + + [IniProperty("SearchSpaceKey", Description = "Key of last space that was searched for")] + public string SearchSpaceKey { get; set; } + + [IniProperty("IncludePersonSpaces", Description = "Include personal spaces in the search & browse spaces list", DefaultValue = "False")] + public bool IncludePersonSpaces { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs index d2661d141..275ace4d1 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs @@ -32,174 +32,221 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Confluence { - /// - /// Description of ConfluenceDestination. - /// - public class ConfluenceDestination : AbstractDestination { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceDestination)); - private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection(); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static readonly Image ConfluenceIcon; - private readonly Page _page; +namespace Greenshot.Plugin.Confluence +{ + /// + /// Description of ConfluenceDestination. + /// + public class ConfluenceDestination : AbstractDestination + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceDestination)); + private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection(); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static readonly Image ConfluenceIcon; + private readonly Page _page; - static ConfluenceDestination() { - IsInitialized = false; - try { - Uri confluenceIconUri = new Uri("/GreenshotConfluencePlugin;component/Images/Confluence.ico", UriKind.Relative); - using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream) - { - // TODO: Check what to do with the IImage - ConfluenceIcon = ImageHelper.FromStream(iconStream); - } - IsInitialized = true; - } catch (Exception ex) { - Log.ErrorFormat("Problem in the confluence static initializer: {0}", ex.Message); - } - } - - public static bool IsInitialized + static ConfluenceDestination() { - get; - private set; + IsInitialized = false; + try + { + Uri confluenceIconUri = new Uri("/GreenshotConfluencePlugin;component/Images/Confluence.ico", UriKind.Relative); + using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream) + { + // TODO: Check what to do with the IImage + ConfluenceIcon = ImageHelper.FromStream(iconStream); + } + + IsInitialized = true; + } + catch (Exception ex) + { + Log.ErrorFormat("Problem in the confluence static initializer: {0}", ex.Message); + } } - public ConfluenceDestination() { - } + public static bool IsInitialized { get; private set; } - public ConfluenceDestination(Page page) { - _page = page; - } - - public override string Designation { - get { - return "Confluence"; - } - } + public ConfluenceDestination() + { + } - public override string Description { - get { - if (_page == null) { - return Language.GetString("confluence", LangKey.upload_menu_item); - } else { - return Language.GetString("confluence", LangKey.upload_menu_item) + ": \"" + _page.Title + "\""; - } - } - } + public ConfluenceDestination(Page page) + { + _page = page; + } - public override bool IsDynamic { - get { - return true; - } - } - - public override bool IsActive { - get { - return base.IsActive && !string.IsNullOrEmpty(ConfluenceConfig.Url); - } - } + public override string Designation + { + get { return "Confluence"; } + } - public override Image DisplayIcon { - get { - return ConfluenceIcon; - } - } - - public override IEnumerable DynamicDestinations() { - if (ConfluencePlugin.ConfluenceConnectorNoLogin == null || !ConfluencePlugin.ConfluenceConnectorNoLogin.IsLoggedIn) { - yield break; - } - List currentPages = ConfluenceUtils.GetCurrentPages(); - if (currentPages == null || currentPages.Count == 0) { - yield break; - } - foreach(Page currentPage in currentPages) { - yield return new ConfluenceDestination(currentPage); - } - } + public override string Description + { + get + { + if (_page == null) + { + return Language.GetString("confluence", LangKey.upload_menu_item); + } + else + { + return Language.GetString("confluence", LangKey.upload_menu_item) + ": \"" + _page.Title + "\""; + } + } + } - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - // force password check to take place before the pages load - if (!ConfluencePlugin.ConfluenceConnector.IsLoggedIn) { - return exportInformation; - } + public override bool IsDynamic + { + get { return true; } + } - Page selectedPage = _page; - bool openPage = (_page == null) && ConfluenceConfig.OpenPageAfterUpload; - string filename = FilenameHelper.GetFilenameWithoutExtensionFromPattern(CoreConfig.OutputFileFilenamePattern, captureDetails); - if (selectedPage == null) { - Forms.ConfluenceUpload confluenceUpload = new Forms.ConfluenceUpload(filename); - bool? dialogResult = confluenceUpload.ShowDialog(); - if (dialogResult.HasValue && dialogResult.Value) { - selectedPage = confluenceUpload.SelectedPage; - if (confluenceUpload.IsOpenPageSelected) { - openPage = false; - } - filename = confluenceUpload.Filename; - } - } - string extension = "." + ConfluenceConfig.UploadFormat; - if (!filename.ToLower().EndsWith(extension)) { - filename += extension; - } - if (selectedPage != null) { + public override bool IsActive + { + get { return base.IsActive && !string.IsNullOrEmpty(ConfluenceConfig.Url); } + } + + public override Image DisplayIcon + { + get { return ConfluenceIcon; } + } + + public override IEnumerable DynamicDestinations() + { + if (ConfluencePlugin.ConfluenceConnectorNoLogin == null || !ConfluencePlugin.ConfluenceConnectorNoLogin.IsLoggedIn) + { + yield break; + } + + List currentPages = ConfluenceUtils.GetCurrentPages(); + if (currentPages == null || currentPages.Count == 0) + { + yield break; + } + + foreach (Page currentPage in currentPages) + { + yield return new ConfluenceDestination(currentPage); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + // force password check to take place before the pages load + if (!ConfluencePlugin.ConfluenceConnector.IsLoggedIn) + { + return exportInformation; + } + + Page selectedPage = _page; + bool openPage = (_page == null) && ConfluenceConfig.OpenPageAfterUpload; + string filename = FilenameHelper.GetFilenameWithoutExtensionFromPattern(CoreConfig.OutputFileFilenamePattern, captureDetails); + if (selectedPage == null) + { + Forms.ConfluenceUpload confluenceUpload = new Forms.ConfluenceUpload(filename); + bool? dialogResult = confluenceUpload.ShowDialog(); + if (dialogResult.HasValue && dialogResult.Value) + { + selectedPage = confluenceUpload.SelectedPage; + if (confluenceUpload.IsOpenPageSelected) + { + openPage = false; + } + + filename = confluenceUpload.Filename; + } + } + + string extension = "." + ConfluenceConfig.UploadFormat; + if (!filename.ToLower().EndsWith(extension)) + { + filename += extension; + } + + if (selectedPage != null) + { bool uploaded = Upload(surface, selectedPage, filename, out var errorMessage); - if (uploaded) { - if (openPage) { - try - { - Process.Start(selectedPage.Url); - } - catch - { - // Ignore - } - } - exportInformation.ExportMade = true; - exportInformation.Uri = selectedPage.Url; - } else { - exportInformation.ErrorMessage = errorMessage; - } - } - ProcessExport(exportInformation, surface); - return exportInformation; - } + if (uploaded) + { + if (openPage) + { + try + { + Process.Start(selectedPage.Url); + } + catch + { + // Ignore + } + } - private bool Upload(ISurface surfaceToUpload, Page page, string filename, out string errorMessage) { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(ConfluenceConfig.UploadFormat, ConfluenceConfig.UploadJpegQuality, ConfluenceConfig.UploadReduceColors); - errorMessage = null; - try { - new PleaseWaitForm().ShowAndWait(Description, Language.GetString("confluence", LangKey.communication_wait), - delegate { - ConfluencePlugin.ConfluenceConnector.AddAttachment(page.Id, "image/" + ConfluenceConfig.UploadFormat.ToString().ToLower(), null, filename, new SurfaceContainer(surfaceToUpload, outputSettings, filename)); - } - ); - Log.Debug("Uploaded to Confluence."); - if (!ConfluenceConfig.CopyWikiMarkupForImageToClipboard) - { - return true; - } - int retryCount = 2; - while (retryCount >= 0) { - try { - Clipboard.SetText("!" + filename + "!"); - break; - } catch (Exception ee) { - if (retryCount == 0) { - Log.Error(ee); - } else { - Thread.Sleep(100); - } - } finally { - --retryCount; - } - } - return true; - } catch(Exception e) { - errorMessage = e.Message; - } - return false; - } - } -} + exportInformation.ExportMade = true; + exportInformation.Uri = selectedPage.Url; + } + else + { + exportInformation.ErrorMessage = errorMessage; + } + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + + private bool Upload(ISurface surfaceToUpload, Page page, string filename, out string errorMessage) + { + SurfaceOutputSettings outputSettings = + new SurfaceOutputSettings(ConfluenceConfig.UploadFormat, ConfluenceConfig.UploadJpegQuality, ConfluenceConfig.UploadReduceColors); + errorMessage = null; + try + { + new PleaseWaitForm().ShowAndWait(Description, Language.GetString("confluence", LangKey.communication_wait), + delegate + { + ConfluencePlugin.ConfluenceConnector.AddAttachment(page.Id, "image/" + ConfluenceConfig.UploadFormat.ToString().ToLower(), null, filename, + new SurfaceContainer(surfaceToUpload, outputSettings, filename)); + } + ); + Log.Debug("Uploaded to Confluence."); + if (!ConfluenceConfig.CopyWikiMarkupForImageToClipboard) + { + return true; + } + + int retryCount = 2; + while (retryCount >= 0) + { + try + { + Clipboard.SetText("!" + filename + "!"); + break; + } + catch (Exception ee) + { + if (retryCount == 0) + { + Log.Error(ee); + } + else + { + Thread.Sleep(100); + } + } + finally + { + --retryCount; + } + } + + return true; + } + catch (Exception e) + { + errorMessage = e.Message; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs index 4cca23c8f..fbe852691 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs @@ -28,109 +28,142 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Confluence { - /// - /// This is the ConfluencePlugin base code - /// - [Plugin("Confluence", true)] - public class ConfluencePlugin : IGreenshotPlugin { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluencePlugin)); - private static ConfluenceConnector _confluenceConnector; - private static ConfluenceConfiguration _config; +namespace Greenshot.Plugin.Confluence +{ + /// + /// This is the ConfluencePlugin base code + /// + [Plugin("Confluence", true)] + public class ConfluencePlugin : IGreenshotPlugin + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluencePlugin)); + private static ConfluenceConnector _confluenceConnector; + private static ConfluenceConfiguration _config; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected void Dispose(bool disposing) { - //if (disposing) {} - } + protected void Dispose(bool disposing) + { + //if (disposing) {} + } - private static void CreateConfluenceConnector() { - if (_confluenceConnector == null) { - if (_config.Url.Contains("soap-axis")) { - _confluenceConnector = new ConfluenceConnector(_config.Url, _config.Timeout); - } else { - _confluenceConnector = new ConfluenceConnector(_config.Url + ConfluenceConfiguration.DEFAULT_POSTFIX2, _config.Timeout); - } - } - } + private static void CreateConfluenceConnector() + { + if (_confluenceConnector == null) + { + if (_config.Url.Contains("soap-axis")) + { + _confluenceConnector = new ConfluenceConnector(_config.Url, _config.Timeout); + } + else + { + _confluenceConnector = new ConfluenceConnector(_config.Url + ConfluenceConfiguration.DEFAULT_POSTFIX2, _config.Timeout); + } + } + } - public static ConfluenceConnector ConfluenceConnectorNoLogin { - get { - return _confluenceConnector; - } - } + public static ConfluenceConnector ConfluenceConnectorNoLogin + { + get { return _confluenceConnector; } + } - public static ConfluenceConnector ConfluenceConnector { - get { - if (_confluenceConnector == null) { - CreateConfluenceConnector(); - } - try { - if (_confluenceConnector != null && !_confluenceConnector.IsLoggedIn) { - _confluenceConnector.Login(); - } - } catch (Exception e) { - MessageBox.Show(Language.GetFormattedString("confluence", LangKey.login_error, e.Message)); - } - return _confluenceConnector; - } - } + public static ConfluenceConnector ConfluenceConnector + { + get + { + if (_confluenceConnector == null) + { + CreateConfluenceConnector(); + } + + try + { + if (_confluenceConnector != null && !_confluenceConnector.IsLoggedIn) + { + _confluenceConnector.Login(); + } + } + catch (Exception e) + { + MessageBox.Show(Language.GetFormattedString("confluence", LangKey.login_error, e.Message)); + } + + return _confluenceConnector; + } + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + public bool Initialize() + { + // Register configuration (don't need the configuration itself) + _config = IniConfig.GetIniSection(); + if (_config.IsDirty) + { + IniConfig.Save(); + } + + try + { + TranslationManager.Instance.TranslationProvider = new LanguageXMLTranslationProvider(); + //resources = new ComponentResourceManager(typeof(ConfluencePlugin)); + } + catch (Exception ex) + { + LOG.ErrorFormat("Problem in ConfluencePlugin.Initialize: {0}", ex.Message); + return false; + } - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - public bool Initialize() { - // Register configuration (don't need the configuration itself) - _config = IniConfig.GetIniSection(); - if(_config.IsDirty) { - IniConfig.Save(); - } - try { - TranslationManager.Instance.TranslationProvider = new LanguageXMLTranslationProvider(); - //resources = new ComponentResourceManager(typeof(ConfluencePlugin)); - } catch (Exception ex) { - LOG.ErrorFormat("Problem in ConfluencePlugin.Initialize: {0}", ex.Message); - return false; - } if (ConfluenceDestination.IsInitialized) { SimpleServiceProvider.Current.AddService(new ConfluenceDestination()); } - return true; - } - public void Shutdown() { - LOG.Debug("Confluence Plugin shutdown."); - if (_confluenceConnector != null) { - _confluenceConnector.Logout(); - _confluenceConnector = null; - } - } + return true; + } - /// - /// Implementation of the IPlugin.Configure - /// - public void Configure() { - ConfluenceConfiguration clonedConfig = _config.Clone(); - ConfluenceConfigurationForm configForm = new ConfluenceConfigurationForm(clonedConfig); - string url = _config.Url; - bool? dialogResult = configForm.ShowDialog(); - if (dialogResult.HasValue && dialogResult.Value) { - // copy the new object to the old... - clonedConfig.CloneTo(_config); - IniConfig.Save(); - if (_confluenceConnector != null) { - if (!url.Equals(_config.Url)) { - if (_confluenceConnector.IsLoggedIn) { - _confluenceConnector.Logout(); - } - _confluenceConnector = null; - } - } - } - } - } -} + public void Shutdown() + { + LOG.Debug("Confluence Plugin shutdown."); + if (_confluenceConnector != null) + { + _confluenceConnector.Logout(); + _confluenceConnector = null; + } + } + + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + ConfluenceConfiguration clonedConfig = _config.Clone(); + ConfluenceConfigurationForm configForm = new ConfluenceConfigurationForm(clonedConfig); + string url = _config.Url; + bool? dialogResult = configForm.ShowDialog(); + if (dialogResult.HasValue && dialogResult.Value) + { + // copy the new object to the old... + clonedConfig.CloneTo(_config); + IniConfig.Save(); + if (_confluenceConnector != null) + { + if (!url.Equals(_config.Url)) + { + if (_confluenceConnector.IsLoggedIn) + { + _confluenceConnector.Logout(); + } + + _confluenceConnector = null; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs b/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs index 55a40fa8c..2c878d6d9 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs @@ -26,126 +26,172 @@ using System.Text.RegularExpressions; using System.Windows.Automation; using GreenshotPlugin.Core; -namespace Greenshot.Plugin.Confluence { - /// - /// Description of ConfluenceUtils. - /// - public class ConfluenceUtils { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluenceUtils)); +namespace Greenshot.Plugin.Confluence +{ + /// + /// Description of ConfluenceUtils. + /// + public class ConfluenceUtils + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluenceUtils)); - public static List GetCurrentPages() { - List pages = new List(); - Regex pageIdRegex = new Regex(@"pageId=(\d+)"); - Regex spacePageRegex = new Regex(@"\/display\/([^\/]+)\/([^#]+)"); - foreach(string browserurl in GetBrowserUrls()) { - string url; - try { - url = Uri.UnescapeDataString(browserurl).Replace("+", " "); - } catch { - LOG.WarnFormat("Error processing URL: {0}", browserurl); - continue; - } - MatchCollection pageIdMatch = pageIdRegex.Matches(url); - if (pageIdMatch != null && pageIdMatch.Count > 0) { - long pageId = long.Parse(pageIdMatch[0].Groups[1].Value); - try { - bool pageDouble = false; - foreach(Page page in pages) { - if (page.Id == pageId) { - pageDouble = true; - LOG.DebugFormat("Skipping double page with ID {0}", pageId); - break; - } - } - if (!pageDouble) { - Page page = ConfluencePlugin.ConfluenceConnector.GetPage(pageId); - LOG.DebugFormat("Adding page {0}", page.Title); - pages.Add(page); - } - continue; - } catch (Exception ex) { - // Preventing security problems - LOG.DebugFormat("Couldn't get page details for PageID {0}", pageId); - LOG.Warn(ex); - } - } - MatchCollection spacePageMatch = spacePageRegex.Matches(url); - if (spacePageMatch != null && spacePageMatch.Count > 0) { - if (spacePageMatch[0].Groups.Count >= 2) { - string space = spacePageMatch[0].Groups[1].Value; - string title = spacePageMatch[0].Groups[2].Value; - if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(space)) { - continue; - } - if (title.EndsWith("#")) { - title = title.Substring(0, title.Length-1); - } - try { - bool pageDouble = false; - foreach(Page page in pages) { - if (page.Title.Equals(title)) { - LOG.DebugFormat("Skipping double page with title {0}", title); - pageDouble = true; - break; - } - } - if (!pageDouble) { - Page page = ConfluencePlugin.ConfluenceConnector.GetPage(space, title); - LOG.DebugFormat("Adding page {0}", page.Title); - pages.Add(page); - - } - } catch (Exception ex) { - // Preventing security problems - LOG.DebugFormat("Couldn't get page details for space {0} / title {1}", space, title); - LOG.Warn(ex); - } - } - } - } - return pages; - } + public static List GetCurrentPages() + { + List pages = new List(); + Regex pageIdRegex = new Regex(@"pageId=(\d+)"); + Regex spacePageRegex = new Regex(@"\/display\/([^\/]+)\/([^#]+)"); + foreach (string browserurl in GetBrowserUrls()) + { + string url; + try + { + url = Uri.UnescapeDataString(browserurl).Replace("+", " "); + } + catch + { + LOG.WarnFormat("Error processing URL: {0}", browserurl); + continue; + } - private static IEnumerable GetBrowserUrls() { - HashSet urls = new HashSet(); + MatchCollection pageIdMatch = pageIdRegex.Matches(url); + if (pageIdMatch != null && pageIdMatch.Count > 0) + { + long pageId = long.Parse(pageIdMatch[0].Groups[1].Value); + try + { + bool pageDouble = false; + foreach (Page page in pages) + { + if (page.Id == pageId) + { + pageDouble = true; + LOG.DebugFormat("Skipping double page with ID {0}", pageId); + break; + } + } - // FireFox - foreach (WindowDetails window in WindowDetails.GetAllWindows("MozillaWindowClass")) { - if (window.Text.Length == 0) { - continue; - } - AutomationElement currentElement = AutomationElement.FromHandle(window.Handle); - Condition conditionCustom = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom), new PropertyCondition(AutomationElement.IsOffscreenProperty, false)); - for (int i = 5; i > 0 && currentElement != null; i--) { - currentElement = currentElement.FindFirst(TreeScope.Children, conditionCustom); - } - if (currentElement == null) { - continue; - } + if (!pageDouble) + { + Page page = ConfluencePlugin.ConfluenceConnector.GetPage(pageId); + LOG.DebugFormat("Adding page {0}", page.Title); + pages.Add(page); + } - Condition conditionDocument = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document), new PropertyCondition(AutomationElement.IsOffscreenProperty, false)); - AutomationElement docElement = currentElement.FindFirst(TreeScope.Children, conditionDocument); - if (docElement == null) { - continue; - } - foreach (AutomationPattern pattern in docElement.GetSupportedPatterns()) { - if (pattern.ProgrammaticName != "ValuePatternIdentifiers.Pattern") { - continue; - } - string url = (docElement.GetCurrentPattern(pattern) as ValuePattern).Current.Value; - if (!string.IsNullOrEmpty(url)) { - urls.Add(url); - break; - } - } - } + continue; + } + catch (Exception ex) + { + // Preventing security problems + LOG.DebugFormat("Couldn't get page details for PageID {0}", pageId); + LOG.Warn(ex); + } + } - foreach(string url in IEHelper.GetIEUrls().Distinct()) { - urls.Add(url); - } + MatchCollection spacePageMatch = spacePageRegex.Matches(url); + if (spacePageMatch != null && spacePageMatch.Count > 0) + { + if (spacePageMatch[0].Groups.Count >= 2) + { + string space = spacePageMatch[0].Groups[1].Value; + string title = spacePageMatch[0].Groups[2].Value; + if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(space)) + { + continue; + } - return urls; - } + if (title.EndsWith("#")) + { + title = title.Substring(0, title.Length - 1); + } - } -} + try + { + bool pageDouble = false; + foreach (Page page in pages) + { + if (page.Title.Equals(title)) + { + LOG.DebugFormat("Skipping double page with title {0}", title); + pageDouble = true; + break; + } + } + + if (!pageDouble) + { + Page page = ConfluencePlugin.ConfluenceConnector.GetPage(space, title); + LOG.DebugFormat("Adding page {0}", page.Title); + pages.Add(page); + } + } + catch (Exception ex) + { + // Preventing security problems + LOG.DebugFormat("Couldn't get page details for space {0} / title {1}", space, title); + LOG.Warn(ex); + } + } + } + } + + return pages; + } + + private static IEnumerable GetBrowserUrls() + { + HashSet urls = new HashSet(); + + // FireFox + foreach (WindowDetails window in WindowDetails.GetAllWindows("MozillaWindowClass")) + { + if (window.Text.Length == 0) + { + continue; + } + + AutomationElement currentElement = AutomationElement.FromHandle(window.Handle); + Condition conditionCustom = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom), + new PropertyCondition(AutomationElement.IsOffscreenProperty, false)); + for (int i = 5; i > 0 && currentElement != null; i--) + { + currentElement = currentElement.FindFirst(TreeScope.Children, conditionCustom); + } + + if (currentElement == null) + { + continue; + } + + Condition conditionDocument = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document), + new PropertyCondition(AutomationElement.IsOffscreenProperty, false)); + AutomationElement docElement = currentElement.FindFirst(TreeScope.Children, conditionDocument); + if (docElement == null) + { + continue; + } + + foreach (AutomationPattern pattern in docElement.GetSupportedPatterns()) + { + if (pattern.ProgrammaticName != "ValuePatternIdentifiers.Pattern") + { + continue; + } + + string url = (docElement.GetCurrentPattern(pattern) as ValuePattern).Current.Value; + if (!string.IsNullOrEmpty(url)) + { + urls.Add(url); + break; + } + } + } + + foreach (string url in IEHelper.GetIEUrls().Distinct()) + { + urls.Add(url); + } + + return urls; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs b/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs index 185593c87..c4023a828 100644 --- a/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs +++ b/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs @@ -28,70 +28,87 @@ using System.Reflection; using System.Windows.Data; using GreenshotPlugin.Core; -namespace Greenshot.Plugin.Confluence { - public class EnumDisplayer : IValueConverter { - private Type _type; - private IDictionary _displayValues; - private IDictionary _reverseValues; +namespace Greenshot.Plugin.Confluence +{ + public class EnumDisplayer : IValueConverter + { + private Type _type; + private IDictionary _displayValues; + private IDictionary _reverseValues; - public Type Type { - get { return _type; } - set { - if (!value.IsEnum) { - throw new ArgumentException("parameter is not an Enumerated type", nameof(value)); - } - _type = value; - } - } - - public ReadOnlyCollection DisplayNames { - get { - var genericTypeDefinition = typeof(Dictionary<,>).GetGenericTypeDefinition(); - if (genericTypeDefinition != null) - { - _reverseValues = (IDictionary) Activator.CreateInstance(genericTypeDefinition.MakeGenericType(typeof(string),_type)); - } + public Type Type + { + get { return _type; } + set + { + if (!value.IsEnum) + { + throw new ArgumentException("parameter is not an Enumerated type", nameof(value)); + } - var typeDefinition = typeof(Dictionary<,>).GetGenericTypeDefinition(); - if (typeDefinition != null) - { - _displayValues = (IDictionary)Activator.CreateInstance(typeDefinition.MakeGenericType(_type, typeof(string))); - } + _type = value; + } + } - var fields = _type.GetFields(BindingFlags.Public | BindingFlags.Static); - foreach (var field in fields) { - DisplayKeyAttribute[] a = (DisplayKeyAttribute[])field.GetCustomAttributes(typeof(DisplayKeyAttribute), false); - - string displayKey = GetDisplayKeyValue(a); - object enumValue = field.GetValue(null); - - string displayString; - if (displayKey != null && Language.HasKey(displayKey)) { - displayString = Language.GetString(displayKey); - } - displayString = displayKey ?? enumValue.ToString(); + public ReadOnlyCollection DisplayNames + { + get + { + var genericTypeDefinition = typeof(Dictionary<,>).GetGenericTypeDefinition(); + if (genericTypeDefinition != null) + { + _reverseValues = (IDictionary) Activator.CreateInstance(genericTypeDefinition.MakeGenericType(typeof(string), _type)); + } - _displayValues.Add(enumValue, displayString); - _reverseValues.Add(displayString, enumValue); - } - return new List((IEnumerable)_displayValues.Values).AsReadOnly(); - } - } - - private static string GetDisplayKeyValue(DisplayKeyAttribute[] a) { - if (a == null || a.Length == 0) { - return null; - } - DisplayKeyAttribute dka = a[0]; - return dka.Value; - } - - object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return _displayValues[value]; - } - - object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - return _reverseValues[value]; - } - } -} + var typeDefinition = typeof(Dictionary<,>).GetGenericTypeDefinition(); + if (typeDefinition != null) + { + _displayValues = (IDictionary) Activator.CreateInstance(typeDefinition.MakeGenericType(_type, typeof(string))); + } + + var fields = _type.GetFields(BindingFlags.Public | BindingFlags.Static); + foreach (var field in fields) + { + DisplayKeyAttribute[] a = (DisplayKeyAttribute[]) field.GetCustomAttributes(typeof(DisplayKeyAttribute), false); + + string displayKey = GetDisplayKeyValue(a); + object enumValue = field.GetValue(null); + + string displayString; + if (displayKey != null && Language.HasKey(displayKey)) + { + displayString = Language.GetString(displayKey); + } + + displayString = displayKey ?? enumValue.ToString(); + + _displayValues.Add(enumValue, displayString); + _reverseValues.Add(displayString, enumValue); + } + + return new List((IEnumerable) _displayValues.Values).AsReadOnly(); + } + } + + private static string GetDisplayKeyValue(DisplayKeyAttribute[] a) + { + if (a == null || a.Length == 0) + { + return null; + } + + DisplayKeyAttribute dka = a[0]; + return dka.Value; + } + + object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return _displayValues[value]; + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return _reverseValues[value]; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs index cd31165ba..dd9d46a1b 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs @@ -21,21 +21,25 @@ using System.Windows; -namespace Greenshot.Plugin.Confluence.Forms { - /// - /// Interaction logic for ConfluenceConfigurationForm.xaml - /// - public partial class ConfluenceConfigurationForm : Window { - public ConfluenceConfiguration Config { get; } +namespace Greenshot.Plugin.Confluence.Forms +{ + /// + /// Interaction logic for ConfluenceConfigurationForm.xaml + /// + public partial class ConfluenceConfigurationForm : Window + { + public ConfluenceConfiguration Config { get; } - public ConfluenceConfigurationForm(ConfluenceConfiguration config) { - DataContext = config; - Config = config; - InitializeComponent(); - } + public ConfluenceConfigurationForm(ConfluenceConfiguration config) + { + DataContext = config; + Config = config; + InitializeComponent(); + } - private void Button_OK_Click(object sender, RoutedEventArgs e) { - DialogResult = true; - } - } + private void Button_OK_Click(object sender, RoutedEventArgs e) + { + DialogResult = true; + } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs index 55ca76659..de3ffc934 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs @@ -21,36 +21,44 @@ using System.Collections.Generic; -namespace Greenshot.Plugin.Confluence.Forms { - /// - /// Interaction logic for ConfluencePagePicker.xaml - /// - public partial class ConfluencePagePicker - { - private readonly ConfluenceUpload _confluenceUpload; +namespace Greenshot.Plugin.Confluence.Forms +{ + /// + /// Interaction logic for ConfluencePagePicker.xaml + /// + public partial class ConfluencePagePicker + { + private readonly ConfluenceUpload _confluenceUpload; - public ConfluencePagePicker(ConfluenceUpload confluenceUpload, List pagesToPick) { - _confluenceUpload = confluenceUpload; - DataContext = pagesToPick; - InitializeComponent(); - } + public ConfluencePagePicker(ConfluenceUpload confluenceUpload, List pagesToPick) + { + _confluenceUpload = confluenceUpload; + DataContext = pagesToPick; + InitializeComponent(); + } - private void PageListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { - SelectionChanged(); - } + private void PageListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) + { + SelectionChanged(); + } - private void SelectionChanged() { - if (PageListView.HasItems && PageListView.SelectedItems.Count > 0) { - _confluenceUpload.SelectedPage = (Page)PageListView.SelectedItem; - // Make sure the uploader knows we selected an already opened page - _confluenceUpload.IsOpenPageSelected = true; - } else { - _confluenceUpload.SelectedPage = null; - } - } + private void SelectionChanged() + { + if (PageListView.HasItems && PageListView.SelectedItems.Count > 0) + { + _confluenceUpload.SelectedPage = (Page) PageListView.SelectedItem; + // Make sure the uploader knows we selected an already opened page + _confluenceUpload.IsOpenPageSelected = true; + } + else + { + _confluenceUpload.SelectedPage = null; + } + } - private void Page_Loaded(object sender, System.Windows.RoutedEventArgs e) { - SelectionChanged(); - } - } + private void Page_Loaded(object sender, System.Windows.RoutedEventArgs e) + { + SelectionChanged(); + } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs index a39c36a39..2b296f5f0 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs @@ -25,69 +25,88 @@ using System.Linq; using System.Windows; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Confluence.Forms { - public partial class ConfluenceSearch - { - private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection(); - private readonly ConfluenceUpload _confluenceUpload; - - public IEnumerable Spaces => _confluenceUpload.Spaces; +namespace Greenshot.Plugin.Confluence.Forms +{ + public partial class ConfluenceSearch + { + private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection(); + private readonly ConfluenceUpload _confluenceUpload; - public ObservableCollection Pages { get; } = new ObservableCollection(); + public IEnumerable Spaces => _confluenceUpload.Spaces; - public ConfluenceSearch(ConfluenceUpload confluenceUpload) { - _confluenceUpload = confluenceUpload; - DataContext = this; - InitializeComponent(); - if (ConfluenceConfig.SearchSpaceKey == null) { - SpaceComboBox.SelectedItem = Spaces.FirstOrDefault(); - } else { - foreach(var space in Spaces) { - if (space.Key.Equals(ConfluenceConfig.SearchSpaceKey)) { - SpaceComboBox.SelectedItem = space; - } - } - } - } + public ObservableCollection Pages { get; } = new ObservableCollection(); - private void PageListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { - SelectionChanged(); - } + public ConfluenceSearch(ConfluenceUpload confluenceUpload) + { + _confluenceUpload = confluenceUpload; + DataContext = this; + InitializeComponent(); + if (ConfluenceConfig.SearchSpaceKey == null) + { + SpaceComboBox.SelectedItem = Spaces.FirstOrDefault(); + } + else + { + foreach (var space in Spaces) + { + if (space.Key.Equals(ConfluenceConfig.SearchSpaceKey)) + { + SpaceComboBox.SelectedItem = space; + } + } + } + } - private void SelectionChanged() { - if (PageListView.HasItems && PageListView.SelectedItems.Count > 0) { - _confluenceUpload.SelectedPage = (Page)PageListView.SelectedItem; - } else { - _confluenceUpload.SelectedPage = null; - } - } + private void PageListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) + { + SelectionChanged(); + } - private void Search_Click(object sender, RoutedEventArgs e) { - DoSearch(); - } + private void SelectionChanged() + { + if (PageListView.HasItems && PageListView.SelectedItems.Count > 0) + { + _confluenceUpload.SelectedPage = (Page) PageListView.SelectedItem; + } + else + { + _confluenceUpload.SelectedPage = null; + } + } - private void DoSearch() { - string spaceKey = (string)SpaceComboBox.SelectedValue; - ConfluenceConfig.SearchSpaceKey = spaceKey; - Pages.Clear(); - foreach(var page in ConfluencePlugin.ConfluenceConnector.SearchPages(searchText.Text, spaceKey).OrderBy(p => p.Title)) { - Pages.Add(page); - } - } + private void Search_Click(object sender, RoutedEventArgs e) + { + DoSearch(); + } - private void SearchText_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) { - if (e.Key == System.Windows.Input.Key.Return && Search.IsEnabled) { - DoSearch(); - e.Handled = true; - } - } + private void DoSearch() + { + string spaceKey = (string) SpaceComboBox.SelectedValue; + ConfluenceConfig.SearchSpaceKey = spaceKey; + Pages.Clear(); + foreach (var page in ConfluencePlugin.ConfluenceConnector.SearchPages(searchText.Text, spaceKey).OrderBy(p => p.Title)) + { + Pages.Add(page); + } + } - private void Page_Loaded(object sender, RoutedEventArgs e) { - SelectionChanged(); - } + private void SearchText_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) + { + if (e.Key == System.Windows.Input.Key.Return && Search.IsEnabled) + { + DoSearch(); + e.Handled = true; + } + } - private void SearchText_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) { - Search.IsEnabled = !string.IsNullOrEmpty(searchText.Text); - } - } + private void Page_Loaded(object sender, RoutedEventArgs e) + { + SelectionChanged(); + } + + private void SearchText_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) + { + Search.IsEnabled = !string.IsNullOrEmpty(searchText.Text); + } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml.cs index cff4878be..62089b4ed 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml.cs @@ -27,101 +27,131 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Threading; -namespace Greenshot.Plugin.Confluence.Forms { - /// - /// Interaction logic for ConfluenceTreePicker.xaml - /// - public partial class ConfluenceTreePicker - { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceTreePicker)); - private readonly ConfluenceConnector _confluenceConnector; - private readonly ConfluenceUpload _confluenceUpload; - private bool _isInitDone; - - public ConfluenceTreePicker(ConfluenceUpload confluenceUpload) { - _confluenceConnector = ConfluencePlugin.ConfluenceConnector; - _confluenceUpload = confluenceUpload; - InitializeComponent(); - } +namespace Greenshot.Plugin.Confluence.Forms +{ + /// + /// Interaction logic for ConfluenceTreePicker.xaml + /// + public partial class ConfluenceTreePicker + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceTreePicker)); + private readonly ConfluenceConnector _confluenceConnector; + private readonly ConfluenceUpload _confluenceUpload; + private bool _isInitDone; - private void PageTreeViewItem_DoubleClick(object sender, MouseButtonEventArgs eventArgs) { - Log.Debug("spaceTreeViewItem_MouseLeftButtonDown is called!"); - TreeViewItem clickedItem = eventArgs.Source as TreeViewItem; - if (clickedItem?.Tag is not Page page) { - return; - } - if (clickedItem.HasItems) - { - return; - } - Log.Debug("Loading pages for page: " + page.Title); - new Thread(() => { - Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)(() => {ShowBusy.Visibility = Visibility.Visible;})); - var pages = _confluenceConnector.GetPageChildren(page).OrderBy(p => p.Title); - Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)(() => { - foreach(var childPage in pages) { - Log.Debug("Adding page: " + childPage.Title); - var pageTreeViewItem = new TreeViewItem - { - Header = childPage.Title, - Tag = childPage - }; - clickedItem.Items.Add(pageTreeViewItem); - pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick; - pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click; - } - ShowBusy.Visibility = Visibility.Collapsed; - })); - }) { Name = "Loading childpages for confluence page " + page.Title }.Start(); - } + public ConfluenceTreePicker(ConfluenceUpload confluenceUpload) + { + _confluenceConnector = ConfluencePlugin.ConfluenceConnector; + _confluenceUpload = confluenceUpload; + InitializeComponent(); + } - private void PageTreeViewItem_Click(object sender, MouseButtonEventArgs eventArgs) { - Log.Debug("pageTreeViewItem_PreviewMouseDoubleClick is called!"); - if (eventArgs.Source is not TreeViewItem clickedItem) { - return; - } - Page page = clickedItem.Tag as Page; - _confluenceUpload.SelectedPage = page; - if (page != null) { - Log.Debug("Page selected: " + page.Title); - } - } + private void PageTreeViewItem_DoubleClick(object sender, MouseButtonEventArgs eventArgs) + { + Log.Debug("spaceTreeViewItem_MouseLeftButtonDown is called!"); + TreeViewItem clickedItem = eventArgs.Source as TreeViewItem; + if (clickedItem?.Tag is not Page page) + { + return; + } - private void Page_Loaded(object sender, RoutedEventArgs e) { - _confluenceUpload.SelectedPage = null; - if (_isInitDone) { - return; - } - ShowBusy.Visibility = Visibility.Visible; - new Thread(() => { - Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)(() => { - foreach (Space space in _confluenceUpload.Spaces) { - TreeViewItem spaceTreeViewItem = new TreeViewItem - { - Header = space.Name, - Tag = space - }; + if (clickedItem.HasItems) + { + return; + } - // Get homepage - try { - Page page = _confluenceConnector.GetSpaceHomepage(space); - TreeViewItem pageTreeViewItem = new TreeViewItem - { - Header = page.Title, - Tag = page - }; - pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick; - pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click; - spaceTreeViewItem.Items.Add(pageTreeViewItem); - ConfluenceTreeView.Items.Add(spaceTreeViewItem); - } catch (Exception ex) { - Log.Error("Can't get homepage for space : " + space.Name + " (" + ex.Message + ")"); - } - } - ShowBusy.Visibility = Visibility.Collapsed; - _isInitDone = true; - })); - }) { Name = "Loading spaces for confluence"}.Start(); - } - } + Log.Debug("Loading pages for page: " + page.Title); + new Thread(() => + { + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() => { ShowBusy.Visibility = Visibility.Visible; })); + var pages = _confluenceConnector.GetPageChildren(page).OrderBy(p => p.Title); + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() => + { + foreach (var childPage in pages) + { + Log.Debug("Adding page: " + childPage.Title); + var pageTreeViewItem = new TreeViewItem + { + Header = childPage.Title, + Tag = childPage + }; + clickedItem.Items.Add(pageTreeViewItem); + pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick; + pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click; + } + + ShowBusy.Visibility = Visibility.Collapsed; + })); + }) + { + Name = "Loading childpages for confluence page " + page.Title + }.Start(); + } + + private void PageTreeViewItem_Click(object sender, MouseButtonEventArgs eventArgs) + { + Log.Debug("pageTreeViewItem_PreviewMouseDoubleClick is called!"); + if (eventArgs.Source is not TreeViewItem clickedItem) + { + return; + } + + Page page = clickedItem.Tag as Page; + _confluenceUpload.SelectedPage = page; + if (page != null) + { + Log.Debug("Page selected: " + page.Title); + } + } + + private void Page_Loaded(object sender, RoutedEventArgs e) + { + _confluenceUpload.SelectedPage = null; + if (_isInitDone) + { + return; + } + + ShowBusy.Visibility = Visibility.Visible; + new Thread(() => + { + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() => + { + foreach (Space space in _confluenceUpload.Spaces) + { + TreeViewItem spaceTreeViewItem = new TreeViewItem + { + Header = space.Name, + Tag = space + }; + + // Get homepage + try + { + Page page = _confluenceConnector.GetSpaceHomepage(space); + TreeViewItem pageTreeViewItem = new TreeViewItem + { + Header = page.Title, + Tag = page + }; + pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick; + pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click; + spaceTreeViewItem.Items.Add(pageTreeViewItem); + ConfluenceTreeView.Items.Add(spaceTreeViewItem); + } + catch (Exception ex) + { + Log.Error("Can't get homepage for space : " + space.Name + " (" + ex.Message + ")"); + } + } + + ShowBusy.Visibility = Visibility.Collapsed; + _isInitDone = true; + })); + }) + { + Name = "Loading spaces for confluence" + }.Start(); + } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs index 276788579..494036c24 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs @@ -25,92 +25,117 @@ using System.Linq; using System.Threading; using System.Windows; -namespace Greenshot.Plugin.Confluence.Forms { - /// - /// Interaction logic for ConfluenceUpload.xaml - /// - public partial class ConfluenceUpload : Window { - private System.Windows.Controls.Page _pickerPage; - public System.Windows.Controls.Page PickerPage { - get { - if (_pickerPage == null) { - List pages = ConfluenceUtils.GetCurrentPages(); - if (pages != null && pages.Count > 0) { - _pickerPage = new ConfluencePagePicker(this, pages); - } - } - return _pickerPage; - } - } +namespace Greenshot.Plugin.Confluence.Forms +{ + /// + /// Interaction logic for ConfluenceUpload.xaml + /// + public partial class ConfluenceUpload : Window + { + private System.Windows.Controls.Page _pickerPage; - private System.Windows.Controls.Page _searchPage; - public System.Windows.Controls.Page SearchPage { - get { return _searchPage ??= new ConfluenceSearch(this); } - } + public System.Windows.Controls.Page PickerPage + { + get + { + if (_pickerPage == null) + { + List pages = ConfluenceUtils.GetCurrentPages(); + if (pages != null && pages.Count > 0) + { + _pickerPage = new ConfluencePagePicker(this, pages); + } + } - private System.Windows.Controls.Page _browsePage; - public System.Windows.Controls.Page BrowsePage { - get { return _browsePage ??= new ConfluenceTreePicker(this); } - } + return _pickerPage; + } + } - private Page _selectedPage; - public Page SelectedPage { - get => _selectedPage; - set { - _selectedPage = value; - Upload.IsEnabled = _selectedPage != null; - IsOpenPageSelected = false; - } - } + private System.Windows.Controls.Page _searchPage; - public bool IsOpenPageSelected { - get; - set; - } - public string Filename { - get; - set; - } - - private static DateTime _lastLoad = DateTime.Now; - private static IList _spaces; - public IList Spaces { - get { - UpdateSpaces(); - while (_spaces == null) { - Thread.Sleep(300); - } - return _spaces; - } - } + public System.Windows.Controls.Page SearchPage + { + get { return _searchPage ??= new ConfluenceSearch(this); } + } - public ConfluenceUpload(string filename) { - Filename = filename; - InitializeComponent(); - DataContext = this; - UpdateSpaces(); - if (PickerPage == null) { - PickerTab.Visibility = Visibility.Collapsed; - SearchTab.IsSelected = true; - } - } + private System.Windows.Controls.Page _browsePage; - private void UpdateSpaces() { - if (_spaces != null && DateTime.Now.AddMinutes(-60).CompareTo(_lastLoad) > 0) { - // Reset - _spaces = null; - } - // Check if load is needed - if (_spaces == null) { - (new Thread(() => { - _spaces = ConfluencePlugin.ConfluenceConnector.GetSpaceSummaries().OrderBy(s => s.Name).ToList(); - _lastLoad = DateTime.Now; - }) { Name = "Loading spaces for confluence"}).Start(); - } - } + public System.Windows.Controls.Page BrowsePage + { + get { return _browsePage ??= new ConfluenceTreePicker(this); } + } - private void Upload_Click(object sender, RoutedEventArgs e) { - DialogResult = true; - } - } + private Page _selectedPage; + + public Page SelectedPage + { + get => _selectedPage; + set + { + _selectedPage = value; + Upload.IsEnabled = _selectedPage != null; + IsOpenPageSelected = false; + } + } + + public bool IsOpenPageSelected { get; set; } + public string Filename { get; set; } + + private static DateTime _lastLoad = DateTime.Now; + private static IList _spaces; + + public IList Spaces + { + get + { + UpdateSpaces(); + while (_spaces == null) + { + Thread.Sleep(300); + } + + return _spaces; + } + } + + public ConfluenceUpload(string filename) + { + Filename = filename; + InitializeComponent(); + DataContext = this; + UpdateSpaces(); + if (PickerPage == null) + { + PickerTab.Visibility = Visibility.Collapsed; + SearchTab.IsSelected = true; + } + } + + private void UpdateSpaces() + { + if (_spaces != null && DateTime.Now.AddMinutes(-60).CompareTo(_lastLoad) > 0) + { + // Reset + _spaces = null; + } + + // Check if load is needed + if (_spaces == null) + { + (new Thread(() => + { + _spaces = ConfluencePlugin.ConfluenceConnector.GetSpaceSummaries().OrderBy(s => s.Name).ToList(); + _lastLoad = DateTime.Now; + }) + { + Name = "Loading spaces for confluence" + }).Start(); + } + } + + private void Upload_Click(object sender, RoutedEventArgs e) + { + DialogResult = true; + } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/LanguageKeys.cs b/src/Greenshot.Plugin.Confluence/LanguageKeys.cs index bdbd039a7..bfee1cea8 100644 --- a/src/Greenshot.Plugin.Confluence/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Confluence/LanguageKeys.cs @@ -19,10 +19,12 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.Confluence { - public enum LangKey { - login_error, - upload_menu_item, - communication_wait - } -} +namespace Greenshot.Plugin.Confluence +{ + public enum LangKey + { + login_error, + upload_menu_item, + communication_wait + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs b/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs index bbabf3a0b..d189db670 100644 --- a/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs +++ b/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs @@ -1,5 +1,7 @@ -namespace Greenshot.Plugin.Confluence.Support { - public interface ITranslationProvider { +namespace Greenshot.Plugin.Confluence.Support +{ + public interface ITranslationProvider + { /// /// Translates the specified key. /// @@ -7,4 +9,4 @@ /// object Translate(string key); } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs b/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs index 64cc4b0a3..6ca4ec384 100644 --- a/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs +++ b/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs @@ -22,13 +22,13 @@ namespace Greenshot.Plugin.Confluence.Support protected override void StartListening(object source) { - var manager = (TranslationManager)source; + var manager = (TranslationManager) source; manager.LanguageChanged += OnLanguageChanged; } protected override void StopListening(object source) { - var manager = (TranslationManager)source; + var manager = (TranslationManager) source; manager.LanguageChanged -= OnLanguageChanged; } @@ -37,15 +37,15 @@ namespace Greenshot.Plugin.Confluence.Support get { Type managerType = typeof(LanguageChangedEventManager); - var manager = (LanguageChangedEventManager)GetCurrentManager(managerType); + var manager = (LanguageChangedEventManager) GetCurrentManager(managerType); if (manager == null) { manager = new LanguageChangedEventManager(); SetCurrentManager(managerType, manager); } + return manager; } - } - + } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs b/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs index 4c98fd1b9..926e7ad8e 100644 --- a/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs +++ b/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs @@ -1,18 +1,23 @@ using GreenshotPlugin.Core; -namespace Greenshot.Plugin.Confluence.Support { - /// - /// - /// - public class LanguageXMLTranslationProvider : ITranslationProvider { +namespace Greenshot.Plugin.Confluence.Support +{ + /// + /// + /// + public class LanguageXMLTranslationProvider : ITranslationProvider + { /// - /// See - /// - public object Translate(string key) { - if (Language.HasKey("confluence", key)) { - return Language.GetString("confluence", key); - } - return key; - } + /// See + ///
+ public object Translate(string key) + { + if (Language.HasKey("confluence", key)) + { + return Language.GetString("confluence", key); + } + + return key; + } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs b/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs index 8d9a6e230..012f0c552 100644 --- a/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs +++ b/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs @@ -25,7 +25,7 @@ namespace Greenshot.Plugin.Confluence.Support public string Key { get { return _key; } - set { _key = value;} + set { _key = value; } } /// @@ -34,10 +34,10 @@ namespace Greenshot.Plugin.Confluence.Support public override object ProvideValue(IServiceProvider serviceProvider) { var binding = new Binding("Value") - { - Source = new TranslationData(_key) - }; + { + Source = new TranslationData(_key) + }; return binding.ProvideValue(serviceProvider); } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs b/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs index 0f920efc4..0ebce8300 100644 --- a/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs +++ b/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs @@ -2,44 +2,49 @@ using System.ComponentModel; using System.Windows; -namespace Greenshot.Plugin.Confluence.Support { - public class TranslationData : IWeakEventListener, INotifyPropertyChanged { +namespace Greenshot.Plugin.Confluence.Support +{ + public class TranslationData : IWeakEventListener, INotifyPropertyChanged + { private readonly string _key; /// - /// Initializes a new instance of the class. - /// - /// The key. - public TranslationData( string key) { - _key = key; - LanguageChangedEventManager.AddListener(TranslationManager.Instance, this); - } + /// Initializes a new instance of the class. + /// + /// The key. + public TranslationData(string key) + { + _key = key; + LanguageChangedEventManager.AddListener(TranslationManager.Instance, this); + } - /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. - /// - ~TranslationData() { - LanguageChangedEventManager.RemoveListener(TranslationManager.Instance, this); - } + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// is reclaimed by garbage collection. + /// + ~TranslationData() + { + LanguageChangedEventManager.RemoveListener(TranslationManager.Instance, this); + } - public object Value => TranslationManager.Instance.Translate(_key); + public object Value => TranslationManager.Instance.Translate(_key); public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) - { - if (managerType == typeof(LanguageChangedEventManager)) - { - OnLanguageChanged(sender, e); - return true; - } - return false; - } + { + if (managerType == typeof(LanguageChangedEventManager)) + { + OnLanguageChanged(sender, e); + return true; + } - private void OnLanguageChanged(object sender, EventArgs e) - { - PropertyChanged?.Invoke( this, new PropertyChangedEventArgs("Value")); - } + return false; + } + + private void OnLanguageChanged(object sender, EventArgs e) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); + } public event PropertyChangedEventHandler PropertyChanged; } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs b/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs index c9af13a4f..825d1aae7 100644 --- a/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs +++ b/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs @@ -1,40 +1,45 @@ using System; -namespace Greenshot.Plugin.Confluence.Support { - public class TranslationManager { - private static TranslationManager _translationManager; +namespace Greenshot.Plugin.Confluence.Support +{ + public class TranslationManager + { + private static TranslationManager _translationManager; - public event EventHandler LanguageChanged; + public event EventHandler LanguageChanged; - /*public CultureInfo CurrentLanguage { - get { return Thread.CurrentThread.CurrentUICulture; } - set { - if( value != Thread.CurrentThread.CurrentUICulture) { - Thread.CurrentThread.CurrentUICulture = value; - OnLanguageChanged(); - } - } - } + /*public CultureInfo CurrentLanguage { + get { return Thread.CurrentThread.CurrentUICulture; } + set { + if( value != Thread.CurrentThread.CurrentUICulture) { + Thread.CurrentThread.CurrentUICulture = value; + OnLanguageChanged(); + } + } + } - public IEnumerable Languages { - get { - if( TranslationProvider != null) { - return TranslationProvider.Languages; - } - return Enumerable.Empty(); - } - }*/ + public IEnumerable Languages { + get { + if( TranslationProvider != null) { + return TranslationProvider.Languages; + } + return Enumerable.Empty(); + } + }*/ - public static TranslationManager Instance => _translationManager ??= new TranslationManager(); + public static TranslationManager Instance => _translationManager ??= new TranslationManager(); - public ITranslationProvider TranslationProvider { get; set; } + public ITranslationProvider TranslationProvider { get; set; } - public object Translate(string key) { - object translatedValue = TranslationProvider?.Translate(key); - if( translatedValue != null) { - return translatedValue; - } - return $"!{key}!"; - } - } -} + public object Translate(string key) + { + object translatedValue = TranslationProvider?.Translate(key); + if (translatedValue != null) + { + return translatedValue; + } + + return $"!{key}!"; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs index 7de974307..61f7a8705 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs @@ -25,38 +25,48 @@ using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; -namespace Greenshot.Plugin.Dropbox { - internal class DropboxDestination : AbstractDestination { - private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection(); +namespace Greenshot.Plugin.Dropbox +{ + internal class DropboxDestination : AbstractDestination + { + private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection(); - private readonly DropboxPlugin _plugin; - public DropboxDestination(DropboxPlugin plugin) { - _plugin = plugin; - } + private readonly DropboxPlugin _plugin; - public override string Designation => "Dropbox"; + public DropboxDestination(DropboxPlugin plugin) + { + _plugin = plugin; + } - public override string Description => Language.GetString("dropbox", LangKey.upload_menu_item); + public override string Designation => "Dropbox"; - public override Image DisplayIcon { - get { - ComponentResourceManager resources = new ComponentResourceManager(typeof(DropboxPlugin)); - return (Image)resources.GetObject("Dropbox"); - } - } + public override string Description => Language.GetString("dropbox", LangKey.upload_menu_item); - public override ExportInformation ExportCapture(bool manually, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); - if (uploaded) { - exportInformation.Uri = uploadUrl; - exportInformation.ExportMade = true; - if (DropboxConfig.AfterUploadLinkToClipBoard) { - ClipboardHelper.SetClipboardData(uploadUrl); - } - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(DropboxPlugin)); + return (Image) resources.GetObject("Dropbox"); + } + } + + public override ExportInformation ExportCapture(bool manually, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); + if (uploaded) + { + exportInformation.Uri = uploadUrl; + exportInformation.ExportMade = true; + if (DropboxConfig.AfterUploadLinkToClipBoard) + { + ClipboardHelper.SetClipboardData(uploadUrl); + } + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs index abd83112f..1ec893423 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs @@ -29,93 +29,101 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Dropbox { - /// - /// This is the Dropbox base code - /// +namespace Greenshot.Plugin.Dropbox +{ + /// + /// This is the Dropbox base code + /// [Plugin("Dropbox", true)] - public class DropboxPlugin : IGreenshotPlugin { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxPlugin)); - private static DropboxPluginConfiguration _config; - private ComponentResourceManager _resources; - private ToolStripMenuItem _itemPlugInConfig; + public class DropboxPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxPlugin)); + private static DropboxPluginConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInConfig; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - private void Dispose(bool disposing) - { - if (!disposing) return; - if (_itemPlugInConfig == null) return; - _itemPlugInConfig.Dispose(); - _itemPlugInConfig = null; - } + private void Dispose(bool disposing) + { + if (!disposing) return; + if (_itemPlugInConfig == null) return; + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; + } - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - public bool Initialize() { - - // Register configuration (don't need the configuration itself) - _config = IniConfig.GetIniSection(); - _resources = new ComponentResourceManager(typeof(DropboxPlugin)); + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + public bool Initialize() + { + // Register configuration (don't need the configuration itself) + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(DropboxPlugin)); SimpleServiceProvider.Current.AddService(new DropboxDestination(this)); - _itemPlugInConfig = new ToolStripMenuItem - { - Text = Language.GetString("dropbox", LangKey.Configure), - Image = (Image)_resources.GetObject("Dropbox") - }; - _itemPlugInConfig.Click += ConfigMenuClick; + _itemPlugInConfig = new ToolStripMenuItem + { + Text = Language.GetString("dropbox", LangKey.Configure), + Image = (Image) _resources.GetObject("Dropbox") + }; + _itemPlugInConfig.Click += ConfigMenuClick; - PluginUtils.AddToContextMenu(_itemPlugInConfig); - Language.LanguageChanged += OnLanguageChanged; - return true; - } + PluginUtils.AddToContextMenu(_itemPlugInConfig); + Language.LanguageChanged += OnLanguageChanged; + return true; + } - public void OnLanguageChanged(object sender, EventArgs e) { - if (_itemPlugInConfig != null) { - _itemPlugInConfig.Text = Language.GetString("dropbox", LangKey.Configure); - } - } + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Text = Language.GetString("dropbox", LangKey.Configure); + } + } - public void Shutdown() { - Log.Debug("Dropbox Plugin shutdown."); - } + public void Shutdown() + { + Log.Debug("Dropbox Plugin shutdown."); + } - /// - /// Implementation of the IPlugin.Configure - /// - public void Configure() { - _config.ShowConfigDialog(); - } + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + _config.ShowConfigDialog(); + } - public void ConfigMenuClick(object sender, EventArgs eventArgs) { - _config.ShowConfigDialog(); - } + public void ConfigMenuClick(object sender, EventArgs eventArgs) + { + _config.ShowConfigDialog(); + } - /// - /// This will be called when the menu item in the Editor is clicked - /// - public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) { - uploadUrl = null; - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); - try + /// + /// This will be called when the menu item in the Editor is clicked + /// + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) + { + uploadUrl = null; + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); + try { bool result = false; - new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait), - delegate - { - result = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, captureDetails); - } - ); + new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait), + delegate { result = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, captureDetails); } + ); return result; - } catch (Exception e) { - Log.Error(e); - MessageBox.Show(Language.GetString("dropbox", LangKey.upload_failure) + " " + e.Message); - return false; - } - } - } -} + } + catch (Exception e) + { + Log.Error(e); + MessageBox.Show(Language.GetString("dropbox", LangKey.upload_failure) + " " + e.Message); + return false; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs b/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs index 1b738cdeb..4a2bd95d0 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs @@ -25,25 +25,27 @@ using Greenshot.Plugin.Dropbox.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Dropbox { - /// - /// Description of ImgurConfiguration. - /// - [IniSection("Dropbox", Description = "Greenshot Dropbox Plugin configuration")] - public class DropboxPluginConfiguration : IniSection { - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat { get; set; } +namespace Greenshot.Plugin.Dropbox +{ + /// + /// Description of ImgurConfiguration. + /// + [IniSection("Dropbox", Description = "Greenshot Dropbox Plugin configuration")] + public class DropboxPluginConfiguration : IniSection + { + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } - [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality { get; set; } + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } - [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Dropbox link to clipboard.", DefaultValue = "true")] - public bool AfterUploadLinkToClipBoard { get; set; } + [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Dropbox link to clipboard.", DefaultValue = "true")] + public bool AfterUploadLinkToClipBoard { get; set; } [IniProperty("RefreshToken", Description = "Dropbox refresh Token", Encrypted = true, ExcludeIfNull = true)] public string RefreshToken { get; set; } - /// + /// /// AccessToken, not stored /// public string AccessToken { get; set; } @@ -53,16 +55,19 @@ namespace Greenshot.Plugin.Dropbox { /// public DateTimeOffset AccessTokenExpires { get; set; } - /// - /// A form for token - /// - /// bool true if OK was pressed, false if cancel - public bool ShowConfigDialog() { - DialogResult result = new SettingsForm().ShowDialog(); - if (result == DialogResult.OK) { - return true; - } - return false; - } - } -} + /// + /// A form for token + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + DialogResult result = new SettingsForm().ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs index dd130c9bc..ebb7b2685 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs @@ -29,19 +29,22 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using Newtonsoft.Json; -namespace Greenshot.Plugin.Dropbox { - /// - /// Description of DropboxUtils. - /// - public class DropboxUtils { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxUtils)); - private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection(); +namespace Greenshot.Plugin.Dropbox +{ + /// + /// Description of DropboxUtils. + /// + public class DropboxUtils + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxUtils)); + private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection(); - private DropboxUtils() { - } + private DropboxUtils() + { + } - public static bool UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, ICaptureDetails captureDetails) - { + public static bool UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, ICaptureDetails captureDetails) + { var oauth2Settings = new OAuth2Settings { AuthUrlPattern = "https://api.dropbox.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}&redirect_uri={RedirectUrl}", @@ -51,24 +54,32 @@ namespace Greenshot.Plugin.Dropbox { ClientId = DropBoxCredentials.CONSUMER_KEY, ClientSecret = DropBoxCredentials.CONSUMER_SECRET, AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, - RefreshToken = DropboxConfig.RefreshToken, + RefreshToken = DropboxConfig.RefreshToken, AccessToken = DropboxConfig.AccessToken, AccessTokenExpires = DropboxConfig.AccessTokenExpires - }; + }; try - { + { string filename = Path.GetFileName(FilenameHelper.GetFilename(DropboxConfig.UploadFormat, captureDetails)); SurfaceContainer image = new SurfaceContainer(surfaceToUpload, outputSettings, filename); IDictionary arguments = new Dictionary { - { "autorename", true }, - { "mute", true }, - { "path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\')} + { + "autorename", true + }, + { + "mute", true + }, + { + "path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\') + } }; IDictionary headers = new Dictionary { - { "Dropbox-API-Arg", JsonConvert.SerializeObject(arguments)} + { + "Dropbox-API-Arg", JsonConvert.SerializeObject(arguments) + } }; var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, "https://content.dropboxapi.com/2/files/upload", oauth2Settings); @@ -78,16 +89,19 @@ namespace Greenshot.Plugin.Dropbox { var response = JsonConvert.DeserializeObject>(responseString); return response.ContainsKey("id"); } - catch (Exception ex) { - Log.Error("Upload error: ", ex); - throw; - } finally { + catch (Exception ex) + { + Log.Error("Upload error: ", ex); + throw; + } + finally + { DropboxConfig.RefreshToken = oauth2Settings.RefreshToken; DropboxConfig.AccessToken = oauth2Settings.AccessToken; DropboxConfig.AccessTokenExpires = oauth2Settings.AccessTokenExpires; DropboxConfig.IsDirty = true; IniConfig.Save(); } - } - } -} + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs b/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs index c7aaecb1d..b39d1e14d 100644 --- a/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs +++ b/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs @@ -21,7 +21,9 @@ using GreenshotPlugin.Controls; -namespace Greenshot.Plugin.Dropbox.Forms { - public class DropboxForm : GreenshotForm { - } -} +namespace Greenshot.Plugin.Dropbox.Forms +{ + public class DropboxForm : GreenshotForm + { + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs index 9586c9ca7..c79844e6d 100644 --- a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs @@ -19,19 +19,21 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.Dropbox.Forms { - /// - /// Description of PasswordRequestForm. - /// - public partial class SettingsForm : DropboxForm { - public SettingsForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - AcceptButton = buttonOK; - CancelButton = buttonCancel; - } - - } -} +namespace Greenshot.Plugin.Dropbox.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : DropboxForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = buttonOK; + CancelButton = buttonCancel; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs b/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs index 9b42f6c75..37d6b50e3 100644 --- a/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs @@ -18,11 +18,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace Greenshot.Plugin.Dropbox { - public enum LangKey { - upload_menu_item, - upload_failure, - communication_wait, - Configure + +namespace Greenshot.Plugin.Dropbox +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + Configure } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs index 9e9b18e04..5870d89ea 100644 --- a/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs index e4f345f47..8d677e200 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs @@ -25,122 +25,140 @@ using System.IO; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.ExternalCommand { - /// - /// Description of FlickrConfiguration. - /// - [IniSection("ExternalCommand", Description="Greenshot ExternalCommand Plugin configuration")] - public class ExternalCommandConfiguration : IniSection { - [IniProperty("Commands", Description="The commands that are available.")] - public List Commands { get; set; } +namespace Greenshot.Plugin.ExternalCommand +{ + /// + /// Description of FlickrConfiguration. + /// + [IniSection("ExternalCommand", Description = "Greenshot ExternalCommand Plugin configuration")] + public class ExternalCommandConfiguration : IniSection + { + [IniProperty("Commands", Description = "The commands that are available.")] + public List Commands { get; set; } - [IniProperty("RedirectStandardError", Description = "Redirect the standard error of all external commands, used to output as warning to the greenshot.log.", DefaultValue = "true")] - public bool RedirectStandardError { get; set; } + [IniProperty("RedirectStandardError", Description = "Redirect the standard error of all external commands, used to output as warning to the greenshot.log.", + DefaultValue = "true")] + public bool RedirectStandardError { get; set; } - [IniProperty("RedirectStandardOutput", Description = "Redirect the standard output of all external commands, used for different other functions (more below).", DefaultValue = "true")] - public bool RedirectStandardOutput { get; set; } + [IniProperty("RedirectStandardOutput", Description = "Redirect the standard output of all external commands, used for different other functions (more below).", + DefaultValue = "true")] + public bool RedirectStandardOutput { get; set; } - [IniProperty("ShowStandardOutputInLog", Description = "Depends on 'RedirectStandardOutput': Show standard output of all external commands to the Greenshot log, this can be usefull for debugging.", DefaultValue = "false")] - public bool ShowStandardOutputInLog { get; set; } + [IniProperty("ShowStandardOutputInLog", + Description = "Depends on 'RedirectStandardOutput': Show standard output of all external commands to the Greenshot log, this can be usefull for debugging.", + DefaultValue = "false")] + public bool ShowStandardOutputInLog { get; set; } - [IniProperty("ParseForUri", Description = "Depends on 'RedirectStandardOutput': Parse the output and take the first found URI, if a URI is found than clicking on the notify bubble goes there.", DefaultValue = "true")] - public bool ParseOutputForUri { get; set; } + [IniProperty("ParseForUri", + Description = "Depends on 'RedirectStandardOutput': Parse the output and take the first found URI, if a URI is found than clicking on the notify bubble goes there.", + DefaultValue = "true")] + public bool ParseOutputForUri { get; set; } - [IniProperty("OutputToClipboard", Description = "Depends on 'RedirectStandardOutput': Place the standard output on the clipboard.", DefaultValue = "false")] - public bool OutputToClipboard { get; set; } + [IniProperty("OutputToClipboard", Description = "Depends on 'RedirectStandardOutput': Place the standard output on the clipboard.", DefaultValue = "false")] + public bool OutputToClipboard { get; set; } - [IniProperty("UriToClipboard", Description = "Depends on 'RedirectStandardOutput' & 'ParseForUri': If an URI is found in the standard input, place it on the clipboard. (This overwrites the output from OutputToClipboard setting.)", DefaultValue = "true")] - public bool UriToClipboard { get; set; } + [IniProperty("UriToClipboard", + Description = + "Depends on 'RedirectStandardOutput' & 'ParseForUri': If an URI is found in the standard input, place it on the clipboard. (This overwrites the output from OutputToClipboard setting.)", + DefaultValue = "true")] + public bool UriToClipboard { get; set; } - [IniProperty("Commandline", Description="The commandline for the output command.")] - public Dictionary Commandline { get; set; } + [IniProperty("Commandline", Description = "The commandline for the output command.")] + public Dictionary Commandline { get; set; } - [IniProperty("Argument", Description="The arguments for the output command.")] - public Dictionary Argument { get; set; } + [IniProperty("Argument", Description = "The arguments for the output command.")] + public Dictionary Argument { get; set; } - [IniProperty("RunInbackground", Description = "Should the command be started in the background.")] - public Dictionary RunInbackground { get; set; } + [IniProperty("RunInbackground", Description = "Should the command be started in the background.")] + public Dictionary RunInbackground { get; set; } - [IniProperty("DeletedBuildInCommands", Description = "If a build in command was deleted manually, it should not be recreated.")] - public List DeletedBuildInCommands { get; set; } + [IniProperty("DeletedBuildInCommands", Description = "If a build in command was deleted manually, it should not be recreated.")] + public List DeletedBuildInCommands { get; set; } - private const string MsPaint = "MS Paint"; - private static readonly string PaintPath; - private static readonly bool HasPaint; + private const string MsPaint = "MS Paint"; + private static readonly string PaintPath; + private static readonly bool HasPaint; - private const string PaintDotNet = "Paint.NET"; - private static readonly string PaintDotNetPath; - private static readonly bool HasPaintDotNet; - static ExternalCommandConfiguration() { - try { - PaintPath = PluginUtils.GetExePath("pbrush.exe"); - HasPaint = !string.IsNullOrEmpty(PaintPath) && File.Exists(PaintPath); - } catch { - // Ignore - } - try - { - PaintDotNetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Paint.NET\PaintDotNet.exe"); - HasPaintDotNet = !string.IsNullOrEmpty(PaintDotNetPath) && File.Exists(PaintDotNetPath); - } - catch - { - // Ignore - } - } + private const string PaintDotNet = "Paint.NET"; + private static readonly string PaintDotNetPath; + private static readonly bool HasPaintDotNet; - /// - /// Delete the configuration for the specified command - /// - /// string with command - public void Delete(string command) - { - if (string.IsNullOrEmpty(command)) - { - return; - } - Commands.Remove(command); - Commandline.Remove(command); - Argument.Remove(command); - RunInbackground.Remove(command); - if (MsPaint.Equals(command) || PaintDotNet.Equals(command)) - { - if (!DeletedBuildInCommands.Contains(command)) - { - DeletedBuildInCommands.Add(command); - } - } - } + static ExternalCommandConfiguration() + { + try + { + PaintPath = PluginUtils.GetExePath("pbrush.exe"); + HasPaint = !string.IsNullOrEmpty(PaintPath) && File.Exists(PaintPath); + } + catch + { + // Ignore + } - public override void AfterLoad() - { - base.AfterLoad(); + try + { + PaintDotNetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Paint.NET\PaintDotNet.exe"); + HasPaintDotNet = !string.IsNullOrEmpty(PaintDotNetPath) && File.Exists(PaintDotNetPath); + } + catch + { + // Ignore + } + } - // Check if we need to add MsPaint - if (HasPaint && !Commands.Contains(MsPaint) && !DeletedBuildInCommands.Contains(MsPaint)) - { - Commands.Add(MsPaint); - Commandline.Add(MsPaint, PaintPath); - Argument.Add(MsPaint, "\"{0}\""); - RunInbackground.Add(MsPaint, true); - } + /// + /// Delete the configuration for the specified command + /// + /// string with command + public void Delete(string command) + { + if (string.IsNullOrEmpty(command)) + { + return; + } - // Check if we need to add Paint.NET - if (HasPaintDotNet && !Commands.Contains(PaintDotNet) && !DeletedBuildInCommands.Contains(PaintDotNet)) - { - Commands.Add(PaintDotNet); - Commandline.Add(PaintDotNet, PaintDotNetPath); - Argument.Add(PaintDotNet, "\"{0}\""); - RunInbackground.Add(PaintDotNet, true); - } - } + Commands.Remove(command); + Commandline.Remove(command); + Argument.Remove(command); + RunInbackground.Remove(command); + if (MsPaint.Equals(command) || PaintDotNet.Equals(command)) + { + if (!DeletedBuildInCommands.Contains(command)) + { + DeletedBuildInCommands.Add(command); + } + } + } - /// - /// Supply values we can't put as defaults - /// - /// The property to return a default for - /// object with the default value for the supplied property - public override object GetDefault(string property) => + public override void AfterLoad() + { + base.AfterLoad(); + + // Check if we need to add MsPaint + if (HasPaint && !Commands.Contains(MsPaint) && !DeletedBuildInCommands.Contains(MsPaint)) + { + Commands.Add(MsPaint); + Commandline.Add(MsPaint, PaintPath); + Argument.Add(MsPaint, "\"{0}\""); + RunInbackground.Add(MsPaint, true); + } + + // Check if we need to add Paint.NET + if (HasPaintDotNet && !Commands.Contains(PaintDotNet) && !DeletedBuildInCommands.Contains(PaintDotNet)) + { + Commands.Add(PaintDotNet); + Commandline.Add(PaintDotNet, PaintDotNetPath); + Argument.Add(PaintDotNet, "\"{0}\""); + RunInbackground.Add(PaintDotNet, true); + } + } + + /// + /// Supply values we can't put as defaults + /// + /// The property to return a default for + /// object with the default value for the supplied property + public override object GetDefault(string property) => property switch { nameof(DeletedBuildInCommands) => (object) new List(), @@ -151,4 +169,4 @@ namespace Greenshot.Plugin.ExternalCommand { _ => null }; } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs index df9b25352..c7ab3b957 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs @@ -31,146 +31,184 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.ExternalCommand { - /// - /// Description of OCRDestination. - /// - public class ExternalCommandDestination : AbstractDestination { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExternalCommandDestination)); - private static readonly Regex URI_REGEXP = new Regex(@"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)"); - private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection(); - private readonly string _presetCommand; - - public ExternalCommandDestination(string commando) { - _presetCommand = commando; - } +namespace Greenshot.Plugin.ExternalCommand +{ + /// + /// Description of OCRDestination. + /// + public class ExternalCommandDestination : AbstractDestination + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExternalCommandDestination)); - public override string Designation => "External " + _presetCommand.Replace(',','_'); + private static readonly Regex URI_REGEXP = + new Regex( + @"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)"); - public override string Description => _presetCommand; + private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection(); + private readonly string _presetCommand; - public override IEnumerable DynamicDestinations() { - yield break; - } + public ExternalCommandDestination(string commando) + { + _presetCommand = commando; + } - public override Image DisplayIcon => IconCache.IconForCommand(_presetCommand); + public override string Designation => "External " + _presetCommand.Replace(',', '_'); - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); - outputSettings.PreventGreenshotFormat(); + public override string Description => _presetCommand; - if (_presetCommand != null) { - if (!config.RunInbackground.ContainsKey(_presetCommand)) { - config.RunInbackground.Add(_presetCommand, true); - } - bool runInBackground = config.RunInbackground[_presetCommand]; - string fullPath = captureDetails.Filename ?? ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings); + public override IEnumerable DynamicDestinations() + { + yield break; + } + + public override Image DisplayIcon => IconCache.IconForCommand(_presetCommand); + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); + outputSettings.PreventGreenshotFormat(); + + if (_presetCommand != null) + { + if (!config.RunInbackground.ContainsKey(_presetCommand)) + { + config.RunInbackground.Add(_presetCommand, true); + } + + bool runInBackground = config.RunInbackground[_presetCommand]; + string fullPath = captureDetails.Filename ?? ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings); string output; - string error; - if (runInBackground) { - Thread commandThread = new Thread(delegate() - { - CallExternalCommand(exportInformation, fullPath, out output, out error); - ProcessExport(exportInformation, surface); - }) - { - Name = "Running " + _presetCommand, - IsBackground = true - }; - commandThread.SetApartmentState(ApartmentState.STA); - commandThread.Start(); - exportInformation.ExportMade = true; - } else { - CallExternalCommand(exportInformation, fullPath, out output, out error); - ProcessExport(exportInformation, surface); - } - } - return exportInformation; - } + string error; + if (runInBackground) + { + Thread commandThread = new Thread(delegate() + { + CallExternalCommand(exportInformation, fullPath, out output, out error); + ProcessExport(exportInformation, surface); + }) + { + Name = "Running " + _presetCommand, + IsBackground = true + }; + commandThread.SetApartmentState(ApartmentState.STA); + commandThread.Start(); + exportInformation.ExportMade = true; + } + else + { + CallExternalCommand(exportInformation, fullPath, out output, out error); + ProcessExport(exportInformation, surface); + } + } - /// - /// Wrapper method for the background and normal call, this does all the logic: - /// Call the external command, parse for URI, place to clipboard and set the export information - /// - /// - /// - /// - /// - private void CallExternalCommand(ExportInformation exportInformation, string fullPath, out string output, out string error) { - output = null; - error = null; - try { - if (CallExternalCommand(_presetCommand, fullPath, out output, out error) == 0) { - exportInformation.ExportMade = true; - if (!string.IsNullOrEmpty(output)) { - MatchCollection uriMatches = URI_REGEXP.Matches(output); - // Place output on the clipboard before the URI, so if one is found this overwrites - if (config.OutputToClipboard) { - ClipboardHelper.SetClipboardData(output); - } - if (uriMatches.Count > 0) { - exportInformation.Uri = uriMatches[0].Groups[1].Value; - LOG.InfoFormat("Got URI : {0} ", exportInformation.Uri); - if (config.UriToClipboard) { - ClipboardHelper.SetClipboardData(exportInformation.Uri); - } - } - } - } else { - LOG.WarnFormat("Error calling external command: {0} ", output); - exportInformation.ExportMade = false; - exportInformation.ErrorMessage = error; - } - } catch (Exception ex) { - exportInformation.ExportMade = false; - exportInformation.ErrorMessage = ex.Message; - LOG.WarnFormat("Error calling external command: {0} ", exportInformation.ErrorMessage); - } - } + return exportInformation; + } - /// - /// Wrapper to retry with a runas - /// - /// - /// - /// - /// - /// - private int CallExternalCommand(string commando, string fullPath, out string output, out string error) { - try { - return CallExternalCommand(commando, fullPath, null, out output, out error); - } catch (Win32Exception w32Ex) { - try { - return CallExternalCommand(commando, fullPath, "runas", out output, out error); - } catch { - w32Ex.Data.Add("commandline", config.Commandline[_presetCommand]); - w32Ex.Data.Add("arguments", config.Argument[_presetCommand]); - throw; - } - } catch (Exception ex) { - ex.Data.Add("commandline", config.Commandline[_presetCommand]); - ex.Data.Add("arguments", config.Argument[_presetCommand]); - throw; - } - } + /// + /// Wrapper method for the background and normal call, this does all the logic: + /// Call the external command, parse for URI, place to clipboard and set the export information + /// + /// + /// + /// + /// + private void CallExternalCommand(ExportInformation exportInformation, string fullPath, out string output, out string error) + { + output = null; + error = null; + try + { + if (CallExternalCommand(_presetCommand, fullPath, out output, out error) == 0) + { + exportInformation.ExportMade = true; + if (!string.IsNullOrEmpty(output)) + { + MatchCollection uriMatches = URI_REGEXP.Matches(output); + // Place output on the clipboard before the URI, so if one is found this overwrites + if (config.OutputToClipboard) + { + ClipboardHelper.SetClipboardData(output); + } - /// - /// The actual executing code for the external command - /// - /// - /// - /// - /// - /// - /// - private int CallExternalCommand(string commando, string fullPath, string verb, out string output, out string error) { - string commandline = config.Commandline[commando]; - string arguments = config.Argument[commando]; - output = null; - error = null; - if (!string.IsNullOrEmpty(commandline)) + if (uriMatches.Count > 0) + { + exportInformation.Uri = uriMatches[0].Groups[1].Value; + LOG.InfoFormat("Got URI : {0} ", exportInformation.Uri); + if (config.UriToClipboard) + { + ClipboardHelper.SetClipboardData(exportInformation.Uri); + } + } + } + } + else + { + LOG.WarnFormat("Error calling external command: {0} ", output); + exportInformation.ExportMade = false; + exportInformation.ErrorMessage = error; + } + } + catch (Exception ex) + { + exportInformation.ExportMade = false; + exportInformation.ErrorMessage = ex.Message; + LOG.WarnFormat("Error calling external command: {0} ", exportInformation.ErrorMessage); + } + } + + /// + /// Wrapper to retry with a runas + /// + /// + /// + /// + /// + /// + private int CallExternalCommand(string commando, string fullPath, out string output, out string error) + { + try + { + return CallExternalCommand(commando, fullPath, null, out output, out error); + } + catch (Win32Exception w32Ex) + { + try + { + return CallExternalCommand(commando, fullPath, "runas", out output, out error); + } + catch + { + w32Ex.Data.Add("commandline", config.Commandline[_presetCommand]); + w32Ex.Data.Add("arguments", config.Argument[_presetCommand]); + throw; + } + } + catch (Exception ex) + { + ex.Data.Add("commandline", config.Commandline[_presetCommand]); + ex.Data.Add("arguments", config.Argument[_presetCommand]); + throw; + } + } + + /// + /// The actual executing code for the external command + /// + /// + /// + /// + /// + /// + /// + private int CallExternalCommand(string commando, string fullPath, string verb, out string output, out string error) + { + string commandline = config.Commandline[commando]; + string arguments = config.Argument[commando]; + output = null; + error = null; + if (!string.IsNullOrEmpty(commandline)) { using Process process = new Process(); // Fix variables @@ -183,39 +221,52 @@ namespace Greenshot.Plugin.ExternalCommand { process.StartInfo.FileName = FilenameHelper.FillCmdVariables(commandline, true); process.StartInfo.Arguments = FormatArguments(arguments, fullPath); process.StartInfo.UseShellExecute = false; - if (config.RedirectStandardOutput) { + if (config.RedirectStandardOutput) + { process.StartInfo.RedirectStandardOutput = true; } - if (config.RedirectStandardError) { + + if (config.RedirectStandardError) + { process.StartInfo.RedirectStandardError = true; } - if (verb != null) { + + if (verb != null) + { process.StartInfo.Verb = verb; } + LOG.InfoFormat("Starting : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); process.Start(); process.WaitForExit(); - if (config.RedirectStandardOutput) { + if (config.RedirectStandardOutput) + { output = process.StandardOutput.ReadToEnd(); - if (config.ShowStandardOutputInLog && output.Trim().Length > 0) { + if (config.ShowStandardOutputInLog && output.Trim().Length > 0) + { LOG.InfoFormat("Output:\n{0}", output); } } - if (config.RedirectStandardError) { + + if (config.RedirectStandardError) + { error = process.StandardError.ReadToEnd(); - if (error.Trim().Length > 0) { + if (error.Trim().Length > 0) + { LOG.WarnFormat("Error:\n{0}", error); } } + LOG.InfoFormat("Finished : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); return process.ExitCode; } - return -1; - } - public static string FormatArguments(string arguments, string fullpath) - { - return string.Format(arguments, fullpath); - } - } -} + return -1; + } + + public static string FormatArguments(string arguments, string fullpath) + { + return string.Format(arguments, fullpath); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs index 7167b954b..7fdfffa2a 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs @@ -21,10 +21,12 @@ using GreenshotPlugin.Controls; -namespace Greenshot.Plugin.ExternalCommand { - /// - /// This class is needed for design-time resolving of the language files - /// - public class ExternalCommandForm : GreenshotForm { - } +namespace Greenshot.Plugin.ExternalCommand +{ + /// + /// This class is needed for design-time resolving of the language files + /// + public class ExternalCommandForm : GreenshotForm + { + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs index eeb99ed41..43ae03f41 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs @@ -55,6 +55,7 @@ namespace Greenshot.Plugin.ExternalCommand _itemPlugInRoot.Dispose(); _itemPlugInRoot = null; } + private IEnumerable Destinations() { foreach (string command in ExternalCommandConfig.Commands) @@ -77,17 +78,20 @@ namespace Greenshot.Plugin.ExternalCommand // Fix it ExternalCommandConfig.RunInbackground.Add(command, true); } + if (!ExternalCommandConfig.Argument.ContainsKey(command)) { Log.WarnFormat("Found missing argument for {0}", command); // Fix it ExternalCommandConfig.Argument.Add(command, "{0}"); } + if (!ExternalCommandConfig.Commandline.ContainsKey(command)) { Log.WarnFormat("Found missing commandline for {0}", command); return false; } + string commandline = FilenameHelper.FillVariables(ExternalCommandConfig.Commandline[command], true); commandline = FilenameHelper.FillCmdVariables(commandline, true); @@ -96,8 +100,10 @@ namespace Greenshot.Plugin.ExternalCommand Log.WarnFormat("Found 'invalid' commandline {0} for command {1}", ExternalCommandConfig.Commandline[command], command); return false; } + return true; } + /// /// Implementation of the IGreenshotPlugin.Initialize /// @@ -114,11 +120,13 @@ namespace Greenshot.Plugin.ExternalCommand commandsToDelete.Add(command); } } + // cleanup foreach (string command in commandsToDelete) { ExternalCommandConfig.Delete(command); } + SimpleServiceProvider.Current.AddService(Destinations()); _itemPlugInRoot = new ToolStripMenuItem(); diff --git a/src/Greenshot.Plugin.ExternalCommand/IconCache.cs b/src/Greenshot.Plugin.ExternalCommand/IconCache.cs index 44ea0a84d..f1b854164 100644 --- a/src/Greenshot.Plugin.ExternalCommand/IconCache.cs +++ b/src/Greenshot.Plugin.ExternalCommand/IconCache.cs @@ -25,23 +25,32 @@ using System.IO; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.ExternalCommand { - public static class IconCache { - private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection(); - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(IconCache)); +namespace Greenshot.Plugin.ExternalCommand +{ + public static class IconCache + { + private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection(); + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(IconCache)); - public static Image IconForCommand(string commandName) { - Image icon = null; - if (commandName != null) { - if (config.Commandline.ContainsKey(commandName) && File.Exists(config.Commandline[commandName])) { - try { - icon = PluginUtils.GetCachedExeIcon(config.Commandline[commandName], 0); - } catch (Exception ex) { - LOG.Warn("Problem loading icon for " + config.Commandline[commandName], ex); - } - } - } - return icon; - } - } -} + public static Image IconForCommand(string commandName) + { + Image icon = null; + if (commandName != null) + { + if (config.Commandline.ContainsKey(commandName) && File.Exists(config.Commandline[commandName])) + { + try + { + icon = PluginUtils.GetCachedExeIcon(config.Commandline[commandName], 0); + } + catch (Exception ex) + { + LOG.Warn("Problem loading icon for " + config.Commandline[commandName], ex); + } + } + } + + return icon; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs index c4cf9ca2b..49e872d7f 100644 --- a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs @@ -24,103 +24,129 @@ using System.Drawing; using System.Windows.Forms; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.ExternalCommand { - /// - /// Description of SettingsForm. - /// - public partial class SettingsForm : ExternalCommandForm { - private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection(); +namespace Greenshot.Plugin.ExternalCommand +{ + /// + /// Description of SettingsForm. + /// + public partial class SettingsForm : ExternalCommandForm + { + private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection(); - public SettingsForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - AcceptButton = buttonOk; - CancelButton = buttonCancel; - UpdateView(); - } + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = buttonOk; + CancelButton = buttonCancel; + UpdateView(); + } - private void ButtonOkClick(object sender, EventArgs e) { - IniConfig.Save(); - } + private void ButtonOkClick(object sender, EventArgs e) + { + IniConfig.Save(); + } - private void ButtonAddClick(object sender, EventArgs e) { - var form = new SettingsFormDetail(null); - form.ShowDialog(); + private void ButtonAddClick(object sender, EventArgs e) + { + var form = new SettingsFormDetail(null); + form.ShowDialog(); - UpdateView(); - } + UpdateView(); + } - private void ButtonDeleteClick(object sender, EventArgs e) { - foreach(ListViewItem item in listView1.SelectedItems) { - string commando = item.Tag as string; + private void ButtonDeleteClick(object sender, EventArgs e) + { + foreach (ListViewItem item in listView1.SelectedItems) + { + string commando = item.Tag as string; - ExternalCommandConfig.Delete(commando); - } - UpdateView(); - } + ExternalCommandConfig.Delete(commando); + } - private void UpdateView() { - listView1.Items.Clear(); - if(ExternalCommandConfig.Commands != null) { - listView1.ListViewItemSorter = new ListviewComparer(); - ImageList imageList = new ImageList(); - listView1.SmallImageList = imageList; - int imageNr = 0; - foreach(string commando in ExternalCommandConfig.Commands) { - ListViewItem item; - Image iconForExe = IconCache.IconForCommand(commando); - if(iconForExe != null) { - imageList.Images.Add(iconForExe); - item = new ListViewItem(commando, imageNr++); - } else { - item = new ListViewItem(commando); - } - item.Tag = commando; - listView1.Items.Add(item); - } - } - // Fix for bug #1484, getting an ArgumentOutOfRangeException as there is nothing selected but the edit button was still active. - button_edit.Enabled = listView1.SelectedItems.Count > 0; - } + UpdateView(); + } - private void ListView1ItemSelectionChanged(object sender, EventArgs e) { - button_edit.Enabled = listView1.SelectedItems.Count > 0; - } + private void UpdateView() + { + listView1.Items.Clear(); + if (ExternalCommandConfig.Commands != null) + { + listView1.ListViewItemSorter = new ListviewComparer(); + ImageList imageList = new ImageList(); + listView1.SmallImageList = imageList; + int imageNr = 0; + foreach (string commando in ExternalCommandConfig.Commands) + { + ListViewItem item; + Image iconForExe = IconCache.IconForCommand(commando); + if (iconForExe != null) + { + imageList.Images.Add(iconForExe); + item = new ListViewItem(commando, imageNr++); + } + else + { + item = new ListViewItem(commando); + } - private void ButtonEditClick(object sender, EventArgs e) { - ListView1DoubleClick(sender, e); - } + item.Tag = commando; + listView1.Items.Add(item); + } + } - private void ListView1DoubleClick(object sender, EventArgs e) { - // Safety check for bug #1484 - bool selectionActive = listView1.SelectedItems.Count > 0; - if(!selectionActive) { - button_edit.Enabled = false; - return; - } - string commando = listView1.SelectedItems[0].Tag as string; + // Fix for bug #1484, getting an ArgumentOutOfRangeException as there is nothing selected but the edit button was still active. + button_edit.Enabled = listView1.SelectedItems.Count > 0; + } - var form = new SettingsFormDetail(commando); - form.ShowDialog(); + private void ListView1ItemSelectionChanged(object sender, EventArgs e) + { + button_edit.Enabled = listView1.SelectedItems.Count > 0; + } - UpdateView(); - } - } + private void ButtonEditClick(object sender, EventArgs e) + { + ListView1DoubleClick(sender, e); + } - public class ListviewComparer : System.Collections.IComparer { - public int Compare(object x, object y) { - if(!(x is ListViewItem)) { - return (0); - } - if(!(y is ListViewItem)) { - return (0); - } + private void ListView1DoubleClick(object sender, EventArgs e) + { + // Safety check for bug #1484 + bool selectionActive = listView1.SelectedItems.Count > 0; + if (!selectionActive) + { + button_edit.Enabled = false; + return; + } - var l1 = (ListViewItem)x; - var l2 = (ListViewItem)y; - return string.Compare(l1.Text, l2.Text, StringComparison.Ordinal); - } - } -} + string commando = listView1.SelectedItems[0].Tag as string; + + var form = new SettingsFormDetail(commando); + form.ShowDialog(); + + UpdateView(); + } + } + + public class ListviewComparer : System.Collections.IComparer + { + public int Compare(object x, object y) + { + if (!(x is ListViewItem)) + { + return (0); + } + + if (!(y is ListViewItem)) + { + return (0); + } + + var l1 = (ListViewItem) x; + var l2 = (ListViewItem) y; + return string.Compare(l1.Text, l2.Text, StringComparison.Ordinal); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs index 9c353b197..8aa235a67 100644 --- a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs @@ -26,141 +26,167 @@ using System.Windows.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.ExternalCommand { - /// - /// Description of SettingsFormDetail. - /// - public partial class SettingsFormDetail : ExternalCommandForm { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(SettingsFormDetail)); - private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection(); +namespace Greenshot.Plugin.ExternalCommand +{ + /// + /// Description of SettingsFormDetail. + /// + public partial class SettingsFormDetail : ExternalCommandForm + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(SettingsFormDetail)); + private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection(); - private readonly string _commando; - private readonly int _commandIndex; + private readonly string _commando; + private readonly int _commandIndex; - public SettingsFormDetail(string commando) { - InitializeComponent(); - AcceptButton = buttonOk; - CancelButton = buttonCancel; - _commando = commando; + public SettingsFormDetail(string commando) + { + InitializeComponent(); + AcceptButton = buttonOk; + CancelButton = buttonCancel; + _commando = commando; - if(commando != null) { - textBox_name.Text = commando; - textBox_commandline.Text = ExternalCommandConfig.Commandline[commando]; - textBox_arguments.Text = ExternalCommandConfig.Argument[commando]; - _commandIndex = ExternalCommandConfig.Commands.FindIndex(s => s == commando); - } else { - textBox_arguments.Text = "\"{0}\""; - } - OkButtonState(); - } + if (commando != null) + { + textBox_name.Text = commando; + textBox_commandline.Text = ExternalCommandConfig.Commandline[commando]; + textBox_arguments.Text = ExternalCommandConfig.Argument[commando]; + _commandIndex = ExternalCommandConfig.Commands.FindIndex(s => s == commando); + } + else + { + textBox_arguments.Text = "\"{0}\""; + } - private void ButtonOkClick(object sender, EventArgs e) { - string commandName = textBox_name.Text; - string commandLine = textBox_commandline.Text; - string arguments = textBox_arguments.Text; - if(_commando != null) { - ExternalCommandConfig.Commands[_commandIndex] = commandName; - ExternalCommandConfig.Commandline.Remove(_commando); - ExternalCommandConfig.Commandline.Add(commandName, commandLine); - ExternalCommandConfig.Argument.Remove(_commando); - ExternalCommandConfig.Argument.Add(commandName, arguments); - } else { - ExternalCommandConfig.Commands.Add(commandName); - ExternalCommandConfig.Commandline.Add(commandName, commandLine); - ExternalCommandConfig.Argument.Add(commandName, arguments); - } - } + OkButtonState(); + } - private void Button3Click(object sender, EventArgs e) { - var openFileDialog = new OpenFileDialog - { - Filter = "Executables (*.exe, *.bat, *.com)|*.exe; *.bat; *.com|All files (*)|*", - FilterIndex = 1, - CheckFileExists = true, - Multiselect = false - }; - string initialPath = null; - try - { - initialPath = Path.GetDirectoryName(textBox_commandline.Text); - } - catch (Exception ex) - { - Log.WarnFormat("Can't get the initial path via {0}", textBox_commandline.Text); - Log.Warn("Exception: ", ex); - } - if(initialPath != null && Directory.Exists(initialPath)) { - openFileDialog.InitialDirectory = initialPath; - } else { - initialPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); - openFileDialog.InitialDirectory = initialPath; - } - Log.DebugFormat("Starting OpenFileDialog at {0}", initialPath); - if(openFileDialog.ShowDialog() == DialogResult.OK) { - textBox_commandline.Text = openFileDialog.FileName; - } - } + private void ButtonOkClick(object sender, EventArgs e) + { + string commandName = textBox_name.Text; + string commandLine = textBox_commandline.Text; + string arguments = textBox_arguments.Text; + if (_commando != null) + { + ExternalCommandConfig.Commands[_commandIndex] = commandName; + ExternalCommandConfig.Commandline.Remove(_commando); + ExternalCommandConfig.Commandline.Add(commandName, commandLine); + ExternalCommandConfig.Argument.Remove(_commando); + ExternalCommandConfig.Argument.Add(commandName, arguments); + } + else + { + ExternalCommandConfig.Commands.Add(commandName); + ExternalCommandConfig.Commandline.Add(commandName, commandLine); + ExternalCommandConfig.Argument.Add(commandName, arguments); + } + } - private void OkButtonState() { - // Assume OK - buttonOk.Enabled = true; - textBox_name.BackColor = Color.White; - textBox_commandline.BackColor = Color.White; - textBox_arguments.BackColor = Color.White; - // Is there a text in the name field - if(string.IsNullOrEmpty(textBox_name.Text)) { - buttonOk.Enabled = false; - } - // Check if commandname is unique - if(_commando == null && !string.IsNullOrEmpty(textBox_name.Text) && ExternalCommandConfig.Commands.Contains(textBox_name.Text)) { - buttonOk.Enabled = false; - textBox_name.BackColor = Color.Red; - } - // Is there a text in the commandline field - if(string.IsNullOrEmpty(textBox_commandline.Text)) { - buttonOk.Enabled = false; - } + private void Button3Click(object sender, EventArgs e) + { + var openFileDialog = new OpenFileDialog + { + Filter = "Executables (*.exe, *.bat, *.com)|*.exe; *.bat; *.com|All files (*)|*", + FilterIndex = 1, + CheckFileExists = true, + Multiselect = false + }; + string initialPath = null; + try + { + initialPath = Path.GetDirectoryName(textBox_commandline.Text); + } + catch (Exception ex) + { + Log.WarnFormat("Can't get the initial path via {0}", textBox_commandline.Text); + Log.Warn("Exception: ", ex); + } - if (!string.IsNullOrEmpty(textBox_commandline.Text)) - { - // Added this to be more flexible, using the Greenshot var format - string cmdPath = FilenameHelper.FillVariables(textBox_commandline.Text, true); - // And also replace the "DOS" Variables - cmdPath = FilenameHelper.FillCmdVariables(cmdPath, true); - // Is the command available? - if (!File.Exists(cmdPath)) - { - buttonOk.Enabled = false; - textBox_commandline.BackColor = Color.Red; - } - } - // Are the arguments in a valid format? - try - { - string arguments = FilenameHelper.FillVariables(textBox_arguments.Text, false); - arguments = FilenameHelper.FillCmdVariables(arguments, false); + if (initialPath != null && Directory.Exists(initialPath)) + { + openFileDialog.InitialDirectory = initialPath; + } + else + { + initialPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + openFileDialog.InitialDirectory = initialPath; + } - ExternalCommandDestination.FormatArguments(arguments, string.Empty); - } - catch - { - buttonOk.Enabled = false; - textBox_arguments.BackColor = Color.Red; - } - } + Log.DebugFormat("Starting OpenFileDialog at {0}", initialPath); + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + textBox_commandline.Text = openFileDialog.FileName; + } + } - private void textBox_name_TextChanged(object sender, EventArgs e) { - OkButtonState(); - } + private void OkButtonState() + { + // Assume OK + buttonOk.Enabled = true; + textBox_name.BackColor = Color.White; + textBox_commandline.BackColor = Color.White; + textBox_arguments.BackColor = Color.White; + // Is there a text in the name field + if (string.IsNullOrEmpty(textBox_name.Text)) + { + buttonOk.Enabled = false; + } - private void textBox_commandline_TextChanged(object sender, EventArgs e) { - OkButtonState(); - } + // Check if commandname is unique + if (_commando == null && !string.IsNullOrEmpty(textBox_name.Text) && ExternalCommandConfig.Commands.Contains(textBox_name.Text)) + { + buttonOk.Enabled = false; + textBox_name.BackColor = Color.Red; + } - private void textBox_arguments_TextChanged(object sender, EventArgs e) - { - OkButtonState(); - } + // Is there a text in the commandline field + if (string.IsNullOrEmpty(textBox_commandline.Text)) + { + buttonOk.Enabled = false; + } - } -} + if (!string.IsNullOrEmpty(textBox_commandline.Text)) + { + // Added this to be more flexible, using the Greenshot var format + string cmdPath = FilenameHelper.FillVariables(textBox_commandline.Text, true); + // And also replace the "DOS" Variables + cmdPath = FilenameHelper.FillCmdVariables(cmdPath, true); + // Is the command available? + if (!File.Exists(cmdPath)) + { + buttonOk.Enabled = false; + textBox_commandline.BackColor = Color.Red; + } + } + + // Are the arguments in a valid format? + try + { + string arguments = FilenameHelper.FillVariables(textBox_arguments.Text, false); + arguments = FilenameHelper.FillCmdVariables(arguments, false); + + ExternalCommandDestination.FormatArguments(arguments, string.Empty); + } + catch + { + buttonOk.Enabled = false; + textBox_arguments.BackColor = Color.Red; + } + } + + private void textBox_name_TextChanged(object sender, EventArgs e) + { + OkButtonState(); + } + + private void textBox_commandline_TextChanged(object sender, EventArgs e) + { + OkButtonState(); + } + + private void textBox_arguments_TextChanged(object sender, EventArgs e) + { + OkButtonState(); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs index 600e61a47..68fc72a3e 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs @@ -24,59 +24,67 @@ using Greenshot.Plugin.Flickr.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Flickr { - public enum SafetyLevel { - Safe = 1, - Moderate = 2, - Restricted = 3 - } - /// - /// Description of FlickrConfiguration. - /// - [IniSection("Flickr", Description = "Greenshot Flickr Plugin configuration")] - public class FlickrConfiguration : IniSection { - [IniProperty("flickrIsPublic", Description = "IsPublic.", DefaultValue = "true")] - public bool IsPublic { get; set; } +namespace Greenshot.Plugin.Flickr +{ + public enum SafetyLevel + { + Safe = 1, + Moderate = 2, + Restricted = 3 + } - [IniProperty("flickrIsFamily", Description = "IsFamily.", DefaultValue = "true")] - public bool IsFamily { get; set; } + /// + /// Description of FlickrConfiguration. + /// + [IniSection("Flickr", Description = "Greenshot Flickr Plugin configuration")] + public class FlickrConfiguration : IniSection + { + [IniProperty("flickrIsPublic", Description = "IsPublic.", DefaultValue = "true")] + public bool IsPublic { get; set; } - [IniProperty("flickrIsFriend", Description = "IsFriend.", DefaultValue = "true")] - public bool IsFriend { get; set; } + [IniProperty("flickrIsFamily", Description = "IsFamily.", DefaultValue = "true")] + public bool IsFamily { get; set; } - [IniProperty("SafetyLevel", Description = "Safety level", DefaultValue = "Safe")] - public SafetyLevel SafetyLevel { get; set; } + [IniProperty("flickrIsFriend", Description = "IsFriend.", DefaultValue = "true")] + public bool IsFriend { get; set; } - [IniProperty("HiddenFromSearch", Description = "Hidden from search", DefaultValue = "false")] - public bool HiddenFromSearch { get; set; } + [IniProperty("SafetyLevel", Description = "Safety level", DefaultValue = "Safe")] + public SafetyLevel SafetyLevel { get; set; } - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat { get; set; } + [IniProperty("HiddenFromSearch", Description = "Hidden from search", DefaultValue = "false")] + public bool HiddenFromSearch { get; set; } - [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality { get; set; } + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } - [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send flickr link to clipboard.", DefaultValue = "true")] - public bool AfterUploadLinkToClipBoard { get; set; } + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } - [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] - public bool UsePageLink { get; set; } + [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send flickr link to clipboard.", DefaultValue = "true")] + public bool AfterUploadLinkToClipBoard { get; set; } - [IniProperty("FlickrToken", Description = "The Flickr token", Encrypted = true, ExcludeIfNull = true)] - public string FlickrToken { get; set; } - [IniProperty("FlickrTokenSecret", Description = "The Flickr token secret", Encrypted = true, ExcludeIfNull = true)] - public string FlickrTokenSecret { get; set; } + [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] + public bool UsePageLink { get; set; } - /// - /// A form for token - /// - /// bool true if OK was pressed, false if cancel - public bool ShowConfigDialog() { - DialogResult result = new SettingsForm().ShowDialog(); - if (result == DialogResult.OK) { - return true; - } - return false; - } - } -} + [IniProperty("FlickrToken", Description = "The Flickr token", Encrypted = true, ExcludeIfNull = true)] + public string FlickrToken { get; set; } + + [IniProperty("FlickrTokenSecret", Description = "The Flickr token secret", Encrypted = true, ExcludeIfNull = true)] + public string FlickrTokenSecret { get; set; } + + /// + /// A form for token + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + DialogResult result = new SettingsForm().ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/FlickrDestination.cs b/src/Greenshot.Plugin.Flickr/FlickrDestination.cs index 340cf3c09..ec61f3b62 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrDestination.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrDestination.cs @@ -24,33 +24,42 @@ using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace Greenshot.Plugin.Flickr { - public class FlickrDestination : AbstractDestination { - private readonly FlickrPlugin _plugin; - public FlickrDestination(FlickrPlugin plugin) { - _plugin = plugin; - } +namespace Greenshot.Plugin.Flickr +{ + public class FlickrDestination : AbstractDestination + { + private readonly FlickrPlugin _plugin; - public override string Designation => "Flickr"; + public FlickrDestination(FlickrPlugin plugin) + { + _plugin = plugin; + } - public override string Description => Language.GetString("flickr", LangKey.upload_menu_item); + public override string Designation => "Flickr"; - public override Image DisplayIcon { - get { - ComponentResourceManager resources = new ComponentResourceManager(typeof(FlickrPlugin)); - return (Image)resources.GetObject("flickr"); - } - } + public override string Description => Language.GetString("flickr", LangKey.upload_menu_item); - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(FlickrPlugin)); + return (Image) resources.GetObject("flickr"); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); - if (uploaded) { - exportInformation.ExportMade = true; - exportInformation.Uri = uploadUrl; - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + if (uploaded) + { + exportInformation.ExportMade = true; + exportInformation.Uri = uploadUrl; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs index 62f21a509..0ce2afaad 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs @@ -33,99 +33,122 @@ using log4net; namespace Greenshot.Plugin.Flickr { - /// - /// This is the Flickr base code - /// + /// + /// This is the Flickr base code + /// [Plugin("Flickr", true)] - public class FlickrPlugin : IGreenshotPlugin { - private static readonly ILog Log = LogManager.GetLogger(typeof(FlickrPlugin)); - private static FlickrConfiguration _config; - private ComponentResourceManager _resources; - private ToolStripMenuItem _itemPlugInConfig; + public class FlickrPlugin : IGreenshotPlugin + { + private static readonly ILog Log = LogManager.GetLogger(typeof(FlickrPlugin)); + private static FlickrConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInConfig; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected void Dispose(bool disposing) { - if (!disposing) { - return; - } - if (_itemPlugInConfig == null) { - return; - } - _itemPlugInConfig.Dispose(); - _itemPlugInConfig = null; - } + protected void Dispose(bool disposing) + { + if (!disposing) + { + return; + } - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - public bool Initialize() { - // Register configuration (don't need the configuration itself) - _config = IniConfig.GetIniSection(); - _resources = new ComponentResourceManager(typeof(FlickrPlugin)); + if (_itemPlugInConfig == null) + { + return; + } - _itemPlugInConfig = new ToolStripMenuItem - { - Text = Language.GetString("flickr", LangKey.Configure), - Image = (Image) _resources.GetObject("flickr") - }; - _itemPlugInConfig.Click += ConfigMenuClick; + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + public bool Initialize() + { + // Register configuration (don't need the configuration itself) + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(FlickrPlugin)); + + _itemPlugInConfig = new ToolStripMenuItem + { + Text = Language.GetString("flickr", LangKey.Configure), + Image = (Image) _resources.GetObject("flickr") + }; + _itemPlugInConfig.Click += ConfigMenuClick; SimpleServiceProvider.Current.AddService(new FlickrDestination(this)); - PluginUtils.AddToContextMenu(_itemPlugInConfig); - Language.LanguageChanged += OnLanguageChanged; - return true; - } + PluginUtils.AddToContextMenu(_itemPlugInConfig); + Language.LanguageChanged += OnLanguageChanged; + return true; + } - public void OnLanguageChanged(object sender, EventArgs e) { - if (_itemPlugInConfig != null) { - _itemPlugInConfig.Text = Language.GetString("flickr", LangKey.Configure); - } - } + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Text = Language.GetString("flickr", LangKey.Configure); + } + } - public void Shutdown() { - Log.Debug("Flickr Plugin shutdown."); - } + public void Shutdown() + { + Log.Debug("Flickr Plugin shutdown."); + } - /// - /// Implementation of the IPlugin.Configure - /// - public void Configure() { - _config.ShowConfigDialog(); - } + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + _config.ShowConfigDialog(); + } - public void ConfigMenuClick(object sender, EventArgs eventArgs) { - _config.ShowConfigDialog(); - } + public void ConfigMenuClick(object sender, EventArgs eventArgs) + { + _config.ShowConfigDialog(); + } - public bool Upload(ICaptureDetails captureDetails, ISurface surface, out string uploadUrl) { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); - uploadUrl = null; - try { - string flickrUrl = null; - new PleaseWaitForm().ShowAndWait("Flickr", Language.GetString("flickr", LangKey.communication_wait), - delegate { - string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); - flickrUrl = FlickrUtils.UploadToFlickr(surface, outputSettings, captureDetails.Title, filename); - } - ); - - if (flickrUrl == null) { - return false; - } - uploadUrl = flickrUrl; + public bool Upload(ICaptureDetails captureDetails, ISurface surface, out string uploadUrl) + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); + uploadUrl = null; + try + { + string flickrUrl = null; + new PleaseWaitForm().ShowAndWait("Flickr", Language.GetString("flickr", LangKey.communication_wait), + delegate + { + string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); + flickrUrl = FlickrUtils.UploadToFlickr(surface, outputSettings, captureDetails.Title, filename); + } + ); - if (_config.AfterUploadLinkToClipBoard) { - ClipboardHelper.SetClipboardData(flickrUrl); - } - return true; - } catch (Exception e) { - Log.Error("Error uploading.", e); - MessageBox.Show(Language.GetString("flickr", LangKey.upload_failure) + " " + e.Message); - } - return false; - } - } -} + if (flickrUrl == null) + { + return false; + } + + uploadUrl = flickrUrl; + + if (_config.AfterUploadLinkToClipBoard) + { + ClipboardHelper.SetClipboardData(flickrUrl); + } + + return true; + } + catch (Exception e) + { + Log.Error("Error uploading.", e); + MessageBox.Show(Language.GetString("flickr", LangKey.upload_failure) + " " + e.Message); + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/FlickrUtils.cs b/src/Greenshot.Plugin.Flickr/FlickrUtils.cs index c6978a17d..582484433 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrUtils.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrUtils.cs @@ -30,140 +30,203 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using log4net; -namespace Greenshot.Plugin.Flickr { - /// - /// Description of FlickrUtils. - /// - public static class FlickrUtils { - private static readonly ILog LOG = LogManager.GetLogger(typeof(FlickrUtils)); - private static readonly FlickrConfiguration config = IniConfig.GetIniSection(); - private const string FLICKR_API_BASE_URL = "https://api.flickr.com/services/"; - private const string FLICKR_UPLOAD_URL = FLICKR_API_BASE_URL + "upload/"; - // OAUTH - private const string FLICKR_OAUTH_BASE_URL = FLICKR_API_BASE_URL + "oauth/"; - private const string FLICKR_ACCESS_TOKEN_URL = FLICKR_OAUTH_BASE_URL + "access_token"; - private const string FLICKR_AUTHORIZE_URL = FLICKR_OAUTH_BASE_URL + "authorize"; - private const string FLICKR_REQUEST_TOKEN_URL = FLICKR_OAUTH_BASE_URL + "request_token"; - private const string FLICKR_FARM_URL = "https://farm{0}.staticflickr.com/{1}/{2}_{3}_o.{4}"; - // REST - private const string FLICKR_REST_URL = FLICKR_API_BASE_URL + "rest/"; - private const string FLICKR_GET_INFO_URL = FLICKR_REST_URL + "?method=flickr.photos.getInfo"; +namespace Greenshot.Plugin.Flickr +{ + /// + /// Description of FlickrUtils. + /// + public static class FlickrUtils + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(FlickrUtils)); + private static readonly FlickrConfiguration config = IniConfig.GetIniSection(); + private const string FLICKR_API_BASE_URL = "https://api.flickr.com/services/"; - /// - /// Do the actual upload to Flickr - /// For more details on the available parameters, see: http://flickrnet.codeplex.com - /// - /// - /// - /// - /// - /// url to image - public static string UploadToFlickr(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) { - var oAuth = new OAuthSession(FlickrCredentials.ConsumerKey, FlickrCredentials.ConsumerSecret) - { - BrowserSize = new Size(520, 800), - CheckVerifier = false, - AccessTokenUrl = FLICKR_ACCESS_TOKEN_URL, - AuthorizeUrl = FLICKR_AUTHORIZE_URL, - RequestTokenUrl = FLICKR_REQUEST_TOKEN_URL, - LoginTitle = "Flickr authorization", - Token = config.FlickrToken, - TokenSecret = config.FlickrTokenSecret - }; - if (string.IsNullOrEmpty(oAuth.Token)) { - if (!oAuth.Authorize()) { - return null; - } - if (!string.IsNullOrEmpty(oAuth.Token)) { - config.FlickrToken = oAuth.Token; - } - if (!string.IsNullOrEmpty(oAuth.TokenSecret)) { - config.FlickrTokenSecret = oAuth.TokenSecret; - } - IniConfig.Save(); - } - try { - IDictionary signedParameters = new Dictionary - { - { "content_type", "2" }, // Screenshot - { "tags", "Greenshot" }, - { "is_public", config.IsPublic ? "1" : "0" }, - { "is_friend", config.IsFriend ? "1" : "0" }, - { "is_family", config.IsFamily ? "1" : "0" }, - { "safety_level", $"{(int)config.SafetyLevel}" }, - { "hidden", config.HiddenFromSearch ? "1" : "2" } - }; - IDictionary otherParameters = new Dictionary - { - { "photo", new SurfaceContainer(surfaceToUpload, outputSettings, filename) } - }; - string response = oAuth.MakeOAuthRequest(HTTPMethod.POST, FLICKR_UPLOAD_URL, signedParameters, otherParameters, null); - string photoId = GetPhotoId(response); + private const string FLICKR_UPLOAD_URL = FLICKR_API_BASE_URL + "upload/"; - // Get Photo Info - signedParameters = new Dictionary { { "photo_id", photoId } }; - string photoInfo = oAuth.MakeOAuthRequest(HTTPMethod.POST, FLICKR_GET_INFO_URL, signedParameters, null, null); - return GetUrl(photoInfo); - } catch (Exception ex) { - LOG.Error("Upload error: ", ex); - throw; - } finally { - if (!string.IsNullOrEmpty(oAuth.Token)) { - config.FlickrToken = oAuth.Token; - } - if (!string.IsNullOrEmpty(oAuth.TokenSecret)) { - config.FlickrTokenSecret = oAuth.TokenSecret; - } - } - } + // OAUTH + private const string FLICKR_OAUTH_BASE_URL = FLICKR_API_BASE_URL + "oauth/"; + private const string FLICKR_ACCESS_TOKEN_URL = FLICKR_OAUTH_BASE_URL + "access_token"; + private const string FLICKR_AUTHORIZE_URL = FLICKR_OAUTH_BASE_URL + "authorize"; + private const string FLICKR_REQUEST_TOKEN_URL = FLICKR_OAUTH_BASE_URL + "request_token"; - private static string GetUrl(string response) { - try { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(response); - if (config.UsePageLink) { - XmlNodeList nodes = doc.GetElementsByTagName("url"); - if (nodes.Count > 0) { - var xmlNode = nodes.Item(0); - if (xmlNode != null) { - return xmlNode.InnerText; - } - } - } else { - XmlNodeList nodes = doc.GetElementsByTagName("photo"); - if (nodes.Count > 0) { - var item = nodes.Item(0); - if (item?.Attributes != null) { - string farmId = item.Attributes["farm"].Value; - string serverId = item.Attributes["server"].Value; - string photoId = item.Attributes["id"].Value; - string originalsecret = item.Attributes["originalsecret"].Value; - string originalFormat = item.Attributes["originalformat"].Value; - return string.Format(FLICKR_FARM_URL, farmId, serverId, photoId, originalsecret, originalFormat); - } - } - } - } catch (Exception ex) { - LOG.Error("Error parsing Flickr Response.", ex); - } - return null; - } + private const string FLICKR_FARM_URL = "https://farm{0}.staticflickr.com/{1}/{2}_{3}_o.{4}"; - private static string GetPhotoId(string response) { - try { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(response); - XmlNodeList nodes = doc.GetElementsByTagName("photoid"); - if (nodes.Count > 0) { - var xmlNode = nodes.Item(0); - if (xmlNode != null) { - return xmlNode.InnerText; - } - } - } catch (Exception ex) { - LOG.Error("Error parsing Flickr Response.", ex); - } - return null; - } - } -} + // REST + private const string FLICKR_REST_URL = FLICKR_API_BASE_URL + "rest/"; + private const string FLICKR_GET_INFO_URL = FLICKR_REST_URL + "?method=flickr.photos.getInfo"; + + /// + /// Do the actual upload to Flickr + /// For more details on the available parameters, see: http://flickrnet.codeplex.com + /// + /// + /// + /// + /// + /// url to image + public static string UploadToFlickr(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) + { + var oAuth = new OAuthSession(FlickrCredentials.ConsumerKey, FlickrCredentials.ConsumerSecret) + { + BrowserSize = new Size(520, 800), + CheckVerifier = false, + AccessTokenUrl = FLICKR_ACCESS_TOKEN_URL, + AuthorizeUrl = FLICKR_AUTHORIZE_URL, + RequestTokenUrl = FLICKR_REQUEST_TOKEN_URL, + LoginTitle = "Flickr authorization", + Token = config.FlickrToken, + TokenSecret = config.FlickrTokenSecret + }; + if (string.IsNullOrEmpty(oAuth.Token)) + { + if (!oAuth.Authorize()) + { + return null; + } + + if (!string.IsNullOrEmpty(oAuth.Token)) + { + config.FlickrToken = oAuth.Token; + } + + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) + { + config.FlickrTokenSecret = oAuth.TokenSecret; + } + + IniConfig.Save(); + } + + try + { + IDictionary signedParameters = new Dictionary + { + { + "content_type", "2" + }, // Screenshot + { + "tags", "Greenshot" + }, + { + "is_public", config.IsPublic ? "1" : "0" + }, + { + "is_friend", config.IsFriend ? "1" : "0" + }, + { + "is_family", config.IsFamily ? "1" : "0" + }, + { + "safety_level", $"{(int) config.SafetyLevel}" + }, + { + "hidden", config.HiddenFromSearch ? "1" : "2" + } + }; + IDictionary otherParameters = new Dictionary + { + { + "photo", new SurfaceContainer(surfaceToUpload, outputSettings, filename) + } + }; + string response = oAuth.MakeOAuthRequest(HTTPMethod.POST, FLICKR_UPLOAD_URL, signedParameters, otherParameters, null); + string photoId = GetPhotoId(response); + + // Get Photo Info + signedParameters = new Dictionary + { + { + "photo_id", photoId + } + }; + string photoInfo = oAuth.MakeOAuthRequest(HTTPMethod.POST, FLICKR_GET_INFO_URL, signedParameters, null, null); + return GetUrl(photoInfo); + } + catch (Exception ex) + { + LOG.Error("Upload error: ", ex); + throw; + } + finally + { + if (!string.IsNullOrEmpty(oAuth.Token)) + { + config.FlickrToken = oAuth.Token; + } + + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) + { + config.FlickrTokenSecret = oAuth.TokenSecret; + } + } + } + + private static string GetUrl(string response) + { + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + if (config.UsePageLink) + { + XmlNodeList nodes = doc.GetElementsByTagName("url"); + if (nodes.Count > 0) + { + var xmlNode = nodes.Item(0); + if (xmlNode != null) + { + return xmlNode.InnerText; + } + } + } + else + { + XmlNodeList nodes = doc.GetElementsByTagName("photo"); + if (nodes.Count > 0) + { + var item = nodes.Item(0); + if (item?.Attributes != null) + { + string farmId = item.Attributes["farm"].Value; + string serverId = item.Attributes["server"].Value; + string photoId = item.Attributes["id"].Value; + string originalsecret = item.Attributes["originalsecret"].Value; + string originalFormat = item.Attributes["originalformat"].Value; + return string.Format(FLICKR_FARM_URL, farmId, serverId, photoId, originalsecret, originalFormat); + } + } + } + } + catch (Exception ex) + { + LOG.Error("Error parsing Flickr Response.", ex); + } + + return null; + } + + private static string GetPhotoId(string response) + { + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + XmlNodeList nodes = doc.GetElementsByTagName("photoid"); + if (nodes.Count > 0) + { + var xmlNode = nodes.Item(0); + if (xmlNode != null) + { + return xmlNode.InnerText; + } + } + } + catch (Exception ex) + { + LOG.Error("Error parsing Flickr Response.", ex); + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs b/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs index 74e032708..0c8f4130e 100644 --- a/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs @@ -21,7 +21,9 @@ using GreenshotPlugin.Controls; -namespace Greenshot.Plugin.Flickr.Forms { - public class FlickrForm : GreenshotForm { - } +namespace Greenshot.Plugin.Flickr.Forms +{ + public class FlickrForm : GreenshotForm + { + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs index eba638160..332f28664 100644 --- a/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs @@ -19,19 +19,21 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.Flickr.Forms { - /// - /// Description of PasswordRequestForm. - /// - public partial class SettingsForm : FlickrForm { - public SettingsForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - CancelButton = buttonCancel; - AcceptButton = buttonOK; - } - - } -} +namespace Greenshot.Plugin.Flickr.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : FlickrForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + CancelButton = buttonCancel; + AcceptButton = buttonOK; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/LanguageKeys.cs b/src/Greenshot.Plugin.Flickr/LanguageKeys.cs index d347faa0a..da634aabe 100644 --- a/src/Greenshot.Plugin.Flickr/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Flickr/LanguageKeys.cs @@ -18,11 +18,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace Greenshot.Plugin.Flickr { - public enum LangKey { - upload_menu_item, - upload_failure, - communication_wait, - Configure + +namespace Greenshot.Plugin.Flickr +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + Configure } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs index 7cc8b4a3a..84938a6ab 100644 --- a/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs index 1b3c76816..616398591 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs @@ -20,7 +20,9 @@ using GreenshotPlugin.Controls; -namespace Greenshot.Plugin.GooglePhotos.Forms { - public class GooglePhotosForm : GreenshotForm { - } -} +namespace Greenshot.Plugin.GooglePhotos.Forms +{ + public class GooglePhotosForm : GreenshotForm + { + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs index 3946baf1b..6029212f9 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs @@ -18,21 +18,21 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.GooglePhotos.Forms { - /// - /// Description of PasswordRequestForm. - /// - public partial class SettingsForm : GooglePhotosForm { - - public SettingsForm() - { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - CancelButton = buttonCancel; - AcceptButton = buttonOK; - } - - } -} +namespace Greenshot.Plugin.GooglePhotos.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : GooglePhotosForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + CancelButton = buttonCancel; + AcceptButton = buttonOK; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs index d11d797d1..411cf6ba9 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs @@ -24,71 +24,58 @@ using Greenshot.Plugin.GooglePhotos.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.GooglePhotos { - /// - /// Description of GooglePhotosConfiguration. - /// - [IniSection("GooglePhotos", Description = "Greenshot GooglePhotos Plugin configuration")] - public class GooglePhotosConfiguration : IniSection { - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat { get; set; } +namespace Greenshot.Plugin.GooglePhotos +{ + /// + /// Description of GooglePhotosConfiguration. + /// + [IniSection("GooglePhotos", Description = "Greenshot GooglePhotos Plugin configuration")] + public class GooglePhotosConfiguration : IniSection + { + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } - [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality { get; set; } + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } - [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send GooglePhotos link to clipboard.", DefaultValue = "true")] - public bool AfterUploadLinkToClipBoard { get; set; } - [IniProperty("AddFilename", Description = "Is the filename passed on to GooglePhotos", DefaultValue = "False")] - public bool AddFilename { - get; - set; - } + [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send GooglePhotos link to clipboard.", DefaultValue = "true")] + public bool AfterUploadLinkToClipBoard { get; set; } - [IniProperty("UploadUser", Description = "The GooglePhotos user to upload to", DefaultValue = "default")] - public string UploadUser { - get; - set; - } + [IniProperty("AddFilename", Description = "Is the filename passed on to GooglePhotos", DefaultValue = "False")] + public bool AddFilename { get; set; } - [IniProperty("UploadAlbum", Description = "The GooglePhotos album to upload to", DefaultValue = "default")] - public string UploadAlbum { - get; - set; - } + [IniProperty("UploadUser", Description = "The GooglePhotos user to upload to", DefaultValue = "default")] + public string UploadUser { get; set; } - [IniProperty("RefreshToken", Description = "GooglePhotos authorization refresh Token", Encrypted = true)] - public string RefreshToken { - get; - set; - } + [IniProperty("UploadAlbum", Description = "The GooglePhotos album to upload to", DefaultValue = "default")] + public string UploadAlbum { get; set; } - /// - /// Not stored - /// - public string AccessToken { - get; - set; - } + [IniProperty("RefreshToken", Description = "GooglePhotos authorization refresh Token", Encrypted = true)] + public string RefreshToken { get; set; } - /// - /// Not stored - /// - public DateTimeOffset AccessTokenExpires { - get; - set; - } + /// + /// Not stored + /// + public string AccessToken { get; set; } - /// - /// A form for token - /// - /// bool true if OK was pressed, false if cancel - public bool ShowConfigDialog() { - DialogResult result = new SettingsForm().ShowDialog(); - if (result == DialogResult.OK) { - return true; - } - return false; - } + /// + /// Not stored + /// + public DateTimeOffset AccessTokenExpires { get; set; } - } -} + /// + /// A form for token + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + DialogResult result = new SettingsForm().ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs index 2948773ce..8a66faef7 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs @@ -23,33 +23,42 @@ using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace Greenshot.Plugin.GooglePhotos { - public class GooglePhotosDestination : AbstractDestination { - private readonly GooglePhotosPlugin _plugin; - public GooglePhotosDestination(GooglePhotosPlugin plugin) { - _plugin = plugin; - } - - public override string Designation => "GooglePhotos"; +namespace Greenshot.Plugin.GooglePhotos +{ + public class GooglePhotosDestination : AbstractDestination + { + private readonly GooglePhotosPlugin _plugin; - public override string Description => Language.GetString("googlephotos", LangKey.upload_menu_item); + public GooglePhotosDestination(GooglePhotosPlugin plugin) + { + _plugin = plugin; + } - public override Image DisplayIcon { - get { - ComponentResourceManager resources = new ComponentResourceManager(typeof(GooglePhotosPlugin)); - return (Image)resources.GetObject("GooglePhotos"); - } - } + public override string Designation => "GooglePhotos"; - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); + public override string Description => Language.GetString("googlephotos", LangKey.upload_menu_item); + + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(GooglePhotosPlugin)); + return (Image) resources.GetObject("GooglePhotos"); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); - if (uploaded) { - exportInformation.ExportMade = true; - exportInformation.Uri = uploadUrl; - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + if (uploaded) + { + exportInformation.ExportMade = true; + exportInformation.Uri = uploadUrl; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs index ed1727c05..91978b8ef 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs @@ -29,97 +29,113 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.GooglePhotos { - /// - /// This is the GooglePhotos base code - /// - [Plugin("GooglePhotos", true)] - public class GooglePhotosPlugin : IGreenshotPlugin { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosPlugin)); - private static GooglePhotosConfiguration _config; - private ComponentResourceManager _resources; - private ToolStripMenuItem _itemPlugInRoot; +namespace Greenshot.Plugin.GooglePhotos +{ + /// + /// This is the GooglePhotos base code + /// + [Plugin("GooglePhotos", true)] + public class GooglePhotosPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosPlugin)); + private static GooglePhotosConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInRoot; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - private void Dispose(bool disposing) - { - if (!disposing) return; - if (_itemPlugInRoot == null) return; - _itemPlugInRoot.Dispose(); - _itemPlugInRoot = null; - } + private void Dispose(bool disposing) + { + if (!disposing) return; + if (_itemPlugInRoot == null) return; + _itemPlugInRoot.Dispose(); + _itemPlugInRoot = null; + } - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - public bool Initialize() { - SimpleServiceProvider.Current.AddService(new GooglePhotosDestination(this)); + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + public bool Initialize() + { + SimpleServiceProvider.Current.AddService(new GooglePhotosDestination(this)); - // Get configuration - _config = IniConfig.GetIniSection(); - _resources = new ComponentResourceManager(typeof(GooglePhotosPlugin)); + // Get configuration + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(GooglePhotosPlugin)); - _itemPlugInRoot = new ToolStripMenuItem - { - Text = Language.GetString("googlephotos", LangKey.Configure), - Image = (Image) _resources.GetObject("GooglePhotos") - }; - _itemPlugInRoot.Click += ConfigMenuClick; - PluginUtils.AddToContextMenu(_itemPlugInRoot); - Language.LanguageChanged += OnLanguageChanged; - return true; - } + _itemPlugInRoot = new ToolStripMenuItem + { + Text = Language.GetString("googlephotos", LangKey.Configure), + Image = (Image) _resources.GetObject("GooglePhotos") + }; + _itemPlugInRoot.Click += ConfigMenuClick; + PluginUtils.AddToContextMenu(_itemPlugInRoot); + Language.LanguageChanged += OnLanguageChanged; + return true; + } - public void OnLanguageChanged(object sender, EventArgs e) { - if (_itemPlugInRoot != null) { - _itemPlugInRoot.Text = Language.GetString("googlephotos", LangKey.Configure); - } - } + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInRoot != null) + { + _itemPlugInRoot.Text = Language.GetString("googlephotos", LangKey.Configure); + } + } - public void Shutdown() { - Log.Debug("GooglePhotos Plugin shutdown."); - Language.LanguageChanged -= OnLanguageChanged; - //host.OnImageEditorOpen -= new OnImageEditorOpenHandler(ImageEditorOpened); - } + public void Shutdown() + { + Log.Debug("GooglePhotos Plugin shutdown."); + Language.LanguageChanged -= OnLanguageChanged; + //host.OnImageEditorOpen -= new OnImageEditorOpenHandler(ImageEditorOpened); + } - /// - /// Implementation of the IPlugin.Configure - /// - public void Configure() { - _config.ShowConfigDialog(); - } + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + _config.ShowConfigDialog(); + } - public void ConfigMenuClick(object sender, EventArgs eventArgs) { - Configure(); - } + public void ConfigMenuClick(object sender, EventArgs eventArgs) + { + Configure(); + } - public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality); - try { - string url = null; - new PleaseWaitForm().ShowAndWait("GooglePhotos", Language.GetString("googlephotos", LangKey.communication_wait), - delegate - { - string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); - url = GooglePhotosUtils.UploadToGooglePhotos(surfaceToUpload, outputSettings, captureDetails.Title, filename); - } - ); - uploadUrl = url; + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality); + try + { + string url = null; + new PleaseWaitForm().ShowAndWait("GooglePhotos", Language.GetString("googlephotos", LangKey.communication_wait), + delegate + { + string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); + url = GooglePhotosUtils.UploadToGooglePhotos(surfaceToUpload, outputSettings, captureDetails.Title, filename); + } + ); + uploadUrl = url; - if (uploadUrl != null && _config.AfterUploadLinkToClipBoard) { - ClipboardHelper.SetClipboardData(uploadUrl); - } - return true; - } catch (Exception e) { - Log.Error("Error uploading.", e); - MessageBox.Show(Language.GetString("googlephotos", LangKey.upload_failure) + " " + e.Message); - } - uploadUrl = null; - return false; - } - } -} + if (uploadUrl != null && _config.AfterUploadLinkToClipBoard) + { + ClipboardHelper.SetClipboardData(uploadUrl); + } + + return true; + } + catch (Exception e) + { + Log.Error("Error uploading.", e); + MessageBox.Show(Language.GetString("googlephotos", LangKey.upload_failure) + " " + e.Message); + } + + uploadUrl = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs index a11edf090..2b4638839 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs @@ -26,95 +26,118 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.GooglePhotos { - /// - /// Description of GooglePhotosUtils. - /// - public static class GooglePhotosUtils { - private const string GooglePhotosScope = "https://picasaweb.google.com/data/"; - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosUtils)); - private static readonly GooglePhotosConfiguration Config = IniConfig.GetIniSection(); - private const string AuthUrl = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}&scope=" + GooglePhotosScope; - private const string TokenUrl = "https://www.googleapis.com/oauth2/v3/token"; - private const string UploadUrl = "https://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}"; +namespace Greenshot.Plugin.GooglePhotos +{ + /// + /// Description of GooglePhotosUtils. + /// + public static class GooglePhotosUtils + { + private const string GooglePhotosScope = "https://picasaweb.google.com/data/"; + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosUtils)); + private static readonly GooglePhotosConfiguration Config = IniConfig.GetIniSection(); - /// - /// Do the actual upload to GooglePhotos - /// - /// Image to upload - /// SurfaceOutputSettings - /// string - /// string - /// GooglePhotosResponse - public static string UploadToGooglePhotos(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) { - // Fill the OAuth2Settings - var settings = new OAuth2Settings - { - AuthUrlPattern = AuthUrl, - TokenUrl = TokenUrl, - CloudServiceName = "GooglePhotos", - ClientId = GooglePhotosCredentials.ClientId, - ClientSecret = GooglePhotosCredentials.ClientSecret, - AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, - RefreshToken = Config.RefreshToken, - AccessToken = Config.AccessToken, - AccessTokenExpires = Config.AccessTokenExpires - }; + private const string AuthUrl = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}&scope=" + + GooglePhotosScope; - // Copy the settings from the config, which is kept in memory and on the disk + private const string TokenUrl = "https://www.googleapis.com/oauth2/v3/token"; + private const string UploadUrl = "https://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}"; - try { - var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum), settings); - if (Config.AddFilename) { - webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename)); - } - SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename); - container.Upload(webRequest); - - string response = NetworkHelper.GetResponseAsString(webRequest); + /// + /// Do the actual upload to GooglePhotos + /// + /// Image to upload + /// SurfaceOutputSettings + /// string + /// string + /// GooglePhotosResponse + public static string UploadToGooglePhotos(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) + { + // Fill the OAuth2Settings + var settings = new OAuth2Settings + { + AuthUrlPattern = AuthUrl, + TokenUrl = TokenUrl, + CloudServiceName = "GooglePhotos", + ClientId = GooglePhotosCredentials.ClientId, + ClientSecret = GooglePhotosCredentials.ClientSecret, + AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, + RefreshToken = Config.RefreshToken, + AccessToken = Config.AccessToken, + AccessTokenExpires = Config.AccessTokenExpires + }; - return ParseResponse(response); - } finally { - // Copy the settings back to the config, so they are stored. - Config.RefreshToken = settings.RefreshToken; - Config.AccessToken = settings.AccessToken; - Config.AccessTokenExpires = settings.AccessTokenExpires; - Config.IsDirty = true; - IniConfig.Save(); - } - } - - /// - /// Parse the upload URL from the response - /// - /// - /// - public static string ParseResponse(string response) { - if (response == null) { - return null; - } - try { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(response); - XmlNodeList nodes = doc.GetElementsByTagName("link", "*"); - if(nodes.Count > 0) { - string url = null; - foreach(XmlNode node in nodes) { - if (node.Attributes != null) { - url = node.Attributes["href"].Value; - string rel = node.Attributes["rel"].Value; - // Pictures with rel="http://schemas.google.com/photos/2007#canonical" are the direct link - if (rel != null && rel.EndsWith("canonical")) { - break; - } - } - } - return url; - } - } catch(Exception e) { - Log.ErrorFormat("Could not parse GooglePhotos response due to error {0}, response was: {1}", e.Message, response); - } - return null; - } - } -} + // Copy the settings from the config, which is kept in memory and on the disk + + try + { + var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum), settings); + if (Config.AddFilename) + { + webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename)); + } + + SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename); + container.Upload(webRequest); + + string response = NetworkHelper.GetResponseAsString(webRequest); + + return ParseResponse(response); + } + finally + { + // Copy the settings back to the config, so they are stored. + Config.RefreshToken = settings.RefreshToken; + Config.AccessToken = settings.AccessToken; + Config.AccessTokenExpires = settings.AccessTokenExpires; + Config.IsDirty = true; + IniConfig.Save(); + } + } + + /// + /// Parse the upload URL from the response + /// + /// + /// + public static string ParseResponse(string response) + { + if (response == null) + { + return null; + } + + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + XmlNodeList nodes = doc.GetElementsByTagName("link", "*"); + if (nodes.Count > 0) + { + string url = null; + foreach (XmlNode node in nodes) + { + if (node.Attributes != null) + { + url = node.Attributes["href"].Value; + string rel = node.Attributes["rel"].Value; + // Pictures with rel="http://schemas.google.com/photos/2007#canonical" are the direct link + if (rel != null && rel.EndsWith("canonical")) + { + break; + } + } + } + + return url; + } + } + catch (Exception e) + { + Log.ErrorFormat("Could not parse GooglePhotos response due to error {0}, response was: {1}", e.Message, response); + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs b/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs index 34feda885..7eaab1020 100644 --- a/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs +++ b/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs @@ -18,12 +18,13 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.GooglePhotos { - public enum LangKey - { - upload_menu_item, - upload_failure, - communication_wait, - Configure - } -} +namespace Greenshot.Plugin.GooglePhotos +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + Configure + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs index d4fa2878a..d04662538 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs index c4fb88791..c94f6d1eb 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs @@ -21,10 +21,12 @@ using GreenshotPlugin.Controls; -namespace Greenshot.Plugin.Imgur.Forms { - /// - /// This class is needed for design-time resolving of the language files - /// - public class ImgurForm : GreenshotForm { - } -} +namespace Greenshot.Plugin.Imgur.Forms +{ + /// + /// This class is needed for design-time resolving of the language files + /// + public class ImgurForm : GreenshotForm + { + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs index 3b2efcd48..417f5e7d5 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs @@ -27,195 +27,237 @@ using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Imgur.Forms { - /// - /// Imgur history form - /// - public sealed partial class ImgurHistory : ImgurForm { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurHistory)); - private readonly GreenshotColumnSorter _columnSorter; - private static readonly object Lock = new object(); - private static readonly ImgurConfiguration Config = IniConfig.GetIniSection(); - private static ImgurHistory _instance; - - public static void ShowHistory() { - lock (Lock) - { - if (ImgurUtils.IsHistoryLoadingNeeded()) - { - // Run upload in the background - new PleaseWaitForm().ShowAndWait("Imgur " + Language.GetString("imgur", LangKey.history), Language.GetString("imgur", LangKey.communication_wait), - ImgurUtils.LoadHistory - ); - } +namespace Greenshot.Plugin.Imgur.Forms +{ + /// + /// Imgur history form + /// + public sealed partial class ImgurHistory : ImgurForm + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurHistory)); + private readonly GreenshotColumnSorter _columnSorter; + private static readonly object Lock = new object(); + private static readonly ImgurConfiguration Config = IniConfig.GetIniSection(); + private static ImgurHistory _instance; - // Make sure the history is loaded, will be done only once - if (_instance == null) - { - _instance = new ImgurHistory(); - } - if (!_instance.Visible) - { - _instance.Show(); - } - _instance.Redraw(); - } - } - - private ImgurHistory() { - ManualLanguageApply = true; - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - AcceptButton = finishedButton; - CancelButton = finishedButton; - // Init sorting - _columnSorter = new GreenshotColumnSorter(); - listview_imgur_uploads.ListViewItemSorter = _columnSorter; - _columnSorter.SortColumn = 3; - _columnSorter.Order = SortOrder.Descending; - Redraw(); - if (listview_imgur_uploads.Items.Count > 0) { - listview_imgur_uploads.Items[0].Selected = true; - } - ApplyLanguage(); - if (Config.Credits > 0) { - Text = Text + " (" + Config.Credits + " credits)"; - } - } + public static void ShowHistory() + { + lock (Lock) + { + if (ImgurUtils.IsHistoryLoadingNeeded()) + { + // Run upload in the background + new PleaseWaitForm().ShowAndWait("Imgur " + Language.GetString("imgur", LangKey.history), Language.GetString("imgur", LangKey.communication_wait), + ImgurUtils.LoadHistory + ); + } - private void Redraw() { - // Should fix Bug #3378699 - pictureBox1.Image = pictureBox1.ErrorImage; - listview_imgur_uploads.BeginUpdate(); - listview_imgur_uploads.Items.Clear(); - listview_imgur_uploads.Columns.Clear(); - string[] columns = { "hash", "title", "deleteHash", "Date"}; - foreach (string column in columns) { - listview_imgur_uploads.Columns.Add(column); - } - foreach (ImgurInfo imgurInfo in Config.runtimeImgurHistory.Values) { - var item = new ListViewItem(imgurInfo.Hash) - { - Tag = imgurInfo - }; - item.SubItems.Add(imgurInfo.Title); - item.SubItems.Add(imgurInfo.DeleteHash); - item.SubItems.Add(imgurInfo.Timestamp.ToString("yyyy-MM-dd HH:mm:ss", DateTimeFormatInfo.InvariantInfo)); - listview_imgur_uploads.Items.Add(item); - } - for (int i = 0; i < columns.Length; i++) { - listview_imgur_uploads.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent); - } - - listview_imgur_uploads.EndUpdate(); - listview_imgur_uploads.Refresh(); - deleteButton.Enabled = false; - openButton.Enabled = false; - clipboardButton.Enabled = false; - } + // Make sure the history is loaded, will be done only once + if (_instance == null) + { + _instance = new ImgurHistory(); + } - private void Listview_imgur_uploadsSelectedIndexChanged(object sender, EventArgs e) { - pictureBox1.Image = pictureBox1.ErrorImage; - if (listview_imgur_uploads.SelectedItems.Count > 0) { - deleteButton.Enabled = true; - openButton.Enabled = true; - clipboardButton.Enabled = true; - if (listview_imgur_uploads.SelectedItems.Count == 1) { - ImgurInfo imgurInfo = (ImgurInfo)listview_imgur_uploads.SelectedItems[0].Tag; - pictureBox1.Image = imgurInfo.Image; - } - } else { - pictureBox1.Image = pictureBox1.ErrorImage; - deleteButton.Enabled = false; - openButton.Enabled = false; - clipboardButton.Enabled = false; - } - } + if (!_instance.Visible) + { + _instance.Show(); + } - private void DeleteButtonClick(object sender, EventArgs e) { - if (listview_imgur_uploads.SelectedItems.Count > 0) { - for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) { - ImgurInfo imgurInfo = (ImgurInfo)listview_imgur_uploads.SelectedItems[i].Tag; - DialogResult result = MessageBox.Show(Language.GetFormattedString("imgur", LangKey.delete_question, imgurInfo.Title), Language.GetFormattedString("imgur", LangKey.delete_title, imgurInfo.Hash), MessageBoxButtons.YesNo, MessageBoxIcon.Question); - if (result != DialogResult.Yes) - { - continue; - } - // Should fix Bug #3378699 - pictureBox1.Image = pictureBox1.ErrorImage; - try { - new PleaseWaitForm().ShowAndWait("Imgur", Language.GetString("imgur", LangKey.communication_wait), - delegate { - ImgurUtils.DeleteImgurImage(imgurInfo); - } - ); - } catch (Exception ex) { - Log.Warn("Problem communicating with Imgur: ", ex); - } + _instance.Redraw(); + } + } - imgurInfo.Dispose(); - } - } - Redraw(); - } + private ImgurHistory() + { + ManualLanguageApply = true; + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = finishedButton; + CancelButton = finishedButton; + // Init sorting + _columnSorter = new GreenshotColumnSorter(); + listview_imgur_uploads.ListViewItemSorter = _columnSorter; + _columnSorter.SortColumn = 3; + _columnSorter.Order = SortOrder.Descending; + Redraw(); + if (listview_imgur_uploads.Items.Count > 0) + { + listview_imgur_uploads.Items[0].Selected = true; + } - private void ClipboardButtonClick(object sender, EventArgs e) { - StringBuilder links = new StringBuilder(); - if (listview_imgur_uploads.SelectedItems.Count > 0) { - for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) - { - ImgurInfo imgurInfo = (ImgurInfo)listview_imgur_uploads.SelectedItems[i].Tag; - links.AppendLine(Config.UsePageLink ? imgurInfo.Page : imgurInfo.Original); - } - } - ClipboardHelper.SetClipboardData(links.ToString()); - } + ApplyLanguage(); + if (Config.Credits > 0) + { + Text = Text + " (" + Config.Credits + " credits)"; + } + } - private void ClearHistoryButtonClick(object sender, EventArgs e) { - DialogResult result = MessageBox.Show(Language.GetString("imgur", LangKey.clear_question), "Imgur", MessageBoxButtons.YesNo, MessageBoxIcon.Question); - if (result == DialogResult.Yes) { - Config.runtimeImgurHistory.Clear(); - Config.ImgurUploadHistory.Clear(); - IniConfig.Save(); - Redraw(); - } - } + private void Redraw() + { + // Should fix Bug #3378699 + pictureBox1.Image = pictureBox1.ErrorImage; + listview_imgur_uploads.BeginUpdate(); + listview_imgur_uploads.Items.Clear(); + listview_imgur_uploads.Columns.Clear(); + string[] columns = + { + "hash", "title", "deleteHash", "Date" + }; + foreach (string column in columns) + { + listview_imgur_uploads.Columns.Add(column); + } - private void FinishedButtonClick(object sender, EventArgs e) - { - Hide(); - } + foreach (ImgurInfo imgurInfo in Config.runtimeImgurHistory.Values) + { + var item = new ListViewItem(imgurInfo.Hash) + { + Tag = imgurInfo + }; + item.SubItems.Add(imgurInfo.Title); + item.SubItems.Add(imgurInfo.DeleteHash); + item.SubItems.Add(imgurInfo.Timestamp.ToString("yyyy-MM-dd HH:mm:ss", DateTimeFormatInfo.InvariantInfo)); + listview_imgur_uploads.Items.Add(item); + } - private void OpenButtonClick(object sender, EventArgs e) { - if (listview_imgur_uploads.SelectedItems.Count > 0) { - for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) { - ImgurInfo imgurInfo = (ImgurInfo)listview_imgur_uploads.SelectedItems[i].Tag; - System.Diagnostics.Process.Start(imgurInfo.Page); - } - } - } - - private void listview_imgur_uploads_ColumnClick(object sender, ColumnClickEventArgs e) { - // Determine if clicked column is already the column that is being sorted. - if (e.Column == _columnSorter.SortColumn) { - // Reverse the current sort direction for this column. - _columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; - } else { - // Set the column number that is to be sorted; default to ascending. - _columnSorter.SortColumn = e.Column; - _columnSorter.Order = SortOrder.Ascending; - } + for (int i = 0; i < columns.Length; i++) + { + listview_imgur_uploads.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent); + } - // Perform the sort with these new sort options. - listview_imgur_uploads.Sort(); - } + listview_imgur_uploads.EndUpdate(); + listview_imgur_uploads.Refresh(); + deleteButton.Enabled = false; + openButton.Enabled = false; + clipboardButton.Enabled = false; + } + + private void Listview_imgur_uploadsSelectedIndexChanged(object sender, EventArgs e) + { + pictureBox1.Image = pictureBox1.ErrorImage; + if (listview_imgur_uploads.SelectedItems.Count > 0) + { + deleteButton.Enabled = true; + openButton.Enabled = true; + clipboardButton.Enabled = true; + if (listview_imgur_uploads.SelectedItems.Count == 1) + { + ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[0].Tag; + pictureBox1.Image = imgurInfo.Image; + } + } + else + { + pictureBox1.Image = pictureBox1.ErrorImage; + deleteButton.Enabled = false; + openButton.Enabled = false; + clipboardButton.Enabled = false; + } + } + + private void DeleteButtonClick(object sender, EventArgs e) + { + if (listview_imgur_uploads.SelectedItems.Count > 0) + { + for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) + { + ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag; + DialogResult result = MessageBox.Show(Language.GetFormattedString("imgur", LangKey.delete_question, imgurInfo.Title), + Language.GetFormattedString("imgur", LangKey.delete_title, imgurInfo.Hash), MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (result != DialogResult.Yes) + { + continue; + } + + // Should fix Bug #3378699 + pictureBox1.Image = pictureBox1.ErrorImage; + try + { + new PleaseWaitForm().ShowAndWait("Imgur", Language.GetString("imgur", LangKey.communication_wait), + delegate { ImgurUtils.DeleteImgurImage(imgurInfo); } + ); + } + catch (Exception ex) + { + Log.Warn("Problem communicating with Imgur: ", ex); + } + + imgurInfo.Dispose(); + } + } + + Redraw(); + } + + private void ClipboardButtonClick(object sender, EventArgs e) + { + StringBuilder links = new StringBuilder(); + if (listview_imgur_uploads.SelectedItems.Count > 0) + { + for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) + { + ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag; + links.AppendLine(Config.UsePageLink ? imgurInfo.Page : imgurInfo.Original); + } + } + + ClipboardHelper.SetClipboardData(links.ToString()); + } + + private void ClearHistoryButtonClick(object sender, EventArgs e) + { + DialogResult result = MessageBox.Show(Language.GetString("imgur", LangKey.clear_question), "Imgur", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (result == DialogResult.Yes) + { + Config.runtimeImgurHistory.Clear(); + Config.ImgurUploadHistory.Clear(); + IniConfig.Save(); + Redraw(); + } + } + + private void FinishedButtonClick(object sender, EventArgs e) + { + Hide(); + } + + private void OpenButtonClick(object sender, EventArgs e) + { + if (listview_imgur_uploads.SelectedItems.Count > 0) + { + for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) + { + ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag; + System.Diagnostics.Process.Start(imgurInfo.Page); + } + } + } + + private void listview_imgur_uploads_ColumnClick(object sender, ColumnClickEventArgs e) + { + // Determine if clicked column is already the column that is being sorted. + if (e.Column == _columnSorter.SortColumn) + { + // Reverse the current sort direction for this column. + _columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; + } + else + { + // Set the column number that is to be sorted; default to ascending. + _columnSorter.SortColumn = e.Column; + _columnSorter.Order = SortOrder.Ascending; + } + + // Perform the sort with these new sort options. + listview_imgur_uploads.Sort(); + } - private void ImgurHistoryFormClosing(object sender, FormClosingEventArgs e) - { - _instance = null; - } - } -} + private void ImgurHistoryFormClosing(object sender, FormClosingEventArgs e) + { + _instance = null; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs index 1ece15fb9..4958f897c 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs @@ -21,25 +21,28 @@ using System; -namespace Greenshot.Plugin.Imgur.Forms { - /// - /// Description of PasswordRequestForm. - /// - public partial class SettingsForm : ImgurForm { - public SettingsForm() - { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - CancelButton = buttonCancel; - AcceptButton = buttonOK; - - historyButton.Enabled = ImgurUtils.IsHistoryLoadingNeeded(); - } +namespace Greenshot.Plugin.Imgur.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : ImgurForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + CancelButton = buttonCancel; + AcceptButton = buttonOK; - private void ButtonHistoryClick(object sender, EventArgs e) { - ImgurHistory.ShowHistory(); - } - } -} + historyButton.Enabled = ImgurUtils.IsHistoryLoadingNeeded(); + } + + private void ButtonHistoryClick(object sender, EventArgs e) + { + ImgurHistory.ShowHistory(); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs index e9725a2d2..fdac54ee3 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs @@ -26,64 +26,70 @@ using Greenshot.Plugin.Imgur.Forms; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Imgur { - /// - /// Description of ImgurConfiguration. - /// - [IniSection("Imgur", Description="Greenshot Imgur Plugin configuration")] - public class ImgurConfiguration : IniSection { - [IniProperty("ImgurApi3Url", Description = "Url to Imgur system.", DefaultValue = "https://api.imgur.com/3")] - public string ImgurApi3Url { get; set; } +namespace Greenshot.Plugin.Imgur +{ + /// + /// Description of ImgurConfiguration. + /// + [IniSection("Imgur", Description = "Greenshot Imgur Plugin configuration")] + public class ImgurConfiguration : IniSection + { + [IniProperty("ImgurApi3Url", Description = "Url to Imgur system.", DefaultValue = "https://api.imgur.com/3")] + public string ImgurApi3Url { get; set; } - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat { get; set; } - [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality { get; set; } - [IniProperty("UploadReduceColors", Description="Reduce color amount of the uploaded image to 256", DefaultValue="False")] - public bool UploadReduceColors { get; set; } - [IniProperty("CopyLinkToClipboard", Description = "Copy the link, which one is controlled by the UsePageLink, on the clipboard", DefaultValue = "True")] - public bool CopyLinkToClipboard { get; set; } - [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] - public bool UsePageLink { get; set; } - [IniProperty("AnonymousAccess", Description = "Use anonymous access to Imgur", DefaultValue="true")] - public bool AnonymousAccess { get; set; } + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } - [IniProperty("RefreshToken", Description = "Imgur refresh Token", Encrypted = true, ExcludeIfNull = true)] - public string RefreshToken { get; set; } + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } - /// - /// AccessToken, not stored - /// - public string AccessToken { get; set; } + [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] + public bool UploadReduceColors { get; set; } - /// - /// AccessTokenExpires, not stored - /// - public DateTimeOffset AccessTokenExpires { get; set; } + [IniProperty("CopyLinkToClipboard", Description = "Copy the link, which one is controlled by the UsePageLink, on the clipboard", DefaultValue = "True")] + public bool CopyLinkToClipboard { get; set; } - [IniProperty("AddTitle", Description = "Is the title passed on to Imgur", DefaultValue = "False")] - public bool AddTitle { get; set; } - [IniProperty("AddFilename", Description = "Is the filename passed on to Imgur", DefaultValue = "False")] - public bool AddFilename { get; set; } - [IniProperty("FilenamePattern", Description = "Filename for the Imgur upload", DefaultValue = "${capturetime:d\"yyyyMMdd-HHmm\"}")] - public string FilenamePattern { get; set; } + [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] + public bool UsePageLink { get; set; } - [IniProperty("ImgurUploadHistory", Description="Imgur upload history (ImgurUploadHistory.hash=deleteHash)")] - public Dictionary ImgurUploadHistory { get; set; } + [IniProperty("AnonymousAccess", Description = "Use anonymous access to Imgur", DefaultValue = "true")] + public bool AnonymousAccess { get; set; } - // Not stored, only run-time! - public Dictionary runtimeImgurHistory = new Dictionary(); - public int Credits { - get; - set; - } + [IniProperty("RefreshToken", Description = "Imgur refresh Token", Encrypted = true, ExcludeIfNull = true)] + public string RefreshToken { get; set; } - /// - /// Supply values we can't put as defaults - /// - /// The property to return a default for - /// object with the default value for the supplied property - public override object GetDefault(string property) => + /// + /// AccessToken, not stored + /// + public string AccessToken { get; set; } + + /// + /// AccessTokenExpires, not stored + /// + public DateTimeOffset AccessTokenExpires { get; set; } + + [IniProperty("AddTitle", Description = "Is the title passed on to Imgur", DefaultValue = "False")] + public bool AddTitle { get; set; } + + [IniProperty("AddFilename", Description = "Is the filename passed on to Imgur", DefaultValue = "False")] + public bool AddFilename { get; set; } + + [IniProperty("FilenamePattern", Description = "Filename for the Imgur upload", DefaultValue = "${capturetime:d\"yyyyMMdd-HHmm\"}")] + public string FilenamePattern { get; set; } + + [IniProperty("ImgurUploadHistory", Description = "Imgur upload history (ImgurUploadHistory.hash=deleteHash)")] + public Dictionary ImgurUploadHistory { get; set; } + + // Not stored, only run-time! + public Dictionary runtimeImgurHistory = new Dictionary(); + public int Credits { get; set; } + + /// + /// Supply values we can't put as defaults + /// + /// The property to return a default for + /// object with the default value for the supplied property + public override object GetDefault(string property) => property switch { "ImgurUploadHistory" => new Dictionary(), @@ -91,13 +97,14 @@ namespace Greenshot.Plugin.Imgur { }; /// - /// A form for username/password - /// - /// bool true if OK was pressed, false if cancel - public bool ShowConfigDialog() { - SettingsForm settingsForm = new SettingsForm(); - DialogResult result = settingsForm.ShowDialog(); - return result == DialogResult.OK; - } - } -} + /// A form for username/password + ///
+ /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + SettingsForm settingsForm = new SettingsForm(); + DialogResult result = settingsForm.ShowDialog(); + return result == DialogResult.OK; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/ImgurDestination.cs b/src/Greenshot.Plugin.Imgur/ImgurDestination.cs index aa24ad68c..a0d069f1a 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurDestination.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurDestination.cs @@ -24,35 +24,42 @@ using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace Greenshot.Plugin.Imgur { - /// - /// Description of ImgurDestination. - /// - public class ImgurDestination : AbstractDestination { - private readonly ImgurPlugin _plugin; +namespace Greenshot.Plugin.Imgur +{ + /// + /// Description of ImgurDestination. + /// + public class ImgurDestination : AbstractDestination + { + private readonly ImgurPlugin _plugin; - public ImgurDestination(ImgurPlugin plugin) { - _plugin = plugin; - } - - public override string Designation => "Imgur"; + public ImgurDestination(ImgurPlugin plugin) + { + _plugin = plugin; + } - public override string Description => Language.GetString("imgur", LangKey.upload_menu_item); + public override string Designation => "Imgur"; - public override Image DisplayIcon { - get { - ComponentResourceManager resources = new ComponentResourceManager(typeof(ImgurPlugin)); - return (Image)resources.GetObject("Imgur"); - } - } + public override string Description => Language.GetString("imgur", LangKey.upload_menu_item); - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(ImgurPlugin)); + return (Image) resources.GetObject("Imgur"); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { ExportInformation exportInformation = new ExportInformation(Designation, Description) { - ExportMade = _plugin.Upload(captureDetails, surface, out var uploadUrl), Uri = uploadUrl + ExportMade = _plugin.Upload(captureDetails, surface, out var uploadUrl), + Uri = uploadUrl }; ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/ImgurInfo.cs b/src/Greenshot.Plugin.Imgur/ImgurInfo.cs index 5dc82ec2a..4fdfb7a86 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurInfo.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurInfo.cs @@ -25,194 +25,172 @@ using System.Xml; namespace Greenshot.Plugin.Imgur { - /// - /// Description of ImgurInfo. - /// - public class ImgurInfo : IDisposable - { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurInfo)); + /// + /// Description of ImgurInfo. + /// + public class ImgurInfo : IDisposable + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurInfo)); - public string Hash - { - get; - set; - } + public string Hash { get; set; } - private string _deleteHash; - public string DeleteHash - { - get { return _deleteHash; } - set - { - _deleteHash = value; - DeletePage = "https://imgur.com/delete/" + value; - } - } + private string _deleteHash; - public string Title - { - get; - set; - } + public string DeleteHash + { + get { return _deleteHash; } + set + { + _deleteHash = value; + DeletePage = "https://imgur.com/delete/" + value; + } + } - public string ImageType - { - get; - set; - } + public string Title { get; set; } - public DateTime Timestamp - { - get; - set; - } + public string ImageType { get; set; } - public string Original - { - get; - set; - } + public DateTime Timestamp { get; set; } - public string Page - { - get; - set; - } + public string Original { get; set; } - public string SmallSquare - { - get; - set; - } + public string Page { get; set; } - public string LargeThumbnail - { - get; - set; - } + public string SmallSquare { get; set; } - public string DeletePage - { - get; - set; - } + public string LargeThumbnail { get; set; } - private Image _image; - public Image Image - { - get { return _image; } - set - { - _image?.Dispose(); - _image = value; - } - } + public string DeletePage { get; set; } - /// - /// The public accessible Dispose - /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + private Image _image; - /// - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _image?.Dispose(); - } - _image = null; - } - public static ImgurInfo ParseResponse(string response) - { - Log.Debug(response); - // This is actually a hack for BUG-1695 - // The problem is the (C) sign, we send it HTML encoded "®" to Imgur and get it HTML encoded in the XML back - // Added all the encodings I found quickly, I guess these are not all... but it should fix the issue for now. - response = response.Replace("¢", "¢"); - response = response.Replace("£", "£"); - response = response.Replace("¥", "¥"); - response = response.Replace("€", "€"); - response = response.Replace("©", "©"); - response = response.Replace("®", "®"); + public Image Image + { + get { return _image; } + set + { + _image?.Dispose(); + _image = value; + } + } - ImgurInfo imgurInfo = new ImgurInfo(); - try - { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(response); - XmlNodeList nodes = doc.GetElementsByTagName("id"); - if (nodes.Count > 0) - { - imgurInfo.Hash = nodes.Item(0)?.InnerText; - } - nodes = doc.GetElementsByTagName("hash"); - if (nodes.Count > 0) - { - imgurInfo.Hash = nodes.Item(0)?.InnerText; - } - nodes = doc.GetElementsByTagName("deletehash"); - if (nodes.Count > 0) - { - imgurInfo.DeleteHash = nodes.Item(0)?.InnerText; - } - nodes = doc.GetElementsByTagName("type"); - if (nodes.Count > 0) - { - imgurInfo.ImageType = nodes.Item(0)?.InnerText; - } - nodes = doc.GetElementsByTagName("title"); - if (nodes.Count > 0) - { - imgurInfo.Title = nodes.Item(0)?.InnerText; - } - nodes = doc.GetElementsByTagName("datetime"); - if (nodes.Count > 0) - { - // Version 3 has seconds since Epoch + /// + /// The public accessible Dispose + /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _image?.Dispose(); + } + + _image = null; + } + + public static ImgurInfo ParseResponse(string response) + { + Log.Debug(response); + // This is actually a hack for BUG-1695 + // The problem is the (C) sign, we send it HTML encoded "®" to Imgur and get it HTML encoded in the XML back + // Added all the encodings I found quickly, I guess these are not all... but it should fix the issue for now. + response = response.Replace("¢", "¢"); + response = response.Replace("£", "£"); + response = response.Replace("¥", "¥"); + response = response.Replace("€", "€"); + response = response.Replace("©", "©"); + response = response.Replace("®", "®"); + + ImgurInfo imgurInfo = new ImgurInfo(); + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + XmlNodeList nodes = doc.GetElementsByTagName("id"); + if (nodes.Count > 0) + { + imgurInfo.Hash = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("hash"); + if (nodes.Count > 0) + { + imgurInfo.Hash = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("deletehash"); + if (nodes.Count > 0) + { + imgurInfo.DeleteHash = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("type"); + if (nodes.Count > 0) + { + imgurInfo.ImageType = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("title"); + if (nodes.Count > 0) + { + imgurInfo.Title = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("datetime"); + if (nodes.Count > 0) + { + // Version 3 has seconds since Epoch if (double.TryParse(nodes.Item(0)?.InnerText, out var secondsSince)) - { - var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); - imgurInfo.Timestamp = epoch.AddSeconds(secondsSince).DateTime; - } - } - nodes = doc.GetElementsByTagName("original"); - if (nodes.Count > 0) - { - imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:"); - } - // Version 3 API only has Link - nodes = doc.GetElementsByTagName("link"); - if (nodes.Count > 0) - { - imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:"); - } - nodes = doc.GetElementsByTagName("imgur_page"); - if (nodes.Count > 0) - { - imgurInfo.Page = nodes.Item(0)?.InnerText.Replace("http:", "https:"); - } - else - { - // Version 3 doesn't have a page link in the response - imgurInfo.Page = $"https://imgur.com/{imgurInfo.Hash}"; - } - nodes = doc.GetElementsByTagName("small_square"); - imgurInfo.SmallSquare = nodes.Count > 0 ? nodes.Item(0)?.InnerText : $"http://i.imgur.com/{imgurInfo.Hash}s.png"; - } - catch (Exception e) - { - Log.ErrorFormat("Could not parse Imgur response due to error {0}, response was: {1}", e.Message, response); - } - return imgurInfo; - } - } -} + { + var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + imgurInfo.Timestamp = epoch.AddSeconds(secondsSince).DateTime; + } + } + + nodes = doc.GetElementsByTagName("original"); + if (nodes.Count > 0) + { + imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:"); + } + + // Version 3 API only has Link + nodes = doc.GetElementsByTagName("link"); + if (nodes.Count > 0) + { + imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:"); + } + + nodes = doc.GetElementsByTagName("imgur_page"); + if (nodes.Count > 0) + { + imgurInfo.Page = nodes.Item(0)?.InnerText.Replace("http:", "https:"); + } + else + { + // Version 3 doesn't have a page link in the response + imgurInfo.Page = $"https://imgur.com/{imgurInfo.Hash}"; + } + + nodes = doc.GetElementsByTagName("small_square"); + imgurInfo.SmallSquare = nodes.Count > 0 ? nodes.Item(0)?.InnerText : $"http://i.imgur.com/{imgurInfo.Hash}s.png"; + } + catch (Exception e) + { + Log.ErrorFormat("Could not parse Imgur response due to error {0}, response was: {1}", e.Message, response); + } + + return imgurInfo; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs index ef2edfe4b..a936c80d7 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs @@ -32,186 +32,216 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Imgur { - /// - /// This is the ImgurPlugin code - /// +namespace Greenshot.Plugin.Imgur +{ + /// + /// This is the ImgurPlugin code + /// [Plugin("Imgur", true)] - public class ImgurPlugin : IGreenshotPlugin { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurPlugin)); - private static ImgurConfiguration _config; - private ComponentResourceManager _resources; - private ToolStripMenuItem _historyMenuItem; - private ToolStripMenuItem _itemPlugInConfig; + public class ImgurPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurPlugin)); + private static ImgurConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _historyMenuItem; + private ToolStripMenuItem _itemPlugInConfig; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected virtual void Dispose(bool disposing) { - if (disposing) { - if (_historyMenuItem != null) { - _historyMenuItem.Dispose(); - _historyMenuItem = null; - } - if (_itemPlugInConfig != null) { - _itemPlugInConfig.Dispose(); - _itemPlugInConfig = null; - } - } - } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (_historyMenuItem != null) + { + _historyMenuItem.Dispose(); + _historyMenuItem = null; + } - private IEnumerable Destinations() { - yield return new ImgurDestination(this); - } + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; + } + } + } - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - /// true if plugin is initialized, false if not (doesn't show) - public bool Initialize() { - // Get configuration - _config = IniConfig.GetIniSection(); - _resources = new ComponentResourceManager(typeof(ImgurPlugin)); + private IEnumerable Destinations() + { + yield return new ImgurDestination(this); + } - ToolStripMenuItem itemPlugInRoot = new ToolStripMenuItem("Imgur") - { - Image = (Image) _resources.GetObject("Imgur") - }; + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// true if plugin is initialized, false if not (doesn't show) + public bool Initialize() + { + // Get configuration + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(ImgurPlugin)); + + ToolStripMenuItem itemPlugInRoot = new ToolStripMenuItem("Imgur") + { + Image = (Image) _resources.GetObject("Imgur") + }; // Provide the IDestination SimpleServiceProvider.Current.AddService(Destinations()); _historyMenuItem = new ToolStripMenuItem(Language.GetString("imgur", LangKey.history)); - _historyMenuItem.Click += delegate { - ImgurHistory.ShowHistory(); - }; - itemPlugInRoot.DropDownItems.Add(_historyMenuItem); + _historyMenuItem.Click += delegate { ImgurHistory.ShowHistory(); }; + itemPlugInRoot.DropDownItems.Add(_historyMenuItem); _itemPlugInConfig = new ToolStripMenuItem(Language.GetString("imgur", LangKey.configure)); - _itemPlugInConfig.Click += delegate { - _config.ShowConfigDialog(); - }; - itemPlugInRoot.DropDownItems.Add(_itemPlugInConfig); + _itemPlugInConfig.Click += delegate { _config.ShowConfigDialog(); }; + itemPlugInRoot.DropDownItems.Add(_itemPlugInConfig); - PluginUtils.AddToContextMenu(itemPlugInRoot); - Language.LanguageChanged += OnLanguageChanged; + PluginUtils.AddToContextMenu(itemPlugInRoot); + Language.LanguageChanged += OnLanguageChanged; - // Enable history if there are items available - UpdateHistoryMenuItem(); - return true; - } + // Enable history if there are items available + UpdateHistoryMenuItem(); + return true; + } - public void OnLanguageChanged(object sender, EventArgs e) { - if (_itemPlugInConfig != null) { - _itemPlugInConfig.Text = Language.GetString("imgur", LangKey.configure); - } - if (_historyMenuItem != null) { - _historyMenuItem.Text = Language.GetString("imgur", LangKey.history); - } - } + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Text = Language.GetString("imgur", LangKey.configure); + } - private void UpdateHistoryMenuItem() { - if (_historyMenuItem == null) - { - return; - } - try + if (_historyMenuItem != null) + { + _historyMenuItem.Text = Language.GetString("imgur", LangKey.history); + } + } + + private void UpdateHistoryMenuItem() + { + if (_historyMenuItem == null) + { + return; + } + + try { var form = SimpleServiceProvider.Current.GetInstance
(); - form.BeginInvoke((MethodInvoker)delegate + form.BeginInvoke((MethodInvoker) delegate { var historyMenuItem = _historyMenuItem; - if (historyMenuItem == null) + if (historyMenuItem == null) { return; } - if (_config?.ImgurUploadHistory != null && _config.ImgurUploadHistory.Count > 0) { + + if (_config?.ImgurUploadHistory != null && _config.ImgurUploadHistory.Count > 0) + { historyMenuItem.Enabled = true; - } else { + } + else + { historyMenuItem.Enabled = false; - } - }); - } catch (Exception ex) { - Log.Error("Error loading history", ex); - } - } + } + }); + } + catch (Exception ex) + { + Log.Error("Error loading history", ex); + } + } - public virtual void Shutdown() { - Log.Debug("Imgur Plugin shutdown."); - Language.LanguageChanged -= OnLanguageChanged; - } + public virtual void Shutdown() + { + Log.Debug("Imgur Plugin shutdown."); + Language.LanguageChanged -= OnLanguageChanged; + } - /// - /// Implementation of the IPlugin.Configure - /// - public virtual void Configure() { - _config.ShowConfigDialog(); - } + /// + /// Implementation of the IPlugin.Configure + /// + public virtual void Configure() + { + _config.ShowConfigDialog(); + } - /// - /// Upload the capture to imgur - /// - /// ICaptureDetails - /// ISurface - /// out string for the url - /// true if the upload succeeded - public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, _config.UploadReduceColors); - try { - string filename = Path.GetFileName(FilenameHelper.GetFilenameFromPattern(_config.FilenamePattern, _config.UploadFormat, captureDetails)); - ImgurInfo imgurInfo = null; + /// + /// Upload the capture to imgur + /// + /// ICaptureDetails + /// ISurface + /// out string for the url + /// true if the upload succeeded + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, _config.UploadReduceColors); + try + { + string filename = Path.GetFileName(FilenameHelper.GetFilenameFromPattern(_config.FilenamePattern, _config.UploadFormat, captureDetails)); + ImgurInfo imgurInfo = null; - // Run upload in the background - new PleaseWaitForm().ShowAndWait("Imgur plug-in", Language.GetString("imgur", LangKey.communication_wait), - delegate - { - imgurInfo = ImgurUtils.UploadToImgur(surfaceToUpload, outputSettings, captureDetails.Title, filename); - if (imgurInfo != null && _config.AnonymousAccess) { - Log.InfoFormat("Storing imgur upload for hash {0} and delete hash {1}", imgurInfo.Hash, imgurInfo.DeleteHash); - _config.ImgurUploadHistory.Add(imgurInfo.Hash, imgurInfo.DeleteHash); - _config.runtimeImgurHistory.Add(imgurInfo.Hash, imgurInfo); - UpdateHistoryMenuItem(); - } - } - ); + // Run upload in the background + new PleaseWaitForm().ShowAndWait("Imgur plug-in", Language.GetString("imgur", LangKey.communication_wait), + delegate + { + imgurInfo = ImgurUtils.UploadToImgur(surfaceToUpload, outputSettings, captureDetails.Title, filename); + if (imgurInfo != null && _config.AnonymousAccess) + { + Log.InfoFormat("Storing imgur upload for hash {0} and delete hash {1}", imgurInfo.Hash, imgurInfo.DeleteHash); + _config.ImgurUploadHistory.Add(imgurInfo.Hash, imgurInfo.DeleteHash); + _config.runtimeImgurHistory.Add(imgurInfo.Hash, imgurInfo); + UpdateHistoryMenuItem(); + } + } + ); - if (imgurInfo != null) { - // TODO: Optimize a second call for export - using (Image tmpImage = surfaceToUpload.GetImageForExport()) { - imgurInfo.Image = ImageHelper.CreateThumbnail(tmpImage, 90, 90); - } - IniConfig.Save(); + if (imgurInfo != null) + { + // TODO: Optimize a second call for export + using (Image tmpImage = surfaceToUpload.GetImageForExport()) + { + imgurInfo.Image = ImageHelper.CreateThumbnail(tmpImage, 90, 90); + } - if (_config.UsePageLink) - { - uploadUrl = imgurInfo.Page; - } - else - { - uploadUrl = imgurInfo.Original; - } - if (!string.IsNullOrEmpty(uploadUrl) && _config.CopyLinkToClipboard) - { - try - { - ClipboardHelper.SetClipboardData(uploadUrl); + IniConfig.Save(); - } - catch (Exception ex) - { - Log.Error("Can't write to clipboard: ", ex); - uploadUrl = null; - } - } - return true; - } - } catch (Exception e) { - Log.Error("Error uploading.", e); - MessageBox.Show(Language.GetString("imgur", LangKey.upload_failure) + " " + e.Message); - } - uploadUrl = null; - return false; - } - } -} + if (_config.UsePageLink) + { + uploadUrl = imgurInfo.Page; + } + else + { + uploadUrl = imgurInfo.Original; + } + + if (!string.IsNullOrEmpty(uploadUrl) && _config.CopyLinkToClipboard) + { + try + { + ClipboardHelper.SetClipboardData(uploadUrl); + } + catch (Exception ex) + { + Log.Error("Can't write to clipboard: ", ex); + uploadUrl = null; + } + } + + return true; + } + } + catch (Exception e) + { + Log.Error("Error uploading.", e); + MessageBox.Show(Language.GetString("imgur", LangKey.upload_failure) + " " + e.Message); + } + + uploadUrl = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/ImgurUtils.cs b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs index e80aa0f49..32b83d6e3 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurUtils.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs @@ -30,127 +30,157 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Imgur { - /// - /// A collection of Imgur helper methods - /// - public static class ImgurUtils { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurUtils)); - private const string SmallUrlPattern = "http://i.imgur.com/{0}s.jpg"; - private static readonly ImgurConfiguration Config = IniConfig.GetIniSection(); +namespace Greenshot.Plugin.Imgur +{ + /// + /// A collection of Imgur helper methods + /// + public static class ImgurUtils + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurUtils)); + private const string SmallUrlPattern = "http://i.imgur.com/{0}s.jpg"; + private static readonly ImgurConfiguration Config = IniConfig.GetIniSection(); /// - /// Check if we need to load the history - /// - /// - public static bool IsHistoryLoadingNeeded() - { - Log.InfoFormat("Checking if imgur cache loading needed, configuration has {0} imgur hashes, loaded are {1} hashes.", Config.ImgurUploadHistory.Count, Config.runtimeImgurHistory.Count); - return Config.runtimeImgurHistory.Count != Config.ImgurUploadHistory.Count; - } + /// Check if we need to load the history + ///
+ /// + public static bool IsHistoryLoadingNeeded() + { + Log.InfoFormat("Checking if imgur cache loading needed, configuration has {0} imgur hashes, loaded are {1} hashes.", Config.ImgurUploadHistory.Count, + Config.runtimeImgurHistory.Count); + return Config.runtimeImgurHistory.Count != Config.ImgurUploadHistory.Count; + } - /// - /// Load the complete history of the imgur uploads, with the corresponding information - /// - public static void LoadHistory() { - if (!IsHistoryLoadingNeeded()) - { - return; - } + /// + /// Load the complete history of the imgur uploads, with the corresponding information + /// + public static void LoadHistory() + { + if (!IsHistoryLoadingNeeded()) + { + return; + } - bool saveNeeded = false; + bool saveNeeded = false; - // Load the ImUr history - foreach (string hash in Config.ImgurUploadHistory.Keys.ToList()) { - if (Config.runtimeImgurHistory.ContainsKey(hash)) { - // Already loaded - continue; - } + // Load the ImUr history + foreach (string hash in Config.ImgurUploadHistory.Keys.ToList()) + { + if (Config.runtimeImgurHistory.ContainsKey(hash)) + { + // Already loaded + continue; + } - try - { - var deleteHash = Config.ImgurUploadHistory[hash]; - ImgurInfo imgurInfo = RetrieveImgurInfo(hash, deleteHash); - if (imgurInfo != null) { - RetrieveImgurThumbnail(imgurInfo); - Config.runtimeImgurHistory[hash] = imgurInfo; - } else { - Log.InfoFormat("Deleting unknown ImgUr {0} from config, delete hash was {1}.", hash, deleteHash); - Config.ImgurUploadHistory.Remove(hash); - Config.runtimeImgurHistory.Remove(hash); - saveNeeded = true; - } - } catch (WebException wE) { - bool redirected = false; - if (wE.Status == WebExceptionStatus.ProtocolError) { - HttpWebResponse response = (HttpWebResponse)wE.Response; + try + { + var deleteHash = Config.ImgurUploadHistory[hash]; + ImgurInfo imgurInfo = RetrieveImgurInfo(hash, deleteHash); + if (imgurInfo != null) + { + RetrieveImgurThumbnail(imgurInfo); + Config.runtimeImgurHistory[hash] = imgurInfo; + } + else + { + Log.InfoFormat("Deleting unknown ImgUr {0} from config, delete hash was {1}.", hash, deleteHash); + Config.ImgurUploadHistory.Remove(hash); + Config.runtimeImgurHistory.Remove(hash); + saveNeeded = true; + } + } + catch (WebException wE) + { + bool redirected = false; + if (wE.Status == WebExceptionStatus.ProtocolError) + { + HttpWebResponse response = (HttpWebResponse) wE.Response; - if (response.StatusCode == HttpStatusCode.Forbidden) - { - Log.Error("Imgur loading forbidden", wE); - break; - } - // Image no longer available? - if (response.StatusCode == HttpStatusCode.Redirect) { - Log.InfoFormat("ImgUr image for hash {0} is no longer available, removing it from the history", hash); - Config.ImgurUploadHistory.Remove(hash); - Config.runtimeImgurHistory.Remove(hash); - redirected = true; - } - } - if (!redirected) { - Log.Error("Problem loading ImgUr history for hash " + hash, wE); - } - } catch (Exception e) { - Log.Error("Problem loading ImgUr history for hash " + hash, e); - } - } - if (saveNeeded) { - // Save needed changes - IniConfig.Save(); - } - } + if (response.StatusCode == HttpStatusCode.Forbidden) + { + Log.Error("Imgur loading forbidden", wE); + break; + } - /// - /// Use this to make sure Imgur knows from where the upload comes. - /// - /// - private static void SetClientId(HttpWebRequest webRequest) { - webRequest.Headers.Add("Authorization", "Client-ID " + ImgurCredentials.CONSUMER_KEY); - } + // Image no longer available? + if (response.StatusCode == HttpStatusCode.Redirect) + { + Log.InfoFormat("ImgUr image for hash {0} is no longer available, removing it from the history", hash); + Config.ImgurUploadHistory.Remove(hash); + Config.runtimeImgurHistory.Remove(hash); + redirected = true; + } + } - /// - /// Do the actual upload to Imgur - /// For more details on the available parameters, see: http://api.imgur.com/resources_anon - /// - /// ISurface to upload - /// OutputSettings for the image file format - /// Title - /// Filename - /// ImgurInfo with details - public static ImgurInfo UploadToImgur(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) { - IDictionary otherParameters = new Dictionary(); - // add title - if (title != null && Config.AddTitle) { - otherParameters["title"]= title; - } - // add filename - if (filename != null && Config.AddFilename) { - otherParameters["name"] = filename; - } - string responseString = null; - if (Config.AnonymousAccess) { - // add key, we only use the other parameters for the AnonymousAccess - //otherParameters.Add("key", IMGUR_ANONYMOUS_API_KEY); - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(Config.ImgurApi3Url + "/upload.xml?" + NetworkHelper.GenerateQueryParameters(otherParameters), HTTPMethod.POST); - webRequest.ContentType = "image/" + outputSettings.Format; - webRequest.ServicePoint.Expect100Continue = false; + if (!redirected) + { + Log.Error("Problem loading ImgUr history for hash " + hash, wE); + } + } + catch (Exception e) + { + Log.Error("Problem loading ImgUr history for hash " + hash, e); + } + } - SetClientId(webRequest); - try { - using (var requestStream = webRequest.GetRequestStream()) { - ImageOutput.SaveToStream(surfaceToUpload, requestStream, outputSettings); - } + if (saveNeeded) + { + // Save needed changes + IniConfig.Save(); + } + } + + /// + /// Use this to make sure Imgur knows from where the upload comes. + /// + /// + private static void SetClientId(HttpWebRequest webRequest) + { + webRequest.Headers.Add("Authorization", "Client-ID " + ImgurCredentials.CONSUMER_KEY); + } + + /// + /// Do the actual upload to Imgur + /// For more details on the available parameters, see: http://api.imgur.com/resources_anon + /// + /// ISurface to upload + /// OutputSettings for the image file format + /// Title + /// Filename + /// ImgurInfo with details + public static ImgurInfo UploadToImgur(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) + { + IDictionary otherParameters = new Dictionary(); + // add title + if (title != null && Config.AddTitle) + { + otherParameters["title"] = title; + } + + // add filename + if (filename != null && Config.AddFilename) + { + otherParameters["name"] = filename; + } + + string responseString = null; + if (Config.AnonymousAccess) + { + // add key, we only use the other parameters for the AnonymousAccess + //otherParameters.Add("key", IMGUR_ANONYMOUS_API_KEY); + HttpWebRequest webRequest = + NetworkHelper.CreateWebRequest(Config.ImgurApi3Url + "/upload.xml?" + NetworkHelper.GenerateQueryParameters(otherParameters), HTTPMethod.POST); + webRequest.ContentType = "image/" + outputSettings.Format; + webRequest.ServicePoint.Expect100Continue = false; + + SetClientId(webRequest); + try + { + using (var requestStream = webRequest.GetRequestStream()) + { + ImageOutput.SaveToStream(surfaceToUpload, requestStream, outputSettings); + } using WebResponse response = webRequest.GetResponse(); LogRateLimitInfo(response); @@ -160,68 +190,76 @@ namespace Greenshot.Plugin.Imgur { using StreamReader reader = new StreamReader(responseStream, true); responseString = reader.ReadToEnd(); } - } catch (Exception ex) { - Log.Error("Upload to imgur gave an exception: ", ex); - throw; - } - } else { + } + catch (Exception ex) + { + Log.Error("Upload to imgur gave an exception: ", ex); + throw; + } + } + else + { + var oauth2Settings = new OAuth2Settings + { + AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}", + TokenUrl = "https://api.imgur.com/oauth2/token", + RedirectUrl = "https://getgreenshot.org/authorize/imgur", + CloudServiceName = "Imgur", + ClientId = ImgurCredentials.CONSUMER_KEY, + ClientSecret = ImgurCredentials.CONSUMER_SECRET, + AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, + RefreshToken = Config.RefreshToken, + AccessToken = Config.AccessToken, + AccessTokenExpires = Config.AccessTokenExpires + }; - var oauth2Settings = new OAuth2Settings - { - AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}", - TokenUrl = "https://api.imgur.com/oauth2/token", - RedirectUrl = "https://getgreenshot.org/authorize/imgur", - CloudServiceName = "Imgur", - ClientId = ImgurCredentials.CONSUMER_KEY, - ClientSecret = ImgurCredentials.CONSUMER_SECRET, - AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, - RefreshToken = Config.RefreshToken, - AccessToken = Config.AccessToken, - AccessTokenExpires = Config.AccessTokenExpires - }; + // Copy the settings from the config, which is kept in memory and on the disk - // Copy the settings from the config, which is kept in memory and on the disk + try + { + var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, Config.ImgurApi3Url + "/upload.xml", oauth2Settings); + otherParameters["image"] = new SurfaceContainer(surfaceToUpload, outputSettings, filename); - try - { - var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, Config.ImgurApi3Url + "/upload.xml", oauth2Settings); - otherParameters["image"] = new SurfaceContainer(surfaceToUpload, outputSettings, filename); + NetworkHelper.WriteMultipartFormData(webRequest, otherParameters); - NetworkHelper.WriteMultipartFormData(webRequest, otherParameters); + responseString = NetworkHelper.GetResponseAsString(webRequest); + } + finally + { + // Copy the settings back to the config, so they are stored. + Config.RefreshToken = oauth2Settings.RefreshToken; + Config.AccessToken = oauth2Settings.AccessToken; + Config.AccessTokenExpires = oauth2Settings.AccessTokenExpires; + Config.IsDirty = true; + IniConfig.Save(); + } + } - responseString = NetworkHelper.GetResponseAsString(webRequest); - } - finally - { - // Copy the settings back to the config, so they are stored. - Config.RefreshToken = oauth2Settings.RefreshToken; - Config.AccessToken = oauth2Settings.AccessToken; - Config.AccessTokenExpires = oauth2Settings.AccessTokenExpires; - Config.IsDirty = true; - IniConfig.Save(); - } - } - if (string.IsNullOrEmpty(responseString)) - { - return null; - } - return ImgurInfo.ParseResponse(responseString); - } + if (string.IsNullOrEmpty(responseString)) + { + return null; + } - /// - /// Retrieve the thumbnail of an imgur image - /// - /// - public static void RetrieveImgurThumbnail(ImgurInfo imgurInfo) { - if (imgurInfo.SmallSquare == null) { - Log.Warn("Imgur URL was null, not retrieving thumbnail."); - return; - } - Log.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare); - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(string.Format(SmallUrlPattern, imgurInfo.Hash), HTTPMethod.GET); - webRequest.ServicePoint.Expect100Continue = false; - // Not for getting the thumbnail, in anonymous mode - //SetClientId(webRequest); + return ImgurInfo.ParseResponse(responseString); + } + + /// + /// Retrieve the thumbnail of an imgur image + /// + /// + public static void RetrieveImgurThumbnail(ImgurInfo imgurInfo) + { + if (imgurInfo.SmallSquare == null) + { + Log.Warn("Imgur URL was null, not retrieving thumbnail."); + return; + } + + Log.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare); + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(string.Format(SmallUrlPattern, imgurInfo.Hash), HTTPMethod.GET); + webRequest.ServicePoint.Expect100Continue = false; + // Not for getting the thumbnail, in anonymous mode + //SetClientId(webRequest); using WebResponse response = webRequest.GetResponse(); LogRateLimitInfo(response); Stream responseStream = response.GetResponseStream(); @@ -231,20 +269,21 @@ namespace Greenshot.Plugin.Imgur { } } - /// - /// Retrieve information on an imgur image - /// - /// - /// - /// ImgurInfo - public static ImgurInfo RetrieveImgurInfo(string hash, string deleteHash) { - string url = Config.ImgurApi3Url + "/image/" + hash + ".xml"; - Log.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url); - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET); - webRequest.ServicePoint.Expect100Continue = false; - SetClientId(webRequest); - string responseString = null; - try + /// + /// Retrieve information on an imgur image + /// + /// + /// + /// ImgurInfo + public static ImgurInfo RetrieveImgurInfo(string hash, string deleteHash) + { + string url = Config.ImgurApi3Url + "/image/" + hash + ".xml"; + Log.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url); + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET); + webRequest.ServicePoint.Expect100Continue = false; + SetClientId(webRequest); + string responseString = null; + try { using WebResponse response = webRequest.GetResponse(); LogRateLimitInfo(response); @@ -254,95 +293,118 @@ namespace Greenshot.Plugin.Imgur { using StreamReader reader = new StreamReader(responseStream, true); responseString = reader.ReadToEnd(); } - } catch (WebException wE) { - if (wE.Status == WebExceptionStatus.ProtocolError) { - if (((HttpWebResponse)wE.Response).StatusCode == HttpStatusCode.NotFound) { - return null; - } - } - throw; - } - ImgurInfo imgurInfo = null; - if (responseString != null) - { - Log.Debug(responseString); - imgurInfo = ImgurInfo.ParseResponse(responseString); - imgurInfo.DeleteHash = deleteHash; - } - return imgurInfo; - } + } + catch (WebException wE) + { + if (wE.Status == WebExceptionStatus.ProtocolError) + { + if (((HttpWebResponse) wE.Response).StatusCode == HttpStatusCode.NotFound) + { + return null; + } + } - /// - /// Delete an imgur image, this is done by specifying the delete hash - /// - /// - public static void DeleteImgurImage(ImgurInfo imgurInfo) { - Log.InfoFormat("Deleting Imgur image for {0}", imgurInfo.DeleteHash); + throw; + } - try { - string url = Config.ImgurApi3Url + "/image/" + imgurInfo.DeleteHash + ".xml"; - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.DELETE); - webRequest.ServicePoint.Expect100Continue = false; - SetClientId(webRequest); - string responseString = null; - using (WebResponse response = webRequest.GetResponse()) { - LogRateLimitInfo(response); - var responseStream = response.GetResponseStream(); - if (responseStream != null) + ImgurInfo imgurInfo = null; + if (responseString != null) + { + Log.Debug(responseString); + imgurInfo = ImgurInfo.ParseResponse(responseString); + imgurInfo.DeleteHash = deleteHash; + } + + return imgurInfo; + } + + /// + /// Delete an imgur image, this is done by specifying the delete hash + /// + /// + public static void DeleteImgurImage(ImgurInfo imgurInfo) + { + Log.InfoFormat("Deleting Imgur image for {0}", imgurInfo.DeleteHash); + + try + { + string url = Config.ImgurApi3Url + "/image/" + imgurInfo.DeleteHash + ".xml"; + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.DELETE); + webRequest.ServicePoint.Expect100Continue = false; + SetClientId(webRequest); + string responseString = null; + using (WebResponse response = webRequest.GetResponse()) + { + LogRateLimitInfo(response); + var responseStream = response.GetResponseStream(); + if (responseStream != null) { using StreamReader reader = new StreamReader(responseStream, true); responseString = reader.ReadToEnd(); } - } - Log.InfoFormat("Delete result: {0}", responseString); - } catch (WebException wE) { - // Allow "Bad request" this means we already deleted it - if (wE.Status == WebExceptionStatus.ProtocolError) { - if (((HttpWebResponse)wE.Response).StatusCode != HttpStatusCode.BadRequest) { - throw ; - } - } - } - // Make sure we remove it from the history, if no error occurred - Config.runtimeImgurHistory.Remove(imgurInfo.Hash); - Config.ImgurUploadHistory.Remove(imgurInfo.Hash); - imgurInfo.Image = null; - } + } - /// - /// Helper for logging - /// - /// - /// - private static void LogHeader(IDictionary nameValues, string key) { - if (nameValues.ContainsKey(key)) { - Log.InfoFormat("{0}={1}", key, nameValues[key]); - } - } + Log.InfoFormat("Delete result: {0}", responseString); + } + catch (WebException wE) + { + // Allow "Bad request" this means we already deleted it + if (wE.Status == WebExceptionStatus.ProtocolError) + { + if (((HttpWebResponse) wE.Response).StatusCode != HttpStatusCode.BadRequest) + { + throw; + } + } + } - /// - /// Log the current rate-limit information - /// - /// - private static void LogRateLimitInfo(WebResponse response) { - IDictionary nameValues = new Dictionary(); - foreach (string key in response.Headers.AllKeys) { - if (!nameValues.ContainsKey(key)) { - nameValues.Add(key, response.Headers[key]); - } - } - LogHeader(nameValues, "X-RateLimit-Limit"); - LogHeader(nameValues, "X-RateLimit-Remaining"); - LogHeader(nameValues, "X-RateLimit-UserLimit"); - LogHeader(nameValues, "X-RateLimit-UserRemaining"); - LogHeader(nameValues, "X-RateLimit-UserReset"); - LogHeader(nameValues, "X-RateLimit-ClientLimit"); - LogHeader(nameValues, "X-RateLimit-ClientRemaining"); + // Make sure we remove it from the history, if no error occurred + Config.runtimeImgurHistory.Remove(imgurInfo.Hash); + Config.ImgurUploadHistory.Remove(imgurInfo.Hash); + imgurInfo.Image = null; + } - // Update the credits in the config, this is shown in a form - if (nameValues.ContainsKey("X-RateLimit-Remaining") && int.TryParse(nameValues["X-RateLimit-Remaining"], out var credits)) { - Config.Credits = credits; - } - } - } -} + /// + /// Helper for logging + /// + /// + /// + private static void LogHeader(IDictionary nameValues, string key) + { + if (nameValues.ContainsKey(key)) + { + Log.InfoFormat("{0}={1}", key, nameValues[key]); + } + } + + /// + /// Log the current rate-limit information + /// + /// + private static void LogRateLimitInfo(WebResponse response) + { + IDictionary nameValues = new Dictionary(); + foreach (string key in response.Headers.AllKeys) + { + if (!nameValues.ContainsKey(key)) + { + nameValues.Add(key, response.Headers[key]); + } + } + + LogHeader(nameValues, "X-RateLimit-Limit"); + LogHeader(nameValues, "X-RateLimit-Remaining"); + LogHeader(nameValues, "X-RateLimit-UserLimit"); + LogHeader(nameValues, "X-RateLimit-UserRemaining"); + LogHeader(nameValues, "X-RateLimit-UserReset"); + LogHeader(nameValues, "X-RateLimit-ClientLimit"); + LogHeader(nameValues, "X-RateLimit-ClientRemaining"); + + // Update the credits in the config, this is shown in a form + if (nameValues.ContainsKey("X-RateLimit-Remaining") && int.TryParse(nameValues["X-RateLimit-Remaining"], out var credits)) + { + Config.Credits = credits; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/LanguageKeys.cs b/src/Greenshot.Plugin.Imgur/LanguageKeys.cs index 9643fb92c..7b8a0ee3e 100644 --- a/src/Greenshot.Plugin.Imgur/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Imgur/LanguageKeys.cs @@ -19,15 +19,17 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.Imgur { - public enum LangKey { - upload_menu_item, - upload_failure, - communication_wait, - delete_question, - clear_question, - delete_title, - history, - configure - } -} +namespace Greenshot.Plugin.Imgur +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + delete_question, + clear_question, + delete_title, + history, + configure + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs index 6818a420b..31ecce89a 100644 --- a/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs b/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs index 382e61c87..5445fafde 100644 --- a/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs +++ b/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs @@ -27,164 +27,165 @@ using Dapplo.Log; namespace Greenshot.Plugin.Jira { - /// - /// This abstract class builds a base for a simple async memory cache. - /// - /// Type for the key - /// Type for the stored value - public abstract class AsyncMemoryCache where TResult : class - { - private static readonly Task EmptyValueTask = Task.FromResult(null); - private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1); - private readonly MemoryCache _cache = new MemoryCache(Guid.NewGuid().ToString()); - private readonly LogSource _log = new LogSource(); - - /// - /// Set the timespan for items to expire. - /// - public TimeSpan? ExpireTimeSpan { get; set; } - - /// - /// Set the timespan for items to slide. - /// - public TimeSpan? SlidingTimeSpan { get; set; } - - /// - /// Specifies if the RemovedCallback needs to be called - /// If this is active, ActivateUpdateCallback should be false - /// - protected bool ActivateRemovedCallback { get; set; } = true; - - /// - /// Specifies if the UpdateCallback needs to be called. - /// If this is active, ActivateRemovedCallback should be false - /// - protected bool ActivateUpdateCallback { get; set; } = false; - - /// - /// Implement this method, it should create an instance of TResult via the supplied TKey. - /// - /// TKey - /// CancellationToken - /// TResult - protected abstract Task CreateAsync(TKey key, CancellationToken cancellationToken = default); - - /// - /// Creates a key under which the object is stored or retrieved, default is a toString on the object. - /// - /// TKey - /// string - protected virtual string CreateKey(TKey keyObject) - { - return keyObject.ToString(); - } + /// + /// This abstract class builds a base for a simple async memory cache. + /// + /// Type for the key + /// Type for the stored value + public abstract class AsyncMemoryCache where TResult : class + { + private static readonly Task EmptyValueTask = Task.FromResult(null); + private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1); + private readonly MemoryCache _cache = new MemoryCache(Guid.NewGuid().ToString()); + private readonly LogSource _log = new LogSource(); /// - /// Get a task element from the cache, if this is not available call the create function. - /// - /// object for the key - /// CancellationToken - /// Task with TResult - public Task GetOrCreateAsync(TKey keyObject, CancellationToken cancellationToken = default) - { - var key = CreateKey(keyObject); - return _cache.Get(key) as Task ?? GetOrCreateInternalAsync(keyObject, null, cancellationToken); - } + /// Set the timespan for items to expire. + ///
+ public TimeSpan? ExpireTimeSpan { get; set; } /// - /// This takes care of the real async part of the code. - /// - /// - /// CacheItemPolicy for when you want more control over the item - /// CancellationToken - /// TResult - private async Task GetOrCreateInternalAsync(TKey keyObject, CacheItemPolicy cacheItemPolicy = null, CancellationToken cancellationToken = default) - { - var key = CreateKey(keyObject); - var completionSource = new TaskCompletionSource(); + /// Set the timespan for items to slide. + ///
+ public TimeSpan? SlidingTimeSpan { get; set; } - if (cacheItemPolicy == null) - { - cacheItemPolicy = new CacheItemPolicy - { - AbsoluteExpiration = ExpireTimeSpan.HasValue ? DateTimeOffset.Now.Add(ExpireTimeSpan.Value) : ObjectCache.InfiniteAbsoluteExpiration, - SlidingExpiration = SlidingTimeSpan ?? ObjectCache.NoSlidingExpiration - }; - if (ActivateUpdateCallback) - { - cacheItemPolicy.UpdateCallback = UpdateCallback; - } - if (ActivateRemovedCallback) - { - cacheItemPolicy.RemovedCallback = RemovedCallback; - } - } + /// + /// Specifies if the RemovedCallback needs to be called + /// If this is active, ActivateUpdateCallback should be false + /// + protected bool ActivateRemovedCallback { get; set; } = true; + + /// + /// Specifies if the UpdateCallback needs to be called. + /// If this is active, ActivateRemovedCallback should be false + /// + protected bool ActivateUpdateCallback { get; set; } = false; + + /// + /// Implement this method, it should create an instance of TResult via the supplied TKey. + /// + /// TKey + /// CancellationToken + /// TResult + protected abstract Task CreateAsync(TKey key, CancellationToken cancellationToken = default); + + /// + /// Creates a key under which the object is stored or retrieved, default is a toString on the object. + /// + /// TKey + /// string + protected virtual string CreateKey(TKey keyObject) + { + return keyObject.ToString(); + } + + /// + /// Get a task element from the cache, if this is not available call the create function. + /// + /// object for the key + /// CancellationToken + /// Task with TResult + public Task GetOrCreateAsync(TKey keyObject, CancellationToken cancellationToken = default) + { + var key = CreateKey(keyObject); + return _cache.Get(key) as Task ?? GetOrCreateInternalAsync(keyObject, null, cancellationToken); + } + + /// + /// This takes care of the real async part of the code. + /// + /// + /// CacheItemPolicy for when you want more control over the item + /// CancellationToken + /// TResult + private async Task GetOrCreateInternalAsync(TKey keyObject, CacheItemPolicy cacheItemPolicy = null, CancellationToken cancellationToken = default) + { + var key = CreateKey(keyObject); + var completionSource = new TaskCompletionSource(); + + if (cacheItemPolicy == null) + { + cacheItemPolicy = new CacheItemPolicy + { + AbsoluteExpiration = ExpireTimeSpan.HasValue ? DateTimeOffset.Now.Add(ExpireTimeSpan.Value) : ObjectCache.InfiniteAbsoluteExpiration, + SlidingExpiration = SlidingTimeSpan ?? ObjectCache.NoSlidingExpiration + }; + if (ActivateUpdateCallback) + { + cacheItemPolicy.UpdateCallback = UpdateCallback; + } + + if (ActivateRemovedCallback) + { + cacheItemPolicy.RemovedCallback = RemovedCallback; + } + } // Test if we got an existing object or our own - if (_cache.AddOrGetExisting(key, completionSource.Task, cacheItemPolicy) is Task result && !completionSource.Task.Equals(result)) - { - return await result.ConfigureAwait(false); - } + if (_cache.AddOrGetExisting(key, completionSource.Task, cacheItemPolicy) is Task result && !completionSource.Task.Equals(result)) + { + return await result.ConfigureAwait(false); + } - await _semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - result = _cache.AddOrGetExisting(key, completionSource.Task, cacheItemPolicy) as Task; - if (result != null && !completionSource.Task.Equals(result)) - { - return await result.ConfigureAwait(false); - } + await _semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + result = _cache.AddOrGetExisting(key, completionSource.Task, cacheItemPolicy) as Task; + if (result != null && !completionSource.Task.Equals(result)) + { + return await result.ConfigureAwait(false); + } - // Now, start the background task, which will set the completionSource with the correct response - // ReSharper disable once MethodSupportsCancellation - // ReSharper disable once UnusedVariable - var ignoreBackgroundTask = Task.Run(async () => - { - try - { - var backgroundResult = await CreateAsync(keyObject, cancellationToken).ConfigureAwait(false); - completionSource.TrySetResult(backgroundResult); - } - catch (TaskCanceledException) - { - completionSource.TrySetCanceled(); - } - catch (Exception ex) - { - completionSource.TrySetException(ex); - } - }); - } - finally - { - _semaphoreSlim.Release(); - } + // Now, start the background task, which will set the completionSource with the correct response + // ReSharper disable once MethodSupportsCancellation + // ReSharper disable once UnusedVariable + var ignoreBackgroundTask = Task.Run(async () => + { + try + { + var backgroundResult = await CreateAsync(keyObject, cancellationToken).ConfigureAwait(false); + completionSource.TrySetResult(backgroundResult); + } + catch (TaskCanceledException) + { + completionSource.TrySetCanceled(); + } + catch (Exception ex) + { + completionSource.TrySetException(ex); + } + }); + } + finally + { + _semaphoreSlim.Release(); + } - return await completionSource.Task.ConfigureAwait(false); - } + return await completionSource.Task.ConfigureAwait(false); + } - /// - /// Override to know when an item is removed, make sure to configure ActivateUpdateCallback / ActivateRemovedCallback - /// - /// CacheEntryRemovedArguments - protected void RemovedCallback(CacheEntryRemovedArguments cacheEntryRemovedArguments) - { - _log.Verbose().WriteLine("Item {0} removed due to {1}.", cacheEntryRemovedArguments.CacheItem.Key, cacheEntryRemovedArguments.RemovedReason); + /// + /// Override to know when an item is removed, make sure to configure ActivateUpdateCallback / ActivateRemovedCallback + /// + /// CacheEntryRemovedArguments + protected void RemovedCallback(CacheEntryRemovedArguments cacheEntryRemovedArguments) + { + _log.Verbose().WriteLine("Item {0} removed due to {1}.", cacheEntryRemovedArguments.CacheItem.Key, cacheEntryRemovedArguments.RemovedReason); if (cacheEntryRemovedArguments.CacheItem.Value is IDisposable disposable) - { - _log.Debug().WriteLine("Disposed cached item."); - disposable.Dispose(); - } - } + { + _log.Debug().WriteLine("Disposed cached item."); + disposable.Dispose(); + } + } - /// - /// Override to modify the cache behaviour when an item is about to be removed, make sure to configure - /// ActivateUpdateCallback / ActivateRemovedCallback - /// - /// CacheEntryUpdateArguments - protected void UpdateCallback(CacheEntryUpdateArguments cacheEntryUpdateArguments) - { - _log.Verbose().WriteLine("Update request for {0} due to {1}.", cacheEntryUpdateArguments.Key, cacheEntryUpdateArguments.RemovedReason); - } - } -} + /// + /// Override to modify the cache behaviour when an item is about to be removed, make sure to configure + /// ActivateUpdateCallback / ActivateRemovedCallback + /// + /// CacheEntryUpdateArguments + protected void UpdateCallback(CacheEntryUpdateArguments cacheEntryUpdateArguments) + { + _log.Verbose().WriteLine("Update request for {0} due to {1}.", cacheEntryUpdateArguments.Key, cacheEntryUpdateArguments.RemovedReason); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs index 3c3cad44d..6eb143889 100644 --- a/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs +++ b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs @@ -30,207 +30,242 @@ using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Jira.Forms { - public partial class JiraForm : Form { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraForm)); - private readonly JiraConnector _jiraConnector; - private Issue _selectedIssue; - private readonly GreenshotColumnSorter _columnSorter; - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); +namespace Greenshot.Plugin.Jira.Forms +{ + public partial class JiraForm : Form + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraForm)); + private readonly JiraConnector _jiraConnector; + private Issue _selectedIssue; + private readonly GreenshotColumnSorter _columnSorter; + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - public JiraForm(JiraConnector jiraConnector) { - InitializeComponent(); - Icon = GreenshotResources.GetGreenshotIcon(); - AcceptButton = uploadButton; - CancelButton = cancelButton; + public JiraForm(JiraConnector jiraConnector) + { + InitializeComponent(); + Icon = GreenshotResources.GetGreenshotIcon(); + AcceptButton = uploadButton; + CancelButton = cancelButton; - InitializeComponentText(); + InitializeComponentText(); - _columnSorter = new GreenshotColumnSorter(); - jiraListView.ListViewItemSorter = _columnSorter; + _columnSorter = new GreenshotColumnSorter(); + jiraListView.ListViewItemSorter = _columnSorter; - _jiraConnector = jiraConnector; + _jiraConnector = jiraConnector; - ChangeModus(false); + ChangeModus(false); - uploadButton.Enabled = false; - Load += OnLoad; - } + uploadButton.Enabled = false; + Load += OnLoad; + } - private async void OnLoad(object sender, EventArgs eventArgs) - { - try - { - if (!_jiraConnector.IsLoggedIn) - { - await _jiraConnector.LoginAsync(); - } - } - catch (Exception e) - { - MessageBox.Show(Language.GetFormattedString("jira", LangKey.login_error, e.Message)); - } - if (_jiraConnector.IsLoggedIn) - { - var filters = await _jiraConnector.GetFavoriteFiltersAsync(); - if (filters.Count > 0) - { - foreach (var filter in filters) - { - jiraFilterBox.Items.Add(filter); - } - jiraFilterBox.SelectedIndex = 0; - } - ChangeModus(true); - if (_jiraConnector.Monitor.RecentJiras.Any()) - { - _selectedIssue = _jiraConnector.Monitor.RecentJiras.First().JiraIssue; - jiraKey.Text = _selectedIssue.Key; - uploadButton.Enabled = true; - } - } - } + private async void OnLoad(object sender, EventArgs eventArgs) + { + try + { + if (!_jiraConnector.IsLoggedIn) + { + await _jiraConnector.LoginAsync(); + } + } + catch (Exception e) + { + MessageBox.Show(Language.GetFormattedString("jira", LangKey.login_error, e.Message)); + } - private void InitializeComponentText() { - label_jirafilter.Text = Language.GetString("jira", LangKey.label_jirafilter); - label_comment.Text = Language.GetString("jira", LangKey.label_comment); - label_filename.Text = Language.GetString("jira", LangKey.label_filename); - } + if (_jiraConnector.IsLoggedIn) + { + var filters = await _jiraConnector.GetFavoriteFiltersAsync(); + if (filters.Count > 0) + { + foreach (var filter in filters) + { + jiraFilterBox.Items.Add(filter); + } - private void ChangeModus(bool enabled) { - jiraFilterBox.Enabled = enabled; - jiraListView.Enabled = enabled; - jiraFilenameBox.Enabled = enabled; - jiraCommentBox.Enabled = enabled; - } + jiraFilterBox.SelectedIndex = 0; + } - public void SetFilename(string filename) { - jiraFilenameBox.Text = filename; - } + ChangeModus(true); + if (_jiraConnector.Monitor.RecentJiras.Any()) + { + _selectedIssue = _jiraConnector.Monitor.RecentJiras.First().JiraIssue; + jiraKey.Text = _selectedIssue.Key; + uploadButton.Enabled = true; + } + } + } - public Issue GetJiraIssue() { - return _selectedIssue; - } + private void InitializeComponentText() + { + label_jirafilter.Text = Language.GetString("jira", LangKey.label_jirafilter); + label_comment.Text = Language.GetString("jira", LangKey.label_comment); + label_filename.Text = Language.GetString("jira", LangKey.label_filename); + } - public async Task UploadAsync(IBinaryContainer attachment) { - attachment.Filename = jiraFilenameBox.Text; - await _jiraConnector.AttachAsync(_selectedIssue.Key, attachment); + private void ChangeModus(bool enabled) + { + jiraFilterBox.Enabled = enabled; + jiraListView.Enabled = enabled; + jiraFilenameBox.Enabled = enabled; + jiraCommentBox.Enabled = enabled; + } - if (!string.IsNullOrEmpty(jiraCommentBox.Text)) { - await _jiraConnector.AddCommentAsync(_selectedIssue.Key, jiraCommentBox.Text); - } - } + public void SetFilename(string filename) + { + jiraFilenameBox.Text = filename; + } - private async void JiraFilterBox_SelectedIndexChanged(object sender, EventArgs e) { - if (_jiraConnector.IsLoggedIn) { + public Issue GetJiraIssue() + { + return _selectedIssue; + } - uploadButton.Enabled = false; - var filter = (Filter)jiraFilterBox.SelectedItem; - if (filter == null) { - return; - } - IList issues = null; - try - { - issues = await _jiraConnector.SearchAsync(filter); - } - catch (Exception ex) - { - Log.Error(ex); - MessageBox.Show(this, ex.Message, "Error in filter", MessageBoxButtons.OK, MessageBoxIcon.Error); - } + public async Task UploadAsync(IBinaryContainer attachment) + { + attachment.Filename = jiraFilenameBox.Text; + await _jiraConnector.AttachAsync(_selectedIssue.Key, attachment); - jiraListView.Items.Clear(); - if (issues?.Count > 0) { - jiraListView.Columns.Clear(); - LangKey[] columns = { LangKey.column_issueType, LangKey.column_id, LangKey.column_created, LangKey.column_assignee, LangKey.column_reporter, LangKey.column_summary }; - foreach (LangKey column in columns) - { - if (!Language.TryGetString("jira", column, out var translation)) - { - translation = string.Empty; - } - jiraListView.Columns.Add(translation); - } - var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, DpiHelper.GetDpi(Handle)); - var imageList = new ImageList { - ImageSize = scaledIconSize - }; - jiraListView.SmallImageList = imageList; - jiraListView.LargeImageList = imageList; + if (!string.IsNullOrEmpty(jiraCommentBox.Text)) + { + await _jiraConnector.AddCommentAsync(_selectedIssue.Key, jiraCommentBox.Text); + } + } - foreach (var issue in issues) { - var item = new ListViewItem - { - Tag = issue - }; - try - { - var issueIcon = await _jiraConnector.GetIssueTypeBitmapAsync(issue); - imageList.Images.Add(issueIcon); - item.ImageIndex = imageList.Images.Count - 1; - } - catch (Exception ex) - { - Log.Warn("Problem loading issue type, ignoring", ex); - } + private async void JiraFilterBox_SelectedIndexChanged(object sender, EventArgs e) + { + if (_jiraConnector.IsLoggedIn) + { + uploadButton.Enabled = false; + var filter = (Filter) jiraFilterBox.SelectedItem; + if (filter == null) + { + return; + } - item.SubItems.Add(issue.Key); + IList issues = null; + try + { + issues = await _jiraConnector.SearchAsync(filter); + } + catch (Exception ex) + { + Log.Error(ex); + MessageBox.Show(this, ex.Message, "Error in filter", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + jiraListView.Items.Clear(); + if (issues?.Count > 0) + { + jiraListView.Columns.Clear(); + LangKey[] columns = + { + LangKey.column_issueType, LangKey.column_id, LangKey.column_created, LangKey.column_assignee, LangKey.column_reporter, LangKey.column_summary + }; + foreach (LangKey column in columns) + { + if (!Language.TryGetString("jira", column, out var translation)) + { + translation = string.Empty; + } + + jiraListView.Columns.Add(translation); + } + + var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, DpiHelper.GetDpi(Handle)); + var imageList = new ImageList + { + ImageSize = scaledIconSize + }; + jiraListView.SmallImageList = imageList; + jiraListView.LargeImageList = imageList; + + foreach (var issue in issues) + { + var item = new ListViewItem + { + Tag = issue + }; + try + { + var issueIcon = await _jiraConnector.GetIssueTypeBitmapAsync(issue); + imageList.Images.Add(issueIcon); + item.ImageIndex = imageList.Images.Count - 1; + } + catch (Exception ex) + { + Log.Warn("Problem loading issue type, ignoring", ex); + } + + item.SubItems.Add(issue.Key); item.SubItems.Add(issue.Fields.Created.HasValue ? issue.Fields.Created.Value.ToString("d", DateTimeFormatInfo.InvariantInfo) : string.Empty); item.SubItems.Add(issue.Fields.Assignee?.DisplayName); - item.SubItems.Add(issue.Fields.Reporter?.DisplayName); - item.SubItems.Add(issue.Fields.Summary); - jiraListView.Items.Add(item); - for (int i = 0; i < columns.Length; i++) - { - jiraListView.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent); - } - jiraListView.Invalidate(); - jiraListView.Update(); - } + item.SubItems.Add(issue.Fields.Reporter?.DisplayName); + item.SubItems.Add(issue.Fields.Summary); + jiraListView.Items.Add(item); + for (int i = 0; i < columns.Length; i++) + { + jiraListView.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent); + } - jiraListView.Refresh(); - } - } - } + jiraListView.Invalidate(); + jiraListView.Update(); + } - private void JiraListView_SelectedIndexChanged(object sender, EventArgs e) { - if (jiraListView.SelectedItems.Count > 0) { - _selectedIssue = (Issue)jiraListView.SelectedItems[0].Tag; - jiraKey.Text = _selectedIssue.Key; - uploadButton.Enabled = true; - } else { - uploadButton.Enabled = false; - } - } + jiraListView.Refresh(); + } + } + } - private void JiraListView_ColumnClick(object sender, ColumnClickEventArgs e) { - // Determine if clicked column is already the column that is being sorted. - if (e.Column == _columnSorter.SortColumn) { - // Reverse the current sort direction for this column. - _columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; - } else { - // Set the column number that is to be sorted; default to ascending. - _columnSorter.SortColumn = e.Column; - _columnSorter.Order = SortOrder.Ascending; - } + private void JiraListView_SelectedIndexChanged(object sender, EventArgs e) + { + if (jiraListView.SelectedItems.Count > 0) + { + _selectedIssue = (Issue) jiraListView.SelectedItems[0].Tag; + jiraKey.Text = _selectedIssue.Key; + uploadButton.Enabled = true; + } + else + { + uploadButton.Enabled = false; + } + } - // Perform the sort with these new sort options. - jiraListView.Sort(); - } + private void JiraListView_ColumnClick(object sender, ColumnClickEventArgs e) + { + // Determine if clicked column is already the column that is being sorted. + if (e.Column == _columnSorter.SortColumn) + { + // Reverse the current sort direction for this column. + _columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; + } + else + { + // Set the column number that is to be sorted; default to ascending. + _columnSorter.SortColumn = e.Column; + _columnSorter.Order = SortOrder.Ascending; + } - private async void JiraKeyTextChanged(object sender, EventArgs e) { - string jiranumber = jiraKey.Text; - uploadButton.Enabled = false; - int dashIndex = jiranumber.IndexOf('-'); - if (dashIndex > 0 && jiranumber.Length > dashIndex+1) { - _selectedIssue = await _jiraConnector.GetIssueAsync(jiraKey.Text); - if (_selectedIssue != null) { - uploadButton.Enabled = true; - } - } - } - } -} + // Perform the sort with these new sort options. + jiraListView.Sort(); + } + + private async void JiraKeyTextChanged(object sender, EventArgs e) + { + string jiranumber = jiraKey.Text; + uploadButton.Enabled = false; + int dashIndex = jiranumber.IndexOf('-'); + if (dashIndex > 0 && jiranumber.Length > dashIndex + 1) + { + _selectedIssue = await _jiraConnector.GetIssueAsync(jiraKey.Text); + if (_selectedIssue != null) + { + uploadButton.Enabled = true; + } + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs b/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs index caf947779..21ab33509 100644 --- a/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs +++ b/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs @@ -21,7 +21,9 @@ using GreenshotPlugin.Controls; -namespace Greenshot.Plugin.Jira.Forms { - public class JiraFormBase : GreenshotForm { - } -} +namespace Greenshot.Plugin.Jira.Forms +{ + public class JiraFormBase : GreenshotForm + { + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs index 9871fd74f..9009b70e1 100644 --- a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs @@ -19,19 +19,21 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.Jira.Forms { - /// - /// Description of PasswordRequestForm. - /// - public partial class SettingsForm : JiraFormBase { - public SettingsForm() - { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - AcceptButton = buttonOK; - CancelButton = buttonCancel; - } - } -} +namespace Greenshot.Plugin.Jira.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : JiraFormBase + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = buttonOK; + CancelButton = buttonCancel; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs b/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs index a1eab6112..26d63e7c0 100644 --- a/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs +++ b/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs @@ -28,28 +28,28 @@ using Dapplo.Jira.Entities; namespace Greenshot.Plugin.Jira { - /// - /// This is the bach for the IssueType bitmaps - /// - public class IssueTypeBitmapCache : AsyncMemoryCache - { - private readonly IJiraClient _jiraClient; + /// + /// This is the bach for the IssueType bitmaps + /// + public class IssueTypeBitmapCache : AsyncMemoryCache + { + private readonly IJiraClient _jiraClient; - public IssueTypeBitmapCache(IJiraClient jiraClient) - { - _jiraClient = jiraClient; - // Set the expire timeout to an hour - ExpireTimeSpan = TimeSpan.FromHours(4); - } + public IssueTypeBitmapCache(IJiraClient jiraClient) + { + _jiraClient = jiraClient; + // Set the expire timeout to an hour + ExpireTimeSpan = TimeSpan.FromHours(4); + } - protected override string CreateKey(IssueType keyObject) - { - return keyObject.Name; - } + protected override string CreateKey(IssueType keyObject) + { + return keyObject.Name; + } - protected override async Task CreateAsync(IssueType issueType, CancellationToken cancellationToken = new CancellationToken()) - { - return await _jiraClient.Server.GetUriContentAsync(issueType.IconUri, cancellationToken).ConfigureAwait(false); - } - } -} + protected override async Task CreateAsync(IssueType issueType, CancellationToken cancellationToken = new CancellationToken()) + { + return await _jiraClient.Server.GetUriContentAsync(issueType.IconUri, cancellationToken).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraConfiguration.cs b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs index 50a521bef..cce59453b 100644 --- a/src/Greenshot.Plugin.Jira/JiraConfiguration.cs +++ b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs @@ -22,25 +22,27 @@ using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Jira { - /// - /// Description of JiraConfiguration. - /// - [IniSection("Jira", Description="Greenshot Jira Plugin configuration")] - public class JiraConfiguration : IniSection { - public const string DefaultPrefix = "http://"; - private const string DefaultUrl = DefaultPrefix + "jira"; +namespace Greenshot.Plugin.Jira +{ + /// + /// Description of JiraConfiguration. + /// + [IniSection("Jira", Description = "Greenshot Jira Plugin configuration")] + public class JiraConfiguration : IniSection + { + public const string DefaultPrefix = "http://"; + private const string DefaultUrl = DefaultPrefix + "jira"; - [IniProperty("Url", Description="Base url to Jira system, without anything else", DefaultValue=DefaultUrl)] - public string Url { get; set; } + [IniProperty("Url", Description = "Base url to Jira system, without anything else", DefaultValue = DefaultUrl)] + public string Url { get; set; } - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat { get; set; } + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } - [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality { get; set; } + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } - [IniProperty("UploadReduceColors", Description="Reduce color amount of the uploaded image to 256", DefaultValue="False")] - public bool UploadReduceColors { get; set; } - } -} + [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] + public bool UploadReduceColors { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraConnector.cs b/src/Greenshot.Plugin.Jira/JiraConnector.cs index d16a4b235..e25c4fb75 100644 --- a/src/Greenshot.Plugin.Jira/JiraConnector.cs +++ b/src/Greenshot.Plugin.Jira/JiraConnector.cs @@ -34,247 +34,280 @@ using Dapplo.Jira.SvgWinForms.Converters; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Jira { - /// - /// This encapsulates the JiraClient to make it possible to change as less old Greenshot code as needed - /// - public sealed class JiraConnector : IDisposable { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraConnector)); - private static readonly JiraConfiguration JiraConfig = IniConfig.GetIniSection(); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - // Used to remove the wsdl information from the old SOAP Uri - public const string DefaultPostfix = "/rpc/soap/jirasoapservice-v2?wsdl"; - private IJiraClient _jiraClient; - private IssueTypeBitmapCache _issueTypeBitmapCache; +namespace Greenshot.Plugin.Jira +{ + /// + /// This encapsulates the JiraClient to make it possible to change as less old Greenshot code as needed + /// + public sealed class JiraConnector : IDisposable + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraConnector)); + private static readonly JiraConfiguration JiraConfig = IniConfig.GetIniSection(); - /// - /// Initialize some basic stuff, in the case the SVG to bitmap converter - /// - static JiraConnector() - { - CoreConfig.PropertyChanged += (sender, args) => - { - if (args.PropertyName == nameof(CoreConfig.IconSize)) + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + + // Used to remove the wsdl information from the old SOAP Uri + public const string DefaultPostfix = "/rpc/soap/jirasoapservice-v2?wsdl"; + private IJiraClient _jiraClient; + private IssueTypeBitmapCache _issueTypeBitmapCache; + + /// + /// Initialize some basic stuff, in the case the SVG to bitmap converter + /// + static JiraConnector() + { + CoreConfig.PropertyChanged += (sender, args) => + { + if (args.PropertyName == nameof(CoreConfig.IconSize)) { var jiraConnector = SimpleServiceProvider.Current.GetInstance(); - jiraConnector._jiraClient?.Behaviour.SetConfig(new SvgConfiguration { Width = CoreConfig.ScaledIconSize.Width, Height = CoreConfig.ScaledIconSize.Height }); - } - }; + jiraConnector._jiraClient?.Behaviour.SetConfig(new SvgConfiguration + { + Width = CoreConfig.ScaledIconSize.Width, + Height = CoreConfig.ScaledIconSize.Height + }); + } + }; + } - } - - /// - /// Dispose, logout the users - /// - public void Dispose() { - if (_jiraClient != null) - { + /// + /// Dispose, logout the users + /// + public void Dispose() + { + if (_jiraClient != null) + { Logout(); - } - FavIcon?.Dispose(); - } + } - /// - /// Constructor - /// - public JiraConnector() - { - JiraConfig.Url = JiraConfig.Url.Replace(DefaultPostfix, string.Empty); - } + FavIcon?.Dispose(); + } - /// - /// Access the jira monitor - /// - public JiraMonitor Monitor { get; private set; } + /// + /// Constructor + /// + public JiraConnector() + { + JiraConfig.Url = JiraConfig.Url.Replace(DefaultPostfix, string.Empty); + } - public Bitmap FavIcon { get; private set; } + /// + /// Access the jira monitor + /// + public JiraMonitor Monitor { get; private set; } - /// - /// Internal login which catches the exceptions - /// - /// true if login was done successfully - private async Task DoLoginAsync(string user, string password, CancellationToken cancellationToken = default) - { - if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(password)) - { - return false; - } - _jiraClient = JiraClient.Create(new Uri(JiraConfig.Url)); - _jiraClient.Behaviour.SetConfig(new SvgConfiguration { Width = CoreConfig.ScaledIconSize.Width, Height = CoreConfig.ScaledIconSize.Height }); + public Bitmap FavIcon { get; private set; } + + /// + /// Internal login which catches the exceptions + /// + /// true if login was done successfully + private async Task DoLoginAsync(string user, string password, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(password)) + { + return false; + } + + _jiraClient = JiraClient.Create(new Uri(JiraConfig.Url)); + _jiraClient.Behaviour.SetConfig(new SvgConfiguration + { + Width = CoreConfig.ScaledIconSize.Width, + Height = CoreConfig.ScaledIconSize.Height + }); _jiraClient.SetBasicAuthentication(user, password); - _issueTypeBitmapCache = new IssueTypeBitmapCache(_jiraClient); - try - { - Monitor = new JiraMonitor(); - await Monitor.AddJiraInstanceAsync(_jiraClient, cancellationToken); + _issueTypeBitmapCache = new IssueTypeBitmapCache(_jiraClient); + try + { + Monitor = new JiraMonitor(); + await Monitor.AddJiraInstanceAsync(_jiraClient, cancellationToken); - var favIconUri = _jiraClient.JiraBaseUri.AppendSegments("favicon.ico"); - try - { - FavIcon = await _jiraClient.Server.GetUriContentAsync(favIconUri, cancellationToken); - } - catch (Exception ex) - { - Log.WarnFormat("Couldn't load favicon from {0}", favIconUri); - Log.Warn("Exception details: ", ex); - } - } - catch (Exception ex2) - { + var favIconUri = _jiraClient.JiraBaseUri.AppendSegments("favicon.ico"); + try + { + FavIcon = await _jiraClient.Server.GetUriContentAsync(favIconUri, cancellationToken); + } + catch (Exception ex) + { + Log.WarnFormat("Couldn't load favicon from {0}", favIconUri); + Log.Warn("Exception details: ", ex); + } + } + catch (Exception ex2) + { Log.WarnFormat("Couldn't connect to JIRA {0}", JiraConfig.Url); Log.Warn("Exception details: ", ex2); - return false; - } - return true; - } + return false; + } - /// - /// Use the credentials dialog, this will show if there are not correct credentials. - /// If there are credentials, call the real login. - /// - /// Task - public async Task LoginAsync(CancellationToken cancellationToken = default) { - Logout(); - try { - // Get the system name, so the user knows where to login to - var credentialsDialog = new CredentialsDialog(JiraConfig.Url) - { - Name = null - }; - while (credentialsDialog.Show(credentialsDialog.Name) == DialogResult.OK) { - if (await DoLoginAsync(credentialsDialog.Name, credentialsDialog.Password, cancellationToken)) { - if (credentialsDialog.SaveChecked) { - credentialsDialog.Confirm(true); - } - IsLoggedIn = true; - return; - } - // Login failed, confirm this - try { - credentialsDialog.Confirm(false); - } catch (ApplicationException e) { - // exception handling ... - Log.Error("Problem using the credentials dialog", e); - } - // For every windows version after XP show an incorrect password baloon - credentialsDialog.IncorrectPassword = true; - // Make sure the dialog is display, the password was false! - credentialsDialog.AlwaysDisplay = true; - } - } catch (ApplicationException e) { - // exception handling ... - Log.Error("Problem using the credentials dialog", e); - } + return true; + } - } + /// + /// Use the credentials dialog, this will show if there are not correct credentials. + /// If there are credentials, call the real login. + /// + /// Task + public async Task LoginAsync(CancellationToken cancellationToken = default) + { + Logout(); + try + { + // Get the system name, so the user knows where to login to + var credentialsDialog = new CredentialsDialog(JiraConfig.Url) + { + Name = null + }; + while (credentialsDialog.Show(credentialsDialog.Name) == DialogResult.OK) + { + if (await DoLoginAsync(credentialsDialog.Name, credentialsDialog.Password, cancellationToken)) + { + if (credentialsDialog.SaveChecked) + { + credentialsDialog.Confirm(true); + } - /// - /// End the session, if there was one - /// - public void Logout() { + IsLoggedIn = true; + return; + } + + // Login failed, confirm this + try + { + credentialsDialog.Confirm(false); + } + catch (ApplicationException e) + { + // exception handling ... + Log.Error("Problem using the credentials dialog", e); + } + + // For every windows version after XP show an incorrect password baloon + credentialsDialog.IncorrectPassword = true; + // Make sure the dialog is display, the password was false! + credentialsDialog.AlwaysDisplay = true; + } + } + catch (ApplicationException e) + { + // exception handling ... + Log.Error("Problem using the credentials dialog", e); + } + } + + /// + /// End the session, if there was one + /// + public void Logout() + { if (_jiraClient == null || !IsLoggedIn) return; Monitor.Dispose(); IsLoggedIn = false; } - /// - /// check the login credentials, to prevent timeouts of the session, or makes a login - /// Do not use ConfigureAwait to call this, as it will move await from the UI thread. - /// - /// - private async Task CheckCredentialsAsync(CancellationToken cancellationToken = default) { - if (!IsLoggedIn) { - await LoginAsync(cancellationToken); - } - } + /// + /// check the login credentials, to prevent timeouts of the session, or makes a login + /// Do not use ConfigureAwait to call this, as it will move await from the UI thread. + /// + /// + private async Task CheckCredentialsAsync(CancellationToken cancellationToken = default) + { + if (!IsLoggedIn) + { + await LoginAsync(cancellationToken); + } + } - /// - /// Get the favorite filters - /// - /// List with filters - public async Task> GetFavoriteFiltersAsync(CancellationToken cancellationToken = default) - { - await CheckCredentialsAsync(cancellationToken); - return await _jiraClient.Filter.GetFavoritesAsync(cancellationToken).ConfigureAwait(false); - } + /// + /// Get the favorite filters + /// + /// List with filters + public async Task> GetFavoriteFiltersAsync(CancellationToken cancellationToken = default) + { + await CheckCredentialsAsync(cancellationToken); + return await _jiraClient.Filter.GetFavoritesAsync(cancellationToken).ConfigureAwait(false); + } - /// - /// Get the issue for a key - /// - /// Jira issue key - /// CancellationToken - /// Issue - public async Task GetIssueAsync(string issueKey, CancellationToken cancellationToken = default) - { - await CheckCredentialsAsync(cancellationToken); - try - { - return await _jiraClient.Issue.GetAsync(issueKey, cancellationToken: cancellationToken).ConfigureAwait(false); - } - catch - { - return null; - } - } + /// + /// Get the issue for a key + /// + /// Jira issue key + /// CancellationToken + /// Issue + public async Task GetIssueAsync(string issueKey, CancellationToken cancellationToken = default) + { + await CheckCredentialsAsync(cancellationToken); + try + { + return await _jiraClient.Issue.GetAsync(issueKey, cancellationToken: cancellationToken).ConfigureAwait(false); + } + catch + { + return null; + } + } - /// - /// Attach the content to the jira - /// - /// - /// IBinaryContainer - /// - /// - public async Task AttachAsync(string issueKey, IBinaryContainer content, CancellationToken cancellationToken = default) - { - await CheckCredentialsAsync(cancellationToken); + /// + /// Attach the content to the jira + /// + /// + /// IBinaryContainer + /// + /// + public async Task AttachAsync(string issueKey, IBinaryContainer content, CancellationToken cancellationToken = default) + { + await CheckCredentialsAsync(cancellationToken); using var memoryStream = new MemoryStream(); content.WriteToStream(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); await _jiraClient.Attachment.AttachAsync(issueKey, memoryStream, content.Filename, content.ContentType, cancellationToken).ConfigureAwait(false); } - /// - /// Add a comment to the supplied issue - /// - /// Jira issue key - /// text - /// the visibility role - /// CancellationToken - public async Task AddCommentAsync(string issueKey, string body, Visibility visibility = null, CancellationToken cancellationToken = default) - { - await CheckCredentialsAsync(cancellationToken); - await _jiraClient.Issue.AddCommentAsync(issueKey, body, visibility, cancellationToken).ConfigureAwait(false); - } + /// + /// Add a comment to the supplied issue + /// + /// Jira issue key + /// text + /// the visibility role + /// CancellationToken + public async Task AddCommentAsync(string issueKey, string body, Visibility visibility = null, CancellationToken cancellationToken = default) + { + await CheckCredentialsAsync(cancellationToken); + await _jiraClient.Issue.AddCommentAsync(issueKey, body, visibility, cancellationToken).ConfigureAwait(false); + } - /// - /// Get the search results for the specified filter - /// - /// Filter - /// - /// - public async Task> SearchAsync(Filter filter, CancellationToken cancellationToken = default) - { - await CheckCredentialsAsync(cancellationToken); - var searchResult = await _jiraClient.Issue.SearchAsync(filter.Jql, null, new[] { "summary", "reporter", "assignee", "created", "issuetype" }, null, cancellationToken).ConfigureAwait(false); - return searchResult.Issues; - } + /// + /// Get the search results for the specified filter + /// + /// Filter + /// + /// + public async Task> SearchAsync(Filter filter, CancellationToken cancellationToken = default) + { + await CheckCredentialsAsync(cancellationToken); + var searchResult = await _jiraClient.Issue.SearchAsync(filter.Jql, null, new[] + { + "summary", "reporter", "assignee", "created", "issuetype" + }, null, cancellationToken).ConfigureAwait(false); + return searchResult.Issues; + } - /// - /// Get the bitmap representing the issue type of an issue, from cache. - /// - /// Issue - /// CancellationToken - /// Bitmap - public async Task GetIssueTypeBitmapAsync(Issue issue, CancellationToken cancellationToken = default) - { - return await _issueTypeBitmapCache.GetOrCreateAsync(issue.Fields.IssueType, cancellationToken).ConfigureAwait(false); - } + /// + /// Get the bitmap representing the issue type of an issue, from cache. + /// + /// Issue + /// CancellationToken + /// Bitmap + public async Task GetIssueTypeBitmapAsync(Issue issue, CancellationToken cancellationToken = default) + { + return await _issueTypeBitmapCache.GetOrCreateAsync(issue.Fields.IssueType, cancellationToken).ConfigureAwait(false); + } - /// - /// Get the base uri - /// - public Uri JiraBaseUri => _jiraClient.JiraBaseUri; + /// + /// Get the base uri + /// + public Uri JiraBaseUri => _jiraClient.JiraBaseUri; /// /// Is the user "logged in? diff --git a/src/Greenshot.Plugin.Jira/JiraDestination.cs b/src/Greenshot.Plugin.Jira/JiraDestination.cs index 9bc66dd1b..2dd871cf3 100644 --- a/src/Greenshot.Plugin.Jira/JiraDestination.cs +++ b/src/Greenshot.Plugin.Jira/JiraDestination.cs @@ -34,127 +34,148 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Jira { - /// - /// Description of JiraDestination. - /// - public class JiraDestination : AbstractDestination { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraDestination)); - private static readonly JiraConfiguration Config = IniConfig.GetIniSection(); - private readonly Issue _jiraIssue; - - public JiraDestination(Issue jiraIssue = null) { +namespace Greenshot.Plugin.Jira +{ + /// + /// Description of JiraDestination. + /// + public class JiraDestination : AbstractDestination + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraDestination)); + private static readonly JiraConfiguration Config = IniConfig.GetIniSection(); + private readonly Issue _jiraIssue; + + public JiraDestination(Issue jiraIssue = null) + { _jiraIssue = jiraIssue; - } + } - public override string Designation => "Jira"; + public override string Designation => "Jira"; - public override string Description { - get - { - if (_jiraIssue?.Fields?.Summary == null) { - return Language.GetString("jira", LangKey.upload_menu_item); - } - // Format the title of this destination - return _jiraIssue.Key + ": " + _jiraIssue.Fields.Summary.Substring(0, Math.Min(20, _jiraIssue.Fields.Summary.Length)); - } - } - - public override bool IsActive => base.IsActive && !string.IsNullOrEmpty(Config.Url); + public override string Description + { + get + { + if (_jiraIssue?.Fields?.Summary == null) + { + return Language.GetString("jira", LangKey.upload_menu_item); + } - public override bool IsDynamic => true; + // Format the title of this destination + return _jiraIssue.Key + ": " + _jiraIssue.Fields.Summary.Substring(0, Math.Min(20, _jiraIssue.Fields.Summary.Length)); + } + } - public override Image DisplayIcon { - get - { - Image displayIcon = null; + public override bool IsActive => base.IsActive && !string.IsNullOrEmpty(Config.Url); + + public override bool IsDynamic => true; + + public override Image DisplayIcon + { + get + { + Image displayIcon = null; var jiraConnector = SimpleServiceProvider.Current.GetInstance(); - if (jiraConnector != null) - { - if (_jiraIssue != null) - { - // Try to get the issue type as icon - try - { - displayIcon = jiraConnector.GetIssueTypeBitmapAsync(_jiraIssue).Result; - } - catch (Exception ex) - { - Log.Warn($"Problem loading issue type for {_jiraIssue.Key}, ignoring", ex); - } - } - if (displayIcon == null) - { - displayIcon = jiraConnector.FavIcon; - } - } - if (displayIcon == null) - { - var resources = new ComponentResourceManager(typeof(JiraPlugin)); - displayIcon = (Image)resources.GetObject("Jira"); - } - return displayIcon; - } - } + if (jiraConnector != null) + { + if (_jiraIssue != null) + { + // Try to get the issue type as icon + try + { + displayIcon = jiraConnector.GetIssueTypeBitmapAsync(_jiraIssue).Result; + } + catch (Exception ex) + { + Log.Warn($"Problem loading issue type for {_jiraIssue.Key}, ignoring", ex); + } + } - public override IEnumerable DynamicDestinations() - { - var jiraConnector = SimpleServiceProvider.Current.GetInstance(); - if (jiraConnector == null || !jiraConnector.IsLoggedIn) { - yield break; - } - foreach(var jiraDetails in jiraConnector.Monitor.RecentJiras) - { - yield return new JiraDestination(jiraDetails.JiraIssue); - } - } + if (displayIcon == null) + { + displayIcon = jiraConnector.FavIcon; + } + } - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surfaceToUpload, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - string filename = Path.GetFileName(FilenameHelper.GetFilename(Config.UploadFormat, captureDetails)); - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(Config.UploadFormat, Config.UploadJpegQuality, Config.UploadReduceColors); + if (displayIcon == null) + { + var resources = new ComponentResourceManager(typeof(JiraPlugin)); + displayIcon = (Image) resources.GetObject("Jira"); + } + + return displayIcon; + } + } + + public override IEnumerable DynamicDestinations() + { var jiraConnector = SimpleServiceProvider.Current.GetInstance(); - if (_jiraIssue != null) { - try { - // Run upload in the background - new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait), - async () => - { - var surfaceContainer = new SurfaceContainer(surfaceToUpload, outputSettings, filename); - await jiraConnector.AttachAsync(_jiraIssue.Key, surfaceContainer); - surfaceToUpload.UploadUrl = jiraConnector.JiraBaseUri.AppendSegments("browse", _jiraIssue.Key).AbsoluteUri; - } - ); - Log.DebugFormat("Uploaded to Jira {0}", _jiraIssue.Key); - exportInformation.ExportMade = true; - exportInformation.Uri = surfaceToUpload.UploadUrl; - } catch (Exception e) { - MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message); - } - } else { - var jiraForm = new JiraForm(jiraConnector); - jiraForm.SetFilename(filename); - var dialogResult = jiraForm.ShowDialog(); - if (dialogResult == DialogResult.OK) { - try { - surfaceToUpload.UploadUrl = jiraConnector.JiraBaseUri.AppendSegments("browse", jiraForm.GetJiraIssue().Key).AbsoluteUri; - // Run upload in the background - new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait), - async () => - { - await jiraForm.UploadAsync(new SurfaceContainer(surfaceToUpload, outputSettings, filename)); - } - ); - Log.DebugFormat("Uploaded to Jira {0}", jiraForm.GetJiraIssue().Key); - exportInformation.ExportMade = true; - exportInformation.Uri = surfaceToUpload.UploadUrl; - } catch(Exception e) { - MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message); - } - } - } - ProcessExport(exportInformation, surfaceToUpload); - return exportInformation; - } - } -} + if (jiraConnector == null || !jiraConnector.IsLoggedIn) + { + yield break; + } + + foreach (var jiraDetails in jiraConnector.Monitor.RecentJiras) + { + yield return new JiraDestination(jiraDetails.JiraIssue); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surfaceToUpload, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + string filename = Path.GetFileName(FilenameHelper.GetFilename(Config.UploadFormat, captureDetails)); + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(Config.UploadFormat, Config.UploadJpegQuality, Config.UploadReduceColors); + var jiraConnector = SimpleServiceProvider.Current.GetInstance(); + if (_jiraIssue != null) + { + try + { + // Run upload in the background + new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait), + async () => + { + var surfaceContainer = new SurfaceContainer(surfaceToUpload, outputSettings, filename); + await jiraConnector.AttachAsync(_jiraIssue.Key, surfaceContainer); + surfaceToUpload.UploadUrl = jiraConnector.JiraBaseUri.AppendSegments("browse", _jiraIssue.Key).AbsoluteUri; + } + ); + Log.DebugFormat("Uploaded to Jira {0}", _jiraIssue.Key); + exportInformation.ExportMade = true; + exportInformation.Uri = surfaceToUpload.UploadUrl; + } + catch (Exception e) + { + MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message); + } + } + else + { + var jiraForm = new JiraForm(jiraConnector); + jiraForm.SetFilename(filename); + var dialogResult = jiraForm.ShowDialog(); + if (dialogResult == DialogResult.OK) + { + try + { + surfaceToUpload.UploadUrl = jiraConnector.JiraBaseUri.AppendSegments("browse", jiraForm.GetJiraIssue().Key).AbsoluteUri; + // Run upload in the background + new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait), + async () => { await jiraForm.UploadAsync(new SurfaceContainer(surfaceToUpload, outputSettings, filename)); } + ); + Log.DebugFormat("Uploaded to Jira {0}", jiraForm.GetJiraIssue().Key); + exportInformation.ExportMade = true; + exportInformation.Uri = surfaceToUpload.UploadUrl; + } + catch (Exception e) + { + MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message); + } + } + } + + ProcessExport(exportInformation, surfaceToUpload); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraDetails.cs b/src/Greenshot.Plugin.Jira/JiraDetails.cs index c0ce97a50..d3ebf0255 100644 --- a/src/Greenshot.Plugin.Jira/JiraDetails.cs +++ b/src/Greenshot.Plugin.Jira/JiraDetails.cs @@ -24,48 +24,28 @@ using Dapplo.Jira.Entities; namespace Greenshot.Plugin.Jira { - public class JiraDetails : IComparable - { - public JiraDetails() - { - FirstSeenAt = SeenAt = DateTimeOffset.Now; - } + public class JiraDetails : IComparable + { + public JiraDetails() + { + FirstSeenAt = SeenAt = DateTimeOffset.Now; + } - public string ProjectKey - { - get; - set; - } + public string ProjectKey { get; set; } - public string Id - { - get; - set; - } + public string Id { get; set; } - public string JiraKey => ProjectKey + "-" + Id; + public string JiraKey => ProjectKey + "-" + Id; - public Issue JiraIssue - { - get; - set; - } + public Issue JiraIssue { get; set; } - public DateTimeOffset FirstSeenAt - { - get; - private set; - } + public DateTimeOffset FirstSeenAt { get; private set; } - public DateTimeOffset SeenAt - { - get; - set; - } + public DateTimeOffset SeenAt { get; set; } - public int CompareTo(JiraDetails other) - { - return SeenAt.CompareTo(other.SeenAt); - } - } + public int CompareTo(JiraDetails other) + { + return SeenAt.CompareTo(other.SeenAt); + } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraEventArgs.cs b/src/Greenshot.Plugin.Jira/JiraEventArgs.cs index a3b5bdeb9..203194fca 100644 --- a/src/Greenshot.Plugin.Jira/JiraEventArgs.cs +++ b/src/Greenshot.Plugin.Jira/JiraEventArgs.cs @@ -23,18 +23,10 @@ using System; namespace Greenshot.Plugin.Jira { - public class JiraEventArgs : EventArgs - { - public JiraEventTypes EventType - { - get; - set; - } + public class JiraEventArgs : EventArgs + { + public JiraEventTypes EventType { get; set; } - public JiraDetails Details - { - get; - set; - } - } -} + public JiraDetails Details { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraEventTypes.cs b/src/Greenshot.Plugin.Jira/JiraEventTypes.cs index 704fa182a..3e3c80093 100644 --- a/src/Greenshot.Plugin.Jira/JiraEventTypes.cs +++ b/src/Greenshot.Plugin.Jira/JiraEventTypes.cs @@ -21,9 +21,9 @@ namespace Greenshot.Plugin.Jira { - public enum JiraEventTypes - { - OrderChanged, - DetectedNewJiraIssue - } + public enum JiraEventTypes + { + OrderChanged, + DetectedNewJiraIssue + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraMonitor.cs b/src/Greenshot.Plugin.Jira/JiraMonitor.cs index 9a4ff1c7e..43a5e5487 100644 --- a/src/Greenshot.Plugin.Jira/JiraMonitor.cs +++ b/src/Greenshot.Plugin.Jira/JiraMonitor.cs @@ -31,188 +31,203 @@ using GreenshotPlugin.Hooking; namespace Greenshot.Plugin.Jira { - /// /// This class will monitor all _jira activity by registering for title changes /// It keeps a list of the last "accessed" jiras, and makes it easy to upload to one. /// Make sure this is instanciated on the UI thread! /// public class JiraMonitor : IDisposable - { - private static readonly LogSource Log = new LogSource(); - private readonly Regex _jiraKeyPattern = new Regex(@"[A-Z][A-Z0-9]+\-[0-9]+"); - private readonly WindowsTitleMonitor _monitor; - private readonly IList _jiraInstances = new List(); - private readonly IDictionary _projectJiraClientMap = new Dictionary(); - private readonly int _maxEntries; - // TODO: Add issues from issueHistory (JQL -> Where.IssueKey.InIssueHistory()) - private IDictionary _recentJiras = new Dictionary(); + { + private static readonly LogSource Log = new LogSource(); + private readonly Regex _jiraKeyPattern = new Regex(@"[A-Z][A-Z0-9]+\-[0-9]+"); + private readonly WindowsTitleMonitor _monitor; + private readonly IList _jiraInstances = new List(); + private readonly IDictionary _projectJiraClientMap = new Dictionary(); - /// - /// Register to this event to get events when new jira issues are detected - /// - public event EventHandler JiraEvent; + private readonly int _maxEntries; - public JiraMonitor(int maxEntries = 40) - { - _maxEntries = maxEntries; - _monitor = new WindowsTitleMonitor(); - _monitor.TitleChangeEvent += MonitorTitleChangeEvent; - } + // TODO: Add issues from issueHistory (JQL -> Where.IssueKey.InIssueHistory()) + private IDictionary _recentJiras = new Dictionary(); /// - /// Dispose - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + /// Register to this event to get events when new jira issues are detected + /// + public event EventHandler JiraEvent; - /// - /// Dispose all managed resources - /// - /// when true is passed all managed resources are disposed. - protected void Dispose(bool disposing) - { - if (!disposing) - { - return; - } - // free managed resources - _monitor.TitleChangeEvent -= MonitorTitleChangeEvent; - _monitor.Dispose(); - // free native resources if there are any. - } + public JiraMonitor(int maxEntries = 40) + { + _maxEntries = maxEntries; + _monitor = new WindowsTitleMonitor(); + _monitor.TitleChangeEvent += MonitorTitleChangeEvent; + } /// - /// Retrieve the API belonging to a JiraDetails - /// - /// - /// IJiraClient - public IJiraClient GetJiraClientForKey(JiraDetails jiraDetails) - { - return _projectJiraClientMap[jiraDetails.ProjectKey]; - } + /// Dispose + ///
+ public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - /// - /// Get the "list" of recently seen Jiras - /// - public IEnumerable RecentJiras => - (from jiraDetails in _recentJiras.Values - orderby jiraDetails.SeenAt descending - select jiraDetails); + /// + /// Dispose all managed resources + /// + /// when true is passed all managed resources are disposed. + protected void Dispose(bool disposing) + { + if (!disposing) + { + return; + } - /// - /// Check if this monitor has active instances - /// - public bool HasJiraInstances => _jiraInstances.Count > 0; + // free managed resources + _monitor.TitleChangeEvent -= MonitorTitleChangeEvent; + _monitor.Dispose(); + // free native resources if there are any. + } - /// - /// Add an instance of a JIRA system - /// - /// IJiraClient - /// CancellationToken - public async Task AddJiraInstanceAsync(IJiraClient jiraInstance, CancellationToken token = default) - { - _jiraInstances.Add(jiraInstance); - var projects = await jiraInstance.Project.GetAllAsync(cancellationToken: token).ConfigureAwait(false); - if (projects != null) - { - foreach (var project in projects) - { - if (!_projectJiraClientMap.ContainsKey(project.Key)) - { - _projectJiraClientMap.Add(project.Key, jiraInstance); - } - } - } - } + /// + /// Retrieve the API belonging to a JiraDetails + /// + /// + /// IJiraClient + public IJiraClient GetJiraClientForKey(JiraDetails jiraDetails) + { + return _projectJiraClientMap[jiraDetails.ProjectKey]; + } - /// - /// This method will update details, like the title, and send an event to registed listeners of the JiraEvent - /// - /// Contains the jira key to retrieve the title (XYZ-1234) - /// Task - private async Task DetectedNewJiraIssueAsync(JiraDetails jiraDetails) - { - try - { + /// + /// Get the "list" of recently seen Jiras + /// + public IEnumerable RecentJiras => + (from jiraDetails in _recentJiras.Values + orderby jiraDetails.SeenAt descending + select jiraDetails); + + /// + /// Check if this monitor has active instances + /// + public bool HasJiraInstances => _jiraInstances.Count > 0; + + /// + /// Add an instance of a JIRA system + /// + /// IJiraClient + /// CancellationToken + public async Task AddJiraInstanceAsync(IJiraClient jiraInstance, CancellationToken token = default) + { + _jiraInstances.Add(jiraInstance); + var projects = await jiraInstance.Project.GetAllAsync(cancellationToken: token).ConfigureAwait(false); + if (projects != null) + { + foreach (var project in projects) + { + if (!_projectJiraClientMap.ContainsKey(project.Key)) + { + _projectJiraClientMap.Add(project.Key, jiraInstance); + } + } + } + } + + /// + /// This method will update details, like the title, and send an event to registed listeners of the JiraEvent + /// + /// Contains the jira key to retrieve the title (XYZ-1234) + /// Task + private async Task DetectedNewJiraIssueAsync(JiraDetails jiraDetails) + { + try + { if (_projectJiraClientMap.TryGetValue(jiraDetails.ProjectKey, out var jiraClient)) - { - var issue = await jiraClient.Issue.GetAsync(jiraDetails.JiraKey).ConfigureAwait(false); - jiraDetails.JiraIssue = issue; - } - // Send event - JiraEvent?.Invoke(this, new JiraEventArgs { Details = jiraDetails, EventType = JiraEventTypes.DetectedNewJiraIssue }); - } - catch (Exception ex) - { - Log.Warn().WriteLine("Couldn't retrieve JIRA title: {0}", ex.Message); - } - } + { + var issue = await jiraClient.Issue.GetAsync(jiraDetails.JiraKey).ConfigureAwait(false); + jiraDetails.JiraIssue = issue; + } - /// - /// Handle title changes, check for JIRA - /// - /// - private void MonitorTitleChangeEvent(TitleChangeEventArgs eventArgs) - { - string windowTitle = eventArgs.Title; - if (string.IsNullOrEmpty(windowTitle)) - { - return; - } - var jiraKeyMatch = _jiraKeyPattern.Match(windowTitle); - if (!jiraKeyMatch.Success) - { - return; - } - // Found a possible JIRA title - var jiraKey = jiraKeyMatch.Value; - var jiraKeyParts = jiraKey.Split('-'); - var projectKey = jiraKeyParts[0]; - var jiraId = jiraKeyParts[1]; + // Send event + JiraEvent?.Invoke(this, new JiraEventArgs + { + Details = jiraDetails, + EventType = JiraEventTypes.DetectedNewJiraIssue + }); + } + catch (Exception ex) + { + Log.Warn().WriteLine("Couldn't retrieve JIRA title: {0}", ex.Message); + } + } + + /// + /// Handle title changes, check for JIRA + /// + /// + private void MonitorTitleChangeEvent(TitleChangeEventArgs eventArgs) + { + string windowTitle = eventArgs.Title; + if (string.IsNullOrEmpty(windowTitle)) + { + return; + } + + var jiraKeyMatch = _jiraKeyPattern.Match(windowTitle); + if (!jiraKeyMatch.Success) + { + return; + } + + // Found a possible JIRA title + var jiraKey = jiraKeyMatch.Value; + var jiraKeyParts = jiraKey.Split('-'); + var projectKey = jiraKeyParts[0]; + var jiraId = jiraKeyParts[1]; // Check if we have a JIRA instance with a project for this key - if (_projectJiraClientMap.TryGetValue(projectKey, out var jiraClient)) - { - // We have found a project for this _jira key, so it must be a valid & known JIRA + if (_projectJiraClientMap.TryGetValue(projectKey, out var jiraClient)) + { + // We have found a project for this _jira key, so it must be a valid & known JIRA if (_recentJiras.TryGetValue(jiraKey, out var currentJiraDetails)) - { - // update - currentJiraDetails.SeenAt = DateTimeOffset.Now; + { + // update + currentJiraDetails.SeenAt = DateTimeOffset.Now; - // Notify the order change - JiraEvent?.Invoke(this, new JiraEventArgs { Details = currentJiraDetails, EventType = JiraEventTypes.OrderChanged }); - // Nothing else to do + // Notify the order change + JiraEvent?.Invoke(this, new JiraEventArgs + { + Details = currentJiraDetails, + EventType = JiraEventTypes.OrderChanged + }); + // Nothing else to do - return; - } - // We detected an unknown JIRA, so add it to our list - currentJiraDetails = new JiraDetails - { - Id = jiraId, - ProjectKey = projectKey - }; - _recentJiras.Add(currentJiraDetails.JiraKey, currentJiraDetails); + return; + } - // Make sure we don't collect _jira's until the memory is full - if (_recentJiras.Count > _maxEntries) - { - // Add it to the list of recent Jiras - _recentJiras = (from jiraDetails in _recentJiras.Values.ToList() - orderby jiraDetails.SeenAt descending - select jiraDetails).Take(_maxEntries).ToDictionary(jd => jd.JiraKey, jd => jd); - } - // Now we can get the title from JIRA itself - // ReSharper disable once UnusedVariable - var updateTitleTask = DetectedNewJiraIssueAsync(currentJiraDetails); - } - else - { - Log.Info().WriteLine("Couldn't match possible JIRA key {0} to projects in a configured JIRA instance, ignoring", projectKey); - } - } - } + // We detected an unknown JIRA, so add it to our list + currentJiraDetails = new JiraDetails + { + Id = jiraId, + ProjectKey = projectKey + }; + _recentJiras.Add(currentJiraDetails.JiraKey, currentJiraDetails); + + // Make sure we don't collect _jira's until the memory is full + if (_recentJiras.Count > _maxEntries) + { + // Add it to the list of recent Jiras + _recentJiras = (from jiraDetails in _recentJiras.Values.ToList() + orderby jiraDetails.SeenAt descending + select jiraDetails).Take(_maxEntries).ToDictionary(jd => jd.JiraKey, jd => jd); + } + + // Now we can get the title from JIRA itself + // ReSharper disable once UnusedVariable + var updateTitleTask = DetectedNewJiraIssueAsync(currentJiraDetails); + } + else + { + Log.Info().WriteLine("Couldn't match possible JIRA key {0} to projects in a configured JIRA instance, ignoring", projectKey); + } + } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraPlugin.cs b/src/Greenshot.Plugin.Jira/JiraPlugin.cs index 8ab273768..e00f0263d 100644 --- a/src/Greenshot.Plugin.Jira/JiraPlugin.cs +++ b/src/Greenshot.Plugin.Jira/JiraPlugin.cs @@ -30,109 +30,117 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using log4net; -namespace Greenshot.Plugin.Jira { - /// - /// This is the JiraPlugin base code - /// +namespace Greenshot.Plugin.Jira +{ + /// + /// This is the JiraPlugin base code + /// [Plugin("Jira", true)] - public class JiraPlugin : IGreenshotPlugin { - private static readonly ILog Log = LogManager.GetLogger(typeof(JiraPlugin)); - private JiraConfiguration _config; + public class JiraPlugin : IGreenshotPlugin + { + private static readonly ILog Log = LogManager.GetLogger(typeof(JiraPlugin)); + private JiraConfiguration _config; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected void Dispose(bool disposing) { - if (disposing) + protected void Dispose(bool disposing) + { + if (disposing) { var jiraConnector = SimpleServiceProvider.Current.GetInstance(); jiraConnector?.Dispose(); - } - } + } + } - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - /// true if plugin is initialized, false if not (doesn't show) - public bool Initialize() { - // Register configuration (don't need the configuration itself) - _config = IniConfig.GetIniSection(); + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// true if plugin is initialized, false if not (doesn't show) + public bool Initialize() + { + // Register configuration (don't need the configuration itself) + _config = IniConfig.GetIniSection(); - // Provide the JiraConnector - SimpleServiceProvider.Current.AddService(new JiraConnector()); - // Provide the IDestination - SimpleServiceProvider.Current.AddService(new JiraDestination()); + // Provide the JiraConnector + SimpleServiceProvider.Current.AddService(new JiraConnector()); + // Provide the IDestination + SimpleServiceProvider.Current.AddService(new JiraDestination()); - // Make sure the log is enabled for the correct level. - if (Log.IsDebugEnabled) - { - LogSettings.RegisterDefaultLogger(LogLevels.Verbose); - } - else if (Log.IsInfoEnabled) - { - LogSettings.RegisterDefaultLogger(LogLevels.Info); - } - else if (Log.IsWarnEnabled) - { - LogSettings.RegisterDefaultLogger(LogLevels.Warn); - } - else if (Log.IsErrorEnabled) - { - LogSettings.RegisterDefaultLogger(LogLevels.Error); - } - else if (Log.IsErrorEnabled) - { - LogSettings.RegisterDefaultLogger(LogLevels.Error); - } - else - { - LogSettings.RegisterDefaultLogger(LogLevels.Fatal); - } + // Make sure the log is enabled for the correct level. + if (Log.IsDebugEnabled) + { + LogSettings.RegisterDefaultLogger(LogLevels.Verbose); + } + else if (Log.IsInfoEnabled) + { + LogSettings.RegisterDefaultLogger(LogLevels.Info); + } + else if (Log.IsWarnEnabled) + { + LogSettings.RegisterDefaultLogger(LogLevels.Warn); + } + else if (Log.IsErrorEnabled) + { + LogSettings.RegisterDefaultLogger(LogLevels.Error); + } + else if (Log.IsErrorEnabled) + { + LogSettings.RegisterDefaultLogger(LogLevels.Error); + } + else + { + LogSettings.RegisterDefaultLogger(LogLevels.Fatal); + } return true; - } + } - public void Shutdown() { - Log.Debug("Jira Plugin shutdown."); + public void Shutdown() + { + Log.Debug("Jira Plugin shutdown."); var jiraConnector = SimpleServiceProvider.Current.GetInstance(); jiraConnector?.Logout(); } - /// - /// Implementation of the IPlugin.Configure - /// - public void Configure() { - string url = _config.Url; - if (ShowConfigDialog()) { - // check for re-login + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + string url = _config.Url; + if (ShowConfigDialog()) + { + // check for re-login var jiraConnector = SimpleServiceProvider.Current.GetInstance(); - if (jiraConnector != null && jiraConnector.IsLoggedIn && !string.IsNullOrEmpty(url)) { - if (!url.Equals(_config.Url)) { + if (jiraConnector != null && jiraConnector.IsLoggedIn && !string.IsNullOrEmpty(url)) + { + if (!url.Equals(_config.Url)) + { jiraConnector.Logout(); - Task.Run(async () => - { - await jiraConnector.LoginAsync(); - }); - } - } - } - } + Task.Run(async () => { await jiraConnector.LoginAsync(); }); + } + } + } + } - /// - /// A form for username/password - /// - /// bool true if OK was pressed, false if cancel - private bool ShowConfigDialog() - { - var settingsForm = new SettingsForm(); - var result = settingsForm.ShowDialog(); - if (result == DialogResult.OK) - { - return true; - } - return false; - } - } -} + /// + /// A form for username/password + /// + /// bool true if OK was pressed, false if cancel + private bool ShowConfigDialog() + { + var settingsForm = new SettingsForm(); + var result = settingsForm.ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/LanguageKeys.cs b/src/Greenshot.Plugin.Jira/LanguageKeys.cs index a387b44d0..fd3fae242 100644 --- a/src/Greenshot.Plugin.Jira/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Jira/LanguageKeys.cs @@ -19,20 +19,22 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.Jira { - public enum LangKey { - upload_menu_item, - column_assignee, - column_created, - column_issueType, - column_id, - column_reporter, - column_summary, - label_comment, - label_filename, - label_jirafilter, - login_error, - upload_failure, - communication_wait, - } -} +namespace Greenshot.Plugin.Jira +{ + public enum LangKey + { + upload_menu_item, + column_assignee, + column_created, + column_issueType, + column_id, + column_reporter, + column_summary, + label_comment, + label_filename, + label_jirafilter, + login_error, + upload_failure, + communication_wait, + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/Log4NetLogger.cs b/src/Greenshot.Plugin.Jira/Log4NetLogger.cs index 12a4ac01a..125fbcbcc 100644 --- a/src/Greenshot.Plugin.Jira/Log4NetLogger.cs +++ b/src/Greenshot.Plugin.Jira/Log4NetLogger.cs @@ -24,97 +24,98 @@ using log4net; namespace Greenshot.Plugin.Jira { - /// - /// Used to make Dapplo.Log, used in Dapplo.Jira, write to Log4net - /// - public class Log4NetLogger : AbstractLogger - { - private ILog GetLogger(LogSource logSource) - { - return logSource.SourceType != null ? LogManager.GetLogger(logSource.SourceType) : LogManager.GetLogger(logSource.Source); - } + /// + /// Used to make Dapplo.Log, used in Dapplo.Jira, write to Log4net + /// + public class Log4NetLogger : AbstractLogger + { + private ILog GetLogger(LogSource logSource) + { + return logSource.SourceType != null ? LogManager.GetLogger(logSource.SourceType) : LogManager.GetLogger(logSource.Source); + } - /// - /// Write the supplied information to a log4net.ILog - /// - /// LogInfo - /// string - /// params object[] - public override void Write(LogInfo logInfo, string messageTemplate, params object[] propertyValues) - { - var log = GetLogger(logInfo.Source); + /// + /// Write the supplied information to a log4net.ILog + /// + /// LogInfo + /// string + /// params object[] + public override void Write(LogInfo logInfo, string messageTemplate, params object[] propertyValues) + { + var log = GetLogger(logInfo.Source); - switch (logInfo.LogLevel) - { - case LogLevels.Verbose: - case LogLevels.Debug: - if (propertyValues != null) - log.DebugFormat(messageTemplate, propertyValues); - else - log.Debug(messageTemplate); - break; - case LogLevels.Error: - if (propertyValues != null) - log.ErrorFormat(messageTemplate, propertyValues); - else - log.Error(messageTemplate); - break; - case LogLevels.Fatal: - if (propertyValues != null) - log.FatalFormat(messageTemplate, propertyValues); - else - log.Fatal(messageTemplate); - break; - case LogLevels.Info: - if (propertyValues != null) - log.InfoFormat(messageTemplate, propertyValues); - else - log.Info(messageTemplate); - break; - case LogLevels.Warn: - if (propertyValues != null) - log.WarnFormat(messageTemplate, propertyValues); - else - log.Warn(messageTemplate); - break; - } - } + switch (logInfo.LogLevel) + { + case LogLevels.Verbose: + case LogLevels.Debug: + if (propertyValues != null) + log.DebugFormat(messageTemplate, propertyValues); + else + log.Debug(messageTemplate); + break; + case LogLevels.Error: + if (propertyValues != null) + log.ErrorFormat(messageTemplate, propertyValues); + else + log.Error(messageTemplate); + break; + case LogLevels.Fatal: + if (propertyValues != null) + log.FatalFormat(messageTemplate, propertyValues); + else + log.Fatal(messageTemplate); + break; + case LogLevels.Info: + if (propertyValues != null) + log.InfoFormat(messageTemplate, propertyValues); + else + log.Info(messageTemplate); + break; + case LogLevels.Warn: + if (propertyValues != null) + log.WarnFormat(messageTemplate, propertyValues); + else + log.Warn(messageTemplate); + break; + } + } - /// - /// Make sure there are no newlines passed - /// - /// - /// - /// - public override void WriteLine(LogInfo logInfo, string messageTemplate, params object[] logParameters) - { - Write(logInfo, messageTemplate, logParameters); - } + /// + /// Make sure there are no newlines passed + /// + /// + /// + /// + public override void WriteLine(LogInfo logInfo, string messageTemplate, params object[] logParameters) + { + Write(logInfo, messageTemplate, logParameters); + } - /// - /// Test if a certain LogLevels enum is enabled - /// - /// LogLevels value - /// LogSource to check for - /// bool true if the LogLevels enum is enabled - public override bool IsLogLevelEnabled(LogLevels level, LogSource logSource = null) - { - var log = GetLogger(logSource); - switch (level) - { - case LogLevels.Verbose: - case LogLevels.Debug: - return log.IsDebugEnabled; - case LogLevels.Error: - return log.IsErrorEnabled; - case LogLevels.Fatal: - return log.IsFatalEnabled; - case LogLevels.Info: - return log.IsInfoEnabled; - case LogLevels.Warn: - return log.IsWarnEnabled; - } - return false; - } - } -} + /// + /// Test if a certain LogLevels enum is enabled + /// + /// LogLevels value + /// LogSource to check for + /// bool true if the LogLevels enum is enabled + public override bool IsLogLevelEnabled(LogLevels level, LogSource logSource = null) + { + var log = GetLogger(logSource); + switch (level) + { + case LogLevels.Verbose: + case LogLevels.Debug: + return log.IsDebugEnabled; + case LogLevels.Error: + return log.IsErrorEnabled; + case LogLevels.Fatal: + return log.IsFatalEnabled; + case LogLevels.Info: + return log.IsInfoEnabled; + case LogLevels.Warn: + return log.IsWarnEnabled; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Com/DisposableCom.cs b/src/Greenshot.Plugin.Office/Com/DisposableCom.cs index 5d969d0be..e722f48e3 100644 --- a/src/Greenshot.Plugin.Office/Com/DisposableCom.cs +++ b/src/Greenshot.Plugin.Office/Com/DisposableCom.cs @@ -1,5 +1,6 @@ // Copyright (c) Dapplo and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. + namespace Greenshot.Plugin.Office.Com { /// diff --git a/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs b/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs index 3f721fc38..572de52d8 100644 --- a/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs +++ b/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs @@ -38,6 +38,7 @@ namespace Greenshot.Plugin.Office.Com { return; } + // Do not catch an exception from this. // You may want to remove these guards depending on // what you think the semantics should be. @@ -45,6 +46,7 @@ namespace Greenshot.Plugin.Office.Com { Marshal.ReleaseComObject(ComObject); } + ComObject = default; } } diff --git a/src/Greenshot.Plugin.Office/Com/Ole32Api.cs b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs index 60167897e..efbf3614b 100644 --- a/src/Greenshot.Plugin.Office/Com/Ole32Api.cs +++ b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs @@ -24,6 +24,7 @@ namespace Greenshot.Plugin.Office.Com { return clsId; } + return clsId; } @@ -36,4 +37,4 @@ namespace Greenshot.Plugin.Office.Com [DllImport("ole32.dll", ExactSpelling = true)] private static extern HResult CLSIDFromProgID([In] [MarshalAs(UnmanagedType.LPWStr)] string progId, [Out] out Guid clsId); } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs index 1c38477b9..534f8a274 100644 --- a/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs +++ b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs @@ -23,7 +23,7 @@ namespace Greenshot.Plugin.Office.Com { if (GetActiveObject(ref clsId, IntPtr.Zero, out object comObject).Succeeded()) { - return DisposableCom.Create((T)comObject); + return DisposableCom.Create((T) comObject); } return null; @@ -51,4 +51,4 @@ namespace Greenshot.Plugin.Office.Com [DllImport("oleaut32.dll")] private static extern HResult GetActiveObject(ref Guid rclsId, IntPtr pvReserved, [MarshalAs(UnmanagedType.IUnknown)] out object ppunk); } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs index 571ebc7c4..5df550775 100644 --- a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs @@ -28,70 +28,89 @@ using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Office.Destinations { - /// - /// Description of PowerpointDestination. - /// - public class ExcelDestination : AbstractDestination { - private const int IconApplication = 0; - private const int IconWorkbook = 1; - private static readonly string ExePath; - private readonly string _workbookName; +namespace Greenshot.Plugin.Office.Destinations +{ + /// + /// Description of PowerpointDestination. + /// + public class ExcelDestination : AbstractDestination + { + private const int IconApplication = 0; + private const int IconWorkbook = 1; + private static readonly string ExePath; + private readonly string _workbookName; - static ExcelDestination() { - ExePath = PluginUtils.GetExePath("EXCEL.EXE"); - if (ExePath != null && File.Exists(ExePath)) { - WindowDetails.AddProcessToExcludeFromFreeze("excel"); - } else { - ExePath = null; - } - } + static ExcelDestination() + { + ExePath = PluginUtils.GetExePath("EXCEL.EXE"); + if (ExePath != null && File.Exists(ExePath)) + { + WindowDetails.AddProcessToExcludeFromFreeze("excel"); + } + else + { + ExePath = null; + } + } - public ExcelDestination() { - } + public ExcelDestination() + { + } - public ExcelDestination(string workbookName) { - _workbookName = workbookName; - } + public ExcelDestination(string workbookName) + { + _workbookName = workbookName; + } - public override string Designation => "Excel"; + public override string Designation => "Excel"; - public override string Description => _workbookName ?? "Microsoft Excel"; + public override string Description => _workbookName ?? "Microsoft Excel"; - public override int Priority => 5; + public override int Priority => 5; - public override bool IsDynamic => true; + public override bool IsDynamic => true; - public override bool IsActive => base.IsActive && ExePath != null; + public override bool IsActive => base.IsActive && ExePath != null; - public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(ExePath, !string.IsNullOrEmpty(_workbookName) ? IconWorkbook : IconApplication); + public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(ExePath, !string.IsNullOrEmpty(_workbookName) ? IconWorkbook : IconApplication); - public override IEnumerable DynamicDestinations() { - foreach (string workbookName in ExcelExporter.GetWorkbooks()) { - yield return new ExcelDestination(workbookName); - } - } + public override IEnumerable DynamicDestinations() + { + foreach (string workbookName in ExcelExporter.GetWorkbooks()) + { + yield return new ExcelDestination(workbookName); + } + } - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - bool createdFile = false; - string imageFile = captureDetails.Filename; - if (imageFile == null || surface.Modified || !Regex.IsMatch(imageFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { - imageFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); - createdFile = true; - } - if (_workbookName != null) { - ExcelExporter.InsertIntoExistingWorkbook(_workbookName, imageFile, surface.Image.Size); - } else { - ExcelExporter.InsertIntoNewWorkbook(imageFile, surface.Image.Size); - } - exportInformation.ExportMade = true; - ProcessExport(exportInformation, surface); - // Cleanup imageFile if we created it here, so less tmp-files are generated and left - if (createdFile) { - ImageOutput.DeleteNamedTmpFile(imageFile); - } - return exportInformation; - } - } -} + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + bool createdFile = false; + string imageFile = captureDetails.Filename; + if (imageFile == null || surface.Modified || !Regex.IsMatch(imageFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) + { + imageFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + createdFile = true; + } + + if (_workbookName != null) + { + ExcelExporter.InsertIntoExistingWorkbook(_workbookName, imageFile, surface.Image.Size); + } + else + { + ExcelExporter.InsertIntoNewWorkbook(imageFile, surface.Image.Size); + } + + exportInformation.ExportMade = true; + ProcessExport(exportInformation, surface); + // Cleanup imageFile if we created it here, so less tmp-files are generated and left + if (createdFile) + { + ImageOutput.DeleteNamedTmpFile(imageFile); + } + + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs index d638682f7..578f357fb 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs @@ -28,97 +28,117 @@ using Greenshot.Plugin.Office.OfficeExport.Entities; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace Greenshot.Plugin.Office.Destinations { - public class OneNoteDestination : AbstractDestination { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WordDestination)); - private const int ICON_APPLICATION = 0; - public const string DESIGNATION = "OneNote"; - private static readonly string exePath; - private readonly OneNotePage page; - private readonly OneNoteExporter _oneNoteExporter = new OneNoteExporter(); +namespace Greenshot.Plugin.Office.Destinations +{ + public class OneNoteDestination : AbstractDestination + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WordDestination)); + private const int ICON_APPLICATION = 0; + public const string DESIGNATION = "OneNote"; + private static readonly string exePath; + private readonly OneNotePage page; + private readonly OneNoteExporter _oneNoteExporter = new OneNoteExporter(); - static OneNoteDestination() { - exePath = PluginUtils.GetExePath("ONENOTE.EXE"); - if (exePath != null && File.Exists(exePath)) { - WindowDetails.AddProcessToExcludeFromFreeze("onenote"); - } else { - exePath = null; - } - } + static OneNoteDestination() + { + exePath = PluginUtils.GetExePath("ONENOTE.EXE"); + if (exePath != null && File.Exists(exePath)) + { + WindowDetails.AddProcessToExcludeFromFreeze("onenote"); + } + else + { + exePath = null; + } + } - public OneNoteDestination() { + public OneNoteDestination() + { + } - } + public OneNoteDestination(OneNotePage page) + { + this.page = page; + } - public OneNoteDestination(OneNotePage page) { - this.page = page; - } + public override string Designation + { + get { return DESIGNATION; } + } - public override string Designation { - get { - return DESIGNATION; - } - } + public override string Description + { + get + { + if (page == null) + { + return "Microsoft OneNote"; + } + else + { + return page.DisplayName; + } + } + } - public override string Description { - get { - if (page == null) { - return "Microsoft OneNote"; - } else { - return page.DisplayName; - } - } - } + public override int Priority + { + get { return 4; } + } - public override int Priority { - get { - return 4; - } - } + public override bool IsDynamic + { + get { return true; } + } - public override bool IsDynamic { - get { - return true; - } - } + public override bool IsActive + { + get { return base.IsActive && exePath != null; } + } - public override bool IsActive { - get { - return base.IsActive && exePath != null; - } - } + public override Image DisplayIcon + { + get { return PluginUtils.GetCachedExeIcon(exePath, ICON_APPLICATION); } + } - public override Image DisplayIcon { - get { - return PluginUtils.GetCachedExeIcon(exePath, ICON_APPLICATION); - } - } + public override IEnumerable DynamicDestinations() + { + foreach (OneNotePage page in _oneNoteExporter.GetPages()) + { + yield return new OneNoteDestination(page); + } + } - public override IEnumerable DynamicDestinations() { - foreach (OneNotePage page in _oneNoteExporter.GetPages()) { - yield return new OneNoteDestination(page); - } - } + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); + if (page == null) + { + try + { + exportInformation.ExportMade = _oneNoteExporter.ExportToNewPage(surface); + } + catch (Exception ex) + { + exportInformation.ErrorMessage = ex.Message; + LOG.Error(ex); + } + } + else + { + try + { + exportInformation.ExportMade = _oneNoteExporter.ExportToPage(surface, page); + } + catch (Exception ex) + { + exportInformation.ErrorMessage = ex.Message; + LOG.Error(ex); + } + } - if (page == null) { - try { - exportInformation.ExportMade = _oneNoteExporter.ExportToNewPage(surface); - } catch(Exception ex) { - exportInformation.ErrorMessage = ex.Message; - LOG.Error(ex); - } - } else { - try { - exportInformation.ExportMade = _oneNoteExporter.ExportToPage(surface, page); - } catch(Exception ex) { - exportInformation.ErrorMessage = ex.Message; - LOG.Error(ex); - } - } - return exportInformation; - } - } -} + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs index 5f5182235..ae80b6f1e 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs @@ -32,152 +32,192 @@ using GreenshotPlugin.Interfaces.Plugin; using Microsoft.Office.Interop.Outlook; using Microsoft.Win32; -namespace Greenshot.Plugin.Office.Destinations { - /// - /// Description of OutlookDestination. - /// - public class OutlookDestination : AbstractDestination { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(OutlookDestination)); - private const int IconApplication = 0; - private const int IconMeeting = 2; +namespace Greenshot.Plugin.Office.Destinations +{ + /// + /// Description of OutlookDestination. + /// + public class OutlookDestination : AbstractDestination + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(OutlookDestination)); + private const int IconApplication = 0; + private const int IconMeeting = 2; - private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); - private static readonly OfficeConfiguration OfficeConfig = IniConfig.GetIniSection(); - private static readonly string ExePath; - private static readonly bool IsActiveFlag; - private const string MapiClient = "Microsoft Outlook"; - private readonly string _outlookInspectorCaption; - private readonly OlObjectClass _outlookInspectorType; - private readonly OutlookEmailExporter _outlookEmailExporter = new(); + private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); + private static readonly OfficeConfiguration OfficeConfig = IniConfig.GetIniSection(); + private static readonly string ExePath; + private static readonly bool IsActiveFlag; + private const string MapiClient = "Microsoft Outlook"; + private readonly string _outlookInspectorCaption; + private readonly OlObjectClass _outlookInspectorType; + private readonly OutlookEmailExporter _outlookEmailExporter = new(); - static OutlookDestination() { - if (HasOutlook()) { - IsActiveFlag = true; - } - ExePath = PluginUtils.GetExePath("OUTLOOK.EXE"); - if (ExePath != null && File.Exists(ExePath)) { - WindowDetails.AddProcessToExcludeFromFreeze("outlook"); - } else { - ExePath = GetOutlookExePath(); - } - if (ExePath == null) { - IsActiveFlag = false; - } - } + static OutlookDestination() + { + if (HasOutlook()) + { + IsActiveFlag = true; + } + + ExePath = PluginUtils.GetExePath("OUTLOOK.EXE"); + if (ExePath != null && File.Exists(ExePath)) + { + WindowDetails.AddProcessToExcludeFromFreeze("outlook"); + } + else + { + ExePath = GetOutlookExePath(); + } + + if (ExePath == null) + { + IsActiveFlag = false; + } + } - private static string GetOutlookExePath() => RegistryHive.LocalMachine.ReadKey64Or32(@"Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"); + private static string GetOutlookExePath() => RegistryHive.LocalMachine.ReadKey64Or32(@"Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"); - /// - /// Check if Outlook is installed - /// - /// Returns true if outlook is installed - private static bool HasOutlook() - { - string outlookPath = GetOutlookExePath(); - if (outlookPath == null) - { - return false; - } - return File.Exists(outlookPath); - } + /// + /// Check if Outlook is installed + /// + /// Returns true if outlook is installed + private static bool HasOutlook() + { + string outlookPath = GetOutlookExePath(); + if (outlookPath == null) + { + return false; + } - public OutlookDestination() { - } + return File.Exists(outlookPath); + } - public OutlookDestination(string outlookInspectorCaption, OlObjectClass outlookInspectorType) { - _outlookInspectorCaption = outlookInspectorCaption; - _outlookInspectorType = outlookInspectorType; - } + public OutlookDestination() + { + } - public override string Designation => "Outlook"; + public OutlookDestination(string outlookInspectorCaption, OlObjectClass outlookInspectorType) + { + _outlookInspectorCaption = outlookInspectorCaption; + _outlookInspectorType = outlookInspectorType; + } - public override string Description => _outlookInspectorCaption ?? MapiClient; + public override string Designation => "Outlook"; - public override int Priority => 3; + public override string Description => _outlookInspectorCaption ?? MapiClient; - public override bool IsActive => base.IsActive && IsActiveFlag; + public override int Priority => 3; - public override bool IsDynamic => true; + public override bool IsActive => base.IsActive && IsActiveFlag; - public override Keys EditorShortcutKeys => Keys.Control | Keys.E; + public override bool IsDynamic => true; - public override Image DisplayIcon { - get - { - if (_outlookInspectorCaption == null) - { - return PluginUtils.GetCachedExeIcon(ExePath, IconApplication); - } - if (OlObjectClass.olAppointment.Equals(_outlookInspectorType)) { - // Make sure we loaded the icon, maybe the configuration has been changed! - return PluginUtils.GetCachedExeIcon(ExePath, IconMeeting); - } - return MailIcon; - } - } - - public override IEnumerable DynamicDestinations() { - IDictionary inspectorCaptions = _outlookEmailExporter.RetrievePossibleTargets(); - if (inspectorCaptions != null) { - foreach (string inspectorCaption in inspectorCaptions.Keys) { - yield return new OutlookDestination(inspectorCaption, inspectorCaptions[inspectorCaption]); - } - } - } + public override Keys EditorShortcutKeys => Keys.Control | Keys.E; - /// - /// Export the capture to outlook - /// - /// - /// - /// - /// - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - // Outlook logic - string tmpFile = captureDetails.Filename; - if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { - tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); - } else { - Log.InfoFormat("Using already available file: {0}", tmpFile); - } + public override Image DisplayIcon + { + get + { + if (_outlookInspectorCaption == null) + { + return PluginUtils.GetCachedExeIcon(ExePath, IconApplication); + } - // Create a attachment name for the image - string attachmentName = captureDetails.Title; - if (!string.IsNullOrEmpty(attachmentName)) { - attachmentName = attachmentName.Trim(); - } - // Set default if non is set - if (string.IsNullOrEmpty(attachmentName)) { - attachmentName = "Greenshot Capture"; - } - // Make sure it's "clean" so it doesn't corrupt the header - attachmentName = Regex.Replace(attachmentName, @"[^\x20\d\w]", string.Empty); + if (OlObjectClass.olAppointment.Equals(_outlookInspectorType)) + { + // Make sure we loaded the icon, maybe the configuration has been changed! + return PluginUtils.GetCachedExeIcon(ExePath, IconMeeting); + } - if (_outlookInspectorCaption != null) { + return MailIcon; + } + } + + public override IEnumerable DynamicDestinations() + { + IDictionary inspectorCaptions = _outlookEmailExporter.RetrievePossibleTargets(); + if (inspectorCaptions != null) + { + foreach (string inspectorCaption in inspectorCaptions.Keys) + { + yield return new OutlookDestination(inspectorCaption, inspectorCaptions[inspectorCaption]); + } + } + } + + /// + /// Export the capture to outlook + /// + /// + /// + /// + /// + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + // Outlook logic + string tmpFile = captureDetails.Filename; + if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) + { + tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + } + else + { + Log.InfoFormat("Using already available file: {0}", tmpFile); + } + + // Create a attachment name for the image + string attachmentName = captureDetails.Title; + if (!string.IsNullOrEmpty(attachmentName)) + { + attachmentName = attachmentName.Trim(); + } + + // Set default if non is set + if (string.IsNullOrEmpty(attachmentName)) + { + attachmentName = "Greenshot Capture"; + } + + // Make sure it's "clean" so it doesn't corrupt the header + attachmentName = Regex.Replace(attachmentName, @"[^\x20\d\w]", string.Empty); + + if (_outlookInspectorCaption != null) + { _outlookEmailExporter.ExportToInspector(_outlookInspectorCaption, tmpFile, attachmentName); - exportInformation.ExportMade = true; - } else { - if (!manuallyInitiated) { - var inspectorCaptions = _outlookEmailExporter.RetrievePossibleTargets(); - if (inspectorCaptions != null && inspectorCaptions.Count > 0) { - var destinations = new List - { - new OutlookDestination() - }; - foreach (string inspectorCaption in inspectorCaptions.Keys) { - destinations.Add(new OutlookDestination(inspectorCaption, inspectorCaptions[inspectorCaption])); - } - // Return the ExportInformation from the picker without processing, as this indirectly comes from us self - return ShowPickerMenu(false, surface, captureDetails, destinations); - } - } else { - exportInformation.ExportMade = _outlookEmailExporter.ExportToOutlook(OfficeConfig.OutlookEmailFormat, tmpFile, FilenameHelper.FillPattern(OfficeConfig.EmailSubjectPattern, captureDetails, false), attachmentName, OfficeConfig.EmailTo, OfficeConfig.EmailCC, OfficeConfig.EmailBCC, null); - } - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } + exportInformation.ExportMade = true; + } + else + { + if (!manuallyInitiated) + { + var inspectorCaptions = _outlookEmailExporter.RetrievePossibleTargets(); + if (inspectorCaptions != null && inspectorCaptions.Count > 0) + { + var destinations = new List + { + new OutlookDestination() + }; + foreach (string inspectorCaption in inspectorCaptions.Keys) + { + destinations.Add(new OutlookDestination(inspectorCaption, inspectorCaptions[inspectorCaption])); + } + + // Return the ExportInformation from the picker without processing, as this indirectly comes from us self + return ShowPickerMenu(false, surface, captureDetails, destinations); + } + } + else + { + exportInformation.ExportMade = _outlookEmailExporter.ExportToOutlook(OfficeConfig.OutlookEmailFormat, tmpFile, + FilenameHelper.FillPattern(OfficeConfig.EmailSubjectPattern, captureDetails, false), attachmentName, OfficeConfig.EmailTo, OfficeConfig.EmailCC, + OfficeConfig.EmailBCC, null); + } + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs index 1382a316a..bb5a0c453 100644 --- a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs @@ -29,95 +29,127 @@ using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Office.Destinations { - /// - /// Description of PowerpointDestination. - /// - public class PowerpointDestination : AbstractDestination { - private const int IconApplication = 0; - private const int IconPresentation = 1; +namespace Greenshot.Plugin.Office.Destinations +{ + /// + /// Description of PowerpointDestination. + /// + public class PowerpointDestination : AbstractDestination + { + private const int IconApplication = 0; + private const int IconPresentation = 1; - private static readonly string ExePath; - private readonly string _presentationName; - private readonly PowerpointExporter _powerpointExporter = new PowerpointExporter(); - - static PowerpointDestination() { - ExePath = PluginUtils.GetExePath("POWERPNT.EXE"); - if (ExePath != null && File.Exists(ExePath)) { - WindowDetails.AddProcessToExcludeFromFreeze("powerpnt"); - } else { - ExePath = null; - } - } + private static readonly string ExePath; + private readonly string _presentationName; + private readonly PowerpointExporter _powerpointExporter = new PowerpointExporter(); - public PowerpointDestination() { - } + static PowerpointDestination() + { + ExePath = PluginUtils.GetExePath("POWERPNT.EXE"); + if (ExePath != null && File.Exists(ExePath)) + { + WindowDetails.AddProcessToExcludeFromFreeze("powerpnt"); + } + else + { + ExePath = null; + } + } - public PowerpointDestination(string presentationName) { - _presentationName = presentationName; - } + public PowerpointDestination() + { + } - public override string Designation => "Powerpoint"; + public PowerpointDestination(string presentationName) + { + _presentationName = presentationName; + } - public override string Description { - get - { - if (_presentationName == null) { - return "Microsoft Powerpoint"; - } - return _presentationName; - } - } + public override string Designation => "Powerpoint"; - public override int Priority => 4; + public override string Description + { + get + { + if (_presentationName == null) + { + return "Microsoft Powerpoint"; + } - public override bool IsDynamic => true; + return _presentationName; + } + } - public override bool IsActive => base.IsActive && ExePath != null; + public override int Priority => 4; - public override Image DisplayIcon { - get { - if (!string.IsNullOrEmpty(_presentationName)) { - return PluginUtils.GetCachedExeIcon(ExePath, IconPresentation); - } + public override bool IsDynamic => true; - return PluginUtils.GetCachedExeIcon(ExePath, IconApplication); - } - } + public override bool IsActive => base.IsActive && ExePath != null; - public override IEnumerable DynamicDestinations() { - foreach (string presentationName in _powerpointExporter.GetPowerpointPresentations()) { - yield return new PowerpointDestination(presentationName); - } - } + public override Image DisplayIcon + { + get + { + if (!string.IsNullOrEmpty(_presentationName)) + { + return PluginUtils.GetCachedExeIcon(ExePath, IconPresentation); + } - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - string tmpFile = captureDetails.Filename; - Size imageSize = Size.Empty; - if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { - tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); - imageSize = surface.Image.Size; - } - if (_presentationName != null) { - exportInformation.ExportMade = _powerpointExporter.ExportToPresentation(_presentationName, tmpFile, imageSize, captureDetails.Title); - } else { - if (!manuallyInitiated) { - var presentations = _powerpointExporter.GetPowerpointPresentations().ToList(); - if (presentations != null && presentations.Count > 0) { - var destinations = new List {new PowerpointDestination()}; - foreach (string presentation in presentations) { - destinations.Add(new PowerpointDestination(presentation)); - } - // Return the ExportInformation from the picker without processing, as this indirectly comes from us self - return ShowPickerMenu(false, surface, captureDetails, destinations); - } - } else if (!exportInformation.ExportMade) { - exportInformation.ExportMade = _powerpointExporter.InsertIntoNewPresentation(tmpFile, imageSize, captureDetails.Title); - } - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + return PluginUtils.GetCachedExeIcon(ExePath, IconApplication); + } + } + + public override IEnumerable DynamicDestinations() + { + foreach (string presentationName in _powerpointExporter.GetPowerpointPresentations()) + { + yield return new PowerpointDestination(presentationName); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + string tmpFile = captureDetails.Filename; + Size imageSize = Size.Empty; + if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) + { + tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + imageSize = surface.Image.Size; + } + + if (_presentationName != null) + { + exportInformation.ExportMade = _powerpointExporter.ExportToPresentation(_presentationName, tmpFile, imageSize, captureDetails.Title); + } + else + { + if (!manuallyInitiated) + { + var presentations = _powerpointExporter.GetPowerpointPresentations().ToList(); + if (presentations != null && presentations.Count > 0) + { + var destinations = new List + { + new PowerpointDestination() + }; + foreach (string presentation in presentations) + { + destinations.Add(new PowerpointDestination(presentation)); + } + + // Return the ExportInformation from the picker without processing, as this indirectly comes from us self + return ShowPickerMenu(false, surface, captureDetails, destinations); + } + } + else if (!exportInformation.ExportMade) + { + exportInformation.ExportMade = _powerpointExporter.InsertIntoNewPresentation(tmpFile, imageSize, captureDetails.Title); + } + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs index 4f85dd99e..ff9945824 100644 --- a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs @@ -30,102 +30,134 @@ using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Office.Destinations { - /// - /// Description of EmailDestination. - /// - public class WordDestination : AbstractDestination { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(WordDestination)); - private const int IconApplication = 0; - private const int IconDocument = 1; - private static readonly string ExePath; - private readonly string _documentCaption; +namespace Greenshot.Plugin.Office.Destinations +{ + /// + /// Description of EmailDestination. + /// + public class WordDestination : AbstractDestination + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(WordDestination)); + private const int IconApplication = 0; + private const int IconDocument = 1; + private static readonly string ExePath; + private readonly string _documentCaption; private readonly WordExporter _wordExporter = new WordExporter(); - static WordDestination() { - ExePath = PluginUtils.GetExePath("WINWORD.EXE"); - if (ExePath != null && !File.Exists(ExePath)) { - ExePath = null; - } - } - - public WordDestination() { - - } - public WordDestination(string wordCaption) { - _documentCaption = wordCaption; - } + static WordDestination() + { + ExePath = PluginUtils.GetExePath("WINWORD.EXE"); + if (ExePath != null && !File.Exists(ExePath)) + { + ExePath = null; + } + } - public override string Designation => "Word"; + public WordDestination() + { + } - public override string Description => _documentCaption ?? "Microsoft Word"; + public WordDestination(string wordCaption) + { + _documentCaption = wordCaption; + } - public override int Priority => 4; + public override string Designation => "Word"; - public override bool IsDynamic => true; + public override string Description => _documentCaption ?? "Microsoft Word"; - public override bool IsActive => base.IsActive && ExePath != null; + public override int Priority => 4; - public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(ExePath, !string.IsNullOrEmpty(_documentCaption) ? IconDocument : IconApplication); + public override bool IsDynamic => true; - public override IEnumerable DynamicDestinations() { - foreach (string wordCaption in _wordExporter.GetWordDocuments()) { - yield return new WordDestination(wordCaption); - } - } + public override bool IsActive => base.IsActive && ExePath != null; - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - string tmpFile = captureDetails.Filename; - if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { - tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); - } - if (_documentCaption != null) { - try { + public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(ExePath, !string.IsNullOrEmpty(_documentCaption) ? IconDocument : IconApplication); + + public override IEnumerable DynamicDestinations() + { + foreach (string wordCaption in _wordExporter.GetWordDocuments()) + { + yield return new WordDestination(wordCaption); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + string tmpFile = captureDetails.Filename; + if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) + { + tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + } + + if (_documentCaption != null) + { + try + { _wordExporter.InsertIntoExistingDocument(_documentCaption, tmpFile); - exportInformation.ExportMade = true; - } catch (Exception) { - try { + exportInformation.ExportMade = true; + } + catch (Exception) + { + try + { _wordExporter.InsertIntoExistingDocument(_documentCaption, tmpFile); - exportInformation.ExportMade = true; - } catch (Exception ex) { - Log.Error(ex); - // TODO: Change to general logic in ProcessExport - surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description)); - } - } - } else { - if (!manuallyInitiated) { - var documents = _wordExporter.GetWordDocuments().ToList(); - if (documents != null && documents.Count > 0) { - var destinations = new List - { - new WordDestination() - }; - foreach (string document in documents) { - destinations.Add(new WordDestination(document)); - } - // Return the ExportInformation from the picker without processing, as this indirectly comes from us self - return ShowPickerMenu(false, surface, captureDetails, destinations); - } - } - try { + exportInformation.ExportMade = true; + } + catch (Exception ex) + { + Log.Error(ex); + // TODO: Change to general logic in ProcessExport + surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description)); + } + } + } + else + { + if (!manuallyInitiated) + { + var documents = _wordExporter.GetWordDocuments().ToList(); + if (documents != null && documents.Count > 0) + { + var destinations = new List + { + new WordDestination() + }; + foreach (string document in documents) + { + destinations.Add(new WordDestination(document)); + } + + // Return the ExportInformation from the picker without processing, as this indirectly comes from us self + return ShowPickerMenu(false, surface, captureDetails, destinations); + } + } + + try + { _wordExporter.InsertIntoNewDocument(tmpFile, null, null); - exportInformation.ExportMade = true; - } catch(Exception) { - // Retry once, just in case - try { + exportInformation.ExportMade = true; + } + catch (Exception) + { + // Retry once, just in case + try + { _wordExporter.InsertIntoNewDocument(tmpFile, null, null); - exportInformation.ExportMade = true; - } catch (Exception ex) { - Log.Error(ex); - // TODO: Change to general logic in ProcessExport - surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description)); - } - } - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + exportInformation.ExportMade = true; + } + catch (Exception ex) + { + Log.Error(ex); + // TODO: Change to general logic in ProcessExport + surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description)); + } + } + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/GlobalSuppressions.cs b/src/Greenshot.Plugin.Office/GlobalSuppressions.cs index 882507f6b2bc153394105cf0e4819544426c8df0..0adf57f14d766987b7b593f86de6b34d72bad816 100644 GIT binary patch delta 208 zcmdlZc|>Z%BW6xs1}+8#5ZwHbnVC@#&V>jvC`?|iwMTNpBj(MExS1FyGjXO&PGRjsa7x$ + /// Description of CoreConfiguration. + /// + [IniSection("Office", Description = "Greenshot Office configuration")] + public class OfficeConfiguration : IniSection + { + [IniProperty("OutlookEmailFormat", Description = "Default type for emails. (Text, HTML)", DefaultValue = "HTML")] + public EmailFormat OutlookEmailFormat { get; set; } - /// - /// Description of CoreConfiguration. - /// - [IniSection("Office", Description="Greenshot Office configuration")] - public class OfficeConfiguration : IniSection { - [IniProperty("OutlookEmailFormat", Description = "Default type for emails. (Text, HTML)", DefaultValue = "HTML")] - public EmailFormat OutlookEmailFormat { get; set; } + [IniProperty("EmailSubjectPattern", Description = "Email subject pattern, works like the OutputFileFilenamePattern", DefaultValue = "${title}")] + public string EmailSubjectPattern { get; set; } - [IniProperty("EmailSubjectPattern", Description = "Email subject pattern, works like the OutputFileFilenamePattern", DefaultValue = "${title}")] - public string EmailSubjectPattern { get; set; } - [IniProperty("EmailTo", Description = "Default value for the to in emails that are created", DefaultValue = "")] - public string EmailTo { get; set; } - [IniProperty("EmailCC", Description = "Default value for the CC in emails that are created", DefaultValue = "")] - public string EmailCC { get; set; } - [IniProperty("EmailBCC", Description = "Default value for the BCC in emails that are created", DefaultValue = "")] - public string EmailBCC { get; set; } - [IniProperty("OutlookAllowExportInMeetings", Description = "For Outlook: Allow export in meeting items", DefaultValue = "False")] - public bool OutlookAllowExportInMeetings { get; set; } - [IniProperty("WordLockAspectRatio", Description = "For Word: Lock the aspect ratio of the image", DefaultValue = "True")] - public bool WordLockAspectRatio { get; set; } - [IniProperty("PowerpointLockAspectRatio", Description = "For Powerpoint: Lock the aspect ratio of the image", DefaultValue = "True")] - public bool PowerpointLockAspectRatio { get; set; } - [IniProperty("PowerpointSlideLayout", Description = "For Powerpoint: Slide layout, changing this to a wrong value will fallback on ppLayoutBlank!!", DefaultValue = "ppLayoutPictureWithCaption")] - public PpSlideLayout PowerpointSlideLayout { get; set; } + [IniProperty("EmailTo", Description = "Default value for the to in emails that are created", DefaultValue = "")] + public string EmailTo { get; set; } - } + [IniProperty("EmailCC", Description = "Default value for the CC in emails that are created", DefaultValue = "")] + public string EmailCC { get; set; } + + [IniProperty("EmailBCC", Description = "Default value for the BCC in emails that are created", DefaultValue = "")] + public string EmailBCC { get; set; } + + [IniProperty("OutlookAllowExportInMeetings", Description = "For Outlook: Allow export in meeting items", DefaultValue = "False")] + public bool OutlookAllowExportInMeetings { get; set; } + + [IniProperty("WordLockAspectRatio", Description = "For Word: Lock the aspect ratio of the image", DefaultValue = "True")] + public bool WordLockAspectRatio { get; set; } + + [IniProperty("PowerpointLockAspectRatio", Description = "For Powerpoint: Lock the aspect ratio of the image", DefaultValue = "True")] + public bool PowerpointLockAspectRatio { get; set; } + + [IniProperty("PowerpointSlideLayout", Description = "For Powerpoint: Slide layout, changing this to a wrong value will fallback on ppLayoutBlank!!", + DefaultValue = "ppLayoutPictureWithCaption")] + public PpSlideLayout PowerpointSlideLayout { get; set; } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs index 685fc4e18..2a0904870 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs @@ -34,6 +34,7 @@ namespace Greenshot.Plugin.Office.OfficeExport.Entities { return string.Format("{0} / {1}", Parent.Name, Name); } + return string.Format("{0} / {1} / {2}", Parent.Parent.Name, Parent.Name, Name); } } diff --git a/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs index f508208f7..4455bfd73 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs @@ -53,10 +53,12 @@ namespace Greenshot.Plugin.Office.OfficeExport // Ignore, probably no excel running return null; } + if (excelApplication?.ComObject != null) { InitializeVariables(excelApplication); } + return excelApplication; } @@ -71,6 +73,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { excelApplication = DisposableCom.Create(new Application()); } + InitializeVariables(excelApplication); return excelApplication; } @@ -108,10 +111,11 @@ namespace Greenshot.Plugin.Office.OfficeExport { return; } + if (!Version.TryParse(excelApplication.ComObject.Version, out _excelVersion)) { LOG.Warn("Assuming Excel version 1997."); - _excelVersion = new Version((int)OfficeVersions.Office97, 0, 0, 0); + _excelVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0); } } @@ -132,7 +136,7 @@ namespace Greenshot.Plugin.Office.OfficeExport using var workbooks = DisposableCom.Create(excelApplication.ComObject.Workbooks); for (int i = 1; i <= workbooks.ComObject.Count; i++) { - using var workbook = DisposableCom.Create((_Workbook)workbooks.ComObject[i]); + using var workbook = DisposableCom.Create((_Workbook) workbooks.ComObject[i]); if ((workbook != null) && workbook.ComObject.Name.StartsWith(workbookName)) { InsertIntoExistingWorkbook(workbook, tmpFile, imageSize); @@ -191,9 +195,8 @@ namespace Greenshot.Plugin.Office.OfficeExport excelApplication.ComObject.Visible = true; using var workbooks = DisposableCom.Create(excelApplication.ComObject.Workbooks); - using var workbook = DisposableCom.Create((_Workbook)workbooks.ComObject.Add()); + using var workbook = DisposableCom.Create((_Workbook) workbooks.ComObject.Add()); InsertIntoExistingWorkbook(workbook, tmpFile, imageSize); } } - } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs index 4936315bc..f42622356 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs @@ -38,7 +38,10 @@ namespace Greenshot.Plugin.Office.OfficeExport public class OneNoteExporter { private const string XmlImageContent = "{0}"; - private const string XmlOutline = "{0}"; + + private const string XmlOutline = + "{0}"; + private const string OnenoteNamespace2010 = "http://schemas.microsoft.com/office/onenote/2010/onenote"; private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OneNoteExporter)); @@ -107,6 +110,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { LOG.Warn("Unable to navigate to the target page", ex); } + return true; } @@ -126,6 +130,7 @@ namespace Greenshot.Plugin.Office.OfficeExport // Ignore, probably no OneNote running return null; } + return oneNoteApplication; } @@ -140,6 +145,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { oneNoteApplication = DisposableCom.Create(new Application()); } + return oneNoteApplication; } @@ -183,6 +189,7 @@ namespace Greenshot.Plugin.Office.OfficeExport }; } } + if ("one:Section".Equals(xmlReader.Name)) { string id = xmlReader.GetAttribute("ID"); @@ -196,6 +203,7 @@ namespace Greenshot.Plugin.Office.OfficeExport }; } } + if ("one:Page".Equals(xmlReader.Name)) { // Skip deleted items @@ -214,6 +222,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { continue; } + page.IsCurrentlyViewed = "true".Equals(xmlReader.GetAttribute("isCurrentlyViewed")); pages.Add(page); } @@ -231,22 +240,26 @@ namespace Greenshot.Plugin.Office.OfficeExport } catch (COMException cEx) { - if (cEx.ErrorCode == unchecked((int)0x8002801D)) + if (cEx.ErrorCode == unchecked((int) 0x8002801D)) { - LOG.Warn("Wrong registry keys, to solve this remove the OneNote key as described here: http://microsoftmercenary.com/wp/outlook-excel-interop-calls-breaking-solved/"); + LOG.Warn( + "Wrong registry keys, to solve this remove the OneNote key as described here: http://microsoftmercenary.com/wp/outlook-excel-interop-calls-breaking-solved/"); } + LOG.Warn("Problem retrieving onenote destinations, ignoring: ", cEx); } catch (Exception ex) { LOG.Warn("Problem retrieving onenote destinations, ignoring: ", ex); } + pages.Sort((page1, page2) => { if (page1.IsCurrentlyViewed || page2.IsCurrentlyViewed) { return page2.IsCurrentlyViewed.CompareTo(page1.IsCurrentlyViewed); } + return string.Compare(page1.DisplayName, page2.DisplayName, StringComparison.Ordinal); }); return pages; @@ -264,6 +277,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { return null; } + // ReSharper disable once RedundantAssignment string unfiledNotesPath = ""; oneNoteApplication.ComObject.GetSpecialLocation(specialLocation, out unfiledNotesPath); @@ -285,6 +299,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { continue; } + string id = xmlReader.GetAttribute("ID"); string path = xmlReader.GetAttribute("path"); if (unfiledNotesPath.Equals(path)) @@ -301,6 +316,7 @@ namespace Greenshot.Plugin.Office.OfficeExport } } } + return null; } } diff --git a/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs index 93fc68567..55cad605e 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs @@ -47,7 +47,9 @@ namespace Greenshot.Plugin.Office.OfficeExport private const string ProfilesKey = @"Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\"; private const string AccountKey = "9375CFF0413111d3B88A00104B2A6676"; private const string NewSignatureValue = "New Signature"; + private const string DefaultProfileValue = "DefaultProfile"; + // Schema definitions for the MAPI properties, see: http://msdn.microsoft.com/en-us/library/aa454438.aspx and: http://msdn.microsoft.com/en-us/library/bb446117.aspx private const string AttachmentContentId = @"http://schemas.microsoft.com/mapi/proptag/0x3712001E"; @@ -73,10 +75,10 @@ namespace Greenshot.Plugin.Office.OfficeExport } // The activeexplorer inline response only works with >= 2013, Microsoft Outlook 15.0 Object Library - if (_outlookVersion.Major >= (int)OfficeVersions.Office2013) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2013) { // Check inline "panel" for Outlook 2013 - using var activeExplorer = DisposableCom.Create((_Explorer)outlookApplication.ComObject.ActiveExplorer()); + using var activeExplorer = DisposableCom.Create((_Explorer) outlookApplication.ComObject.ActiveExplorer()); // Only if we have one and if the capture is the one we selected if ((activeExplorer != null) && activeExplorer.ComObject.Caption.StartsWith(inspectorCaption)) { @@ -90,15 +92,17 @@ namespace Greenshot.Plugin.Office.OfficeExport { return ExportToInspector(null, activeExplorer, mailItem.Class, mailItem, tmpFile, attachmentName); } + break; case AppointmentItem appointmentItem: - if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) + if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) { if (!string.IsNullOrEmpty(appointmentItem.Organizer) && appointmentItem.Organizer.Equals(_currentUser)) { return ExportToInspector(null, activeExplorer, appointmentItem.Class, null, tmpFile, attachmentName); } } + break; } } @@ -110,10 +114,11 @@ namespace Greenshot.Plugin.Office.OfficeExport { return false; } + LOG.DebugFormat("Got {0} inspectors to check", inspectors.ComObject.Count); for (int i = 1; i <= inspectors.ComObject.Count; i++) { - using var inspector = DisposableCom.Create((_Inspector)inspectors.ComObject[i]); + using var inspector = DisposableCom.Create((_Inspector) inspectors.ComObject[i]); string currentCaption = inspector.ComObject.Caption; if (!currentCaption.StartsWith(inspectorCaption)) { @@ -130,6 +135,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { continue; } + try { return ExportToInspector(inspector, null, mailItem.Class, mailItem, tmpFile, attachmentName); @@ -138,9 +144,10 @@ namespace Greenshot.Plugin.Office.OfficeExport { LOG.Error($"Export to {currentCaption} failed.", exExport); } + break; case AppointmentItem appointmentItem: - if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) + if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) { if (!string.IsNullOrEmpty(appointmentItem.Organizer) && !appointmentItem.Organizer.Equals(_currentUser)) { @@ -153,6 +160,7 @@ namespace Greenshot.Plugin.Office.OfficeExport // skip, can't export to olAppointment continue; } + try { return ExportToInspector(inspector, null, appointmentItem.Class, null, tmpFile, attachmentName); @@ -161,6 +169,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { LOG.Error($"Export to {currentCaption} failed.", exExport); } + break; default: continue; @@ -168,6 +177,7 @@ namespace Greenshot.Plugin.Office.OfficeExport } } } + return false; } @@ -181,7 +191,8 @@ namespace Greenshot.Plugin.Office.OfficeExport /// /// /// - private bool ExportToInspector(IDisposableCom<_Inspector> inspector, IDisposableCom<_Explorer> explorer, OlObjectClass itemClass, MailItem mailItem, string tmpFile, string attachmentName) + private bool ExportToInspector(IDisposableCom<_Inspector> inspector, IDisposableCom<_Explorer> explorer, OlObjectClass itemClass, MailItem mailItem, string tmpFile, + string attachmentName) { bool isMail = OlObjectClass.olMail.Equals(itemClass); bool isAppointment = OlObjectClass.olAppointment.Equals(itemClass); @@ -190,6 +201,7 @@ namespace Greenshot.Plugin.Office.OfficeExport LOG.Warn("Item is no mail or appointment."); return false; } + try { // Make sure the inspector is activated, only this way the word editor is active! @@ -200,25 +212,27 @@ namespace Greenshot.Plugin.Office.OfficeExport { isTextFormat = OlBodyFormat.olFormatPlain.Equals(mailItem.BodyFormat); } + if (isAppointment || !isTextFormat) { // Check for wordmail, if so use the wordexporter // http://msdn.microsoft.com/en-us/library/dd492012%28v=office.12%29.aspx // Earlier versions of Outlook also supported an Inspector.HTMLEditor object property, but since Internet Explorer is no longer the rendering engine for HTML messages and posts, HTMLEditor is no longer supported. IDisposableCom<_Document> wordDocument = null; - if ((explorer != null) && (_outlookVersion.Major >= (int)OfficeVersions.Office2013)) + if ((explorer != null) && (_outlookVersion.Major >= (int) OfficeVersions.Office2013)) { // TODO: Needs to have the Microsoft Outlook 15.0 Object Library installed - wordDocument = DisposableCom.Create((_Document)explorer.ComObject.ActiveInlineResponseWordEditor); + wordDocument = DisposableCom.Create((_Document) explorer.ComObject.ActiveInlineResponseWordEditor); } else if (inspector != null) { if (inspector.ComObject.IsWordMail() && (inspector.ComObject.EditorType == OlEditorType.olEditorWord)) { - var tmpWordDocument = (_Document)inspector.ComObject.WordEditor; + var tmpWordDocument = (_Document) inspector.ComObject.WordEditor; wordDocument = DisposableCom.Create(tmpWordDocument); } } + if (wordDocument != null) { using (wordDocument) @@ -248,6 +262,7 @@ namespace Greenshot.Plugin.Office.OfficeExport LOG.Info("Trying export for outlook < 2007."); } } + // Only use mailitem as it should be filled!! if (mailItem != null) { @@ -255,7 +270,7 @@ namespace Greenshot.Plugin.Office.OfficeExport } string contentId; - if (_outlookVersion.Major >= (int)OfficeVersions.Office2007) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2007) { contentId = Guid.NewGuid().ToString(); } @@ -283,7 +298,7 @@ namespace Greenshot.Plugin.Office.OfficeExport var selection = document2.selection; if (selection != null) { - var range = (IHTMLTxtRange)selection.createRange(); + var range = (IHTMLTxtRange) selection.createRange(); if (range != null) { // First paste, than attach (otherwise the range is wrong!) @@ -315,7 +330,7 @@ namespace Greenshot.Plugin.Office.OfficeExport // Create the attachment (if inlined the attachment isn't visible as attachment!) using var attachments = DisposableCom.Create(mailItem.Attachments); using var attachment = DisposableCom.Create(attachments.ComObject.Add(tmpFile, OlAttachmentType.olByValue, inlinePossible ? 0 : 1, attachmentName)); - if (_outlookVersion.Major >= (int)OfficeVersions.Office2007) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2007) { // Add the content id to the attachment, this only works for Outlook >= 2007 try @@ -341,9 +356,11 @@ namespace Greenshot.Plugin.Office.OfficeExport { caption = explorer.ComObject.Caption; } + LOG.Warn($"Problem while trying to add attachment to Item '{caption}'", ex); return false; } + try { if (inspector != null) @@ -360,6 +377,7 @@ namespace Greenshot.Plugin.Office.OfficeExport LOG.Warn("Problem activating inspector/explorer: ", ex); return false; } + LOG.Debug("Finished!"); return true; } @@ -376,27 +394,32 @@ namespace Greenshot.Plugin.Office.OfficeExport /// /// /// - private void ExportToNewEmail(IDisposableCom outlookApplication, EmailFormat format, string tmpFile, string subject, string attachmentName, string to, string cc, string bcc, string url) + private void ExportToNewEmail(IDisposableCom outlookApplication, EmailFormat format, string tmpFile, string subject, string attachmentName, string to, + string cc, string bcc, string url) { - using var newItem = DisposableCom.Create((MailItem)outlookApplication.ComObject.CreateItem(OlItemType.olMailItem)); + using var newItem = DisposableCom.Create((MailItem) outlookApplication.ComObject.CreateItem(OlItemType.olMailItem)); if (newItem == null) { return; } + var newMail = newItem.ComObject; newMail.Subject = subject; if (!string.IsNullOrEmpty(to)) { newMail.To = to; } + if (!string.IsNullOrEmpty(cc)) { newMail.CC = cc; } + if (!string.IsNullOrEmpty(bcc)) { newMail.BCC = bcc; } + newMail.BodyFormat = OlBodyFormat.olFormatHTML; string bodyString = null; // Read the default signature, if nothing found use empty email @@ -408,6 +431,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { LOG.Error("Problem reading signature!", e); } + switch (format) { case EmailFormat.Text: @@ -421,9 +445,11 @@ namespace Greenshot.Plugin.Office.OfficeExport { bodyString = ""; } + newMail.Body = bodyString; } } + break; default: string contentId = Path.GetFileName(tmpFile); @@ -432,7 +458,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { using var attachment = DisposableCom.Create(attachments.ComObject.Add(tmpFile, OlAttachmentType.olByValue, 0, attachmentName)); // add content ID to the attachment - if (_outlookVersion.Major >= (int)OfficeVersions.Office2007) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2007) { try { @@ -456,6 +482,7 @@ namespace Greenshot.Plugin.Office.OfficeExport href = $""; hrefEnd = ""; } + string htmlImgEmbedded = $"
{href}\"{attachmentName}\"{hrefEnd}
"; string fallbackBody = $"{htmlImgEmbedded}"; if (bodyString == null) @@ -482,13 +509,15 @@ namespace Greenshot.Plugin.Office.OfficeExport bodyString = fallbackBody; } } + newMail.HTMLBody = bodyString; break; } + // So not save, otherwise the email is always stored in Draft folder.. (newMail.Save();) newMail.Display(false); - using var inspector = DisposableCom.Create((_Inspector)newMail.GetInspector); + using var inspector = DisposableCom.Create((_Inspector) newMail.GetInspector); if (inspector != null) { try @@ -528,12 +557,14 @@ namespace Greenshot.Plugin.Office.OfficeExport exported = true; } } + return exported; } catch (Exception e) { LOG.Error("Error while creating an outlook mail item: ", e); } + return exported; } @@ -548,6 +579,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { outlookApplication = DisposableCom.Create(new Application()); } + InitializeVariables(outlookApplication); return outlookApplication; } @@ -568,10 +600,12 @@ namespace Greenshot.Plugin.Office.OfficeExport // Ignore, probably no outlook running return null; } + if ((outlookApplication != null) && (outlookApplication.ComObject != null)) { InitializeVariables(outlookApplication); } + return outlookApplication; } @@ -587,7 +621,8 @@ namespace Greenshot.Plugin.Office.OfficeExport { return null; } - string defaultProfile = (string)profilesKey.GetValue(DefaultProfileValue); + + string defaultProfile = (string) profilesKey.GetValue(DefaultProfileValue); LOG.DebugFormat("defaultProfile={0}", defaultProfile); using var profileKey = profilesKey.OpenSubKey(defaultProfile + @"\" + AccountKey, false); if (profileKey != null) @@ -599,19 +634,21 @@ namespace Greenshot.Plugin.Office.OfficeExport using var numberKey = profileKey.OpenSubKey(number, false); if (numberKey != null) { - byte[] val = (byte[])numberKey.GetValue(NewSignatureValue); + byte[] val = (byte[]) numberKey.GetValue(NewSignatureValue); if (val == null) { continue; } + string signatureName = ""; foreach (byte b in val) { if (b != 0) { - signatureName += (char)b; + signatureName += (char) b; } } + LOG.DebugFormat("Found email signature: {0}", signatureName); var extension = format switch { @@ -628,6 +665,7 @@ namespace Greenshot.Plugin.Office.OfficeExport } } } + return null; } @@ -642,13 +680,15 @@ namespace Greenshot.Plugin.Office.OfficeExport { return; } + if (!Version.TryParse(outlookApplication.ComObject.Version, out _outlookVersion)) { LOG.Warn("Assuming outlook version 1997."); - _outlookVersion = new Version((int)OfficeVersions.Office97, 0, 0, 0); + _outlookVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0); } + // Preventing retrieval of currentUser if Outlook is older than 2007 - if (_outlookVersion.Major >= (int)OfficeVersions.Office2007) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2007) { try { @@ -657,6 +697,7 @@ namespace Greenshot.Plugin.Office.OfficeExport using var currentUser = DisposableCom.Create(mapiNamespace.ComObject.CurrentUser); _currentUser = currentUser.ComObject.Name; } + LOG.InfoFormat("Current user: {0}", _currentUser); } catch (Exception exNs) @@ -682,7 +723,7 @@ namespace Greenshot.Plugin.Office.OfficeExport } // The activeexplorer inline response only works with >= 2013, Microsoft Outlook 15.0 Object Library - if (_outlookVersion.Major >= (int)OfficeVersions.Office2013) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2013) { // Check inline "panel" for Outlook 2013 using var activeExplorer = DisposableCom.Create(outlookApplication.ComObject.ActiveExplorer()); @@ -701,15 +742,17 @@ namespace Greenshot.Plugin.Office.OfficeExport { inspectorCaptions.Add(caption, mailItem.Class); } + break; case AppointmentItem appointmentItem: - if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) + if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) { if (!string.IsNullOrEmpty(appointmentItem.Organizer) && appointmentItem.Organizer.Equals(_currentUser)) { inspectorCaptions.Add(caption, appointmentItem.Class); } } + break; } } @@ -740,10 +783,11 @@ namespace Greenshot.Plugin.Office.OfficeExport { continue; } + inspectorCaptions.Add(caption, mailItem.Class); break; case AppointmentItem appointmentItem: - if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) + if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) { if (!string.IsNullOrEmpty(appointmentItem.Organizer) && !appointmentItem.Organizer.Equals(_currentUser)) { @@ -756,6 +800,7 @@ namespace Greenshot.Plugin.Office.OfficeExport // skip, can't export to olAppointment continue; } + inspectorCaptions.Add(caption, appointmentItem.Class); break; default: @@ -769,6 +814,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { LOG.Warn("Problem retrieving word destinations, ignoring: ", ex); } + return inspectorCaptions; } } diff --git a/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs index aaa473ddf..c2bc7e2b3 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs @@ -60,6 +60,7 @@ namespace Greenshot.Plugin.Office.OfficeExport left = pageSetup.ComObject.SlideWidth / 2 - imageSize.Width / 2f; top = pageSetup.ComObject.SlideHeight / 2 - imageSize.Height / 2f; } + float width = imageSize.Width; float height = imageSize.Height; IDisposableCom shapeForCaption = null; @@ -86,6 +87,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { shapeForLocation.ComObject.Left = left; } + shapeForLocation.ComObject.Width = imageSize.Width; if (height > shapeForLocation.ComObject.Height) @@ -98,6 +100,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { top = shapeForLocation.ComObject.Top + shapeForLocation.ComObject.Height / 2 - imageSize.Height / 2f; } + shapeForLocation.ComObject.Height = imageSize.Height; } catch (Exception e) @@ -106,6 +109,7 @@ namespace Greenshot.Plugin.Office.OfficeExport using var slides = DisposableCom.Create(presentation.ComObject.Slides); slide = DisposableCom.Create(slides.ComObject.Add(slides.ComObject.Count + 1, PpSlideLayout.ppLayoutBlank)); } + using (var shapes = DisposableCom.Create(slide.ComObject.Shapes)) { using var shape = DisposableCom.Create(shapes.ComObject.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, 0, 0, width, height)); @@ -117,20 +121,24 @@ namespace Greenshot.Plugin.Office.OfficeExport { shape.ComObject.LockAspectRatio = MsoTriState.msoFalse; } + shape.ComObject.ScaleHeight(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle); shape.ComObject.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle); if (hasScaledWidth) { shape.ComObject.Width = width; } + if (hasScaledHeight) { shape.ComObject.Height = height; } + shape.ComObject.Left = left; shape.ComObject.Top = top; shape.ComObject.AlternativeText = title; } + if (shapeForCaption != null) { try @@ -148,6 +156,7 @@ namespace Greenshot.Plugin.Office.OfficeExport LOG.Warn("Problem setting the title to a text-range", ex); } } + // Activate/Goto the slide try { @@ -194,10 +203,12 @@ namespace Greenshot.Plugin.Office.OfficeExport { continue; } + if (!presentation.ComObject.Name.StartsWith(presentationName)) { continue; } + try { AddPictureToPresentation(presentation, tmpFile, imageSize, title); @@ -209,6 +220,7 @@ namespace Greenshot.Plugin.Office.OfficeExport } } } + return false; } @@ -223,6 +235,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { powerPointApplication = DisposableCom.Create(new Application()); } + InitializeVariables(powerPointApplication); return powerPointApplication; } @@ -243,10 +256,12 @@ namespace Greenshot.Plugin.Office.OfficeExport // Ignore, probably no PowerPoint running return null; } + if (powerPointApplication?.ComObject != null) { InitializeVariables(powerPointApplication); } + return powerPointApplication; } @@ -271,10 +286,12 @@ namespace Greenshot.Plugin.Office.OfficeExport { continue; } + if (presentation.ComObject.ReadOnly == MsoTriState.msoTrue) { continue; } + if (IsAfter2003()) { if (presentation.ComObject.Final) @@ -282,6 +299,7 @@ namespace Greenshot.Plugin.Office.OfficeExport continue; } } + yield return presentation.ComObject.Name; } } @@ -296,10 +314,11 @@ namespace Greenshot.Plugin.Office.OfficeExport { return; } + if (!Version.TryParse(powerpointApplication.ComObject.Version, out _powerpointVersion)) { LOG.Warn("Assuming Powerpoint version 1997."); - _powerpointVersion = new Version((int)OfficeVersions.Office97, 0, 0, 0); + _powerpointVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0); } } @@ -332,13 +351,13 @@ namespace Greenshot.Plugin.Office.OfficeExport } } } + return isPictureAdded; } private bool IsAfter2003() { - return _powerpointVersion.Major > (int)OfficeVersions.Office2003; + return _powerpointVersion.Major > (int) OfficeVersions.Office2003; } } - } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs index ce4da64d2..0cef0c696 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs @@ -53,6 +53,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { shape.ComObject.LockAspectRatio = MsoTriState.msoTrue; } + selection.ComObject.InsertAfter("\r\n"); selection.ComObject.MoveDown(WdUnits.wdLine, 1, Type.Missing); return shape; @@ -69,6 +70,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { wordApplication = DisposableCom.Create(new Application()); } + InitializeVariables(wordApplication); return wordApplication; } @@ -89,10 +91,12 @@ namespace Greenshot.Plugin.Office.OfficeExport // Ignore, probably no word running return null; } + if ((wordApplication != null) && (wordApplication.ComObject != null)) { InitializeVariables(wordApplication); } + return wordApplication; } @@ -116,6 +120,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { continue; } + if (IsAfter2003()) { if (document.ComObject.Final) @@ -139,10 +144,11 @@ namespace Greenshot.Plugin.Office.OfficeExport { return; } + if (!Version.TryParse(wordApplication.ComObject.Version, out _wordVersion)) { LOG.Warn("Assuming Word version 1997."); - _wordVersion = new Version((int)OfficeVersions.Office97, 0, 0, 0); + _wordVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0); } } @@ -164,7 +170,7 @@ namespace Greenshot.Plugin.Office.OfficeExport using var documents = DisposableCom.Create(wordApplication.ComObject.Documents); for (int i = 1; i <= documents.ComObject.Count; i++) { - using var wordDocument = DisposableCom.Create((_Document)documents.ComObject[i]); + using var wordDocument = DisposableCom.Create((_Document) documents.ComObject[i]); using var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow); if (activeWindow.ComObject.Caption.StartsWith(wordCaption)) { @@ -172,6 +178,7 @@ namespace Greenshot.Plugin.Office.OfficeExport } } } + return false; } @@ -184,7 +191,8 @@ namespace Greenshot.Plugin.Office.OfficeExport /// string /// string with the tooltip of the image /// bool - internal bool InsertIntoExistingDocument(IDisposableCom wordApplication, IDisposableCom<_Document> wordDocument, string tmpFile, string address, string tooltip) + internal bool InsertIntoExistingDocument(IDisposableCom wordApplication, IDisposableCom<_Document> wordDocument, string tmpFile, string address, + string tooltip) { // Bug #1517: image will be inserted into that document, where the focus was last. It will not inserted into the chosen one. // Solution: Make sure the selected document is active, otherwise the insert will be made in a different document! @@ -204,6 +212,7 @@ namespace Greenshot.Plugin.Office.OfficeExport LOG.InfoFormat("No selection to insert {0} into found.", tmpFile); return false; } + // Add Picture using (var shape = AddPictureToSelection(selection, tmpFile)) { @@ -214,6 +223,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { screentip = tooltip; } + try { using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks); @@ -225,6 +235,7 @@ namespace Greenshot.Plugin.Office.OfficeExport } } } + try { // When called for Outlook, the follow error is created: This object model command is not available in e-mail @@ -245,6 +256,7 @@ namespace Greenshot.Plugin.Office.OfficeExport LOG.WarnFormat("Couldn't set zoom to 100, error: {0}", e.Message); } } + try { wordApplication.ComObject.Activate(); @@ -254,6 +266,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { LOG.Warn("Error activating word application", ex); } + try { wordDocument.ComObject.Activate(); @@ -263,6 +276,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { LOG.Warn("Error activating word document", ex); } + return true; } @@ -279,6 +293,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { return; } + wordApplication.ComObject.Visible = true; wordApplication.ComObject.Activate(); // Create new Document @@ -299,6 +314,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { screentip = tooltip; } + try { using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks); @@ -313,6 +329,7 @@ namespace Greenshot.Plugin.Office.OfficeExport } } } + try { wordDocument.ComObject.Activate(); @@ -322,6 +339,7 @@ namespace Greenshot.Plugin.Office.OfficeExport { LOG.Warn("Error activating word document", ex); } + try { using var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow); @@ -340,7 +358,7 @@ namespace Greenshot.Plugin.Office.OfficeExport /// private bool IsAfter2003() { - return _wordVersion.Major > (int)OfficeVersions.Office2003; + return _wordVersion.Major > (int) OfficeVersions.Office2003; } } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs b/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs index 55c347c5e..ea78fce8b 100644 --- a/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs +++ b/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs @@ -19,18 +19,19 @@ namespace Greenshot.Plugin.Office.OfficeInterop { - /// - /// Specifies which EmailFormat the email needs to use - /// - public enum EmailFormat - { + /// + /// Specifies which EmailFormat the email needs to use + /// + public enum EmailFormat + { /// /// Use the plain text format /// - Text, + Text, + /// /// Use HTML format /// - Html - } + Html + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs b/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs index ef74d6f9a..321e6de2f 100644 --- a/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs +++ b/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs @@ -19,38 +19,44 @@ namespace Greenshot.Plugin.Office.OfficeInterop { - /// - /// A mapping between the version and a usable name - /// - public enum OfficeVersions - { + /// + /// A mapping between the version and a usable name + /// + public enum OfficeVersions + { /// /// Office 97 /// - Office97 = 8, + Office97 = 8, + /// /// Office 2003 /// - Office2003 = 11, + Office2003 = 11, + /// /// Office 2007 /// - Office2007 = 12, + Office2007 = 12, + /// /// Office 2010 /// - Office2010 = 14, + Office2010 = 14, + /// /// Office 2013 /// - Office2013 = 15, + Office2013 = 15, + /// /// Office 2016 /// Office2016 = 16, + /// /// Office 2019 /// Office2019 = 17 - } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/OfficePlugin.cs b/src/Greenshot.Plugin.Office/OfficePlugin.cs index 7abdecf02..c7e75afcd 100644 --- a/src/Greenshot.Plugin.Office/OfficePlugin.cs +++ b/src/Greenshot.Plugin.Office/OfficePlugin.cs @@ -26,91 +26,123 @@ using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Office { - /// - /// This is the OfficePlugin base code - /// +namespace Greenshot.Plugin.Office +{ + /// + /// This is the OfficePlugin base code + /// [Plugin("Office", false)] public class OfficePlugin : IGreenshotPlugin { - private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OfficePlugin)); + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OfficePlugin)); - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected void Dispose(bool disposing) { - // Do nothing - } + protected void Dispose(bool disposing) + { + // Do nothing + } - private IEnumerable Destinations() { - IDestination destination; - try { - destination = new ExcelDestination(); - } catch { - destination = null; - } - if (destination != null) { - yield return destination; - } + private IEnumerable Destinations() + { + IDestination destination; + try + { + destination = new ExcelDestination(); + } + catch + { + destination = null; + } - try { - destination = new PowerpointDestination(); - } catch { - destination = null; - } - if (destination != null) { - yield return destination; - } + if (destination != null) + { + yield return destination; + } - try { - destination = new WordDestination(); - } catch { - destination = null; - } - if (destination != null) { - yield return destination; - } + try + { + destination = new PowerpointDestination(); + } + catch + { + destination = null; + } - try { - destination = new OutlookDestination(); - } catch { - destination = null; - } - if (destination != null) { - yield return destination; - } + if (destination != null) + { + yield return destination; + } - try { - destination = new OneNoteDestination(); - } catch { - destination = null; - } - if (destination != null) { - yield return destination; - } - } + try + { + destination = new WordDestination(); + } + catch + { + destination = null; + } + + if (destination != null) + { + yield return destination; + } + + try + { + destination = new OutlookDestination(); + } + catch + { + destination = null; + } + + if (destination != null) + { + yield return destination; + } + + try + { + destination = new OneNoteDestination(); + } + catch + { + destination = null; + } + + if (destination != null) + { + yield return destination; + } + } - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - /// true if plugin is initialized, false if not (doesn't show) - public bool Initialize() { + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// true if plugin is initialized, false if not (doesn't show) + public bool Initialize() + { SimpleServiceProvider.Current.AddService(Destinations()); - return true; - } - - public void Shutdown() { - LOG.Debug("Office Plugin shutdown."); - } + return true; + } - /// - /// Implementation of the IPlugin.Configure - /// - public void Configure() { + public void Shutdown() + { + LOG.Debug("Office Plugin shutdown."); + } + + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { throw new NotImplementedException(); - } - } -} + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs index 3e2563a07..a65ac387f 100644 --- a/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs b/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs index 09e3bc3ca..6bf170ca5 100644 --- a/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs +++ b/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs @@ -19,10 +19,12 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.Photobucket.Forms { - /// - /// This class is needed for design-time resolving of the language files - /// - public class PhotobucketForm : GreenshotPlugin.Controls.GreenshotForm { - } -} +namespace Greenshot.Plugin.Photobucket.Forms +{ + /// + /// This class is needed for design-time resolving of the language files + /// + public class PhotobucketForm : GreenshotPlugin.Controls.GreenshotForm + { + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs index 9d380bdd8..b6a51f8ae 100644 --- a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs @@ -19,19 +19,21 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.Photobucket.Forms { - /// - /// Description of PasswordRequestForm. - /// - public partial class SettingsForm : PhotobucketForm { - public SettingsForm() - { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - AcceptButton = buttonOK; - CancelButton = buttonCancel; - } - } -} +namespace Greenshot.Plugin.Photobucket.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : PhotobucketForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = buttonOK; + CancelButton = buttonCancel; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs b/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs index 8795b92f0..e9ac6058b 100644 --- a/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs @@ -19,11 +19,13 @@ * along with this program. If not, see . */ -namespace Greenshot.Plugin.Photobucket { - public enum LangKey { - upload_menu_item, - upload_failure, - communication_wait, - configure - } -} +namespace Greenshot.Plugin.Photobucket +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + configure + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs index cf2501cd0..4c1c976d2 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs @@ -25,46 +25,56 @@ using GreenshotPlugin.Controls; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; -namespace Greenshot.Plugin.Photobucket { - /// - /// Description of PhotobucketConfiguration. - /// - [IniSection("Photobucket", Description="Greenshot Photobucket Plugin configuration")] - public class PhotobucketConfiguration : IniSection { - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat { get; set; } - [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality { get; set; } - [IniProperty("UploadReduceColors", Description="Reduce color amount of the uploaded image to 256", DefaultValue="False")] - public bool UploadReduceColors { get; set; } - [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] - public bool UsePageLink { get; set; } - [IniProperty("Token", Description = "The Photobucket token", Encrypted=true, ExcludeIfNull=true)] - public string Token { get; set; } - [IniProperty("TokenSecret", Description = "The Photobucket token secret", Encrypted=true, ExcludeIfNull=true)] - public string TokenSecret { get; set; } - [IniProperty("SubDomain", Description = "The Photobucket api subdomain", Encrypted = true, ExcludeIfNull = true)] - public string SubDomain { get; set; } - [IniProperty("Username", Description = "The Photobucket api username", ExcludeIfNull = true)] - public string Username { get; set; } +namespace Greenshot.Plugin.Photobucket +{ + /// + /// Description of PhotobucketConfiguration. + /// + [IniSection("Photobucket", Description = "Greenshot Photobucket Plugin configuration")] + public class PhotobucketConfiguration : IniSection + { + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] + public bool UploadReduceColors { get; set; } + + [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] + public bool UsePageLink { get; set; } + + [IniProperty("Token", Description = "The Photobucket token", Encrypted = true, ExcludeIfNull = true)] + public string Token { get; set; } + + [IniProperty("TokenSecret", Description = "The Photobucket token secret", Encrypted = true, ExcludeIfNull = true)] + public string TokenSecret { get; set; } + + [IniProperty("SubDomain", Description = "The Photobucket api subdomain", Encrypted = true, ExcludeIfNull = true)] + public string SubDomain { get; set; } + + [IniProperty("Username", Description = "The Photobucket api username", ExcludeIfNull = true)] + public string Username { get; set; } /// - /// A form for username/password - /// - /// bool true if OK was pressed, false if cancel - public bool ShowConfigDialog() { - SettingsForm settingsForm = null; + /// A form for username/password + ///
+ /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + SettingsForm settingsForm = null; - new PleaseWaitForm().ShowAndWait("Photobucket", Language.GetString("photobucket", LangKey.communication_wait), - delegate { - settingsForm = new SettingsForm(); - } - ); - DialogResult result = settingsForm.ShowDialog(); - if (result == DialogResult.OK) { - return true; - } - return false; - } - } -} + new PleaseWaitForm().ShowAndWait("Photobucket", Language.GetString("photobucket", LangKey.communication_wait), + delegate { settingsForm = new SettingsForm(); } + ); + DialogResult result = settingsForm.ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs index 564e64511..34bffa89b 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs @@ -25,78 +25,95 @@ using System.Drawing; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace Greenshot.Plugin.Photobucket { - /// - /// Description of PhotobucketDestination. - /// - public class PhotobucketDestination : AbstractDestination { - private readonly PhotobucketPlugin _plugin; - private readonly string _albumPath; +namespace Greenshot.Plugin.Photobucket +{ + /// + /// Description of PhotobucketDestination. + /// + public class PhotobucketDestination : AbstractDestination + { + private readonly PhotobucketPlugin _plugin; + private readonly string _albumPath; - /// - /// Create a Photobucket destination, which also has the path to the album in it - /// - /// - /// path to the album, null for default - public PhotobucketDestination(PhotobucketPlugin plugin, string albumPath = null) { - _plugin = plugin; - _albumPath = albumPath; - } - - public override string Designation => "Photobucket"; + /// + /// Create a Photobucket destination, which also has the path to the album in it + /// + /// + /// path to the album, null for default + public PhotobucketDestination(PhotobucketPlugin plugin, string albumPath = null) + { + _plugin = plugin; + _albumPath = albumPath; + } - public override string Description { - get { - if (_albumPath != null) { - return _albumPath; - } - return Language.GetString("photobucket", LangKey.upload_menu_item); - } - } + public override string Designation => "Photobucket"; - public override Image DisplayIcon { - get { - ComponentResourceManager resources = new ComponentResourceManager(typeof(PhotobucketPlugin)); - return (Image)resources.GetObject("Photobucket"); - } - } - - public override bool IsDynamic => true; + public override string Description + { + get + { + if (_albumPath != null) + { + return _albumPath; + } - public override IEnumerable DynamicDestinations() { - IList albums = null; - try { - albums = PhotobucketUtils.RetrievePhotobucketAlbums(); - } - catch - { - // ignored - } + return Language.GetString("photobucket", LangKey.upload_menu_item); + } + } - if (albums == null || albums.Count == 0) { - yield break; - } - foreach (string album in albums) { - yield return new PhotobucketDestination(_plugin, album); - } - } + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(PhotobucketPlugin)); + return (Image) resources.GetObject("Photobucket"); + } + } - /// - /// Export the capture to Photobucket - /// - /// - /// - /// - /// - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); + public override bool IsDynamic => true; + + public override IEnumerable DynamicDestinations() + { + IList albums = null; + try + { + albums = PhotobucketUtils.RetrievePhotobucketAlbums(); + } + catch + { + // ignored + } + + if (albums == null || albums.Count == 0) + { + yield break; + } + + foreach (string album in albums) + { + yield return new PhotobucketDestination(_plugin, album); + } + } + + /// + /// Export the capture to Photobucket + /// + /// + /// + /// + /// + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); bool uploaded = _plugin.Upload(captureDetails, surface, _albumPath, out var uploadUrl); - if (uploaded) { - exportInformation.ExportMade = true; - exportInformation.Uri = uploadUrl; - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + if (uploaded) + { + exportInformation.ExportMade = true; + exportInformation.Uri = uploadUrl; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs index 98b3b7517..7cb584b72 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs @@ -24,45 +24,56 @@ using System.Xml; namespace Greenshot.Plugin.Photobucket { - /// - /// Description of PhotobucketInfo. - /// - public class PhotobucketInfo { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketInfo)); + /// + /// Description of PhotobucketInfo. + /// + public class PhotobucketInfo + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketInfo)); - public string Original { get; set; } + public string Original { get; set; } - public string Page { get; set; } + public string Page { get; set; } - public string Thumbnail { get; set; } + public string Thumbnail { get; set; } - /// - /// Parse the upload response - /// - /// XML - /// PhotobucketInfo object - public static PhotobucketInfo FromUploadResponse(string response) { - Log.Debug(response); - PhotobucketInfo photobucketInfo = new PhotobucketInfo(); - try { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(response); - var nodes = doc.GetElementsByTagName("url"); - if(nodes.Count > 0) { - photobucketInfo.Original = nodes.Item(0)?.InnerText; - } - nodes = doc.GetElementsByTagName("browseurl"); - if(nodes.Count > 0) { - photobucketInfo.Page = nodes.Item(0)?.InnerText; - } - nodes = doc.GetElementsByTagName("thumb"); - if(nodes.Count > 0) { - photobucketInfo.Thumbnail = nodes.Item(0)?.InnerText; - } - } catch(Exception e) { - Log.ErrorFormat("Could not parse Photobucket response due to error {0}, response was: {1}", e.Message, response); - } - return photobucketInfo; - } - } -} + /// + /// Parse the upload response + /// + /// XML + /// PhotobucketInfo object + public static PhotobucketInfo FromUploadResponse(string response) + { + Log.Debug(response); + PhotobucketInfo photobucketInfo = new PhotobucketInfo(); + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + var nodes = doc.GetElementsByTagName("url"); + if (nodes.Count > 0) + { + photobucketInfo.Original = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("browseurl"); + if (nodes.Count > 0) + { + photobucketInfo.Page = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("thumb"); + if (nodes.Count > 0) + { + photobucketInfo.Thumbnail = nodes.Item(0)?.InnerText; + } + } + catch (Exception e) + { + Log.ErrorFormat("Could not parse Photobucket response due to error {0}, response was: {1}", e.Message, response); + } + + return photobucketInfo; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs index b45f563e0..394707897 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs @@ -30,23 +30,26 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Photobucket { - /// - /// This is the GreenshotPhotobucketPlugin base code - /// - [Plugin("Photobucket", true)] - public class PhotobucketPlugin : IGreenshotPlugin { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketPlugin)); - private static PhotobucketConfiguration _config; - private ComponentResourceManager _resources; - private ToolStripMenuItem _itemPlugInConfig; +namespace Greenshot.Plugin.Photobucket +{ + /// + /// This is the GreenshotPhotobucketPlugin base code + /// + [Plugin("Photobucket", true)] + public class PhotobucketPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketPlugin)); + private static PhotobucketConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInConfig; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected void Dispose(bool disposing) + protected void Dispose(bool disposing) { if (!disposing) return; if (_itemPlugInConfig == null) return; @@ -54,89 +57,102 @@ namespace Greenshot.Plugin.Photobucket { _itemPlugInConfig = null; } - /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - /// true if plugin is initialized, false if not (doesn't show) - public bool Initialize() { + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// true if plugin is initialized, false if not (doesn't show) + public bool Initialize() + { SimpleServiceProvider.Current.AddService(new PhotobucketDestination(this)); - // Get configuration - _config = IniConfig.GetIniSection(); - _resources = new ComponentResourceManager(typeof(PhotobucketPlugin)); + // Get configuration + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(PhotobucketPlugin)); - _itemPlugInConfig = new ToolStripMenuItem(Language.GetString("photobucket", LangKey.configure)) - { - Image = (Image)_resources.GetObject("Photobucket") - }; - _itemPlugInConfig.Click += delegate { - _config.ShowConfigDialog(); - }; + _itemPlugInConfig = new ToolStripMenuItem(Language.GetString("photobucket", LangKey.configure)) + { + Image = (Image) _resources.GetObject("Photobucket") + }; + _itemPlugInConfig.Click += delegate { _config.ShowConfigDialog(); }; - PluginUtils.AddToContextMenu(_itemPlugInConfig); - Language.LanguageChanged += OnLanguageChanged; - return true; - } + PluginUtils.AddToContextMenu(_itemPlugInConfig); + Language.LanguageChanged += OnLanguageChanged; + return true; + } - public void OnLanguageChanged(object sender, EventArgs e) { - if (_itemPlugInConfig != null) { - _itemPlugInConfig.Text = Language.GetString("photobucket", LangKey.configure); - } - } + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Text = Language.GetString("photobucket", LangKey.configure); + } + } - public void Shutdown() { - Log.Debug("Photobucket Plugin shutdown."); - Language.LanguageChanged -= OnLanguageChanged; - } + public void Shutdown() + { + Log.Debug("Photobucket Plugin shutdown."); + Language.LanguageChanged -= OnLanguageChanged; + } - /// - /// Implementation of the IPlugin.Configure - /// - public void Configure() { - _config.ShowConfigDialog(); - } + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + _config.ShowConfigDialog(); + } - /// - /// Upload the capture to Photobucket - /// - /// - /// ISurface - /// Path to the album - /// out string for the url - /// true if the upload succeeded - public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, string albumPath, out string uploadUrl) { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, _config.UploadReduceColors); - try { - string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); - PhotobucketInfo photobucketInfo = null; - - // Run upload in the background - new PleaseWaitForm().ShowAndWait("Photobucket", Language.GetString("photobucket", LangKey.communication_wait), - delegate { - photobucketInfo = PhotobucketUtils.UploadToPhotobucket(surfaceToUpload, outputSettings, albumPath, captureDetails.Title, filename); - } - ); - // This causes an exeption if the upload failed :) - Log.DebugFormat("Uploaded to Photobucket page: " + photobucketInfo.Page); - uploadUrl = null; - try { - if (_config.UsePageLink) { - uploadUrl = photobucketInfo.Page; - Clipboard.SetText(photobucketInfo.Page); - } else { - uploadUrl = photobucketInfo.Original; - Clipboard.SetText(photobucketInfo.Original); - } - } catch (Exception ex) { - Log.Error("Can't write to clipboard: ", ex); - } - return true; - } catch (Exception e) { - Log.Error(e); - MessageBox.Show(Language.GetString("photobucket", LangKey.upload_failure) + " " + e.Message); - } - uploadUrl = null; - return false; - } - } -} + /// + /// Upload the capture to Photobucket + /// + /// + /// ISurface + /// Path to the album + /// out string for the url + /// true if the upload succeeded + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, string albumPath, out string uploadUrl) + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, _config.UploadReduceColors); + try + { + string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); + PhotobucketInfo photobucketInfo = null; + + // Run upload in the background + new PleaseWaitForm().ShowAndWait("Photobucket", Language.GetString("photobucket", LangKey.communication_wait), + delegate { photobucketInfo = PhotobucketUtils.UploadToPhotobucket(surfaceToUpload, outputSettings, albumPath, captureDetails.Title, filename); } + ); + // This causes an exeption if the upload failed :) + Log.DebugFormat("Uploaded to Photobucket page: " + photobucketInfo.Page); + uploadUrl = null; + try + { + if (_config.UsePageLink) + { + uploadUrl = photobucketInfo.Page; + Clipboard.SetText(photobucketInfo.Page); + } + else + { + uploadUrl = photobucketInfo.Original; + Clipboard.SetText(photobucketInfo.Original); + } + } + catch (Exception ex) + { + Log.Error("Can't write to clipboard: ", ex); + } + + return true; + } + catch (Exception e) + { + Log.Error(e); + MessageBox.Show(Language.GetString("photobucket", LangKey.upload_failure) + " " + e.Message); + } + + uploadUrl = null; + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs index eeda1ae74..61a61f8a3 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs @@ -30,197 +30,264 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Plugin.Photobucket { - /// - /// Description of PhotobucketUtils. - /// - public static class PhotobucketUtils { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketUtils)); - private static readonly PhotobucketConfiguration PhotobucketConfig = IniConfig.GetIniSection(); - private static List _albumsCache; +namespace Greenshot.Plugin.Photobucket +{ + /// + /// Description of PhotobucketUtils. + /// + public static class PhotobucketUtils + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketUtils)); + private static readonly PhotobucketConfiguration PhotobucketConfig = IniConfig.GetIniSection(); + private static List _albumsCache; - /// - /// Do the actual upload to Photobucket - /// For more details on the available parameters, see: http://api.Photobucket.com/resources_anon - /// - /// PhotobucketResponse - public static PhotobucketInfo UploadToPhotobucket(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string albumPath, string title, string filename) { - string responseString; - - var oAuth = CreateSession(true); - if (oAuth == null) { - return null; - } - IDictionary signedParameters = new Dictionary(); - // add album - if (string.IsNullOrEmpty(albumPath)) - { - signedParameters.Add("id", string.IsNullOrEmpty(PhotobucketConfig.Username) ? "!" : PhotobucketConfig.Username); - } else { - signedParameters.Add("id", albumPath); - } - // add type - signedParameters.Add("type", "image"); - // add title - if (title != null) { - signedParameters.Add("title", title); - } - // add filename - if (filename != null) { - signedParameters.Add("filename", filename); - } - IDictionary unsignedParameters = new Dictionary - { - // Add image - { "uploadfile", new SurfaceContainer(surfaceToUpload, outputSettings, filename) } - }; - try { - string apiUrl = "http://api.photobucket.com/album/!/upload"; - responseString = oAuth.MakeOAuthRequest(HTTPMethod.POST, apiUrl, apiUrl.Replace("api.photobucket.com", PhotobucketConfig.SubDomain), signedParameters, unsignedParameters, null); - } catch (Exception ex) { - Log.Error("Error uploading to Photobucket.", ex); - throw; - } finally { - if (!string.IsNullOrEmpty(oAuth.Token)) { - PhotobucketConfig.Token = oAuth.Token; - } - if (!string.IsNullOrEmpty(oAuth.TokenSecret)) { - PhotobucketConfig.TokenSecret = oAuth.TokenSecret; - } - } - if (responseString == null) { - return null; - } - Log.Info(responseString); - var photobucketInfo = PhotobucketInfo.FromUploadResponse(responseString); - Log.Debug("Upload to Photobucket was finished"); - return photobucketInfo; - } - - /// - /// Helper method to create an OAuth session object for contacting the Photobucket API - /// - /// OAuthSession - private static OAuthSession CreateSession(bool autoLogin) { - var oAuth = new OAuthSession(PhotobucketCredentials.ConsumerKey, PhotobucketCredentials.ConsumerSecret) - { - AutoLogin = autoLogin, - CheckVerifier = false, - CallbackUrl = "http://getgreenshot.org", - AccessTokenUrl = "http://api.photobucket.com/login/access", - AuthorizeUrl = "http://photobucket.com/apilogin/login", - RequestTokenUrl = "http://api.photobucket.com/login/request", - BrowserSize = new Size(1010, 400), - RequestTokenMethod = HTTPMethod.POST, - AccessTokenMethod = HTTPMethod.POST, - LoginTitle = "Photobucket authorization" - }; - // This url is configured in the Photobucket API settings in the Photobucket site!! - // Photobucket is very particular about the used methods! + /// + /// Do the actual upload to Photobucket + /// For more details on the available parameters, see: http://api.Photobucket.com/resources_anon + /// + /// PhotobucketResponse + public static PhotobucketInfo UploadToPhotobucket(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string albumPath, string title, string filename) + { + string responseString; - if (string.IsNullOrEmpty(PhotobucketConfig.SubDomain) || string.IsNullOrEmpty(PhotobucketConfig.Token) || string.IsNullOrEmpty(PhotobucketConfig.Username)) { - if (!autoLogin) { - return null; - } - if (!oAuth.Authorize()) { - return null; - } - if (!string.IsNullOrEmpty(oAuth.Token)) { - PhotobucketConfig.Token = oAuth.Token; - } - if (!string.IsNullOrEmpty(oAuth.TokenSecret)) { - PhotobucketConfig.TokenSecret = oAuth.TokenSecret; - } - if (oAuth.AccessTokenResponseParameters?["subdomain"] != null) { - PhotobucketConfig.SubDomain = oAuth.AccessTokenResponseParameters["subdomain"]; - } - if (oAuth.AccessTokenResponseParameters?["username"] != null) { - PhotobucketConfig.Username = oAuth.AccessTokenResponseParameters["username"]; - } - IniConfig.Save(); - } - oAuth.Token = PhotobucketConfig.Token; - oAuth.TokenSecret = PhotobucketConfig.TokenSecret; - return oAuth; - } + var oAuth = CreateSession(true); + if (oAuth == null) + { + return null; + } - /// - /// Get list of photobucket albums - /// - /// List of string - public static IList RetrievePhotobucketAlbums() { - if (_albumsCache != null) { - return _albumsCache; - } - string responseString; + IDictionary signedParameters = new Dictionary(); + // add album + if (string.IsNullOrEmpty(albumPath)) + { + signedParameters.Add("id", string.IsNullOrEmpty(PhotobucketConfig.Username) ? "!" : PhotobucketConfig.Username); + } + else + { + signedParameters.Add("id", albumPath); + } - OAuthSession oAuth = CreateSession(false); - if (oAuth == null) { - return null; - } - IDictionary signedParameters = new Dictionary(); - try { - string apiUrl = $"http://api.photobucket.com/album/{PhotobucketConfig.Username}"; - responseString = oAuth.MakeOAuthRequest(HTTPMethod.GET, apiUrl, apiUrl.Replace("api.photobucket.com", PhotobucketConfig.SubDomain), signedParameters, null, null); - } catch (Exception ex) { - Log.Error("Error uploading to Photobucket.", ex); - throw; - } finally { - if (!string.IsNullOrEmpty(oAuth.Token)) { - PhotobucketConfig.Token = oAuth.Token; - } - if (!string.IsNullOrEmpty(oAuth.TokenSecret)) { - PhotobucketConfig.TokenSecret = oAuth.TokenSecret; - } - } - if (responseString == null) { - return null; - } - try { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(responseString); - List albums = new List(); - var xmlNode = doc.GetElementsByTagName("content").Item(0); - if (xmlNode != null) - { - RecurseAlbums(albums, null, xmlNode.ChildNodes); - } - Log.DebugFormat("Albums: {0}", string.Join(",", albums.ToArray())); - _albumsCache = albums; - return albums; - } catch(Exception e) { - Log.Error("Error while Reading albums: ", e); - } + // add type + signedParameters.Add("type", "image"); + // add title + if (title != null) + { + signedParameters.Add("title", title); + } - Log.Debug("Upload to Photobucket was finished"); - return null; - } - - /// - /// Parse the album nodes recursively - /// - /// - /// - /// - private static void RecurseAlbums(ICollection albums, string path, IEnumerable nodes) { - foreach(XmlNode node in nodes) { - if (node.Name != "album") { - continue; - } - if (node.Attributes != null) - { - string currentAlbum = node.Attributes["name"].Value; - string currentPath = currentAlbum; - if (!string.IsNullOrEmpty(path)) { - currentPath = $"{path}/{currentAlbum}"; - } - - albums.Add(currentPath); - if (node.Attributes["subalbum_count"] != null && node.Attributes["subalbum_count"].Value != "0") { - RecurseAlbums(albums, currentPath, node.ChildNodes); - } - } - } - } - } -} + // add filename + if (filename != null) + { + signedParameters.Add("filename", filename); + } + + IDictionary unsignedParameters = new Dictionary + { + // Add image + { + "uploadfile", new SurfaceContainer(surfaceToUpload, outputSettings, filename) + } + }; + try + { + string apiUrl = "http://api.photobucket.com/album/!/upload"; + responseString = oAuth.MakeOAuthRequest(HTTPMethod.POST, apiUrl, apiUrl.Replace("api.photobucket.com", PhotobucketConfig.SubDomain), signedParameters, + unsignedParameters, null); + } + catch (Exception ex) + { + Log.Error("Error uploading to Photobucket.", ex); + throw; + } + finally + { + if (!string.IsNullOrEmpty(oAuth.Token)) + { + PhotobucketConfig.Token = oAuth.Token; + } + + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) + { + PhotobucketConfig.TokenSecret = oAuth.TokenSecret; + } + } + + if (responseString == null) + { + return null; + } + + Log.Info(responseString); + var photobucketInfo = PhotobucketInfo.FromUploadResponse(responseString); + Log.Debug("Upload to Photobucket was finished"); + return photobucketInfo; + } + + /// + /// Helper method to create an OAuth session object for contacting the Photobucket API + /// + /// OAuthSession + private static OAuthSession CreateSession(bool autoLogin) + { + var oAuth = new OAuthSession(PhotobucketCredentials.ConsumerKey, PhotobucketCredentials.ConsumerSecret) + { + AutoLogin = autoLogin, + CheckVerifier = false, + CallbackUrl = "http://getgreenshot.org", + AccessTokenUrl = "http://api.photobucket.com/login/access", + AuthorizeUrl = "http://photobucket.com/apilogin/login", + RequestTokenUrl = "http://api.photobucket.com/login/request", + BrowserSize = new Size(1010, 400), + RequestTokenMethod = HTTPMethod.POST, + AccessTokenMethod = HTTPMethod.POST, + LoginTitle = "Photobucket authorization" + }; + // This url is configured in the Photobucket API settings in the Photobucket site!! + // Photobucket is very particular about the used methods! + + if (string.IsNullOrEmpty(PhotobucketConfig.SubDomain) || string.IsNullOrEmpty(PhotobucketConfig.Token) || string.IsNullOrEmpty(PhotobucketConfig.Username)) + { + if (!autoLogin) + { + return null; + } + + if (!oAuth.Authorize()) + { + return null; + } + + if (!string.IsNullOrEmpty(oAuth.Token)) + { + PhotobucketConfig.Token = oAuth.Token; + } + + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) + { + PhotobucketConfig.TokenSecret = oAuth.TokenSecret; + } + + if (oAuth.AccessTokenResponseParameters?["subdomain"] != null) + { + PhotobucketConfig.SubDomain = oAuth.AccessTokenResponseParameters["subdomain"]; + } + + if (oAuth.AccessTokenResponseParameters?["username"] != null) + { + PhotobucketConfig.Username = oAuth.AccessTokenResponseParameters["username"]; + } + + IniConfig.Save(); + } + + oAuth.Token = PhotobucketConfig.Token; + oAuth.TokenSecret = PhotobucketConfig.TokenSecret; + return oAuth; + } + + /// + /// Get list of photobucket albums + /// + /// List of string + public static IList RetrievePhotobucketAlbums() + { + if (_albumsCache != null) + { + return _albumsCache; + } + + string responseString; + + OAuthSession oAuth = CreateSession(false); + if (oAuth == null) + { + return null; + } + + IDictionary signedParameters = new Dictionary(); + try + { + string apiUrl = $"http://api.photobucket.com/album/{PhotobucketConfig.Username}"; + responseString = oAuth.MakeOAuthRequest(HTTPMethod.GET, apiUrl, apiUrl.Replace("api.photobucket.com", PhotobucketConfig.SubDomain), signedParameters, null, null); + } + catch (Exception ex) + { + Log.Error("Error uploading to Photobucket.", ex); + throw; + } + finally + { + if (!string.IsNullOrEmpty(oAuth.Token)) + { + PhotobucketConfig.Token = oAuth.Token; + } + + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) + { + PhotobucketConfig.TokenSecret = oAuth.TokenSecret; + } + } + + if (responseString == null) + { + return null; + } + + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(responseString); + List albums = new List(); + var xmlNode = doc.GetElementsByTagName("content").Item(0); + if (xmlNode != null) + { + RecurseAlbums(albums, null, xmlNode.ChildNodes); + } + + Log.DebugFormat("Albums: {0}", string.Join(",", albums.ToArray())); + _albumsCache = albums; + return albums; + } + catch (Exception e) + { + Log.Error("Error while Reading albums: ", e); + } + + Log.Debug("Upload to Photobucket was finished"); + return null; + } + + /// + /// Parse the album nodes recursively + /// + /// + /// + /// + private static void RecurseAlbums(ICollection albums, string path, IEnumerable nodes) + { + foreach (XmlNode node in nodes) + { + if (node.Name != "album") + { + continue; + } + + if (node.Attributes != null) + { + string currentAlbum = node.Attributes["name"].Value; + string currentPath = currentAlbum; + if (!string.IsNullOrEmpty(path)) + { + currentPath = $"{path}/{currentAlbum}"; + } + + albums.Add(currentPath); + if (node.Attributes["subalbum_count"] != null && node.Attributes["subalbum_count"].Value != "0") + { + RecurseAlbums(albums, currentPath, node.ChildNodes); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs index 99952c5c0..470ed7174 100644 --- a/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs @@ -30,5 +30,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] - +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs index 616960615..cc119b70d 100644 --- a/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs +++ b/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs @@ -29,70 +29,70 @@ using GreenshotPlugin.Interfaces.Ocr; namespace Greenshot.Plugin.Win10.Destinations { - /// - /// This uses the OcrEngine from Windows 10 to perform OCR on the captured image. - /// - public class Win10OcrDestination : AbstractDestination - { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10OcrDestination)); + /// + /// This uses the OcrEngine from Windows 10 to perform OCR on the captured image. + /// + public class Win10OcrDestination : AbstractDestination + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10OcrDestination)); - public override string Designation { get; } = "Windows10OCR"; - public override string Description { get; } = "Windows 10 OCR"; + public override string Designation { get; } = "Windows10OCR"; + public override string Description { get; } = "Windows 10 OCR"; - /// - /// Icon for the OCR function, the icon was found via: http://help4windows.com/windows_8_imageres_dll.shtml - /// - public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(FilenameHelper.FillCmdVariables(@"%windir%\system32\imageres.dll"), 97); + /// + /// Icon for the OCR function, the icon was found via: http://help4windows.com/windows_8_imageres_dll.shtml + /// + public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(FilenameHelper.FillCmdVariables(@"%windir%\system32\imageres.dll"), 97); - /// - /// Constructor, this is only debug information - /// - public Win10OcrDestination() - { - var languages = OcrEngine.AvailableRecognizerLanguages; - foreach (var language in languages) - { - Log.DebugFormat("Found language {0} {1}", language.NativeName, language.LanguageTag); - } - } - - /// - /// Run the Windows 10 OCR engine to process the text on the captured image - /// - /// - /// - /// - /// ExportInformation - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) - { - var exportInformation = new ExportInformation(Designation, Description); - try + /// + /// Constructor, this is only debug information + /// + public Win10OcrDestination() + { + var languages = OcrEngine.AvailableRecognizerLanguages; + foreach (var language in languages) { - // TODO: Check if the OcrInformation is for the selected surface... otherwise discard & do it again + Log.DebugFormat("Found language {0} {1}", language.NativeName, language.LanguageTag); + } + } + + /// + /// Run the Windows 10 OCR engine to process the text on the captured image + /// + /// + /// + /// + /// ExportInformation + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + var exportInformation = new ExportInformation(Designation, Description); + try + { + // TODO: Check if the OcrInformation is for the selected surface... otherwise discard & do it again var ocrInformation = captureDetails.OcrInformation; - if (captureDetails.OcrInformation == null) + if (captureDetails.OcrInformation == null) { var ocrProvider = SimpleServiceProvider.Current.GetInstance(); - ocrInformation = Task.Run(async () => await ocrProvider.DoOcrAsync(surface)).Result; - } + ocrInformation = Task.Run(async () => await ocrProvider.DoOcrAsync(surface)).Result; + } - // Check if we found text - if (!string.IsNullOrWhiteSpace(ocrInformation.Text)) - { - // Place the OCR text on the - ClipboardHelper.SetClipboardData(ocrInformation.Text); - } - exportInformation.ExportMade = true; - } - catch (Exception ex) - { - exportInformation.ExportMade = false; - exportInformation.ErrorMessage = ex.Message; - } + // Check if we found text + if (!string.IsNullOrWhiteSpace(ocrInformation.Text)) + { + // Place the OCR text on the + ClipboardHelper.SetClipboardData(ocrInformation.Text); + } - ProcessExport(exportInformation, surface); - return exportInformation; + exportInformation.ExportMade = true; + } + catch (Exception ex) + { + exportInformation.ExportMade = false; + exportInformation.ErrorMessage = ex.Message; + } - } - } -} + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs index 2581dc586..e8178a8cf 100644 --- a/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs +++ b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs @@ -61,7 +61,7 @@ namespace Greenshot.Plugin.Win10.Destinations /// ISurface /// ICaptureDetails /// ExportInformation - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { var exportInformation = new ExportInformation(Designation, Description); try @@ -88,13 +88,13 @@ namespace Greenshot.Plugin.Win10.Destinations // Wait for the focus to return, and depending on the state close the window! focusMonitor.WindowOpenCloseChangeEvent += e => { - if (e.IsOpen) { if ("Windows Shell Experience Host" == e.Title) { shareInfo.SharingHwnd = e.HWnd; } + return; } @@ -104,6 +104,7 @@ namespace Greenshot.Plugin.Win10.Destinations { return; } + shareInfo.ShareTask.TrySetResult(false); } }; @@ -130,8 +131,8 @@ namespace Greenshot.Plugin.Win10.Destinations ProcessExport(exportInformation, surface); return exportInformation; - } + /// /// Share the surface by using the Share-UI of Windows 10 /// @@ -191,8 +192,8 @@ namespace Greenshot.Plugin.Win10.Destinations var storageFile = await StorageFile.CreateStreamedFileAsync(filename, async streamedFileDataRequest => { shareInfo.IsDeferredFileCreated = true; - // Information on the "how" was found here: https://socialeboladev.wordpress.com/2013/03/15/how-to-use-createstreamedfileasync/ - Log.DebugFormat("Creating deferred file {0}", filename); + // Information on the "how" was found here: https://socialeboladev.wordpress.com/2013/03/15/how-to-use-createstreamedfileasync/ + Log.DebugFormat("Creating deferred file {0}", filename); try { using (var deferredStream = streamedFileDataRequest.AsStreamForWrite()) @@ -200,6 +201,7 @@ namespace Greenshot.Plugin.Win10.Destinations await imageStream.CopyToAsync(deferredStream).ConfigureAwait(false); await imageStream.FlushAsync().ConfigureAwait(false); } + // Signal that the stream is ready streamedFileDataRequest.Dispose(); // Signal that the action is ready, bitmap was exported @@ -245,7 +247,10 @@ namespace Greenshot.Plugin.Win10.Destinations dataPackage.Properties.Thumbnail = thumbnailRandomAccessStreamReference; dataPackage.Properties.Square30x30Logo = logoRandomAccessStreamReference; dataPackage.Properties.LogoBackgroundColor = Color.FromArgb(0xff, 0x3d, 0x3d, 0x3d); - dataPackage.SetStorageItems(new[] { storageFile }); + dataPackage.SetStorageItems(new[] + { + storageFile + }); dataPackage.SetBitmap(imageRandomAccessStreamReference); } finally @@ -259,4 +264,4 @@ namespace Greenshot.Plugin.Win10.Destinations await shareInfo.ShareTask.Task.ConfigureAwait(false); } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs b/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs index e4a49c64e..230c76ed7 100644 --- a/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs +++ b/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs @@ -27,67 +27,67 @@ namespace Greenshot.Plugin.Win10.Internal /// /// This is an IRandomAccessStream implementation which uses a MemoryStream /// - internal sealed class MemoryRandomAccessStream : MemoryStream, IRandomAccessStream - { + internal sealed class MemoryRandomAccessStream : MemoryStream, IRandomAccessStream + { /// public IInputStream GetInputStreamAt(ulong position) - { - Seek((long)position, SeekOrigin.Begin); + { + Seek((long) position, SeekOrigin.Begin); - return this.AsInputStream(); - } + return this.AsInputStream(); + } /// public IOutputStream GetOutputStreamAt(ulong position) - { - Seek((long)position, SeekOrigin.Begin); + { + Seek((long) position, SeekOrigin.Begin); - return this.AsOutputStream(); - } + return this.AsOutputStream(); + } /// - ulong IRandomAccessStream.Position => (ulong)Position; + ulong IRandomAccessStream.Position => (ulong) Position; /// public ulong Size - { - get { return (ulong)Length; } - set { SetLength((long)value); } - } + { + get { return (ulong) Length; } + set { SetLength((long) value); } + } /// public IRandomAccessStream CloneStream() - { - var cloned = new MemoryRandomAccessStream(); - CopyTo(cloned); - return cloned; - } + { + var cloned = new MemoryRandomAccessStream(); + CopyTo(cloned); + return cloned; + } /// public void Seek(ulong position) - { - Seek((long)position, SeekOrigin.Begin); - } + { + Seek((long) position, SeekOrigin.Begin); + } /// public Windows.Foundation.IAsyncOperationWithProgress ReadAsync(IBuffer buffer, uint count, InputStreamOptions options) - { - var inputStream = GetInputStreamAt(0); - return inputStream.ReadAsync(buffer, count, options); - } + { + var inputStream = GetInputStreamAt(0); + return inputStream.ReadAsync(buffer, count, options); + } /// Windows.Foundation.IAsyncOperation IOutputStream.FlushAsync() - { - var outputStream = GetOutputStreamAt(0); - return outputStream.FlushAsync(); - } + { + var outputStream = GetOutputStreamAt(0); + return outputStream.FlushAsync(); + } /// public Windows.Foundation.IAsyncOperationWithProgress WriteAsync(IBuffer buffer) - { - var outputStream = GetOutputStreamAt(0); - return outputStream.WriteAsync(buffer); - } - } -} + { + var outputStream = GetOutputStreamAt(0); + return outputStream.WriteAsync(buffer); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs b/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs index 44b0d529b..f28370e06 100644 --- a/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs +++ b/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs @@ -40,4 +40,4 @@ namespace Greenshot.Plugin.Win10.Internal public IntPtr SharingHwnd { get; set; } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs index 192e818ec..9f2540694 100644 --- a/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs +++ b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs @@ -26,62 +26,59 @@ using GreenshotPlugin.Core; namespace Greenshot.Plugin.Win10.Native { - /// - /// Wraps the interop for calling the ShareUI - /// - public class DataTransferManagerHelper - { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DataTransferManagerHelper)); + /// + /// Wraps the interop for calling the ShareUI + /// + public class DataTransferManagerHelper + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DataTransferManagerHelper)); - private const string DataTransferManagerId = "a5caee9b-8708-49d1-8d36-67d25a8da00c"; - private readonly IDataTransferManagerInterOp _dataTransferManagerInterOp; - private readonly IntPtr _windowHandle; + private const string DataTransferManagerId = "a5caee9b-8708-49d1-8d36-67d25a8da00c"; + private readonly IDataTransferManagerInterOp _dataTransferManagerInterOp; + private readonly IntPtr _windowHandle; /// /// The DataTransferManager /// - public DataTransferManager DataTransferManager - { - get; - private set; - } + public DataTransferManager DataTransferManager { get; private set; } + /// /// Constructor which takes a handle to initialize /// /// - public DataTransferManagerHelper(IntPtr handle) - { - //TODO: Add a check for failure here. This will fail for versions of Windows below Windows 10 - IActivationFactory activationFactory = WindowsRuntimeMarshal.GetActivationFactory(typeof(DataTransferManager)); + public DataTransferManagerHelper(IntPtr handle) + { + //TODO: Add a check for failure here. This will fail for versions of Windows below Windows 10 + IActivationFactory activationFactory = WindowsRuntimeMarshal.GetActivationFactory(typeof(DataTransferManager)); - // ReSharper disable once SuspiciousTypeConversion.Global - _dataTransferManagerInterOp = (IDataTransferManagerInterOp)activationFactory; + // ReSharper disable once SuspiciousTypeConversion.Global + _dataTransferManagerInterOp = (IDataTransferManagerInterOp) activationFactory; - _windowHandle = handle; - var riid = new Guid(DataTransferManagerId); - var hresult = _dataTransferManagerInterOp.GetForWindow(_windowHandle, riid, out var dataTransferManager); - if (hresult.Failed()) - { - Log.WarnFormat("HResult for GetForWindow: {0}", hresult); - } - DataTransferManager = dataTransferManager; - } + _windowHandle = handle; + var riid = new Guid(DataTransferManagerId); + var hresult = _dataTransferManagerInterOp.GetForWindow(_windowHandle, riid, out var dataTransferManager); + if (hresult.Failed()) + { + Log.WarnFormat("HResult for GetForWindow: {0}", hresult); + } - /// - /// Show the share UI - /// - public void ShowShareUi() - { - var hresult = _dataTransferManagerInterOp.ShowShareUIForWindow(_windowHandle); - if (hresult.Failed()) - { + DataTransferManager = dataTransferManager; + } + + /// + /// Show the share UI + /// + public void ShowShareUi() + { + var hresult = _dataTransferManagerInterOp.ShowShareUIForWindow(_windowHandle); + if (hresult.Failed()) + { Log.WarnFormat("HResult for ShowShareUIForWindow: {0}", hresult); - } - else - { - Log.Debug("ShowShareUIForWindow called"); - } - } - } - -} + } + else + { + Log.Debug("ShowShareUIForWindow called"); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs index dc477aac8..8bdba3366 100644 --- a/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs +++ b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs @@ -30,27 +30,26 @@ namespace Greenshot.Plugin.Win10.Native /// window using a window handle. Useful for Win32 apps. ///
[ComImport, Guid("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IDataTransferManagerInterOp - { - /// - /// Get an instance of Windows.ApplicationModel.DataTransfer.DataTransferManager - /// for the window identified by a window handle - /// - /// The window handle - /// ID of the DataTransferManager interface - /// The DataTransferManager instance for this window handle - /// HRESULT - [PreserveSig] - HResult GetForWindow([In] IntPtr appWindow, [In] ref Guid riid, [Out] out DataTransferManager pDataTransferManager); + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IDataTransferManagerInterOp + { + /// + /// Get an instance of Windows.ApplicationModel.DataTransfer.DataTransferManager + /// for the window identified by a window handle + /// + /// The window handle + /// ID of the DataTransferManager interface + /// The DataTransferManager instance for this window handle + /// HRESULT + [PreserveSig] + HResult GetForWindow([In] IntPtr appWindow, [In] ref Guid riid, [Out] out DataTransferManager pDataTransferManager); - /// - /// Show the share flyout for the window identified by a window handle - /// - /// The window handle - /// HRESULT - [PreserveSig] - HResult ShowShareUIForWindow(IntPtr appWindow); - } - -} + /// + /// Show the share flyout for the window identified by a window handle + /// + /// The window handle + /// HRESULT + [PreserveSig] + HResult ShowShareUIForWindow(IntPtr appWindow); + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs b/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs index c70c6fb27..cfbf88d18 100644 --- a/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs +++ b/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs @@ -25,11 +25,13 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; -namespace Greenshot.Plugin.Win10.Processors { - /// - /// This processor processes a capture to see if there is text on it - /// - public class Win10OcrProcessor : AbstractProcessor { +namespace Greenshot.Plugin.Win10.Processors +{ + /// + /// This processor processes a capture to see if there is text on it + /// + public class Win10OcrProcessor : AbstractProcessor + { private static readonly Win10Configuration Win10Configuration = IniConfig.GetIniSection(); public override string Designation => "Windows10OcrProcessor"; @@ -46,10 +48,12 @@ namespace Greenshot.Plugin.Win10.Processors { { return false; } + if (captureDetails == null || captureDetails.OcrInformation != null) { return false; } + var ocrProvider = SimpleServiceProvider.Current.GetInstance(); if (ocrProvider == null) @@ -68,5 +72,5 @@ namespace Greenshot.Plugin.Win10.Processors { return true; } - } -} + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs index 7c2dc1d2c..d1b6cbd1b 100644 --- a/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs @@ -12,4 +12,4 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("9801f62c-540f-4bfe-9211-6405dede563b")] +[assembly: Guid("9801f62c-540f-4bfe-9211-6405dede563b")] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/ToastNotificationService.cs b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs index 444d397ef..eea987802 100644 --- a/src/Greenshot.Plugin.Win10/ToastNotificationService.cs +++ b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs @@ -42,12 +42,14 @@ namespace Greenshot.Plugin.Win10 private static readonly CoreConfiguration CoreConfiguration = IniConfig.GetIniSection(); private readonly string _imageFilePath; + public ToastNotificationService() { if (ToastNotificationManagerCompat.WasCurrentProcessToastActivated()) { Log.Info("Greenshot was activated due to a toast."); } + // Listen to notification activation ToastNotificationManagerCompat.OnActivated += toastArgs => { @@ -65,6 +67,7 @@ namespace Greenshot.Plugin.Win10 { Directory.CreateDirectory(localAppData); } + _imageFilePath = Path.Combine(localAppData, "greenshot.png"); if (File.Exists(_imageFilePath)) @@ -90,6 +93,7 @@ namespace Greenshot.Plugin.Win10 { return; } + // Prepare the toast notifier. Be sure to specify the AppUserModelId on your application's shortcut! var toastNotifier = ToastNotificationManagerCompat.CreateToastNotifier(); @@ -109,7 +113,6 @@ namespace Greenshot.Plugin.Win10 // Generate the toast and send it off new ToastContentBuilder() - .AddArgument("ToastID", 100) // Inline image .AddText(message) @@ -119,6 +122,7 @@ namespace Greenshot.Plugin.Win10 { // Windows 10 first with 1903: ExpiresOnReboot = true toast.ExpirationTime = timeout.HasValue ? DateTimeOffset.Now.Add(timeout.Value) : (DateTimeOffset?) null; + void ToastActivatedHandler(ToastNotification toastNotification, object sender) { try @@ -145,6 +149,7 @@ namespace Greenshot.Plugin.Win10 { return; } + try { onClosedAction?.Invoke(); @@ -158,8 +163,8 @@ namespace Greenshot.Plugin.Win10 // Remove the other handler too toast.Activated -= ToastActivatedHandler; toast.Failed -= ToastOnFailed; - } + toast.Dismissed += ToastDismissedHandler; toast.Failed += ToastOnFailed; }); @@ -196,9 +201,10 @@ namespace Greenshot.Plugin.Win10 { return new ToastNotificationService(); } + Log.Warn("ToastNotificationActionTrigger not available."); return null; } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Win10Configuration.cs b/src/Greenshot.Plugin.Win10/Win10Configuration.cs index 9c24787bf..bbd1ff35e 100644 --- a/src/Greenshot.Plugin.Win10/Win10Configuration.cs +++ b/src/Greenshot.Plugin.Win10/Win10Configuration.cs @@ -23,12 +23,13 @@ using GreenshotPlugin.IniFile; namespace Greenshot.Plugin.Win10 { - /// - /// Description of Win10Configuration. - /// - [IniSection("Win10", Description = "Greenshot Win10 Plugin configuration")] - public class Win10Configuration : IniSection { - [IniProperty("AlwaysRunOCROnCapture", Description="Determines if OCR is run automatically on every capture", DefaultValue="False")] - public bool AlwaysRunOCROnCapture { get; set; } - } -} + /// + /// Description of Win10Configuration. + /// + [IniSection("Win10", Description = "Greenshot Win10 Plugin configuration")] + public class Win10Configuration : IniSection + { + [IniProperty("AlwaysRunOCROnCapture", Description = "Determines if OCR is run automatically on every capture", DefaultValue = "False")] + public bool AlwaysRunOCROnCapture { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs index 5ade2f329..e6feb8193 100644 --- a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs +++ b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs @@ -33,24 +33,24 @@ using GreenshotPlugin.Interfaces.Plugin; namespace Greenshot.Plugin.Win10 { - /// - /// This uses the OcrEngine from Windows 10 to perform OCR on the captured image. - /// - public class Win10OcrProvider : IOcrProvider - { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10OcrProvider)); + /// + /// This uses the OcrEngine from Windows 10 to perform OCR on the captured image. + /// + public class Win10OcrProvider : IOcrProvider + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10OcrProvider)); - /// - /// Constructor, this is only debug information - /// - public Win10OcrProvider() - { - var languages = OcrEngine.AvailableRecognizerLanguages; - foreach (var language in languages) - { - Log.DebugFormat("Found language {0} {1}", language.NativeName, language.LanguageTag); - } - } + /// + /// Constructor, this is only debug information + /// + public Win10OcrProvider() + { + var languages = OcrEngine.AvailableRecognizerLanguages; + foreach (var language in languages) + { + Log.DebugFormat("Found language {0} {1}", language.NativeName, language.LanguageTag); + } + } /// /// Scan the surface bitmap for text, and get the OcrResult @@ -68,15 +68,16 @@ namespace Greenshot.Plugin.Win10 result = await DoOcrAsync(randomAccessStream); } + return result; } - /// - /// Scan the Image for text, and get the OcrResult - /// - /// Image - /// OcrResult sync - public async Task DoOcrAsync(Image image) + /// + /// Scan the Image for text, and get the OcrResult + /// + /// Image + /// OcrResult sync + public async Task DoOcrAsync(Image image) { OcrInformation result; using (var imageStream = new MemoryStream()) @@ -86,29 +87,31 @@ namespace Greenshot.Plugin.Win10 var randomAccessStream = imageStream.AsRandomAccessStream(); result = await DoOcrAsync(randomAccessStream); - } - return result; + } + + return result; } - /// - /// Scan the surface bitmap for text, and get the OcrResult - /// - /// IRandomAccessStream - /// OcrResult sync - public async Task DoOcrAsync(IRandomAccessStream randomAccessStream) + /// + /// Scan the surface bitmap for text, and get the OcrResult + /// + /// IRandomAccessStream + /// OcrResult sync + public async Task DoOcrAsync(IRandomAccessStream randomAccessStream) { var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages(); if (ocrEngine is null) { return null; } - var decoder = await BitmapDecoder.CreateAsync(randomAccessStream); - var softwareBitmap = await decoder.GetSoftwareBitmapAsync(); - var ocrResult = await ocrEngine.RecognizeAsync(softwareBitmap); + var decoder = await BitmapDecoder.CreateAsync(randomAccessStream); + var softwareBitmap = await decoder.GetSoftwareBitmapAsync(); + + var ocrResult = await ocrEngine.RecognizeAsync(softwareBitmap); return CreateOcrInformation(ocrResult); - } + } /// /// Create the OcrInformation @@ -131,8 +134,8 @@ namespace Greenshot.Plugin.Win10 for (var index = 0; index < ocrLine.Words.Count; index++) { var ocrWord = ocrLine.Words[index]; - var location = new Rectangle((int)ocrWord.BoundingRect.X, (int)ocrWord.BoundingRect.Y, - (int)ocrWord.BoundingRect.Width, (int)ocrWord.BoundingRect.Height); + var location = new Rectangle((int) ocrWord.BoundingRect.X, (int) ocrWord.BoundingRect.Y, + (int) ocrWord.BoundingRect.Width, (int) ocrWord.BoundingRect.Height); var word = line.Words[index]; word.Text = ocrWord.Text; @@ -143,4 +146,4 @@ namespace Greenshot.Plugin.Win10 return result; } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Win10Plugin.cs b/src/Greenshot.Plugin.Win10/Win10Plugin.cs index b70a417cb..25d8d048e 100644 --- a/src/Greenshot.Plugin.Win10/Win10Plugin.cs +++ b/src/Greenshot.Plugin.Win10/Win10Plugin.cs @@ -29,53 +29,52 @@ using GreenshotPlugin.Interfaces.Plugin; namespace Greenshot.Plugin.Win10 { - /// - /// This is the Win10Plugin - /// - [Plugin("Win10", false)] - public sealed class Win10Plugin : IGreenshotPlugin - { + /// + /// This is the Win10Plugin + /// + [Plugin("Win10", false)] + public sealed class Win10Plugin : IGreenshotPlugin + { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10Plugin)); public void Dispose() - { - // Nothing to dispose - } + { + // Nothing to dispose + } public void Configure() - { - throw new NotImplementedException(); - } + { + throw new NotImplementedException(); + } /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - /// true if plugin is initialized, false if not (doesn't show) - public bool Initialize() - { - // Here we check if the build version of Windows is actually what we support + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// true if plugin is initialized, false if not (doesn't show) + public bool Initialize() + { + // Here we check if the build version of Windows is actually what we support if (!WindowsVersion.IsWindows10BuildOrLater(17763)) { - Log.WarnFormat("No support for Windows build {0}", WindowsVersion.BuildVersion); + Log.WarnFormat("No support for Windows build {0}", WindowsVersion.BuildVersion); return false; } SimpleServiceProvider.Current.AddService(ToastNotificationService.Create()); - // Set this as IOcrProvider - SimpleServiceProvider.Current.AddService(new Win10OcrProvider()); + // Set this as IOcrProvider + SimpleServiceProvider.Current.AddService(new Win10OcrProvider()); // Add the processor SimpleServiceProvider.Current.AddService(new Win10OcrProcessor()); // Add the destinations - SimpleServiceProvider.Current.AddService(new Win10OcrDestination()); + SimpleServiceProvider.Current.AddService(new Win10OcrDestination()); SimpleServiceProvider.Current.AddService(new Win10ShareDestination()); - return true; - } + return true; + } - public void Shutdown() - { - // Nothing to shutdown - } - } - -} + public void Shutdown() + { + // Nothing to shutdown + } + } +} \ No newline at end of file diff --git a/src/Greenshot/App.config b/src/Greenshot/App.config index f15ae706e..3b81b058d 100644 --- a/src/Greenshot/App.config +++ b/src/Greenshot/App.config @@ -1,18 +1,19 @@ + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Greenshot/Configuration/EditorConfiguration.cs b/src/Greenshot/Configuration/EditorConfiguration.cs index 019ea9ef6..97856f5d0 100644 --- a/src/Greenshot/Configuration/EditorConfiguration.cs +++ b/src/Greenshot/Configuration/EditorConfiguration.cs @@ -18,10 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; - using Greenshot.Drawing.Fields; using GreenshotPlugin.Effects; using GreenshotPlugin.IniFile; @@ -29,123 +29,153 @@ using GreenshotPlugin.Interfaces.Drawing; using GreenshotPlugin.UnmanagedHelpers.Enums; using GreenshotPlugin.UnmanagedHelpers.Structs; -namespace Greenshot.Configuration { - /// - /// Description of CoreConfiguration. - /// - [IniSection("Editor", Description="Greenshot editor configuration")] - public class EditorConfiguration : IniSection { - [IniProperty("RecentColors", Separator="|", Description="Last used colors")] - public List RecentColors { get; set; } +namespace Greenshot.Configuration +{ + /// + /// Description of CoreConfiguration. + /// + [IniSection("Editor", Description = "Greenshot editor configuration")] + public class EditorConfiguration : IniSection + { + [IniProperty("RecentColors", Separator = "|", Description = "Last used colors")] + public List RecentColors { get; set; } - [IniProperty("LastFieldValue", Separator="|", Description="Field values, make sure the last used settings are re-used")] - public Dictionary LastUsedFieldValues { get; set; } + [IniProperty("LastFieldValue", Separator = "|", Description = "Field values, make sure the last used settings are re-used")] + public Dictionary LastUsedFieldValues { get; set; } - [IniProperty("MatchSizeToCapture", Description="Match the editor window size to the capture", DefaultValue="True")] - public bool MatchSizeToCapture { get; set; } - [IniProperty("WindowPlacementFlags", Description="Placement flags", DefaultValue="0")] - public WindowPlacementFlags WindowPlacementFlags { get; set; } - [IniProperty("WindowShowCommand", Description="Show command", DefaultValue="Normal")] - public ShowWindowCommand ShowWindowCommand { get; set; } - [IniProperty("WindowMinPosition", Description="Position of minimized window", DefaultValue="-1,-1")] - public Point WindowMinPosition { get; set; } - [IniProperty("WindowMaxPosition", Description="Position of maximized window", DefaultValue="-1,-1")] - public Point WindowMaxPosition { get; set; } - [IniProperty("WindowNormalPosition", Description="Position of normal window", DefaultValue="100,100,400,400")] - public Rectangle WindowNormalPosition { get; set; } - [IniProperty("ReuseEditor", Description = "Reuse already open editor", DefaultValue = "false")] - public bool ReuseEditor { get; set; } - [IniProperty("FreehandSensitivity", Description = "The smaller this number, the less smoothing is used. Decrease for detailed drawing, e.g. when using a pen. Increase for smoother lines. e.g. when you want to draw a smooth line.", DefaultValue = "3")] - public int FreehandSensitivity { get; set; } - [IniProperty("SuppressSaveDialogAtClose", Description="Suppressed the 'do you want to save' dialog when closing the editor.", DefaultValue="False")] - public bool SuppressSaveDialogAtClose { get; set; } + [IniProperty("MatchSizeToCapture", Description = "Match the editor window size to the capture", DefaultValue = "True")] + public bool MatchSizeToCapture { get; set; } - [IniProperty("DropShadowEffectSettings", Description = "Settings for the drop shadow effect.")] - public DropShadowEffect DropShadowEffectSettings { get; set; } + [IniProperty("WindowPlacementFlags", Description = "Placement flags", DefaultValue = "0")] + public WindowPlacementFlags WindowPlacementFlags { get; set; } - [IniProperty("TornEdgeEffectSettings", Description = "Settings for the torn edge effect.")] - public TornEdgeEffect TornEdgeEffectSettings { get; set; } + [IniProperty("WindowShowCommand", Description = "Show command", DefaultValue = "Normal")] + public ShowWindowCommand ShowWindowCommand { get; set; } - public override void AfterLoad() { - base.AfterLoad(); - if (RecentColors == null) { - RecentColors = new List(); - } - } + [IniProperty("WindowMinPosition", Description = "Position of minimized window", DefaultValue = "-1,-1")] + public Point WindowMinPosition { get; set; } - /// Type of the class for which to create the field - /// FieldType of the field to construct - /// - /// a new Field of the given fieldType, with the scope of it's value being restricted to the Type scope - public IField CreateField(Type requestingType, IFieldType fieldType, object preferredDefaultValue) - { - string requestingTypeName = requestingType.Name; - string requestedField = requestingTypeName + "." + fieldType.Name; - object fieldValue = preferredDefaultValue; - - // Check if the configuration exists - if (LastUsedFieldValues == null) { - LastUsedFieldValues = new Dictionary(); - } - - // Check if settings for the requesting type exist, if not create! - if (LastUsedFieldValues.ContainsKey(requestedField)) { - // Check if a value is set (not null)! - if (LastUsedFieldValues[requestedField] != null) { - fieldValue = LastUsedFieldValues[requestedField]; - } else { - // Overwrite null value - LastUsedFieldValues[requestedField] = fieldValue; - } - } else { - LastUsedFieldValues.Add(requestedField, fieldValue); - } - return new Field(fieldType, requestingType) - { - Value = fieldValue - }; - } + [IniProperty("WindowMaxPosition", Description = "Position of maximized window", DefaultValue = "-1,-1")] + public Point WindowMaxPosition { get; set; } - public void UpdateLastFieldValue(IField field) - { - string requestedField = field.Scope + "." + field.FieldType.Name; - // Check if the configuration exists - if (LastUsedFieldValues == null) { - LastUsedFieldValues = new Dictionary(); - } - // check if settings for the requesting type exist, if not create! - if (LastUsedFieldValues.ContainsKey(requestedField)) { - LastUsedFieldValues[requestedField] = field.Value; - } else { - LastUsedFieldValues.Add(requestedField, field.Value); - } - } + [IniProperty("WindowNormalPosition", Description = "Position of normal window", DefaultValue = "100,100,400,400")] + public Rectangle WindowNormalPosition { get; set; } - public void ResetEditorPlacement() - { - WindowNormalPosition = new Rectangle(100, 100, 400, 400); - WindowMaxPosition = new Point(-1,-1); - WindowMinPosition = new Point(-1, -1); - WindowPlacementFlags = 0; - ShowWindowCommand = ShowWindowCommand.Normal; - } + [IniProperty("ReuseEditor", Description = "Reuse already open editor", DefaultValue = "false")] + public bool ReuseEditor { get; set; } - public WindowPlacement GetEditorPlacement() { - WindowPlacement placement = WindowPlacement.Default; - placement.NormalPosition = new RECT(WindowNormalPosition); - placement.MaxPosition = new POINT(WindowMaxPosition); - placement.MinPosition = new POINT(WindowMinPosition); - placement.ShowCmd = ShowWindowCommand; - placement.Flags = WindowPlacementFlags; - return placement; - } + [IniProperty("FreehandSensitivity", + Description = + "The smaller this number, the less smoothing is used. Decrease for detailed drawing, e.g. when using a pen. Increase for smoother lines. e.g. when you want to draw a smooth line.", + DefaultValue = "3")] + public int FreehandSensitivity { get; set; } - public void SetEditorPlacement(WindowPlacement placement) { - WindowNormalPosition = placement.NormalPosition.ToRectangle(); - WindowMaxPosition = placement.MaxPosition.ToPoint(); - WindowMinPosition = placement.MinPosition.ToPoint(); - ShowWindowCommand = placement.ShowCmd; - WindowPlacementFlags = placement.Flags; - } - } -} + [IniProperty("SuppressSaveDialogAtClose", Description = "Suppressed the 'do you want to save' dialog when closing the editor.", DefaultValue = "False")] + public bool SuppressSaveDialogAtClose { get; set; } + + [IniProperty("DropShadowEffectSettings", Description = "Settings for the drop shadow effect.")] + public DropShadowEffect DropShadowEffectSettings { get; set; } + + [IniProperty("TornEdgeEffectSettings", Description = "Settings for the torn edge effect.")] + public TornEdgeEffect TornEdgeEffectSettings { get; set; } + + public override void AfterLoad() + { + base.AfterLoad(); + if (RecentColors == null) + { + RecentColors = new List(); + } + } + + /// Type of the class for which to create the field + /// FieldType of the field to construct + /// + /// a new Field of the given fieldType, with the scope of it's value being restricted to the Type scope + public IField CreateField(Type requestingType, IFieldType fieldType, object preferredDefaultValue) + { + string requestingTypeName = requestingType.Name; + string requestedField = requestingTypeName + "." + fieldType.Name; + object fieldValue = preferredDefaultValue; + + // Check if the configuration exists + if (LastUsedFieldValues == null) + { + LastUsedFieldValues = new Dictionary(); + } + + // Check if settings for the requesting type exist, if not create! + if (LastUsedFieldValues.ContainsKey(requestedField)) + { + // Check if a value is set (not null)! + if (LastUsedFieldValues[requestedField] != null) + { + fieldValue = LastUsedFieldValues[requestedField]; + } + else + { + // Overwrite null value + LastUsedFieldValues[requestedField] = fieldValue; + } + } + else + { + LastUsedFieldValues.Add(requestedField, fieldValue); + } + + return new Field(fieldType, requestingType) + { + Value = fieldValue + }; + } + + public void UpdateLastFieldValue(IField field) + { + string requestedField = field.Scope + "." + field.FieldType.Name; + // Check if the configuration exists + if (LastUsedFieldValues == null) + { + LastUsedFieldValues = new Dictionary(); + } + + // check if settings for the requesting type exist, if not create! + if (LastUsedFieldValues.ContainsKey(requestedField)) + { + LastUsedFieldValues[requestedField] = field.Value; + } + else + { + LastUsedFieldValues.Add(requestedField, field.Value); + } + } + + public void ResetEditorPlacement() + { + WindowNormalPosition = new Rectangle(100, 100, 400, 400); + WindowMaxPosition = new Point(-1, -1); + WindowMinPosition = new Point(-1, -1); + WindowPlacementFlags = 0; + ShowWindowCommand = ShowWindowCommand.Normal; + } + + public WindowPlacement GetEditorPlacement() + { + WindowPlacement placement = WindowPlacement.Default; + placement.NormalPosition = new RECT(WindowNormalPosition); + placement.MaxPosition = new POINT(WindowMaxPosition); + placement.MinPosition = new POINT(WindowMinPosition); + placement.ShowCmd = ShowWindowCommand; + placement.Flags = WindowPlacementFlags; + return placement; + } + + public void SetEditorPlacement(WindowPlacement placement) + { + WindowNormalPosition = placement.NormalPosition.ToRectangle(); + WindowMaxPosition = placement.MaxPosition.ToPoint(); + WindowMinPosition = placement.MinPosition.ToPoint(); + ShowWindowCommand = placement.ShowCmd; + WindowPlacementFlags = placement.Flags; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Configuration/LanguageKeys.cs b/src/Greenshot/Configuration/LanguageKeys.cs index a668218eb..e156261b7 100644 --- a/src/Greenshot/Configuration/LanguageKeys.cs +++ b/src/Greenshot/Configuration/LanguageKeys.cs @@ -21,60 +21,62 @@ using System.Diagnostics.CodeAnalysis; -namespace Greenshot.Configuration { +namespace Greenshot.Configuration +{ [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum LangKey { - none, + public enum LangKey + { + none, contextmenu_capturefullscreen_all, - contextmenu_capturefullscreen_left, - contextmenu_capturefullscreen_top, - contextmenu_capturefullscreen_right, - contextmenu_capturefullscreen_bottom, + contextmenu_capturefullscreen_left, + contextmenu_capturefullscreen_top, + contextmenu_capturefullscreen_right, + contextmenu_capturefullscreen_bottom, contextmenu_captureie, editor_clipboardfailed, - editor_close_on_save, - editor_close_on_save_title, - editor_copytoclipboard, - editor_cuttoclipboard, - editor_deleteelement, - editor_downonelevel, - editor_downtobottom, - editor_duplicate, - editor_email, - editor_imagesaved, - editor_title, - editor_uponelevel, - editor_uptotop, - editor_undo, - editor_redo, - editor_resetsize, - error, - error_multipleinstances, - error_openfile, - error_openlink, - error_save, - error_save_invalid_chars, - print_error, - quicksettings_destination_file, - settings_destination, - settings_destination_clipboard, - settings_destination_editor, - settings_destination_fileas, - settings_destination_printer, - settings_destination_picker, - settings_filenamepattern, - settings_message_filenamepattern, - settings_printoptions, - settings_tooltip_filenamepattern, - settings_tooltip_language, - settings_tooltip_primaryimageformat, - settings_tooltip_storagelocation, - settings_visualization, - settings_window_capture_mode, - tooltip_firststart, - warning, - warning_hotkeys, - wait_ie_capture, - update_found + editor_close_on_save, + editor_close_on_save_title, + editor_copytoclipboard, + editor_cuttoclipboard, + editor_deleteelement, + editor_downonelevel, + editor_downtobottom, + editor_duplicate, + editor_email, + editor_imagesaved, + editor_title, + editor_uponelevel, + editor_uptotop, + editor_undo, + editor_redo, + editor_resetsize, + error, + error_multipleinstances, + error_openfile, + error_openlink, + error_save, + error_save_invalid_chars, + print_error, + quicksettings_destination_file, + settings_destination, + settings_destination_clipboard, + settings_destination_editor, + settings_destination_fileas, + settings_destination_printer, + settings_destination_picker, + settings_filenamepattern, + settings_message_filenamepattern, + settings_printoptions, + settings_tooltip_filenamepattern, + settings_tooltip_language, + settings_tooltip_primaryimageformat, + settings_tooltip_storagelocation, + settings_visualization, + settings_window_capture_mode, + tooltip_firststart, + warning, + warning_hotkeys, + wait_ie_capture, + update_found } -} +} \ No newline at end of file diff --git a/src/Greenshot/Controls/BindableToolStripButton.cs b/src/Greenshot/Controls/BindableToolStripButton.cs index b44a1a31c..37088476a 100644 --- a/src/Greenshot/Controls/BindableToolStripButton.cs +++ b/src/Greenshot/Controls/BindableToolStripButton.cs @@ -18,32 +18,32 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Windows.Forms; using GreenshotPlugin.Controls; -namespace Greenshot.Controls { - /// - /// Description of BindableToolStripButton. - /// - public class BindableToolStripButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; +namespace Greenshot.Controls +{ + /// + /// Description of BindableToolStripButton. + /// + public class BindableToolStripButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable + { + public event PropertyChangedEventHandler PropertyChanged; - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } - public BindableToolStripButton() - { - CheckedChanged += BindableToolStripButton_CheckedChanged; - } + public BindableToolStripButton() + { + CheckedChanged += BindableToolStripButton_CheckedChanged; + } - private void BindableToolStripButton_CheckedChanged(object sender, EventArgs e) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Checked")); - } - } -} + private void BindableToolStripButton_CheckedChanged(object sender, EventArgs e) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Checked")); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/BindableToolStripComboBox.cs b/src/Greenshot/Controls/BindableToolStripComboBox.cs index 3637f2380..b0f87cff8 100644 --- a/src/Greenshot/Controls/BindableToolStripComboBox.cs +++ b/src/Greenshot/Controls/BindableToolStripComboBox.cs @@ -18,32 +18,32 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Windows.Forms; using GreenshotPlugin.Controls; -namespace Greenshot.Controls { - /// - /// A simple ToolStripComboBox implementing INotifyPropertyChanged for data binding - /// - public class BindableToolStripComboBox : ToolStripComboBox, INotifyPropertyChanged, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; +namespace Greenshot.Controls +{ + /// + /// A simple ToolStripComboBox implementing INotifyPropertyChanged for data binding + /// + public class BindableToolStripComboBox : ToolStripComboBox, INotifyPropertyChanged, IGreenshotLanguageBindable + { + public event PropertyChangedEventHandler PropertyChanged; - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } - public BindableToolStripComboBox() - { - SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged; - } + public BindableToolStripComboBox() + { + SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged; + } - private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedItem")); - } - } -} + private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedItem")); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/BindableToolStripDropDownButton.cs b/src/Greenshot/Controls/BindableToolStripDropDownButton.cs index 4071d6b81..428b66bb3 100644 --- a/src/Greenshot/Controls/BindableToolStripDropDownButton.cs +++ b/src/Greenshot/Controls/BindableToolStripDropDownButton.cs @@ -18,53 +18,65 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.ComponentModel; using System.Windows.Forms; using GreenshotPlugin.Controls; -namespace Greenshot.Controls { - /// - /// A simple ToolStripDropDownButton implementing INotifyPropertyChanged for data binding. - /// Also, when a DropDownItem is selected, the DropDownButton adopts its Tag and Image. - /// The selected tag can be accessed via SelectedTag property. - /// - public class BindableToolStripDropDownButton : ToolStripDropDownButton, INotifyPropertyChanged, IGreenshotLanguageBindable { - - public event PropertyChangedEventHandler PropertyChanged; +namespace Greenshot.Controls +{ + /// + /// A simple ToolStripDropDownButton implementing INotifyPropertyChanged for data binding. + /// Also, when a DropDownItem is selected, the DropDownButton adopts its Tag and Image. + /// The selected tag can be accessed via SelectedTag property. + /// + public class BindableToolStripDropDownButton : ToolStripDropDownButton, INotifyPropertyChanged, IGreenshotLanguageBindable + { + public event PropertyChangedEventHandler PropertyChanged; - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } - public object SelectedTag { - get { if(Tag==null && DropDownItems.Count>0) Tag=DropDownItems[0].Tag; return Tag; } - set { AdoptFromTag(value); } - } - - protected override void OnDropDownItemClicked(ToolStripItemClickedEventArgs e) { - ToolStripItem clickedItem = e.ClickedItem; - if(Tag == null || !Tag.Equals(clickedItem.Tag)) { - Tag = clickedItem.Tag; - Image = clickedItem.Image; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag")); - } - base.OnDropDownItemClicked(e); - } - - private void AdoptFromTag(object tag) { - if(Tag == null || !Tag.Equals(tag)) { - Tag = tag; - foreach(ToolStripItem item in DropDownItems) { - if(item.Tag != null && item.Tag.Equals(tag)) { - Image = item.Image; - break; - } - } - Tag = tag; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag")); - } - } - } -} + public object SelectedTag + { + get + { + if (Tag == null && DropDownItems.Count > 0) Tag = DropDownItems[0].Tag; + return Tag; + } + set { AdoptFromTag(value); } + } + + protected override void OnDropDownItemClicked(ToolStripItemClickedEventArgs e) + { + ToolStripItem clickedItem = e.ClickedItem; + if (Tag == null || !Tag.Equals(clickedItem.Tag)) + { + Tag = clickedItem.Tag; + Image = clickedItem.Image; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag")); + } + + base.OnDropDownItemClicked(e); + } + + private void AdoptFromTag(object tag) + { + if (Tag == null || !Tag.Equals(tag)) + { + Tag = tag; + foreach (ToolStripItem item in DropDownItems) + { + if (item.Tag != null && item.Tag.Equals(tag)) + { + Image = item.Image; + break; + } + } + + Tag = tag; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag")); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/ColorButton.cs b/src/Greenshot/Controls/ColorButton.cs index fe31d2e11..068033522 100644 --- a/src/Greenshot/Controls/ColorButton.cs +++ b/src/Greenshot/Controls/ColorButton.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Drawing; @@ -26,65 +27,73 @@ using System.Windows.Forms; using GreenshotPlugin.Controls; using ColorDialog = Greenshot.Forms.ColorDialog; -namespace Greenshot.Controls { - /// - /// Description of ColorButton. - /// - public class ColorButton : Button, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; - private Color _selectedColor = Color.White; +namespace Greenshot.Controls +{ + /// + /// Description of ColorButton. + /// + public class ColorButton : Button, IGreenshotLanguageBindable + { + public event PropertyChangedEventHandler PropertyChanged; + private Color _selectedColor = Color.White; - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } - public ColorButton() { - Click += ColorButtonClick; - } + public ColorButton() + { + Click += ColorButtonClick; + } - public Color SelectedColor { - get {return _selectedColor;} - set { - _selectedColor = value; + public Color SelectedColor + { + get { return _selectedColor; } + set + { + _selectedColor = value; - Brush brush; - if(value != Color.Transparent) { - brush = new SolidBrush(value); - } else { - brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray); - } - - if (Image != null) + Brush brush; + if (value != Color.Transparent) { - using Graphics graphics = Graphics.FromImage(Image); - graphics.FillRectangle(brush, new Rectangle(4,17,16,3)); + brush = new SolidBrush(value); + } + else + { + brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray); } - // cleanup GDI Object - brush.Dispose(); - Invalidate(); - } - } + if (Image != null) + { + using Graphics graphics = Graphics.FromImage(Image); + graphics.FillRectangle(brush, new Rectangle(4, 17, 16, 3)); + } - private void ColorButtonClick(object sender, EventArgs e) { - var colorDialog = new ColorDialog - { - Color = SelectedColor - }; - // Using the parent to make sure the dialog doesn't show on another window - colorDialog.ShowDialog(Parent.Parent); - if (colorDialog.DialogResult == DialogResult.Cancel) - { - return; - } - if (colorDialog.Color.Equals(SelectedColor)) - { - return; - } - SelectedColor = colorDialog.Color; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor")); - } - } -} + // cleanup GDI Object + brush.Dispose(); + Invalidate(); + } + } + + private void ColorButtonClick(object sender, EventArgs e) + { + var colorDialog = new ColorDialog + { + Color = SelectedColor + }; + // Using the parent to make sure the dialog doesn't show on another window + colorDialog.ShowDialog(Parent.Parent); + if (colorDialog.DialogResult == DialogResult.Cancel) + { + return; + } + + if (colorDialog.Color.Equals(SelectedColor)) + { + return; + } + + SelectedColor = colorDialog.Color; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor")); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs b/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs index e5ebf5478..e85817d7f 100644 --- a/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs +++ b/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs @@ -24,22 +24,27 @@ using System.Drawing; using System.Windows.Forms; using GreenshotPlugin.IniFile; -namespace Greenshot.Controls { - /// - /// ToolStripProfessionalRenderer which draws the Check correctly when the icons are larger - /// - public class ContextMenuToolStripProfessionalRenderer : ToolStripProfessionalRenderer { - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static Image _scaledCheckbox; +namespace Greenshot.Controls +{ + /// + /// ToolStripProfessionalRenderer which draws the Check correctly when the icons are larger + /// + public class ContextMenuToolStripProfessionalRenderer : ToolStripProfessionalRenderer + { + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static Image _scaledCheckbox; - protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) { - if (_scaledCheckbox == null || _scaledCheckbox.Size != CoreConfig.ScaledIconSize) { - _scaledCheckbox?.Dispose(); - _scaledCheckbox = ImageHelper.ResizeImage(e.Image, true, CoreConfig.ScaledIconSize.Width, CoreConfig.ScaledIconSize.Height, null); - } - Rectangle old = e.ImageRectangle; - ToolStripItemImageRenderEventArgs clone = new ToolStripItemImageRenderEventArgs(e.Graphics, e.Item, _scaledCheckbox, new Rectangle(old.X, 0, old.Width, old.Height)); - base.OnRenderItemCheck(clone); - } - } -} + protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) + { + if (_scaledCheckbox == null || _scaledCheckbox.Size != CoreConfig.ScaledIconSize) + { + _scaledCheckbox?.Dispose(); + _scaledCheckbox = ImageHelper.ResizeImage(e.Image, true, CoreConfig.ScaledIconSize.Width, CoreConfig.ScaledIconSize.Height, null); + } + + Rectangle old = e.ImageRectangle; + ToolStripItemImageRenderEventArgs clone = new ToolStripItemImageRenderEventArgs(e.Graphics, e.Item, _scaledCheckbox, new Rectangle(old.X, 0, old.Width, old.Height)); + base.OnRenderItemCheck(clone); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs b/src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs index d559d771b..90f3a7818 100644 --- a/src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs +++ b/src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs @@ -22,46 +22,63 @@ using System.Drawing; using System.Windows.Forms; -namespace Greenshot.Controls { - /// - /// Prevent having a gradient background in the toolstrip, and the overflow button - /// See: http://stackoverflow.com/a/16926979 - /// - internal class CustomProfessionalColorTable : ProfessionalColorTable { - public override Color ToolStripGradientBegin { - get { return SystemColors.Control; } - } - public override Color ToolStripGradientMiddle { - get { return SystemColors.Control; } - } - public override Color ToolStripGradientEnd { - get { return SystemColors.Control; } - } - public override Color OverflowButtonGradientBegin { - get { return SystemColors.Control; } - } - public override Color OverflowButtonGradientMiddle { - get { return SystemColors.Control; } - } - public override Color OverflowButtonGradientEnd { - get { return SystemColors.Control; } - } - } +namespace Greenshot.Controls +{ + /// + /// Prevent having a gradient background in the toolstrip, and the overflow button + /// See: http://stackoverflow.com/a/16926979 + /// + internal class CustomProfessionalColorTable : ProfessionalColorTable + { + public override Color ToolStripGradientBegin + { + get { return SystemColors.Control; } + } - /// - /// ToolStripProfessionalRenderer without having a visual artifact - /// See: http://stackoverflow.com/a/16926979 and http://stackoverflow.com/a/13418840 - /// - public class CustomToolStripProfessionalRenderer : ToolStripProfessionalRenderer { - public CustomToolStripProfessionalRenderer() : base(new CustomProfessionalColorTable()) { - RoundedEdges = false; - } - /// - /// By overriding the OnRenderToolStripBorder we can make the ToolStrip without border - /// - /// - protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) { - // Don't draw a border - } - } -} + public override Color ToolStripGradientMiddle + { + get { return SystemColors.Control; } + } + + public override Color ToolStripGradientEnd + { + get { return SystemColors.Control; } + } + + public override Color OverflowButtonGradientBegin + { + get { return SystemColors.Control; } + } + + public override Color OverflowButtonGradientMiddle + { + get { return SystemColors.Control; } + } + + public override Color OverflowButtonGradientEnd + { + get { return SystemColors.Control; } + } + } + + /// + /// ToolStripProfessionalRenderer without having a visual artifact + /// See: http://stackoverflow.com/a/16926979 and http://stackoverflow.com/a/13418840 + /// + public class CustomToolStripProfessionalRenderer : ToolStripProfessionalRenderer + { + public CustomToolStripProfessionalRenderer() : base(new CustomProfessionalColorTable()) + { + RoundedEdges = false; + } + + /// + /// By overriding the OnRenderToolStripBorder we can make the ToolStrip without border + /// + /// + protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) + { + // Don't draw a border + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/FontFamilyComboBox.cs b/src/Greenshot/Controls/FontFamilyComboBox.cs index d37244eab..db1cef03e 100644 --- a/src/Greenshot/Controls/FontFamilyComboBox.cs +++ b/src/Greenshot/Controls/FontFamilyComboBox.cs @@ -24,97 +24,118 @@ using System.ComponentModel; using System.Drawing; using System.Windows.Forms; -namespace Greenshot.Controls { - /// - /// ToolStripComboBox containing installed font families, - /// implementing INotifyPropertyChanged for data binding - /// - public class FontFamilyComboBox : ToolStripComboBox, INotifyPropertyChanged { - public event PropertyChangedEventHandler PropertyChanged; +namespace Greenshot.Controls +{ + /// + /// ToolStripComboBox containing installed font families, + /// implementing INotifyPropertyChanged for data binding + /// + public class FontFamilyComboBox : ToolStripComboBox, INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; - public FontFamily FontFamily { - get { return (FontFamily)SelectedItem; } - set { - if (!SelectedItem.Equals(value)) { - SelectedItem = value; - } - } - } - - public FontFamilyComboBox() - { - if (ComboBox != null) - { - ComboBox.DataSource = FontFamily.Families; - ComboBox.DisplayMember = "Name"; - SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged; - ComboBox.DrawMode = DrawMode.OwnerDrawFixed; - ComboBox.DrawItem += ComboBox_DrawItem; - } - } - - private void ComboBox_DrawItem(object sender, DrawItemEventArgs e) { - // DrawBackground handles drawing the background (i.e,. hot-tracked v. not) - // It uses the system colors (Bluish, and and white, by default) - // same as calling e.Graphics.FillRectangle ( SystemBrushes.Highlight, e.Bounds ); - e.DrawBackground(); - - if (e.Index > -1) { - FontFamily fontFamily = Items[e.Index] as FontFamily; - FontStyle fontStyle = FontStyle.Regular; - if (fontFamily != null && !fontFamily.IsStyleAvailable(FontStyle.Regular)) { - if (fontFamily.IsStyleAvailable(FontStyle.Bold)) { - fontStyle = FontStyle.Bold; - } else if (fontFamily.IsStyleAvailable(FontStyle.Italic)) { - fontStyle = FontStyle.Italic; - } else if (fontFamily.IsStyleAvailable(FontStyle.Strikeout)) { - fontStyle = FontStyle.Strikeout; - } else if (fontFamily.IsStyleAvailable(FontStyle.Underline)) { - fontStyle = FontStyle.Underline; - } - } - try { - if (fontFamily != null) - { - DrawText(e.Graphics, fontFamily, fontStyle, e.Bounds, fontFamily.Name); - } - } catch { - // If the drawing failed, BUG-1770 seems to have a weird case that causes: Font 'Lucida Sans Typewriter' does not support style 'Regular' - if (fontFamily != null) - { - DrawText(e.Graphics, FontFamily.GenericSansSerif, FontStyle.Regular, e.Bounds, fontFamily.Name); - } - } - } - // Uncomment this if you actually like the way the focus rectangle looks - //e.DrawFocusRectangle (); - } - - /// - /// Helper method to draw the string - /// - /// - /// - /// - /// - /// - private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, Rectangle bounds, string text) + public FontFamily FontFamily { - using Font font = new Font(fontFamily, Font.Size + 5, fontStyle, GraphicsUnit.Pixel); - // Make sure the text is visible by centering it in the line - using StringFormat stringFormat = new StringFormat - { - LineAlignment = StringAlignment.Center - }; - graphics.DrawString(text, font, Brushes.Black, bounds, stringFormat); + get { return (FontFamily) SelectedItem; } + set + { + if (!SelectedItem.Equals(value)) + { + SelectedItem = value; + } + } } - private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) { + public FontFamilyComboBox() + { + if (ComboBox != null) + { + ComboBox.DataSource = FontFamily.Families; + ComboBox.DisplayMember = "Name"; + SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged; + ComboBox.DrawMode = DrawMode.OwnerDrawFixed; + ComboBox.DrawItem += ComboBox_DrawItem; + } + } + + private void ComboBox_DrawItem(object sender, DrawItemEventArgs e) + { + // DrawBackground handles drawing the background (i.e,. hot-tracked v. not) + // It uses the system colors (Bluish, and and white, by default) + // same as calling e.Graphics.FillRectangle ( SystemBrushes.Highlight, e.Bounds ); + e.DrawBackground(); + + if (e.Index > -1) + { + FontFamily fontFamily = Items[e.Index] as FontFamily; + FontStyle fontStyle = FontStyle.Regular; + if (fontFamily != null && !fontFamily.IsStyleAvailable(FontStyle.Regular)) + { + if (fontFamily.IsStyleAvailable(FontStyle.Bold)) + { + fontStyle = FontStyle.Bold; + } + else if (fontFamily.IsStyleAvailable(FontStyle.Italic)) + { + fontStyle = FontStyle.Italic; + } + else if (fontFamily.IsStyleAvailable(FontStyle.Strikeout)) + { + fontStyle = FontStyle.Strikeout; + } + else if (fontFamily.IsStyleAvailable(FontStyle.Underline)) + { + fontStyle = FontStyle.Underline; + } + } + + try + { + if (fontFamily != null) + { + DrawText(e.Graphics, fontFamily, fontStyle, e.Bounds, fontFamily.Name); + } + } + catch + { + // If the drawing failed, BUG-1770 seems to have a weird case that causes: Font 'Lucida Sans Typewriter' does not support style 'Regular' + if (fontFamily != null) + { + DrawText(e.Graphics, FontFamily.GenericSansSerif, FontStyle.Regular, e.Bounds, fontFamily.Name); + } + } + } + + // Uncomment this if you actually like the way the focus rectangle looks + //e.DrawFocusRectangle (); + } + + /// + /// Helper method to draw the string + /// + /// + /// + /// + /// + /// + private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, Rectangle bounds, string text) + { + using Font font = new Font(fontFamily, Font.Size + 5, fontStyle, GraphicsUnit.Pixel); + // Make sure the text is visible by centering it in the line + using StringFormat stringFormat = new StringFormat + { + LineAlignment = StringAlignment.Center + }; + graphics.DrawString(text, font, Brushes.Black, bounds, stringFormat); + } + + private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) + { if (PropertyChanged == null) return; PropertyChanged(this, new PropertyChangedEventArgs("Text")); PropertyChanged(this, new PropertyChangedEventArgs("FontFamily")); PropertyChanged(this, new PropertyChangedEventArgs("SelectedIndex")); PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem")); } - } -} + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/MenuStripEx.cs b/src/Greenshot/Controls/MenuStripEx.cs index 7dda22931..34f1d168a 100644 --- a/src/Greenshot/Controls/MenuStripEx.cs +++ b/src/Greenshot/Controls/MenuStripEx.cs @@ -18,45 +18,48 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Windows.Forms; using GreenshotPlugin.UnmanagedHelpers.Enums; -namespace Greenshot.Controls { - /// - /// This is an extension of the default MenuStrip and allows us to click it even when the form doesn't have focus. - /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx - /// - public class MenuStripEx : MenuStrip { - private enum NativeConstants : uint { - MA_ACTIVATE = 1, - MA_ACTIVATEANDEAT = 2, - } +namespace Greenshot.Controls +{ + /// + /// This is an extension of the default MenuStrip and allows us to click it even when the form doesn't have focus. + /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx + /// + public class MenuStripEx : MenuStrip + { + private enum NativeConstants : uint + { + MA_ACTIVATE = 1, + MA_ACTIVATEANDEAT = 2, + } - private bool _clickThrough; - /// - /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus. - /// - /// - /// Default value is false, which is the same behavior provided by the base ToolStrip class. - /// - public bool ClickThrough { - get { - return _clickThrough; - } + private bool _clickThrough; - set { - _clickThrough = value; - } - } + /// + /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus. + /// + /// + /// Default value is false, which is the same behavior provided by the base ToolStrip class. + /// + public bool ClickThrough + { + get { return _clickThrough; } - protected override void WndProc(ref Message m) { - base.WndProc(ref m); + set { _clickThrough = value; } + } + + protected override void WndProc(ref Message m) + { + base.WndProc(ref m); var windowsMessage = (WindowsMessages) m.Msg; - if (_clickThrough && windowsMessage == WindowsMessages.WM_MOUSEACTIVATE && m.Result == (IntPtr)NativeConstants.MA_ACTIVATEANDEAT) + if (_clickThrough && windowsMessage == WindowsMessages.WM_MOUSEACTIVATE && m.Result == (IntPtr) NativeConstants.MA_ACTIVATEANDEAT) { - m.Result = (IntPtr)NativeConstants.MA_ACTIVATE; - } - } - } -} + m.Result = (IntPtr) NativeConstants.MA_ACTIVATE; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/NonJumpingPanel.cs b/src/Greenshot/Controls/NonJumpingPanel.cs index d5565c637..8f14303a8 100644 --- a/src/Greenshot/Controls/NonJumpingPanel.cs +++ b/src/Greenshot/Controls/NonJumpingPanel.cs @@ -67,4 +67,4 @@ namespace Greenshot.Controls } } } -} +} \ No newline at end of file diff --git a/src/Greenshot/Controls/Pipette.cs b/src/Greenshot/Controls/Pipette.cs index ca7333d81..d4636b017 100644 --- a/src/Greenshot/Controls/Pipette.cs +++ b/src/Greenshot/Controls/Pipette.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Drawing; @@ -27,40 +28,43 @@ using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.UnmanagedHelpers.Enums; using ColorDialog = Greenshot.Forms.ColorDialog; -namespace Greenshot.Controls { - /// - /// This code was supplied by Hi-Coder as a patch for Greenshot - /// Needed some modifications to be stable. - /// - public sealed class Pipette : Label, IMessageFilter, IDisposable { - private MovableShowColorForm _movableShowColorForm; - private bool _dragging; - private Cursor _cursor; - private readonly Bitmap _image; - private const int VkEsc = 27; +namespace Greenshot.Controls +{ + /// + /// This code was supplied by Hi-Coder as a patch for Greenshot + /// Needed some modifications to be stable. + /// + public sealed class Pipette : Label, IMessageFilter, IDisposable + { + private MovableShowColorForm _movableShowColorForm; + private bool _dragging; + private Cursor _cursor; + private readonly Bitmap _image; + private const int VkEsc = 27; - public event EventHandler PipetteUsed; + public event EventHandler PipetteUsed; - public Pipette() { - BorderStyle = BorderStyle.FixedSingle; - _dragging = false; - _image = (Bitmap)new ComponentResourceManager(typeof(ColorDialog)).GetObject("pipette.Image"); - Image = _image; - _cursor = CreateCursor(_image, 1, 14); - _movableShowColorForm = new MovableShowColorForm(); - Application.AddMessageFilter(this); - } - - /// - /// Create a cursor from the supplied bitmap & hotspot coordinates - /// - /// Bitmap to create an icon from - /// Hotspot X coordinate - /// Hotspot Y coordinate - /// Cursor - private static Cursor CreateCursor(Bitmap bitmap, int hotspotX, int hotspotY) + public Pipette() { - using SafeIconHandle iconHandle = new SafeIconHandle( bitmap.GetHicon()); + BorderStyle = BorderStyle.FixedSingle; + _dragging = false; + _image = (Bitmap) new ComponentResourceManager(typeof(ColorDialog)).GetObject("pipette.Image"); + Image = _image; + _cursor = CreateCursor(_image, 1, 14); + _movableShowColorForm = new MovableShowColorForm(); + Application.AddMessageFilter(this); + } + + /// + /// Create a cursor from the supplied bitmap & hotspot coordinates + /// + /// Bitmap to create an icon from + /// Hotspot X coordinate + /// Hotspot Y coordinate + /// Cursor + private static Cursor CreateCursor(Bitmap bitmap, int hotspotX, int hotspotY) + { + using SafeIconHandle iconHandle = new SafeIconHandle(bitmap.GetHicon()); User32.GetIconInfo(iconHandle, out var iconInfo); iconInfo.xHotspot = hotspotX; iconInfo.yHotspot = hotspotY; @@ -69,106 +73,132 @@ namespace Greenshot.Controls { return new Cursor(icon); } - /// - /// The bulk of the clean-up code is implemented in Dispose(bool) - /// - public new void Dispose() { - Dispose(true); - } + /// + /// The bulk of the clean-up code is implemented in Dispose(bool) + /// + public new void Dispose() + { + Dispose(true); + } - /// - /// This Dispose is called from the Dispose and the Destructor. - /// - /// When disposing==true all non-managed resources should be freed too! - protected override void Dispose(bool disposing) { - if (disposing) { - if (_cursor != null) { - _cursor.Dispose(); - } - _movableShowColorForm?.Dispose(); - } - _movableShowColorForm = null; - _cursor = null; - base.Dispose(disposing); - } + /// + /// This Dispose is called from the Dispose and the Destructor. + /// + /// When disposing==true all non-managed resources should be freed too! + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_cursor != null) + { + _cursor.Dispose(); + } - /// - /// Handle the mouse down on the Pipette "label", we take the capture and move the zoomer to the current location - /// - /// MouseEventArgs - protected override void OnMouseDown(MouseEventArgs e) { - if (e.Button == MouseButtons.Left) { - User32.SetCapture(Handle); - _movableShowColorForm.MoveTo(PointToScreen(new Point(e.X, e.Y))); - } - base.OnMouseDown(e); - } + _movableShowColorForm?.Dispose(); + } - /// - /// Handle the mouse up on the Pipette "label", we release the capture and fire the PipetteUsed event - /// - /// MouseEventArgs - protected override void OnMouseUp(MouseEventArgs e) { - if (e.Button == MouseButtons.Left) - { - //Release Capture should consume MouseUp when canceled with the escape key - User32.ReleaseCapture(); - PipetteUsed?.Invoke(this, new PipetteUsedArgs(_movableShowColorForm.color)); - } - base.OnMouseUp(e); - } + _movableShowColorForm = null; + _cursor = null; + base.Dispose(disposing); + } - /// - /// Handle the mouse Move event, we move the ColorUnderCursor to the current location. - /// - /// MouseEventArgs - protected override void OnMouseMove(MouseEventArgs e) { - if (_dragging) { - //display the form on the right side of the cursor by default; - Point zp = PointToScreen(new Point(e.X, e.Y)); - _movableShowColorForm.MoveTo(zp); - } - base.OnMouseMove(e); - } + /// + /// Handle the mouse down on the Pipette "label", we take the capture and move the zoomer to the current location + /// + /// MouseEventArgs + protected override void OnMouseDown(MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + User32.SetCapture(Handle); + _movableShowColorForm.MoveTo(PointToScreen(new Point(e.X, e.Y))); + } - /// - /// Handle the MouseCaptureChanged event - /// - /// - protected override void OnMouseCaptureChanged(EventArgs e) { - if (Capture) { - _dragging = true; - Image = null; - Cursor c = _cursor; - Cursor = c; - _movableShowColorForm.Visible = true; - } else { - _dragging = false; - Image = _image; - Cursor = Cursors.Arrow; - _movableShowColorForm.Visible = false; - } - Update(); - base.OnMouseCaptureChanged(e); - } + base.OnMouseDown(e); + } - public bool PreFilterMessage(ref Message m) { - if (_dragging) { - if (m.Msg == (int)WindowsMessages.WM_CHAR) { - if ((int)m.WParam == VkEsc) { - User32.ReleaseCapture(); - } - } - } - return false; - } + /// + /// Handle the mouse up on the Pipette "label", we release the capture and fire the PipetteUsed event + /// + /// MouseEventArgs + protected override void OnMouseUp(MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + //Release Capture should consume MouseUp when canceled with the escape key + User32.ReleaseCapture(); + PipetteUsed?.Invoke(this, new PipetteUsedArgs(_movableShowColorForm.color)); + } + + base.OnMouseUp(e); + } + + /// + /// Handle the mouse Move event, we move the ColorUnderCursor to the current location. + /// + /// MouseEventArgs + protected override void OnMouseMove(MouseEventArgs e) + { + if (_dragging) + { + //display the form on the right side of the cursor by default; + Point zp = PointToScreen(new Point(e.X, e.Y)); + _movableShowColorForm.MoveTo(zp); + } + + base.OnMouseMove(e); + } + + /// + /// Handle the MouseCaptureChanged event + /// + /// + protected override void OnMouseCaptureChanged(EventArgs e) + { + if (Capture) + { + _dragging = true; + Image = null; + Cursor c = _cursor; + Cursor = c; + _movableShowColorForm.Visible = true; + } + else + { + _dragging = false; + Image = _image; + Cursor = Cursors.Arrow; + _movableShowColorForm.Visible = false; + } + + Update(); + base.OnMouseCaptureChanged(e); + } + + public bool PreFilterMessage(ref Message m) + { + if (_dragging) + { + if (m.Msg == (int) WindowsMessages.WM_CHAR) + { + if ((int) m.WParam == VkEsc) + { + User32.ReleaseCapture(); + } + } + } + + return false; + } } - public class PipetteUsedArgs : EventArgs { - public Color Color; + public class PipetteUsedArgs : EventArgs + { + public Color Color; - public PipetteUsedArgs(Color c) { - Color = c; - } - } -} + public PipetteUsedArgs(Color c) + { + Color = c; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/ToolStripColorButton.cs b/src/Greenshot/Controls/ToolStripColorButton.cs index 951e117fd..ffc2606f5 100644 --- a/src/Greenshot/Controls/ToolStripColorButton.cs +++ b/src/Greenshot/Controls/ToolStripColorButton.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Drawing; @@ -26,63 +27,71 @@ using System.Windows.Forms; using GreenshotPlugin.Controls; using ColorDialog = Greenshot.Forms.ColorDialog; -namespace Greenshot.Controls { - public class ToolStripColorButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; +namespace Greenshot.Controls +{ + public class ToolStripColorButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable + { + public event PropertyChangedEventHandler PropertyChanged; - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } - private Color _selectedColor = Color.Transparent; - - public ToolStripColorButton() { - Click+= ColorButtonClick; - } + private Color _selectedColor = Color.Transparent; - public Color SelectedColor { - get {return _selectedColor;} - set { - _selectedColor = value; + public ToolStripColorButton() + { + Click += ColorButtonClick; + } - Brush brush; - if(value != Color.Transparent) { - brush = new SolidBrush(value); - } else { - brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray); - } + public Color SelectedColor + { + get { return _selectedColor; } + set + { + _selectedColor = value; - if (Image != null) + Brush brush; + if (value != Color.Transparent) { - using Graphics graphics = Graphics.FromImage(Image); - graphics.FillRectangle(brush, new Rectangle(0,13,16,3)); + brush = new SolidBrush(value); + } + else + { + brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray); } - // cleanup GDI Object - brush.Dispose(); - Invalidate(); - } - } + if (Image != null) + { + using Graphics graphics = Graphics.FromImage(Image); + graphics.FillRectangle(brush, new Rectangle(0, 13, 16, 3)); + } - private void ColorButtonClick(object sender, EventArgs e) { - var colorDialog = new ColorDialog - { - Color = SelectedColor - }; - // Using the parent to make sure the dialog doesn't show on another window - colorDialog.ShowDialog(Parent.Parent); - if (colorDialog.DialogResult == DialogResult.Cancel) - { - return; - } - if (colorDialog.Color.Equals(SelectedColor)) - { - return; - } - SelectedColor = colorDialog.Color; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor")); - } - } -} + // cleanup GDI Object + brush.Dispose(); + Invalidate(); + } + } + + private void ColorButtonClick(object sender, EventArgs e) + { + var colorDialog = new ColorDialog + { + Color = SelectedColor + }; + // Using the parent to make sure the dialog doesn't show on another window + colorDialog.ShowDialog(Parent.Parent); + if (colorDialog.DialogResult == DialogResult.Cancel) + { + return; + } + + if (colorDialog.Color.Equals(SelectedColor)) + { + return; + } + + SelectedColor = colorDialog.Color; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor")); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/ToolStripEx.cs b/src/Greenshot/Controls/ToolStripEx.cs index 7d2ca63ed..c7ff79048 100644 --- a/src/Greenshot/Controls/ToolStripEx.cs +++ b/src/Greenshot/Controls/ToolStripEx.cs @@ -18,45 +18,49 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Windows.Forms; -namespace Greenshot.Controls { - /// - /// This is an extension of the default ToolStrip and allows us to click it even when the form doesn't have focus. - /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx - /// - internal class ToolStripEx : ToolStrip { - private const int WM_MOUSEACTIVATE = 0x21; +namespace Greenshot.Controls +{ + /// + /// This is an extension of the default ToolStrip and allows us to click it even when the form doesn't have focus. + /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx + /// + internal class ToolStripEx : ToolStrip + { + private const int WM_MOUSEACTIVATE = 0x21; - private enum NativeConstants : uint { - MA_ACTIVATE = 1, - MA_ACTIVATEANDEAT = 2, - } + private enum NativeConstants : uint + { + MA_ACTIVATE = 1, + MA_ACTIVATEANDEAT = 2, + } - private bool _clickThrough; - /// - /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus. - /// - /// - /// Default value is false, which is the same behavior provided by the base ToolStrip class. - /// + private bool _clickThrough; - public bool ClickThrough { - get { - return _clickThrough; - } + /// + /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus. + /// + /// + /// Default value is false, which is the same behavior provided by the base ToolStrip class. + /// - set { - _clickThrough = value; - } - } + public bool ClickThrough + { + get { return _clickThrough; } - protected override void WndProc(ref Message m) { - base.WndProc(ref m); - if (_clickThrough && m.Msg == WM_MOUSEACTIVATE && m.Result == (IntPtr)NativeConstants.MA_ACTIVATEANDEAT) { - m.Result = (IntPtr)NativeConstants.MA_ACTIVATE; - } - } - } -} + set { _clickThrough = value; } + } + + protected override void WndProc(ref Message m) + { + base.WndProc(ref m); + if (_clickThrough && m.Msg == WM_MOUSEACTIVATE && m.Result == (IntPtr) NativeConstants.MA_ACTIVATEANDEAT) + { + m.Result = (IntPtr) NativeConstants.MA_ACTIVATE; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/ToolStripNumericUpDown.cs b/src/Greenshot/Controls/ToolStripNumericUpDown.cs index 13652fc41..ecbc470ca 100644 --- a/src/Greenshot/Controls/ToolStripNumericUpDown.cs +++ b/src/Greenshot/Controls/ToolStripNumericUpDown.cs @@ -18,62 +18,71 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Windows.Forms; using System.Windows.Forms.Design; -namespace Greenshot.Controls { +namespace Greenshot.Controls +{ + [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)] + public class ToolStripNumericUpDown : ToolStripControlHost, INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; - [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)] - public class ToolStripNumericUpDown : ToolStripControlHost, INotifyPropertyChanged - { - public event PropertyChangedEventHandler PropertyChanged; - - public ToolStripNumericUpDown() : base(new NumericUpDown()) - { - } - - public NumericUpDown NumericUpDown => Control as NumericUpDown; + public ToolStripNumericUpDown() : base(new NumericUpDown()) + { + } - public decimal Value - { - get { return NumericUpDown.Value; } - set { NumericUpDown.Value = value;} - } - public decimal Minimum { - get { return NumericUpDown.Minimum; } - set { NumericUpDown.Minimum = value; } - } - - public decimal Maximum { - get { return NumericUpDown.Maximum; } - set { NumericUpDown.Maximum = value; } - } - - public decimal Increment { - get { return NumericUpDown.Increment; } - set { NumericUpDown.Increment = value; } - } - - public int DecimalPlaces { - get { return NumericUpDown.DecimalPlaces; } - set { NumericUpDown.DecimalPlaces = value; } - } - - - protected override void OnSubscribeControlEvents(Control control) { - base.OnSubscribeControlEvents(control); - NumericUpDown.ValueChanged += _valueChanged; - } - protected override void OnUnsubscribeControlEvents(Control control) { - base.OnUnsubscribeControlEvents(control); - NumericUpDown.ValueChanged -= _valueChanged; - } - - private void _valueChanged(object sender, EventArgs e) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); - } - } -} + public NumericUpDown NumericUpDown => Control as NumericUpDown; + + public decimal Value + { + get { return NumericUpDown.Value; } + set { NumericUpDown.Value = value; } + } + + public decimal Minimum + { + get { return NumericUpDown.Minimum; } + set { NumericUpDown.Minimum = value; } + } + + public decimal Maximum + { + get { return NumericUpDown.Maximum; } + set { NumericUpDown.Maximum = value; } + } + + public decimal Increment + { + get { return NumericUpDown.Increment; } + set { NumericUpDown.Increment = value; } + } + + public int DecimalPlaces + { + get { return NumericUpDown.DecimalPlaces; } + set { NumericUpDown.DecimalPlaces = value; } + } + + + protected override void OnSubscribeControlEvents(Control control) + { + base.OnSubscribeControlEvents(control); + NumericUpDown.ValueChanged += _valueChanged; + } + + protected override void OnUnsubscribeControlEvents(Control control) + { + base.OnUnsubscribeControlEvents(control); + NumericUpDown.ValueChanged -= _valueChanged; + } + + private void _valueChanged(object sender, EventArgs e) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/ClipboardDestination.cs b/src/Greenshot/Destinations/ClipboardDestination.cs index a1172ede4..88a2e2ecb 100644 --- a/src/Greenshot/Destinations/ClipboardDestination.cs +++ b/src/Greenshot/Destinations/ClipboardDestination.cs @@ -18,61 +18,64 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Windows.Forms; - using Greenshot.Configuration; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace Greenshot.Destinations { - /// - /// Description of ClipboardDestination. - /// - public class ClipboardDestination : AbstractDestination { - public const string DESIGNATION = "Clipboard"; +namespace Greenshot.Destinations +{ + /// + /// Description of ClipboardDestination. + /// + public class ClipboardDestination : AbstractDestination + { + public const string DESIGNATION = "Clipboard"; - public override string Designation { - get { - return DESIGNATION; - } - } + public override string Designation + { + get { return DESIGNATION; } + } - public override string Description { - get { - return Language.GetString(LangKey.settings_destination_clipboard); - } - } - public override int Priority { - get { - return 2; - } - } - - public override Keys EditorShortcutKeys { - get { - return Keys.Control | Keys.Shift | Keys.C; - } - } + public override string Description + { + get { return Language.GetString(LangKey.settings_destination_clipboard); } + } - public override Image DisplayIcon { - get { - return GreenshotResources.GetImage("Clipboard.Image"); - } - } + public override int Priority + { + get { return 2; } + } - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - try { - ClipboardHelper.SetClipboardData(surface); - exportInformation.ExportMade = true; - } catch (Exception) { - // TODO: Change to general logic in ProcessExport - surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetString(LangKey.editor_clipboardfailed)); - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + public override Keys EditorShortcutKeys + { + get { return Keys.Control | Keys.Shift | Keys.C; } + } + + public override Image DisplayIcon + { + get { return GreenshotResources.GetImage("Clipboard.Image"); } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + try + { + ClipboardHelper.SetClipboardData(surface); + exportInformation.ExportMade = true; + } + catch (Exception) + { + // TODO: Change to general logic in ProcessExport + surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetString(LangKey.editor_clipboardfailed)); + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/EditorDestination.cs b/src/Greenshot/Destinations/EditorDestination.cs index 220359238..b22cc0894 100644 --- a/src/Greenshot/Destinations/EditorDestination.cs +++ b/src/Greenshot/Destinations/EditorDestination.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; @@ -29,97 +30,125 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Forms; using log4net; -namespace Greenshot.Destinations { - /// - /// Description of EditorDestination. - /// - public class EditorDestination : AbstractDestination { - private static readonly ILog LOG = LogManager.GetLogger(typeof(EditorDestination)); - private static readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection(); - public const string DESIGNATION = "Editor"; - private readonly IImageEditor editor; - private static readonly Image greenshotIcon = GreenshotResources.GetGreenshotIcon().ToBitmap(); +namespace Greenshot.Destinations +{ + /// + /// Description of EditorDestination. + /// + public class EditorDestination : AbstractDestination + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(EditorDestination)); + private static readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection(); + public const string DESIGNATION = "Editor"; + private readonly IImageEditor editor; + private static readonly Image greenshotIcon = GreenshotResources.GetGreenshotIcon().ToBitmap(); public EditorDestination() { // Do not remove, is needed for the framework } - public EditorDestination(IImageEditor editor) { - this.editor = editor; - } + public EditorDestination(IImageEditor editor) + { + this.editor = editor; + } - public override string Designation => DESIGNATION; + public override string Designation => DESIGNATION; - public override string Description { - get { - if (editor == null) { - return Language.GetString(LangKey.settings_destination_editor); - } - return Language.GetString(LangKey.settings_destination_editor) + " - " + editor.CaptureDetails.Title; - } - } + public override string Description + { + get + { + if (editor == null) + { + return Language.GetString(LangKey.settings_destination_editor); + } - public override int Priority => 1; + return Language.GetString(LangKey.settings_destination_editor) + " - " + editor.CaptureDetails.Title; + } + } + + public override int Priority => 1; public override bool IsDynamic => true; public override Image DisplayIcon => greenshotIcon; - public override IEnumerable DynamicDestinations() { - foreach (IImageEditor someEditor in ImageEditorForm.Editors) { - yield return new EditorDestination(someEditor); - } - } + public override IEnumerable DynamicDestinations() + { + foreach (IImageEditor someEditor in ImageEditorForm.Editors) + { + yield return new EditorDestination(someEditor); + } + } - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - // Make sure we collect the garbage before opening the screenshot - GC.Collect(); - GC.WaitForPendingFinalizers(); + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + // Make sure we collect the garbage before opening the screenshot + GC.Collect(); + GC.WaitForPendingFinalizers(); - bool modified = surface.Modified; - if (editor == null) { - if (editorConfiguration.ReuseEditor) { - foreach(IImageEditor openedEditor in ImageEditorForm.Editors) { + bool modified = surface.Modified; + if (editor == null) + { + if (editorConfiguration.ReuseEditor) + { + foreach (IImageEditor openedEditor in ImageEditorForm.Editors) + { if (openedEditor.Surface.Modified) continue; - + openedEditor.Surface = surface; exportInformation.ExportMade = true; break; } - } - if (!exportInformation.ExportMade) { - try { - ImageEditorForm editorForm = new ImageEditorForm(surface, !surface.Modified); // Output made?? + } - if (!string.IsNullOrEmpty(captureDetails.Filename)) { - editorForm.SetImagePath(captureDetails.Filename); - } - editorForm.Show(); - editorForm.Activate(); - LOG.Debug("Finished opening Editor"); - exportInformation.ExportMade = true; - } catch (Exception e) { - LOG.Error(e); - exportInformation.ErrorMessage = e.Message; - } - } - } else { - try { - using (Image image = surface.GetImageForExport()) { - editor.Surface.AddImageContainer(image, 10, 10); - } - exportInformation.ExportMade = true; - } catch (Exception e) { - LOG.Error(e); - exportInformation.ErrorMessage = e.Message; - } - } - ProcessExport(exportInformation, surface); - // Workaround for the modified flag when using the editor. - surface.Modified = modified; - return exportInformation; - } - } -} + if (!exportInformation.ExportMade) + { + try + { + ImageEditorForm editorForm = new ImageEditorForm(surface, !surface.Modified); // Output made?? + + if (!string.IsNullOrEmpty(captureDetails.Filename)) + { + editorForm.SetImagePath(captureDetails.Filename); + } + + editorForm.Show(); + editorForm.Activate(); + LOG.Debug("Finished opening Editor"); + exportInformation.ExportMade = true; + } + catch (Exception e) + { + LOG.Error(e); + exportInformation.ErrorMessage = e.Message; + } + } + } + else + { + try + { + using (Image image = surface.GetImageForExport()) + { + editor.Surface.AddImageContainer(image, 10, 10); + } + + exportInformation.ExportMade = true; + } + catch (Exception e) + { + LOG.Error(e); + exportInformation.ErrorMessage = e.Message; + } + } + + ProcessExport(exportInformation, surface); + // Workaround for the modified flag when using the editor. + surface.Modified = modified; + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/EmailDestination.cs b/src/Greenshot/Destinations/EmailDestination.cs index 326e27e9c..c8e99b870 100644 --- a/src/Greenshot/Destinations/EmailDestination.cs +++ b/src/Greenshot/Destinations/EmailDestination.cs @@ -18,71 +18,82 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Windows.Forms; - using Greenshot.Configuration; using Greenshot.Helpers; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using Microsoft.Win32; -namespace Greenshot.Destinations { - /// - /// Description of EmailDestination. - /// - public class EmailDestination : AbstractDestination { - private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); - private static bool _isActiveFlag; - private static string _mapiClient; - public const string DESIGNATION = "EMail"; +namespace Greenshot.Destinations +{ + /// + /// Description of EmailDestination. + /// + public class EmailDestination : AbstractDestination + { + private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); + private static bool _isActiveFlag; + private static string _mapiClient; + public const string DESIGNATION = "EMail"; - static EmailDestination() { - // Logic to decide what email implementation we use - _mapiClient = RegistryHive.LocalMachine.ReadKey64Or32(@"Clients\Mail"); - if (!string.IsNullOrEmpty(_mapiClient)) { + static EmailDestination() + { + // Logic to decide what email implementation we use + _mapiClient = RegistryHive.LocalMachine.ReadKey64Or32(@"Clients\Mail"); + if (!string.IsNullOrEmpty(_mapiClient)) + { // Active as we have a MAPI client, can be disabled later _isActiveFlag = true; } } - public override string Designation => DESIGNATION; + public override string Designation => DESIGNATION; - public override string Description { - get + public override string Description + { + get { // Make sure there is some kind of "mail" name return _mapiClient ??= Language.GetString(LangKey.editor_email); } - } + } - public override int Priority => 3; + public override int Priority => 3; - public override bool IsActive { - get { - if (_isActiveFlag) { - // Disable if the office plugin is installed and the client is outlook - // TODO: Change this! It always creates an exception, as the plugin has not been loaded the type is not there :( - var outlookDestination = Type.GetType("GreenshotOfficePlugin.OutlookDestination,GreenshotOfficePlugin", false); - if (outlookDestination != null && _mapiClient.ToLower().Contains("microsoft outlook")) { - _isActiveFlag = false; - } - } - return base.IsActive && _isActiveFlag; - } - } + public override bool IsActive + { + get + { + if (_isActiveFlag) + { + // Disable if the office plugin is installed and the client is outlook + // TODO: Change this! It always creates an exception, as the plugin has not been loaded the type is not there :( + var outlookDestination = Type.GetType("GreenshotOfficePlugin.OutlookDestination,GreenshotOfficePlugin", false); + if (outlookDestination != null && _mapiClient.ToLower().Contains("microsoft outlook")) + { + _isActiveFlag = false; + } + } - public override Keys EditorShortcutKeys => Keys.Control | Keys.E; + return base.IsActive && _isActiveFlag; + } + } - public override Image DisplayIcon => MailIcon; + public override Keys EditorShortcutKeys => Keys.Control | Keys.E; - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - MapiMailMessage.SendImage(surface, captureDetails); - exportInformation.ExportMade = true; - ProcessExport(exportInformation, surface); - return exportInformation; - } - } + public override Image DisplayIcon => MailIcon; + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + MapiMailMessage.SendImage(surface, captureDetails); + exportInformation.ExportMade = true; + ProcessExport(exportInformation, surface); + return exportInformation; + } + } } \ No newline at end of file diff --git a/src/Greenshot/Destinations/FileDestination.cs b/src/Greenshot/Destinations/FileDestination.cs index d6e89c0d5..95365677a 100644 --- a/src/Greenshot/Destinations/FileDestination.cs +++ b/src/Greenshot/Destinations/FileDestination.cs @@ -18,11 +18,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.IO; using System.Windows.Forms; - using Greenshot.Configuration; using Greenshot.Forms; using GreenshotPlugin.Core; @@ -32,112 +32,137 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using log4net; -namespace Greenshot.Destinations { - /// - /// Description of FileSaveAsDestination. - /// - public class FileDestination : AbstractDestination { - private static readonly ILog Log = LogManager.GetLogger(typeof(FileDestination)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - public const string DESIGNATION = "FileNoDialog"; +namespace Greenshot.Destinations +{ + /// + /// Description of FileSaveAsDestination. + /// + public class FileDestination : AbstractDestination + { + private static readonly ILog Log = LogManager.GetLogger(typeof(FileDestination)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + public const string DESIGNATION = "FileNoDialog"; - public override string Designation => DESIGNATION; + public override string Designation => DESIGNATION; - public override string Description => Language.GetString(LangKey.quicksettings_destination_file); + public override string Description => Language.GetString(LangKey.quicksettings_destination_file); - public override int Priority => 0; + public override int Priority => 0; - public override Keys EditorShortcutKeys => Keys.Control | Keys.S; + public override Keys EditorShortcutKeys => Keys.Control | Keys.S; - public override Image DisplayIcon => GreenshotResources.GetImage("Save.Image"); + public override Image DisplayIcon => GreenshotResources.GetImage("Save.Image"); - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - bool outputMade; - bool overwrite; - string fullPath; - // Get output settings from the configuration - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + bool outputMade; + bool overwrite; + string fullPath; + // Get output settings from the configuration + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); - if (captureDetails?.Filename != null) { - // As we save a pre-selected file, allow to overwrite. - overwrite = true; - Log.InfoFormat("Using previous filename"); - fullPath = captureDetails.Filename; - outputSettings.Format = ImageOutput.FormatForFilename(fullPath); - } else { - fullPath = CreateNewFilename(captureDetails); - // As we generate a file, the configuration tells us if we allow to overwrite - overwrite = CoreConfig.OutputFileAllowOverwrite; - } - if (CoreConfig.OutputFilePromptQuality) { - QualityDialog qualityDialog = new QualityDialog(outputSettings); - qualityDialog.ShowDialog(); - } + if (captureDetails?.Filename != null) + { + // As we save a pre-selected file, allow to overwrite. + overwrite = true; + Log.InfoFormat("Using previous filename"); + fullPath = captureDetails.Filename; + outputSettings.Format = ImageOutput.FormatForFilename(fullPath); + } + else + { + fullPath = CreateNewFilename(captureDetails); + // As we generate a file, the configuration tells us if we allow to overwrite + overwrite = CoreConfig.OutputFileAllowOverwrite; + } - // Catching any exception to prevent that the user can't write in the directory. - // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 - try { - ImageOutput.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); - outputMade = true; - } catch (ArgumentException ex1) { - // Our generated filename exists, display 'save-as' - Log.InfoFormat("Not overwriting: {0}", ex1.Message); - // when we don't allow to overwrite present a new SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); - outputMade = fullPath != null; - } catch (Exception ex2) { - Log.Error("Error saving screenshot!", ex2); - // Show the problem - MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error)); - // when save failed we present a SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); - outputMade = fullPath != null; - } - // Don't overwrite filename if no output is made - if (outputMade) { - exportInformation.ExportMade = true; - exportInformation.Filepath = fullPath; - if (captureDetails != null) - { - captureDetails.Filename = fullPath; - } - CoreConfig.OutputFileAsFullpath = fullPath; - } + if (CoreConfig.OutputFilePromptQuality) + { + QualityDialog qualityDialog = new QualityDialog(outputSettings); + qualityDialog.ShowDialog(); + } - ProcessExport(exportInformation, surface); - return exportInformation; - } + // Catching any exception to prevent that the user can't write in the directory. + // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 + try + { + ImageOutput.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); + outputMade = true; + } + catch (ArgumentException ex1) + { + // Our generated filename exists, display 'save-as' + Log.InfoFormat("Not overwriting: {0}", ex1.Message); + // when we don't allow to overwrite present a new SaveWithDialog + fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); + outputMade = fullPath != null; + } + catch (Exception ex2) + { + Log.Error("Error saving screenshot!", ex2); + // Show the problem + MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error)); + // when save failed we present a SaveWithDialog + fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); + outputMade = fullPath != null; + } - private static string CreateNewFilename(ICaptureDetails captureDetails) { - string fullPath; - Log.InfoFormat("Creating new filename"); - string pattern = CoreConfig.OutputFileFilenamePattern; - if (string.IsNullOrEmpty(pattern)) { - pattern = "greenshot ${capturetime}"; - } - string filename = FilenameHelper.GetFilenameFromPattern(pattern, CoreConfig.OutputFileFormat, captureDetails); - CoreConfig.ValidateAndCorrectOutputFilePath(); - string filepath = FilenameHelper.FillVariables(CoreConfig.OutputFilePath, false); - try { - fullPath = Path.Combine(filepath, filename); - } catch (ArgumentException) { - // configured filename or path not valid, show error message... - Log.InfoFormat("Generated path or filename not valid: {0}, {1}", filepath, filename); + // Don't overwrite filename if no output is made + if (outputMade) + { + exportInformation.ExportMade = true; + exportInformation.Filepath = fullPath; + if (captureDetails != null) + { + captureDetails.Filename = fullPath; + } - MessageBox.Show(Language.GetString(LangKey.error_save_invalid_chars), Language.GetString(LangKey.error)); - // ... lets get the pattern fixed.... - var dialogResult = new SettingsForm().ShowDialog(); - if (dialogResult == DialogResult.OK) { - // ... OK -> then try again: - fullPath = CreateNewFilename(captureDetails); - } else { - // ... cancelled. - fullPath = null; - } - - } - return fullPath; - } - } -} + CoreConfig.OutputFileAsFullpath = fullPath; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + + private static string CreateNewFilename(ICaptureDetails captureDetails) + { + string fullPath; + Log.InfoFormat("Creating new filename"); + string pattern = CoreConfig.OutputFileFilenamePattern; + if (string.IsNullOrEmpty(pattern)) + { + pattern = "greenshot ${capturetime}"; + } + + string filename = FilenameHelper.GetFilenameFromPattern(pattern, CoreConfig.OutputFileFormat, captureDetails); + CoreConfig.ValidateAndCorrectOutputFilePath(); + string filepath = FilenameHelper.FillVariables(CoreConfig.OutputFilePath, false); + try + { + fullPath = Path.Combine(filepath, filename); + } + catch (ArgumentException) + { + // configured filename or path not valid, show error message... + Log.InfoFormat("Generated path or filename not valid: {0}, {1}", filepath, filename); + + MessageBox.Show(Language.GetString(LangKey.error_save_invalid_chars), Language.GetString(LangKey.error)); + // ... lets get the pattern fixed.... + var dialogResult = new SettingsForm().ShowDialog(); + if (dialogResult == DialogResult.OK) + { + // ... OK -> then try again: + fullPath = CreateNewFilename(captureDetails); + } + else + { + // ... cancelled. + fullPath = null; + } + } + + return fullPath; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/FileWithDialogDestination.cs b/src/Greenshot/Destinations/FileWithDialogDestination.cs index b378f5f34..02c5e9bd4 100644 --- a/src/Greenshot/Destinations/FileWithDialogDestination.cs +++ b/src/Greenshot/Destinations/FileWithDialogDestination.cs @@ -21,62 +21,61 @@ using System.Drawing; using System.Windows.Forms; - using Greenshot.Configuration; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; -namespace Greenshot.Destinations { - /// - /// Description of FileWithDialog. - /// - public class FileWithDialogDestination : AbstractDestination { - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - public const string DESIGNATION = "FileDialog"; +namespace Greenshot.Destinations +{ + /// + /// Description of FileWithDialog. + /// + public class FileWithDialogDestination : AbstractDestination + { + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + public const string DESIGNATION = "FileDialog"; - public override string Designation { - get { - return DESIGNATION; - } - } + public override string Designation + { + get { return DESIGNATION; } + } - public override string Description { - get { - return Language.GetString(LangKey.settings_destination_fileas); - } - } + public override string Description + { + get { return Language.GetString(LangKey.settings_destination_fileas); } + } - public override int Priority { - get { - return 0; - } - } - - public override Keys EditorShortcutKeys { - get { - return Keys.Control | Keys.Shift | Keys.S; - } - } + public override int Priority + { + get { return 0; } + } - public override Image DisplayIcon { - get { - return GreenshotResources.GetImage("Save.Image"); - } - } + public override Keys EditorShortcutKeys + { + get { return Keys.Control | Keys.Shift | Keys.S; } + } - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - // Bug #2918756 don't overwrite path if SaveWithDialog returns null! - var savedTo = ImageOutput.SaveWithDialog(surface, captureDetails); - if (savedTo != null) { - exportInformation.ExportMade = true; - exportInformation.Filepath = savedTo; - captureDetails.Filename = savedTo; - conf.OutputFileAsFullpath = savedTo; - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + public override Image DisplayIcon + { + get { return GreenshotResources.GetImage("Save.Image"); } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + // Bug #2918756 don't overwrite path if SaveWithDialog returns null! + var savedTo = ImageOutput.SaveWithDialog(surface, captureDetails); + if (savedTo != null) + { + exportInformation.ExportMade = true; + exportInformation.Filepath = savedTo; + captureDetails.Filename = savedTo; + conf.OutputFileAsFullpath = savedTo; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/PickerDestination.cs b/src/Greenshot/Destinations/PickerDestination.cs index e7ea94c83..2195e1d6b 100644 --- a/src/Greenshot/Destinations/PickerDestination.cs +++ b/src/Greenshot/Destinations/PickerDestination.cs @@ -24,42 +24,50 @@ using Greenshot.Configuration; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; -namespace Greenshot.Destinations { - /// - /// The PickerDestination shows a context menu with all possible destinations, so the user can "pick" one - /// - public class PickerDestination : AbstractDestination { - public const string DESIGNATION = "Picker"; +namespace Greenshot.Destinations +{ + /// + /// The PickerDestination shows a context menu with all possible destinations, so the user can "pick" one + /// + public class PickerDestination : AbstractDestination + { + public const string DESIGNATION = "Picker"; - public override string Designation => DESIGNATION; + public override string Designation => DESIGNATION; - public override string Description => Language.GetString(LangKey.settings_destination_picker); + public override string Description => Language.GetString(LangKey.settings_destination_picker); - public override int Priority => 1; + public override int Priority => 1; - /// - /// Export the capture with the destination picker - /// - /// Did the user select this destination? - /// Surface to export - /// Details of the capture - /// true if export was made - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - List destinations = new List(); + /// + /// Export the capture with the destination picker + /// + /// Did the user select this destination? + /// Surface to export + /// Details of the capture + /// true if export was made + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + List destinations = new List(); - foreach(var destination in SimpleServiceProvider.Current.GetAllInstances()) { - if ("Picker".Equals(destination.Designation)) { - continue; - } - if (!destination.IsActive) { - continue; - } - destinations.Add(destination); - } + foreach (var destination in SimpleServiceProvider.Current.GetAllInstances()) + { + if ("Picker".Equals(destination.Designation)) + { + continue; + } - // No Processing, this is done in the selected destination (if anything was selected) - return ShowPickerMenu(true, surface, captureDetails, destinations); - } - } -} + if (!destination.IsActive) + { + continue; + } + + destinations.Add(destination); + } + + // No Processing, this is done in the selected destination (if anything was selected) + return ShowPickerMenu(true, surface, captureDetails, destinations); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/PrinterDestination.cs b/src/Greenshot/Destinations/PrinterDestination.cs index 3a45268e2..09b51880c 100644 --- a/src/Greenshot/Destinations/PrinterDestination.cs +++ b/src/Greenshot/Destinations/PrinterDestination.cs @@ -24,38 +24,46 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Printing; using System.Windows.Forms; - using Greenshot.Configuration; using GreenshotPlugin.Core; using Greenshot.Helpers; using GreenshotPlugin.Interfaces; -namespace Greenshot.Destinations { - /// - /// Description of PrinterDestination. - /// - public class PrinterDestination : AbstractDestination { - public const string DESIGNATION = "Printer"; +namespace Greenshot.Destinations +{ + /// + /// Description of PrinterDestination. + /// + public class PrinterDestination : AbstractDestination + { + public const string DESIGNATION = "Printer"; private readonly string _printerName; - public PrinterDestination() { - } + public PrinterDestination() + { + } - public PrinterDestination(string printerName) { - _printerName = printerName; - } - public override string Designation => DESIGNATION; + public PrinterDestination(string printerName) + { + _printerName = printerName; + } - public override string Description { - get { - if (_printerName != null) { - return Language.GetString(LangKey.settings_destination_printer) + " - " + _printerName; - } - return Language.GetString(LangKey.settings_destination_printer); - } - } + public override string Designation => DESIGNATION; - public override int Priority => 2; + public override string Description + { + get + { + if (_printerName != null) + { + return Language.GetString(LangKey.settings_destination_printer) + " - " + _printerName; + } + + return Language.GetString(LangKey.settings_destination_printer); + } + } + + public override int Priority => 2; public override Keys EditorShortcutKeys => Keys.Control | Keys.P; @@ -64,60 +72,75 @@ namespace Greenshot.Destinations { public override bool IsDynamic => true; /// - /// Create destinations for all the installed printers - /// - /// IEnumerable of IDestination - public override IEnumerable DynamicDestinations() { - PrinterSettings settings = new PrinterSettings(); - string defaultPrinter = settings.PrinterName; - List printers = new List(); + /// Create destinations for all the installed printers + /// + /// IEnumerable of IDestination + public override IEnumerable DynamicDestinations() + { + PrinterSettings settings = new PrinterSettings(); + string defaultPrinter = settings.PrinterName; + List printers = new List(); - foreach (string printer in PrinterSettings.InstalledPrinters) { - printers.Add(printer); - } - printers.Sort(delegate(string p1, string p2) { - if(defaultPrinter.Equals(p1)) { - return -1; - } - if(defaultPrinter.Equals(p2)) { - return 1; - } - return string.Compare(p1, p2, StringComparison.Ordinal); - }); - foreach(string printer in printers) { - yield return new PrinterDestination(printer); - } - } + foreach (string printer in PrinterSettings.InstalledPrinters) + { + printers.Add(printer); + } - /// - /// Export the capture to the printer - /// - /// - /// - /// - /// ExportInformation - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - PrinterSettings printerSettings; - if (!string.IsNullOrEmpty(_printerName)) + printers.Sort(delegate(string p1, string p2) + { + if (defaultPrinter.Equals(p1)) + { + return -1; + } + + if (defaultPrinter.Equals(p2)) + { + return 1; + } + + return string.Compare(p1, p2, StringComparison.Ordinal); + }); + foreach (string printer in printers) + { + yield return new PrinterDestination(printer); + } + } + + /// + /// Export the capture to the printer + /// + /// + /// + /// + /// ExportInformation + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + PrinterSettings printerSettings; + if (!string.IsNullOrEmpty(_printerName)) { using PrintHelper printHelper = new PrintHelper(surface, captureDetails); printerSettings = printHelper.PrintTo(_printerName); - } else if (!manuallyInitiated) { - PrinterSettings settings = new PrinterSettings(); + } + else if (!manuallyInitiated) + { + PrinterSettings settings = new PrinterSettings(); using PrintHelper printHelper = new PrintHelper(surface, captureDetails); printerSettings = printHelper.PrintTo(settings.PrinterName); - } else + } + else { using PrintHelper printHelper = new PrintHelper(surface, captureDetails); printerSettings = printHelper.PrintWithDialog(); } - if (printerSettings != null) { - exportInformation.ExportMade = true; - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + if (printerSettings != null) + { + exportInformation.ExportMade = true; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs index 5461b4df4..19f531a5c 100644 --- a/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ b/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs @@ -28,143 +28,129 @@ using GreenshotPlugin.Interfaces.Drawing.Adorners; namespace Greenshot.Drawing.Adorners { - public class AbstractAdorner : IAdorner - { - public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE; + public class AbstractAdorner : IAdorner + { + public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE; - private static readonly Size DefaultSize = new Size(6, 6); - protected Size _size; + private static readonly Size DefaultSize = new Size(6, 6); + protected Size _size; - public AbstractAdorner(IDrawableContainer owner) - { - _size = DpiHelper.ScaleWithDpi(DefaultSize, 0); - Owner = owner; - } + public AbstractAdorner(IDrawableContainer owner) + { + _size = DpiHelper.ScaleWithDpi(DefaultSize, 0); + Owner = owner; + } - /// - /// Returns the cursor for when the mouse is over the adorner - /// - public virtual Cursor Cursor - { - get - { - return Cursors.SizeAll; - } - } + /// + /// Returns the cursor for when the mouse is over the adorner + /// + public virtual Cursor Cursor + { + get { return Cursors.SizeAll; } + } - public virtual IDrawableContainer Owner - { - get; - set; - } + public virtual IDrawableContainer Owner { get; set; } - /// - /// Test if the point is inside the adorner - /// - /// - /// - public virtual bool HitTest(Point point) - { - Rectangle hitBounds = Bounds; - hitBounds.Inflate(3, 3); - return hitBounds.Contains(point); - } + /// + /// Test if the point is inside the adorner + /// + /// + /// + public virtual bool HitTest(Point point) + { + Rectangle hitBounds = Bounds; + hitBounds.Inflate(3, 3); + return hitBounds.Contains(point); + } - /// - /// Handle the mouse down - /// - /// - /// - public virtual void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - } + /// + /// Handle the mouse down + /// + /// + /// + public virtual void MouseDown(object sender, MouseEventArgs mouseEventArgs) + { + } - /// - /// Handle the mouse move - /// - /// - /// - public virtual void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - } + /// + /// Handle the mouse move + /// + /// + /// + public virtual void MouseMove(object sender, MouseEventArgs mouseEventArgs) + { + } - /// - /// Handle the mouse up - /// - /// - /// - public virtual void MouseUp(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.IDLE; - } + /// + /// Handle the mouse up + /// + /// + /// + public virtual void MouseUp(object sender, MouseEventArgs mouseEventArgs) + { + EditStatus = EditStatus.IDLE; + } - /// - /// Return the location of the adorner - /// - public virtual Point Location - { - get; - set; - } + /// + /// Return the location of the adorner + /// + public virtual Point Location { get; set; } - /// - /// Return the bounds of the Adorner - /// - public virtual Rectangle Bounds - { - get - { - Point location = Location; - return new Rectangle(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height); - } - } + /// + /// Return the bounds of the Adorner + /// + public virtual Rectangle Bounds + { + get + { + Point location = Location; + return new Rectangle(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height); + } + } - /// - /// Return the bounds of the Adorner as displayed on the parent Surface - /// - protected virtual Rectangle BoundsOnSurface - { - get - { - Point displayLocation = Owner.Parent.ToSurfaceCoordinates(Location); - return new Rectangle(displayLocation.X - _size.Width / 2, displayLocation.Y - _size.Height / 2, _size.Width, _size.Height); - } - } + /// + /// Return the bounds of the Adorner as displayed on the parent Surface + /// + protected virtual Rectangle BoundsOnSurface + { + get + { + Point displayLocation = Owner.Parent.ToSurfaceCoordinates(Location); + return new Rectangle(displayLocation.X - _size.Width / 2, displayLocation.Y - _size.Height / 2, _size.Width, _size.Height); + } + } - /// - /// The adorner is active if the edit status is not idle or undrawn - /// - public virtual bool IsActive - { - get - { - return EditStatus != EditStatus.IDLE && EditStatus != EditStatus.UNDRAWN; - } - } + /// + /// The adorner is active if the edit status is not idle or undrawn + /// + public virtual bool IsActive + { + get { return EditStatus != EditStatus.IDLE && EditStatus != EditStatus.UNDRAWN; } + } - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// uint - public void AdjustToDpi(uint dpi) - { - _size = DpiHelper.ScaleWithDpi(DefaultSize, dpi); - } + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// uint + public void AdjustToDpi(uint dpi) + { + _size = DpiHelper.ScaleWithDpi(DefaultSize, dpi); + } - /// - /// Draw the adorner - /// - /// PaintEventArgs - public virtual void Paint(PaintEventArgs paintEventArgs) - { - } + /// + /// Draw the adorner + /// + /// PaintEventArgs + public virtual void Paint(PaintEventArgs paintEventArgs) + { + } - /// - /// We ignore the Transform, as the coordinates are directly bound to those of the owner - /// - /// - public virtual void Transform(Matrix matrix) - { - } - } -} + /// + /// We ignore the Transform, as the coordinates are directly bound to those of the owner + /// + /// + public virtual void Transform(Matrix matrix) + { + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Adorners/MoveAdorner.cs b/src/Greenshot/Drawing/Adorners/MoveAdorner.cs index c8ef3ea22..73c75141c 100644 --- a/src/Greenshot/Drawing/Adorners/MoveAdorner.cs +++ b/src/Greenshot/Drawing/Adorners/MoveAdorner.cs @@ -27,136 +27,140 @@ using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing.Adorners { - /// - /// This is the adorner for the line based containers - /// - public class MoveAdorner : AbstractAdorner - { - private Rectangle _boundsBeforeResize = Rectangle.Empty; - private RectangleF _boundsAfterResize = RectangleF.Empty; + /// + /// This is the adorner for the line based containers + /// + public class MoveAdorner : AbstractAdorner + { + private Rectangle _boundsBeforeResize = Rectangle.Empty; + private RectangleF _boundsAfterResize = RectangleF.Empty; - public Positions Position { get; private set; } + public Positions Position { get; private set; } - public MoveAdorner(IDrawableContainer owner, Positions position) : base(owner) - { - Position = position; - } + public MoveAdorner(IDrawableContainer owner, Positions position) : base(owner) + { + Position = position; + } - /// - /// Returns the cursor for when the mouse is over the adorner - /// - public override Cursor Cursor => Cursors.SizeAll; + /// + /// Returns the cursor for when the mouse is over the adorner + /// + public override Cursor Cursor => Cursors.SizeAll; - /// - /// Handle the mouse down - /// - /// - /// - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.RESIZING; - _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); - _boundsAfterResize = _boundsBeforeResize; - } + /// + /// Handle the mouse down + /// + /// + /// + public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) + { + EditStatus = EditStatus.RESIZING; + _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); + _boundsAfterResize = _boundsBeforeResize; + } - /// - /// Handle the mouse move - /// - /// - /// - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.RESIZING) - { - return; - } - Owner.Invalidate(); - Owner.MakeBoundsChangeUndoable(false); + /// + /// Handle the mouse move + /// + /// + /// + public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) + { + if (EditStatus != EditStatus.RESIZING) + { + return; + } - // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.X; - _boundsAfterResize.Y = _boundsBeforeResize.Y; - _boundsAfterResize.Width = _boundsBeforeResize.Width; - _boundsAfterResize.Height = _boundsBeforeResize.Height; + Owner.Invalidate(); + Owner.MakeBoundsChangeUndoable(false); - // calculate scaled rectangle - ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); + // reset "workbench" rectangle to current bounds + _boundsAfterResize.X = _boundsBeforeResize.X; + _boundsAfterResize.Y = _boundsBeforeResize.Y; + _boundsAfterResize.Width = _boundsBeforeResize.Width; + _boundsAfterResize.Height = _boundsBeforeResize.Height; - // apply scaled bounds to this DrawableContainer - Owner.ApplyBounds(_boundsAfterResize); + // calculate scaled rectangle + ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); - Owner.Invalidate(); - } + // apply scaled bounds to this DrawableContainer + Owner.ApplyBounds(_boundsAfterResize); - /// - /// Return the location of the adorner - /// - public override Point Location { - get - { - int x = 0,y = 0; - switch (Position) - { - case Positions.TopLeft: - x = Owner.Left; - y = Owner.Top; - break; - case Positions.BottomLeft: - x = Owner.Left; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleLeft: - x = Owner.Left; - y = Owner.Top + (Owner.Height / 2); - break; - case Positions.TopCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top; - break; - case Positions.BottomCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top + Owner.Height; - break; - case Positions.TopRight: - x = Owner.Left + Owner.Width; - y = Owner.Top; - break; - case Positions.BottomRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + (Owner.Height / 2); - break; - } - return new Point(x, y); - } - } + Owner.Invalidate(); + } - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; + /// + /// Return the location of the adorner + /// + public override Point Location + { + get + { + int x = 0, y = 0; + switch (Position) + { + case Positions.TopLeft: + x = Owner.Left; + y = Owner.Top; + break; + case Positions.BottomLeft: + x = Owner.Left; + y = Owner.Top + Owner.Height; + break; + case Positions.MiddleLeft: + x = Owner.Left; + y = Owner.Top + (Owner.Height / 2); + break; + case Positions.TopCenter: + x = Owner.Left + (Owner.Width / 2); + y = Owner.Top; + break; + case Positions.BottomCenter: + x = Owner.Left + (Owner.Width / 2); + y = Owner.Top + Owner.Height; + break; + case Positions.TopRight: + x = Owner.Left + Owner.Width; + y = Owner.Top; + break; + case Positions.BottomRight: + x = Owner.Left + Owner.Width; + y = Owner.Top + Owner.Height; + break; + case Positions.MiddleRight: + x = Owner.Left + Owner.Width; + y = Owner.Top + (Owner.Height / 2); + break; + } - var bounds = BoundsOnSurface; - GraphicsState state = targetGraphics.Save(); + return new Point(x, y); + } + } - targetGraphics.CompositingMode = CompositingMode.SourceCopy; + /// + /// Draw the adorner + /// + /// PaintEventArgs + public override void Paint(PaintEventArgs paintEventArgs) + { + Graphics targetGraphics = paintEventArgs.Graphics; - try - { - targetGraphics.FillRectangle(Brushes.Black, bounds); - targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); - } - catch - { - // Ignore, BUG-2065 - } - targetGraphics.Restore(state); - } - } -} + var bounds = BoundsOnSurface; + GraphicsState state = targetGraphics.Save(); + + targetGraphics.CompositingMode = CompositingMode.SourceCopy; + + try + { + targetGraphics.FillRectangle(Brushes.Black, bounds); + targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); + } + catch + { + // Ignore, BUG-2065 + } + + targetGraphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs index b2e7261a9..b6480180d 100644 --- a/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs +++ b/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs @@ -27,156 +27,160 @@ using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing.Adorners { - /// - /// This is the default "legacy" gripper adorner, not the one used for the tail in the speech-bubble - /// - public class ResizeAdorner : AbstractAdorner - { - private Rectangle _boundsBeforeResize = Rectangle.Empty; - private RectangleF _boundsAfterResize = RectangleF.Empty; + /// + /// This is the default "legacy" gripper adorner, not the one used for the tail in the speech-bubble + /// + public class ResizeAdorner : AbstractAdorner + { + private Rectangle _boundsBeforeResize = Rectangle.Empty; + private RectangleF _boundsAfterResize = RectangleF.Empty; - public Positions Position { get; private set; } + public Positions Position { get; private set; } - public ResizeAdorner(IDrawableContainer owner, Positions position) : base(owner) - { - Position = position; - } + public ResizeAdorner(IDrawableContainer owner, Positions position) : base(owner) + { + Position = position; + } - /// - /// Returns the cursor for when the mouse is over the adorner - /// - public override Cursor Cursor - { - get - { - bool isNotSwitched = Owner.Width >= 0; - if (Owner.Height < 0) - { - isNotSwitched = !isNotSwitched; - } - switch (Position) - { - case Positions.TopLeft: - case Positions.BottomRight: - return isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW; - case Positions.TopRight: - case Positions.BottomLeft: - return isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE; - case Positions.MiddleLeft: - case Positions.MiddleRight: - return Cursors.SizeWE; - case Positions.TopCenter: - case Positions.BottomCenter: - return Cursors.SizeNS; - default: - return Cursors.SizeAll; - } - } - } + /// + /// Returns the cursor for when the mouse is over the adorner + /// + public override Cursor Cursor + { + get + { + bool isNotSwitched = Owner.Width >= 0; + if (Owner.Height < 0) + { + isNotSwitched = !isNotSwitched; + } - /// - /// Handle the mouse down - /// - /// - /// - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.RESIZING; - _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); - _boundsAfterResize = _boundsBeforeResize; - } + switch (Position) + { + case Positions.TopLeft: + case Positions.BottomRight: + return isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW; + case Positions.TopRight: + case Positions.BottomLeft: + return isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE; + case Positions.MiddleLeft: + case Positions.MiddleRight: + return Cursors.SizeWE; + case Positions.TopCenter: + case Positions.BottomCenter: + return Cursors.SizeNS; + default: + return Cursors.SizeAll; + } + } + } - /// - /// Handle the mouse move - /// - /// - /// - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.RESIZING) - { - return; - } - Owner.Invalidate(); - Owner.MakeBoundsChangeUndoable(false); + /// + /// Handle the mouse down + /// + /// + /// + public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) + { + EditStatus = EditStatus.RESIZING; + _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); + _boundsAfterResize = _boundsBeforeResize; + } - // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.X; - _boundsAfterResize.Y = _boundsBeforeResize.Y; - _boundsAfterResize.Width = _boundsBeforeResize.Width; - _boundsAfterResize.Height = _boundsBeforeResize.Height; + /// + /// Handle the mouse move + /// + /// + /// + public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) + { + if (EditStatus != EditStatus.RESIZING) + { + return; + } - // calculate scaled rectangle - ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); + Owner.Invalidate(); + Owner.MakeBoundsChangeUndoable(false); - // apply scaled bounds to this DrawableContainer - Owner.ApplyBounds(_boundsAfterResize); + // reset "workbench" rectangle to current bounds + _boundsAfterResize.X = _boundsBeforeResize.X; + _boundsAfterResize.Y = _boundsBeforeResize.Y; + _boundsAfterResize.Width = _boundsBeforeResize.Width; + _boundsAfterResize.Height = _boundsBeforeResize.Height; - Owner.Invalidate(); - } + // calculate scaled rectangle + ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); - /// - /// Return the location of the adorner - /// - public override Point Location { - get - { - int x = 0,y = 0; - switch (Position) - { - case Positions.TopLeft: - x = Owner.Left; - y = Owner.Top; - break; - case Positions.BottomLeft: - x = Owner.Left; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleLeft: - x = Owner.Left; - y = Owner.Top + (Owner.Height / 2); - break; - case Positions.TopCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top; - break; - case Positions.BottomCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top + Owner.Height; - break; - case Positions.TopRight: - x = Owner.Left + Owner.Width; - y = Owner.Top; - break; - case Positions.BottomRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + (Owner.Height / 2); - break; - } - return new Point(x, y); - } - } + // apply scaled bounds to this DrawableContainer + Owner.ApplyBounds(_boundsAfterResize); - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; + Owner.Invalidate(); + } - var bounds = BoundsOnSurface; - GraphicsState state = targetGraphics.Save(); + /// + /// Return the location of the adorner + /// + public override Point Location + { + get + { + int x = 0, y = 0; + switch (Position) + { + case Positions.TopLeft: + x = Owner.Left; + y = Owner.Top; + break; + case Positions.BottomLeft: + x = Owner.Left; + y = Owner.Top + Owner.Height; + break; + case Positions.MiddleLeft: + x = Owner.Left; + y = Owner.Top + (Owner.Height / 2); + break; + case Positions.TopCenter: + x = Owner.Left + (Owner.Width / 2); + y = Owner.Top; + break; + case Positions.BottomCenter: + x = Owner.Left + (Owner.Width / 2); + y = Owner.Top + Owner.Height; + break; + case Positions.TopRight: + x = Owner.Left + Owner.Width; + y = Owner.Top; + break; + case Positions.BottomRight: + x = Owner.Left + Owner.Width; + y = Owner.Top + Owner.Height; + break; + case Positions.MiddleRight: + x = Owner.Left + Owner.Width; + y = Owner.Top + (Owner.Height / 2); + break; + } - targetGraphics.CompositingMode = CompositingMode.SourceCopy; + return new Point(x, y); + } + } - targetGraphics.FillRectangle(Brushes.Black, bounds); - targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); - targetGraphics.Restore(state); - } - } -} + /// + /// Draw the adorner + /// + /// PaintEventArgs + public override void Paint(PaintEventArgs paintEventArgs) + { + Graphics targetGraphics = paintEventArgs.Graphics; + + var bounds = BoundsOnSurface; + GraphicsState state = targetGraphics.Save(); + + targetGraphics.CompositingMode = CompositingMode.SourceCopy; + + targetGraphics.FillRectangle(Brushes.Black, bounds); + targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); + targetGraphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Adorners/TargetAdorner.cs b/src/Greenshot/Drawing/Adorners/TargetAdorner.cs index e0d0bbf13..546606b66 100644 --- a/src/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ b/src/Greenshot/Drawing/Adorners/TargetAdorner.cs @@ -26,94 +26,100 @@ using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing.Adorners { - /// - /// This implements the special "gripper" for the Speech-Bubble tail - /// - public class TargetAdorner : AbstractAdorner - { + /// + /// This implements the special "gripper" for the Speech-Bubble tail + /// + public class TargetAdorner : AbstractAdorner + { + public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) + { + Location = location; + } - public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) - { - Location = location; - } + /// + /// Handle the mouse down + /// + /// + /// + public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) + { + EditStatus = EditStatus.MOVING; + } - /// - /// Handle the mouse down - /// - /// - /// - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.MOVING; - } + /// + /// Handle the mouse move + /// + /// + /// + public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) + { + if (EditStatus != EditStatus.MOVING) + { + return; + } - /// - /// Handle the mouse move - /// - /// - /// - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.MOVING) - { - return; - } + Owner.Invalidate(); + Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); + Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height); + // Check if gripper inside the parent (surface), if not we need to move it inside + // This was made for BUG-1682 + if (!imageBounds.Contains(newGripperLocation)) + { + if (newGripperLocation.X > imageBounds.Right) + { + newGripperLocation.X = imageBounds.Right - 5; + } - Owner.Invalidate(); - Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); - Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height); - // Check if gripper inside the parent (surface), if not we need to move it inside - // This was made for BUG-1682 - if (!imageBounds.Contains(newGripperLocation)) - { - if (newGripperLocation.X > imageBounds.Right) - { - newGripperLocation.X = imageBounds.Right - 5; - } - if (newGripperLocation.X < imageBounds.Left) - { - newGripperLocation.X = imageBounds.Left; - } - if (newGripperLocation.Y > imageBounds.Bottom) - { - newGripperLocation.Y = imageBounds.Bottom - 5; - } - if (newGripperLocation.Y < imageBounds.Top) - { - newGripperLocation.Y = imageBounds.Top; - } - } + if (newGripperLocation.X < imageBounds.Left) + { + newGripperLocation.X = imageBounds.Left; + } - Location = newGripperLocation; - Owner.Invalidate(); - } + if (newGripperLocation.Y > imageBounds.Bottom) + { + newGripperLocation.Y = imageBounds.Bottom - 5; + } - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; + if (newGripperLocation.Y < imageBounds.Top) + { + newGripperLocation.Y = imageBounds.Top; + } + } - var bounds = BoundsOnSurface; + Location = newGripperLocation; + Owner.Invalidate(); + } + + /// + /// Draw the adorner + /// + /// PaintEventArgs + public override void Paint(PaintEventArgs paintEventArgs) + { + Graphics targetGraphics = paintEventArgs.Graphics; + + var bounds = BoundsOnSurface; targetGraphics.FillRectangle(Brushes.Green, bounds); - targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); - } + targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); + } - /// - /// Made sure this adorner is transformed - /// - /// Matrix - public override void Transform(Matrix matrix) - { - if (matrix == null) - { - return; - } - Point[] points = new[] { Location }; - matrix.TransformPoints(points); - Location = points[0]; - } - } -} + /// + /// Made sure this adorner is transformed + /// + /// Matrix + public override void Transform(Matrix matrix) + { + if (matrix == null) + { + return; + } + + Point[] points = new[] + { + Location + }; + matrix.TransformPoints(points); + Location = points[0]; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/ArrowContainer.cs b/src/Greenshot/Drawing/ArrowContainer.cs index acfd1ad03..a49ffe863 100644 --- a/src/Greenshot/Drawing/ArrowContainer.cs +++ b/src/Greenshot/Drawing/ArrowContainer.cs @@ -18,57 +18,71 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Drawing.Drawing2D; - using Greenshot.Drawing.Fields; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Description of LineContainer. - /// - [Serializable()] - public class ArrowContainer : LineContainer { - public enum ArrowHeadCombination { NONE, START_POINT, END_POINT, BOTH }; - - private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6); +namespace Greenshot.Drawing +{ + /// + /// Description of LineContainer. + /// + [Serializable()] + public class ArrowContainer : LineContainer + { + public enum ArrowHeadCombination + { + NONE, + START_POINT, + END_POINT, + BOTH + }; - public ArrowContainer(Surface parent) : base(parent) { - } + private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6); - /// - /// Do not use the base, just override so we have our own defaults - /// - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.ARROWHEADS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, true); - AddField(GetType(), FieldType.ARROWHEADS, ArrowHeadCombination.END_POINT); - } + public ArrowContainer(Surface parent) : base(parent) + { + } - public override void Draw(Graphics graphics, RenderMode rm) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + /// + /// Do not use the base, just override so we have our own defaults + /// + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.ARROWHEADS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); + AddField(GetType(), FieldType.SHADOW, true); + AddField(GetType(), FieldType.ARROWHEADS, ArrowHeadCombination.END_POINT); + } - if (lineThickness > 0 ) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS); - if (lineThickness > 0) { - if (shadow) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = 1; - while (currentStep <= steps) + public override void Draw(Graphics graphics, RenderMode rm) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + + if (lineThickness > 0) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + ArrowHeadCombination heads = (ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS); + if (lineThickness > 0) + { + if (shadow) + { + //draw shadow first + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = 1; + while (currentStep <= steps) { using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); SetArrowHeads(heads, shadowCapPen); @@ -82,35 +96,40 @@ namespace Greenshot.Drawing { currentStep++; alpha -= basealpha / steps; } - - } + } using Pen pen = new Pen(lineColor, lineThickness); SetArrowHeads(heads, pen); graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); } - } - } - - private void SetArrowHeads(ArrowHeadCombination heads, Pen pen) { - if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT ) { - pen.CustomStartCap = ARROW_CAP; - } - if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT ) { - pen.CustomEndCap = ARROW_CAP; - } - } - - public override Rectangle DrawingBounds { - get { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - if (lineThickness > 0) + } + } + + private void SetArrowHeads(ArrowHeadCombination heads, Pen pen) + { + if (heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT) + { + pen.CustomStartCap = ARROW_CAP; + } + + if (heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT) + { + pen.CustomEndCap = ARROW_CAP; + } + } + + public override Rectangle DrawingBounds + { + get + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + if (lineThickness > 0) { - using Pen pen = new Pen(Color.White) - { - Width = lineThickness - }; - SetArrowHeads((ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS), pen); + using Pen pen = new Pen(Color.White) + { + Width = lineThickness + }; + SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS), pen); using GraphicsPath path = new GraphicsPath(); path.AddLine(Left, Top, Left + Width, Top + Height); using Matrix matrix = new Matrix(); @@ -118,24 +137,27 @@ namespace Greenshot.Drawing { drawingBounds.Inflate(2, 2); return drawingBounds; } - return Rectangle.Empty; - } - } - - public override bool ClickableAt(int x, int y) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; - if (lineThickness > 0) + + return Rectangle.Empty; + } + } + + public override bool ClickableAt(int x, int y) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; + if (lineThickness > 0) { - using Pen pen = new Pen(Color.White) - { - Width = lineThickness - }; - SetArrowHeads((ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS), pen); + using Pen pen = new Pen(Color.White) + { + Width = lineThickness + }; + SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS), pen); using GraphicsPath path = new GraphicsPath(); path.AddLine(Left, Top, Left + Width, Top + Height); return path.IsOutlineVisible(x, y, pen); } - return false; - } - } -} + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/CropContainer.cs b/src/Greenshot/Drawing/CropContainer.cs index da160f11e..164fd791e 100644 --- a/src/Greenshot/Drawing/CropContainer.cs +++ b/src/Greenshot/Drawing/CropContainer.cs @@ -25,53 +25,62 @@ using Greenshot.Drawing.Fields; using Greenshot.Helpers; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Description of CropContainer. - /// - public class CropContainer : DrawableContainer { - public CropContainer(Surface parent) : base(parent) { - Init(); - } +namespace Greenshot.Drawing +{ + /// + /// Description of CropContainer. + /// + public class CropContainer : DrawableContainer + { + public CropContainer(Surface parent) : base(parent) + { + Init(); + } - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } - private void Init() - { - CreateDefaultAdorners(); - } - protected override void InitializeFields() { - AddField(GetType(), FieldType.FLAGS, FieldFlag.CONFIRMABLE); - } + private void Init() + { + CreateDefaultAdorners(); + } - public override void Invalidate() { - _parent?.Invalidate(); - } + protected override void InitializeFields() + { + AddField(GetType(), FieldType.FLAGS, FieldFlag.CONFIRMABLE); + } - /// - /// We need to override the DrawingBound, return a rectangle in the size of the image, to make sure this element is always draw - /// (we create a transparent brown over the complete picture) - /// - public override Rectangle DrawingBounds { - get - { - if (_parent?.Image is { } image) { - return new Rectangle(0, 0, image.Width, image.Height); - } + public override void Invalidate() + { + _parent?.Invalidate(); + } - return Rectangle.Empty; - } - } + /// + /// We need to override the DrawingBound, return a rectangle in the size of the image, to make sure this element is always draw + /// (we create a transparent brown over the complete picture) + /// + public override Rectangle DrawingBounds + { + get + { + if (_parent?.Image is { } image) + { + return new Rectangle(0, 0, image.Width, image.Height); + } - public override void Draw(Graphics g, RenderMode rm) { - if (_parent == null) - { - return; - } + return Rectangle.Empty; + } + } + + public override void Draw(Graphics g, RenderMode rm) + { + if (_parent == null) + { + return; + } using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100)); Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); @@ -79,20 +88,21 @@ namespace Greenshot.Drawing { Size imageSize = _parent.Image.Size; DrawSelectionBorder(g, selectionRect); - + // top g.FillRectangle(cropBrush, new Rectangle(0, 0, imageSize.Width, cropRectangle.Top)); // left g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); // right - g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); + g.FillRectangle(cropBrush, + new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); // bottom g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height))); } - - /// - /// No context menu for the CropContainer - /// - public override bool HasContextMenu => false; - } -} + + /// + /// No context menu for the CropContainer + /// + public override bool HasContextMenu => false; + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/CursorContainer.cs b/src/Greenshot/Drawing/CursorContainer.cs index 7b3078510..d22b5d672 100644 --- a/src/Greenshot/Drawing/CursorContainer.cs +++ b/src/Greenshot/Drawing/CursorContainer.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.IO; @@ -27,84 +28,101 @@ using log4net; using System.Runtime.Serialization; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Description of CursorContainer. - /// - [Serializable] - public class CursorContainer : DrawableContainer, ICursorContainer { - private static readonly ILog LOG = LogManager.GetLogger(typeof(CursorContainer)); +namespace Greenshot.Drawing +{ + /// + /// Description of CursorContainer. + /// + [Serializable] + public class CursorContainer : DrawableContainer, ICursorContainer + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(CursorContainer)); - protected Cursor cursor; + protected Cursor cursor; - public CursorContainer(Surface parent) : base(parent) { - Init(); - } + public CursorContainer(Surface parent) : base(parent) + { + Init(); + } - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } - private void Init() - { - CreateDefaultAdorners(); - } + private void Init() + { + CreateDefaultAdorners(); + } - public CursorContainer(Surface parent, string filename) : this(parent) { - Load(filename); - } + public CursorContainer(Surface parent, string filename) : this(parent) + { + Load(filename); + } - public Cursor Cursor { - set { - if (cursor != null) { - cursor.Dispose(); - } - // Clone cursor (is this correct??) - cursor = new Cursor(value.CopyHandle()); - Width = value.Size.Width; - Height = value.Size.Height; - } - get { return cursor; } - } + public Cursor Cursor + { + set + { + if (cursor != null) + { + cursor.Dispose(); + } - /// - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected override void Dispose(bool disposing) { - if (disposing) { - if (cursor != null) { - cursor.Dispose(); - } - } - cursor = null; - base.Dispose(disposing); - } + // Clone cursor (is this correct??) + cursor = new Cursor(value.CopyHandle()); + Width = value.Size.Width; + Height = value.Size.Height; + } + get { return cursor; } + } - public void Load(string filename) { - if (!File.Exists(filename)) { - return; - } + /// + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (cursor != null) + { + cursor.Dispose(); + } + } + + cursor = null; + base.Dispose(disposing); + } + + public void Load(string filename) + { + if (!File.Exists(filename)) + { + return; + } using Cursor fileCursor = new Cursor(filename); Cursor = fileCursor; LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); } - public override void Draw(Graphics graphics, RenderMode rm) { - if (cursor == null) { - return; - } - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.Default; - graphics.PixelOffsetMode = PixelOffsetMode.None; - cursor.DrawStretched(graphics, Bounds); - } + public override void Draw(Graphics graphics, RenderMode rm) + { + if (cursor == null) + { + return; + } - public override Size DefaultSize => cursor?.Size ?? new Size(16, 16); - } -} + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.CompositingQuality = CompositingQuality.Default; + graphics.PixelOffsetMode = PixelOffsetMode.None; + cursor.DrawStretched(graphics, Bounds); + } + + public override Size DefaultSize => cursor?.Size ?? new Size(16, 16); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/DrawableContainer.cs b/src/Greenshot/Drawing/DrawableContainer.cs index bc0973300..96ef93b9c 100644 --- a/src/Greenshot/Drawing/DrawableContainer.cs +++ b/src/Greenshot/Drawing/DrawableContainer.cs @@ -40,524 +40,631 @@ using GreenshotPlugin.Interfaces.Drawing.Adorners; namespace Greenshot.Drawing { - /// - /// represents a rectangle, ellipse, label or whatever. Can contain filters, too. - /// serializable for clipboard support - /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call - /// OnPropertyChanged whenever a public property has been changed. - /// - [Serializable] - public abstract class DrawableContainer : AbstractFieldHolderWithChildren, IDrawableContainer { - private static readonly ILog LOG = LogManager.GetLogger(typeof(DrawableContainer)); - protected static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - private const int M11 = 0; - private const int M22 = 3; + /// + /// represents a rectangle, ellipse, label or whatever. Can contain filters, too. + /// serializable for clipboard support + /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call + /// OnPropertyChanged whenever a public property has been changed. + /// + [Serializable] + public abstract class DrawableContainer : AbstractFieldHolderWithChildren, IDrawableContainer + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(DrawableContainer)); + protected static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); + private const int M11 = 0; + private const int M22 = 3; - [OnDeserialized] - private void OnDeserializedInit(StreamingContext context) - { - _adorners = new List(); - OnDeserialized(context); - } + [OnDeserialized] + private void OnDeserializedInit(StreamingContext context) + { + _adorners = new List(); + OnDeserialized(context); + } - /// - /// Override to implement your own deserialization logic, like initializing properties which are not serialized - /// - /// - protected virtual void OnDeserialized(StreamingContext streamingContext) - { - } + /// + /// Override to implement your own deserialization logic, like initializing properties which are not serialized + /// + /// + protected virtual void OnDeserialized(StreamingContext streamingContext) + { + } - protected EditStatus _defaultEditMode = EditStatus.DRAWING; - public EditStatus DefaultEditMode { - get { - return _defaultEditMode; - } - } + protected EditStatus _defaultEditMode = EditStatus.DRAWING; - /// - /// The public accessible Dispose - /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice - /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public EditStatus DefaultEditMode + { + get { return _defaultEditMode; } + } - protected virtual void Dispose(bool disposing) { - if (!disposing) { - return; - } - _parent?.FieldAggregator?.UnbindElement(this); - } + /// + /// The public accessible Dispose + /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - ~DrawableContainer() { - Dispose(false); - } + protected virtual void Dispose(bool disposing) + { + if (!disposing) + { + return; + } - [NonSerialized] - private PropertyChangedEventHandler _propertyChanged; - public event PropertyChangedEventHandler PropertyChanged { - add => _propertyChanged += value; - remove => _propertyChanged -= value; - } + _parent?.FieldAggregator?.UnbindElement(this); + } - public IList Filters { - get { - List ret = new List(); - foreach(IFieldHolder c in Children) { - if (c is IFilter) { - ret.Add(c as IFilter); - } - } - return ret; - } - } + ~DrawableContainer() + { + Dispose(false); + } - [NonSerialized] - internal Surface _parent; - public ISurface Parent { - get => _parent; - set => SwitchParent((Surface)value); - } + [NonSerialized] private PropertyChangedEventHandler _propertyChanged; - [NonSerialized] - private TargetAdorner _targetAdorner; - public TargetAdorner TargetAdorner => _targetAdorner; + public event PropertyChangedEventHandler PropertyChanged + { + add => _propertyChanged += value; + remove => _propertyChanged -= value; + } - [NonSerialized] - private bool _selected; - public bool Selected { - get => _selected; - set { - _selected = value; - OnPropertyChanged("Selected"); - } - } + public IList Filters + { + get + { + List ret = new List(); + foreach (IFieldHolder c in Children) + { + if (c is IFilter) + { + ret.Add(c as IFilter); + } + } - [NonSerialized] - private EditStatus _status = EditStatus.UNDRAWN; - public EditStatus Status { - get => _status; - set => _status = value; - } + return ret; + } + } + + [NonSerialized] internal Surface _parent; + + public ISurface Parent + { + get => _parent; + set => SwitchParent((Surface) value); + } + + [NonSerialized] private TargetAdorner _targetAdorner; + public TargetAdorner TargetAdorner => _targetAdorner; + + [NonSerialized] private bool _selected; + + public bool Selected + { + get => _selected; + set + { + _selected = value; + OnPropertyChanged("Selected"); + } + } + + [NonSerialized] private EditStatus _status = EditStatus.UNDRAWN; + + public EditStatus Status + { + get => _status; + set => _status = value; + } - private int left; - public int Left { - get => left; - set { - if (value == left) { - return; - } - left = value; - } - } + private int left; - private int top; - public int Top { - get => top; - set { - if (value == top) { - return; - } - top = value; - } - } + public int Left + { + get => left; + set + { + if (value == left) + { + return; + } - private int width; - public int Width { - get => width; - set { - if (value == width) { - return; - } - width = value; - } - } + left = value; + } + } - private int height; - public int Height { - get => height; - set { - if (value == height) { - return; - } - height = value; - } - } + private int top; - public Point Location { - get => new Point(left, top); - set { - left = value.X; - top = value.Y; - } - } + public int Top + { + get => top; + set + { + if (value == top) + { + return; + } - public Size Size { - get => new Size(width, height); - set { - width = value.Width; - height = value.Height; - } - } + top = value; + } + } - /// - /// List of available Adorners - /// - [NonSerialized] - private IList _adorners = new List(); - public IList Adorners => _adorners; + private int width; + + public int Width + { + get => width; + set + { + if (value == width) + { + return; + } + + width = value; + } + } + + private int height; + + public int Height + { + get => height; + set + { + if (value == height) + { + return; + } + + height = value; + } + } + + public Point Location + { + get => new Point(left, top); + set + { + left = value.X; + top = value.Y; + } + } + + public Size Size + { + get => new Size(width, height); + set + { + width = value.Width; + height = value.Height; + } + } + + /// + /// List of available Adorners + /// + [NonSerialized] private IList _adorners = new List(); + + public IList Adorners => _adorners; [NonSerialized] - // will store current bounds of this DrawableContainer before starting a resize - protected Rectangle _boundsBeforeResize = Rectangle.Empty; + // will store current bounds of this DrawableContainer before starting a resize + protected Rectangle _boundsBeforeResize = Rectangle.Empty; - [NonSerialized] - // "workbench" rectangle - used for calculating bounds during resizing (to be applied to this DrawableContainer afterwards) - protected RectangleF _boundsAfterResize = RectangleF.Empty; + [NonSerialized] + // "workbench" rectangle - used for calculating bounds during resizing (to be applied to this DrawableContainer afterwards) + protected RectangleF _boundsAfterResize = RectangleF.Empty; - public Rectangle Bounds { - get => GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - set { - Left = Round(value.Left); - Top = Round(value.Top); - Width = Round(value.Width); - Height = Round(value.Height); - } - } + public Rectangle Bounds + { + get => GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + set + { + Left = Round(value.Left); + Top = Round(value.Top); + Width = Round(value.Width); + Height = Round(value.Height); + } + } - public virtual void ApplyBounds(RectangleF newBounds) { - Left = Round(newBounds.Left); - Top = Round(newBounds.Top); - Width = Round(newBounds.Width); - Height = Round(newBounds.Height); - } + public virtual void ApplyBounds(RectangleF newBounds) + { + Left = Round(newBounds.Left); + Top = Round(newBounds.Top); + Width = Round(newBounds.Width); + Height = Round(newBounds.Height); + } - public DrawableContainer(Surface parent) { - InitializeFields(); - _parent = parent; - } + public DrawableContainer(Surface parent) + { + InitializeFields(); + _parent = parent; + } - public void Add(IFilter filter) { - AddChild(filter); - } + public void Add(IFilter filter) + { + AddChild(filter); + } - public void Remove(IFilter filter) { - RemoveChild(filter); - } + public void Remove(IFilter filter) + { + RemoveChild(filter); + } - private static int Round(float f) { - if(float.IsPositiveInfinity(f) || f>int.MaxValue/2) return int.MaxValue/2; - if (float.IsNegativeInfinity(f) || f int.MaxValue / 2) return int.MaxValue / 2; + if (float.IsNegativeInfinity(f) || f < int.MinValue / 2) return int.MinValue / 2; + return (int) Math.Round(f); + } - private bool accountForShadowChange; - public virtual Rectangle DrawingBounds { - get { - foreach(IFilter filter in Filters) { - if (filter.Invert) { - return new Rectangle(Point.Empty, _parent.Image.Size); - } - } - // Take a base safety margin - int lineThickness = 5; + private bool accountForShadowChange; + + public virtual Rectangle DrawingBounds + { + get + { + foreach (IFilter filter in Filters) + { + if (filter.Invert) + { + return new Rectangle(Point.Empty, _parent.Image.Size); + } + } + + // Take a base safety margin + int lineThickness = 5; // add adorner size lineThickness += Adorners.Max(adorner => Math.Max(adorner.Bounds.Width, adorner.Bounds.Height)); - if (HasField(FieldType.LINE_THICKNESS)) { - lineThickness += GetFieldValueAsInt(FieldType.LINE_THICKNESS); - } - int offset = lineThickness/2; + if (HasField(FieldType.LINE_THICKNESS)) + { + lineThickness += GetFieldValueAsInt(FieldType.LINE_THICKNESS); + } - int shadow = 0; - if (accountForShadowChange || (HasField(FieldType.SHADOW) && GetFieldValueAsBool(FieldType.SHADOW))){ - accountForShadowChange = false; - shadow += 10; - } - return new Rectangle(Bounds.Left-offset, Bounds.Top-offset, Bounds.Width+lineThickness+shadow, Bounds.Height+lineThickness+shadow); - } - } + int offset = lineThickness / 2; - public virtual void Invalidate() { - if (Status != EditStatus.UNDRAWN) { - _parent?.InvalidateElements(DrawingBounds); - } - } + int shadow = 0; + if (accountForShadowChange || (HasField(FieldType.SHADOW) && GetFieldValueAsBool(FieldType.SHADOW))) + { + accountForShadowChange = false; + shadow += 10; + } - public virtual bool InitContent() { return true; } + return new Rectangle(Bounds.Left - offset, Bounds.Top - offset, Bounds.Width + lineThickness + shadow, Bounds.Height + lineThickness + shadow); + } + } - public virtual void OnDoubleClick() {} - - /// - /// Initialize a target gripper - /// - protected void InitAdorner(Color gripperColor, Point location) { - _targetAdorner = new TargetAdorner(this, location); - Adorners.Add(_targetAdorner); - } - - /// - /// Create the default adorners for a rectangle based container - /// - - protected void CreateDefaultAdorners() { - if (Adorners.Count > 0) - { - LOG.Warn("Adorners are already defined!"); - } - // Create the GripperAdorners - Adorners.Add(new ResizeAdorner(this, Positions.TopLeft)); - Adorners.Add(new ResizeAdorner(this, Positions.TopCenter)); - Adorners.Add(new ResizeAdorner(this, Positions.TopRight)); - Adorners.Add(new ResizeAdorner(this, Positions.BottomLeft)); - Adorners.Add(new ResizeAdorner(this, Positions.BottomCenter)); - Adorners.Add(new ResizeAdorner(this, Positions.BottomRight)); - Adorners.Add(new ResizeAdorner(this, Positions.MiddleLeft)); - Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight)); - } - - public bool hasFilters => Filters.Count > 0; - - public abstract void Draw(Graphics graphics, RenderMode renderMode); - - public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle) { - if (Children.Count > 0) { - if (Status != EditStatus.IDLE) { - DrawSelectionBorder(graphics, Bounds); - } else { - if (clipRectangle.Width != 0 && clipRectangle.Height != 0) { - foreach(IFilter filter in Filters) { - if (filter.Invert) { - filter.Apply(graphics, bmp, Bounds, renderMode); - } else { - Rectangle drawingRect = new Rectangle(Bounds.Location, Bounds.Size); - drawingRect.Intersect(clipRectangle); - if(filter is MagnifierFilter) { - // quick&dirty bugfix, because MagnifierFilter behaves differently when drawn only partially - // what we should actually do to resolve this is add a better magnifier which is not that special - filter.Apply(graphics, bmp, Bounds, renderMode); - } else { - filter.Apply(graphics, bmp, drawingRect, renderMode); - } - } - } - } - - } - } - Draw(graphics, renderMode); - } - - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// uint with dpi value - public void AdjustToDpi(uint dpi) - { - foreach(var adorner in Adorners) - { - adorner.AdjustToDpi(dpi); - } - } - - public virtual bool Contains(int x, int y) { - return Bounds.Contains(x , y); - } - - public virtual bool ClickableAt(int x, int y) { - Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - r.Inflate(5, 5); - return r.Contains(x, y); - } - - protected void DrawSelectionBorder(Graphics g, Rectangle rect) + public virtual void Invalidate() { - using Pen pen = new Pen(Color.MediumSeaGreen) - { - DashPattern = new float[] { 1, 2 }, - Width = 1 - }; - g.DrawRectangle(pen, rect); + if (Status != EditStatus.UNDRAWN) + { + _parent?.InvalidateElements(DrawingBounds); + } + } + + public virtual bool InitContent() + { + return true; + } + + public virtual void OnDoubleClick() + { + } + + /// + /// Initialize a target gripper + /// + protected void InitAdorner(Color gripperColor, Point location) + { + _targetAdorner = new TargetAdorner(this, location); + Adorners.Add(_targetAdorner); + } + + /// + /// Create the default adorners for a rectangle based container + /// + protected void CreateDefaultAdorners() + { + if (Adorners.Count > 0) + { + LOG.Warn("Adorners are already defined!"); + } + + // Create the GripperAdorners + Adorners.Add(new ResizeAdorner(this, Positions.TopLeft)); + Adorners.Add(new ResizeAdorner(this, Positions.TopCenter)); + Adorners.Add(new ResizeAdorner(this, Positions.TopRight)); + Adorners.Add(new ResizeAdorner(this, Positions.BottomLeft)); + Adorners.Add(new ResizeAdorner(this, Positions.BottomCenter)); + Adorners.Add(new ResizeAdorner(this, Positions.BottomRight)); + Adorners.Add(new ResizeAdorner(this, Positions.MiddleLeft)); + Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight)); + } + + public bool hasFilters => Filters.Count > 0; + + public abstract void Draw(Graphics graphics, RenderMode renderMode); + + public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle) + { + if (Children.Count > 0) + { + if (Status != EditStatus.IDLE) + { + DrawSelectionBorder(graphics, Bounds); + } + else + { + if (clipRectangle.Width != 0 && clipRectangle.Height != 0) + { + foreach (IFilter filter in Filters) + { + if (filter.Invert) + { + filter.Apply(graphics, bmp, Bounds, renderMode); + } + else + { + Rectangle drawingRect = new Rectangle(Bounds.Location, Bounds.Size); + drawingRect.Intersect(clipRectangle); + if (filter is MagnifierFilter) + { + // quick&dirty bugfix, because MagnifierFilter behaves differently when drawn only partially + // what we should actually do to resolve this is add a better magnifier which is not that special + filter.Apply(graphics, bmp, Bounds, renderMode); + } + else + { + filter.Apply(graphics, bmp, drawingRect, renderMode); + } + } + } + } + } + } + + Draw(graphics, renderMode); + } + + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// uint with dpi value + public void AdjustToDpi(uint dpi) + { + foreach (var adorner in Adorners) + { + adorner.AdjustToDpi(dpi); + } + } + + public virtual bool Contains(int x, int y) + { + return Bounds.Contains(x, y); + } + + public virtual bool ClickableAt(int x, int y) + { + Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + r.Inflate(5, 5); + return r.Contains(x, y); + } + + protected void DrawSelectionBorder(Graphics g, Rectangle rect) + { + using Pen pen = new Pen(Color.MediumSeaGreen) + { + DashPattern = new float[] + { + 1, 2 + }, + Width = 1 + }; + g.DrawRectangle(pen, rect); } - public void ResizeTo(int width, int height, int anchorPosition) { - Width = width; - Height = height; - } + public void ResizeTo(int width, int height, int anchorPosition) + { + Width = width; + Height = height; + } - /// - /// Make a following bounds change on this drawablecontainer undoable! - /// - /// true means allow the moves to be merged - public void MakeBoundsChangeUndoable(bool allowMerge) { - _parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); - } + /// + /// Make a following bounds change on this drawablecontainer undoable! + /// + /// true means allow the moves to be merged + public void MakeBoundsChangeUndoable(bool allowMerge) + { + _parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); + } - public void MoveBy(int dx, int dy) { - Left += dx; - Top += dy; - } + public void MoveBy(int dx, int dy) + { + Left += dx; + Top += dy; + } - /// - /// A handler for the MouseDown, used if you don't want the surface to handle this for you - /// - /// current mouse x - /// current mouse y - /// true if the event is handled, false if the surface needs to handle it - public virtual bool HandleMouseDown(int x, int y) { - Left = _boundsBeforeResize.X = x; - Top = _boundsBeforeResize.Y = y; - return true; - } + /// + /// A handler for the MouseDown, used if you don't want the surface to handle this for you + /// + /// current mouse x + /// current mouse y + /// true if the event is handled, false if the surface needs to handle it + public virtual bool HandleMouseDown(int x, int y) + { + Left = _boundsBeforeResize.X = x; + Top = _boundsBeforeResize.Y = y; + return true; + } - /// - /// A handler for the MouseMove, used if you don't want the surface to handle this for you - /// - /// current mouse x - /// current mouse y - /// true if the event is handled, false if the surface needs to handle it - public virtual bool HandleMouseMove(int x, int y) { - Invalidate(); + /// + /// A handler for the MouseMove, used if you don't want the surface to handle this for you + /// + /// current mouse x + /// current mouse y + /// true if the event is handled, false if the surface needs to handle it + public virtual bool HandleMouseMove(int x, int y) + { + Invalidate(); - // reset "workrbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.Left; - _boundsAfterResize.Y = _boundsBeforeResize.Top; - _boundsAfterResize.Width = x - _boundsAfterResize.Left; - _boundsAfterResize.Height = y - _boundsAfterResize.Top; + // reset "workrbench" rectangle to current bounds + _boundsAfterResize.X = _boundsBeforeResize.Left; + _boundsAfterResize.Y = _boundsBeforeResize.Top; + _boundsAfterResize.Width = x - _boundsAfterResize.Left; + _boundsAfterResize.Height = y - _boundsAfterResize.Top; - ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); + ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); - // apply scaled bounds to this DrawableContainer - ApplyBounds(_boundsAfterResize); + // apply scaled bounds to this DrawableContainer + ApplyBounds(_boundsAfterResize); - Invalidate(); - return true; - } + Invalidate(); + return true; + } - /// - /// A handler for the MouseUp - /// - /// current mouse x - /// current mouse y - public virtual void HandleMouseUp(int x, int y) { - } + /// + /// A handler for the MouseUp + /// + /// current mouse x + /// current mouse y + public virtual void HandleMouseUp(int x, int y) + { + } - protected virtual void SwitchParent(Surface newParent) { - if (newParent == Parent) - { - return; - } - _parent?.FieldAggregator?.UnbindElement(this); + protected virtual void SwitchParent(Surface newParent) + { + if (newParent == Parent) + { + return; + } - _parent = newParent; - foreach(IFilter filter in Filters) { - filter.Parent = this; - } - } + _parent?.FieldAggregator?.UnbindElement(this); - protected void OnPropertyChanged(string propertyName) { - if (_propertyChanged != null) { - _propertyChanged(this, new PropertyChangedEventArgs(propertyName)); - Invalidate(); - } - } + _parent = newParent; + foreach (IFilter filter in Filters) + { + filter.Parent = this; + } + } - /// - /// This method will be called before a field is changes. - /// Using this makes it possible to invalidate the object as is before changing. - /// - /// The field to be changed - /// The new value - public virtual void BeforeFieldChange(IField fieldToBeChanged, object newValue) { - _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); - Invalidate(); - } + protected void OnPropertyChanged(string propertyName) + { + if (_propertyChanged != null) + { + _propertyChanged(this, new PropertyChangedEventArgs(propertyName)); + Invalidate(); + } + } - /// - /// Handle the field changed event, this should invalidate the correct bounds (e.g. when shadow comes or goes more pixels!) - /// - /// - /// - public void HandleFieldChanged(object sender, FieldChangedEventArgs e) { - LOG.DebugFormat("Field {0} changed", e.Field.FieldType); - if (Equals(e.Field.FieldType, FieldType.SHADOW)) { - accountForShadowChange = true; - } - } + /// + /// This method will be called before a field is changes. + /// Using this makes it possible to invalidate the object as is before changing. + /// + /// The field to be changed + /// The new value + public virtual void BeforeFieldChange(IField fieldToBeChanged, object newValue) + { + _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); + Invalidate(); + } - /// - /// Retrieve the Y scale from the matrix - /// - /// - /// - public static float CalculateScaleY(Matrix matrix) { - return matrix.Elements[M22]; - } + /// + /// Handle the field changed event, this should invalidate the correct bounds (e.g. when shadow comes or goes more pixels!) + /// + /// + /// + public void HandleFieldChanged(object sender, FieldChangedEventArgs e) + { + LOG.DebugFormat("Field {0} changed", e.Field.FieldType); + if (Equals(e.Field.FieldType, FieldType.SHADOW)) + { + accountForShadowChange = true; + } + } - /// - /// Retrieve the X scale from the matrix - /// - /// - /// - public static float CalculateScaleX(Matrix matrix) { - return matrix.Elements[M11]; - } + /// + /// Retrieve the Y scale from the matrix + /// + /// + /// + public static float CalculateScaleY(Matrix matrix) + { + return matrix.Elements[M22]; + } - /// - /// Retrieve the rotation angle from the matrix - /// - /// - /// - public static int CalculateAngle(Matrix matrix) { - const int M11 = 0; - const int M21 = 2; - var radians = Math.Atan2(matrix.Elements[M21], matrix.Elements[M11]); - return (int)-Math.Round(radians * 180 / Math.PI); - } + /// + /// Retrieve the X scale from the matrix + /// + /// + /// + public static float CalculateScaleX(Matrix matrix) + { + return matrix.Elements[M11]; + } - /// - /// This method is called on a DrawableContainers when: - /// 1) The capture on the surface is modified in such a way, that the elements would not be placed correctly. - /// 2) Currently not implemented: an element needs to be moved, scaled or rotated. - /// This basis implementation makes sure the coordinates of the element, including the TargetGripper, is correctly rotated/scaled/translated. - /// But this implementation doesn't take care of any changes to the content!! - /// - /// - public virtual void Transform(Matrix matrix) { - if (matrix == null) { - return; - } - Point topLeft = new Point(Left, Top); - Point bottomRight = new Point(Left + Width, Top + Height); - Point[] points = new[] { topLeft, bottomRight }; - matrix.TransformPoints(points); + /// + /// Retrieve the rotation angle from the matrix + /// + /// + /// + public static int CalculateAngle(Matrix matrix) + { + const int M11 = 0; + const int M21 = 2; + var radians = Math.Atan2(matrix.Elements[M21], matrix.Elements[M11]); + return (int) -Math.Round(radians * 180 / Math.PI); + } - Left = points[0].X; - Top = points[0].Y; - Width = points[1].X - points[0].X; - Height = points[1].Y - points[0].Y; + /// + /// This method is called on a DrawableContainers when: + /// 1) The capture on the surface is modified in such a way, that the elements would not be placed correctly. + /// 2) Currently not implemented: an element needs to be moved, scaled or rotated. + /// This basis implementation makes sure the coordinates of the element, including the TargetGripper, is correctly rotated/scaled/translated. + /// But this implementation doesn't take care of any changes to the content!! + /// + /// + public virtual void Transform(Matrix matrix) + { + if (matrix == null) + { + return; + } - } + Point topLeft = new Point(Left, Top); + Point bottomRight = new Point(Left + Width, Top + Height); + Point[] points = new[] + { + topLeft, bottomRight + }; + matrix.TransformPoints(points); - protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() { - return ScaleHelper.ShapeAngleRoundBehavior.Instance; - } + Left = points[0].X; + Top = points[0].Y; + Width = points[1].X - points[0].X; + Height = points[1].Y - points[0].Y; + } - public virtual bool HasContextMenu => true; + protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() + { + return ScaleHelper.ShapeAngleRoundBehavior.Instance; + } - public virtual bool HasDefaultSize => false; + public virtual bool HasContextMenu => true; - public virtual Size DefaultSize => throw new NotSupportedException("Object doesn't have a default size"); + public virtual bool HasDefaultSize => false; - /// - /// Allows to override the initializing of the fields, so we can actually have our own defaults - /// - protected virtual void InitializeFields() { - } - } + public virtual Size DefaultSize => throw new NotSupportedException("Object doesn't have a default size"); + + /// + /// Allows to override the initializing of the fields, so we can actually have our own defaults + /// + protected virtual void InitializeFields() + { + } + } } \ No newline at end of file diff --git a/src/Greenshot/Drawing/DrawableContainerList.cs b/src/Greenshot/Drawing/DrawableContainerList.cs index a7107543e..c450ebad4 100644 --- a/src/Greenshot/Drawing/DrawableContainerList.cs +++ b/src/Greenshot/Drawing/DrawableContainerList.cs @@ -33,588 +33,696 @@ using System.Windows.Forms; using Greenshot.Forms; using GreenshotPlugin.Interfaces; -namespace Greenshot.Drawing { - /// - /// Dispatches most of a DrawableContainer's public properties and methods to a list of DrawableContainers. - /// - [Serializable] - public class DrawableContainerList : List, IDrawableContainerList - { - private static readonly ComponentResourceManager EditorFormResources = new ComponentResourceManager(typeof(ImageEditorForm)); +namespace Greenshot.Drawing +{ + /// + /// Dispatches most of a DrawableContainer's public properties and methods to a list of DrawableContainers. + /// + [Serializable] + public class DrawableContainerList : List, IDrawableContainerList + { + private static readonly ComponentResourceManager EditorFormResources = new ComponentResourceManager(typeof(ImageEditorForm)); - public Guid ParentID { - get; - private set; - } + public Guid ParentID { get; private set; } - public DrawableContainerList() { - } + public DrawableContainerList() + { + } - public DrawableContainerList(Guid parentId) { - ParentID = parentId; - } - - public EditStatus Status { - get { - return this[Count-1].Status; - } - set { - foreach (var dc in this) { - dc.Status = value; - } - } - } - - public List AsIDrawableContainerList() { - List interfaceList = new List(); - foreach(IDrawableContainer container in this) { - interfaceList.Add(container); - } - return interfaceList; - } - - /// - /// Gets or sets the selection status of the elements. - /// If several elements are in the list, true is only returned when all elements are selected. - /// - public bool Selected { - get { - bool ret = true; - foreach(var dc in this) { - ret &= dc.Selected; - } - return ret; - } - set { - foreach(var dc in this) { - dc.Selected = value; - } - } - } - - /// - /// Gets or sets the parent control of the elements in the list. - /// If there are several elements, the parent control of the last added is returned. - /// - public ISurface Parent { - get { - if (Count > 0) { - return this[Count-1].Parent; - } - return null; - } - set { - ParentID = value?.ID ?? Guid.NewGuid(); - foreach (var drawableContainer in this) { - var dc = (DrawableContainer) drawableContainer; - dc.Parent = value; - } - } - } - - /// - /// Make a following bounds change on this containerlist undoable! - /// - /// true means allow the moves to be merged - public void MakeBoundsChangeUndoable(bool allowMerge) { - if (Count > 0 && Parent != null) - { - var clone = new DrawableContainerList(); - clone.AddRange(this); - Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge); - } - } + public DrawableContainerList(Guid parentId) + { + ParentID = parentId; + } - /// - /// Apply matrix to all elements - /// - public void Transform(Matrix matrix) { - // Track modifications - bool modified = false; - Invalidate(); - foreach (var dc in this) { - dc.Transform(matrix); - modified = true; - } - // Invalidate after - Invalidate(); - // If we moved something, tell the surface it's modified! - if (modified) { - Parent.Modified = true; - } - } + public EditStatus Status + { + get { return this[Count - 1].Status; } + set + { + foreach (var dc in this) + { + dc.Status = value; + } + } + } - /// - /// Moves all elements in the list by the given amount of pixels. - /// - /// pixels to move horizontally - /// pixels to move vertically - public void MoveBy(int dx, int dy) { - // Track modifications - bool modified = false; + public List AsIDrawableContainerList() + { + List interfaceList = new List(); + foreach (IDrawableContainer container in this) + { + interfaceList.Add(container); + } - // Invalidate before moving, otherwise the old locations aren't refreshed - Invalidate(); - foreach(var dc in this) { - dc.Left += dx; - dc.Top += dy; - modified = true; - } - // Invalidate after - Invalidate(); + return interfaceList; + } - // If we moved something, tell the surface it's modified! - if (modified) { - Parent.Modified = true; - } - } - - /// - /// Indicates whether on of the elements is clickable at the given location - /// - /// x coordinate to be checked - /// y coordinate to be checked - /// true if one of the elements in the list is clickable at the given location, false otherwise - public bool ClickableAt(int x, int y) { - bool ret = false; - foreach(var dc in this) { - ret |= dc.ClickableAt(x, y); - } - return ret; - } - - /// - /// retrieves the topmost element being clickable at the given location - /// - /// x coordinate to be checked - /// y coordinate to be checked - /// the topmost element from the list being clickable at the given location, null if there is no clickable element - public IDrawableContainer ClickableElementAt(int x, int y) { - for (int i=Count-1; i>=0; i--) { - if (this[i].ClickableAt(x,y)) { - return this[i]; - } - } - return null; - } - - /// - /// Dispatches OnDoubleClick to all elements in the list. - /// - public void OnDoubleClick() { - foreach(var drawableContainer in this) { - var dc = (DrawableContainer) drawableContainer; - dc.OnDoubleClick(); - } - } + /// + /// Gets or sets the selection status of the elements. + /// If several elements are in the list, true is only returned when all elements are selected. + /// + public bool Selected + { + get + { + bool ret = true; + foreach (var dc in this) + { + ret &= dc.Selected; + } - /// - /// Check if there are any intersecting filters, if so we need to redraw more - /// - /// - /// true if an filter intersects - public bool HasIntersectingFilters(Rectangle clipRectangle) { - foreach(var dc in this) { - if (dc.DrawingBounds.IntersectsWith(clipRectangle) && dc.hasFilters && dc.Status == EditStatus.IDLE) { - return true; - } - } - return false; - } + return ret; + } + set + { + foreach (var dc in this) + { + dc.Selected = value; + } + } + } - /// - /// Check if any of the drawableContainers are inside the rectangle - /// - /// - /// - public bool IntersectsWith(Rectangle clipRectangle) { - foreach(var dc in this) { - if (dc.DrawingBounds.IntersectsWith(clipRectangle)) { - return true; - } - } - return false; - } + /// + /// Gets or sets the parent control of the elements in the list. + /// If there are several elements, the parent control of the last added is returned. + /// + public ISurface Parent + { + get + { + if (Count > 0) + { + return this[Count - 1].Parent; + } - /// - /// A rectangle containing DrawingBounds of all drawableContainers in this list, - /// or empty rectangle if nothing is there. - /// - public Rectangle DrawingBounds - { - get - { - if (Count == 0) - { - return Rectangle.Empty; - } - else - { - var result = this[0].DrawingBounds; - for (int i = 1; i < Count; i++) - { - result = Rectangle.Union(result, this[i].DrawingBounds); - } - return result; - } - } - } + return null; + } + set + { + ParentID = value?.ID ?? Guid.NewGuid(); + foreach (var drawableContainer in this) + { + var dc = (DrawableContainer) drawableContainer; + dc.Parent = value; + } + } + } - /// - /// Triggers all elements in the list ot be redrawn. - /// - /// the to the bitmap related Graphics object - /// Bitmap to draw - /// the rendermode in which the element is to be drawn - /// - public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle) { - if (Parent == null) - { - return; - } - foreach (var drawableContainer in this) - { - var dc = (DrawableContainer)drawableContainer; - if (dc.Parent == null) - { - continue; - } - if (dc.DrawingBounds.IntersectsWith(clipRectangle)) - { - dc.DrawContent(g, bitmap, renderMode, clipRectangle); - } - } - } - - /// - /// Pass the field changed event to all elements in the list - /// - /// - /// - public void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e) { - foreach(var drawableContainer in this) { - var dc = (DrawableContainer) drawableContainer; - dc.HandleFieldChanged(sender, e); - } - } + /// + /// Make a following bounds change on this containerlist undoable! + /// + /// true means allow the moves to be merged + public void MakeBoundsChangeUndoable(bool allowMerge) + { + if (Count > 0 && Parent != null) + { + var clone = new DrawableContainerList(); + clone.AddRange(this); + Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge); + } + } - /// - /// Invalidate the bounds of all the DC's in this list - /// - public void Invalidate() { - if (Parent == null) - { - return; - } - Rectangle region = Rectangle.Empty; - foreach (var dc in this) - { - region = Rectangle.Union(region, dc.DrawingBounds); - } - Parent.InvalidateElements(region); - } - /// - /// Indicates whether the given list of elements can be pulled up, - /// i.e. whether there is at least one unselected element higher in hierarchy - /// - /// list of elements to pull up - /// true if the elements could be pulled up - public bool CanPullUp(IDrawableContainerList elements) { - if (elements.Count == 0 || elements.Count == Count) { - return false; - } - foreach(var element in elements) { - if (IndexOf(element) < Count - elements.Count) { - return true; - } - } - return false; - } - - /// - /// Pulls one or several elements up one level in hierarchy (z-index). - /// - /// list of elements to pull up - public void PullElementsUp(IDrawableContainerList elements) { - for(int i=Count-1; i>=0; i--) { - var dc = this[i]; - if (!elements.Contains(dc)) { - continue; - } - if (Count > i+1 && !elements.Contains(this[i+1])) { - SwapElements(i,i+1); - } - } - } - - /// - /// Pulls one or several elements up to the topmost level(s) in hierarchy (z-index). - /// - /// of elements to pull to top - public void PullElementsToTop(IDrawableContainerList elements) - { - var dcs = ToArray(); - foreach (var dc in dcs) - { - if (!elements.Contains(dc)) { - continue; - } - Remove(dc); - Add(dc); - Parent.Modified = true; - } - } + /// + /// Apply matrix to all elements + /// + public void Transform(Matrix matrix) + { + // Track modifications + bool modified = false; + Invalidate(); + foreach (var dc in this) + { + dc.Transform(matrix); + modified = true; + } - /// - /// Indicates whether the given list of elements can be pushed down, - /// i.e. whether there is at least one unselected element lower in hierarchy - /// - /// list of elements to push down - /// true if the elements could be pushed down - public bool CanPushDown(IDrawableContainerList elements) { - if (elements.Count == 0 || elements.Count == Count) { - return false; - } - foreach(var element in elements) { - if (IndexOf(element) >= elements.Count) { - return true; - } - } - return false; - } - - /// - /// Pushes one or several elements down one level in hierarchy (z-index). - /// - /// list of elements to push down - public void PushElementsDown(IDrawableContainerList elements) { - for(int i=0; i0) && !elements.Contains(this[i-1])) { - SwapElements(i,i-1); - } - } - } - - /// - /// Pushes one or several elements down to the bottommost level(s) in hierarchy (z-index). - /// - /// of elements to push to bottom - public void PushElementsToBottom(IDrawableContainerList elements) { - var dcs = ToArray(); - for(int i=dcs.Length-1; i>=0; i--) { - var dc = dcs[i]; - if (!elements.Contains(dc)) { - continue; - } - Remove(dc); - Insert(0, dc); - Parent.Modified = true; - } - } - - /// - /// swaps two elements in hierarchy (z-index), - /// checks both indices to be in range - /// - /// index of the 1st element - /// index of the 2nd element - private void SwapElements(int index1, int index2) { - if (index1 < 0 || index1 >= Count || index2 < 0 || index2 >= Count || index1 == index2) { - return; - } - var dc = this[index1]; - this[index1] = this[index2]; - this[index2] = dc; - Parent.Modified = true; - } + // Invalidate after + Invalidate(); + // If we moved something, tell the surface it's modified! + if (modified) + { + Parent.Modified = true; + } + } - /// - /// Add items to a context menu for the selected item - /// - /// - /// - public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface) { - bool push = surface.Elements.CanPushDown(this); - bool pull = surface.Elements.CanPullUp(this); + /// + /// Moves all elements in the list by the given amount of pixels. + /// + /// pixels to move horizontally + /// pixels to move vertically + public void MoveBy(int dx, int dy) + { + // Track modifications + bool modified = false; - ToolStripMenuItem item; + // Invalidate before moving, otherwise the old locations aren't refreshed + Invalidate(); + foreach (var dc in this) + { + dc.Left += dx; + dc.Top += dy; + modified = true; + } - // Pull "up" - if (pull) { - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uptotop)); - item.Click += delegate { - surface.Elements.PullElementsToTop(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uponelevel)); - item.Click += delegate { - surface.Elements.PullElementsUp(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - } - // Push "down" - if (push) { - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downtobottom)); - item.Click += delegate { - surface.Elements.PushElementsToBottom(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downonelevel)); - item.Click += delegate { - surface.Elements.PushElementsDown(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - } + // Invalidate after + Invalidate(); - // Duplicate - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_duplicate)); - item.Click += delegate { - IDrawableContainerList dcs = this.Clone(); - dcs.Parent = surface; - dcs.MoveBy(10, 10); - surface.AddElements(dcs); - surface.DeselectAllElements(); - surface.SelectElements(dcs); - }; - menu.Items.Add(item); + // If we moved something, tell the surface it's modified! + if (modified) + { + Parent.Modified = true; + } + } - // Copy - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_copytoclipboard)) - { - Image = (Image) EditorFormResources.GetObject("copyToolStripMenuItem.Image") - }; - item.Click += delegate { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); - }; - menu.Items.Add(item); + /// + /// Indicates whether on of the elements is clickable at the given location + /// + /// x coordinate to be checked + /// y coordinate to be checked + /// true if one of the elements in the list is clickable at the given location, false otherwise + public bool ClickableAt(int x, int y) + { + bool ret = false; + foreach (var dc in this) + { + ret |= dc.ClickableAt(x, y); + } - // Cut - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_cuttoclipboard)) - { - Image = (Image) EditorFormResources.GetObject("btnCut.Image") - }; - item.Click += delegate { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); - surface.RemoveElements(this); - }; - menu.Items.Add(item); + return ret; + } + + /// + /// retrieves the topmost element being clickable at the given location + /// + /// x coordinate to be checked + /// y coordinate to be checked + /// the topmost element from the list being clickable at the given location, null if there is no clickable element + public IDrawableContainer ClickableElementAt(int x, int y) + { + for (int i = Count - 1; i >= 0; i--) + { + if (this[i].ClickableAt(x, y)) + { + return this[i]; + } + } + + return null; + } + + /// + /// Dispatches OnDoubleClick to all elements in the list. + /// + public void OnDoubleClick() + { + foreach (var drawableContainer in this) + { + var dc = (DrawableContainer) drawableContainer; + dc.OnDoubleClick(); + } + } + + /// + /// Check if there are any intersecting filters, if so we need to redraw more + /// + /// + /// true if an filter intersects + public bool HasIntersectingFilters(Rectangle clipRectangle) + { + foreach (var dc in this) + { + if (dc.DrawingBounds.IntersectsWith(clipRectangle) && dc.hasFilters && dc.Status == EditStatus.IDLE) + { + return true; + } + } + + return false; + } + + /// + /// Check if any of the drawableContainers are inside the rectangle + /// + /// + /// + public bool IntersectsWith(Rectangle clipRectangle) + { + foreach (var dc in this) + { + if (dc.DrawingBounds.IntersectsWith(clipRectangle)) + { + return true; + } + } + + return false; + } + + /// + /// A rectangle containing DrawingBounds of all drawableContainers in this list, + /// or empty rectangle if nothing is there. + /// + public Rectangle DrawingBounds + { + get + { + if (Count == 0) + { + return Rectangle.Empty; + } + else + { + var result = this[0].DrawingBounds; + for (int i = 1; i < Count; i++) + { + result = Rectangle.Union(result, this[i].DrawingBounds); + } + + return result; + } + } + } + + /// + /// Triggers all elements in the list ot be redrawn. + /// + /// the to the bitmap related Graphics object + /// Bitmap to draw + /// the rendermode in which the element is to be drawn + /// + public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle) + { + if (Parent == null) + { + return; + } + + foreach (var drawableContainer in this) + { + var dc = (DrawableContainer) drawableContainer; + if (dc.Parent == null) + { + continue; + } + + if (dc.DrawingBounds.IntersectsWith(clipRectangle)) + { + dc.DrawContent(g, bitmap, renderMode, clipRectangle); + } + } + } + + /// + /// Pass the field changed event to all elements in the list + /// + /// + /// + public void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e) + { + foreach (var drawableContainer in this) + { + var dc = (DrawableContainer) drawableContainer; + dc.HandleFieldChanged(sender, e); + } + } + + /// + /// Invalidate the bounds of all the DC's in this list + /// + public void Invalidate() + { + if (Parent == null) + { + return; + } + + Rectangle region = Rectangle.Empty; + foreach (var dc in this) + { + region = Rectangle.Union(region, dc.DrawingBounds); + } + + Parent.InvalidateElements(region); + } + + /// + /// Indicates whether the given list of elements can be pulled up, + /// i.e. whether there is at least one unselected element higher in hierarchy + /// + /// list of elements to pull up + /// true if the elements could be pulled up + public bool CanPullUp(IDrawableContainerList elements) + { + if (elements.Count == 0 || elements.Count == Count) + { + return false; + } + + foreach (var element in elements) + { + if (IndexOf(element) < Count - elements.Count) + { + return true; + } + } + + return false; + } + + /// + /// Pulls one or several elements up one level in hierarchy (z-index). + /// + /// list of elements to pull up + public void PullElementsUp(IDrawableContainerList elements) + { + for (int i = Count - 1; i >= 0; i--) + { + var dc = this[i]; + if (!elements.Contains(dc)) + { + continue; + } + + if (Count > i + 1 && !elements.Contains(this[i + 1])) + { + SwapElements(i, i + 1); + } + } + } + + /// + /// Pulls one or several elements up to the topmost level(s) in hierarchy (z-index). + /// + /// of elements to pull to top + public void PullElementsToTop(IDrawableContainerList elements) + { + var dcs = ToArray(); + foreach (var dc in dcs) + { + if (!elements.Contains(dc)) + { + continue; + } + + Remove(dc); + Add(dc); + Parent.Modified = true; + } + } + + /// + /// Indicates whether the given list of elements can be pushed down, + /// i.e. whether there is at least one unselected element lower in hierarchy + /// + /// list of elements to push down + /// true if the elements could be pushed down + public bool CanPushDown(IDrawableContainerList elements) + { + if (elements.Count == 0 || elements.Count == Count) + { + return false; + } + + foreach (var element in elements) + { + if (IndexOf(element) >= elements.Count) + { + return true; + } + } + + return false; + } + + /// + /// Pushes one or several elements down one level in hierarchy (z-index). + /// + /// list of elements to push down + public void PushElementsDown(IDrawableContainerList elements) + { + for (int i = 0; i < Count; i++) + { + var dc = this[i]; + if (!elements.Contains(dc)) + { + continue; + } + + if ((i > 0) && !elements.Contains(this[i - 1])) + { + SwapElements(i, i - 1); + } + } + } + + /// + /// Pushes one or several elements down to the bottommost level(s) in hierarchy (z-index). + /// + /// of elements to push to bottom + public void PushElementsToBottom(IDrawableContainerList elements) + { + var dcs = ToArray(); + for (int i = dcs.Length - 1; i >= 0; i--) + { + var dc = dcs[i]; + if (!elements.Contains(dc)) + { + continue; + } + + Remove(dc); + Insert(0, dc); + Parent.Modified = true; + } + } + + /// + /// swaps two elements in hierarchy (z-index), + /// checks both indices to be in range + /// + /// index of the 1st element + /// index of the 2nd element + private void SwapElements(int index1, int index2) + { + if (index1 < 0 || index1 >= Count || index2 < 0 || index2 >= Count || index1 == index2) + { + return; + } + + var dc = this[index1]; + this[index1] = this[index2]; + this[index2] = dc; + Parent.Modified = true; + } + + /// + /// Add items to a context menu for the selected item + /// + /// + /// + public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface) + { + bool push = surface.Elements.CanPushDown(this); + bool pull = surface.Elements.CanPullUp(this); + + ToolStripMenuItem item; + + // Pull "up" + if (pull) + { + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uptotop)); + item.Click += delegate + { + surface.Elements.PullElementsToTop(this); + surface.Elements.Invalidate(); + }; + menu.Items.Add(item); + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uponelevel)); + item.Click += delegate + { + surface.Elements.PullElementsUp(this); + surface.Elements.Invalidate(); + }; + menu.Items.Add(item); + } + + // Push "down" + if (push) + { + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downtobottom)); + item.Click += delegate + { + surface.Elements.PushElementsToBottom(this); + surface.Elements.Invalidate(); + }; + menu.Items.Add(item); + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downonelevel)); + item.Click += delegate + { + surface.Elements.PushElementsDown(this); + surface.Elements.Invalidate(); + }; + menu.Items.Add(item); + } + + // Duplicate + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_duplicate)); + item.Click += delegate + { + IDrawableContainerList dcs = this.Clone(); + dcs.Parent = surface; + dcs.MoveBy(10, 10); + surface.AddElements(dcs); + surface.DeselectAllElements(); + surface.SelectElements(dcs); + }; + menu.Items.Add(item); + + // Copy + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_copytoclipboard)) + { + Image = (Image) EditorFormResources.GetObject("copyToolStripMenuItem.Image") + }; + item.Click += delegate { ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); }; + menu.Items.Add(item); + + // Cut + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_cuttoclipboard)) + { + Image = (Image) EditorFormResources.GetObject("btnCut.Image") + }; + item.Click += delegate + { + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); + surface.RemoveElements(this); + }; + menu.Items.Add(item); // Delete item = new ToolStripMenuItem(Language.GetString(LangKey.editor_deleteelement)) { - Image = (Image)EditorFormResources.GetObject("removeObjectToolStripMenuItem.Image") + Image = (Image) EditorFormResources.GetObject("removeObjectToolStripMenuItem.Image") }; - item.Click += delegate { - surface.RemoveElements(this); - }; - menu.Items.Add(item); + item.Click += delegate { surface.RemoveElements(this); }; + menu.Items.Add(item); - // Reset - bool canReset = false; - foreach (var drawableContainer in this) - { - var container = (DrawableContainer)drawableContainer; - if (container.HasDefaultSize) - { - canReset = true; - } - } - if (canReset) { - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_resetsize)); - //item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("removeObjectToolStripMenuItem.Image"))); - item.Click += delegate { - MakeBoundsChangeUndoable(false); - foreach (var drawableContainer in this) { - var container = (DrawableContainer) drawableContainer; - if (!container.HasDefaultSize) { - continue; - } - Size defaultSize = container.DefaultSize; - container.MakeBoundsChangeUndoable(false); - container.Width = defaultSize.Width; - container.Height = defaultSize.Height; - } - surface.Invalidate(); - }; - menu.Items.Add(item); - } - } + // Reset + bool canReset = false; + foreach (var drawableContainer in this) + { + var container = (DrawableContainer) drawableContainer; + if (container.HasDefaultSize) + { + canReset = true; + } + } - public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface) - { - if (!(iSurface is Surface surface)) - { - return; - } - bool hasMenu = false; - foreach (var drawableContainer in this) { - var container = (DrawableContainer) drawableContainer; - if (!container.HasContextMenu) { - continue; - } - hasMenu = true; - break; - } - if (hasMenu) { - ContextMenuStrip menu = new ContextMenuStrip(); - AddContextMenuItems(menu, surface); - if (menu.Items.Count > 0) { - menu.Show(surface, surface.ToSurfaceCoordinates(e.Location)); - while (true) { - if (menu.Visible) { - Application.DoEvents(); - Thread.Sleep(100); - } else { - menu.Dispose(); - break; - } - } - } - } - } + if (canReset) + { + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_resetsize)); + //item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("removeObjectToolStripMenuItem.Image"))); + item.Click += delegate + { + MakeBoundsChangeUndoable(false); + foreach (var drawableContainer in this) + { + var container = (DrawableContainer) drawableContainer; + if (!container.HasDefaultSize) + { + continue; + } + + Size defaultSize = container.DefaultSize; + container.MakeBoundsChangeUndoable(false); + container.Width = defaultSize.Width; + container.Height = defaultSize.Height; + } + + surface.Invalidate(); + }; + menu.Items.Add(item); + } + } + + public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface) + { + if (!(iSurface is Surface surface)) + { + return; + } + + bool hasMenu = false; + foreach (var drawableContainer in this) + { + var container = (DrawableContainer) drawableContainer; + if (!container.HasContextMenu) + { + continue; + } + + hasMenu = true; + break; + } + + if (hasMenu) + { + ContextMenuStrip menu = new ContextMenuStrip(); + AddContextMenuItems(menu, surface); + if (menu.Items.Count > 0) + { + menu.Show(surface, surface.ToSurfaceCoordinates(e.Location)); + while (true) + { + if (menu.Visible) + { + Application.DoEvents(); + Thread.Sleep(100); + } + else + { + menu.Dispose(); + break; + } + } + } + } + } private bool _disposedValue; // To detect redundant calls - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - foreach (var drawableContainer in this) - { - drawableContainer.Dispose(); - } - } + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + foreach (var drawableContainer in this) + { + drawableContainer.Dispose(); + } + } - _disposedValue = true; - } - } + _disposedValue = true; + } + } - // This code added to correctly implement the disposable pattern. - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - } + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + } - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// - public void AdjustToDpi(uint dpi) - { - foreach (var drawableContainer in this) { - drawableContainer.AdjustToDpi(dpi); - } - } - } -} + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// + public void AdjustToDpi(uint dpi) + { + foreach (var drawableContainer in this) + { + drawableContainer.AdjustToDpi(dpi); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/EllipseContainer.cs b/src/Greenshot/Drawing/EllipseContainer.cs index b7d03ecfe..091c03b17 100644 --- a/src/Greenshot/Drawing/EllipseContainer.cs +++ b/src/Greenshot/Drawing/EllipseContainer.cs @@ -18,64 +18,71 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Drawing.Drawing2D; - using Greenshot.Drawing.Fields; using Greenshot.Helpers; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Description of EllipseContainer. - /// - [Serializable()] - public class EllipseContainer : DrawableContainer { - public EllipseContainer(Surface parent) : base(parent) { - CreateDefaultAdorners(); - } +namespace Greenshot.Drawing +{ + /// + /// Description of EllipseContainer. + /// + [Serializable()] + public class EllipseContainer : DrawableContainer + { + public EllipseContainer(Surface parent) : base(parent) + { + CreateDefaultAdorners(); + } - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, true); - } + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); + AddField(GetType(), FieldType.SHADOW, true); + } - public override void Draw(Graphics graphics, RenderMode renderMode) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - DrawEllipse(rect, graphics, renderMode, lineThickness, lineColor, fillColor, shadow); - } + public override void Draw(Graphics graphics, RenderMode renderMode) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; - /// - /// This allows another container to draw an ellipse - /// - /// - /// - /// - /// - /// - /// - /// - public static void DrawEllipse(Rectangle rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow) { - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - // draw shadow before anything else - if (shadow && (lineVisible || Colors.IsVisible(fillColor))) { - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = lineVisible ? 1 : 0; - while (currentStep <= steps) + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + DrawEllipse(rect, graphics, renderMode, lineThickness, lineColor, fillColor, shadow); + } + + /// + /// This allows another container to draw an ellipse + /// + /// + /// + /// + /// + /// + /// + /// + public static void DrawEllipse(Rectangle rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow) + { + bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); + // draw shadow before anything else + if (shadow && (lineVisible || Colors.IsVisible(fillColor))) + { + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = lineVisible ? 1 : 0; + while (currentStep <= steps) { using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)) { @@ -86,63 +93,71 @@ namespace Greenshot.Drawing { currentStep++; alpha -= basealpha / steps; } - } - //draw the original shape - if (Colors.IsVisible(fillColor)) + } + + //draw the original shape + if (Colors.IsVisible(fillColor)) { using Brush brush = new SolidBrush(fillColor); graphics.FillEllipse(brush, rect); } - if (lineVisible) + + if (lineVisible) { using Pen pen = new Pen(lineColor, lineThickness); graphics.DrawEllipse(pen, rect); } - } - - public override bool Contains(int x, int y) { - return EllipseContains(this, x, y); - } + } - /// - /// Allow the code to be used externally - /// - /// - /// - /// - /// - public static bool EllipseContains(DrawableContainer caller, int x, int y) { - double xDistanceFromCenter = x - (caller.Left + caller.Width / 2); - double yDistanceFromCenter = y - (caller.Top + caller.Height / 2); - // ellipse: x^2/a^2 + y^2/b^2 = 1 - return Math.Pow(xDistanceFromCenter, 2) / Math.Pow(caller.Width / 2, 2) + Math.Pow(yDistanceFromCenter, 2) / Math.Pow(caller.Height / 2, 2) < 1; - } + public override bool Contains(int x, int y) + { + return EllipseContains(this, x, y); + } - public override bool ClickableAt(int x, int y) { + /// + /// Allow the code to be used externally + /// + /// + /// + /// + /// + public static bool EllipseContains(DrawableContainer caller, int x, int y) + { + double xDistanceFromCenter = x - (caller.Left + caller.Width / 2); + double yDistanceFromCenter = y - (caller.Top + caller.Height / 2); + // ellipse: x^2/a^2 + y^2/b^2 = 1 + return Math.Pow(xDistanceFromCenter, 2) / Math.Pow(caller.Width / 2, 2) + Math.Pow(yDistanceFromCenter, 2) / Math.Pow(caller.Height / 2, 2) < 1; + } - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - return EllipseClickableAt(rect, lineThickness, fillColor, x, y); - } + public override bool ClickableAt(int x, int y) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + return EllipseClickableAt(rect, lineThickness, fillColor, x, y); + } - public static bool EllipseClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) { - // If we clicked inside the rectangle and it's visible we are clickable at. - if (!Color.Transparent.Equals(fillColor)) { - if (rect.Contains(x, y)) { - return true; - } - } + public static bool EllipseClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) + { + // If we clicked inside the rectangle and it's visible we are clickable at. + if (!Color.Transparent.Equals(fillColor)) + { + if (rect.Contains(x, y)) + { + return true; + } + } - // check the rest of the lines - if (lineThickness > 0) + // check the rest of the lines + if (lineThickness > 0) { using Pen pen = new Pen(Color.White, lineThickness); using GraphicsPath path = new GraphicsPath(); path.AddEllipse(rect); return path.IsOutlineVisible(x, y, pen); } - return false; - } - } -} + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs index 48dfd95f9..f4bc0377f 100644 --- a/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs +++ b/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs @@ -18,12 +18,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Runtime.Serialization; - using Greenshot.Configuration; using GreenshotPlugin.IniFile; using log4net; @@ -31,170 +31,162 @@ using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing.Fields { - /// - /// Basic IFieldHolder implementation, providing access to a set of fields - /// - [Serializable] - public abstract class AbstractFieldHolder : IFieldHolder - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(AbstractFieldHolder)); - private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - [NonSerialized] - private readonly IDictionary _handlers = new Dictionary(); + /// + /// Basic IFieldHolder implementation, providing access to a set of fields + /// + [Serializable] + public abstract class AbstractFieldHolder : IFieldHolder + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(AbstractFieldHolder)); + private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); + [NonSerialized] private readonly IDictionary _handlers = new Dictionary(); - /// - /// called when a field's value has changed - /// - [NonSerialized] - private FieldChangedEventHandler _fieldChanged; + /// + /// called when a field's value has changed + /// + [NonSerialized] private FieldChangedEventHandler _fieldChanged; - public event FieldChangedEventHandler FieldChanged - { - add { _fieldChanged += value; } - remove { _fieldChanged -= value; } - } + public event FieldChangedEventHandler FieldChanged + { + add { _fieldChanged += value; } + remove { _fieldChanged -= value; } + } - // we keep two Collections of our fields, dictionary for quick access, list for serialization - // this allows us to use default serialization - [NonSerialized] - private IDictionary _fieldsByType = new Dictionary(); - private readonly IList fields = new List(); + // we keep two Collections of our fields, dictionary for quick access, list for serialization + // this allows us to use default serialization + [NonSerialized] private IDictionary _fieldsByType = new Dictionary(); + private readonly IList fields = new List(); - [OnDeserialized] - private void OnDeserialized(StreamingContext context) - { - _fieldsByType = new Dictionary(); - // listen to changing properties - foreach (var field in fields) - { - field.PropertyChanged += delegate { - _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); - }; - _fieldsByType[field.FieldType] = field; - } - } + [OnDeserialized] + private void OnDeserialized(StreamingContext context) + { + _fieldsByType = new Dictionary(); + // listen to changing properties + foreach (var field in fields) + { + field.PropertyChanged += delegate { _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); }; + _fieldsByType[field.FieldType] = field; + } + } - public void AddField(Type requestingType, IFieldType fieldType, object fieldValue) - { - AddField(EditorConfig.CreateField(requestingType, fieldType, fieldValue)); - } + public void AddField(Type requestingType, IFieldType fieldType, object fieldValue) + { + AddField(EditorConfig.CreateField(requestingType, fieldType, fieldValue)); + } - public virtual void AddField(IField field) - { - fields.Add(field); - if (_fieldsByType == null) - { - return; - } + public virtual void AddField(IField field) + { + fields.Add(field); + if (_fieldsByType == null) + { + return; + } - if (_fieldsByType.ContainsKey(field.FieldType)) - { - if (LOG.IsDebugEnabled) - { - LOG.DebugFormat("A field with of type '{0}' already exists in this {1}, will overwrite.", field.FieldType, GetType()); - } - } + if (_fieldsByType.ContainsKey(field.FieldType)) + { + if (LOG.IsDebugEnabled) + { + LOG.DebugFormat("A field with of type '{0}' already exists in this {1}, will overwrite.", field.FieldType, GetType()); + } + } - _fieldsByType[field.FieldType] = field; + _fieldsByType[field.FieldType] = field; - _handlers[field] = (sender, args) => - { - _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); - }; - field.PropertyChanged += _handlers[field]; - } + _handlers[field] = (sender, args) => { _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); }; + field.PropertyChanged += _handlers[field]; + } - public void RemoveField(IField field) - { - fields.Remove(field); - _fieldsByType.Remove(field.FieldType); - field.PropertyChanged -= _handlers[field]; - _handlers.Remove(field); - } + public void RemoveField(IField field) + { + fields.Remove(field); + _fieldsByType.Remove(field.FieldType); + field.PropertyChanged -= _handlers[field]; + _handlers.Remove(field); + } - public IList GetFields() - { - return fields; - } + public IList GetFields() + { + return fields; + } - public IField GetField(IFieldType fieldType) - { - try - { - return _fieldsByType[fieldType]; - } - catch (KeyNotFoundException e) - { - throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); - } - } + public IField GetField(IFieldType fieldType) + { + try + { + return _fieldsByType[fieldType]; + } + catch (KeyNotFoundException e) + { + throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); + } + } - public object GetFieldValue(IFieldType fieldType) - { - return GetField(fieldType)?.Value; - } + public object GetFieldValue(IFieldType fieldType) + { + return GetField(fieldType)?.Value; + } public string GetFieldValueAsString(IFieldType fieldType) - { - return Convert.ToString(GetFieldValue(fieldType)); - } + { + return Convert.ToString(GetFieldValue(fieldType)); + } - public int GetFieldValueAsInt(IFieldType fieldType) - { - return Convert.ToInt32(GetFieldValue(fieldType)); - } + public int GetFieldValueAsInt(IFieldType fieldType) + { + return Convert.ToInt32(GetFieldValue(fieldType)); + } - public decimal GetFieldValueAsDecimal(IFieldType fieldType) - { - return Convert.ToDecimal(GetFieldValue(fieldType)); - } + public decimal GetFieldValueAsDecimal(IFieldType fieldType) + { + return Convert.ToDecimal(GetFieldValue(fieldType)); + } - public double GetFieldValueAsDouble(IFieldType fieldType) - { - return Convert.ToDouble(GetFieldValue(fieldType)); - } + public double GetFieldValueAsDouble(IFieldType fieldType) + { + return Convert.ToDouble(GetFieldValue(fieldType)); + } - public float GetFieldValueAsFloat(IFieldType fieldType) - { - return Convert.ToSingle(GetFieldValue(fieldType)); - } + public float GetFieldValueAsFloat(IFieldType fieldType) + { + return Convert.ToSingle(GetFieldValue(fieldType)); + } - public bool GetFieldValueAsBool(IFieldType fieldType) - { - return Convert.ToBoolean(GetFieldValue(fieldType)); - } + public bool GetFieldValueAsBool(IFieldType fieldType) + { + return Convert.ToBoolean(GetFieldValue(fieldType)); + } - public Color GetFieldValueAsColor(IFieldType fieldType, Color defaultColor = default) - { - return (Color)(GetFieldValue(fieldType) ?? defaultColor); - } + public Color GetFieldValueAsColor(IFieldType fieldType, Color defaultColor = default) + { + return (Color) (GetFieldValue(fieldType) ?? defaultColor); + } public bool HasField(IFieldType fieldType) - { - return _fieldsByType.ContainsKey(fieldType); - } + { + return _fieldsByType.ContainsKey(fieldType); + } - public bool HasFieldValue(IFieldType fieldType) - { - return HasField(fieldType) && _fieldsByType[fieldType].HasValue; - } + public bool HasFieldValue(IFieldType fieldType) + { + return HasField(fieldType) && _fieldsByType[fieldType].HasValue; + } - public void SetFieldValue(IFieldType fieldType, object value) - { - try - { - _fieldsByType[fieldType].Value = value; - } - catch (KeyNotFoundException e) - { - throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); - } - } + public void SetFieldValue(IFieldType fieldType, object value) + { + try + { + _fieldsByType[fieldType].Value = value; + } + catch (KeyNotFoundException e) + { + throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); + } + } - protected void OnFieldChanged(object sender, FieldChangedEventArgs e) - { - _fieldChanged?.Invoke(sender, e); - } - } -} + protected void OnFieldChanged(object sender, FieldChangedEventArgs e) + { + _fieldChanged?.Invoke(sender, e); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs index bb6ae068c..979a80168 100644 --- a/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs +++ b/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs @@ -26,121 +26,124 @@ using System.Runtime.Serialization; namespace Greenshot.Drawing.Fields { - /// - /// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder, - /// but has a List of IFieldHolder for children. - /// Field values are passed to and from children as well. - /// - [Serializable] - public abstract class AbstractFieldHolderWithChildren : AbstractFieldHolder - { - [NonSerialized] - private readonly FieldChangedEventHandler _fieldChangedEventHandler; + /// + /// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder, + /// but has a List of IFieldHolder for children. + /// Field values are passed to and from children as well. + /// + [Serializable] + public abstract class AbstractFieldHolderWithChildren : AbstractFieldHolder + { + [NonSerialized] private readonly FieldChangedEventHandler _fieldChangedEventHandler; - [NonSerialized] - private EventHandler childrenChanged; - public event EventHandler ChildrenChanged - { - add { childrenChanged += value; } - remove { childrenChanged -= value; } - } + [NonSerialized] private EventHandler childrenChanged; - public IList Children = new List(); + public event EventHandler ChildrenChanged + { + add { childrenChanged += value; } + remove { childrenChanged -= value; } + } - public AbstractFieldHolderWithChildren() - { - _fieldChangedEventHandler = OnFieldChanged; - } + public IList Children = new List(); - [OnDeserialized()] - private void OnDeserialized(StreamingContext context) - { - // listen to changing properties - foreach (IFieldHolder fieldHolder in Children) - { - fieldHolder.FieldChanged += _fieldChangedEventHandler; - } - childrenChanged?.Invoke(this, EventArgs.Empty); - } + public AbstractFieldHolderWithChildren() + { + _fieldChangedEventHandler = OnFieldChanged; + } - public void AddChild(IFieldHolder fieldHolder) - { - Children.Add(fieldHolder); - fieldHolder.FieldChanged += _fieldChangedEventHandler; - childrenChanged?.Invoke(this, EventArgs.Empty); - } + [OnDeserialized()] + private void OnDeserialized(StreamingContext context) + { + // listen to changing properties + foreach (IFieldHolder fieldHolder in Children) + { + fieldHolder.FieldChanged += _fieldChangedEventHandler; + } - public void RemoveChild(IFieldHolder fieldHolder) - { - Children.Remove(fieldHolder); - fieldHolder.FieldChanged -= _fieldChangedEventHandler; - childrenChanged?.Invoke(this, EventArgs.Empty); - } + childrenChanged?.Invoke(this, EventArgs.Empty); + } - public new IList GetFields() - { - var ret = new List(); - ret.AddRange(base.GetFields()); - foreach (IFieldHolder fh in Children) - { - ret.AddRange(fh.GetFields()); - } - return ret; - } + public void AddChild(IFieldHolder fieldHolder) + { + Children.Add(fieldHolder); + fieldHolder.FieldChanged += _fieldChangedEventHandler; + childrenChanged?.Invoke(this, EventArgs.Empty); + } - public new IField GetField(IFieldType fieldType) - { - IField ret = null; - if (base.HasField(fieldType)) - { - ret = base.GetField(fieldType); - } - else - { - foreach (IFieldHolder fh in Children) - { - if (fh.HasField(fieldType)) - { - ret = fh.GetField(fieldType); - break; - } - } - } - if (ret == null) - { - throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType()); - } - return ret; - } + public void RemoveChild(IFieldHolder fieldHolder) + { + Children.Remove(fieldHolder); + fieldHolder.FieldChanged -= _fieldChangedEventHandler; + childrenChanged?.Invoke(this, EventArgs.Empty); + } - public new bool HasField(IFieldType fieldType) - { - bool ret = base.HasField(fieldType); - if (!ret) - { - foreach (IFieldHolder fh in Children) - { - if (fh.HasField(fieldType)) - { - ret = true; - break; - } - } - } - return ret; - } + public new IList GetFields() + { + var ret = new List(); + ret.AddRange(base.GetFields()); + foreach (IFieldHolder fh in Children) + { + ret.AddRange(fh.GetFields()); + } - public new bool HasFieldValue(IFieldType fieldType) - { - IField f = GetField(fieldType); - return f != null && f.HasValue; - } + return ret; + } - public new void SetFieldValue(IFieldType fieldType, object value) - { - IField f = GetField(fieldType); - if (f != null) f.Value = value; - } + public new IField GetField(IFieldType fieldType) + { + IField ret = null; + if (base.HasField(fieldType)) + { + ret = base.GetField(fieldType); + } + else + { + foreach (IFieldHolder fh in Children) + { + if (fh.HasField(fieldType)) + { + ret = fh.GetField(fieldType); + break; + } + } + } - } -} + if (ret == null) + { + throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType()); + } + + return ret; + } + + public new bool HasField(IFieldType fieldType) + { + bool ret = base.HasField(fieldType); + if (!ret) + { + foreach (IFieldHolder fh in Children) + { + if (fh.HasField(fieldType)) + { + ret = true; + break; + } + } + } + + return ret; + } + + public new bool HasFieldValue(IFieldType fieldType) + { + IField f = GetField(fieldType); + return f != null && f.HasValue; + } + + public new void SetFieldValue(IFieldType fieldType, object value) + { + IField f = GetField(fieldType); + if (f != null) f.Value = value; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs b/src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs index a1ffd80c1..9870db505 100644 --- a/src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs +++ b/src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs @@ -18,29 +18,37 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Basic IBindingConverter implementation - /// - public abstract class AbstractBindingConverter : IBindingConverter - { - public object convert(object o) { - if(o == null) { - return null; - } - if(o is T1) { - return convert((T1)o); - } - if(o is T2) { - return convert((T2)o); - } - throw new ArgumentException("Cannot handle argument of type "+o.GetType()); - } +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Basic IBindingConverter implementation + /// + public abstract class AbstractBindingConverter : IBindingConverter + { + public object convert(object o) + { + if (o == null) + { + return null; + } - protected abstract T2 convert(T1 o); - protected abstract T1 convert(T2 o); - - } -} + if (o is T1) + { + return convert((T1) o); + } + + if (o is T2) + { + return convert((T2) o); + } + + throw new ArgumentException("Cannot handle argument of type " + o.GetType()); + } + + protected abstract T2 convert(T1 o); + protected abstract T1 convert(T2 o); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs b/src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs index 5a9652d5c..d9a69140d 100644 --- a/src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs +++ b/src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs @@ -18,141 +18,167 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Reflection; -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Bidirectional binding of properties of two INotifyPropertyChanged instances. - /// This implementation synchronizes null values, too. If you do not want this - /// behavior (e.g. when binding to a - /// - public class BidirectionalBinding { - private readonly INotifyPropertyChanged _controlObject; - private readonly INotifyPropertyChanged _fieldObject; - private readonly string _controlPropertyName; - private readonly string _fieldPropertyName; - private bool _updatingControl; - private bool _updatingField; - private IBindingConverter _converter; - private readonly IBindingValidator _validator; - - /// - /// Whether or not null values are passed on to the other object. - /// - protected bool AllowSynchronizeNull = true; +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Bidirectional binding of properties of two INotifyPropertyChanged instances. + /// This implementation synchronizes null values, too. If you do not want this + /// behavior (e.g. when binding to a + /// + public class BidirectionalBinding + { + private readonly INotifyPropertyChanged _controlObject; + private readonly INotifyPropertyChanged _fieldObject; + private readonly string _controlPropertyName; + private readonly string _fieldPropertyName; + private bool _updatingControl; + private bool _updatingField; + private IBindingConverter _converter; + private readonly IBindingValidator _validator; - /// - /// Bind properties of two objects bidirectionally - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName) { - _controlObject = controlObject; - _fieldObject = fieldObject; - _controlPropertyName = controlPropertyName; - _fieldPropertyName = fieldPropertyName; - - _controlObject.PropertyChanged += ControlPropertyChanged; - _fieldObject.PropertyChanged += FieldPropertyChanged; - } - - /// - /// Bind properties of two objects bidirectionally, converting the values using a converter - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - /// taking care of converting the synchronized value to the correct target format and back - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingConverter converter) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) { - _converter = converter; - } - - /// - /// Bind properties of two objects bidirectionally, converting the values using a converter. - /// Synchronization can be intercepted by adding a validator. - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - /// validator to intercept synchronization if the value does not match certain criteria - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) { - _validator = validator; - } - - /// - /// Bind properties of two objects bidirectionally, converting the values using a converter. - /// Synchronization can be intercepted by adding a validator. - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - /// taking care of converting the synchronized value to the correct target format and back - /// validator to intercept synchronization if the value does not match certain criteria - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingConverter converter, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName, converter) { - _validator = validator; - } - - public void ControlPropertyChanged(object sender, PropertyChangedEventArgs e) { - if (!_updatingControl && e.PropertyName.Equals(_controlPropertyName)) { - _updatingField = true; - Synchronize(_controlObject, _controlPropertyName, _fieldObject, _fieldPropertyName); - _updatingField = false; - } - } - - public void FieldPropertyChanged(object sender, PropertyChangedEventArgs e) { - if (!_updatingField && e.PropertyName.Equals(_fieldPropertyName)) { - _updatingControl = true; - Synchronize(_fieldObject, _fieldPropertyName, _controlObject, _controlPropertyName); - _updatingControl = false; - } - } - - private void Synchronize(INotifyPropertyChanged sourceObject, string sourceProperty, INotifyPropertyChanged targetObject, string targetProperty) { - PropertyInfo targetPropertyInfo = ResolvePropertyInfo(targetObject, targetProperty); - PropertyInfo sourcePropertyInfo = ResolvePropertyInfo(sourceObject, sourceProperty); - - if (sourcePropertyInfo != null && targetPropertyInfo != null && targetPropertyInfo.CanWrite) { - object bValue = sourcePropertyInfo.GetValue(sourceObject, null); - if (_converter != null && bValue != null) { - bValue = _converter.convert(bValue); - } - try { - if (_validator == null || _validator.validate(bValue)) { - targetPropertyInfo.SetValue(targetObject, bValue, null); - } - } catch (Exception e) { - throw new MemberAccessException("Could not set property '"+targetProperty+"' to '"+bValue+"' ["+(bValue?.GetType().Name ?? string.Empty)+"] on "+targetObject+". Probably other type than expected, IBindingCoverter to the rescue.", e); - } - - } - } - - private static PropertyInfo ResolvePropertyInfo(object obj, string property) { - PropertyInfo ret = null; - string[] properties = property.Split(".".ToCharArray()); - for(int i=0; i + /// Whether or not null values are passed on to the other object. + ///
+ protected bool AllowSynchronizeNull = true; + + /// + /// Bind properties of two objects bidirectionally + /// + /// Object containing 1st property to bind + /// Property of 1st object to bind + /// Object containing 2nd property to bind + /// Property of 2nd object to bind + public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName) + { + _controlObject = controlObject; + _fieldObject = fieldObject; + _controlPropertyName = controlPropertyName; + _fieldPropertyName = fieldPropertyName; + + _controlObject.PropertyChanged += ControlPropertyChanged; + _fieldObject.PropertyChanged += FieldPropertyChanged; + } + + /// + /// Bind properties of two objects bidirectionally, converting the values using a converter + /// + /// Object containing 1st property to bind + /// Property of 1st object to bind + /// Object containing 2nd property to bind + /// Property of 2nd object to bind + /// taking care of converting the synchronized value to the correct target format and back + public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, + IBindingConverter converter) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) + { + _converter = converter; + } + + /// + /// Bind properties of two objects bidirectionally, converting the values using a converter. + /// Synchronization can be intercepted by adding a validator. + /// + /// Object containing 1st property to bind + /// Property of 1st object to bind + /// Object containing 2nd property to bind + /// Property of 2nd object to bind + /// validator to intercept synchronization if the value does not match certain criteria + public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, + IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) + { + _validator = validator; + } + + /// + /// Bind properties of two objects bidirectionally, converting the values using a converter. + /// Synchronization can be intercepted by adding a validator. + /// + /// Object containing 1st property to bind + /// Property of 1st object to bind + /// Object containing 2nd property to bind + /// Property of 2nd object to bind + /// taking care of converting the synchronized value to the correct target format and back + /// validator to intercept synchronization if the value does not match certain criteria + public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, + IBindingConverter converter, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName, converter) + { + _validator = validator; + } + + public void ControlPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (!_updatingControl && e.PropertyName.Equals(_controlPropertyName)) + { + _updatingField = true; + Synchronize(_controlObject, _controlPropertyName, _fieldObject, _fieldPropertyName); + _updatingField = false; + } + } + + public void FieldPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (!_updatingField && e.PropertyName.Equals(_fieldPropertyName)) + { + _updatingControl = true; + Synchronize(_fieldObject, _fieldPropertyName, _controlObject, _controlPropertyName); + _updatingControl = false; + } + } + + private void Synchronize(INotifyPropertyChanged sourceObject, string sourceProperty, INotifyPropertyChanged targetObject, string targetProperty) + { + PropertyInfo targetPropertyInfo = ResolvePropertyInfo(targetObject, targetProperty); + PropertyInfo sourcePropertyInfo = ResolvePropertyInfo(sourceObject, sourceProperty); + + if (sourcePropertyInfo != null && targetPropertyInfo != null && targetPropertyInfo.CanWrite) + { + object bValue = sourcePropertyInfo.GetValue(sourceObject, null); + if (_converter != null && bValue != null) + { + bValue = _converter.convert(bValue); + } + + try + { + if (_validator == null || _validator.validate(bValue)) + { + targetPropertyInfo.SetValue(targetObject, bValue, null); + } + } + catch (Exception e) + { + throw new MemberAccessException( + "Could not set property '" + targetProperty + "' to '" + bValue + "' [" + (bValue?.GetType().Name ?? string.Empty) + "] on " + targetObject + + ". Probably other type than expected, IBindingCoverter to the rescue.", e); + } + } + } + + private static PropertyInfo ResolvePropertyInfo(object obj, string property) + { + PropertyInfo ret = null; + string[] properties = property.Split(".".ToCharArray()); + for (int i = 0; i < properties.Length; i++) + { + string prop = properties[i]; + ret = obj.GetType().GetProperty(prop); + if (ret != null && ret.CanRead && i < prop.Length - 1) + { + obj = ret.GetValue(obj, null); + } + } + + return ret; + } + + public IBindingConverter Converter + { + get { return _converter; } + set { _converter = value; } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs b/src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs index 0ac7d02bb..b7e1849f0 100644 --- a/src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs +++ b/src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs @@ -18,30 +18,35 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Converts decimal to double (%) and vice versa, e.g. 95f to 0.95d - /// - public class DecimalDoublePercentageConverter : AbstractBindingConverter - { - private static DecimalDoublePercentageConverter _uniqueInstance; - - private DecimalDoublePercentageConverter() {} - - protected override decimal convert(double o) { - return Convert.ToDecimal(o)*100; - } - - protected override double convert(decimal o) { - return Convert.ToDouble(o)/100; - } - - public static DecimalDoublePercentageConverter GetInstance() +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Converts decimal to double (%) and vice versa, e.g. 95f to 0.95d + /// + public class DecimalDoublePercentageConverter : AbstractBindingConverter + { + private static DecimalDoublePercentageConverter _uniqueInstance; + + private DecimalDoublePercentageConverter() + { + } + + protected override decimal convert(double o) + { + return Convert.ToDecimal(o) * 100; + } + + protected override double convert(decimal o) + { + return Convert.ToDouble(o) / 100; + } + + public static DecimalDoublePercentageConverter GetInstance() { return _uniqueInstance ??= new DecimalDoublePercentageConverter(); } - - } -} + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs b/src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs index 528af1c2e..0c2cbe5e5 100644 --- a/src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs +++ b/src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs @@ -18,30 +18,35 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Converts decimal to float and vice versa. - /// - public class DecimalFloatConverter : AbstractBindingConverter - { - private static DecimalFloatConverter _uniqueInstance; - - private DecimalFloatConverter() {} - - protected override decimal convert(float o) { - return Convert.ToDecimal(o); - } - - protected override float convert(decimal o) { - return Convert.ToSingle(o); - } - - public static DecimalFloatConverter GetInstance() - { - return _uniqueInstance ??= new DecimalFloatConverter(); - } - - } -} +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Converts decimal to float and vice versa. + /// + public class DecimalFloatConverter : AbstractBindingConverter + { + private static DecimalFloatConverter _uniqueInstance; + + private DecimalFloatConverter() + { + } + + protected override decimal convert(float o) + { + return Convert.ToDecimal(o); + } + + protected override float convert(decimal o) + { + return Convert.ToSingle(o); + } + + public static DecimalFloatConverter GetInstance() + { + return _uniqueInstance ??= new DecimalFloatConverter(); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs b/src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs index 6a8ff7e84..8e1b4e42f 100644 --- a/src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs +++ b/src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs @@ -18,30 +18,35 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Converts decimal to int and vice versa. - /// - public class DecimalIntConverter : AbstractBindingConverter - { - private static DecimalIntConverter _uniqueInstance; - - private DecimalIntConverter() {} - - protected override decimal convert(int o) { - return Convert.ToDecimal(o); - } - - protected override int convert(decimal o) { - return Convert.ToInt32(o); - } - - public static DecimalIntConverter GetInstance() - { - return _uniqueInstance ??= new DecimalIntConverter(); - } - - } -} +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Converts decimal to int and vice versa. + /// + public class DecimalIntConverter : AbstractBindingConverter + { + private static DecimalIntConverter _uniqueInstance; + + private DecimalIntConverter() + { + } + + protected override decimal convert(int o) + { + return Convert.ToDecimal(o); + } + + protected override int convert(decimal o) + { + return Convert.ToInt32(o); + } + + public static DecimalIntConverter GetInstance() + { + return _uniqueInstance ??= new DecimalIntConverter(); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs b/src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs index cdb573470..9c45dd044 100644 --- a/src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs +++ b/src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs @@ -19,15 +19,15 @@ * along with this program. If not, see . */ -namespace Greenshot.Drawing.Fields.Binding { - - /// - /// Interface for a bidirectional converter, for use with BidirectionalBinding. - /// convert(object) implementation must deal with both directions. - /// see DecimalIntConverter - /// - public interface IBindingConverter { - object convert(object o); - } - -} +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Interface for a bidirectional converter, for use with BidirectionalBinding. + /// convert(object) implementation must deal with both directions. + /// see DecimalIntConverter + /// + public interface IBindingConverter + { + object convert(object o); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs b/src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs index d21b575a4..6406e80ab 100644 --- a/src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs +++ b/src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs @@ -19,16 +19,16 @@ * along with this program. If not, see . */ -namespace Greenshot.Drawing.Fields.Binding { - - /// - /// Interface for a bidirectional validator, for use with BidirectionalBinding. - /// Useful if you do not want to synchronize values which would be illegal on - /// one of the bound objects (e.g. null value on some form components) - /// see NotNullValidator - /// - public interface IBindingValidator { - bool validate(object o); - } - -} +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Interface for a bidirectional validator, for use with BidirectionalBinding. + /// Useful if you do not want to synchronize values which would be illegal on + /// one of the bound objects (e.g. null value on some form components) + /// see NotNullValidator + /// + public interface IBindingValidator + { + bool validate(object o); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs b/src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs index 5d15b6699..e2089ab05 100644 --- a/src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs +++ b/src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs @@ -19,23 +19,27 @@ * along with this program. If not, see . */ -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Validates a value not to be null. - /// - public class NotNullValidator : IBindingValidator { - private static NotNullValidator _uniqueInstance; - - private NotNullValidator() { - } - - public bool validate(object o) { - return o != null; - } - - public static NotNullValidator GetInstance() +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Validates a value not to be null. + /// + public class NotNullValidator : IBindingValidator + { + private static NotNullValidator _uniqueInstance; + + private NotNullValidator() + { + } + + public bool validate(object o) + { + return o != null; + } + + public static NotNullValidator GetInstance() { return _uniqueInstance ??= new NotNullValidator(); } - } -} + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Field.cs b/src/Greenshot/Drawing/Fields/Field.cs index f08033fd0..e58de2122 100644 --- a/src/Greenshot/Drawing/Fields/Field.cs +++ b/src/Greenshot/Drawing/Fields/Field.cs @@ -25,106 +25,104 @@ using System.ComponentModel; namespace Greenshot.Drawing.Fields { - /// - /// Represents a single field of a drawable element, i.e. - /// line thickness of a rectangle. - /// - [Serializable] - public class Field : IField - { - [field: NonSerialized] - public event PropertyChangedEventHandler PropertyChanged; + /// + /// Represents a single field of a drawable element, i.e. + /// line thickness of a rectangle. + /// + [Serializable] + public class Field : IField + { + [field: NonSerialized] public event PropertyChangedEventHandler PropertyChanged; - private object _myValue; - public object Value - { - get - { - return _myValue; - } - set - { - if (!Equals(_myValue, value)) - { - _myValue = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); - } - } - } - public IFieldType FieldType - { - get; - set; - } - public string Scope - { - get; - set; - } + private object _myValue; - /// - /// Constructs a new Field instance, usually you should be using FieldFactory - /// to create Fields. - /// - /// FieldType of the Field to be created - /// The scope to which the value of this Field is relevant. - /// Depending on the scope the Field's value may be shared for other elements - /// containing the same FieldType for defaulting to the last used value. - /// When scope is set to a Type (e.g. typeof(RectangleContainer)), its value - /// should not be reused for FieldHolders of another Type (e.g. typeof(EllipseContainer)) - /// - public Field(IFieldType fieldType, Type scope) - { - FieldType = fieldType; - Scope = scope.Name; - } - public Field(IFieldType fieldType, string scope) - { - FieldType = fieldType; - Scope = scope; - } - public Field(IFieldType fieldType) - { - FieldType = fieldType; - } - /// - /// Returns true if this field holds a value other than null. - /// - public bool HasValue => Value != null; + public object Value + { + get { return _myValue; } + set + { + if (!Equals(_myValue, value)) + { + _myValue = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); + } + } + } - /// - /// Creates a flat clone of this Field. The fields value itself is not cloned. - /// - /// - public Field Clone() - { - return new Field(FieldType, Scope) {Value = Value}; - } + public IFieldType FieldType { get; set; } + public string Scope { get; set; } - public override int GetHashCode() - { - int hashCode = 0; - unchecked - { - hashCode += 1000000009 * FieldType.GetHashCode(); - if (Scope != null) - hashCode += 1000000021 * Scope.GetHashCode(); - } - return hashCode; - } + /// + /// Constructs a new Field instance, usually you should be using FieldFactory + /// to create Fields. + /// + /// FieldType of the Field to be created + /// The scope to which the value of this Field is relevant. + /// Depending on the scope the Field's value may be shared for other elements + /// containing the same FieldType for defaulting to the last used value. + /// When scope is set to a Type (e.g. typeof(RectangleContainer)), its value + /// should not be reused for FieldHolders of another Type (e.g. typeof(EllipseContainer)) + /// + public Field(IFieldType fieldType, Type scope) + { + FieldType = fieldType; + Scope = scope.Name; + } - public override bool Equals(object obj) - { + public Field(IFieldType fieldType, string scope) + { + FieldType = fieldType; + Scope = scope; + } + + public Field(IFieldType fieldType) + { + FieldType = fieldType; + } + + /// + /// Returns true if this field holds a value other than null. + /// + public bool HasValue => Value != null; + + /// + /// Creates a flat clone of this Field. The fields value itself is not cloned. + /// + /// + public Field Clone() + { + return new Field(FieldType, Scope) + { + Value = Value + }; + } + + public override int GetHashCode() + { + int hashCode = 0; + unchecked + { + hashCode += 1000000009 * FieldType.GetHashCode(); + if (Scope != null) + hashCode += 1000000021 * Scope.GetHashCode(); + } + + return hashCode; + } + + public override bool Equals(object obj) + { if (!(obj is Field other)) - { - return false; - } - return FieldType == other.FieldType && Equals(Scope, other.Scope); - } + { + return false; + } - public override string ToString() - { - return string.Format("[Field FieldType={1} Value={0} Scope={2}]", _myValue, FieldType, Scope); - } - } -} + return FieldType == other.FieldType && Equals(Scope, other.Scope); + } + + public override string ToString() + { + return string.Format("[Field FieldType={1} Value={0} Scope={2}]", _myValue, FieldType, Scope); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/FieldAggregator.cs b/src/Greenshot/Drawing/Fields/FieldAggregator.cs index 6606a96b1..39f859503 100644 --- a/src/Greenshot/Drawing/Fields/FieldAggregator.cs +++ b/src/Greenshot/Drawing/Fields/FieldAggregator.cs @@ -30,146 +30,149 @@ using GreenshotPlugin.Interfaces; namespace Greenshot.Drawing.Fields { - /// - /// Represents the current set of properties for the editor. - /// When one of EditorProperties' properties is updated, the change will be promoted - /// to all bound elements. - /// * If an element is selected: - /// This class represents the element's properties - /// * I n>1 elements are selected: - /// This class represents the properties of all elements. - /// Properties that do not apply for ALL selected elements are null (or 0 respectively) - /// If the property values of the selected elements differ, the value of the last bound element wins. - /// - [Serializable] - public sealed class FieldAggregator : AbstractFieldHolder - { + /// + /// Represents the current set of properties for the editor. + /// When one of EditorProperties' properties is updated, the change will be promoted + /// to all bound elements. + /// * If an element is selected: + /// This class represents the element's properties + /// * I n>1 elements are selected: + /// This class represents the properties of all elements. + /// Properties that do not apply for ALL selected elements are null (or 0 respectively) + /// If the property values of the selected elements differ, the value of the last bound element wins. + /// + [Serializable] + public sealed class FieldAggregator : AbstractFieldHolder + { + private readonly IDrawableContainerList _boundContainers; + private bool _internalUpdateRunning; - private readonly IDrawableContainerList _boundContainers; - private bool _internalUpdateRunning; + private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); + public FieldAggregator(ISurface parent) + { + foreach (var fieldType in FieldType.Values) + { + var field = new Field(fieldType, GetType()); + AddField(field); + } - public FieldAggregator(ISurface parent) - { - foreach (var fieldType in FieldType.Values) - { - var field = new Field(fieldType, GetType()); - AddField(field); - } - _boundContainers = new DrawableContainerList - { - Parent = parent - }; - } + _boundContainers = new DrawableContainerList + { + Parent = parent + }; + } - public override void AddField(IField field) - { - base.AddField(field); - field.PropertyChanged += OwnPropertyChanged; - } + public override void AddField(IField field) + { + base.AddField(field); + field.PropertyChanged += OwnPropertyChanged; + } - public void BindElements(IDrawableContainerList dcs) - { - foreach (var dc in dcs) - { - BindElement(dc); - } - } + public void BindElements(IDrawableContainerList dcs) + { + foreach (var dc in dcs) + { + BindElement(dc); + } + } - public void BindElement(IDrawableContainer dc) - { + public void BindElement(IDrawableContainer dc) + { if (!(dc is DrawableContainer container) || _boundContainers.Contains(container)) - { - return; - } - _boundContainers.Add(container); - container.ChildrenChanged += delegate { - UpdateFromBoundElements(); - }; - UpdateFromBoundElements(); - } + { + return; + } - public void BindAndUpdateElement(IDrawableContainer dc) - { - UpdateElement(dc); - BindElement(dc); - } + _boundContainers.Add(container); + container.ChildrenChanged += delegate { UpdateFromBoundElements(); }; + UpdateFromBoundElements(); + } - public void UpdateElement(IDrawableContainer dc) - { + public void BindAndUpdateElement(IDrawableContainer dc) + { + UpdateElement(dc); + BindElement(dc); + } + + public void UpdateElement(IDrawableContainer dc) + { if (!(dc is DrawableContainer container)) - { - return; - } - _internalUpdateRunning = true; - foreach (var field in GetFields()) - { - if (container.HasField(field.FieldType) && field.HasValue) - { - //if(LOG.IsDebugEnabled) LOG.Debug(" "+field+ ": "+field.Value); - container.SetFieldValue(field.FieldType, field.Value); - } - } - _internalUpdateRunning = false; - } + { + return; + } - public void UnbindElement(IDrawableContainer dc) - { - if (_boundContainers.Contains(dc)) - { - _boundContainers.Remove(dc); - UpdateFromBoundElements(); - } - } + _internalUpdateRunning = true; + foreach (var field in GetFields()) + { + if (container.HasField(field.FieldType) && field.HasValue) + { + //if(LOG.IsDebugEnabled) LOG.Debug(" "+field+ ": "+field.Value); + container.SetFieldValue(field.FieldType, field.Value); + } + } - public void Clear() - { - ClearFields(); - _boundContainers.Clear(); - UpdateFromBoundElements(); - } + _internalUpdateRunning = false; + } - /// - /// sets all field values to null, however does not remove fields - /// - private void ClearFields() - { - _internalUpdateRunning = true; - foreach (var field in GetFields()) - { - field.Value = null; - } - _internalUpdateRunning = false; - } + public void UnbindElement(IDrawableContainer dc) + { + if (_boundContainers.Contains(dc)) + { + _boundContainers.Remove(dc); + UpdateFromBoundElements(); + } + } - /// - /// Updates this instance using the respective fields from the bound elements. - /// Fields that do not apply to every bound element are set to null, or 0 respectively. - /// All other fields will be set to the field value of the least bound element. - /// - private void UpdateFromBoundElements() - { - ClearFields(); - _internalUpdateRunning = true; - foreach (var field in FindCommonFields()) - { - SetFieldValue(field.FieldType, field.Value); - } - _internalUpdateRunning = false; - } + public void Clear() + { + ClearFields(); + _boundContainers.Clear(); + UpdateFromBoundElements(); + } - private IList FindCommonFields() - { - IList returnFields = null; - if (_boundContainers.Count > 0) - { - // take all fields from the least selected container... + /// + /// sets all field values to null, however does not remove fields + /// + private void ClearFields() + { + _internalUpdateRunning = true; + foreach (var field in GetFields()) + { + field.Value = null; + } + + _internalUpdateRunning = false; + } + + /// + /// Updates this instance using the respective fields from the bound elements. + /// Fields that do not apply to every bound element are set to null, or 0 respectively. + /// All other fields will be set to the field value of the least bound element. + /// + private void UpdateFromBoundElements() + { + ClearFields(); + _internalUpdateRunning = true; + foreach (var field in FindCommonFields()) + { + SetFieldValue(field.FieldType, field.Value); + } + + _internalUpdateRunning = false; + } + + private IList FindCommonFields() + { + IList returnFields = null; + if (_boundContainers.Count > 0) + { + // take all fields from the least selected container... if (_boundContainers[_boundContainers.Count - 1] is DrawableContainer leastSelectedContainer) - { - returnFields = leastSelectedContainer.GetFields(); - for (int i = 0; i < _boundContainers.Count - 1; i++) - { + { + returnFields = leastSelectedContainer.GetFields(); + for (int i = 0; i < _boundContainers.Count - 1; i++) + { if (!(_boundContainers[i] is DrawableContainer dc)) continue; IList fieldsToRemove = new List(); foreach (IField field in returnFields) @@ -180,39 +183,42 @@ namespace Greenshot.Drawing.Fields fieldsToRemove.Add(field); } } + foreach (var field in fieldsToRemove) { returnFields.Remove(field); } } - } - } - return returnFields ?? new List(); - } + } + } - public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea) - { - IField field = (IField)sender; - if (_internalUpdateRunning || field.Value == null) - { - return; - } - foreach (var drawableContainer1 in _boundContainers.ToList()) - { - var drawableContainer = (DrawableContainer) drawableContainer1; - if (!drawableContainer.HasField(field.FieldType)) - { - continue; - } - IField drawableContainerField = drawableContainer.GetField(field.FieldType); - // Notify before change, so we can e.g. invalidate the area - drawableContainer.BeforeFieldChange(drawableContainerField, field.Value); + return returnFields ?? new List(); + } - drawableContainerField.Value = field.Value; - // update last used from DC field, so that scope is honored - EditorConfig.UpdateLastFieldValue(drawableContainerField); - } - } + public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea) + { + IField field = (IField) sender; + if (_internalUpdateRunning || field.Value == null) + { + return; + } - } -} + foreach (var drawableContainer1 in _boundContainers.ToList()) + { + var drawableContainer = (DrawableContainer) drawableContainer1; + if (!drawableContainer.HasField(field.FieldType)) + { + continue; + } + + IField drawableContainerField = drawableContainer.GetField(field.FieldType); + // Notify before change, so we can e.g. invalidate the area + drawableContainer.BeforeFieldChange(drawableContainerField, field.Value); + + drawableContainerField.Value = field.Value; + // update last used from DC field, so that scope is honored + EditorConfig.UpdateLastFieldValue(drawableContainerField); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/FieldType.cs b/src/Greenshot/Drawing/Fields/FieldType.cs index 7531e5b27..3e6711898 100644 --- a/src/Greenshot/Drawing/Fields/FieldType.cs +++ b/src/Greenshot/Drawing/Fields/FieldType.cs @@ -18,106 +18,89 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using GreenshotPlugin.Interfaces.Drawing; using System; namespace Greenshot.Drawing.Fields { - /// - /// Defines all FieldTypes + their default value. - /// (The additional value is why this is not an enum) - /// - [Serializable] - public class FieldType : IFieldType - { + /// + /// Defines all FieldTypes + their default value. + /// (The additional value is why this is not an enum) + /// + [Serializable] + public class FieldType : IFieldType + { + public static readonly IFieldType ARROWHEADS = new FieldType("ARROWHEADS"); + public static readonly IFieldType BLUR_RADIUS = new FieldType("BLUR_RADIUS"); + public static readonly IFieldType BRIGHTNESS = new FieldType("BRIGHTNESS"); + public static readonly IFieldType FILL_COLOR = new FieldType("FILL_COLOR"); + public static readonly IFieldType FONT_BOLD = new FieldType("FONT_BOLD"); + public static readonly IFieldType FONT_FAMILY = new FieldType("FONT_FAMILY"); + public static readonly IFieldType FONT_ITALIC = new FieldType("FONT_ITALIC"); + public static readonly IFieldType FONT_SIZE = new FieldType("FONT_SIZE"); + public static readonly IFieldType TEXT_HORIZONTAL_ALIGNMENT = new FieldType("TEXT_HORIZONTAL_ALIGNMENT"); + public static readonly IFieldType TEXT_VERTICAL_ALIGNMENT = new FieldType("TEXT_VERTICAL_ALIGNMENT"); + public static readonly IFieldType HIGHLIGHT_COLOR = new FieldType("HIGHLIGHT_COLOR"); + public static readonly IFieldType LINE_COLOR = new FieldType("LINE_COLOR"); + public static readonly IFieldType LINE_THICKNESS = new FieldType("LINE_THICKNESS"); + public static readonly IFieldType MAGNIFICATION_FACTOR = new FieldType("MAGNIFICATION_FACTOR"); + public static readonly IFieldType PIXEL_SIZE = new FieldType("PIXEL_SIZE"); + public static readonly IFieldType PREVIEW_QUALITY = new FieldType("PREVIEW_QUALITY"); + public static readonly IFieldType SHADOW = new FieldType("SHADOW"); + public static readonly IFieldType PREPARED_FILTER_OBFUSCATE = new FieldType("PREPARED_FILTER_OBFUSCATE"); + public static readonly IFieldType PREPARED_FILTER_HIGHLIGHT = new FieldType("PREPARED_FILTER_HIGHLIGHT"); + public static readonly IFieldType FLAGS = new FieldType("FLAGS"); - public static readonly IFieldType ARROWHEADS = new FieldType("ARROWHEADS"); - public static readonly IFieldType BLUR_RADIUS = new FieldType("BLUR_RADIUS"); - public static readonly IFieldType BRIGHTNESS = new FieldType("BRIGHTNESS"); - public static readonly IFieldType FILL_COLOR = new FieldType("FILL_COLOR"); - public static readonly IFieldType FONT_BOLD = new FieldType("FONT_BOLD"); - public static readonly IFieldType FONT_FAMILY = new FieldType("FONT_FAMILY"); - public static readonly IFieldType FONT_ITALIC = new FieldType("FONT_ITALIC"); - public static readonly IFieldType FONT_SIZE = new FieldType("FONT_SIZE"); - public static readonly IFieldType TEXT_HORIZONTAL_ALIGNMENT = new FieldType("TEXT_HORIZONTAL_ALIGNMENT"); - public static readonly IFieldType TEXT_VERTICAL_ALIGNMENT = new FieldType("TEXT_VERTICAL_ALIGNMENT"); - public static readonly IFieldType HIGHLIGHT_COLOR = new FieldType("HIGHLIGHT_COLOR"); - public static readonly IFieldType LINE_COLOR = new FieldType("LINE_COLOR"); - public static readonly IFieldType LINE_THICKNESS = new FieldType("LINE_THICKNESS"); - public static readonly IFieldType MAGNIFICATION_FACTOR = new FieldType("MAGNIFICATION_FACTOR"); - public static readonly IFieldType PIXEL_SIZE = new FieldType("PIXEL_SIZE"); - public static readonly IFieldType PREVIEW_QUALITY = new FieldType("PREVIEW_QUALITY"); - public static readonly IFieldType SHADOW = new FieldType("SHADOW"); - public static readonly IFieldType PREPARED_FILTER_OBFUSCATE = new FieldType("PREPARED_FILTER_OBFUSCATE"); - public static readonly IFieldType PREPARED_FILTER_HIGHLIGHT = new FieldType("PREPARED_FILTER_HIGHLIGHT"); - public static readonly IFieldType FLAGS = new FieldType("FLAGS"); - - public static IFieldType[] Values = { - ARROWHEADS, - BLUR_RADIUS, - BRIGHTNESS, - FILL_COLOR, - FONT_BOLD, - FONT_FAMILY, - FONT_ITALIC, - FONT_SIZE, - TEXT_HORIZONTAL_ALIGNMENT, - TEXT_VERTICAL_ALIGNMENT, - HIGHLIGHT_COLOR, - LINE_COLOR, - LINE_THICKNESS, - MAGNIFICATION_FACTOR, - PIXEL_SIZE, - PREVIEW_QUALITY, - SHADOW, - PREPARED_FILTER_OBFUSCATE, - PREPARED_FILTER_HIGHLIGHT, - FLAGS - }; + public static IFieldType[] Values = + { + ARROWHEADS, BLUR_RADIUS, BRIGHTNESS, FILL_COLOR, FONT_BOLD, FONT_FAMILY, FONT_ITALIC, FONT_SIZE, TEXT_HORIZONTAL_ALIGNMENT, TEXT_VERTICAL_ALIGNMENT, HIGHLIGHT_COLOR, + LINE_COLOR, LINE_THICKNESS, MAGNIFICATION_FACTOR, PIXEL_SIZE, PREVIEW_QUALITY, SHADOW, PREPARED_FILTER_OBFUSCATE, PREPARED_FILTER_HIGHLIGHT, FLAGS + }; - public string Name - { - get; - set; - } + public string Name { get; set; } - private FieldType(string name) - { - Name = name; - } - public override string ToString() - { - return Name; - } - public override int GetHashCode() - { - int hashCode = 0; - unchecked - { - if (Name != null) - hashCode += 1000000009 * Name.GetHashCode(); - } - return hashCode; - } + private FieldType(string name) + { + Name = name; + } - public override bool Equals(object obj) - { - FieldType other = obj as FieldType; - if (other == null) - { - return false; - } - return Equals(Name, other.Name); - } + public override string ToString() + { + return Name; + } - public static bool operator ==(FieldType a, FieldType b) - { - return Equals(a, b); - } + public override int GetHashCode() + { + int hashCode = 0; + unchecked + { + if (Name != null) + hashCode += 1000000009 * Name.GetHashCode(); + } - public static bool operator !=(FieldType a, FieldType b) - { - return !Equals(a, b); - } - } -} + return hashCode; + } + + public override bool Equals(object obj) + { + FieldType other = obj as FieldType; + if (other == null) + { + return false; + } + + return Equals(Name, other.Name); + } + + public static bool operator ==(FieldType a, FieldType b) + { + return Equals(a, b); + } + + public static bool operator !=(FieldType a, FieldType b) + { + return !Equals(a, b); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/FilterContainer.cs b/src/Greenshot/Drawing/FilterContainer.cs index 631cbed33..93e3352c9 100644 --- a/src/Greenshot/Drawing/FilterContainer.cs +++ b/src/Greenshot/Drawing/FilterContainer.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using Greenshot.Drawing.Fields; @@ -26,54 +27,73 @@ using System.Drawing.Drawing2D; using System.Runtime.Serialization; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// empty container for filter-only elements - /// - [Serializable] - public abstract class FilterContainer : DrawableContainer { - - public enum PreparedFilterMode {OBFUSCATE, HIGHLIGHT}; - public enum PreparedFilter {BLUR, PIXELIZE, TEXT_HIGHTLIGHT, AREA_HIGHLIGHT, GRAYSCALE, MAGNIFICATION}; +namespace Greenshot.Drawing +{ + /// + /// empty container for filter-only elements + /// + [Serializable] + public abstract class FilterContainer : DrawableContainer + { + public enum PreparedFilterMode + { + OBFUSCATE, + HIGHLIGHT + }; - public FilterContainer(Surface parent) : base(parent) { - Init(); - } + public enum PreparedFilter + { + BLUR, + PIXELIZE, + TEXT_HIGHTLIGHT, + AREA_HIGHLIGHT, + GRAYSCALE, + MAGNIFICATION + }; - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } + public FilterContainer(Surface parent) : base(parent) + { + Init(); + } - private void Init() - { - CreateDefaultAdorners(); - } + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 0); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.SHADOW, false); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - if (lineVisible) { - graphics.SmoothingMode = SmoothingMode.HighSpeed; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - //draw shadow first - if (shadow) { - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = lineVisible ? 1 : 0; - while (currentStep <= steps) + private void Init() + { + CreateDefaultAdorners(); + } + + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 0); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + AddField(GetType(), FieldType.SHADOW, false); + } + + public override void Draw(Graphics graphics, RenderMode rm) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); + if (lineVisible) + { + graphics.SmoothingMode = SmoothingMode.HighSpeed; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + //draw shadow first + if (shadow) + { + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = lineVisible ? 1 : 0; + while (currentStep <= steps) { using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + currentStep, Top + currentStep, Width, Height); @@ -81,14 +101,15 @@ namespace Greenshot.Drawing { currentStep++; alpha -= basealpha / steps; } - } - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - if (lineThickness > 0) + } + + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + if (lineThickness > 0) { using Pen pen = new Pen(lineColor, lineThickness); graphics.DrawRectangle(pen, rect); } - } - } - } -} + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/AbstractFilter.cs b/src/Greenshot/Drawing/Filters/AbstractFilter.cs index 419038d40..1608fd866 100644 --- a/src/Greenshot/Drawing/Filters/AbstractFilter.cs +++ b/src/Greenshot/Drawing/Filters/AbstractFilter.cs @@ -18,63 +18,66 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Drawing; - using Greenshot.Drawing.Fields; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing.Filters { - /// - /// Graphical filter which can be added to DrawableContainer. - /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call - /// OnPropertyChanged whenever a public property has been changed. - /// - [Serializable] - public abstract class AbstractFilter : AbstractFieldHolder, IFilter { - - [NonSerialized] - private PropertyChangedEventHandler propertyChanged; - public event PropertyChangedEventHandler PropertyChanged { - add { propertyChanged += value; } - remove{ propertyChanged -= value; } - } - - private bool invert; - public bool Invert { - get { - return invert; - } - set { - invert = value; - OnPropertyChanged("Invert"); - } - } +namespace Greenshot.Drawing.Filters +{ + /// + /// Graphical filter which can be added to DrawableContainer. + /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call + /// OnPropertyChanged whenever a public property has been changed. + /// + [Serializable] + public abstract class AbstractFilter : AbstractFieldHolder, IFilter + { + [NonSerialized] private PropertyChangedEventHandler propertyChanged; - protected DrawableContainer parent; - public DrawableContainer Parent { - get { - return parent; - } - set { - parent = value; - } - } - - public AbstractFilter(DrawableContainer parent) { - this.parent = parent; - } - - public DrawableContainer GetParent() { - return parent; - } + public event PropertyChangedEventHandler PropertyChanged + { + add { propertyChanged += value; } + remove { propertyChanged -= value; } + } - public abstract void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode); - - protected void OnPropertyChanged(string propertyName) - { - propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - } -} + private bool invert; + + public bool Invert + { + get { return invert; } + set + { + invert = value; + OnPropertyChanged("Invert"); + } + } + + protected DrawableContainer parent; + + public DrawableContainer Parent + { + get { return parent; } + set { parent = value; } + } + + public AbstractFilter(DrawableContainer parent) + { + this.parent = parent; + } + + public DrawableContainer GetParent() + { + return parent; + } + + public abstract void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode); + + protected void OnPropertyChanged(string propertyName) + { + propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/BlurFilter.cs b/src/Greenshot/Drawing/Filters/BlurFilter.cs index 79f617ac6..9b8c5d0f9 100644 --- a/src/Greenshot/Drawing/Filters/BlurFilter.cs +++ b/src/Greenshot/Drawing/Filters/BlurFilter.cs @@ -27,40 +27,57 @@ using GreenshotPlugin.UnmanagedHelpers; using System.Drawing.Drawing2D; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing.Filters { - [Serializable] - public class BlurFilter : AbstractFilter { - public double previewQuality; - public double PreviewQuality { - get { return previewQuality; } - set { previewQuality = value; OnPropertyChanged("PreviewQuality"); } - } - - public BlurFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.BLUR_RADIUS, 3); - AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d); - } +namespace Greenshot.Drawing.Filters +{ + [Serializable] + public class BlurFilter : AbstractFilter + { + public double previewQuality; - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - if (applyRect.Width == 0 || applyRect.Height == 0) { - return; - } - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - if (GDIplus.IsBlurPossible(blurRadius)) { - GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false); - } else + public double PreviewQuality + { + get { return previewQuality; } + set + { + previewQuality = value; + OnPropertyChanged("PreviewQuality"); + } + } + + public BlurFilter(DrawableContainer parent) : base(parent) + { + AddField(GetType(), FieldType.BLUR_RADIUS, 3); + AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d); + } + + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); + Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + if (applyRect.Width == 0 || applyRect.Height == 0) + { + return; + } + + GraphicsState state = graphics.Save(); + if (Invert) + { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + + if (GDIplus.IsBlurPossible(blurRadius)) + { + GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false); + } + else { using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect); ImageHelper.ApplyBoxBlur(fastBitmap, blurRadius); fastBitmap.DrawTo(graphics, applyRect); } - graphics.Restore(state); - } - } -} + + graphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/BrightnessFilter.cs b/src/Greenshot/Drawing/Filters/BrightnessFilter.cs index a43a68f67..cba712bbe 100644 --- a/src/Greenshot/Drawing/Filters/BrightnessFilter.cs +++ b/src/Greenshot/Drawing/Filters/BrightnessFilter.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using Greenshot.Drawing.Fields; @@ -26,39 +27,47 @@ using System.Drawing.Imaging; using System.Drawing.Drawing2D; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing.Filters { - [Serializable()] - public class BrightnessFilter : AbstractFilter { - - public BrightnessFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.BRIGHTNESS, 0.9d); - } +namespace Greenshot.Drawing.Filters +{ + [Serializable()] + public class BrightnessFilter : AbstractFilter + { + public BrightnessFilter(DrawableContainer parent) : base(parent) + { + AddField(GetType(), FieldType.BRIGHTNESS, 0.9d); + } - /// - /// Implements the Apply code for the Brightness Filet - /// - /// - /// - /// - /// - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + /// + /// Implements the Apply code for the Brightness Filet + /// + /// + /// + /// + /// + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } + if (applyRect.Width == 0 || applyRect.Height == 0) + { + // nothing to do + return; + } - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - float brightness = GetFieldValueAsFloat(FieldType.BRIGHTNESS); - using (ImageAttributes ia = ImageHelper.CreateAdjustAttributes(brightness, 1f, 1f)) { - graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); - } - graphics.Restore(state); - } - } -} + GraphicsState state = graphics.Save(); + if (Invert) + { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + + float brightness = GetFieldValueAsFloat(FieldType.BRIGHTNESS); + using (ImageAttributes ia = ImageHelper.CreateAdjustAttributes(brightness, 1f, 1f)) + { + graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); + } + + graphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs index f66b29fba..2565999a9 100644 --- a/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs +++ b/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using GreenshotPlugin.Core; @@ -25,40 +26,65 @@ using System.Drawing.Drawing2D; using System.Drawing.Imaging; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing.Filters { - /// - /// Description of GrayscaleFilter. - /// - [Serializable()] - public class GrayscaleFilter : AbstractFilter { - public GrayscaleFilter(DrawableContainer parent) : base(parent) { - } +namespace Greenshot.Drawing.Filters +{ + /// + /// Description of GrayscaleFilter. + /// + [Serializable()] + public class GrayscaleFilter : AbstractFilter + { + public GrayscaleFilter(DrawableContainer parent) : base(parent) + { + } - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - ColorMatrix grayscaleMatrix = new ColorMatrix(new[] { - new[] {.3f, .3f, .3f, 0, 0}, - new[] {.59f, .59f, .59f, 0, 0}, - new[] {.11f, .11f, .11f, 0, 0}, - new float[] {0, 0, 0, 1, 0}, - new float[] {0, 0, 0, 0, 1} - }); - using (ImageAttributes ia = new ImageAttributes()) { - ia.SetColorMatrix(grayscaleMatrix); - graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); - } - graphics.Restore(state); + if (applyRect.Width == 0 || applyRect.Height == 0) + { + // nothing to do + return; + } - } - } -} + GraphicsState state = graphics.Save(); + if (Invert) + { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + + ColorMatrix grayscaleMatrix = new ColorMatrix(new[] + { + new[] + { + .3f, .3f, .3f, 0, 0 + }, + new[] + { + .59f, .59f, .59f, 0, 0 + }, + new[] + { + .11f, .11f, .11f, 0, 0 + }, + new float[] + { + 0, 0, 0, 1, 0 + }, + new float[] + { + 0, 0, 0, 0, 1 + } + }); + using (ImageAttributes ia = new ImageAttributes()) + { + ia.SetColorMatrix(grayscaleMatrix); + graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); + } + + graphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/HighlightFilter.cs b/src/Greenshot/Drawing/Filters/HighlightFilter.cs index 38b6a8ee7..e311293c5 100644 --- a/src/Greenshot/Drawing/Filters/HighlightFilter.cs +++ b/src/Greenshot/Drawing/Filters/HighlightFilter.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using Greenshot.Drawing.Fields; @@ -25,44 +26,57 @@ using GreenshotPlugin.Core; using System.Drawing.Drawing2D; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing.Filters { - [Serializable()] - public class HighlightFilter : AbstractFilter { - public HighlightFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.FILL_COLOR, Color.Yellow); - } +namespace Greenshot.Drawing.Filters +{ + [Serializable()] + public class HighlightFilter : AbstractFilter + { + public HighlightFilter(DrawableContainer parent) : base(parent) + { + AddField(GetType(), FieldType.FILL_COLOR, Color.Yellow); + } - /// - /// Implements the Apply code for the Brightness Filet - /// - /// - /// - /// - /// - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + /// + /// Implements the Apply code for the Brightness Filet + /// + /// + /// + /// + /// + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) { - Color highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - for (int y = fastBitmap.Top; y < fastBitmap.Bottom; y++) { - for (int x = fastBitmap.Left; x < fastBitmap.Right; x++) { - Color color = fastBitmap.GetColorAt(x, y); - color = Color.FromArgb(color.A, Math.Min(highlightColor.R, color.R), Math.Min(highlightColor.G, color.G), Math.Min(highlightColor.B, color.B)); - fastBitmap.SetColorAt(x, y, color); - } - } - fastBitmap.DrawTo(graphics, applyRect.Location); - } - graphics.Restore(state); - } - } -} + if (applyRect.Width == 0 || applyRect.Height == 0) + { + // nothing to do + return; + } + + GraphicsState state = graphics.Save(); + if (Invert) + { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + + using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) + { + Color highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + for (int y = fastBitmap.Top; y < fastBitmap.Bottom; y++) + { + for (int x = fastBitmap.Left; x < fastBitmap.Right; x++) + { + Color color = fastBitmap.GetColorAt(x, y); + color = Color.FromArgb(color.A, Math.Min(highlightColor.R, color.R), Math.Min(highlightColor.G, color.G), Math.Min(highlightColor.B, color.B)); + fastBitmap.SetColorAt(x, y, color); + } + } + + fastBitmap.DrawTo(graphics, applyRect.Location); + } + + graphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/IFilter.cs b/src/Greenshot/Drawing/Filters/IFilter.cs index 8c3b5b23e..bbf255dd1 100644 --- a/src/Greenshot/Drawing/Filters/IFilter.cs +++ b/src/Greenshot/Drawing/Filters/IFilter.cs @@ -25,10 +25,11 @@ using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing.Filters { - public interface IFilter : INotifyPropertyChanged, IFieldHolder { - DrawableContainer Parent {get; set; } - void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode); - DrawableContainer GetParent(); - bool Invert {get; set;} - } -} + public interface IFilter : INotifyPropertyChanged, IFieldHolder + { + DrawableContainer Parent { get; set; } + void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode); + DrawableContainer GetParent(); + bool Invert { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/MagnifierFilter.cs b/src/Greenshot/Drawing/Filters/MagnifierFilter.cs index 68b033ef5..c3f9835fa 100644 --- a/src/Greenshot/Drawing/Filters/MagnifierFilter.cs +++ b/src/Greenshot/Drawing/Filters/MagnifierFilter.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using Greenshot.Drawing.Fields; @@ -25,37 +26,45 @@ using GreenshotPlugin.Core; using System.Drawing.Drawing2D; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing.Filters { - [Serializable] - public class MagnifierFilter : AbstractFilter { - public MagnifierFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.MAGNIFICATION_FACTOR, 2); - } +namespace Greenshot.Drawing.Filters +{ + [Serializable] + public class MagnifierFilter : AbstractFilter + { + public MagnifierFilter(DrawableContainer parent) : base(parent) + { + AddField(GetType(), FieldType.MAGNIFICATION_FACTOR, 2); + } - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - int magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR); - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - graphics.SmoothingMode = SmoothingMode.None; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - int halfWidth = rect.Width / 2; - int halfHeight = rect.Height / 2; - int newWidth = rect.Width / magnificationFactor; - int newHeight = rect.Height / magnificationFactor; - Rectangle source = new Rectangle(rect.X + halfWidth - newWidth / 2, rect.Y + halfHeight - newHeight / 2, newWidth, newHeight); - graphics.DrawImage(applyBitmap, rect, source, GraphicsUnit.Pixel); - graphics.Restore(state); - } - } -} + if (applyRect.Width == 0 || applyRect.Height == 0) + { + // nothing to do + return; + } + + int magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR); + GraphicsState state = graphics.Save(); + if (Invert) + { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + + graphics.SmoothingMode = SmoothingMode.None; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + int halfWidth = rect.Width / 2; + int halfHeight = rect.Height / 2; + int newWidth = rect.Width / magnificationFactor; + int newHeight = rect.Height / magnificationFactor; + Rectangle source = new Rectangle(rect.X + halfWidth - newWidth / 2, rect.Y + halfHeight - newHeight / 2, newWidth, newHeight); + graphics.DrawImage(applyBitmap, rect, source, GraphicsUnit.Pixel); + graphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/PixelizationFilter.cs b/src/Greenshot/Drawing/Filters/PixelizationFilter.cs index dbf19d3f7..00a3e2f11 100644 --- a/src/Greenshot/Drawing/Filters/PixelizationFilter.cs +++ b/src/Greenshot/Drawing/Filters/PixelizationFilter.cs @@ -18,58 +18,78 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; - using Greenshot.Drawing.Fields; using Greenshot.Helpers; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing.Filters { - [Serializable()] - public class PixelizationFilter : AbstractFilter { - - public PixelizationFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.PIXEL_SIZE, 5); - } - - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE); - ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - if (pixelSize <= 1 || rect.Width == 0 || rect.Height == 0) { - // Nothing to do - return; - } - if (rect.Width < pixelSize) { - pixelSize = rect.Width; - } - if (rect.Height < pixelSize) { - pixelSize = rect.Height; - } +namespace Greenshot.Drawing.Filters +{ + [Serializable()] + public class PixelizationFilter : AbstractFilter + { + public PixelizationFilter(DrawableContainer parent) : base(parent) + { + AddField(GetType(), FieldType.PIXEL_SIZE, 5); + } + + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE); + ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + if (pixelSize <= 1 || rect.Width == 0 || rect.Height == 0) + { + // Nothing to do + return; + } + + if (rect.Width < pixelSize) + { + pixelSize = rect.Width; + } + + if (rect.Height < pixelSize) + { + pixelSize = rect.Height; + } using IFastBitmap dest = FastBitmap.CreateCloneOf(applyBitmap, rect); - using (IFastBitmap src = FastBitmap.Create(applyBitmap, rect)) { + using (IFastBitmap src = FastBitmap.Create(applyBitmap, rect)) + { List colors = new List(); int halbPixelSize = pixelSize / 2; - for (int y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y += pixelSize) { - for (int x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x += pixelSize) { + for (int y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y += pixelSize) + { + for (int x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x += pixelSize) + { colors.Clear(); - for (int yy = y; yy < y + pixelSize; yy++) { - if (yy >= src.Top && yy < src.Bottom) { - for (int xx = x; xx < x + pixelSize; xx++) { - if (xx >= src.Left && xx < src.Right) { + for (int yy = y; yy < y + pixelSize; yy++) + { + if (yy >= src.Top && yy < src.Bottom) + { + for (int xx = x; xx < x + pixelSize; xx++) + { + if (xx >= src.Left && xx < src.Right) + { colors.Add(src.GetColorAt(xx, yy)); } } } } + Color currentAvgColor = Colors.Mix(colors); - for (int yy = y; yy <= y + pixelSize; yy++) { - if (yy >= src.Top && yy < src.Bottom) { - for (int xx = x; xx <= x + pixelSize; xx++) { - if (xx >= src.Left && xx < src.Right) { + for (int yy = y; yy <= y + pixelSize; yy++) + { + if (yy >= src.Top && yy < src.Bottom) + { + for (int xx = x; xx <= x + pixelSize; xx++) + { + if (xx >= src.Left && xx < src.Right) + { dest.SetColorAt(xx, yy, currentAvgColor); } } @@ -78,7 +98,8 @@ namespace Greenshot.Drawing.Filters { } } } + dest.DrawTo(graphics, rect.Location); } - } -} + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/FreehandContainer.cs b/src/Greenshot/Drawing/FreehandContainer.cs index 0485f2ae5..a493ee670 100644 --- a/src/Greenshot/Drawing/FreehandContainer.cs +++ b/src/Greenshot/Drawing/FreehandContainer.cs @@ -28,155 +28,176 @@ using System.Drawing.Drawing2D; using System.Runtime.Serialization; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Description of PathContainer. - /// - [Serializable] - public class FreehandContainer : DrawableContainer { - private static readonly float [] PointOffset = {0.5f, 0.25f, 0.75f}; +namespace Greenshot.Drawing +{ + /// + /// Description of PathContainer. + /// + [Serializable] + public class FreehandContainer : DrawableContainer + { + private static readonly float[] PointOffset = + { + 0.5f, 0.25f, 0.75f + }; - [NonSerialized] - private GraphicsPath freehandPath = new GraphicsPath(); - private Rectangle myBounds = Rectangle.Empty; - private Point lastMouse = Point.Empty; - private readonly List capturePoints = new List(); - private bool isRecalculated; - - /// - /// Constructor - /// - public FreehandContainer(Surface parent) : base(parent) { - Width = parent.Image.Width; - Height = parent.Image.Height; - Top = 0; - Left = 0; - } + [NonSerialized] private GraphicsPath freehandPath = new GraphicsPath(); + private Rectangle myBounds = Rectangle.Empty; + private Point lastMouse = Point.Empty; + private readonly List capturePoints = new List(); + private bool isRecalculated; - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 3); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - } + /// + /// Constructor + /// + public FreehandContainer(Surface parent) : base(parent) + { + Width = parent.Image.Width; + Height = parent.Image.Height; + Top = 0; + Left = 0; + } - public override void Transform(Matrix matrix) { - Point[] points = capturePoints.ToArray(); + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 3); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + } - matrix.TransformPoints(points); - capturePoints.Clear(); - capturePoints.AddRange(points); - RecalculatePath(); - } - - protected override void OnDeserialized(StreamingContext context) { - RecalculatePath(); - } + public override void Transform(Matrix matrix) + { + Point[] points = capturePoints.ToArray(); - /// - /// This Dispose is called from the Dispose and the Destructor. - /// - /// When disposing==true all non-managed resources should be freed too! - protected override void Dispose(bool disposing) { - base.Dispose(disposing); - if (disposing) - { - freehandPath?.Dispose(); - } - freehandPath = null; - } - - /// - /// Called from Surface (the parent) when the drawing begins (mouse-down) - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseDown(int mouseX, int mouseY) { - lastMouse = new Point(mouseX, mouseY); - capturePoints.Add(lastMouse); - return true; - } + matrix.TransformPoints(points); + capturePoints.Clear(); + capturePoints.AddRange(points); + RecalculatePath(); + } - /// - /// Called from Surface (the parent) if a mouse move is made while drawing - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseMove(int mouseX, int mouseY) { - Point previousPoint = capturePoints[capturePoints.Count-1]; + protected override void OnDeserialized(StreamingContext context) + { + RecalculatePath(); + } - if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= 2*EditorConfig.FreehandSensitivity) { - capturePoints.Add(new Point(mouseX, mouseY)); - } - if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) < EditorConfig.FreehandSensitivity) - { - return true; - } - //path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)}); - lastMouse = new Point(mouseX, mouseY); - freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY)); - // Only re-calculate the bounds & redraw when we added something to the path - myBounds = Rectangle.Round(freehandPath.GetBounds()); + /// + /// This Dispose is called from the Dispose and the Destructor. + /// + /// When disposing==true all non-managed resources should be freed too! + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + freehandPath?.Dispose(); + } + + freehandPath = null; + } + + /// + /// Called from Surface (the parent) when the drawing begins (mouse-down) + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseDown(int mouseX, int mouseY) + { + lastMouse = new Point(mouseX, mouseY); + capturePoints.Add(lastMouse); + return true; + } + + /// + /// Called from Surface (the parent) if a mouse move is made while drawing + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseMove(int mouseX, int mouseY) + { + Point previousPoint = capturePoints[capturePoints.Count - 1]; + + if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= 2 * EditorConfig.FreehandSensitivity) + { + capturePoints.Add(new Point(mouseX, mouseY)); + } + + if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) < EditorConfig.FreehandSensitivity) + { + return true; + } + + //path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)}); + lastMouse = new Point(mouseX, mouseY); + freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY)); + // Only re-calculate the bounds & redraw when we added something to the path + myBounds = Rectangle.Round(freehandPath.GetBounds()); Invalidate(); - return true; - } + return true; + } - /// - /// Called when the surface finishes drawing the element - /// - public override void HandleMouseUp(int mouseX, int mouseY) { - // Make sure we don't loose the ending point - if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) >= EditorConfig.FreehandSensitivity) { - capturePoints.Add(new Point(mouseX, mouseY)); - } - RecalculatePath(); - } - - /// - /// Here we recalculate the freehand path by smoothing out the lines with Beziers. - /// - private void RecalculatePath() { - // Store the previous path, to dispose it later when we are finished + /// + /// Called when the surface finishes drawing the element + /// + public override void HandleMouseUp(int mouseX, int mouseY) + { + // Make sure we don't loose the ending point + if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) >= EditorConfig.FreehandSensitivity) + { + capturePoints.Add(new Point(mouseX, mouseY)); + } + + RecalculatePath(); + } + + /// + /// Here we recalculate the freehand path by smoothing out the lines with Beziers. + /// + private void RecalculatePath() + { + // Store the previous path, to dispose it later when we are finished var previousFreehandPath = freehandPath; - var newFreehandPath = new GraphicsPath(); + var newFreehandPath = new GraphicsPath(); + + // Here we can put some cleanup... like losing all the uninteresting points. + if (capturePoints.Count >= 3) + { + int index = 0; + while ((capturePoints.Count - 1) % 3 != 0) + { + // duplicate points, first at 50% than 25% than 75% + capturePoints.Insert((int) (capturePoints.Count * PointOffset[index]), capturePoints[(int) (capturePoints.Count * PointOffset[index++])]); + } - // Here we can put some cleanup... like losing all the uninteresting points. - if (capturePoints.Count >= 3) - { - int index = 0; - while ((capturePoints.Count - 1) % 3 != 0) - { - // duplicate points, first at 50% than 25% than 75% - capturePoints.Insert((int)(capturePoints.Count * PointOffset[index]), capturePoints[(int)(capturePoints.Count * PointOffset[index++])]); - } newFreehandPath.AddBeziers(capturePoints.ToArray()); - } - else if (capturePoints.Count == 2) - { + } + else if (capturePoints.Count == 2) + { newFreehandPath.AddLine(capturePoints[0], capturePoints[1]); - } + } - // Recalculate the bounds - myBounds = Rectangle.Round(newFreehandPath.GetBounds()); + // Recalculate the bounds + myBounds = Rectangle.Round(newFreehandPath.GetBounds()); - // assign + // assign isRecalculated = true; freehandPath = newFreehandPath; - // dispose previous - previousFreehandPath?.Dispose(); - } + // dispose previous + previousFreehandPath?.Dispose(); + } - /// - /// Do the drawing of the freehand "stroke" - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode renderMode) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + /// + /// Do the drawing of the freehand "stroke" + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode renderMode) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); using var pen = new Pen(lineColor) { Width = lineThickness @@ -185,6 +206,7 @@ namespace Greenshot.Drawing { { return; } + // Make sure the lines are nicely rounded pen.EndCap = LineCap.Round; pen.StartCap = LineCap.Round; @@ -199,11 +221,12 @@ namespace Greenshot.Drawing { isRecalculated = false; DrawSelectionBorder(graphics, pen, currentFreehandPath); } + graphics.DrawPath(pen, currentFreehandPath); - } + } // Move back, otherwise everything is shifted - graphics.TranslateTransform(-Left,-Top); + graphics.TranslateTransform(-Left, -Top); } /// @@ -215,71 +238,86 @@ namespace Greenshot.Drawing { protected static void DrawSelectionBorder(Graphics graphics, Pen linePen, GraphicsPath path) { using var selectionPen = (Pen) linePen.Clone(); - using var selectionPath = (GraphicsPath)path.Clone(); + using var selectionPath = (GraphicsPath) path.Clone(); selectionPen.Width += 5; selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen); graphics.DrawPath(selectionPen, selectionPath); selectionPath.Widen(selectionPen); - selectionPen.DashPattern = new float[]{2,2}; + selectionPen.DashPattern = new float[] + { + 2, 2 + }; selectionPen.Color = Color.LightSeaGreen; selectionPen.Width = 1; graphics.DrawPath(selectionPen, selectionPath); } - - /// - /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds... - /// - public override Rectangle DrawingBounds { - get { - if (!myBounds.IsEmpty) { - int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS)); - int safetymargin = 10; - return new Rectangle(myBounds.Left + Left - (safetymargin+lineThickness), myBounds.Top + Top - (safetymargin+lineThickness), myBounds.Width + 2*(lineThickness+safetymargin), myBounds.Height + 2*(lineThickness+safetymargin)); - } - if (_parent?.Image is Image image) - { - return new Rectangle(0, 0, image.Width, image.Height); - } - else - { - return Rectangle.Empty; - } - } - } + + /// + /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds... + /// + public override Rectangle DrawingBounds + { + get + { + if (!myBounds.IsEmpty) + { + int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS)); + int safetymargin = 10; + return new Rectangle(myBounds.Left + Left - (safetymargin + lineThickness), myBounds.Top + Top - (safetymargin + lineThickness), + myBounds.Width + 2 * (lineThickness + safetymargin), myBounds.Height + 2 * (lineThickness + safetymargin)); + } + + if (_parent?.Image is Image image) + { + return new Rectangle(0, 0, image.Width, image.Height); + } + else + { + return Rectangle.Empty; + } + } + } /// /// FreehandContainer are regarded equal if they are of the same type and their paths are equal. /// /// object /// bool - public override bool Equals(object obj) { - bool ret = false; + public override bool Equals(object obj) + { + bool ret = false; if (obj == null || GetType() != obj.GetType()) { return false; } - if (obj is FreehandContainer other && Equals(freehandPath, other.freehandPath)) { + if (obj is FreehandContainer other && Equals(freehandPath, other.freehandPath)) + { ret = true; } + return ret; - } + } - public override int GetHashCode() { - return freehandPath?.GetHashCode() ?? 0; - } + public override int GetHashCode() + { + return freehandPath?.GetHashCode() ?? 0; + } - public override bool ClickableAt(int x, int y) { - bool returnValue = base.ClickableAt(x, y); - if (returnValue) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + public override bool ClickableAt(int x, int y) + { + bool returnValue = base.ClickableAt(x, y); + if (returnValue) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); using var pen = new Pen(Color.White) { Width = lineThickness + 10 }; returnValue = freehandPath.IsOutlineVisible(x - Left, y - Top, pen); } - return returnValue; - } - } -} + + return returnValue; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/HighlightContainer.cs b/src/Greenshot/Drawing/HighlightContainer.cs index 788360004..267e2784b 100644 --- a/src/Greenshot/Drawing/HighlightContainer.cs +++ b/src/Greenshot/Drawing/HighlightContainer.cs @@ -18,82 +18,95 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Runtime.Serialization; - using Greenshot.Drawing.Fields; using Greenshot.Drawing.Filters; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Description of ObfuscateContainer. - /// - [Serializable] - public class HighlightContainer : FilterContainer { - public HighlightContainer(Surface parent) : base(parent) { - Init(); - } +namespace Greenshot.Drawing +{ + /// + /// Description of ObfuscateContainer. + /// + [Serializable] + public class HighlightContainer : FilterContainer + { + public HighlightContainer(Surface parent) : base(parent) + { + Init(); + } - /// - /// Use settings from base, extend with our own field - /// - protected override void InitializeFields() { - base.InitializeFields(); - AddField(GetType(), FieldType.PREPARED_FILTER_HIGHLIGHT, PreparedFilter.TEXT_HIGHTLIGHT); - } + /// + /// Use settings from base, extend with our own field + /// + protected override void InitializeFields() + { + base.InitializeFields(); + AddField(GetType(), FieldType.PREPARED_FILTER_HIGHLIGHT, PreparedFilter.TEXT_HIGHTLIGHT); + } - protected override void OnDeserialized(StreamingContext context) - { - Init(); - } - - private void Init() { - FieldChanged += HighlightContainer_OnFieldChanged; - ConfigurePreparedFilters(); - } - - protected void HighlightContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { - if (!sender.Equals(this)) { - return; - } - if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_HIGHLIGHT)) { - ConfigurePreparedFilters(); - } - } + protected override void OnDeserialized(StreamingContext context) + { + Init(); + } - private void ConfigurePreparedFilters() { - PreparedFilter preset = (PreparedFilter)GetFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); - while(Filters.Count>0) { - Remove(Filters[0]); - } - switch(preset) { - case PreparedFilter.TEXT_HIGHTLIGHT: - Add(new HighlightFilter(this)); - break; - case PreparedFilter.AREA_HIGHLIGHT: - var brightnessFilter = new BrightnessFilter(this) - { - Invert = true - }; - Add(brightnessFilter); - var blurFilter = new BlurFilter(this) - { - Invert = true - }; - Add(blurFilter); - break; - case PreparedFilter.GRAYSCALE: + private void Init() + { + FieldChanged += HighlightContainer_OnFieldChanged; + ConfigurePreparedFilters(); + } + + protected void HighlightContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) + { + if (!sender.Equals(this)) + { + return; + } + + if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_HIGHLIGHT)) + { + ConfigurePreparedFilters(); + } + } + + private void ConfigurePreparedFilters() + { + PreparedFilter preset = (PreparedFilter) GetFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); + while (Filters.Count > 0) + { + Remove(Filters[0]); + } + + switch (preset) + { + case PreparedFilter.TEXT_HIGHTLIGHT: + Add(new HighlightFilter(this)); + break; + case PreparedFilter.AREA_HIGHLIGHT: + var brightnessFilter = new BrightnessFilter(this) + { + Invert = true + }; + Add(brightnessFilter); + var blurFilter = new BlurFilter(this) + { + Invert = true + }; + Add(blurFilter); + break; + case PreparedFilter.GRAYSCALE: AbstractFilter f = new GrayscaleFilter(this) { Invert = true }; Add(f); - break; - case PreparedFilter.MAGNIFICATION: - Add(new MagnifierFilter(this)); - break; - } - } - } -} + break; + case PreparedFilter.MAGNIFICATION: + Add(new MagnifierFilter(this)); + break; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/IconContainer.cs b/src/Greenshot/Drawing/IconContainer.cs index 6d5c90986..a89e0a258 100644 --- a/src/Greenshot/Drawing/IconContainer.cs +++ b/src/Greenshot/Drawing/IconContainer.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.IO; @@ -26,84 +27,94 @@ using log4net; using System.Runtime.Serialization; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Description of IconContainer. - /// - [Serializable] - public class IconContainer : DrawableContainer, IIconContainer { - private static readonly ILog Log = LogManager.GetLogger(typeof(IconContainer)); +namespace Greenshot.Drawing +{ + /// + /// Description of IconContainer. + /// + [Serializable] + public class IconContainer : DrawableContainer, IIconContainer + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IconContainer)); - protected Icon icon; + protected Icon icon; - public IconContainer(Surface parent) : base(parent) { - Init(); - } + public IconContainer(Surface parent) : base(parent) + { + Init(); + } - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } - private void Init() - { - CreateDefaultAdorners(); - } + private void Init() + { + CreateDefaultAdorners(); + } - public IconContainer(Surface parent, string filename) : base(parent) { - Load(filename); - } + public IconContainer(Surface parent, string filename) : base(parent) + { + Load(filename); + } - public Icon Icon { - set { - icon?.Dispose(); - icon = (Icon)value.Clone(); - Width = value.Width; - Height = value.Height; - } - get => icon; - } + public Icon Icon + { + set + { + icon?.Dispose(); + icon = (Icon) value.Clone(); + Width = value.Width; + Height = value.Height; + } + get => icon; + } - /** + /** * This Dispose is called from the Dispose and the Destructor. * When disposing==true all non-managed resources should be freed too! */ - protected override void Dispose(bool disposing) { - if (disposing) - { - icon?.Dispose(); - } - icon = null; - base.Dispose(disposing); - } + protected override void Dispose(bool disposing) + { + if (disposing) + { + icon?.Dispose(); + } - public void Load(string filename) - { - if (!File.Exists(filename)) - { - return; - } - using Icon fileIcon = new Icon(filename); - Icon = fileIcon; - Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); - } - - public override void Draw(Graphics graphics, RenderMode rm) - { - if (icon == null) - { - return; - } - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.Default; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.DrawIcon(icon, Bounds); - } + icon = null; + base.Dispose(disposing); + } - public override bool HasDefaultSize => true; + public void Load(string filename) + { + if (!File.Exists(filename)) + { + return; + } - public override Size DefaultSize => icon?.Size ?? new Size(16,16); - } -} + using Icon fileIcon = new Icon(filename); + Icon = fileIcon; + Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); + } + + public override void Draw(Graphics graphics, RenderMode rm) + { + if (icon == null) + { + return; + } + + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.CompositingQuality = CompositingQuality.Default; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.DrawIcon(icon, Bounds); + } + + public override bool HasDefaultSize => true; + + public override Size DefaultSize => icon?.Size ?? new Size(16, 16); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/ImageContainer.cs b/src/Greenshot/Drawing/ImageContainer.cs index 5840c9507..3b99e36af 100644 --- a/src/Greenshot/Drawing/ImageContainer.cs +++ b/src/Greenshot/Drawing/ImageContainer.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.IO; @@ -29,206 +30,238 @@ using System.Runtime.Serialization; using GreenshotPlugin.Effects; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Description of BitmapContainer. - /// - [Serializable] - public class ImageContainer : DrawableContainer, IImageContainer { - private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer)); +namespace Greenshot.Drawing +{ + /// + /// Description of BitmapContainer. + /// + [Serializable] + public class ImageContainer : DrawableContainer, IImageContainer + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer)); - private Image image; + private Image image; - /// - /// This is the shadow version of the bitmap, rendered once to save performance - /// Do not serialize, as the shadow is recreated from the original bitmap if it's not available - /// - [NonSerialized] - private Image _shadowBitmap; + /// + /// This is the shadow version of the bitmap, rendered once to save performance + /// Do not serialize, as the shadow is recreated from the original bitmap if it's not available + /// + [NonSerialized] private Image _shadowBitmap; - /// - /// This is the offset for the shadow version of the bitmap - /// Do not serialize, as the offset is recreated - /// - [NonSerialized] - private Point _shadowOffset = new Point(-1, -1); + /// + /// This is the offset for the shadow version of the bitmap + /// Do not serialize, as the offset is recreated + /// + [NonSerialized] private Point _shadowOffset = new Point(-1, -1); - public ImageContainer(Surface parent, string filename) : this(parent) { - Load(filename); - } + public ImageContainer(Surface parent, string filename) : this(parent) + { + Load(filename); + } - public ImageContainer(Surface parent) : base(parent) { - FieldChanged += BitmapContainer_OnFieldChanged; - Init(); - } + public ImageContainer(Surface parent) : base(parent) + { + FieldChanged += BitmapContainer_OnFieldChanged; + Init(); + } - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } - private void Init() - { - CreateDefaultAdorners(); - } + private void Init() + { + CreateDefaultAdorners(); + } - protected override void InitializeFields() { - AddField(GetType(), FieldType.SHADOW, false); - } + protected override void InitializeFields() + { + AddField(GetType(), FieldType.SHADOW, false); + } - protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) - { - if (!sender.Equals(this)) - { - return; - } - if (FieldType.SHADOW.Equals(e.Field.FieldType)) { - ChangeShadowField(); - } - } + protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) + { + if (!sender.Equals(this)) + { + return; + } - public void ChangeShadowField() { - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - if (shadow) { - CheckShadow(true); - Width = _shadowBitmap.Width; - Height = _shadowBitmap.Height; - Left -= _shadowOffset.X; - Top -= _shadowOffset.Y; - } else { - Width = image.Width; - Height = image.Height; - if (_shadowBitmap != null) { - Left += _shadowOffset.X; - Top += _shadowOffset.Y; - } - } - } + if (FieldType.SHADOW.Equals(e.Field.FieldType)) + { + ChangeShadowField(); + } + } - public Image Image { - set { - // Remove all current bitmaps - DisposeImage(); - DisposeShadow(); - image = ImageHelper.Clone(value); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - CheckShadow(shadow); - if (!shadow) { - Width = image.Width; - Height = image.Height; - } else { - Width = _shadowBitmap.Width; - Height = _shadowBitmap.Height; - Left -= _shadowOffset.X; - Top -= _shadowOffset.Y; - } - } - get { return image; } - } + public void ChangeShadowField() + { + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + if (shadow) + { + CheckShadow(true); + Width = _shadowBitmap.Width; + Height = _shadowBitmap.Height; + Left -= _shadowOffset.X; + Top -= _shadowOffset.Y; + } + else + { + Width = image.Width; + Height = image.Height; + if (_shadowBitmap != null) + { + Left += _shadowOffset.X; + Top += _shadowOffset.Y; + } + } + } - /// - /// The bulk of the clean-up code is implemented in Dispose(bool) - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected override void Dispose(bool disposing) { - if (disposing) { - DisposeImage(); - DisposeShadow(); - } - base.Dispose(disposing); - } + public Image Image + { + set + { + // Remove all current bitmaps + DisposeImage(); + DisposeShadow(); + image = ImageHelper.Clone(value); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + CheckShadow(shadow); + if (!shadow) + { + Width = image.Width; + Height = image.Height; + } + else + { + Width = _shadowBitmap.Width; + Height = _shadowBitmap.Height; + Left -= _shadowOffset.X; + Top -= _shadowOffset.Y; + } + } + get { return image; } + } - private void DisposeImage() { - image?.Dispose(); - image = null; - } - private void DisposeShadow() { - _shadowBitmap?.Dispose(); - _shadowBitmap = null; - } + /// + /// The bulk of the clean-up code is implemented in Dispose(bool) + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + DisposeImage(); + DisposeShadow(); + } + + base.Dispose(disposing); + } + + private void DisposeImage() + { + image?.Dispose(); + image = null; + } + + private void DisposeShadow() + { + _shadowBitmap?.Dispose(); + _shadowBitmap = null; + } - - /// - /// Make sure the content is also transformed. - /// - /// - public override void Transform(Matrix matrix) { - int rotateAngle = CalculateAngle(matrix); - // we currently assume only one transformation has been made. - if (rotateAngle != 0) { - Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle); - DisposeShadow(); + /// + /// Make sure the content is also transformed. + /// + /// + public override void Transform(Matrix matrix) + { + int rotateAngle = CalculateAngle(matrix); + // we currently assume only one transformation has been made. + if (rotateAngle != 0) + { + Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle); + DisposeShadow(); using var tmpMatrix = new Matrix(); using (image) { image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix); } } - base.Transform(matrix); - } - /// - /// - /// - /// - public void Load(string filename) { - if (!File.Exists(filename)) - { - return; - } - // Always make sure ImageHelper.LoadBitmap results are disposed some time, - // as we close the bitmap internally, we need to do it afterwards - using (var tmpImage = ImageHelper.LoadImage(filename)) { - Image = tmpImage; - } - Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); - } + base.Transform(matrix); + } - /// - /// This checks if a shadow is already generated - /// - /// - private void CheckShadow(bool shadow) - { - if (!shadow || _shadowBitmap != null) - { - return; - } - using var matrix = new Matrix(); - _shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix); - } + /// + /// + /// + /// + public void Load(string filename) + { + if (!File.Exists(filename)) + { + return; + } - /// - /// Draw the actual container to the graphics object - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode rm) - { - if (image == null) - { - return; - } - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + // Always make sure ImageHelper.LoadBitmap results are disposed some time, + // as we close the bitmap internally, we need to do it afterwards + using (var tmpImage = ImageHelper.LoadImage(filename)) + { + Image = tmpImage; + } - if (shadow) { - CheckShadow(true); - graphics.DrawImage(_shadowBitmap, Bounds); - } else { - graphics.DrawImage(image, Bounds); - } - } + Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); + } - public override bool HasDefaultSize => true; + /// + /// This checks if a shadow is already generated + /// + /// + private void CheckShadow(bool shadow) + { + if (!shadow || _shadowBitmap != null) + { + return; + } - public override Size DefaultSize => image?.Size ?? new Size(32, 32); - } -} + using var matrix = new Matrix(); + _shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix); + } + + /// + /// Draw the actual container to the graphics object + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode rm) + { + if (image == null) + { + return; + } + + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + if (shadow) + { + CheckShadow(true); + graphics.DrawImage(_shadowBitmap, Bounds); + } + else + { + graphics.DrawImage(image, Bounds); + } + } + + public override bool HasDefaultSize => true; + + public override Size DefaultSize => image?.Size ?? new Size(32, 32); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/LineContainer.cs b/src/Greenshot/Drawing/LineContainer.cs index 93b76ad89..6a5229107 100644 --- a/src/Greenshot/Drawing/LineContainer.cs +++ b/src/Greenshot/Drawing/LineContainer.cs @@ -18,60 +18,68 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; - using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Drawing.Adorners; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Description of LineContainer. - /// - [Serializable()] - public class LineContainer : DrawableContainer { - public LineContainer(Surface parent) : base(parent) { - Init(); - } +namespace Greenshot.Drawing +{ + /// + /// Description of LineContainer. + /// + [Serializable()] + public class LineContainer : DrawableContainer + { + public LineContainer(Surface parent) : base(parent) + { + Init(); + } - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.SHADOW, true); - } + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + AddField(GetType(), FieldType.SHADOW, true); + } - protected override void OnDeserialized(StreamingContext context) - { - Init(); - } + protected override void OnDeserialized(StreamingContext context) + { + Init(); + } - protected void Init() { - Adorners.Add(new MoveAdorner(this, Positions.TopLeft)); - Adorners.Add(new MoveAdorner(this, Positions.BottomRight)); - } + protected void Init() + { + Adorners.Add(new MoveAdorner(this, Positions.TopLeft)); + Adorners.Add(new MoveAdorner(this, Positions.BottomRight)); + } - public override void Draw(Graphics graphics, RenderMode rm) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; + public override void Draw(Graphics graphics, RenderMode rm) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - if (lineThickness > 0) { - if (shadow) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = 1; - while (currentStep <= steps) + if (lineThickness > 0) + { + if (shadow) + { + //draw shadow first + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = 1; + while (currentStep <= steps) { using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); graphics.DrawLine(shadowCapPen, @@ -83,16 +91,17 @@ namespace Greenshot.Drawing { currentStep++; alpha -= basealpha / steps; } - } + } using Pen pen = new Pen(lineColor, lineThickness); graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); } - } + } - public override bool ClickableAt(int x, int y) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) +5; - if (lineThickness > 0) + public override bool ClickableAt(int x, int y) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 5; + if (lineThickness > 0) { using Pen pen = new Pen(Color.White) { @@ -100,13 +109,15 @@ namespace Greenshot.Drawing { }; using GraphicsPath path = new GraphicsPath(); path.AddLine(Left, Top, Left + Width, Top + Height); - return path.IsOutlineVisible(x, y, pen); + return path.IsOutlineVisible(x, y, pen); } - return false; - } - protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() { - return ScaleHelper.LineAngleRoundBehavior.Instance; - } - } -} + return false; + } + + protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() + { + return ScaleHelper.LineAngleRoundBehavior.Instance; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/ObfuscateContainer.cs b/src/Greenshot/Drawing/ObfuscateContainer.cs index f1fdbf156..127ff2b61 100644 --- a/src/Greenshot/Drawing/ObfuscateContainer.cs +++ b/src/Greenshot/Drawing/ObfuscateContainer.cs @@ -18,59 +18,72 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Runtime.Serialization; using Greenshot.Drawing.Fields; using Greenshot.Drawing.Filters; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Description of ObfuscateContainer. - /// - [Serializable] - public class ObfuscateContainer : FilterContainer { - public ObfuscateContainer(Surface parent) : base(parent) { - Init(); - } +namespace Greenshot.Drawing +{ + /// + /// Description of ObfuscateContainer. + /// + [Serializable] + public class ObfuscateContainer : FilterContainer + { + public ObfuscateContainer(Surface parent) : base(parent) + { + Init(); + } - protected override void InitializeFields() { - base.InitializeFields(); - AddField(GetType(), FieldType.PREPARED_FILTER_OBFUSCATE, PreparedFilter.PIXELIZE); - } + protected override void InitializeFields() + { + base.InitializeFields(); + AddField(GetType(), FieldType.PREPARED_FILTER_OBFUSCATE, PreparedFilter.PIXELIZE); + } - protected override void OnDeserialized(StreamingContext context) - { - Init(); - } - - private void Init() { - FieldChanged += ObfuscateContainer_OnFieldChanged; - ConfigurePreparedFilters(); - CreateDefaultAdorners(); - } - - protected void ObfuscateContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { - if(sender.Equals(this)) { - if(Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_OBFUSCATE)) { - ConfigurePreparedFilters(); - } - } - } - - private void ConfigurePreparedFilters() { - PreparedFilter preset = (PreparedFilter)GetFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE); - while(Filters.Count>0) { - Remove(Filters[0]); - } - switch(preset) { - case PreparedFilter.BLUR: - Add(new BlurFilter(this)); - break; - case PreparedFilter.PIXELIZE: - Add(new PixelizationFilter(this)); - break; - } - } - } -} + protected override void OnDeserialized(StreamingContext context) + { + Init(); + } + + private void Init() + { + FieldChanged += ObfuscateContainer_OnFieldChanged; + ConfigurePreparedFilters(); + CreateDefaultAdorners(); + } + + protected void ObfuscateContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) + { + if (sender.Equals(this)) + { + if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_OBFUSCATE)) + { + ConfigurePreparedFilters(); + } + } + } + + private void ConfigurePreparedFilters() + { + PreparedFilter preset = (PreparedFilter) GetFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE); + while (Filters.Count > 0) + { + Remove(Filters[0]); + } + + switch (preset) + { + case PreparedFilter.BLUR: + Add(new BlurFilter(this)); + break; + case PreparedFilter.PIXELIZE: + Add(new PixelizationFilter(this)); + break; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Positions.cs b/src/Greenshot/Drawing/Positions.cs index f7061d023..ca42ee728 100644 --- a/src/Greenshot/Drawing/Positions.cs +++ b/src/Greenshot/Drawing/Positions.cs @@ -21,18 +21,18 @@ namespace Greenshot.Drawing { - /// - /// Position - /// - public enum Positions : int - { - TopLeft = 0, - TopCenter = 1, - TopRight = 2, - MiddleRight = 3, - BottomRight = 4, - BottomCenter = 5, - BottomLeft = 6, - MiddleLeft = 7 - } -} + /// + /// Position + /// + public enum Positions : int + { + TopLeft = 0, + TopCenter = 1, + TopRight = 2, + MiddleRight = 3, + BottomRight = 4, + BottomCenter = 5, + BottomLeft = 6, + MiddleLeft = 7 + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/RectangleContainer.cs b/src/Greenshot/Drawing/RectangleContainer.cs index 2e86fa509..b26193ee7 100644 --- a/src/Greenshot/Drawing/RectangleContainer.cs +++ b/src/Greenshot/Drawing/RectangleContainer.cs @@ -27,73 +27,79 @@ using Greenshot.Helpers; using System.Runtime.Serialization; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// Represents a rectangular shape on the Surface - /// - [Serializable] - public class RectangleContainer : DrawableContainer { +namespace Greenshot.Drawing +{ + /// + /// Represents a rectangular shape on the Surface + /// + [Serializable] + public class RectangleContainer : DrawableContainer + { + public RectangleContainer(Surface parent) : base(parent) + { + Init(); + } - public RectangleContainer(Surface parent) : base(parent) { - Init(); - } + /// + /// Do some logic to make sure all field are initiated correctly + /// + /// StreamingContext + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } - /// - /// Do some logic to make sure all field are initiated correctly - /// - /// StreamingContext - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } + private void Init() + { + CreateDefaultAdorners(); + } - private void Init() - { - CreateDefaultAdorners(); - } + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); + AddField(GetType(), FieldType.SHADOW, true); + } - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, true); - } + public override void Draw(Graphics graphics, RenderMode rm) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR, Color.Red); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR, Color.Transparent); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - public override void Draw(Graphics graphics, RenderMode rm) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR, Color.Red); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR, Color.Transparent); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + DrawRectangle(rect, graphics, rm, lineThickness, lineColor, fillColor, shadow); + } - DrawRectangle(rect, graphics, rm, lineThickness, lineColor, fillColor, shadow); - } + /// + /// This method can also be used from other containers, if the right values are passed! + /// + /// + /// + /// + /// + /// + /// + /// + public static void DrawRectangle(Rectangle rect, Graphics graphics, RenderMode rm, int lineThickness, Color lineColor, Color fillColor, bool shadow) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; - /// - /// This method can also be used from other containers, if the right values are passed! - /// - /// - /// - /// - /// - /// - /// - /// - public static void DrawRectangle(Rectangle rect, Graphics graphics, RenderMode rm, int lineThickness, Color lineColor, Color fillColor, bool shadow) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - if (shadow && (lineVisible || Colors.IsVisible(fillColor))) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = lineVisible ? 1 : 0; - while (currentStep <= steps) + bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); + if (shadow && (lineVisible || Colors.IsVisible(fillColor))) + { + //draw shadow first + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = lineVisible ? 1 : 0; + while (currentStep <= steps) { using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)) { @@ -108,50 +114,54 @@ namespace Greenshot.Drawing { currentStep++; alpha -= basealpha / steps; } - } + } - if (Colors.IsVisible(fillColor)) + if (Colors.IsVisible(fillColor)) { using Brush brush = new SolidBrush(fillColor); graphics.FillRectangle(brush, rect); } - graphics.SmoothingMode = SmoothingMode.HighSpeed; - if (lineVisible) + graphics.SmoothingMode = SmoothingMode.HighSpeed; + if (lineVisible) { using Pen pen = new Pen(lineColor, lineThickness); graphics.DrawRectangle(pen, rect); } + } - } - public override bool ClickableAt(int x, int y) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + public override bool ClickableAt(int x, int y) + { + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - return RectangleClickableAt(rect, lineThickness, fillColor, x, y); - } + return RectangleClickableAt(rect, lineThickness, fillColor, x, y); + } - public static bool RectangleClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) { + public static bool RectangleClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) + { + // If we clicked inside the rectangle and it's visible we are clickable at. + if (!Color.Transparent.Equals(fillColor)) + { + if (rect.Contains(x, y)) + { + return true; + } + } - // If we clicked inside the rectangle and it's visible we are clickable at. - if (!Color.Transparent.Equals(fillColor)) { - if (rect.Contains(x,y)) { - return true; - } - } - - // check the rest of the lines - if (lineThickness > 0) + // check the rest of the lines + if (lineThickness > 0) { using Pen pen = new Pen(Color.White, lineThickness); using GraphicsPath path = new GraphicsPath(); path.AddRectangle(rect); return path.IsOutlineVisible(x, y, pen); } - return false; - } - } -} + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/SpeechbubbleContainer.cs b/src/Greenshot/Drawing/SpeechbubbleContainer.cs index ee00714e9..ce11402b9 100644 --- a/src/Greenshot/Drawing/SpeechbubbleContainer.cs +++ b/src/Greenshot/Drawing/SpeechbubbleContainer.cs @@ -30,316 +30,370 @@ using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing { - /// - /// Description of SpeechbubbleContainer. - /// - [Serializable] - public class SpeechbubbleContainer : TextContainer { - - private Point _initialGripperPoint; + /// + /// Description of SpeechbubbleContainer. + /// + [Serializable] + public class SpeechbubbleContainer : TextContainer + { + private Point _initialGripperPoint; // Only used for serializing the TargetGripper location - private Point _storedTargetGripperLocation; + private Point _storedTargetGripperLocation; - /// - /// Store the current location of the target gripper - /// - /// - [OnSerializing] - private void SetValuesOnSerializing(StreamingContext context) { - if (TargetAdorner != null) { - _storedTargetGripperLocation = TargetAdorner.Location; - } - } + /// + /// Store the current location of the target gripper + /// + /// + [OnSerializing] + private void SetValuesOnSerializing(StreamingContext context) + { + if (TargetAdorner != null) + { + _storedTargetGripperLocation = TargetAdorner.Location; + } + } - /// - /// Restore the target gripper - /// - /// StreamingContext - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - InitAdorner(Color.Green, _storedTargetGripperLocation); - } + /// + /// Restore the target gripper + /// + /// StreamingContext + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + InitAdorner(Color.Green, _storedTargetGripperLocation); + } public SpeechbubbleContainer(Surface parent) - : base(parent) { - } + : base(parent) + { + } - /// - /// We set our own field values - /// - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Blue); - AddField(GetType(), FieldType.SHADOW, false); - AddField(GetType(), FieldType.FONT_ITALIC, false); - AddField(GetType(), FieldType.FONT_BOLD, true); - AddField(GetType(), FieldType.FILL_COLOR, Color.White); - AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name); - AddField(GetType(), FieldType.FONT_SIZE, 20f); - AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, StringAlignment.Center); - AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, StringAlignment.Center); - } + /// + /// We set our own field values + /// + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Blue); + AddField(GetType(), FieldType.SHADOW, false); + AddField(GetType(), FieldType.FONT_ITALIC, false); + AddField(GetType(), FieldType.FONT_BOLD, true); + AddField(GetType(), FieldType.FILL_COLOR, Color.White); + AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name); + AddField(GetType(), FieldType.FONT_SIZE, 20f); + AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, StringAlignment.Center); + AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, StringAlignment.Center); + } - /// - /// Called from Surface (the _parent) when the drawing begins (mouse-down) - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseDown(int mouseX, int mouseY) { - if (TargetAdorner == null) { - _initialGripperPoint = new Point(mouseX, mouseY); - InitAdorner(Color.Green, new Point(mouseX, mouseY)); - } - return base.HandleMouseDown(mouseX, mouseY); - } + /// + /// Called from Surface (the _parent) when the drawing begins (mouse-down) + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseDown(int mouseX, int mouseY) + { + if (TargetAdorner == null) + { + _initialGripperPoint = new Point(mouseX, mouseY); + InitAdorner(Color.Green, new Point(mouseX, mouseY)); + } - /// - /// Overriding the HandleMouseMove will help us to make sure the tail is always visible. - /// Should fix BUG-1682 - /// - /// - /// - /// base.HandleMouseMove - public override bool HandleMouseMove(int x, int y) { - bool returnValue = base.HandleMouseMove(x, y); + return base.HandleMouseDown(mouseX, mouseY); + } - bool leftAligned = _boundsAfterResize.Right - _boundsAfterResize.Left >= 0; - bool topAligned = _boundsAfterResize.Bottom - _boundsAfterResize.Top >= 0; + /// + /// Overriding the HandleMouseMove will help us to make sure the tail is always visible. + /// Should fix BUG-1682 + /// + /// + /// + /// base.HandleMouseMove + public override bool HandleMouseMove(int x, int y) + { + bool returnValue = base.HandleMouseMove(x, y); - int xOffset = leftAligned ? -20 : 20; - int yOffset = topAligned ? -20 : 20; + bool leftAligned = _boundsAfterResize.Right - _boundsAfterResize.Left >= 0; + bool topAligned = _boundsAfterResize.Bottom - _boundsAfterResize.Top >= 0; - Point newGripperLocation = _initialGripperPoint; - newGripperLocation.Offset(xOffset, yOffset); - - if (TargetAdorner.Location != newGripperLocation) { - Invalidate(); - TargetAdorner.Location = newGripperLocation; - Invalidate(); - } - return returnValue; - } + int xOffset = leftAligned ? -20 : 20; + int yOffset = topAligned ? -20 : 20; - /// - /// The DrawingBound should be so close as possible to the shape, so we don't invalidate to much. - /// - public override Rectangle DrawingBounds { - get { - if (Status != EditStatus.UNDRAWN) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + Point newGripperLocation = _initialGripperPoint; + newGripperLocation.Offset(xOffset, yOffset); + + if (TargetAdorner.Location != newGripperLocation) + { + Invalidate(); + TargetAdorner.Location = newGripperLocation; + Invalidate(); + } + + return returnValue; + } + + /// + /// The DrawingBound should be so close as possible to the shape, so we don't invalidate to much. + /// + public override Rectangle DrawingBounds + { + get + { + if (Status != EditStatus.UNDRAWN) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); using Pen pen = new Pen(lineColor, lineThickness); int inflateValue = lineThickness + 2 + (shadow ? 6 : 0); using GraphicsPath tailPath = CreateTail(); - return Rectangle.Inflate(Rectangle.Union(Rectangle.Round(tailPath.GetBounds(new Matrix(), pen)), GuiRectangle.GetGuiRectangle(Left, Top, Width, Height)), inflateValue, inflateValue); + return Rectangle.Inflate(Rectangle.Union(Rectangle.Round(tailPath.GetBounds(new Matrix(), pen)), GuiRectangle.GetGuiRectangle(Left, Top, Width, Height)), + inflateValue, inflateValue); } - return Rectangle.Empty; - } - } - /// - /// Helper method to create the bubble GraphicsPath, so we can also calculate the bounds - /// - /// - /// - private GraphicsPath CreateBubble(int lineThickness) { - GraphicsPath bubble = new GraphicsPath(); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + return Rectangle.Empty; + } + } - Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height); - // adapt corner radius to small rectangle dimensions - int smallerSideLength = Math.Min(bubbleRect.Width, bubbleRect.Height); - int cornerRadius = Math.Min(30, smallerSideLength / 2 - lineThickness); - if (cornerRadius > 0) { - bubble.AddArc(bubbleRect.X, bubbleRect.Y, cornerRadius, cornerRadius, 180, 90); - bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y, cornerRadius, cornerRadius, 270, 90); - bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 0, 90); - bubble.AddArc(bubbleRect.X, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90); - } else { - bubble.AddRectangle(bubbleRect); - } - bubble.CloseAllFigures(); - using (Matrix bubbleMatrix = new Matrix()) { - bubbleMatrix.Translate(rect.Left, rect.Top); - bubble.Transform(bubbleMatrix); - } - return bubble; - } + /// + /// Helper method to create the bubble GraphicsPath, so we can also calculate the bounds + /// + /// + /// + private GraphicsPath CreateBubble(int lineThickness) + { + GraphicsPath bubble = new GraphicsPath(); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - /// - /// Helper method to create the tail of the bubble, so we can also calculate the bounds - /// - /// - private GraphicsPath CreateTail() { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height); + // adapt corner radius to small rectangle dimensions + int smallerSideLength = Math.Min(bubbleRect.Width, bubbleRect.Height); + int cornerRadius = Math.Min(30, smallerSideLength / 2 - lineThickness); + if (cornerRadius > 0) + { + bubble.AddArc(bubbleRect.X, bubbleRect.Y, cornerRadius, cornerRadius, 180, 90); + bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y, cornerRadius, cornerRadius, 270, 90); + bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 0, 90); + bubble.AddArc(bubbleRect.X, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90); + } + else + { + bubble.AddRectangle(bubbleRect); + } - int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetAdorner.Location.X, TargetAdorner.Location.Y); - int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20; + bubble.CloseAllFigures(); + using (Matrix bubbleMatrix = new Matrix()) + { + bubbleMatrix.Translate(rect.Left, rect.Top); + bubble.Transform(bubbleMatrix); + } - // This should fix a problem with the tail being to wide - tailWidth = Math.Min(Math.Abs(rect.Width) / 2, tailWidth); - tailWidth = Math.Min(Math.Abs(rect.Height) / 2, tailWidth); + return bubble; + } - GraphicsPath tail = new GraphicsPath(); - tail.AddLine(-tailWidth, 0, tailWidth, 0); - tail.AddLine(tailWidth, 0, 0, -tailLength); - tail.CloseFigure(); + /// + /// Helper method to create the tail of the bubble, so we can also calculate the bounds + /// + /// + private GraphicsPath CreateTail() + { + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - int tailAngle = 90 + (int)GeometryHelper.Angle2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetAdorner.Location.X, TargetAdorner.Location.Y); + int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetAdorner.Location.X, TargetAdorner.Location.Y); + int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20; - using (Matrix tailMatrix = new Matrix()) { - tailMatrix.Translate(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2); - tailMatrix.Rotate(tailAngle); - tail.Transform(tailMatrix); - } + // This should fix a problem with the tail being to wide + tailWidth = Math.Min(Math.Abs(rect.Width) / 2, tailWidth); + tailWidth = Math.Min(Math.Abs(rect.Height) / 2, tailWidth); - return tail; - } + GraphicsPath tail = new GraphicsPath(); + tail.AddLine(-tailWidth, 0, tailWidth, 0); + tail.AddLine(tailWidth, 0, 0, -tailLength); + tail.CloseFigure(); - /// - /// This is to draw the actual container - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode renderMode) { - if (TargetAdorner == null) { - return; - } - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; + int tailAngle = 90 + (int) GeometryHelper.Angle2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetAdorner.Location.X, TargetAdorner.Location.Y); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + using (Matrix tailMatrix = new Matrix()) + { + tailMatrix.Translate(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2); + tailMatrix.Rotate(tailAngle); + tail.Transform(tailMatrix); + } - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + return tail; + } - if (Selected && renderMode == RenderMode.EDIT) { - DrawSelectionBorder(graphics, rect); - } + /// + /// This is to draw the actual container + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode renderMode) + { + if (TargetAdorner == null) + { + return; + } - GraphicsPath bubble = CreateBubble(lineThickness); + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; - GraphicsPath tail = CreateTail(); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - //draw shadow first - if (shadow && (lineVisible || Colors.IsVisible(fillColor))) { - const int basealpha = 100; - int alpha = basealpha; - const int steps = 5; - int currentStep = lineVisible ? 1 : 0; + bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + + if (Selected && renderMode == RenderMode.EDIT) + { + DrawSelectionBorder(graphics, rect); + } + + GraphicsPath bubble = CreateBubble(lineThickness); + + GraphicsPath tail = CreateTail(); + + //draw shadow first + if (shadow && (lineVisible || Colors.IsVisible(fillColor))) + { + const int basealpha = 100; + int alpha = basealpha; + const int steps = 5; + int currentStep = lineVisible ? 1 : 0; using Matrix shadowMatrix = new Matrix(); - using GraphicsPath bubbleClone = (GraphicsPath)bubble.Clone(); - using GraphicsPath tailClone = (GraphicsPath)tail.Clone(); + using GraphicsPath bubbleClone = (GraphicsPath) bubble.Clone(); + using GraphicsPath tailClone = (GraphicsPath) tail.Clone(); shadowMatrix.Translate(1, 1); - while (currentStep <= steps) { - using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) { + while (currentStep <= steps) + { + using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) + { shadowPen.Width = lineVisible ? lineThickness : 1; tailClone.Transform(shadowMatrix); graphics.DrawPath(shadowPen, tailClone); bubbleClone.Transform(shadowMatrix); graphics.DrawPath(shadowPen, bubbleClone); } + currentStep++; alpha -= basealpha / steps; } } - GraphicsState state = graphics.Save(); - // draw the tail border where the bubble is not visible - using (Region clipRegion = new Region(bubble)) { - graphics.SetClip(clipRegion, CombineMode.Exclude); + GraphicsState state = graphics.Save(); + // draw the tail border where the bubble is not visible + using (Region clipRegion = new Region(bubble)) + { + graphics.SetClip(clipRegion, CombineMode.Exclude); using Pen pen = new Pen(lineColor, lineThickness); graphics.DrawPath(pen, tail); } - graphics.Restore(state); - if (Colors.IsVisible(fillColor)) { - //draw the bubbleshape - state = graphics.Save(); - using (Brush brush = new SolidBrush(fillColor)) { - graphics.FillPath(brush, bubble); - } - graphics.Restore(state); - } + graphics.Restore(state); - if (lineVisible) { - //draw the bubble border - state = graphics.Save(); - // Draw bubble where the Tail is not visible. - using (Region clipRegion = new Region(tail)) { - graphics.SetClip(clipRegion, CombineMode.Exclude); + if (Colors.IsVisible(fillColor)) + { + //draw the bubbleshape + state = graphics.Save(); + using (Brush brush = new SolidBrush(fillColor)) + { + graphics.FillPath(brush, bubble); + } + + graphics.Restore(state); + } + + if (lineVisible) + { + //draw the bubble border + state = graphics.Save(); + // Draw bubble where the Tail is not visible. + using (Region clipRegion = new Region(tail)) + { + graphics.SetClip(clipRegion, CombineMode.Exclude); using Pen pen = new Pen(lineColor, lineThickness); //pen.EndCap = pen.StartCap = LineCap.Round; graphics.DrawPath(pen, bubble); } - graphics.Restore(state); - } - if (Colors.IsVisible(fillColor)) { - // Draw the tail border - state = graphics.Save(); - using (Brush brush = new SolidBrush(fillColor)) { - graphics.FillPath(brush, tail); - } - graphics.Restore(state); - } + graphics.Restore(state); + } - // cleanup the paths - bubble.Dispose(); - tail.Dispose(); + if (Colors.IsVisible(fillColor)) + { + // Draw the tail border + state = graphics.Save(); + using (Brush brush = new SolidBrush(fillColor)) + { + graphics.FillPath(brush, tail); + } - // Draw the text - DrawText(graphics, rect, lineThickness, lineColor, shadow, StringFormat, Text, Font); - } + graphics.Restore(state); + } - public override bool Contains(int x, int y) { - if (base.Contains(x, y)) { - return true; - } - Point clickedPoint = new Point(x, y); - if (Status != EditStatus.UNDRAWN) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + // cleanup the paths + bubble.Dispose(); + tail.Dispose(); + + // Draw the text + DrawText(graphics, rect, lineThickness, lineColor, shadow, StringFormat, Text, Font); + } + + public override bool Contains(int x, int y) + { + if (base.Contains(x, y)) + { + return true; + } + + Point clickedPoint = new Point(x, y); + if (Status != EditStatus.UNDRAWN) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); using Pen pen = new Pen(lineColor, lineThickness); - using (GraphicsPath bubblePath = CreateBubble(lineThickness)) { + using (GraphicsPath bubblePath = CreateBubble(lineThickness)) + { bubblePath.Widen(pen); - if (bubblePath.IsVisible(clickedPoint)) { + if (bubblePath.IsVisible(clickedPoint)) + { return true; } } using GraphicsPath tailPath = CreateTail(); tailPath.Widen(pen); - if (tailPath.IsVisible(clickedPoint)) { + if (tailPath.IsVisible(clickedPoint)) + { return true; } } - return false; - } + return false; + } - public override bool ClickableAt(int x, int y) { - return Contains(x,y); - } + public override bool ClickableAt(int x, int y) + { + return Contains(x, y); + } - /// - /// Additional to the Transform of the TextContainer the bubble tail coordinates also need to be moved - /// - /// Matrix - public override void Transform(Matrix matrix) - { - Point[] points = { TargetAdorner.Location }; - matrix.TransformPoints(points); - TargetAdorner.Location = points[0]; - base.Transform(matrix); - } - } -} + /// + /// Additional to the Transform of the TextContainer the bubble tail coordinates also need to be moved + /// + /// Matrix + public override void Transform(Matrix matrix) + { + Point[] points = + { + TargetAdorner.Location + }; + matrix.TransformPoints(points); + TargetAdorner.Location = points[0]; + base.Transform(matrix); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/StepLabelContainer.cs b/src/Greenshot/Drawing/StepLabelContainer.cs index b750fcb20..ff01af1c1 100644 --- a/src/Greenshot/Drawing/StepLabelContainer.cs +++ b/src/Greenshot/Drawing/StepLabelContainer.cs @@ -28,179 +28,198 @@ using System.Drawing.Text; using System.Runtime.Serialization; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing { - /// - /// This is an enumerated label, every single StepLabelContainer shows the number of the order it was created. - /// To make sure that deleting recalculates, we check the location before every draw. - /// - [Serializable] - public sealed class StepLabelContainer : DrawableContainer { - [NonSerialized] - private StringFormat _stringFormat = new StringFormat(); +namespace Greenshot.Drawing +{ + /// + /// This is an enumerated label, every single StepLabelContainer shows the number of the order it was created. + /// To make sure that deleting recalculates, we check the location before every draw. + /// + [Serializable] + public sealed class StepLabelContainer : DrawableContainer + { + [NonSerialized] private StringFormat _stringFormat = new StringFormat(); - private readonly bool _drawAsRectangle = false; + private readonly bool _drawAsRectangle = false; - public StepLabelContainer(Surface parent) : base(parent) { - parent.AddStepLabel(this); - InitContent(); - Init(); - } + public StepLabelContainer(Surface parent) : base(parent) + { + parent.AddStepLabel(this); + InitContent(); + Init(); + } - private void Init() - { - CreateDefaultAdorners(); - } + private void Init() + { + CreateDefaultAdorners(); + } // Used to store the number of this label, so when deserializing it can be placed back to the StepLabels list in the right location - private int _number; - // Used to store the counter start of the Surface, as the surface is NOT stored. - private int _counterStart = 1; - public int Number { - get { - return _number; - } - set { - _number = value; - } - } + private int _number; - /// - /// Retrieve the counter before serializing - /// - /// - [OnSerializing] - private void SetValuesOnSerializing(StreamingContext context) { - if (Parent != null) { - Number = ((Surface)Parent).CountStepLabels(this); - _counterStart = ((Surface) Parent).CounterStart; - } - } + // Used to store the counter start of the Surface, as the surface is NOT stored. + private int _counterStart = 1; + + public int Number + { + get { return _number; } + set { _number = value; } + } /// - /// Restore values that don't serialize - /// - /// - protected override void OnDeserialized(StreamingContext context) - { - Init(); - _stringFormat = new StringFormat - { - Alignment = StringAlignment.Center, - LineAlignment = StringAlignment.Center - }; + /// Retrieve the counter before serializing + /// + /// + [OnSerializing] + private void SetValuesOnSerializing(StreamingContext context) + { + if (Parent != null) + { + Number = ((Surface) Parent).CountStepLabels(this); + _counterStart = ((Surface) Parent).CounterStart; + } + } - } + /// + /// Restore values that don't serialize + /// + /// + protected override void OnDeserialized(StreamingContext context) + { + Init(); + _stringFormat = new StringFormat + { + Alignment = StringAlignment.Center, + LineAlignment = StringAlignment.Center + }; + } - /// - /// Add the StepLabel to the parent - /// - /// - protected override void SwitchParent(Surface newParent) { - if (newParent == Parent) - { - return; - } - ((Surface) Parent)?.RemoveStepLabel(this); - base.SwitchParent(newParent); - if (newParent == null) - { - return; - } - // Make sure the counter start is restored (this unfortunately happens multiple times... -> hack) - newParent.CounterStart = _counterStart; - newParent.AddStepLabel(this); - } + /// + /// Add the StepLabel to the parent + /// + /// + protected override void SwitchParent(Surface newParent) + { + if (newParent == Parent) + { + return; + } - public override Size DefaultSize => new Size(30, 30); + ((Surface) Parent)?.RemoveStepLabel(this); + base.SwitchParent(newParent); + if (newParent == null) + { + return; + } - public override bool InitContent() { - _defaultEditMode = EditStatus.IDLE; - _stringFormat.Alignment = StringAlignment.Center; - _stringFormat.LineAlignment = StringAlignment.Center; + // Make sure the counter start is restored (this unfortunately happens multiple times... -> hack) + newParent.CounterStart = _counterStart; + newParent.AddStepLabel(this); + } - // Set defaults - Width = DefaultSize.Width; - Height = DefaultSize.Height; + public override Size DefaultSize => new Size(30, 30); - return true; - } + public override bool InitContent() + { + _defaultEditMode = EditStatus.IDLE; + _stringFormat.Alignment = StringAlignment.Center; + _stringFormat.LineAlignment = StringAlignment.Center; - /// - /// This makes it possible for the label to be placed exactly in the middle of the pointer. - /// - public override bool HandleMouseDown(int mouseX, int mouseY) { - return base.HandleMouseDown(mouseX - Width / 2, mouseY - Height / 2); - } + // Set defaults + Width = DefaultSize.Width; + Height = DefaultSize.Height; - /// - /// We set our own field values - /// - protected override void InitializeFields() { - AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed); - AddField(GetType(), FieldType.LINE_COLOR, Color.White); - AddField(GetType(), FieldType.FLAGS, FieldFlag.COUNTER); - } + return true; + } - /// - /// Make sure this element is no longer referenced from the surface - /// - protected override void Dispose(bool disposing) { - base.Dispose(disposing); - if (!disposing) { - return; - } - ((Surface) Parent)?.RemoveStepLabel(this); - if (_stringFormat == null) - { - return; - } - _stringFormat.Dispose(); - _stringFormat = null; - } + /// + /// This makes it possible for the label to be placed exactly in the middle of the pointer. + /// + public override bool HandleMouseDown(int mouseX, int mouseY) + { + return base.HandleMouseDown(mouseX - Width / 2, mouseY - Height / 2); + } - public override bool HandleMouseMove(int x, int y) { - Invalidate(); - Left = x - Width / 2; - Top = y - Height / 2; - Invalidate(); - return true; - } + /// + /// We set our own field values + /// + protected override void InitializeFields() + { + AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed); + AddField(GetType(), FieldType.LINE_COLOR, Color.White); + AddField(GetType(), FieldType.FLAGS, FieldFlag.COUNTER); + } - /// - /// Override the parent, calculate the label number, than draw - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode rm) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; - string text = ((Surface)Parent).CountStepLabels(this).ToString(); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - if (_drawAsRectangle) { - RectangleContainer.DrawRectangle(rect, graphics, rm, 0, Color.Transparent, fillColor, false); - } else { - EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false); - } + /// + /// Make sure this element is no longer referenced from the surface + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + { + return; + } - float fontSize = Math.Min(Width,Height) / 1.4f; + ((Surface) Parent)?.RemoveStepLabel(this); + if (_stringFormat == null) + { + return; + } + + _stringFormat.Dispose(); + _stringFormat = null; + } + + public override bool HandleMouseMove(int x, int y) + { + Invalidate(); + Left = x - Width / 2; + Top = y - Height / 2; + Invalidate(); + return true; + } + + /// + /// Override the parent, calculate the label number, than draw + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode rm) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; + string text = ((Surface) Parent).CountStepLabels(this).ToString(); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + if (_drawAsRectangle) + { + RectangleContainer.DrawRectangle(rect, graphics, rm, 0, Color.Transparent, fillColor, false); + } + else + { + EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false); + } + + float fontSize = Math.Min(Width, Height) / 1.4f; using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name); using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel); TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font); } - public override bool ClickableAt(int x, int y) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - if (_drawAsRectangle) { - return RectangleContainer.RectangleClickableAt(rect, 0, fillColor, x, y); - } + public override bool ClickableAt(int x, int y) + { + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + if (_drawAsRectangle) + { + return RectangleContainer.RectangleClickableAt(rect, 0, fillColor, x, y); + } return EllipseContainer.EllipseClickableAt(rect, 0, fillColor, x, y); } - } -} + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Surface.cs b/src/Greenshot/Drawing/Surface.cs index ed3118db6..4dd3c55bd 100644 --- a/src/Greenshot/Drawing/Surface.cs +++ b/src/Greenshot/Drawing/Surface.cs @@ -43,843 +43,857 @@ using GreenshotPlugin.Interfaces.Drawing.Adorners; namespace Greenshot.Drawing { - /// - /// Description of Surface. - /// - public sealed class Surface : Control, ISurface, INotifyPropertyChanged - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface)); - public static int Count; - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + /// + /// Description of Surface. + /// + public sealed class Surface : Control, ISurface, INotifyPropertyChanged + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface)); + public static int Count; + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - // Property to identify the Surface ID - private Guid _uniqueId = Guid.NewGuid(); + // Property to identify the Surface ID + private Guid _uniqueId = Guid.NewGuid(); - /// - /// This value is used to start counting the step labels - /// - private int _counterStart = 1; + /// + /// This value is used to start counting the step labels + /// + private int _counterStart = 1; - /// - /// The GUID of the surface - /// - public Guid ID - { - get => _uniqueId; + /// + /// The GUID of the surface + /// + public Guid ID + { + get => _uniqueId; set => _uniqueId = value; } - /// - /// Event handlers (do not serialize!) - /// - [NonSerialized] - private PropertyChangedEventHandler _propertyChanged; - public event PropertyChangedEventHandler PropertyChanged - { - add => _propertyChanged += value; + /// + /// Event handlers (do not serialize!) + /// + [NonSerialized] private PropertyChangedEventHandler _propertyChanged; + + public event PropertyChangedEventHandler PropertyChanged + { + add => _propertyChanged += value; remove => _propertyChanged -= value; } - [NonSerialized] - private SurfaceElementEventHandler _movingElementChanged; - public event SurfaceElementEventHandler MovingElementChanged + [NonSerialized] private SurfaceElementEventHandler _movingElementChanged; + + public event SurfaceElementEventHandler MovingElementChanged { add => _movingElementChanged += value; remove => _movingElementChanged -= value; } - [NonSerialized] - private SurfaceDrawingModeEventHandler _drawingModeChanged; - public event SurfaceDrawingModeEventHandler DrawingModeChanged - { - add => _drawingModeChanged += value; + [NonSerialized] private SurfaceDrawingModeEventHandler _drawingModeChanged; + + public event SurfaceDrawingModeEventHandler DrawingModeChanged + { + add => _drawingModeChanged += value; remove => _drawingModeChanged -= value; } - [NonSerialized] - private SurfaceSizeChangeEventHandler _surfaceSizeChanged; - public event SurfaceSizeChangeEventHandler SurfaceSizeChanged - { - add => _surfaceSizeChanged += value; + + [NonSerialized] private SurfaceSizeChangeEventHandler _surfaceSizeChanged; + + public event SurfaceSizeChangeEventHandler SurfaceSizeChanged + { + add => _surfaceSizeChanged += value; remove => _surfaceSizeChanged -= value; } - [NonSerialized] - private SurfaceMessageEventHandler _surfaceMessage; - public event SurfaceMessageEventHandler SurfaceMessage - { - add => _surfaceMessage += value; + + [NonSerialized] private SurfaceMessageEventHandler _surfaceMessage; + + public event SurfaceMessageEventHandler SurfaceMessage + { + add => _surfaceMessage += value; remove => _surfaceMessage -= value; } - /// - /// inUndoRedo makes sure we don't undo/redo while in a undo/redo action - /// - [NonSerialized] - private bool _inUndoRedo; + /// + /// inUndoRedo makes sure we don't undo/redo while in a undo/redo action + /// + [NonSerialized] private bool _inUndoRedo; - /// - /// Make only one surface move cycle undoable, see SurfaceMouseMove - /// - [NonSerialized] - private bool _isSurfaceMoveMadeUndoable; + /// + /// Make only one surface move cycle undoable, see SurfaceMouseMove + /// + [NonSerialized] private bool _isSurfaceMoveMadeUndoable; - /// - /// Undo/Redo stacks, should not be serialized as the file would be way to big - /// - [NonSerialized] - private readonly Stack _undoStack = new Stack(); - [NonSerialized] - private readonly Stack _redoStack = new Stack(); + /// + /// Undo/Redo stacks, should not be serialized as the file would be way to big + /// + [NonSerialized] private readonly Stack _undoStack = new Stack(); - /// - /// Last save location, do not serialize! - /// - [NonSerialized] - private string _lastSaveFullPath; + [NonSerialized] private readonly Stack _redoStack = new Stack(); - /// - /// current drawing mode, do not serialize! - /// - [NonSerialized] - private DrawingModes _drawingMode = DrawingModes.None; + /// + /// Last save location, do not serialize! + /// + [NonSerialized] private string _lastSaveFullPath; - /// - /// the keys-locked flag helps with focus issues - /// - [NonSerialized] - private bool _keysLocked; + /// + /// current drawing mode, do not serialize! + /// + [NonSerialized] private DrawingModes _drawingMode = DrawingModes.None; - /// - /// Location of the mouse-down (it "starts" here), do not serialize - /// - [NonSerialized] - private Point _mouseStart = Point.Empty; + /// + /// the keys-locked flag helps with focus issues + /// + [NonSerialized] private bool _keysLocked; - /// - /// are we in a mouse down, do not serialize - /// - [NonSerialized] - private bool _mouseDown; + /// + /// Location of the mouse-down (it "starts" here), do not serialize + /// + [NonSerialized] private Point _mouseStart = Point.Empty; - /// - /// The selected element for the mouse down, do not serialize - /// - [NonSerialized] - private IDrawableContainer _mouseDownElement; + /// + /// are we in a mouse down, do not serialize + /// + [NonSerialized] private bool _mouseDown; - /// - /// all selected elements, do not serialize - /// - [NonSerialized] - private readonly IDrawableContainerList selectedElements; + /// + /// The selected element for the mouse down, do not serialize + /// + [NonSerialized] private IDrawableContainer _mouseDownElement; - /// - /// the element we are drawing with, do not serialize - /// - [NonSerialized] - private IDrawableContainer _drawingElement; + /// + /// all selected elements, do not serialize + /// + [NonSerialized] private readonly IDrawableContainerList selectedElements; - /// - /// the element we want to draw with (not yet drawn), do not serialize - /// - [NonSerialized] - private IDrawableContainer _undrawnElement; + /// + /// the element we are drawing with, do not serialize + /// + [NonSerialized] private IDrawableContainer _drawingElement; - /// - /// the cropcontainer, when cropping this is set, do not serialize - /// - [NonSerialized] - private IDrawableContainer _cropContainer; + /// + /// the element we want to draw with (not yet drawn), do not serialize + /// + [NonSerialized] private IDrawableContainer _undrawnElement; - /// - /// the brush which is used for transparent backgrounds, set by the editor, do not serialize - /// - [NonSerialized] - private Brush _transparencyBackgroundBrush; + /// + /// the cropcontainer, when cropping this is set, do not serialize + /// + [NonSerialized] private IDrawableContainer _cropContainer; - /// - /// The buffer is only for drawing on it when using filters (to supply access) - /// This saves a lot of "create new bitmap" commands - /// Should not be serialized, as it's generated. - /// The actual bitmap is in the paintbox... - /// TODO: Check if this buffer is still needed! - /// - [NonSerialized] - private Bitmap _buffer; + /// + /// the brush which is used for transparent backgrounds, set by the editor, do not serialize + /// + [NonSerialized] private Brush _transparencyBackgroundBrush; - /// - /// all stepLabels for the surface, needed with serialization - /// - private readonly List _stepLabels = new List(); + /// + /// The buffer is only for drawing on it when using filters (to supply access) + /// This saves a lot of "create new bitmap" commands + /// Should not be serialized, as it's generated. + /// The actual bitmap is in the paintbox... + /// TODO: Check if this buffer is still needed! + /// + [NonSerialized] private Bitmap _buffer; - public void AddStepLabel(StepLabelContainer stepLabel) - { - if (!_stepLabels.Contains(stepLabel)) - { - _stepLabels.Add(stepLabel); - } - } + /// + /// all stepLabels for the surface, needed with serialization + /// + private readonly List _stepLabels = new List(); - public void RemoveStepLabel(StepLabelContainer stepLabel) - { - _stepLabels.Remove(stepLabel); - } + public void AddStepLabel(StepLabelContainer stepLabel) + { + if (!_stepLabels.Contains(stepLabel)) + { + _stepLabels.Add(stepLabel); + } + } - /// - /// The start value of the counter objects - /// - public int CounterStart - { - get => _counterStart; + public void RemoveStepLabel(StepLabelContainer stepLabel) + { + _stepLabels.Remove(stepLabel); + } + + /// + /// The start value of the counter objects + /// + public int CounterStart + { + get => _counterStart; set - { - if (_counterStart == value) - { - return; - } + { + if (_counterStart == value) + { + return; + } - _counterStart = value; - Invalidate(); - _propertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CounterStart))); - } - } + _counterStart = value; + Invalidate(); + _propertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CounterStart))); + } + } - /// - /// Count all the VISIBLE steplabels in the surface, up to the supplied one - /// - /// can be null, if not the counting stops here - /// number of steplabels before the supplied container - public int CountStepLabels(IDrawableContainer stopAtContainer) - { - int number = CounterStart; - foreach (var possibleThis in _stepLabels) - { - if (possibleThis.Equals(stopAtContainer)) - { - break; - } - if (IsOnSurface(possibleThis)) - { - number++; - } - } - return number; - } + /// + /// Count all the VISIBLE steplabels in the surface, up to the supplied one + /// + /// can be null, if not the counting stops here + /// number of steplabels before the supplied container + public int CountStepLabels(IDrawableContainer stopAtContainer) + { + int number = CounterStart; + foreach (var possibleThis in _stepLabels) + { + if (possibleThis.Equals(stopAtContainer)) + { + break; + } - /// - /// all elements on the surface, needed with serialization - /// - private readonly IDrawableContainerList _elements; + if (IsOnSurface(possibleThis)) + { + number++; + } + } - /// - /// all elements on the surface, needed with serialization - /// - private FieldAggregator _fieldAggregator; + return number; + } - /// - /// the cursor container, needed with serialization as we need a direct acces to it. - /// - private IDrawableContainer _cursorContainer; + /// + /// all elements on the surface, needed with serialization + /// + private readonly IDrawableContainerList _elements; - /// - /// the modified flag specifies if the surface has had modifications after the last export. - /// Initial state is modified, as "it's not saved" - /// After serialization this should actually be "false" (the surface came from a stream) - /// For now we just serialize it... - /// - private bool _modified = true; + /// + /// all elements on the surface, needed with serialization + /// + private FieldAggregator _fieldAggregator; - /// - /// The image is the actual captured image, needed with serialization - /// - private Image _image; - public Image Image - { - get => _image; + /// + /// the cursor container, needed with serialization as we need a direct acces to it. + /// + private IDrawableContainer _cursorContainer; + + /// + /// the modified flag specifies if the surface has had modifications after the last export. + /// Initial state is modified, as "it's not saved" + /// After serialization this should actually be "false" (the surface came from a stream) + /// For now we just serialize it... + /// + private bool _modified = true; + + /// + /// The image is the actual captured image, needed with serialization + /// + private Image _image; + + public Image Image + { + get => _image; set - { - _image = value; - UpdateSize(); - } - } + { + _image = value; + UpdateSize(); + } + } - [NonSerialized] - private Matrix _zoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); - [NonSerialized] - private Matrix _inverseZoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); - [NonSerialized] - private Fraction _zoomFactor = Fraction.Identity; - public Fraction ZoomFactor - { - get => _zoomFactor; - set - { - _zoomFactor = value; - var inverse = _zoomFactor.Inverse(); - _zoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0); - _inverseZoomMatrix = new Matrix(inverse, 0, 0, inverse, 0, 0); - UpdateSize(); - } - } + [NonSerialized] private Matrix _zoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); + [NonSerialized] private Matrix _inverseZoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); + [NonSerialized] private Fraction _zoomFactor = Fraction.Identity; + + public Fraction ZoomFactor + { + get => _zoomFactor; + set + { + _zoomFactor = value; + var inverse = _zoomFactor.Inverse(); + _zoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0); + _inverseZoomMatrix = new Matrix(inverse, 0, 0, inverse, 0, 0); + UpdateSize(); + } + } - /// - /// Sets the surface size as zoomed image size. - /// - private void UpdateSize() - { - var size = _image.Size; - Size = new Size((int)(size.Width * _zoomFactor), (int)(size.Height * _zoomFactor)); - } + /// + /// Sets the surface size as zoomed image size. + /// + private void UpdateSize() + { + var size = _image.Size; + Size = new Size((int) (size.Width * _zoomFactor), (int) (size.Height * _zoomFactor)); + } - /// - /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements. - /// e.g. used to decided if and which line thickness is shown when multiple elements are selected. - /// - public FieldAggregator FieldAggregator - { - get => _fieldAggregator; + /// + /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements. + /// e.g. used to decided if and which line thickness is shown when multiple elements are selected. + /// + public FieldAggregator FieldAggregator + { + get => _fieldAggregator; set => _fieldAggregator = value; } - /// - /// The cursor container has it's own accessor so we can find and remove this (when needed) - /// - public IDrawableContainer CursorContainer => _cursorContainer; + /// + /// The cursor container has it's own accessor so we can find and remove this (when needed) + /// + public IDrawableContainer CursorContainer => _cursorContainer; - /// - /// A simple getter to ask if this surface has a cursor - /// - public bool HasCursor => _cursorContainer != null; + /// + /// A simple getter to ask if this surface has a cursor + /// + public bool HasCursor => _cursorContainer != null; - /// - /// A simple helper method to remove the cursor from the surface - /// - public void RemoveCursor() - { - RemoveElement(_cursorContainer); - _cursorContainer = null; - } + /// + /// A simple helper method to remove the cursor from the surface + /// + public void RemoveCursor() + { + RemoveElement(_cursorContainer); + _cursorContainer = null; + } - /// - /// The brush which is used to draw the transparent background - /// - public Brush TransparencyBackgroundBrush - { - get => _transparencyBackgroundBrush; + /// + /// The brush which is used to draw the transparent background + /// + public Brush TransparencyBackgroundBrush + { + get => _transparencyBackgroundBrush; set => _transparencyBackgroundBrush = value; } - /// - /// Are the keys on this surface locked? - /// - public bool KeysLocked - { - get => _keysLocked; + /// + /// Are the keys on this surface locked? + /// + public bool KeysLocked + { + get => _keysLocked; set => _keysLocked = value; } - /// - /// Is this surface modified? This is only true if the surface has not been exported. - /// - public bool Modified - { - get => _modified; + /// + /// Is this surface modified? This is only true if the surface has not been exported. + /// + public bool Modified + { + get => _modified; set => _modified = value; } - /// - /// The DrawingMode property specifies the mode for drawing, more or less the element type. - /// - public DrawingModes DrawingMode - { - get => _drawingMode; + /// + /// The DrawingMode property specifies the mode for drawing, more or less the element type. + /// + public DrawingModes DrawingMode + { + get => _drawingMode; set - { - _drawingMode = value; - if (_drawingModeChanged != null) - { - SurfaceDrawingModeEventArgs eventArgs = new SurfaceDrawingModeEventArgs - { - DrawingMode = _drawingMode - }; - _drawingModeChanged.Invoke(this, eventArgs); - } - DeselectAllElements(); - CreateUndrawnElement(); - } - } + { + _drawingMode = value; + if (_drawingModeChanged != null) + { + SurfaceDrawingModeEventArgs eventArgs = new SurfaceDrawingModeEventArgs + { + DrawingMode = _drawingMode + }; + _drawingModeChanged.Invoke(this, eventArgs); + } - /// - /// Property for accessing the last save "full" path - /// - public string LastSaveFullPath - { - get => _lastSaveFullPath; + DeselectAllElements(); + CreateUndrawnElement(); + } + } + + /// + /// Property for accessing the last save "full" path + /// + public string LastSaveFullPath + { + get => _lastSaveFullPath; set => _lastSaveFullPath = value; } - /// - /// Property for accessing the URL to which the surface was recently uploaded - /// - public string UploadUrl - { - get; - set; - } + /// + /// Property for accessing the URL to which the surface was recently uploaded + /// + public string UploadUrl { get; set; } - /// - /// Property for accessing the capture details - /// - public ICaptureDetails CaptureDetails { get; set; } + /// + /// Property for accessing the capture details + /// + public ICaptureDetails CaptureDetails { get; set; } - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// - public void AdjustToDpi(uint dpi) - { - foreach (var element in this._elements) { - element.AdjustToDpi(dpi); - } - } + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// + public void AdjustToDpi(uint dpi) + { + foreach (var element in this._elements) + { + element.AdjustToDpi(dpi); + } + } - /// - /// Base Surface constructor - /// - public Surface() - { - _fieldAggregator = new FieldAggregator(this); - Count++; - _elements = new DrawableContainerList(_uniqueId); - selectedElements = new DrawableContainerList(_uniqueId); - LOG.Debug("Creating surface!"); - MouseDown += SurfaceMouseDown; - MouseUp += SurfaceMouseUp; - MouseMove += SurfaceMouseMove; - MouseDoubleClick += SurfaceDoubleClick; - Paint += SurfacePaint; - AllowDrop = true; - DragDrop += OnDragDrop; - DragEnter += OnDragEnter; - // bind selected & elements to this, otherwise they can't inform of modifications - selectedElements.Parent = this; - _elements.Parent = this; - // Make sure we are visible - Visible = true; - TabStop = false; - // Enable double buffering - DoubleBuffered = true; - SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.ContainerControl | ControlStyles.OptimizedDoubleBuffer | ControlStyles.SupportsTransparentBackColor, true); - } + /// + /// Base Surface constructor + /// + public Surface() + { + _fieldAggregator = new FieldAggregator(this); + Count++; + _elements = new DrawableContainerList(_uniqueId); + selectedElements = new DrawableContainerList(_uniqueId); + LOG.Debug("Creating surface!"); + MouseDown += SurfaceMouseDown; + MouseUp += SurfaceMouseUp; + MouseMove += SurfaceMouseMove; + MouseDoubleClick += SurfaceDoubleClick; + Paint += SurfacePaint; + AllowDrop = true; + DragDrop += OnDragDrop; + DragEnter += OnDragEnter; + // bind selected & elements to this, otherwise they can't inform of modifications + selectedElements.Parent = this; + _elements.Parent = this; + // Make sure we are visible + Visible = true; + TabStop = false; + // Enable double buffering + DoubleBuffered = true; + SetStyle( + ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.ContainerControl | ControlStyles.OptimizedDoubleBuffer | + ControlStyles.SupportsTransparentBackColor, true); + } - /// - /// Private method, the current image is disposed the new one will stay. - /// - /// The new image - /// true if the old image needs to be disposed, when using undo this should not be true!! - private void SetImage(Image newImage, bool dispose) - { - // Dispose - if (_image != null && dispose) - { - _image.Dispose(); - } + /// + /// Private method, the current image is disposed the new one will stay. + /// + /// The new image + /// true if the old image needs to be disposed, when using undo this should not be true!! + private void SetImage(Image newImage, bool dispose) + { + // Dispose + if (_image != null && dispose) + { + _image.Dispose(); + } - // Set new values - Image = newImage; + // Set new values + Image = newImage; - _modified = true; - } + _modified = true; + } - /// - /// Surface constructor with an image - /// - /// - public Surface(Image newImage) : this() - { - LOG.DebugFormat("Got image with dimensions {0} and format {1}", newImage.Size, newImage.PixelFormat); - SetImage(newImage, true); - } + /// + /// Surface constructor with an image + /// + /// + public Surface(Image newImage) : this() + { + LOG.DebugFormat("Got image with dimensions {0} and format {1}", newImage.Size, newImage.PixelFormat); + SetImage(newImage, true); + } - /// - /// Surface contructor with a capture - /// - /// - public Surface(ICapture capture) : this(capture.Image) - { - // check if cursor is captured, and visible - if (capture.Cursor != null && capture.CursorVisible) - { - Rectangle cursorRect = new Rectangle(capture.CursorLocation, capture.Cursor.Size); - Rectangle captureRect = new Rectangle(Point.Empty, capture.Image.Size); - // check if cursor is on the capture, otherwise we leave it out. - if (cursorRect.IntersectsWith(captureRect)) - { - _cursorContainer = AddIconContainer(capture.Cursor, capture.CursorLocation.X, capture.CursorLocation.Y); - SelectElement(_cursorContainer); - } - } - // Make sure the image is NOT disposed, we took the reference directly into ourselves - ((Capture)capture).NullImage(); + /// + /// Surface contructor with a capture + /// + /// + public Surface(ICapture capture) : this(capture.Image) + { + // check if cursor is captured, and visible + if (capture.Cursor != null && capture.CursorVisible) + { + Rectangle cursorRect = new Rectangle(capture.CursorLocation, capture.Cursor.Size); + Rectangle captureRect = new Rectangle(Point.Empty, capture.Image.Size); + // check if cursor is on the capture, otherwise we leave it out. + if (cursorRect.IntersectsWith(captureRect)) + { + _cursorContainer = AddIconContainer(capture.Cursor, capture.CursorLocation.X, capture.CursorLocation.Y); + SelectElement(_cursorContainer); + } + } - CaptureDetails = capture.CaptureDetails; - } + // Make sure the image is NOT disposed, we took the reference directly into ourselves + ((Capture) capture).NullImage(); - protected override void Dispose(bool disposing) - { - if (disposing) - { - Count--; - LOG.Debug("Disposing surface!"); - if (_buffer != null) - { - _buffer.Dispose(); - _buffer = null; - } - if (_transparencyBackgroundBrush != null) - { - _transparencyBackgroundBrush.Dispose(); - _transparencyBackgroundBrush = null; - } + CaptureDetails = capture.CaptureDetails; + } - // Cleanup undo/redo stacks - while (_undoStack != null && _undoStack.Count > 0) - { - _undoStack.Pop().Dispose(); - } - while (_redoStack != null && _redoStack.Count > 0) - { - _redoStack.Pop().Dispose(); - } - foreach (IDrawableContainer container in _elements) - { - container.Dispose(); - } - if (_undrawnElement != null) - { - _undrawnElement.Dispose(); - _undrawnElement = null; - } - if (_cropContainer != null) - { - _cropContainer.Dispose(); - _cropContainer = null; - } - } - base.Dispose(disposing); - } + protected override void Dispose(bool disposing) + { + if (disposing) + { + Count--; + LOG.Debug("Disposing surface!"); + if (_buffer != null) + { + _buffer.Dispose(); + _buffer = null; + } - /// - /// Undo the last action - /// - public void Undo() - { - if (_undoStack.Count > 0) - { - _inUndoRedo = true; - IMemento top = _undoStack.Pop(); - _redoStack.Push(top.Restore()); - _inUndoRedo = false; - } - } + if (_transparencyBackgroundBrush != null) + { + _transparencyBackgroundBrush.Dispose(); + _transparencyBackgroundBrush = null; + } - /// - /// Undo an undo (=redo) - /// - public void Redo() - { - if (_redoStack.Count > 0) - { - _inUndoRedo = true; - IMemento top = _redoStack.Pop(); - _undoStack.Push(top.Restore()); - _inUndoRedo = false; - } - } + // Cleanup undo/redo stacks + while (_undoStack != null && _undoStack.Count > 0) + { + _undoStack.Pop().Dispose(); + } - /// - /// Returns if the surface can do a undo - /// - public bool CanUndo => _undoStack.Count > 0; + while (_redoStack != null && _redoStack.Count > 0) + { + _redoStack.Pop().Dispose(); + } - /// - /// Returns if the surface can do a redo - /// - public bool CanRedo => _redoStack.Count > 0; + foreach (IDrawableContainer container in _elements) + { + container.Dispose(); + } - /// - /// Get the language key for the undo action - /// - public LangKey UndoActionLanguageKey => LangKey.none; + if (_undrawnElement != null) + { + _undrawnElement.Dispose(); + _undrawnElement = null; + } - /// - /// Get the language key for redo action - /// - public LangKey RedoActionLanguageKey => LangKey.none; + if (_cropContainer != null) + { + _cropContainer.Dispose(); + _cropContainer = null; + } + } - /// - /// Make an action undo-able - /// - /// The memento implementing the undo - /// Allow changes to be merged - public void MakeUndoable(IMemento memento, bool allowMerge) - { - if (_inUndoRedo) - { - throw new InvalidOperationException("Invoking do within an undo/redo action."); - } - if (memento != null) - { - bool allowPush = true; - if (_undoStack.Count > 0 && allowMerge) - { - // Check if merge is possible - allowPush = !_undoStack.Peek().Merge(memento); - } - if (allowPush) - { - // Clear the redo-stack and dispose - while (_redoStack.Count > 0) - { - _redoStack.Pop().Dispose(); - } - _undoStack.Push(memento); - } - } - } + base.Dispose(disposing); + } - /// - /// This saves the elements of this surface to a stream. - /// Is used to save a template of the complete surface - /// - /// - /// - public long SaveElementsToStream(Stream streamWrite) - { - long bytesWritten = 0; - try - { - long lengtBefore = streamWrite.Length; - BinaryFormatter binaryWrite = new BinaryFormatter(); - binaryWrite.Serialize(streamWrite, _elements); - bytesWritten = streamWrite.Length - lengtBefore; - } - catch (Exception e) - { - LOG.Error("Error serializing elements to stream.", e); - } - return bytesWritten; - } + /// + /// Undo the last action + /// + public void Undo() + { + if (_undoStack.Count > 0) + { + _inUndoRedo = true; + IMemento top = _undoStack.Pop(); + _redoStack.Push(top.Restore()); + _inUndoRedo = false; + } + } - /// - /// This loads elements from a stream, among others this is used to load a surface. - /// - /// - public void LoadElementsFromStream(Stream streamRead) - { - try - { - BinaryFormatter binaryRead = new BinaryFormatter(); - IDrawableContainerList loadedElements = (IDrawableContainerList)binaryRead.Deserialize(streamRead); - loadedElements.Parent = this; - // Make sure the steplabels are sorted accoring to their number - _stepLabels.Sort((p1, p2) => p1.Number.CompareTo(p2.Number)); - DeselectAllElements(); - AddElements(loadedElements); - SelectElements(loadedElements); - FieldAggregator.BindElements(loadedElements); - } - catch (Exception e) - { - LOG.Error("Error serializing elements from stream.", e); - } - } + /// + /// Undo an undo (=redo) + /// + public void Redo() + { + if (_redoStack.Count > 0) + { + _inUndoRedo = true; + IMemento top = _redoStack.Pop(); + _undoStack.Push(top.Restore()); + _inUndoRedo = false; + } + } - /// - /// This is called from the DrawingMode setter, which is not very correct... - /// But here an element is created which is not yet draw, thus "undrawnElement". - /// The element is than used while drawing on the surface. - /// - private void CreateUndrawnElement() - { - if (_undrawnElement != null) - { - FieldAggregator.UnbindElement(_undrawnElement); - } - switch (DrawingMode) - { - case DrawingModes.Rect: - _undrawnElement = new RectangleContainer(this); - break; - case DrawingModes.Ellipse: - _undrawnElement = new EllipseContainer(this); - break; - case DrawingModes.Text: - _undrawnElement = new TextContainer(this); - break; - case DrawingModes.SpeechBubble: - _undrawnElement = new SpeechbubbleContainer(this); - break; - case DrawingModes.StepLabel: - _undrawnElement = new StepLabelContainer(this); - break; - case DrawingModes.Line: - _undrawnElement = new LineContainer(this); - break; - case DrawingModes.Arrow: - _undrawnElement = new ArrowContainer(this); - break; - case DrawingModes.Highlight: - _undrawnElement = new HighlightContainer(this); - break; - case DrawingModes.Obfuscate: - _undrawnElement = new ObfuscateContainer(this); - break; - case DrawingModes.Crop: - _cropContainer = new CropContainer(this); - _undrawnElement = _cropContainer; - break; - case DrawingModes.Bitmap: - _undrawnElement = new ImageContainer(this); - break; - case DrawingModes.Path: - _undrawnElement = new FreehandContainer(this); - break; - case DrawingModes.None: - _undrawnElement = null; - break; - } - if (_undrawnElement != null) - { - FieldAggregator.BindElement(_undrawnElement); - } - } + /// + /// Returns if the surface can do a undo + /// + public bool CanUndo => _undoStack.Count > 0; - #region Plugin interface implementations - public IImageContainer AddImageContainer(Image image, int x, int y) - { - ImageContainer bitmapContainer = new ImageContainer(this) - { - Image = image, - Left = x, - Top = y - }; - AddElement(bitmapContainer); - return bitmapContainer; - } + /// + /// Returns if the surface can do a redo + /// + public bool CanRedo => _redoStack.Count > 0; - public IImageContainer AddImageContainer(string filename, int x, int y) - { - ImageContainer bitmapContainer = new ImageContainer(this); - bitmapContainer.Load(filename); - bitmapContainer.Left = x; - bitmapContainer.Top = y; - AddElement(bitmapContainer); - return bitmapContainer; - } - public IIconContainer AddIconContainer(Icon icon, int x, int y) - { - IconContainer iconContainer = new IconContainer(this) - { - Icon = icon, - Left = x, - Top = y - }; - AddElement(iconContainer); - return iconContainer; - } - public IIconContainer AddIconContainer(string filename, int x, int y) - { - IconContainer iconContainer = new IconContainer(this); - iconContainer.Load(filename); - iconContainer.Left = x; - iconContainer.Top = y; - AddElement(iconContainer); - return iconContainer; - } - public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y) - { - CursorContainer cursorContainer = new CursorContainer(this) - { - Cursor = cursor, - Left = x, - Top = y - }; - AddElement(cursorContainer); - return cursorContainer; - } - public ICursorContainer AddCursorContainer(string filename, int x, int y) - { - CursorContainer cursorContainer = new CursorContainer(this); - cursorContainer.Load(filename); - cursorContainer.Left = x; - cursorContainer.Top = y; - AddElement(cursorContainer); - return cursorContainer; - } + /// + /// Get the language key for the undo action + /// + public LangKey UndoActionLanguageKey => LangKey.none; - public ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor) - { - TextContainer textContainer = new TextContainer(this) {Text = text, Left = x, Top = y}; - textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name); - textContainer.SetFieldValue(FieldType.FONT_BOLD, bold); - textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic); - textContainer.SetFieldValue(FieldType.FONT_SIZE, size); - textContainer.SetFieldValue(FieldType.FILL_COLOR, fillColor); - textContainer.SetFieldValue(FieldType.LINE_COLOR, color); - textContainer.SetFieldValue(FieldType.LINE_THICKNESS, borderSize); - textContainer.SetFieldValue(FieldType.SHADOW, shadow); - // Make sure the Text fits - textContainer.FitToText(); + /// + /// Get the language key for redo action + /// + public LangKey RedoActionLanguageKey => LangKey.none; - //AggregatedProperties.UpdateElement(textContainer); - AddElement(textContainer); - return textContainer; - } - #endregion + /// + /// Make an action undo-able + /// + /// The memento implementing the undo + /// Allow changes to be merged + public void MakeUndoable(IMemento memento, bool allowMerge) + { + if (_inUndoRedo) + { + throw new InvalidOperationException("Invoking do within an undo/redo action."); + } - #region DragDrop + if (memento != null) + { + bool allowPush = true; + if (_undoStack.Count > 0 && allowMerge) + { + // Check if merge is possible + allowPush = !_undoStack.Peek().Merge(memento); + } - private void OnDragEnter(object sender, DragEventArgs e) - { - if (LOG.IsDebugEnabled) - { - LOG.Debug("DragEnter got following formats: "); - foreach (string format in ClipboardHelper.GetFormats(e.Data)) - { - LOG.Debug(format); - } - } - if ((e.AllowedEffect & DragDropEffects.Copy) != DragDropEffects.Copy) - { - e.Effect = DragDropEffects.None; - } - else - { - if (ClipboardHelper.ContainsImage(e.Data) || ClipboardHelper.ContainsFormat(e.Data, "DragImageBits")) - { - e.Effect = DragDropEffects.Copy; - } - else - { - e.Effect = DragDropEffects.None; - } - } - } + if (allowPush) + { + // Clear the redo-stack and dispose + while (_redoStack.Count > 0) + { + _redoStack.Pop().Dispose(); + } - /// - /// Handle the drag/drop - /// - /// - /// - private void OnDragDrop(object sender, DragEventArgs e) - { - Point mouse = PointToClient(new Point(e.X, e.Y)); - if (e.Data.GetDataPresent("Text")) - { - string possibleUrl = ClipboardHelper.GetText(e.Data); - // Test if it's an url and try to download the image so we have it in the original form - if (possibleUrl != null && possibleUrl.StartsWith("http")) + _undoStack.Push(memento); + } + } + } + + /// + /// This saves the elements of this surface to a stream. + /// Is used to save a template of the complete surface + /// + /// + /// + public long SaveElementsToStream(Stream streamWrite) + { + long bytesWritten = 0; + try + { + long lengtBefore = streamWrite.Length; + BinaryFormatter binaryWrite = new BinaryFormatter(); + binaryWrite.Serialize(streamWrite, _elements); + bytesWritten = streamWrite.Length - lengtBefore; + } + catch (Exception e) + { + LOG.Error("Error serializing elements to stream.", e); + } + + return bytesWritten; + } + + /// + /// This loads elements from a stream, among others this is used to load a surface. + /// + /// + public void LoadElementsFromStream(Stream streamRead) + { + try + { + BinaryFormatter binaryRead = new BinaryFormatter(); + IDrawableContainerList loadedElements = (IDrawableContainerList) binaryRead.Deserialize(streamRead); + loadedElements.Parent = this; + // Make sure the steplabels are sorted accoring to their number + _stepLabels.Sort((p1, p2) => p1.Number.CompareTo(p2.Number)); + DeselectAllElements(); + AddElements(loadedElements); + SelectElements(loadedElements); + FieldAggregator.BindElements(loadedElements); + } + catch (Exception e) + { + LOG.Error("Error serializing elements from stream.", e); + } + } + + /// + /// This is called from the DrawingMode setter, which is not very correct... + /// But here an element is created which is not yet draw, thus "undrawnElement". + /// The element is than used while drawing on the surface. + /// + private void CreateUndrawnElement() + { + if (_undrawnElement != null) + { + FieldAggregator.UnbindElement(_undrawnElement); + } + + switch (DrawingMode) + { + case DrawingModes.Rect: + _undrawnElement = new RectangleContainer(this); + break; + case DrawingModes.Ellipse: + _undrawnElement = new EllipseContainer(this); + break; + case DrawingModes.Text: + _undrawnElement = new TextContainer(this); + break; + case DrawingModes.SpeechBubble: + _undrawnElement = new SpeechbubbleContainer(this); + break; + case DrawingModes.StepLabel: + _undrawnElement = new StepLabelContainer(this); + break; + case DrawingModes.Line: + _undrawnElement = new LineContainer(this); + break; + case DrawingModes.Arrow: + _undrawnElement = new ArrowContainer(this); + break; + case DrawingModes.Highlight: + _undrawnElement = new HighlightContainer(this); + break; + case DrawingModes.Obfuscate: + _undrawnElement = new ObfuscateContainer(this); + break; + case DrawingModes.Crop: + _cropContainer = new CropContainer(this); + _undrawnElement = _cropContainer; + break; + case DrawingModes.Bitmap: + _undrawnElement = new ImageContainer(this); + break; + case DrawingModes.Path: + _undrawnElement = new FreehandContainer(this); + break; + case DrawingModes.None: + _undrawnElement = null; + break; + } + + if (_undrawnElement != null) + { + FieldAggregator.BindElement(_undrawnElement); + } + } + + #region Plugin interface implementations + + public IImageContainer AddImageContainer(Image image, int x, int y) + { + ImageContainer bitmapContainer = new ImageContainer(this) + { + Image = image, + Left = x, + Top = y + }; + AddElement(bitmapContainer); + return bitmapContainer; + } + + public IImageContainer AddImageContainer(string filename, int x, int y) + { + ImageContainer bitmapContainer = new ImageContainer(this); + bitmapContainer.Load(filename); + bitmapContainer.Left = x; + bitmapContainer.Top = y; + AddElement(bitmapContainer); + return bitmapContainer; + } + + public IIconContainer AddIconContainer(Icon icon, int x, int y) + { + IconContainer iconContainer = new IconContainer(this) + { + Icon = icon, + Left = x, + Top = y + }; + AddElement(iconContainer); + return iconContainer; + } + + public IIconContainer AddIconContainer(string filename, int x, int y) + { + IconContainer iconContainer = new IconContainer(this); + iconContainer.Load(filename); + iconContainer.Left = x; + iconContainer.Top = y; + AddElement(iconContainer); + return iconContainer; + } + + public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y) + { + CursorContainer cursorContainer = new CursorContainer(this) + { + Cursor = cursor, + Left = x, + Top = y + }; + AddElement(cursorContainer); + return cursorContainer; + } + + public ICursorContainer AddCursorContainer(string filename, int x, int y) + { + CursorContainer cursorContainer = new CursorContainer(this); + cursorContainer.Load(filename); + cursorContainer.Left = x; + cursorContainer.Top = y; + AddElement(cursorContainer); + return cursorContainer; + } + + public ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, + Color fillColor) + { + TextContainer textContainer = new TextContainer(this) + { + Text = text, + Left = x, + Top = y + }; + textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name); + textContainer.SetFieldValue(FieldType.FONT_BOLD, bold); + textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic); + textContainer.SetFieldValue(FieldType.FONT_SIZE, size); + textContainer.SetFieldValue(FieldType.FILL_COLOR, fillColor); + textContainer.SetFieldValue(FieldType.LINE_COLOR, color); + textContainer.SetFieldValue(FieldType.LINE_THICKNESS, borderSize); + textContainer.SetFieldValue(FieldType.SHADOW, shadow); + // Make sure the Text fits + textContainer.FitToText(); + + //AggregatedProperties.UpdateElement(textContainer); + AddElement(textContainer); + return textContainer; + } + + #endregion + + #region DragDrop + + private void OnDragEnter(object sender, DragEventArgs e) + { + if (LOG.IsDebugEnabled) + { + LOG.Debug("DragEnter got following formats: "); + foreach (string format in ClipboardHelper.GetFormats(e.Data)) + { + LOG.Debug(format); + } + } + + if ((e.AllowedEffect & DragDropEffects.Copy) != DragDropEffects.Copy) + { + e.Effect = DragDropEffects.None; + } + else + { + if (ClipboardHelper.ContainsImage(e.Data) || ClipboardHelper.ContainsFormat(e.Data, "DragImageBits")) + { + e.Effect = DragDropEffects.Copy; + } + else + { + e.Effect = DragDropEffects.None; + } + } + } + + /// + /// Handle the drag/drop + /// + /// + /// + private void OnDragDrop(object sender, DragEventArgs e) + { + Point mouse = PointToClient(new Point(e.X, e.Y)); + if (e.Data.GetDataPresent("Text")) + { + string possibleUrl = ClipboardHelper.GetText(e.Data); + // Test if it's an url and try to download the image so we have it in the original form + if (possibleUrl != null && possibleUrl.StartsWith("http")) { using Image image = NetworkHelper.DownloadImage(possibleUrl); if (image != null) @@ -888,1377 +902,1466 @@ namespace Greenshot.Drawing return; } } - } + } - foreach (Image image in ClipboardHelper.GetImages(e.Data)) - { - AddImageContainer(image, mouse.X, mouse.Y); - mouse.Offset(10, 10); - image.Dispose(); - } - } + foreach (Image image in ClipboardHelper.GetImages(e.Data)) + { + AddImageContainer(image, mouse.X, mouse.Y); + mouse.Offset(10, 10); + image.Dispose(); + } + } - #endregion + #endregion - /// - /// Auto crop the image - /// - /// true if cropped - public bool AutoCrop() - { - Rectangle cropRectangle; - using (Image tmpImage = GetImageForExport()) - { - cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference); - } - if (!IsCropPossible(ref cropRectangle)) - { - return false; - } - DeselectAllElements(); - // Maybe a bit obscure, but the following line creates a drop container - // It's available as "undrawnElement" - DrawingMode = DrawingModes.Crop; - _undrawnElement.Left = cropRectangle.X; - _undrawnElement.Top = cropRectangle.Y; - _undrawnElement.Width = cropRectangle.Width; - _undrawnElement.Height = cropRectangle.Height; - _undrawnElement.Status = EditStatus.UNDRAWN; - AddElement(_undrawnElement); - SelectElement(_undrawnElement); - _drawingElement = null; - _undrawnElement = null; - return true; - } + /// + /// Auto crop the image + /// + /// true if cropped + public bool AutoCrop() + { + Rectangle cropRectangle; + using (Image tmpImage = GetImageForExport()) + { + cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference); + } - /// - /// A simple clear - /// - /// The color for the background - public void Clear(Color newColor) - { - //create a blank bitmap the same size as original - Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty); - if (newBitmap != null) - { - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false); - SetImage(newBitmap, false); - Invalidate(); - } - } + if (!IsCropPossible(ref cropRectangle)) + { + return false; + } - /// - /// Apply a bitmap effect to the surface - /// - /// - public void ApplyBitmapEffect(IEffect effect) - { - BackgroundForm backgroundForm = new BackgroundForm("Effect", "Please wait"); - backgroundForm.Show(); - Application.DoEvents(); - try - { - Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); - Matrix matrix = new Matrix(); - Image newImage = ImageHelper.ApplyEffect(Image, effect, matrix); - if (newImage != null) - { - // Make sure the elements move according to the offset the effect made the bitmap move - _elements.Transform(matrix); - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); - SetImage(newImage, false); - Invalidate(); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) - { - _surfaceSizeChanged(this, null); - } - } - else - { - // clean up matrix, as it hasn't been used in the undo stack. - matrix.Dispose(); - } - } - finally - { - // Always close the background form - backgroundForm.CloseDialog(); - } - } + DeselectAllElements(); + // Maybe a bit obscure, but the following line creates a drop container + // It's available as "undrawnElement" + DrawingMode = DrawingModes.Crop; + _undrawnElement.Left = cropRectangle.X; + _undrawnElement.Top = cropRectangle.Y; + _undrawnElement.Width = cropRectangle.Width; + _undrawnElement.Height = cropRectangle.Height; + _undrawnElement.Status = EditStatus.UNDRAWN; + AddElement(_undrawnElement); + SelectElement(_undrawnElement); + _drawingElement = null; + _undrawnElement = null; + return true; + } - /// - /// check if a crop is possible - /// - /// - /// true if this is possible - public bool IsCropPossible(ref Rectangle cropRectangle) - { - cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); - if (cropRectangle.Left < 0) - { - cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); - } - if (cropRectangle.Top < 0) - { - cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); - } - if (cropRectangle.Left + cropRectangle.Width > Image.Width) - { - cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height); - } - if (cropRectangle.Top + cropRectangle.Height > Image.Height) - { - cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top); - } - if (cropRectangle.Height > 0 && cropRectangle.Width > 0) - { - return true; - } - return false; - } + /// + /// A simple clear + /// + /// The color for the background + public void Clear(Color newColor) + { + //create a blank bitmap the same size as original + Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty); + if (newBitmap != null) + { + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false); + SetImage(newBitmap, false); + Invalidate(); + } + } - /// - /// Use to send any registered SurfaceMessageEventHandler a message, e.g. used for the notification area - /// - /// Who send - /// Type of message - /// Message itself - public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message) - { - if (_surfaceMessage != null) - { - var eventArgs = new SurfaceMessageEventArgs - { - Message = message, - MessageType = messageType, - Surface = this - }; - _surfaceMessage(source, eventArgs); - } - } + /// + /// Apply a bitmap effect to the surface + /// + /// + public void ApplyBitmapEffect(IEffect effect) + { + BackgroundForm backgroundForm = new BackgroundForm("Effect", "Please wait"); + backgroundForm.Show(); + Application.DoEvents(); + try + { + Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); + Matrix matrix = new Matrix(); + Image newImage = ImageHelper.ApplyEffect(Image, effect, matrix); + if (newImage != null) + { + // Make sure the elements move according to the offset the effect made the bitmap move + _elements.Transform(matrix); + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); + SetImage(newImage, false); + Invalidate(); + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) + { + _surfaceSizeChanged(this, null); + } + } + else + { + // clean up matrix, as it hasn't been used in the undo stack. + matrix.Dispose(); + } + } + finally + { + // Always close the background form + backgroundForm.CloseDialog(); + } + } - /// - /// Crop the surface - /// - /// - /// - public bool ApplyCrop(Rectangle cropRectangle) - { - if (IsCropPossible(ref cropRectangle)) - { - Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); - Bitmap tmpImage; - // Make sure we have information, this this fails - try - { - tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); - } - catch (Exception ex) - { - ex.Data.Add("CropRectangle", cropRectangle); - ex.Data.Add("Width", Image.Width); - ex.Data.Add("Height", Image.Height); - ex.Data.Add("Pixelformat", Image.PixelFormat); - throw; - } + /// + /// check if a crop is possible + /// + /// + /// true if this is possible + public bool IsCropPossible(ref Rectangle cropRectangle) + { + cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); + if (cropRectangle.Left < 0) + { + cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); + } - Matrix matrix = new Matrix(); - matrix.Translate(-cropRectangle.Left, -cropRectangle.Top, MatrixOrder.Append); - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); + if (cropRectangle.Top < 0) + { + cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); + } - // Do not dispose otherwise we can't undo the image! - SetImage(tmpImage, false); - _elements.Transform(matrix); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) - { - _surfaceSizeChanged(this, null); - } - Invalidate(); - return true; - } - return false; - } + if (cropRectangle.Left + cropRectangle.Width > Image.Width) + { + cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height); + } - /// - /// The background here is the captured image. - /// This is called from the SurfaceBackgroundChangeMemento. - /// - /// - /// - public void UndoBackgroundChange(Image previous, Matrix matrix) - { - SetImage(previous, false); - if (matrix != null) - { - _elements.Transform(matrix); - } - _surfaceSizeChanged?.Invoke(this, null); - Invalidate(); - } - /// - /// Check if an adorner was "hit", and change the cursor if so - /// - /// MouseEventArgs - /// IAdorner - private IAdorner FindActiveAdorner(MouseEventArgs mouseEventArgs) - { - foreach (IDrawableContainer drawableContainer in selectedElements) - { - foreach (IAdorner adorner in drawableContainer.Adorners) - { + if (cropRectangle.Top + cropRectangle.Height > Image.Height) + { + cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top); + } - if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location)) - { - if (adorner.Cursor != null) - { - Cursor = adorner.Cursor; - } - return adorner; - } - } - } - return null; - } + if (cropRectangle.Height > 0 && cropRectangle.Width > 0) + { + return true; + } - /// - /// Translate mouse coordinates as if they were applied directly to unscaled image. - /// - private MouseEventArgs InverseZoomMouseCoordinates(MouseEventArgs e) - => new MouseEventArgs(e.Button, e.Clicks, (int)(e.X / _zoomFactor), (int)(e.Y / _zoomFactor), e.Delta); + return false; + } - /// - /// This event handler is called when someone presses the mouse on a surface. - /// - /// - /// - private void SurfaceMouseDown(object sender, MouseEventArgs e) - { - e = InverseZoomMouseCoordinates(e); + /// + /// Use to send any registered SurfaceMessageEventHandler a message, e.g. used for the notification area + /// + /// Who send + /// Type of message + /// Message itself + public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message) + { + if (_surfaceMessage != null) + { + var eventArgs = new SurfaceMessageEventArgs + { + Message = message, + MessageType = messageType, + Surface = this + }; + _surfaceMessage(source, eventArgs); + } + } - // Handle Adorners - var adorner = FindActiveAdorner(e); - if (adorner != null) - { - adorner.MouseDown(sender, e); - return; - } + /// + /// Crop the surface + /// + /// + /// + public bool ApplyCrop(Rectangle cropRectangle) + { + if (IsCropPossible(ref cropRectangle)) + { + Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); + Bitmap tmpImage; + // Make sure we have information, this this fails + try + { + tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); + } + catch (Exception ex) + { + ex.Data.Add("CropRectangle", cropRectangle); + ex.Data.Add("Width", Image.Width); + ex.Data.Add("Height", Image.Height); + ex.Data.Add("Pixelformat", Image.PixelFormat); + throw; + } - _mouseStart = e.Location; + Matrix matrix = new Matrix(); + matrix.Translate(-cropRectangle.Left, -cropRectangle.Top, MatrixOrder.Append); + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); - // check contextmenu - if (e.Button == MouseButtons.Right) - { - IDrawableContainerList selectedList = null; - if (selectedElements != null && selectedElements.Count > 0) - { - selectedList = selectedElements; - } - else - { - // Single element - IDrawableContainer rightClickedContainer = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); - if (rightClickedContainer != null) - { - selectedList = new DrawableContainerList(ID) {rightClickedContainer}; - } - } - if (selectedList != null && selectedList.Count > 0) - { - selectedList.ShowContextMenu(e, this); - } - return; - } + // Do not dispose otherwise we can't undo the image! + SetImage(tmpImage, false); + _elements.Transform(matrix); + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) + { + _surfaceSizeChanged(this, null); + } - _mouseDown = true; - _isSurfaceMoveMadeUndoable = false; + Invalidate(); + return true; + } - if (_cropContainer != null && ((_undrawnElement == null) || (_undrawnElement != null && DrawingMode != DrawingModes.Crop))) - { - RemoveElement(_cropContainer, false); - _cropContainer = null; - _drawingElement = null; - } + return false; + } - if (_drawingElement == null && DrawingMode != DrawingModes.None) - { - if (_undrawnElement == null) - { - DeselectAllElements(); - if (_undrawnElement == null) - { - CreateUndrawnElement(); - } - } - _drawingElement = _undrawnElement; - // if a new element has been drawn, set location and register it - if (_drawingElement != null) - { - if (_undrawnElement != null) - { - _drawingElement.Status = _undrawnElement.DefaultEditMode; - } - if (!_drawingElement.HandleMouseDown(_mouseStart.X, _mouseStart.Y)) - { - _drawingElement.Left = _mouseStart.X; - _drawingElement.Top = _mouseStart.Y; - } - AddElement(_drawingElement); - _drawingElement.Selected = true; - } - _undrawnElement = null; - } - else - { - // check whether an existing element was clicked - // we save mouse down element separately from selectedElements (checked on mouse up), - // since it could be moved around before it is actually selected - _mouseDownElement = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); + /// + /// The background here is the captured image. + /// This is called from the SurfaceBackgroundChangeMemento. + /// + /// + /// + public void UndoBackgroundChange(Image previous, Matrix matrix) + { + SetImage(previous, false); + if (matrix != null) + { + _elements.Transform(matrix); + } - if (_mouseDownElement != null) - { - _mouseDownElement.Status = EditStatus.MOVING; - } - } - } + _surfaceSizeChanged?.Invoke(this, null); + Invalidate(); + } - /// - /// This event handle is called when the mouse button is unpressed - /// - /// - /// - private void SurfaceMouseUp(object sender, MouseEventArgs e) - { - e = InverseZoomMouseCoordinates(e); + /// + /// Check if an adorner was "hit", and change the cursor if so + /// + /// MouseEventArgs + /// IAdorner + private IAdorner FindActiveAdorner(MouseEventArgs mouseEventArgs) + { + foreach (IDrawableContainer drawableContainer in selectedElements) + { + foreach (IAdorner adorner in drawableContainer.Adorners) + { + if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location)) + { + if (adorner.Cursor != null) + { + Cursor = adorner.Cursor; + } - // Handle Adorners - var adorner = FindActiveAdorner(e); - if (adorner != null) - { - adorner.MouseUp(sender, e); - return; - } + return adorner; + } + } + } - Point currentMouse = new Point(e.X, e.Y); + return null; + } - _elements.Status = EditStatus.IDLE; - if (_mouseDownElement != null) - { - _mouseDownElement.Status = EditStatus.IDLE; - } - _mouseDown = false; - _mouseDownElement = null; - if (DrawingMode == DrawingModes.None) - { - // check whether an existing element was clicked - IDrawableContainer element = _elements.ClickableElementAt(currentMouse.X, currentMouse.Y); - bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; - if (element != null) - { - element.Invalidate(); - bool alreadySelected = selectedElements.Contains(element); - if (shiftModifier) - { - if (alreadySelected) - { - DeselectElement(element); - } - else - { - SelectElement(element); - } - } - else - { - if (!alreadySelected) - { - DeselectAllElements(); - SelectElement(element); - } - } - } - else if (!shiftModifier) - { - DeselectAllElements(); - } - } + /// + /// Translate mouse coordinates as if they were applied directly to unscaled image. + /// + private MouseEventArgs InverseZoomMouseCoordinates(MouseEventArgs e) + => new MouseEventArgs(e.Button, e.Clicks, (int) (e.X / _zoomFactor), (int) (e.Y / _zoomFactor), e.Delta); - if (selectedElements.Count > 0) - { - selectedElements.Invalidate(); - selectedElements.Selected = true; - } + /// + /// This event handler is called when someone presses the mouse on a surface. + /// + /// + /// + private void SurfaceMouseDown(object sender, MouseEventArgs e) + { + e = InverseZoomMouseCoordinates(e); - if (_drawingElement != null) - { - if (!_drawingElement.InitContent()) - { - _elements.Remove(_drawingElement); - _drawingElement.Invalidate(); - } - else - { - _drawingElement.HandleMouseUp(currentMouse.X, currentMouse.Y); - _drawingElement.Invalidate(); - if (Math.Abs(_drawingElement.Width) < 5 && Math.Abs(_drawingElement.Height) < 5) - { - _drawingElement.Width = 25; - _drawingElement.Height = 25; - } - SelectElement(_drawingElement); - _drawingElement.Selected = true; - } - _drawingElement = null; - } - } + // Handle Adorners + var adorner = FindActiveAdorner(e); + if (adorner != null) + { + adorner.MouseDown(sender, e); + return; + } - /// - /// This event handler is called when the mouse moves over the surface - /// - /// - /// - private void SurfaceMouseMove(object sender, MouseEventArgs e) - { - e = InverseZoomMouseCoordinates(e); + _mouseStart = e.Location; - // Handle Adorners - var adorner = FindActiveAdorner(e); - if (adorner != null) - { - adorner.MouseMove(sender, e); - return; - } + // check contextmenu + if (e.Button == MouseButtons.Right) + { + IDrawableContainerList selectedList = null; + if (selectedElements != null && selectedElements.Count > 0) + { + selectedList = selectedElements; + } + else + { + // Single element + IDrawableContainer rightClickedContainer = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); + if (rightClickedContainer != null) + { + selectedList = new DrawableContainerList(ID) + { + rightClickedContainer + }; + } + } - Point currentMouse = e.Location; + if (selectedList != null && selectedList.Count > 0) + { + selectedList.ShowContextMenu(e, this); + } - Cursor = DrawingMode != DrawingModes.None ? Cursors.Cross : Cursors.Default; + return; + } - if (_mouseDown) - { - if (_mouseDownElement != null) - { // an element is currently dragged - _mouseDownElement.Invalidate(); - selectedElements.Invalidate(); - // Move the element - if (_mouseDownElement.Selected) - { - if (!_isSurfaceMoveMadeUndoable) - { - // Only allow one undoable per mouse-down/move/up "cycle" - _isSurfaceMoveMadeUndoable = true; - selectedElements.MakeBoundsChangeUndoable(false); - } - // dragged element has been selected before -> move all - selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); - } - else - { - if (!_isSurfaceMoveMadeUndoable) - { - // Only allow one undoable per mouse-down/move/up "cycle" - _isSurfaceMoveMadeUndoable = true; - _mouseDownElement.MakeBoundsChangeUndoable(false); - } - // dragged element is not among selected elements -> just move dragged one - _mouseDownElement.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); - } - _mouseStart = currentMouse; - _mouseDownElement.Invalidate(); - _modified = true; - } - else if (_drawingElement != null) - { - _drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); - _modified = true; - } - } - } + _mouseDown = true; + _isSurfaceMoveMadeUndoable = false; - /// - /// This event handler is called when the surface is double clicked. - /// - /// - /// - private void SurfaceDoubleClick(object sender, MouseEventArgs e) - { - selectedElements.OnDoubleClick(); - selectedElements.Invalidate(); - } + if (_cropContainer != null && ((_undrawnElement == null) || (_undrawnElement != null && DrawingMode != DrawingModes.Crop))) + { + RemoveElement(_cropContainer, false); + _cropContainer = null; + _drawingElement = null; + } - /// - /// Privately used to get the rendered image with all the elements on it. - /// - /// - /// - private Image GetImage(RenderMode renderMode) - { - // Generate a copy of the original image with a dpi equal to the default... - Bitmap clone = ImageHelper.Clone(_image, PixelFormat.DontCare); - // otherwise we would have a problem drawing the image to the surface... :( - using (Graphics graphics = Graphics.FromImage(clone)) - { - // Do not set the following, the containers need to decide themselves - //graphics.SmoothingMode = SmoothingMode.HighQuality; - //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - //graphics.CompositingQuality = CompositingQuality.HighQuality; - //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - _elements.Draw(graphics, clone, renderMode, new Rectangle(Point.Empty, clone.Size)); - } - return clone; - } + if (_drawingElement == null && DrawingMode != DrawingModes.None) + { + if (_undrawnElement == null) + { + DeselectAllElements(); + if (_undrawnElement == null) + { + CreateUndrawnElement(); + } + } - /// - /// This returns the image "result" of this surface, with all the elements rendered on it. - /// - /// - public Image GetImageForExport() - { - return GetImage(RenderMode.EXPORT); - } + _drawingElement = _undrawnElement; + // if a new element has been drawn, set location and register it + if (_drawingElement != null) + { + if (_undrawnElement != null) + { + _drawingElement.Status = _undrawnElement.DefaultEditMode; + } - private static Rectangle ZoomClipRectangle(Rectangle rc, double scale, int inflateAmount = 0) - { - rc = new Rectangle( - (int)(rc.X * scale), - (int)(rc.Y * scale), - (int)(rc.Width * scale) + 1, - (int)(rc.Height * scale) + 1 - ); - if (scale > 1) - { - inflateAmount = (int)(inflateAmount * scale); - } - rc.Inflate(inflateAmount, inflateAmount); - return rc; - } + if (!_drawingElement.HandleMouseDown(_mouseStart.X, _mouseStart.Y)) + { + _drawingElement.Left = _mouseStart.X; + _drawingElement.Top = _mouseStart.Y; + } - public void InvalidateElements(Rectangle rc) - => Invalidate(ZoomClipRectangle(rc, _zoomFactor, 1)); + AddElement(_drawingElement); + _drawingElement.Selected = true; + } - /// - /// This is the event handler for the Paint Event, try to draw as little as possible! - /// - /// - /// PaintEventArgs - private void SurfacePaint(object sender, PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - Rectangle targetClipRectangle = paintEventArgs.ClipRectangle; - if (Rectangle.Empty.Equals(targetClipRectangle)) - { - LOG.Debug("Empty cliprectangle??"); - return; - } + _undrawnElement = null; + } + else + { + // check whether an existing element was clicked + // we save mouse down element separately from selectedElements (checked on mouse up), + // since it could be moved around before it is actually selected + _mouseDownElement = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); - // Correction to prevent rounding errors at certain zoom levels. - // When zooming to N/M, clip rectangle top and left coordinates should be multiples of N. - if (_zoomFactor.Numerator > 1 && _zoomFactor.Denominator > 1) - { - int horizontalCorrection = targetClipRectangle.Left % (int)_zoomFactor.Numerator; - int verticalCorrection = targetClipRectangle.Top % (int)_zoomFactor.Numerator; - if (horizontalCorrection != 0) - { - targetClipRectangle.X -= horizontalCorrection; - targetClipRectangle.Width += horizontalCorrection; - } - if (verticalCorrection != 0) - { - targetClipRectangle.Y -= verticalCorrection; - targetClipRectangle.Height += verticalCorrection; - } - } + if (_mouseDownElement != null) + { + _mouseDownElement.Status = EditStatus.MOVING; + } + } + } - Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2); + /// + /// This event handle is called when the mouse button is unpressed + /// + /// + /// + private void SurfaceMouseUp(object sender, MouseEventArgs e) + { + e = InverseZoomMouseCoordinates(e); - if (_elements.HasIntersectingFilters(imageClipRectangle) || _zoomFactor > Fraction.Identity) - { - if (_buffer != null) - { - if (_buffer.Width != Image.Width || _buffer.Height != Image.Height || _buffer.PixelFormat != Image.PixelFormat) - { - _buffer.Dispose(); - _buffer = null; - } - } - if (_buffer == null) - { - _buffer = ImageHelper.CreateEmpty(Image.Width, Image.Height, Image.PixelFormat, Color.Empty, Image.HorizontalResolution, Image.VerticalResolution); - LOG.DebugFormat("Created buffer with size: {0}x{1}", Image.Width, Image.Height); - } - // Elements might need the bitmap, so we copy the part we need - using (Graphics graphics = Graphics.FromImage(_buffer)) - { - // do not set the following, the containers need to decide this themselves! - //graphics.SmoothingMode = SmoothingMode.HighQuality; - //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - //graphics.CompositingQuality = CompositingQuality.HighQuality; - //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - DrawBackground(graphics, imageClipRectangle); - graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), _zoomFactor.Inverse(), 2)); - _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle); - } - if (_zoomFactor == Fraction.Identity) - { - targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - } - else - { - targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); - if (_zoomFactor > Fraction.Identity) - { - DrawSharpImage(targetGraphics, _buffer, imageClipRectangle); - } - else - { - DrawSmoothImage(targetGraphics, _buffer, imageClipRectangle); - } - targetGraphics.ResetTransform(); - } - } - else - { - DrawBackground(targetGraphics, targetClipRectangle); - if (_zoomFactor == Fraction.Identity) - { - targetGraphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); - } - else - { - targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); - DrawSmoothImage(targetGraphics, Image, imageClipRectangle); - _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); - targetGraphics.ResetTransform(); - } - } + // Handle Adorners + var adorner = FindActiveAdorner(e); + if (adorner != null) + { + adorner.MouseUp(sender, e); + return; + } - // No clipping for the adorners - targetGraphics.ResetClip(); - // Draw adorners last - foreach (var drawableContainer in selectedElements) - { - foreach (var adorner in drawableContainer.Adorners) - { - adorner.Paint(paintEventArgs); - } - } - } + Point currentMouse = new Point(e.X, e.Y); - private void DrawSmoothImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) - { - var state = targetGraphics.Save(); - targetGraphics.SmoothingMode = SmoothingMode.HighQuality; - targetGraphics.InterpolationMode = InterpolationMode.HighQualityBilinear; - targetGraphics.CompositingQuality = CompositingQuality.HighQuality; - targetGraphics.PixelOffsetMode = PixelOffsetMode.None; + _elements.Status = EditStatus.IDLE; + if (_mouseDownElement != null) + { + _mouseDownElement.Status = EditStatus.IDLE; + } - targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + _mouseDown = false; + _mouseDownElement = null; + if (DrawingMode == DrawingModes.None) + { + // check whether an existing element was clicked + IDrawableContainer element = _elements.ClickableElementAt(currentMouse.X, currentMouse.Y); + bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; + if (element != null) + { + element.Invalidate(); + bool alreadySelected = selectedElements.Contains(element); + if (shiftModifier) + { + if (alreadySelected) + { + DeselectElement(element); + } + else + { + SelectElement(element); + } + } + else + { + if (!alreadySelected) + { + DeselectAllElements(); + SelectElement(element); + } + } + } + else if (!shiftModifier) + { + DeselectAllElements(); + } + } - targetGraphics.Restore(state); - } + if (selectedElements.Count > 0) + { + selectedElements.Invalidate(); + selectedElements.Selected = true; + } - private void DrawSharpImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) - { - var state = targetGraphics.Save(); - targetGraphics.SmoothingMode = SmoothingMode.None; - targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; - targetGraphics.CompositingQuality = CompositingQuality.HighQuality; - targetGraphics.PixelOffsetMode = PixelOffsetMode.None; + if (_drawingElement != null) + { + if (!_drawingElement.InitContent()) + { + _elements.Remove(_drawingElement); + _drawingElement.Invalidate(); + } + else + { + _drawingElement.HandleMouseUp(currentMouse.X, currentMouse.Y); + _drawingElement.Invalidate(); + if (Math.Abs(_drawingElement.Width) < 5 && Math.Abs(_drawingElement.Height) < 5) + { + _drawingElement.Width = 25; + _drawingElement.Height = 25; + } - targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + SelectElement(_drawingElement); + _drawingElement.Selected = true; + } - targetGraphics.Restore(state); - } + _drawingElement = null; + } + } - private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) - { - // check if we need to draw the checkerboard - if (Image.IsAlphaPixelFormat(Image.PixelFormat) && _transparencyBackgroundBrush != null) - { - targetGraphics.FillRectangle(_transparencyBackgroundBrush, clipRectangle); - } - else - { - targetGraphics.Clear(BackColor); - } - } + /// + /// This event handler is called when the mouse moves over the surface + /// + /// + /// + private void SurfaceMouseMove(object sender, MouseEventArgs e) + { + e = InverseZoomMouseCoordinates(e); - /// - /// Draw a checkboard when capturing with transparency - /// - /// PaintEventArgs - protected override void OnPaintBackground(PaintEventArgs e) - { - } + // Handle Adorners + var adorner = FindActiveAdorner(e); + if (adorner != null) + { + adorner.MouseMove(sender, e); + return; + } - /// - /// Add a new element to the surface - /// - /// the new element - /// true if the adding should be undoable - /// true if invalidate needs to be called - public void AddElement(IDrawableContainer element, bool makeUndoable = true, bool invalidate = true) - { - _elements.Add(element); + Point currentMouse = e.Location; + + Cursor = DrawingMode != DrawingModes.None ? Cursors.Cross : Cursors.Default; + + if (_mouseDown) + { + if (_mouseDownElement != null) + { + // an element is currently dragged + _mouseDownElement.Invalidate(); + selectedElements.Invalidate(); + // Move the element + if (_mouseDownElement.Selected) + { + if (!_isSurfaceMoveMadeUndoable) + { + // Only allow one undoable per mouse-down/move/up "cycle" + _isSurfaceMoveMadeUndoable = true; + selectedElements.MakeBoundsChangeUndoable(false); + } + + // dragged element has been selected before -> move all + selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); + } + else + { + if (!_isSurfaceMoveMadeUndoable) + { + // Only allow one undoable per mouse-down/move/up "cycle" + _isSurfaceMoveMadeUndoable = true; + _mouseDownElement.MakeBoundsChangeUndoable(false); + } + + // dragged element is not among selected elements -> just move dragged one + _mouseDownElement.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); + } + + _mouseStart = currentMouse; + _mouseDownElement.Invalidate(); + _modified = true; + } + else if (_drawingElement != null) + { + _drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); + _modified = true; + } + } + } + + /// + /// This event handler is called when the surface is double clicked. + /// + /// + /// + private void SurfaceDoubleClick(object sender, MouseEventArgs e) + { + selectedElements.OnDoubleClick(); + selectedElements.Invalidate(); + } + + /// + /// Privately used to get the rendered image with all the elements on it. + /// + /// + /// + private Image GetImage(RenderMode renderMode) + { + // Generate a copy of the original image with a dpi equal to the default... + Bitmap clone = ImageHelper.Clone(_image, PixelFormat.DontCare); + // otherwise we would have a problem drawing the image to the surface... :( + using (Graphics graphics = Graphics.FromImage(clone)) + { + // Do not set the following, the containers need to decide themselves + //graphics.SmoothingMode = SmoothingMode.HighQuality; + //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + //graphics.CompositingQuality = CompositingQuality.HighQuality; + //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + _elements.Draw(graphics, clone, renderMode, new Rectangle(Point.Empty, clone.Size)); + } + + return clone; + } + + /// + /// This returns the image "result" of this surface, with all the elements rendered on it. + /// + /// + public Image GetImageForExport() + { + return GetImage(RenderMode.EXPORT); + } + + private static Rectangle ZoomClipRectangle(Rectangle rc, double scale, int inflateAmount = 0) + { + rc = new Rectangle( + (int) (rc.X * scale), + (int) (rc.Y * scale), + (int) (rc.Width * scale) + 1, + (int) (rc.Height * scale) + 1 + ); + if (scale > 1) + { + inflateAmount = (int) (inflateAmount * scale); + } + + rc.Inflate(inflateAmount, inflateAmount); + return rc; + } + + public void InvalidateElements(Rectangle rc) + => Invalidate(ZoomClipRectangle(rc, _zoomFactor, 1)); + + /// + /// This is the event handler for the Paint Event, try to draw as little as possible! + /// + /// + /// PaintEventArgs + private void SurfacePaint(object sender, PaintEventArgs paintEventArgs) + { + Graphics targetGraphics = paintEventArgs.Graphics; + Rectangle targetClipRectangle = paintEventArgs.ClipRectangle; + if (Rectangle.Empty.Equals(targetClipRectangle)) + { + LOG.Debug("Empty cliprectangle??"); + return; + } + + // Correction to prevent rounding errors at certain zoom levels. + // When zooming to N/M, clip rectangle top and left coordinates should be multiples of N. + if (_zoomFactor.Numerator > 1 && _zoomFactor.Denominator > 1) + { + int horizontalCorrection = targetClipRectangle.Left % (int) _zoomFactor.Numerator; + int verticalCorrection = targetClipRectangle.Top % (int) _zoomFactor.Numerator; + if (horizontalCorrection != 0) + { + targetClipRectangle.X -= horizontalCorrection; + targetClipRectangle.Width += horizontalCorrection; + } + + if (verticalCorrection != 0) + { + targetClipRectangle.Y -= verticalCorrection; + targetClipRectangle.Height += verticalCorrection; + } + } + + Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2); + + if (_elements.HasIntersectingFilters(imageClipRectangle) || _zoomFactor > Fraction.Identity) + { + if (_buffer != null) + { + if (_buffer.Width != Image.Width || _buffer.Height != Image.Height || _buffer.PixelFormat != Image.PixelFormat) + { + _buffer.Dispose(); + _buffer = null; + } + } + + if (_buffer == null) + { + _buffer = ImageHelper.CreateEmpty(Image.Width, Image.Height, Image.PixelFormat, Color.Empty, Image.HorizontalResolution, Image.VerticalResolution); + LOG.DebugFormat("Created buffer with size: {0}x{1}", Image.Width, Image.Height); + } + + // Elements might need the bitmap, so we copy the part we need + using (Graphics graphics = Graphics.FromImage(_buffer)) + { + // do not set the following, the containers need to decide this themselves! + //graphics.SmoothingMode = SmoothingMode.HighQuality; + //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + //graphics.CompositingQuality = CompositingQuality.HighQuality; + //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + DrawBackground(graphics, imageClipRectangle); + graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), _zoomFactor.Inverse(), 2)); + _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle); + } + + if (_zoomFactor == Fraction.Identity) + { + targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + } + else + { + targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); + if (_zoomFactor > Fraction.Identity) + { + DrawSharpImage(targetGraphics, _buffer, imageClipRectangle); + } + else + { + DrawSmoothImage(targetGraphics, _buffer, imageClipRectangle); + } + + targetGraphics.ResetTransform(); + } + } + else + { + DrawBackground(targetGraphics, targetClipRectangle); + if (_zoomFactor == Fraction.Identity) + { + targetGraphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); + } + else + { + targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); + DrawSmoothImage(targetGraphics, Image, imageClipRectangle); + _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); + targetGraphics.ResetTransform(); + } + } + + // No clipping for the adorners + targetGraphics.ResetClip(); + // Draw adorners last + foreach (var drawableContainer in selectedElements) + { + foreach (var adorner in drawableContainer.Adorners) + { + adorner.Paint(paintEventArgs); + } + } + } + + private void DrawSmoothImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) + { + var state = targetGraphics.Save(); + targetGraphics.SmoothingMode = SmoothingMode.HighQuality; + targetGraphics.InterpolationMode = InterpolationMode.HighQualityBilinear; + targetGraphics.CompositingQuality = CompositingQuality.HighQuality; + targetGraphics.PixelOffsetMode = PixelOffsetMode.None; + + targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + + targetGraphics.Restore(state); + } + + private void DrawSharpImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) + { + var state = targetGraphics.Save(); + targetGraphics.SmoothingMode = SmoothingMode.None; + targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; + targetGraphics.CompositingQuality = CompositingQuality.HighQuality; + targetGraphics.PixelOffsetMode = PixelOffsetMode.None; + + targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + + targetGraphics.Restore(state); + } + + private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) + { + // check if we need to draw the checkerboard + if (Image.IsAlphaPixelFormat(Image.PixelFormat) && _transparencyBackgroundBrush != null) + { + targetGraphics.FillRectangle(_transparencyBackgroundBrush, clipRectangle); + } + else + { + targetGraphics.Clear(BackColor); + } + } + + /// + /// Draw a checkboard when capturing with transparency + /// + /// PaintEventArgs + protected override void OnPaintBackground(PaintEventArgs e) + { + } + + /// + /// Add a new element to the surface + /// + /// the new element + /// true if the adding should be undoable + /// true if invalidate needs to be called + public void AddElement(IDrawableContainer element, bool makeUndoable = true, bool invalidate = true) + { + _elements.Add(element); if (element is DrawableContainer container) - { - container.FieldChanged += Element_FieldChanged; - } - element.Parent = this; - if (element.Status == EditStatus.UNDRAWN) - { - element.Status = EditStatus.IDLE; - } - if (element.Selected) - { - // Use false, as the element is invalidated when invalidate == true anyway - SelectElement(element, false); - } - if (invalidate) - { - element.Invalidate(); - } - if (makeUndoable) - { - MakeUndoable(new AddElementMemento(this, element), false); - } - _modified = true; - } + { + container.FieldChanged += Element_FieldChanged; + } - /// - /// Remove the list of elements - /// - /// IDrawableContainerList - /// flag specifying if the remove needs to be undoable - public void RemoveElements(IDrawableContainerList elementsToRemove, bool makeUndoable = true) - { - // fix potential issues with iterating a changing list - DrawableContainerList cloned = new DrawableContainerList(); - cloned.AddRange(elementsToRemove); - if (makeUndoable) - { - MakeUndoable(new DeleteElementsMemento(this, cloned), false); - } - SuspendLayout(); - foreach (var drawableContainer in cloned) - { - RemoveElement(drawableContainer, false, false, false); - } - ResumeLayout(); - Invalidate(); - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs {Elements = cloned}; - _movingElementChanged(this, eventArgs); - } - } + element.Parent = this; + if (element.Status == EditStatus.UNDRAWN) + { + element.Status = EditStatus.IDLE; + } - /// - /// Remove an element of the elements list - /// - /// Element to remove - /// flag specifying if the remove needs to be undoable - /// flag specifying if an surface invalidate needs to be called - /// false to skip event generation - public void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable = true, bool invalidate = true, bool generateEvents = true) - { - DeselectElement(elementToRemove, generateEvents); - _elements.Remove(elementToRemove); + if (element.Selected) + { + // Use false, as the element is invalidated when invalidate == true anyway + SelectElement(element, false); + } + + if (invalidate) + { + element.Invalidate(); + } + + if (makeUndoable) + { + MakeUndoable(new AddElementMemento(this, element), false); + } + + _modified = true; + } + + /// + /// Remove the list of elements + /// + /// IDrawableContainerList + /// flag specifying if the remove needs to be undoable + public void RemoveElements(IDrawableContainerList elementsToRemove, bool makeUndoable = true) + { + // fix potential issues with iterating a changing list + DrawableContainerList cloned = new DrawableContainerList(); + cloned.AddRange(elementsToRemove); + if (makeUndoable) + { + MakeUndoable(new DeleteElementsMemento(this, cloned), false); + } + + SuspendLayout(); + foreach (var drawableContainer in cloned) + { + RemoveElement(drawableContainer, false, false, false); + } + + ResumeLayout(); + Invalidate(); + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs + { + Elements = cloned + }; + _movingElementChanged(this, eventArgs); + } + } + + /// + /// Remove an element of the elements list + /// + /// Element to remove + /// flag specifying if the remove needs to be undoable + /// flag specifying if an surface invalidate needs to be called + /// false to skip event generation + public void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable = true, bool invalidate = true, bool generateEvents = true) + { + DeselectElement(elementToRemove, generateEvents); + _elements.Remove(elementToRemove); if (elementToRemove is DrawableContainer element) - { - element.FieldChanged -= Element_FieldChanged; - } - if (elementToRemove != null) - { - elementToRemove.Parent = null; - } - // Do not dispose, the memento should!! element.Dispose(); - if (invalidate) - { - Invalidate(); - } - if (makeUndoable) - { - MakeUndoable(new DeleteElementMemento(this, elementToRemove), false); - } - _modified = true; - } + { + element.FieldChanged -= Element_FieldChanged; + } - /// - /// Add the supplied elements to the surface - /// - /// DrawableContainerList - /// true if the adding should be undoable - public void AddElements(IDrawableContainerList elementsToAdd, bool makeUndoable = true) - { - // fix potential issues with iterating a changing list - DrawableContainerList cloned = new DrawableContainerList(); - cloned.AddRange(elementsToAdd); - if (makeUndoable) - { - MakeUndoable(new AddElementsMemento(this, cloned), false); - } - SuspendLayout(); - foreach (var element in cloned) - { - element.Selected = true; - AddElement(element, false, false); - } - ResumeLayout(); - Invalidate(); - } + if (elementToRemove != null) + { + elementToRemove.Parent = null; + } - /// - /// Returns if this surface has selected elements - /// - /// - public bool HasSelectedElements => (selectedElements != null && selectedElements.Count > 0); + // Do not dispose, the memento should!! element.Dispose(); + if (invalidate) + { + Invalidate(); + } - /// - /// Remove all the selected elements - /// - public void RemoveSelectedElements() - { - if (HasSelectedElements) - { - // As RemoveElement will remove the element from the selectedElements list we need to copy the element to another list. - RemoveElements(selectedElements); - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); - _movingElementChanged(this, eventArgs); - } - } - } + if (makeUndoable) + { + MakeUndoable(new DeleteElementMemento(this, elementToRemove), false); + } - /// - /// Cut the selected elements from the surface to the clipboard - /// - public void CutSelectedElements() - { - if (HasSelectedElements) - { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); - RemoveSelectedElements(); - } - } + _modified = true; + } - /// - /// Copy the selected elements to the clipboard - /// - public void CopySelectedElements() - { - if (HasSelectedElements) - { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); - } - } + /// + /// Add the supplied elements to the surface + /// + /// DrawableContainerList + /// true if the adding should be undoable + public void AddElements(IDrawableContainerList elementsToAdd, bool makeUndoable = true) + { + // fix potential issues with iterating a changing list + DrawableContainerList cloned = new DrawableContainerList(); + cloned.AddRange(elementsToAdd); + if (makeUndoable) + { + MakeUndoable(new AddElementsMemento(this, cloned), false); + } - /// - /// This method is called to confirm/cancel "confirmable" elements, like the crop-container. - /// Called when pressing enter or using the "check" in the editor. - /// - /// - public void ConfirmSelectedConfirmableElements(bool confirm) - { - // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel) - List selectedDCs = new List(selectedElements); - foreach (IDrawableContainer dc in selectedDCs) - { - if (dc.Equals(_cropContainer)) - { - DrawingMode = DrawingModes.None; - // No undo memento for the cropcontainer itself, only for the effect - RemoveElement(_cropContainer, false); - if (confirm) - { - ApplyCrop(_cropContainer.Bounds); - } - _cropContainer.Dispose(); - _cropContainer = null; - break; - } - } - } + SuspendLayout(); + foreach (var element in cloned) + { + element.Selected = true; + AddElement(element, false, false); + } - /// - /// Paste all the elements that are on the clipboard - /// - public void PasteElementFromClipboard() - { - IDataObject clipboard = ClipboardHelper.GetDataObject(); + ResumeLayout(); + Invalidate(); + } - var formats = ClipboardHelper.GetFormats(clipboard); - if (formats == null || formats.Count == 0) - { - return; - } - if (LOG.IsDebugEnabled) - { - LOG.Debug("List of clipboard formats available for pasting:"); - foreach (string format in formats) - { - LOG.Debug("\tgot format: " + format); - } - } + /// + /// Returns if this surface has selected elements + /// + /// + public bool HasSelectedElements => (selectedElements != null && selectedElements.Count > 0); - if (formats.Contains(typeof(IDrawableContainerList).FullName)) - { - IDrawableContainerList dcs = (IDrawableContainerList)ClipboardHelper.GetFromDataObject(clipboard, typeof(IDrawableContainerList)); - if (dcs != null) - { - // Make element(s) only move 10,10 if the surface is the same - bool isSameSurface = (dcs.ParentID == _uniqueId); - dcs.Parent = this; - var moveOffset = isSameSurface ? new Point(10, 10) : Point.Empty; - // Here a fix for bug #1475, first calculate the bounds of the complete IDrawableContainerList - Rectangle drawableContainerListBounds = Rectangle.Empty; - foreach (var element in dcs) - { - drawableContainerListBounds = drawableContainerListBounds == Rectangle.Empty ? element.DrawingBounds : Rectangle.Union(drawableContainerListBounds, element.DrawingBounds); - } - // And find a location inside the target surface to paste to - bool containersCanFit = drawableContainerListBounds.Width < Bounds.Width && drawableContainerListBounds.Height < Bounds.Height; - if (!containersCanFit) - { - Point containersLocation = drawableContainerListBounds.Location; - containersLocation.Offset(moveOffset); - if (!Bounds.Contains(containersLocation)) - { - // Easy fix for same surface - moveOffset = isSameSurface ? new Point(-10, -10) : new Point(-drawableContainerListBounds.Location.X + 10, -drawableContainerListBounds.Location.Y + 10); - } - } - else - { - Rectangle moveContainerListBounds = drawableContainerListBounds; - moveContainerListBounds.Offset(moveOffset); - // check if the element is inside - if (!Bounds.Contains(moveContainerListBounds)) - { - // Easy fix for same surface - if (isSameSurface) - { - moveOffset = new Point(-10, -10); - } - else - { - // For different surface, which is most likely smaller - int offsetX = 0; - int offsetY = 0; - if (drawableContainerListBounds.Right > Bounds.Right) - { - offsetX = Bounds.Right - drawableContainerListBounds.Right; - // Correction for the correction - if (drawableContainerListBounds.Left + offsetX < 0) - { - offsetX += Math.Abs(drawableContainerListBounds.Left + offsetX); - } - } - if (drawableContainerListBounds.Bottom > Bounds.Bottom) - { - offsetY = Bounds.Bottom - drawableContainerListBounds.Bottom; - // Correction for the correction - if (drawableContainerListBounds.Top + offsetY < 0) - { - offsetY += Math.Abs(drawableContainerListBounds.Top + offsetY); - } - } - moveOffset = new Point(offsetX, offsetY); - } - } - } - dcs.MoveBy(moveOffset.X, moveOffset.Y); - AddElements(dcs); - FieldAggregator.BindElements(dcs); - DeselectAllElements(); - SelectElements(dcs); - } - } - else if (ClipboardHelper.ContainsImage(clipboard)) - { - Point pasteLocation = GetPasteLocation(0.1f, 0.1f); + /// + /// Remove all the selected elements + /// + public void RemoveSelectedElements() + { + if (HasSelectedElements) + { + // As RemoveElement will remove the element from the selectedElements list we need to copy the element to another list. + RemoveElements(selectedElements); + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); + _movingElementChanged(this, eventArgs); + } + } + } - foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) - { - if (clipboardImage != null) - { - DeselectAllElements(); - IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y); - SelectElement(container); - clipboardImage.Dispose(); - pasteLocation.X += 10; - pasteLocation.Y += 10; - } - } - } - else if (ClipboardHelper.ContainsText(clipboard)) - { - Point pasteLocation = GetPasteLocation(0.4f, 0.4f); + /// + /// Cut the selected elements from the surface to the clipboard + /// + public void CutSelectedElements() + { + if (HasSelectedElements) + { + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); + RemoveSelectedElements(); + } + } - string text = ClipboardHelper.GetText(clipboard); - if (text != null) - { - DeselectAllElements(); - ITextContainer textContainer = AddTextContainer(text, pasteLocation.X, pasteLocation.Y, - FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); - SelectElement(textContainer); - } - } - } + /// + /// Copy the selected elements to the clipboard + /// + public void CopySelectedElements() + { + if (HasSelectedElements) + { + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); + } + } - /// - /// Find a location to paste elements. - /// If mouse is over the surface - use it's position, otherwise use the visible area. - /// Return a point in image coordinate space. - /// - /// 0.0f for the left edge of visible area, 1.0f for the right edge of visible area. - /// 0.0f for the top edge of visible area, 1.0f for the bottom edge of visible area. - private Point GetPasteLocation(float horizontalRatio = 0.5f, float verticalRatio = 0.5f) - { - var point = PointToClient(MousePosition); - var rc = GetVisibleRectangle(); - if (!rc.Contains(point)) - { - point = new Point( - rc.Left + (int)(rc.Width * horizontalRatio), - rc.Top + (int)(rc.Height * verticalRatio) - ); - } - return ToImageCoordinates(point); - } + /// + /// This method is called to confirm/cancel "confirmable" elements, like the crop-container. + /// Called when pressing enter or using the "check" in the editor. + /// + /// + public void ConfirmSelectedConfirmableElements(bool confirm) + { + // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel) + List selectedDCs = new List(selectedElements); + foreach (IDrawableContainer dc in selectedDCs) + { + if (dc.Equals(_cropContainer)) + { + DrawingMode = DrawingModes.None; + // No undo memento for the cropcontainer itself, only for the effect + RemoveElement(_cropContainer, false); + if (confirm) + { + ApplyCrop(_cropContainer.Bounds); + } - /// - /// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space). - /// - public Rectangle GetVisibleRectangle() - { - var bounds = Bounds; - var clientArea = Parent.ClientRectangle; - return new Rectangle( - Math.Max(0, -bounds.Left), - Math.Max(0, -bounds.Top), - clientArea.Width, - clientArea.Height - ); - } + _cropContainer.Dispose(); + _cropContainer = null; + break; + } + } + } - /// - /// Get the rectangle bounding all selected elements (in surface coordinates space), - /// or empty rectangle if nothing is selcted. - /// - public Rectangle GetSelectionRectangle() - => ToSurfaceCoordinates(selectedElements.DrawingBounds); + /// + /// Paste all the elements that are on the clipboard + /// + public void PasteElementFromClipboard() + { + IDataObject clipboard = ClipboardHelper.GetDataObject(); - /// - /// Duplicate all the selecteded elements - /// - public void DuplicateSelectedElements() - { - LOG.DebugFormat("Duplicating {0} selected elements", selectedElements.Count); - IDrawableContainerList dcs = selectedElements.Clone(); - dcs.Parent = this; - dcs.MoveBy(10, 10); - AddElements(dcs); - DeselectAllElements(); - SelectElements(dcs); - } + var formats = ClipboardHelper.GetFormats(clipboard); + if (formats == null || formats.Count == 0) + { + return; + } - /// - /// Deselect the specified element - /// - /// IDrawableContainerList - /// false to skip event generation - public void DeselectElement(IDrawableContainer container, bool generateEvents = true) - { - container.Selected = false; - selectedElements.Remove(container); - FieldAggregator.UnbindElement(container); - if (generateEvents && _movingElementChanged != null) - { - var eventArgs = new SurfaceElementEventArgs {Elements = selectedElements}; - _movingElementChanged(this, eventArgs); - } - } + if (LOG.IsDebugEnabled) + { + LOG.Debug("List of clipboard formats available for pasting:"); + foreach (string format in formats) + { + LOG.Debug("\tgot format: " + format); + } + } - /// - /// Deselect the specified elements - /// - /// IDrawableContainerList - public void DeselectElements(IDrawableContainerList elements) - { - if (elements.Count == 0) - { - return; - } - while (elements.Count > 0) - { - var element = elements[0]; - DeselectElement(element, false); - } - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs - { - Elements = selectedElements - }; - _movingElementChanged(this, eventArgs); - } - Invalidate(); - } + if (formats.Contains(typeof(IDrawableContainerList).FullName)) + { + IDrawableContainerList dcs = (IDrawableContainerList) ClipboardHelper.GetFromDataObject(clipboard, typeof(IDrawableContainerList)); + if (dcs != null) + { + // Make element(s) only move 10,10 if the surface is the same + bool isSameSurface = (dcs.ParentID == _uniqueId); + dcs.Parent = this; + var moveOffset = isSameSurface ? new Point(10, 10) : Point.Empty; + // Here a fix for bug #1475, first calculate the bounds of the complete IDrawableContainerList + Rectangle drawableContainerListBounds = Rectangle.Empty; + foreach (var element in dcs) + { + drawableContainerListBounds = drawableContainerListBounds == Rectangle.Empty + ? element.DrawingBounds + : Rectangle.Union(drawableContainerListBounds, element.DrawingBounds); + } - /// - /// Deselect all the selected elements - /// - public void DeselectAllElements() - { - DeselectElements(selectedElements); - } + // And find a location inside the target surface to paste to + bool containersCanFit = drawableContainerListBounds.Width < Bounds.Width && drawableContainerListBounds.Height < Bounds.Height; + if (!containersCanFit) + { + Point containersLocation = drawableContainerListBounds.Location; + containersLocation.Offset(moveOffset); + if (!Bounds.Contains(containersLocation)) + { + // Easy fix for same surface + moveOffset = isSameSurface + ? new Point(-10, -10) + : new Point(-drawableContainerListBounds.Location.X + 10, -drawableContainerListBounds.Location.Y + 10); + } + } + else + { + Rectangle moveContainerListBounds = drawableContainerListBounds; + moveContainerListBounds.Offset(moveOffset); + // check if the element is inside + if (!Bounds.Contains(moveContainerListBounds)) + { + // Easy fix for same surface + if (isSameSurface) + { + moveOffset = new Point(-10, -10); + } + else + { + // For different surface, which is most likely smaller + int offsetX = 0; + int offsetY = 0; + if (drawableContainerListBounds.Right > Bounds.Right) + { + offsetX = Bounds.Right - drawableContainerListBounds.Right; + // Correction for the correction + if (drawableContainerListBounds.Left + offsetX < 0) + { + offsetX += Math.Abs(drawableContainerListBounds.Left + offsetX); + } + } - /// - /// Select the supplied element - /// - /// - /// false to skip invalidation - /// false to skip event generation - public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true) - { - if (!selectedElements.Contains(container)) - { - selectedElements.Add(container); - container.Selected = true; - FieldAggregator.BindElement(container); - if (generateEvents && _movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs - { - Elements = selectedElements - }; - _movingElementChanged(this, eventArgs); - } - if (invalidate) - { - container.Invalidate(); - } - } - } + if (drawableContainerListBounds.Bottom > Bounds.Bottom) + { + offsetY = Bounds.Bottom - drawableContainerListBounds.Bottom; + // Correction for the correction + if (drawableContainerListBounds.Top + offsetY < 0) + { + offsetY += Math.Abs(drawableContainerListBounds.Top + offsetY); + } + } - /// - /// Select all elements, this is called when Ctrl+A is pressed - /// - public void SelectAllElements() - { - SelectElements(_elements); - } + moveOffset = new Point(offsetX, offsetY); + } + } + } - /// - /// Select the supplied elements - /// - /// - public void SelectElements(IDrawableContainerList elements) - { - SuspendLayout(); - foreach (var drawableContainer in elements) - { - var element = (DrawableContainer) drawableContainer; - SelectElement(element, false, false); - } - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs {Elements = selectedElements}; - _movingElementChanged(this, eventArgs); - } - ResumeLayout(); - Invalidate(); - } + dcs.MoveBy(moveOffset.X, moveOffset.Y); + AddElements(dcs); + FieldAggregator.BindElements(dcs); + DeselectAllElements(); + SelectElements(dcs); + } + } + else if (ClipboardHelper.ContainsImage(clipboard)) + { + Point pasteLocation = GetPasteLocation(0.1f, 0.1f); - /// - /// Process key presses on the surface, this is called from the editor (and NOT an override from the Control) - /// - /// Keys - /// false if no keys were processed - public bool ProcessCmdKey(Keys k) - { - if (selectedElements.Count > 0) - { - bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; - int px = shiftModifier ? 10 : 1; - Point moveBy = Point.Empty; + foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) + { + if (clipboardImage != null) + { + DeselectAllElements(); + IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y); + SelectElement(container); + clipboardImage.Dispose(); + pasteLocation.X += 10; + pasteLocation.Y += 10; + } + } + } + else if (ClipboardHelper.ContainsText(clipboard)) + { + Point pasteLocation = GetPasteLocation(0.4f, 0.4f); - switch (k) - { - case Keys.Left: - case Keys.Left | Keys.Shift: - moveBy = new Point(-px, 0); - break; - case Keys.Up: - case Keys.Up | Keys.Shift: - moveBy = new Point(0, -px); - break; - case Keys.Right: - case Keys.Right | Keys.Shift: - moveBy = new Point(px, 0); - break; - case Keys.Down: - case Keys.Down | Keys.Shift: - moveBy = new Point(0, px); - break; - case Keys.PageUp: - PullElementsUp(); - break; - case Keys.PageDown: - PushElementsDown(); - break; - case Keys.Home: - PullElementsToTop(); - break; - case Keys.End: - PushElementsToBottom(); - break; - case Keys.Enter: - ConfirmSelectedConfirmableElements(true); - break; - case Keys.Escape: - ConfirmSelectedConfirmableElements(false); - break; - /*case Keys.Delete: - RemoveSelectedElements(); - break;*/ - default: - return false; - } - if (!Point.Empty.Equals(moveBy)) - { - selectedElements.MakeBoundsChangeUndoable(true); - selectedElements.MoveBy(moveBy.X, moveBy.Y); - } - return true; - } - return false; - } + string text = ClipboardHelper.GetText(clipboard); + if (text != null) + { + DeselectAllElements(); + ITextContainer textContainer = AddTextContainer(text, pasteLocation.X, pasteLocation.Y, + FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); + SelectElement(textContainer); + } + } + } - /// - /// Property for accessing the elements on the surface - /// - public IDrawableContainerList Elements => _elements; + /// + /// Find a location to paste elements. + /// If mouse is over the surface - use it's position, otherwise use the visible area. + /// Return a point in image coordinate space. + /// + /// 0.0f for the left edge of visible area, 1.0f for the right edge of visible area. + /// 0.0f for the top edge of visible area, 1.0f for the bottom edge of visible area. + private Point GetPasteLocation(float horizontalRatio = 0.5f, float verticalRatio = 0.5f) + { + var point = PointToClient(MousePosition); + var rc = GetVisibleRectangle(); + if (!rc.Contains(point)) + { + point = new Point( + rc.Left + (int) (rc.Width * horizontalRatio), + rc.Top + (int) (rc.Height * verticalRatio) + ); + } - /// - /// pulls selected elements up one level in hierarchy - /// - public void PullElementsUp() - { - _elements.PullElementsUp(selectedElements); - _elements.Invalidate(); - } + return ToImageCoordinates(point); + } - /// - /// pushes selected elements up to top in hierarchy - /// - public void PullElementsToTop() - { - _elements.PullElementsToTop(selectedElements); - _elements.Invalidate(); - } + /// + /// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space). + /// + public Rectangle GetVisibleRectangle() + { + var bounds = Bounds; + var clientArea = Parent.ClientRectangle; + return new Rectangle( + Math.Max(0, -bounds.Left), + Math.Max(0, -bounds.Top), + clientArea.Width, + clientArea.Height + ); + } - /// - /// pushes selected elements down one level in hierarchy - /// - public void PushElementsDown() - { - _elements.PushElementsDown(selectedElements); - _elements.Invalidate(); - } + /// + /// Get the rectangle bounding all selected elements (in surface coordinates space), + /// or empty rectangle if nothing is selcted. + /// + public Rectangle GetSelectionRectangle() + => ToSurfaceCoordinates(selectedElements.DrawingBounds); - /// - /// pushes selected elements down to bottom in hierarchy - /// - public void PushElementsToBottom() - { - _elements.PushElementsToBottom(selectedElements); - _elements.Invalidate(); - } + /// + /// Duplicate all the selecteded elements + /// + public void DuplicateSelectedElements() + { + LOG.DebugFormat("Duplicating {0} selected elements", selectedElements.Count); + IDrawableContainerList dcs = selectedElements.Clone(); + dcs.Parent = this; + dcs.MoveBy(10, 10); + AddElements(dcs); + DeselectAllElements(); + SelectElements(dcs); + } - /// - /// indicates whether the selected elements could be pulled up in hierarchy - /// - /// true if selected elements could be pulled up, false otherwise - public bool CanPullSelectionUp() - { - return _elements.CanPullUp(selectedElements); - } + /// + /// Deselect the specified element + /// + /// IDrawableContainerList + /// false to skip event generation + public void DeselectElement(IDrawableContainer container, bool generateEvents = true) + { + container.Selected = false; + selectedElements.Remove(container); + FieldAggregator.UnbindElement(container); + if (generateEvents && _movingElementChanged != null) + { + var eventArgs = new SurfaceElementEventArgs + { + Elements = selectedElements + }; + _movingElementChanged(this, eventArgs); + } + } - /// - /// indicates whether the selected elements could be pushed down in hierarchy - /// - /// true if selected elements could be pushed down, false otherwise - public bool CanPushSelectionDown() - { - return _elements.CanPushDown(selectedElements); - } + /// + /// Deselect the specified elements + /// + /// IDrawableContainerList + public void DeselectElements(IDrawableContainerList elements) + { + if (elements.Count == 0) + { + return; + } - public void Element_FieldChanged(object sender, FieldChangedEventArgs e) - { - selectedElements.HandleFieldChangedEvent(sender, e); - } + while (elements.Count > 0) + { + var element = elements[0]; + DeselectElement(element, false); + } - public bool IsOnSurface(IDrawableContainer container) - { - return _elements.Contains(container); - } + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs + { + Elements = selectedElements + }; + _movingElementChanged(this, eventArgs); + } - public Point ToSurfaceCoordinates(Point point) - { - Point[] points = { point }; - _zoomMatrix.TransformPoints(points); - return points[0]; - } + Invalidate(); + } - public Rectangle ToSurfaceCoordinates(Rectangle rc) - { - if (_zoomMatrix.IsIdentity) - { - return rc; - } - else - { - Point[] points = { rc.Location, rc.Location + rc.Size }; - _zoomMatrix.TransformPoints(points); - return new Rectangle( - points[0].X, - points[0].Y, - points[1].X - points[0].X, - points[1].Y - points[0].Y - ); - } - } + /// + /// Deselect all the selected elements + /// + public void DeselectAllElements() + { + DeselectElements(selectedElements); + } - public Point ToImageCoordinates(Point point) - { - Point[] points = { point }; - _inverseZoomMatrix.TransformPoints(points); - return points[0]; - } + /// + /// Select the supplied element + /// + /// + /// false to skip invalidation + /// false to skip event generation + public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true) + { + if (!selectedElements.Contains(container)) + { + selectedElements.Add(container); + container.Selected = true; + FieldAggregator.BindElement(container); + if (generateEvents && _movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs + { + Elements = selectedElements + }; + _movingElementChanged(this, eventArgs); + } - public Rectangle ToImageCoordinates(Rectangle rc) - { - if (_inverseZoomMatrix.IsIdentity) - { - return rc; - } - else - { - Point[] points = { rc.Location, rc.Location + rc.Size }; - _inverseZoomMatrix.TransformPoints(points); - return new Rectangle( - points[0].X, - points[0].Y, - points[1].X - points[0].X, - points[1].Y - points[0].Y - ); - } - } - } -} + if (invalidate) + { + container.Invalidate(); + } + } + } + + /// + /// Select all elements, this is called when Ctrl+A is pressed + /// + public void SelectAllElements() + { + SelectElements(_elements); + } + + /// + /// Select the supplied elements + /// + /// + public void SelectElements(IDrawableContainerList elements) + { + SuspendLayout(); + foreach (var drawableContainer in elements) + { + var element = (DrawableContainer) drawableContainer; + SelectElement(element, false, false); + } + + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs + { + Elements = selectedElements + }; + _movingElementChanged(this, eventArgs); + } + + ResumeLayout(); + Invalidate(); + } + + /// + /// Process key presses on the surface, this is called from the editor (and NOT an override from the Control) + /// + /// Keys + /// false if no keys were processed + public bool ProcessCmdKey(Keys k) + { + if (selectedElements.Count > 0) + { + bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; + int px = shiftModifier ? 10 : 1; + Point moveBy = Point.Empty; + + switch (k) + { + case Keys.Left: + case Keys.Left | Keys.Shift: + moveBy = new Point(-px, 0); + break; + case Keys.Up: + case Keys.Up | Keys.Shift: + moveBy = new Point(0, -px); + break; + case Keys.Right: + case Keys.Right | Keys.Shift: + moveBy = new Point(px, 0); + break; + case Keys.Down: + case Keys.Down | Keys.Shift: + moveBy = new Point(0, px); + break; + case Keys.PageUp: + PullElementsUp(); + break; + case Keys.PageDown: + PushElementsDown(); + break; + case Keys.Home: + PullElementsToTop(); + break; + case Keys.End: + PushElementsToBottom(); + break; + case Keys.Enter: + ConfirmSelectedConfirmableElements(true); + break; + case Keys.Escape: + ConfirmSelectedConfirmableElements(false); + break; + /*case Keys.Delete: + RemoveSelectedElements(); + break;*/ + default: + return false; + } + + if (!Point.Empty.Equals(moveBy)) + { + selectedElements.MakeBoundsChangeUndoable(true); + selectedElements.MoveBy(moveBy.X, moveBy.Y); + } + + return true; + } + + return false; + } + + /// + /// Property for accessing the elements on the surface + /// + public IDrawableContainerList Elements => _elements; + + /// + /// pulls selected elements up one level in hierarchy + /// + public void PullElementsUp() + { + _elements.PullElementsUp(selectedElements); + _elements.Invalidate(); + } + + /// + /// pushes selected elements up to top in hierarchy + /// + public void PullElementsToTop() + { + _elements.PullElementsToTop(selectedElements); + _elements.Invalidate(); + } + + /// + /// pushes selected elements down one level in hierarchy + /// + public void PushElementsDown() + { + _elements.PushElementsDown(selectedElements); + _elements.Invalidate(); + } + + /// + /// pushes selected elements down to bottom in hierarchy + /// + public void PushElementsToBottom() + { + _elements.PushElementsToBottom(selectedElements); + _elements.Invalidate(); + } + + /// + /// indicates whether the selected elements could be pulled up in hierarchy + /// + /// true if selected elements could be pulled up, false otherwise + public bool CanPullSelectionUp() + { + return _elements.CanPullUp(selectedElements); + } + + /// + /// indicates whether the selected elements could be pushed down in hierarchy + /// + /// true if selected elements could be pushed down, false otherwise + public bool CanPushSelectionDown() + { + return _elements.CanPushDown(selectedElements); + } + + public void Element_FieldChanged(object sender, FieldChangedEventArgs e) + { + selectedElements.HandleFieldChangedEvent(sender, e); + } + + public bool IsOnSurface(IDrawableContainer container) + { + return _elements.Contains(container); + } + + public Point ToSurfaceCoordinates(Point point) + { + Point[] points = + { + point + }; + _zoomMatrix.TransformPoints(points); + return points[0]; + } + + public Rectangle ToSurfaceCoordinates(Rectangle rc) + { + if (_zoomMatrix.IsIdentity) + { + return rc; + } + else + { + Point[] points = + { + rc.Location, rc.Location + rc.Size + }; + _zoomMatrix.TransformPoints(points); + return new Rectangle( + points[0].X, + points[0].Y, + points[1].X - points[0].X, + points[1].Y - points[0].Y + ); + } + } + + public Point ToImageCoordinates(Point point) + { + Point[] points = + { + point + }; + _inverseZoomMatrix.TransformPoints(points); + return points[0]; + } + + public Rectangle ToImageCoordinates(Rectangle rc) + { + if (_inverseZoomMatrix.IsIdentity) + { + return rc; + } + else + { + Point[] points = + { + rc.Location, rc.Location + rc.Size + }; + _inverseZoomMatrix.TransformPoints(points); + return new Rectangle( + points[0].X, + points[0].Y, + points[1].X - points[0].X, + points[1].Y - points[0].Y + ); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/TextContainer.cs b/src/Greenshot/Drawing/TextContainer.cs index 9d3838580..8f1a819f6 100644 --- a/src/Greenshot/Drawing/TextContainer.cs +++ b/src/Greenshot/Drawing/TextContainer.cs @@ -46,24 +46,22 @@ namespace Greenshot.Drawing // Although the name is wrong, we can't change it due to file serialization // ReSharper disable once InconsistentNaming private bool makeUndoable; - [NonSerialized] - private Font _font; + [NonSerialized] private Font _font; public Font Font => _font; - [NonSerialized] - private TextBox _textBox; + [NonSerialized] private TextBox _textBox; /// /// The StringFormat object is not serializable!! /// - [NonSerialized] - private StringFormat _stringFormat = new StringFormat(); + [NonSerialized] private StringFormat _stringFormat = new StringFormat(); public StringFormat StringFormat => _stringFormat; // Although the name is wrong, we can't change it due to file serialization // ReSharper disable once InconsistentNaming private string text; + // there is a binding on the following property! public string Text { @@ -74,12 +72,13 @@ namespace Greenshot.Drawing internal void ChangeText(string newText, bool allowUndoable) { if ((text != null || newText == null) && string.Equals(text, newText)) return; - + if (makeUndoable && allowUndoable) { makeUndoable = false; _parent.MakeUndoable(new TextChangeMemento(this), false); } + text = newText; OnPropertyChanged("Text"); } @@ -122,17 +121,20 @@ namespace Greenshot.Drawing _font.Dispose(); _font = null; } + if (_stringFormat != null) { _stringFormat.Dispose(); _stringFormat = null; } + if (_textBox != null) { _textBox.Dispose(); _textBox = null; } } + base.Dispose(disposing); } @@ -158,6 +160,7 @@ namespace Greenshot.Drawing { _parent.SizeChanged -= Parent_SizeChanged; } + base.SwitchParent(newParent); if (_parent != null) { @@ -224,6 +227,7 @@ namespace Greenshot.Drawing _parent.KeysLocked = true; } } + if (_textBox.Visible) { _textBox.Invalidate(); @@ -236,10 +240,12 @@ namespace Greenshot.Drawing { return; } + if (_textBox.Visible) { _textBox.Invalidate(); } + // Only dispose the font, and re-create it, when a font field has changed. if (e.Field.FieldType.Name.StartsWith("FONT")) { @@ -248,12 +254,14 @@ namespace Greenshot.Drawing _font.Dispose(); _font = null; } + UpdateFormat(); } else { UpdateAlignment(); } + UpdateTextBoxFormat(); if (_textBox.Visible) @@ -292,6 +300,7 @@ namespace Greenshot.Drawing _parent.KeysLocked = true; _parent.Controls.Add(_textBox); } + EnsureTextBoxContrast(); if (_textBox != null) { @@ -309,6 +318,7 @@ namespace Greenshot.Drawing { return; } + Color lc = GetFieldValueAsColor(FieldType.LINE_COLOR); if (lc.R > 203 && lc.G > 203 && lc.B > 203) { @@ -328,6 +338,7 @@ namespace Greenshot.Drawing { return; } + _parent.KeysLocked = false; _parent.Controls.Remove(_textBox); } @@ -346,7 +357,7 @@ namespace Greenshot.Drawing rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); int pixelsAfter = rect.Width * rect.Height; - float factor = pixelsAfter / (float)pixelsBefore; + float factor = pixelsAfter / (float) pixelsBefore; float fontSize = GetFieldValueAsFloat(FieldType.FONT_SIZE); fontSize *= factor; @@ -393,6 +404,7 @@ namespace Greenshot.Drawing } } } + return new Font(fontFamily, fontSize, fontStyle, GraphicsUnit.Pixel); } @@ -405,6 +417,7 @@ namespace Greenshot.Drawing { return; } + string fontFamily = GetFieldValueAsString(FieldType.FONT_FAMILY); bool fontBold = GetFieldValueAsBool(FieldType.FONT_BOLD); bool fontItalic = GetFieldValueAsBool(FieldType.FONT_ITALIC); @@ -444,8 +457,8 @@ namespace Greenshot.Drawing private void UpdateAlignment() { - _stringFormat.Alignment = (StringAlignment)GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); - _stringFormat.LineAlignment = (StringAlignment)GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT); + _stringFormat.Alignment = (StringAlignment) GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); + _stringFormat.LineAlignment = (StringAlignment) GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT); } /// @@ -465,7 +478,7 @@ namespace Greenshot.Drawing _font.Size * textBoxFontScale, _font.Style, GraphicsUnit.Pixel - ); + ); _textBox.Font.Dispose(); _textBox.Font = newFont; } @@ -480,15 +493,17 @@ namespace Greenshot.Drawing { return; } + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - int lineWidth = (int)Math.Floor(lineThickness / 2d); + int lineWidth = (int) Math.Floor(lineThickness / 2d); int correction = (lineThickness + 1) % 2; if (lineThickness <= 1) { lineWidth = 1; correction = -1; } + Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); Rectangle displayRectangle = Parent.ToSurfaceCoordinates(absRectangle); _textBox.Left = displayRectangle.X + lineWidth; @@ -497,6 +512,7 @@ namespace Greenshot.Drawing { lineWidth = 0; } + _textBox.Width = displayRectangle.Width - 2 * lineWidth + correction; _textBox.Height = displayRectangle.Height - 2 * lineWidth + correction; } @@ -510,7 +526,8 @@ namespace Greenshot.Drawing { return; } - var alignment = (StringAlignment)GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); + + var alignment = (StringAlignment) GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); switch (alignment) { case StringAlignment.Near: @@ -541,6 +558,7 @@ namespace Greenshot.Drawing { _textBox.SelectAll(); } + // Added for FEATURE-1064 if (e.KeyCode == Keys.Back && e.Control) { @@ -550,11 +568,13 @@ namespace Greenshot.Drawing { selStart--; } + int prevSpacePos = -1; if (selStart != 0) { prevSpacePos = _textBox.Text.LastIndexOf(' ', selStart - 1); } + _textBox.Select(prevSpacePos + 1, _textBox.SelectionStart - prevSpacePos - 1); _textBox.SelectedText = string.Empty; } @@ -611,6 +631,7 @@ namespace Greenshot.Drawing { return flags; } + switch (stringFormat.LineAlignment) { case StringAlignment.Center: @@ -623,6 +644,7 @@ namespace Greenshot.Drawing flags |= TextFormatFlags.Top; break; } + switch (stringFormat.Alignment) { case StringAlignment.Center: @@ -650,7 +672,8 @@ namespace Greenshot.Drawing /// /// /// - public static void DrawText(Graphics graphics, Rectangle drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text, Font font) + public static void DrawText(Graphics graphics, Rectangle drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text, + Font font) { #if DEBUG Debug.Assert(font != null); @@ -660,7 +683,7 @@ namespace Greenshot.Drawing return; } #endif - int textOffset = lineThickness > 0 ? (int)Math.Ceiling(lineThickness / 2d) : 0; + int textOffset = lineThickness > 0 ? (int) Math.Ceiling(lineThickness / 2d) : 0; // draw shadow before anything else if (drawShadow) { @@ -699,4 +722,4 @@ namespace Greenshot.Drawing return r.Contains(x, y); } } -} +} \ No newline at end of file diff --git a/src/Greenshot/Forms/AboutForm.cs b/src/Greenshot/Forms/AboutForm.cs index f3c67edd8..6fdf4eddd 100644 --- a/src/Greenshot/Forms/AboutForm.cs +++ b/src/Greenshot/Forms/AboutForm.cs @@ -34,246 +34,280 @@ using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using log4net; -namespace Greenshot.Forms { - /// - /// The about form - /// - public sealed partial class AboutForm : AnimatingBaseForm { - private static readonly ILog Log = LogManager.GetLogger(typeof(AboutForm)); - private Bitmap _bitmap; - private readonly ColorAnimator _backgroundAnimation; - private readonly List _pixels = new List(); - private readonly List _colorFlow = new List(); - private readonly List _pixelColors = new List(); - private readonly Random _rand = new Random(); - private readonly Color _backColor = Color.FromArgb(61, 61, 61); - private readonly Color _pixelColor = Color.FromArgb(138, 255, 0); +namespace Greenshot.Forms +{ + /// + /// The about form + /// + public sealed partial class AboutForm : AnimatingBaseForm + { + private static readonly ILog Log = LogManager.GetLogger(typeof(AboutForm)); + private Bitmap _bitmap; + private readonly ColorAnimator _backgroundAnimation; + private readonly List _pixels = new List(); + private readonly List _colorFlow = new List(); + private readonly List _pixelColors = new List(); + private readonly Random _rand = new Random(); + private readonly Color _backColor = Color.FromArgb(61, 61, 61); + private readonly Color _pixelColor = Color.FromArgb(138, 255, 0); - // Variables used for the color-cycle - private int _waitFrames; - private int _colorIndex; - private int _scrollCount; - private bool _hasAnimationsLeft; + // Variables used for the color-cycle + private int _waitFrames; + private int _colorIndex; + private int _scrollCount; + private bool _hasAnimationsLeft; - // Variables are used to define the location of the dots - private const int W = 13; - private const int P1 = 7; - private const int P2 = P1 + W; - private const int P3 = P2 + W; - private const int P4 = P3 + W; - private const int P5 = P4 + W; - private const int P6 = P5 + W; - private const int P7 = P6 + W; + // Variables are used to define the location of the dots + private const int W = 13; + private const int P1 = 7; + private const int P2 = P1 + W; + private const int P3 = P2 + W; + private const int P4 = P3 + W; + private const int P5 = P4 + W; + private const int P6 = P5 + W; + private const int P7 = P6 + W; - /// - /// The location of every dot in the "G" - /// - private readonly List _gSpots = new List + /// + /// The location of every dot in the "G" + /// + private readonly List _gSpots = new List { - // Top row - new Point(P2, P1), // 0 - new Point(P3, P1), // 1 - new Point(P4, P1), // 2 - new Point(P5, P1), // 3 - new Point(P6, P1), // 4 + // Top row + new Point(P2, P1), // 0 + new Point(P3, P1), // 1 + new Point(P4, P1), // 2 + new Point(P5, P1), // 3 + new Point(P6, P1), // 4 - // Second row - new Point(P1, P2), // 5 - new Point(P2, P2), // 6 + // Second row + new Point(P1, P2), // 5 + new Point(P2, P2), // 6 - // Third row - new Point(P1, P3), // 7 - new Point(P2, P3), // 8 + // Third row + new Point(P1, P3), // 7 + new Point(P2, P3), // 8 - // Fourth row - new Point(P1, P4), // 9 - new Point(P2, P4), // 10 - new Point(P5, P4), // 11 - new Point(P6, P4), // 12 - new Point(P7, P4), // 13 + // Fourth row + new Point(P1, P4), // 9 + new Point(P2, P4), // 10 + new Point(P5, P4), // 11 + new Point(P6, P4), // 12 + new Point(P7, P4), // 13 - // Fifth row - new Point(P1, P5), // 14 - new Point(P2, P5), // 15 - new Point(P6, P5), // 16 - new Point(P7, P5), // 17 + // Fifth row + new Point(P1, P5), // 14 + new Point(P2, P5), // 15 + new Point(P6, P5), // 16 + new Point(P7, P5), // 17 - // Sixth row - new Point(P1, P6), // 18 - new Point(P2, P6), // 19 - new Point(P3, P6), // 20 - new Point(P4, P6), // 21 - new Point(P5, P6), // 22 - new Point(P6, P6) // 23 - }; + // Sixth row + new Point(P1, P6), // 18 + new Point(P2, P6), // 19 + new Point(P3, P6), // 20 + new Point(P4, P6), // 21 + new Point(P5, P6), // 22 + new Point(P6, P6) // 23 + }; - // 0 1 2 3 4 - // 5 6 - // 7 8 - // 9 10 11 12 13 - // 14 15 16 17 - // 18 19 20 21 22 23 + // 0 1 2 3 4 + // 5 6 + // 7 8 + // 9 10 11 12 13 + // 14 15 16 17 + // 18 19 20 21 22 23 - // The order in which we draw the dots & flow the colors. - private readonly List _flowOrder = new List{ 4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11 }; + // The order in which we draw the dots & flow the colors. + private readonly List _flowOrder = new List{ 4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11 }; - /// - /// Cleanup all the allocated resources - /// - private void Cleanup(object sender, EventArgs e) { + /// + /// Cleanup all the allocated resources + /// + private void Cleanup(object sender, EventArgs e) + { if (_bitmap == null) return; _bitmap.Dispose(); _bitmap = null; } - /// - /// Constructor - /// - public AboutForm() { - // Make sure our resources are removed again. - Disposed += Cleanup; - FormClosing += Cleanup; + /// + /// Constructor + /// + public AboutForm() + { + // Make sure our resources are removed again. + Disposed += Cleanup; + FormClosing += Cleanup; - // Enable animation for this form, when we don't set this the timer doesn't start as soon as the form is loaded. - EnableAnimation = true; - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); + // Enable animation for this form, when we don't set this the timer doesn't start as soon as the form is loaded. + EnableAnimation = true; + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); - // Only use double-buffering when we are NOT in a Terminal Server session - DoubleBuffered = !IsTerminalServerSession; + // Only use double-buffering when we are NOT in a Terminal Server session + DoubleBuffered = !IsTerminalServerSession; - // Use the self drawn image, first we create the background to be the back-color (as we animate from this) + // Use the self drawn image, first we create the background to be the back-color (as we animate from this) - _bitmap = ImageHelper.CreateEmpty(90, 90, PixelFormat.Format24bppRgb, BackColor, 96, 96); - pictureBox1.Image = _bitmap; + _bitmap = ImageHelper.CreateEmpty(90, 90, PixelFormat.Format24bppRgb, BackColor, 96, 96); + pictureBox1.Image = _bitmap; lblTitle.Text = $@"Greenshot {EnvironmentInfo.GetGreenshotVersion()} {(IniConfig.IsPortable ? " Portable" : "")} ({OsInfo.Bits}) bit)"; - // Number of frames the pixel animation takes - int frames = FramesForMillis(2000); - // The number of frames the color-cycle waits before it starts - _waitFrames = FramesForMillis(6000); + // Number of frames the pixel animation takes + int frames = FramesForMillis(2000); + // The number of frames the color-cycle waits before it starts + _waitFrames = FramesForMillis(6000); - // Every pixel is created after pixelWaitFrames frames, which is increased in the loop. - int pixelWaitFrames = FramesForMillis(2000); - // Create pixels - for (int index = 0; index < _gSpots.Count; index++) { - // Read the pixels in the order of the flow - Point gSpot = _gSpots[_flowOrder[index]]; - // Create the animation, first we do nothing (on the final destination) - RectangleAnimator pixelAnimation; + // Every pixel is created after pixelWaitFrames frames, which is increased in the loop. + int pixelWaitFrames = FramesForMillis(2000); + // Create pixels + for (int index = 0; index < _gSpots.Count; index++) + { + // Read the pixels in the order of the flow + Point gSpot = _gSpots[_flowOrder[index]]; + // Create the animation, first we do nothing (on the final destination) + RectangleAnimator pixelAnimation; - // Make the pixel grow from the middle, if this offset isn't used it looks like it's shifted - int offset = (W - 2) / 2; + // Make the pixel grow from the middle, if this offset isn't used it looks like it's shifted + int offset = (W - 2) / 2; - // If the optimize for Terminal Server is set we make the animation without much ado - if (IsTerminalServerSession) { - // No animation - pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic, EasingMode.EaseIn); - } else { - // Create the animation, first we do nothing (on the final destination) - Rectangle standingStill = new Rectangle(gSpot.X + offset, gSpot.Y + offset, 0, 0); - pixelAnimation = new RectangleAnimator(standingStill, standingStill, pixelWaitFrames, EasingType.Quintic, EasingMode.EaseIn); - // And than we size to the wanted size. - pixelAnimation.QueueDestinationLeg(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), frames); - } - // Increase the wait frames - pixelWaitFrames += FramesForMillis(100); - // Add to the list of to be animated pixels - _pixels.Add(pixelAnimation); - // Add a color to the list for this pixel. - _pixelColors.Add(_pixelColor); - } - // Make sure the frame "loop" knows we have to animate - _hasAnimationsLeft = true; + // If the optimize for Terminal Server is set we make the animation without much ado + if (IsTerminalServerSession) + { + // No animation + pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic, + EasingMode.EaseIn); + } + else + { + // Create the animation, first we do nothing (on the final destination) + Rectangle standingStill = new Rectangle(gSpot.X + offset, gSpot.Y + offset, 0, 0); + pixelAnimation = new RectangleAnimator(standingStill, standingStill, pixelWaitFrames, EasingType.Quintic, EasingMode.EaseIn); + // And than we size to the wanted size. + pixelAnimation.QueueDestinationLeg(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), frames); + } - // Pixel Color cycle colors, here we use a pre-animated loop which stores the values. - ColorAnimator pixelColorAnimator = new ColorAnimator(_pixelColor, Color.FromArgb(255, 255, 255), 6, EasingType.Quadratic, EasingMode.EaseIn); - pixelColorAnimator.QueueDestinationLeg(_pixelColor, 6, EasingType.Quadratic, EasingMode.EaseOut); - do { - _colorFlow.Add(pixelColorAnimator.Current); - pixelColorAnimator.Next(); - } while (pixelColorAnimator.HasNext); + // Increase the wait frames + pixelWaitFrames += FramesForMillis(100); + // Add to the list of to be animated pixels + _pixels.Add(pixelAnimation); + // Add a color to the list for this pixel. + _pixelColors.Add(_pixelColor); + } - // color animation for the background - _backgroundAnimation = new ColorAnimator(BackColor, _backColor, FramesForMillis(5000), EasingType.Linear, EasingMode.EaseIn); - } + // Make sure the frame "loop" knows we have to animate + _hasAnimationsLeft = true; - /// - /// This is called when a link is clicked - /// - /// - /// - private void LinkLabelClicked(object sender, LinkLabelLinkClickedEventArgs e) + // Pixel Color cycle colors, here we use a pre-animated loop which stores the values. + ColorAnimator pixelColorAnimator = new ColorAnimator(_pixelColor, Color.FromArgb(255, 255, 255), 6, EasingType.Quadratic, EasingMode.EaseIn); + pixelColorAnimator.QueueDestinationLeg(_pixelColor, 6, EasingType.Quadratic, EasingMode.EaseOut); + do + { + _colorFlow.Add(pixelColorAnimator.Current); + pixelColorAnimator.Next(); + } while (pixelColorAnimator.HasNext); + + // color animation for the background + _backgroundAnimation = new ColorAnimator(BackColor, _backColor, FramesForMillis(5000), EasingType.Linear, EasingMode.EaseIn); + } + + /// + /// This is called when a link is clicked + /// + /// + /// + private void LinkLabelClicked(object sender, LinkLabelLinkClickedEventArgs e) { if (!(sender is LinkLabel linkLabel)) return; - try { + try + { linkLabel.LinkVisited = true; Process.Start(linkLabel.Text); - } catch (Exception) { + } + catch (Exception) + { MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, linkLabel.Text), Language.GetString(LangKey.error)); } } - /// - /// Called from the AnimatingForm, for every frame - /// - protected override void Animate() { - if (_bitmap == null) { - return; - } - if (!IsTerminalServerSession) { - // Color cycle - if (_waitFrames != 0) { - _waitFrames--; - // Check if there is something else to do, if not we return so we don't occupy the CPU - if (!_hasAnimationsLeft) { - return; - } - } else if (_scrollCount < _pixelColors.Count + _colorFlow.Count) { - // Scroll colors, the scrollCount is the amount of pixels + the amount of colors to cycle. - for (int index = _pixelColors.Count - 1; index > 0; index--) { - _pixelColors[index] = _pixelColors[index - 1]; - } - // Keep adding from the colors to cycle until there is nothing left - if (_colorIndex < _colorFlow.Count) { - _pixelColors[0] = _colorFlow[_colorIndex++]; - } - _scrollCount++; - } else { - // Reset values, wait X time for the next one - _waitFrames = FramesForMillis(3000 + _rand.Next(35000)); - _colorIndex = 0; - _scrollCount = 0; - // Check if there is something else to do, if not we return so we don't occupy the CPU - if (!_hasAnimationsLeft) { - return; - } - } - } else if (!_hasAnimationsLeft) { - return; - } + /// + /// Called from the AnimatingForm, for every frame + /// + protected override void Animate() + { + if (_bitmap == null) + { + return; + } - // Draw the "G" - using (Graphics graphics = Graphics.FromImage(_bitmap)) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + if (!IsTerminalServerSession) + { + // Color cycle + if (_waitFrames != 0) + { + _waitFrames--; + // Check if there is something else to do, if not we return so we don't occupy the CPU + if (!_hasAnimationsLeft) + { + return; + } + } + else if (_scrollCount < _pixelColors.Count + _colorFlow.Count) + { + // Scroll colors, the scrollCount is the amount of pixels + the amount of colors to cycle. + for (int index = _pixelColors.Count - 1; index > 0; index--) + { + _pixelColors[index] = _pixelColors[index - 1]; + } - graphics.Clear(_backgroundAnimation.Next()); + // Keep adding from the colors to cycle until there is nothing left + if (_colorIndex < _colorFlow.Count) + { + _pixelColors[0] = _colorFlow[_colorIndex++]; + } - graphics.TranslateTransform(2, -2); - graphics.RotateTransform(20); + _scrollCount++; + } + else + { + // Reset values, wait X time for the next one + _waitFrames = FramesForMillis(3000 + _rand.Next(35000)); + _colorIndex = 0; + _scrollCount = 0; + // Check if there is something else to do, if not we return so we don't occupy the CPU + if (!_hasAnimationsLeft) + { + return; + } + } + } + else if (!_hasAnimationsLeft) + { + return; + } + + // Draw the "G" + using (Graphics graphics = Graphics.FromImage(_bitmap)) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + graphics.Clear(_backgroundAnimation.Next()); + + graphics.TranslateTransform(2, -2); + graphics.RotateTransform(20); using SolidBrush brush = new SolidBrush(_pixelColor); int index = 0; // We assume there is nothing to animate in the next Animate loop _hasAnimationsLeft = false; // Pixels of the G - foreach (RectangleAnimator pixel in _pixels) { + foreach (RectangleAnimator pixel in _pixels) + { brush.Color = _pixelColors[index++]; graphics.FillEllipse(brush, pixel.Current); // If a pixel still has frames left, the hasAnimationsLeft will be true @@ -281,53 +315,75 @@ namespace Greenshot.Forms { pixel.Next(); } } - pictureBox1.Invalidate(); - } - /// - /// CmdKey handler - /// - /// - /// - /// - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { - try { - switch (keyData) { - case Keys.Escape: - DialogResult = DialogResult.Cancel; - break; - case Keys.E: - MessageBox.Show(EnvironmentInfo.EnvironmentToString(true)); - break; - case Keys.L: - try { - if (File.Exists(MainForm.LogFileLocation)) { - using (Process.Start("\"" + MainForm.LogFileLocation + "\"")) { - // nothing to do, just using dispose to cleanup - } - } else { - MessageBox.Show(@"Greenshot can't find the logfile, it should have been here: " + MainForm.LogFileLocation); - } - } catch (Exception) { - MessageBox.Show(@"Couldn't open the greenshot.log, it's located here: " + MainForm.LogFileLocation, @"Error opening greenshot.log", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); - } - break; - case Keys.I: - try { - using (Process.Start("\"" + IniConfig.ConfigLocation + "\"")) { - } - } catch (Exception) { - MessageBox.Show(@"Couldn't open the greenshot.ini, it's located here: " + IniConfig.ConfigLocation, @"Error opening greenshot.ini", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); - } - break; - default: - return base.ProcessCmdKey(ref msg, keyData); - } - } catch (Exception ex) { - Log.Error($"Error handling key '{keyData}'", ex); - } - return true; - } - } + pictureBox1.Invalidate(); + } + + /// + /// CmdKey handler + /// + /// + /// + /// + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + try + { + switch (keyData) + { + case Keys.Escape: + DialogResult = DialogResult.Cancel; + break; + case Keys.E: + MessageBox.Show(EnvironmentInfo.EnvironmentToString(true)); + break; + case Keys.L: + try + { + if (File.Exists(MainForm.LogFileLocation)) + { + using (Process.Start("\"" + MainForm.LogFileLocation + "\"")) + { + // nothing to do, just using dispose to cleanup + } + } + else + { + MessageBox.Show(@"Greenshot can't find the logfile, it should have been here: " + MainForm.LogFileLocation); + } + } + catch (Exception) + { + MessageBox.Show(@"Couldn't open the greenshot.log, it's located here: " + MainForm.LogFileLocation, @"Error opening greenshot.log", + MessageBoxButtons.OK, MessageBoxIcon.Asterisk); + } + + break; + case Keys.I: + try + { + using (Process.Start("\"" + IniConfig.ConfigLocation + "\"")) + { + } + } + catch (Exception) + { + MessageBox.Show(@"Couldn't open the greenshot.ini, it's located here: " + IniConfig.ConfigLocation, @"Error opening greenshot.ini", + MessageBoxButtons.OK, MessageBoxIcon.Asterisk); + } + + break; + default: + return base.ProcessCmdKey(ref msg, keyData); + } + } + catch (Exception ex) + { + Log.Error($"Error handling key '{keyData}'", ex); + } + + return true; + } + } } \ No newline at end of file diff --git a/src/Greenshot/Forms/AnimatingBaseForm.cs b/src/Greenshot/Forms/AnimatingBaseForm.cs index 5456ba037..7f9fec60e 100644 --- a/src/Greenshot/Forms/AnimatingBaseForm.cs +++ b/src/Greenshot/Forms/AnimatingBaseForm.cs @@ -21,10 +21,12 @@ using GreenshotPlugin.Controls; -namespace Greenshot.Forms { - /// - /// This class is only here to help in the Designer mode, so it's clear where the language files are - /// - public class AnimatingBaseForm : AnimatingForm { - } -} +namespace Greenshot.Forms +{ + /// + /// This class is only here to help in the Designer mode, so it's clear where the language files are + /// + public class AnimatingBaseForm : AnimatingForm + { + } +} \ No newline at end of file diff --git a/src/Greenshot/Forms/BaseForm.cs b/src/Greenshot/Forms/BaseForm.cs index ffc0e86db..e67654df5 100644 --- a/src/Greenshot/Forms/BaseForm.cs +++ b/src/Greenshot/Forms/BaseForm.cs @@ -21,10 +21,12 @@ using GreenshotPlugin.Controls; -namespace Greenshot.Forms { - /// - /// This class is only here to help in the Designer mode, so it's clear where the language files are - /// - public class BaseForm : GreenshotForm { - } -} +namespace Greenshot.Forms +{ + /// + /// This class is only here to help in the Designer mode, so it's clear where the language files are + /// + public class BaseForm : GreenshotForm + { + } +} \ No newline at end of file diff --git a/src/Greenshot/Forms/BugReportForm.cs b/src/Greenshot/Forms/BugReportForm.cs index 7c26e1b54..b42f20d18 100644 --- a/src/Greenshot/Forms/BugReportForm.cs +++ b/src/Greenshot/Forms/BugReportForm.cs @@ -18,37 +18,47 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Diagnostics; using System.Windows.Forms; using Greenshot.Configuration; using GreenshotPlugin.Core; -namespace Greenshot.Forms { - public partial class BugReportForm : BaseForm { - private BugReportForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - ToFront = true; - } +namespace Greenshot.Forms +{ + public partial class BugReportForm : BaseForm + { + private BugReportForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + ToFront = true; + } - public BugReportForm(string bugText) : this() { - textBoxDescription.Text = bugText; - } + public BugReportForm(string bugText) : this() + { + textBoxDescription.Text = bugText; + } - private void LinkLblBugsLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - openLink((LinkLabel)sender); - } + private void LinkLblBugsLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + openLink((LinkLabel) sender); + } - private void openLink(LinkLabel link) { - try { - link.LinkVisited = true; - Process.Start(link.Text); - } catch (Exception) { - MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, link.Text), Language.GetString(LangKey.error)); - } - } - } -} + private void openLink(LinkLabel link) + { + try + { + link.LinkVisited = true; + Process.Start(link.Text); + } + catch (Exception) + { + MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, link.Text), Language.GetString(LangKey.error)); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs index 3cc04ebf6..efdf7583c 100644 --- a/src/Greenshot/Forms/CaptureForm.cs +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -39,365 +39,416 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Ocr; -namespace Greenshot.Forms { - /// - /// The capture form is used to select a part of the capture - /// - public sealed partial class CaptureForm : AnimatingForm { - private enum FixMode {None, Initiated, Horizontal, Vertical}; +namespace Greenshot.Forms +{ + /// + /// The capture form is used to select a part of the capture + /// + public sealed partial class CaptureForm : AnimatingForm + { + private enum FixMode + { + None, + Initiated, + Horizontal, + Vertical + }; - private static readonly ILog Log = LogManager.GetLogger(typeof(CaptureForm)); - private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); - private static readonly Brush GreenOverlayBrush = new SolidBrush(Color.FromArgb(50, Color.MediumSeaGreen)); - private static readonly Pen OverlayPen = new Pen(Color.FromArgb(50, Color.Black)); - private static CaptureForm _currentForm; - private static readonly Brush BackgroundBrush; + private static readonly ILog Log = LogManager.GetLogger(typeof(CaptureForm)); + private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); + private static readonly Brush GreenOverlayBrush = new SolidBrush(Color.FromArgb(50, Color.MediumSeaGreen)); + private static readonly Pen OverlayPen = new Pen(Color.FromArgb(50, Color.Black)); + private static CaptureForm _currentForm; + private static readonly Brush BackgroundBrush; - /// - /// Initialize the background brush - /// - static CaptureForm() { - Image backgroundForTransparency = GreenshotResources.GetImage("Checkerboard.Image"); - BackgroundBrush = new TextureBrush(backgroundForTransparency, WrapMode.Tile); - } + /// + /// Initialize the background brush + /// + static CaptureForm() + { + Image backgroundForTransparency = GreenshotResources.GetImage("Checkerboard.Image"); + BackgroundBrush = new TextureBrush(backgroundForTransparency, WrapMode.Tile); + } - private int _mX; - private int _mY; - private Point _mouseMovePos = Point.Empty; - private Point _cursorPos; - private CaptureMode _captureMode; - private readonly List _windows; - private WindowDetails _selectedCaptureWindow; - private bool _mouseDown; - private Rectangle _captureRect = Rectangle.Empty; - private readonly ICapture _capture; - private Point _previousMousePos = Point.Empty; - private FixMode _fixMode = FixMode.None; - private RectangleAnimator _windowAnimator; - private RectangleAnimator _zoomAnimator; - private readonly bool _isZoomerTransparent = Conf.ZoomerOpacity < 1; - private bool _isCtrlPressed; - private bool _showDebugInfo; + private int _mX; + private int _mY; + private Point _mouseMovePos = Point.Empty; + private Point _cursorPos; + private CaptureMode _captureMode; + private readonly List _windows; + private WindowDetails _selectedCaptureWindow; + private bool _mouseDown; + private Rectangle _captureRect = Rectangle.Empty; + private readonly ICapture _capture; + private Point _previousMousePos = Point.Empty; + private FixMode _fixMode = FixMode.None; + private RectangleAnimator _windowAnimator; + private RectangleAnimator _zoomAnimator; + private readonly bool _isZoomerTransparent = Conf.ZoomerOpacity < 1; + private bool _isCtrlPressed; + private bool _showDebugInfo; - /// - /// Property to access the selected capture rectangle - /// - public Rectangle CaptureRectangle => _captureRect; + /// + /// Property to access the selected capture rectangle + /// + public Rectangle CaptureRectangle => _captureRect; - /// - /// Property to access the used capture mode - /// - public CaptureMode UsedCaptureMode => _captureMode; + /// + /// Property to access the used capture mode + /// + public CaptureMode UsedCaptureMode => _captureMode; - /// - /// Get the selected window - /// - public WindowDetails SelectedCaptureWindow => _selectedCaptureWindow; + /// + /// Get the selected window + /// + public WindowDetails SelectedCaptureWindow => _selectedCaptureWindow; - /// - /// This should prevent children to draw backgrounds - /// - protected override CreateParams CreateParams { - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - get { - CreateParams createParams = base.CreateParams; - createParams.ExStyle |= 0x02000000; - return createParams; - } - } + /// + /// This should prevent children to draw backgrounds + /// + protected override CreateParams CreateParams + { + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + get + { + CreateParams createParams = base.CreateParams; + createParams.ExStyle |= 0x02000000; + return createParams; + } + } - private void ClosedHandler(object sender, EventArgs e) { - _currentForm = null; - // Change the final mode + private void ClosedHandler(object sender, EventArgs e) + { + _currentForm = null; + // Change the final mode if (_captureMode == CaptureMode.Text) { _capture.CaptureDetails.CaptureMode = CaptureMode.Text; - } - Log.Debug("Remove CaptureForm from currentForm"); - } + } - private void ClosingHandler(object sender, EventArgs e) { - Log.Debug("Closing capture form"); - WindowDetails.UnregisterIgnoreHandle(Handle); - } + Log.Debug("Remove CaptureForm from currentForm"); + } - /// - /// This creates the capture form - /// - /// - /// - public CaptureForm(ICapture capture, List windows) { - if (_currentForm != null) { - Log.Warn("Found currentForm, Closing already opened CaptureForm"); - _currentForm.Close(); - _currentForm = null; - Application.DoEvents(); - } - _currentForm = this; + private void ClosingHandler(object sender, EventArgs e) + { + Log.Debug("Closing capture form"); + WindowDetails.UnregisterIgnoreHandle(Handle); + } - // Enable the AnimatingForm - EnableAnimation = true; + /// + /// This creates the capture form + /// + /// + /// + public CaptureForm(ICapture capture, List windows) + { + if (_currentForm != null) + { + Log.Warn("Found currentForm, Closing already opened CaptureForm"); + _currentForm.Close(); + _currentForm = null; + Application.DoEvents(); + } - // clean up - FormClosed += ClosedHandler; + _currentForm = this; - _capture = capture; - _windows = windows; - _captureMode = capture.CaptureDetails.CaptureMode; + // Enable the AnimatingForm + EnableAnimation = true; - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - // Only double-buffer when we are not in a TerminalServerSession - DoubleBuffered = !IsTerminalServerSession; - Text = @"Greenshot capture form"; + // clean up + FormClosed += ClosedHandler; - // Make sure we never capture the capture-form - WindowDetails.RegisterIgnoreHandle(Handle); - // Un-register at close - FormClosing += ClosingHandler; + _capture = capture; + _windows = windows; + _captureMode = capture.CaptureDetails.CaptureMode; - // set cursor location - _cursorPos = WindowCapture.GetCursorLocationRelativeToScreenBounds(); + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + // Only double-buffer when we are not in a TerminalServerSession + DoubleBuffered = !IsTerminalServerSession; + Text = @"Greenshot capture form"; - // Initialize the animations, the window capture zooms out from the cursor to the window under the cursor - if (_captureMode == CaptureMode.Window) { - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); - } + // Make sure we never capture the capture-form + WindowDetails.RegisterIgnoreHandle(Handle); + // Un-register at close + FormClosing += ClosingHandler; - // Set the zoomer animation - InitializeZoomer(Conf.ZoomerEnabled); + // set cursor location + _cursorPos = WindowCapture.GetCursorLocationRelativeToScreenBounds(); - SuspendLayout(); - Bounds = capture.ScreenBounds; - ResumeLayout(); + // Initialize the animations, the window capture zooms out from the cursor to the window under the cursor + if (_captureMode == CaptureMode.Window) + { + _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); + } - // Fix missing focus - ToFront = true; - TopMost = true; - } + // Set the zoomer animation + InitializeZoomer(Conf.ZoomerEnabled); - /// - /// Create an animation for the zoomer, depending on if it's active or not. - /// - private void InitializeZoomer(bool isOn) { - if (isOn) { - // Initialize the zoom with a invalid position - _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut); - VerifyZoomAnimation(_cursorPos, false); - } - else - { - _zoomAnimator?.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), FramesForMillis(1000)); - } - } + SuspendLayout(); + Bounds = capture.ScreenBounds; + ResumeLayout(); - private void CaptureFormKeyUp(object sender, KeyEventArgs e) { - switch(e.KeyCode) { - case Keys.ShiftKey: - _fixMode = FixMode.None; - break; - case Keys.ControlKey: - _isCtrlPressed = false; - break; - } - } + // Fix missing focus + ToFront = true; + TopMost = true; + } - /// - /// Handle the key down event - /// - /// - /// - private void CaptureFormKeyDown(object sender, KeyEventArgs e) { - int step = _isCtrlPressed ? 10 : 1; + /// + /// Create an animation for the zoomer, depending on if it's active or not. + /// + private void InitializeZoomer(bool isOn) + { + if (isOn) + { + // Initialize the zoom with a invalid position + _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, + EasingMode.EaseOut); + VerifyZoomAnimation(_cursorPos, false); + } + else + { + _zoomAnimator?.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), FramesForMillis(1000)); + } + } - switch (e.KeyCode) { - case Keys.Up: - Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y - step); - break; - case Keys.Down: - Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + step); - break; - case Keys.Left: - Cursor.Position = new Point(Cursor.Position.X - step, Cursor.Position.Y); - break; - case Keys.Right: - Cursor.Position = new Point(Cursor.Position.X + step, Cursor.Position.Y); - break; - case Keys.ShiftKey: - // Fix mode - if (_fixMode == FixMode.None) { - _fixMode = FixMode.Initiated; - } - break; - case Keys.ControlKey: - _isCtrlPressed = true; - break; - case Keys.Escape: - // Cancel - DialogResult = DialogResult.Cancel; - break; - case Keys.M: - // Toggle mouse cursor - _capture.CursorVisible = !_capture.CursorVisible; - Invalidate(); - break; - //// TODO: Enable when the screen capture code works reliable - //case Keys.V: - // // Video - // if (capture.CaptureDetails.CaptureMode != CaptureMode.Video) { - // capture.CaptureDetails.CaptureMode = CaptureMode.Video; - // } else { - // capture.CaptureDetails.CaptureMode = captureMode; - // } - // Invalidate(); - // break; - case Keys.Z: - if (_captureMode == CaptureMode.Region) { - // Toggle zoom - Conf.ZoomerEnabled = !Conf.ZoomerEnabled; - InitializeZoomer(Conf.ZoomerEnabled); - Invalidate(); - } - break; - case Keys.D: - if (_captureMode == CaptureMode.Window) - { - // Toggle debug - _showDebugInfo = !_showDebugInfo; - Invalidate(); - } - break; - case Keys.Space: - // Toggle capture mode - switch (_captureMode) { - case CaptureMode.Region: - // Set the window capture mode - _captureMode = CaptureMode.Window; - // "Fade out" Zoom - InitializeZoomer(false); - // "Fade in" window - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); - _captureRect = Rectangle.Empty; - Invalidate(); - break; - case CaptureMode.Text: - // Set the region capture mode - _captureMode = CaptureMode.Region; - Invalidate(); - break; - case CaptureMode.Window: - // Set the region capture mode - _captureMode = CaptureMode.Region; - // "Fade out" window - _windowAnimator.ChangeDestination(new Rectangle(_cursorPos, Size.Empty), FramesForMillis(700)); - // Fade in zoom - InitializeZoomer(Conf.ZoomerEnabled); - _captureRect = Rectangle.Empty; - Invalidate(); - break; - } - _selectedCaptureWindow = null; - OnMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); - break; - case Keys.Return: - // Confirm - if (_captureMode == CaptureMode.Window) { - DialogResult = DialogResult.OK; - } else if (!_mouseDown) { - HandleMouseDown(); - } else if (_mouseDown) { - HandleMouseUp(); - } - break; - case Keys.F: - ToFront = !ToFront; - TopMost = !TopMost; - break; - case Keys.T: + private void CaptureFormKeyUp(object sender, KeyEventArgs e) + { + switch (e.KeyCode) + { + case Keys.ShiftKey: + _fixMode = FixMode.None; + break; + case Keys.ControlKey: + _isCtrlPressed = false; + break; + } + } + + /// + /// Handle the key down event + /// + /// + /// + private void CaptureFormKeyDown(object sender, KeyEventArgs e) + { + int step = _isCtrlPressed ? 10 : 1; + + switch (e.KeyCode) + { + case Keys.Up: + Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y - step); + break; + case Keys.Down: + Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + step); + break; + case Keys.Left: + Cursor.Position = new Point(Cursor.Position.X - step, Cursor.Position.Y); + break; + case Keys.Right: + Cursor.Position = new Point(Cursor.Position.X + step, Cursor.Position.Y); + break; + case Keys.ShiftKey: + // Fix mode + if (_fixMode == FixMode.None) + { + _fixMode = FixMode.Initiated; + } + + break; + case Keys.ControlKey: + _isCtrlPressed = true; + break; + case Keys.Escape: + // Cancel + DialogResult = DialogResult.Cancel; + break; + case Keys.M: + // Toggle mouse cursor + _capture.CursorVisible = !_capture.CursorVisible; + Invalidate(); + break; + //// TODO: Enable when the screen capture code works reliable + //case Keys.V: + // // Video + // if (capture.CaptureDetails.CaptureMode != CaptureMode.Video) { + // capture.CaptureDetails.CaptureMode = CaptureMode.Video; + // } else { + // capture.CaptureDetails.CaptureMode = captureMode; + // } + // Invalidate(); + // break; + case Keys.Z: + if (_captureMode == CaptureMode.Region) + { + // Toggle zoom + Conf.ZoomerEnabled = !Conf.ZoomerEnabled; + InitializeZoomer(Conf.ZoomerEnabled); + Invalidate(); + } + + break; + case Keys.D: + if (_captureMode == CaptureMode.Window) + { + // Toggle debug + _showDebugInfo = !_showDebugInfo; + Invalidate(); + } + + break; + case Keys.Space: + // Toggle capture mode + switch (_captureMode) + { + case CaptureMode.Region: + // Set the window capture mode + _captureMode = CaptureMode.Window; + // "Fade out" Zoom + InitializeZoomer(false); + // "Fade in" window + _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, + EasingMode.EaseOut); + _captureRect = Rectangle.Empty; + Invalidate(); + break; + case CaptureMode.Text: + // Set the region capture mode + _captureMode = CaptureMode.Region; + Invalidate(); + break; + case CaptureMode.Window: + // Set the region capture mode + _captureMode = CaptureMode.Region; + // "Fade out" window + _windowAnimator.ChangeDestination(new Rectangle(_cursorPos, Size.Empty), FramesForMillis(700)); + // Fade in zoom + InitializeZoomer(Conf.ZoomerEnabled); + _captureRect = Rectangle.Empty; + Invalidate(); + break; + } + + _selectedCaptureWindow = null; + OnMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); + break; + case Keys.Return: + // Confirm + if (_captureMode == CaptureMode.Window) + { + DialogResult = DialogResult.OK; + } + else if (!_mouseDown) + { + HandleMouseDown(); + } + else if (_mouseDown) + { + HandleMouseUp(); + } + + break; + case Keys.F: + ToFront = !ToFront; + TopMost = !TopMost; + break; + case Keys.T: _captureMode = CaptureMode.Text; - if (_capture.CaptureDetails.OcrInformation is null) - { - var ocrProvider = SimpleServiceProvider.Current.GetInstance(); - if (ocrProvider != null) - { - var uiTaskScheduler = SimpleServiceProvider.Current.GetInstance(); + if (_capture.CaptureDetails.OcrInformation is null) + { + var ocrProvider = SimpleServiceProvider.Current.GetInstance(); + if (ocrProvider != null) + { + var uiTaskScheduler = SimpleServiceProvider.Current.GetInstance(); - Task.Factory.StartNew(async () => - { - _capture.CaptureDetails.OcrInformation = await ocrProvider.DoOcrAsync(_capture.Image); - Invalidate(); - }, CancellationToken.None, TaskCreationOptions.None, uiTaskScheduler); - } - } + Task.Factory.StartNew(async () => + { + _capture.CaptureDetails.OcrInformation = await ocrProvider.DoOcrAsync(_capture.Image); + Invalidate(); + }, CancellationToken.None, TaskCreationOptions.None, uiTaskScheduler); + } + } else { Invalidate(); - } - break; + } + + break; } - } + } /// - /// The mousedown handler of the capture form - /// - /// - /// - private void OnMouseDown(object sender, MouseEventArgs e) { - if (e.Button == MouseButtons.Left) { - HandleMouseDown(); - } - } + /// The mousedown handler of the capture form + /// + /// + /// + private void OnMouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + HandleMouseDown(); + } + } - private void HandleMouseDown() { - Point tmpCursorLocation = WindowCapture.GetCursorLocationRelativeToScreenBounds(); - _mX = tmpCursorLocation.X; - _mY = tmpCursorLocation.Y; - _mouseDown = true; - OnMouseMove(this, null); - Invalidate(); - } + private void HandleMouseDown() + { + Point tmpCursorLocation = WindowCapture.GetCursorLocationRelativeToScreenBounds(); + _mX = tmpCursorLocation.X; + _mY = tmpCursorLocation.Y; + _mouseDown = true; + OnMouseMove(this, null); + Invalidate(); + } - private void HandleMouseUp() { - // If the mouse goes up we set down to false (nice logic!) - _mouseDown = false; - // Check if anything is selected - if (_captureMode == CaptureMode.Window && _selectedCaptureWindow != null) { - // Go and process the capture - DialogResult = DialogResult.OK; - } else if (_captureRect.Height > 0 && _captureRect.Width > 0) { - // correct the GUI width to real width if Region mode - if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) { - _captureRect.Width += 1; - _captureRect.Height += 1; - } - // Go and process the capture - DialogResult = DialogResult.OK; - } else if (_captureMode == CaptureMode.Text && IsWordUnderCursor(_mouseMovePos)) + private void HandleMouseUp() + { + // If the mouse goes up we set down to false (nice logic!) + _mouseDown = false; + // Check if anything is selected + if (_captureMode == CaptureMode.Window && _selectedCaptureWindow != null) + { + // Go and process the capture + DialogResult = DialogResult.OK; + } + else if (_captureRect.Height > 0 && _captureRect.Width > 0) + { + // correct the GUI width to real width if Region mode + if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) + { + _captureRect.Width += 1; + _captureRect.Height += 1; + } + + // Go and process the capture + DialogResult = DialogResult.OK; + } + else if (_captureMode == CaptureMode.Text && IsWordUnderCursor(_mouseMovePos)) { // Handle a click on a single word _captureRect = new Rectangle(_mouseMovePos, new Size(1, 1)); // Go and process the capture DialogResult = DialogResult.OK; - } else { - Invalidate(); - } + } + else + { + Invalidate(); + } + } - } - - /// - /// - /// - /// - /// + /// + /// + /// + /// + /// private bool IsWordUnderCursor(Point cursorLocation) { if (_captureMode != CaptureMode.Text || _capture.CaptureDetails.OcrInformation == null) return false; var ocrInfo = _capture.CaptureDetails.OcrInformation; - foreach (var line in ocrInfo.Lines) + foreach (var line in ocrInfo.Lines) { var lineBounds = line.CalculatedBounds; if (lineBounds.IsEmpty) continue; @@ -415,210 +466,255 @@ namespace Greenshot.Forms { return false; } - /// - /// The mouse up handler of the capture form - /// - /// - /// - private void OnMouseUp(object sender, MouseEventArgs e) { - if (_mouseDown) { - HandleMouseUp(); - } - } + /// + /// The mouse up handler of the capture form + /// + /// + /// + private void OnMouseUp(object sender, MouseEventArgs e) + { + if (_mouseDown) + { + HandleMouseUp(); + } + } - /// - /// This method is used to "fix" the mouse coordinates when keeping shift/ctrl pressed - /// - /// - /// - private Point FixMouseCoordinates(Point currentMouse) { - if (_fixMode == FixMode.Initiated) { - if (_previousMousePos.X != currentMouse.X) { - _fixMode = FixMode.Vertical; - } else if (_previousMousePos.Y != currentMouse.Y) { - _fixMode = FixMode.Horizontal; - } - } else if (_fixMode == FixMode.Vertical) { - currentMouse = new Point(currentMouse.X, _previousMousePos.Y); - } else if (_fixMode == FixMode.Horizontal) { - currentMouse = new Point(_previousMousePos.X, currentMouse.Y); - } - _previousMousePos = currentMouse; - return currentMouse; - } + /// + /// This method is used to "fix" the mouse coordinates when keeping shift/ctrl pressed + /// + /// + /// + private Point FixMouseCoordinates(Point currentMouse) + { + if (_fixMode == FixMode.Initiated) + { + if (_previousMousePos.X != currentMouse.X) + { + _fixMode = FixMode.Vertical; + } + else if (_previousMousePos.Y != currentMouse.Y) + { + _fixMode = FixMode.Horizontal; + } + } + else if (_fixMode == FixMode.Vertical) + { + currentMouse = new Point(currentMouse.X, _previousMousePos.Y); + } + else if (_fixMode == FixMode.Horizontal) + { + currentMouse = new Point(_previousMousePos.X, currentMouse.Y); + } - /// - /// The mouse move handler of the capture form - /// - /// object - /// MouseEventArgs - private void OnMouseMove(object sender, MouseEventArgs e) { - // Make sure the mouse coordinates are fixed, when pressing shift - var mouseMovePos = FixMouseCoordinates(User32.GetCursorLocation()); - _mouseMovePos = WindowCapture.GetLocationRelativeToScreenBounds(mouseMovePos); - } + _previousMousePos = currentMouse; + return currentMouse; + } - /// - /// Helper method to simplify check - /// - /// - /// - private bool IsAnimating(IAnimator animator) { - if (animator == null) { - return false; - } - return animator.HasNext; - } + /// + /// The mouse move handler of the capture form + /// + /// object + /// MouseEventArgs + private void OnMouseMove(object sender, MouseEventArgs e) + { + // Make sure the mouse coordinates are fixed, when pressing shift + var mouseMovePos = FixMouseCoordinates(User32.GetCursorLocation()); + _mouseMovePos = WindowCapture.GetLocationRelativeToScreenBounds(mouseMovePos); + } - /// - /// update the frame, this only invalidates - /// - protected override void Animate() { - Point lastPos = _cursorPos; - _cursorPos = _mouseMovePos; + /// + /// Helper method to simplify check + /// + /// + /// + private bool IsAnimating(IAnimator animator) + { + if (animator == null) + { + return false; + } - if (_selectedCaptureWindow != null && lastPos.Equals(_cursorPos) && !IsAnimating(_zoomAnimator) && !IsAnimating(_windowAnimator)) { - return; - } + return animator.HasNext; + } - WindowDetails lastWindow = _selectedCaptureWindow; - bool horizontalMove = false; - bool verticalMove = false; + /// + /// update the frame, this only invalidates + /// + protected override void Animate() + { + Point lastPos = _cursorPos; + _cursorPos = _mouseMovePos; - if (lastPos.X != _cursorPos.X) { - horizontalMove = true; - } - if (lastPos.Y != _cursorPos.Y) { - verticalMove = true; - } + if (_selectedCaptureWindow != null && lastPos.Equals(_cursorPos) && !IsAnimating(_zoomAnimator) && !IsAnimating(_windowAnimator)) + { + return; + } - if ((_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) && _mouseDown) { - _captureRect = GuiRectangle.GetGuiRectangle(_cursorPos.X, _cursorPos.Y, _mX - _cursorPos.X, _mY - _cursorPos.Y); - } + WindowDetails lastWindow = _selectedCaptureWindow; + bool horizontalMove = false; + bool verticalMove = false; - // Iterate over the found windows and check if the current location is inside a window - Point cursorPosition = Cursor.Position; - _selectedCaptureWindow = null; - lock (_windows) { - foreach (var window in _windows) { - if (!window.Contains(cursorPosition)) - { - continue; - } - // Only go over the children if we are in window mode - _selectedCaptureWindow = CaptureMode.Window == _captureMode ? window.FindChildUnderPoint(cursorPosition) : window; - break; - } - } + if (lastPos.X != _cursorPos.X) + { + horizontalMove = true; + } - if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) { - _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; - _capture.CaptureDetails.AddMetaData("windowtitle", _selectedCaptureWindow.Text); - if (_captureMode == CaptureMode.Window) { - // Here we want to capture the window which is under the mouse - _captureRect = _selectedCaptureWindow.WindowRectangle; - // As the ClientRectangle is not in Bitmap coordinates, we need to correct. - _captureRect.Offset(-_capture.ScreenBounds.Location.X, -_capture.ScreenBounds.Location.Y); - } - } + if (lastPos.Y != _cursorPos.Y) + { + verticalMove = true; + } - Rectangle invalidateRectangle; - if (_mouseDown && (_captureMode != CaptureMode.Window)) { - int x1 = Math.Min(_mX, lastPos.X); - int x2 = Math.Max(_mX, lastPos.X); - int y1 = Math.Min(_mY, lastPos.Y); - int y2 = Math.Max(_mY, lastPos.Y); - x1= Math.Min(x1, _cursorPos.X); - x2= Math.Max(x2, _cursorPos.X); - y1= Math.Min(y1, _cursorPos.Y); - y2= Math.Max(y2, _cursorPos.Y); + if ((_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) && _mouseDown) + { + _captureRect = GuiRectangle.GetGuiRectangle(_cursorPos.X, _cursorPos.Y, _mX - _cursorPos.X, _mY - _cursorPos.Y); + } - // Safety correction - x2 += 2; - y2 += 2; + // Iterate over the found windows and check if the current location is inside a window + Point cursorPosition = Cursor.Position; + _selectedCaptureWindow = null; + lock (_windows) + { + foreach (var window in _windows) + { + if (!window.Contains(cursorPosition)) + { + continue; + } - // Here we correct for text-size + // Only go over the children if we are in window mode + _selectedCaptureWindow = CaptureMode.Window == _captureMode ? window.FindChildUnderPoint(cursorPosition) : window; + break; + } + } - // Calculate the size - int textForWidth = Math.Max(Math.Abs(_mX - _cursorPos.X), Math.Abs(_mX - lastPos.X)); - int textForHeight = Math.Max(Math.Abs(_mY - _cursorPos.Y), Math.Abs(_mY - lastPos.Y)); + if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) + { + _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; + _capture.CaptureDetails.AddMetaData("windowtitle", _selectedCaptureWindow.Text); + if (_captureMode == CaptureMode.Window) + { + // Here we want to capture the window which is under the mouse + _captureRect = _selectedCaptureWindow.WindowRectangle; + // As the ClientRectangle is not in Bitmap coordinates, we need to correct. + _captureRect.Offset(-_capture.ScreenBounds.Location.X, -_capture.ScreenBounds.Location.Y); + } + } - using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) { - Size measureWidth = TextRenderer.MeasureText(textForWidth.ToString(CultureInfo.InvariantCulture), rulerFont); - x1 -= measureWidth.Width + 15; + Rectangle invalidateRectangle; + if (_mouseDown && (_captureMode != CaptureMode.Window)) + { + int x1 = Math.Min(_mX, lastPos.X); + int x2 = Math.Max(_mX, lastPos.X); + int y1 = Math.Min(_mY, lastPos.Y); + int y2 = Math.Max(_mY, lastPos.Y); + x1 = Math.Min(x1, _cursorPos.X); + x2 = Math.Max(x2, _cursorPos.X); + y1 = Math.Min(y1, _cursorPos.Y); + y2 = Math.Max(y2, _cursorPos.Y); - Size measureHeight = TextRenderer.MeasureText(textForHeight.ToString(CultureInfo.InvariantCulture), rulerFont); - y1 -= measureHeight.Height + 10; - } - invalidateRectangle = new Rectangle(x1,y1, x2-x1, y2-y1); - Invalidate(invalidateRectangle); - } else if (_captureMode != CaptureMode.Window) { - if (!IsTerminalServerSession) { - Rectangle allScreenBounds = WindowCapture.GetScreenBounds(); - allScreenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(allScreenBounds.Location); - if (verticalMove) { - // Before - invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, lastPos.Y - 2, Width + 2, 45); - Invalidate(invalidateRectangle); - // After - invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, _cursorPos.Y - 2, Width + 2, 45); - Invalidate(invalidateRectangle); - } - if (horizontalMove) { - // Before - invalidateRectangle = GuiRectangle.GetGuiRectangle(lastPos.X - 2, allScreenBounds.Top, 75, Height + 2); - Invalidate(invalidateRectangle); - // After - invalidateRectangle = GuiRectangle.GetGuiRectangle(_cursorPos.X - 2, allScreenBounds.Top, 75, Height + 2); - Invalidate(invalidateRectangle); - } - } - } else { - if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) { - // Window changes, make new animation from current to target - _windowAnimator.ChangeDestination(_captureRect, FramesForMillis(700)); - } - } - // always animate the Window area through to the last frame, so we see the fade-in/out untill the end - // Using a safety "offset" to make sure the text is invalidated too - const int safetySize = 30; - // Check if the animation needs to be drawn - if (IsAnimating(_windowAnimator)) { - invalidateRectangle = _windowAnimator.Current; - invalidateRectangle.Inflate(safetySize, safetySize); - Invalidate(invalidateRectangle); - invalidateRectangle = _windowAnimator.Next(); - invalidateRectangle.Inflate(safetySize, safetySize); - Invalidate(invalidateRectangle); - // Check if this was the last of the windows animations in the normal region capture. - if (_captureMode != CaptureMode.Window && !IsAnimating(_windowAnimator)) { - Invalidate(); - } - } + // Safety correction + x2 += 2; + y2 += 2; - if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) { - // Make sure we invalidate the old zoom area - invalidateRectangle = _zoomAnimator.Current; - invalidateRectangle.Offset(lastPos); - Invalidate(invalidateRectangle); - // Only verify if we are really showing the zoom, not the outgoing animation - if (Conf.ZoomerEnabled && _captureMode != CaptureMode.Window) { - VerifyZoomAnimation(_cursorPos, false); - } - // The following logic is not needed, next always returns the current if there are no frames left - // but it makes more sense if we want to change something in the logic - invalidateRectangle = IsAnimating(_zoomAnimator) ? _zoomAnimator.Next() : _zoomAnimator.Current; - invalidateRectangle.Offset(_cursorPos); - Invalidate(invalidateRectangle); - } + // Here we correct for text-size - // OCR + // Calculate the size + int textForWidth = Math.Max(Math.Abs(_mX - _cursorPos.X), Math.Abs(_mX - lastPos.X)); + int textForHeight = Math.Max(Math.Abs(_mY - _cursorPos.Y), Math.Abs(_mY - lastPos.Y)); + + using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) + { + Size measureWidth = TextRenderer.MeasureText(textForWidth.ToString(CultureInfo.InvariantCulture), rulerFont); + x1 -= measureWidth.Width + 15; + + Size measureHeight = TextRenderer.MeasureText(textForHeight.ToString(CultureInfo.InvariantCulture), rulerFont); + y1 -= measureHeight.Height + 10; + } + + invalidateRectangle = new Rectangle(x1, y1, x2 - x1, y2 - y1); + Invalidate(invalidateRectangle); + } + else if (_captureMode != CaptureMode.Window) + { + if (!IsTerminalServerSession) + { + Rectangle allScreenBounds = WindowCapture.GetScreenBounds(); + allScreenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(allScreenBounds.Location); + if (verticalMove) + { + // Before + invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, lastPos.Y - 2, Width + 2, 45); + Invalidate(invalidateRectangle); + // After + invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, _cursorPos.Y - 2, Width + 2, 45); + Invalidate(invalidateRectangle); + } + + if (horizontalMove) + { + // Before + invalidateRectangle = GuiRectangle.GetGuiRectangle(lastPos.X - 2, allScreenBounds.Top, 75, Height + 2); + Invalidate(invalidateRectangle); + // After + invalidateRectangle = GuiRectangle.GetGuiRectangle(_cursorPos.X - 2, allScreenBounds.Top, 75, Height + 2); + Invalidate(invalidateRectangle); + } + } + } + else + { + if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) + { + // Window changes, make new animation from current to target + _windowAnimator.ChangeDestination(_captureRect, FramesForMillis(700)); + } + } + + // always animate the Window area through to the last frame, so we see the fade-in/out untill the end + // Using a safety "offset" to make sure the text is invalidated too + const int safetySize = 30; + // Check if the animation needs to be drawn + if (IsAnimating(_windowAnimator)) + { + invalidateRectangle = _windowAnimator.Current; + invalidateRectangle.Inflate(safetySize, safetySize); + Invalidate(invalidateRectangle); + invalidateRectangle = _windowAnimator.Next(); + invalidateRectangle.Inflate(safetySize, safetySize); + Invalidate(invalidateRectangle); + // Check if this was the last of the windows animations in the normal region capture. + if (_captureMode != CaptureMode.Window && !IsAnimating(_windowAnimator)) + { + Invalidate(); + } + } + + if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) + { + // Make sure we invalidate the old zoom area + invalidateRectangle = _zoomAnimator.Current; + invalidateRectangle.Offset(lastPos); + Invalidate(invalidateRectangle); + // Only verify if we are really showing the zoom, not the outgoing animation + if (Conf.ZoomerEnabled && _captureMode != CaptureMode.Window) + { + VerifyZoomAnimation(_cursorPos, false); + } + + // The following logic is not needed, next always returns the current if there are no frames left + // but it makes more sense if we want to change something in the logic + invalidateRectangle = IsAnimating(_zoomAnimator) ? _zoomAnimator.Next() : _zoomAnimator.Current; + invalidateRectangle.Offset(_cursorPos); + Invalidate(invalidateRectangle); + } + + // OCR if (_captureMode == CaptureMode.Text && _capture.CaptureDetails.OcrInformation != null) { var ocrInfo = _capture.CaptureDetails.OcrInformation; invalidateRectangle = Rectangle.Empty; - foreach (var line in ocrInfo.Lines) + foreach (var line in ocrInfo.Lines) { var lineBounds = line.CalculatedBounds; if (!lineBounds.IsEmpty) @@ -639,8 +735,8 @@ namespace Greenshot.Forms { else { invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); - } - } + } + } } } } @@ -657,172 +753,207 @@ namespace Greenshot.Forms { { invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); } + break; } } } } + if (!invalidateRectangle.IsEmpty) { Invalidate(invalidateRectangle); - } - } - // Force update "now" - Update(); - } + } + } - /// - /// This makes sure there is no background painted, as we have complete "paint" control it doesn't make sense to do otherwise. - /// - /// - protected override void OnPaintBackground(PaintEventArgs pevent) { - } + // Force update "now" + Update(); + } - /// - /// Checks if the Zoom area can move there where it wants to go, change direction if not. - /// - /// preferred destination location for the zoom area - /// false to try to find a location which is neither out of screen bounds nor intersects with the selected rectangle - private void VerifyZoomAnimation(Point pos, bool allowZoomOverCaptureRect) { - Rectangle screenBounds = Screen.GetBounds(MousePosition); - // convert to be relative to top left corner of all screen bounds - screenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(screenBounds.Location); - int relativeZoomSize = Math.Min(screenBounds.Width, screenBounds.Height) / 5; - // Make sure the final size is a plural of 4, this makes it look better - relativeZoomSize -= relativeZoomSize % 4; - Size zoomSize = new Size(relativeZoomSize, relativeZoomSize); - Point zoomOffset = new Point(20, 20); + /// + /// This makes sure there is no background painted, as we have complete "paint" control it doesn't make sense to do otherwise. + /// + /// + protected override void OnPaintBackground(PaintEventArgs pevent) + { + } - Rectangle targetRectangle = _zoomAnimator.Final; - targetRectangle.Offset(pos); - if (!screenBounds.Contains(targetRectangle) || (!allowZoomOverCaptureRect && _captureRect.IntersectsWith(targetRectangle))) { - Point destinationLocation = Point.Empty; - Rectangle tl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); - Rectangle tr = new Rectangle(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); - Rectangle bl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); - Rectangle br = new Rectangle(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); - if (screenBounds.Contains(br) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(br))) { - destinationLocation = new Point(zoomOffset.X, zoomOffset.Y); - } else if (screenBounds.Contains(bl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(bl))) { - destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, zoomOffset.Y); - } else if (screenBounds.Contains(tr) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tr))) { - destinationLocation = new Point(zoomOffset.X, -zoomOffset.Y - zoomSize.Width); - } else if (screenBounds.Contains(tl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tl))) { - destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width); - } - if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect) { - VerifyZoomAnimation(pos, true); - } else { - _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize)); - } - } - } + /// + /// Checks if the Zoom area can move there where it wants to go, change direction if not. + /// + /// preferred destination location for the zoom area + /// false to try to find a location which is neither out of screen bounds nor intersects with the selected rectangle + private void VerifyZoomAnimation(Point pos, bool allowZoomOverCaptureRect) + { + Rectangle screenBounds = Screen.GetBounds(MousePosition); + // convert to be relative to top left corner of all screen bounds + screenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(screenBounds.Location); + int relativeZoomSize = Math.Min(screenBounds.Width, screenBounds.Height) / 5; + // Make sure the final size is a plural of 4, this makes it look better + relativeZoomSize -= relativeZoomSize % 4; + Size zoomSize = new Size(relativeZoomSize, relativeZoomSize); + Point zoomOffset = new Point(20, 20); - /// - /// Draw the zoomed area - /// - /// - /// - /// - private void DrawZoom(Graphics graphics, Rectangle sourceRectangle, Rectangle destinationRectangle) { - if (_capture.Image == null) { - return; - } - ImageAttributes attributes; + Rectangle targetRectangle = _zoomAnimator.Final; + targetRectangle.Offset(pos); + if (!screenBounds.Contains(targetRectangle) || (!allowZoomOverCaptureRect && _captureRect.IntersectsWith(targetRectangle))) + { + Point destinationLocation = Point.Empty; + Rectangle tl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); + Rectangle tr = new Rectangle(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); + Rectangle bl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); + Rectangle br = new Rectangle(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); + if (screenBounds.Contains(br) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(br))) + { + destinationLocation = new Point(zoomOffset.X, zoomOffset.Y); + } + else if (screenBounds.Contains(bl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(bl))) + { + destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, zoomOffset.Y); + } + else if (screenBounds.Contains(tr) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tr))) + { + destinationLocation = new Point(zoomOffset.X, -zoomOffset.Y - zoomSize.Width); + } + else if (screenBounds.Contains(tl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tl))) + { + destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width); + } - if (_isZoomerTransparent) { - //create a color matrix object to change the opacy - ColorMatrix opacyMatrix = new ColorMatrix - { - Matrix33 = Conf.ZoomerOpacity - }; - attributes = new ImageAttributes(); - attributes.SetColorMatrix(opacyMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); - } else { - attributes = null; - } + if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect) + { + VerifyZoomAnimation(pos, true); + } + else + { + _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize)); + } + } + } - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.HighSpeed; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + /// + /// Draw the zoomed area + /// + /// + /// + /// + private void DrawZoom(Graphics graphics, Rectangle sourceRectangle, Rectangle destinationRectangle) + { + if (_capture.Image == null) + { + return; + } - using (GraphicsPath path = new GraphicsPath()) { - path.AddEllipse(destinationRectangle); - graphics.SetClip(path); - if (!_isZoomerTransparent) { - graphics.FillRectangle(BackgroundBrush, destinationRectangle); - graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); - } else { - graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, GraphicsUnit.Pixel, attributes); - } - } - int alpha = (int)(255 * Conf.ZoomerOpacity); - Color opacyWhite = Color.FromArgb(alpha, 255, 255, 255); - Color opacyBlack = Color.FromArgb(alpha, 0, 0, 0); + ImageAttributes attributes; - // Draw the circle around the zoomer - using (Pen pen = new Pen(opacyWhite, 2)) { - graphics.DrawEllipse(pen, destinationRectangle); - } + if (_isZoomerTransparent) + { + //create a color matrix object to change the opacy + ColorMatrix opacyMatrix = new ColorMatrix + { + Matrix33 = Conf.ZoomerOpacity + }; + attributes = new ImageAttributes(); + attributes.SetColorMatrix(opacyMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); + } + else + { + attributes = null; + } - // Make sure we don't have a pixeloffsetmode/smoothingmode when drawing the crosshair - graphics.SmoothingMode = SmoothingMode.None; - graphics.PixelOffsetMode = PixelOffsetMode.None; + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.CompositingQuality = CompositingQuality.HighSpeed; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - // Calculate some values - int pixelThickness = destinationRectangle.Width / sourceRectangle.Width; - int halfWidth = destinationRectangle.Width / 2; - int halfWidthEnd = destinationRectangle.Width / 2 - pixelThickness / 2; - int halfHeight = destinationRectangle.Height / 2; - int halfHeightEnd = destinationRectangle.Height / 2 - pixelThickness / 2; + using (GraphicsPath path = new GraphicsPath()) + { + path.AddEllipse(destinationRectangle); + graphics.SetClip(path); + if (!_isZoomerTransparent) + { + graphics.FillRectangle(BackgroundBrush, destinationRectangle); + graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); + } + else + { + graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, + GraphicsUnit.Pixel, attributes); + } + } - int drawAtHeight = destinationRectangle.Y + halfHeight; - int drawAtWidth = destinationRectangle.X + halfWidth; - int padding = pixelThickness; + int alpha = (int) (255 * Conf.ZoomerOpacity); + Color opacyWhite = Color.FromArgb(alpha, 255, 255, 255); + Color opacyBlack = Color.FromArgb(alpha, 0, 0, 0); - // Pen to draw - using (Pen pen = new Pen(opacyBlack, pixelThickness)) { - // Draw the cross-hair-lines - // Vertical top to middle - graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + padding, drawAtWidth, destinationRectangle.Y + halfHeightEnd - padding); - // Vertical middle + 1 to bottom - graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, drawAtWidth, destinationRectangle.Y + destinationRectangle.Width - padding); - // Horizontal left to middle - graphics.DrawLine(pen, destinationRectangle.X + padding, drawAtHeight, destinationRectangle.X + halfWidthEnd - padding, drawAtHeight); - // Horizontal middle + 1 to right - graphics.DrawLine(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, destinationRectangle.X + destinationRectangle.Width - padding, drawAtHeight); + // Draw the circle around the zoomer + using (Pen pen = new Pen(opacyWhite, 2)) + { + graphics.DrawEllipse(pen, destinationRectangle); + } - // Fix offset for drawing the white rectangle around the cross-hair-lines - drawAtHeight -= pixelThickness / 2; - drawAtWidth -= pixelThickness / 2; - // Fix off by one error with the DrawRectangle - pixelThickness -= 1; - // Change the color and the pen width - pen.Color = opacyWhite; - pen.Width = 1; - // Vertical top to middle - graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + padding, pixelThickness, halfHeightEnd - 2 * padding - 1); - // Vertical middle + 1 to bottom - graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, pixelThickness, halfHeightEnd - 2 * padding - 1); - // Horizontal left to middle - graphics.DrawRectangle(pen, destinationRectangle.X + padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); - // Horizontal middle + 1 to right - graphics.DrawRectangle(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); - } - attributes?.Dispose(); - } + // Make sure we don't have a pixeloffsetmode/smoothingmode when drawing the crosshair + graphics.SmoothingMode = SmoothingMode.None; + graphics.PixelOffsetMode = PixelOffsetMode.None; - /// - /// Paint the actual visible parts - /// - /// - /// - private void OnPaint(object sender, PaintEventArgs e) { - Graphics graphics = e.Graphics; - Rectangle clipRectangle = e.ClipRectangle; - //graphics.BitBlt((Bitmap)buffer, Point.Empty); - graphics.DrawImageUnscaled(_capture.Image, Point.Empty); + // Calculate some values + int pixelThickness = destinationRectangle.Width / sourceRectangle.Width; + int halfWidth = destinationRectangle.Width / 2; + int halfWidthEnd = destinationRectangle.Width / 2 - pixelThickness / 2; + int halfHeight = destinationRectangle.Height / 2; + int halfHeightEnd = destinationRectangle.Height / 2 - pixelThickness / 2; + + int drawAtHeight = destinationRectangle.Y + halfHeight; + int drawAtWidth = destinationRectangle.X + halfWidth; + int padding = pixelThickness; + + // Pen to draw + using (Pen pen = new Pen(opacyBlack, pixelThickness)) + { + // Draw the cross-hair-lines + // Vertical top to middle + graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + padding, drawAtWidth, destinationRectangle.Y + halfHeightEnd - padding); + // Vertical middle + 1 to bottom + graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, drawAtWidth, + destinationRectangle.Y + destinationRectangle.Width - padding); + // Horizontal left to middle + graphics.DrawLine(pen, destinationRectangle.X + padding, drawAtHeight, destinationRectangle.X + halfWidthEnd - padding, drawAtHeight); + // Horizontal middle + 1 to right + graphics.DrawLine(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, destinationRectangle.X + destinationRectangle.Width - padding, + drawAtHeight); + + // Fix offset for drawing the white rectangle around the cross-hair-lines + drawAtHeight -= pixelThickness / 2; + drawAtWidth -= pixelThickness / 2; + // Fix off by one error with the DrawRectangle + pixelThickness -= 1; + // Change the color and the pen width + pen.Color = opacyWhite; + pen.Width = 1; + // Vertical top to middle + graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + padding, pixelThickness, halfHeightEnd - 2 * padding - 1); + // Vertical middle + 1 to bottom + graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, pixelThickness, halfHeightEnd - 2 * padding - 1); + // Horizontal left to middle + graphics.DrawRectangle(pen, destinationRectangle.X + padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); + // Horizontal middle + 1 to right + graphics.DrawRectangle(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); + } + + attributes?.Dispose(); + } + + /// + /// Paint the actual visible parts + /// + /// + /// + private void OnPaint(object sender, PaintEventArgs e) + { + Graphics graphics = e.Graphics; + Rectangle clipRectangle = e.ClipRectangle; + //graphics.BitBlt((Bitmap)buffer, Point.Empty); + graphics.DrawImageUnscaled(_capture.Image, Point.Empty); var ocrInfo = _capture.CaptureDetails.OcrInformation; if (ocrInfo != null && _captureMode == CaptureMode.Text) @@ -849,7 +980,7 @@ namespace Greenshot.Forms { } } } - } + } else if (lineBounds.Contains(_mouseMovePos)) { foreach (var word in line.Words) @@ -858,52 +989,59 @@ namespace Greenshot.Forms { graphics.FillRectangle(highlightTextBrush, word.Bounds); break; } - } - } + } + } } - } + } // Only draw Cursor if it's (partly) visible - if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new Rectangle(_capture.CursorLocation, _capture.Cursor.Size))) { - graphics.DrawIcon(_capture.Cursor, _capture.CursorLocation.X, _capture.CursorLocation.Y); - } + if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new Rectangle(_capture.CursorLocation, _capture.Cursor.Size))) + { + graphics.DrawIcon(_capture.Cursor, _capture.CursorLocation.X, _capture.CursorLocation.Y); + } - if (_mouseDown || _captureMode == CaptureMode.Window || IsAnimating(_windowAnimator)) { - _captureRect.Intersect(new Rectangle(Point.Empty, _capture.ScreenBounds.Size)); // crop what is outside the screen + if (_mouseDown || _captureMode == CaptureMode.Window || IsAnimating(_windowAnimator)) + { + _captureRect.Intersect(new Rectangle(Point.Empty, _capture.ScreenBounds.Size)); // crop what is outside the screen - var fixedRect = IsAnimating(_windowAnimator) ? _windowAnimator.Current : _captureRect; + var fixedRect = IsAnimating(_windowAnimator) ? _windowAnimator.Current : _captureRect; - // TODO: enable when the screen capture code works reliable - //if (capture.CaptureDetails.CaptureMode == CaptureMode.Video) { - // graphics.FillRectangle(RedOverlayBrush, fixedRect); - //} else { - graphics.FillRectangle(GreenOverlayBrush, fixedRect); - //} - graphics.DrawRectangle(OverlayPen, fixedRect); + // TODO: enable when the screen capture code works reliable + //if (capture.CaptureDetails.CaptureMode == CaptureMode.Video) { + // graphics.FillRectangle(RedOverlayBrush, fixedRect); + //} else { + graphics.FillRectangle(GreenOverlayBrush, fixedRect); + //} + graphics.DrawRectangle(OverlayPen, fixedRect); - // rulers - const int dist = 8; + // rulers + const int dist = 8; - string captureWidth; - string captureHeight; - // The following fixes the very old incorrect size information bug - if (_captureMode == CaptureMode.Window) { - captureWidth = _captureRect.Width.ToString(CultureInfo.InvariantCulture); - captureHeight = _captureRect.Height.ToString(CultureInfo.InvariantCulture); - } else { - captureWidth = (_captureRect.Width + 1).ToString(CultureInfo.InvariantCulture); - captureHeight = (_captureRect.Height + 1).ToString(CultureInfo.InvariantCulture); - } - using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) { - Size measureWidth = TextRenderer.MeasureText(captureWidth, rulerFont); - Size measureHeight = TextRenderer.MeasureText(captureHeight, rulerFont); - int hSpace = measureWidth.Width + 3; - int vSpace = measureHeight.Height + 3; - Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227)); - Pen rulerPen = new Pen(Color.SeaGreen); + string captureWidth; + string captureHeight; + // The following fixes the very old incorrect size information bug + if (_captureMode == CaptureMode.Window) + { + captureWidth = _captureRect.Width.ToString(CultureInfo.InvariantCulture); + captureHeight = _captureRect.Height.ToString(CultureInfo.InvariantCulture); + } + else + { + captureWidth = (_captureRect.Width + 1).ToString(CultureInfo.InvariantCulture); + captureHeight = (_captureRect.Height + 1).ToString(CultureInfo.InvariantCulture); + } - // horizontal ruler - if (fixedRect.Width > hSpace + 3) + using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) + { + Size measureWidth = TextRenderer.MeasureText(captureWidth, rulerFont); + Size measureHeight = TextRenderer.MeasureText(captureHeight, rulerFont); + int hSpace = measureWidth.Width + 3; + int vSpace = measureHeight.Height + 3; + Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227)); + Pen rulerPen = new Pen(Color.SeaGreen); + + // horizontal ruler + if (fixedRect.Width > hSpace + 3) { using GraphicsPath p = CreateRoundedRectangle( fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, @@ -920,8 +1058,8 @@ namespace Greenshot.Forms { graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width, fixedRect.Y - dist - 3, fixedRect.X + fixedRect.Width, fixedRect.Y - dist + 3); } - // vertical ruler - if (fixedRect.Height > vSpace + 3) + // vertical ruler + if (fixedRect.Height > vSpace + 3) { using GraphicsPath p = CreateRoundedRectangle( fixedRect.X - measureHeight.Width + 1, @@ -938,34 +1076,40 @@ namespace Greenshot.Forms { graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y + fixedRect.Height, fixedRect.X - dist + 3, fixedRect.Y + fixedRect.Height); } - rulerPen.Dispose(); - bgBrush.Dispose(); - } + rulerPen.Dispose(); + bgBrush.Dispose(); + } - // Display size of selected rectangle - // Prepare the font and text. - using Font sizeFont = new Font( FontFamily.GenericSansSerif, 12 ); + // Display size of selected rectangle + // Prepare the font and text. + using Font sizeFont = new Font(FontFamily.GenericSansSerif, 12); // When capturing a Region we need to add 1 to the height/width for correction string sizeText; - if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) { + if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) + { // correct the GUI width to real width for the shown size sizeText = _captureRect.Width + 1 + " x " + (_captureRect.Height + 1); - } else { + } + else + { sizeText = _captureRect.Width + " x " + _captureRect.Height; } // Calculate the scaled font size. - SizeF extent = graphics.MeasureString( sizeText, sizeFont ); + SizeF extent = graphics.MeasureString(sizeText, sizeFont); float hRatio = _captureRect.Height / (extent.Height * 2); float wRatio = _captureRect.Width / (extent.Width * 2); float ratio = hRatio < wRatio ? hRatio : wRatio; float newSize = sizeFont.Size * ratio; - if ( newSize >= 4 ) { + if (newSize >= 4) + { // Only show if 4pt or larger. - if (newSize > 20) { + if (newSize > 20) + { newSize = 20; } + // Draw the size. using Font newSizeFont = new Font(FontFamily.GenericSansSerif, newSize, FontStyle.Bold); PointF sizeLocation = new PointF(fixedRect.X + _captureRect.Width / 2 - extent.Width / 2, fixedRect.Y + _captureRect.Height / 2 - newSizeFont.GetHeight() / 2); @@ -973,47 +1117,56 @@ namespace Greenshot.Forms { if (_showDebugInfo && _selectedCaptureWindow != null) { - string title = $"#{_selectedCaptureWindow.Handle.ToInt64():X} - {(_selectedCaptureWindow.Text.Length > 0 ? _selectedCaptureWindow.Text : _selectedCaptureWindow.Process.ProcessName)}"; + string title = + $"#{_selectedCaptureWindow.Handle.ToInt64():X} - {(_selectedCaptureWindow.Text.Length > 0 ? _selectedCaptureWindow.Text : _selectedCaptureWindow.Process.ProcessName)}"; PointF debugLocation = new PointF(fixedRect.X, fixedRect.Y); graphics.DrawString(title, sizeFont, Brushes.DarkOrange, debugLocation); } } - } else { - if (!IsTerminalServerSession) { - using (Pen pen = new Pen(Color.LightSeaGreen)) { - pen.DashStyle = DashStyle.Dot; - Rectangle screenBounds = _capture.ScreenBounds; - graphics.DrawLine(pen, _cursorPos.X, screenBounds.Y, _cursorPos.X, screenBounds.Height); - graphics.DrawLine(pen, screenBounds.X, _cursorPos.Y, screenBounds.Width, _cursorPos.Y); - } + } + else + { + if (!IsTerminalServerSession) + { + using (Pen pen = new Pen(Color.LightSeaGreen)) + { + pen.DashStyle = DashStyle.Dot; + Rectangle screenBounds = _capture.ScreenBounds; + graphics.DrawLine(pen, _cursorPos.X, screenBounds.Y, _cursorPos.X, screenBounds.Height); + graphics.DrawLine(pen, screenBounds.X, _cursorPos.Y, screenBounds.Width, _cursorPos.Y); + } - string xy = _cursorPos.X + " x " + _cursorPos.Y; + string xy = _cursorPos.X + " x " + _cursorPos.Y; using Font f = new Font(FontFamily.GenericSansSerif, 8); Size xySize = TextRenderer.MeasureText(xy, f); using GraphicsPath gp = CreateRoundedRectangle(_cursorPos.X + 5, _cursorPos.Y + 5, xySize.Width - 3, xySize.Height, 3); - using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227))) { + using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227))) + { graphics.FillPath(bgBrush, gp); } - using (Pen pen = new Pen(Color.SeaGreen)) { + + using (Pen pen = new Pen(Color.SeaGreen)) + { graphics.DrawPath(pen, gp); Point coordinatePosition = new Point(_cursorPos.X + 5, _cursorPos.Y + 5); graphics.DrawString(xy, f, pen.Brush, coordinatePosition); } } - } + } - // Zoom - if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) { - const int zoomSourceWidth = 25; - const int zoomSourceHeight = 25; + // Zoom + if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) + { + const int zoomSourceWidth = 25; + const int zoomSourceHeight = 25; - Rectangle sourceRectangle = new Rectangle(_cursorPos.X - zoomSourceWidth / 2, _cursorPos.Y - zoomSourceHeight / 2, zoomSourceWidth, zoomSourceHeight); + Rectangle sourceRectangle = new Rectangle(_cursorPos.X - zoomSourceWidth / 2, _cursorPos.Y - zoomSourceHeight / 2, zoomSourceWidth, zoomSourceHeight); - Rectangle destinationRectangle = _zoomAnimator.Current; - destinationRectangle.Offset(_cursorPos); - DrawZoom(graphics, sourceRectangle, destinationRectangle); - } - } + Rectangle destinationRectangle = _zoomAnimator.Current; + destinationRectangle.Offset(_cursorPos); + DrawZoom(graphics, sourceRectangle, destinationRectangle); + } + } private static GraphicsPath CreateRoundedRectangle(int x, int y, int width, int height, int radius) { @@ -1031,4 +1184,4 @@ namespace Greenshot.Forms { return gp; } } -} +} \ No newline at end of file diff --git a/src/Greenshot/Forms/ColorDialog.cs b/src/Greenshot/Forms/ColorDialog.cs index b93c01258..91c314cd9 100644 --- a/src/Greenshot/Forms/ColorDialog.cs +++ b/src/Greenshot/Forms/ColorDialog.cs @@ -29,204 +29,252 @@ using Greenshot.Configuration; using Greenshot.Controls; using GreenshotPlugin.IniFile; -namespace Greenshot.Forms { - /// - /// Description of ColorDialog. - /// - public partial class ColorDialog : BaseForm { - private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); +namespace Greenshot.Forms +{ + /// + /// Description of ColorDialog. + /// + public partial class ColorDialog : BaseForm + { + private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); private static ColorDialog _instance; - public ColorDialog() { - SuspendLayout(); - InitializeComponent(); - SuspendLayout(); - CreateColorPalette(5, 5, 15, 15); - CreateLastUsedColorButtonRow(5, 190, 15, 15); - ResumeLayout(); - UpdateRecentColorsButtonRow(); + + public ColorDialog() + { + SuspendLayout(); + InitializeComponent(); + SuspendLayout(); + CreateColorPalette(5, 5, 15, 15); + CreateLastUsedColorButtonRow(5, 190, 15, 15); + ResumeLayout(); + UpdateRecentColorsButtonRow(); _instance = this; } public static ColorDialog GetInstance() => _instance; - private readonly List
+ /// the label to be displayed + /// the data to be returned when an item is queried + /// whether the item is initially checked + public void AddItem(string label, object data, bool isChecked) + { + AddItem(label, null, data, isChecked); + } /// - /// unchecks all items of the list - /// - public void UncheckAll() { - IEnumerator items = DropDownItems.GetEnumerator(); - while (items.MoveNext()) - { - var toolStripMenuSelectListItem = (ToolStripMenuSelectListItem)items.Current; - if (toolStripMenuSelectListItem != null) - { - toolStripMenuSelectListItem.Checked = false; - } - } - } - } + /// unchecks all items of the list + ///
+ public void UncheckAll() + { + IEnumerator items = DropDownItems.GetEnumerator(); + while (items.MoveNext()) + { + var toolStripMenuSelectListItem = (ToolStripMenuSelectListItem) items.Current; + if (toolStripMenuSelectListItem != null) + { + toolStripMenuSelectListItem.Checked = false; + } + } + } + } - /// - /// Event class for the CheckedChanged event in the ToolStripMenuSelectList - /// - public class ItemCheckedChangedEventArgs : EventArgs { - public ToolStripMenuSelectListItem Item { - get; - set; - } - public ItemCheckedChangedEventArgs(ToolStripMenuSelectListItem item) { - Item = item; - } - } + /// + /// Event class for the CheckedChanged event in the ToolStripMenuSelectList + /// + public class ItemCheckedChangedEventArgs : EventArgs + { + public ToolStripMenuSelectListItem Item { get; set; } - /// - /// Wrapper around the ToolStripMenuItem, which can contain an object - /// Also the Checked property hides the normal checked property so we can render our own check - /// - public class ToolStripMenuSelectListItem : ToolStripMenuItem { - public object Data { - get; - set; - } + public ItemCheckedChangedEventArgs(ToolStripMenuSelectListItem item) + { + Item = item; + } + } - } + /// + /// Wrapper around the ToolStripMenuItem, which can contain an object + /// Also the Checked property hides the normal checked property so we can render our own check + /// + public class ToolStripMenuSelectListItem : ToolStripMenuItem + { + public object Data { get; set; } + } } \ No newline at end of file diff --git a/src/Greenshot/Forms/TornEdgeSettingsForm.cs b/src/Greenshot/Forms/TornEdgeSettingsForm.cs index 520f795b9..dac953bd4 100644 --- a/src/Greenshot/Forms/TornEdgeSettingsForm.cs +++ b/src/Greenshot/Forms/TornEdgeSettingsForm.cs @@ -18,85 +18,98 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Windows.Forms; using GreenshotPlugin.Effects; -namespace Greenshot.Forms { - public partial class TornEdgeSettingsForm : BaseForm { - private readonly TornEdgeEffect _effect; - public TornEdgeSettingsForm(TornEdgeEffect effect) { - _effect = effect; - InitializeComponent(); - ShowSettings(); - } +namespace Greenshot.Forms +{ + public partial class TornEdgeSettingsForm : BaseForm + { + private readonly TornEdgeEffect _effect; - private void ShowSettings() { - shadowCheckbox.Checked = _effect.GenerateShadow; - // Fix to prevent BUG-1753 - shadowDarkness.Value = Math.Max(shadowDarkness.Minimum, Math.Min(shadowDarkness.Maximum, (int)(_effect.Darkness * shadowDarkness.Maximum))); - offsetX.Value = _effect.ShadowOffset.X; - offsetY.Value = _effect.ShadowOffset.Y; - toothsize.Value = _effect.ToothHeight; - verticaltoothrange.Value = _effect.VerticalToothRange; - horizontaltoothrange.Value = _effect.HorizontalToothRange; - top.Checked = _effect.Edges[0]; - right.Checked = _effect.Edges[1]; - bottom.Checked = _effect.Edges[2]; - left.Checked = _effect.Edges[3]; - } + public TornEdgeSettingsForm(TornEdgeEffect effect) + { + _effect = effect; + InitializeComponent(); + ShowSettings(); + } - private void ButtonOK_Click(object sender, EventArgs e) { - _effect.Darkness = shadowDarkness.Value / (float)40; - _effect.ShadowOffset = new Point((int)offsetX.Value, (int)offsetY.Value); - _effect.ShadowSize = (int)thickness.Value; - _effect.ToothHeight = (int)toothsize.Value; - _effect.VerticalToothRange = (int)verticaltoothrange.Value; - _effect.HorizontalToothRange = (int)horizontaltoothrange.Value; - _effect.Edges = new[] { top.Checked, right.Checked, bottom.Checked, left.Checked }; - _effect.GenerateShadow = shadowCheckbox.Checked; - DialogResult = DialogResult.OK; - } + private void ShowSettings() + { + shadowCheckbox.Checked = _effect.GenerateShadow; + // Fix to prevent BUG-1753 + shadowDarkness.Value = Math.Max(shadowDarkness.Minimum, Math.Min(shadowDarkness.Maximum, (int) (_effect.Darkness * shadowDarkness.Maximum))); + offsetX.Value = _effect.ShadowOffset.X; + offsetY.Value = _effect.ShadowOffset.Y; + toothsize.Value = _effect.ToothHeight; + verticaltoothrange.Value = _effect.VerticalToothRange; + horizontaltoothrange.Value = _effect.HorizontalToothRange; + top.Checked = _effect.Edges[0]; + right.Checked = _effect.Edges[1]; + bottom.Checked = _effect.Edges[2]; + left.Checked = _effect.Edges[3]; + } - private void ShadowCheckbox_CheckedChanged(object sender, EventArgs e) { - thickness.Enabled = shadowCheckbox.Checked; - offsetX.Enabled = shadowCheckbox.Checked; - offsetY.Enabled = shadowCheckbox.Checked; - shadowDarkness.Enabled = shadowCheckbox.Checked; - } + private void ButtonOK_Click(object sender, EventArgs e) + { + _effect.Darkness = shadowDarkness.Value / (float) 40; + _effect.ShadowOffset = new Point((int) offsetX.Value, (int) offsetY.Value); + _effect.ShadowSize = (int) thickness.Value; + _effect.ToothHeight = (int) toothsize.Value; + _effect.VerticalToothRange = (int) verticaltoothrange.Value; + _effect.HorizontalToothRange = (int) horizontaltoothrange.Value; + _effect.Edges = new[] + { + top.Checked, right.Checked, bottom.Checked, left.Checked + }; + _effect.GenerateShadow = shadowCheckbox.Checked; + DialogResult = DialogResult.OK; + } - + private void ShadowCheckbox_CheckedChanged(object sender, EventArgs e) + { + thickness.Enabled = shadowCheckbox.Checked; + offsetX.Enabled = shadowCheckbox.Checked; + offsetY.Enabled = shadowCheckbox.Checked; + shadowDarkness.Enabled = shadowCheckbox.Checked; + } - private void all_CheckedChanged(object sender, EventArgs e) { - AnySideChangeChecked(top, all.Checked); - AnySideChangeChecked(right, all.Checked); - AnySideChangeChecked(bottom, all.Checked); - AnySideChangeChecked(left, all.Checked); - } - private void AnySideCheckedChanged(object sender, EventArgs e) { - all.CheckedChanged -= all_CheckedChanged; - all.Checked = top.Checked && right.Checked && bottom.Checked && left.Checked; - all.CheckedChanged += all_CheckedChanged; - } + private void all_CheckedChanged(object sender, EventArgs e) + { + AnySideChangeChecked(top, all.Checked); + AnySideChangeChecked(right, all.Checked); + AnySideChangeChecked(bottom, all.Checked); + AnySideChangeChecked(left, all.Checked); + } - /// - /// changes the Checked property of top/right/bottom/left checkboxes without triggering AnySideCheckedChange - /// - /// Checkbox to change Checked - /// true to check - private void AnySideChangeChecked(CheckBox cb, bool status) { - if (status != cb.Checked) { - cb.CheckedChanged -= AnySideCheckedChanged; - cb.Checked = status; - cb.CheckedChanged += AnySideCheckedChanged; - } - } + private void AnySideCheckedChanged(object sender, EventArgs e) + { + all.CheckedChanged -= all_CheckedChanged; + all.Checked = top.Checked && right.Checked && bottom.Checked && left.Checked; + all.CheckedChanged += all_CheckedChanged; + } - private void TornEdgeSettingsForm_Load(object sender, EventArgs e) - { + /// + /// changes the Checked property of top/right/bottom/left checkboxes without triggering AnySideCheckedChange + /// + /// Checkbox to change Checked + /// true to check + private void AnySideChangeChecked(CheckBox cb, bool status) + { + if (status != cb.Checked) + { + cb.CheckedChanged -= AnySideCheckedChanged; + cb.Checked = status; + cb.CheckedChanged += AnySideCheckedChanged; + } + } - } - } -} + private void TornEdgeSettingsForm_Load(object sender, EventArgs e) + { + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Help/HelpFileLoader.cs b/src/Greenshot/Help/HelpFileLoader.cs index 4dec29979..69396490a 100644 --- a/src/Greenshot/Help/HelpFileLoader.cs +++ b/src/Greenshot/Help/HelpFileLoader.cs @@ -26,61 +26,76 @@ using log4net; namespace Greenshot.Help { - /// - /// Description of HelpFileLoader. - /// - public static class HelpFileLoader - { - private static readonly ILog Log = LogManager.GetLogger(typeof(HelpFileLoader)); - - private const string ExtHelpUrl = @"http://getgreenshot.org/help/"; + /// + /// Description of HelpFileLoader. + /// + public static class HelpFileLoader + { + private static readonly ILog Log = LogManager.GetLogger(typeof(HelpFileLoader)); - public static void LoadHelp() { - string uri = FindOnlineHelpUrl(Language.CurrentLanguage) ?? Language.HelpFilePath; - Process.Start(uri); - } - - /// URL of help file in selected ietf, or (if not present) default ietf, or null (if not present, too. probably indicating that there is no internet connection) - private static string FindOnlineHelpUrl(string currentIETF) { - string ret = null; - - string extHelpUrlForCurrrentIETF = ExtHelpUrl; - - if(!currentIETF.Equals("en-US")) { - extHelpUrlForCurrrentIETF += currentIETF.ToLower() + "/"; - } - - HttpStatusCode? httpStatusCode = GetHttpStatus(extHelpUrlForCurrrentIETF); - if(httpStatusCode == HttpStatusCode.OK) { - ret = extHelpUrlForCurrrentIETF; - } else if(httpStatusCode != null && !extHelpUrlForCurrrentIETF.Equals(ExtHelpUrl)) { - Log.DebugFormat("Localized online help not found at {0}, will try {1} as fallback", extHelpUrlForCurrrentIETF, ExtHelpUrl); - httpStatusCode = GetHttpStatus(ExtHelpUrl); - if(httpStatusCode == HttpStatusCode.OK) { - ret = ExtHelpUrl; - } else { - Log.WarnFormat("{0} returned status {1}", ExtHelpUrl, httpStatusCode); - } - } else if(httpStatusCode == null){ - Log.Info("Internet connection does not seem to be available, will load help from file system."); - } - - return ret; - } - - /// - /// Retrieves HTTP status for a given url. - /// - /// URL for which the HTTP status is to be checked - /// An HTTP status code, or null if there is none (probably indicating that there is no internet connection available - private static HttpStatusCode? GetHttpStatus(string url) { - try { - HttpWebRequest req = NetworkHelper.CreateWebRequest(url); - using HttpWebResponse res = (HttpWebResponse)req.GetResponse(); + private const string ExtHelpUrl = @"http://getgreenshot.org/help/"; + + public static void LoadHelp() + { + string uri = FindOnlineHelpUrl(Language.CurrentLanguage) ?? Language.HelpFilePath; + Process.Start(uri); + } + + /// URL of help file in selected ietf, or (if not present) default ietf, or null (if not present, too. probably indicating that there is no internet connection) + private static string FindOnlineHelpUrl(string currentIETF) + { + string ret = null; + + string extHelpUrlForCurrrentIETF = ExtHelpUrl; + + if (!currentIETF.Equals("en-US")) + { + extHelpUrlForCurrrentIETF += currentIETF.ToLower() + "/"; + } + + HttpStatusCode? httpStatusCode = GetHttpStatus(extHelpUrlForCurrrentIETF); + if (httpStatusCode == HttpStatusCode.OK) + { + ret = extHelpUrlForCurrrentIETF; + } + else if (httpStatusCode != null && !extHelpUrlForCurrrentIETF.Equals(ExtHelpUrl)) + { + Log.DebugFormat("Localized online help not found at {0}, will try {1} as fallback", extHelpUrlForCurrrentIETF, ExtHelpUrl); + httpStatusCode = GetHttpStatus(ExtHelpUrl); + if (httpStatusCode == HttpStatusCode.OK) + { + ret = ExtHelpUrl; + } + else + { + Log.WarnFormat("{0} returned status {1}", ExtHelpUrl, httpStatusCode); + } + } + else if (httpStatusCode == null) + { + Log.Info("Internet connection does not seem to be available, will load help from file system."); + } + + return ret; + } + + /// + /// Retrieves HTTP status for a given url. + /// + /// URL for which the HTTP status is to be checked + /// An HTTP status code, or null if there is none (probably indicating that there is no internet connection available + private static HttpStatusCode? GetHttpStatus(string url) + { + try + { + HttpWebRequest req = NetworkHelper.CreateWebRequest(url); + using HttpWebResponse res = (HttpWebResponse) req.GetResponse(); return res.StatusCode; - } catch (WebException e) { - return ((HttpWebResponse) e.Response)?.StatusCode; - } - } - } -} + } + catch (WebException e) + { + return ((HttpWebResponse) e.Response)?.StatusCode; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/CaptureHelper.cs b/src/Greenshot/Helpers/CaptureHelper.cs index 813a18b4f..5b90092d1 100644 --- a/src/Greenshot/Helpers/CaptureHelper.cs +++ b/src/Greenshot/Helpers/CaptureHelper.cs @@ -39,85 +39,98 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.UnmanagedHelpers.Enums; -namespace Greenshot.Helpers { - /// - /// CaptureHelper contains all the capture logic - /// - public class CaptureHelper : IDisposable { - private static readonly ILog Log = LogManager.GetLogger(typeof(CaptureHelper)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - // TODO: when we get the screen capture code working correctly, this needs to be enabled - //private static ScreenCaptureHelper screenCapture = null; - private List _windows = new List(); - private WindowDetails _selectedCaptureWindow; - private Rectangle _captureRect = Rectangle.Empty; - private readonly bool _captureMouseCursor; - private ICapture _capture; - private CaptureMode _captureMode; - private ScreenCaptureMode _screenCaptureMode = ScreenCaptureMode.Auto; +namespace Greenshot.Helpers +{ + /// + /// CaptureHelper contains all the capture logic + /// + public class CaptureHelper : IDisposable + { + private static readonly ILog Log = LogManager.GetLogger(typeof(CaptureHelper)); - /// - /// The public accessible Dispose - /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice - /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - // The bulk of the clean-up code is implemented in Dispose(bool) + // TODO: when we get the screen capture code working correctly, this needs to be enabled + //private static ScreenCaptureHelper screenCapture = null; + private List _windows = new List(); + private WindowDetails _selectedCaptureWindow; + private Rectangle _captureRect = Rectangle.Empty; + private readonly bool _captureMouseCursor; + private ICapture _capture; + private CaptureMode _captureMode; + private ScreenCaptureMode _screenCaptureMode = ScreenCaptureMode.Auto; - /// - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected virtual void Dispose(bool disposing) { - if (disposing) { - // Cleanup - } - // Unfortunately we can't dispose the capture, this might still be used somewhere else. - _windows = null; - _selectedCaptureWindow = null; - _capture = null; - // Empty working set after capturing - if (CoreConfig.MinimizeWorkingSetSize) { - PsAPI.EmptyWorkingSet(); - } - } + /// + /// The public accessible Dispose + /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - public static void CaptureClipboard() - { - using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Clipboard); - captureHelper.MakeCapture(); - } + // The bulk of the clean-up code is implemented in Dispose(bool) - public static void CaptureClipboard(IDestination destination) + /// + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // Cleanup + } + + // Unfortunately we can't dispose the capture, this might still be used somewhere else. + _windows = null; + _selectedCaptureWindow = null; + _capture = null; + // Empty working set after capturing + if (CoreConfig.MinimizeWorkingSetSize) + { + PsAPI.EmptyWorkingSet(); + } + } + + public static void CaptureClipboard() + { + using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Clipboard); + captureHelper.MakeCapture(); + } + + public static void CaptureClipboard(IDestination destination) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Clipboard); if (destination != null) { - captureHelper.AddDestination(destination); - } + captureHelper.AddDestination(destination); + } + captureHelper.MakeCapture(); } - public static void CaptureRegion(bool captureMouse) + public static void CaptureRegion(bool captureMouse) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Region, captureMouse); captureHelper.MakeCapture(); } - public static void CaptureRegion(bool captureMouse, IDestination destination) + + public static void CaptureRegion(bool captureMouse, IDestination destination) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Region, captureMouse, destination); captureHelper.MakeCapture(); } - public static void CaptureRegion(bool captureMouse, Rectangle region) + + public static void CaptureRegion(bool captureMouse, Rectangle region) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Region, captureMouse); captureHelper.MakeCapture(region); } - public static void CaptureFullscreen(bool captureMouse, ScreenCaptureMode screenCaptureMode) + + public static void CaptureFullscreen(bool captureMouse, ScreenCaptureMode screenCaptureMode) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.FullScreen, captureMouse) { @@ -125,13 +138,14 @@ namespace Greenshot.Helpers { }; captureHelper.MakeCapture(); } - public static void CaptureLastRegion(bool captureMouse) + + public static void CaptureLastRegion(bool captureMouse) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.LastRegion, captureMouse); captureHelper.MakeCapture(); } - public static void CaptureIe(bool captureMouse, WindowDetails windowToCapture) + public static void CaptureIe(bool captureMouse, WindowDetails windowToCapture) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.IE, captureMouse) { @@ -140,13 +154,13 @@ namespace Greenshot.Helpers { captureHelper.MakeCapture(); } - public static void CaptureWindow(bool captureMouse) + public static void CaptureWindow(bool captureMouse) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.ActiveWindow, captureMouse); captureHelper.MakeCapture(); } - public static void CaptureWindow(WindowDetails windowToCapture) + public static void CaptureWindow(WindowDetails windowToCapture) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.ActiveWindow) { @@ -155,25 +169,25 @@ namespace Greenshot.Helpers { captureHelper.MakeCapture(); } - public static void CaptureWindowInteractive(bool captureMouse) + public static void CaptureWindowInteractive(bool captureMouse) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Window, captureMouse); captureHelper.MakeCapture(); } - public static void CaptureFile(string filename) + public static void CaptureFile(string filename) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.File); captureHelper.MakeCapture(filename); } - public static void CaptureFile(string filename, IDestination destination) + public static void CaptureFile(string filename, IDestination destination) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.File); captureHelper.AddDestination(destination).MakeCapture(filename); } - public static void ImportCapture(ICapture captureToImport) + public static void ImportCapture(ICapture captureToImport) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.File) { @@ -182,409 +196,505 @@ namespace Greenshot.Helpers { captureHelper.HandleCapture(); } - public CaptureHelper AddDestination(IDestination destination) { - _capture.CaptureDetails.AddDestination(destination); - return this; - } + public CaptureHelper AddDestination(IDestination destination) + { + _capture.CaptureDetails.AddDestination(destination); + return this; + } - public CaptureHelper(CaptureMode captureMode) { - _captureMode = captureMode; - _capture = new Capture(); - } + public CaptureHelper(CaptureMode captureMode) + { + _captureMode = captureMode; + _capture = new Capture(); + } - public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor) : this(captureMode) { - _captureMouseCursor = captureMouseCursor; - } + public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor) : this(captureMode) + { + _captureMouseCursor = captureMouseCursor; + } - public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor, ScreenCaptureMode screenCaptureMode) : this(captureMode) { - _captureMouseCursor = captureMouseCursor; - _screenCaptureMode = screenCaptureMode; - } + public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor, ScreenCaptureMode screenCaptureMode) : this(captureMode) + { + _captureMouseCursor = captureMouseCursor; + _screenCaptureMode = screenCaptureMode; + } - public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor, IDestination destination) : this(captureMode, captureMouseCursor) { - _capture.CaptureDetails.AddDestination(destination); - } + public CaptureHelper(CaptureMode captureMode, bool captureMouseCursor, IDestination destination) : this(captureMode, captureMouseCursor) + { + _capture.CaptureDetails.AddDestination(destination); + } - public WindowDetails SelectedCaptureWindow { - get => _selectedCaptureWindow; - set => _selectedCaptureWindow = value; - } + public WindowDetails SelectedCaptureWindow + { + get => _selectedCaptureWindow; + set => _selectedCaptureWindow = value; + } - private void DoCaptureFeedback() { - if (CoreConfig.PlayCameraSound) { - SoundHelper.Play(); - } - } + private void DoCaptureFeedback() + { + if (CoreConfig.PlayCameraSound) + { + SoundHelper.Play(); + } + } - /// - /// Make Capture with file name - /// - /// filename - private void MakeCapture(string filename) { - _capture.CaptureDetails.Filename = filename; - MakeCapture(); - } + /// + /// Make Capture with file name + /// + /// filename + private void MakeCapture(string filename) + { + _capture.CaptureDetails.Filename = filename; + MakeCapture(); + } - /// - /// Make Capture for region - /// - /// Rectangle - private void MakeCapture(Rectangle region) { - _captureRect = region; - MakeCapture(); - } + /// + /// Make Capture for region + /// + /// Rectangle + private void MakeCapture(Rectangle region) + { + _captureRect = region; + MakeCapture(); + } - /// - /// Make Capture with specified destinations - /// - private void MakeCapture() { - Thread retrieveWindowDetailsThread = null; + /// + /// Make Capture with specified destinations + /// + private void MakeCapture() + { + Thread retrieveWindowDetailsThread = null; - // This fixes a problem when a balloon is still visible and a capture needs to be taken - // forcefully removes the balloon! - if (!CoreConfig.HideTrayicon) + // This fixes a problem when a balloon is still visible and a capture needs to be taken + // forcefully removes the balloon! + if (!CoreConfig.HideTrayicon) { var notifyIcon = SimpleServiceProvider.Current.GetInstance(); notifyIcon.Visible = false; notifyIcon.Visible = true; - } - Log.Debug($"Capturing with mode {_captureMode} and using Cursor {_captureMouseCursor}"); - _capture.CaptureDetails.CaptureMode = _captureMode; + } - // Get the windows details in a separate thread, only for those captures that have a Feedback - // As currently the "elements" aren't used, we don't need them yet - switch (_captureMode) { - case CaptureMode.Region: - // Check if a region is pre-supplied! - if (Rectangle.Empty.Equals(_captureRect)) { - retrieveWindowDetailsThread = PrepareForCaptureWithFeedback(); - } - break; - case CaptureMode.Window: - retrieveWindowDetailsThread = PrepareForCaptureWithFeedback(); - break; - } + Log.Debug($"Capturing with mode {_captureMode} and using Cursor {_captureMouseCursor}"); + _capture.CaptureDetails.CaptureMode = _captureMode; - // Add destinations if no-one passed a handler - if (_capture.CaptureDetails.CaptureDestinations == null || _capture.CaptureDetails.CaptureDestinations.Count == 0) { - AddConfiguredDestination(); - } + // Get the windows details in a separate thread, only for those captures that have a Feedback + // As currently the "elements" aren't used, we don't need them yet + switch (_captureMode) + { + case CaptureMode.Region: + // Check if a region is pre-supplied! + if (Rectangle.Empty.Equals(_captureRect)) + { + retrieveWindowDetailsThread = PrepareForCaptureWithFeedback(); + } - // Delay for the Context menu - if (CoreConfig.CaptureDelay > 0) { - Thread.Sleep(CoreConfig.CaptureDelay); - } else { - CoreConfig.CaptureDelay = 0; - } + break; + case CaptureMode.Window: + retrieveWindowDetailsThread = PrepareForCaptureWithFeedback(); + break; + } - // Capture Mouse cursor if we are not loading from file or clipboard, only show when needed - if (_captureMode != CaptureMode.File && _captureMode != CaptureMode.Clipboard) - { - _capture = WindowCapture.CaptureCursor(_capture); - _capture.CursorVisible = _captureMouseCursor && CoreConfig.CaptureMousepointer; - } + // Add destinations if no-one passed a handler + if (_capture.CaptureDetails.CaptureDestinations == null || _capture.CaptureDetails.CaptureDestinations.Count == 0) + { + AddConfiguredDestination(); + } - switch(_captureMode) { - case CaptureMode.Window: - _capture = WindowCapture.CaptureScreen(_capture); - _capture.CaptureDetails.AddMetaData("source", "Screen"); - SetDpi(); - CaptureWithFeedback(); - break; - case CaptureMode.ActiveWindow: - if (CaptureActiveWindow()) { - // Capture worked, offset mouse according to screen bounds and capture location - _capture.MoveMouseLocation(_capture.ScreenBounds.Location.X-_capture.Location.X, _capture.ScreenBounds.Location.Y-_capture.Location.Y); - _capture.CaptureDetails.AddMetaData("source", "Window"); - } else { - _captureMode = CaptureMode.FullScreen; - _capture = WindowCapture.CaptureScreen(_capture); - _capture.CaptureDetails.AddMetaData("source", "Screen"); - _capture.CaptureDetails.Title = "Screen"; - } - SetDpi(); - HandleCapture(); - break; - case CaptureMode.IE: - if (IeCaptureHelper.CaptureIe(_capture, SelectedCaptureWindow) != null) { - _capture.CaptureDetails.AddMetaData("source", "Internet Explorer"); - SetDpi(); - HandleCapture(); - } - break; - case CaptureMode.FullScreen: - // Check how we need to capture the screen - bool captureTaken = false; - switch (_screenCaptureMode) { - case ScreenCaptureMode.Auto: - Point mouseLocation = User32.GetCursorLocation(); - foreach (Screen screen in Screen.AllScreens) { - if (screen.Bounds.Contains(mouseLocation)) { - _capture = WindowCapture.CaptureRectangle(_capture, screen.Bounds); - captureTaken = true; - // As the screen shot might be on a different monitor we need to correct the mouse location - var correctedCursorLocation = _capture.CursorLocation; - correctedCursorLocation.Offset(-screen.Bounds.Location.X, -screen.Bounds.Location.Y); - _capture.CursorLocation = correctedCursorLocation; - break; - } - } - break; - case ScreenCaptureMode.Fixed: - if (CoreConfig.ScreenToCapture > 0 && CoreConfig.ScreenToCapture <= Screen.AllScreens.Length) { - _capture = WindowCapture.CaptureRectangle(_capture, Screen.AllScreens[CoreConfig.ScreenToCapture].Bounds); - captureTaken = true; - } - break; - case ScreenCaptureMode.FullScreen: - // Do nothing, we take the fullscreen capture automatically - break; - } - if (!captureTaken) { - _capture = WindowCapture.CaptureScreen(_capture); - } - SetDpi(); - HandleCapture(); - break; - case CaptureMode.Clipboard: - Image clipboardImage = ClipboardHelper.GetImage(); - if (clipboardImage != null) { - if (_capture != null) { - _capture.Image = clipboardImage; - } else { - _capture = new Capture(clipboardImage); - } - _capture.CaptureDetails.Title = "Clipboard"; - _capture.CaptureDetails.AddMetaData("source", "Clipboard"); - // Force Editor, keep picker - if (_capture.CaptureDetails.HasDestination(PickerDestination.DESIGNATION)) { - _capture.CaptureDetails.ClearDestinations(); - _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); - _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(PickerDestination.DESIGNATION)); - } else { - _capture.CaptureDetails.ClearDestinations(); - _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); - } - HandleCapture(); - } else { - MessageBox.Show(Language.GetString("clipboard_noimage")); - } - break; - case CaptureMode.File: - Image fileImage = null; - string filename = _capture.CaptureDetails.Filename; + // Delay for the Context menu + if (CoreConfig.CaptureDelay > 0) + { + Thread.Sleep(CoreConfig.CaptureDelay); + } + else + { + CoreConfig.CaptureDelay = 0; + } - if (!string.IsNullOrEmpty(filename)) { - try { - if (filename.ToLower().EndsWith("." + OutputFormat.greenshot)) { - ISurface surface = new Surface(); - surface = ImageOutput.LoadGreenshotSurface(filename, surface); - surface.CaptureDetails = _capture.CaptureDetails; - DestinationHelper.GetDestination(EditorDestination.DESIGNATION).ExportCapture(true, surface, _capture.CaptureDetails); - break; - } - } catch (Exception e) { - Log.Error(e.Message, e); - MessageBox.Show(Language.GetFormattedString(LangKey.error_openfile, filename)); - } - try { - fileImage = ImageHelper.LoadImage(filename); - } catch (Exception e) { - Log.Error(e.Message, e); - MessageBox.Show(Language.GetFormattedString(LangKey.error_openfile, filename)); - } - } - if (fileImage != null) { - _capture.CaptureDetails.Title = Path.GetFileNameWithoutExtension(filename); - _capture.CaptureDetails.AddMetaData("file", filename); - _capture.CaptureDetails.AddMetaData("source", "file"); - if (_capture != null) { - _capture.Image = fileImage; - } else { - _capture = new Capture(fileImage); - } - // Force Editor, keep picker, this is currently the only usefull destination - if (_capture.CaptureDetails.HasDestination(PickerDestination.DESIGNATION)) { - _capture.CaptureDetails.ClearDestinations(); - _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); - _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(PickerDestination.DESIGNATION)); - } else { - _capture.CaptureDetails.ClearDestinations(); - _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); - } - HandleCapture(); - } - break; - case CaptureMode.LastRegion: - if (!CoreConfig.LastCapturedRegion.IsEmpty) { - _capture = WindowCapture.CaptureRectangle(_capture, CoreConfig.LastCapturedRegion); - // TODO: Reactive / check if the elements code is activated - //if (windowDetailsThread != null) { - // windowDetailsThread.Join(); - //} + // Capture Mouse cursor if we are not loading from file or clipboard, only show when needed + if (_captureMode != CaptureMode.File && _captureMode != CaptureMode.Clipboard) + { + _capture = WindowCapture.CaptureCursor(_capture); + _capture.CursorVisible = _captureMouseCursor && CoreConfig.CaptureMousepointer; + } - // Set capture title, fixing bug #3569703 - foreach (WindowDetails window in WindowDetails.GetVisibleWindows()) { - Point estimatedLocation = new Point(CoreConfig.LastCapturedRegion.X + CoreConfig.LastCapturedRegion.Width / 2, CoreConfig.LastCapturedRegion.Y + CoreConfig.LastCapturedRegion.Height / 2); - if (window.Contains(estimatedLocation)) { - _selectedCaptureWindow = window; - _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; - break; - } - } - // Move cursor, fixing bug #3569703 - _capture.MoveMouseLocation(_capture.ScreenBounds.Location.X - _capture.Location.X, _capture.ScreenBounds.Location.Y - _capture.Location.Y); - //capture.MoveElements(capture.ScreenBounds.Location.X - capture.Location.X, capture.ScreenBounds.Location.Y - capture.Location.Y); + switch (_captureMode) + { + case CaptureMode.Window: + _capture = WindowCapture.CaptureScreen(_capture); + _capture.CaptureDetails.AddMetaData("source", "Screen"); + SetDpi(); + CaptureWithFeedback(); + break; + case CaptureMode.ActiveWindow: + if (CaptureActiveWindow()) + { + // Capture worked, offset mouse according to screen bounds and capture location + _capture.MoveMouseLocation(_capture.ScreenBounds.Location.X - _capture.Location.X, _capture.ScreenBounds.Location.Y - _capture.Location.Y); + _capture.CaptureDetails.AddMetaData("source", "Window"); + } + else + { + _captureMode = CaptureMode.FullScreen; + _capture = WindowCapture.CaptureScreen(_capture); + _capture.CaptureDetails.AddMetaData("source", "Screen"); + _capture.CaptureDetails.Title = "Screen"; + } - _capture.CaptureDetails.AddMetaData("source", "screen"); - SetDpi(); - HandleCapture(); - } - break; - case CaptureMode.Region: - // Check if a region is pre-supplied! - if (Rectangle.Empty.Equals(_captureRect)) { - _capture = WindowCapture.CaptureScreen(_capture); - _capture.CaptureDetails.AddMetaData("source", "screen"); - SetDpi(); - CaptureWithFeedback(); - } else { - _capture = WindowCapture.CaptureRectangle(_capture, _captureRect); - _capture.CaptureDetails.AddMetaData("source", "screen"); - SetDpi(); - HandleCapture(); - } - break; - default: - Log.Warn("Unknown capture mode: " + _captureMode); - break; - } - // Wait for thread, otherwise we can't dispose the CaptureHelper - retrieveWindowDetailsThread?.Join(); - if (_capture != null) { - Log.Debug("Disposing capture"); - _capture.Dispose(); - } - } + SetDpi(); + HandleCapture(); + break; + case CaptureMode.IE: + if (IeCaptureHelper.CaptureIe(_capture, SelectedCaptureWindow) != null) + { + _capture.CaptureDetails.AddMetaData("source", "Internet Explorer"); + SetDpi(); + HandleCapture(); + } - /// - /// Pre-Initialization for CaptureWithFeedback, this will get all the windows before we change anything - /// - private Thread PrepareForCaptureWithFeedback() { - _windows = new List(); + break; + case CaptureMode.FullScreen: + // Check how we need to capture the screen + bool captureTaken = false; + switch (_screenCaptureMode) + { + case ScreenCaptureMode.Auto: + Point mouseLocation = User32.GetCursorLocation(); + foreach (Screen screen in Screen.AllScreens) + { + if (screen.Bounds.Contains(mouseLocation)) + { + _capture = WindowCapture.CaptureRectangle(_capture, screen.Bounds); + captureTaken = true; + // As the screen shot might be on a different monitor we need to correct the mouse location + var correctedCursorLocation = _capture.CursorLocation; + correctedCursorLocation.Offset(-screen.Bounds.Location.X, -screen.Bounds.Location.Y); + _capture.CursorLocation = correctedCursorLocation; + break; + } + } - // If the App Launcher is visisble, no other windows are active - WindowDetails appLauncherWindow = WindowDetails.GetAppLauncher(); - if (appLauncherWindow != null && appLauncherWindow.Visible) { - _windows.Add(appLauncherWindow); - return null; - } + break; + case ScreenCaptureMode.Fixed: + if (CoreConfig.ScreenToCapture > 0 && CoreConfig.ScreenToCapture <= Screen.AllScreens.Length) + { + _capture = WindowCapture.CaptureRectangle(_capture, Screen.AllScreens[CoreConfig.ScreenToCapture].Bounds); + captureTaken = true; + } - Thread getWindowDetailsThread = new Thread(RetrieveWindowDetails) - { - Name = "Retrieve window details", - IsBackground = true - }; - getWindowDetailsThread.Start(); - return getWindowDetailsThread; - } + break; + case ScreenCaptureMode.FullScreen: + // Do nothing, we take the fullscreen capture automatically + break; + } - private void RetrieveWindowDetails() { - Log.Debug("start RetrieveWindowDetails"); - // Start Enumeration of "active" windows - foreach (var window in WindowDetails.GetVisibleWindows()) { - // Make sure the details are retrieved once - window.FreezeDetails(); + if (!captureTaken) + { + _capture = WindowCapture.CaptureScreen(_capture); + } - // Force children retrieval, sometimes windows close on losing focus and this is solved by caching - int goLevelDeep = 3; - if (CoreConfig.WindowCaptureAllChildLocations) { - goLevelDeep = 20; - } - window.GetChildren(goLevelDeep); - lock (_windows) { - _windows.Add(window); - } - } - Log.Debug("end RetrieveWindowDetails"); - } + SetDpi(); + HandleCapture(); + break; + case CaptureMode.Clipboard: + Image clipboardImage = ClipboardHelper.GetImage(); + if (clipboardImage != null) + { + if (_capture != null) + { + _capture.Image = clipboardImage; + } + else + { + _capture = new Capture(clipboardImage); + } - private void AddConfiguredDestination() { - foreach(string destinationDesignation in CoreConfig.OutputDestinations) { - IDestination destination = DestinationHelper.GetDestination(destinationDesignation); - if (destination != null) { - _capture.CaptureDetails.AddDestination(destination); - } - } - } + _capture.CaptureDetails.Title = "Clipboard"; + _capture.CaptureDetails.AddMetaData("source", "Clipboard"); + // Force Editor, keep picker + if (_capture.CaptureDetails.HasDestination(PickerDestination.DESIGNATION)) + { + _capture.CaptureDetails.ClearDestinations(); + _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); + _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(PickerDestination.DESIGNATION)); + } + else + { + _capture.CaptureDetails.ClearDestinations(); + _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); + } - /// - /// If a balloon tip is show for a taken capture, this handles the click on it - /// - /// SurfaceMessageEventArgs - private void OpenCaptureOnClick(SurfaceMessageEventArgs e) { - var notifyIcon = SimpleServiceProvider.Current.GetInstance(); - if (notifyIcon.Tag is not SurfaceMessageEventArgs eventArgs) { - Log.Warn("OpenCaptureOnClick called without SurfaceMessageEventArgs"); - return; - } - ISurface surface = eventArgs.Surface; - if (surface != null) - { - switch (eventArgs.MessageType) - { - case SurfaceMessageTyp.FileSaved: - ExplorerHelper.OpenInExplorer(surface.LastSaveFullPath); - break; - case SurfaceMessageTyp.UploadedUri: - Process.Start(surface.UploadUrl); - break; - } - } - Log.DebugFormat("Deregistering the BalloonTipClicked"); + HandleCapture(); + } + else + { + MessageBox.Show(Language.GetString("clipboard_noimage")); + } + + break; + case CaptureMode.File: + Image fileImage = null; + string filename = _capture.CaptureDetails.Filename; + + if (!string.IsNullOrEmpty(filename)) + { + try + { + if (filename.ToLower().EndsWith("." + OutputFormat.greenshot)) + { + ISurface surface = new Surface(); + surface = ImageOutput.LoadGreenshotSurface(filename, surface); + surface.CaptureDetails = _capture.CaptureDetails; + DestinationHelper.GetDestination(EditorDestination.DESIGNATION).ExportCapture(true, surface, _capture.CaptureDetails); + break; + } + } + catch (Exception e) + { + Log.Error(e.Message, e); + MessageBox.Show(Language.GetFormattedString(LangKey.error_openfile, filename)); + } + + try + { + fileImage = ImageHelper.LoadImage(filename); + } + catch (Exception e) + { + Log.Error(e.Message, e); + MessageBox.Show(Language.GetFormattedString(LangKey.error_openfile, filename)); + } + } + + if (fileImage != null) + { + _capture.CaptureDetails.Title = Path.GetFileNameWithoutExtension(filename); + _capture.CaptureDetails.AddMetaData("file", filename); + _capture.CaptureDetails.AddMetaData("source", "file"); + if (_capture != null) + { + _capture.Image = fileImage; + } + else + { + _capture = new Capture(fileImage); + } + + // Force Editor, keep picker, this is currently the only usefull destination + if (_capture.CaptureDetails.HasDestination(PickerDestination.DESIGNATION)) + { + _capture.CaptureDetails.ClearDestinations(); + _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); + _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(PickerDestination.DESIGNATION)); + } + else + { + _capture.CaptureDetails.ClearDestinations(); + _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); + } + + HandleCapture(); + } + + break; + case CaptureMode.LastRegion: + if (!CoreConfig.LastCapturedRegion.IsEmpty) + { + _capture = WindowCapture.CaptureRectangle(_capture, CoreConfig.LastCapturedRegion); + // TODO: Reactive / check if the elements code is activated + //if (windowDetailsThread != null) { + // windowDetailsThread.Join(); + //} + + // Set capture title, fixing bug #3569703 + foreach (WindowDetails window in WindowDetails.GetVisibleWindows()) + { + Point estimatedLocation = new Point(CoreConfig.LastCapturedRegion.X + CoreConfig.LastCapturedRegion.Width / 2, + CoreConfig.LastCapturedRegion.Y + CoreConfig.LastCapturedRegion.Height / 2); + if (window.Contains(estimatedLocation)) + { + _selectedCaptureWindow = window; + _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; + break; + } + } + + // Move cursor, fixing bug #3569703 + _capture.MoveMouseLocation(_capture.ScreenBounds.Location.X - _capture.Location.X, _capture.ScreenBounds.Location.Y - _capture.Location.Y); + //capture.MoveElements(capture.ScreenBounds.Location.X - capture.Location.X, capture.ScreenBounds.Location.Y - capture.Location.Y); + + _capture.CaptureDetails.AddMetaData("source", "screen"); + SetDpi(); + HandleCapture(); + } + + break; + case CaptureMode.Region: + // Check if a region is pre-supplied! + if (Rectangle.Empty.Equals(_captureRect)) + { + _capture = WindowCapture.CaptureScreen(_capture); + _capture.CaptureDetails.AddMetaData("source", "screen"); + SetDpi(); + CaptureWithFeedback(); + } + else + { + _capture = WindowCapture.CaptureRectangle(_capture, _captureRect); + _capture.CaptureDetails.AddMetaData("source", "screen"); + SetDpi(); + HandleCapture(); + } + + break; + default: + Log.Warn("Unknown capture mode: " + _captureMode); + break; + } + + // Wait for thread, otherwise we can't dispose the CaptureHelper + retrieveWindowDetailsThread?.Join(); + if (_capture != null) + { + Log.Debug("Disposing capture"); + _capture.Dispose(); + } } /// - /// This is the SurfaceMessageEvent receiver - /// - /// object - /// SurfaceMessageEventArgs - private void SurfaceMessageReceived(object sender, SurfaceMessageEventArgs eventArgs) { - if (string.IsNullOrEmpty(eventArgs?.Message)) { - return; - } - var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); - switch (eventArgs.MessageType) { - case SurfaceMessageTyp.Error: - notifyIconClassicMessageHandler.ShowErrorMessage(eventArgs.Message, TimeSpan.FromHours(1)); - break; - case SurfaceMessageTyp.Info: - notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, TimeSpan.FromHours(1), () => - { - Log.Info("Clicked!"); - }); - break; - case SurfaceMessageTyp.FileSaved: - case SurfaceMessageTyp.UploadedUri: - // Show a balloon and register an event handler to open the "capture" for if someone clicks the balloon. - notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, TimeSpan.FromHours(1), () => OpenCaptureOnClick(eventArgs)); - break; - } - } + /// Pre-Initialization for CaptureWithFeedback, this will get all the windows before we change anything + ///
+ private Thread PrepareForCaptureWithFeedback() + { + _windows = new List(); - private void HandleCapture() { - // Flag to see if the image was "exported" so the FileEditor doesn't - // ask to save the file as long as nothing is done. - bool outputMade = false; + // If the App Launcher is visisble, no other windows are active + WindowDetails appLauncherWindow = WindowDetails.GetAppLauncher(); + if (appLauncherWindow != null && appLauncherWindow.Visible) + { + _windows.Add(appLauncherWindow); + return null; + } + + Thread getWindowDetailsThread = new Thread(RetrieveWindowDetails) + { + Name = "Retrieve window details", + IsBackground = true + }; + getWindowDetailsThread.Start(); + return getWindowDetailsThread; + } + + private void RetrieveWindowDetails() + { + Log.Debug("start RetrieveWindowDetails"); + // Start Enumeration of "active" windows + foreach (var window in WindowDetails.GetVisibleWindows()) + { + // Make sure the details are retrieved once + window.FreezeDetails(); + + // Force children retrieval, sometimes windows close on losing focus and this is solved by caching + int goLevelDeep = 3; + if (CoreConfig.WindowCaptureAllChildLocations) + { + goLevelDeep = 20; + } + + window.GetChildren(goLevelDeep); + lock (_windows) + { + _windows.Add(window); + } + } + + Log.Debug("end RetrieveWindowDetails"); + } + + private void AddConfiguredDestination() + { + foreach (string destinationDesignation in CoreConfig.OutputDestinations) + { + IDestination destination = DestinationHelper.GetDestination(destinationDesignation); + if (destination != null) + { + _capture.CaptureDetails.AddDestination(destination); + } + } + } + + /// + /// If a balloon tip is show for a taken capture, this handles the click on it + /// + /// SurfaceMessageEventArgs + private void OpenCaptureOnClick(SurfaceMessageEventArgs e) + { + var notifyIcon = SimpleServiceProvider.Current.GetInstance(); + if (notifyIcon.Tag is not SurfaceMessageEventArgs eventArgs) + { + Log.Warn("OpenCaptureOnClick called without SurfaceMessageEventArgs"); + return; + } + + ISurface surface = eventArgs.Surface; + if (surface != null) + { + switch (eventArgs.MessageType) + { + case SurfaceMessageTyp.FileSaved: + ExplorerHelper.OpenInExplorer(surface.LastSaveFullPath); + break; + case SurfaceMessageTyp.UploadedUri: + Process.Start(surface.UploadUrl); + break; + } + } + + Log.DebugFormat("Deregistering the BalloonTipClicked"); + } + + /// + /// This is the SurfaceMessageEvent receiver + /// + /// object + /// SurfaceMessageEventArgs + private void SurfaceMessageReceived(object sender, SurfaceMessageEventArgs eventArgs) + { + if (string.IsNullOrEmpty(eventArgs?.Message)) + { + return; + } + + var notifyIconClassicMessageHandler = SimpleServiceProvider.Current.GetInstance(); + switch (eventArgs.MessageType) + { + case SurfaceMessageTyp.Error: + notifyIconClassicMessageHandler.ShowErrorMessage(eventArgs.Message, TimeSpan.FromHours(1)); + break; + case SurfaceMessageTyp.Info: + notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, TimeSpan.FromHours(1), () => { Log.Info("Clicked!"); }); + break; + case SurfaceMessageTyp.FileSaved: + case SurfaceMessageTyp.UploadedUri: + // Show a balloon and register an event handler to open the "capture" for if someone clicks the balloon. + notifyIconClassicMessageHandler.ShowInfoMessage(eventArgs.Message, TimeSpan.FromHours(1), () => OpenCaptureOnClick(eventArgs)); + break; + } + } + + private void HandleCapture() + { + // Flag to see if the image was "exported" so the FileEditor doesn't + // ask to save the file as long as nothing is done. + bool outputMade = false; if (_capture.CaptureDetails.CaptureMode == CaptureMode.Text) { var selectionRectangle = new Rectangle(Point.Empty, _capture.Image.Size); - var ocrInfo = _capture.CaptureDetails.OcrInformation; + var ocrInfo = _capture.CaptureDetails.OcrInformation; if (ocrInfo != null) { - var textResult = new StringBuilder(); + var textResult = new StringBuilder(); foreach (var line in ocrInfo.Lines) { var lineBounds = line.CalculatedBounds; @@ -601,388 +711,495 @@ namespace Greenshot.Helpers { if (index + 1 < line.Words.Length && word.Text.Length > 1) { textResult.Append(' '); - } - } + } + } textResult.AppendLine(); } + Clipboard.SetText(textResult.ToString()); } - // Disable capturing - _captureMode = CaptureMode.None; + + // Disable capturing + _captureMode = CaptureMode.None; // Dispose the capture, we don't need it anymore (the surface copied all information and we got the title (if any)). _capture.Dispose(); _capture = null; - return; + return; } // Make sure the user sees that the capture is made - if (_capture.CaptureDetails.CaptureMode == CaptureMode.File || _capture.CaptureDetails.CaptureMode == CaptureMode.Clipboard) { - // Maybe not "made" but the original is still there... somehow - outputMade = true; - } else { - // Make sure the resolution is set correctly! - if (_capture.CaptureDetails != null) { - ((Bitmap) _capture.Image)?.SetResolution(_capture.CaptureDetails.DpiX, _capture.CaptureDetails.DpiY); - } - DoCaptureFeedback(); - } + if (_capture.CaptureDetails.CaptureMode == CaptureMode.File || _capture.CaptureDetails.CaptureMode == CaptureMode.Clipboard) + { + // Maybe not "made" but the original is still there... somehow + outputMade = true; + } + else + { + // Make sure the resolution is set correctly! + if (_capture.CaptureDetails != null) + { + ((Bitmap) _capture.Image)?.SetResolution(_capture.CaptureDetails.DpiX, _capture.CaptureDetails.DpiY); + } - Log.Debug("A capture of: " + _capture.CaptureDetails.Title); + DoCaptureFeedback(); + } - // check if someone has passed a destination - if (_capture.CaptureDetails.CaptureDestinations == null || _capture.CaptureDetails.CaptureDestinations.Count == 0) { - AddConfiguredDestination(); - } + Log.Debug("A capture of: " + _capture.CaptureDetails.Title); - // Create Surface with capture, this way elements can be added automatically (like the mouse cursor) - Surface surface = new Surface(_capture) - { - Modified = !outputMade - }; + // check if someone has passed a destination + if (_capture.CaptureDetails.CaptureDestinations == null || _capture.CaptureDetails.CaptureDestinations.Count == 0) + { + AddConfiguredDestination(); + } - // Register notify events if this is wanted - if (CoreConfig.ShowTrayNotification && !CoreConfig.HideTrayicon) { - surface.SurfaceMessage += SurfaceMessageReceived; + // Create Surface with capture, this way elements can be added automatically (like the mouse cursor) + Surface surface = new Surface(_capture) + { + Modified = !outputMade + }; - } - // Let the processors do their job - foreach(var processor in SimpleServiceProvider.Current.GetAllInstances()) { + // Register notify events if this is wanted + if (CoreConfig.ShowTrayNotification && !CoreConfig.HideTrayicon) + { + surface.SurfaceMessage += SurfaceMessageReceived; + } + + // Let the processors do their job + foreach (var processor in SimpleServiceProvider.Current.GetAllInstances()) + { if (!processor.isActive) continue; Log.InfoFormat("Calling processor {0}", processor.Description); processor.ProcessCapture(surface, _capture.CaptureDetails); } - // As the surfaces copies the reference to the image, make sure the image is not being disposed (a trick to save memory) - _capture.Image = null; + // As the surfaces copies the reference to the image, make sure the image is not being disposed (a trick to save memory) + _capture.Image = null; - // Get CaptureDetails as we need it even after the capture is disposed - ICaptureDetails captureDetails = _capture.CaptureDetails; - bool canDisposeSurface = true; + // Get CaptureDetails as we need it even after the capture is disposed + ICaptureDetails captureDetails = _capture.CaptureDetails; + bool canDisposeSurface = true; - if (captureDetails.HasDestination(PickerDestination.DESIGNATION)) { - DestinationHelper.ExportCapture(false, PickerDestination.DESIGNATION, surface, captureDetails); - captureDetails.CaptureDestinations.Clear(); - canDisposeSurface = false; - } + if (captureDetails.HasDestination(PickerDestination.DESIGNATION)) + { + DestinationHelper.ExportCapture(false, PickerDestination.DESIGNATION, surface, captureDetails); + captureDetails.CaptureDestinations.Clear(); + canDisposeSurface = false; + } - // Disable capturing - _captureMode = CaptureMode.None; - // Dispose the capture, we don't need it anymore (the surface copied all information and we got the title (if any)). - _capture.Dispose(); - _capture = null; + // Disable capturing + _captureMode = CaptureMode.None; + // Dispose the capture, we don't need it anymore (the surface copied all information and we got the title (if any)). + _capture.Dispose(); + _capture = null; - int destinationCount = captureDetails.CaptureDestinations.Count; - if (destinationCount > 0) { - // Flag to detect if we need to create a temp file for the email - // or use the file that was written - foreach(IDestination destination in captureDetails.CaptureDestinations) { - if (PickerDestination.DESIGNATION.Equals(destination.Designation)) { - continue; - } - Log.InfoFormat("Calling destination {0}", destination.Description); + int destinationCount = captureDetails.CaptureDestinations.Count; + if (destinationCount > 0) + { + // Flag to detect if we need to create a temp file for the email + // or use the file that was written + foreach (IDestination destination in captureDetails.CaptureDestinations) + { + if (PickerDestination.DESIGNATION.Equals(destination.Designation)) + { + continue; + } - ExportInformation exportInformation = destination.ExportCapture(false, surface, captureDetails); - if (EditorDestination.DESIGNATION.Equals(destination.Designation) && exportInformation.ExportMade) { - canDisposeSurface = false; - } - } - } - if (canDisposeSurface) { - surface.Dispose(); - } - } + Log.InfoFormat("Calling destination {0}", destination.Description); - private bool CaptureActiveWindow() { - bool presupplied = false; - Log.Debug("CaptureActiveWindow"); - if (_selectedCaptureWindow != null) { - Log.Debug("Using supplied window"); - presupplied = true; - } else { - _selectedCaptureWindow = WindowDetails.GetActiveWindow(); - if (_selectedCaptureWindow != null) { - if (Log.IsDebugEnabled) - { - Log.DebugFormat("Capturing window: {0} with {1}", _selectedCaptureWindow.Text, _selectedCaptureWindow.WindowRectangle); - } - } - } - if (_selectedCaptureWindow == null || (!presupplied && _selectedCaptureWindow.Iconic)) { - Log.Warn("No window to capture!"); - // Nothing to capture, code up in the stack will capture the full screen - return false; - } - if (!presupplied && _selectedCaptureWindow != null && _selectedCaptureWindow.Iconic) { - // Restore the window making sure it's visible! - // This is done mainly for a screen capture, but some applications like Excel and TOAD have weird behaviour! - _selectedCaptureWindow.Restore(); - } - _selectedCaptureWindow = SelectCaptureWindow(_selectedCaptureWindow); - if (_selectedCaptureWindow == null) { - Log.Warn("No window to capture, after SelectCaptureWindow!"); - // Nothing to capture, code up in the stack will capture the full screen - return false; - } - // Fix for Bug #3430560 - CoreConfig.LastCapturedRegion = _selectedCaptureWindow.WindowRectangle; - bool returnValue = CaptureWindow(_selectedCaptureWindow, _capture, CoreConfig.WindowCaptureMode) != null; - return returnValue; - } + ExportInformation exportInformation = destination.ExportCapture(false, surface, captureDetails); + if (EditorDestination.DESIGNATION.Equals(destination.Designation) && exportInformation.ExportMade) + { + canDisposeSurface = false; + } + } + } - /// - /// Select the window to capture, this has logic which takes care of certain special applications - /// like TOAD or Excel - /// - /// WindowDetails with the target Window - /// WindowDetails with the target Window OR a replacement - public static WindowDetails SelectCaptureWindow(WindowDetails windowToCapture) { - Rectangle windowRectangle = windowToCapture.WindowRectangle; - if (windowRectangle.Width == 0 || windowRectangle.Height == 0) { - Log.WarnFormat("Window {0} has nothing to capture, using workaround to find other window of same process.", windowToCapture.Text); - // Trying workaround, the size 0 arises with e.g. Toad.exe, has a different Window when minimized - WindowDetails linkedWindow = WindowDetails.GetLinkedWindow(windowToCapture); - if (linkedWindow != null) { - windowToCapture = linkedWindow; - } else { - return null; - } - } - return windowToCapture; - } + if (canDisposeSurface) + { + surface.Dispose(); + } + } - /// - /// Check if Process uses PresentationFramework.dll -> meaning it uses WPF - /// - /// Proces to check for the presentation framework - /// true if the process uses WPF - private static bool IsWpf(Process process) { - if (process != null) { - try { - foreach (ProcessModule module in process.Modules) { - if (module.ModuleName.StartsWith("PresentationFramework")) { - Log.InfoFormat("Found that Process {0} uses {1}, assuming it's using WPF", process.ProcessName, module.FileName); - return true; - } - } - } catch (Exception) { - // Access denied on the modules - Log.WarnFormat("No access on the modules from process {0}, assuming WPF is used.", process.ProcessName); - return true; - } - } - return false; - } + private bool CaptureActiveWindow() + { + bool presupplied = false; + Log.Debug("CaptureActiveWindow"); + if (_selectedCaptureWindow != null) + { + Log.Debug("Using supplied window"); + presupplied = true; + } + else + { + _selectedCaptureWindow = WindowDetails.GetActiveWindow(); + if (_selectedCaptureWindow != null) + { + if (Log.IsDebugEnabled) + { + Log.DebugFormat("Capturing window: {0} with {1}", _selectedCaptureWindow.Text, _selectedCaptureWindow.WindowRectangle); + } + } + } - /// - /// Capture the supplied Window - /// - /// Window to capture - /// The capture to store the details - /// What WindowCaptureMode to use - /// - public static ICapture CaptureWindow(WindowDetails windowToCapture, ICapture captureForWindow, WindowCaptureMode windowCaptureMode) { - if (captureForWindow == null) { - captureForWindow = new Capture(); - } - Rectangle windowRectangle = windowToCapture.WindowRectangle; + if (_selectedCaptureWindow == null || (!presupplied && _selectedCaptureWindow.Iconic)) + { + Log.Warn("No window to capture!"); + // Nothing to capture, code up in the stack will capture the full screen + return false; + } - // When Vista & DWM (Aero) enabled - bool dwmEnabled = DWM.IsDwmEnabled; - // get process name to be able to exclude certain processes from certain capture modes - using (Process process = windowToCapture.Process) { - bool isAutoMode = windowCaptureMode == WindowCaptureMode.Auto; - // For WindowCaptureMode.Auto we check: - // 1) Is window IE, use IE Capture - // 2) Is Windows >= Vista & DWM enabled: use DWM - // 3) Otherwise use GDI (Screen might be also okay but might lose content) - if (isAutoMode) { - if (CoreConfig.IECapture && IeCaptureHelper.IsIeWindow(windowToCapture)) { - try { - ICapture ieCapture = IeCaptureHelper.CaptureIe(captureForWindow, windowToCapture); - if (ieCapture != null) { - return ieCapture; - } - } catch (Exception ex) { - Log.WarnFormat("Problem capturing IE, skipping to normal capture. Exception message was: {0}", ex.Message); - } - } + if (!presupplied && _selectedCaptureWindow != null && _selectedCaptureWindow.Iconic) + { + // Restore the window making sure it's visible! + // This is done mainly for a screen capture, but some applications like Excel and TOAD have weird behaviour! + _selectedCaptureWindow.Restore(); + } - // Take default screen - windowCaptureMode = WindowCaptureMode.Screen; + _selectedCaptureWindow = SelectCaptureWindow(_selectedCaptureWindow); + if (_selectedCaptureWindow == null) + { + Log.Warn("No window to capture, after SelectCaptureWindow!"); + // Nothing to capture, code up in the stack will capture the full screen + return false; + } - // Change to GDI, if allowed - if (!windowToCapture.IsMetroApp && WindowCapture.IsGdiAllowed(process)) { - if (!dwmEnabled && IsWpf(process)) { - // do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF - Log.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName); - } else { - windowCaptureMode = WindowCaptureMode.GDI; - } - } + // Fix for Bug #3430560 + CoreConfig.LastCapturedRegion = _selectedCaptureWindow.WindowRectangle; + bool returnValue = CaptureWindow(_selectedCaptureWindow, _capture, CoreConfig.WindowCaptureMode) != null; + return returnValue; + } - // Change to DWM, if enabled and allowed - if (dwmEnabled) { - if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) { - windowCaptureMode = WindowCaptureMode.Aero; - } - } - } else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) { - if (!dwmEnabled || (!windowToCapture.IsMetroApp && !WindowCapture.IsDwmAllowed(process))) { - // Take default screen - windowCaptureMode = WindowCaptureMode.Screen; - // Change to GDI, if allowed - if (WindowCapture.IsGdiAllowed(process)) { - windowCaptureMode = WindowCaptureMode.GDI; - } - } - } else if (windowCaptureMode == WindowCaptureMode.GDI && !WindowCapture.IsGdiAllowed(process)) { - // GDI not allowed, take screen - windowCaptureMode = WindowCaptureMode.Screen; - } + /// + /// Select the window to capture, this has logic which takes care of certain special applications + /// like TOAD or Excel + /// + /// WindowDetails with the target Window + /// WindowDetails with the target Window OR a replacement + public static WindowDetails SelectCaptureWindow(WindowDetails windowToCapture) + { + Rectangle windowRectangle = windowToCapture.WindowRectangle; + if (windowRectangle.Width == 0 || windowRectangle.Height == 0) + { + Log.WarnFormat("Window {0} has nothing to capture, using workaround to find other window of same process.", windowToCapture.Text); + // Trying workaround, the size 0 arises with e.g. Toad.exe, has a different Window when minimized + WindowDetails linkedWindow = WindowDetails.GetLinkedWindow(windowToCapture); + if (linkedWindow != null) + { + windowToCapture = linkedWindow; + } + else + { + return null; + } + } - Log.InfoFormat("Capturing window with mode {0}", windowCaptureMode); - bool captureTaken = false; - windowRectangle.Intersect(captureForWindow.ScreenBounds); - // Try to capture - while (!captureTaken) { - ICapture tmpCapture = null; - switch (windowCaptureMode) { - case WindowCaptureMode.GDI: - if (WindowCapture.IsGdiAllowed(process)) { - if (windowToCapture.Iconic) { - // Restore the window making sure it's visible! - windowToCapture.Restore(); - } else { - windowToCapture.ToForeground(); - } - tmpCapture = windowToCapture.CaptureGdiWindow(captureForWindow); - if (tmpCapture != null) { - // check if GDI capture any good, by comparing it with the screen content - int blackCountGdi = ImageHelper.CountColor(tmpCapture.Image, Color.Black, false); - int gdiPixels = tmpCapture.Image.Width * tmpCapture.Image.Height; - int blackPercentageGdi = blackCountGdi * 100 / gdiPixels; - if (blackPercentageGdi >= 1) { - int screenPixels = windowRectangle.Width * windowRectangle.Height; + return windowToCapture; + } + + /// + /// Check if Process uses PresentationFramework.dll -> meaning it uses WPF + /// + /// Proces to check for the presentation framework + /// true if the process uses WPF + private static bool IsWpf(Process process) + { + if (process != null) + { + try + { + foreach (ProcessModule module in process.Modules) + { + if (module.ModuleName.StartsWith("PresentationFramework")) + { + Log.InfoFormat("Found that Process {0} uses {1}, assuming it's using WPF", process.ProcessName, module.FileName); + return true; + } + } + } + catch (Exception) + { + // Access denied on the modules + Log.WarnFormat("No access on the modules from process {0}, assuming WPF is used.", process.ProcessName); + return true; + } + } + + return false; + } + + /// + /// Capture the supplied Window + /// + /// Window to capture + /// The capture to store the details + /// What WindowCaptureMode to use + /// + public static ICapture CaptureWindow(WindowDetails windowToCapture, ICapture captureForWindow, WindowCaptureMode windowCaptureMode) + { + if (captureForWindow == null) + { + captureForWindow = new Capture(); + } + + Rectangle windowRectangle = windowToCapture.WindowRectangle; + + // When Vista & DWM (Aero) enabled + bool dwmEnabled = DWM.IsDwmEnabled; + // get process name to be able to exclude certain processes from certain capture modes + using (Process process = windowToCapture.Process) + { + bool isAutoMode = windowCaptureMode == WindowCaptureMode.Auto; + // For WindowCaptureMode.Auto we check: + // 1) Is window IE, use IE Capture + // 2) Is Windows >= Vista & DWM enabled: use DWM + // 3) Otherwise use GDI (Screen might be also okay but might lose content) + if (isAutoMode) + { + if (CoreConfig.IECapture && IeCaptureHelper.IsIeWindow(windowToCapture)) + { + try + { + ICapture ieCapture = IeCaptureHelper.CaptureIe(captureForWindow, windowToCapture); + if (ieCapture != null) + { + return ieCapture; + } + } + catch (Exception ex) + { + Log.WarnFormat("Problem capturing IE, skipping to normal capture. Exception message was: {0}", ex.Message); + } + } + + // Take default screen + windowCaptureMode = WindowCaptureMode.Screen; + + // Change to GDI, if allowed + if (!windowToCapture.IsMetroApp && WindowCapture.IsGdiAllowed(process)) + { + if (!dwmEnabled && IsWpf(process)) + { + // do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF + Log.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName); + } + else + { + windowCaptureMode = WindowCaptureMode.GDI; + } + } + + // Change to DWM, if enabled and allowed + if (dwmEnabled) + { + if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) + { + windowCaptureMode = WindowCaptureMode.Aero; + } + } + } + else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) + { + if (!dwmEnabled || (!windowToCapture.IsMetroApp && !WindowCapture.IsDwmAllowed(process))) + { + // Take default screen + windowCaptureMode = WindowCaptureMode.Screen; + // Change to GDI, if allowed + if (WindowCapture.IsGdiAllowed(process)) + { + windowCaptureMode = WindowCaptureMode.GDI; + } + } + } + else if (windowCaptureMode == WindowCaptureMode.GDI && !WindowCapture.IsGdiAllowed(process)) + { + // GDI not allowed, take screen + windowCaptureMode = WindowCaptureMode.Screen; + } + + Log.InfoFormat("Capturing window with mode {0}", windowCaptureMode); + bool captureTaken = false; + windowRectangle.Intersect(captureForWindow.ScreenBounds); + // Try to capture + while (!captureTaken) + { + ICapture tmpCapture = null; + switch (windowCaptureMode) + { + case WindowCaptureMode.GDI: + if (WindowCapture.IsGdiAllowed(process)) + { + if (windowToCapture.Iconic) + { + // Restore the window making sure it's visible! + windowToCapture.Restore(); + } + else + { + windowToCapture.ToForeground(); + } + + tmpCapture = windowToCapture.CaptureGdiWindow(captureForWindow); + if (tmpCapture != null) + { + // check if GDI capture any good, by comparing it with the screen content + int blackCountGdi = ImageHelper.CountColor(tmpCapture.Image, Color.Black, false); + int gdiPixels = tmpCapture.Image.Width * tmpCapture.Image.Height; + int blackPercentageGdi = blackCountGdi * 100 / gdiPixels; + if (blackPercentageGdi >= 1) + { + int screenPixels = windowRectangle.Width * windowRectangle.Height; using ICapture screenCapture = new Capture { CaptureDetails = captureForWindow.CaptureDetails }; - if (WindowCapture.CaptureRectangleFromDesktopScreen(screenCapture, windowRectangle) != null) { + if (WindowCapture.CaptureRectangleFromDesktopScreen(screenCapture, windowRectangle) != null) + { int blackCountScreen = ImageHelper.CountColor(screenCapture.Image, Color.Black, false); int blackPercentageScreen = blackCountScreen * 100 / screenPixels; - if (screenPixels == gdiPixels) { + if (screenPixels == gdiPixels) + { // "easy compare", both have the same size // If GDI has more black, use the screen capture. - if (blackPercentageGdi > blackPercentageScreen) { + if (blackPercentageGdi > blackPercentageScreen) + { Log.Debug("Using screen capture, as GDI had additional black."); // changeing the image will automatically dispose the previous tmpCapture.Image = screenCapture.Image; // Make sure it's not disposed, else the picture is gone! screenCapture.NullImage(); } - } else if (screenPixels < gdiPixels) { + } + else if (screenPixels < gdiPixels) + { // Screen capture is cropped, window is outside of screen - if (blackPercentageGdi > 50 && blackPercentageGdi > blackPercentageScreen) { + if (blackPercentageGdi > 50 && blackPercentageGdi > blackPercentageScreen) + { Log.Debug("Using screen capture, as GDI had additional black."); // changeing the image will automatically dispose the previous tmpCapture.Image = screenCapture.Image; // Make sure it's not disposed, else the picture is gone! screenCapture.NullImage(); } - } else { + } + else + { // Use the GDI capture by doing nothing Log.Debug("This should not happen, how can there be more screen as GDI pixels?"); } } } - } - } - if (tmpCapture != null) { - captureForWindow = tmpCapture; - captureTaken = true; - } else { - // A problem, try Screen - windowCaptureMode = WindowCaptureMode.Screen; - } - break; - case WindowCaptureMode.Aero: - case WindowCaptureMode.AeroTransparent: - if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) { - tmpCapture = windowToCapture.CaptureDwmWindow(captureForWindow, windowCaptureMode, isAutoMode); - } - if (tmpCapture != null) { - captureForWindow = tmpCapture; - captureTaken = true; - } else { - // A problem, try GDI - windowCaptureMode = WindowCaptureMode.GDI; - } - break; - default: - // Screen capture - if (windowToCapture.Iconic) { - // Restore the window making sure it's visible! - windowToCapture.Restore(); - } else { - windowToCapture.ToForeground(); - } + } + } - try { - captureForWindow = WindowCapture.CaptureRectangleFromDesktopScreen(captureForWindow, windowRectangle); - captureTaken = true; - } catch (Exception e) { - Log.Error("Problem capturing", e); - return null; - } - break; - } - } - } + if (tmpCapture != null) + { + captureForWindow = tmpCapture; + captureTaken = true; + } + else + { + // A problem, try Screen + windowCaptureMode = WindowCaptureMode.Screen; + } - if (captureForWindow != null) - { - captureForWindow.CaptureDetails.Title = windowToCapture.Text; - } + break; + case WindowCaptureMode.Aero: + case WindowCaptureMode.AeroTransparent: + if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) + { + tmpCapture = windowToCapture.CaptureDwmWindow(captureForWindow, windowCaptureMode, isAutoMode); + } - return captureForWindow; - } + if (tmpCapture != null) + { + captureForWindow = tmpCapture; + captureTaken = true; + } + else + { + // A problem, try GDI + windowCaptureMode = WindowCaptureMode.GDI; + } - private void SetDpi() { - // Workaround for problem with DPI retrieval, the FromHwnd activates the window... - WindowDetails previouslyActiveWindow = WindowDetails.GetActiveWindow(); - // Workaround for changed DPI settings in Windows 7 + break; + default: + // Screen capture + if (windowToCapture.Iconic) + { + // Restore the window making sure it's visible! + windowToCapture.Restore(); + } + else + { + windowToCapture.ToForeground(); + } + + try + { + captureForWindow = WindowCapture.CaptureRectangleFromDesktopScreen(captureForWindow, windowRectangle); + captureTaken = true; + } + catch (Exception e) + { + Log.Error("Problem capturing", e); + return null; + } + + break; + } + } + } + + if (captureForWindow != null) + { + captureForWindow.CaptureDetails.Title = windowToCapture.Text; + } + + return captureForWindow; + } + + private void SetDpi() + { + // Workaround for problem with DPI retrieval, the FromHwnd activates the window... + WindowDetails previouslyActiveWindow = WindowDetails.GetActiveWindow(); + // Workaround for changed DPI settings in Windows 7 var mainForm = SimpleServiceProvider.Current.GetInstance(); - using (Graphics graphics = Graphics.FromHwnd(mainForm.Handle)) { - _capture.CaptureDetails.DpiX = graphics.DpiX; - _capture.CaptureDetails.DpiY = graphics.DpiY; - } - // Set previouslyActiveWindow as foreground window - previouslyActiveWindow?.ToForeground(); - if (_capture.CaptureDetails != null) { - ((Bitmap) _capture.Image)?.SetResolution(_capture.CaptureDetails.DpiX, _capture.CaptureDetails.DpiY); - } + using (Graphics graphics = Graphics.FromHwnd(mainForm.Handle)) + { + _capture.CaptureDetails.DpiX = graphics.DpiX; + _capture.CaptureDetails.DpiY = graphics.DpiY; + } - } + // Set previouslyActiveWindow as foreground window + previouslyActiveWindow?.ToForeground(); + if (_capture.CaptureDetails != null) + { + ((Bitmap) _capture.Image)?.SetResolution(_capture.CaptureDetails.DpiX, _capture.CaptureDetails.DpiY); + } + } private void CaptureWithFeedback() { // The following, to be precise the HideApp, causes the app to close as described in BUG-1620 - // Added check for metro (Modern UI) apps, which might be maximized and cover the screen. + // Added check for metro (Modern UI) apps, which might be maximized and cover the screen. - //foreach(WindowDetails app in WindowDetails.GetAppWindows()) { - // if (app.Maximised) { - // app.HideApp(); - // } - //} + //foreach(WindowDetails app in WindowDetails.GetAppWindows()) { + // if (app.Maximised) { + // app.HideApp(); + // } + //} using CaptureForm captureForm = new CaptureForm(_capture, _windows); // Make sure the form is hidden after showing, even if an exception occurs, so all errors will be shown DialogResult result; - try { + try + { var mainForm = SimpleServiceProvider.Current.GetInstance(); - result = captureForm.ShowDialog(mainForm); - } finally { + result = captureForm.ShowDialog(mainForm); + } + finally + { captureForm.Hide(); } @@ -991,11 +1208,13 @@ namespace Greenshot.Helpers { _selectedCaptureWindow = captureForm.SelectedCaptureWindow; _captureRect = captureForm.CaptureRectangle; // Get title - if (_selectedCaptureWindow != null) { + if (_selectedCaptureWindow != null) + { _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; } - if (_captureRect.Height > 0 && _captureRect.Width > 0) { + if (_captureRect.Height > 0 && _captureRect.Width > 0) + { // Take the captureRect, this already is specified as bitmap coordinates _capture.Crop(_captureRect); @@ -1005,7 +1224,8 @@ namespace Greenshot.Helpers { tmpRectangle.Offset(_capture.ScreenBounds.Location.X, _capture.ScreenBounds.Location.Y); CoreConfig.LastCapturedRegion = tmpRectangle; } + HandleCapture(); } } -} +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/Colors.cs b/src/Greenshot/Helpers/Colors.cs index 4588f4274..b7411c6a6 100644 --- a/src/Greenshot/Helpers/Colors.cs +++ b/src/Greenshot/Helpers/Colors.cs @@ -22,31 +22,40 @@ using System.Collections.Generic; using System.Drawing; -namespace Greenshot.Helpers { - public static class Colors { - public static bool IsVisible(Color c) { - return c != null && !c.Equals(Color.Empty) && !c.Equals(Color.Transparent) && c.A > 0; - } - - public static Color Mix(List colors) { - int a = 0; - int r = 0; - int g = 0; - int b = 0; - int count = 0; - foreach (Color color in colors) { - if (!color.Equals(Color.Empty)) { - a += color.A; - r += color.R; - g += color.G; - b += color.B; - count++; - } - } - if (count==0) { - return Color.Empty; - } - return Color.FromArgb(a/count, r/count, g/count, b/count); - } - } -} +namespace Greenshot.Helpers +{ + public static class Colors + { + public static bool IsVisible(Color c) + { + return c != null && !c.Equals(Color.Empty) && !c.Equals(Color.Transparent) && c.A > 0; + } + + public static Color Mix(List colors) + { + int a = 0; + int r = 0; + int g = 0; + int b = 0; + int count = 0; + foreach (Color color in colors) + { + if (!color.Equals(Color.Empty)) + { + a += color.A; + r += color.R; + g += color.G; + b += color.B; + count++; + } + } + + if (count == 0) + { + return Color.Empty; + } + + return Color.FromArgb(a / count, r / count, g / count, b / count); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/CopyData.cs b/src/Greenshot/Helpers/CopyData.cs index 3bbebc8b4..e77ba045f 100644 --- a/src/Greenshot/Helpers/CopyData.cs +++ b/src/Greenshot/Helpers/CopyData.cs @@ -26,502 +26,573 @@ using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using System.Windows.Forms; - using GreenshotPlugin.Core; -namespace Greenshot.Helpers { - public enum CommandEnum { OpenFile, Exit, FirstLaunch, ReloadConfig }; +namespace Greenshot.Helpers +{ + public enum CommandEnum + { + OpenFile, + Exit, + FirstLaunch, + ReloadConfig + }; - /// - /// Code from vbAccelerator, location: - /// http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows_Messages/Simple_Interprocess_Communication/WM_COPYDATA_Demo_zip_SimpleInterprocessCommunicationsCS_CopyData_cs.asp - /// - [Serializable()] - public class CopyDataTransport { - private readonly List> _commands; - public List> Commands => _commands; + /// + /// Code from vbAccelerator, location: + /// http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows_Messages/Simple_Interprocess_Communication/WM_COPYDATA_Demo_zip_SimpleInterprocessCommunicationsCS_CopyData_cs.asp + /// + [Serializable()] + public class CopyDataTransport + { + private readonly List> _commands; + public List> Commands => _commands; - public CopyDataTransport() { - _commands = new List>(); - } - - public CopyDataTransport(CommandEnum command) : this() { - AddCommand(command, null); - } + public CopyDataTransport() + { + _commands = new List>(); + } - public CopyDataTransport(CommandEnum command, string commandData) : this() { - AddCommand(command, commandData); - } - public void AddCommand(CommandEnum command) { - _commands.Add(new KeyValuePair(command, null)); - } - public void AddCommand(CommandEnum command, string commandData) { - _commands.Add(new KeyValuePair(command, commandData)); - } - - } + public CopyDataTransport(CommandEnum command) : this() + { + AddCommand(command, null); + } - public delegate void CopyDataReceivedEventHandler(object sender, CopyDataReceivedEventArgs e); - - /// - /// A class which wraps using Windows native WM_COPYDATA - /// message to send interprocess data between applications. - /// This is a simple technique for interprocess data sends - /// using Windows. The alternative to this is to use - /// Remoting, which requires a network card and a way - /// to register the Remoting name of an object so it - /// can be read by other applications. - /// - public class CopyData : NativeWindow, IDisposable { - /// - /// Event raised when data is received on any of the channels - /// this class is subscribed to. - /// - public event CopyDataReceivedEventHandler CopyDataReceived; + public CopyDataTransport(CommandEnum command, string commandData) : this() + { + AddCommand(command, commandData); + } - [StructLayout(LayoutKind.Sequential)] - private struct COPYDATASTRUCT { - public readonly IntPtr dwData; - public readonly int cbData; - public readonly IntPtr lpData; - } - - private const int WM_COPYDATA = 0x4A; - private const int WM_DESTROY = 0x2; + public void AddCommand(CommandEnum command) + { + _commands.Add(new KeyValuePair(command, null)); + } + + public void AddCommand(CommandEnum command, string commandData) + { + _commands.Add(new KeyValuePair(command, commandData)); + } + } + + public delegate void CopyDataReceivedEventHandler(object sender, CopyDataReceivedEventArgs e); + + /// + /// A class which wraps using Windows native WM_COPYDATA + /// message to send interprocess data between applications. + /// This is a simple technique for interprocess data sends + /// using Windows. The alternative to this is to use + /// Remoting, which requires a network card and a way + /// to register the Remoting name of an object so it + /// can be read by other applications. + /// + public class CopyData : NativeWindow, IDisposable + { + /// + /// Event raised when data is received on any of the channels + /// this class is subscribed to. + /// + public event CopyDataReceivedEventHandler CopyDataReceived; + + [StructLayout(LayoutKind.Sequential)] + private struct COPYDATASTRUCT + { + public readonly IntPtr dwData; + public readonly int cbData; + public readonly IntPtr lpData; + } + + private const int WM_COPYDATA = 0x4A; + private const int WM_DESTROY = 0x2; private CopyDataChannels _channels; /// - /// Override for a form's Window Procedure to handle WM_COPYDATA - /// messages sent by other instances of this class. - /// - /// The Windows Message information. - protected override void WndProc (ref Message m ) { - if (m.Msg == WM_COPYDATA) - { - var cds = (COPYDATASTRUCT) Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT)); - if (cds.cbData > 0) { - byte[] data = new byte[cds.cbData]; - Marshal.Copy(cds.lpData, data, 0, cds.cbData); - MemoryStream stream = new MemoryStream(data); - BinaryFormatter b = new BinaryFormatter(); - CopyDataObjectData cdo = (CopyDataObjectData) b.Deserialize(stream); - - if (_channels != null && _channels.Contains(cdo.Channel)) { - CopyDataReceivedEventArgs d = new CopyDataReceivedEventArgs(cdo.Channel, cdo.Data, cdo.Sent); - OnCopyDataReceived(d); - m.Result = (IntPtr) 1; - } - } - } else if (m.Msg == WM_DESTROY) { - // WM_DESTROY fires before OnHandleChanged and is - // a better place to ensure that we've cleared - // everything up. - _channels?.OnHandleChange(); - base.OnHandleChange(); - } - base.WndProc(ref m); - } + /// Override for a form's Window Procedure to handle WM_COPYDATA + /// messages sent by other instances of this class. + ///
+ /// The Windows Message information. + protected override void WndProc(ref Message m) + { + if (m.Msg == WM_COPYDATA) + { + var cds = (COPYDATASTRUCT) Marshal.PtrToStructure(m.LParam, typeof(COPYDATASTRUCT)); + if (cds.cbData > 0) + { + byte[] data = new byte[cds.cbData]; + Marshal.Copy(cds.lpData, data, 0, cds.cbData); + MemoryStream stream = new MemoryStream(data); + BinaryFormatter b = new BinaryFormatter(); + CopyDataObjectData cdo = (CopyDataObjectData) b.Deserialize(stream); - /// - /// Raises the DataReceived event from this class. - /// - /// The data which has been received. - protected void OnCopyDataReceived(CopyDataReceivedEventArgs e) - { - CopyDataReceived?.Invoke(this, e); - } + if (_channels != null && _channels.Contains(cdo.Channel)) + { + CopyDataReceivedEventArgs d = new CopyDataReceivedEventArgs(cdo.Channel, cdo.Data, cdo.Sent); + OnCopyDataReceived(d); + m.Result = (IntPtr) 1; + } + } + } + else if (m.Msg == WM_DESTROY) + { + // WM_DESTROY fires before OnHandleChanged and is + // a better place to ensure that we've cleared + // everything up. + _channels?.OnHandleChange(); + base.OnHandleChange(); + } - /// - /// If the form's handle changes, the properties associated - /// with the window need to be cleared up. This override ensures - /// that it is done. Note that the CopyData class will then - /// stop responding to events and it should be recreated once - /// the new handle has been assigned. - /// - protected override void OnHandleChange () { - // need to clear up everything we had set. - _channels?.OnHandleChange(); - base.OnHandleChange(); - } - - /// - /// Gets the collection of channels. - /// - public CopyDataChannels Channels => _channels; - - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Clears up any resources associated with this object. - /// - protected virtual void Dispose(bool disposing) - { - if (!disposing || _channels == null) return; - - _channels.Clear(); - _channels = null; - } - - /// - /// Constructs a new instance of the CopyData class - /// - public CopyData() { - _channels = new CopyDataChannels(this); - } - - /// - /// Finalises a CopyData class which has not been disposed. - /// There may be a minor resource leak if this class is finalised - /// after the form it is associated with. - /// - ~CopyData() { - Dispose(false); - } - } - - /// - /// Contains data and other information associated with data - /// which has been sent from another application. - /// - public class CopyDataReceivedEventArgs : EventArgs { - /// - /// Gets the channel name that this data was sent on. - /// - public string ChannelName { get; } - - /// - /// Gets the data object which was sent. - /// - public object Data { get; } - - /// - /// Gets the date and time which at the data was sent - /// by the sending application. - /// - public DateTime Sent { get; } - - /// - /// Gets the date and time which this data item as - /// received. - /// - public DateTime Received { get; } - - /// - /// Constructs an instance of this class. - /// - /// The channel that the data was received from - /// The data which was sent - /// The date and time the data was sent - internal CopyDataReceivedEventArgs(string channelName, object data, DateTime sent) { - ChannelName = channelName; - Data = data; - Sent = sent; - Received = DateTime.Now; - } - } - - /// - /// A strongly-typed collection of channels associated with the CopyData - /// class. - /// - public class CopyDataChannels : DictionaryBase { - private readonly NativeWindow _owner; - - /// - /// Returns an enumerator for each of the CopyDataChannel objects - /// within this collection. - /// - /// An enumerator for each of the CopyDataChannel objects - /// within this collection. - public new IEnumerator GetEnumerator ( ) { - return Dictionary.Values.GetEnumerator(); - } - - /// - /// Returns the CopyDataChannel at the specified 0-based index. - /// - public CopyDataChannel this[int index] { - get { - CopyDataChannel ret = null; - int i = 0; - foreach (CopyDataChannel cdc in Dictionary.Values) { - i++; - if (i != index) continue; - - ret = cdc; - break; - } - return ret; - } - } - /// - /// Returns the CopyDataChannel for the specified channelName - /// - public CopyDataChannel this[string channelName] => (CopyDataChannel) Dictionary[channelName]; - - /// - /// Adds a new channel on which this application can send and - /// receive messages. - /// - public void Add(string channelName) { - CopyDataChannel cdc = new CopyDataChannel(_owner, channelName); - Dictionary.Add(channelName , cdc); - } - /// - /// Removes an existing channel. - /// - /// The channel to remove - public void Remove(string channelName) { - Dictionary.Remove(channelName); - } - /// - /// Gets/sets whether this channel contains a CopyDataChannel - /// for the specified channelName. - /// - public bool Contains(string channelName) { - return Dictionary.Contains(channelName); - } - - /// - /// Ensures the resources associated with a CopyDataChannel - /// object collected by this class are cleared up. - /// - protected override void OnClear() { - foreach (CopyDataChannel cdc in Dictionary.Values) { - cdc.Dispose(); - } - base.OnClear(); - } - - /// - /// Ensures any resoures associated with the CopyDataChannel object - /// which has been removed are cleared up. - /// - /// The channelName - /// The CopyDataChannel object which has - /// just been removed - protected override void OnRemoveComplete ( object key , object data ) { - ( (CopyDataChannel) data).Dispose(); - OnRemove(key, data); - } - - /// - /// If the form's handle changes, the properties associated - /// with the window need to be cleared up. This override ensures - /// that it is done. Note that the CopyData class will then - /// stop responding to events and it should be recreated once - /// the new handle has been assigned. - /// - public void OnHandleChange() { - foreach (CopyDataChannel cdc in Dictionary.Values) { - cdc.OnHandleChange(); - } - } - - /// - /// Constructs a new instance of the CopyDataChannels collection. - /// Automatically managed by the CopyData class. - /// - /// The NativeWindow this collection - /// will be associated with - internal CopyDataChannels(NativeWindow owner) { - _owner = owner; - } - } - - /// - /// A channel on which messages can be sent. - /// - public class CopyDataChannel : IDisposable { - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern IntPtr GetProp(IntPtr hWnd, string lpString); - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern bool SetProp(IntPtr hWnd, string lpString, IntPtr hData); - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern IntPtr RemoveProp(IntPtr hWnd, string lpString); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, ref COPYDATASTRUCT lParam); - - [StructLayout(LayoutKind.Sequential)] - private struct COPYDATASTRUCT { - public IntPtr dwData; - public int cbData; - public IntPtr lpData; - } - - private const int WM_COPYDATA = 0x4A; - - private readonly NativeWindow _owner; - private bool _recreateChannel; + base.WndProc(ref m); + } /// - /// Gets the name associated with this channel. - /// - public string ChannelName { get; private set; } + /// Raises the DataReceived event from this class. + ///
+ /// The data which has been received. + protected void OnCopyDataReceived(CopyDataReceivedEventArgs e) + { + CopyDataReceived?.Invoke(this, e); + } - /// - /// Sends the specified object on this channel to any other - /// applications which are listening. The object must have the - /// SerializableAttribute set, or must implement ISerializable. - /// - /// The object to send - /// The number of recipients - public int Send(object obj) { - int recipients = 0; + /// + /// If the form's handle changes, the properties associated + /// with the window need to be cleared up. This override ensures + /// that it is done. Note that the CopyData class will then + /// stop responding to events and it should be recreated once + /// the new handle has been assigned. + /// + protected override void OnHandleChange() + { + // need to clear up everything we had set. + _channels?.OnHandleChange(); + base.OnHandleChange(); + } - if (_recreateChannel) { - // handle has changed - AddChannel(); - } + /// + /// Gets the collection of channels. + /// + public CopyDataChannels Channels => _channels; - CopyDataObjectData cdo = new CopyDataObjectData(obj, ChannelName); - + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - // Try to do a binary serialization on obj. - // This will throw and exception if the object to - // be passed isn't serializable. - BinaryFormatter b = new BinaryFormatter(); - MemoryStream stream = new MemoryStream(); - b.Serialize(stream, cdo); - stream.Flush(); + /// + /// Clears up any resources associated with this object. + /// + protected virtual void Dispose(bool disposing) + { + if (!disposing || _channels == null) return; - // Now move the data into a pointer so we can send - // it using WM_COPYDATA: - // Get the length of the data: - int dataSize = (int)stream.Length; - if (dataSize > 0) { - // This isn't very efficient if your data is very large. - // First we copy to a byte array, then copy to a CoTask - // Mem object... And when we use WM_COPYDATA windows will - // make yet another copy! But if you're talking about 4K - // or less of data then it doesn't really matter. - byte[] data = new byte[dataSize]; - stream.Seek(0, SeekOrigin.Begin); - stream.Read(data, 0, dataSize); - IntPtr ptrData = Marshal.AllocCoTaskMem(dataSize); - Marshal.Copy(data, 0, ptrData, dataSize); + _channels.Clear(); + _channels = null; + } - // Send the data to each window identified on - // the channel: - foreach(WindowDetails window in WindowDetails.GetAllWindows()) { - if (!window.Handle.Equals(_owner.Handle)) { - if (GetProp(window.Handle, ChannelName) != IntPtr.Zero) { - COPYDATASTRUCT cds = new COPYDATASTRUCT - { - cbData = dataSize, - dwData = IntPtr.Zero, - lpData = ptrData - }; - SendMessage(window.Handle, WM_COPYDATA, _owner.Handle, ref cds); - recipients += Marshal.GetLastWin32Error() == 0 ? 1 : 0; - } - } - } + /// + /// Constructs a new instance of the CopyData class + /// + public CopyData() + { + _channels = new CopyDataChannels(this); + } - // Clear up the data: - Marshal.FreeCoTaskMem(ptrData); - } - stream.Close(); + /// + /// Finalises a CopyData class which has not been disposed. + /// There may be a minor resource leak if this class is finalised + /// after the form it is associated with. + /// + ~CopyData() + { + Dispose(false); + } + } - return recipients; - } + /// + /// Contains data and other information associated with data + /// which has been sent from another application. + /// + public class CopyDataReceivedEventArgs : EventArgs + { + /// + /// Gets the channel name that this data was sent on. + /// + public string ChannelName { get; } - private void AddChannel() { - // Tag this window with property "channelName" - SetProp(_owner.Handle, ChannelName, _owner.Handle); - } + /// + /// Gets the data object which was sent. + /// + public object Data { get; } - private void RemoveChannel() { - // Remove the "channelName" property from this window - RemoveProp(_owner.Handle, ChannelName); - } + /// + /// Gets the date and time which at the data was sent + /// by the sending application. + /// + public DateTime Sent { get; } - /// - /// If the form's handle changes, the properties associated - /// with the window need to be cleared up. This method ensures - /// that it is done. Note that the CopyData class will then - /// stop responding to events and it should be recreated once - /// the new handle has been assigned. - /// - public void OnHandleChange() { - RemoveChannel(); - _recreateChannel = true; - } + /// + /// Gets the date and time which this data item as + /// received. + /// + public DateTime Received { get; } - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + /// + /// Constructs an instance of this class. + /// + /// The channel that the data was received from + /// The data which was sent + /// The date and time the data was sent + internal CopyDataReceivedEventArgs(string channelName, object data, DateTime sent) + { + ChannelName = channelName; + Data = data; + Sent = sent; + Received = DateTime.Now; + } + } - /// - /// Clears up any resources associated with this channel. - /// - protected virtual void Dispose(bool disposing) - { - if (!disposing) return; - - if (ChannelName.Length > 0) { - RemoveChannel(); - } - ChannelName = string.Empty; - } + /// + /// A strongly-typed collection of channels associated with the CopyData + /// class. + /// + public class CopyDataChannels : DictionaryBase + { + private readonly NativeWindow _owner; - /// - /// Constructs a new instance of a CopyData channel. Called - /// automatically by the CopyDataChannels collection. - /// - /// The owning native window - /// The name of the channel to - /// send messages on - internal CopyDataChannel(NativeWindow owner, string channelName) { - _owner = owner; - ChannelName = channelName; - AddChannel(); - } + /// + /// Returns an enumerator for each of the CopyDataChannel objects + /// within this collection. + /// + /// An enumerator for each of the CopyDataChannel objects + /// within this collection. + public new IEnumerator GetEnumerator() + { + return Dictionary.Values.GetEnumerator(); + } - ~CopyDataChannel() { - Dispose(false); - } - } + /// + /// Returns the CopyDataChannel at the specified 0-based index. + /// + public CopyDataChannel this[int index] + { + get + { + CopyDataChannel ret = null; + int i = 0; + foreach (CopyDataChannel cdc in Dictionary.Values) + { + i++; + if (i != index) continue; - /// - /// A class which wraps the data being copied, used - /// internally within the CopyData class objects. - /// - [Serializable()] - internal class CopyDataObjectData { - /// - /// The Object to copy. Must be Serializable. - /// - public object Data; - /// - /// The date and time this object was sent. - /// - public DateTime Sent; - /// - /// The name of the channel this object is being sent on - /// - public string Channel; + ret = cdc; + break; + } - /// - /// Constructs a new instance of this object - /// - /// The data to copy - /// The channel name to send on - /// If data is not serializable. - public CopyDataObjectData(object data, string channel) { - Data = data; - if (!data.GetType().IsSerializable) { - throw new ArgumentException("Data object must be serializable.", - nameof(data)); - } - Channel = channel; - Sent = DateTime.Now; - } - } -} + return ret; + } + } + + /// + /// Returns the CopyDataChannel for the specified channelName + /// + public CopyDataChannel this[string channelName] => (CopyDataChannel) Dictionary[channelName]; + + /// + /// Adds a new channel on which this application can send and + /// receive messages. + /// + public void Add(string channelName) + { + CopyDataChannel cdc = new CopyDataChannel(_owner, channelName); + Dictionary.Add(channelName, cdc); + } + + /// + /// Removes an existing channel. + /// + /// The channel to remove + public void Remove(string channelName) + { + Dictionary.Remove(channelName); + } + + /// + /// Gets/sets whether this channel contains a CopyDataChannel + /// for the specified channelName. + /// + public bool Contains(string channelName) + { + return Dictionary.Contains(channelName); + } + + /// + /// Ensures the resources associated with a CopyDataChannel + /// object collected by this class are cleared up. + /// + protected override void OnClear() + { + foreach (CopyDataChannel cdc in Dictionary.Values) + { + cdc.Dispose(); + } + + base.OnClear(); + } + + /// + /// Ensures any resoures associated with the CopyDataChannel object + /// which has been removed are cleared up. + /// + /// The channelName + /// The CopyDataChannel object which has + /// just been removed + protected override void OnRemoveComplete(object key, object data) + { + ((CopyDataChannel) data).Dispose(); + OnRemove(key, data); + } + + /// + /// If the form's handle changes, the properties associated + /// with the window need to be cleared up. This override ensures + /// that it is done. Note that the CopyData class will then + /// stop responding to events and it should be recreated once + /// the new handle has been assigned. + /// + public void OnHandleChange() + { + foreach (CopyDataChannel cdc in Dictionary.Values) + { + cdc.OnHandleChange(); + } + } + + /// + /// Constructs a new instance of the CopyDataChannels collection. + /// Automatically managed by the CopyData class. + /// + /// The NativeWindow this collection + /// will be associated with + internal CopyDataChannels(NativeWindow owner) + { + _owner = owner; + } + } + + /// + /// A channel on which messages can be sent. + /// + public class CopyDataChannel : IDisposable + { + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern IntPtr GetProp(IntPtr hWnd, string lpString); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern bool SetProp(IntPtr hWnd, string lpString, IntPtr hData); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern IntPtr RemoveProp(IntPtr hWnd, string lpString); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, ref COPYDATASTRUCT lParam); + + [StructLayout(LayoutKind.Sequential)] + private struct COPYDATASTRUCT + { + public IntPtr dwData; + public int cbData; + public IntPtr lpData; + } + + private const int WM_COPYDATA = 0x4A; + + private readonly NativeWindow _owner; + private bool _recreateChannel; + + /// + /// Gets the name associated with this channel. + /// + public string ChannelName { get; private set; } + + /// + /// Sends the specified object on this channel to any other + /// applications which are listening. The object must have the + /// SerializableAttribute set, or must implement ISerializable. + /// + /// The object to send + /// The number of recipients + public int Send(object obj) + { + int recipients = 0; + + if (_recreateChannel) + { + // handle has changed + AddChannel(); + } + + CopyDataObjectData cdo = new CopyDataObjectData(obj, ChannelName); + + + // Try to do a binary serialization on obj. + // This will throw and exception if the object to + // be passed isn't serializable. + BinaryFormatter b = new BinaryFormatter(); + MemoryStream stream = new MemoryStream(); + b.Serialize(stream, cdo); + stream.Flush(); + + // Now move the data into a pointer so we can send + // it using WM_COPYDATA: + // Get the length of the data: + int dataSize = (int) stream.Length; + if (dataSize > 0) + { + // This isn't very efficient if your data is very large. + // First we copy to a byte array, then copy to a CoTask + // Mem object... And when we use WM_COPYDATA windows will + // make yet another copy! But if you're talking about 4K + // or less of data then it doesn't really matter. + byte[] data = new byte[dataSize]; + stream.Seek(0, SeekOrigin.Begin); + stream.Read(data, 0, dataSize); + IntPtr ptrData = Marshal.AllocCoTaskMem(dataSize); + Marshal.Copy(data, 0, ptrData, dataSize); + + // Send the data to each window identified on + // the channel: + foreach (WindowDetails window in WindowDetails.GetAllWindows()) + { + if (!window.Handle.Equals(_owner.Handle)) + { + if (GetProp(window.Handle, ChannelName) != IntPtr.Zero) + { + COPYDATASTRUCT cds = new COPYDATASTRUCT + { + cbData = dataSize, + dwData = IntPtr.Zero, + lpData = ptrData + }; + SendMessage(window.Handle, WM_COPYDATA, _owner.Handle, ref cds); + recipients += Marshal.GetLastWin32Error() == 0 ? 1 : 0; + } + } + } + + // Clear up the data: + Marshal.FreeCoTaskMem(ptrData); + } + + stream.Close(); + + return recipients; + } + + private void AddChannel() + { + // Tag this window with property "channelName" + SetProp(_owner.Handle, ChannelName, _owner.Handle); + } + + private void RemoveChannel() + { + // Remove the "channelName" property from this window + RemoveProp(_owner.Handle, ChannelName); + } + + /// + /// If the form's handle changes, the properties associated + /// with the window need to be cleared up. This method ensures + /// that it is done. Note that the CopyData class will then + /// stop responding to events and it should be recreated once + /// the new handle has been assigned. + /// + public void OnHandleChange() + { + RemoveChannel(); + _recreateChannel = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Clears up any resources associated with this channel. + /// + protected virtual void Dispose(bool disposing) + { + if (!disposing) return; + + if (ChannelName.Length > 0) + { + RemoveChannel(); + } + + ChannelName = string.Empty; + } + + /// + /// Constructs a new instance of a CopyData channel. Called + /// automatically by the CopyDataChannels collection. + /// + /// The owning native window + /// The name of the channel to + /// send messages on + internal CopyDataChannel(NativeWindow owner, string channelName) + { + _owner = owner; + ChannelName = channelName; + AddChannel(); + } + + ~CopyDataChannel() + { + Dispose(false); + } + } + + /// + /// A class which wraps the data being copied, used + /// internally within the CopyData class objects. + /// + [Serializable()] + internal class CopyDataObjectData + { + /// + /// The Object to copy. Must be Serializable. + /// + public object Data; + + /// + /// The date and time this object was sent. + /// + public DateTime Sent; + + /// + /// The name of the channel this object is being sent on + /// + public string Channel; + + /// + /// Constructs a new instance of this object + /// + /// The data to copy + /// The channel name to send on + /// If data is not serializable. + public CopyDataObjectData(object data, string channel) + { + Data = data; + if (!data.GetType().IsSerializable) + { + throw new ArgumentException("Data object must be serializable.", + nameof(data)); + } + + Channel = channel; + Sent = DateTime.Now; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/DestinationHelper.cs b/src/Greenshot/Helpers/DestinationHelper.cs index 1169edb40..0e2288e36 100644 --- a/src/Greenshot/Helpers/DestinationHelper.cs +++ b/src/Greenshot/Helpers/DestinationHelper.cs @@ -27,85 +27,106 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using log4net; -namespace Greenshot.Helpers { - /// - /// Description of DestinationHelper. - /// - public static class DestinationHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(DestinationHelper)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); +namespace Greenshot.Helpers +{ + /// + /// Description of DestinationHelper. + /// + public static class DestinationHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(DestinationHelper)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - /// - /// Initialize the internal destinations - /// - public static void RegisterInternalDestinations() { - foreach(Type destinationType in InterfaceUtils.GetSubclassesOf(typeof(IDestination),true)) { - // Only take our own - if (!"Greenshot.Destinations".Equals(destinationType.Namespace)) { - continue; - } + /// + /// Initialize the internal destinations + /// + public static void RegisterInternalDestinations() + { + foreach (Type destinationType in InterfaceUtils.GetSubclassesOf(typeof(IDestination), true)) + { + // Only take our own + if (!"Greenshot.Destinations".Equals(destinationType.Namespace)) + { + continue; + } if (destinationType.IsAbstract) continue; IDestination destination; - try { - destination = (IDestination)Activator.CreateInstance(destinationType); - } catch (Exception e) { + try + { + destination = (IDestination) Activator.CreateInstance(destinationType); + } + catch (Exception e) + { Log.ErrorFormat("Can't create instance of {0}", destinationType); Log.Error(e); continue; } - if (destination.IsActive) { + + if (destination.IsActive) + { Log.DebugFormat("Found destination {0} with designation {1}", destinationType.Name, destination.Designation); SimpleServiceProvider.Current.AddService(destination); - } else { + } + else + { Log.DebugFormat("Ignoring destination {0} with designation {1}", destinationType.Name, destination.Designation); } } - } + } - /// - /// Method to get all the destinations from the plugins - /// - /// List of IDestination - public static IEnumerable GetAllDestinations() + /// + /// Method to get all the destinations from the plugins + /// + /// List of IDestination + public static IEnumerable GetAllDestinations() { return SimpleServiceProvider.Current.GetAllInstances() .Where(destination => destination.IsActive) .Where(destination => CoreConfig.ExcludeDestinations == null || !CoreConfig.ExcludeDestinations.Contains(destination.Designation)).OrderBy(p => p.Priority).ThenBy(p => p.Description); - } + } - /// - /// Get a destination by a designation - /// - /// Designation of the destination - /// IDestination or null - public static IDestination GetDestination(string designation) { - if (designation == null) { - return null; - } - foreach (IDestination destination in GetAllDestinations()) { - if (designation.Equals(destination.Designation)) { - return destination; - } - } - return null; - } + /// + /// Get a destination by a designation + /// + /// Designation of the destination + /// IDestination or null + public static IDestination GetDestination(string designation) + { + if (designation == null) + { + return null; + } - /// - /// A simple helper method which will call ExportCapture for the destination with the specified designation - /// - /// - /// - /// - /// - public static ExportInformation ExportCapture(bool manuallyInitiated, string designation, ISurface surface, ICaptureDetails captureDetails) { - IDestination destination = GetDestination(designation); - if (destination != null && destination.IsActive) { - return destination.ExportCapture(manuallyInitiated, surface, captureDetails); - } - return null; - } - } -} + foreach (IDestination destination in GetAllDestinations()) + { + if (designation.Equals(destination.Designation)) + { + return destination; + } + } + + return null; + } + + /// + /// A simple helper method which will call ExportCapture for the destination with the specified designation + /// + /// + /// + /// + /// + public static ExportInformation ExportCapture(bool manuallyInitiated, string designation, ISurface surface, ICaptureDetails captureDetails) + { + IDestination destination = GetDestination(designation); + if (destination != null && destination.IsActive) + { + return destination.ExportCapture(manuallyInitiated, surface, captureDetails); + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/Entities/UpdateFeed.cs b/src/Greenshot/Helpers/Entities/UpdateFeed.cs index 280518fc8..7eb23d4d1 100644 --- a/src/Greenshot/Helpers/Entities/UpdateFeed.cs +++ b/src/Greenshot/Helpers/Entities/UpdateFeed.cs @@ -26,10 +26,8 @@ namespace Greenshot.Helpers.Entities [JsonObject] public class UpdateFeed { - [JsonProperty("release")] - public string CurrentReleaseVersion { get; set; } + [JsonProperty("release")] public string CurrentReleaseVersion { get; set; } - [JsonProperty("beta")] - public string CurrentBetaVersion { get; set; } + [JsonProperty("beta")] public string CurrentBetaVersion { get; set; } } -} +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/GeometryHelper.cs b/src/Greenshot/Helpers/GeometryHelper.cs index e20cf5035..f26475862 100644 --- a/src/Greenshot/Helpers/GeometryHelper.cs +++ b/src/Greenshot/Helpers/GeometryHelper.cs @@ -18,42 +18,47 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; -namespace Greenshot.Helpers { - /// - /// Description of GeometryHelper. - /// - public static class GeometryHelper { - /// - /// Finds the distance between two points on a 2D surface. - /// - /// The point on the x-axis of the first point - /// The point on the x-axis of the second point - /// The point on the y-axis of the first point - /// The point on the y-axis of the second point - /// - public static int Distance2D(int x1, int y1, int x2, int y2) { - //Take x2-x1, then square it - double part1 = Math.Pow(x2 - x1, 2); - //Take y2-y1, then square it - double part2 = Math.Pow(y2 - y1, 2); - //Add both of the parts together - double underRadical = part1 + part2; - //Get the square root of the parts - return (int)Math.Sqrt(underRadical); - } - - /// - /// Calculates the angle of a line defined by two points on a 2D surface. - /// - /// The point on the x-axis of the first point - /// The point on the x-axis of the second point - /// The point on the y-axis of the first point - /// The point on the y-axis of the second point - /// - public static double Angle2D(int x1, int y1, int x2, int y2) { - return Math.Atan2(y2 - y1, x2 - x1) * 180 / Math.PI; - } - } -} +namespace Greenshot.Helpers +{ + /// + /// Description of GeometryHelper. + /// + public static class GeometryHelper + { + /// + /// Finds the distance between two points on a 2D surface. + /// + /// The point on the x-axis of the first point + /// The point on the x-axis of the second point + /// The point on the y-axis of the first point + /// The point on the y-axis of the second point + /// + public static int Distance2D(int x1, int y1, int x2, int y2) + { + //Take x2-x1, then square it + double part1 = Math.Pow(x2 - x1, 2); + //Take y2-y1, then square it + double part2 = Math.Pow(y2 - y1, 2); + //Add both of the parts together + double underRadical = part1 + part2; + //Get the square root of the parts + return (int) Math.Sqrt(underRadical); + } + + /// + /// Calculates the angle of a line defined by two points on a 2D surface. + /// + /// The point on the x-axis of the first point + /// The point on the x-axis of the second point + /// The point on the y-axis of the first point + /// The point on the y-axis of the second point + /// + public static double Angle2D(int x1, int y1, int x2, int y2) + { + return Math.Atan2(y2 - y1, x2 - x1) * 180 / Math.PI; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/GuiRectangle.cs b/src/Greenshot/Helpers/GuiRectangle.cs index 108c5a48e..565671452 100644 --- a/src/Greenshot/Helpers/GuiRectangle.cs +++ b/src/Greenshot/Helpers/GuiRectangle.cs @@ -21,27 +21,33 @@ using System.Drawing; -namespace Greenshot.Helpers { - /// - /// Helper class for creating rectangles with positive dimensions, regardless of input coordinates - /// - public static class GuiRectangle { - - public static Rectangle GetGuiRectangle(int x, int y, int w, int h) { - var rect = new Rectangle(x, y, w, h); - MakeGuiRectangle(ref rect); - return rect; - } - - public static void MakeGuiRectangle(ref Rectangle rect) { - if (rect.Width < 0) { - rect.X += rect.Width; - rect.Width = -rect.Width; - } - if (rect.Height < 0) { - rect.Y += rect.Height; - rect.Height = -rect.Height; - } - } +namespace Greenshot.Helpers +{ + /// + /// Helper class for creating rectangles with positive dimensions, regardless of input coordinates + /// + public static class GuiRectangle + { + public static Rectangle GetGuiRectangle(int x, int y, int w, int h) + { + var rect = new Rectangle(x, y, w, h); + MakeGuiRectangle(ref rect); + return rect; + } + + public static void MakeGuiRectangle(ref Rectangle rect) + { + if (rect.Width < 0) + { + rect.X += rect.Width; + rect.Width = -rect.Width; + } + + if (rect.Height < 0) + { + rect.Y += rect.Height; + rect.Height = -rect.Height; + } + } } -} +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/IECaptureHelper.cs b/src/Greenshot/Helpers/IECaptureHelper.cs index 24b5136cf..19b020567 100644 --- a/src/Greenshot/Helpers/IECaptureHelper.cs +++ b/src/Greenshot/Helpers/IECaptureHelper.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; @@ -36,608 +37,761 @@ using GreenshotPlugin.Interop; using GreenshotPlugin.UnmanagedHelpers.Enums; using log4net; -namespace Greenshot.Helpers { - /// - /// The code for this helper comes from: http://www.codeproject.com/KB/graphics/IECapture.aspx - /// The code is modified with some of the suggestions in different comments and there still were leaks which I fixed. - /// On top I modified it to use the already available code in Greenshot. - /// Many thanks to all the people who contributed here! - /// - public static class IeCaptureHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(IeCaptureHelper)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); +namespace Greenshot.Helpers +{ + /// + /// The code for this helper comes from: http://www.codeproject.com/KB/graphics/IECapture.aspx + /// The code is modified with some of the suggestions in different comments and there still were leaks which I fixed. + /// On top I modified it to use the already available code in Greenshot. + /// Many thanks to all the people who contributed here! + /// + public static class IeCaptureHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IeCaptureHelper)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - // Helper method to activate a certain IE Tab - public static void ActivateIeTab(WindowDetails ieWindowDetails, int tabIndex) { - WindowDetails directUiWindowDetails = IEHelper.GetDirectUI(ieWindowDetails); - if (directUiWindowDetails == null) return; - - // Bring window to the front - ieWindowDetails.Restore(); - // Get accessible - Accessible ieAccessible = new Accessible(directUiWindowDetails.Handle); - // Activate Tab - ieAccessible.ActivateIETab(tabIndex); - } + // Helper method to activate a certain IE Tab + public static void ActivateIeTab(WindowDetails ieWindowDetails, int tabIndex) + { + WindowDetails directUiWindowDetails = IEHelper.GetDirectUI(ieWindowDetails); + if (directUiWindowDetails == null) return; + + // Bring window to the front + ieWindowDetails.Restore(); + // Get accessible + Accessible ieAccessible = new Accessible(directUiWindowDetails.Handle); + // Activate Tab + ieAccessible.ActivateIETab(tabIndex); + } /// - /// Does the supplied window have a IE part? - /// - /// - /// - public static bool IsIeWindow(WindowDetails someWindow) { - if ("IEFrame".Equals(someWindow.ClassName)) { - return true; - } - if (CoreConfig.WindowClassesToCheckForIE != null && CoreConfig.WindowClassesToCheckForIE.Contains(someWindow.ClassName)) { - return someWindow.GetChild("Internet Explorer_Server") != null; - } - return false; - } + /// Does the supplied window have a IE part? + ///
+ /// + /// + public static bool IsIeWindow(WindowDetails someWindow) + { + if ("IEFrame".Equals(someWindow.ClassName)) + { + return true; + } - /// - /// Get Windows displaying an IE - /// - /// IEnumerable WindowDetails - public static IEnumerable GetIeWindows() { - foreach (var possibleIeWindow in WindowDetails.GetAllWindows()) { - if (possibleIeWindow.Text.Length == 0) { - continue; - } - if (possibleIeWindow.ClientRectangle.IsEmpty) { - continue; - } - if (IsIeWindow(possibleIeWindow)) { - yield return possibleIeWindow; - } - } - } + if (CoreConfig.WindowClassesToCheckForIE != null && CoreConfig.WindowClassesToCheckForIE.Contains(someWindow.ClassName)) + { + return someWindow.GetChild("Internet Explorer_Server") != null; + } - /// - /// Simple check if IE is running - /// - /// bool - public static bool IsIeRunning() - { - return GetIeWindows().Any(); - } + return false; + } - /// - /// Gets a list of all IE Windows & tabs with the captions of the instances - /// - /// List with KeyValuePair of WindowDetails and string - public static List> GetBrowserTabs() { - var ieHandleList = new List(); - var browserWindows = new Dictionary>(); + /// + /// Get Windows displaying an IE + /// + /// IEnumerable WindowDetails + public static IEnumerable GetIeWindows() + { + foreach (var possibleIeWindow in WindowDetails.GetAllWindows()) + { + if (possibleIeWindow.Text.Length == 0) + { + continue; + } - // Find the IE windows - foreach (var ieWindow in GetIeWindows()) { - try { - if (ieHandleList.Contains(ieWindow.Handle)) - { - continue; - } - if ("IEFrame".Equals(ieWindow.ClassName)) { - var directUiwd = IEHelper.GetDirectUI(ieWindow); - if (directUiwd != null) { - var accessible = new Accessible(directUiwd.Handle); - browserWindows.Add(ieWindow, accessible.IETabCaptions); - } - } else if (CoreConfig.WindowClassesToCheckForIE != null && CoreConfig.WindowClassesToCheckForIE.Contains(ieWindow.ClassName)) { - var singleWindowText = new List(); - try { - var document2 = GetHtmlDocument(ieWindow); - string title = document2.title; - Marshal.ReleaseComObject(document2); - if (string.IsNullOrEmpty(title)) { - singleWindowText.Add(ieWindow.Text); - } else { - singleWindowText.Add(ieWindow.Text + " - " + title); - } - } catch { - singleWindowText.Add(ieWindow.Text); - } - browserWindows.Add(ieWindow, singleWindowText); - } - ieHandleList.Add(ieWindow.Handle); - } catch (Exception) { - Log.Warn("Can't get Info from " + ieWindow.ClassName); - } - } + if (possibleIeWindow.ClientRectangle.IsEmpty) + { + continue; + } - var returnList = new List>(); - foreach(var windowDetails in browserWindows.Keys) { - foreach(string tab in browserWindows[windowDetails]) { - returnList.Add(new KeyValuePair(windowDetails, tab)); - } - } - return returnList; - } + if (IsIeWindow(possibleIeWindow)) + { + yield return possibleIeWindow; + } + } + } - /// - /// Helper Method to get the IHTMLDocument2 - /// - /// - /// - private static IHTMLDocument2 GetHtmlDocument(WindowDetails mainWindow) { - var ieServer = "Internet Explorer_Server".Equals(mainWindow.ClassName) ? mainWindow : mainWindow.GetChild("Internet Explorer_Server"); - if (ieServer == null) { - Log.WarnFormat("No Internet Explorer_Server for {0}", mainWindow.Text); - return null; - } + /// + /// Simple check if IE is running + /// + /// bool + public static bool IsIeRunning() + { + return GetIeWindows().Any(); + } - uint windowMessage = User32.RegisterWindowMessage("WM_HTML_GETOBJECT"); - if (windowMessage == 0) { - Log.WarnFormat("Couldn't register WM_HTML_GETOBJECT"); - return null; - } + /// + /// Gets a list of all IE Windows & tabs with the captions of the instances + /// + /// List with KeyValuePair of WindowDetails and string + public static List> GetBrowserTabs() + { + var ieHandleList = new List(); + var browserWindows = new Dictionary>(); - Log.DebugFormat("Trying WM_HTML_GETOBJECT on {0}", ieServer.ClassName); + // Find the IE windows + foreach (var ieWindow in GetIeWindows()) + { + try + { + if (ieHandleList.Contains(ieWindow.Handle)) + { + continue; + } + + if ("IEFrame".Equals(ieWindow.ClassName)) + { + var directUiwd = IEHelper.GetDirectUI(ieWindow); + if (directUiwd != null) + { + var accessible = new Accessible(directUiwd.Handle); + browserWindows.Add(ieWindow, accessible.IETabCaptions); + } + } + else if (CoreConfig.WindowClassesToCheckForIE != null && CoreConfig.WindowClassesToCheckForIE.Contains(ieWindow.ClassName)) + { + var singleWindowText = new List(); + try + { + var document2 = GetHtmlDocument(ieWindow); + string title = document2.title; + Marshal.ReleaseComObject(document2); + if (string.IsNullOrEmpty(title)) + { + singleWindowText.Add(ieWindow.Text); + } + else + { + singleWindowText.Add(ieWindow.Text + " - " + title); + } + } + catch + { + singleWindowText.Add(ieWindow.Text); + } + + browserWindows.Add(ieWindow, singleWindowText); + } + + ieHandleList.Add(ieWindow.Handle); + } + catch (Exception) + { + Log.Warn("Can't get Info from " + ieWindow.ClassName); + } + } + + var returnList = new List>(); + foreach (var windowDetails in browserWindows.Keys) + { + foreach (string tab in browserWindows[windowDetails]) + { + returnList.Add(new KeyValuePair(windowDetails, tab)); + } + } + + return returnList; + } + + /// + /// Helper Method to get the IHTMLDocument2 + /// + /// + /// + private static IHTMLDocument2 GetHtmlDocument(WindowDetails mainWindow) + { + var ieServer = "Internet Explorer_Server".Equals(mainWindow.ClassName) ? mainWindow : mainWindow.GetChild("Internet Explorer_Server"); + if (ieServer == null) + { + Log.WarnFormat("No Internet Explorer_Server for {0}", mainWindow.Text); + return null; + } + + uint windowMessage = User32.RegisterWindowMessage("WM_HTML_GETOBJECT"); + if (windowMessage == 0) + { + Log.WarnFormat("Couldn't register WM_HTML_GETOBJECT"); + return null; + } + + Log.DebugFormat("Trying WM_HTML_GETOBJECT on {0}", ieServer.ClassName); User32.SendMessageTimeout(ieServer.Handle, windowMessage, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_NORMAL, 5000, out var response); - IHTMLDocument2 document2; - if (response != UIntPtr.Zero) { - document2 = (IHTMLDocument2)Accessible.ObjectFromLresult(response, typeof(IHTMLDocument).GUID, IntPtr.Zero); - if (document2 == null) { - Log.Error("No IHTMLDocument2 found"); - return null; - } - } else { - Log.Error("No answer on WM_HTML_GETOBJECT."); - return null; - } - return document2; - } + IHTMLDocument2 document2; + if (response != UIntPtr.Zero) + { + document2 = (IHTMLDocument2) Accessible.ObjectFromLresult(response, typeof(IHTMLDocument).GUID, IntPtr.Zero); + if (document2 == null) + { + Log.Error("No IHTMLDocument2 found"); + return null; + } + } + else + { + Log.Error("No answer on WM_HTML_GETOBJECT."); + return null; + } - /// - /// Helper method which will retrieve the IHTMLDocument2 for the supplied window, - /// or return the first if none is supplied. - /// - /// The WindowDetails to get the IHTMLDocument2 for - /// The WindowDetails to which the IHTMLDocument2 belongs - private static DocumentContainer CreateDocumentContainer(WindowDetails browserWindow) { - DocumentContainer returnDocumentContainer = null; - WindowDetails returnWindow = null; - IHTMLDocument2 returnDocument2 = null; - // alternative if no match - WindowDetails alternativeReturnWindow = null; - IHTMLDocument2 alternativeReturnDocument2 = null; - - // Find the IE windows - foreach (WindowDetails ieWindow in GetIeWindows()) { - Log.DebugFormat("Processing {0} - {1}", ieWindow.ClassName, ieWindow.Text); - - Accessible ieAccessible = null; - WindowDetails directUiwd = IEHelper.GetDirectUI(ieWindow); - if (directUiwd != null) { - ieAccessible = new Accessible(directUiwd.Handle); - } - if (ieAccessible == null) { - if (browserWindow != null) { - Log.InfoFormat("Active Window is {0}", browserWindow.Text); - } - if (!ieWindow.Equals(browserWindow)) { - Log.WarnFormat("No ieAccessible for {0}", ieWindow.Text); - continue; - } - Log.DebugFormat("No ieAccessible, but the active window is an IE window: {0}, ", ieWindow.Text); - } - - try { - // Get the Document - IHTMLDocument2 document2 = GetHtmlDocument(ieWindow); - if (document2 == null) { - continue; - } - - // Get the content window handle for the shellWindow.Document - IOleWindow oleWindow = (IOleWindow)document2; - IntPtr contentWindowHandle = IntPtr.Zero; - oleWindow?.GetWindow(out contentWindowHandle); - - if (contentWindowHandle != IntPtr.Zero) { - // Get the HTMLDocument to check the hasFocus - // See: http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/60c6c95d-377c-4bf4-860d-390840fce31c/ - IHTMLDocument4 document4 = (IHTMLDocument4)document2; - - if (document4.hasFocus()) { - Log.DebugFormat("Matched focused document: {0}", document2.title); - // Look no further, we got what we wanted! - returnDocument2 = document2; - returnWindow = new WindowDetails(contentWindowHandle); - break; - } - try { - if (ieWindow.Equals(browserWindow)) { - returnDocument2 = document2; - returnWindow = new WindowDetails(contentWindowHandle); - break; - } - if (ieAccessible != null && returnWindow == null && document2.title.Equals(ieAccessible.IEActiveTabCaption) ) { - Log.DebugFormat("Title: {0}", document2.title); - returnDocument2 = document2; - returnWindow = new WindowDetails(contentWindowHandle); - } else { - alternativeReturnDocument2 = document2; - alternativeReturnWindow = new WindowDetails(contentWindowHandle); - } - } catch (Exception) { - alternativeReturnDocument2 = document2; - alternativeReturnWindow = new WindowDetails(contentWindowHandle); - } - } - } catch (Exception e) { - Log.ErrorFormat("Major problem: Problem retrieving Document from {0}", ieWindow.Text); - Log.Error(e); - } - } - - // check if we have something to return - if (returnWindow != null) { - // As it doesn't have focus, make sure it's active - returnWindow.Restore(); - returnWindow.GetParent(); - - // Create the container - try { - returnDocumentContainer = new DocumentContainer(returnDocument2, returnWindow); - } catch (Exception e) { - Log.Error("Major problem: Problem retrieving Document."); - Log.Error(e); - } - } - - if (returnDocumentContainer == null && alternativeReturnDocument2 != null) { - // As it doesn't have focus, make sure it's active - alternativeReturnWindow.Restore(); - alternativeReturnWindow.GetParent(); - // Create the container - try { - returnDocumentContainer = new DocumentContainer(alternativeReturnDocument2, alternativeReturnWindow); - } catch (Exception e) { - Log.Error("Major problem: Problem retrieving Document."); - Log.Error(e); - } - } - return returnDocumentContainer; - } + return document2; + } /// - /// Here the logic for capturing the IE Content is located - /// - /// ICapture where the capture needs to be stored - /// window to use - /// ICapture with the content (if any) - public static ICapture CaptureIe(ICapture capture, WindowDetails windowToCapture) { - windowToCapture ??= WindowDetails.GetActiveWindow(); - - // Show backgroundform after retrieving the active window.. - BackgroundForm backgroundForm = new BackgroundForm(Language.GetString(LangKey.contextmenu_captureie), Language.GetString(LangKey.wait_ie_capture)); - backgroundForm.Show(); - //BackgroundForm backgroundForm = BackgroundForm.ShowAndWait(language.GetString(LangKey.contextmenu_captureie), language.GetString(LangKey.wait_ie_capture)); - try { - //Get IHTMLDocument2 for the current active window - DocumentContainer documentContainer = CreateDocumentContainer(windowToCapture); - - // Nothing found - if (documentContainer == null) { - Log.Debug("Nothing to capture found"); - return null; - } + /// Helper method which will retrieve the IHTMLDocument2 for the supplied window, + /// or return the first if none is supplied. + ///
+ /// The WindowDetails to get the IHTMLDocument2 for + /// The WindowDetails to which the IHTMLDocument2 belongs + private static DocumentContainer CreateDocumentContainer(WindowDetails browserWindow) + { + DocumentContainer returnDocumentContainer = null; + WindowDetails returnWindow = null; + IHTMLDocument2 returnDocument2 = null; + // alternative if no match + WindowDetails alternativeReturnWindow = null; + IHTMLDocument2 alternativeReturnDocument2 = null; - try { - Log.DebugFormat("Window class {0}", documentContainer.ContentWindow.ClassName); - Log.DebugFormat("Window location {0}", documentContainer.ContentWindow.Location); - } catch (Exception ex) { - Log.Warn("Error while logging information.", ex); - } + // Find the IE windows + foreach (WindowDetails ieWindow in GetIeWindows()) + { + Log.DebugFormat("Processing {0} - {1}", ieWindow.ClassName, ieWindow.Text); - // bitmap to return - Bitmap returnBitmap = null; - try { - Size pageSize = PrepareCapture(documentContainer, capture); - returnBitmap = CapturePage(documentContainer, pageSize); - } catch (Exception captureException) { - Log.Error("Exception found, ignoring and returning nothing! Error was: ", captureException); - } - // TODO: Enable when the elements are usable again. - // Capture the element on the page - //try { - // if (CoreConfig.IEFieldCapture && capture.CaptureDetails.HasDestination("Editor")) { - // // clear the current elements, as they are for the window itself - // capture.Elements.Clear(); - // CaptureElement documentCaptureElement = documentContainer.CreateCaptureElements(pageSize); - // foreach(DocumentContainer frameDocument in documentContainer.Frames) { - // try { - // CaptureElement frameCaptureElement = frameDocument.CreateCaptureElements(Size.Empty); - // if (frameCaptureElement != null) { - // documentCaptureElement.Children.Add(frameCaptureElement); - // } - // } catch (Exception ex) { - // LOG.Warn("An error occurred while creating the capture elements: ", ex); - // } - // } - // capture.AddElement(documentCaptureElement); - // // Offset the elements, as they are "back offseted" later... - // Point windowLocation = documentContainer.ContentWindow.WindowRectangle.Location; - // capture.MoveElements(-(capture.ScreenBounds.Location.X-windowLocation.X), -(capture.ScreenBounds.Location.Y-windowLocation.Y)); - // } - //} catch (Exception elementsException) { - // LOG.Warn("An error occurred while creating the capture elements: ", elementsException); - //} - - - if (returnBitmap == null) { - return null; - } - - // Store the bitmap for further processing - capture.Image = returnBitmap; - try { - // Store the location of the window - capture.Location = documentContainer.ContentWindow.Location; + Accessible ieAccessible = null; + WindowDetails directUiwd = IEHelper.GetDirectUI(ieWindow); + if (directUiwd != null) + { + ieAccessible = new Accessible(directUiwd.Handle); + } - // The URL is available unter "document2.url" and can be used to enhance the meta-data etc. - capture.CaptureDetails.AddMetaData("url", documentContainer.Url); - // Store the title of the page - capture.CaptureDetails.Title = documentContainer.Name ?? windowToCapture.Text; - } catch (Exception ex) { - Log.Warn("Problems getting some attributes...", ex); - } + if (ieAccessible == null) + { + if (browserWindow != null) + { + Log.InfoFormat("Active Window is {0}", browserWindow.Text); + } - // Store the URL of the page - if (documentContainer.Url != null) { - try { - Uri uri = new Uri(documentContainer.Url); - capture.CaptureDetails.AddMetaData("URL", uri.OriginalString); - // As the URL can hardly be used in a filename, the following can be used - if (!string.IsNullOrEmpty(uri.Scheme)) { - capture.CaptureDetails.AddMetaData("URL_SCHEME", uri.Scheme); - } - if (!string.IsNullOrEmpty(uri.DnsSafeHost)) { - capture.CaptureDetails.AddMetaData("URL_HOSTNAME", uri.DnsSafeHost); - } - if (!string.IsNullOrEmpty(uri.AbsolutePath)) { - capture.CaptureDetails.AddMetaData("URL_PATH", uri.AbsolutePath); - } - if (!string.IsNullOrEmpty(uri.Query)) { - capture.CaptureDetails.AddMetaData("URL_QUERY", uri.Query); - } - if (!string.IsNullOrEmpty(uri.UserInfo)) { - capture.CaptureDetails.AddMetaData("URL_USER", uri.UserInfo); - } - capture.CaptureDetails.AddMetaData("URL_PORT", uri.Port.ToString()); - } catch(Exception e) { - Log.Warn("Exception when trying to use url in metadata "+documentContainer.Url,e); - } - } - try { - // Only move the mouse to correct for the capture offset - capture.MoveMouseLocation(-documentContainer.ViewportRectangle.X, -documentContainer.ViewportRectangle.Y); - // Used to be: capture.MoveMouseLocation(-(capture.Location.X + documentContainer.CaptureOffset.X), -(capture.Location.Y + documentContainer.CaptureOffset.Y)); - } catch (Exception ex) { - Log.Warn("Error while correcting the mouse offset.", ex); - } - } finally { - // Always close the background form - backgroundForm.CloseDialog(); - } - return capture; - } - - /// - /// Prepare the calculates for all the frames, move and fit... - /// - /// - /// - /// Size of the complete page - private static Size PrepareCapture(DocumentContainer documentContainer, ICapture capture) { - // Calculate the page size - int pageWidth = documentContainer.ScrollWidth; - int pageHeight = documentContainer.ScrollHeight; + if (!ieWindow.Equals(browserWindow)) + { + Log.WarnFormat("No ieAccessible for {0}", ieWindow.Text); + continue; + } - // Here we loop over all the frames and try to make sure they don't overlap - bool movedFrame; - do { - movedFrame = false; - foreach(DocumentContainer currentFrame in documentContainer.Frames) { - foreach(DocumentContainer otherFrame in documentContainer.Frames) { - if (otherFrame.Id == currentFrame.Id) { - continue; - } - // check if we need to move - if (!otherFrame.DestinationRectangle.IntersectsWith(currentFrame.DestinationRectangle) || - otherFrame.SourceRectangle.IntersectsWith(currentFrame.SourceRectangle)) continue; - - bool horizontalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; - bool verticalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; - bool horizontalMove = currentFrame.SourceLeft < currentFrame.DestinationLeft; - bool verticalMove = currentFrame.SourceTop < currentFrame.DestinationTop; - bool leftOf = currentFrame.SourceRight <= otherFrame.SourceLeft; - bool belowOf = currentFrame.SourceBottom <= otherFrame.SourceTop; - - if ((horizontalResize || horizontalMove) && leftOf) { - // Current frame resized horizontally, so move other horizontally - Log.DebugFormat("Moving Frame {0} horizontally to the right of {1}", otherFrame.Name, currentFrame.Name); - otherFrame.DestinationLeft = currentFrame.DestinationRight; - movedFrame = true; - } else if ((verticalResize || verticalMove) && belowOf){ - // Current frame resized vertically, so move other vertically - Log.DebugFormat("Moving Frame {0} vertically to the bottom of {1}", otherFrame.Name, currentFrame.Name); - otherFrame.DestinationTop = currentFrame.DestinationBottom; - movedFrame = true; - } else { - Log.DebugFormat("Frame {0} intersects with {1}", otherFrame.Name, currentFrame.Name); - } - } - } - } while(movedFrame); + Log.DebugFormat("No ieAccessible, but the active window is an IE window: {0}, ", ieWindow.Text); + } - bool movedMouse = false; - // Correct cursor location to be inside the window - capture.MoveMouseLocation(-documentContainer.ContentWindow.Location.X, -documentContainer.ContentWindow.Location.Y); - // See if the page has the correct size, as we capture the full frame content AND might have moved them - // the normal pageSize will no longer be enough - foreach(DocumentContainer frameData in documentContainer.Frames) { - if (!movedMouse && frameData.SourceRectangle.Contains(capture.CursorLocation)) { - // Correct mouse cursor location for scrolled position (so it shows on the capture where it really was) - capture.MoveMouseLocation(frameData.ScrollLeft, frameData.ScrollTop); - movedMouse = true; - // Apply any other offset changes - int offsetX = frameData.DestinationLocation.X - frameData.SourceLocation.X; - int offsetY = frameData.DestinationLocation.Y - frameData.SourceLocation.Y; - capture.MoveMouseLocation(offsetX, offsetY); - } + try + { + // Get the Document + IHTMLDocument2 document2 = GetHtmlDocument(ieWindow); + if (document2 == null) + { + continue; + } - //Get Frame Width & Height - pageWidth = Math.Max(pageWidth, frameData.DestinationRight); - pageHeight = Math.Max(pageHeight, frameData.DestinationBottom); - } - - // If the mouse hasn't been moved, it wasn't on a frame. So correct the mouse according to the scroll position of the document - if (!movedMouse) { - // Correct mouse cursor location - capture.MoveMouseLocation(documentContainer.ScrollLeft, documentContainer.ScrollTop); - } - - // Limit the size as the editor currently can't work with sizes > short.MaxValue - if (pageWidth > short.MaxValue) { - Log.WarnFormat("Capture has a width of {0} which bigger than the maximum supported {1}, cutting width to the maxium.", pageWidth, short.MaxValue); - pageWidth = Math.Min(pageWidth, short.MaxValue); - } - if (pageHeight > short.MaxValue) { - Log.WarnFormat("Capture has a height of {0} which bigger than the maximum supported {1}, cutting height to the maxium", pageHeight, short.MaxValue); - pageHeight = Math.Min(pageHeight, short.MaxValue); - } - return new Size(pageWidth, pageHeight); - } + // Get the content window handle for the shellWindow.Document + IOleWindow oleWindow = (IOleWindow) document2; + IntPtr contentWindowHandle = IntPtr.Zero; + oleWindow?.GetWindow(out contentWindowHandle); - /// - /// Capture the actual page (document) - /// - /// The document wrapped in a container - /// - /// Bitmap with the page content as an image - private static Bitmap CapturePage(DocumentContainer documentContainer, Size pageSize) { - WindowDetails contentWindowDetails = documentContainer.ContentWindow; + if (contentWindowHandle != IntPtr.Zero) + { + // Get the HTMLDocument to check the hasFocus + // See: http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/60c6c95d-377c-4bf4-860d-390840fce31c/ + IHTMLDocument4 document4 = (IHTMLDocument4) document2; - //Create a target bitmap to draw into with the calculated page size - Bitmap returnBitmap = new Bitmap(pageSize.Width, pageSize.Height, PixelFormat.Format24bppRgb); - using (Graphics graphicsTarget = Graphics.FromImage(returnBitmap)) { - // Clear the target with the backgroundcolor - Color clearColor = documentContainer.BackgroundColor; - Log.DebugFormat("Clear color: {0}", clearColor); - graphicsTarget.Clear(clearColor); + if (document4.hasFocus()) + { + Log.DebugFormat("Matched focused document: {0}", document2.title); + // Look no further, we got what we wanted! + returnDocument2 = document2; + returnWindow = new WindowDetails(contentWindowHandle); + break; + } - // Get the base document & draw it - DrawDocument(documentContainer, contentWindowDetails, graphicsTarget); - - // Loop over the frames and clear their source area so we don't see any artefacts - foreach(DocumentContainer frameDocument in documentContainer.Frames) + try + { + if (ieWindow.Equals(browserWindow)) + { + returnDocument2 = document2; + returnWindow = new WindowDetails(contentWindowHandle); + break; + } + + if (ieAccessible != null && returnWindow == null && document2.title.Equals(ieAccessible.IEActiveTabCaption)) + { + Log.DebugFormat("Title: {0}", document2.title); + returnDocument2 = document2; + returnWindow = new WindowDetails(contentWindowHandle); + } + else + { + alternativeReturnDocument2 = document2; + alternativeReturnWindow = new WindowDetails(contentWindowHandle); + } + } + catch (Exception) + { + alternativeReturnDocument2 = document2; + alternativeReturnWindow = new WindowDetails(contentWindowHandle); + } + } + } + catch (Exception e) + { + Log.ErrorFormat("Major problem: Problem retrieving Document from {0}", ieWindow.Text); + Log.Error(e); + } + } + + // check if we have something to return + if (returnWindow != null) + { + // As it doesn't have focus, make sure it's active + returnWindow.Restore(); + returnWindow.GetParent(); + + // Create the container + try + { + returnDocumentContainer = new DocumentContainer(returnDocument2, returnWindow); + } + catch (Exception e) + { + Log.Error("Major problem: Problem retrieving Document."); + Log.Error(e); + } + } + + if (returnDocumentContainer == null && alternativeReturnDocument2 != null) + { + // As it doesn't have focus, make sure it's active + alternativeReturnWindow.Restore(); + alternativeReturnWindow.GetParent(); + // Create the container + try + { + returnDocumentContainer = new DocumentContainer(alternativeReturnDocument2, alternativeReturnWindow); + } + catch (Exception e) + { + Log.Error("Major problem: Problem retrieving Document."); + Log.Error(e); + } + } + + return returnDocumentContainer; + } + + /// + /// Here the logic for capturing the IE Content is located + /// + /// ICapture where the capture needs to be stored + /// window to use + /// ICapture with the content (if any) + public static ICapture CaptureIe(ICapture capture, WindowDetails windowToCapture) + { + windowToCapture ??= WindowDetails.GetActiveWindow(); + + // Show backgroundform after retrieving the active window.. + BackgroundForm backgroundForm = new BackgroundForm(Language.GetString(LangKey.contextmenu_captureie), Language.GetString(LangKey.wait_ie_capture)); + backgroundForm.Show(); + //BackgroundForm backgroundForm = BackgroundForm.ShowAndWait(language.GetString(LangKey.contextmenu_captureie), language.GetString(LangKey.wait_ie_capture)); + try + { + //Get IHTMLDocument2 for the current active window + DocumentContainer documentContainer = CreateDocumentContainer(windowToCapture); + + // Nothing found + if (documentContainer == null) + { + Log.Debug("Nothing to capture found"); + return null; + } + + try + { + Log.DebugFormat("Window class {0}", documentContainer.ContentWindow.ClassName); + Log.DebugFormat("Window location {0}", documentContainer.ContentWindow.Location); + } + catch (Exception ex) + { + Log.Warn("Error while logging information.", ex); + } + + // bitmap to return + Bitmap returnBitmap = null; + try + { + Size pageSize = PrepareCapture(documentContainer, capture); + returnBitmap = CapturePage(documentContainer, pageSize); + } + catch (Exception captureException) + { + Log.Error("Exception found, ignoring and returning nothing! Error was: ", captureException); + } + // TODO: Enable when the elements are usable again. + // Capture the element on the page + //try { + // if (CoreConfig.IEFieldCapture && capture.CaptureDetails.HasDestination("Editor")) { + // // clear the current elements, as they are for the window itself + // capture.Elements.Clear(); + // CaptureElement documentCaptureElement = documentContainer.CreateCaptureElements(pageSize); + // foreach(DocumentContainer frameDocument in documentContainer.Frames) { + // try { + // CaptureElement frameCaptureElement = frameDocument.CreateCaptureElements(Size.Empty); + // if (frameCaptureElement != null) { + // documentCaptureElement.Children.Add(frameCaptureElement); + // } + // } catch (Exception ex) { + // LOG.Warn("An error occurred while creating the capture elements: ", ex); + // } + // } + // capture.AddElement(documentCaptureElement); + // // Offset the elements, as they are "back offseted" later... + // Point windowLocation = documentContainer.ContentWindow.WindowRectangle.Location; + // capture.MoveElements(-(capture.ScreenBounds.Location.X-windowLocation.X), -(capture.ScreenBounds.Location.Y-windowLocation.Y)); + // } + //} catch (Exception elementsException) { + // LOG.Warn("An error occurred while creating the capture elements: ", elementsException); + //} + + + if (returnBitmap == null) + { + return null; + } + + // Store the bitmap for further processing + capture.Image = returnBitmap; + try + { + // Store the location of the window + capture.Location = documentContainer.ContentWindow.Location; + + // The URL is available unter "document2.url" and can be used to enhance the meta-data etc. + capture.CaptureDetails.AddMetaData("url", documentContainer.Url); + // Store the title of the page + capture.CaptureDetails.Title = documentContainer.Name ?? windowToCapture.Text; + } + catch (Exception ex) + { + Log.Warn("Problems getting some attributes...", ex); + } + + // Store the URL of the page + if (documentContainer.Url != null) + { + try + { + Uri uri = new Uri(documentContainer.Url); + capture.CaptureDetails.AddMetaData("URL", uri.OriginalString); + // As the URL can hardly be used in a filename, the following can be used + if (!string.IsNullOrEmpty(uri.Scheme)) + { + capture.CaptureDetails.AddMetaData("URL_SCHEME", uri.Scheme); + } + + if (!string.IsNullOrEmpty(uri.DnsSafeHost)) + { + capture.CaptureDetails.AddMetaData("URL_HOSTNAME", uri.DnsSafeHost); + } + + if (!string.IsNullOrEmpty(uri.AbsolutePath)) + { + capture.CaptureDetails.AddMetaData("URL_PATH", uri.AbsolutePath); + } + + if (!string.IsNullOrEmpty(uri.Query)) + { + capture.CaptureDetails.AddMetaData("URL_QUERY", uri.Query); + } + + if (!string.IsNullOrEmpty(uri.UserInfo)) + { + capture.CaptureDetails.AddMetaData("URL_USER", uri.UserInfo); + } + + capture.CaptureDetails.AddMetaData("URL_PORT", uri.Port.ToString()); + } + catch (Exception e) + { + Log.Warn("Exception when trying to use url in metadata " + documentContainer.Url, e); + } + } + + try + { + // Only move the mouse to correct for the capture offset + capture.MoveMouseLocation(-documentContainer.ViewportRectangle.X, -documentContainer.ViewportRectangle.Y); + // Used to be: capture.MoveMouseLocation(-(capture.Location.X + documentContainer.CaptureOffset.X), -(capture.Location.Y + documentContainer.CaptureOffset.Y)); + } + catch (Exception ex) + { + Log.Warn("Error while correcting the mouse offset.", ex); + } + } + finally + { + // Always close the background form + backgroundForm.CloseDialog(); + } + + return capture; + } + + /// + /// Prepare the calculates for all the frames, move and fit... + /// + /// + /// + /// Size of the complete page + private static Size PrepareCapture(DocumentContainer documentContainer, ICapture capture) + { + // Calculate the page size + int pageWidth = documentContainer.ScrollWidth; + int pageHeight = documentContainer.ScrollHeight; + + // Here we loop over all the frames and try to make sure they don't overlap + bool movedFrame; + do + { + movedFrame = false; + foreach (DocumentContainer currentFrame in documentContainer.Frames) + { + foreach (DocumentContainer otherFrame in documentContainer.Frames) + { + if (otherFrame.Id == currentFrame.Id) + { + continue; + } + + // check if we need to move + if (!otherFrame.DestinationRectangle.IntersectsWith(currentFrame.DestinationRectangle) || + otherFrame.SourceRectangle.IntersectsWith(currentFrame.SourceRectangle)) continue; + + bool horizontalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; + bool verticalResize = currentFrame.SourceSize.Width < currentFrame.DestinationSize.Width; + bool horizontalMove = currentFrame.SourceLeft < currentFrame.DestinationLeft; + bool verticalMove = currentFrame.SourceTop < currentFrame.DestinationTop; + bool leftOf = currentFrame.SourceRight <= otherFrame.SourceLeft; + bool belowOf = currentFrame.SourceBottom <= otherFrame.SourceTop; + + if ((horizontalResize || horizontalMove) && leftOf) + { + // Current frame resized horizontally, so move other horizontally + Log.DebugFormat("Moving Frame {0} horizontally to the right of {1}", otherFrame.Name, currentFrame.Name); + otherFrame.DestinationLeft = currentFrame.DestinationRight; + movedFrame = true; + } + else if ((verticalResize || verticalMove) && belowOf) + { + // Current frame resized vertically, so move other vertically + Log.DebugFormat("Moving Frame {0} vertically to the bottom of {1}", otherFrame.Name, currentFrame.Name); + otherFrame.DestinationTop = currentFrame.DestinationBottom; + movedFrame = true; + } + else + { + Log.DebugFormat("Frame {0} intersects with {1}", otherFrame.Name, currentFrame.Name); + } + } + } + } while (movedFrame); + + bool movedMouse = false; + // Correct cursor location to be inside the window + capture.MoveMouseLocation(-documentContainer.ContentWindow.Location.X, -documentContainer.ContentWindow.Location.Y); + // See if the page has the correct size, as we capture the full frame content AND might have moved them + // the normal pageSize will no longer be enough + foreach (DocumentContainer frameData in documentContainer.Frames) + { + if (!movedMouse && frameData.SourceRectangle.Contains(capture.CursorLocation)) + { + // Correct mouse cursor location for scrolled position (so it shows on the capture where it really was) + capture.MoveMouseLocation(frameData.ScrollLeft, frameData.ScrollTop); + movedMouse = true; + // Apply any other offset changes + int offsetX = frameData.DestinationLocation.X - frameData.SourceLocation.X; + int offsetY = frameData.DestinationLocation.Y - frameData.SourceLocation.Y; + capture.MoveMouseLocation(offsetX, offsetY); + } + + //Get Frame Width & Height + pageWidth = Math.Max(pageWidth, frameData.DestinationRight); + pageHeight = Math.Max(pageHeight, frameData.DestinationBottom); + } + + // If the mouse hasn't been moved, it wasn't on a frame. So correct the mouse according to the scroll position of the document + if (!movedMouse) + { + // Correct mouse cursor location + capture.MoveMouseLocation(documentContainer.ScrollLeft, documentContainer.ScrollTop); + } + + // Limit the size as the editor currently can't work with sizes > short.MaxValue + if (pageWidth > short.MaxValue) + { + Log.WarnFormat("Capture has a width of {0} which bigger than the maximum supported {1}, cutting width to the maxium.", pageWidth, short.MaxValue); + pageWidth = Math.Min(pageWidth, short.MaxValue); + } + + if (pageHeight > short.MaxValue) + { + Log.WarnFormat("Capture has a height of {0} which bigger than the maximum supported {1}, cutting height to the maxium", pageHeight, short.MaxValue); + pageHeight = Math.Min(pageHeight, short.MaxValue); + } + + return new Size(pageWidth, pageHeight); + } + + /// + /// Capture the actual page (document) + /// + /// The document wrapped in a container + /// + /// Bitmap with the page content as an image + private static Bitmap CapturePage(DocumentContainer documentContainer, Size pageSize) + { + WindowDetails contentWindowDetails = documentContainer.ContentWindow; + + //Create a target bitmap to draw into with the calculated page size + Bitmap returnBitmap = new Bitmap(pageSize.Width, pageSize.Height, PixelFormat.Format24bppRgb); + using (Graphics graphicsTarget = Graphics.FromImage(returnBitmap)) + { + // Clear the target with the backgroundcolor + Color clearColor = documentContainer.BackgroundColor; + Log.DebugFormat("Clear color: {0}", clearColor); + graphicsTarget.Clear(clearColor); + + // Get the base document & draw it + DrawDocument(documentContainer, contentWindowDetails, graphicsTarget); + + // Loop over the frames and clear their source area so we don't see any artefacts + foreach (DocumentContainer frameDocument in documentContainer.Frames) { using Brush brush = new SolidBrush(clearColor); graphicsTarget.FillRectangle(brush, frameDocument.SourceRectangle); } - // Loop over the frames and capture their content - foreach(DocumentContainer frameDocument in documentContainer.Frames) { - DrawDocument(frameDocument, contentWindowDetails, graphicsTarget); - } - } - return returnBitmap; - } - /// - /// This method takes the actual capture of the document (frame) - /// - /// DocumentContainer - /// Needed for referencing the location of the frame - /// Graphics - /// Bitmap with the capture - private static void DrawDocument(DocumentContainer documentContainer, WindowDetails contentWindowDetails, Graphics graphicsTarget) { - documentContainer.SetAttribute("scroll", 1); + // Loop over the frames and capture their content + foreach (DocumentContainer frameDocument in documentContainer.Frames) + { + DrawDocument(frameDocument, contentWindowDetails, graphicsTarget); + } + } - //Get Browser Window Width & Height - int pageWidth = documentContainer.ScrollWidth; - int pageHeight = documentContainer.ScrollHeight; - if (pageWidth * pageHeight == 0) { - Log.WarnFormat("Empty page for DocumentContainer {0}: {1}", documentContainer.Name, documentContainer.Url); - return; - } + return returnBitmap; + } - //Get Screen Width & Height (this is better as the WindowDetails.ClientRectangle as the real visible parts are there! - int viewportWidth = documentContainer.ClientWidth; - int viewportHeight = documentContainer.ClientHeight; - if (viewportWidth * viewportHeight == 0) { - Log.WarnFormat("Empty viewport for DocumentContainer {0}: {1}", documentContainer.Name, documentContainer.Url); - return; - } + /// + /// This method takes the actual capture of the document (frame) + /// + /// DocumentContainer + /// Needed for referencing the location of the frame + /// Graphics + /// Bitmap with the capture + private static void DrawDocument(DocumentContainer documentContainer, WindowDetails contentWindowDetails, Graphics graphicsTarget) + { + documentContainer.SetAttribute("scroll", 1); - // Store the current location so we can set the browser back and use it for the mouse cursor - int startLeft = documentContainer.ScrollLeft; - int startTop = documentContainer.ScrollTop; + //Get Browser Window Width & Height + int pageWidth = documentContainer.ScrollWidth; + int pageHeight = documentContainer.ScrollHeight; + if (pageWidth * pageHeight == 0) + { + Log.WarnFormat("Empty page for DocumentContainer {0}: {1}", documentContainer.Name, documentContainer.Url); + return; + } - Log.DebugFormat("Capturing {4} with total size {0},{1} displayed with size {2},{3}", pageWidth, pageHeight, viewportWidth, viewportHeight, documentContainer.Name); + //Get Screen Width & Height (this is better as the WindowDetails.ClientRectangle as the real visible parts are there! + int viewportWidth = documentContainer.ClientWidth; + int viewportHeight = documentContainer.ClientHeight; + if (viewportWidth * viewportHeight == 0) + { + Log.WarnFormat("Empty viewport for DocumentContainer {0}: {1}", documentContainer.Name, documentContainer.Url); + return; + } - // Variable used for looping horizontally - int horizontalPage = 0; - - // The location of the browser, used as the destination into the bitmap target - Point targetOffset = new Point(); - - // Loop of the pages and make a copy of the visible viewport - while (horizontalPage * viewportWidth < pageWidth) { - // Scroll to location - documentContainer.ScrollLeft = viewportWidth * horizontalPage; - targetOffset.X = documentContainer.ScrollLeft; + // Store the current location so we can set the browser back and use it for the mouse cursor + int startLeft = documentContainer.ScrollLeft; + int startTop = documentContainer.ScrollTop; - // Variable used for looping vertically - int verticalPage = 0; - while (verticalPage * viewportHeight < pageHeight) { - // Scroll to location - documentContainer.ScrollTop = viewportHeight * verticalPage; - //Shoot visible window - targetOffset.Y = documentContainer.ScrollTop; + Log.DebugFormat("Capturing {4} with total size {0},{1} displayed with size {2},{3}", pageWidth, pageHeight, viewportWidth, viewportHeight, documentContainer.Name); - // Draw the captured fragment to the target, but "crop" the scrollbars etc while capturing - Size viewPortSize = new Size(viewportWidth, viewportHeight); - Rectangle clientRectangle = new Rectangle(documentContainer.SourceLocation, viewPortSize); - Image fragment = contentWindowDetails.PrintWindow(); - if (fragment != null) { - Log.DebugFormat("Captured fragment size: {0}x{1}", fragment.Width, fragment.Height); - try { - // cut all junk, due to IE "border" we need to remove some parts - Rectangle viewportRect = documentContainer.ViewportRectangle; - if (!viewportRect.IsEmpty) { - Log.DebugFormat("Cropping to viewport: {0}", viewportRect); - ImageHelper.Crop(ref fragment, ref viewportRect); - } - Log.DebugFormat("Cropping to clientRectangle: {0}", clientRectangle); - // Crop to clientRectangle - if (ImageHelper.Crop(ref fragment, ref clientRectangle)) { - Point targetLocation = new Point(documentContainer.DestinationLocation.X, documentContainer.DestinationLocation.Y); - Log.DebugFormat("Fragment targetLocation is {0}", targetLocation); - targetLocation.Offset(targetOffset); - Log.DebugFormat("After offsetting the fragment targetLocation is {0}", targetLocation); - Log.DebugFormat("Drawing fragment of size {0} to {1}", fragment.Size, targetLocation); - graphicsTarget.DrawImage(fragment, targetLocation); - graphicsTarget.Flush(); - } else { - // somehow we are capturing nothing!? - Log.WarnFormat("Crop of {0} failed?", documentContainer.Name); - break; - } - } finally { - fragment.Dispose(); - } - } else { - Log.WarnFormat("Capture of {0} failed!", documentContainer.Name); - } - verticalPage++; - } - horizontalPage++; - } - // Return to where we were - documentContainer.ScrollLeft = startLeft; - documentContainer.ScrollTop = startTop; - } - } -} + // Variable used for looping horizontally + int horizontalPage = 0; + + // The location of the browser, used as the destination into the bitmap target + Point targetOffset = new Point(); + + // Loop of the pages and make a copy of the visible viewport + while (horizontalPage * viewportWidth < pageWidth) + { + // Scroll to location + documentContainer.ScrollLeft = viewportWidth * horizontalPage; + targetOffset.X = documentContainer.ScrollLeft; + + // Variable used for looping vertically + int verticalPage = 0; + while (verticalPage * viewportHeight < pageHeight) + { + // Scroll to location + documentContainer.ScrollTop = viewportHeight * verticalPage; + //Shoot visible window + targetOffset.Y = documentContainer.ScrollTop; + + // Draw the captured fragment to the target, but "crop" the scrollbars etc while capturing + Size viewPortSize = new Size(viewportWidth, viewportHeight); + Rectangle clientRectangle = new Rectangle(documentContainer.SourceLocation, viewPortSize); + Image fragment = contentWindowDetails.PrintWindow(); + if (fragment != null) + { + Log.DebugFormat("Captured fragment size: {0}x{1}", fragment.Width, fragment.Height); + try + { + // cut all junk, due to IE "border" we need to remove some parts + Rectangle viewportRect = documentContainer.ViewportRectangle; + if (!viewportRect.IsEmpty) + { + Log.DebugFormat("Cropping to viewport: {0}", viewportRect); + ImageHelper.Crop(ref fragment, ref viewportRect); + } + + Log.DebugFormat("Cropping to clientRectangle: {0}", clientRectangle); + // Crop to clientRectangle + if (ImageHelper.Crop(ref fragment, ref clientRectangle)) + { + Point targetLocation = new Point(documentContainer.DestinationLocation.X, documentContainer.DestinationLocation.Y); + Log.DebugFormat("Fragment targetLocation is {0}", targetLocation); + targetLocation.Offset(targetOffset); + Log.DebugFormat("After offsetting the fragment targetLocation is {0}", targetLocation); + Log.DebugFormat("Drawing fragment of size {0} to {1}", fragment.Size, targetLocation); + graphicsTarget.DrawImage(fragment, targetLocation); + graphicsTarget.Flush(); + } + else + { + // somehow we are capturing nothing!? + Log.WarnFormat("Crop of {0} failed?", documentContainer.Name); + break; + } + } + finally + { + fragment.Dispose(); + } + } + else + { + Log.WarnFormat("Capture of {0} failed!", documentContainer.Name); + } + + verticalPage++; + } + + horizontalPage++; + } + + // Return to where we were + documentContainer.ScrollLeft = startLeft; + documentContainer.ScrollTop = startTop; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/IEInterop/IEContainer.cs b/src/Greenshot/Helpers/IEInterop/IEContainer.cs index 824cf3fa9..cfae1481e 100644 --- a/src/Greenshot/Helpers/IEInterop/IEContainer.cs +++ b/src/Greenshot/Helpers/IEInterop/IEContainer.cs @@ -18,485 +18,559 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.Runtime.InteropServices; - using GreenshotPlugin.Core; using GreenshotPlugin.IEInterop; using log4net; using IServiceProvider = GreenshotPlugin.Interop.IServiceProvider; -namespace Greenshot.Helpers.IEInterop { - public class DocumentContainer { - private static readonly ILog LOG = LogManager.GetLogger(typeof(DocumentContainer)); - private const int E_ACCESSDENIED = unchecked((int)0x80070005L); - private static readonly Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046"); - private static readonly Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"); - private static int _counter; - private IHTMLDocument2 _document2; - private IHTMLDocument3 _document3; - private Point _sourceLocation; - private Point _destinationLocation; - private Point _startLocation = Point.Empty; - private Rectangle _viewportRectangle = Rectangle.Empty; - private bool _isDtd; - private DocumentContainer _parent; - private WindowDetails _contentWindow; - private double _zoomLevelX = 1; - private double _zoomLevelY = 1; - private readonly IList _frames = new List(); +namespace Greenshot.Helpers.IEInterop +{ + public class DocumentContainer + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(DocumentContainer)); + private const int E_ACCESSDENIED = unchecked((int) 0x80070005L); + private static readonly Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046"); + private static readonly Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"); + private static int _counter; + private IHTMLDocument2 _document2; + private IHTMLDocument3 _document3; + private Point _sourceLocation; + private Point _destinationLocation; + private Point _startLocation = Point.Empty; + private Rectangle _viewportRectangle = Rectangle.Empty; + private bool _isDtd; + private DocumentContainer _parent; + private WindowDetails _contentWindow; + private double _zoomLevelX = 1; + private double _zoomLevelY = 1; + private readonly IList _frames = new List(); - private DocumentContainer(IHTMLWindow2 frameWindow, WindowDetails contentWindow, DocumentContainer parent) { - //IWebBrowser2 webBrowser2 = frame as IWebBrowser2; - //IHTMLDocument2 document2 = webBrowser2.Document as IHTMLDocument2; - IHTMLDocument2 document2 = GetDocumentFromWindow(frameWindow); - try { - LOG.DebugFormat("frameWindow.name {0}", frameWindow.name); - Name = frameWindow.name; - } catch { - // Ignore - } - try { - LOG.DebugFormat("document2.url {0}",document2.url); - } catch { - // Ignore - } - try { - LOG.DebugFormat("document2.title {0}", document2.title); - } catch { - // Ignore - } + private DocumentContainer(IHTMLWindow2 frameWindow, WindowDetails contentWindow, DocumentContainer parent) + { + //IWebBrowser2 webBrowser2 = frame as IWebBrowser2; + //IHTMLDocument2 document2 = webBrowser2.Document as IHTMLDocument2; + IHTMLDocument2 document2 = GetDocumentFromWindow(frameWindow); + try + { + LOG.DebugFormat("frameWindow.name {0}", frameWindow.name); + Name = frameWindow.name; + } + catch + { + // Ignore + } - _parent = parent; - // Calculate startLocation for the frames - IHTMLWindow2 window2 = document2.parentWindow; - IHTMLWindow3 window3 = (IHTMLWindow3)window2; - Point contentWindowLocation = contentWindow.WindowRectangle.Location; - int x = window3.screenLeft - contentWindowLocation.X; - int y = window3.screenTop - contentWindowLocation.Y; + try + { + LOG.DebugFormat("document2.url {0}", document2.url); + } + catch + { + // Ignore + } - // Release IHTMLWindow 2+3 com objects - releaseCom(window2); - releaseCom(window3); + try + { + LOG.DebugFormat("document2.title {0}", document2.title); + } + catch + { + // Ignore + } - _startLocation = new Point(x, y); - Init(document2, contentWindow); - } + _parent = parent; + // Calculate startLocation for the frames + IHTMLWindow2 window2 = document2.parentWindow; + IHTMLWindow3 window3 = (IHTMLWindow3) window2; + Point contentWindowLocation = contentWindow.WindowRectangle.Location; + int x = window3.screenLeft - contentWindowLocation.X; + int y = window3.screenTop - contentWindowLocation.Y; - public DocumentContainer(IHTMLDocument2 document2, WindowDetails contentWindow) { - Init(document2, contentWindow); - LOG.DebugFormat("Creating DocumentContainer for Document {0} found in window with rectangle {1}", Name, SourceRectangle); - } + // Release IHTMLWindow 2+3 com objects + releaseCom(window2); + releaseCom(window3); - /// - /// Helper method to release com objects - /// - /// - private void releaseCom(object comObject) { - if (comObject != null) { - Marshal.ReleaseComObject(comObject); - } - } + _startLocation = new Point(x, y); + Init(document2, contentWindow); + } - /// - /// Private helper method for the constructors - /// - /// IHTMLDocument2 - /// WindowDetails - private void Init(IHTMLDocument2 document2, WindowDetails contentWindow) { - _document2 = document2; - _contentWindow = contentWindow; - _document3 = document2 as IHTMLDocument3; - // Check what access method is needed for the document - IHTMLDocument5 document5 = (IHTMLDocument5)document2; + public DocumentContainer(IHTMLDocument2 document2, WindowDetails contentWindow) + { + Init(document2, contentWindow); + LOG.DebugFormat("Creating DocumentContainer for Document {0} found in window with rectangle {1}", Name, SourceRectangle); + } - //compatibility mode affects how height is computed - _isDtd = false; - try { - if (_document3?.documentElement != null && !document5.compatMode.Equals("BackCompat")) { - _isDtd = true; - } - } catch (Exception ex) { - LOG.Error("Error checking the compatibility mode:"); - LOG.Error(ex); - } - // Do not release IHTMLDocument5 com object, as this also gives problems with the document2! - //Marshal.ReleaseComObject(document5); + /// + /// Helper method to release com objects + /// + /// + private void releaseCom(object comObject) + { + if (comObject != null) + { + Marshal.ReleaseComObject(comObject); + } + } - Rectangle clientRectangle = contentWindow.WindowRectangle; - try { - IHTMLWindow2 window2 = document2.parentWindow; - //IHTMLWindow3 window3 = (IHTMLWindow3)document2.parentWindow; - IHTMLScreen screen = window2.screen; - IHTMLScreen2 screen2 = (IHTMLScreen2)screen; - if (_parent != null) { - // Copy parent values - _zoomLevelX = _parent._zoomLevelX; - _zoomLevelY = _parent._zoomLevelY; - _viewportRectangle = _parent._viewportRectangle; - } else { - //DisableScrollbars(document2); + /// + /// Private helper method for the constructors + /// + /// IHTMLDocument2 + /// WindowDetails + private void Init(IHTMLDocument2 document2, WindowDetails contentWindow) + { + _document2 = document2; + _contentWindow = contentWindow; + _document3 = document2 as IHTMLDocument3; + // Check what access method is needed for the document + IHTMLDocument5 document5 = (IHTMLDocument5) document2; - // Calculate zoom level - _zoomLevelX = screen2.deviceXDPI/(double)screen2.logicalXDPI; - _zoomLevelY = screen2.deviceYDPI/(double)screen2.logicalYDPI; + //compatibility mode affects how height is computed + _isDtd = false; + try + { + if (_document3?.documentElement != null && !document5.compatMode.Equals("BackCompat")) + { + _isDtd = true; + } + } + catch (Exception ex) + { + LOG.Error("Error checking the compatibility mode:"); + LOG.Error(ex); + } + // Do not release IHTMLDocument5 com object, as this also gives problems with the document2! + //Marshal.ReleaseComObject(document5); + + Rectangle clientRectangle = contentWindow.WindowRectangle; + try + { + IHTMLWindow2 window2 = document2.parentWindow; + //IHTMLWindow3 window3 = (IHTMLWindow3)document2.parentWindow; + IHTMLScreen screen = window2.screen; + IHTMLScreen2 screen2 = (IHTMLScreen2) screen; + if (_parent != null) + { + // Copy parent values + _zoomLevelX = _parent._zoomLevelX; + _zoomLevelY = _parent._zoomLevelY; + _viewportRectangle = _parent._viewportRectangle; + } + else + { + //DisableScrollbars(document2); + + // Calculate zoom level + _zoomLevelX = screen2.deviceXDPI / (double) screen2.logicalXDPI; + _zoomLevelY = screen2.deviceYDPI / (double) screen2.logicalYDPI; - // Calculate the viewport rectangle, needed if there is a frame around the html window - LOG.DebugFormat("Screen {0}x{1}", ScaleX(screen.width), ScaleY(screen.height)); - //LOG.DebugFormat("Screen location {0},{1}", window3.screenLeft, window3.screenTop); - LOG.DebugFormat("Window rectangle {0}", clientRectangle); - LOG.DebugFormat("Client size {0}x{1}", ClientWidth, ClientHeight); - int diffX = clientRectangle.Width - ClientWidth; - int diffY = clientRectangle.Height - ClientHeight; - // If there is a border around the inner window, the diff == 4 - // If there is a border AND a scrollbar the diff == 20 - if ((diffX == 4 || diffX >= 20) && (diffY == 4 || diffY >= 20)) { - Point viewportOffset = new Point(2, 2); - Size viewportSize = new Size(ClientWidth, ClientHeight); - _viewportRectangle = new Rectangle(viewportOffset, viewportSize); - LOG.DebugFormat("viewportRect {0}", _viewportRectangle); - } - } - LOG.DebugFormat("Zoomlevel {0}, {1}", _zoomLevelX, _zoomLevelY); - // Release com objects - releaseCom(window2); - releaseCom(screen); - releaseCom(screen2); - } catch (Exception e) { - LOG.Warn("Can't get certain properties for documents, using default. Due to: ", e); - } + // Calculate the viewport rectangle, needed if there is a frame around the html window + LOG.DebugFormat("Screen {0}x{1}", ScaleX(screen.width), ScaleY(screen.height)); + //LOG.DebugFormat("Screen location {0},{1}", window3.screenLeft, window3.screenTop); + LOG.DebugFormat("Window rectangle {0}", clientRectangle); + LOG.DebugFormat("Client size {0}x{1}", ClientWidth, ClientHeight); + int diffX = clientRectangle.Width - ClientWidth; + int diffY = clientRectangle.Height - ClientHeight; + // If there is a border around the inner window, the diff == 4 + // If there is a border AND a scrollbar the diff == 20 + if ((diffX == 4 || diffX >= 20) && (diffY == 4 || diffY >= 20)) + { + Point viewportOffset = new Point(2, 2); + Size viewportSize = new Size(ClientWidth, ClientHeight); + _viewportRectangle = new Rectangle(viewportOffset, viewportSize); + LOG.DebugFormat("viewportRect {0}", _viewportRectangle); + } + } + + LOG.DebugFormat("Zoomlevel {0}, {1}", _zoomLevelX, _zoomLevelY); + // Release com objects + releaseCom(window2); + releaseCom(screen); + releaseCom(screen2); + } + catch (Exception e) + { + LOG.Warn("Can't get certain properties for documents, using default. Due to: ", e); + } - try { - LOG.DebugFormat("Calculated location {0} for {1}", _startLocation, document2.title); - if (Name == null) { - Name = document2.title; - } - } catch (Exception e) { - LOG.Warn("Problem while trying to get document title!", e); - } + try + { + LOG.DebugFormat("Calculated location {0} for {1}", _startLocation, document2.title); + if (Name == null) + { + Name = document2.title; + } + } + catch (Exception e) + { + LOG.Warn("Problem while trying to get document title!", e); + } - try { - Url = document2.url; - } catch (Exception e) { - LOG.Warn("Problem while trying to get document url!", e); - } - _sourceLocation = new Point(ScaleX(_startLocation.X), ScaleY(_startLocation.Y)); - _destinationLocation = new Point(ScaleX(_startLocation.X), ScaleY(_startLocation.Y)); - - if (_parent != null) { - return; - } - try { - IHTMLFramesCollection2 frameCollection = (IHTMLFramesCollection2)document2.frames; - for (int frame = 0; frame < frameCollection.length; frame++) { - try { - IHTMLWindow2 frameWindow = frameCollection.item(frame); - DocumentContainer frameData = new DocumentContainer(frameWindow, contentWindow, this); - // check if frame is hidden - if (!frameData.IsHidden) { - LOG.DebugFormat("Creating DocumentContainer for Frame {0} found in window with rectangle {1}", frameData.Name, frameData.SourceRectangle); - _frames.Add(frameData); - } else { - LOG.DebugFormat("Skipping frame {0}", frameData.Name); - } - // Clean up frameWindow - releaseCom(frameWindow); - } catch (Exception e) { - LOG.Warn("Problem while trying to get information from a frame, skipping the frame!", e); - } - } - // Clean up collection - releaseCom(frameCollection); - } catch (Exception ex) { - LOG.Warn("Problem while trying to get the frames, skipping!", ex); - } + try + { + Url = document2.url; + } + catch (Exception e) + { + LOG.Warn("Problem while trying to get document url!", e); + } - try { - // Correct iframe locations - foreach (IHTMLElement frameElement in _document3.getElementsByTagName("IFRAME")) { - try { - CorrectFrameLocations(frameElement); - // Clean up frameElement - releaseCom(frameElement); - } catch (Exception e) { - LOG.Warn("Problem while trying to get information from an iframe, skipping the frame!", e); - } - } - } catch (Exception ex) { - LOG.Warn("Problem while trying to get the iframes, skipping!", ex); - } - } - - /// - /// Corrent the frame locations with the information - /// - /// - private void CorrectFrameLocations(IHTMLElement frameElement) { - long x = 0; - long y = 0; - IHTMLElement element = frameElement; - IHTMLElement oldElement = null; - do { - x += element.offsetLeft; - y += element.offsetTop; - element = element.offsetParent; - // Release element, but prevent the frameElement to be released - if (oldElement != null) { - releaseCom(oldElement); - } - oldElement = element; - } while (element != null); + _sourceLocation = new Point(ScaleX(_startLocation.X), ScaleY(_startLocation.Y)); + _destinationLocation = new Point(ScaleX(_startLocation.X), ScaleY(_startLocation.Y)); - Point elementLocation = new Point((int)x, (int)y); - IHTMLElement2 element2 = (IHTMLElement2)frameElement; - IHTMLRect rec = element2.getBoundingClientRect(); - Point elementBoundingLocation = new Point(rec.left, rec.top); - // Release IHTMLRect - releaseCom(rec); - LOG.DebugFormat("Looking for iframe to correct at {0}", elementBoundingLocation); - foreach(DocumentContainer foundFrame in _frames) { - Point frameLocation = foundFrame.SourceLocation; - if (frameLocation.Equals(elementBoundingLocation)) { - // Match found, correcting location - LOG.DebugFormat("Correcting frame from {0} to {1}", frameLocation, elementLocation); - foundFrame.SourceLocation = elementLocation; - foundFrame.DestinationLocation = elementLocation; - } else { - LOG.DebugFormat("{0} != {1}", frameLocation, elementBoundingLocation); - } - } - } + if (_parent != null) + { + return; + } - /// - /// A "workaround" for Access Denied when dealing with Frames from different domains - /// - /// The IHTMLWindow2 to get the document from - /// IHTMLDocument2 or null - private static IHTMLDocument2 GetDocumentFromWindow(IHTMLWindow2 htmlWindow) { - if (htmlWindow == null) { - LOG.Warn("htmlWindow == null"); - return null; - } - - // First try the usual way to get the document. - try { - IHTMLDocument2 doc = htmlWindow.document; - return doc; - } catch (COMException comEx) { - // I think COMException won't be ever fired but just to be sure ... - if (comEx.ErrorCode != E_ACCESSDENIED) { - LOG.Warn("comEx.ErrorCode != E_ACCESSDENIED but", comEx); - return null; - } - } catch (UnauthorizedAccessException) { - // This error is okay, ignoring it - } catch (Exception ex1) { - LOG.Warn("Some error: ", ex1); - // Any other error. - return null; - } - - // At this point the error was E_ACCESSDENIED because the frame contains a document from another domain. - // IE tries to prevent a cross frame scripting security issue. - try { - // Convert IHTMLWindow2 to IWebBrowser2 using IServiceProvider. - IServiceProvider sp = (IServiceProvider)htmlWindow; + try + { + IHTMLFramesCollection2 frameCollection = (IHTMLFramesCollection2) document2.frames; + for (int frame = 0; frame < frameCollection.length; frame++) + { + try + { + IHTMLWindow2 frameWindow = frameCollection.item(frame); + DocumentContainer frameData = new DocumentContainer(frameWindow, contentWindow, this); + // check if frame is hidden + if (!frameData.IsHidden) + { + LOG.DebugFormat("Creating DocumentContainer for Frame {0} found in window with rectangle {1}", frameData.Name, frameData.SourceRectangle); + _frames.Add(frameData); + } + else + { + LOG.DebugFormat("Skipping frame {0}", frameData.Name); + } - // Use IServiceProvider.QueryService to get IWebBrowser2 object. + // Clean up frameWindow + releaseCom(frameWindow); + } + catch (Exception e) + { + LOG.Warn("Problem while trying to get information from a frame, skipping the frame!", e); + } + } + + // Clean up collection + releaseCom(frameCollection); + } + catch (Exception ex) + { + LOG.Warn("Problem while trying to get the frames, skipping!", ex); + } + + try + { + // Correct iframe locations + foreach (IHTMLElement frameElement in _document3.getElementsByTagName("IFRAME")) + { + try + { + CorrectFrameLocations(frameElement); + // Clean up frameElement + releaseCom(frameElement); + } + catch (Exception e) + { + LOG.Warn("Problem while trying to get information from an iframe, skipping the frame!", e); + } + } + } + catch (Exception ex) + { + LOG.Warn("Problem while trying to get the iframes, skipping!", ex); + } + } + + /// + /// Corrent the frame locations with the information + /// + /// + private void CorrectFrameLocations(IHTMLElement frameElement) + { + long x = 0; + long y = 0; + IHTMLElement element = frameElement; + IHTMLElement oldElement = null; + do + { + x += element.offsetLeft; + y += element.offsetTop; + element = element.offsetParent; + // Release element, but prevent the frameElement to be released + if (oldElement != null) + { + releaseCom(oldElement); + } + + oldElement = element; + } while (element != null); + + Point elementLocation = new Point((int) x, (int) y); + IHTMLElement2 element2 = (IHTMLElement2) frameElement; + IHTMLRect rec = element2.getBoundingClientRect(); + Point elementBoundingLocation = new Point(rec.left, rec.top); + // Release IHTMLRect + releaseCom(rec); + LOG.DebugFormat("Looking for iframe to correct at {0}", elementBoundingLocation); + foreach (DocumentContainer foundFrame in _frames) + { + Point frameLocation = foundFrame.SourceLocation; + if (frameLocation.Equals(elementBoundingLocation)) + { + // Match found, correcting location + LOG.DebugFormat("Correcting frame from {0} to {1}", frameLocation, elementLocation); + foundFrame.SourceLocation = elementLocation; + foundFrame.DestinationLocation = elementLocation; + } + else + { + LOG.DebugFormat("{0} != {1}", frameLocation, elementBoundingLocation); + } + } + } + + /// + /// A "workaround" for Access Denied when dealing with Frames from different domains + /// + /// The IHTMLWindow2 to get the document from + /// IHTMLDocument2 or null + private static IHTMLDocument2 GetDocumentFromWindow(IHTMLWindow2 htmlWindow) + { + if (htmlWindow == null) + { + LOG.Warn("htmlWindow == null"); + return null; + } + + // First try the usual way to get the document. + try + { + IHTMLDocument2 doc = htmlWindow.document; + return doc; + } + catch (COMException comEx) + { + // I think COMException won't be ever fired but just to be sure ... + if (comEx.ErrorCode != E_ACCESSDENIED) + { + LOG.Warn("comEx.ErrorCode != E_ACCESSDENIED but", comEx); + return null; + } + } + catch (UnauthorizedAccessException) + { + // This error is okay, ignoring it + } + catch (Exception ex1) + { + LOG.Warn("Some error: ", ex1); + // Any other error. + return null; + } + + // At this point the error was E_ACCESSDENIED because the frame contains a document from another domain. + // IE tries to prevent a cross frame scripting security issue. + try + { + // Convert IHTMLWindow2 to IWebBrowser2 using IServiceProvider. + IServiceProvider sp = (IServiceProvider) htmlWindow; + + // Use IServiceProvider.QueryService to get IWebBrowser2 object. Guid webBrowserApp = IID_IWebBrowserApp; - Guid webBrowser2 = IID_IWebBrowser2; - sp.QueryService(ref webBrowserApp, ref webBrowser2, out var brws); - - // Get the document from IWebBrowser2. - IWebBrowser2 browser = (IWebBrowser2)brws; - - return (IHTMLDocument2)browser.Document; - } catch (Exception ex2) { - LOG.Warn("another error: ", ex2); - } - return null; - } - - public Color BackgroundColor { - get { - try { - string bgColor = (string)_document2.bgColor; - if (bgColor != null) { - int rgbInt = int.Parse(bgColor.Substring(1), NumberStyles.HexNumber); - return Color.FromArgb(rgbInt >> 16, (rgbInt >> 8) & 255, rgbInt & 255); - } - } catch (Exception ex) { - LOG.Error("Problem retrieving the background color: ", ex); - } - return Color.White; - } - } + Guid webBrowser2 = IID_IWebBrowser2; + sp.QueryService(ref webBrowserApp, ref webBrowser2, out var brws); - public Rectangle ViewportRectangle => _viewportRectangle; + // Get the document from IWebBrowser2. + IWebBrowser2 browser = (IWebBrowser2) brws; - public WindowDetails ContentWindow => _contentWindow; + return (IHTMLDocument2) browser.Document; + } + catch (Exception ex2) + { + LOG.Warn("another error: ", ex2); + } - public DocumentContainer Parent { - get { - return _parent; - } - set { - _parent = value; - } - } - - private int ScaleX(int physicalValue) { - return (int)Math.Round(physicalValue * _zoomLevelX, MidpointRounding.AwayFromZero); - } + return null; + } - private int ScaleY(int physicalValue) { - return (int)Math.Round(physicalValue * _zoomLevelY, MidpointRounding.AwayFromZero); - } + public Color BackgroundColor + { + get + { + try + { + string bgColor = (string) _document2.bgColor; + if (bgColor != null) + { + int rgbInt = int.Parse(bgColor.Substring(1), NumberStyles.HexNumber); + return Color.FromArgb(rgbInt >> 16, (rgbInt >> 8) & 255, rgbInt & 255); + } + } + catch (Exception ex) + { + LOG.Error("Problem retrieving the background color: ", ex); + } - private int UnscaleX(int physicalValue) { - return (int)Math.Round(physicalValue / _zoomLevelX, MidpointRounding.AwayFromZero); - } + return Color.White; + } + } - private int UnscaleY(int physicalValue) { - return (int)Math.Round(physicalValue / _zoomLevelY, MidpointRounding.AwayFromZero); - } + public Rectangle ViewportRectangle => _viewportRectangle; - /// - /// Set/change an int attribute on a document - /// - public void SetAttribute(string attribute, int value) { - SetAttribute(attribute, value.ToString()); - } + public WindowDetails ContentWindow => _contentWindow; - /// - /// Set/change an attribute on a document - /// - /// Attribute to set - /// Value to set - public void SetAttribute(string attribute, string value) { - var element = !_isDtd ? _document2.body : _document3.documentElement; - element.setAttribute(attribute, value, 1); - // Release IHTMLElement com object - releaseCom(element); - } + public DocumentContainer Parent + { + get { return _parent; } + set { _parent = value; } + } - /// - /// Get the attribute from a document - /// - /// Attribute to get - /// object with the attribute value - public object GetAttribute(string attribute) { - var element = !_isDtd ? _document2.body : _document3.documentElement; - var retVal = element.getAttribute(attribute, 1); - // Release IHTMLElement com object - releaseCom(element); - return retVal; - } - - /// - /// Get the attribute as int from a document - /// - public int GetAttributeAsInt(string attribute) { - int retVal = (int)GetAttribute(attribute); - return retVal; - } - - public int Id { get; } = _counter++; + private int ScaleX(int physicalValue) + { + return (int) Math.Round(physicalValue * _zoomLevelX, MidpointRounding.AwayFromZero); + } - public string Name { get; private set; } + private int ScaleY(int physicalValue) + { + return (int) Math.Round(physicalValue * _zoomLevelY, MidpointRounding.AwayFromZero); + } - public string Url { get; private set; } + private int UnscaleX(int physicalValue) + { + return (int) Math.Round(physicalValue / _zoomLevelX, MidpointRounding.AwayFromZero); + } - public bool IsHidden => ClientWidth == 0 || ClientHeight == 0; + private int UnscaleY(int physicalValue) + { + return (int) Math.Round(physicalValue / _zoomLevelY, MidpointRounding.AwayFromZero); + } - public int ClientWidth => ScaleX(GetAttributeAsInt("clientWidth")); + /// + /// Set/change an int attribute on a document + /// + public void SetAttribute(string attribute, int value) + { + SetAttribute(attribute, value.ToString()); + } - public int ClientHeight => ScaleY(GetAttributeAsInt("clientHeight")); + /// + /// Set/change an attribute on a document + /// + /// Attribute to set + /// Value to set + public void SetAttribute(string attribute, string value) + { + var element = !_isDtd ? _document2.body : _document3.documentElement; + element.setAttribute(attribute, value, 1); + // Release IHTMLElement com object + releaseCom(element); + } - public int ScrollWidth => ScaleX(GetAttributeAsInt("scrollWidth")); + /// + /// Get the attribute from a document + /// + /// Attribute to get + /// object with the attribute value + public object GetAttribute(string attribute) + { + var element = !_isDtd ? _document2.body : _document3.documentElement; + var retVal = element.getAttribute(attribute, 1); + // Release IHTMLElement com object + releaseCom(element); + return retVal; + } - public int ScrollHeight => ScaleY(GetAttributeAsInt("scrollHeight")); + /// + /// Get the attribute as int from a document + /// + public int GetAttributeAsInt(string attribute) + { + int retVal = (int) GetAttribute(attribute); + return retVal; + } - public Point SourceLocation { - get { - return _sourceLocation; - } - set { - _sourceLocation = value; - } - } + public int Id { get; } = _counter++; - public Size SourceSize => new Size(ClientWidth, ClientHeight); + public string Name { get; private set; } - public Rectangle SourceRectangle => new Rectangle(SourceLocation, SourceSize); + public string Url { get; private set; } - public int SourceLeft => _sourceLocation.X; + public bool IsHidden => ClientWidth == 0 || ClientHeight == 0; - public int SourceTop => _sourceLocation.Y; + public int ClientWidth => ScaleX(GetAttributeAsInt("clientWidth")); - public int SourceRight => _sourceLocation.X + ClientWidth; + public int ClientHeight => ScaleY(GetAttributeAsInt("clientHeight")); - public int SourceBottom => _sourceLocation.Y + ClientHeight; + public int ScrollWidth => ScaleX(GetAttributeAsInt("scrollWidth")); - public Point DestinationLocation { - get { - return _destinationLocation; - } - set { - _destinationLocation = value; - } + public int ScrollHeight => ScaleY(GetAttributeAsInt("scrollHeight")); - } - - public Size DestinationSize => new Size(ScrollWidth, ScrollHeight); + public Point SourceLocation + { + get { return _sourceLocation; } + set { _sourceLocation = value; } + } - public Rectangle DestinationRectangle => new Rectangle(DestinationLocation, DestinationSize); + public Size SourceSize => new Size(ClientWidth, ClientHeight); - public int DestinationLeft { - get { - return _destinationLocation.X; - } - set { - _destinationLocation.X = value; - } - } + public Rectangle SourceRectangle => new Rectangle(SourceLocation, SourceSize); - public int DestinationTop { - get { - return _destinationLocation.Y; - } - set { - _destinationLocation.Y = value; - } - } + public int SourceLeft => _sourceLocation.X; - public int DestinationRight => _destinationLocation.X + ScrollWidth; + public int SourceTop => _sourceLocation.Y; - public int DestinationBottom => _destinationLocation.Y + ScrollHeight; + public int SourceRight => _sourceLocation.X + ClientWidth; - public int ScrollLeft { - get{ - return ScaleX(GetAttributeAsInt("scrollLeft")); - } - set { - SetAttribute("scrollLeft", UnscaleX(value)); - } - } + public int SourceBottom => _sourceLocation.Y + ClientHeight; - public int ScrollTop { - get{ - return ScaleY(GetAttributeAsInt("scrollTop")); - } - set { - SetAttribute("scrollTop", UnscaleY(value)); - } - } - - public IList Frames => _frames; - } -} + public Point DestinationLocation + { + get { return _destinationLocation; } + set { _destinationLocation = value; } + } + + public Size DestinationSize => new Size(ScrollWidth, ScrollHeight); + + public Rectangle DestinationRectangle => new Rectangle(DestinationLocation, DestinationSize); + + public int DestinationLeft + { + get { return _destinationLocation.X; } + set { _destinationLocation.X = value; } + } + + public int DestinationTop + { + get { return _destinationLocation.Y; } + set { _destinationLocation.Y = value; } + } + + public int DestinationRight => _destinationLocation.X + ScrollWidth; + + public int DestinationBottom => _destinationLocation.Y + ScrollHeight; + + public int ScrollLeft + { + get { return ScaleX(GetAttributeAsInt("scrollLeft")); } + set { SetAttribute("scrollLeft", UnscaleX(value)); } + } + + public int ScrollTop + { + get { return ScaleY(GetAttributeAsInt("scrollTop")); } + set { SetAttribute("scrollTop", UnscaleY(value)); } + } + + public IList Frames => _frames; + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/MailHelper.cs b/src/Greenshot/Helpers/MailHelper.cs index 2ba02461e..1f626a2da 100644 --- a/src/Greenshot/Helpers/MailHelper.cs +++ b/src/Greenshot/Helpers/MailHelper.cs @@ -32,504 +32,546 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; -namespace Greenshot.Helpers { - /// - /// Author: Andrew Baker - /// Datum: 10.03.2006 - /// Available from here - /// - +namespace Greenshot.Helpers +{ /// - /// Represents an email message to be sent through MAPI. - /// - public class MapiMailMessage : IDisposable { - private static readonly ILog Log = LogManager.GetLogger(typeof(MapiMailMessage)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + /// Author: Andrew Baker + /// Datum: 10.03.2006 + /// Available from here + ///
+ /// + /// Represents an email message to be sent through MAPI. + /// + public class MapiMailMessage : IDisposable + { + private static readonly ILog Log = LogManager.GetLogger(typeof(MapiMailMessage)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - /// - /// Helper Method for creating an Email with Attachment - /// - /// Path to file - /// - public static void SendImage(string fullPath, string title) + /// + /// Helper Method for creating an Email with Attachment + /// + /// Path to file + /// + public static void SendImage(string fullPath, string title) { using MapiMailMessage message = new MapiMailMessage(title, null); message.Files.Add(fullPath); - if (!string.IsNullOrEmpty(CoreConfig.MailApiTo)) { + if (!string.IsNullOrEmpty(CoreConfig.MailApiTo)) + { message.Recipients.Add(new Recipient(CoreConfig.MailApiTo, RecipientType.To)); } - if (!string.IsNullOrEmpty(CoreConfig.MailApiCC)) { + + if (!string.IsNullOrEmpty(CoreConfig.MailApiCC)) + { message.Recipients.Add(new Recipient(CoreConfig.MailApiCC, RecipientType.CC)); } - if (!string.IsNullOrEmpty(CoreConfig.MailApiBCC)) { + + if (!string.IsNullOrEmpty(CoreConfig.MailApiBCC)) + { message.Recipients.Add(new Recipient(CoreConfig.MailApiBCC, RecipientType.BCC)); } + message.ShowDialog(); } - /// - /// Helper Method for creating an Email with Image Attachment - /// - /// The image to send - /// ICaptureDetails - public static void SendImage(ISurface surface, ICaptureDetails captureDetails) { - string tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings()); + /// + /// Helper Method for creating an Email with Image Attachment + /// + /// The image to send + /// ICaptureDetails + public static void SendImage(ISurface surface, ICaptureDetails captureDetails) + { + string tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings()); - if (tmpFile == null) return; - - // Store the list of currently active windows, so we can make sure we show the email window later! - var windowsBefore = WindowDetails.GetVisibleWindows(); - SendImage(tmpFile, captureDetails.Title); - WindowDetails.ActiveNewerWindows(windowsBefore); - } + if (tmpFile == null) return; + + // Store the list of currently active windows, so we can make sure we show the email window later! + var windowsBefore = WindowDetails.GetVisibleWindows(); + SendImage(tmpFile, captureDetails.Title); + WindowDetails.ActiveNewerWindows(windowsBefore); + } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - private class MapiFileDescriptor { - public int reserved = 0; - public int flags = 0; - public int position; - public string path; - public string name; - public IntPtr type = IntPtr.Zero; - } + private class MapiFileDescriptor + { + public int reserved = 0; + public int flags = 0; + public int position; + public string path; + public string name; + public IntPtr type = IntPtr.Zero; + } /// - /// Specifies the valid RecipientTypes for a Recipient. - /// - public enum RecipientType - { - /// - /// Recipient will be in the TO list. - /// - To = 1, + /// Specifies the valid RecipientTypes for a Recipient. + ///
+ public enum RecipientType + { + /// + /// Recipient will be in the TO list. + /// + To = 1, - /// - /// Recipient will be in the CC list. - /// - CC = 2, + /// + /// Recipient will be in the CC list. + /// + CC = 2, - /// - /// Recipient will be in the BCC list. - /// - BCC = 3 - }; + /// + /// Recipient will be in the BCC list. + /// + BCC = 3 + }; private readonly ManualResetEvent _manualResetEvent; /// - /// Creates a blank mail message. - /// - public MapiMailMessage() { - Files = new List(); - Recipients = new RecipientCollection(); - _manualResetEvent = new ManualResetEvent(false); - } + /// Creates a blank mail message. + ///
+ public MapiMailMessage() + { + Files = new List(); + Recipients = new RecipientCollection(); + _manualResetEvent = new ManualResetEvent(false); + } /// - /// Creates a new mail message with the specified subject and body. - /// - public MapiMailMessage(string subject, string body) : this() { - Subject = subject; - Body = body; - } + /// Creates a new mail message with the specified subject and body. + ///
+ public MapiMailMessage(string subject, string body) : this() + { + Subject = subject; + Body = body; + } /// - /// Gets or sets the subject of this mail message. - /// - public string Subject { get; set; } - - /// - /// Gets or sets the body of this mail message. - /// - public string Body { get; set; } - - /// - /// Gets the recipient list for this mail message. - /// - public RecipientCollection Recipients { get; private set; } - - /// - /// Gets the file list for this mail message. - /// - public List Files { get; } + /// Gets or sets the subject of this mail message. + ///
+ public string Subject { get; set; } /// - /// Displays the mail message dialog asynchronously. - /// - public void ShowDialog() { - // Create the mail message in an STA thread - var thread = new Thread(ShowMail) - { - IsBackground = true, - Name = "Create MAPI mail" - }; - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); + /// Gets or sets the body of this mail message. + ///
+ public string Body { get; set; } - // only return when the new thread has built it's interop representation - _manualResetEvent.WaitOne(); - _manualResetEvent.Reset(); - } + /// + /// Gets the recipient list for this mail message. + /// + public RecipientCollection Recipients { get; private set; } - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + /// + /// Gets the file list for this mail message. + /// + public List Files { get; } - protected virtual void Dispose(bool disposing) { - if (!disposing) { - return; - } - _manualResetEvent?.Close(); - } + /// + /// Displays the mail message dialog asynchronously. + /// + public void ShowDialog() + { + // Create the mail message in an STA thread + var thread = new Thread(ShowMail) + { + IsBackground = true, + Name = "Create MAPI mail" + }; + thread.SetApartmentState(ApartmentState.STA); + thread.Start(); + + // only return when the new thread has built it's interop representation + _manualResetEvent.WaitOne(); + _manualResetEvent.Reset(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposing) + { + return; + } + + _manualResetEvent?.Close(); + } /// /// Sends the mail message. /// private void ShowMail() { - while (true) - { - var message = new MapiHelperInterop.MapiMessage(); + while (true) + { + var message = new MapiHelperInterop.MapiMessage(); - using var interopRecipients = Recipients.GetInteropRepresentation(); - message.Subject = Subject; - message.NoteText = Body; + using var interopRecipients = Recipients.GetInteropRepresentation(); + message.Subject = Subject; + message.NoteText = Body; - message.Recipients = interopRecipients.Handle; - message.RecipientCount = Recipients.Count; + message.Recipients = interopRecipients.Handle; + message.RecipientCount = Recipients.Count; - // Check if we need to add attachments - if (Files.Count > 0) - { - // Add attachments - message.Files = AllocAttachments(out message.FileCount); - } + // Check if we need to add attachments + if (Files.Count > 0) + { + // Add attachments + message.Files = AllocAttachments(out message.FileCount); + } - // Signal the creating thread (make the remaining code async) - _manualResetEvent.Set(); + // Signal the creating thread (make the remaining code async) + _manualResetEvent.Set(); - const int MAPI_DIALOG = 0x8; - //const int MAPI_LOGON_UI = 0x1; - int error = MapiHelperInterop.MAPISendMail(IntPtr.Zero, IntPtr.Zero, message, MAPI_DIALOG, 0); + const int MAPI_DIALOG = 0x8; + //const int MAPI_LOGON_UI = 0x1; + int error = MapiHelperInterop.MAPISendMail(IntPtr.Zero, IntPtr.Zero, message, MAPI_DIALOG, 0); - if (Files.Count > 0) - { - // Deallocate the files - DeallocFiles(message); - } + if (Files.Count > 0) + { + // Deallocate the files + DeallocFiles(message); + } - MAPI_CODES errorCode = (MAPI_CODES) Enum.ToObject(typeof(MAPI_CODES), error); + MAPI_CODES errorCode = (MAPI_CODES) Enum.ToObject(typeof(MAPI_CODES), error); - // Check for error - if (errorCode == MAPI_CODES.SUCCESS || errorCode == MAPI_CODES.USER_ABORT) - { - return; - } + // Check for error + if (errorCode == MAPI_CODES.SUCCESS || errorCode == MAPI_CODES.USER_ABORT) + { + return; + } - string errorText = GetMapiError(errorCode); - Log.Error("Error sending MAPI Email. Error: " + errorText + " (code = " + errorCode + ")."); - MessageBox.Show(errorText, "Mail (MAPI) destination", MessageBoxButtons.OK, MessageBoxIcon.Error); - // Recover from bad settings, show again - if (errorCode != MAPI_CODES.INVALID_RECIPS) - { - return; - } + string errorText = GetMapiError(errorCode); + Log.Error("Error sending MAPI Email. Error: " + errorText + " (code = " + errorCode + ")."); + MessageBox.Show(errorText, "Mail (MAPI) destination", MessageBoxButtons.OK, MessageBoxIcon.Error); + // Recover from bad settings, show again + if (errorCode != MAPI_CODES.INVALID_RECIPS) + { + return; + } - Recipients = new RecipientCollection(); - } + Recipients = new RecipientCollection(); + } } /// - /// Deallocates the files in a message. - /// - /// The message to deallocate the files from. - private void DeallocFiles(MapiHelperInterop.MapiMessage message) - { - if (message.Files == IntPtr.Zero) return; - - Type fileDescType = typeof(MapiFileDescriptor); - int fsize = Marshal.SizeOf(fileDescType); + /// Deallocates the files in a message. + ///
+ /// The message to deallocate the files from. + private void DeallocFiles(MapiHelperInterop.MapiMessage message) + { + if (message.Files == IntPtr.Zero) return; - // Get the ptr to the files - IntPtr runptr = message.Files; - // Release each file - for (int i = 0; i < message.FileCount; i++) { - Marshal.DestroyStructure(runptr, fileDescType); - runptr = new IntPtr(runptr.ToInt64() + fsize); - } - // Release the file - Marshal.FreeHGlobal(message.Files); - } + Type fileDescType = typeof(MapiFileDescriptor); + int fsize = Marshal.SizeOf(fileDescType); - /// - /// Allocates the file attachments - /// - /// - /// - private IntPtr AllocAttachments(out int fileCount) { - fileCount = 0; - if (Files == null) { - return IntPtr.Zero; - } - if ((Files.Count <= 0) || (Files.Count > 100)) { - return IntPtr.Zero; - } + // Get the ptr to the files + IntPtr runptr = message.Files; + // Release each file + for (int i = 0; i < message.FileCount; i++) + { + Marshal.DestroyStructure(runptr, fileDescType); + runptr = new IntPtr(runptr.ToInt64() + fsize); + } - Type atype = typeof(MapiFileDescriptor); - int asize = Marshal.SizeOf(atype); - IntPtr ptra = Marshal.AllocHGlobal(Files.Count * asize); - - MapiFileDescriptor mfd = new MapiFileDescriptor - { - position = -1 - }; - IntPtr runptr = ptra; - foreach (string path in Files) - { - mfd.name = Path.GetFileName(path); - mfd.path = path; - Marshal.StructureToPtr(mfd, runptr, false); - runptr = new IntPtr(runptr.ToInt64() + asize); - } - - fileCount = Files.Count; - return ptra; - } - - private enum MAPI_CODES { - SUCCESS = 0, - USER_ABORT = 1, - FAILURE = 2, - LOGIN_FAILURE = 3, - DISK_FULL = 4, - INSUFFICIENT_MEMORY = 5, - BLK_TOO_SMALL = 6, - TOO_MANY_SESSIONS = 8, - TOO_MANY_FILES = 9, - TOO_MANY_RECIPIENTS = 10, - ATTACHMENT_NOT_FOUND = 11, - ATTACHMENT_OPEN_FAILURE = 12, - ATTACHMENT_WRITE_FAILURE = 13, - UNKNOWN_RECIPIENT = 14, - BAD_RECIPTYPE = 15, - NO_MESSAGES = 16, - INVALID_MESSAGE = 17, - TEXT_TOO_LARGE = 18, - INVALID_SESSION = 19, - TYPE_NOT_SUPPORTED = 20, - AMBIGUOUS_RECIPIENT = 21, - MESSAGE_IN_USE = 22, - NETWORK_FAILURE = 23, - INVALID_EDITFIELDS = 24, - INVALID_RECIPS = 25, - NOT_SUPPORTED = 26, - NO_LIBRARY = 999, - INVALID_PARAMETER = 998 - } - /// - /// Logs any Mapi errors. - /// - private string GetMapiError(MAPI_CODES errorCode) - { - string error = errorCode switch - { - MAPI_CODES.USER_ABORT => "User Aborted.", - MAPI_CODES.FAILURE => "MAPI Failure.", - MAPI_CODES.LOGIN_FAILURE => "Login Failure.", - MAPI_CODES.DISK_FULL => "MAPI Disk full.", - MAPI_CODES.INSUFFICIENT_MEMORY => "MAPI Insufficient memory.", - MAPI_CODES.BLK_TOO_SMALL => "MAPI Block too small.", - MAPI_CODES.TOO_MANY_SESSIONS => "MAPI Too many sessions.", - MAPI_CODES.TOO_MANY_FILES => "MAPI too many files.", - MAPI_CODES.TOO_MANY_RECIPIENTS => "MAPI too many recipients.", - MAPI_CODES.ATTACHMENT_NOT_FOUND => "MAPI Attachment not found.", - MAPI_CODES.ATTACHMENT_OPEN_FAILURE => "MAPI Attachment open failure.", - MAPI_CODES.ATTACHMENT_WRITE_FAILURE => "MAPI Attachment Write Failure.", - MAPI_CODES.UNKNOWN_RECIPIENT => "MAPI Unknown recipient.", - MAPI_CODES.BAD_RECIPTYPE => "MAPI Bad recipient type.", - MAPI_CODES.NO_MESSAGES => "MAPI No messages.", - MAPI_CODES.INVALID_MESSAGE => "MAPI Invalid message.", - MAPI_CODES.TEXT_TOO_LARGE => "MAPI Text too large.", - MAPI_CODES.INVALID_SESSION => "MAPI Invalid session.", - MAPI_CODES.TYPE_NOT_SUPPORTED => "MAPI Type not supported.", - MAPI_CODES.AMBIGUOUS_RECIPIENT => "MAPI Ambiguous recipient.", - MAPI_CODES.MESSAGE_IN_USE => "MAPI Message in use.", - MAPI_CODES.NETWORK_FAILURE => "MAPI Network failure.", - MAPI_CODES.INVALID_EDITFIELDS => "MAPI Invalid edit fields.", - MAPI_CODES.INVALID_RECIPS => "MAPI Invalid Recipients.", - MAPI_CODES.NOT_SUPPORTED => "MAPI Not supported.", - MAPI_CODES.NO_LIBRARY => "MAPI No Library.", - MAPI_CODES.INVALID_PARAMETER => "MAPI Invalid parameter.", - _ => string.Empty - }; - return error; - } + // Release the file + Marshal.FreeHGlobal(message.Files); + } /// - /// Internal class for calling MAPI APIs - /// - internal class MapiHelperInterop { + /// Allocates the file attachments + ///
+ /// + /// + private IntPtr AllocAttachments(out int fileCount) + { + fileCount = 0; + if (Files == null) + { + return IntPtr.Zero; + } + + if ((Files.Count <= 0) || (Files.Count > 100)) + { + return IntPtr.Zero; + } + + Type atype = typeof(MapiFileDescriptor); + int asize = Marshal.SizeOf(atype); + IntPtr ptra = Marshal.AllocHGlobal(Files.Count * asize); + + MapiFileDescriptor mfd = new MapiFileDescriptor + { + position = -1 + }; + IntPtr runptr = ptra; + foreach (string path in Files) + { + mfd.name = Path.GetFileName(path); + mfd.path = path; + Marshal.StructureToPtr(mfd, runptr, false); + runptr = new IntPtr(runptr.ToInt64() + asize); + } + + fileCount = Files.Count; + return ptra; + } + + private enum MAPI_CODES + { + SUCCESS = 0, + USER_ABORT = 1, + FAILURE = 2, + LOGIN_FAILURE = 3, + DISK_FULL = 4, + INSUFFICIENT_MEMORY = 5, + BLK_TOO_SMALL = 6, + TOO_MANY_SESSIONS = 8, + TOO_MANY_FILES = 9, + TOO_MANY_RECIPIENTS = 10, + ATTACHMENT_NOT_FOUND = 11, + ATTACHMENT_OPEN_FAILURE = 12, + ATTACHMENT_WRITE_FAILURE = 13, + UNKNOWN_RECIPIENT = 14, + BAD_RECIPTYPE = 15, + NO_MESSAGES = 16, + INVALID_MESSAGE = 17, + TEXT_TOO_LARGE = 18, + INVALID_SESSION = 19, + TYPE_NOT_SUPPORTED = 20, + AMBIGUOUS_RECIPIENT = 21, + MESSAGE_IN_USE = 22, + NETWORK_FAILURE = 23, + INVALID_EDITFIELDS = 24, + INVALID_RECIPS = 25, + NOT_SUPPORTED = 26, + NO_LIBRARY = 999, + INVALID_PARAMETER = 998 + } + + /// + /// Logs any Mapi errors. + /// + private string GetMapiError(MAPI_CODES errorCode) + { + string error = errorCode switch + { + MAPI_CODES.USER_ABORT => "User Aborted.", + MAPI_CODES.FAILURE => "MAPI Failure.", + MAPI_CODES.LOGIN_FAILURE => "Login Failure.", + MAPI_CODES.DISK_FULL => "MAPI Disk full.", + MAPI_CODES.INSUFFICIENT_MEMORY => "MAPI Insufficient memory.", + MAPI_CODES.BLK_TOO_SMALL => "MAPI Block too small.", + MAPI_CODES.TOO_MANY_SESSIONS => "MAPI Too many sessions.", + MAPI_CODES.TOO_MANY_FILES => "MAPI too many files.", + MAPI_CODES.TOO_MANY_RECIPIENTS => "MAPI too many recipients.", + MAPI_CODES.ATTACHMENT_NOT_FOUND => "MAPI Attachment not found.", + MAPI_CODES.ATTACHMENT_OPEN_FAILURE => "MAPI Attachment open failure.", + MAPI_CODES.ATTACHMENT_WRITE_FAILURE => "MAPI Attachment Write Failure.", + MAPI_CODES.UNKNOWN_RECIPIENT => "MAPI Unknown recipient.", + MAPI_CODES.BAD_RECIPTYPE => "MAPI Bad recipient type.", + MAPI_CODES.NO_MESSAGES => "MAPI No messages.", + MAPI_CODES.INVALID_MESSAGE => "MAPI Invalid message.", + MAPI_CODES.TEXT_TOO_LARGE => "MAPI Text too large.", + MAPI_CODES.INVALID_SESSION => "MAPI Invalid session.", + MAPI_CODES.TYPE_NOT_SUPPORTED => "MAPI Type not supported.", + MAPI_CODES.AMBIGUOUS_RECIPIENT => "MAPI Ambiguous recipient.", + MAPI_CODES.MESSAGE_IN_USE => "MAPI Message in use.", + MAPI_CODES.NETWORK_FAILURE => "MAPI Network failure.", + MAPI_CODES.INVALID_EDITFIELDS => "MAPI Invalid edit fields.", + MAPI_CODES.INVALID_RECIPS => "MAPI Invalid Recipients.", + MAPI_CODES.NOT_SUPPORTED => "MAPI Not supported.", + MAPI_CODES.NO_LIBRARY => "MAPI No Library.", + MAPI_CODES.INVALID_PARAMETER => "MAPI Invalid parameter.", + _ => string.Empty + }; + return error; + } + + /// + /// Internal class for calling MAPI APIs + /// + internal class MapiHelperInterop + { /// - /// Private constructor. - /// - private MapiHelperInterop() { - // Intenationally blank - } + /// Private constructor. + ///
+ private MapiHelperInterop() + { + // Intenationally blank + } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public class MapiMessage { - public int Reserved = 0; - public string Subject; - public string NoteText; - public string MessageType = null; - public string DateReceived = null; - public string ConversationID = null; - public int Flags = 0; - public IntPtr Originator = IntPtr.Zero; - public int RecipientCount; - public IntPtr Recipients = IntPtr.Zero; - public int FileCount; - public IntPtr Files = IntPtr.Zero; - } + public class MapiMessage + { + public int Reserved = 0; + public string Subject; + public string NoteText; + public string MessageType = null; + public string DateReceived = null; + public string ConversationID = null; + public int Flags = 0; + public IntPtr Originator = IntPtr.Zero; + public int RecipientCount; + public IntPtr Recipients = IntPtr.Zero; + public int FileCount; + public IntPtr Files = IntPtr.Zero; + } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public class MapiRecipDesc { - public int Reserved = 0; - public int RecipientClass; - public string Name; - public string Address; - public int eIDSize = 0; - public IntPtr EntryID = IntPtr.Zero; - } + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public class MapiRecipDesc + { + public int Reserved = 0; + public int RecipientClass; + public string Name; + public string Address; + public int eIDSize = 0; + public IntPtr EntryID = IntPtr.Zero; + } - [DllImport("MAPI32.DLL", SetLastError = true, CharSet=CharSet.Ansi)] - public static extern int MAPISendMail(IntPtr session, IntPtr hWnd, MapiMessage message, int flg, int rsv); + [DllImport("MAPI32.DLL", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern int MAPISendMail(IntPtr session, IntPtr hWnd, MapiMessage message, int flg, int rsv); } } /// - /// Represents a Recipient for a MapiMailMessage. - /// - public class Recipient { + /// Represents a Recipient for a MapiMailMessage. + ///
+ public class Recipient + { /// - /// The email address of this recipient. - /// - public string Address; - - /// - /// The display name of this recipient. - /// - public string DisplayName; - - /// - /// How the recipient will receive this message (To, CC, BCC). - /// - public MapiMailMessage.RecipientType RecipientType = MapiMailMessage.RecipientType.To; + /// The email address of this recipient. + ///
+ public string Address; /// - /// Creates a new recipient with the specified address and recipient type. - /// - public Recipient(string address, MapiMailMessage.RecipientType recipientType) { - Address = address; - RecipientType = recipientType; - } + /// The display name of this recipient. + ///
+ public string DisplayName; /// - /// Returns an interop representation of a recepient. - /// - /// - internal MapiMailMessage.MapiHelperInterop.MapiRecipDesc GetInteropRepresentation() { - MapiMailMessage.MapiHelperInterop.MapiRecipDesc interop = new MapiMailMessage.MapiHelperInterop.MapiRecipDesc(); + /// How the recipient will receive this message (To, CC, BCC). + ///
+ public MapiMailMessage.RecipientType RecipientType = MapiMailMessage.RecipientType.To; - if (DisplayName == null) { - interop.Name = Address; - } else { - interop.Name = DisplayName; - interop.Address = Address; - } + /// + /// Creates a new recipient with the specified address and recipient type. + /// + public Recipient(string address, MapiMailMessage.RecipientType recipientType) + { + Address = address; + RecipientType = recipientType; + } - interop.RecipientClass = (int)RecipientType; + /// + /// Returns an interop representation of a recepient. + /// + /// + internal MapiMailMessage.MapiHelperInterop.MapiRecipDesc GetInteropRepresentation() + { + MapiMailMessage.MapiHelperInterop.MapiRecipDesc interop = new MapiMailMessage.MapiHelperInterop.MapiRecipDesc(); - return interop; - } + if (DisplayName == null) + { + interop.Name = Address; + } + else + { + interop.Name = DisplayName; + interop.Address = Address; + } + + interop.RecipientClass = (int) RecipientType; + + return interop; + } } /// - /// Represents a collection of recipients for a mail message. - /// - public class RecipientCollection : CollectionBase { - /// - /// Adds the specified recipient to this collection. - /// - public void Add(Recipient value) { - List.Add(value); - } + /// Represents a collection of recipients for a mail message. + ///
+ public class RecipientCollection : CollectionBase + { + /// + /// Adds the specified recipient to this collection. + /// + public void Add(Recipient value) + { + List.Add(value); + } - internal InteropRecipientCollection GetInteropRepresentation() { - return new InteropRecipientCollection(this); - } + internal InteropRecipientCollection GetInteropRepresentation() + { + return new InteropRecipientCollection(this); + } - /// - /// Struct which contains an interop representation of a colleciton of recipients. - /// - internal struct InteropRecipientCollection : IDisposable { + /// + /// Struct which contains an interop representation of a colleciton of recipients. + /// + internal struct InteropRecipientCollection : IDisposable + { private int _count; /// - /// Default constructor for creating InteropRecipientCollection. - /// - /// - public InteropRecipientCollection(RecipientCollection outer) { - _count = outer.Count; + /// Default constructor for creating InteropRecipientCollection. + ///
+ /// + public InteropRecipientCollection(RecipientCollection outer) + { + _count = outer.Count; - if (_count == 0) { - Handle = IntPtr.Zero; - return; - } + if (_count == 0) + { + Handle = IntPtr.Zero; + return; + } - // allocate enough memory to hold all recipients - int size = Marshal.SizeOf(typeof(MapiMailMessage.MapiHelperInterop.MapiRecipDesc)); - Handle = Marshal.AllocHGlobal(_count * size); + // allocate enough memory to hold all recipients + int size = Marshal.SizeOf(typeof(MapiMailMessage.MapiHelperInterop.MapiRecipDesc)); + Handle = Marshal.AllocHGlobal(_count * size); - // place all interop recipients into the memory just allocated - IntPtr ptr = Handle; - foreach (Recipient native in outer) { - MapiMailMessage.MapiHelperInterop.MapiRecipDesc interop = native.GetInteropRepresentation(); + // place all interop recipients into the memory just allocated + IntPtr ptr = Handle; + foreach (Recipient native in outer) + { + MapiMailMessage.MapiHelperInterop.MapiRecipDesc interop = native.GetInteropRepresentation(); - // stick it in the memory block - Marshal.StructureToPtr(interop, ptr, false); - ptr = new IntPtr(ptr.ToInt64() + size); - } - } + // stick it in the memory block + Marshal.StructureToPtr(interop, ptr, false); + ptr = new IntPtr(ptr.ToInt64() + size); + } + } public IntPtr Handle { get; private set; } /// - /// Disposes of resources. - /// - public void Dispose() + /// Disposes of resources. + ///
+ public void Dispose() { - if (Handle == IntPtr.Zero) return; - - Type type = typeof(MapiMailMessage.MapiHelperInterop.MapiRecipDesc); - int size = Marshal.SizeOf(type); + if (Handle == IntPtr.Zero) return; - // destroy all the structures in the memory area - IntPtr ptr = Handle; - for (int i = 0; i < _count; i++) { - Marshal.DestroyStructure(ptr, type); - ptr = new IntPtr(ptr.ToInt64() + size); - } + Type type = typeof(MapiMailMessage.MapiHelperInterop.MapiRecipDesc); + int size = Marshal.SizeOf(type); - // free the memory - Marshal.FreeHGlobal(Handle); + // destroy all the structures in the memory area + IntPtr ptr = Handle; + for (int i = 0; i < _count; i++) + { + Marshal.DestroyStructure(ptr, type); + ptr = new IntPtr(ptr.ToInt64() + size); + } - Handle = IntPtr.Zero; - _count = 0; + // free the memory + Marshal.FreeHGlobal(Handle); + + Handle = IntPtr.Zero; + _count = 0; } } - } + } } \ No newline at end of file diff --git a/src/Greenshot/Helpers/NotifyIconNotificationService.cs b/src/Greenshot/Helpers/NotifyIconNotificationService.cs index 708da7592..a00c3f660 100644 --- a/src/Greenshot/Helpers/NotifyIconNotificationService.cs +++ b/src/Greenshot/Helpers/NotifyIconNotificationService.cs @@ -86,7 +86,8 @@ namespace Greenshot.Helpers /// ToolTipIcon /// Action /// Action - private void ShowMessage(string message, TimeSpan? timeout = null, ToolTipIcon level = ToolTipIcon.Info, Action onClickAction = null, Action onClosedAction = null) { + private void ShowMessage(string message, TimeSpan? timeout = null, ToolTipIcon level = ToolTipIcon.Info, Action onClickAction = null, Action onClosedAction = null) + { // Do not inform the user if this is disabled if (!CoreConfiguration.ShowTrayNotification) { @@ -127,8 +128,9 @@ namespace Greenshot.Helpers // Remove the other handler too _notifyIcon.BalloonTipClicked -= BalloonClickedHandler; } + _notifyIcon.BalloonTipClosed += BalloonClosedHandler; - _notifyIcon.ShowBalloonTip(timeout.HasValue ? (int)timeout.Value.TotalMilliseconds : 5000, @"Greenshot", message, level); + _notifyIcon.ShowBalloonTip(timeout.HasValue ? (int) timeout.Value.TotalMilliseconds : 5000, @"Greenshot", message, level); } } -} +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/PluginHelper.cs b/src/Greenshot/Helpers/PluginHelper.cs index 38de55b24..d8eb4f811 100644 --- a/src/Greenshot/Helpers/PluginHelper.cs +++ b/src/Greenshot/Helpers/PluginHelper.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; @@ -32,181 +33,199 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using log4net; -namespace Greenshot.Helpers { - /// - /// The PluginHelper takes care of all plugin related functionality - /// - [Serializable] - public class PluginHelper : IGreenshotHost { - private static readonly ILog Log = LogManager.GetLogger(typeof(PluginHelper)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); +namespace Greenshot.Helpers +{ + /// + /// The PluginHelper takes care of all plugin related functionality + /// + [Serializable] + public class PluginHelper : IGreenshotHost + { + private static readonly ILog Log = LogManager.GetLogger(typeof(PluginHelper)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static readonly string PluginPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),Application.ProductName); - private static readonly string ApplicationPath = Path.GetDirectoryName(Application.ExecutablePath); - private static readonly string PafPath = Path.Combine(Application.StartupPath, @"App\Greenshot"); + private static readonly string PluginPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.ProductName); + private static readonly string ApplicationPath = Path.GetDirectoryName(Application.ExecutablePath); + private static readonly string PafPath = Path.Combine(Application.StartupPath, @"App\Greenshot"); public static PluginHelper Instance { get; } = new PluginHelper(); - public void Shutdown() { - foreach(var plugin in SimpleServiceProvider.Current.GetAllInstances()) { - plugin.Shutdown(); - plugin.Dispose(); - } - } + public void Shutdown() + { + foreach (var plugin in SimpleServiceProvider.Current.GetAllInstances()) + { + plugin.Shutdown(); + plugin.Dispose(); + } + } - /// - /// Add plugins to the ListView - /// - /// - public void FillListView(ListView listView) { + /// + /// Add plugins to the ListView + /// + /// + public void FillListView(ListView listView) + { foreach (var plugin in SimpleServiceProvider.Current.GetAllInstances()) { var pluginAttribute = plugin.GetType().GetCustomAttribute(); - var item = new ListViewItem(pluginAttribute.Name) - { - Tag = pluginAttribute - }; + var item = new ListViewItem(pluginAttribute.Name) + { + Tag = pluginAttribute + }; var assembly = plugin.GetType().Assembly; var company = assembly.GetCustomAttribute(); - item.SubItems.Add(assembly.GetName().Version.ToString()); - item.SubItems.Add(company.Company); - item.SubItems.Add(assembly.Location); - listView.Items.Add(item); - } - } - - public bool IsSelectedItemConfigurable(ListView listView) { - if (listView.SelectedItems.Count <= 0) - { - return false; - } - var pluginAttribute = (PluginAttribute)listView.SelectedItems[0].Tag; - return pluginAttribute != null && pluginAttribute.Configurable; - } - - public void ConfigureSelectedItem(ListView listView) { - if (listView.SelectedItems.Count <= 0) - { - return; - } - var pluginAttribute = (PluginAttribute)listView.SelectedItems[0].Tag; - if (pluginAttribute == null) - { - return; - } + item.SubItems.Add(assembly.GetName().Version.ToString()); + item.SubItems.Add(company.Company); + item.SubItems.Add(assembly.Location); + listView.Items.Add(item); + } + } + + public bool IsSelectedItemConfigurable(ListView listView) + { + if (listView.SelectedItems.Count <= 0) + { + return false; + } + + var pluginAttribute = (PluginAttribute) listView.SelectedItems[0].Tag; + return pluginAttribute != null && pluginAttribute.Configurable; + } + + public void ConfigureSelectedItem(ListView listView) + { + if (listView.SelectedItems.Count <= 0) + { + return; + } + + var pluginAttribute = (PluginAttribute) listView.SelectedItems[0].Tag; + if (pluginAttribute == null) + { + return; + } var plugin = SimpleServiceProvider.Current.GetAllInstances().FirstOrDefault(p => p.GetType().GetCustomAttribute().Name == pluginAttribute.Name); - plugin?.Configure(); - } + plugin?.Configure(); + } /// - /// Create a Thumbnail - /// - /// Image of which we need a Thumbnail - /// Thumbnail width - /// Thumbnail height - /// Image with Thumbnail - public Image GetThumbnail(Image image, int width, int height) { - return image.GetThumbnailImage(width, height, ThumbnailCallback, IntPtr.Zero); - } + /// Create a Thumbnail + ///
+ /// Image of which we need a Thumbnail + /// Thumbnail width + /// Thumbnail height + /// Image with Thumbnail + public Image GetThumbnail(Image image, int width, int height) + { + return image.GetThumbnailImage(width, height, ThumbnailCallback, IntPtr.Zero); + } - /// - /// Required for GetThumbnail, but not used - /// - /// true - private bool ThumbnailCallback() { - return true; - } + /// + /// Required for GetThumbnail, but not used + /// + /// true + private bool ThumbnailCallback() + { + return true; + } - public ExportInformation ExportCapture(bool manuallyInitiated, string designation, ISurface surface, ICaptureDetails captureDetails) { - return DestinationHelper.ExportCapture(manuallyInitiated, designation, surface, captureDetails); - } + public ExportInformation ExportCapture(bool manuallyInitiated, string designation, ISurface surface, ICaptureDetails captureDetails) + { + return DestinationHelper.ExportCapture(manuallyInitiated, designation, surface, captureDetails); + } - /// - /// Make Capture with specified Handler - /// - /// bool false if the mouse should not be captured, true if the configuration should be checked - /// IDestination - public void CaptureRegion(bool captureMouseCursor, IDestination destination) { - CaptureHelper.CaptureRegion(captureMouseCursor, destination); - } + /// + /// Make Capture with specified Handler + /// + /// bool false if the mouse should not be captured, true if the configuration should be checked + /// IDestination + public void CaptureRegion(bool captureMouseCursor, IDestination destination) + { + CaptureHelper.CaptureRegion(captureMouseCursor, destination); + } - /// - /// Use the supplied image, and handle it as if it's captured. - /// - /// Image to handle - public void ImportCapture(ICapture captureToImport) + /// + /// Use the supplied image, and handle it as if it's captured. + /// + /// Image to handle + public void ImportCapture(ICapture captureToImport) { var mainForm = SimpleServiceProvider.Current.GetInstance(); - mainForm.BeginInvoke((MethodInvoker)delegate { - CaptureHelper.ImportCapture(captureToImport); - }); - } - - /// - /// Get an ICapture object, so the plugin can modify this - /// - /// - public ICapture GetCapture(Image imageToCapture) { - var capture = new Capture(imageToCapture) - { - CaptureDetails = new CaptureDetails - { - CaptureMode = CaptureMode.Import, - Title = "Imported" - } - }; - return capture; - } + mainForm.BeginInvoke((MethodInvoker) delegate { CaptureHelper.ImportCapture(captureToImport); }); + } + + /// + /// Get an ICapture object, so the plugin can modify this + /// + /// + public ICapture GetCapture(Image imageToCapture) + { + var capture = new Capture(imageToCapture) + { + CaptureDetails = new CaptureDetails + { + CaptureMode = CaptureMode.Import, + Title = "Imported" + } + }; + return capture; + } /// - /// Private helper to find the plugins in the path - /// - /// string - /// IEnumerable with plugin files - private IEnumerable FindPluginsOnPath(string path) + /// Private helper to find the plugins in the path + ///
+ /// string + /// IEnumerable with plugin files + private IEnumerable FindPluginsOnPath(string path) { var pluginFiles = Enumerable.Empty(); if (!Directory.Exists(path)) return pluginFiles; try - { + { pluginFiles = Directory.GetFiles(path, "*Plugin.dll", SearchOption.AllDirectories) - // Skip the GreenshotPlugin.dll itself + // Skip the GreenshotPlugin.dll itself .Where(p => CultureInfo.CurrentCulture.CompareInfo.IndexOf(p, "GreenshotPlugin.dll", CompareOptions.IgnoreCase) < 0); - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Error("Error loading plugin: ", ex); } return pluginFiles; - } - /// - /// Load the plugins - /// - public void LoadPlugins() { - List pluginFiles = new List(); + /// + /// Load the plugins + /// + public void LoadPlugins() + { + List pluginFiles = new List(); - if (IniConfig.IsPortable) { + if (IniConfig.IsPortable) + { pluginFiles.AddRange(FindPluginsOnPath(PafPath)); - } else { + } + else + { pluginFiles.AddRange(FindPluginsOnPath(PluginPath)); pluginFiles.AddRange(FindPluginsOnPath(ApplicationPath)); - } + } - // Loop over the list of available files and get the Plugin Attributes - foreach (string pluginFile in pluginFiles) { - - try { - Assembly assembly = Assembly.LoadFrom(pluginFile); + // Loop over the list of available files and get the Plugin Attributes + foreach (string pluginFile in pluginFiles) + { + try + { + Assembly assembly = Assembly.LoadFrom(pluginFile); var assemblyName = assembly.GetName().Name; - var pluginEntryName = $"{assemblyName}.{assemblyName.Replace("Greenshot", string.Empty)}"; - var pluginEntryType = assembly.GetType(pluginEntryName, false, true); + var pluginEntryName = $"{assemblyName}.{assemblyName.Replace("Greenshot", string.Empty)}"; + var pluginEntryType = assembly.GetType(pluginEntryName, false, true); var pluginAttribute = pluginEntryType.GetCustomAttribute(); if (CoreConfig.ExcludePlugins != null && CoreConfig.ExcludePlugins.Contains(pluginAttribute.Name)) @@ -216,16 +235,15 @@ namespace Greenshot.Helpers { continue; } - IGreenshotPlugin plugin = (IGreenshotPlugin)Activator.CreateInstance(pluginEntryType); + IGreenshotPlugin plugin = (IGreenshotPlugin) Activator.CreateInstance(pluginEntryType); if (plugin != null) { if (plugin.Initialize()) { - SimpleServiceProvider.Current.AddService(plugin); + SimpleServiceProvider.Current.AddService(plugin); } else { - Log.InfoFormat("Plugin {0} not initialized!", pluginAttribute.Name); } } @@ -237,9 +255,9 @@ namespace Greenshot.Helpers { catch (Exception e) { Log.ErrorFormat("Can't load Plugin: {0}", pluginFile); - Log.Error(e); + Log.Error(e); } - } - } + } + } } -} +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/PrintHelper.cs b/src/Greenshot/Helpers/PrintHelper.cs index d04f8e317..6ca6cb068 100644 --- a/src/Greenshot/Helpers/PrintHelper.cs +++ b/src/Greenshot/Helpers/PrintHelper.cs @@ -18,11 +18,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Drawing.Printing; using System.Windows.Forms; - using Greenshot.Configuration; using Greenshot.Forms; using GreenshotPlugin.Core; @@ -32,209 +32,251 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using log4net; -namespace Greenshot.Helpers { - /// - /// Description of PrintHelper. - /// - public class PrintHelper : IDisposable { - private static readonly ILog Log = LogManager.GetLogger(typeof(PrintHelper)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); +namespace Greenshot.Helpers +{ + /// + /// Description of PrintHelper. + /// + public class PrintHelper : IDisposable + { + private static readonly ILog Log = LogManager.GetLogger(typeof(PrintHelper)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private ISurface _surface; - private readonly ICaptureDetails _captureDetails; - private PrintDocument _printDocument = new PrintDocument(); - private PrintDialog _printDialog = new PrintDialog(); + private ISurface _surface; + private readonly ICaptureDetails _captureDetails; + private PrintDocument _printDocument = new PrintDocument(); + private PrintDialog _printDialog = new PrintDialog(); - public PrintHelper(ISurface surface, ICaptureDetails captureDetails) { - _surface = surface; - _captureDetails = captureDetails; - _printDialog.UseEXDialog = true; - _printDocument.DocumentName = FilenameHelper.GetFilenameWithoutExtensionFromPattern(CoreConfig.OutputFileFilenamePattern, captureDetails); - _printDocument.PrintPage += DrawImageForPrint; - _printDialog.Document = _printDocument; - } + public PrintHelper(ISurface surface, ICaptureDetails captureDetails) + { + _surface = surface; + _captureDetails = captureDetails; + _printDialog.UseEXDialog = true; + _printDocument.DocumentName = FilenameHelper.GetFilenameWithoutExtensionFromPattern(CoreConfig.OutputFileFilenamePattern, captureDetails); + _printDocument.PrintPage += DrawImageForPrint; + _printDialog.Document = _printDocument; + } - /** + /** * Destructor */ - ~PrintHelper() { - Dispose(false); - } + ~PrintHelper() + { + Dispose(false); + } - /** + /** * The public accessible Dispose * Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice */ - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - /** + /** * This Dispose is called from the Dispose and the Destructor. * When disposing==true all non-managed resources should be freed too! */ - protected virtual void Dispose(bool disposing) { - if (disposing) { - _printDocument?.Dispose(); - _printDialog?.Dispose(); - } - _surface = null; - _printDocument = null; - _printDialog = null; - } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _printDocument?.Dispose(); + _printDialog?.Dispose(); + } - /// - /// displays options dialog (if not disabled via settings) and windows - /// print dialog. - /// - /// printer settings if actually printed, or null if print was cancelled or has failed - public PrinterSettings PrintTo(string printerName) { - PrinterSettings returnPrinterSettings = null; - DialogResult? printOptionsResult = ShowPrintOptionsDialog(); - try { - if (printOptionsResult == null || printOptionsResult == DialogResult.OK) { - _printDocument.PrinterSettings.PrinterName = printerName; - if (!IsColorPrint()) { - _printDocument.DefaultPageSettings.Color = false; - } - _printDocument.Print(); - returnPrinterSettings = _printDocument.PrinterSettings; - } - } catch (Exception e) { - Log.Error("An error occurred while trying to print", e); - MessageBox.Show(Language.GetString(LangKey.print_error), Language.GetString(LangKey.error)); - } - return returnPrinterSettings; - } + _surface = null; + _printDocument = null; + _printDialog = null; + } - /// - /// displays options dialog (if not disabled via settings) and windows - /// print dialog. - /// - /// printer settings if actually printed, or null if print was cancelled or has failed - public PrinterSettings PrintWithDialog() { - PrinterSettings returnPrinterSettings = null; - if (_printDialog.ShowDialog() != DialogResult.OK) return null; + /// + /// displays options dialog (if not disabled via settings) and windows + /// print dialog. + /// + /// printer settings if actually printed, or null if print was cancelled or has failed + public PrinterSettings PrintTo(string printerName) + { + PrinterSettings returnPrinterSettings = null; + DialogResult? printOptionsResult = ShowPrintOptionsDialog(); + try + { + if (printOptionsResult == null || printOptionsResult == DialogResult.OK) + { + _printDocument.PrinterSettings.PrinterName = printerName; + if (!IsColorPrint()) + { + _printDocument.DefaultPageSettings.Color = false; + } - DialogResult? printOptionsResult = ShowPrintOptionsDialog(); - try { - if (printOptionsResult == null || printOptionsResult == DialogResult.OK) { - if (!IsColorPrint()) { - _printDocument.DefaultPageSettings.Color = false; - } - _printDocument.Print(); - returnPrinterSettings = _printDialog.PrinterSettings; - } - } catch (Exception e) { - Log.Error("An error occurred while trying to print", e); - MessageBox.Show(Language.GetString(LangKey.print_error), Language.GetString(LangKey.error)); - } - return returnPrinterSettings; - } + _printDocument.Print(); + returnPrinterSettings = _printDocument.PrinterSettings; + } + } + catch (Exception e) + { + Log.Error("An error occurred while trying to print", e); + MessageBox.Show(Language.GetString(LangKey.print_error), Language.GetString(LangKey.error)); + } - private bool IsColorPrint() { - return !CoreConfig.OutputPrintGrayscale && !CoreConfig.OutputPrintMonochrome; - } + return returnPrinterSettings; + } - /// - /// display print options dialog (if the user has not configured Greenshot not to) - /// - /// result of the print dialog, or null if the dialog has not been displayed by config - private DialogResult? ShowPrintOptionsDialog() { - DialogResult? ret = null; - if (CoreConfig.OutputPrintPromptOptions) + /// + /// displays options dialog (if not disabled via settings) and windows + /// print dialog. + /// + /// printer settings if actually printed, or null if print was cancelled or has failed + public PrinterSettings PrintWithDialog() + { + PrinterSettings returnPrinterSettings = null; + if (_printDialog.ShowDialog() != DialogResult.OK) return null; + + DialogResult? printOptionsResult = ShowPrintOptionsDialog(); + try + { + if (printOptionsResult == null || printOptionsResult == DialogResult.OK) + { + if (!IsColorPrint()) + { + _printDocument.DefaultPageSettings.Color = false; + } + + _printDocument.Print(); + returnPrinterSettings = _printDialog.PrinterSettings; + } + } + catch (Exception e) + { + Log.Error("An error occurred while trying to print", e); + MessageBox.Show(Language.GetString(LangKey.print_error), Language.GetString(LangKey.error)); + } + + return returnPrinterSettings; + } + + private bool IsColorPrint() + { + return !CoreConfig.OutputPrintGrayscale && !CoreConfig.OutputPrintMonochrome; + } + + /// + /// display print options dialog (if the user has not configured Greenshot not to) + /// + /// result of the print dialog, or null if the dialog has not been displayed by config + private DialogResult? ShowPrintOptionsDialog() + { + DialogResult? ret = null; + if (CoreConfig.OutputPrintPromptOptions) { using PrintOptionsDialog printOptionsDialog = new PrintOptionsDialog(); ret = printOptionsDialog.ShowDialog(); - } - return ret; - } + } - private void DrawImageForPrint(object sender, PrintPageEventArgs e) { - // Create the output settings - SurfaceOutputSettings printOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); + return ret; + } - ApplyEffects(printOutputSettings); + private void DrawImageForPrint(object sender, PrintPageEventArgs e) + { + // Create the output settings + SurfaceOutputSettings printOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); + + ApplyEffects(printOutputSettings); bool disposeImage = ImageOutput.CreateImageFromSurface(_surface, printOutputSettings, out var image); - try { - ContentAlignment alignment = CoreConfig.OutputPrintCenter ? ContentAlignment.MiddleCenter : ContentAlignment.TopLeft; + try + { + ContentAlignment alignment = CoreConfig.OutputPrintCenter ? ContentAlignment.MiddleCenter : ContentAlignment.TopLeft; - // prepare timestamp - float footerStringWidth = 0; - float footerStringHeight = 0; - string footerString = null; //DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString(); - if (CoreConfig.OutputPrintFooter) { - footerString = FilenameHelper.FillPattern(CoreConfig.OutputPrintFooterPattern, _captureDetails, false); + // prepare timestamp + float footerStringWidth = 0; + float footerStringHeight = 0; + string footerString = null; //DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString(); + if (CoreConfig.OutputPrintFooter) + { + footerString = FilenameHelper.FillPattern(CoreConfig.OutputPrintFooterPattern, _captureDetails, false); using Font f = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular); footerStringWidth = e.Graphics.MeasureString(footerString, f).Width; footerStringHeight = e.Graphics.MeasureString(footerString, f).Height; } - // Get a rectangle representing the printable Area - RectangleF pageRect = e.PageSettings.PrintableArea; - if(e.PageSettings.Landscape) { - float origWidth = pageRect.Width; - pageRect.Width = pageRect.Height; - pageRect.Height = origWidth; - } + // Get a rectangle representing the printable Area + RectangleF pageRect = e.PageSettings.PrintableArea; + if (e.PageSettings.Landscape) + { + float origWidth = pageRect.Width; + pageRect.Width = pageRect.Height; + pageRect.Height = origWidth; + } - // Subtract the dateString height from the available area, this way the area stays free - pageRect.Height -= footerStringHeight; + // Subtract the dateString height from the available area, this way the area stays free + pageRect.Height -= footerStringHeight; - GraphicsUnit gu = GraphicsUnit.Pixel; - RectangleF imageRect = image.GetBounds(ref gu); - // rotate the image if it fits the page better - if (CoreConfig.OutputPrintAllowRotate) { - if (pageRect.Width > pageRect.Height && imageRect.Width < imageRect.Height || pageRect.Width < pageRect.Height && imageRect.Width > imageRect.Height) { - image.RotateFlip(RotateFlipType.Rotate270FlipNone); - imageRect = image.GetBounds(ref gu); - if (alignment.Equals(ContentAlignment.TopLeft)) { - alignment = ContentAlignment.TopRight; - } - } - } + GraphicsUnit gu = GraphicsUnit.Pixel; + RectangleF imageRect = image.GetBounds(ref gu); + // rotate the image if it fits the page better + if (CoreConfig.OutputPrintAllowRotate) + { + if (pageRect.Width > pageRect.Height && imageRect.Width < imageRect.Height || pageRect.Width < pageRect.Height && imageRect.Width > imageRect.Height) + { + image.RotateFlip(RotateFlipType.Rotate270FlipNone); + imageRect = image.GetBounds(ref gu); + if (alignment.Equals(ContentAlignment.TopLeft)) + { + alignment = ContentAlignment.TopRight; + } + } + } - RectangleF printRect = new RectangleF(0, 0, imageRect.Width, imageRect.Height); - // scale the image to fit the page better - if (CoreConfig.OutputPrintAllowEnlarge || CoreConfig.OutputPrintAllowShrink) { - SizeF resizedRect = ScaleHelper.GetScaledSize(imageRect.Size, pageRect.Size, false); - if (CoreConfig.OutputPrintAllowShrink && resizedRect.Width < printRect.Width || CoreConfig.OutputPrintAllowEnlarge && resizedRect.Width > printRect.Width) { - printRect.Size = resizedRect; - } - } + RectangleF printRect = new RectangleF(0, 0, imageRect.Width, imageRect.Height); + // scale the image to fit the page better + if (CoreConfig.OutputPrintAllowEnlarge || CoreConfig.OutputPrintAllowShrink) + { + SizeF resizedRect = ScaleHelper.GetScaledSize(imageRect.Size, pageRect.Size, false); + if (CoreConfig.OutputPrintAllowShrink && resizedRect.Width < printRect.Width || CoreConfig.OutputPrintAllowEnlarge && resizedRect.Width > printRect.Width) + { + printRect.Size = resizedRect; + } + } - // align the image - printRect = ScaleHelper.GetAlignedRectangle(printRect, new RectangleF(0, 0, pageRect.Width, pageRect.Height), alignment); - if (CoreConfig.OutputPrintFooter) + // align the image + printRect = ScaleHelper.GetAlignedRectangle(printRect, new RectangleF(0, 0, pageRect.Width, pageRect.Height), alignment); + if (CoreConfig.OutputPrintFooter) { //printRect = new RectangleF(0, 0, printRect.Width, printRect.Height - (dateStringHeight * 2)); using Font f = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular); e.Graphics.DrawString(footerString, f, Brushes.Black, pageRect.Width / 2 - footerStringWidth / 2, pageRect.Height); } - e.Graphics.DrawImage(image, printRect, imageRect, GraphicsUnit.Pixel); - } finally { - if (disposeImage) { - image?.Dispose(); - } - } - } + e.Graphics.DrawImage(image, printRect, imageRect, GraphicsUnit.Pixel); + } + finally + { + if (disposeImage) + { + image?.Dispose(); + } + } + } - private void ApplyEffects(SurfaceOutputSettings printOutputSettings) { - // TODO: - // add effects here - if (CoreConfig.OutputPrintMonochrome) { - byte threshold = CoreConfig.OutputPrintMonochromeThreshold; - printOutputSettings.Effects.Add(new MonochromeEffect(threshold)); - printOutputSettings.ReduceColors = true; - } + private void ApplyEffects(SurfaceOutputSettings printOutputSettings) + { + // TODO: + // add effects here + if (CoreConfig.OutputPrintMonochrome) + { + byte threshold = CoreConfig.OutputPrintMonochromeThreshold; + printOutputSettings.Effects.Add(new MonochromeEffect(threshold)); + printOutputSettings.ReduceColors = true; + } - // the invert effect should probably be the last - if (CoreConfig.OutputPrintInverted) { - printOutputSettings.Effects.Add(new InvertEffect()); - } - } - } -} + // the invert effect should probably be the last + if (CoreConfig.OutputPrintInverted) + { + printOutputSettings.Effects.Add(new InvertEffect()); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/ProcessorHelper.cs b/src/Greenshot/Helpers/ProcessorHelper.cs index 25598944a..d43473103 100644 --- a/src/Greenshot/Helpers/ProcessorHelper.cs +++ b/src/Greenshot/Helpers/ProcessorHelper.cs @@ -18,48 +18,66 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces; using log4net; -namespace Greenshot.Helpers { - /// - /// Description of ProcessorHelper. - /// - public static class ProcessorHelper { - private static readonly ILog LOG = LogManager.GetLogger(typeof(ProcessorHelper)); +namespace Greenshot.Helpers +{ + /// + /// Description of ProcessorHelper. + /// + public static class ProcessorHelper + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(ProcessorHelper)); - /// - /// Register the internal processors - /// - public static void RegisterInternalProcessors() { - foreach(Type processorType in InterfaceUtils.GetSubclassesOf(typeof(IProcessor),true)) { - // Only take our own - if (!"Greenshot.Processors".Equals(processorType.Namespace)) { - continue; - } - try { - if (!processorType.IsAbstract) { - IProcessor processor; - try { - processor = (IProcessor)Activator.CreateInstance(processorType); - } catch (Exception e) { - LOG.ErrorFormat("Can't create instance of {0}", processorType); - LOG.Error(e); - continue; - } - if (processor.isActive) { - LOG.DebugFormat("Found Processor {0} with designation {1}", processorType.Name, processor.Designation); - SimpleServiceProvider.Current.AddService(processor); - } else { - LOG.DebugFormat("Ignoring Processor {0} with designation {1}", processorType.Name, processor.Designation); - } - } - } catch (Exception ex) { - LOG.ErrorFormat("Error loading processor {0}, message: ", processorType.FullName, ex.Message); - } - } - } - } -} + /// + /// Register the internal processors + /// + public static void RegisterInternalProcessors() + { + foreach (Type processorType in InterfaceUtils.GetSubclassesOf(typeof(IProcessor), true)) + { + // Only take our own + if (!"Greenshot.Processors".Equals(processorType.Namespace)) + { + continue; + } + + try + { + if (!processorType.IsAbstract) + { + IProcessor processor; + try + { + processor = (IProcessor) Activator.CreateInstance(processorType); + } + catch (Exception e) + { + LOG.ErrorFormat("Can't create instance of {0}", processorType); + LOG.Error(e); + continue; + } + + if (processor.isActive) + { + LOG.DebugFormat("Found Processor {0} with designation {1}", processorType.Name, processor.Designation); + SimpleServiceProvider.Current.AddService(processor); + } + else + { + LOG.DebugFormat("Ignoring Processor {0} with designation {1}", processorType.Name, processor.Designation); + } + } + } + catch (Exception ex) + { + LOG.ErrorFormat("Error loading processor {0}, message: ", processorType.FullName, ex.Message); + } + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/ResourceMutex.cs b/src/Greenshot/Helpers/ResourceMutex.cs index 9854c3dca..9ffb4b3d9 100644 --- a/src/Greenshot/Helpers/ResourceMutex.cs +++ b/src/Greenshot/Helpers/ResourceMutex.cs @@ -27,149 +27,151 @@ using System.Threading; namespace Greenshot.Helpers { - /// - /// This protects your resources or application from running more than once - /// Simplifies the usage of the Mutex class, as described here: - /// https://msdn.microsoft.com/en-us/library/System.Threading.Mutex.aspx - /// - public class ResourceMutex : IDisposable - { - private static readonly ILog Log = LogManager.GetLogger(typeof(ResourceMutex)); - private readonly string _mutexId; - private readonly string _resourceName; - private Mutex _applicationMutex; + /// + /// This protects your resources or application from running more than once + /// Simplifies the usage of the Mutex class, as described here: + /// https://msdn.microsoft.com/en-us/library/System.Threading.Mutex.aspx + /// + public class ResourceMutex : IDisposable + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ResourceMutex)); + private readonly string _mutexId; + private readonly string _resourceName; + private Mutex _applicationMutex; - /// - /// Private constructor - /// - /// - /// - private ResourceMutex(string mutexId, string resourceName = null) - { - _mutexId = mutexId; - _resourceName = resourceName ?? "some resource"; - } + /// + /// Private constructor + /// + /// + /// + private ResourceMutex(string mutexId, string resourceName = null) + { + _mutexId = mutexId; + _resourceName = resourceName ?? "some resource"; + } - /// - /// Test if the Mutex was created and locked. - /// - public bool IsLocked { get; set; } + /// + /// Test if the Mutex was created and locked. + /// + public bool IsLocked { get; set; } - /// - /// Create a ResourceMutex for the specified mutex id and resource-name - /// - /// ID of the mutex, preferably a Guid as string - /// Name of the resource to lock, e.g your application name, usefull for logs - /// true to have a global mutex see: https://msdn.microsoft.com/en-us/library/bwe34f1k.aspx - public static ResourceMutex Create(string mutexId, string resourceName = null, bool global = false) - { - var applicationMutex = new ResourceMutex((global ? @"Global\" : @"Local\") + mutexId, resourceName); - applicationMutex.Lock(); - return applicationMutex; - } + /// + /// Create a ResourceMutex for the specified mutex id and resource-name + /// + /// ID of the mutex, preferably a Guid as string + /// Name of the resource to lock, e.g your application name, usefull for logs + /// true to have a global mutex see: https://msdn.microsoft.com/en-us/library/bwe34f1k.aspx + public static ResourceMutex Create(string mutexId, string resourceName = null, bool global = false) + { + var applicationMutex = new ResourceMutex((global ? @"Global\" : @"Local\") + mutexId, resourceName); + applicationMutex.Lock(); + return applicationMutex; + } - /// - /// This tries to get the Mutex, which takes care of having multiple instances running - /// - /// true if it worked, false if another instance is already running or something went wrong - public bool Lock() - { - Log.DebugFormat("{0} is trying to get Mutex {1}", _resourceName, _mutexId); + /// + /// This tries to get the Mutex, which takes care of having multiple instances running + /// + /// true if it worked, false if another instance is already running or something went wrong + public bool Lock() + { + Log.DebugFormat("{0} is trying to get Mutex {1}", _resourceName, _mutexId); - IsLocked = true; - // check whether there's an local instance running already, but use local so this works in a multi-user environment - try - { - // Added Mutex Security, hopefully this prevents the UnauthorizedAccessException more gracefully - var sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null); - var mutexSecurity = new MutexSecurity(); - mutexSecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.FullControl, AccessControlType.Allow)); - mutexSecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.ChangePermissions, AccessControlType.Deny)); - mutexSecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.Delete, AccessControlType.Deny)); + IsLocked = true; + // check whether there's an local instance running already, but use local so this works in a multi-user environment + try + { + // Added Mutex Security, hopefully this prevents the UnauthorizedAccessException more gracefully + var sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null); + var mutexSecurity = new MutexSecurity(); + mutexSecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.FullControl, AccessControlType.Allow)); + mutexSecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.ChangePermissions, AccessControlType.Deny)); + mutexSecurity.AddAccessRule(new MutexAccessRule(sid, MutexRights.Delete, AccessControlType.Deny)); // 1) Create Mutex - _applicationMutex = new Mutex(true, _mutexId, out var createdNew, mutexSecurity); - // 2) if the mutex wasn't created new get the right to it, this returns false if it's already locked - if (!createdNew && !_applicationMutex.WaitOne(100, false)) - { - Log.InfoFormat("{0} is already in use, mutex {1} is NOT locked for the caller", _resourceName, _mutexId); - IsLocked = false; - // Clean up - _applicationMutex.Close(); - _applicationMutex = null; - } - else - { - Log.InfoFormat(createdNew ? "{0} has created & claimed the mutex {1}" : "{0} has claimed the mutex {1}", _resourceName, _mutexId); - } - } - catch (AbandonedMutexException e) - { - // Another instance didn't cleanup correctly! - // we can ignore the exception, it happened on the "waitOne" but still the mutex belongs to us - Log.WarnFormat("{0} didn't cleanup correctly, but we got the mutex {1}.", _resourceName, _mutexId); - Log.Warn(e); - } - catch (UnauthorizedAccessException e) - { - Log.ErrorFormat("{0} is most likely already running for a different user in the same session, can't create/get mutex {1} due to error.", _resourceName, _mutexId); - Log.Error(e); - IsLocked = false; - } - catch (Exception ex) - { - Log.ErrorFormat("Problem obtaining the Mutex {1} for {0}, assuming it was already taken!", _resourceName, _mutexId); - Log.Error(ex); - IsLocked = false; - } - return IsLocked; - } + _applicationMutex = new Mutex(true, _mutexId, out var createdNew, mutexSecurity); + // 2) if the mutex wasn't created new get the right to it, this returns false if it's already locked + if (!createdNew && !_applicationMutex.WaitOne(100, false)) + { + Log.InfoFormat("{0} is already in use, mutex {1} is NOT locked for the caller", _resourceName, _mutexId); + IsLocked = false; + // Clean up + _applicationMutex.Close(); + _applicationMutex = null; + } + else + { + Log.InfoFormat(createdNew ? "{0} has created & claimed the mutex {1}" : "{0} has claimed the mutex {1}", _resourceName, _mutexId); + } + } + catch (AbandonedMutexException e) + { + // Another instance didn't cleanup correctly! + // we can ignore the exception, it happened on the "waitOne" but still the mutex belongs to us + Log.WarnFormat("{0} didn't cleanup correctly, but we got the mutex {1}.", _resourceName, _mutexId); + Log.Warn(e); + } + catch (UnauthorizedAccessException e) + { + Log.ErrorFormat("{0} is most likely already running for a different user in the same session, can't create/get mutex {1} due to error.", _resourceName, _mutexId); + Log.Error(e); + IsLocked = false; + } + catch (Exception ex) + { + Log.ErrorFormat("Problem obtaining the Mutex {1} for {0}, assuming it was already taken!", _resourceName, _mutexId); + Log.Error(ex); + IsLocked = false; + } + + return IsLocked; + } // To detect redundant Dispose calls - private bool _disposedValue; + private bool _disposedValue; - /// - /// The real disposing code - /// - /// true if dispose is called, false when the finalizer is called - protected void Dispose(bool disposing) - { - if (_disposedValue) return; - - if (_applicationMutex != null) - { - try - { - _applicationMutex.ReleaseMutex(); - _applicationMutex = null; - Log.InfoFormat("Released Mutex {0} for {1}", _mutexId, _resourceName); - } - catch (Exception ex) - { - Log.ErrorFormat("Error releasing Mutex {0} for {1}", _mutexId, _resourceName); - Log.Error(ex); - } - } - _disposedValue = true; - } + /// + /// The real disposing code + /// + /// true if dispose is called, false when the finalizer is called + protected void Dispose(bool disposing) + { + if (_disposedValue) return; - /// - /// Make sure the ApplicationMutex is disposed when the finalizer is called - /// - ~ResourceMutex() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(false); - } + if (_applicationMutex != null) + { + try + { + _applicationMutex.ReleaseMutex(); + _applicationMutex = null; + Log.InfoFormat("Released Mutex {0} for {1}", _mutexId, _resourceName); + } + catch (Exception ex) + { + Log.ErrorFormat("Error releasing Mutex {0} for {1}", _mutexId, _resourceName); + Log.Error(ex); + } + } - /// - /// The dispose interface, which calls Dispose(true) to signal that dispose is called. - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - GC.SuppressFinalize(this); - } + _disposedValue = true; + } + + /// + /// Make sure the ApplicationMutex is disposed when the finalizer is called + /// + ~ResourceMutex() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(false); + } + + /// + /// The dispose interface, which calls Dispose(true) to signal that dispose is called. + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + GC.SuppressFinalize(this); + } } } \ No newline at end of file diff --git a/src/Greenshot/Helpers/ScaleHelper.cs b/src/Greenshot/Helpers/ScaleHelper.cs index 08956a5c5..fc7ba17fe 100644 --- a/src/Greenshot/Helpers/ScaleHelper.cs +++ b/src/Greenshot/Helpers/ScaleHelper.cs @@ -18,322 +18,354 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Windows.Forms; using Greenshot.Drawing; -namespace Greenshot.Helpers { - /// - /// Offers a few helper functions for scaling/aligning an element with another element - /// - public static class ScaleHelper { - - [Flags] - public enum ScaleOptions { - /// - /// Default scale behavior. - /// - Default = 0x00, - /// - /// Scale a rectangle in two our four directions, mirrored at it's center coordinates - /// - Centered = 0x01, - /// - /// Scale a rectangle maintaining it's aspect ratio - /// - Rational = 0x02 - } +namespace Greenshot.Helpers +{ + /// + /// Offers a few helper functions for scaling/aligning an element with another element + /// + public static class ScaleHelper + { + [Flags] + public enum ScaleOptions + { + /// + /// Default scale behavior. + /// + Default = 0x00, - /// - /// calculates the Size an element must be resized to, in order to fit another element, keeping aspect ratio - /// - /// the size of the element to be resized - /// the target size of the element - /// in case the aspect ratio of currentSize and targetSize differs: shall the scaled size fit into targetSize (i.e. that one of its dimensions is smaller - false) or vice versa (true) - /// a new SizeF object indicating the width and height the element should be scaled to - public static SizeF GetScaledSize(SizeF currentSize, SizeF targetSize, bool crop) { - float wFactor = targetSize.Width/currentSize.Width; - float hFactor = targetSize.Height/currentSize.Height; - - float factor = crop ? Math.Max(wFactor, hFactor) : Math.Min(wFactor, hFactor); - return new SizeF(currentSize.Width * factor, currentSize.Height * factor); - } - - /// - /// calculates the position of an element depending on the desired alignment within a RectangleF - /// - /// the bounds of the element to be aligned - /// the rectangle reference for alignment of the element - /// the System.Drawing.ContentAlignment value indicating how the element is to be aligned should the width or height differ from targetSize - /// a new RectangleF object with Location aligned aligned to targetRect - public static RectangleF GetAlignedRectangle(RectangleF currentRect, RectangleF targetRect, ContentAlignment alignment) { - RectangleF newRect = new RectangleF(targetRect.Location, currentRect.Size); - switch(alignment) { - case ContentAlignment.TopCenter: - newRect.X = (targetRect.Width - currentRect.Width) / 2; - break; - case ContentAlignment.TopRight: - newRect.X = targetRect.Width - currentRect.Width; - break; - case ContentAlignment.MiddleLeft: - newRect.Y = (targetRect.Height - currentRect.Height) / 2; - break; - case ContentAlignment.MiddleCenter: - newRect.Y = (targetRect.Height - currentRect.Height) / 2; - newRect.X = (targetRect.Width - currentRect.Width) / 2; - break; - case ContentAlignment.MiddleRight: - newRect.Y = (targetRect.Height - currentRect.Height) / 2; - newRect.X = targetRect.Width - currentRect.Width; - break; - case ContentAlignment.BottomLeft: - newRect.Y = targetRect.Height - currentRect.Height; - break; - case ContentAlignment.BottomCenter: - newRect.Y = targetRect.Height - currentRect.Height; - newRect.X = (targetRect.Width - currentRect.Width) / 2; - break; - case ContentAlignment.BottomRight: - newRect.Y = targetRect.Height - currentRect.Height; - newRect.X = targetRect.Width - currentRect.Width; - break; - } - return newRect; - } + /// + /// Scale a rectangle in two our four directions, mirrored at it's center coordinates + /// + Centered = 0x01, + + /// + /// Scale a rectangle maintaining it's aspect ratio + /// + Rational = 0x02 + } /// - /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) - /// - /// bounds of the current rectangle, scaled values will be written to this reference - /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT - /// coordinates of the used handle/gripper - /// ScaleOptions to use when scaling - public static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords, ScaleOptions? options) { - options ??= GetScaleOptions(); - - if ((options & ScaleOptions.Rational) == ScaleOptions.Rational) { - AdjustCoordsForRationalScale(originalRectangle, resizeHandlePosition, ref resizeHandleCoords); - } + /// calculates the Size an element must be resized to, in order to fit another element, keeping aspect ratio + ///
+ /// the size of the element to be resized + /// the target size of the element + /// in case the aspect ratio of currentSize and targetSize differs: shall the scaled size fit into targetSize (i.e. that one of its dimensions is smaller - false) or vice versa (true) + /// a new SizeF object indicating the width and height the element should be scaled to + public static SizeF GetScaledSize(SizeF currentSize, SizeF targetSize, bool crop) + { + float wFactor = targetSize.Width / currentSize.Width; + float hFactor = targetSize.Height / currentSize.Height; - if ((options & ScaleOptions.Centered) == ScaleOptions.Centered) { - // store center coordinates of rectangle - float rectCenterX = originalRectangle.Left + originalRectangle.Width / 2; - float rectCenterY = originalRectangle.Top + originalRectangle.Height / 2; - // scale rectangle using handle coordinates - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); - // mirror handle coordinates via rectangle center coordinates - resizeHandleCoords.X -= 2 * (resizeHandleCoords.X - rectCenterX); - resizeHandleCoords.Y -= 2 * (resizeHandleCoords.Y - rectCenterY); - // scale again with opposing handle and mirrored coordinates - resizeHandlePosition = (Positions)((((int)resizeHandlePosition) + 4) % 8); - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); - } else { - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); - } - - } - - /// - /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) - /// - /// bounds of the current rectangle, scaled values will be written to this reference - /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT - /// coordinates of the used handle/gripper - private static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) { - switch(resizeHandlePosition) { - - case Positions.TopLeft: - originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; - originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; - originalRectangle.X = resizeHandleCoords.X; - originalRectangle.Y = resizeHandleCoords.Y; - break; - - case Positions.TopCenter: - originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; - originalRectangle.Y = resizeHandleCoords.Y; - break; - - case Positions.TopRight: - originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; - originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; - originalRectangle.Y = resizeHandleCoords.Y; - break; - - case Positions.MiddleLeft: - originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; - originalRectangle.X = resizeHandleCoords.X; - break; - - case Positions.MiddleRight: - originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; - break; - - case Positions.BottomLeft: - originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; - originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; - originalRectangle.X = resizeHandleCoords.X; - break; - - case Positions.BottomCenter: - originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; - break; - - case Positions.BottomRight: - originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; - originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; - break; - - default: - throw new ArgumentException("Position cannot be handled: "+resizeHandlePosition); - - } - } + float factor = crop ? Math.Max(wFactor, hFactor) : Math.Min(wFactor, hFactor); + return new SizeF(currentSize.Width * factor, currentSize.Height * factor); + } - /// - /// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments. + /// + /// calculates the position of an element depending on the desired alignment within a RectangleF + /// + /// the bounds of the element to be aligned + /// the rectangle reference for alignment of the element + /// the System.Drawing.ContentAlignment value indicating how the element is to be aligned should the width or height differ from targetSize + /// a new RectangleF object with Location aligned aligned to targetRect + public static RectangleF GetAlignedRectangle(RectangleF currentRect, RectangleF targetRect, ContentAlignment alignment) + { + RectangleF newRect = new RectangleF(targetRect.Location, currentRect.Size); + switch (alignment) + { + case ContentAlignment.TopCenter: + newRect.X = (targetRect.Width - currentRect.Width) / 2; + break; + case ContentAlignment.TopRight: + newRect.X = targetRect.Width - currentRect.Width; + break; + case ContentAlignment.MiddleLeft: + newRect.Y = (targetRect.Height - currentRect.Height) / 2; + break; + case ContentAlignment.MiddleCenter: + newRect.Y = (targetRect.Height - currentRect.Height) / 2; + newRect.X = (targetRect.Width - currentRect.Width) / 2; + break; + case ContentAlignment.MiddleRight: + newRect.Y = (targetRect.Height - currentRect.Height) / 2; + newRect.X = targetRect.Width - currentRect.Width; + break; + case ContentAlignment.BottomLeft: + newRect.Y = targetRect.Height - currentRect.Height; + break; + case ContentAlignment.BottomCenter: + newRect.Y = targetRect.Height - currentRect.Height; + newRect.X = (targetRect.Width - currentRect.Width) / 2; + break; + case ContentAlignment.BottomRight: + newRect.Y = targetRect.Height - currentRect.Height; + newRect.X = targetRect.Width - currentRect.Width; + break; + } + + return newRect; + } + + /// + /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) + /// + /// bounds of the current rectangle, scaled values will be written to this reference + /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT + /// coordinates of the used handle/gripper + /// ScaleOptions to use when scaling + public static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords, ScaleOptions? options) + { + options ??= GetScaleOptions(); + + if ((options & ScaleOptions.Rational) == ScaleOptions.Rational) + { + AdjustCoordsForRationalScale(originalRectangle, resizeHandlePosition, ref resizeHandleCoords); + } + + if ((options & ScaleOptions.Centered) == ScaleOptions.Centered) + { + // store center coordinates of rectangle + float rectCenterX = originalRectangle.Left + originalRectangle.Width / 2; + float rectCenterY = originalRectangle.Top + originalRectangle.Height / 2; + // scale rectangle using handle coordinates + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + // mirror handle coordinates via rectangle center coordinates + resizeHandleCoords.X -= 2 * (resizeHandleCoords.X - rectCenterX); + resizeHandleCoords.Y -= 2 * (resizeHandleCoords.Y - rectCenterY); + // scale again with opposing handle and mirrored coordinates + resizeHandlePosition = (Positions) ((((int) resizeHandlePosition) + 4) % 8); + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + } + else + { + Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + } + } + + /// + /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) + /// + /// bounds of the current rectangle, scaled values will be written to this reference + /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT + /// coordinates of the used handle/gripper + private static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) + { + switch (resizeHandlePosition) + { + case Positions.TopLeft: + originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; + originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; + originalRectangle.X = resizeHandleCoords.X; + originalRectangle.Y = resizeHandleCoords.Y; + break; + + case Positions.TopCenter: + originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; + originalRectangle.Y = resizeHandleCoords.Y; + break; + + case Positions.TopRight: + originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; + originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; + originalRectangle.Y = resizeHandleCoords.Y; + break; + + case Positions.MiddleLeft: + originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; + originalRectangle.X = resizeHandleCoords.X; + break; + + case Positions.MiddleRight: + originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; + break; + + case Positions.BottomLeft: + originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; + originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + originalRectangle.X = resizeHandleCoords.X; + break; + + case Positions.BottomCenter: + originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + break; + + case Positions.BottomRight: + originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; + originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + break; + + default: + throw new ArgumentException("Position cannot be handled: " + resizeHandlePosition); + } + } + + /// + /// Adjusts resizeHandleCoords so that aspect ratio is kept after resizing a given rectangle with provided arguments. /// An adjustment can always be done in two ways, e.g. *in*crease width until fit or *de*crease height until fit. /// To avoid objects growing near infinity unexpectedly in certain combinations, the adjustment will choose the /// option resulting in the smaller rectangle. - /// - /// bounds of the current rectangle - /// position of the handle/gripper being used for resized, see Position - /// coordinates of the used handle/gripper, adjusted coordinates will be written to this reference - private static void AdjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) { - SizeF selectedRectangle, newSize; + /// + /// bounds of the current rectangle + /// position of the handle/gripper being used for resized, see Position + /// coordinates of the used handle/gripper, adjusted coordinates will be written to this reference + private static void AdjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) + { + SizeF selectedRectangle, newSize; - switch(resizeHandlePosition) { - - case Positions.TopLeft: - selectedRectangle = new SizeF(originalRectangle.Right - resizeHandleCoords.X, originalRectangle.Bottom - resizeHandleCoords.Y); - newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); - resizeHandleCoords.X = originalRectangle.Right - newSize.Width; - resizeHandleCoords.Y = originalRectangle.Bottom - newSize.Height; - break; - - case Positions.TopRight: - selectedRectangle = new SizeF(resizeHandleCoords.X - originalRectangle.Left, originalRectangle.Bottom - resizeHandleCoords.Y); - newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); - resizeHandleCoords.X = originalRectangle.Left + newSize.Width; - resizeHandleCoords.Y = originalRectangle.Bottom - newSize.Height; + switch (resizeHandlePosition) + { + case Positions.TopLeft: + selectedRectangle = new SizeF(originalRectangle.Right - resizeHandleCoords.X, originalRectangle.Bottom - resizeHandleCoords.Y); + newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); + resizeHandleCoords.X = originalRectangle.Right - newSize.Width; + resizeHandleCoords.Y = originalRectangle.Bottom - newSize.Height; break; - - case Positions.BottomLeft: - selectedRectangle = new SizeF(originalRectangle.Right - resizeHandleCoords.X, resizeHandleCoords.Y - originalRectangle.Top); - newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); - resizeHandleCoords.X = originalRectangle.Right - newSize.Width; - resizeHandleCoords.Y = originalRectangle.Top + newSize.Height; + + case Positions.TopRight: + selectedRectangle = new SizeF(resizeHandleCoords.X - originalRectangle.Left, originalRectangle.Bottom - resizeHandleCoords.Y); + newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); + resizeHandleCoords.X = originalRectangle.Left + newSize.Width; + resizeHandleCoords.Y = originalRectangle.Bottom - newSize.Height; break; - - case Positions.BottomRight: - selectedRectangle = new SizeF(resizeHandleCoords.X - originalRectangle.Left, resizeHandleCoords.Y - originalRectangle.Top); - newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); - resizeHandleCoords.X = originalRectangle.Left + newSize.Width; - resizeHandleCoords.Y = originalRectangle.Top + newSize.Height; + + case Positions.BottomLeft: + selectedRectangle = new SizeF(originalRectangle.Right - resizeHandleCoords.X, resizeHandleCoords.Y - originalRectangle.Top); + newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); + resizeHandleCoords.X = originalRectangle.Right - newSize.Width; + resizeHandleCoords.Y = originalRectangle.Top + newSize.Height; break; - } - } - /// - /// For an original size, and a selected size, returns the the largest possible size that - /// * has the same aspect ratio as the original - /// * fits into selected size - /// - /// size to be considered for keeping aspect ratio - /// selection size (i.e. the size we'd produce if we wouldn't keep aspect ratio) - /// - private static SizeF GetNewSizeForRationalScale(SizeF originalSize, SizeF selectedSize) - { - SizeF newSize = selectedSize; - float originalRatio = originalSize.Width / originalSize.Height; - float selectedRatio = selectedSize.Width / selectedSize.Height; - // will fix orientation if the scaling causes size to be flipped in any direction - int flippedRatioSign = Math.Sign(selectedRatio) * Math.Sign(originalRatio); - if (Math.Abs(selectedRatio) > Math.Abs(originalRatio)) - { - // scaled rectangle (ratio) would be wider than original - // keep height and tweak width to maintain aspect ratio - newSize.Width = selectedSize.Height * originalRatio * flippedRatioSign; - } - else if (Math.Abs(selectedRatio) < Math.Abs(originalRatio)) - { - // scaled rectangle (ratio) would be taller than original - // keep width and tweak height to maintain aspect ratio - newSize.Height = selectedSize.Width / originalRatio * flippedRatioSign; - } - return newSize; - } + case Positions.BottomRight: + selectedRectangle = new SizeF(resizeHandleCoords.X - originalRectangle.Left, resizeHandleCoords.Y - originalRectangle.Top); + newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); + resizeHandleCoords.X = originalRectangle.Left + newSize.Width; + resizeHandleCoords.Y = originalRectangle.Top + newSize.Height; + break; + } + } - public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize) { - Scale(boundsBeforeResize, cursorX, cursorY, ref boundsAfterResize, null); - } - - public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) { - - Scale(boundsBeforeResize, Positions.TopLeft, cursorX, cursorY, ref boundsAfterResize, angleRoundBehavior); - } - - public static void Scale(Rectangle boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) { - - ScaleOptions opts = GetScaleOptions(); - - bool rationalScale = (opts & ScaleOptions.Rational) == ScaleOptions.Rational; - bool centeredScale = (opts & ScaleOptions.Centered) == ScaleOptions.Centered; - - if(rationalScale) { - double angle = GeometryHelper.Angle2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); - - if(angleRoundBehavior != null) { - angle = angleRoundBehavior.Process(angle); - } - - int dist = GeometryHelper.Distance2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); - - boundsAfterResize.Width = (int)Math.Round(dist * Math.Cos(angle / 180 * Math.PI)); - boundsAfterResize.Height = (int)Math.Round(dist * Math.Sin(angle / 180 * Math.PI)); - } - - if(centeredScale) { - float wdiff = boundsAfterResize.Width - boundsBeforeResize.Width; - float hdiff = boundsAfterResize.Height - boundsBeforeResize.Height; - boundsAfterResize.Width += wdiff; - boundsAfterResize.Height += hdiff; - boundsAfterResize.X -= wdiff; - boundsAfterResize.Y -= hdiff; - } - + /// + /// For an original size, and a selected size, returns the the largest possible size that + /// * has the same aspect ratio as the original + /// * fits into selected size + /// + /// size to be considered for keeping aspect ratio + /// selection size (i.e. the size we'd produce if we wouldn't keep aspect ratio) + /// + private static SizeF GetNewSizeForRationalScale(SizeF originalSize, SizeF selectedSize) + { + SizeF newSize = selectedSize; + float originalRatio = originalSize.Width / originalSize.Height; + float selectedRatio = selectedSize.Width / selectedSize.Height; + // will fix orientation if the scaling causes size to be flipped in any direction + int flippedRatioSign = Math.Sign(selectedRatio) * Math.Sign(originalRatio); + if (Math.Abs(selectedRatio) > Math.Abs(originalRatio)) + { + // scaled rectangle (ratio) would be wider than original + // keep height and tweak width to maintain aspect ratio + newSize.Width = selectedSize.Height * originalRatio * flippedRatioSign; + } + else if (Math.Abs(selectedRatio) < Math.Abs(originalRatio)) + { + // scaled rectangle (ratio) would be taller than original + // keep width and tweak height to maintain aspect ratio + newSize.Height = selectedSize.Width / originalRatio * flippedRatioSign; + } - } - - /// the current ScaleOptions depending on modifier keys held down - public static ScaleOptions GetScaleOptions() { - bool anchorAtCenter = (Control.ModifierKeys & Keys.Control) != 0; - bool maintainAspectRatio = (Control.ModifierKeys & Keys.Shift) != 0; - ScaleOptions opts = ScaleOptions.Default; - if(anchorAtCenter) opts |= ScaleOptions.Centered; - if(maintainAspectRatio) opts |= ScaleOptions.Rational; - return opts; - } - - public interface IDoubleProcessor { - double Process(double d); - } - - public class ShapeAngleRoundBehavior : IDoubleProcessor { - public static ShapeAngleRoundBehavior Instance = new(); - private ShapeAngleRoundBehavior() {} - public double Process(double angle) { - return Math.Round((angle+45)/90)*90 - 45; - } - } - public class LineAngleRoundBehavior : IDoubleProcessor { - public static LineAngleRoundBehavior Instance = new(); - private LineAngleRoundBehavior() {} - public double Process(double angle) { - return Math.Round(angle/15)*15; - } - } + return newSize; + } + + public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize) + { + Scale(boundsBeforeResize, cursorX, cursorY, ref boundsAfterResize, null); + } + + public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) + { + Scale(boundsBeforeResize, Positions.TopLeft, cursorX, cursorY, ref boundsAfterResize, angleRoundBehavior); + } + + public static void Scale(Rectangle boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, ref RectangleF boundsAfterResize, + IDoubleProcessor angleRoundBehavior) + { + ScaleOptions opts = GetScaleOptions(); + + bool rationalScale = (opts & ScaleOptions.Rational) == ScaleOptions.Rational; + bool centeredScale = (opts & ScaleOptions.Centered) == ScaleOptions.Centered; + + if (rationalScale) + { + double angle = GeometryHelper.Angle2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); + + if (angleRoundBehavior != null) + { + angle = angleRoundBehavior.Process(angle); + } + + int dist = GeometryHelper.Distance2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); + + boundsAfterResize.Width = (int) Math.Round(dist * Math.Cos(angle / 180 * Math.PI)); + boundsAfterResize.Height = (int) Math.Round(dist * Math.Sin(angle / 180 * Math.PI)); + } + + if (centeredScale) + { + float wdiff = boundsAfterResize.Width - boundsBeforeResize.Width; + float hdiff = boundsAfterResize.Height - boundsBeforeResize.Height; + boundsAfterResize.Width += wdiff; + boundsAfterResize.Height += hdiff; + boundsAfterResize.X -= wdiff; + boundsAfterResize.Y -= hdiff; + } + } + + /// the current ScaleOptions depending on modifier keys held down + public static ScaleOptions GetScaleOptions() + { + bool anchorAtCenter = (Control.ModifierKeys & Keys.Control) != 0; + bool maintainAspectRatio = (Control.ModifierKeys & Keys.Shift) != 0; + ScaleOptions opts = ScaleOptions.Default; + if (anchorAtCenter) opts |= ScaleOptions.Centered; + if (maintainAspectRatio) opts |= ScaleOptions.Rational; + return opts; + } + + public interface IDoubleProcessor + { + double Process(double d); + } + + public class ShapeAngleRoundBehavior : IDoubleProcessor + { + public static ShapeAngleRoundBehavior Instance = new(); + + private ShapeAngleRoundBehavior() + { + } + + public double Process(double angle) + { + return Math.Round((angle + 45) / 90) * 90 - 45; + } + } + + public class LineAngleRoundBehavior : IDoubleProcessor + { + public static LineAngleRoundBehavior Instance = new(); + + private LineAngleRoundBehavior() + { + } + + public double Process(double angle) + { + return Math.Round(angle / 15) * 15; + } + } } -} - \ No newline at end of file +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/SoundHelper.cs b/src/Greenshot/Helpers/SoundHelper.cs index 427909d86..54a25df8c 100644 --- a/src/Greenshot/Helpers/SoundHelper.cs +++ b/src/Greenshot/Helpers/SoundHelper.cs @@ -18,11 +18,11 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Reflection; using System.Resources; using System.Runtime.InteropServices; - using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.Core; using System.IO; @@ -30,66 +30,90 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.UnmanagedHelpers.Enums; using log4net; -namespace Greenshot.Helpers { - /// - /// Create to fix the sometimes wrongly played sample, especially after first start from IDE - /// See: http://www.codeproject.com/KB/audio-video/soundplayerbug.aspx?msg=2487569 - /// - public static class SoundHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(SoundHelper)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static GCHandle? _gcHandle; - private static byte[] _soundBuffer; - - public static void Initialize() { - if (_gcHandle == null) { - try { - ResourceManager resources = new ResourceManager("Greenshot.Sounds", Assembly.GetExecutingAssembly()); - _soundBuffer = (byte[])resources.GetObject("camera"); +namespace Greenshot.Helpers +{ + /// + /// Create to fix the sometimes wrongly played sample, especially after first start from IDE + /// See: http://www.codeproject.com/KB/audio-video/soundplayerbug.aspx?msg=2487569 + /// + public static class SoundHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(SoundHelper)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static GCHandle? _gcHandle; + private static byte[] _soundBuffer; - if (CoreConfig.NotificationSound != null && CoreConfig.NotificationSound.EndsWith(".wav")) { - try { - if (File.Exists(CoreConfig.NotificationSound)) { - _soundBuffer = File.ReadAllBytes(CoreConfig.NotificationSound); - } - } catch (Exception ex) { - Log.WarnFormat("couldn't load {0}: {1}", CoreConfig.NotificationSound, ex.Message); - } - } - // Pin sound so it can't be moved by the Garbage Collector, this was the cause for the bad sound - _gcHandle = GCHandle.Alloc(_soundBuffer, GCHandleType.Pinned); - } catch (Exception e) { - Log.Error("Error initializing.", e); - } - } - } - - public static void Play() { - if (_soundBuffer != null) { - //Thread playSoundThread = new Thread(delegate() { - SoundFlags flags = SoundFlags.SND_ASYNC | SoundFlags.SND_MEMORY | SoundFlags.SND_NOWAIT | SoundFlags.SND_NOSTOP; - try { - if (_gcHandle != null) WinMM.PlaySound(_gcHandle.Value.AddrOfPinnedObject(), (UIntPtr)0, (uint)flags); - } catch (Exception e) { - Log.Error("Error in play.", e); - } - //}); - //playSoundThread.Name = "Play camera sound"; - //playSoundThread.IsBackground = true; - //playSoundThread.Start(); - } - } + public static void Initialize() + { + if (_gcHandle == null) + { + try + { + ResourceManager resources = new ResourceManager("Greenshot.Sounds", Assembly.GetExecutingAssembly()); + _soundBuffer = (byte[]) resources.GetObject("camera"); - public static void Deinitialize() { - try { - if (_gcHandle != null) { - WinMM.PlaySound(null, (UIntPtr)0, 0); - _gcHandle.Value.Free(); - _gcHandle = null; - } - } catch (Exception e) { - Log.Error("Error in deinitialize.", e); - } - } - } -} + if (CoreConfig.NotificationSound != null && CoreConfig.NotificationSound.EndsWith(".wav")) + { + try + { + if (File.Exists(CoreConfig.NotificationSound)) + { + _soundBuffer = File.ReadAllBytes(CoreConfig.NotificationSound); + } + } + catch (Exception ex) + { + Log.WarnFormat("couldn't load {0}: {1}", CoreConfig.NotificationSound, ex.Message); + } + } + + // Pin sound so it can't be moved by the Garbage Collector, this was the cause for the bad sound + _gcHandle = GCHandle.Alloc(_soundBuffer, GCHandleType.Pinned); + } + catch (Exception e) + { + Log.Error("Error initializing.", e); + } + } + } + + public static void Play() + { + if (_soundBuffer != null) + { + //Thread playSoundThread = new Thread(delegate() { + SoundFlags flags = SoundFlags.SND_ASYNC | SoundFlags.SND_MEMORY | SoundFlags.SND_NOWAIT | SoundFlags.SND_NOSTOP; + try + { + if (_gcHandle != null) WinMM.PlaySound(_gcHandle.Value.AddrOfPinnedObject(), (UIntPtr) 0, (uint) flags); + } + catch (Exception e) + { + Log.Error("Error in play.", e); + } + + //}); + //playSoundThread.Name = "Play camera sound"; + //playSoundThread.IsBackground = true; + //playSoundThread.Start(); + } + } + + public static void Deinitialize() + { + try + { + if (_gcHandle != null) + { + WinMM.PlaySound(null, (UIntPtr) 0, 0); + _gcHandle.Value.Free(); + _gcHandle = null; + } + } + catch (Exception e) + { + Log.Error("Error in deinitialize.", e); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/StartupHelper.cs b/src/Greenshot/Helpers/StartupHelper.cs index 1ca5180e8..ba9eb9bea 100644 --- a/src/Greenshot/Helpers/StartupHelper.cs +++ b/src/Greenshot/Helpers/StartupHelper.cs @@ -18,240 +18,300 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Windows.Forms; using log4net; using Microsoft.Win32; using System.IO; -namespace Greenshot.Helpers { - /// - /// A helper class for the startup registry - /// - public static class StartupHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(StartupHelper)); +namespace Greenshot.Helpers +{ + /// + /// A helper class for the startup registry + /// + public static class StartupHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(StartupHelper)); - private const string RunKey6432 = @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run"; - private const string RunKey = @"Software\Microsoft\Windows\CurrentVersion\Run"; + private const string RunKey6432 = @"Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run"; + private const string RunKey = @"Software\Microsoft\Windows\CurrentVersion\Run"; - private const string ApplicationName = "Greenshot"; + private const string ApplicationName = "Greenshot"; - private static string GetExecutablePath() { - return "\"" + Application.ExecutablePath + "\""; - } + private static string GetExecutablePath() + { + return "\"" + Application.ExecutablePath + "\""; + } - /// - /// Return true if the current user can write the RUN key of the local machine. - /// - /// true if Greenshot can write key - public static bool CanWriteRunAll() { - try { - using (Registry.LocalMachine.OpenSubKey(RunKey, true)) - { - } - } catch { - return false; - } - return true; - } + /// + /// Return true if the current user can write the RUN key of the local machine. + /// + /// true if Greenshot can write key + public static bool CanWriteRunAll() + { + try + { + using (Registry.LocalMachine.OpenSubKey(RunKey, true)) + { + } + } + catch + { + return false; + } - /// - /// Return true if the current user can write the RUN key of the current user. - /// - /// true if Greenshot can write key - public static bool CanWriteRunUser() { - try { - using (Registry.CurrentUser.OpenSubKey(RunKey, true)) - { - } - } catch { - return false; - } - return true; - } + return true; + } - /// - /// Return the RUN key value of the local machine - /// - /// the RUN key value of the local machine - public static object GetRunAllValue() - { - using (var key = Registry.LocalMachine.OpenSubKey(RunKey, false)) - { - object runValue = key?.GetValue(ApplicationName); - if (runValue != null) - { - return runValue; - } - } - // for 64-bit systems we need to check the 32-bit keys too - if (IntPtr.Size != 8) - { - return null; - } - using (var key = Registry.LocalMachine.OpenSubKey(RunKey6432, false)) - { - object runValue = key?.GetValue(ApplicationName); - if (runValue != null) - { - return runValue; - } - } - return null; - } + /// + /// Return true if the current user can write the RUN key of the current user. + /// + /// true if Greenshot can write key + public static bool CanWriteRunUser() + { + try + { + using (Registry.CurrentUser.OpenSubKey(RunKey, true)) + { + } + } + catch + { + return false; + } - /// - /// Return the RUN key value of the current user - /// - /// the RUN key value of the current user - public static object GetRunUserValue() { - using (var key = Registry.CurrentUser.OpenSubKey(RunKey, false)) { - object runValue = key?.GetValue(ApplicationName); - if (runValue != null) { - return runValue; - } - } - // for 64-bit systems we need to check the 32-bit keys too - if (IntPtr.Size != 8) - { - return null; - } - using (var key = Registry.CurrentUser.OpenSubKey(RunKey6432, false)) { - object runValue = key?.GetValue(ApplicationName); - if (runValue != null) { - return runValue; - } - } - return null; - } + return true; + } - /// - /// Return true if the local machine has a RUN entry for Greenshot - /// - /// true if there is a run key - public static bool HasRunAll() { - try { - return GetRunAllValue() != null; - } catch (Exception e) { - Log.Error("Error retrieving RunAllValue", e); - } - return false; - } + /// + /// Return the RUN key value of the local machine + /// + /// the RUN key value of the local machine + public static object GetRunAllValue() + { + using (var key = Registry.LocalMachine.OpenSubKey(RunKey, false)) + { + object runValue = key?.GetValue(ApplicationName); + if (runValue != null) + { + return runValue; + } + } - /// - /// Return true if the current user has a RUN entry for Greenshot - /// - /// true if there is a run key - public static bool HasRunUser() { - object runValue = null; - try { - runValue = GetRunUserValue(); - } catch (Exception e) { - Log.Error("Error retrieving RunUserValue", e); - } - return runValue != null; - } + // for 64-bit systems we need to check the 32-bit keys too + if (IntPtr.Size != 8) + { + return null; + } - /// - /// Delete the RUN key for the localmachine ("ALL") - /// - public static void DeleteRunAll() { - if (!HasRunAll()) - { - return; - } - try + using (var key = Registry.LocalMachine.OpenSubKey(RunKey6432, false)) + { + object runValue = key?.GetValue(ApplicationName); + if (runValue != null) + { + return runValue; + } + } + + return null; + } + + /// + /// Return the RUN key value of the current user + /// + /// the RUN key value of the current user + public static object GetRunUserValue() + { + using (var key = Registry.CurrentUser.OpenSubKey(RunKey, false)) + { + object runValue = key?.GetValue(ApplicationName); + if (runValue != null) + { + return runValue; + } + } + + // for 64-bit systems we need to check the 32-bit keys too + if (IntPtr.Size != 8) + { + return null; + } + + using (var key = Registry.CurrentUser.OpenSubKey(RunKey6432, false)) + { + object runValue = key?.GetValue(ApplicationName); + if (runValue != null) + { + return runValue; + } + } + + return null; + } + + /// + /// Return true if the local machine has a RUN entry for Greenshot + /// + /// true if there is a run key + public static bool HasRunAll() + { + try + { + return GetRunAllValue() != null; + } + catch (Exception e) + { + Log.Error("Error retrieving RunAllValue", e); + } + + return false; + } + + /// + /// Return true if the current user has a RUN entry for Greenshot + /// + /// true if there is a run key + public static bool HasRunUser() + { + object runValue = null; + try + { + runValue = GetRunUserValue(); + } + catch (Exception e) + { + Log.Error("Error retrieving RunUserValue", e); + } + + return runValue != null; + } + + /// + /// Delete the RUN key for the localmachine ("ALL") + /// + public static void DeleteRunAll() + { + if (!HasRunAll()) + { + return; + } + + try { using var key = Registry.LocalMachine.OpenSubKey(RunKey, true); key?.DeleteValue(ApplicationName); - } catch (Exception e) { - Log.Error("Error in deleteRunAll.", e); - } - try - { - // for 64-bit systems we need to delete the 32-bit keys too - if (IntPtr.Size != 8) - { - return; - } + } + catch (Exception e) + { + Log.Error("Error in deleteRunAll.", e); + } + + try + { + // for 64-bit systems we need to delete the 32-bit keys too + if (IntPtr.Size != 8) + { + return; + } using var key = Registry.LocalMachine.OpenSubKey(RunKey6432, false); key?.DeleteValue(ApplicationName); - } catch (Exception e) { - Log.Error("Error in deleteRunAll.", e); - } - } + } + catch (Exception e) + { + Log.Error("Error in deleteRunAll.", e); + } + } - /// - /// Delete the RUN key for the current user - /// - public static void DeleteRunUser() { - if (!HasRunUser()) - { - return; - } - try + /// + /// Delete the RUN key for the current user + /// + public static void DeleteRunUser() + { + if (!HasRunUser()) + { + return; + } + + try { using var key = Registry.CurrentUser.OpenSubKey(RunKey, true); key?.DeleteValue(ApplicationName); - } catch (Exception e) { - Log.Error("Error in deleteRunUser.", e); - } - try - { - // for 64-bit systems we need to delete the 32-bit keys too - if (IntPtr.Size != 8) - { - return; - } + } + catch (Exception e) + { + Log.Error("Error in deleteRunUser.", e); + } + + try + { + // for 64-bit systems we need to delete the 32-bit keys too + if (IntPtr.Size != 8) + { + return; + } using var key = Registry.CurrentUser.OpenSubKey(RunKey6432, false); key?.DeleteValue(ApplicationName); - } catch (Exception e) { - Log.Error("Error in deleteRunUser.", e); - } - } + } + catch (Exception e) + { + Log.Error("Error in deleteRunUser.", e); + } + } - /// - /// Set the RUN key for the current user - /// - public static void SetRunUser() { - try + /// + /// Set the RUN key for the current user + /// + public static void SetRunUser() + { + try { using var key = Registry.CurrentUser.OpenSubKey(RunKey, true); key?.SetValue(ApplicationName, GetExecutablePath()); - } catch (Exception e) { - Log.Error("Error in setRunUser.", e); - } - } + } + catch (Exception e) + { + Log.Error("Error in setRunUser.", e); + } + } - /// - /// Test if there is a link in the Startup folder - /// - /// bool - public static bool IsInStartupFolder() { - try { - string lnkName = Path.GetFileNameWithoutExtension(Application.ExecutablePath) + ".lnk"; - string startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup); - if (Directory.Exists(startupPath)) { - Log.DebugFormat("Startup path: {0}", startupPath); - if (File.Exists(Path.Combine(startupPath, lnkName))) { - return true; - } - } - string startupAll = Environment.GetEnvironmentVariable("ALLUSERSPROFILE") + @"\Microsoft\Windows\Start Menu\Programs\Startup"; - if (Directory.Exists(startupAll)) { - Log.DebugFormat("Startup all path: {0}", startupAll); - if (File.Exists(Path.Combine(startupAll, lnkName))) { - return true; - } - } - } - catch - { - // ignored - } - return false; - } - } -} + /// + /// Test if there is a link in the Startup folder + /// + /// bool + public static bool IsInStartupFolder() + { + try + { + string lnkName = Path.GetFileNameWithoutExtension(Application.ExecutablePath) + ".lnk"; + string startupPath = Environment.GetFolderPath(Environment.SpecialFolder.Startup); + if (Directory.Exists(startupPath)) + { + Log.DebugFormat("Startup path: {0}", startupPath); + if (File.Exists(Path.Combine(startupPath, lnkName))) + { + return true; + } + } + + string startupAll = Environment.GetEnvironmentVariable("ALLUSERSPROFILE") + @"\Microsoft\Windows\Start Menu\Programs\Startup"; + if (Directory.Exists(startupAll)) + { + Log.DebugFormat("Startup all path: {0}", startupAll); + if (File.Exists(Path.Combine(startupAll, lnkName))) + { + return true; + } + } + } + catch + { + // ignored + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/ToolStripItemEndisabler.cs b/src/Greenshot/Helpers/ToolStripItemEndisabler.cs index 0a8e13d84..5db2a109f 100644 --- a/src/Greenshot/Helpers/ToolStripItemEndisabler.cs +++ b/src/Greenshot/Helpers/ToolStripItemEndisabler.cs @@ -18,73 +18,91 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Windows.Forms; -namespace Greenshot.Helpers { - /// - /// Enables or disables toolstrip items, taking care of the hierarchy. - /// (parent) OwnerItems are ENabled with ToolStripItems, - /// (child) DropDownItems are ENabled and DISabled with ToolStripItems. - /// - public static class ToolStripItemEndisabler { - [Flags] - private enum PropagationMode {NONE=0, CHILDREN=1, ANCESTORS=2}; - - /// - /// Enables all of a ToolStrip's children (recursively), - /// but not the ToolStrip itself - /// - public static void Enable(ToolStrip ts) { - Endisable(ts, true, PropagationMode.CHILDREN); - } - - /// - /// Disables all of a ToolStrip's children (recursively), - /// but not the ToolStrip itself - /// - public static void Disable(ToolStrip ts) { - Endisable(ts, false, PropagationMode.CHILDREN); - } - - /// - /// Enables the ToolStripItem, including children (ToolStripDropDownItem) - /// and ancestor (OwnerItem) - /// - public static void Enable(ToolStripItem tsi) { - Endisable(tsi, true, PropagationMode.CHILDREN | PropagationMode.ANCESTORS); - } +namespace Greenshot.Helpers +{ + /// + /// Enables or disables toolstrip items, taking care of the hierarchy. + /// (parent) OwnerItems are ENabled with ToolStripItems, + /// (child) DropDownItems are ENabled and DISabled with ToolStripItems. + /// + public static class ToolStripItemEndisabler + { + [Flags] + private enum PropagationMode + { + NONE = 0, + CHILDREN = 1, + ANCESTORS = 2 + }; + + /// + /// Enables all of a ToolStrip's children (recursively), + /// but not the ToolStrip itself + /// + public static void Enable(ToolStrip ts) + { + Endisable(ts, true, PropagationMode.CHILDREN); + } + + /// + /// Disables all of a ToolStrip's children (recursively), + /// but not the ToolStrip itself + /// + public static void Disable(ToolStrip ts) + { + Endisable(ts, false, PropagationMode.CHILDREN); + } + + /// + /// Enables the ToolStripItem, including children (ToolStripDropDownItem) + /// and ancestor (OwnerItem) + /// + public static void Enable(ToolStripItem tsi) + { + Endisable(tsi, true, PropagationMode.CHILDREN | PropagationMode.ANCESTORS); + } private static void Endisable(ToolStrip ts, bool enable, PropagationMode mode) - { - if ((mode & PropagationMode.CHILDREN) != PropagationMode.CHILDREN) return; - - foreach(ToolStripItem tsi in ts.Items) { - Endisable(tsi, enable, PropagationMode.CHILDREN); - } - } - - private static void Endisable(ToolStripItem tsi, bool enable, PropagationMode mode){ - if (tsi is ToolStripDropDownItem item) { - Endisable(item, enable, mode); - } else { - tsi.Enabled = enable; - } + { + if ((mode & PropagationMode.CHILDREN) != PropagationMode.CHILDREN) return; - if ((mode & PropagationMode.ANCESTORS) != PropagationMode.ANCESTORS) return; - - if (tsi.OwnerItem != null) Endisable(tsi.OwnerItem, enable, PropagationMode.ANCESTORS); + foreach (ToolStripItem tsi in ts.Items) + { + Endisable(tsi, enable, PropagationMode.CHILDREN); + } + } - } - - private static void Endisable(ToolStripDropDownItem tsddi, bool enable, PropagationMode mode) { - - if((mode & PropagationMode.CHILDREN) == PropagationMode.CHILDREN) { - foreach(ToolStripItem tsi in tsddi.DropDownItems) { - Endisable(tsi, enable, PropagationMode.CHILDREN); - } - } - tsddi.Enabled = enable; - } - } -} + private static void Endisable(ToolStripItem tsi, bool enable, PropagationMode mode) + { + if (tsi is ToolStripDropDownItem item) + { + Endisable(item, enable, mode); + } + else + { + tsi.Enabled = enable; + } + + if ((mode & PropagationMode.ANCESTORS) != PropagationMode.ANCESTORS) return; + + if (tsi.OwnerItem != null) Endisable(tsi.OwnerItem, enable, PropagationMode.ANCESTORS); + } + + private static void Endisable(ToolStripDropDownItem tsddi, bool enable, PropagationMode mode) + { + if ((mode & PropagationMode.CHILDREN) == PropagationMode.CHILDREN) + { + foreach (ToolStripItem tsi in tsddi.DropDownItems) + { + Endisable(tsi, enable, PropagationMode.CHILDREN); + } + } + + tsddi.Enabled = enable; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Helpers/UpdateService.cs b/src/Greenshot/Helpers/UpdateService.cs index 4ef120690..d4cb57a20 100644 --- a/src/Greenshot/Helpers/UpdateService.cs +++ b/src/Greenshot/Helpers/UpdateService.cs @@ -139,7 +139,6 @@ namespace Greenshot.Helpers { Log.Error("Error occured await for the next update check.", ex); } - } }, cancellationToken).ConfigureAwait(false); } @@ -169,13 +168,13 @@ namespace Greenshot.Helpers { LastUpdateShown = DateTimeOffset.Now; ShowUpdate(LatestBetaVersion); - } else if (IsUpdateAvailable) + } + else if (IsUpdateAvailable) { LastUpdateShown = DateTimeOffset.Now; ShowUpdate(LatestReleaseVersion); } } - } @@ -201,6 +200,7 @@ namespace Greenshot.Helpers { LatestReleaseVersion = latestReleaseVersion; } + var latestBetaString = Regex.Replace(updateFeed.CurrentBetaVersion, "[a-zA-Z\\-]*", ""); if (Version.TryParse(latestBetaString, out var latestBetaVersion)) { diff --git a/src/Greenshot/Memento/AddElementMemento.cs b/src/Greenshot/Memento/AddElementMemento.cs index 07b4f18d3..13b6a5749 100644 --- a/src/Greenshot/Memento/AddElementMemento.cs +++ b/src/Greenshot/Memento/AddElementMemento.cs @@ -18,50 +18,58 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using Greenshot.Drawing; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Memento { - /// - /// The AddElementMemento makes it possible to undo adding an element - /// - public class AddElementMemento : IMemento { - private IDrawableContainer _drawableContainer; - private Surface _surface; - - public AddElementMemento(Surface surface, IDrawableContainer drawableContainer) { - _surface = surface; - _drawableContainer = drawableContainer; - } +namespace Greenshot.Memento +{ + /// + /// The AddElementMemento makes it possible to undo adding an element + /// + public class AddElementMemento : IMemento + { + private IDrawableContainer _drawableContainer; + private Surface _surface; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public AddElementMemento(Surface surface, IDrawableContainer drawableContainer) + { + _surface = surface; + _drawableContainer = drawableContainer; + } - protected virtual void Dispose(bool disposing) { - //if (disposing) { } - _drawableContainer = null; - _surface = null; - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - public bool Merge(IMemento otherMemento) { - return false; - } + protected virtual void Dispose(bool disposing) + { + //if (disposing) { } + _drawableContainer = null; + _surface = null; + } - public IMemento Restore() { - // Before - _drawableContainer.Invalidate(); - // Store the selected state, as it's overwritten by the RemoveElement + public bool Merge(IMemento otherMemento) + { + return false; + } - DeleteElementMemento oldState = new DeleteElementMemento(_surface, _drawableContainer); - _surface.RemoveElement(_drawableContainer, false); - _drawableContainer.Selected = true; + public IMemento Restore() + { + // Before + _drawableContainer.Invalidate(); + // Store the selected state, as it's overwritten by the RemoveElement - // After - _drawableContainer.Invalidate(); - return oldState; - } - } -} + DeleteElementMemento oldState = new DeleteElementMemento(_surface, _drawableContainer); + _surface.RemoveElement(_drawableContainer, false); + _drawableContainer.Selected = true; + + // After + _drawableContainer.Invalidate(); + return oldState; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Memento/AddElementsMemento.cs b/src/Greenshot/Memento/AddElementsMemento.cs index 1f73f2106..1701a4d29 100644 --- a/src/Greenshot/Memento/AddElementsMemento.cs +++ b/src/Greenshot/Memento/AddElementsMemento.cs @@ -18,54 +18,56 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using Greenshot.Drawing; using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Memento { - /// - /// The AddElementMemento makes it possible to undo adding an element - /// - public class AddElementsMemento : IMemento - { - private IDrawableContainerList _containerList; - private Surface _surface; + /// + /// The AddElementMemento makes it possible to undo adding an element + /// + public class AddElementsMemento : IMemento + { + private IDrawableContainerList _containerList; + private Surface _surface; - public AddElementsMemento(Surface surface, IDrawableContainerList containerList) - { - _surface = surface; - _containerList = containerList; - } + public AddElementsMemento(Surface surface, IDrawableContainerList containerList) + { + _surface = surface; + _containerList = containerList; + } - public void Dispose() - { - Dispose(true); - } + public void Dispose() + { + Dispose(true); + } - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _containerList?.Dispose(); - } - _containerList = null; - _surface = null; - } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _containerList?.Dispose(); + } - public bool Merge(IMemento otherMemento) - { - return false; - } + _containerList = null; + _surface = null; + } - public IMemento Restore() - { - var oldState = new DeleteElementsMemento(_surface, _containerList); + public bool Merge(IMemento otherMemento) + { + return false; + } - _surface.RemoveElements(_containerList, false); + public IMemento Restore() + { + var oldState = new DeleteElementsMemento(_surface, _containerList); - // After, so everything is gone - _surface.Invalidate(); - return oldState; - } - } -} + _surface.RemoveElements(_containerList, false); + + // After, so everything is gone + _surface.Invalidate(); + return oldState; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Memento/ChangeFieldHolderMemento.cs b/src/Greenshot/Memento/ChangeFieldHolderMemento.cs index 225e8de20..b8cd718e3 100644 --- a/src/Greenshot/Memento/ChangeFieldHolderMemento.cs +++ b/src/Greenshot/Memento/ChangeFieldHolderMemento.cs @@ -23,54 +23,55 @@ using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Memento { - /// - /// The ChangeFieldHolderMemento makes it possible to undo-redo an IDrawableContainer move - /// - public class ChangeFieldHolderMemento : IMemento - { - private IDrawableContainer _drawableContainer; - private readonly IField _fieldToBeChanged; - private readonly object _oldValue; + /// + /// The ChangeFieldHolderMemento makes it possible to undo-redo an IDrawableContainer move + /// + public class ChangeFieldHolderMemento : IMemento + { + private IDrawableContainer _drawableContainer; + private readonly IField _fieldToBeChanged; + private readonly object _oldValue; - public ChangeFieldHolderMemento(IDrawableContainer drawableContainer, IField fieldToBeChanged) - { - _drawableContainer = drawableContainer; - _fieldToBeChanged = fieldToBeChanged; - _oldValue = fieldToBeChanged.Value; - } + public ChangeFieldHolderMemento(IDrawableContainer drawableContainer, IField fieldToBeChanged) + { + _drawableContainer = drawableContainer; + _fieldToBeChanged = fieldToBeChanged; + _oldValue = fieldToBeChanged.Value; + } - public void Dispose() - { - Dispose(true); - } + public void Dispose() + { + Dispose(true); + } - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _drawableContainer?.Dispose(); - } - _drawableContainer = null; - } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _drawableContainer?.Dispose(); + } - public bool Merge(IMemento otherMemento) - { - if (otherMemento is not ChangeFieldHolderMemento other) return false; + _drawableContainer = null; + } - if (!other._drawableContainer.Equals(_drawableContainer)) return false; - - return other._fieldToBeChanged.Equals(_fieldToBeChanged); - } + public bool Merge(IMemento otherMemento) + { + if (otherMemento is not ChangeFieldHolderMemento other) return false; - public IMemento Restore() - { - // Before - _drawableContainer.Invalidate(); - ChangeFieldHolderMemento oldState = new ChangeFieldHolderMemento(_drawableContainer, _fieldToBeChanged); - _fieldToBeChanged.Value = _oldValue; - // After - _drawableContainer.Invalidate(); - return oldState; - } - } -} + if (!other._drawableContainer.Equals(_drawableContainer)) return false; + + return other._fieldToBeChanged.Equals(_fieldToBeChanged); + } + + public IMemento Restore() + { + // Before + _drawableContainer.Invalidate(); + ChangeFieldHolderMemento oldState = new ChangeFieldHolderMemento(_drawableContainer, _fieldToBeChanged); + _fieldToBeChanged.Value = _oldValue; + // After + _drawableContainer.Invalidate(); + return oldState; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Memento/DeleteElementMemento.cs b/src/Greenshot/Memento/DeleteElementMemento.cs index cf921713f..b42992007 100644 --- a/src/Greenshot/Memento/DeleteElementMemento.cs +++ b/src/Greenshot/Memento/DeleteElementMemento.cs @@ -18,56 +18,65 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using Greenshot.Drawing; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Memento { - /// - /// The DeleteElementMemento makes it possible to undo deleting an element - /// - public class DeleteElementMemento : IMemento { - private IDrawableContainer _drawableContainer; - private readonly Surface _surface; +namespace Greenshot.Memento +{ + /// + /// The DeleteElementMemento makes it possible to undo deleting an element + /// + public class DeleteElementMemento : IMemento + { + private IDrawableContainer _drawableContainer; + private readonly Surface _surface; - public DeleteElementMemento(Surface surface, IDrawableContainer drawableContainer) { - _surface = surface; - _drawableContainer = drawableContainer; - } + public DeleteElementMemento(Surface surface, IDrawableContainer drawableContainer) + { + _surface = surface; + _drawableContainer = drawableContainer; + } - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected virtual void Dispose(bool disposing) - { - if (!disposing) return; - - if (_drawableContainer != null) { - _drawableContainer.Dispose(); - _drawableContainer = null; - } - } + protected virtual void Dispose(bool disposing) + { + if (!disposing) return; - public bool Merge(IMemento otherMemento) { - return false; - } + if (_drawableContainer != null) + { + _drawableContainer.Dispose(); + _drawableContainer = null; + } + } - public IMemento Restore() { - // Before - _drawableContainer.Invalidate(); + public bool Merge(IMemento otherMemento) + { + return false; + } - var oldState = new AddElementMemento(_surface, _drawableContainer); - _surface.AddElement(_drawableContainer, false); - // The container has a selected flag which represents the state at the moment it was deleted. - if (_drawableContainer.Selected) { - _surface.SelectElement(_drawableContainer); - } + public IMemento Restore() + { + // Before + _drawableContainer.Invalidate(); - // After - _drawableContainer.Invalidate(); - return oldState; - } - } -} + var oldState = new AddElementMemento(_surface, _drawableContainer); + _surface.AddElement(_drawableContainer, false); + // The container has a selected flag which represents the state at the moment it was deleted. + if (_drawableContainer.Selected) + { + _surface.SelectElement(_drawableContainer); + } + + // After + _drawableContainer.Invalidate(); + return oldState; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Memento/DeleteElementsMemento.cs b/src/Greenshot/Memento/DeleteElementsMemento.cs index 33b0fe0ac..096df18d3 100644 --- a/src/Greenshot/Memento/DeleteElementsMemento.cs +++ b/src/Greenshot/Memento/DeleteElementsMemento.cs @@ -18,52 +18,54 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using Greenshot.Drawing; using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Memento { - /// - /// The DeleteElementMemento makes it possible to undo deleting an element - /// - public class DeleteElementsMemento : IMemento - { - private IDrawableContainerList _containerList; - private Surface _surface; + /// + /// The DeleteElementMemento makes it possible to undo deleting an element + /// + public class DeleteElementsMemento : IMemento + { + private IDrawableContainerList _containerList; + private Surface _surface; - public DeleteElementsMemento(Surface surface, IDrawableContainerList containerList) - { - _surface = surface; - _containerList = containerList; - } + public DeleteElementsMemento(Surface surface, IDrawableContainerList containerList) + { + _surface = surface; + _containerList = containerList; + } - public void Dispose() - { - Dispose(true); - } + public void Dispose() + { + Dispose(true); + } - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _containerList?.Dispose(); - } - _containerList = null; - _surface = null; - } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _containerList?.Dispose(); + } - public bool Merge(IMemento otherMemento) - { - return false; - } + _containerList = null; + _surface = null; + } - public IMemento Restore() - { - var oldState = new AddElementsMemento(_surface, _containerList); - _surface.AddElements(_containerList, false); - // After - _surface.Invalidate(); - return oldState; - } - } -} + public bool Merge(IMemento otherMemento) + { + return false; + } + + public IMemento Restore() + { + var oldState = new AddElementsMemento(_surface, _containerList); + _surface.AddElements(_containerList, false); + // After + _surface.Invalidate(); + return oldState; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs b/src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs index 32870a88a..6db480c39 100644 --- a/src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs +++ b/src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using Greenshot.Drawing; using GreenshotPlugin.Core; using System.Collections.Generic; @@ -26,83 +27,86 @@ using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Memento { - /// - /// The DrawableContainerBoundsChangeMemento makes it possible to undo-redo an IDrawableContainer resize & move - /// - public class DrawableContainerBoundsChangeMemento : IMemento - { - private readonly List _points = new(); - private readonly List _sizes = new(); - private IDrawableContainerList _listOfdrawableContainer; + /// + /// The DrawableContainerBoundsChangeMemento makes it possible to undo-redo an IDrawableContainer resize & move + /// + public class DrawableContainerBoundsChangeMemento : IMemento + { + private readonly List _points = new(); + private readonly List _sizes = new(); + private IDrawableContainerList _listOfdrawableContainer; - private void StoreBounds() - { - foreach (IDrawableContainer drawableContainer in _listOfdrawableContainer) - { - _points.Add(drawableContainer.Location); - _sizes.Add(drawableContainer.Size); - } - } - - public DrawableContainerBoundsChangeMemento(IDrawableContainerList listOfdrawableContainer) - { - _listOfdrawableContainer = listOfdrawableContainer; - StoreBounds(); - } - - public DrawableContainerBoundsChangeMemento(IDrawableContainer drawableContainer) - { - _listOfdrawableContainer = new DrawableContainerList - { - drawableContainer - }; - _listOfdrawableContainer.Parent = drawableContainer.Parent; - StoreBounds(); - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - _listOfdrawableContainer?.Dispose(); - } - _listOfdrawableContainer = null; - } - - public bool Merge(IMemento otherMemento) - { - if (otherMemento is not DrawableContainerBoundsChangeMemento other) return false; - - if (ObjectExtensions.CompareLists(_listOfdrawableContainer, other._listOfdrawableContainer)) + private void StoreBounds() + { + foreach (IDrawableContainer drawableContainer in _listOfdrawableContainer) { - // Lists are equal, as we have the state already we can ignore the new memento - return true; + _points.Add(drawableContainer.Location); + _sizes.Add(drawableContainer.Size); } - return false; - } + } - public IMemento Restore() - { - var oldState = new DrawableContainerBoundsChangeMemento(_listOfdrawableContainer); - for (int index = 0; index < _listOfdrawableContainer.Count; index++) - { - IDrawableContainer drawableContainer = _listOfdrawableContainer[index]; - // Before - drawableContainer.Invalidate(); - drawableContainer.Left = _points[index].X; - drawableContainer.Top = _points[index].Y; - drawableContainer.Width = _sizes[index].Width; - drawableContainer.Height = _sizes[index].Height; - // After - drawableContainer.Invalidate(); - drawableContainer.Parent.Modified = true; - } - return oldState; - } - } -} + public DrawableContainerBoundsChangeMemento(IDrawableContainerList listOfdrawableContainer) + { + _listOfdrawableContainer = listOfdrawableContainer; + StoreBounds(); + } + + public DrawableContainerBoundsChangeMemento(IDrawableContainer drawableContainer) + { + _listOfdrawableContainer = new DrawableContainerList + { + drawableContainer + }; + _listOfdrawableContainer.Parent = drawableContainer.Parent; + StoreBounds(); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _listOfdrawableContainer?.Dispose(); + } + + _listOfdrawableContainer = null; + } + + public bool Merge(IMemento otherMemento) + { + if (otherMemento is not DrawableContainerBoundsChangeMemento other) return false; + + if (ObjectExtensions.CompareLists(_listOfdrawableContainer, other._listOfdrawableContainer)) + { + // Lists are equal, as we have the state already we can ignore the new memento + return true; + } + + return false; + } + + public IMemento Restore() + { + var oldState = new DrawableContainerBoundsChangeMemento(_listOfdrawableContainer); + for (int index = 0; index < _listOfdrawableContainer.Count; index++) + { + IDrawableContainer drawableContainer = _listOfdrawableContainer[index]; + // Before + drawableContainer.Invalidate(); + drawableContainer.Left = _points[index].X; + drawableContainer.Top = _points[index].Y; + drawableContainer.Width = _sizes[index].Width; + drawableContainer.Height = _sizes[index].Height; + // After + drawableContainer.Invalidate(); + drawableContainer.Parent.Modified = true; + } + + return oldState; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs b/src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs index a20823878..23e463b1a 100644 --- a/src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs +++ b/src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs @@ -24,51 +24,61 @@ using System.Drawing; using System.Drawing.Drawing2D; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Memento { - /// - /// The SurfaceCropMemento makes it possible to undo-redo an surface crop - /// - public class SurfaceBackgroundChangeMemento : IMemento { - private Image _image; - private Surface _surface; - private Matrix _matrix; - - public SurfaceBackgroundChangeMemento(Surface surface, Matrix matrix) { - _surface = surface; - _image = surface.Image; - _matrix = matrix.Clone(); - // Make sure the reverse is applied - _matrix.Invert(); - } - - public void Dispose() { - Dispose(true); - } +namespace Greenshot.Memento +{ + /// + /// The SurfaceCropMemento makes it possible to undo-redo an surface crop + /// + public class SurfaceBackgroundChangeMemento : IMemento + { + private Image _image; + private Surface _surface; + private Matrix _matrix; - protected virtual void Dispose(bool disposing) - { - if (!disposing) return; - - if (_matrix != null) { - _matrix.Dispose(); - _matrix = null; - } - if (_image != null) { - _image.Dispose(); - _image = null; - } - _surface = null; - } + public SurfaceBackgroundChangeMemento(Surface surface, Matrix matrix) + { + _surface = surface; + _image = surface.Image; + _matrix = matrix.Clone(); + // Make sure the reverse is applied + _matrix.Invert(); + } - public bool Merge(IMemento otherMemento) { - return false; - } + public void Dispose() + { + Dispose(true); + } - public IMemento Restore() { - SurfaceBackgroundChangeMemento oldState = new SurfaceBackgroundChangeMemento(_surface, _matrix); - _surface.UndoBackgroundChange(_image, _matrix); - _surface.Invalidate(); - return oldState; - } - } -} + protected virtual void Dispose(bool disposing) + { + if (!disposing) return; + + if (_matrix != null) + { + _matrix.Dispose(); + _matrix = null; + } + + if (_image != null) + { + _image.Dispose(); + _image = null; + } + + _surface = null; + } + + public bool Merge(IMemento otherMemento) + { + return false; + } + + public IMemento Restore() + { + SurfaceBackgroundChangeMemento oldState = new SurfaceBackgroundChangeMemento(_surface, _matrix); + _surface.UndoBackgroundChange(_image, _matrix); + _surface.Invalidate(); + return oldState; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Memento/TextChangeMemento.cs b/src/Greenshot/Memento/TextChangeMemento.cs index 4971b8ff0..faabd493f 100644 --- a/src/Greenshot/Memento/TextChangeMemento.cs +++ b/src/Greenshot/Memento/TextChangeMemento.cs @@ -22,43 +22,51 @@ using Greenshot.Drawing; using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Memento { - /// - /// The TextChangeMemento makes it possible to undo-redo an IDrawableContainer move - /// - public class TextChangeMemento : IMemento { - private TextContainer _textContainer; - private readonly string _oldText; - - public TextChangeMemento(TextContainer textContainer) { - _textContainer = textContainer; - _oldText = textContainer.Text; - } +namespace Greenshot.Memento +{ + /// + /// The TextChangeMemento makes it possible to undo-redo an IDrawableContainer move + /// + public class TextChangeMemento : IMemento + { + private TextContainer _textContainer; + private readonly string _oldText; - public void Dispose() { - Dispose(true); - } + public TextChangeMemento(TextContainer textContainer) + { + _textContainer = textContainer; + _oldText = textContainer.Text; + } - protected virtual void Dispose(bool disposing) { - if (disposing) { - _textContainer = null; - } - } + public void Dispose() + { + Dispose(true); + } - public bool Merge(IMemento otherMemento) { - if (otherMemento is not TextChangeMemento other) return false; - - return other._textContainer.Equals(_textContainer); - } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _textContainer = null; + } + } - public IMemento Restore() { - // Before - _textContainer.Invalidate(); - TextChangeMemento oldState = new TextChangeMemento(_textContainer); - _textContainer.ChangeText(_oldText, false); - // After - _textContainer.Invalidate(); - return oldState; - } - } -} + public bool Merge(IMemento otherMemento) + { + if (otherMemento is not TextChangeMemento other) return false; + + return other._textContainer.Equals(_textContainer); + } + + public IMemento Restore() + { + // Before + _textContainer.Invalidate(); + TextChangeMemento oldState = new TextChangeMemento(_textContainer); + _textContainer.ChangeText(_oldText, false); + // After + _textContainer.Invalidate(); + return oldState; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Processors/TitleFixProcessor.cs b/src/Greenshot/Processors/TitleFixProcessor.cs index 7bcc59f01..f4dcba9f9 100644 --- a/src/Greenshot/Processors/TitleFixProcessor.cs +++ b/src/Greenshot/Processors/TitleFixProcessor.cs @@ -26,17 +26,21 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using log4net; -namespace Greenshot.Processors { - /// - /// Description of TitleFixProcessor. - /// - public class TitleFixProcessor : AbstractProcessor { - private static readonly ILog LOG = LogManager.GetLogger(typeof(TitleFixProcessor)); - private static readonly CoreConfiguration config = IniConfig.GetIniSection(); +namespace Greenshot.Processors +{ + /// + /// Description of TitleFixProcessor. + /// + public class TitleFixProcessor : AbstractProcessor + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(TitleFixProcessor)); + private static readonly CoreConfiguration config = IniConfig.GetIniSection(); - public TitleFixProcessor() { - List corruptKeys = new List(); - foreach(string key in config.ActiveTitleFixes) { + public TitleFixProcessor() + { + List corruptKeys = new List(); + foreach (string key in config.ActiveTitleFixes) + { if (config.TitleFixMatcher.ContainsKey(key)) continue; LOG.WarnFormat("Key {0} not found, configuration is broken! Disabling this key!", key); @@ -46,12 +50,14 @@ namespace Greenshot.Processors { // Fix configuration if needed if (corruptKeys.Count <= 0) return; - foreach(string corruptKey in corruptKeys) { + foreach (string corruptKey in corruptKeys) + { // Removing any reference to the key config.ActiveTitleFixes.Remove(corruptKey); config.TitleFixMatcher.Remove(corruptKey); config.TitleFixReplacer.Remove(corruptKey); } + config.IsDirty = true; } @@ -59,14 +65,17 @@ namespace Greenshot.Processors { public override string Description => Designation; - public override bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails) { - bool changed = false; - string title = captureDetails.Title; - if (!string.IsNullOrEmpty(title)) { - title = title.Trim(); - foreach(string titleIdentifier in config.ActiveTitleFixes) { - string regexpString = config.TitleFixMatcher[titleIdentifier]; - string replaceString = config.TitleFixReplacer[titleIdentifier] ?? string.Empty; + public override bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails) + { + bool changed = false; + string title = captureDetails.Title; + if (!string.IsNullOrEmpty(title)) + { + title = title.Trim(); + foreach (string titleIdentifier in config.ActiveTitleFixes) + { + string regexpString = config.TitleFixMatcher[titleIdentifier]; + string replaceString = config.TitleFixReplacer[titleIdentifier] ?? string.Empty; if (string.IsNullOrEmpty(regexpString)) continue; @@ -74,9 +83,10 @@ namespace Greenshot.Processors { title = regex.Replace(title, replaceString); changed = true; } - } - captureDetails.Title = title; - return changed; - } - } -} + } + + captureDetails.Title = title; + return changed; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/AnimatingForm.cs b/src/GreenshotPlugin/Controls/AnimatingForm.cs index 55d6e1865..2bfb06a52 100644 --- a/src/GreenshotPlugin/Controls/AnimatingForm.cs +++ b/src/GreenshotPlugin/Controls/AnimatingForm.cs @@ -25,104 +25,116 @@ using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.UnmanagedHelpers.Enums; using log4net; -namespace GreenshotPlugin.Controls { - /// - /// Extend this Form to have the possibility for animations on your form - /// - public class AnimatingForm : GreenshotForm { - private static readonly ILog Log = LogManager.GetLogger(typeof(AnimatingForm)); - private const int DEFAULT_VREFRESH = 60; - private int _vRefresh; - private Timer _timer; +namespace GreenshotPlugin.Controls +{ + /// + /// Extend this Form to have the possibility for animations on your form + /// + public class AnimatingForm : GreenshotForm + { + private static readonly ILog Log = LogManager.GetLogger(typeof(AnimatingForm)); + private const int DEFAULT_VREFRESH = 60; + private int _vRefresh; + private Timer _timer; - /// - /// This flag specifies if any animation is used - /// - protected bool EnableAnimation { - get; - set; - } + /// + /// This flag specifies if any animation is used + /// + protected bool EnableAnimation { get; set; } - /// - /// Vertical Refresh Rate - /// - protected int VRefresh { - get { - if (_vRefresh == 0) + /// + /// Vertical Refresh Rate + /// + protected int VRefresh + { + get + { + if (_vRefresh == 0) { // get te hDC of the desktop to get the VREFRESH using SafeWindowDcHandle desktopHandle = SafeWindowDcHandle.FromDesktop(); _vRefresh = GDI32.GetDeviceCaps(desktopHandle, DeviceCaps.VREFRESH); } - // A vertical refresh rate value of 0 or 1 represents the display hardware's default refresh rate. - // As there is currently no know way to get the default, we guess it. - if (_vRefresh <= 1) { - _vRefresh = DEFAULT_VREFRESH; - } - return _vRefresh; - } - } - /// - /// Check if we are in a Terminal Server session OR need to optimize for RDP / remote desktop connections - /// - protected bool IsTerminalServerSession => !coreConfiguration.DisableRDPOptimizing && (coreConfiguration.OptimizeForRDP || SystemInformation.TerminalServerSession); + // A vertical refresh rate value of 0 or 1 represents the display hardware's default refresh rate. + // As there is currently no know way to get the default, we guess it. + if (_vRefresh <= 1) + { + _vRefresh = DEFAULT_VREFRESH; + } - /// - /// Calculate the amount of frames that an animation takes - /// - /// - /// Number of frames, 1 if in Terminal Server Session - protected int FramesForMillis(int milliseconds) { - // If we are in a Terminal Server Session we return 1 - if (IsTerminalServerSession) { - return 1; - } - return milliseconds / VRefresh; - } + return _vRefresh; + } + } - /// - /// Initialize the animation - /// - protected AnimatingForm() { - Load += delegate { - if (!EnableAnimation) - { - return; - } - _timer = new Timer - { - Interval = 1000/VRefresh - }; - _timer.Tick += timer_Tick; - _timer.Start(); - }; + /// + /// Check if we are in a Terminal Server session OR need to optimize for RDP / remote desktop connections + /// + protected bool IsTerminalServerSession => !coreConfiguration.DisableRDPOptimizing && (coreConfiguration.OptimizeForRDP || SystemInformation.TerminalServerSession); - // Unregister at close - FormClosing += delegate - { - _timer?.Stop(); - }; - } + /// + /// Calculate the amount of frames that an animation takes + /// + /// + /// Number of frames, 1 if in Terminal Server Session + protected int FramesForMillis(int milliseconds) + { + // If we are in a Terminal Server Session we return 1 + if (IsTerminalServerSession) + { + return 1; + } - /// - /// The tick handler initiates the animation. - /// - /// - /// - private void timer_Tick(object sender, EventArgs e) { - try { - Animate(); - } catch (Exception ex) { - Log.Warn("An exception occured while animating:", ex); - } - } + return milliseconds / VRefresh; + } - /// - /// This method will be called every frame, so implement your animation/redraw logic here. - /// - protected virtual void Animate() { - throw new NotImplementedException(); - } - } -} + /// + /// Initialize the animation + /// + protected AnimatingForm() + { + Load += delegate + { + if (!EnableAnimation) + { + return; + } + + _timer = new Timer + { + Interval = 1000 / VRefresh + }; + _timer.Tick += timer_Tick; + _timer.Start(); + }; + + // Unregister at close + FormClosing += delegate { _timer?.Stop(); }; + } + + /// + /// The tick handler initiates the animation. + /// + /// + /// + private void timer_Tick(object sender, EventArgs e) + { + try + { + Animate(); + } + catch (Exception ex) + { + Log.Warn("An exception occured while animating:", ex); + } + } + + /// + /// This method will be called every frame, so implement your animation/redraw logic here. + /// + protected virtual void Animate() + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/BackgroundForm.cs b/src/GreenshotPlugin/Controls/BackgroundForm.cs index 9ffe414e1..beda8b73b 100644 --- a/src/GreenshotPlugin/Controls/BackgroundForm.cs +++ b/src/GreenshotPlugin/Controls/BackgroundForm.cs @@ -18,67 +18,82 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Windows.Forms; using GreenshotPlugin.Core; -namespace GreenshotPlugin.Controls { - /// - /// Description of PleaseWaitForm. - /// - public sealed partial class BackgroundForm : Form { - private volatile bool _shouldClose; +namespace GreenshotPlugin.Controls +{ + /// + /// Description of PleaseWaitForm. + /// + public sealed partial class BackgroundForm : Form + { + private volatile bool _shouldClose; - public BackgroundForm(string title, string text){ - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - Icon = GreenshotResources.GetGreenshotIcon(); - _shouldClose = false; - Text = title; - label_pleasewait.Text = text; - FormClosing += PreventFormClose; - timer_checkforclose.Start(); - } - - // Can be used instead of ShowDialog - public new void Show() { - base.Show(); - bool positioned = false; - foreach(Screen screen in Screen.AllScreens) { - if (screen.Bounds.Contains(Cursor.Position)) { - positioned = true; - Location = new Point(screen.Bounds.X + (screen.Bounds.Width / 2) - (Width / 2), screen.Bounds.Y + (screen.Bounds.Height / 2) - (Height / 2)); - break; - } - } - if (!positioned) { - Location = new Point(Cursor.Position.X - Width / 2, Cursor.Position.Y - Height / 2); - } - } + public BackgroundForm(string title, string text) + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + Icon = GreenshotResources.GetGreenshotIcon(); + _shouldClose = false; + Text = title; + label_pleasewait.Text = text; + FormClosing += PreventFormClose; + timer_checkforclose.Start(); + } - private void PreventFormClose(object sender, FormClosingEventArgs e) { - if(!_shouldClose) { - e.Cancel = true; - } - } + // Can be used instead of ShowDialog + public new void Show() + { + base.Show(); + bool positioned = false; + foreach (Screen screen in Screen.AllScreens) + { + if (screen.Bounds.Contains(Cursor.Position)) + { + positioned = true; + Location = new Point(screen.Bounds.X + (screen.Bounds.Width / 2) - (Width / 2), screen.Bounds.Y + (screen.Bounds.Height / 2) - (Height / 2)); + break; + } + } - private void Timer_checkforcloseTick(object sender, EventArgs e) { - if (_shouldClose) { - timer_checkforclose.Stop(); - BeginInvoke(new EventHandler( delegate {Close();})); - } - } - - public void CloseDialog() { - _shouldClose = true; - Application.DoEvents(); - } + if (!positioned) + { + Location = new Point(Cursor.Position.X - Width / 2, Cursor.Position.Y - Height / 2); + } + } - private void BackgroundFormFormClosing(object sender, FormClosingEventArgs e) { - timer_checkforclose.Stop(); - } - } -} + private void PreventFormClose(object sender, FormClosingEventArgs e) + { + if (!_shouldClose) + { + e.Cancel = true; + } + } + + private void Timer_checkforcloseTick(object sender, EventArgs e) + { + if (_shouldClose) + { + timer_checkforclose.Stop(); + BeginInvoke(new EventHandler(delegate { Close(); })); + } + } + + public void CloseDialog() + { + _shouldClose = true; + Application.DoEvents(); + } + + private void BackgroundFormFormClosing(object sender, FormClosingEventArgs e) + { + timer_checkforclose.Stop(); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/ExtendedWebBrowser.cs b/src/GreenshotPlugin/Controls/ExtendedWebBrowser.cs index c18a2071f..e5bc1c622 100644 --- a/src/GreenshotPlugin/Controls/ExtendedWebBrowser.cs +++ b/src/GreenshotPlugin/Controls/ExtendedWebBrowser.cs @@ -18,41 +18,51 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Windows.Forms; using GreenshotPlugin.Interop; -namespace GreenshotPlugin.Controls { - public class ExtendedWebBrowser : WebBrowser { - protected class ExtendedWebBrowserSite : WebBrowserSite, IOleCommandTarget { - private const int OLECMDID_SHOWSCRIPTERROR = 40; +namespace GreenshotPlugin.Controls +{ + public class ExtendedWebBrowser : WebBrowser + { + protected class ExtendedWebBrowserSite : WebBrowserSite, IOleCommandTarget + { + private const int OLECMDID_SHOWSCRIPTERROR = 40; - private static readonly Guid CGID_DocHostCommandHandler = new Guid("F38BC242-B950-11D1-8918-00C04FC2C836"); + private static readonly Guid CGID_DocHostCommandHandler = new Guid("F38BC242-B950-11D1-8918-00C04FC2C836"); - private const int S_OK = 0; - private const int OLECMDERR_E_NOTSUPPORTED = (-2147221248); + private const int S_OK = 0; + private const int OLECMDERR_E_NOTSUPPORTED = (-2147221248); - public ExtendedWebBrowserSite(WebBrowser wb) : base(wb) { - } + public ExtendedWebBrowserSite(WebBrowser wb) : base(wb) + { + } - public int QueryStatus(Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText) { - return OLECMDERR_E_NOTSUPPORTED; - } + public int QueryStatus(Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText) + { + return OLECMDERR_E_NOTSUPPORTED; + } - public int Exec(Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) { - if (pguidCmdGroup == CGID_DocHostCommandHandler) { - if (nCmdID == OLECMDID_SHOWSCRIPTERROR) { - // do not need to alter pvaOut as the docs says, enough to return S_OK here - return S_OK; - } - } + public int Exec(Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (pguidCmdGroup == CGID_DocHostCommandHandler) + { + if (nCmdID == OLECMDID_SHOWSCRIPTERROR) + { + // do not need to alter pvaOut as the docs says, enough to return S_OK here + return S_OK; + } + } - return OLECMDERR_E_NOTSUPPORTED; - } + return OLECMDERR_E_NOTSUPPORTED; + } } - protected override WebBrowserSiteBase CreateWebBrowserSiteBase() { - return new ExtendedWebBrowserSite(this); - } - } + protected override WebBrowserSiteBase CreateWebBrowserSiteBase() + { + return new ExtendedWebBrowserSite(this); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/FormWithoutActivation.cs b/src/GreenshotPlugin/Controls/FormWithoutActivation.cs index 4491bbf2b..06cde98a2 100644 --- a/src/GreenshotPlugin/Controls/FormWithoutActivation.cs +++ b/src/GreenshotPlugin/Controls/FormWithoutActivation.cs @@ -21,13 +21,16 @@ using System.Windows.Forms; -namespace GreenshotPlugin.Controls { +namespace GreenshotPlugin.Controls +{ /// /// FormWithoutActivation is exactly like a normal form, but doesn't activate (steal focus) /// - public class FormWithoutActivation : Form { - protected override bool ShowWithoutActivation { + public class FormWithoutActivation : Form + { + protected override bool ShowWithoutActivation + { get { return true; } } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotButton.cs b/src/GreenshotPlugin/Controls/GreenshotButton.cs index 16288ce43..9849f2c50 100644 --- a/src/GreenshotPlugin/Controls/GreenshotButton.cs +++ b/src/GreenshotPlugin/Controls/GreenshotButton.cs @@ -22,12 +22,11 @@ using System.ComponentModel; using System.Windows.Forms; -namespace GreenshotPlugin.Controls { - public class GreenshotButton : Button, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +namespace GreenshotPlugin.Controls +{ + public class GreenshotButton : Button, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotCheckBox.cs b/src/GreenshotPlugin/Controls/GreenshotCheckBox.cs index e7e3483ab..f0e4563b9 100644 --- a/src/GreenshotPlugin/Controls/GreenshotCheckBox.cs +++ b/src/GreenshotPlugin/Controls/GreenshotCheckBox.cs @@ -22,24 +22,20 @@ using System.ComponentModel; using System.Windows.Forms; -namespace GreenshotPlugin.Controls { - /// - /// Description of GreenshotCheckbox. - /// - public class GreenshotCheckBox : CheckBox, IGreenshotLanguageBindable, IGreenshotConfigBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } +namespace GreenshotPlugin.Controls +{ + /// + /// Description of GreenshotCheckbox. + /// + public class GreenshotCheckBox : CheckBox, IGreenshotLanguageBindable, IGreenshotConfigBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } - [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] - public string SectionName { get; set; } = "Core"; + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; - [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] - public string PropertyName { - get; - set; - } - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotColumnSorter.cs b/src/GreenshotPlugin/Controls/GreenshotColumnSorter.cs index efad46cd0..02c8f16ef 100644 --- a/src/GreenshotPlugin/Controls/GreenshotColumnSorter.cs +++ b/src/GreenshotPlugin/Controls/GreenshotColumnSorter.cs @@ -18,101 +18,110 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.Collections; using System.Windows.Forms; -namespace GreenshotPlugin.Controls { - /// - /// This class is an implementation of the 'IComparer' interface. - /// - public class GreenshotColumnSorter : IComparer { - /// - /// Specifies the column to be sorted - /// - private int _columnToSort; - /// - /// Specifies the order in which to sort (i.e. 'Ascending'). - /// - private SortOrder _orderOfSort; - /// - /// Case insensitive comparer object - /// - private readonly CaseInsensitiveComparer _objectCompare; +namespace GreenshotPlugin.Controls +{ + /// + /// This class is an implementation of the 'IComparer' interface. + /// + public class GreenshotColumnSorter : IComparer + { + /// + /// Specifies the column to be sorted + /// + private int _columnToSort; - /// - /// Class constructor. Initializes various elements - /// - public GreenshotColumnSorter() { - // Initialize the column to '0' - _columnToSort = 0; + /// + /// Specifies the order in which to sort (i.e. 'Ascending'). + /// + private SortOrder _orderOfSort; - // Initialize the sort order to 'none' - _orderOfSort = SortOrder.None; + /// + /// Case insensitive comparer object + /// + private readonly CaseInsensitiveComparer _objectCompare; - // Initialize the CaseInsensitiveComparer object - _objectCompare = new CaseInsensitiveComparer(); - } + /// + /// Class constructor. Initializes various elements + /// + public GreenshotColumnSorter() + { + // Initialize the column to '0' + _columnToSort = 0; - /// - /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison. - /// - /// First object to be compared - /// Second object to be compared - /// The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y' - public int Compare(object x, object y) { - if (x == null && y == null) { - return 0; - } - if (x == null) { - return -1; - } - if (y == null) { - return 1; - } - // Cast the objects to be compared to ListViewItem objects - var listviewX = (ListViewItem)x; - var listviewY = (ListViewItem)y; + // Initialize the sort order to 'none' + _orderOfSort = SortOrder.None; - // Compare the two items - var compareResult = _objectCompare.Compare(listviewX.SubItems[_columnToSort].Text, listviewY.SubItems[_columnToSort].Text); + // Initialize the CaseInsensitiveComparer object + _objectCompare = new CaseInsensitiveComparer(); + } - // Calculate correct return value based on object comparison - if (_orderOfSort == SortOrder.Ascending) { - // Ascending sort is selected, return normal result of compare operation - return compareResult; - } - if (_orderOfSort == SortOrder.Descending) { - // Descending sort is selected, return negative result of compare operation - return -compareResult; - } - // Return '0' to indicate they are equal - return 0; - } + /// + /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison. + /// + /// First object to be compared + /// Second object to be compared + /// The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y' + public int Compare(object x, object y) + { + if (x == null && y == null) + { + return 0; + } - /// - /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0'). - /// - public int SortColumn { - set { - _columnToSort = value; - } - get { - return _columnToSort; - } - } + if (x == null) + { + return -1; + } - /// - /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending'). - /// - public SortOrder Order { - set { - _orderOfSort = value; - } - get { - return _orderOfSort; - } - } - } -} + if (y == null) + { + return 1; + } + // Cast the objects to be compared to ListViewItem objects + var listviewX = (ListViewItem) x; + var listviewY = (ListViewItem) y; + // Compare the two items + var compareResult = _objectCompare.Compare(listviewX.SubItems[_columnToSort].Text, listviewY.SubItems[_columnToSort].Text); + + // Calculate correct return value based on object comparison + if (_orderOfSort == SortOrder.Ascending) + { + // Ascending sort is selected, return normal result of compare operation + return compareResult; + } + + if (_orderOfSort == SortOrder.Descending) + { + // Descending sort is selected, return negative result of compare operation + return -compareResult; + } + + // Return '0' to indicate they are equal + return 0; + } + + /// + /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0'). + /// + public int SortColumn + { + set { _columnToSort = value; } + get { return _columnToSort; } + } + + /// + /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending'). + /// + public SortOrder Order + { + set { _orderOfSort = value; } + get { return _orderOfSort; } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotComboBox.cs b/src/GreenshotPlugin/Controls/GreenshotComboBox.cs index c9f0b3d9e..5fc0437b6 100644 --- a/src/GreenshotPlugin/Controls/GreenshotComboBox.cs +++ b/src/GreenshotPlugin/Controls/GreenshotComboBox.cs @@ -18,87 +18,99 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Windows.Forms; using GreenshotPlugin.Core; -namespace GreenshotPlugin.Controls { - public class GreenshotComboBox : ComboBox, IGreenshotConfigBindable { - private Type _enumType; - private Enum _selectedEnum; +namespace GreenshotPlugin.Controls +{ + public class GreenshotComboBox : ComboBox, IGreenshotConfigBindable + { + private Type _enumType; + private Enum _selectedEnum; - [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] - public string SectionName { get; set; } = "Core"; + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; - [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] - public string PropertyName { - get; - set; - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } - public GreenshotComboBox() { - SelectedIndexChanged += delegate { - StoreSelectedEnum(); - }; - } + public GreenshotComboBox() + { + SelectedIndexChanged += delegate { StoreSelectedEnum(); }; + } - public void SetValue(Enum currentValue) { - if (currentValue != null) { - _selectedEnum = currentValue; - SelectedItem = Language.Translate(currentValue); - } - } + public void SetValue(Enum currentValue) + { + if (currentValue != null) + { + _selectedEnum = currentValue; + SelectedItem = Language.Translate(currentValue); + } + } - /// - /// This is a method to popululate the ComboBox - /// with the items from the enumeration - /// - /// TEnum to populate with - public void Populate(Type enumType) { - // Store the enum-type, so we can work with it - _enumType = enumType; + /// + /// This is a method to popululate the ComboBox + /// with the items from the enumeration + /// + /// TEnum to populate with + public void Populate(Type enumType) + { + // Store the enum-type, so we can work with it + _enumType = enumType; - var availableValues = Enum.GetValues(enumType); - Items.Clear(); - foreach (var enumValue in availableValues) { - Items.Add(Language.Translate((Enum)enumValue)); - } - } + var availableValues = Enum.GetValues(enumType); + Items.Clear(); + foreach (var enumValue in availableValues) + { + Items.Add(Language.Translate((Enum) enumValue)); + } + } - /// - /// Store the selected value internally - /// - private void StoreSelectedEnum() { - string enumTypeName = _enumType.Name; - string selectedValue = SelectedItem as string; - var availableValues = Enum.GetValues(_enumType); - object returnValue = null; + /// + /// Store the selected value internally + /// + private void StoreSelectedEnum() + { + string enumTypeName = _enumType.Name; + string selectedValue = SelectedItem as string; + var availableValues = Enum.GetValues(_enumType); + object returnValue = null; - try { - returnValue = Enum.Parse(_enumType, selectedValue); - } catch (Exception) { - // Ignore - } + try + { + returnValue = Enum.Parse(_enumType, selectedValue); + } + catch (Exception) + { + // Ignore + } - foreach (Enum enumValue in availableValues) { - string enumKey = enumTypeName + "." + enumValue; - if (Language.HasKey(enumKey)) { - string translation = Language.GetString(enumTypeName + "." + enumValue); - if (translation.Equals(selectedValue)) { - returnValue = enumValue; - } - } - } - _selectedEnum = (Enum)returnValue; - } + foreach (Enum enumValue in availableValues) + { + string enumKey = enumTypeName + "." + enumValue; + if (Language.HasKey(enumKey)) + { + string translation = Language.GetString(enumTypeName + "." + enumValue); + if (translation.Equals(selectedValue)) + { + returnValue = enumValue; + } + } + } - /// - /// Get the selected enum value from the combobox, uses generics - /// - /// The enum value of the combobox - public Enum GetSelectedEnum() { - return _selectedEnum; - } - } -} + _selectedEnum = (Enum) returnValue; + } + + /// + /// Get the selected enum value from the combobox, uses generics + /// + /// The enum value of the combobox + public Enum GetSelectedEnum() + { + return _selectedEnum; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotForm.cs b/src/GreenshotPlugin/Controls/GreenshotForm.cs index 1375c0b7a..c91a48ddc 100644 --- a/src/GreenshotPlugin/Controls/GreenshotForm.cs +++ b/src/GreenshotPlugin/Controls/GreenshotForm.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Windows.Forms; @@ -29,77 +30,75 @@ using System.IO; using GreenshotPlugin.IniFile; using log4net; -namespace GreenshotPlugin.Controls { - /// - /// This form is used for automatically binding the elements of the form to the language - /// - public class GreenshotForm : Form, IGreenshotLanguageBindable { - private static readonly ILog LOG = LogManager.GetLogger(typeof(GreenshotForm)); - protected static CoreConfiguration coreConfiguration; - private static readonly IDictionary reflectionCache = new Dictionary(); - private IComponentChangeService m_changeService; - private bool _isDesignModeLanguageSet; - private bool _applyLanguageManually; - private bool _storeFieldsManually; - private IDictionary _designTimeControls; - private IDictionary _designTimeToolStripItems; +namespace GreenshotPlugin.Controls +{ + /// + /// This form is used for automatically binding the elements of the form to the language + /// + public class GreenshotForm : Form, IGreenshotLanguageBindable + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(GreenshotForm)); + protected static CoreConfiguration coreConfiguration; + private static readonly IDictionary reflectionCache = new Dictionary(); + private IComponentChangeService m_changeService; + private bool _isDesignModeLanguageSet; + private bool _applyLanguageManually; + private bool _storeFieldsManually; + private IDictionary _designTimeControls; + private IDictionary _designTimeToolStripItems; - static GreenshotForm() { - if (!IsInDesignMode) { - coreConfiguration = IniConfig.GetIniSection(); - } - } + static GreenshotForm() + { + if (!IsInDesignMode) + { + coreConfiguration = IniConfig.GetIniSection(); + } + } - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } - /// - /// Used to check the designmode during a constructor - /// - /// - protected static bool IsInDesignMode { - get { - return (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) > -1) || (Application.ExecutablePath.IndexOf("sharpdevelop.exe", StringComparison.OrdinalIgnoreCase) > -1 || (Application.ExecutablePath.IndexOf("wdexpress.exe", StringComparison.OrdinalIgnoreCase) > -1)); - } - } + /// + /// Used to check the designmode during a constructor + /// + /// + protected static bool IsInDesignMode + { + get + { + return (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) > -1) || + (Application.ExecutablePath.IndexOf("sharpdevelop.exe", StringComparison.OrdinalIgnoreCase) > -1 || + (Application.ExecutablePath.IndexOf("wdexpress.exe", StringComparison.OrdinalIgnoreCase) > -1)); + } + } - protected bool ManualLanguageApply { - get { - return _applyLanguageManually; - } - set { - _applyLanguageManually = value; - } - } + protected bool ManualLanguageApply + { + get { return _applyLanguageManually; } + set { _applyLanguageManually = value; } + } - protected bool ManualStoreFields { - get { - return _storeFieldsManually; - } - set { - _storeFieldsManually = value; - } - } + protected bool ManualStoreFields + { + get { return _storeFieldsManually; } + set { _storeFieldsManually = value; } + } - /// - /// When this is set, the form will be brought to the foreground as soon as it is shown. - /// - protected bool ToFront { - get; - set; - } + /// + /// When this is set, the form will be brought to the foreground as soon as it is shown. + /// + protected bool ToFront { get; set; } - /// - /// Code to initialize the language etc during design time - /// - protected void InitializeForDesigner() { + /// + /// Code to initialize the language etc during design time + /// + protected void InitializeForDesigner() + { if (!DesignMode) return; _designTimeControls = new Dictionary(); _designTimeToolStripItems = new Dictionary(); - try { + try + { ITypeResolutionService typeResService = GetService(typeof(ITypeResolutionService)) as ITypeResolutionService; // Add a hard-path if you are using SharpDevelop @@ -111,416 +110,534 @@ namespace GreenshotPlugin.Controls { { string assemblyPath = typeResService.GetPathOfAssembly(currentAssembly.GetName()); string assemblyDirectory = Path.GetDirectoryName(assemblyPath); - if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Greenshot\Languages\"))) { + if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Greenshot\Languages\"))) + { Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Greenshot\Languages\")); } - if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Languages\"))) { + + if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Languages\"))) + { Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Languages\")); } } - } catch (Exception ex) { + } + catch (Exception ex) + { MessageBox.Show(ex.Message); } } - /// - /// This override is only for the design-time of the form - /// - /// - protected override void OnPaint(PaintEventArgs e) { - if (DesignMode) { - if (!_isDesignModeLanguageSet) { - _isDesignModeLanguageSet = true; - try { - ApplyLanguage(); - } - catch (Exception) - { - // ignored - } - } - } - base.OnPaint(e); - } + /// + /// This override is only for the design-time of the form + /// + /// + protected override void OnPaint(PaintEventArgs e) + { + if (DesignMode) + { + if (!_isDesignModeLanguageSet) + { + _isDesignModeLanguageSet = true; + try + { + ApplyLanguage(); + } + catch (Exception) + { + // ignored + } + } + } - protected override void OnLoad(EventArgs e) { - // Every GreenshotForm should have it's default icon - // And it might not ne needed for a Tool Window, but still for the task manager / switcher it's important - Icon = GreenshotResources.GetGreenshotIcon(); - if (!DesignMode) { - if (!_applyLanguageManually) { - ApplyLanguage(); - } - FillFields(); - base.OnLoad(e); - } else { - LOG.Info("OnLoad called from designer."); - InitializeForDesigner(); - base.OnLoad(e); - ApplyLanguage(); - } - } + base.OnPaint(e); + } - /// - /// Make sure the form is visible, if this is wanted - /// - /// EventArgs - protected override void OnShown(EventArgs e) { - base.OnShown(e); - if (ToFront) { - WindowDetails.ToForeground(Handle); - } - } + protected override void OnLoad(EventArgs e) + { + // Every GreenshotForm should have it's default icon + // And it might not ne needed for a Tool Window, but still for the task manager / switcher it's important + Icon = GreenshotResources.GetGreenshotIcon(); + if (!DesignMode) + { + if (!_applyLanguageManually) + { + ApplyLanguage(); + } - /// - /// check if the form was closed with an OK, if so store the values in the GreenshotControls - /// - /// - protected override void OnClosed(EventArgs e) { - if (!DesignMode && !_storeFieldsManually) { - if (DialogResult == DialogResult.OK) { - LOG.Info("Form was closed with OK: storing field values."); - StoreFields(); - } - } - base.OnClosed(e); - } + FillFields(); + base.OnLoad(e); + } + else + { + LOG.Info("OnLoad called from designer."); + InitializeForDesigner(); + base.OnLoad(e); + ApplyLanguage(); + } + } - /// - /// This override allows the control to register event handlers for IComponentChangeService events - /// at the time the control is sited, which happens only in design mode. - /// - public override ISite Site { - get { - return base.Site; - } - set { - // Clear any component change event handlers. - ClearChangeNotifications(); + /// + /// Make sure the form is visible, if this is wanted + /// + /// EventArgs + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + if (ToFront) + { + WindowDetails.ToForeground(Handle); + } + } - // Set the new Site value. - base.Site = value; + /// + /// check if the form was closed with an OK, if so store the values in the GreenshotControls + /// + /// + protected override void OnClosed(EventArgs e) + { + if (!DesignMode && !_storeFieldsManually) + { + if (DialogResult == DialogResult.OK) + { + LOG.Info("Form was closed with OK: storing field values."); + StoreFields(); + } + } - m_changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService)); + base.OnClosed(e); + } - // Register event handlers for component change events. - RegisterChangeNotifications(); - } - } + /// + /// This override allows the control to register event handlers for IComponentChangeService events + /// at the time the control is sited, which happens only in design mode. + /// + public override ISite Site + { + get { return base.Site; } + set + { + // Clear any component change event handlers. + ClearChangeNotifications(); - private void ClearChangeNotifications() { - // The m_changeService value is null when not in design mode, - // as the IComponentChangeService is only available at design time. - m_changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService)); + // Set the new Site value. + base.Site = value; - // Clear our the component change events to prepare for re-siting. - if (m_changeService != null) { - m_changeService.ComponentChanged -= OnComponentChanged; - m_changeService.ComponentAdded -= OnComponentAdded; - } - } + m_changeService = (IComponentChangeService) GetService(typeof(IComponentChangeService)); - private void RegisterChangeNotifications() { - // Register the event handlers for the IComponentChangeService events - if (m_changeService != null) { - m_changeService.ComponentChanged += OnComponentChanged; - m_changeService.ComponentAdded += OnComponentAdded; - } - } + // Register event handlers for component change events. + RegisterChangeNotifications(); + } + } - /// - /// This method handles the OnComponentChanged event to display a notification. - /// - /// - /// - private void OnComponentChanged(object sender, ComponentChangedEventArgs ce) + private void ClearChangeNotifications() + { + // The m_changeService value is null when not in design mode, + // as the IComponentChangeService is only available at design time. + m_changeService = (IComponentChangeService) GetService(typeof(IComponentChangeService)); + + // Clear our the component change events to prepare for re-siting. + if (m_changeService != null) + { + m_changeService.ComponentChanged -= OnComponentChanged; + m_changeService.ComponentAdded -= OnComponentAdded; + } + } + + private void RegisterChangeNotifications() + { + // Register the event handlers for the IComponentChangeService events + if (m_changeService != null) + { + m_changeService.ComponentChanged += OnComponentChanged; + m_changeService.ComponentAdded += OnComponentAdded; + } + } + + /// + /// This method handles the OnComponentChanged event to display a notification. + /// + /// + /// + private void OnComponentChanged(object sender, ComponentChangedEventArgs ce) { if (((IComponent) ce.Component)?.Site == null || ce.Member == null) return; if (!"LanguageKey".Equals(ce.Member.Name)) return; - if (ce.Component is Control control) { + if (ce.Component is Control control) + { LOG.InfoFormat("Changing LanguageKey for {0} to {1}", control.Name, ce.NewValue); - ApplyLanguage(control, (string)ce.NewValue); - } else { - if (ce.Component is ToolStripItem item) { + ApplyLanguage(control, (string) ce.NewValue); + } + else + { + if (ce.Component is ToolStripItem item) + { LOG.InfoFormat("Changing LanguageKey for {0} to {1}", item.Name, ce.NewValue); - ApplyLanguage(item, (string)ce.NewValue); - } else { + ApplyLanguage(item, (string) ce.NewValue); + } + else + { LOG.InfoFormat("Not possible to changing LanguageKey for {0} to {1}", ce.Component.GetType(), ce.NewValue); } } } - private void OnComponentAdded(object sender, ComponentEventArgs ce) { + private void OnComponentAdded(object sender, ComponentEventArgs ce) + { if (ce.Component?.Site == null) return; - if (ce.Component is Control control) { - if (!_designTimeControls.ContainsKey(control.Name)) { + if (ce.Component is Control control) + { + if (!_designTimeControls.ContainsKey(control.Name)) + { _designTimeControls.Add(control.Name, control); - } else { + } + else + { _designTimeControls[control.Name] = control; } } else { - if (ce.Component is ToolStripItem stripItem) { + if (ce.Component is ToolStripItem stripItem) + { ToolStripItem item = stripItem; - if (!_designTimeControls.ContainsKey(item.Name)) { + if (!_designTimeControls.ContainsKey(item.Name)) + { _designTimeToolStripItems.Add(item.Name, item); - } else { + } + else + { _designTimeToolStripItems[item.Name] = item; } } } } - // Clean up any resources being used. - protected override void Dispose(bool disposing) { - if (disposing) { - ClearChangeNotifications(); - } - base.Dispose(disposing); - } + // Clean up any resources being used. + protected override void Dispose(bool disposing) + { + if (disposing) + { + ClearChangeNotifications(); + } - protected void ApplyLanguage(ToolStripItem applyTo, string languageKey) { - string langString; - if (!string.IsNullOrEmpty(languageKey)) { - if (!Language.TryGetString(languageKey, out langString)) { - LOG.WarnFormat("Unknown language key '{0}' configured for control '{1}', this might be okay.", languageKey, applyTo.Name); - return; - } - applyTo.Text = langString; - } else { - // Fallback to control name! - if (Language.TryGetString(applyTo.Name, out langString)) { - applyTo.Text = langString; - return; - } - if (!DesignMode) { - LOG.DebugFormat("Greenshot control without language key: {0}", applyTo.Name); - } - } - } + base.Dispose(disposing); + } - protected void ApplyLanguage(ToolStripItem applyTo) { - if (applyTo is IGreenshotLanguageBindable languageBindable) { - ApplyLanguage(applyTo, languageBindable.LanguageKey); - } - } + protected void ApplyLanguage(ToolStripItem applyTo, string languageKey) + { + string langString; + if (!string.IsNullOrEmpty(languageKey)) + { + if (!Language.TryGetString(languageKey, out langString)) + { + LOG.WarnFormat("Unknown language key '{0}' configured for control '{1}', this might be okay.", languageKey, applyTo.Name); + return; + } - protected void ApplyLanguage(Control applyTo) { - if (!(applyTo is IGreenshotLanguageBindable languageBindable)) { - // check if it's a menu! + applyTo.Text = langString; + } + else + { + // Fallback to control name! + if (Language.TryGetString(applyTo.Name, out langString)) + { + applyTo.Text = langString; + return; + } + + if (!DesignMode) + { + LOG.DebugFormat("Greenshot control without language key: {0}", applyTo.Name); + } + } + } + + protected void ApplyLanguage(ToolStripItem applyTo) + { + if (applyTo is IGreenshotLanguageBindable languageBindable) + { + ApplyLanguage(applyTo, languageBindable.LanguageKey); + } + } + + protected void ApplyLanguage(Control applyTo) + { + if (!(applyTo is IGreenshotLanguageBindable languageBindable)) + { + // check if it's a menu! if (!(applyTo is ToolStrip toolStrip)) - { - return; - } - foreach (ToolStripItem item in toolStrip.Items) { - ApplyLanguage(item); - } - return; - } + { + return; + } - // Apply language text to the control - ApplyLanguage(applyTo, languageBindable.LanguageKey); + foreach (ToolStripItem item in toolStrip.Items) + { + ApplyLanguage(item); + } - // Repopulate the combox boxes - if (applyTo is IGreenshotConfigBindable configBindable && applyTo is GreenshotComboBox comboxBox) { - if (!string.IsNullOrEmpty(configBindable.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) { - IniSection section = IniConfig.GetIniSection(configBindable.SectionName); - if (section != null) { - // Only update the language, so get the actual value and than repopulate - Enum currentValue = comboxBox.GetSelectedEnum(); - comboxBox.Populate(section.Values[configBindable.PropertyName].ValueType); - comboxBox.SetValue(currentValue); - } - } - } - } + return; + } - /// - /// Helper method to cache the fieldinfo values, so we don't need to reflect all the time! - /// - /// - /// - private static FieldInfo[] GetCachedFields(Type typeToGetFieldsFor) { - if (!reflectionCache.TryGetValue(typeToGetFieldsFor, out var fields)) { - fields = typeToGetFieldsFor.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - reflectionCache.Add(typeToGetFieldsFor, fields); - } - return fields; - } + // Apply language text to the control + ApplyLanguage(applyTo, languageBindable.LanguageKey); - /// - /// Apply all the language settings to the "Greenshot" Controls on this form - /// - protected void ApplyLanguage() { - SuspendLayout(); - try { - // Set title of the form - if (!string.IsNullOrEmpty(LanguageKey) && Language.TryGetString(LanguageKey, out var langString)) { - Text = langString; - } + // Repopulate the combox boxes + if (applyTo is IGreenshotConfigBindable configBindable && applyTo is GreenshotComboBox comboxBox) + { + if (!string.IsNullOrEmpty(configBindable.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + { + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section != null) + { + // Only update the language, so get the actual value and than repopulate + Enum currentValue = comboxBox.GetSelectedEnum(); + comboxBox.Populate(section.Values[configBindable.PropertyName].ValueType); + comboxBox.SetValue(currentValue); + } + } + } + } - // Reset the text values for all GreenshotControls - foreach (FieldInfo field in GetCachedFields(GetType())) { - object controlObject = field.GetValue(this); - if (controlObject == null) { - LOG.DebugFormat("No value: {0}", field.Name); - continue; - } + /// + /// Helper method to cache the fieldinfo values, so we don't need to reflect all the time! + /// + /// + /// + private static FieldInfo[] GetCachedFields(Type typeToGetFieldsFor) + { + if (!reflectionCache.TryGetValue(typeToGetFieldsFor, out var fields)) + { + fields = typeToGetFieldsFor.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + reflectionCache.Add(typeToGetFieldsFor, fields); + } - if (!(controlObject is Control applyToControl)) { - ToolStripItem applyToItem = controlObject as ToolStripItem; - if (applyToItem == null) { - LOG.DebugFormat("No Control or ToolStripItem: {0}", field.Name); - continue; - } - ApplyLanguage(applyToItem); - } else { - ApplyLanguage(applyToControl); - } - } + return fields; + } - if (DesignMode) { - foreach (Control designControl in _designTimeControls.Values) { - ApplyLanguage(designControl); - } - foreach (ToolStripItem designToolStripItem in _designTimeToolStripItems.Values) { - ApplyLanguage(designToolStripItem); - } - } - } finally { - ResumeLayout(); - } - } + /// + /// Apply all the language settings to the "Greenshot" Controls on this form + /// + protected void ApplyLanguage() + { + SuspendLayout(); + try + { + // Set title of the form + if (!string.IsNullOrEmpty(LanguageKey) && Language.TryGetString(LanguageKey, out var langString)) + { + Text = langString; + } - /// - /// Apply the language text to supplied control - /// - protected void ApplyLanguage(Control applyTo, string languageKey) { - string langString; - if (!string.IsNullOrEmpty(languageKey)) { - if (!Language.TryGetString(languageKey, out langString)) { - LOG.WarnFormat("Wrong language key '{0}' configured for control '{1}'", languageKey, applyTo.Name); - return; - } - applyTo.Text = langString; - } else { - // Fallback to control name! - if (Language.TryGetString(applyTo.Name, out langString)) { - applyTo.Text = langString; - return; - } - if (!DesignMode) { - LOG.DebugFormat("Greenshot control without language key: {0}", applyTo.Name); - } - } - } + // Reset the text values for all GreenshotControls + foreach (FieldInfo field in GetCachedFields(GetType())) + { + object controlObject = field.GetValue(this); + if (controlObject == null) + { + LOG.DebugFormat("No value: {0}", field.Name); + continue; + } - /// - /// Fill all GreenshotControls with the values from the configuration - /// - protected void FillFields() { - foreach (FieldInfo field in GetCachedFields(GetType())) { - var controlObject = field.GetValue(this); - IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; - if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) { - IniSection section = IniConfig.GetIniSection(configBindable.SectionName); - if (section != null) { - if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) { - LOG.DebugFormat("Wrong property '{0}' configured for field '{1}'",configBindable.PropertyName,field.Name); - continue; - } + if (!(controlObject is Control applyToControl)) + { + ToolStripItem applyToItem = controlObject as ToolStripItem; + if (applyToItem == null) + { + LOG.DebugFormat("No Control or ToolStripItem: {0}", field.Name); + continue; + } - if (controlObject is CheckBox checkBox) { - checkBox.Checked = (bool)iniValue.Value; - checkBox.Enabled = !iniValue.IsFixed; - continue; - } + ApplyLanguage(applyToItem); + } + else + { + ApplyLanguage(applyToControl); + } + } - if (controlObject is RadioButton radíoButton) { - radíoButton.Checked = (bool)iniValue.Value; - radíoButton.Enabled = !iniValue.IsFixed; - continue; - } + if (DesignMode) + { + foreach (Control designControl in _designTimeControls.Values) + { + ApplyLanguage(designControl); + } - if (controlObject is TextBox textBox) { - if (controlObject is HotkeyControl hotkeyControl) { - string hotkeyValue = (string)iniValue.Value; - if (!string.IsNullOrEmpty(hotkeyValue)) { - hotkeyControl.SetHotkey(hotkeyValue); - hotkeyControl.Enabled = !iniValue.IsFixed; - } - continue; - } - textBox.Text = iniValue.ToString(); - textBox.Enabled = !iniValue.IsFixed; - continue; - } + foreach (ToolStripItem designToolStripItem in _designTimeToolStripItems.Values) + { + ApplyLanguage(designToolStripItem); + } + } + } + finally + { + ResumeLayout(); + } + } - if (controlObject is GreenshotComboBox comboxBox) { - comboxBox.Populate(iniValue.ValueType); - comboxBox.SetValue((Enum)iniValue.Value); - comboxBox.Enabled = !iniValue.IsFixed; - } - } - } - } - OnFieldsFilled(); - } + /// + /// Apply the language text to supplied control + /// + protected void ApplyLanguage(Control applyTo, string languageKey) + { + string langString; + if (!string.IsNullOrEmpty(languageKey)) + { + if (!Language.TryGetString(languageKey, out langString)) + { + LOG.WarnFormat("Wrong language key '{0}' configured for control '{1}'", languageKey, applyTo.Name); + return; + } - protected virtual void OnFieldsFilled() { - } + applyTo.Text = langString; + } + else + { + // Fallback to control name! + if (Language.TryGetString(applyTo.Name, out langString)) + { + applyTo.Text = langString; + return; + } - /// - /// Store all GreenshotControl values to the configuration - /// - protected void StoreFields() { - bool iniDirty = false; - foreach (FieldInfo field in GetCachedFields(GetType())) { - var controlObject = field.GetValue(this); - IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; + if (!DesignMode) + { + LOG.DebugFormat("Greenshot control without language key: {0}", applyTo.Name); + } + } + } - if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) { - IniSection section = IniConfig.GetIniSection(configBindable.SectionName); - if (section != null) { - if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) { - continue; - } + /// + /// Fill all GreenshotControls with the values from the configuration + /// + protected void FillFields() + { + foreach (FieldInfo field in GetCachedFields(GetType())) + { + var controlObject = field.GetValue(this); + IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; + if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + { + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section != null) + { + if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) + { + LOG.DebugFormat("Wrong property '{0}' configured for field '{1}'", configBindable.PropertyName, field.Name); + continue; + } - if (controlObject is CheckBox checkBox) { - iniValue.Value = checkBox.Checked; - iniDirty = true; - continue; - } + if (controlObject is CheckBox checkBox) + { + checkBox.Checked = (bool) iniValue.Value; + checkBox.Enabled = !iniValue.IsFixed; + continue; + } - if (controlObject is RadioButton radioButton) { - iniValue.Value = radioButton.Checked; - iniDirty = true; - continue; - } + if (controlObject is RadioButton radíoButton) + { + radíoButton.Checked = (bool) iniValue.Value; + radíoButton.Enabled = !iniValue.IsFixed; + continue; + } - if (controlObject is TextBox textBox) { - if (controlObject is HotkeyControl hotkeyControl) { - iniValue.Value = hotkeyControl.ToString(); - iniDirty = true; - continue; - } - iniValue.UseValueOrDefault(textBox.Text); - iniDirty = true; - continue; - } + if (controlObject is TextBox textBox) + { + if (controlObject is HotkeyControl hotkeyControl) + { + string hotkeyValue = (string) iniValue.Value; + if (!string.IsNullOrEmpty(hotkeyValue)) + { + hotkeyControl.SetHotkey(hotkeyValue); + hotkeyControl.Enabled = !iniValue.IsFixed; + } - if (controlObject is GreenshotComboBox comboxBox) { - iniValue.Value = comboxBox.GetSelectedEnum(); - iniDirty = true; - } + continue; + } - } - } - } - if (iniDirty) { - IniConfig.Save(); - } - } - } -} + textBox.Text = iniValue.ToString(); + textBox.Enabled = !iniValue.IsFixed; + continue; + } + + if (controlObject is GreenshotComboBox comboxBox) + { + comboxBox.Populate(iniValue.ValueType); + comboxBox.SetValue((Enum) iniValue.Value); + comboxBox.Enabled = !iniValue.IsFixed; + } + } + } + } + + OnFieldsFilled(); + } + + protected virtual void OnFieldsFilled() + { + } + + /// + /// Store all GreenshotControl values to the configuration + /// + protected void StoreFields() + { + bool iniDirty = false; + foreach (FieldInfo field in GetCachedFields(GetType())) + { + var controlObject = field.GetValue(this); + IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; + + if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + { + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section != null) + { + if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) + { + continue; + } + + if (controlObject is CheckBox checkBox) + { + iniValue.Value = checkBox.Checked; + iniDirty = true; + continue; + } + + if (controlObject is RadioButton radioButton) + { + iniValue.Value = radioButton.Checked; + iniDirty = true; + continue; + } + + if (controlObject is TextBox textBox) + { + if (controlObject is HotkeyControl hotkeyControl) + { + iniValue.Value = hotkeyControl.ToString(); + iniDirty = true; + continue; + } + + iniValue.UseValueOrDefault(textBox.Text); + iniDirty = true; + continue; + } + + if (controlObject is GreenshotComboBox comboxBox) + { + iniValue.Value = comboxBox.GetSelectedEnum(); + iniDirty = true; + } + } + } + } + + if (iniDirty) + { + IniConfig.Save(); + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotGroupBox.cs b/src/GreenshotPlugin/Controls/GreenshotGroupBox.cs index 954027948..7f4886122 100644 --- a/src/GreenshotPlugin/Controls/GreenshotGroupBox.cs +++ b/src/GreenshotPlugin/Controls/GreenshotGroupBox.cs @@ -22,12 +22,11 @@ using System.Windows.Forms; using System.ComponentModel; -namespace GreenshotPlugin.Controls { - public class GreenshotGroupBox : GroupBox , IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +namespace GreenshotPlugin.Controls +{ + public class GreenshotGroupBox : GroupBox, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotLabel.cs b/src/GreenshotPlugin/Controls/GreenshotLabel.cs index 887bdb2ea..904980f9f 100644 --- a/src/GreenshotPlugin/Controls/GreenshotLabel.cs +++ b/src/GreenshotPlugin/Controls/GreenshotLabel.cs @@ -22,12 +22,11 @@ using System.Windows.Forms; using System.ComponentModel; -namespace GreenshotPlugin.Controls { - public class GreenshotLabel : Label, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +namespace GreenshotPlugin.Controls +{ + public class GreenshotLabel : Label, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotRadioButton.cs b/src/GreenshotPlugin/Controls/GreenshotRadioButton.cs index ca68fb284..9fdc172d4 100644 --- a/src/GreenshotPlugin/Controls/GreenshotRadioButton.cs +++ b/src/GreenshotPlugin/Controls/GreenshotRadioButton.cs @@ -22,24 +22,20 @@ using System.ComponentModel; using System.Windows.Forms; -namespace GreenshotPlugin.Controls { - /// - /// Description of GreenshotCheckbox. - /// - public class GreenshotRadioButton : RadioButton, IGreenshotLanguageBindable, IGreenshotConfigBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } +namespace GreenshotPlugin.Controls +{ + /// + /// Description of GreenshotCheckbox. + /// + public class GreenshotRadioButton : RadioButton, IGreenshotLanguageBindable, IGreenshotConfigBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } - [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] - public string SectionName { get; set; } = "Core"; + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; - [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] - public string PropertyName { - get; - set; - } - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotTabPage.cs b/src/GreenshotPlugin/Controls/GreenshotTabPage.cs index 6941a861a..40b53b30f 100644 --- a/src/GreenshotPlugin/Controls/GreenshotTabPage.cs +++ b/src/GreenshotPlugin/Controls/GreenshotTabPage.cs @@ -22,12 +22,11 @@ using System.Windows.Forms; using System.ComponentModel; -namespace GreenshotPlugin.Controls { - public class GreenshotTabPage : TabPage, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +namespace GreenshotPlugin.Controls +{ + public class GreenshotTabPage : TabPage, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotTextBox.cs b/src/GreenshotPlugin/Controls/GreenshotTextBox.cs index a4f743f25..49c7a4d2e 100644 --- a/src/GreenshotPlugin/Controls/GreenshotTextBox.cs +++ b/src/GreenshotPlugin/Controls/GreenshotTextBox.cs @@ -22,15 +22,14 @@ using System.ComponentModel; using System.Windows.Forms; -namespace GreenshotPlugin.Controls { - public class GreenshotTextBox : TextBox, IGreenshotConfigBindable { - [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] - public string SectionName { get; set; } = "Core"; +namespace GreenshotPlugin.Controls +{ + public class GreenshotTextBox : TextBox, IGreenshotConfigBindable + { + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; - [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] - public string PropertyName { - get; - set; - } - } -} + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs b/src/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs index e9a9edb7d..e719187c7 100644 --- a/src/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs +++ b/src/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs @@ -22,12 +22,11 @@ using System.ComponentModel; using System.Windows.Forms; -namespace GreenshotPlugin.Controls { - public class GreenshotToolStripDropDownButton : ToolStripDropDownButton, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +namespace GreenshotPlugin.Controls +{ + public class GreenshotToolStripDropDownButton : ToolStripDropDownButton, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotToolStripButton.cs b/src/GreenshotPlugin/Controls/GreenshotToolStripButton.cs index 06bf59597..e95bd1803 100644 --- a/src/GreenshotPlugin/Controls/GreenshotToolStripButton.cs +++ b/src/GreenshotPlugin/Controls/GreenshotToolStripButton.cs @@ -22,12 +22,11 @@ using System.ComponentModel; using System.Windows.Forms; -namespace GreenshotPlugin.Controls { - public class GreenshotToolStripButton : ToolStripButton, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +namespace GreenshotPlugin.Controls +{ + public class GreenshotToolStripButton : ToolStripButton, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs b/src/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs index 5bee42167..07443d894 100644 --- a/src/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs +++ b/src/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs @@ -22,12 +22,11 @@ using System.Windows.Forms; using System.ComponentModel; -namespace GreenshotPlugin.Controls { - public class GreenshotToolStripLabel : ToolStripLabel, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +namespace GreenshotPlugin.Controls +{ + public class GreenshotToolStripLabel : ToolStripLabel, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs b/src/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs index 8547b65c8..c7a64c743 100644 --- a/src/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs +++ b/src/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs @@ -22,12 +22,11 @@ using System.ComponentModel; using System.Windows.Forms; -namespace GreenshotPlugin.Controls { - public class GreenshotToolStripMenuItem : ToolStripMenuItem, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +namespace GreenshotPlugin.Controls +{ + public class GreenshotToolStripMenuItem : ToolStripMenuItem, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/HotkeyControl.cs b/src/GreenshotPlugin/Controls/HotkeyControl.cs index 6f1c6d8d5..af59a27dd 100644 --- a/src/GreenshotPlugin/Controls/HotkeyControl.cs +++ b/src/GreenshotPlugin/Controls/HotkeyControl.cs @@ -29,536 +29,658 @@ using log4net; using GreenshotPlugin.Core; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotPlugin.Controls { - /// - /// A simple control that allows the user to select pretty much any valid hotkey combination - /// See: http://www.codeproject.com/KB/buttons/hotkeycontrol.aspx - /// But is modified to fit in Greenshot, and have localized support - /// - public sealed class HotkeyControl : GreenshotTextBox { - private static readonly ILog Log = LogManager.GetLogger(typeof(HotkeyControl)); +namespace GreenshotPlugin.Controls +{ + /// + /// A simple control that allows the user to select pretty much any valid hotkey combination + /// See: http://www.codeproject.com/KB/buttons/hotkeycontrol.aspx + /// But is modified to fit in Greenshot, and have localized support + /// + public sealed class HotkeyControl : GreenshotTextBox + { + private static readonly ILog Log = LogManager.GetLogger(typeof(HotkeyControl)); - private static readonly EventDelay EventDelay = new EventDelay(TimeSpan.FromMilliseconds(600).Ticks); - private static readonly bool IsWindows7OrOlder = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 1; + private static readonly EventDelay EventDelay = new EventDelay(TimeSpan.FromMilliseconds(600).Ticks); + private static readonly bool IsWindows7OrOlder = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 1; - // Holds the list of hotkeys - private static readonly IDictionary KeyHandlers = new Dictionary(); - private static int _hotKeyCounter = 1; - private const uint WM_HOTKEY = 0x312; - private static IntPtr _hotkeyHwnd; + // Holds the list of hotkeys + private static readonly IDictionary KeyHandlers = new Dictionary(); + private static int _hotKeyCounter = 1; + private const uint WM_HOTKEY = 0x312; + private static IntPtr _hotkeyHwnd; - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum Modifiers : uint { - NONE = 0, - ALT = 1, - CTRL = 2, - SHIFT = 4, - WIN = 8, - NO_REPEAT = 0x4000 - } + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum Modifiers : uint + { + NONE = 0, + ALT = 1, + CTRL = 2, + SHIFT = 4, + WIN = 8, + NO_REPEAT = 0x4000 + } - [SuppressMessage("ReSharper", "InconsistentNaming")] - private enum MapType : uint { - MAPVK_VK_TO_VSC = 0, //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0. - MAPVK_VSC_TO_VK = 1, //The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0. - MAPVK_VK_TO_CHAR = 2, //The uCode parameter is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0. - MAPVK_VSC_TO_VK_EX = 3, //The uCode parameter is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0. - MAPVK_VK_TO_VSC_EX = 4 //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If the scan code is an extended scan code, the high byte of the uCode value can contain either 0xe0 or 0xe1 to specify the extended scan code. If there is no translation, the function returns 0. - } + [SuppressMessage("ReSharper", "InconsistentNaming")] + private enum MapType : uint + { + MAPVK_VK_TO_VSC = + 0, //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0. - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint virtualKeyCode); + MAPVK_VSC_TO_VK = + 1, //The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0. - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + MAPVK_VK_TO_CHAR = + 2, //The uCode parameter is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0. - [DllImport("user32.dll", SetLastError = true)] - private static extern uint MapVirtualKey(uint uCode, uint uMapType); - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern int GetKeyNameText(uint lParam, [Out] StringBuilder lpString, int nSize); + MAPVK_VSC_TO_VK_EX = + 3, //The uCode parameter is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0. - // These variables store the current hotkey and modifier(s) - private Keys _hotkey = Keys.None; - private Keys _modifiers = Keys.None; + MAPVK_VK_TO_VSC_EX = + 4 //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If the scan code is an extended scan code, the high byte of the uCode value can contain either 0xe0 or 0xe1 to specify the extended scan code. If there is no translation, the function returns 0. + } - // ArrayLists used to enforce the use of proper modifiers. - // Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing. - private readonly IList _needNonShiftModifier = new List(); - private readonly IList _needNonAltGrModifier = new List(); + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint virtualKeyCode); - private readonly ContextMenuStrip _dummy = new ContextMenuStrip(); + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); - /// - /// Used to make sure that there is no right-click menu available - /// - public override ContextMenuStrip ContextMenuStrip - { - get { - return _dummy; - } - set { - base.ContextMenuStrip = _dummy; - } - } + [DllImport("user32.dll", SetLastError = true)] + private static extern uint MapVirtualKey(uint uCode, uint uMapType); - /// - /// Forces the control to be non-multiline - /// - public override bool Multiline { - get { - return base.Multiline; - } - set { - // Ignore what the user wants; force Multiline to false - base.Multiline = false; - } - } + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern int GetKeyNameText(uint lParam, [Out] StringBuilder lpString, int nSize); - /// - /// Creates a new HotkeyControl - /// - public HotkeyControl() { - ContextMenuStrip = _dummy; // Disable right-clicking - Text = "None"; + // These variables store the current hotkey and modifier(s) + private Keys _hotkey = Keys.None; + private Keys _modifiers = Keys.None; - // Handle events that occurs when keys are pressed - KeyPress += HotkeyControl_KeyPress; - KeyUp += HotkeyControl_KeyUp; - KeyDown += HotkeyControl_KeyDown; + // ArrayLists used to enforce the use of proper modifiers. + // Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing. + private readonly IList _needNonShiftModifier = new List(); + private readonly IList _needNonAltGrModifier = new List(); - PopulateModifierLists(); - } - - /// - /// Populates the ArrayLists specifying disallowed hotkeys - /// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc - /// - private void PopulateModifierLists() { - // Shift + 0 - 9, A - Z - for (Keys k = Keys.D0; k <= Keys.Z; k++) { - _needNonShiftModifier.Add((int)k); - } - - // Shift + Numpad keys - for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++) { - _needNonShiftModifier.Add((int)k); - } - - // Shift + Misc (,;<./ etc) - for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++) { - _needNonShiftModifier.Add((int)k); - } - - // Shift + Space, PgUp, PgDn, End, Home - for (Keys k = Keys.Space; k <= Keys.Home; k++) { - _needNonShiftModifier.Add((int)k); - } - - // Misc keys that we can't loop through - _needNonShiftModifier.Add((int)Keys.Insert); - _needNonShiftModifier.Add((int)Keys.Help); - _needNonShiftModifier.Add((int)Keys.Multiply); - _needNonShiftModifier.Add((int)Keys.Add); - _needNonShiftModifier.Add((int)Keys.Subtract); - _needNonShiftModifier.Add((int)Keys.Divide); - _needNonShiftModifier.Add((int)Keys.Decimal); - _needNonShiftModifier.Add((int)Keys.Return); - _needNonShiftModifier.Add((int)Keys.Escape); - _needNonShiftModifier.Add((int)Keys.NumLock); - - // Ctrl+Alt + 0 - 9 - for (Keys k = Keys.D0; k <= Keys.D9; k++) { - _needNonAltGrModifier.Add((int)k); - } - } - - /// - /// Resets this hotkey control to None - /// - public new void Clear() { - Hotkey = Keys.None; - HotkeyModifiers = Keys.None; - } - - /// - /// Fires when a key is pushed down. Here, we'll want to update the text in the box - /// to notify the user what combination is currently pressed. - /// - private void HotkeyControl_KeyDown(object sender, KeyEventArgs e) { - // Clear the current hotkey - if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete) { - ResetHotkey(); - } else { - _modifiers = e.Modifiers; - _hotkey = e.KeyCode; - Redraw(); - } - } - - /// - /// Fires when all keys are released. If the current hotkey isn't valid, reset it. - /// Otherwise, do nothing and keep the text and hotkey as it was. - /// - private void HotkeyControl_KeyUp(object sender, KeyEventArgs e) { - // Somehow the PrintScreen only comes as a keyup, therefore we handle it here. - if (e.KeyCode == Keys.PrintScreen) { - _modifiers = e.Modifiers; - _hotkey = e.KeyCode; - Redraw(); - } - - if (_hotkey == Keys.None && ModifierKeys == Keys.None) { - ResetHotkey(); - } - } - - /// - /// Prevents the letter/whatever entered to show up in the TextBox - /// Without this, a "A" key press would appear as "aControl, Alt + A" - /// - private void HotkeyControl_KeyPress(object sender, KeyPressEventArgs e) { - e.Handled = true; - } - - /// - /// Handles some misc keys, such as Ctrl+Delete and Shift+Insert - /// - protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { - if (keyData == Keys.Delete || keyData == (Keys.Control | Keys.Delete)) { - ResetHotkey(); - return true; - } - - // Paste - if (keyData == (Keys.Shift | Keys.Insert)) { - return true; // Don't allow - } - - // Allow the rest - return base.ProcessCmdKey(ref msg, keyData); - } - - /// - /// Clears the current hotkey and resets the TextBox - /// - public void ResetHotkey() { - _hotkey = Keys.None; - _modifiers = Keys.None; - Redraw(); - } - - /// - /// Used to get/set the hotkey (e.g. Keys.A) - /// - public Keys Hotkey { - get { - return _hotkey; - } - set { - _hotkey = value; - Redraw(true); - } - } - - /// - /// Used to get/set the hotkey (e.g. Keys.A) - /// - public void SetHotkey(string hotkey) { - _hotkey = HotkeyFromString(hotkey); - _modifiers = HotkeyModifiersFromString(hotkey); - Redraw(true); - } - - /// - /// Used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control) - /// - public Keys HotkeyModifiers { - get { - return _modifiers; - } - set { - _modifiers = value; - Redraw(true); - } - } - - /// - /// Redraws the TextBox when necessary. - /// - /// Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user. - private void Redraw(bool bCalledProgramatically = false) { - // No hotkey set - if (_hotkey == Keys.None) { - Text = string.Empty; - return; - } - - // LWin/RWin doesn't work as hotkeys (neither do they work as modifier keys in .NET 2.0) - if (_hotkey == Keys.LWin || _hotkey == Keys.RWin) { - Text = string.Empty; - return; - } - - // Only validate input if it comes from the user - if (bCalledProgramatically == false) { - // No modifier or shift only, AND a hotkey that needs another modifier - if ((_modifiers == Keys.Shift || _modifiers == Keys.None) && _needNonShiftModifier.Contains((int)_hotkey)) { - if (_modifiers == Keys.None) { - // Set Ctrl+Alt as the modifier unless Ctrl+Alt+ won't work... - if (_needNonAltGrModifier.Contains((int)_hotkey) == false) { - _modifiers = Keys.Alt | Keys.Control; - } else { - // ... in that case, use Shift+Alt instead. - _modifiers = Keys.Alt | Keys.Shift; - } - } else { - // User pressed Shift and an invalid key (e.g. a letter or a number), - // that needs another set of modifier keys - _hotkey = Keys.None; - Text = string.Empty; - return; - } - } - // Check all Ctrl+Alt keys - if ((_modifiers == (Keys.Alt | Keys.Control)) && _needNonAltGrModifier.Contains((int)_hotkey)) { - // Ctrl+Alt+4 etc won't work; reset hotkey and tell the user - _hotkey = Keys.None; - Text = string.Empty; - return; - } - } - - // I have no idea why this is needed, but it is. Without this code, pressing only Ctrl - // will show up as "Control + ControlKey", etc. - if (_hotkey == Keys.Menu /* Alt */ || _hotkey == Keys.ShiftKey || _hotkey == Keys.ControlKey) { - _hotkey = Keys.None; - } - Text = HotkeyToLocalizedString(_modifiers, _hotkey); - } - - public override string ToString() { - return HotkeyToString(HotkeyModifiers, Hotkey); - } - - public static string GetLocalizedHotkeyStringFromString(string hotkeyString) { - Keys virtualKeyCode = HotkeyFromString(hotkeyString); - Keys modifiers = HotkeyModifiersFromString(hotkeyString); - return HotkeyToLocalizedString(modifiers, virtualKeyCode); - } - - public static string HotkeyToString(Keys modifierKeyCode, Keys virtualKeyCode) { - return HotkeyModifiersToString(modifierKeyCode) + virtualKeyCode; - } - - public static string HotkeyModifiersToString(Keys modifierKeyCode) { - StringBuilder hotkeyString = new StringBuilder(); - if ((modifierKeyCode & Keys.Alt) > 0) { - hotkeyString.Append("Alt").Append(" + "); - } - if ((modifierKeyCode & Keys.Control) > 0) { - hotkeyString.Append("Ctrl").Append(" + "); - } - if ((modifierKeyCode & Keys.Shift) > 0) { - hotkeyString.Append("Shift").Append(" + "); - } - if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) { - hotkeyString.Append("Win").Append(" + "); - } - return hotkeyString.ToString(); - } - - - public static string HotkeyToLocalizedString(Keys modifierKeyCode, Keys virtualKeyCode) { - return HotkeyModifiersToLocalizedString(modifierKeyCode) + GetKeyName(virtualKeyCode); - } - - public static string HotkeyModifiersToLocalizedString(Keys modifierKeyCode) { - StringBuilder hotkeyString = new StringBuilder(); - if ((modifierKeyCode & Keys.Alt) > 0) { - hotkeyString.Append(GetKeyName(Keys.Alt)).Append(" + "); - } - if ((modifierKeyCode & Keys.Control) > 0) { - hotkeyString.Append(GetKeyName(Keys.Control)).Append(" + "); - } - if ((modifierKeyCode & Keys.Shift) > 0) { - hotkeyString.Append(GetKeyName(Keys.Shift)).Append(" + "); - } - if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) { - hotkeyString.Append("Win").Append(" + "); - } - return hotkeyString.ToString(); - } - - - public static Keys HotkeyModifiersFromString(string modifiersString) { - Keys modifiers = Keys.None; - if (!string.IsNullOrEmpty(modifiersString)) { - if (modifiersString.ToLower().Contains("alt")) { - modifiers |= Keys.Alt; - } - if (modifiersString.ToLower().Contains("ctrl")) { - modifiers |= Keys.Control; - } - if (modifiersString.ToLower().Contains("shift")) { - modifiers |= Keys.Shift; - } - if (modifiersString.ToLower().Contains("win")) { - modifiers |= Keys.LWin; - } - } - return modifiers; - } - - public static Keys HotkeyFromString(string hotkey) { - Keys key = Keys.None; - if (!string.IsNullOrEmpty(hotkey)) { - if (hotkey.LastIndexOf('+') > 0) { - hotkey = hotkey.Remove(0,hotkey.LastIndexOf('+')+1).Trim(); - } - key = (Keys)Enum.Parse(typeof(Keys), hotkey); - } - return key; - } - - public static void RegisterHotkeyHwnd(IntPtr hWnd) { - _hotkeyHwnd = hWnd; - } + private readonly ContextMenuStrip _dummy = new ContextMenuStrip(); /// - /// Register a hotkey - /// - /// The modifier, e.g.: Modifiers.CTRL, Modifiers.NONE or Modifiers.ALT - /// The virtual key code - /// A HotKeyHandler, this will be called to handle the hotkey press - /// the hotkey number, -1 if failed - public static int RegisterHotKey(Keys modifierKeyCode, Keys virtualKeyCode, HotKeyHandler handler) { - if (virtualKeyCode == Keys.None) { - Log.Warn("Trying to register a Keys.none hotkey, ignoring"); - return 0; - } - // Convert Modifiers to fit HKM_SETHOTKEY - uint modifiers = 0; - if ((modifierKeyCode & Keys.Alt) > 0) { - modifiers |= (uint)Modifiers.ALT; - } - if ((modifierKeyCode & Keys.Control) > 0) { - modifiers |= (uint)Modifiers.CTRL; - } - if ((modifierKeyCode & Keys.Shift) > 0) { - modifiers |= (uint)Modifiers.SHIFT; - } - if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) { - modifiers |= (uint)Modifiers.WIN; - } - // Disable repeating hotkey for Windows 7 and beyond, as described in #1559 - if (IsWindows7OrOlder) { - modifiers |= (uint)Modifiers.NO_REPEAT; - } - if (RegisterHotKey(_hotkeyHwnd, _hotKeyCounter, modifiers, (uint)virtualKeyCode)) { - KeyHandlers.Add(_hotKeyCounter, handler); - return _hotKeyCounter++; - } - - Log.Warn($"Couldn't register hotkey modifier {modifierKeyCode} virtualKeyCode {virtualKeyCode}"); - return -1; - } - - public static void UnregisterHotkeys() { - foreach(int hotkey in KeyHandlers.Keys) { - UnregisterHotKey(_hotkeyHwnd, hotkey); - } - // Remove all key handlers - KeyHandlers.Clear(); - } + /// Used to make sure that there is no right-click menu available + ///
+ public override ContextMenuStrip ContextMenuStrip + { + get { return _dummy; } + set { base.ContextMenuStrip = _dummy; } + } /// - /// Handle WndProc messages for the hotkey - /// - /// - /// true if the message was handled - public static bool HandleMessages(ref Message m) { - if (m.Msg != WM_HOTKEY) - { - return false; - } - // Call handler - if (!IsWindows7OrOlder && !EventDelay.Check()) - { - return true; - } + /// Forces the control to be non-multiline + ///
+ public override bool Multiline + { + get { return base.Multiline; } + set + { + // Ignore what the user wants; force Multiline to false + base.Multiline = false; + } + } - if (KeyHandlers.TryGetValue((int)m.WParam, out var handler)) - { - handler(); - } - return true; - } + /// + /// Creates a new HotkeyControl + /// + public HotkeyControl() + { + ContextMenuStrip = _dummy; // Disable right-clicking + Text = "None"; - public static string GetKeyName(Keys givenKey) { - StringBuilder keyName = new StringBuilder(); - const uint numpad = 55; + // Handle events that occurs when keys are pressed + KeyPress += HotkeyControl_KeyPress; + KeyUp += HotkeyControl_KeyUp; + KeyDown += HotkeyControl_KeyDown; - Keys virtualKey = givenKey; - string keyString; - // Make VC's to real keys - switch(virtualKey) { - case Keys.Alt: - virtualKey = Keys.LMenu; - break; - case Keys.Control: - virtualKey = Keys.ControlKey; - break; - case Keys.Shift: - virtualKey = Keys.LShiftKey; - break; - case Keys.Multiply: - GetKeyNameText(numpad << 16, keyName, 100); - keyString = keyName.ToString().Replace("*", string.Empty).Trim().ToLower(); - if (keyString.IndexOf("(", StringComparison.Ordinal) >= 0) { - return "* " + keyString; - } - keyString = keyString.Substring(0,1).ToUpper() + keyString.Substring(1).ToLower(); - return keyString + " *"; - case Keys.Divide: - GetKeyNameText(numpad << 16, keyName, 100); - keyString = keyName.ToString().Replace("*", string.Empty).Trim().ToLower(); - if (keyString.IndexOf("(", StringComparison.Ordinal) >= 0) { - return "/ " + keyString; - } - keyString = keyString.Substring(0,1).ToUpper() + keyString.Substring(1).ToLower(); - return keyString + " /"; - } - uint scanCode = MapVirtualKey((uint)virtualKey, (uint)MapType.MAPVK_VK_TO_VSC); + PopulateModifierLists(); + } - // because MapVirtualKey strips the extended bit for some keys - switch (virtualKey) { - case Keys.Left: case Keys.Up: case Keys.Right: case Keys.Down: // arrow keys - case Keys.Prior: case Keys.Next: // page up and page down - case Keys.End: case Keys.Home: - case Keys.Insert: case Keys.Delete: - case Keys.NumLock: - Log.Debug("Modifying Extended bit"); - scanCode |= 0x100; // set extended bit - break; - case Keys.PrintScreen: // PrintScreen - scanCode = 311; - break; - case Keys.Pause: // PrintScreen - scanCode = 69; - break; - } - scanCode |= 0x200; - if (GetKeyNameText(scanCode << 16, keyName, 100) != 0) { - string visibleName = keyName.ToString(); - if (visibleName.Length > 1) { - visibleName = visibleName.Substring(0,1) + visibleName.Substring(1).ToLower(); - } - return visibleName; - } + /// + /// Populates the ArrayLists specifying disallowed hotkeys + /// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc + /// + private void PopulateModifierLists() + { + // Shift + 0 - 9, A - Z + for (Keys k = Keys.D0; k <= Keys.Z; k++) + { + _needNonShiftModifier.Add((int) k); + } - return givenKey.ToString(); - } - } + // Shift + Numpad keys + for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Shift + Misc (,;<./ etc) + for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Shift + Space, PgUp, PgDn, End, Home + for (Keys k = Keys.Space; k <= Keys.Home; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Misc keys that we can't loop through + _needNonShiftModifier.Add((int) Keys.Insert); + _needNonShiftModifier.Add((int) Keys.Help); + _needNonShiftModifier.Add((int) Keys.Multiply); + _needNonShiftModifier.Add((int) Keys.Add); + _needNonShiftModifier.Add((int) Keys.Subtract); + _needNonShiftModifier.Add((int) Keys.Divide); + _needNonShiftModifier.Add((int) Keys.Decimal); + _needNonShiftModifier.Add((int) Keys.Return); + _needNonShiftModifier.Add((int) Keys.Escape); + _needNonShiftModifier.Add((int) Keys.NumLock); + + // Ctrl+Alt + 0 - 9 + for (Keys k = Keys.D0; k <= Keys.D9; k++) + { + _needNonAltGrModifier.Add((int) k); + } + } + + /// + /// Resets this hotkey control to None + /// + public new void Clear() + { + Hotkey = Keys.None; + HotkeyModifiers = Keys.None; + } + + /// + /// Fires when a key is pushed down. Here, we'll want to update the text in the box + /// to notify the user what combination is currently pressed. + /// + private void HotkeyControl_KeyDown(object sender, KeyEventArgs e) + { + // Clear the current hotkey + if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete) + { + ResetHotkey(); + } + else + { + _modifiers = e.Modifiers; + _hotkey = e.KeyCode; + Redraw(); + } + } + + /// + /// Fires when all keys are released. If the current hotkey isn't valid, reset it. + /// Otherwise, do nothing and keep the text and hotkey as it was. + /// + private void HotkeyControl_KeyUp(object sender, KeyEventArgs e) + { + // Somehow the PrintScreen only comes as a keyup, therefore we handle it here. + if (e.KeyCode == Keys.PrintScreen) + { + _modifiers = e.Modifiers; + _hotkey = e.KeyCode; + Redraw(); + } + + if (_hotkey == Keys.None && ModifierKeys == Keys.None) + { + ResetHotkey(); + } + } + + /// + /// Prevents the letter/whatever entered to show up in the TextBox + /// Without this, a "A" key press would appear as "aControl, Alt + A" + /// + private void HotkeyControl_KeyPress(object sender, KeyPressEventArgs e) + { + e.Handled = true; + } + + /// + /// Handles some misc keys, such as Ctrl+Delete and Shift+Insert + /// + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (keyData == Keys.Delete || keyData == (Keys.Control | Keys.Delete)) + { + ResetHotkey(); + return true; + } + + // Paste + if (keyData == (Keys.Shift | Keys.Insert)) + { + return true; // Don't allow + } + + // Allow the rest + return base.ProcessCmdKey(ref msg, keyData); + } + + /// + /// Clears the current hotkey and resets the TextBox + /// + public void ResetHotkey() + { + _hotkey = Keys.None; + _modifiers = Keys.None; + Redraw(); + } + + /// + /// Used to get/set the hotkey (e.g. Keys.A) + /// + public Keys Hotkey + { + get { return _hotkey; } + set + { + _hotkey = value; + Redraw(true); + } + } + + /// + /// Used to get/set the hotkey (e.g. Keys.A) + /// + public void SetHotkey(string hotkey) + { + _hotkey = HotkeyFromString(hotkey); + _modifiers = HotkeyModifiersFromString(hotkey); + Redraw(true); + } + + /// + /// Used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control) + /// + public Keys HotkeyModifiers + { + get { return _modifiers; } + set + { + _modifiers = value; + Redraw(true); + } + } + + /// + /// Redraws the TextBox when necessary. + /// + /// Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user. + private void Redraw(bool bCalledProgramatically = false) + { + // No hotkey set + if (_hotkey == Keys.None) + { + Text = string.Empty; + return; + } + + // LWin/RWin doesn't work as hotkeys (neither do they work as modifier keys in .NET 2.0) + if (_hotkey == Keys.LWin || _hotkey == Keys.RWin) + { + Text = string.Empty; + return; + } + + // Only validate input if it comes from the user + if (bCalledProgramatically == false) + { + // No modifier or shift only, AND a hotkey that needs another modifier + if ((_modifiers == Keys.Shift || _modifiers == Keys.None) && _needNonShiftModifier.Contains((int) _hotkey)) + { + if (_modifiers == Keys.None) + { + // Set Ctrl+Alt as the modifier unless Ctrl+Alt+ won't work... + if (_needNonAltGrModifier.Contains((int) _hotkey) == false) + { + _modifiers = Keys.Alt | Keys.Control; + } + else + { + // ... in that case, use Shift+Alt instead. + _modifiers = Keys.Alt | Keys.Shift; + } + } + else + { + // User pressed Shift and an invalid key (e.g. a letter or a number), + // that needs another set of modifier keys + _hotkey = Keys.None; + Text = string.Empty; + return; + } + } + + // Check all Ctrl+Alt keys + if ((_modifiers == (Keys.Alt | Keys.Control)) && _needNonAltGrModifier.Contains((int) _hotkey)) + { + // Ctrl+Alt+4 etc won't work; reset hotkey and tell the user + _hotkey = Keys.None; + Text = string.Empty; + return; + } + } + + // I have no idea why this is needed, but it is. Without this code, pressing only Ctrl + // will show up as "Control + ControlKey", etc. + if (_hotkey == Keys.Menu /* Alt */ || _hotkey == Keys.ShiftKey || _hotkey == Keys.ControlKey) + { + _hotkey = Keys.None; + } + + Text = HotkeyToLocalizedString(_modifiers, _hotkey); + } + + public override string ToString() + { + return HotkeyToString(HotkeyModifiers, Hotkey); + } + + public static string GetLocalizedHotkeyStringFromString(string hotkeyString) + { + Keys virtualKeyCode = HotkeyFromString(hotkeyString); + Keys modifiers = HotkeyModifiersFromString(hotkeyString); + return HotkeyToLocalizedString(modifiers, virtualKeyCode); + } + + public static string HotkeyToString(Keys modifierKeyCode, Keys virtualKeyCode) + { + return HotkeyModifiersToString(modifierKeyCode) + virtualKeyCode; + } + + public static string HotkeyModifiersToString(Keys modifierKeyCode) + { + StringBuilder hotkeyString = new StringBuilder(); + if ((modifierKeyCode & Keys.Alt) > 0) + { + hotkeyString.Append("Alt").Append(" + "); + } + + if ((modifierKeyCode & Keys.Control) > 0) + { + hotkeyString.Append("Ctrl").Append(" + "); + } + + if ((modifierKeyCode & Keys.Shift) > 0) + { + hotkeyString.Append("Shift").Append(" + "); + } + + if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) + { + hotkeyString.Append("Win").Append(" + "); + } + + return hotkeyString.ToString(); + } + + + public static string HotkeyToLocalizedString(Keys modifierKeyCode, Keys virtualKeyCode) + { + return HotkeyModifiersToLocalizedString(modifierKeyCode) + GetKeyName(virtualKeyCode); + } + + public static string HotkeyModifiersToLocalizedString(Keys modifierKeyCode) + { + StringBuilder hotkeyString = new StringBuilder(); + if ((modifierKeyCode & Keys.Alt) > 0) + { + hotkeyString.Append(GetKeyName(Keys.Alt)).Append(" + "); + } + + if ((modifierKeyCode & Keys.Control) > 0) + { + hotkeyString.Append(GetKeyName(Keys.Control)).Append(" + "); + } + + if ((modifierKeyCode & Keys.Shift) > 0) + { + hotkeyString.Append(GetKeyName(Keys.Shift)).Append(" + "); + } + + if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) + { + hotkeyString.Append("Win").Append(" + "); + } + + return hotkeyString.ToString(); + } + + + public static Keys HotkeyModifiersFromString(string modifiersString) + { + Keys modifiers = Keys.None; + if (!string.IsNullOrEmpty(modifiersString)) + { + if (modifiersString.ToLower().Contains("alt")) + { + modifiers |= Keys.Alt; + } + + if (modifiersString.ToLower().Contains("ctrl")) + { + modifiers |= Keys.Control; + } + + if (modifiersString.ToLower().Contains("shift")) + { + modifiers |= Keys.Shift; + } + + if (modifiersString.ToLower().Contains("win")) + { + modifiers |= Keys.LWin; + } + } + + return modifiers; + } + + public static Keys HotkeyFromString(string hotkey) + { + Keys key = Keys.None; + if (!string.IsNullOrEmpty(hotkey)) + { + if (hotkey.LastIndexOf('+') > 0) + { + hotkey = hotkey.Remove(0, hotkey.LastIndexOf('+') + 1).Trim(); + } + + key = (Keys) Enum.Parse(typeof(Keys), hotkey); + } + + return key; + } + + public static void RegisterHotkeyHwnd(IntPtr hWnd) + { + _hotkeyHwnd = hWnd; + } + + /// + /// Register a hotkey + /// + /// The modifier, e.g.: Modifiers.CTRL, Modifiers.NONE or Modifiers.ALT + /// The virtual key code + /// A HotKeyHandler, this will be called to handle the hotkey press + /// the hotkey number, -1 if failed + public static int RegisterHotKey(Keys modifierKeyCode, Keys virtualKeyCode, HotKeyHandler handler) + { + if (virtualKeyCode == Keys.None) + { + Log.Warn("Trying to register a Keys.none hotkey, ignoring"); + return 0; + } + + // Convert Modifiers to fit HKM_SETHOTKEY + uint modifiers = 0; + if ((modifierKeyCode & Keys.Alt) > 0) + { + modifiers |= (uint) Modifiers.ALT; + } + + if ((modifierKeyCode & Keys.Control) > 0) + { + modifiers |= (uint) Modifiers.CTRL; + } + + if ((modifierKeyCode & Keys.Shift) > 0) + { + modifiers |= (uint) Modifiers.SHIFT; + } + + if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) + { + modifiers |= (uint) Modifiers.WIN; + } + + // Disable repeating hotkey for Windows 7 and beyond, as described in #1559 + if (IsWindows7OrOlder) + { + modifiers |= (uint) Modifiers.NO_REPEAT; + } + + if (RegisterHotKey(_hotkeyHwnd, _hotKeyCounter, modifiers, (uint) virtualKeyCode)) + { + KeyHandlers.Add(_hotKeyCounter, handler); + return _hotKeyCounter++; + } + + Log.Warn($"Couldn't register hotkey modifier {modifierKeyCode} virtualKeyCode {virtualKeyCode}"); + return -1; + } + + public static void UnregisterHotkeys() + { + foreach (int hotkey in KeyHandlers.Keys) + { + UnregisterHotKey(_hotkeyHwnd, hotkey); + } + + // Remove all key handlers + KeyHandlers.Clear(); + } + + /// + /// Handle WndProc messages for the hotkey + /// + /// + /// true if the message was handled + public static bool HandleMessages(ref Message m) + { + if (m.Msg != WM_HOTKEY) + { + return false; + } + + // Call handler + if (!IsWindows7OrOlder && !EventDelay.Check()) + { + return true; + } + + if (KeyHandlers.TryGetValue((int) m.WParam, out var handler)) + { + handler(); + } + + return true; + } + + public static string GetKeyName(Keys givenKey) + { + StringBuilder keyName = new StringBuilder(); + const uint numpad = 55; + + Keys virtualKey = givenKey; + string keyString; + // Make VC's to real keys + switch (virtualKey) + { + case Keys.Alt: + virtualKey = Keys.LMenu; + break; + case Keys.Control: + virtualKey = Keys.ControlKey; + break; + case Keys.Shift: + virtualKey = Keys.LShiftKey; + break; + case Keys.Multiply: + GetKeyNameText(numpad << 16, keyName, 100); + keyString = keyName.ToString().Replace("*", string.Empty).Trim().ToLower(); + if (keyString.IndexOf("(", StringComparison.Ordinal) >= 0) + { + return "* " + keyString; + } + + keyString = keyString.Substring(0, 1).ToUpper() + keyString.Substring(1).ToLower(); + return keyString + " *"; + case Keys.Divide: + GetKeyNameText(numpad << 16, keyName, 100); + keyString = keyName.ToString().Replace("*", string.Empty).Trim().ToLower(); + if (keyString.IndexOf("(", StringComparison.Ordinal) >= 0) + { + return "/ " + keyString; + } + + keyString = keyString.Substring(0, 1).ToUpper() + keyString.Substring(1).ToLower(); + return keyString + " /"; + } + + uint scanCode = MapVirtualKey((uint) virtualKey, (uint) MapType.MAPVK_VK_TO_VSC); + + // because MapVirtualKey strips the extended bit for some keys + switch (virtualKey) + { + case Keys.Left: + case Keys.Up: + case Keys.Right: + case Keys.Down: // arrow keys + case Keys.Prior: + case Keys.Next: // page up and page down + case Keys.End: + case Keys.Home: + case Keys.Insert: + case Keys.Delete: + case Keys.NumLock: + Log.Debug("Modifying Extended bit"); + scanCode |= 0x100; // set extended bit + break; + case Keys.PrintScreen: // PrintScreen + scanCode = 311; + break; + case Keys.Pause: // PrintScreen + scanCode = 69; + break; + } + + scanCode |= 0x200; + if (GetKeyNameText(scanCode << 16, keyName, 100) != 0) + { + string visibleName = keyName.ToString(); + if (visibleName.Length > 1) + { + visibleName = visibleName.Substring(0, 1) + visibleName.Substring(1).ToLower(); + } + + return visibleName; + } + + return givenKey.ToString(); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs b/src/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs index d20ed1cd1..e02358718 100644 --- a/src/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs +++ b/src/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs @@ -19,22 +19,18 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Controls { - public interface IGreenshotConfigBindable { - /// - /// The class where the property-value is stored - /// - string SectionName { - get; - set; - } +namespace GreenshotPlugin.Controls +{ + public interface IGreenshotConfigBindable + { + /// + /// The class where the property-value is stored + /// + string SectionName { get; set; } - /// - /// Path to the property value which will be mapped with this control - /// - string PropertyName { - get; - set; - } - } -} + /// + /// Path to the property value which will be mapped with this control + /// + string PropertyName { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs b/src/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs index 06237dcc9..c83c50d57 100644 --- a/src/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs +++ b/src/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs @@ -19,18 +19,16 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Controls { - /// - /// This interface describes the designer fields that need to be implemented for Greenshot controls - /// - public interface IGreenshotLanguageBindable { - /// - /// Language key to use to fill the Text value with - /// - string LanguageKey { - get; - set; - } - - } -} +namespace GreenshotPlugin.Controls +{ + /// + /// This interface describes the designer fields that need to be implemented for Greenshot controls + /// + public interface IGreenshotLanguageBindable + { + /// + /// Language key to use to fill the Text value with + /// + string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/OAuthLoginForm.cs b/src/GreenshotPlugin/Controls/OAuthLoginForm.cs index 998b938bb..59a1ea9ca 100644 --- a/src/GreenshotPlugin/Controls/OAuthLoginForm.cs +++ b/src/GreenshotPlugin/Controls/OAuthLoginForm.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; @@ -25,83 +26,96 @@ using System.Windows.Forms; using GreenshotPlugin.Core; using log4net; -namespace GreenshotPlugin.Controls { - /// - /// The OAuthLoginForm is used to allow the user to authorize Greenshot with an "Oauth" application - /// - public sealed partial class OAuthLoginForm : Form { - private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthLoginForm)); - private readonly string _callbackUrl; +namespace GreenshotPlugin.Controls +{ + /// + /// The OAuthLoginForm is used to allow the user to authorize Greenshot with an "Oauth" application + /// + public sealed partial class OAuthLoginForm : Form + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthLoginForm)); + private readonly string _callbackUrl; public IDictionary CallbackParameters { get; private set; } - public bool IsOk => DialogResult == DialogResult.OK; + public bool IsOk => DialogResult == DialogResult.OK; - public OAuthLoginForm(string browserTitle, Size size, string authorizationLink, string callbackUrl) { - // Make sure Greenshot uses the correct browser version - IEHelper.FixBrowserVersion(false); + public OAuthLoginForm(string browserTitle, Size size, string authorizationLink, string callbackUrl) + { + // Make sure Greenshot uses the correct browser version + IEHelper.FixBrowserVersion(false); - _callbackUrl = callbackUrl; - // Fix for BUG-2071 - if (callbackUrl.EndsWith("/")) - { - _callbackUrl = callbackUrl.Substring(0, callbackUrl.Length - 1); - } - InitializeComponent(); - ClientSize = size; - Icon = GreenshotResources.GetGreenshotIcon(); - Text = browserTitle; - _addressTextBox.Text = authorizationLink; + _callbackUrl = callbackUrl; + // Fix for BUG-2071 + if (callbackUrl.EndsWith("/")) + { + _callbackUrl = callbackUrl.Substring(0, callbackUrl.Length - 1); + } - // The script errors are suppressed by using the ExtendedWebBrowser - _browser.ScriptErrorsSuppressed = false; - _browser.DocumentCompleted += Browser_DocumentCompleted; - _browser.Navigated += Browser_Navigated; - _browser.Navigating += Browser_Navigating; - _browser.Navigate(new Uri(authorizationLink)); - } + InitializeComponent(); + ClientSize = size; + Icon = GreenshotResources.GetGreenshotIcon(); + Text = browserTitle; + _addressTextBox.Text = authorizationLink; - /// - /// Make sure the form is visible - /// - /// EventArgs - protected override void OnShown(EventArgs e) { - base.OnShown(e); - WindowDetails.ToForeground(Handle); - } + // The script errors are suppressed by using the ExtendedWebBrowser + _browser.ScriptErrorsSuppressed = false; + _browser.DocumentCompleted += Browser_DocumentCompleted; + _browser.Navigated += Browser_Navigated; + _browser.Navigating += Browser_Navigating; + _browser.Navigate(new Uri(authorizationLink)); + } - private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { - LOG.DebugFormat("document completed with url: {0}", _browser.Url); - CheckUrl(); - } + /// + /// Make sure the form is visible + /// + /// EventArgs + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + WindowDetails.ToForeground(Handle); + } - private void Browser_Navigating(object sender, WebBrowserNavigatingEventArgs e) { - LOG.DebugFormat("Navigating to url: {0}", _browser.Url); - _addressTextBox.Text = e.Url.ToString(); - } + private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) + { + LOG.DebugFormat("document completed with url: {0}", _browser.Url); + CheckUrl(); + } - private void Browser_Navigated(object sender, WebBrowserNavigatedEventArgs e) { - LOG.DebugFormat("Navigated to url: {0}", _browser.Url); - CheckUrl(); - } + private void Browser_Navigating(object sender, WebBrowserNavigatingEventArgs e) + { + LOG.DebugFormat("Navigating to url: {0}", _browser.Url); + _addressTextBox.Text = e.Url.ToString(); + } - private void CheckUrl() { - if (_browser.Url.ToString().StartsWith(_callbackUrl)) { - var correctedUri = new Uri(_browser.Url.AbsoluteUri.Replace("#", "&")); + private void Browser_Navigated(object sender, WebBrowserNavigatedEventArgs e) + { + LOG.DebugFormat("Navigated to url: {0}", _browser.Url); + CheckUrl(); + } - string queryParams = correctedUri.Query; - if (queryParams.Length > 0) { - queryParams = NetworkHelper.UrlDecode(queryParams); - //Store the Token and Token Secret - CallbackParameters = NetworkHelper.ParseQueryString(queryParams); - } - DialogResult = DialogResult.OK; - } - } + private void CheckUrl() + { + if (_browser.Url.ToString().StartsWith(_callbackUrl)) + { + var correctedUri = new Uri(_browser.Url.AbsoluteUri.Replace("#", "&")); - private void AddressTextBox_KeyPress(object sender, KeyPressEventArgs e) { - //Cancel the key press so the user can't enter a new url - e.Handled = true; - } - } -} + string queryParams = correctedUri.Query; + if (queryParams.Length > 0) + { + queryParams = NetworkHelper.UrlDecode(queryParams); + //Store the Token and Token Secret + CallbackParameters = NetworkHelper.ParseQueryString(queryParams); + } + + DialogResult = DialogResult.OK; + } + } + + private void AddressTextBox_KeyPress(object sender, KeyPressEventArgs e) + { + //Cancel the key press so the user can't enter a new url + e.Handled = true; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/PleaseWaitForm.cs b/src/GreenshotPlugin/Controls/PleaseWaitForm.cs index fecd1afc9..8d0ced972 100644 --- a/src/GreenshotPlugin/Controls/PleaseWaitForm.cs +++ b/src/GreenshotPlugin/Controls/PleaseWaitForm.cs @@ -18,107 +18,126 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Windows.Forms; using System.Threading; using GreenshotPlugin.Core; using log4net; -namespace GreenshotPlugin.Controls { - /// - /// Description of PleaseWaitForm. - /// - public partial class PleaseWaitForm : Form { - private static readonly ILog LOG = LogManager.GetLogger(typeof(PleaseWaitForm)); - private Thread _waitFor; - private string _title; - public PleaseWaitForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - Icon = GreenshotResources.GetGreenshotIcon(); - } - - /// - /// Prevent the close-window button showing - /// - private const int CP_NOCLOSE_BUTTON = 0x200; - protected override CreateParams CreateParams { - get { - CreateParams createParams = base.CreateParams; - createParams.ClassStyle |= CP_NOCLOSE_BUTTON ; - return createParams; - } - } - - /// - /// Show the "please wait" form, execute the code from the delegate and wait until execution finishes. - /// The supplied delegate will be wrapped with a try/catch so this method can return any exception that was thrown. - /// - /// The title of the form (and Thread) - /// The text in the form - /// delegate { with your code } - public void ShowAndWait(string title, string text, ThreadStart waitDelegate) { - _title = title; - Text = title; - label_pleasewait.Text = text; - cancelButton.Text = Language.GetString("CANCEL"); +namespace GreenshotPlugin.Controls +{ + /// + /// Description of PleaseWaitForm. + /// + public partial class PleaseWaitForm : Form + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(PleaseWaitForm)); + private Thread _waitFor; + private string _title; - // Make sure the form is shown. - Show(); - - // Variable to store the exception, if one is generated, from inside the thread. - Exception threadException = null; - try { - // Wrap the passed delegate in a try/catch which makes it possible to save the exception - _waitFor = new Thread(new ThreadStart( - delegate - { - try - { - waitDelegate.Invoke(); - } - catch (Exception ex) - { - LOG.Error("invoke error:", ex); - threadException = ex; - } - }) - ) - { - Name = title, - IsBackground = true - }; - _waitFor.SetApartmentState(ApartmentState.STA); - _waitFor.Start(); - - // Wait until finished - while (!_waitFor.Join(TimeSpan.FromMilliseconds(100))) { - Application.DoEvents(); - } - LOG.DebugFormat("Finished {0}", title); - } catch (Exception ex) { - LOG.Error(ex); - throw; - } finally { - Close(); - } - // Check if an exception occured, if so throw it - if (threadException != null) { - throw threadException; - } - } - - /// - /// Called if the cancel button is clicked, will use Thread.Abort() - /// - /// - /// - private void CancelButtonClick(object sender, EventArgs e) { - LOG.DebugFormat("Cancel clicked on {0}", _title); - cancelButton.Enabled = false; - _waitFor.Abort(); - } - } -} + public PleaseWaitForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + Icon = GreenshotResources.GetGreenshotIcon(); + } + + /// + /// Prevent the close-window button showing + /// + private const int CP_NOCLOSE_BUTTON = 0x200; + + protected override CreateParams CreateParams + { + get + { + CreateParams createParams = base.CreateParams; + createParams.ClassStyle |= CP_NOCLOSE_BUTTON; + return createParams; + } + } + + /// + /// Show the "please wait" form, execute the code from the delegate and wait until execution finishes. + /// The supplied delegate will be wrapped with a try/catch so this method can return any exception that was thrown. + /// + /// The title of the form (and Thread) + /// The text in the form + /// delegate { with your code } + public void ShowAndWait(string title, string text, ThreadStart waitDelegate) + { + _title = title; + Text = title; + label_pleasewait.Text = text; + cancelButton.Text = Language.GetString("CANCEL"); + + // Make sure the form is shown. + Show(); + + // Variable to store the exception, if one is generated, from inside the thread. + Exception threadException = null; + try + { + // Wrap the passed delegate in a try/catch which makes it possible to save the exception + _waitFor = new Thread(new ThreadStart( + delegate + { + try + { + waitDelegate.Invoke(); + } + catch (Exception ex) + { + LOG.Error("invoke error:", ex); + threadException = ex; + } + }) + ) + { + Name = title, + IsBackground = true + }; + _waitFor.SetApartmentState(ApartmentState.STA); + _waitFor.Start(); + + // Wait until finished + while (!_waitFor.Join(TimeSpan.FromMilliseconds(100))) + { + Application.DoEvents(); + } + + LOG.DebugFormat("Finished {0}", title); + } + catch (Exception ex) + { + LOG.Error(ex); + throw; + } + finally + { + Close(); + } + + // Check if an exception occured, if so throw it + if (threadException != null) + { + throw threadException; + } + } + + /// + /// Called if the cancel button is clicked, will use Thread.Abort() + /// + /// + /// + private void CancelButtonClick(object sender, EventArgs e) + { + LOG.DebugFormat("Cancel clicked on {0}", _title); + cancelButton.Enabled = false; + _waitFor.Abort(); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/QualityDialog.cs b/src/GreenshotPlugin/Controls/QualityDialog.cs index 0e196f387..ae8ae07f2 100644 --- a/src/GreenshotPlugin/Controls/QualityDialog.cs +++ b/src/GreenshotPlugin/Controls/QualityDialog.cs @@ -18,50 +18,54 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using GreenshotPlugin.Core; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces.Plugin; -namespace GreenshotPlugin.Controls { - /// - /// Description of JpegQualityDialog. - /// - public partial class QualityDialog : GreenshotForm { - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - public SurfaceOutputSettings Settings { - get; - set; - } +namespace GreenshotPlugin.Controls +{ + /// + /// Description of JpegQualityDialog. + /// + public partial class QualityDialog : GreenshotForm + { + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + public SurfaceOutputSettings Settings { get; set; } - public QualityDialog(SurfaceOutputSettings outputSettings) { - Settings = outputSettings; - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); + public QualityDialog(SurfaceOutputSettings outputSettings) + { + Settings = outputSettings; + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); - checkBox_reduceColors.Checked = Settings.ReduceColors; - trackBarJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); - trackBarJpegQuality.Value = Settings.JPGQuality; - textBoxJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); - textBoxJpegQuality.Text = Settings.JPGQuality.ToString(); - ToFront = true; - } + checkBox_reduceColors.Checked = Settings.ReduceColors; + trackBarJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); + trackBarJpegQuality.Value = Settings.JPGQuality; + textBoxJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); + textBoxJpegQuality.Text = Settings.JPGQuality.ToString(); + ToFront = true; + } - private void Button_okClick(object sender, EventArgs e) { - Settings.JPGQuality = trackBarJpegQuality.Value; - Settings.ReduceColors = checkBox_reduceColors.Checked; - if (checkbox_dontaskagain.Checked) { - conf.OutputFileJpegQuality = Settings.JPGQuality; - conf.OutputFilePromptQuality = false; - conf.OutputFileReduceColors = Settings.ReduceColors; - IniConfig.Save(); - } - } + private void Button_okClick(object sender, EventArgs e) + { + Settings.JPGQuality = trackBarJpegQuality.Value; + Settings.ReduceColors = checkBox_reduceColors.Checked; + if (checkbox_dontaskagain.Checked) + { + conf.OutputFileJpegQuality = Settings.JPGQuality; + conf.OutputFilePromptQuality = false; + conf.OutputFileReduceColors = Settings.ReduceColors; + IniConfig.Save(); + } + } - private void TrackBarJpegQualityScroll(object sender, EventArgs e) { - textBoxJpegQuality.Text = trackBarJpegQuality.Value.ToString(); - } - } -} + private void TrackBarJpegQualityScroll(object sender, EventArgs e) + { + textBoxJpegQuality.Text = trackBarJpegQuality.Value.ToString(); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/SaveImageFileDialog.cs b/src/GreenshotPlugin/Controls/SaveImageFileDialog.cs index a27eccd15..49caedb07 100644 --- a/src/GreenshotPlugin/Controls/SaveImageFileDialog.cs +++ b/src/GreenshotPlugin/Controls/SaveImageFileDialog.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.IO; using System.Windows.Forms; @@ -26,174 +27,209 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using log4net; -namespace GreenshotPlugin.Controls { - /// - /// Custom dialog for saving images, wraps SaveFileDialog. - /// For some reason SFD is sealed :( - /// - public class SaveImageFileDialog : IDisposable { - private static readonly ILog LOG = LogManager.GetLogger(typeof(SaveImageFileDialog)); - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - protected SaveFileDialog SaveFileDialog; - private FilterOption[] _filterOptions; - private DirectoryInfo _eagerlyCreatedDirectory; - private readonly ICaptureDetails _captureDetails; +namespace GreenshotPlugin.Controls +{ + /// + /// Custom dialog for saving images, wraps SaveFileDialog. + /// For some reason SFD is sealed :( + /// + public class SaveImageFileDialog : IDisposable + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(SaveImageFileDialog)); + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + protected SaveFileDialog SaveFileDialog; + private FilterOption[] _filterOptions; + private DirectoryInfo _eagerlyCreatedDirectory; + private readonly ICaptureDetails _captureDetails; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected virtual void Dispose(bool disposing) { - if (disposing) { - if (SaveFileDialog != null) { - SaveFileDialog.Dispose(); - SaveFileDialog = null; - } - } - } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (SaveFileDialog != null) + { + SaveFileDialog.Dispose(); + SaveFileDialog = null; + } + } + } - public SaveImageFileDialog(ICaptureDetails captureDetails) { - _captureDetails = captureDetails; - Init(); - } + public SaveImageFileDialog(ICaptureDetails captureDetails) + { + _captureDetails = captureDetails; + Init(); + } - private void Init() { - SaveFileDialog = new SaveFileDialog(); - ApplyFilterOptions(); - string initialDirectory = null; - try { - conf.ValidateAndCorrectOutputFileAsFullpath(); - initialDirectory = Path.GetDirectoryName(conf.OutputFileAsFullpath); - } catch { - LOG.WarnFormat("OutputFileAsFullpath was set to {0}, ignoring due to problem in path.", conf.OutputFileAsFullpath); - } - - if (!string.IsNullOrEmpty(initialDirectory) && Directory.Exists(initialDirectory)) { - SaveFileDialog.InitialDirectory = initialDirectory; - } else if (Directory.Exists(conf.OutputFilePath)) { - SaveFileDialog.InitialDirectory = conf.OutputFilePath; - } - // The following property fixes a problem that the directory where we save is locked (bug #2899790) - SaveFileDialog.RestoreDirectory = true; - SaveFileDialog.OverwritePrompt = true; - SaveFileDialog.CheckPathExists = false; - SaveFileDialog.AddExtension = true; - ApplySuggestedValues(); - } + private void Init() + { + SaveFileDialog = new SaveFileDialog(); + ApplyFilterOptions(); + string initialDirectory = null; + try + { + conf.ValidateAndCorrectOutputFileAsFullpath(); + initialDirectory = Path.GetDirectoryName(conf.OutputFileAsFullpath); + } + catch + { + LOG.WarnFormat("OutputFileAsFullpath was set to {0}, ignoring due to problem in path.", conf.OutputFileAsFullpath); + } - private void ApplyFilterOptions() { - PrepareFilterOptions(); - string fdf = string.Empty; - int preselect = 0; - var outputFileFormatAsString = Enum.GetName(typeof(OutputFormat), conf.OutputFileFormat); - for(int i=0; i<_filterOptions.Length; i++){ - FilterOption fo = _filterOptions[i]; - fdf += fo.Label + "|*." + fo.Extension + "|"; - if(outputFileFormatAsString == fo.Extension) - preselect = i; - } - fdf = fdf.Substring(0, fdf.Length-1); - SaveFileDialog.Filter = fdf; - SaveFileDialog.FilterIndex = preselect + 1; - } - - private void PrepareFilterOptions() { - OutputFormat[] supportedImageFormats = (OutputFormat[])Enum.GetValues(typeof(OutputFormat)); - _filterOptions = new FilterOption[supportedImageFormats.Length]; - for(int i=0; i<_filterOptions.Length; i++){ - string ifo = supportedImageFormats[i].ToString(); - if (ifo.ToLower().Equals("jpeg")) ifo = "Jpg"; // we dont want no jpeg files, so let the dialog check for jpg - FilterOption fo = new FilterOption - { - Label = ifo.ToUpper(), - Extension = ifo.ToLower() - }; - _filterOptions.SetValue(fo, i); - } - } - - /// - /// filename exactly as typed in the filename field - /// - public string FileName { - get {return SaveFileDialog.FileName;} - set {SaveFileDialog.FileName = value;} - } - - /// - /// initial directory of the dialog - /// - public string InitialDirectory { - get {return SaveFileDialog.InitialDirectory;} - set {SaveFileDialog.InitialDirectory = value;} - } - - /// - /// returns filename as typed in the filename field with extension. - /// if filename field value ends with selected extension, the value is just returned. - /// otherwise, the selected extension is appended to the filename. - /// - public string FileNameWithExtension { - get { - string fn = SaveFileDialog.FileName; - // if the filename contains a valid extension, which is the same like the selected filter item's extension, the filename is okay - if(fn.EndsWith(Extension,StringComparison.CurrentCultureIgnoreCase)) return fn; - // otherwise we just add the selected filter item's extension - else return fn + "." + Extension; - } - set { - FileName = Path.GetFileNameWithoutExtension(value); - Extension = Path.GetExtension(value); - } - } - - /// - /// gets or sets selected extension - /// - public string Extension { - get { - return _filterOptions[SaveFileDialog.FilterIndex-1].Extension; - } - set { - for(int i=0; i<_filterOptions.Length; i++) { - if(value.Equals(_filterOptions[i].Extension, StringComparison.CurrentCultureIgnoreCase)) { - SaveFileDialog.FilterIndex = i + 1; - } - } - } - } - - public DialogResult ShowDialog() { - DialogResult ret = SaveFileDialog.ShowDialog(); - CleanUp(); - return ret; - } - - /// - /// sets InitialDirectory and FileName property of a SaveFileDialog smartly, considering default pattern and last used path - /// - private void ApplySuggestedValues() { - // build the full path and set dialog properties - FileName = FilenameHelper.GetFilenameWithoutExtensionFromPattern(conf.OutputFileFilenamePattern, _captureDetails); - } + if (!string.IsNullOrEmpty(initialDirectory) && Directory.Exists(initialDirectory)) + { + SaveFileDialog.InitialDirectory = initialDirectory; + } + else if (Directory.Exists(conf.OutputFilePath)) + { + SaveFileDialog.InitialDirectory = conf.OutputFilePath; + } - private class FilterOption { - public string Label; - public string Extension; - } - - private void CleanUp() { - // fix for bug #3379053 - try { - if(_eagerlyCreatedDirectory != null && _eagerlyCreatedDirectory.GetFiles().Length == 0 && _eagerlyCreatedDirectory.GetDirectories().Length == 0) { - _eagerlyCreatedDirectory.Delete(); - _eagerlyCreatedDirectory = null; - } - } catch (Exception e) { - LOG.WarnFormat("Couldn't cleanup directory due to: {0}", e.Message); - _eagerlyCreatedDirectory = null; - } - } - } -} + // The following property fixes a problem that the directory where we save is locked (bug #2899790) + SaveFileDialog.RestoreDirectory = true; + SaveFileDialog.OverwritePrompt = true; + SaveFileDialog.CheckPathExists = false; + SaveFileDialog.AddExtension = true; + ApplySuggestedValues(); + } + + private void ApplyFilterOptions() + { + PrepareFilterOptions(); + string fdf = string.Empty; + int preselect = 0; + var outputFileFormatAsString = Enum.GetName(typeof(OutputFormat), conf.OutputFileFormat); + for (int i = 0; i < _filterOptions.Length; i++) + { + FilterOption fo = _filterOptions[i]; + fdf += fo.Label + "|*." + fo.Extension + "|"; + if (outputFileFormatAsString == fo.Extension) + preselect = i; + } + + fdf = fdf.Substring(0, fdf.Length - 1); + SaveFileDialog.Filter = fdf; + SaveFileDialog.FilterIndex = preselect + 1; + } + + private void PrepareFilterOptions() + { + OutputFormat[] supportedImageFormats = (OutputFormat[]) Enum.GetValues(typeof(OutputFormat)); + _filterOptions = new FilterOption[supportedImageFormats.Length]; + for (int i = 0; i < _filterOptions.Length; i++) + { + string ifo = supportedImageFormats[i].ToString(); + if (ifo.ToLower().Equals("jpeg")) ifo = "Jpg"; // we dont want no jpeg files, so let the dialog check for jpg + FilterOption fo = new FilterOption + { + Label = ifo.ToUpper(), + Extension = ifo.ToLower() + }; + _filterOptions.SetValue(fo, i); + } + } + + /// + /// filename exactly as typed in the filename field + /// + public string FileName + { + get { return SaveFileDialog.FileName; } + set { SaveFileDialog.FileName = value; } + } + + /// + /// initial directory of the dialog + /// + public string InitialDirectory + { + get { return SaveFileDialog.InitialDirectory; } + set { SaveFileDialog.InitialDirectory = value; } + } + + /// + /// returns filename as typed in the filename field with extension. + /// if filename field value ends with selected extension, the value is just returned. + /// otherwise, the selected extension is appended to the filename. + /// + public string FileNameWithExtension + { + get + { + string fn = SaveFileDialog.FileName; + // if the filename contains a valid extension, which is the same like the selected filter item's extension, the filename is okay + if (fn.EndsWith(Extension, StringComparison.CurrentCultureIgnoreCase)) return fn; + // otherwise we just add the selected filter item's extension + else return fn + "." + Extension; + } + set + { + FileName = Path.GetFileNameWithoutExtension(value); + Extension = Path.GetExtension(value); + } + } + + /// + /// gets or sets selected extension + /// + public string Extension + { + get { return _filterOptions[SaveFileDialog.FilterIndex - 1].Extension; } + set + { + for (int i = 0; i < _filterOptions.Length; i++) + { + if (value.Equals(_filterOptions[i].Extension, StringComparison.CurrentCultureIgnoreCase)) + { + SaveFileDialog.FilterIndex = i + 1; + } + } + } + } + + public DialogResult ShowDialog() + { + DialogResult ret = SaveFileDialog.ShowDialog(); + CleanUp(); + return ret; + } + + /// + /// sets InitialDirectory and FileName property of a SaveFileDialog smartly, considering default pattern and last used path + /// + private void ApplySuggestedValues() + { + // build the full path and set dialog properties + FileName = FilenameHelper.GetFilenameWithoutExtensionFromPattern(conf.OutputFileFilenamePattern, _captureDetails); + } + + private class FilterOption + { + public string Label; + public string Extension; + } + + private void CleanUp() + { + // fix for bug #3379053 + try + { + if (_eagerlyCreatedDirectory != null && _eagerlyCreatedDirectory.GetFiles().Length == 0 && _eagerlyCreatedDirectory.GetDirectories().Length == 0) + { + _eagerlyCreatedDirectory.Delete(); + _eagerlyCreatedDirectory = null; + } + } + catch (Exception e) + { + LOG.WarnFormat("Couldn't cleanup directory due to: {0}", e.Message); + _eagerlyCreatedDirectory = null; + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/ThumbnailForm.cs b/src/GreenshotPlugin/Controls/ThumbnailForm.cs index aae16b46c..2b6b349b4 100644 --- a/src/GreenshotPlugin/Controls/ThumbnailForm.cs +++ b/src/GreenshotPlugin/Controls/ThumbnailForm.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Windows.Forms; using GreenshotPlugin.Core; @@ -28,39 +29,44 @@ using GreenshotPlugin.UnmanagedHelpers; using GreenshotPlugin.UnmanagedHelpers.Enums; using GreenshotPlugin.UnmanagedHelpers.Structs; -namespace GreenshotPlugin.Controls { - /// - /// This form allows us to show a Thumbnail preview of a window near the context menu when selecting a window to capture. - /// Didn't make it completely "generic" yet, but at least most logic is in here so we don't have it in the mainform. - /// - public sealed class ThumbnailForm : FormWithoutActivation { - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); +namespace GreenshotPlugin.Controls +{ + /// + /// This form allows us to show a Thumbnail preview of a window near the context menu when selecting a window to capture. + /// Didn't make it completely "generic" yet, but at least most logic is in here so we don't have it in the mainform. + /// + public sealed class ThumbnailForm : FormWithoutActivation + { + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - private IntPtr _thumbnailHandle = IntPtr.Zero; + private IntPtr _thumbnailHandle = IntPtr.Zero; - public ThumbnailForm() { - ShowInTaskbar = false; - FormBorderStyle = FormBorderStyle.None; - TopMost = false; - Enabled = false; - if (conf.WindowCaptureMode == WindowCaptureMode.Auto || conf.WindowCaptureMode == WindowCaptureMode.Aero) { - BackColor = Color.FromArgb(255, conf.DWMBackgroundColor.R, conf.DWMBackgroundColor.G, conf.DWMBackgroundColor.B); - } else { - BackColor = Color.White; - } + public ThumbnailForm() + { + ShowInTaskbar = false; + FormBorderStyle = FormBorderStyle.None; + TopMost = false; + Enabled = false; + if (conf.WindowCaptureMode == WindowCaptureMode.Auto || conf.WindowCaptureMode == WindowCaptureMode.Aero) + { + BackColor = Color.FromArgb(255, conf.DWMBackgroundColor.R, conf.DWMBackgroundColor.G, conf.DWMBackgroundColor.B); + } + else + { + BackColor = Color.White; + } - // cleanup at close - FormClosing += delegate { - UnregisterThumbnail(); - }; - } + // cleanup at close + FormClosing += delegate { UnregisterThumbnail(); }; + } - public new void Hide() { - UnregisterThumbnail(); - base.Hide(); - } + public new void Hide() + { + UnregisterThumbnail(); + base.Hide(); + } - private void UnregisterThumbnail() + private void UnregisterThumbnail() { if (_thumbnailHandle == IntPtr.Zero) return; @@ -68,15 +74,16 @@ namespace GreenshotPlugin.Controls { _thumbnailHandle = IntPtr.Zero; } - /// - /// Show the thumbnail of the supplied window above (or under) the parent Control - /// - /// WindowDetails - /// Control - public void ShowThumbnail(WindowDetails window, Control parentControl) { - UnregisterThumbnail(); + /// + /// Show the thumbnail of the supplied window above (or under) the parent Control + /// + /// WindowDetails + /// Control + public void ShowThumbnail(WindowDetails window, Control parentControl) + { + UnregisterThumbnail(); - DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle); + DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle); if (_thumbnailHandle == IntPtr.Zero) return; var result = DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize); @@ -93,12 +100,13 @@ namespace GreenshotPlugin.Controls { } int thumbnailHeight = 200; - int thumbnailWidth = (int)(thumbnailHeight * (sourceSize.Width / (float)sourceSize.Height)); + int thumbnailWidth = (int) (thumbnailHeight * (sourceSize.Width / (float) sourceSize.Height)); if (parentControl != null && thumbnailWidth > parentControl.Width) { thumbnailWidth = parentControl.Width; - thumbnailHeight = (int)(thumbnailWidth * (sourceSize.Height / (float)sourceSize.Width)); + thumbnailHeight = (int) (thumbnailWidth * (sourceSize.Height / (float) sourceSize.Width)); } + Width = thumbnailWidth; Height = thumbnailHeight; // Prepare the displaying of the Thumbnail @@ -116,26 +124,34 @@ namespace GreenshotPlugin.Controls { return; } - if (parentControl != null) { + if (parentControl != null) + { AlignToControl(parentControl); } - if (!Visible) { + if (!Visible) + { Show(); } + // Make sure it's on "top"! - if (parentControl != null) { + if (parentControl != null) + { User32.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE); } } - public void AlignToControl(Control alignTo) { - var screenBounds = WindowCapture.GetScreenBounds(); - if (screenBounds.Contains(alignTo.Left, alignTo.Top - Height)) { - Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Top - Height); - } else { - Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Bottom); - } - } - } -} + public void AlignToControl(Control alignTo) + { + var screenBounds = WindowCapture.GetScreenBounds(); + if (screenBounds.Contains(alignTo.Left, alignTo.Top - Height)) + { + Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Top - Height); + } + else + { + Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Bottom); + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/AbstractDestination.cs b/src/GreenshotPlugin/Core/AbstractDestination.cs index 7efa0f570..27c6abbb4 100644 --- a/src/GreenshotPlugin/Core/AbstractDestination.cs +++ b/src/GreenshotPlugin/Core/AbstractDestination.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; @@ -28,323 +29,388 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.UnmanagedHelpers; using log4net; -namespace GreenshotPlugin.Core { - /// - /// Description of AbstractDestination. - /// - public abstract class AbstractDestination : IDestination { - private static readonly ILog Log = LogManager.GetLogger(typeof(AbstractDestination)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); +namespace GreenshotPlugin.Core +{ + /// + /// Description of AbstractDestination. + /// + public abstract class AbstractDestination : IDestination + { + private static readonly ILog Log = LogManager.GetLogger(typeof(AbstractDestination)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - public virtual int CompareTo(object obj) { - if (!(obj is IDestination other)) { - return 1; - } - if (Priority == other.Priority) { - return string.Compare(Description, other.Description, StringComparison.Ordinal); - } - return Priority - other.Priority; - } - - public abstract string Designation { - get; - } - - public abstract string Description { - get; - } - - public virtual int Priority => 10; - - public virtual Image DisplayIcon => null; - - public virtual Keys EditorShortcutKeys => Keys.None; - - public virtual IEnumerable DynamicDestinations() { - yield break; - } - - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) { - //if (disposing) {} - } - - public virtual bool IsDynamic => false; - - public virtual bool UseDynamicsOnly => false; - - public virtual bool IsLinkable => false; - - public virtual bool IsActive { - get { - if (CoreConfig.ExcludeDestinations != null && CoreConfig.ExcludeDestinations.Contains(Designation)) { - return false; - } - return true; - } - } - - public abstract ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); - - /// - /// A small helper method to perform some default destination actions, like inform the surface of the export - /// - /// - /// - public void ProcessExport(ExportInformation exportInformation, ISurface surface) { - if (exportInformation != null && exportInformation.ExportMade) { - if (!string.IsNullOrEmpty(exportInformation.Uri)) { - surface.UploadUrl = exportInformation.Uri; - surface.SendMessageEvent(this, SurfaceMessageTyp.UploadedUri, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); - } else if (!string.IsNullOrEmpty(exportInformation.Filepath)) { - surface.LastSaveFullPath = exportInformation.Filepath; - surface.SendMessageEvent(this, SurfaceMessageTyp.FileSaved, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); - } else { - surface.SendMessageEvent(this, SurfaceMessageTyp.Info, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); - } - surface.Modified = false; - } else if (!string.IsNullOrEmpty(exportInformation?.ErrorMessage)) { - surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("exported_to_error", exportInformation.DestinationDescription) + " " + exportInformation.ErrorMessage); - } - } - - public override string ToString() { - return Description; - } - - /// - /// Helper method to add events which set the tag, this way we can see why there might be a close. - /// - /// Item to add the events to - /// Menu to set the tag - /// Value for the tag - private void AddTagEvents(ToolStripMenuItem menuItem, ContextMenuStrip menu, string tagValue) { - if (menuItem != null && menu != null) { - menuItem.MouseDown += delegate - { - Log.DebugFormat("Setting tag to '{0}'", tagValue); - menu.Tag = tagValue; - }; - menuItem.MouseUp += delegate - { - Log.Debug("Deleting tag"); - menu.Tag = null; - }; - } - } - - /// - /// This method will create and show the destination picker menu - /// - /// Boolean if the dynamic values also need to be added - /// The surface which can be exported - /// Details for the surface - /// The list of destinations to show - /// - public ExportInformation ShowPickerMenu(bool addDynamics, ISurface surface, ICaptureDetails captureDetails, IEnumerable destinations) { - // Generate an empty ExportInformation object, for when nothing was selected. - ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker")); - var menu = new ContextMenuStrip - { - ImageScalingSize = CoreConfig.ScaledIconSize, - Tag = null, - TopLevel = true - }; - - menu.Opening += (sender, args) => + public virtual int CompareTo(object obj) + { + if (!(obj is IDestination other)) { - // find the DPI settings for the screen where this is going to land - var screenDpi = DpiHelper.GetDpi(menu.Location); - var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, screenDpi); + return 1; + } + + if (Priority == other.Priority) + { + return string.Compare(Description, other.Description, StringComparison.Ordinal); + } + + return Priority - other.Priority; + } + + public abstract string Designation { get; } + + public abstract string Description { get; } + + public virtual int Priority => 10; + + public virtual Image DisplayIcon => null; + + public virtual Keys EditorShortcutKeys => Keys.None; + + public virtual IEnumerable DynamicDestinations() + { + yield break; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + //if (disposing) {} + } + + public virtual bool IsDynamic => false; + + public virtual bool UseDynamicsOnly => false; + + public virtual bool IsLinkable => false; + + public virtual bool IsActive + { + get + { + if (CoreConfig.ExcludeDestinations != null && CoreConfig.ExcludeDestinations.Contains(Designation)) + { + return false; + } + + return true; + } + } + + public abstract ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); + + /// + /// A small helper method to perform some default destination actions, like inform the surface of the export + /// + /// + /// + public void ProcessExport(ExportInformation exportInformation, ISurface surface) + { + if (exportInformation != null && exportInformation.ExportMade) + { + if (!string.IsNullOrEmpty(exportInformation.Uri)) + { + surface.UploadUrl = exportInformation.Uri; + surface.SendMessageEvent(this, SurfaceMessageTyp.UploadedUri, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); + } + else if (!string.IsNullOrEmpty(exportInformation.Filepath)) + { + surface.LastSaveFullPath = exportInformation.Filepath; + surface.SendMessageEvent(this, SurfaceMessageTyp.FileSaved, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); + } + else + { + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); + } + + surface.Modified = false; + } + else if (!string.IsNullOrEmpty(exportInformation?.ErrorMessage)) + { + surface.SendMessageEvent(this, SurfaceMessageTyp.Error, + Language.GetFormattedString("exported_to_error", exportInformation.DestinationDescription) + " " + exportInformation.ErrorMessage); + } + } + + public override string ToString() + { + return Description; + } + + /// + /// Helper method to add events which set the tag, this way we can see why there might be a close. + /// + /// Item to add the events to + /// Menu to set the tag + /// Value for the tag + private void AddTagEvents(ToolStripMenuItem menuItem, ContextMenuStrip menu, string tagValue) + { + if (menuItem != null && menu != null) + { + menuItem.MouseDown += delegate + { + Log.DebugFormat("Setting tag to '{0}'", tagValue); + menu.Tag = tagValue; + }; + menuItem.MouseUp += delegate + { + Log.Debug("Deleting tag"); + menu.Tag = null; + }; + } + } + + /// + /// This method will create and show the destination picker menu + /// + /// Boolean if the dynamic values also need to be added + /// The surface which can be exported + /// Details for the surface + /// The list of destinations to show + /// + public ExportInformation ShowPickerMenu(bool addDynamics, ISurface surface, ICaptureDetails captureDetails, IEnumerable destinations) + { + // Generate an empty ExportInformation object, for when nothing was selected. + ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker")); + var menu = new ContextMenuStrip + { + ImageScalingSize = CoreConfig.ScaledIconSize, + Tag = null, + TopLevel = true + }; + + menu.Opening += (sender, args) => + { + // find the DPI settings for the screen where this is going to land + var screenDpi = DpiHelper.GetDpi(menu.Location); + var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, screenDpi); menu.SuspendLayout(); var fontSize = DpiHelper.ScaleWithDpi(12f, screenDpi); - menu.Font = new Font(FontFamily.GenericSansSerif, fontSize, FontStyle.Regular, GraphicsUnit.Pixel); + menu.Font = new Font(FontFamily.GenericSansSerif, fontSize, FontStyle.Regular, GraphicsUnit.Pixel); menu.ImageScalingSize = scaledIconSize; - menu.ResumeLayout(); - }; + menu.ResumeLayout(); + }; - menu.Closing += delegate(object source, ToolStripDropDownClosingEventArgs eventArgs) { - Log.DebugFormat("Close reason: {0}", eventArgs.CloseReason); - switch (eventArgs.CloseReason) { - case ToolStripDropDownCloseReason.AppFocusChange: - if (menu.Tag == null) { - // Do not allow the close if the tag is not set, this means the user clicked somewhere else. - eventArgs.Cancel = true; - } else { - Log.DebugFormat("Letting the menu 'close' as the tag is set to '{0}'", menu.Tag); - } - break; - case ToolStripDropDownCloseReason.ItemClicked: - case ToolStripDropDownCloseReason.CloseCalled: - // The ContextMenuStrip can be "closed" for these reasons. - break; - case ToolStripDropDownCloseReason.Keyboard: - // Dispose as the close is clicked - if (!captureDetails.HasDestination("Editor")) { - surface.Dispose(); - surface = null; - } - break; - default: - eventArgs.Cancel = true; - break; - } - }; - menu.MouseEnter += delegate - { - // in case the menu has been unfocused, focus again so that dropdown menus will still open on mouseenter + menu.Closing += delegate(object source, ToolStripDropDownClosingEventArgs eventArgs) + { + Log.DebugFormat("Close reason: {0}", eventArgs.CloseReason); + switch (eventArgs.CloseReason) + { + case ToolStripDropDownCloseReason.AppFocusChange: + if (menu.Tag == null) + { + // Do not allow the close if the tag is not set, this means the user clicked somewhere else. + eventArgs.Cancel = true; + } + else + { + Log.DebugFormat("Letting the menu 'close' as the tag is set to '{0}'", menu.Tag); + } + + break; + case ToolStripDropDownCloseReason.ItemClicked: + case ToolStripDropDownCloseReason.CloseCalled: + // The ContextMenuStrip can be "closed" for these reasons. + break; + case ToolStripDropDownCloseReason.Keyboard: + // Dispose as the close is clicked + if (!captureDetails.HasDestination("Editor")) + { + surface.Dispose(); + surface = null; + } + + break; + default: + eventArgs.Cancel = true; + break; + } + }; + menu.MouseEnter += delegate + { + // in case the menu has been unfocused, focus again so that dropdown menus will still open on mouseenter if (!menu.ContainsFocus) { menu.Focus(); } - }; - foreach (IDestination destination in destinations) { - // Fix foreach loop variable for the delegate - ToolStripMenuItem item = destination.GetMenuItem(addDynamics, menu, - delegate(object sender, EventArgs e) { - ToolStripMenuItem toolStripMenuItem = sender as ToolStripMenuItem; - IDestination clickedDestination = (IDestination) toolStripMenuItem?.Tag; - if (clickedDestination == null) { - return; - } - menu.Tag = clickedDestination.Designation; - // Export - exportInformation = clickedDestination.ExportCapture(true, surface, captureDetails); - if (exportInformation != null && exportInformation.ExportMade) { - Log.InfoFormat("Export to {0} success, closing menu", exportInformation.DestinationDescription); - // close menu if the destination wasn't the editor - menu.Close(); + }; + foreach (IDestination destination in destinations) + { + // Fix foreach loop variable for the delegate + ToolStripMenuItem item = destination.GetMenuItem(addDynamics, menu, + delegate(object sender, EventArgs e) + { + ToolStripMenuItem toolStripMenuItem = sender as ToolStripMenuItem; + IDestination clickedDestination = (IDestination) toolStripMenuItem?.Tag; + if (clickedDestination == null) + { + return; + } - // Cleanup surface, only if there is no editor in the destinations and we didn't export to the editor - if (!captureDetails.HasDestination("Editor") && !"Editor".Equals(clickedDestination.Designation)) { - surface.Dispose(); - surface = null; - } - } else { - Log.Info("Export cancelled or failed, showing menu again"); + menu.Tag = clickedDestination.Designation; + // Export + exportInformation = clickedDestination.ExportCapture(true, surface, captureDetails); + if (exportInformation != null && exportInformation.ExportMade) + { + Log.InfoFormat("Export to {0} success, closing menu", exportInformation.DestinationDescription); + // close menu if the destination wasn't the editor + menu.Close(); - // Make sure a click besides the menu don't close it. - menu.Tag = null; + // Cleanup surface, only if there is no editor in the destinations and we didn't export to the editor + if (!captureDetails.HasDestination("Editor") && !"Editor".Equals(clickedDestination.Designation)) + { + surface.Dispose(); + surface = null; + } + } + else + { + Log.Info("Export cancelled or failed, showing menu again"); - // This prevents the problem that the context menu shows in the task-bar - ShowMenuAtCursor(menu); - } - } - ); - if (item != null) { - menu.Items.Add(item); - } - } - // Close - menu.Items.Add(new ToolStripSeparator()); - ToolStripMenuItem closeItem = new ToolStripMenuItem(Language.GetString("editor_close")) - { - Image = GreenshotResources.GetImage("Close.Image") - }; - closeItem.Click += delegate { - // This menu entry is the close itself, we can dispose the surface - menu.Close(); - if (!captureDetails.HasDestination("Editor")) { - surface.Dispose(); - surface = null; - } - }; - menu.Items.Add(closeItem); + // Make sure a click besides the menu don't close it. + menu.Tag = null; - ShowMenuAtCursor(menu); - return exportInformation; - } + // This prevents the problem that the context menu shows in the task-bar + ShowMenuAtCursor(menu); + } + } + ); + if (item != null) + { + menu.Items.Add(item); + } + } - /// - /// This method will show the supplied context menu at the mouse cursor, also makes sure it has focus and it's not visible in the taskbar. - /// - /// - private static void ShowMenuAtCursor(ContextMenuStrip menu) { - // find a suitable location - Point location = Cursor.Position; - Rectangle menuRectangle = new Rectangle(location, menu.Size); + // Close + menu.Items.Add(new ToolStripSeparator()); + ToolStripMenuItem closeItem = new ToolStripMenuItem(Language.GetString("editor_close")) + { + Image = GreenshotResources.GetImage("Close.Image") + }; + closeItem.Click += delegate + { + // This menu entry is the close itself, we can dispose the surface + menu.Close(); + if (!captureDetails.HasDestination("Editor")) + { + surface.Dispose(); + surface = null; + } + }; + menu.Items.Add(closeItem); - menuRectangle.Intersect(WindowCapture.GetScreenBounds()); - if (menuRectangle.Height < menu.Height) { - location.Offset(-40, -(menuRectangle.Height - menu.Height)); - } else { - location.Offset(-40, -10); - } - // This prevents the problem that the context menu shows in the task-bar - User32.SetForegroundWindow(SimpleServiceProvider.Current.GetInstance().ContextMenuStrip.Handle); - menu.Show(location); - menu.Focus(); + ShowMenuAtCursor(menu); + return exportInformation; + } - // Wait for the menu to close, so we can dispose it. - while (true) { - if (menu.Visible) { - Application.DoEvents(); - Thread.Sleep(100); - } else { - menu.Dispose(); - break; - } - } - } + /// + /// This method will show the supplied context menu at the mouse cursor, also makes sure it has focus and it's not visible in the taskbar. + /// + /// + private static void ShowMenuAtCursor(ContextMenuStrip menu) + { + // find a suitable location + Point location = Cursor.Position; + Rectangle menuRectangle = new Rectangle(location, menu.Size); - /// - /// Return a menu item - /// - /// - /// - /// - /// ToolStripMenuItem - public virtual ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler) { - var basisMenuItem = new ToolStripMenuItem(Description) - { - Image = DisplayIcon, - Tag = this, - Text = Description - }; - AddTagEvents(basisMenuItem, menu, Description); - basisMenuItem.Click -= destinationClickHandler; - basisMenuItem.Click += destinationClickHandler; + menuRectangle.Intersect(WindowCapture.GetScreenBounds()); + if (menuRectangle.Height < menu.Height) + { + location.Offset(-40, -(menuRectangle.Height - menu.Height)); + } + else + { + location.Offset(-40, -10); + } - if (IsDynamic && addDynamics) { - basisMenuItem.DropDownOpening += delegate - { - if (basisMenuItem.DropDownItems.Count == 0) { - List subDestinations = new List(); - // Fixing Bug #3536968 by catching the COMException (every exception) and not displaying the "subDestinations" - try { - subDestinations.AddRange(DynamicDestinations()); - } catch (Exception ex) { - Log.ErrorFormat("Skipping {0}, due to the following error: {1}", Description, ex.Message); - } - if (subDestinations.Count > 0) { - if (UseDynamicsOnly && subDestinations.Count == 1) { - basisMenuItem.Tag = subDestinations[0]; - basisMenuItem.Text = subDestinations[0].Description; - basisMenuItem.Click -= destinationClickHandler; - basisMenuItem.Click += destinationClickHandler; - } else { - foreach (IDestination subDestination in subDestinations) { - var destinationMenuItem = new ToolStripMenuItem(subDestination.Description) - { - Tag = subDestination, - Image = subDestination.DisplayIcon - }; - destinationMenuItem.Click += destinationClickHandler; - AddTagEvents(destinationMenuItem, menu, subDestination.Description); - basisMenuItem.DropDownItems.Add(destinationMenuItem); - } - } - } - } - }; - } + // This prevents the problem that the context menu shows in the task-bar + User32.SetForegroundWindow(SimpleServiceProvider.Current.GetInstance().ContextMenuStrip.Handle); + menu.Show(location); + menu.Focus(); - return basisMenuItem; - } + // Wait for the menu to close, so we can dispose it. + while (true) + { + if (menu.Visible) + { + Application.DoEvents(); + Thread.Sleep(100); + } + else + { + menu.Dispose(); + break; + } + } + } - } -} + /// + /// Return a menu item + /// + /// + /// + /// + /// ToolStripMenuItem + public virtual ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler) + { + var basisMenuItem = new ToolStripMenuItem(Description) + { + Image = DisplayIcon, + Tag = this, + Text = Description + }; + AddTagEvents(basisMenuItem, menu, Description); + basisMenuItem.Click -= destinationClickHandler; + basisMenuItem.Click += destinationClickHandler; + + if (IsDynamic && addDynamics) + { + basisMenuItem.DropDownOpening += delegate + { + if (basisMenuItem.DropDownItems.Count == 0) + { + List subDestinations = new List(); + // Fixing Bug #3536968 by catching the COMException (every exception) and not displaying the "subDestinations" + try + { + subDestinations.AddRange(DynamicDestinations()); + } + catch (Exception ex) + { + Log.ErrorFormat("Skipping {0}, due to the following error: {1}", Description, ex.Message); + } + + if (subDestinations.Count > 0) + { + if (UseDynamicsOnly && subDestinations.Count == 1) + { + basisMenuItem.Tag = subDestinations[0]; + basisMenuItem.Text = subDestinations[0].Description; + basisMenuItem.Click -= destinationClickHandler; + basisMenuItem.Click += destinationClickHandler; + } + else + { + foreach (IDestination subDestination in subDestinations) + { + var destinationMenuItem = new ToolStripMenuItem(subDestination.Description) + { + Tag = subDestination, + Image = subDestination.DisplayIcon + }; + destinationMenuItem.Click += destinationClickHandler; + AddTagEvents(destinationMenuItem, menu, subDestination.Description); + basisMenuItem.DropDownItems.Add(destinationMenuItem); + } + } + } + } + }; + } + + return basisMenuItem; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/AbstractProcessor.cs b/src/GreenshotPlugin/Core/AbstractProcessor.cs index f93a405fb..6e016e857 100644 --- a/src/GreenshotPlugin/Core/AbstractProcessor.cs +++ b/src/GreenshotPlugin/Core/AbstractProcessor.cs @@ -18,46 +18,51 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using GreenshotPlugin.Interfaces; -namespace GreenshotPlugin.Core { - /// - /// Description of AbstractProcessor. - /// - public abstract class AbstractProcessor : IProcessor { +namespace GreenshotPlugin.Core +{ + /// + /// Description of AbstractProcessor. + /// + public abstract class AbstractProcessor : IProcessor + { + public virtual int CompareTo(object obj) + { + if (!(obj is IProcessor other)) + { + return 1; + } - public virtual int CompareTo(object obj) { - if (!(obj is IProcessor other)) { - return 1; - } - if (Priority == other.Priority) { - return string.Compare(Description, other.Description, StringComparison.Ordinal); - } - return Priority - other.Priority; - } + if (Priority == other.Priority) + { + return string.Compare(Description, other.Description, StringComparison.Ordinal); + } - public abstract string Designation { - get; - } + return Priority - other.Priority; + } - public abstract string Description { - get; - } + public abstract string Designation { get; } - public virtual int Priority => 10; + public abstract string Description { get; } - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public virtual int Priority => 10; - protected virtual void Dispose(bool disposing) { - //if (disposing) {} - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - public virtual bool isActive => true; + protected virtual void Dispose(bool disposing) + { + //if (disposing) {} + } + + public virtual bool isActive => true; public abstract bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); - } -} + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/AccessibleHelper.cs b/src/GreenshotPlugin/Core/AccessibleHelper.cs index 36d9e0ed5..9a88f68b8 100644 --- a/src/GreenshotPlugin/Core/AccessibleHelper.cs +++ b/src/GreenshotPlugin/Core/AccessibleHelper.cs @@ -18,175 +18,220 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Runtime.InteropServices; - using Accessibility; -namespace GreenshotPlugin.Core { +namespace GreenshotPlugin.Core +{ + /// + /// See: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/03a8c835-e9e4-405b-8345-6c3d36bc8941 + /// This should really be cleaned up, there is little OO behind this class! + /// Maybe move the basic Accessible functions to WindowDetails!? + /// + public class Accessible + { + private static int AccessibleObjectFromWindow(IntPtr hWnd, OBJID idObject, ref IAccessible acc) + { + var guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible + object obj = null; + int num = AccessibleObjectFromWindow(hWnd, (uint) idObject, ref guid, ref obj); + acc = (IAccessible) obj; + return num; + } - /// - /// See: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/03a8c835-e9e4-405b-8345-6c3d36bc8941 - /// This should really be cleaned up, there is little OO behind this class! - /// Maybe move the basic Accessible functions to WindowDetails!? - /// - public class Accessible { - private static int AccessibleObjectFromWindow(IntPtr hWnd, OBJID idObject, ref IAccessible acc) { - var guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible - object obj = null; - int num = AccessibleObjectFromWindow(hWnd, (uint)idObject, ref guid, ref obj); - acc = (IAccessible)obj; - return num; - } - [DllImport("oleacc.dll")] - private static extern int AccessibleObjectFromWindow(IntPtr hWnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject); - [DllImport("oleacc.dll")] - private static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] object[] rgvarChildren, out int pcObtained); - - [DllImport("oleacc.dll", PreserveSig=false)] - [return: MarshalAs(UnmanagedType.Interface)] - public static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam); + [DllImport("oleacc.dll")] + private static extern int AccessibleObjectFromWindow(IntPtr hWnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] + ref object ppvObject); - private enum OBJID : uint { - OBJID_WINDOW = 0x00000000, - } + [DllImport("oleacc.dll")] + private static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] + object[] rgvarChildren, out int pcObtained); - private const int IE_ACTIVE_TAB = 2097154; - private const int CHILDID_SELF = 0; - private readonly IAccessible accessible; - private Accessible[] Children { - get { + [DllImport("oleacc.dll", PreserveSig = false)] + [return: MarshalAs(UnmanagedType.Interface)] + public static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam); + + private enum OBJID : uint + { + OBJID_WINDOW = 0x00000000, + } + + private const int IE_ACTIVE_TAB = 2097154; + private const int CHILDID_SELF = 0; + private readonly IAccessible accessible; + + private Accessible[] Children + { + get + { object[] res = GetAccessibleChildren(accessible, out var num); - if (res == null) { - return new Accessible[0]; - } + if (res == null) + { + return new Accessible[0]; + } - List list = new List(res.Length); - foreach (object obj in res) { - if (obj is IAccessible acc) { - list.Add(new Accessible(acc)); - } - } - return list.ToArray(); - } - } + List list = new List(res.Length); + foreach (object obj in res) + { + if (obj is IAccessible acc) + { + list.Add(new Accessible(acc)); + } + } - private string Name { - get { - return accessible.get_accName(CHILDID_SELF); - } - } + return list.ToArray(); + } + } - private int ChildCount { - get { - return accessible.accChildCount; - } - } + private string Name + { + get { return accessible.get_accName(CHILDID_SELF); } + } - public Accessible(IntPtr hWnd) { - AccessibleObjectFromWindow(hWnd, OBJID.OBJID_WINDOW, ref accessible); - if (accessible == null) { - throw new Exception(); - } - } + private int ChildCount + { + get { return accessible.accChildCount; } + } - public void ActivateIETab(int tabIndexToActivate) { - var index = 0; - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - if (tabIndexToActivate >= child.ChildCount -1) { - return; - } + public Accessible(IntPtr hWnd) + { + AccessibleObjectFromWindow(hWnd, OBJID.OBJID_WINDOW, ref accessible); + if (accessible == null) + { + throw new Exception(); + } + } - if (index == tabIndexToActivate) { - tab.Activate(); - return; - } - index++; - } - } - } - } + public void ActivateIETab(int tabIndexToActivate) + { + var index = 0; + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + if (tabIndexToActivate >= child.ChildCount - 1) + { + return; + } - public string IEActiveTabCaption { - get { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - object tabIndex = tab.accessible.get_accState(0); - - if ((int)tabIndex == IE_ACTIVE_TAB) { - return tab.Name; - } - } - } - } - return string.Empty; - } - } + if (index == tabIndexToActivate) + { + tab.Activate(); + return; + } - public List IETabCaptions { - get { - var captionList = new List(); - - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - captionList.Add(tab.Name); - } - } - } - - // TODO: Why again? - if (captionList.Count > 0) { - captionList.RemoveAt(captionList.Count - 1); - } - - return captionList; - } - } - - - public IEnumerable IETabUrls { - get { - foreach (Accessible accessor in Children) { - foreach (var child in accessor.Children) { - foreach (var tab in child.Children) { - object tabIndex = tab.accessible.get_accState(CHILDID_SELF); - var description = tab.accessible.get_accDescription(CHILDID_SELF); - if (!string.IsNullOrEmpty(description)) { - if (description.Contains(Environment.NewLine)) { - var url = description.Substring(description.IndexOf(Environment.NewLine)).Trim(); - yield return url; - } - } - } - } - } - } - } + index++; + } + } + } + } - private Accessible(IAccessible acc) { + public string IEActiveTabCaption + { + get + { + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + object tabIndex = tab.accessible.get_accState(0); + + if ((int) tabIndex == IE_ACTIVE_TAB) + { + return tab.Name; + } + } + } + } + + return string.Empty; + } + } + + public List IETabCaptions + { + get + { + var captionList = new List(); + + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + captionList.Add(tab.Name); + } + } + } + + // TODO: Why again? + if (captionList.Count > 0) + { + captionList.RemoveAt(captionList.Count - 1); + } + + return captionList; + } + } + + + public IEnumerable IETabUrls + { + get + { + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + object tabIndex = tab.accessible.get_accState(CHILDID_SELF); + var description = tab.accessible.get_accDescription(CHILDID_SELF); + if (!string.IsNullOrEmpty(description)) + { + if (description.Contains(Environment.NewLine)) + { + var url = description.Substring(description.IndexOf(Environment.NewLine)).Trim(); + yield return url; + } + } + } + } + } + } + } + + private Accessible(IAccessible acc) + { accessible = acc ?? throw new Exception(); - } + } - private void Activate() { - accessible.accDoDefaultAction(CHILDID_SELF); - } + private void Activate() + { + accessible.accDoDefaultAction(CHILDID_SELF); + } - private static object[] GetAccessibleChildren(IAccessible ao, out int childs) { - childs = 0; - object[] ret = null; - int count = ao.accChildCount; + private static object[] GetAccessibleChildren(IAccessible ao, out int childs) + { + childs = 0; + object[] ret = null; + int count = ao.accChildCount; - if (count > 0) { - ret = new object[count]; - AccessibleChildren(ao, 0, count, ret, out childs); - } - return ret; - } - } -} + if (count > 0) + { + ret = new object[count]; + AccessibleChildren(ao, 0, count, ret, out childs); + } + return ret; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/AnimationHelpers.cs b/src/GreenshotPlugin/Core/AnimationHelpers.cs index 9ed92eef6..ed8282ac6 100644 --- a/src/GreenshotPlugin/Core/AnimationHelpers.cs +++ b/src/GreenshotPlugin/Core/AnimationHelpers.cs @@ -18,209 +18,199 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Collections.Generic; -namespace GreenshotPlugin.Core { +namespace GreenshotPlugin.Core +{ + /// + /// Helper interface for passing base type + /// + public interface IAnimator + { + /// + /// Is there a next frame? + /// + bool HasNext { get; } - /// - /// Helper interface for passing base type - /// - public interface IAnimator { - /// - /// Is there a next frame? - /// - bool HasNext { - get; - } - /// - /// The amount of frames - /// - int Frames { - get; - } + /// + /// The amount of frames + /// + int Frames { get; } - /// - /// Current frame number - /// - int CurrentFrameNr { - get; - } - } - - /// - /// This class is used to store a animation leg - /// - internal class AnimationLeg { - public T Destination { - get; - set; - } - - public int Frames { - get; - set; - } - - public EasingType EasingType { - get; - set; - } - - public EasingMode EasingMode { - get; - set; - } - } + /// + /// Current frame number + /// + int CurrentFrameNr { get; } + } - /// - /// Base class for the animation logic, this only implements Properties and a constructor - /// - /// Type for the animation, like Point/Rectangle/Size - public abstract class AnimatorBase : IAnimator { - private readonly Queue> _queue = new Queue>(); + /// + /// This class is used to store a animation leg + /// + internal class AnimationLeg + { + public T Destination { get; set; } - /// - /// Constructor - /// - /// - /// - /// - /// - /// - public AnimatorBase(T first, T last, int frames, EasingType easingType, EasingMode easingMode) { - First = first; - Last = last; - Frames = frames; - Current = first; - EasingType = easingType; - EasingMode = easingMode; - } + public int Frames { get; set; } - /// - /// The amount of frames - /// - public int Frames { - get; - private set; - } + public EasingType EasingType { get; set; } - /// - /// Current frame number - /// - public int CurrentFrameNr { get; private set; } + public EasingMode EasingMode { get; set; } + } - /// - /// First animation value - /// - public T First { get; private set; } - - /// - /// Last animation value, of this "leg" - /// - public T Last { get; private set; } + /// + /// Base class for the animation logic, this only implements Properties and a constructor + /// + /// Type for the animation, like Point/Rectangle/Size + public abstract class AnimatorBase : IAnimator + { + private readonly Queue> _queue = new Queue>(); - /// - /// Final animation value, this is including the legs - /// - public T Final { - get { - if (_queue.Count == 0) { - return Last; - } - return _queue.ToArray()[_queue.Count - 1].Destination; - } - } - - /// - /// This restarts the current animation and changes the last frame - /// - /// - public void ChangeDestination(T newDestination) { - ChangeDestination(newDestination, Frames); - } - - /// - /// This restarts the current animation and changes the last frame - /// - /// - /// - public void ChangeDestination(T newDestination, int frames) { - _queue.Clear(); - First = Current; - CurrentFrameNr = 0; - Frames = frames; - Last = newDestination; - } + /// + /// Constructor + /// + /// + /// + /// + /// + /// + public AnimatorBase(T first, T last, int frames, EasingType easingType, EasingMode easingMode) + { + First = first; + Last = last; + Frames = frames; + Current = first; + EasingType = easingType; + EasingMode = easingMode; + } - /// - /// Queue the destination, it will be used to continue at the last frame - /// All values will stay the same - /// - /// - public void QueueDestinationLeg(T queuedDestination) { - QueueDestinationLeg(queuedDestination, Frames, EasingType, EasingMode); - } + /// + /// The amount of frames + /// + public int Frames { get; private set; } - /// - /// Queue the destination, it will be used to continue at the last frame - /// - /// - /// - public void QueueDestinationLeg(T queuedDestination, int frames) { - QueueDestinationLeg(queuedDestination, frames, EasingType, EasingMode); - } + /// + /// Current frame number + /// + public int CurrentFrameNr { get; private set; } - /// - /// Queue the destination, it will be used to continue at the last frame - /// - /// - /// - /// EasingType - public void QueueDestinationLeg(T queuedDestination, int frames, EasingType easingType) { - QueueDestinationLeg(queuedDestination, frames, easingType, EasingMode); - } + /// + /// First animation value + /// + public T First { get; private set; } - /// - /// Queue the destination, it will be used to continue at the last frame - /// - /// - /// - /// - /// - public void QueueDestinationLeg(T queuedDestination, int frames, EasingType easingType, EasingMode easingMode) { - AnimationLeg leg = new AnimationLeg - { - Destination = queuedDestination, - Frames = frames, - EasingType = easingType, - EasingMode = easingMode - }; - _queue.Enqueue(leg); - } + /// + /// Last animation value, of this "leg" + /// + public T Last { get; private set; } - /// - /// The EasingType to use for the animation - /// - public EasingType EasingType { - get; - set; - } - - /// - /// The EasingMode to use for the animation - /// - public EasingMode EasingMode { - get; - set; - } + /// + /// Final animation value, this is including the legs + /// + public T Final + { + get + { + if (_queue.Count == 0) + { + return Last; + } - /// - /// Get the easing value, which is from 0-1 and depends on the frame - /// - protected double EasingValue { - get => + return _queue.ToArray()[_queue.Count - 1].Destination; + } + } + + /// + /// This restarts the current animation and changes the last frame + /// + /// + public void ChangeDestination(T newDestination) + { + ChangeDestination(newDestination, Frames); + } + + /// + /// This restarts the current animation and changes the last frame + /// + /// + /// + public void ChangeDestination(T newDestination, int frames) + { + _queue.Clear(); + First = Current; + CurrentFrameNr = 0; + Frames = frames; + Last = newDestination; + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// All values will stay the same + /// + /// + public void QueueDestinationLeg(T queuedDestination) + { + QueueDestinationLeg(queuedDestination, Frames, EasingType, EasingMode); + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// + /// + /// + public void QueueDestinationLeg(T queuedDestination, int frames) + { + QueueDestinationLeg(queuedDestination, frames, EasingType, EasingMode); + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// + /// + /// + /// EasingType + public void QueueDestinationLeg(T queuedDestination, int frames, EasingType easingType) + { + QueueDestinationLeg(queuedDestination, frames, easingType, EasingMode); + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// + /// + /// + /// + /// + public void QueueDestinationLeg(T queuedDestination, int frames, EasingType easingType, EasingMode easingMode) + { + AnimationLeg leg = new AnimationLeg + { + Destination = queuedDestination, + Frames = frames, + EasingType = easingType, + EasingMode = easingMode + }; + _queue.Enqueue(leg); + } + + /// + /// The EasingType to use for the animation + /// + public EasingType EasingType { get; set; } + + /// + /// The EasingMode to use for the animation + /// + public EasingMode EasingMode { get; set; } + + /// + /// Get the easing value, which is from 0-1 and depends on the frame + /// + protected double EasingValue + { + get => EasingMode switch { EasingMode.EaseOut => Easing.EaseOut(CurrentFrameNr / (double) Frames, EasingType), @@ -230,229 +220,285 @@ namespace GreenshotPlugin.Core { }; } - /// - /// Get the current (previous) frame object - /// - public virtual T Current { get; set; } - - /// - /// Returns if there are any frame left, and if this is the case than the frame is increased. - /// - public virtual bool NextFrame { - get { - if (CurrentFrameNr < Frames) { - CurrentFrameNr++; - return true; - } - if (_queue.Count > 0) { - First = Current; - CurrentFrameNr = 0; - AnimationLeg nextLeg = _queue.Dequeue(); - Last = nextLeg.Destination; - Frames = nextLeg.Frames; - EasingType = nextLeg.EasingType; - EasingMode = nextLeg.EasingMode; - return true; - } - return false; - } - } - - /// - /// Are there more frames to animate? - /// - public virtual bool HasNext { - get { - if (CurrentFrameNr < Frames) { - return true; - } - return _queue.Count > 0; - } - } + /// + /// Get the current (previous) frame object + /// + public virtual T Current { get; set; } - /// - /// Get the next animation frame value object - /// - /// - public abstract T Next(); - } + /// + /// Returns if there are any frame left, and if this is the case than the frame is increased. + /// + public virtual bool NextFrame + { + get + { + if (CurrentFrameNr < Frames) + { + CurrentFrameNr++; + return true; + } - /// - /// Implementation of the RectangleAnimator - /// - public class RectangleAnimator : AnimatorBase { - public RectangleAnimator(Rectangle first, Rectangle last, int frames) - : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) { - } - public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType) - : base(first, last, frames, easingType, EasingMode.EaseIn) { - } + if (_queue.Count > 0) + { + First = Current; + CurrentFrameNr = 0; + AnimationLeg nextLeg = _queue.Dequeue(); + Last = nextLeg.Destination; + Frames = nextLeg.Frames; + EasingType = nextLeg.EasingType; + EasingMode = nextLeg.EasingMode; + return true; + } - public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType, EasingMode easingMode) - : base(first, last, frames, easingType, easingMode) { - } + return false; + } + } - /// - /// Calculate the next frame object - /// - /// Rectangle - public override Rectangle Next() { - if (NextFrame) { - double easingValue = EasingValue; - double dx = Last.X - First.X; - double dy = Last.Y - First.Y; + /// + /// Are there more frames to animate? + /// + public virtual bool HasNext + { + get + { + if (CurrentFrameNr < Frames) + { + return true; + } - int x = First.X + (int)(easingValue * dx); - int y = First.Y + (int)(easingValue * dy); - double dw = Last.Width - First.Width; - double dh = Last.Height - First.Height; - int width = First.Width + (int)(easingValue * dw); - int height = First.Height + (int)(easingValue * dh); - Current = new Rectangle(x, y, width, height); - } - return Current; - } - } + return _queue.Count > 0; + } + } - /// - /// Implementation of the PointAnimator - /// - public class PointAnimator : AnimatorBase { - public PointAnimator(Point first, Point last, int frames) - : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) { - } - public PointAnimator(Point first, Point last, int frames, EasingType easingType) - : base(first, last, frames, easingType, EasingMode.EaseIn) { - } - public PointAnimator(Point first, Point last, int frames, EasingType easingType, EasingMode easingMode) - : base(first, last, frames, easingType, easingMode) { - } - - /// - /// Calculate the next frame value - /// - /// Point - public override Point Next() { - if (NextFrame) { - double easingValue = EasingValue; - double dx = Last.X - First.X; - double dy = Last.Y - First.Y; + /// + /// Get the next animation frame value object + /// + /// + public abstract T Next(); + } - int x = First.X + (int)(easingValue * dx); - int y = First.Y + (int)(easingValue * dy); - Current = new Point(x, y); - } - return Current; - } - } + /// + /// Implementation of the RectangleAnimator + /// + public class RectangleAnimator : AnimatorBase + { + public RectangleAnimator(Rectangle first, Rectangle last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } - /// - /// Implementation of the SizeAnimator - /// - public class SizeAnimator : AnimatorBase { - public SizeAnimator(Size first, Size last, int frames) - : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) { - } - public SizeAnimator(Size first, Size last, int frames, EasingType easingType) - : base(first, last, frames, easingType, EasingMode.EaseIn) { - } - public SizeAnimator(Size first, Size last, int frames, EasingType easingType, EasingMode easingMode) - : base(first, last, frames, easingType, easingMode) { - } + public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } - /// - /// Calculate the next frame values - /// - /// Size - public override Size Next() { - if (NextFrame) { - double easingValue = EasingValue; - double dw = Last.Width - First.Width; - double dh = Last.Height - First.Height; - int width = First.Width + (int)(easingValue * dw); - int height = First.Height + (int)(easingValue * dh); - Current = new Size(width, height); - } - return Current; - } - } + public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } - /// - /// Implementation of the ColorAnimator - /// - public class ColorAnimator : AnimatorBase { - public ColorAnimator(Color first, Color last, int frames) - : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) { - } - public ColorAnimator(Color first, Color last, int frames, EasingType easingType) - : base(first, last, frames, easingType, EasingMode.EaseIn) { - } - public ColorAnimator(Color first, Color last, int frames, EasingType easingType, EasingMode easingMode) - : base(first, last, frames, easingType, easingMode) { - } + /// + /// Calculate the next frame object + /// + /// Rectangle + public override Rectangle Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double dx = Last.X - First.X; + double dy = Last.Y - First.Y; - /// - /// Calculate the next frame values - /// - /// Color - public override Color Next() { - if (NextFrame) { - double easingValue = EasingValue; - double da = Last.A - First.A; - double dr = Last.R - First.R; - double dg = Last.G - First.G; - double db = Last.B - First.B; - int a = First.A + (int)(easingValue * da); - int r = First.R + (int)(easingValue * dr); - int g = First.G + (int)(easingValue * dg); - int b = First.B + (int)(easingValue * db); - Current = Color.FromArgb(a,r,g,b); - } - return Current; - } - } + int x = First.X + (int) (easingValue * dx); + int y = First.Y + (int) (easingValue * dy); + double dw = Last.Width - First.Width; + double dh = Last.Height - First.Height; + int width = First.Width + (int) (easingValue * dw); + int height = First.Height + (int) (easingValue * dh); + Current = new Rectangle(x, y, width, height); + } - /// - /// Implementation of the IntAnimator - /// - public class IntAnimator : AnimatorBase { - public IntAnimator(int first, int last, int frames) - : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) { - } - public IntAnimator(int first, int last, int frames, EasingType easingType) - : base(first, last, frames, easingType, EasingMode.EaseIn) { - } - public IntAnimator(int first, int last, int frames, EasingType easingType, EasingMode easingMode) - : base(first, last, frames, easingType, easingMode) { - } + return Current; + } + } - /// - /// Calculate the next frame values - /// - /// int - public override int Next() { - if (NextFrame) { - double easingValue = EasingValue; - double delta = Last - First; - Current = First + (int)(easingValue * delta); - } - return Current; - } - } + /// + /// Implementation of the PointAnimator + /// + public class PointAnimator : AnimatorBase + { + public PointAnimator(Point first, Point last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } - /// - /// Easing logic, to make the animations more "fluent" - /// - public static class Easing { - // Adapted from http://www.robertpenner.com/easing/penner_chapter7_tweening.pdf + public PointAnimator(Point first, Point last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } - public static double Ease(double linearStep, double acceleration, EasingType type) { - double easedStep = acceleration > 0 ? EaseIn(linearStep, type) : acceleration < 0 ? EaseOut(linearStep, type) : linearStep; - // Lerp: - return ((easedStep - linearStep) * Math.Abs(acceleration) + linearStep); - } + public PointAnimator(Point first, Point last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } - public static double EaseIn(double linearStep, EasingType type) => + /// + /// Calculate the next frame value + /// + /// Point + public override Point Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double dx = Last.X - First.X; + double dy = Last.Y - First.Y; + + int x = First.X + (int) (easingValue * dx); + int y = First.Y + (int) (easingValue * dy); + Current = new Point(x, y); + } + + return Current; + } + } + + /// + /// Implementation of the SizeAnimator + /// + public class SizeAnimator : AnimatorBase + { + public SizeAnimator(Size first, Size last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public SizeAnimator(Size first, Size last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public SizeAnimator(Size first, Size last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame values + /// + /// Size + public override Size Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double dw = Last.Width - First.Width; + double dh = Last.Height - First.Height; + int width = First.Width + (int) (easingValue * dw); + int height = First.Height + (int) (easingValue * dh); + Current = new Size(width, height); + } + + return Current; + } + } + + /// + /// Implementation of the ColorAnimator + /// + public class ColorAnimator : AnimatorBase + { + public ColorAnimator(Color first, Color last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public ColorAnimator(Color first, Color last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public ColorAnimator(Color first, Color last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame values + /// + /// Color + public override Color Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double da = Last.A - First.A; + double dr = Last.R - First.R; + double dg = Last.G - First.G; + double db = Last.B - First.B; + int a = First.A + (int) (easingValue * da); + int r = First.R + (int) (easingValue * dr); + int g = First.G + (int) (easingValue * dg); + int b = First.B + (int) (easingValue * db); + Current = Color.FromArgb(a, r, g, b); + } + + return Current; + } + } + + /// + /// Implementation of the IntAnimator + /// + public class IntAnimator : AnimatorBase + { + public IntAnimator(int first, int last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public IntAnimator(int first, int last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public IntAnimator(int first, int last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame values + /// + /// int + public override int Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double delta = Last - First; + Current = First + (int) (easingValue * delta); + } + + return Current; + } + } + + /// + /// Easing logic, to make the animations more "fluent" + /// + public static class Easing + { + // Adapted from http://www.robertpenner.com/easing/penner_chapter7_tweening.pdf + + public static double Ease(double linearStep, double acceleration, EasingType type) + { + double easedStep = acceleration > 0 ? EaseIn(linearStep, type) : acceleration < 0 ? EaseOut(linearStep, type) : linearStep; + // Lerp: + return ((easedStep - linearStep) * Math.Abs(acceleration) + linearStep); + } + + public static double EaseIn(double linearStep, EasingType type) => type switch { EasingType.Step => (linearStep < 0.5 ? 0 : 1), @@ -478,11 +524,12 @@ namespace GreenshotPlugin.Core { _ => throw new NotImplementedException() }; - public static double EaseInOut(double linearStep, EasingType easeInType, EasingType easeOutType) { - return linearStep < 0.5 ? EaseInOut(linearStep, easeInType) : EaseInOut(linearStep, easeOutType); - } + public static double EaseInOut(double linearStep, EasingType easeInType, EasingType easeOutType) + { + return linearStep < 0.5 ? EaseInOut(linearStep, easeInType) : EaseInOut(linearStep, easeOutType); + } - public static double EaseInOut(double linearStep, EasingType type) => + public static double EaseInOut(double linearStep, EasingType type) => type switch { EasingType.Step => (linearStep < 0.5 ? 0 : 1), @@ -495,53 +542,69 @@ namespace GreenshotPlugin.Core { _ => throw new NotImplementedException() }; - private static class Sine { - public static double EaseIn(double s) { - return Math.Sin(s * (Math.PI / 2) - (Math.PI / 2)) + 1; - } - public static double EaseOut(double s) { - return Math.Sin(s * (Math.PI / 2)); - } - public static double EaseInOut(double s) { - return Math.Sin(s * Math.PI - (Math.PI / 2) + 1) / 2; - } - } + private static class Sine + { + public static double EaseIn(double s) + { + return Math.Sin(s * (Math.PI / 2) - (Math.PI / 2)) + 1; + } - private static class Power { - public static double EaseIn(double s, int power) { - return Math.Pow(s, power); - } - public static double EaseOut(double s, int power) { - var sign = power % 2 == 0 ? -1 : 1; - return sign * (Math.Pow(s - 1, power) + sign); - } - public static double EaseInOut(double s, int power) { - s *= 2; - if (s < 1) { - return EaseIn(s, power) / 2; - } - var sign = power % 2 == 0 ? -1 : 1; - return (sign / 2.0 * (Math.Pow(s - 2, power) + sign * 2)); - } - } - } + public static double EaseOut(double s) + { + return Math.Sin(s * (Math.PI / 2)); + } - /// - /// This defines the way the animation works - /// - public enum EasingType { - Step, - Linear, - Sine, - Quadratic, - Cubic, - Quartic, - Quintic - } + public static double EaseInOut(double s) + { + return Math.Sin(s * Math.PI - (Math.PI / 2) + 1) / 2; + } + } - public enum EasingMode { - EaseIn, - EaseOut, - EaseInOut - } -} + private static class Power + { + public static double EaseIn(double s, int power) + { + return Math.Pow(s, power); + } + + public static double EaseOut(double s, int power) + { + var sign = power % 2 == 0 ? -1 : 1; + return sign * (Math.Pow(s - 1, power) + sign); + } + + public static double EaseInOut(double s, int power) + { + s *= 2; + if (s < 1) + { + return EaseIn(s, power) / 2; + } + + var sign = power % 2 == 0 ? -1 : 1; + return (sign / 2.0 * (Math.Pow(s - 2, power) + sign * 2)); + } + } + } + + /// + /// This defines the way the animation works + /// + public enum EasingType + { + Step, + Linear, + Sine, + Quadratic, + Cubic, + Quartic, + Quintic + } + + public enum EasingMode + { + EaseIn, + EaseOut, + EaseInOut + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/BinaryStructHelper.cs b/src/GreenshotPlugin/Core/BinaryStructHelper.cs index 1d8af4700..1da7254f7 100644 --- a/src/GreenshotPlugin/Core/BinaryStructHelper.cs +++ b/src/GreenshotPlugin/Core/BinaryStructHelper.cs @@ -18,76 +18,91 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Runtime.InteropServices; -namespace GreenshotPlugin.Core { - /// - /// A helper class which does the mashalling for structs - /// - public static class BinaryStructHelper { - /// - /// Get a struct from a byte array - /// - /// typeof struct - /// byte[] - /// struct - public static T FromByteArray(byte[] bytes) where T : struct { - IntPtr ptr = IntPtr.Zero; - try { - int size = Marshal.SizeOf(typeof(T)); - ptr = Marshal.AllocHGlobal(size); - Marshal.Copy(bytes, 0, ptr, size); - return FromIntPtr(ptr); - } finally { - if (ptr != IntPtr.Zero) { - Marshal.FreeHGlobal(ptr); - } - } - } +namespace GreenshotPlugin.Core +{ + /// + /// A helper class which does the mashalling for structs + /// + public static class BinaryStructHelper + { + /// + /// Get a struct from a byte array + /// + /// typeof struct + /// byte[] + /// struct + public static T FromByteArray(byte[] bytes) where T : struct + { + IntPtr ptr = IntPtr.Zero; + try + { + int size = Marshal.SizeOf(typeof(T)); + ptr = Marshal.AllocHGlobal(size); + Marshal.Copy(bytes, 0, ptr, size); + return FromIntPtr(ptr); + } + finally + { + if (ptr != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptr); + } + } + } - /// - /// Get a struct from a byte array - /// - /// typeof struct - /// Pointer to the structor to return - /// struct - public static T FromIntPtr(IntPtr intPtr) where T : struct { - object obj = Marshal.PtrToStructure(intPtr, typeof(T)); - return (T)obj; - } + /// + /// Get a struct from a byte array + /// + /// typeof struct + /// Pointer to the structor to return + /// struct + public static T FromIntPtr(IntPtr intPtr) where T : struct + { + object obj = Marshal.PtrToStructure(intPtr, typeof(T)); + return (T) obj; + } - /// - /// copy a struct to a byte array - /// - /// typeof struct - /// struct - /// byte[] - public static byte[] ToByteArray(T obj) where T : struct { - IntPtr ptr = IntPtr.Zero; - try { - int size = Marshal.SizeOf(typeof(T)); - ptr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(obj, ptr, true); - return FromPtrToByteArray(ptr); - } finally { - if (ptr != IntPtr.Zero) { - Marshal.FreeHGlobal(ptr); - } - } - } + /// + /// copy a struct to a byte array + /// + /// typeof struct + /// struct + /// byte[] + public static byte[] ToByteArray(T obj) where T : struct + { + IntPtr ptr = IntPtr.Zero; + try + { + int size = Marshal.SizeOf(typeof(T)); + ptr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(obj, ptr, true); + return FromPtrToByteArray(ptr); + } + finally + { + if (ptr != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptr); + } + } + } - /// - /// copy a struct from a pointer to a byte array - /// - /// typeof struct - /// IntPtr to struct - /// byte[] - public static byte[] FromPtrToByteArray(IntPtr ptr) where T : struct { - int size = Marshal.SizeOf(typeof(T)); - byte[] bytes = new byte[size]; - Marshal.Copy(ptr, bytes, 0, size); - return bytes; - } - } -} + /// + /// copy a struct from a pointer to a byte array + /// + /// typeof struct + /// IntPtr to struct + /// byte[] + public static byte[] FromPtrToByteArray(IntPtr ptr) where T : struct + { + int size = Marshal.SizeOf(typeof(T)); + byte[] bytes = new byte[size]; + Marshal.Copy(ptr, bytes, 0, size); + return bytes; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Cache.cs b/src/GreenshotPlugin/Core/Cache.cs index 857f5327a..5707f2465 100644 --- a/src/GreenshotPlugin/Core/Cache.cs +++ b/src/GreenshotPlugin/Core/Cache.cs @@ -18,197 +18,242 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Timers; using log4net; -namespace GreenshotPlugin.Core { - /// - /// Cache class - /// - /// Type of key - /// Type of value - public class Cache { - private static readonly ILog Log = LogManager.GetLogger(typeof(Cache)); - private readonly IDictionary _internalCache = new Dictionary(); - private readonly object _lockObject = new object(); - private readonly int _secondsToExpire = 10; - private readonly CacheObjectExpired _expiredCallback; - public delegate void CacheObjectExpired(TK key, TV cacheValue); +namespace GreenshotPlugin.Core +{ + /// + /// Cache class + /// + /// Type of key + /// Type of value + public class Cache + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Cache)); + private readonly IDictionary _internalCache = new Dictionary(); + private readonly object _lockObject = new object(); + private readonly int _secondsToExpire = 10; + private readonly CacheObjectExpired _expiredCallback; - /// - /// Initialize the cache - /// - public Cache() { - } - /// - /// Initialize the cache - /// - /// - public Cache(CacheObjectExpired expiredCallback) : this() { - _expiredCallback = expiredCallback; - } + public delegate void CacheObjectExpired(TK key, TV cacheValue); - /// - /// Initialize the cache with a expire setting - /// - /// - public Cache(int secondsToExpire) : this() { - _secondsToExpire = secondsToExpire; - } + /// + /// Initialize the cache + /// + public Cache() + { + } - /// - /// Initialize the cache with a expire setting - /// - /// - /// - public Cache(int secondsToExpire, CacheObjectExpired expiredCallback) : this(expiredCallback) { - _secondsToExpire = secondsToExpire; - } + /// + /// Initialize the cache + /// + /// + public Cache(CacheObjectExpired expiredCallback) : this() + { + _expiredCallback = expiredCallback; + } - /// - /// Enumerable for the values in the cache - /// - public IEnumerable Elements { - get { - List elements = new List(); + /// + /// Initialize the cache with a expire setting + /// + /// + public Cache(int secondsToExpire) : this() + { + _secondsToExpire = secondsToExpire; + } - lock (_lockObject) - { - foreach (TV element in _internalCache.Values) { - elements.Add(element); - } - } - foreach (TV element in elements) { - yield return element; - } - } - } + /// + /// Initialize the cache with a expire setting + /// + /// + /// + public Cache(int secondsToExpire, CacheObjectExpired expiredCallback) : this(expiredCallback) + { + _secondsToExpire = secondsToExpire; + } - /// - /// Get the value by key from the cache - /// - /// - /// - public TV this[TK key] { - get { - TV result = default; - lock (_lockObject) { - if (_internalCache.ContainsKey(key)) { - result = _internalCache[key]; - } - } - return result; - } - } + /// + /// Enumerable for the values in the cache + /// + public IEnumerable Elements + { + get + { + List elements = new List(); - /// - /// Contains - /// - /// - /// true if the cache contains the key - public bool Contains(TK key) - { - lock (_lockObject) - { - return _internalCache.ContainsKey(key); - } - } + lock (_lockObject) + { + foreach (TV element in _internalCache.Values) + { + elements.Add(element); + } + } - /// - /// Add a value to the cache - /// - /// - /// - public void Add(TK key, TV value) { - Add(key, value, null); - } + foreach (TV element in elements) + { + yield return element; + } + } + } - /// - /// Add a value to the cache - /// - /// - /// - /// optional value for the seconds to expire - public void Add(TK key, TV value, int? secondsToExpire) { - lock (_lockObject) { - var cachedItem = new CachedItem(key, value, secondsToExpire ?? _secondsToExpire); - cachedItem.Expired += delegate(TK cacheKey, TV cacheValue) { - if (_internalCache.ContainsKey(cacheKey)) { - Log.DebugFormat("Expiring object with Key: {0}", cacheKey); - _expiredCallback?.Invoke(cacheKey, cacheValue); - Remove(cacheKey); - } else { - Log.DebugFormat("Expired old object with Key: {0}", cacheKey); - } - }; + /// + /// Get the value by key from the cache + /// + /// + /// + public TV this[TK key] + { + get + { + TV result = default; + lock (_lockObject) + { + if (_internalCache.ContainsKey(key)) + { + result = _internalCache[key]; + } + } - if (_internalCache.ContainsKey(key)) { - _internalCache[key] = value; - Log.DebugFormat("Updated item with Key: {0}", key); - } else { - _internalCache.Add(key, cachedItem); - Log.DebugFormat("Added item with Key: {0}", key); - } - } - } + return result; + } + } - /// - /// Remove item from cache - /// - /// - public void Remove(TK key) { - lock (_lockObject) { - if (!_internalCache.ContainsKey(key)) { - throw new ApplicationException($"An object with key ‘{key}’ does not exists in cache"); - } - _internalCache.Remove(key); - Log.DebugFormat("Removed item with Key: {0}", key); - } - } + /// + /// Contains + /// + /// + /// true if the cache contains the key + public bool Contains(TK key) + { + lock (_lockObject) + { + return _internalCache.ContainsKey(key); + } + } - /// - /// A cache item - /// - private class CachedItem { - public event CacheObjectExpired Expired; - private readonly int _secondsToExpire; - private readonly Timer _timerEvent; + /// + /// Add a value to the cache + /// + /// + /// + public void Add(TK key, TV value) + { + Add(key, value, null); + } - public CachedItem(TK key, TV item, int secondsToExpire) { - if (key == null) { - throw new ArgumentNullException(nameof(key)); - } - Key = key; - Item = item; - _secondsToExpire = secondsToExpire; - if (secondsToExpire <= 0) - { - return; - } - _timerEvent = new Timer(secondsToExpire * 1000) { AutoReset = false }; - _timerEvent.Elapsed += timerEvent_Elapsed; - _timerEvent.Start(); - } + /// + /// Add a value to the cache + /// + /// + /// + /// optional value for the seconds to expire + public void Add(TK key, TV value, int? secondsToExpire) + { + lock (_lockObject) + { + var cachedItem = new CachedItem(key, value, secondsToExpire ?? _secondsToExpire); + cachedItem.Expired += delegate(TK cacheKey, TV cacheValue) + { + if (_internalCache.ContainsKey(cacheKey)) + { + Log.DebugFormat("Expiring object with Key: {0}", cacheKey); + _expiredCallback?.Invoke(cacheKey, cacheValue); + Remove(cacheKey); + } + else + { + Log.DebugFormat("Expired old object with Key: {0}", cacheKey); + } + }; - private void ExpireNow() { - _timerEvent.Stop(); - if (_secondsToExpire > 0) { - Expired?.Invoke(Key, Item); - } - } + if (_internalCache.ContainsKey(key)) + { + _internalCache[key] = value; + Log.DebugFormat("Updated item with Key: {0}", key); + } + else + { + _internalCache.Add(key, cachedItem); + Log.DebugFormat("Added item with Key: {0}", key); + } + } + } - private void timerEvent_Elapsed(object sender, ElapsedEventArgs e) { - ExpireNow(); - } + /// + /// Remove item from cache + /// + /// + public void Remove(TK key) + { + lock (_lockObject) + { + if (!_internalCache.ContainsKey(key)) + { + throw new ApplicationException($"An object with key ‘{key}’ does not exists in cache"); + } - public TK Key { get; private set; } - public TV Item { get; private set; } + _internalCache.Remove(key); + Log.DebugFormat("Removed item with Key: {0}", key); + } + } - public static implicit operator TV(CachedItem a) { - return a.Item; - } - } - } + /// + /// A cache item + /// + private class CachedItem + { + public event CacheObjectExpired Expired; + private readonly int _secondsToExpire; + private readonly Timer _timerEvent; + + public CachedItem(TK key, TV item, int secondsToExpire) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + Key = key; + Item = item; + _secondsToExpire = secondsToExpire; + if (secondsToExpire <= 0) + { + return; + } + + _timerEvent = new Timer(secondsToExpire * 1000) + { + AutoReset = false + }; + _timerEvent.Elapsed += timerEvent_Elapsed; + _timerEvent.Start(); + } + + private void ExpireNow() + { + _timerEvent.Stop(); + if (_secondsToExpire > 0) + { + Expired?.Invoke(Key, Item); + } + } + + private void timerEvent_Elapsed(object sender, ElapsedEventArgs e) + { + ExpireNow(); + } + + public TK Key { get; private set; } + public TV Item { get; private set; } + + public static implicit operator TV(CachedItem a) + { + return a.Item; + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Capture.cs b/src/GreenshotPlugin/Core/Capture.cs index 2b0180de2..e5e7d7234 100644 --- a/src/GreenshotPlugin/Core/Capture.cs +++ b/src/GreenshotPlugin/Core/Capture.cs @@ -32,63 +32,85 @@ namespace GreenshotPlugin.Core /// This class is used to pass an instance of the "Capture" around /// Having the Bitmap, eventually the Windows Title and cursor all together. ///
- public class Capture : ICapture { + public class Capture : ICapture + { private static readonly ILog Log = LogManager.GetLogger(typeof(Capture)); private Rectangle _screenBounds; + /// /// Get/Set the screen bounds /// - public Rectangle ScreenBounds { - get { - if (_screenBounds == Rectangle.Empty) { + public Rectangle ScreenBounds + { + get + { + if (_screenBounds == Rectangle.Empty) + { _screenBounds = WindowCapture.GetScreenBounds(); } + return _screenBounds; } set => _screenBounds = value; } private Image _image; + /// /// Get/Set the Image /// - public Image Image { + public Image Image + { get => _image; - set { + set + { _image?.Dispose(); _image = value; - if (value != null) { - if (value.PixelFormat.Equals(PixelFormat.Format8bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format1bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format4bppIndexed)) { + if (value != null) + { + if (value.PixelFormat.Equals(PixelFormat.Format8bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format1bppIndexed) || + value.PixelFormat.Equals(PixelFormat.Format4bppIndexed)) + { Log.Debug("Converting Bitmap to PixelFormat.Format32bppArgb as we don't support: " + value.PixelFormat); - try { + try + { // Default Bitmap PixelFormat is Format32bppArgb _image = new Bitmap(value); - } finally { + } + finally + { // Always dispose, even when a exception occured value.Dispose(); } } + Log.DebugFormat("Image is set with the following specifications: {0} - {1}", _image.Size, _image.PixelFormat); - } else { + } + else + { Log.Debug("Image is removed."); } } } - public void NullImage() { + public void NullImage() + { _image = null; } private Icon _cursor; + /// /// Get/Set the image for the Cursor /// - public Icon Cursor { + public Icon Cursor + { get => _cursor; - set { + set + { _cursor?.Dispose(); - _cursor = (Icon)value.Clone(); + _cursor = (Icon) value.Clone(); } } @@ -103,36 +125,43 @@ namespace GreenshotPlugin.Core public bool CursorVisible { get; set; } private Point _cursorLocation = Point.Empty; + /// /// Get/Set the CursorLocation /// - public Point CursorLocation { + public Point CursorLocation + { get => _cursorLocation; set => _cursorLocation = value; } private Point _location = Point.Empty; + /// /// Get/set the Location /// - public Point Location { + public Point Location + { get => _location; set => _location = value; } private CaptureDetails _captureDetails; + /// /// Get/set the CaptureDetails /// - public ICaptureDetails CaptureDetails { + public ICaptureDetails CaptureDetails + { get => _captureDetails; - set => _captureDetails = (CaptureDetails)value; + set => _captureDetails = (CaptureDetails) value; } /// /// Default Constructor /// - public Capture() { + public Capture() + { _screenBounds = WindowCapture.GetScreenBounds(); _captureDetails = new CaptureDetails(); } @@ -142,14 +171,16 @@ namespace GreenshotPlugin.Core /// Note: the supplied bitmap can be disposed immediately or when constructor is called. ///
/// Image - public Capture(Image newImage) : this() { + public Capture(Image newImage) : this() + { Image = newImage; } /// /// Destructor /// - ~Capture() { + ~Capture() + { Dispose(false); } @@ -157,7 +188,8 @@ namespace GreenshotPlugin.Core /// The public accessible Dispose /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice ///
- public void Dispose() { + public void Dispose() + { Dispose(true); GC.SuppressFinalize(this); } @@ -167,11 +199,14 @@ namespace GreenshotPlugin.Core /// When disposing==true all non-managed resources should be freed too! ///
/// - protected virtual void Dispose(bool disposing) { - if (disposing) { + protected virtual void Dispose(bool disposing) + { + if (disposing) + { _image?.Dispose(); _cursor?.Dispose(); } + _image = null; _cursor = null; } @@ -180,12 +215,14 @@ namespace GreenshotPlugin.Core /// Crops the capture to the specified rectangle (with Bitmap coordinates!) ///
/// Rectangle with bitmap coordinates - public bool Crop(Rectangle cropRectangle) { + public bool Crop(Rectangle cropRectangle) + { Log.Debug("Cropping to: " + cropRectangle); if (!ImageHelper.Crop(ref _image, ref cropRectangle)) { return false; } + _location = cropRectangle.Location; // Change mouse location according to the cropRectangle (including screenbounds) offset MoveMouseLocation(-cropRectangle.Location.X, -cropRectangle.Location.Y); @@ -206,7 +243,8 @@ namespace GreenshotPlugin.Core ///
/// x coordinates to move the mouse /// y coordinates to move the mouse - public void MoveMouseLocation(int x, int y) { + public void MoveMouseLocation(int x, int y) + { _cursorLocation.Offset(x, y); } @@ -257,6 +295,5 @@ namespace GreenshotPlugin.Core // elements = value; // } //} - } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/CaptureDetails.cs b/src/GreenshotPlugin/Core/CaptureDetails.cs index c600ced26..96c9abb41 100644 --- a/src/GreenshotPlugin/Core/CaptureDetails.cs +++ b/src/GreenshotPlugin/Core/CaptureDetails.cs @@ -30,37 +30,22 @@ namespace GreenshotPlugin.Core /// This Class is used to pass details about the capture around. /// The time the Capture was taken and the Title of the window (or a region of) that is captured ///
- public class CaptureDetails : ICaptureDetails { + public class CaptureDetails : ICaptureDetails + { + /// + public string Title { get; set; } /// - public string Title { - get; - set; - } + public string Filename { get; set; } /// - public string Filename { - get; - set; - } + public DateTime DateTime { get; set; } /// - public DateTime DateTime { - get; - set; - } + public float DpiX { get; set; } /// - public float DpiX { - get; - set; - } - - /// - public float DpiY { - get; - set; - } + public float DpiY { get; set; } /// public OcrInformation OcrInformation { get; set; } @@ -69,53 +54,64 @@ namespace GreenshotPlugin.Core public Dictionary MetaData { get; } = new Dictionary(); /// - public void AddMetaData(string key, string value) { - if (MetaData.ContainsKey(key)) { + public void AddMetaData(string key, string value) + { + if (MetaData.ContainsKey(key)) + { MetaData[key] = value; - } else { + } + else + { MetaData.Add(key, value); } } /// - public CaptureMode CaptureMode { - get; - set; - } + public CaptureMode CaptureMode { get; set; } /// public List CaptureDestinations { get; set; } = new List(); /// - public void ClearDestinations() { + public void ClearDestinations() + { CaptureDestinations.Clear(); } /// - public void RemoveDestination(IDestination destination) { - if (CaptureDestinations.Contains(destination)) { + public void RemoveDestination(IDestination destination) + { + if (CaptureDestinations.Contains(destination)) + { CaptureDestinations.Remove(destination); } } /// - public void AddDestination(IDestination captureDestination) { - if (!CaptureDestinations.Contains(captureDestination)) { + public void AddDestination(IDestination captureDestination) + { + if (!CaptureDestinations.Contains(captureDestination)) + { CaptureDestinations.Add(captureDestination); } } /// - public bool HasDestination(string designation) { - foreach(IDestination destination in CaptureDestinations) { - if (designation.Equals(destination.Designation)) { + public bool HasDestination(string designation) + { + foreach (IDestination destination in CaptureDestinations) + { + if (designation.Equals(destination.Designation)) + { return true; } } + return false; } - public CaptureDetails() { + public CaptureDetails() + { DateTime = DateTime.Now; } } diff --git a/src/GreenshotPlugin/Core/CaptureHandler.cs b/src/GreenshotPlugin/Core/CaptureHandler.cs index 7716b56c1..952131330 100644 --- a/src/GreenshotPlugin/Core/CaptureHandler.cs +++ b/src/GreenshotPlugin/Core/CaptureHandler.cs @@ -21,24 +21,23 @@ using System.Drawing; -namespace GreenshotPlugin.Core { - /// - /// This is the method signature which is used to capture a rectangle from the screen. - /// - /// - /// Captured Bitmap - public delegate Bitmap CaptureScreenRectangleHandler(Rectangle captureBounds); +namespace GreenshotPlugin.Core +{ + /// + /// This is the method signature which is used to capture a rectangle from the screen. + /// + /// + /// Captured Bitmap + public delegate Bitmap CaptureScreenRectangleHandler(Rectangle captureBounds); - /// - /// This is a hack to experiment with different screen capture routines - /// - public static class CaptureHandler { - /// - /// By changing this value, null is default - /// - public static CaptureScreenRectangleHandler CaptureScreenRectangle { - get; - set; - } - } -} + /// + /// This is a hack to experiment with different screen capture routines + /// + public static class CaptureHandler + { + /// + /// By changing this value, null is default + /// + public static CaptureScreenRectangleHandler CaptureScreenRectangle { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/ClipboardHelper.cs b/src/GreenshotPlugin/Core/ClipboardHelper.cs index 2d675d24e..f3c57b3d0 100644 --- a/src/GreenshotPlugin/Core/ClipboardHelper.cs +++ b/src/GreenshotPlugin/Core/ClipboardHelper.cs @@ -38,31 +38,34 @@ using GreenshotPlugin.Interop; using log4net; using HtmlDocument = HtmlAgilityPack.HtmlDocument; -namespace GreenshotPlugin.Core { - /// - /// Description of ClipboardHelper. - /// - public static class ClipboardHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(ClipboardHelper)); - private static readonly object ClipboardLockObject = new object(); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static readonly string FORMAT_FILECONTENTS = "FileContents"; +namespace GreenshotPlugin.Core +{ + /// + /// Description of ClipboardHelper. + /// + public static class ClipboardHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ClipboardHelper)); + private static readonly object ClipboardLockObject = new object(); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static readonly string FORMAT_FILECONTENTS = "FileContents"; private static readonly string FORMAT_HTML = "text/html"; private static readonly string FORMAT_PNG = "PNG"; - private static readonly string FORMAT_PNG_OFFICEART = "PNG+Office Art"; - private static readonly string FORMAT_17 = "Format17"; - private static readonly string FORMAT_JPG = "JPG"; + private static readonly string FORMAT_PNG_OFFICEART = "PNG+Office Art"; + private static readonly string FORMAT_17 = "Format17"; + private static readonly string FORMAT_JPG = "JPG"; private static readonly string FORMAT_JPEG = "JPEG"; - private static readonly string FORMAT_JFIF = "JFIF"; - private static readonly string FORMAT_JFIF_OFFICEART = "JFIF+Office Art"; - private static readonly string FORMAT_GIF = "GIF"; - private static readonly string FORMAT_BITMAP = "System.Drawing.Bitmap"; - //private static readonly string FORMAT_HTML = "HTML Format"; + private static readonly string FORMAT_JFIF = "JFIF"; + private static readonly string FORMAT_JFIF_OFFICEART = "JFIF+Office Art"; + private static readonly string FORMAT_GIF = "GIF"; - // Template for the HTML Text on the clipboard - // see: http://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx - // or: http://msdn.microsoft.com/en-us/library/Aa767917.aspx - private const string HtmlClipboardString = @"Version:0.9 + private static readonly string FORMAT_BITMAP = "System.Drawing.Bitmap"; + //private static readonly string FORMAT_HTML = "HTML Format"; + + // Template for the HTML Text on the clipboard + // see: http://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx + // or: http://msdn.microsoft.com/en-us/library/Aa767917.aspx + private const string HtmlClipboardString = @"Version:0.9 StartHTML:<<<<<<<1 EndHTML:<<<<<<<2 StartFragment:<<<<<<<3 @@ -80,7 +83,8 @@ EndSelection:<<<<<<<4 "; - private const string HtmlClipboardBase64String = @"Version:0.9 + + private const string HtmlClipboardBase64String = @"Version:0.9 StartHTML:<<<<<<<1 EndHTML:<<<<<<<2 StartFragment:<<<<<<<3 @@ -98,18 +102,21 @@ EndSelection:<<<<<<<4 "; - - /// - /// Get the current "ClipboardOwner" but only if it isn't us! - /// - /// current clipboard owner - private static string GetClipboardOwner() { - string owner = null; - try { - IntPtr hWnd = User32.GetClipboardOwner(); - if (hWnd != IntPtr.Zero) { - try - { + + /// + /// Get the current "ClipboardOwner" but only if it isn't us! + /// + /// current clipboard owner + private static string GetClipboardOwner() + { + string owner = null; + try + { + IntPtr hWnd = User32.GetClipboardOwner(); + if (hWnd != IntPtr.Zero) + { + try + { User32.GetWindowThreadProcessId(hWnd, out var pid); using Process me = Process.GetCurrentProcess(); using Process ownerProcess = Process.GetProcessById(pid); @@ -129,117 +136,147 @@ EndSelection:<<<<<<<4 } } } - catch(Exception e) - { - Log.Warn("Non critical error: Couldn't get clipboard process, trying to use the title.", e); - var title = new StringBuilder(260, 260); - User32.GetWindowText(hWnd, title, title.Capacity); - owner = title.ToString(); - } - } - } catch (Exception e) { - Log.Warn("Non critical error: Couldn't get clipboard owner.", e); - } - return owner; - } + catch (Exception e) + { + Log.Warn("Non critical error: Couldn't get clipboard process, trying to use the title.", e); + var title = new StringBuilder(260, 260); + User32.GetWindowText(hWnd, title, title.Capacity); + owner = title.ToString(); + } + } + } + catch (Exception e) + { + Log.Warn("Non critical error: Couldn't get clipboard owner.", e); + } - /// - /// The SetDataObject will lock/try/catch clipboard operations making it save and not show exceptions. - /// The bool "copy" is used to decided if the information stays on the clipboard after exit. - /// - /// - /// - private static void SetDataObject(IDataObject ido, bool copy) { - lock (ClipboardLockObject) { - // Clear first, this seems to solve some issues - try - { - Clipboard.Clear(); - } - catch (Exception clearException) - { - Log.Warn(clearException.Message); - } - try - { - // For BUG-1935 this was changed from looping ourselfs, or letting MS retry... - Clipboard.SetDataObject(ido, copy, 15, 200); - } - catch (Exception clipboardSetException) - { - string messageText; - string clipboardOwner = GetClipboardOwner(); - if (clipboardOwner != null) - { - messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner); - } - else { - messageText = Language.GetString("clipboard_error"); - } - Log.Error(messageText, clipboardSetException); - } - } - } - - /// - /// The GetDataObject will lock/try/catch clipboard operations making it save and not show exceptions. - /// - public static IDataObject GetDataObject() { - lock (ClipboardLockObject) { - int retryCount = 2; - while (retryCount >= 0) { - try { - return Clipboard.GetDataObject(); - } catch (Exception ee) { - if (retryCount == 0) { - string messageText; - string clipboardOwner = GetClipboardOwner(); - if (clipboardOwner != null) { - messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner); - } else { - messageText = Language.GetString("clipboard_error"); - } - Log.Error(messageText, ee); - } else { - Thread.Sleep(100); - } - } finally { - --retryCount; - } - } - } - return null; - } + return owner; + } /// - /// Test if the IDataObject contains Text - /// - /// - /// - public static bool ContainsText(IDataObject dataObject) { - if (dataObject != null) { - if (dataObject.GetDataPresent(DataFormats.Text) || dataObject.GetDataPresent(DataFormats.UnicodeText)) { - return true; - } - } - return false; - } - - /// - /// Wrapper for Clipboard.ContainsImage, specialized for Greenshot, Created for Bug #3432313 - /// - /// boolean if there is an image on the clipboard - public static bool ContainsImage() { - IDataObject clipboardData = GetDataObject(); - return ContainsImage(clipboardData); - } + /// The SetDataObject will lock/try/catch clipboard operations making it save and not show exceptions. + /// The bool "copy" is used to decided if the information stays on the clipboard after exit. + ///
+ /// + /// + private static void SetDataObject(IDataObject ido, bool copy) + { + lock (ClipboardLockObject) + { + // Clear first, this seems to solve some issues + try + { + Clipboard.Clear(); + } + catch (Exception clearException) + { + Log.Warn(clearException.Message); + } - /// - /// Check if the IDataObject has an image - /// - /// - /// true if an image is there - public static bool ContainsImage(IDataObject dataObject) { + try + { + // For BUG-1935 this was changed from looping ourselfs, or letting MS retry... + Clipboard.SetDataObject(ido, copy, 15, 200); + } + catch (Exception clipboardSetException) + { + string messageText; + string clipboardOwner = GetClipboardOwner(); + if (clipboardOwner != null) + { + messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner); + } + else + { + messageText = Language.GetString("clipboard_error"); + } + + Log.Error(messageText, clipboardSetException); + } + } + } + + /// + /// The GetDataObject will lock/try/catch clipboard operations making it save and not show exceptions. + /// + public static IDataObject GetDataObject() + { + lock (ClipboardLockObject) + { + int retryCount = 2; + while (retryCount >= 0) + { + try + { + return Clipboard.GetDataObject(); + } + catch (Exception ee) + { + if (retryCount == 0) + { + string messageText; + string clipboardOwner = GetClipboardOwner(); + if (clipboardOwner != null) + { + messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner); + } + else + { + messageText = Language.GetString("clipboard_error"); + } + + Log.Error(messageText, ee); + } + else + { + Thread.Sleep(100); + } + } + finally + { + --retryCount; + } + } + } + + return null; + } + + /// + /// Test if the IDataObject contains Text + /// + /// + /// + public static bool ContainsText(IDataObject dataObject) + { + if (dataObject != null) + { + if (dataObject.GetDataPresent(DataFormats.Text) || dataObject.GetDataPresent(DataFormats.UnicodeText)) + { + return true; + } + } + + return false; + } + + /// + /// Wrapper for Clipboard.ContainsImage, specialized for Greenshot, Created for Bug #3432313 + /// + /// boolean if there is an image on the clipboard + public static bool ContainsImage() + { + IDataObject clipboardData = GetDataObject(); + return ContainsImage(clipboardData); + } + + /// + /// Check if the IDataObject has an image + /// + /// + /// true if an image is there + public static bool ContainsImage(IDataObject dataObject) + { if (dataObject == null) return false; if (dataObject.GetDataPresent(DataFormats.Bitmap) @@ -251,16 +288,18 @@ EndSelection:<<<<<<<4 || dataObject.GetDataPresent(FORMAT_JPG) || dataObject.GetDataPresent(FORMAT_JFIF) || dataObject.GetDataPresent(FORMAT_JPEG) - || dataObject.GetDataPresent(FORMAT_GIF)) { + || dataObject.GetDataPresent(FORMAT_GIF)) + { return true; } var imageFiles = GetImageFilenames(dataObject); - if (imageFiles.Any()) { + if (imageFiles.Any()) + { return true; } - var fileDescriptor = (MemoryStream)dataObject.GetData("FileGroupDescriptorW"); + var fileDescriptor = (MemoryStream) dataObject.GetData("FileGroupDescriptorW"); var files = FileDescriptorReader.Read(fileDescriptor); var fileIndex = 0; foreach (var fileContentFile in files) @@ -291,6 +330,7 @@ EndSelection:<<<<<<<4 { fileData?.Dispose(); } + fileIndex++; } @@ -335,8 +375,9 @@ EndSelection:<<<<<<<4 } } } + return false; - } + } /// /// Get the specified IDataObject format as a string @@ -358,101 +399,137 @@ EndSelection:<<<<<<<4 }; } - /// - /// Simple helper to check the stream - /// - /// - /// - private static bool IsValidStream(MemoryStream memoryStream) { - return memoryStream != null && memoryStream.Length > 0; - } + /// + /// Simple helper to check the stream + /// + /// + /// + private static bool IsValidStream(MemoryStream memoryStream) + { + return memoryStream != null && memoryStream.Length > 0; + } - /// - /// Wrapper for Clipboard.GetImage, Created for Bug #3432313 - /// - /// Image if there is an image on the clipboard - public static Image GetImage() { - IDataObject clipboardData = GetDataObject(); - // Return the first image - foreach (Image clipboardImage in GetImages(clipboardData)) { - return clipboardImage; - } - return null; - } + /// + /// Wrapper for Clipboard.GetImage, Created for Bug #3432313 + /// + /// Image if there is an image on the clipboard + public static Image GetImage() + { + IDataObject clipboardData = GetDataObject(); + // Return the first image + foreach (Image clipboardImage in GetImages(clipboardData)) + { + return clipboardImage; + } - /// - /// Get all images (multiple if filenames are available) from the dataObject - /// Returned images must be disposed by the calling code! - /// - /// - /// IEnumerable of Image - public static IEnumerable GetImages(IDataObject dataObject) { - // Get single image, this takes the "best" match - Image singleImage = GetImage(dataObject); - if (singleImage != null) { - Log.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat); - yield return singleImage; - } else { - // check if files are supplied - foreach (string imageFile in GetImageFilenames(dataObject)) { - Image returnImage = null; - try { - returnImage = ImageHelper.LoadImage(imageFile); - } catch (Exception streamImageEx) { - Log.Error("Problem retrieving Image from clipboard.", streamImageEx); - } - if (returnImage != null) { - Log.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat); - yield return returnImage; - } - } - } - } + return null; + } - /// - /// Get an Image from the IDataObject, don't check for FileDrop - /// - /// - /// Image or null - private static Image GetImage(IDataObject dataObject) { - Image returnImage = null; - if (dataObject != null) { - IList formats = GetFormats(dataObject); - string[] retrieveFormats; + /// + /// Get all images (multiple if filenames are available) from the dataObject + /// Returned images must be disposed by the calling code! + /// + /// + /// IEnumerable of Image + public static IEnumerable GetImages(IDataObject dataObject) + { + // Get single image, this takes the "best" match + Image singleImage = GetImage(dataObject); + if (singleImage != null) + { + Log.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat); + yield return singleImage; + } + else + { + // check if files are supplied + foreach (string imageFile in GetImageFilenames(dataObject)) + { + Image returnImage = null; + try + { + returnImage = ImageHelper.LoadImage(imageFile); + } + catch (Exception streamImageEx) + { + Log.Error("Problem retrieving Image from clipboard.", streamImageEx); + } - // Found a weird bug, where PNG's from Outlook 2010 are clipped - // So I build some special logik to get the best format: - if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) { - // Outlook ?? - Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front..."); - retrieveFormats = new[] { DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML }; - } else { - retrieveFormats = new[] { FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML }; - } - foreach (string currentFormat in retrieveFormats) { - if (formats != null && formats.Contains(currentFormat)) { - Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat); - returnImage = GetImageForFormat(currentFormat, dataObject); - } else { - Log.DebugFormat("Couldn't find format {0}.", currentFormat); - } - if (returnImage != null) { - return returnImage; - } - } - } - return null; - } - - /// - /// Helper method to try to get an image in the specified format from the dataObject - /// the DIB reader should solve some issues - /// It also supports Format17/DibV5, by using the following information: http://stackoverflow.com/a/14335591 - /// - /// string with the format - /// IDataObject - /// Image or null - private static Image GetImageForFormat(string format, IDataObject dataObject) { + if (returnImage != null) + { + Log.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat); + yield return returnImage; + } + } + } + } + + /// + /// Get an Image from the IDataObject, don't check for FileDrop + /// + /// + /// Image or null + private static Image GetImage(IDataObject dataObject) + { + Image returnImage = null; + if (dataObject != null) + { + IList formats = GetFormats(dataObject); + string[] retrieveFormats; + + // Found a weird bug, where PNG's from Outlook 2010 are clipped + // So I build some special logik to get the best format: + if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) + { + // Outlook ?? + Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front..."); + retrieveFormats = new[] + { + DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, + DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML + }; + } + else + { + retrieveFormats = new[] + { + FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, + FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML + }; + } + + foreach (string currentFormat in retrieveFormats) + { + if (formats != null && formats.Contains(currentFormat)) + { + Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat); + returnImage = GetImageForFormat(currentFormat, dataObject); + } + else + { + Log.DebugFormat("Couldn't find format {0}.", currentFormat); + } + + if (returnImage != null) + { + return returnImage; + } + } + } + + return null; + } + + /// + /// Helper method to try to get an image in the specified format from the dataObject + /// the DIB reader should solve some issues + /// It also supports Format17/DibV5, by using the following information: http://stackoverflow.com/a/14335591 + /// + /// string with the format + /// IDataObject + /// Image or null + private static Image GetImageForFormat(string format, IDataObject dataObject) + { if (format == FORMAT_HTML) { var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); @@ -477,37 +554,44 @@ EndSelection:<<<<<<<4 } } } - object clipboardObject = GetFromDataObject(dataObject, format); + + object clipboardObject = GetFromDataObject(dataObject, format); var imageStream = clipboardObject as MemoryStream; - if (!IsValidStream(imageStream)) { - // TODO: add "HTML Format" support here... - return clipboardObject as Image; - } - if (CoreConfig.EnableSpecialDIBClipboardReader) { - if (format == FORMAT_17 || format == DataFormats.Dib) { - Log.Info("Found DIB stream, trying to process it."); - try { - if (imageStream != null) - { - byte[] dibBuffer = new byte[imageStream.Length]; - imageStream.Read(dibBuffer, 0, dibBuffer.Length); - var infoHeader = BinaryStructHelper.FromByteArray(dibBuffer); - if (!infoHeader.IsDibV5) { - Log.InfoFormat("Using special DIB (dibBuffer); + if (!infoHeader.IsDibV5) + { + Log.InfoFormat("Using special DIB - /// Get Text from the DataObject - /// - /// string if there is text on the clipboard - public static string GetText(IDataObject dataObject) { - if (ContainsText(dataObject)) { - return (string)dataObject.GetData(DataFormats.Text); - } - return null; - } - - /// - /// Set text to the clipboard - /// - /// - public static void SetClipboardData(string text) { - IDataObject ido = new DataObject(); - ido.SetData(DataFormats.Text, true, text); - SetDataObject(ido, true); - } - - private static string GetHtmlString(ISurface surface, string filename) { - string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardString)); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); - utf8EncodedHtmlString= utf8EncodedHtmlString.Replace("${file}", filename.Replace("\\","/")); - StringBuilder sb=new StringBuilder(); - sb.Append(utf8EncodedHtmlString); - sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); - sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)+"".Length).ToString("D8")); - sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - return sb.ToString(); - } + /// Get Text from the DataObject + ///
+ /// string if there is text on the clipboard + public static string GetText(IDataObject dataObject) + { + if (ContainsText(dataObject)) + { + return (string) dataObject.GetData(DataFormats.Text); + } - private static string GetHtmlDataUrlString(ISurface surface, MemoryStream pngStream) { - string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardBase64String)); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${format}", "png"); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${data}", Convert.ToBase64String(pngStream.GetBuffer(),0, (int)pngStream.Length)); - StringBuilder sb=new StringBuilder(); - sb.Append(utf8EncodedHtmlString); - sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); - sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)+"".Length).ToString("D8")); - sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - return sb.ToString(); - } - - private const int BITMAPFILEHEADER_LENGTH = 14; - /// - /// Set an Image to the clipboard - /// This method will place images to the clipboard depending on the ClipboardFormats setting. - /// e.g. Bitmap which works with pretty much everything and type Dib for e.g. OpenOffice - /// because OpenOffice has a bug http://qa.openoffice.org/issues/show_bug.cgi?id=85661 - /// The Dib (Device Indenpendend Bitmap) in 32bpp actually won't work with Powerpoint 2003! - /// When pasting a Dib in PP 2003 the Bitmap is somehow shifted left! - /// For this problem the user should not use the direct paste (=Dib), but select Bitmap - /// - public static void SetClipboardData(ISurface surface) { - DataObject dataObject = new DataObject(); - - // This will work for Office and most other applications - //ido.SetData(DataFormats.Bitmap, true, image); - - MemoryStream dibStream = null; - MemoryStream dibV5Stream = null; - MemoryStream pngStream = null; - Image imageToSave = null; - bool disposeImage = false; - try { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); - // Create the image which is going to be saved so we don't create it multiple times - disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave); - try { - // Create PNG stream - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.PNG)) { - pngStream = new MemoryStream(); - // PNG works for e.g. Powerpoint - SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); - ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings); - pngStream.Seek(0, SeekOrigin.Begin); - // Set the PNG stream - dataObject.SetData(FORMAT_PNG, false, pngStream); - } - } catch (Exception pngEx) { - Log.Error("Error creating PNG for the Clipboard.", pngEx); - } - - try { - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIB)) { - using (MemoryStream tmpBmpStream = new MemoryStream()) { - // Save image as BMP - SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false); - ImageOutput.SaveToStream(imageToSave, null, tmpBmpStream, bmpOutputSettings); - - dibStream = new MemoryStream(); - // Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14 - dibStream.Write(tmpBmpStream.GetBuffer(), BITMAPFILEHEADER_LENGTH, (int)tmpBmpStream.Length - BITMAPFILEHEADER_LENGTH); - } - - // Set the DIB to the clipboard DataObject - dataObject.SetData(DataFormats.Dib, true, dibStream); - } - } catch (Exception dibEx) { - Log.Error("Error creating DIB for the Clipboard.", dibEx); - } - - // CF_DibV5 - try { - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIBV5)) { - // Create the stream for the clipboard - dibV5Stream = new MemoryStream(); - - // Create the BITMAPINFOHEADER - BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32) - { - // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? - biCompression = BI_COMPRESSION.BI_BITFIELDS - }; - // Create a byte[] to write - byte[] headerBytes = BinaryStructHelper.ToByteArray(header); - // Write the BITMAPINFOHEADER to the stream - dibV5Stream.Write(headerBytes, 0, headerBytes.Length); - - // As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added - BitfieldColorMask colorMask = new BitfieldColorMask(); - // Make sure the values are set - colorMask.InitValues(); - // Create the byte[] from the struct - byte[] colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask); - Array.Reverse(colorMaskBytes); - // Write to the stream - dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length); - - // Create the raw bytes for the pixels only - byte[] bitmapBytes = BitmapToByteArray((Bitmap)imageToSave); - // Write to the stream - dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length); - - // Set the DIBv5 to the clipboard DataObject - dataObject.SetData(FORMAT_17, true, dibV5Stream); - } - } catch (Exception dibEx) { - Log.Error("Error creating DIB for the Clipboard.", dibEx); - } - - // Set the HTML - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTML)) { - string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null); - string html = GetHtmlString(surface, tmpFile); - dataObject.SetText(html, TextDataFormat.Html); - } else if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTMLDATAURL)) { - string html; - using (MemoryStream tmpPngStream = new MemoryStream()) { - SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false) - { - // Do not allow to reduce the colors, some applications dislike 256 color images - // reported with bug #3594681 - DisableReduceColors = true - }; - // Check if we can use the previously used image - if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) { - ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings); - } else { - ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings); - } - html = GetHtmlDataUrlString(surface, tmpPngStream); - } - dataObject.SetText(html, TextDataFormat.Html); - } - } finally { - // we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone! - // Check if Bitmap is wanted - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) { - dataObject.SetImage(imageToSave); - // Place the DataObject to the clipboard - SetDataObject(dataObject, true); - } else { - // Place the DataObject to the clipboard - SetDataObject(dataObject, true); - } - - pngStream?.Dispose(); - dibStream?.Dispose(); - dibV5Stream?.Dispose(); - // cleanup if needed - if (disposeImage) { - imageToSave?.Dispose(); - } - } - } - - /// - /// Helper method so get the bitmap bytes - /// See: http://stackoverflow.com/a/6570155 - /// - /// Bitmap - /// byte[] - private static byte[] BitmapToByteArray(Bitmap bitmap) { - // Lock the bitmap's bits. - Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); - BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat); - - int absStride = Math.Abs(bmpData.Stride); - int bytes = absStride * bitmap.Height; - long ptr = bmpData.Scan0.ToInt32(); - // Declare an array to hold the bytes of the bitmap. - byte[] rgbValues = new byte[bytes]; - - for (int i = 0; i < bitmap.Height; i++) { - IntPtr pointer = new IntPtr(ptr + (bmpData.Stride * i)); - Marshal.Copy(pointer, rgbValues, absStride * (bitmap.Height - i - 1), absStride); - } - - // Unlock the bits. - bitmap.UnlockBits(bmpData); - - return rgbValues; - } - - /// - /// Set Object with type Type to the clipboard - /// - /// Type - /// object - public static void SetClipboardData(Type type, object obj) { - DataFormats.Format format = DataFormats.GetFormat(type.FullName); - - //now copy to clipboard - IDataObject dataObj = new DataObject(); - dataObj.SetData(format.Name, false, obj); - // Use false to make the object disappear when the application stops. - SetDataObject(dataObj, true); - } + return null; + } /// - /// Retrieve a list of all formats currently in the IDataObject - /// - /// List of string with the current formats - public static List GetFormats(IDataObject dataObj) { - string[] formats = null; + /// Set text to the clipboard + ///
+ /// + public static void SetClipboardData(string text) + { + IDataObject ido = new DataObject(); + ido.SetData(DataFormats.Text, true, text); + SetDataObject(ido, true); + } - if (dataObj != null) { - formats = dataObj.GetFormats(); - } - if (formats != null) { - Log.DebugFormat("Got clipboard formats: {0}", string.Join(",", formats)); - return new List(formats); - } - return new List(); - } + private static string GetHtmlString(ISurface surface, string filename) + { + string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardString)); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${file}", filename.Replace("\\", "/")); + StringBuilder sb = new StringBuilder(); + sb.Append(utf8EncodedHtmlString); + sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + return sb.ToString(); + } + + private static string GetHtmlDataUrlString(ISurface surface, MemoryStream pngStream) + { + string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardBase64String)); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${format}", "png"); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${data}", Convert.ToBase64String(pngStream.GetBuffer(), 0, (int) pngStream.Length)); + StringBuilder sb = new StringBuilder(); + sb.Append(utf8EncodedHtmlString); + sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + return sb.ToString(); + } + + private const int BITMAPFILEHEADER_LENGTH = 14; /// - /// Check if there is currently something on the clipboard which has the supplied format - /// - /// IDataObject - /// string with format - /// true if one the format is found - public static bool ContainsFormat(IDataObject dataObject, string format) { - return ContainsFormat(dataObject, new[] { format }); - } + /// Set an Image to the clipboard + /// This method will place images to the clipboard depending on the ClipboardFormats setting. + /// e.g. Bitmap which works with pretty much everything and type Dib for e.g. OpenOffice + /// because OpenOffice has a bug http://qa.openoffice.org/issues/show_bug.cgi?id=85661 + /// The Dib (Device Indenpendend Bitmap) in 32bpp actually won't work with Powerpoint 2003! + /// When pasting a Dib in PP 2003 the Bitmap is somehow shifted left! + /// For this problem the user should not use the direct paste (=Dib), but select Bitmap + ///
+ public static void SetClipboardData(ISurface surface) + { + DataObject dataObject = new DataObject(); - /// - /// Check if there is currently something on the clipboard which has one of the supplied formats - /// - /// string[] with formats - /// true if one of the formats was found - public static bool ContainsFormat(string[] formats) { - return ContainsFormat(GetDataObject(), formats); - } + // This will work for Office and most other applications + //ido.SetData(DataFormats.Bitmap, true, image); - /// - /// Check if there is currently something on the clipboard which has one of the supplied formats - /// - /// IDataObject - /// string[] with formats - /// true if one of the formats was found - public static bool ContainsFormat(IDataObject dataObject, string[] formats) { - bool formatFound = false; - List currentFormats = GetFormats(dataObject); - if (currentFormats == null || currentFormats.Count == 0 || formats == null || formats.Length == 0) { - return false; - } - foreach (string format in formats) { - if (currentFormats.Contains(format)) { - formatFound = true; - break; - } - } - return formatFound; - } + MemoryStream dibStream = null; + MemoryStream dibV5Stream = null; + MemoryStream pngStream = null; + Image imageToSave = null; + bool disposeImage = false; + try + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); + // Create the image which is going to be saved so we don't create it multiple times + disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave); + try + { + // Create PNG stream + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.PNG)) + { + pngStream = new MemoryStream(); + // PNG works for e.g. Powerpoint + SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); + ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings); + pngStream.Seek(0, SeekOrigin.Begin); + // Set the PNG stream + dataObject.SetData(FORMAT_PNG, false, pngStream); + } + } + catch (Exception pngEx) + { + Log.Error("Error creating PNG for the Clipboard.", pngEx); + } + + try + { + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIB)) + { + using (MemoryStream tmpBmpStream = new MemoryStream()) + { + // Save image as BMP + SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false); + ImageOutput.SaveToStream(imageToSave, null, tmpBmpStream, bmpOutputSettings); + + dibStream = new MemoryStream(); + // Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14 + dibStream.Write(tmpBmpStream.GetBuffer(), BITMAPFILEHEADER_LENGTH, (int) tmpBmpStream.Length - BITMAPFILEHEADER_LENGTH); + } + + // Set the DIB to the clipboard DataObject + dataObject.SetData(DataFormats.Dib, true, dibStream); + } + } + catch (Exception dibEx) + { + Log.Error("Error creating DIB for the Clipboard.", dibEx); + } + + // CF_DibV5 + try + { + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIBV5)) + { + // Create the stream for the clipboard + dibV5Stream = new MemoryStream(); + + // Create the BITMAPINFOHEADER + BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32) + { + // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? + biCompression = BI_COMPRESSION.BI_BITFIELDS + }; + // Create a byte[] to write + byte[] headerBytes = BinaryStructHelper.ToByteArray(header); + // Write the BITMAPINFOHEADER to the stream + dibV5Stream.Write(headerBytes, 0, headerBytes.Length); + + // As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added + BitfieldColorMask colorMask = new BitfieldColorMask(); + // Make sure the values are set + colorMask.InitValues(); + // Create the byte[] from the struct + byte[] colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask); + Array.Reverse(colorMaskBytes); + // Write to the stream + dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length); + + // Create the raw bytes for the pixels only + byte[] bitmapBytes = BitmapToByteArray((Bitmap) imageToSave); + // Write to the stream + dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length); + + // Set the DIBv5 to the clipboard DataObject + dataObject.SetData(FORMAT_17, true, dibV5Stream); + } + } + catch (Exception dibEx) + { + Log.Error("Error creating DIB for the Clipboard.", dibEx); + } + + // Set the HTML + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTML)) + { + string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null); + string html = GetHtmlString(surface, tmpFile); + dataObject.SetText(html, TextDataFormat.Html); + } + else if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTMLDATAURL)) + { + string html; + using (MemoryStream tmpPngStream = new MemoryStream()) + { + SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false) + { + // Do not allow to reduce the colors, some applications dislike 256 color images + // reported with bug #3594681 + DisableReduceColors = true + }; + // Check if we can use the previously used image + if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) + { + ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings); + } + else + { + ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings); + } + + html = GetHtmlDataUrlString(surface, tmpPngStream); + } + + dataObject.SetText(html, TextDataFormat.Html); + } + } + finally + { + // we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone! + // Check if Bitmap is wanted + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) + { + dataObject.SetImage(imageToSave); + // Place the DataObject to the clipboard + SetDataObject(dataObject, true); + } + else + { + // Place the DataObject to the clipboard + SetDataObject(dataObject, true); + } + + pngStream?.Dispose(); + dibStream?.Dispose(); + dibV5Stream?.Dispose(); + // cleanup if needed + if (disposeImage) + { + imageToSave?.Dispose(); + } + } + } /// - /// Get Object for format from IDataObject - /// - /// IDataObject - /// Type to get - /// object from IDataObject - public static object GetFromDataObject(IDataObject dataObj, Type type) { - if (type != null) { - return GetFromDataObject(dataObj, type.FullName); - } - return null; - } + /// Helper method so get the bitmap bytes + /// See: http://stackoverflow.com/a/6570155 + ///
+ /// Bitmap + /// byte[] + private static byte[] BitmapToByteArray(Bitmap bitmap) + { + // Lock the bitmap's bits. + Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); + BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat); - /// - /// Get ImageFilenames from the IDataObject - /// - /// IDataObject - /// - public static IEnumerable GetImageFilenames(IDataObject dataObject) { - string[] dropFileNames = (string[]) dataObject.GetData(DataFormats.FileDrop); - if (dropFileNames != null && dropFileNames.Length > 0) - { - return dropFileNames - .Where(filename => !string.IsNullOrEmpty(filename)) - .Where(Path.HasExtension) - .Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1))); - } - return Enumerable.Empty(); - } + int absStride = Math.Abs(bmpData.Stride); + int bytes = absStride * bitmap.Height; + long ptr = bmpData.Scan0.ToInt32(); + // Declare an array to hold the bytes of the bitmap. + byte[] rgbValues = new byte[bytes]; - /// - /// Get Object for format from IDataObject - /// - /// IDataObject - /// format to get - /// object from IDataObject - public static object GetFromDataObject(IDataObject dataObj, string format) { - if (dataObj != null) { - try { - return dataObj.GetData(format); - } catch (Exception e) { - Log.Error("Error in GetClipboardData.", e); - } - } - return null; - } + for (int i = 0; i < bitmap.Height; i++) + { + IntPtr pointer = new IntPtr(ptr + (bmpData.Stride * i)); + Marshal.Copy(pointer, rgbValues, absStride * (bitmap.Height - i - 1), absStride); + } + + // Unlock the bits. + bitmap.UnlockBits(bmpData); + + return rgbValues; + } + + /// + /// Set Object with type Type to the clipboard + /// + /// Type + /// object + public static void SetClipboardData(Type type, object obj) + { + DataFormats.Format format = DataFormats.GetFormat(type.FullName); + + //now copy to clipboard + IDataObject dataObj = new DataObject(); + dataObj.SetData(format.Name, false, obj); + // Use false to make the object disappear when the application stops. + SetDataObject(dataObj, true); + } + + /// + /// Retrieve a list of all formats currently in the IDataObject + /// + /// List of string with the current formats + public static List GetFormats(IDataObject dataObj) + { + string[] formats = null; + + if (dataObj != null) + { + formats = dataObj.GetFormats(); + } + + if (formats != null) + { + Log.DebugFormat("Got clipboard formats: {0}", string.Join(",", formats)); + return new List(formats); + } + + return new List(); + } + + /// + /// Check if there is currently something on the clipboard which has the supplied format + /// + /// IDataObject + /// string with format + /// true if one the format is found + public static bool ContainsFormat(IDataObject dataObject, string format) + { + return ContainsFormat(dataObject, new[] + { + format + }); + } + + /// + /// Check if there is currently something on the clipboard which has one of the supplied formats + /// + /// string[] with formats + /// true if one of the formats was found + public static bool ContainsFormat(string[] formats) + { + return ContainsFormat(GetDataObject(), formats); + } + + /// + /// Check if there is currently something on the clipboard which has one of the supplied formats + /// + /// IDataObject + /// string[] with formats + /// true if one of the formats was found + public static bool ContainsFormat(IDataObject dataObject, string[] formats) + { + bool formatFound = false; + List currentFormats = GetFormats(dataObject); + if (currentFormats == null || currentFormats.Count == 0 || formats == null || formats.Length == 0) + { + return false; + } + + foreach (string format in formats) + { + if (currentFormats.Contains(format)) + { + formatFound = true; + break; + } + } + + return formatFound; + } + + /// + /// Get Object for format from IDataObject + /// + /// IDataObject + /// Type to get + /// object from IDataObject + public static object GetFromDataObject(IDataObject dataObj, Type type) + { + if (type != null) + { + return GetFromDataObject(dataObj, type.FullName); + } + + return null; + } + + /// + /// Get ImageFilenames from the IDataObject + /// + /// IDataObject + /// + public static IEnumerable GetImageFilenames(IDataObject dataObject) + { + string[] dropFileNames = (string[]) dataObject.GetData(DataFormats.FileDrop); + if (dropFileNames != null && dropFileNames.Length > 0) + { + return dropFileNames + .Where(filename => !string.IsNullOrEmpty(filename)) + .Where(Path.HasExtension) + .Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1))); + } + + return Enumerable.Empty(); + } + + /// + /// Get Object for format from IDataObject + /// + /// IDataObject + /// format to get + /// object from IDataObject + public static object GetFromDataObject(IDataObject dataObj, string format) + { + if (dataObj != null) + { + try + { + return dataObj.GetData(format); + } + catch (Exception e) + { + Log.Error("Error in GetClipboardData.", e); + } + } + + return null; + } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/CoreConfiguration.cs b/src/GreenshotPlugin/Core/CoreConfiguration.cs index 9a5ef5270..d099770a7 100644 --- a/src/GreenshotPlugin/Core/CoreConfiguration.cs +++ b/src/GreenshotPlugin/Core/CoreConfiguration.cs @@ -29,502 +29,709 @@ using System.Windows.Forms; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; -namespace GreenshotPlugin.Core { - public enum ClipboardFormat { - PNG, DIB, HTML, HTMLDATAURL, BITMAP, DIBV5 - } - public enum OutputFormat { - bmp, gif, jpg, png, tiff, greenshot, ico - } - public enum WindowCaptureMode { - Screen, GDI, Aero, AeroTransparent, Auto - } +namespace GreenshotPlugin.Core +{ + public enum ClipboardFormat + { + PNG, + DIB, + HTML, + HTMLDATAURL, + BITMAP, + DIBV5 + } - public enum BuildStates { - UNSTABLE, - RELEASE_CANDIDATE, - RELEASE - } + public enum OutputFormat + { + bmp, + gif, + jpg, + png, + tiff, + greenshot, + ico + } - public enum ClickActions { - DO_NOTHING, - OPEN_LAST_IN_EXPLORER, - OPEN_LAST_IN_EDITOR, - OPEN_SETTINGS, - SHOW_CONTEXT_MENU - } + public enum WindowCaptureMode + { + Screen, + GDI, + Aero, + AeroTransparent, + Auto + } - /// - /// Description of CoreConfiguration. - /// - [IniSection("Core", Description="Greenshot core configuration")] - public class CoreConfiguration : IniSection, INotifyPropertyChanged { - public event PropertyChangedEventHandler PropertyChanged; + public enum BuildStates + { + UNSTABLE, + RELEASE_CANDIDATE, + RELEASE + } - [IniProperty("Language", Description = "The language in IETF format (e.g. en-US)")] - public string Language { get; set; } + public enum ClickActions + { + DO_NOTHING, + OPEN_LAST_IN_EXPLORER, + OPEN_LAST_IN_EDITOR, + OPEN_SETTINGS, + SHOW_CONTEXT_MENU + } - [IniProperty("RegionHotkey", Description="Hotkey for starting the region capture", DefaultValue="PrintScreen")] - public string RegionHotkey { get; set; } - [IniProperty("WindowHotkey", Description="Hotkey for starting the window capture", DefaultValue="Alt + PrintScreen")] - public string WindowHotkey { get; set; } - [IniProperty("FullscreenHotkey", Description="Hotkey for starting the fullscreen capture", DefaultValue="Ctrl + PrintScreen")] - public string FullscreenHotkey { get; set; } - [IniProperty("LastregionHotkey", Description="Hotkey for starting the last region capture", DefaultValue="Shift + PrintScreen")] - public string LastregionHotkey { get; set; } - [IniProperty("IEHotkey", Description="Hotkey for starting the IE capture", DefaultValue="Shift + Ctrl + PrintScreen")] - public string IEHotkey { get; set; } - - [IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor")] - public string ClipboardHotkey { get; set; } + /// + /// Description of CoreConfiguration. + /// + [IniSection("Core", Description = "Greenshot core configuration")] + public class CoreConfiguration : IniSection, INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; - [IniProperty("IsFirstLaunch", Description="Is this the first time launch?", DefaultValue="true")] - public bool IsFirstLaunch { get; set; } - [IniProperty("Destinations", Separator=",", Description="Which destinations? Possible options (more might be added by plugins) are: Editor, FileDefault, FileWithDialog, Clipboard, Printer, EMail, Picker", DefaultValue="Picker")] - public List OutputDestinations { get; set; } = new List(); - [IniProperty("ClipboardFormats", Separator=",", Description="Specify which formats we copy on the clipboard? Options are: PNG, HTML, HTMLDATAURL and DIB", DefaultValue="PNG,DIB")] - public List ClipboardFormats { get; set; } = new List(); + [IniProperty("Language", Description = "The language in IETF format (e.g. en-US)")] + public string Language { get; set; } - [IniProperty("CaptureMousepointer", Description="Should the mouse be captured?", DefaultValue="true")] - public bool CaptureMousepointer { get; set; } - [IniProperty("CaptureWindowsInteractive", Description="Use interactive window selection to capture? (false=Capture active window)", DefaultValue="false")] - public bool CaptureWindowsInteractive { get; set; } - [IniProperty("CaptureDelay", Description="Capture delay in millseconds.", DefaultValue="100")] - public int CaptureDelay { get; set; } - [IniProperty("ScreenCaptureMode", Description = "The capture mode used to capture a screen. (Auto, FullScreen, Fixed)", DefaultValue = "Auto")] - public ScreenCaptureMode ScreenCaptureMode { get; set; } - [IniProperty("ScreenToCapture", Description = "The screen number to capture when using ScreenCaptureMode Fixed.", DefaultValue = "1")] - public int ScreenToCapture { get; set; } - [IniProperty("WindowCaptureMode", Description = "The capture mode used to capture a Window (Screen, GDI, Aero, AeroTransparent, Auto).", DefaultValue = "Auto")] - public WindowCaptureMode WindowCaptureMode { get; set; } - [IniProperty("WindowCaptureAllChildLocations", Description="Enable/disable capture all children, very slow but will make it possible to use this information in the editor.", DefaultValue="False")] - public bool WindowCaptureAllChildLocations { get; set; } + [IniProperty("RegionHotkey", Description = "Hotkey for starting the region capture", DefaultValue = "PrintScreen")] + public string RegionHotkey { get; set; } - [IniProperty("DWMBackgroundColor", Description="The background color for a DWM window capture.")] - public Color DWMBackgroundColor { get; set; } + [IniProperty("WindowHotkey", Description = "Hotkey for starting the window capture", DefaultValue = "Alt + PrintScreen")] + public string WindowHotkey { get; set; } - [IniProperty("PlayCameraSound", LanguageKey="settings_playsound",Description="Play a camera sound after taking a capture.", DefaultValue="false")] - public bool PlayCameraSound { get; set; } = false; - [IniProperty("ShowTrayNotification", LanguageKey="settings_shownotify",Description="Show a notification from the systray when a capture is taken.", DefaultValue="true")] - public bool ShowTrayNotification { get; set; } = true; + [IniProperty("FullscreenHotkey", Description = "Hotkey for starting the fullscreen capture", DefaultValue = "Ctrl + PrintScreen")] + public string FullscreenHotkey { get; set; } - [IniProperty("OutputFilePath", Description="Output file path.")] - public string OutputFilePath { get; set; } - [IniProperty("OutputFileAllowOverwrite", Description = "If the target file already exists True will make Greenshot always overwrite and False will display a 'Save-As' dialog.", DefaultValue = "true")] - public bool OutputFileAllowOverwrite { get; set; } - [IniProperty("OutputFileFilenamePattern", Description = "Filename pattern for screenshot.", DefaultValue = "${capturetime:d\"yyyy-MM-dd HH_mm_ss\"}-${title}")] - public string OutputFileFilenamePattern { get; set; } - [IniProperty("OutputFileFormat", Description="Default file type for writing screenshots. (bmp, gif, jpg, png, tiff)", DefaultValue="png")] - public OutputFormat OutputFileFormat { get; set; } = OutputFormat.png; - [IniProperty("OutputFileReduceColors", Description="If set to true, than the colors of the output file are reduced to 256 (8-bit) colors", DefaultValue="false")] - public bool OutputFileReduceColors { get; set; } - [IniProperty("OutputFileAutoReduceColors", Description = "If set to true the amount of colors is counted and if smaller than 256 the color reduction is automatically used.", DefaultValue = "false")] - public bool OutputFileAutoReduceColors { get; set; } - [IniProperty("OutputFileReduceColorsTo", Description = "Amount of colors to reduce to, when reducing", DefaultValue = "256")] - public int OutputFileReduceColorsTo { get; set; } + [IniProperty("LastregionHotkey", Description = "Hotkey for starting the last region capture", DefaultValue = "Shift + PrintScreen")] + public string LastregionHotkey { get; set; } - [IniProperty("OutputFileCopyPathToClipboard", Description="When saving a screenshot, copy the path to the clipboard?", DefaultValue="true")] - public bool OutputFileCopyPathToClipboard { get; set; } - [IniProperty("OutputFileAsFullpath", Description="SaveAs Full path?")] - public string OutputFileAsFullpath { get; set; } + [IniProperty("IEHotkey", Description = "Hotkey for starting the IE capture", DefaultValue = "Shift + Ctrl + PrintScreen")] + public string IEHotkey { get; set; } - [IniProperty("OutputFileJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int OutputFileJpegQuality { get; set; } - [IniProperty("OutputFilePromptQuality", Description="Ask for the quality before saving?", DefaultValue="false")] - public bool OutputFilePromptQuality { get; set; } - [IniProperty("OutputFileIncrementingNumber", Description="The number for the ${NUM} in the filename pattern, is increased automatically after each save.", DefaultValue="1")] - public uint OutputFileIncrementingNumber { get; set; } + [IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor")] + public string ClipboardHotkey { get; set; } - [IniProperty("OutputPrintPromptOptions", LanguageKey="settings_alwaysshowprintoptionsdialog", Description="Ask for print options when printing?", DefaultValue="true")] - public bool OutputPrintPromptOptions { get; set; } - [IniProperty("OutputPrintAllowRotate", LanguageKey="printoptions_allowrotate", Description="Allow rotating the picture for fitting on paper?", DefaultValue="false")] - public bool OutputPrintAllowRotate { get; set; } - [IniProperty("OutputPrintAllowEnlarge", LanguageKey="printoptions_allowenlarge", Description="Allow growing the picture for fitting on paper?", DefaultValue="false")] - public bool OutputPrintAllowEnlarge { get; set; } - [IniProperty("OutputPrintAllowShrink", LanguageKey="printoptions_allowshrink", Description="Allow shrinking the picture for fitting on paper?", DefaultValue="true")] - public bool OutputPrintAllowShrink { get; set; } - [IniProperty("OutputPrintCenter", LanguageKey="printoptions_allowcenter", Description="Center image when printing?", DefaultValue="true")] - public bool OutputPrintCenter { get; set; } - [IniProperty("OutputPrintInverted", LanguageKey="printoptions_inverted", Description="Print image inverted (use e.g. for console captures)", DefaultValue="false")] - public bool OutputPrintInverted { get; set; } - [IniProperty("OutputPrintGrayscale", LanguageKey = "printoptions_printgrayscale", Description = "Force grayscale printing", DefaultValue = "false")] - public bool OutputPrintGrayscale { get; set; } - [IniProperty("OutputPrintMonochrome", LanguageKey = "printoptions_printmonochrome", Description = "Force monorchrome printing", DefaultValue = "false")] - public bool OutputPrintMonochrome { get; set; } - [IniProperty("OutputPrintMonochromeThreshold", Description = "Threshold for monochrome filter (0 - 255), lower value means less black", DefaultValue = "127")] - public byte OutputPrintMonochromeThreshold { get; set; } - [IniProperty("OutputPrintFooter", LanguageKey = "printoptions_timestamp", Description = "Print footer on print?", DefaultValue = "true")] - public bool OutputPrintFooter { get; set; } - [IniProperty("OutputPrintFooterPattern", Description = "Footer pattern", DefaultValue = "${capturetime:d\"D\"} ${capturetime:d\"T\"} - ${title}")] - public string OutputPrintFooterPattern { get; set; } - [IniProperty("NotificationSound", Description = "The wav-file to play when a capture is taken, loaded only once at the Greenshot startup", DefaultValue="default")] - public string NotificationSound { get; set; } - [IniProperty("UseProxy", Description="Use your global proxy?", DefaultValue="True")] - public bool UseProxy { get; set; } - [IniProperty("IECapture", Description="Enable/disable IE capture", DefaultValue="True")] - public bool IECapture { get; set; } - [IniProperty("IEFieldCapture", Description="Enable/disable IE field capture, very slow but will make it possible to annotate the fields of a capture in the editor.", DefaultValue="False")] - public bool IEFieldCapture { get; set; } - [IniProperty("WindowClassesToCheckForIE", Description = "Comma separated list of Window-Classes which need to be checked for a IE instance!", DefaultValue = "AfxFrameOrView70,IMWindowClass")] - public List WindowClassesToCheckForIE { get; set; } - [IniProperty("AutoCropDifference", Description="Sets how to compare the colors for the autocrop detection, the higher the more is 'selected'. Possible values are from 0 to 255, where everything above ~150 doesn't make much sense!", DefaultValue="10")] - public int AutoCropDifference { get; set; } + [IniProperty("IsFirstLaunch", Description = "Is this the first time launch?", DefaultValue = "true")] + public bool IsFirstLaunch { get; set; } - [IniProperty("IncludePlugins", Description="Comma separated list of Plugins which are allowed. If something in the list, than every plugin not in the list will not be loaded!")] - public List IncludePlugins { get; set; } - [IniProperty("ExcludePlugins", Description="Comma separated list of Plugins which are NOT allowed.")] - public List ExcludePlugins { get; set; } - [IniProperty("ExcludeDestinations", Description = "Comma separated list of destinations which should be disabled.")] - public List ExcludeDestinations { get; set; } + [IniProperty("Destinations", Separator = ",", + Description = "Which destinations? Possible options (more might be added by plugins) are: Editor, FileDefault, FileWithDialog, Clipboard, Printer, EMail, Picker", + DefaultValue = "Picker")] + public List OutputDestinations { get; set; } = new List(); - [IniProperty("UpdateCheckInterval", Description="How many days between every update check? (0=no checks)", DefaultValue="14")] - public int UpdateCheckInterval { get; set; } - [IniProperty("LastUpdateCheck", Description="Last update check")] - public DateTime LastUpdateCheck { get; set; } + [IniProperty("ClipboardFormats", Separator = ",", Description = "Specify which formats we copy on the clipboard? Options are: PNG, HTML, HTMLDATAURL and DIB", + DefaultValue = "PNG,DIB")] + public List ClipboardFormats { get; set; } = new List(); - [IniProperty("DisableSettings", Description = "Enable/disable the access to the settings, can only be changed manually in this .ini", DefaultValue = "False")] - public bool DisableSettings { get; set; } - [IniProperty("DisableQuickSettings", Description = "Enable/disable the access to the quick settings, can only be changed manually in this .ini", DefaultValue = "False")] - public bool DisableQuickSettings { get; set; } - [IniProperty("DisableTrayicon", Description = "Disable the trayicon, can only be changed manually in this .ini", DefaultValue = "False")] - public bool HideTrayicon { get; set; } - [IniProperty("HideExpertSettings", Description = "Hide expert tab in the settings, can only be changed manually in this .ini", DefaultValue = "False")] - public bool HideExpertSettings { get; set; } + [IniProperty("CaptureMousepointer", Description = "Should the mouse be captured?", DefaultValue = "true")] + public bool CaptureMousepointer { get; set; } - [IniProperty("ThumnailPreview", Description="Enable/disable thumbnail previews", DefaultValue="True")] - public bool ThumnailPreview { get; set; } + [IniProperty("CaptureWindowsInteractive", Description = "Use interactive window selection to capture? (false=Capture active window)", DefaultValue = "false")] + public bool CaptureWindowsInteractive { get; set; } - [IniProperty("NoGDICaptureForProduct", Description = "List of productnames for which GDI capturing is skipped (using fallback).", DefaultValue = "IntelliJ IDEA")] - public List NoGDICaptureForProduct { get; set; } - [IniProperty("NoDWMCaptureForProduct", Description = "List of productnames for which DWM capturing is skipped (using fallback).", DefaultValue = "Citrix ICA Client")] - public List NoDWMCaptureForProduct { get; set; } + [IniProperty("CaptureDelay", Description = "Capture delay in millseconds.", DefaultValue = "100")] + public int CaptureDelay { get; set; } - [IniProperty("OptimizeForRDP", Description="Make some optimizations for usage with remote desktop", DefaultValue="False")] - public bool OptimizeForRDP { get; set; } - [IniProperty("DisableRDPOptimizing", Description = "Disable all optimizations for usage with remote desktop", DefaultValue = "False")] - public bool DisableRDPOptimizing { get; set; } + [IniProperty("ScreenCaptureMode", Description = "The capture mode used to capture a screen. (Auto, FullScreen, Fixed)", DefaultValue = "Auto")] + public ScreenCaptureMode ScreenCaptureMode { get; set; } - [IniProperty("MinimizeWorkingSetSize", Description="Optimize memory footprint, but with a performance penalty!", DefaultValue="False")] - public bool MinimizeWorkingSetSize { get; set; } + [IniProperty("ScreenToCapture", Description = "The screen number to capture when using ScreenCaptureMode Fixed.", DefaultValue = "1")] + public int ScreenToCapture { get; set; } - [IniProperty("WindowCaptureRemoveCorners", Description = "Remove the corners from a window capture", DefaultValue = "True")] - public bool WindowCaptureRemoveCorners { get; set; } + [IniProperty("WindowCaptureMode", Description = "The capture mode used to capture a Window (Screen, GDI, Aero, AeroTransparent, Auto).", DefaultValue = "Auto")] + public WindowCaptureMode WindowCaptureMode { get; set; } - [IniProperty("CheckForUnstable", Description = "Also check for unstable version updates", DefaultValue = "False")] - public bool CheckForUnstable { get; set; } + [IniProperty("WindowCaptureAllChildLocations", + Description = "Enable/disable capture all children, very slow but will make it possible to use this information in the editor.", DefaultValue = "False")] + public bool WindowCaptureAllChildLocations { get; set; } - [IniProperty("ActiveTitleFixes", Description="The fixes that are active.")] - public List ActiveTitleFixes { get; set; } + [IniProperty("DWMBackgroundColor", Description = "The background color for a DWM window capture.")] + public Color DWMBackgroundColor { get; set; } - [IniProperty("TitleFixMatcher", Description="The regular expressions to match the title with.")] - public Dictionary TitleFixMatcher { get; set; } + [IniProperty("PlayCameraSound", LanguageKey = "settings_playsound", Description = "Play a camera sound after taking a capture.", DefaultValue = "false")] + public bool PlayCameraSound { get; set; } = false; - [IniProperty("TitleFixReplacer", Description="The replacements for the matchers.")] - public Dictionary TitleFixReplacer { get; set; } + [IniProperty("ShowTrayNotification", LanguageKey = "settings_shownotify", Description = "Show a notification from the systray when a capture is taken.", + DefaultValue = "true")] + public bool ShowTrayNotification { get; set; } = true; - [IniProperty("ExperimentalFeatures", Description="A list of experimental features, this allows us to test certain features before releasing them.", ExcludeIfNull=true)] - public List ExperimentalFeatures { get; set; } + [IniProperty("OutputFilePath", Description = "Output file path.")] + public string OutputFilePath { get; set; } - [IniProperty("EnableSpecialDIBClipboardReader", Description = "Enable a special DIB clipboard reader", DefaultValue="True")] - public bool EnableSpecialDIBClipboardReader { get; set; } + [IniProperty("OutputFileAllowOverwrite", + Description = "If the target file already exists True will make Greenshot always overwrite and False will display a 'Save-As' dialog.", DefaultValue = "true")] + public bool OutputFileAllowOverwrite { get; set; } - [IniProperty("WindowCornerCutShape", Description = "The cutshape which is used to remove the window corners, is mirrorred for all corners", DefaultValue = "5,3,2,1,1")] - public List WindowCornerCutShape { get; set; } + [IniProperty("OutputFileFilenamePattern", Description = "Filename pattern for screenshot.", DefaultValue = "${capturetime:d\"yyyy-MM-dd HH_mm_ss\"}-${title}")] + public string OutputFileFilenamePattern { get; set; } - [IniProperty("LeftClickAction", Description = "Specify what action is made if the tray icon is left clicked, if a double-click action is specified this action is initiated after a delay (configurable via the windows double-click speed)", DefaultValue = "SHOW_CONTEXT_MENU")] - public ClickActions LeftClickAction { get; set; } + [IniProperty("OutputFileFormat", Description = "Default file type for writing screenshots. (bmp, gif, jpg, png, tiff)", DefaultValue = "png")] + public OutputFormat OutputFileFormat { get; set; } = OutputFormat.png; - [IniProperty("DoubleClickAction", Description = "Specify what action is made if the tray icon is double clicked", DefaultValue = "OPEN_LAST_IN_EXPLORER")] - public ClickActions DoubleClickAction { get; set; } + [IniProperty("OutputFileReduceColors", Description = "If set to true, than the colors of the output file are reduced to 256 (8-bit) colors", DefaultValue = "false")] + public bool OutputFileReduceColors { get; set; } - [IniProperty("ZoomerEnabled", Description = "Sets if the zoomer is enabled", DefaultValue = "True")] - public bool ZoomerEnabled { get; set; } - [IniProperty("ZoomerOpacity", Description = "Specify the transparency for the zoomer, from 0-1 (where 1 is no transparency and 0 is complete transparent. An usefull setting would be 0.7)", DefaultValue = "1")] - public float ZoomerOpacity { get; set; } + [IniProperty("OutputFileAutoReduceColors", + Description = "If set to true the amount of colors is counted and if smaller than 256 the color reduction is automatically used.", DefaultValue = "false")] + public bool OutputFileAutoReduceColors { get; set; } - [IniProperty("MaxMenuItemLength", Description = "Maximum length of submenu items in the context menu, making this longer might cause context menu issues on dual screen systems.", DefaultValue = "25")] - public int MaxMenuItemLength { get; set; } + [IniProperty("OutputFileReduceColorsTo", Description = "Amount of colors to reduce to, when reducing", DefaultValue = "256")] + public int OutputFileReduceColorsTo { get; set; } - [IniProperty("MailApiTo", Description = "The 'to' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] - public string MailApiTo { get; set; } - [IniProperty("MailApiCC", Description = "The 'CC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] - public string MailApiCC { get; set; } - [IniProperty("MailApiBCC", Description = "The 'BCC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] - public string MailApiBCC { get; set; } + [IniProperty("OutputFileCopyPathToClipboard", Description = "When saving a screenshot, copy the path to the clipboard?", DefaultValue = "true")] + public bool OutputFileCopyPathToClipboard { get; set; } - [IniProperty("OptimizePNGCommand", Description = "Optional command to execute on a temporary PNG file, the command should overwrite the file and Greenshot will read it back. Note: this command is also executed when uploading PNG's!", DefaultValue = "")] - public string OptimizePNGCommand { get; set; } - [IniProperty("OptimizePNGCommandArguments", Description = "Arguments for the optional command to execute on a PNG, {0} is replaced by the temp-filename from Greenshot. Note: Temp-file is deleted afterwards by Greenshot.", DefaultValue = "\"{0}\"")] - public string OptimizePNGCommandArguments { get; set; } + [IniProperty("OutputFileAsFullpath", Description = "SaveAs Full path?")] + public string OutputFileAsFullpath { get; set; } - [IniProperty("LastSaveWithVersion", Description = "Version of Greenshot which created this .ini")] - public string LastSaveWithVersion { get; set; } + [IniProperty("OutputFileJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int OutputFileJpegQuality { get; set; } - [IniProperty("ProcessEXIFOrientation", Description = "When reading images from files or clipboard, use the EXIF information to correct the orientation", DefaultValue = "True")] - public bool ProcessEXIFOrientation { get; set; } + [IniProperty("OutputFilePromptQuality", Description = "Ask for the quality before saving?", DefaultValue = "false")] + public bool OutputFilePromptQuality { get; set; } - [IniProperty("LastCapturedRegion", Description = "The last used region, for reuse in the capture last region")] - public Rectangle LastCapturedRegion { get; set; } + [IniProperty("OutputFileIncrementingNumber", Description = "The number for the ${NUM} in the filename pattern, is increased automatically after each save.", + DefaultValue = "1")] + public uint OutputFileIncrementingNumber { get; set; } - [IniProperty("Win10BorderCrop", Description = "The capture is cropped with these settings, e.g. when you don't want to color around it -1,-1"), DefaultValue("0,0")] - public Size Win10BorderCrop { get; set; } + [IniProperty("OutputPrintPromptOptions", LanguageKey = "settings_alwaysshowprintoptionsdialog", Description = "Ask for print options when printing?", + DefaultValue = "true")] + public bool OutputPrintPromptOptions { get; set; } - private Size _iconSize; - [IniProperty("BaseIconSize", Description = "Defines the base size of the icons (e.g. for the buttons in the editor), default value 16,16 and it's scaled to the current DPI", DefaultValue = "16,16")] - public Size IconSize { - get { - return _iconSize; - } - set { - Size newSize = value; - if (newSize != Size.Empty) { - if (newSize.Width < 16) { - newSize.Width = 16; - } else if (newSize.Width > 256) { - newSize.Width = 256; - } - newSize.Width = (newSize.Width / 16) * 16; - if (newSize.Height < 16) { - newSize.Height = 16; - } else if (IconSize.Height > 256) { - newSize.Height = 256; - } - newSize.Height = (newSize.Height / 16) * 16; - } - if (_iconSize != newSize) { - _iconSize = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IconSize")); - } - } - } + [IniProperty("OutputPrintAllowRotate", LanguageKey = "printoptions_allowrotate", Description = "Allow rotating the picture for fitting on paper?", DefaultValue = "false")] + public bool OutputPrintAllowRotate { get; set; } - public Size ScaledIconSize => DpiHelper.ScaleWithCurrentDpi(_iconSize); + [IniProperty("OutputPrintAllowEnlarge", LanguageKey = "printoptions_allowenlarge", Description = "Allow growing the picture for fitting on paper?", DefaultValue = "false")] + public bool OutputPrintAllowEnlarge { get; set; } - [IniProperty("WebRequestTimeout", Description = "The connect timeout value for webrequets, these are seconds", DefaultValue = "100")] - public int WebRequestTimeout { get; set; } - [IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")] - public int WebRequestReadWriteTimeout { get; set; } + [IniProperty("OutputPrintAllowShrink", LanguageKey = "printoptions_allowshrink", Description = "Allow shrinking the picture for fitting on paper?", DefaultValue = "true")] + public bool OutputPrintAllowShrink { get; set; } + + [IniProperty("OutputPrintCenter", LanguageKey = "printoptions_allowcenter", Description = "Center image when printing?", DefaultValue = "true")] + public bool OutputPrintCenter { get; set; } + + [IniProperty("OutputPrintInverted", LanguageKey = "printoptions_inverted", Description = "Print image inverted (use e.g. for console captures)", DefaultValue = "false")] + public bool OutputPrintInverted { get; set; } + + [IniProperty("OutputPrintGrayscale", LanguageKey = "printoptions_printgrayscale", Description = "Force grayscale printing", DefaultValue = "false")] + public bool OutputPrintGrayscale { get; set; } + + [IniProperty("OutputPrintMonochrome", LanguageKey = "printoptions_printmonochrome", Description = "Force monorchrome printing", DefaultValue = "false")] + public bool OutputPrintMonochrome { get; set; } + + [IniProperty("OutputPrintMonochromeThreshold", Description = "Threshold for monochrome filter (0 - 255), lower value means less black", DefaultValue = "127")] + public byte OutputPrintMonochromeThreshold { get; set; } + + [IniProperty("OutputPrintFooter", LanguageKey = "printoptions_timestamp", Description = "Print footer on print?", DefaultValue = "true")] + public bool OutputPrintFooter { get; set; } + + [IniProperty("OutputPrintFooterPattern", Description = "Footer pattern", DefaultValue = "${capturetime:d\"D\"} ${capturetime:d\"T\"} - ${title}")] + public string OutputPrintFooterPattern { get; set; } + + [IniProperty("NotificationSound", Description = "The wav-file to play when a capture is taken, loaded only once at the Greenshot startup", DefaultValue = "default")] + public string NotificationSound { get; set; } + + [IniProperty("UseProxy", Description = "Use your global proxy?", DefaultValue = "True")] + public bool UseProxy { get; set; } + + [IniProperty("IECapture", Description = "Enable/disable IE capture", DefaultValue = "True")] + public bool IECapture { get; set; } + + [IniProperty("IEFieldCapture", Description = "Enable/disable IE field capture, very slow but will make it possible to annotate the fields of a capture in the editor.", + DefaultValue = "False")] + public bool IEFieldCapture { get; set; } + + [IniProperty("WindowClassesToCheckForIE", Description = "Comma separated list of Window-Classes which need to be checked for a IE instance!", + DefaultValue = "AfxFrameOrView70,IMWindowClass")] + public List WindowClassesToCheckForIE { get; set; } + + [IniProperty("AutoCropDifference", + Description = + "Sets how to compare the colors for the autocrop detection, the higher the more is 'selected'. Possible values are from 0 to 255, where everything above ~150 doesn't make much sense!", + DefaultValue = "10")] + public int AutoCropDifference { get; set; } + + [IniProperty("IncludePlugins", + Description = "Comma separated list of Plugins which are allowed. If something in the list, than every plugin not in the list will not be loaded!")] + public List IncludePlugins { get; set; } + + [IniProperty("ExcludePlugins", Description = "Comma separated list of Plugins which are NOT allowed.")] + public List ExcludePlugins { get; set; } + + [IniProperty("ExcludeDestinations", Description = "Comma separated list of destinations which should be disabled.")] + public List ExcludeDestinations { get; set; } + + [IniProperty("UpdateCheckInterval", Description = "How many days between every update check? (0=no checks)", DefaultValue = "14")] + public int UpdateCheckInterval { get; set; } + + [IniProperty("LastUpdateCheck", Description = "Last update check")] + public DateTime LastUpdateCheck { get; set; } + + [IniProperty("DisableSettings", Description = "Enable/disable the access to the settings, can only be changed manually in this .ini", DefaultValue = "False")] + public bool DisableSettings { get; set; } + + [IniProperty("DisableQuickSettings", Description = "Enable/disable the access to the quick settings, can only be changed manually in this .ini", DefaultValue = "False")] + public bool DisableQuickSettings { get; set; } + + [IniProperty("DisableTrayicon", Description = "Disable the trayicon, can only be changed manually in this .ini", DefaultValue = "False")] + public bool HideTrayicon { get; set; } + + [IniProperty("HideExpertSettings", Description = "Hide expert tab in the settings, can only be changed manually in this .ini", DefaultValue = "False")] + public bool HideExpertSettings { get; set; } + + [IniProperty("ThumnailPreview", Description = "Enable/disable thumbnail previews", DefaultValue = "True")] + public bool ThumnailPreview { get; set; } + + [IniProperty("NoGDICaptureForProduct", Description = "List of productnames for which GDI capturing is skipped (using fallback).", DefaultValue = "IntelliJ IDEA")] + public List NoGDICaptureForProduct { get; set; } + + [IniProperty("NoDWMCaptureForProduct", Description = "List of productnames for which DWM capturing is skipped (using fallback).", DefaultValue = "Citrix ICA Client")] + public List NoDWMCaptureForProduct { get; set; } + + [IniProperty("OptimizeForRDP", Description = "Make some optimizations for usage with remote desktop", DefaultValue = "False")] + public bool OptimizeForRDP { get; set; } + + [IniProperty("DisableRDPOptimizing", Description = "Disable all optimizations for usage with remote desktop", DefaultValue = "False")] + public bool DisableRDPOptimizing { get; set; } + + [IniProperty("MinimizeWorkingSetSize", Description = "Optimize memory footprint, but with a performance penalty!", DefaultValue = "False")] + public bool MinimizeWorkingSetSize { get; set; } + + [IniProperty("WindowCaptureRemoveCorners", Description = "Remove the corners from a window capture", DefaultValue = "True")] + public bool WindowCaptureRemoveCorners { get; set; } + + [IniProperty("CheckForUnstable", Description = "Also check for unstable version updates", DefaultValue = "False")] + public bool CheckForUnstable { get; set; } + + [IniProperty("ActiveTitleFixes", Description = "The fixes that are active.")] + public List ActiveTitleFixes { get; set; } + + [IniProperty("TitleFixMatcher", Description = "The regular expressions to match the title with.")] + public Dictionary TitleFixMatcher { get; set; } + + [IniProperty("TitleFixReplacer", Description = "The replacements for the matchers.")] + public Dictionary TitleFixReplacer { get; set; } + + [IniProperty("ExperimentalFeatures", Description = "A list of experimental features, this allows us to test certain features before releasing them.", ExcludeIfNull = true)] + public List ExperimentalFeatures { get; set; } + + [IniProperty("EnableSpecialDIBClipboardReader", Description = "Enable a special DIB clipboard reader", DefaultValue = "True")] + public bool EnableSpecialDIBClipboardReader { get; set; } + + [IniProperty("WindowCornerCutShape", Description = "The cutshape which is used to remove the window corners, is mirrorred for all corners", DefaultValue = "5,3,2,1,1")] + public List WindowCornerCutShape { get; set; } + + [IniProperty("LeftClickAction", + Description = + "Specify what action is made if the tray icon is left clicked, if a double-click action is specified this action is initiated after a delay (configurable via the windows double-click speed)", + DefaultValue = "SHOW_CONTEXT_MENU")] + public ClickActions LeftClickAction { get; set; } + + [IniProperty("DoubleClickAction", Description = "Specify what action is made if the tray icon is double clicked", DefaultValue = "OPEN_LAST_IN_EXPLORER")] + public ClickActions DoubleClickAction { get; set; } + + [IniProperty("ZoomerEnabled", Description = "Sets if the zoomer is enabled", DefaultValue = "True")] + public bool ZoomerEnabled { get; set; } + + [IniProperty("ZoomerOpacity", + Description = "Specify the transparency for the zoomer, from 0-1 (where 1 is no transparency and 0 is complete transparent. An usefull setting would be 0.7)", + DefaultValue = "1")] + public float ZoomerOpacity { get; set; } + + [IniProperty("MaxMenuItemLength", + Description = "Maximum length of submenu items in the context menu, making this longer might cause context menu issues on dual screen systems.", DefaultValue = "25")] + public int MaxMenuItemLength { get; set; } + + [IniProperty("MailApiTo", Description = "The 'to' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] + public string MailApiTo { get; set; } + + [IniProperty("MailApiCC", Description = "The 'CC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] + public string MailApiCC { get; set; } + + [IniProperty("MailApiBCC", Description = "The 'BCC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] + public string MailApiBCC { get; set; } + + [IniProperty("OptimizePNGCommand", + Description = + "Optional command to execute on a temporary PNG file, the command should overwrite the file and Greenshot will read it back. Note: this command is also executed when uploading PNG's!", + DefaultValue = "")] + public string OptimizePNGCommand { get; set; } + + [IniProperty("OptimizePNGCommandArguments", + Description = + "Arguments for the optional command to execute on a PNG, {0} is replaced by the temp-filename from Greenshot. Note: Temp-file is deleted afterwards by Greenshot.", + DefaultValue = "\"{0}\"")] + public string OptimizePNGCommandArguments { get; set; } + + [IniProperty("LastSaveWithVersion", Description = "Version of Greenshot which created this .ini")] + public string LastSaveWithVersion { get; set; } + + [IniProperty("ProcessEXIFOrientation", Description = "When reading images from files or clipboard, use the EXIF information to correct the orientation", + DefaultValue = "True")] + public bool ProcessEXIFOrientation { get; set; } + + [IniProperty("LastCapturedRegion", Description = "The last used region, for reuse in the capture last region")] + public Rectangle LastCapturedRegion { get; set; } + + [IniProperty("Win10BorderCrop", Description = "The capture is cropped with these settings, e.g. when you don't want to color around it -1,-1"), DefaultValue("0,0")] + public Size Win10BorderCrop { get; set; } + + private Size _iconSize; + + [IniProperty("BaseIconSize", + Description = "Defines the base size of the icons (e.g. for the buttons in the editor), default value 16,16 and it's scaled to the current DPI", + DefaultValue = "16,16")] + public Size IconSize + { + get { return _iconSize; } + set + { + Size newSize = value; + if (newSize != Size.Empty) + { + if (newSize.Width < 16) + { + newSize.Width = 16; + } + else if (newSize.Width > 256) + { + newSize.Width = 256; + } + + newSize.Width = (newSize.Width / 16) * 16; + if (newSize.Height < 16) + { + newSize.Height = 16; + } + else if (IconSize.Height > 256) + { + newSize.Height = 256; + } + + newSize.Height = (newSize.Height / 16) * 16; + } + + if (_iconSize != newSize) + { + _iconSize = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IconSize")); + } + } + } + + public Size ScaledIconSize => DpiHelper.ScaleWithCurrentDpi(_iconSize); + + [IniProperty("WebRequestTimeout", Description = "The connect timeout value for webrequets, these are seconds", DefaultValue = "100")] + public int WebRequestTimeout { get; set; } + + [IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")] + public int WebRequestReadWriteTimeout { get; set; } public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32; - /// - /// A helper method which returns true if the supplied experimental feature is enabled - /// - /// - /// - public bool IsExperimentalFeatureEnabled(string experimentalFeature) { - return (ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature)); - } + /// + /// A helper method which returns true if the supplied experimental feature is enabled + /// + /// + /// + public bool IsExperimentalFeatureEnabled(string experimentalFeature) + { + return (ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature)); + } - /// - /// Supply values we can't put as defaults - /// - /// The property to return a default for - /// object with the default value for the supplied property - public override object GetDefault(string property) { - switch(property) { - case "PluginWhitelist": - case "PluginBacklist": - return new List(); - case "OutputFileAsFullpath": - if (IniConfig.IsPortable) { - return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png"); - } - return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),"dummy.png"); - case "OutputFilePath": - if (IniConfig.IsPortable) { - string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots"); - if (!Directory.Exists(pafOutputFilePath)) { - try { - Directory.CreateDirectory(pafOutputFilePath); - return pafOutputFilePath; - } catch (Exception ex) { - LOG.Warn(ex); - // Problem creating directory, fallback to Desktop - } - } else { - return pafOutputFilePath; - } - } - return Environment.GetFolderPath(Environment.SpecialFolder.Desktop); - case "DWMBackgroundColor": - return Color.Transparent; - case "ActiveTitleFixes": - return new List {"Firefox", "IE", "Chrome"}; - case "TitleFixMatcher": - return new Dictionary {{"Firefox", " - Mozilla Firefox.*"}, {"IE", " - (Microsoft|Windows) Internet Explorer.*"}, {"Chrome", " - Google Chrome.*"}}; - case "TitleFixReplacer": - return new Dictionary {{"Firefox", string.Empty }, {"IE", string.Empty }, {"Chrome", string.Empty } }; - } - return null; - } + /// + /// Supply values we can't put as defaults + /// + /// The property to return a default for + /// object with the default value for the supplied property + public override object GetDefault(string property) + { + switch (property) + { + case "PluginWhitelist": + case "PluginBacklist": + return new List(); + case "OutputFileAsFullpath": + if (IniConfig.IsPortable) + { + return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png"); + } - /// - /// This method will be called before converting the property, making to possible to correct a certain value - /// Can be used when migration is needed - /// - /// The name of the property - /// The string value of the property - /// string with the propertyValue, modified or not... - public override string PreCheckValue(string propertyName, string propertyValue) { - // Changed the separator, now we need to correct this - if ("Destinations".Equals(propertyName)) { - if (propertyValue != null) { - return propertyValue.Replace('|',','); - } - } - if("OutputFilePath".Equals(propertyName)) { - if (string.IsNullOrEmpty(propertyValue)) { - return null; - } - } - return base.PreCheckValue(propertyName, propertyValue); - } + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "dummy.png"); + case "OutputFilePath": + if (IniConfig.IsPortable) + { + string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots"); + if (!Directory.Exists(pafOutputFilePath)) + { + try + { + Directory.CreateDirectory(pafOutputFilePath); + return pafOutputFilePath; + } + catch (Exception ex) + { + LOG.Warn(ex); + // Problem creating directory, fallback to Desktop + } + } + else + { + return pafOutputFilePath; + } + } - /// - /// This method will be called before writing the configuration - /// - public override void BeforeSave() { - try { - // Store version, this can be used later to fix settings after an update - LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); - } - catch - { - // ignored - } - } + return Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + case "DWMBackgroundColor": + return Color.Transparent; + case "ActiveTitleFixes": + return new List + { + "Firefox", + "IE", + "Chrome" + }; + case "TitleFixMatcher": + return new Dictionary + { + { + "Firefox", " - Mozilla Firefox.*" + }, + { + "IE", " - (Microsoft|Windows) Internet Explorer.*" + }, + { + "Chrome", " - Google Chrome.*" + } + }; + case "TitleFixReplacer": + return new Dictionary + { + { + "Firefox", string.Empty + }, + { + "IE", string.Empty + }, + { + "Chrome", string.Empty + } + }; + } - /// - /// This method will be called after reading the configuration, so eventually some corrections can be made - /// - public override void AfterLoad() { - // Comment with releases - // CheckForUnstable = true; + return null; + } - if (string.IsNullOrEmpty(LastSaveWithVersion)) { - try { - // Store version, this can be used later to fix settings after an update - LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); - } - catch - { - // ignored - } - // Disable the AutoReduceColors as it causes issues with Mozzila applications and some others - OutputFileAutoReduceColors = false; - } + /// + /// This method will be called before converting the property, making to possible to correct a certain value + /// Can be used when migration is needed + /// + /// The name of the property + /// The string value of the property + /// string with the propertyValue, modified or not... + public override string PreCheckValue(string propertyName, string propertyValue) + { + // Changed the separator, now we need to correct this + if ("Destinations".Equals(propertyName)) + { + if (propertyValue != null) + { + return propertyValue.Replace('|', ','); + } + } - // Fix for excessive feed checking - if (UpdateCheckInterval != 0 && UpdateCheckInterval <= 7 && LastSaveWithVersion.StartsWith("1.2")) - { - UpdateCheckInterval = 14; - } - if (UpdateCheckInterval > 365) - { - UpdateCheckInterval = 365; - } + if ("OutputFilePath".Equals(propertyName)) + { + if (string.IsNullOrEmpty(propertyValue)) + { + return null; + } + } - // Enable OneNote if upgrading from 1.1 - if (ExcludeDestinations != null && ExcludeDestinations.Contains("OneNote")) { - if(LastSaveWithVersion != null && LastSaveWithVersion.StartsWith("1.1")) { - ExcludeDestinations.Remove("OneNote"); - } else { - // TODO: Remove with the release - ExcludeDestinations.Remove("OneNote"); - } - } + return base.PreCheckValue(propertyName, propertyValue); + } - if (OutputDestinations == null) { - OutputDestinations = new List(); - } + /// + /// This method will be called before writing the configuration + /// + public override void BeforeSave() + { + try + { + // Store version, this can be used later to fix settings after an update + LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); + } + catch + { + // ignored + } + } - // Make sure there is an output! - if (OutputDestinations.Count == 0) { - OutputDestinations.Add("Editor"); - } + /// + /// This method will be called after reading the configuration, so eventually some corrections can be made + /// + public override void AfterLoad() + { + // Comment with releases + // CheckForUnstable = true; - // Prevent both settings at once, bug #3435056 - if (OutputDestinations.Contains("Clipboard") && OutputFileCopyPathToClipboard) { - OutputFileCopyPathToClipboard = false; - } + if (string.IsNullOrEmpty(LastSaveWithVersion)) + { + try + { + // Store version, this can be used later to fix settings after an update + LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); + } + catch + { + // ignored + } - // Make sure we have clipboard formats, otherwise a paste doesn't make sense! - if (ClipboardFormats == null || ClipboardFormats.Count == 0) { - ClipboardFormats = new List {ClipboardFormat.PNG, ClipboardFormat.HTML, ClipboardFormat.DIB}; - } + // Disable the AutoReduceColors as it causes issues with Mozzila applications and some others + OutputFileAutoReduceColors = false; + } - // Make sure the lists are lowercase, to speedup the check - if (NoGDICaptureForProduct != null) { - // Fix error in configuration - if (NoGDICaptureForProduct.Count >= 2) { - if ("intellij".Equals(NoGDICaptureForProduct[0]) && "idea".Equals(NoGDICaptureForProduct[1])) { - NoGDICaptureForProduct.RemoveRange(0, 2); - NoGDICaptureForProduct.Add("Intellij Idea"); - IsDirty = true; - } - } - for (int i = 0; i < NoGDICaptureForProduct.Count; i++) { - NoGDICaptureForProduct[i] = NoGDICaptureForProduct[i].ToLower(); - } - } - if (NoDWMCaptureForProduct != null) { - // Fix error in configuration - if (NoDWMCaptureForProduct.Count >= 3) { - if ("citrix".Equals(NoDWMCaptureForProduct[0]) && "ica".Equals(NoDWMCaptureForProduct[1]) && "client".Equals(NoDWMCaptureForProduct[2])) { - NoDWMCaptureForProduct.RemoveRange(0, 3); - NoDWMCaptureForProduct.Add("Citrix ICA Client"); - IsDirty = true; - } - } - for (int i = 0; i < NoDWMCaptureForProduct.Count; i++) { - NoDWMCaptureForProduct[i] = NoDWMCaptureForProduct[i].ToLower(); - } - } + // Fix for excessive feed checking + if (UpdateCheckInterval != 0 && UpdateCheckInterval <= 7 && LastSaveWithVersion.StartsWith("1.2")) + { + UpdateCheckInterval = 14; + } - if (AutoCropDifference < 0) { - AutoCropDifference = 0; - } - if (AutoCropDifference > 255) { - AutoCropDifference = 255; - } - if (OutputFileReduceColorsTo < 2) { - OutputFileReduceColorsTo = 2; - } - if (OutputFileReduceColorsTo > 256) { - OutputFileReduceColorsTo = 256; - } + if (UpdateCheckInterval > 365) + { + UpdateCheckInterval = 365; + } - if (WebRequestTimeout <= 10) { - WebRequestTimeout = 100; - } - if (WebRequestReadWriteTimeout < 1) { - WebRequestReadWriteTimeout = 100; - } - } + // Enable OneNote if upgrading from 1.1 + if (ExcludeDestinations != null && ExcludeDestinations.Contains("OneNote")) + { + if (LastSaveWithVersion != null && LastSaveWithVersion.StartsWith("1.1")) + { + ExcludeDestinations.Remove("OneNote"); + } + else + { + // TODO: Remove with the release + ExcludeDestinations.Remove("OneNote"); + } + } - /// - /// Validate the OutputFilePath, and if this is not correct it will be set to the default - /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) - /// - public void ValidateAndCorrectOutputFilePath() - { - if (!Directory.Exists(OutputFilePath)) - { - OutputFilePath = GetDefault(nameof(OutputFilePath)) as string; - } - } - /// - /// Validate the OutputFileAsFullpath, and if this is not correct it will be set to the default - /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) - /// - public void ValidateAndCorrectOutputFileAsFullpath() - { - var outputFilePath = Path.GetDirectoryName(OutputFileAsFullpath); - if (outputFilePath == null || (!File.Exists(OutputFileAsFullpath) && !Directory.Exists(outputFilePath))) - { - OutputFileAsFullpath = GetDefault(nameof(OutputFileAsFullpath)) as string; - } - } - } + if (OutputDestinations == null) + { + OutputDestinations = new List(); + } + + // Make sure there is an output! + if (OutputDestinations.Count == 0) + { + OutputDestinations.Add("Editor"); + } + + // Prevent both settings at once, bug #3435056 + if (OutputDestinations.Contains("Clipboard") && OutputFileCopyPathToClipboard) + { + OutputFileCopyPathToClipboard = false; + } + + // Make sure we have clipboard formats, otherwise a paste doesn't make sense! + if (ClipboardFormats == null || ClipboardFormats.Count == 0) + { + ClipboardFormats = new List + { + ClipboardFormat.PNG, + ClipboardFormat.HTML, + ClipboardFormat.DIB + }; + } + + // Make sure the lists are lowercase, to speedup the check + if (NoGDICaptureForProduct != null) + { + // Fix error in configuration + if (NoGDICaptureForProduct.Count >= 2) + { + if ("intellij".Equals(NoGDICaptureForProduct[0]) && "idea".Equals(NoGDICaptureForProduct[1])) + { + NoGDICaptureForProduct.RemoveRange(0, 2); + NoGDICaptureForProduct.Add("Intellij Idea"); + IsDirty = true; + } + } + + for (int i = 0; i < NoGDICaptureForProduct.Count; i++) + { + NoGDICaptureForProduct[i] = NoGDICaptureForProduct[i].ToLower(); + } + } + + if (NoDWMCaptureForProduct != null) + { + // Fix error in configuration + if (NoDWMCaptureForProduct.Count >= 3) + { + if ("citrix".Equals(NoDWMCaptureForProduct[0]) && "ica".Equals(NoDWMCaptureForProduct[1]) && "client".Equals(NoDWMCaptureForProduct[2])) + { + NoDWMCaptureForProduct.RemoveRange(0, 3); + NoDWMCaptureForProduct.Add("Citrix ICA Client"); + IsDirty = true; + } + } + + for (int i = 0; i < NoDWMCaptureForProduct.Count; i++) + { + NoDWMCaptureForProduct[i] = NoDWMCaptureForProduct[i].ToLower(); + } + } + + if (AutoCropDifference < 0) + { + AutoCropDifference = 0; + } + + if (AutoCropDifference > 255) + { + AutoCropDifference = 255; + } + + if (OutputFileReduceColorsTo < 2) + { + OutputFileReduceColorsTo = 2; + } + + if (OutputFileReduceColorsTo > 256) + { + OutputFileReduceColorsTo = 256; + } + + if (WebRequestTimeout <= 10) + { + WebRequestTimeout = 100; + } + + if (WebRequestReadWriteTimeout < 1) + { + WebRequestReadWriteTimeout = 100; + } + } + + /// + /// Validate the OutputFilePath, and if this is not correct it will be set to the default + /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) + /// + public void ValidateAndCorrectOutputFilePath() + { + if (!Directory.Exists(OutputFilePath)) + { + OutputFilePath = GetDefault(nameof(OutputFilePath)) as string; + } + } + + /// + /// Validate the OutputFileAsFullpath, and if this is not correct it will be set to the default + /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) + /// + public void ValidateAndCorrectOutputFileAsFullpath() + { + var outputFilePath = Path.GetDirectoryName(OutputFileAsFullpath); + if (outputFilePath == null || (!File.Exists(OutputFileAsFullpath) && !Directory.Exists(outputFilePath))) + { + OutputFileAsFullpath = GetDefault(nameof(OutputFileAsFullpath)) as string; + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/CredentialsHelper.cs b/src/GreenshotPlugin/Core/CredentialsHelper.cs index 49b720b25..a1140dc46 100644 --- a/src/GreenshotPlugin/Core/CredentialsHelper.cs +++ b/src/GreenshotPlugin/Core/CredentialsHelper.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Runtime.InteropServices; @@ -25,356 +26,406 @@ using System.Text; using System.Threading; using System.Windows.Forms; -namespace GreenshotPlugin.Core { - /// - /// The following code comes from: http://www.developerfusion.com/code/4693/using-the-credential-management-api/ - /// and is slightly modified so it works for us. - /// As the "Stored usernames and passwords" which can be accessed by: Start-> Run and type "Control keymgr.dll" - /// doesn't show all credentials use the tool here: http://www.microsoft.com/indonesia/msdn/credmgmt.aspx - /// The following code is an example for a login, it will call the Authenticate with user/password - /// which should return true if the login worked, false if not. - /// private static bool Login(string system, string name) { - /// try { - /// CredentialsDialog dialog = new CredentialsDialog(system); - /// dialog.Name = name; - /// while (dialog.Show(dialog.Name) == DialogResult.OK) { - /// if (Authenticate(dialog.Name, dialog.Password)) { - /// if (dialog.SaveChecked) dialog.Confirm(true); - /// return true; - /// } else { - /// try { - /// dialog.Confirm(false); - /// } catch (ApplicationException) { - /// // exception handling ... - /// } - /// dialog.IncorrectPassword = true; - /// } - /// } - /// } catch (ApplicationException) { - /// // exception handling ... - /// } - /// return false; - /// } - /// - /// Encapsulates dialog functionality from the Credential Management API. - public sealed class CredentialsDialog { - [DllImport("gdi32.dll", SetLastError=true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); +namespace GreenshotPlugin.Core +{ + /// + /// The following code comes from: http://www.developerfusion.com/code/4693/using-the-credential-management-api/ + /// and is slightly modified so it works for us. + /// As the "Stored usernames and passwords" which can be accessed by: Start-> Run and type "Control keymgr.dll" + /// doesn't show all credentials use the tool here: http://www.microsoft.com/indonesia/msdn/credmgmt.aspx + /// The following code is an example for a login, it will call the Authenticate with user/password + /// which should return true if the login worked, false if not. + /// private static bool Login(string system, string name) { + /// try { + /// CredentialsDialog dialog = new CredentialsDialog(system); + /// dialog.Name = name; + /// while (dialog.Show(dialog.Name) == DialogResult.OK) { + /// if (Authenticate(dialog.Name, dialog.Password)) { + /// if (dialog.SaveChecked) dialog.Confirm(true); + /// return true; + /// } else { + /// try { + /// dialog.Confirm(false); + /// } catch (ApplicationException) { + /// // exception handling ... + /// } + /// dialog.IncorrectPassword = true; + /// } + /// } + /// } catch (ApplicationException) { + /// // exception handling ... + /// } + /// return false; + /// } + /// + /// Encapsulates dialog functionality from the Credential Management API. + public sealed class CredentialsDialog + { + [DllImport("gdi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteObject(IntPtr hObject); - /// The only valid bitmap height (in pixels) of a user-defined banner. - private const int ValidBannerHeight = 60; + /// The only valid bitmap height (in pixels) of a user-defined banner. + private const int ValidBannerHeight = 60; - /// The only valid bitmap width (in pixels) of a user-defined banner. - private const int ValidBannerWidth = 320; + /// The only valid bitmap width (in pixels) of a user-defined banner. + private const int ValidBannerWidth = 320; - /// Initializes a new instance of the class - /// with the specified target. - /// The name of the target for the credentials, typically a server name. - public CredentialsDialog(string target) : this(target, null) { - } + /// Initializes a new instance of the class + /// with the specified target. + /// The name of the target for the credentials, typically a server name. + public CredentialsDialog(string target) : this(target, null) + { + } - /// Initializes a new instance of the class - /// with the specified target and caption. - /// The name of the target for the credentials, typically a server name. - /// The caption of the dialog (null will cause a system default title to be used). - public CredentialsDialog(string target, string caption) : this(target, caption, null) { - } + /// Initializes a new instance of the class + /// with the specified target and caption. + /// The name of the target for the credentials, typically a server name. + /// The caption of the dialog (null will cause a system default title to be used). + public CredentialsDialog(string target, string caption) : this(target, caption, null) + { + } - /// Initializes a new instance of the class - /// with the specified target, caption and message. - /// The name of the target for the credentials, typically a server name. - /// The caption of the dialog (null will cause a system default title to be used). - /// The message of the dialog (null will cause a system default message to be used). - public CredentialsDialog(string target, string caption, string message) : this(target, caption, message, null) { - } + /// Initializes a new instance of the class + /// with the specified target, caption and message. + /// The name of the target for the credentials, typically a server name. + /// The caption of the dialog (null will cause a system default title to be used). + /// The message of the dialog (null will cause a system default message to be used). + public CredentialsDialog(string target, string caption, string message) : this(target, caption, message, null) + { + } - /// Initializes a new instance of the class - /// with the specified target, caption, message and banner. - /// The name of the target for the credentials, typically a server name. - /// The caption of the dialog (null will cause a system default title to be used). - /// The message of the dialog (null will cause a system default message to be used). - /// The image to display on the dialog (null will cause a system default image to be used). - public CredentialsDialog(string target, string caption, string message, Image banner) { - Target = target; - Caption = caption; - Message = message; - Banner = banner; - } + /// Initializes a new instance of the class + /// with the specified target, caption, message and banner. + /// The name of the target for the credentials, typically a server name. + /// The caption of the dialog (null will cause a system default title to be used). + /// The message of the dialog (null will cause a system default message to be used). + /// The image to display on the dialog (null will cause a system default image to be used). + public CredentialsDialog(string target, string caption, string message, Image banner) + { + Target = target; + Caption = caption; + Message = message; + Banner = banner; + } - /// - /// Gets or sets if the dialog will be shown even if the credentials - /// can be returned from an existing credential in the credential manager. - /// - public bool AlwaysDisplay { get; set; } + /// + /// Gets or sets if the dialog will be shown even if the credentials + /// can be returned from an existing credential in the credential manager. + /// + public bool AlwaysDisplay { get; set; } - /// Gets or sets if the dialog is populated with name/password only. - public bool ExcludeCertificates { get; set; } = true; + /// Gets or sets if the dialog is populated with name/password only. + public bool ExcludeCertificates { get; set; } = true; - /// Gets or sets if the credentials are to be persisted in the credential manager. - public bool Persist { get; set; } = true; + /// Gets or sets if the credentials are to be persisted in the credential manager. + public bool Persist { get; set; } = true; - /// Gets or sets if the incorrect password balloontip needs to be shown. Introduced AFTER Windows XP - public bool IncorrectPassword { get; set; } + /// Gets or sets if the incorrect password balloontip needs to be shown. Introduced AFTER Windows XP + public bool IncorrectPassword { get; set; } - /// Gets or sets if the name is read-only. - public bool KeepName { get; set; } + /// Gets or sets if the name is read-only. + public bool KeepName { get; set; } - private string _name = string.Empty; - /// Gets or sets the name for the credentials. - public string Name { - get { - return _name; - } - set { - if (value?.Length > CredUi.MAX_USERNAME_LENGTH) { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The name has a maximum length of {0} characters.", - CredUi.MAX_USERNAME_LENGTH); - throw new ArgumentException(message, nameof(Name)); - } - _name = value; - } - } + private string _name = string.Empty; - private string _password = string.Empty; - /// Gets or sets the password for the credentials. - public string Password { - get { - return _password; - } - set { - if (value?.Length > CredUi.MAX_PASSWORD_LENGTH) { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The password has a maximum length of {0} characters.", - CredUi.MAX_PASSWORD_LENGTH); - throw new ArgumentException(message, nameof(Password)); - } - _password = value; - } - } + /// Gets or sets the name for the credentials. + public string Name + { + get { return _name; } + set + { + if (value?.Length > CredUi.MAX_USERNAME_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The name has a maximum length of {0} characters.", + CredUi.MAX_USERNAME_LENGTH); + throw new ArgumentException(message, nameof(Name)); + } - /// Gets or sets if the save checkbox status. - public bool SaveChecked { get; set; } + _name = value; + } + } - /// Gets or sets if the save checkbox is displayed. - /// This value only has effect if Persist is true. - public bool SaveDisplayed { get; set; } = true; + private string _password = string.Empty; - private string _target = string.Empty; - /// Gets or sets the name of the target for the credentials, typically a server name. - public string Target { - get { - return _target; - } - set { - if (value == null) { - throw new ArgumentException("The target cannot be a null value.", nameof(Target)); - } - if (value.Length > CredUi.MAX_GENERIC_TARGET_LENGTH) { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The target has a maximum length of {0} characters.", - CredUi.MAX_GENERIC_TARGET_LENGTH); - throw new ArgumentException(message, nameof(Target)); - } - _target = value; - } - } + /// Gets or sets the password for the credentials. + public string Password + { + get { return _password; } + set + { + if (value?.Length > CredUi.MAX_PASSWORD_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The password has a maximum length of {0} characters.", + CredUi.MAX_PASSWORD_LENGTH); + throw new ArgumentException(message, nameof(Password)); + } - private string _caption = string.Empty; - /// Gets or sets the caption of the dialog. - /// A null value will cause a system default caption to be used. - public string Caption { - get { - return _caption; - } - set { - if (value?.Length > CredUi.MAX_CAPTION_LENGTH) { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The caption has a maximum length of {0} characters.", - CredUi.MAX_CAPTION_LENGTH); - throw new ArgumentException(message, nameof(Caption)); - } - _caption = value; - } - } + _password = value; + } + } - private string _message = string.Empty; - /// Gets or sets the message of the dialog. - /// A null value will cause a system default message to be used. - public string Message { - get { - return _message; - } - set { - if (value?.Length > CredUi.MAX_MESSAGE_LENGTH) { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The message has a maximum length of {0} characters.", - CredUi.MAX_MESSAGE_LENGTH); - throw new ArgumentException(message, nameof(Message)); - } - _message = value; - } - } + /// Gets or sets if the save checkbox status. + public bool SaveChecked { get; set; } - private Image _banner; - /// Gets or sets the image to display on the dialog. - /// A null value will cause a system default image to be used. - public Image Banner { - get { - return _banner; - } - set { - if (value != null) { - if (value.Width != ValidBannerWidth) { - throw new ArgumentException("The banner image width must be 320 pixels.", nameof(Banner)); - } - if (value.Height != ValidBannerHeight) { - throw new ArgumentException("The banner image height must be 60 pixels.", nameof(Banner)); - } - } - _banner = value; - } - } + /// Gets or sets if the save checkbox is displayed. + /// This value only has effect if Persist is true. + public bool SaveDisplayed { get; set; } = true; + + private string _target = string.Empty; + + /// Gets or sets the name of the target for the credentials, typically a server name. + public string Target + { + get { return _target; } + set + { + if (value == null) + { + throw new ArgumentException("The target cannot be a null value.", nameof(Target)); + } + + if (value.Length > CredUi.MAX_GENERIC_TARGET_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The target has a maximum length of {0} characters.", + CredUi.MAX_GENERIC_TARGET_LENGTH); + throw new ArgumentException(message, nameof(Target)); + } + + _target = value; + } + } + + private string _caption = string.Empty; + + /// Gets or sets the caption of the dialog. + /// A null value will cause a system default caption to be used. + public string Caption + { + get { return _caption; } + set + { + if (value?.Length > CredUi.MAX_CAPTION_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The caption has a maximum length of {0} characters.", + CredUi.MAX_CAPTION_LENGTH); + throw new ArgumentException(message, nameof(Caption)); + } + + _caption = value; + } + } + + private string _message = string.Empty; + + /// Gets or sets the message of the dialog. + /// A null value will cause a system default message to be used. + public string Message + { + get { return _message; } + set + { + if (value?.Length > CredUi.MAX_MESSAGE_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The message has a maximum length of {0} characters.", + CredUi.MAX_MESSAGE_LENGTH); + throw new ArgumentException(message, nameof(Message)); + } + + _message = value; + } + } + + private Image _banner; + + /// Gets or sets the image to display on the dialog. + /// A null value will cause a system default image to be used. + public Image Banner + { + get { return _banner; } + set + { + if (value != null) + { + if (value.Width != ValidBannerWidth) + { + throw new ArgumentException("The banner image width must be 320 pixels.", nameof(Banner)); + } + + if (value.Height != ValidBannerHeight) + { + throw new ArgumentException("The banner image height must be 60 pixels.", nameof(Banner)); + } + } + + _banner = value; + } + } /// Shows the credentials dialog with the specified name. - /// The name for the credentials. - /// Returns a DialogResult indicating the user action. - public DialogResult Show(string name) { - return Show(null, name, Password, SaveChecked); - } + /// The name for the credentials. + /// Returns a DialogResult indicating the user action. + public DialogResult Show(string name) + { + return Show(null, name, Password, SaveChecked); + } /// Shows the credentials dialog with the specified owner, name, password and save checkbox status. - /// The System.Windows.Forms.IWin32Window the dialog will display in front of. - /// The name for the credentials. - /// The password for the credentials. - /// True if the save checkbox is checked. - /// Returns a DialogResult indicating the user action. - public DialogResult Show(IWin32Window owner, string name, string password, bool saveChecked) { - if ((Environment.OSVersion.Version.Major < 5) || ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor < 1))) { - throw new ApplicationException("The Credential Management API requires Windows XP / Windows Server 2003 or later."); - } - Name = name; - Password = password; - SaveChecked = saveChecked; - - return ShowDialog(owner); - } + /// The System.Windows.Forms.IWin32Window the dialog will display in front of. + /// The name for the credentials. + /// The password for the credentials. + /// True if the save checkbox is checked. + /// Returns a DialogResult indicating the user action. + public DialogResult Show(IWin32Window owner, string name, string password, bool saveChecked) + { + if ((Environment.OSVersion.Version.Major < 5) || ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor < 1))) + { + throw new ApplicationException("The Credential Management API requires Windows XP / Windows Server 2003 or later."); + } - /// Confirmation action to be applied. - /// True if the credentials should be persisted. - public void Confirm(bool value) - { - var confirmResult = CredUi.CredUIConfirmCredentials(Target, value); - switch (confirmResult) { - case CredUi.ReturnCodes.NO_ERROR: - break; - case CredUi.ReturnCodes.ERROR_INVALID_PARAMETER: - // for some reason, this is encountered when credentials are overwritten - break; - default: - throw new ApplicationException($"Credential confirmation failed: {confirmResult}"); - } - } + Name = name; + Password = password; + SaveChecked = saveChecked; - /// Returns a DialogResult indicating the user action. - /// The System.Windows.Forms.IWin32Window the dialog will display in front of. - /// - /// Sets the name, password and SaveChecked accessors to the state of the dialog as it was dismissed by the user. - /// - private DialogResult ShowDialog(IWin32Window owner) { - // set the api call parameters - StringBuilder name = new StringBuilder(CredUi.MAX_USERNAME_LENGTH); - name.Append(Name); + return ShowDialog(owner); + } - StringBuilder password = new StringBuilder(CredUi.MAX_PASSWORD_LENGTH); - password.Append(Password); + /// Confirmation action to be applied. + /// True if the credentials should be persisted. + public void Confirm(bool value) + { + var confirmResult = CredUi.CredUIConfirmCredentials(Target, value); + switch (confirmResult) + { + case CredUi.ReturnCodes.NO_ERROR: + break; + case CredUi.ReturnCodes.ERROR_INVALID_PARAMETER: + // for some reason, this is encountered when credentials are overwritten + break; + default: + throw new ApplicationException($"Credential confirmation failed: {confirmResult}"); + } + } - int saveChecked = Convert.ToInt32(SaveChecked); + /// Returns a DialogResult indicating the user action. + /// The System.Windows.Forms.IWin32Window the dialog will display in front of. + /// + /// Sets the name, password and SaveChecked accessors to the state of the dialog as it was dismissed by the user. + /// + private DialogResult ShowDialog(IWin32Window owner) + { + // set the api call parameters + StringBuilder name = new StringBuilder(CredUi.MAX_USERNAME_LENGTH); + name.Append(Name); - CredUi.INFO info = GetInfo(owner); - CredUi.CredFlags credFlags = GetFlags(); + StringBuilder password = new StringBuilder(CredUi.MAX_PASSWORD_LENGTH); + password.Append(Password); - // make the api call - CredUi.ReturnCodes code = CredUi.CredUIPromptForCredentials( - ref info, - Target, - IntPtr.Zero, 0, - name, CredUi.MAX_USERNAME_LENGTH, - password, CredUi.MAX_PASSWORD_LENGTH, - ref saveChecked, - credFlags - ); + int saveChecked = Convert.ToInt32(SaveChecked); - // clean up resources - if (Banner != null) { - DeleteObject(info.hbmBanner); - } + CredUi.INFO info = GetInfo(owner); + CredUi.CredFlags credFlags = GetFlags(); - // set the accessors from the api call parameters - Name = name.ToString(); - Password = password.ToString(); - SaveChecked = Convert.ToBoolean(saveChecked); + // make the api call + CredUi.ReturnCodes code = CredUi.CredUIPromptForCredentials( + ref info, + Target, + IntPtr.Zero, 0, + name, CredUi.MAX_USERNAME_LENGTH, + password, CredUi.MAX_PASSWORD_LENGTH, + ref saveChecked, + credFlags + ); - return GetDialogResult(code); - } + // clean up resources + if (Banner != null) + { + DeleteObject(info.hbmBanner); + } - /// Returns the info structure for dialog display settings. - /// The System.Windows.Forms.IWin32Window the dialog will display in front of. - private CredUi.INFO GetInfo(IWin32Window owner) { - CredUi.INFO info = new CredUi.INFO(); - if (owner != null) info.hWndParent = owner.Handle; - info.pszCaptionText = Caption; - info.pszMessageText = Message; - if (Banner != null) { - info.hbmBanner = new Bitmap(Banner, ValidBannerWidth, ValidBannerHeight).GetHbitmap(); - } - info.cbSize = Marshal.SizeOf(info); - return info; - } + // set the accessors from the api call parameters + Name = name.ToString(); + Password = password.ToString(); + SaveChecked = Convert.ToBoolean(saveChecked); - /// Returns the flags for dialog display options. - private CredUi.CredFlags GetFlags() { - CredUi.CredFlags credFlags = CredUi.CredFlags.GENERIC_CREDENTIALS; + return GetDialogResult(code); + } - if (IncorrectPassword) { - credFlags |= CredUi.CredFlags.INCORRECT_PASSWORD; - } + /// Returns the info structure for dialog display settings. + /// The System.Windows.Forms.IWin32Window the dialog will display in front of. + private CredUi.INFO GetInfo(IWin32Window owner) + { + CredUi.INFO info = new CredUi.INFO(); + if (owner != null) info.hWndParent = owner.Handle; + info.pszCaptionText = Caption; + info.pszMessageText = Message; + if (Banner != null) + { + info.hbmBanner = new Bitmap(Banner, ValidBannerWidth, ValidBannerHeight).GetHbitmap(); + } - if (AlwaysDisplay) { - credFlags |= CredUi.CredFlags.ALWAYS_SHOW_UI; - } + info.cbSize = Marshal.SizeOf(info); + return info; + } - if (ExcludeCertificates) { - credFlags |= CredUi.CredFlags.EXCLUDE_CERTIFICATES; - } + /// Returns the flags for dialog display options. + private CredUi.CredFlags GetFlags() + { + CredUi.CredFlags credFlags = CredUi.CredFlags.GENERIC_CREDENTIALS; - if (Persist) { - credFlags |= CredUi.CredFlags.EXPECT_CONFIRMATION; - if (SaveDisplayed) { - credFlags |= CredUi.CredFlags.SHOW_SAVE_CHECK_BOX; - } else { - credFlags |= CredUi.CredFlags.PERSIST; - } - } else { - credFlags |= CredUi.CredFlags.DO_NOT_PERSIST; - } + if (IncorrectPassword) + { + credFlags |= CredUi.CredFlags.INCORRECT_PASSWORD; + } - if (KeepName) { - credFlags |= CredUi.CredFlags.KEEP_USERNAME; - } + if (AlwaysDisplay) + { + credFlags |= CredUi.CredFlags.ALWAYS_SHOW_UI; + } - return credFlags; - } - - /// Returns a DialogResult from the specified code. - /// The credential return code. - private DialogResult GetDialogResult(CredUi.ReturnCodes code) => + if (ExcludeCertificates) + { + credFlags |= CredUi.CredFlags.EXCLUDE_CERTIFICATES; + } + + if (Persist) + { + credFlags |= CredUi.CredFlags.EXPECT_CONFIRMATION; + if (SaveDisplayed) + { + credFlags |= CredUi.CredFlags.SHOW_SAVE_CHECK_BOX; + } + else + { + credFlags |= CredUi.CredFlags.PERSIST; + } + } + else + { + credFlags |= CredUi.CredFlags.DO_NOT_PERSIST; + } + + if (KeepName) + { + credFlags |= CredUi.CredFlags.KEEP_USERNAME; + } + + return credFlags; + } + + /// Returns a DialogResult from the specified code. + /// The credential return code. + private DialogResult GetDialogResult(CredUi.ReturnCodes code) => code switch { CredUi.ReturnCodes.NO_ERROR => DialogResult.OK, @@ -383,7 +434,7 @@ namespace GreenshotPlugin.Core { "No such logon session."), CredUi.ReturnCodes.ERROR_NOT_FOUND => throw new ApplicationException("Not found."), CredUi.ReturnCodes.ERROR_INVALID_ACCOUNT_NAME => - throw new ApplicationException("Invalid account name."), + throw new ApplicationException("Invalid account name."), CredUi.ReturnCodes.ERROR_INSUFFICIENT_BUFFER => throw new ApplicationException("Insufficient buffer."), CredUi.ReturnCodes.ERROR_INVALID_PARAMETER => throw new ApplicationException("Invalid parameter."), CredUi.ReturnCodes.ERROR_INVALID_FLAGS => throw new ApplicationException("Invalid flags."), @@ -391,79 +442,84 @@ namespace GreenshotPlugin.Core { }; } - internal static class CredUi { - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/authentication_constants.asp - public const int MAX_MESSAGE_LENGTH = 100; - public const int MAX_CAPTION_LENGTH = 100; - public const int MAX_GENERIC_TARGET_LENGTH = 100; - public const int MAX_USERNAME_LENGTH = 100; - public const int MAX_PASSWORD_LENGTH = 100; + internal static class CredUi + { + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/authentication_constants.asp + public const int MAX_MESSAGE_LENGTH = 100; - /// - /// http://www.pinvoke.net/default.aspx/Enums.CREDUI_FLAGS - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/dpapiusercredentials.asp - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp - /// - [Flags] - public enum CredFlags { - INCORRECT_PASSWORD = 0x1, - DO_NOT_PERSIST = 0x2, - EXCLUDE_CERTIFICATES = 0x8, - SHOW_SAVE_CHECK_BOX = 0x40, - ALWAYS_SHOW_UI = 0x80, - PERSIST = 0x1000, - EXPECT_CONFIRMATION = 0x20000, - GENERIC_CREDENTIALS = 0x40000, - KEEP_USERNAME = 0x100000, - } + public const int MAX_CAPTION_LENGTH = 100; + public const int MAX_GENERIC_TARGET_LENGTH = 100; + public const int MAX_USERNAME_LENGTH = 100; + public const int MAX_PASSWORD_LENGTH = 100; - /// http://www.pinvoke.net/default.aspx/Enums.CredUIReturnCodes - public enum ReturnCodes { - NO_ERROR = 0, - ERROR_INVALID_PARAMETER = 87, - ERROR_INSUFFICIENT_BUFFER = 122, - ERROR_INVALID_FLAGS = 1004, - ERROR_NOT_FOUND = 1168, - ERROR_CANCELLED = 1223, - ERROR_NO_SUCH_LOGON_SESSION = 1312, - ERROR_INVALID_ACCOUNT_NAME = 1315 - } + /// + /// http://www.pinvoke.net/default.aspx/Enums.CREDUI_FLAGS + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/dpapiusercredentials.asp + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp + /// + [Flags] + public enum CredFlags + { + INCORRECT_PASSWORD = 0x1, + DO_NOT_PERSIST = 0x2, + EXCLUDE_CERTIFICATES = 0x8, + SHOW_SAVE_CHECK_BOX = 0x40, + ALWAYS_SHOW_UI = 0x80, + PERSIST = 0x1000, + EXPECT_CONFIRMATION = 0x20000, + GENERIC_CREDENTIALS = 0x40000, + KEEP_USERNAME = 0x100000, + } - /// - /// http://www.pinvoke.net/default.aspx/Structures.CREDUI_INFO - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/credui_info.asp - /// - public struct INFO { - public int cbSize; - public IntPtr hWndParent; - [MarshalAs(UnmanagedType.LPWStr)] public string pszMessageText; - [MarshalAs(UnmanagedType.LPWStr)] public string pszCaptionText; - public IntPtr hbmBanner; - } + /// http://www.pinvoke.net/default.aspx/Enums.CredUIReturnCodes + public enum ReturnCodes + { + NO_ERROR = 0, + ERROR_INVALID_PARAMETER = 87, + ERROR_INSUFFICIENT_BUFFER = 122, + ERROR_INVALID_FLAGS = 1004, + ERROR_NOT_FOUND = 1168, + ERROR_CANCELLED = 1223, + ERROR_NO_SUCH_LOGON_SESSION = 1312, + ERROR_INVALID_ACCOUNT_NAME = 1315 + } - /// - /// http://www.pinvoke.net/default.aspx/credui.CredUIPromptForCredentialsW - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp - /// - [DllImport("credui", CharSet = CharSet.Unicode)] - public static extern ReturnCodes CredUIPromptForCredentials ( - ref INFO creditUR, - string targetName, - IntPtr reserved1, - int iError, - StringBuilder userName, - int maxUserName, - StringBuilder password, - int maxPassword, - ref int iSave, - CredFlags credFlags - ); + /// + /// http://www.pinvoke.net/default.aspx/Structures.CREDUI_INFO + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/credui_info.asp + /// + public struct INFO + { + public int cbSize; + public IntPtr hWndParent; + [MarshalAs(UnmanagedType.LPWStr)] public string pszMessageText; + [MarshalAs(UnmanagedType.LPWStr)] public string pszCaptionText; + public IntPtr hbmBanner; + } - /// - /// http://www.pinvoke.net/default.aspx/credui.CredUIConfirmCredentials - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduiconfirmcredentials.asp - /// - [DllImport("credui.dll", CharSet=CharSet.Unicode)] - public static extern ReturnCodes CredUIConfirmCredentials(string targetName, [MarshalAs(UnmanagedType.Bool)] bool confirm); - } + /// + /// http://www.pinvoke.net/default.aspx/credui.CredUIPromptForCredentialsW + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp + /// + [DllImport("credui", CharSet = CharSet.Unicode)] + public static extern ReturnCodes CredUIPromptForCredentials( + ref INFO creditUR, + string targetName, + IntPtr reserved1, + int iError, + StringBuilder userName, + int maxUserName, + StringBuilder password, + int maxPassword, + ref int iSave, + CredFlags credFlags + ); + + /// + /// http://www.pinvoke.net/default.aspx/credui.CredUIConfirmCredentials + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduiconfirmcredentials.asp + /// + [DllImport("credui.dll", CharSet = CharSet.Unicode)] + public static extern ReturnCodes CredUIConfirmCredentials(string targetName, [MarshalAs(UnmanagedType.Bool)] bool confirm); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/DisplayKeyAttribute.cs b/src/GreenshotPlugin/Core/DisplayKeyAttribute.cs index 8f1b81b68..1719e0092 100644 --- a/src/GreenshotPlugin/Core/DisplayKeyAttribute.cs +++ b/src/GreenshotPlugin/Core/DisplayKeyAttribute.cs @@ -18,18 +18,23 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; -namespace GreenshotPlugin.Core { - [AttributeUsage(AttributeTargets.Field)] - public sealed class DisplayKeyAttribute : Attribute { - public string Value { get; } +namespace GreenshotPlugin.Core +{ + [AttributeUsage(AttributeTargets.Field)] + public sealed class DisplayKeyAttribute : Attribute + { + public string Value { get; } - public DisplayKeyAttribute(string v) { - Value = v; - } - - public DisplayKeyAttribute() { - } - } -} + public DisplayKeyAttribute(string v) + { + Value = v; + } + + public DisplayKeyAttribute() + { + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/DpiHelper.cs b/src/GreenshotPlugin/Core/DpiHelper.cs index 7f98f69a6..ec9ae8f41 100644 --- a/src/GreenshotPlugin/Core/DpiHelper.cs +++ b/src/GreenshotPlugin/Core/DpiHelper.cs @@ -56,7 +56,8 @@ namespace GreenshotPlugin.Core { dpi = Dpi; } - return (float)dpi / DefaultScreenDpi; + + return (float) dpi / DefaultScreenDpi; } /// @@ -73,6 +74,7 @@ namespace GreenshotPlugin.Core { dpiScaleFactor = scaleModifier(dpiScaleFactor); } + return dpiScaleFactor * someNumber; } @@ -90,7 +92,8 @@ namespace GreenshotPlugin.Core { dpiScaleFactor = scaleModifier(dpiScaleFactor); } - return new Size((int)(dpiScaleFactor * size.Width), (int)(dpiScaleFactor * size.Height)); + + return new Size((int) (dpiScaleFactor * size.Width), (int) (dpiScaleFactor * size.Height)); } /// @@ -111,13 +114,14 @@ namespace GreenshotPlugin.Core /// uint public static uint GetDpi(POINT location) { - RECT rect = new RECT(location.X, location.Y, 1,1); + RECT rect = new RECT(location.X, location.Y, 1, 1); IntPtr hMonitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONEAREST); var result = GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY); if (result.Succeeded()) { return dpiX; } + return DefaultScreenDpi; } @@ -158,7 +162,8 @@ namespace GreenshotPlugin.Core { return DefaultScreenDpi; } - return (uint)GDI32.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX); + + return (uint) GDI32.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX); } /// @@ -191,4 +196,4 @@ namespace GreenshotPlugin.Core [DllImport("User32.dll")] private static extern uint GetDpiForSystem(); } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/EffectConverter.cs b/src/GreenshotPlugin/Core/EffectConverter.cs index f72e271dc..1b69dc3ed 100644 --- a/src/GreenshotPlugin/Core/EffectConverter.cs +++ b/src/GreenshotPlugin/Core/EffectConverter.cs @@ -7,164 +7,227 @@ using GreenshotPlugin.Effects; namespace GreenshotPlugin.Core { - public class EffectConverter : TypeConverter { - // Fix to prevent BUG-1753 - private readonly NumberFormatInfo _numberFormatInfo = new NumberFormatInfo(); + public class EffectConverter : TypeConverter + { + // Fix to prevent BUG-1753 + private readonly NumberFormatInfo _numberFormatInfo = new NumberFormatInfo(); - public EffectConverter() - { - _numberFormatInfo.NumberDecimalSeparator = "."; - _numberFormatInfo.NumberGroupSeparator = ","; - } + public EffectConverter() + { + _numberFormatInfo.NumberDecimalSeparator = "."; + _numberFormatInfo.NumberGroupSeparator = ","; + } - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - if (sourceType == typeof(string)) { - return true; - } - return base.CanConvertFrom(context, sourceType); - } + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { - if (destinationType == typeof(string)) { - return true; - } - if (destinationType == typeof(DropShadowEffect)) { - return true; - } - if (destinationType == typeof(TornEdgeEffect)) { - return true; - } - return base.CanConvertTo(context, destinationType); - } + return base.CanConvertFrom(context, sourceType); + } - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { - // to string - if (destinationType == typeof(string)) { - StringBuilder sb = new StringBuilder(); - if (value.GetType() == typeof(DropShadowEffect)) { - DropShadowEffect effect = value as DropShadowEffect; - RetrieveDropShadowEffectValues(effect, sb); - return sb.ToString(); - } - if (value.GetType() == typeof(TornEdgeEffect)) { - TornEdgeEffect effect = value as TornEdgeEffect; - RetrieveDropShadowEffectValues(effect, sb); - sb.Append("|"); - RetrieveTornEdgeEffectValues(effect, sb); - return sb.ToString(); - } - } - // from string - if (value is string) { - string settings = value as string; - if (destinationType == typeof(DropShadowEffect)) { - DropShadowEffect effect = new DropShadowEffect(); - ApplyDropShadowEffectValues(settings, effect); - return effect; - } - if (destinationType == typeof(TornEdgeEffect)) { - TornEdgeEffect effect = new TornEdgeEffect(); - ApplyDropShadowEffectValues(settings, effect); - ApplyTornEdgeEffectValues(settings, effect); - return effect; - } - } - return base.ConvertTo(context, culture, value, destinationType); - } + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + { + return true; + } - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - if (value is string settings) { - if (settings.Contains("ToothHeight")) { - return ConvertTo(context, culture, settings, typeof(TornEdgeEffect)); - } - return ConvertTo(context, culture, settings, typeof(DropShadowEffect)); - } - return base.ConvertFrom(context, culture, value); - } + if (destinationType == typeof(DropShadowEffect)) + { + return true; + } - private void ApplyDropShadowEffectValues(string valuesString, DropShadowEffect effect) { - string[] values = valuesString.Split('|'); - foreach(string nameValuePair in values) { - string[] pair = nameValuePair.Split(':'); - switch (pair[0]) { - case "Darkness" : + if (destinationType == typeof(TornEdgeEffect)) + { + return true; + } + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + // to string + if (destinationType == typeof(string)) + { + StringBuilder sb = new StringBuilder(); + if (value.GetType() == typeof(DropShadowEffect)) + { + DropShadowEffect effect = value as DropShadowEffect; + RetrieveDropShadowEffectValues(effect, sb); + return sb.ToString(); + } + + if (value.GetType() == typeof(TornEdgeEffect)) + { + TornEdgeEffect effect = value as TornEdgeEffect; + RetrieveDropShadowEffectValues(effect, sb); + sb.Append("|"); + RetrieveTornEdgeEffectValues(effect, sb); + return sb.ToString(); + } + } + + // from string + if (value is string) + { + string settings = value as string; + if (destinationType == typeof(DropShadowEffect)) + { + DropShadowEffect effect = new DropShadowEffect(); + ApplyDropShadowEffectValues(settings, effect); + return effect; + } + + if (destinationType == typeof(TornEdgeEffect)) + { + TornEdgeEffect effect = new TornEdgeEffect(); + ApplyDropShadowEffectValues(settings, effect); + ApplyTornEdgeEffectValues(settings, effect); + return effect; + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string settings) + { + if (settings.Contains("ToothHeight")) + { + return ConvertTo(context, culture, settings, typeof(TornEdgeEffect)); + } + + return ConvertTo(context, culture, settings, typeof(DropShadowEffect)); + } + + return base.ConvertFrom(context, culture, value); + } + + private void ApplyDropShadowEffectValues(string valuesString, DropShadowEffect effect) + { + string[] values = valuesString.Split('|'); + foreach (string nameValuePair in values) + { + string[] pair = nameValuePair.Split(':'); + switch (pair[0]) + { + case "Darkness": // Fix to prevent BUG-1753 - if (pair[1] != null && float.TryParse(pair[1], NumberStyles.Float, _numberFormatInfo, out var darkness)) { - if (darkness <= 1.0) { - effect.Darkness = darkness; - } - } - break; - case "ShadowSize": - if (int.TryParse(pair[1], out var shadowSize)) { - effect.ShadowSize = shadowSize; - } - break; - case "ShadowOffset": - Point shadowOffset = new Point(); + if (pair[1] != null && float.TryParse(pair[1], NumberStyles.Float, _numberFormatInfo, out var darkness)) + { + if (darkness <= 1.0) + { + effect.Darkness = darkness; + } + } + + break; + case "ShadowSize": + if (int.TryParse(pair[1], out var shadowSize)) + { + effect.ShadowSize = shadowSize; + } + + break; + case "ShadowOffset": + Point shadowOffset = new Point(); string[] coordinates = pair[1].Split(','); - if (int.TryParse(coordinates[0], out var shadowOffsetX)) { - shadowOffset.X = shadowOffsetX; - } - if (int.TryParse(coordinates[1], out var shadowOffsetY)) { - shadowOffset.Y = shadowOffsetY; - } - effect.ShadowOffset = shadowOffset; - break; - } - } - } + if (int.TryParse(coordinates[0], out var shadowOffsetX)) + { + shadowOffset.X = shadowOffsetX; + } - private void ApplyTornEdgeEffectValues(string valuesString, TornEdgeEffect effect) { - string[] values = valuesString.Split('|'); - foreach (string nameValuePair in values) { - string[] pair = nameValuePair.Split(':'); - switch (pair[0]) { - case "GenerateShadow": - if (bool.TryParse(pair[1], out var generateShadow)) { - effect.GenerateShadow = generateShadow; - } - break; - case "ToothHeight": - if (int.TryParse(pair[1], out var toothHeight)) { - effect.ToothHeight = toothHeight; - } - break; - case "HorizontalToothRange": - if (int.TryParse(pair[1], out var horizontalToothRange)) { - effect.HorizontalToothRange = horizontalToothRange; - } - break; - case "VerticalToothRange": - if (int.TryParse(pair[1], out var verticalToothRange)) { - effect.VerticalToothRange = verticalToothRange; - } - break; - case "Edges": - string[] edges = pair[1].Split(','); - if (bool.TryParse(edges[0], out var edge)) { - effect.Edges[0] = edge; - } - if (bool.TryParse(edges[1], out edge)) { - effect.Edges[1] = edge; - } - if (bool.TryParse(edges[2], out edge)) { - effect.Edges[2] = edge; - } - if (bool.TryParse(edges[3], out edge)) { - effect.Edges[3] = edge; - } - break; - } - } - } + if (int.TryParse(coordinates[1], out var shadowOffsetY)) + { + shadowOffset.Y = shadowOffsetY; + } - private void RetrieveDropShadowEffectValues(DropShadowEffect effect, StringBuilder sb) { - // Fix to prevent BUG-1753 is to use the numberFormatInfo - sb.AppendFormat("Darkness:{0}|ShadowSize:{1}|ShadowOffset:{2},{3}", effect.Darkness.ToString("F2", _numberFormatInfo), effect.ShadowSize, effect.ShadowOffset.X, effect.ShadowOffset.Y); - } - private void RetrieveTornEdgeEffectValues(TornEdgeEffect effect, StringBuilder sb) { - sb.AppendFormat("GenerateShadow:{0}|ToothHeight:{1}|HorizontalToothRange:{2}|VerticalToothRange:{3}|Edges:{4},{5},{6},{7}", effect.GenerateShadow, effect.ToothHeight, effect.HorizontalToothRange, effect.VerticalToothRange, effect.Edges[0], effect.Edges[1], effect.Edges[2], effect.Edges[3]); - } - } + effect.ShadowOffset = shadowOffset; + break; + } + } + } + + private void ApplyTornEdgeEffectValues(string valuesString, TornEdgeEffect effect) + { + string[] values = valuesString.Split('|'); + foreach (string nameValuePair in values) + { + string[] pair = nameValuePair.Split(':'); + switch (pair[0]) + { + case "GenerateShadow": + if (bool.TryParse(pair[1], out var generateShadow)) + { + effect.GenerateShadow = generateShadow; + } + + break; + case "ToothHeight": + if (int.TryParse(pair[1], out var toothHeight)) + { + effect.ToothHeight = toothHeight; + } + + break; + case "HorizontalToothRange": + if (int.TryParse(pair[1], out var horizontalToothRange)) + { + effect.HorizontalToothRange = horizontalToothRange; + } + + break; + case "VerticalToothRange": + if (int.TryParse(pair[1], out var verticalToothRange)) + { + effect.VerticalToothRange = verticalToothRange; + } + + break; + case "Edges": + string[] edges = pair[1].Split(','); + if (bool.TryParse(edges[0], out var edge)) + { + effect.Edges[0] = edge; + } + + if (bool.TryParse(edges[1], out edge)) + { + effect.Edges[1] = edge; + } + + if (bool.TryParse(edges[2], out edge)) + { + effect.Edges[2] = edge; + } + + if (bool.TryParse(edges[3], out edge)) + { + effect.Edges[3] = edge; + } + + break; + } + } + } + + private void RetrieveDropShadowEffectValues(DropShadowEffect effect, StringBuilder sb) + { + // Fix to prevent BUG-1753 is to use the numberFormatInfo + sb.AppendFormat("Darkness:{0}|ShadowSize:{1}|ShadowOffset:{2},{3}", effect.Darkness.ToString("F2", _numberFormatInfo), effect.ShadowSize, effect.ShadowOffset.X, + effect.ShadowOffset.Y); + } + + private void RetrieveTornEdgeEffectValues(TornEdgeEffect effect, StringBuilder sb) + { + sb.AppendFormat("GenerateShadow:{0}|ToothHeight:{1}|HorizontalToothRange:{2}|VerticalToothRange:{3}|Edges:{4},{5},{6},{7}", effect.GenerateShadow, effect.ToothHeight, + effect.HorizontalToothRange, effect.VerticalToothRange, effect.Edges[0], effect.Edges[1], effect.Edges[2], effect.Edges[3]); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Enums/HResult.cs b/src/GreenshotPlugin/Core/Enums/HResult.cs index a1d2036d7..96e867c6c 100644 --- a/src/GreenshotPlugin/Core/Enums/HResult.cs +++ b/src/GreenshotPlugin/Core/Enums/HResult.cs @@ -30,4 +30,4 @@ namespace GreenshotPlugin.Core.Enums { S_OK = 0, } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Enums/MonitorDpiType.cs b/src/GreenshotPlugin/Core/Enums/MonitorDpiType.cs index ebe0033b4..c1db8ce18 100644 --- a/src/GreenshotPlugin/Core/Enums/MonitorDpiType.cs +++ b/src/GreenshotPlugin/Core/Enums/MonitorDpiType.cs @@ -1,5 +1,6 @@ // Copyright (c) Dapplo and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System; namespace GreenshotPlugin.Core.Enums diff --git a/src/GreenshotPlugin/Core/Enums/MonitorFrom.cs b/src/GreenshotPlugin/Core/Enums/MonitorFrom.cs index 57e57a390..40f25961b 100644 --- a/src/GreenshotPlugin/Core/Enums/MonitorFrom.cs +++ b/src/GreenshotPlugin/Core/Enums/MonitorFrom.cs @@ -1,5 +1,6 @@ // Copyright (c) Dapplo and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System; namespace GreenshotPlugin.Core.Enums diff --git a/src/GreenshotPlugin/Core/EnvironmentInfo.cs b/src/GreenshotPlugin/Core/EnvironmentInfo.cs index 01eb11772..27a3eeda1 100644 --- a/src/GreenshotPlugin/Core/EnvironmentInfo.cs +++ b/src/GreenshotPlugin/Core/EnvironmentInfo.cs @@ -29,31 +29,32 @@ using Microsoft.Win32; namespace GreenshotPlugin.Core { - /// - /// Description of EnvironmentInfo. - /// - public static class EnvironmentInfo - { - private static bool? _isWindows; + /// + /// Description of EnvironmentInfo. + /// + public static class EnvironmentInfo + { + private static bool? _isWindows; - public static bool IsWindows - { - get - { - if (_isWindows.HasValue) - { - return _isWindows.Value; - } - _isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win"); - return _isWindows.Value; - } - } + public static bool IsWindows + { + get + { + if (_isWindows.HasValue) + { + return _isWindows.Value; + } - public static bool IsNet45OrNewer() - { - // Class "ReflectionContext" exists from .NET 4.5 onwards. - return Type.GetType("System.Reflection.ReflectionContext", false) != null; - } + _isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win"); + return _isWindows.Value; + } + } + + public static bool IsNet45OrNewer() + { + // Class "ReflectionContext" exists from .NET 4.5 onwards. + return Type.GetType("System.Reflection.ReflectionContext", false) != null; + } public static string GetGreenshotVersion(bool shortVersion = false) { @@ -66,8 +67,8 @@ namespace GreenshotPlugin.Core var assemblyFileVersionAttribute = executingAssembly.GetCustomAttribute(); if (!string.IsNullOrEmpty(assemblyFileVersionAttribute?.Version)) { - var assemblyFileVersion = new Version(assemblyFileVersionAttribute.Version); - greenshotVersion = assemblyFileVersion.ToString(3); + var assemblyFileVersion = new Version(assemblyFileVersionAttribute.Version); + greenshotVersion = assemblyFileVersion.ToString(3); } if (!shortVersion) @@ -78,171 +79,181 @@ namespace GreenshotPlugin.Core { greenshotVersion = informationalVersionAttribute.InformationalVersion; } - } + } - return greenshotVersion.Replace("+", " - "); - } + return greenshotVersion.Replace("+", " - "); + } - public static string EnvironmentToString(bool newline) - { - StringBuilder environment = new StringBuilder(); - environment.Append("Software version: " + GetGreenshotVersion()); - if (IniConfig.IsPortable) { - environment.Append(" Portable"); - } - environment.Append(" (" + OsInfo.Bits + " bit)"); + public static string EnvironmentToString(bool newline) + { + StringBuilder environment = new StringBuilder(); + environment.Append("Software version: " + GetGreenshotVersion()); + if (IniConfig.IsPortable) + { + environment.Append(" Portable"); + } - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.Append(".NET runtime version: " + Environment.Version); - if (IsNet45OrNewer()) - { - environment.Append("+"); + environment.Append(" (" + OsInfo.Bits + " bit)"); - } - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.Append("Time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz")); + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } - if (IsWindows) - { - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } + environment.Append(".NET runtime version: " + Environment.Version); + if (IsNet45OrNewer()) + { + environment.Append("+"); + } + + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + + environment.Append("Time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz")); + + if (IsWindows) + { + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } environment.Append($"OS: {OsInfo.Name}"); if (!string.IsNullOrEmpty(OsInfo.Edition)) { environment.Append($" {OsInfo.Edition}"); + } - } if (!string.IsNullOrEmpty(OsInfo.ServicePack)) { environment.Append($" {OsInfo.ServicePack}"); - } + environment.Append($" x{OsInfo.Bits}"); environment.Append($" {OsInfo.VersionString}"); - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - // Get some important information for fixing GDI related Problems - environment.AppendFormat("GDI object count: {0}", User32.GetGuiResourcesGDICount()); - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.AppendFormat("User object count: {0}", User32.GetGuiResourcesUserCount()); - } - else - { - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.AppendFormat("OS: {0}", Environment.OSVersion.Platform); - } - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - // TODO: Is this needed? - // environment.AppendFormat("Surface count: {0}", Surface.Count); + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } - return environment.ToString(); - } + // Get some important information for fixing GDI related Problems + environment.AppendFormat("GDI object count: {0}", User32.GetGuiResourcesGDICount()); + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } - public static string ExceptionToString(Exception ex) - { - if (ex == null) - return "null\r\n"; + environment.AppendFormat("User object count: {0}", User32.GetGuiResourcesUserCount()); + } + else + { + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } - StringBuilder report = new StringBuilder(); + environment.AppendFormat("OS: {0}", Environment.OSVersion.Platform); + } - report.AppendLine("Exception: " + ex.GetType()); - report.AppendLine("Message: " + ex.Message); - if (ex.Data.Count > 0) - { - report.AppendLine(); - report.AppendLine("Additional Information:"); - foreach (object key in ex.Data.Keys) - { - object data = ex.Data[key]; - if (data != null) - { - report.AppendLine(key + " : " + data); - } - } - } - if (ex is ExternalException externalException) - { - // e.g. COMException - report.AppendLine().AppendLine("ErrorCode: 0x" + externalException.ErrorCode.ToString("X")); - } + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + // TODO: Is this needed? + // environment.AppendFormat("Surface count: {0}", Surface.Count); - report.AppendLine().AppendLine("Stack:").AppendLine(ex.StackTrace); + return environment.ToString(); + } - if (ex is ReflectionTypeLoadException reflectionTypeLoadException) - { - report.AppendLine().AppendLine("LoaderExceptions: "); - foreach (Exception cbE in reflectionTypeLoadException.LoaderExceptions) - { - report.AppendLine(cbE.Message); - } - } + public static string ExceptionToString(Exception ex) + { + if (ex == null) + return "null\r\n"; - if (ex.InnerException != null) - { - report.AppendLine("--- InnerException: ---"); - report.AppendLine(ExceptionToString(ex.InnerException)); - } - return report.ToString(); - } + StringBuilder report = new StringBuilder(); - public static string BuildReport(Exception exception) - { - StringBuilder exceptionText = new StringBuilder(); - exceptionText.AppendLine(EnvironmentToString(true)); - exceptionText.AppendLine(ExceptionToString(exception)); - exceptionText.AppendLine("Configuration dump:"); + report.AppendLine("Exception: " + ex.GetType()); + report.AppendLine("Message: " + ex.Message); + if (ex.Data.Count > 0) + { + report.AppendLine(); + report.AppendLine("Additional Information:"); + foreach (object key in ex.Data.Keys) + { + object data = ex.Data[key]; + if (data != null) + { + report.AppendLine(key + " : " + data); + } + } + } - return exceptionText.ToString(); - } - } + if (ex is ExternalException externalException) + { + // e.g. COMException + report.AppendLine().AppendLine("ErrorCode: 0x" + externalException.ErrorCode.ToString("X")); + } + + report.AppendLine().AppendLine("Stack:").AppendLine(ex.StackTrace); + + if (ex is ReflectionTypeLoadException reflectionTypeLoadException) + { + report.AppendLine().AppendLine("LoaderExceptions: "); + foreach (Exception cbE in reflectionTypeLoadException.LoaderExceptions) + { + report.AppendLine(cbE.Message); + } + } + + if (ex.InnerException != null) + { + report.AppendLine("--- InnerException: ---"); + report.AppendLine(ExceptionToString(ex.InnerException)); + } + + return report.ToString(); + } + + public static string BuildReport(Exception exception) + { + StringBuilder exceptionText = new StringBuilder(); + exceptionText.AppendLine(EnvironmentToString(true)); + exceptionText.AppendLine(ExceptionToString(exception)); + exceptionText.AppendLine("Configuration dump:"); + + return exceptionText.ToString(); + } + } /// /// Provides detailed information about the host operating system. @@ -664,7 +675,6 @@ namespace GreenshotPlugin.Core { return new string(servicePackVersion); } - } } diff --git a/src/GreenshotPlugin/Core/EventDelay.cs b/src/GreenshotPlugin/Core/EventDelay.cs index c00306309..1c6ec235c 100644 --- a/src/GreenshotPlugin/Core/EventDelay.cs +++ b/src/GreenshotPlugin/Core/EventDelay.cs @@ -21,21 +21,27 @@ using System; -namespace GreenshotPlugin.Core { - public class EventDelay { - private long lastCheck; - private readonly long waitTime; - public EventDelay(long ticks) { - waitTime = ticks; - } +namespace GreenshotPlugin.Core +{ + public class EventDelay + { + private long lastCheck; + private readonly long waitTime; - public bool Check() { - lock (this) { - long now = DateTime.Now.Ticks; - bool isPassed = now - lastCheck > waitTime; - lastCheck = now; - return isPassed; - } - } - } -} + public EventDelay(long ticks) + { + waitTime = ticks; + } + + public bool Check() + { + lock (this) + { + long now = DateTime.Now.Ticks; + bool isPassed = now - lastCheck > waitTime; + lastCheck = now; + return isPassed; + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/ExplorerHelper.cs b/src/GreenshotPlugin/Core/ExplorerHelper.cs index 8f67018b1..934d0ed74 100644 --- a/src/GreenshotPlugin/Core/ExplorerHelper.cs +++ b/src/GreenshotPlugin/Core/ExplorerHelper.cs @@ -4,49 +4,52 @@ using System.IO; namespace GreenshotPlugin.Core { - /// - /// Simple utility for the explorer - /// - public static class ExplorerHelper - { - /// - /// Open the path in the windows explorer. - /// If the path is a directory, it will just open the explorer with that directory. - /// If the path is a file, the explorer is opened with the directory and the file is selected. - /// - /// Path to file or directory - public static bool OpenInExplorer(string path) - { - if (path == null) - { - return false; - } - try - { - // Check if path is a directory - if (Directory.Exists(path)) - { - using (Process.Start(path)) - { - return true; - } - } - // Check if path is a file - if (File.Exists(path)) + /// + /// Simple utility for the explorer + /// + public static class ExplorerHelper + { + /// + /// Open the path in the windows explorer. + /// If the path is a directory, it will just open the explorer with that directory. + /// If the path is a file, the explorer is opened with the directory and the file is selected. + /// + /// Path to file or directory + public static bool OpenInExplorer(string path) + { + if (path == null) + { + return false; + } + + try + { + // Check if path is a directory + if (Directory.Exists(path)) + { + using (Process.Start(path)) + { + return true; + } + } + + // Check if path is a file + if (File.Exists(path)) { // Start the explorer process and select the file using var explorer = Process.Start("explorer.exe", $"/select,\"{path}\""); explorer?.WaitForInputIdle(500); return true; } - } - catch (Exception ex) - { - // Make sure we show what we tried to open in the exception - ex.Data.Add("path", path); - throw; - } - return false; - } - } -} + } + catch (Exception ex) + { + // Make sure we show what we tried to open in the exception + ex.Data.Add("path", path); + throw; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/FastBitmap.cs b/src/GreenshotPlugin/Core/FastBitmap.cs index 54b11e5ce..2ef28af93 100644 --- a/src/GreenshotPlugin/Core/FastBitmap.cs +++ b/src/GreenshotPlugin/Core/FastBitmap.cs @@ -18,993 +18,1038 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; -namespace GreenshotPlugin.Core { - - /// - /// The interface for the FastBitmap - /// - public interface IFastBitmap : IDisposable { - /// - /// Get the color at x,y - /// The returned Color object depends on the underlying pixel format - /// - /// int x - /// int y - /// Color - Color GetColorAt(int x, int y); - - /// - /// Set the color at the specified location - /// - /// int x - /// int y - /// Color - void SetColorAt(int x, int y, Color color); - - /// - /// Get the color at x,y - /// The returned byte[] color depends on the underlying pixel format - /// - /// int x - /// int y - /// byte array - void GetColorAt(int x, int y, byte[] color); - - /// - /// Set the color at the specified location - /// - /// int x - /// int y - /// byte[] color - void SetColorAt(int x, int y, byte[] color); - - /// - /// Lock the bitmap - /// - void Lock(); - - /// - /// Unlock the bitmap - /// - void Unlock(); - - /// - /// Unlock the bitmap and get the underlying bitmap in one call - /// - /// - Bitmap UnlockAndReturnBitmap(); - - /// - /// Size of the underlying image - /// - Size Size { - get; - } - - /// - /// Height of the image area that this fastbitmap covers - /// - int Height { - get; - } - - /// - /// Width of the image area that this fastbitmap covers - /// - int Width { - get; - } - - /// - /// Top of the image area that this fastbitmap covers - /// - int Top { - get; - } - - /// - /// Left of the image area that this fastbitmap covers - /// - int Left { - get; - } - - /// - /// Right of the image area that this fastbitmap covers - /// - int Right { - get; - } - - /// - /// Bottom of the image area that this fastbitmap covers - /// - int Bottom { - get; - } - - /// - /// Does the underlying image need to be disposed - /// - bool NeedsDispose { - get; - set; - } - - /// - /// Returns if this FastBitmap has an alpha channel - /// - bool HasAlphaChannel { - get; - } - - /// - /// Draw the stored bitmap to the destionation bitmap at the supplied point - /// - /// Graphics - /// Point with location - void DrawTo(Graphics graphics, Point destination); - - /// - /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle - /// Be aware that the stored bitmap will be resized to the specified rectangle!! - /// - /// Graphics - /// Rectangle with destination - void DrawTo(Graphics graphics, Rectangle destinationRect); - - /// - /// Return true if the coordinates are inside the FastBitmap - /// - /// - /// - /// - bool Contains(int x, int y); - - /// - /// Set the bitmap resolution - /// - /// - /// - void SetResolution(float horizontal, float vertical); - } - - /// - /// This interface can be used for when offsetting is needed - /// - public interface IFastBitmapWithOffset : IFastBitmap { - /// - /// Return true if the coordinates are inside the FastBitmap - /// - /// - /// - /// - new bool Contains(int x, int y); - - /// - /// Set the color at the specified location, using offsetting so the original coordinates can be used - /// - /// int x - /// int y - /// Color color - new void SetColorAt(int x, int y, Color color); - - /// - /// Set the color at the specified location, using offsetting so the original coordinates can be used - /// - /// int x - /// int y - /// byte[] color - new void SetColorAt(int x, int y, byte[] color); - - /// - /// Get the color at x,y - /// The returned Color object depends on the underlying pixel format - /// - /// int x - /// int y - /// Color - new Color GetColorAt(int x, int y); - - /// - /// Get the color at x,y, using offsetting so the original coordinates can be used - /// The returned byte[] color depends on the underlying pixel format - /// - /// int x - /// int y - /// byte array - new void GetColorAt(int x, int y, byte[] color); - - new int Left { - get; - set; - } - - new int Top { - get; - set; - } - } - - /// - /// This interface can be used for when clipping is needed - /// - public interface IFastBitmapWithClip : IFastBitmap { - Rectangle Clip { - get; - set; - } - - bool InvertClip { - get; - set; - } - - /// - /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping - /// - /// int x - /// int y - /// Color color - new void SetColorAt(int x, int y, Color color); - - /// - /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping - /// - /// int x - /// int y - /// byte[] color - new void SetColorAt(int x, int y, byte[] color); - - /// - /// Return true if the coordinates are inside the FastBitmap and not clipped - /// - /// - /// - /// - new bool Contains(int x, int y); - } - - /// - /// This interface is implemented when there is a alpha-blending possibility - /// - public interface IFastBitmapWithBlend : IFastBitmap { - Color BackgroundBlendColor { - get; - set; - } - Color GetBlendedColorAt(int x, int y); - } - - /// - /// The base class for the fast bitmap implementation - /// - public abstract unsafe class FastBitmap : IFastBitmapWithClip, IFastBitmapWithOffset { - protected const int PixelformatIndexA = 3; - protected const int PixelformatIndexR = 2; - protected const int PixelformatIndexG = 1; - protected const int PixelformatIndexB = 0; - - public const int ColorIndexR = 0; - public const int ColorIndexG = 1; - public const int ColorIndexB = 2; - public const int ColorIndexA = 3; - - protected Rectangle Area; - /// - /// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap - /// - public bool NeedsDispose { - get; - set; - } - - public Rectangle Clip { - get; - set; - } - - public bool InvertClip { - get; - set; - } - - /// - /// The bitmap for which the FastBitmap is creating access - /// - protected Bitmap Bitmap; - - protected BitmapData BmData; - protected int Stride; /* bytes per pixel row */ - protected bool BitsLocked; - protected byte* Pointer; - - public static IFastBitmap Create(Bitmap source) { - return Create(source, Rectangle.Empty); - } - - public void SetResolution(float horizontal, float vertical) { - Bitmap.SetResolution(horizontal, vertical); - } - - /// - /// Factory for creating a FastBitmap depending on the pixelformat of the source - /// The supplied rectangle specifies the area for which the FastBitmap does its thing - /// - /// Bitmap to access - /// Rectangle which specifies the area to have access to, can be Rectangle.Empty for the whole image - /// IFastBitmap - public static IFastBitmap Create(Bitmap source, Rectangle area) { - switch (source.PixelFormat) { - case PixelFormat.Format8bppIndexed: - return new FastChunkyBitmap(source, area); - case PixelFormat.Format24bppRgb: - return new Fast24RgbBitmap(source, area); - case PixelFormat.Format32bppRgb: - return new Fast32RgbBitmap(source, area); - case PixelFormat.Format32bppArgb: - case PixelFormat.Format32bppPArgb: - return new Fast32ArgbBitmap(source, area); - default: - throw new NotSupportedException($"Not supported Pixelformat {source.PixelFormat}"); - } - } +namespace GreenshotPlugin.Core +{ + /// + /// The interface for the FastBitmap + /// + public interface IFastBitmap : IDisposable + { + /// + /// Get the color at x,y + /// The returned Color object depends on the underlying pixel format + /// + /// int x + /// int y + /// Color + Color GetColorAt(int x, int y); /// - /// Factory for creating a FastBitmap as a destination for the source - /// - /// Bitmap to clone - /// new Pixelformat - /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat) { - return CreateCloneOf(source, pixelFormat, Rectangle.Empty); - } - /// - /// Factory for creating a FastBitmap as a destination for the source - /// - /// Bitmap to clone - /// Area of the bitmap to access, can be Rectangle.Empty for the whole - /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, Rectangle area) { - return CreateCloneOf(source, PixelFormat.DontCare, area); - } - - /// - /// Factory for creating a FastBitmap as a destination for the source - /// - /// Bitmap to clone - /// Pixelformat of the cloned bitmap - /// Area of the bitmap to access, can be Rectangle.Empty for the whole - /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) { - Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat); - FastBitmap fastBitmap = Create(destination) as FastBitmap; - if (fastBitmap != null) - { - fastBitmap.NeedsDispose = true; - fastBitmap.Left = area.Left; - fastBitmap.Top = area.Top; - } - return fastBitmap; - } - - /// - /// Factory for creating a FastBitmap as a destination - /// - /// - /// - /// - /// IFastBitmap - public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat, Color backgroundColor) { - Bitmap destination = ImageHelper.CreateEmpty(newSize.Width, newSize.Height, pixelFormat, backgroundColor, 96f, 96f); - IFastBitmap fastBitmap = Create(destination); - fastBitmap.NeedsDispose = true; - return fastBitmap; - } - - /// - /// Constructor which stores the image and locks it when called - /// - /// Bitmap - /// Rectangle - protected FastBitmap(Bitmap bitmap, Rectangle area) { - Bitmap = bitmap; - Rectangle bitmapArea = new Rectangle(Point.Empty, bitmap.Size); - if (area != Rectangle.Empty) { - area.Intersect(bitmapArea); - Area = area; - } else { - Area = bitmapArea; - } - // As the lock takes care that only the specified area is made available we need to calculate the offset - Left = area.Left; - Top = area.Top; - // Default cliping is done to the area without invert - Clip = Area; - InvertClip = false; - // Always lock, so we don't need to do this ourselves - Lock(); - } - - /// - /// Return the size of the image - /// - public Size Size { - get { - if (Area == Rectangle.Empty) { - return Bitmap.Size; - } - return Area.Size; - } - } - - /// - /// Return the width of the image - /// - public int Width { - get { - if (Area == Rectangle.Empty) { - return Bitmap.Width; - } - return Area.Width; - } - } - - /// - /// Return the height of the image - /// - public int Height { - get { - if (Area == Rectangle.Empty) { - return Bitmap.Height; - } - return Area.Height; - } - } - - private int _left; - /// - /// Return the left of the fastbitmap, this is also used as an offset - /// - public int Left { - get { - return 0; - } - set { - _left = value; - } - } - - /// - /// Return the left of the fastbitmap, this is also used as an offset - /// - int IFastBitmapWithOffset.Left { - get { - return _left; - } - set { - _left = value; - } - } - - private int _top; - /// - /// Return the top of the fastbitmap, this is also used as an offset - /// - public int Top { - get { - return 0; - } - set { - _top = value; - } - } - - /// - /// Return the top of the fastbitmap, this is also used as an offset - /// - int IFastBitmapWithOffset.Top { - get { - return _top; - } - set { - _top = value; - } - } - - /// - /// Return the right of the fastbitmap - /// - public int Right => Left + Width; - - /// - /// Return the bottom of the fastbitmap - /// - public int Bottom => Top + Height; - - /// - /// Returns the underlying bitmap, unlocks it and prevents that it will be disposed - /// - public Bitmap UnlockAndReturnBitmap() { - if (BitsLocked) { - Unlock(); - } - NeedsDispose = false; - return Bitmap; - } - - public virtual bool HasAlphaChannel => false; - - /// - /// Destructor - /// - ~FastBitmap() { - Dispose(false); - } - - /// - /// The public accessible Dispose - /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice - /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - // The bulk of the clean-up code is implemented in Dispose(bool) - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected virtual void Dispose(bool disposing) { - Unlock(); - if (disposing) { - if (Bitmap != null && NeedsDispose) { - Bitmap.Dispose(); - } - } - Bitmap = null; - BmData = null; - Pointer = null; - } - - /// - /// Lock the bitmap so we have direct access to the memory - /// - public void Lock() { - if (Width <= 0 || Height <= 0 || BitsLocked) - { - return; - } - BmData = Bitmap.LockBits(Area, ImageLockMode.ReadWrite, Bitmap.PixelFormat); - BitsLocked = true; - - IntPtr scan0 = BmData.Scan0; - Pointer = (byte*)(void*)scan0; - Stride = BmData.Stride; - } - - /// - /// Unlock the System Memory - /// - public void Unlock() { - if (BitsLocked) { - Bitmap.UnlockBits(BmData); - BitsLocked = false; - } - } - - /// - /// Draw the stored bitmap to the destionation bitmap at the supplied point - /// - /// - /// - public void DrawTo(Graphics graphics, Point destination) { - DrawTo(graphics, new Rectangle(destination, Area.Size)); - } - - /// - /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle - /// Be aware that the stored bitmap will be resized to the specified rectangle!! - /// - /// - /// - public void DrawTo(Graphics graphics, Rectangle destinationRect) { - // Make sure this.bitmap is unlocked, if it was locked - bool isLocked = BitsLocked; - if (isLocked) { - Unlock(); - } - - graphics.DrawImage(Bitmap, destinationRect, Area, GraphicsUnit.Pixel); - } - - /// - /// returns true if x & y are inside the FastBitmap - /// - /// - /// - /// true if x & y are inside the FastBitmap - public bool Contains(int x, int y) { - return Area.Contains(x - Left, y - Top); - } - - public abstract Color GetColorAt(int x, int y); - public abstract void SetColorAt(int x, int y, Color color); - public abstract void GetColorAt(int x, int y, byte[] color); - public abstract void SetColorAt(int x, int y, byte[] color); - - bool IFastBitmapWithClip.Contains(int x, int y) { - bool contains = Clip.Contains(x, y); - if (InvertClip) { - return !contains; - } else { - return contains; - } - } - - void IFastBitmapWithClip.SetColorAt(int x, int y, byte[] color) { - bool contains = Clip.Contains(x, y); - if ((InvertClip && contains) || (!InvertClip && !contains)) { - return; - } - SetColorAt(x, y, color); - } - - void IFastBitmapWithClip.SetColorAt(int x, int y, Color color) { - bool contains = Clip.Contains(x, y); - if ((InvertClip && contains) || (!InvertClip && !contains)) { - return; - } - SetColorAt(x, y, color); - } + /// Set the color at the specified location + /// + /// int x + /// int y + /// Color + void SetColorAt(int x, int y, Color color); /// - /// returns true if x & y are inside the FastBitmap - /// - /// - /// - /// true if x & y are inside the FastBitmap - bool IFastBitmapWithOffset.Contains(int x, int y) { - return Area.Contains(x - Left, y - Top); - } + /// Get the color at x,y + /// The returned byte[] color depends on the underlying pixel format + /// + /// int x + /// int y + /// byte array + void GetColorAt(int x, int y, byte[] color); - Color IFastBitmapWithOffset.GetColorAt(int x, int y) { - x -= _left; - y -= _top; - return GetColorAt(x, y); - } - void IFastBitmapWithOffset.GetColorAt(int x, int y, byte[] color) { - x -= _left; - y -= _top; - GetColorAt(x, y, color); - } + /// + /// Set the color at the specified location + /// + /// int x + /// int y + /// byte[] color + void SetColorAt(int x, int y, byte[] color); - void IFastBitmapWithOffset.SetColorAt(int x, int y, byte[] color) { - x -= _left; - y -= _top; - SetColorAt(x, y, color); - } + /// + /// Lock the bitmap + /// + void Lock(); - void IFastBitmapWithOffset.SetColorAt(int x, int y, Color color) { - x -= _left; - y -= _top; - SetColorAt(x, y, color); - } + /// + /// Unlock the bitmap + /// + void Unlock(); + + /// + /// Unlock the bitmap and get the underlying bitmap in one call + /// + /// + Bitmap UnlockAndReturnBitmap(); + + /// + /// Size of the underlying image + /// + Size Size { get; } + + /// + /// Height of the image area that this fastbitmap covers + /// + int Height { get; } + + /// + /// Width of the image area that this fastbitmap covers + /// + int Width { get; } + + /// + /// Top of the image area that this fastbitmap covers + /// + int Top { get; } + + /// + /// Left of the image area that this fastbitmap covers + /// + int Left { get; } + + /// + /// Right of the image area that this fastbitmap covers + /// + int Right { get; } + + /// + /// Bottom of the image area that this fastbitmap covers + /// + int Bottom { get; } + + /// + /// Does the underlying image need to be disposed + /// + bool NeedsDispose { get; set; } + + /// + /// Returns if this FastBitmap has an alpha channel + /// + bool HasAlphaChannel { get; } + + /// + /// Draw the stored bitmap to the destionation bitmap at the supplied point + /// + /// Graphics + /// Point with location + void DrawTo(Graphics graphics, Point destination); + + /// + /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle + /// Be aware that the stored bitmap will be resized to the specified rectangle!! + /// + /// Graphics + /// Rectangle with destination + void DrawTo(Graphics graphics, Rectangle destinationRect); + + /// + /// Return true if the coordinates are inside the FastBitmap + /// + /// + /// + /// + bool Contains(int x, int y); + + /// + /// Set the bitmap resolution + /// + /// + /// + void SetResolution(float horizontal, float vertical); } - /// - /// This is the implementation of the FastBitmat for the 8BPP pixelformat - /// - public unsafe class FastChunkyBitmap : FastBitmap { - // Used for indexed images - private readonly Color[] _colorEntries; - private readonly Dictionary _colorCache = new Dictionary(); + /// + /// This interface can be used for when offsetting is needed + /// + public interface IFastBitmapWithOffset : IFastBitmap + { + /// + /// Return true if the coordinates are inside the FastBitmap + /// + /// + /// + /// + new bool Contains(int x, int y); - public FastChunkyBitmap(Bitmap source, Rectangle area) : base(source, area) { - _colorEntries = Bitmap.Palette.Entries; - } + /// + /// Set the color at the specified location, using offsetting so the original coordinates can be used + /// + /// int x + /// int y + /// Color color + new void SetColorAt(int x, int y, Color color); - /// - /// Get the color from the specified location - /// - /// - /// - /// Color - public override Color GetColorAt(int x, int y) { - int offset = x + (y * Stride); - byte colorIndex = Pointer[offset]; - return _colorEntries[colorIndex]; - } + /// + /// Set the color at the specified location, using offsetting so the original coordinates can be used + /// + /// int x + /// int y + /// byte[] color + new void SetColorAt(int x, int y, byte[] color); - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference - public override void GetColorAt(int x, int y, byte[] color) { - throw new NotImplementedException("No performance gain!"); - } + /// + /// Get the color at x,y + /// The returned Color object depends on the underlying pixel format + /// + /// int x + /// int y + /// Color + new Color GetColorAt(int x, int y); - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference - public override void SetColorAt(int x, int y, byte[] color) { - throw new NotImplementedException("No performance gain!"); - } + /// + /// Get the color at x,y, using offsetting so the original coordinates can be used + /// The returned byte[] color depends on the underlying pixel format + /// + /// int x + /// int y + /// byte array + new void GetColorAt(int x, int y, byte[] color); - /// - /// Get the color-index from the specified location - /// - /// - /// - /// byte with index - public byte GetColorIndexAt(int x, int y) { - int offset = x + (y * Stride); - return Pointer[offset]; - } + new int Left { get; set; } - /// - /// Set the color-index at the specified location - /// - /// - /// - /// - public void SetColorIndexAt(int x, int y, byte colorIndex) { - int offset = x + (y * Stride); - Pointer[offset] = colorIndex; - } + new int Top { get; set; } + } - /// - /// Set the supplied color at the specified location. - /// Throws an ArgumentException if the color is not in the palette - /// - /// - /// - /// Color to set - public override void SetColorAt(int x, int y, Color color) { - int offset = x + (y * Stride); - if (!_colorCache.TryGetValue(color, out var colorIndex)) { - bool foundColor = false; - for (colorIndex = 0; colorIndex < _colorEntries.Length; colorIndex++) { - if (color == _colorEntries[colorIndex]) { - _colorCache.Add(color, colorIndex); - foundColor = true; - break; - } - } - if (!foundColor) { - throw new ArgumentException("No such color!"); - } - } - Pointer[offset] = colorIndex; - } - } + /// + /// This interface can be used for when clipping is needed + /// + public interface IFastBitmapWithClip : IFastBitmap + { + Rectangle Clip { get; set; } - /// - /// This is the implementation of the IFastBitmap for 24 bit images (no Alpha) - /// - public unsafe class Fast24RgbBitmap : FastBitmap { + bool InvertClip { get; set; } - public Fast24RgbBitmap(Bitmap source, Rectangle area) : base(source, area) { - } + /// + /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping + /// + /// int x + /// int y + /// Color color + new void SetColorAt(int x, int y, Color color); - /// - /// Retrieve the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public override Color GetColorAt(int x, int y) { - int offset = (x * 3) + (y * Stride); - return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); - } + /// + /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping + /// + /// int x + /// int y + /// byte[] color + new void SetColorAt(int x, int y, byte[] color); - /// - /// Set the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public override void SetColorAt(int x, int y, Color color) { - int offset = (x * 3) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color.R; - Pointer[PixelformatIndexG + offset] = color.G; - Pointer[PixelformatIndexB + offset] = color.B; - } + /// + /// Return true if the coordinates are inside the FastBitmap and not clipped + /// + /// + /// + /// + new bool Contains(int x, int y); + } - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b) - public override void GetColorAt(int x, int y, byte[] color) { - int offset = (x * 3) + (y * Stride); - color[PixelformatIndexR] = Pointer[PixelformatIndexR + offset]; - color[PixelformatIndexG] = Pointer[PixelformatIndexG + offset]; - color[PixelformatIndexB] = Pointer[PixelformatIndexB + offset]; - } + /// + /// This interface is implemented when there is a alpha-blending possibility + /// + public interface IFastBitmapWithBlend : IFastBitmap + { + Color BackgroundBlendColor { get; set; } + Color GetBlendedColorAt(int x, int y); + } - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b) - public override void SetColorAt(int x, int y, byte[] color) { - int offset = (x * 3) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color[PixelformatIndexR]; - Pointer[PixelformatIndexG + offset] = color[PixelformatIndexG]; - Pointer[PixelformatIndexB + offset] = color[PixelformatIndexB]; - } + /// + /// The base class for the fast bitmap implementation + /// + public abstract unsafe class FastBitmap : IFastBitmapWithClip, IFastBitmapWithOffset + { + protected const int PixelformatIndexA = 3; + protected const int PixelformatIndexR = 2; + protected const int PixelformatIndexG = 1; + protected const int PixelformatIndexB = 0; - } + public const int ColorIndexR = 0; + public const int ColorIndexG = 1; + public const int ColorIndexB = 2; + public const int ColorIndexA = 3; - /// - /// This is the implementation of the IFastBitmap for 32 bit images (no Alpha) - /// - public unsafe class Fast32RgbBitmap : FastBitmap { - public Fast32RgbBitmap(Bitmap source, Rectangle area) : base(source, area) { + protected Rectangle Area; - } + /// + /// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap + /// + public bool NeedsDispose { get; set; } - /// - /// Retrieve the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public override Color GetColorAt(int x, int y) { - int offset = (x * 4) + (y * Stride); - return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); - } + public Rectangle Clip { get; set; } - /// - /// Set the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public override void SetColorAt(int x, int y, Color color) { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color.R; - Pointer[PixelformatIndexG + offset] = color.G; - Pointer[PixelformatIndexB + offset] = color.B; - } + public bool InvertClip { get; set; } - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference (a,r,g,b) - public override void GetColorAt(int x, int y, byte[] color) { - int offset = (x * 4) + (y * Stride); - color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; - color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; - color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; - } + /// + /// The bitmap for which the FastBitmap is creating access + /// + protected Bitmap Bitmap; - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b) - public override void SetColorAt(int x, int y, byte[] color) { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R - Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; - Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; - } - } + protected BitmapData BmData; + protected int Stride; /* bytes per pixel row */ + protected bool BitsLocked; + protected byte* Pointer; - /// - /// This is the implementation of the IFastBitmap for 32 bit images with Alpha - /// - public unsafe class Fast32ArgbBitmap : FastBitmap, IFastBitmapWithBlend { - public override bool HasAlphaChannel => true; + public static IFastBitmap Create(Bitmap source) + { + return Create(source, Rectangle.Empty); + } - public Color BackgroundBlendColor { - get; - set; - } - public Fast32ArgbBitmap(Bitmap source, Rectangle area) : base(source, area) { - BackgroundBlendColor = Color.White; - } + public void SetResolution(float horizontal, float vertical) + { + Bitmap.SetResolution(horizontal, vertical); + } - /// - /// Retrieve the color at location x,y - /// - /// X coordinate - /// Y Coordinate - /// Color - public override Color GetColorAt(int x, int y) { - int offset = (x * 4) + (y * Stride); - return Color.FromArgb(Pointer[PixelformatIndexA + offset], Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); - } + /// + /// Factory for creating a FastBitmap depending on the pixelformat of the source + /// The supplied rectangle specifies the area for which the FastBitmap does its thing + /// + /// Bitmap to access + /// Rectangle which specifies the area to have access to, can be Rectangle.Empty for the whole image + /// IFastBitmap + public static IFastBitmap Create(Bitmap source, Rectangle area) + { + switch (source.PixelFormat) + { + case PixelFormat.Format8bppIndexed: + return new FastChunkyBitmap(source, area); + case PixelFormat.Format24bppRgb: + return new Fast24RgbBitmap(source, area); + case PixelFormat.Format32bppRgb: + return new Fast32RgbBitmap(source, area); + case PixelFormat.Format32bppArgb: + case PixelFormat.Format32bppPArgb: + return new Fast32ArgbBitmap(source, area); + default: + throw new NotSupportedException($"Not supported Pixelformat {source.PixelFormat}"); + } + } - /// - /// Set the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public override void SetColorAt(int x, int y, Color color) { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexA + offset] = color.A; - Pointer[PixelformatIndexR + offset] = color.R; - Pointer[PixelformatIndexG + offset] = color.G; - Pointer[PixelformatIndexB + offset] = color.B; - } + /// + /// Factory for creating a FastBitmap as a destination for the source + /// + /// Bitmap to clone + /// new Pixelformat + /// IFastBitmap + public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat) + { + return CreateCloneOf(source, pixelFormat, Rectangle.Empty); + } - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b,a) - public override void GetColorAt(int x, int y, byte[] color) { - int offset = (x * 4) + (y * Stride); - color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; - color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; - color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; - color[ColorIndexA] = Pointer[PixelformatIndexA + offset]; - } + /// + /// Factory for creating a FastBitmap as a destination for the source + /// + /// Bitmap to clone + /// Area of the bitmap to access, can be Rectangle.Empty for the whole + /// IFastBitmap + public static IFastBitmap CreateCloneOf(Image source, Rectangle area) + { + return CreateCloneOf(source, PixelFormat.DontCare, area); + } - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b,a) - public override void SetColorAt(int x, int y, byte[] color) { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R - Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; - Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; - Pointer[PixelformatIndexA + offset] = color[ColorIndexA]; - } + /// + /// Factory for creating a FastBitmap as a destination for the source + /// + /// Bitmap to clone + /// Pixelformat of the cloned bitmap + /// Area of the bitmap to access, can be Rectangle.Empty for the whole + /// IFastBitmap + public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) + { + Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat); + FastBitmap fastBitmap = Create(destination) as FastBitmap; + if (fastBitmap != null) + { + fastBitmap.NeedsDispose = true; + fastBitmap.Left = area.Left; + fastBitmap.Top = area.Top; + } - /// - /// Retrieve the color, without alpha (is blended), at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public Color GetBlendedColorAt(int x, int y) { - int offset = (x * 4) + (y * Stride); - int a = Pointer[PixelformatIndexA + offset]; - int red = Pointer[PixelformatIndexR + offset]; - int green = Pointer[PixelformatIndexG + offset]; - int blue = Pointer[PixelformatIndexB + offset]; + return fastBitmap; + } - if (a < 255) { - // As the request is to get without alpha, we blend. - int rem = 255 - a; - red = (red * a + BackgroundBlendColor.R * rem) / 255; - green = (green * a + BackgroundBlendColor.G * rem) / 255; - blue = (blue * a + BackgroundBlendColor.B * rem) / 255; - } - return Color.FromArgb(255, red, green, blue); - } - } -} + /// + /// Factory for creating a FastBitmap as a destination + /// + /// + /// + /// + /// IFastBitmap + public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat, Color backgroundColor) + { + Bitmap destination = ImageHelper.CreateEmpty(newSize.Width, newSize.Height, pixelFormat, backgroundColor, 96f, 96f); + IFastBitmap fastBitmap = Create(destination); + fastBitmap.NeedsDispose = true; + return fastBitmap; + } + + /// + /// Constructor which stores the image and locks it when called + /// + /// Bitmap + /// Rectangle + protected FastBitmap(Bitmap bitmap, Rectangle area) + { + Bitmap = bitmap; + Rectangle bitmapArea = new Rectangle(Point.Empty, bitmap.Size); + if (area != Rectangle.Empty) + { + area.Intersect(bitmapArea); + Area = area; + } + else + { + Area = bitmapArea; + } + + // As the lock takes care that only the specified area is made available we need to calculate the offset + Left = area.Left; + Top = area.Top; + // Default cliping is done to the area without invert + Clip = Area; + InvertClip = false; + // Always lock, so we don't need to do this ourselves + Lock(); + } + + /// + /// Return the size of the image + /// + public Size Size + { + get + { + if (Area == Rectangle.Empty) + { + return Bitmap.Size; + } + + return Area.Size; + } + } + + /// + /// Return the width of the image + /// + public int Width + { + get + { + if (Area == Rectangle.Empty) + { + return Bitmap.Width; + } + + return Area.Width; + } + } + + /// + /// Return the height of the image + /// + public int Height + { + get + { + if (Area == Rectangle.Empty) + { + return Bitmap.Height; + } + + return Area.Height; + } + } + + private int _left; + + /// + /// Return the left of the fastbitmap, this is also used as an offset + /// + public int Left + { + get { return 0; } + set { _left = value; } + } + + /// + /// Return the left of the fastbitmap, this is also used as an offset + /// + int IFastBitmapWithOffset.Left + { + get { return _left; } + set { _left = value; } + } + + private int _top; + + /// + /// Return the top of the fastbitmap, this is also used as an offset + /// + public int Top + { + get { return 0; } + set { _top = value; } + } + + /// + /// Return the top of the fastbitmap, this is also used as an offset + /// + int IFastBitmapWithOffset.Top + { + get { return _top; } + set { _top = value; } + } + + /// + /// Return the right of the fastbitmap + /// + public int Right => Left + Width; + + /// + /// Return the bottom of the fastbitmap + /// + public int Bottom => Top + Height; + + /// + /// Returns the underlying bitmap, unlocks it and prevents that it will be disposed + /// + public Bitmap UnlockAndReturnBitmap() + { + if (BitsLocked) + { + Unlock(); + } + + NeedsDispose = false; + return Bitmap; + } + + public virtual bool HasAlphaChannel => false; + + /// + /// Destructor + /// + ~FastBitmap() + { + Dispose(false); + } + + /// + /// The public accessible Dispose + /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // The bulk of the clean-up code is implemented in Dispose(bool) + + /// + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + protected virtual void Dispose(bool disposing) + { + Unlock(); + if (disposing) + { + if (Bitmap != null && NeedsDispose) + { + Bitmap.Dispose(); + } + } + + Bitmap = null; + BmData = null; + Pointer = null; + } + + /// + /// Lock the bitmap so we have direct access to the memory + /// + public void Lock() + { + if (Width <= 0 || Height <= 0 || BitsLocked) + { + return; + } + + BmData = Bitmap.LockBits(Area, ImageLockMode.ReadWrite, Bitmap.PixelFormat); + BitsLocked = true; + + IntPtr scan0 = BmData.Scan0; + Pointer = (byte*) (void*) scan0; + Stride = BmData.Stride; + } + + /// + /// Unlock the System Memory + /// + public void Unlock() + { + if (BitsLocked) + { + Bitmap.UnlockBits(BmData); + BitsLocked = false; + } + } + + /// + /// Draw the stored bitmap to the destionation bitmap at the supplied point + /// + /// + /// + public void DrawTo(Graphics graphics, Point destination) + { + DrawTo(graphics, new Rectangle(destination, Area.Size)); + } + + /// + /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle + /// Be aware that the stored bitmap will be resized to the specified rectangle!! + /// + /// + /// + public void DrawTo(Graphics graphics, Rectangle destinationRect) + { + // Make sure this.bitmap is unlocked, if it was locked + bool isLocked = BitsLocked; + if (isLocked) + { + Unlock(); + } + + graphics.DrawImage(Bitmap, destinationRect, Area, GraphicsUnit.Pixel); + } + + /// + /// returns true if x & y are inside the FastBitmap + /// + /// + /// + /// true if x & y are inside the FastBitmap + public bool Contains(int x, int y) + { + return Area.Contains(x - Left, y - Top); + } + + public abstract Color GetColorAt(int x, int y); + public abstract void SetColorAt(int x, int y, Color color); + public abstract void GetColorAt(int x, int y, byte[] color); + public abstract void SetColorAt(int x, int y, byte[] color); + + bool IFastBitmapWithClip.Contains(int x, int y) + { + bool contains = Clip.Contains(x, y); + if (InvertClip) + { + return !contains; + } + else + { + return contains; + } + } + + void IFastBitmapWithClip.SetColorAt(int x, int y, byte[] color) + { + bool contains = Clip.Contains(x, y); + if ((InvertClip && contains) || (!InvertClip && !contains)) + { + return; + } + + SetColorAt(x, y, color); + } + + void IFastBitmapWithClip.SetColorAt(int x, int y, Color color) + { + bool contains = Clip.Contains(x, y); + if ((InvertClip && contains) || (!InvertClip && !contains)) + { + return; + } + + SetColorAt(x, y, color); + } + + /// + /// returns true if x & y are inside the FastBitmap + /// + /// + /// + /// true if x & y are inside the FastBitmap + bool IFastBitmapWithOffset.Contains(int x, int y) + { + return Area.Contains(x - Left, y - Top); + } + + Color IFastBitmapWithOffset.GetColorAt(int x, int y) + { + x -= _left; + y -= _top; + return GetColorAt(x, y); + } + + void IFastBitmapWithOffset.GetColorAt(int x, int y, byte[] color) + { + x -= _left; + y -= _top; + GetColorAt(x, y, color); + } + + void IFastBitmapWithOffset.SetColorAt(int x, int y, byte[] color) + { + x -= _left; + y -= _top; + SetColorAt(x, y, color); + } + + void IFastBitmapWithOffset.SetColorAt(int x, int y, Color color) + { + x -= _left; + y -= _top; + SetColorAt(x, y, color); + } + } + + /// + /// This is the implementation of the FastBitmat for the 8BPP pixelformat + /// + public unsafe class FastChunkyBitmap : FastBitmap + { + // Used for indexed images + private readonly Color[] _colorEntries; + private readonly Dictionary _colorCache = new Dictionary(); + + public FastChunkyBitmap(Bitmap source, Rectangle area) : base(source, area) + { + _colorEntries = Bitmap.Palette.Entries; + } + + /// + /// Get the color from the specified location + /// + /// + /// + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = x + (y * Stride); + byte colorIndex = Pointer[offset]; + return _colorEntries[colorIndex]; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference + public override void GetColorAt(int x, int y, byte[] color) + { + throw new NotImplementedException("No performance gain!"); + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference + public override void SetColorAt(int x, int y, byte[] color) + { + throw new NotImplementedException("No performance gain!"); + } + + /// + /// Get the color-index from the specified location + /// + /// + /// + /// byte with index + public byte GetColorIndexAt(int x, int y) + { + int offset = x + (y * Stride); + return Pointer[offset]; + } + + /// + /// Set the color-index at the specified location + /// + /// + /// + /// + public void SetColorIndexAt(int x, int y, byte colorIndex) + { + int offset = x + (y * Stride); + Pointer[offset] = colorIndex; + } + + /// + /// Set the supplied color at the specified location. + /// Throws an ArgumentException if the color is not in the palette + /// + /// + /// + /// Color to set + public override void SetColorAt(int x, int y, Color color) + { + int offset = x + (y * Stride); + if (!_colorCache.TryGetValue(color, out var colorIndex)) + { + bool foundColor = false; + for (colorIndex = 0; colorIndex < _colorEntries.Length; colorIndex++) + { + if (color == _colorEntries[colorIndex]) + { + _colorCache.Add(color, colorIndex); + foundColor = true; + break; + } + } + + if (!foundColor) + { + throw new ArgumentException("No such color!"); + } + } + + Pointer[offset] = colorIndex; + } + } + + /// + /// This is the implementation of the IFastBitmap for 24 bit images (no Alpha) + /// + public unsafe class Fast24RgbBitmap : FastBitmap + { + public Fast24RgbBitmap(Bitmap source, Rectangle area) : base(source, area) + { + } + + /// + /// Retrieve the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// X coordinate + /// Y Coordinate + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = (x * 3) + (y * Stride); + return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); + } + + /// + /// Set the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// + public override void SetColorAt(int x, int y, Color color) + { + int offset = (x * 3) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color.R; + Pointer[PixelformatIndexG + offset] = color.G; + Pointer[PixelformatIndexB + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b) + public override void GetColorAt(int x, int y, byte[] color) + { + int offset = (x * 3) + (y * Stride); + color[PixelformatIndexR] = Pointer[PixelformatIndexR + offset]; + color[PixelformatIndexG] = Pointer[PixelformatIndexG + offset]; + color[PixelformatIndexB] = Pointer[PixelformatIndexB + offset]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b) + public override void SetColorAt(int x, int y, byte[] color) + { + int offset = (x * 3) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color[PixelformatIndexR]; + Pointer[PixelformatIndexG + offset] = color[PixelformatIndexG]; + Pointer[PixelformatIndexB + offset] = color[PixelformatIndexB]; + } + } + + /// + /// This is the implementation of the IFastBitmap for 32 bit images (no Alpha) + /// + public unsafe class Fast32RgbBitmap : FastBitmap + { + public Fast32RgbBitmap(Bitmap source, Rectangle area) : base(source, area) + { + } + + /// + /// Retrieve the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// X coordinate + /// Y Coordinate + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = (x * 4) + (y * Stride); + return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); + } + + /// + /// Set the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// + public override void SetColorAt(int x, int y, Color color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color.R; + Pointer[PixelformatIndexG + offset] = color.G; + Pointer[PixelformatIndexB + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference (a,r,g,b) + public override void GetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; + color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; + color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b) + public override void SetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R + Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; + Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; + } + } + + /// + /// This is the implementation of the IFastBitmap for 32 bit images with Alpha + /// + public unsafe class Fast32ArgbBitmap : FastBitmap, IFastBitmapWithBlend + { + public override bool HasAlphaChannel => true; + + public Color BackgroundBlendColor { get; set; } + + public Fast32ArgbBitmap(Bitmap source, Rectangle area) : base(source, area) + { + BackgroundBlendColor = Color.White; + } + + /// + /// Retrieve the color at location x,y + /// + /// X coordinate + /// Y Coordinate + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = (x * 4) + (y * Stride); + return Color.FromArgb(Pointer[PixelformatIndexA + offset], Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], + Pointer[PixelformatIndexB + offset]); + } + + /// + /// Set the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// + public override void SetColorAt(int x, int y, Color color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexA + offset] = color.A; + Pointer[PixelformatIndexR + offset] = color.R; + Pointer[PixelformatIndexG + offset] = color.G; + Pointer[PixelformatIndexB + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b,a) + public override void GetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; + color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; + color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; + color[ColorIndexA] = Pointer[PixelformatIndexA + offset]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b,a) + public override void SetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R + Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; + Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; + Pointer[PixelformatIndexA + offset] = color[ColorIndexA]; + } + + /// + /// Retrieve the color, without alpha (is blended), at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// X coordinate + /// Y Coordinate + /// Color + public Color GetBlendedColorAt(int x, int y) + { + int offset = (x * 4) + (y * Stride); + int a = Pointer[PixelformatIndexA + offset]; + int red = Pointer[PixelformatIndexR + offset]; + int green = Pointer[PixelformatIndexG + offset]; + int blue = Pointer[PixelformatIndexB + offset]; + + if (a < 255) + { + // As the request is to get without alpha, we blend. + int rem = 255 - a; + red = (red * a + BackgroundBlendColor.R * rem) / 255; + green = (green * a + BackgroundBlendColor.G * rem) / 255; + blue = (blue * a + BackgroundBlendColor.B * rem) / 255; + } + + return Color.FromArgb(255, red, green, blue); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/FilenameHelper.cs b/src/GreenshotPlugin/Core/FilenameHelper.cs index 5edf92afb..6d8073843 100644 --- a/src/GreenshotPlugin/Core/FilenameHelper.cs +++ b/src/GreenshotPlugin/Core/FilenameHelper.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections; using System.IO; @@ -28,532 +29,677 @@ using System.Collections.Generic; using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; -namespace GreenshotPlugin.Core { - public static class FilenameHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(FilenameHelper)); - // Specify the regular expression for the filename formatting: - // Starting with ${ - // than the varname, which ends with a : or } - // If a parameters needs to be supplied, than a ":" should follow the name... everything from the : until the } is considered to be part of the parameters. - // The parameter format is a single alpha followed by the value belonging to the parameter, e.g. : - // ${capturetime:d"yyyy-MM-dd HH_mm_ss"} - private static readonly Regex VarRegexp = new Regex(@"\${(?[^:}]+)[:]?(?[^}]*)}", RegexOptions.Compiled); - private static readonly Regex CmdVarRegexp = new Regex(@"%(?[^%]+)%", RegexOptions.Compiled); +namespace GreenshotPlugin.Core +{ + public static class FilenameHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(FilenameHelper)); - private static readonly Regex SplitRegexp = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled); - private const int MaxTitleLength = 80; - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const string UnsafeReplacement = "_"; - private static readonly Random RandomNumberGen = new Random(); - private static readonly Regex RandRegexp = new Regex("^R+$", RegexOptions.Compiled); + // Specify the regular expression for the filename formatting: + // Starting with ${ + // than the varname, which ends with a : or } + // If a parameters needs to be supplied, than a ":" should follow the name... everything from the : until the } is considered to be part of the parameters. + // The parameter format is a single alpha followed by the value belonging to the parameter, e.g. : + // ${capturetime:d"yyyy-MM-dd HH_mm_ss"} + private static readonly Regex VarRegexp = new Regex(@"\${(?[^:}]+)[:]?(?[^}]*)}", RegexOptions.Compiled); + private static readonly Regex CmdVarRegexp = new Regex(@"%(?[^%]+)%", RegexOptions.Compiled); - /// - /// Remove invalid characters from the fully qualified filename - /// - /// string with the full path to a file - /// string with the full path to a file, without invalid characters - public static string MakeFqFilenameSafe(string fullPath) { - string path = MakePathSafe(Path.GetDirectoryName(fullPath)); - string filename = MakeFilenameSafe(Path.GetFileName(fullPath)); - // Make the fullpath again and return - return Path.Combine(path, filename); - } + private static readonly Regex SplitRegexp = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled); + private const int MaxTitleLength = 80; + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private const string UnsafeReplacement = "_"; + private static readonly Random RandomNumberGen = new Random(); + private static readonly Regex RandRegexp = new Regex("^R+$", RegexOptions.Compiled); - /// - /// Remove invalid characters from the filename - /// - /// string with the full path to a file - /// string with the full path to a file, without invalid characters - public static string MakeFilenameSafe(string filename) { - // Make the filename save! - if (filename != null) { - foreach (char disallowed in Path.GetInvalidFileNameChars()) { - filename = filename.Replace(disallowed.ToString(), UnsafeReplacement); - } - } - return filename; - } + /// + /// Remove invalid characters from the fully qualified filename + /// + /// string with the full path to a file + /// string with the full path to a file, without invalid characters + public static string MakeFqFilenameSafe(string fullPath) + { + string path = MakePathSafe(Path.GetDirectoryName(fullPath)); + string filename = MakeFilenameSafe(Path.GetFileName(fullPath)); + // Make the fullpath again and return + return Path.Combine(path, filename); + } - /// - /// Remove invalid characters from the path - /// - /// string with the full path to a file - /// string with the full path to a file, without invalid characters - public static string MakePathSafe(string path) { - // Make the path save! - if (path != null) { - foreach (char disallowed in Path.GetInvalidPathChars()) { - path = path.Replace(disallowed.ToString(), UnsafeReplacement); - } - } - return path; - } + /// + /// Remove invalid characters from the filename + /// + /// string with the full path to a file + /// string with the full path to a file, without invalid characters + public static string MakeFilenameSafe(string filename) + { + // Make the filename save! + if (filename != null) + { + foreach (char disallowed in Path.GetInvalidFileNameChars()) + { + filename = filename.Replace(disallowed.ToString(), UnsafeReplacement); + } + } - public static string GetFilenameWithoutExtensionFromPattern(string pattern) { - return GetFilenameWithoutExtensionFromPattern(pattern, null); - } + return filename; + } - public static string GetFilenameWithoutExtensionFromPattern(string pattern, ICaptureDetails captureDetails) { - return FillPattern(pattern, captureDetails, true); - } + /// + /// Remove invalid characters from the path + /// + /// string with the full path to a file + /// string with the full path to a file, without invalid characters + public static string MakePathSafe(string path) + { + // Make the path save! + if (path != null) + { + foreach (char disallowed in Path.GetInvalidPathChars()) + { + path = path.Replace(disallowed.ToString(), UnsafeReplacement); + } + } - public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat) { - return GetFilenameFromPattern(pattern, imageFormat, null); - } + return path; + } - public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat, ICaptureDetails captureDetails) { - return FillPattern(pattern, captureDetails, true) + "." + imageFormat.ToString().ToLower(); - } + public static string GetFilenameWithoutExtensionFromPattern(string pattern) + { + return GetFilenameWithoutExtensionFromPattern(pattern, null); + } - /// - /// Return a filename for the current image format (png,jpg etc) with the default file pattern - /// that is specified in the configuration - /// - /// A string with the format - /// - /// The filename which should be used to save the image - public static string GetFilename(OutputFormat format, ICaptureDetails captureDetails) { - string pattern = CoreConfig.OutputFileFilenamePattern; - if (string.IsNullOrEmpty(pattern?.Trim())) { - pattern = "greenshot ${capturetime}"; - } - return GetFilenameFromPattern(pattern, format, captureDetails); - } + public static string GetFilenameWithoutExtensionFromPattern(string pattern, ICaptureDetails captureDetails) + { + return FillPattern(pattern, captureDetails, true); + } + + public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat) + { + return GetFilenameFromPattern(pattern, imageFormat, null); + } + + public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat, ICaptureDetails captureDetails) + { + return FillPattern(pattern, captureDetails, true) + "." + imageFormat.ToString().ToLower(); + } + + /// + /// Return a filename for the current image format (png,jpg etc) with the default file pattern + /// that is specified in the configuration + /// + /// A string with the format + /// + /// The filename which should be used to save the image + public static string GetFilename(OutputFormat format, ICaptureDetails captureDetails) + { + string pattern = CoreConfig.OutputFileFilenamePattern; + if (string.IsNullOrEmpty(pattern?.Trim())) + { + pattern = "greenshot ${capturetime}"; + } + + return GetFilenameFromPattern(pattern, format, captureDetails); + } - /// - /// This method will be called by the regexp.replace as a MatchEvaluator delegate! - /// Will delegate this to the MatchVarEvaluatorInternal and catch any exceptions - /// - /// What are we matching? - /// The detail, can be null - /// Variables from the process - /// Variables from the user - /// Variables from the machine - /// - /// string with the match replacement - private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, bool filenameSafeMode) { - try { - return MatchVarEvaluatorInternal(match, captureDetails, processVars, userVars, machineVars, filenameSafeMode); - } catch (Exception e) { - Log.Error("Error in MatchVarEvaluatorInternal", e); - } - return string.Empty; - } + /// + /// This method will be called by the regexp.replace as a MatchEvaluator delegate! + /// Will delegate this to the MatchVarEvaluatorInternal and catch any exceptions + /// + /// What are we matching? + /// The detail, can be null + /// Variables from the process + /// Variables from the user + /// Variables from the machine + /// + /// string with the match replacement + private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, + bool filenameSafeMode) + { + try + { + return MatchVarEvaluatorInternal(match, captureDetails, processVars, userVars, machineVars, filenameSafeMode); + } + catch (Exception e) + { + Log.Error("Error in MatchVarEvaluatorInternal", e); + } - /// - /// This method will be called by the regexp.replace as a MatchEvaluator delegate! - /// - /// What are we matching? - /// The detail, can be null - /// - /// - /// - /// - /// - private static string MatchVarEvaluatorInternal(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, bool filenameSafeMode) { - // some defaults - int padWidth = 0; - int startIndex = 0; - int endIndex = 0; - char padChar = ' '; - string dateFormat = "yyyy-MM-dd HH-mm-ss"; - IDictionary replacements = new Dictionary(); - string replaceValue = string.Empty; - string variable = match.Groups["variable"].Value; - string parameters = match.Groups["parameters"].Value; - string randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + return string.Empty; + } - if (parameters.Length > 0) { - string[] parms = SplitRegexp.Split(parameters); - foreach (string parameter in parms) { - switch (parameter.Substring(0, 1)) { - // Padding p[,pad-character] - case "p": - string[] padParams = parameter.Substring(1).Split(','); - try { - padWidth = int.Parse(padParams[0]); - } - catch - { - // ignored - } - if (padParams.Length > 1) { - padChar = padParams[1][0]; - } - break; - // replace - // r, - case "r": - string[] replaceParameters = parameter.Substring(1).Split(','); - if (replaceParameters != null && replaceParameters.Length == 2) { - replacements.Add(replaceParameters[0], replaceParameters[1]); - } - break; - // Dateformat d - // Format can be anything that is used in C# date formatting - case "d": - dateFormat = parameter.Substring(1); - if (dateFormat.StartsWith("\"")) { - dateFormat = dateFormat.Substring(1); - } - if (dateFormat.EndsWith("\"")) { - dateFormat = dateFormat.Substring(0, dateFormat.Length - 1); - } - break; - // Substring: - // s[,length] - case "s": - string range = parameter.Substring(1); - string[] rangelist = range.Split(','); - if (rangelist.Length > 0) { - try { - startIndex = int.Parse(rangelist[0]); - } catch { - // Ignore - } - } - if (rangelist.Length > 1) { - try { - endIndex = int.Parse(rangelist[1]); - } catch { - // Ignore - } - } - break; - } - } - } - if (processVars != null && processVars.Contains(variable)) { - replaceValue = (string)processVars[variable]; - if (filenameSafeMode) { - replaceValue = MakePathSafe(replaceValue); - } - } else if (userVars != null && userVars.Contains(variable)) { - replaceValue = (string)userVars[variable]; - if (filenameSafeMode) { - replaceValue = MakePathSafe(replaceValue); - } - } else if (machineVars != null && machineVars.Contains(variable)) { - replaceValue = (string)machineVars[variable]; - if (filenameSafeMode) { - replaceValue = MakePathSafe(replaceValue); - } - } else if (captureDetails?.MetaData != null && captureDetails.MetaData.ContainsKey(variable)) { - replaceValue = captureDetails.MetaData[variable]; - if (filenameSafeMode) { - replaceValue = MakePathSafe(replaceValue); - } - } else if (RandRegexp.IsMatch(variable)) { - for (int i = 0; i < variable.Length; i++) { - replaceValue += randomChars[RandomNumberGen.Next(randomChars.Length)]; - } - } else { - // Handle other variables - // Default use "now" for the capture take´n - DateTime capturetime = DateTime.Now; - // Use default application name for title - string title = Application.ProductName; + /// + /// This method will be called by the regexp.replace as a MatchEvaluator delegate! + /// + /// What are we matching? + /// The detail, can be null + /// + /// + /// + /// + /// + private static string MatchVarEvaluatorInternal(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, + bool filenameSafeMode) + { + // some defaults + int padWidth = 0; + int startIndex = 0; + int endIndex = 0; + char padChar = ' '; + string dateFormat = "yyyy-MM-dd HH-mm-ss"; + IDictionary replacements = new Dictionary(); + string replaceValue = string.Empty; + string variable = match.Groups["variable"].Value; + string parameters = match.Groups["parameters"].Value; + string randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - // Check if we have capture details - if (captureDetails != null) { - capturetime = captureDetails.DateTime; - if (captureDetails.Title != null) { - title = captureDetails.Title; - if (title.Length > MaxTitleLength) { - title = title.Substring(0, MaxTitleLength); - } - } - } - switch (variable) { - case "domain": - replaceValue = Environment.UserDomainName; - break; - case "user": - replaceValue = Environment.UserName; - break; - case "hostname": - replaceValue = Environment.MachineName; - break; - case "YYYY": - if (padWidth == 0) { - padWidth = -4; - padChar = '0'; - } - replaceValue = capturetime.Year.ToString(); - break; - case "MM": - replaceValue = capturetime.Month.ToString(); - if (padWidth == 0) { - padWidth = -2; - padChar = '0'; - } - break; - case "DD": - replaceValue = capturetime.Day.ToString(); - if (padWidth == 0) { - padWidth = -2; - padChar = '0'; - } - break; - case "hh": - if (padWidth == 0) { - padWidth = -2; - padChar = '0'; - } - replaceValue = capturetime.Hour.ToString(); - break; - case "mm": - if (padWidth == 0) { - padWidth = -2; - padChar = '0'; - } - replaceValue = capturetime.Minute.ToString(); - break; - case "ss": - if (padWidth == 0) { - padWidth = -2; - padChar = '0'; - } - replaceValue = capturetime.Second.ToString(); - break; - case "now": - replaceValue = DateTime.Now.ToString(dateFormat); - if (filenameSafeMode) { - replaceValue = MakeFilenameSafe(replaceValue); - } - break; - case "capturetime": - replaceValue = capturetime.ToString(dateFormat); - if (filenameSafeMode) { - replaceValue = MakeFilenameSafe(replaceValue); - } - break; - case "NUM": - CoreConfig.OutputFileIncrementingNumber++; - IniConfig.Save(); - replaceValue = CoreConfig.OutputFileIncrementingNumber.ToString(); - if (padWidth == 0) { - padWidth = -6; - padChar = '0'; - } + if (parameters.Length > 0) + { + string[] parms = SplitRegexp.Split(parameters); + foreach (string parameter in parms) + { + switch (parameter.Substring(0, 1)) + { + // Padding p[,pad-character] + case "p": + string[] padParams = parameter.Substring(1).Split(','); + try + { + padWidth = int.Parse(padParams[0]); + } + catch + { + // ignored + } - break; - case "title": - replaceValue = title; - if (filenameSafeMode) { - replaceValue = MakeFilenameSafe(replaceValue); - } - break; - case "MyPictures": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); - break; - case "MyMusic": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic); - break; - case "MyDocuments": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); - break; - case "Personal": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Personal); - break; - case "Desktop": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); - break; - case "ApplicationData": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - break; - case "LocalApplicationData": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - break; - } - } - // do padding - if (padWidth > 0) { - replaceValue = replaceValue.PadRight(padWidth, padChar); - } else if (padWidth < 0) { - replaceValue = replaceValue.PadLeft(-padWidth, padChar); - } + if (padParams.Length > 1) + { + padChar = padParams[1][0]; + } - // do substring - if (startIndex != 0 || endIndex != 0) { - if (startIndex < 0) { - startIndex = replaceValue.Length + startIndex; - } - if (endIndex < 0) { - endIndex = replaceValue.Length + endIndex; - } - if (endIndex != 0) { - try { - replaceValue = replaceValue.Substring(startIndex, endIndex); - } catch { - // Ignore - } - } else { - try { - replaceValue = replaceValue.Substring(startIndex); - } catch { - // Ignore - } - } - } + break; + // replace + // r, + case "r": + string[] replaceParameters = parameter.Substring(1).Split(','); + if (replaceParameters != null && replaceParameters.Length == 2) + { + replacements.Add(replaceParameters[0], replaceParameters[1]); + } - // new for feature #697 - if (replacements.Count > 0) { - foreach (string oldValue in replacements.Keys) { - replaceValue = replaceValue.Replace(oldValue, replacements[oldValue]); - } - } - return replaceValue; - } + break; + // Dateformat d + // Format can be anything that is used in C# date formatting + case "d": + dateFormat = parameter.Substring(1); + if (dateFormat.StartsWith("\"")) + { + dateFormat = dateFormat.Substring(1); + } - /// - /// "Simply" fill the pattern with environment variables - /// - /// String with pattern %var% - /// true to make sure everything is filenamesafe - /// Filled string - public static string FillCmdVariables(string pattern, bool filenameSafeMode = true) - { - IDictionary processVars = null; - IDictionary userVars = null; - IDictionary machineVars = null; - try - { - processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); - } + if (dateFormat.EndsWith("\"")) + { + dateFormat = dateFormat.Substring(0, dateFormat.Length - 1); + } - try - { - userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.User", e); - } + break; + // Substring: + // s[,length] + case "s": + string range = parameter.Substring(1); + string[] rangelist = range.Split(','); + if (rangelist.Length > 0) + { + try + { + startIndex = int.Parse(rangelist[0]); + } + catch + { + // Ignore + } + } - try - { - machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); - } + if (rangelist.Length > 1) + { + try + { + endIndex = int.Parse(rangelist[1]); + } + catch + { + // Ignore + } + } - return CmdVarRegexp.Replace(pattern, - m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) - ); - } + break; + } + } + } - /// - /// "Simply" fill the pattern with environment variables - /// - /// String with pattern ${var} - /// true to make sure everything is filenamesafe - /// Filled string - public static string FillVariables(string pattern, bool filenameSafeMode) { - IDictionary processVars = null; - IDictionary userVars = null; - IDictionary machineVars = null; - try { - processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); - } + if (processVars != null && processVars.Contains(variable)) + { + replaceValue = (string) processVars[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (userVars != null && userVars.Contains(variable)) + { + replaceValue = (string) userVars[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (machineVars != null && machineVars.Contains(variable)) + { + replaceValue = (string) machineVars[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (captureDetails?.MetaData != null && captureDetails.MetaData.ContainsKey(variable)) + { + replaceValue = captureDetails.MetaData[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (RandRegexp.IsMatch(variable)) + { + for (int i = 0; i < variable.Length; i++) + { + replaceValue += randomChars[RandomNumberGen.Next(randomChars.Length)]; + } + } + else + { + // Handle other variables + // Default use "now" for the capture take´n + DateTime capturetime = DateTime.Now; + // Use default application name for title + string title = Application.ProductName; - try { - userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.User", e); - } + // Check if we have capture details + if (captureDetails != null) + { + capturetime = captureDetails.DateTime; + if (captureDetails.Title != null) + { + title = captureDetails.Title; + if (title.Length > MaxTitleLength) + { + title = title.Substring(0, MaxTitleLength); + } + } + } - try { - machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); - } + switch (variable) + { + case "domain": + replaceValue = Environment.UserDomainName; + break; + case "user": + replaceValue = Environment.UserName; + break; + case "hostname": + replaceValue = Environment.MachineName; + break; + case "YYYY": + if (padWidth == 0) + { + padWidth = -4; + padChar = '0'; + } - return VarRegexp.Replace(pattern, - m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) - ); - } + replaceValue = capturetime.Year.ToString(); + break; + case "MM": + replaceValue = capturetime.Month.ToString(); + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } - /// - /// Fill the pattern wit the supplied details - /// - /// Pattern - /// CaptureDetails, can be null - /// Should the result be made "filename" safe? - /// Filled pattern - public static string FillPattern(string pattern, ICaptureDetails captureDetails, bool filenameSafeMode) { - IDictionary processVars = null; - IDictionary userVars = null; - IDictionary machineVars = null; - try { - processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); - } + break; + case "DD": + replaceValue = capturetime.Day.ToString(); + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } - try { - userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.User", e); - } + break; + case "hh": + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } - try { - machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); - } + replaceValue = capturetime.Hour.ToString(); + break; + case "mm": + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } - try { - return VarRegexp.Replace(pattern, - m => MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars, filenameSafeMode) - ); - } catch (Exception e) { - // adding additional data for bug tracking - if (captureDetails != null) { - e.Data.Add("title", captureDetails.Title); - } - e.Data.Add("pattern", pattern); - throw; - } - } + replaceValue = capturetime.Minute.ToString(); + break; + case "ss": + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } - /// - /// Checks whether a directory name is valid in the current file system - /// - /// directory name (not path!) - /// true if directory name is valid - public static bool IsDirectoryNameValid(string directoryName) { - var forbiddenChars = Path.GetInvalidPathChars(); - foreach (var forbiddenChar in forbiddenChars) { - if (directoryName == null || directoryName.Contains(forbiddenChar.ToString())) { - return false; - } - } - return true; - } + replaceValue = capturetime.Second.ToString(); + break; + case "now": + replaceValue = DateTime.Now.ToString(dateFormat); + if (filenameSafeMode) + { + replaceValue = MakeFilenameSafe(replaceValue); + } - /// - /// Checks whether a filename is valid in the current file system - /// - /// name of the file - /// true if filename is valid - public static bool IsFilenameValid(string filename) { - var forbiddenChars = Path.GetInvalidFileNameChars(); - foreach (var forbiddenChar in forbiddenChars) { - if (filename == null || filename.Contains(forbiddenChar.ToString())) { - return false; - } - } - return true; - } - } -} + break; + case "capturetime": + replaceValue = capturetime.ToString(dateFormat); + if (filenameSafeMode) + { + replaceValue = MakeFilenameSafe(replaceValue); + } + + break; + case "NUM": + CoreConfig.OutputFileIncrementingNumber++; + IniConfig.Save(); + replaceValue = CoreConfig.OutputFileIncrementingNumber.ToString(); + if (padWidth == 0) + { + padWidth = -6; + padChar = '0'; + } + + break; + case "title": + replaceValue = title; + if (filenameSafeMode) + { + replaceValue = MakeFilenameSafe(replaceValue); + } + + break; + case "MyPictures": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); + break; + case "MyMusic": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic); + break; + case "MyDocuments": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + break; + case "Personal": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Personal); + break; + case "Desktop": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + break; + case "ApplicationData": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + break; + case "LocalApplicationData": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + break; + } + } + + // do padding + if (padWidth > 0) + { + replaceValue = replaceValue.PadRight(padWidth, padChar); + } + else if (padWidth < 0) + { + replaceValue = replaceValue.PadLeft(-padWidth, padChar); + } + + // do substring + if (startIndex != 0 || endIndex != 0) + { + if (startIndex < 0) + { + startIndex = replaceValue.Length + startIndex; + } + + if (endIndex < 0) + { + endIndex = replaceValue.Length + endIndex; + } + + if (endIndex != 0) + { + try + { + replaceValue = replaceValue.Substring(startIndex, endIndex); + } + catch + { + // Ignore + } + } + else + { + try + { + replaceValue = replaceValue.Substring(startIndex); + } + catch + { + // Ignore + } + } + } + + // new for feature #697 + if (replacements.Count > 0) + { + foreach (string oldValue in replacements.Keys) + { + replaceValue = replaceValue.Replace(oldValue, replacements[oldValue]); + } + } + + return replaceValue; + } + + /// + /// "Simply" fill the pattern with environment variables + /// + /// String with pattern %var% + /// true to make sure everything is filenamesafe + /// Filled string + public static string FillCmdVariables(string pattern, bool filenameSafeMode = true) + { + IDictionary processVars = null; + IDictionary userVars = null; + IDictionary machineVars = null; + try + { + processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); + } + + try + { + userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.User", e); + } + + try + { + machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); + } + + return CmdVarRegexp.Replace(pattern, + m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) + ); + } + + /// + /// "Simply" fill the pattern with environment variables + /// + /// String with pattern ${var} + /// true to make sure everything is filenamesafe + /// Filled string + public static string FillVariables(string pattern, bool filenameSafeMode) + { + IDictionary processVars = null; + IDictionary userVars = null; + IDictionary machineVars = null; + try + { + processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); + } + + try + { + userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.User", e); + } + + try + { + machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); + } + + return VarRegexp.Replace(pattern, + m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) + ); + } + + /// + /// Fill the pattern wit the supplied details + /// + /// Pattern + /// CaptureDetails, can be null + /// Should the result be made "filename" safe? + /// Filled pattern + public static string FillPattern(string pattern, ICaptureDetails captureDetails, bool filenameSafeMode) + { + IDictionary processVars = null; + IDictionary userVars = null; + IDictionary machineVars = null; + try + { + processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); + } + + try + { + userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.User", e); + } + + try + { + machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); + } + + try + { + return VarRegexp.Replace(pattern, + m => MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars, filenameSafeMode) + ); + } + catch (Exception e) + { + // adding additional data for bug tracking + if (captureDetails != null) + { + e.Data.Add("title", captureDetails.Title); + } + + e.Data.Add("pattern", pattern); + throw; + } + } + + /// + /// Checks whether a directory name is valid in the current file system + /// + /// directory name (not path!) + /// true if directory name is valid + public static bool IsDirectoryNameValid(string directoryName) + { + var forbiddenChars = Path.GetInvalidPathChars(); + foreach (var forbiddenChar in forbiddenChars) + { + if (directoryName == null || directoryName.Contains(forbiddenChar.ToString())) + { + return false; + } + } + + return true; + } + + /// + /// Checks whether a filename is valid in the current file system + /// + /// name of the file + /// true if filename is valid + public static bool IsFilenameValid(string filename) + { + var forbiddenChars = Path.GetInvalidFileNameChars(); + foreach (var forbiddenChar in forbiddenChars) + { + if (filename == null || filename.Contains(forbiddenChar.ToString())) + { + return false; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Fraction.cs b/src/GreenshotPlugin/Core/Fraction.cs index 312b91bb8..94c4fddf4 100644 --- a/src/GreenshotPlugin/Core/Fraction.cs +++ b/src/GreenshotPlugin/Core/Fraction.cs @@ -19,10 +19,12 @@ namespace GreenshotPlugin.Core { throw new ArgumentException("Can't divide by zero.", nameof(denominator)); } + if (numerator == 0) { throw new ArgumentException("Zero is not supported by this implementation.", nameof(numerator)); } + var gcd = GreatestCommonDivisor(numerator, denominator); Numerator = numerator / gcd; Denominator = denominator / gcd; @@ -34,6 +36,7 @@ namespace GreenshotPlugin.Core #region Parse private static readonly Regex PARSE_REGEX = new Regex(@"^([1-9][0-9]*)\/([1-9][0-9]*)$", RegexOptions.Compiled); + public static bool TryParse(string str, out Fraction result) { var match = PARSE_REGEX.Match(str); @@ -42,6 +45,7 @@ namespace GreenshotPlugin.Core result = Identity; return false; } + var numerator = uint.Parse(match.Groups[1].Value); var denominator = uint.Parse(match.Groups[2].Value); result = new Fraction(numerator, denominator); @@ -78,7 +82,7 @@ namespace GreenshotPlugin.Core } public int CompareTo(Fraction other) - => (int)(Numerator * other.Denominator) - (int)(other.Numerator * Denominator); + => (int) (Numerator * other.Denominator) - (int) (other.Numerator * Denominator); #endregion @@ -149,4 +153,4 @@ namespace GreenshotPlugin.Core private static uint GreatestCommonDivisor(uint a, uint b) => (b != 0) ? GreatestCommonDivisor(b, a % b) : a; } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/GreenshotResources.cs b/src/GreenshotPlugin/Core/GreenshotResources.cs index 6b80acf3f..b4de5d007 100644 --- a/src/GreenshotPlugin/Core/GreenshotResources.cs +++ b/src/GreenshotPlugin/Core/GreenshotResources.cs @@ -18,26 +18,32 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.ComponentModel; using System.Drawing; -namespace GreenshotPlugin.Core { - /// - /// Centralized storage of the icons & bitmaps - /// - public static class GreenshotResources { - private static readonly ComponentResourceManager GreenshotResourceManager = new ComponentResourceManager(typeof(GreenshotResources)); +namespace GreenshotPlugin.Core +{ + /// + /// Centralized storage of the icons & bitmaps + /// + public static class GreenshotResources + { + private static readonly ComponentResourceManager GreenshotResourceManager = new ComponentResourceManager(typeof(GreenshotResources)); - public static Image GetImage(string imageName) { - return (Image)GreenshotResourceManager.GetObject(imageName); - } - public static Icon GetIcon(string imageName) { - return (Icon)GreenshotResourceManager.GetObject(imageName); - } + public static Image GetImage(string imageName) + { + return (Image) GreenshotResourceManager.GetObject(imageName); + } - public static Icon GetGreenshotIcon() { - return GetIcon("Greenshot.Icon"); - } + public static Icon GetIcon(string imageName) + { + return (Icon) GreenshotResourceManager.GetObject(imageName); + } - } -} + public static Icon GetGreenshotIcon() + { + return GetIcon("Greenshot.Icon"); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/HResultExtensions.cs b/src/GreenshotPlugin/Core/HResultExtensions.cs index 450636ef7..891f48908 100644 --- a/src/GreenshotPlugin/Core/HResultExtensions.cs +++ b/src/GreenshotPlugin/Core/HResultExtensions.cs @@ -49,4 +49,4 @@ namespace GreenshotPlugin.Core return hResult >= HResult.S_OK; } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/IEHelper.cs b/src/GreenshotPlugin/Core/IEHelper.cs index 2a85958fc..5fb52032f 100644 --- a/src/GreenshotPlugin/Core/IEHelper.cs +++ b/src/GreenshotPlugin/Core/IEHelper.cs @@ -26,164 +26,178 @@ using System.Reflection; using log4net; using Microsoft.Win32; -namespace GreenshotPlugin.Core { - /// - /// Description of IEHelper. - /// - public static class IEHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(IEHelper)); - // Internet explorer Registry key - private const string IeKey = @"Software\Microsoft\Internet Explorer"; +namespace GreenshotPlugin.Core +{ + /// + /// Description of IEHelper. + /// + public static class IEHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IEHelper)); - /// - /// Get the current browser version - /// - /// int with browser version - public static int IEVersion - { - get - { - var maxVer = 7; - using (var ieKey = Registry.LocalMachine.OpenSubKey(IeKey, false)) - { - foreach (var value in new[] { "svcVersion", "svcUpdateVersion", "Version", "W2kVersion" }) - { - var objVal = ieKey.GetValue(value, "0"); - var strVal = Convert.ToString(objVal); + // Internet explorer Registry key + private const string IeKey = @"Software\Microsoft\Internet Explorer"; - var iPos = strVal.IndexOf('.'); - if (iPos > 0) - { - strVal = strVal.Substring(0, iPos); - } + /// + /// Get the current browser version + /// + /// int with browser version + public static int IEVersion + { + get + { + var maxVer = 7; + using (var ieKey = Registry.LocalMachine.OpenSubKey(IeKey, false)) + { + foreach (var value in new[] + { + "svcVersion", "svcUpdateVersion", "Version", "W2kVersion" + }) + { + var objVal = ieKey.GetValue(value, "0"); + var strVal = Convert.ToString(objVal); + + var iPos = strVal.IndexOf('.'); + if (iPos > 0) + { + strVal = strVal.Substring(0, iPos); + } if (int.TryParse(strVal, out var res)) - { - maxVer = Math.Max(maxVer, res); - } - } - } + { + maxVer = Math.Max(maxVer, res); + } + } + } - return maxVer; - } - } + return maxVer; + } + } - /// - /// Get the highest possible version for the embedded browser - /// - /// true to ignore the doctype when loading a page - /// IE Feature - public static int GetEmbVersion(bool ignoreDoctype = true) - { - var ieVersion = IEVersion; + /// + /// Get the highest possible version for the embedded browser + /// + /// true to ignore the doctype when loading a page + /// IE Feature + public static int GetEmbVersion(bool ignoreDoctype = true) + { + var ieVersion = IEVersion; - if (ieVersion > 9) - { - return ieVersion * 1000 + (ignoreDoctype ? 1 : 0); - } + if (ieVersion > 9) + { + return ieVersion * 1000 + (ignoreDoctype ? 1 : 0); + } - if (ieVersion > 7) - { - return ieVersion * 1111; - } + if (ieVersion > 7) + { + return ieVersion * 1111; + } - return 7000; - } + return 7000; + } - /// - /// Fix browser version to the highest possible - /// - /// true to ignore the doctype when loading a page - public static void FixBrowserVersion(bool ignoreDoctype = true) - { - var applicationName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location); - FixBrowserVersion(applicationName, ignoreDoctype); - } + /// + /// Fix browser version to the highest possible + /// + /// true to ignore the doctype when loading a page + public static void FixBrowserVersion(bool ignoreDoctype = true) + { + var applicationName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location); + FixBrowserVersion(applicationName, ignoreDoctype); + } - /// - /// Fix the browser version for the specified application - /// - /// Name of the process - /// true to ignore the doctype when loading a page - public static void FixBrowserVersion(string applicationName, bool ignoreDoctype = true) - { - FixBrowserVersion(applicationName, GetEmbVersion(ignoreDoctype)); - } + /// + /// Fix the browser version for the specified application + /// + /// Name of the process + /// true to ignore the doctype when loading a page + public static void FixBrowserVersion(string applicationName, bool ignoreDoctype = true) + { + FixBrowserVersion(applicationName, GetEmbVersion(ignoreDoctype)); + } - /// - /// Fix the browser version for the specified application - /// - /// Name of the process - /// - /// Version, see - /// Browser Emulation - /// - public static void FixBrowserVersion(string applicationName, int ieVersion) - { - ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".exe", ieVersion); + /// + /// Fix the browser version for the specified application + /// + /// Name of the process + /// + /// Version, see + /// Browser Emulation + /// + public static void FixBrowserVersion(string applicationName, int ieVersion) + { + ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".exe", ieVersion); #if DEBUG ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".vshost.exe", ieVersion); #endif - } + } - /// - /// Make the change to the registry - /// - /// HKEY_CURRENT_USER or something - /// Name of the executable - /// Version to use - private static void ModifyRegistry(string root, string applicationName, int ieFeatureVersion) - { - var regKey = root + @"\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION"; - try - { - Registry.SetValue(regKey, applicationName, ieFeatureVersion); - } - catch (Exception ex) - { - // some config will hit access rights exceptions - // this is why we try with both LOCAL_MACHINE and CURRENT_USER - Log.Error(ex); - Log.ErrorFormat("couldn't modify the registry key {0}", regKey); - } - } + /// + /// Make the change to the registry + /// + /// HKEY_CURRENT_USER or something + /// Name of the executable + /// Version to use + private static void ModifyRegistry(string root, string applicationName, int ieFeatureVersion) + { + var regKey = root + @"\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION"; + try + { + Registry.SetValue(regKey, applicationName, ieFeatureVersion); + } + catch (Exception ex) + { + // some config will hit access rights exceptions + // this is why we try with both LOCAL_MACHINE and CURRENT_USER + Log.Error(ex); + Log.ErrorFormat("couldn't modify the registry key {0}", regKey); + } + } - /// - /// Find the DirectUI window for MSAA (Accessible) - /// - /// The browser WindowDetails - /// WindowDetails for the DirectUI window - public static WindowDetails GetDirectUI(WindowDetails browserWindowDetails) { - if (browserWindowDetails == null) { - return null; - } - WindowDetails tmpWd = browserWindowDetails; - // Since IE 9 the TabBandClass is less deep! - if (IEVersion < 9) { - tmpWd = tmpWd.GetChild("CommandBarClass"); - tmpWd = tmpWd?.GetChild("ReBarWindow32"); - } - tmpWd = tmpWd?.GetChild("TabBandClass"); - tmpWd = tmpWd?.GetChild("DirectUIHWND"); - return tmpWd; - } - - /// - /// Return an IEnumerable with the currently opened IE urls - /// - /// - public static IEnumerable GetIEUrls() { - // Find the IE window - foreach (WindowDetails ieWindow in WindowDetails.GetAllWindows("IEFrame")) { - WindowDetails directUIWD = GetDirectUI(ieWindow); - if (directUIWD != null) { - Accessible ieAccessible = new Accessible(directUIWD.Handle); - foreach(string url in ieAccessible.IETabUrls) - { - yield return url; - } - } - } - } - } -} + /// + /// Find the DirectUI window for MSAA (Accessible) + /// + /// The browser WindowDetails + /// WindowDetails for the DirectUI window + public static WindowDetails GetDirectUI(WindowDetails browserWindowDetails) + { + if (browserWindowDetails == null) + { + return null; + } + + WindowDetails tmpWd = browserWindowDetails; + // Since IE 9 the TabBandClass is less deep! + if (IEVersion < 9) + { + tmpWd = tmpWd.GetChild("CommandBarClass"); + tmpWd = tmpWd?.GetChild("ReBarWindow32"); + } + + tmpWd = tmpWd?.GetChild("TabBandClass"); + tmpWd = tmpWd?.GetChild("DirectUIHWND"); + return tmpWd; + } + + /// + /// Return an IEnumerable with the currently opened IE urls + /// + /// + public static IEnumerable GetIEUrls() + { + // Find the IE window + foreach (WindowDetails ieWindow in WindowDetails.GetAllWindows("IEFrame")) + { + WindowDetails directUIWD = GetDirectUI(ieWindow); + if (directUIWD != null) + { + Accessible ieAccessible = new Accessible(directUIWD.Handle); + foreach (string url in ieAccessible.IETabUrls) + { + yield return url; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/IImage.cs b/src/GreenshotPlugin/Core/IImage.cs index 710a0d04d..ffeff3d24 100644 --- a/src/GreenshotPlugin/Core/IImage.cs +++ b/src/GreenshotPlugin/Core/IImage.cs @@ -25,44 +25,44 @@ using System.Drawing.Imaging; namespace GreenshotPlugin.Core { - /// - /// The image interface, this abstracts an image - /// - public interface IImage : IDisposable - { - /// - /// Height of the image, can be set to change - /// - int Height { get; set; } + /// + /// The image interface, this abstracts an image + /// + public interface IImage : IDisposable + { + /// + /// Height of the image, can be set to change + /// + int Height { get; set; } - /// - /// Width of the image, can be set to change. - /// - int Width { get; set; } + /// + /// Width of the image, can be set to change. + /// + int Width { get; set; } - /// - /// Size of the image - /// - Size Size { get; } + /// + /// Size of the image + /// + Size Size { get; } - /// - /// Pixelformat of the underlying image - /// - PixelFormat PixelFormat { get; } + /// + /// Pixelformat of the underlying image + /// + PixelFormat PixelFormat { get; } - /// - /// Vertical resolution of the underlying image - /// - float VerticalResolution { get; } + /// + /// Vertical resolution of the underlying image + /// + float VerticalResolution { get; } - /// - /// Horizontal resolution of the underlying image - /// - float HorizontalResolution { get; } + /// + /// Horizontal resolution of the underlying image + /// + float HorizontalResolution { get; } - /// - /// Unterlying image, or an on demand rendered version with different attributes as the original - /// - Image Image { get; } - } -} + /// + /// Unterlying image, or an on demand rendered version with different attributes as the original + /// + Image Image { get; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/ImageHelper.cs b/src/GreenshotPlugin/Core/ImageHelper.cs index 0f19462bd..d6263813c 100644 --- a/src/GreenshotPlugin/Core/ImageHelper.cs +++ b/src/GreenshotPlugin/Core/ImageHelper.cs @@ -31,34 +31,37 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using log4net; -namespace GreenshotPlugin.Core { - internal enum ExifOrientations : byte { - Unknown = 0, - TopLeft = 1, - TopRight = 2, - BottomRight = 3, - BottomLeft = 4, - LeftTop = 5, - RightTop = 6, - RightBottom = 7, - LeftBottom = 8, - } +namespace GreenshotPlugin.Core +{ + internal enum ExifOrientations : byte + { + Unknown = 0, + TopLeft = 1, + TopRight = 2, + BottomRight = 3, + BottomLeft = 4, + LeftTop = 5, + RightTop = 6, + RightBottom = 7, + LeftBottom = 8, + } - /// - /// Description of ImageHelper. - /// - public static class ImageHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const int ExifOrientationId = 0x0112; + /// + /// Description of ImageHelper. + /// + public static class ImageHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private const int ExifOrientationId = 0x0112; static ImageHelper() - { - StreamConverters["greenshot"] = (stream, s) => - { - var surface = SimpleServiceProvider.Current.GetInstance>().Invoke(); - return surface.GetImageForExport(); - }; + { + StreamConverters["greenshot"] = (stream, s) => + { + var surface = SimpleServiceProvider.Current.GetInstance>().Invoke(); + return surface.GetImageForExport(); + }; // Add a SVG converter StreamConverters["svg"] = (stream, s) => @@ -72,10 +75,11 @@ namespace GreenshotPlugin.Core { { Log.Error("Can't load SVG", ex); } + return null; }; - static Image DefaultConverter(Stream stream, string s) + static Image DefaultConverter(Stream stream, string s) { stream.Position = 0; using var tmpImage = Image.FromStream(stream, true, true); @@ -84,18 +88,18 @@ namespace GreenshotPlugin.Core { } // Fallback - StreamConverters[string.Empty] = DefaultConverter; - StreamConverters["gif"] = DefaultConverter; - StreamConverters["bmp"] = DefaultConverter; - StreamConverters["jpg"] = DefaultConverter; - StreamConverters["jpeg"] = DefaultConverter; - StreamConverters["png"] = DefaultConverter; - StreamConverters["wmf"] = DefaultConverter; + StreamConverters[string.Empty] = DefaultConverter; + StreamConverters["gif"] = DefaultConverter; + StreamConverters["bmp"] = DefaultConverter; + StreamConverters["jpg"] = DefaultConverter; + StreamConverters["jpeg"] = DefaultConverter; + StreamConverters["png"] = DefaultConverter; + StreamConverters["wmf"] = DefaultConverter; - StreamConverters["ico"] = (stream, extension) => - { - // Icon logic, try to get the Vista icon, else the biggest possible - try + StreamConverters["ico"] = (stream, extension) => + { + // Icon logic, try to get the Vista icon, else the biggest possible + try { using Image tmpImage = ExtractVistaIcon(stream); if (tmpImage != null) @@ -103,529 +107,564 @@ namespace GreenshotPlugin.Core { return Clone(tmpImage, PixelFormat.Format32bppArgb); } } - catch (Exception vistaIconException) - { - Log.Warn("Can't read icon", vistaIconException); - } - try - { - // No vista icon, try normal icon - stream.Position = 0; - // We create a copy of the bitmap, so everything else can be disposed + catch (Exception vistaIconException) + { + Log.Warn("Can't read icon", vistaIconException); + } + + try + { + // No vista icon, try normal icon + stream.Position = 0; + // We create a copy of the bitmap, so everything else can be disposed using Icon tmpIcon = new Icon(stream, new Size(1024, 1024)); using Image tmpImage = tmpIcon.ToBitmap(); return Clone(tmpImage, PixelFormat.Format32bppArgb); } - catch (Exception iconException) - { - Log.Warn("Can't read icon", iconException); - } + catch (Exception iconException) + { + Log.Warn("Can't read icon", iconException); + } - stream.Position = 0; - return DefaultConverter(stream, extension); - }; - } + stream.Position = 0; + return DefaultConverter(stream, extension); + }; + } - public static IDictionary> StreamConverters { get; } = new Dictionary>(); + public static IDictionary> StreamConverters { get; } = new Dictionary>(); - /// - /// Make sure the image is orientated correctly - /// - /// - public static void Orientate(Image image) - { - if (!CoreConfig.ProcessEXIFOrientation) - { - return; - } - try - { - // Get the index of the orientation property. - int orientationIndex = Array.IndexOf(image.PropertyIdList, ExifOrientationId); - // If there is no such property, return Unknown. - if (orientationIndex < 0) - { - return; - } - PropertyItem item = image.GetPropertyItem(ExifOrientationId); + /// + /// Make sure the image is orientated correctly + /// + /// + public static void Orientate(Image image) + { + if (!CoreConfig.ProcessEXIFOrientation) + { + return; + } - ExifOrientations orientation = (ExifOrientations)item.Value[0]; - // Orient the image. - switch (orientation) - { - case ExifOrientations.Unknown: - case ExifOrientations.TopLeft: - break; - case ExifOrientations.TopRight: - image.RotateFlip(RotateFlipType.RotateNoneFlipX); - break; - case ExifOrientations.BottomRight: - image.RotateFlip(RotateFlipType.Rotate180FlipNone); - break; - case ExifOrientations.BottomLeft: - image.RotateFlip(RotateFlipType.RotateNoneFlipY); - break; - case ExifOrientations.LeftTop: - image.RotateFlip(RotateFlipType.Rotate90FlipX); - break; - case ExifOrientations.RightTop: - image.RotateFlip(RotateFlipType.Rotate90FlipNone); - break; - case ExifOrientations.RightBottom: - image.RotateFlip(RotateFlipType.Rotate90FlipY); - break; - case ExifOrientations.LeftBottom: - image.RotateFlip(RotateFlipType.Rotate270FlipNone); - break; - } - // Set the orientation to be normal, as we rotated the image. - item.Value[0] = (byte)ExifOrientations.TopLeft; - image.SetPropertyItem(item); - } - catch (Exception orientEx) - { - Log.Warn("Problem orientating the image: ", orientEx); - } - } + try + { + // Get the index of the orientation property. + int orientationIndex = Array.IndexOf(image.PropertyIdList, ExifOrientationId); + // If there is no such property, return Unknown. + if (orientationIndex < 0) + { + return; + } - /// - /// Create a Thumbnail - /// - /// - /// - /// - /// - /// - /// - public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight, int maxWidth = -1, int maxHeight = -1) - { - int srcWidth = image.Width; - int srcHeight = image.Height; - if (thumbHeight < 0) - { - thumbHeight = (int)(thumbWidth * (srcHeight / (float)srcWidth)); - } - if (thumbWidth < 0) - { - thumbWidth = (int)(thumbHeight * (srcWidth / (float)srcHeight)); - } - if (maxWidth > 0 && thumbWidth > maxWidth) - { - thumbWidth = Math.Min(thumbWidth, maxWidth); - thumbHeight = (int)(thumbWidth * (srcHeight / (float)srcWidth)); - } - if (maxHeight > 0 && thumbHeight > maxHeight) - { - thumbHeight = Math.Min(thumbHeight, maxHeight); - thumbWidth = (int)(thumbHeight * (srcWidth / (float)srcHeight)); - } + PropertyItem item = image.GetPropertyItem(ExifOrientationId); - Bitmap bmp = new Bitmap(thumbWidth, thumbHeight); - using (Graphics graphics = Graphics.FromImage(bmp)) - { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight); - graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); - } - return bmp; - } + ExifOrientations orientation = (ExifOrientations) item.Value[0]; + // Orient the image. + switch (orientation) + { + case ExifOrientations.Unknown: + case ExifOrientations.TopLeft: + break; + case ExifOrientations.TopRight: + image.RotateFlip(RotateFlipType.RotateNoneFlipX); + break; + case ExifOrientations.BottomRight: + image.RotateFlip(RotateFlipType.Rotate180FlipNone); + break; + case ExifOrientations.BottomLeft: + image.RotateFlip(RotateFlipType.RotateNoneFlipY); + break; + case ExifOrientations.LeftTop: + image.RotateFlip(RotateFlipType.Rotate90FlipX); + break; + case ExifOrientations.RightTop: + image.RotateFlip(RotateFlipType.Rotate90FlipNone); + break; + case ExifOrientations.RightBottom: + image.RotateFlip(RotateFlipType.Rotate90FlipY); + break; + case ExifOrientations.LeftBottom: + image.RotateFlip(RotateFlipType.Rotate270FlipNone); + break; + } - /// - /// Crops the image to the specified rectangle - /// - /// Image to crop - /// Rectangle with bitmap coordinates, will be "intersected" to the bitmap - public static bool Crop(ref Image image, ref Rectangle cropRectangle) - { - if (image is Bitmap && (image.Width * image.Height > 0)) - { - cropRectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height)); - if (cropRectangle.Width != 0 || cropRectangle.Height != 0) - { - Image returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare); - image.Dispose(); - image = returnImage; - return true; - } - } - Log.Warn("Can't crop a null/zero size image!"); - return false; - } + // Set the orientation to be normal, as we rotated the image. + item.Value[0] = (byte) ExifOrientations.TopLeft; + image.SetPropertyItem(item); + } + catch (Exception orientEx) + { + Log.Warn("Problem orientating the image: ", orientEx); + } + } - /// - /// Private helper method for the FindAutoCropRectangle - /// - /// - /// - /// - /// Rectangle - private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) - { - Rectangle cropRectangle = Rectangle.Empty; - Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); - Point min = new Point(int.MaxValue, int.MaxValue); - Point max = new Point(int.MinValue, int.MinValue); + /// + /// Create a Thumbnail + /// + /// + /// + /// + /// + /// + /// + public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight, int maxWidth = -1, int maxHeight = -1) + { + int srcWidth = image.Width; + int srcHeight = image.Height; + if (thumbHeight < 0) + { + thumbHeight = (int) (thumbWidth * (srcHeight / (float) srcWidth)); + } - if (cropDifference > 0) - { - for (int y = 0; y < fastBitmap.Height; y++) - { - for (int x = 0; x < fastBitmap.Width; x++) - { - Color currentColor = fastBitmap.GetColorAt(x, y); - int diffR = Math.Abs(currentColor.R - referenceColor.R); - int diffG = Math.Abs(currentColor.G - referenceColor.G); - int diffB = Math.Abs(currentColor.B - referenceColor.B); - if ((diffR + diffG + diffB) / 3 <= cropDifference) - { - continue; - } - if (x < min.X) min.X = x; - if (y < min.Y) min.Y = y; - if (x > max.X) max.X = x; - if (y > max.Y) max.Y = y; - } - } - } - else - { - for (int y = 0; y < fastBitmap.Height; y++) - { - for (int x = 0; x < fastBitmap.Width; x++) - { - Color currentColor = fastBitmap.GetColorAt(x, y); - if (!referenceColor.Equals(currentColor)) - { - continue; - } - if (x < min.X) min.X = x; - if (y < min.Y) min.Y = y; - if (x > max.X) max.X = x; - if (y > max.Y) max.Y = y; - } - } - } + if (thumbWidth < 0) + { + thumbWidth = (int) (thumbHeight * (srcWidth / (float) srcHeight)); + } - if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) - { - if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) - { - cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); - } - } - return cropRectangle; - } + if (maxWidth > 0 && thumbWidth > maxWidth) + { + thumbWidth = Math.Min(thumbWidth, maxWidth); + thumbHeight = (int) (thumbWidth * (srcHeight / (float) srcWidth)); + } - /// - /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 - /// - /// - /// - /// Rectangle - public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) - { - Rectangle cropRectangle = Rectangle.Empty; - var checkPoints = new List - { - new Point(0, 0), - new Point(0, image.Height - 1), - new Point(image.Width - 1, 0), - new Point(image.Width - 1, image.Height - 1) - }; - // Top Left - // Bottom Left - // Top Right - // Bottom Right - using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap)image)) - { - // find biggest area - foreach (Point checkPoint in checkPoints) - { - var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); - if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) - { - cropRectangle = currentRectangle; - } - } - } - return cropRectangle; - } + if (maxHeight > 0 && thumbHeight > maxHeight) + { + thumbHeight = Math.Min(thumbHeight, maxHeight); + thumbWidth = (int) (thumbHeight * (srcWidth / (float) srcHeight)); + } - /// - /// Load an image from file - /// - /// - /// - public static Image LoadImage(string filename) - { - if (string.IsNullOrEmpty(filename)) - { - return null; - } - if (!File.Exists(filename)) - { - return null; - } - Image fileImage; - Log.InfoFormat("Loading image from file {0}", filename); - // Fixed lock problem Bug #3431881 - using (Stream imageFileStream = File.OpenRead(filename)) - { - fileImage = FromStream(imageFileStream, Path.GetExtension(filename)); - } - if (fileImage != null) - { - Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat, fileImage.HorizontalResolution, fileImage.VerticalResolution); - } - return fileImage; - } + Bitmap bmp = new Bitmap(thumbWidth, thumbHeight); + using (Graphics graphics = Graphics.FromImage(bmp)) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight); + graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); + } - /// - /// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx - /// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx - /// - /// Stream with the icon information - /// Bitmap with the Vista Icon (256x256) - private static Bitmap ExtractVistaIcon(Stream iconStream) - { - const int sizeIconDir = 6; - const int sizeIconDirEntry = 16; - Bitmap bmpPngExtracted = null; - try - { - byte[] srcBuf = new byte[iconStream.Length]; - iconStream.Read(srcBuf, 0, (int)iconStream.Length); - int iCount = BitConverter.ToInt16(srcBuf, 4); - for (int iIndex = 0; iIndex < iCount; iIndex++) - { - int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex]; - int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1]; - if (iWidth == 0 && iHeight == 0) - { - int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); - int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); + return bmp; + } + + /// + /// Crops the image to the specified rectangle + /// + /// Image to crop + /// Rectangle with bitmap coordinates, will be "intersected" to the bitmap + public static bool Crop(ref Image image, ref Rectangle cropRectangle) + { + if (image is Bitmap && (image.Width * image.Height > 0)) + { + cropRectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height)); + if (cropRectangle.Width != 0 || cropRectangle.Height != 0) + { + Image returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare); + image.Dispose(); + image = returnImage; + return true; + } + } + + Log.Warn("Can't crop a null/zero size image!"); + return false; + } + + /// + /// Private helper method for the FindAutoCropRectangle + /// + /// + /// + /// + /// Rectangle + private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) + { + Rectangle cropRectangle = Rectangle.Empty; + Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); + Point min = new Point(int.MaxValue, int.MaxValue); + Point max = new Point(int.MinValue, int.MinValue); + + if (cropDifference > 0) + { + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { + Color currentColor = fastBitmap.GetColorAt(x, y); + int diffR = Math.Abs(currentColor.R - referenceColor.R); + int diffG = Math.Abs(currentColor.G - referenceColor.G); + int diffB = Math.Abs(currentColor.B - referenceColor.B); + if ((diffR + diffG + diffB) / 3 <= cropDifference) + { + continue; + } + + if (x < min.X) min.X = x; + if (y < min.Y) min.Y = y; + if (x > max.X) max.X = x; + if (y > max.Y) max.Y = y; + } + } + } + else + { + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { + Color currentColor = fastBitmap.GetColorAt(x, y); + if (!referenceColor.Equals(currentColor)) + { + continue; + } + + if (x < min.X) min.X = x; + if (y < min.Y) min.Y = y; + if (x > max.X) max.X = x; + if (y > max.Y) max.Y = y; + } + } + } + + if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) + { + if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) + { + cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); + } + } + + return cropRectangle; + } + + /// + /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 + /// + /// + /// + /// Rectangle + public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) + { + Rectangle cropRectangle = Rectangle.Empty; + var checkPoints = new List + { + new Point(0, 0), + new Point(0, image.Height - 1), + new Point(image.Width - 1, 0), + new Point(image.Width - 1, image.Height - 1) + }; + // Top Left + // Bottom Left + // Top Right + // Bottom Right + using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap) image)) + { + // find biggest area + foreach (Point checkPoint in checkPoints) + { + var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); + if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) + { + cropRectangle = currentRectangle; + } + } + } + + return cropRectangle; + } + + /// + /// Load an image from file + /// + /// + /// + public static Image LoadImage(string filename) + { + if (string.IsNullOrEmpty(filename)) + { + return null; + } + + if (!File.Exists(filename)) + { + return null; + } + + Image fileImage; + Log.InfoFormat("Loading image from file {0}", filename); + // Fixed lock problem Bug #3431881 + using (Stream imageFileStream = File.OpenRead(filename)) + { + fileImage = FromStream(imageFileStream, Path.GetExtension(filename)); + } + + if (fileImage != null) + { + Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat, + fileImage.HorizontalResolution, fileImage.VerticalResolution); + } + + return fileImage; + } + + /// + /// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx + /// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx + /// + /// Stream with the icon information + /// Bitmap with the Vista Icon (256x256) + private static Bitmap ExtractVistaIcon(Stream iconStream) + { + const int sizeIconDir = 6; + const int sizeIconDirEntry = 16; + Bitmap bmpPngExtracted = null; + try + { + byte[] srcBuf = new byte[iconStream.Length]; + iconStream.Read(srcBuf, 0, (int) iconStream.Length); + int iCount = BitConverter.ToInt16(srcBuf, 4); + for (int iIndex = 0; iIndex < iCount; iIndex++) + { + int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex]; + int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1]; + if (iWidth == 0 && iHeight == 0) + { + int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); + int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); using MemoryStream destStream = new MemoryStream(); destStream.Write(srcBuf, iImageOffset, iImageSize); destStream.Seek(0, SeekOrigin.Begin); bmpPngExtracted = new Bitmap(destStream); // This is PNG! :) break; - } - } - } - catch - { - return null; - } - return bmpPngExtracted; - } + } + } + } + catch + { + return null; + } - /// - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx - /// - /// The file (EXE or DLL) to get the icon from - /// Index of the icon - /// true if the large icon is wanted - /// Icon - public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) - { - Shell32.ExtractIconEx(location, index, out var large, out var small, 1); - Icon returnIcon = null; - bool isLarge = false; - bool isSmall = false; - try - { - if (takeLarge && !IntPtr.Zero.Equals(large)) - { - returnIcon = Icon.FromHandle(large); - isLarge = true; - } - else if (!IntPtr.Zero.Equals(small)) - { - returnIcon = Icon.FromHandle(small); - isSmall = true; - } - else if (!IntPtr.Zero.Equals(large)) - { - returnIcon = Icon.FromHandle(large); - isLarge = true; - } - } - finally - { - if (isLarge && !IntPtr.Zero.Equals(small)) - { - User32.DestroyIcon(small); - } - if (isSmall && !IntPtr.Zero.Equals(large)) - { - User32.DestroyIcon(large); - } - } - return returnIcon; - } + return bmpPngExtracted; + } /// - /// Apply the effect to the bitmap - /// - /// Bitmap - /// IEffect - /// - /// Bitmap - public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix) - { - var effects = new List { effect }; - return ApplyEffects(sourceImage, effects, matrix); - } + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx + /// + /// The file (EXE or DLL) to get the icon from + /// Index of the icon + /// true if the large icon is wanted + /// Icon + public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) + { + Shell32.ExtractIconEx(location, index, out var large, out var small, 1); + Icon returnIcon = null; + bool isLarge = false; + bool isSmall = false; + try + { + if (takeLarge && !IntPtr.Zero.Equals(large)) + { + returnIcon = Icon.FromHandle(large); + isLarge = true; + } + else if (!IntPtr.Zero.Equals(small)) + { + returnIcon = Icon.FromHandle(small); + isSmall = true; + } + else if (!IntPtr.Zero.Equals(large)) + { + returnIcon = Icon.FromHandle(large); + isLarge = true; + } + } + finally + { + if (isLarge && !IntPtr.Zero.Equals(small)) + { + User32.DestroyIcon(small); + } - /// - /// Apply the effects in the supplied order to the bitmap - /// - /// Bitmap - /// List of IEffect - /// - /// Bitmap - public static Image ApplyEffects(Image sourceImage, IEnumerable effects, Matrix matrix) - { - var currentImage = sourceImage; - bool disposeImage = false; - foreach (var effect in effects) - { - var tmpImage = effect.Apply(currentImage, matrix); - if (tmpImage != null) - { - if (disposeImage) - { - currentImage.Dispose(); - } - currentImage = tmpImage; - // Make sure the "new" image is disposed - disposeImage = true; - } - } - return currentImage; - } + if (isSmall && !IntPtr.Zero.Equals(large)) + { + User32.DestroyIcon(large); + } + } - /// - /// Helper method for the tornedge - /// - /// Path to draw to - /// Points for the lines to draw - private static void DrawLines(GraphicsPath path, List points) - { - path.AddLine(points[0], points[1]); - for (int i = 0; i < points.Count - 1; i++) - { - path.AddLine(points[i], points[i + 1]); - } - } + return returnIcon; + } - /// - /// Make the picture look like it's torn - /// - /// Bitmap to make torn edge off - /// How large (height) is each tooth - /// How wide is a horizontal tooth - /// How wide is a vertical tooth - /// bool[] with information on if the edge needs torn or not. Order is clockwise: 0=top,1=right,2=bottom,3=left - /// Changed bitmap - public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, bool[] edges) - { - Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (var path = new GraphicsPath()) - { - Random random = new Random(); - int horizontalRegions = (int)Math.Round((float)sourceImage.Width / horizontalToothRange); - int verticalRegions = (int)Math.Round((float)sourceImage.Height / verticalToothRange); + /// + /// Apply the effect to the bitmap + /// + /// Bitmap + /// IEffect + /// + /// Bitmap + public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix) + { + var effects = new List + { + effect + }; + return ApplyEffects(sourceImage, effects, matrix); + } - Point topLeft = new Point(0, 0); - Point topRight = new Point(sourceImage.Width, 0); - Point bottomLeft = new Point(0, sourceImage.Height); - Point bottomRight = new Point(sourceImage.Width, sourceImage.Height); + /// + /// Apply the effects in the supplied order to the bitmap + /// + /// Bitmap + /// List of IEffect + /// + /// Bitmap + public static Image ApplyEffects(Image sourceImage, IEnumerable effects, Matrix matrix) + { + var currentImage = sourceImage; + bool disposeImage = false; + foreach (var effect in effects) + { + var tmpImage = effect.Apply(currentImage, matrix); + if (tmpImage != null) + { + if (disposeImage) + { + currentImage.Dispose(); + } - List points = new List(); + currentImage = tmpImage; + // Make sure the "new" image is disposed + disposeImage = true; + } + } - if (edges[0]) - { - // calculate starting point only if the left edge is torn - if (!edges[3]) - { - points.Add(topLeft); - } - else - { - points.Add(new Point(random.Next(1, toothHeight), random.Next(1, toothHeight))); - } - for (int i = 1; i < horizontalRegions - 1; i++) - { - points.Add(new Point(i * horizontalToothRange, random.Next(1, toothHeight))); - } - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight))); - } - else - { - // set start & endpoint to be the default "whole-line" - points.Add(topLeft); - points.Add(topRight); - } - // Right - if (edges[1]) - { - for (int i = 1; i < verticalRegions - 1; i++) - { - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange)); - } - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); - } - else - { - // correct previous ending point - points[points.Count - 1] = topRight; - // set endpoint to be the default "whole-line" - points.Add(bottomRight); - } - // Bottom - if (edges[2]) - { - for (int i = 1; i < horizontalRegions - 1; i++) - { - points.Add(new Point(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight))); - } - points.Add(new Point(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); - } - else - { - // correct previous ending point - points[points.Count - 1] = bottomRight; - // set endpoint to be the default "whole-line" - points.Add(bottomLeft); - } - // Left - if (edges[3]) - { - // One fewer as the end point is the starting point - for (int i = 1; i < verticalRegions - 1; i++) - { - points.Add(new Point(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange)); - } - } - else - { - // correct previous ending point - points[points.Count - 1] = bottomLeft; - // set endpoint to be the default "whole-line" - points.Add(topLeft); - } - // End point always is the starting point - points[points.Count - 1] = points[0]; + return currentImage; + } - DrawLines(path, points); + /// + /// Helper method for the tornedge + /// + /// Path to draw to + /// Points for the lines to draw + private static void DrawLines(GraphicsPath path, List points) + { + path.AddLine(points[0], points[1]); + for (int i = 0; i < points.Count - 1; i++) + { + path.AddLine(points[i], points[i + 1]); + } + } - path.CloseFigure(); + /// + /// Make the picture look like it's torn + /// + /// Bitmap to make torn edge off + /// How large (height) is each tooth + /// How wide is a horizontal tooth + /// How wide is a vertical tooth + /// bool[] with information on if the edge needs torn or not. Order is clockwise: 0=top,1=right,2=bottom,3=left + /// Changed bitmap + public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, bool[] edges) + { + Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, + sourceImage.VerticalResolution); + using (var path = new GraphicsPath()) + { + Random random = new Random(); + int horizontalRegions = (int) Math.Round((float) sourceImage.Width / horizontalToothRange); + int verticalRegions = (int) Math.Round((float) sourceImage.Height / verticalToothRange); - // Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing + Point topLeft = new Point(0, 0); + Point topRight = new Point(sourceImage.Width, 0); + Point bottomLeft = new Point(0, sourceImage.Height); + Point bottomRight = new Point(sourceImage.Width, sourceImage.Height); + + List points = new List(); + + if (edges[0]) + { + // calculate starting point only if the left edge is torn + if (!edges[3]) + { + points.Add(topLeft); + } + else + { + points.Add(new Point(random.Next(1, toothHeight), random.Next(1, toothHeight))); + } + + for (int i = 1; i < horizontalRegions - 1; i++) + { + points.Add(new Point(i * horizontalToothRange, random.Next(1, toothHeight))); + } + + points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight))); + } + else + { + // set start & endpoint to be the default "whole-line" + points.Add(topLeft); + points.Add(topRight); + } + + // Right + if (edges[1]) + { + for (int i = 1; i < verticalRegions - 1; i++) + { + points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange)); + } + + points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); + } + else + { + // correct previous ending point + points[points.Count - 1] = topRight; + // set endpoint to be the default "whole-line" + points.Add(bottomRight); + } + + // Bottom + if (edges[2]) + { + for (int i = 1; i < horizontalRegions - 1; i++) + { + points.Add(new Point(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight))); + } + + points.Add(new Point(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); + } + else + { + // correct previous ending point + points[points.Count - 1] = bottomRight; + // set endpoint to be the default "whole-line" + points.Add(bottomLeft); + } + + // Left + if (edges[3]) + { + // One fewer as the end point is the starting point + for (int i = 1; i < verticalRegions - 1; i++) + { + points.Add(new Point(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange)); + } + } + else + { + // correct previous ending point + points[points.Count - 1] = bottomLeft; + // set endpoint to be the default "whole-line" + points.Add(topLeft); + } + + // End point always is the starting point + points[points.Count - 1] = points[0]; + + DrawLines(path, points); + + path.CloseFigure(); + + // Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing using Graphics graphics = Graphics.FromImage(returnImage); graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; @@ -635,417 +674,448 @@ namespace GreenshotPlugin.Core { // Important note: If the target wouldn't be at 0,0 we need to translate-transform!! graphics.FillPath(brush, path); } - return returnImage; - } - /// - /// Apply BoxBlur to the destinationBitmap - /// - /// Bitmap to blur - /// Must be ODD! - public static void ApplyBoxBlur(Bitmap destinationBitmap, int range) + return returnImage; + } + + /// + /// Apply BoxBlur to the destinationBitmap + /// + /// Bitmap to blur + /// Must be ODD! + public static void ApplyBoxBlur(Bitmap destinationBitmap, int range) { // We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V) using IFastBitmap fastBitmap = FastBitmap.Create(destinationBitmap); ApplyBoxBlur(fastBitmap, range); } - /// - /// Apply BoxBlur to the fastBitmap - /// - /// IFastBitmap to blur - /// Must be ODD! - public static void ApplyBoxBlur(IFastBitmap fastBitmap, int range) - { - // Range must be odd! - if ((range & 1) == 0) - { - range++; - } - if (range <= 1) - { - return; - } - // Box blurs are frequently used to approximate a Gaussian blur. - // By the central limit theorem, if applied 3 times on the same image, a box blur approximates the Gaussian kernel to within about 3%, yielding the same result as a quadratic convolution kernel. - // This might be true, but the GDI+ BlurEffect doesn't look the same, a 2x blur is more simular and we only make 2x Box-Blur. - // (Might also be a mistake in our blur, but for now it looks great) - if (fastBitmap.HasAlphaChannel) - { - BoxBlurHorizontalAlpha(fastBitmap, range); - BoxBlurVerticalAlpha(fastBitmap, range); - BoxBlurHorizontalAlpha(fastBitmap, range); - BoxBlurVerticalAlpha(fastBitmap, range); - } - else - { - BoxBlurHorizontal(fastBitmap, range); - BoxBlurVertical(fastBitmap, range); - BoxBlurHorizontal(fastBitmap, range); - BoxBlurVertical(fastBitmap, range); - } - } + /// + /// Apply BoxBlur to the fastBitmap + /// + /// IFastBitmap to blur + /// Must be ODD! + public static void ApplyBoxBlur(IFastBitmap fastBitmap, int range) + { + // Range must be odd! + if ((range & 1) == 0) + { + range++; + } - /// - /// BoxBlurHorizontal is a private helper method for the BoxBlur - /// - /// Target BitmapBuffer - /// Range must be odd! - private static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) - { - if (targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel"); - } - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Width]; - byte[] tmpColor = new byte[3]; - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - int hits = 0; - int r = 0; - int g = 0; - int b = 0; - for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) - { - int oldPixel = x - halfRange - 1; - if (oldPixel >= targetFastBitmap.Left) - { - targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } + if (range <= 1) + { + return; + } - int newPixel = x + halfRange; - if (newPixel < targetFastBitmap.Right) - { - targetFastBitmap.GetColorAt(newPixel, y, tmpColor); - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } + // Box blurs are frequently used to approximate a Gaussian blur. + // By the central limit theorem, if applied 3 times on the same image, a box blur approximates the Gaussian kernel to within about 3%, yielding the same result as a quadratic convolution kernel. + // This might be true, but the GDI+ BlurEffect doesn't look the same, a 2x blur is more simular and we only make 2x Box-Blur. + // (Might also be a mistake in our blur, but for now it looks great) + if (fastBitmap.HasAlphaChannel) + { + BoxBlurHorizontalAlpha(fastBitmap, range); + BoxBlurVerticalAlpha(fastBitmap, range); + BoxBlurHorizontalAlpha(fastBitmap, range); + BoxBlurVerticalAlpha(fastBitmap, range); + } + else + { + BoxBlurHorizontal(fastBitmap, range); + BoxBlurVertical(fastBitmap, range); + BoxBlurHorizontal(fastBitmap, range); + BoxBlurVertical(fastBitmap, range); + } + } - if (x >= targetFastBitmap.Left) - { - newColors[x - targetFastBitmap.Left] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); - } - } - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); - } - } - } - /// - /// BoxBlurHorizontal is a private helper method for the BoxBlur, only for IFastBitmaps with alpha channel - /// - /// Target BitmapBuffer - /// Range must be odd! - private static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) - { - if (!targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel"); - } - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Width]; - byte[] tmpColor = new byte[4]; - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - int hits = 0; - int a = 0; - int r = 0; - int g = 0; - int b = 0; - for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) - { - int oldPixel = x - halfRange - 1; - if (oldPixel >= targetFastBitmap.Left) - { - targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); - a -= tmpColor[FastBitmap.ColorIndexA]; - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } + /// + /// BoxBlurHorizontal is a private helper method for the BoxBlur + /// + /// Target BitmapBuffer + /// Range must be odd! + private static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) + { + if (targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel"); + } - int newPixel = x + halfRange; - if (newPixel < targetFastBitmap.Right) - { - targetFastBitmap.GetColorAt(newPixel, y, tmpColor); - a += tmpColor[FastBitmap.ColorIndexA]; - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Width]; + byte[] tmpColor = new byte[3]; + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + int hits = 0; + int r = 0; + int g = 0; + int b = 0; + for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) + { + int oldPixel = x - halfRange - 1; + if (oldPixel >= targetFastBitmap.Left) + { + targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } - if (x >= targetFastBitmap.Left) - { - newColors[x - targetFastBitmap.Left] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); - } - } - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); - } - } - } + int newPixel = x + halfRange; + if (newPixel < targetFastBitmap.Right) + { + targetFastBitmap.GetColorAt(newPixel, y, tmpColor); + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } - /// - /// BoxBlurVertical is a private helper method for the BoxBlur - /// - /// BitmapBuffer which previously was created with BoxBlurHorizontal - /// Range must be odd! - private static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) - { - if (targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel"); - } - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Height]; - byte[] tmpColor = new byte[4]; - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - int hits = 0; - int r = 0; - int g = 0; - int b = 0; - for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) - { - int oldPixel = y - halfRange - 1; - if (oldPixel >= targetFastBitmap.Top) - { - targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } + if (x >= targetFastBitmap.Left) + { + newColors[x - targetFastBitmap.Left] = Color.FromArgb(255, (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } - int newPixel = y + halfRange; - if (newPixel < targetFastBitmap.Bottom) - { - targetFastBitmap.GetColorAt(x, newPixel, tmpColor); - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); + } + } + } - if (y >= targetFastBitmap.Top) - { - newColors[y - targetFastBitmap.Top] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); - } - } + /// + /// BoxBlurHorizontal is a private helper method for the BoxBlur, only for IFastBitmaps with alpha channel + /// + /// Target BitmapBuffer + /// Range must be odd! + private static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) + { + if (!targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel"); + } - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); - } - } - } + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Width]; + byte[] tmpColor = new byte[4]; + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + int hits = 0; + int a = 0; + int r = 0; + int g = 0; + int b = 0; + for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) + { + int oldPixel = x - halfRange - 1; + if (oldPixel >= targetFastBitmap.Left) + { + targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); + a -= tmpColor[FastBitmap.ColorIndexA]; + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } - /// - /// BoxBlurVertical is a private helper method for the BoxBlur - /// - /// BitmapBuffer which previously was created with BoxBlurHorizontal - /// Range must be odd! - private static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) - { - if (!targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurVerticalAlpha should be called for bitmaps with alpha channel"); - } + int newPixel = x + halfRange; + if (newPixel < targetFastBitmap.Right) + { + targetFastBitmap.GetColorAt(newPixel, y, tmpColor); + a += tmpColor[FastBitmap.ColorIndexA]; + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Height]; - byte[] tmpColor = new byte[4]; - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - int hits = 0; - int a = 0; - int r = 0; - int g = 0; - int b = 0; - for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) - { - int oldPixel = y - halfRange - 1; - if (oldPixel >= targetFastBitmap.Top) - { - targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); - a -= tmpColor[FastBitmap.ColorIndexA]; - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } + if (x >= targetFastBitmap.Left) + { + newColors[x - targetFastBitmap.Left] = Color.FromArgb((byte) (a / hits), (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } - int newPixel = y + halfRange; - if (newPixel < targetFastBitmap.Bottom) - { - //int colorg = pixels[index + newPixelOffset]; - targetFastBitmap.GetColorAt(x, newPixel, tmpColor); - a += tmpColor[FastBitmap.ColorIndexA]; - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); + } + } + } - if (y >= targetFastBitmap.Top) - { - newColors[y - targetFastBitmap.Top] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); - } - } + /// + /// BoxBlurVertical is a private helper method for the BoxBlur + /// + /// BitmapBuffer which previously was created with BoxBlurHorizontal + /// Range must be odd! + private static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) + { + if (targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel"); + } - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); - } - } - } + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Height]; + byte[] tmpColor = new byte[4]; + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + int hits = 0; + int r = 0; + int g = 0; + int b = 0; + for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) + { + int oldPixel = y - halfRange - 1; + if (oldPixel >= targetFastBitmap.Top) + { + targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } - /// - /// This method fixes the problem that we can't apply a filter outside the target bitmap, - /// therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap. - /// It will also account for the Invert flag. - /// - /// - /// - /// - /// - public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) - { - Rectangle myRect; - if (invert) - { - myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); - } - else - { - Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height); - myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); - myRect.Intersect(applyRect); - } - return myRect; - } + int newPixel = y + halfRange; + if (newPixel < targetFastBitmap.Bottom) + { + targetFastBitmap.GetColorAt(x, newPixel, tmpColor); + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } - /// - /// Create a new bitmap where the sourceBitmap has a shadow - /// - /// Bitmap to make a shadow on - /// How dark is the shadow - /// Size of the shadow - /// What pixel format must the returning bitmap have - /// - /// The transform matrix which describes how the elements need to be transformed to stay at the same location - /// Bitmap with the shadow, is bigger than the sourceBitmap!! - public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, Matrix matrix, PixelFormat targetPixelformat) - { - Point offset = shadowOffset; - offset.X += shadowSize - 1; - offset.Y += shadowSize - 1; - matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); - // Create a new "clean" image - Bitmap returnImage = CreateEmpty(sourceBitmap.Width + shadowSize * 2, sourceBitmap.Height + shadowSize * 2, targetPixelformat, Color.Empty, sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); - // Make sure the shadow is odd, there is no reason for an even blur! - if ((shadowSize & 1) == 0) - { - shadowSize++; - } - bool useGdiBlur = GDIplus.IsBlurPossible(shadowSize); - // Create "mask" for the shadow - ColorMatrix maskMatrix = new ColorMatrix - { - Matrix00 = 0, - Matrix11 = 0, - Matrix22 = 0 - }; - if (useGdiBlur) - { - maskMatrix.Matrix33 = darkness + 0.1f; - } - else - { - maskMatrix.Matrix33 = darkness; - } - Rectangle shadowRectangle = new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size); - ApplyColorMatrix((Bitmap)sourceBitmap, Rectangle.Empty, returnImage, shadowRectangle, maskMatrix); + if (y >= targetFastBitmap.Top) + { + newColors[y - targetFastBitmap.Top] = Color.FromArgb(255, (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } - // blur "shadow", apply to whole new image - if (useGdiBlur) - { - // Use GDI Blur - Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height); - GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize + 1, false); - } - else - { - // try normal software blur - //returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); - ApplyBoxBlur(returnImage, shadowSize); - } + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); + } + } + } - // Draw the original image over the shadow - using (Graphics graphics = Graphics.FromImage(returnImage)) - { - // Make sure we draw with the best quality! - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - // draw original with a TextureBrush so we have nice antialiasing! + /// + /// BoxBlurVertical is a private helper method for the BoxBlur + /// + /// BitmapBuffer which previously was created with BoxBlurHorizontal + /// Range must be odd! + private static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) + { + if (!targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurVerticalAlpha should be called for bitmaps with alpha channel"); + } + + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Height]; + byte[] tmpColor = new byte[4]; + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + int hits = 0; + int a = 0; + int r = 0; + int g = 0; + int b = 0; + for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) + { + int oldPixel = y - halfRange - 1; + if (oldPixel >= targetFastBitmap.Top) + { + targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); + a -= tmpColor[FastBitmap.ColorIndexA]; + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } + + int newPixel = y + halfRange; + if (newPixel < targetFastBitmap.Bottom) + { + //int colorg = pixels[index + newPixelOffset]; + targetFastBitmap.GetColorAt(x, newPixel, tmpColor); + a += tmpColor[FastBitmap.ColorIndexA]; + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } + + if (y >= targetFastBitmap.Top) + { + newColors[y - targetFastBitmap.Top] = Color.FromArgb((byte) (a / hits), (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } + + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); + } + } + } + + /// + /// This method fixes the problem that we can't apply a filter outside the target bitmap, + /// therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap. + /// It will also account for the Invert flag. + /// + /// + /// + /// + /// + public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) + { + Rectangle myRect; + if (invert) + { + myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); + } + else + { + Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height); + myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); + myRect.Intersect(applyRect); + } + + return myRect; + } + + /// + /// Create a new bitmap where the sourceBitmap has a shadow + /// + /// Bitmap to make a shadow on + /// How dark is the shadow + /// Size of the shadow + /// What pixel format must the returning bitmap have + /// + /// The transform matrix which describes how the elements need to be transformed to stay at the same location + /// Bitmap with the shadow, is bigger than the sourceBitmap!! + public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, Matrix matrix, PixelFormat targetPixelformat) + { + Point offset = shadowOffset; + offset.X += shadowSize - 1; + offset.Y += shadowSize - 1; + matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); + // Create a new "clean" image + Bitmap returnImage = CreateEmpty(sourceBitmap.Width + shadowSize * 2, sourceBitmap.Height + shadowSize * 2, targetPixelformat, Color.Empty, + sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); + // Make sure the shadow is odd, there is no reason for an even blur! + if ((shadowSize & 1) == 0) + { + shadowSize++; + } + + bool useGdiBlur = GDIplus.IsBlurPossible(shadowSize); + // Create "mask" for the shadow + ColorMatrix maskMatrix = new ColorMatrix + { + Matrix00 = 0, + Matrix11 = 0, + Matrix22 = 0 + }; + if (useGdiBlur) + { + maskMatrix.Matrix33 = darkness + 0.1f; + } + else + { + maskMatrix.Matrix33 = darkness; + } + + Rectangle shadowRectangle = new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size); + ApplyColorMatrix((Bitmap) sourceBitmap, Rectangle.Empty, returnImage, shadowRectangle, maskMatrix); + + // blur "shadow", apply to whole new image + if (useGdiBlur) + { + // Use GDI Blur + Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height); + GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize + 1, false); + } + else + { + // try normal software blur + //returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); + ApplyBoxBlur(returnImage, shadowSize); + } + + // Draw the original image over the shadow + using (Graphics graphics = Graphics.FromImage(returnImage)) + { + // Make sure we draw with the best quality! + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + // draw original with a TextureBrush so we have nice antialiasing! using Brush textureBrush = new TextureBrush(sourceBitmap, WrapMode.Clamp); // We need to do a translate-transform otherwise the image is wrapped graphics.TranslateTransform(offset.X, offset.Y); graphics.FillRectangle(textureBrush, 0, 0, sourceBitmap.Width, sourceBitmap.Height); } - return returnImage; - } - /// - /// Return negative of Bitmap - /// - /// Bitmap to create a negative off - /// Negative bitmap - public static Bitmap CreateNegative(Image sourceImage) - { - Bitmap clone = (Bitmap)Clone(sourceImage); - ColorMatrix invertMatrix = new ColorMatrix(new[] { - new float[] {-1, 0, 0, 0, 0}, - new float[] {0, -1, 0, 0, 0}, - new float[] {0, 0, -1, 0, 0}, - new float[] {0, 0, 0, 1, 0}, - new float[] {1, 1, 1, 1, 1} - }); - ApplyColorMatrix(clone, invertMatrix); - return clone; - } - /// - /// Apply a color matrix to the image - /// - /// Image to apply matrix to - /// ColorMatrix to apply - public static void ApplyColorMatrix(Bitmap source, ColorMatrix colorMatrix) - { - ApplyColorMatrix(source, Rectangle.Empty, source, Rectangle.Empty, colorMatrix); - } + return returnImage; + } - /// - /// Apply a color matrix by copying from the source to the destination - /// - /// Image to copy from - /// Rectangle to copy from - /// Rectangle to copy to - /// Image to copy to - /// ColorMatrix to apply - public static void ApplyColorMatrix(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ColorMatrix colorMatrix) + /// + /// Return negative of Bitmap + /// + /// Bitmap to create a negative off + /// Negative bitmap + public static Bitmap CreateNegative(Image sourceImage) + { + Bitmap clone = (Bitmap) Clone(sourceImage); + ColorMatrix invertMatrix = new ColorMatrix(new[] + { + new float[] + { + -1, 0, 0, 0, 0 + }, + new float[] + { + 0, -1, 0, 0, 0 + }, + new float[] + { + 0, 0, -1, 0, 0 + }, + new float[] + { + 0, 0, 0, 1, 0 + }, + new float[] + { + 1, 1, 1, 1, 1 + } + }); + ApplyColorMatrix(clone, invertMatrix); + return clone; + } + + /// + /// Apply a color matrix to the image + /// + /// Image to apply matrix to + /// ColorMatrix to apply + public static void ApplyColorMatrix(Bitmap source, ColorMatrix colorMatrix) + { + ApplyColorMatrix(source, Rectangle.Empty, source, Rectangle.Empty, colorMatrix); + } + + /// + /// Apply a color matrix by copying from the source to the destination + /// + /// Image to copy from + /// Rectangle to copy from + /// Rectangle to copy to + /// Image to copy to + /// ColorMatrix to apply + public static void ApplyColorMatrix(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ColorMatrix colorMatrix) { using ImageAttributes imageAttributes = new ImageAttributes(); imageAttributes.ClearColorMatrix(); @@ -1054,27 +1124,29 @@ namespace GreenshotPlugin.Core { } /// - /// Apply a color matrix by copying from the source to the destination - /// - /// Image to copy from - /// Rectangle to copy from - /// Rectangle to copy to - /// Image to copy to - /// ImageAttributes to apply - public static void ApplyImageAttributes(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ImageAttributes imageAttributes) - { - if (sourceRect == Rectangle.Empty) - { - sourceRect = new Rectangle(0, 0, source.Width, source.Height); - } - if (dest == null) - { - dest = source; - } - if (destRect == Rectangle.Empty) - { - destRect = new Rectangle(0, 0, dest.Width, dest.Height); - } + /// Apply a color matrix by copying from the source to the destination + /// + /// Image to copy from + /// Rectangle to copy from + /// Rectangle to copy to + /// Image to copy to + /// ImageAttributes to apply + public static void ApplyImageAttributes(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ImageAttributes imageAttributes) + { + if (sourceRect == Rectangle.Empty) + { + sourceRect = new Rectangle(0, 0, source.Width, source.Height); + } + + if (dest == null) + { + dest = source; + } + + if (destRect == Rectangle.Empty) + { + destRect = new Rectangle(0, 0, dest.Width, dest.Height); + } using Graphics graphics = Graphics.FromImage(dest); // Make sure we draw with the best quality! @@ -1087,13 +1159,13 @@ namespace GreenshotPlugin.Core { graphics.DrawImage(source, destRect, sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height, GraphicsUnit.Pixel, imageAttributes); } - /// - /// Returns a b/w of Bitmap - /// - /// Bitmap to create a b/w of - /// Threshold for monochrome filter (0 - 255), lower value means less black - /// b/w bitmap - public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) + /// + /// Returns a b/w of Bitmap + /// + /// Bitmap to create a b/w of + /// Threshold for monochrome filter (0 - 255), lower value means less black + /// b/w bitmap + public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) { using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat); for (int y = 0; y < fastBitmap.Height; y++) @@ -1106,313 +1178,353 @@ namespace GreenshotPlugin.Core { fastBitmap.SetColorAt(x, y, monoColor); } } + return fastBitmap.UnlockAndReturnBitmap(); } - /// - /// Create a new bitmap where the sourceBitmap has a Simple border around it - /// - /// Bitmap to make a border on - /// Size of the border - /// Color of the border - /// What pixel format must the returning bitmap have - /// The transform matrix which describes how the elements need to be transformed to stay at the same location - /// Bitmap with the shadow, is bigger than the sourceBitmap!! - public static Image CreateBorder(Image sourceImage, int borderSize, Color borderColor, PixelFormat targetPixelformat, Matrix matrix) - { - // "return" the shifted offset, so the caller can e.g. move elements - Point offset = new Point(borderSize, borderSize); - matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); + /// + /// Create a new bitmap where the sourceBitmap has a Simple border around it + /// + /// Bitmap to make a border on + /// Size of the border + /// Color of the border + /// What pixel format must the returning bitmap have + /// The transform matrix which describes how the elements need to be transformed to stay at the same location + /// Bitmap with the shadow, is bigger than the sourceBitmap!! + public static Image CreateBorder(Image sourceImage, int borderSize, Color borderColor, PixelFormat targetPixelformat, Matrix matrix) + { + // "return" the shifted offset, so the caller can e.g. move elements + Point offset = new Point(borderSize, borderSize); + matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); - // Create a new "clean" image - Bitmap newImage = CreateEmpty(sourceImage.Width + borderSize * 2, sourceImage.Height + borderSize * 2, targetPixelformat, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (Graphics graphics = Graphics.FromImage(newImage)) - { - // Make sure we draw with the best quality! - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - using (GraphicsPath path = new GraphicsPath()) - { - path.AddRectangle(new Rectangle(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize)); - using Pen pen = new Pen(borderColor, borderSize) - { - LineJoin = LineJoin.Round, - StartCap = LineCap.Round, - EndCap = LineCap.Round - }; - graphics.DrawPath(pen, path); + // Create a new "clean" image + Bitmap newImage = CreateEmpty(sourceImage.Width + borderSize * 2, sourceImage.Height + borderSize * 2, targetPixelformat, Color.Empty, sourceImage.HorizontalResolution, + sourceImage.VerticalResolution); + using (Graphics graphics = Graphics.FromImage(newImage)) + { + // Make sure we draw with the best quality! + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + using (GraphicsPath path = new GraphicsPath()) + { + path.AddRectangle(new Rectangle(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize)); + using Pen pen = new Pen(borderColor, borderSize) + { + LineJoin = LineJoin.Round, + StartCap = LineCap.Round, + EndCap = LineCap.Round + }; + graphics.DrawPath(pen, path); } - // draw original with a TextureBrush so we have nice antialiasing! + + // draw original with a TextureBrush so we have nice antialiasing! using Brush textureBrush = new TextureBrush(sourceImage, WrapMode.Clamp); // We need to do a translate-tranform otherwise the image is wrapped graphics.TranslateTransform(offset.X, offset.Y); graphics.FillRectangle(textureBrush, 0, 0, sourceImage.Width, sourceImage.Height); } - return newImage; - } - /// - /// Create ImageAttributes to modify - /// - /// - /// - /// - /// ImageAttributes - public static ImageAttributes CreateAdjustAttributes(float brightness, float contrast, float gamma) - { - float adjustedBrightness = brightness - 1.0f; - ColorMatrix applyColorMatrix = new ColorMatrix( - new[] - { - new[] {contrast, 0, 0, 0, 0}, // scale red - new[] {0, contrast, 0, 0, 0}, // scale green - new[] {0, 0, contrast, 0, 0}, // scale blue - new[] {0, 0, 0, 1.0f, 0}, // don't scale alpha - new[] {adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1} - }); - - //create some image attributes - ImageAttributes attributes = new ImageAttributes(); - attributes.ClearColorMatrix(); - attributes.SetColorMatrix(applyColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); - attributes.SetGamma(gamma, ColorAdjustType.Bitmap); - return attributes; - } - - /// - /// Adjust the brightness, contract or gamma of an image. - /// Use the value "1.0f" for no changes. - /// - /// Original bitmap - /// - /// - /// - /// Bitmap with grayscale - public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) - { - //create a blank bitmap the same size as original - // If using 8bpp than the following exception comes: A Graphics object cannot be created from an image that has an indexed pixel format. - Bitmap newBitmap = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format24bppRgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (ImageAttributes adjustAttributes = CreateAdjustAttributes(brightness, contrast, gamma)) - { - ApplyImageAttributes((Bitmap)sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, adjustAttributes); - } - return newBitmap; - } - - /// - /// Create a new bitmap where the sourceBitmap is in grayscale - /// - /// Original bitmap - /// Bitmap with grayscale - public static Image CreateGrayscale(Image sourceImage) - { - Bitmap clone = (Bitmap)Clone(sourceImage); - ColorMatrix grayscaleMatrix = new ColorMatrix(new[] - { - new[] {.3f, .3f, .3f, 0, 0}, - new[] {.59f, .59f, .59f, 0, 0}, - new[] {.11f, .11f, .11f, 0, 0}, - new float[] {0, 0, 0, 1, 0}, - new float[] {0, 0, 0, 0, 1} - }); - ApplyColorMatrix(clone, grayscaleMatrix); - return clone; - } + return newImage; + } /// - /// Checks if we support the pixel format - /// - /// PixelFormat to check - /// bool if we support it - public static bool SupportsPixelFormat(PixelFormat pixelformat) - { - return pixelformat.Equals(PixelFormat.Format32bppArgb) || - pixelformat.Equals(PixelFormat.Format32bppPArgb) || - pixelformat.Equals(PixelFormat.Format32bppRgb) || - pixelformat.Equals(PixelFormat.Format24bppRgb); - } + /// Create ImageAttributes to modify + ///
+ /// + /// + /// + /// ImageAttributes + public static ImageAttributes CreateAdjustAttributes(float brightness, float contrast, float gamma) + { + float adjustedBrightness = brightness - 1.0f; + ColorMatrix applyColorMatrix = new ColorMatrix( + new[] + { + new[] + { + contrast, 0, 0, 0, 0 + }, // scale red + new[] + { + 0, contrast, 0, 0, 0 + }, // scale green + new[] + { + 0, 0, contrast, 0, 0 + }, // scale blue + new[] + { + 0, 0, 0, 1.0f, 0 + }, // don't scale alpha + new[] + { + adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1 + } + }); - /// - /// Wrapper for just cloning which calls the CloneArea - /// - /// Image to clone - /// Bitmap with clone image data - public static Image Clone(Image sourceImage) - { - if (sourceImage is Metafile) - { - return (Image)sourceImage.Clone(); - } - return CloneArea(sourceImage, Rectangle.Empty, PixelFormat.DontCare); - } + //create some image attributes + ImageAttributes attributes = new ImageAttributes(); + attributes.ClearColorMatrix(); + attributes.SetColorMatrix(applyColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); + attributes.SetGamma(gamma, ColorAdjustType.Bitmap); + return attributes; + } - /// - /// Wrapper for just cloning & TargetFormat which calls the CloneArea - /// - /// Image to clone - /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) - /// Bitmap with clone image data - public static Bitmap Clone(Image sourceBitmap, PixelFormat targetFormat) - { - return CloneArea(sourceBitmap, Rectangle.Empty, targetFormat); - } + /// + /// Adjust the brightness, contract or gamma of an image. + /// Use the value "1.0f" for no changes. + /// + /// Original bitmap + /// + /// + /// + /// Bitmap with grayscale + public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) + { + //create a blank bitmap the same size as original + // If using 8bpp than the following exception comes: A Graphics object cannot be created from an image that has an indexed pixel format. + Bitmap newBitmap = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format24bppRgb, Color.Empty, sourceImage.HorizontalResolution, + sourceImage.VerticalResolution); + using (ImageAttributes adjustAttributes = CreateAdjustAttributes(brightness, contrast, gamma)) + { + ApplyImageAttributes((Bitmap) sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, adjustAttributes); + } - /// - /// Clone an image, taking some rules into account: - /// 1) When sourceRect is the whole bitmap there is a GDI+ bug in Clone - /// Clone will than return the same PixelFormat as the source - /// a quick workaround is using new Bitmap which uses a default of Format32bppArgb - /// 2) When going from a transparent to a non transparent bitmap, we draw the background white! - /// - /// Source bitmap to clone - /// Rectangle to copy from the source, use Rectangle.Empty for all - /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) - /// - public static Bitmap CloneArea(Image sourceImage, Rectangle sourceRect, PixelFormat targetFormat) - { - Bitmap newImage; - Rectangle bitmapRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); + return newBitmap; + } - // Make sure the source is not Rectangle.Empty - if (Rectangle.Empty.Equals(sourceRect)) - { - sourceRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); - } - else - { - sourceRect.Intersect(bitmapRect); - } + /// + /// Create a new bitmap where the sourceBitmap is in grayscale + /// + /// Original bitmap + /// Bitmap with grayscale + public static Image CreateGrayscale(Image sourceImage) + { + Bitmap clone = (Bitmap) Clone(sourceImage); + ColorMatrix grayscaleMatrix = new ColorMatrix(new[] + { + new[] + { + .3f, .3f, .3f, 0, 0 + }, + new[] + { + .59f, .59f, .59f, 0, 0 + }, + new[] + { + .11f, .11f, .11f, 0, 0 + }, + new float[] + { + 0, 0, 0, 1, 0 + }, + new float[] + { + 0, 0, 0, 0, 1 + } + }); + ApplyColorMatrix(clone, grayscaleMatrix); + return clone; + } - // If no pixelformat is supplied - if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) - { - if (SupportsPixelFormat(sourceImage.PixelFormat)) - { - targetFormat = sourceImage.PixelFormat; - } - else if (Image.IsAlphaPixelFormat(sourceImage.PixelFormat)) - { - targetFormat = PixelFormat.Format32bppArgb; - } - else - { - targetFormat = PixelFormat.Format24bppRgb; - } - } + /// + /// Checks if we support the pixel format + /// + /// PixelFormat to check + /// bool if we support it + public static bool SupportsPixelFormat(PixelFormat pixelformat) + { + return pixelformat.Equals(PixelFormat.Format32bppArgb) || + pixelformat.Equals(PixelFormat.Format32bppPArgb) || + pixelformat.Equals(PixelFormat.Format32bppRgb) || + pixelformat.Equals(PixelFormat.Format24bppRgb); + } - // check the target format - if (!SupportsPixelFormat(targetFormat)) - { - targetFormat = Image.IsAlphaPixelFormat(targetFormat) ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb; - } + /// + /// Wrapper for just cloning which calls the CloneArea + /// + /// Image to clone + /// Bitmap with clone image data + public static Image Clone(Image sourceImage) + { + if (sourceImage is Metafile) + { + return (Image) sourceImage.Clone(); + } - bool destinationIsTransparent = Image.IsAlphaPixelFormat(targetFormat); - bool sourceIsTransparent = Image.IsAlphaPixelFormat(sourceImage.PixelFormat); - bool fromTransparentToNon = !destinationIsTransparent && sourceIsTransparent; - bool isBitmap = sourceImage is Bitmap; - bool isAreaEqual = sourceRect.Equals(bitmapRect); - if (isAreaEqual || fromTransparentToNon || !isBitmap) - { - // Rule 1: if the areas are equal, always copy ourselves - newImage = new Bitmap(bitmapRect.Width, bitmapRect.Height, targetFormat); - // Make sure both images have the same resolution - newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + return CloneArea(sourceImage, Rectangle.Empty, PixelFormat.DontCare); + } - using Graphics graphics = Graphics.FromImage(newImage); - if (fromTransparentToNon) - { - // Rule 2: Make sure the background color is white - graphics.Clear(Color.White); - } - // decide fastest copy method - if (isAreaEqual) - { - graphics.DrawImageUnscaled(sourceImage, 0, 0); - } - else - { - graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel); - } - } - else - { - // Let GDI+ decide how to convert, need to test what is quicker... - newImage = (sourceImage as Bitmap).Clone(sourceRect, targetFormat); - // Make sure both images have the same resolution - newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - } + /// + /// Wrapper for just cloning & TargetFormat which calls the CloneArea + /// + /// Image to clone + /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) + /// Bitmap with clone image data + public static Bitmap Clone(Image sourceBitmap, PixelFormat targetFormat) + { + return CloneArea(sourceBitmap, Rectangle.Empty, targetFormat); + } - // In WINE someone getting the PropertyItems doesn't work - try - { - // Clone property items (EXIF information etc) - foreach (var propertyItem in sourceImage.PropertyItems) - { - try - { - newImage.SetPropertyItem(propertyItem); - } - catch (Exception innerEx) - { - Log.Warn("Problem cloning a propertyItem.", innerEx); - } - } - } - catch (Exception ex) - { - Log.Warn("Problem cloning a propertyItem.", ex); - } - return newImage; - } + /// + /// Clone an image, taking some rules into account: + /// 1) When sourceRect is the whole bitmap there is a GDI+ bug in Clone + /// Clone will than return the same PixelFormat as the source + /// a quick workaround is using new Bitmap which uses a default of Format32bppArgb + /// 2) When going from a transparent to a non transparent bitmap, we draw the background white! + /// + /// Source bitmap to clone + /// Rectangle to copy from the source, use Rectangle.Empty for all + /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) + /// + public static Bitmap CloneArea(Image sourceImage, Rectangle sourceRect, PixelFormat targetFormat) + { + Bitmap newImage; + Rectangle bitmapRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); - /// - /// Rotate the bitmap - /// - /// - /// - /// - public static Image RotateFlip(Image sourceImage, RotateFlipType rotateFlipType) - { - Image returnImage = Clone(sourceImage); - returnImage.RotateFlip(rotateFlipType); - return returnImage; - } + // Make sure the source is not Rectangle.Empty + if (Rectangle.Empty.Equals(sourceRect)) + { + sourceRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); + } + else + { + sourceRect.Intersect(bitmapRect); + } - /// - /// A generic way to create an empty image - /// - /// the source bitmap as the specifications for the new bitmap - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - public static Bitmap CreateEmptyLike(Image sourceImage, Color backgroundColor) - { - PixelFormat pixelFormat = sourceImage.PixelFormat; - if (backgroundColor.A < 255) - { - pixelFormat = PixelFormat.Format32bppArgb; - } - return CreateEmpty(sourceImage.Width, sourceImage.Height, pixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - } + // If no pixelformat is supplied + if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) + { + if (SupportsPixelFormat(sourceImage.PixelFormat)) + { + targetFormat = sourceImage.PixelFormat; + } + else if (Image.IsAlphaPixelFormat(sourceImage.PixelFormat)) + { + targetFormat = PixelFormat.Format32bppArgb; + } + else + { + targetFormat = PixelFormat.Format24bppRgb; + } + } - /// - /// A generic way to create an empty image - /// - /// - /// - /// - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - /// - /// Bitmap - public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution, float verticalResolution) - { - // Create a new "clean" image - Bitmap newImage = new Bitmap(width, height, format); - newImage.SetResolution(horizontalResolution, verticalResolution); - if (format != PixelFormat.Format8bppIndexed) + // check the target format + if (!SupportsPixelFormat(targetFormat)) + { + targetFormat = Image.IsAlphaPixelFormat(targetFormat) ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb; + } + + bool destinationIsTransparent = Image.IsAlphaPixelFormat(targetFormat); + bool sourceIsTransparent = Image.IsAlphaPixelFormat(sourceImage.PixelFormat); + bool fromTransparentToNon = !destinationIsTransparent && sourceIsTransparent; + bool isBitmap = sourceImage is Bitmap; + bool isAreaEqual = sourceRect.Equals(bitmapRect); + if (isAreaEqual || fromTransparentToNon || !isBitmap) + { + // Rule 1: if the areas are equal, always copy ourselves + newImage = new Bitmap(bitmapRect.Width, bitmapRect.Height, targetFormat); + // Make sure both images have the same resolution + newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + + using Graphics graphics = Graphics.FromImage(newImage); + if (fromTransparentToNon) + { + // Rule 2: Make sure the background color is white + graphics.Clear(Color.White); + } + + // decide fastest copy method + if (isAreaEqual) + { + graphics.DrawImageUnscaled(sourceImage, 0, 0); + } + else + { + graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel); + } + } + else + { + // Let GDI+ decide how to convert, need to test what is quicker... + newImage = (sourceImage as Bitmap).Clone(sourceRect, targetFormat); + // Make sure both images have the same resolution + newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + } + + // In WINE someone getting the PropertyItems doesn't work + try + { + // Clone property items (EXIF information etc) + foreach (var propertyItem in sourceImage.PropertyItems) + { + try + { + newImage.SetPropertyItem(propertyItem); + } + catch (Exception innerEx) + { + Log.Warn("Problem cloning a propertyItem.", innerEx); + } + } + } + catch (Exception ex) + { + Log.Warn("Problem cloning a propertyItem.", ex); + } + + return newImage; + } + + /// + /// Rotate the bitmap + /// + /// + /// + /// + public static Image RotateFlip(Image sourceImage, RotateFlipType rotateFlipType) + { + Image returnImage = Clone(sourceImage); + returnImage.RotateFlip(rotateFlipType); + return returnImage; + } + + /// + /// A generic way to create an empty image + /// + /// the source bitmap as the specifications for the new bitmap + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// + public static Bitmap CreateEmptyLike(Image sourceImage, Color backgroundColor) + { + PixelFormat pixelFormat = sourceImage.PixelFormat; + if (backgroundColor.A < 255) + { + pixelFormat = PixelFormat.Format32bppArgb; + } + + return CreateEmpty(sourceImage.Width, sourceImage.Height, pixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + } + + /// + /// A generic way to create an empty image + /// + /// + /// + /// + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// + /// + /// Bitmap + public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution, float verticalResolution) + { + // Create a new "clean" image + Bitmap newImage = new Bitmap(width, height, format); + newImage.SetResolution(horizontalResolution, verticalResolution); + if (format != PixelFormat.Format8bppIndexed) { using Graphics graphics = Graphics.FromImage(newImage); // Make sure the background color is what we want (transparent or white, depending on the pixel format) @@ -1429,62 +1541,65 @@ namespace GreenshotPlugin.Core { graphics.Clear(Color.White); } } - return newImage; - } + + return newImage; + } /// - /// Resize canvas with pixel to the left, right, top and bottom - /// - /// - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - /// - /// - /// - /// - /// a new bitmap with the source copied on it - public static Image ResizeCanvas(Image sourceImage, Color backgroundColor, int left, int right, int top, int bottom, Matrix matrix) - { - matrix.Translate(left, top, MatrixOrder.Append); - Bitmap newBitmap = CreateEmpty(sourceImage.Width + left + right, sourceImage.Height + top + bottom, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (Graphics graphics = Graphics.FromImage(newBitmap)) - { - graphics.DrawImageUnscaled(sourceImage, left, top); - } - return newBitmap; - } + /// Resize canvas with pixel to the left, right, top and bottom + ///
+ /// + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// + /// + /// + /// + /// + /// a new bitmap with the source copied on it + public static Image ResizeCanvas(Image sourceImage, Color backgroundColor, int left, int right, int top, int bottom, Matrix matrix) + { + matrix.Translate(left, top, MatrixOrder.Append); + Bitmap newBitmap = CreateEmpty(sourceImage.Width + left + right, sourceImage.Height + top + bottom, sourceImage.PixelFormat, backgroundColor, + sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + using (Graphics graphics = Graphics.FromImage(newBitmap)) + { + graphics.DrawImageUnscaled(sourceImage, left, top); + } - /// - /// Wrapper for the more complex Resize, this resize could be used for e.g. Thumbnails - /// - /// - /// true to maintain the aspect ratio - /// - /// - /// - /// - public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, int newWidth, int newHeight, Matrix matrix) - { - return ResizeImage(sourceImage, maintainAspectRatio, false, Color.Empty, newWidth, newHeight, matrix); - } + return newBitmap; + } - /// - /// Count how many times the supplied color exists - /// - /// Image to count the pixels of - /// Color to count - /// true if Alpha needs to be checked - /// int with the number of pixels which have colorToCount - public static int CountColor(Image sourceImage, Color colorToCount, bool includeAlpha) - { - int colors = 0; - int toCount = colorToCount.ToArgb(); - if (!includeAlpha) - { - toCount &= 0xffffff; - } + /// + /// Wrapper for the more complex Resize, this resize could be used for e.g. Thumbnails + /// + /// + /// true to maintain the aspect ratio + /// + /// + /// + /// + public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, int newWidth, int newHeight, Matrix matrix) + { + return ResizeImage(sourceImage, maintainAspectRatio, false, Color.Empty, newWidth, newHeight, matrix); + } - using IFastBitmap bb = FastBitmap.Create((Bitmap)sourceImage); + /// + /// Count how many times the supplied color exists + /// + /// Image to count the pixels of + /// Color to count + /// true if Alpha needs to be checked + /// int with the number of pixels which have colorToCount + public static int CountColor(Image sourceImage, Color colorToCount, bool includeAlpha) + { + int colors = 0; + int toCount = colorToCount.ToArgb(); + if (!includeAlpha) + { + toCount &= 0xffffff; + } + + using IFastBitmap bb = FastBitmap.Create((Bitmap) sourceImage); for (int y = 0; y < bb.Height; y++) { for (int x = 0; x < bb.Width; x++) @@ -1494,186 +1609,199 @@ namespace GreenshotPlugin.Core { { bitmapcolor &= 0xffffff; } + if (bitmapcolor == toCount) { colors++; } } } + return colors; } - /// - /// Scale the bitmap, keeping aspect ratio, but the canvas will always have the specified size. - /// - /// Image to scale - /// true to maintain the aspect ratio - /// Makes the image maintain aspect ratio, but the canvas get's the specified size - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// new width - /// new height - /// - /// a new bitmap with the specified size, the source-Image scaled to fit with aspect ratio locked - public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, bool canvasUseNewSize, Color backgroundColor, int newWidth, int newHeight, Matrix matrix) - { - int destX = 0; - int destY = 0; + /// + /// Scale the bitmap, keeping aspect ratio, but the canvas will always have the specified size. + /// + /// Image to scale + /// true to maintain the aspect ratio + /// Makes the image maintain aspect ratio, but the canvas get's the specified size + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// new width + /// new height + /// + /// a new bitmap with the specified size, the source-Image scaled to fit with aspect ratio locked + public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, bool canvasUseNewSize, Color backgroundColor, int newWidth, int newHeight, Matrix matrix) + { + int destX = 0; + int destY = 0; - var nPercentW = newWidth / (float)sourceImage.Width; - var nPercentH = newHeight / (float)sourceImage.Height; - if (maintainAspectRatio) - { - if ((int)nPercentW == 1) - { - nPercentW = nPercentH; - if (canvasUseNewSize) - { - destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); - } - } - else if ((int)nPercentH == 1) - { - nPercentH = nPercentW; - if (canvasUseNewSize) - { - destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); - } - } - else if ((int)nPercentH != 0 && nPercentH < nPercentW) - { - nPercentW = nPercentH; - if (canvasUseNewSize) - { - destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); - } - } - else - { - nPercentH = nPercentW; - if (canvasUseNewSize) - { - destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); - } - } - } + var nPercentW = newWidth / (float) sourceImage.Width; + var nPercentH = newHeight / (float) sourceImage.Height; + if (maintainAspectRatio) + { + if ((int) nPercentW == 1) + { + nPercentW = nPercentH; + if (canvasUseNewSize) + { + destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); + } + } + else if ((int) nPercentH == 1) + { + nPercentH = nPercentW; + if (canvasUseNewSize) + { + destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); + } + } + else if ((int) nPercentH != 0 && nPercentH < nPercentW) + { + nPercentW = nPercentH; + if (canvasUseNewSize) + { + destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); + } + } + else + { + nPercentH = nPercentW; + if (canvasUseNewSize) + { + destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); + } + } + } - int destWidth = (int)(sourceImage.Width * nPercentW); - int destHeight = (int)(sourceImage.Height * nPercentH); - if (newWidth == 0) - { - newWidth = destWidth; - } - if (newHeight == 0) - { - newHeight = destHeight; - } - Image newImage; - if (maintainAspectRatio && canvasUseNewSize) - { - newImage = CreateEmpty(newWidth, newHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - matrix?.Scale((float)newWidth / sourceImage.Width, (float)newHeight / sourceImage.Height, MatrixOrder.Append); - } - else - { - newImage = CreateEmpty(destWidth, destHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - matrix?.Scale((float)destWidth / sourceImage.Width, (float)destHeight / sourceImage.Height, MatrixOrder.Append); - } + int destWidth = (int) (sourceImage.Width * nPercentW); + int destHeight = (int) (sourceImage.Height * nPercentH); + if (newWidth == 0) + { + newWidth = destWidth; + } - using (Graphics graphics = Graphics.FromImage(newImage)) - { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + if (newHeight == 0) + { + newHeight = destHeight; + } + + Image newImage; + if (maintainAspectRatio && canvasUseNewSize) + { + newImage = CreateEmpty(newWidth, newHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + matrix?.Scale((float) newWidth / sourceImage.Width, (float) newHeight / sourceImage.Height, MatrixOrder.Append); + } + else + { + newImage = CreateEmpty(destWidth, destHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + matrix?.Scale((float) destWidth / sourceImage.Width, (float) destHeight / sourceImage.Height, MatrixOrder.Append); + } + + using (Graphics graphics = Graphics.FromImage(newImage)) + { + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; using ImageAttributes wrapMode = new ImageAttributes(); wrapMode.SetWrapMode(WrapMode.TileFlipXY); graphics.DrawImage(sourceImage, new Rectangle(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode); } - return newImage; - } - /// - /// Load a Greenshot surface from a stream - /// - /// Stream - /// - /// ISurface - public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface) - { - Image fileImage; - // Fixed problem that the bitmap stream is disposed... by Cloning the image - // This also ensures the bitmap is correctly created + return newImage; + } - // We create a copy of the bitmap, so everything else can be disposed - surfaceFileStream.Position = 0; - using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) - { - Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - fileImage = Clone(tmpImage); - } - // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) - const int markerSize = 14; - surfaceFileStream.Seek(-markerSize, SeekOrigin.End); - using (StreamReader streamReader = new StreamReader(surfaceFileStream)) - { - var greenshotMarker = streamReader.ReadToEnd(); - if (!greenshotMarker.StartsWith("Greenshot")) - { - throw new ArgumentException("Stream is not a Greenshot file!"); - } - Log.InfoFormat("Greenshot file format: {0}", greenshotMarker); - const int filesizeLocation = 8 + markerSize; - surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); + /// + /// Load a Greenshot surface from a stream + /// + /// Stream + /// + /// ISurface + public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface) + { + Image fileImage; + // Fixed problem that the bitmap stream is disposed... by Cloning the image + // This also ensures the bitmap is correctly created + + // We create a copy of the bitmap, so everything else can be disposed + surfaceFileStream.Position = 0; + using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) + { + Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); + fileImage = Clone(tmpImage); + } + + // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) + const int markerSize = 14; + surfaceFileStream.Seek(-markerSize, SeekOrigin.End); + using (StreamReader streamReader = new StreamReader(surfaceFileStream)) + { + var greenshotMarker = streamReader.ReadToEnd(); + if (!greenshotMarker.StartsWith("Greenshot")) + { + throw new ArgumentException("Stream is not a Greenshot file!"); + } + + Log.InfoFormat("Greenshot file format: {0}", greenshotMarker); + const int filesizeLocation = 8 + markerSize; + surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); using BinaryReader reader = new BinaryReader(surfaceFileStream); long bytesWritten = reader.ReadInt64(); surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End); returnSurface.LoadElementsFromStream(surfaceFileStream); } - if (fileImage != null) - { - returnSurface.Image = fileImage; - Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat, fileImage.HorizontalResolution, fileImage.VerticalResolution); - } - return returnSurface; - } - /// - /// Create an image from a stream, if an extension is supplied more formats are supported. - /// - /// Stream - /// - /// Image - public static Image FromStream(Stream stream, string extension = null) - { - if (stream == null) - { - return null; - } - if (!string.IsNullOrEmpty(extension)) - { - extension = extension.Replace(".", string.Empty); - } + if (fileImage != null) + { + returnSurface.Image = fileImage; + Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat, + fileImage.HorizontalResolution, fileImage.VerticalResolution); + } - // Make sure we can try multiple times - if (!stream.CanSeek) - { - var memoryStream = new MemoryStream(); - stream.CopyTo(memoryStream); - stream = memoryStream; - } + return returnSurface; + } - Image returnImage = null; + /// + /// Create an image from a stream, if an extension is supplied more formats are supported. + /// + /// Stream + /// + /// Image + public static Image FromStream(Stream stream, string extension = null) + { + if (stream == null) + { + return null; + } + + if (!string.IsNullOrEmpty(extension)) + { + extension = extension.Replace(".", string.Empty); + } + + // Make sure we can try multiple times + if (!stream.CanSeek) + { + var memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + stream = memoryStream; + } + + Image returnImage = null; if (StreamConverters.TryGetValue(extension ?? string.Empty, out var converter)) - { - returnImage = converter(stream, extension); - } - // Fallback - if (returnImage == null) - { - // We create a copy of the bitmap, so everything else can be disposed - stream.Position = 0; + { + returnImage = converter(stream, extension); + } + + // Fallback + if (returnImage == null) + { + // We create a copy of the bitmap, so everything else can be disposed + stream.Position = 0; using var tmpImage = Image.FromStream(stream, true, true); Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); returnImage = Clone(tmpImage, PixelFormat.Format32bppArgb); } - return returnImage; - } - } -} + + return returnImage; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/ImageOutput.cs b/src/GreenshotPlugin/Core/ImageOutput.cs index 4388f2b59..233ffe377 100644 --- a/src/GreenshotPlugin/Core/ImageOutput.cs +++ b/src/GreenshotPlugin/Core/ImageOutput.cs @@ -38,77 +38,91 @@ using GreenshotPlugin.Interfaces; using GreenshotPlugin.Interfaces.Plugin; using Encoder = System.Drawing.Imaging.Encoder; -namespace GreenshotPlugin.Core { - /// - /// Description of ImageOutput. - /// - public static class ImageOutput { - private static readonly ILog Log = LogManager.GetLogger(typeof(ImageOutput)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131; - private static readonly Cache TmpFileCache = new Cache(10 * 60 * 60, RemoveExpiredTmpFile); - - /// - /// Creates a PropertyItem (Metadata) to store with the image. - /// For the possible ID's see: http://msdn.microsoft.com/de-de/library/system.drawing.imaging.propertyitem.id(v=vs.80).aspx - /// This code uses Reflection to create a PropertyItem, although it's not adviced it's not as stupid as having a image in the project so we can read a PropertyItem from that! - /// - /// ID - /// Text - /// - private static PropertyItem CreatePropertyItem(int id, string text) { - PropertyItem propertyItem = null; - try { - ConstructorInfo ci = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] { }, null); - propertyItem = (PropertyItem)ci.Invoke(null); - // Make sure it's of type string - propertyItem.Type = 2; - // Set the ID - propertyItem.Id = id; - // Set the text - byte[] byteString = Encoding.ASCII.GetBytes(text + " "); - // Set Zero byte for String end. - byteString[byteString.Length - 1] = 0; - propertyItem.Value = byteString; - propertyItem.Len = text.Length + 1; - } catch (Exception e) { - Log.WarnFormat("Error creating a PropertyItem: {0}", e.Message); - } - return propertyItem; - } +namespace GreenshotPlugin.Core +{ + /// + /// Description of ImageOutput. + /// + public static class ImageOutput + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ImageOutput)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131; + private static readonly Cache TmpFileCache = new Cache(10 * 60 * 60, RemoveExpiredTmpFile); /// - /// Saves ISurface to stream with specified output settings - /// - /// ISurface to save - /// Stream to save to - /// SurfaceOutputSettings - public static void SaveToStream(ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) { + /// Creates a PropertyItem (Metadata) to store with the image. + /// For the possible ID's see: http://msdn.microsoft.com/de-de/library/system.drawing.imaging.propertyitem.id(v=vs.80).aspx + /// This code uses Reflection to create a PropertyItem, although it's not adviced it's not as stupid as having a image in the project so we can read a PropertyItem from that! + ///
+ /// ID + /// Text + /// + private static PropertyItem CreatePropertyItem(int id, string text) + { + PropertyItem propertyItem = null; + try + { + ConstructorInfo ci = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] + { + }, null); + propertyItem = (PropertyItem) ci.Invoke(null); + // Make sure it's of type string + propertyItem.Type = 2; + // Set the ID + propertyItem.Id = id; + // Set the text + byte[] byteString = Encoding.ASCII.GetBytes(text + " "); + // Set Zero byte for String end. + byteString[byteString.Length - 1] = 0; + propertyItem.Value = byteString; + propertyItem.Len = text.Length + 1; + } + catch (Exception e) + { + Log.WarnFormat("Error creating a PropertyItem: {0}", e.Message); + } + + return propertyItem; + } + + /// + /// Saves ISurface to stream with specified output settings + /// + /// ISurface to save + /// Stream to save to + /// SurfaceOutputSettings + public static void SaveToStream(ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) + { bool disposeImage = CreateImageFromSurface(surface, outputSettings, out var imageToSave); - SaveToStream(imageToSave, surface, stream, outputSettings); - // cleanup if needed - if (disposeImage) { - imageToSave?.Dispose(); - } - } + SaveToStream(imageToSave, surface, stream, outputSettings); + // cleanup if needed + if (disposeImage) + { + imageToSave?.Dispose(); + } + } - /// - /// Saves image to stream with specified quality - /// To prevent problems with GDI version of before Windows 7: - /// the stream is checked if it's seekable and if needed a MemoryStream as "cache" is used. - /// - /// image to save - /// surface for the elements, needed if the greenshot format is used - /// Stream to save to - /// SurfaceOutputSettings - public static void SaveToStream(Image imageToSave, ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) { - bool useMemoryStream = false; - MemoryStream memoryStream = null; - if (outputSettings.Format == OutputFormat.greenshot && surface == null) { - throw new ArgumentException("Surface needs to be set when using OutputFormat.Greenshot"); - } + /// + /// Saves image to stream with specified quality + /// To prevent problems with GDI version of before Windows 7: + /// the stream is checked if it's seekable and if needed a MemoryStream as "cache" is used. + /// + /// image to save + /// surface for the elements, needed if the greenshot format is used + /// Stream to save to + /// SurfaceOutputSettings + public static void SaveToStream(Image imageToSave, ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) + { + bool useMemoryStream = false; + MemoryStream memoryStream = null; + if (outputSettings.Format == OutputFormat.greenshot && surface == null) + { + throw new ArgumentException("Surface needs to be set when using OutputFormat.Greenshot"); + } - try { + try + { var imageFormat = outputSettings.Format switch { OutputFormat.bmp => ImageFormat.Bmp, @@ -120,87 +134,104 @@ namespace GreenshotPlugin.Core { }; Log.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat); - // Check if we want to use a memory stream, to prevent issues with non seakable streams - // The save is made to the targetStream, this is directed to either the MemoryStream or the original - Stream targetStream = stream; - if (!stream.CanSeek) - { - useMemoryStream = true; - Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream."); - memoryStream = new MemoryStream(); - targetStream = memoryStream; - } + // Check if we want to use a memory stream, to prevent issues with non seakable streams + // The save is made to the targetStream, this is directed to either the MemoryStream or the original + Stream targetStream = stream; + if (!stream.CanSeek) + { + useMemoryStream = true; + Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream."); + memoryStream = new MemoryStream(); + targetStream = memoryStream; + } - if (Equals(imageFormat, ImageFormat.Jpeg)) - { - bool foundEncoder = false; - foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders()) - { - if (imageCodec.FormatID == imageFormat.Guid) - { - EncoderParameters parameters = new EncoderParameters(1) - { - Param = {[0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality)} - }; - // Removing transparency if it's not supported in the output - if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) - { - Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); - AddTag(nonAlphaImage); - nonAlphaImage.Save(targetStream, imageCodec, parameters); - nonAlphaImage.Dispose(); - } - else - { - AddTag(imageToSave); - imageToSave.Save(targetStream, imageCodec, parameters); - } - foundEncoder = true; - break; - } - } - if (!foundEncoder) - { - throw new ApplicationException("No JPG encoder found, this should not happen."); - } - } else if (Equals(imageFormat, ImageFormat.Icon)) { - // FEATURE-916: Added Icon support - IList images = new List - { - imageToSave - }; - WriteIcon(stream, images); - } else { - bool needsDispose = false; - // Removing transparency if it's not supported in the output - if (!Equals(imageFormat, ImageFormat.Png) && Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) { - imageToSave = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); - needsDispose = true; - } - AddTag(imageToSave); - // Added for OptiPNG - bool processed = false; - if (Equals(imageFormat, ImageFormat.Png) && !string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) { - processed = ProcessPngImageExternally(imageToSave, targetStream); - } - if (!processed) { - imageToSave.Save(targetStream, imageFormat); - } - if (needsDispose) { - imageToSave.Dispose(); - } - } + if (Equals(imageFormat, ImageFormat.Jpeg)) + { + bool foundEncoder = false; + foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders()) + { + if (imageCodec.FormatID == imageFormat.Guid) + { + EncoderParameters parameters = new EncoderParameters(1) + { + Param = + { + [0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality) + } + }; + // Removing transparency if it's not supported in the output + if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) + { + Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); + AddTag(nonAlphaImage); + nonAlphaImage.Save(targetStream, imageCodec, parameters); + nonAlphaImage.Dispose(); + } + else + { + AddTag(imageToSave); + imageToSave.Save(targetStream, imageCodec, parameters); + } - // If we used a memory stream, we need to stream the memory stream to the original stream. - if (useMemoryStream) { - memoryStream.WriteTo(stream); - } + foundEncoder = true; + break; + } + } - // Output the surface elements, size and marker to the stream - if (outputSettings.Format != OutputFormat.greenshot) - { - return; - } + if (!foundEncoder) + { + throw new ApplicationException("No JPG encoder found, this should not happen."); + } + } + else if (Equals(imageFormat, ImageFormat.Icon)) + { + // FEATURE-916: Added Icon support + IList images = new List + { + imageToSave + }; + WriteIcon(stream, images); + } + else + { + bool needsDispose = false; + // Removing transparency if it's not supported in the output + if (!Equals(imageFormat, ImageFormat.Png) && Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) + { + imageToSave = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); + needsDispose = true; + } + + AddTag(imageToSave); + // Added for OptiPNG + bool processed = false; + if (Equals(imageFormat, ImageFormat.Png) && !string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) + { + processed = ProcessPngImageExternally(imageToSave, targetStream); + } + + if (!processed) + { + imageToSave.Save(targetStream, imageFormat); + } + + if (needsDispose) + { + imageToSave.Dispose(); + } + } + + // If we used a memory stream, we need to stream the memory stream to the original stream. + if (useMemoryStream) + { + memoryStream.WriteTo(stream); + } + + // Output the surface elements, size and marker to the stream + if (outputSettings.Format != OutputFormat.greenshot) + { + return; + } using MemoryStream tmpStream = new MemoryStream(); long bytesWritten = surface.SaveElementsToStream(tmpStream); @@ -211,404 +242,514 @@ namespace GreenshotPlugin.Core { writer.Write(marker); tmpStream.WriteTo(stream); } - finally - { - memoryStream?.Dispose(); - } - } + finally + { + memoryStream?.Dispose(); + } + } - /// - /// Write the passed Image to a tmp-file and call an external process, than read the file back and write it to the targetStream - /// - /// Image to pass to the external process - /// stream to write the processed image to - /// - private static bool ProcessPngImageExternally(Image imageToProcess, Stream targetStream) { - if (string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) { - return false; - } - if (!File.Exists(CoreConfig.OptimizePNGCommand)) { - Log.WarnFormat("Can't find 'OptimizePNGCommand' {0}", CoreConfig.OptimizePNGCommand); - return false; - } - string tmpFileName = Path.Combine(Path.GetTempPath(),Path.GetRandomFileName() + ".png"); - try { - using (FileStream tmpStream = File.Create(tmpFileName)) { - Log.DebugFormat("Writing png to tmp file: {0}", tmpFileName); - imageToProcess.Save(tmpStream, ImageFormat.Png); - if (Log.IsDebugEnabled) { - Log.DebugFormat("File size before processing {0}", new FileInfo(tmpFileName).Length); - } - } - if (Log.IsDebugEnabled) { - Log.DebugFormat("Starting : {0}", CoreConfig.OptimizePNGCommand); - } + /// + /// Write the passed Image to a tmp-file and call an external process, than read the file back and write it to the targetStream + /// + /// Image to pass to the external process + /// stream to write the processed image to + /// + private static bool ProcessPngImageExternally(Image imageToProcess, Stream targetStream) + { + if (string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) + { + return false; + } - ProcessStartInfo processStartInfo = new ProcessStartInfo(CoreConfig.OptimizePNGCommand) - { - Arguments = string.Format(CoreConfig.OptimizePNGCommandArguments, tmpFileName), - CreateNoWindow = true, - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false - }; + if (!File.Exists(CoreConfig.OptimizePNGCommand)) + { + Log.WarnFormat("Can't find 'OptimizePNGCommand' {0}", CoreConfig.OptimizePNGCommand); + return false; + } + + string tmpFileName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".png"); + try + { + using (FileStream tmpStream = File.Create(tmpFileName)) + { + Log.DebugFormat("Writing png to tmp file: {0}", tmpFileName); + imageToProcess.Save(tmpStream, ImageFormat.Png); + if (Log.IsDebugEnabled) + { + Log.DebugFormat("File size before processing {0}", new FileInfo(tmpFileName).Length); + } + } + + if (Log.IsDebugEnabled) + { + Log.DebugFormat("Starting : {0}", CoreConfig.OptimizePNGCommand); + } + + ProcessStartInfo processStartInfo = new ProcessStartInfo(CoreConfig.OptimizePNGCommand) + { + Arguments = string.Format(CoreConfig.OptimizePNGCommandArguments, tmpFileName), + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false + }; using Process process = Process.Start(processStartInfo); - if (process != null) { + if (process != null) + { process.WaitForExit(); - if (process.ExitCode == 0) { - if (Log.IsDebugEnabled) { + if (process.ExitCode == 0) + { + if (Log.IsDebugEnabled) + { Log.DebugFormat("File size after processing {0}", new FileInfo(tmpFileName).Length); Log.DebugFormat("Reading back tmp file: {0}", tmpFileName); } + byte[] processedImage = File.ReadAllBytes(tmpFileName); targetStream.Write(processedImage, 0, processedImage.Length); return true; } + Log.ErrorFormat("Error while processing PNG image: {0}", process.ExitCode); Log.ErrorFormat("Output: {0}", process.StandardOutput.ReadToEnd()); Log.ErrorFormat("Error: {0}", process.StandardError.ReadToEnd()); } - } catch (Exception e) { - Log.Error("Error while processing PNG image: ", e); - } finally { - if (File.Exists(tmpFileName)) { - Log.DebugFormat("Cleaning up tmp file: {0}", tmpFileName); - File.Delete(tmpFileName); - } - } - return false; - } - - /// - /// Create an image from a surface with the settings from the output settings applied - /// - /// - /// - /// - /// true if the image must be disposed - public static bool CreateImageFromSurface(ISurface surface, SurfaceOutputSettings outputSettings, out Image imageToSave) { - bool disposeImage = false; - - if (outputSettings.Format == OutputFormat.greenshot || outputSettings.SaveBackgroundOnly) { - // We save the image of the surface, this should not be disposed - imageToSave = surface.Image; - } else { - // We create the export image of the surface to save - imageToSave = surface.GetImageForExport(); - disposeImage = true; - } - - // The following block of modifications should be skipped when saving the greenshot format, no effects or otherwise! - if (outputSettings.Format == OutputFormat.greenshot) { - return disposeImage; - } - Image tmpImage; - if (outputSettings.Effects != null && outputSettings.Effects.Count > 0) { - // apply effects, if there are any - using (Matrix matrix = new Matrix()) { - tmpImage = ImageHelper.ApplyEffects(imageToSave, outputSettings.Effects, matrix); - } - if (tmpImage != null) { - if (disposeImage) { - imageToSave.Dispose(); - } - imageToSave = tmpImage; - disposeImage = true; - } - } - - // check for color reduction, forced or automatically, only when the DisableReduceColors is false - if (outputSettings.DisableReduceColors || (!CoreConfig.OutputFileAutoReduceColors && !outputSettings.ReduceColors)) { - return disposeImage; - } - bool isAlpha = Image.IsAlphaPixelFormat(imageToSave.PixelFormat); - if (outputSettings.ReduceColors || (!isAlpha && CoreConfig.OutputFileAutoReduceColors)) + } + catch (Exception e) { - using var quantizer = new WuQuantizer((Bitmap)imageToSave); - int colorCount = quantizer.GetColorCount(); - Log.InfoFormat("Image with format {0} has {1} colors", imageToSave.PixelFormat, colorCount); - if (!outputSettings.ReduceColors && colorCount >= 256) { - return disposeImage; + Log.Error("Error while processing PNG image: ", e); + } + finally + { + if (File.Exists(tmpFileName)) + { + Log.DebugFormat("Cleaning up tmp file: {0}", tmpFileName); + File.Delete(tmpFileName); } - try { - Log.Info("Reducing colors on bitmap to 256."); - tmpImage = quantizer.GetQuantizedImage(CoreConfig.OutputFileReduceColorsTo); - if (disposeImage) { + } + + return false; + } + + /// + /// Create an image from a surface with the settings from the output settings applied + /// + /// + /// + /// + /// true if the image must be disposed + public static bool CreateImageFromSurface(ISurface surface, SurfaceOutputSettings outputSettings, out Image imageToSave) + { + bool disposeImage = false; + + if (outputSettings.Format == OutputFormat.greenshot || outputSettings.SaveBackgroundOnly) + { + // We save the image of the surface, this should not be disposed + imageToSave = surface.Image; + } + else + { + // We create the export image of the surface to save + imageToSave = surface.GetImageForExport(); + disposeImage = true; + } + + // The following block of modifications should be skipped when saving the greenshot format, no effects or otherwise! + if (outputSettings.Format == OutputFormat.greenshot) + { + return disposeImage; + } + + Image tmpImage; + if (outputSettings.Effects != null && outputSettings.Effects.Count > 0) + { + // apply effects, if there are any + using (Matrix matrix = new Matrix()) + { + tmpImage = ImageHelper.ApplyEffects(imageToSave, outputSettings.Effects, matrix); + } + + if (tmpImage != null) + { + if (disposeImage) + { imageToSave.Dispose(); } + + imageToSave = tmpImage; + disposeImage = true; + } + } + + // check for color reduction, forced or automatically, only when the DisableReduceColors is false + if (outputSettings.DisableReduceColors || (!CoreConfig.OutputFileAutoReduceColors && !outputSettings.ReduceColors)) + { + return disposeImage; + } + + bool isAlpha = Image.IsAlphaPixelFormat(imageToSave.PixelFormat); + if (outputSettings.ReduceColors || (!isAlpha && CoreConfig.OutputFileAutoReduceColors)) + { + using var quantizer = new WuQuantizer((Bitmap) imageToSave); + int colorCount = quantizer.GetColorCount(); + Log.InfoFormat("Image with format {0} has {1} colors", imageToSave.PixelFormat, colorCount); + if (!outputSettings.ReduceColors && colorCount >= 256) + { + return disposeImage; + } + + try + { + Log.Info("Reducing colors on bitmap to 256."); + tmpImage = quantizer.GetQuantizedImage(CoreConfig.OutputFileReduceColorsTo); + if (disposeImage) + { + imageToSave.Dispose(); + } + imageToSave = tmpImage; // Make sure the "new" image is disposed disposeImage = true; - } catch (Exception e) { + } + catch (Exception e) + { Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); } - } else if (isAlpha && !outputSettings.ReduceColors) { - Log.Info("Skipping 'optional' color reduction as the image has alpha"); - } - return disposeImage; - } - - /// - /// Add the greenshot property! - /// - /// - private static void AddTag(Image imageToSave) { - // Create meta-data - PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot"); - if (softwareUsedPropertyItem != null) { - try { - imageToSave.SetPropertyItem(softwareUsedPropertyItem); - } catch (Exception) { - Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id); - } - } - } + } + else if (isAlpha && !outputSettings.ReduceColors) + { + Log.Info("Skipping 'optional' color reduction as the image has alpha"); + } - /// - /// Load a Greenshot surface - /// - /// - /// - /// - public static ISurface LoadGreenshotSurface(string fullPath, ISurface returnSurface) { - if (string.IsNullOrEmpty(fullPath)) { - return null; - } - Log.InfoFormat("Loading image from file {0}", fullPath); - // Fixed lock problem Bug #3431881 - using (Stream surfaceFileStream = File.OpenRead(fullPath)) { - returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface); - } - if (returnSurface != null) { - Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", fullPath, returnSurface.Image.Width, returnSurface.Image.Height, returnSurface.Image.PixelFormat, returnSurface.Image.HorizontalResolution, returnSurface.Image.VerticalResolution); - } - return returnSurface; - } - - /// - /// Saves image to specific path with specified quality - /// - public static void Save(ISurface surface, string fullPath, bool allowOverwrite, SurfaceOutputSettings outputSettings, bool copyPathToClipboard) { - fullPath = FilenameHelper.MakeFqFilenameSafe(fullPath); - string path = Path.GetDirectoryName(fullPath); - - // check whether path exists - if not create it - if (path != null) { - DirectoryInfo di = new DirectoryInfo(path); - if (!di.Exists) { - Directory.CreateDirectory(di.FullName); - } - } - - if (!allowOverwrite && File.Exists(fullPath)) { - ArgumentException throwingException = new ArgumentException("File '" + fullPath + "' already exists."); - throwingException.Data.Add("fullPath", fullPath); - throw throwingException; - } - Log.DebugFormat("Saving surface to {0}", fullPath); - // Create the stream and call SaveToStream - using (FileStream stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write)) { - SaveToStream(surface, stream, outputSettings); - } - - if (copyPathToClipboard) { - ClipboardHelper.SetClipboardData(fullPath); - } - } - - /// - /// Get the OutputFormat for a filename - /// - /// filename (can be a complete path) - /// OutputFormat - public static OutputFormat FormatForFilename(string fullPath) { - // Fix for bug 2912959 - string extension = fullPath.Substring(fullPath.LastIndexOf(".", StringComparison.Ordinal) + 1); - OutputFormat format = OutputFormat.png; - try { - format = (OutputFormat)Enum.Parse(typeof(OutputFormat), extension.ToLower()); - } catch (ArgumentException ae) { - Log.Warn("Couldn't parse extension: " + extension, ae); - } - return format; - } + return disposeImage; + } /// - /// Save with showing a dialog - /// - /// - /// - /// Path to filename - public static string SaveWithDialog(ISurface surface, ICaptureDetails captureDetails) { - string returnValue = null; - using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails)) { - DialogResult dialogResult = saveImageFileDialog.ShowDialog(); - if (dialogResult.Equals(DialogResult.OK)) { - try { - string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension)); - if (CoreConfig.OutputFilePromptQuality) { - QualityDialog qualityDialog = new QualityDialog(outputSettings); - qualityDialog.ShowDialog(); - } - // TODO: For now we always overwrite, should be changed - Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); - returnValue = fileNameWithExtension; - IniConfig.Save(); - } catch (ExternalException) { - MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error")); - } - } - } - return returnValue; - } + /// Add the greenshot property! + /// + /// + private static void AddTag(Image imageToSave) + { + // Create meta-data + PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot"); + if (softwareUsedPropertyItem != null) + { + try + { + imageToSave.SetPropertyItem(softwareUsedPropertyItem); + } + catch (Exception) + { + Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id); + } + } + } /// - /// Create a tmpfile which has the name like in the configured pattern. - /// Used e.g. by the email export - /// - /// - /// - /// - /// Path to image file - public static string SaveNamedTmpFile(ISurface surface, ICaptureDetails captureDetails, SurfaceOutputSettings outputSettings) { - string pattern = CoreConfig.OutputFileFilenamePattern; - if (string.IsNullOrEmpty(pattern?.Trim())) { - pattern = "greenshot ${capturetime}"; - } - string filename = FilenameHelper.GetFilenameFromPattern(pattern, outputSettings.Format, captureDetails); - // Prevent problems with "other characters", which causes a problem in e.g. Outlook 2007 or break our HTML - filename = Regex.Replace(filename, @"[^\d\w\.]", "_"); - // Remove multiple "_" - filename = Regex.Replace(filename, @"_+", "_"); - string tmpFile = Path.Combine(Path.GetTempPath(), filename); + /// Load a Greenshot surface + /// + /// + /// + /// + public static ISurface LoadGreenshotSurface(string fullPath, ISurface returnSurface) + { + if (string.IsNullOrEmpty(fullPath)) + { + return null; + } - Log.Debug("Creating TMP File: " + tmpFile); + Log.InfoFormat("Loading image from file {0}", fullPath); + // Fixed lock problem Bug #3431881 + using (Stream surfaceFileStream = File.OpenRead(fullPath)) + { + returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface); + } - // Catching any exception to prevent that the user can't write in the directory. - // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218 - try { - Save(surface, tmpFile, true, outputSettings, false); - TmpFileCache.Add(tmpFile, tmpFile); - } catch (Exception e) { - // Show the problem - MessageBox.Show(e.Message, "Error"); - // when save failed we present a SaveWithDialog - tmpFile = SaveWithDialog(surface, captureDetails); - } - return tmpFile; - } + if (returnSurface != null) + { + Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", fullPath, returnSurface.Image.Width, returnSurface.Image.Height, + returnSurface.Image.PixelFormat, returnSurface.Image.HorizontalResolution, returnSurface.Image.VerticalResolution); + } - /// - /// Remove a tmpfile which was created by SaveNamedTmpFile - /// Used e.g. by the email export - /// - /// - /// true if it worked - public static bool DeleteNamedTmpFile(string tmpfile) { - Log.Debug("Deleting TMP File: " + tmpfile); - try { - if (File.Exists(tmpfile)) { - File.Delete(tmpfile); - TmpFileCache.Remove(tmpfile); - } - return true; - } catch (Exception ex) { - Log.Warn("Error deleting tmp file: ", ex); - } - return false; - } - - /// - /// Helper method to create a temp image file - /// - /// - /// - /// - /// - public static string SaveToTmpFile(ISurface surface, SurfaceOutputSettings outputSettings, string destinationPath) { - string tmpFile = Path.GetRandomFileName() + "." + outputSettings.Format; - // Prevent problems with "other characters", which could cause problems - tmpFile = Regex.Replace(tmpFile, @"[^\d\w\.]", string.Empty); - if (destinationPath == null) { - destinationPath = Path.GetTempPath(); - } - string tmpPath = Path.Combine(destinationPath, tmpFile); - Log.Debug("Creating TMP File : " + tmpPath); - - try { - Save(surface, tmpPath, true, outputSettings, false); - TmpFileCache.Add(tmpPath, tmpPath); - } catch (Exception) { - return null; - } - return tmpPath; - } - - /// - /// Cleanup all created tmpfiles - /// - public static void RemoveTmpFiles() { - foreach (string tmpFile in TmpFileCache.Elements) { - if (File.Exists(tmpFile)) { - Log.DebugFormat("Removing old temp file {0}", tmpFile); - File.Delete(tmpFile); - } - TmpFileCache.Remove(tmpFile); - } - } - - /// - /// Cleanup handler for expired tempfiles - /// - /// - /// - private static void RemoveExpiredTmpFile(string filekey, object filename) { - if (filename is string path && File.Exists(path)) { - Log.DebugFormat("Removing expired file {0}", path); - File.Delete(path); - } - } + return returnSurface; + } /// - /// Write the images to the stream as icon - /// Every image is resized to 256x256 (but the content maintains the aspect ratio) - /// - /// Stream to write to - /// List of images - public static void WriteIcon(Stream stream, IList images) - { - var binaryWriter = new BinaryWriter(stream); - // - // ICONDIR structure - // - binaryWriter.Write((short)0); // reserved - binaryWriter.Write((short)1); // image type (icon) - binaryWriter.Write((short)images.Count); // number of images + /// Saves image to specific path with specified quality + /// + public static void Save(ISurface surface, string fullPath, bool allowOverwrite, SurfaceOutputSettings outputSettings, bool copyPathToClipboard) + { + fullPath = FilenameHelper.MakeFqFilenameSafe(fullPath); + string path = Path.GetDirectoryName(fullPath); - IList imageSizes = new List(); - IList encodedImages = new List(); - foreach (var image in images) - { - // Pick the best fit - var sizes = new[] { 16, 32, 48 }; - int size = 256; - foreach (var possibleSize in sizes) - { - if (image.Width <= possibleSize && image.Height <= possibleSize) - { - size = possibleSize; - break; - } - } - var imageStream = new MemoryStream(); - if (image.Width == size && image.Height == size) + // check whether path exists - if not create it + if (path != null) + { + DirectoryInfo di = new DirectoryInfo(path); + if (!di.Exists) + { + Directory.CreateDirectory(di.FullName); + } + } + + if (!allowOverwrite && File.Exists(fullPath)) + { + ArgumentException throwingException = new ArgumentException("File '" + fullPath + "' already exists."); + throwingException.Data.Add("fullPath", fullPath); + throw throwingException; + } + + Log.DebugFormat("Saving surface to {0}", fullPath); + // Create the stream and call SaveToStream + using (FileStream stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write)) + { + SaveToStream(surface, stream, outputSettings); + } + + if (copyPathToClipboard) + { + ClipboardHelper.SetClipboardData(fullPath); + } + } + + /// + /// Get the OutputFormat for a filename + /// + /// filename (can be a complete path) + /// OutputFormat + public static OutputFormat FormatForFilename(string fullPath) + { + // Fix for bug 2912959 + string extension = fullPath.Substring(fullPath.LastIndexOf(".", StringComparison.Ordinal) + 1); + OutputFormat format = OutputFormat.png; + try + { + format = (OutputFormat) Enum.Parse(typeof(OutputFormat), extension.ToLower()); + } + catch (ArgumentException ae) + { + Log.Warn("Couldn't parse extension: " + extension, ae); + } + + return format; + } + + /// + /// Save with showing a dialog + /// + /// + /// + /// Path to filename + public static string SaveWithDialog(ISurface surface, ICaptureDetails captureDetails) + { + string returnValue = null; + using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails)) + { + DialogResult dialogResult = saveImageFileDialog.ShowDialog(); + if (dialogResult.Equals(DialogResult.OK)) + { + try + { + string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension)); + if (CoreConfig.OutputFilePromptQuality) + { + QualityDialog qualityDialog = new QualityDialog(outputSettings); + qualityDialog.ShowDialog(); + } + + // TODO: For now we always overwrite, should be changed + Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); + returnValue = fileNameWithExtension; + IniConfig.Save(); + } + catch (ExternalException) + { + MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error")); + } + } + } + + return returnValue; + } + + /// + /// Create a tmpfile which has the name like in the configured pattern. + /// Used e.g. by the email export + /// + /// + /// + /// + /// Path to image file + public static string SaveNamedTmpFile(ISurface surface, ICaptureDetails captureDetails, SurfaceOutputSettings outputSettings) + { + string pattern = CoreConfig.OutputFileFilenamePattern; + if (string.IsNullOrEmpty(pattern?.Trim())) + { + pattern = "greenshot ${capturetime}"; + } + + string filename = FilenameHelper.GetFilenameFromPattern(pattern, outputSettings.Format, captureDetails); + // Prevent problems with "other characters", which causes a problem in e.g. Outlook 2007 or break our HTML + filename = Regex.Replace(filename, @"[^\d\w\.]", "_"); + // Remove multiple "_" + filename = Regex.Replace(filename, @"_+", "_"); + string tmpFile = Path.Combine(Path.GetTempPath(), filename); + + Log.Debug("Creating TMP File: " + tmpFile); + + // Catching any exception to prevent that the user can't write in the directory. + // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218 + try + { + Save(surface, tmpFile, true, outputSettings, false); + TmpFileCache.Add(tmpFile, tmpFile); + } + catch (Exception e) + { + // Show the problem + MessageBox.Show(e.Message, "Error"); + // when save failed we present a SaveWithDialog + tmpFile = SaveWithDialog(surface, captureDetails); + } + + return tmpFile; + } + + /// + /// Remove a tmpfile which was created by SaveNamedTmpFile + /// Used e.g. by the email export + /// + /// + /// true if it worked + public static bool DeleteNamedTmpFile(string tmpfile) + { + Log.Debug("Deleting TMP File: " + tmpfile); + try + { + if (File.Exists(tmpfile)) + { + File.Delete(tmpfile); + TmpFileCache.Remove(tmpfile); + } + + return true; + } + catch (Exception ex) + { + Log.Warn("Error deleting tmp file: ", ex); + } + + return false; + } + + /// + /// Helper method to create a temp image file + /// + /// + /// + /// + /// + public static string SaveToTmpFile(ISurface surface, SurfaceOutputSettings outputSettings, string destinationPath) + { + string tmpFile = Path.GetRandomFileName() + "." + outputSettings.Format; + // Prevent problems with "other characters", which could cause problems + tmpFile = Regex.Replace(tmpFile, @"[^\d\w\.]", string.Empty); + if (destinationPath == null) + { + destinationPath = Path.GetTempPath(); + } + + string tmpPath = Path.Combine(destinationPath, tmpFile); + Log.Debug("Creating TMP File : " + tmpPath); + + try + { + Save(surface, tmpPath, true, outputSettings, false); + TmpFileCache.Add(tmpPath, tmpPath); + } + catch (Exception) + { + return null; + } + + return tmpPath; + } + + /// + /// Cleanup all created tmpfiles + /// + public static void RemoveTmpFiles() + { + foreach (string tmpFile in TmpFileCache.Elements) + { + if (File.Exists(tmpFile)) + { + Log.DebugFormat("Removing old temp file {0}", tmpFile); + File.Delete(tmpFile); + } + + TmpFileCache.Remove(tmpFile); + } + } + + /// + /// Cleanup handler for expired tempfiles + /// + /// + /// + private static void RemoveExpiredTmpFile(string filekey, object filename) + { + if (filename is string path && File.Exists(path)) + { + Log.DebugFormat("Removing expired file {0}", path); + File.Delete(path); + } + } + + /// + /// Write the images to the stream as icon + /// Every image is resized to 256x256 (but the content maintains the aspect ratio) + /// + /// Stream to write to + /// List of images + public static void WriteIcon(Stream stream, IList images) + { + var binaryWriter = new BinaryWriter(stream); + // + // ICONDIR structure + // + binaryWriter.Write((short) 0); // reserved + binaryWriter.Write((short) 1); // image type (icon) + binaryWriter.Write((short) images.Count); // number of images + + IList imageSizes = new List(); + IList encodedImages = new List(); + foreach (var image in images) + { + // Pick the best fit + var sizes = new[] + { + 16, 32, 48 + }; + int size = 256; + foreach (var possibleSize in sizes) + { + if (image.Width <= possibleSize && image.Height <= possibleSize) + { + size = possibleSize; + break; + } + } + + var imageStream = new MemoryStream(); + if (image.Width == size && image.Height == size) { using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); clonedImage.Save(imageStream, ImageFormat.Png); imageSizes.Add(new Size(size, size)); } - else + else { // Resize to the specified size, first make sure the image is 32bpp using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); @@ -617,41 +758,41 @@ namespace GreenshotPlugin.Core { imageSizes.Add(resizedImage.Size); } - imageStream.Seek(0, SeekOrigin.Begin); - encodedImages.Add(imageStream); - } + imageStream.Seek(0, SeekOrigin.Begin); + encodedImages.Add(imageStream); + } - // - // ICONDIRENTRY structure - // - const int iconDirSize = 6; - const int iconDirEntrySize = 16; + // + // ICONDIRENTRY structure + // + const int iconDirSize = 6; + const int iconDirEntrySize = 16; - var offset = iconDirSize + (images.Count * iconDirEntrySize); - for (int i = 0; i < images.Count; i++) - { - var imageSize = imageSizes[i]; - // Write the width / height, 0 means 256 - binaryWriter.Write(imageSize.Width == 256 ? (byte)0 : (byte)imageSize.Width); - binaryWriter.Write(imageSize.Height == 256 ? (byte)0 : (byte)imageSize.Height); - binaryWriter.Write((byte)0); // no pallete - binaryWriter.Write((byte)0); // reserved - binaryWriter.Write((short)0); // no color planes - binaryWriter.Write((short)32); // 32 bpp - binaryWriter.Write((int)encodedImages[i].Length); // image data length - binaryWriter.Write(offset); - offset += (int)encodedImages[i].Length; - } + var offset = iconDirSize + (images.Count * iconDirEntrySize); + for (int i = 0; i < images.Count; i++) + { + var imageSize = imageSizes[i]; + // Write the width / height, 0 means 256 + binaryWriter.Write(imageSize.Width == 256 ? (byte) 0 : (byte) imageSize.Width); + binaryWriter.Write(imageSize.Height == 256 ? (byte) 0 : (byte) imageSize.Height); + binaryWriter.Write((byte) 0); // no pallete + binaryWriter.Write((byte) 0); // reserved + binaryWriter.Write((short) 0); // no color planes + binaryWriter.Write((short) 32); // 32 bpp + binaryWriter.Write((int) encodedImages[i].Length); // image data length + binaryWriter.Write(offset); + offset += (int) encodedImages[i].Length; + } - binaryWriter.Flush(); - // - // Write image data - // - foreach (var encodedImage in encodedImages) - { - encodedImage.WriteTo(stream); - encodedImage.Dispose(); - } - } + binaryWriter.Flush(); + // + // Write image data + // + foreach (var encodedImage in encodedImages) + { + encodedImage.WriteTo(stream); + encodedImage.Dispose(); + } + } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/ImageWrapper.cs b/src/GreenshotPlugin/Core/ImageWrapper.cs index 270164cb7..720d2ce50 100644 --- a/src/GreenshotPlugin/Core/ImageWrapper.cs +++ b/src/GreenshotPlugin/Core/ImageWrapper.cs @@ -3,74 +3,75 @@ using System.Drawing.Imaging; namespace GreenshotPlugin.Core { - /// - /// Wrap an image, make it resizeable - /// - public class ImageWrapper : IImage - { - // Underlying image, is used to generate a resized version of it when needed - private readonly Image _image; - private Image _imageClone; + /// + /// Wrap an image, make it resizeable + /// + public class ImageWrapper : IImage + { + // Underlying image, is used to generate a resized version of it when needed + private readonly Image _image; + private Image _imageClone; - public ImageWrapper(Image image) - { - // Make sure the orientation is set correctly so Greenshot can process the image correctly - ImageHelper.Orientate(image); - _image = image; - Width = _image.Width; - Height = _image.Height; - } + public ImageWrapper(Image image) + { + // Make sure the orientation is set correctly so Greenshot can process the image correctly + ImageHelper.Orientate(image); + _image = image; + Width = _image.Width; + Height = _image.Height; + } - public void Dispose() - { - _image.Dispose(); - _imageClone?.Dispose(); - } + public void Dispose() + { + _image.Dispose(); + _imageClone?.Dispose(); + } - /// - /// Height of the image, can be set to change - /// - public int Height { get; set; } + /// + /// Height of the image, can be set to change + /// + public int Height { get; set; } - /// - /// Width of the image, can be set to change. - /// - public int Width { get; set; } + /// + /// Width of the image, can be set to change. + /// + public int Width { get; set; } - /// - /// Size of the image - /// - public Size Size => new Size(Width, Height); + /// + /// Size of the image + /// + public Size Size => new Size(Width, Height); - /// - /// Pixelformat of the underlying image - /// - public PixelFormat PixelFormat => Image.PixelFormat; + /// + /// Pixelformat of the underlying image + /// + public PixelFormat PixelFormat => Image.PixelFormat; - public float HorizontalResolution => Image.HorizontalResolution; - public float VerticalResolution => Image.VerticalResolution; + public float HorizontalResolution => Image.HorizontalResolution; + public float VerticalResolution => Image.VerticalResolution; - public Image Image - { - get - { - if (_imageClone == null) - { - if (_image.Height == Height && _image.Width == Width) - { - return _image; - } - } - if (_imageClone?.Height == Height && _imageClone?.Width == Width) - { - return _imageClone; - } - // Calculate new image clone - _imageClone?.Dispose(); - _imageClone = ImageHelper.ResizeImage(_image, false, Width, Height, null); - return _imageClone; - } - } + public Image Image + { + get + { + if (_imageClone == null) + { + if (_image.Height == Height && _image.Width == Width) + { + return _image; + } + } - } -} + if (_imageClone?.Height == Height && _imageClone?.Width == Width) + { + return _imageClone; + } + + // Calculate new image clone + _imageClone?.Dispose(); + _imageClone = ImageHelper.ResizeImage(_image, false, Width, Height, null); + return _imageClone; + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/InterfaceUtils.cs b/src/GreenshotPlugin/Core/InterfaceUtils.cs index 7dca0f172..c71c7b6ad 100644 --- a/src/GreenshotPlugin/Core/InterfaceUtils.cs +++ b/src/GreenshotPlugin/Core/InterfaceUtils.cs @@ -18,41 +18,56 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Threading; using log4net; -namespace GreenshotPlugin.Core { - /// - /// Description of InterfaceUtils. - /// - public static class InterfaceUtils { - private static readonly ILog LOG = LogManager.GetLogger(typeof(InterfaceUtils)); +namespace GreenshotPlugin.Core +{ + /// + /// Description of InterfaceUtils. + /// + public static class InterfaceUtils + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(InterfaceUtils)); - public static List GetSubclassesOf(Type type, bool excludeSystemTypes) { - var list = new List(); - foreach(var currentAssembly in Thread.GetDomain().GetAssemblies()) { - try { - Type[] types = currentAssembly.GetTypes(); + public static List GetSubclassesOf(Type type, bool excludeSystemTypes) + { + var list = new List(); + foreach (var currentAssembly in Thread.GetDomain().GetAssemblies()) + { + try + { + Type[] types = currentAssembly.GetTypes(); if (excludeSystemTypes && (!excludeSystemTypes || currentAssembly.FullName.StartsWith("System."))) { continue; } - foreach(var currentType in types) { - if (type.IsInterface) { - if (currentType.GetInterface(type.FullName) != null) { + + foreach (var currentType in types) + { + if (type.IsInterface) + { + if (currentType.GetInterface(type.FullName) != null) + { list.Add(currentType); } - } else if (currentType.IsSubclassOf(type)) { + } + else if (currentType.IsSubclassOf(type)) + { list.Add(currentType); } } - } catch (Exception ex) { - LOG.WarnFormat("Problem getting subclasses of type: {0}, message: {1}", type.FullName, ex.Message); - } - } - return list; - } + } + catch (Exception ex) + { + LOG.WarnFormat("Problem getting subclasses of type: {0}, message: {1}", type.FullName, ex.Message); + } + } + + return list; + } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/JSONHelper.cs b/src/GreenshotPlugin/Core/JSONHelper.cs index d02845b72..28a76a71d 100644 --- a/src/GreenshotPlugin/Core/JSONHelper.cs +++ b/src/GreenshotPlugin/Core/JSONHelper.cs @@ -12,348 +12,425 @@ using System.Collections.Generic; using System.Globalization; using System.Text; -namespace GreenshotPlugin.Core { - /// - /// This parses a JSON response, a modified version of the code found at: - /// See: http://techblog.procurios.nl/k/n618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html - /// - /// This file is under the MIT License, which is GPL Compatible and according to: http://en.wikipedia.org/wiki/MIT_License - /// can be used under the GPL "umbrella". - /// - /// TODO: code should be replaced when upgrading to .NET 3.5 or higher!! - /// - public class JSONHelper { - public const int TOKEN_NONE = 0; - public const int TOKEN_CURLY_OPEN = 1; - public const int TOKEN_CURLY_CLOSE = 2; - public const int TOKEN_SQUARED_OPEN = 3; - public const int TOKEN_SQUARED_CLOSE = 4; - public const int TOKEN_COLON = 5; - public const int TOKEN_COMMA = 6; - public const int TOKEN_STRING = 7; - public const int TOKEN_NUMBER = 8; - public const int TOKEN_TRUE = 9; - public const int TOKEN_FALSE = 10; - public const int TOKEN_NULL = 11; +namespace GreenshotPlugin.Core +{ + /// + /// This parses a JSON response, a modified version of the code found at: + /// See: http://techblog.procurios.nl/k/n618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html + /// + /// This file is under the MIT License, which is GPL Compatible and according to: http://en.wikipedia.org/wiki/MIT_License + /// can be used under the GPL "umbrella". + /// + /// TODO: code should be replaced when upgrading to .NET 3.5 or higher!! + /// + public class JSONHelper + { + public const int TOKEN_NONE = 0; + public const int TOKEN_CURLY_OPEN = 1; + public const int TOKEN_CURLY_CLOSE = 2; + public const int TOKEN_SQUARED_OPEN = 3; + public const int TOKEN_SQUARED_CLOSE = 4; + public const int TOKEN_COLON = 5; + public const int TOKEN_COMMA = 6; + public const int TOKEN_STRING = 7; + public const int TOKEN_NUMBER = 8; + public const int TOKEN_TRUE = 9; + public const int TOKEN_FALSE = 10; + public const int TOKEN_NULL = 11; - private const int BUILDER_CAPACITY = 2000; + private const int BUILDER_CAPACITY = 2000; - /// - /// Parses the string json into a value - /// - /// A JSON string. - /// An ArrayList, a Hashtable, a double, a string, null, true, or false - public static IDictionary JsonDecode(string json) { - bool success = true; + /// + /// Parses the string json into a value + /// + /// A JSON string. + /// An ArrayList, a Hashtable, a double, a string, null, true, or false + public static IDictionary JsonDecode(string json) + { + bool success = true; - return JsonDecode(json, ref success); - } + return JsonDecode(json, ref success); + } - /// - /// Parses the string json into a value; and fills 'success' with the successfullness of the parse. - /// - /// A JSON string. - /// Successful parse? - /// An ArrayList, a Hashtable, a double, a string, null, true, or false - public static IDictionary JsonDecode(string json, ref bool success) { - success = true; - if (json != null) { - char[] charArray = json.ToCharArray(); - int index = 0; - IDictionary value = ParseValue(charArray, ref index, ref success) as IDictionary; - return value; - } - return null; - } + /// + /// Parses the string json into a value; and fills 'success' with the successfullness of the parse. + /// + /// A JSON string. + /// Successful parse? + /// An ArrayList, a Hashtable, a double, a string, null, true, or false + public static IDictionary JsonDecode(string json, ref bool success) + { + success = true; + if (json != null) + { + char[] charArray = json.ToCharArray(); + int index = 0; + IDictionary value = ParseValue(charArray, ref index, ref success) as IDictionary; + return value; + } - protected static IDictionary ParseObject(char[] json, ref int index, ref bool success) { - IDictionary table = new Dictionary(); - int token; + return null; + } - // { - NextToken(json, ref index); + protected static IDictionary ParseObject(char[] json, ref int index, ref bool success) + { + IDictionary table = new Dictionary(); + int token; - bool done = false; - while (!done) { - token = LookAhead(json, index); - if (token == TOKEN_NONE) { - success = false; - return null; - } else if (token == TOKEN_COMMA) { - NextToken(json, ref index); - } else if (token == TOKEN_CURLY_CLOSE) { - NextToken(json, ref index); - return table; - } else { + // { + NextToken(json, ref index); - // name - string name = ParseString(json, ref index, ref success); - if (!success) { - success = false; - return null; - } + bool done = false; + while (!done) + { + token = LookAhead(json, index); + if (token == TOKEN_NONE) + { + success = false; + return null; + } + else if (token == TOKEN_COMMA) + { + NextToken(json, ref index); + } + else if (token == TOKEN_CURLY_CLOSE) + { + NextToken(json, ref index); + return table; + } + else + { + // name + string name = ParseString(json, ref index, ref success); + if (!success) + { + success = false; + return null; + } - // : - token = NextToken(json, ref index); - if (token != TOKEN_COLON) { - success = false; - return null; - } + // : + token = NextToken(json, ref index); + if (token != TOKEN_COLON) + { + success = false; + return null; + } - // value - object value = ParseValue(json, ref index, ref success); - if (!success) { - success = false; - return null; - } + // value + object value = ParseValue(json, ref index, ref success); + if (!success) + { + success = false; + return null; + } - table.Add(name, value); - } - } + table.Add(name, value); + } + } - return table; - } + return table; + } - protected static IList ParseArray(char[] json, ref int index, ref bool success) { - IList array = new List(); + protected static IList ParseArray(char[] json, ref int index, ref bool success) + { + IList array = new List(); - // [ - NextToken(json, ref index); + // [ + NextToken(json, ref index); - bool done = false; - while (!done) { - int token = LookAhead(json, index); - if (token == TOKEN_NONE) { - success = false; - return null; - } else if (token == TOKEN_COMMA) { - NextToken(json, ref index); - } else if (token == TOKEN_SQUARED_CLOSE) { - NextToken(json, ref index); - break; - } else { - object value = ParseValue(json, ref index, ref success); - if (!success) { - return null; - } + bool done = false; + while (!done) + { + int token = LookAhead(json, index); + if (token == TOKEN_NONE) + { + success = false; + return null; + } + else if (token == TOKEN_COMMA) + { + NextToken(json, ref index); + } + else if (token == TOKEN_SQUARED_CLOSE) + { + NextToken(json, ref index); + break; + } + else + { + object value = ParseValue(json, ref index, ref success); + if (!success) + { + return null; + } - array.Add(value); - } - } + array.Add(value); + } + } - return array; - } + return array; + } - protected static object ParseValue(char[] json, ref int index, ref bool success) { - switch (LookAhead(json, index)) { - case TOKEN_STRING: - return ParseString(json, ref index, ref success); - case TOKEN_NUMBER: - return ParseNumber(json, ref index, ref success); - case TOKEN_CURLY_OPEN: - return ParseObject(json, ref index, ref success); - case TOKEN_SQUARED_OPEN: - return ParseArray(json, ref index, ref success); - case TOKEN_TRUE: - NextToken(json, ref index); - return true; - case TOKEN_FALSE: - NextToken(json, ref index); - return false; - case TOKEN_NULL: - NextToken(json, ref index); - return null; - case TOKEN_NONE: - break; - } + protected static object ParseValue(char[] json, ref int index, ref bool success) + { + switch (LookAhead(json, index)) + { + case TOKEN_STRING: + return ParseString(json, ref index, ref success); + case TOKEN_NUMBER: + return ParseNumber(json, ref index, ref success); + case TOKEN_CURLY_OPEN: + return ParseObject(json, ref index, ref success); + case TOKEN_SQUARED_OPEN: + return ParseArray(json, ref index, ref success); + case TOKEN_TRUE: + NextToken(json, ref index); + return true; + case TOKEN_FALSE: + NextToken(json, ref index); + return false; + case TOKEN_NULL: + NextToken(json, ref index); + return null; + case TOKEN_NONE: + break; + } - success = false; - return null; - } + success = false; + return null; + } - protected static string ParseString(char[] json, ref int index, ref bool success) { - StringBuilder s = new StringBuilder(BUILDER_CAPACITY); + protected static string ParseString(char[] json, ref int index, ref bool success) + { + StringBuilder s = new StringBuilder(BUILDER_CAPACITY); - EatWhitespace(json, ref index); + EatWhitespace(json, ref index); - // " - var c = json[index++]; + // " + var c = json[index++]; - bool complete = false; - while (!complete) { + bool complete = false; + while (!complete) + { + if (index == json.Length) + { + break; + } - if (index == json.Length) { - break; - } + c = json[index++]; + if (c == '"') + { + complete = true; + break; + } + else if (c == '\\') + { + if (index == json.Length) + { + break; + } - c = json[index++]; - if (c == '"') { - complete = true; - break; - } else if (c == '\\') { + c = json[index++]; + if (c == '"') + { + s.Append('"'); + } + else if (c == '\\') + { + s.Append('\\'); + } + else if (c == '/') + { + s.Append('/'); + } + else if (c == 'b') + { + s.Append('\b'); + } + else if (c == 'f') + { + s.Append('\f'); + } + else if (c == 'n') + { + s.Append('\n'); + } + else if (c == 'r') + { + s.Append('\r'); + } + else if (c == 't') + { + s.Append('\t'); + } + else if (c == 'u') + { + int remainingLength = json.Length - index; + if (remainingLength >= 4) + { + // parse the 32 bit hex into an integer codepoint + if (!(success = uint.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var codePoint))) + { + return string.Empty; + } - if (index == json.Length) { - break; - } - c = json[index++]; - if (c == '"') { - s.Append('"'); - } else if (c == '\\') { - s.Append('\\'); - } else if (c == '/') { - s.Append('/'); - } else if (c == 'b') { - s.Append('\b'); - } else if (c == 'f') { - s.Append('\f'); - } else if (c == 'n') { - s.Append('\n'); - } else if (c == 'r') { - s.Append('\r'); - } else if (c == 't') { - s.Append('\t'); - } else if (c == 'u') { - int remainingLength = json.Length - index; - if (remainingLength >= 4) { - // parse the 32 bit hex into an integer codepoint - if (!(success = uint.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var codePoint))) { - return string.Empty; - } - // convert the integer codepoint to a unicode char and add to string - s.Append(char.ConvertFromUtf32((int)codePoint)); - // skip 4 chars - index += 4; - } else { - break; - } - } + // convert the integer codepoint to a unicode char and add to string + s.Append(char.ConvertFromUtf32((int) codePoint)); + // skip 4 chars + index += 4; + } + else + { + break; + } + } + } + else + { + s.Append(c); + } + } - } else { - s.Append(c); - } + if (!complete) + { + success = false; + return null; + } - } + return s.ToString(); + } - if (!complete) { - success = false; - return null; - } + protected static double ParseNumber(char[] json, ref int index, ref bool success) + { + EatWhitespace(json, ref index); - return s.ToString(); - } - - protected static double ParseNumber(char[] json, ref int index, ref bool success) { - EatWhitespace(json, ref index); - - int lastIndex = GetLastIndexOfNumber(json, index); - int charLength = (lastIndex - index) + 1; + int lastIndex = GetLastIndexOfNumber(json, index); + int charLength = (lastIndex - index) + 1; success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out var number); - index = lastIndex + 1; - return number; - } + index = lastIndex + 1; + return number; + } - protected static int GetLastIndexOfNumber(char[] json, int index) { - int lastIndex; + protected static int GetLastIndexOfNumber(char[] json, int index) + { + int lastIndex; - for (lastIndex = index; lastIndex < json.Length; lastIndex++) { - if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) { - break; - } - } - return lastIndex - 1; - } + for (lastIndex = index; lastIndex < json.Length; lastIndex++) + { + if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) + { + break; + } + } - protected static void EatWhitespace(char[] json, ref int index) { - for (; index < json.Length; index++) { - if (" \t\n\r".IndexOf(json[index]) == -1) { - break; - } - } - } + return lastIndex - 1; + } - protected static int LookAhead(char[] json, int index) { - int saveIndex = index; - return NextToken(json, ref saveIndex); - } + protected static void EatWhitespace(char[] json, ref int index) + { + for (; index < json.Length; index++) + { + if (" \t\n\r".IndexOf(json[index]) == -1) + { + break; + } + } + } - protected static int NextToken(char[] json, ref int index) { - EatWhitespace(json, ref index); + protected static int LookAhead(char[] json, int index) + { + int saveIndex = index; + return NextToken(json, ref saveIndex); + } - if (index == json.Length) { - return TOKEN_NONE; - } + protected static int NextToken(char[] json, ref int index) + { + EatWhitespace(json, ref index); - char c = json[index]; - index++; - switch (c) { - case '{': - return TOKEN_CURLY_OPEN; - case '}': - return TOKEN_CURLY_CLOSE; - case '[': - return TOKEN_SQUARED_OPEN; - case ']': - return TOKEN_SQUARED_CLOSE; - case ',': - return TOKEN_COMMA; - case '"': - return TOKEN_STRING; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - return TOKEN_NUMBER; - case ':': - return TOKEN_COLON; - } - index--; + if (index == json.Length) + { + return TOKEN_NONE; + } - int remainingLength = json.Length - index; + char c = json[index]; + index++; + switch (c) + { + case '{': + return TOKEN_CURLY_OPEN; + case '}': + return TOKEN_CURLY_CLOSE; + case '[': + return TOKEN_SQUARED_OPEN; + case ']': + return TOKEN_SQUARED_CLOSE; + case ',': + return TOKEN_COMMA; + case '"': + return TOKEN_STRING; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return TOKEN_NUMBER; + case ':': + return TOKEN_COLON; + } - // false - if (remainingLength >= 5) { - if (json[index] == 'f' && - json[index + 1] == 'a' && - json[index + 2] == 'l' && - json[index + 3] == 's' && - json[index + 4] == 'e') { - index += 5; - return TOKEN_FALSE; - } - } + index--; - // true - if (remainingLength >= 4) { - if (json[index] == 't' && - json[index + 1] == 'r' && - json[index + 2] == 'u' && - json[index + 3] == 'e') { - index += 4; - return TOKEN_TRUE; - } - } + int remainingLength = json.Length - index; - // null - if (remainingLength >= 4) { - if (json[index] == 'n' && - json[index + 1] == 'u' && - json[index + 2] == 'l' && - json[index + 3] == 'l') { - index += 4; - return TOKEN_NULL; - } - } + // false + if (remainingLength >= 5) + { + if (json[index] == 'f' && + json[index + 1] == 'a' && + json[index + 2] == 'l' && + json[index + 3] == 's' && + json[index + 4] == 'e') + { + index += 5; + return TOKEN_FALSE; + } + } - return TOKEN_NONE; - } - } -} + // true + if (remainingLength >= 4) + { + if (json[index] == 't' && + json[index + 1] == 'r' && + json[index + 2] == 'u' && + json[index + 3] == 'e') + { + index += 4; + return TOKEN_TRUE; + } + } + + // null + if (remainingLength >= 4) + { + if (json[index] == 'n' && + json[index + 1] == 'u' && + json[index + 2] == 'l' && + json[index + 3] == 'l') + { + index += 4; + return TOKEN_NULL; + } + } + + return TOKEN_NONE; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Language.cs b/src/GreenshotPlugin/Core/Language.cs index 1b60b6dc8..ae0b4ed0f 100644 --- a/src/GreenshotPlugin/Core/Language.cs +++ b/src/GreenshotPlugin/Core/Language.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.IO; @@ -28,617 +29,779 @@ using GreenshotPlugin.IniFile; using log4net; using Microsoft.Win32; -namespace GreenshotPlugin.Core { +namespace GreenshotPlugin.Core +{ /// - /// This class supplies the GUI with translations, based upon keys. - /// The language resources are loaded from the language files found on fixed or supplied paths - /// - public class Language { - private static readonly ILog Log = LogManager.GetLogger(typeof(Language)); - private static readonly List LanguagePaths = new List(); - private static readonly Dictionary> LanguageFiles = new Dictionary>(); - private static readonly Dictionary HelpFiles = new Dictionary(); - private const string DefaultLanguage = "en-US"; - private const string HelpFilenamePattern = @"help-*.html"; - private const string LanguageFilenamePattern = @"language*.xml"; - private static readonly Regex PrefixRegexp = new Regex(@"language_([a-zA-Z0-9]+).*"); - private static readonly Regex IetfCleanRegexp = new Regex(@"[^a-zA-Z]+"); - private static readonly Regex IetfRegexp = new Regex(@"^.*([a-zA-Z]{2,3}-[a-zA-Z]{1,2})\.xml$"); - private const string LanguageGroupsKey = @"SYSTEM\CurrentControlSet\Control\Nls\Language Groups"; - private static readonly List UnsupportedLanguageGroups = new List(); - private static readonly Dictionary Resources = new Dictionary(); - private static string _currentLanguage; + /// This class supplies the GUI with translations, based upon keys. + /// The language resources are loaded from the language files found on fixed or supplied paths + /// + public class Language + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Language)); + private static readonly List LanguagePaths = new List(); + private static readonly Dictionary> LanguageFiles = new Dictionary>(); + private static readonly Dictionary HelpFiles = new Dictionary(); + private const string DefaultLanguage = "en-US"; + private const string HelpFilenamePattern = @"help-*.html"; + private const string LanguageFilenamePattern = @"language*.xml"; + private static readonly Regex PrefixRegexp = new Regex(@"language_([a-zA-Z0-9]+).*"); + private static readonly Regex IetfCleanRegexp = new Regex(@"[^a-zA-Z]+"); + private static readonly Regex IetfRegexp = new Regex(@"^.*([a-zA-Z]{2,3}-[a-zA-Z]{1,2})\.xml$"); + private const string LanguageGroupsKey = @"SYSTEM\CurrentControlSet\Control\Nls\Language Groups"; + private static readonly List UnsupportedLanguageGroups = new List(); + private static readonly Dictionary Resources = new Dictionary(); + private static string _currentLanguage; - public static event LanguageChangedHandler LanguageChanged; - - /// - /// Static initializer for the language code - /// - static Language() { - if (!IniConfig.IsInitialized) { - Log.Warn("IniConfig hasn't been initialized yet! (Design mode?)"); - IniConfig.Init("greenshot", "greenshot"); - } - if (!LogHelper.IsInitialized) { - Log.Warn("Log4net hasn't been initialized yet! (Design mode?)"); - LogHelper.InitializeLog4Net(); - } - - try { - string applicationFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - - // PAF Path - if (applicationFolder != null) - { - AddPath(Path.Combine(applicationFolder, @"App\Greenshot\Languages")); - } - // Application data path - string applicationDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - AddPath(Path.Combine(applicationDataFolder, @"Greenshot\Languages\")); - - // Startup path - if (applicationFolder != null) - { - AddPath(Path.Combine(applicationFolder, @"Languages")); - } - } - catch (Exception pathException) { - Log.Error(pathException); - } - - try - { - using RegistryKey languageGroupsKey = Registry.LocalMachine.OpenSubKey(LanguageGroupsKey, false); - if (languageGroupsKey != null) { - string [] groups = languageGroupsKey.GetValueNames(); - foreach(string group in groups) { - string groupValue = (string)languageGroupsKey.GetValue(group); - bool isGroupNotInstalled = "0".Equals(groupValue); - if (isGroupNotInstalled) { - UnsupportedLanguageGroups.Add(group.ToLower()); - } - } - } - } catch(Exception e) { - Log.Warn("Couldn't read the installed language groups.", e); - } - - var coreConfig = IniConfig.GetIniSection(); - ScanFiles(); - if (!string.IsNullOrEmpty(coreConfig.Language)) { - CurrentLanguage = coreConfig.Language; - if (CurrentLanguage != null && CurrentLanguage != coreConfig.Language) { - coreConfig.Language = CurrentLanguage; - } - } - - if (CurrentLanguage == null) { - Log.Warn("Couldn't set language from configuration, changing to default. Installation problem?"); - CurrentLanguage = DefaultLanguage; - if (CurrentLanguage != null) { - coreConfig.Language = CurrentLanguage; - } - } - - if (CurrentLanguage == null) { - Log.Error("Couldn't set language, installation problem?"); - } - } - - /// - /// Internal method to add a path to the paths that will be scanned for language files! - /// - /// - /// true if the path exists and is added - private static bool AddPath(string path) { - if (!LanguagePaths.Contains(path)) - { - if (Directory.Exists(path)) { - Log.DebugFormat("Adding language path {0}", path); - LanguagePaths.Add(path); - return true; - } - - Log.InfoFormat("Not adding non existing language path {0}", path); - } - return false; - } - - /// - /// Add a new path to the paths that will be scanned for language files! - /// - /// - /// true if the path exists and is added - public static bool AddLanguageFilePath(string path) { - if (!LanguagePaths.Contains(path)) { - Log.DebugFormat("New language path {0}", path); - if (AddPath(path)) { - ScanFiles(); - Reload(); - } else { - return false; - } - } - return true; - } - - /// - /// Load the files for the specified ietf - /// - /// - private static void LoadFiles(string ietf) { - ietf = ReformatIetf(ietf); - if (!LanguageFiles.ContainsKey(ietf)) { - Log.ErrorFormat("No language {0} available.", ietf); - return; - } - List filesToLoad = LanguageFiles[ietf]; - foreach (LanguageFile fileToLoad in filesToLoad) { - LoadResources(fileToLoad); - } - } - - /// - /// Load the language resources from the scanned files - /// - private static void Reload() { - Resources.Clear(); - LoadFiles(DefaultLanguage); - if (_currentLanguage != null && !_currentLanguage.Equals(DefaultLanguage)) { - LoadFiles(_currentLanguage); - } - } - - /// - /// Get or set the current language - /// - public static string CurrentLanguage { - get => _currentLanguage; - set { - string ietf = FindBestIetfMatch(value); - if (!LanguageFiles.ContainsKey(ietf)) { - Log.WarnFormat("No match for language {0} found!", ietf); - } else { - if (_currentLanguage == null || !_currentLanguage.Equals(ietf)) { - _currentLanguage = ietf; - Reload(); - if (LanguageChanged == null) - { - return; - } - try { - LanguageChanged(null, null); - } - catch - { - // ignored - } - return; - } - } - Log.Debug("CurrentLanguage not changed!"); - } - } - - /// - /// Try to find the best match for the supplied IETF - /// - /// string - /// IETF - private static string FindBestIetfMatch(string inputIetf) { - string returnIetf = inputIetf; - if (string.IsNullOrEmpty(returnIetf)) { - returnIetf = DefaultLanguage; - } - returnIetf = ReformatIetf(returnIetf); - if (!LanguageFiles.ContainsKey(returnIetf)) { - Log.WarnFormat("Unknown language {0}, trying best match!", returnIetf); - if (returnIetf.Length == 5) { - returnIetf = returnIetf.Substring(0, 2); - } - foreach (string availableIetf in LanguageFiles.Keys) { - if (!availableIetf.StartsWith(returnIetf)) continue; - - Log.InfoFormat("Found language {0}, best match for {1}!", availableIetf, returnIetf); - returnIetf = availableIetf; - break; - } - } - return returnIetf; - } - - /// - /// This helper method clears all non alpha characters from the IETF, and does a reformatting. - /// This prevents problems with multiple formats or typos. - /// - /// - /// - private static string ReformatIetf(string inputIetf) { - string returnIetf = null; - if (!string.IsNullOrEmpty(inputIetf)) { - returnIetf = inputIetf.ToLower(); - returnIetf = IetfCleanRegexp.Replace(returnIetf, string.Empty); - if (returnIetf.Length == 4) { - returnIetf = returnIetf.Substring(0, 2) + "-" + returnIetf.Substring(2, 2).ToUpper(); - } - } - return returnIetf; - } - - /// - /// Return a list of all the supported languages - /// - public static IList SupportedLanguages { - get { - IList languages = new List(); - // Loop over all languages with all the files in there - foreach (List langs in LanguageFiles.Values) { - // Loop over all the files for a language - foreach (LanguageFile langFile in langs) { - // Only take the ones without prefix, these are the "base" language files - if (langFile.Prefix != null) continue; - languages.Add(langFile); - break; - } - } - return languages; - } - } - - /// - /// Return the path to the help-file - /// - public static string HelpFilePath { - get { - if (HelpFiles.ContainsKey(_currentLanguage)) { - return HelpFiles[_currentLanguage]; - } - return HelpFiles[DefaultLanguage]; - } - } - - /// - /// Load the resources from the language file - /// - /// File to load from - private static void LoadResources(LanguageFile languageFile) { - Log.InfoFormat("Loading language file {0}", languageFile.Filepath); - try { - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.Load(languageFile.Filepath); - XmlNodeList resourceNodes = xmlDocument.GetElementsByTagName("resource"); - foreach (XmlNode resourceNode in resourceNodes) { - string key = resourceNode.Attributes["name"].Value; - if (!string.IsNullOrEmpty(languageFile.Prefix)) { - key = languageFile.Prefix + "." + key; - } - string text = resourceNode.InnerText; - if (!string.IsNullOrEmpty(text)) { - text = text.Trim(); - } - if (!Resources.ContainsKey(key)) { - Resources.Add(key, text); - } else { - Resources[key] = text; - } - } - } catch (Exception e) { - Log.Error("Could not load language file " + languageFile.Filepath, e); - } - } - - /// - /// Load the language file information - /// - /// - /// - private static LanguageFile LoadFileInfo(string languageFilePath) { - try { - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.Load(languageFilePath); - XmlNodeList nodes = xmlDocument.GetElementsByTagName("language"); - if (nodes.Count > 0) { - LanguageFile languageFile = new LanguageFile - { - Filepath = languageFilePath - }; - XmlNode node = nodes.Item(0); - if (node?.Attributes != null) - { - languageFile.Description = node.Attributes["description"].Value; - if (node.Attributes["ietf"] != null) { - languageFile.Ietf = ReformatIetf(node.Attributes["ietf"].Value); - } - if (node.Attributes["version"] != null) { - languageFile.Version = new Version(node.Attributes["version"].Value); - } - if (node.Attributes["prefix"] != null) { - languageFile.Prefix = node.Attributes["prefix"].Value.ToLower(); - } - if (node.Attributes["languagegroup"] != null) { - string languageGroup = node.Attributes["languagegroup"].Value; - languageFile.LanguageGroup = languageGroup.ToLower(); - } - } - return languageFile; - } - throw new XmlException("Root element is missing"); - } catch (Exception e) { - Log.Error("Could not load language file " + languageFilePath, e); - } - return null; - } - - /// - /// Scan the files in all directories - /// - private static void ScanFiles() { - LanguageFiles.Clear(); - HelpFiles.Clear(); - foreach (string languagePath in LanguagePaths) { - if (!Directory.Exists(languagePath)) { - Log.InfoFormat("Skipping non existing language path {0}", languagePath); - continue; - } - Log.InfoFormat("Searching language directory '{0}' for language files with pattern '{1}'", languagePath, LanguageFilenamePattern); - try { - foreach (string languageFilepath in Directory.GetFiles(languagePath, LanguageFilenamePattern, SearchOption.AllDirectories)) { - //LOG.DebugFormat("Found language file: {0}", languageFilepath); - LanguageFile languageFile = LoadFileInfo(languageFilepath); - if (languageFile == null) { - continue; - } - if (string.IsNullOrEmpty(languageFile.Ietf)) { - Log.WarnFormat("Fixing missing ietf in language-file {0}", languageFilepath); - string languageFilename = Path.GetFileName(languageFilepath); - if (IetfRegexp.IsMatch(languageFilename)) { - string replacementIetf = IetfRegexp.Replace(languageFilename, "$1"); - languageFile.Ietf = ReformatIetf(replacementIetf); - Log.InfoFormat("Fixed IETF to {0}", languageFile.Ietf); - } else { - Log.ErrorFormat("Missing ietf , no recover possible... skipping language-file {0}!", languageFilepath); - continue; - } - } - - // Check if we can display the file - if (!string.IsNullOrEmpty(languageFile.LanguageGroup) && UnsupportedLanguageGroups.Contains(languageFile.LanguageGroup)) { - Log.InfoFormat("Skipping unsuported (not able to display) language {0} from file {1}", languageFile.Description, languageFilepath); - continue; - } - - // build prefix, based on the filename, but only if it's not set in the file itself. - if (string.IsNullOrEmpty(languageFile.Prefix)) { - string languageFilename = Path.GetFileNameWithoutExtension(languageFilepath); - if (PrefixRegexp.IsMatch(languageFilename)) { - languageFile.Prefix = PrefixRegexp.Replace(languageFilename, "$1"); - if (!string.IsNullOrEmpty(languageFile.Prefix)) { - languageFile.Prefix = languageFile.Prefix.Replace("plugin", string.Empty).ToLower(); - } - } - } - List currentFiles; - if (LanguageFiles.ContainsKey(languageFile.Ietf)) { - currentFiles = LanguageFiles[languageFile.Ietf]; - bool needToAdd = true; - List deleteList = new List(); - foreach (LanguageFile compareWithLangfile in currentFiles) { - if ((languageFile.Prefix != null || compareWithLangfile.Prefix != null) && - (languageFile.Prefix == null || - !languageFile.Prefix.Equals(compareWithLangfile.Prefix))) continue; - - if (compareWithLangfile.Version > languageFile.Version) { - Log.WarnFormat("Skipping {0}:{1}:{2} as {3}:{4}:{5} is newer", languageFile.Filepath, languageFile.Prefix, languageFile.Version, compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); - needToAdd = false; - break; - } - - Log.WarnFormat("Found {0}:{1}:{2} and deleting {3}:{4}:{5}", languageFile.Filepath, languageFile.Prefix, languageFile.Version, compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); - deleteList.Add(compareWithLangfile); - } - if (needToAdd) { - foreach (LanguageFile deleteFile in deleteList) { - currentFiles.Remove(deleteFile); - } - Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); - currentFiles.Add(languageFile); - } - } else { - currentFiles = new List {languageFile}; - LanguageFiles.Add(languageFile.Ietf, currentFiles); - Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); - } - } - } catch (DirectoryNotFoundException) { - Log.InfoFormat("Non existing language directory: {0}", languagePath); - } catch (Exception e) { - Log.Error("Error trying for read directory " + languagePath, e); - } - - // Now find the help files - Log.InfoFormat("Searching language directory '{0}' for help files with pattern '{1}'", languagePath, HelpFilenamePattern); - try { - foreach (string helpFilepath in Directory.GetFiles(languagePath, HelpFilenamePattern, SearchOption.AllDirectories)) { - Log.DebugFormat("Found help file: {0}", helpFilepath); - string helpFilename = Path.GetFileName(helpFilepath); - string ietf = ReformatIetf(helpFilename.Replace(".html", string.Empty).Replace("help-", "")); - if (!HelpFiles.ContainsKey(ietf)) { - HelpFiles.Add(ietf, helpFilepath); - } else { - Log.WarnFormat("skipping help file {0}, already a file with the same IETF {1} found!", helpFilepath, ietf); - } - } - } catch (DirectoryNotFoundException) { - Log.InfoFormat("Non existing language directory: {0}", languagePath); - } catch (Exception e) { - Log.Error("Error trying for read directory " + languagePath, e); - } - } - } + public static event LanguageChangedHandler LanguageChanged; /// - /// Check if a resource with prefix.key exists - /// - /// - /// - /// true if available - public static bool HasKey(string prefix, string key) { - return HasKey(prefix + "." + key); - } + /// Static initializer for the language code + /// + static Language() + { + if (!IniConfig.IsInitialized) + { + Log.Warn("IniConfig hasn't been initialized yet! (Design mode?)"); + IniConfig.Init("greenshot", "greenshot"); + } - /// - /// Check if a resource with key exists - /// - /// - /// true if available - public static bool HasKey(string key) { - if (key == null) { - return false; - } - return Resources.ContainsKey(key); - } - - /// - /// TryGet method which combines HasKey & GetString - /// - /// - /// out string - /// - public static bool TryGetString(string key, out string languageString) { - return Resources.TryGetValue(key, out languageString); - } + if (!LogHelper.IsInitialized) + { + Log.Warn("Log4net hasn't been initialized yet! (Design mode?)"); + LogHelper.InitializeLog4Net(); + } - /// - /// TryGet method which combines HasKey & GetString - /// - /// string with prefix - /// string with key - /// out string - /// - public static bool TryGetString(string prefix, string key, out string languageString) { - return Resources.TryGetValue(prefix + "." + key, out languageString); - } + try + { + string applicationFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - /// - /// TryGet method which combines HasKey & GetString - /// - /// string with prefix - /// Enum with key - /// out string - /// - public static bool TryGetString(string prefix, Enum key, out string languageString) - { - return Resources.TryGetValue(prefix + "." + key, out languageString); - } + // PAF Path + if (applicationFolder != null) + { + AddPath(Path.Combine(applicationFolder, @"App\Greenshot\Languages")); + } - /// - /// Translate - /// - /// object - /// string - public static string Translate(object key) { - string typename = key.GetType().Name; - string enumKey = typename + "." + key; - if (HasKey(enumKey)) { - return GetString(enumKey); - } - return key.ToString(); - } + // Application data path + string applicationDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + AddPath(Path.Combine(applicationDataFolder, @"Greenshot\Languages\")); - /// - /// Get the resource for key - /// - /// Enum - /// resource or a "string ###key### not found" - public static string GetString(Enum key) { - if (key == null) { - return null; - } - return GetString(key.ToString()); - } + // Startup path + if (applicationFolder != null) + { + AddPath(Path.Combine(applicationFolder, @"Languages")); + } + } + catch (Exception pathException) + { + Log.Error(pathException); + } - /// - /// Get the resource for prefix.key - /// - /// string - /// Enum - /// resource or a "string ###prefix.key### not found" - public static string GetString(string prefix, Enum key) { - if (key == null) { - return null; - } - return GetString(prefix + "." + key); - } + try + { + using RegistryKey languageGroupsKey = Registry.LocalMachine.OpenSubKey(LanguageGroupsKey, false); + if (languageGroupsKey != null) + { + string[] groups = languageGroupsKey.GetValueNames(); + foreach (string group in groups) + { + string groupValue = (string) languageGroupsKey.GetValue(group); + bool isGroupNotInstalled = "0".Equals(groupValue); + if (isGroupNotInstalled) + { + UnsupportedLanguageGroups.Add(group.ToLower()); + } + } + } + } + catch (Exception e) + { + Log.Warn("Couldn't read the installed language groups.", e); + } - /// - /// Get the resource for prefix.key - /// - /// string - /// string - /// resource or a "string ###prefix.key### not found" - public static string GetString(string prefix, string key) { - return GetString(prefix + "." + key); - } + var coreConfig = IniConfig.GetIniSection(); + ScanFiles(); + if (!string.IsNullOrEmpty(coreConfig.Language)) + { + CurrentLanguage = coreConfig.Language; + if (CurrentLanguage != null && CurrentLanguage != coreConfig.Language) + { + coreConfig.Language = CurrentLanguage; + } + } - /// - /// Get the resource for key - /// - /// string - /// resource or a "string ###key### not found" - public static string GetString(string key) { - if (key == null) { - return null; - } + if (CurrentLanguage == null) + { + Log.Warn("Couldn't set language from configuration, changing to default. Installation problem?"); + CurrentLanguage = DefaultLanguage; + if (CurrentLanguage != null) + { + coreConfig.Language = CurrentLanguage; + } + } - if (!Resources.TryGetValue(key, out var returnValue)) { - return "string ###" + key + "### not found"; - } - return returnValue; - } + if (CurrentLanguage == null) + { + Log.Error("Couldn't set language, installation problem?"); + } + } - /// - /// Get the resource for key, format with with string.format an supply the parameters - /// - /// Enum - /// object - /// formatted resource or a "string ###key### not found" - public static string GetFormattedString(Enum key, object param) { - return GetFormattedString(key.ToString(), param); - } + /// + /// Internal method to add a path to the paths that will be scanned for language files! + /// + /// + /// true if the path exists and is added + private static bool AddPath(string path) + { + if (!LanguagePaths.Contains(path)) + { + if (Directory.Exists(path)) + { + Log.DebugFormat("Adding language path {0}", path); + LanguagePaths.Add(path); + return true; + } - /// - /// Get the resource for prefix.key, format with with string.format an supply the parameters - /// - /// string - /// Enum - /// object - /// formatted resource or a "string ###prefix.key### not found" - public static string GetFormattedString(string prefix, Enum key, object param) { - return GetFormattedString(prefix, key.ToString(), param); - } + Log.InfoFormat("Not adding non existing language path {0}", path); + } - /// - /// Get the resource for prefix.key, format with with string.format an supply the parameters - /// - /// string - /// string - /// object - /// formatted resource or a "string ###prefix.key### not found" - public static string GetFormattedString(string prefix, string key, object param) { - return GetFormattedString(prefix + "." + key, param); - } + return false; + } - /// - /// Get the resource for key, format with with string.format an supply the parameters - /// - /// string - /// object - /// formatted resource or a "string ###key### not found" - public static string GetFormattedString(string key, object param) { - if (!Resources.TryGetValue(key, out var returnValue)) { - return "string ###" + key + "### not found"; - } - return string.Format(returnValue, param); - } - } -} + /// + /// Add a new path to the paths that will be scanned for language files! + /// + /// + /// true if the path exists and is added + public static bool AddLanguageFilePath(string path) + { + if (!LanguagePaths.Contains(path)) + { + Log.DebugFormat("New language path {0}", path); + if (AddPath(path)) + { + ScanFiles(); + Reload(); + } + else + { + return false; + } + } + + return true; + } + + /// + /// Load the files for the specified ietf + /// + /// + private static void LoadFiles(string ietf) + { + ietf = ReformatIetf(ietf); + if (!LanguageFiles.ContainsKey(ietf)) + { + Log.ErrorFormat("No language {0} available.", ietf); + return; + } + + List filesToLoad = LanguageFiles[ietf]; + foreach (LanguageFile fileToLoad in filesToLoad) + { + LoadResources(fileToLoad); + } + } + + /// + /// Load the language resources from the scanned files + /// + private static void Reload() + { + Resources.Clear(); + LoadFiles(DefaultLanguage); + if (_currentLanguage != null && !_currentLanguage.Equals(DefaultLanguage)) + { + LoadFiles(_currentLanguage); + } + } + + /// + /// Get or set the current language + /// + public static string CurrentLanguage + { + get => _currentLanguage; + set + { + string ietf = FindBestIetfMatch(value); + if (!LanguageFiles.ContainsKey(ietf)) + { + Log.WarnFormat("No match for language {0} found!", ietf); + } + else + { + if (_currentLanguage == null || !_currentLanguage.Equals(ietf)) + { + _currentLanguage = ietf; + Reload(); + if (LanguageChanged == null) + { + return; + } + + try + { + LanguageChanged(null, null); + } + catch + { + // ignored + } + + return; + } + } + + Log.Debug("CurrentLanguage not changed!"); + } + } + + /// + /// Try to find the best match for the supplied IETF + /// + /// string + /// IETF + private static string FindBestIetfMatch(string inputIetf) + { + string returnIetf = inputIetf; + if (string.IsNullOrEmpty(returnIetf)) + { + returnIetf = DefaultLanguage; + } + + returnIetf = ReformatIetf(returnIetf); + if (!LanguageFiles.ContainsKey(returnIetf)) + { + Log.WarnFormat("Unknown language {0}, trying best match!", returnIetf); + if (returnIetf.Length == 5) + { + returnIetf = returnIetf.Substring(0, 2); + } + + foreach (string availableIetf in LanguageFiles.Keys) + { + if (!availableIetf.StartsWith(returnIetf)) continue; + + Log.InfoFormat("Found language {0}, best match for {1}!", availableIetf, returnIetf); + returnIetf = availableIetf; + break; + } + } + + return returnIetf; + } + + /// + /// This helper method clears all non alpha characters from the IETF, and does a reformatting. + /// This prevents problems with multiple formats or typos. + /// + /// + /// + private static string ReformatIetf(string inputIetf) + { + string returnIetf = null; + if (!string.IsNullOrEmpty(inputIetf)) + { + returnIetf = inputIetf.ToLower(); + returnIetf = IetfCleanRegexp.Replace(returnIetf, string.Empty); + if (returnIetf.Length == 4) + { + returnIetf = returnIetf.Substring(0, 2) + "-" + returnIetf.Substring(2, 2).ToUpper(); + } + } + + return returnIetf; + } + + /// + /// Return a list of all the supported languages + /// + public static IList SupportedLanguages + { + get + { + IList languages = new List(); + // Loop over all languages with all the files in there + foreach (List langs in LanguageFiles.Values) + { + // Loop over all the files for a language + foreach (LanguageFile langFile in langs) + { + // Only take the ones without prefix, these are the "base" language files + if (langFile.Prefix != null) continue; + languages.Add(langFile); + break; + } + } + + return languages; + } + } + + /// + /// Return the path to the help-file + /// + public static string HelpFilePath + { + get + { + if (HelpFiles.ContainsKey(_currentLanguage)) + { + return HelpFiles[_currentLanguage]; + } + + return HelpFiles[DefaultLanguage]; + } + } + + /// + /// Load the resources from the language file + /// + /// File to load from + private static void LoadResources(LanguageFile languageFile) + { + Log.InfoFormat("Loading language file {0}", languageFile.Filepath); + try + { + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.Load(languageFile.Filepath); + XmlNodeList resourceNodes = xmlDocument.GetElementsByTagName("resource"); + foreach (XmlNode resourceNode in resourceNodes) + { + string key = resourceNode.Attributes["name"].Value; + if (!string.IsNullOrEmpty(languageFile.Prefix)) + { + key = languageFile.Prefix + "." + key; + } + + string text = resourceNode.InnerText; + if (!string.IsNullOrEmpty(text)) + { + text = text.Trim(); + } + + if (!Resources.ContainsKey(key)) + { + Resources.Add(key, text); + } + else + { + Resources[key] = text; + } + } + } + catch (Exception e) + { + Log.Error("Could not load language file " + languageFile.Filepath, e); + } + } + + /// + /// Load the language file information + /// + /// + /// + private static LanguageFile LoadFileInfo(string languageFilePath) + { + try + { + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.Load(languageFilePath); + XmlNodeList nodes = xmlDocument.GetElementsByTagName("language"); + if (nodes.Count > 0) + { + LanguageFile languageFile = new LanguageFile + { + Filepath = languageFilePath + }; + XmlNode node = nodes.Item(0); + if (node?.Attributes != null) + { + languageFile.Description = node.Attributes["description"].Value; + if (node.Attributes["ietf"] != null) + { + languageFile.Ietf = ReformatIetf(node.Attributes["ietf"].Value); + } + + if (node.Attributes["version"] != null) + { + languageFile.Version = new Version(node.Attributes["version"].Value); + } + + if (node.Attributes["prefix"] != null) + { + languageFile.Prefix = node.Attributes["prefix"].Value.ToLower(); + } + + if (node.Attributes["languagegroup"] != null) + { + string languageGroup = node.Attributes["languagegroup"].Value; + languageFile.LanguageGroup = languageGroup.ToLower(); + } + } + + return languageFile; + } + + throw new XmlException("Root element is missing"); + } + catch (Exception e) + { + Log.Error("Could not load language file " + languageFilePath, e); + } + + return null; + } + + /// + /// Scan the files in all directories + /// + private static void ScanFiles() + { + LanguageFiles.Clear(); + HelpFiles.Clear(); + foreach (string languagePath in LanguagePaths) + { + if (!Directory.Exists(languagePath)) + { + Log.InfoFormat("Skipping non existing language path {0}", languagePath); + continue; + } + + Log.InfoFormat("Searching language directory '{0}' for language files with pattern '{1}'", languagePath, LanguageFilenamePattern); + try + { + foreach (string languageFilepath in Directory.GetFiles(languagePath, LanguageFilenamePattern, SearchOption.AllDirectories)) + { + //LOG.DebugFormat("Found language file: {0}", languageFilepath); + LanguageFile languageFile = LoadFileInfo(languageFilepath); + if (languageFile == null) + { + continue; + } + + if (string.IsNullOrEmpty(languageFile.Ietf)) + { + Log.WarnFormat("Fixing missing ietf in language-file {0}", languageFilepath); + string languageFilename = Path.GetFileName(languageFilepath); + if (IetfRegexp.IsMatch(languageFilename)) + { + string replacementIetf = IetfRegexp.Replace(languageFilename, "$1"); + languageFile.Ietf = ReformatIetf(replacementIetf); + Log.InfoFormat("Fixed IETF to {0}", languageFile.Ietf); + } + else + { + Log.ErrorFormat("Missing ietf , no recover possible... skipping language-file {0}!", languageFilepath); + continue; + } + } + + // Check if we can display the file + if (!string.IsNullOrEmpty(languageFile.LanguageGroup) && UnsupportedLanguageGroups.Contains(languageFile.LanguageGroup)) + { + Log.InfoFormat("Skipping unsuported (not able to display) language {0} from file {1}", languageFile.Description, languageFilepath); + continue; + } + + // build prefix, based on the filename, but only if it's not set in the file itself. + if (string.IsNullOrEmpty(languageFile.Prefix)) + { + string languageFilename = Path.GetFileNameWithoutExtension(languageFilepath); + if (PrefixRegexp.IsMatch(languageFilename)) + { + languageFile.Prefix = PrefixRegexp.Replace(languageFilename, "$1"); + if (!string.IsNullOrEmpty(languageFile.Prefix)) + { + languageFile.Prefix = languageFile.Prefix.Replace("plugin", string.Empty).ToLower(); + } + } + } + + List currentFiles; + if (LanguageFiles.ContainsKey(languageFile.Ietf)) + { + currentFiles = LanguageFiles[languageFile.Ietf]; + bool needToAdd = true; + List deleteList = new List(); + foreach (LanguageFile compareWithLangfile in currentFiles) + { + if ((languageFile.Prefix != null || compareWithLangfile.Prefix != null) && + (languageFile.Prefix == null || + !languageFile.Prefix.Equals(compareWithLangfile.Prefix))) continue; + + if (compareWithLangfile.Version > languageFile.Version) + { + Log.WarnFormat("Skipping {0}:{1}:{2} as {3}:{4}:{5} is newer", languageFile.Filepath, languageFile.Prefix, languageFile.Version, + compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); + needToAdd = false; + break; + } + + Log.WarnFormat("Found {0}:{1}:{2} and deleting {3}:{4}:{5}", languageFile.Filepath, languageFile.Prefix, languageFile.Version, + compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); + deleteList.Add(compareWithLangfile); + } + + if (needToAdd) + { + foreach (LanguageFile deleteFile in deleteList) + { + currentFiles.Remove(deleteFile); + } + + Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); + currentFiles.Add(languageFile); + } + } + else + { + currentFiles = new List + { + languageFile + }; + LanguageFiles.Add(languageFile.Ietf, currentFiles); + Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); + } + } + } + catch (DirectoryNotFoundException) + { + Log.InfoFormat("Non existing language directory: {0}", languagePath); + } + catch (Exception e) + { + Log.Error("Error trying for read directory " + languagePath, e); + } + + // Now find the help files + Log.InfoFormat("Searching language directory '{0}' for help files with pattern '{1}'", languagePath, HelpFilenamePattern); + try + { + foreach (string helpFilepath in Directory.GetFiles(languagePath, HelpFilenamePattern, SearchOption.AllDirectories)) + { + Log.DebugFormat("Found help file: {0}", helpFilepath); + string helpFilename = Path.GetFileName(helpFilepath); + string ietf = ReformatIetf(helpFilename.Replace(".html", string.Empty).Replace("help-", "")); + if (!HelpFiles.ContainsKey(ietf)) + { + HelpFiles.Add(ietf, helpFilepath); + } + else + { + Log.WarnFormat("skipping help file {0}, already a file with the same IETF {1} found!", helpFilepath, ietf); + } + } + } + catch (DirectoryNotFoundException) + { + Log.InfoFormat("Non existing language directory: {0}", languagePath); + } + catch (Exception e) + { + Log.Error("Error trying for read directory " + languagePath, e); + } + } + } + + /// + /// Check if a resource with prefix.key exists + /// + /// + /// + /// true if available + public static bool HasKey(string prefix, string key) + { + return HasKey(prefix + "." + key); + } + + /// + /// Check if a resource with key exists + /// + /// + /// true if available + public static bool HasKey(string key) + { + if (key == null) + { + return false; + } + + return Resources.ContainsKey(key); + } + + /// + /// TryGet method which combines HasKey & GetString + /// + /// + /// out string + /// + public static bool TryGetString(string key, out string languageString) + { + return Resources.TryGetValue(key, out languageString); + } + + /// + /// TryGet method which combines HasKey & GetString + /// + /// string with prefix + /// string with key + /// out string + /// + public static bool TryGetString(string prefix, string key, out string languageString) + { + return Resources.TryGetValue(prefix + "." + key, out languageString); + } + + /// + /// TryGet method which combines HasKey & GetString + /// + /// string with prefix + /// Enum with key + /// out string + /// + public static bool TryGetString(string prefix, Enum key, out string languageString) + { + return Resources.TryGetValue(prefix + "." + key, out languageString); + } + + /// + /// Translate + /// + /// object + /// string + public static string Translate(object key) + { + string typename = key.GetType().Name; + string enumKey = typename + "." + key; + if (HasKey(enumKey)) + { + return GetString(enumKey); + } + + return key.ToString(); + } + + /// + /// Get the resource for key + /// + /// Enum + /// resource or a "string ###key### not found" + public static string GetString(Enum key) + { + if (key == null) + { + return null; + } + + return GetString(key.ToString()); + } + + /// + /// Get the resource for prefix.key + /// + /// string + /// Enum + /// resource or a "string ###prefix.key### not found" + public static string GetString(string prefix, Enum key) + { + if (key == null) + { + return null; + } + + return GetString(prefix + "." + key); + } + + /// + /// Get the resource for prefix.key + /// + /// string + /// string + /// resource or a "string ###prefix.key### not found" + public static string GetString(string prefix, string key) + { + return GetString(prefix + "." + key); + } + + /// + /// Get the resource for key + /// + /// string + /// resource or a "string ###key### not found" + public static string GetString(string key) + { + if (key == null) + { + return null; + } + + if (!Resources.TryGetValue(key, out var returnValue)) + { + return "string ###" + key + "### not found"; + } + + return returnValue; + } + + /// + /// Get the resource for key, format with with string.format an supply the parameters + /// + /// Enum + /// object + /// formatted resource or a "string ###key### not found" + public static string GetFormattedString(Enum key, object param) + { + return GetFormattedString(key.ToString(), param); + } + + /// + /// Get the resource for prefix.key, format with with string.format an supply the parameters + /// + /// string + /// Enum + /// object + /// formatted resource or a "string ###prefix.key### not found" + public static string GetFormattedString(string prefix, Enum key, object param) + { + return GetFormattedString(prefix, key.ToString(), param); + } + + /// + /// Get the resource for prefix.key, format with with string.format an supply the parameters + /// + /// string + /// string + /// object + /// formatted resource or a "string ###prefix.key### not found" + public static string GetFormattedString(string prefix, string key, object param) + { + return GetFormattedString(prefix + "." + key, param); + } + + /// + /// Get the resource for key, format with with string.format an supply the parameters + /// + /// string + /// object + /// formatted resource or a "string ###key### not found" + public static string GetFormattedString(string key, object param) + { + if (!Resources.TryGetValue(key, out var returnValue)) + { + return "string ###" + key + "### not found"; + } + + return string.Format(returnValue, param); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/LanguageFile.cs b/src/GreenshotPlugin/Core/LanguageFile.cs index 8c2c69ff1..3d6552a3c 100644 --- a/src/GreenshotPlugin/Core/LanguageFile.cs +++ b/src/GreenshotPlugin/Core/LanguageFile.cs @@ -5,71 +5,75 @@ namespace GreenshotPlugin.Core /// /// This class contains the information about a language file /// - public class LanguageFile : IEquatable { - public string Description { - get; - set; - } + public class LanguageFile : IEquatable + { + public string Description { get; set; } - public string Ietf { - get; - set; - } + public string Ietf { get; set; } - public Version Version { - get; - set; - } + public Version Version { get; set; } - public string LanguageGroup { - get; - set; - } + public string LanguageGroup { get; set; } - public string Filepath { - get; - set; - } + public string Filepath { get; set; } - public string Prefix { - get; - set; - } + public string Prefix { get; set; } /// /// Overload equals so we can delete a entry from a collection /// /// /// - public bool Equals(LanguageFile other) { - if (Prefix != null) { - if (other != null && !Prefix.Equals(other.Prefix)) { + public bool Equals(LanguageFile other) + { + if (Prefix != null) + { + if (other != null && !Prefix.Equals(other.Prefix)) + { return false; } - } else if (other?.Prefix != null) { + } + else if (other?.Prefix != null) + { return false; } - if (Ietf != null) { - if (other != null && !Ietf.Equals(other.Ietf)) { + + if (Ietf != null) + { + if (other != null && !Ietf.Equals(other.Ietf)) + { return false; } - } else if (other?.Ietf != null) { + } + else if (other?.Ietf != null) + { return false; } - if (Version != null) { - if (other != null && !Version.Equals(other.Version)) { + + if (Version != null) + { + if (other != null && !Version.Equals(other.Version)) + { return false; } - } else if (other != null && other.Version != null) { + } + else if (other != null && other.Version != null) + { return false; } - if (Filepath != null) { - if (other != null && !Filepath.Equals(other.Filepath)) { + + if (Filepath != null) + { + if (other != null && !Filepath.Equals(other.Filepath)) + { return false; } - } else if (other?.Filepath != null) { + } + else if (other?.Filepath != null) + { return false; } + return true; } } diff --git a/src/GreenshotPlugin/Core/LogHelper.cs b/src/GreenshotPlugin/Core/LogHelper.cs index c0849537e..45cd9df0e 100644 --- a/src/GreenshotPlugin/Core/LogHelper.cs +++ b/src/GreenshotPlugin/Core/LogHelper.cs @@ -30,77 +30,95 @@ using System; using GreenshotPlugin.IniFile; using log4net.Util; -namespace GreenshotPlugin.Core { - /// - /// Initialize the logger - /// - public class LogHelper { - private static bool _isLog4NetConfigured; - private const string InitMessage = "Greenshot initialization of log system failed"; +namespace GreenshotPlugin.Core +{ + /// + /// Initialize the logger + /// + public class LogHelper + { + private static bool _isLog4NetConfigured; + private const string InitMessage = "Greenshot initialization of log system failed"; - public static bool IsInitialized => _isLog4NetConfigured; + public static bool IsInitialized => _isLog4NetConfigured; - // Initialize Log4J - public static string InitializeLog4Net() { - // Setup log4j, currently the file is called log4net.xml - foreach (var logName in new[] { "log4net.xml" , @"App\Greenshot\log4net-portable.xml"}) - { - string log4NetFilename = Path.Combine(Application.StartupPath, logName); - if (File.Exists(log4NetFilename)) - { - try - { - XmlConfigurator.Configure(new FileInfo(log4NetFilename)); - _isLog4NetConfigured = true; - } - catch (Exception ex) - { - MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - } - } - // Fallback - if (!_isLog4NetConfigured) { - try { - Assembly assembly = typeof(LogHelper).Assembly; + // Initialize Log4J + public static string InitializeLog4Net() + { + // Setup log4j, currently the file is called log4net.xml + foreach (var logName in new[] + { + "log4net.xml", @"App\Greenshot\log4net-portable.xml" + }) + { + string log4NetFilename = Path.Combine(Application.StartupPath, logName); + if (File.Exists(log4NetFilename)) + { + try + { + XmlConfigurator.Configure(new FileInfo(log4NetFilename)); + _isLog4NetConfigured = true; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } + } + + // Fallback + if (!_isLog4NetConfigured) + { + try + { + Assembly assembly = typeof(LogHelper).Assembly; using Stream stream = assembly.GetManifestResourceStream("GreenshotPlugin.log4net-embedded.xml"); XmlConfigurator.Configure(stream); _isLog4NetConfigured = true; IniConfig.ForceIniInStartupPath(); - } catch (Exception ex){ - MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } - if (_isLog4NetConfigured) { - // Get the logfile name - try { - if (((Hierarchy)LogManager.GetRepository()).Root.Appenders.Count > 0) { - foreach (IAppender appender in ((Hierarchy)LogManager.GetRepository()).Root.Appenders) - { - var fileAppender = appender as FileAppender; - if (fileAppender != null) { - return fileAppender.File; - } - } - } - } - catch - { - // ignored - } - } - return null; - } - } + if (_isLog4NetConfigured) + { + // Get the logfile name + try + { + if (((Hierarchy) LogManager.GetRepository()).Root.Appenders.Count > 0) + { + foreach (IAppender appender in ((Hierarchy) LogManager.GetRepository()).Root.Appenders) + { + var fileAppender = appender as FileAppender; + if (fileAppender != null) + { + return fileAppender.File; + } + } + } + } + catch + { + // ignored + } + } - /// - /// A simple helper class to support the logging to the AppData location - /// - public class SpecialFolderPatternConverter : PatternConverter { - protected override void Convert(TextWriter writer, object state) { - Environment.SpecialFolder specialFolder = (Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), Option, true); - writer.Write(Environment.GetFolderPath(specialFolder)); - } - } -} + return null; + } + } + + /// + /// A simple helper class to support the logging to the AppData location + /// + public class SpecialFolderPatternConverter : PatternConverter + { + protected override void Convert(TextWriter writer, object state) + { + Environment.SpecialFolder specialFolder = (Environment.SpecialFolder) Enum.Parse(typeof(Environment.SpecialFolder), Option, true); + writer.Write(Environment.GetFolderPath(specialFolder)); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/NetworkHelper.cs b/src/GreenshotPlugin/Core/NetworkHelper.cs index 3159c9dcc..463a9bd19 100644 --- a/src/GreenshotPlugin/Core/NetworkHelper.cs +++ b/src/GreenshotPlugin/Core/NetworkHelper.cs @@ -74,7 +74,7 @@ namespace GreenshotPlugin.Core public static MemoryStream GetAsMemoryStream(string url) { var request = CreateWebRequest(url); - using var response = (HttpWebResponse)request.GetResponse(); + using var response = (HttpWebResponse) request.GetResponse(); var memoryStream = new MemoryStream(); using (var responseStream = response.GetResponseStream()) { @@ -188,7 +188,7 @@ namespace GreenshotPlugin.Core /// WebRequest public static HttpWebRequest CreateWebRequest(Uri uri) { - var webRequest = (HttpWebRequest)WebRequest.Create(uri); + var webRequest = (HttpWebRequest) WebRequest.Create(uri); webRequest.Proxy = Config.UseProxy ? CreateProxy(uri) : null; // Make sure the default credentials are available webRequest.Credentials = CredentialCache.DefaultCredentials; @@ -436,6 +436,7 @@ namespace GreenshotPlugin.Core break; } } + if (!headers.ContainsKey("Content-Type")) { webRequest.ContentType = "application/octet-stream"; @@ -473,6 +474,7 @@ namespace GreenshotPlugin.Core break; } } + if (!headers.ContainsKey("Content-Type")) { webRequest.ContentType = "application/json"; @@ -574,9 +576,9 @@ namespace GreenshotPlugin.Core bool isHttpError = false; try { - response = (HttpWebResponse)webRequest.GetResponse(); + response = (HttpWebResponse) webRequest.GetResponse(); Log.InfoFormat("Response status: {0}", response.StatusCode); - isHttpError = (int)response.StatusCode >= 300; + isHttpError = (int) response.StatusCode >= 300; if (isHttpError) { Log.ErrorFormat("HTTP error {0}", response.StatusCode); @@ -591,7 +593,7 @@ namespace GreenshotPlugin.Core } catch (WebException e) { - response = (HttpWebResponse)e.Response; + response = (HttpWebResponse) e.Response; HttpStatusCode statusCode = HttpStatusCode.Unused; if (response != null) { @@ -629,8 +631,8 @@ namespace GreenshotPlugin.Core return responseData; } - } + /// /// This interface can be used to pass binary information around, like byte[] or Image /// @@ -669,7 +671,7 @@ namespace GreenshotPlugin.Core { using MemoryStream stream = new MemoryStream(); ImageOutput.SaveToStream(_surface, stream, _outputSettings); - return Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length, formattingOptions); + return Convert.ToBase64String(stream.GetBuffer(), 0, (int) stream.Length, formattingOptions); } /// diff --git a/src/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs b/src/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs index 7b363b2fa..d837e85c0 100644 --- a/src/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs +++ b/src/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs @@ -49,15 +49,19 @@ namespace GreenshotPlugin.Core.OAuth public string ListeningUrlFormat { get; set; } = "http://localhost:{0}/authorize/"; private string _listeningUri; + /// /// The URL where the server is listening /// - public string ListeningUri { - get { + public string ListeningUri + { + get + { if (string.IsNullOrEmpty(_listeningUri)) { _listeningUri = string.Format(ListeningUrlFormat, GetRandomUnusedPort()); } + return _listeningUri; } set => _listeningUri = value; @@ -66,11 +70,7 @@ namespace GreenshotPlugin.Core.OAuth /// /// This action is called when the URI must be opened, default is just to run Process.Start /// - public Action OpenUriAction - { - set; - get; - } = authorizationUrl => + public Action OpenUriAction { set; get; } = authorizationUrl => { Log.DebugFormat("Open a browser with: {0}", authorizationUrl); using var process = Process.Start(authorizationUrl); @@ -86,23 +86,29 @@ namespace GreenshotPlugin.Core.OAuth /// /// OAuth2Settings /// Dictionary with values - public IDictionary ReceiveCode(OAuth2Settings oauth2Settings) { + public IDictionary ReceiveCode(OAuth2Settings oauth2Settings) + { using var listener = new HttpListener(); // Make sure the port is stored in the state, so the website can process this. oauth2Settings.State = new Uri(ListeningUri).Port.ToString(); listener.Prefixes.Add(ListeningUri); - try { + try + { listener.Start(); _ready.Reset(); listener.BeginGetContext(ListenerCallback, listener); OpenUriAction(oauth2Settings.FormattedAuthUrl); _ready.WaitOne(Timeout, true); - } catch (Exception) { + } + catch (Exception) + { // Make sure we can clean up, also if the thead is aborted _ready.Set(); throw; - } finally { + } + finally + { listener.Close(); } @@ -113,11 +119,13 @@ namespace GreenshotPlugin.Core.OAuth /// Handle a connection async, this allows us to break the waiting /// /// IAsyncResult - private void ListenerCallback(IAsyncResult result) { - HttpListener listener = (HttpListener)result.AsyncState; + private void ListenerCallback(IAsyncResult result) + { + HttpListener listener = (HttpListener) result.AsyncState; //If not listening return immediately as this method is called one last time after Close() - if (!listener.IsListening) { + if (!listener.IsListening) + { return; } @@ -178,12 +186,16 @@ namespace GreenshotPlugin.Core.OAuth /// Returns a random, unused port. /// /// port to use - private static int GetRandomUnusedPort() { + private static int GetRandomUnusedPort() + { var listener = new TcpListener(IPAddress.Loopback, 0); - try { + try + { listener.Start(); - return ((IPEndPoint)listener.LocalEndpoint).Port; - } finally { + return ((IPEndPoint) listener.LocalEndpoint).Port; + } + finally + { listener.Stop(); } } diff --git a/src/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs b/src/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs index a4915e8b6..1bc9670c7 100644 --- a/src/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs +++ b/src/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs @@ -35,7 +35,8 @@ namespace GreenshotPlugin.Core.OAuth /// OAuth 2.0 verification code receiver that runs a local server on a free port /// and waits for a call with the authorization verification code. /// - public class LocalServerCodeReceiver { + public class LocalServerCodeReceiver + { private static readonly ILog Log = LogManager.GetLogger(typeof(LocalServerCodeReceiver)); private readonly ManualResetEvent _ready = new ManualResetEvent(true); @@ -66,12 +67,16 @@ Greenshot received information from CloudServiceName. You can close this browser "; private string _redirectUri; + /// /// The URL to redirect to /// - protected string RedirectUri { - get { - if (!string.IsNullOrEmpty(_redirectUri)) { + protected string RedirectUri + { + get + { + if (!string.IsNullOrEmpty(_redirectUri)) + { return _redirectUri; } @@ -89,13 +94,16 @@ Greenshot received information from CloudServiceName. You can close this browser /// /// /// Dictionary with values - public IDictionary ReceiveCode(OAuth2Settings oauth2Settings) { + public IDictionary ReceiveCode(OAuth2Settings oauth2Settings) + { // Set the redirect URL on the settings oauth2Settings.RedirectUrl = RedirectUri; _cloudServiceName = oauth2Settings.CloudServiceName; - using (var listener = new HttpListener()) { + using (var listener = new HttpListener()) + { listener.Prefixes.Add(oauth2Settings.RedirectUrl); - try { + try + { listener.Start(); // Get the formatted FormattedAuthUrl @@ -107,18 +115,24 @@ Greenshot received information from CloudServiceName. You can close this browser var context = listener.BeginGetContext(ListenerCallback, listener); _ready.Reset(); - while (!context.AsyncWaitHandle.WaitOne(1000, true)) { + while (!context.AsyncWaitHandle.WaitOne(1000, true)) + { Log.Debug("Waiting for response"); } - } catch (Exception) { + } + catch (Exception) + { // Make sure we can clean up, also if the thead is aborted _ready.Set(); throw; - } finally { + } + finally + { _ready.WaitOne(); listener.Close(); } } + return _returnValues; } @@ -126,11 +140,13 @@ Greenshot received information from CloudServiceName. You can close this browser /// Handle a connection async, this allows us to break the waiting /// /// IAsyncResult - private void ListenerCallback(IAsyncResult result) { - HttpListener listener = (HttpListener)result.AsyncState; + private void ListenerCallback(IAsyncResult result) + { + HttpListener listener = (HttpListener) result.AsyncState; //If not listening return immediately as this method is called one last time after Close() - if (!listener.IsListening) { + if (!listener.IsListening) + { return; } @@ -140,11 +156,13 @@ Greenshot received information from CloudServiceName. You can close this browser // Handle request HttpListenerRequest request = context.Request; - try { + try + { NameValueCollection nameValueCollection = request.QueryString; // Get response object. - using (HttpListenerResponse response = context.Response) { + using (HttpListenerResponse response = context.Response) + { // Write a "close" response. byte[] buffer = Encoding.UTF8.GetBytes(ClosePageResponse.Replace("CloudServiceName", _cloudServiceName)); // Write to response stream. @@ -154,15 +172,20 @@ Greenshot received information from CloudServiceName. You can close this browser } // Create a new response URL with a dictionary that contains all the response query parameters. - foreach (var name in nameValueCollection.AllKeys) { - if (!_returnValues.ContainsKey(name)) { + foreach (var name in nameValueCollection.AllKeys) + { + if (!_returnValues.ContainsKey(name)) + { _returnValues.Add(name, nameValueCollection[name]); } } - } catch (Exception) { + } + catch (Exception) + { context.Response.OutputStream.Close(); throw; } + _ready.Set(); } @@ -170,12 +193,16 @@ Greenshot received information from CloudServiceName. You can close this browser /// Returns a random, unused port. /// /// port to use - private static int GetRandomUnusedPort() { + private static int GetRandomUnusedPort() + { var listener = new TcpListener(IPAddress.Loopback, 0); - try { + try + { listener.Start(); - return ((IPEndPoint)listener.LocalEndpoint).Port; - } finally { + return ((IPEndPoint) listener.LocalEndpoint).Port; + } + finally + { listener.Stop(); } } diff --git a/src/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs b/src/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs index 98d4515f9..ed391d9a8 100644 --- a/src/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs +++ b/src/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs @@ -24,10 +24,11 @@ namespace GreenshotPlugin.Core.OAuth /// /// Specify the authorize mode that is used to get the token from the cloud service. /// - public enum OAuth2AuthorizeMode { - Unknown, // Will give an exception, caller needs to specify another value - LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener - JsonReceiver, // Will start a local HttpListener and wait for a Json post + public enum OAuth2AuthorizeMode + { + Unknown, // Will give an exception, caller needs to specify another value + LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener + JsonReceiver, // Will start a local HttpListener and wait for a Json post EmbeddedBrowser // Will open into an embedded _browser (OAuthLoginForm), and catch the redirect } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs b/src/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs index b80d62b3d..36704a055 100644 --- a/src/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs +++ b/src/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs @@ -25,188 +25,224 @@ using System.Drawing; using System.Net; using GreenshotPlugin.Controls; -namespace GreenshotPlugin.Core.OAuth { +namespace GreenshotPlugin.Core.OAuth +{ /// - /// Code to simplify OAuth 2 - /// - public static class OAuth2Helper { - private const string RefreshToken = "refresh_token"; - private const string AccessToken = "access_token"; - private const string Code = "code"; + /// Code to simplify OAuth 2 + /// + public static class OAuth2Helper + { + private const string RefreshToken = "refresh_token"; + private const string AccessToken = "access_token"; + private const string Code = "code"; private const string Error = "error"; - private const string ClientId = "client_id"; - private const string ClientSecret = "client_secret"; - private const string GrantType = "grant_type"; - private const string AuthorizationCode = "authorization_code"; - private const string RedirectUri = "redirect_uri"; - private const string ExpiresIn = "expires_in"; + private const string ClientId = "client_id"; + private const string ClientSecret = "client_secret"; + private const string GrantType = "grant_type"; + private const string AuthorizationCode = "authorization_code"; + private const string RedirectUri = "redirect_uri"; + private const string ExpiresIn = "expires_in"; - /// - /// Generate an OAuth 2 Token by using the supplied code - /// - /// OAuth2Settings to update with the information that was retrieved - public static void GenerateRefreshToken(OAuth2Settings settings) { - IDictionary data = new Dictionary - { - // Use the returned code to get a refresh code - { Code, settings.Code }, - { ClientId, settings.ClientId }, - { ClientSecret, settings.ClientSecret }, - { GrantType, AuthorizationCode } - }; - foreach (string key in settings.AdditionalAttributes.Keys) { - data.Add(key, settings.AdditionalAttributes[key]); - } - - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); - NetworkHelper.UploadFormUrlEncoded(webRequest, data); - string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); - - IDictionary refreshTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); - if (refreshTokenResult.ContainsKey("error")) - { - if (refreshTokenResult.ContainsKey("error_description")) { - throw new Exception($"{refreshTokenResult["error"]} - {refreshTokenResult["error_description"]}"); - } - throw new Exception((string)refreshTokenResult["error"]); - } - - // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp - // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", - // "expires_in":3920, - // "token_type":"Bearer", - // "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" - if (refreshTokenResult.ContainsKey(AccessToken)) - { - settings.AccessToken = (string)refreshTokenResult[AccessToken]; - } - if (refreshTokenResult.ContainsKey(RefreshToken)) - { - settings.RefreshToken = (string)refreshTokenResult[RefreshToken]; - } - if (refreshTokenResult.ContainsKey(ExpiresIn)) - { - object seconds = refreshTokenResult[ExpiresIn]; - if (seconds != null) - { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double)seconds); - } - } - settings.Code = null; - } - - /// - /// Used to update the settings with the callback information - /// - /// OAuth2Settings - /// IDictionary - /// true if the access token is already in the callback - private static bool UpdateFromCallback(OAuth2Settings settings, IDictionary callbackParameters) - { - if (!callbackParameters.ContainsKey(AccessToken)) - { - return false; - } - if (callbackParameters.ContainsKey(RefreshToken)) - { - // Refresh the refresh token :) - settings.RefreshToken = callbackParameters[RefreshToken]; - } - if (callbackParameters.ContainsKey(ExpiresIn)) - { - var expiresIn = callbackParameters[ExpiresIn]; - settings.AccessTokenExpires = DateTimeOffset.MaxValue; - if (expiresIn != null) - { - if (double.TryParse(expiresIn, out var seconds)) - { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); - } - } - } - settings.AccessToken = callbackParameters[AccessToken]; - return true; - } - - /// - /// Go out and retrieve a new access token via refresh-token with the TokenUrl in the settings - /// Will update the access token, refresh token, expire date - /// - /// - public static void GenerateAccessToken(OAuth2Settings settings) { - IDictionary data = new Dictionary - { - { RefreshToken, settings.RefreshToken }, - { ClientId, settings.ClientId }, - { ClientSecret, settings.ClientSecret }, - { GrantType, RefreshToken } - }; - foreach (string key in settings.AdditionalAttributes.Keys) { - data.Add(key, settings.AdditionalAttributes[key]); - } - - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); - NetworkHelper.UploadFormUrlEncoded(webRequest, data); - string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); - - // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp - // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", - // "expires_in":3920, - // "token_type":"Bearer", - - IDictionary accessTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); - if (accessTokenResult.ContainsKey("error")) + /// + /// Generate an OAuth 2 Token by using the supplied code + /// + /// OAuth2Settings to update with the information that was retrieved + public static void GenerateRefreshToken(OAuth2Settings settings) + { + IDictionary data = new Dictionary { - if ("invalid_grant" == (string)accessTokenResult["error"]) { - // Refresh token has also expired, we need a new one! - settings.RefreshToken = null; - settings.AccessToken = null; - settings.AccessTokenExpires = DateTimeOffset.MinValue; - settings.Code = null; - return; - } + // Use the returned code to get a refresh code + { + Code, settings.Code + }, + { + ClientId, settings.ClientId + }, + { + ClientSecret, settings.ClientSecret + }, + { + GrantType, AuthorizationCode + } + }; + foreach (string key in settings.AdditionalAttributes.Keys) + { + data.Add(key, settings.AdditionalAttributes[key]); + } - if (accessTokenResult.ContainsKey("error_description")) { + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); + NetworkHelper.UploadFormUrlEncoded(webRequest, data); + string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); + + IDictionary refreshTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); + if (refreshTokenResult.ContainsKey("error")) + { + if (refreshTokenResult.ContainsKey("error_description")) + { + throw new Exception($"{refreshTokenResult["error"]} - {refreshTokenResult["error_description"]}"); + } + + throw new Exception((string) refreshTokenResult["error"]); + } + + // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp + // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", + // "expires_in":3920, + // "token_type":"Bearer", + // "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" + if (refreshTokenResult.ContainsKey(AccessToken)) + { + settings.AccessToken = (string) refreshTokenResult[AccessToken]; + } + + if (refreshTokenResult.ContainsKey(RefreshToken)) + { + settings.RefreshToken = (string) refreshTokenResult[RefreshToken]; + } + + if (refreshTokenResult.ContainsKey(ExpiresIn)) + { + object seconds = refreshTokenResult[ExpiresIn]; + if (seconds != null) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double) seconds); + } + } + + settings.Code = null; + } + + /// + /// Used to update the settings with the callback information + /// + /// OAuth2Settings + /// IDictionary + /// true if the access token is already in the callback + private static bool UpdateFromCallback(OAuth2Settings settings, IDictionary callbackParameters) + { + if (!callbackParameters.ContainsKey(AccessToken)) + { + return false; + } + + if (callbackParameters.ContainsKey(RefreshToken)) + { + // Refresh the refresh token :) + settings.RefreshToken = callbackParameters[RefreshToken]; + } + + if (callbackParameters.ContainsKey(ExpiresIn)) + { + var expiresIn = callbackParameters[ExpiresIn]; + settings.AccessTokenExpires = DateTimeOffset.MaxValue; + if (expiresIn != null) + { + if (double.TryParse(expiresIn, out var seconds)) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); + } + } + } + + settings.AccessToken = callbackParameters[AccessToken]; + return true; + } + + /// + /// Go out and retrieve a new access token via refresh-token with the TokenUrl in the settings + /// Will update the access token, refresh token, expire date + /// + /// + public static void GenerateAccessToken(OAuth2Settings settings) + { + IDictionary data = new Dictionary + { + { + RefreshToken, settings.RefreshToken + }, + { + ClientId, settings.ClientId + }, + { + ClientSecret, settings.ClientSecret + }, + { + GrantType, RefreshToken + } + }; + foreach (string key in settings.AdditionalAttributes.Keys) + { + data.Add(key, settings.AdditionalAttributes[key]); + } + + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); + NetworkHelper.UploadFormUrlEncoded(webRequest, data); + string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); + + // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp + // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", + // "expires_in":3920, + // "token_type":"Bearer", + + IDictionary accessTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); + if (accessTokenResult.ContainsKey("error")) + { + if ("invalid_grant" == (string) accessTokenResult["error"]) + { + // Refresh token has also expired, we need a new one! + settings.RefreshToken = null; + settings.AccessToken = null; + settings.AccessTokenExpires = DateTimeOffset.MinValue; + settings.Code = null; + return; + } + + if (accessTokenResult.ContainsKey("error_description")) + { throw new Exception($"{accessTokenResult["error"]} - {accessTokenResult["error_description"]}"); } - throw new Exception((string)accessTokenResult["error"]); + throw new Exception((string) accessTokenResult["error"]); } - if (accessTokenResult.ContainsKey(AccessToken)) - { - settings.AccessToken = (string) accessTokenResult[AccessToken]; - settings.AccessTokenExpires = DateTimeOffset.MaxValue; - } - if (accessTokenResult.ContainsKey(RefreshToken)) { - // Refresh the refresh token :) - settings.RefreshToken = (string)accessTokenResult[RefreshToken]; - } - if (accessTokenResult.ContainsKey(ExpiresIn)) - { - object seconds = accessTokenResult[ExpiresIn]; - if (seconds != null) - { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double) seconds); - } - } - } + if (accessTokenResult.ContainsKey(AccessToken)) + { + settings.AccessToken = (string) accessTokenResult[AccessToken]; + settings.AccessTokenExpires = DateTimeOffset.MaxValue; + } - /// - /// Authorize by using the mode specified in the settings - /// - /// OAuth2Settings - /// false if it was canceled, true if it worked, exception if not - public static bool Authorize(OAuth2Settings settings) { - var completed = settings.AuthorizeMode switch - { - OAuth2AuthorizeMode.LocalServer => AuthorizeViaLocalServer(settings), - OAuth2AuthorizeMode.EmbeddedBrowser => AuthorizeViaEmbeddedBrowser(settings), + if (accessTokenResult.ContainsKey(RefreshToken)) + { + // Refresh the refresh token :) + settings.RefreshToken = (string) accessTokenResult[RefreshToken]; + } + + if (accessTokenResult.ContainsKey(ExpiresIn)) + { + object seconds = accessTokenResult[ExpiresIn]; + if (seconds != null) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double) seconds); + } + } + } + + /// + /// Authorize by using the mode specified in the settings + /// + /// OAuth2Settings + /// false if it was canceled, true if it worked, exception if not + public static bool Authorize(OAuth2Settings settings) + { + var completed = settings.AuthorizeMode switch + { + OAuth2AuthorizeMode.LocalServer => AuthorizeViaLocalServer(settings), + OAuth2AuthorizeMode.EmbeddedBrowser => AuthorizeViaEmbeddedBrowser(settings), OAuth2AuthorizeMode.JsonReceiver => AuthorizeViaDefaultBrowser(settings), _ => throw new NotImplementedException($"Authorize mode '{settings.AuthorizeMode}' is not 'yet' implemented."), - }; - return completed; - } + }; + return completed; + } /// /// Authorize via the default browser, via the Greenshot website. @@ -217,13 +253,14 @@ namespace GreenshotPlugin.Core.OAuth { /// true if completed, false if canceled private static bool AuthorizeViaDefaultBrowser(OAuth2Settings settings) { - var codeReceiver = new LocalJsonReceiver(); + var codeReceiver = new LocalJsonReceiver(); IDictionary result = codeReceiver.ReceiveCode(settings); if (result == null || result.Count == 0) { return false; } + foreach (var key in result.Keys) { switch (key) @@ -236,6 +273,7 @@ namespace GreenshotPlugin.Core.OAuth { { settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); } + break; case RefreshToken: settings.RefreshToken = result[key]; @@ -249,124 +287,155 @@ namespace GreenshotPlugin.Core.OAuth { { throw new Exception(errorDescription); } + if ("access_denied" == error) { throw new UnauthorizedAccessException("Access denied"); } + throw new Exception(error); - } + } + if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) { - settings.Code = code; + settings.Code = code; GenerateRefreshToken(settings); return !string.IsNullOrEmpty(settings.AccessToken); } - return true; + return true; } /// - /// Authorize via an embedded browser - /// If this works, return the code - /// - /// OAuth2Settings with the Auth / Token url etc - /// true if completed, false if canceled - private static bool AuthorizeViaEmbeddedBrowser(OAuth2Settings settings) { - if (string.IsNullOrEmpty(settings.CloudServiceName)) { - throw new ArgumentNullException(nameof(settings.CloudServiceName)); - } - if (settings.BrowserSize == Size.Empty) { - throw new ArgumentNullException(nameof(settings.BrowserSize)); - } - OAuthLoginForm loginForm = new OAuthLoginForm($"Authorize {settings.CloudServiceName}", settings.BrowserSize, settings.FormattedAuthUrl, settings.RedirectUrl); - loginForm.ShowDialog(); + /// Authorize via an embedded browser + /// If this works, return the code + /// + /// OAuth2Settings with the Auth / Token url etc + /// true if completed, false if canceled + private static bool AuthorizeViaEmbeddedBrowser(OAuth2Settings settings) + { + if (string.IsNullOrEmpty(settings.CloudServiceName)) + { + throw new ArgumentNullException(nameof(settings.CloudServiceName)); + } + + if (settings.BrowserSize == Size.Empty) + { + throw new ArgumentNullException(nameof(settings.BrowserSize)); + } + + OAuthLoginForm loginForm = new OAuthLoginForm($"Authorize {settings.CloudServiceName}", settings.BrowserSize, settings.FormattedAuthUrl, settings.RedirectUrl); + loginForm.ShowDialog(); if (!loginForm.IsOk) return false; - if (loginForm.CallbackParameters.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) { + if (loginForm.CallbackParameters.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) + { settings.Code = code; GenerateRefreshToken(settings); return true; } + return UpdateFromCallback(settings, loginForm.CallbackParameters); } - /// - /// Authorize via a local server by using the LocalServerCodeReceiver - /// If this works, return the code - /// - /// OAuth2Settings with the Auth / Token url etc - /// true if completed - private static bool AuthorizeViaLocalServer(OAuth2Settings settings) { - var codeReceiver = new LocalServerCodeReceiver(); - IDictionary result = codeReceiver.ReceiveCode(settings); + /// + /// Authorize via a local server by using the LocalServerCodeReceiver + /// If this works, return the code + /// + /// OAuth2Settings with the Auth / Token url etc + /// true if completed + private static bool AuthorizeViaLocalServer(OAuth2Settings settings) + { + var codeReceiver = new LocalServerCodeReceiver(); + IDictionary result = codeReceiver.ReceiveCode(settings); - if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) { - settings.Code = code; - GenerateRefreshToken(settings); - return true; - } + if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) + { + settings.Code = code; + GenerateRefreshToken(settings); + return true; + } - if (result.TryGetValue("error", out var error)) { - if (result.TryGetValue("error_description", out var errorDescription)) { - throw new Exception(errorDescription); - } - if ("access_denied" == error) { - throw new UnauthorizedAccessException("Access denied"); - } - throw new Exception(error); - } - return false; - } + if (result.TryGetValue("error", out var error)) + { + if (result.TryGetValue("error_description", out var errorDescription)) + { + throw new Exception(errorDescription); + } - /// - /// Simple helper to add the Authorization Bearer header - /// - /// WebRequest - /// OAuth2Settings - public static void AddOAuth2Credentials(HttpWebRequest webRequest, OAuth2Settings settings) { - if (!string.IsNullOrEmpty(settings.AccessToken)) { - webRequest.Headers.Add("Authorization", "Bearer " + settings.AccessToken); - } - } + if ("access_denied" == error) + { + throw new UnauthorizedAccessException("Access denied"); + } - /// - /// Check and authenticate or refresh tokens - /// - /// OAuth2Settings - public static void CheckAndAuthenticateOrRefresh(OAuth2Settings settings) { - // Get Refresh / Access token - if (string.IsNullOrEmpty(settings.RefreshToken)) { - if (!Authorize(settings)) { - throw new Exception("Authentication cancelled"); - } - } - if (settings.IsAccessTokenExpired) { - GenerateAccessToken(settings); - // Get Refresh / Access token - if (string.IsNullOrEmpty(settings.RefreshToken)) { - if (!Authorize(settings)) { - throw new Exception("Authentication cancelled"); - } - GenerateAccessToken(settings); - } - } - if (settings.IsAccessTokenExpired) { - throw new Exception("Authentication failed"); - } - } + throw new Exception(error); + } - /// - /// CreateWebRequest ready for OAuth 2 access - /// - /// HTTPMethod - /// - /// OAuth2Settings - /// HttpWebRequest - public static HttpWebRequest CreateOAuth2WebRequest(HTTPMethod method, string url, OAuth2Settings settings) { - CheckAndAuthenticateOrRefresh(settings); + return false; + } - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, method); - AddOAuth2Credentials(webRequest, settings); - return webRequest; - } - } -} + /// + /// Simple helper to add the Authorization Bearer header + /// + /// WebRequest + /// OAuth2Settings + public static void AddOAuth2Credentials(HttpWebRequest webRequest, OAuth2Settings settings) + { + if (!string.IsNullOrEmpty(settings.AccessToken)) + { + webRequest.Headers.Add("Authorization", "Bearer " + settings.AccessToken); + } + } + + /// + /// Check and authenticate or refresh tokens + /// + /// OAuth2Settings + public static void CheckAndAuthenticateOrRefresh(OAuth2Settings settings) + { + // Get Refresh / Access token + if (string.IsNullOrEmpty(settings.RefreshToken)) + { + if (!Authorize(settings)) + { + throw new Exception("Authentication cancelled"); + } + } + + if (settings.IsAccessTokenExpired) + { + GenerateAccessToken(settings); + // Get Refresh / Access token + if (string.IsNullOrEmpty(settings.RefreshToken)) + { + if (!Authorize(settings)) + { + throw new Exception("Authentication cancelled"); + } + + GenerateAccessToken(settings); + } + } + + if (settings.IsAccessTokenExpired) + { + throw new Exception("Authentication failed"); + } + } + + /// + /// CreateWebRequest ready for OAuth 2 access + /// + /// HTTPMethod + /// + /// OAuth2Settings + /// HttpWebRequest + public static HttpWebRequest CreateOAuth2WebRequest(HTTPMethod method, string url, OAuth2Settings settings) + { + CheckAndAuthenticateOrRefresh(settings); + + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, method); + AddOAuth2Credentials(webRequest, settings); + return webRequest; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs b/src/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs index 57b566aaa..d008c6b5b 100644 --- a/src/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs +++ b/src/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs @@ -28,70 +28,51 @@ namespace GreenshotPlugin.Core.OAuth /// /// Settings for the OAuth 2 protocol /// - public class OAuth2Settings { - public OAuth2Settings() { + public class OAuth2Settings + { + public OAuth2Settings() + { AdditionalAttributes = new Dictionary(); // Create a default state var state = Guid.NewGuid().ToString(); // Only store a small part of the GUID - State = state.Substring(0, state.IndexOf('-')-1); + State = state.Substring(0, state.IndexOf('-') - 1); AuthorizeMode = OAuth2AuthorizeMode.Unknown; } - public OAuth2AuthorizeMode AuthorizeMode { - get; - set; - } + public OAuth2AuthorizeMode AuthorizeMode { get; set; } /// /// Specify the name of the cloud service, so it can be used in window titles, logs etc /// - public string CloudServiceName { - get; - set; - } + public string CloudServiceName { get; set; } /// /// Specify the size of the embedded Browser, if using this /// - public Size BrowserSize { - get; - set; - } + public Size BrowserSize { get; set; } /// /// The OAuth 2 client id /// - public string ClientId { - get; - set; - } + public string ClientId { get; set; } /// /// The OAuth 2 client secret /// - public string ClientSecret { - get; - set; - } + public string ClientSecret { get; set; } /// /// The OAuth 2 state, this is something that is passed to the server, is not processed but returned back to the client. /// e.g. a correlation ID /// Default this is filled with a new Guid /// - public string State { - get; - set; - } + public string State { get; set; } /// /// The authorization URL where the values of this class can be "injected" /// - public string AuthUrlPattern { - get; - set; - } + public string AuthUrlPattern { get; set; } /// /// Get formatted Auth url (this will call a FormatWith(this) on the AuthUrlPattern @@ -101,54 +82,49 @@ namespace GreenshotPlugin.Core.OAuth /// /// The URL to get a Token /// - public string TokenUrl { - get; - set; - } + public string TokenUrl { get; set; } /// /// This is the redirect URL, in some implementations this is automatically set (LocalServerCodeReceiver) /// In some implementations this could be e.g. urn:ietf:wg:oauth:2.0:oob or urn:ietf:wg:oauth:2.0:oob:auto /// - public string RedirectUrl { - get; - set; - } + public string RedirectUrl { get; set; } /// /// Bearer token for accessing OAuth 2 services /// - public string AccessToken { - get; - set; - } + public string AccessToken { get; set; } /// /// Expire time for the AccessToken, this this time (-60 seconds) is passed a new AccessToken needs to be generated with the RefreshToken /// - public DateTimeOffset AccessTokenExpires { - get; - set; - } + public DateTimeOffset AccessTokenExpires { get; set; } /// /// Return true if the access token is expired. /// Important "side-effect": if true is returned the AccessToken will be set to null! /// - public bool IsAccessTokenExpired { - get { + public bool IsAccessTokenExpired + { + get + { if (AccessTokenExpires == default) { return false; } + bool expired = true; - if (!string.IsNullOrEmpty(AccessToken)) { + if (!string.IsNullOrEmpty(AccessToken)) + { expired = DateTimeOffset.Now.AddSeconds(60) > AccessTokenExpires; } + // Make sure the token is not usable - if (expired) { + if (expired) + { AccessToken = null; } + return expired; } } @@ -156,26 +132,17 @@ namespace GreenshotPlugin.Core.OAuth /// /// Token used to get a new Access Token /// - public string RefreshToken { - get; - set; - } + public string RefreshToken { get; set; } /// /// Put anything in here which is needed for the OAuth 2 implementation of this specific service but isn't generic, e.g. for Google there is a "scope" /// - public IDictionary AdditionalAttributes { - get; - set; - } + public IDictionary AdditionalAttributes { get; set; } /// /// This contains the code returned from the authorization, but only shortly after it was received. /// It will be cleared as soon as it was used. /// - public string Code { - get; - set; - } + public string Code { get; set; } } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/OAuth/OAuthSession.cs b/src/GreenshotPlugin/Core/OAuth/OAuthSession.cs index 9a40c0b8d..aedff7fe2 100644 --- a/src/GreenshotPlugin/Core/OAuth/OAuthSession.cs +++ b/src/GreenshotPlugin/Core/OAuth/OAuthSession.cs @@ -35,7 +35,8 @@ namespace GreenshotPlugin.Core.OAuth /// /// An OAuth 1 session object /// - public class OAuthSession { + public class OAuthSession + { private static readonly ILog Log = LogManager.GetLogger(typeof(OAuthSession)); protected const string OAUTH_VERSION = "1.0"; protected const string OAUTH_PARAMETER_PREFIX = "oauth_"; @@ -81,52 +82,24 @@ namespace GreenshotPlugin.Core.OAuth // default _browser size - public HTTPMethod RequestTokenMethod { - get; - set; - } - public HTTPMethod AccessTokenMethod { - get; - set; - } - public string RequestTokenUrl { - get; - set; - } - public string AuthorizeUrl { - get; - set; - } - public string AccessTokenUrl { - get; - set; - } - public string Token { - get; - set; - } - public string TokenSecret { - get; - set; - } - public string Verifier { - get; - set; - } - public OAuthSignatureTypes SignatureType { - get; - set; - } + public HTTPMethod RequestTokenMethod { get; set; } + public HTTPMethod AccessTokenMethod { get; set; } + public string RequestTokenUrl { get; set; } + public string AuthorizeUrl { get; set; } + public string AccessTokenUrl { get; set; } + public string Token { get; set; } + public string TokenSecret { get; set; } + public string Verifier { get; set; } + public OAuthSignatureTypes SignatureType { get; set; } public bool UseMultipartFormData { get; set; } - public string UserAgent { - get { - return _userAgent; - } - set { - _userAgent = value; - } + + public string UserAgent + { + get { return _userAgent; } + set { _userAgent = value; } } + public string CallbackUrl { get; set; } = "http://getgreenshot.org"; public bool CheckVerifier { get; set; } = true; @@ -137,17 +110,15 @@ namespace GreenshotPlugin.Core.OAuth public bool UseHttpHeadersForAuthorization { get; set; } = true; - public bool AutoLogin { - get; - set; - } + public bool AutoLogin { get; set; } /// /// Create an OAuthSession with the consumerKey / consumerSecret /// /// "Public" key for the encoding. When using RSASHA1 this is the path to the private key file /// "Private" key for the encoding. when usin RSASHA1 this is the password for the private key file - public OAuthSession(string consumerKey, string consumerSecret) { + public OAuthSession(string consumerKey, string consumerSecret) + { _consumerKey = consumerKey; _consumerSecret = consumerSecret; UseMultipartFormData = true; @@ -163,12 +134,15 @@ namespace GreenshotPlugin.Core.OAuth /// The hashing algorithm used. If that algorithm needs some initialization, like HMAC and its derivatives, they should be initialized prior to passing it to this function /// The data to hash /// a Base64 string of the hash value - private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) { - if (hashAlgorithm == null) { + private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) + { + if (hashAlgorithm == null) + { throw new ArgumentNullException(nameof(hashAlgorithm)); } - if (string.IsNullOrEmpty(data)) { + if (string.IsNullOrEmpty(data)) + { throw new ArgumentNullException(nameof(data)); } @@ -183,19 +157,24 @@ namespace GreenshotPlugin.Core.OAuth /// /// the list of query parameters /// a string with the normalized query parameters - private static string GenerateNormalizedParametersString(IDictionary queryParameters) { - if (queryParameters == null || queryParameters.Count == 0) { + private static string GenerateNormalizedParametersString(IDictionary queryParameters) + { + if (queryParameters == null || queryParameters.Count == 0) + { return string.Empty; } queryParameters = new SortedDictionary(queryParameters); StringBuilder sb = new StringBuilder(); - foreach (string key in queryParameters.Keys) { - if (queryParameters[key] is string) { + foreach (string key in queryParameters.Keys) + { + if (queryParameters[key] is string) + { sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode3986($"{queryParameters[key]}")); } } + sb.Remove(sb.Length - 1, 1); return sb.ToString(); @@ -208,15 +187,21 @@ namespace GreenshotPlugin.Core.OAuth /// /// The value to Url encode /// Returns a Url encoded string (unicode) with UTF-8 encoded % values - public static string UrlEncode3986(string value) { + public static string UrlEncode3986(string value) + { StringBuilder result = new StringBuilder(); - foreach (char symbol in value) { - if (UnreservedChars.IndexOf(symbol) != -1) { + foreach (char symbol in value) + { + if (UnreservedChars.IndexOf(symbol) != -1) + { result.Append(symbol); - } else { + } + else + { byte[] utf8Bytes = Encoding.UTF8.GetBytes(symbol.ToString()); - foreach(byte utf8Byte in utf8Bytes) { + foreach (byte utf8Byte in utf8Bytes) + { result.AppendFormat("%{0:X2}", utf8Byte); } } @@ -229,7 +214,8 @@ namespace GreenshotPlugin.Core.OAuth /// Generate the timestamp for the signature /// /// - public static string GenerateTimeStamp() { + public static string GenerateTimeStamp() + { // Default implementation of UNIX time of the current UTC time TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); @@ -239,7 +225,8 @@ namespace GreenshotPlugin.Core.OAuth /// Generate a nonce /// /// - public static string GenerateNonce() { + public static string GenerateNonce() + { // Just a simple implementation of a random number between 123400 and 9999999 return random.Next(123400, 9999999).ToString(); } @@ -248,22 +235,28 @@ namespace GreenshotPlugin.Core.OAuth /// Get the request token using the consumer key and secret. Also initializes tokensecret /// /// response, this doesn't need to be used!! - private string GetRequestToken() { + private string GetRequestToken() + { IDictionary parameters = new Dictionary(); - foreach(var value in RequestTokenParameters) { + foreach (var value in RequestTokenParameters) + { parameters.Add(value); } + Sign(RequestTokenMethod, RequestTokenUrl, parameters); string response = MakeRequest(RequestTokenMethod, RequestTokenUrl, null, parameters, null); - if (!string.IsNullOrEmpty(response)) { + if (!string.IsNullOrEmpty(response)) + { response = NetworkHelper.UrlDecode(response); Log.DebugFormat("Request token response: {0}", response); _requestTokenResponseParameters = NetworkHelper.ParseQueryString(response); - if (_requestTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var value)) { + if (_requestTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var value)) + { Token = value; TokenSecret = _requestTokenResponseParameters[OAUTH_TOKEN_SECRET_KEY]; } } + return response; } @@ -272,31 +265,43 @@ namespace GreenshotPlugin.Core.OAuth /// /// Pass the response from the server's request token, so if there is something wrong we can show it. /// The request token. - private string GetAuthorizeToken(string requestTokenResponse) { - if (string.IsNullOrEmpty(Token)) { + private string GetAuthorizeToken(string requestTokenResponse) + { + if (string.IsNullOrEmpty(Token)) + { Exception e = new Exception("The request token is not set, service responded with: " + requestTokenResponse); throw e; } + Log.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink); OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(LoginTitle, BrowserSize, AuthorizationLink, CallbackUrl); oAuthLoginForm.ShowDialog(); - if (oAuthLoginForm.IsOk) { - if (oAuthLoginForm.CallbackParameters != null) { - if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue)) { + if (oAuthLoginForm.IsOk) + { + if (oAuthLoginForm.CallbackParameters != null) + { + if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue)) + { Token = tokenValue; } - if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_VERIFIER_KEY, out var verifierValue)) { + if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_VERIFIER_KEY, out var verifierValue)) + { Verifier = verifierValue; } } } - if (CheckVerifier) { - if (!string.IsNullOrEmpty(Verifier)) { + + if (CheckVerifier) + { + if (!string.IsNullOrEmpty(Verifier)) + { return Token; } + return null; } + return Token; } @@ -304,8 +309,10 @@ namespace GreenshotPlugin.Core.OAuth /// Get the access token /// /// The access token. - private string GetAccessToken() { - if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) { + private string GetAccessToken() + { + if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) + { Exception e = new Exception("The request token and verifier were not set"); throw e; } @@ -313,15 +320,18 @@ namespace GreenshotPlugin.Core.OAuth IDictionary parameters = new Dictionary(); Sign(AccessTokenMethod, AccessTokenUrl, parameters); string response = MakeRequest(AccessTokenMethod, AccessTokenUrl, null, parameters, null); - if (!string.IsNullOrEmpty(response)) { + if (!string.IsNullOrEmpty(response)) + { response = NetworkHelper.UrlDecode(response); Log.DebugFormat("Access token response: {0}", response); AccessTokenResponseParameters = NetworkHelper.ParseQueryString(response); - if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue) && tokenValue != null) { + if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue) && tokenValue != null) + { Token = tokenValue; } - if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_SECRET_KEY, out var secretValue) && secretValue != null) { + if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_SECRET_KEY, out var secretValue) && secretValue != null) + { TokenSecret = secretValue; } } @@ -333,26 +343,36 @@ namespace GreenshotPlugin.Core.OAuth /// This method goes through the whole authorize process, including a Authorization window. /// /// true if the process is completed - public bool Authorize() { + public bool Authorize() + { Token = null; TokenSecret = null; Verifier = null; Log.Debug("Creating Token"); string requestTokenResponse; - try { + try + { requestTokenResponse = GetRequestToken(); - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Error(ex); throw new NotSupportedException("Service is not available: " + ex.Message); } - if (string.IsNullOrEmpty(GetAuthorizeToken(requestTokenResponse))) { + + if (string.IsNullOrEmpty(GetAuthorizeToken(requestTokenResponse))) + { Log.Debug("User didn't authenticate!"); return false; } - try { + + try + { Thread.Sleep(1000); return GetAccessToken() != null; - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Error(ex); throw; } @@ -373,7 +393,9 @@ namespace GreenshotPlugin.Core.OAuth /// Parameters for the request, which do not need to be signed /// Data to post (MemoryStream) /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { + public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary parametersToSign, IDictionary additionalParameters, + IBinaryContainer postData) + { return MakeOAuthRequest(method, requestUrl, requestUrl, null, parametersToSign, additionalParameters, postData); } @@ -387,7 +409,9 @@ namespace GreenshotPlugin.Core.OAuth /// Parameters for the request, which do not need to be signed /// Data to post (MemoryStream) /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { + public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parametersToSign, + IDictionary additionalParameters, IBinaryContainer postData) + { return MakeOAuthRequest(method, requestUrl, requestUrl, headers, parametersToSign, additionalParameters, postData); } @@ -401,7 +425,9 @@ namespace GreenshotPlugin.Core.OAuth /// Parameters for the request, which do not need to be signed /// Data to post (MemoryStream) /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { + public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary parametersToSign, + IDictionary additionalParameters, IBinaryContainer postData) + { return MakeOAuthRequest(method, signUrl, requestUrl, null, parametersToSign, additionalParameters, postData); } @@ -416,34 +442,50 @@ namespace GreenshotPlugin.Core.OAuth /// Parameters for the request, which do not need to be signed /// Data to post (MemoryStream) /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary headers, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { - if (parametersToSign == null) { + public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary headers, IDictionary parametersToSign, + IDictionary additionalParameters, IBinaryContainer postData) + { + if (parametersToSign == null) + { parametersToSign = new Dictionary(); } + int retries = 2; Exception lastException = null; - while (retries-- > 0) { + while (retries-- > 0) + { // If we are not trying to get a Authorization or Accestoken, and we don't have a token, create one - if (string.IsNullOrEmpty(Token)) { - if (!AutoLogin || !Authorize()) { + if (string.IsNullOrEmpty(Token)) + { + if (!AutoLogin || !Authorize()) + { throw new Exception("Not authorized"); } } - try { + + try + { Sign(method, signUrl, parametersToSign); // Join all parameters IDictionary newParameters = new Dictionary(); - foreach (var parameter in parametersToSign) { + foreach (var parameter in parametersToSign) + { newParameters.Add(parameter); } - if (additionalParameters != null) { - foreach (var parameter in additionalParameters) { + + if (additionalParameters != null) + { + foreach (var parameter in additionalParameters) + { newParameters.Add(parameter); } } + return MakeRequest(method, requestUrl, headers, newParameters, postData); - } catch (UnauthorizedAccessException uaEx) { + } + catch (UnauthorizedAccessException uaEx) + { lastException = uaEx; Token = null; TokenSecret = null; @@ -456,15 +498,19 @@ namespace GreenshotPlugin.Core.OAuth keysToDelete.Add(parameterKey); } } + foreach (string keyToDelete in keysToDelete) { parametersToSign.Remove(keyToDelete); } } } - if (lastException != null) { + + if (lastException != null) + { throw lastException; } + throw new Exception("Not authorized"); } @@ -475,10 +521,13 @@ namespace GreenshotPlugin.Core.OAuth /// Method (POST,PUT,GET) /// Url to call /// IDictionary of string and string - private void Sign(HTTPMethod method, string requestUrl, IDictionary parameters) { - if (parameters == null) { + private void Sign(HTTPMethod method, string requestUrl, IDictionary parameters) + { + if (parameters == null) + { throw new ArgumentNullException(nameof(parameters)); } + // Build the signature base StringBuilder signatureBase = new StringBuilder(); @@ -488,9 +537,11 @@ namespace GreenshotPlugin.Core.OAuth // Add normalized URL Uri url = new Uri(requestUrl); string normalizedUrl = string.Format(CultureInfo.InvariantCulture, "{0}://{1}", url.Scheme, url.Host); - if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) { + if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) + { normalizedUrl += ":" + url.Port; } + normalizedUrl += url.AbsolutePath; signatureBase.Append(UrlEncode3986(normalizedUrl)).Append("&"); @@ -498,7 +549,8 @@ namespace GreenshotPlugin.Core.OAuth parameters.Add(OAUTH_VERSION_KEY, OAUTH_VERSION); parameters.Add(OAUTH_NONCE_KEY, GenerateNonce()); parameters.Add(OAUTH_TIMESTAMP_KEY, GenerateTimeStamp()); - switch(SignatureType) { + switch (SignatureType) + { case OAuthSignatureTypes.PLAINTEXT: parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, PlainTextSignatureType); break; @@ -506,26 +558,38 @@ namespace GreenshotPlugin.Core.OAuth parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, HMACSHA1SignatureType); break; } + parameters.Add(OAUTH_CONSUMER_KEY_KEY, _consumerKey); - if (CallbackUrl != null && RequestTokenUrl != null && requestUrl.StartsWith(RequestTokenUrl)) { + if (CallbackUrl != null && RequestTokenUrl != null && requestUrl.StartsWith(RequestTokenUrl)) + { parameters.Add(OAUTH_CALLBACK_KEY, CallbackUrl); } - if (!string.IsNullOrEmpty(Verifier)) { + + if (!string.IsNullOrEmpty(Verifier)) + { parameters.Add(OAUTH_VERIFIER_KEY, Verifier); } - if (!string.IsNullOrEmpty(Token)) { + + if (!string.IsNullOrEmpty(Token)) + { parameters.Add(OAUTH_TOKEN_KEY, Token); } + signatureBase.Append(UrlEncode3986(GenerateNormalizedParametersString(parameters))); Log.DebugFormat("Signature base: {0}", signatureBase); - string key = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", UrlEncode3986(_consumerSecret), string.IsNullOrEmpty(TokenSecret) ? string.Empty : UrlEncode3986(TokenSecret)); - switch (SignatureType) { + string key = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", UrlEncode3986(_consumerSecret), + string.IsNullOrEmpty(TokenSecret) ? string.Empty : UrlEncode3986(TokenSecret)); + switch (SignatureType) + { case OAuthSignatureTypes.PLAINTEXT: parameters.Add(OAUTH_SIGNATURE_KEY, key); break; default: // Generate Signature and add it to the parameters - HMACSHA1 hmacsha1 = new HMACSHA1 {Key = Encoding.UTF8.GetBytes(key)}; + HMACSHA1 hmacsha1 = new HMACSHA1 + { + Key = Encoding.UTF8.GetBytes(key) + }; string signature = ComputeHash(hmacsha1, signatureBase.ToString()); parameters.Add(OAUTH_SIGNATURE_KEY, signature); break; @@ -542,83 +606,116 @@ namespace GreenshotPlugin.Core.OAuth /// /// IBinaryParameter /// Response from server - private string MakeRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parameters, IBinaryContainer postData) { - if (parameters == null) { + private string MakeRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parameters, IBinaryContainer postData) + { + if (parameters == null) + { throw new ArgumentNullException(nameof(parameters)); } + IDictionary requestParameters; // Add oAuth values as HTTP headers, if this is allowed StringBuilder authHeader = null; - if (UseHttpHeadersForAuthorization) { + if (UseHttpHeadersForAuthorization) + { authHeader = new StringBuilder(); requestParameters = new Dictionary(); - foreach (string parameterKey in parameters.Keys) { - if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) { + foreach (string parameterKey in parameters.Keys) + { + if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) + { authHeader.AppendFormat(CultureInfo.InvariantCulture, "{0}=\"{1}\", ", parameterKey, UrlEncode3986($"{parameters[parameterKey]}")); - } else if (!requestParameters.ContainsKey(parameterKey)) { + } + else if (!requestParameters.ContainsKey(parameterKey)) + { requestParameters.Add(parameterKey, parameters[parameterKey]); } } + // Remove trailing comma and space and add it to the headers - if (authHeader.Length > 0) { + if (authHeader.Length > 0) + { authHeader.Remove(authHeader.Length - 2, 2); } - } else { + } + else + { requestParameters = parameters; } - if (HTTPMethod.GET == method || postData != null) { - if (requestParameters.Count > 0) { + if (HTTPMethod.GET == method || postData != null) + { + if (requestParameters.Count > 0) + { // Add the parameters to the request requestUrl += "?" + NetworkHelper.GenerateQueryParameters(requestParameters); } } + // Create webrequest HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(requestUrl, method); webRequest.ServicePoint.Expect100Continue = false; webRequest.UserAgent = _userAgent; - if (UseHttpHeadersForAuthorization && authHeader != null) { + if (UseHttpHeadersForAuthorization && authHeader != null) + { Log.DebugFormat("Authorization: OAuth {0}", authHeader); webRequest.Headers.Add("Authorization: OAuth " + authHeader); } - if (headers != null) { - foreach(string key in headers.Keys) { + if (headers != null) + { + foreach (string key in headers.Keys) + { webRequest.Headers.Add(key, headers[key]); } } - if ((HTTPMethod.POST == method || HTTPMethod.PUT == method) && postData == null && requestParameters.Count > 0) { - if (UseMultipartFormData) { + if ((HTTPMethod.POST == method || HTTPMethod.PUT == method) && postData == null && requestParameters.Count > 0) + { + if (UseMultipartFormData) + { NetworkHelper.WriteMultipartFormData(webRequest, requestParameters); - } else { + } + else + { StringBuilder form = new StringBuilder(); foreach (string parameterKey in requestParameters.Keys) { var binaryParameter = parameters[parameterKey] as IBinaryContainer; - form.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), binaryParameter != null ? UrlEncode3986(binaryParameter.ToBase64String(Base64FormattingOptions.None)) : UrlEncode3986($"{parameters[parameterKey]}")); + form.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), + binaryParameter != null ? UrlEncode3986(binaryParameter.ToBase64String(Base64FormattingOptions.None)) : UrlEncode3986($"{parameters[parameterKey]}")); } + // Remove trailing & - if (form.Length > 0) { + if (form.Length > 0) + { form.Remove(form.Length - 1, 1); } + webRequest.ContentType = "application/x-www-form-urlencoded"; byte[] data = Encoding.UTF8.GetBytes(form.ToString()); using var requestStream = webRequest.GetRequestStream(); requestStream.Write(data, 0, data.Length); } - } else if (postData != null) { + } + else if (postData != null) + { postData.Upload(webRequest); - } else { + } + else + { webRequest.ContentLength = 0; } string responseData; - try { + try + { responseData = NetworkHelper.GetResponseAsString(webRequest); Log.DebugFormat("Response: {0}", responseData); - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Error("Couldn't retrieve response: ", ex); throw; } diff --git a/src/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs b/src/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs index af2bfc710..6b07f2de2 100644 --- a/src/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs +++ b/src/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs @@ -24,7 +24,8 @@ namespace GreenshotPlugin.Core.OAuth /// /// Provides a predefined set of algorithms that are supported officially by the OAuth 1.x protocol /// - public enum OAuthSignatureTypes { + public enum OAuthSignatureTypes + { HMACSHA1, PLAINTEXT, } diff --git a/src/GreenshotPlugin/Core/ObjectExtensions.cs b/src/GreenshotPlugin/Core/ObjectExtensions.cs index a948242b0..5a47a3d08 100644 --- a/src/GreenshotPlugin/Core/ObjectExtensions.cs +++ b/src/GreenshotPlugin/Core/ObjectExtensions.cs @@ -26,79 +26,93 @@ using System.Reflection; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; -namespace GreenshotPlugin.Core { - /// - /// Extension methods which work for objects - /// - public static class ObjectExtensions { - - /// - /// Perform a deep Copy of the object. - /// - /// The type of object being copied. - /// The object instance to copy. - /// The copied object. - public static T Clone(this T source) - { - var typeparam = typeof(T); - if (!typeparam.IsInterface && !typeparam.IsSerializable) - { - throw new ArgumentException("The type must be serializable.", nameof(source)); - } +namespace GreenshotPlugin.Core +{ + /// + /// Extension methods which work for objects + /// + public static class ObjectExtensions + { + /// + /// Perform a deep Copy of the object. + /// + /// The type of object being copied. + /// The object instance to copy. + /// The copied object. + public static T Clone(this T source) + { + var typeparam = typeof(T); + if (!typeparam.IsInterface && !typeparam.IsSerializable) + { + throw new ArgumentException("The type must be serializable.", nameof(source)); + } - // Don't serialize a null object, simply return the default for that object - if (source == null) { - return default; - } - - IFormatter formatter = new BinaryFormatter(); + // Don't serialize a null object, simply return the default for that object + if (source == null) + { + return default; + } + + IFormatter formatter = new BinaryFormatter(); using var stream = new MemoryStream(); formatter.Serialize(stream, source); stream.Seek(0, SeekOrigin.Begin); - return (T)formatter.Deserialize(stream); + return (T) formatter.Deserialize(stream); } - - /// - /// Clone the content from source to destination - /// - /// Type to clone - /// Instance to copy from - /// Instance to copy to - public static void CloneTo(this T source, T destination) { - var type = typeof(T); - var myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - foreach (var fieldInfo in myObjectFields) { - fieldInfo.SetValue(destination, fieldInfo.GetValue(source)); - } - var myObjectProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + /// + /// Clone the content from source to destination + /// + /// Type to clone + /// Instance to copy from + /// Instance to copy to + public static void CloneTo(this T source, T destination) + { + var type = typeof(T); + var myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - foreach (var propertyInfo in myObjectProperties) { - if (propertyInfo.CanWrite) { - propertyInfo.SetValue(destination, propertyInfo.GetValue(source, null), null); - } - } - } + foreach (var fieldInfo in myObjectFields) + { + fieldInfo.SetValue(destination, fieldInfo.GetValue(source)); + } - /// - /// Compare two lists - /// - /// - /// IList - /// IList - /// true if they are the same - public static bool CompareLists(IList l1, IList l2) { - if (l1.Count != l2.Count) { - return false; - } - int matched = 0; - foreach(T item in l1) { - if (!l2.Contains(item)) { - return false; - } - matched++; - } - return matched == l1.Count; - } - } -} + var myObjectProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + + foreach (var propertyInfo in myObjectProperties) + { + if (propertyInfo.CanWrite) + { + propertyInfo.SetValue(destination, propertyInfo.GetValue(source, null), null); + } + } + } + + /// + /// Compare two lists + /// + /// + /// IList + /// IList + /// true if they are the same + public static bool CompareLists(IList l1, IList l2) + { + if (l1.Count != l2.Count) + { + return false; + } + + int matched = 0; + foreach (T item in l1) + { + if (!l2.Contains(item)) + { + return false; + } + + matched++; + } + + return matched == l1.Count; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/PluginUtils.cs b/src/GreenshotPlugin/Core/PluginUtils.cs index 51edfffa8..870e2cca7 100644 --- a/src/GreenshotPlugin/Core/PluginUtils.cs +++ b/src/GreenshotPlugin/Core/PluginUtils.cs @@ -30,154 +30,199 @@ using System.IO; using System.Windows.Forms; using GreenshotPlugin.IniFile; -namespace GreenshotPlugin.Core { - /// - /// Description of PluginUtils. - /// - public static class PluginUtils { - private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\"; - private static readonly IDictionary ExeIconCache = new Dictionary(); +namespace GreenshotPlugin.Core +{ + /// + /// Description of PluginUtils. + /// + public static class PluginUtils + { + private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\"; + private static readonly IDictionary ExeIconCache = new Dictionary(); - static PluginUtils() { - CoreConfig.PropertyChanged += OnIconSizeChanged; - } + static PluginUtils() + { + CoreConfig.PropertyChanged += OnIconSizeChanged; + } - /// - /// Clear icon cache - /// - /// - /// - private static void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) { + /// + /// Clear icon cache + /// + /// + /// + private static void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) + { if (e.PropertyName != "IconSize") return; var cachedImages = new List(); - lock (ExeIconCache) { - foreach (string key in ExeIconCache.Keys) { + lock (ExeIconCache) + { + foreach (string key in ExeIconCache.Keys) + { cachedImages.Add(ExeIconCache[key]); } + ExeIconCache.Clear(); } + foreach (Image cachedImage in cachedImages) { cachedImage?.Dispose(); } } - /// - /// Get the path of an executable - /// - /// e.g. cmd.exe - /// Path to file - public static string GetExePath(string exeName) { - using (var key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) { - if (key != null) { - // "" is the default key, which should point to the requested location - return (string)key.GetValue(string.Empty); - } - } - foreach (string pathEntry in (Environment.GetEnvironmentVariable("PATH") ?? string.Empty).Split(';')) { - try { - string path = pathEntry.Trim(); - if (!string.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exeName))) { - return Path.GetFullPath(path); - } - } catch (Exception) { - Log.WarnFormat("Problem with path entry '{0}'.", pathEntry); - } - } - return null; - } + /// + /// Get the path of an executable + /// + /// e.g. cmd.exe + /// Path to file + public static string GetExePath(string exeName) + { + using (var key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) + { + if (key != null) + { + // "" is the default key, which should point to the requested location + return (string) key.GetValue(string.Empty); + } + } - /// - /// Get icon from resource files, from the cache. - /// Examples can be found here: https://diymediahome.org/windows-icons-reference-list-with-details-locations-images/ - /// - /// path to the exe or dll - /// index of the icon - /// Bitmap with the icon or null if something happended - public static Image GetCachedExeIcon(string path, int index) { - string cacheKey = $"{path}:{index}"; - Image returnValue; - lock (ExeIconCache) - { - if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) - { - return returnValue; - } - lock (ExeIconCache) { - if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) - { - return returnValue; - } - returnValue = GetExeIcon(path, index); - if (returnValue != null) { - ExeIconCache.Add(cacheKey, returnValue); - } - } - } - return returnValue; - } + foreach (string pathEntry in (Environment.GetEnvironmentVariable("PATH") ?? string.Empty).Split(';')) + { + try + { + string path = pathEntry.Trim(); + if (!string.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exeName))) + { + return Path.GetFullPath(path); + } + } + catch (Exception) + { + Log.WarnFormat("Problem with path entry '{0}'.", pathEntry); + } + } - /// - /// Get icon for executable - /// - /// path to the exe or dll - /// index of the icon - /// Bitmap with the icon or null if something happended - private static Bitmap GetExeIcon(string path, int index) { - if (!File.Exists(path)) { - return null; - } - try { - using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) { - if (appIcon != null) { - return appIcon.ToBitmap(); - } - } - using (Icon appIcon = Shell32.GetFileIcon(path, CoreConfig.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false)) { - if (appIcon != null) { - return appIcon.ToBitmap(); - } - } - } catch (Exception exIcon) { - Log.Error("error retrieving icon: ", exIcon); - } - return null; - } + return null; + } /// - /// Helper method to add a plugin MenuItem to the Greenshot context menu - /// - /// ToolStripMenuItem - public static void AddToContextMenu(ToolStripMenuItem item) { + /// Get icon from resource files, from the cache. + /// Examples can be found here: https://diymediahome.org/windows-icons-reference-list-with-details-locations-images/ + /// + /// path to the exe or dll + /// index of the icon + /// Bitmap with the icon or null if something happended + public static Image GetCachedExeIcon(string path, int index) + { + string cacheKey = $"{path}:{index}"; + Image returnValue; + lock (ExeIconCache) + { + if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) + { + return returnValue; + } + + lock (ExeIconCache) + { + if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) + { + return returnValue; + } + + returnValue = GetExeIcon(path, index); + if (returnValue != null) + { + ExeIconCache.Add(cacheKey, returnValue); + } + } + } + + return returnValue; + } + + /// + /// Get icon for executable + /// + /// path to the exe or dll + /// index of the icon + /// Bitmap with the icon or null if something happended + private static Bitmap GetExeIcon(string path, int index) + { + if (!File.Exists(path)) + { + return null; + } + + try + { + using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) + { + if (appIcon != null) + { + return appIcon.ToBitmap(); + } + } + + using (Icon appIcon = Shell32.GetFileIcon(path, CoreConfig.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false)) + { + if (appIcon != null) + { + return appIcon.ToBitmap(); + } + } + } + catch (Exception exIcon) + { + Log.Error("error retrieving icon: ", exIcon); + } + + return null; + } + + /// + /// Helper method to add a plugin MenuItem to the Greenshot context menu + /// + /// ToolStripMenuItem + public static void AddToContextMenu(ToolStripMenuItem item) + { // Here we can hang ourselves to the main context menu! var contextMenu = SimpleServiceProvider.Current.GetInstance(); - bool addedItem = false; + bool addedItem = false; - // Try to find a separator, so we insert ourselves after it - for(int i=0; i < contextMenu.Items.Count; i++) { - if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) { - // Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore" - if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag)) { - var separator = new ToolStripSeparator - { - Tag = "PluginsAreAddedAfter", - Size = new Size(305, 6) - }; - contextMenu.Items.Insert(i, separator); - } else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag)) { - continue; - } - contextMenu.Items.Insert(i + 1, item); - addedItem = true; - break; - } - } - // If we didn't insert the item, we just add it... - if (!addedItem) { - contextMenu.Items.Add(item); - } - } - } -} + // Try to find a separator, so we insert ourselves after it + for (int i = 0; i < contextMenu.Items.Count; i++) + { + if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) + { + // Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore" + if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag)) + { + var separator = new ToolStripSeparator + { + Tag = "PluginsAreAddedAfter", + Size = new Size(305, 6) + }; + contextMenu.Items.Insert(i, separator); + } + else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag)) + { + continue; + } + + contextMenu.Items.Insert(i + 1, item); + addedItem = true; + break; + } + } + + // If we didn't insert the item, we just add it... + if (!addedItem) + { + contextMenu.Items.Add(item); + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/QuantizerHelper.cs b/src/GreenshotPlugin/Core/QuantizerHelper.cs index f5396810f..91296005d 100644 --- a/src/GreenshotPlugin/Core/QuantizerHelper.cs +++ b/src/GreenshotPlugin/Core/QuantizerHelper.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections; using System.Collections.Generic; @@ -25,153 +26,170 @@ using System.Drawing; using System.Drawing.Imaging; using log4net; -namespace GreenshotPlugin.Core { - internal class WuColorCube { - /// - /// Gets or sets the red minimum. - /// - /// The red minimum. - public int RedMinimum { get; set; } +namespace GreenshotPlugin.Core +{ + internal class WuColorCube + { + /// + /// Gets or sets the red minimum. + /// + /// The red minimum. + public int RedMinimum { get; set; } - /// - /// Gets or sets the red maximum. - /// - /// The red maximum. - public int RedMaximum { get; set; } + /// + /// Gets or sets the red maximum. + /// + /// The red maximum. + public int RedMaximum { get; set; } - /// - /// Gets or sets the green minimum. - /// - /// The green minimum. - public int GreenMinimum { get; set; } + /// + /// Gets or sets the green minimum. + /// + /// The green minimum. + public int GreenMinimum { get; set; } - /// - /// Gets or sets the green maximum. - /// - /// The green maximum. - public int GreenMaximum { get; set; } + /// + /// Gets or sets the green maximum. + /// + /// The green maximum. + public int GreenMaximum { get; set; } - /// - /// Gets or sets the blue minimum. - /// - /// The blue minimum. - public int BlueMinimum { get; set; } + /// + /// Gets or sets the blue minimum. + /// + /// The blue minimum. + public int BlueMinimum { get; set; } - /// - /// Gets or sets the blue maximum. - /// - /// The blue maximum. - public int BlueMaximum { get; set; } + /// + /// Gets or sets the blue maximum. + /// + /// The blue maximum. + public int BlueMaximum { get; set; } - /// - /// Gets or sets the cube volume. - /// - /// The volume. - public int Volume { get; set; } - } + /// + /// Gets or sets the cube volume. + /// + /// The volume. + public int Volume { get; set; } + } - public class WuQuantizer : IDisposable { - private static readonly ILog LOG = LogManager.GetLogger(typeof(WuQuantizer)); + public class WuQuantizer : IDisposable + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(WuQuantizer)); - private const int MAXCOLOR = 512; - private const int RED = 2; - private const int GREEN = 1; - private const int BLUE = 0; - private const int SIDESIZE = 33; - private const int MAXSIDEINDEX = 32; - private const int MAXVOLUME = SIDESIZE * SIDESIZE * SIDESIZE; + private const int MAXCOLOR = 512; + private const int RED = 2; + private const int GREEN = 1; + private const int BLUE = 0; + private const int SIDESIZE = 33; + private const int MAXSIDEINDEX = 32; + private const int MAXVOLUME = SIDESIZE * SIDESIZE * SIDESIZE; - // To count the colors - private readonly int colorCount; + // To count the colors + private readonly int colorCount; - private int[] reds; - private int[] greens; - private int[] blues; - private int[] sums; + private int[] reds; + private int[] greens; + private int[] blues; + private int[] sums; - private readonly long[,,] weights; - private readonly long[,,] momentsRed; - private readonly long[,,] momentsGreen; - private readonly long[,,] momentsBlue; - private readonly float[,,] moments; + private readonly long[,,] weights; + private readonly long[,,] momentsRed; + private readonly long[,,] momentsGreen; + private readonly long[,,] momentsBlue; + private readonly float[,,] moments; - private byte[] tag; + private byte[] tag; - private readonly WuColorCube[] cubes; - private readonly Bitmap sourceBitmap; - private Bitmap resultBitmap; + private readonly WuColorCube[] cubes; + private readonly Bitmap sourceBitmap; + private Bitmap resultBitmap; - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - protected virtual void Dispose(bool disposing) { - if (disposing) { - if (resultBitmap != null) { - resultBitmap.Dispose(); - resultBitmap = null; - } - } - } + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (resultBitmap != null) + { + resultBitmap.Dispose(); + resultBitmap = null; + } + } + } - /// - /// See for more details. - /// - public WuQuantizer(Bitmap sourceBitmap) { - this.sourceBitmap = sourceBitmap; - // Make sure the color count variables are reset - BitArray bitArray = new BitArray((int)Math.Pow(2, 24)); - colorCount = 0; + /// + /// See for more details. + /// + public WuQuantizer(Bitmap sourceBitmap) + { + this.sourceBitmap = sourceBitmap; + // Make sure the color count variables are reset + BitArray bitArray = new BitArray((int) Math.Pow(2, 24)); + colorCount = 0; - // creates all the cubes - cubes = new WuColorCube[MAXCOLOR]; + // creates all the cubes + cubes = new WuColorCube[MAXCOLOR]; - // initializes all the cubes - for (int cubeIndex = 0; cubeIndex < MAXCOLOR; cubeIndex++) { - cubes[cubeIndex] = new WuColorCube(); - } + // initializes all the cubes + for (int cubeIndex = 0; cubeIndex < MAXCOLOR; cubeIndex++) + { + cubes[cubeIndex] = new WuColorCube(); + } - // resets the reference minimums - cubes[0].RedMinimum = 0; - cubes[0].GreenMinimum = 0; - cubes[0].BlueMinimum = 0; + // resets the reference minimums + cubes[0].RedMinimum = 0; + cubes[0].GreenMinimum = 0; + cubes[0].BlueMinimum = 0; - // resets the reference maximums - cubes[0].RedMaximum = MAXSIDEINDEX; - cubes[0].GreenMaximum = MAXSIDEINDEX; - cubes[0].BlueMaximum = MAXSIDEINDEX; + // resets the reference maximums + cubes[0].RedMaximum = MAXSIDEINDEX; + cubes[0].GreenMaximum = MAXSIDEINDEX; + cubes[0].BlueMaximum = MAXSIDEINDEX; - weights = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - momentsRed = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - momentsGreen = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - momentsBlue = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - moments = new float[SIDESIZE, SIDESIZE, SIDESIZE]; + weights = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + momentsRed = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + momentsGreen = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + momentsBlue = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + moments = new float[SIDESIZE, SIDESIZE, SIDESIZE]; - int[] table = new int[256]; + int[] table = new int[256]; - for (int tableIndex = 0; tableIndex < 256; ++tableIndex) { - table[tableIndex] = tableIndex * tableIndex; - } + for (int tableIndex = 0; tableIndex < 256; ++tableIndex) + { + table[tableIndex] = tableIndex * tableIndex; + } - // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage + // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage using IFastBitmap sourceFastBitmap = FastBitmap.Create(sourceBitmap); IFastBitmapWithBlend sourceFastBitmapWithBlend = sourceFastBitmap as IFastBitmapWithBlend; sourceFastBitmap.Lock(); using FastChunkyBitmap destinationFastBitmap = FastBitmap.CreateEmpty(sourceBitmap.Size, PixelFormat.Format8bppIndexed, Color.White) as FastChunkyBitmap; destinationFastBitmap.Lock(); - for (int y = 0; y < sourceFastBitmap.Height; y++) { - for (int x = 0; x < sourceFastBitmap.Width; x++) { + for (int y = 0; y < sourceFastBitmap.Height; y++) + { + for (int x = 0; x < sourceFastBitmap.Width; x++) + { Color color; - if (sourceFastBitmapWithBlend == null) { + if (sourceFastBitmapWithBlend == null) + { color = sourceFastBitmap.GetColorAt(x, y); - } else { + } + else + { color = sourceFastBitmapWithBlend.GetBlendedColorAt(x, y); } + // To count the colors int index = color.ToArgb() & 0x00ffffff; // Check if we already have this color - if (!bitArray.Get(index)) { + if (!bitArray.Get(index)) + { // If not, add 1 to the single colors colorCount++; bitArray.Set(index, true); @@ -189,165 +207,206 @@ namespace GreenshotPlugin.Core { // Store the initial "match" int paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue; - destinationFastBitmap.SetColorIndexAt(x, y, (byte)(paletteIndex & 0xff)); + destinationFastBitmap.SetColorIndexAt(x, y, (byte) (paletteIndex & 0xff)); } } + resultBitmap = destinationFastBitmap.UnlockAndReturnBitmap(); } - /// - /// See for more details. - /// - public int GetColorCount() { - return colorCount; - } + /// + /// See for more details. + /// + public int GetColorCount() + { + return colorCount; + } - /// - /// Reindex the 24/32 BPP (A)RGB image to a 8BPP - /// - /// Bitmap - public Bitmap SimpleReindex() { - List colors = new List(); - Dictionary lookup = new Dictionary(); - using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) { - bbbDest.Lock(); + /// + /// Reindex the 24/32 BPP (A)RGB image to a 8BPP + /// + /// Bitmap + public Bitmap SimpleReindex() + { + List colors = new List(); + Dictionary lookup = new Dictionary(); + using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) + { + bbbDest.Lock(); using IFastBitmap bbbSrc = FastBitmap.Create(sourceBitmap); IFastBitmapWithBlend bbbSrcBlend = bbbSrc as IFastBitmapWithBlend; bbbSrc.Lock(); byte index; - for (int y = 0; y < bbbSrc.Height; y++) { - for (int x = 0; x < bbbSrc.Width; x++) { + for (int y = 0; y < bbbSrc.Height; y++) + { + for (int x = 0; x < bbbSrc.Width; x++) + { Color color; - if (bbbSrcBlend != null) { + if (bbbSrcBlend != null) + { color = bbbSrcBlend.GetBlendedColorAt(x, y); - } else { + } + else + { color = bbbSrc.GetColorAt(x, y); } - if (lookup.ContainsKey(color)) { + + if (lookup.ContainsKey(color)) + { index = lookup[color]; - } else { + } + else + { colors.Add(color); - index = (byte)(colors.Count - 1); + index = (byte) (colors.Count - 1); lookup.Add(color, index); } + bbbDest.SetColorIndexAt(x, y, index); } } } - // generates palette - ColorPalette imagePalette = resultBitmap.Palette; - Color[] entries = imagePalette.Entries; - for (int paletteIndex = 0; paletteIndex < 256; paletteIndex++) { - if (paletteIndex < colorCount) { - entries[paletteIndex] = colors[paletteIndex]; - } else { - entries[paletteIndex] = Color.Black; - } - } - resultBitmap.Palette = imagePalette; + // generates palette + ColorPalette imagePalette = resultBitmap.Palette; + Color[] entries = imagePalette.Entries; + for (int paletteIndex = 0; paletteIndex < 256; paletteIndex++) + { + if (paletteIndex < colorCount) + { + entries[paletteIndex] = colors[paletteIndex]; + } + else + { + entries[paletteIndex] = Color.Black; + } + } - // Make sure the bitmap is not disposed, as we return it. - Bitmap tmpBitmap = resultBitmap; - resultBitmap = null; - return tmpBitmap; - } + resultBitmap.Palette = imagePalette; - /// - /// Get the image - /// - public Bitmap GetQuantizedImage(int allowedColorCount) { - if (allowedColorCount > 256) { - throw new ArgumentOutOfRangeException(nameof(allowedColorCount), "Quantizing muss be done to get less than 256 colors"); - } - if (colorCount < allowedColorCount) { - // Simple logic to reduce to 8 bit - LOG.Info("Colors in the image are already less as whished for, using simple copy to indexed image, no quantizing needed!"); - return SimpleReindex(); - } - // preprocess the colors - CalculateMoments(); - LOG.Info("Calculated the moments..."); - int next = 0; - float[] volumeVariance = new float[MAXCOLOR]; + // Make sure the bitmap is not disposed, as we return it. + Bitmap tmpBitmap = resultBitmap; + resultBitmap = null; + return tmpBitmap; + } - // processes the cubes - for (int cubeIndex = 1; cubeIndex < allowedColorCount; ++cubeIndex) { - // if cut is possible; make it - if (Cut(cubes[next], cubes[cubeIndex])) { - volumeVariance[next] = cubes[next].Volume > 1 ? CalculateVariance(cubes[next]) : 0.0f; - volumeVariance[cubeIndex] = cubes[cubeIndex].Volume > 1 ? CalculateVariance(cubes[cubeIndex]) : 0.0f; - } else { - // the cut was not possible, revert the index - volumeVariance[next] = 0.0f; - cubeIndex--; - } + /// + /// Get the image + /// + public Bitmap GetQuantizedImage(int allowedColorCount) + { + if (allowedColorCount > 256) + { + throw new ArgumentOutOfRangeException(nameof(allowedColorCount), "Quantizing muss be done to get less than 256 colors"); + } - next = 0; - float temp = volumeVariance[0]; + if (colorCount < allowedColorCount) + { + // Simple logic to reduce to 8 bit + LOG.Info("Colors in the image are already less as whished for, using simple copy to indexed image, no quantizing needed!"); + return SimpleReindex(); + } - for (int index = 1; index <= cubeIndex; ++index) { - if (volumeVariance[index] > temp) { - temp = volumeVariance[index]; - next = index; - } - } + // preprocess the colors + CalculateMoments(); + LOG.Info("Calculated the moments..."); + int next = 0; + float[] volumeVariance = new float[MAXCOLOR]; - if (temp <= 0.0) { - allowedColorCount = cubeIndex + 1; - break; - } - } + // processes the cubes + for (int cubeIndex = 1; cubeIndex < allowedColorCount; ++cubeIndex) + { + // if cut is possible; make it + if (Cut(cubes[next], cubes[cubeIndex])) + { + volumeVariance[next] = cubes[next].Volume > 1 ? CalculateVariance(cubes[next]) : 0.0f; + volumeVariance[cubeIndex] = cubes[cubeIndex].Volume > 1 ? CalculateVariance(cubes[cubeIndex]) : 0.0f; + } + else + { + // the cut was not possible, revert the index + volumeVariance[next] = 0.0f; + cubeIndex--; + } - int[] lookupRed = new int[MAXCOLOR]; - int[] lookupGreen = new int[MAXCOLOR]; - int[] lookupBlue = new int[MAXCOLOR]; + next = 0; + float temp = volumeVariance[0]; - tag = new byte[MAXVOLUME]; + for (int index = 1; index <= cubeIndex; ++index) + { + if (volumeVariance[index] > temp) + { + temp = volumeVariance[index]; + next = index; + } + } - // precalculates lookup tables - for (int k = 0; k < allowedColorCount; ++k) { - Mark(cubes[k], k, tag); + if (temp <= 0.0) + { + allowedColorCount = cubeIndex + 1; + break; + } + } - long weight = Volume(cubes[k], weights); + int[] lookupRed = new int[MAXCOLOR]; + int[] lookupGreen = new int[MAXCOLOR]; + int[] lookupBlue = new int[MAXCOLOR]; - if (weight > 0) { - lookupRed[k] = (int)(Volume(cubes[k], momentsRed) / weight); - lookupGreen[k] = (int)(Volume(cubes[k], momentsGreen) / weight); - lookupBlue[k] = (int)(Volume(cubes[k], momentsBlue) / weight); - } else { - lookupRed[k] = 0; - lookupGreen[k] = 0; - lookupBlue[k] = 0; - } - } + tag = new byte[MAXVOLUME]; - reds = new int[allowedColorCount + 1]; - greens = new int[allowedColorCount + 1]; - blues = new int[allowedColorCount + 1]; - sums = new int[allowedColorCount + 1]; + // precalculates lookup tables + for (int k = 0; k < allowedColorCount; ++k) + { + Mark(cubes[k], k, tag); - LOG.Info("Starting bitmap reconstruction..."); + long weight = Volume(cubes[k], weights); - using (FastChunkyBitmap dest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) + if (weight > 0) + { + lookupRed[k] = (int) (Volume(cubes[k], momentsRed) / weight); + lookupGreen[k] = (int) (Volume(cubes[k], momentsGreen) / weight); + lookupBlue[k] = (int) (Volume(cubes[k], momentsBlue) / weight); + } + else + { + lookupRed[k] = 0; + lookupGreen[k] = 0; + lookupBlue[k] = 0; + } + } + + reds = new int[allowedColorCount + 1]; + greens = new int[allowedColorCount + 1]; + blues = new int[allowedColorCount + 1]; + sums = new int[allowedColorCount + 1]; + + LOG.Info("Starting bitmap reconstruction..."); + + using (FastChunkyBitmap dest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) { using IFastBitmap src = FastBitmap.Create(sourceBitmap); IFastBitmapWithBlend srcBlend = src as IFastBitmapWithBlend; Dictionary lookup = new Dictionary(); - for (int y = 0; y < src.Height; y++) { - for (int x = 0; x < src.Width; x++) { + for (int y = 0; y < src.Height; y++) + { + for (int x = 0; x < src.Width; x++) + { Color color; - if (srcBlend != null) { + if (srcBlend != null) + { // WithoutAlpha, this makes it possible to ignore the alpha color = srcBlend.GetBlendedColorAt(x, y); - } else { + } + else + { color = src.GetColorAt(x, y); } // Check if we already matched the color byte bestMatch; - if (!lookup.ContainsKey(color)) { + if (!lookup.ContainsKey(color)) + { // If not we need to find the best match // First get initial match @@ -355,7 +414,8 @@ namespace GreenshotPlugin.Core { bestMatch = tag[bestMatch]; int bestDistance = 100000000; - for (int lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++) { + for (int lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++) + { int foundRed = lookupRed[lookupIndex]; int foundGreen = lookupGreen[lookupIndex]; int foundBlue = lookupBlue[lookupIndex]; @@ -365,13 +425,17 @@ namespace GreenshotPlugin.Core { int distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue; - if (distance < bestDistance) { + if (distance < bestDistance) + { bestDistance = distance; - bestMatch = (byte)lookupIndex; + bestMatch = (byte) lookupIndex; } } + lookup.Add(color, bestMatch); - } else { + } + else + { // Already matched, so we just use the lookup bestMatch = lookup[color]; } @@ -387,129 +451,140 @@ namespace GreenshotPlugin.Core { } - // generates palette - ColorPalette imagePalette = resultBitmap.Palette; - Color[] entries = imagePalette.Entries; - for (int paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++) { - if (sums[paletteIndex] > 0) { - reds[paletteIndex] /= sums[paletteIndex]; - greens[paletteIndex] /= sums[paletteIndex]; - blues[paletteIndex] /= sums[paletteIndex]; - } + // generates palette + ColorPalette imagePalette = resultBitmap.Palette; + Color[] entries = imagePalette.Entries; + for (int paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++) + { + if (sums[paletteIndex] > 0) + { + reds[paletteIndex] /= sums[paletteIndex]; + greens[paletteIndex] /= sums[paletteIndex]; + blues[paletteIndex] /= sums[paletteIndex]; + } - entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]); - } - resultBitmap.Palette = imagePalette; + entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]); + } - // Make sure the bitmap is not disposed, as we return it. - Bitmap tmpBitmap = resultBitmap; - resultBitmap = null; - return tmpBitmap; - } + resultBitmap.Palette = imagePalette; - /// - /// Converts the histogram to a series of moments. - /// - private void CalculateMoments() { - long[] area = new long[SIDESIZE]; - long[] areaRed = new long[SIDESIZE]; - long[] areaGreen = new long[SIDESIZE]; - long[] areaBlue = new long[SIDESIZE]; - float[] area2 = new float[SIDESIZE]; + // Make sure the bitmap is not disposed, as we return it. + Bitmap tmpBitmap = resultBitmap; + resultBitmap = null; + return tmpBitmap; + } - for (int redIndex = 1; redIndex <= MAXSIDEINDEX; ++redIndex) { - for (int index = 0; index <= MAXSIDEINDEX; ++index) { - area[index] = 0; - areaRed[index] = 0; - areaGreen[index] = 0; - areaBlue[index] = 0; - area2[index] = 0; - } + /// + /// Converts the histogram to a series of moments. + /// + private void CalculateMoments() + { + long[] area = new long[SIDESIZE]; + long[] areaRed = new long[SIDESIZE]; + long[] areaGreen = new long[SIDESIZE]; + long[] areaBlue = new long[SIDESIZE]; + float[] area2 = new float[SIDESIZE]; - for (int greenIndex = 1; greenIndex <= MAXSIDEINDEX; ++greenIndex) { - long line = 0; - long lineRed = 0; - long lineGreen = 0; - long lineBlue = 0; - float line2 = 0.0f; + for (int redIndex = 1; redIndex <= MAXSIDEINDEX; ++redIndex) + { + for (int index = 0; index <= MAXSIDEINDEX; ++index) + { + area[index] = 0; + areaRed[index] = 0; + areaGreen[index] = 0; + areaBlue[index] = 0; + area2[index] = 0; + } - for (int blueIndex = 1; blueIndex <= MAXSIDEINDEX; ++blueIndex) { - line += weights[redIndex, greenIndex, blueIndex]; - lineRed += momentsRed[redIndex, greenIndex, blueIndex]; - lineGreen += momentsGreen[redIndex, greenIndex, blueIndex]; - lineBlue += momentsBlue[redIndex, greenIndex, blueIndex]; - line2 += moments[redIndex, greenIndex, blueIndex]; + for (int greenIndex = 1; greenIndex <= MAXSIDEINDEX; ++greenIndex) + { + long line = 0; + long lineRed = 0; + long lineGreen = 0; + long lineBlue = 0; + float line2 = 0.0f; - area[blueIndex] += line; - areaRed[blueIndex] += lineRed; - areaGreen[blueIndex] += lineGreen; - areaBlue[blueIndex] += lineBlue; - area2[blueIndex] += line2; + for (int blueIndex = 1; blueIndex <= MAXSIDEINDEX; ++blueIndex) + { + line += weights[redIndex, greenIndex, blueIndex]; + lineRed += momentsRed[redIndex, greenIndex, blueIndex]; + lineGreen += momentsGreen[redIndex, greenIndex, blueIndex]; + lineBlue += momentsBlue[redIndex, greenIndex, blueIndex]; + line2 += moments[redIndex, greenIndex, blueIndex]; - weights[redIndex, greenIndex, blueIndex] = weights[redIndex - 1, greenIndex, blueIndex] + area[blueIndex]; - momentsRed[redIndex, greenIndex, blueIndex] = momentsRed[redIndex - 1, greenIndex, blueIndex] + areaRed[blueIndex]; - momentsGreen[redIndex, greenIndex, blueIndex] = momentsGreen[redIndex - 1, greenIndex, blueIndex] + areaGreen[blueIndex]; - momentsBlue[redIndex, greenIndex, blueIndex] = momentsBlue[redIndex - 1, greenIndex, blueIndex] + areaBlue[blueIndex]; - moments[redIndex, greenIndex, blueIndex] = moments[redIndex - 1, greenIndex, blueIndex] + area2[blueIndex]; - } - } - } - } + area[blueIndex] += line; + areaRed[blueIndex] += lineRed; + areaGreen[blueIndex] += lineGreen; + areaBlue[blueIndex] += lineBlue; + area2[blueIndex] += line2; - /// - /// Computes the volume of the cube in a specific moment. - /// - private static long Volume(WuColorCube cube, long[,,] moment) { - return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - - moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; - } + weights[redIndex, greenIndex, blueIndex] = weights[redIndex - 1, greenIndex, blueIndex] + area[blueIndex]; + momentsRed[redIndex, greenIndex, blueIndex] = momentsRed[redIndex - 1, greenIndex, blueIndex] + areaRed[blueIndex]; + momentsGreen[redIndex, greenIndex, blueIndex] = momentsGreen[redIndex - 1, greenIndex, blueIndex] + areaGreen[blueIndex]; + momentsBlue[redIndex, greenIndex, blueIndex] = momentsBlue[redIndex - 1, greenIndex, blueIndex] + areaBlue[blueIndex]; + moments[redIndex, greenIndex, blueIndex] = moments[redIndex - 1, greenIndex, blueIndex] + area2[blueIndex]; + } + } + } + } - /// - /// Computes the volume of the cube in a specific moment. For the floating-point values. - /// - private static float VolumeFloat(WuColorCube cube, float[,,] moment) { - return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - - moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; - } + /// + /// Computes the volume of the cube in a specific moment. + /// + private static long Volume(WuColorCube cube, long[,,] moment) + { + return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - + moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; + } - /// - /// Splits the cube in given position, and color direction. - /// - private static long Top(WuColorCube cube, int direction, int position, long[,,] moment) { - return direction switch - { - RED => (moment[position, cube.GreenMaximum, cube.BlueMaximum] - - moment[position, cube.GreenMaximum, cube.BlueMinimum] - - moment[position, cube.GreenMinimum, cube.BlueMaximum] + - moment[position, cube.GreenMinimum, cube.BlueMinimum]), - GREEN => (moment[cube.RedMaximum, position, cube.BlueMaximum] - - moment[cube.RedMaximum, position, cube.BlueMinimum] - - moment[cube.RedMinimum, position, cube.BlueMaximum] + - moment[cube.RedMinimum, position, cube.BlueMinimum]), - BLUE => (moment[cube.RedMaximum, cube.GreenMaximum, position] - - moment[cube.RedMaximum, cube.GreenMinimum, position] - - moment[cube.RedMinimum, cube.GreenMaximum, position] + - moment[cube.RedMinimum, cube.GreenMinimum, position]), - _ => 0, - }; - } + /// + /// Computes the volume of the cube in a specific moment. For the floating-point values. + /// + private static float VolumeFloat(WuColorCube cube, float[,,] moment) + { + return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - + moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; + } - /// - /// Splits the cube in a given color direction at its minimum. - /// - private static long Bottom(WuColorCube cube, int direction, long[,,] moment) + /// + /// Splits the cube in given position, and color direction. + /// + private static long Top(WuColorCube cube, int direction, int position, long[,,] moment) + { + return direction switch + { + RED => (moment[position, cube.GreenMaximum, cube.BlueMaximum] - + moment[position, cube.GreenMaximum, cube.BlueMinimum] - + moment[position, cube.GreenMinimum, cube.BlueMaximum] + + moment[position, cube.GreenMinimum, cube.BlueMinimum]), + GREEN => (moment[cube.RedMaximum, position, cube.BlueMaximum] - + moment[cube.RedMaximum, position, cube.BlueMinimum] - + moment[cube.RedMinimum, position, cube.BlueMaximum] + + moment[cube.RedMinimum, position, cube.BlueMinimum]), + BLUE => (moment[cube.RedMaximum, cube.GreenMaximum, position] - + moment[cube.RedMaximum, cube.GreenMinimum, position] - + moment[cube.RedMinimum, cube.GreenMaximum, position] + + moment[cube.RedMinimum, cube.GreenMinimum, position]), + _ => 0, + }; + } + + /// + /// Splits the cube in a given color direction at its minimum. + /// + private static long Bottom(WuColorCube cube, int direction, long[,,] moment) { return direction switch { @@ -529,141 +604,168 @@ namespace GreenshotPlugin.Core { }; } - /// - /// Calculates statistical variance for a given cube. - /// - private float CalculateVariance(WuColorCube cube) { - float volumeRed = Volume(cube, momentsRed); - float volumeGreen = Volume(cube, momentsGreen); - float volumeBlue = Volume(cube, momentsBlue); - float volumeMoment = VolumeFloat(cube, moments); - float volumeWeight = Volume(cube, weights); + /// + /// Calculates statistical variance for a given cube. + /// + private float CalculateVariance(WuColorCube cube) + { + float volumeRed = Volume(cube, momentsRed); + float volumeGreen = Volume(cube, momentsGreen); + float volumeBlue = Volume(cube, momentsBlue); + float volumeMoment = VolumeFloat(cube, moments); + float volumeWeight = Volume(cube, weights); - float distance = volumeRed * volumeRed + volumeGreen * volumeGreen + volumeBlue * volumeBlue; + float distance = volumeRed * volumeRed + volumeGreen * volumeGreen + volumeBlue * volumeBlue; - return volumeMoment - (distance / volumeWeight); - } + return volumeMoment - (distance / volumeWeight); + } - /// - /// Finds the optimal (maximal) position for the cut. - /// - private float Maximize(WuColorCube cube, int direction, int first, int last, int[] cut, long wholeRed, long wholeGreen, long wholeBlue, long wholeWeight) { - long bottomRed = Bottom(cube, direction, momentsRed); - long bottomGreen = Bottom(cube, direction, momentsGreen); - long bottomBlue = Bottom(cube, direction, momentsBlue); - long bottomWeight = Bottom(cube, direction, weights); + /// + /// Finds the optimal (maximal) position for the cut. + /// + private float Maximize(WuColorCube cube, int direction, int first, int last, int[] cut, long wholeRed, long wholeGreen, long wholeBlue, long wholeWeight) + { + long bottomRed = Bottom(cube, direction, momentsRed); + long bottomGreen = Bottom(cube, direction, momentsGreen); + long bottomBlue = Bottom(cube, direction, momentsBlue); + long bottomWeight = Bottom(cube, direction, weights); - float result = 0.0f; - cut[0] = -1; + float result = 0.0f; + cut[0] = -1; - for (int position = first; position < last; ++position) { - // determines the cube cut at a certain position - long halfRed = bottomRed + Top(cube, direction, position, momentsRed); - long halfGreen = bottomGreen + Top(cube, direction, position, momentsGreen); - long halfBlue = bottomBlue + Top(cube, direction, position, momentsBlue); - long halfWeight = bottomWeight + Top(cube, direction, position, weights); + for (int position = first; position < last; ++position) + { + // determines the cube cut at a certain position + long halfRed = bottomRed + Top(cube, direction, position, momentsRed); + long halfGreen = bottomGreen + Top(cube, direction, position, momentsGreen); + long halfBlue = bottomBlue + Top(cube, direction, position, momentsBlue); + long halfWeight = bottomWeight + Top(cube, direction, position, weights); - // the cube cannot be cut at bottom (this would lead to empty cube) - if (halfWeight != 0) { - float halfDistance = (float)halfRed * halfRed + (float)halfGreen * halfGreen + (float)halfBlue * halfBlue; - float temp = halfDistance / halfWeight; + // the cube cannot be cut at bottom (this would lead to empty cube) + if (halfWeight != 0) + { + float halfDistance = (float) halfRed * halfRed + (float) halfGreen * halfGreen + (float) halfBlue * halfBlue; + float temp = halfDistance / halfWeight; - halfRed = wholeRed - halfRed; - halfGreen = wholeGreen - halfGreen; - halfBlue = wholeBlue - halfBlue; - halfWeight = wholeWeight - halfWeight; + halfRed = wholeRed - halfRed; + halfGreen = wholeGreen - halfGreen; + halfBlue = wholeBlue - halfBlue; + halfWeight = wholeWeight - halfWeight; - if (halfWeight != 0) { - halfDistance = (float)halfRed * halfRed + (float)halfGreen * halfGreen + (float)halfBlue * halfBlue; - temp += halfDistance / halfWeight; + if (halfWeight != 0) + { + halfDistance = (float) halfRed * halfRed + (float) halfGreen * halfGreen + (float) halfBlue * halfBlue; + temp += halfDistance / halfWeight; - if (temp > result) { - result = temp; - cut[0] = position; - } - } - } - } + if (temp > result) + { + result = temp; + cut[0] = position; + } + } + } + } - return result; - } + return result; + } - /// - /// Cuts a cube with another one. - /// - private bool Cut(WuColorCube first, WuColorCube second) { - int direction; + /// + /// Cuts a cube with another one. + /// + private bool Cut(WuColorCube first, WuColorCube second) + { + int direction; - int[] cutRed = { 0 }; - int[] cutGreen = { 0 }; - int[] cutBlue = { 0 }; + int[] cutRed = + { + 0 + }; + int[] cutGreen = + { + 0 + }; + int[] cutBlue = + { + 0 + }; - long wholeRed = Volume(first, momentsRed); - long wholeGreen = Volume(first, momentsGreen); - long wholeBlue = Volume(first, momentsBlue); - long wholeWeight = Volume(first, weights); + long wholeRed = Volume(first, momentsRed); + long wholeGreen = Volume(first, momentsGreen); + long wholeBlue = Volume(first, momentsBlue); + long wholeWeight = Volume(first, weights); - float maxRed = Maximize(first, RED, first.RedMinimum + 1, first.RedMaximum, cutRed, wholeRed, wholeGreen, wholeBlue, wholeWeight); - float maxGreen = Maximize(first, GREEN, first.GreenMinimum + 1, first.GreenMaximum, cutGreen, wholeRed, wholeGreen, wholeBlue, wholeWeight); - float maxBlue = Maximize(first, BLUE, first.BlueMinimum + 1, first.BlueMaximum, cutBlue, wholeRed, wholeGreen, wholeBlue, wholeWeight); + float maxRed = Maximize(first, RED, first.RedMinimum + 1, first.RedMaximum, cutRed, wholeRed, wholeGreen, wholeBlue, wholeWeight); + float maxGreen = Maximize(first, GREEN, first.GreenMinimum + 1, first.GreenMaximum, cutGreen, wholeRed, wholeGreen, wholeBlue, wholeWeight); + float maxBlue = Maximize(first, BLUE, first.BlueMinimum + 1, first.BlueMaximum, cutBlue, wholeRed, wholeGreen, wholeBlue, wholeWeight); - if ((maxRed >= maxGreen) && (maxRed >= maxBlue)) { - direction = RED; + if ((maxRed >= maxGreen) && (maxRed >= maxBlue)) + { + direction = RED; - // cannot split empty cube - if (cutRed[0] < 0) return false; - } else { - if ((maxGreen >= maxRed) && (maxGreen >= maxBlue)) { - direction = GREEN; - } else { - direction = BLUE; - } - } + // cannot split empty cube + if (cutRed[0] < 0) return false; + } + else + { + if ((maxGreen >= maxRed) && (maxGreen >= maxBlue)) + { + direction = GREEN; + } + else + { + direction = BLUE; + } + } - second.RedMaximum = first.RedMaximum; - second.GreenMaximum = first.GreenMaximum; - second.BlueMaximum = first.BlueMaximum; + second.RedMaximum = first.RedMaximum; + second.GreenMaximum = first.GreenMaximum; + second.BlueMaximum = first.BlueMaximum; - // cuts in a certain direction - switch (direction) { - case RED: - second.RedMinimum = first.RedMaximum = cutRed[0]; - second.GreenMinimum = first.GreenMinimum; - second.BlueMinimum = first.BlueMinimum; - break; + // cuts in a certain direction + switch (direction) + { + case RED: + second.RedMinimum = first.RedMaximum = cutRed[0]; + second.GreenMinimum = first.GreenMinimum; + second.BlueMinimum = first.BlueMinimum; + break; - case GREEN: - second.GreenMinimum = first.GreenMaximum = cutGreen[0]; - second.RedMinimum = first.RedMinimum; - second.BlueMinimum = first.BlueMinimum; - break; + case GREEN: + second.GreenMinimum = first.GreenMaximum = cutGreen[0]; + second.RedMinimum = first.RedMinimum; + second.BlueMinimum = first.BlueMinimum; + break; - case BLUE: - second.BlueMinimum = first.BlueMaximum = cutBlue[0]; - second.RedMinimum = first.RedMinimum; - second.GreenMinimum = first.GreenMinimum; - break; - } + case BLUE: + second.BlueMinimum = first.BlueMaximum = cutBlue[0]; + second.RedMinimum = first.RedMinimum; + second.GreenMinimum = first.GreenMinimum; + break; + } - // determines the volumes after cut - first.Volume = (first.RedMaximum - first.RedMinimum) * (first.GreenMaximum - first.GreenMinimum) * (first.BlueMaximum - first.BlueMinimum); - second.Volume = (second.RedMaximum - second.RedMinimum) * (second.GreenMaximum - second.GreenMinimum) * (second.BlueMaximum - second.BlueMinimum); + // determines the volumes after cut + first.Volume = (first.RedMaximum - first.RedMinimum) * (first.GreenMaximum - first.GreenMinimum) * (first.BlueMaximum - first.BlueMinimum); + second.Volume = (second.RedMaximum - second.RedMinimum) * (second.GreenMaximum - second.GreenMinimum) * (second.BlueMaximum - second.BlueMinimum); - // the cut was successfull - return true; - } + // the cut was successfull + return true; + } - /// - /// Marks all the tags with a given label. - /// - private void Mark(WuColorCube cube, int label, byte[] tag) { - for (int redIndex = cube.RedMinimum + 1; redIndex <= cube.RedMaximum; ++redIndex) { - for (int greenIndex = cube.GreenMinimum + 1; greenIndex <= cube.GreenMaximum; ++greenIndex) { - for (int blueIndex = cube.BlueMinimum + 1; blueIndex <= cube.BlueMaximum; ++blueIndex) { - tag[(redIndex << 10) + (redIndex << 6) + redIndex + (greenIndex << 5) + greenIndex + blueIndex] = (byte)label; - } - } - } - } - } + /// + /// Marks all the tags with a given label. + /// + private void Mark(WuColorCube cube, int label, byte[] tag) + { + for (int redIndex = cube.RedMinimum + 1; redIndex <= cube.RedMaximum; ++redIndex) + { + for (int greenIndex = cube.GreenMinimum + 1; greenIndex <= cube.GreenMaximum; ++greenIndex) + { + for (int blueIndex = cube.BlueMinimum + 1; blueIndex <= cube.BlueMaximum; ++blueIndex) + { + tag[(redIndex << 10) + (redIndex << 6) + redIndex + (greenIndex << 5) + greenIndex + blueIndex] = (byte) label; + } + } + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/RegistryKeyExtensions.cs b/src/GreenshotPlugin/Core/RegistryKeyExtensions.cs index bfdb63e10..383c55e67 100644 --- a/src/GreenshotPlugin/Core/RegistryKeyExtensions.cs +++ b/src/GreenshotPlugin/Core/RegistryKeyExtensions.cs @@ -50,22 +50,26 @@ namespace GreenshotPlugin.Core if (key != null) { - result = (string)key.GetValue(value); + result = (string) key.GetValue(value); } + if (string.IsNullOrEmpty(result)) { result = defaultValue; } + return result; } + using var registryKey64 = RegistryKey.OpenBaseKey(registryHive, RegistryView.Registry64); // Logic for 64 bit Windows, is trying the key which is 64 bit using (var key = registryKey64.OpenSubKey($@"SOFTWARE\{keyName}", false)) { if (key != null) { - result = (string)key.GetValue(value); + result = (string) key.GetValue(value); } + if (!string.IsNullOrEmpty(result)) return result; } @@ -74,7 +78,7 @@ namespace GreenshotPlugin.Core { if (key != null) { - result = (string)key.GetValue(value); + result = (string) key.GetValue(value); } } @@ -82,6 +86,7 @@ namespace GreenshotPlugin.Core { result = defaultValue; } + return result; } } diff --git a/src/GreenshotPlugin/Core/SimpleServiceProvider.cs b/src/GreenshotPlugin/Core/SimpleServiceProvider.cs index 9ffd9d590..fc197367d 100644 --- a/src/GreenshotPlugin/Core/SimpleServiceProvider.cs +++ b/src/GreenshotPlugin/Core/SimpleServiceProvider.cs @@ -21,6 +21,7 @@ namespace GreenshotPlugin.Core { yield break; } + foreach (TService result in results) { yield return result; @@ -47,6 +48,7 @@ namespace GreenshotPlugin.Core { continue; } + currentServices.Add(service); } } @@ -56,4 +58,4 @@ namespace GreenshotPlugin.Core AddService(services.AsEnumerable()); } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/StringExtensions.cs b/src/GreenshotPlugin/Core/StringExtensions.cs index cd957c543..d82f51e14 100644 --- a/src/GreenshotPlugin/Core/StringExtensions.cs +++ b/src/GreenshotPlugin/Core/StringExtensions.cs @@ -27,75 +27,90 @@ using log4net; using System.Text.RegularExpressions; using System.Collections.Generic; -namespace GreenshotPlugin.Core { - public static class StringExtensions { - private static readonly ILog LOG = LogManager.GetLogger(typeof(StringExtensions)); - private const string RGBIV = "dlgjowejgogkklwj"; - private const string KEY = "lsjvkwhvwujkagfauguwcsjgu2wueuff"; +namespace GreenshotPlugin.Core +{ + public static class StringExtensions + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(StringExtensions)); + private const string RGBIV = "dlgjowejgogkklwj"; + private const string KEY = "lsjvkwhvwujkagfauguwcsjgu2wueuff"; - /// - /// Format a string with the specified object - /// - /// String with formatting, like {name} - /// Object used for the formatting - /// Formatted string - public static string FormatWith(this string format, object source) { - return FormatWith(format, null, source); - } + /// + /// Format a string with the specified object + /// + /// String with formatting, like {name} + /// Object used for the formatting + /// Formatted string + public static string FormatWith(this string format, object source) + { + return FormatWith(format, null, source); + } - /// - /// Format the string "format" with the source - /// - /// - /// - /// object with properties, if a property has the type IDictionary string,string it can used these parameters too - /// Formatted string - public static string FormatWith(this string format, IFormatProvider provider, object source) { - if (format == null) { - throw new ArgumentNullException(nameof(format)); - } + /// + /// Format the string "format" with the source + /// + /// + /// + /// object with properties, if a property has the type IDictionary string,string it can used these parameters too + /// Formatted string + public static string FormatWith(this string format, IFormatProvider provider, object source) + { + if (format == null) + { + throw new ArgumentNullException(nameof(format)); + } - IDictionary properties = new Dictionary(); - foreach(var propertyInfo in source.GetType().GetProperties()) { - if (propertyInfo.CanRead && propertyInfo.CanWrite) { - object value = propertyInfo.GetValue(source, null); - if (propertyInfo.PropertyType != typeof(IDictionary)) { - properties.Add(propertyInfo.Name, value); - } else { - IDictionary dictionary = (IDictionary)value; - foreach (var propertyKey in dictionary.Keys) { - properties.Add(propertyKey, dictionary[propertyKey]); - } - } - } - } + IDictionary properties = new Dictionary(); + foreach (var propertyInfo in source.GetType().GetProperties()) + { + if (propertyInfo.CanRead && propertyInfo.CanWrite) + { + object value = propertyInfo.GetValue(source, null); + if (propertyInfo.PropertyType != typeof(IDictionary)) + { + properties.Add(propertyInfo.Name, value); + } + else + { + IDictionary dictionary = (IDictionary) value; + foreach (var propertyKey in dictionary.Keys) + { + properties.Add(propertyKey, dictionary[propertyKey]); + } + } + } + } - Regex r = new Regex(@"(?\{)+(?[\w\.\[\]]+)(?:[^}]+)?(?\})+", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + Regex r = new Regex(@"(?\{)+(?[\w\.\[\]]+)(?:[^}]+)?(?\})+", + RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); - List values = new List(); - string rewrittenFormat = r.Replace(format, delegate(Match m) { - Group startGroup = m.Groups["start"]; - Group propertyGroup = m.Groups["property"]; - Group formatGroup = m.Groups["format"]; - Group endGroup = m.Groups["end"]; + List values = new List(); + string rewrittenFormat = r.Replace(format, delegate(Match m) + { + Group startGroup = m.Groups["start"]; + Group propertyGroup = m.Groups["property"]; + Group formatGroup = m.Groups["format"]; + Group endGroup = m.Groups["end"]; values.Add(properties.TryGetValue(propertyGroup.Value, out var value) ? value : source); - return new string('{', startGroup.Captures.Count) + (values.Count - 1) + formatGroup.Value + new string('}', endGroup.Captures.Count); - }); + return new string('{', startGroup.Captures.Count) + (values.Count - 1) + formatGroup.Value + new string('}', endGroup.Captures.Count); + }); - return string.Format(provider, rewrittenFormat, values.ToArray()); - } + return string.Format(provider, rewrittenFormat, values.ToArray()); + } - /// - /// A simply rijndael aes encryption, can be used to store passwords - /// - /// the string to call upon - /// an encryped string in base64 form - public static string Encrypt(this string clearText) { - string returnValue = clearText; - try { - byte[] clearTextBytes = Encoding.ASCII.GetBytes(clearText); - SymmetricAlgorithm rijn = SymmetricAlgorithm.Create(); + /// + /// A simply rijndael aes encryption, can be used to store passwords + /// + /// the string to call upon + /// an encryped string in base64 form + public static string Encrypt(this string clearText) + { + string returnValue = clearText; + try + { + byte[] clearTextBytes = Encoding.ASCII.GetBytes(clearText); + SymmetricAlgorithm rijn = SymmetricAlgorithm.Create(); using MemoryStream ms = new MemoryStream(); byte[] rgbIV = Encoding.ASCII.GetBytes(RGBIV); @@ -105,25 +120,30 @@ namespace GreenshotPlugin.Core { cs.FlushFinalBlock(); returnValue = Convert.ToBase64String(ms.ToArray()); - } catch (Exception ex) { - LOG.ErrorFormat("Error encrypting, error: {0}", ex.Message); - } - return returnValue; - } + } + catch (Exception ex) + { + LOG.ErrorFormat("Error encrypting, error: {0}", ex.Message); + } - /// - /// A simply rijndael aes decryption, can be used to store passwords - /// - /// a base64 encoded rijndael encrypted string - /// Decrypeted text - public static string Decrypt(this string encryptedText) { - string returnValue = encryptedText; - try { - byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText); + return returnValue; + } + + /// + /// A simply rijndael aes decryption, can be used to store passwords + /// + /// a base64 encoded rijndael encrypted string + /// Decrypeted text + public static string Decrypt(this string encryptedText) + { + string returnValue = encryptedText; + try + { + byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText); using MemoryStream ms = new MemoryStream(); SymmetricAlgorithm rijn = SymmetricAlgorithm.Create(); - - + + byte[] rgbIV = Encoding.ASCII.GetBytes(RGBIV); byte[] key = Encoding.ASCII.GetBytes(KEY); @@ -131,11 +151,13 @@ namespace GreenshotPlugin.Core { cs.Write(encryptedTextBytes, 0, encryptedTextBytes.Length); cs.FlushFinalBlock(); returnValue = Encoding.ASCII.GetString(ms.ToArray()); - } catch (Exception ex) { - LOG.ErrorFormat("Error decrypting {0}, error: {1}", encryptedText, ex.Message); - } + } + catch (Exception ex) + { + LOG.ErrorFormat("Error decrypting {0}, error: {1}", encryptedText, ex.Message); + } - return returnValue; - } + return returnValue; + } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/SvgImage.cs b/src/GreenshotPlugin/Core/SvgImage.cs index d777d30ad..7924c3480 100644 --- a/src/GreenshotPlugin/Core/SvgImage.cs +++ b/src/GreenshotPlugin/Core/SvgImage.cs @@ -26,92 +26,92 @@ using Svg; namespace GreenshotPlugin.Core { - /// - /// Create an image look like of the SVG - /// - public sealed class SvgImage : IImage - { - private readonly SvgDocument _svgDocument; + /// + /// Create an image look like of the SVG + /// + public sealed class SvgImage : IImage + { + private readonly SvgDocument _svgDocument; - private Image _imageClone; + private Image _imageClone; - /// - /// Factory to create via a stream - /// - /// Stream - /// IImage - public static IImage FromStream(Stream stream) - { - return new SvgImage(stream); - } + /// + /// Factory to create via a stream + /// + /// Stream + /// IImage + public static IImage FromStream(Stream stream) + { + return new SvgImage(stream); + } - /// - /// Default constructor - /// - /// - public SvgImage(Stream stream) - { - _svgDocument = SvgDocument.Open(stream); - Height = (int)_svgDocument.ViewBox.Height; - Width = (int)_svgDocument.ViewBox.Width; - } + /// + /// Default constructor + /// + /// + public SvgImage(Stream stream) + { + _svgDocument = SvgDocument.Open(stream); + Height = (int) _svgDocument.ViewBox.Height; + Width = (int) _svgDocument.ViewBox.Width; + } - /// - /// Height of the image, can be set to change - /// - public int Height { get; set; } + /// + /// Height of the image, can be set to change + /// + public int Height { get; set; } - /// - /// Width of the image, can be set to change. - /// - public int Width { get; set; } + /// + /// Width of the image, can be set to change. + /// + public int Width { get; set; } - /// - /// Size of the image - /// - public Size Size => new Size(Width, Height); + /// + /// Size of the image + /// + public Size Size => new Size(Width, Height); - /// - /// Pixelformat of the underlying image - /// - public PixelFormat PixelFormat => Image.PixelFormat; + /// + /// Pixelformat of the underlying image + /// + public PixelFormat PixelFormat => Image.PixelFormat; - /// - /// Horizontal resolution of the underlying image - /// - public float HorizontalResolution => Image.HorizontalResolution; + /// + /// Horizontal resolution of the underlying image + /// + public float HorizontalResolution => Image.HorizontalResolution; - /// - /// Vertical resolution of the underlying image - /// - public float VerticalResolution => Image.VerticalResolution; + /// + /// Vertical resolution of the underlying image + /// + public float VerticalResolution => Image.VerticalResolution; - /// - /// Underlying image, or an on demand rendered version with different attributes as the original - /// - public Image Image - { - get - { - if (_imageClone?.Height == Height && _imageClone?.Width == Width) - { - return _imageClone; - } - // Calculate new image clone - _imageClone?.Dispose(); - _imageClone = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent, 96, 96); - _svgDocument.Draw((Bitmap)_imageClone); - return _imageClone; + /// + /// Underlying image, or an on demand rendered version with different attributes as the original + /// + public Image Image + { + get + { + if (_imageClone?.Height == Height && _imageClone?.Width == Width) + { + return _imageClone; + } - } - } + // Calculate new image clone + _imageClone?.Dispose(); + _imageClone = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent, 96, 96); + _svgDocument.Draw((Bitmap) _imageClone); + return _imageClone; + } + } - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - _imageClone?.Dispose(); - } - } -} + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + _imageClone?.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/WindowCapture.cs b/src/GreenshotPlugin/Core/WindowCapture.cs index 828851444..fafd88a18 100644 --- a/src/GreenshotPlugin/Core/WindowCapture.cs +++ b/src/GreenshotPlugin/Core/WindowCapture.cs @@ -32,76 +32,86 @@ using GreenshotPlugin.IniFile; using GreenshotPlugin.Interfaces; using GreenshotPlugin.UnmanagedHelpers.Structs; -namespace GreenshotPlugin.Core { +namespace GreenshotPlugin.Core +{ /// - /// The Window Capture code - /// - public static class WindowCapture { - private static readonly ILog Log = LogManager.GetLogger(typeof(WindowCapture)); - private static readonly CoreConfiguration Configuration = IniConfig.GetIniSection(); - - /// - /// Used to cleanup the unmanaged resource in the iconInfo for the CaptureCursor method - /// - /// - /// - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); + /// The Window Capture code + /// + public static class WindowCapture + { + private static readonly ILog Log = LogManager.GetLogger(typeof(WindowCapture)); + private static readonly CoreConfiguration Configuration = IniConfig.GetIniSection(); /// - /// Get the bounds of all screens combined. - /// - /// A Rectangle of the bounds of the entire display area. - public static Rectangle GetScreenBounds() { - int left = 0, top = 0, bottom = 0, right = 0; - foreach (Screen screen in Screen.AllScreens) { - left = Math.Min(left, screen.Bounds.X); - top = Math.Min(top, screen.Bounds.Y); - int screenAbsRight = screen.Bounds.X + screen.Bounds.Width; - int screenAbsBottom = screen.Bounds.Y + screen.Bounds.Height; - right = Math.Max(right, screenAbsRight); - bottom = Math.Max(bottom, screenAbsBottom); - } - return new Rectangle(left, top, (right + Math.Abs(left)), (bottom + Math.Abs(top))); - } + /// Used to cleanup the unmanaged resource in the iconInfo for the CaptureCursor method + /// + /// + /// + [DllImport("gdi32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteObject(IntPtr hObject); - /// - /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. This implementation - /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. - /// - /// - /// Point with cursor location, relative to the top left corner of the monitor setup (which itself might actually not be on any screen) - /// - public static Point GetCursorLocationRelativeToScreenBounds() { - return GetLocationRelativeToScreenBounds(User32.GetCursorLocation()); - } + /// + /// Get the bounds of all screens combined. + /// + /// A Rectangle of the bounds of the entire display area. + public static Rectangle GetScreenBounds() + { + int left = 0, top = 0, bottom = 0, right = 0; + foreach (Screen screen in Screen.AllScreens) + { + left = Math.Min(left, screen.Bounds.X); + top = Math.Min(top, screen.Bounds.Y); + int screenAbsRight = screen.Bounds.X + screen.Bounds.Width; + int screenAbsBottom = screen.Bounds.Y + screen.Bounds.Height; + right = Math.Max(right, screenAbsRight); + bottom = Math.Max(bottom, screenAbsBottom); + } - /// - /// Converts locationRelativeToScreenOrigin to be relative to top left corner of all screen bounds, which might - /// be different in multi-screen setups. This implementation - /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. - /// - /// - /// Point - public static Point GetLocationRelativeToScreenBounds(Point locationRelativeToScreenOrigin) { - Point ret = locationRelativeToScreenOrigin; - Rectangle bounds = GetScreenBounds(); - ret.Offset(-bounds.X, -bounds.Y); - return ret; - } + return new Rectangle(left, top, (right + Math.Abs(left)), (bottom + Math.Abs(top))); + } - /// - /// This method will capture the current Cursor by using User32 Code - /// - /// A Capture Object with the Mouse Cursor information in it. - public static ICapture CaptureCursor(ICapture capture) { - Log.Debug("Capturing the mouse cursor."); - if (capture == null) { - capture = new Capture(); - } - var cursorInfo = new CursorInfo(); - cursorInfo.cbSize = Marshal.SizeOf(cursorInfo); + /// + /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. This implementation + /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. + /// + /// + /// Point with cursor location, relative to the top left corner of the monitor setup (which itself might actually not be on any screen) + /// + public static Point GetCursorLocationRelativeToScreenBounds() + { + return GetLocationRelativeToScreenBounds(User32.GetCursorLocation()); + } + + /// + /// Converts locationRelativeToScreenOrigin to be relative to top left corner of all screen bounds, which might + /// be different in multi-screen setups. This implementation + /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. + /// + /// + /// Point + public static Point GetLocationRelativeToScreenBounds(Point locationRelativeToScreenOrigin) + { + Point ret = locationRelativeToScreenOrigin; + Rectangle bounds = GetScreenBounds(); + ret.Offset(-bounds.X, -bounds.Y); + return ret; + } + + /// + /// This method will capture the current Cursor by using User32 Code + /// + /// A Capture Object with the Mouse Cursor information in it. + public static ICapture CaptureCursor(ICapture capture) + { + Log.Debug("Capturing the mouse cursor."); + if (capture == null) + { + capture = new Capture(); + } + + var cursorInfo = new CursorInfo(); + cursorInfo.cbSize = Marshal.SizeOf(cursorInfo); if (!User32.GetCursorInfo(out cursorInfo)) return capture; if (cursorInfo.flags != User32.CURSOR_SHOWING) return capture; @@ -115,171 +125,212 @@ namespace GreenshotPlugin.Core { // Set the location capture.CursorLocation = new Point(x, y); - using (Icon icon = Icon.FromHandle(safeIcon.DangerousGetHandle())) { + using (Icon icon = Icon.FromHandle(safeIcon.DangerousGetHandle())) + { capture.Cursor = icon; } - if (iconInfo.hbmMask != IntPtr.Zero) { + if (iconInfo.hbmMask != IntPtr.Zero) + { DeleteObject(iconInfo.hbmMask); } - if (iconInfo.hbmColor != IntPtr.Zero) { + + if (iconInfo.hbmColor != IntPtr.Zero) + { DeleteObject(iconInfo.hbmColor); } + return capture; - } + } - /// - /// This method will call the CaptureRectangle with the screenbounds, therefor Capturing the whole screen. - /// - /// A Capture Object with the Screen as an Image - public static ICapture CaptureScreen(ICapture capture) { - if (capture == null) { - capture = new Capture(); - } - return CaptureRectangle(capture, capture.ScreenBounds); - } + /// + /// This method will call the CaptureRectangle with the screenbounds, therefor Capturing the whole screen. + /// + /// A Capture Object with the Screen as an Image + public static ICapture CaptureScreen(ICapture capture) + { + if (capture == null) + { + capture = new Capture(); + } - /// - /// Helper method to create an exception that might explain what is wrong while capturing - /// - /// string with current method - /// Rectangle of what we want to capture - /// - private static Exception CreateCaptureException(string method, Rectangle captureBounds) { - Exception exceptionToThrow = User32.CreateWin32Exception(method); - if (!captureBounds.IsEmpty) { - exceptionToThrow.Data.Add("Height", captureBounds.Height); - exceptionToThrow.Data.Add("Width", captureBounds.Width); - } - return exceptionToThrow; - } + return CaptureRectangle(capture, capture.ScreenBounds); + } - /// - /// Helper method to check if it is allowed to capture the process using DWM - /// - /// Process owning the window - /// true if it's allowed - public static bool IsDwmAllowed(Process process) { + /// + /// Helper method to create an exception that might explain what is wrong while capturing + /// + /// string with current method + /// Rectangle of what we want to capture + /// + private static Exception CreateCaptureException(string method, Rectangle captureBounds) + { + Exception exceptionToThrow = User32.CreateWin32Exception(method); + if (!captureBounds.IsEmpty) + { + exceptionToThrow.Data.Add("Height", captureBounds.Height); + exceptionToThrow.Data.Add("Width", captureBounds.Width); + } + + return exceptionToThrow; + } + + /// + /// Helper method to check if it is allowed to capture the process using DWM + /// + /// Process owning the window + /// true if it's allowed + public static bool IsDwmAllowed(Process process) + { if (process == null) return true; if (Configuration.NoDWMCaptureForProduct == null || Configuration.NoDWMCaptureForProduct.Count <= 0) return true; - try { + try + { string productName = process.MainModule?.FileVersionInfo.ProductName; - if (productName != null && Configuration.NoDWMCaptureForProduct.Contains(productName.ToLower())) { + if (productName != null && Configuration.NoDWMCaptureForProduct.Contains(productName.ToLower())) + { return false; } - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Warn(ex.Message); } - return true; - } - /// - /// Helper method to check if it is allowed to capture the process using GDI - /// - /// Process owning the window - /// true if it's allowed - public static bool IsGdiAllowed(Process process) { + return true; + } + + /// + /// Helper method to check if it is allowed to capture the process using GDI + /// + /// Process owning the window + /// true if it's allowed + public static bool IsGdiAllowed(Process process) + { if (process == null) return true; if (Configuration.NoGDICaptureForProduct == null || Configuration.NoGDICaptureForProduct.Count <= 0) return true; - try { + try + { string productName = process.MainModule?.FileVersionInfo.ProductName; - if (productName != null && Configuration.NoGDICaptureForProduct.Contains(productName.ToLower())) { + if (productName != null && Configuration.NoGDICaptureForProduct.Contains(productName.ToLower())) + { return false; } - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Warn(ex.Message); } + return true; - } + } - /// - /// This method will use User32 code to capture the specified captureBounds from the screen - /// - /// ICapture where the captured Bitmap will be stored - /// Rectangle with the bounds to capture - /// A Capture Object with a part of the Screen as an Image - public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds) { - if (capture == null) { - capture = new Capture(); - } - Image capturedImage = null; - // If the CaptureHandler has a handle use this, otherwise use the CaptureRectangle here - if (CaptureHandler.CaptureScreenRectangle != null) { - try { - capturedImage = CaptureHandler.CaptureScreenRectangle(captureBounds); - } - catch - { - // ignored - } - } - // If no capture, use the normal screen capture - if (capturedImage == null) { - capturedImage = CaptureRectangle(captureBounds); - } - capture.Image = capturedImage; - capture.Location = captureBounds.Location; - return capture.Image == null ? null : capture; - } + /// + /// This method will use User32 code to capture the specified captureBounds from the screen + /// + /// ICapture where the captured Bitmap will be stored + /// Rectangle with the bounds to capture + /// A Capture Object with a part of the Screen as an Image + public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds) + { + if (capture == null) + { + capture = new Capture(); + } - /// - /// This method will use User32 code to capture the specified captureBounds from the screen - /// - /// ICapture where the captured Bitmap will be stored - /// Rectangle with the bounds to capture - /// A Capture Object with a part of the Screen as an Image - public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, Rectangle captureBounds) { - if (capture == null) { - capture = new Capture(); - } - capture.Image = CaptureRectangle(captureBounds); - capture.Location = captureBounds.Location; - return capture.Image == null ? null : capture; - } + Image capturedImage = null; + // If the CaptureHandler has a handle use this, otherwise use the CaptureRectangle here + if (CaptureHandler.CaptureScreenRectangle != null) + { + try + { + capturedImage = CaptureHandler.CaptureScreenRectangle(captureBounds); + } + catch + { + // ignored + } + } - /// - /// This method will use User32 code to capture the specified captureBounds from the screen - /// - /// Rectangle with the bounds to capture - /// Bitmap which is captured from the screen at the location specified by the captureBounds - public static Bitmap CaptureRectangle(Rectangle captureBounds) { - Bitmap returnBitmap = null; - if (captureBounds.Height <= 0 || captureBounds.Width <= 0) { - Log.Warn("Nothing to capture, ignoring!"); - return null; - } - Log.Debug("CaptureRectangle Called!"); + // If no capture, use the normal screen capture + if (capturedImage == null) + { + capturedImage = CaptureRectangle(captureBounds); + } - // .NET GDI+ Solution, according to some post this has a GDI+ leak... - // See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen - // Bitmap capturedBitmap = new Bitmap(captureBounds.Width, captureBounds.Height); - // using (Graphics graphics = Graphics.FromImage(capturedBitmap)) { - // graphics.CopyFromScreen(captureBounds.Location, Point.Empty, captureBounds.Size, CopyPixelOperation.CaptureBlt); - // } - // capture.Image = capturedBitmap; - // capture.Location = captureBounds.Location; + capture.Image = capturedImage; + capture.Location = captureBounds.Location; + return capture.Image == null ? null : capture; + } - using (var desktopDcHandle = SafeWindowDcHandle.FromDesktop()) { - if (desktopDcHandle.IsInvalid) { - // Get Exception before the error is lost - Exception exceptionToThrow = CreateCaptureException("desktopDCHandle", captureBounds); - // throw exception - throw exceptionToThrow; - } + /// + /// This method will use User32 code to capture the specified captureBounds from the screen + /// + /// ICapture where the captured Bitmap will be stored + /// Rectangle with the bounds to capture + /// A Capture Object with a part of the Screen as an Image + public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, Rectangle captureBounds) + { + if (capture == null) + { + capture = new Capture(); + } - // create a device context we can copy to + capture.Image = CaptureRectangle(captureBounds); + capture.Location = captureBounds.Location; + return capture.Image == null ? null : capture; + } + + /// + /// This method will use User32 code to capture the specified captureBounds from the screen + /// + /// Rectangle with the bounds to capture + /// Bitmap which is captured from the screen at the location specified by the captureBounds + public static Bitmap CaptureRectangle(Rectangle captureBounds) + { + Bitmap returnBitmap = null; + if (captureBounds.Height <= 0 || captureBounds.Width <= 0) + { + Log.Warn("Nothing to capture, ignoring!"); + return null; + } + + Log.Debug("CaptureRectangle Called!"); + + // .NET GDI+ Solution, according to some post this has a GDI+ leak... + // See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen + // Bitmap capturedBitmap = new Bitmap(captureBounds.Width, captureBounds.Height); + // using (Graphics graphics = Graphics.FromImage(capturedBitmap)) { + // graphics.CopyFromScreen(captureBounds.Location, Point.Empty, captureBounds.Size, CopyPixelOperation.CaptureBlt); + // } + // capture.Image = capturedBitmap; + // capture.Location = captureBounds.Location; + + using (var desktopDcHandle = SafeWindowDcHandle.FromDesktop()) + { + if (desktopDcHandle.IsInvalid) + { + // Get Exception before the error is lost + Exception exceptionToThrow = CreateCaptureException("desktopDCHandle", captureBounds); + // throw exception + throw exceptionToThrow; + } + + // create a device context we can copy to using SafeCompatibleDCHandle safeCompatibleDcHandle = GDI32.CreateCompatibleDC(desktopDcHandle); // Check if the device context is there, if not throw an error with as much info as possible! - if (safeCompatibleDcHandle.IsInvalid) { + if (safeCompatibleDcHandle.IsInvalid) + { // Get Exception before the error is lost Exception exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds); // throw exception throw exceptionToThrow; } + // Create BITMAPINFOHEADER for CreateDIBSection BITMAPINFOHEADER bmi = new BITMAPINFOHEADER(captureBounds.Width, captureBounds.Height, 24); @@ -288,7 +339,8 @@ namespace GreenshotPlugin.Core { // create a bitmap we can copy it to, using GetDeviceCaps to get the width/height using SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDcHandle, ref bmi, BITMAPINFOHEADER.DIB_RGB_COLORS, out _, IntPtr.Zero, 0); - if (safeDibSectionHandle.IsInvalid) { + if (safeDibSectionHandle.IsInvalid) + { // Get Exception before the error is lost var exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds); exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32()); @@ -297,73 +349,96 @@ namespace GreenshotPlugin.Core { // Throw so people can report the problem throw exceptionToThrow; } + // select the bitmap object and store the old handle - using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle)) { + using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle)) + { // bitblt over (make copy) // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags - GDI32.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt); + GDI32.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y, + CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt); } // get a .NET image object for it // A suggestion for the "A generic error occurred in GDI+." E_FAIL/0�80004005 error is to re-try... bool success = false; ExternalException exception = null; - for (int i = 0; i < 3; i++) { - try { + for (int i = 0; i < 3; i++) + { + try + { // Collect all screens inside this capture List screensInsideCapture = new List(); - foreach (Screen screen in Screen.AllScreens) { - if (screen.Bounds.IntersectsWith(captureBounds)) { + foreach (Screen screen in Screen.AllScreens) + { + if (screen.Bounds.IntersectsWith(captureBounds)) + { screensInsideCapture.Add(screen); } } + // Check all all screens are of an equal size bool offscreenContent; - using (Region captureRegion = new Region(captureBounds)) { + using (Region captureRegion = new Region(captureBounds)) + { // Exclude every visible part - foreach (Screen screen in screensInsideCapture) { + foreach (Screen screen in screensInsideCapture) + { captureRegion.Exclude(screen.Bounds); } + // If the region is not empty, we have "offscreenContent" using Graphics screenGraphics = Graphics.FromHwnd(User32.GetDesktopWindow()); offscreenContent = !captureRegion.IsEmpty(screenGraphics); } + // Check if we need to have a transparent background, needed for offscreen content if (offscreenContent) { using Bitmap tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); // Create a new bitmap which has a transparent background - returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution); + returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, + tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution); // Content will be copied here using Graphics graphics = Graphics.FromImage(returnBitmap); // For all screens copy the content to the new bitmap - foreach (Screen screen in Screen.AllScreens) { + foreach (Screen screen in Screen.AllScreens) + { Rectangle screenBounds = screen.Bounds; // Make sure the bounds are offsetted to the capture bounds screenBounds.Offset(-captureBounds.X, -captureBounds.Y); graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel); } - } else { + } + else + { // All screens, which are inside the capture, are of equal size // assign image to Capture, the image will be disposed there.. returnBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); } + // We got through the capture without exception success = true; break; - } catch (ExternalException ee) { + } + catch (ExternalException ee) + { Log.Warn("Problem getting bitmap at try " + i + " : ", ee); exception = ee; } } - if (!success) { + + if (!success) + { Log.Error("Still couldn't create Bitmap!"); - if (exception != null) { + if (exception != null) + { throw exception; } } } - return returnBitmap; - } - } -} + + return returnBitmap; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/WindowDetails.cs b/src/GreenshotPlugin/Core/WindowDetails.cs index 7c9a2b905..641c0db20 100644 --- a/src/GreenshotPlugin/Core/WindowDetails.cs +++ b/src/GreenshotPlugin/Core/WindowDetails.cs @@ -27,12 +27,17 @@ namespace GreenshotPlugin.Core /// /// Provides details about a Window returned by the enumeration /// - public class WindowDetails : IEquatable { + public class WindowDetails : IEquatable + { private const string AppWindowClass = "Windows.UI.Core.CoreWindow"; //Used for Windows 8(.1) private const string AppFrameWindowClass = "ApplicationFrameWindow"; // Windows 10 uses ApplicationFrameWindow private const string ApplauncherClass = "ImmersiveLauncher"; private const string GutterClass = "ImmersiveGutter"; - private static readonly IList IgnoreClasses = new List(new[] { "Progman", "Button", "Dwm" }); //"MS-SDIa" + + private static readonly IList IgnoreClasses = new List(new[] + { + "Progman", "Button", "Dwm" + }); //"MS-SDIa" private static readonly ILog Log = LogManager.GetLogger(typeof(WindowDetails)); private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); @@ -40,7 +45,8 @@ namespace GreenshotPlugin.Core private static readonly IList ExcludeProcessesFromFreeze = new List(); private static readonly IAppVisibility AppVisibility; - static WindowDetails() { + static WindowDetails() + { try { // Only try to instantiate when Windows 8 or later. @@ -55,13 +61,16 @@ namespace GreenshotPlugin.Core } } - public static void AddProcessToExcludeFromFreeze(string processName) { - if (!ExcludeProcessesFromFreeze.Contains(processName)) { + public static void AddProcessToExcludeFromFreeze(string processName) + { + if (!ExcludeProcessesFromFreeze.Contains(processName)) + { ExcludeProcessesFromFreeze.Add(processName); } } - internal static bool IsIgnoreHandle(IntPtr handle) { + internal static bool IsIgnoreHandle(IntPtr handle) + { return IgnoreHandles.Contains(handle); } @@ -85,8 +94,9 @@ namespace GreenshotPlugin.Core /// /// Check if this window belongs to a background app /// - public bool IsBackgroundWin10App => WindowsVersion.IsWindows10OrLater && AppFrameWindowClass.Equals(ClassName) && !Children.Any(window => string.Equals(window.ClassName, AppWindowClass)); - + public bool IsBackgroundWin10App => WindowsVersion.IsWindows10OrLater && AppFrameWindowClass.Equals(ClassName) && + !Children.Any(window => string.Equals(window.ClassName, AppWindowClass)); + /// /// Check if the window is the metro gutter (sizeable separator) /// @@ -108,11 +118,13 @@ namespace GreenshotPlugin.Core /// objects for the same Window will be equal. /// /// The Window Handle for this window - public override int GetHashCode() { + public override int GetHashCode() + { return Handle.ToInt32(); } - public override bool Equals(object right) { + public override bool Equals(object right) + { return Equals(right as WindowDetails); } @@ -121,18 +133,23 @@ namespace GreenshotPlugin.Core /// /// /// - public bool Equals(WindowDetails other) { - if (other is null) { + public bool Equals(WindowDetails other) + { + if (other is null) + { return false; } - if (ReferenceEquals(this, other)) { + if (ReferenceEquals(this, other)) + { return true; } - if (GetType() != other.GetType()){ + if (GetType() != other.GetType()) + { return false; } + return other.Handle == Handle; } @@ -144,26 +161,32 @@ namespace GreenshotPlugin.Core /// /// Freeze information updates /// - public void FreezeDetails() { + public void FreezeDetails() + { _frozen = true; } /// /// Make the information update again. /// - public void UnfreezeDetails() { + public void UnfreezeDetails() + { _frozen = false; } /// /// Get the file path to the exe for the process which owns this window /// - public string ProcessPath { - get { - if (Handle == IntPtr.Zero) { + public string ProcessPath + { + get + { + if (Handle == IntPtr.Zero) + { // not a valid window handle return string.Empty; } + // Get the process id User32.GetWindowThreadProcessId(Handle, out var processId); return Kernel32.GetProcessPath(processId); @@ -174,28 +197,40 @@ namespace GreenshotPlugin.Core /// /// Get the icon belonging to the process /// - public Image DisplayIcon { - get { + public Image DisplayIcon + { + get + { try { using var appIcon = GetAppIcon(Handle); - if (appIcon != null) { + if (appIcon != null) + { return appIcon.ToBitmap(); } - } catch (Exception ex) { + } + catch (Exception ex) + { Log.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); Log.Warn(ex); } - if (IsMetroApp) { + + if (IsMetroApp) + { // No method yet to get the metro icon return null; } - try { + + try + { return PluginUtils.GetCachedExeIcon(ProcessPath, 0); - } catch (Exception ex) { + } + catch (Exception ex) + { Log.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); Log.Warn(ex); } + return null; } } @@ -205,34 +240,48 @@ namespace GreenshotPlugin.Core /// /// /// - private static Icon GetAppIcon(IntPtr hWnd) { + private static Icon GetAppIcon(IntPtr hWnd) + { IntPtr iconSmall = IntPtr.Zero; IntPtr iconBig = new IntPtr(1); IntPtr iconSmall2 = new IntPtr(2); IntPtr iconHandle; - if (Conf.UseLargeIcons) { - iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); - if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hWnd, (int)ClassLongIndex.GCL_HICON); + if (Conf.UseLargeIcons) + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICON); } - } else { - iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconSmall2, IntPtr.Zero); } - if (iconHandle == IntPtr.Zero) { - iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconSmall, IntPtr.Zero); - } - if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hWnd, (int)ClassLongIndex.GCL_HICONSM); - } - if (iconHandle == IntPtr.Zero) { - iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); - } - if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hWnd, (int)ClassLongIndex.GCL_HICON); + else + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconSmall2, IntPtr.Zero); } - if (iconHandle == IntPtr.Zero) { + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconSmall, IntPtr.Zero); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICONSM); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICON); + } + + if (iconHandle == IntPtr.Zero) + { return null; } @@ -245,7 +294,8 @@ namespace GreenshotPlugin.Core /// Use this to make remove internal windows, like the mainform and the captureforms, invisible /// /// - public static void RegisterIgnoreHandle(IntPtr ignoreHandle) { + public static void RegisterIgnoreHandle(IntPtr ignoreHandle) + { IgnoreHandles.Add(ignoreHandle); } @@ -253,15 +303,20 @@ namespace GreenshotPlugin.Core /// Use this to remove the with RegisterIgnoreHandle registered handle /// /// - public static void UnregisterIgnoreHandle(IntPtr ignoreHandle) { + public static void UnregisterIgnoreHandle(IntPtr ignoreHandle) + { IgnoreHandles.Remove(ignoreHandle); } - public IList Children { - get { - if (_childWindows == null) { + public IList Children + { + get + { + if (_childWindows == null) + { GetChildren(); } + return _childWindows; } } @@ -269,43 +324,60 @@ namespace GreenshotPlugin.Core /// /// Retrieve the child with matching classname /// - public WindowDetails GetChild(string childClassname) { - foreach(var child in Children) { - if (childClassname.Equals(child.ClassName)) { + public WindowDetails GetChild(string childClassname) + { + foreach (var child in Children) + { + if (childClassname.Equals(child.ClassName)) + { return child; } } + return null; } - public IntPtr ParentHandle { - get { - if (_parentHandle == IntPtr.Zero) { + public IntPtr ParentHandle + { + get + { + if (_parentHandle == IntPtr.Zero) + { _parentHandle = User32.GetParent(Handle); _parent = null; } + return _parentHandle; } - set { - if (_parentHandle != value) { + set + { + if (_parentHandle != value) + { _parentHandle = value; _parent = null; } } } + /// /// Get the parent of the current window /// /// WindowDetails of the parent, or null if none - public WindowDetails GetParent() { - if (_parent == null) { - if (_parentHandle == IntPtr.Zero) { + public WindowDetails GetParent() + { + if (_parent == null) + { + if (_parentHandle == IntPtr.Zero) + { _parentHandle = User32.GetParent(Handle); } - if (_parentHandle != IntPtr.Zero) { + + if (_parentHandle != IntPtr.Zero) + { _parent = new WindowDetails(_parentHandle); } } + return _parent; } @@ -313,10 +385,13 @@ namespace GreenshotPlugin.Core /// Retrieve all the children, this only stores the children internally. /// One should normally use the getter "Children" /// - public IList GetChildren() { - if (_childWindows == null) { + public IList GetChildren() + { + if (_childWindows == null) + { return GetChildren(0); } + return _childWindows; } @@ -324,17 +399,22 @@ namespace GreenshotPlugin.Core /// Retrieve all the children, this only stores the children internally, use the "Children" property for the value /// /// Specify how many levels we go in - public IList GetChildren(int levelsToGo) { + public IList GetChildren(int levelsToGo) + { if (_childWindows != null) { return _childWindows; } + _childWindows = new WindowsEnumerator().GetWindows(Handle, null).Items; - foreach(var childWindow in _childWindows) { - if (levelsToGo > 0) { - childWindow.GetChildren(levelsToGo-1); + foreach (var childWindow in _childWindows) + { + if (levelsToGo > 0) + { + childWindow.GetChildren(levelsToGo - 1); } } + return _childWindows; } @@ -344,22 +424,28 @@ namespace GreenshotPlugin.Core public IntPtr Handle { get; } private string _text; + /// /// Gets the window's title (caption) /// - public string Text { + public string Text + { set => _text = value; - get { - if (_text == null) { + get + { + if (_text == null) + { var title = new StringBuilder(260, 260); User32.GetWindowText(Handle, title, title.Capacity); _text = title.ToString(); } + return _text; } } private string _className; + /// /// Gets the window's class name. /// @@ -368,18 +454,26 @@ namespace GreenshotPlugin.Core /// /// Gets/Sets whether the window is iconic (minimized) or not. /// - public bool Iconic { - get { - if (IsMetroApp) { + public bool Iconic + { + get + { + if (IsMetroApp) + { return !Visible; } + return User32.IsIconic(Handle) || Location.X <= -32000; } - set { - if (value) { - User32.SendMessage(Handle, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_MINIMIZE, IntPtr.Zero); - } else { - User32.SendMessage(Handle, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_RESTORE, IntPtr.Zero); + set + { + if (value) + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MINIMIZE, IntPtr.Zero); + } + else + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_RESTORE, IntPtr.Zero); } } } @@ -387,29 +481,41 @@ namespace GreenshotPlugin.Core /// /// Gets/Sets whether the window is maximized or not. /// - public bool Maximised { - get { + public bool Maximised + { + get + { if (IsApp) { - if (Visible) { + if (Visible) + { Rectangle windowRectangle = WindowRectangle; - foreach (var screen in Screen.AllScreens) { - if (screen.Bounds.Contains(windowRectangle)) { - if (windowRectangle.Equals(screen.Bounds)) { + foreach (var screen in Screen.AllScreens) + { + if (screen.Bounds.Contains(windowRectangle)) + { + if (windowRectangle.Equals(screen.Bounds)) + { return true; } } } } + return false; } + return User32.IsZoomed(Handle); } - set { - if (value) { - User32.SendMessage(Handle, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_MAXIMIZE, IntPtr.Zero); - } else { - User32.SendMessage(Handle, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_MINIMIZE, IntPtr.Zero); + set + { + if (value) + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MAXIMIZE, IntPtr.Zero); + } + else + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MINIMIZE, IntPtr.Zero); } } } @@ -425,70 +531,97 @@ namespace GreenshotPlugin.Core /// /// Gets whether the window is visible. /// - public bool Visible { - get { + public bool Visible + { + get + { // Tip from Raymond Chen https://devblogs.microsoft.com/oldnewthing/20200302-00/?p=103507 if (IsCloaked) { return false; } - if (IsApp) { + + if (IsApp) + { Rectangle windowRectangle = WindowRectangle; - foreach (Screen screen in Screen.AllScreens) { - if (screen.Bounds.Contains(windowRectangle)) { - if (windowRectangle.Equals(screen.Bounds)) { + foreach (Screen screen in Screen.AllScreens) + { + if (screen.Bounds.Contains(windowRectangle)) + { + if (windowRectangle.Equals(screen.Bounds)) + { // Fullscreen, it's "visible" when AppVisibilityOnMonitor says yes // Although it might be the other App, this is not "very" important RECT rect = new RECT(screen.Bounds); IntPtr monitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONULL); - if (monitor != IntPtr.Zero) { + if (monitor != IntPtr.Zero) + { MONITOR_APP_VISIBILITY? monitorAppVisibility = AppVisibility?.GetAppVisibilityOnMonitor(monitor); //LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds); - if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) { + if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) + { return true; } } - } else { + } + else + { // Is only partly on the screen, when this happens the app is always visible! return true; } } } + return false; } - if (IsGutter) { + + if (IsGutter) + { // gutter is only made available when it's visible return true; } - if (IsAppLauncher) { + + if (IsAppLauncher) + { return IsAppLauncherVisible; } + return User32.IsWindowVisible(Handle); } } - public bool HasParent { - get { + public bool HasParent + { + get + { GetParent(); return _parentHandle != IntPtr.Zero; } } - public int ProcessId { - get { + public int ProcessId + { + get + { User32.GetWindowThreadProcessId(Handle, out var processId); return processId; } } - public Process Process { - get { - try { + public Process Process + { + get + { + try + { User32.GetWindowThreadProcessId(Handle, out var processId); return Process.GetProcessById(processId); - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Warn(ex); } + return null; } } @@ -500,15 +633,19 @@ namespace GreenshotPlugin.Core /// /// Gets the bounding rectangle of the window /// - public Rectangle WindowRectangle { - get { + public Rectangle WindowRectangle + { + get + { // Try to return a cached value long now = DateTime.Now.Ticks; - if (_previousWindowRectangle.IsEmpty || !_frozen) { + if (_previousWindowRectangle.IsEmpty || !_frozen) + { if (!_previousWindowRectangle.IsEmpty && now - _lastWindowRectangleRetrieveTime <= CacheTime) { return _previousWindowRectangle; } + Rectangle windowRect = Rectangle.Empty; if (DWM.IsDwmEnabled) { @@ -522,6 +659,7 @@ namespace GreenshotPlugin.Core _lastWindowRectangleRetrieveTime = now; } } + if (gotFrameBounds && WindowsVersion.IsWindows10OrLater && !Maximised) { // Somehow DWM doesn't calculate it corectly, there is a 1 pixel border around the capture @@ -533,7 +671,8 @@ namespace GreenshotPlugin.Core } } - if (windowRect.IsEmpty) { + if (windowRect.IsEmpty) + { if (!GetWindowRect(out windowRect)) { Win32Error error = Win32.GetLastErrorCode(); @@ -542,21 +681,27 @@ namespace GreenshotPlugin.Core } // Correction for maximized windows, only if it's not an app - if (!HasParent && !IsApp && Maximised) { + if (!HasParent && !IsApp && Maximised) + { // Only if the border size can be retrieved if (GetBorderSize(out var size)) { - windowRect = new Rectangle(windowRect.X + size.Width, windowRect.Y + size.Height, windowRect.Width - (2 * size.Width), windowRect.Height - (2 * size.Height)); + windowRect = new Rectangle(windowRect.X + size.Width, windowRect.Y + size.Height, windowRect.Width - (2 * size.Width), + windowRect.Height - (2 * size.Height)); } } + _lastWindowRectangleRetrieveTime = now; // Try to return something valid, by getting returning the previous size if the window doesn't have a Rectangle anymore - if (windowRect.IsEmpty) { + if (windowRect.IsEmpty) + { return _previousWindowRectangle; } + _previousWindowRectangle = windowRect; return windowRect; } + return _previousWindowRectangle; } } @@ -564,8 +709,10 @@ namespace GreenshotPlugin.Core /// /// Gets the location of the window relative to the screen. /// - public Point Location { - get { + public Point Location + { + get + { Rectangle tmpRectangle = WindowRectangle; return new Point(tmpRectangle.Left, tmpRectangle.Top); } @@ -574,8 +721,10 @@ namespace GreenshotPlugin.Core /// /// Gets the size of the window. /// - public Size Size { - get { + public Size Size + { + get + { Rectangle tmpRectangle = WindowRectangle; return new Size(tmpRectangle.Right - tmpRectangle.Left, tmpRectangle.Bottom - tmpRectangle.Top); } @@ -584,13 +733,16 @@ namespace GreenshotPlugin.Core /// /// Get the client rectangle, this is the part of the window inside the borders (drawable area) /// - public Rectangle ClientRectangle { - get { + public Rectangle ClientRectangle + { + get + { if (!GetClientRect(out var clientRect)) { Win32Error error = Win32.GetLastErrorCode(); Log.WarnFormat("Couldn't retrieve the client rectangle for {0}, error: {1}", Text, Win32.GetMessage(error)); } + return clientRect; } } @@ -600,7 +752,8 @@ namespace GreenshotPlugin.Core /// /// Point with the coordinates to check /// true if the point lies within - public bool Contains(Point p) { + public bool Contains(Point p) + { return WindowRectangle.Contains(p); } @@ -608,15 +761,19 @@ namespace GreenshotPlugin.Core /// Restores and Brings the window to the front, /// assuming it is a visible application window. /// - public void Restore() { - if (Iconic) { - User32.SendMessage(Handle, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_RESTORE, IntPtr.Zero); + public void Restore() + { + if (Iconic) + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_RESTORE, IntPtr.Zero); } + User32.BringWindowToTop(Handle); User32.SetForegroundWindow(Handle); // Make sure windows has time to perform the action // TODO: this is BAD practice! - while(Iconic) { + while (Iconic) + { Application.DoEvents(); } } @@ -624,31 +781,33 @@ namespace GreenshotPlugin.Core /// /// Get / Set the WindowStyle /// - public WindowStyleFlags WindowStyle { - get => (WindowStyleFlags)User32.GetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_STYLE); - set => User32.SetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_STYLE, new IntPtr((long)value)); + public WindowStyleFlags WindowStyle + { + get => (WindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE); + set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE, new IntPtr((long) value)); } /// /// Get/Set the WindowPlacement /// - public WindowPlacement WindowPlacement { - get { + public WindowPlacement WindowPlacement + { + get + { var placement = WindowPlacement.Default; User32.GetWindowPlacement(Handle, ref placement); return placement; } - set { - User32.SetWindowPlacement(Handle, ref value); - } + set { User32.SetWindowPlacement(Handle, ref value); } } /// /// Get/Set the Extended WindowStyle /// - public ExtendedWindowStyleFlags ExtendedWindowStyle { - get => (ExtendedWindowStyleFlags)User32.GetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_EXSTYLE); - set => User32.SetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_EXSTYLE, new IntPtr((uint)value)); + public ExtendedWindowStyleFlags ExtendedWindowStyle + { + get => (ExtendedWindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_EXSTYLE); + set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_EXSTYLE, new IntPtr((uint) value)); } /// @@ -656,13 +815,16 @@ namespace GreenshotPlugin.Core /// /// The capture to fill /// ICapture - public ICapture CaptureGdiWindow(ICapture capture) { + public ICapture CaptureGdiWindow(ICapture capture) + { Image capturedImage = PrintWindow(); - if (capturedImage != null) { + if (capturedImage != null) + { capture.Image = capturedImage; capture.Location = Location; return capture; } + return null; } @@ -673,11 +835,13 @@ namespace GreenshotPlugin.Core /// Wanted WindowCaptureMode /// True if auto mode is used /// ICapture with the capture - public ICapture CaptureDwmWindow(ICapture capture, WindowCaptureMode windowCaptureMode, bool autoMode) { + public ICapture CaptureDwmWindow(ICapture capture, WindowCaptureMode windowCaptureMode, bool autoMode) + { IntPtr thumbnailHandle = IntPtr.Zero; Form tempForm = null; bool tempFormShown = false; - try { + try + { tempForm = new Form { ShowInTaskbar = false, @@ -691,7 +855,8 @@ namespace GreenshotPlugin.Core // Get the original size DWM.DwmQueryThumbnailSourceSize(thumbnailHandle, out var sourceSize); - if (sourceSize.Width <= 0 || sourceSize.Height <= 0) { + if (sourceSize.Width <= 0 || sourceSize.Height <= 0) + { return null; } @@ -700,33 +865,43 @@ namespace GreenshotPlugin.Core Point formLocation = windowRectangle.Location; Size borderSize = new Size(); bool doesCaptureFit = false; - if (!Maximised) { + if (!Maximised) + { // Assume using it's own location formLocation = windowRectangle.Location; // TODO: Use Rectangle.Union! using Region workingArea = new Region(Screen.PrimaryScreen.Bounds); // Find the screen where the window is and check if it fits - foreach (Screen screen in Screen.AllScreens) { - if (!Equals(screen, Screen.PrimaryScreen)) { + foreach (Screen screen in Screen.AllScreens) + { + if (!Equals(screen, Screen.PrimaryScreen)) + { workingArea.Union(screen.Bounds); } } // If the formLocation is not inside the visible area - if (!workingArea.AreRectangleCornersVisisble(windowRectangle)) { + if (!workingArea.AreRectangleCornersVisisble(windowRectangle)) + { // If none found we find the biggest screen - foreach (Screen screen in Screen.AllScreens) { + foreach (Screen screen in Screen.AllScreens) + { Rectangle newWindowRectangle = new Rectangle(screen.WorkingArea.Location, windowRectangle.Size); - if (workingArea.AreRectangleCornersVisisble(newWindowRectangle)) { + if (workingArea.AreRectangleCornersVisisble(newWindowRectangle)) + { formLocation = screen.Bounds.Location; doesCaptureFit = true; break; } } - } else { + } + else + { doesCaptureFit = true; } - } else if (!WindowsVersion.IsWindows8OrLater) { + } + else if (!WindowsVersion.IsWindows8OrLater) + { //GetClientRect(out windowRectangle); GetBorderSize(out borderSize); formLocation = new Point(windowRectangle.X - borderSize.Width, windowRectangle.Y - borderSize.Height); @@ -737,30 +912,36 @@ namespace GreenshotPlugin.Core // Prepare rectangle to capture from the screen. Rectangle captureRectangle = new Rectangle(formLocation.X, formLocation.Y, sourceSize.Width, sourceSize.Height); - if (Maximised) { + if (Maximised) + { // Correct capture size for maximized window by offsetting the X,Y with the border size // and subtracting the border from the size (2 times, as we move right/down for the capture without resizing) captureRectangle.Inflate(borderSize.Width, borderSize.Height); - } else { + } + else + { // TODO: Also 8.x? if (WindowsVersion.IsWindows10OrLater) { captureRectangle.Inflate(Conf.Win10BorderCrop); } - if (autoMode) { + if (autoMode) + { // check if the capture fits if (!doesCaptureFit) { // if GDI is allowed.. (a screenshot won't be better than we comes if we continue) using Process thisWindowProcess = Process; - if (!IsMetroApp && WindowCapture.IsGdiAllowed(thisWindowProcess)) { + if (!IsMetroApp && WindowCapture.IsGdiAllowed(thisWindowProcess)) + { // we return null which causes the capturing code to try another method. return null; } } } } + // Prepare the displaying of the Thumbnail DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES { @@ -778,9 +959,11 @@ namespace GreenshotPlugin.Core // Destination bitmap for the capture Bitmap capturedBitmap = null; bool frozen = false; - try { + try + { // Check if we make a transparent capture - if (windowCaptureMode == WindowCaptureMode.AeroTransparent) { + if (windowCaptureMode == WindowCaptureMode.AeroTransparent) + { frozen = FreezeWindow(); // Use white, later black to capture transparent tempForm.BackColor = Color.White; @@ -795,64 +978,86 @@ namespace GreenshotPlugin.Core tempForm.BackColor = Color.Black; // Make sure everything is visible tempForm.Refresh(); - if (!IsMetroApp) { + if (!IsMetroApp) + { // Make sure the application window is active, so the colors & buttons are right ToForeground(); } + // Make sure all changes are processed and visible Application.DoEvents(); using Bitmap blackBitmap = WindowCapture.CaptureRectangle(captureRectangle); capturedBitmap = ApplyTransparency(blackBitmap, whiteBitmap); - } catch (Exception e) { + } + catch (Exception e) + { Log.Debug("Exception: ", e); // Some problem occurred, cleanup and make a normal capture - if (capturedBitmap != null) { + if (capturedBitmap != null) + { capturedBitmap.Dispose(); capturedBitmap = null; } } } + // If no capture up till now, create a normal capture. - if (capturedBitmap == null) { + if (capturedBitmap == null) + { // Remove transparency, this will break the capturing - if (!autoMode) { + if (!autoMode) + { tempForm.BackColor = Color.FromArgb(255, Conf.DWMBackgroundColor.R, Conf.DWMBackgroundColor.G, Conf.DWMBackgroundColor.B); - } else { + } + else + { Color colorizationColor = DWM.ColorizationColor; // Modify by losing the transparency and increasing the intensity (as if the background color is white) colorizationColor = Color.FromArgb(255, (colorizationColor.R + 255) >> 1, (colorizationColor.G + 255) >> 1, (colorizationColor.B + 255) >> 1); tempForm.BackColor = colorizationColor; } + // Make sure everything is visible tempForm.Refresh(); - if (!IsMetroApp) { + if (!IsMetroApp) + { // Make sure the application window is active, so the colors & buttons are right ToForeground(); } + // Make sure all changes are processed and visible Application.DoEvents(); // Capture from the screen capturedBitmap = WindowCapture.CaptureRectangle(captureRectangle); } - if (capturedBitmap != null) { + + if (capturedBitmap != null) + { // Not needed for Windows 8 - if (!WindowsVersion.IsWindows8OrLater) { + if (!WindowsVersion.IsWindows8OrLater) + { // Only if the Inivalue is set, not maximized and it's not a tool window. - if (Conf.WindowCaptureRemoveCorners && !Maximised && (ExtendedWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) == 0) { + if (Conf.WindowCaptureRemoveCorners && !Maximised && (ExtendedWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) == 0) + { // Remove corners - if (!Image.IsAlphaPixelFormat(capturedBitmap.PixelFormat)) { + if (!Image.IsAlphaPixelFormat(capturedBitmap.PixelFormat)) + { Log.Debug("Changing pixelformat to Alpha for the RemoveCorners"); Bitmap tmpBitmap = ImageHelper.Clone(capturedBitmap, PixelFormat.Format32bppArgb); capturedBitmap.Dispose(); capturedBitmap = tmpBitmap; } + RemoveCorners(capturedBitmap); } } } - } finally { + } + finally + { // Make sure to ALWAYS unfreeze!! - if (frozen) { + if (frozen) + { UnfreezeWindow(); } } @@ -860,15 +1065,22 @@ namespace GreenshotPlugin.Core capture.Image = capturedBitmap; // Make sure the capture location is the location of the window, not the copy capture.Location = Location; - } finally { - if (thumbnailHandle != IntPtr.Zero) { + } + finally + { + if (thumbnailHandle != IntPtr.Zero) + { // Unregister (cleanup), as we are finished we don't need the form or the thumbnail anymore DWM.DwmUnregisterThumbnail(thumbnailHandle); } - if (tempForm != null) { - if (tempFormShown) { + + if (tempForm != null) + { + if (tempFormShown) + { tempForm.Close(); } + tempForm.Dispose(); tempForm = null; } @@ -884,12 +1096,14 @@ namespace GreenshotPlugin.Core private void RemoveCorners(Bitmap image) { using IFastBitmap fastBitmap = FastBitmap.Create(image); - for (int y = 0; y < Conf.WindowCornerCutShape.Count; y++) { - for (int x = 0; x < Conf.WindowCornerCutShape[y]; x++) { + for (int y = 0; y < Conf.WindowCornerCutShape.Count; y++) + { + for (int x = 0; x < Conf.WindowCornerCutShape[y]; x++) + { fastBitmap.SetColorAt(x, y, Color.Transparent); - fastBitmap.SetColorAt(image.Width-1-x, y, Color.Transparent); - fastBitmap.SetColorAt(image.Width-1-x, image.Height-1-y, Color.Transparent); - fastBitmap.SetColorAt(x, image.Height-1-y, Color.Transparent); + fastBitmap.SetColorAt(image.Width - 1 - x, y, Color.Transparent); + fastBitmap.SetColorAt(image.Width - 1 - x, image.Height - 1 - y, Color.Transparent); + fastBitmap.SetColorAt(x, image.Height - 1 - y, Color.Transparent); } } } @@ -909,26 +1123,33 @@ namespace GreenshotPlugin.Core using (IFastBitmap blackBuffer = FastBitmap.Create(blackBitmap)) { using IFastBitmap whiteBuffer = FastBitmap.Create(whiteBitmap); - for (int y = 0; y < blackBuffer.Height; y++) { - for (int x = 0; x < blackBuffer.Width; x++) { + for (int y = 0; y < blackBuffer.Height; y++) + { + for (int x = 0; x < blackBuffer.Width; x++) + { Color c0 = blackBuffer.GetColorAt(x, y); Color c1 = whiteBuffer.GetColorAt(x, y); // Calculate alpha as double in range 0-1 int alpha = c0.R - c1.R + 255; - if (alpha == 255) { + if (alpha == 255) + { // Alpha == 255 means no change! targetBuffer.SetColorAt(x, y, c0); - } else if (alpha == 0) { + } + else if (alpha == 0) + { // Complete transparency, use transparent pixel targetBuffer.SetColorAt(x, y, Color.Transparent); - } else { + } + else + { // Calculate original color - byte originalAlpha = (byte)Math.Min(255, alpha); - var alphaFactor = alpha/255d; + byte originalAlpha = (byte) Math.Min(255, alpha); + var alphaFactor = alpha / 255d; //LOG.DebugFormat("Alpha {0} & c0 {1} & c1 {2}", alpha, c0, c1); - byte originalRed = (byte)Math.Min(255, c0.R / alphaFactor); - byte originalGreen = (byte)Math.Min(255, c0.G / alphaFactor); - byte originalBlue = (byte)Math.Min(255, c0.B / alphaFactor); + byte originalRed = (byte) Math.Min(255, c0.R / alphaFactor); + byte originalGreen = (byte) Math.Min(255, c0.G / alphaFactor); + byte originalBlue = (byte) Math.Min(255, c0.B / alphaFactor); Color originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue); //Color originalColor = Color.FromArgb(originalAlpha, originalRed, c0.G, c0.B); targetBuffer.SetColorAt(x, y, originalColor); @@ -936,6 +1157,7 @@ namespace GreenshotPlugin.Core } } } + return targetBuffer.UnlockAndReturnBitmap(); } @@ -944,12 +1166,15 @@ namespace GreenshotPlugin.Core /// /// out Rectangle /// bool true if it worked - private bool GetExtendedFrameBounds(out Rectangle rectangle) { + private bool GetExtendedFrameBounds(out Rectangle rectangle) + { int result = DWM.DwmGetWindowAttribute(Handle, DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out RECT rect, Marshal.SizeOf(typeof(RECT))); - if (result >= 0) { + if (result >= 0) + { rectangle = rect.ToRectangle(); return true; } + rectangle = Rectangle.Empty; return false; } @@ -959,7 +1184,8 @@ namespace GreenshotPlugin.Core /// /// out Rectangle /// bool true if it worked - private bool GetClientRect(out Rectangle rectangle) { + private bool GetClientRect(out Rectangle rectangle) + { var windowInfo = new WindowInfo(); // Get the Window Info for this window bool result = User32.GetWindowInfo(Handle, ref windowInfo); @@ -972,7 +1198,8 @@ namespace GreenshotPlugin.Core /// /// out Rectangle /// bool true if it worked - private bool GetWindowRect(out Rectangle rectangle) { + private bool GetWindowRect(out Rectangle rectangle) + { var windowInfo = new WindowInfo(); // Get the Window Info for this window bool result = User32.GetWindowInfo(Handle, ref windowInfo); @@ -985,11 +1212,12 @@ namespace GreenshotPlugin.Core /// /// out Size /// bool true if it worked - private bool GetBorderSize(out Size size) { + private bool GetBorderSize(out Size size) + { var windowInfo = new WindowInfo(); // Get the Window Info for this window bool result = User32.GetWindowInfo(Handle, ref windowInfo); - size = result ? new Size((int)windowInfo.cxWindowBorders, (int)windowInfo.cyWindowBorders) : Size.Empty; + size = result ? new Size((int) windowInfo.cxWindowBorders, (int) windowInfo.cyWindowBorders) : Size.Empty; return result; } @@ -1038,38 +1266,51 @@ namespace GreenshotPlugin.Core /// /// Set the window as foreground window /// - public void ToForeground() { + public void ToForeground() + { ToForeground(Handle); } /// /// Get the region for a window /// - private Region GetRegion() { - using (SafeRegionHandle region = GDI32.CreateRectRgn(0, 0, 0, 0)) { - if (!region.IsInvalid) { + private Region GetRegion() + { + using (SafeRegionHandle region = GDI32.CreateRectRgn(0, 0, 0, 0)) + { + if (!region.IsInvalid) + { RegionResult result = User32.GetWindowRgn(Handle, region); - if (result != RegionResult.REGION_ERROR && result != RegionResult.REGION_NULLREGION) { + if (result != RegionResult.REGION_ERROR && result != RegionResult.REGION_NULLREGION) + { return Region.FromHrgn(region.DangerousGetHandle()); } } } + return null; } - private bool CanFreezeOrUnfreeze(string titleOrProcessname) { - if (string.IsNullOrEmpty(titleOrProcessname)) { - return false; - } - if (titleOrProcessname.ToLower().Contains("greenshot")) { + private bool CanFreezeOrUnfreeze(string titleOrProcessname) + { + if (string.IsNullOrEmpty(titleOrProcessname)) + { return false; } - foreach (string excludeProcess in ExcludeProcessesFromFreeze) { - if (titleOrProcessname.ToLower().Contains(excludeProcess)) { + if (titleOrProcessname.ToLower().Contains("greenshot")) + { + return false; + } + + foreach (string excludeProcess in ExcludeProcessesFromFreeze) + { + if (titleOrProcessname.ToLower().Contains(excludeProcess)) + { return false; } } + return true; } @@ -1077,32 +1318,42 @@ namespace GreenshotPlugin.Core /// Freezes the process belonging to the window /// Warning: Use only if no other way!! /// - private bool FreezeWindow() { + private bool FreezeWindow() + { bool frozen = false; - using (Process proc = Process.GetProcessById(ProcessId)) { + using (Process proc = Process.GetProcessById(ProcessId)) + { string processName = proc.ProcessName; - if (!CanFreezeOrUnfreeze(processName)) { + if (!CanFreezeOrUnfreeze(processName)) + { Log.DebugFormat("Not freezing {0}", processName); return false; } - if (!CanFreezeOrUnfreeze(Text)) { + + if (!CanFreezeOrUnfreeze(Text)) + { Log.DebugFormat("Not freezing {0}", processName); return false; } + Log.DebugFormat("Freezing process: {0}", processName); - foreach (ProcessThread pT in proc.Threads) { - IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id); + foreach (ProcessThread pT in proc.Threads) + { + IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); - if (pOpenThread == IntPtr.Zero) { + if (pOpenThread == IntPtr.Zero) + { break; } + frozen = true; Kernel32.SuspendThread(pOpenThread); pT.Dispose(); } } + return frozen; } @@ -1113,20 +1364,26 @@ namespace GreenshotPlugin.Core { using Process proc = Process.GetProcessById(ProcessId); string processName = proc.ProcessName; - if (!CanFreezeOrUnfreeze(processName)) { + if (!CanFreezeOrUnfreeze(processName)) + { Log.DebugFormat("Not unfreezing {0}", processName); return; } - if (!CanFreezeOrUnfreeze(Text)) { + + if (!CanFreezeOrUnfreeze(Text)) + { Log.DebugFormat("Not unfreezing {0}", processName); return; } + Log.DebugFormat("Unfreezing process: {0}", processName); - foreach (ProcessThread pT in proc.Threads) { - IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id); + foreach (ProcessThread pT in proc.Threads) + { + IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); - if (pOpenThread == IntPtr.Zero) { + if (pOpenThread == IntPtr.Zero) + { break; } @@ -1138,29 +1395,36 @@ namespace GreenshotPlugin.Core /// Return an Image representing the Window! /// As GDI+ draws it, it will be without Aero borders! /// - public Image PrintWindow() { + public Image PrintWindow() + { Rectangle windowRect = WindowRectangle; // Start the capture Exception exceptionOccured = null; Image returnImage; - using (Region region = GetRegion()) { + using (Region region = GetRegion()) + { PixelFormat pixelFormat = PixelFormat.Format24bppRgb; // Only use 32 bpp ARGB when the window has a region - if (region != null) { + if (region != null) + { pixelFormat = PixelFormat.Format32bppArgb; } + returnImage = new Bitmap(windowRect.Width, windowRect.Height, pixelFormat); using Graphics graphics = Graphics.FromImage(returnImage); - using (SafeDeviceContextHandle graphicsDc = graphics.GetSafeDeviceContext()) { + using (SafeDeviceContextHandle graphicsDc = graphics.GetSafeDeviceContext()) + { bool printSucceeded = User32.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), 0x0); - if (!printSucceeded) { + if (!printSucceeded) + { // something went wrong, most likely a "0x80004005" (Acess Denied) when using UAC exceptionOccured = User32.CreateWin32Exception("PrintWindow"); } } // Apply the region "transparency" - if (region != null && !region.IsEmpty(graphics)) { + if (region != null && !region.IsEmpty(graphics)) + { graphics.ExcludeClip(region); graphics.Clear(Color.Transparent); } @@ -1169,17 +1433,22 @@ namespace GreenshotPlugin.Core } // Return null if error - if (exceptionOccured != null) { + if (exceptionOccured != null) + { Log.ErrorFormat("Error calling print window: {0}", exceptionOccured.Message); returnImage.Dispose(); return null; } - if (!HasParent && Maximised) { + + if (!HasParent && Maximised) + { Log.Debug("Correcting for maximalization"); GetBorderSize(out var borderSize); - Rectangle borderRectangle = new Rectangle(borderSize.Width, borderSize.Height, windowRect.Width - (2 * borderSize.Width), windowRect.Height - (2 * borderSize.Height)); + Rectangle borderRectangle = new Rectangle(borderSize.Width, borderSize.Height, windowRect.Width - (2 * borderSize.Width), + windowRect.Height - (2 * borderSize.Height)); ImageHelper.Crop(ref returnImage, ref borderRectangle); } + return returnImage; } @@ -1188,7 +1457,8 @@ namespace GreenshotPlugin.Core /// the specified Window Handle. /// /// The Window Handle - public WindowDetails(IntPtr hWnd) { + public WindowDetails(IntPtr hWnd) + { Handle = hWnd; } @@ -1196,20 +1466,26 @@ namespace GreenshotPlugin.Core /// Gets an instance of the current active foreground window /// /// WindowDetails of the current window - public static WindowDetails GetActiveWindow() { + public static WindowDetails GetActiveWindow() + { IntPtr hWnd = User32.GetForegroundWindow(); - if (hWnd != IntPtr.Zero) { - if (IgnoreHandles.Contains(hWnd)) { + if (hWnd != IntPtr.Zero) + { + if (IgnoreHandles.Contains(hWnd)) + { return GetDesktopWindow(); } WindowDetails activeWindow = new WindowDetails(hWnd); // Invisible Windows should not be active - if (!activeWindow.Visible) { + if (!activeWindow.Visible) + { return GetDesktopWindow(); } + return activeWindow; } + return null; } @@ -1217,7 +1493,8 @@ namespace GreenshotPlugin.Core /// Gets the Desktop window /// /// WindowDetails for the desktop window - public static WindowDetails GetDesktopWindow() { + public static WindowDetails GetDesktopWindow() + { return new WindowDetails(User32.GetDesktopWindow()); } @@ -1225,7 +1502,8 @@ namespace GreenshotPlugin.Core /// Get all the top level windows /// /// List of WindowDetails with all the top level windows - public static IList GetAllWindows() { + public static IList GetAllWindows() + { return GetAllWindows(null); } @@ -1233,7 +1511,8 @@ namespace GreenshotPlugin.Core /// Get all the top level windows, with matching classname /// /// List WindowDetails with all the top level windows - public static IList GetAllWindows(string classname) { + public static IList GetAllWindows(string classname) + { return new WindowsEnumerator().GetWindows(IntPtr.Zero, classname).Items; } @@ -1242,22 +1521,29 @@ namespace GreenshotPlugin.Core /// /// point to check for /// - public WindowDetails FindChildUnderPoint(Point point) { - if (!Contains(point)) { + public WindowDetails FindChildUnderPoint(Point point) + { + if (!Contains(point)) + { return null; } + var rect = WindowRectangle; // If the mouse it at the edge, take the whole window if (rect.X == point.X || rect.Y == point.Y || rect.Right == point.X || rect.Bottom == point.Y) { return this; } + // Look into the child windows - foreach(var childWindow in Children) { - if (childWindow.Contains(point)) { + foreach (var childWindow in Children) + { + if (childWindow.Contains(point)) + { return childWindow.FindChildUnderPoint(point); } } + return this; } @@ -1266,7 +1552,8 @@ namespace GreenshotPlugin.Core /// /// IntPtr with the windows handle /// String with ClassName - public static string GetClassName(IntPtr hWnd) { + public static string GetClassName(IntPtr hWnd) + { var classNameBuilder = new StringBuilder(260, 260); User32.GetClassName(hWnd, classNameBuilder, classNameBuilder.Capacity); return classNameBuilder.ToString(); @@ -1285,15 +1572,18 @@ namespace GreenshotPlugin.Core { return false; } + // Ignore minimized if (window.Iconic) { return false; } + if (IgnoreClasses.Contains(window.ClassName)) { return false; } + // On windows which are visible on the screen var windowRect = window.WindowRectangle; windowRect.Intersect(screenBounds); @@ -1301,6 +1591,7 @@ namespace GreenshotPlugin.Core { return false; } + // Skip everything which is not rendered "normally", trying to fix BUG-2017 var exWindowStyle = window.ExtendedWindowStyle; if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) @@ -1315,14 +1606,17 @@ namespace GreenshotPlugin.Core /// Get all the visible top level windows /// /// List WindowDetails with all the visible top level windows - public static IEnumerable GetVisibleWindows() { + public static IEnumerable GetVisibleWindows() + { Rectangle screenBounds = WindowCapture.GetScreenBounds(); - foreach(var window in GetAppWindows()) { + foreach (var window in GetAppWindows()) + { if (IsVisible(window, screenBounds)) { yield return window; } } + foreach (var window in GetAllWindows()) { if (IsVisible(window, screenBounds)) @@ -1337,23 +1631,29 @@ namespace GreenshotPlugin.Core /// These are all Windows with Classname "Windows.UI.Core.CoreWindow" /// /// List WindowDetails with visible metro apps - public static IEnumerable GetAppWindows() { + public static IEnumerable GetAppWindows() + { // if the appVisibility != null we have Windows 8. if (AppVisibility == null) { yield break; } + var nextHandle = User32.FindWindow(AppWindowClass, null); - while (nextHandle != IntPtr.Zero) { + while (nextHandle != IntPtr.Zero) + { var metroApp = new WindowDetails(nextHandle); yield return metroApp; // Check if we have a gutter! - if (metroApp.Visible && !metroApp.Maximised) { + if (metroApp.Visible && !metroApp.Maximised) + { var gutterHandle = User32.FindWindow(GutterClass, null); - if (gutterHandle != IntPtr.Zero) { + if (gutterHandle != IntPtr.Zero) + { yield return new WindowDetails(gutterHandle); } } + nextHandle = User32.FindWindowEx(IntPtr.Zero, nextHandle, AppWindowClass, null); } } @@ -1369,39 +1669,47 @@ namespace GreenshotPlugin.Core { return false; } + // Windows without size if (window.WindowRectangle.Size.Width * window.WindowRectangle.Size.Height == 0) { return false; } + if (window.HasParent) { return false; } + var exWindowStyle = window.ExtendedWindowStyle; if ((exWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) != 0) { return false; } + // Skip everything which is not rendered "normally", trying to fix BUG-2017 if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) { return false; } + // Skip preview windows, like the one from Firefox if ((window.WindowStyle & WindowStyleFlags.WS_VISIBLE) == 0) { return false; } + // Ignore windows without title if (window.Text.Length == 0) { return false; } + if (IgnoreClasses.Contains(window.ClassName)) { return false; } + if (!(window.Visible || window.Iconic)) { return false; @@ -1414,7 +1722,8 @@ namespace GreenshotPlugin.Core /// Get all the top level windows /// /// List WindowDetails with all the top level windows - public static IEnumerable GetTopLevelWindows() { + public static IEnumerable GetTopLevelWindows() + { foreach (var possibleTopLevel in GetAppWindows()) { if (IsTopLevel(possibleTopLevel)) @@ -1437,35 +1746,47 @@ namespace GreenshotPlugin.Core /// /// /// - public static WindowDetails GetLinkedWindow(WindowDetails windowToLinkTo) { + public static WindowDetails GetLinkedWindow(WindowDetails windowToLinkTo) + { int processIdSelectedWindow = windowToLinkTo.ProcessId; - foreach(var window in GetAllWindows()) { + foreach (var window in GetAllWindows()) + { // Ignore windows without title - if (window.Text.Length == 0) { + if (window.Text.Length == 0) + { continue; } + // Ignore invisible - if (!window.Visible) { + if (!window.Visible) + { continue; } - if (window.Handle == windowToLinkTo.Handle) { + + if (window.Handle == windowToLinkTo.Handle) + { continue; } - if (window.Iconic) { + + if (window.Iconic) + { continue; } // Windows without size Size windowSize = window.WindowRectangle.Size; - if (windowSize.Width == 0 || windowSize.Height == 0) { + if (windowSize.Width == 0 || windowSize.Height == 0) + { continue; } - if (window.ProcessId == processIdSelectedWindow) { + if (window.ProcessId == processIdSelectedWindow) + { Log.InfoFormat("Found window {0} belonging to same process as the window {1}", window.Text, windowToLinkTo.Text); return window; } } + return null; } @@ -1477,8 +1798,10 @@ namespace GreenshotPlugin.Core public static void ActiveNewerWindows(IEnumerable oldWindows) { var oldWindowsList = new List(oldWindows); - foreach(var window in GetVisibleWindows()) { - if (!oldWindowsList.Contains(window)) { + foreach (var window in GetVisibleWindows()) + { + if (!oldWindowsList.Contains(window)) + { window.ToForeground(); } } @@ -1488,15 +1811,20 @@ namespace GreenshotPlugin.Core /// Get the AppLauncher /// /// - public static WindowDetails GetAppLauncher() { + public static WindowDetails GetAppLauncher() + { // Only if Windows 8 (or higher) - if (AppVisibility == null) { + if (AppVisibility == null) + { return null; } + IntPtr appLauncher = User32.FindWindow(ApplauncherClass, null); - if (appLauncher != IntPtr.Zero) { - return new WindowDetails (appLauncher); + if (appLauncher != IntPtr.Zero) + { + return new WindowDetails(appLauncher); } + return null; } @@ -1504,11 +1832,15 @@ namespace GreenshotPlugin.Core /// Return true if the metro-app-launcher is visible /// /// - public static bool IsAppLauncherVisible { - get { - if (AppVisibility != null) { + public static bool IsAppLauncherVisible + { + get + { + if (AppVisibility != null) + { return AppVisibility.IsLauncherVisible; } + return false; } } @@ -1537,6 +1869,7 @@ namespace GreenshotPlugin.Core { result.AppendLine($"Children classes: {string.Join(",", Children.Select(c => c.ClassName))}"); } + return result.ToString(); } } diff --git a/src/GreenshotPlugin/Core/WindowsEnumerator.cs b/src/GreenshotPlugin/Core/WindowsEnumerator.cs index 9025cd7b8..09eece85f 100644 --- a/src/GreenshotPlugin/Core/WindowsEnumerator.cs +++ b/src/GreenshotPlugin/Core/WindowsEnumerator.cs @@ -24,73 +24,85 @@ using System; using System.Collections.Generic; using System.Text; -namespace GreenshotPlugin.Core { +namespace GreenshotPlugin.Core +{ /// - /// EnumWindows wrapper for .NET - /// - public class WindowsEnumerator { - /// - /// Returns the collection of windows returned by GetWindows - /// - public IList Items { get; private set; } + /// EnumWindows wrapper for .NET + /// + public class WindowsEnumerator + { + /// + /// Returns the collection of windows returned by GetWindows + /// + public IList Items { get; private set; } /// - /// Gets all child windows of the specified window - /// - /// Window Handle to get children for - /// Window Classname to copy, use null to copy all - public WindowsEnumerator GetWindows(IntPtr hWndParent, string classname) { - Items = new List(); - User32.EnumChildWindows(hWndParent, WindowEnum, IntPtr.Zero); + /// Gets all child windows of the specified window + /// + /// Window Handle to get children for + /// Window Classname to copy, use null to copy all + public WindowsEnumerator GetWindows(IntPtr hWndParent, string classname) + { + Items = new List(); + User32.EnumChildWindows(hWndParent, WindowEnum, IntPtr.Zero); - bool hasParent = !IntPtr.Zero.Equals(hWndParent); - string parentText = null; - if (hasParent) { - var title = new StringBuilder(260, 260); - User32.GetWindowText(hWndParent, title, title.Capacity); - parentText = title.ToString(); - } + bool hasParent = !IntPtr.Zero.Equals(hWndParent); + string parentText = null; + if (hasParent) + { + var title = new StringBuilder(260, 260); + User32.GetWindowText(hWndParent, title, title.Capacity); + parentText = title.ToString(); + } var windows = new List(); - foreach (var window in Items) { - if (hasParent) { - window.Text = parentText; - window.ParentHandle = hWndParent; - } - if (classname == null || window.ClassName.Equals(classname)) { - windows.Add(window); - } - } - Items = windows; - return this; - } + foreach (var window in Items) + { + if (hasParent) + { + window.Text = parentText; + window.ParentHandle = hWndParent; + } + + if (classname == null || window.ClassName.Equals(classname)) + { + windows.Add(window); + } + } + + Items = windows; + return this; + } /// - /// The enum Windows callback. - /// - /// Window Handle - /// Application defined value - /// 1 to continue enumeration, 0 to stop - private int WindowEnum(IntPtr hWnd, int lParam) + /// The enum Windows callback. + /// + /// Window Handle + /// Application defined value + /// 1 to continue enumeration, 0 to stop + private int WindowEnum(IntPtr hWnd, int lParam) { return OnWindowEnum(hWnd) ? 1 : 0; } /// - /// Called whenever a new window is about to be added - /// by the Window enumeration called from GetWindows. - /// If overriding this function, return true to continue - /// enumeration or false to stop. If you do not call - /// the base implementation the Items collection will - /// be empty. - /// - /// Window handle to add - /// True to continue enumeration, False to stop - private bool OnWindowEnum(IntPtr hWnd) { - if (!WindowDetails.IsIgnoreHandle(hWnd)) { - Items.Add(new WindowDetails(hWnd)); - } - return true; - } - } -} + /// Called whenever a new window is about to be added + /// by the Window enumeration called from GetWindows. + /// If overriding this function, return true to continue + /// enumeration or false to stop. If you do not call + /// the base implementation the Items collection will + /// be empty. + /// + /// Window handle to add + /// True to continue enumeration, False to stop + private bool OnWindowEnum(IntPtr hWnd) + { + if (!WindowDetails.IsIgnoreHandle(hWnd)) + { + Items.Add(new WindowDetails(hWnd)); + } + + return true; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs b/src/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs index e48062f57..fba055f7f 100644 --- a/src/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs +++ b/src/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs @@ -25,41 +25,42 @@ using log4net; namespace GreenshotPlugin.Core { - /// - /// This IMessageFilter filters out all WM_INPUTLANGCHANGEREQUEST messages which go to a handle which is >32 bits. - /// The need for this is documented here: http://stackoverflow.com/a/32021586 - /// - public class WmInputLangChangeRequestFilter : IMessageFilter - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(WmInputLangChangeRequestFilter)); + /// + /// This IMessageFilter filters out all WM_INPUTLANGCHANGEREQUEST messages which go to a handle which is >32 bits. + /// The need for this is documented here: http://stackoverflow.com/a/32021586 + /// + public class WmInputLangChangeRequestFilter : IMessageFilter + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(WmInputLangChangeRequestFilter)); - /// - /// This will do some filtering - /// - /// Message - /// true if the message should be filtered - public bool PreFilterMessage(ref Message m) - { - return PreFilterMessageExternal(ref m); + /// + /// This will do some filtering + /// + /// Message + /// true if the message should be filtered + public bool PreFilterMessage(ref Message m) + { + return PreFilterMessageExternal(ref m); } - /// - /// Also used in the MainForm WndProc - /// - /// Message - /// true if the message should be filtered - public static bool PreFilterMessageExternal(ref Message m) - { - WindowsMessages message = (WindowsMessages)m.Msg; - if (message == WindowsMessages.WM_INPUTLANGCHANGEREQUEST || message == WindowsMessages.WM_INPUTLANGCHANGE) - { - LOG.WarnFormat("Filtering: {0}, {1:X} - {2:X} - {3:X}", message, m.LParam.ToInt64(), m.WParam.ToInt64(), m.HWnd.ToInt64()); - // For now we always return true - return true; - // But it could look something like this: - //return (m.LParam.ToInt64() | 0x7FFFFFFF) != 0; - } - return false; - } + /// + /// Also used in the MainForm WndProc + /// + /// Message + /// true if the message should be filtered + public static bool PreFilterMessageExternal(ref Message m) + { + WindowsMessages message = (WindowsMessages) m.Msg; + if (message == WindowsMessages.WM_INPUTLANGCHANGEREQUEST || message == WindowsMessages.WM_INPUTLANGCHANGE) + { + LOG.WarnFormat("Filtering: {0}, {1:X} - {2:X} - {3:X}", message, m.LParam.ToInt64(), m.WParam.ToInt64(), m.HWnd.ToInt64()); + // For now we always return true + return true; + // But it could look something like this: + //return (m.LParam.ToInt64() | 0x7FFFFFFF) != 0; + } + + return false; + } } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/AdjustEffect.cs b/src/GreenshotPlugin/Effects/AdjustEffect.cs index a01dd16d2..f2f472805 100644 --- a/src/GreenshotPlugin/Effects/AdjustEffect.cs +++ b/src/GreenshotPlugin/Effects/AdjustEffect.cs @@ -25,33 +25,30 @@ using GreenshotPlugin.Core; namespace GreenshotPlugin.Effects { - /// - /// AdjustEffect - /// - public class AdjustEffect : IEffect { - public AdjustEffect() - { - Reset(); - } - public float Contrast { - get; - set; - } - public float Brightness { - get; - set; - } - public float Gamma { - get; - set; - } - public void Reset() { - Contrast = 1f; - Brightness = 1f; - Gamma = 1f; - } - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.Adjust(sourceImage, Brightness, Contrast, Gamma); - } - } + /// + /// AdjustEffect + /// + public class AdjustEffect : IEffect + { + public AdjustEffect() + { + Reset(); + } + + public float Contrast { get; set; } + public float Brightness { get; set; } + public float Gamma { get; set; } + + public void Reset() + { + Contrast = 1f; + Brightness = 1f; + Gamma = 1f; + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.Adjust(sourceImage, Brightness, Contrast, Gamma); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/BorderEffect.cs b/src/GreenshotPlugin/Effects/BorderEffect.cs index 4e45f920c..650f63fe5 100644 --- a/src/GreenshotPlugin/Effects/BorderEffect.cs +++ b/src/GreenshotPlugin/Effects/BorderEffect.cs @@ -25,27 +25,28 @@ using GreenshotPlugin.Core; namespace GreenshotPlugin.Effects { - /// - /// BorderEffect - /// - public class BorderEffect : IEffect { - public BorderEffect() { - Reset(); - } - public Color Color { - get; - set; - } - public int Width { - get; - set; - } - public void Reset() { - Width = 2; - Color = Color.Black; - } - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.CreateBorder(sourceImage, Width, Color, sourceImage.PixelFormat, matrix); - } - } + /// + /// BorderEffect + /// + public class BorderEffect : IEffect + { + public BorderEffect() + { + Reset(); + } + + public Color Color { get; set; } + public int Width { get; set; } + + public void Reset() + { + Width = 2; + Color = Color.Black; + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateBorder(sourceImage, Width, Color, sourceImage.PixelFormat, matrix); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/DropShadowEffect.cs b/src/GreenshotPlugin/Effects/DropShadowEffect.cs index 5f05b889f..dd262aa07 100644 --- a/src/GreenshotPlugin/Effects/DropShadowEffect.cs +++ b/src/GreenshotPlugin/Effects/DropShadowEffect.cs @@ -25,39 +25,35 @@ using System.Drawing.Drawing2D; using System.Drawing.Imaging; using GreenshotPlugin.Core; -namespace GreenshotPlugin.Effects { - /// - /// DropShadowEffect - /// - [TypeConverter(typeof(EffectConverter))] - public class DropShadowEffect : IEffect { - public DropShadowEffect() { - Reset(); - } +namespace GreenshotPlugin.Effects +{ + /// + /// DropShadowEffect + /// + [TypeConverter(typeof(EffectConverter))] + public class DropShadowEffect : IEffect + { + public DropShadowEffect() + { + Reset(); + } - public float Darkness { - get; - set; - } + public float Darkness { get; set; } - public int ShadowSize { - get; - set; - } + public int ShadowSize { get; set; } - public Point ShadowOffset { - get; - set; - } + public Point ShadowOffset { get; set; } - public virtual void Reset() { - Darkness = 0.6f; - ShadowSize = 7; - ShadowOffset = new Point(-1, -1); - } + public virtual void Reset() + { + Darkness = 0.6f; + ShadowSize = 7; + ShadowOffset = new Point(-1, -1); + } - public virtual Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.CreateShadow(sourceImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); - } - } + public virtual Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateShadow(sourceImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/GrayscaleEffect.cs b/src/GreenshotPlugin/Effects/GrayscaleEffect.cs index 7c8e5c7b2..11e0f14a9 100644 --- a/src/GreenshotPlugin/Effects/GrayscaleEffect.cs +++ b/src/GreenshotPlugin/Effects/GrayscaleEffect.cs @@ -25,15 +25,19 @@ using GreenshotPlugin.Core; namespace GreenshotPlugin.Effects { - /// - /// GrayscaleEffect - /// - public class GrayscaleEffect : IEffect { - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.CreateGrayscale(sourceImage); - } - public void Reset() { - // No settings to reset - } - } + /// + /// GrayscaleEffect + /// + public class GrayscaleEffect : IEffect + { + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateGrayscale(sourceImage); + } + + public void Reset() + { + // No settings to reset + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/IEffect.cs b/src/GreenshotPlugin/Effects/IEffect.cs index 1beeb1aa5..26c2d1240 100644 --- a/src/GreenshotPlugin/Effects/IEffect.cs +++ b/src/GreenshotPlugin/Effects/IEffect.cs @@ -24,22 +24,23 @@ using System.Drawing.Drawing2D; namespace GreenshotPlugin.Effects { - /// - /// Interface to describe an effect - /// - public interface IEffect { - /// - /// Apply this IEffect to the supplied sourceImage. - /// In the process of applying the supplied matrix will be modified to represent the changes. - /// - /// Image to apply the effect to - /// Matrix with the modifications like rotate, translate etc. this can be used to calculate the new location of elements on a canvas - /// new image with applied effect - Image Apply(Image sourceImage, Matrix matrix); + /// + /// Interface to describe an effect + /// + public interface IEffect + { + /// + /// Apply this IEffect to the supplied sourceImage. + /// In the process of applying the supplied matrix will be modified to represent the changes. + /// + /// Image to apply the effect to + /// Matrix with the modifications like rotate, translate etc. this can be used to calculate the new location of elements on a canvas + /// new image with applied effect + Image Apply(Image sourceImage, Matrix matrix); - /// - /// Reset all values to their defaults - /// - void Reset(); - } + /// + /// Reset all values to their defaults + /// + void Reset(); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/InvertEffect.cs b/src/GreenshotPlugin/Effects/InvertEffect.cs index f890f5dd5..fc5d09178 100644 --- a/src/GreenshotPlugin/Effects/InvertEffect.cs +++ b/src/GreenshotPlugin/Effects/InvertEffect.cs @@ -25,15 +25,19 @@ using GreenshotPlugin.Core; namespace GreenshotPlugin.Effects { - /// - /// InvertEffect - /// - public class InvertEffect : IEffect { - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.CreateNegative(sourceImage); - } - public void Reset() { - // No settings to reset - } - } + /// + /// InvertEffect + /// + public class InvertEffect : IEffect + { + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateNegative(sourceImage); + } + + public void Reset() + { + // No settings to reset + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/MonochromeEffect.cs b/src/GreenshotPlugin/Effects/MonochromeEffect.cs index 8e0b69c7b..7d3bcec87 100644 --- a/src/GreenshotPlugin/Effects/MonochromeEffect.cs +++ b/src/GreenshotPlugin/Effects/MonochromeEffect.cs @@ -25,20 +25,27 @@ using GreenshotPlugin.Core; namespace GreenshotPlugin.Effects { - /// - /// MonochromeEffect - /// - public class MonochromeEffect : IEffect { - private readonly byte _threshold; - /// Threshold for monochrome filter (0 - 255), lower value means less black - public MonochromeEffect(byte threshold) { - _threshold = threshold; - } - public void Reset() { - // TODO: Modify the threshold to have a default, which is reset here - } - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.CreateMonochrome(sourceImage, _threshold); - } - } + /// + /// MonochromeEffect + /// + public class MonochromeEffect : IEffect + { + private readonly byte _threshold; + + /// Threshold for monochrome filter (0 - 255), lower value means less black + public MonochromeEffect(byte threshold) + { + _threshold = threshold; + } + + public void Reset() + { + // TODO: Modify the threshold to have a default, which is reset here + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateMonochrome(sourceImage, _threshold); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/ReduceColorsEffect.cs b/src/GreenshotPlugin/Effects/ReduceColorsEffect.cs index a432850b6..be8aad54d 100644 --- a/src/GreenshotPlugin/Effects/ReduceColorsEffect.cs +++ b/src/GreenshotPlugin/Effects/ReduceColorsEffect.cs @@ -27,34 +27,44 @@ using log4net; namespace GreenshotPlugin.Effects { - /// - /// ReduceColorsEffect - /// - public class ReduceColorsEffect : IEffect { - private static readonly ILog Log = LogManager.GetLogger(typeof(ReduceColorsEffect)); - public ReduceColorsEffect() - { - Reset(); - } - public int Colors { - get; - set; - } - public void Reset() { - Colors = 256; - } - public Image Apply(Image sourceImage, Matrix matrix) { - using (WuQuantizer quantizer = new WuQuantizer((Bitmap)sourceImage)) { - int colorCount = quantizer.GetColorCount(); - if (colorCount > Colors) { - try { - return quantizer.GetQuantizedImage(Colors); - } catch (Exception e) { - Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); - } - } - } - return null; - } - } + /// + /// ReduceColorsEffect + /// + public class ReduceColorsEffect : IEffect + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ReduceColorsEffect)); + + public ReduceColorsEffect() + { + Reset(); + } + + public int Colors { get; set; } + + public void Reset() + { + Colors = 256; + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + using (WuQuantizer quantizer = new WuQuantizer((Bitmap) sourceImage)) + { + int colorCount = quantizer.GetColorCount(); + if (colorCount > Colors) + { + try + { + return quantizer.GetQuantizedImage(Colors); + } + catch (Exception e) + { + Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); + } + } + } + + return null; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/ResizeCanvasEffect.cs b/src/GreenshotPlugin/Effects/ResizeCanvasEffect.cs index 67bbf6e7d..5b990f2d4 100644 --- a/src/GreenshotPlugin/Effects/ResizeCanvasEffect.cs +++ b/src/GreenshotPlugin/Effects/ResizeCanvasEffect.cs @@ -25,42 +25,34 @@ using GreenshotPlugin.Core; namespace GreenshotPlugin.Effects { - /// - /// ResizeCanvasEffect - /// - public class ResizeCanvasEffect : IEffect { - public ResizeCanvasEffect(int left, int right, int top, int bottom) { - Left = left; - Right = right; - Top = top; - Bottom = bottom; - BackgroundColor = Color.Empty; // Uses the default background color depending on the format - } - public int Left { - get; - set; - } - public int Right { - get; - set; - } - public int Top { - get; - set; - } - public int Bottom { - get; - set; - } - public Color BackgroundColor { - get; - set; - } - public void Reset() { - // values don't have a default value - } - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.ResizeCanvas(sourceImage, BackgroundColor, Left, Right, Top, Bottom, matrix); - } - } + /// + /// ResizeCanvasEffect + /// + public class ResizeCanvasEffect : IEffect + { + public ResizeCanvasEffect(int left, int right, int top, int bottom) + { + Left = left; + Right = right; + Top = top; + Bottom = bottom; + BackgroundColor = Color.Empty; // Uses the default background color depending on the format + } + + public int Left { get; set; } + public int Right { get; set; } + public int Top { get; set; } + public int Bottom { get; set; } + public Color BackgroundColor { get; set; } + + public void Reset() + { + // values don't have a default value + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.ResizeCanvas(sourceImage, BackgroundColor, Left, Right, Top, Bottom, matrix); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/ResizeEffect.cs b/src/GreenshotPlugin/Effects/ResizeEffect.cs index 38f997f71..cfcae71cd 100644 --- a/src/GreenshotPlugin/Effects/ResizeEffect.cs +++ b/src/GreenshotPlugin/Effects/ResizeEffect.cs @@ -25,32 +25,30 @@ using GreenshotPlugin.Core; namespace GreenshotPlugin.Effects { - /// - /// ResizeEffect - /// - public class ResizeEffect : IEffect { - public ResizeEffect(int width, int height, bool maintainAspectRatio) { - Width = width; - Height = height; - MaintainAspectRatio = maintainAspectRatio; - } - public int Width { - get; - set; - } - public int Height { - get; - set; - } - public bool MaintainAspectRatio { - get; - set; - } - public void Reset() { - // values don't have a default value - } - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.ResizeImage(sourceImage, MaintainAspectRatio, Width, Height, matrix); - } - } + /// + /// ResizeEffect + /// + public class ResizeEffect : IEffect + { + public ResizeEffect(int width, int height, bool maintainAspectRatio) + { + Width = width; + Height = height; + MaintainAspectRatio = maintainAspectRatio; + } + + public int Width { get; set; } + public int Height { get; set; } + public bool MaintainAspectRatio { get; set; } + + public void Reset() + { + // values don't have a default value + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.ResizeImage(sourceImage, MaintainAspectRatio, Width, Height, matrix); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/RotateEffect.cs b/src/GreenshotPlugin/Effects/RotateEffect.cs index 772a41a6a..8eb7a6978 100644 --- a/src/GreenshotPlugin/Effects/RotateEffect.cs +++ b/src/GreenshotPlugin/Effects/RotateEffect.cs @@ -26,34 +26,44 @@ using GreenshotPlugin.Core; namespace GreenshotPlugin.Effects { - /// - /// RotateEffect - /// - public class RotateEffect : IEffect { - public RotateEffect(int angle) { - Angle = angle; - } - public int Angle { - get; - set; - } - public void Reset() { - // Angle doesn't have a default value - } - public Image Apply(Image sourceImage, Matrix matrix) { - RotateFlipType flipType; - if (Angle == 90) { - matrix.Rotate(90, MatrixOrder.Append); - matrix.Translate(sourceImage.Height, 0, MatrixOrder.Append); - flipType = RotateFlipType.Rotate90FlipNone; - } else if (Angle == -90 || Angle == 270) { - flipType = RotateFlipType.Rotate270FlipNone; - matrix.Rotate(-90, MatrixOrder.Append); - matrix.Translate(0, sourceImage.Width, MatrixOrder.Append); - } else { - throw new NotSupportedException("Currently only an angle of 90 or -90 (270) is supported."); - } - return ImageHelper.RotateFlip(sourceImage, flipType); - } - } + /// + /// RotateEffect + /// + public class RotateEffect : IEffect + { + public RotateEffect(int angle) + { + Angle = angle; + } + + public int Angle { get; set; } + + public void Reset() + { + // Angle doesn't have a default value + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + RotateFlipType flipType; + if (Angle == 90) + { + matrix.Rotate(90, MatrixOrder.Append); + matrix.Translate(sourceImage.Height, 0, MatrixOrder.Append); + flipType = RotateFlipType.Rotate90FlipNone; + } + else if (Angle == -90 || Angle == 270) + { + flipType = RotateFlipType.Rotate270FlipNone; + matrix.Rotate(-90, MatrixOrder.Append); + matrix.Translate(0, sourceImage.Width, MatrixOrder.Append); + } + else + { + throw new NotSupportedException("Currently only an angle of 90 or -90 (270) is supported."); + } + + return ImageHelper.RotateFlip(sourceImage, flipType); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/TornEdgeEffect.cs b/src/GreenshotPlugin/Effects/TornEdgeEffect.cs index 682435132..70d671287 100644 --- a/src/GreenshotPlugin/Effects/TornEdgeEffect.cs +++ b/src/GreenshotPlugin/Effects/TornEdgeEffect.cs @@ -27,53 +27,49 @@ using GreenshotPlugin.Core; namespace GreenshotPlugin.Effects { - /// - /// TornEdgeEffect extends on DropShadowEffect - /// - [TypeConverter(typeof(EffectConverter))] - public sealed class TornEdgeEffect : DropShadowEffect { - public TornEdgeEffect() - { - Reset(); - } - public int ToothHeight { - get; - set; - } - public int HorizontalToothRange { - get; - set; - } - public int VerticalToothRange { - get; - set; - } - public bool[] Edges { - get; - set; - } - public bool GenerateShadow { - get; - set; - } + /// + /// TornEdgeEffect extends on DropShadowEffect + /// + [TypeConverter(typeof(EffectConverter))] + public sealed class TornEdgeEffect : DropShadowEffect + { + public TornEdgeEffect() + { + Reset(); + } - public override void Reset() { - base.Reset(); - ShadowSize = 7; - ToothHeight = 12; - HorizontalToothRange = 20; - VerticalToothRange = 20; - Edges = new[] { true, true, true, true }; - GenerateShadow = true; - } - public override Image Apply(Image sourceImage, Matrix matrix) { - Image tmpTornImage = ImageHelper.CreateTornEdge(sourceImage, ToothHeight, HorizontalToothRange, VerticalToothRange, Edges); - if (GenerateShadow) { - using (tmpTornImage) { - return ImageHelper.CreateShadow(tmpTornImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); - } - } - return tmpTornImage; - } - } + public int ToothHeight { get; set; } + public int HorizontalToothRange { get; set; } + public int VerticalToothRange { get; set; } + public bool[] Edges { get; set; } + public bool GenerateShadow { get; set; } + + public override void Reset() + { + base.Reset(); + ShadowSize = 7; + ToothHeight = 12; + HorizontalToothRange = 20; + VerticalToothRange = 20; + Edges = new[] + { + true, true, true, true + }; + GenerateShadow = true; + } + + public override Image Apply(Image sourceImage, Matrix matrix) + { + Image tmpTornImage = ImageHelper.CreateTornEdge(sourceImage, ToothHeight, HorizontalToothRange, VerticalToothRange, Edges); + if (GenerateShadow) + { + using (tmpTornImage) + { + return ImageHelper.CreateShadow(tmpTornImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); + } + } + + return tmpTornImage; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/FileDescriptorReader.cs b/src/GreenshotPlugin/FileDescriptorReader.cs index 7e0f3b9ab..3acfcf7a3 100644 --- a/src/GreenshotPlugin/FileDescriptorReader.cs +++ b/src/GreenshotPlugin/FileDescriptorReader.cs @@ -29,7 +29,6 @@ using GreenshotPlugin.UnmanagedHelpers.Structs; namespace GreenshotPlugin { - /// /// Specifies which fields are valid in a FileDescriptor Structure /// @@ -113,6 +112,7 @@ namespace GreenshotPlugin { yield break; } + var reader = new BinaryReader(fileDescriptorStream); var count = reader.ReadUInt32(); while (count > 0) @@ -128,7 +128,7 @@ namespace GreenshotPlugin internal static MemoryStream GetFileContents(System.Windows.Forms.IDataObject dataObject, int index) { //cast the default IDataObject to a com IDataObject - var comDataObject = (IDataObject)dataObject; + var comDataObject = (IDataObject) dataObject; var format = System.Windows.DataFormats.GetDataFormat("FileContents"); if (format == null) @@ -143,7 +143,7 @@ namespace GreenshotPlugin { var formatetc = new FORMATETC { - cfFormat = (short)format.Id, + cfFormat = (short) format.Id, dwAspect = DVASPECT.DVASPECT_CONTENT, lindex = index, tymed = TYMED.TYMED_ISTREAM | TYMED.TYMED_HGLOBAL @@ -152,7 +152,7 @@ namespace GreenshotPlugin //using the com IDataObject interface get the data using the defined FORMATETC comDataObject.GetData(ref formatetc, out medium); } - + return medium.tymed switch { TYMED.TYMED_ISTREAM => GetIStream(medium), @@ -163,13 +163,13 @@ namespace GreenshotPlugin private static MemoryStream GetIStream(STGMEDIUM medium) { //marshal the returned pointer to a IStream object - IStream iStream = (IStream)Marshal.GetObjectForIUnknown(medium.unionmember); + IStream iStream = (IStream) Marshal.GetObjectForIUnknown(medium.unionmember); Marshal.Release(medium.unionmember); //get the STATSTG of the IStream to determine how many bytes are in it var iStreamStat = new System.Runtime.InteropServices.ComTypes.STATSTG(); iStream.Stat(out iStreamStat, 0); - int iStreamSize = (int)iStreamStat.cbSize; + int iStreamSize = (int) iStreamStat.cbSize; //read the data from the IStream into a managed byte array byte[] iStreamContent = new byte[iStreamSize]; diff --git a/src/GreenshotPlugin/GlobalSuppressions.cs b/src/GreenshotPlugin/GlobalSuppressions.cs index c050f5d980bbaf4f7f04fa6cb01422c0eebd5458..148f8734d4145c7536cec4062f00e77f26868c14 100644 GIT binary patch literal 119362 zcmeHQU2hx7mF?#M`455v3>?fv$z+2(1lR{rlw~8*m=Wcj-5CrFT9jnQq9~A*J<5;Y z-E-=y+|||9MNwUpx|j>Wro>`@u@Co_s5@S2X6z@(jw!DAcDTc*uaf6>Zj$7d8 z`2KZNT$(few)hS1g7-1PQA>Pof~(!)H-3HxuOH0_$9WFE@_bkLoZOpSnV*w8;k9PP zKQVfSqj!t)3WLhXAIx|CjL%)+tPAfxCpgEoxr1|@muEl6(L3gDc+3t)`HlHa=jOXC z@z>0J#@^{Aj^t;rF;d>e2!Ac`4S0VO^UTj`=NaJ`KKBJaGc%v%U-C_PJfHp)XW)58 z_{@3nof*F~pXKiyo#ILIuKD*ljy`jqMtMJ{=6j5AJzhiZt|~Km7WVq(leT!_`6;(c zJe_6n2V95JIV(QleR*yy^|^UGQe_?nMo8J09j< zm?P~IcJH;kix0fd!5#2tXyz(s)f7kdasQMA?{R^yRtGM{*XZVclv#_tH zI7c~m<+wwdtfNS028xUu^#XI~@mg5X0gN=*V`2WhxyE%^Gcm5G~yIcGY zzkR`H-(hTwPxINI;+(f;Uh;TiNH~dXFgM?o&+DZpEn<=PL3aGENOgzraW}7VcgIB! zPkIl}|EPG6tDF>X@&5r{Px0OX?&X`}_mJD~i(kxB>?YFW8SyC!4(52iAIuXbd*6BJ z`wOu5J<#W)ZfImqh8g3TQ2ISc=D%lbZ*nMpnU(rEt#kVWF>dnyKqlVvw{eNa`Li&)_(j{Yr-hT^A*v400 z;rJOmnjdi#V-_>`JTZ&F$HzP4_brS6DE7huv8~F=Qp(x_YRa-D6^;bN*;%t zefU@OddCKJ*FcJoFOG`GwhLtVqx8Rgl!%TA;iq}T#m~?1Yn#uh=;|iATnSnZIx?tY zT#XSzpM@;b*f>g?4ZBctgJ?|7LA6#MKzTzJ{l(^ZjY&`@^Mt2qY|xCa|$!ckcVMyjjYEs_^W0&!`A^ z8U$41>ZLugZ&;jpMzR3&6j!isBx7*}`||QWw$7+Kk#P=oDD6=n53baezti$}D5qj` zD=${&De4k`2WgkQK1JSS30|j%62`>KM_%Jw=!YM0=C=XQ!qo*aTOd3ZvO-UR&|mRQ zm_sY|Owaf>w1lb6p6hHfJ9yXhu~uc4!V>%Tt8`vrMlvh5$RJ;|eUYB9bU2?la&0ON z=J3>;=2F!jcCqTCvxoD|4Er(D6?a{vxtuASD{xaM_Lxk7F0=di8UXAAMU+?ehjsWebWz4bSQi)I1UJg_8t;)GXmilRp*N?|plzt0wbCBm zOO!SIG08W5&Y$OE8HA(1?wE2wmpQ<4y3~b>&(Vi17~=zu$Ize>Pb=|uQQ_6r{~_4^ zjj0zQ^Y@G=O53rX@jZb(DLDkL2JkaZWR5x37I5tYtL_;c5KZHvDdx#kBW9)Vk>Z%H z+vV4Gdel;BZ7Ju_e%A91RQD;=nGfE=AvR>>X=9kW_?y!Q+ zMzZWS*tu0LCOH{dBi3Z&_%=)m4WUe(mZ{U^ZmQULsE3mR55DD+;+%@Hv>1C@``TqD z+TA@^$+EIuvOk+(r4%^=@e8<8_Xc;(?Dx#9)aB}HTC4Tkfg1_*=YiPv55lqG zx@Xmykai|)f^A*Ab0rMpPbctvSgXECe@`%^QE2I6@YJgr){Qzyezf#~eQc!An?942 z2x%TshUq@T2zHpUu(79oqowM7AJU*GMP{^quZpy^NP8Nqj(wBZ)rpbQLs&u+SVyj< zw1>a>nLFgZFHF{r`p;*#n7vaSYmdF=T90aFQJ52B`5x7^>2>Y%q1Z;o-k?HFYT8~E z|J@1Xz6$sn)majvrv2OqXf}Z#OI9nx*g7M#ZG>GK1=Zr`H9{`>?=*7+O@m`N)?Y!)K7MFi9z0 zm0>P2luFxc(}S0`9BUa?_rO@q2khx<&*yer^KJfk#NE{*im6;M#TD_g8wJ->xk&JN zU*iK^j{t`BI->;ah$r@6InPzPx$P?vlCISV(g{!2u`uS}J~LE3qpKClEZiwsD8O5TcswQXgIGAWPA+{pdMBWaI{n zbcbGJ>@@rdc~W*dkm|Y^TGW#0q9wr{9GTZDGh5Urtg2ydYl*dhXOQzX>L%-2Cgxj+ zmI+nKxcVo)Hn3?_V#pW;yU;L-dr_;;dW?Q5 zajX%NZbnGn8J}nVH8ao7yKW!M>Ta|?%3L;54b?>r<;z!M8LougESzuG);lb_5)b=E z)Gs>Q^O)^|23g4=JD}(c&n;8u&v5Z29xBuD9F{d-%IJAAdTb7-=yp=qA*}M6;z#=A zDsFPX4ZRKSpX%BIn?_FPnu;CfmAKyp_cO}LZg7!fy~8+ys%ww!FKh)Q=ElVC-`V9*UtxwMh=zMC2^bya&8iCA(=X;Rh#LUtv*U!w#rJDx% zs`rqaCYOCLxn7g&fo~yke>WUu;e1$_6>SUT7MGCajc4Dh9CMJP#Bf&6%Bnr>#%5K{ zImo$g9S@8b$l7|Yp1_r;%zzvACERw(%%J2SwxZiP=Mh8oo}IcOP5 z^e14PG5XN1xoS7$8GkJ!#py!AQUS(V5J_lRJ)REOh1EXx7WI8mbzM&+b;Whbh+J(_jQ2i z2lX*?@iCk6(1r`bsL*PXe5y&P1!aF1R)4)R*_G*|y;0ZuP|Gj}%P=f|t|yh9z1nw* zYu=$t(UNBt!_8UK4&dIo@hD|`6osy-l@57SIvfBa>@e!eFijWA@R{wJShY@aUm0oT zyN?wI6VzE%Yg||DUe=yBetl2?4~)OMu3M_K>YisrOvPP5yEk6Gb9 z?*8bn&kSKtGhq2-z(lfrc-=8Qrn5AMS<1W>_oQT2{v2z=;xY|u2c5gQ&0SW`Pr%C` zz|M@djN!$8fd|W7OkWl{b90!v64$6plHF|2Ax)8`>e{>`4b0=Pk6n2QKSOYYX0#KR6zu{S{-3NwQ2FE~dX0e@e|GS~Xv-0FKN?@P#iVJwY# zB}Ws_4!aznS|P1gcn&+gz6$*mxR?STWP?>b?yA;=%LBfCc(~4KpL=7BY1Q{Cty%w0 zW8cD#iGI|&^gQa)Mbixsi?{>hv2)r8p4Pt6cGP-vtPPghs`l6$ASTUf&Qq=B#IsJz zkDKw6j)8`1u9s+_@3h4IuVV*QIW8@he3p`H>AKup*5wKZx%yJ-2w8=BW^mRXFHL7x zJ1qwu;@%85&``F+XN-ANqB%%Zy1jGH;hD`TFJnEBUH3zxh0Bek)tj&0B4q4TPz zk%uiQ$gm8a5*4;S+Me63lTMNKvFEk-tcc44akid@KFrd1wCthoT7tV~t>Y3tE;W%_ z4mns3)%wPL^qsFKOnBmAC&c!uOtUvf*>b#%2%MtTS^gDO4 zYu*`tqz8z-8#2OM+}S_zK0Q<0A@;}|vp{6&3h(+15oZCZEgaXl!^Kkf*&$Cvw6k4H ztVk4NT)YErMQd=ELQso=_NG5e7Sm1K0ADkZ%y@#^g{D3N4NISA9FDk9t&B^ zX)W8dXOnNlyZ+_@{pOmUrj<@v@1`@Z3mk0aV&@g*#~dPKgHzO|k*UY{$10?9PF3Uj zvH6f&&$m2THcdrZANAK_llQR#dI|h-wq9^}rP9c?t$V#hOkF|F6WDxtZ%d#R^Xvpk<>S=|%YXBn4EdSDc;{h^n_ z4$Q084T{XIztwGh;7-F3`x)ejXVTfxAKf@1T{$ADv)Yqt|u+CDfDGJ@IBCgAb`#VrIhc!gcg3Q5K zj$|Q5K-@S$e9&fHUM201h0;7VENY;JQ_qJP&|bNvzX zS-hGQeOKM{xm9GoS5wVI`=iPeIrGF2nZkvME;CE$BEr`PuHUO1k{gH6t7Y9Md%>xc ziRI7Gi=WI>>0*8FaU8-!78=L$COhVt{ z4wdDsCBH(hl9j}^4*d;yW@Pq@V2>DbPE4ElxN$8Cf9x?;x$gP2j_x^EEj*6ZO0@NX zu?1=q%BYEtt5_9nTkI%L<;GJIsXYd2#)hY=JCeq*qq5FT*4&wh>=2i+dNH|ps{_b# z&#c8`+_FBCxg!QECai^#a&H9H6tbT21)_(0SQDAk%E;9=MhIC=_N$LFUuU>{lG;{P z9n@tVR7KGNyqp_U4cuY%4_D@X0z0vqQ~E8$P@_`rvXmJcV*aempi$3o9S?J8OH>=3 zLEhI`;qYtC$Bp?SW%R>m4VO{k)kjUE8dKR^<$ap!BY&TAt`U@e9%G>Ci`QE~*<%47 z<=&Is>cOzu((vV6Ulr)a;(Z&Wz9!V=hA?k%?rV&z+cB;%DhALf%@f7uWb=@LsjhKmHZeQ_}6Mn?r`BJe8H;tgs zH5Ef$>G-w2?x{0^jcdk{RINO>$Lzuem;M!uYxH1?Gycl1HuHuxGU|us=7%;T=Ezv4 zmq5VBTAai6N>t0_q-8|jGT+Jc%%IhK!HRr!Hs>~*dywVCM4??f^b|7YzZ;#$h`Mc4 zTuC}OaxZAsV%-|6-y#(OFOG%SrfY|(wibGY6FYD^nm05|?S*w{PETBYt&7R9=W;=GoRT za2M@RU~cI~fPFWXX+YvsI;6%(>j#>Y}D%C0!OL{#u4GPK8d zdS|AhnVsq{U=7+xp{_74J7W#+pAkEiSe+Bsb0PH6hfYy-I7D9k1pAmB;fMRazQXUS z0rS#;b~UJrte)vn5XV(}=Bi(@4-Q~&1a{n!z0-X?S?x8f{#{P~oy37$sSm*P^__4e z0w|FjU;b6yx(mi(%wUSM?1Fok0cW;z3H&x8NX{+{Smj2=R=#U41WC({X1PO{Dbb`{ zloJ=#vz4)Z0K;6AV#h8;&1O)u>HSpw>Z^K=V}0Eg(|aY)_!_b8NP9cZ)yeX$71f(T z^=7&f3Kz;+aaWcx`(GuTpM*pE&%2zXGR;Y*%!{!vI@gArW3P<;75R>;ucLC$JKx1h z{|S0~e1QMUev)H&zhB__GFGbnA99Ppog-RNmniFe&LLHism|Z+=;6XV5j!<9?@^bz zj7~5fv%bPUfYv_cSNp_jDR#W(9))6iA7IBqiDAYNptjm(Y_;c%8My)`p?12t=ub9=jmqV>1HA!+y#hhk_f-}H@{kxG&6vgft;tjNm? zc~T3$Z+xDm@r1d;)wLMy%2ut|$gg6fT6gJ7S*^sJti*lThpeDwX`?8kcbm~Ahr`GZSKbSs9|0%K@f-jd^eXE6C)!B1MvS`Np-$v`jMbu)uk4p} z2RYl_^n7jIgAYlL___F{R%>LX9$q78M->y>h6#xd$E6-0RZMgp6Mf_?gd_T>!=D!K z5G@?v+Y6`2d9icU2l##?*b7(S5$c5-@WdQ!!P@;*xsCRb3c17g$ceqi-5q1U?jMRh Z*fK}Od)yCuvkaiIPB8ukuS3W3_3kp{Aa{Qs^ld5?Bei0)aMHngL8WTU>%=@+`Ro>fmMP?= z`$QLXS5?98NC8{gSvBe|?UD{Qz=@hhn5{nQHNG~vR=K!ERKi4U+HZx5jUll@2fMpt zE(9wNXE28&>mB2;{gJp8wGAaBWJk3K!F!FP1LSJS5)5xD#!D+BS=-nXnSGQ2*o@?Hp-O$i7F#C0ZD1 z-)E9Bn0&s{-%)Ioe6>G2Xo5>vb(Ym)@ zJx?Ncc$VEGlIP90sML#rgLoZhQ< zip$U;amcpD-;Y|6fIT{wgr*NnY(TER&aWQ=LrLhK-zq0w6ZGSP=$Xs7O6J}WR6!tr z3}WYaoQh~u5_J@HZ@2h)3xr2K z#`08~HE5`iN*$vm+E|_%)J9x>J17Qx>OuJX3mUSR8y404DobDS=Ul8mWj+x1h1{9G zhRciU>9bvK3E(vQ3tte#V8*x;I z$NBZh>^U)MHh}&g4pOQ!FIIW+%^BP8p099XKmEan^xQrUg~qTfd?x54a(ZruJp=sv zGciThPl*NES3UR>PIyKCxYdQ_=$Asj!=ZTgmt{UyJ&MGybT_G{>4TBq`1>laU*U=J zDcJoxp$6Qo8m@{JJM6VTX@PrX{@vn62mkVstrAlIq-mA<^&kwp{~JL=W;cmgaZm_; zSE!}Zm9p+${(-yRnn|C8@Z2`pQX!)Bhr`A8U0V{t3F{kOm+Ry~I*2&;D8+ND4AA{n zjHPC@l@`n7A(w5Nz-+Z4Gg}(Xyx3(kcN7`9${aaQm1U#J5F9J`m772 zkdU5+LL@0-B-IE>&byT4yv8I;rXnjBW-blfqj+f?0;XRgG07riQti0RWE-K$tC*VHL2Poz9YJxE6oS(%L2}v{qSG{y zogSs&Ny^fbwTn*E5EH_A8lM@Wx^5Xwz2L&-vj>ZOW;ilU?tqg)z}+8~0I zrTWGcNo~(XDX-Kl)y?%QdJWN3`;1fFRF_jcC51rcQWKS>3rq`0Yp&UHBO>|#@P+>Y D_m=qV diff --git a/src/GreenshotPlugin/Hooking/WindowsEventHook.cs b/src/GreenshotPlugin/Hooking/WindowsEventHook.cs index 8893bd57e..06ae3a83c 100644 --- a/src/GreenshotPlugin/Hooking/WindowsEventHook.cs +++ b/src/GreenshotPlugin/Hooking/WindowsEventHook.cs @@ -26,124 +26,126 @@ using GreenshotPlugin.UnmanagedHelpers.Enums; namespace GreenshotPlugin.Hooking { - /// - /// The WinEventHook can register handlers to become important windows events - /// This makes it possible to know a.o. when a window is created, moved, updated and closed. - /// - public class WindowsEventHook : IDisposable - { - private readonly WinEventDelegate _winEventHandler; - private GCHandle _gcHandle; + /// + /// The WinEventHook can register handlers to become important windows events + /// This makes it possible to know a.o. when a window is created, moved, updated and closed. + /// + public class WindowsEventHook : IDisposable + { + private readonly WinEventDelegate _winEventHandler; + private GCHandle _gcHandle; - /// - /// Used with Register hook - /// - /// - /// - /// - /// - /// - /// - public delegate void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); + /// + /// Used with Register hook + /// + /// + /// + /// + /// + /// + /// + public delegate void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); - /// - /// Create a WindowsEventHook object - /// - public WindowsEventHook() - { - _winEventHandler = WinEventDelegateHandler; - _gcHandle = GCHandle.Alloc(_winEventHandler); - } + /// + /// Create a WindowsEventHook object + /// + public WindowsEventHook() + { + _winEventHandler = WinEventDelegateHandler; + _gcHandle = GCHandle.Alloc(_winEventHandler); + } - [DllImport("user32", SetLastError = true)] - private static extern bool UnhookWinEvent(IntPtr hWinEventHook); - [DllImport("user32", SetLastError = true)] - private static extern IntPtr SetWinEventHook(WinEvent eventMin, WinEvent eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, int idProcess, int idThread, WinEventHookFlags dwFlags); + [DllImport("user32", SetLastError = true)] + private static extern bool UnhookWinEvent(IntPtr hWinEventHook); - /// - /// Used with SetWinEventHook - /// - /// - /// - /// - /// - /// - /// - /// - private delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); + [DllImport("user32", SetLastError = true)] + private static extern IntPtr SetWinEventHook(WinEvent eventMin, WinEvent eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, int idProcess, int idThread, + WinEventHookFlags dwFlags); - private readonly IDictionary _winEventHandlers = new Dictionary(); + /// + /// Used with SetWinEventHook + /// + /// + /// + /// + /// + /// + /// + /// + private delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); - /// - /// Are hooks active? - /// - public bool IsHooked => _winEventHandlers.Count > 0; + private readonly IDictionary _winEventHandlers = new Dictionary(); - /// - /// Hook a WinEvent - /// - /// - /// - /// true if success - public void Hook(WinEvent winEvent, WinEventHandler winEventHandler) - { - Hook(winEvent, winEvent, winEventHandler); - } + /// + /// Are hooks active? + /// + public bool IsHooked => _winEventHandlers.Count > 0; - /// - /// Hook a WinEvent - /// - /// - /// - /// - public void Hook(WinEvent winEventStart, WinEvent winEventEnd, WinEventHandler winEventHandler) - { - var hookPtr = SetWinEventHook(winEventStart, winEventEnd, IntPtr.Zero, _winEventHandler, 0, 0, WinEventHookFlags.WINEVENT_SKIPOWNPROCESS | WinEventHookFlags.WINEVENT_OUTOFCONTEXT); - _winEventHandlers.Add(hookPtr, winEventHandler); - } + /// + /// Hook a WinEvent + /// + /// + /// + /// true if success + public void Hook(WinEvent winEvent, WinEventHandler winEventHandler) + { + Hook(winEvent, winEvent, winEventHandler); + } - /// - /// Remove all hooks - /// - private void Unhook() - { - foreach (var hookPtr in _winEventHandlers.Keys) - { - if (hookPtr != IntPtr.Zero) - { - UnhookWinEvent(hookPtr); - } - } - _winEventHandlers.Clear(); - _gcHandle.Free(); - } + /// + /// Hook a WinEvent + /// + /// + /// + /// + public void Hook(WinEvent winEventStart, WinEvent winEventEnd, WinEventHandler winEventHandler) + { + var hookPtr = SetWinEventHook(winEventStart, winEventEnd, IntPtr.Zero, _winEventHandler, 0, 0, + WinEventHookFlags.WINEVENT_SKIPOWNPROCESS | WinEventHookFlags.WINEVENT_OUTOFCONTEXT); + _winEventHandlers.Add(hookPtr, winEventHandler); + } - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Unhook(); - } + /// + /// Remove all hooks + /// + private void Unhook() + { + foreach (var hookPtr in _winEventHandlers.Keys) + { + if (hookPtr != IntPtr.Zero) + { + UnhookWinEvent(hookPtr); + } + } - /// - /// Call the WinEventHandler for this event - /// - /// - /// - /// - /// - /// - /// - /// - private void WinEventDelegateHandler(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) - { - if (_winEventHandlers.TryGetValue(hWinEventHook, out var handler)) - { - handler(eventType, hWnd, idObject, idChild, dwEventThread, dwmsEventTime); - } - } + _winEventHandlers.Clear(); + _gcHandle.Free(); + } - } + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Unhook(); + } -} + /// + /// Call the WinEventHandler for this event + /// + /// + /// + /// + /// + /// + /// + /// + private void WinEventDelegateHandler(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) + { + if (_winEventHandlers.TryGetValue(hWinEventHook, out var handler)) + { + handler(eventType, hWnd, idObject, idChild, dwEventThread, dwmsEventTime); + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs b/src/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs index 97634b92f..626e3424f 100644 --- a/src/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs +++ b/src/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs @@ -25,147 +25,156 @@ using GreenshotPlugin.UnmanagedHelpers.Enums; namespace GreenshotPlugin.Hooking { - /// - /// Event arguments for the WindowOpenCloseEvent - /// - public class WindowOpenCloseEventArgs : EventArgs - { - public bool IsOpen { get; set; } - /// - /// HWnd of the window which has a changed title - /// - public IntPtr HWnd - { - get; - set; - } + /// + /// Event arguments for the WindowOpenCloseEvent + /// + public class WindowOpenCloseEventArgs : EventArgs + { + public bool IsOpen { get; set; } - /// - /// Title which is changed - /// - public string Title - { - get; - set; - } + /// + /// HWnd of the window which has a changed title + /// + public IntPtr HWnd { get; set; } - public string ClassName { get; set; } - } - /// - /// Delegate for the window open close event - /// - /// - public delegate void WindowOpenCloseEventDelegate(WindowOpenCloseEventArgs eventArgs); + /// + /// Title which is changed + /// + public string Title { get; set; } - /// - /// Monitor all new and destroyed windows - /// - public sealed class WindowsOpenCloseMonitor : IDisposable - { - private WindowsEventHook _hook; - private readonly object _lockObject = new object(); - // ReSharper disable once InconsistentNaming - private event WindowOpenCloseEventDelegate _windowOpenCloseEvent; + public string ClassName { get; set; } + } - /// - /// Add / remove event handler to the title monitor - /// - public event WindowOpenCloseEventDelegate WindowOpenCloseChangeEvent - { - add - { - lock (_lockObject) - { - if (_hook == null) - { - _hook = new WindowsEventHook(); - _hook.Hook(WinEvent.EVENT_OBJECT_CREATE, WinEvent.EVENT_OBJECT_DESTROY, WinEventHandler); - } - _windowOpenCloseEvent += value; - } - } - remove - { - lock (_lockObject) - { - _windowOpenCloseEvent -= value; - if (_windowOpenCloseEvent == null || _windowOpenCloseEvent.GetInvocationList().Length == 0) - { - if (_hook != null) - { - _hook.Dispose(); - _hook = null; - } - } - } - } - } + /// + /// Delegate for the window open close event + /// + /// + public delegate void WindowOpenCloseEventDelegate(WindowOpenCloseEventArgs eventArgs); - /// - /// WinEventDelegate for the creation and destruction - /// - /// - /// - /// - /// - /// - /// - private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) - { - if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) - { - return; - } - if (eventType == WinEvent.EVENT_OBJECT_CREATE) - { - if (_windowOpenCloseEvent != null) - { - var windowsDetails = new WindowDetails(hWnd); - _windowOpenCloseEvent(new WindowOpenCloseEventArgs { HWnd = hWnd, IsOpen = true, Title = windowsDetails.Text, ClassName = windowsDetails.ClassName }); - } - } - if (eventType == WinEvent.EVENT_OBJECT_DESTROY) - { - _windowOpenCloseEvent?.Invoke(new WindowOpenCloseEventArgs { HWnd = hWnd, IsOpen = false }); - } - } + /// + /// Monitor all new and destroyed windows + /// + public sealed class WindowsOpenCloseMonitor : IDisposable + { + private WindowsEventHook _hook; + private readonly object _lockObject = new object(); - private bool _disposedValue; // To detect redundant calls + // ReSharper disable once InconsistentNaming + private event WindowOpenCloseEventDelegate _windowOpenCloseEvent; - /// - /// Dispose the underlying hook - /// - public void Dispose(bool disposing) - { - if (_disposedValue) - { - return; - } - lock (_lockObject) - { - _hook?.Dispose(); - } - _disposedValue = true; - } + /// + /// Add / remove event handler to the title monitor + /// + public event WindowOpenCloseEventDelegate WindowOpenCloseChangeEvent + { + add + { + lock (_lockObject) + { + if (_hook == null) + { + _hook = new WindowsEventHook(); + _hook.Hook(WinEvent.EVENT_OBJECT_CREATE, WinEvent.EVENT_OBJECT_DESTROY, WinEventHandler); + } - /// - /// Make sure the finalizer disposes the underlying hook - /// - ~WindowsOpenCloseMonitor() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(false); - } + _windowOpenCloseEvent += value; + } + } + remove + { + lock (_lockObject) + { + _windowOpenCloseEvent -= value; + if (_windowOpenCloseEvent == null || _windowOpenCloseEvent.GetInvocationList().Length == 0) + { + if (_hook != null) + { + _hook.Dispose(); + _hook = null; + } + } + } + } + } - /// - /// Dispose the underlying hook - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - GC.SuppressFinalize(this); - } - } + /// + /// WinEventDelegate for the creation and destruction + /// + /// + /// + /// + /// + /// + /// + private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) + { + if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) + { + return; + } -} + if (eventType == WinEvent.EVENT_OBJECT_CREATE) + { + if (_windowOpenCloseEvent != null) + { + var windowsDetails = new WindowDetails(hWnd); + _windowOpenCloseEvent(new WindowOpenCloseEventArgs + { + HWnd = hWnd, + IsOpen = true, + Title = windowsDetails.Text, + ClassName = windowsDetails.ClassName + }); + } + } + + if (eventType == WinEvent.EVENT_OBJECT_DESTROY) + { + _windowOpenCloseEvent?.Invoke(new WindowOpenCloseEventArgs + { + HWnd = hWnd, + IsOpen = false + }); + } + } + + private bool _disposedValue; // To detect redundant calls + + /// + /// Dispose the underlying hook + /// + public void Dispose(bool disposing) + { + if (_disposedValue) + { + return; + } + + lock (_lockObject) + { + _hook?.Dispose(); + } + + _disposedValue = true; + } + + /// + /// Make sure the finalizer disposes the underlying hook + /// + ~WindowsOpenCloseMonitor() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(false); + } + + /// + /// Dispose the underlying hook + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs b/src/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs index c35dbf2e8..081b1f28f 100644 --- a/src/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs +++ b/src/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs @@ -25,140 +25,141 @@ using GreenshotPlugin.UnmanagedHelpers.Enums; namespace GreenshotPlugin.Hooking { - /// - /// Event arguments for the TitleChangeEvent - /// - public class TitleChangeEventArgs : EventArgs - { - /// - /// HWnd of the window which has a changed title - /// - public IntPtr HWnd - { - get; - set; - } + /// + /// Event arguments for the TitleChangeEvent + /// + public class TitleChangeEventArgs : EventArgs + { + /// + /// HWnd of the window which has a changed title + /// + public IntPtr HWnd { get; set; } - /// - /// Title which is changed - /// - public string Title - { - get; - set; - } - } - /// - /// Delegate for the title change event - /// - /// - public delegate void TitleChangeEventDelegate(TitleChangeEventArgs eventArgs); + /// + /// Title which is changed + /// + public string Title { get; set; } + } - /// - /// Monitor all title changes - /// - public sealed class WindowsTitleMonitor : IDisposable - { - private WindowsEventHook _hook; - private readonly object _lockObject = new object(); - // ReSharper disable once InconsistentNaming - private event TitleChangeEventDelegate _titleChangeEvent; + /// + /// Delegate for the title change event + /// + /// + public delegate void TitleChangeEventDelegate(TitleChangeEventArgs eventArgs); - /// - /// Add / remove event handler to the title monitor - /// - public event TitleChangeEventDelegate TitleChangeEvent - { - add - { - lock (_lockObject) - { - if (_hook == null) - { - _hook = new WindowsEventHook(); - _hook.Hook(WinEvent.EVENT_OBJECT_NAMECHANGE, WinEventHandler); - } - _titleChangeEvent += value; - } - } - remove - { - lock (_lockObject) - { - _titleChangeEvent -= value; - if (_titleChangeEvent == null || _titleChangeEvent.GetInvocationList().Length == 0) - { - if (_hook != null) - { - _hook.Dispose(); - _hook = null; - } - } - } - } - } + /// + /// Monitor all title changes + /// + public sealed class WindowsTitleMonitor : IDisposable + { + private WindowsEventHook _hook; + private readonly object _lockObject = new object(); - /// - /// WinEventDelegate for the creation & destruction - /// - /// - /// - /// - /// - /// - /// - private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) - { - if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) - { - return; - } - if (eventType == WinEvent.EVENT_OBJECT_NAMECHANGE) - { - if (_titleChangeEvent != null) - { - string newTitle = new WindowDetails(hWnd).Text; - _titleChangeEvent(new TitleChangeEventArgs { HWnd = hWnd, Title = newTitle }); - } - } - } + // ReSharper disable once InconsistentNaming + private event TitleChangeEventDelegate _titleChangeEvent; - private bool _disposedValue; // To detect redundant calls + /// + /// Add / remove event handler to the title monitor + /// + public event TitleChangeEventDelegate TitleChangeEvent + { + add + { + lock (_lockObject) + { + if (_hook == null) + { + _hook = new WindowsEventHook(); + _hook.Hook(WinEvent.EVENT_OBJECT_NAMECHANGE, WinEventHandler); + } - /// - /// Dispose the underlying hook - /// - public void Dispose(bool disposing) - { - if (_disposedValue) - { - return; - } - lock (_lockObject) - { - _hook?.Dispose(); - } - _disposedValue = true; - } + _titleChangeEvent += value; + } + } + remove + { + lock (_lockObject) + { + _titleChangeEvent -= value; + if (_titleChangeEvent == null || _titleChangeEvent.GetInvocationList().Length == 0) + { + if (_hook != null) + { + _hook.Dispose(); + _hook = null; + } + } + } + } + } - /// - /// Make sure the finalizer disposes the underlying hook - /// - ~WindowsTitleMonitor() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(false); - } + /// + /// WinEventDelegate for the creation & destruction + /// + /// + /// + /// + /// + /// + /// + private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) + { + if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) + { + return; + } - /// - /// Dispose the underlying hook - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - GC.SuppressFinalize(this); - } - } + if (eventType == WinEvent.EVENT_OBJECT_NAMECHANGE) + { + if (_titleChangeEvent != null) + { + string newTitle = new WindowDetails(hWnd).Text; + _titleChangeEvent(new TitleChangeEventArgs + { + HWnd = hWnd, + Title = newTitle + }); + } + } + } -} + private bool _disposedValue; // To detect redundant calls + + /// + /// Dispose the underlying hook + /// + public void Dispose(bool disposing) + { + if (_disposedValue) + { + return; + } + + lock (_lockObject) + { + _hook?.Dispose(); + } + + _disposedValue = true; + } + + /// + /// Make sure the finalizer disposes the underlying hook + /// + ~WindowsTitleMonitor() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(false); + } + + /// + /// Dispose the underlying hook + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs b/src/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs index 0890cc628..234a1ec29 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs @@ -21,15 +21,18 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F1D8-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLBodyElement { - string scroll { - set; - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - } -} +namespace GreenshotPlugin.IEInterop +{ + [ComImport, Guid("3050F1D8-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLBodyElement + { + string scroll + { + set; + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs b/src/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs index cfbab4b3f..95539a5f7 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs @@ -21,47 +21,61 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050f3db-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLCurrentStyle { +namespace GreenshotPlugin.IEInterop +{ + [ComImport, Guid("3050f3db-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLCurrentStyle + { /// styleFloat property of IHTMLStyle interface. - string styleFloat { + string styleFloat + { [DispId(-2147413042)] [return: MarshalAs(UnmanagedType.BStr)] get; } - - string left { - [DispId(-2147418112 + 3)] - [return: MarshalAs(UnmanagedType.BStr)] - get; + + string left + { + [DispId(-2147418112 + 3)] + [return: MarshalAs(UnmanagedType.BStr)] + get; } - string top { - [DispId(-2147418112 + 4)] - [return: MarshalAs(UnmanagedType.BStr)] - get; + + string top + { + [DispId(-2147418112 + 4)] + [return: MarshalAs(UnmanagedType.BStr)] + get; } - string width { - [DispId(-2147418112 + 5)] - [return: MarshalAs(UnmanagedType.BStr)] - get; + + string width + { + [DispId(-2147418112 + 5)] + [return: MarshalAs(UnmanagedType.BStr)] + get; } - string height { - [DispId(-2147418112 + 6)] - [return: MarshalAs(UnmanagedType.BStr)] - get; + + string height + { + [DispId(-2147418112 + 6)] + [return: MarshalAs(UnmanagedType.BStr)] + get; } - string right { - [DispId(-2147418112 + 0x4d)] - [return: MarshalAs(UnmanagedType.BStr)] - get; + + string right + { + [DispId(-2147418112 + 0x4d)] + [return: MarshalAs(UnmanagedType.BStr)] + get; } - string bottom { - [DispId(-2147418112 + 0x4e)] - [return: MarshalAs(UnmanagedType.BStr)] - get; + + string bottom + { + [DispId(-2147418112 + 0x4e)] + [return: MarshalAs(UnmanagedType.BStr)] + get; } - } -} + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLDocument.cs b/src/GreenshotPlugin/IEInterop/IHTMLDocument.cs index 5faeda803..3ef5be8a7 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLDocument.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLDocument.cs @@ -21,16 +21,19 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - /// IHTMLDocument interface. - [Guid("626FC520-A41E-11CF-A731-00A0C9082637")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument { - object Script { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - } +namespace GreenshotPlugin.IEInterop +{ + /// IHTMLDocument interface. + [Guid("626FC520-A41E-11CF-A731-00A0C9082637")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument + { + object Script + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLDocument2.cs b/src/GreenshotPlugin/IEInterop/IHTMLDocument2.cs index 6ca8d9c9b..1ee72c537 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLDocument2.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLDocument2.cs @@ -21,57 +21,65 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - /// IHTMLDocument2 interface. - [Guid("332C4425-26CB-11D0-B483-00C04FD90119")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument2 { - IHTMLElement body { - [DispId(1004)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - string title { - [DispId(1012)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - object frames { - [DispId(1019)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - string url { - [DispId(1025)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - IHTMLWindow2 parentWindow { - [DispId(1034)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } +namespace GreenshotPlugin.IEInterop +{ + /// IHTMLDocument2 interface. + [Guid("332C4425-26CB-11D0-B483-00C04FD90119")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument2 + { + IHTMLElement body + { + [DispId(1004)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } - object bgColor { - [DispId(-501)] - get; - } + string title + { + [DispId(1012)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } - IHTMLSelectionObject selection { - [DispId(1017)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } + object frames + { + [DispId(1019)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } - string designMode { - [DispId(1014)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - [DispId(1014)] - set; - } - } -} + string url + { + [DispId(1025)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + IHTMLWindow2 parentWindow + { + [DispId(1034)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + object bgColor { [DispId(-501)] get; } + + IHTMLSelectionObject selection + { + [DispId(1017)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string designMode + { + [DispId(1014)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + [DispId(1014)] set; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLDocument3.cs b/src/GreenshotPlugin/IEInterop/IHTMLDocument3.cs index e12344f62..21d73b54a 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLDocument3.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLDocument3.cs @@ -21,27 +21,30 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - /// IHTMLDocument3 interface. - [Guid("3050F485-98B5-11CF-BB82-00AA00BDCE0B")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument3 { - IHTMLElement documentElement { - [DispId(1075)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } +namespace GreenshotPlugin.IEInterop +{ + /// IHTMLDocument3 interface. + [Guid("3050F485-98B5-11CF-BB82-00AA00BDCE0B")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument3 + { + IHTMLElement documentElement + { + [DispId(1075)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } - [DispId(1086)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLElementCollection getElementsByName([MarshalAs(UnmanagedType.BStr)] string v); + [DispId(1086)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLElementCollection getElementsByName([MarshalAs(UnmanagedType.BStr)] string v); - [DispId(1088)] - IHTMLElement getElementById([MarshalAs(UnmanagedType.BStr)] string v); + [DispId(1088)] + IHTMLElement getElementById([MarshalAs(UnmanagedType.BStr)] string v); - [DispId(1087)] - IHTMLElementCollection getElementsByTagName([MarshalAs(UnmanagedType.BStr)] string v); - } + [DispId(1087)] + IHTMLElementCollection getElementsByTagName([MarshalAs(UnmanagedType.BStr)] string v); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLDocument4.cs b/src/GreenshotPlugin/IEInterop/IHTMLDocument4.cs index 57e4a32ee..09f8d7a02 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLDocument4.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLDocument4.cs @@ -21,11 +21,13 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { +namespace GreenshotPlugin.IEInterop +{ [ComVisible(true), Guid("3050f69a-98b5-11cf-bb82-00aa00bdce0b"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch), TypeLibType(TypeLibTypeFlags.FDual)] - public interface IHTMLDocument4 { + public interface IHTMLDocument4 + { [DispId(1090)] [return: MarshalAs(UnmanagedType.VariantBool)] bool hasFocus(); diff --git a/src/GreenshotPlugin/IEInterop/IHTMLDocument5.cs b/src/GreenshotPlugin/IEInterop/IHTMLDocument5.cs index 60b5aab8c..628652a37 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLDocument5.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLDocument5.cs @@ -21,14 +21,18 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport, ComVisible(true), Guid("3050f80c-98b5-11cf-bb82-00aa00bdce0b"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDual)] - public interface IHTMLDocument5 { - [DispId(1102)] - string compatMode { - [return: MarshalAs(UnmanagedType.BStr)] get; - } - } +namespace GreenshotPlugin.IEInterop +{ + [ComImport, ComVisible(true), Guid("3050f80c-98b5-11cf-bb82-00aa00bdce0b"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDual)] + public interface IHTMLDocument5 + { + [DispId(1102)] + string compatMode + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLElement.cs b/src/GreenshotPlugin/IEInterop/IHTMLElement.cs index aa0a54b79..df1c5d9f4 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLElement.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLElement.cs @@ -21,97 +21,93 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F1FF-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLElement { - [DispId(-2147417611)] - void setAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, object AttributeValue, int lFlags); +namespace GreenshotPlugin.IEInterop +{ + [ComImport, Guid("3050F1FF-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLElement + { + [DispId(-2147417611)] + void setAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, object AttributeValue, int lFlags); - [DispId(-2147417610)] - object getAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); - - long offsetLeft { - [DispId(-2147417104)] - get; - } + [DispId(-2147417610)] + object getAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); - long offsetTop { - [DispId(-2147417103)] - get; - } + long offsetLeft { [DispId(-2147417104)] get; } - long offsetWidth { - [DispId(-2147417102)] - get; - } + long offsetTop { [DispId(-2147417103)] get; } - long offsetHeight { - [DispId(-2147417101)] - get; - } + long offsetWidth { [DispId(-2147417102)] get; } - IHTMLElement offsetParent { - [DispId(-2147417100)] - get; - } - - string className { - [DispId(-2147417111)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } + long offsetHeight { [DispId(-2147417101)] get; } - IHTMLDocument2 document { - [DispId(-2147417094)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } + IHTMLElement offsetParent { [DispId(-2147417100)] get; } - string id { - [DispId(-2147417110)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } + string className + { + [DispId(-2147417111)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } - string innerHTML { - [DispId(-2147417086)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } + IHTMLDocument2 document + { + [DispId(-2147417094)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } - string innerText { - [DispId(-2147417085)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } + string id + { + [DispId(-2147417110)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } - IHTMLStyle style { - [DispId(-2147418038)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } + string innerHTML + { + [DispId(-2147417086)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } - string tagName { - [DispId(-2147417108)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } + string innerText + { + [DispId(-2147417085)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } - string title { - [DispId(-2147418043)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - [DispId(-2147417093)] - void scrollIntoView(bool varargStart); - - IHTMLElementCollection children { - [DispId(-2147417075)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - } + IHTMLStyle style + { + [DispId(-2147418038)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string tagName + { + [DispId(-2147417108)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string title + { + [DispId(-2147418043)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + [DispId(-2147417093)] + void scrollIntoView(bool varargStart); + + IHTMLElementCollection children + { + [DispId(-2147417075)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLElement2.cs b/src/GreenshotPlugin/IEInterop/IHTMLElement2.cs index 44ace8d30..df5a5d9d4 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLElement2.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLElement2.cs @@ -21,19 +21,22 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F434-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLElement2 { - [DispId(-2147417067)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLRect getBoundingClientRect(); +namespace GreenshotPlugin.IEInterop +{ + [ComImport, Guid("3050F434-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLElement2 + { + [DispId(-2147417067)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLRect getBoundingClientRect(); - IHTMLCurrentStyle currentStyle { - [DispId(-2147417105)] - [return: MarshalAs(UnmanagedType.Interface)] //IHTMLCurrentStyle - get; - } - } + IHTMLCurrentStyle currentStyle + { + [DispId(-2147417105)] + [return: MarshalAs(UnmanagedType.Interface)] //IHTMLCurrentStyle + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs b/src/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs index d9a7211dc..d8ac07646 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs @@ -22,12 +22,14 @@ using System.Collections; using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport(), ComVisible(true), - Guid("3050F21F-98B5-11CF-BB82-00AA00BDCE0B"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDispatchable)] - public interface IHTMLElementCollection : IEnumerable { - new IEnumerator GetEnumerator(); - } +namespace GreenshotPlugin.IEInterop +{ + [ComImport(), ComVisible(true), + Guid("3050F21F-98B5-11CF-BB82-00AA00BDCE0B"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDispatchable)] + public interface IHTMLElementCollection : IEnumerable + { + new IEnumerator GetEnumerator(); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs b/src/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs index d9566c0cc..db68866d2 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs @@ -21,11 +21,13 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComVisible(true), ComImport(), Guid("3050f311-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLFrameBase { +namespace GreenshotPlugin.IEInterop +{ + [ComVisible(true), ComImport(), Guid("3050f311-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLFrameBase + { //dispinterface IHTMLFrameBase { // properties: // methods: @@ -67,38 +69,40 @@ namespace GreenshotPlugin.IEInterop { // BSTR scrolling(); //}; // [DispId(HTMLDispIDs.DISPID_IHTMLFRAMEBASE_SRC)] - string src { - [return: MarshalAs(UnmanagedType.BStr)] - get; + string src + { + [return: MarshalAs(UnmanagedType.BStr)] + get; } - string name { - [return: MarshalAs(UnmanagedType.BStr)] - get; + + string name + { + [return: MarshalAs(UnmanagedType.BStr)] + get; } - object border { - get; + + object border { get; } + + string frameBorder + { + [return: MarshalAs(UnmanagedType.BStr)] + get; } - string frameBorder { - [return: MarshalAs(UnmanagedType.BStr)] - get; + + object frameSpacing { get; } + object marginWidth { get; } + object marginHeight { get; } + + bool noResize + { + [return: MarshalAs(UnmanagedType.VariantBool)] + get; } - object frameSpacing { - get; - } - object marginWidth { - get; - } - object marginHeight { - get; - } - bool noResize { - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - string scrolling { - [return: MarshalAs(UnmanagedType.BStr)] - get; + + string scrolling + { + [return: MarshalAs(UnmanagedType.BStr)] + get; } } - -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs b/src/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs index 2c651db26..41b759aef 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs @@ -21,19 +21,18 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport(), ComVisible(true), - Guid("332C4426-26CB-11D0-B483-00C04FD90119"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDispatchable)] - public interface IHTMLFramesCollection2 { - [DispId(0)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLWindow2 item(int pvarIndex); +namespace GreenshotPlugin.IEInterop +{ + [ComImport(), ComVisible(true), + Guid("332C4426-26CB-11D0-B483-00C04FD90119"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDispatchable)] + public interface IHTMLFramesCollection2 + { + [DispId(0)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLWindow2 item(int pvarIndex); - long length { - [DispId(1001)] - get; - } - } + long length { [DispId(1001)] get; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLRect.cs b/src/GreenshotPlugin/IEInterop/IHTMLRect.cs index c2d6d375a..1b2f8363c 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLRect.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLRect.cs @@ -21,29 +21,19 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F4A3-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLRect { - int bottom { - [DispId(1004)] - get; - } +namespace GreenshotPlugin.IEInterop +{ + [ComImport, Guid("3050F4A3-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLRect + { + int bottom { [DispId(1004)] get; } - int left { - [DispId(1001)] - get; - } + int left { [DispId(1001)] get; } - int right { - [DispId(1003)] - get; - } + int right { [DispId(1003)] get; } - int top { - [DispId(1002)] - get; - } + int top { [DispId(1002)] get; } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLScreen.cs b/src/GreenshotPlugin/IEInterop/IHTMLScreen.cs index f65b77da7..082935187 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLScreen.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLScreen.cs @@ -21,18 +21,14 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F35C-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLScreen { - [DispId(1003)] - int width { - get; - } - [DispId(1004)] - int height { - get; - } - } -} +namespace GreenshotPlugin.IEInterop +{ + [ComImport, Guid("3050F35C-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLScreen + { + [DispId(1003)] int width { get; } + [DispId(1004)] int height { get; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLScreen2.cs b/src/GreenshotPlugin/IEInterop/IHTMLScreen2.cs index 3814da360..9870f889e 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLScreen2.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLScreen2.cs @@ -21,29 +21,19 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F84A-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLScreen2 { - int logicalXDPI { - [DispId(1009)] - get; - } +namespace GreenshotPlugin.IEInterop +{ + [ComImport, Guid("3050F84A-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLScreen2 + { + int logicalXDPI { [DispId(1009)] get; } - int logicalYDPI { - [DispId(1010)] - get; - } + int logicalYDPI { [DispId(1010)] get; } - int deviceXDPI { - [DispId(1011)] - get; - } + int deviceXDPI { [DispId(1011)] get; } - int deviceYDPI { - [DispId(1012)] - get; - } + int deviceYDPI { [DispId(1012)] get; } }; -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs b/src/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs index fadb35ca0..32982a281 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs @@ -21,20 +21,29 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - // See: http://msdn.microsoft.com/en-us/library/aa768849%28v=vs.85%29.aspx - [ComImport, Guid("3050f25A-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLSelectionObject { - [return: MarshalAs(UnmanagedType.IDispatch)] - [DispId(1001)] - IHTMLTxtRange createRange(); - [DispId(1002)] - void empty(); - [DispId(1003)] - void clear(); - [DispId(1004)] - string EventType { [return: MarshalAs(UnmanagedType.BStr)] get;} - } -} +namespace GreenshotPlugin.IEInterop +{ + // See: http://msdn.microsoft.com/en-us/library/aa768849%28v=vs.85%29.aspx + [ComImport, Guid("3050f25A-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLSelectionObject + { + [return: MarshalAs(UnmanagedType.IDispatch)] + [DispId(1001)] + IHTMLTxtRange createRange(); + + [DispId(1002)] + void empty(); + + [DispId(1003)] + void clear(); + + [DispId(1004)] + string EventType + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLStyle.cs b/src/GreenshotPlugin/IEInterop/IHTMLStyle.cs index 43d10fa84..d5cd7f5be 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLStyle.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLStyle.cs @@ -21,11 +21,13 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F25E-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLStyle { +namespace GreenshotPlugin.IEInterop +{ + [ComImport, Guid("3050F25E-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLStyle + { /// setAttribute method of IHTMLStyle interface. /// An original IDL definition of setAttribute method was the following: HRESULT setAttribute (BSTR strAttributeName, VARIANT AttributeValue, [optional, defaultvalue(1)] long lFlags); // IDL: HRESULT setAttribute (BSTR strAttributeName, VARIANT AttributeValue, [optional, defaultvalue(1)] long lFlags); @@ -60,7 +62,8 @@ namespace GreenshotPlugin.IEInterop { /// An original IDL definition of background property was the following: BSTR background; // IDL: BSTR background; // VB6: background As String - string background { + string background + { // IDL: HRESULT background ([out, retval] BSTR* ReturnValue); // VB6: Function background As String [DispId(-2147413080)] @@ -68,15 +71,15 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT background (BSTR value); // VB6: Sub background (ByVal value As String) - [DispId(-2147413080)] - set; + [DispId(-2147413080)] set; } /// backgroundAttachment property of IHTMLStyle interface. /// An original IDL definition of backgroundAttachment property was the following: BSTR backgroundAttachment; // IDL: BSTR backgroundAttachment; // VB6: backgroundAttachment As String - string backgroundAttachment { + string backgroundAttachment + { // IDL: HRESULT backgroundAttachment ([out, retval] BSTR* ReturnValue); // VB6: Function backgroundAttachment As String [DispId(-2147413067)] @@ -84,30 +87,29 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT backgroundAttachment (BSTR value); // VB6: Sub backgroundAttachment (ByVal value As String) - [DispId(-2147413067)] - set; + [DispId(-2147413067)] set; } /// backgroundColor property of IHTMLStyle interface. /// An original IDL definition of backgroundColor property was the following: VARIANT backgroundColor; // IDL: VARIANT backgroundColor; // VB6: backgroundColor As Any - object backgroundColor { + object backgroundColor + { // IDL: HRESULT backgroundColor ([out, retval] VARIANT* ReturnValue); // VB6: Function backgroundColor As Any - [DispId(-501)] - get; + [DispId(-501)] get; // IDL: HRESULT backgroundColor (VARIANT value); // VB6: Sub backgroundColor (ByVal value As Any) - [DispId(-501)] - set; + [DispId(-501)] set; } /// backgroundImage property of IHTMLStyle interface. /// An original IDL definition of backgroundImage property was the following: BSTR backgroundImage; // IDL: BSTR backgroundImage; // VB6: backgroundImage As String - string backgroundImage { + string backgroundImage + { // IDL: HRESULT backgroundImage ([out, retval] BSTR* ReturnValue); // VB6: Function backgroundImage As String [DispId(-2147413111)] @@ -115,15 +117,15 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT backgroundImage (BSTR value); // VB6: Sub backgroundImage (ByVal value As String) - [DispId(-2147413111)] - set; + [DispId(-2147413111)] set; } /// backgroundPosition property of IHTMLStyle interface. /// An original IDL definition of backgroundPosition property was the following: BSTR backgroundPosition; // IDL: BSTR backgroundPosition; // VB6: backgroundPosition As String - string backgroundPosition { + string backgroundPosition + { // IDL: HRESULT backgroundPosition ([out, retval] BSTR* ReturnValue); // VB6: Function backgroundPosition As String [DispId(-2147413066)] @@ -131,45 +133,43 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT backgroundPosition (BSTR value); // VB6: Sub backgroundPosition (ByVal value As String) - [DispId(-2147413066)] - set; + [DispId(-2147413066)] set; } /// backgroundPositionX property of IHTMLStyle interface. /// An original IDL definition of backgroundPositionX property was the following: VARIANT backgroundPositionX; // IDL: VARIANT backgroundPositionX; // VB6: backgroundPositionX As Any - object backgroundPositionX { + object backgroundPositionX + { // IDL: HRESULT backgroundPositionX ([out, retval] VARIANT* ReturnValue); // VB6: Function backgroundPositionX As Any - [DispId(-2147413079)] - get; + [DispId(-2147413079)] get; // IDL: HRESULT backgroundPositionX (VARIANT value); // VB6: Sub backgroundPositionX (ByVal value As Any) - [DispId(-2147413079)] - set; + [DispId(-2147413079)] set; } /// backgroundPositionY property of IHTMLStyle interface. /// An original IDL definition of backgroundPositionY property was the following: VARIANT backgroundPositionY; // IDL: VARIANT backgroundPositionY; // VB6: backgroundPositionY As Any - object backgroundPositionY { + object backgroundPositionY + { // IDL: HRESULT backgroundPositionY ([out, retval] VARIANT* ReturnValue); // VB6: Function backgroundPositionY As Any - [DispId(-2147413078)] - get; + [DispId(-2147413078)] get; // IDL: HRESULT backgroundPositionY (VARIANT value); // VB6: Sub backgroundPositionY (ByVal value As Any) - [DispId(-2147413078)] - set; + [DispId(-2147413078)] set; } /// backgroundRepeat property of IHTMLStyle interface. /// An original IDL definition of backgroundRepeat property was the following: BSTR backgroundRepeat; // IDL: BSTR backgroundRepeat; // VB6: backgroundRepeat As String - string backgroundRepeat { + string backgroundRepeat + { // IDL: HRESULT backgroundRepeat ([out, retval] BSTR* ReturnValue); // VB6: Function backgroundRepeat As String [DispId(-2147413068)] @@ -177,15 +177,15 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT backgroundRepeat (BSTR value); // VB6: Sub backgroundRepeat (ByVal value As String) - [DispId(-2147413068)] - set; + [DispId(-2147413068)] set; } /// border property of IHTMLStyle interface. /// An original IDL definition of border property was the following: BSTR border; // IDL: BSTR border; // VB6: border As String - string border { + string border + { // IDL: HRESULT border ([out, retval] BSTR* ReturnValue); // VB6: Function border As String [DispId(-2147413063)] @@ -193,15 +193,15 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT border (BSTR value); // VB6: Sub border (ByVal value As String) - [DispId(-2147413063)] - set; + [DispId(-2147413063)] set; } /// borderBottom property of IHTMLStyle interface. /// An original IDL definition of borderBottom property was the following: BSTR borderBottom; // IDL: BSTR borderBottom; // VB6: borderBottom As String - string borderBottom { + string borderBottom + { // IDL: HRESULT borderBottom ([out, retval] BSTR* ReturnValue); // VB6: Function borderBottom As String [DispId(-2147413060)] @@ -209,30 +209,29 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderBottom (BSTR value); // VB6: Sub borderBottom (ByVal value As String) - [DispId(-2147413060)] - set; + [DispId(-2147413060)] set; } /// borderBottomColor property of IHTMLStyle interface. /// An original IDL definition of borderBottomColor property was the following: VARIANT borderBottomColor; // IDL: VARIANT borderBottomColor; // VB6: borderBottomColor As Any - object borderBottomColor { + object borderBottomColor + { // IDL: HRESULT borderBottomColor ([out, retval] VARIANT* ReturnValue); // VB6: Function borderBottomColor As Any - [DispId(-2147413055)] - get; + [DispId(-2147413055)] get; // IDL: HRESULT borderBottomColor (VARIANT value); // VB6: Sub borderBottomColor (ByVal value As Any) - [DispId(-2147413055)] - set; + [DispId(-2147413055)] set; } /// borderBottomStyle property of IHTMLStyle interface. /// An original IDL definition of borderBottomStyle property was the following: BSTR borderBottomStyle; // IDL: BSTR borderBottomStyle; // VB6: borderBottomStyle As String - string borderBottomStyle { + string borderBottomStyle + { // IDL: HRESULT borderBottomStyle ([out, retval] BSTR* ReturnValue); // VB6: Function borderBottomStyle As String [DispId(-2147413045)] @@ -240,30 +239,29 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderBottomStyle (BSTR value); // VB6: Sub borderBottomStyle (ByVal value As String) - [DispId(-2147413045)] - set; + [DispId(-2147413045)] set; } /// borderBottomWidth property of IHTMLStyle interface. /// An original IDL definition of borderBottomWidth property was the following: VARIANT borderBottomWidth; // IDL: VARIANT borderBottomWidth; // VB6: borderBottomWidth As Any - object borderBottomWidth { + object borderBottomWidth + { // IDL: HRESULT borderBottomWidth ([out, retval] VARIANT* ReturnValue); // VB6: Function borderBottomWidth As Any - [DispId(-2147413050)] - get; + [DispId(-2147413050)] get; // IDL: HRESULT borderBottomWidth (VARIANT value); // VB6: Sub borderBottomWidth (ByVal value As Any) - [DispId(-2147413050)] - set; + [DispId(-2147413050)] set; } /// borderColor property of IHTMLStyle interface. /// An original IDL definition of borderColor property was the following: BSTR borderColor; // IDL: BSTR borderColor; // VB6: borderColor As String - string borderColor { + string borderColor + { // IDL: HRESULT borderColor ([out, retval] BSTR* ReturnValue); // VB6: Function borderColor As String [DispId(-2147413058)] @@ -271,15 +269,15 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderColor (BSTR value); // VB6: Sub borderColor (ByVal value As String) - [DispId(-2147413058)] - set; + [DispId(-2147413058)] set; } /// borderLeft property of IHTMLStyle interface. /// An original IDL definition of borderLeft property was the following: BSTR borderLeft; // IDL: BSTR borderLeft; // VB6: borderLeft As String - string borderLeft { + string borderLeft + { // IDL: HRESULT borderLeft ([out, retval] BSTR* ReturnValue); // VB6: Function borderLeft As String [DispId(-2147413059)] @@ -287,30 +285,29 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderLeft (BSTR value); // VB6: Sub borderLeft (ByVal value As String) - [DispId(-2147413059)] - set; + [DispId(-2147413059)] set; } /// borderLeftColor property of IHTMLStyle interface. /// An original IDL definition of borderLeftColor property was the following: VARIANT borderLeftColor; // IDL: VARIANT borderLeftColor; // VB6: borderLeftColor As Any - object borderLeftColor { + object borderLeftColor + { // IDL: HRESULT borderLeftColor ([out, retval] VARIANT* ReturnValue); // VB6: Function borderLeftColor As Any - [DispId(-2147413054)] - get; + [DispId(-2147413054)] get; // IDL: HRESULT borderLeftColor (VARIANT value); // VB6: Sub borderLeftColor (ByVal value As Any) - [DispId(-2147413054)] - set; + [DispId(-2147413054)] set; } /// borderLeftStyle property of IHTMLStyle interface. /// An original IDL definition of borderLeftStyle property was the following: BSTR borderLeftStyle; // IDL: BSTR borderLeftStyle; // VB6: borderLeftStyle As String - string borderLeftStyle { + string borderLeftStyle + { // IDL: HRESULT borderLeftStyle ([out, retval] BSTR* ReturnValue); // VB6: Function borderLeftStyle As String [DispId(-2147413044)] @@ -318,30 +315,29 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderLeftStyle (BSTR value); // VB6: Sub borderLeftStyle (ByVal value As String) - [DispId(-2147413044)] - set; + [DispId(-2147413044)] set; } /// borderLeftWidth property of IHTMLStyle interface. /// An original IDL definition of borderLeftWidth property was the following: VARIANT borderLeftWidth; // IDL: VARIANT borderLeftWidth; // VB6: borderLeftWidth As Any - object borderLeftWidth { + object borderLeftWidth + { // IDL: HRESULT borderLeftWidth ([out, retval] VARIANT* ReturnValue); // VB6: Function borderLeftWidth As Any - [DispId(-2147413049)] - get; + [DispId(-2147413049)] get; // IDL: HRESULT borderLeftWidth (VARIANT value); // VB6: Sub borderLeftWidth (ByVal value As Any) - [DispId(-2147413049)] - set; + [DispId(-2147413049)] set; } /// borderRight property of IHTMLStyle interface. /// An original IDL definition of borderRight property was the following: BSTR borderRight; // IDL: BSTR borderRight; // VB6: borderRight As String - string borderRight { + string borderRight + { // IDL: HRESULT borderRight ([out, retval] BSTR* ReturnValue); // VB6: Function borderRight As String [DispId(-2147413061)] @@ -349,30 +345,29 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderRight (BSTR value); // VB6: Sub borderRight (ByVal value As String) - [DispId(-2147413061)] - set; + [DispId(-2147413061)] set; } /// borderRightColor property of IHTMLStyle interface. /// An original IDL definition of borderRightColor property was the following: VARIANT borderRightColor; // IDL: VARIANT borderRightColor; // VB6: borderRightColor As Any - object borderRightColor { + object borderRightColor + { // IDL: HRESULT borderRightColor ([out, retval] VARIANT* ReturnValue); // VB6: Function borderRightColor As Any - [DispId(-2147413056)] - get; + [DispId(-2147413056)] get; // IDL: HRESULT borderRightColor (VARIANT value); // VB6: Sub borderRightColor (ByVal value As Any) - [DispId(-2147413056)] - set; + [DispId(-2147413056)] set; } /// borderRightStyle property of IHTMLStyle interface. /// An original IDL definition of borderRightStyle property was the following: BSTR borderRightStyle; // IDL: BSTR borderRightStyle; // VB6: borderRightStyle As String - string borderRightStyle { + string borderRightStyle + { // IDL: HRESULT borderRightStyle ([out, retval] BSTR* ReturnValue); // VB6: Function borderRightStyle As String [DispId(-2147413046)] @@ -380,30 +375,29 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderRightStyle (BSTR value); // VB6: Sub borderRightStyle (ByVal value As String) - [DispId(-2147413046)] - set; + [DispId(-2147413046)] set; } /// borderRightWidth property of IHTMLStyle interface. /// An original IDL definition of borderRightWidth property was the following: VARIANT borderRightWidth; // IDL: VARIANT borderRightWidth; // VB6: borderRightWidth As Any - object borderRightWidth { + object borderRightWidth + { // IDL: HRESULT borderRightWidth ([out, retval] VARIANT* ReturnValue); // VB6: Function borderRightWidth As Any - [DispId(-2147413051)] - get; + [DispId(-2147413051)] get; // IDL: HRESULT borderRightWidth (VARIANT value); // VB6: Sub borderRightWidth (ByVal value As Any) - [DispId(-2147413051)] - set; + [DispId(-2147413051)] set; } /// borderStyle property of IHTMLStyle interface. /// An original IDL definition of borderStyle property was the following: BSTR borderStyle; // IDL: BSTR borderStyle; // VB6: borderStyle As String - string borderStyle { + string borderStyle + { // IDL: HRESULT borderStyle ([out, retval] BSTR* ReturnValue); // VB6: Function borderStyle As String [DispId(-2147413048)] @@ -411,15 +405,15 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderStyle (BSTR value); // VB6: Sub borderStyle (ByVal value As String) - [DispId(-2147413048)] - set; + [DispId(-2147413048)] set; } /// borderTop property of IHTMLStyle interface. /// An original IDL definition of borderTop property was the following: BSTR borderTop; // IDL: BSTR borderTop; // VB6: borderTop As String - string borderTop { + string borderTop + { // IDL: HRESULT borderTop ([out, retval] BSTR* ReturnValue); // VB6: Function borderTop As String [DispId(-2147413062)] @@ -427,30 +421,29 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderTop (BSTR value); // VB6: Sub borderTop (ByVal value As String) - [DispId(-2147413062)] - set; + [DispId(-2147413062)] set; } /// borderTopColor property of IHTMLStyle interface. /// An original IDL definition of borderTopColor property was the following: VARIANT borderTopColor; // IDL: VARIANT borderTopColor; // VB6: borderTopColor As Any - object borderTopColor { + object borderTopColor + { // IDL: HRESULT borderTopColor ([out, retval] VARIANT* ReturnValue); // VB6: Function borderTopColor As Any - [DispId(-2147413057)] - get; + [DispId(-2147413057)] get; // IDL: HRESULT borderTopColor (VARIANT value); // VB6: Sub borderTopColor (ByVal value As Any) - [DispId(-2147413057)] - set; + [DispId(-2147413057)] set; } /// borderTopStyle property of IHTMLStyle interface. /// An original IDL definition of borderTopStyle property was the following: BSTR borderTopStyle; // IDL: BSTR borderTopStyle; // VB6: borderTopStyle As String - string borderTopStyle { + string borderTopStyle + { // IDL: HRESULT borderTopStyle ([out, retval] BSTR* ReturnValue); // VB6: Function borderTopStyle As String [DispId(-2147413047)] @@ -458,30 +451,29 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderTopStyle (BSTR value); // VB6: Sub borderTopStyle (ByVal value As String) - [DispId(-2147413047)] - set; + [DispId(-2147413047)] set; } /// borderTopWidth property of IHTMLStyle interface. /// An original IDL definition of borderTopWidth property was the following: VARIANT borderTopWidth; // IDL: VARIANT borderTopWidth; // VB6: borderTopWidth As Any - object borderTopWidth { + object borderTopWidth + { // IDL: HRESULT borderTopWidth ([out, retval] VARIANT* ReturnValue); // VB6: Function borderTopWidth As Any - [DispId(-2147413052)] - get; + [DispId(-2147413052)] get; // IDL: HRESULT borderTopWidth (VARIANT value); // VB6: Sub borderTopWidth (ByVal value As Any) - [DispId(-2147413052)] - set; + [DispId(-2147413052)] set; } /// borderWidth property of IHTMLStyle interface. /// An original IDL definition of borderWidth property was the following: BSTR borderWidth; // IDL: BSTR borderWidth; // VB6: borderWidth As String - string borderWidth { + string borderWidth + { // IDL: HRESULT borderWidth ([out, retval] BSTR* ReturnValue); // VB6: Function borderWidth As String [DispId(-2147413053)] @@ -489,8 +481,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT borderWidth (BSTR value); // VB6: Sub borderWidth (ByVal value As String) - [DispId(-2147413053)] - set; + [DispId(-2147413053)] set; } /// clear property of IHTMLStyle interface. @@ -506,8 +497,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT clear (BSTR value); // VB6: Sub clear (ByVal value As String) - [DispId(-2147413096)] - set; + [DispId(-2147413096)] set; } /// clip property of IHTMLStyle interface. @@ -523,8 +513,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT clip (BSTR value); // VB6: Sub clip (ByVal value As String) - [DispId(-2147413020)] - set; + [DispId(-2147413020)] set; } /// color property of IHTMLStyle interface. @@ -535,12 +524,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT color ([out, retval] VARIANT* ReturnValue); // VB6: Function color As Any - [DispId(-2147413110)] - get; + [DispId(-2147413110)] get; // IDL: HRESULT color (VARIANT value); // VB6: Sub color (ByVal value As Any) - [DispId(-2147413110)] - set; + [DispId(-2147413110)] set; } /// cssText property of IHTMLStyle interface. @@ -556,8 +543,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT cssText (BSTR value); // VB6: Sub cssText (ByVal value As String) - [DispId(-2147413013)] - set; + [DispId(-2147413013)] set; } /// cursor property of IHTMLStyle interface. @@ -573,8 +559,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT cursor (BSTR value); // VB6: Sub cursor (ByVal value As String) - [DispId(-2147413010)] - set; + [DispId(-2147413010)] set; } /// display property of IHTMLStyle interface. @@ -590,8 +575,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT display (BSTR value); // VB6: Sub display (ByVal value As String) - [DispId(-2147413041)] - set; + [DispId(-2147413041)] set; } /// filter property of IHTMLStyle interface. @@ -607,8 +591,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT filter (BSTR value); // VB6: Sub filter (ByVal value As String) - [DispId(-2147413030)] - set; + [DispId(-2147413030)] set; } /// font property of IHTMLStyle interface. @@ -624,8 +607,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT font (BSTR value); // VB6: Sub font (ByVal value As String) - [DispId(-2147413071)] - set; + [DispId(-2147413071)] set; } /// fontFamily property of IHTMLStyle interface. @@ -641,8 +623,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT fontFamily (BSTR value); // VB6: Sub fontFamily (ByVal value As String) - [DispId(-2147413094)] - set; + [DispId(-2147413094)] set; } /// fontSize property of IHTMLStyle interface. @@ -653,12 +634,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT fontSize ([out, retval] VARIANT* ReturnValue); // VB6: Function fontSize As Any - [DispId(-2147413093)] - get; + [DispId(-2147413093)] get; // IDL: HRESULT fontSize (VARIANT value); // VB6: Sub fontSize (ByVal value As Any) - [DispId(-2147413093)] - set; + [DispId(-2147413093)] set; } /// fontStyle property of IHTMLStyle interface. @@ -674,8 +653,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT fontStyle (BSTR value); // VB6: Sub fontStyle (ByVal value As String) - [DispId(-2147413088)] - set; + [DispId(-2147413088)] set; } /// fontVariant property of IHTMLStyle interface. @@ -691,8 +669,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT fontVariant (BSTR value); // VB6: Sub fontVariant (ByVal value As String) - [DispId(-2147413087)] - set; + [DispId(-2147413087)] set; } /// fontWeight property of IHTMLStyle interface. @@ -708,8 +685,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT fontWeight (BSTR value); // VB6: Sub fontWeight (ByVal value As String) - [DispId(-2147413085)] - set; + [DispId(-2147413085)] set; } /// height property of IHTMLStyle interface. @@ -720,12 +696,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT height ([out, retval] VARIANT* ReturnValue); // VB6: Function height As Any - [DispId(-2147418106)] - get; + [DispId(-2147418106)] get; // IDL: HRESULT height (VARIANT value); // VB6: Sub height (ByVal value As Any) - [DispId(-2147418106)] - set; + [DispId(-2147418106)] set; } /// left property of IHTMLStyle interface. @@ -736,12 +710,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT left ([out, retval] VARIANT* ReturnValue); // VB6: Function left As Any - [DispId(-2147418109)] - get; + [DispId(-2147418109)] get; // IDL: HRESULT left (VARIANT value); // VB6: Sub left (ByVal value As Any) - [DispId(-2147418109)] - set; + [DispId(-2147418109)] set; } /// letterSpacing property of IHTMLStyle interface. @@ -752,12 +724,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT letterSpacing ([out, retval] VARIANT* ReturnValue); // VB6: Function letterSpacing As Any - [DispId(-2147413104)] - get; + [DispId(-2147413104)] get; // IDL: HRESULT letterSpacing (VARIANT value); // VB6: Sub letterSpacing (ByVal value As Any) - [DispId(-2147413104)] - set; + [DispId(-2147413104)] set; } /// lineHeight property of IHTMLStyle interface. @@ -768,12 +738,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT lineHeight ([out, retval] VARIANT* ReturnValue); // VB6: Function lineHeight As Any - [DispId(-2147413106)] - get; + [DispId(-2147413106)] get; // IDL: HRESULT lineHeight (VARIANT value); // VB6: Sub lineHeight (ByVal value As Any) - [DispId(-2147413106)] - set; + [DispId(-2147413106)] set; } /// listStyle property of IHTMLStyle interface. @@ -789,8 +757,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT listStyle (BSTR value); // VB6: Sub listStyle (ByVal value As String) - [DispId(-2147413037)] - set; + [DispId(-2147413037)] set; } /// listStyleImage property of IHTMLStyle interface. @@ -806,8 +773,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT listStyleImage (BSTR value); // VB6: Sub listStyleImage (ByVal value As String) - [DispId(-2147413038)] - set; + [DispId(-2147413038)] set; } /// listStylePosition property of IHTMLStyle interface. @@ -823,8 +789,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT listStylePosition (BSTR value); // VB6: Sub listStylePosition (ByVal value As String) - [DispId(-2147413039)] - set; + [DispId(-2147413039)] set; } /// listStyleType property of IHTMLStyle interface. @@ -840,8 +805,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT listStyleType (BSTR value); // VB6: Sub listStyleType (ByVal value As String) - [DispId(-2147413040)] - set; + [DispId(-2147413040)] set; } /// margin property of IHTMLStyle interface. @@ -857,8 +821,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT margin (BSTR value); // VB6: Sub margin (ByVal value As String) - [DispId(-2147413076)] - set; + [DispId(-2147413076)] set; } /// marginBottom property of IHTMLStyle interface. @@ -869,12 +832,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT marginBottom ([out, retval] VARIANT* ReturnValue); // VB6: Function marginBottom As Any - [DispId(-2147413073)] - get; + [DispId(-2147413073)] get; // IDL: HRESULT marginBottom (VARIANT value); // VB6: Sub marginBottom (ByVal value As Any) - [DispId(-2147413073)] - set; + [DispId(-2147413073)] set; } /// marginLeft property of IHTMLStyle interface. @@ -885,12 +846,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT marginLeft ([out, retval] VARIANT* ReturnValue); // VB6: Function marginLeft As Any - [DispId(-2147413072)] - get; + [DispId(-2147413072)] get; // IDL: HRESULT marginLeft (VARIANT value); // VB6: Sub marginLeft (ByVal value As Any) - [DispId(-2147413072)] - set; + [DispId(-2147413072)] set; } /// marginRight property of IHTMLStyle interface. @@ -901,12 +860,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT marginRight ([out, retval] VARIANT* ReturnValue); // VB6: Function marginRight As Any - [DispId(-2147413074)] - get; + [DispId(-2147413074)] get; // IDL: HRESULT marginRight (VARIANT value); // VB6: Sub marginRight (ByVal value As Any) - [DispId(-2147413074)] - set; + [DispId(-2147413074)] set; } /// marginTop property of IHTMLStyle interface. @@ -917,12 +874,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT marginTop ([out, retval] VARIANT* ReturnValue); // VB6: Function marginTop As Any - [DispId(-2147413075)] - get; + [DispId(-2147413075)] get; // IDL: HRESULT marginTop (VARIANT value); // VB6: Sub marginTop (ByVal value As Any) - [DispId(-2147413075)] - set; + [DispId(-2147413075)] set; } /// overflow property of IHTMLStyle interface. @@ -938,8 +893,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT overflow (BSTR value); // VB6: Sub overflow (ByVal value As String) - [DispId(-2147413102)] - set; + [DispId(-2147413102)] set; } /// padding property of IHTMLStyle interface. @@ -955,8 +909,7 @@ namespace GreenshotPlugin.IEInterop { get; // IDL: HRESULT padding (BSTR value); // VB6: Sub padding (ByVal value As String) - [DispId(-2147413101)] - set; + [DispId(-2147413101)] set; } /// paddingBottom property of IHTMLStyle interface. @@ -967,12 +920,10 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT paddingBottom ([out, retval] VARIANT* ReturnValue); // VB6: Function paddingBottom As Any - [DispId(-2147413098)] - get; + [DispId(-2147413098)] get; // IDL: HRESULT paddingBottom (VARIANT value); // VB6: Sub paddingBottom (ByVal value As Any) - [DispId(-2147413098)] - set; + [DispId(-2147413098)] set; } /// paddingLeft property of IHTMLStyle interface. @@ -983,206 +934,170 @@ namespace GreenshotPlugin.IEInterop { { // IDL: HRESULT paddingLeft ([out, retval] VARIANT* ReturnValue); // VB6: Function paddingLeft As Any - [DispId(-2147413097)] - get; + [DispId(-2147413097)] get; // IDL: HRESULT paddingLeft (VARIANT value); // VB6: Sub paddingLeft (ByVal value As Any) - [DispId(-2147413097)] - set; + [DispId(-2147413097)] set; } /// paddingRight property of IHTMLStyle interface. - object paddingRight { - [DispId(-2147413099)] - get; - } + object paddingRight { [DispId(-2147413099)] get; } /// paddingTop property of IHTMLStyle interface. - object paddingTop { - [DispId(-2147413100)] - get; - } + object paddingTop { [DispId(-2147413100)] get; } /// pageBreakAfter property of IHTMLStyle interface. - string pageBreakAfter { + string pageBreakAfter + { [DispId(-2147413034)] [return: MarshalAs(UnmanagedType.BStr)] get; } /// pageBreakBefore property of IHTMLStyle interface. - string pageBreakBefore { + string pageBreakBefore + { [DispId(-2147413035)] [return: MarshalAs(UnmanagedType.BStr)] get; } /// pixelHeight property of IHTMLStyle interface. - int pixelHeight { - [DispId(-2147414109)] - get; - } + int pixelHeight { [DispId(-2147414109)] get; } /// pixelLeft property of IHTMLStyle interface. - int pixelLeft { - [DispId(-2147414111)] - get; - } + int pixelLeft { [DispId(-2147414111)] get; } /// pixelTop property of IHTMLStyle interface. - int pixelTop { - [DispId(-2147414112)] - get; - } + int pixelTop { [DispId(-2147414112)] get; } /// pixelWidth property of IHTMLStyle interface. - int pixelWidth { - [DispId(-2147414110)] - get; - } + int pixelWidth { [DispId(-2147414110)] get; } /// posHeight property of IHTMLStyle interface. - float posHeight { - [DispId(-2147414105)] - get; - } + float posHeight { [DispId(-2147414105)] get; } /// position property of IHTMLStyle interface. - string position { + string position + { [DispId(-2147413022)] [return: MarshalAs(UnmanagedType.BStr)] get; } /// posLeft property of IHTMLStyle interface. - float posLeft { - [DispId(-2147414107)] - get; - } + float posLeft { [DispId(-2147414107)] get; } /// posTop property of IHTMLStyle interface. - float posTop { - [DispId(-2147414108)] - get; - } + float posTop { [DispId(-2147414108)] get; } /// posWidth property of IHTMLStyle interface. - float posWidth { - [DispId(-2147414106)] - get; - } + float posWidth { [DispId(-2147414106)] get; } /// styleFloat property of IHTMLStyle interface. - string styleFloat { + string styleFloat + { [DispId(-2147413042)] [return: MarshalAs(UnmanagedType.BStr)] get; } /// textAlign property of IHTMLStyle interface. - string textAlign { + string textAlign + { [DispId(-2147418040)] [return: MarshalAs(UnmanagedType.BStr)] get; } /// textDecoration property of IHTMLStyle interface. - string textDecoration { + string textDecoration + { [DispId(-2147413077)] [return: MarshalAs(UnmanagedType.BStr)] get; } /// textDecorationBlink property of IHTMLStyle interface. - bool textDecorationBlink { + bool textDecorationBlink + { [DispId(-2147413090)] [return: MarshalAs(UnmanagedType.VariantBool)] get; } /// textDecorationLineThrough property of IHTMLStyle interface. - bool textDecorationLineThrough { + bool textDecorationLineThrough + { [DispId(-2147413092)] [return: MarshalAs(UnmanagedType.VariantBool)] get; } /// textDecorationNone property of IHTMLStyle interface. - bool textDecorationNone { + bool textDecorationNone + { [DispId(-2147413089)] [return: MarshalAs(UnmanagedType.VariantBool)] get; } /// textDecorationOverline property of IHTMLStyle interface. - bool textDecorationOverline { + bool textDecorationOverline + { [DispId(-2147413043)] [return: MarshalAs(UnmanagedType.VariantBool)] get; } /// textDecorationUnderline property of IHTMLStyle interface. - bool textDecorationUnderline { + bool textDecorationUnderline + { [DispId(-2147413091)] [return: MarshalAs(UnmanagedType.VariantBool)] get; } /// textIndent property of IHTMLStyle interface. - object textIndent { - [DispId(-2147413105)] - get; - } + object textIndent { [DispId(-2147413105)] get; } /// textTransform property of IHTMLStyle interface. - string textTransform { + string textTransform + { [DispId(-2147413108)] [return: MarshalAs(UnmanagedType.BStr)] get; } /// top property of IHTMLStyle interface. - object top { - [DispId(-2147418108)] - get; - } + object top { [DispId(-2147418108)] get; } /// verticalAlign property of IHTMLStyle interface. - object verticalAlign { - [DispId(-2147413064)] - get; - } + object verticalAlign { [DispId(-2147413064)] get; } /// visibility property of IHTMLStyle interface. - string visibility { + string visibility + { [DispId(-2147413032)] [return: MarshalAs(UnmanagedType.BStr)] get; } /// whiteSpace property of IHTMLStyle interface. - string whiteSpace { + string whiteSpace + { [DispId(-2147413036)] [return: MarshalAs(UnmanagedType.BStr)] get; } /// width property of IHTMLStyle interface. - object width { - [DispId(-2147418107)] - get; - } + object width { [DispId(-2147418107)] get; } /// wordSpacing property of IHTMLStyle interface. - object wordSpacing { - [DispId(-2147413065)] - get; - } + object wordSpacing { [DispId(-2147413065)] get; } /// zIndex property of IHTMLStyle interface. - object zIndex { - [DispId(-2147413021)] - get; - } + object zIndex { [DispId(-2147413021)] get; } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs b/src/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs index f9ff8d690..2a2cf3986 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs @@ -21,118 +21,121 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - // See: http://msdn.microsoft.com/en-us/library/aa741548%28v=vs.85%29.aspx - [ComImport, Guid("3050F220-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLTxtRange { - [DispId(1006)] - IHTMLElement parentElement(); +namespace GreenshotPlugin.IEInterop +{ + // See: http://msdn.microsoft.com/en-us/library/aa741548%28v=vs.85%29.aspx + [ComImport, Guid("3050F220-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLTxtRange + { + [DispId(1006)] + IHTMLElement parentElement(); - [DispId(1008)] - IHTMLTxtRange duplicate(); + [DispId(1008)] + IHTMLTxtRange duplicate(); - [DispId(1010)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool inRange(IHTMLTxtRange range); + [DispId(1010)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool inRange(IHTMLTxtRange range); - [DispId(1011)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool isEqual(IHTMLTxtRange range); + [DispId(1011)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool isEqual(IHTMLTxtRange range); - [DispId(1012)] - void scrollIntoView([MarshalAs(UnmanagedType.VariantBool)] bool fStart); + [DispId(1012)] + void scrollIntoView([MarshalAs(UnmanagedType.VariantBool)] bool fStart); - [DispId(1013)] - void collapse([MarshalAs(UnmanagedType.VariantBool)] bool Start); + [DispId(1013)] + void collapse([MarshalAs(UnmanagedType.VariantBool)] bool Start); - [DispId(1014)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool expand([MarshalAs(UnmanagedType.BStr)] string Unit); + [DispId(1014)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool expand([MarshalAs(UnmanagedType.BStr)] string Unit); - [DispId(1015)] - int move([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); + [DispId(1015)] + int move([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); - [DispId(1016)] - int moveStart([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); + [DispId(1016)] + int moveStart([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); - [DispId(1017)] - int moveEnd([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); + [DispId(1017)] + int moveEnd([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); - [DispId(1024)] - void select(); + [DispId(1024)] + void select(); - [DispId(1026)] - void pasteHTML([MarshalAs(UnmanagedType.BStr)] string html); + [DispId(1026)] + void pasteHTML([MarshalAs(UnmanagedType.BStr)] string html); - [DispId(1001)] - void moveToElementText(IHTMLElement element); + [DispId(1001)] + void moveToElementText(IHTMLElement element); - [DispId(1025)] - void setEndPoint([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); + [DispId(1025)] + void setEndPoint([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); - [DispId(1018)] - int compareEndPoints([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); + [DispId(1018)] + int compareEndPoints([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); - [DispId(1019)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool findText([MarshalAs(UnmanagedType.BStr)] string String, int Count, int Flags); + [DispId(1019)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool findText([MarshalAs(UnmanagedType.BStr)] string String, int Count, int Flags); - [DispId(1020)] - void moveToPoint(int x, int y); + [DispId(1020)] + void moveToPoint(int x, int y); - [DispId(1021)] - [return: MarshalAs(UnmanagedType.BStr)] - string getBookmark(); + [DispId(1021)] + [return: MarshalAs(UnmanagedType.BStr)] + string getBookmark(); - [DispId(1009)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool moveToBookmark([MarshalAs(UnmanagedType.BStr)] string Bookmark); + [DispId(1009)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool moveToBookmark([MarshalAs(UnmanagedType.BStr)] string Bookmark); - [DispId(1027)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandSupported([MarshalAs(UnmanagedType.BStr)] string cmdID); + [DispId(1027)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandSupported([MarshalAs(UnmanagedType.BStr)] string cmdID); - [DispId(1028)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandEnabled([MarshalAs(UnmanagedType.BStr)] string cmdID); + [DispId(1028)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandEnabled([MarshalAs(UnmanagedType.BStr)] string cmdID); - [DispId(1029)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandState([MarshalAs(UnmanagedType.BStr)] string cmdID); + [DispId(1029)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandState([MarshalAs(UnmanagedType.BStr)] string cmdID); - [DispId(1030)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandIndeterm([MarshalAs(UnmanagedType.BStr)] string cmdID); + [DispId(1030)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandIndeterm([MarshalAs(UnmanagedType.BStr)] string cmdID); - [DispId(1031)] - [return: MarshalAs(UnmanagedType.BStr)] - string queryCommandText([MarshalAs(UnmanagedType.BStr)] string cmdID); + [DispId(1031)] + [return: MarshalAs(UnmanagedType.BStr)] + string queryCommandText([MarshalAs(UnmanagedType.BStr)] string cmdID); - [DispId(1032)] - object queryCommandValue([MarshalAs(UnmanagedType.BStr)] string cmdID); + [DispId(1032)] + object queryCommandValue([MarshalAs(UnmanagedType.BStr)] string cmdID); - [DispId(1033)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool execCommand([MarshalAs(UnmanagedType.BStr)] string cmdID, [MarshalAs(UnmanagedType.VariantBool)] bool showUI, object value); + [DispId(1033)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool execCommand([MarshalAs(UnmanagedType.BStr)] string cmdID, [MarshalAs(UnmanagedType.VariantBool)] bool showUI, object value); - [DispId(1034)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool execCommandShowHelp([MarshalAs(UnmanagedType.BStr)] string cmdID); + [DispId(1034)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool execCommandShowHelp([MarshalAs(UnmanagedType.BStr)] string cmdID); - string htmlText { - [DispId(1003)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } + string htmlText + { + [DispId(1003)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } - string text { - [DispId(1004)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - [DispId(1004)] - set; - } - } -} + string text + { + [DispId(1004)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + [DispId(1004)] set; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLWindow2.cs b/src/GreenshotPlugin/IEInterop/IHTMLWindow2.cs index 02b2a756c..316aa821c 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLWindow2.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLWindow2.cs @@ -21,26 +21,32 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComVisible(true), ComImport(), Guid("332c4427-26cb-11d0-b483-00c04fd90119"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLWindow2 { - [DispId(1156)] - IHTMLScreen screen { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(1151)] - IHTMLDocument2 document { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(11)] - string name { - [return: MarshalAs(UnmanagedType.BStr)] get; +namespace GreenshotPlugin.IEInterop +{ + [ComVisible(true), ComImport(), Guid("332c4427-26cb-11d0-b483-00c04fd90119"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLWindow2 + { + [DispId(1156)] + IHTMLScreen screen + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; } - } + + [DispId(1151)] + IHTMLDocument2 document + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(11)] + string name + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLWindow3.cs b/src/GreenshotPlugin/IEInterop/IHTMLWindow3.cs index f3c872f5a..47089f067 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLWindow3.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLWindow3.cs @@ -21,15 +21,15 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComVisible(true), ComImport(), Guid("3050f4ae-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLWindow3 { - [DispId(1170)] - int screenLeft { get;} - - [DispId(1171)] - int screenTop { get;} - } +namespace GreenshotPlugin.IEInterop +{ + [ComVisible(true), ComImport(), Guid("3050f4ae-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLWindow3 + { + [DispId(1170)] int screenLeft { get; } + + [DispId(1171)] int screenTop { get; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLWindow4.cs b/src/GreenshotPlugin/IEInterop/IHTMLWindow4.cs index 8643c88c1..1409852fb 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLWindow4.cs +++ b/src/GreenshotPlugin/IEInterop/IHTMLWindow4.cs @@ -21,15 +21,18 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - [ComVisible(true), ComImport(), Guid("3050f6cf-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLWindow4 { +namespace GreenshotPlugin.IEInterop +{ + [ComVisible(true), ComImport(), Guid("3050f6cf-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLWindow4 + { [DispId(1181)] - IHTMLFrameBase frameElement { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; + IHTMLFrameBase frameElement + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; } } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IWebBrowser2.cs b/src/GreenshotPlugin/IEInterop/IWebBrowser2.cs index 36b06d6e4..5a4a4c5d5 100644 --- a/src/GreenshotPlugin/IEInterop/IWebBrowser2.cs +++ b/src/GreenshotPlugin/IEInterop/IWebBrowser2.cs @@ -21,8 +21,9 @@ using System.Runtime.InteropServices; -namespace GreenshotPlugin.IEInterop { - // IWebBrowser: EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B +namespace GreenshotPlugin.IEInterop +{ + // IWebBrowser: EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B // [ComVisible(true), ComImport(), Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"), // TypeLibType(TypeLibTypeFlags.FDual), // InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] @@ -33,122 +34,119 @@ namespace GreenshotPlugin.IEInterop { // get; // } // } - [ComImport, /*SuppressUnmanagedCodeSecurity,*/ - TypeLibType(TypeLibTypeFlags.FOleAutomation | - TypeLibTypeFlags.FDual | - TypeLibTypeFlags.FHidden), - Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")] - public interface IWebBrowser2 { - [DispId(100)] - void GoBack(); - [DispId(0x65)] - void GoForward(); - [DispId(0x66)] - void GoHome(); - [DispId(0x67)] - void GoSearch(); - [DispId(0x68)] - void Navigate([In] string Url, - [In] ref object flags, - [In] ref object targetFrameName, - [In] ref object postData, - [In] ref object headers); - [DispId(-550)] - void Refresh(); - [DispId(0x69)] - void Refresh2([In] ref object level); - [DispId(0x6a)] - void Stop(); - [DispId(200)] - object Application { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - [DispId(0xc9)] - object Parent { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - [DispId(0xca)] - object Container { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - [DispId(0xcb)] - object Document { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - [DispId(0xcc)] - bool TopLevelContainer { get; } - [DispId(0xcd)] - string Type { get; } - [DispId(0xce)] - int Left { get; set; } - [DispId(0xcf)] - int Top { get; set; } - [DispId(0xd0)] - int Width { get; set; } - [DispId(0xd1)] - int Height { get; set; } - [DispId(210)] - string LocationName { get; } - [DispId(0xd3)] - string LocationURL { get; } - [DispId(0xd4)] - bool Busy { get; } - [DispId(300)] - void Quit(); - [DispId(0x12d)] - void ClientToWindow(out int pcx, out int pcy); - [DispId(0x12e)] - void PutProperty([In] string property, [In] object vtValue); - [DispId(0x12f)] - object GetProperty([In] string property); - [DispId(0)] - string Name { get; } - [DispId(-515)] - int HWND { get; } - [DispId(400)] - string FullName { get; } - [DispId(0x191)] - string Path { get; } - [DispId(0x192)] - bool Visible { get; set; } - [DispId(0x193)] - bool StatusBar { get; set; } - [DispId(0x194)] - string StatusText { get; set; } - [DispId(0x195)] - int ToolBar { get; set; } - [DispId(0x196)] - bool MenuBar { get; set; } - [DispId(0x197)] - bool FullScreen { get; set; } - [DispId(500)] - void Navigate2([In] ref object URL, - [In] ref object flags, - [In] ref object targetFrameName, - [In] ref object postData, - [In] ref object headers); - - [DispId(550)] - bool Offline { get; set; } - [DispId(0x227)] - bool Silent { get; set; } - [DispId(0x228)] - bool RegisterAsBrowser { get; set; } - [DispId(0x229)] - bool RegisterAsDropTarget { get; set; } - [DispId(0x22a)] - bool TheaterMode { get; set; } - [DispId(0x22b)] - bool AddressBar { get; set; } - [DispId(0x22c)] - bool Resizable { get; set; } - } + [ComImport, /*SuppressUnmanagedCodeSecurity,*/ + TypeLibType(TypeLibTypeFlags.FOleAutomation | + TypeLibTypeFlags.FDual | + TypeLibTypeFlags.FHidden), + Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")] + public interface IWebBrowser2 + { + [DispId(100)] + void GoBack(); + + [DispId(0x65)] + void GoForward(); + + [DispId(0x66)] + void GoHome(); + + [DispId(0x67)] + void GoSearch(); + + [DispId(0x68)] + void Navigate([In] string Url, + [In] ref object flags, + [In] ref object targetFrameName, + [In] ref object postData, + [In] ref object headers); + + [DispId(-550)] + void Refresh(); + + [DispId(0x69)] + void Refresh2([In] ref object level); + + [DispId(0x6a)] + void Stop(); + + [DispId(200)] + object Application + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xc9)] + object Parent + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xca)] + object Container + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xcb)] + object Document + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xcc)] bool TopLevelContainer { get; } + [DispId(0xcd)] string Type { get; } + [DispId(0xce)] int Left { get; set; } + [DispId(0xcf)] int Top { get; set; } + [DispId(0xd0)] int Width { get; set; } + [DispId(0xd1)] int Height { get; set; } + [DispId(210)] string LocationName { get; } + [DispId(0xd3)] string LocationURL { get; } + [DispId(0xd4)] bool Busy { get; } + + [DispId(300)] + void Quit(); + + [DispId(0x12d)] + void ClientToWindow(out int pcx, out int pcy); + + [DispId(0x12e)] + void PutProperty([In] string property, [In] object vtValue); + + [DispId(0x12f)] + object GetProperty([In] string property); + + [DispId(0)] string Name { get; } + [DispId(-515)] int HWND { get; } + [DispId(400)] string FullName { get; } + [DispId(0x191)] string Path { get; } + [DispId(0x192)] bool Visible { get; set; } + [DispId(0x193)] bool StatusBar { get; set; } + [DispId(0x194)] string StatusText { get; set; } + [DispId(0x195)] int ToolBar { get; set; } + [DispId(0x196)] bool MenuBar { get; set; } + [DispId(0x197)] bool FullScreen { get; set; } + + [DispId(500)] + void Navigate2([In] ref object URL, + [In] ref object flags, + [In] ref object targetFrameName, + [In] ref object postData, + [In] ref object headers); + + [DispId(550)] bool Offline { get; set; } + [DispId(0x227)] bool Silent { get; set; } + [DispId(0x228)] bool RegisterAsBrowser { get; set; } + [DispId(0x229)] bool RegisterAsDropTarget { get; set; } + [DispId(0x22a)] bool TheaterMode { get; set; } + [DispId(0x22b)] bool AddressBar { get; set; } + [DispId(0x22c)] bool Resizable { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IniFile/IniAttributes.cs b/src/GreenshotPlugin/IniFile/IniAttributes.cs index 0b23b679e..6f41b98b5 100644 --- a/src/GreenshotPlugin/IniFile/IniAttributes.cs +++ b/src/GreenshotPlugin/IniFile/IniAttributes.cs @@ -21,67 +21,51 @@ using System; -namespace GreenshotPlugin.IniFile { - /// - /// Attribute for telling that this class is linked to a section in the ini-configuration - /// - [AttributeUsage(AttributeTargets.Class)] - public class IniSectionAttribute : Attribute { - public IniSectionAttribute(string name) { - Name = name; - } - public string Description; - public string Name { get; set; } - } +namespace GreenshotPlugin.IniFile +{ + /// + /// Attribute for telling that this class is linked to a section in the ini-configuration + /// + [AttributeUsage(AttributeTargets.Class)] + public class IniSectionAttribute : Attribute + { + public IniSectionAttribute(string name) + { + Name = name; + } - /// - /// Attribute for telling that a field is linked to a property in the ini-configuration selection - /// - [AttributeUsage(AttributeTargets.Field|AttributeTargets.Property)] - public class IniPropertyAttribute : Attribute { - public IniPropertyAttribute() { - Separator = ","; - } - public IniPropertyAttribute(string name) : this() { - Name = name; - } - public string Description { - get; - set; - } - public string Separator { - get; - set; - } - public string DefaultValue { - get; - set; - } - public string LanguageKey { - get; - set; - } - // If Encrypted is set to true, the value will be decrypted on load and encrypted on save - public bool Encrypted { - get; - set; - } - public bool FixedValue { - get; - set; - } - public bool Expert { - get; - set; - } - public bool ExcludeIfNull { - get; - set; - } + public string Description; + public string Name { get; set; } + } - public string Name { - get; - set; - } - } + /// + /// Attribute for telling that a field is linked to a property in the ini-configuration selection + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class IniPropertyAttribute : Attribute + { + public IniPropertyAttribute() + { + Separator = ","; + } + + public IniPropertyAttribute(string name) : this() + { + Name = name; + } + + public string Description { get; set; } + public string Separator { get; set; } + public string DefaultValue { get; set; } + + public string LanguageKey { get; set; } + + // If Encrypted is set to true, the value will be decrypted on load and encrypted on save + public bool Encrypted { get; set; } + public bool FixedValue { get; set; } + public bool Expert { get; set; } + public bool ExcludeIfNull { get; set; } + + public string Name { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IniFile/IniConfig.cs b/src/GreenshotPlugin/IniFile/IniConfig.cs index 5ea33f6df..691bd6eb2 100644 --- a/src/GreenshotPlugin/IniFile/IniConfig.cs +++ b/src/GreenshotPlugin/IniFile/IniConfig.cs @@ -27,438 +27,548 @@ using System.Text; using System.Threading; using log4net; -namespace GreenshotPlugin.IniFile { - public class IniConfig { - private static readonly ILog Log = LogManager.GetLogger(typeof(IniConfig)); - private const string IniExtension = ".ini"; - private const string DefaultsPostfix = "-defaults"; - private const string FixedPostfix = "-fixed"; +namespace GreenshotPlugin.IniFile +{ + public class IniConfig + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IniConfig)); + private const string IniExtension = ".ini"; + private const string DefaultsPostfix = "-defaults"; + private const string FixedPostfix = "-fixed"; - /// - /// A lock object for the ini file saving - /// - private static readonly object IniLock = new object(); + /// + /// A lock object for the ini file saving + /// + private static readonly object IniLock = new object(); - /// - /// As the ini implementation is kept someone generic, for reusing, this holds the name of the application - /// - private static string _applicationName; + /// + /// As the ini implementation is kept someone generic, for reusing, this holds the name of the application + /// + private static string _applicationName; - /// - /// As the ini implementation is kept someone generic, for reusing, this holds the name of the configuration - /// - private static string _configName; + /// + /// As the ini implementation is kept someone generic, for reusing, this holds the name of the configuration + /// + private static string _configName; - /// - /// A Dictionary with all the sections stored by section name - /// - private static readonly IDictionary SectionMap = new Dictionary(); + /// + /// A Dictionary with all the sections stored by section name + /// + private static readonly IDictionary SectionMap = new Dictionary(); - /// - /// A Dictionary with the properties for a section stored by section name - /// - private static IDictionary> _sections = new Dictionary>(); + /// + /// A Dictionary with the properties for a section stored by section name + /// + private static IDictionary> _sections = new Dictionary>(); - /// - /// A Dictionary with the fixed-properties for a section stored by section name - /// - private static IDictionary> _fixedProperties; - - /// - /// Stores if we checked for portable - /// - private static bool _portableCheckMade; + /// + /// A Dictionary with the fixed-properties for a section stored by section name + /// + private static IDictionary> _fixedProperties; - /// - /// Is the configuration portable (meaning we don't store it in the AppData directory) - /// - public static bool IsPortable { get; private set; } + /// + /// Stores if we checked for portable + /// + private static bool _portableCheckMade; - /// - /// Config directory when set from external - /// - public static string IniDirectory { - get; - set; - } + /// + /// Is the configuration portable (meaning we don't store it in the AppData directory) + /// + public static bool IsPortable { get; private set; } - /// - /// Initialize the ini config - /// - /// - /// - public static void Init(string appName, string configName) { - _applicationName = appName; - _configName = configName; - Reload(); - } + /// + /// Config directory when set from external + /// + public static string IniDirectory { get; set; } - /// - /// Checks if we initialized the ini - /// - public static bool IsInitialized => _applicationName != null && _configName != null && SectionMap.Count > 0; + /// + /// Initialize the ini config + /// + /// + /// + public static void Init(string appName, string configName) + { + _applicationName = appName; + _configName = configName; + Reload(); + } - /// - /// This forces the ini to be stored in the startup path, used for portable applications - /// - public static void ForceIniInStartupPath() { - if (_portableCheckMade) { - throw new Exception("ForceLocal should be called before any file is read"); - } - IsPortable = false; - _portableCheckMade = true; - string applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - if (_applicationName == null || _configName == null) { - Init(); - } - if (applicationStartupPath == null) - { - return; - } - string forcedIni = Path.Combine(applicationStartupPath, _applicationName + IniExtension); - if (!File.Exists(forcedIni)) { - using (File.Create(forcedIni)) {} - } - } + /// + /// Checks if we initialized the ini + /// + public static bool IsInitialized => _applicationName != null && _configName != null && SectionMap.Count > 0; - /// - /// Default init - /// - public static void Init() { - AssemblyProductAttribute[] assemblyProductAttributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false) as AssemblyProductAttribute[]; - if (assemblyProductAttributes != null && assemblyProductAttributes.Length > 0) { - string productName = assemblyProductAttributes[0].Product; - Log.InfoFormat("Using ProductName {0}", productName); - Init(productName, productName); - } else { - throw new InvalidOperationException("Assembly ProductName not set."); - } - } + /// + /// This forces the ini to be stored in the startup path, used for portable applications + /// + public static void ForceIniInStartupPath() + { + if (_portableCheckMade) + { + throw new Exception("ForceLocal should be called before any file is read"); + } - /// - /// Get the location of the configuration - /// - public static string ConfigLocation { - get { - if (IsInitialized) { - return CreateIniLocation(_configName + IniExtension, false); - } - throw new InvalidOperationException("Ini configuration was not initialized!"); - } - } + IsPortable = false; + _portableCheckMade = true; + string applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + if (_applicationName == null || _configName == null) + { + Init(); + } - /// - /// Create the location of the configuration file - /// - private static string CreateIniLocation(string configFilename, bool isReadOnly) { - if (_applicationName == null || _configName == null) { - throw new InvalidOperationException("IniConfig.Init not called!"); - } - string iniFilePath = null; + if (applicationStartupPath == null) + { + return; + } - // Check if a Ini-Directory was supplied, and it's valid, use this before any others. - try { - if (IniDirectory != null && Directory.Exists(IniDirectory)) { - // If the greenshot.ini is requested, use the supplied directory even if empty - if (!isReadOnly) { - return Path.Combine(IniDirectory, configFilename); - } - iniFilePath = Path.Combine(IniDirectory, configFilename); - if (File.Exists(iniFilePath)) { - return iniFilePath; - } - iniFilePath = null; - } - } catch (Exception exception) { - Log.WarnFormat("The ini-directory {0} can't be used due to: {1}", IniDirectory, exception.Message); - } + string forcedIni = Path.Combine(applicationStartupPath, _applicationName + IniExtension); + if (!File.Exists(forcedIni)) + { + using (File.Create(forcedIni)) + { + } + } + } - string applicationStartupPath; - try { - applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - } catch (Exception exception) { - Log.WarnFormat("Problem retrieving the AssemblyLocation: {0} (Designer mode?)", exception.Message); - applicationStartupPath = @"."; - } - if (applicationStartupPath != null) - { - string pafPath = Path.Combine(applicationStartupPath, @"App\" + _applicationName); - - if (IsPortable || !_portableCheckMade) { - if (!IsPortable) { - Log.Info("Checking for portable mode."); - _portableCheckMade = true; - if (Directory.Exists(pafPath)) { - IsPortable = true; - Log.Info("Portable mode active!"); - } - } - if (IsPortable) { - string pafConfigPath = Path.Combine(applicationStartupPath, @"Data\Settings"); - try { - if (!Directory.Exists(pafConfigPath)) { - Directory.CreateDirectory(pafConfigPath); - } - iniFilePath = Path.Combine(pafConfigPath, configFilename); - } catch(Exception e) { - Log.InfoFormat("Portable mode NOT possible, couldn't create directory '{0}'! Reason: {1}", pafConfigPath, e.Message); - } - } - } - } - if (iniFilePath == null) - { - // check if file is in the same location as started from, if this is the case - // we will use this file instead of the ApplicationData folder - // Done for Feature Request #2741508 - if (applicationStartupPath != null) - { - iniFilePath = Path.Combine(applicationStartupPath, configFilename); - } - if (!File.Exists(iniFilePath)) { - string iniDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), _applicationName); - if (!Directory.Exists(iniDirectory)) { - Directory.CreateDirectory(iniDirectory); - } - iniFilePath = Path.Combine(iniDirectory, configFilename); - } - } - Log.InfoFormat("Using ini file {0}", iniFilePath); - return iniFilePath; - } + /// + /// Default init + /// + public static void Init() + { + AssemblyProductAttribute[] assemblyProductAttributes = + Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false) as AssemblyProductAttribute[]; + if (assemblyProductAttributes != null && assemblyProductAttributes.Length > 0) + { + string productName = assemblyProductAttributes[0].Product; + Log.InfoFormat("Using ProductName {0}", productName); + Init(productName, productName); + } + else + { + throw new InvalidOperationException("Assembly ProductName not set."); + } + } - /// - /// Reload the Ini file - /// - public static void Reload() { - // Clear the current properties - _sections = new Dictionary>(); - // Load the defaults - Read(CreateIniLocation(_configName + DefaultsPostfix + IniExtension, true)); - // Load the normal - Read(CreateIniLocation(_configName + IniExtension, false)); - // Load the fixed settings - _fixedProperties = Read(CreateIniLocation(_configName + FixedPostfix + IniExtension, true)); + /// + /// Get the location of the configuration + /// + public static string ConfigLocation + { + get + { + if (IsInitialized) + { + return CreateIniLocation(_configName + IniExtension, false); + } - foreach (IniSection section in SectionMap.Values) { - try { - section.Fill(PropertiesForSection(section)); - FixProperties(section); - } catch (Exception ex) { - string sectionName = "unknown"; - if (section?.IniSectionAttribute?.Name != null) { - sectionName = section.IniSectionAttribute.Name; - } - Log.WarnFormat("Problem reading the ini section {0}", sectionName); - Log.Warn("Exception", ex); - } - } - } + throw new InvalidOperationException("Ini configuration was not initialized!"); + } + } - /// - /// This "fixes" the properties of the section, meaning any properties in the fixed file can't be changed. - /// - /// IniSection - private static void FixProperties(IniSection section) { - // Make properties unchangeable - if (_fixedProperties == null) - { - return; - } + /// + /// Create the location of the configuration file + /// + private static string CreateIniLocation(string configFilename, bool isReadOnly) + { + if (_applicationName == null || _configName == null) + { + throw new InvalidOperationException("IniConfig.Init not called!"); + } + + string iniFilePath = null; + + // Check if a Ini-Directory was supplied, and it's valid, use this before any others. + try + { + if (IniDirectory != null && Directory.Exists(IniDirectory)) + { + // If the greenshot.ini is requested, use the supplied directory even if empty + if (!isReadOnly) + { + return Path.Combine(IniDirectory, configFilename); + } + + iniFilePath = Path.Combine(IniDirectory, configFilename); + if (File.Exists(iniFilePath)) + { + return iniFilePath; + } + + iniFilePath = null; + } + } + catch (Exception exception) + { + Log.WarnFormat("The ini-directory {0} can't be used due to: {1}", IniDirectory, exception.Message); + } + + string applicationStartupPath; + try + { + applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + } + catch (Exception exception) + { + Log.WarnFormat("Problem retrieving the AssemblyLocation: {0} (Designer mode?)", exception.Message); + applicationStartupPath = @"."; + } + + if (applicationStartupPath != null) + { + string pafPath = Path.Combine(applicationStartupPath, @"App\" + _applicationName); + + if (IsPortable || !_portableCheckMade) + { + if (!IsPortable) + { + Log.Info("Checking for portable mode."); + _portableCheckMade = true; + if (Directory.Exists(pafPath)) + { + IsPortable = true; + Log.Info("Portable mode active!"); + } + } + + if (IsPortable) + { + string pafConfigPath = Path.Combine(applicationStartupPath, @"Data\Settings"); + try + { + if (!Directory.Exists(pafConfigPath)) + { + Directory.CreateDirectory(pafConfigPath); + } + + iniFilePath = Path.Combine(pafConfigPath, configFilename); + } + catch (Exception e) + { + Log.InfoFormat("Portable mode NOT possible, couldn't create directory '{0}'! Reason: {1}", pafConfigPath, e.Message); + } + } + } + } + + if (iniFilePath == null) + { + // check if file is in the same location as started from, if this is the case + // we will use this file instead of the ApplicationData folder + // Done for Feature Request #2741508 + if (applicationStartupPath != null) + { + iniFilePath = Path.Combine(applicationStartupPath, configFilename); + } + + if (!File.Exists(iniFilePath)) + { + string iniDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), _applicationName); + if (!Directory.Exists(iniDirectory)) + { + Directory.CreateDirectory(iniDirectory); + } + + iniFilePath = Path.Combine(iniDirectory, configFilename); + } + } + + Log.InfoFormat("Using ini file {0}", iniFilePath); + return iniFilePath; + } + + /// + /// Reload the Ini file + /// + public static void Reload() + { + // Clear the current properties + _sections = new Dictionary>(); + // Load the defaults + Read(CreateIniLocation(_configName + DefaultsPostfix + IniExtension, true)); + // Load the normal + Read(CreateIniLocation(_configName + IniExtension, false)); + // Load the fixed settings + _fixedProperties = Read(CreateIniLocation(_configName + FixedPostfix + IniExtension, true)); + + foreach (IniSection section in SectionMap.Values) + { + try + { + section.Fill(PropertiesForSection(section)); + FixProperties(section); + } + catch (Exception ex) + { + string sectionName = "unknown"; + if (section?.IniSectionAttribute?.Name != null) + { + sectionName = section.IniSectionAttribute.Name; + } + + Log.WarnFormat("Problem reading the ini section {0}", sectionName); + Log.Warn("Exception", ex); + } + } + } + + /// + /// This "fixes" the properties of the section, meaning any properties in the fixed file can't be changed. + /// + /// IniSection + private static void FixProperties(IniSection section) + { + // Make properties unchangeable + if (_fixedProperties == null) + { + return; + } if (!_fixedProperties.TryGetValue(section.IniSectionAttribute.Name, out var fixedPropertiesForSection)) - { - return; - } - foreach (string fixedPropertyKey in fixedPropertiesForSection.Keys) { - if (section.Values.ContainsKey(fixedPropertyKey)) { - section.Values[fixedPropertyKey].IsFixed = true; - } - } - } + { + return; + } - /// - /// Read the ini file into the Dictionary - /// - /// Path & Filename of ini file - private static IDictionary> Read(string iniLocation) { - if (!File.Exists(iniLocation)) { - Log.Info("Can't find file: " + iniLocation); - return null; - } - Log.InfoFormat("Loading ini-file: {0}", iniLocation); - //LOG.Info("Reading ini-properties from file: " + iniLocation); - var newSections = IniReader.Read(iniLocation, Encoding.UTF8); - // Merge the newly loaded properties to the already available - foreach(string section in newSections.Keys) { - IDictionary newProperties = newSections[section]; - if (!_sections.ContainsKey(section)) { - // This section is not yet loaded, simply add the complete section - _sections.Add(section, newProperties); - } else { - // Overwrite or add every property from the newly loaded section to the available one - var currentProperties = _sections[section]; - foreach(string propertyName in newProperties.Keys) { - string propertyValue = newProperties[propertyName]; - if (currentProperties.ContainsKey(propertyName)) { - // Override current value as we are loading in a certain order which insures the default, current and fixed - currentProperties[propertyName] = propertyValue; - } else { - // Add "new" value - currentProperties.Add(propertyName, propertyValue); - } - } - } - } - return newSections; - } + foreach (string fixedPropertyKey in fixedPropertiesForSection.Keys) + { + if (section.Values.ContainsKey(fixedPropertyKey)) + { + section.Values[fixedPropertyKey].IsFixed = true; + } + } + } - public static IEnumerable IniSectionNames { - get { - foreach (string sectionName in SectionMap.Keys) { - yield return sectionName; - } - } - } + /// + /// Read the ini file into the Dictionary + /// + /// Path & Filename of ini file + private static IDictionary> Read(string iniLocation) + { + if (!File.Exists(iniLocation)) + { + Log.Info("Can't find file: " + iniLocation); + return null; + } - /// - /// Method used for internal tricks... - /// - /// - /// - public static IniSection GetIniSection(string sectionName) { + Log.InfoFormat("Loading ini-file: {0}", iniLocation); + //LOG.Info("Reading ini-properties from file: " + iniLocation); + var newSections = IniReader.Read(iniLocation, Encoding.UTF8); + // Merge the newly loaded properties to the already available + foreach (string section in newSections.Keys) + { + IDictionary newProperties = newSections[section]; + if (!_sections.ContainsKey(section)) + { + // This section is not yet loaded, simply add the complete section + _sections.Add(section, newProperties); + } + else + { + // Overwrite or add every property from the newly loaded section to the available one + var currentProperties = _sections[section]; + foreach (string propertyName in newProperties.Keys) + { + string propertyValue = newProperties[propertyName]; + if (currentProperties.ContainsKey(propertyName)) + { + // Override current value as we are loading in a certain order which insures the default, current and fixed + currentProperties[propertyName] = propertyValue; + } + else + { + // Add "new" value + currentProperties.Add(propertyName, propertyValue); + } + } + } + } + + return newSections; + } + + public static IEnumerable IniSectionNames + { + get + { + foreach (string sectionName in SectionMap.Keys) + { + yield return sectionName; + } + } + } + + /// + /// Method used for internal tricks... + /// + /// + /// + public static IniSection GetIniSection(string sectionName) + { SectionMap.TryGetValue(sectionName, out var returnValue); - return returnValue; - } + return returnValue; + } - /// - /// A generic method which returns an instance of the supplied type, filled with it's configuration - /// - /// IniSection Type to get the configuration for - /// Filled instance of IniSection type which was supplied - public static T GetIniSection() where T : IniSection { - return GetIniSection(true); - } + /// + /// A generic method which returns an instance of the supplied type, filled with it's configuration + /// + /// IniSection Type to get the configuration for + /// Filled instance of IniSection type which was supplied + public static T GetIniSection() where T : IniSection + { + return GetIniSection(true); + } - /// - /// - /// - /// IniSection Type to get the configuration for - /// false to skip saving - /// IniSection - public static T GetIniSection(bool allowSave) where T : IniSection { - T section; + /// + /// + /// + /// IniSection Type to get the configuration for + /// false to skip saving + /// IniSection + public static T GetIniSection(bool allowSave) where T : IniSection + { + T section; - Type iniSectionType = typeof(T); - string sectionName = IniSection.GetIniSectionAttribute(iniSectionType).Name; - if (SectionMap.ContainsKey(sectionName)) { - //LOG.Debug("Returning pre-mapped section " + sectionName); - section = (T)SectionMap[sectionName]; - } else { - // Create instance of this type - section = (T)Activator.CreateInstance(iniSectionType); + Type iniSectionType = typeof(T); + string sectionName = IniSection.GetIniSectionAttribute(iniSectionType).Name; + if (SectionMap.ContainsKey(sectionName)) + { + //LOG.Debug("Returning pre-mapped section " + sectionName); + section = (T) SectionMap[sectionName]; + } + else + { + // Create instance of this type + section = (T) Activator.CreateInstance(iniSectionType); - // Store for later save & retrieval - SectionMap.Add(sectionName, section); - section.Fill(PropertiesForSection(section)); - FixProperties(section); - } - if (allowSave && section.IsDirty) { - Log.DebugFormat("Section {0} is marked dirty, saving!", sectionName); - Save(); - } - return section; - } + // Store for later save & retrieval + SectionMap.Add(sectionName, section); + section.Fill(PropertiesForSection(section)); + FixProperties(section); + } - /// - /// Get the raw properties for a section - /// - /// - /// - public static IDictionary PropertiesForSection(IniSection section) { - string sectionName = section.IniSectionAttribute.Name; - // Get the properties for the section - IDictionary properties; - if (_sections.ContainsKey(sectionName)) { - properties = _sections[sectionName]; - } else { - _sections.Add(sectionName, new Dictionary()); - properties = _sections[sectionName]; - } - return properties; - } + if (allowSave && section.IsDirty) + { + Log.DebugFormat("Section {0} is marked dirty, saving!", sectionName); + Save(); + } - /// - /// Save the ini file - /// - public static void Save() { - bool acquiredLock = false; - try { - acquiredLock = Monitor.TryEnter(IniLock, TimeSpan.FromMilliseconds(200)); - if (acquiredLock) { - // Code that accesses resources that are protected by the lock. - string iniLocation = CreateIniLocation(_configName + IniExtension, false); - try { - SaveInternally(iniLocation); - } catch (Exception ex) { - Log.Error("A problem occured while writing the configuration file to: " + iniLocation); - Log.Error(ex); - } - } else { - // Code to deal with the fact that the lock was not acquired. - Log.Warn("A second thread tried to save the ini-file, we blocked as the first took too long."); - } - } finally { - if (acquiredLock) { - Monitor.Exit(IniLock); - } - } - } + return section; + } - /// - /// The real save implementation - /// - /// - private static void SaveInternally(string iniLocation) { - Log.Info("Saving configuration to: " + iniLocation); - var iniPath = Path.GetDirectoryName(iniLocation); - if (iniPath != null && !Directory.Exists(iniPath)) - { - Directory.CreateDirectory(iniPath); - } + /// + /// Get the raw properties for a section + /// + /// + /// + public static IDictionary PropertiesForSection(IniSection section) + { + string sectionName = section.IniSectionAttribute.Name; + // Get the properties for the section + IDictionary properties; + if (_sections.ContainsKey(sectionName)) + { + properties = _sections[sectionName]; + } + else + { + _sections.Add(sectionName, new Dictionary()); + properties = _sections[sectionName]; + } + + return properties; + } + + /// + /// Save the ini file + /// + public static void Save() + { + bool acquiredLock = false; + try + { + acquiredLock = Monitor.TryEnter(IniLock, TimeSpan.FromMilliseconds(200)); + if (acquiredLock) + { + // Code that accesses resources that are protected by the lock. + string iniLocation = CreateIniLocation(_configName + IniExtension, false); + try + { + SaveInternally(iniLocation); + } + catch (Exception ex) + { + Log.Error("A problem occured while writing the configuration file to: " + iniLocation); + Log.Error(ex); + } + } + else + { + // Code to deal with the fact that the lock was not acquired. + Log.Warn("A second thread tried to save the ini-file, we blocked as the first took too long."); + } + } + finally + { + if (acquiredLock) + { + Monitor.Exit(IniLock); + } + } + } + + /// + /// The real save implementation + /// + /// + private static void SaveInternally(string iniLocation) + { + Log.Info("Saving configuration to: " + iniLocation); + var iniPath = Path.GetDirectoryName(iniLocation); + if (iniPath != null && !Directory.Exists(iniPath)) + { + Directory.CreateDirectory(iniPath); + } using var memoryStream = new MemoryStream(); using TextWriter writer = new StreamWriter(memoryStream, Encoding.UTF8); - foreach (var section in SectionMap.Values) { + foreach (var section in SectionMap.Values) + { section.Write(writer, false); // Add empty line after section writer.WriteLine(); section.IsDirty = false; } + writer.WriteLine(); // Write left over properties - foreach (string sectionName in _sections.Keys) { + foreach (string sectionName in _sections.Keys) + { // Check if the section is one that is "registered", if so skip it! if (SectionMap.ContainsKey(sectionName)) { continue; } + writer.WriteLine("; The section {0} hasn't been 'claimed' since the last start of Greenshot, therefor it doesn't have additional information here!", sectionName); - writer.WriteLine("; The reason could be that the section {0} just hasn't been used, a plugin has an error and can't claim it or maybe the whole section {0} is obsolete.", sectionName); + writer.WriteLine( + "; The reason could be that the section {0} just hasn't been used, a plugin has an error and can't claim it or maybe the whole section {0} is obsolete.", + sectionName); // Write section name writer.WriteLine("[{0}]", sectionName); var properties = _sections[sectionName]; // Loop and write properties - foreach (string propertyName in properties.Keys) { + foreach (string propertyName in properties.Keys) + { writer.WriteLine("{0}={1}", propertyName, properties[propertyName]); } + writer.WriteLine(); } + // Don't forget to flush the buffer writer.Flush(); // Now write the created .ini string to the real file using FileStream fileStream = new FileStream(iniLocation, FileMode.Create, FileAccess.Write); memoryStream.WriteTo(fileStream); } - } -} + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IniFile/IniReader.cs b/src/GreenshotPlugin/IniFile/IniReader.cs index 641b5414e..de83fde26 100644 --- a/src/GreenshotPlugin/IniFile/IniReader.cs +++ b/src/GreenshotPlugin/IniFile/IniReader.cs @@ -23,63 +23,82 @@ using System.Collections.Generic; using System.IO; using System.Text; -namespace GreenshotPlugin.IniFile { - /// - /// The IniReader does exactly what it says, it reads the .ini file - /// - public static class IniReader { - private const char SectionStartToken = '['; - private const char SectionEndToken = ']'; - private const char CommentToken = ';'; - private static readonly char[] Assignment = { '=' }; +namespace GreenshotPlugin.IniFile +{ + /// + /// The IniReader does exactly what it says, it reads the .ini file + /// + public static class IniReader + { + private const char SectionStartToken = '['; + private const char SectionEndToken = ']'; + private const char CommentToken = ';'; - /// - /// Read an ini file to a Dictionary, each key is a section and the value is a Dictionary with name and values. - /// - /// - /// - /// - public static IDictionary> Read(string path, Encoding encoding) { - var ini = new Dictionary>(); - using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024)) + private static readonly char[] Assignment = + { + '=' + }; + + /// + /// Read an ini file to a Dictionary, each key is a section and the value is a Dictionary with name and values. + /// + /// + /// + /// + public static IDictionary> Read(string path, Encoding encoding) + { + var ini = new Dictionary>(); + using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024)) { using var streamReader = new StreamReader(fileStream, encoding); IDictionary nameValues = new Dictionary(); - while (!streamReader.EndOfStream) { + while (!streamReader.EndOfStream) + { string line = streamReader.ReadLine(); if (line == null) { continue; } + string cleanLine = line.Trim(); - if (cleanLine.Length == 0 || cleanLine[0] == CommentToken) { + if (cleanLine.Length == 0 || cleanLine[0] == CommentToken) + { continue; } - if (cleanLine[0] == SectionStartToken) { - var sectionEndIndex = line.IndexOf(SectionEndToken,1); - if (sectionEndIndex <0) + + if (cleanLine[0] == SectionStartToken) + { + var sectionEndIndex = line.IndexOf(SectionEndToken, 1); + if (sectionEndIndex < 0) { continue; } - string section = line.Substring(1,sectionEndIndex-1).Trim(); + + string section = line.Substring(1, sectionEndIndex - 1).Trim(); if (!ini.TryGetValue(section, out nameValues)) { nameValues = new Dictionary(); ini.Add(section, nameValues); } - } else { + } + else + { string[] keyvalueSplitter = line.Split(Assignment, 2); string name = keyvalueSplitter[0]; string inivalue = keyvalueSplitter.Length > 1 ? keyvalueSplitter[1] : null; - if (nameValues.ContainsKey(name)) { + if (nameValues.ContainsKey(name)) + { nameValues[name] = inivalue; - } else { + } + else + { nameValues.Add(name, inivalue); } } } } - return ini; - } - } -} + + return ini; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IniFile/IniSection.cs b/src/GreenshotPlugin/IniFile/IniSection.cs index c8c9221dd..1c5b501a9 100644 --- a/src/GreenshotPlugin/IniFile/IniSection.cs +++ b/src/GreenshotPlugin/IniFile/IniSection.cs @@ -26,173 +26,210 @@ using System.Reflection; using GreenshotPlugin.Core; using log4net; -namespace GreenshotPlugin.IniFile { - /// - /// Base class for all IniSections - /// - [Serializable] - public abstract class IniSection { - protected static ILog LOG = LogManager.GetLogger(typeof(IniSection)); +namespace GreenshotPlugin.IniFile +{ + /// + /// Base class for all IniSections + /// + [Serializable] + public abstract class IniSection + { + protected static ILog LOG = LogManager.GetLogger(typeof(IniSection)); - [NonSerialized] - private readonly IDictionary values = new Dictionary(); - [NonSerialized] - private IniSectionAttribute iniSectionAttribute; - public IniSectionAttribute IniSectionAttribute { - get { - if (iniSectionAttribute == null) { - iniSectionAttribute = GetIniSectionAttribute(GetType()); - } - return iniSectionAttribute; - } - } + [NonSerialized] private readonly IDictionary values = new Dictionary(); + [NonSerialized] private IniSectionAttribute iniSectionAttribute; - /// - /// Get the dictionary with all the IniValues - /// - public IDictionary Values { - get { - return values; - } - } + public IniSectionAttribute IniSectionAttribute + { + get + { + if (iniSectionAttribute == null) + { + iniSectionAttribute = GetIniSectionAttribute(GetType()); + } - /// - /// Flag to specify if values have been changed - /// - public bool IsDirty { - get; - set; - } + return iniSectionAttribute; + } + } - /// - /// Supply values we can't put as defaults - /// - /// The property to return a default for - /// object with the default value for the supplied property - public virtual object GetDefault(string property) { - return null; - } + /// + /// Get the dictionary with all the IniValues + /// + public IDictionary Values + { + get { return values; } + } - /// - /// This method will be called before converting the property, making to possible to correct a certain value - /// Can be used when migration is needed - /// - /// The name of the property - /// The string value of the property - /// string with the propertyValue, modified or not... - public virtual string PreCheckValue(string propertyName, string propertyValue) { - return propertyValue; - } + /// + /// Flag to specify if values have been changed + /// + public bool IsDirty { get; set; } - /// - /// This method will be called after reading the configuration, so eventually some corrections can be made - /// - public virtual void AfterLoad() { - } + /// + /// Supply values we can't put as defaults + /// + /// The property to return a default for + /// object with the default value for the supplied property + public virtual object GetDefault(string property) + { + return null; + } - /// - /// This will be called before saving the Section, so we can encrypt passwords etc... - /// - public virtual void BeforeSave() { - } + /// + /// This method will be called before converting the property, making to possible to correct a certain value + /// Can be used when migration is needed + /// + /// The name of the property + /// The string value of the property + /// string with the propertyValue, modified or not... + public virtual string PreCheckValue(string propertyName, string propertyValue) + { + return propertyValue; + } - /// - /// This will be called before saving the Section, so we can decrypt passwords etc... - /// - public virtual void AfterSave() { - } + /// + /// This method will be called after reading the configuration, so eventually some corrections can be made + /// + public virtual void AfterLoad() + { + } - /// - /// Helper method to get the IniSectionAttribute of a type - /// - /// - /// - public static IniSectionAttribute GetIniSectionAttribute(Type iniSectionType) { - Attribute[] classAttributes = Attribute.GetCustomAttributes(iniSectionType); - foreach (Attribute attribute in classAttributes) { - if (attribute is IniSectionAttribute) { - return (IniSectionAttribute)attribute; - } - } - return null; - } + /// + /// This will be called before saving the Section, so we can encrypt passwords etc... + /// + public virtual void BeforeSave() + { + } - /// - /// Fill the section with the supplied properties - /// - /// - public void Fill(IDictionary properties) { - Type iniSectionType = GetType(); + /// + /// This will be called before saving the Section, so we can decrypt passwords etc... + /// + public virtual void AfterSave() + { + } - // Iterate over the members and create IniValueContainers - foreach (FieldInfo fieldInfo in iniSectionType.GetFields()) { - if (Attribute.IsDefined(fieldInfo, typeof(IniPropertyAttribute))) { - IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute)fieldInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; - if (!Values.ContainsKey(iniPropertyAttribute.Name)) { - Values.Add(iniPropertyAttribute.Name, new IniValue(this, fieldInfo, iniPropertyAttribute)); - } - } - } + /// + /// Helper method to get the IniSectionAttribute of a type + /// + /// + /// + public static IniSectionAttribute GetIniSectionAttribute(Type iniSectionType) + { + Attribute[] classAttributes = Attribute.GetCustomAttributes(iniSectionType); + foreach (Attribute attribute in classAttributes) + { + if (attribute is IniSectionAttribute) + { + return (IniSectionAttribute) attribute; + } + } - foreach (PropertyInfo propertyInfo in iniSectionType.GetProperties()) { - if (Attribute.IsDefined(propertyInfo, typeof(IniPropertyAttribute))) { - if (!Values.ContainsKey(propertyInfo.Name)) { - IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute)propertyInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; - Values.Add(iniPropertyAttribute.Name, new IniValue(this, propertyInfo, iniPropertyAttribute)); - } - } - } + return null; + } - foreach (string fieldName in Values.Keys) { - IniValue iniValue = Values[fieldName]; - try { - iniValue.SetValueFromProperties(properties); - if (iniValue.Attributes.Encrypted) { - if (iniValue.Value is string stringValue && stringValue.Length > 2) { - iniValue.Value = stringValue.Decrypt(); - } - } - } catch (Exception ex) { - LOG.Error(ex); - } - } - AfterLoad(); - } + /// + /// Fill the section with the supplied properties + /// + /// + public void Fill(IDictionary properties) + { + Type iniSectionType = GetType(); - /// - /// Write the section to the writer - /// - /// - /// - public void Write(TextWriter writer, bool onlyProperties) { - if (IniSectionAttribute == null) { - throw new ArgumentException("Section didn't implement the IniSectionAttribute"); - } - BeforeSave(); - try { + // Iterate over the members and create IniValueContainers + foreach (FieldInfo fieldInfo in iniSectionType.GetFields()) + { + if (Attribute.IsDefined(fieldInfo, typeof(IniPropertyAttribute))) + { + IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute) fieldInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; + if (!Values.ContainsKey(iniPropertyAttribute.Name)) + { + Values.Add(iniPropertyAttribute.Name, new IniValue(this, fieldInfo, iniPropertyAttribute)); + } + } + } - if (!onlyProperties) { - writer.WriteLine("; {0}", IniSectionAttribute.Description); - } - writer.WriteLine("[{0}]", IniSectionAttribute.Name); + foreach (PropertyInfo propertyInfo in iniSectionType.GetProperties()) + { + if (Attribute.IsDefined(propertyInfo, typeof(IniPropertyAttribute))) + { + if (!Values.ContainsKey(propertyInfo.Name)) + { + IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute) propertyInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; + Values.Add(iniPropertyAttribute.Name, new IniValue(this, propertyInfo, iniPropertyAttribute)); + } + } + } - foreach (IniValue value in Values.Values) { - if (value.Attributes.Encrypted) { - if (value.Value is string stringValue && stringValue.Length > 2) { - value.Value = stringValue.Encrypt(); - } - } - // Write the value - value.Write(writer, onlyProperties); - if (value.Attributes.Encrypted) { - if (value.Value is string stringValue && stringValue.Length > 2) { - value.Value = stringValue.Decrypt(); - } - } - } - } finally { - AfterSave(); - } - } - } -} + foreach (string fieldName in Values.Keys) + { + IniValue iniValue = Values[fieldName]; + try + { + iniValue.SetValueFromProperties(properties); + if (iniValue.Attributes.Encrypted) + { + if (iniValue.Value is string stringValue && stringValue.Length > 2) + { + iniValue.Value = stringValue.Decrypt(); + } + } + } + catch (Exception ex) + { + LOG.Error(ex); + } + } + + AfterLoad(); + } + + /// + /// Write the section to the writer + /// + /// + /// + public void Write(TextWriter writer, bool onlyProperties) + { + if (IniSectionAttribute == null) + { + throw new ArgumentException("Section didn't implement the IniSectionAttribute"); + } + + BeforeSave(); + try + { + if (!onlyProperties) + { + writer.WriteLine("; {0}", IniSectionAttribute.Description); + } + + writer.WriteLine("[{0}]", IniSectionAttribute.Name); + + foreach (IniValue value in Values.Values) + { + if (value.Attributes.Encrypted) + { + if (value.Value is string stringValue && stringValue.Length > 2) + { + value.Value = stringValue.Encrypt(); + } + } + + // Write the value + value.Write(writer, onlyProperties); + if (value.Attributes.Encrypted) + { + if (value.Value is string stringValue && stringValue.Length > 2) + { + value.Value = stringValue.Decrypt(); + } + } + } + } + finally + { + AfterSave(); + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/IniFile/IniValue.cs b/src/GreenshotPlugin/IniFile/IniValue.cs index de04c0b44..a6599990a 100644 --- a/src/GreenshotPlugin/IniFile/IniValue.cs +++ b/src/GreenshotPlugin/IniFile/IniValue.cs @@ -27,446 +27,595 @@ using System.Reflection; using System.Text; using log4net; -namespace GreenshotPlugin.IniFile { - /// - /// A container to be able to pass the value from a IniSection around. - /// - public class IniValue { - private static readonly ILog Log = LogManager.GetLogger(typeof(IniValue)); - private readonly PropertyInfo _propertyInfo; - private readonly FieldInfo _fieldInfo; - private readonly IniSection _containingIniSection; - private readonly IniPropertyAttribute _attributes; +namespace GreenshotPlugin.IniFile +{ + /// + /// A container to be able to pass the value from a IniSection around. + /// + public class IniValue + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IniValue)); + private readonly PropertyInfo _propertyInfo; + private readonly FieldInfo _fieldInfo; + private readonly IniSection _containingIniSection; + private readonly IniPropertyAttribute _attributes; - public IniValue(IniSection containingIniSection, PropertyInfo propertyInfo, IniPropertyAttribute iniPropertyAttribute) { - _containingIniSection = containingIniSection; - _propertyInfo = propertyInfo; - _attributes = iniPropertyAttribute; - } + public IniValue(IniSection containingIniSection, PropertyInfo propertyInfo, IniPropertyAttribute iniPropertyAttribute) + { + _containingIniSection = containingIniSection; + _propertyInfo = propertyInfo; + _attributes = iniPropertyAttribute; + } - public IniValue(IniSection containingIniSection, FieldInfo fieldInfo, IniPropertyAttribute iniPropertyAttribute) { - _containingIniSection = containingIniSection; - _fieldInfo = fieldInfo; - _attributes = iniPropertyAttribute; - } - - /// - /// Return true when the value is fixed - /// - public bool IsFixed { - get { - if (_attributes != null) { - return _attributes.FixedValue; - } - return false; - } - set { - if (_attributes != null) { - _attributes.FixedValue = value; - } - } - } + public IniValue(IniSection containingIniSection, FieldInfo fieldInfo, IniPropertyAttribute iniPropertyAttribute) + { + _containingIniSection = containingIniSection; + _fieldInfo = fieldInfo; + _attributes = iniPropertyAttribute; + } - /// - /// Return true when the value is for experts - /// - public bool IsExpert { - get { - if (_attributes != null) { - return _attributes.Expert; - } - return false; - } - set { - if (_attributes != null) { - _attributes.Expert = value; - } - } - } + /// + /// Return true when the value is fixed + /// + public bool IsFixed + { + get + { + if (_attributes != null) + { + return _attributes.FixedValue; + } + + return false; + } + set + { + if (_attributes != null) + { + _attributes.FixedValue = value; + } + } + } + + /// + /// Return true when the value is for experts + /// + public bool IsExpert + { + get + { + if (_attributes != null) + { + return _attributes.Expert; + } + + return false; + } + set + { + if (_attributes != null) + { + _attributes.Expert = value; + } + } + } - /// - /// Return true when the value is can be changed by the GUI - /// - public bool IsEditable => !IsFixed; + /// + /// Return true when the value is can be changed by the GUI + /// + public bool IsEditable => !IsFixed; - /// - /// Return true when the value is visible in the GUI - /// - public bool IsVisible => !IsExpert; + /// + /// Return true when the value is visible in the GUI + /// + public bool IsVisible => !IsExpert; - public MemberInfo MemberInfo { - get - { - if (_propertyInfo == null) { - return _fieldInfo; - } - return _propertyInfo; - } - } + public MemberInfo MemberInfo + { + get + { + if (_propertyInfo == null) + { + return _fieldInfo; + } - /// - /// Returns the IniSection this value is contained in - /// - public IniSection ContainingIniSection => _containingIniSection; + return _propertyInfo; + } + } - /// - /// Get the in the ini file defined attributes - /// - public IniPropertyAttribute Attributes => _attributes; + /// + /// Returns the IniSection this value is contained in + /// + public IniSection ContainingIniSection => _containingIniSection; - /// - /// Get the value for this IniValue - /// - public object Value { - get - { - if (_propertyInfo == null) { - return _fieldInfo.GetValue(_containingIniSection); - } - return _propertyInfo.GetValue(_containingIniSection, null); - } - set { - if (_propertyInfo == null) { - _fieldInfo.SetValue(_containingIniSection, value); - } else { - _propertyInfo.SetValue(_containingIniSection, value, null); - } - } - } - - /// - /// Get the Type of the value - /// - public Type ValueType { - get { - var valueType = _propertyInfo?.PropertyType ?? _fieldInfo.FieldType; - if (!valueType.IsGenericType) - { - return valueType; - } - var genericTypeDefinition = valueType.GetGenericTypeDefinition(); - if (genericTypeDefinition != null && genericTypeDefinition == typeof(Nullable<>)) - { - // We are dealing with a generic type that is nullable - valueType = Nullable.GetUnderlyingType(valueType); - } - return valueType; - } - } + /// + /// Get the in the ini file defined attributes + /// + public IniPropertyAttribute Attributes => _attributes; - /// - /// Write the value to the text writer - /// - /// TextWriter to write to - /// true if we do not want the comment - public void Write(TextWriter writer, bool onlyProperties) { - object myValue = Value; - Type valueType = ValueType; - if (myValue == null) { - if (_attributes.ExcludeIfNull) { - return; - } - if (_attributes.DefaultValue != null) { - myValue = _attributes.DefaultValue; - valueType = typeof(string); - } else { - myValue = _containingIniSection.GetDefault(_attributes.Name); - if (myValue != null) { - valueType = myValue.GetType(); - } - } - } - if (myValue == null) { - if (_attributes.ExcludeIfNull) { - return; - } - } - if (!onlyProperties) { - writer.WriteLine("; {0}", _attributes.Description); - } - if (myValue == null) { - writer.WriteLine("{0}=", _attributes.Name); - return; - } - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { - // Handle dictionaries. - Type valueType1 = valueType.GetGenericArguments()[0]; - Type valueType2 = valueType.GetGenericArguments()[1]; - // Get the methods we need to deal with dictionaries. - var keys = valueType.GetProperty("Keys").GetValue(myValue, null); - var item = valueType.GetProperty("Item"); - var enumerator = keys.GetType().GetMethod("GetEnumerator").Invoke(keys, null); - var moveNext = enumerator.GetType().GetMethod("MoveNext"); - var current = enumerator.GetType().GetProperty("Current").GetGetMethod(); - // Get all the values. - while ((bool)moveNext.Invoke(enumerator, null)) { - var key = current.Invoke(enumerator, null); - var valueObject = item.GetValue(myValue, new[] { key }); - // Write to ini file! - writer.WriteLine("{0}.{1}={2}", _attributes.Name, ConvertValueToString(valueType1, key, _attributes.Separator), ConvertValueToString(valueType2, valueObject, _attributes.Separator)); - } - } else { - writer.WriteLine("{0}={1}", _attributes.Name, ConvertValueToString(valueType, myValue, _attributes.Separator)); - } - } + /// + /// Get the value for this IniValue + /// + public object Value + { + get + { + if (_propertyInfo == null) + { + return _fieldInfo.GetValue(_containingIniSection); + } - /// - /// Set the value to the value in the ini file, or default - /// - /// - public void SetValueFromProperties(IDictionary properties) { - string propertyName = _attributes.Name; - string propertyValue = null; - if (properties.ContainsKey(propertyName) && properties[propertyName] != null) { - propertyValue = _containingIniSection.PreCheckValue(propertyName, properties[propertyName]); - } - UseValueOrDefault(propertyValue); - } + return _propertyInfo.GetValue(_containingIniSection, null); + } + set + { + if (_propertyInfo == null) + { + _fieldInfo.SetValue(_containingIniSection, value); + } + else + { + _propertyInfo.SetValue(_containingIniSection, value, null); + } + } + } - /// - /// This method will set the ini value to the supplied value or use the default if non supplied - /// - /// - public void UseValueOrDefault(string propertyValue) { - Type valueType = ValueType; - string propertyName = _attributes.Name; - string defaultValue = _attributes.DefaultValue; - bool defaultUsed = false; - object defaultValueFromConfig = _containingIniSection.GetDefault(propertyName); + /// + /// Get the Type of the value + /// + public Type ValueType + { + get + { + var valueType = _propertyInfo?.PropertyType ?? _fieldInfo.FieldType; + if (!valueType.IsGenericType) + { + return valueType; + } - if (string.IsNullOrEmpty(propertyValue)) { - if (defaultValue != null && defaultValue.Trim().Length != 0) { - propertyValue = defaultValue; - defaultUsed = true; - } else if (defaultValueFromConfig != null) { - Log.DebugFormat("Default for Property {0} implemented!", propertyName); - } else { - if (_attributes.ExcludeIfNull) { - Value = null; - return; - } - Log.DebugFormat("Property {0} has no value or default value!", propertyName); - } - } - // Now set the value - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { - // Logic for Dictionary<,> - Type type1 = valueType.GetGenericArguments()[0]; - Type type2 = valueType.GetGenericArguments()[1]; - //LOG.Info(String.Format("Found Dictionary<{0},{1}>", type1.Name, type2.Name)); - object dictionary = Activator.CreateInstance(valueType); - MethodInfo addMethodInfo = valueType.GetMethod("Add"); - bool addedElements = false; - IDictionary properties = IniConfig.PropertiesForSection(_containingIniSection); - foreach (string key in properties.Keys) { - if (key != null && key.StartsWith(propertyName + ".")) { - // What "key" do we need to store it under? - string subPropertyName = key.Substring(propertyName.Length + 1); - string stringValue = properties[key]; - object newValue1 = null; - object newValue2 = null; - try { - newValue1 = ConvertStringToValueType(type1, subPropertyName, _attributes.Separator); - } catch (Exception ex) { - Log.Warn(ex); - //LOG.Error("Problem converting " + subPropertyName + " to type " + type1.FullName, e); - } - try { - newValue2 = ConvertStringToValueType(type2, stringValue, _attributes.Separator); - } catch (Exception ex) { - Log.Warn(ex); - //LOG.Error("Problem converting " + stringValue + " to type " + type2.FullName, e); - } - addMethodInfo.Invoke(dictionary, new[] { newValue1, newValue2 }); - addedElements = true; - } - } - // No need to return something that isn't filled! - if (addedElements) { - Value = dictionary; - return; - } - if (defaultValueFromConfig != null) { - Value = defaultValueFromConfig; - return; - } - } else if (!string.IsNullOrEmpty(propertyValue)) { - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - // We are dealing with a generic type that is nullable - valueType = Nullable.GetUnderlyingType(valueType); - } - object newValue; - try { - newValue = ConvertStringToValueType(valueType, propertyValue, _attributes.Separator); - } catch (Exception ex1) { - newValue = null; - if (!defaultUsed) { - try { - Log.WarnFormat("Problem '{0}' while converting {1} to type {2} trying fallback...", ex1.Message, propertyValue, valueType.FullName); - newValue = ConvertStringToValueType(valueType, defaultValue, _attributes.Separator); - ContainingIniSection.IsDirty = true; - Log.InfoFormat("Used default value {0} for property {1}", defaultValue, propertyName); - } catch (Exception ex2) { - Log.Warn("Problem converting fallback value " + defaultValue + " to type " + valueType.FullName, ex2); - } - } else { - Log.Warn("Problem converting " + propertyValue + " to type " + valueType.FullName, ex1); - } - } - Value = newValue; - return; - } + var genericTypeDefinition = valueType.GetGenericTypeDefinition(); + if (genericTypeDefinition != null && genericTypeDefinition == typeof(Nullable<>)) + { + // We are dealing with a generic type that is nullable + valueType = Nullable.GetUnderlyingType(valueType); + } - // If nothing is set, we can use the default value from the config (if we habe one) - if (defaultValueFromConfig != null) { - Value = defaultValueFromConfig; - return; - } - if (ValueType != typeof(string)) { - try { - Value = Activator.CreateInstance(ValueType); - } catch (Exception) { - Log.WarnFormat("Couldn't create instance of {0} for {1}, using default value.", ValueType.FullName, _attributes.Name); - Value = default(ValueType); - } - } else { - Value = default(ValueType); - } - } + return valueType; + } + } - /// - /// Convert a string to a value of type "valueType" - /// - /// Type to convert tp - /// string to convert from - /// - /// Value - private static object ConvertStringToValueType(Type valueType, string valueString, string separator) { - if (valueString == null) { - return null; - } - if (valueType == typeof(string)) { - return valueString; - } - if (string.IsNullOrEmpty(valueString)) { - return null; - } + /// + /// Write the value to the text writer + /// + /// TextWriter to write to + /// true if we do not want the comment + public void Write(TextWriter writer, bool onlyProperties) + { + object myValue = Value; + Type valueType = ValueType; + if (myValue == null) + { + if (_attributes.ExcludeIfNull) + { + return; + } - // The following makes the enum string values a bit less restrictive - if (valueType.IsEnum) - { - string searchingEnumString = valueString.Replace("_", string.Empty).ToLowerInvariant(); - foreach (var possibleValue in Enum.GetValues(valueType)) - { - var possibleString = possibleValue.ToString().Replace("_", string.Empty).ToLowerInvariant(); - if (possibleString.Equals(searchingEnumString)) - { - return possibleValue; - } - } - } + if (_attributes.DefaultValue != null) + { + myValue = _attributes.DefaultValue; + valueType = typeof(string); + } + else + { + myValue = _containingIniSection.GetDefault(_attributes.Name); + if (myValue != null) + { + valueType = myValue.GetType(); + } + } + } - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) { - string arraySeparator = separator; - object list = Activator.CreateInstance(valueType); - // Logic for List<> - string[] arrayValues = valueString.Split(new[] { arraySeparator }, StringSplitOptions.None); - if (arrayValues.Length == 0) { - return list; - } - MethodInfo addMethodInfo = valueType.GetMethod("Add"); + if (myValue == null) + { + if (_attributes.ExcludeIfNull) + { + return; + } + } - foreach (string arrayValue in arrayValues) { - if (!string.IsNullOrEmpty(arrayValue)) { - object newValue = null; - try { - newValue = ConvertStringToValueType(valueType.GetGenericArguments()[0], arrayValue, separator); - } catch (Exception ex) { - Log.Warn("Problem converting " + arrayValue + " to type " + valueType.FullName, ex); - } - if (newValue != null) { - addMethodInfo.Invoke(list, new[] { newValue }); - } - } - } - return list; - } - //LOG.Debug("No convertor for " + fieldType.ToString()); - if (valueType == typeof(object) && valueString.Length > 0) { - //LOG.Debug("Parsing: " + valueString); - string[] values = valueString.Split(':'); - //LOG.Debug("Type: " + values[0]); - //LOG.Debug("Value: " + values[1]); - Type fieldTypeForValue = Type.GetType(values[0], true); - //LOG.Debug("Type after GetType: " + fieldTypeForValue); - return ConvertStringToValueType(fieldTypeForValue, values[1], separator); - } - TypeConverter converter = TypeDescriptor.GetConverter(valueType); - return converter.ConvertFromInvariantString(valueString); - } + if (!onlyProperties) + { + writer.WriteLine("; {0}", _attributes.Description); + } - /// - /// Override of ToString which calls the ConvertValueToString - /// - /// string representation of this - public override string ToString() { - return ConvertValueToString(ValueType, Value, _attributes.Separator); - } + if (myValue == null) + { + writer.WriteLine("{0}=", _attributes.Name); + return; + } - /// - /// Convert the supplied value to a string - /// - /// Type to convert - /// Value to convert - /// separator for lists - /// string representation of the value - private static string ConvertValueToString(Type valueType, object valueObject, string separator) { - if (valueObject == null) { - // If there is nothing, deliver nothing! - return string.Empty; - } + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // Handle dictionaries. + Type valueType1 = valueType.GetGenericArguments()[0]; + Type valueType2 = valueType.GetGenericArguments()[1]; + // Get the methods we need to deal with dictionaries. + var keys = valueType.GetProperty("Keys").GetValue(myValue, null); + var item = valueType.GetProperty("Item"); + var enumerator = keys.GetType().GetMethod("GetEnumerator").Invoke(keys, null); + var moveNext = enumerator.GetType().GetMethod("MoveNext"); + var current = enumerator.GetType().GetProperty("Current").GetGetMethod(); + // Get all the values. + while ((bool) moveNext.Invoke(enumerator, null)) + { + var key = current.Invoke(enumerator, null); + var valueObject = item.GetValue(myValue, new[] + { + key + }); + // Write to ini file! + writer.WriteLine("{0}.{1}={2}", _attributes.Name, ConvertValueToString(valueType1, key, _attributes.Separator), + ConvertValueToString(valueType2, valueObject, _attributes.Separator)); + } + } + else + { + writer.WriteLine("{0}={1}", _attributes.Name, ConvertValueToString(valueType, myValue, _attributes.Separator)); + } + } - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) { - StringBuilder stringBuilder = new StringBuilder(); - Type specificValueType = valueType.GetGenericArguments()[0]; - int listCount = (int)valueType.GetProperty("Count").GetValue(valueObject, null); - // Loop though generic list - for (int index = 0; index < listCount; index++) { - object item = valueType.GetMethod("get_Item").Invoke(valueObject, new object[] { index }); + /// + /// Set the value to the value in the ini file, or default + /// + /// + public void SetValueFromProperties(IDictionary properties) + { + string propertyName = _attributes.Name; + string propertyValue = null; + if (properties.ContainsKey(propertyName) && properties[propertyName] != null) + { + propertyValue = _containingIniSection.PreCheckValue(propertyName, properties[propertyName]); + } - // Now you have an instance of the item in the generic list - if (index < listCount - 1) { - stringBuilder.AppendFormat("{0}{1}", ConvertValueToString(specificValueType, item, separator), separator); - } else { - stringBuilder.AppendFormat("{0}", ConvertValueToString(specificValueType, item, separator)); - } - } - return stringBuilder.ToString(); - } - if (valueType == typeof(object)) { - // object to String, this is the hardest - // Format will be "FQTypename[,Assemblyname]:Value" + UseValueOrDefault(propertyValue); + } - // Get the type so we can call ourselves recursive - Type objectType = valueObject.GetType(); + /// + /// This method will set the ini value to the supplied value or use the default if non supplied + /// + /// + public void UseValueOrDefault(string propertyValue) + { + Type valueType = ValueType; + string propertyName = _attributes.Name; + string defaultValue = _attributes.DefaultValue; + bool defaultUsed = false; + object defaultValueFromConfig = _containingIniSection.GetDefault(propertyName); - // Get the value as string - string ourValue = ConvertValueToString(objectType, valueObject, separator); + if (string.IsNullOrEmpty(propertyValue)) + { + if (defaultValue != null && defaultValue.Trim().Length != 0) + { + propertyValue = defaultValue; + defaultUsed = true; + } + else if (defaultValueFromConfig != null) + { + Log.DebugFormat("Default for Property {0} implemented!", propertyName); + } + else + { + if (_attributes.ExcludeIfNull) + { + Value = null; + return; + } - // Get the valuetype as string - string valueTypeName = objectType.FullName; - // Find the assembly name and only append it if it's not already in the fqtypename (like System.Drawing) - string assemblyName = objectType.Assembly.FullName; - // correct assemblyName, this also has version information etc. - if (assemblyName.StartsWith("Green")) { - assemblyName = assemblyName.Substring(0, assemblyName.IndexOf(',')); - } - return $"{valueTypeName},{assemblyName}:{ourValue}"; - } - TypeConverter converter = TypeDescriptor.GetConverter(valueType); - return converter.ConvertToInvariantString(valueObject); - } - } + Log.DebugFormat("Property {0} has no value or default value!", propertyName); + } + } + + // Now set the value + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // Logic for Dictionary<,> + Type type1 = valueType.GetGenericArguments()[0]; + Type type2 = valueType.GetGenericArguments()[1]; + //LOG.Info(String.Format("Found Dictionary<{0},{1}>", type1.Name, type2.Name)); + object dictionary = Activator.CreateInstance(valueType); + MethodInfo addMethodInfo = valueType.GetMethod("Add"); + bool addedElements = false; + IDictionary properties = IniConfig.PropertiesForSection(_containingIniSection); + foreach (string key in properties.Keys) + { + if (key != null && key.StartsWith(propertyName + ".")) + { + // What "key" do we need to store it under? + string subPropertyName = key.Substring(propertyName.Length + 1); + string stringValue = properties[key]; + object newValue1 = null; + object newValue2 = null; + try + { + newValue1 = ConvertStringToValueType(type1, subPropertyName, _attributes.Separator); + } + catch (Exception ex) + { + Log.Warn(ex); + //LOG.Error("Problem converting " + subPropertyName + " to type " + type1.FullName, e); + } + + try + { + newValue2 = ConvertStringToValueType(type2, stringValue, _attributes.Separator); + } + catch (Exception ex) + { + Log.Warn(ex); + //LOG.Error("Problem converting " + stringValue + " to type " + type2.FullName, e); + } + + addMethodInfo.Invoke(dictionary, new[] + { + newValue1, newValue2 + }); + addedElements = true; + } + } + + // No need to return something that isn't filled! + if (addedElements) + { + Value = dictionary; + return; + } + + if (defaultValueFromConfig != null) + { + Value = defaultValueFromConfig; + return; + } + } + else if (!string.IsNullOrEmpty(propertyValue)) + { + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + // We are dealing with a generic type that is nullable + valueType = Nullable.GetUnderlyingType(valueType); + } + + object newValue; + try + { + newValue = ConvertStringToValueType(valueType, propertyValue, _attributes.Separator); + } + catch (Exception ex1) + { + newValue = null; + if (!defaultUsed) + { + try + { + Log.WarnFormat("Problem '{0}' while converting {1} to type {2} trying fallback...", ex1.Message, propertyValue, valueType.FullName); + newValue = ConvertStringToValueType(valueType, defaultValue, _attributes.Separator); + ContainingIniSection.IsDirty = true; + Log.InfoFormat("Used default value {0} for property {1}", defaultValue, propertyName); + } + catch (Exception ex2) + { + Log.Warn("Problem converting fallback value " + defaultValue + " to type " + valueType.FullName, ex2); + } + } + else + { + Log.Warn("Problem converting " + propertyValue + " to type " + valueType.FullName, ex1); + } + } + + Value = newValue; + return; + } + + // If nothing is set, we can use the default value from the config (if we habe one) + if (defaultValueFromConfig != null) + { + Value = defaultValueFromConfig; + return; + } + + if (ValueType != typeof(string)) + { + try + { + Value = Activator.CreateInstance(ValueType); + } + catch (Exception) + { + Log.WarnFormat("Couldn't create instance of {0} for {1}, using default value.", ValueType.FullName, _attributes.Name); + Value = default(ValueType); + } + } + else + { + Value = default(ValueType); + } + } + + /// + /// Convert a string to a value of type "valueType" + /// + /// Type to convert tp + /// string to convert from + /// + /// Value + private static object ConvertStringToValueType(Type valueType, string valueString, string separator) + { + if (valueString == null) + { + return null; + } + + if (valueType == typeof(string)) + { + return valueString; + } + + if (string.IsNullOrEmpty(valueString)) + { + return null; + } + + // The following makes the enum string values a bit less restrictive + if (valueType.IsEnum) + { + string searchingEnumString = valueString.Replace("_", string.Empty).ToLowerInvariant(); + foreach (var possibleValue in Enum.GetValues(valueType)) + { + var possibleString = possibleValue.ToString().Replace("_", string.Empty).ToLowerInvariant(); + if (possibleString.Equals(searchingEnumString)) + { + return possibleValue; + } + } + } + + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) + { + string arraySeparator = separator; + object list = Activator.CreateInstance(valueType); + // Logic for List<> + string[] arrayValues = valueString.Split(new[] + { + arraySeparator + }, StringSplitOptions.None); + if (arrayValues.Length == 0) + { + return list; + } + + MethodInfo addMethodInfo = valueType.GetMethod("Add"); + + foreach (string arrayValue in arrayValues) + { + if (!string.IsNullOrEmpty(arrayValue)) + { + object newValue = null; + try + { + newValue = ConvertStringToValueType(valueType.GetGenericArguments()[0], arrayValue, separator); + } + catch (Exception ex) + { + Log.Warn("Problem converting " + arrayValue + " to type " + valueType.FullName, ex); + } + + if (newValue != null) + { + addMethodInfo.Invoke(list, new[] + { + newValue + }); + } + } + } + + return list; + } + + //LOG.Debug("No convertor for " + fieldType.ToString()); + if (valueType == typeof(object) && valueString.Length > 0) + { + //LOG.Debug("Parsing: " + valueString); + string[] values = valueString.Split(':'); + //LOG.Debug("Type: " + values[0]); + //LOG.Debug("Value: " + values[1]); + Type fieldTypeForValue = Type.GetType(values[0], true); + //LOG.Debug("Type after GetType: " + fieldTypeForValue); + return ConvertStringToValueType(fieldTypeForValue, values[1], separator); + } + + TypeConverter converter = TypeDescriptor.GetConverter(valueType); + return converter.ConvertFromInvariantString(valueString); + } + + /// + /// Override of ToString which calls the ConvertValueToString + /// + /// string representation of this + public override string ToString() + { + return ConvertValueToString(ValueType, Value, _attributes.Separator); + } + + /// + /// Convert the supplied value to a string + /// + /// Type to convert + /// Value to convert + /// separator for lists + /// string representation of the value + private static string ConvertValueToString(Type valueType, object valueObject, string separator) + { + if (valueObject == null) + { + // If there is nothing, deliver nothing! + return string.Empty; + } + + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) + { + StringBuilder stringBuilder = new StringBuilder(); + Type specificValueType = valueType.GetGenericArguments()[0]; + int listCount = (int) valueType.GetProperty("Count").GetValue(valueObject, null); + // Loop though generic list + for (int index = 0; index < listCount; index++) + { + object item = valueType.GetMethod("get_Item").Invoke(valueObject, new object[] + { + index + }); + + // Now you have an instance of the item in the generic list + if (index < listCount - 1) + { + stringBuilder.AppendFormat("{0}{1}", ConvertValueToString(specificValueType, item, separator), separator); + } + else + { + stringBuilder.AppendFormat("{0}", ConvertValueToString(specificValueType, item, separator)); + } + } + + return stringBuilder.ToString(); + } + + if (valueType == typeof(object)) + { + // object to String, this is the hardest + // Format will be "FQTypename[,Assemblyname]:Value" + + // Get the type so we can call ourselves recursive + Type objectType = valueObject.GetType(); + + // Get the value as string + string ourValue = ConvertValueToString(objectType, valueObject, separator); + + // Get the valuetype as string + string valueTypeName = objectType.FullName; + // Find the assembly name and only append it if it's not already in the fqtypename (like System.Drawing) + string assemblyName = objectType.Assembly.FullName; + // correct assemblyName, this also has version information etc. + if (assemblyName.StartsWith("Green")) + { + assemblyName = assemblyName.Substring(0, assemblyName.IndexOf(',')); + } + + return $"{valueTypeName},{assemblyName}:{ourValue}"; + } + + TypeConverter converter = TypeDescriptor.GetConverter(valueType); + return converter.ConvertToInvariantString(valueObject); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/CaptureMode.cs b/src/GreenshotPlugin/Interfaces/CaptureMode.cs index 8c9c9e268..161726a2f 100644 --- a/src/GreenshotPlugin/Interfaces/CaptureMode.cs +++ b/src/GreenshotPlugin/Interfaces/CaptureMode.cs @@ -36,6 +36,7 @@ namespace GreenshotPlugin.Interfaces File, IE, Import, + Text // Video }; diff --git a/src/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs b/src/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs index db5319e2c..60206099a 100644 --- a/src/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs +++ b/src/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs @@ -25,78 +25,78 @@ using System.Windows.Forms; namespace GreenshotPlugin.Interfaces.Drawing.Adorners { - public interface IAdorner - { - /// - /// Returns if this adorner is active - /// - bool IsActive { get; } + public interface IAdorner + { + /// + /// Returns if this adorner is active + /// + bool IsActive { get; } - /// - /// These are the bounds of the adorner - /// - Rectangle Bounds { get; } + /// + /// These are the bounds of the adorner + /// + Rectangle Bounds { get; } - /// - /// The current edit status, this is needed to locate the adorner to send events to - /// - EditStatus EditStatus { get; } + /// + /// The current edit status, this is needed to locate the adorner to send events to + /// + EditStatus EditStatus { get; } - /// - /// The owner of this adorner - /// - IDrawableContainer Owner { get; } + /// + /// The owner of this adorner + /// + IDrawableContainer Owner { get; } - /// - /// Is the current point "over" the Adorner? - /// If this is the case, the - /// - /// Point to test - /// true if so - bool HitTest(Point point); + /// + /// Is the current point "over" the Adorner? + /// If this is the case, the + /// + /// Point to test + /// true if so + bool HitTest(Point point); - /// - /// Handle the MouseDown event - /// - /// - /// MouseEventArgs - void MouseDown(object sender, MouseEventArgs mouseEventArgs); + /// + /// Handle the MouseDown event + /// + /// + /// MouseEventArgs + void MouseDown(object sender, MouseEventArgs mouseEventArgs); - /// - /// Handle the MouseUp event - /// - /// - /// MouseEventArgs - void MouseUp(object sender, MouseEventArgs mouseEventArgs); + /// + /// Handle the MouseUp event + /// + /// + /// MouseEventArgs + void MouseUp(object sender, MouseEventArgs mouseEventArgs); - /// - /// Handle the MouseMove event - /// - /// - /// MouseEventArgs - void MouseMove(object sender, MouseEventArgs mouseEventArgs); + /// + /// Handle the MouseMove event + /// + /// + /// MouseEventArgs + void MouseMove(object sender, MouseEventArgs mouseEventArgs); - /// - /// Gets the cursor that should be displayed for this behavior. - /// - Cursor Cursor { get; } + /// + /// Gets the cursor that should be displayed for this behavior. + /// + Cursor Cursor { get; } - /// - /// Draw the adorner - /// - /// PaintEventArgs - void Paint(PaintEventArgs paintEventArgs); + /// + /// Draw the adorner + /// + /// PaintEventArgs + void Paint(PaintEventArgs paintEventArgs); - /// - /// Called if the owner is transformed - /// - /// Matrix - void Transform(Matrix matrix); + /// + /// Called if the owner is transformed + /// + /// Matrix + void Transform(Matrix matrix); - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// - void AdjustToDpi(uint dpi); - } -} + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// + void AdjustToDpi(uint dpi); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Drawing/Container.cs b/src/GreenshotPlugin/Interfaces/Drawing/Container.cs index 7b999565a..0180886bc 100644 --- a/src/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ b/src/GreenshotPlugin/Interfaces/Drawing/Container.cs @@ -29,187 +29,121 @@ using GreenshotPlugin.Interfaces.Drawing.Adorners; namespace GreenshotPlugin.Interfaces.Drawing { - public enum RenderMode { EDIT, EXPORT }; - public enum EditStatus { UNDRAWN, DRAWING, MOVING, RESIZING, IDLE }; + public enum RenderMode + { + EDIT, + EXPORT + }; - public interface IDrawableContainer : INotifyPropertyChanged, IDisposable - { - ISurface Parent - { - get; - set; - } - bool Selected - { - get; - set; - } + public enum EditStatus + { + UNDRAWN, + DRAWING, + MOVING, + RESIZING, + IDLE + }; - int Left - { - get; - set; - } + public interface IDrawableContainer : INotifyPropertyChanged, IDisposable + { + ISurface Parent { get; set; } + bool Selected { get; set; } - int Top - { - get; - set; - } + int Left { get; set; } - int Width - { - get; - set; - } + int Top { get; set; } - int Height - { - get; - set; - } + int Width { get; set; } - Point Location - { - get; - } + int Height { get; set; } - Size Size - { - get; - } + Point Location { get; } - Rectangle Bounds - { - get; - } + Size Size { get; } - Rectangle DrawingBounds - { - get; - } + Rectangle Bounds { get; } - void ApplyBounds(RectangleF newBounds); + Rectangle DrawingBounds { get; } - bool hasFilters - { - get; - } + void ApplyBounds(RectangleF newBounds); - EditStatus Status - { - get; - set; - } - void Invalidate(); - bool ClickableAt(int x, int y); - void MoveBy(int x, int y); - void Transform(Matrix matrix); - bool HandleMouseDown(int x, int y); - void HandleMouseUp(int x, int y); - bool HandleMouseMove(int x, int y); - bool InitContent(); - void MakeBoundsChangeUndoable(bool allowMerge); - EditStatus DefaultEditMode - { - get; - } + bool hasFilters { get; } - /// - /// Available adorners for the DrawableContainer - /// - IList Adorners { get; } + EditStatus Status { get; set; } + void Invalidate(); + bool ClickableAt(int x, int y); + void MoveBy(int x, int y); + void Transform(Matrix matrix); + bool HandleMouseDown(int x, int y); + void HandleMouseUp(int x, int y); + bool HandleMouseMove(int x, int y); + bool InitContent(); + void MakeBoundsChangeUndoable(bool allowMerge); + EditStatus DefaultEditMode { get; } - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// uint - void AdjustToDpi(uint dpi); - } + /// + /// Available adorners for the DrawableContainer + /// + IList Adorners { get; } - public interface IDrawableContainerList : IList, IDisposable - { - Guid ParentID - { - get; - } + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// uint + void AdjustToDpi(uint dpi); + } - bool Selected - { - get; - set; - } + public interface IDrawableContainerList : IList, IDisposable + { + Guid ParentID { get; } - ISurface Parent - { - get; - set; - } - EditStatus Status - { - get; - set; - } - Rectangle DrawingBounds - { - get; - } - void MakeBoundsChangeUndoable(bool allowMerge); - void Transform(Matrix matrix); - void MoveBy(int dx, int dy); - bool ClickableAt(int x, int y); - IDrawableContainer ClickableElementAt(int x, int y); - void OnDoubleClick(); - bool HasIntersectingFilters(Rectangle clipRectangle); - bool IntersectsWith(Rectangle clipRectangle); - void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle); - void Invalidate(); - void PullElementsToTop(IDrawableContainerList elements); - bool CanPushDown(IDrawableContainerList elements); - void PullElementsUp(IDrawableContainerList elements); - bool CanPullUp(IDrawableContainerList elements); - void PushElementsDown(IDrawableContainerList elements); - void PushElementsToBottom(IDrawableContainerList elements); - void ShowContextMenu(MouseEventArgs e, ISurface surface); - void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e); - void AdjustToDpi(uint dpi); - } + bool Selected { get; set; } - public interface ITextContainer : IDrawableContainer - { - string Text - { - get; - set; - } - void FitToText(); - } + ISurface Parent { get; set; } + EditStatus Status { get; set; } + Rectangle DrawingBounds { get; } + void MakeBoundsChangeUndoable(bool allowMerge); + void Transform(Matrix matrix); + void MoveBy(int dx, int dy); + bool ClickableAt(int x, int y); + IDrawableContainer ClickableElementAt(int x, int y); + void OnDoubleClick(); + bool HasIntersectingFilters(Rectangle clipRectangle); + bool IntersectsWith(Rectangle clipRectangle); + void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle); + void Invalidate(); + void PullElementsToTop(IDrawableContainerList elements); + bool CanPushDown(IDrawableContainerList elements); + void PullElementsUp(IDrawableContainerList elements); + bool CanPullUp(IDrawableContainerList elements); + void PushElementsDown(IDrawableContainerList elements); + void PushElementsToBottom(IDrawableContainerList elements); + void ShowContextMenu(MouseEventArgs e, ISurface surface); + void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e); + void AdjustToDpi(uint dpi); + } - public interface IImageContainer : IDrawableContainer - { - Image Image - { - get; - set; - } - void Load(string filename); - } - public interface ICursorContainer : IDrawableContainer - { - Cursor Cursor - { - get; - set; - } - void Load(string filename); - } - public interface IIconContainer : IDrawableContainer - { - Icon Icon - { - get; - set; - } - void Load(string filename); - } -} + public interface ITextContainer : IDrawableContainer + { + string Text { get; set; } + void FitToText(); + } + + public interface IImageContainer : IDrawableContainer + { + Image Image { get; set; } + void Load(string filename); + } + + public interface ICursorContainer : IDrawableContainer + { + Cursor Cursor { get; set; } + void Load(string filename); + } + + public interface IIconContainer : IDrawableContainer + { + Icon Icon { get; set; } + void Load(string filename); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Drawing/IField.cs b/src/GreenshotPlugin/Interfaces/Drawing/IField.cs index 97c13c2d9..f241e6a53 100644 --- a/src/GreenshotPlugin/Interfaces/Drawing/IField.cs +++ b/src/GreenshotPlugin/Interfaces/Drawing/IField.cs @@ -24,62 +24,42 @@ using System.ComponentModel; namespace GreenshotPlugin.Interfaces.Drawing { - [Flags] - public enum FieldFlag - { - NONE = 0, - CONFIRMABLE = 1, - COUNTER = 2 - } - public interface IFieldType - { - string Name - { - get; - set; - } - } + [Flags] + public enum FieldFlag + { + NONE = 0, + CONFIRMABLE = 1, + COUNTER = 2 + } - public interface IField : INotifyPropertyChanged - { - object Value - { - get; - set; - } - IFieldType FieldType - { - get; - set; - } - string Scope - { - get; - set; - } - bool HasValue - { - get; - } - } - /// - /// EventHandler to be used when a field value changes - /// - public delegate void FieldChangedEventHandler(object sender, FieldChangedEventArgs e); + public interface IFieldType + { + string Name { get; set; } + } - /// - /// EventArgs to be used with FieldChangedEventHandler - /// - public class FieldChangedEventArgs : EventArgs - { - public IField Field - { - get; - private set; - } - public FieldChangedEventArgs(IField field) - { - Field = field; - } - } -} + public interface IField : INotifyPropertyChanged + { + object Value { get; set; } + IFieldType FieldType { get; set; } + string Scope { get; set; } + bool HasValue { get; } + } + + /// + /// EventHandler to be used when a field value changes + /// + public delegate void FieldChangedEventHandler(object sender, FieldChangedEventArgs e); + + /// + /// EventArgs to be used with FieldChangedEventHandler + /// + public class FieldChangedEventArgs : EventArgs + { + public IField Field { get; private set; } + + public FieldChangedEventArgs(IField field) + { + Field = field; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs b/src/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs index df0f779d5..9cc046b82 100644 --- a/src/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs +++ b/src/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs @@ -23,17 +23,17 @@ using System.Collections.Generic; namespace GreenshotPlugin.Interfaces.Drawing { - /// - /// Any element holding Fields must provide access to it. - /// AbstractFieldHolder is the basic implementation. - /// If you need the fieldHolder to have child fieldHolders, - /// you should consider using IFieldHolderWithChildren. - /// - public interface IFieldHolder - { - event FieldChangedEventHandler FieldChanged; - IList GetFields(); - IField GetField(IFieldType fieldType); - bool HasField(IFieldType fieldType); - } -} + /// + /// Any element holding Fields must provide access to it. + /// AbstractFieldHolder is the basic implementation. + /// If you need the fieldHolder to have child fieldHolders, + /// you should consider using IFieldHolderWithChildren. + /// + public interface IFieldHolder + { + event FieldChangedEventHandler FieldChanged; + IList GetFields(); + IField GetField(IFieldType fieldType); + bool HasField(IFieldType fieldType); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Drawing/IMemento.cs b/src/GreenshotPlugin/Interfaces/Drawing/IMemento.cs index bb64237fe..cc5a357f3 100644 --- a/src/GreenshotPlugin/Interfaces/Drawing/IMemento.cs +++ b/src/GreenshotPlugin/Interfaces/Drawing/IMemento.cs @@ -21,24 +21,26 @@ using System; -namespace GreenshotPlugin.Interfaces.Drawing { - /// - /// Description of IMemento. - /// - public interface IMemento : IDisposable { - /// - /// Restores target to the state memorized by this memento. - /// - /// - /// A memento of the state before restoring - /// - IMemento Restore(); - - /// - /// Try to merge the current memento with another, preventing loads of items on the stack - /// - /// The memento to try to merge with - /// - bool Merge(IMemento other); - } -} +namespace GreenshotPlugin.Interfaces.Drawing +{ + /// + /// Description of IMemento. + /// + public interface IMemento : IDisposable + { + /// + /// Restores target to the state memorized by this memento. + /// + /// + /// A memento of the state before restoring + /// + IMemento Restore(); + + /// + /// Try to merge the current memento with another, preventing loads of items on the stack + /// + /// The memento to try to merge with + /// + bool Merge(IMemento other); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs b/src/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs index 808951234..912f2987d 100644 --- a/src/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs +++ b/src/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs @@ -21,29 +21,26 @@ using System.Drawing; -namespace GreenshotPlugin.Interfaces.Forms { - /// - /// The IImageEditor is the Interface that the Greenshot ImageEditor has to implement - /// - public interface IImageEditor { +namespace GreenshotPlugin.Interfaces.Forms +{ + /// + /// The IImageEditor is the Interface that the Greenshot ImageEditor has to implement + /// + public interface IImageEditor + { /// - /// Get the current Image from the Editor for Exporting (save/upload etc) - /// This is actually a wrapper which calls Surface.GetImageForExport(). - /// Don't forget to call image.Dispose() when finished!!! - /// - /// Bitmap - Image GetImageForExport(); + /// Get the current Image from the Editor for Exporting (save/upload etc) + /// This is actually a wrapper which calls Surface.GetImageForExport(). + /// Don't forget to call image.Dispose() when finished!!! + /// + /// Bitmap + Image GetImageForExport(); /// - /// Make the ICaptureDetails from the current Surface in the EditorForm available. - /// - ICaptureDetails CaptureDetails { - get; - } + /// Make the ICaptureDetails from the current Surface in the EditorForm available. + /// + ICaptureDetails CaptureDetails { get; } - ISurface Surface { - get; - set; - } - } -} + ISurface Surface { get; set; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/ICapture.cs b/src/GreenshotPlugin/Interfaces/ICapture.cs index 24f67a9f0..425d936de 100644 --- a/src/GreenshotPlugin/Interfaces/ICapture.cs +++ b/src/GreenshotPlugin/Interfaces/ICapture.cs @@ -27,22 +27,17 @@ namespace GreenshotPlugin.Interfaces /// /// The interface to the Capture object, so Plugins can use it. /// - public interface ICapture : IDisposable { + public interface ICapture : IDisposable + { /// /// The Capture Details /// - ICaptureDetails CaptureDetails { - get; - set; - } + ICaptureDetails CaptureDetails { get; set; } /// /// The captured Image /// - Image Image { - get; - set; - } + Image Image { get; set; } /// /// Null the image @@ -52,42 +47,27 @@ namespace GreenshotPlugin.Interfaces /// /// Bounds on the screen from which the capture comes /// - Rectangle ScreenBounds { - get; - set; - } + Rectangle ScreenBounds { get; set; } /// /// The cursor /// - Icon Cursor { - get; - set; - } + Icon Cursor { get; set; } /// /// Boolean to specify if the cursor is available /// - bool CursorVisible { - get; - set; - } + bool CursorVisible { get; set; } /// /// Location of the cursor /// - Point CursorLocation { - get; - set; - } + Point CursorLocation { get; set; } /// /// Location of the capture /// - Point Location { - get; - set; - } + Point Location { get; set; } /// /// Crops the capture to the specified rectangle (with Bitmap coordinates!) diff --git a/src/GreenshotPlugin/Interfaces/ICaptureDetails.cs b/src/GreenshotPlugin/Interfaces/ICaptureDetails.cs index c475283da..5001f7bd0 100644 --- a/src/GreenshotPlugin/Interfaces/ICaptureDetails.cs +++ b/src/GreenshotPlugin/Interfaces/ICaptureDetails.cs @@ -23,81 +23,59 @@ using System; using System.Collections.Generic; using GreenshotPlugin.Interfaces.Ocr; -namespace GreenshotPlugin.Interfaces { +namespace GreenshotPlugin.Interfaces +{ /// - /// Details for the capture, like the window title and date/time etc. - /// - public interface ICaptureDetails { + /// Details for the capture, like the window title and date/time etc. + /// + public interface ICaptureDetails + { + /// + /// If the capture comes from a file, this contains the filename + /// + string Filename { get; set; } - /// - /// If the capture comes from a file, this contains the filename - /// - string Filename { - get; - set; - } + /// + /// The title of the capture + /// + string Title { get; set; } - /// - /// The title of the capture - /// - string Title { - get; - set; - } + /// + /// When was the capture taken (or loaded) + /// + DateTime DateTime { get; set; } - /// - /// When was the capture taken (or loaded) - /// - DateTime DateTime { - get; - set; - } + /// + /// Destinations to where this capture goes or went + /// + List CaptureDestinations { get; set; } - /// - /// Destinations to where this capture goes or went - /// - List CaptureDestinations { - get; - set; - } + /// + /// The meta data of the capture + /// + Dictionary MetaData { get; } - /// - /// The meta data of the capture - /// - Dictionary MetaData { - get; - } + /// + /// Helper method to prevent complex code which needs to check every key + /// + /// The key for the meta-data + /// The value for the meta-data + void AddMetaData(string key, string value); - /// - /// Helper method to prevent complex code which needs to check every key - /// - /// The key for the meta-data - /// The value for the meta-data - void AddMetaData(string key, string value); + void ClearDestinations(); + void RemoveDestination(IDestination captureDestination); + void AddDestination(IDestination captureDestination); + bool HasDestination(string designation); - void ClearDestinations(); - void RemoveDestination(IDestination captureDestination); - void AddDestination(IDestination captureDestination); - bool HasDestination(string designation); + CaptureMode CaptureMode { get; set; } - CaptureMode CaptureMode { - get; - set; - } + float DpiX { get; set; } - float DpiX { - get; - set; - } - - float DpiY { - get; - set; - } + float DpiY { get; set; } /// /// Store the OCR information for this capture /// OcrInformation OcrInformation { get; set; } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/IDestination.cs b/src/GreenshotPlugin/Interfaces/IDestination.cs index 8bfb72ac3..d57244c69 100644 --- a/src/GreenshotPlugin/Interfaces/IDestination.cs +++ b/src/GreenshotPlugin/Interfaces/IDestination.cs @@ -24,120 +24,108 @@ using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; -namespace GreenshotPlugin.Interfaces { - public class ExportInformation { - public ExportInformation(string destinationDesignation, string destinationDescription) { - DestinationDesignation = destinationDesignation; - DestinationDescription = destinationDescription; - } - public ExportInformation(string destinationDesignation, string destinationDescription, bool exportMade): this(destinationDesignation, destinationDescription) { - ExportMade = exportMade; - } +namespace GreenshotPlugin.Interfaces +{ + public class ExportInformation + { + public ExportInformation(string destinationDesignation, string destinationDescription) + { + DestinationDesignation = destinationDesignation; + DestinationDescription = destinationDescription; + } - public string DestinationDesignation { get; } + public ExportInformation(string destinationDesignation, string destinationDescription, bool exportMade) : this(destinationDesignation, destinationDescription) + { + ExportMade = exportMade; + } - public string DestinationDescription { get; set; } + public string DestinationDesignation { get; } - /// - /// Set to true to specify if the export worked. - /// - public bool ExportMade { get; set; } - - public string Uri { get; set; } - - public string ErrorMessage { get; set; } - - public string Filepath { get; set; } - } - - /// - /// Description of IDestination. - /// - public interface IDestination : IDisposable, IComparable { - /// - /// Simple "designation" like "File", "Editor" etc, used to store the configuration - /// - string Designation { - get; - } - - /// - /// Description which will be shown in the settings form, destination picker etc - /// - string Description { - get; - } - - /// - /// Priority, used for sorting - /// - int Priority { - get; - } - - /// - /// Gets an icon for the destination - /// - Image DisplayIcon { - get; - } - - /// - /// Returns if the destination is active - /// - bool IsActive { - get; - } - - /// - /// Return a menu item - /// - /// Resolve the dynamic destinations too? - /// The menu for which the item is created - /// Handler which is called when clicked - /// ToolStripMenuItem - ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler); - - /// - /// Gets the ShortcutKeys for the Editor - /// - Keys EditorShortcutKeys { - get; - } + public string DestinationDescription { get; set; } /// - /// Gets the dynamic destinations - /// - IEnumerable DynamicDestinations(); + /// Set to true to specify if the export worked. + /// + public bool ExportMade { get; set; } - /// - /// Returns true if this destination can be dynamic - /// - bool IsDynamic { - get; - } + public string Uri { get; set; } - /// - /// Returns if the destination is active - /// - bool UseDynamicsOnly { - get; - } + public string ErrorMessage { get; set; } - /// - /// Returns true if this destination returns a link - /// - bool IsLinkable { - get; - } + public string Filepath { get; set; } + } - /// - /// If a capture is made, and the destination is enabled, this method is called. - /// - /// true if the user selected this destination from a GUI, false if it was called as part of a process - /// - /// - /// DestinationExportInformation with information, like if the destination has "exported" the capture - ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); - } -} + /// + /// Description of IDestination. + /// + public interface IDestination : IDisposable, IComparable + { + /// + /// Simple "designation" like "File", "Editor" etc, used to store the configuration + /// + string Designation { get; } + + /// + /// Description which will be shown in the settings form, destination picker etc + /// + string Description { get; } + + /// + /// Priority, used for sorting + /// + int Priority { get; } + + /// + /// Gets an icon for the destination + /// + Image DisplayIcon { get; } + + /// + /// Returns if the destination is active + /// + bool IsActive { get; } + + /// + /// Return a menu item + /// + /// Resolve the dynamic destinations too? + /// The menu for which the item is created + /// Handler which is called when clicked + /// ToolStripMenuItem + ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler); + + /// + /// Gets the ShortcutKeys for the Editor + /// + Keys EditorShortcutKeys { get; } + + /// + /// Gets the dynamic destinations + /// + IEnumerable DynamicDestinations(); + + /// + /// Returns true if this destination can be dynamic + /// + bool IsDynamic { get; } + + /// + /// Returns if the destination is active + /// + bool UseDynamicsOnly { get; } + + /// + /// Returns true if this destination returns a link + /// + bool IsLinkable { get; } + + /// + /// If a capture is made, and the destination is enabled, this method is called. + /// + /// true if the user selected this destination from a GUI, false if it was called as part of a process + /// + /// + /// DestinationExportInformation with information, like if the destination has "exported" the capture + ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/IProcessor.cs b/src/GreenshotPlugin/Interfaces/IProcessor.cs index d5f4c0ba8..1e8d8a9eb 100644 --- a/src/GreenshotPlugin/Interfaces/IProcessor.cs +++ b/src/GreenshotPlugin/Interfaces/IProcessor.cs @@ -21,45 +21,39 @@ using System; -namespace GreenshotPlugin.Interfaces { - /// - /// Description of IProcessor. - /// - public interface IProcessor : IDisposable, IComparable { - /// - /// Simple "designation" like "FixTitle" - /// - string Designation { - get; - } +namespace GreenshotPlugin.Interfaces +{ + /// + /// Description of IProcessor. + /// + public interface IProcessor : IDisposable, IComparable + { + /// + /// Simple "designation" like "FixTitle" + /// + string Designation { get; } - /// - /// Description which will be shown in the settings form, destination picker etc - /// - string Description { - get; - } + /// + /// Description which will be shown in the settings form, destination picker etc + /// + string Description { get; } - /// - /// Priority, used for sorting - /// - int Priority { - get; - } + /// + /// Priority, used for sorting + /// + int Priority { get; } - /// - /// Returns if the destination is active - /// - bool isActive { - get; - } + /// + /// Returns if the destination is active + /// + bool isActive { get; } - /// - /// If a capture is made, and the destination is enabled, this method is called. - /// - /// - /// - /// true if the processor has "processed" the capture - bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); - } -} + /// + /// If a capture is made, and the destination is enabled, this method is called. + /// + /// + /// + /// true if the processor has "processed" the capture + bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/IServiceLocator.cs b/src/GreenshotPlugin/Interfaces/IServiceLocator.cs index 1ef9df723..10de96ff8 100644 --- a/src/GreenshotPlugin/Interfaces/IServiceLocator.cs +++ b/src/GreenshotPlugin/Interfaces/IServiceLocator.cs @@ -11,4 +11,4 @@ namespace GreenshotPlugin.Interfaces void AddService(IEnumerable services); } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/ISurface.cs b/src/GreenshotPlugin/Interfaces/ISurface.cs index d6928b87e..51815f580 100644 --- a/src/GreenshotPlugin/Interfaces/ISurface.cs +++ b/src/GreenshotPlugin/Interfaces/ISurface.cs @@ -47,16 +47,9 @@ namespace GreenshotPlugin.Interfaces /// /// Unique ID of the Surface /// - Guid ID - { - get; - set; - } + Guid ID { get; set; } - IDrawableContainerList Elements - { - get; - } + IDrawableContainerList Elements { get; } /// /// Get/Set the image to the Surface @@ -67,11 +60,7 @@ namespace GreenshotPlugin.Interfaces /// The setter will clone the passed bitmap and dispose it when the Surface is disposed /// This means that the supplied image needs to be disposed by the calling code (if needed!) /// - Image Image - { - get; - set; - } + Image Image { get; set; } /// /// Get the current Image from the Editor for Exporting (save/upload etc) @@ -95,7 +84,8 @@ namespace GreenshotPlugin.Interfaces /// size of border (0 for none) /// Color of string /// Color of background (e.g. Color.Transparent) - ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor); + ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, + Color fillColor); IImageContainer AddImageContainer(Image image, int x, int y); ICursorContainer AddCursorContainer(Cursor cursor, int x, int y); @@ -106,10 +96,7 @@ namespace GreenshotPlugin.Interfaces long SaveElementsToStream(Stream stream); void LoadElementsFromStream(Stream stream); - bool HasSelectedElements - { - get; - } + bool HasSelectedElements { get; } void RemoveSelectedElements(); void CutSelectedElements(); void CopySelectedElements(); @@ -124,6 +111,7 @@ namespace GreenshotPlugin.Interfaces /// IDrawableContainerList /// Should it be placed on the undo stack? void AddElements(IDrawableContainerList elements, bool makeUndoable = true); + void RemoveElements(IDrawableContainerList elements, bool makeUndoable = true); void SelectElements(IDrawableContainerList elements); @@ -142,34 +130,27 @@ namespace GreenshotPlugin.Interfaces /// false to skip invalidation /// false to skip event generation void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true); + /// /// Is the supplied container "on" the surface? /// /// /// This returns false if the container is deleted but still in the undo stack bool IsOnSurface(IDrawableContainer container); + void Invalidate(); + /// /// Invalidates the specified region of the Surface. /// Takes care of the Surface zoom level, accepts rectangle in the coordinate space of the Image. /// /// Bounding rectangle for updated elements, in the coordinate space of the Image. void InvalidateElements(Rectangle rectangleToInvalidate); - bool Modified - { - get; - set; - } - string LastSaveFullPath - { - get; - set; - } - string UploadUrl - { - get; - set; - } + + bool Modified { get; set; } + string LastSaveFullPath { get; set; } + string UploadUrl { get; set; } + /// /// Remove an element of the elements list /// @@ -182,36 +163,33 @@ namespace GreenshotPlugin.Interfaces void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message); void ApplyBitmapEffect(IEffect effect); void RemoveCursor(); - bool HasCursor - { - get; - } + bool HasCursor { get; } - ICaptureDetails CaptureDetails - { - get; - set; - } + ICaptureDetails CaptureDetails { get; set; } /// /// Zoom value applied to the surface. /// Fraction ZoomFactor { get; set; } + /// /// Translate a point from image coorditate space to surface coordinate space. /// /// A point in the coordinate space of the image. Point ToSurfaceCoordinates(Point point); + /// /// Translate a rectangle from image coorditate space to surface coordinate space. /// /// A rectangle in the coordinate space of the image. Rectangle ToSurfaceCoordinates(Rectangle rc); + /// /// Translate a point from surface coorditate space to image coordinate space. /// /// A point in the coordinate space of the surface. Point ToImageCoordinates(Point point); + /// /// Translate a rectangle from surface coorditate space to image coordinate space. /// @@ -220,4 +198,4 @@ namespace GreenshotPlugin.Interfaces void MakeUndoable(IMemento memento, bool allowMerge); } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs b/src/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs index 4a9fd657e..a70c661c0 100644 --- a/src/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs +++ b/src/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs @@ -36,11 +36,11 @@ namespace GreenshotPlugin.Interfaces.Ocr /// OcrInformation Task DoOcrAsync(Image image); - /// + /// /// Start the actual OCR /// /// ISurface /// OcrInformation Task DoOcrAsync(ISurface surface); } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Ocr/Line.cs b/src/GreenshotPlugin/Interfaces/Ocr/Line.cs index c4f1dccb7..b00e5a957 100644 --- a/src/GreenshotPlugin/Interfaces/Ocr/Line.cs +++ b/src/GreenshotPlugin/Interfaces/Ocr/Line.cs @@ -70,7 +70,7 @@ namespace GreenshotPlugin.Interfaces.Ocr foreach (var word in Words) { var location = word.Bounds; - location.Offset(x,y); + location.Offset(x, y); word.Bounds = location; } diff --git a/src/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs b/src/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs index cd20eab00..f1dd829ff 100644 --- a/src/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs +++ b/src/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs @@ -1,52 +1,53 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace GreenshotPlugin.Interfaces.Ocr -{ - /// - /// Contains all the information on the OCR result - /// - public class OcrInformation - { +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace GreenshotPlugin.Interfaces.Ocr +{ + /// + /// Contains all the information on the OCR result + /// + public class OcrInformation + { /// /// Check if there is any content - /// - public bool HasContent => Lines.Any(); - - /// - /// The complete text - /// - public string Text - { - get - { - // Build the text from the lines, otherwise it's just everything concatenated together - var text = new StringBuilder(); - foreach (var line in Lines) - { - text.AppendLine(line.Text); - } - return text.ToString(); - } - } - - /// - /// The lines of test which the OCR engine found - /// - public IList Lines { get; } = new List(); - - /// - /// Change the offset of the - /// - /// int - /// int - public void Offset(int x, int y) - { - foreach (var line in Lines) - { - line.Offset(x,y); - } - } - } + /// + public bool HasContent => Lines.Any(); + + /// + /// The complete text + /// + public string Text + { + get + { + // Build the text from the lines, otherwise it's just everything concatenated together + var text = new StringBuilder(); + foreach (var line in Lines) + { + text.AppendLine(line.Text); + } + + return text.ToString(); + } + } + + /// + /// The lines of test which the OCR engine found + /// + public IList Lines { get; } = new List(); + + /// + /// Change the offset of the + /// + /// int + /// int + public void Offset(int x, int y) + { + foreach (var line in Lines) + { + line.Offset(x, y); + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs b/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs index b502a5ba2..fc362436d 100644 --- a/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs +++ b/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs @@ -6,7 +6,8 @@ namespace GreenshotPlugin.Interfaces.Plugin /// This interface is the GreenshotPluginHost, that which "Hosts" the plugin. /// For Greenshot this is implemented in the PluginHelper /// - public interface IGreenshotHost { + public interface IGreenshotHost + { /// /// Create a Thumbnail /// diff --git a/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs b/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs index 697a52a56..b7863e231 100644 --- a/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs +++ b/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs @@ -5,7 +5,8 @@ namespace GreenshotPlugin.Interfaces.Plugin /// /// This defines the plugin /// - public interface IGreenshotPlugin : IDisposable { + public interface IGreenshotPlugin : IDisposable + { /// /// Is called after the plugin is instantiated, the Plugin should keep a copy of the host and pluginAttribute. /// diff --git a/src/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs b/src/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs index c44d7f120..02f0ee14b 100644 --- a/src/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs +++ b/src/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs @@ -21,31 +21,30 @@ using System; -namespace GreenshotPlugin.Interfaces.Plugin { - [Serializable] - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] - public sealed class PluginAttribute : Attribute, IComparable { - public string Name { - get; - set; - } +namespace GreenshotPlugin.Interfaces.Plugin +{ + [Serializable] + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public sealed class PluginAttribute : Attribute, IComparable + { + public string Name { get; set; } - public bool Configurable { - get; - private set; - } + public bool Configurable { get; private set; } - public PluginAttribute(string name, bool configurable) + public PluginAttribute(string name, bool configurable) { Name = name; - Configurable = configurable; - } - - public int CompareTo(object obj) { - if (obj is PluginAttribute other) { - return string.Compare(Name, other.Name, StringComparison.Ordinal); - } - throw new ArgumentException("object is not a PluginAttribute"); - } - } + Configurable = configurable; + } + + public int CompareTo(object obj) + { + if (obj is PluginAttribute other) + { + return string.Compare(Name, other.Name, StringComparison.Ordinal); + } + + throw new ArgumentException("object is not a PluginAttribute"); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs b/src/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs index c3429b2b1..cf77c866b 100644 --- a/src/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs +++ b/src/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs @@ -5,27 +5,32 @@ using GreenshotPlugin.IniFile; namespace GreenshotPlugin.Interfaces.Plugin { - public class SurfaceOutputSettings { + public class SurfaceOutputSettings + { private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); private bool _reduceColors; private bool _disableReduceColors; - public SurfaceOutputSettings() { + public SurfaceOutputSettings() + { _disableReduceColors = false; Format = CoreConfig.OutputFileFormat; JPGQuality = CoreConfig.OutputFileJpegQuality; ReduceColors = CoreConfig.OutputFileReduceColors; } - public SurfaceOutputSettings(OutputFormat format) : this() { + public SurfaceOutputSettings(OutputFormat format) : this() + { Format = format; } - public SurfaceOutputSettings(OutputFormat format, int quality) : this(format) { + public SurfaceOutputSettings(OutputFormat format, int quality) : this(format) + { JPGQuality = quality; } - public SurfaceOutputSettings(OutputFormat format, int quality, bool reduceColors) : this(format, quality) { + public SurfaceOutputSettings(OutputFormat format, int quality, bool reduceColors) : this(format, quality) + { ReduceColors = reduceColors; } @@ -40,49 +45,44 @@ namespace GreenshotPlugin.Interfaces.Plugin { Format = OutputFormat.png; } + return this; } - public OutputFormat Format { - get; - set; - } + public OutputFormat Format { get; set; } - public int JPGQuality { - get; - set; - } + public int JPGQuality { get; set; } - public bool SaveBackgroundOnly { - get; - set; - } + public bool SaveBackgroundOnly { get; set; } public List Effects { get; } = new List(); - public bool ReduceColors { - get { + public bool ReduceColors + { + get + { // Fix for Bug #3468436, force quantizing when output format is gif as this has only 256 colors! - if (OutputFormat.gif.Equals(Format)) { + if (OutputFormat.gif.Equals(Format)) + { return true; } + return _reduceColors; } - set { - _reduceColors = value; - } + set { _reduceColors = value; } } /// /// Disable the reduce colors option, this overrules the enabling /// - public bool DisableReduceColors { - get { - return _disableReduceColors; - } - set { + public bool DisableReduceColors + { + get { return _disableReduceColors; } + set + { // Quantizing os needed when output format is gif as this has only 256 colors! - if (!OutputFormat.gif.Equals(Format)) { + if (!OutputFormat.gif.Equals(Format)) + { _disableReduceColors = value; } } diff --git a/src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs b/src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs index b30a68828..c3abaa642 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs +++ b/src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs @@ -25,10 +25,6 @@ namespace GreenshotPlugin.Interfaces { public class SurfaceDrawingModeEventArgs : EventArgs { - public DrawingModes DrawingMode - { - get; - set; - } + public DrawingModes DrawingMode { get; set; } } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs b/src/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs index f53241447..3212e8613 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs +++ b/src/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs @@ -26,10 +26,6 @@ namespace GreenshotPlugin.Interfaces { public class SurfaceElementEventArgs : EventArgs { - public IDrawableContainerList Elements - { - get; - set; - } + public IDrawableContainerList Elements { get; set; } } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs b/src/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs index 2908e9ffb..783ce1277 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs +++ b/src/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs @@ -24,21 +24,9 @@ using System; namespace GreenshotPlugin.Interfaces { public class SurfaceMessageEventArgs : EventArgs - { - public SurfaceMessageTyp MessageType - { - get; - set; - } - public string Message - { - get; - set; - } - public ISurface Surface - { - get; - set; - } - } + { + public SurfaceMessageTyp MessageType { get; set; } + public string Message { get; set; } + public ISurface Surface { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/Base.cs b/src/GreenshotPlugin/Interop/Base.cs index ec821a6ef..117e5be59 100644 --- a/src/GreenshotPlugin/Interop/Base.cs +++ b/src/GreenshotPlugin/Interop/Base.cs @@ -1,9 +1,11 @@ using System; -namespace GreenshotPlugin.Interop { - /// - /// Common properties that has appreared in almost all objects - /// - public interface ICommon : IDisposable { - } -} +namespace GreenshotPlugin.Interop +{ + /// + /// Common properties that has appreared in almost all objects + /// + public interface ICommon : IDisposable + { + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/COMWrapper.cs b/src/GreenshotPlugin/Interop/COMWrapper.cs index c96033de3..c215809b0 100644 --- a/src/GreenshotPlugin/Interop/COMWrapper.cs +++ b/src/GreenshotPlugin/Interop/COMWrapper.cs @@ -29,470 +29,593 @@ using System.Windows.Forms; using GreenshotPlugin.Core; using log4net; -namespace GreenshotPlugin.Interop { - /// - /// Wraps a late-bound COM server. - /// - public sealed class COMWrapper : RealProxy, IDisposable, IRemotingTypeInfo { - private static readonly ILog Log = LogManager.GetLogger(typeof(COMWrapper)); - public const int RPC_E_CALL_REJECTED = unchecked((int)0x80010001); - public const int RPC_E_FAIL = unchecked((int)0x80004005); +namespace GreenshotPlugin.Interop +{ + /// + /// Wraps a late-bound COM server. + /// + public sealed class COMWrapper : RealProxy, IDisposable, IRemotingTypeInfo + { + private static readonly ILog Log = LogManager.GetLogger(typeof(COMWrapper)); + public const int RPC_E_CALL_REJECTED = unchecked((int) 0x80010001); + public const int RPC_E_FAIL = unchecked((int) 0x80004005); /// - /// Holds reference to the actual COM object which is wrapped by this proxy - /// - private readonly object _comObject; - - /// - /// Type of the COM object, set on constructor after getting the COM reference - /// - private readonly Type _comType; - - /// - /// The type of which method calls are intercepted and executed on the COM object. - /// - private readonly Type _interceptType; - - /// - /// The humanly readable target name - /// - private readonly string _targetName; + /// Holds reference to the actual COM object which is wrapped by this proxy + /// + private readonly object _comObject; /// - /// A simple create instance, doesn't create a wrapper!! - /// - /// T - public static T CreateInstance() { - Type type = typeof(T); - if (null == type) { - throw new ArgumentNullException(nameof(T)); - } - if (!type.IsInterface) { - throw new ArgumentException("The specified type must be an interface.", nameof(T)); - } - - ComProgIdAttribute progIdAttribute = ComProgIdAttribute.GetAttribute(type); - if (string.IsNullOrEmpty(progIdAttribute?.Value)) { - throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T)); - } - string progId = progIdAttribute.Value; - Type comType = null; - if (progId.StartsWith("clsid:")) { - Guid guid = new Guid(progId.Substring(6)); - try { - comType = Type.GetTypeFromCLSID(guid); - } catch (Exception ex) { - Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); - } - } else { - try { - comType = Type.GetTypeFromProgID(progId, true); - } catch (Exception ex) { - Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); - } - } - object comObject = null; - if (comType != null) { - try { - comObject = Activator.CreateInstance(comType); - if (comObject != null) { - Log.DebugFormat("Created new instance of {0} object.", progId); - } - } catch (Exception e) { - Log.WarnFormat("Error {1} creating object for {0}", progId, e.Message); - throw; - } - } - if (comObject != null) { - return (T)comObject; - } - return default; - } + /// Type of the COM object, set on constructor after getting the COM reference + /// + private readonly Type _comType; /// - /// Wrap an object and return the transparent proxy which intercepts all calls to the object - /// - /// An object to intercept - /// Interface which defines the method and properties to intercept - /// - /// Transparent proxy to the real proxy for the object - private static object Wrap(object comObject, Type type, string targetName) { - if (null == comObject) { - throw new ArgumentNullException(nameof(comObject)); - } - if (null == type) { - throw new ArgumentNullException(nameof(type)); - } - - COMWrapper wrapper = new COMWrapper(comObject, type, targetName); - return wrapper.GetTransparentProxy(); - } - - /// - /// Constructor - /// - /// - /// The COM object to wrap. - /// - /// - /// The interface type to impersonate. - /// - /// - private COMWrapper(object comObject, Type type, string targetName) : base(type) { - _comObject = comObject; - _comType = comObject.GetType(); - _interceptType = type; - _targetName = targetName; - } + /// The type of which method calls are intercepted and executed on the COM object. + /// + private readonly Type _interceptType; /// - /// If is not called, we need to make - /// sure that the COM object is still cleaned up. - /// - ~COMWrapper() { - Log.DebugFormat("Finalize {0}", _interceptType); - Dispose(false); - } - - /// - /// Cleans up the COM object. - /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Release the COM reference - /// - /// - /// if this was called from the - /// interface. - /// - private void Dispose(bool disposing) { - if (null != _comObject) { - Log.DebugFormat("Disposing {0}", _interceptType); - if (Marshal.IsComObject(_comObject)) { - try { - int count; - do { - count = Marshal.ReleaseComObject(_comObject); - Log.DebugFormat("RCW count for {0} now is {1}", _interceptType, count); - } while (count > 0); - } catch (Exception ex) { - Log.WarnFormat("Problem releasing COM object {0}", _comType); - Log.Warn("Error: ", ex); - } - } else { - Log.WarnFormat("{0} is not a COM object", _comType); - } - } - } + /// The humanly readable target name + /// + private readonly string _targetName; /// - /// Returns a string representing the wrapped object. - /// - /// - /// The full name of the intercepted type. - /// - public override string ToString() { - return _interceptType.FullName; - } + /// A simple create instance, doesn't create a wrapper!! + /// + /// T + public static T CreateInstance() + { + Type type = typeof(T); + if (null == type) + { + throw new ArgumentNullException(nameof(T)); + } - /// - /// Returns the hash code of the wrapped object. - /// - /// - /// The hash code of the wrapped object. - /// - public override int GetHashCode() { - return _comObject.GetHashCode(); - } + if (!type.IsInterface) + { + throw new ArgumentException("The specified type must be an interface.", nameof(T)); + } - /// - /// Compares this object to another. - /// - /// - /// The value to compare to. - /// - /// - /// if the objects are equal. - /// - public override bool Equals(object value) { - if (null != value && RemotingServices.IsTransparentProxy(value)) { - COMWrapper wrapper = RemotingServices.GetRealProxy(value) as COMWrapper; - if (null != wrapper) { - return _comObject == wrapper._comObject; - } - } + ComProgIdAttribute progIdAttribute = ComProgIdAttribute.GetAttribute(type); + if (string.IsNullOrEmpty(progIdAttribute?.Value)) + { + throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T)); + } - return base.Equals(value); - } + string progId = progIdAttribute.Value; + Type comType = null; + if (progId.StartsWith("clsid:")) + { + Guid guid = new Guid(progId.Substring(6)); + try + { + comType = Type.GetTypeFromCLSID(guid); + } + catch (Exception ex) + { + Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); + } + } + else + { + try + { + comType = Type.GetTypeFromProgID(progId, true); + } + catch (Exception ex) + { + Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); + } + } - /// - /// Returns the base type for a reference type. - /// - /// - /// The reference type. - /// - /// - /// The base value type. - /// - /// - /// is . - /// - private static Type GetByValType(Type byRefType) { - if (null == byRefType) { - throw new ArgumentNullException(nameof(byRefType)); - } + object comObject = null; + if (comType != null) + { + try + { + comObject = Activator.CreateInstance(comType); + if (comObject != null) + { + Log.DebugFormat("Created new instance of {0} object.", progId); + } + } + catch (Exception e) + { + Log.WarnFormat("Error {1} creating object for {0}", progId, e.Message); + throw; + } + } - if (byRefType.IsByRef) { - string name = byRefType.FullName; - name = name.Substring(0, name.Length - 1); - byRefType = byRefType.Assembly.GetType(name, true); - } + if (comObject != null) + { + return (T) comObject; + } - return byRefType; - } + return default; + } /// - /// Intercept method calls - /// - /// - /// Contains information about the method being called - /// - /// - /// A . - /// - public override IMessage Invoke(IMessage myMessage) { - if (!(myMessage is IMethodCallMessage callMessage)) { - Log.DebugFormat("Message type not implemented: {0}", myMessage.GetType()); - return null; - } + /// Wrap an object and return the transparent proxy which intercepts all calls to the object + /// + /// An object to intercept + /// Interface which defines the method and properties to intercept + /// + /// Transparent proxy to the real proxy for the object + private static object Wrap(object comObject, Type type, string targetName) + { + if (null == comObject) + { + throw new ArgumentNullException(nameof(comObject)); + } - MethodInfo method = callMessage.MethodBase as MethodInfo; - if (null == method) { - Log.DebugFormat("Unrecognized Invoke call: {0}", callMessage.MethodBase); - return null; - } + if (null == type) + { + throw new ArgumentNullException(nameof(type)); + } - object returnValue = null; - object[] outArgs = null; - int outArgsCount = 0; + COMWrapper wrapper = new COMWrapper(comObject, type, targetName); + return wrapper.GetTransparentProxy(); + } - string methodName = method.Name; - Type returnType = method.ReturnType; - BindingFlags flags = BindingFlags.InvokeMethod; - int argCount = callMessage.ArgCount; + /// + /// Constructor + /// + /// + /// The COM object to wrap. + /// + /// + /// The interface type to impersonate. + /// + /// + private COMWrapper(object comObject, Type type, string targetName) : base(type) + { + _comObject = comObject; + _comType = comObject.GetType(); + _interceptType = type; + _targetName = targetName; + } - ParameterModifier[] argModifiers = null; - ParameterInfo[] parameters = null; + /// + /// If is not called, we need to make + /// sure that the COM object is still cleaned up. + /// + ~COMWrapper() + { + Log.DebugFormat("Finalize {0}", _interceptType); + Dispose(false); + } - if ("Dispose" == methodName && 0 == argCount && typeof(void) == returnType) { - Dispose(); - } else if ("ToString" == methodName && 0 == argCount && typeof(string) == returnType) { - returnValue = ToString(); - } else if ("GetType" == methodName && 0 == argCount && typeof(Type) == returnType) { - returnValue = _interceptType; - } else if ("GetHashCode" == methodName && 0 == argCount && typeof(int) == returnType) { - returnValue = GetHashCode(); - } else if ("Equals" == methodName && 1 == argCount && typeof(bool) == returnType) { - returnValue = Equals(callMessage.Args[0]); - } else if (1 == argCount && typeof(void) == returnType && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) { - bool removeHandler = methodName.StartsWith("remove_"); - methodName = methodName.Substring(removeHandler ? 7 : 4); - // TODO: Something is missing here - if (!(callMessage.InArgs[0] is Delegate handler)) { - return new ReturnMessage(new ArgumentNullException(nameof(handler)), callMessage); - } - } else { - var invokeObject = _comObject; - var invokeType = _comType; + /// + /// Cleans up the COM object. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } - object[] args; - ParameterInfo parameter; - if (methodName.StartsWith("get_")) { - // Property Get - methodName = methodName.Substring(4); - flags = BindingFlags.GetProperty; - args = callMessage.InArgs; - } else if (methodName.StartsWith("set_")) { - // Property Set - methodName = methodName.Substring(4); - flags = BindingFlags.SetProperty; - args = callMessage.InArgs; - } else { - args = callMessage.Args; - if (null != args && 0 != args.Length) { - // Modifiers for ref / out parameters - argModifiers = new ParameterModifier[1]; - argModifiers[0] = new ParameterModifier(args.Length); + /// + /// Release the COM reference + /// + /// + /// if this was called from the + /// interface. + /// + private void Dispose(bool disposing) + { + if (null != _comObject) + { + Log.DebugFormat("Disposing {0}", _interceptType); + if (Marshal.IsComObject(_comObject)) + { + try + { + int count; + do + { + count = Marshal.ReleaseComObject(_comObject); + Log.DebugFormat("RCW count for {0} now is {1}", _interceptType, count); + } while (count > 0); + } + catch (Exception ex) + { + Log.WarnFormat("Problem releasing COM object {0}", _comType); + Log.Warn("Error: ", ex); + } + } + else + { + Log.WarnFormat("{0} is not a COM object", _comType); + } + } + } - parameters = method.GetParameters(); - for (int i = 0; i < parameters.Length; i++) { - parameter = parameters[i]; - if (parameter.IsOut || parameter.ParameterType.IsByRef) { - argModifiers[0][i] = true; - outArgsCount++; - } - } + /// + /// Returns a string representing the wrapped object. + /// + /// + /// The full name of the intercepted type. + /// + public override string ToString() + { + return _interceptType.FullName; + } - if (0 == outArgsCount) { - argModifiers = null; - } - } - } + /// + /// Returns the hash code of the wrapped object. + /// + /// + /// The hash code of the wrapped object. + /// + public override int GetHashCode() + { + return _comObject.GetHashCode(); + } - // Un-wrap wrapped COM objects before passing to the method - Type byValType; - COMWrapper wrapper; - COMWrapper[] originalArgs; - if (null == args || 0 == args.Length) { - originalArgs = null; - } else { - originalArgs = new COMWrapper[args.Length]; - for (int i = 0; i < args.Length; i++) { - if (null != args[i] && RemotingServices.IsTransparentProxy(args[i])) { - wrapper = RemotingServices.GetRealProxy(args[i]) as COMWrapper; - if (null != wrapper) { - originalArgs[i] = wrapper; - args[i] = wrapper._comObject; - } - } else if (0 != outArgsCount && argModifiers[0][i]) { - byValType = GetByValType(parameters[i].ParameterType); - if (byValType.IsInterface) { - // If we're passing a COM object by reference, and - // the parameter is null, we need to pass a - // DispatchWrapper to avoid a type mismatch exception. - if (null == args[i]) { - args[i] = new DispatchWrapper(null); - } - } else if (typeof(decimal) == byValType) { - // If we're passing a decimal value by reference, - // we need to pass a CurrencyWrapper to avoid a - // type mismatch exception. - // http://support.microsoft.com/?kbid=837378 - args[i] = new CurrencyWrapper(args[i]); - } - } - } - } + /// + /// Compares this object to another. + /// + /// + /// The value to compare to. + /// + /// + /// if the objects are equal. + /// + public override bool Equals(object value) + { + if (null != value && RemotingServices.IsTransparentProxy(value)) + { + COMWrapper wrapper = RemotingServices.GetRealProxy(value) as COMWrapper; + if (null != wrapper) + { + return _comObject == wrapper._comObject; + } + } - do { - try { - returnValue = invokeType.InvokeMember(methodName, flags, null, invokeObject, args, argModifiers, null, null); - break; - } catch (InvalidComObjectException icoEx) { - // Should assist BUG-1616 and others - Log.WarnFormat("COM object {0} has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.", _interceptType.FullName); - return new ReturnMessage(icoEx, callMessage); - } catch (Exception ex) { - // Test for rejected - if (!(ex is COMException comEx)) { - comEx = ex.InnerException as COMException; - } - if (comEx != null && (comEx.ErrorCode == RPC_E_CALL_REJECTED || comEx.ErrorCode == RPC_E_FAIL)) { - string destinationName = _targetName; - // Try to find a "catchy" name for the rejecting application - if (destinationName != null && destinationName.Contains(".")) { - destinationName = destinationName.Substring(0, destinationName.IndexOf(".", StringComparison.Ordinal)); - } - if (destinationName == null) { - destinationName = _interceptType.FullName; - } + return base.Equals(value); + } + + /// + /// Returns the base type for a reference type. + /// + /// + /// The reference type. + /// + /// + /// The base value type. + /// + /// + /// is . + /// + private static Type GetByValType(Type byRefType) + { + if (null == byRefType) + { + throw new ArgumentNullException(nameof(byRefType)); + } + + if (byRefType.IsByRef) + { + string name = byRefType.FullName; + name = name.Substring(0, name.Length - 1); + byRefType = byRefType.Assembly.GetType(name, true); + } + + return byRefType; + } + + /// + /// Intercept method calls + /// + /// + /// Contains information about the method being called + /// + /// + /// A . + /// + public override IMessage Invoke(IMessage myMessage) + { + if (!(myMessage is IMethodCallMessage callMessage)) + { + Log.DebugFormat("Message type not implemented: {0}", myMessage.GetType()); + return null; + } + + MethodInfo method = callMessage.MethodBase as MethodInfo; + if (null == method) + { + Log.DebugFormat("Unrecognized Invoke call: {0}", callMessage.MethodBase); + return null; + } + + object returnValue = null; + object[] outArgs = null; + int outArgsCount = 0; + + string methodName = method.Name; + Type returnType = method.ReturnType; + BindingFlags flags = BindingFlags.InvokeMethod; + int argCount = callMessage.ArgCount; + + ParameterModifier[] argModifiers = null; + ParameterInfo[] parameters = null; + + if ("Dispose" == methodName && 0 == argCount && typeof(void) == returnType) + { + Dispose(); + } + else if ("ToString" == methodName && 0 == argCount && typeof(string) == returnType) + { + returnValue = ToString(); + } + else if ("GetType" == methodName && 0 == argCount && typeof(Type) == returnType) + { + returnValue = _interceptType; + } + else if ("GetHashCode" == methodName && 0 == argCount && typeof(int) == returnType) + { + returnValue = GetHashCode(); + } + else if ("Equals" == methodName && 1 == argCount && typeof(bool) == returnType) + { + returnValue = Equals(callMessage.Args[0]); + } + else if (1 == argCount && typeof(void) == returnType && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) + { + bool removeHandler = methodName.StartsWith("remove_"); + methodName = methodName.Substring(removeHandler ? 7 : 4); + // TODO: Something is missing here + if (!(callMessage.InArgs[0] is Delegate handler)) + { + return new ReturnMessage(new ArgumentNullException(nameof(handler)), callMessage); + } + } + else + { + var invokeObject = _comObject; + var invokeType = _comType; + + object[] args; + ParameterInfo parameter; + if (methodName.StartsWith("get_")) + { + // Property Get + methodName = methodName.Substring(4); + flags = BindingFlags.GetProperty; + args = callMessage.InArgs; + } + else if (methodName.StartsWith("set_")) + { + // Property Set + methodName = methodName.Substring(4); + flags = BindingFlags.SetProperty; + args = callMessage.InArgs; + } + else + { + args = callMessage.Args; + if (null != args && 0 != args.Length) + { + // Modifiers for ref / out parameters + argModifiers = new ParameterModifier[1]; + argModifiers[0] = new ParameterModifier(args.Length); + + parameters = method.GetParameters(); + for (int i = 0; i < parameters.Length; i++) + { + parameter = parameters[i]; + if (parameter.IsOut || parameter.ParameterType.IsByRef) + { + argModifiers[0][i] = true; + outArgsCount++; + } + } + + if (0 == outArgsCount) + { + argModifiers = null; + } + } + } + + // Un-wrap wrapped COM objects before passing to the method + Type byValType; + COMWrapper wrapper; + COMWrapper[] originalArgs; + if (null == args || 0 == args.Length) + { + originalArgs = null; + } + else + { + originalArgs = new COMWrapper[args.Length]; + for (int i = 0; i < args.Length; i++) + { + if (null != args[i] && RemotingServices.IsTransparentProxy(args[i])) + { + wrapper = RemotingServices.GetRealProxy(args[i]) as COMWrapper; + if (null != wrapper) + { + originalArgs[i] = wrapper; + args[i] = wrapper._comObject; + } + } + else if (0 != outArgsCount && argModifiers[0][i]) + { + byValType = GetByValType(parameters[i].ParameterType); + if (byValType.IsInterface) + { + // If we're passing a COM object by reference, and + // the parameter is null, we need to pass a + // DispatchWrapper to avoid a type mismatch exception. + if (null == args[i]) + { + args[i] = new DispatchWrapper(null); + } + } + else if (typeof(decimal) == byValType) + { + // If we're passing a decimal value by reference, + // we need to pass a CurrencyWrapper to avoid a + // type mismatch exception. + // http://support.microsoft.com/?kbid=837378 + args[i] = new CurrencyWrapper(args[i]); + } + } + } + } + + do + { + try + { + returnValue = invokeType.InvokeMember(methodName, flags, null, invokeObject, args, argModifiers, null, null); + break; + } + catch (InvalidComObjectException icoEx) + { + // Should assist BUG-1616 and others + Log.WarnFormat( + "COM object {0} has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.", + _interceptType.FullName); + return new ReturnMessage(icoEx, callMessage); + } + catch (Exception ex) + { + // Test for rejected + if (!(ex is COMException comEx)) + { + comEx = ex.InnerException as COMException; + } + + if (comEx != null && (comEx.ErrorCode == RPC_E_CALL_REJECTED || comEx.ErrorCode == RPC_E_FAIL)) + { + string destinationName = _targetName; + // Try to find a "catchy" name for the rejecting application + if (destinationName != null && destinationName.Contains(".")) + { + destinationName = destinationName.Substring(0, destinationName.IndexOf(".", StringComparison.Ordinal)); + } + + if (destinationName == null) + { + destinationName = _interceptType.FullName; + } var form = SimpleServiceProvider.Current.GetInstance(); - DialogResult result = MessageBox.Show(form, Language.GetFormattedString("com_rejected", destinationName), Language.GetString("com_rejected_title"), MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation); - if (result == DialogResult.OK) { - continue; - } - } - // Not rejected OR pressed cancel - return new ReturnMessage(ex, callMessage); - } - } while (true); + DialogResult result = MessageBox.Show(form, Language.GetFormattedString("com_rejected", destinationName), Language.GetString("com_rejected_title"), + MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation); + if (result == DialogResult.OK) + { + continue; + } + } - // Handle enum and interface return types - if (null != returnValue) { - if (returnType.IsInterface) { - // Wrap the returned value in an intercepting COM wrapper - if (Marshal.IsComObject(returnValue)) { - returnValue = Wrap(returnValue, returnType, _targetName); - } - } else if (returnType.IsEnum) { - // Convert to proper Enum type - returnValue = Enum.Parse(returnType, returnValue.ToString()); - } - } + // Not rejected OR pressed cancel + return new ReturnMessage(ex, callMessage); + } + } while (true); - // Handle out args - if (0 != outArgsCount) { - outArgs = new object[args.Length]; - for (int i = 0; i < parameters.Length; i++) { - if (!argModifiers[0][i]) { - continue; - } + // Handle enum and interface return types + if (null != returnValue) + { + if (returnType.IsInterface) + { + // Wrap the returned value in an intercepting COM wrapper + if (Marshal.IsComObject(returnValue)) + { + returnValue = Wrap(returnValue, returnType, _targetName); + } + } + else if (returnType.IsEnum) + { + // Convert to proper Enum type + returnValue = Enum.Parse(returnType, returnValue.ToString()); + } + } - var arg = args[i]; - if (null == arg) { - continue; - } + // Handle out args + if (0 != outArgsCount) + { + outArgs = new object[args.Length]; + for (int i = 0; i < parameters.Length; i++) + { + if (!argModifiers[0][i]) + { + continue; + } - parameter = parameters[i]; - wrapper = null; + var arg = args[i]; + if (null == arg) + { + continue; + } - byValType = GetByValType(parameter.ParameterType); - if (typeof(decimal) == byValType) { - if (arg is CurrencyWrapper) { - arg = ((CurrencyWrapper)arg).WrappedObject; - } - } else if (byValType.IsEnum) { - arg = Enum.Parse(byValType, arg.ToString()); - } else if (byValType.IsInterface) { - if (Marshal.IsComObject(arg)) { - wrapper = originalArgs[i]; - if (null != wrapper && wrapper._comObject != arg) { - wrapper.Dispose(); - wrapper = null; - } + parameter = parameters[i]; + wrapper = null; - if (null == wrapper) { - wrapper = new COMWrapper(arg, byValType, _targetName); - } - arg = wrapper.GetTransparentProxy(); - } - } - outArgs[i] = arg; - } - } - } + byValType = GetByValType(parameter.ParameterType); + if (typeof(decimal) == byValType) + { + if (arg is CurrencyWrapper) + { + arg = ((CurrencyWrapper) arg).WrappedObject; + } + } + else if (byValType.IsEnum) + { + arg = Enum.Parse(byValType, arg.ToString()); + } + else if (byValType.IsInterface) + { + if (Marshal.IsComObject(arg)) + { + wrapper = originalArgs[i]; + if (null != wrapper && wrapper._comObject != arg) + { + wrapper.Dispose(); + wrapper = null; + } - return new ReturnMessage(returnValue, outArgs, outArgsCount, callMessage.LogicalCallContext, callMessage); - } + if (null == wrapper) + { + wrapper = new COMWrapper(arg, byValType, _targetName); + } - /// - /// Implementation for the interface IRemotingTypeInfo - /// This makes it possible to cast the COMWrapper - /// - /// Type to cast to - /// object to cast - /// - public bool CanCastTo(Type toType, object o) { - bool returnValue = _interceptType.IsAssignableFrom(toType); - return returnValue; - } + arg = wrapper.GetTransparentProxy(); + } + } - /// - /// Implementation for the interface IRemotingTypeInfo - /// - public string TypeName { - get { - throw new NotSupportedException(); - } - set { - throw new NotSupportedException(); - } - } - } -} + outArgs[i] = arg; + } + } + } + + return new ReturnMessage(returnValue, outArgs, outArgsCount, callMessage.LogicalCallContext, callMessage); + } + + /// + /// Implementation for the interface IRemotingTypeInfo + /// This makes it possible to cast the COMWrapper + /// + /// Type to cast to + /// object to cast + /// + public bool CanCastTo(Type toType, object o) + { + bool returnValue = _interceptType.IsAssignableFrom(toType); + return returnValue; + } + + /// + /// Implementation for the interface IRemotingTypeInfo + /// + public string TypeName + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/ComProgIdAttribute.cs b/src/GreenshotPlugin/Interop/ComProgIdAttribute.cs index ed88fa7be..ecb782773 100644 --- a/src/GreenshotPlugin/Interop/ComProgIdAttribute.cs +++ b/src/GreenshotPlugin/Interop/ComProgIdAttribute.cs @@ -21,60 +21,68 @@ using System; -namespace GreenshotPlugin.Interop { - /// - /// An attribute to specifiy the ProgID of the COM class to create. (As suggested by Kristen Wegner) - /// - [AttributeUsage(AttributeTargets.Interface)] - public sealed class ComProgIdAttribute : Attribute { - /// - /// Extracts the attribute from the specified type. - /// - /// - /// The interface type. - /// - /// - /// The . - /// - /// - /// is . - /// - public static ComProgIdAttribute GetAttribute(Type interfaceType) { - if (null == interfaceType) { - throw new ArgumentNullException(nameof(interfaceType)); - } +namespace GreenshotPlugin.Interop +{ + /// + /// An attribute to specifiy the ProgID of the COM class to create. (As suggested by Kristen Wegner) + /// + [AttributeUsage(AttributeTargets.Interface)] + public sealed class ComProgIdAttribute : Attribute + { + /// + /// Extracts the attribute from the specified type. + /// + /// + /// The interface type. + /// + /// + /// The . + /// + /// + /// is . + /// + public static ComProgIdAttribute GetAttribute(Type interfaceType) + { + if (null == interfaceType) + { + throw new ArgumentNullException(nameof(interfaceType)); + } - Type attributeType = typeof(ComProgIdAttribute); - object[] attributes = interfaceType.GetCustomAttributes(attributeType, false); + Type attributeType = typeof(ComProgIdAttribute); + object[] attributes = interfaceType.GetCustomAttributes(attributeType, false); - if (0 == attributes.Length) - { - Type[] interfaces = interfaceType.GetInterfaces(); - foreach (Type t in interfaces) - { - interfaceType = t; - attributes = interfaceType.GetCustomAttributes(attributeType, false); - if (0 != attributes.Length) { - break; - } - } - } + if (0 == attributes.Length) + { + Type[] interfaces = interfaceType.GetInterfaces(); + foreach (Type t in interfaces) + { + interfaceType = t; + attributes = interfaceType.GetCustomAttributes(attributeType, false); + if (0 != attributes.Length) + { + break; + } + } + } - if (0 == attributes.Length) { - return null; - } - return (ComProgIdAttribute)attributes[0]; - } + if (0 == attributes.Length) + { + return null; + } - /// Constructor - /// The COM ProgID. - public ComProgIdAttribute(string value) { - Value = value; - } + return (ComProgIdAttribute) attributes[0]; + } - /// - /// Returns the COM ProgID - /// - public string Value { get; } - } -} + /// Constructor + /// The COM ProgID. + public ComProgIdAttribute(string value) + { + Value = value; + } + + /// + /// Returns the COM ProgID + /// + public string Value { get; } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IAppVisibility.cs b/src/GreenshotPlugin/Interop/IAppVisibility.cs index 58fddc8b8..f9fa6ed10 100644 --- a/src/GreenshotPlugin/Interop/IAppVisibility.cs +++ b/src/GreenshotPlugin/Interop/IAppVisibility.cs @@ -22,19 +22,20 @@ using System; using System.Runtime.InteropServices; -namespace GreenshotPlugin.Interop { - // This is used for Windows 8 to see if the App Launcher is active - // See http://msdn.microsoft.com/en-us/library/windows/desktop/jj554119%28v=vs.85%29.aspx - [ComProgId("clsid:7E5FE3D9-985F-4908-91F9-EE19F9FD1514")] - [ComImport, Guid("2246EA2D-CAEA-4444-A3C4-6DE827E44313"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IAppVisibility { - MONITOR_APP_VISIBILITY GetAppVisibilityOnMonitor(IntPtr hMonitor); - bool IsLauncherVisible { - get; - } - } +namespace GreenshotPlugin.Interop +{ + // This is used for Windows 8 to see if the App Launcher is active + // See http://msdn.microsoft.com/en-us/library/windows/desktop/jj554119%28v=vs.85%29.aspx + [ComProgId("clsid:7E5FE3D9-985F-4908-91F9-EE19F9FD1514")] + [ComImport, Guid("2246EA2D-CAEA-4444-A3C4-6DE827E44313"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IAppVisibility + { + MONITOR_APP_VISIBILITY GetAppVisibilityOnMonitor(IntPtr hMonitor); + bool IsLauncherVisible { get; } + } - public enum MONITOR_APP_VISIBILITY { - MAV_APP_VISIBLE = 2 - } -} + public enum MONITOR_APP_VISIBILITY + { + MAV_APP_VISIBLE = 2 + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IDispatch.cs b/src/GreenshotPlugin/Interop/IDispatch.cs index b4391c621..99edf0a87 100644 --- a/src/GreenshotPlugin/Interop/IDispatch.cs +++ b/src/GreenshotPlugin/Interop/IDispatch.cs @@ -23,21 +23,25 @@ using System; using System.Runtime.InteropServices; using System.Runtime.InteropServices.CustomMarshalers; -namespace GreenshotPlugin.Interop { - [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsDual)] - public interface IDispatch : IUnknown { - [PreserveSig] - int GetTypeInfoCount(out int count); +namespace GreenshotPlugin.Interop +{ + [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsDual)] + public interface IDispatch : IUnknown + { + [PreserveSig] + int GetTypeInfoCount(out int count); - [PreserveSig] - int GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo, [MarshalAs(UnmanagedType.U4)] int lcid, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))] out Type typeInfo); + [PreserveSig] + int GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo, [MarshalAs(UnmanagedType.U4)] int lcid, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))] + out Type typeInfo); - [PreserveSig] - int GetIDsOfNames(ref Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] + [PreserveSig] + int GetIDsOfNames(ref Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgsNames, int cNames, int lcid, [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId); - [PreserveSig] - int Invoke(int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, - out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr); - } -} + [PreserveSig] + int Invoke(int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, + out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IOleCommandTarget.cs b/src/GreenshotPlugin/Interop/IOleCommandTarget.cs index 6207d196e..7e41c51e6 100644 --- a/src/GreenshotPlugin/Interop/IOleCommandTarget.cs +++ b/src/GreenshotPlugin/Interop/IOleCommandTarget.cs @@ -22,15 +22,19 @@ using System; using System.Runtime.InteropServices; -namespace GreenshotPlugin.Interop { - [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(true), Guid("B722BCCB-4E68-101B-A2BC-00AA00404770")] - public interface IOleCommandTarget { - [return: MarshalAs(UnmanagedType.I4)] - [PreserveSig] - int QueryStatus([In, MarshalAs(UnmanagedType.LPStruct)] Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText); +namespace GreenshotPlugin.Interop +{ + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(true), Guid("B722BCCB-4E68-101B-A2BC-00AA00404770")] + public interface IOleCommandTarget + { + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int QueryStatus([In, MarshalAs(UnmanagedType.LPStruct)] + Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText); - [return: MarshalAs(UnmanagedType.I4)] - [PreserveSig] - int Exec([In, MarshalAs(UnmanagedType.LPStruct)] Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut); - } -} + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int Exec([In, MarshalAs(UnmanagedType.LPStruct)] + Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IOleWindow.cs b/src/GreenshotPlugin/Interop/IOleWindow.cs index c5361dc0d..b746dc74d 100644 --- a/src/GreenshotPlugin/Interop/IOleWindow.cs +++ b/src/GreenshotPlugin/Interop/IOleWindow.cs @@ -22,12 +22,14 @@ using System; using System.Runtime.InteropServices; -namespace GreenshotPlugin.Interop { - // Needed to get the Window handle from the IDocument2 - // See: http://msdn.microsoft.com/en-us/library/ms680102%28v=vs.85%29.aspx - [ComImport, Guid("00000114-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IOleWindow { - void GetWindow(out IntPtr phWnd); - void ContextSensitiveHelp([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode); - } -} +namespace GreenshotPlugin.Interop +{ + // Needed to get the Window handle from the IDocument2 + // See: http://msdn.microsoft.com/en-us/library/ms680102%28v=vs.85%29.aspx + [ComImport, Guid("00000114-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IOleWindow + { + void GetWindow(out IntPtr phWnd); + void ContextSensitiveHelp([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IServiceProvider.cs b/src/GreenshotPlugin/Interop/IServiceProvider.cs index d058f81c3..9b15b78d5 100644 --- a/src/GreenshotPlugin/Interop/IServiceProvider.cs +++ b/src/GreenshotPlugin/Interop/IServiceProvider.cs @@ -22,12 +22,15 @@ using System; using System.Runtime.InteropServices; -namespace GreenshotPlugin.Interop { - // This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface! - [ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IServiceProvider { - [return: MarshalAs(UnmanagedType.I4)][PreserveSig] - int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject); - } -} +namespace GreenshotPlugin.Interop +{ + // This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface! + [ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IServiceProvider + { + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IUnknown.cs b/src/GreenshotPlugin/Interop/IUnknown.cs index bee0da243..d7cccb743 100644 --- a/src/GreenshotPlugin/Interop/IUnknown.cs +++ b/src/GreenshotPlugin/Interop/IUnknown.cs @@ -22,15 +22,17 @@ using System; using System.Runtime.InteropServices; -namespace GreenshotPlugin.Interop { - [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000000-0000-0000-C000-000000000046")] - public interface IUnknown { - IntPtr QueryInterface(ref Guid riid); +namespace GreenshotPlugin.Interop +{ + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000000-0000-0000-C000-000000000046")] + public interface IUnknown + { + IntPtr QueryInterface(ref Guid riid); - [PreserveSig] - uint AddRef(); + [PreserveSig] + uint AddRef(); - [PreserveSig] - uint Release(); - } -} + [PreserveSig] + uint Release(); + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/DWM.cs b/src/GreenshotPlugin/UnmanagedHelpers/DWM.cs index eed7c71e5..9e7737289 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/DWM.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/DWM.cs @@ -28,55 +28,61 @@ using GreenshotPlugin.UnmanagedHelpers.Enums; using GreenshotPlugin.UnmanagedHelpers.Structs; using Microsoft.Win32; -namespace GreenshotPlugin.UnmanagedHelpers { +namespace GreenshotPlugin.UnmanagedHelpers +{ + /// + /// Desktop Window Manager helper code + /// + public static class DWM + { + // DWM + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb); - /// - /// Desktop Window Manager helper code - /// - public static class DWM { + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmUnregisterThumbnail(IntPtr thumb); - // DWM - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb); - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmUnregisterThumbnail(IntPtr thumb); - [DllImport("dwmapi", SetLastError = true)] - public static extern HResult DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size); - [DllImport("dwmapi", SetLastError = true)] - public static extern HResult DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); + [DllImport("dwmapi", SetLastError = true)] + public static extern HResult DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size); + + [DllImport("dwmapi", SetLastError = true)] + public static extern HResult DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); + + // Deprecated as of Windows 8 Release Preview + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmIsCompositionEnabled(out bool enabled); + + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT lpRect, int size); - // Deprecated as of Windows 8 Release Preview - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmIsCompositionEnabled(out bool enabled); - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT lpRect, int size); [DllImport("dwmapi", SetLastError = true)] public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool pvAttribute, int cbAttribute); // Key to ColorizationColor for DWM - private const string COLORIZATION_COLOR_KEY = @"SOFTWARE\Microsoft\Windows\DWM"; + private const string COLORIZATION_COLOR_KEY = @"SOFTWARE\Microsoft\Windows\DWM"; - /// - /// Checks if the window is cloaked, this should solve some issues with the window selection code - /// - /// IntPtr as hWmd - /// bool - public static bool IsWindowCloaked(IntPtr hWnd) + /// + /// Checks if the window is cloaked, this should solve some issues with the window selection code + /// + /// IntPtr as hWmd + /// bool + public static bool IsWindowCloaked(IntPtr hWnd) { - if (!WindowsVersion.IsWindows8OrLater) + if (!WindowsVersion.IsWindows8OrLater) { return false; } DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAKED, out bool isCloaked, Marshal.SizeOf(typeof(bool))); - return isCloaked; + return isCloaked; } /// - /// Helper method for an easy DWM check - /// - /// bool true if DWM is available AND active - public static bool IsDwmEnabled { + /// Helper method for an easy DWM check + /// + /// bool true if DWM is available AND active + public static bool IsDwmEnabled + { get { // According to: http://technet.microsoft.com/en-us/subscriptions/aa969538%28v=vs.85%29.aspx @@ -86,25 +92,32 @@ namespace GreenshotPlugin.UnmanagedHelpers { { return true; } + if (WindowsVersion.IsWindowsVistaOrLater) { DwmIsCompositionEnabled(out var dwmEnabled); return dwmEnabled; } - return false; - } - } - public static Color ColorizationColor { - get { - using (RegistryKey key = Registry.CurrentUser.OpenSubKey(COLORIZATION_COLOR_KEY, false)) { - object dwordValue = key?.GetValue("ColorizationColor"); - if (dwordValue != null) { - return Color.FromArgb((int)dwordValue); - } - } - return Color.White; - } - } - } -} + return false; + } + } + + public static Color ColorizationColor + { + get + { + using (RegistryKey key = Registry.CurrentUser.OpenSubKey(COLORIZATION_COLOR_KEY, false)) + { + object dwordValue = key?.GetValue("ColorizationColor"); + if (dwordValue != null) + { + return Color.FromArgb((int) dwordValue); + } + } + + return Color.White; + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs index e58bde613..6c9aeb652 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs @@ -35,12 +35,12 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums DWMWA_FORCE_ICONIC_REPRESENTATION, DWMWA_FLIP3D_POLICY, DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista - DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7 - DWMWA_DISALLOW_PEEK, // Since Windows 7 - DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7 - DWMWA_CLOAK, // Since Windows 8 - DWMWA_CLOAKED, // Since Windows 8 - DWMWA_FREEZE_REPRESENTATION, // Since Windows 8 + DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7 + DWMWA_DISALLOW_PEEK, // Since Windows 7 + DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7 + DWMWA_CLOAK, // Since Windows 8 + DWMWA_CLOAKED, // Since Windows 8 + DWMWA_FREEZE_REPRESENTATION, // Since Windows 8 DWMWA_LAST } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs index e442abfd5..37f64de7c 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs @@ -28,57 +28,83 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums /// See: http://msdn.microsoft.com/en-us/library/aa969502(v=vs.85).aspx /// [StructLayout(LayoutKind.Sequential)] - public struct DWM_THUMBNAIL_PROPERTIES { + public struct DWM_THUMBNAIL_PROPERTIES + { // A bitwise combination of DWM thumbnail constant values that indicates which members of this structure are set. public int dwFlags; + // The area in the destination window where the thumbnail will be rendered. public RECT rcDestination; + // The region of the source window to use as the thumbnail. By default, the entire window is used as the thumbnail. public RECT rcSource; + // The opacity with which to render the thumbnail. 0 is fully transparent while 255 is fully opaque. The default value is 255. public byte opacity; + // TRUE to make the thumbnail visible; otherwise, FALSE. The default is FALSE. public bool fVisible; + // TRUE to use only the thumbnail source's client area; otherwise, FALSE. The default is FALSE. public bool fSourceClientAreaOnly; - public RECT Destination { - set { + + public RECT Destination + { + set + { dwFlags |= DWM_TNP_RECTDESTINATION; rcDestination = value; } } - public RECT Source { - set { + + public RECT Source + { + set + { dwFlags |= DWM_TNP_RECTSOURCE; rcSource = value; } } - public byte Opacity { - set { + + public byte Opacity + { + set + { dwFlags |= DWM_TNP_OPACITY; opacity = value; } } - public bool Visible { - set { + + public bool Visible + { + set + { dwFlags |= DWM_TNP_VISIBLE; fVisible = value; } } - public bool SourceClientAreaOnly { - set { + + public bool SourceClientAreaOnly + { + set + { dwFlags |= DWM_TNP_SOURCECLIENTAREAONLY; fSourceClientAreaOnly = value; } } + // A value for the rcDestination member has been specified. public const int DWM_TNP_RECTDESTINATION = 0x00000001; + // A value for the rcSource member has been specified. public const int DWM_TNP_RECTSOURCE = 0x00000002; + // A value for the opacity member has been specified. public const int DWM_TNP_OPACITY = 0x00000004; + // A value for the fVisible member has been specified. public const int DWM_TNP_VISIBLE = 0x00000008; + // A value for the fSourceClientAreaOnly member has been specified. public const int DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010; } diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs index a52871fa4..a0b5e1be8 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs @@ -26,7 +26,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums { [Flags] [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DesktopAccessRight : uint { + public enum DesktopAccessRight : uint + { DESKTOP_READOBJECTS = 0x00000001, DESKTOP_CREATEWINDOW = 0x00000002, DESKTOP_CREATEMENU = 0x00000004, diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs index d83bf89a0..ff4f3e3e4 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs @@ -28,8 +28,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd144877%28v=vs.85%29.aspx /// [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DeviceCaps { - + public enum DeviceCaps + { /// /// Logical pixels inch in X /// diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs index 6bc87e3f7..e04af4108 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs @@ -26,8 +26,11 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums { [Flags] [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ExtendedWindowStyleFlags : uint { - WS_EX_TOOLWINDOW = 0x00000080, - WS_EX_NOREDIRECTIONBITMAP = 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual. + public enum ExtendedWindowStyleFlags : uint + { + WS_EX_TOOLWINDOW = 0x00000080, + + WS_EX_NOREDIRECTIONBITMAP = + 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual. } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs index 063623e25..27a89b3b6 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs @@ -26,7 +26,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums { [Flags] [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ProcessAccessFlags : uint { + public enum ProcessAccessFlags : uint + { VMRead = 0x00000010, QueryInformation = 0x00000400, } diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs index b9ef9536f..bc1b0f372 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs @@ -24,7 +24,8 @@ using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums { [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum RegionResult { + public enum RegionResult + { REGION_ERROR = 0, REGION_NULLREGION = 1, } diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs index e8cbd4390..70a6ff104 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs @@ -29,7 +29,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums /// [Flags] [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SendMessageTimeoutFlags : uint { - SMTO_NORMAL = 0x0 + public enum SendMessageTimeoutFlags : uint + { + SMTO_NORMAL = 0x0 } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs index 7962650d3..76ccb3ce4 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs @@ -24,11 +24,13 @@ using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums { [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ShowWindowCommand : uint { + public enum ShowWindowCommand : uint + { /// /// Hides the window and activates another window. /// Hide = 0, + /// /// Activates and displays a window. If the window is minimized or /// maximized, the system restores it to its original size and position. @@ -36,57 +38,68 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums /// for the first time. /// Normal = 1, + /// /// Activates the window and displays it as a minimized window. /// ShowMinimized = 2, + /// /// Maximizes the specified window. /// Maximize = 3, // is this the right value? + /// /// Activates the window and displays it as a maximized window. /// ShowMaximized = 3, + /// /// Displays a window in its most recent size and position. This value /// is similar to , except /// the window is not actived. /// ShowNoActivate = 4, + /// /// Activates the window and displays it in its current size and position. /// Show = 5, + /// /// Minimizes the specified window and activates the next top-level /// window in the Z order. /// Minimize = 6, + /// /// Displays the window as a minimized window. This value is similar to /// , except the /// window is not activated. /// ShowMinNoActive = 7, + /// /// Displays the window in its current size and position. This value is /// similar to , except the /// window is not activated. /// ShowNA = 8, + /// /// Activates and displays the window. If the window is minimized or /// maximized, the system restores it to its original size and position. /// An application should specify this flag when restoring a minimized window. /// Restore = 9, + /// /// Sets the show state based on the SW_* value specified in the /// STARTUPINFO structure passed to the CreateProcess function by the /// program that started the application. /// ShowDefault = 10, + /// /// Windows 2000/XP: Minimizes a window, even if the thread /// that owns the window is not responding. This flag should only be diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs index 8104a5dea..8ad288c68 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs @@ -31,9 +31,9 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum SoundFlags { - SND_ASYNC = 0x0001, // play asynchronously - SND_MEMORY = 0x0004, // pszSound points to a memory file - SND_NOSTOP = 0x0010, // don't stop any currently playing sound - SND_NOWAIT = 0x00002000, // don't wait if the driver is busy + SND_ASYNC = 0x0001, // play asynchronously + SND_MEMORY = 0x0004, // pszSound points to a memory file + SND_NOSTOP = 0x0010, // don't stop any currently playing sound + SND_NOWAIT = 0x00002000, // don't wait if the driver is busy } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs index fc5495304..50df23caa 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs @@ -24,7 +24,8 @@ using System; namespace GreenshotPlugin.UnmanagedHelpers.Enums { [Flags] - public enum ThreadAccess : int { + public enum ThreadAccess : int + { SUSPEND_RESUME = (0x0002), } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs index 987bc5654..be8ea2965 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs @@ -24,7 +24,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums /// /// A Win32 error code. /// - public enum Win32Error : uint { + public enum Win32Error : uint + { Success = 0x0, InvalidFunction = 0x1, FileNotFound = 0x2, diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs index a170af781..aaaf0e8e9 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.Diagnostics.CodeAnalysis; namespace GreenshotPlugin.UnmanagedHelpers.Enums @@ -27,7 +28,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums /// See MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/dd318066%28v=vs.85%29.aspx /// [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WinEvent : uint { + public enum WinEvent : uint + { EVENT_OBJECT_CREATE = 32768, EVENT_OBJECT_DESTROY = 32769, EVENT_OBJECT_NAMECHANGE = 32780, diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs index d71a3803e..6da1d01b8 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs @@ -26,7 +26,7 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum WindowLongIndex { - GWL_EXSTYLE = -20, // Sets a new extended window style. - GWL_STYLE = -16, // Sets a new window style. + GWL_EXSTYLE = -20, // Sets a new extended window style. + GWL_STYLE = -16, // Sets a new window style. } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs index ecdc92fe4..feb53a499 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs @@ -26,12 +26,15 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums { [Flags] [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowPlacementFlags : uint { + public enum WindowPlacementFlags : uint + { // The coordinates of the minimized window may be specified. // This flag must be specified if the coordinates are set in the ptMinPosition member. WPF_SETMINPOSITION = 0x0001, + // If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. WPF_ASYNCWINDOWPLACEMENT = 0x0004, + // The restored window will be maximized, regardless of whether it was maximized before it was minimized. This setting is only valid the next time the window is restored. It does not change the default restoration behavior. // This flag is only valid when the SW_SHOWMINIMIZED value is specified for the showCmd member. WPF_RESTORETOMAXIMIZED = 0x0002 diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs index d343962ae..a725e6baf 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs @@ -28,8 +28,9 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum WindowPos { - SWP_NOACTIVATE = 0x0010, // Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). - SWP_NOMOVE = 0x0002, //Retains the current position (ignores X and Y parameters). - SWP_NOSIZE = 0x0001, // Retains the current size (ignores the cx and cy parameters). + SWP_NOACTIVATE = + 0x0010, // Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). + SWP_NOMOVE = 0x0002, //Retains the current position (ignores X and Y parameters). + SWP_NOSIZE = 0x0001, // Retains the current size (ignores the cx and cy parameters). } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs index 48988c643..de33325d0 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs @@ -22,13 +22,15 @@ using System; using System.Diagnostics.CodeAnalysis; -namespace GreenshotPlugin.UnmanagedHelpers.Enums { - /// - /// Window Style Flags - /// - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowStyleFlags : long { - WS_VISIBLE = 0x10000000, - } -} +namespace GreenshotPlugin.UnmanagedHelpers.Enums +{ + /// + /// Window Style Flags + /// + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowStyleFlags : long + { + WS_VISIBLE = 0x10000000, + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs index 8029ccd30..d398fbdc3 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs @@ -13,7 +13,7 @@ namespace GreenshotPlugin.UnmanagedHelpers.Enums WM_INPUTLANGCHANGEREQUEST = 0x0050, WM_INPUTLANGCHANGE = 0x0051, - + /// /// Sent to a window to retrieve a handle to the large or small icon associated with a window. The system displays the large icon in the ALT+TAB dialog, and the small icon in the window caption. /// A window receives this message through its WindowProc function. diff --git a/src/GreenshotPlugin/UnmanagedHelpers/GDI32.cs b/src/GreenshotPlugin/UnmanagedHelpers/GDI32.cs index 0138d9faa..f2591a1d4 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/GDI32.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/GDI32.cs @@ -26,373 +26,400 @@ using System.Security; using GreenshotPlugin.UnmanagedHelpers.Enums; using Microsoft.Win32.SafeHandles; -namespace GreenshotPlugin.UnmanagedHelpers { - public static class GDIExtensions { - /// - /// Check if all the corners of the rectangle are visible in the specified region. - /// Not a perfect check, but this currently a workaround for checking if a window is completely visible - /// - /// - /// - /// - public static bool AreRectangleCornersVisisble(this Region region, Rectangle rectangle) { - Point topLeft = new Point(rectangle.X, rectangle.Y); - Point topRight = new Point(rectangle.X + rectangle.Width, rectangle.Y); - Point bottomLeft = new Point(rectangle.X, rectangle.Y + rectangle.Height); - Point bottomRight = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height); - bool topLeftVisible = region.IsVisible(topLeft); - bool topRightVisible = region.IsVisible(topRight); - bool bottomLeftVisible = region.IsVisible(bottomLeft); - bool bottomRightVisible = region.IsVisible(bottomRight); +namespace GreenshotPlugin.UnmanagedHelpers +{ + public static class GDIExtensions + { + /// + /// Check if all the corners of the rectangle are visible in the specified region. + /// Not a perfect check, but this currently a workaround for checking if a window is completely visible + /// + /// + /// + /// + public static bool AreRectangleCornersVisisble(this Region region, Rectangle rectangle) + { + Point topLeft = new Point(rectangle.X, rectangle.Y); + Point topRight = new Point(rectangle.X + rectangle.Width, rectangle.Y); + Point bottomLeft = new Point(rectangle.X, rectangle.Y + rectangle.Height); + Point bottomRight = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height); + bool topLeftVisible = region.IsVisible(topLeft); + bool topRightVisible = region.IsVisible(topRight); + bool bottomLeftVisible = region.IsVisible(bottomLeft); + bool bottomRightVisible = region.IsVisible(bottomRight); - return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible; - } + return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible; + } - /// - /// Get a SafeHandle for the GetHdc, so one can use using to automatically cleanup the devicecontext - /// - /// - /// SafeDeviceContextHandle - public static SafeDeviceContextHandle GetSafeDeviceContext(this Graphics graphics) { - return SafeDeviceContextHandle.FromGraphics(graphics); - } - } + /// + /// Get a SafeHandle for the GetHdc, so one can use using to automatically cleanup the devicecontext + /// + /// + /// SafeDeviceContextHandle + public static SafeDeviceContextHandle GetSafeDeviceContext(this Graphics graphics) + { + return SafeDeviceContextHandle.FromGraphics(graphics); + } + } - /// - /// Abstract class SafeObjectHandle which contains all handles that are cleaned with DeleteObject - /// - public abstract class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid { - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); + /// + /// Abstract class SafeObjectHandle which contains all handles that are cleaned with DeleteObject + /// + public abstract class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [DllImport("gdi32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteObject(IntPtr hObject); - protected SafeObjectHandle(bool ownsHandle) : base(ownsHandle) { - } + protected SafeObjectHandle(bool ownsHandle) : base(ownsHandle) + { + } - protected override bool ReleaseHandle() { - return DeleteObject(handle); - } - } + protected override bool ReleaseHandle() + { + return DeleteObject(handle); + } + } - /// - /// A hbitmap SafeHandle implementation - /// - public class SafeHBitmapHandle : SafeObjectHandle { + /// + /// A hbitmap SafeHandle implementation + /// + public class SafeHBitmapHandle : SafeObjectHandle + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeHBitmapHandle() : base(true) + { + } - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeHBitmapHandle() : base(true) - { - - } + [SecurityCritical] + public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + } - [SecurityCritical] - public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) { - SetHandle(preexistingHandle); - } - } + /// + /// A hRegion SafeHandle implementation + /// + public class SafeRegionHandle : SafeObjectHandle + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeRegionHandle() : base(true) + { + } - /// - /// A hRegion SafeHandle implementation - /// - public class SafeRegionHandle : SafeObjectHandle { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeRegionHandle() : base(true) - { - } + [SecurityCritical] + public SafeRegionHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + } - [SecurityCritical] - public SafeRegionHandle(IntPtr preexistingHandle) : base(true) { - SetHandle(preexistingHandle); - } - } + /// + /// A dibsection SafeHandle implementation + /// + public class SafeDibSectionHandle : SafeObjectHandle + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeDibSectionHandle() : base(true) + { + } - /// - /// A dibsection SafeHandle implementation - /// - public class SafeDibSectionHandle : SafeObjectHandle { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeDibSectionHandle() : base(true) - { - } + [SecurityCritical] + public SafeDibSectionHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + } - [SecurityCritical] - public SafeDibSectionHandle(IntPtr preexistingHandle) : base(true) { - SetHandle(preexistingHandle); - } - } + /// + /// A select object safehandle implementation + /// This impl will select the passed SafeHandle to the HDC and replace the returned value when disposing + /// + public class SafeSelectObjectHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [DllImport("gdi32", SetLastError = true)] + private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); - /// - /// A select object safehandle implementation - /// This impl will select the passed SafeHandle to the HDC and replace the returned value when disposing - /// - public class SafeSelectObjectHandle : SafeHandleZeroOrMinusOneIsInvalid { - [DllImport("gdi32", SetLastError = true)] - private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); + private readonly SafeHandle _hdc; - private readonly SafeHandle _hdc; - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeSelectObjectHandle() : base(true) - { - } + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeSelectObjectHandle() : base(true) + { + } - [SecurityCritical] - public SafeSelectObjectHandle(SafeDCHandle hdc, SafeHandle newHandle) : base(true) { - _hdc = hdc; - SetHandle(SelectObject(hdc.DangerousGetHandle(), newHandle.DangerousGetHandle())); - } + [SecurityCritical] + public SafeSelectObjectHandle(SafeDCHandle hdc, SafeHandle newHandle) : base(true) + { + _hdc = hdc; + SetHandle(SelectObject(hdc.DangerousGetHandle(), newHandle.DangerousGetHandle())); + } - protected override bool ReleaseHandle() { - SelectObject(_hdc.DangerousGetHandle(), handle); - return true; - } - } + protected override bool ReleaseHandle() + { + SelectObject(_hdc.DangerousGetHandle(), handle); + return true; + } + } - public abstract class SafeDCHandle : SafeHandleZeroOrMinusOneIsInvalid { - protected SafeDCHandle(bool ownsHandle) : base(ownsHandle) { - } - } - /// - /// A CompatibleDC SafeHandle implementation - /// - public class SafeCompatibleDCHandle : SafeDCHandle { - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteDC(IntPtr hDC); + public abstract class SafeDCHandle : SafeHandleZeroOrMinusOneIsInvalid + { + protected SafeDCHandle(bool ownsHandle) : base(ownsHandle) + { + } + } - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeCompatibleDCHandle() : base(true) - { - } + /// + /// A CompatibleDC SafeHandle implementation + /// + public class SafeCompatibleDCHandle : SafeDCHandle + { + [DllImport("gdi32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteDC(IntPtr hDC); - [SecurityCritical] - public SafeCompatibleDCHandle(IntPtr preexistingHandle) : base(true) { - SetHandle(preexistingHandle); - } + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeCompatibleDCHandle() : base(true) + { + } - public SafeSelectObjectHandle SelectObject(SafeHandle newHandle) { - return new SafeSelectObjectHandle(this, newHandle); - } + [SecurityCritical] + public SafeCompatibleDCHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } - protected override bool ReleaseHandle() { - return DeleteDC(handle); - } - } + public SafeSelectObjectHandle SelectObject(SafeHandle newHandle) + { + return new SafeSelectObjectHandle(this, newHandle); + } - /// - /// A DeviceContext SafeHandle implementation - /// - public class SafeDeviceContextHandle : SafeDCHandle { - private readonly Graphics _graphics; + protected override bool ReleaseHandle() + { + return DeleteDC(handle); + } + } - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeDeviceContextHandle() : base(true) - { - } + /// + /// A DeviceContext SafeHandle implementation + /// + public class SafeDeviceContextHandle : SafeDCHandle + { + private readonly Graphics _graphics; - [SecurityCritical] - public SafeDeviceContextHandle(Graphics graphics, IntPtr preexistingHandle) : base(true) { - _graphics = graphics; - SetHandle(preexistingHandle); - } + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeDeviceContextHandle() : base(true) + { + } - protected override bool ReleaseHandle() { - _graphics.ReleaseHdc(handle); - return true; - } + [SecurityCritical] + public SafeDeviceContextHandle(Graphics graphics, IntPtr preexistingHandle) : base(true) + { + _graphics = graphics; + SetHandle(preexistingHandle); + } - public static SafeDeviceContextHandle FromGraphics(Graphics graphics) { - return new SafeDeviceContextHandle(graphics, graphics.GetHdc()); - } - } - - /// - /// GDI32 Helpers - /// - public static class GDI32 { - [DllImport("gdi32", SetLastError=true)] - public static extern bool BitBlt(SafeHandle hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, SafeHandle hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop); + protected override bool ReleaseHandle() + { + _graphics.ReleaseHdc(handle); + return true; + } - [DllImport("gdi32", SetLastError=true)] - public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC); + public static SafeDeviceContextHandle FromGraphics(Graphics graphics) + { + return new SafeDeviceContextHandle(graphics, graphics.GetHdc()); + } + } - [DllImport("gdi32", SetLastError=true)] - public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADER bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset); - [DllImport("gdi32", SetLastError=true)] - public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); - [DllImport("gdi32", SetLastError=true)] - public static extern uint GetPixel(SafeHandle hdc, int nXPos, int nYPos); - [DllImport("gdi32", SetLastError=true)] - public static extern int GetDeviceCaps(SafeHandle hdc, DeviceCaps nIndex); - } + /// + /// GDI32 Helpers + /// + public static class GDI32 + { + [DllImport("gdi32", SetLastError = true)] + public static extern bool BitBlt(SafeHandle hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, SafeHandle hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop); - [StructLayout(LayoutKind.Sequential, Pack = 2)] - public struct BITMAPFILEHEADER { - public static readonly short BM = 0x4d42; // BM - public short bfType; - public int bfSize; - public short bfReserved1; - public short bfReserved2; - public int bfOffBits; - } + [DllImport("gdi32", SetLastError = true)] + public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC); - [StructLayout(LayoutKind.Sequential)] - public struct BitfieldColorMask { - public uint blue; - public uint green; - public uint red; - public void InitValues() { - red = (uint)255 << 8; - green = (uint)255 << 16; - blue = (uint)255 << 24; - } - } + [DllImport("gdi32", SetLastError = true)] + public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADER bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset); - [StructLayout(LayoutKind.Sequential)] - public struct CIEXYZ { - public uint ciexyzX; //FXPT2DOT30 - public uint ciexyzY; //FXPT2DOT30 - public uint ciexyzZ; //FXPT2DOT30 - public CIEXYZ(uint FXPT2DOT30) { - ciexyzX = FXPT2DOT30; - ciexyzY = FXPT2DOT30; - ciexyzZ = FXPT2DOT30; - } - } + [DllImport("gdi32", SetLastError = true)] + public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); - [StructLayout(LayoutKind.Sequential)] - public struct CIEXYZTRIPLE { - public CIEXYZ ciexyzRed; - public CIEXYZ ciexyzGreen; - public CIEXYZ ciexyzBlue; - } + [DllImport("gdi32", SetLastError = true)] + public static extern uint GetPixel(SafeHandle hdc, int nXPos, int nYPos); - public enum BI_COMPRESSION : uint { - BI_RGB = 0, // Uncompressed - BI_RLE8 = 1, // RLE 8BPP - BI_RLE4 = 2, // RLE 4BPP - BI_BITFIELDS = 3, // Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bpp bitmaps. - BI_JPEG = 4, // Indicates that the image is a JPEG image. - BI_PNG = 5 // Indicates that the image is a PNG image. - } + [DllImport("gdi32", SetLastError = true)] + public static extern int GetDeviceCaps(SafeHandle hdc, DeviceCaps nIndex); + } - [StructLayout(LayoutKind.Explicit)] - public struct BITMAPINFOHEADER { - [FieldOffset(0)] - public uint biSize; - [FieldOffset(4)] - public int biWidth; - [FieldOffset(8)] - public int biHeight; - [FieldOffset(12)] - public ushort biPlanes; - [FieldOffset(14)] - public ushort biBitCount; - [FieldOffset(16)] - public BI_COMPRESSION biCompression; - [FieldOffset(20)] - public uint biSizeImage; - [FieldOffset(24)] - public int biXPelsPerMeter; - [FieldOffset(28)] - public int biYPelsPerMeter; - [FieldOffset(32)] - public uint biClrUsed; - [FieldOffset(36)] - public uint biClrImportant; - [FieldOffset(40)] - public uint bV5RedMask; - [FieldOffset(44)] - public uint bV5GreenMask; - [FieldOffset(48)] - public uint bV5BlueMask; - [FieldOffset(52)] - public uint bV5AlphaMask; - [FieldOffset(56)] - public uint bV5CSType; - [FieldOffset(60)] - public CIEXYZTRIPLE bV5Endpoints; - [FieldOffset(96)] - public uint bV5GammaRed; - [FieldOffset(100)] - public uint bV5GammaGreen; - [FieldOffset(104)] - public uint bV5GammaBlue; - [FieldOffset(108)] - public uint bV5Intent; // Rendering intent for bitmap - [FieldOffset(112)] - public uint bV5ProfileData; - [FieldOffset(116)] - public uint bV5ProfileSize; - [FieldOffset(120)] - public uint bV5Reserved; + [StructLayout(LayoutKind.Sequential, Pack = 2)] + public struct BITMAPFILEHEADER + { + public static readonly short BM = 0x4d42; // BM + public short bfType; + public int bfSize; + public short bfReserved1; + public short bfReserved2; + public int bfOffBits; + } - public const int DIB_RGB_COLORS = 0; + [StructLayout(LayoutKind.Sequential)] + public struct BitfieldColorMask + { + public uint blue; + public uint green; + public uint red; - public BITMAPINFOHEADER(int width, int height, ushort bpp) { - biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV5 is 40 bytes - biPlanes = 1; // Should allways be 1 - biCompression = BI_COMPRESSION.BI_RGB; - biWidth = width; - biHeight = height; - biBitCount = bpp; - biSizeImage = (uint)(width*height*(bpp>>3)); - biXPelsPerMeter = 0; - biYPelsPerMeter = 0; - biClrUsed = 0; - biClrImportant = 0; + public void InitValues() + { + red = (uint) 255 << 8; + green = (uint) 255 << 16; + blue = (uint) 255 << 24; + } + } - // V5 - bV5RedMask = (uint)255 << 16; - bV5GreenMask = (uint)255 << 8; - bV5BlueMask = 255; - bV5AlphaMask = (uint)255 << 24; - bV5CSType = 0x73524742; // LCS_sRGB - bV5Endpoints = new CIEXYZTRIPLE - { - ciexyzBlue = new CIEXYZ(0), - ciexyzGreen = new CIEXYZ(0), - ciexyzRed = new CIEXYZ(0) - }; - bV5GammaRed = 0; - bV5GammaGreen = 0; - bV5GammaBlue = 0; - bV5Intent = 4; - bV5ProfileData = 0; - bV5ProfileSize = 0; - bV5Reserved = 0; - } - public bool IsDibV5 { - get { - uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); - return biSize >= sizeOfBMI; - } - } - public uint OffsetToPixels { - get { - if (biCompression == BI_COMPRESSION.BI_BITFIELDS) { - // Add 3x4 bytes for the bitfield color mask - return biSize + 3 * 4; - } - return biSize; - } - } - } -} + [StructLayout(LayoutKind.Sequential)] + public struct CIEXYZ + { + public uint ciexyzX; //FXPT2DOT30 + public uint ciexyzY; //FXPT2DOT30 + public uint ciexyzZ; //FXPT2DOT30 + + public CIEXYZ(uint FXPT2DOT30) + { + ciexyzX = FXPT2DOT30; + ciexyzY = FXPT2DOT30; + ciexyzZ = FXPT2DOT30; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct CIEXYZTRIPLE + { + public CIEXYZ ciexyzRed; + public CIEXYZ ciexyzGreen; + public CIEXYZ ciexyzBlue; + } + + public enum BI_COMPRESSION : uint + { + BI_RGB = 0, // Uncompressed + BI_RLE8 = 1, // RLE 8BPP + BI_RLE4 = 2, // RLE 4BPP + + BI_BITFIELDS = + 3, // Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bpp bitmaps. + BI_JPEG = 4, // Indicates that the image is a JPEG image. + BI_PNG = 5 // Indicates that the image is a PNG image. + } + + [StructLayout(LayoutKind.Explicit)] + public struct BITMAPINFOHEADER + { + [FieldOffset(0)] public uint biSize; + [FieldOffset(4)] public int biWidth; + [FieldOffset(8)] public int biHeight; + [FieldOffset(12)] public ushort biPlanes; + [FieldOffset(14)] public ushort biBitCount; + [FieldOffset(16)] public BI_COMPRESSION biCompression; + [FieldOffset(20)] public uint biSizeImage; + [FieldOffset(24)] public int biXPelsPerMeter; + [FieldOffset(28)] public int biYPelsPerMeter; + [FieldOffset(32)] public uint biClrUsed; + [FieldOffset(36)] public uint biClrImportant; + [FieldOffset(40)] public uint bV5RedMask; + [FieldOffset(44)] public uint bV5GreenMask; + [FieldOffset(48)] public uint bV5BlueMask; + [FieldOffset(52)] public uint bV5AlphaMask; + [FieldOffset(56)] public uint bV5CSType; + [FieldOffset(60)] public CIEXYZTRIPLE bV5Endpoints; + [FieldOffset(96)] public uint bV5GammaRed; + [FieldOffset(100)] public uint bV5GammaGreen; + [FieldOffset(104)] public uint bV5GammaBlue; + [FieldOffset(108)] public uint bV5Intent; // Rendering intent for bitmap + [FieldOffset(112)] public uint bV5ProfileData; + [FieldOffset(116)] public uint bV5ProfileSize; + [FieldOffset(120)] public uint bV5Reserved; + + public const int DIB_RGB_COLORS = 0; + + public BITMAPINFOHEADER(int width, int height, ushort bpp) + { + biSize = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV5 is 40 bytes + biPlanes = 1; // Should allways be 1 + biCompression = BI_COMPRESSION.BI_RGB; + biWidth = width; + biHeight = height; + biBitCount = bpp; + biSizeImage = (uint) (width * height * (bpp >> 3)); + biXPelsPerMeter = 0; + biYPelsPerMeter = 0; + biClrUsed = 0; + biClrImportant = 0; + + // V5 + bV5RedMask = (uint) 255 << 16; + bV5GreenMask = (uint) 255 << 8; + bV5BlueMask = 255; + bV5AlphaMask = (uint) 255 << 24; + bV5CSType = 0x73524742; // LCS_sRGB + bV5Endpoints = new CIEXYZTRIPLE + { + ciexyzBlue = new CIEXYZ(0), + ciexyzGreen = new CIEXYZ(0), + ciexyzRed = new CIEXYZ(0) + }; + bV5GammaRed = 0; + bV5GammaGreen = 0; + bV5GammaBlue = 0; + bV5Intent = 4; + bV5ProfileData = 0; + bV5ProfileSize = 0; + bV5Reserved = 0; + } + + public bool IsDibV5 + { + get + { + uint sizeOfBMI = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADER)); + return biSize >= sizeOfBMI; + } + } + + public uint OffsetToPixels + { + get + { + if (biCompression == BI_COMPRESSION.BI_BITFIELDS) + { + // Add 3x4 bytes for the bitfield color mask + return biSize + 3 * 4; + } + + return biSize; + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs b/src/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs index c8caf7700..6da5b3850 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs @@ -18,6 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Runtime.InteropServices; @@ -27,303 +28,360 @@ using System.Drawing.Drawing2D; using System.Drawing.Imaging; using GreenshotPlugin.UnmanagedHelpers.Structs; -namespace GreenshotPlugin.UnmanagedHelpers { - /// - /// Contains members that specify the nature of a Gaussian blur. - /// - /// Cannot be pinned with GCHandle due to bool value. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct BlurParams { - /// - /// Real number that specifies the blur radius (the radius of the Gaussian convolution kernel) in - /// pixels. The radius must be in the range 0 through 255. As the radius increases, the resulting - /// bitmap becomes more blurry. - /// - public float Radius; +namespace GreenshotPlugin.UnmanagedHelpers +{ + /// + /// Contains members that specify the nature of a Gaussian blur. + /// + /// Cannot be pinned with GCHandle due to bool value. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct BlurParams + { + /// + /// Real number that specifies the blur radius (the radius of the Gaussian convolution kernel) in + /// pixels. The radius must be in the range 0 through 255. As the radius increases, the resulting + /// bitmap becomes more blurry. + /// + public float Radius; - /// - /// Boolean value that specifies whether the bitmap expands by an amount equal to the blur radius. - /// If TRUE, the bitmap expands by an amount equal to the radius so that it can have soft edges. - /// If FALSE, the bitmap remains the same size and the soft edges are clipped. - /// - public bool ExpandEdges; - } + /// + /// Boolean value that specifies whether the bitmap expands by an amount equal to the blur radius. + /// If TRUE, the bitmap expands by an amount equal to the radius so that it can have soft edges. + /// If FALSE, the bitmap remains the same size and the soft edges are clipped. + /// + public bool ExpandEdges; + } - /// - /// GDI Plus unit description. - /// - public enum GpUnit { - /// - /// World coordinate (non-physical unit). - /// - UnitWorld, + /// + /// GDI Plus unit description. + /// + public enum GpUnit + { + /// + /// World coordinate (non-physical unit). + /// + UnitWorld, - /// - /// Variable - for PageTransform only. - /// - UnitDisplay, + /// + /// Variable - for PageTransform only. + /// + UnitDisplay, - /// - /// Each unit is one device pixel. - /// - UnitPixel, + /// + /// Each unit is one device pixel. + /// + UnitPixel, - /// - /// Each unit is a printer's point, or 1/72 inch. - /// - UnitPoint, + /// + /// Each unit is a printer's point, or 1/72 inch. + /// + UnitPoint, - /// - /// Each unit is 1 inch. - /// - UnitInch, + /// + /// Each unit is 1 inch. + /// + UnitInch, - /// - /// Each unit is 1/300 inch. - /// - UnitDocument, + /// + /// Each unit is 1/300 inch. + /// + UnitDocument, - /// - /// Each unit is 1 millimeter. - /// - UnitMillimeter - } + /// + /// Each unit is 1 millimeter. + /// + UnitMillimeter + } - /// - /// GDIplus Helpers - /// - public static class GDIplus { - private static readonly ILog Log = LogManager.GetLogger(typeof(GDIplus)); + /// + /// GDIplus Helpers + /// + public static class GDIplus + { + private static readonly ILog Log = LogManager.GetLogger(typeof(GDIplus)); - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipBitmapApplyEffect(IntPtr bitmap, IntPtr effect, ref RECT rectOfInterest, bool useAuxData, IntPtr auxData, int auxDataSize); + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipBitmapApplyEffect(IntPtr bitmap, IntPtr effect, ref RECT rectOfInterest, bool useAuxData, IntPtr auxData, int auxDataSize); - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipDrawImageFX(IntPtr graphics, IntPtr bitmap, ref RECTF source, IntPtr matrix, IntPtr effect, IntPtr imageAttributes, GpUnit srcUnit); - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipSetEffectParameters(IntPtr effect, IntPtr parameters, uint size); - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipCreateEffect(Guid guid, out IntPtr effect); - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipDeleteEffect(IntPtr effect); - private static readonly Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}"); + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipDrawImageFX(IntPtr graphics, IntPtr bitmap, ref RECTF source, IntPtr matrix, IntPtr effect, IntPtr imageAttributes, GpUnit srcUnit); - // Constant "FieldInfo" for getting the nativeImage from the Bitmap - private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGE = typeof(Bitmap).GetField("nativeImage", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - // Constant "FieldInfo" for getting the NativeGraphics from the Graphics - private static readonly FieldInfo FIELD_INFO_NATIVE_GRAPHICS = typeof(Graphics).GetField("nativeGraphics", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - // Constant "FieldInfo" for getting the nativeMatrix from the Matrix - private static readonly FieldInfo FIELD_INFO_NATIVE_MATRIX = typeof(Matrix).GetField("nativeMatrix", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - // Constant "FieldInfo" for getting the nativeImageAttributes from the ImageAttributes - private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGEATTRIBUTES = typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipSetEffectParameters(IntPtr effect, IntPtr parameters, uint size); - private static bool _isBlurEnabled = Environment.OSVersion.Version.Major >= 6; - /// - /// Get the nativeImage field from the bitmap - /// - /// - /// IntPtr - private static IntPtr GetNativeImage(Bitmap bitmap) { - if (bitmap == null) { - return IntPtr.Zero; - } - return (IntPtr)FIELD_INFO_NATIVE_IMAGE.GetValue(bitmap); - } + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipCreateEffect(Guid guid, out IntPtr effect); - /// - /// Get the NativeGraphics field from the graphics - /// - /// - /// IntPtr - private static IntPtr GetNativeGraphics(Graphics graphics) { - if (graphics == null) { - return IntPtr.Zero; - } - return (IntPtr)FIELD_INFO_NATIVE_GRAPHICS.GetValue(graphics); - } + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipDeleteEffect(IntPtr effect); - /// - /// Get the nativeMatrix field from the matrix - /// - /// - /// IntPtr - private static IntPtr GetNativeMatrix(Matrix matrix) { - if (matrix == null) { - return IntPtr.Zero; - } - return (IntPtr)FIELD_INFO_NATIVE_MATRIX.GetValue(matrix); - } + private static readonly Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}"); - /// - /// Get the nativeImageAttributes field from the ImageAttributes - /// - /// - /// IntPtr - private static IntPtr GetNativeImageAttributes(ImageAttributes imageAttributes) { - if (imageAttributes == null) { - return IntPtr.Zero; - } - return (IntPtr)FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes); - } + // Constant "FieldInfo" for getting the nativeImage from the Bitmap + private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGE = typeof(Bitmap).GetField("nativeImage", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - /// - /// Returns if a GDIPlus blur can be made for the supplied radius. - /// This accounts for the "bug" I reported here: http://social.technet.microsoft.com/Forums/en/w8itprogeneral/thread/99ddbe9d-556d-475a-8bab-84e25aa13a2c - /// - /// - /// false if blur is not possible - public static bool IsBlurPossible(int radius) - { - if (!_isBlurEnabled) { - return false; - } - if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2) - { - return true; - } - return Environment.OSVersion.Version.Major > 6 && radius >= 20; - } + // Constant "FieldInfo" for getting the NativeGraphics from the Graphics + private static readonly FieldInfo FIELD_INFO_NATIVE_GRAPHICS = + typeof(Graphics).GetField("nativeGraphics", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - /// - /// Use the GDI+ blur effect on the bitmap - /// - /// Bitmap to apply the effect to - /// Rectangle to apply the blur effect to - /// 0-255 - /// bool true if the edges are expanded with the radius - /// false if there is no GDI+ available or an exception occured - public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, int radius, bool expandEdges) { - if (!IsBlurPossible(radius)) { - return false; - } - IntPtr hBlurParams = IntPtr.Zero; - IntPtr hEffect = IntPtr.Zero; + // Constant "FieldInfo" for getting the nativeMatrix from the Matrix + private static readonly FieldInfo FIELD_INFO_NATIVE_MATRIX = + typeof(Matrix).GetField("nativeMatrix", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - try { - // Create the GDI+ BlurEffect, using the Guid - int status = GdipCreateEffect(BlurEffectGuid, out hEffect); - if (status != 0) - { - return false; - } - // Create a BlurParams struct and set the values - var blurParams = new BlurParams - { - Radius = radius, - ExpandEdges = expandEdges - }; + // Constant "FieldInfo" for getting the nativeImageAttributes from the ImageAttributes + private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGEATTRIBUTES = + typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - // Allocate space in unmanaged memory - hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); - // Copy the structure to the unmanaged memory - Marshal.StructureToPtr(blurParams, hBlurParams, false); + private static bool _isBlurEnabled = Environment.OSVersion.Version.Major >= 6; + + /// + /// Get the nativeImage field from the bitmap + /// + /// + /// IntPtr + private static IntPtr GetNativeImage(Bitmap bitmap) + { + if (bitmap == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_IMAGE.GetValue(bitmap); + } + + /// + /// Get the NativeGraphics field from the graphics + /// + /// + /// IntPtr + private static IntPtr GetNativeGraphics(Graphics graphics) + { + if (graphics == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_GRAPHICS.GetValue(graphics); + } + + /// + /// Get the nativeMatrix field from the matrix + /// + /// + /// IntPtr + private static IntPtr GetNativeMatrix(Matrix matrix) + { + if (matrix == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_MATRIX.GetValue(matrix); + } + + /// + /// Get the nativeImageAttributes field from the ImageAttributes + /// + /// + /// IntPtr + private static IntPtr GetNativeImageAttributes(ImageAttributes imageAttributes) + { + if (imageAttributes == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes); + } + + /// + /// Returns if a GDIPlus blur can be made for the supplied radius. + /// This accounts for the "bug" I reported here: http://social.technet.microsoft.com/Forums/en/w8itprogeneral/thread/99ddbe9d-556d-475a-8bab-84e25aa13a2c + /// + /// + /// false if blur is not possible + public static bool IsBlurPossible(int radius) + { + if (!_isBlurEnabled) + { + return false; + } + + if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2) + { + return true; + } + + return Environment.OSVersion.Version.Major > 6 && radius >= 20; + } + + /// + /// Use the GDI+ blur effect on the bitmap + /// + /// Bitmap to apply the effect to + /// Rectangle to apply the blur effect to + /// 0-255 + /// bool true if the edges are expanded with the radius + /// false if there is no GDI+ available or an exception occured + public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, int radius, bool expandEdges) + { + if (!IsBlurPossible(radius)) + { + return false; + } + + IntPtr hBlurParams = IntPtr.Zero; + IntPtr hEffect = IntPtr.Zero; + + try + { + // Create the GDI+ BlurEffect, using the Guid + int status = GdipCreateEffect(BlurEffectGuid, out hEffect); + if (status != 0) + { + return false; + } + + // Create a BlurParams struct and set the values + var blurParams = new BlurParams + { + Radius = radius, + ExpandEdges = expandEdges + }; + + // Allocate space in unmanaged memory + hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); + // Copy the structure to the unmanaged memory + Marshal.StructureToPtr(blurParams, hBlurParams, false); - // Set the blurParams to the effect - GdipSetEffectParameters(hEffect, hBlurParams, (uint)Marshal.SizeOf(blurParams)); + // Set the blurParams to the effect + GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams)); - // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! - // Get the private nativeImage property from the Bitmap - IntPtr hBitmap = GetNativeImage(destinationBitmap); + // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! + // Get the private nativeImage property from the Bitmap + IntPtr hBitmap = GetNativeImage(destinationBitmap); - // Create a RECT from the Rectangle - RECT rec = new RECT(area); - // Apply the effect to the bitmap in the specified area - GdipBitmapApplyEffect(hBitmap, hEffect, ref rec, false, IntPtr.Zero, 0); + // Create a RECT from the Rectangle + RECT rec = new RECT(area); + // Apply the effect to the bitmap in the specified area + GdipBitmapApplyEffect(hBitmap, hEffect, ref rec, false, IntPtr.Zero, 0); - // Everything worked, return true - return true; - } catch (Exception ex) { - _isBlurEnabled = false; - Log.Error("Problem using GdipBitmapApplyEffect: ", ex); - return false; - } finally { - try { - if (hEffect != IntPtr.Zero) { - // Delete the effect - GdipDeleteEffect(hEffect); - } - if (hBlurParams != IntPtr.Zero) { - // Free the memory - Marshal.FreeHGlobal(hBlurParams); - } - } catch (Exception ex) { - _isBlurEnabled = false; - Log.Error("Problem cleaning up ApplyBlur: ", ex); - } - } - } + // Everything worked, return true + return true; + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem using GdipBitmapApplyEffect: ", ex); + return false; + } + finally + { + try + { + if (hEffect != IntPtr.Zero) + { + // Delete the effect + GdipDeleteEffect(hEffect); + } - /// - /// Draw the image on the graphics with GDI+ blur effect - /// - /// false if there is no GDI+ available or an exception occured - public static bool DrawWithBlur(Graphics graphics, Bitmap image, Rectangle source, Matrix transform, ImageAttributes imageAttributes, int radius, bool expandEdges) { - if (!IsBlurPossible(radius)) { - return false; - } + if (hBlurParams != IntPtr.Zero) + { + // Free the memory + Marshal.FreeHGlobal(hBlurParams); + } + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem cleaning up ApplyBlur: ", ex); + } + } + } - IntPtr hBlurParams = IntPtr.Zero; - IntPtr hEffect = IntPtr.Zero; + /// + /// Draw the image on the graphics with GDI+ blur effect + /// + /// false if there is no GDI+ available or an exception occured + public static bool DrawWithBlur(Graphics graphics, Bitmap image, Rectangle source, Matrix transform, ImageAttributes imageAttributes, int radius, bool expandEdges) + { + if (!IsBlurPossible(radius)) + { + return false; + } - try { - // Create the GDI+ BlurEffect, using the Guid - int status = GdipCreateEffect(BlurEffectGuid, out hEffect); - if (status != 0) - { - return false; - } + IntPtr hBlurParams = IntPtr.Zero; + IntPtr hEffect = IntPtr.Zero; - // Create a BlurParams struct and set the values - var blurParams = new BlurParams - { - Radius = radius, - ExpandEdges = false - }; - //blurParams.Padding = radius; + try + { + // Create the GDI+ BlurEffect, using the Guid + int status = GdipCreateEffect(BlurEffectGuid, out hEffect); + if (status != 0) + { + return false; + } - // Allocate space in unmanaged memory - hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); - // Copy the structure to the unmanaged memory - Marshal.StructureToPtr(blurParams, hBlurParams, true); + // Create a BlurParams struct and set the values + var blurParams = new BlurParams + { + Radius = radius, + ExpandEdges = false + }; + //blurParams.Padding = radius; - // Set the blurParams to the effect - GdipSetEffectParameters(hEffect, hBlurParams, (uint)Marshal.SizeOf(blurParams)); + // Allocate space in unmanaged memory + hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); + // Copy the structure to the unmanaged memory + Marshal.StructureToPtr(blurParams, hBlurParams, true); - // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! - // Get the private nativeImage property from the Bitmap - IntPtr hBitmap = GetNativeImage(image); - IntPtr hGraphics = GetNativeGraphics(graphics); - IntPtr hMatrix = GetNativeMatrix(transform); - IntPtr hAttributes = GetNativeImageAttributes(imageAttributes); + // Set the blurParams to the effect + GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams)); - // Create a RECT from the Rectangle - RECTF sourceRecf = new RECTF(source); - // Apply the effect to the bitmap in the specified area - GdipDrawImageFX(hGraphics, hBitmap, ref sourceRecf, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel); + // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! + // Get the private nativeImage property from the Bitmap + IntPtr hBitmap = GetNativeImage(image); + IntPtr hGraphics = GetNativeGraphics(graphics); + IntPtr hMatrix = GetNativeMatrix(transform); + IntPtr hAttributes = GetNativeImageAttributes(imageAttributes); - // Everything worked, return true - return true; - } catch (Exception ex) { - _isBlurEnabled = false; - Log.Error("Problem using GdipDrawImageFX: ", ex); - return false; - } finally { - try { - if (hEffect != IntPtr.Zero) { - // Delete the effect - GdipDeleteEffect(hEffect); - } - if (hBlurParams != IntPtr.Zero) { - // Free the memory - Marshal.FreeHGlobal(hBlurParams); - } - } catch (Exception ex) { - _isBlurEnabled = false; - Log.Error("Problem cleaning up DrawWithBlur: ", ex); - } - } - } + // Create a RECT from the Rectangle + RECTF sourceRecf = new RECTF(source); + // Apply the effect to the bitmap in the specified area + GdipDrawImageFX(hGraphics, hBitmap, ref sourceRecf, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel); - } -} + // Everything worked, return true + return true; + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem using GdipDrawImageFX: ", ex); + return false; + } + finally + { + try + { + if (hEffect != IntPtr.Zero) + { + // Delete the effect + GdipDeleteEffect(hEffect); + } + + if (hBlurParams != IntPtr.Zero) + { + // Free the memory + Marshal.FreeHGlobal(hBlurParams); + } + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem cleaning up DrawWithBlur: ", ex); + } + } + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs b/src/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs index 101d74bbf..df512ee08 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs @@ -18,91 +18,114 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Runtime.InteropServices; using System.Text; using GreenshotPlugin.UnmanagedHelpers.Enums; -namespace GreenshotPlugin.UnmanagedHelpers { +namespace GreenshotPlugin.UnmanagedHelpers +{ /// - /// Description of Kernel32. - /// - public class Kernel32 { - public const uint ATTACHCONSOLE_ATTACHPARENTPROCESS = 0x0ffffffff; // default value if not specifing a process ID - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool AttachConsole(uint dwProcessId); - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool AllocConsole(); - - [DllImport("kernel32", SetLastError = true)] - public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); - [DllImport("kernel32", SetLastError = true)] - public static extern uint SuspendThread(IntPtr hThread); - [DllImport("kernel32", SetLastError = true)] - public static extern int ResumeThread(IntPtr hThread); - [DllImport("kernel32", SetLastError = true)] - public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId); - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize); - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, uint uuchMax); + /// Description of Kernel32. + /// + public class Kernel32 + { + public const uint ATTACHCONSOLE_ATTACHPARENTPROCESS = 0x0ffffffff; // default value if not specifing a process ID [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CloseHandle(IntPtr hObject); + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AttachConsole(uint dwProcessId); - /// - /// Method to get the process path - /// - /// - /// - public static string GetProcessPath(int processid) { - StringBuilder _PathBuffer = new StringBuilder(512); - // Try the GetModuleFileName method first since it's the fastest. - // May return ACCESS_DENIED (due to VM_READ flag) if the process is not owned by the current user. - // Will fail if we are compiled as x86 and we're trying to open a 64 bit process...not allowed. - IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead, false, processid); - if (hprocess != IntPtr.Zero) { - try { - if (PsAPI.GetModuleFileNameEx(hprocess, IntPtr.Zero, _PathBuffer, (uint)_PathBuffer.Capacity) > 0) { - return _PathBuffer.ToString(); - } - } finally { - CloseHandle(hprocess); - } - } + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AllocConsole(); - hprocess = OpenProcess(ProcessAccessFlags.QueryInformation, false, processid); - if (hprocess != IntPtr.Zero) { - try { - // Try this method for Vista or higher operating systems - uint size = (uint)_PathBuffer.Capacity; - if ((Environment.OSVersion.Version.Major >= 6) && (QueryFullProcessImageName(hprocess, 0, _PathBuffer, ref size) && (size > 0))) { - return _PathBuffer.ToString(); - } + [DllImport("kernel32", SetLastError = true)] + public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); - // Try the GetProcessImageFileName method - if (PsAPI.GetProcessImageFileName(hprocess, _PathBuffer, (uint)_PathBuffer.Capacity) > 0) { - string dospath = _PathBuffer.ToString(); - foreach (string drive in Environment.GetLogicalDrives()) { - if (QueryDosDevice(drive.TrimEnd('\\'), _PathBuffer, (uint)_PathBuffer.Capacity) > 0) { - if (dospath.StartsWith(_PathBuffer.ToString())) { - return drive + dospath.Remove(0, _PathBuffer.Length); - } - } - } - } - } finally { - CloseHandle(hprocess); - } - } + [DllImport("kernel32", SetLastError = true)] + public static extern uint SuspendThread(IntPtr hThread); - return string.Empty; - } - } -} + [DllImport("kernel32", SetLastError = true)] + public static extern int ResumeThread(IntPtr hThread); + + [DllImport("kernel32", SetLastError = true)] + public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, uint uuchMax); + + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseHandle(IntPtr hObject); + + /// + /// Method to get the process path + /// + /// + /// + public static string GetProcessPath(int processid) + { + StringBuilder _PathBuffer = new StringBuilder(512); + // Try the GetModuleFileName method first since it's the fastest. + // May return ACCESS_DENIED (due to VM_READ flag) if the process is not owned by the current user. + // Will fail if we are compiled as x86 and we're trying to open a 64 bit process...not allowed. + IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead, false, processid); + if (hprocess != IntPtr.Zero) + { + try + { + if (PsAPI.GetModuleFileNameEx(hprocess, IntPtr.Zero, _PathBuffer, (uint) _PathBuffer.Capacity) > 0) + { + return _PathBuffer.ToString(); + } + } + finally + { + CloseHandle(hprocess); + } + } + + hprocess = OpenProcess(ProcessAccessFlags.QueryInformation, false, processid); + if (hprocess != IntPtr.Zero) + { + try + { + // Try this method for Vista or higher operating systems + uint size = (uint) _PathBuffer.Capacity; + if ((Environment.OSVersion.Version.Major >= 6) && (QueryFullProcessImageName(hprocess, 0, _PathBuffer, ref size) && (size > 0))) + { + return _PathBuffer.ToString(); + } + + // Try the GetProcessImageFileName method + if (PsAPI.GetProcessImageFileName(hprocess, _PathBuffer, (uint) _PathBuffer.Capacity) > 0) + { + string dospath = _PathBuffer.ToString(); + foreach (string drive in Environment.GetLogicalDrives()) + { + if (QueryDosDevice(drive.TrimEnd('\\'), _PathBuffer, (uint) _PathBuffer.Capacity) > 0) + { + if (dospath.StartsWith(_PathBuffer.ToString())) + { + return drive + dospath.Remove(0, _PathBuffer.Length); + } + } + } + } + } + finally + { + CloseHandle(hprocess); + } + } + + return string.Empty; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs b/src/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs index 8b77f8d97..67bc5f764 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs @@ -18,32 +18,39 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; using log4net; -namespace GreenshotPlugin.UnmanagedHelpers { - /// - /// Description of PsAPI. - /// - public class PsAPI { - private static readonly ILog LOG = LogManager.GetLogger(typeof(PsAPI)); - [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize); - [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint GetProcessImageFileName(IntPtr hProcess, StringBuilder lpImageFileName, uint nSize); - [DllImport("psapi")] - private static extern int EmptyWorkingSet(IntPtr hwProc); +namespace GreenshotPlugin.UnmanagedHelpers +{ + /// + /// Description of PsAPI. + /// + public class PsAPI + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(PsAPI)); - /// - /// Make the process use less memory by emptying the working set - /// - public static void EmptyWorkingSet() { - LOG.Info("Calling EmptyWorkingSet"); + [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize); + + [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint GetProcessImageFileName(IntPtr hProcess, StringBuilder lpImageFileName, uint nSize); + + [DllImport("psapi")] + private static extern int EmptyWorkingSet(IntPtr hwProc); + + /// + /// Make the process use less memory by emptying the working set + /// + public static void EmptyWorkingSet() + { + LOG.Info("Calling EmptyWorkingSet"); using Process currentProcess = Process.GetCurrentProcess(); EmptyWorkingSet(currentProcess.Handle); } - } -} + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs b/src/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs index 6a4d02617..f1178a424 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs @@ -9,27 +9,36 @@ namespace GreenshotPlugin.UnmanagedHelpers /// /// A SafeHandle class implementation for the current input desktop /// - public class SafeCurrentInputDesktopHandle : SafeHandleZeroOrMinusOneIsInvalid { + public class SafeCurrentInputDesktopHandle : SafeHandleZeroOrMinusOneIsInvalid + { private static readonly ILog LOG = LogManager.GetLogger(typeof(SafeCurrentInputDesktopHandle)); - public SafeCurrentInputDesktopHandle() : base(true) { + public SafeCurrentInputDesktopHandle() : base(true) + { IntPtr hDesktop = User32.OpenInputDesktop(0, true, DesktopAccessRight.GENERIC_ALL); - if (hDesktop != IntPtr.Zero) { + if (hDesktop != IntPtr.Zero) + { SetHandle(hDesktop); - if (User32.SetThreadDesktop(hDesktop)) { + if (User32.SetThreadDesktop(hDesktop)) + { LOG.DebugFormat("Switched to desktop {0}", hDesktop); - } else { + } + else + { LOG.WarnFormat("Couldn't switch to desktop {0}", hDesktop); LOG.Error(User32.CreateWin32Exception("SetThreadDesktop")); } - } else { + } + else + { LOG.Warn("Couldn't get current desktop."); LOG.Error(User32.CreateWin32Exception("OpenInputDesktop")); } } [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - protected override bool ReleaseHandle() { + protected override bool ReleaseHandle() + { return User32.CloseDesktop(handle); } } diff --git a/src/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs b/src/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs index dbd3ef2a3..50f6a4369 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs @@ -8,8 +8,8 @@ namespace GreenshotPlugin.UnmanagedHelpers /// /// A SafeHandle class implementation for the hIcon /// - public class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid { - + public class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid + { /// /// Needed for marshalling return values /// @@ -19,12 +19,14 @@ namespace GreenshotPlugin.UnmanagedHelpers } - public SafeIconHandle(IntPtr hIcon) : base(true) { + public SafeIconHandle(IntPtr hIcon) : base(true) + { SetHandle(hIcon); } [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - protected override bool ReleaseHandle() { + protected override bool ReleaseHandle() + { return User32.DestroyIcon(handle); } } diff --git a/src/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs b/src/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs index d9371ee4b..671c07a3f 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs @@ -9,9 +9,11 @@ namespace GreenshotPlugin.UnmanagedHelpers /// /// A WindowDC SafeHandle implementation /// - public class SafeWindowDcHandle : SafeHandleZeroOrMinusOneIsInvalid { + public class SafeWindowDcHandle : SafeHandleZeroOrMinusOneIsInvalid + { [DllImport("user32", SetLastError = true)] private static extern IntPtr GetWindowDC(IntPtr hWnd); + [DllImport("user32", SetLastError = true)] private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); @@ -25,13 +27,15 @@ namespace GreenshotPlugin.UnmanagedHelpers } [SecurityCritical] - public SafeWindowDcHandle(IntPtr hWnd, IntPtr preexistingHandle) : base(true) { + public SafeWindowDcHandle(IntPtr hWnd, IntPtr preexistingHandle) : base(true) + { _hWnd = hWnd; SetHandle(preexistingHandle); } - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)] - protected override bool ReleaseHandle() { + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] + protected override bool ReleaseHandle() + { bool returnValue = ReleaseDC(_hWnd, handle); return returnValue; } @@ -47,11 +51,13 @@ namespace GreenshotPlugin.UnmanagedHelpers { return null; } + var hDcDesktop = GetWindowDC(hWnd); return new SafeWindowDcHandle(hWnd, hDcDesktop); } - public static SafeWindowDcHandle FromDesktop() { + public static SafeWindowDcHandle FromDesktop() + { IntPtr hWndDesktop = User32.GetDesktopWindow(); IntPtr hDCDesktop = GetWindowDC(hWndDesktop); return new SafeWindowDcHandle(hWndDesktop, hDCDesktop); diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Shell32.cs b/src/GreenshotPlugin/UnmanagedHelpers/Shell32.cs index f16d46cec..a1eb7e890 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Shell32.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Shell32.cs @@ -18,91 +18,106 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Drawing; using System.Runtime.InteropServices; using System.IO; -namespace GreenshotPlugin.UnmanagedHelpers { - /// - /// Description of Shell32. - /// - public static class Shell32 { - [DllImport("shell32", CharSet = CharSet.Unicode)] - public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons); +namespace GreenshotPlugin.UnmanagedHelpers +{ + /// + /// Description of Shell32. + /// + public static class Shell32 + { + [DllImport("shell32", CharSet = CharSet.Unicode)] + public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons); [DllImport("shell32", CharSet = CharSet.Unicode)] - private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); + private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); - [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] - private struct SHFILEINFO { - public readonly IntPtr hIcon; - public readonly int iIcon; - public readonly uint dwAttributes; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public readonly string szDisplayName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] - public readonly string szTypeName; - }; + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct SHFILEINFO + { + public readonly IntPtr hIcon; + public readonly int iIcon; + public readonly uint dwAttributes; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public readonly string szDisplayName; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] + public readonly string szTypeName; + }; // Browsing for directory. - private const uint SHGFI_ICON = 0x000000100; // get icon - private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon - private const uint SHGFI_LARGEICON = 0x000000000; // get large icon - private const uint SHGFI_SMALLICON = 0x000000001; // get small icon - private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute - private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; + private const uint SHGFI_ICON = 0x000000100; // get icon + private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon + private const uint SHGFI_LARGEICON = 0x000000000; // get large icon + private const uint SHGFI_SMALLICON = 0x000000001; // get small icon + private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute + private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; /// - /// Options to specify the size of icons to return. - /// - public enum IconSize { - /// - /// Specify large icon - 32 pixels by 32 pixels. - /// - Large = 0, - /// - /// Specify small icon - 16 pixels by 16 pixels. - /// - Small = 1 - } + /// Options to specify the size of icons to return. + /// + public enum IconSize + { + /// + /// Specify large icon - 32 pixels by 32 pixels. + /// + Large = 0, + + /// + /// Specify small icon - 16 pixels by 16 pixels. + /// + Small = 1 + } /// - /// Returns an icon for a given file extension - indicated by the name parameter. - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx - /// - /// Filename - /// Large or small - /// Whether to include the link icon - /// System.Drawing.Icon - public static Icon GetFileIcon(string filename, IconSize size, bool linkOverlay) { - SHFILEINFO shfi = new SHFILEINFO(); - // SHGFI_USEFILEATTRIBUTES makes it simulate, just gets the icon for the extension - uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; + /// Returns an icon for a given file extension - indicated by the name parameter. + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx + /// + /// Filename + /// Large or small + /// Whether to include the link icon + /// System.Drawing.Icon + public static Icon GetFileIcon(string filename, IconSize size, bool linkOverlay) + { + SHFILEINFO shfi = new SHFILEINFO(); + // SHGFI_USEFILEATTRIBUTES makes it simulate, just gets the icon for the extension + uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; - if (linkOverlay) { - flags += SHGFI_LINKOVERLAY; - } + if (linkOverlay) + { + flags += SHGFI_LINKOVERLAY; + } - // Check the size specified for return. - if (IconSize.Small == size) { - flags += SHGFI_SMALLICON; - } else { - flags += SHGFI_LARGEICON; - } + // Check the size specified for return. + if (IconSize.Small == size) + { + flags += SHGFI_SMALLICON; + } + else + { + flags += SHGFI_LARGEICON; + } - SHGetFileInfo(Path.GetFileName(filename), FILE_ATTRIBUTE_NORMAL, ref shfi, (uint)Marshal.SizeOf(shfi), flags); + SHGetFileInfo(Path.GetFileName(filename), FILE_ATTRIBUTE_NORMAL, ref shfi, (uint) Marshal.SizeOf(shfi), flags); - // Only return an icon if we really got one - if (shfi.hIcon != IntPtr.Zero) { - // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly - Icon icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone(); - // Cleanup - User32.DestroyIcon(shfi.hIcon); - return icon; - } - return null; - } + // Only return an icon if we really got one + if (shfi.hIcon != IntPtr.Zero) + { + // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly + Icon icon = (Icon) Icon.FromHandle(shfi.hIcon).Clone(); + // Cleanup + User32.DestroyIcon(shfi.hIcon); + return icon; + } + + return null; + } } -} +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs index 7f18bf9ec..1eae0c0ad 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs @@ -25,7 +25,8 @@ using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers.Structs { [StructLayout(LayoutKind.Sequential)] - public struct CursorInfo { + public struct CursorInfo + { public int cbSize; public int flags; public IntPtr hCursor; diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs index ae8629b4d..cd953d244 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs @@ -25,7 +25,8 @@ using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers.Structs { [StructLayout(LayoutKind.Sequential)] - public struct IconInfo { + public struct IconInfo + { public bool fIcon; public int xHotspot; public int yHotspot; diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs index b94be1de4..f22f34e49 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs @@ -26,32 +26,40 @@ using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers.Structs { [StructLayout(LayoutKind.Sequential), Serializable()] - public struct POINT { + public struct POINT + { public int X; public int Y; - public POINT(int x, int y) { + public POINT(int x, int y) + { X = x; Y = y; } - public POINT(Point point) { + + public POINT(Point point) + { X = point.X; Y = point.Y; } - public static implicit operator Point(POINT p) { + public static implicit operator Point(POINT p) + { return new Point(p.X, p.Y); } - public static implicit operator POINT(Point p) { + public static implicit operator POINT(Point p) + { return new POINT(p.X, p.Y); } - public Point ToPoint() { + public Point ToPoint() + { return new Point(X, Y); } - public override string ToString() { + public override string ToString() + { return X + "," + Y; } } diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs index 5186f072b..4541c7445 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs @@ -26,141 +26,148 @@ using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers.Structs { [StructLayout(LayoutKind.Sequential), Serializable()] - public struct RECT { + public struct RECT + { private int _Left; private int _Top; private int _Right; private int _Bottom; public RECT(RECT rectangle) - : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) { + : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) + { } + public RECT(Rectangle rectangle) - : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) { + : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) + { } - public RECT(int left, int top, int right, int bottom) { + + public RECT(int left, int top, int right, int bottom) + { _Left = left; _Top = top; _Right = right; _Bottom = bottom; } - public int X { - get { - return _Left; - } - set { - _Left = value; - } + public int X + { + get { return _Left; } + set { _Left = value; } } - public int Y { - get { - return _Top; - } - set { - _Top = value; - } + + public int Y + { + get { return _Top; } + set { _Top = value; } } - public int Left { - get { - return _Left; - } - set { - _Left = value; - } + + public int Left + { + get { return _Left; } + set { _Left = value; } } - public int Top { - get { - return _Top; - } - set { - _Top = value; - } + + public int Top + { + get { return _Top; } + set { _Top = value; } } - public int Right { - get { - return _Right; - } - set { - _Right = value; - } + + public int Right + { + get { return _Right; } + set { _Right = value; } } - public int Bottom { - get { - return _Bottom; - } - set { - _Bottom = value; - } + + public int Bottom + { + get { return _Bottom; } + set { _Bottom = value; } } - public int Height { - get { - return _Bottom - _Top; - } - set { - _Bottom = value - _Top; - } + + public int Height + { + get { return _Bottom - _Top; } + set { _Bottom = value - _Top; } } - public int Width { - get { - return _Right - _Left; - } - set { - _Right = value + _Left; - } + + public int Width + { + get { return _Right - _Left; } + set { _Right = value + _Left; } } - public Point Location { - get { - return new Point(Left, Top); - } - set { + + public Point Location + { + get { return new Point(Left, Top); } + set + { _Left = value.X; _Top = value.Y; } } - public Size Size { - get { - return new Size(Width, Height); - } - set { + + public Size Size + { + get { return new Size(Width, Height); } + set + { _Right = value.Width + _Left; _Bottom = value.Height + _Top; } } - public static implicit operator Rectangle(RECT rectangle) { + public static implicit operator Rectangle(RECT rectangle) + { return new Rectangle(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height); } - public static implicit operator RECT(Rectangle rectangle) { + + public static implicit operator RECT(Rectangle rectangle) + { return new RECT(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); } - public static bool operator ==(RECT rectangle1, RECT rectangle2) { + + public static bool operator ==(RECT rectangle1, RECT rectangle2) + { return rectangle1.Equals(rectangle2); } - public static bool operator !=(RECT rectangle1, RECT rectangle2) { + + public static bool operator !=(RECT rectangle1, RECT rectangle2) + { return !rectangle1.Equals(rectangle2); } - public override string ToString() { + public override string ToString() + { return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}"; } - public override int GetHashCode() { + public override int GetHashCode() + { return ToString().GetHashCode(); } - public bool Equals(RECT rectangle) { + public bool Equals(RECT rectangle) + { return rectangle.Left == _Left && rectangle.Top == _Top && rectangle.Right == _Right && rectangle.Bottom == _Bottom; } - public Rectangle ToRectangle() { + public Rectangle ToRectangle() + { return new Rectangle(Left, Top, Width, Height); } - public override bool Equals(object Object) { - if (Object is RECT) { - return Equals((RECT)Object); - } else if (Object is Rectangle) { - return Equals(new RECT((Rectangle)Object)); + + public override bool Equals(object Object) + { + if (Object is RECT) + { + return Equals((RECT) Object); + } + else if (Object is Rectangle) + { + return Equals(new RECT((Rectangle) Object)); } return false; diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs index 471d0c4cb..00aa12c09 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs @@ -28,7 +28,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// A floating point GDI Plus width/hight based rectangle. /// [StructLayout(LayoutKind.Sequential)] - public struct RECTF { + public struct RECTF + { /// /// The X corner location of the rectangle. /// @@ -56,7 +57,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// The Y corner location of the rectangle. /// The width of the rectangle. /// The height of the rectangle. - public RECTF(float x, float y, float width, float height) { + public RECTF(float x, float y, float width, float height) + { X = x; Y = y; Width = width; @@ -67,7 +69,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// Creates a new GDI Plus rectangle from a System.Drawing.RectangleF. /// /// The rectangle to base this GDI Plus rectangle on. - public RECTF(RectangleF rect) { + public RECTF(RectangleF rect) + { X = rect.X; Y = rect.Y; Width = rect.Width; @@ -78,7 +81,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// Creates a new GDI Plus rectangle from a System.Drawing.Rectangle. /// /// The rectangle to base this GDI Plus rectangle on. - public RECTF(Rectangle rect) { + public RECTF(Rectangle rect) + { X = rect.X; Y = rect.Y; Width = rect.Width; @@ -89,7 +93,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// Returns a RectangleF for this GDI Plus rectangle. /// /// A System.Drawing.RectangleF structure. - public RectangleF ToRectangle() { + public RectangleF ToRectangle() + { return new RectangleF(X, Y, Width, Height); } @@ -98,7 +103,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// /// The GDI Plus rectangle to get the RectangleF for. /// A System.Drawing.RectangleF structure. - public static RectangleF ToRectangle(RECTF rect) { + public static RectangleF ToRectangle(RECTF rect) + { return rect.ToRectangle(); } @@ -107,7 +113,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// /// The RectangleF to get the GDI Plus rectangle for. /// A GDI Plus rectangle structure. - public static RECTF FromRectangle(RectangleF rect) { + public static RECTF FromRectangle(RectangleF rect) + { return new RECTF(rect); } @@ -116,7 +123,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// /// The Rectangle to get the GDI Plus rectangle for. /// A GDI Plus rectangle structure. - public static RECTF FromRectangle(Rectangle rect) { + public static RECTF FromRectangle(Rectangle rect) + { return new RECTF(rect); } } diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs index 0a6451b23..d2157e966 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs @@ -25,7 +25,8 @@ using System.Runtime.InteropServices; namespace GreenshotPlugin.UnmanagedHelpers.Structs { [Serializable, StructLayout(LayoutKind.Sequential)] - public struct SCROLLINFO { + public struct SCROLLINFO + { public int cbSize; public int fMask; public int nMin; diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs index bd1b78699..531fa977d 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs @@ -23,24 +23,29 @@ using System; using System.Drawing; using System.Runtime.InteropServices; -namespace GreenshotPlugin.UnmanagedHelpers.Structs { - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct SIZE { - public int Width; - public int Height; - public SIZE(Size size) : this(size.Width, size.Height) { - - } +namespace GreenshotPlugin.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential), Serializable()] + public struct SIZE + { + public int Width; + public int Height; - public SIZE(int width, int height) { - Width = width; - Height = height; - } + public SIZE(Size size) : this(size.Width, size.Height) + { + } - public Size ToSize() { - return new Size(Width, Height); - } + public SIZE(int width, int height) + { + Width = width; + Height = height; + } - public bool IsEmpty => Width * Height == 0; - } -} + public Size ToSize() + { + return new Size(Width, Height); + } + + public bool IsEmpty => Width * Height == 0; + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs index 532d597a3..237fca4b8 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs @@ -29,7 +29,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632610%28v=vs.85%29.aspx /// [StructLayout(LayoutKind.Sequential), Serializable] - public struct WindowInfo { + public struct WindowInfo + { public uint cbSize; public RECT rcWindow; public RECT rcClient; @@ -39,10 +40,13 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs public uint cxWindowBorders; public uint cyWindowBorders; public ushort atomWindowType; + public ushort wCreatorVersion; + // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)". - public WindowInfo(bool? filler) : this() { - cbSize = (uint)(Marshal.SizeOf(typeof(WindowInfo))); + public WindowInfo(bool? filler) : this() + { + cbSize = (uint) (Marshal.SizeOf(typeof(WindowInfo))); } } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs b/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs index 1a7de8ebb..c1f064c48 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs @@ -29,7 +29,8 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// Contains information about the placement of a window on the screen. /// [StructLayout(LayoutKind.Sequential), Serializable()] - public struct WindowPlacement { + public struct WindowPlacement + { /// /// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT). /// @@ -66,8 +67,10 @@ namespace GreenshotPlugin.UnmanagedHelpers.Structs /// /// Gets the default (empty) value. /// - public static WindowPlacement Default { - get { + public static WindowPlacement Default + { + get + { WindowPlacement result = new WindowPlacement(); result.Length = Marshal.SizeOf(result); return result; diff --git a/src/GreenshotPlugin/UnmanagedHelpers/User32.cs b/src/GreenshotPlugin/UnmanagedHelpers/User32.cs index 784b7d129..2cedb28f7 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/User32.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/User32.cs @@ -31,247 +31,303 @@ using GreenshotPlugin.Core.Enums; using GreenshotPlugin.UnmanagedHelpers.Enums; using GreenshotPlugin.UnmanagedHelpers.Structs; -namespace GreenshotPlugin.UnmanagedHelpers { +namespace GreenshotPlugin.UnmanagedHelpers +{ /// - /// User32 Wrappers - /// - public static class User32 { - private static readonly ILog LOG = LogManager.GetLogger(typeof(User32)); - private static bool _CanCallGetPhysicalCursorPos = true; - public const int SC_RESTORE = 0xF120; - public const int SC_MAXIMIZE = 0xF030; - public const int SC_MINIMIZE = 0xF020; + /// User32 Wrappers + /// + public static class User32 + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(User32)); + private static bool _CanCallGetPhysicalCursorPos = true; + public const int SC_RESTORE = 0xF120; + public const int SC_MAXIMIZE = 0xF030; + public const int SC_MINIMIZE = 0xF020; // For MonitorFromWindow - public const int MONITOR_DEFAULTTONULL = 0; - public const int MONITOR_DEFAULTTONEAREST = 2; - public const int CURSOR_SHOWING = 0x00000001; + public const int MONITOR_DEFAULTTONULL = 0; + public const int MONITOR_DEFAULTTONEAREST = 2; + public const int CURSOR_SHOWING = 0x00000001; - /// - /// Determines whether the specified window handle identifies an existing window. - /// - /// A handle to the window to be tested. - /// - /// If the window handle identifies an existing window, the return value is true. - /// If the window handle does not identify an existing window, the return value is false. - /// - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindow(IntPtr hWnd); + /// + /// Determines whether the specified window handle identifies an existing window. + /// + /// A handle to the window to be tested. + /// + /// If the window handle identifies an existing window, the return value is true. + /// If the window handle does not identify an existing window, the return value is false. + /// + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindow(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindowVisible(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindowVisible(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId); [DllImport("user32", SetLastError = true)] public static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId); + [DllImport("user32")] public static extern IntPtr AttachThreadInput(int idAttach, int idAttachTo, int fAttach); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetParent(IntPtr hWnd); + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetParent(IntPtr hWnd); [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int cch); + public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int cch); [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool BringWindowToTop(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetForegroundWindow(); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetDesktopWindow(); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetForegroundWindow(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WindowPlacement lpwndpl); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsIconic(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsZoomed(IntPtr hWnd); - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetClassName (IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); - [DllImport("user32", SetLastError = true)] - public static extern uint GetClassLong(IntPtr hWnd, int nIndex); - [DllImport("user32", SetLastError = true, EntryPoint = "GetClassLongPtr")] - public static extern IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, uint nFlags); - [DllImport("user32", CharSet=CharSet.Unicode, SetLastError=true)] - public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool BringWindowToTop(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetDesktopWindow(); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetForegroundWindow(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WindowPlacement lpwndpl); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsIconic(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsZoomed(IntPtr hWnd); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); + + [DllImport("user32", SetLastError = true)] + public static extern uint GetClassLong(IntPtr hWnd, int nIndex); + + [DllImport("user32", SetLastError = true, EntryPoint = "GetClassLongPtr")] + public static extern IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, uint nFlags); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")] - public static extern int GetWindowLong(IntPtr hWnd, int index); - [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")] - public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int SetWindowLong(IntPtr hWnd, int index, int styleFlags); - [DllImport("user32", SetLastError = true, EntryPoint = "SetWindowLongPtr")] - public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int index, IntPtr styleFlags); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr MonitorFromWindow(IntPtr hWnd, MonitorFrom dwFlags); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowInfo(IntPtr hWnd, ref WindowInfo pwi); + public static extern int GetWindowLong(IntPtr hWnd, int index); + + [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")] + public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int SetWindowLong(IntPtr hWnd, int index, int styleFlags); + + [DllImport("user32", SetLastError = true, EntryPoint = "SetWindowLongPtr")] + public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int index, IntPtr styleFlags); [DllImport("user32", SetLastError = true)] - public static extern int EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); + public static extern IntPtr MonitorFromWindow(IntPtr hWnd, MonitorFrom dwFlags); [DllImport("user32", SetLastError = true)] - public static extern RegionResult GetWindowRgn(IntPtr hWnd, SafeHandle hRgn); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, WindowPos uFlags); + public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags); [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetClipboardOwner(); + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowInfo(IntPtr hWnd, ref WindowInfo pwi); + + [DllImport("user32", SetLastError = true)] + public static extern int EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); + + [DllImport("user32", SetLastError = true)] + public static extern RegionResult GetWindowRgn(IntPtr hWnd, SafeHandle hRgn); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, WindowPos uFlags); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetClipboardOwner(); // Added for finding Metro apps, Greenshot 1.1 - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow); + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - /// uiFlags: 0 - Count of GDI objects - /// uiFlags: 1 - Count of USER objects - /// - Win32 GDI objects (pens, brushes, fonts, palettes, regions, device contexts, bitmap headers) - /// - Win32 USER objects: - /// - WIN32 resources (accelerator tables, bitmap resources, dialog box templates, font resources, menu resources, raw data resources, string table entries, message table entries, cursors/icons) - /// - Other USER objects (windows, menus) - /// - [DllImport("user32", SetLastError = true)] - public static extern uint GetGuiResources(IntPtr hProcess, uint uiFlags); - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint RegisterWindowMessage(string lpString); - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult); - [DllImport("user32", SetLastError = true)] - private static extern bool GetPhysicalCursorPos(out POINT cursorLocation); + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow); + + /// uiFlags: 0 - Count of GDI objects + /// uiFlags: 1 - Count of USER objects + /// - Win32 GDI objects (pens, brushes, fonts, palettes, regions, device contexts, bitmap headers) + /// - Win32 USER objects: + /// - WIN32 resources (accelerator tables, bitmap resources, dialog box templates, font resources, menu resources, raw data resources, string table entries, message table entries, cursors/icons) + /// - Other USER objects (windows, menus) + /// + [DllImport("user32", SetLastError = true)] + public static extern uint GetGuiResources(IntPtr hProcess, uint uiFlags); + + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint RegisterWindowMessage(string lpString); + + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult); + + [DllImport("user32", SetLastError = true)] + private static extern bool GetPhysicalCursorPos(out POINT cursorLocation); /// - /// The following is used for Icon handling - /// - /// - /// - [DllImport("user32", SetLastError = true)] - public static extern SafeIconHandle CopyIcon(IntPtr hIcon); - [DllImport("user32", SetLastError = true)] - public static extern bool DestroyIcon(IntPtr hIcon); - [DllImport("user32", SetLastError = true)] - public static extern bool GetCursorInfo(out CursorInfo cursorInfo); - [DllImport("user32", SetLastError = true)] - public static extern bool GetIconInfo(SafeIconHandle iconHandle, out IconInfo iconInfo); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr SetCapture(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool ReleaseCapture(); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr CreateIconIndirect(ref IconInfo icon); + /// The following is used for Icon handling + /// + /// + /// + [DllImport("user32", SetLastError = true)] + public static extern SafeIconHandle CopyIcon(IntPtr hIcon); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, DesktopAccessRight dwDesiredAccess); - [DllImport("user32", SetLastError = true)] - public static extern bool SetThreadDesktop(IntPtr hDesktop); - [DllImport("user32", SetLastError = true)] - public static extern bool CloseDesktop(IntPtr hDesktop); + [DllImport("user32", SetLastError = true)] + public static extern bool DestroyIcon(IntPtr hIcon); + + [DllImport("user32", SetLastError = true)] + public static extern bool GetCursorInfo(out CursorInfo cursorInfo); + + [DllImport("user32", SetLastError = true)] + public static extern bool GetIconInfo(SafeIconHandle iconHandle, out IconInfo iconInfo); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr SetCapture(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ReleaseCapture(); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr CreateIconIndirect(ref IconInfo icon); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, DesktopAccessRight dwDesiredAccess); + + [DllImport("user32", SetLastError = true)] + public static extern bool SetThreadDesktop(IntPtr hDesktop); + + [DllImport("user32", SetLastError = true)] + public static extern bool CloseDesktop(IntPtr hDesktop); /// - /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. - /// - /// Point with cursor location, relative to the origin of the monitor setup - /// (i.e. negative coordinates arepossible in multiscreen setups) - public static Point GetCursorLocation() { - if (Environment.OSVersion.Version.Major >= 6 && _CanCallGetPhysicalCursorPos) { - try { - if (GetPhysicalCursorPos(out var cursorLocation)) { - return new Point(cursorLocation.X, cursorLocation.Y); - } + /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. + /// + /// Point with cursor location, relative to the origin of the monitor setup + /// (i.e. negative coordinates arepossible in multiscreen setups) + public static Point GetCursorLocation() + { + if (Environment.OSVersion.Version.Major >= 6 && _CanCallGetPhysicalCursorPos) + { + try + { + if (GetPhysicalCursorPos(out var cursorLocation)) + { + return new Point(cursorLocation.X, cursorLocation.Y); + } Win32Error error = Win32.GetLastErrorCode(); LOG.ErrorFormat("Error retrieving PhysicalCursorPos : {0}", Win32.GetMessage(error)); - } catch (Exception ex) { - LOG.Error("Exception retrieving PhysicalCursorPos, no longer calling this. Cause :", ex); - _CanCallGetPhysicalCursorPos = false; - } - } - return new Point(Cursor.Position.X, Cursor.Position.Y); - } + } + catch (Exception ex) + { + LOG.Error("Exception retrieving PhysicalCursorPos, no longer calling this. Cause :", ex); + _CanCallGetPhysicalCursorPos = false; + } + } - /// - /// Wrapper for the GetClassLong which decides if the system is 64-bit or not and calls the right one. - /// - /// IntPtr - /// int - /// IntPtr - public static IntPtr GetClassLongWrapper(IntPtr hWnd, int nIndex) { - if (IntPtr.Size > 4) { - return GetClassLongPtr(hWnd, nIndex); - } else { - return new IntPtr(GetClassLong(hWnd, nIndex)); - } - } + return new Point(Cursor.Position.X, Cursor.Position.Y); + } - /// - /// Wrapper for the GetWindowLong which decides if the system is 64-bit or not and calls the right one. - /// - /// - /// - /// - public static long GetWindowLongWrapper(IntPtr hWnd, int nIndex) { - if (IntPtr.Size == 8) { - return GetWindowLongPtr(hWnd, nIndex).ToInt64(); - } else { - return GetWindowLong(hWnd, nIndex); - } - } + /// + /// Wrapper for the GetClassLong which decides if the system is 64-bit or not and calls the right one. + /// + /// IntPtr + /// int + /// IntPtr + public static IntPtr GetClassLongWrapper(IntPtr hWnd, int nIndex) + { + if (IntPtr.Size > 4) + { + return GetClassLongPtr(hWnd, nIndex); + } + else + { + return new IntPtr(GetClassLong(hWnd, nIndex)); + } + } - /// - /// Wrapper for the SetWindowLong which decides if the system is 64-bit or not and calls the right one. - /// - /// - /// - /// - public static void SetWindowLongWrapper(IntPtr hWnd, int nIndex, IntPtr styleFlags) { - if (IntPtr.Size == 8) { - SetWindowLongPtr(hWnd, nIndex, styleFlags); - } else { - SetWindowLong(hWnd, nIndex, styleFlags.ToInt32()); - } - } + /// + /// Wrapper for the GetWindowLong which decides if the system is 64-bit or not and calls the right one. + /// + /// + /// + /// + public static long GetWindowLongWrapper(IntPtr hWnd, int nIndex) + { + if (IntPtr.Size == 8) + { + return GetWindowLongPtr(hWnd, nIndex).ToInt64(); + } + else + { + return GetWindowLong(hWnd, nIndex); + } + } - public static uint GetGuiResourcesGDICount() + /// + /// Wrapper for the SetWindowLong which decides if the system is 64-bit or not and calls the right one. + /// + /// + /// + /// + public static void SetWindowLongWrapper(IntPtr hWnd, int nIndex, IntPtr styleFlags) + { + if (IntPtr.Size == 8) + { + SetWindowLongPtr(hWnd, nIndex, styleFlags); + } + else + { + SetWindowLong(hWnd, nIndex, styleFlags.ToInt32()); + } + } + + public static uint GetGuiResourcesGDICount() { using var currentProcess = Process.GetCurrentProcess(); return GetGuiResources(currentProcess.Handle, 0); } - public static uint GetGuiResourcesUserCount() + public static uint GetGuiResourcesUserCount() { using var currentProcess = Process.GetCurrentProcess(); return GetGuiResources(currentProcess.Handle, 1); } - /// - /// Helper method to create a Win32 exception with the windows message in it - /// - /// string with current method - /// Exception - public static Exception CreateWin32Exception(string method) { - var exceptionToThrow = new Win32Exception(); - exceptionToThrow.Data.Add("Method", method); - return exceptionToThrow; - } - } -} + /// + /// Helper method to create a Win32 exception with the windows message in it + /// + /// string with current method + /// Exception + public static Exception CreateWin32Exception(string method) + { + var exceptionToThrow = new Win32Exception(); + exceptionToThrow.Data.Add("Method", method); + return exceptionToThrow; + } + } +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Win32.cs b/src/GreenshotPlugin/UnmanagedHelpers/Win32.cs index 7efb73292..2721572f0 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Win32.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/Win32.cs @@ -18,34 +18,41 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Runtime.InteropServices; using System.Text; using GreenshotPlugin.UnmanagedHelpers.Enums; -namespace GreenshotPlugin.UnmanagedHelpers { - public static class Win32 { - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - private static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer, int nSize, IntPtr arguments); - - [DllImport("kernel32.dll")] - public static extern void SetLastError(uint dwErrCode); - - public static Win32Error GetLastErrorCode() { - return (Win32Error)Marshal.GetLastWin32Error(); +namespace GreenshotPlugin.UnmanagedHelpers +{ + public static class Win32 + { + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + private static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer, int nSize, IntPtr arguments); + + [DllImport("kernel32.dll")] + public static extern void SetLastError(uint dwErrCode); + + public static Win32Error GetLastErrorCode() + { + return (Win32Error) Marshal.GetLastWin32Error(); } - public static string GetMessage(Win32Error errorCode) { + public static string GetMessage(Win32Error errorCode) + { var buffer = new StringBuilder(0x100); - if (FormatMessage(0x3200, IntPtr.Zero, (uint)errorCode, 0, buffer, buffer.Capacity, IntPtr.Zero) == 0) { - return "Unknown error (0x" + ((int)errorCode).ToString("x") + ")"; + if (FormatMessage(0x3200, IntPtr.Zero, (uint) errorCode, 0, buffer, buffer.Capacity, IntPtr.Zero) == 0) + { + return "Unknown error (0x" + ((int) errorCode).ToString("x") + ")"; } var result = new StringBuilder(); int i = 0; - while (i < buffer.Length) { + while (i < buffer.Length) + { if (!char.IsLetterOrDigit(buffer[i]) && !char.IsPunctuation(buffer[i]) && !char.IsSymbol(buffer[i]) && @@ -59,5 +66,4 @@ namespace GreenshotPlugin.UnmanagedHelpers { return result.ToString().Replace("\r\n", string.Empty); } } -} - +} \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/WinMM.cs b/src/GreenshotPlugin/UnmanagedHelpers/WinMM.cs index 71e8f6b7b..25bb503b4 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/WinMM.cs +++ b/src/GreenshotPlugin/UnmanagedHelpers/WinMM.cs @@ -18,18 +18,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Runtime.InteropServices; -namespace GreenshotPlugin.UnmanagedHelpers { - /// - /// Windows Media - /// - public class WinMM { - [DllImport("winmm.dll", SetLastError = true)] - public static extern bool PlaySound(byte[] ptrToSound, UIntPtr hmod, uint fdwSound); - - [DllImport("winmm.dll", SetLastError = true)] - public static extern bool PlaySound(IntPtr ptrToSound, UIntPtr hmod, uint fdwSound); - } -} +namespace GreenshotPlugin.UnmanagedHelpers +{ + /// + /// Windows Media + /// + public class WinMM + { + [DllImport("winmm.dll", SetLastError = true)] + public static extern bool PlaySound(byte[] ptrToSound, UIntPtr hmod, uint fdwSound); + + [DllImport("winmm.dll", SetLastError = true)] + public static extern bool PlaySound(IntPtr ptrToSound, UIntPtr hmod, uint fdwSound); + } +} \ No newline at end of file From 79cdca03ebb0d376439f7c589148ff33d2146768 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 28 Mar 2021 21:01:29 +0200 Subject: [PATCH 118/232] Renamed the GreenshotPlugin to Greenshot.Base --- installer/innosetup/setup.iss | 2 +- .../Controls/AnimatingForm.cs | 278 +- .../Controls/BackgroundForm.Designer.cs | 192 +- .../Controls/BackgroundForm.cs | 196 +- .../Controls/ExtendedWebBrowser.cs | 134 +- .../Controls/FormWithoutActivation.cs | 70 +- .../Controls/GreenshotButton.cs | 62 +- .../Controls/GreenshotCheckBox.cs | 80 +- .../Controls/GreenshotColumnSorter.cs | 2 +- .../Controls/GreenshotComboBox.cs | 230 +- .../Controls/GreenshotForm.cs | 1284 +++--- .../Controls/GreenshotGroupBox.cs | 62 +- .../Controls/GreenshotLabel.cs | 62 +- .../Controls/GreenshotRadioButton.cs | 80 +- .../Controls/GreenshotTabPage.cs | 62 +- .../Controls/GreenshotTextBox.cs | 68 +- .../Controls/GreenshotToolDropDownButton.cs | 62 +- .../Controls/GreenshotToolStripButton.cs | 62 +- .../Controls/GreenshotToolStripLabel.cs | 62 +- .../Controls/GreenshotToolStripMenuItem.cs | 62 +- .../Controls/HotkeyControl.cs | 1370 +++--- .../Controls/IGreenshotConfigBindable.cs | 70 +- .../Controls/IGreenshotLanguageBindable.cs | 66 +- .../Controls/OAuthLoginForm.Designer.cs | 184 +- .../Controls/OAuthLoginForm.cs | 240 +- .../Controls/PleaseWaitForm.Designer.cs | 198 +- .../Controls/PleaseWaitForm.cs | 284 +- .../Controls/QualityDialog.Designer.cs | 294 +- .../Controls/QualityDialog.cs | 140 +- .../Controls/SaveImageFileDialog.cs | 468 +- .../Controls/ThumbnailForm.cs | 311 +- .../Core/AbstractDestination.cs | 830 ++-- .../Core/AbstractProcessor.cs | 134 +- .../Core/AccessibleHelper.cs | 472 +-- .../Core/AnimationHelpers.cs | 1218 +++--- .../Core/BinaryStructHelper.cs | 214 +- .../Core/Cache.cs | 516 +-- .../Core/Capture.cs | 6 +- .../Core/CaptureDetails.cs | 6 +- .../Core/CaptureHandler.cs | 84 +- .../Core/ClipboardHelper.cs | 2151 +++++----- .../Core/CoreConfiguration.cs | 1472 +++---- .../Core/CredentialsHelper.cs | 1048 ++--- .../Core/DisplayKeyAttribute.cs | 78 +- .../Core/DpiHelper.cs | 10 +- .../Core/EffectConverter.cs | 464 +- .../Core/Enums/HResult.cs | 2 +- .../Core/Enums/MonitorDpiType.cs | 2 +- .../Core/Enums/MonitorFrom.cs | 2 +- .../Core/EnvironmentInfo.cs | 6 +- .../Core/EventDelay.cs | 2 +- .../Core/ExplorerHelper.cs | 108 +- .../Core/FastBitmap.cs | 2108 ++++----- .../Core/FilenameHelper.cs | 1408 +++---- .../Core/Fraction.cs | 2 +- .../Core/GreenshotResources.cs | 96 +- .../Core/GreenshotResources.resx | 940 ++--- .../Core/HResultExtensions.cs | 4 +- .../Core/IEHelper.cs | 404 +- .../Core/IImage.cs | 134 +- .../Core/ImageHelper.cs | 3612 ++++++++-------- .../Core/ImageOutput.cs | 1594 +++---- .../Core/ImageWrapper.cs | 152 +- .../Core/InterfaceUtils.cs | 144 +- .../Core/JSONHelper.cs | 870 ++-- .../Core/Language.cs | 1612 +++---- .../Core/LanguageChangedHandler.cs | 10 +- .../Core/LanguageFile.cs | 158 +- .../Core/LogHelper.cs | 246 +- .../Core/NetworkHelper.cs | 1454 +++---- .../Core/OAuth/LocalJsonReceiver.cs | 2 +- .../Core/OAuth/LocalServerCodeReceiver.cs | 2 +- .../Core/OAuth/OAuth2AuthorizeMode.cs | 2 +- .../Core/OAuth/OAuth2Helper.cs | 4 +- .../Core/OAuth/OAuth2Settings.cs | 2 +- .../Core/OAuth/OAuthSession.cs | 4 +- .../Core/OAuth/OAuthSignatureTypes.cs | 2 +- .../Core/ObjectExtensions.cs | 234 +- .../Core/PluginUtils.cs | 454 +- .../Core/QuantizerHelper.cs | 1540 +++---- .../Core/RegistryKeyExtensions.cs | 2 +- .../Core/SimpleServiceProvider.cs | 120 +- .../Core/StringExtensions.cs | 6 +- .../Core/SvgImage.cs | 2 +- .../Core/WindowCapture.cs | 886 ++-- .../Core/WindowDetails.cs | 3748 ++++++++--------- .../Core/WindowsEnumerator.cs | 214 +- .../Core/WindowsVersion.cs | 2 +- .../Core/WmInputLangChangeRequestFilter.cs | 130 +- .../Effects/AdjustEffect.cs | 106 +- .../Effects/BorderEffect.cs | 102 +- .../Effects/DropShadowEffect.cs | 116 +- .../Effects/GrayscaleEffect.cs | 84 +- .../Effects/IEffect.cs | 90 +- .../Effects/InvertEffect.cs | 84 +- .../Effects/MonochromeEffect.cs | 100 +- .../Effects/ReduceColorsEffect.cs | 138 +- .../Effects/ResizeCanvasEffect.cs | 114 +- .../Effects/ResizeEffect.cs | 106 +- .../Effects/RotateEffect.cs | 136 +- .../Effects/TornEdgeEffect.cs | 148 +- .../FileDescriptorReader.cs | 4 +- .../GlobalSuppressions.cs | Bin .../Greenshot.Base.csproj} | 44 +- .../Hooking/WindowsEventHook.cs | 4 +- .../Hooking/WindowsOpenCloseMonitor.cs | 6 +- .../Hooking/WindowsTitleMonitor.cs | 6 +- .../IEInterop/IHTMLBodyElement.cs | 74 +- .../IEInterop/IHTMLCurrentStyle.cs | 160 +- .../IEInterop/IHTMLDocument.cs | 76 +- .../IEInterop/IHTMLDocument2.cs | 168 +- .../IEInterop/IHTMLDocument3.cs | 98 +- .../IEInterop/IHTMLDocument4.cs | 68 +- .../IEInterop/IHTMLDocument5.cs | 74 +- .../IEInterop/IHTMLElement.cs | 224 +- .../IEInterop/IHTMLElement2.cs | 82 +- .../IEInterop/IHTMLElementCollection.cs | 68 +- .../IEInterop/IHTMLFrameBase.cs | 214 +- .../IEInterop/IHTMLFramesCollection2.cs | 74 +- .../IEInterop/IHTMLRect.cs | 76 +- .../IEInterop/IHTMLScreen.cs | 66 +- .../IEInterop/IHTMLScreen2.cs | 76 +- .../IEInterop/IHTMLSelectionObject.cs | 96 +- .../IEInterop/IHTMLStyle.cs | 2204 +++++----- .../IEInterop/IHTMLTxtRange.cs | 280 +- .../IEInterop/IHTMLWindow2.cs | 102 +- .../IEInterop/IHTMLWindow3.cs | 68 +- .../IEInterop/IHTMLWindow4.cs | 74 +- .../IEInterop/IWebBrowser2.cs | 302 +- .../IniFile/IniAttributes.cs | 140 +- .../IniFile/IniConfig.cs | 1146 ++--- .../IniFile/IniReader.cs | 206 +- .../IniFile/IniSection.cs | 468 +- .../IniFile/IniValue.cs | 1240 +++--- .../Interfaces/CaptureMode.cs | 2 +- .../Interfaces/Drawing/Adorners/IAdorner.cs | 202 +- .../Interfaces/Drawing/Container.cs | 296 +- .../Interfaces/Drawing/IField.cs | 128 +- .../Interfaces/Drawing/IFieldholder.cs | 76 +- .../Interfaces/Drawing/IMemento.cs | 90 +- .../Interfaces/DrawingModes.cs | 2 +- .../Interfaces/Forms/ImageEditor.cs | 90 +- .../Interfaces/ICapture.cs | 2 +- .../Interfaces/ICaptureDetails.cs | 4 +- .../Interfaces/IDestination.cs | 260 +- .../Interfaces/INotificationService.cs | 2 +- .../Interfaces/IProcessor.cs | 116 +- .../Interfaces/IServiceLocator.cs | 26 +- .../Interfaces/ISurface.cs | 8 +- .../Interfaces/Ocr/IOcrProvider.cs | 2 +- .../Interfaces/Ocr/Line.cs | 2 +- .../Interfaces/Ocr/OcrInformation.cs | 104 +- .../Interfaces/Ocr/Word.cs | 2 +- .../Interfaces/Plugin/HotKeyHandler.cs | 4 + .../Interfaces/Plugin/IGreenshotHost.cs | 96 +- .../Interfaces/Plugin/IGreenshotPlugin.cs | 50 +- .../Interfaces/Plugin/PluginAttribute.cs | 98 +- .../Plugin/SurfaceOutputSettings.cs | 180 +- .../Interfaces/ScreenCaptureMode.cs | 2 +- .../Interfaces/SurfaceDrawingModeEventArgs.cs | 2 +- .../SurfaceDrawingModeEventHandler.cs | 2 +- .../Interfaces/SurfaceElementEventArgs.cs | 4 +- .../Interfaces/SurfaceElementEventHandler.cs | 2 +- .../Interfaces/SurfaceMessageEventArgs.cs | 2 +- .../Interfaces/SurfaceMessageEventHandler.cs | 2 +- .../Interfaces/SurfaceMessageTyp.cs | 2 +- .../SurfaceSizeChangeEventHandler.cs | 2 +- .../Interop/Base.cs | 20 +- .../Interop/COMWrapper.cs | 1240 +++--- .../Interop/ComProgIdAttribute.cs | 174 +- .../Interop/IAppVisibility.cs | 80 +- .../Interop/IDispatch.cs | 92 +- .../Interop/IOleCommandTarget.cs | 78 +- .../Interop/IOleWindow.cs | 68 +- .../Interop/IServiceProvider.cs | 70 +- .../Interop/IUnknown.cs | 74 +- .../UnmanagedHelpers/DWM.cs | 244 +- .../UnmanagedHelpers/EnumWindowsProc.cs | 64 +- .../UnmanagedHelpers/Enums/ClassLongIndex.cs | 62 +- .../Enums/DWMWINDOWATTRIBUTE.cs | 90 +- .../Enums/DWM_THUMBNAIL_PROPERTIES.cs | 220 +- .../Enums/DesktopAccessRight.cs | 88 +- .../UnmanagedHelpers/Enums/DeviceCaps.cs | 84 +- .../UnmanagedHelpers/Enums/EventObjects.cs | 68 +- .../Enums/ExtendedWindowStyleFlags.cs | 70 +- .../Enums/ProcessAccessFlags.cs | 66 +- .../UnmanagedHelpers/Enums/RegionResult.cs | 62 +- .../Enums/SendMessageTimeoutFlags.cs | 70 +- .../Enums/ShowWindowCommand.cs | 218 +- .../UnmanagedHelpers/Enums/SoundFlags.cs | 76 +- .../UnmanagedHelpers/Enums/ThreadAccess.cs | 60 +- .../UnmanagedHelpers/Enums/Win32Error.cs | 176 +- .../UnmanagedHelpers/Enums/WinEvent.cs | 72 +- .../Enums/WinEventHookFlags.cs | 34 +- .../UnmanagedHelpers/Enums/WindowLongIndex.cs | 62 +- .../Enums/WindowPlacementFlags.cs | 82 +- .../UnmanagedHelpers/Enums/WindowPos.cs | 70 +- .../Enums/WindowStyleFlags.cs | 70 +- .../UnmanagedHelpers/Enums/WindowsMessages.cs | 50 +- .../UnmanagedHelpers/GDI32.cs | 848 ++-- .../UnmanagedHelpers/GDIplus.cs | 772 ++-- .../UnmanagedHelpers/Kernel32.cs | 260 +- .../UnmanagedHelpers/PsAPI.cs | 110 +- .../SafeCurrentInputDesktopHandle.cs | 88 +- .../UnmanagedHelpers/SafeIconHandle.cs | 64 +- .../UnmanagedHelpers/SafeWindowDcHandle.cs | 130 +- .../UnmanagedHelpers/Shell32.cs | 244 +- .../UnmanagedHelpers/Structs/CursorInfo.cs | 68 +- .../UnmanagedHelpers/Structs/IconInfo.cs | 70 +- .../UnmanagedHelpers/Structs/POINT.cs | 130 +- .../UnmanagedHelpers/Structs/RECT.cs | 350 +- .../UnmanagedHelpers/Structs/RECTF.cs | 260 +- .../UnmanagedHelpers/Structs/SCROLLINFO.cs | 74 +- .../UnmanagedHelpers/Structs/SIZE.cs | 100 +- .../UnmanagedHelpers/Structs/WindowInfo.cs | 102 +- .../Structs/WindowPlacement.cs | 158 +- .../UnmanagedHelpers/User32.cs | 664 +-- .../UnmanagedHelpers/Win32.cs | 136 +- .../UnmanagedHelpers/WinEventDelegate.cs | 32 +- .../UnmanagedHelpers/WinMM.cs | 74 +- .../log4net-embedded.xml | 40 +- src/Greenshot.Plugin.Box/BoxConfiguration.cs | 4 +- src/Greenshot.Plugin.Box/BoxDestination.cs | 4 +- src/Greenshot.Plugin.Box/BoxPlugin.cs | 10 +- src/Greenshot.Plugin.Box/BoxUtils.cs | 6 +- src/Greenshot.Plugin.Box/Forms/BoxForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 27 +- .../Greenshot.Plugin.Box.csproj | 2 +- src/Greenshot.Plugin.Confluence/Confluence.cs | 4 +- .../ConfluenceConfiguration.cs | 4 +- .../ConfluenceDestination.cs | 10 +- .../ConfluencePlugin.cs | 8 +- .../ConfluenceUtils.cs | 2 +- .../EnumDisplayer.cs | 2 +- .../Forms/ConfluenceConfigurationForm.xaml | 3 +- .../Forms/ConfluenceSearch.xaml.cs | 2 +- .../Greenshot.Plugin.Confluence.csproj | 2 +- .../Support/LanguageXMLTranslationProvider.cs | 2 +- .../DropboxDestination.cs | 6 +- src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs | 10 +- .../DropboxPluginConfiguration.cs | 4 +- src/Greenshot.Plugin.Dropbox/DropboxUtils.cs | 10 +- .../Forms/DropboxForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 27 +- .../Greenshot.Plugin.Dropbox.csproj | 2 +- .../ExternalCommandConfiguration.cs | 4 +- .../ExternalCommandDestination.cs | 8 +- .../ExternalCommandForm.cs | 2 +- .../ExternalCommandPlugin.cs | 8 +- .../Greenshot.Plugin.ExternalCommand.csproj | 2 +- .../IconCache.cs | 4 +- .../SettingsForm.Designer.cs | 23 +- .../SettingsForm.cs | 2 +- .../SettingsFormDetail.Designer.cs | 31 +- .../SettingsFormDetail.cs | 4 +- .../FlickrConfiguration.cs | 4 +- .../FlickrDestination.cs | 4 +- src/Greenshot.Plugin.Flickr/FlickrPlugin.cs | 10 +- src/Greenshot.Plugin.Flickr/FlickrUtils.cs | 10 +- .../Forms/FlickrForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 51 +- .../Greenshot.Plugin.Flickr.csproj | 2 +- .../Forms/GooglePhotosForm.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 27 +- .../GooglePhotosConfiguration.cs | 4 +- .../GooglePhotosDestination.cs | 4 +- .../GooglePhotosPlugin.cs | 10 +- .../GooglePhotosUtils.cs | 10 +- .../Greenshot.Plugin.GooglePhotos.csproj | 2 +- src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs | 2 +- .../Forms/ImgurHistory.cs | 6 +- .../Forms/SettingsForm.Designer.cs | 31 +- .../Greenshot.Plugin.Imgur.csproj | 2 +- .../ImgurConfiguration.cs | 4 +- .../ImgurDestination.cs | 4 +- src/Greenshot.Plugin.Imgur/ImgurPlugin.cs | 10 +- src/Greenshot.Plugin.Imgur/ImgurUtils.cs | 10 +- src/Greenshot.Plugin.Jira/Forms/JiraForm.cs | 6 +- .../Forms/JiraFormBase.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 27 +- .../Greenshot.Plugin.Jira.csproj | 2 +- .../JiraConfiguration.cs | 4 +- src/Greenshot.Plugin.Jira/JiraConnector.cs | 4 +- src/Greenshot.Plugin.Jira/JiraDestination.cs | 10 +- src/Greenshot.Plugin.Jira/JiraMonitor.cs | 2 +- src/Greenshot.Plugin.Jira/JiraPlugin.cs | 8 +- src/Greenshot.Plugin.Office/Com/Ole32Api.cs | 4 +- .../Com/OleAut32Api.cs | 4 +- .../Destinations/ExcelDestination.cs | 6 +- .../Destinations/OneNoteDestination.cs | 4 +- .../Destinations/OutlookDestination.cs | 8 +- .../Destinations/PowerpointDestination.cs | 6 +- .../Destinations/WordDestination.cs | 6 +- .../Greenshot.Plugin.Office.csproj | 2 +- .../OfficeConfiguration.cs | 2 +- .../OfficeExport/ExcelExporter.cs | 2 +- .../OfficeExport/OneNoteExporter.cs | 6 +- .../OfficeExport/OutlookEmailExporter.cs | 2 +- .../OfficeExport/PowerpointExporter.cs | 2 +- .../OfficeExport/WordExporter.cs | 2 +- src/Greenshot.Plugin.Office/OfficePlugin.cs | 6 +- .../Forms/PhotobucketForm.cs | 4 +- .../Forms/SettingsForm.Designer.cs | 23 +- .../Greenshot.Plugin.Photobucket.csproj | 2 +- .../PhotobucketConfiguration.cs | 6 +- .../PhotobucketDestination.cs | 4 +- .../PhotobucketPlugin.cs | 10 +- .../PhotobucketUtils.cs | 10 +- .../Destinations/Win10OcrDestination.cs | 6 +- .../Destinations/Win10ShareDestination.cs | 8 +- .../Greenshot.Plugin.Win10.csproj | 2 +- .../Native/DataTransferManagerHelper.cs | 2 +- .../Native/IDataTransferManagerInterOp.cs | 2 +- .../Processors/Win10OcrProcessor.cs | 8 +- .../ToastNotificationService.cs | 6 +- .../Win10Configuration.cs | 2 +- .../Win10OcrProvider.cs | 8 +- src/Greenshot.Plugin.Win10/Win10Plugin.cs | 8 +- src/Greenshot.sln | 2 +- .../Configuration/EditorConfiguration.cs | 10 +- .../Controls/BindableToolStripButton.cs | 2 +- .../Controls/BindableToolStripComboBox.cs | 2 +- .../BindableToolStripDropDownButton.cs | 2 +- src/Greenshot/Controls/ColorButton.cs | 2 +- ...ontextMenuToolStripProfessionalRenderer.cs | 4 +- src/Greenshot/Controls/MenuStripEx.cs | 2 +- src/Greenshot/Controls/Pipette.cs | 4 +- .../Controls/ToolStripColorButton.cs | 2 +- .../Destinations/ClipboardDestination.cs | 4 +- .../Destinations/EditorDestination.cs | 8 +- .../Destinations/EmailDestination.cs | 4 +- src/Greenshot/Destinations/FileDestination.cs | 10 +- .../Destinations/FileWithDialogDestination.cs | 6 +- .../Destinations/PickerDestination.cs | 4 +- .../Destinations/PrinterDestination.cs | 4 +- .../Drawing/Adorners/AbstractAdorner.cs | 6 +- src/Greenshot/Drawing/Adorners/MoveAdorner.cs | 2 +- .../Drawing/Adorners/ResizeAdorner.cs | 2 +- .../Drawing/Adorners/TargetAdorner.cs | 2 +- src/Greenshot/Drawing/ArrowContainer.cs | 2 +- src/Greenshot/Drawing/CropContainer.cs | 2 +- src/Greenshot/Drawing/CursorContainer.cs | 2 +- src/Greenshot/Drawing/DrawableContainer.cs | 8 +- .../Drawing/DrawableContainerList.cs | 6 +- src/Greenshot/Drawing/EllipseContainer.cs | 2 +- .../Drawing/Fields/AbstractFieldHolder.cs | 4 +- .../Fields/AbstractFieldHolderWithChildren.cs | 2 +- src/Greenshot/Drawing/Fields/Field.cs | 2 +- .../Drawing/Fields/FieldAggregator.cs | 6 +- src/Greenshot/Drawing/Fields/FieldType.cs | 2 +- src/Greenshot/Drawing/FilterContainer.cs | 2 +- .../Drawing/Filters/AbstractFilter.cs | 2 +- src/Greenshot/Drawing/Filters/BlurFilter.cs | 6 +- .../Drawing/Filters/BrightnessFilter.cs | 4 +- .../Drawing/Filters/GrayscaleFilter.cs | 4 +- .../Drawing/Filters/HighlightFilter.cs | 4 +- src/Greenshot/Drawing/Filters/IFilter.cs | 2 +- .../Drawing/Filters/MagnifierFilter.cs | 4 +- .../Drawing/Filters/PixelizationFilter.cs | 4 +- src/Greenshot/Drawing/FreehandContainer.cs | 2 +- src/Greenshot/Drawing/HighlightContainer.cs | 2 +- src/Greenshot/Drawing/IconContainer.cs | 2 +- src/Greenshot/Drawing/ImageContainer.cs | 6 +- src/Greenshot/Drawing/LineContainer.cs | 2 +- src/Greenshot/Drawing/ObfuscateContainer.cs | 2 +- src/Greenshot/Drawing/RectangleContainer.cs | 2 +- .../Drawing/SpeechbubbleContainer.cs | 2 +- src/Greenshot/Drawing/StepLabelContainer.cs | 2 +- src/Greenshot/Drawing/Surface.cs | 14 +- src/Greenshot/Drawing/TextContainer.cs | 4 +- src/Greenshot/Forms/AboutForm.Designer.cs | 27 +- src/Greenshot/Forms/AboutForm.cs | 4 +- src/Greenshot/Forms/AnimatingBaseForm.cs | 2 +- src/Greenshot/Forms/BaseForm.cs | 2 +- src/Greenshot/Forms/BugReportForm.Designer.cs | 11 +- src/Greenshot/Forms/BugReportForm.cs | 2 +- src/Greenshot/Forms/CaptureForm.cs | 12 +- src/Greenshot/Forms/ColorDialog.Designer.cs | 35 +- src/Greenshot/Forms/ColorDialog.cs | 2 +- .../Forms/DropShadowSettingsForm.Designer.cs | 23 +- src/Greenshot/Forms/DropShadowSettingsForm.cs | 2 +- .../Forms/ImageEditorForm.Designer.cs | 361 +- src/Greenshot/Forms/ImageEditorForm.cs | 18 +- src/Greenshot/Forms/LanguageDialog.cs | 2 +- src/Greenshot/Forms/MainForm.Designer.cs | 67 +- src/Greenshot/Forms/MainForm.cs | 12 +- src/Greenshot/Forms/MovableShowColorForm.cs | 2 +- .../Forms/PrintOptionsDialog.Designer.cs | 59 +- src/Greenshot/Forms/PrintOptionsDialog.cs | 2 +- .../Forms/ResizeSettingsForm.Designer.cs | 23 +- src/Greenshot/Forms/ResizeSettingsForm.cs | 4 +- src/Greenshot/Forms/SettingsForm.Designer.cs | 331 +- src/Greenshot/Forms/SettingsForm.cs | 20 +- .../Forms/ToolStripMenuSelectList.cs | 4 +- .../Forms/TornEdgeSettingsForm.Designer.cs | 57 +- src/Greenshot/Forms/TornEdgeSettingsForm.cs | 2 +- src/Greenshot/Greenshot.csproj | 2 +- src/Greenshot/GreenshotMain.cs | 67 +- src/Greenshot/Help/HelpFileLoader.cs | 2 +- src/Greenshot/Helpers/CaptureHelper.cs | 9 +- src/Greenshot/Helpers/CopyData.cs | 2 +- src/Greenshot/Helpers/DestinationHelper.cs | 6 +- src/Greenshot/Helpers/IECaptureHelper.cs | 16 +- .../Helpers/IEInterop/IEContainer.cs | 6 +- src/Greenshot/Helpers/MailHelper.cs | 8 +- .../Helpers/NotifyIconNotificationService.cs | 6 +- src/Greenshot/Helpers/PluginHelper.cs | 20 +- src/Greenshot/Helpers/PrintHelper.cs | 10 +- src/Greenshot/Helpers/ProcessorHelper.cs | 4 +- src/Greenshot/Helpers/SoundHelper.cs | 8 +- src/Greenshot/Helpers/UpdateService.cs | 6 +- src/Greenshot/Memento/AddElementMemento.cs | 2 +- src/Greenshot/Memento/AddElementsMemento.cs | 2 +- .../Memento/ChangeFieldHolderMemento.cs | 2 +- src/Greenshot/Memento/DeleteElementMemento.cs | 2 +- .../Memento/DeleteElementsMemento.cs | 2 +- .../DrawableContainerBoundsChangeMemento.cs | 4 +- .../Memento/SurfaceBackgroundChangeMemento.cs | 2 +- src/Greenshot/Memento/TextChangeMemento.cs | 2 +- src/Greenshot/Processors/TitleFixProcessor.cs | 6 +- src/Greenshot/log4net-debug.xml | 2 +- src/Greenshot/log4net.xml | 2 +- .../Interfaces/Plugin/HotKeyHandler.cs | 4 - 423 files changed, 30044 insertions(+), 30000 deletions(-) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/AnimatingForm.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/BackgroundForm.Designer.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/BackgroundForm.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/ExtendedWebBrowser.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/FormWithoutActivation.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotButton.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotCheckBox.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotColumnSorter.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotComboBox.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotForm.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotGroupBox.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotLabel.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotRadioButton.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotTabPage.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotTextBox.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotToolDropDownButton.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotToolStripButton.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotToolStripLabel.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/GreenshotToolStripMenuItem.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/HotkeyControl.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/IGreenshotConfigBindable.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/IGreenshotLanguageBindable.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/OAuthLoginForm.Designer.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/OAuthLoginForm.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/PleaseWaitForm.Designer.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/PleaseWaitForm.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/QualityDialog.Designer.cs (90%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/QualityDialog.cs (92%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/SaveImageFileDialog.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Controls/ThumbnailForm.cs (92%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/AbstractDestination.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/AbstractProcessor.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/AccessibleHelper.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/AnimationHelpers.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/BinaryStructHelper.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/Cache.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/Capture.cs (98%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/CaptureDetails.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/CaptureHandler.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/ClipboardHelper.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/CoreConfiguration.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/CredentialsHelper.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/DisplayKeyAttribute.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/DpiHelper.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/EffectConverter.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/Enums/HResult.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/Enums/MonitorDpiType.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/Enums/MonitorFrom.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/EnvironmentInfo.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/EventDelay.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/ExplorerHelper.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/FastBitmap.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/FilenameHelper.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/Fraction.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/GreenshotResources.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/GreenshotResources.resx (98%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/HResultExtensions.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/IEHelper.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/IImage.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/ImageHelper.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/ImageOutput.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/ImageWrapper.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/InterfaceUtils.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/JSONHelper.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/Language.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/LanguageChangedHandler.cs (73%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/LanguageFile.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/LogHelper.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/NetworkHelper.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/OAuth/LocalJsonReceiver.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/OAuth/LocalServerCodeReceiver.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/OAuth/OAuth2AuthorizeMode.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/OAuth/OAuth2Helper.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/OAuth/OAuth2Settings.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/OAuth/OAuthSession.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/OAuth/OAuthSignatureTypes.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/ObjectExtensions.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/PluginUtils.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/QuantizerHelper.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/RegistryKeyExtensions.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/SimpleServiceProvider.cs (92%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/StringExtensions.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/SvgImage.cs (99%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/WindowCapture.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/WindowDetails.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/WindowsEnumerator.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/WindowsVersion.cs (98%) rename src/{GreenshotPlugin => Greenshot.Base}/Core/WmInputLangChangeRequestFilter.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/AdjustEffect.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/BorderEffect.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/DropShadowEffect.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/GrayscaleEffect.cs (92%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/IEffect.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/InvertEffect.cs (92%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/MonochromeEffect.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/ReduceColorsEffect.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/ResizeCanvasEffect.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/ResizeEffect.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/RotateEffect.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Effects/TornEdgeEffect.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/FileDescriptorReader.cs (98%) rename src/{GreenshotPlugin => Greenshot.Base}/GlobalSuppressions.cs (100%) rename src/{GreenshotPlugin/GreenshotPlugin.csproj => Greenshot.Base/Greenshot.Base.csproj} (68%) rename src/{GreenshotPlugin => Greenshot.Base}/Hooking/WindowsEventHook.cs (98%) rename src/{GreenshotPlugin => Greenshot.Base}/Hooking/WindowsOpenCloseMonitor.cs (98%) rename src/{GreenshotPlugin => Greenshot.Base}/Hooking/WindowsTitleMonitor.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLBodyElement.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLCurrentStyle.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLDocument.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLDocument2.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLDocument3.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLDocument4.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLDocument5.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLElement.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLElement2.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLElementCollection.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLFrameBase.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLFramesCollection2.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLRect.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLScreen.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLScreen2.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLSelectionObject.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLStyle.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLTxtRange.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLWindow2.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLWindow3.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IHTMLWindow4.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/IEInterop/IWebBrowser2.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/IniFile/IniAttributes.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/IniFile/IniConfig.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/IniFile/IniReader.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/IniFile/IniSection.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/IniFile/IniValue.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/CaptureMode.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Drawing/Adorners/IAdorner.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Drawing/Container.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Drawing/IField.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Drawing/IFieldholder.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Drawing/IMemento.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/DrawingModes.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Forms/ImageEditor.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/ICapture.cs (98%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/ICaptureDetails.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/IDestination.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/INotificationService.cs (98%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/IProcessor.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/IServiceLocator.cs (86%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/ISurface.cs (98%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Ocr/IOcrProvider.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Ocr/Line.cs (98%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Ocr/OcrInformation.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Ocr/Word.cs (90%) create mode 100644 src/Greenshot.Base/Interfaces/Plugin/HotKeyHandler.cs rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Plugin/IGreenshotHost.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Plugin/IGreenshotPlugin.cs (91%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Plugin/PluginAttribute.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/Plugin/SurfaceOutputSettings.cs (92%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/ScreenCaptureMode.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/SurfaceDrawingModeEventArgs.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/SurfaceDrawingModeEventHandler.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/SurfaceElementEventArgs.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/SurfaceElementEventHandler.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/SurfaceMessageEventArgs.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/SurfaceMessageEventHandler.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/SurfaceMessageTyp.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interfaces/SurfaceSizeChangeEventHandler.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interop/Base.cs (80%) rename src/{GreenshotPlugin => Greenshot.Base}/Interop/COMWrapper.cs (97%) rename src/{GreenshotPlugin => Greenshot.Base}/Interop/ComProgIdAttribute.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interop/IAppVisibility.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Interop/IDispatch.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/Interop/IOleCommandTarget.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Interop/IOleWindow.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Interop/IServiceProvider.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/Interop/IUnknown.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/DWM.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/EnumWindowsProc.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/ClassLongIndex.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/DesktopAccessRight.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/DeviceCaps.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/EventObjects.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/ProcessAccessFlags.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/RegionResult.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/ShowWindowCommand.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/SoundFlags.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/ThreadAccess.cs (92%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/Win32Error.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/WinEvent.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/WinEventHookFlags.cs (87%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/WindowLongIndex.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/WindowPlacementFlags.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/WindowPos.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/WindowStyleFlags.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Enums/WindowsMessages.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/GDI32.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/GDIplus.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Kernel32.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/PsAPI.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs (91%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/SafeIconHandle.cs (91%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/SafeWindowDcHandle.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Shell32.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Structs/CursorInfo.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Structs/IconInfo.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Structs/POINT.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Structs/RECT.cs (95%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Structs/RECTF.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Structs/SCROLLINFO.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Structs/SIZE.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Structs/WindowInfo.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Structs/WindowPlacement.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/User32.cs (96%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/Win32.cs (93%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/WinEventDelegate.cs (84%) rename src/{GreenshotPlugin => Greenshot.Base}/UnmanagedHelpers/WinMM.cs (94%) rename src/{GreenshotPlugin => Greenshot.Base}/log4net-embedded.xml (97%) delete mode 100644 src/GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index 977f4cf8b..f8bd75b1d 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -20,7 +20,7 @@ [Files] Source: {#ReleaseDir}\Greenshot.exe; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\GreenshotPlugin.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\Greenshot.Base.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Greenshot.exe.config; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\log4net.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Dapplo.Http*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion diff --git a/src/GreenshotPlugin/Controls/AnimatingForm.cs b/src/Greenshot.Base/Controls/AnimatingForm.cs similarity index 94% rename from src/GreenshotPlugin/Controls/AnimatingForm.cs rename to src/Greenshot.Base/Controls/AnimatingForm.cs index 2bfb06a52..c5a5e3e7e 100644 --- a/src/GreenshotPlugin/Controls/AnimatingForm.cs +++ b/src/Greenshot.Base/Controls/AnimatingForm.cs @@ -1,140 +1,140 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Windows.Forms; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using log4net; - -namespace GreenshotPlugin.Controls -{ - /// - /// Extend this Form to have the possibility for animations on your form - /// - public class AnimatingForm : GreenshotForm - { - private static readonly ILog Log = LogManager.GetLogger(typeof(AnimatingForm)); - private const int DEFAULT_VREFRESH = 60; - private int _vRefresh; - private Timer _timer; - - /// - /// This flag specifies if any animation is used - /// - protected bool EnableAnimation { get; set; } - - /// - /// Vertical Refresh Rate - /// - protected int VRefresh - { - get - { - if (_vRefresh == 0) - { - // get te hDC of the desktop to get the VREFRESH - using SafeWindowDcHandle desktopHandle = SafeWindowDcHandle.FromDesktop(); - _vRefresh = GDI32.GetDeviceCaps(desktopHandle, DeviceCaps.VREFRESH); - } - - // A vertical refresh rate value of 0 or 1 represents the display hardware's default refresh rate. - // As there is currently no know way to get the default, we guess it. - if (_vRefresh <= 1) - { - _vRefresh = DEFAULT_VREFRESH; - } - - return _vRefresh; - } - } - - /// - /// Check if we are in a Terminal Server session OR need to optimize for RDP / remote desktop connections - /// - protected bool IsTerminalServerSession => !coreConfiguration.DisableRDPOptimizing && (coreConfiguration.OptimizeForRDP || SystemInformation.TerminalServerSession); - - /// - /// Calculate the amount of frames that an animation takes - /// - /// - /// Number of frames, 1 if in Terminal Server Session - protected int FramesForMillis(int milliseconds) - { - // If we are in a Terminal Server Session we return 1 - if (IsTerminalServerSession) - { - return 1; - } - - return milliseconds / VRefresh; - } - - /// - /// Initialize the animation - /// - protected AnimatingForm() - { - Load += delegate - { - if (!EnableAnimation) - { - return; - } - - _timer = new Timer - { - Interval = 1000 / VRefresh - }; - _timer.Tick += timer_Tick; - _timer.Start(); - }; - - // Unregister at close - FormClosing += delegate { _timer?.Stop(); }; - } - - /// - /// The tick handler initiates the animation. - /// - /// - /// - private void timer_Tick(object sender, EventArgs e) - { - try - { - Animate(); - } - catch (Exception ex) - { - Log.Warn("An exception occured while animating:", ex); - } - } - - /// - /// This method will be called every frame, so implement your animation/redraw logic here. - /// - protected virtual void Animate() - { - throw new NotImplementedException(); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows.Forms; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// Extend this Form to have the possibility for animations on your form + /// + public class AnimatingForm : GreenshotForm + { + private static readonly ILog Log = LogManager.GetLogger(typeof(AnimatingForm)); + private const int DEFAULT_VREFRESH = 60; + private int _vRefresh; + private Timer _timer; + + /// + /// This flag specifies if any animation is used + /// + protected bool EnableAnimation { get; set; } + + /// + /// Vertical Refresh Rate + /// + protected int VRefresh + { + get + { + if (_vRefresh == 0) + { + // get te hDC of the desktop to get the VREFRESH + using SafeWindowDcHandle desktopHandle = SafeWindowDcHandle.FromDesktop(); + _vRefresh = GDI32.GetDeviceCaps(desktopHandle, DeviceCaps.VREFRESH); + } + + // A vertical refresh rate value of 0 or 1 represents the display hardware's default refresh rate. + // As there is currently no know way to get the default, we guess it. + if (_vRefresh <= 1) + { + _vRefresh = DEFAULT_VREFRESH; + } + + return _vRefresh; + } + } + + /// + /// Check if we are in a Terminal Server session OR need to optimize for RDP / remote desktop connections + /// + protected bool IsTerminalServerSession => !coreConfiguration.DisableRDPOptimizing && (coreConfiguration.OptimizeForRDP || SystemInformation.TerminalServerSession); + + /// + /// Calculate the amount of frames that an animation takes + /// + /// + /// Number of frames, 1 if in Terminal Server Session + protected int FramesForMillis(int milliseconds) + { + // If we are in a Terminal Server Session we return 1 + if (IsTerminalServerSession) + { + return 1; + } + + return milliseconds / VRefresh; + } + + /// + /// Initialize the animation + /// + protected AnimatingForm() + { + Load += delegate + { + if (!EnableAnimation) + { + return; + } + + _timer = new Timer + { + Interval = 1000 / VRefresh + }; + _timer.Tick += timer_Tick; + _timer.Start(); + }; + + // Unregister at close + FormClosing += delegate { _timer?.Stop(); }; + } + + /// + /// The tick handler initiates the animation. + /// + /// + /// + private void timer_Tick(object sender, EventArgs e) + { + try + { + Animate(); + } + catch (Exception ex) + { + Log.Warn("An exception occured while animating:", ex); + } + } + + /// + /// This method will be called every frame, so implement your animation/redraw logic here. + /// + protected virtual void Animate() + { + throw new NotImplementedException(); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/BackgroundForm.Designer.cs b/src/Greenshot.Base/Controls/BackgroundForm.Designer.cs similarity index 96% rename from src/GreenshotPlugin/Controls/BackgroundForm.Designer.cs rename to src/Greenshot.Base/Controls/BackgroundForm.Designer.cs index cafbb6e18..1bbde20ad 100644 --- a/src/GreenshotPlugin/Controls/BackgroundForm.Designer.cs +++ b/src/Greenshot.Base/Controls/BackgroundForm.Designer.cs @@ -1,96 +1,96 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -namespace GreenshotPlugin.Controls -{ - partial class BackgroundForm - { - /// - /// Designer variable used to keep track of non-visual components. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Disposes resources used by the form. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing) { - if (components != null) { - components.Dispose(); - } - } - base.Dispose(disposing); - } - - /// - /// This method is required for Windows Forms designer support. - /// Do not change the method contents inside the source code editor. The Forms designer might - /// not be able to load this method if it was changed manually. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - this.label_pleasewait = new System.Windows.Forms.Label(); - this.timer_checkforclose = new System.Windows.Forms.Timer(this.components); - this.SuspendLayout(); - // - // label_pleasewait - // - this.label_pleasewait.Dock = System.Windows.Forms.DockStyle.Fill; - this.label_pleasewait.Location = new System.Drawing.Point(0, 0); - this.label_pleasewait.Name = "label_pleasewait"; - this.label_pleasewait.Padding = new System.Windows.Forms.Padding(10); - this.label_pleasewait.Size = new System.Drawing.Size(90, 33); - this.label_pleasewait.TabIndex = 0; - this.label_pleasewait.Text = "Please wait..."; - this.label_pleasewait.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - this.label_pleasewait.UseWaitCursor = true; - // - // timer_checkforclose - // - this.timer_checkforclose.Interval = 200; - this.timer_checkforclose.Tick += new System.EventHandler(this.Timer_checkforcloseTick); - // - // BackgroundForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(169, 52); - this.ControlBox = true; - this.Controls.Add(this.label_pleasewait); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "BackgroundForm"; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Greenshot"; - this.TopMost = true; - this.UseWaitCursor = true; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.BackgroundFormFormClosing); - this.ResumeLayout(false); - this.PerformLayout(); - } - private System.Windows.Forms.Timer timer_checkforclose; - private System.Windows.Forms.Label label_pleasewait; - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +namespace Greenshot.Base.Controls +{ + partial class BackgroundForm + { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.label_pleasewait = new System.Windows.Forms.Label(); + this.timer_checkforclose = new System.Windows.Forms.Timer(this.components); + this.SuspendLayout(); + // + // label_pleasewait + // + this.label_pleasewait.Dock = System.Windows.Forms.DockStyle.Fill; + this.label_pleasewait.Location = new System.Drawing.Point(0, 0); + this.label_pleasewait.Name = "label_pleasewait"; + this.label_pleasewait.Padding = new System.Windows.Forms.Padding(10); + this.label_pleasewait.Size = new System.Drawing.Size(90, 33); + this.label_pleasewait.TabIndex = 0; + this.label_pleasewait.Text = "Please wait..."; + this.label_pleasewait.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.label_pleasewait.UseWaitCursor = true; + // + // timer_checkforclose + // + this.timer_checkforclose.Interval = 200; + this.timer_checkforclose.Tick += new System.EventHandler(this.Timer_checkforcloseTick); + // + // BackgroundForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(169, 52); + this.ControlBox = true; + this.Controls.Add(this.label_pleasewait); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "BackgroundForm"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Greenshot"; + this.TopMost = true; + this.UseWaitCursor = true; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.BackgroundFormFormClosing); + this.ResumeLayout(false); + this.PerformLayout(); + } + private System.Windows.Forms.Timer timer_checkforclose; + private System.Windows.Forms.Label label_pleasewait; + } +} diff --git a/src/GreenshotPlugin/Controls/BackgroundForm.cs b/src/Greenshot.Base/Controls/BackgroundForm.cs similarity index 95% rename from src/GreenshotPlugin/Controls/BackgroundForm.cs rename to src/Greenshot.Base/Controls/BackgroundForm.cs index beda8b73b..45691c8e3 100644 --- a/src/GreenshotPlugin/Controls/BackgroundForm.cs +++ b/src/Greenshot.Base/Controls/BackgroundForm.cs @@ -1,99 +1,99 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Windows.Forms; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Controls -{ - /// - /// Description of PleaseWaitForm. - /// - public sealed partial class BackgroundForm : Form - { - private volatile bool _shouldClose; - - public BackgroundForm(string title, string text) - { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - Icon = GreenshotResources.GetGreenshotIcon(); - _shouldClose = false; - Text = title; - label_pleasewait.Text = text; - FormClosing += PreventFormClose; - timer_checkforclose.Start(); - } - - // Can be used instead of ShowDialog - public new void Show() - { - base.Show(); - bool positioned = false; - foreach (Screen screen in Screen.AllScreens) - { - if (screen.Bounds.Contains(Cursor.Position)) - { - positioned = true; - Location = new Point(screen.Bounds.X + (screen.Bounds.Width / 2) - (Width / 2), screen.Bounds.Y + (screen.Bounds.Height / 2) - (Height / 2)); - break; - } - } - - if (!positioned) - { - Location = new Point(Cursor.Position.X - Width / 2, Cursor.Position.Y - Height / 2); - } - } - - private void PreventFormClose(object sender, FormClosingEventArgs e) - { - if (!_shouldClose) - { - e.Cancel = true; - } - } - - private void Timer_checkforcloseTick(object sender, EventArgs e) - { - if (_shouldClose) - { - timer_checkforclose.Stop(); - BeginInvoke(new EventHandler(delegate { Close(); })); - } - } - - public void CloseDialog() - { - _shouldClose = true; - Application.DoEvents(); - } - - private void BackgroundFormFormClosing(object sender, FormClosingEventArgs e) - { - timer_checkforclose.Stop(); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Controls +{ + /// + /// Description of PleaseWaitForm. + /// + public sealed partial class BackgroundForm : Form + { + private volatile bool _shouldClose; + + public BackgroundForm(string title, string text) + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + Icon = GreenshotResources.GetGreenshotIcon(); + _shouldClose = false; + Text = title; + label_pleasewait.Text = text; + FormClosing += PreventFormClose; + timer_checkforclose.Start(); + } + + // Can be used instead of ShowDialog + public new void Show() + { + base.Show(); + bool positioned = false; + foreach (Screen screen in Screen.AllScreens) + { + if (screen.Bounds.Contains(Cursor.Position)) + { + positioned = true; + Location = new Point(screen.Bounds.X + (screen.Bounds.Width / 2) - (Width / 2), screen.Bounds.Y + (screen.Bounds.Height / 2) - (Height / 2)); + break; + } + } + + if (!positioned) + { + Location = new Point(Cursor.Position.X - Width / 2, Cursor.Position.Y - Height / 2); + } + } + + private void PreventFormClose(object sender, FormClosingEventArgs e) + { + if (!_shouldClose) + { + e.Cancel = true; + } + } + + private void Timer_checkforcloseTick(object sender, EventArgs e) + { + if (_shouldClose) + { + timer_checkforclose.Stop(); + BeginInvoke(new EventHandler(delegate { Close(); })); + } + } + + public void CloseDialog() + { + _shouldClose = true; + Application.DoEvents(); + } + + private void BackgroundFormFormClosing(object sender, FormClosingEventArgs e) + { + timer_checkforclose.Stop(); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/ExtendedWebBrowser.cs b/src/Greenshot.Base/Controls/ExtendedWebBrowser.cs similarity index 94% rename from src/GreenshotPlugin/Controls/ExtendedWebBrowser.cs rename to src/Greenshot.Base/Controls/ExtendedWebBrowser.cs index e5bc1c622..0e4d439ae 100644 --- a/src/GreenshotPlugin/Controls/ExtendedWebBrowser.cs +++ b/src/Greenshot.Base/Controls/ExtendedWebBrowser.cs @@ -1,68 +1,68 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Windows.Forms; -using GreenshotPlugin.Interop; - -namespace GreenshotPlugin.Controls -{ - public class ExtendedWebBrowser : WebBrowser - { - protected class ExtendedWebBrowserSite : WebBrowserSite, IOleCommandTarget - { - private const int OLECMDID_SHOWSCRIPTERROR = 40; - - private static readonly Guid CGID_DocHostCommandHandler = new Guid("F38BC242-B950-11D1-8918-00C04FC2C836"); - - private const int S_OK = 0; - private const int OLECMDERR_E_NOTSUPPORTED = (-2147221248); - - public ExtendedWebBrowserSite(WebBrowser wb) : base(wb) - { - } - - public int QueryStatus(Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText) - { - return OLECMDERR_E_NOTSUPPORTED; - } - - public int Exec(Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) - { - if (pguidCmdGroup == CGID_DocHostCommandHandler) - { - if (nCmdID == OLECMDID_SHOWSCRIPTERROR) - { - // do not need to alter pvaOut as the docs says, enough to return S_OK here - return S_OK; - } - } - - return OLECMDERR_E_NOTSUPPORTED; - } - } - - protected override WebBrowserSiteBase CreateWebBrowserSiteBase() - { - return new ExtendedWebBrowserSite(this); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows.Forms; +using Greenshot.Base.Interop; + +namespace Greenshot.Base.Controls +{ + public class ExtendedWebBrowser : WebBrowser + { + protected class ExtendedWebBrowserSite : WebBrowserSite, IOleCommandTarget + { + private const int OLECMDID_SHOWSCRIPTERROR = 40; + + private static readonly Guid CGID_DocHostCommandHandler = new Guid("F38BC242-B950-11D1-8918-00C04FC2C836"); + + private const int S_OK = 0; + private const int OLECMDERR_E_NOTSUPPORTED = (-2147221248); + + public ExtendedWebBrowserSite(WebBrowser wb) : base(wb) + { + } + + public int QueryStatus(Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText) + { + return OLECMDERR_E_NOTSUPPORTED; + } + + public int Exec(Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (pguidCmdGroup == CGID_DocHostCommandHandler) + { + if (nCmdID == OLECMDID_SHOWSCRIPTERROR) + { + // do not need to alter pvaOut as the docs says, enough to return S_OK here + return S_OK; + } + } + + return OLECMDERR_E_NOTSUPPORTED; + } + } + + protected override WebBrowserSiteBase CreateWebBrowserSiteBase() + { + return new ExtendedWebBrowserSite(this); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/FormWithoutActivation.cs b/src/Greenshot.Base/Controls/FormWithoutActivation.cs similarity index 94% rename from src/GreenshotPlugin/Controls/FormWithoutActivation.cs rename to src/Greenshot.Base/Controls/FormWithoutActivation.cs index 06cde98a2..f9fee5ef5 100644 --- a/src/GreenshotPlugin/Controls/FormWithoutActivation.cs +++ b/src/Greenshot.Base/Controls/FormWithoutActivation.cs @@ -1,36 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls -{ - /// - /// FormWithoutActivation is exactly like a normal form, but doesn't activate (steal focus) - /// - public class FormWithoutActivation : Form - { - protected override bool ShowWithoutActivation - { - get { return true; } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + /// + /// FormWithoutActivation is exactly like a normal form, but doesn't activate (steal focus) + /// + public class FormWithoutActivation : Form + { + protected override bool ShowWithoutActivation + { + get { return true; } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotButton.cs b/src/Greenshot.Base/Controls/GreenshotButton.cs similarity index 94% rename from src/GreenshotPlugin/Controls/GreenshotButton.cs rename to src/Greenshot.Base/Controls/GreenshotButton.cs index 9849f2c50..703be11e5 100644 --- a/src/GreenshotPlugin/Controls/GreenshotButton.cs +++ b/src/Greenshot.Base/Controls/GreenshotButton.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls -{ - public class GreenshotButton : Button, IGreenshotLanguageBindable - { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotButton : Button, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotCheckBox.cs b/src/Greenshot.Base/Controls/GreenshotCheckBox.cs similarity index 95% rename from src/GreenshotPlugin/Controls/GreenshotCheckBox.cs rename to src/Greenshot.Base/Controls/GreenshotCheckBox.cs index f0e4563b9..c7552fb74 100644 --- a/src/GreenshotPlugin/Controls/GreenshotCheckBox.cs +++ b/src/Greenshot.Base/Controls/GreenshotCheckBox.cs @@ -1,41 +1,41 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls -{ - /// - /// Description of GreenshotCheckbox. - /// - public class GreenshotCheckBox : CheckBox, IGreenshotLanguageBindable, IGreenshotConfigBindable - { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - - [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] - public string SectionName { get; set; } = "Core"; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] - public string PropertyName { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + /// + /// Description of GreenshotCheckbox. + /// + public class GreenshotCheckBox : CheckBox, IGreenshotLanguageBindable, IGreenshotConfigBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotColumnSorter.cs b/src/Greenshot.Base/Controls/GreenshotColumnSorter.cs similarity index 99% rename from src/GreenshotPlugin/Controls/GreenshotColumnSorter.cs rename to src/Greenshot.Base/Controls/GreenshotColumnSorter.cs index 02c8f16ef..f33379cda 100644 --- a/src/GreenshotPlugin/Controls/GreenshotColumnSorter.cs +++ b/src/Greenshot.Base/Controls/GreenshotColumnSorter.cs @@ -22,7 +22,7 @@ using System.Collections; using System.Windows.Forms; -namespace GreenshotPlugin.Controls +namespace Greenshot.Base.Controls { /// /// This class is an implementation of the 'IComparer' interface. diff --git a/src/GreenshotPlugin/Controls/GreenshotComboBox.cs b/src/Greenshot.Base/Controls/GreenshotComboBox.cs similarity index 95% rename from src/GreenshotPlugin/Controls/GreenshotComboBox.cs rename to src/Greenshot.Base/Controls/GreenshotComboBox.cs index 5fc0437b6..4c464544c 100644 --- a/src/GreenshotPlugin/Controls/GreenshotComboBox.cs +++ b/src/Greenshot.Base/Controls/GreenshotComboBox.cs @@ -1,116 +1,116 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.ComponentModel; -using System.Windows.Forms; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Controls -{ - public class GreenshotComboBox : ComboBox, IGreenshotConfigBindable - { - private Type _enumType; - private Enum _selectedEnum; - - [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] - public string SectionName { get; set; } = "Core"; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] - public string PropertyName { get; set; } - - public GreenshotComboBox() - { - SelectedIndexChanged += delegate { StoreSelectedEnum(); }; - } - - public void SetValue(Enum currentValue) - { - if (currentValue != null) - { - _selectedEnum = currentValue; - SelectedItem = Language.Translate(currentValue); - } - } - - /// - /// This is a method to popululate the ComboBox - /// with the items from the enumeration - /// - /// TEnum to populate with - public void Populate(Type enumType) - { - // Store the enum-type, so we can work with it - _enumType = enumType; - - var availableValues = Enum.GetValues(enumType); - Items.Clear(); - foreach (var enumValue in availableValues) - { - Items.Add(Language.Translate((Enum) enumValue)); - } - } - - /// - /// Store the selected value internally - /// - private void StoreSelectedEnum() - { - string enumTypeName = _enumType.Name; - string selectedValue = SelectedItem as string; - var availableValues = Enum.GetValues(_enumType); - object returnValue = null; - - try - { - returnValue = Enum.Parse(_enumType, selectedValue); - } - catch (Exception) - { - // Ignore - } - - foreach (Enum enumValue in availableValues) - { - string enumKey = enumTypeName + "." + enumValue; - if (Language.HasKey(enumKey)) - { - string translation = Language.GetString(enumTypeName + "." + enumValue); - if (translation.Equals(selectedValue)) - { - returnValue = enumValue; - } - } - } - - _selectedEnum = (Enum) returnValue; - } - - /// - /// Get the selected enum value from the combobox, uses generics - /// - /// The enum value of the combobox - public Enum GetSelectedEnum() - { - return _selectedEnum; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Windows.Forms; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Controls +{ + public class GreenshotComboBox : ComboBox, IGreenshotConfigBindable + { + private Type _enumType; + private Enum _selectedEnum; + + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + + public GreenshotComboBox() + { + SelectedIndexChanged += delegate { StoreSelectedEnum(); }; + } + + public void SetValue(Enum currentValue) + { + if (currentValue != null) + { + _selectedEnum = currentValue; + SelectedItem = Language.Translate(currentValue); + } + } + + /// + /// This is a method to popululate the ComboBox + /// with the items from the enumeration + /// + /// TEnum to populate with + public void Populate(Type enumType) + { + // Store the enum-type, so we can work with it + _enumType = enumType; + + var availableValues = Enum.GetValues(enumType); + Items.Clear(); + foreach (var enumValue in availableValues) + { + Items.Add(Language.Translate((Enum) enumValue)); + } + } + + /// + /// Store the selected value internally + /// + private void StoreSelectedEnum() + { + string enumTypeName = _enumType.Name; + string selectedValue = SelectedItem as string; + var availableValues = Enum.GetValues(_enumType); + object returnValue = null; + + try + { + returnValue = Enum.Parse(_enumType, selectedValue); + } + catch (Exception) + { + // Ignore + } + + foreach (Enum enumValue in availableValues) + { + string enumKey = enumTypeName + "." + enumValue; + if (Language.HasKey(enumKey)) + { + string translation = Language.GetString(enumTypeName + "." + enumValue); + if (translation.Equals(selectedValue)) + { + returnValue = enumValue; + } + } + } + + _selectedEnum = (Enum) returnValue; + } + + /// + /// Get the selected enum value from the combobox, uses generics + /// + /// The enum value of the combobox + public Enum GetSelectedEnum() + { + return _selectedEnum; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotForm.cs b/src/Greenshot.Base/Controls/GreenshotForm.cs similarity index 96% rename from src/GreenshotPlugin/Controls/GreenshotForm.cs rename to src/Greenshot.Base/Controls/GreenshotForm.cs index c91a48ddc..9850e71ed 100644 --- a/src/GreenshotPlugin/Controls/GreenshotForm.cs +++ b/src/Greenshot.Base/Controls/GreenshotForm.cs @@ -1,643 +1,643 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Windows.Forms; -using System.Reflection; -using GreenshotPlugin.Core; -using System.ComponentModel; -using System.ComponentModel.Design; -using System.IO; -using GreenshotPlugin.IniFile; -using log4net; - -namespace GreenshotPlugin.Controls -{ - /// - /// This form is used for automatically binding the elements of the form to the language - /// - public class GreenshotForm : Form, IGreenshotLanguageBindable - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(GreenshotForm)); - protected static CoreConfiguration coreConfiguration; - private static readonly IDictionary reflectionCache = new Dictionary(); - private IComponentChangeService m_changeService; - private bool _isDesignModeLanguageSet; - private bool _applyLanguageManually; - private bool _storeFieldsManually; - private IDictionary _designTimeControls; - private IDictionary _designTimeToolStripItems; - - static GreenshotForm() - { - if (!IsInDesignMode) - { - coreConfiguration = IniConfig.GetIniSection(); - } - } - - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - - /// - /// Used to check the designmode during a constructor - /// - /// - protected static bool IsInDesignMode - { - get - { - return (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) > -1) || - (Application.ExecutablePath.IndexOf("sharpdevelop.exe", StringComparison.OrdinalIgnoreCase) > -1 || - (Application.ExecutablePath.IndexOf("wdexpress.exe", StringComparison.OrdinalIgnoreCase) > -1)); - } - } - - protected bool ManualLanguageApply - { - get { return _applyLanguageManually; } - set { _applyLanguageManually = value; } - } - - protected bool ManualStoreFields - { - get { return _storeFieldsManually; } - set { _storeFieldsManually = value; } - } - - /// - /// When this is set, the form will be brought to the foreground as soon as it is shown. - /// - protected bool ToFront { get; set; } - - /// - /// Code to initialize the language etc during design time - /// - protected void InitializeForDesigner() - { - if (!DesignMode) return; - _designTimeControls = new Dictionary(); - _designTimeToolStripItems = new Dictionary(); - try - { - ITypeResolutionService typeResService = GetService(typeof(ITypeResolutionService)) as ITypeResolutionService; - - // Add a hard-path if you are using SharpDevelop - // Language.AddLanguageFilePath(@"C:\Greenshot\Greenshot\Languages"); - - // this "type" - Assembly currentAssembly = GetType().Assembly; - if (typeResService != null) - { - string assemblyPath = typeResService.GetPathOfAssembly(currentAssembly.GetName()); - string assemblyDirectory = Path.GetDirectoryName(assemblyPath); - if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Greenshot\Languages\"))) - { - Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Greenshot\Languages\")); - } - - if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Languages\"))) - { - Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Languages\")); - } - } - } - catch (Exception ex) - { - MessageBox.Show(ex.Message); - } - } - - /// - /// This override is only for the design-time of the form - /// - /// - protected override void OnPaint(PaintEventArgs e) - { - if (DesignMode) - { - if (!_isDesignModeLanguageSet) - { - _isDesignModeLanguageSet = true; - try - { - ApplyLanguage(); - } - catch (Exception) - { - // ignored - } - } - } - - base.OnPaint(e); - } - - protected override void OnLoad(EventArgs e) - { - // Every GreenshotForm should have it's default icon - // And it might not ne needed for a Tool Window, but still for the task manager / switcher it's important - Icon = GreenshotResources.GetGreenshotIcon(); - if (!DesignMode) - { - if (!_applyLanguageManually) - { - ApplyLanguage(); - } - - FillFields(); - base.OnLoad(e); - } - else - { - LOG.Info("OnLoad called from designer."); - InitializeForDesigner(); - base.OnLoad(e); - ApplyLanguage(); - } - } - - /// - /// Make sure the form is visible, if this is wanted - /// - /// EventArgs - protected override void OnShown(EventArgs e) - { - base.OnShown(e); - if (ToFront) - { - WindowDetails.ToForeground(Handle); - } - } - - /// - /// check if the form was closed with an OK, if so store the values in the GreenshotControls - /// - /// - protected override void OnClosed(EventArgs e) - { - if (!DesignMode && !_storeFieldsManually) - { - if (DialogResult == DialogResult.OK) - { - LOG.Info("Form was closed with OK: storing field values."); - StoreFields(); - } - } - - base.OnClosed(e); - } - - /// - /// This override allows the control to register event handlers for IComponentChangeService events - /// at the time the control is sited, which happens only in design mode. - /// - public override ISite Site - { - get { return base.Site; } - set - { - // Clear any component change event handlers. - ClearChangeNotifications(); - - // Set the new Site value. - base.Site = value; - - m_changeService = (IComponentChangeService) GetService(typeof(IComponentChangeService)); - - // Register event handlers for component change events. - RegisterChangeNotifications(); - } - } - - private void ClearChangeNotifications() - { - // The m_changeService value is null when not in design mode, - // as the IComponentChangeService is only available at design time. - m_changeService = (IComponentChangeService) GetService(typeof(IComponentChangeService)); - - // Clear our the component change events to prepare for re-siting. - if (m_changeService != null) - { - m_changeService.ComponentChanged -= OnComponentChanged; - m_changeService.ComponentAdded -= OnComponentAdded; - } - } - - private void RegisterChangeNotifications() - { - // Register the event handlers for the IComponentChangeService events - if (m_changeService != null) - { - m_changeService.ComponentChanged += OnComponentChanged; - m_changeService.ComponentAdded += OnComponentAdded; - } - } - - /// - /// This method handles the OnComponentChanged event to display a notification. - /// - /// - /// - private void OnComponentChanged(object sender, ComponentChangedEventArgs ce) - { - if (((IComponent) ce.Component)?.Site == null || ce.Member == null) return; - if (!"LanguageKey".Equals(ce.Member.Name)) return; - if (ce.Component is Control control) - { - LOG.InfoFormat("Changing LanguageKey for {0} to {1}", control.Name, ce.NewValue); - ApplyLanguage(control, (string) ce.NewValue); - } - else - { - if (ce.Component is ToolStripItem item) - { - LOG.InfoFormat("Changing LanguageKey for {0} to {1}", item.Name, ce.NewValue); - ApplyLanguage(item, (string) ce.NewValue); - } - else - { - LOG.InfoFormat("Not possible to changing LanguageKey for {0} to {1}", ce.Component.GetType(), ce.NewValue); - } - } - } - - private void OnComponentAdded(object sender, ComponentEventArgs ce) - { - if (ce.Component?.Site == null) return; - if (ce.Component is Control control) - { - if (!_designTimeControls.ContainsKey(control.Name)) - { - _designTimeControls.Add(control.Name, control); - } - else - { - _designTimeControls[control.Name] = control; - } - } - else - { - if (ce.Component is ToolStripItem stripItem) - { - ToolStripItem item = stripItem; - if (!_designTimeControls.ContainsKey(item.Name)) - { - _designTimeToolStripItems.Add(item.Name, item); - } - else - { - _designTimeToolStripItems[item.Name] = item; - } - } - } - } - - // Clean up any resources being used. - protected override void Dispose(bool disposing) - { - if (disposing) - { - ClearChangeNotifications(); - } - - base.Dispose(disposing); - } - - protected void ApplyLanguage(ToolStripItem applyTo, string languageKey) - { - string langString; - if (!string.IsNullOrEmpty(languageKey)) - { - if (!Language.TryGetString(languageKey, out langString)) - { - LOG.WarnFormat("Unknown language key '{0}' configured for control '{1}', this might be okay.", languageKey, applyTo.Name); - return; - } - - applyTo.Text = langString; - } - else - { - // Fallback to control name! - if (Language.TryGetString(applyTo.Name, out langString)) - { - applyTo.Text = langString; - return; - } - - if (!DesignMode) - { - LOG.DebugFormat("Greenshot control without language key: {0}", applyTo.Name); - } - } - } - - protected void ApplyLanguage(ToolStripItem applyTo) - { - if (applyTo is IGreenshotLanguageBindable languageBindable) - { - ApplyLanguage(applyTo, languageBindable.LanguageKey); - } - } - - protected void ApplyLanguage(Control applyTo) - { - if (!(applyTo is IGreenshotLanguageBindable languageBindable)) - { - // check if it's a menu! - if (!(applyTo is ToolStrip toolStrip)) - { - return; - } - - foreach (ToolStripItem item in toolStrip.Items) - { - ApplyLanguage(item); - } - - return; - } - - // Apply language text to the control - ApplyLanguage(applyTo, languageBindable.LanguageKey); - - // Repopulate the combox boxes - if (applyTo is IGreenshotConfigBindable configBindable && applyTo is GreenshotComboBox comboxBox) - { - if (!string.IsNullOrEmpty(configBindable.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) - { - IniSection section = IniConfig.GetIniSection(configBindable.SectionName); - if (section != null) - { - // Only update the language, so get the actual value and than repopulate - Enum currentValue = comboxBox.GetSelectedEnum(); - comboxBox.Populate(section.Values[configBindable.PropertyName].ValueType); - comboxBox.SetValue(currentValue); - } - } - } - } - - /// - /// Helper method to cache the fieldinfo values, so we don't need to reflect all the time! - /// - /// - /// - private static FieldInfo[] GetCachedFields(Type typeToGetFieldsFor) - { - if (!reflectionCache.TryGetValue(typeToGetFieldsFor, out var fields)) - { - fields = typeToGetFieldsFor.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - reflectionCache.Add(typeToGetFieldsFor, fields); - } - - return fields; - } - - /// - /// Apply all the language settings to the "Greenshot" Controls on this form - /// - protected void ApplyLanguage() - { - SuspendLayout(); - try - { - // Set title of the form - if (!string.IsNullOrEmpty(LanguageKey) && Language.TryGetString(LanguageKey, out var langString)) - { - Text = langString; - } - - // Reset the text values for all GreenshotControls - foreach (FieldInfo field in GetCachedFields(GetType())) - { - object controlObject = field.GetValue(this); - if (controlObject == null) - { - LOG.DebugFormat("No value: {0}", field.Name); - continue; - } - - if (!(controlObject is Control applyToControl)) - { - ToolStripItem applyToItem = controlObject as ToolStripItem; - if (applyToItem == null) - { - LOG.DebugFormat("No Control or ToolStripItem: {0}", field.Name); - continue; - } - - ApplyLanguage(applyToItem); - } - else - { - ApplyLanguage(applyToControl); - } - } - - if (DesignMode) - { - foreach (Control designControl in _designTimeControls.Values) - { - ApplyLanguage(designControl); - } - - foreach (ToolStripItem designToolStripItem in _designTimeToolStripItems.Values) - { - ApplyLanguage(designToolStripItem); - } - } - } - finally - { - ResumeLayout(); - } - } - - /// - /// Apply the language text to supplied control - /// - protected void ApplyLanguage(Control applyTo, string languageKey) - { - string langString; - if (!string.IsNullOrEmpty(languageKey)) - { - if (!Language.TryGetString(languageKey, out langString)) - { - LOG.WarnFormat("Wrong language key '{0}' configured for control '{1}'", languageKey, applyTo.Name); - return; - } - - applyTo.Text = langString; - } - else - { - // Fallback to control name! - if (Language.TryGetString(applyTo.Name, out langString)) - { - applyTo.Text = langString; - return; - } - - if (!DesignMode) - { - LOG.DebugFormat("Greenshot control without language key: {0}", applyTo.Name); - } - } - } - - /// - /// Fill all GreenshotControls with the values from the configuration - /// - protected void FillFields() - { - foreach (FieldInfo field in GetCachedFields(GetType())) - { - var controlObject = field.GetValue(this); - IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; - if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) - { - IniSection section = IniConfig.GetIniSection(configBindable.SectionName); - if (section != null) - { - if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) - { - LOG.DebugFormat("Wrong property '{0}' configured for field '{1}'", configBindable.PropertyName, field.Name); - continue; - } - - if (controlObject is CheckBox checkBox) - { - checkBox.Checked = (bool) iniValue.Value; - checkBox.Enabled = !iniValue.IsFixed; - continue; - } - - if (controlObject is RadioButton radíoButton) - { - radíoButton.Checked = (bool) iniValue.Value; - radíoButton.Enabled = !iniValue.IsFixed; - continue; - } - - if (controlObject is TextBox textBox) - { - if (controlObject is HotkeyControl hotkeyControl) - { - string hotkeyValue = (string) iniValue.Value; - if (!string.IsNullOrEmpty(hotkeyValue)) - { - hotkeyControl.SetHotkey(hotkeyValue); - hotkeyControl.Enabled = !iniValue.IsFixed; - } - - continue; - } - - textBox.Text = iniValue.ToString(); - textBox.Enabled = !iniValue.IsFixed; - continue; - } - - if (controlObject is GreenshotComboBox comboxBox) - { - comboxBox.Populate(iniValue.ValueType); - comboxBox.SetValue((Enum) iniValue.Value); - comboxBox.Enabled = !iniValue.IsFixed; - } - } - } - } - - OnFieldsFilled(); - } - - protected virtual void OnFieldsFilled() - { - } - - /// - /// Store all GreenshotControl values to the configuration - /// - protected void StoreFields() - { - bool iniDirty = false; - foreach (FieldInfo field in GetCachedFields(GetType())) - { - var controlObject = field.GetValue(this); - IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; - - if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) - { - IniSection section = IniConfig.GetIniSection(configBindable.SectionName); - if (section != null) - { - if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) - { - continue; - } - - if (controlObject is CheckBox checkBox) - { - iniValue.Value = checkBox.Checked; - iniDirty = true; - continue; - } - - if (controlObject is RadioButton radioButton) - { - iniValue.Value = radioButton.Checked; - iniDirty = true; - continue; - } - - if (controlObject is TextBox textBox) - { - if (controlObject is HotkeyControl hotkeyControl) - { - iniValue.Value = hotkeyControl.ToString(); - iniDirty = true; - continue; - } - - iniValue.UseValueOrDefault(textBox.Text); - iniDirty = true; - continue; - } - - if (controlObject is GreenshotComboBox comboxBox) - { - iniValue.Value = comboxBox.GetSelectedEnum(); - iniDirty = true; - } - } - } - } - - if (iniDirty) - { - IniConfig.Save(); - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.IO; +using System.Reflection; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// This form is used for automatically binding the elements of the form to the language + /// + public class GreenshotForm : Form, IGreenshotLanguageBindable + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(GreenshotForm)); + protected static CoreConfiguration coreConfiguration; + private static readonly IDictionary reflectionCache = new Dictionary(); + private IComponentChangeService m_changeService; + private bool _isDesignModeLanguageSet; + private bool _applyLanguageManually; + private bool _storeFieldsManually; + private IDictionary _designTimeControls; + private IDictionary _designTimeToolStripItems; + + static GreenshotForm() + { + if (!IsInDesignMode) + { + coreConfiguration = IniConfig.GetIniSection(); + } + } + + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + + /// + /// Used to check the designmode during a constructor + /// + /// + protected static bool IsInDesignMode + { + get + { + return (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) > -1) || + (Application.ExecutablePath.IndexOf("sharpdevelop.exe", StringComparison.OrdinalIgnoreCase) > -1 || + (Application.ExecutablePath.IndexOf("wdexpress.exe", StringComparison.OrdinalIgnoreCase) > -1)); + } + } + + protected bool ManualLanguageApply + { + get { return _applyLanguageManually; } + set { _applyLanguageManually = value; } + } + + protected bool ManualStoreFields + { + get { return _storeFieldsManually; } + set { _storeFieldsManually = value; } + } + + /// + /// When this is set, the form will be brought to the foreground as soon as it is shown. + /// + protected bool ToFront { get; set; } + + /// + /// Code to initialize the language etc during design time + /// + protected void InitializeForDesigner() + { + if (!DesignMode) return; + _designTimeControls = new Dictionary(); + _designTimeToolStripItems = new Dictionary(); + try + { + ITypeResolutionService typeResService = GetService(typeof(ITypeResolutionService)) as ITypeResolutionService; + + // Add a hard-path if you are using SharpDevelop + // Language.AddLanguageFilePath(@"C:\Greenshot\Greenshot\Languages"); + + // this "type" + Assembly currentAssembly = GetType().Assembly; + if (typeResService != null) + { + string assemblyPath = typeResService.GetPathOfAssembly(currentAssembly.GetName()); + string assemblyDirectory = Path.GetDirectoryName(assemblyPath); + if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Greenshot\Languages\"))) + { + Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Greenshot\Languages\")); + } + + if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Languages\"))) + { + Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Languages\")); + } + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + + /// + /// This override is only for the design-time of the form + /// + /// + protected override void OnPaint(PaintEventArgs e) + { + if (DesignMode) + { + if (!_isDesignModeLanguageSet) + { + _isDesignModeLanguageSet = true; + try + { + ApplyLanguage(); + } + catch (Exception) + { + // ignored + } + } + } + + base.OnPaint(e); + } + + protected override void OnLoad(EventArgs e) + { + // Every GreenshotForm should have it's default icon + // And it might not ne needed for a Tool Window, but still for the task manager / switcher it's important + Icon = GreenshotResources.GetGreenshotIcon(); + if (!DesignMode) + { + if (!_applyLanguageManually) + { + ApplyLanguage(); + } + + FillFields(); + base.OnLoad(e); + } + else + { + LOG.Info("OnLoad called from designer."); + InitializeForDesigner(); + base.OnLoad(e); + ApplyLanguage(); + } + } + + /// + /// Make sure the form is visible, if this is wanted + /// + /// EventArgs + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + if (ToFront) + { + WindowDetails.ToForeground(Handle); + } + } + + /// + /// check if the form was closed with an OK, if so store the values in the GreenshotControls + /// + /// + protected override void OnClosed(EventArgs e) + { + if (!DesignMode && !_storeFieldsManually) + { + if (DialogResult == DialogResult.OK) + { + LOG.Info("Form was closed with OK: storing field values."); + StoreFields(); + } + } + + base.OnClosed(e); + } + + /// + /// This override allows the control to register event handlers for IComponentChangeService events + /// at the time the control is sited, which happens only in design mode. + /// + public override ISite Site + { + get { return base.Site; } + set + { + // Clear any component change event handlers. + ClearChangeNotifications(); + + // Set the new Site value. + base.Site = value; + + m_changeService = (IComponentChangeService) GetService(typeof(IComponentChangeService)); + + // Register event handlers for component change events. + RegisterChangeNotifications(); + } + } + + private void ClearChangeNotifications() + { + // The m_changeService value is null when not in design mode, + // as the IComponentChangeService is only available at design time. + m_changeService = (IComponentChangeService) GetService(typeof(IComponentChangeService)); + + // Clear our the component change events to prepare for re-siting. + if (m_changeService != null) + { + m_changeService.ComponentChanged -= OnComponentChanged; + m_changeService.ComponentAdded -= OnComponentAdded; + } + } + + private void RegisterChangeNotifications() + { + // Register the event handlers for the IComponentChangeService events + if (m_changeService != null) + { + m_changeService.ComponentChanged += OnComponentChanged; + m_changeService.ComponentAdded += OnComponentAdded; + } + } + + /// + /// This method handles the OnComponentChanged event to display a notification. + /// + /// + /// + private void OnComponentChanged(object sender, ComponentChangedEventArgs ce) + { + if (((IComponent) ce.Component)?.Site == null || ce.Member == null) return; + if (!"LanguageKey".Equals(ce.Member.Name)) return; + if (ce.Component is Control control) + { + LOG.InfoFormat("Changing LanguageKey for {0} to {1}", control.Name, ce.NewValue); + ApplyLanguage(control, (string) ce.NewValue); + } + else + { + if (ce.Component is ToolStripItem item) + { + LOG.InfoFormat("Changing LanguageKey for {0} to {1}", item.Name, ce.NewValue); + ApplyLanguage(item, (string) ce.NewValue); + } + else + { + LOG.InfoFormat("Not possible to changing LanguageKey for {0} to {1}", ce.Component.GetType(), ce.NewValue); + } + } + } + + private void OnComponentAdded(object sender, ComponentEventArgs ce) + { + if (ce.Component?.Site == null) return; + if (ce.Component is Control control) + { + if (!_designTimeControls.ContainsKey(control.Name)) + { + _designTimeControls.Add(control.Name, control); + } + else + { + _designTimeControls[control.Name] = control; + } + } + else + { + if (ce.Component is ToolStripItem stripItem) + { + ToolStripItem item = stripItem; + if (!_designTimeControls.ContainsKey(item.Name)) + { + _designTimeToolStripItems.Add(item.Name, item); + } + else + { + _designTimeToolStripItems[item.Name] = item; + } + } + } + } + + // Clean up any resources being used. + protected override void Dispose(bool disposing) + { + if (disposing) + { + ClearChangeNotifications(); + } + + base.Dispose(disposing); + } + + protected void ApplyLanguage(ToolStripItem applyTo, string languageKey) + { + string langString; + if (!string.IsNullOrEmpty(languageKey)) + { + if (!Language.TryGetString(languageKey, out langString)) + { + LOG.WarnFormat("Unknown language key '{0}' configured for control '{1}', this might be okay.", languageKey, applyTo.Name); + return; + } + + applyTo.Text = langString; + } + else + { + // Fallback to control name! + if (Language.TryGetString(applyTo.Name, out langString)) + { + applyTo.Text = langString; + return; + } + + if (!DesignMode) + { + LOG.DebugFormat("Greenshot control without language key: {0}", applyTo.Name); + } + } + } + + protected void ApplyLanguage(ToolStripItem applyTo) + { + if (applyTo is IGreenshotLanguageBindable languageBindable) + { + ApplyLanguage(applyTo, languageBindable.LanguageKey); + } + } + + protected void ApplyLanguage(Control applyTo) + { + if (!(applyTo is IGreenshotLanguageBindable languageBindable)) + { + // check if it's a menu! + if (!(applyTo is ToolStrip toolStrip)) + { + return; + } + + foreach (ToolStripItem item in toolStrip.Items) + { + ApplyLanguage(item); + } + + return; + } + + // Apply language text to the control + ApplyLanguage(applyTo, languageBindable.LanguageKey); + + // Repopulate the combox boxes + if (applyTo is IGreenshotConfigBindable configBindable && applyTo is GreenshotComboBox comboxBox) + { + if (!string.IsNullOrEmpty(configBindable.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + { + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section != null) + { + // Only update the language, so get the actual value and than repopulate + Enum currentValue = comboxBox.GetSelectedEnum(); + comboxBox.Populate(section.Values[configBindable.PropertyName].ValueType); + comboxBox.SetValue(currentValue); + } + } + } + } + + /// + /// Helper method to cache the fieldinfo values, so we don't need to reflect all the time! + /// + /// + /// + private static FieldInfo[] GetCachedFields(Type typeToGetFieldsFor) + { + if (!reflectionCache.TryGetValue(typeToGetFieldsFor, out var fields)) + { + fields = typeToGetFieldsFor.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + reflectionCache.Add(typeToGetFieldsFor, fields); + } + + return fields; + } + + /// + /// Apply all the language settings to the "Greenshot" Controls on this form + /// + protected void ApplyLanguage() + { + SuspendLayout(); + try + { + // Set title of the form + if (!string.IsNullOrEmpty(LanguageKey) && Language.TryGetString(LanguageKey, out var langString)) + { + Text = langString; + } + + // Reset the text values for all GreenshotControls + foreach (FieldInfo field in GetCachedFields(GetType())) + { + object controlObject = field.GetValue(this); + if (controlObject == null) + { + LOG.DebugFormat("No value: {0}", field.Name); + continue; + } + + if (!(controlObject is Control applyToControl)) + { + ToolStripItem applyToItem = controlObject as ToolStripItem; + if (applyToItem == null) + { + LOG.DebugFormat("No Control or ToolStripItem: {0}", field.Name); + continue; + } + + ApplyLanguage(applyToItem); + } + else + { + ApplyLanguage(applyToControl); + } + } + + if (DesignMode) + { + foreach (Control designControl in _designTimeControls.Values) + { + ApplyLanguage(designControl); + } + + foreach (ToolStripItem designToolStripItem in _designTimeToolStripItems.Values) + { + ApplyLanguage(designToolStripItem); + } + } + } + finally + { + ResumeLayout(); + } + } + + /// + /// Apply the language text to supplied control + /// + protected void ApplyLanguage(Control applyTo, string languageKey) + { + string langString; + if (!string.IsNullOrEmpty(languageKey)) + { + if (!Language.TryGetString(languageKey, out langString)) + { + LOG.WarnFormat("Wrong language key '{0}' configured for control '{1}'", languageKey, applyTo.Name); + return; + } + + applyTo.Text = langString; + } + else + { + // Fallback to control name! + if (Language.TryGetString(applyTo.Name, out langString)) + { + applyTo.Text = langString; + return; + } + + if (!DesignMode) + { + LOG.DebugFormat("Greenshot control without language key: {0}", applyTo.Name); + } + } + } + + /// + /// Fill all GreenshotControls with the values from the configuration + /// + protected void FillFields() + { + foreach (FieldInfo field in GetCachedFields(GetType())) + { + var controlObject = field.GetValue(this); + IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; + if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + { + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section != null) + { + if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) + { + LOG.DebugFormat("Wrong property '{0}' configured for field '{1}'", configBindable.PropertyName, field.Name); + continue; + } + + if (controlObject is CheckBox checkBox) + { + checkBox.Checked = (bool) iniValue.Value; + checkBox.Enabled = !iniValue.IsFixed; + continue; + } + + if (controlObject is RadioButton radíoButton) + { + radíoButton.Checked = (bool) iniValue.Value; + radíoButton.Enabled = !iniValue.IsFixed; + continue; + } + + if (controlObject is TextBox textBox) + { + if (controlObject is HotkeyControl hotkeyControl) + { + string hotkeyValue = (string) iniValue.Value; + if (!string.IsNullOrEmpty(hotkeyValue)) + { + hotkeyControl.SetHotkey(hotkeyValue); + hotkeyControl.Enabled = !iniValue.IsFixed; + } + + continue; + } + + textBox.Text = iniValue.ToString(); + textBox.Enabled = !iniValue.IsFixed; + continue; + } + + if (controlObject is GreenshotComboBox comboxBox) + { + comboxBox.Populate(iniValue.ValueType); + comboxBox.SetValue((Enum) iniValue.Value); + comboxBox.Enabled = !iniValue.IsFixed; + } + } + } + } + + OnFieldsFilled(); + } + + protected virtual void OnFieldsFilled() + { + } + + /// + /// Store all GreenshotControl values to the configuration + /// + protected void StoreFields() + { + bool iniDirty = false; + foreach (FieldInfo field in GetCachedFields(GetType())) + { + var controlObject = field.GetValue(this); + IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; + + if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + { + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section != null) + { + if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) + { + continue; + } + + if (controlObject is CheckBox checkBox) + { + iniValue.Value = checkBox.Checked; + iniDirty = true; + continue; + } + + if (controlObject is RadioButton radioButton) + { + iniValue.Value = radioButton.Checked; + iniDirty = true; + continue; + } + + if (controlObject is TextBox textBox) + { + if (controlObject is HotkeyControl hotkeyControl) + { + iniValue.Value = hotkeyControl.ToString(); + iniDirty = true; + continue; + } + + iniValue.UseValueOrDefault(textBox.Text); + iniDirty = true; + continue; + } + + if (controlObject is GreenshotComboBox comboxBox) + { + iniValue.Value = comboxBox.GetSelectedEnum(); + iniDirty = true; + } + } + } + } + + if (iniDirty) + { + IniConfig.Save(); + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotGroupBox.cs b/src/Greenshot.Base/Controls/GreenshotGroupBox.cs similarity index 95% rename from src/GreenshotPlugin/Controls/GreenshotGroupBox.cs rename to src/Greenshot.Base/Controls/GreenshotGroupBox.cs index 7f4886122..a213f1139 100644 --- a/src/GreenshotPlugin/Controls/GreenshotGroupBox.cs +++ b/src/Greenshot.Base/Controls/GreenshotGroupBox.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; -using System.ComponentModel; - -namespace GreenshotPlugin.Controls -{ - public class GreenshotGroupBox : GroupBox, IGreenshotLanguageBindable - { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotGroupBox : GroupBox, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotLabel.cs b/src/Greenshot.Base/Controls/GreenshotLabel.cs similarity index 94% rename from src/GreenshotPlugin/Controls/GreenshotLabel.cs rename to src/Greenshot.Base/Controls/GreenshotLabel.cs index 904980f9f..152bf5fb1 100644 --- a/src/GreenshotPlugin/Controls/GreenshotLabel.cs +++ b/src/Greenshot.Base/Controls/GreenshotLabel.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; -using System.ComponentModel; - -namespace GreenshotPlugin.Controls -{ - public class GreenshotLabel : Label, IGreenshotLanguageBindable - { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotLabel : Label, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotRadioButton.cs b/src/Greenshot.Base/Controls/GreenshotRadioButton.cs similarity index 95% rename from src/GreenshotPlugin/Controls/GreenshotRadioButton.cs rename to src/Greenshot.Base/Controls/GreenshotRadioButton.cs index 9fdc172d4..0e0e87d58 100644 --- a/src/GreenshotPlugin/Controls/GreenshotRadioButton.cs +++ b/src/Greenshot.Base/Controls/GreenshotRadioButton.cs @@ -1,41 +1,41 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls -{ - /// - /// Description of GreenshotCheckbox. - /// - public class GreenshotRadioButton : RadioButton, IGreenshotLanguageBindable, IGreenshotConfigBindable - { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - - [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] - public string SectionName { get; set; } = "Core"; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] - public string PropertyName { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + /// + /// Description of GreenshotCheckbox. + /// + public class GreenshotRadioButton : RadioButton, IGreenshotLanguageBindable, IGreenshotConfigBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotTabPage.cs b/src/Greenshot.Base/Controls/GreenshotTabPage.cs similarity index 95% rename from src/GreenshotPlugin/Controls/GreenshotTabPage.cs rename to src/Greenshot.Base/Controls/GreenshotTabPage.cs index 40b53b30f..8577368c9 100644 --- a/src/GreenshotPlugin/Controls/GreenshotTabPage.cs +++ b/src/Greenshot.Base/Controls/GreenshotTabPage.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; -using System.ComponentModel; - -namespace GreenshotPlugin.Controls -{ - public class GreenshotTabPage : TabPage, IGreenshotLanguageBindable - { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotTabPage : TabPage, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotTextBox.cs b/src/Greenshot.Base/Controls/GreenshotTextBox.cs similarity index 95% rename from src/GreenshotPlugin/Controls/GreenshotTextBox.cs rename to src/Greenshot.Base/Controls/GreenshotTextBox.cs index 49c7a4d2e..744a479d1 100644 --- a/src/GreenshotPlugin/Controls/GreenshotTextBox.cs +++ b/src/Greenshot.Base/Controls/GreenshotTextBox.cs @@ -1,35 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls -{ - public class GreenshotTextBox : TextBox, IGreenshotConfigBindable - { - [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] - public string SectionName { get; set; } = "Core"; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] - public string PropertyName { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotTextBox : TextBox, IGreenshotConfigBindable + { + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs b/src/Greenshot.Base/Controls/GreenshotToolDropDownButton.cs similarity index 95% rename from src/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs rename to src/Greenshot.Base/Controls/GreenshotToolDropDownButton.cs index e719187c7..81f5b7c2f 100644 --- a/src/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs +++ b/src/Greenshot.Base/Controls/GreenshotToolDropDownButton.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls -{ - public class GreenshotToolStripDropDownButton : ToolStripDropDownButton, IGreenshotLanguageBindable - { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotToolStripDropDownButton : ToolStripDropDownButton, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotToolStripButton.cs b/src/Greenshot.Base/Controls/GreenshotToolStripButton.cs similarity index 95% rename from src/GreenshotPlugin/Controls/GreenshotToolStripButton.cs rename to src/Greenshot.Base/Controls/GreenshotToolStripButton.cs index e95bd1803..68dee4ba6 100644 --- a/src/GreenshotPlugin/Controls/GreenshotToolStripButton.cs +++ b/src/Greenshot.Base/Controls/GreenshotToolStripButton.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls -{ - public class GreenshotToolStripButton : ToolStripButton, IGreenshotLanguageBindable - { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotToolStripButton : ToolStripButton, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs b/src/Greenshot.Base/Controls/GreenshotToolStripLabel.cs similarity index 95% rename from src/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs rename to src/Greenshot.Base/Controls/GreenshotToolStripLabel.cs index 07443d894..e47de2955 100644 --- a/src/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs +++ b/src/Greenshot.Base/Controls/GreenshotToolStripLabel.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; -using System.ComponentModel; - -namespace GreenshotPlugin.Controls -{ - public class GreenshotToolStripLabel : ToolStripLabel, IGreenshotLanguageBindable - { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotToolStripLabel : ToolStripLabel, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs b/src/Greenshot.Base/Controls/GreenshotToolStripMenuItem.cs similarity index 95% rename from src/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs rename to src/Greenshot.Base/Controls/GreenshotToolStripMenuItem.cs index c7a64c743..4feec806b 100644 --- a/src/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs +++ b/src/Greenshot.Base/Controls/GreenshotToolStripMenuItem.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls -{ - public class GreenshotToolStripMenuItem : ToolStripMenuItem, IGreenshotLanguageBindable - { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotToolStripMenuItem : ToolStripMenuItem, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/HotkeyControl.cs b/src/Greenshot.Base/Controls/HotkeyControl.cs similarity index 96% rename from src/GreenshotPlugin/Controls/HotkeyControl.cs rename to src/Greenshot.Base/Controls/HotkeyControl.cs index af59a27dd..da1ae6696 100644 --- a/src/GreenshotPlugin/Controls/HotkeyControl.cs +++ b/src/Greenshot.Base/Controls/HotkeyControl.cs @@ -1,686 +1,686 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using System.Windows.Forms; -using log4net; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Plugin; - -namespace GreenshotPlugin.Controls -{ - /// - /// A simple control that allows the user to select pretty much any valid hotkey combination - /// See: http://www.codeproject.com/KB/buttons/hotkeycontrol.aspx - /// But is modified to fit in Greenshot, and have localized support - /// - public sealed class HotkeyControl : GreenshotTextBox - { - private static readonly ILog Log = LogManager.GetLogger(typeof(HotkeyControl)); - - private static readonly EventDelay EventDelay = new EventDelay(TimeSpan.FromMilliseconds(600).Ticks); - private static readonly bool IsWindows7OrOlder = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 1; - - // Holds the list of hotkeys - private static readonly IDictionary KeyHandlers = new Dictionary(); - private static int _hotKeyCounter = 1; - private const uint WM_HOTKEY = 0x312; - private static IntPtr _hotkeyHwnd; - - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum Modifiers : uint - { - NONE = 0, - ALT = 1, - CTRL = 2, - SHIFT = 4, - WIN = 8, - NO_REPEAT = 0x4000 - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - private enum MapType : uint - { - MAPVK_VK_TO_VSC = - 0, //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0. - - MAPVK_VSC_TO_VK = - 1, //The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0. - - MAPVK_VK_TO_CHAR = - 2, //The uCode parameter is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0. - - MAPVK_VSC_TO_VK_EX = - 3, //The uCode parameter is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0. - - MAPVK_VK_TO_VSC_EX = - 4 //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If the scan code is an extended scan code, the high byte of the uCode value can contain either 0xe0 or 0xe1 to specify the extended scan code. If there is no translation, the function returns 0. - } - - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint virtualKeyCode); - - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool UnregisterHotKey(IntPtr hWnd, int id); - - [DllImport("user32.dll", SetLastError = true)] - private static extern uint MapVirtualKey(uint uCode, uint uMapType); - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern int GetKeyNameText(uint lParam, [Out] StringBuilder lpString, int nSize); - - // These variables store the current hotkey and modifier(s) - private Keys _hotkey = Keys.None; - private Keys _modifiers = Keys.None; - - // ArrayLists used to enforce the use of proper modifiers. - // Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing. - private readonly IList _needNonShiftModifier = new List(); - private readonly IList _needNonAltGrModifier = new List(); - - private readonly ContextMenuStrip _dummy = new ContextMenuStrip(); - - /// - /// Used to make sure that there is no right-click menu available - /// - public override ContextMenuStrip ContextMenuStrip - { - get { return _dummy; } - set { base.ContextMenuStrip = _dummy; } - } - - /// - /// Forces the control to be non-multiline - /// - public override bool Multiline - { - get { return base.Multiline; } - set - { - // Ignore what the user wants; force Multiline to false - base.Multiline = false; - } - } - - /// - /// Creates a new HotkeyControl - /// - public HotkeyControl() - { - ContextMenuStrip = _dummy; // Disable right-clicking - Text = "None"; - - // Handle events that occurs when keys are pressed - KeyPress += HotkeyControl_KeyPress; - KeyUp += HotkeyControl_KeyUp; - KeyDown += HotkeyControl_KeyDown; - - PopulateModifierLists(); - } - - /// - /// Populates the ArrayLists specifying disallowed hotkeys - /// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc - /// - private void PopulateModifierLists() - { - // Shift + 0 - 9, A - Z - for (Keys k = Keys.D0; k <= Keys.Z; k++) - { - _needNonShiftModifier.Add((int) k); - } - - // Shift + Numpad keys - for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++) - { - _needNonShiftModifier.Add((int) k); - } - - // Shift + Misc (,;<./ etc) - for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++) - { - _needNonShiftModifier.Add((int) k); - } - - // Shift + Space, PgUp, PgDn, End, Home - for (Keys k = Keys.Space; k <= Keys.Home; k++) - { - _needNonShiftModifier.Add((int) k); - } - - // Misc keys that we can't loop through - _needNonShiftModifier.Add((int) Keys.Insert); - _needNonShiftModifier.Add((int) Keys.Help); - _needNonShiftModifier.Add((int) Keys.Multiply); - _needNonShiftModifier.Add((int) Keys.Add); - _needNonShiftModifier.Add((int) Keys.Subtract); - _needNonShiftModifier.Add((int) Keys.Divide); - _needNonShiftModifier.Add((int) Keys.Decimal); - _needNonShiftModifier.Add((int) Keys.Return); - _needNonShiftModifier.Add((int) Keys.Escape); - _needNonShiftModifier.Add((int) Keys.NumLock); - - // Ctrl+Alt + 0 - 9 - for (Keys k = Keys.D0; k <= Keys.D9; k++) - { - _needNonAltGrModifier.Add((int) k); - } - } - - /// - /// Resets this hotkey control to None - /// - public new void Clear() - { - Hotkey = Keys.None; - HotkeyModifiers = Keys.None; - } - - /// - /// Fires when a key is pushed down. Here, we'll want to update the text in the box - /// to notify the user what combination is currently pressed. - /// - private void HotkeyControl_KeyDown(object sender, KeyEventArgs e) - { - // Clear the current hotkey - if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete) - { - ResetHotkey(); - } - else - { - _modifiers = e.Modifiers; - _hotkey = e.KeyCode; - Redraw(); - } - } - - /// - /// Fires when all keys are released. If the current hotkey isn't valid, reset it. - /// Otherwise, do nothing and keep the text and hotkey as it was. - /// - private void HotkeyControl_KeyUp(object sender, KeyEventArgs e) - { - // Somehow the PrintScreen only comes as a keyup, therefore we handle it here. - if (e.KeyCode == Keys.PrintScreen) - { - _modifiers = e.Modifiers; - _hotkey = e.KeyCode; - Redraw(); - } - - if (_hotkey == Keys.None && ModifierKeys == Keys.None) - { - ResetHotkey(); - } - } - - /// - /// Prevents the letter/whatever entered to show up in the TextBox - /// Without this, a "A" key press would appear as "aControl, Alt + A" - /// - private void HotkeyControl_KeyPress(object sender, KeyPressEventArgs e) - { - e.Handled = true; - } - - /// - /// Handles some misc keys, such as Ctrl+Delete and Shift+Insert - /// - protected override bool ProcessCmdKey(ref Message msg, Keys keyData) - { - if (keyData == Keys.Delete || keyData == (Keys.Control | Keys.Delete)) - { - ResetHotkey(); - return true; - } - - // Paste - if (keyData == (Keys.Shift | Keys.Insert)) - { - return true; // Don't allow - } - - // Allow the rest - return base.ProcessCmdKey(ref msg, keyData); - } - - /// - /// Clears the current hotkey and resets the TextBox - /// - public void ResetHotkey() - { - _hotkey = Keys.None; - _modifiers = Keys.None; - Redraw(); - } - - /// - /// Used to get/set the hotkey (e.g. Keys.A) - /// - public Keys Hotkey - { - get { return _hotkey; } - set - { - _hotkey = value; - Redraw(true); - } - } - - /// - /// Used to get/set the hotkey (e.g. Keys.A) - /// - public void SetHotkey(string hotkey) - { - _hotkey = HotkeyFromString(hotkey); - _modifiers = HotkeyModifiersFromString(hotkey); - Redraw(true); - } - - /// - /// Used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control) - /// - public Keys HotkeyModifiers - { - get { return _modifiers; } - set - { - _modifiers = value; - Redraw(true); - } - } - - /// - /// Redraws the TextBox when necessary. - /// - /// Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user. - private void Redraw(bool bCalledProgramatically = false) - { - // No hotkey set - if (_hotkey == Keys.None) - { - Text = string.Empty; - return; - } - - // LWin/RWin doesn't work as hotkeys (neither do they work as modifier keys in .NET 2.0) - if (_hotkey == Keys.LWin || _hotkey == Keys.RWin) - { - Text = string.Empty; - return; - } - - // Only validate input if it comes from the user - if (bCalledProgramatically == false) - { - // No modifier or shift only, AND a hotkey that needs another modifier - if ((_modifiers == Keys.Shift || _modifiers == Keys.None) && _needNonShiftModifier.Contains((int) _hotkey)) - { - if (_modifiers == Keys.None) - { - // Set Ctrl+Alt as the modifier unless Ctrl+Alt+ won't work... - if (_needNonAltGrModifier.Contains((int) _hotkey) == false) - { - _modifiers = Keys.Alt | Keys.Control; - } - else - { - // ... in that case, use Shift+Alt instead. - _modifiers = Keys.Alt | Keys.Shift; - } - } - else - { - // User pressed Shift and an invalid key (e.g. a letter or a number), - // that needs another set of modifier keys - _hotkey = Keys.None; - Text = string.Empty; - return; - } - } - - // Check all Ctrl+Alt keys - if ((_modifiers == (Keys.Alt | Keys.Control)) && _needNonAltGrModifier.Contains((int) _hotkey)) - { - // Ctrl+Alt+4 etc won't work; reset hotkey and tell the user - _hotkey = Keys.None; - Text = string.Empty; - return; - } - } - - // I have no idea why this is needed, but it is. Without this code, pressing only Ctrl - // will show up as "Control + ControlKey", etc. - if (_hotkey == Keys.Menu /* Alt */ || _hotkey == Keys.ShiftKey || _hotkey == Keys.ControlKey) - { - _hotkey = Keys.None; - } - - Text = HotkeyToLocalizedString(_modifiers, _hotkey); - } - - public override string ToString() - { - return HotkeyToString(HotkeyModifiers, Hotkey); - } - - public static string GetLocalizedHotkeyStringFromString(string hotkeyString) - { - Keys virtualKeyCode = HotkeyFromString(hotkeyString); - Keys modifiers = HotkeyModifiersFromString(hotkeyString); - return HotkeyToLocalizedString(modifiers, virtualKeyCode); - } - - public static string HotkeyToString(Keys modifierKeyCode, Keys virtualKeyCode) - { - return HotkeyModifiersToString(modifierKeyCode) + virtualKeyCode; - } - - public static string HotkeyModifiersToString(Keys modifierKeyCode) - { - StringBuilder hotkeyString = new StringBuilder(); - if ((modifierKeyCode & Keys.Alt) > 0) - { - hotkeyString.Append("Alt").Append(" + "); - } - - if ((modifierKeyCode & Keys.Control) > 0) - { - hotkeyString.Append("Ctrl").Append(" + "); - } - - if ((modifierKeyCode & Keys.Shift) > 0) - { - hotkeyString.Append("Shift").Append(" + "); - } - - if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) - { - hotkeyString.Append("Win").Append(" + "); - } - - return hotkeyString.ToString(); - } - - - public static string HotkeyToLocalizedString(Keys modifierKeyCode, Keys virtualKeyCode) - { - return HotkeyModifiersToLocalizedString(modifierKeyCode) + GetKeyName(virtualKeyCode); - } - - public static string HotkeyModifiersToLocalizedString(Keys modifierKeyCode) - { - StringBuilder hotkeyString = new StringBuilder(); - if ((modifierKeyCode & Keys.Alt) > 0) - { - hotkeyString.Append(GetKeyName(Keys.Alt)).Append(" + "); - } - - if ((modifierKeyCode & Keys.Control) > 0) - { - hotkeyString.Append(GetKeyName(Keys.Control)).Append(" + "); - } - - if ((modifierKeyCode & Keys.Shift) > 0) - { - hotkeyString.Append(GetKeyName(Keys.Shift)).Append(" + "); - } - - if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) - { - hotkeyString.Append("Win").Append(" + "); - } - - return hotkeyString.ToString(); - } - - - public static Keys HotkeyModifiersFromString(string modifiersString) - { - Keys modifiers = Keys.None; - if (!string.IsNullOrEmpty(modifiersString)) - { - if (modifiersString.ToLower().Contains("alt")) - { - modifiers |= Keys.Alt; - } - - if (modifiersString.ToLower().Contains("ctrl")) - { - modifiers |= Keys.Control; - } - - if (modifiersString.ToLower().Contains("shift")) - { - modifiers |= Keys.Shift; - } - - if (modifiersString.ToLower().Contains("win")) - { - modifiers |= Keys.LWin; - } - } - - return modifiers; - } - - public static Keys HotkeyFromString(string hotkey) - { - Keys key = Keys.None; - if (!string.IsNullOrEmpty(hotkey)) - { - if (hotkey.LastIndexOf('+') > 0) - { - hotkey = hotkey.Remove(0, hotkey.LastIndexOf('+') + 1).Trim(); - } - - key = (Keys) Enum.Parse(typeof(Keys), hotkey); - } - - return key; - } - - public static void RegisterHotkeyHwnd(IntPtr hWnd) - { - _hotkeyHwnd = hWnd; - } - - /// - /// Register a hotkey - /// - /// The modifier, e.g.: Modifiers.CTRL, Modifiers.NONE or Modifiers.ALT - /// The virtual key code - /// A HotKeyHandler, this will be called to handle the hotkey press - /// the hotkey number, -1 if failed - public static int RegisterHotKey(Keys modifierKeyCode, Keys virtualKeyCode, HotKeyHandler handler) - { - if (virtualKeyCode == Keys.None) - { - Log.Warn("Trying to register a Keys.none hotkey, ignoring"); - return 0; - } - - // Convert Modifiers to fit HKM_SETHOTKEY - uint modifiers = 0; - if ((modifierKeyCode & Keys.Alt) > 0) - { - modifiers |= (uint) Modifiers.ALT; - } - - if ((modifierKeyCode & Keys.Control) > 0) - { - modifiers |= (uint) Modifiers.CTRL; - } - - if ((modifierKeyCode & Keys.Shift) > 0) - { - modifiers |= (uint) Modifiers.SHIFT; - } - - if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) - { - modifiers |= (uint) Modifiers.WIN; - } - - // Disable repeating hotkey for Windows 7 and beyond, as described in #1559 - if (IsWindows7OrOlder) - { - modifiers |= (uint) Modifiers.NO_REPEAT; - } - - if (RegisterHotKey(_hotkeyHwnd, _hotKeyCounter, modifiers, (uint) virtualKeyCode)) - { - KeyHandlers.Add(_hotKeyCounter, handler); - return _hotKeyCounter++; - } - - Log.Warn($"Couldn't register hotkey modifier {modifierKeyCode} virtualKeyCode {virtualKeyCode}"); - return -1; - } - - public static void UnregisterHotkeys() - { - foreach (int hotkey in KeyHandlers.Keys) - { - UnregisterHotKey(_hotkeyHwnd, hotkey); - } - - // Remove all key handlers - KeyHandlers.Clear(); - } - - /// - /// Handle WndProc messages for the hotkey - /// - /// - /// true if the message was handled - public static bool HandleMessages(ref Message m) - { - if (m.Msg != WM_HOTKEY) - { - return false; - } - - // Call handler - if (!IsWindows7OrOlder && !EventDelay.Check()) - { - return true; - } - - if (KeyHandlers.TryGetValue((int) m.WParam, out var handler)) - { - handler(); - } - - return true; - } - - public static string GetKeyName(Keys givenKey) - { - StringBuilder keyName = new StringBuilder(); - const uint numpad = 55; - - Keys virtualKey = givenKey; - string keyString; - // Make VC's to real keys - switch (virtualKey) - { - case Keys.Alt: - virtualKey = Keys.LMenu; - break; - case Keys.Control: - virtualKey = Keys.ControlKey; - break; - case Keys.Shift: - virtualKey = Keys.LShiftKey; - break; - case Keys.Multiply: - GetKeyNameText(numpad << 16, keyName, 100); - keyString = keyName.ToString().Replace("*", string.Empty).Trim().ToLower(); - if (keyString.IndexOf("(", StringComparison.Ordinal) >= 0) - { - return "* " + keyString; - } - - keyString = keyString.Substring(0, 1).ToUpper() + keyString.Substring(1).ToLower(); - return keyString + " *"; - case Keys.Divide: - GetKeyNameText(numpad << 16, keyName, 100); - keyString = keyName.ToString().Replace("*", string.Empty).Trim().ToLower(); - if (keyString.IndexOf("(", StringComparison.Ordinal) >= 0) - { - return "/ " + keyString; - } - - keyString = keyString.Substring(0, 1).ToUpper() + keyString.Substring(1).ToLower(); - return keyString + " /"; - } - - uint scanCode = MapVirtualKey((uint) virtualKey, (uint) MapType.MAPVK_VK_TO_VSC); - - // because MapVirtualKey strips the extended bit for some keys - switch (virtualKey) - { - case Keys.Left: - case Keys.Up: - case Keys.Right: - case Keys.Down: // arrow keys - case Keys.Prior: - case Keys.Next: // page up and page down - case Keys.End: - case Keys.Home: - case Keys.Insert: - case Keys.Delete: - case Keys.NumLock: - Log.Debug("Modifying Extended bit"); - scanCode |= 0x100; // set extended bit - break; - case Keys.PrintScreen: // PrintScreen - scanCode = 311; - break; - case Keys.Pause: // PrintScreen - scanCode = 69; - break; - } - - scanCode |= 0x200; - if (GetKeyNameText(scanCode << 16, keyName, 100) != 0) - { - string visibleName = keyName.ToString(); - if (visibleName.Length > 1) - { - visibleName = visibleName.Substring(0, 1) + visibleName.Substring(1).ToLower(); - } - - return visibleName; - } - - return givenKey.ToString(); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Plugin; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// A simple control that allows the user to select pretty much any valid hotkey combination + /// See: http://www.codeproject.com/KB/buttons/hotkeycontrol.aspx + /// But is modified to fit in Greenshot, and have localized support + /// + public sealed class HotkeyControl : GreenshotTextBox + { + private static readonly ILog Log = LogManager.GetLogger(typeof(HotkeyControl)); + + private static readonly EventDelay EventDelay = new EventDelay(TimeSpan.FromMilliseconds(600).Ticks); + private static readonly bool IsWindows7OrOlder = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 1; + + // Holds the list of hotkeys + private static readonly IDictionary KeyHandlers = new Dictionary(); + private static int _hotKeyCounter = 1; + private const uint WM_HOTKEY = 0x312; + private static IntPtr _hotkeyHwnd; + + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum Modifiers : uint + { + NONE = 0, + ALT = 1, + CTRL = 2, + SHIFT = 4, + WIN = 8, + NO_REPEAT = 0x4000 + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + private enum MapType : uint + { + MAPVK_VK_TO_VSC = + 0, //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0. + + MAPVK_VSC_TO_VK = + 1, //The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0. + + MAPVK_VK_TO_CHAR = + 2, //The uCode parameter is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0. + + MAPVK_VSC_TO_VK_EX = + 3, //The uCode parameter is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0. + + MAPVK_VK_TO_VSC_EX = + 4 //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If the scan code is an extended scan code, the high byte of the uCode value can contain either 0xe0 or 0xe1 to specify the extended scan code. If there is no translation, the function returns 0. + } + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint virtualKeyCode); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + + [DllImport("user32.dll", SetLastError = true)] + private static extern uint MapVirtualKey(uint uCode, uint uMapType); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern int GetKeyNameText(uint lParam, [Out] StringBuilder lpString, int nSize); + + // These variables store the current hotkey and modifier(s) + private Keys _hotkey = Keys.None; + private Keys _modifiers = Keys.None; + + // ArrayLists used to enforce the use of proper modifiers. + // Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing. + private readonly IList _needNonShiftModifier = new List(); + private readonly IList _needNonAltGrModifier = new List(); + + private readonly ContextMenuStrip _dummy = new ContextMenuStrip(); + + /// + /// Used to make sure that there is no right-click menu available + /// + public override ContextMenuStrip ContextMenuStrip + { + get { return _dummy; } + set { base.ContextMenuStrip = _dummy; } + } + + /// + /// Forces the control to be non-multiline + /// + public override bool Multiline + { + get { return base.Multiline; } + set + { + // Ignore what the user wants; force Multiline to false + base.Multiline = false; + } + } + + /// + /// Creates a new HotkeyControl + /// + public HotkeyControl() + { + ContextMenuStrip = _dummy; // Disable right-clicking + Text = "None"; + + // Handle events that occurs when keys are pressed + KeyPress += HotkeyControl_KeyPress; + KeyUp += HotkeyControl_KeyUp; + KeyDown += HotkeyControl_KeyDown; + + PopulateModifierLists(); + } + + /// + /// Populates the ArrayLists specifying disallowed hotkeys + /// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc + /// + private void PopulateModifierLists() + { + // Shift + 0 - 9, A - Z + for (Keys k = Keys.D0; k <= Keys.Z; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Shift + Numpad keys + for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Shift + Misc (,;<./ etc) + for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Shift + Space, PgUp, PgDn, End, Home + for (Keys k = Keys.Space; k <= Keys.Home; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Misc keys that we can't loop through + _needNonShiftModifier.Add((int) Keys.Insert); + _needNonShiftModifier.Add((int) Keys.Help); + _needNonShiftModifier.Add((int) Keys.Multiply); + _needNonShiftModifier.Add((int) Keys.Add); + _needNonShiftModifier.Add((int) Keys.Subtract); + _needNonShiftModifier.Add((int) Keys.Divide); + _needNonShiftModifier.Add((int) Keys.Decimal); + _needNonShiftModifier.Add((int) Keys.Return); + _needNonShiftModifier.Add((int) Keys.Escape); + _needNonShiftModifier.Add((int) Keys.NumLock); + + // Ctrl+Alt + 0 - 9 + for (Keys k = Keys.D0; k <= Keys.D9; k++) + { + _needNonAltGrModifier.Add((int) k); + } + } + + /// + /// Resets this hotkey control to None + /// + public new void Clear() + { + Hotkey = Keys.None; + HotkeyModifiers = Keys.None; + } + + /// + /// Fires when a key is pushed down. Here, we'll want to update the text in the box + /// to notify the user what combination is currently pressed. + /// + private void HotkeyControl_KeyDown(object sender, KeyEventArgs e) + { + // Clear the current hotkey + if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete) + { + ResetHotkey(); + } + else + { + _modifiers = e.Modifiers; + _hotkey = e.KeyCode; + Redraw(); + } + } + + /// + /// Fires when all keys are released. If the current hotkey isn't valid, reset it. + /// Otherwise, do nothing and keep the text and hotkey as it was. + /// + private void HotkeyControl_KeyUp(object sender, KeyEventArgs e) + { + // Somehow the PrintScreen only comes as a keyup, therefore we handle it here. + if (e.KeyCode == Keys.PrintScreen) + { + _modifiers = e.Modifiers; + _hotkey = e.KeyCode; + Redraw(); + } + + if (_hotkey == Keys.None && ModifierKeys == Keys.None) + { + ResetHotkey(); + } + } + + /// + /// Prevents the letter/whatever entered to show up in the TextBox + /// Without this, a "A" key press would appear as "aControl, Alt + A" + /// + private void HotkeyControl_KeyPress(object sender, KeyPressEventArgs e) + { + e.Handled = true; + } + + /// + /// Handles some misc keys, such as Ctrl+Delete and Shift+Insert + /// + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (keyData == Keys.Delete || keyData == (Keys.Control | Keys.Delete)) + { + ResetHotkey(); + return true; + } + + // Paste + if (keyData == (Keys.Shift | Keys.Insert)) + { + return true; // Don't allow + } + + // Allow the rest + return base.ProcessCmdKey(ref msg, keyData); + } + + /// + /// Clears the current hotkey and resets the TextBox + /// + public void ResetHotkey() + { + _hotkey = Keys.None; + _modifiers = Keys.None; + Redraw(); + } + + /// + /// Used to get/set the hotkey (e.g. Keys.A) + /// + public Keys Hotkey + { + get { return _hotkey; } + set + { + _hotkey = value; + Redraw(true); + } + } + + /// + /// Used to get/set the hotkey (e.g. Keys.A) + /// + public void SetHotkey(string hotkey) + { + _hotkey = HotkeyFromString(hotkey); + _modifiers = HotkeyModifiersFromString(hotkey); + Redraw(true); + } + + /// + /// Used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control) + /// + public Keys HotkeyModifiers + { + get { return _modifiers; } + set + { + _modifiers = value; + Redraw(true); + } + } + + /// + /// Redraws the TextBox when necessary. + /// + /// Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user. + private void Redraw(bool bCalledProgramatically = false) + { + // No hotkey set + if (_hotkey == Keys.None) + { + Text = string.Empty; + return; + } + + // LWin/RWin doesn't work as hotkeys (neither do they work as modifier keys in .NET 2.0) + if (_hotkey == Keys.LWin || _hotkey == Keys.RWin) + { + Text = string.Empty; + return; + } + + // Only validate input if it comes from the user + if (bCalledProgramatically == false) + { + // No modifier or shift only, AND a hotkey that needs another modifier + if ((_modifiers == Keys.Shift || _modifiers == Keys.None) && _needNonShiftModifier.Contains((int) _hotkey)) + { + if (_modifiers == Keys.None) + { + // Set Ctrl+Alt as the modifier unless Ctrl+Alt+ won't work... + if (_needNonAltGrModifier.Contains((int) _hotkey) == false) + { + _modifiers = Keys.Alt | Keys.Control; + } + else + { + // ... in that case, use Shift+Alt instead. + _modifiers = Keys.Alt | Keys.Shift; + } + } + else + { + // User pressed Shift and an invalid key (e.g. a letter or a number), + // that needs another set of modifier keys + _hotkey = Keys.None; + Text = string.Empty; + return; + } + } + + // Check all Ctrl+Alt keys + if ((_modifiers == (Keys.Alt | Keys.Control)) && _needNonAltGrModifier.Contains((int) _hotkey)) + { + // Ctrl+Alt+4 etc won't work; reset hotkey and tell the user + _hotkey = Keys.None; + Text = string.Empty; + return; + } + } + + // I have no idea why this is needed, but it is. Without this code, pressing only Ctrl + // will show up as "Control + ControlKey", etc. + if (_hotkey == Keys.Menu /* Alt */ || _hotkey == Keys.ShiftKey || _hotkey == Keys.ControlKey) + { + _hotkey = Keys.None; + } + + Text = HotkeyToLocalizedString(_modifiers, _hotkey); + } + + public override string ToString() + { + return HotkeyToString(HotkeyModifiers, Hotkey); + } + + public static string GetLocalizedHotkeyStringFromString(string hotkeyString) + { + Keys virtualKeyCode = HotkeyFromString(hotkeyString); + Keys modifiers = HotkeyModifiersFromString(hotkeyString); + return HotkeyToLocalizedString(modifiers, virtualKeyCode); + } + + public static string HotkeyToString(Keys modifierKeyCode, Keys virtualKeyCode) + { + return HotkeyModifiersToString(modifierKeyCode) + virtualKeyCode; + } + + public static string HotkeyModifiersToString(Keys modifierKeyCode) + { + StringBuilder hotkeyString = new StringBuilder(); + if ((modifierKeyCode & Keys.Alt) > 0) + { + hotkeyString.Append("Alt").Append(" + "); + } + + if ((modifierKeyCode & Keys.Control) > 0) + { + hotkeyString.Append("Ctrl").Append(" + "); + } + + if ((modifierKeyCode & Keys.Shift) > 0) + { + hotkeyString.Append("Shift").Append(" + "); + } + + if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) + { + hotkeyString.Append("Win").Append(" + "); + } + + return hotkeyString.ToString(); + } + + + public static string HotkeyToLocalizedString(Keys modifierKeyCode, Keys virtualKeyCode) + { + return HotkeyModifiersToLocalizedString(modifierKeyCode) + GetKeyName(virtualKeyCode); + } + + public static string HotkeyModifiersToLocalizedString(Keys modifierKeyCode) + { + StringBuilder hotkeyString = new StringBuilder(); + if ((modifierKeyCode & Keys.Alt) > 0) + { + hotkeyString.Append(GetKeyName(Keys.Alt)).Append(" + "); + } + + if ((modifierKeyCode & Keys.Control) > 0) + { + hotkeyString.Append(GetKeyName(Keys.Control)).Append(" + "); + } + + if ((modifierKeyCode & Keys.Shift) > 0) + { + hotkeyString.Append(GetKeyName(Keys.Shift)).Append(" + "); + } + + if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) + { + hotkeyString.Append("Win").Append(" + "); + } + + return hotkeyString.ToString(); + } + + + public static Keys HotkeyModifiersFromString(string modifiersString) + { + Keys modifiers = Keys.None; + if (!string.IsNullOrEmpty(modifiersString)) + { + if (modifiersString.ToLower().Contains("alt")) + { + modifiers |= Keys.Alt; + } + + if (modifiersString.ToLower().Contains("ctrl")) + { + modifiers |= Keys.Control; + } + + if (modifiersString.ToLower().Contains("shift")) + { + modifiers |= Keys.Shift; + } + + if (modifiersString.ToLower().Contains("win")) + { + modifiers |= Keys.LWin; + } + } + + return modifiers; + } + + public static Keys HotkeyFromString(string hotkey) + { + Keys key = Keys.None; + if (!string.IsNullOrEmpty(hotkey)) + { + if (hotkey.LastIndexOf('+') > 0) + { + hotkey = hotkey.Remove(0, hotkey.LastIndexOf('+') + 1).Trim(); + } + + key = (Keys) Enum.Parse(typeof(Keys), hotkey); + } + + return key; + } + + public static void RegisterHotkeyHwnd(IntPtr hWnd) + { + _hotkeyHwnd = hWnd; + } + + /// + /// Register a hotkey + /// + /// The modifier, e.g.: Modifiers.CTRL, Modifiers.NONE or Modifiers.ALT + /// The virtual key code + /// A HotKeyHandler, this will be called to handle the hotkey press + /// the hotkey number, -1 if failed + public static int RegisterHotKey(Keys modifierKeyCode, Keys virtualKeyCode, HotKeyHandler handler) + { + if (virtualKeyCode == Keys.None) + { + Log.Warn("Trying to register a Keys.none hotkey, ignoring"); + return 0; + } + + // Convert Modifiers to fit HKM_SETHOTKEY + uint modifiers = 0; + if ((modifierKeyCode & Keys.Alt) > 0) + { + modifiers |= (uint) Modifiers.ALT; + } + + if ((modifierKeyCode & Keys.Control) > 0) + { + modifiers |= (uint) Modifiers.CTRL; + } + + if ((modifierKeyCode & Keys.Shift) > 0) + { + modifiers |= (uint) Modifiers.SHIFT; + } + + if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) + { + modifiers |= (uint) Modifiers.WIN; + } + + // Disable repeating hotkey for Windows 7 and beyond, as described in #1559 + if (IsWindows7OrOlder) + { + modifiers |= (uint) Modifiers.NO_REPEAT; + } + + if (RegisterHotKey(_hotkeyHwnd, _hotKeyCounter, modifiers, (uint) virtualKeyCode)) + { + KeyHandlers.Add(_hotKeyCounter, handler); + return _hotKeyCounter++; + } + + Log.Warn($"Couldn't register hotkey modifier {modifierKeyCode} virtualKeyCode {virtualKeyCode}"); + return -1; + } + + public static void UnregisterHotkeys() + { + foreach (int hotkey in KeyHandlers.Keys) + { + UnregisterHotKey(_hotkeyHwnd, hotkey); + } + + // Remove all key handlers + KeyHandlers.Clear(); + } + + /// + /// Handle WndProc messages for the hotkey + /// + /// + /// true if the message was handled + public static bool HandleMessages(ref Message m) + { + if (m.Msg != WM_HOTKEY) + { + return false; + } + + // Call handler + if (!IsWindows7OrOlder && !EventDelay.Check()) + { + return true; + } + + if (KeyHandlers.TryGetValue((int) m.WParam, out var handler)) + { + handler(); + } + + return true; + } + + public static string GetKeyName(Keys givenKey) + { + StringBuilder keyName = new StringBuilder(); + const uint numpad = 55; + + Keys virtualKey = givenKey; + string keyString; + // Make VC's to real keys + switch (virtualKey) + { + case Keys.Alt: + virtualKey = Keys.LMenu; + break; + case Keys.Control: + virtualKey = Keys.ControlKey; + break; + case Keys.Shift: + virtualKey = Keys.LShiftKey; + break; + case Keys.Multiply: + GetKeyNameText(numpad << 16, keyName, 100); + keyString = keyName.ToString().Replace("*", string.Empty).Trim().ToLower(); + if (keyString.IndexOf("(", StringComparison.Ordinal) >= 0) + { + return "* " + keyString; + } + + keyString = keyString.Substring(0, 1).ToUpper() + keyString.Substring(1).ToLower(); + return keyString + " *"; + case Keys.Divide: + GetKeyNameText(numpad << 16, keyName, 100); + keyString = keyName.ToString().Replace("*", string.Empty).Trim().ToLower(); + if (keyString.IndexOf("(", StringComparison.Ordinal) >= 0) + { + return "/ " + keyString; + } + + keyString = keyString.Substring(0, 1).ToUpper() + keyString.Substring(1).ToLower(); + return keyString + " /"; + } + + uint scanCode = MapVirtualKey((uint) virtualKey, (uint) MapType.MAPVK_VK_TO_VSC); + + // because MapVirtualKey strips the extended bit for some keys + switch (virtualKey) + { + case Keys.Left: + case Keys.Up: + case Keys.Right: + case Keys.Down: // arrow keys + case Keys.Prior: + case Keys.Next: // page up and page down + case Keys.End: + case Keys.Home: + case Keys.Insert: + case Keys.Delete: + case Keys.NumLock: + Log.Debug("Modifying Extended bit"); + scanCode |= 0x100; // set extended bit + break; + case Keys.PrintScreen: // PrintScreen + scanCode = 311; + break; + case Keys.Pause: // PrintScreen + scanCode = 69; + break; + } + + scanCode |= 0x200; + if (GetKeyNameText(scanCode << 16, keyName, 100) != 0) + { + string visibleName = keyName.ToString(); + if (visibleName.Length > 1) + { + visibleName = visibleName.Substring(0, 1) + visibleName.Substring(1).ToLower(); + } + + return visibleName; + } + + return givenKey.ToString(); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs b/src/Greenshot.Base/Controls/IGreenshotConfigBindable.cs similarity index 94% rename from src/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs rename to src/Greenshot.Base/Controls/IGreenshotConfigBindable.cs index e02358718..7a4865031 100644 --- a/src/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs +++ b/src/Greenshot.Base/Controls/IGreenshotConfigBindable.cs @@ -1,36 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -namespace GreenshotPlugin.Controls -{ - public interface IGreenshotConfigBindable - { - /// - /// The class where the property-value is stored - /// - string SectionName { get; set; } - - /// - /// Path to the property value which will be mapped with this control - /// - string PropertyName { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Controls +{ + public interface IGreenshotConfigBindable + { + /// + /// The class where the property-value is stored + /// + string SectionName { get; set; } + + /// + /// Path to the property value which will be mapped with this control + /// + string PropertyName { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs b/src/Greenshot.Base/Controls/IGreenshotLanguageBindable.cs similarity index 94% rename from src/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs rename to src/Greenshot.Base/Controls/IGreenshotLanguageBindable.cs index c83c50d57..2a06d4f7e 100644 --- a/src/GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs +++ b/src/Greenshot.Base/Controls/IGreenshotLanguageBindable.cs @@ -1,34 +1,34 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -namespace GreenshotPlugin.Controls -{ - /// - /// This interface describes the designer fields that need to be implemented for Greenshot controls - /// - public interface IGreenshotLanguageBindable - { - /// - /// Language key to use to fill the Text value with - /// - string LanguageKey { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Controls +{ + /// + /// This interface describes the designer fields that need to be implemented for Greenshot controls + /// + public interface IGreenshotLanguageBindable + { + /// + /// Language key to use to fill the Text value with + /// + string LanguageKey { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs b/src/Greenshot.Base/Controls/OAuthLoginForm.Designer.cs similarity index 96% rename from src/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs rename to src/Greenshot.Base/Controls/OAuthLoginForm.Designer.cs index abf92060c..f930762af 100644 --- a/src/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs +++ b/src/Greenshot.Base/Controls/OAuthLoginForm.Designer.cs @@ -1,92 +1,92 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -namespace GreenshotPlugin.Controls { - partial class OAuthLoginForm { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() { - this._addressTextBox = new System.Windows.Forms.TextBox(); - this._browser = new ExtendedWebBrowser(); - this.SuspendLayout(); - // - // _addressTextBox - // - this._addressTextBox.Cursor = System.Windows.Forms.Cursors.Arrow; - this._addressTextBox.Dock = System.Windows.Forms.DockStyle.Top; - this._addressTextBox.Enabled = false; - this._addressTextBox.Location = new System.Drawing.Point(0, 0); - this._addressTextBox.Name = "addressTextBox"; - this._addressTextBox.Size = new System.Drawing.Size(595, 20); - this._addressTextBox.TabIndex = 3; - this._addressTextBox.TabStop = false; - // - // _browser - // - this._browser.Dock = System.Windows.Forms.DockStyle.Fill; - this._browser.Location = new System.Drawing.Point(0, 20); - this._browser.MinimumSize = new System.Drawing.Size(100, 100); - this._browser.Name = "browser"; - this._browser.Size = new System.Drawing.Size(595, 295); - this._browser.TabIndex = 4; - // - // OAuthLoginForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(595, 315); - this.Controls.Add(this._browser); - this.Controls.Add(this._addressTextBox); - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "OAuthLoginForm"; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.TextBox _addressTextBox; - private ExtendedWebBrowser _browser; - - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +namespace Greenshot.Base.Controls { + partial class OAuthLoginForm { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() { + this._addressTextBox = new System.Windows.Forms.TextBox(); + this._browser = new ExtendedWebBrowser(); + this.SuspendLayout(); + // + // _addressTextBox + // + this._addressTextBox.Cursor = System.Windows.Forms.Cursors.Arrow; + this._addressTextBox.Dock = System.Windows.Forms.DockStyle.Top; + this._addressTextBox.Enabled = false; + this._addressTextBox.Location = new System.Drawing.Point(0, 0); + this._addressTextBox.Name = "addressTextBox"; + this._addressTextBox.Size = new System.Drawing.Size(595, 20); + this._addressTextBox.TabIndex = 3; + this._addressTextBox.TabStop = false; + // + // _browser + // + this._browser.Dock = System.Windows.Forms.DockStyle.Fill; + this._browser.Location = new System.Drawing.Point(0, 20); + this._browser.MinimumSize = new System.Drawing.Size(100, 100); + this._browser.Name = "browser"; + this._browser.Size = new System.Drawing.Size(595, 295); + this._browser.TabIndex = 4; + // + // OAuthLoginForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(595, 315); + this.Controls.Add(this._browser); + this.Controls.Add(this._addressTextBox); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "OAuthLoginForm"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox _addressTextBox; + private ExtendedWebBrowser _browser; + + } +} diff --git a/src/GreenshotPlugin/Controls/OAuthLoginForm.cs b/src/Greenshot.Base/Controls/OAuthLoginForm.cs similarity index 95% rename from src/GreenshotPlugin/Controls/OAuthLoginForm.cs rename to src/Greenshot.Base/Controls/OAuthLoginForm.cs index 59a1ea9ca..4cbc1dc9c 100644 --- a/src/GreenshotPlugin/Controls/OAuthLoginForm.cs +++ b/src/Greenshot.Base/Controls/OAuthLoginForm.cs @@ -1,121 +1,121 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Windows.Forms; -using GreenshotPlugin.Core; -using log4net; - -namespace GreenshotPlugin.Controls -{ - /// - /// The OAuthLoginForm is used to allow the user to authorize Greenshot with an "Oauth" application - /// - public sealed partial class OAuthLoginForm : Form - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthLoginForm)); - private readonly string _callbackUrl; - - public IDictionary CallbackParameters { get; private set; } - - public bool IsOk => DialogResult == DialogResult.OK; - - public OAuthLoginForm(string browserTitle, Size size, string authorizationLink, string callbackUrl) - { - // Make sure Greenshot uses the correct browser version - IEHelper.FixBrowserVersion(false); - - _callbackUrl = callbackUrl; - // Fix for BUG-2071 - if (callbackUrl.EndsWith("/")) - { - _callbackUrl = callbackUrl.Substring(0, callbackUrl.Length - 1); - } - - InitializeComponent(); - ClientSize = size; - Icon = GreenshotResources.GetGreenshotIcon(); - Text = browserTitle; - _addressTextBox.Text = authorizationLink; - - // The script errors are suppressed by using the ExtendedWebBrowser - _browser.ScriptErrorsSuppressed = false; - _browser.DocumentCompleted += Browser_DocumentCompleted; - _browser.Navigated += Browser_Navigated; - _browser.Navigating += Browser_Navigating; - _browser.Navigate(new Uri(authorizationLink)); - } - - /// - /// Make sure the form is visible - /// - /// EventArgs - protected override void OnShown(EventArgs e) - { - base.OnShown(e); - WindowDetails.ToForeground(Handle); - } - - private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) - { - LOG.DebugFormat("document completed with url: {0}", _browser.Url); - CheckUrl(); - } - - private void Browser_Navigating(object sender, WebBrowserNavigatingEventArgs e) - { - LOG.DebugFormat("Navigating to url: {0}", _browser.Url); - _addressTextBox.Text = e.Url.ToString(); - } - - private void Browser_Navigated(object sender, WebBrowserNavigatedEventArgs e) - { - LOG.DebugFormat("Navigated to url: {0}", _browser.Url); - CheckUrl(); - } - - private void CheckUrl() - { - if (_browser.Url.ToString().StartsWith(_callbackUrl)) - { - var correctedUri = new Uri(_browser.Url.AbsoluteUri.Replace("#", "&")); - - string queryParams = correctedUri.Query; - if (queryParams.Length > 0) - { - queryParams = NetworkHelper.UrlDecode(queryParams); - //Store the Token and Token Secret - CallbackParameters = NetworkHelper.ParseQueryString(queryParams); - } - - DialogResult = DialogResult.OK; - } - } - - private void AddressTextBox_KeyPress(object sender, KeyPressEventArgs e) - { - //Cancel the key press so the user can't enter a new url - e.Handled = true; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Core; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// The OAuthLoginForm is used to allow the user to authorize Greenshot with an "Oauth" application + /// + public sealed partial class OAuthLoginForm : Form + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthLoginForm)); + private readonly string _callbackUrl; + + public IDictionary CallbackParameters { get; private set; } + + public bool IsOk => DialogResult == DialogResult.OK; + + public OAuthLoginForm(string browserTitle, Size size, string authorizationLink, string callbackUrl) + { + // Make sure Greenshot uses the correct browser version + IEHelper.FixBrowserVersion(false); + + _callbackUrl = callbackUrl; + // Fix for BUG-2071 + if (callbackUrl.EndsWith("/")) + { + _callbackUrl = callbackUrl.Substring(0, callbackUrl.Length - 1); + } + + InitializeComponent(); + ClientSize = size; + Icon = GreenshotResources.GetGreenshotIcon(); + Text = browserTitle; + _addressTextBox.Text = authorizationLink; + + // The script errors are suppressed by using the ExtendedWebBrowser + _browser.ScriptErrorsSuppressed = false; + _browser.DocumentCompleted += Browser_DocumentCompleted; + _browser.Navigated += Browser_Navigated; + _browser.Navigating += Browser_Navigating; + _browser.Navigate(new Uri(authorizationLink)); + } + + /// + /// Make sure the form is visible + /// + /// EventArgs + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + WindowDetails.ToForeground(Handle); + } + + private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) + { + LOG.DebugFormat("document completed with url: {0}", _browser.Url); + CheckUrl(); + } + + private void Browser_Navigating(object sender, WebBrowserNavigatingEventArgs e) + { + LOG.DebugFormat("Navigating to url: {0}", _browser.Url); + _addressTextBox.Text = e.Url.ToString(); + } + + private void Browser_Navigated(object sender, WebBrowserNavigatedEventArgs e) + { + LOG.DebugFormat("Navigated to url: {0}", _browser.Url); + CheckUrl(); + } + + private void CheckUrl() + { + if (_browser.Url.ToString().StartsWith(_callbackUrl)) + { + var correctedUri = new Uri(_browser.Url.AbsoluteUri.Replace("#", "&")); + + string queryParams = correctedUri.Query; + if (queryParams.Length > 0) + { + queryParams = NetworkHelper.UrlDecode(queryParams); + //Store the Token and Token Secret + CallbackParameters = NetworkHelper.ParseQueryString(queryParams); + } + + DialogResult = DialogResult.OK; + } + } + + private void AddressTextBox_KeyPress(object sender, KeyPressEventArgs e) + { + //Cancel the key press so the user can't enter a new url + e.Handled = true; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs b/src/Greenshot.Base/Controls/PleaseWaitForm.Designer.cs similarity index 96% rename from src/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs rename to src/Greenshot.Base/Controls/PleaseWaitForm.Designer.cs index a3ab2832b..3083b7bf2 100644 --- a/src/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs +++ b/src/Greenshot.Base/Controls/PleaseWaitForm.Designer.cs @@ -1,99 +1,99 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -namespace GreenshotPlugin.Controls { - partial class PleaseWaitForm { - /// - /// Designer variable used to keep track of non-visual components. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Disposes resources used by the form. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) { - if (disposing) { - if (components != null) { - components.Dispose(); - } - } - base.Dispose(disposing); - } - - /// - /// This method is required for Windows Forms designer support. - /// Do not change the method contents inside the source code editor. The Forms designer might - /// not be able to load this method if it was changed manually. - /// - private void InitializeComponent() { - this.label_pleasewait = new System.Windows.Forms.Label(); - this.cancelButton = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // label_pleasewait - // - this.label_pleasewait.Dock = System.Windows.Forms.DockStyle.Fill; - this.label_pleasewait.Location = new System.Drawing.Point(0, 0); - this.label_pleasewait.Name = "label_pleasewait"; - this.label_pleasewait.Padding = new System.Windows.Forms.Padding(10); - this.label_pleasewait.Size = new System.Drawing.Size(90, 33); - this.label_pleasewait.TabIndex = 0; - this.label_pleasewait.Text = "Please wait..."; - this.label_pleasewait.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - this.label_pleasewait.UseWaitCursor = true; - // - // cancelButton - // - this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.cancelButton.Location = new System.Drawing.Point(38, 41); - this.cancelButton.Name = "cancelButton"; - this.cancelButton.Size = new System.Drawing.Size(94, 23); - this.cancelButton.TabIndex = 1; - this.cancelButton.Text = "Cancel"; - this.cancelButton.UseVisualStyleBackColor = true; - this.cancelButton.UseWaitCursor = true; - this.cancelButton.Click += new System.EventHandler(this.CancelButtonClick); - // - // PleaseWaitForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.CancelButton = this.cancelButton; - this.ClientSize = new System.Drawing.Size(169, 76); - this.Controls.Add(this.cancelButton); - this.Controls.Add(this.label_pleasewait); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "PleaseWaitForm"; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Greenshot"; - this.UseWaitCursor = true; - this.ResumeLayout(false); - this.PerformLayout(); - } - private System.Windows.Forms.Button cancelButton; - private System.Windows.Forms.Label label_pleasewait; - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +namespace Greenshot.Base.Controls { + partial class PleaseWaitForm { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() { + this.label_pleasewait = new System.Windows.Forms.Label(); + this.cancelButton = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label_pleasewait + // + this.label_pleasewait.Dock = System.Windows.Forms.DockStyle.Fill; + this.label_pleasewait.Location = new System.Drawing.Point(0, 0); + this.label_pleasewait.Name = "label_pleasewait"; + this.label_pleasewait.Padding = new System.Windows.Forms.Padding(10); + this.label_pleasewait.Size = new System.Drawing.Size(90, 33); + this.label_pleasewait.TabIndex = 0; + this.label_pleasewait.Text = "Please wait..."; + this.label_pleasewait.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.label_pleasewait.UseWaitCursor = true; + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(38, 41); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(94, 23); + this.cancelButton.TabIndex = 1; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.UseWaitCursor = true; + this.cancelButton.Click += new System.EventHandler(this.CancelButtonClick); + // + // PleaseWaitForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(169, 76); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.label_pleasewait); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "PleaseWaitForm"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Greenshot"; + this.UseWaitCursor = true; + this.ResumeLayout(false); + this.PerformLayout(); + } + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Label label_pleasewait; + } +} diff --git a/src/GreenshotPlugin/Controls/PleaseWaitForm.cs b/src/Greenshot.Base/Controls/PleaseWaitForm.cs similarity index 95% rename from src/GreenshotPlugin/Controls/PleaseWaitForm.cs rename to src/Greenshot.Base/Controls/PleaseWaitForm.cs index 8d0ced972..e87ab38ef 100644 --- a/src/GreenshotPlugin/Controls/PleaseWaitForm.cs +++ b/src/Greenshot.Base/Controls/PleaseWaitForm.cs @@ -1,143 +1,143 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Windows.Forms; -using System.Threading; -using GreenshotPlugin.Core; -using log4net; - -namespace GreenshotPlugin.Controls -{ - /// - /// Description of PleaseWaitForm. - /// - public partial class PleaseWaitForm : Form - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(PleaseWaitForm)); - private Thread _waitFor; - private string _title; - - public PleaseWaitForm() - { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - Icon = GreenshotResources.GetGreenshotIcon(); - } - - /// - /// Prevent the close-window button showing - /// - private const int CP_NOCLOSE_BUTTON = 0x200; - - protected override CreateParams CreateParams - { - get - { - CreateParams createParams = base.CreateParams; - createParams.ClassStyle |= CP_NOCLOSE_BUTTON; - return createParams; - } - } - - /// - /// Show the "please wait" form, execute the code from the delegate and wait until execution finishes. - /// The supplied delegate will be wrapped with a try/catch so this method can return any exception that was thrown. - /// - /// The title of the form (and Thread) - /// The text in the form - /// delegate { with your code } - public void ShowAndWait(string title, string text, ThreadStart waitDelegate) - { - _title = title; - Text = title; - label_pleasewait.Text = text; - cancelButton.Text = Language.GetString("CANCEL"); - - // Make sure the form is shown. - Show(); - - // Variable to store the exception, if one is generated, from inside the thread. - Exception threadException = null; - try - { - // Wrap the passed delegate in a try/catch which makes it possible to save the exception - _waitFor = new Thread(new ThreadStart( - delegate - { - try - { - waitDelegate.Invoke(); - } - catch (Exception ex) - { - LOG.Error("invoke error:", ex); - threadException = ex; - } - }) - ) - { - Name = title, - IsBackground = true - }; - _waitFor.SetApartmentState(ApartmentState.STA); - _waitFor.Start(); - - // Wait until finished - while (!_waitFor.Join(TimeSpan.FromMilliseconds(100))) - { - Application.DoEvents(); - } - - LOG.DebugFormat("Finished {0}", title); - } - catch (Exception ex) - { - LOG.Error(ex); - throw; - } - finally - { - Close(); - } - - // Check if an exception occured, if so throw it - if (threadException != null) - { - throw threadException; - } - } - - /// - /// Called if the cancel button is clicked, will use Thread.Abort() - /// - /// - /// - private void CancelButtonClick(object sender, EventArgs e) - { - LOG.DebugFormat("Cancel clicked on {0}", _title); - cancelButton.Enabled = false; - _waitFor.Abort(); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Threading; +using System.Windows.Forms; +using Greenshot.Base.Core; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// Description of PleaseWaitForm. + /// + public partial class PleaseWaitForm : Form + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(PleaseWaitForm)); + private Thread _waitFor; + private string _title; + + public PleaseWaitForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + Icon = GreenshotResources.GetGreenshotIcon(); + } + + /// + /// Prevent the close-window button showing + /// + private const int CP_NOCLOSE_BUTTON = 0x200; + + protected override CreateParams CreateParams + { + get + { + CreateParams createParams = base.CreateParams; + createParams.ClassStyle |= CP_NOCLOSE_BUTTON; + return createParams; + } + } + + /// + /// Show the "please wait" form, execute the code from the delegate and wait until execution finishes. + /// The supplied delegate will be wrapped with a try/catch so this method can return any exception that was thrown. + /// + /// The title of the form (and Thread) + /// The text in the form + /// delegate { with your code } + public void ShowAndWait(string title, string text, ThreadStart waitDelegate) + { + _title = title; + Text = title; + label_pleasewait.Text = text; + cancelButton.Text = Language.GetString("CANCEL"); + + // Make sure the form is shown. + Show(); + + // Variable to store the exception, if one is generated, from inside the thread. + Exception threadException = null; + try + { + // Wrap the passed delegate in a try/catch which makes it possible to save the exception + _waitFor = new Thread(new ThreadStart( + delegate + { + try + { + waitDelegate.Invoke(); + } + catch (Exception ex) + { + LOG.Error("invoke error:", ex); + threadException = ex; + } + }) + ) + { + Name = title, + IsBackground = true + }; + _waitFor.SetApartmentState(ApartmentState.STA); + _waitFor.Start(); + + // Wait until finished + while (!_waitFor.Join(TimeSpan.FromMilliseconds(100))) + { + Application.DoEvents(); + } + + LOG.DebugFormat("Finished {0}", title); + } + catch (Exception ex) + { + LOG.Error(ex); + throw; + } + finally + { + Close(); + } + + // Check if an exception occured, if so throw it + if (threadException != null) + { + throw threadException; + } + } + + /// + /// Called if the cancel button is clicked, will use Thread.Abort() + /// + /// + /// + private void CancelButtonClick(object sender, EventArgs e) + { + LOG.DebugFormat("Cancel clicked on {0}", _title); + cancelButton.Enabled = false; + _waitFor.Abort(); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/QualityDialog.Designer.cs b/src/Greenshot.Base/Controls/QualityDialog.Designer.cs similarity index 90% rename from src/GreenshotPlugin/Controls/QualityDialog.Designer.cs rename to src/Greenshot.Base/Controls/QualityDialog.Designer.cs index 5f1c03fce..dd67f3358 100644 --- a/src/GreenshotPlugin/Controls/QualityDialog.Designer.cs +++ b/src/Greenshot.Base/Controls/QualityDialog.Designer.cs @@ -1,147 +1,147 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -namespace GreenshotPlugin.Controls { - partial class QualityDialog { - /// - /// Designer variable used to keep track of non-visual components. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Disposes resources used by the form. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing) { - if (components != null) { - components.Dispose(); - } - } - base.Dispose(disposing); - } - - /// - /// This method is required for Windows Forms designer support. - /// Do not change the method contents inside the source code editor. The Forms designer might - /// not be able to load this method if it was changed manually. - /// - private void InitializeComponent() - { - this.label_choosejpegquality = new GreenshotPlugin.Controls.GreenshotLabel(); - this.textBoxJpegQuality = new System.Windows.Forms.TextBox(); - this.trackBarJpegQuality = new System.Windows.Forms.TrackBar(); - this.checkbox_dontaskagain = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.button_ok = new GreenshotPlugin.Controls.GreenshotButton(); - this.checkBox_reduceColors = new System.Windows.Forms.CheckBox(); - ((System.ComponentModel.ISupportInitialize)(this.trackBarJpegQuality)).BeginInit(); - this.SuspendLayout(); - // - // label_choosejpegquality - // - this.label_choosejpegquality.Location = new System.Drawing.Point(12, 47); - this.label_choosejpegquality.Name = "label_choosejpegquality"; - this.label_choosejpegquality.Size = new System.Drawing.Size(268, 19); - this.label_choosejpegquality.TabIndex = 15; - this.label_choosejpegquality.LanguageKey = "jpegqualitydialog_choosejpegquality"; - // - // textBoxJpegQuality - // - this.textBoxJpegQuality.Location = new System.Drawing.Point(245, 69); - this.textBoxJpegQuality.Name = "textBoxJpegQuality"; - this.textBoxJpegQuality.ReadOnly = true; - this.textBoxJpegQuality.Size = new System.Drawing.Size(35, 20); - this.textBoxJpegQuality.TabIndex = 4; - this.textBoxJpegQuality.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; - // - // trackBarJpegQuality - // - this.trackBarJpegQuality.LargeChange = 10; - this.trackBarJpegQuality.Location = new System.Drawing.Point(12, 69); - this.trackBarJpegQuality.Maximum = 100; - this.trackBarJpegQuality.Name = "trackBarJpegQuality"; - this.trackBarJpegQuality.Size = new System.Drawing.Size(233, 45); - this.trackBarJpegQuality.TabIndex = 3; - this.trackBarJpegQuality.TickFrequency = 10; - this.trackBarJpegQuality.Scroll += new System.EventHandler(this.TrackBarJpegQualityScroll); - // - // checkbox_dontaskagain - // - this.checkbox_dontaskagain.CheckAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_dontaskagain.ImageAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_dontaskagain.Location = new System.Drawing.Point(12, 106); - this.checkbox_dontaskagain.Name = "checkbox_dontaskagain"; - this.checkbox_dontaskagain.LanguageKey = "qualitydialog_dontaskagain"; - this.checkbox_dontaskagain.Size = new System.Drawing.Size(268, 37); - this.checkbox_dontaskagain.TabIndex = 5; - this.checkbox_dontaskagain.TextAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_dontaskagain.UseVisualStyleBackColor = true; - // - // button_ok - // - this.button_ok.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.button_ok.Location = new System.Drawing.Point(205, 149); - this.button_ok.Name = "button_ok"; - this.button_ok.Size = new System.Drawing.Size(75, 23); - this.button_ok.TabIndex = 1; - this.button_ok.LanguageKey = "OK"; - this.button_ok.UseVisualStyleBackColor = true; - this.button_ok.Click += new System.EventHandler(this.Button_okClick); - // - // checkBox_reduceColors - // - this.checkBox_reduceColors.Location = new System.Drawing.Point(12, 11); - this.checkBox_reduceColors.Name = "checkBox_reduceColors"; - this.checkBox_reduceColors.Size = new System.Drawing.Size(95, 17); - this.checkBox_reduceColors.TabIndex = 2; - this.checkBox_reduceColors.Text = "settings_reducecolors"; - this.checkBox_reduceColors.UseVisualStyleBackColor = true; - // - // QualityDialog - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(299, 184); - this.ControlBox = false; - this.Controls.Add(this.checkBox_reduceColors); - this.Controls.Add(this.button_ok); - this.Controls.Add(this.checkbox_dontaskagain); - this.Controls.Add(this.label_choosejpegquality); - this.Controls.Add(this.textBoxJpegQuality); - this.Controls.Add(this.trackBarJpegQuality); - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "QualityDialog"; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.LanguageKey = "qualitydialog_title"; - ((System.ComponentModel.ISupportInitialize)(this.trackBarJpegQuality)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - private GreenshotPlugin.Controls.GreenshotButton button_ok; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_dontaskagain; - private System.Windows.Forms.TrackBar trackBarJpegQuality; - private System.Windows.Forms.TextBox textBoxJpegQuality; - private GreenshotPlugin.Controls.GreenshotLabel label_choosejpegquality; - private System.Windows.Forms.CheckBox checkBox_reduceColors; - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +namespace Greenshot.Base.Controls { + partial class QualityDialog { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() + { + this.label_choosejpegquality = new GreenshotLabel(); + this.textBoxJpegQuality = new System.Windows.Forms.TextBox(); + this.trackBarJpegQuality = new System.Windows.Forms.TrackBar(); + this.checkbox_dontaskagain = new GreenshotCheckBox(); + this.button_ok = new GreenshotButton(); + this.checkBox_reduceColors = new System.Windows.Forms.CheckBox(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarJpegQuality)).BeginInit(); + this.SuspendLayout(); + // + // label_choosejpegquality + // + this.label_choosejpegquality.Location = new System.Drawing.Point(12, 47); + this.label_choosejpegquality.Name = "label_choosejpegquality"; + this.label_choosejpegquality.Size = new System.Drawing.Size(268, 19); + this.label_choosejpegquality.TabIndex = 15; + this.label_choosejpegquality.LanguageKey = "jpegqualitydialog_choosejpegquality"; + // + // textBoxJpegQuality + // + this.textBoxJpegQuality.Location = new System.Drawing.Point(245, 69); + this.textBoxJpegQuality.Name = "textBoxJpegQuality"; + this.textBoxJpegQuality.ReadOnly = true; + this.textBoxJpegQuality.Size = new System.Drawing.Size(35, 20); + this.textBoxJpegQuality.TabIndex = 4; + this.textBoxJpegQuality.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // trackBarJpegQuality + // + this.trackBarJpegQuality.LargeChange = 10; + this.trackBarJpegQuality.Location = new System.Drawing.Point(12, 69); + this.trackBarJpegQuality.Maximum = 100; + this.trackBarJpegQuality.Name = "trackBarJpegQuality"; + this.trackBarJpegQuality.Size = new System.Drawing.Size(233, 45); + this.trackBarJpegQuality.TabIndex = 3; + this.trackBarJpegQuality.TickFrequency = 10; + this.trackBarJpegQuality.Scroll += new System.EventHandler(this.TrackBarJpegQualityScroll); + // + // checkbox_dontaskagain + // + this.checkbox_dontaskagain.CheckAlign = System.Drawing.ContentAlignment.TopLeft; + this.checkbox_dontaskagain.ImageAlign = System.Drawing.ContentAlignment.TopLeft; + this.checkbox_dontaskagain.Location = new System.Drawing.Point(12, 106); + this.checkbox_dontaskagain.Name = "checkbox_dontaskagain"; + this.checkbox_dontaskagain.LanguageKey = "qualitydialog_dontaskagain"; + this.checkbox_dontaskagain.Size = new System.Drawing.Size(268, 37); + this.checkbox_dontaskagain.TabIndex = 5; + this.checkbox_dontaskagain.TextAlign = System.Drawing.ContentAlignment.TopLeft; + this.checkbox_dontaskagain.UseVisualStyleBackColor = true; + // + // button_ok + // + this.button_ok.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button_ok.Location = new System.Drawing.Point(205, 149); + this.button_ok.Name = "button_ok"; + this.button_ok.Size = new System.Drawing.Size(75, 23); + this.button_ok.TabIndex = 1; + this.button_ok.LanguageKey = "OK"; + this.button_ok.UseVisualStyleBackColor = true; + this.button_ok.Click += new System.EventHandler(this.Button_okClick); + // + // checkBox_reduceColors + // + this.checkBox_reduceColors.Location = new System.Drawing.Point(12, 11); + this.checkBox_reduceColors.Name = "checkBox_reduceColors"; + this.checkBox_reduceColors.Size = new System.Drawing.Size(95, 17); + this.checkBox_reduceColors.TabIndex = 2; + this.checkBox_reduceColors.Text = "settings_reducecolors"; + this.checkBox_reduceColors.UseVisualStyleBackColor = true; + // + // QualityDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(299, 184); + this.ControlBox = false; + this.Controls.Add(this.checkBox_reduceColors); + this.Controls.Add(this.button_ok); + this.Controls.Add(this.checkbox_dontaskagain); + this.Controls.Add(this.label_choosejpegquality); + this.Controls.Add(this.textBoxJpegQuality); + this.Controls.Add(this.trackBarJpegQuality); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "QualityDialog"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.LanguageKey = "qualitydialog_title"; + ((System.ComponentModel.ISupportInitialize)(this.trackBarJpegQuality)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + private GreenshotButton button_ok; + private GreenshotCheckBox checkbox_dontaskagain; + private System.Windows.Forms.TrackBar trackBarJpegQuality; + private System.Windows.Forms.TextBox textBoxJpegQuality; + private GreenshotLabel label_choosejpegquality; + private System.Windows.Forms.CheckBox checkBox_reduceColors; + } +} diff --git a/src/GreenshotPlugin/Controls/QualityDialog.cs b/src/Greenshot.Base/Controls/QualityDialog.cs similarity index 92% rename from src/GreenshotPlugin/Controls/QualityDialog.cs rename to src/Greenshot.Base/Controls/QualityDialog.cs index ae8ae07f2..1da67eb2b 100644 --- a/src/GreenshotPlugin/Controls/QualityDialog.cs +++ b/src/Greenshot.Base/Controls/QualityDialog.cs @@ -1,71 +1,71 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces.Plugin; - -namespace GreenshotPlugin.Controls -{ - /// - /// Description of JpegQualityDialog. - /// - public partial class QualityDialog : GreenshotForm - { - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - public SurfaceOutputSettings Settings { get; set; } - - public QualityDialog(SurfaceOutputSettings outputSettings) - { - Settings = outputSettings; - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - - checkBox_reduceColors.Checked = Settings.ReduceColors; - trackBarJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); - trackBarJpegQuality.Value = Settings.JPGQuality; - textBoxJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); - textBoxJpegQuality.Text = Settings.JPGQuality.ToString(); - ToFront = true; - } - - private void Button_okClick(object sender, EventArgs e) - { - Settings.JPGQuality = trackBarJpegQuality.Value; - Settings.ReduceColors = checkBox_reduceColors.Checked; - if (checkbox_dontaskagain.Checked) - { - conf.OutputFileJpegQuality = Settings.JPGQuality; - conf.OutputFilePromptQuality = false; - conf.OutputFileReduceColors = Settings.ReduceColors; - IniConfig.Save(); - } - } - - private void TrackBarJpegQualityScroll(object sender, EventArgs e) - { - textBoxJpegQuality.Text = trackBarJpegQuality.Value.ToString(); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Base.Controls +{ + /// + /// Description of JpegQualityDialog. + /// + public partial class QualityDialog : GreenshotForm + { + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + public SurfaceOutputSettings Settings { get; set; } + + public QualityDialog(SurfaceOutputSettings outputSettings) + { + Settings = outputSettings; + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + + checkBox_reduceColors.Checked = Settings.ReduceColors; + trackBarJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); + trackBarJpegQuality.Value = Settings.JPGQuality; + textBoxJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); + textBoxJpegQuality.Text = Settings.JPGQuality.ToString(); + ToFront = true; + } + + private void Button_okClick(object sender, EventArgs e) + { + Settings.JPGQuality = trackBarJpegQuality.Value; + Settings.ReduceColors = checkBox_reduceColors.Checked; + if (checkbox_dontaskagain.Checked) + { + conf.OutputFileJpegQuality = Settings.JPGQuality; + conf.OutputFilePromptQuality = false; + conf.OutputFileReduceColors = Settings.ReduceColors; + IniConfig.Save(); + } + } + + private void TrackBarJpegQualityScroll(object sender, EventArgs e) + { + textBoxJpegQuality.Text = trackBarJpegQuality.Value.ToString(); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/SaveImageFileDialog.cs b/src/Greenshot.Base/Controls/SaveImageFileDialog.cs similarity index 95% rename from src/GreenshotPlugin/Controls/SaveImageFileDialog.cs rename to src/Greenshot.Base/Controls/SaveImageFileDialog.cs index 49caedb07..d95702547 100644 --- a/src/GreenshotPlugin/Controls/SaveImageFileDialog.cs +++ b/src/Greenshot.Base/Controls/SaveImageFileDialog.cs @@ -1,235 +1,235 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.IO; -using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using log4net; - -namespace GreenshotPlugin.Controls -{ - /// - /// Custom dialog for saving images, wraps SaveFileDialog. - /// For some reason SFD is sealed :( - /// - public class SaveImageFileDialog : IDisposable - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(SaveImageFileDialog)); - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - protected SaveFileDialog SaveFileDialog; - private FilterOption[] _filterOptions; - private DirectoryInfo _eagerlyCreatedDirectory; - private readonly ICaptureDetails _captureDetails; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - if (SaveFileDialog != null) - { - SaveFileDialog.Dispose(); - SaveFileDialog = null; - } - } - } - - public SaveImageFileDialog(ICaptureDetails captureDetails) - { - _captureDetails = captureDetails; - Init(); - } - - private void Init() - { - SaveFileDialog = new SaveFileDialog(); - ApplyFilterOptions(); - string initialDirectory = null; - try - { - conf.ValidateAndCorrectOutputFileAsFullpath(); - initialDirectory = Path.GetDirectoryName(conf.OutputFileAsFullpath); - } - catch - { - LOG.WarnFormat("OutputFileAsFullpath was set to {0}, ignoring due to problem in path.", conf.OutputFileAsFullpath); - } - - if (!string.IsNullOrEmpty(initialDirectory) && Directory.Exists(initialDirectory)) - { - SaveFileDialog.InitialDirectory = initialDirectory; - } - else if (Directory.Exists(conf.OutputFilePath)) - { - SaveFileDialog.InitialDirectory = conf.OutputFilePath; - } - - // The following property fixes a problem that the directory where we save is locked (bug #2899790) - SaveFileDialog.RestoreDirectory = true; - SaveFileDialog.OverwritePrompt = true; - SaveFileDialog.CheckPathExists = false; - SaveFileDialog.AddExtension = true; - ApplySuggestedValues(); - } - - private void ApplyFilterOptions() - { - PrepareFilterOptions(); - string fdf = string.Empty; - int preselect = 0; - var outputFileFormatAsString = Enum.GetName(typeof(OutputFormat), conf.OutputFileFormat); - for (int i = 0; i < _filterOptions.Length; i++) - { - FilterOption fo = _filterOptions[i]; - fdf += fo.Label + "|*." + fo.Extension + "|"; - if (outputFileFormatAsString == fo.Extension) - preselect = i; - } - - fdf = fdf.Substring(0, fdf.Length - 1); - SaveFileDialog.Filter = fdf; - SaveFileDialog.FilterIndex = preselect + 1; - } - - private void PrepareFilterOptions() - { - OutputFormat[] supportedImageFormats = (OutputFormat[]) Enum.GetValues(typeof(OutputFormat)); - _filterOptions = new FilterOption[supportedImageFormats.Length]; - for (int i = 0; i < _filterOptions.Length; i++) - { - string ifo = supportedImageFormats[i].ToString(); - if (ifo.ToLower().Equals("jpeg")) ifo = "Jpg"; // we dont want no jpeg files, so let the dialog check for jpg - FilterOption fo = new FilterOption - { - Label = ifo.ToUpper(), - Extension = ifo.ToLower() - }; - _filterOptions.SetValue(fo, i); - } - } - - /// - /// filename exactly as typed in the filename field - /// - public string FileName - { - get { return SaveFileDialog.FileName; } - set { SaveFileDialog.FileName = value; } - } - - /// - /// initial directory of the dialog - /// - public string InitialDirectory - { - get { return SaveFileDialog.InitialDirectory; } - set { SaveFileDialog.InitialDirectory = value; } - } - - /// - /// returns filename as typed in the filename field with extension. - /// if filename field value ends with selected extension, the value is just returned. - /// otherwise, the selected extension is appended to the filename. - /// - public string FileNameWithExtension - { - get - { - string fn = SaveFileDialog.FileName; - // if the filename contains a valid extension, which is the same like the selected filter item's extension, the filename is okay - if (fn.EndsWith(Extension, StringComparison.CurrentCultureIgnoreCase)) return fn; - // otherwise we just add the selected filter item's extension - else return fn + "." + Extension; - } - set - { - FileName = Path.GetFileNameWithoutExtension(value); - Extension = Path.GetExtension(value); - } - } - - /// - /// gets or sets selected extension - /// - public string Extension - { - get { return _filterOptions[SaveFileDialog.FilterIndex - 1].Extension; } - set - { - for (int i = 0; i < _filterOptions.Length; i++) - { - if (value.Equals(_filterOptions[i].Extension, StringComparison.CurrentCultureIgnoreCase)) - { - SaveFileDialog.FilterIndex = i + 1; - } - } - } - } - - public DialogResult ShowDialog() - { - DialogResult ret = SaveFileDialog.ShowDialog(); - CleanUp(); - return ret; - } - - /// - /// sets InitialDirectory and FileName property of a SaveFileDialog smartly, considering default pattern and last used path - /// - private void ApplySuggestedValues() - { - // build the full path and set dialog properties - FileName = FilenameHelper.GetFilenameWithoutExtensionFromPattern(conf.OutputFileFilenamePattern, _captureDetails); - } - - private class FilterOption - { - public string Label; - public string Extension; - } - - private void CleanUp() - { - // fix for bug #3379053 - try - { - if (_eagerlyCreatedDirectory != null && _eagerlyCreatedDirectory.GetFiles().Length == 0 && _eagerlyCreatedDirectory.GetDirectories().Length == 0) - { - _eagerlyCreatedDirectory.Delete(); - _eagerlyCreatedDirectory = null; - } - } - catch (Exception e) - { - LOG.WarnFormat("Couldn't cleanup directory due to: {0}", e.Message); - _eagerlyCreatedDirectory = null; - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// Custom dialog for saving images, wraps SaveFileDialog. + /// For some reason SFD is sealed :( + /// + public class SaveImageFileDialog : IDisposable + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(SaveImageFileDialog)); + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + protected SaveFileDialog SaveFileDialog; + private FilterOption[] _filterOptions; + private DirectoryInfo _eagerlyCreatedDirectory; + private readonly ICaptureDetails _captureDetails; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (SaveFileDialog != null) + { + SaveFileDialog.Dispose(); + SaveFileDialog = null; + } + } + } + + public SaveImageFileDialog(ICaptureDetails captureDetails) + { + _captureDetails = captureDetails; + Init(); + } + + private void Init() + { + SaveFileDialog = new SaveFileDialog(); + ApplyFilterOptions(); + string initialDirectory = null; + try + { + conf.ValidateAndCorrectOutputFileAsFullpath(); + initialDirectory = Path.GetDirectoryName(conf.OutputFileAsFullpath); + } + catch + { + LOG.WarnFormat("OutputFileAsFullpath was set to {0}, ignoring due to problem in path.", conf.OutputFileAsFullpath); + } + + if (!string.IsNullOrEmpty(initialDirectory) && Directory.Exists(initialDirectory)) + { + SaveFileDialog.InitialDirectory = initialDirectory; + } + else if (Directory.Exists(conf.OutputFilePath)) + { + SaveFileDialog.InitialDirectory = conf.OutputFilePath; + } + + // The following property fixes a problem that the directory where we save is locked (bug #2899790) + SaveFileDialog.RestoreDirectory = true; + SaveFileDialog.OverwritePrompt = true; + SaveFileDialog.CheckPathExists = false; + SaveFileDialog.AddExtension = true; + ApplySuggestedValues(); + } + + private void ApplyFilterOptions() + { + PrepareFilterOptions(); + string fdf = string.Empty; + int preselect = 0; + var outputFileFormatAsString = Enum.GetName(typeof(OutputFormat), conf.OutputFileFormat); + for (int i = 0; i < _filterOptions.Length; i++) + { + FilterOption fo = _filterOptions[i]; + fdf += fo.Label + "|*." + fo.Extension + "|"; + if (outputFileFormatAsString == fo.Extension) + preselect = i; + } + + fdf = fdf.Substring(0, fdf.Length - 1); + SaveFileDialog.Filter = fdf; + SaveFileDialog.FilterIndex = preselect + 1; + } + + private void PrepareFilterOptions() + { + OutputFormat[] supportedImageFormats = (OutputFormat[]) Enum.GetValues(typeof(OutputFormat)); + _filterOptions = new FilterOption[supportedImageFormats.Length]; + for (int i = 0; i < _filterOptions.Length; i++) + { + string ifo = supportedImageFormats[i].ToString(); + if (ifo.ToLower().Equals("jpeg")) ifo = "Jpg"; // we dont want no jpeg files, so let the dialog check for jpg + FilterOption fo = new FilterOption + { + Label = ifo.ToUpper(), + Extension = ifo.ToLower() + }; + _filterOptions.SetValue(fo, i); + } + } + + /// + /// filename exactly as typed in the filename field + /// + public string FileName + { + get { return SaveFileDialog.FileName; } + set { SaveFileDialog.FileName = value; } + } + + /// + /// initial directory of the dialog + /// + public string InitialDirectory + { + get { return SaveFileDialog.InitialDirectory; } + set { SaveFileDialog.InitialDirectory = value; } + } + + /// + /// returns filename as typed in the filename field with extension. + /// if filename field value ends with selected extension, the value is just returned. + /// otherwise, the selected extension is appended to the filename. + /// + public string FileNameWithExtension + { + get + { + string fn = SaveFileDialog.FileName; + // if the filename contains a valid extension, which is the same like the selected filter item's extension, the filename is okay + if (fn.EndsWith(Extension, StringComparison.CurrentCultureIgnoreCase)) return fn; + // otherwise we just add the selected filter item's extension + else return fn + "." + Extension; + } + set + { + FileName = Path.GetFileNameWithoutExtension(value); + Extension = Path.GetExtension(value); + } + } + + /// + /// gets or sets selected extension + /// + public string Extension + { + get { return _filterOptions[SaveFileDialog.FilterIndex - 1].Extension; } + set + { + for (int i = 0; i < _filterOptions.Length; i++) + { + if (value.Equals(_filterOptions[i].Extension, StringComparison.CurrentCultureIgnoreCase)) + { + SaveFileDialog.FilterIndex = i + 1; + } + } + } + } + + public DialogResult ShowDialog() + { + DialogResult ret = SaveFileDialog.ShowDialog(); + CleanUp(); + return ret; + } + + /// + /// sets InitialDirectory and FileName property of a SaveFileDialog smartly, considering default pattern and last used path + /// + private void ApplySuggestedValues() + { + // build the full path and set dialog properties + FileName = FilenameHelper.GetFilenameWithoutExtensionFromPattern(conf.OutputFileFilenamePattern, _captureDetails); + } + + private class FilterOption + { + public string Label; + public string Extension; + } + + private void CleanUp() + { + // fix for bug #3379053 + try + { + if (_eagerlyCreatedDirectory != null && _eagerlyCreatedDirectory.GetFiles().Length == 0 && _eagerlyCreatedDirectory.GetDirectories().Length == 0) + { + _eagerlyCreatedDirectory.Delete(); + _eagerlyCreatedDirectory = null; + } + } + catch (Exception e) + { + LOG.WarnFormat("Couldn't cleanup directory due to: {0}", e.Message); + _eagerlyCreatedDirectory = null; + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Controls/ThumbnailForm.cs b/src/Greenshot.Base/Controls/ThumbnailForm.cs similarity index 92% rename from src/GreenshotPlugin/Controls/ThumbnailForm.cs rename to src/Greenshot.Base/Controls/ThumbnailForm.cs index 2b6b349b4..16d597f3c 100644 --- a/src/GreenshotPlugin/Controls/ThumbnailForm.cs +++ b/src/Greenshot.Base/Controls/ThumbnailForm.cs @@ -1,157 +1,156 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Windows.Forms; -using GreenshotPlugin.Core; -using System.Drawing; -using GreenshotPlugin.Core.Enums; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace GreenshotPlugin.Controls -{ - /// - /// This form allows us to show a Thumbnail preview of a window near the context menu when selecting a window to capture. - /// Didn't make it completely "generic" yet, but at least most logic is in here so we don't have it in the mainform. - /// - public sealed class ThumbnailForm : FormWithoutActivation - { - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - - private IntPtr _thumbnailHandle = IntPtr.Zero; - - public ThumbnailForm() - { - ShowInTaskbar = false; - FormBorderStyle = FormBorderStyle.None; - TopMost = false; - Enabled = false; - if (conf.WindowCaptureMode == WindowCaptureMode.Auto || conf.WindowCaptureMode == WindowCaptureMode.Aero) - { - BackColor = Color.FromArgb(255, conf.DWMBackgroundColor.R, conf.DWMBackgroundColor.G, conf.DWMBackgroundColor.B); - } - else - { - BackColor = Color.White; - } - - // cleanup at close - FormClosing += delegate { UnregisterThumbnail(); }; - } - - public new void Hide() - { - UnregisterThumbnail(); - base.Hide(); - } - - private void UnregisterThumbnail() - { - if (_thumbnailHandle == IntPtr.Zero) return; - - DWM.DwmUnregisterThumbnail(_thumbnailHandle); - _thumbnailHandle = IntPtr.Zero; - } - - /// - /// Show the thumbnail of the supplied window above (or under) the parent Control - /// - /// WindowDetails - /// Control - public void ShowThumbnail(WindowDetails window, Control parentControl) - { - UnregisterThumbnail(); - - DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle); - if (_thumbnailHandle == IntPtr.Zero) return; - - var result = DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize); - if (result.Failed()) - { - DWM.DwmUnregisterThumbnail(_thumbnailHandle); - return; - } - - if (sourceSize.IsEmpty) - { - DWM.DwmUnregisterThumbnail(_thumbnailHandle); - return; - } - - int thumbnailHeight = 200; - int thumbnailWidth = (int) (thumbnailHeight * (sourceSize.Width / (float) sourceSize.Height)); - if (parentControl != null && thumbnailWidth > parentControl.Width) - { - thumbnailWidth = parentControl.Width; - thumbnailHeight = (int) (thumbnailWidth * (sourceSize.Height / (float) sourceSize.Width)); - } - - Width = thumbnailWidth; - Height = thumbnailHeight; - // Prepare the displaying of the Thumbnail - var dwmThumbnailProperties = new DWM_THUMBNAIL_PROPERTIES - { - Opacity = 255, - Visible = true, - SourceClientAreaOnly = false, - Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight) - }; - result = DWM.DwmUpdateThumbnailProperties(_thumbnailHandle, ref dwmThumbnailProperties); - if (result.Failed()) - { - DWM.DwmUnregisterThumbnail(_thumbnailHandle); - return; - } - - if (parentControl != null) - { - AlignToControl(parentControl); - } - - if (!Visible) - { - Show(); - } - - // Make sure it's on "top"! - if (parentControl != null) - { - User32.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE); - } - } - - public void AlignToControl(Control alignTo) - { - var screenBounds = WindowCapture.GetScreenBounds(); - if (screenBounds.Contains(alignTo.Left, alignTo.Top - Height)) - { - Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Top - Height); - } - else - { - Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Bottom); - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; + +namespace Greenshot.Base.Controls +{ + /// + /// This form allows us to show a Thumbnail preview of a window near the context menu when selecting a window to capture. + /// Didn't make it completely "generic" yet, but at least most logic is in here so we don't have it in the mainform. + /// + public sealed class ThumbnailForm : FormWithoutActivation + { + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + + private IntPtr _thumbnailHandle = IntPtr.Zero; + + public ThumbnailForm() + { + ShowInTaskbar = false; + FormBorderStyle = FormBorderStyle.None; + TopMost = false; + Enabled = false; + if (conf.WindowCaptureMode == WindowCaptureMode.Auto || conf.WindowCaptureMode == WindowCaptureMode.Aero) + { + BackColor = Color.FromArgb(255, conf.DWMBackgroundColor.R, conf.DWMBackgroundColor.G, conf.DWMBackgroundColor.B); + } + else + { + BackColor = Color.White; + } + + // cleanup at close + FormClosing += delegate { UnregisterThumbnail(); }; + } + + public new void Hide() + { + UnregisterThumbnail(); + base.Hide(); + } + + private void UnregisterThumbnail() + { + if (_thumbnailHandle == IntPtr.Zero) return; + + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + _thumbnailHandle = IntPtr.Zero; + } + + /// + /// Show the thumbnail of the supplied window above (or under) the parent Control + /// + /// WindowDetails + /// Control + public void ShowThumbnail(WindowDetails window, Control parentControl) + { + UnregisterThumbnail(); + + DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle); + if (_thumbnailHandle == IntPtr.Zero) return; + + var result = DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize); + if (result.Failed()) + { + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + return; + } + + if (sourceSize.IsEmpty) + { + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + return; + } + + int thumbnailHeight = 200; + int thumbnailWidth = (int) (thumbnailHeight * (sourceSize.Width / (float) sourceSize.Height)); + if (parentControl != null && thumbnailWidth > parentControl.Width) + { + thumbnailWidth = parentControl.Width; + thumbnailHeight = (int) (thumbnailWidth * (sourceSize.Height / (float) sourceSize.Width)); + } + + Width = thumbnailWidth; + Height = thumbnailHeight; + // Prepare the displaying of the Thumbnail + var dwmThumbnailProperties = new DWM_THUMBNAIL_PROPERTIES + { + Opacity = 255, + Visible = true, + SourceClientAreaOnly = false, + Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight) + }; + result = DWM.DwmUpdateThumbnailProperties(_thumbnailHandle, ref dwmThumbnailProperties); + if (result.Failed()) + { + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + return; + } + + if (parentControl != null) + { + AlignToControl(parentControl); + } + + if (!Visible) + { + Show(); + } + + // Make sure it's on "top"! + if (parentControl != null) + { + User32.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE); + } + } + + public void AlignToControl(Control alignTo) + { + var screenBounds = WindowCapture.GetScreenBounds(); + if (screenBounds.Contains(alignTo.Left, alignTo.Top - Height)) + { + Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Top - Height); + } + else + { + Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Bottom); + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/AbstractDestination.cs b/src/Greenshot.Base/Core/AbstractDestination.cs similarity index 96% rename from src/GreenshotPlugin/Core/AbstractDestination.cs rename to src/Greenshot.Base/Core/AbstractDestination.cs index 27c6abbb4..c9864f99b 100644 --- a/src/GreenshotPlugin/Core/AbstractDestination.cs +++ b/src/Greenshot.Base/Core/AbstractDestination.cs @@ -1,416 +1,416 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Threading; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.UnmanagedHelpers; -using log4net; - -namespace GreenshotPlugin.Core -{ - /// - /// Description of AbstractDestination. - /// - public abstract class AbstractDestination : IDestination - { - private static readonly ILog Log = LogManager.GetLogger(typeof(AbstractDestination)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - - public virtual int CompareTo(object obj) - { - if (!(obj is IDestination other)) - { - return 1; - } - - if (Priority == other.Priority) - { - return string.Compare(Description, other.Description, StringComparison.Ordinal); - } - - return Priority - other.Priority; - } - - public abstract string Designation { get; } - - public abstract string Description { get; } - - public virtual int Priority => 10; - - public virtual Image DisplayIcon => null; - - public virtual Keys EditorShortcutKeys => Keys.None; - - public virtual IEnumerable DynamicDestinations() - { - yield break; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - //if (disposing) {} - } - - public virtual bool IsDynamic => false; - - public virtual bool UseDynamicsOnly => false; - - public virtual bool IsLinkable => false; - - public virtual bool IsActive - { - get - { - if (CoreConfig.ExcludeDestinations != null && CoreConfig.ExcludeDestinations.Contains(Designation)) - { - return false; - } - - return true; - } - } - - public abstract ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); - - /// - /// A small helper method to perform some default destination actions, like inform the surface of the export - /// - /// - /// - public void ProcessExport(ExportInformation exportInformation, ISurface surface) - { - if (exportInformation != null && exportInformation.ExportMade) - { - if (!string.IsNullOrEmpty(exportInformation.Uri)) - { - surface.UploadUrl = exportInformation.Uri; - surface.SendMessageEvent(this, SurfaceMessageTyp.UploadedUri, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); - } - else if (!string.IsNullOrEmpty(exportInformation.Filepath)) - { - surface.LastSaveFullPath = exportInformation.Filepath; - surface.SendMessageEvent(this, SurfaceMessageTyp.FileSaved, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); - } - else - { - surface.SendMessageEvent(this, SurfaceMessageTyp.Info, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); - } - - surface.Modified = false; - } - else if (!string.IsNullOrEmpty(exportInformation?.ErrorMessage)) - { - surface.SendMessageEvent(this, SurfaceMessageTyp.Error, - Language.GetFormattedString("exported_to_error", exportInformation.DestinationDescription) + " " + exportInformation.ErrorMessage); - } - } - - public override string ToString() - { - return Description; - } - - /// - /// Helper method to add events which set the tag, this way we can see why there might be a close. - /// - /// Item to add the events to - /// Menu to set the tag - /// Value for the tag - private void AddTagEvents(ToolStripMenuItem menuItem, ContextMenuStrip menu, string tagValue) - { - if (menuItem != null && menu != null) - { - menuItem.MouseDown += delegate - { - Log.DebugFormat("Setting tag to '{0}'", tagValue); - menu.Tag = tagValue; - }; - menuItem.MouseUp += delegate - { - Log.Debug("Deleting tag"); - menu.Tag = null; - }; - } - } - - /// - /// This method will create and show the destination picker menu - /// - /// Boolean if the dynamic values also need to be added - /// The surface which can be exported - /// Details for the surface - /// The list of destinations to show - /// - public ExportInformation ShowPickerMenu(bool addDynamics, ISurface surface, ICaptureDetails captureDetails, IEnumerable destinations) - { - // Generate an empty ExportInformation object, for when nothing was selected. - ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker")); - var menu = new ContextMenuStrip - { - ImageScalingSize = CoreConfig.ScaledIconSize, - Tag = null, - TopLevel = true - }; - - menu.Opening += (sender, args) => - { - // find the DPI settings for the screen where this is going to land - var screenDpi = DpiHelper.GetDpi(menu.Location); - var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, screenDpi); - menu.SuspendLayout(); - var fontSize = DpiHelper.ScaleWithDpi(12f, screenDpi); - menu.Font = new Font(FontFamily.GenericSansSerif, fontSize, FontStyle.Regular, GraphicsUnit.Pixel); - menu.ImageScalingSize = scaledIconSize; - menu.ResumeLayout(); - }; - - menu.Closing += delegate(object source, ToolStripDropDownClosingEventArgs eventArgs) - { - Log.DebugFormat("Close reason: {0}", eventArgs.CloseReason); - switch (eventArgs.CloseReason) - { - case ToolStripDropDownCloseReason.AppFocusChange: - if (menu.Tag == null) - { - // Do not allow the close if the tag is not set, this means the user clicked somewhere else. - eventArgs.Cancel = true; - } - else - { - Log.DebugFormat("Letting the menu 'close' as the tag is set to '{0}'", menu.Tag); - } - - break; - case ToolStripDropDownCloseReason.ItemClicked: - case ToolStripDropDownCloseReason.CloseCalled: - // The ContextMenuStrip can be "closed" for these reasons. - break; - case ToolStripDropDownCloseReason.Keyboard: - // Dispose as the close is clicked - if (!captureDetails.HasDestination("Editor")) - { - surface.Dispose(); - surface = null; - } - - break; - default: - eventArgs.Cancel = true; - break; - } - }; - menu.MouseEnter += delegate - { - // in case the menu has been unfocused, focus again so that dropdown menus will still open on mouseenter - if (!menu.ContainsFocus) - { - menu.Focus(); - } - }; - foreach (IDestination destination in destinations) - { - // Fix foreach loop variable for the delegate - ToolStripMenuItem item = destination.GetMenuItem(addDynamics, menu, - delegate(object sender, EventArgs e) - { - ToolStripMenuItem toolStripMenuItem = sender as ToolStripMenuItem; - IDestination clickedDestination = (IDestination) toolStripMenuItem?.Tag; - if (clickedDestination == null) - { - return; - } - - menu.Tag = clickedDestination.Designation; - // Export - exportInformation = clickedDestination.ExportCapture(true, surface, captureDetails); - if (exportInformation != null && exportInformation.ExportMade) - { - Log.InfoFormat("Export to {0} success, closing menu", exportInformation.DestinationDescription); - // close menu if the destination wasn't the editor - menu.Close(); - - // Cleanup surface, only if there is no editor in the destinations and we didn't export to the editor - if (!captureDetails.HasDestination("Editor") && !"Editor".Equals(clickedDestination.Designation)) - { - surface.Dispose(); - surface = null; - } - } - else - { - Log.Info("Export cancelled or failed, showing menu again"); - - // Make sure a click besides the menu don't close it. - menu.Tag = null; - - // This prevents the problem that the context menu shows in the task-bar - ShowMenuAtCursor(menu); - } - } - ); - if (item != null) - { - menu.Items.Add(item); - } - } - - // Close - menu.Items.Add(new ToolStripSeparator()); - ToolStripMenuItem closeItem = new ToolStripMenuItem(Language.GetString("editor_close")) - { - Image = GreenshotResources.GetImage("Close.Image") - }; - closeItem.Click += delegate - { - // This menu entry is the close itself, we can dispose the surface - menu.Close(); - if (!captureDetails.HasDestination("Editor")) - { - surface.Dispose(); - surface = null; - } - }; - menu.Items.Add(closeItem); - - ShowMenuAtCursor(menu); - return exportInformation; - } - - /// - /// This method will show the supplied context menu at the mouse cursor, also makes sure it has focus and it's not visible in the taskbar. - /// - /// - private static void ShowMenuAtCursor(ContextMenuStrip menu) - { - // find a suitable location - Point location = Cursor.Position; - Rectangle menuRectangle = new Rectangle(location, menu.Size); - - menuRectangle.Intersect(WindowCapture.GetScreenBounds()); - if (menuRectangle.Height < menu.Height) - { - location.Offset(-40, -(menuRectangle.Height - menu.Height)); - } - else - { - location.Offset(-40, -10); - } - - // This prevents the problem that the context menu shows in the task-bar - User32.SetForegroundWindow(SimpleServiceProvider.Current.GetInstance().ContextMenuStrip.Handle); - menu.Show(location); - menu.Focus(); - - // Wait for the menu to close, so we can dispose it. - while (true) - { - if (menu.Visible) - { - Application.DoEvents(); - Thread.Sleep(100); - } - else - { - menu.Dispose(); - break; - } - } - } - - /// - /// Return a menu item - /// - /// - /// - /// - /// ToolStripMenuItem - public virtual ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler) - { - var basisMenuItem = new ToolStripMenuItem(Description) - { - Image = DisplayIcon, - Tag = this, - Text = Description - }; - AddTagEvents(basisMenuItem, menu, Description); - basisMenuItem.Click -= destinationClickHandler; - basisMenuItem.Click += destinationClickHandler; - - if (IsDynamic && addDynamics) - { - basisMenuItem.DropDownOpening += delegate - { - if (basisMenuItem.DropDownItems.Count == 0) - { - List subDestinations = new List(); - // Fixing Bug #3536968 by catching the COMException (every exception) and not displaying the "subDestinations" - try - { - subDestinations.AddRange(DynamicDestinations()); - } - catch (Exception ex) - { - Log.ErrorFormat("Skipping {0}, due to the following error: {1}", Description, ex.Message); - } - - if (subDestinations.Count > 0) - { - if (UseDynamicsOnly && subDestinations.Count == 1) - { - basisMenuItem.Tag = subDestinations[0]; - basisMenuItem.Text = subDestinations[0].Description; - basisMenuItem.Click -= destinationClickHandler; - basisMenuItem.Click += destinationClickHandler; - } - else - { - foreach (IDestination subDestination in subDestinations) - { - var destinationMenuItem = new ToolStripMenuItem(subDestination.Description) - { - Tag = subDestination, - Image = subDestination.DisplayIcon - }; - destinationMenuItem.Click += destinationClickHandler; - AddTagEvents(destinationMenuItem, menu, subDestination.Description); - basisMenuItem.DropDownItems.Add(destinationMenuItem); - } - } - } - } - }; - } - - return basisMenuItem; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Threading; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.UnmanagedHelpers; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// Description of AbstractDestination. + /// + public abstract class AbstractDestination : IDestination + { + private static readonly ILog Log = LogManager.GetLogger(typeof(AbstractDestination)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + + public virtual int CompareTo(object obj) + { + if (!(obj is IDestination other)) + { + return 1; + } + + if (Priority == other.Priority) + { + return string.Compare(Description, other.Description, StringComparison.Ordinal); + } + + return Priority - other.Priority; + } + + public abstract string Designation { get; } + + public abstract string Description { get; } + + public virtual int Priority => 10; + + public virtual Image DisplayIcon => null; + + public virtual Keys EditorShortcutKeys => Keys.None; + + public virtual IEnumerable DynamicDestinations() + { + yield break; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + //if (disposing) {} + } + + public virtual bool IsDynamic => false; + + public virtual bool UseDynamicsOnly => false; + + public virtual bool IsLinkable => false; + + public virtual bool IsActive + { + get + { + if (CoreConfig.ExcludeDestinations != null && CoreConfig.ExcludeDestinations.Contains(Designation)) + { + return false; + } + + return true; + } + } + + public abstract ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); + + /// + /// A small helper method to perform some default destination actions, like inform the surface of the export + /// + /// + /// + public void ProcessExport(ExportInformation exportInformation, ISurface surface) + { + if (exportInformation != null && exportInformation.ExportMade) + { + if (!string.IsNullOrEmpty(exportInformation.Uri)) + { + surface.UploadUrl = exportInformation.Uri; + surface.SendMessageEvent(this, SurfaceMessageTyp.UploadedUri, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); + } + else if (!string.IsNullOrEmpty(exportInformation.Filepath)) + { + surface.LastSaveFullPath = exportInformation.Filepath; + surface.SendMessageEvent(this, SurfaceMessageTyp.FileSaved, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); + } + else + { + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); + } + + surface.Modified = false; + } + else if (!string.IsNullOrEmpty(exportInformation?.ErrorMessage)) + { + surface.SendMessageEvent(this, SurfaceMessageTyp.Error, + Language.GetFormattedString("exported_to_error", exportInformation.DestinationDescription) + " " + exportInformation.ErrorMessage); + } + } + + public override string ToString() + { + return Description; + } + + /// + /// Helper method to add events which set the tag, this way we can see why there might be a close. + /// + /// Item to add the events to + /// Menu to set the tag + /// Value for the tag + private void AddTagEvents(ToolStripMenuItem menuItem, ContextMenuStrip menu, string tagValue) + { + if (menuItem != null && menu != null) + { + menuItem.MouseDown += delegate + { + Log.DebugFormat("Setting tag to '{0}'", tagValue); + menu.Tag = tagValue; + }; + menuItem.MouseUp += delegate + { + Log.Debug("Deleting tag"); + menu.Tag = null; + }; + } + } + + /// + /// This method will create and show the destination picker menu + /// + /// Boolean if the dynamic values also need to be added + /// The surface which can be exported + /// Details for the surface + /// The list of destinations to show + /// + public ExportInformation ShowPickerMenu(bool addDynamics, ISurface surface, ICaptureDetails captureDetails, IEnumerable destinations) + { + // Generate an empty ExportInformation object, for when nothing was selected. + ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker")); + var menu = new ContextMenuStrip + { + ImageScalingSize = CoreConfig.ScaledIconSize, + Tag = null, + TopLevel = true + }; + + menu.Opening += (sender, args) => + { + // find the DPI settings for the screen where this is going to land + var screenDpi = DpiHelper.GetDpi(menu.Location); + var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, screenDpi); + menu.SuspendLayout(); + var fontSize = DpiHelper.ScaleWithDpi(12f, screenDpi); + menu.Font = new Font(FontFamily.GenericSansSerif, fontSize, FontStyle.Regular, GraphicsUnit.Pixel); + menu.ImageScalingSize = scaledIconSize; + menu.ResumeLayout(); + }; + + menu.Closing += delegate(object source, ToolStripDropDownClosingEventArgs eventArgs) + { + Log.DebugFormat("Close reason: {0}", eventArgs.CloseReason); + switch (eventArgs.CloseReason) + { + case ToolStripDropDownCloseReason.AppFocusChange: + if (menu.Tag == null) + { + // Do not allow the close if the tag is not set, this means the user clicked somewhere else. + eventArgs.Cancel = true; + } + else + { + Log.DebugFormat("Letting the menu 'close' as the tag is set to '{0}'", menu.Tag); + } + + break; + case ToolStripDropDownCloseReason.ItemClicked: + case ToolStripDropDownCloseReason.CloseCalled: + // The ContextMenuStrip can be "closed" for these reasons. + break; + case ToolStripDropDownCloseReason.Keyboard: + // Dispose as the close is clicked + if (!captureDetails.HasDestination("Editor")) + { + surface.Dispose(); + surface = null; + } + + break; + default: + eventArgs.Cancel = true; + break; + } + }; + menu.MouseEnter += delegate + { + // in case the menu has been unfocused, focus again so that dropdown menus will still open on mouseenter + if (!menu.ContainsFocus) + { + menu.Focus(); + } + }; + foreach (IDestination destination in destinations) + { + // Fix foreach loop variable for the delegate + ToolStripMenuItem item = destination.GetMenuItem(addDynamics, menu, + delegate(object sender, EventArgs e) + { + ToolStripMenuItem toolStripMenuItem = sender as ToolStripMenuItem; + IDestination clickedDestination = (IDestination) toolStripMenuItem?.Tag; + if (clickedDestination == null) + { + return; + } + + menu.Tag = clickedDestination.Designation; + // Export + exportInformation = clickedDestination.ExportCapture(true, surface, captureDetails); + if (exportInformation != null && exportInformation.ExportMade) + { + Log.InfoFormat("Export to {0} success, closing menu", exportInformation.DestinationDescription); + // close menu if the destination wasn't the editor + menu.Close(); + + // Cleanup surface, only if there is no editor in the destinations and we didn't export to the editor + if (!captureDetails.HasDestination("Editor") && !"Editor".Equals(clickedDestination.Designation)) + { + surface.Dispose(); + surface = null; + } + } + else + { + Log.Info("Export cancelled or failed, showing menu again"); + + // Make sure a click besides the menu don't close it. + menu.Tag = null; + + // This prevents the problem that the context menu shows in the task-bar + ShowMenuAtCursor(menu); + } + } + ); + if (item != null) + { + menu.Items.Add(item); + } + } + + // Close + menu.Items.Add(new ToolStripSeparator()); + ToolStripMenuItem closeItem = new ToolStripMenuItem(Language.GetString("editor_close")) + { + Image = GreenshotResources.GetImage("Close.Image") + }; + closeItem.Click += delegate + { + // This menu entry is the close itself, we can dispose the surface + menu.Close(); + if (!captureDetails.HasDestination("Editor")) + { + surface.Dispose(); + surface = null; + } + }; + menu.Items.Add(closeItem); + + ShowMenuAtCursor(menu); + return exportInformation; + } + + /// + /// This method will show the supplied context menu at the mouse cursor, also makes sure it has focus and it's not visible in the taskbar. + /// + /// + private static void ShowMenuAtCursor(ContextMenuStrip menu) + { + // find a suitable location + Point location = Cursor.Position; + Rectangle menuRectangle = new Rectangle(location, menu.Size); + + menuRectangle.Intersect(WindowCapture.GetScreenBounds()); + if (menuRectangle.Height < menu.Height) + { + location.Offset(-40, -(menuRectangle.Height - menu.Height)); + } + else + { + location.Offset(-40, -10); + } + + // This prevents the problem that the context menu shows in the task-bar + User32.SetForegroundWindow(SimpleServiceProvider.Current.GetInstance().ContextMenuStrip.Handle); + menu.Show(location); + menu.Focus(); + + // Wait for the menu to close, so we can dispose it. + while (true) + { + if (menu.Visible) + { + Application.DoEvents(); + Thread.Sleep(100); + } + else + { + menu.Dispose(); + break; + } + } + } + + /// + /// Return a menu item + /// + /// + /// + /// + /// ToolStripMenuItem + public virtual ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler) + { + var basisMenuItem = new ToolStripMenuItem(Description) + { + Image = DisplayIcon, + Tag = this, + Text = Description + }; + AddTagEvents(basisMenuItem, menu, Description); + basisMenuItem.Click -= destinationClickHandler; + basisMenuItem.Click += destinationClickHandler; + + if (IsDynamic && addDynamics) + { + basisMenuItem.DropDownOpening += delegate + { + if (basisMenuItem.DropDownItems.Count == 0) + { + List subDestinations = new List(); + // Fixing Bug #3536968 by catching the COMException (every exception) and not displaying the "subDestinations" + try + { + subDestinations.AddRange(DynamicDestinations()); + } + catch (Exception ex) + { + Log.ErrorFormat("Skipping {0}, due to the following error: {1}", Description, ex.Message); + } + + if (subDestinations.Count > 0) + { + if (UseDynamicsOnly && subDestinations.Count == 1) + { + basisMenuItem.Tag = subDestinations[0]; + basisMenuItem.Text = subDestinations[0].Description; + basisMenuItem.Click -= destinationClickHandler; + basisMenuItem.Click += destinationClickHandler; + } + else + { + foreach (IDestination subDestination in subDestinations) + { + var destinationMenuItem = new ToolStripMenuItem(subDestination.Description) + { + Tag = subDestination, + Image = subDestination.DisplayIcon + }; + destinationMenuItem.Click += destinationClickHandler; + AddTagEvents(destinationMenuItem, menu, subDestination.Description); + basisMenuItem.DropDownItems.Add(destinationMenuItem); + } + } + } + } + }; + } + + return basisMenuItem; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/AbstractProcessor.cs b/src/Greenshot.Base/Core/AbstractProcessor.cs similarity index 93% rename from src/GreenshotPlugin/Core/AbstractProcessor.cs rename to src/Greenshot.Base/Core/AbstractProcessor.cs index 6e016e857..b82d11e46 100644 --- a/src/GreenshotPlugin/Core/AbstractProcessor.cs +++ b/src/Greenshot.Base/Core/AbstractProcessor.cs @@ -1,68 +1,68 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using GreenshotPlugin.Interfaces; - -namespace GreenshotPlugin.Core -{ - /// - /// Description of AbstractProcessor. - /// - public abstract class AbstractProcessor : IProcessor - { - public virtual int CompareTo(object obj) - { - if (!(obj is IProcessor other)) - { - return 1; - } - - if (Priority == other.Priority) - { - return string.Compare(Description, other.Description, StringComparison.Ordinal); - } - - return Priority - other.Priority; - } - - public abstract string Designation { get; } - - public abstract string Description { get; } - - public virtual int Priority => 10; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - //if (disposing) {} - } - - public virtual bool isActive => true; - - public abstract bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Base.Core +{ + /// + /// Description of AbstractProcessor. + /// + public abstract class AbstractProcessor : IProcessor + { + public virtual int CompareTo(object obj) + { + if (!(obj is IProcessor other)) + { + return 1; + } + + if (Priority == other.Priority) + { + return string.Compare(Description, other.Description, StringComparison.Ordinal); + } + + return Priority - other.Priority; + } + + public abstract string Designation { get; } + + public abstract string Description { get; } + + public virtual int Priority => 10; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + //if (disposing) {} + } + + public virtual bool isActive => true; + + public abstract bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/AccessibleHelper.cs b/src/Greenshot.Base/Core/AccessibleHelper.cs similarity index 96% rename from src/GreenshotPlugin/Core/AccessibleHelper.cs rename to src/Greenshot.Base/Core/AccessibleHelper.cs index 9a88f68b8..31fca4e83 100644 --- a/src/GreenshotPlugin/Core/AccessibleHelper.cs +++ b/src/Greenshot.Base/Core/AccessibleHelper.cs @@ -1,237 +1,237 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using Accessibility; - -namespace GreenshotPlugin.Core -{ - /// - /// See: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/03a8c835-e9e4-405b-8345-6c3d36bc8941 - /// This should really be cleaned up, there is little OO behind this class! - /// Maybe move the basic Accessible functions to WindowDetails!? - /// - public class Accessible - { - private static int AccessibleObjectFromWindow(IntPtr hWnd, OBJID idObject, ref IAccessible acc) - { - var guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible - object obj = null; - int num = AccessibleObjectFromWindow(hWnd, (uint) idObject, ref guid, ref obj); - acc = (IAccessible) obj; - return num; - } - - [DllImport("oleacc.dll")] - private static extern int AccessibleObjectFromWindow(IntPtr hWnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] - ref object ppvObject); - - [DllImport("oleacc.dll")] - private static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] - object[] rgvarChildren, out int pcObtained); - - [DllImport("oleacc.dll", PreserveSig = false)] - [return: MarshalAs(UnmanagedType.Interface)] - public static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam); - - private enum OBJID : uint - { - OBJID_WINDOW = 0x00000000, - } - - private const int IE_ACTIVE_TAB = 2097154; - private const int CHILDID_SELF = 0; - private readonly IAccessible accessible; - - private Accessible[] Children - { - get - { - object[] res = GetAccessibleChildren(accessible, out var num); - if (res == null) - { - return new Accessible[0]; - } - - List list = new List(res.Length); - foreach (object obj in res) - { - if (obj is IAccessible acc) - { - list.Add(new Accessible(acc)); - } - } - - return list.ToArray(); - } - } - - private string Name - { - get { return accessible.get_accName(CHILDID_SELF); } - } - - private int ChildCount - { - get { return accessible.accChildCount; } - } - - public Accessible(IntPtr hWnd) - { - AccessibleObjectFromWindow(hWnd, OBJID.OBJID_WINDOW, ref accessible); - if (accessible == null) - { - throw new Exception(); - } - } - - public void ActivateIETab(int tabIndexToActivate) - { - var index = 0; - foreach (Accessible accessor in Children) - { - foreach (var child in accessor.Children) - { - foreach (var tab in child.Children) - { - if (tabIndexToActivate >= child.ChildCount - 1) - { - return; - } - - if (index == tabIndexToActivate) - { - tab.Activate(); - return; - } - - index++; - } - } - } - } - - public string IEActiveTabCaption - { - get - { - foreach (Accessible accessor in Children) - { - foreach (var child in accessor.Children) - { - foreach (var tab in child.Children) - { - object tabIndex = tab.accessible.get_accState(0); - - if ((int) tabIndex == IE_ACTIVE_TAB) - { - return tab.Name; - } - } - } - } - - return string.Empty; - } - } - - public List IETabCaptions - { - get - { - var captionList = new List(); - - foreach (Accessible accessor in Children) - { - foreach (var child in accessor.Children) - { - foreach (var tab in child.Children) - { - captionList.Add(tab.Name); - } - } - } - - // TODO: Why again? - if (captionList.Count > 0) - { - captionList.RemoveAt(captionList.Count - 1); - } - - return captionList; - } - } - - - public IEnumerable IETabUrls - { - get - { - foreach (Accessible accessor in Children) - { - foreach (var child in accessor.Children) - { - foreach (var tab in child.Children) - { - object tabIndex = tab.accessible.get_accState(CHILDID_SELF); - var description = tab.accessible.get_accDescription(CHILDID_SELF); - if (!string.IsNullOrEmpty(description)) - { - if (description.Contains(Environment.NewLine)) - { - var url = description.Substring(description.IndexOf(Environment.NewLine)).Trim(); - yield return url; - } - } - } - } - } - } - } - - private Accessible(IAccessible acc) - { - accessible = acc ?? throw new Exception(); - } - - private void Activate() - { - accessible.accDoDefaultAction(CHILDID_SELF); - } - - private static object[] GetAccessibleChildren(IAccessible ao, out int childs) - { - childs = 0; - object[] ret = null; - int count = ao.accChildCount; - - if (count > 0) - { - ret = new object[count]; - AccessibleChildren(ao, 0, count, ret, out childs); - } - - return ret; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Accessibility; + +namespace Greenshot.Base.Core +{ + /// + /// See: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/03a8c835-e9e4-405b-8345-6c3d36bc8941 + /// This should really be cleaned up, there is little OO behind this class! + /// Maybe move the basic Accessible functions to WindowDetails!? + /// + public class Accessible + { + private static int AccessibleObjectFromWindow(IntPtr hWnd, OBJID idObject, ref IAccessible acc) + { + var guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible + object obj = null; + int num = AccessibleObjectFromWindow(hWnd, (uint) idObject, ref guid, ref obj); + acc = (IAccessible) obj; + return num; + } + + [DllImport("oleacc.dll")] + private static extern int AccessibleObjectFromWindow(IntPtr hWnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] + ref object ppvObject); + + [DllImport("oleacc.dll")] + private static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] + object[] rgvarChildren, out int pcObtained); + + [DllImport("oleacc.dll", PreserveSig = false)] + [return: MarshalAs(UnmanagedType.Interface)] + public static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam); + + private enum OBJID : uint + { + OBJID_WINDOW = 0x00000000, + } + + private const int IE_ACTIVE_TAB = 2097154; + private const int CHILDID_SELF = 0; + private readonly IAccessible accessible; + + private Accessible[] Children + { + get + { + object[] res = GetAccessibleChildren(accessible, out var num); + if (res == null) + { + return new Accessible[0]; + } + + List list = new List(res.Length); + foreach (object obj in res) + { + if (obj is IAccessible acc) + { + list.Add(new Accessible(acc)); + } + } + + return list.ToArray(); + } + } + + private string Name + { + get { return accessible.get_accName(CHILDID_SELF); } + } + + private int ChildCount + { + get { return accessible.accChildCount; } + } + + public Accessible(IntPtr hWnd) + { + AccessibleObjectFromWindow(hWnd, OBJID.OBJID_WINDOW, ref accessible); + if (accessible == null) + { + throw new Exception(); + } + } + + public void ActivateIETab(int tabIndexToActivate) + { + var index = 0; + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + if (tabIndexToActivate >= child.ChildCount - 1) + { + return; + } + + if (index == tabIndexToActivate) + { + tab.Activate(); + return; + } + + index++; + } + } + } + } + + public string IEActiveTabCaption + { + get + { + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + object tabIndex = tab.accessible.get_accState(0); + + if ((int) tabIndex == IE_ACTIVE_TAB) + { + return tab.Name; + } + } + } + } + + return string.Empty; + } + } + + public List IETabCaptions + { + get + { + var captionList = new List(); + + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + captionList.Add(tab.Name); + } + } + } + + // TODO: Why again? + if (captionList.Count > 0) + { + captionList.RemoveAt(captionList.Count - 1); + } + + return captionList; + } + } + + + public IEnumerable IETabUrls + { + get + { + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + object tabIndex = tab.accessible.get_accState(CHILDID_SELF); + var description = tab.accessible.get_accDescription(CHILDID_SELF); + if (!string.IsNullOrEmpty(description)) + { + if (description.Contains(Environment.NewLine)) + { + var url = description.Substring(description.IndexOf(Environment.NewLine)).Trim(); + yield return url; + } + } + } + } + } + } + } + + private Accessible(IAccessible acc) + { + accessible = acc ?? throw new Exception(); + } + + private void Activate() + { + accessible.accDoDefaultAction(CHILDID_SELF); + } + + private static object[] GetAccessibleChildren(IAccessible ao, out int childs) + { + childs = 0; + object[] ret = null; + int count = ao.accChildCount; + + if (count > 0) + { + ret = new object[count]; + AccessibleChildren(ao, 0, count, ret, out childs); + } + + return ret; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/AnimationHelpers.cs b/src/Greenshot.Base/Core/AnimationHelpers.cs similarity index 96% rename from src/GreenshotPlugin/Core/AnimationHelpers.cs rename to src/Greenshot.Base/Core/AnimationHelpers.cs index ed8282ac6..0d96016ab 100644 --- a/src/GreenshotPlugin/Core/AnimationHelpers.cs +++ b/src/Greenshot.Base/Core/AnimationHelpers.cs @@ -1,610 +1,610 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Collections.Generic; - -namespace GreenshotPlugin.Core -{ - /// - /// Helper interface for passing base type - /// - public interface IAnimator - { - /// - /// Is there a next frame? - /// - bool HasNext { get; } - - /// - /// The amount of frames - /// - int Frames { get; } - - /// - /// Current frame number - /// - int CurrentFrameNr { get; } - } - - /// - /// This class is used to store a animation leg - /// - internal class AnimationLeg - { - public T Destination { get; set; } - - public int Frames { get; set; } - - public EasingType EasingType { get; set; } - - public EasingMode EasingMode { get; set; } - } - - /// - /// Base class for the animation logic, this only implements Properties and a constructor - /// - /// Type for the animation, like Point/Rectangle/Size - public abstract class AnimatorBase : IAnimator - { - private readonly Queue> _queue = new Queue>(); - - /// - /// Constructor - /// - /// - /// - /// - /// - /// - public AnimatorBase(T first, T last, int frames, EasingType easingType, EasingMode easingMode) - { - First = first; - Last = last; - Frames = frames; - Current = first; - EasingType = easingType; - EasingMode = easingMode; - } - - /// - /// The amount of frames - /// - public int Frames { get; private set; } - - /// - /// Current frame number - /// - public int CurrentFrameNr { get; private set; } - - /// - /// First animation value - /// - public T First { get; private set; } - - /// - /// Last animation value, of this "leg" - /// - public T Last { get; private set; } - - /// - /// Final animation value, this is including the legs - /// - public T Final - { - get - { - if (_queue.Count == 0) - { - return Last; - } - - return _queue.ToArray()[_queue.Count - 1].Destination; - } - } - - /// - /// This restarts the current animation and changes the last frame - /// - /// - public void ChangeDestination(T newDestination) - { - ChangeDestination(newDestination, Frames); - } - - /// - /// This restarts the current animation and changes the last frame - /// - /// - /// - public void ChangeDestination(T newDestination, int frames) - { - _queue.Clear(); - First = Current; - CurrentFrameNr = 0; - Frames = frames; - Last = newDestination; - } - - /// - /// Queue the destination, it will be used to continue at the last frame - /// All values will stay the same - /// - /// - public void QueueDestinationLeg(T queuedDestination) - { - QueueDestinationLeg(queuedDestination, Frames, EasingType, EasingMode); - } - - /// - /// Queue the destination, it will be used to continue at the last frame - /// - /// - /// - public void QueueDestinationLeg(T queuedDestination, int frames) - { - QueueDestinationLeg(queuedDestination, frames, EasingType, EasingMode); - } - - /// - /// Queue the destination, it will be used to continue at the last frame - /// - /// - /// - /// EasingType - public void QueueDestinationLeg(T queuedDestination, int frames, EasingType easingType) - { - QueueDestinationLeg(queuedDestination, frames, easingType, EasingMode); - } - - /// - /// Queue the destination, it will be used to continue at the last frame - /// - /// - /// - /// - /// - public void QueueDestinationLeg(T queuedDestination, int frames, EasingType easingType, EasingMode easingMode) - { - AnimationLeg leg = new AnimationLeg - { - Destination = queuedDestination, - Frames = frames, - EasingType = easingType, - EasingMode = easingMode - }; - _queue.Enqueue(leg); - } - - /// - /// The EasingType to use for the animation - /// - public EasingType EasingType { get; set; } - - /// - /// The EasingMode to use for the animation - /// - public EasingMode EasingMode { get; set; } - - /// - /// Get the easing value, which is from 0-1 and depends on the frame - /// - protected double EasingValue - { - get => - EasingMode switch - { - EasingMode.EaseOut => Easing.EaseOut(CurrentFrameNr / (double) Frames, EasingType), - EasingMode.EaseInOut => Easing.EaseInOut(CurrentFrameNr / (double) Frames, EasingType), - EasingMode.EaseIn => Easing.EaseIn(CurrentFrameNr / (double) Frames, EasingType), - _ => Easing.EaseIn(CurrentFrameNr / (double) Frames, EasingType) - }; - } - - /// - /// Get the current (previous) frame object - /// - public virtual T Current { get; set; } - - /// - /// Returns if there are any frame left, and if this is the case than the frame is increased. - /// - public virtual bool NextFrame - { - get - { - if (CurrentFrameNr < Frames) - { - CurrentFrameNr++; - return true; - } - - if (_queue.Count > 0) - { - First = Current; - CurrentFrameNr = 0; - AnimationLeg nextLeg = _queue.Dequeue(); - Last = nextLeg.Destination; - Frames = nextLeg.Frames; - EasingType = nextLeg.EasingType; - EasingMode = nextLeg.EasingMode; - return true; - } - - return false; - } - } - - /// - /// Are there more frames to animate? - /// - public virtual bool HasNext - { - get - { - if (CurrentFrameNr < Frames) - { - return true; - } - - return _queue.Count > 0; - } - } - - /// - /// Get the next animation frame value object - /// - /// - public abstract T Next(); - } - - /// - /// Implementation of the RectangleAnimator - /// - public class RectangleAnimator : AnimatorBase - { - public RectangleAnimator(Rectangle first, Rectangle last, int frames) - : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) - { - } - - public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType) - : base(first, last, frames, easingType, EasingMode.EaseIn) - { - } - - public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType, EasingMode easingMode) - : base(first, last, frames, easingType, easingMode) - { - } - - /// - /// Calculate the next frame object - /// - /// Rectangle - public override Rectangle Next() - { - if (NextFrame) - { - double easingValue = EasingValue; - double dx = Last.X - First.X; - double dy = Last.Y - First.Y; - - int x = First.X + (int) (easingValue * dx); - int y = First.Y + (int) (easingValue * dy); - double dw = Last.Width - First.Width; - double dh = Last.Height - First.Height; - int width = First.Width + (int) (easingValue * dw); - int height = First.Height + (int) (easingValue * dh); - Current = new Rectangle(x, y, width, height); - } - - return Current; - } - } - - /// - /// Implementation of the PointAnimator - /// - public class PointAnimator : AnimatorBase - { - public PointAnimator(Point first, Point last, int frames) - : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) - { - } - - public PointAnimator(Point first, Point last, int frames, EasingType easingType) - : base(first, last, frames, easingType, EasingMode.EaseIn) - { - } - - public PointAnimator(Point first, Point last, int frames, EasingType easingType, EasingMode easingMode) - : base(first, last, frames, easingType, easingMode) - { - } - - /// - /// Calculate the next frame value - /// - /// Point - public override Point Next() - { - if (NextFrame) - { - double easingValue = EasingValue; - double dx = Last.X - First.X; - double dy = Last.Y - First.Y; - - int x = First.X + (int) (easingValue * dx); - int y = First.Y + (int) (easingValue * dy); - Current = new Point(x, y); - } - - return Current; - } - } - - /// - /// Implementation of the SizeAnimator - /// - public class SizeAnimator : AnimatorBase - { - public SizeAnimator(Size first, Size last, int frames) - : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) - { - } - - public SizeAnimator(Size first, Size last, int frames, EasingType easingType) - : base(first, last, frames, easingType, EasingMode.EaseIn) - { - } - - public SizeAnimator(Size first, Size last, int frames, EasingType easingType, EasingMode easingMode) - : base(first, last, frames, easingType, easingMode) - { - } - - /// - /// Calculate the next frame values - /// - /// Size - public override Size Next() - { - if (NextFrame) - { - double easingValue = EasingValue; - double dw = Last.Width - First.Width; - double dh = Last.Height - First.Height; - int width = First.Width + (int) (easingValue * dw); - int height = First.Height + (int) (easingValue * dh); - Current = new Size(width, height); - } - - return Current; - } - } - - /// - /// Implementation of the ColorAnimator - /// - public class ColorAnimator : AnimatorBase - { - public ColorAnimator(Color first, Color last, int frames) - : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) - { - } - - public ColorAnimator(Color first, Color last, int frames, EasingType easingType) - : base(first, last, frames, easingType, EasingMode.EaseIn) - { - } - - public ColorAnimator(Color first, Color last, int frames, EasingType easingType, EasingMode easingMode) - : base(first, last, frames, easingType, easingMode) - { - } - - /// - /// Calculate the next frame values - /// - /// Color - public override Color Next() - { - if (NextFrame) - { - double easingValue = EasingValue; - double da = Last.A - First.A; - double dr = Last.R - First.R; - double dg = Last.G - First.G; - double db = Last.B - First.B; - int a = First.A + (int) (easingValue * da); - int r = First.R + (int) (easingValue * dr); - int g = First.G + (int) (easingValue * dg); - int b = First.B + (int) (easingValue * db); - Current = Color.FromArgb(a, r, g, b); - } - - return Current; - } - } - - /// - /// Implementation of the IntAnimator - /// - public class IntAnimator : AnimatorBase - { - public IntAnimator(int first, int last, int frames) - : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) - { - } - - public IntAnimator(int first, int last, int frames, EasingType easingType) - : base(first, last, frames, easingType, EasingMode.EaseIn) - { - } - - public IntAnimator(int first, int last, int frames, EasingType easingType, EasingMode easingMode) - : base(first, last, frames, easingType, easingMode) - { - } - - /// - /// Calculate the next frame values - /// - /// int - public override int Next() - { - if (NextFrame) - { - double easingValue = EasingValue; - double delta = Last - First; - Current = First + (int) (easingValue * delta); - } - - return Current; - } - } - - /// - /// Easing logic, to make the animations more "fluent" - /// - public static class Easing - { - // Adapted from http://www.robertpenner.com/easing/penner_chapter7_tweening.pdf - - public static double Ease(double linearStep, double acceleration, EasingType type) - { - double easedStep = acceleration > 0 ? EaseIn(linearStep, type) : acceleration < 0 ? EaseOut(linearStep, type) : linearStep; - // Lerp: - return ((easedStep - linearStep) * Math.Abs(acceleration) + linearStep); - } - - public static double EaseIn(double linearStep, EasingType type) => - type switch - { - EasingType.Step => (linearStep < 0.5 ? 0 : 1), - EasingType.Linear => linearStep, - EasingType.Sine => Sine.EaseIn(linearStep), - EasingType.Quadratic => Power.EaseIn(linearStep, 2), - EasingType.Cubic => Power.EaseIn(linearStep, 3), - EasingType.Quartic => Power.EaseIn(linearStep, 4), - EasingType.Quintic => Power.EaseIn(linearStep, 5), - _ => throw new NotImplementedException() - }; - - public static double EaseOut(double linearStep, EasingType type) => - type switch - { - EasingType.Step => (linearStep < 0.5 ? 0 : 1), - EasingType.Linear => linearStep, - EasingType.Sine => Sine.EaseOut(linearStep), - EasingType.Quadratic => Power.EaseOut(linearStep, 2), - EasingType.Cubic => Power.EaseOut(linearStep, 3), - EasingType.Quartic => Power.EaseOut(linearStep, 4), - EasingType.Quintic => Power.EaseOut(linearStep, 5), - _ => throw new NotImplementedException() - }; - - public static double EaseInOut(double linearStep, EasingType easeInType, EasingType easeOutType) - { - return linearStep < 0.5 ? EaseInOut(linearStep, easeInType) : EaseInOut(linearStep, easeOutType); - } - - public static double EaseInOut(double linearStep, EasingType type) => - type switch - { - EasingType.Step => (linearStep < 0.5 ? 0 : 1), - EasingType.Linear => linearStep, - EasingType.Sine => Sine.EaseInOut(linearStep), - EasingType.Quadratic => Power.EaseInOut(linearStep, 2), - EasingType.Cubic => Power.EaseInOut(linearStep, 3), - EasingType.Quartic => Power.EaseInOut(linearStep, 4), - EasingType.Quintic => Power.EaseInOut(linearStep, 5), - _ => throw new NotImplementedException() - }; - - private static class Sine - { - public static double EaseIn(double s) - { - return Math.Sin(s * (Math.PI / 2) - (Math.PI / 2)) + 1; - } - - public static double EaseOut(double s) - { - return Math.Sin(s * (Math.PI / 2)); - } - - public static double EaseInOut(double s) - { - return Math.Sin(s * Math.PI - (Math.PI / 2) + 1) / 2; - } - } - - private static class Power - { - public static double EaseIn(double s, int power) - { - return Math.Pow(s, power); - } - - public static double EaseOut(double s, int power) - { - var sign = power % 2 == 0 ? -1 : 1; - return sign * (Math.Pow(s - 1, power) + sign); - } - - public static double EaseInOut(double s, int power) - { - s *= 2; - if (s < 1) - { - return EaseIn(s, power) / 2; - } - - var sign = power % 2 == 0 ? -1 : 1; - return (sign / 2.0 * (Math.Pow(s - 2, power) + sign * 2)); - } - } - } - - /// - /// This defines the way the animation works - /// - public enum EasingType - { - Step, - Linear, - Sine, - Quadratic, - Cubic, - Quartic, - Quintic - } - - public enum EasingMode - { - EaseIn, - EaseOut, - EaseInOut - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace Greenshot.Base.Core +{ + /// + /// Helper interface for passing base type + /// + public interface IAnimator + { + /// + /// Is there a next frame? + /// + bool HasNext { get; } + + /// + /// The amount of frames + /// + int Frames { get; } + + /// + /// Current frame number + /// + int CurrentFrameNr { get; } + } + + /// + /// This class is used to store a animation leg + /// + internal class AnimationLeg + { + public T Destination { get; set; } + + public int Frames { get; set; } + + public EasingType EasingType { get; set; } + + public EasingMode EasingMode { get; set; } + } + + /// + /// Base class for the animation logic, this only implements Properties and a constructor + /// + /// Type for the animation, like Point/Rectangle/Size + public abstract class AnimatorBase : IAnimator + { + private readonly Queue> _queue = new Queue>(); + + /// + /// Constructor + /// + /// + /// + /// + /// + /// + public AnimatorBase(T first, T last, int frames, EasingType easingType, EasingMode easingMode) + { + First = first; + Last = last; + Frames = frames; + Current = first; + EasingType = easingType; + EasingMode = easingMode; + } + + /// + /// The amount of frames + /// + public int Frames { get; private set; } + + /// + /// Current frame number + /// + public int CurrentFrameNr { get; private set; } + + /// + /// First animation value + /// + public T First { get; private set; } + + /// + /// Last animation value, of this "leg" + /// + public T Last { get; private set; } + + /// + /// Final animation value, this is including the legs + /// + public T Final + { + get + { + if (_queue.Count == 0) + { + return Last; + } + + return _queue.ToArray()[_queue.Count - 1].Destination; + } + } + + /// + /// This restarts the current animation and changes the last frame + /// + /// + public void ChangeDestination(T newDestination) + { + ChangeDestination(newDestination, Frames); + } + + /// + /// This restarts the current animation and changes the last frame + /// + /// + /// + public void ChangeDestination(T newDestination, int frames) + { + _queue.Clear(); + First = Current; + CurrentFrameNr = 0; + Frames = frames; + Last = newDestination; + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// All values will stay the same + /// + /// + public void QueueDestinationLeg(T queuedDestination) + { + QueueDestinationLeg(queuedDestination, Frames, EasingType, EasingMode); + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// + /// + /// + public void QueueDestinationLeg(T queuedDestination, int frames) + { + QueueDestinationLeg(queuedDestination, frames, EasingType, EasingMode); + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// + /// + /// + /// EasingType + public void QueueDestinationLeg(T queuedDestination, int frames, EasingType easingType) + { + QueueDestinationLeg(queuedDestination, frames, easingType, EasingMode); + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// + /// + /// + /// + /// + public void QueueDestinationLeg(T queuedDestination, int frames, EasingType easingType, EasingMode easingMode) + { + AnimationLeg leg = new AnimationLeg + { + Destination = queuedDestination, + Frames = frames, + EasingType = easingType, + EasingMode = easingMode + }; + _queue.Enqueue(leg); + } + + /// + /// The EasingType to use for the animation + /// + public EasingType EasingType { get; set; } + + /// + /// The EasingMode to use for the animation + /// + public EasingMode EasingMode { get; set; } + + /// + /// Get the easing value, which is from 0-1 and depends on the frame + /// + protected double EasingValue + { + get => + EasingMode switch + { + EasingMode.EaseOut => Easing.EaseOut(CurrentFrameNr / (double) Frames, EasingType), + EasingMode.EaseInOut => Easing.EaseInOut(CurrentFrameNr / (double) Frames, EasingType), + EasingMode.EaseIn => Easing.EaseIn(CurrentFrameNr / (double) Frames, EasingType), + _ => Easing.EaseIn(CurrentFrameNr / (double) Frames, EasingType) + }; + } + + /// + /// Get the current (previous) frame object + /// + public virtual T Current { get; set; } + + /// + /// Returns if there are any frame left, and if this is the case than the frame is increased. + /// + public virtual bool NextFrame + { + get + { + if (CurrentFrameNr < Frames) + { + CurrentFrameNr++; + return true; + } + + if (_queue.Count > 0) + { + First = Current; + CurrentFrameNr = 0; + AnimationLeg nextLeg = _queue.Dequeue(); + Last = nextLeg.Destination; + Frames = nextLeg.Frames; + EasingType = nextLeg.EasingType; + EasingMode = nextLeg.EasingMode; + return true; + } + + return false; + } + } + + /// + /// Are there more frames to animate? + /// + public virtual bool HasNext + { + get + { + if (CurrentFrameNr < Frames) + { + return true; + } + + return _queue.Count > 0; + } + } + + /// + /// Get the next animation frame value object + /// + /// + public abstract T Next(); + } + + /// + /// Implementation of the RectangleAnimator + /// + public class RectangleAnimator : AnimatorBase + { + public RectangleAnimator(Rectangle first, Rectangle last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame object + /// + /// Rectangle + public override Rectangle Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double dx = Last.X - First.X; + double dy = Last.Y - First.Y; + + int x = First.X + (int) (easingValue * dx); + int y = First.Y + (int) (easingValue * dy); + double dw = Last.Width - First.Width; + double dh = Last.Height - First.Height; + int width = First.Width + (int) (easingValue * dw); + int height = First.Height + (int) (easingValue * dh); + Current = new Rectangle(x, y, width, height); + } + + return Current; + } + } + + /// + /// Implementation of the PointAnimator + /// + public class PointAnimator : AnimatorBase + { + public PointAnimator(Point first, Point last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public PointAnimator(Point first, Point last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public PointAnimator(Point first, Point last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame value + /// + /// Point + public override Point Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double dx = Last.X - First.X; + double dy = Last.Y - First.Y; + + int x = First.X + (int) (easingValue * dx); + int y = First.Y + (int) (easingValue * dy); + Current = new Point(x, y); + } + + return Current; + } + } + + /// + /// Implementation of the SizeAnimator + /// + public class SizeAnimator : AnimatorBase + { + public SizeAnimator(Size first, Size last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public SizeAnimator(Size first, Size last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public SizeAnimator(Size first, Size last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame values + /// + /// Size + public override Size Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double dw = Last.Width - First.Width; + double dh = Last.Height - First.Height; + int width = First.Width + (int) (easingValue * dw); + int height = First.Height + (int) (easingValue * dh); + Current = new Size(width, height); + } + + return Current; + } + } + + /// + /// Implementation of the ColorAnimator + /// + public class ColorAnimator : AnimatorBase + { + public ColorAnimator(Color first, Color last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public ColorAnimator(Color first, Color last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public ColorAnimator(Color first, Color last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame values + /// + /// Color + public override Color Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double da = Last.A - First.A; + double dr = Last.R - First.R; + double dg = Last.G - First.G; + double db = Last.B - First.B; + int a = First.A + (int) (easingValue * da); + int r = First.R + (int) (easingValue * dr); + int g = First.G + (int) (easingValue * dg); + int b = First.B + (int) (easingValue * db); + Current = Color.FromArgb(a, r, g, b); + } + + return Current; + } + } + + /// + /// Implementation of the IntAnimator + /// + public class IntAnimator : AnimatorBase + { + public IntAnimator(int first, int last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public IntAnimator(int first, int last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public IntAnimator(int first, int last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame values + /// + /// int + public override int Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double delta = Last - First; + Current = First + (int) (easingValue * delta); + } + + return Current; + } + } + + /// + /// Easing logic, to make the animations more "fluent" + /// + public static class Easing + { + // Adapted from http://www.robertpenner.com/easing/penner_chapter7_tweening.pdf + + public static double Ease(double linearStep, double acceleration, EasingType type) + { + double easedStep = acceleration > 0 ? EaseIn(linearStep, type) : acceleration < 0 ? EaseOut(linearStep, type) : linearStep; + // Lerp: + return ((easedStep - linearStep) * Math.Abs(acceleration) + linearStep); + } + + public static double EaseIn(double linearStep, EasingType type) => + type switch + { + EasingType.Step => (linearStep < 0.5 ? 0 : 1), + EasingType.Linear => linearStep, + EasingType.Sine => Sine.EaseIn(linearStep), + EasingType.Quadratic => Power.EaseIn(linearStep, 2), + EasingType.Cubic => Power.EaseIn(linearStep, 3), + EasingType.Quartic => Power.EaseIn(linearStep, 4), + EasingType.Quintic => Power.EaseIn(linearStep, 5), + _ => throw new NotImplementedException() + }; + + public static double EaseOut(double linearStep, EasingType type) => + type switch + { + EasingType.Step => (linearStep < 0.5 ? 0 : 1), + EasingType.Linear => linearStep, + EasingType.Sine => Sine.EaseOut(linearStep), + EasingType.Quadratic => Power.EaseOut(linearStep, 2), + EasingType.Cubic => Power.EaseOut(linearStep, 3), + EasingType.Quartic => Power.EaseOut(linearStep, 4), + EasingType.Quintic => Power.EaseOut(linearStep, 5), + _ => throw new NotImplementedException() + }; + + public static double EaseInOut(double linearStep, EasingType easeInType, EasingType easeOutType) + { + return linearStep < 0.5 ? EaseInOut(linearStep, easeInType) : EaseInOut(linearStep, easeOutType); + } + + public static double EaseInOut(double linearStep, EasingType type) => + type switch + { + EasingType.Step => (linearStep < 0.5 ? 0 : 1), + EasingType.Linear => linearStep, + EasingType.Sine => Sine.EaseInOut(linearStep), + EasingType.Quadratic => Power.EaseInOut(linearStep, 2), + EasingType.Cubic => Power.EaseInOut(linearStep, 3), + EasingType.Quartic => Power.EaseInOut(linearStep, 4), + EasingType.Quintic => Power.EaseInOut(linearStep, 5), + _ => throw new NotImplementedException() + }; + + private static class Sine + { + public static double EaseIn(double s) + { + return Math.Sin(s * (Math.PI / 2) - (Math.PI / 2)) + 1; + } + + public static double EaseOut(double s) + { + return Math.Sin(s * (Math.PI / 2)); + } + + public static double EaseInOut(double s) + { + return Math.Sin(s * Math.PI - (Math.PI / 2) + 1) / 2; + } + } + + private static class Power + { + public static double EaseIn(double s, int power) + { + return Math.Pow(s, power); + } + + public static double EaseOut(double s, int power) + { + var sign = power % 2 == 0 ? -1 : 1; + return sign * (Math.Pow(s - 1, power) + sign); + } + + public static double EaseInOut(double s, int power) + { + s *= 2; + if (s < 1) + { + return EaseIn(s, power) / 2; + } + + var sign = power % 2 == 0 ? -1 : 1; + return (sign / 2.0 * (Math.Pow(s - 2, power) + sign * 2)); + } + } + } + + /// + /// This defines the way the animation works + /// + public enum EasingType + { + Step, + Linear, + Sine, + Quadratic, + Cubic, + Quartic, + Quintic + } + + public enum EasingMode + { + EaseIn, + EaseOut, + EaseInOut + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/BinaryStructHelper.cs b/src/Greenshot.Base/Core/BinaryStructHelper.cs similarity index 96% rename from src/GreenshotPlugin/Core/BinaryStructHelper.cs rename to src/Greenshot.Base/Core/BinaryStructHelper.cs index 1da7254f7..257d8dd2c 100644 --- a/src/GreenshotPlugin/Core/BinaryStructHelper.cs +++ b/src/Greenshot.Base/Core/BinaryStructHelper.cs @@ -1,108 +1,108 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Core -{ - /// - /// A helper class which does the mashalling for structs - /// - public static class BinaryStructHelper - { - /// - /// Get a struct from a byte array - /// - /// typeof struct - /// byte[] - /// struct - public static T FromByteArray(byte[] bytes) where T : struct - { - IntPtr ptr = IntPtr.Zero; - try - { - int size = Marshal.SizeOf(typeof(T)); - ptr = Marshal.AllocHGlobal(size); - Marshal.Copy(bytes, 0, ptr, size); - return FromIntPtr(ptr); - } - finally - { - if (ptr != IntPtr.Zero) - { - Marshal.FreeHGlobal(ptr); - } - } - } - - /// - /// Get a struct from a byte array - /// - /// typeof struct - /// Pointer to the structor to return - /// struct - public static T FromIntPtr(IntPtr intPtr) where T : struct - { - object obj = Marshal.PtrToStructure(intPtr, typeof(T)); - return (T) obj; - } - - /// - /// copy a struct to a byte array - /// - /// typeof struct - /// struct - /// byte[] - public static byte[] ToByteArray(T obj) where T : struct - { - IntPtr ptr = IntPtr.Zero; - try - { - int size = Marshal.SizeOf(typeof(T)); - ptr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(obj, ptr, true); - return FromPtrToByteArray(ptr); - } - finally - { - if (ptr != IntPtr.Zero) - { - Marshal.FreeHGlobal(ptr); - } - } - } - - /// - /// copy a struct from a pointer to a byte array - /// - /// typeof struct - /// IntPtr to struct - /// byte[] - public static byte[] FromPtrToByteArray(IntPtr ptr) where T : struct - { - int size = Marshal.SizeOf(typeof(T)); - byte[] bytes = new byte[size]; - Marshal.Copy(ptr, bytes, 0, size); - return bytes; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Core +{ + /// + /// A helper class which does the mashalling for structs + /// + public static class BinaryStructHelper + { + /// + /// Get a struct from a byte array + /// + /// typeof struct + /// byte[] + /// struct + public static T FromByteArray(byte[] bytes) where T : struct + { + IntPtr ptr = IntPtr.Zero; + try + { + int size = Marshal.SizeOf(typeof(T)); + ptr = Marshal.AllocHGlobal(size); + Marshal.Copy(bytes, 0, ptr, size); + return FromIntPtr(ptr); + } + finally + { + if (ptr != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptr); + } + } + } + + /// + /// Get a struct from a byte array + /// + /// typeof struct + /// Pointer to the structor to return + /// struct + public static T FromIntPtr(IntPtr intPtr) where T : struct + { + object obj = Marshal.PtrToStructure(intPtr, typeof(T)); + return (T) obj; + } + + /// + /// copy a struct to a byte array + /// + /// typeof struct + /// struct + /// byte[] + public static byte[] ToByteArray(T obj) where T : struct + { + IntPtr ptr = IntPtr.Zero; + try + { + int size = Marshal.SizeOf(typeof(T)); + ptr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(obj, ptr, true); + return FromPtrToByteArray(ptr); + } + finally + { + if (ptr != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptr); + } + } + } + + /// + /// copy a struct from a pointer to a byte array + /// + /// typeof struct + /// IntPtr to struct + /// byte[] + public static byte[] FromPtrToByteArray(IntPtr ptr) where T : struct + { + int size = Marshal.SizeOf(typeof(T)); + byte[] bytes = new byte[size]; + Marshal.Copy(ptr, bytes, 0, size); + return bytes; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Cache.cs b/src/Greenshot.Base/Core/Cache.cs similarity index 96% rename from src/GreenshotPlugin/Core/Cache.cs rename to src/Greenshot.Base/Core/Cache.cs index 5707f2465..f761b8b89 100644 --- a/src/GreenshotPlugin/Core/Cache.cs +++ b/src/Greenshot.Base/Core/Cache.cs @@ -1,259 +1,259 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Timers; -using log4net; - -namespace GreenshotPlugin.Core -{ - /// - /// Cache class - /// - /// Type of key - /// Type of value - public class Cache - { - private static readonly ILog Log = LogManager.GetLogger(typeof(Cache)); - private readonly IDictionary _internalCache = new Dictionary(); - private readonly object _lockObject = new object(); - private readonly int _secondsToExpire = 10; - private readonly CacheObjectExpired _expiredCallback; - - public delegate void CacheObjectExpired(TK key, TV cacheValue); - - /// - /// Initialize the cache - /// - public Cache() - { - } - - /// - /// Initialize the cache - /// - /// - public Cache(CacheObjectExpired expiredCallback) : this() - { - _expiredCallback = expiredCallback; - } - - /// - /// Initialize the cache with a expire setting - /// - /// - public Cache(int secondsToExpire) : this() - { - _secondsToExpire = secondsToExpire; - } - - /// - /// Initialize the cache with a expire setting - /// - /// - /// - public Cache(int secondsToExpire, CacheObjectExpired expiredCallback) : this(expiredCallback) - { - _secondsToExpire = secondsToExpire; - } - - /// - /// Enumerable for the values in the cache - /// - public IEnumerable Elements - { - get - { - List elements = new List(); - - lock (_lockObject) - { - foreach (TV element in _internalCache.Values) - { - elements.Add(element); - } - } - - foreach (TV element in elements) - { - yield return element; - } - } - } - - /// - /// Get the value by key from the cache - /// - /// - /// - public TV this[TK key] - { - get - { - TV result = default; - lock (_lockObject) - { - if (_internalCache.ContainsKey(key)) - { - result = _internalCache[key]; - } - } - - return result; - } - } - - /// - /// Contains - /// - /// - /// true if the cache contains the key - public bool Contains(TK key) - { - lock (_lockObject) - { - return _internalCache.ContainsKey(key); - } - } - - /// - /// Add a value to the cache - /// - /// - /// - public void Add(TK key, TV value) - { - Add(key, value, null); - } - - /// - /// Add a value to the cache - /// - /// - /// - /// optional value for the seconds to expire - public void Add(TK key, TV value, int? secondsToExpire) - { - lock (_lockObject) - { - var cachedItem = new CachedItem(key, value, secondsToExpire ?? _secondsToExpire); - cachedItem.Expired += delegate(TK cacheKey, TV cacheValue) - { - if (_internalCache.ContainsKey(cacheKey)) - { - Log.DebugFormat("Expiring object with Key: {0}", cacheKey); - _expiredCallback?.Invoke(cacheKey, cacheValue); - Remove(cacheKey); - } - else - { - Log.DebugFormat("Expired old object with Key: {0}", cacheKey); - } - }; - - if (_internalCache.ContainsKey(key)) - { - _internalCache[key] = value; - Log.DebugFormat("Updated item with Key: {0}", key); - } - else - { - _internalCache.Add(key, cachedItem); - Log.DebugFormat("Added item with Key: {0}", key); - } - } - } - - /// - /// Remove item from cache - /// - /// - public void Remove(TK key) - { - lock (_lockObject) - { - if (!_internalCache.ContainsKey(key)) - { - throw new ApplicationException($"An object with key ‘{key}’ does not exists in cache"); - } - - _internalCache.Remove(key); - Log.DebugFormat("Removed item with Key: {0}", key); - } - } - - /// - /// A cache item - /// - private class CachedItem - { - public event CacheObjectExpired Expired; - private readonly int _secondsToExpire; - private readonly Timer _timerEvent; - - public CachedItem(TK key, TV item, int secondsToExpire) - { - if (key == null) - { - throw new ArgumentNullException(nameof(key)); - } - - Key = key; - Item = item; - _secondsToExpire = secondsToExpire; - if (secondsToExpire <= 0) - { - return; - } - - _timerEvent = new Timer(secondsToExpire * 1000) - { - AutoReset = false - }; - _timerEvent.Elapsed += timerEvent_Elapsed; - _timerEvent.Start(); - } - - private void ExpireNow() - { - _timerEvent.Stop(); - if (_secondsToExpire > 0) - { - Expired?.Invoke(Key, Item); - } - } - - private void timerEvent_Elapsed(object sender, ElapsedEventArgs e) - { - ExpireNow(); - } - - public TK Key { get; private set; } - public TV Item { get; private set; } - - public static implicit operator TV(CachedItem a) - { - return a.Item; - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Timers; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// Cache class + /// + /// Type of key + /// Type of value + public class Cache + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Cache)); + private readonly IDictionary _internalCache = new Dictionary(); + private readonly object _lockObject = new object(); + private readonly int _secondsToExpire = 10; + private readonly CacheObjectExpired _expiredCallback; + + public delegate void CacheObjectExpired(TK key, TV cacheValue); + + /// + /// Initialize the cache + /// + public Cache() + { + } + + /// + /// Initialize the cache + /// + /// + public Cache(CacheObjectExpired expiredCallback) : this() + { + _expiredCallback = expiredCallback; + } + + /// + /// Initialize the cache with a expire setting + /// + /// + public Cache(int secondsToExpire) : this() + { + _secondsToExpire = secondsToExpire; + } + + /// + /// Initialize the cache with a expire setting + /// + /// + /// + public Cache(int secondsToExpire, CacheObjectExpired expiredCallback) : this(expiredCallback) + { + _secondsToExpire = secondsToExpire; + } + + /// + /// Enumerable for the values in the cache + /// + public IEnumerable Elements + { + get + { + List elements = new List(); + + lock (_lockObject) + { + foreach (TV element in _internalCache.Values) + { + elements.Add(element); + } + } + + foreach (TV element in elements) + { + yield return element; + } + } + } + + /// + /// Get the value by key from the cache + /// + /// + /// + public TV this[TK key] + { + get + { + TV result = default; + lock (_lockObject) + { + if (_internalCache.ContainsKey(key)) + { + result = _internalCache[key]; + } + } + + return result; + } + } + + /// + /// Contains + /// + /// + /// true if the cache contains the key + public bool Contains(TK key) + { + lock (_lockObject) + { + return _internalCache.ContainsKey(key); + } + } + + /// + /// Add a value to the cache + /// + /// + /// + public void Add(TK key, TV value) + { + Add(key, value, null); + } + + /// + /// Add a value to the cache + /// + /// + /// + /// optional value for the seconds to expire + public void Add(TK key, TV value, int? secondsToExpire) + { + lock (_lockObject) + { + var cachedItem = new CachedItem(key, value, secondsToExpire ?? _secondsToExpire); + cachedItem.Expired += delegate(TK cacheKey, TV cacheValue) + { + if (_internalCache.ContainsKey(cacheKey)) + { + Log.DebugFormat("Expiring object with Key: {0}", cacheKey); + _expiredCallback?.Invoke(cacheKey, cacheValue); + Remove(cacheKey); + } + else + { + Log.DebugFormat("Expired old object with Key: {0}", cacheKey); + } + }; + + if (_internalCache.ContainsKey(key)) + { + _internalCache[key] = value; + Log.DebugFormat("Updated item with Key: {0}", key); + } + else + { + _internalCache.Add(key, cachedItem); + Log.DebugFormat("Added item with Key: {0}", key); + } + } + } + + /// + /// Remove item from cache + /// + /// + public void Remove(TK key) + { + lock (_lockObject) + { + if (!_internalCache.ContainsKey(key)) + { + throw new ApplicationException($"An object with key ‘{key}’ does not exists in cache"); + } + + _internalCache.Remove(key); + Log.DebugFormat("Removed item with Key: {0}", key); + } + } + + /// + /// A cache item + /// + private class CachedItem + { + public event CacheObjectExpired Expired; + private readonly int _secondsToExpire; + private readonly Timer _timerEvent; + + public CachedItem(TK key, TV item, int secondsToExpire) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + Key = key; + Item = item; + _secondsToExpire = secondsToExpire; + if (secondsToExpire <= 0) + { + return; + } + + _timerEvent = new Timer(secondsToExpire * 1000) + { + AutoReset = false + }; + _timerEvent.Elapsed += timerEvent_Elapsed; + _timerEvent.Start(); + } + + private void ExpireNow() + { + _timerEvent.Stop(); + if (_secondsToExpire > 0) + { + Expired?.Invoke(Key, Item); + } + } + + private void timerEvent_Elapsed(object sender, ElapsedEventArgs e) + { + ExpireNow(); + } + + public TK Key { get; private set; } + public TV Item { get; private set; } + + public static implicit operator TV(CachedItem a) + { + return a.Item; + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Capture.cs b/src/Greenshot.Base/Core/Capture.cs similarity index 98% rename from src/GreenshotPlugin/Core/Capture.cs rename to src/Greenshot.Base/Core/Capture.cs index e5e7d7234..b4d172dc2 100644 --- a/src/GreenshotPlugin/Core/Capture.cs +++ b/src/Greenshot.Base/Core/Capture.cs @@ -22,11 +22,11 @@ using System; using System.Drawing; using System.Drawing.Imaging; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; using log4net; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// This class is used to pass an instance of the "Capture" around diff --git a/src/GreenshotPlugin/Core/CaptureDetails.cs b/src/Greenshot.Base/Core/CaptureDetails.cs similarity index 97% rename from src/GreenshotPlugin/Core/CaptureDetails.cs rename to src/Greenshot.Base/Core/CaptureDetails.cs index 96c9abb41..58e3f19be 100644 --- a/src/GreenshotPlugin/Core/CaptureDetails.cs +++ b/src/Greenshot.Base/Core/CaptureDetails.cs @@ -21,10 +21,10 @@ using System; using System.Collections.Generic; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// This Class is used to pass details about the capture around. diff --git a/src/GreenshotPlugin/Core/CaptureHandler.cs b/src/Greenshot.Base/Core/CaptureHandler.cs similarity index 95% rename from src/GreenshotPlugin/Core/CaptureHandler.cs rename to src/Greenshot.Base/Core/CaptureHandler.cs index 952131330..ea11c464d 100644 --- a/src/GreenshotPlugin/Core/CaptureHandler.cs +++ b/src/Greenshot.Base/Core/CaptureHandler.cs @@ -1,43 +1,43 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; - -namespace GreenshotPlugin.Core -{ - /// - /// This is the method signature which is used to capture a rectangle from the screen. - /// - /// - /// Captured Bitmap - public delegate Bitmap CaptureScreenRectangleHandler(Rectangle captureBounds); - - /// - /// This is a hack to experiment with different screen capture routines - /// - public static class CaptureHandler - { - /// - /// By changing this value, null is default - /// - public static CaptureScreenRectangleHandler CaptureScreenRectangle { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; + +namespace Greenshot.Base.Core +{ + /// + /// This is the method signature which is used to capture a rectangle from the screen. + /// + /// + /// Captured Bitmap + public delegate Bitmap CaptureScreenRectangleHandler(Rectangle captureBounds); + + /// + /// This is a hack to experiment with different screen capture routines + /// + public static class CaptureHandler + { + /// + /// By changing this value, null is default + /// + public static CaptureScreenRectangleHandler CaptureScreenRectangle { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs similarity index 97% rename from src/GreenshotPlugin/Core/ClipboardHelper.cs rename to src/Greenshot.Base/Core/ClipboardHelper.cs index f3c57b3d0..cb10a7be3 100644 --- a/src/GreenshotPlugin/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -1,1077 +1,1076 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Windows.Forms; -using GreenshotPlugin.UnmanagedHelpers; -using System.Runtime.InteropServices; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; -using GreenshotPlugin.Interop; -using log4net; -using HtmlDocument = HtmlAgilityPack.HtmlDocument; - -namespace GreenshotPlugin.Core -{ - /// - /// Description of ClipboardHelper. - /// - public static class ClipboardHelper - { - private static readonly ILog Log = LogManager.GetLogger(typeof(ClipboardHelper)); - private static readonly object ClipboardLockObject = new object(); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static readonly string FORMAT_FILECONTENTS = "FileContents"; - private static readonly string FORMAT_HTML = "text/html"; - private static readonly string FORMAT_PNG = "PNG"; - private static readonly string FORMAT_PNG_OFFICEART = "PNG+Office Art"; - private static readonly string FORMAT_17 = "Format17"; - private static readonly string FORMAT_JPG = "JPG"; - private static readonly string FORMAT_JPEG = "JPEG"; - private static readonly string FORMAT_JFIF = "JFIF"; - private static readonly string FORMAT_JFIF_OFFICEART = "JFIF+Office Art"; - private static readonly string FORMAT_GIF = "GIF"; - - private static readonly string FORMAT_BITMAP = "System.Drawing.Bitmap"; - //private static readonly string FORMAT_HTML = "HTML Format"; - - // Template for the HTML Text on the clipboard - // see: http://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx - // or: http://msdn.microsoft.com/en-us/library/Aa767917.aspx - private const string HtmlClipboardString = @"Version:0.9 -StartHTML:<<<<<<<1 -EndHTML:<<<<<<<2 -StartFragment:<<<<<<<3 -EndFragment:<<<<<<<4 -StartSelection:<<<<<<<3 -EndSelection:<<<<<<<4 - - - -Greenshot capture - - - - - - -"; - - private const string HtmlClipboardBase64String = @"Version:0.9 -StartHTML:<<<<<<<1 -EndHTML:<<<<<<<2 -StartFragment:<<<<<<<3 -EndFragment:<<<<<<<4 -StartSelection:<<<<<<<3 -EndSelection:<<<<<<<4 - - - -Greenshot capture - - - - - - -"; - - /// - /// Get the current "ClipboardOwner" but only if it isn't us! - /// - /// current clipboard owner - private static string GetClipboardOwner() - { - string owner = null; - try - { - IntPtr hWnd = User32.GetClipboardOwner(); - if (hWnd != IntPtr.Zero) - { - try - { - User32.GetWindowThreadProcessId(hWnd, out var pid); - using Process me = Process.GetCurrentProcess(); - using Process ownerProcess = Process.GetProcessById(pid); - // Exclude myself - if (me.Id != ownerProcess.Id) - { - // Get Process Name - owner = ownerProcess.ProcessName; - // Try to get the starting Process Filename, this might fail. - try - { - owner = ownerProcess.Modules[0].FileName; - } - catch (Exception) - { - // Ignore - } - } - } - catch (Exception e) - { - Log.Warn("Non critical error: Couldn't get clipboard process, trying to use the title.", e); - var title = new StringBuilder(260, 260); - User32.GetWindowText(hWnd, title, title.Capacity); - owner = title.ToString(); - } - } - } - catch (Exception e) - { - Log.Warn("Non critical error: Couldn't get clipboard owner.", e); - } - - return owner; - } - - /// - /// The SetDataObject will lock/try/catch clipboard operations making it save and not show exceptions. - /// The bool "copy" is used to decided if the information stays on the clipboard after exit. - /// - /// - /// - private static void SetDataObject(IDataObject ido, bool copy) - { - lock (ClipboardLockObject) - { - // Clear first, this seems to solve some issues - try - { - Clipboard.Clear(); - } - catch (Exception clearException) - { - Log.Warn(clearException.Message); - } - - try - { - // For BUG-1935 this was changed from looping ourselfs, or letting MS retry... - Clipboard.SetDataObject(ido, copy, 15, 200); - } - catch (Exception clipboardSetException) - { - string messageText; - string clipboardOwner = GetClipboardOwner(); - if (clipboardOwner != null) - { - messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner); - } - else - { - messageText = Language.GetString("clipboard_error"); - } - - Log.Error(messageText, clipboardSetException); - } - } - } - - /// - /// The GetDataObject will lock/try/catch clipboard operations making it save and not show exceptions. - /// - public static IDataObject GetDataObject() - { - lock (ClipboardLockObject) - { - int retryCount = 2; - while (retryCount >= 0) - { - try - { - return Clipboard.GetDataObject(); - } - catch (Exception ee) - { - if (retryCount == 0) - { - string messageText; - string clipboardOwner = GetClipboardOwner(); - if (clipboardOwner != null) - { - messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner); - } - else - { - messageText = Language.GetString("clipboard_error"); - } - - Log.Error(messageText, ee); - } - else - { - Thread.Sleep(100); - } - } - finally - { - --retryCount; - } - } - } - - return null; - } - - /// - /// Test if the IDataObject contains Text - /// - /// - /// - public static bool ContainsText(IDataObject dataObject) - { - if (dataObject != null) - { - if (dataObject.GetDataPresent(DataFormats.Text) || dataObject.GetDataPresent(DataFormats.UnicodeText)) - { - return true; - } - } - - return false; - } - - /// - /// Wrapper for Clipboard.ContainsImage, specialized for Greenshot, Created for Bug #3432313 - /// - /// boolean if there is an image on the clipboard - public static bool ContainsImage() - { - IDataObject clipboardData = GetDataObject(); - return ContainsImage(clipboardData); - } - - /// - /// Check if the IDataObject has an image - /// - /// - /// true if an image is there - public static bool ContainsImage(IDataObject dataObject) - { - if (dataObject == null) return false; - - if (dataObject.GetDataPresent(DataFormats.Bitmap) - || dataObject.GetDataPresent(DataFormats.Dib) - || dataObject.GetDataPresent(DataFormats.Tiff) - || dataObject.GetDataPresent(DataFormats.EnhancedMetafile) - || dataObject.GetDataPresent(FORMAT_PNG) - || dataObject.GetDataPresent(FORMAT_17) - || dataObject.GetDataPresent(FORMAT_JPG) - || dataObject.GetDataPresent(FORMAT_JFIF) - || dataObject.GetDataPresent(FORMAT_JPEG) - || dataObject.GetDataPresent(FORMAT_GIF)) - { - return true; - } - - var imageFiles = GetImageFilenames(dataObject); - if (imageFiles.Any()) - { - return true; - } - - var fileDescriptor = (MemoryStream) dataObject.GetData("FileGroupDescriptorW"); - var files = FileDescriptorReader.Read(fileDescriptor); - var fileIndex = 0; - foreach (var fileContentFile in files) - { - if ((fileContentFile.FileAttributes & FileAttributes.Directory) != 0) - { - //Do something with directories? - //Note that directories do not have FileContents - //And will throw if we try to read them - continue; - } - - var fileData = FileDescriptorReader.GetFileContents(dataObject, fileIndex); - try - { - //Do something with the fileContent Stream - if (IsValidStream(fileData)) - { - fileData.Position = 0; - using (ImageHelper.FromStream(fileData)) - { - // If we get here, there is an image - return true; - } - } - } - finally - { - fileData?.Dispose(); - } - - fileIndex++; - } - - if (dataObject.GetDataPresent(FORMAT_FILECONTENTS)) - { - try - { - var clipboardContent = dataObject.GetData(FORMAT_FILECONTENTS, true); - var imageStream = clipboardContent as MemoryStream; - if (IsValidStream(imageStream)) - { - using (ImageHelper.FromStream(imageStream)) - { - // If we get here, there is an image - return true; - } - } - } - catch (Exception) - { - // Ignore - } - } - - // Try to get the image from the HTML code - var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); - if (textObject != null) - { - var doc = new HtmlDocument(); - doc.LoadHtml(textObject); - var imgNodes = doc.DocumentNode.SelectNodes("//img"); - if (imgNodes != null) - { - foreach (var imgNode in imgNodes) - { - var srcAttribute = imgNode.Attributes["src"]; - var imageUrl = srcAttribute.Value; - if (!string.IsNullOrEmpty(imageUrl)) - { - return true; - } - } - } - } - - return false; - } - - /// - /// Get the specified IDataObject format as a string - /// - /// IDataObject - /// string - /// Encoding - /// sting - private static string ContentAsString(IDataObject dataObject, string format, Encoding encoding = null) - { - encoding ??= Encoding.Unicode; - var objectAsFormat = dataObject.GetData(format); - return objectAsFormat switch - { - null => null, - string text => text, - MemoryStream ms => encoding.GetString(ms.ToArray()), - _ => null - }; - } - - /// - /// Simple helper to check the stream - /// - /// - /// - private static bool IsValidStream(MemoryStream memoryStream) - { - return memoryStream != null && memoryStream.Length > 0; - } - - /// - /// Wrapper for Clipboard.GetImage, Created for Bug #3432313 - /// - /// Image if there is an image on the clipboard - public static Image GetImage() - { - IDataObject clipboardData = GetDataObject(); - // Return the first image - foreach (Image clipboardImage in GetImages(clipboardData)) - { - return clipboardImage; - } - - return null; - } - - /// - /// Get all images (multiple if filenames are available) from the dataObject - /// Returned images must be disposed by the calling code! - /// - /// - /// IEnumerable of Image - public static IEnumerable GetImages(IDataObject dataObject) - { - // Get single image, this takes the "best" match - Image singleImage = GetImage(dataObject); - if (singleImage != null) - { - Log.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat); - yield return singleImage; - } - else - { - // check if files are supplied - foreach (string imageFile in GetImageFilenames(dataObject)) - { - Image returnImage = null; - try - { - returnImage = ImageHelper.LoadImage(imageFile); - } - catch (Exception streamImageEx) - { - Log.Error("Problem retrieving Image from clipboard.", streamImageEx); - } - - if (returnImage != null) - { - Log.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat); - yield return returnImage; - } - } - } - } - - /// - /// Get an Image from the IDataObject, don't check for FileDrop - /// - /// - /// Image or null - private static Image GetImage(IDataObject dataObject) - { - Image returnImage = null; - if (dataObject != null) - { - IList formats = GetFormats(dataObject); - string[] retrieveFormats; - - // Found a weird bug, where PNG's from Outlook 2010 are clipped - // So I build some special logik to get the best format: - if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) - { - // Outlook ?? - Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front..."); - retrieveFormats = new[] - { - DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, - DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML - }; - } - else - { - retrieveFormats = new[] - { - FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, - FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML - }; - } - - foreach (string currentFormat in retrieveFormats) - { - if (formats != null && formats.Contains(currentFormat)) - { - Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat); - returnImage = GetImageForFormat(currentFormat, dataObject); - } - else - { - Log.DebugFormat("Couldn't find format {0}.", currentFormat); - } - - if (returnImage != null) - { - return returnImage; - } - } - } - - return null; - } - - /// - /// Helper method to try to get an image in the specified format from the dataObject - /// the DIB reader should solve some issues - /// It also supports Format17/DibV5, by using the following information: http://stackoverflow.com/a/14335591 - /// - /// string with the format - /// IDataObject - /// Image or null - private static Image GetImageForFormat(string format, IDataObject dataObject) - { - if (format == FORMAT_HTML) - { - var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); - if (textObject != null) - { - var doc = new HtmlDocument(); - doc.LoadHtml(textObject); - var imgNodes = doc.DocumentNode.SelectNodes("//img"); - if (imgNodes != null) - { - foreach (var imgNode in imgNodes) - { - var srcAttribute = imgNode.Attributes["src"]; - var imageUrl = srcAttribute.Value; - Log.Debug(imageUrl); - var image = NetworkHelper.DownloadImage(imageUrl); - if (image != null) - { - return image; - } - } - } - } - } - - object clipboardObject = GetFromDataObject(dataObject, format); - var imageStream = clipboardObject as MemoryStream; - if (!IsValidStream(imageStream)) - { - // TODO: add "HTML Format" support here... - return clipboardObject as Image; - } - - if (CoreConfig.EnableSpecialDIBClipboardReader) - { - if (format == FORMAT_17 || format == DataFormats.Dib) - { - Log.Info("Found DIB stream, trying to process it."); - try - { - if (imageStream != null) - { - byte[] dibBuffer = new byte[imageStream.Length]; - imageStream.Read(dibBuffer, 0, dibBuffer.Length); - var infoHeader = BinaryStructHelper.FromByteArray(dibBuffer); - if (!infoHeader.IsDibV5) - { - Log.InfoFormat("Using special DIB - /// Get Text from the DataObject - /// - /// string if there is text on the clipboard - public static string GetText(IDataObject dataObject) - { - if (ContainsText(dataObject)) - { - return (string) dataObject.GetData(DataFormats.Text); - } - - return null; - } - - /// - /// Set text to the clipboard - /// - /// - public static void SetClipboardData(string text) - { - IDataObject ido = new DataObject(); - ido.SetData(DataFormats.Text, true, text); - SetDataObject(ido, true); - } - - private static string GetHtmlString(ISurface surface, string filename) - { - string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardString)); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${file}", filename.Replace("\\", "/")); - StringBuilder sb = new StringBuilder(); - sb.Append(utf8EncodedHtmlString); - sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); - sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); - sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - return sb.ToString(); - } - - private static string GetHtmlDataUrlString(ISurface surface, MemoryStream pngStream) - { - string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardBase64String)); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${format}", "png"); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${data}", Convert.ToBase64String(pngStream.GetBuffer(), 0, (int) pngStream.Length)); - StringBuilder sb = new StringBuilder(); - sb.Append(utf8EncodedHtmlString); - sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); - sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); - sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - return sb.ToString(); - } - - private const int BITMAPFILEHEADER_LENGTH = 14; - - /// - /// Set an Image to the clipboard - /// This method will place images to the clipboard depending on the ClipboardFormats setting. - /// e.g. Bitmap which works with pretty much everything and type Dib for e.g. OpenOffice - /// because OpenOffice has a bug http://qa.openoffice.org/issues/show_bug.cgi?id=85661 - /// The Dib (Device Indenpendend Bitmap) in 32bpp actually won't work with Powerpoint 2003! - /// When pasting a Dib in PP 2003 the Bitmap is somehow shifted left! - /// For this problem the user should not use the direct paste (=Dib), but select Bitmap - /// - public static void SetClipboardData(ISurface surface) - { - DataObject dataObject = new DataObject(); - - // This will work for Office and most other applications - //ido.SetData(DataFormats.Bitmap, true, image); - - MemoryStream dibStream = null; - MemoryStream dibV5Stream = null; - MemoryStream pngStream = null; - Image imageToSave = null; - bool disposeImage = false; - try - { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); - // Create the image which is going to be saved so we don't create it multiple times - disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave); - try - { - // Create PNG stream - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.PNG)) - { - pngStream = new MemoryStream(); - // PNG works for e.g. Powerpoint - SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); - ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings); - pngStream.Seek(0, SeekOrigin.Begin); - // Set the PNG stream - dataObject.SetData(FORMAT_PNG, false, pngStream); - } - } - catch (Exception pngEx) - { - Log.Error("Error creating PNG for the Clipboard.", pngEx); - } - - try - { - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIB)) - { - using (MemoryStream tmpBmpStream = new MemoryStream()) - { - // Save image as BMP - SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false); - ImageOutput.SaveToStream(imageToSave, null, tmpBmpStream, bmpOutputSettings); - - dibStream = new MemoryStream(); - // Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14 - dibStream.Write(tmpBmpStream.GetBuffer(), BITMAPFILEHEADER_LENGTH, (int) tmpBmpStream.Length - BITMAPFILEHEADER_LENGTH); - } - - // Set the DIB to the clipboard DataObject - dataObject.SetData(DataFormats.Dib, true, dibStream); - } - } - catch (Exception dibEx) - { - Log.Error("Error creating DIB for the Clipboard.", dibEx); - } - - // CF_DibV5 - try - { - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIBV5)) - { - // Create the stream for the clipboard - dibV5Stream = new MemoryStream(); - - // Create the BITMAPINFOHEADER - BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32) - { - // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? - biCompression = BI_COMPRESSION.BI_BITFIELDS - }; - // Create a byte[] to write - byte[] headerBytes = BinaryStructHelper.ToByteArray(header); - // Write the BITMAPINFOHEADER to the stream - dibV5Stream.Write(headerBytes, 0, headerBytes.Length); - - // As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added - BitfieldColorMask colorMask = new BitfieldColorMask(); - // Make sure the values are set - colorMask.InitValues(); - // Create the byte[] from the struct - byte[] colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask); - Array.Reverse(colorMaskBytes); - // Write to the stream - dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length); - - // Create the raw bytes for the pixels only - byte[] bitmapBytes = BitmapToByteArray((Bitmap) imageToSave); - // Write to the stream - dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length); - - // Set the DIBv5 to the clipboard DataObject - dataObject.SetData(FORMAT_17, true, dibV5Stream); - } - } - catch (Exception dibEx) - { - Log.Error("Error creating DIB for the Clipboard.", dibEx); - } - - // Set the HTML - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTML)) - { - string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null); - string html = GetHtmlString(surface, tmpFile); - dataObject.SetText(html, TextDataFormat.Html); - } - else if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTMLDATAURL)) - { - string html; - using (MemoryStream tmpPngStream = new MemoryStream()) - { - SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false) - { - // Do not allow to reduce the colors, some applications dislike 256 color images - // reported with bug #3594681 - DisableReduceColors = true - }; - // Check if we can use the previously used image - if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) - { - ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings); - } - else - { - ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings); - } - - html = GetHtmlDataUrlString(surface, tmpPngStream); - } - - dataObject.SetText(html, TextDataFormat.Html); - } - } - finally - { - // we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone! - // Check if Bitmap is wanted - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) - { - dataObject.SetImage(imageToSave); - // Place the DataObject to the clipboard - SetDataObject(dataObject, true); - } - else - { - // Place the DataObject to the clipboard - SetDataObject(dataObject, true); - } - - pngStream?.Dispose(); - dibStream?.Dispose(); - dibV5Stream?.Dispose(); - // cleanup if needed - if (disposeImage) - { - imageToSave?.Dispose(); - } - } - } - - /// - /// Helper method so get the bitmap bytes - /// See: http://stackoverflow.com/a/6570155 - /// - /// Bitmap - /// byte[] - private static byte[] BitmapToByteArray(Bitmap bitmap) - { - // Lock the bitmap's bits. - Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); - BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat); - - int absStride = Math.Abs(bmpData.Stride); - int bytes = absStride * bitmap.Height; - long ptr = bmpData.Scan0.ToInt32(); - // Declare an array to hold the bytes of the bitmap. - byte[] rgbValues = new byte[bytes]; - - for (int i = 0; i < bitmap.Height; i++) - { - IntPtr pointer = new IntPtr(ptr + (bmpData.Stride * i)); - Marshal.Copy(pointer, rgbValues, absStride * (bitmap.Height - i - 1), absStride); - } - - // Unlock the bits. - bitmap.UnlockBits(bmpData); - - return rgbValues; - } - - /// - /// Set Object with type Type to the clipboard - /// - /// Type - /// object - public static void SetClipboardData(Type type, object obj) - { - DataFormats.Format format = DataFormats.GetFormat(type.FullName); - - //now copy to clipboard - IDataObject dataObj = new DataObject(); - dataObj.SetData(format.Name, false, obj); - // Use false to make the object disappear when the application stops. - SetDataObject(dataObj, true); - } - - /// - /// Retrieve a list of all formats currently in the IDataObject - /// - /// List of string with the current formats - public static List GetFormats(IDataObject dataObj) - { - string[] formats = null; - - if (dataObj != null) - { - formats = dataObj.GetFormats(); - } - - if (formats != null) - { - Log.DebugFormat("Got clipboard formats: {0}", string.Join(",", formats)); - return new List(formats); - } - - return new List(); - } - - /// - /// Check if there is currently something on the clipboard which has the supplied format - /// - /// IDataObject - /// string with format - /// true if one the format is found - public static bool ContainsFormat(IDataObject dataObject, string format) - { - return ContainsFormat(dataObject, new[] - { - format - }); - } - - /// - /// Check if there is currently something on the clipboard which has one of the supplied formats - /// - /// string[] with formats - /// true if one of the formats was found - public static bool ContainsFormat(string[] formats) - { - return ContainsFormat(GetDataObject(), formats); - } - - /// - /// Check if there is currently something on the clipboard which has one of the supplied formats - /// - /// IDataObject - /// string[] with formats - /// true if one of the formats was found - public static bool ContainsFormat(IDataObject dataObject, string[] formats) - { - bool formatFound = false; - List currentFormats = GetFormats(dataObject); - if (currentFormats == null || currentFormats.Count == 0 || formats == null || formats.Length == 0) - { - return false; - } - - foreach (string format in formats) - { - if (currentFormats.Contains(format)) - { - formatFound = true; - break; - } - } - - return formatFound; - } - - /// - /// Get Object for format from IDataObject - /// - /// IDataObject - /// Type to get - /// object from IDataObject - public static object GetFromDataObject(IDataObject dataObj, Type type) - { - if (type != null) - { - return GetFromDataObject(dataObj, type.FullName); - } - - return null; - } - - /// - /// Get ImageFilenames from the IDataObject - /// - /// IDataObject - /// - public static IEnumerable GetImageFilenames(IDataObject dataObject) - { - string[] dropFileNames = (string[]) dataObject.GetData(DataFormats.FileDrop); - if (dropFileNames != null && dropFileNames.Length > 0) - { - return dropFileNames - .Where(filename => !string.IsNullOrEmpty(filename)) - .Where(Path.HasExtension) - .Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1))); - } - - return Enumerable.Empty(); - } - - /// - /// Get Object for format from IDataObject - /// - /// IDataObject - /// format to get - /// object from IDataObject - public static object GetFromDataObject(IDataObject dataObj, string format) - { - if (dataObj != null) - { - try - { - return dataObj.GetData(format); - } - catch (Exception e) - { - Log.Error("Error in GetClipboardData.", e); - } - } - - return null; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Base.UnmanagedHelpers; +using log4net; +using HtmlDocument = HtmlAgilityPack.HtmlDocument; + +namespace Greenshot.Base.Core +{ + /// + /// Description of ClipboardHelper. + /// + public static class ClipboardHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ClipboardHelper)); + private static readonly object ClipboardLockObject = new object(); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static readonly string FORMAT_FILECONTENTS = "FileContents"; + private static readonly string FORMAT_HTML = "text/html"; + private static readonly string FORMAT_PNG = "PNG"; + private static readonly string FORMAT_PNG_OFFICEART = "PNG+Office Art"; + private static readonly string FORMAT_17 = "Format17"; + private static readonly string FORMAT_JPG = "JPG"; + private static readonly string FORMAT_JPEG = "JPEG"; + private static readonly string FORMAT_JFIF = "JFIF"; + private static readonly string FORMAT_JFIF_OFFICEART = "JFIF+Office Art"; + private static readonly string FORMAT_GIF = "GIF"; + + private static readonly string FORMAT_BITMAP = "System.Drawing.Bitmap"; + //private static readonly string FORMAT_HTML = "HTML Format"; + + // Template for the HTML Text on the clipboard + // see: http://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx + // or: http://msdn.microsoft.com/en-us/library/Aa767917.aspx + private const string HtmlClipboardString = @"Version:0.9 +StartHTML:<<<<<<<1 +EndHTML:<<<<<<<2 +StartFragment:<<<<<<<3 +EndFragment:<<<<<<<4 +StartSelection:<<<<<<<3 +EndSelection:<<<<<<<4 + + + +Greenshot capture + + + + + + +"; + + private const string HtmlClipboardBase64String = @"Version:0.9 +StartHTML:<<<<<<<1 +EndHTML:<<<<<<<2 +StartFragment:<<<<<<<3 +EndFragment:<<<<<<<4 +StartSelection:<<<<<<<3 +EndSelection:<<<<<<<4 + + + +Greenshot capture + + + + + + +"; + + /// + /// Get the current "ClipboardOwner" but only if it isn't us! + /// + /// current clipboard owner + private static string GetClipboardOwner() + { + string owner = null; + try + { + IntPtr hWnd = User32.GetClipboardOwner(); + if (hWnd != IntPtr.Zero) + { + try + { + User32.GetWindowThreadProcessId(hWnd, out var pid); + using Process me = Process.GetCurrentProcess(); + using Process ownerProcess = Process.GetProcessById(pid); + // Exclude myself + if (me.Id != ownerProcess.Id) + { + // Get Process Name + owner = ownerProcess.ProcessName; + // Try to get the starting Process Filename, this might fail. + try + { + owner = ownerProcess.Modules[0].FileName; + } + catch (Exception) + { + // Ignore + } + } + } + catch (Exception e) + { + Log.Warn("Non critical error: Couldn't get clipboard process, trying to use the title.", e); + var title = new StringBuilder(260, 260); + User32.GetWindowText(hWnd, title, title.Capacity); + owner = title.ToString(); + } + } + } + catch (Exception e) + { + Log.Warn("Non critical error: Couldn't get clipboard owner.", e); + } + + return owner; + } + + /// + /// The SetDataObject will lock/try/catch clipboard operations making it save and not show exceptions. + /// The bool "copy" is used to decided if the information stays on the clipboard after exit. + /// + /// + /// + private static void SetDataObject(IDataObject ido, bool copy) + { + lock (ClipboardLockObject) + { + // Clear first, this seems to solve some issues + try + { + Clipboard.Clear(); + } + catch (Exception clearException) + { + Log.Warn(clearException.Message); + } + + try + { + // For BUG-1935 this was changed from looping ourselfs, or letting MS retry... + Clipboard.SetDataObject(ido, copy, 15, 200); + } + catch (Exception clipboardSetException) + { + string messageText; + string clipboardOwner = GetClipboardOwner(); + if (clipboardOwner != null) + { + messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner); + } + else + { + messageText = Language.GetString("clipboard_error"); + } + + Log.Error(messageText, clipboardSetException); + } + } + } + + /// + /// The GetDataObject will lock/try/catch clipboard operations making it save and not show exceptions. + /// + public static IDataObject GetDataObject() + { + lock (ClipboardLockObject) + { + int retryCount = 2; + while (retryCount >= 0) + { + try + { + return Clipboard.GetDataObject(); + } + catch (Exception ee) + { + if (retryCount == 0) + { + string messageText; + string clipboardOwner = GetClipboardOwner(); + if (clipboardOwner != null) + { + messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner); + } + else + { + messageText = Language.GetString("clipboard_error"); + } + + Log.Error(messageText, ee); + } + else + { + Thread.Sleep(100); + } + } + finally + { + --retryCount; + } + } + } + + return null; + } + + /// + /// Test if the IDataObject contains Text + /// + /// + /// + public static bool ContainsText(IDataObject dataObject) + { + if (dataObject != null) + { + if (dataObject.GetDataPresent(DataFormats.Text) || dataObject.GetDataPresent(DataFormats.UnicodeText)) + { + return true; + } + } + + return false; + } + + /// + /// Wrapper for Clipboard.ContainsImage, specialized for Greenshot, Created for Bug #3432313 + /// + /// boolean if there is an image on the clipboard + public static bool ContainsImage() + { + IDataObject clipboardData = GetDataObject(); + return ContainsImage(clipboardData); + } + + /// + /// Check if the IDataObject has an image + /// + /// + /// true if an image is there + public static bool ContainsImage(IDataObject dataObject) + { + if (dataObject == null) return false; + + if (dataObject.GetDataPresent(DataFormats.Bitmap) + || dataObject.GetDataPresent(DataFormats.Dib) + || dataObject.GetDataPresent(DataFormats.Tiff) + || dataObject.GetDataPresent(DataFormats.EnhancedMetafile) + || dataObject.GetDataPresent(FORMAT_PNG) + || dataObject.GetDataPresent(FORMAT_17) + || dataObject.GetDataPresent(FORMAT_JPG) + || dataObject.GetDataPresent(FORMAT_JFIF) + || dataObject.GetDataPresent(FORMAT_JPEG) + || dataObject.GetDataPresent(FORMAT_GIF)) + { + return true; + } + + var imageFiles = GetImageFilenames(dataObject); + if (imageFiles.Any()) + { + return true; + } + + var fileDescriptor = (MemoryStream) dataObject.GetData("FileGroupDescriptorW"); + var files = FileDescriptorReader.Read(fileDescriptor); + var fileIndex = 0; + foreach (var fileContentFile in files) + { + if ((fileContentFile.FileAttributes & FileAttributes.Directory) != 0) + { + //Do something with directories? + //Note that directories do not have FileContents + //And will throw if we try to read them + continue; + } + + var fileData = FileDescriptorReader.GetFileContents(dataObject, fileIndex); + try + { + //Do something with the fileContent Stream + if (IsValidStream(fileData)) + { + fileData.Position = 0; + using (ImageHelper.FromStream(fileData)) + { + // If we get here, there is an image + return true; + } + } + } + finally + { + fileData?.Dispose(); + } + + fileIndex++; + } + + if (dataObject.GetDataPresent(FORMAT_FILECONTENTS)) + { + try + { + var clipboardContent = dataObject.GetData(FORMAT_FILECONTENTS, true); + var imageStream = clipboardContent as MemoryStream; + if (IsValidStream(imageStream)) + { + using (ImageHelper.FromStream(imageStream)) + { + // If we get here, there is an image + return true; + } + } + } + catch (Exception) + { + // Ignore + } + } + + // Try to get the image from the HTML code + var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); + if (textObject != null) + { + var doc = new HtmlDocument(); + doc.LoadHtml(textObject); + var imgNodes = doc.DocumentNode.SelectNodes("//img"); + if (imgNodes != null) + { + foreach (var imgNode in imgNodes) + { + var srcAttribute = imgNode.Attributes["src"]; + var imageUrl = srcAttribute.Value; + if (!string.IsNullOrEmpty(imageUrl)) + { + return true; + } + } + } + } + + return false; + } + + /// + /// Get the specified IDataObject format as a string + /// + /// IDataObject + /// string + /// Encoding + /// sting + private static string ContentAsString(IDataObject dataObject, string format, Encoding encoding = null) + { + encoding ??= Encoding.Unicode; + var objectAsFormat = dataObject.GetData(format); + return objectAsFormat switch + { + null => null, + string text => text, + MemoryStream ms => encoding.GetString(ms.ToArray()), + _ => null + }; + } + + /// + /// Simple helper to check the stream + /// + /// + /// + private static bool IsValidStream(MemoryStream memoryStream) + { + return memoryStream != null && memoryStream.Length > 0; + } + + /// + /// Wrapper for Clipboard.GetImage, Created for Bug #3432313 + /// + /// Image if there is an image on the clipboard + public static Image GetImage() + { + IDataObject clipboardData = GetDataObject(); + // Return the first image + foreach (Image clipboardImage in GetImages(clipboardData)) + { + return clipboardImage; + } + + return null; + } + + /// + /// Get all images (multiple if filenames are available) from the dataObject + /// Returned images must be disposed by the calling code! + /// + /// + /// IEnumerable of Image + public static IEnumerable GetImages(IDataObject dataObject) + { + // Get single image, this takes the "best" match + Image singleImage = GetImage(dataObject); + if (singleImage != null) + { + Log.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat); + yield return singleImage; + } + else + { + // check if files are supplied + foreach (string imageFile in GetImageFilenames(dataObject)) + { + Image returnImage = null; + try + { + returnImage = ImageHelper.LoadImage(imageFile); + } + catch (Exception streamImageEx) + { + Log.Error("Problem retrieving Image from clipboard.", streamImageEx); + } + + if (returnImage != null) + { + Log.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat); + yield return returnImage; + } + } + } + } + + /// + /// Get an Image from the IDataObject, don't check for FileDrop + /// + /// + /// Image or null + private static Image GetImage(IDataObject dataObject) + { + Image returnImage = null; + if (dataObject != null) + { + IList formats = GetFormats(dataObject); + string[] retrieveFormats; + + // Found a weird bug, where PNG's from Outlook 2010 are clipped + // So I build some special logik to get the best format: + if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) + { + // Outlook ?? + Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front..."); + retrieveFormats = new[] + { + DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, + DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML + }; + } + else + { + retrieveFormats = new[] + { + FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, + FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML + }; + } + + foreach (string currentFormat in retrieveFormats) + { + if (formats != null && formats.Contains(currentFormat)) + { + Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat); + returnImage = GetImageForFormat(currentFormat, dataObject); + } + else + { + Log.DebugFormat("Couldn't find format {0}.", currentFormat); + } + + if (returnImage != null) + { + return returnImage; + } + } + } + + return null; + } + + /// + /// Helper method to try to get an image in the specified format from the dataObject + /// the DIB reader should solve some issues + /// It also supports Format17/DibV5, by using the following information: http://stackoverflow.com/a/14335591 + /// + /// string with the format + /// IDataObject + /// Image or null + private static Image GetImageForFormat(string format, IDataObject dataObject) + { + if (format == FORMAT_HTML) + { + var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); + if (textObject != null) + { + var doc = new HtmlDocument(); + doc.LoadHtml(textObject); + var imgNodes = doc.DocumentNode.SelectNodes("//img"); + if (imgNodes != null) + { + foreach (var imgNode in imgNodes) + { + var srcAttribute = imgNode.Attributes["src"]; + var imageUrl = srcAttribute.Value; + Log.Debug(imageUrl); + var image = NetworkHelper.DownloadImage(imageUrl); + if (image != null) + { + return image; + } + } + } + } + } + + object clipboardObject = GetFromDataObject(dataObject, format); + var imageStream = clipboardObject as MemoryStream; + if (!IsValidStream(imageStream)) + { + // TODO: add "HTML Format" support here... + return clipboardObject as Image; + } + + if (CoreConfig.EnableSpecialDIBClipboardReader) + { + if (format == FORMAT_17 || format == DataFormats.Dib) + { + Log.Info("Found DIB stream, trying to process it."); + try + { + if (imageStream != null) + { + byte[] dibBuffer = new byte[imageStream.Length]; + imageStream.Read(dibBuffer, 0, dibBuffer.Length); + var infoHeader = BinaryStructHelper.FromByteArray(dibBuffer); + if (!infoHeader.IsDibV5) + { + Log.InfoFormat("Using special DIB + /// Get Text from the DataObject + /// + /// string if there is text on the clipboard + public static string GetText(IDataObject dataObject) + { + if (ContainsText(dataObject)) + { + return (string) dataObject.GetData(DataFormats.Text); + } + + return null; + } + + /// + /// Set text to the clipboard + /// + /// + public static void SetClipboardData(string text) + { + IDataObject ido = new DataObject(); + ido.SetData(DataFormats.Text, true, text); + SetDataObject(ido, true); + } + + private static string GetHtmlString(ISurface surface, string filename) + { + string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardString)); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${file}", filename.Replace("\\", "/")); + StringBuilder sb = new StringBuilder(); + sb.Append(utf8EncodedHtmlString); + sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + return sb.ToString(); + } + + private static string GetHtmlDataUrlString(ISurface surface, MemoryStream pngStream) + { + string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardBase64String)); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${format}", "png"); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${data}", Convert.ToBase64String(pngStream.GetBuffer(), 0, (int) pngStream.Length)); + StringBuilder sb = new StringBuilder(); + sb.Append(utf8EncodedHtmlString); + sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + return sb.ToString(); + } + + private const int BITMAPFILEHEADER_LENGTH = 14; + + /// + /// Set an Image to the clipboard + /// This method will place images to the clipboard depending on the ClipboardFormats setting. + /// e.g. Bitmap which works with pretty much everything and type Dib for e.g. OpenOffice + /// because OpenOffice has a bug http://qa.openoffice.org/issues/show_bug.cgi?id=85661 + /// The Dib (Device Indenpendend Bitmap) in 32bpp actually won't work with Powerpoint 2003! + /// When pasting a Dib in PP 2003 the Bitmap is somehow shifted left! + /// For this problem the user should not use the direct paste (=Dib), but select Bitmap + /// + public static void SetClipboardData(ISurface surface) + { + DataObject dataObject = new DataObject(); + + // This will work for Office and most other applications + //ido.SetData(DataFormats.Bitmap, true, image); + + MemoryStream dibStream = null; + MemoryStream dibV5Stream = null; + MemoryStream pngStream = null; + Image imageToSave = null; + bool disposeImage = false; + try + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); + // Create the image which is going to be saved so we don't create it multiple times + disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave); + try + { + // Create PNG stream + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.PNG)) + { + pngStream = new MemoryStream(); + // PNG works for e.g. Powerpoint + SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); + ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings); + pngStream.Seek(0, SeekOrigin.Begin); + // Set the PNG stream + dataObject.SetData(FORMAT_PNG, false, pngStream); + } + } + catch (Exception pngEx) + { + Log.Error("Error creating PNG for the Clipboard.", pngEx); + } + + try + { + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIB)) + { + using (MemoryStream tmpBmpStream = new MemoryStream()) + { + // Save image as BMP + SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false); + ImageOutput.SaveToStream(imageToSave, null, tmpBmpStream, bmpOutputSettings); + + dibStream = new MemoryStream(); + // Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14 + dibStream.Write(tmpBmpStream.GetBuffer(), BITMAPFILEHEADER_LENGTH, (int) tmpBmpStream.Length - BITMAPFILEHEADER_LENGTH); + } + + // Set the DIB to the clipboard DataObject + dataObject.SetData(DataFormats.Dib, true, dibStream); + } + } + catch (Exception dibEx) + { + Log.Error("Error creating DIB for the Clipboard.", dibEx); + } + + // CF_DibV5 + try + { + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIBV5)) + { + // Create the stream for the clipboard + dibV5Stream = new MemoryStream(); + + // Create the BITMAPINFOHEADER + BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32) + { + // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? + biCompression = BI_COMPRESSION.BI_BITFIELDS + }; + // Create a byte[] to write + byte[] headerBytes = BinaryStructHelper.ToByteArray(header); + // Write the BITMAPINFOHEADER to the stream + dibV5Stream.Write(headerBytes, 0, headerBytes.Length); + + // As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added + BitfieldColorMask colorMask = new BitfieldColorMask(); + // Make sure the values are set + colorMask.InitValues(); + // Create the byte[] from the struct + byte[] colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask); + Array.Reverse(colorMaskBytes); + // Write to the stream + dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length); + + // Create the raw bytes for the pixels only + byte[] bitmapBytes = BitmapToByteArray((Bitmap) imageToSave); + // Write to the stream + dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length); + + // Set the DIBv5 to the clipboard DataObject + dataObject.SetData(FORMAT_17, true, dibV5Stream); + } + } + catch (Exception dibEx) + { + Log.Error("Error creating DIB for the Clipboard.", dibEx); + } + + // Set the HTML + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTML)) + { + string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null); + string html = GetHtmlString(surface, tmpFile); + dataObject.SetText(html, TextDataFormat.Html); + } + else if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTMLDATAURL)) + { + string html; + using (MemoryStream tmpPngStream = new MemoryStream()) + { + SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false) + { + // Do not allow to reduce the colors, some applications dislike 256 color images + // reported with bug #3594681 + DisableReduceColors = true + }; + // Check if we can use the previously used image + if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) + { + ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings); + } + else + { + ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings); + } + + html = GetHtmlDataUrlString(surface, tmpPngStream); + } + + dataObject.SetText(html, TextDataFormat.Html); + } + } + finally + { + // we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone! + // Check if Bitmap is wanted + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) + { + dataObject.SetImage(imageToSave); + // Place the DataObject to the clipboard + SetDataObject(dataObject, true); + } + else + { + // Place the DataObject to the clipboard + SetDataObject(dataObject, true); + } + + pngStream?.Dispose(); + dibStream?.Dispose(); + dibV5Stream?.Dispose(); + // cleanup if needed + if (disposeImage) + { + imageToSave?.Dispose(); + } + } + } + + /// + /// Helper method so get the bitmap bytes + /// See: http://stackoverflow.com/a/6570155 + /// + /// Bitmap + /// byte[] + private static byte[] BitmapToByteArray(Bitmap bitmap) + { + // Lock the bitmap's bits. + Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); + BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat); + + int absStride = Math.Abs(bmpData.Stride); + int bytes = absStride * bitmap.Height; + long ptr = bmpData.Scan0.ToInt32(); + // Declare an array to hold the bytes of the bitmap. + byte[] rgbValues = new byte[bytes]; + + for (int i = 0; i < bitmap.Height; i++) + { + IntPtr pointer = new IntPtr(ptr + (bmpData.Stride * i)); + Marshal.Copy(pointer, rgbValues, absStride * (bitmap.Height - i - 1), absStride); + } + + // Unlock the bits. + bitmap.UnlockBits(bmpData); + + return rgbValues; + } + + /// + /// Set Object with type Type to the clipboard + /// + /// Type + /// object + public static void SetClipboardData(Type type, object obj) + { + DataFormats.Format format = DataFormats.GetFormat(type.FullName); + + //now copy to clipboard + IDataObject dataObj = new DataObject(); + dataObj.SetData(format.Name, false, obj); + // Use false to make the object disappear when the application stops. + SetDataObject(dataObj, true); + } + + /// + /// Retrieve a list of all formats currently in the IDataObject + /// + /// List of string with the current formats + public static List GetFormats(IDataObject dataObj) + { + string[] formats = null; + + if (dataObj != null) + { + formats = dataObj.GetFormats(); + } + + if (formats != null) + { + Log.DebugFormat("Got clipboard formats: {0}", string.Join(",", formats)); + return new List(formats); + } + + return new List(); + } + + /// + /// Check if there is currently something on the clipboard which has the supplied format + /// + /// IDataObject + /// string with format + /// true if one the format is found + public static bool ContainsFormat(IDataObject dataObject, string format) + { + return ContainsFormat(dataObject, new[] + { + format + }); + } + + /// + /// Check if there is currently something on the clipboard which has one of the supplied formats + /// + /// string[] with formats + /// true if one of the formats was found + public static bool ContainsFormat(string[] formats) + { + return ContainsFormat(GetDataObject(), formats); + } + + /// + /// Check if there is currently something on the clipboard which has one of the supplied formats + /// + /// IDataObject + /// string[] with formats + /// true if one of the formats was found + public static bool ContainsFormat(IDataObject dataObject, string[] formats) + { + bool formatFound = false; + List currentFormats = GetFormats(dataObject); + if (currentFormats == null || currentFormats.Count == 0 || formats == null || formats.Length == 0) + { + return false; + } + + foreach (string format in formats) + { + if (currentFormats.Contains(format)) + { + formatFound = true; + break; + } + } + + return formatFound; + } + + /// + /// Get Object for format from IDataObject + /// + /// IDataObject + /// Type to get + /// object from IDataObject + public static object GetFromDataObject(IDataObject dataObj, Type type) + { + if (type != null) + { + return GetFromDataObject(dataObj, type.FullName); + } + + return null; + } + + /// + /// Get ImageFilenames from the IDataObject + /// + /// IDataObject + /// + public static IEnumerable GetImageFilenames(IDataObject dataObject) + { + string[] dropFileNames = (string[]) dataObject.GetData(DataFormats.FileDrop); + if (dropFileNames != null && dropFileNames.Length > 0) + { + return dropFileNames + .Where(filename => !string.IsNullOrEmpty(filename)) + .Where(Path.HasExtension) + .Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1))); + } + + return Enumerable.Empty(); + } + + /// + /// Get Object for format from IDataObject + /// + /// IDataObject + /// format to get + /// object from IDataObject + public static object GetFromDataObject(IDataObject dataObj, string format) + { + if (dataObj != null) + { + try + { + return dataObj.GetData(format); + } + catch (Exception e) + { + Log.Error("Error in GetClipboardData.", e); + } + } + + return null; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/CoreConfiguration.cs b/src/Greenshot.Base/Core/CoreConfiguration.cs similarity index 97% rename from src/GreenshotPlugin/Core/CoreConfiguration.cs rename to src/Greenshot.Base/Core/CoreConfiguration.cs index d099770a7..638613011 100644 --- a/src/GreenshotPlugin/Core/CoreConfiguration.cs +++ b/src/Greenshot.Base/Core/CoreConfiguration.cs @@ -1,737 +1,737 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.IO; -using System.Reflection; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; - -namespace GreenshotPlugin.Core -{ - public enum ClipboardFormat - { - PNG, - DIB, - HTML, - HTMLDATAURL, - BITMAP, - DIBV5 - } - - public enum OutputFormat - { - bmp, - gif, - jpg, - png, - tiff, - greenshot, - ico - } - - public enum WindowCaptureMode - { - Screen, - GDI, - Aero, - AeroTransparent, - Auto - } - - public enum BuildStates - { - UNSTABLE, - RELEASE_CANDIDATE, - RELEASE - } - - public enum ClickActions - { - DO_NOTHING, - OPEN_LAST_IN_EXPLORER, - OPEN_LAST_IN_EDITOR, - OPEN_SETTINGS, - SHOW_CONTEXT_MENU - } - - /// - /// Description of CoreConfiguration. - /// - [IniSection("Core", Description = "Greenshot core configuration")] - public class CoreConfiguration : IniSection, INotifyPropertyChanged - { - public event PropertyChangedEventHandler PropertyChanged; - - [IniProperty("Language", Description = "The language in IETF format (e.g. en-US)")] - public string Language { get; set; } - - [IniProperty("RegionHotkey", Description = "Hotkey for starting the region capture", DefaultValue = "PrintScreen")] - public string RegionHotkey { get; set; } - - [IniProperty("WindowHotkey", Description = "Hotkey for starting the window capture", DefaultValue = "Alt + PrintScreen")] - public string WindowHotkey { get; set; } - - [IniProperty("FullscreenHotkey", Description = "Hotkey for starting the fullscreen capture", DefaultValue = "Ctrl + PrintScreen")] - public string FullscreenHotkey { get; set; } - - [IniProperty("LastregionHotkey", Description = "Hotkey for starting the last region capture", DefaultValue = "Shift + PrintScreen")] - public string LastregionHotkey { get; set; } - - [IniProperty("IEHotkey", Description = "Hotkey for starting the IE capture", DefaultValue = "Shift + Ctrl + PrintScreen")] - public string IEHotkey { get; set; } - - [IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor")] - public string ClipboardHotkey { get; set; } - - [IniProperty("IsFirstLaunch", Description = "Is this the first time launch?", DefaultValue = "true")] - public bool IsFirstLaunch { get; set; } - - [IniProperty("Destinations", Separator = ",", - Description = "Which destinations? Possible options (more might be added by plugins) are: Editor, FileDefault, FileWithDialog, Clipboard, Printer, EMail, Picker", - DefaultValue = "Picker")] - public List OutputDestinations { get; set; } = new List(); - - [IniProperty("ClipboardFormats", Separator = ",", Description = "Specify which formats we copy on the clipboard? Options are: PNG, HTML, HTMLDATAURL and DIB", - DefaultValue = "PNG,DIB")] - public List ClipboardFormats { get; set; } = new List(); - - [IniProperty("CaptureMousepointer", Description = "Should the mouse be captured?", DefaultValue = "true")] - public bool CaptureMousepointer { get; set; } - - [IniProperty("CaptureWindowsInteractive", Description = "Use interactive window selection to capture? (false=Capture active window)", DefaultValue = "false")] - public bool CaptureWindowsInteractive { get; set; } - - [IniProperty("CaptureDelay", Description = "Capture delay in millseconds.", DefaultValue = "100")] - public int CaptureDelay { get; set; } - - [IniProperty("ScreenCaptureMode", Description = "The capture mode used to capture a screen. (Auto, FullScreen, Fixed)", DefaultValue = "Auto")] - public ScreenCaptureMode ScreenCaptureMode { get; set; } - - [IniProperty("ScreenToCapture", Description = "The screen number to capture when using ScreenCaptureMode Fixed.", DefaultValue = "1")] - public int ScreenToCapture { get; set; } - - [IniProperty("WindowCaptureMode", Description = "The capture mode used to capture a Window (Screen, GDI, Aero, AeroTransparent, Auto).", DefaultValue = "Auto")] - public WindowCaptureMode WindowCaptureMode { get; set; } - - [IniProperty("WindowCaptureAllChildLocations", - Description = "Enable/disable capture all children, very slow but will make it possible to use this information in the editor.", DefaultValue = "False")] - public bool WindowCaptureAllChildLocations { get; set; } - - [IniProperty("DWMBackgroundColor", Description = "The background color for a DWM window capture.")] - public Color DWMBackgroundColor { get; set; } - - [IniProperty("PlayCameraSound", LanguageKey = "settings_playsound", Description = "Play a camera sound after taking a capture.", DefaultValue = "false")] - public bool PlayCameraSound { get; set; } = false; - - [IniProperty("ShowTrayNotification", LanguageKey = "settings_shownotify", Description = "Show a notification from the systray when a capture is taken.", - DefaultValue = "true")] - public bool ShowTrayNotification { get; set; } = true; - - [IniProperty("OutputFilePath", Description = "Output file path.")] - public string OutputFilePath { get; set; } - - [IniProperty("OutputFileAllowOverwrite", - Description = "If the target file already exists True will make Greenshot always overwrite and False will display a 'Save-As' dialog.", DefaultValue = "true")] - public bool OutputFileAllowOverwrite { get; set; } - - [IniProperty("OutputFileFilenamePattern", Description = "Filename pattern for screenshot.", DefaultValue = "${capturetime:d\"yyyy-MM-dd HH_mm_ss\"}-${title}")] - public string OutputFileFilenamePattern { get; set; } - - [IniProperty("OutputFileFormat", Description = "Default file type for writing screenshots. (bmp, gif, jpg, png, tiff)", DefaultValue = "png")] - public OutputFormat OutputFileFormat { get; set; } = OutputFormat.png; - - [IniProperty("OutputFileReduceColors", Description = "If set to true, than the colors of the output file are reduced to 256 (8-bit) colors", DefaultValue = "false")] - public bool OutputFileReduceColors { get; set; } - - [IniProperty("OutputFileAutoReduceColors", - Description = "If set to true the amount of colors is counted and if smaller than 256 the color reduction is automatically used.", DefaultValue = "false")] - public bool OutputFileAutoReduceColors { get; set; } - - [IniProperty("OutputFileReduceColorsTo", Description = "Amount of colors to reduce to, when reducing", DefaultValue = "256")] - public int OutputFileReduceColorsTo { get; set; } - - [IniProperty("OutputFileCopyPathToClipboard", Description = "When saving a screenshot, copy the path to the clipboard?", DefaultValue = "true")] - public bool OutputFileCopyPathToClipboard { get; set; } - - [IniProperty("OutputFileAsFullpath", Description = "SaveAs Full path?")] - public string OutputFileAsFullpath { get; set; } - - [IniProperty("OutputFileJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] - public int OutputFileJpegQuality { get; set; } - - [IniProperty("OutputFilePromptQuality", Description = "Ask for the quality before saving?", DefaultValue = "false")] - public bool OutputFilePromptQuality { get; set; } - - [IniProperty("OutputFileIncrementingNumber", Description = "The number for the ${NUM} in the filename pattern, is increased automatically after each save.", - DefaultValue = "1")] - public uint OutputFileIncrementingNumber { get; set; } - - [IniProperty("OutputPrintPromptOptions", LanguageKey = "settings_alwaysshowprintoptionsdialog", Description = "Ask for print options when printing?", - DefaultValue = "true")] - public bool OutputPrintPromptOptions { get; set; } - - [IniProperty("OutputPrintAllowRotate", LanguageKey = "printoptions_allowrotate", Description = "Allow rotating the picture for fitting on paper?", DefaultValue = "false")] - public bool OutputPrintAllowRotate { get; set; } - - [IniProperty("OutputPrintAllowEnlarge", LanguageKey = "printoptions_allowenlarge", Description = "Allow growing the picture for fitting on paper?", DefaultValue = "false")] - public bool OutputPrintAllowEnlarge { get; set; } - - [IniProperty("OutputPrintAllowShrink", LanguageKey = "printoptions_allowshrink", Description = "Allow shrinking the picture for fitting on paper?", DefaultValue = "true")] - public bool OutputPrintAllowShrink { get; set; } - - [IniProperty("OutputPrintCenter", LanguageKey = "printoptions_allowcenter", Description = "Center image when printing?", DefaultValue = "true")] - public bool OutputPrintCenter { get; set; } - - [IniProperty("OutputPrintInverted", LanguageKey = "printoptions_inverted", Description = "Print image inverted (use e.g. for console captures)", DefaultValue = "false")] - public bool OutputPrintInverted { get; set; } - - [IniProperty("OutputPrintGrayscale", LanguageKey = "printoptions_printgrayscale", Description = "Force grayscale printing", DefaultValue = "false")] - public bool OutputPrintGrayscale { get; set; } - - [IniProperty("OutputPrintMonochrome", LanguageKey = "printoptions_printmonochrome", Description = "Force monorchrome printing", DefaultValue = "false")] - public bool OutputPrintMonochrome { get; set; } - - [IniProperty("OutputPrintMonochromeThreshold", Description = "Threshold for monochrome filter (0 - 255), lower value means less black", DefaultValue = "127")] - public byte OutputPrintMonochromeThreshold { get; set; } - - [IniProperty("OutputPrintFooter", LanguageKey = "printoptions_timestamp", Description = "Print footer on print?", DefaultValue = "true")] - public bool OutputPrintFooter { get; set; } - - [IniProperty("OutputPrintFooterPattern", Description = "Footer pattern", DefaultValue = "${capturetime:d\"D\"} ${capturetime:d\"T\"} - ${title}")] - public string OutputPrintFooterPattern { get; set; } - - [IniProperty("NotificationSound", Description = "The wav-file to play when a capture is taken, loaded only once at the Greenshot startup", DefaultValue = "default")] - public string NotificationSound { get; set; } - - [IniProperty("UseProxy", Description = "Use your global proxy?", DefaultValue = "True")] - public bool UseProxy { get; set; } - - [IniProperty("IECapture", Description = "Enable/disable IE capture", DefaultValue = "True")] - public bool IECapture { get; set; } - - [IniProperty("IEFieldCapture", Description = "Enable/disable IE field capture, very slow but will make it possible to annotate the fields of a capture in the editor.", - DefaultValue = "False")] - public bool IEFieldCapture { get; set; } - - [IniProperty("WindowClassesToCheckForIE", Description = "Comma separated list of Window-Classes which need to be checked for a IE instance!", - DefaultValue = "AfxFrameOrView70,IMWindowClass")] - public List WindowClassesToCheckForIE { get; set; } - - [IniProperty("AutoCropDifference", - Description = - "Sets how to compare the colors for the autocrop detection, the higher the more is 'selected'. Possible values are from 0 to 255, where everything above ~150 doesn't make much sense!", - DefaultValue = "10")] - public int AutoCropDifference { get; set; } - - [IniProperty("IncludePlugins", - Description = "Comma separated list of Plugins which are allowed. If something in the list, than every plugin not in the list will not be loaded!")] - public List IncludePlugins { get; set; } - - [IniProperty("ExcludePlugins", Description = "Comma separated list of Plugins which are NOT allowed.")] - public List ExcludePlugins { get; set; } - - [IniProperty("ExcludeDestinations", Description = "Comma separated list of destinations which should be disabled.")] - public List ExcludeDestinations { get; set; } - - [IniProperty("UpdateCheckInterval", Description = "How many days between every update check? (0=no checks)", DefaultValue = "14")] - public int UpdateCheckInterval { get; set; } - - [IniProperty("LastUpdateCheck", Description = "Last update check")] - public DateTime LastUpdateCheck { get; set; } - - [IniProperty("DisableSettings", Description = "Enable/disable the access to the settings, can only be changed manually in this .ini", DefaultValue = "False")] - public bool DisableSettings { get; set; } - - [IniProperty("DisableQuickSettings", Description = "Enable/disable the access to the quick settings, can only be changed manually in this .ini", DefaultValue = "False")] - public bool DisableQuickSettings { get; set; } - - [IniProperty("DisableTrayicon", Description = "Disable the trayicon, can only be changed manually in this .ini", DefaultValue = "False")] - public bool HideTrayicon { get; set; } - - [IniProperty("HideExpertSettings", Description = "Hide expert tab in the settings, can only be changed manually in this .ini", DefaultValue = "False")] - public bool HideExpertSettings { get; set; } - - [IniProperty("ThumnailPreview", Description = "Enable/disable thumbnail previews", DefaultValue = "True")] - public bool ThumnailPreview { get; set; } - - [IniProperty("NoGDICaptureForProduct", Description = "List of productnames for which GDI capturing is skipped (using fallback).", DefaultValue = "IntelliJ IDEA")] - public List NoGDICaptureForProduct { get; set; } - - [IniProperty("NoDWMCaptureForProduct", Description = "List of productnames for which DWM capturing is skipped (using fallback).", DefaultValue = "Citrix ICA Client")] - public List NoDWMCaptureForProduct { get; set; } - - [IniProperty("OptimizeForRDP", Description = "Make some optimizations for usage with remote desktop", DefaultValue = "False")] - public bool OptimizeForRDP { get; set; } - - [IniProperty("DisableRDPOptimizing", Description = "Disable all optimizations for usage with remote desktop", DefaultValue = "False")] - public bool DisableRDPOptimizing { get; set; } - - [IniProperty("MinimizeWorkingSetSize", Description = "Optimize memory footprint, but with a performance penalty!", DefaultValue = "False")] - public bool MinimizeWorkingSetSize { get; set; } - - [IniProperty("WindowCaptureRemoveCorners", Description = "Remove the corners from a window capture", DefaultValue = "True")] - public bool WindowCaptureRemoveCorners { get; set; } - - [IniProperty("CheckForUnstable", Description = "Also check for unstable version updates", DefaultValue = "False")] - public bool CheckForUnstable { get; set; } - - [IniProperty("ActiveTitleFixes", Description = "The fixes that are active.")] - public List ActiveTitleFixes { get; set; } - - [IniProperty("TitleFixMatcher", Description = "The regular expressions to match the title with.")] - public Dictionary TitleFixMatcher { get; set; } - - [IniProperty("TitleFixReplacer", Description = "The replacements for the matchers.")] - public Dictionary TitleFixReplacer { get; set; } - - [IniProperty("ExperimentalFeatures", Description = "A list of experimental features, this allows us to test certain features before releasing them.", ExcludeIfNull = true)] - public List ExperimentalFeatures { get; set; } - - [IniProperty("EnableSpecialDIBClipboardReader", Description = "Enable a special DIB clipboard reader", DefaultValue = "True")] - public bool EnableSpecialDIBClipboardReader { get; set; } - - [IniProperty("WindowCornerCutShape", Description = "The cutshape which is used to remove the window corners, is mirrorred for all corners", DefaultValue = "5,3,2,1,1")] - public List WindowCornerCutShape { get; set; } - - [IniProperty("LeftClickAction", - Description = - "Specify what action is made if the tray icon is left clicked, if a double-click action is specified this action is initiated after a delay (configurable via the windows double-click speed)", - DefaultValue = "SHOW_CONTEXT_MENU")] - public ClickActions LeftClickAction { get; set; } - - [IniProperty("DoubleClickAction", Description = "Specify what action is made if the tray icon is double clicked", DefaultValue = "OPEN_LAST_IN_EXPLORER")] - public ClickActions DoubleClickAction { get; set; } - - [IniProperty("ZoomerEnabled", Description = "Sets if the zoomer is enabled", DefaultValue = "True")] - public bool ZoomerEnabled { get; set; } - - [IniProperty("ZoomerOpacity", - Description = "Specify the transparency for the zoomer, from 0-1 (where 1 is no transparency and 0 is complete transparent. An usefull setting would be 0.7)", - DefaultValue = "1")] - public float ZoomerOpacity { get; set; } - - [IniProperty("MaxMenuItemLength", - Description = "Maximum length of submenu items in the context menu, making this longer might cause context menu issues on dual screen systems.", DefaultValue = "25")] - public int MaxMenuItemLength { get; set; } - - [IniProperty("MailApiTo", Description = "The 'to' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] - public string MailApiTo { get; set; } - - [IniProperty("MailApiCC", Description = "The 'CC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] - public string MailApiCC { get; set; } - - [IniProperty("MailApiBCC", Description = "The 'BCC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] - public string MailApiBCC { get; set; } - - [IniProperty("OptimizePNGCommand", - Description = - "Optional command to execute on a temporary PNG file, the command should overwrite the file and Greenshot will read it back. Note: this command is also executed when uploading PNG's!", - DefaultValue = "")] - public string OptimizePNGCommand { get; set; } - - [IniProperty("OptimizePNGCommandArguments", - Description = - "Arguments for the optional command to execute on a PNG, {0} is replaced by the temp-filename from Greenshot. Note: Temp-file is deleted afterwards by Greenshot.", - DefaultValue = "\"{0}\"")] - public string OptimizePNGCommandArguments { get; set; } - - [IniProperty("LastSaveWithVersion", Description = "Version of Greenshot which created this .ini")] - public string LastSaveWithVersion { get; set; } - - [IniProperty("ProcessEXIFOrientation", Description = "When reading images from files or clipboard, use the EXIF information to correct the orientation", - DefaultValue = "True")] - public bool ProcessEXIFOrientation { get; set; } - - [IniProperty("LastCapturedRegion", Description = "The last used region, for reuse in the capture last region")] - public Rectangle LastCapturedRegion { get; set; } - - [IniProperty("Win10BorderCrop", Description = "The capture is cropped with these settings, e.g. when you don't want to color around it -1,-1"), DefaultValue("0,0")] - public Size Win10BorderCrop { get; set; } - - private Size _iconSize; - - [IniProperty("BaseIconSize", - Description = "Defines the base size of the icons (e.g. for the buttons in the editor), default value 16,16 and it's scaled to the current DPI", - DefaultValue = "16,16")] - public Size IconSize - { - get { return _iconSize; } - set - { - Size newSize = value; - if (newSize != Size.Empty) - { - if (newSize.Width < 16) - { - newSize.Width = 16; - } - else if (newSize.Width > 256) - { - newSize.Width = 256; - } - - newSize.Width = (newSize.Width / 16) * 16; - if (newSize.Height < 16) - { - newSize.Height = 16; - } - else if (IconSize.Height > 256) - { - newSize.Height = 256; - } - - newSize.Height = (newSize.Height / 16) * 16; - } - - if (_iconSize != newSize) - { - _iconSize = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IconSize")); - } - } - } - - public Size ScaledIconSize => DpiHelper.ScaleWithCurrentDpi(_iconSize); - - [IniProperty("WebRequestTimeout", Description = "The connect timeout value for webrequets, these are seconds", DefaultValue = "100")] - public int WebRequestTimeout { get; set; } - - [IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")] - public int WebRequestReadWriteTimeout { get; set; } - - public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32; - - /// - /// A helper method which returns true if the supplied experimental feature is enabled - /// - /// - /// - public bool IsExperimentalFeatureEnabled(string experimentalFeature) - { - return (ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature)); - } - - /// - /// Supply values we can't put as defaults - /// - /// The property to return a default for - /// object with the default value for the supplied property - public override object GetDefault(string property) - { - switch (property) - { - case "PluginWhitelist": - case "PluginBacklist": - return new List(); - case "OutputFileAsFullpath": - if (IniConfig.IsPortable) - { - return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png"); - } - - return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "dummy.png"); - case "OutputFilePath": - if (IniConfig.IsPortable) - { - string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots"); - if (!Directory.Exists(pafOutputFilePath)) - { - try - { - Directory.CreateDirectory(pafOutputFilePath); - return pafOutputFilePath; - } - catch (Exception ex) - { - LOG.Warn(ex); - // Problem creating directory, fallback to Desktop - } - } - else - { - return pafOutputFilePath; - } - } - - return Environment.GetFolderPath(Environment.SpecialFolder.Desktop); - case "DWMBackgroundColor": - return Color.Transparent; - case "ActiveTitleFixes": - return new List - { - "Firefox", - "IE", - "Chrome" - }; - case "TitleFixMatcher": - return new Dictionary - { - { - "Firefox", " - Mozilla Firefox.*" - }, - { - "IE", " - (Microsoft|Windows) Internet Explorer.*" - }, - { - "Chrome", " - Google Chrome.*" - } - }; - case "TitleFixReplacer": - return new Dictionary - { - { - "Firefox", string.Empty - }, - { - "IE", string.Empty - }, - { - "Chrome", string.Empty - } - }; - } - - return null; - } - - /// - /// This method will be called before converting the property, making to possible to correct a certain value - /// Can be used when migration is needed - /// - /// The name of the property - /// The string value of the property - /// string with the propertyValue, modified or not... - public override string PreCheckValue(string propertyName, string propertyValue) - { - // Changed the separator, now we need to correct this - if ("Destinations".Equals(propertyName)) - { - if (propertyValue != null) - { - return propertyValue.Replace('|', ','); - } - } - - if ("OutputFilePath".Equals(propertyName)) - { - if (string.IsNullOrEmpty(propertyValue)) - { - return null; - } - } - - return base.PreCheckValue(propertyName, propertyValue); - } - - /// - /// This method will be called before writing the configuration - /// - public override void BeforeSave() - { - try - { - // Store version, this can be used later to fix settings after an update - LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); - } - catch - { - // ignored - } - } - - /// - /// This method will be called after reading the configuration, so eventually some corrections can be made - /// - public override void AfterLoad() - { - // Comment with releases - // CheckForUnstable = true; - - if (string.IsNullOrEmpty(LastSaveWithVersion)) - { - try - { - // Store version, this can be used later to fix settings after an update - LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); - } - catch - { - // ignored - } - - // Disable the AutoReduceColors as it causes issues with Mozzila applications and some others - OutputFileAutoReduceColors = false; - } - - // Fix for excessive feed checking - if (UpdateCheckInterval != 0 && UpdateCheckInterval <= 7 && LastSaveWithVersion.StartsWith("1.2")) - { - UpdateCheckInterval = 14; - } - - if (UpdateCheckInterval > 365) - { - UpdateCheckInterval = 365; - } - - // Enable OneNote if upgrading from 1.1 - if (ExcludeDestinations != null && ExcludeDestinations.Contains("OneNote")) - { - if (LastSaveWithVersion != null && LastSaveWithVersion.StartsWith("1.1")) - { - ExcludeDestinations.Remove("OneNote"); - } - else - { - // TODO: Remove with the release - ExcludeDestinations.Remove("OneNote"); - } - } - - if (OutputDestinations == null) - { - OutputDestinations = new List(); - } - - // Make sure there is an output! - if (OutputDestinations.Count == 0) - { - OutputDestinations.Add("Editor"); - } - - // Prevent both settings at once, bug #3435056 - if (OutputDestinations.Contains("Clipboard") && OutputFileCopyPathToClipboard) - { - OutputFileCopyPathToClipboard = false; - } - - // Make sure we have clipboard formats, otherwise a paste doesn't make sense! - if (ClipboardFormats == null || ClipboardFormats.Count == 0) - { - ClipboardFormats = new List - { - ClipboardFormat.PNG, - ClipboardFormat.HTML, - ClipboardFormat.DIB - }; - } - - // Make sure the lists are lowercase, to speedup the check - if (NoGDICaptureForProduct != null) - { - // Fix error in configuration - if (NoGDICaptureForProduct.Count >= 2) - { - if ("intellij".Equals(NoGDICaptureForProduct[0]) && "idea".Equals(NoGDICaptureForProduct[1])) - { - NoGDICaptureForProduct.RemoveRange(0, 2); - NoGDICaptureForProduct.Add("Intellij Idea"); - IsDirty = true; - } - } - - for (int i = 0; i < NoGDICaptureForProduct.Count; i++) - { - NoGDICaptureForProduct[i] = NoGDICaptureForProduct[i].ToLower(); - } - } - - if (NoDWMCaptureForProduct != null) - { - // Fix error in configuration - if (NoDWMCaptureForProduct.Count >= 3) - { - if ("citrix".Equals(NoDWMCaptureForProduct[0]) && "ica".Equals(NoDWMCaptureForProduct[1]) && "client".Equals(NoDWMCaptureForProduct[2])) - { - NoDWMCaptureForProduct.RemoveRange(0, 3); - NoDWMCaptureForProduct.Add("Citrix ICA Client"); - IsDirty = true; - } - } - - for (int i = 0; i < NoDWMCaptureForProduct.Count; i++) - { - NoDWMCaptureForProduct[i] = NoDWMCaptureForProduct[i].ToLower(); - } - } - - if (AutoCropDifference < 0) - { - AutoCropDifference = 0; - } - - if (AutoCropDifference > 255) - { - AutoCropDifference = 255; - } - - if (OutputFileReduceColorsTo < 2) - { - OutputFileReduceColorsTo = 2; - } - - if (OutputFileReduceColorsTo > 256) - { - OutputFileReduceColorsTo = 256; - } - - if (WebRequestTimeout <= 10) - { - WebRequestTimeout = 100; - } - - if (WebRequestReadWriteTimeout < 1) - { - WebRequestReadWriteTimeout = 100; - } - } - - /// - /// Validate the OutputFilePath, and if this is not correct it will be set to the default - /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) - /// - public void ValidateAndCorrectOutputFilePath() - { - if (!Directory.Exists(OutputFilePath)) - { - OutputFilePath = GetDefault(nameof(OutputFilePath)) as string; - } - } - - /// - /// Validate the OutputFileAsFullpath, and if this is not correct it will be set to the default - /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) - /// - public void ValidateAndCorrectOutputFileAsFullpath() - { - var outputFilePath = Path.GetDirectoryName(OutputFileAsFullpath); - if (outputFilePath == null || (!File.Exists(OutputFileAsFullpath) && !Directory.Exists(outputFilePath))) - { - OutputFileAsFullpath = GetDefault(nameof(OutputFileAsFullpath)) as string; - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Reflection; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Base.Core +{ + public enum ClipboardFormat + { + PNG, + DIB, + HTML, + HTMLDATAURL, + BITMAP, + DIBV5 + } + + public enum OutputFormat + { + bmp, + gif, + jpg, + png, + tiff, + greenshot, + ico + } + + public enum WindowCaptureMode + { + Screen, + GDI, + Aero, + AeroTransparent, + Auto + } + + public enum BuildStates + { + UNSTABLE, + RELEASE_CANDIDATE, + RELEASE + } + + public enum ClickActions + { + DO_NOTHING, + OPEN_LAST_IN_EXPLORER, + OPEN_LAST_IN_EDITOR, + OPEN_SETTINGS, + SHOW_CONTEXT_MENU + } + + /// + /// Description of CoreConfiguration. + /// + [IniSection("Core", Description = "Greenshot core configuration")] + public class CoreConfiguration : IniSection, INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + [IniProperty("Language", Description = "The language in IETF format (e.g. en-US)")] + public string Language { get; set; } + + [IniProperty("RegionHotkey", Description = "Hotkey for starting the region capture", DefaultValue = "PrintScreen")] + public string RegionHotkey { get; set; } + + [IniProperty("WindowHotkey", Description = "Hotkey for starting the window capture", DefaultValue = "Alt + PrintScreen")] + public string WindowHotkey { get; set; } + + [IniProperty("FullscreenHotkey", Description = "Hotkey for starting the fullscreen capture", DefaultValue = "Ctrl + PrintScreen")] + public string FullscreenHotkey { get; set; } + + [IniProperty("LastregionHotkey", Description = "Hotkey for starting the last region capture", DefaultValue = "Shift + PrintScreen")] + public string LastregionHotkey { get; set; } + + [IniProperty("IEHotkey", Description = "Hotkey for starting the IE capture", DefaultValue = "Shift + Ctrl + PrintScreen")] + public string IEHotkey { get; set; } + + [IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor")] + public string ClipboardHotkey { get; set; } + + [IniProperty("IsFirstLaunch", Description = "Is this the first time launch?", DefaultValue = "true")] + public bool IsFirstLaunch { get; set; } + + [IniProperty("Destinations", Separator = ",", + Description = "Which destinations? Possible options (more might be added by plugins) are: Editor, FileDefault, FileWithDialog, Clipboard, Printer, EMail, Picker", + DefaultValue = "Picker")] + public List OutputDestinations { get; set; } = new List(); + + [IniProperty("ClipboardFormats", Separator = ",", Description = "Specify which formats we copy on the clipboard? Options are: PNG, HTML, HTMLDATAURL and DIB", + DefaultValue = "PNG,DIB")] + public List ClipboardFormats { get; set; } = new List(); + + [IniProperty("CaptureMousepointer", Description = "Should the mouse be captured?", DefaultValue = "true")] + public bool CaptureMousepointer { get; set; } + + [IniProperty("CaptureWindowsInteractive", Description = "Use interactive window selection to capture? (false=Capture active window)", DefaultValue = "false")] + public bool CaptureWindowsInteractive { get; set; } + + [IniProperty("CaptureDelay", Description = "Capture delay in millseconds.", DefaultValue = "100")] + public int CaptureDelay { get; set; } + + [IniProperty("ScreenCaptureMode", Description = "The capture mode used to capture a screen. (Auto, FullScreen, Fixed)", DefaultValue = "Auto")] + public ScreenCaptureMode ScreenCaptureMode { get; set; } + + [IniProperty("ScreenToCapture", Description = "The screen number to capture when using ScreenCaptureMode Fixed.", DefaultValue = "1")] + public int ScreenToCapture { get; set; } + + [IniProperty("WindowCaptureMode", Description = "The capture mode used to capture a Window (Screen, GDI, Aero, AeroTransparent, Auto).", DefaultValue = "Auto")] + public WindowCaptureMode WindowCaptureMode { get; set; } + + [IniProperty("WindowCaptureAllChildLocations", + Description = "Enable/disable capture all children, very slow but will make it possible to use this information in the editor.", DefaultValue = "False")] + public bool WindowCaptureAllChildLocations { get; set; } + + [IniProperty("DWMBackgroundColor", Description = "The background color for a DWM window capture.")] + public Color DWMBackgroundColor { get; set; } + + [IniProperty("PlayCameraSound", LanguageKey = "settings_playsound", Description = "Play a camera sound after taking a capture.", DefaultValue = "false")] + public bool PlayCameraSound { get; set; } = false; + + [IniProperty("ShowTrayNotification", LanguageKey = "settings_shownotify", Description = "Show a notification from the systray when a capture is taken.", + DefaultValue = "true")] + public bool ShowTrayNotification { get; set; } = true; + + [IniProperty("OutputFilePath", Description = "Output file path.")] + public string OutputFilePath { get; set; } + + [IniProperty("OutputFileAllowOverwrite", + Description = "If the target file already exists True will make Greenshot always overwrite and False will display a 'Save-As' dialog.", DefaultValue = "true")] + public bool OutputFileAllowOverwrite { get; set; } + + [IniProperty("OutputFileFilenamePattern", Description = "Filename pattern for screenshot.", DefaultValue = "${capturetime:d\"yyyy-MM-dd HH_mm_ss\"}-${title}")] + public string OutputFileFilenamePattern { get; set; } + + [IniProperty("OutputFileFormat", Description = "Default file type for writing screenshots. (bmp, gif, jpg, png, tiff)", DefaultValue = "png")] + public OutputFormat OutputFileFormat { get; set; } = OutputFormat.png; + + [IniProperty("OutputFileReduceColors", Description = "If set to true, than the colors of the output file are reduced to 256 (8-bit) colors", DefaultValue = "false")] + public bool OutputFileReduceColors { get; set; } + + [IniProperty("OutputFileAutoReduceColors", + Description = "If set to true the amount of colors is counted and if smaller than 256 the color reduction is automatically used.", DefaultValue = "false")] + public bool OutputFileAutoReduceColors { get; set; } + + [IniProperty("OutputFileReduceColorsTo", Description = "Amount of colors to reduce to, when reducing", DefaultValue = "256")] + public int OutputFileReduceColorsTo { get; set; } + + [IniProperty("OutputFileCopyPathToClipboard", Description = "When saving a screenshot, copy the path to the clipboard?", DefaultValue = "true")] + public bool OutputFileCopyPathToClipboard { get; set; } + + [IniProperty("OutputFileAsFullpath", Description = "SaveAs Full path?")] + public string OutputFileAsFullpath { get; set; } + + [IniProperty("OutputFileJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int OutputFileJpegQuality { get; set; } + + [IniProperty("OutputFilePromptQuality", Description = "Ask for the quality before saving?", DefaultValue = "false")] + public bool OutputFilePromptQuality { get; set; } + + [IniProperty("OutputFileIncrementingNumber", Description = "The number for the ${NUM} in the filename pattern, is increased automatically after each save.", + DefaultValue = "1")] + public uint OutputFileIncrementingNumber { get; set; } + + [IniProperty("OutputPrintPromptOptions", LanguageKey = "settings_alwaysshowprintoptionsdialog", Description = "Ask for print options when printing?", + DefaultValue = "true")] + public bool OutputPrintPromptOptions { get; set; } + + [IniProperty("OutputPrintAllowRotate", LanguageKey = "printoptions_allowrotate", Description = "Allow rotating the picture for fitting on paper?", DefaultValue = "false")] + public bool OutputPrintAllowRotate { get; set; } + + [IniProperty("OutputPrintAllowEnlarge", LanguageKey = "printoptions_allowenlarge", Description = "Allow growing the picture for fitting on paper?", DefaultValue = "false")] + public bool OutputPrintAllowEnlarge { get; set; } + + [IniProperty("OutputPrintAllowShrink", LanguageKey = "printoptions_allowshrink", Description = "Allow shrinking the picture for fitting on paper?", DefaultValue = "true")] + public bool OutputPrintAllowShrink { get; set; } + + [IniProperty("OutputPrintCenter", LanguageKey = "printoptions_allowcenter", Description = "Center image when printing?", DefaultValue = "true")] + public bool OutputPrintCenter { get; set; } + + [IniProperty("OutputPrintInverted", LanguageKey = "printoptions_inverted", Description = "Print image inverted (use e.g. for console captures)", DefaultValue = "false")] + public bool OutputPrintInverted { get; set; } + + [IniProperty("OutputPrintGrayscale", LanguageKey = "printoptions_printgrayscale", Description = "Force grayscale printing", DefaultValue = "false")] + public bool OutputPrintGrayscale { get; set; } + + [IniProperty("OutputPrintMonochrome", LanguageKey = "printoptions_printmonochrome", Description = "Force monorchrome printing", DefaultValue = "false")] + public bool OutputPrintMonochrome { get; set; } + + [IniProperty("OutputPrintMonochromeThreshold", Description = "Threshold for monochrome filter (0 - 255), lower value means less black", DefaultValue = "127")] + public byte OutputPrintMonochromeThreshold { get; set; } + + [IniProperty("OutputPrintFooter", LanguageKey = "printoptions_timestamp", Description = "Print footer on print?", DefaultValue = "true")] + public bool OutputPrintFooter { get; set; } + + [IniProperty("OutputPrintFooterPattern", Description = "Footer pattern", DefaultValue = "${capturetime:d\"D\"} ${capturetime:d\"T\"} - ${title}")] + public string OutputPrintFooterPattern { get; set; } + + [IniProperty("NotificationSound", Description = "The wav-file to play when a capture is taken, loaded only once at the Greenshot startup", DefaultValue = "default")] + public string NotificationSound { get; set; } + + [IniProperty("UseProxy", Description = "Use your global proxy?", DefaultValue = "True")] + public bool UseProxy { get; set; } + + [IniProperty("IECapture", Description = "Enable/disable IE capture", DefaultValue = "True")] + public bool IECapture { get; set; } + + [IniProperty("IEFieldCapture", Description = "Enable/disable IE field capture, very slow but will make it possible to annotate the fields of a capture in the editor.", + DefaultValue = "False")] + public bool IEFieldCapture { get; set; } + + [IniProperty("WindowClassesToCheckForIE", Description = "Comma separated list of Window-Classes which need to be checked for a IE instance!", + DefaultValue = "AfxFrameOrView70,IMWindowClass")] + public List WindowClassesToCheckForIE { get; set; } + + [IniProperty("AutoCropDifference", + Description = + "Sets how to compare the colors for the autocrop detection, the higher the more is 'selected'. Possible values are from 0 to 255, where everything above ~150 doesn't make much sense!", + DefaultValue = "10")] + public int AutoCropDifference { get; set; } + + [IniProperty("IncludePlugins", + Description = "Comma separated list of Plugins which are allowed. If something in the list, than every plugin not in the list will not be loaded!")] + public List IncludePlugins { get; set; } + + [IniProperty("ExcludePlugins", Description = "Comma separated list of Plugins which are NOT allowed.")] + public List ExcludePlugins { get; set; } + + [IniProperty("ExcludeDestinations", Description = "Comma separated list of destinations which should be disabled.")] + public List ExcludeDestinations { get; set; } + + [IniProperty("UpdateCheckInterval", Description = "How many days between every update check? (0=no checks)", DefaultValue = "14")] + public int UpdateCheckInterval { get; set; } + + [IniProperty("LastUpdateCheck", Description = "Last update check")] + public DateTime LastUpdateCheck { get; set; } + + [IniProperty("DisableSettings", Description = "Enable/disable the access to the settings, can only be changed manually in this .ini", DefaultValue = "False")] + public bool DisableSettings { get; set; } + + [IniProperty("DisableQuickSettings", Description = "Enable/disable the access to the quick settings, can only be changed manually in this .ini", DefaultValue = "False")] + public bool DisableQuickSettings { get; set; } + + [IniProperty("DisableTrayicon", Description = "Disable the trayicon, can only be changed manually in this .ini", DefaultValue = "False")] + public bool HideTrayicon { get; set; } + + [IniProperty("HideExpertSettings", Description = "Hide expert tab in the settings, can only be changed manually in this .ini", DefaultValue = "False")] + public bool HideExpertSettings { get; set; } + + [IniProperty("ThumnailPreview", Description = "Enable/disable thumbnail previews", DefaultValue = "True")] + public bool ThumnailPreview { get; set; } + + [IniProperty("NoGDICaptureForProduct", Description = "List of productnames for which GDI capturing is skipped (using fallback).", DefaultValue = "IntelliJ IDEA")] + public List NoGDICaptureForProduct { get; set; } + + [IniProperty("NoDWMCaptureForProduct", Description = "List of productnames for which DWM capturing is skipped (using fallback).", DefaultValue = "Citrix ICA Client")] + public List NoDWMCaptureForProduct { get; set; } + + [IniProperty("OptimizeForRDP", Description = "Make some optimizations for usage with remote desktop", DefaultValue = "False")] + public bool OptimizeForRDP { get; set; } + + [IniProperty("DisableRDPOptimizing", Description = "Disable all optimizations for usage with remote desktop", DefaultValue = "False")] + public bool DisableRDPOptimizing { get; set; } + + [IniProperty("MinimizeWorkingSetSize", Description = "Optimize memory footprint, but with a performance penalty!", DefaultValue = "False")] + public bool MinimizeWorkingSetSize { get; set; } + + [IniProperty("WindowCaptureRemoveCorners", Description = "Remove the corners from a window capture", DefaultValue = "True")] + public bool WindowCaptureRemoveCorners { get; set; } + + [IniProperty("CheckForUnstable", Description = "Also check for unstable version updates", DefaultValue = "False")] + public bool CheckForUnstable { get; set; } + + [IniProperty("ActiveTitleFixes", Description = "The fixes that are active.")] + public List ActiveTitleFixes { get; set; } + + [IniProperty("TitleFixMatcher", Description = "The regular expressions to match the title with.")] + public Dictionary TitleFixMatcher { get; set; } + + [IniProperty("TitleFixReplacer", Description = "The replacements for the matchers.")] + public Dictionary TitleFixReplacer { get; set; } + + [IniProperty("ExperimentalFeatures", Description = "A list of experimental features, this allows us to test certain features before releasing them.", ExcludeIfNull = true)] + public List ExperimentalFeatures { get; set; } + + [IniProperty("EnableSpecialDIBClipboardReader", Description = "Enable a special DIB clipboard reader", DefaultValue = "True")] + public bool EnableSpecialDIBClipboardReader { get; set; } + + [IniProperty("WindowCornerCutShape", Description = "The cutshape which is used to remove the window corners, is mirrorred for all corners", DefaultValue = "5,3,2,1,1")] + public List WindowCornerCutShape { get; set; } + + [IniProperty("LeftClickAction", + Description = + "Specify what action is made if the tray icon is left clicked, if a double-click action is specified this action is initiated after a delay (configurable via the windows double-click speed)", + DefaultValue = "SHOW_CONTEXT_MENU")] + public ClickActions LeftClickAction { get; set; } + + [IniProperty("DoubleClickAction", Description = "Specify what action is made if the tray icon is double clicked", DefaultValue = "OPEN_LAST_IN_EXPLORER")] + public ClickActions DoubleClickAction { get; set; } + + [IniProperty("ZoomerEnabled", Description = "Sets if the zoomer is enabled", DefaultValue = "True")] + public bool ZoomerEnabled { get; set; } + + [IniProperty("ZoomerOpacity", + Description = "Specify the transparency for the zoomer, from 0-1 (where 1 is no transparency and 0 is complete transparent. An usefull setting would be 0.7)", + DefaultValue = "1")] + public float ZoomerOpacity { get; set; } + + [IniProperty("MaxMenuItemLength", + Description = "Maximum length of submenu items in the context menu, making this longer might cause context menu issues on dual screen systems.", DefaultValue = "25")] + public int MaxMenuItemLength { get; set; } + + [IniProperty("MailApiTo", Description = "The 'to' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] + public string MailApiTo { get; set; } + + [IniProperty("MailApiCC", Description = "The 'CC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] + public string MailApiCC { get; set; } + + [IniProperty("MailApiBCC", Description = "The 'BCC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] + public string MailApiBCC { get; set; } + + [IniProperty("OptimizePNGCommand", + Description = + "Optional command to execute on a temporary PNG file, the command should overwrite the file and Greenshot will read it back. Note: this command is also executed when uploading PNG's!", + DefaultValue = "")] + public string OptimizePNGCommand { get; set; } + + [IniProperty("OptimizePNGCommandArguments", + Description = + "Arguments for the optional command to execute on a PNG, {0} is replaced by the temp-filename from Greenshot. Note: Temp-file is deleted afterwards by Greenshot.", + DefaultValue = "\"{0}\"")] + public string OptimizePNGCommandArguments { get; set; } + + [IniProperty("LastSaveWithVersion", Description = "Version of Greenshot which created this .ini")] + public string LastSaveWithVersion { get; set; } + + [IniProperty("ProcessEXIFOrientation", Description = "When reading images from files or clipboard, use the EXIF information to correct the orientation", + DefaultValue = "True")] + public bool ProcessEXIFOrientation { get; set; } + + [IniProperty("LastCapturedRegion", Description = "The last used region, for reuse in the capture last region")] + public Rectangle LastCapturedRegion { get; set; } + + [IniProperty("Win10BorderCrop", Description = "The capture is cropped with these settings, e.g. when you don't want to color around it -1,-1"), DefaultValue("0,0")] + public Size Win10BorderCrop { get; set; } + + private Size _iconSize; + + [IniProperty("BaseIconSize", + Description = "Defines the base size of the icons (e.g. for the buttons in the editor), default value 16,16 and it's scaled to the current DPI", + DefaultValue = "16,16")] + public Size IconSize + { + get { return _iconSize; } + set + { + Size newSize = value; + if (newSize != Size.Empty) + { + if (newSize.Width < 16) + { + newSize.Width = 16; + } + else if (newSize.Width > 256) + { + newSize.Width = 256; + } + + newSize.Width = (newSize.Width / 16) * 16; + if (newSize.Height < 16) + { + newSize.Height = 16; + } + else if (IconSize.Height > 256) + { + newSize.Height = 256; + } + + newSize.Height = (newSize.Height / 16) * 16; + } + + if (_iconSize != newSize) + { + _iconSize = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IconSize")); + } + } + } + + public Size ScaledIconSize => DpiHelper.ScaleWithCurrentDpi(_iconSize); + + [IniProperty("WebRequestTimeout", Description = "The connect timeout value for webrequets, these are seconds", DefaultValue = "100")] + public int WebRequestTimeout { get; set; } + + [IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")] + public int WebRequestReadWriteTimeout { get; set; } + + public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32; + + /// + /// A helper method which returns true if the supplied experimental feature is enabled + /// + /// + /// + public bool IsExperimentalFeatureEnabled(string experimentalFeature) + { + return (ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature)); + } + + /// + /// Supply values we can't put as defaults + /// + /// The property to return a default for + /// object with the default value for the supplied property + public override object GetDefault(string property) + { + switch (property) + { + case "PluginWhitelist": + case "PluginBacklist": + return new List(); + case "OutputFileAsFullpath": + if (IniConfig.IsPortable) + { + return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png"); + } + + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "dummy.png"); + case "OutputFilePath": + if (IniConfig.IsPortable) + { + string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots"); + if (!Directory.Exists(pafOutputFilePath)) + { + try + { + Directory.CreateDirectory(pafOutputFilePath); + return pafOutputFilePath; + } + catch (Exception ex) + { + LOG.Warn(ex); + // Problem creating directory, fallback to Desktop + } + } + else + { + return pafOutputFilePath; + } + } + + return Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + case "DWMBackgroundColor": + return Color.Transparent; + case "ActiveTitleFixes": + return new List + { + "Firefox", + "IE", + "Chrome" + }; + case "TitleFixMatcher": + return new Dictionary + { + { + "Firefox", " - Mozilla Firefox.*" + }, + { + "IE", " - (Microsoft|Windows) Internet Explorer.*" + }, + { + "Chrome", " - Google Chrome.*" + } + }; + case "TitleFixReplacer": + return new Dictionary + { + { + "Firefox", string.Empty + }, + { + "IE", string.Empty + }, + { + "Chrome", string.Empty + } + }; + } + + return null; + } + + /// + /// This method will be called before converting the property, making to possible to correct a certain value + /// Can be used when migration is needed + /// + /// The name of the property + /// The string value of the property + /// string with the propertyValue, modified or not... + public override string PreCheckValue(string propertyName, string propertyValue) + { + // Changed the separator, now we need to correct this + if ("Destinations".Equals(propertyName)) + { + if (propertyValue != null) + { + return propertyValue.Replace('|', ','); + } + } + + if ("OutputFilePath".Equals(propertyName)) + { + if (string.IsNullOrEmpty(propertyValue)) + { + return null; + } + } + + return base.PreCheckValue(propertyName, propertyValue); + } + + /// + /// This method will be called before writing the configuration + /// + public override void BeforeSave() + { + try + { + // Store version, this can be used later to fix settings after an update + LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); + } + catch + { + // ignored + } + } + + /// + /// This method will be called after reading the configuration, so eventually some corrections can be made + /// + public override void AfterLoad() + { + // Comment with releases + // CheckForUnstable = true; + + if (string.IsNullOrEmpty(LastSaveWithVersion)) + { + try + { + // Store version, this can be used later to fix settings after an update + LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); + } + catch + { + // ignored + } + + // Disable the AutoReduceColors as it causes issues with Mozzila applications and some others + OutputFileAutoReduceColors = false; + } + + // Fix for excessive feed checking + if (UpdateCheckInterval != 0 && UpdateCheckInterval <= 7 && LastSaveWithVersion.StartsWith("1.2")) + { + UpdateCheckInterval = 14; + } + + if (UpdateCheckInterval > 365) + { + UpdateCheckInterval = 365; + } + + // Enable OneNote if upgrading from 1.1 + if (ExcludeDestinations != null && ExcludeDestinations.Contains("OneNote")) + { + if (LastSaveWithVersion != null && LastSaveWithVersion.StartsWith("1.1")) + { + ExcludeDestinations.Remove("OneNote"); + } + else + { + // TODO: Remove with the release + ExcludeDestinations.Remove("OneNote"); + } + } + + if (OutputDestinations == null) + { + OutputDestinations = new List(); + } + + // Make sure there is an output! + if (OutputDestinations.Count == 0) + { + OutputDestinations.Add("Editor"); + } + + // Prevent both settings at once, bug #3435056 + if (OutputDestinations.Contains("Clipboard") && OutputFileCopyPathToClipboard) + { + OutputFileCopyPathToClipboard = false; + } + + // Make sure we have clipboard formats, otherwise a paste doesn't make sense! + if (ClipboardFormats == null || ClipboardFormats.Count == 0) + { + ClipboardFormats = new List + { + ClipboardFormat.PNG, + ClipboardFormat.HTML, + ClipboardFormat.DIB + }; + } + + // Make sure the lists are lowercase, to speedup the check + if (NoGDICaptureForProduct != null) + { + // Fix error in configuration + if (NoGDICaptureForProduct.Count >= 2) + { + if ("intellij".Equals(NoGDICaptureForProduct[0]) && "idea".Equals(NoGDICaptureForProduct[1])) + { + NoGDICaptureForProduct.RemoveRange(0, 2); + NoGDICaptureForProduct.Add("Intellij Idea"); + IsDirty = true; + } + } + + for (int i = 0; i < NoGDICaptureForProduct.Count; i++) + { + NoGDICaptureForProduct[i] = NoGDICaptureForProduct[i].ToLower(); + } + } + + if (NoDWMCaptureForProduct != null) + { + // Fix error in configuration + if (NoDWMCaptureForProduct.Count >= 3) + { + if ("citrix".Equals(NoDWMCaptureForProduct[0]) && "ica".Equals(NoDWMCaptureForProduct[1]) && "client".Equals(NoDWMCaptureForProduct[2])) + { + NoDWMCaptureForProduct.RemoveRange(0, 3); + NoDWMCaptureForProduct.Add("Citrix ICA Client"); + IsDirty = true; + } + } + + for (int i = 0; i < NoDWMCaptureForProduct.Count; i++) + { + NoDWMCaptureForProduct[i] = NoDWMCaptureForProduct[i].ToLower(); + } + } + + if (AutoCropDifference < 0) + { + AutoCropDifference = 0; + } + + if (AutoCropDifference > 255) + { + AutoCropDifference = 255; + } + + if (OutputFileReduceColorsTo < 2) + { + OutputFileReduceColorsTo = 2; + } + + if (OutputFileReduceColorsTo > 256) + { + OutputFileReduceColorsTo = 256; + } + + if (WebRequestTimeout <= 10) + { + WebRequestTimeout = 100; + } + + if (WebRequestReadWriteTimeout < 1) + { + WebRequestReadWriteTimeout = 100; + } + } + + /// + /// Validate the OutputFilePath, and if this is not correct it will be set to the default + /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) + /// + public void ValidateAndCorrectOutputFilePath() + { + if (!Directory.Exists(OutputFilePath)) + { + OutputFilePath = GetDefault(nameof(OutputFilePath)) as string; + } + } + + /// + /// Validate the OutputFileAsFullpath, and if this is not correct it will be set to the default + /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) + /// + public void ValidateAndCorrectOutputFileAsFullpath() + { + var outputFilePath = Path.GetDirectoryName(OutputFileAsFullpath); + if (outputFilePath == null || (!File.Exists(OutputFileAsFullpath) && !Directory.Exists(outputFilePath))) + { + OutputFileAsFullpath = GetDefault(nameof(OutputFileAsFullpath)) as string; + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/CredentialsHelper.cs b/src/Greenshot.Base/Core/CredentialsHelper.cs similarity index 97% rename from src/GreenshotPlugin/Core/CredentialsHelper.cs rename to src/Greenshot.Base/Core/CredentialsHelper.cs index a1140dc46..cc02113a0 100644 --- a/src/GreenshotPlugin/Core/CredentialsHelper.cs +++ b/src/Greenshot.Base/Core/CredentialsHelper.cs @@ -1,525 +1,525 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Windows.Forms; - -namespace GreenshotPlugin.Core -{ - /// - /// The following code comes from: http://www.developerfusion.com/code/4693/using-the-credential-management-api/ - /// and is slightly modified so it works for us. - /// As the "Stored usernames and passwords" which can be accessed by: Start-> Run and type "Control keymgr.dll" - /// doesn't show all credentials use the tool here: http://www.microsoft.com/indonesia/msdn/credmgmt.aspx - /// The following code is an example for a login, it will call the Authenticate with user/password - /// which should return true if the login worked, false if not. - /// private static bool Login(string system, string name) { - /// try { - /// CredentialsDialog dialog = new CredentialsDialog(system); - /// dialog.Name = name; - /// while (dialog.Show(dialog.Name) == DialogResult.OK) { - /// if (Authenticate(dialog.Name, dialog.Password)) { - /// if (dialog.SaveChecked) dialog.Confirm(true); - /// return true; - /// } else { - /// try { - /// dialog.Confirm(false); - /// } catch (ApplicationException) { - /// // exception handling ... - /// } - /// dialog.IncorrectPassword = true; - /// } - /// } - /// } catch (ApplicationException) { - /// // exception handling ... - /// } - /// return false; - /// } - /// - /// Encapsulates dialog functionality from the Credential Management API. - public sealed class CredentialsDialog - { - [DllImport("gdi32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); - - /// The only valid bitmap height (in pixels) of a user-defined banner. - private const int ValidBannerHeight = 60; - - /// The only valid bitmap width (in pixels) of a user-defined banner. - private const int ValidBannerWidth = 320; - - /// Initializes a new instance of the class - /// with the specified target. - /// The name of the target for the credentials, typically a server name. - public CredentialsDialog(string target) : this(target, null) - { - } - - /// Initializes a new instance of the class - /// with the specified target and caption. - /// The name of the target for the credentials, typically a server name. - /// The caption of the dialog (null will cause a system default title to be used). - public CredentialsDialog(string target, string caption) : this(target, caption, null) - { - } - - /// Initializes a new instance of the class - /// with the specified target, caption and message. - /// The name of the target for the credentials, typically a server name. - /// The caption of the dialog (null will cause a system default title to be used). - /// The message of the dialog (null will cause a system default message to be used). - public CredentialsDialog(string target, string caption, string message) : this(target, caption, message, null) - { - } - - /// Initializes a new instance of the class - /// with the specified target, caption, message and banner. - /// The name of the target for the credentials, typically a server name. - /// The caption of the dialog (null will cause a system default title to be used). - /// The message of the dialog (null will cause a system default message to be used). - /// The image to display on the dialog (null will cause a system default image to be used). - public CredentialsDialog(string target, string caption, string message, Image banner) - { - Target = target; - Caption = caption; - Message = message; - Banner = banner; - } - - /// - /// Gets or sets if the dialog will be shown even if the credentials - /// can be returned from an existing credential in the credential manager. - /// - public bool AlwaysDisplay { get; set; } - - /// Gets or sets if the dialog is populated with name/password only. - public bool ExcludeCertificates { get; set; } = true; - - /// Gets or sets if the credentials are to be persisted in the credential manager. - public bool Persist { get; set; } = true; - - /// Gets or sets if the incorrect password balloontip needs to be shown. Introduced AFTER Windows XP - public bool IncorrectPassword { get; set; } - - /// Gets or sets if the name is read-only. - public bool KeepName { get; set; } - - private string _name = string.Empty; - - /// Gets or sets the name for the credentials. - public string Name - { - get { return _name; } - set - { - if (value?.Length > CredUi.MAX_USERNAME_LENGTH) - { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The name has a maximum length of {0} characters.", - CredUi.MAX_USERNAME_LENGTH); - throw new ArgumentException(message, nameof(Name)); - } - - _name = value; - } - } - - private string _password = string.Empty; - - /// Gets or sets the password for the credentials. - public string Password - { - get { return _password; } - set - { - if (value?.Length > CredUi.MAX_PASSWORD_LENGTH) - { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The password has a maximum length of {0} characters.", - CredUi.MAX_PASSWORD_LENGTH); - throw new ArgumentException(message, nameof(Password)); - } - - _password = value; - } - } - - /// Gets or sets if the save checkbox status. - public bool SaveChecked { get; set; } - - /// Gets or sets if the save checkbox is displayed. - /// This value only has effect if Persist is true. - public bool SaveDisplayed { get; set; } = true; - - private string _target = string.Empty; - - /// Gets or sets the name of the target for the credentials, typically a server name. - public string Target - { - get { return _target; } - set - { - if (value == null) - { - throw new ArgumentException("The target cannot be a null value.", nameof(Target)); - } - - if (value.Length > CredUi.MAX_GENERIC_TARGET_LENGTH) - { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The target has a maximum length of {0} characters.", - CredUi.MAX_GENERIC_TARGET_LENGTH); - throw new ArgumentException(message, nameof(Target)); - } - - _target = value; - } - } - - private string _caption = string.Empty; - - /// Gets or sets the caption of the dialog. - /// A null value will cause a system default caption to be used. - public string Caption - { - get { return _caption; } - set - { - if (value?.Length > CredUi.MAX_CAPTION_LENGTH) - { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The caption has a maximum length of {0} characters.", - CredUi.MAX_CAPTION_LENGTH); - throw new ArgumentException(message, nameof(Caption)); - } - - _caption = value; - } - } - - private string _message = string.Empty; - - /// Gets or sets the message of the dialog. - /// A null value will cause a system default message to be used. - public string Message - { - get { return _message; } - set - { - if (value?.Length > CredUi.MAX_MESSAGE_LENGTH) - { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The message has a maximum length of {0} characters.", - CredUi.MAX_MESSAGE_LENGTH); - throw new ArgumentException(message, nameof(Message)); - } - - _message = value; - } - } - - private Image _banner; - - /// Gets or sets the image to display on the dialog. - /// A null value will cause a system default image to be used. - public Image Banner - { - get { return _banner; } - set - { - if (value != null) - { - if (value.Width != ValidBannerWidth) - { - throw new ArgumentException("The banner image width must be 320 pixels.", nameof(Banner)); - } - - if (value.Height != ValidBannerHeight) - { - throw new ArgumentException("The banner image height must be 60 pixels.", nameof(Banner)); - } - } - - _banner = value; - } - } - - /// Shows the credentials dialog with the specified name. - /// The name for the credentials. - /// Returns a DialogResult indicating the user action. - public DialogResult Show(string name) - { - return Show(null, name, Password, SaveChecked); - } - - /// Shows the credentials dialog with the specified owner, name, password and save checkbox status. - /// The System.Windows.Forms.IWin32Window the dialog will display in front of. - /// The name for the credentials. - /// The password for the credentials. - /// True if the save checkbox is checked. - /// Returns a DialogResult indicating the user action. - public DialogResult Show(IWin32Window owner, string name, string password, bool saveChecked) - { - if ((Environment.OSVersion.Version.Major < 5) || ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor < 1))) - { - throw new ApplicationException("The Credential Management API requires Windows XP / Windows Server 2003 or later."); - } - - Name = name; - Password = password; - SaveChecked = saveChecked; - - return ShowDialog(owner); - } - - /// Confirmation action to be applied. - /// True if the credentials should be persisted. - public void Confirm(bool value) - { - var confirmResult = CredUi.CredUIConfirmCredentials(Target, value); - switch (confirmResult) - { - case CredUi.ReturnCodes.NO_ERROR: - break; - case CredUi.ReturnCodes.ERROR_INVALID_PARAMETER: - // for some reason, this is encountered when credentials are overwritten - break; - default: - throw new ApplicationException($"Credential confirmation failed: {confirmResult}"); - } - } - - /// Returns a DialogResult indicating the user action. - /// The System.Windows.Forms.IWin32Window the dialog will display in front of. - /// - /// Sets the name, password and SaveChecked accessors to the state of the dialog as it was dismissed by the user. - /// - private DialogResult ShowDialog(IWin32Window owner) - { - // set the api call parameters - StringBuilder name = new StringBuilder(CredUi.MAX_USERNAME_LENGTH); - name.Append(Name); - - StringBuilder password = new StringBuilder(CredUi.MAX_PASSWORD_LENGTH); - password.Append(Password); - - int saveChecked = Convert.ToInt32(SaveChecked); - - CredUi.INFO info = GetInfo(owner); - CredUi.CredFlags credFlags = GetFlags(); - - // make the api call - CredUi.ReturnCodes code = CredUi.CredUIPromptForCredentials( - ref info, - Target, - IntPtr.Zero, 0, - name, CredUi.MAX_USERNAME_LENGTH, - password, CredUi.MAX_PASSWORD_LENGTH, - ref saveChecked, - credFlags - ); - - // clean up resources - if (Banner != null) - { - DeleteObject(info.hbmBanner); - } - - // set the accessors from the api call parameters - Name = name.ToString(); - Password = password.ToString(); - SaveChecked = Convert.ToBoolean(saveChecked); - - return GetDialogResult(code); - } - - /// Returns the info structure for dialog display settings. - /// The System.Windows.Forms.IWin32Window the dialog will display in front of. - private CredUi.INFO GetInfo(IWin32Window owner) - { - CredUi.INFO info = new CredUi.INFO(); - if (owner != null) info.hWndParent = owner.Handle; - info.pszCaptionText = Caption; - info.pszMessageText = Message; - if (Banner != null) - { - info.hbmBanner = new Bitmap(Banner, ValidBannerWidth, ValidBannerHeight).GetHbitmap(); - } - - info.cbSize = Marshal.SizeOf(info); - return info; - } - - /// Returns the flags for dialog display options. - private CredUi.CredFlags GetFlags() - { - CredUi.CredFlags credFlags = CredUi.CredFlags.GENERIC_CREDENTIALS; - - if (IncorrectPassword) - { - credFlags |= CredUi.CredFlags.INCORRECT_PASSWORD; - } - - if (AlwaysDisplay) - { - credFlags |= CredUi.CredFlags.ALWAYS_SHOW_UI; - } - - if (ExcludeCertificates) - { - credFlags |= CredUi.CredFlags.EXCLUDE_CERTIFICATES; - } - - if (Persist) - { - credFlags |= CredUi.CredFlags.EXPECT_CONFIRMATION; - if (SaveDisplayed) - { - credFlags |= CredUi.CredFlags.SHOW_SAVE_CHECK_BOX; - } - else - { - credFlags |= CredUi.CredFlags.PERSIST; - } - } - else - { - credFlags |= CredUi.CredFlags.DO_NOT_PERSIST; - } - - if (KeepName) - { - credFlags |= CredUi.CredFlags.KEEP_USERNAME; - } - - return credFlags; - } - - /// Returns a DialogResult from the specified code. - /// The credential return code. - private DialogResult GetDialogResult(CredUi.ReturnCodes code) => - code switch - { - CredUi.ReturnCodes.NO_ERROR => DialogResult.OK, - CredUi.ReturnCodes.ERROR_CANCELLED => DialogResult.Cancel, - CredUi.ReturnCodes.ERROR_NO_SUCH_LOGON_SESSION => throw new ApplicationException( - "No such logon session."), - CredUi.ReturnCodes.ERROR_NOT_FOUND => throw new ApplicationException("Not found."), - CredUi.ReturnCodes.ERROR_INVALID_ACCOUNT_NAME => - throw new ApplicationException("Invalid account name."), - CredUi.ReturnCodes.ERROR_INSUFFICIENT_BUFFER => throw new ApplicationException("Insufficient buffer."), - CredUi.ReturnCodes.ERROR_INVALID_PARAMETER => throw new ApplicationException("Invalid parameter."), - CredUi.ReturnCodes.ERROR_INVALID_FLAGS => throw new ApplicationException("Invalid flags."), - _ => throw new ApplicationException("Unknown credential result encountered.") - }; - } - - internal static class CredUi - { - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/authentication_constants.asp - public const int MAX_MESSAGE_LENGTH = 100; - - public const int MAX_CAPTION_LENGTH = 100; - public const int MAX_GENERIC_TARGET_LENGTH = 100; - public const int MAX_USERNAME_LENGTH = 100; - public const int MAX_PASSWORD_LENGTH = 100; - - /// - /// http://www.pinvoke.net/default.aspx/Enums.CREDUI_FLAGS - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/dpapiusercredentials.asp - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp - /// - [Flags] - public enum CredFlags - { - INCORRECT_PASSWORD = 0x1, - DO_NOT_PERSIST = 0x2, - EXCLUDE_CERTIFICATES = 0x8, - SHOW_SAVE_CHECK_BOX = 0x40, - ALWAYS_SHOW_UI = 0x80, - PERSIST = 0x1000, - EXPECT_CONFIRMATION = 0x20000, - GENERIC_CREDENTIALS = 0x40000, - KEEP_USERNAME = 0x100000, - } - - /// http://www.pinvoke.net/default.aspx/Enums.CredUIReturnCodes - public enum ReturnCodes - { - NO_ERROR = 0, - ERROR_INVALID_PARAMETER = 87, - ERROR_INSUFFICIENT_BUFFER = 122, - ERROR_INVALID_FLAGS = 1004, - ERROR_NOT_FOUND = 1168, - ERROR_CANCELLED = 1223, - ERROR_NO_SUCH_LOGON_SESSION = 1312, - ERROR_INVALID_ACCOUNT_NAME = 1315 - } - - /// - /// http://www.pinvoke.net/default.aspx/Structures.CREDUI_INFO - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/credui_info.asp - /// - public struct INFO - { - public int cbSize; - public IntPtr hWndParent; - [MarshalAs(UnmanagedType.LPWStr)] public string pszMessageText; - [MarshalAs(UnmanagedType.LPWStr)] public string pszCaptionText; - public IntPtr hbmBanner; - } - - /// - /// http://www.pinvoke.net/default.aspx/credui.CredUIPromptForCredentialsW - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp - /// - [DllImport("credui", CharSet = CharSet.Unicode)] - public static extern ReturnCodes CredUIPromptForCredentials( - ref INFO creditUR, - string targetName, - IntPtr reserved1, - int iError, - StringBuilder userName, - int maxUserName, - StringBuilder password, - int maxPassword, - ref int iSave, - CredFlags credFlags - ); - - /// - /// http://www.pinvoke.net/default.aspx/credui.CredUIConfirmCredentials - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduiconfirmcredentials.asp - /// - [DllImport("credui.dll", CharSet = CharSet.Unicode)] - public static extern ReturnCodes CredUIConfirmCredentials(string targetName, [MarshalAs(UnmanagedType.Bool)] bool confirm); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +namespace Greenshot.Base.Core +{ + /// + /// The following code comes from: http://www.developerfusion.com/code/4693/using-the-credential-management-api/ + /// and is slightly modified so it works for us. + /// As the "Stored usernames and passwords" which can be accessed by: Start-> Run and type "Control keymgr.dll" + /// doesn't show all credentials use the tool here: http://www.microsoft.com/indonesia/msdn/credmgmt.aspx + /// The following code is an example for a login, it will call the Authenticate with user/password + /// which should return true if the login worked, false if not. + /// private static bool Login(string system, string name) { + /// try { + /// CredentialsDialog dialog = new CredentialsDialog(system); + /// dialog.Name = name; + /// while (dialog.Show(dialog.Name) == DialogResult.OK) { + /// if (Authenticate(dialog.Name, dialog.Password)) { + /// if (dialog.SaveChecked) dialog.Confirm(true); + /// return true; + /// } else { + /// try { + /// dialog.Confirm(false); + /// } catch (ApplicationException) { + /// // exception handling ... + /// } + /// dialog.IncorrectPassword = true; + /// } + /// } + /// } catch (ApplicationException) { + /// // exception handling ... + /// } + /// return false; + /// } + /// + /// Encapsulates dialog functionality from the Credential Management API. + public sealed class CredentialsDialog + { + [DllImport("gdi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteObject(IntPtr hObject); + + /// The only valid bitmap height (in pixels) of a user-defined banner. + private const int ValidBannerHeight = 60; + + /// The only valid bitmap width (in pixels) of a user-defined banner. + private const int ValidBannerWidth = 320; + + /// Initializes a new instance of the class + /// with the specified target. + /// The name of the target for the credentials, typically a server name. + public CredentialsDialog(string target) : this(target, null) + { + } + + /// Initializes a new instance of the class + /// with the specified target and caption. + /// The name of the target for the credentials, typically a server name. + /// The caption of the dialog (null will cause a system default title to be used). + public CredentialsDialog(string target, string caption) : this(target, caption, null) + { + } + + /// Initializes a new instance of the class + /// with the specified target, caption and message. + /// The name of the target for the credentials, typically a server name. + /// The caption of the dialog (null will cause a system default title to be used). + /// The message of the dialog (null will cause a system default message to be used). + public CredentialsDialog(string target, string caption, string message) : this(target, caption, message, null) + { + } + + /// Initializes a new instance of the class + /// with the specified target, caption, message and banner. + /// The name of the target for the credentials, typically a server name. + /// The caption of the dialog (null will cause a system default title to be used). + /// The message of the dialog (null will cause a system default message to be used). + /// The image to display on the dialog (null will cause a system default image to be used). + public CredentialsDialog(string target, string caption, string message, Image banner) + { + Target = target; + Caption = caption; + Message = message; + Banner = banner; + } + + /// + /// Gets or sets if the dialog will be shown even if the credentials + /// can be returned from an existing credential in the credential manager. + /// + public bool AlwaysDisplay { get; set; } + + /// Gets or sets if the dialog is populated with name/password only. + public bool ExcludeCertificates { get; set; } = true; + + /// Gets or sets if the credentials are to be persisted in the credential manager. + public bool Persist { get; set; } = true; + + /// Gets or sets if the incorrect password balloontip needs to be shown. Introduced AFTER Windows XP + public bool IncorrectPassword { get; set; } + + /// Gets or sets if the name is read-only. + public bool KeepName { get; set; } + + private string _name = string.Empty; + + /// Gets or sets the name for the credentials. + public string Name + { + get { return _name; } + set + { + if (value?.Length > CredUi.MAX_USERNAME_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The name has a maximum length of {0} characters.", + CredUi.MAX_USERNAME_LENGTH); + throw new ArgumentException(message, nameof(Name)); + } + + _name = value; + } + } + + private string _password = string.Empty; + + /// Gets or sets the password for the credentials. + public string Password + { + get { return _password; } + set + { + if (value?.Length > CredUi.MAX_PASSWORD_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The password has a maximum length of {0} characters.", + CredUi.MAX_PASSWORD_LENGTH); + throw new ArgumentException(message, nameof(Password)); + } + + _password = value; + } + } + + /// Gets or sets if the save checkbox status. + public bool SaveChecked { get; set; } + + /// Gets or sets if the save checkbox is displayed. + /// This value only has effect if Persist is true. + public bool SaveDisplayed { get; set; } = true; + + private string _target = string.Empty; + + /// Gets or sets the name of the target for the credentials, typically a server name. + public string Target + { + get { return _target; } + set + { + if (value == null) + { + throw new ArgumentException("The target cannot be a null value.", nameof(Target)); + } + + if (value.Length > CredUi.MAX_GENERIC_TARGET_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The target has a maximum length of {0} characters.", + CredUi.MAX_GENERIC_TARGET_LENGTH); + throw new ArgumentException(message, nameof(Target)); + } + + _target = value; + } + } + + private string _caption = string.Empty; + + /// Gets or sets the caption of the dialog. + /// A null value will cause a system default caption to be used. + public string Caption + { + get { return _caption; } + set + { + if (value?.Length > CredUi.MAX_CAPTION_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The caption has a maximum length of {0} characters.", + CredUi.MAX_CAPTION_LENGTH); + throw new ArgumentException(message, nameof(Caption)); + } + + _caption = value; + } + } + + private string _message = string.Empty; + + /// Gets or sets the message of the dialog. + /// A null value will cause a system default message to be used. + public string Message + { + get { return _message; } + set + { + if (value?.Length > CredUi.MAX_MESSAGE_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The message has a maximum length of {0} characters.", + CredUi.MAX_MESSAGE_LENGTH); + throw new ArgumentException(message, nameof(Message)); + } + + _message = value; + } + } + + private Image _banner; + + /// Gets or sets the image to display on the dialog. + /// A null value will cause a system default image to be used. + public Image Banner + { + get { return _banner; } + set + { + if (value != null) + { + if (value.Width != ValidBannerWidth) + { + throw new ArgumentException("The banner image width must be 320 pixels.", nameof(Banner)); + } + + if (value.Height != ValidBannerHeight) + { + throw new ArgumentException("The banner image height must be 60 pixels.", nameof(Banner)); + } + } + + _banner = value; + } + } + + /// Shows the credentials dialog with the specified name. + /// The name for the credentials. + /// Returns a DialogResult indicating the user action. + public DialogResult Show(string name) + { + return Show(null, name, Password, SaveChecked); + } + + /// Shows the credentials dialog with the specified owner, name, password and save checkbox status. + /// The System.Windows.Forms.IWin32Window the dialog will display in front of. + /// The name for the credentials. + /// The password for the credentials. + /// True if the save checkbox is checked. + /// Returns a DialogResult indicating the user action. + public DialogResult Show(IWin32Window owner, string name, string password, bool saveChecked) + { + if ((Environment.OSVersion.Version.Major < 5) || ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor < 1))) + { + throw new ApplicationException("The Credential Management API requires Windows XP / Windows Server 2003 or later."); + } + + Name = name; + Password = password; + SaveChecked = saveChecked; + + return ShowDialog(owner); + } + + /// Confirmation action to be applied. + /// True if the credentials should be persisted. + public void Confirm(bool value) + { + var confirmResult = CredUi.CredUIConfirmCredentials(Target, value); + switch (confirmResult) + { + case CredUi.ReturnCodes.NO_ERROR: + break; + case CredUi.ReturnCodes.ERROR_INVALID_PARAMETER: + // for some reason, this is encountered when credentials are overwritten + break; + default: + throw new ApplicationException($"Credential confirmation failed: {confirmResult}"); + } + } + + /// Returns a DialogResult indicating the user action. + /// The System.Windows.Forms.IWin32Window the dialog will display in front of. + /// + /// Sets the name, password and SaveChecked accessors to the state of the dialog as it was dismissed by the user. + /// + private DialogResult ShowDialog(IWin32Window owner) + { + // set the api call parameters + StringBuilder name = new StringBuilder(CredUi.MAX_USERNAME_LENGTH); + name.Append(Name); + + StringBuilder password = new StringBuilder(CredUi.MAX_PASSWORD_LENGTH); + password.Append(Password); + + int saveChecked = Convert.ToInt32(SaveChecked); + + CredUi.INFO info = GetInfo(owner); + CredUi.CredFlags credFlags = GetFlags(); + + // make the api call + CredUi.ReturnCodes code = CredUi.CredUIPromptForCredentials( + ref info, + Target, + IntPtr.Zero, 0, + name, CredUi.MAX_USERNAME_LENGTH, + password, CredUi.MAX_PASSWORD_LENGTH, + ref saveChecked, + credFlags + ); + + // clean up resources + if (Banner != null) + { + DeleteObject(info.hbmBanner); + } + + // set the accessors from the api call parameters + Name = name.ToString(); + Password = password.ToString(); + SaveChecked = Convert.ToBoolean(saveChecked); + + return GetDialogResult(code); + } + + /// Returns the info structure for dialog display settings. + /// The System.Windows.Forms.IWin32Window the dialog will display in front of. + private CredUi.INFO GetInfo(IWin32Window owner) + { + CredUi.INFO info = new CredUi.INFO(); + if (owner != null) info.hWndParent = owner.Handle; + info.pszCaptionText = Caption; + info.pszMessageText = Message; + if (Banner != null) + { + info.hbmBanner = new Bitmap(Banner, ValidBannerWidth, ValidBannerHeight).GetHbitmap(); + } + + info.cbSize = Marshal.SizeOf(info); + return info; + } + + /// Returns the flags for dialog display options. + private CredUi.CredFlags GetFlags() + { + CredUi.CredFlags credFlags = CredUi.CredFlags.GENERIC_CREDENTIALS; + + if (IncorrectPassword) + { + credFlags |= CredUi.CredFlags.INCORRECT_PASSWORD; + } + + if (AlwaysDisplay) + { + credFlags |= CredUi.CredFlags.ALWAYS_SHOW_UI; + } + + if (ExcludeCertificates) + { + credFlags |= CredUi.CredFlags.EXCLUDE_CERTIFICATES; + } + + if (Persist) + { + credFlags |= CredUi.CredFlags.EXPECT_CONFIRMATION; + if (SaveDisplayed) + { + credFlags |= CredUi.CredFlags.SHOW_SAVE_CHECK_BOX; + } + else + { + credFlags |= CredUi.CredFlags.PERSIST; + } + } + else + { + credFlags |= CredUi.CredFlags.DO_NOT_PERSIST; + } + + if (KeepName) + { + credFlags |= CredUi.CredFlags.KEEP_USERNAME; + } + + return credFlags; + } + + /// Returns a DialogResult from the specified code. + /// The credential return code. + private DialogResult GetDialogResult(CredUi.ReturnCodes code) => + code switch + { + CredUi.ReturnCodes.NO_ERROR => DialogResult.OK, + CredUi.ReturnCodes.ERROR_CANCELLED => DialogResult.Cancel, + CredUi.ReturnCodes.ERROR_NO_SUCH_LOGON_SESSION => throw new ApplicationException( + "No such logon session."), + CredUi.ReturnCodes.ERROR_NOT_FOUND => throw new ApplicationException("Not found."), + CredUi.ReturnCodes.ERROR_INVALID_ACCOUNT_NAME => + throw new ApplicationException("Invalid account name."), + CredUi.ReturnCodes.ERROR_INSUFFICIENT_BUFFER => throw new ApplicationException("Insufficient buffer."), + CredUi.ReturnCodes.ERROR_INVALID_PARAMETER => throw new ApplicationException("Invalid parameter."), + CredUi.ReturnCodes.ERROR_INVALID_FLAGS => throw new ApplicationException("Invalid flags."), + _ => throw new ApplicationException("Unknown credential result encountered.") + }; + } + + internal static class CredUi + { + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/authentication_constants.asp + public const int MAX_MESSAGE_LENGTH = 100; + + public const int MAX_CAPTION_LENGTH = 100; + public const int MAX_GENERIC_TARGET_LENGTH = 100; + public const int MAX_USERNAME_LENGTH = 100; + public const int MAX_PASSWORD_LENGTH = 100; + + /// + /// http://www.pinvoke.net/default.aspx/Enums.CREDUI_FLAGS + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/dpapiusercredentials.asp + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp + /// + [Flags] + public enum CredFlags + { + INCORRECT_PASSWORD = 0x1, + DO_NOT_PERSIST = 0x2, + EXCLUDE_CERTIFICATES = 0x8, + SHOW_SAVE_CHECK_BOX = 0x40, + ALWAYS_SHOW_UI = 0x80, + PERSIST = 0x1000, + EXPECT_CONFIRMATION = 0x20000, + GENERIC_CREDENTIALS = 0x40000, + KEEP_USERNAME = 0x100000, + } + + /// http://www.pinvoke.net/default.aspx/Enums.CredUIReturnCodes + public enum ReturnCodes + { + NO_ERROR = 0, + ERROR_INVALID_PARAMETER = 87, + ERROR_INSUFFICIENT_BUFFER = 122, + ERROR_INVALID_FLAGS = 1004, + ERROR_NOT_FOUND = 1168, + ERROR_CANCELLED = 1223, + ERROR_NO_SUCH_LOGON_SESSION = 1312, + ERROR_INVALID_ACCOUNT_NAME = 1315 + } + + /// + /// http://www.pinvoke.net/default.aspx/Structures.CREDUI_INFO + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/credui_info.asp + /// + public struct INFO + { + public int cbSize; + public IntPtr hWndParent; + [MarshalAs(UnmanagedType.LPWStr)] public string pszMessageText; + [MarshalAs(UnmanagedType.LPWStr)] public string pszCaptionText; + public IntPtr hbmBanner; + } + + /// + /// http://www.pinvoke.net/default.aspx/credui.CredUIPromptForCredentialsW + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp + /// + [DllImport("credui", CharSet = CharSet.Unicode)] + public static extern ReturnCodes CredUIPromptForCredentials( + ref INFO creditUR, + string targetName, + IntPtr reserved1, + int iError, + StringBuilder userName, + int maxUserName, + StringBuilder password, + int maxPassword, + ref int iSave, + CredFlags credFlags + ); + + /// + /// http://www.pinvoke.net/default.aspx/credui.CredUIConfirmCredentials + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduiconfirmcredentials.asp + /// + [DllImport("credui.dll", CharSet = CharSet.Unicode)] + public static extern ReturnCodes CredUIConfirmCredentials(string targetName, [MarshalAs(UnmanagedType.Bool)] bool confirm); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/DisplayKeyAttribute.cs b/src/Greenshot.Base/Core/DisplayKeyAttribute.cs similarity index 94% rename from src/GreenshotPlugin/Core/DisplayKeyAttribute.cs rename to src/Greenshot.Base/Core/DisplayKeyAttribute.cs index 1719e0092..39ac43b13 100644 --- a/src/GreenshotPlugin/Core/DisplayKeyAttribute.cs +++ b/src/Greenshot.Base/Core/DisplayKeyAttribute.cs @@ -1,40 +1,40 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.Core -{ - [AttributeUsage(AttributeTargets.Field)] - public sealed class DisplayKeyAttribute : Attribute - { - public string Value { get; } - - public DisplayKeyAttribute(string v) - { - Value = v; - } - - public DisplayKeyAttribute() - { - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Core +{ + [AttributeUsage(AttributeTargets.Field)] + public sealed class DisplayKeyAttribute : Attribute + { + public string Value { get; } + + public DisplayKeyAttribute(string v) + { + Value = v; + } + + public DisplayKeyAttribute() + { + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/DpiHelper.cs b/src/Greenshot.Base/Core/DpiHelper.cs similarity index 97% rename from src/GreenshotPlugin/Core/DpiHelper.cs rename to src/Greenshot.Base/Core/DpiHelper.cs index ec9ae8f41..bcb3314b6 100644 --- a/src/GreenshotPlugin/Core/DpiHelper.cs +++ b/src/Greenshot.Base/Core/DpiHelper.cs @@ -19,15 +19,15 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core.Enums; -using GreenshotPlugin.UnmanagedHelpers; using System; using System.Drawing; using System.Runtime.InteropServices; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; +using Greenshot.Base.Core.Enums; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// This handles DPI changes see diff --git a/src/GreenshotPlugin/Core/EffectConverter.cs b/src/Greenshot.Base/Core/EffectConverter.cs similarity index 96% rename from src/GreenshotPlugin/Core/EffectConverter.cs rename to src/Greenshot.Base/Core/EffectConverter.cs index 1b69dc3ed..40cb1f5ae 100644 --- a/src/GreenshotPlugin/Core/EffectConverter.cs +++ b/src/Greenshot.Base/Core/EffectConverter.cs @@ -1,233 +1,233 @@ -using System; -using System.ComponentModel; -using System.Drawing; -using System.Globalization; -using System.Text; -using GreenshotPlugin.Effects; - -namespace GreenshotPlugin.Core -{ - public class EffectConverter : TypeConverter - { - // Fix to prevent BUG-1753 - private readonly NumberFormatInfo _numberFormatInfo = new NumberFormatInfo(); - - public EffectConverter() - { - _numberFormatInfo.NumberDecimalSeparator = "."; - _numberFormatInfo.NumberGroupSeparator = ","; - } - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - if (sourceType == typeof(string)) - { - return true; - } - - return base.CanConvertFrom(context, sourceType); - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - if (destinationType == typeof(string)) - { - return true; - } - - if (destinationType == typeof(DropShadowEffect)) - { - return true; - } - - if (destinationType == typeof(TornEdgeEffect)) - { - return true; - } - - return base.CanConvertTo(context, destinationType); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - // to string - if (destinationType == typeof(string)) - { - StringBuilder sb = new StringBuilder(); - if (value.GetType() == typeof(DropShadowEffect)) - { - DropShadowEffect effect = value as DropShadowEffect; - RetrieveDropShadowEffectValues(effect, sb); - return sb.ToString(); - } - - if (value.GetType() == typeof(TornEdgeEffect)) - { - TornEdgeEffect effect = value as TornEdgeEffect; - RetrieveDropShadowEffectValues(effect, sb); - sb.Append("|"); - RetrieveTornEdgeEffectValues(effect, sb); - return sb.ToString(); - } - } - - // from string - if (value is string) - { - string settings = value as string; - if (destinationType == typeof(DropShadowEffect)) - { - DropShadowEffect effect = new DropShadowEffect(); - ApplyDropShadowEffectValues(settings, effect); - return effect; - } - - if (destinationType == typeof(TornEdgeEffect)) - { - TornEdgeEffect effect = new TornEdgeEffect(); - ApplyDropShadowEffectValues(settings, effect); - ApplyTornEdgeEffectValues(settings, effect); - return effect; - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value is string settings) - { - if (settings.Contains("ToothHeight")) - { - return ConvertTo(context, culture, settings, typeof(TornEdgeEffect)); - } - - return ConvertTo(context, culture, settings, typeof(DropShadowEffect)); - } - - return base.ConvertFrom(context, culture, value); - } - - private void ApplyDropShadowEffectValues(string valuesString, DropShadowEffect effect) - { - string[] values = valuesString.Split('|'); - foreach (string nameValuePair in values) - { - string[] pair = nameValuePair.Split(':'); - switch (pair[0]) - { - case "Darkness": - // Fix to prevent BUG-1753 - if (pair[1] != null && float.TryParse(pair[1], NumberStyles.Float, _numberFormatInfo, out var darkness)) - { - if (darkness <= 1.0) - { - effect.Darkness = darkness; - } - } - - break; - case "ShadowSize": - if (int.TryParse(pair[1], out var shadowSize)) - { - effect.ShadowSize = shadowSize; - } - - break; - case "ShadowOffset": - Point shadowOffset = new Point(); - string[] coordinates = pair[1].Split(','); - if (int.TryParse(coordinates[0], out var shadowOffsetX)) - { - shadowOffset.X = shadowOffsetX; - } - - if (int.TryParse(coordinates[1], out var shadowOffsetY)) - { - shadowOffset.Y = shadowOffsetY; - } - - effect.ShadowOffset = shadowOffset; - break; - } - } - } - - private void ApplyTornEdgeEffectValues(string valuesString, TornEdgeEffect effect) - { - string[] values = valuesString.Split('|'); - foreach (string nameValuePair in values) - { - string[] pair = nameValuePair.Split(':'); - switch (pair[0]) - { - case "GenerateShadow": - if (bool.TryParse(pair[1], out var generateShadow)) - { - effect.GenerateShadow = generateShadow; - } - - break; - case "ToothHeight": - if (int.TryParse(pair[1], out var toothHeight)) - { - effect.ToothHeight = toothHeight; - } - - break; - case "HorizontalToothRange": - if (int.TryParse(pair[1], out var horizontalToothRange)) - { - effect.HorizontalToothRange = horizontalToothRange; - } - - break; - case "VerticalToothRange": - if (int.TryParse(pair[1], out var verticalToothRange)) - { - effect.VerticalToothRange = verticalToothRange; - } - - break; - case "Edges": - string[] edges = pair[1].Split(','); - if (bool.TryParse(edges[0], out var edge)) - { - effect.Edges[0] = edge; - } - - if (bool.TryParse(edges[1], out edge)) - { - effect.Edges[1] = edge; - } - - if (bool.TryParse(edges[2], out edge)) - { - effect.Edges[2] = edge; - } - - if (bool.TryParse(edges[3], out edge)) - { - effect.Edges[3] = edge; - } - - break; - } - } - } - - private void RetrieveDropShadowEffectValues(DropShadowEffect effect, StringBuilder sb) - { - // Fix to prevent BUG-1753 is to use the numberFormatInfo - sb.AppendFormat("Darkness:{0}|ShadowSize:{1}|ShadowOffset:{2},{3}", effect.Darkness.ToString("F2", _numberFormatInfo), effect.ShadowSize, effect.ShadowOffset.X, - effect.ShadowOffset.Y); - } - - private void RetrieveTornEdgeEffectValues(TornEdgeEffect effect, StringBuilder sb) - { - sb.AppendFormat("GenerateShadow:{0}|ToothHeight:{1}|HorizontalToothRange:{2}|VerticalToothRange:{3}|Edges:{4},{5},{6},{7}", effect.GenerateShadow, effect.ToothHeight, - effect.HorizontalToothRange, effect.VerticalToothRange, effect.Edges[0], effect.Edges[1], effect.Edges[2], effect.Edges[3]); - } - } +using System; +using System.ComponentModel; +using System.Drawing; +using System.Globalization; +using System.Text; +using Greenshot.Base.Effects; + +namespace Greenshot.Base.Core +{ + public class EffectConverter : TypeConverter + { + // Fix to prevent BUG-1753 + private readonly NumberFormatInfo _numberFormatInfo = new NumberFormatInfo(); + + public EffectConverter() + { + _numberFormatInfo.NumberDecimalSeparator = "."; + _numberFormatInfo.NumberGroupSeparator = ","; + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + + return base.CanConvertFrom(context, sourceType); + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + { + return true; + } + + if (destinationType == typeof(DropShadowEffect)) + { + return true; + } + + if (destinationType == typeof(TornEdgeEffect)) + { + return true; + } + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + // to string + if (destinationType == typeof(string)) + { + StringBuilder sb = new StringBuilder(); + if (value.GetType() == typeof(DropShadowEffect)) + { + DropShadowEffect effect = value as DropShadowEffect; + RetrieveDropShadowEffectValues(effect, sb); + return sb.ToString(); + } + + if (value.GetType() == typeof(TornEdgeEffect)) + { + TornEdgeEffect effect = value as TornEdgeEffect; + RetrieveDropShadowEffectValues(effect, sb); + sb.Append("|"); + RetrieveTornEdgeEffectValues(effect, sb); + return sb.ToString(); + } + } + + // from string + if (value is string) + { + string settings = value as string; + if (destinationType == typeof(DropShadowEffect)) + { + DropShadowEffect effect = new DropShadowEffect(); + ApplyDropShadowEffectValues(settings, effect); + return effect; + } + + if (destinationType == typeof(TornEdgeEffect)) + { + TornEdgeEffect effect = new TornEdgeEffect(); + ApplyDropShadowEffectValues(settings, effect); + ApplyTornEdgeEffectValues(settings, effect); + return effect; + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string settings) + { + if (settings.Contains("ToothHeight")) + { + return ConvertTo(context, culture, settings, typeof(TornEdgeEffect)); + } + + return ConvertTo(context, culture, settings, typeof(DropShadowEffect)); + } + + return base.ConvertFrom(context, culture, value); + } + + private void ApplyDropShadowEffectValues(string valuesString, DropShadowEffect effect) + { + string[] values = valuesString.Split('|'); + foreach (string nameValuePair in values) + { + string[] pair = nameValuePair.Split(':'); + switch (pair[0]) + { + case "Darkness": + // Fix to prevent BUG-1753 + if (pair[1] != null && float.TryParse(pair[1], NumberStyles.Float, _numberFormatInfo, out var darkness)) + { + if (darkness <= 1.0) + { + effect.Darkness = darkness; + } + } + + break; + case "ShadowSize": + if (int.TryParse(pair[1], out var shadowSize)) + { + effect.ShadowSize = shadowSize; + } + + break; + case "ShadowOffset": + Point shadowOffset = new Point(); + string[] coordinates = pair[1].Split(','); + if (int.TryParse(coordinates[0], out var shadowOffsetX)) + { + shadowOffset.X = shadowOffsetX; + } + + if (int.TryParse(coordinates[1], out var shadowOffsetY)) + { + shadowOffset.Y = shadowOffsetY; + } + + effect.ShadowOffset = shadowOffset; + break; + } + } + } + + private void ApplyTornEdgeEffectValues(string valuesString, TornEdgeEffect effect) + { + string[] values = valuesString.Split('|'); + foreach (string nameValuePair in values) + { + string[] pair = nameValuePair.Split(':'); + switch (pair[0]) + { + case "GenerateShadow": + if (bool.TryParse(pair[1], out var generateShadow)) + { + effect.GenerateShadow = generateShadow; + } + + break; + case "ToothHeight": + if (int.TryParse(pair[1], out var toothHeight)) + { + effect.ToothHeight = toothHeight; + } + + break; + case "HorizontalToothRange": + if (int.TryParse(pair[1], out var horizontalToothRange)) + { + effect.HorizontalToothRange = horizontalToothRange; + } + + break; + case "VerticalToothRange": + if (int.TryParse(pair[1], out var verticalToothRange)) + { + effect.VerticalToothRange = verticalToothRange; + } + + break; + case "Edges": + string[] edges = pair[1].Split(','); + if (bool.TryParse(edges[0], out var edge)) + { + effect.Edges[0] = edge; + } + + if (bool.TryParse(edges[1], out edge)) + { + effect.Edges[1] = edge; + } + + if (bool.TryParse(edges[2], out edge)) + { + effect.Edges[2] = edge; + } + + if (bool.TryParse(edges[3], out edge)) + { + effect.Edges[3] = edge; + } + + break; + } + } + } + + private void RetrieveDropShadowEffectValues(DropShadowEffect effect, StringBuilder sb) + { + // Fix to prevent BUG-1753 is to use the numberFormatInfo + sb.AppendFormat("Darkness:{0}|ShadowSize:{1}|ShadowOffset:{2},{3}", effect.Darkness.ToString("F2", _numberFormatInfo), effect.ShadowSize, effect.ShadowOffset.X, + effect.ShadowOffset.Y); + } + + private void RetrieveTornEdgeEffectValues(TornEdgeEffect effect, StringBuilder sb) + { + sb.AppendFormat("GenerateShadow:{0}|ToothHeight:{1}|HorizontalToothRange:{2}|VerticalToothRange:{3}|Edges:{4},{5},{6},{7}", effect.GenerateShadow, effect.ToothHeight, + effect.HorizontalToothRange, effect.VerticalToothRange, effect.Edges[0], effect.Edges[1], effect.Edges[2], effect.Edges[3]); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Enums/HResult.cs b/src/Greenshot.Base/Core/Enums/HResult.cs similarity index 97% rename from src/GreenshotPlugin/Core/Enums/HResult.cs rename to src/Greenshot.Base/Core/Enums/HResult.cs index 96e867c6c..e278162f9 100644 --- a/src/GreenshotPlugin/Core/Enums/HResult.cs +++ b/src/Greenshot.Base/Core/Enums/HResult.cs @@ -19,7 +19,7 @@ using System.Diagnostics.CodeAnalysis; -namespace GreenshotPlugin.Core.Enums +namespace Greenshot.Base.Core.Enums { /// /// The HRESULT represents Windows error codes diff --git a/src/GreenshotPlugin/Core/Enums/MonitorDpiType.cs b/src/Greenshot.Base/Core/Enums/MonitorDpiType.cs similarity index 97% rename from src/GreenshotPlugin/Core/Enums/MonitorDpiType.cs rename to src/Greenshot.Base/Core/Enums/MonitorDpiType.cs index c1db8ce18..e434f5bb3 100644 --- a/src/GreenshotPlugin/Core/Enums/MonitorDpiType.cs +++ b/src/Greenshot.Base/Core/Enums/MonitorDpiType.cs @@ -3,7 +3,7 @@ using System; -namespace GreenshotPlugin.Core.Enums +namespace Greenshot.Base.Core.Enums { /// /// See diff --git a/src/GreenshotPlugin/Core/Enums/MonitorFrom.cs b/src/Greenshot.Base/Core/Enums/MonitorFrom.cs similarity index 96% rename from src/GreenshotPlugin/Core/Enums/MonitorFrom.cs rename to src/Greenshot.Base/Core/Enums/MonitorFrom.cs index 40f25961b..f9d9fcc2b 100644 --- a/src/GreenshotPlugin/Core/Enums/MonitorFrom.cs +++ b/src/Greenshot.Base/Core/Enums/MonitorFrom.cs @@ -3,7 +3,7 @@ using System; -namespace GreenshotPlugin.Core.Enums +namespace Greenshot.Base.Core.Enums { /// /// Flags for the MonitorFromRect / MonitorFromWindow "flags" field diff --git a/src/GreenshotPlugin/Core/EnvironmentInfo.cs b/src/Greenshot.Base/Core/EnvironmentInfo.cs similarity index 99% rename from src/GreenshotPlugin/Core/EnvironmentInfo.cs rename to src/Greenshot.Base/Core/EnvironmentInfo.cs index 27a3eeda1..9c23cd2df 100644 --- a/src/GreenshotPlugin/Core/EnvironmentInfo.cs +++ b/src/Greenshot.Base/Core/EnvironmentInfo.cs @@ -23,11 +23,11 @@ using System; using System.Reflection; using System.Runtime.InteropServices; using System.Text; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.UnmanagedHelpers; +using Greenshot.Base.IniFile; +using Greenshot.Base.UnmanagedHelpers; using Microsoft.Win32; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// Description of EnvironmentInfo. diff --git a/src/GreenshotPlugin/Core/EventDelay.cs b/src/Greenshot.Base/Core/EventDelay.cs similarity index 97% rename from src/GreenshotPlugin/Core/EventDelay.cs rename to src/Greenshot.Base/Core/EventDelay.cs index 1c6ec235c..c1a41a1be 100644 --- a/src/GreenshotPlugin/Core/EventDelay.cs +++ b/src/Greenshot.Base/Core/EventDelay.cs @@ -21,7 +21,7 @@ using System; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { public class EventDelay { diff --git a/src/GreenshotPlugin/Core/ExplorerHelper.cs b/src/Greenshot.Base/Core/ExplorerHelper.cs similarity index 94% rename from src/GreenshotPlugin/Core/ExplorerHelper.cs rename to src/Greenshot.Base/Core/ExplorerHelper.cs index 934d0ed74..0ebb88db3 100644 --- a/src/GreenshotPlugin/Core/ExplorerHelper.cs +++ b/src/Greenshot.Base/Core/ExplorerHelper.cs @@ -1,55 +1,55 @@ -using System; -using System.Diagnostics; -using System.IO; - -namespace GreenshotPlugin.Core -{ - /// - /// Simple utility for the explorer - /// - public static class ExplorerHelper - { - /// - /// Open the path in the windows explorer. - /// If the path is a directory, it will just open the explorer with that directory. - /// If the path is a file, the explorer is opened with the directory and the file is selected. - /// - /// Path to file or directory - public static bool OpenInExplorer(string path) - { - if (path == null) - { - return false; - } - - try - { - // Check if path is a directory - if (Directory.Exists(path)) - { - using (Process.Start(path)) - { - return true; - } - } - - // Check if path is a file - if (File.Exists(path)) - { - // Start the explorer process and select the file - using var explorer = Process.Start("explorer.exe", $"/select,\"{path}\""); - explorer?.WaitForInputIdle(500); - return true; - } - } - catch (Exception ex) - { - // Make sure we show what we tried to open in the exception - ex.Data.Add("path", path); - throw; - } - - return false; - } - } +using System; +using System.Diagnostics; +using System.IO; + +namespace Greenshot.Base.Core +{ + /// + /// Simple utility for the explorer + /// + public static class ExplorerHelper + { + /// + /// Open the path in the windows explorer. + /// If the path is a directory, it will just open the explorer with that directory. + /// If the path is a file, the explorer is opened with the directory and the file is selected. + /// + /// Path to file or directory + public static bool OpenInExplorer(string path) + { + if (path == null) + { + return false; + } + + try + { + // Check if path is a directory + if (Directory.Exists(path)) + { + using (Process.Start(path)) + { + return true; + } + } + + // Check if path is a file + if (File.Exists(path)) + { + // Start the explorer process and select the file + using var explorer = Process.Start("explorer.exe", $"/select,\"{path}\""); + explorer?.WaitForInputIdle(500); + return true; + } + } + catch (Exception ex) + { + // Make sure we show what we tried to open in the exception + ex.Data.Add("path", path); + throw; + } + + return false; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/FastBitmap.cs b/src/Greenshot.Base/Core/FastBitmap.cs similarity index 97% rename from src/GreenshotPlugin/Core/FastBitmap.cs rename to src/Greenshot.Base/Core/FastBitmap.cs index 2ef28af93..3b6685dd0 100644 --- a/src/GreenshotPlugin/Core/FastBitmap.cs +++ b/src/Greenshot.Base/Core/FastBitmap.cs @@ -1,1055 +1,1055 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; - -namespace GreenshotPlugin.Core -{ - /// - /// The interface for the FastBitmap - /// - public interface IFastBitmap : IDisposable - { - /// - /// Get the color at x,y - /// The returned Color object depends on the underlying pixel format - /// - /// int x - /// int y - /// Color - Color GetColorAt(int x, int y); - - /// - /// Set the color at the specified location - /// - /// int x - /// int y - /// Color - void SetColorAt(int x, int y, Color color); - - /// - /// Get the color at x,y - /// The returned byte[] color depends on the underlying pixel format - /// - /// int x - /// int y - /// byte array - void GetColorAt(int x, int y, byte[] color); - - /// - /// Set the color at the specified location - /// - /// int x - /// int y - /// byte[] color - void SetColorAt(int x, int y, byte[] color); - - /// - /// Lock the bitmap - /// - void Lock(); - - /// - /// Unlock the bitmap - /// - void Unlock(); - - /// - /// Unlock the bitmap and get the underlying bitmap in one call - /// - /// - Bitmap UnlockAndReturnBitmap(); - - /// - /// Size of the underlying image - /// - Size Size { get; } - - /// - /// Height of the image area that this fastbitmap covers - /// - int Height { get; } - - /// - /// Width of the image area that this fastbitmap covers - /// - int Width { get; } - - /// - /// Top of the image area that this fastbitmap covers - /// - int Top { get; } - - /// - /// Left of the image area that this fastbitmap covers - /// - int Left { get; } - - /// - /// Right of the image area that this fastbitmap covers - /// - int Right { get; } - - /// - /// Bottom of the image area that this fastbitmap covers - /// - int Bottom { get; } - - /// - /// Does the underlying image need to be disposed - /// - bool NeedsDispose { get; set; } - - /// - /// Returns if this FastBitmap has an alpha channel - /// - bool HasAlphaChannel { get; } - - /// - /// Draw the stored bitmap to the destionation bitmap at the supplied point - /// - /// Graphics - /// Point with location - void DrawTo(Graphics graphics, Point destination); - - /// - /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle - /// Be aware that the stored bitmap will be resized to the specified rectangle!! - /// - /// Graphics - /// Rectangle with destination - void DrawTo(Graphics graphics, Rectangle destinationRect); - - /// - /// Return true if the coordinates are inside the FastBitmap - /// - /// - /// - /// - bool Contains(int x, int y); - - /// - /// Set the bitmap resolution - /// - /// - /// - void SetResolution(float horizontal, float vertical); - } - - /// - /// This interface can be used for when offsetting is needed - /// - public interface IFastBitmapWithOffset : IFastBitmap - { - /// - /// Return true if the coordinates are inside the FastBitmap - /// - /// - /// - /// - new bool Contains(int x, int y); - - /// - /// Set the color at the specified location, using offsetting so the original coordinates can be used - /// - /// int x - /// int y - /// Color color - new void SetColorAt(int x, int y, Color color); - - /// - /// Set the color at the specified location, using offsetting so the original coordinates can be used - /// - /// int x - /// int y - /// byte[] color - new void SetColorAt(int x, int y, byte[] color); - - /// - /// Get the color at x,y - /// The returned Color object depends on the underlying pixel format - /// - /// int x - /// int y - /// Color - new Color GetColorAt(int x, int y); - - /// - /// Get the color at x,y, using offsetting so the original coordinates can be used - /// The returned byte[] color depends on the underlying pixel format - /// - /// int x - /// int y - /// byte array - new void GetColorAt(int x, int y, byte[] color); - - new int Left { get; set; } - - new int Top { get; set; } - } - - /// - /// This interface can be used for when clipping is needed - /// - public interface IFastBitmapWithClip : IFastBitmap - { - Rectangle Clip { get; set; } - - bool InvertClip { get; set; } - - /// - /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping - /// - /// int x - /// int y - /// Color color - new void SetColorAt(int x, int y, Color color); - - /// - /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping - /// - /// int x - /// int y - /// byte[] color - new void SetColorAt(int x, int y, byte[] color); - - /// - /// Return true if the coordinates are inside the FastBitmap and not clipped - /// - /// - /// - /// - new bool Contains(int x, int y); - } - - /// - /// This interface is implemented when there is a alpha-blending possibility - /// - public interface IFastBitmapWithBlend : IFastBitmap - { - Color BackgroundBlendColor { get; set; } - Color GetBlendedColorAt(int x, int y); - } - - /// - /// The base class for the fast bitmap implementation - /// - public abstract unsafe class FastBitmap : IFastBitmapWithClip, IFastBitmapWithOffset - { - protected const int PixelformatIndexA = 3; - protected const int PixelformatIndexR = 2; - protected const int PixelformatIndexG = 1; - protected const int PixelformatIndexB = 0; - - public const int ColorIndexR = 0; - public const int ColorIndexG = 1; - public const int ColorIndexB = 2; - public const int ColorIndexA = 3; - - protected Rectangle Area; - - /// - /// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap - /// - public bool NeedsDispose { get; set; } - - public Rectangle Clip { get; set; } - - public bool InvertClip { get; set; } - - /// - /// The bitmap for which the FastBitmap is creating access - /// - protected Bitmap Bitmap; - - protected BitmapData BmData; - protected int Stride; /* bytes per pixel row */ - protected bool BitsLocked; - protected byte* Pointer; - - public static IFastBitmap Create(Bitmap source) - { - return Create(source, Rectangle.Empty); - } - - public void SetResolution(float horizontal, float vertical) - { - Bitmap.SetResolution(horizontal, vertical); - } - - /// - /// Factory for creating a FastBitmap depending on the pixelformat of the source - /// The supplied rectangle specifies the area for which the FastBitmap does its thing - /// - /// Bitmap to access - /// Rectangle which specifies the area to have access to, can be Rectangle.Empty for the whole image - /// IFastBitmap - public static IFastBitmap Create(Bitmap source, Rectangle area) - { - switch (source.PixelFormat) - { - case PixelFormat.Format8bppIndexed: - return new FastChunkyBitmap(source, area); - case PixelFormat.Format24bppRgb: - return new Fast24RgbBitmap(source, area); - case PixelFormat.Format32bppRgb: - return new Fast32RgbBitmap(source, area); - case PixelFormat.Format32bppArgb: - case PixelFormat.Format32bppPArgb: - return new Fast32ArgbBitmap(source, area); - default: - throw new NotSupportedException($"Not supported Pixelformat {source.PixelFormat}"); - } - } - - /// - /// Factory for creating a FastBitmap as a destination for the source - /// - /// Bitmap to clone - /// new Pixelformat - /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat) - { - return CreateCloneOf(source, pixelFormat, Rectangle.Empty); - } - - /// - /// Factory for creating a FastBitmap as a destination for the source - /// - /// Bitmap to clone - /// Area of the bitmap to access, can be Rectangle.Empty for the whole - /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, Rectangle area) - { - return CreateCloneOf(source, PixelFormat.DontCare, area); - } - - /// - /// Factory for creating a FastBitmap as a destination for the source - /// - /// Bitmap to clone - /// Pixelformat of the cloned bitmap - /// Area of the bitmap to access, can be Rectangle.Empty for the whole - /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) - { - Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat); - FastBitmap fastBitmap = Create(destination) as FastBitmap; - if (fastBitmap != null) - { - fastBitmap.NeedsDispose = true; - fastBitmap.Left = area.Left; - fastBitmap.Top = area.Top; - } - - return fastBitmap; - } - - /// - /// Factory for creating a FastBitmap as a destination - /// - /// - /// - /// - /// IFastBitmap - public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat, Color backgroundColor) - { - Bitmap destination = ImageHelper.CreateEmpty(newSize.Width, newSize.Height, pixelFormat, backgroundColor, 96f, 96f); - IFastBitmap fastBitmap = Create(destination); - fastBitmap.NeedsDispose = true; - return fastBitmap; - } - - /// - /// Constructor which stores the image and locks it when called - /// - /// Bitmap - /// Rectangle - protected FastBitmap(Bitmap bitmap, Rectangle area) - { - Bitmap = bitmap; - Rectangle bitmapArea = new Rectangle(Point.Empty, bitmap.Size); - if (area != Rectangle.Empty) - { - area.Intersect(bitmapArea); - Area = area; - } - else - { - Area = bitmapArea; - } - - // As the lock takes care that only the specified area is made available we need to calculate the offset - Left = area.Left; - Top = area.Top; - // Default cliping is done to the area without invert - Clip = Area; - InvertClip = false; - // Always lock, so we don't need to do this ourselves - Lock(); - } - - /// - /// Return the size of the image - /// - public Size Size - { - get - { - if (Area == Rectangle.Empty) - { - return Bitmap.Size; - } - - return Area.Size; - } - } - - /// - /// Return the width of the image - /// - public int Width - { - get - { - if (Area == Rectangle.Empty) - { - return Bitmap.Width; - } - - return Area.Width; - } - } - - /// - /// Return the height of the image - /// - public int Height - { - get - { - if (Area == Rectangle.Empty) - { - return Bitmap.Height; - } - - return Area.Height; - } - } - - private int _left; - - /// - /// Return the left of the fastbitmap, this is also used as an offset - /// - public int Left - { - get { return 0; } - set { _left = value; } - } - - /// - /// Return the left of the fastbitmap, this is also used as an offset - /// - int IFastBitmapWithOffset.Left - { - get { return _left; } - set { _left = value; } - } - - private int _top; - - /// - /// Return the top of the fastbitmap, this is also used as an offset - /// - public int Top - { - get { return 0; } - set { _top = value; } - } - - /// - /// Return the top of the fastbitmap, this is also used as an offset - /// - int IFastBitmapWithOffset.Top - { - get { return _top; } - set { _top = value; } - } - - /// - /// Return the right of the fastbitmap - /// - public int Right => Left + Width; - - /// - /// Return the bottom of the fastbitmap - /// - public int Bottom => Top + Height; - - /// - /// Returns the underlying bitmap, unlocks it and prevents that it will be disposed - /// - public Bitmap UnlockAndReturnBitmap() - { - if (BitsLocked) - { - Unlock(); - } - - NeedsDispose = false; - return Bitmap; - } - - public virtual bool HasAlphaChannel => false; - - /// - /// Destructor - /// - ~FastBitmap() - { - Dispose(false); - } - - /// - /// The public accessible Dispose - /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - // The bulk of the clean-up code is implemented in Dispose(bool) - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected virtual void Dispose(bool disposing) - { - Unlock(); - if (disposing) - { - if (Bitmap != null && NeedsDispose) - { - Bitmap.Dispose(); - } - } - - Bitmap = null; - BmData = null; - Pointer = null; - } - - /// - /// Lock the bitmap so we have direct access to the memory - /// - public void Lock() - { - if (Width <= 0 || Height <= 0 || BitsLocked) - { - return; - } - - BmData = Bitmap.LockBits(Area, ImageLockMode.ReadWrite, Bitmap.PixelFormat); - BitsLocked = true; - - IntPtr scan0 = BmData.Scan0; - Pointer = (byte*) (void*) scan0; - Stride = BmData.Stride; - } - - /// - /// Unlock the System Memory - /// - public void Unlock() - { - if (BitsLocked) - { - Bitmap.UnlockBits(BmData); - BitsLocked = false; - } - } - - /// - /// Draw the stored bitmap to the destionation bitmap at the supplied point - /// - /// - /// - public void DrawTo(Graphics graphics, Point destination) - { - DrawTo(graphics, new Rectangle(destination, Area.Size)); - } - - /// - /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle - /// Be aware that the stored bitmap will be resized to the specified rectangle!! - /// - /// - /// - public void DrawTo(Graphics graphics, Rectangle destinationRect) - { - // Make sure this.bitmap is unlocked, if it was locked - bool isLocked = BitsLocked; - if (isLocked) - { - Unlock(); - } - - graphics.DrawImage(Bitmap, destinationRect, Area, GraphicsUnit.Pixel); - } - - /// - /// returns true if x & y are inside the FastBitmap - /// - /// - /// - /// true if x & y are inside the FastBitmap - public bool Contains(int x, int y) - { - return Area.Contains(x - Left, y - Top); - } - - public abstract Color GetColorAt(int x, int y); - public abstract void SetColorAt(int x, int y, Color color); - public abstract void GetColorAt(int x, int y, byte[] color); - public abstract void SetColorAt(int x, int y, byte[] color); - - bool IFastBitmapWithClip.Contains(int x, int y) - { - bool contains = Clip.Contains(x, y); - if (InvertClip) - { - return !contains; - } - else - { - return contains; - } - } - - void IFastBitmapWithClip.SetColorAt(int x, int y, byte[] color) - { - bool contains = Clip.Contains(x, y); - if ((InvertClip && contains) || (!InvertClip && !contains)) - { - return; - } - - SetColorAt(x, y, color); - } - - void IFastBitmapWithClip.SetColorAt(int x, int y, Color color) - { - bool contains = Clip.Contains(x, y); - if ((InvertClip && contains) || (!InvertClip && !contains)) - { - return; - } - - SetColorAt(x, y, color); - } - - /// - /// returns true if x & y are inside the FastBitmap - /// - /// - /// - /// true if x & y are inside the FastBitmap - bool IFastBitmapWithOffset.Contains(int x, int y) - { - return Area.Contains(x - Left, y - Top); - } - - Color IFastBitmapWithOffset.GetColorAt(int x, int y) - { - x -= _left; - y -= _top; - return GetColorAt(x, y); - } - - void IFastBitmapWithOffset.GetColorAt(int x, int y, byte[] color) - { - x -= _left; - y -= _top; - GetColorAt(x, y, color); - } - - void IFastBitmapWithOffset.SetColorAt(int x, int y, byte[] color) - { - x -= _left; - y -= _top; - SetColorAt(x, y, color); - } - - void IFastBitmapWithOffset.SetColorAt(int x, int y, Color color) - { - x -= _left; - y -= _top; - SetColorAt(x, y, color); - } - } - - /// - /// This is the implementation of the FastBitmat for the 8BPP pixelformat - /// - public unsafe class FastChunkyBitmap : FastBitmap - { - // Used for indexed images - private readonly Color[] _colorEntries; - private readonly Dictionary _colorCache = new Dictionary(); - - public FastChunkyBitmap(Bitmap source, Rectangle area) : base(source, area) - { - _colorEntries = Bitmap.Palette.Entries; - } - - /// - /// Get the color from the specified location - /// - /// - /// - /// Color - public override Color GetColorAt(int x, int y) - { - int offset = x + (y * Stride); - byte colorIndex = Pointer[offset]; - return _colorEntries[colorIndex]; - } - - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference - public override void GetColorAt(int x, int y, byte[] color) - { - throw new NotImplementedException("No performance gain!"); - } - - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference - public override void SetColorAt(int x, int y, byte[] color) - { - throw new NotImplementedException("No performance gain!"); - } - - /// - /// Get the color-index from the specified location - /// - /// - /// - /// byte with index - public byte GetColorIndexAt(int x, int y) - { - int offset = x + (y * Stride); - return Pointer[offset]; - } - - /// - /// Set the color-index at the specified location - /// - /// - /// - /// - public void SetColorIndexAt(int x, int y, byte colorIndex) - { - int offset = x + (y * Stride); - Pointer[offset] = colorIndex; - } - - /// - /// Set the supplied color at the specified location. - /// Throws an ArgumentException if the color is not in the palette - /// - /// - /// - /// Color to set - public override void SetColorAt(int x, int y, Color color) - { - int offset = x + (y * Stride); - if (!_colorCache.TryGetValue(color, out var colorIndex)) - { - bool foundColor = false; - for (colorIndex = 0; colorIndex < _colorEntries.Length; colorIndex++) - { - if (color == _colorEntries[colorIndex]) - { - _colorCache.Add(color, colorIndex); - foundColor = true; - break; - } - } - - if (!foundColor) - { - throw new ArgumentException("No such color!"); - } - } - - Pointer[offset] = colorIndex; - } - } - - /// - /// This is the implementation of the IFastBitmap for 24 bit images (no Alpha) - /// - public unsafe class Fast24RgbBitmap : FastBitmap - { - public Fast24RgbBitmap(Bitmap source, Rectangle area) : base(source, area) - { - } - - /// - /// Retrieve the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public override Color GetColorAt(int x, int y) - { - int offset = (x * 3) + (y * Stride); - return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); - } - - /// - /// Set the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public override void SetColorAt(int x, int y, Color color) - { - int offset = (x * 3) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color.R; - Pointer[PixelformatIndexG + offset] = color.G; - Pointer[PixelformatIndexB + offset] = color.B; - } - - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b) - public override void GetColorAt(int x, int y, byte[] color) - { - int offset = (x * 3) + (y * Stride); - color[PixelformatIndexR] = Pointer[PixelformatIndexR + offset]; - color[PixelformatIndexG] = Pointer[PixelformatIndexG + offset]; - color[PixelformatIndexB] = Pointer[PixelformatIndexB + offset]; - } - - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b) - public override void SetColorAt(int x, int y, byte[] color) - { - int offset = (x * 3) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color[PixelformatIndexR]; - Pointer[PixelformatIndexG + offset] = color[PixelformatIndexG]; - Pointer[PixelformatIndexB + offset] = color[PixelformatIndexB]; - } - } - - /// - /// This is the implementation of the IFastBitmap for 32 bit images (no Alpha) - /// - public unsafe class Fast32RgbBitmap : FastBitmap - { - public Fast32RgbBitmap(Bitmap source, Rectangle area) : base(source, area) - { - } - - /// - /// Retrieve the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public override Color GetColorAt(int x, int y) - { - int offset = (x * 4) + (y * Stride); - return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); - } - - /// - /// Set the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public override void SetColorAt(int x, int y, Color color) - { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color.R; - Pointer[PixelformatIndexG + offset] = color.G; - Pointer[PixelformatIndexB + offset] = color.B; - } - - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference (a,r,g,b) - public override void GetColorAt(int x, int y, byte[] color) - { - int offset = (x * 4) + (y * Stride); - color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; - color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; - color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; - } - - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b) - public override void SetColorAt(int x, int y, byte[] color) - { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R - Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; - Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; - } - } - - /// - /// This is the implementation of the IFastBitmap for 32 bit images with Alpha - /// - public unsafe class Fast32ArgbBitmap : FastBitmap, IFastBitmapWithBlend - { - public override bool HasAlphaChannel => true; - - public Color BackgroundBlendColor { get; set; } - - public Fast32ArgbBitmap(Bitmap source, Rectangle area) : base(source, area) - { - BackgroundBlendColor = Color.White; - } - - /// - /// Retrieve the color at location x,y - /// - /// X coordinate - /// Y Coordinate - /// Color - public override Color GetColorAt(int x, int y) - { - int offset = (x * 4) + (y * Stride); - return Color.FromArgb(Pointer[PixelformatIndexA + offset], Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], - Pointer[PixelformatIndexB + offset]); - } - - /// - /// Set the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public override void SetColorAt(int x, int y, Color color) - { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexA + offset] = color.A; - Pointer[PixelformatIndexR + offset] = color.R; - Pointer[PixelformatIndexG + offset] = color.G; - Pointer[PixelformatIndexB + offset] = color.B; - } - - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b,a) - public override void GetColorAt(int x, int y, byte[] color) - { - int offset = (x * 4) + (y * Stride); - color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; - color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; - color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; - color[ColorIndexA] = Pointer[PixelformatIndexA + offset]; - } - - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b,a) - public override void SetColorAt(int x, int y, byte[] color) - { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R - Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; - Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; - Pointer[PixelformatIndexA + offset] = color[ColorIndexA]; - } - - /// - /// Retrieve the color, without alpha (is blended), at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public Color GetBlendedColorAt(int x, int y) - { - int offset = (x * 4) + (y * Stride); - int a = Pointer[PixelformatIndexA + offset]; - int red = Pointer[PixelformatIndexR + offset]; - int green = Pointer[PixelformatIndexG + offset]; - int blue = Pointer[PixelformatIndexB + offset]; - - if (a < 255) - { - // As the request is to get without alpha, we blend. - int rem = 255 - a; - red = (red * a + BackgroundBlendColor.R * rem) / 255; - green = (green * a + BackgroundBlendColor.G * rem) / 255; - blue = (blue * a + BackgroundBlendColor.B * rem) / 255; - } - - return Color.FromArgb(255, red, green, blue); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; + +namespace Greenshot.Base.Core +{ + /// + /// The interface for the FastBitmap + /// + public interface IFastBitmap : IDisposable + { + /// + /// Get the color at x,y + /// The returned Color object depends on the underlying pixel format + /// + /// int x + /// int y + /// Color + Color GetColorAt(int x, int y); + + /// + /// Set the color at the specified location + /// + /// int x + /// int y + /// Color + void SetColorAt(int x, int y, Color color); + + /// + /// Get the color at x,y + /// The returned byte[] color depends on the underlying pixel format + /// + /// int x + /// int y + /// byte array + void GetColorAt(int x, int y, byte[] color); + + /// + /// Set the color at the specified location + /// + /// int x + /// int y + /// byte[] color + void SetColorAt(int x, int y, byte[] color); + + /// + /// Lock the bitmap + /// + void Lock(); + + /// + /// Unlock the bitmap + /// + void Unlock(); + + /// + /// Unlock the bitmap and get the underlying bitmap in one call + /// + /// + Bitmap UnlockAndReturnBitmap(); + + /// + /// Size of the underlying image + /// + Size Size { get; } + + /// + /// Height of the image area that this fastbitmap covers + /// + int Height { get; } + + /// + /// Width of the image area that this fastbitmap covers + /// + int Width { get; } + + /// + /// Top of the image area that this fastbitmap covers + /// + int Top { get; } + + /// + /// Left of the image area that this fastbitmap covers + /// + int Left { get; } + + /// + /// Right of the image area that this fastbitmap covers + /// + int Right { get; } + + /// + /// Bottom of the image area that this fastbitmap covers + /// + int Bottom { get; } + + /// + /// Does the underlying image need to be disposed + /// + bool NeedsDispose { get; set; } + + /// + /// Returns if this FastBitmap has an alpha channel + /// + bool HasAlphaChannel { get; } + + /// + /// Draw the stored bitmap to the destionation bitmap at the supplied point + /// + /// Graphics + /// Point with location + void DrawTo(Graphics graphics, Point destination); + + /// + /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle + /// Be aware that the stored bitmap will be resized to the specified rectangle!! + /// + /// Graphics + /// Rectangle with destination + void DrawTo(Graphics graphics, Rectangle destinationRect); + + /// + /// Return true if the coordinates are inside the FastBitmap + /// + /// + /// + /// + bool Contains(int x, int y); + + /// + /// Set the bitmap resolution + /// + /// + /// + void SetResolution(float horizontal, float vertical); + } + + /// + /// This interface can be used for when offsetting is needed + /// + public interface IFastBitmapWithOffset : IFastBitmap + { + /// + /// Return true if the coordinates are inside the FastBitmap + /// + /// + /// + /// + new bool Contains(int x, int y); + + /// + /// Set the color at the specified location, using offsetting so the original coordinates can be used + /// + /// int x + /// int y + /// Color color + new void SetColorAt(int x, int y, Color color); + + /// + /// Set the color at the specified location, using offsetting so the original coordinates can be used + /// + /// int x + /// int y + /// byte[] color + new void SetColorAt(int x, int y, byte[] color); + + /// + /// Get the color at x,y + /// The returned Color object depends on the underlying pixel format + /// + /// int x + /// int y + /// Color + new Color GetColorAt(int x, int y); + + /// + /// Get the color at x,y, using offsetting so the original coordinates can be used + /// The returned byte[] color depends on the underlying pixel format + /// + /// int x + /// int y + /// byte array + new void GetColorAt(int x, int y, byte[] color); + + new int Left { get; set; } + + new int Top { get; set; } + } + + /// + /// This interface can be used for when clipping is needed + /// + public interface IFastBitmapWithClip : IFastBitmap + { + Rectangle Clip { get; set; } + + bool InvertClip { get; set; } + + /// + /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping + /// + /// int x + /// int y + /// Color color + new void SetColorAt(int x, int y, Color color); + + /// + /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping + /// + /// int x + /// int y + /// byte[] color + new void SetColorAt(int x, int y, byte[] color); + + /// + /// Return true if the coordinates are inside the FastBitmap and not clipped + /// + /// + /// + /// + new bool Contains(int x, int y); + } + + /// + /// This interface is implemented when there is a alpha-blending possibility + /// + public interface IFastBitmapWithBlend : IFastBitmap + { + Color BackgroundBlendColor { get; set; } + Color GetBlendedColorAt(int x, int y); + } + + /// + /// The base class for the fast bitmap implementation + /// + public abstract unsafe class FastBitmap : IFastBitmapWithClip, IFastBitmapWithOffset + { + protected const int PixelformatIndexA = 3; + protected const int PixelformatIndexR = 2; + protected const int PixelformatIndexG = 1; + protected const int PixelformatIndexB = 0; + + public const int ColorIndexR = 0; + public const int ColorIndexG = 1; + public const int ColorIndexB = 2; + public const int ColorIndexA = 3; + + protected Rectangle Area; + + /// + /// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap + /// + public bool NeedsDispose { get; set; } + + public Rectangle Clip { get; set; } + + public bool InvertClip { get; set; } + + /// + /// The bitmap for which the FastBitmap is creating access + /// + protected Bitmap Bitmap; + + protected BitmapData BmData; + protected int Stride; /* bytes per pixel row */ + protected bool BitsLocked; + protected byte* Pointer; + + public static IFastBitmap Create(Bitmap source) + { + return Create(source, Rectangle.Empty); + } + + public void SetResolution(float horizontal, float vertical) + { + Bitmap.SetResolution(horizontal, vertical); + } + + /// + /// Factory for creating a FastBitmap depending on the pixelformat of the source + /// The supplied rectangle specifies the area for which the FastBitmap does its thing + /// + /// Bitmap to access + /// Rectangle which specifies the area to have access to, can be Rectangle.Empty for the whole image + /// IFastBitmap + public static IFastBitmap Create(Bitmap source, Rectangle area) + { + switch (source.PixelFormat) + { + case PixelFormat.Format8bppIndexed: + return new FastChunkyBitmap(source, area); + case PixelFormat.Format24bppRgb: + return new Fast24RgbBitmap(source, area); + case PixelFormat.Format32bppRgb: + return new Fast32RgbBitmap(source, area); + case PixelFormat.Format32bppArgb: + case PixelFormat.Format32bppPArgb: + return new Fast32ArgbBitmap(source, area); + default: + throw new NotSupportedException($"Not supported Pixelformat {source.PixelFormat}"); + } + } + + /// + /// Factory for creating a FastBitmap as a destination for the source + /// + /// Bitmap to clone + /// new Pixelformat + /// IFastBitmap + public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat) + { + return CreateCloneOf(source, pixelFormat, Rectangle.Empty); + } + + /// + /// Factory for creating a FastBitmap as a destination for the source + /// + /// Bitmap to clone + /// Area of the bitmap to access, can be Rectangle.Empty for the whole + /// IFastBitmap + public static IFastBitmap CreateCloneOf(Image source, Rectangle area) + { + return CreateCloneOf(source, PixelFormat.DontCare, area); + } + + /// + /// Factory for creating a FastBitmap as a destination for the source + /// + /// Bitmap to clone + /// Pixelformat of the cloned bitmap + /// Area of the bitmap to access, can be Rectangle.Empty for the whole + /// IFastBitmap + public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) + { + Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat); + FastBitmap fastBitmap = Create(destination) as FastBitmap; + if (fastBitmap != null) + { + fastBitmap.NeedsDispose = true; + fastBitmap.Left = area.Left; + fastBitmap.Top = area.Top; + } + + return fastBitmap; + } + + /// + /// Factory for creating a FastBitmap as a destination + /// + /// + /// + /// + /// IFastBitmap + public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat, Color backgroundColor) + { + Bitmap destination = ImageHelper.CreateEmpty(newSize.Width, newSize.Height, pixelFormat, backgroundColor, 96f, 96f); + IFastBitmap fastBitmap = Create(destination); + fastBitmap.NeedsDispose = true; + return fastBitmap; + } + + /// + /// Constructor which stores the image and locks it when called + /// + /// Bitmap + /// Rectangle + protected FastBitmap(Bitmap bitmap, Rectangle area) + { + Bitmap = bitmap; + Rectangle bitmapArea = new Rectangle(Point.Empty, bitmap.Size); + if (area != Rectangle.Empty) + { + area.Intersect(bitmapArea); + Area = area; + } + else + { + Area = bitmapArea; + } + + // As the lock takes care that only the specified area is made available we need to calculate the offset + Left = area.Left; + Top = area.Top; + // Default cliping is done to the area without invert + Clip = Area; + InvertClip = false; + // Always lock, so we don't need to do this ourselves + Lock(); + } + + /// + /// Return the size of the image + /// + public Size Size + { + get + { + if (Area == Rectangle.Empty) + { + return Bitmap.Size; + } + + return Area.Size; + } + } + + /// + /// Return the width of the image + /// + public int Width + { + get + { + if (Area == Rectangle.Empty) + { + return Bitmap.Width; + } + + return Area.Width; + } + } + + /// + /// Return the height of the image + /// + public int Height + { + get + { + if (Area == Rectangle.Empty) + { + return Bitmap.Height; + } + + return Area.Height; + } + } + + private int _left; + + /// + /// Return the left of the fastbitmap, this is also used as an offset + /// + public int Left + { + get { return 0; } + set { _left = value; } + } + + /// + /// Return the left of the fastbitmap, this is also used as an offset + /// + int IFastBitmapWithOffset.Left + { + get { return _left; } + set { _left = value; } + } + + private int _top; + + /// + /// Return the top of the fastbitmap, this is also used as an offset + /// + public int Top + { + get { return 0; } + set { _top = value; } + } + + /// + /// Return the top of the fastbitmap, this is also used as an offset + /// + int IFastBitmapWithOffset.Top + { + get { return _top; } + set { _top = value; } + } + + /// + /// Return the right of the fastbitmap + /// + public int Right => Left + Width; + + /// + /// Return the bottom of the fastbitmap + /// + public int Bottom => Top + Height; + + /// + /// Returns the underlying bitmap, unlocks it and prevents that it will be disposed + /// + public Bitmap UnlockAndReturnBitmap() + { + if (BitsLocked) + { + Unlock(); + } + + NeedsDispose = false; + return Bitmap; + } + + public virtual bool HasAlphaChannel => false; + + /// + /// Destructor + /// + ~FastBitmap() + { + Dispose(false); + } + + /// + /// The public accessible Dispose + /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // The bulk of the clean-up code is implemented in Dispose(bool) + + /// + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + protected virtual void Dispose(bool disposing) + { + Unlock(); + if (disposing) + { + if (Bitmap != null && NeedsDispose) + { + Bitmap.Dispose(); + } + } + + Bitmap = null; + BmData = null; + Pointer = null; + } + + /// + /// Lock the bitmap so we have direct access to the memory + /// + public void Lock() + { + if (Width <= 0 || Height <= 0 || BitsLocked) + { + return; + } + + BmData = Bitmap.LockBits(Area, ImageLockMode.ReadWrite, Bitmap.PixelFormat); + BitsLocked = true; + + IntPtr scan0 = BmData.Scan0; + Pointer = (byte*) (void*) scan0; + Stride = BmData.Stride; + } + + /// + /// Unlock the System Memory + /// + public void Unlock() + { + if (BitsLocked) + { + Bitmap.UnlockBits(BmData); + BitsLocked = false; + } + } + + /// + /// Draw the stored bitmap to the destionation bitmap at the supplied point + /// + /// + /// + public void DrawTo(Graphics graphics, Point destination) + { + DrawTo(graphics, new Rectangle(destination, Area.Size)); + } + + /// + /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle + /// Be aware that the stored bitmap will be resized to the specified rectangle!! + /// + /// + /// + public void DrawTo(Graphics graphics, Rectangle destinationRect) + { + // Make sure this.bitmap is unlocked, if it was locked + bool isLocked = BitsLocked; + if (isLocked) + { + Unlock(); + } + + graphics.DrawImage(Bitmap, destinationRect, Area, GraphicsUnit.Pixel); + } + + /// + /// returns true if x & y are inside the FastBitmap + /// + /// + /// + /// true if x & y are inside the FastBitmap + public bool Contains(int x, int y) + { + return Area.Contains(x - Left, y - Top); + } + + public abstract Color GetColorAt(int x, int y); + public abstract void SetColorAt(int x, int y, Color color); + public abstract void GetColorAt(int x, int y, byte[] color); + public abstract void SetColorAt(int x, int y, byte[] color); + + bool IFastBitmapWithClip.Contains(int x, int y) + { + bool contains = Clip.Contains(x, y); + if (InvertClip) + { + return !contains; + } + else + { + return contains; + } + } + + void IFastBitmapWithClip.SetColorAt(int x, int y, byte[] color) + { + bool contains = Clip.Contains(x, y); + if ((InvertClip && contains) || (!InvertClip && !contains)) + { + return; + } + + SetColorAt(x, y, color); + } + + void IFastBitmapWithClip.SetColorAt(int x, int y, Color color) + { + bool contains = Clip.Contains(x, y); + if ((InvertClip && contains) || (!InvertClip && !contains)) + { + return; + } + + SetColorAt(x, y, color); + } + + /// + /// returns true if x & y are inside the FastBitmap + /// + /// + /// + /// true if x & y are inside the FastBitmap + bool IFastBitmapWithOffset.Contains(int x, int y) + { + return Area.Contains(x - Left, y - Top); + } + + Color IFastBitmapWithOffset.GetColorAt(int x, int y) + { + x -= _left; + y -= _top; + return GetColorAt(x, y); + } + + void IFastBitmapWithOffset.GetColorAt(int x, int y, byte[] color) + { + x -= _left; + y -= _top; + GetColorAt(x, y, color); + } + + void IFastBitmapWithOffset.SetColorAt(int x, int y, byte[] color) + { + x -= _left; + y -= _top; + SetColorAt(x, y, color); + } + + void IFastBitmapWithOffset.SetColorAt(int x, int y, Color color) + { + x -= _left; + y -= _top; + SetColorAt(x, y, color); + } + } + + /// + /// This is the implementation of the FastBitmat for the 8BPP pixelformat + /// + public unsafe class FastChunkyBitmap : FastBitmap + { + // Used for indexed images + private readonly Color[] _colorEntries; + private readonly Dictionary _colorCache = new Dictionary(); + + public FastChunkyBitmap(Bitmap source, Rectangle area) : base(source, area) + { + _colorEntries = Bitmap.Palette.Entries; + } + + /// + /// Get the color from the specified location + /// + /// + /// + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = x + (y * Stride); + byte colorIndex = Pointer[offset]; + return _colorEntries[colorIndex]; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference + public override void GetColorAt(int x, int y, byte[] color) + { + throw new NotImplementedException("No performance gain!"); + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference + public override void SetColorAt(int x, int y, byte[] color) + { + throw new NotImplementedException("No performance gain!"); + } + + /// + /// Get the color-index from the specified location + /// + /// + /// + /// byte with index + public byte GetColorIndexAt(int x, int y) + { + int offset = x + (y * Stride); + return Pointer[offset]; + } + + /// + /// Set the color-index at the specified location + /// + /// + /// + /// + public void SetColorIndexAt(int x, int y, byte colorIndex) + { + int offset = x + (y * Stride); + Pointer[offset] = colorIndex; + } + + /// + /// Set the supplied color at the specified location. + /// Throws an ArgumentException if the color is not in the palette + /// + /// + /// + /// Color to set + public override void SetColorAt(int x, int y, Color color) + { + int offset = x + (y * Stride); + if (!_colorCache.TryGetValue(color, out var colorIndex)) + { + bool foundColor = false; + for (colorIndex = 0; colorIndex < _colorEntries.Length; colorIndex++) + { + if (color == _colorEntries[colorIndex]) + { + _colorCache.Add(color, colorIndex); + foundColor = true; + break; + } + } + + if (!foundColor) + { + throw new ArgumentException("No such color!"); + } + } + + Pointer[offset] = colorIndex; + } + } + + /// + /// This is the implementation of the IFastBitmap for 24 bit images (no Alpha) + /// + public unsafe class Fast24RgbBitmap : FastBitmap + { + public Fast24RgbBitmap(Bitmap source, Rectangle area) : base(source, area) + { + } + + /// + /// Retrieve the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// X coordinate + /// Y Coordinate + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = (x * 3) + (y * Stride); + return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); + } + + /// + /// Set the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// + public override void SetColorAt(int x, int y, Color color) + { + int offset = (x * 3) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color.R; + Pointer[PixelformatIndexG + offset] = color.G; + Pointer[PixelformatIndexB + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b) + public override void GetColorAt(int x, int y, byte[] color) + { + int offset = (x * 3) + (y * Stride); + color[PixelformatIndexR] = Pointer[PixelformatIndexR + offset]; + color[PixelformatIndexG] = Pointer[PixelformatIndexG + offset]; + color[PixelformatIndexB] = Pointer[PixelformatIndexB + offset]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b) + public override void SetColorAt(int x, int y, byte[] color) + { + int offset = (x * 3) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color[PixelformatIndexR]; + Pointer[PixelformatIndexG + offset] = color[PixelformatIndexG]; + Pointer[PixelformatIndexB + offset] = color[PixelformatIndexB]; + } + } + + /// + /// This is the implementation of the IFastBitmap for 32 bit images (no Alpha) + /// + public unsafe class Fast32RgbBitmap : FastBitmap + { + public Fast32RgbBitmap(Bitmap source, Rectangle area) : base(source, area) + { + } + + /// + /// Retrieve the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// X coordinate + /// Y Coordinate + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = (x * 4) + (y * Stride); + return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); + } + + /// + /// Set the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// + public override void SetColorAt(int x, int y, Color color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color.R; + Pointer[PixelformatIndexG + offset] = color.G; + Pointer[PixelformatIndexB + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference (a,r,g,b) + public override void GetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; + color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; + color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b) + public override void SetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R + Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; + Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; + } + } + + /// + /// This is the implementation of the IFastBitmap for 32 bit images with Alpha + /// + public unsafe class Fast32ArgbBitmap : FastBitmap, IFastBitmapWithBlend + { + public override bool HasAlphaChannel => true; + + public Color BackgroundBlendColor { get; set; } + + public Fast32ArgbBitmap(Bitmap source, Rectangle area) : base(source, area) + { + BackgroundBlendColor = Color.White; + } + + /// + /// Retrieve the color at location x,y + /// + /// X coordinate + /// Y Coordinate + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = (x * 4) + (y * Stride); + return Color.FromArgb(Pointer[PixelformatIndexA + offset], Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], + Pointer[PixelformatIndexB + offset]); + } + + /// + /// Set the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// + public override void SetColorAt(int x, int y, Color color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexA + offset] = color.A; + Pointer[PixelformatIndexR + offset] = color.R; + Pointer[PixelformatIndexG + offset] = color.G; + Pointer[PixelformatIndexB + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b,a) + public override void GetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; + color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; + color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; + color[ColorIndexA] = Pointer[PixelformatIndexA + offset]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b,a) + public override void SetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R + Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; + Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; + Pointer[PixelformatIndexA + offset] = color[ColorIndexA]; + } + + /// + /// Retrieve the color, without alpha (is blended), at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// X coordinate + /// Y Coordinate + /// Color + public Color GetBlendedColorAt(int x, int y) + { + int offset = (x * 4) + (y * Stride); + int a = Pointer[PixelformatIndexA + offset]; + int red = Pointer[PixelformatIndexR + offset]; + int green = Pointer[PixelformatIndexG + offset]; + int blue = Pointer[PixelformatIndexB + offset]; + + if (a < 255) + { + // As the request is to get without alpha, we blend. + int rem = 255 - a; + red = (red * a + BackgroundBlendColor.R * rem) / 255; + green = (green * a + BackgroundBlendColor.G * rem) / 255; + blue = (blue * a + BackgroundBlendColor.B * rem) / 255; + } + + return Color.FromArgb(255, red, green, blue); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/FilenameHelper.cs b/src/Greenshot.Base/Core/FilenameHelper.cs similarity index 97% rename from src/GreenshotPlugin/Core/FilenameHelper.cs rename to src/Greenshot.Base/Core/FilenameHelper.cs index 6d8073843..83a76f438 100644 --- a/src/GreenshotPlugin/Core/FilenameHelper.cs +++ b/src/Greenshot.Base/Core/FilenameHelper.cs @@ -1,705 +1,705 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections; -using System.IO; -using System.Text.RegularExpressions; -using System.Windows.Forms; -using log4net; -using System.Collections.Generic; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; - -namespace GreenshotPlugin.Core -{ - public static class FilenameHelper - { - private static readonly ILog Log = LogManager.GetLogger(typeof(FilenameHelper)); - - // Specify the regular expression for the filename formatting: - // Starting with ${ - // than the varname, which ends with a : or } - // If a parameters needs to be supplied, than a ":" should follow the name... everything from the : until the } is considered to be part of the parameters. - // The parameter format is a single alpha followed by the value belonging to the parameter, e.g. : - // ${capturetime:d"yyyy-MM-dd HH_mm_ss"} - private static readonly Regex VarRegexp = new Regex(@"\${(?[^:}]+)[:]?(?[^}]*)}", RegexOptions.Compiled); - private static readonly Regex CmdVarRegexp = new Regex(@"%(?[^%]+)%", RegexOptions.Compiled); - - private static readonly Regex SplitRegexp = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled); - private const int MaxTitleLength = 80; - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const string UnsafeReplacement = "_"; - private static readonly Random RandomNumberGen = new Random(); - private static readonly Regex RandRegexp = new Regex("^R+$", RegexOptions.Compiled); - - /// - /// Remove invalid characters from the fully qualified filename - /// - /// string with the full path to a file - /// string with the full path to a file, without invalid characters - public static string MakeFqFilenameSafe(string fullPath) - { - string path = MakePathSafe(Path.GetDirectoryName(fullPath)); - string filename = MakeFilenameSafe(Path.GetFileName(fullPath)); - // Make the fullpath again and return - return Path.Combine(path, filename); - } - - /// - /// Remove invalid characters from the filename - /// - /// string with the full path to a file - /// string with the full path to a file, without invalid characters - public static string MakeFilenameSafe(string filename) - { - // Make the filename save! - if (filename != null) - { - foreach (char disallowed in Path.GetInvalidFileNameChars()) - { - filename = filename.Replace(disallowed.ToString(), UnsafeReplacement); - } - } - - return filename; - } - - /// - /// Remove invalid characters from the path - /// - /// string with the full path to a file - /// string with the full path to a file, without invalid characters - public static string MakePathSafe(string path) - { - // Make the path save! - if (path != null) - { - foreach (char disallowed in Path.GetInvalidPathChars()) - { - path = path.Replace(disallowed.ToString(), UnsafeReplacement); - } - } - - return path; - } - - public static string GetFilenameWithoutExtensionFromPattern(string pattern) - { - return GetFilenameWithoutExtensionFromPattern(pattern, null); - } - - public static string GetFilenameWithoutExtensionFromPattern(string pattern, ICaptureDetails captureDetails) - { - return FillPattern(pattern, captureDetails, true); - } - - public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat) - { - return GetFilenameFromPattern(pattern, imageFormat, null); - } - - public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat, ICaptureDetails captureDetails) - { - return FillPattern(pattern, captureDetails, true) + "." + imageFormat.ToString().ToLower(); - } - - /// - /// Return a filename for the current image format (png,jpg etc) with the default file pattern - /// that is specified in the configuration - /// - /// A string with the format - /// - /// The filename which should be used to save the image - public static string GetFilename(OutputFormat format, ICaptureDetails captureDetails) - { - string pattern = CoreConfig.OutputFileFilenamePattern; - if (string.IsNullOrEmpty(pattern?.Trim())) - { - pattern = "greenshot ${capturetime}"; - } - - return GetFilenameFromPattern(pattern, format, captureDetails); - } - - - /// - /// This method will be called by the regexp.replace as a MatchEvaluator delegate! - /// Will delegate this to the MatchVarEvaluatorInternal and catch any exceptions - /// - /// What are we matching? - /// The detail, can be null - /// Variables from the process - /// Variables from the user - /// Variables from the machine - /// - /// string with the match replacement - private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, - bool filenameSafeMode) - { - try - { - return MatchVarEvaluatorInternal(match, captureDetails, processVars, userVars, machineVars, filenameSafeMode); - } - catch (Exception e) - { - Log.Error("Error in MatchVarEvaluatorInternal", e); - } - - return string.Empty; - } - - /// - /// This method will be called by the regexp.replace as a MatchEvaluator delegate! - /// - /// What are we matching? - /// The detail, can be null - /// - /// - /// - /// - /// - private static string MatchVarEvaluatorInternal(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, - bool filenameSafeMode) - { - // some defaults - int padWidth = 0; - int startIndex = 0; - int endIndex = 0; - char padChar = ' '; - string dateFormat = "yyyy-MM-dd HH-mm-ss"; - IDictionary replacements = new Dictionary(); - string replaceValue = string.Empty; - string variable = match.Groups["variable"].Value; - string parameters = match.Groups["parameters"].Value; - string randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - - if (parameters.Length > 0) - { - string[] parms = SplitRegexp.Split(parameters); - foreach (string parameter in parms) - { - switch (parameter.Substring(0, 1)) - { - // Padding p[,pad-character] - case "p": - string[] padParams = parameter.Substring(1).Split(','); - try - { - padWidth = int.Parse(padParams[0]); - } - catch - { - // ignored - } - - if (padParams.Length > 1) - { - padChar = padParams[1][0]; - } - - break; - // replace - // r, - case "r": - string[] replaceParameters = parameter.Substring(1).Split(','); - if (replaceParameters != null && replaceParameters.Length == 2) - { - replacements.Add(replaceParameters[0], replaceParameters[1]); - } - - break; - // Dateformat d - // Format can be anything that is used in C# date formatting - case "d": - dateFormat = parameter.Substring(1); - if (dateFormat.StartsWith("\"")) - { - dateFormat = dateFormat.Substring(1); - } - - if (dateFormat.EndsWith("\"")) - { - dateFormat = dateFormat.Substring(0, dateFormat.Length - 1); - } - - break; - // Substring: - // s[,length] - case "s": - string range = parameter.Substring(1); - string[] rangelist = range.Split(','); - if (rangelist.Length > 0) - { - try - { - startIndex = int.Parse(rangelist[0]); - } - catch - { - // Ignore - } - } - - if (rangelist.Length > 1) - { - try - { - endIndex = int.Parse(rangelist[1]); - } - catch - { - // Ignore - } - } - - break; - } - } - } - - if (processVars != null && processVars.Contains(variable)) - { - replaceValue = (string) processVars[variable]; - if (filenameSafeMode) - { - replaceValue = MakePathSafe(replaceValue); - } - } - else if (userVars != null && userVars.Contains(variable)) - { - replaceValue = (string) userVars[variable]; - if (filenameSafeMode) - { - replaceValue = MakePathSafe(replaceValue); - } - } - else if (machineVars != null && machineVars.Contains(variable)) - { - replaceValue = (string) machineVars[variable]; - if (filenameSafeMode) - { - replaceValue = MakePathSafe(replaceValue); - } - } - else if (captureDetails?.MetaData != null && captureDetails.MetaData.ContainsKey(variable)) - { - replaceValue = captureDetails.MetaData[variable]; - if (filenameSafeMode) - { - replaceValue = MakePathSafe(replaceValue); - } - } - else if (RandRegexp.IsMatch(variable)) - { - for (int i = 0; i < variable.Length; i++) - { - replaceValue += randomChars[RandomNumberGen.Next(randomChars.Length)]; - } - } - else - { - // Handle other variables - // Default use "now" for the capture take´n - DateTime capturetime = DateTime.Now; - // Use default application name for title - string title = Application.ProductName; - - // Check if we have capture details - if (captureDetails != null) - { - capturetime = captureDetails.DateTime; - if (captureDetails.Title != null) - { - title = captureDetails.Title; - if (title.Length > MaxTitleLength) - { - title = title.Substring(0, MaxTitleLength); - } - } - } - - switch (variable) - { - case "domain": - replaceValue = Environment.UserDomainName; - break; - case "user": - replaceValue = Environment.UserName; - break; - case "hostname": - replaceValue = Environment.MachineName; - break; - case "YYYY": - if (padWidth == 0) - { - padWidth = -4; - padChar = '0'; - } - - replaceValue = capturetime.Year.ToString(); - break; - case "MM": - replaceValue = capturetime.Month.ToString(); - if (padWidth == 0) - { - padWidth = -2; - padChar = '0'; - } - - break; - case "DD": - replaceValue = capturetime.Day.ToString(); - if (padWidth == 0) - { - padWidth = -2; - padChar = '0'; - } - - break; - case "hh": - if (padWidth == 0) - { - padWidth = -2; - padChar = '0'; - } - - replaceValue = capturetime.Hour.ToString(); - break; - case "mm": - if (padWidth == 0) - { - padWidth = -2; - padChar = '0'; - } - - replaceValue = capturetime.Minute.ToString(); - break; - case "ss": - if (padWidth == 0) - { - padWidth = -2; - padChar = '0'; - } - - replaceValue = capturetime.Second.ToString(); - break; - case "now": - replaceValue = DateTime.Now.ToString(dateFormat); - if (filenameSafeMode) - { - replaceValue = MakeFilenameSafe(replaceValue); - } - - break; - case "capturetime": - replaceValue = capturetime.ToString(dateFormat); - if (filenameSafeMode) - { - replaceValue = MakeFilenameSafe(replaceValue); - } - - break; - case "NUM": - CoreConfig.OutputFileIncrementingNumber++; - IniConfig.Save(); - replaceValue = CoreConfig.OutputFileIncrementingNumber.ToString(); - if (padWidth == 0) - { - padWidth = -6; - padChar = '0'; - } - - break; - case "title": - replaceValue = title; - if (filenameSafeMode) - { - replaceValue = MakeFilenameSafe(replaceValue); - } - - break; - case "MyPictures": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); - break; - case "MyMusic": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic); - break; - case "MyDocuments": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); - break; - case "Personal": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Personal); - break; - case "Desktop": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); - break; - case "ApplicationData": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - break; - case "LocalApplicationData": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - break; - } - } - - // do padding - if (padWidth > 0) - { - replaceValue = replaceValue.PadRight(padWidth, padChar); - } - else if (padWidth < 0) - { - replaceValue = replaceValue.PadLeft(-padWidth, padChar); - } - - // do substring - if (startIndex != 0 || endIndex != 0) - { - if (startIndex < 0) - { - startIndex = replaceValue.Length + startIndex; - } - - if (endIndex < 0) - { - endIndex = replaceValue.Length + endIndex; - } - - if (endIndex != 0) - { - try - { - replaceValue = replaceValue.Substring(startIndex, endIndex); - } - catch - { - // Ignore - } - } - else - { - try - { - replaceValue = replaceValue.Substring(startIndex); - } - catch - { - // Ignore - } - } - } - - // new for feature #697 - if (replacements.Count > 0) - { - foreach (string oldValue in replacements.Keys) - { - replaceValue = replaceValue.Replace(oldValue, replacements[oldValue]); - } - } - - return replaceValue; - } - - /// - /// "Simply" fill the pattern with environment variables - /// - /// String with pattern %var% - /// true to make sure everything is filenamesafe - /// Filled string - public static string FillCmdVariables(string pattern, bool filenameSafeMode = true) - { - IDictionary processVars = null; - IDictionary userVars = null; - IDictionary machineVars = null; - try - { - processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); - } - - try - { - userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.User", e); - } - - try - { - machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); - } - - return CmdVarRegexp.Replace(pattern, - m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) - ); - } - - /// - /// "Simply" fill the pattern with environment variables - /// - /// String with pattern ${var} - /// true to make sure everything is filenamesafe - /// Filled string - public static string FillVariables(string pattern, bool filenameSafeMode) - { - IDictionary processVars = null; - IDictionary userVars = null; - IDictionary machineVars = null; - try - { - processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); - } - - try - { - userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.User", e); - } - - try - { - machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); - } - - return VarRegexp.Replace(pattern, - m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) - ); - } - - /// - /// Fill the pattern wit the supplied details - /// - /// Pattern - /// CaptureDetails, can be null - /// Should the result be made "filename" safe? - /// Filled pattern - public static string FillPattern(string pattern, ICaptureDetails captureDetails, bool filenameSafeMode) - { - IDictionary processVars = null; - IDictionary userVars = null; - IDictionary machineVars = null; - try - { - processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); - } - - try - { - userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.User", e); - } - - try - { - machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); - } - - try - { - return VarRegexp.Replace(pattern, - m => MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars, filenameSafeMode) - ); - } - catch (Exception e) - { - // adding additional data for bug tracking - if (captureDetails != null) - { - e.Data.Add("title", captureDetails.Title); - } - - e.Data.Add("pattern", pattern); - throw; - } - } - - /// - /// Checks whether a directory name is valid in the current file system - /// - /// directory name (not path!) - /// true if directory name is valid - public static bool IsDirectoryNameValid(string directoryName) - { - var forbiddenChars = Path.GetInvalidPathChars(); - foreach (var forbiddenChar in forbiddenChars) - { - if (directoryName == null || directoryName.Contains(forbiddenChar.ToString())) - { - return false; - } - } - - return true; - } - - /// - /// Checks whether a filename is valid in the current file system - /// - /// name of the file - /// true if filename is valid - public static bool IsFilenameValid(string filename) - { - var forbiddenChars = Path.GetInvalidFileNameChars(); - foreach (var forbiddenChar in forbiddenChars) - { - if (filename == null || filename.Contains(forbiddenChar.ToString())) - { - return false; - } - } - - return true; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using log4net; + +namespace Greenshot.Base.Core +{ + public static class FilenameHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(FilenameHelper)); + + // Specify the regular expression for the filename formatting: + // Starting with ${ + // than the varname, which ends with a : or } + // If a parameters needs to be supplied, than a ":" should follow the name... everything from the : until the } is considered to be part of the parameters. + // The parameter format is a single alpha followed by the value belonging to the parameter, e.g. : + // ${capturetime:d"yyyy-MM-dd HH_mm_ss"} + private static readonly Regex VarRegexp = new Regex(@"\${(?[^:}]+)[:]?(?[^}]*)}", RegexOptions.Compiled); + private static readonly Regex CmdVarRegexp = new Regex(@"%(?[^%]+)%", RegexOptions.Compiled); + + private static readonly Regex SplitRegexp = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled); + private const int MaxTitleLength = 80; + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private const string UnsafeReplacement = "_"; + private static readonly Random RandomNumberGen = new Random(); + private static readonly Regex RandRegexp = new Regex("^R+$", RegexOptions.Compiled); + + /// + /// Remove invalid characters from the fully qualified filename + /// + /// string with the full path to a file + /// string with the full path to a file, without invalid characters + public static string MakeFqFilenameSafe(string fullPath) + { + string path = MakePathSafe(Path.GetDirectoryName(fullPath)); + string filename = MakeFilenameSafe(Path.GetFileName(fullPath)); + // Make the fullpath again and return + return Path.Combine(path, filename); + } + + /// + /// Remove invalid characters from the filename + /// + /// string with the full path to a file + /// string with the full path to a file, without invalid characters + public static string MakeFilenameSafe(string filename) + { + // Make the filename save! + if (filename != null) + { + foreach (char disallowed in Path.GetInvalidFileNameChars()) + { + filename = filename.Replace(disallowed.ToString(), UnsafeReplacement); + } + } + + return filename; + } + + /// + /// Remove invalid characters from the path + /// + /// string with the full path to a file + /// string with the full path to a file, without invalid characters + public static string MakePathSafe(string path) + { + // Make the path save! + if (path != null) + { + foreach (char disallowed in Path.GetInvalidPathChars()) + { + path = path.Replace(disallowed.ToString(), UnsafeReplacement); + } + } + + return path; + } + + public static string GetFilenameWithoutExtensionFromPattern(string pattern) + { + return GetFilenameWithoutExtensionFromPattern(pattern, null); + } + + public static string GetFilenameWithoutExtensionFromPattern(string pattern, ICaptureDetails captureDetails) + { + return FillPattern(pattern, captureDetails, true); + } + + public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat) + { + return GetFilenameFromPattern(pattern, imageFormat, null); + } + + public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat, ICaptureDetails captureDetails) + { + return FillPattern(pattern, captureDetails, true) + "." + imageFormat.ToString().ToLower(); + } + + /// + /// Return a filename for the current image format (png,jpg etc) with the default file pattern + /// that is specified in the configuration + /// + /// A string with the format + /// + /// The filename which should be used to save the image + public static string GetFilename(OutputFormat format, ICaptureDetails captureDetails) + { + string pattern = CoreConfig.OutputFileFilenamePattern; + if (string.IsNullOrEmpty(pattern?.Trim())) + { + pattern = "greenshot ${capturetime}"; + } + + return GetFilenameFromPattern(pattern, format, captureDetails); + } + + + /// + /// This method will be called by the regexp.replace as a MatchEvaluator delegate! + /// Will delegate this to the MatchVarEvaluatorInternal and catch any exceptions + /// + /// What are we matching? + /// The detail, can be null + /// Variables from the process + /// Variables from the user + /// Variables from the machine + /// + /// string with the match replacement + private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, + bool filenameSafeMode) + { + try + { + return MatchVarEvaluatorInternal(match, captureDetails, processVars, userVars, machineVars, filenameSafeMode); + } + catch (Exception e) + { + Log.Error("Error in MatchVarEvaluatorInternal", e); + } + + return string.Empty; + } + + /// + /// This method will be called by the regexp.replace as a MatchEvaluator delegate! + /// + /// What are we matching? + /// The detail, can be null + /// + /// + /// + /// + /// + private static string MatchVarEvaluatorInternal(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, + bool filenameSafeMode) + { + // some defaults + int padWidth = 0; + int startIndex = 0; + int endIndex = 0; + char padChar = ' '; + string dateFormat = "yyyy-MM-dd HH-mm-ss"; + IDictionary replacements = new Dictionary(); + string replaceValue = string.Empty; + string variable = match.Groups["variable"].Value; + string parameters = match.Groups["parameters"].Value; + string randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + if (parameters.Length > 0) + { + string[] parms = SplitRegexp.Split(parameters); + foreach (string parameter in parms) + { + switch (parameter.Substring(0, 1)) + { + // Padding p[,pad-character] + case "p": + string[] padParams = parameter.Substring(1).Split(','); + try + { + padWidth = int.Parse(padParams[0]); + } + catch + { + // ignored + } + + if (padParams.Length > 1) + { + padChar = padParams[1][0]; + } + + break; + // replace + // r, + case "r": + string[] replaceParameters = parameter.Substring(1).Split(','); + if (replaceParameters != null && replaceParameters.Length == 2) + { + replacements.Add(replaceParameters[0], replaceParameters[1]); + } + + break; + // Dateformat d + // Format can be anything that is used in C# date formatting + case "d": + dateFormat = parameter.Substring(1); + if (dateFormat.StartsWith("\"")) + { + dateFormat = dateFormat.Substring(1); + } + + if (dateFormat.EndsWith("\"")) + { + dateFormat = dateFormat.Substring(0, dateFormat.Length - 1); + } + + break; + // Substring: + // s[,length] + case "s": + string range = parameter.Substring(1); + string[] rangelist = range.Split(','); + if (rangelist.Length > 0) + { + try + { + startIndex = int.Parse(rangelist[0]); + } + catch + { + // Ignore + } + } + + if (rangelist.Length > 1) + { + try + { + endIndex = int.Parse(rangelist[1]); + } + catch + { + // Ignore + } + } + + break; + } + } + } + + if (processVars != null && processVars.Contains(variable)) + { + replaceValue = (string) processVars[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (userVars != null && userVars.Contains(variable)) + { + replaceValue = (string) userVars[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (machineVars != null && machineVars.Contains(variable)) + { + replaceValue = (string) machineVars[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (captureDetails?.MetaData != null && captureDetails.MetaData.ContainsKey(variable)) + { + replaceValue = captureDetails.MetaData[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (RandRegexp.IsMatch(variable)) + { + for (int i = 0; i < variable.Length; i++) + { + replaceValue += randomChars[RandomNumberGen.Next(randomChars.Length)]; + } + } + else + { + // Handle other variables + // Default use "now" for the capture take´n + DateTime capturetime = DateTime.Now; + // Use default application name for title + string title = Application.ProductName; + + // Check if we have capture details + if (captureDetails != null) + { + capturetime = captureDetails.DateTime; + if (captureDetails.Title != null) + { + title = captureDetails.Title; + if (title.Length > MaxTitleLength) + { + title = title.Substring(0, MaxTitleLength); + } + } + } + + switch (variable) + { + case "domain": + replaceValue = Environment.UserDomainName; + break; + case "user": + replaceValue = Environment.UserName; + break; + case "hostname": + replaceValue = Environment.MachineName; + break; + case "YYYY": + if (padWidth == 0) + { + padWidth = -4; + padChar = '0'; + } + + replaceValue = capturetime.Year.ToString(); + break; + case "MM": + replaceValue = capturetime.Month.ToString(); + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } + + break; + case "DD": + replaceValue = capturetime.Day.ToString(); + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } + + break; + case "hh": + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } + + replaceValue = capturetime.Hour.ToString(); + break; + case "mm": + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } + + replaceValue = capturetime.Minute.ToString(); + break; + case "ss": + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } + + replaceValue = capturetime.Second.ToString(); + break; + case "now": + replaceValue = DateTime.Now.ToString(dateFormat); + if (filenameSafeMode) + { + replaceValue = MakeFilenameSafe(replaceValue); + } + + break; + case "capturetime": + replaceValue = capturetime.ToString(dateFormat); + if (filenameSafeMode) + { + replaceValue = MakeFilenameSafe(replaceValue); + } + + break; + case "NUM": + CoreConfig.OutputFileIncrementingNumber++; + IniConfig.Save(); + replaceValue = CoreConfig.OutputFileIncrementingNumber.ToString(); + if (padWidth == 0) + { + padWidth = -6; + padChar = '0'; + } + + break; + case "title": + replaceValue = title; + if (filenameSafeMode) + { + replaceValue = MakeFilenameSafe(replaceValue); + } + + break; + case "MyPictures": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); + break; + case "MyMusic": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic); + break; + case "MyDocuments": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + break; + case "Personal": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Personal); + break; + case "Desktop": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + break; + case "ApplicationData": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + break; + case "LocalApplicationData": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + break; + } + } + + // do padding + if (padWidth > 0) + { + replaceValue = replaceValue.PadRight(padWidth, padChar); + } + else if (padWidth < 0) + { + replaceValue = replaceValue.PadLeft(-padWidth, padChar); + } + + // do substring + if (startIndex != 0 || endIndex != 0) + { + if (startIndex < 0) + { + startIndex = replaceValue.Length + startIndex; + } + + if (endIndex < 0) + { + endIndex = replaceValue.Length + endIndex; + } + + if (endIndex != 0) + { + try + { + replaceValue = replaceValue.Substring(startIndex, endIndex); + } + catch + { + // Ignore + } + } + else + { + try + { + replaceValue = replaceValue.Substring(startIndex); + } + catch + { + // Ignore + } + } + } + + // new for feature #697 + if (replacements.Count > 0) + { + foreach (string oldValue in replacements.Keys) + { + replaceValue = replaceValue.Replace(oldValue, replacements[oldValue]); + } + } + + return replaceValue; + } + + /// + /// "Simply" fill the pattern with environment variables + /// + /// String with pattern %var% + /// true to make sure everything is filenamesafe + /// Filled string + public static string FillCmdVariables(string pattern, bool filenameSafeMode = true) + { + IDictionary processVars = null; + IDictionary userVars = null; + IDictionary machineVars = null; + try + { + processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); + } + + try + { + userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.User", e); + } + + try + { + machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); + } + + return CmdVarRegexp.Replace(pattern, + m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) + ); + } + + /// + /// "Simply" fill the pattern with environment variables + /// + /// String with pattern ${var} + /// true to make sure everything is filenamesafe + /// Filled string + public static string FillVariables(string pattern, bool filenameSafeMode) + { + IDictionary processVars = null; + IDictionary userVars = null; + IDictionary machineVars = null; + try + { + processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); + } + + try + { + userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.User", e); + } + + try + { + machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); + } + + return VarRegexp.Replace(pattern, + m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) + ); + } + + /// + /// Fill the pattern wit the supplied details + /// + /// Pattern + /// CaptureDetails, can be null + /// Should the result be made "filename" safe? + /// Filled pattern + public static string FillPattern(string pattern, ICaptureDetails captureDetails, bool filenameSafeMode) + { + IDictionary processVars = null; + IDictionary userVars = null; + IDictionary machineVars = null; + try + { + processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); + } + + try + { + userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.User", e); + } + + try + { + machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); + } + + try + { + return VarRegexp.Replace(pattern, + m => MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars, filenameSafeMode) + ); + } + catch (Exception e) + { + // adding additional data for bug tracking + if (captureDetails != null) + { + e.Data.Add("title", captureDetails.Title); + } + + e.Data.Add("pattern", pattern); + throw; + } + } + + /// + /// Checks whether a directory name is valid in the current file system + /// + /// directory name (not path!) + /// true if directory name is valid + public static bool IsDirectoryNameValid(string directoryName) + { + var forbiddenChars = Path.GetInvalidPathChars(); + foreach (var forbiddenChar in forbiddenChars) + { + if (directoryName == null || directoryName.Contains(forbiddenChar.ToString())) + { + return false; + } + } + + return true; + } + + /// + /// Checks whether a filename is valid in the current file system + /// + /// name of the file + /// true if filename is valid + public static bool IsFilenameValid(string filename) + { + var forbiddenChars = Path.GetInvalidFileNameChars(); + foreach (var forbiddenChar in forbiddenChars) + { + if (filename == null || filename.Contains(forbiddenChar.ToString())) + { + return false; + } + } + + return true; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Fraction.cs b/src/Greenshot.Base/Core/Fraction.cs similarity index 99% rename from src/GreenshotPlugin/Core/Fraction.cs rename to src/Greenshot.Base/Core/Fraction.cs index 94c4fddf4..e7d999445 100644 --- a/src/GreenshotPlugin/Core/Fraction.cs +++ b/src/Greenshot.Base/Core/Fraction.cs @@ -1,7 +1,7 @@ using System; using System.Text.RegularExpressions; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// Basic Fraction (Rational) numbers with features only needed to represent scale factors. diff --git a/src/GreenshotPlugin/Core/GreenshotResources.cs b/src/Greenshot.Base/Core/GreenshotResources.cs similarity index 95% rename from src/GreenshotPlugin/Core/GreenshotResources.cs rename to src/Greenshot.Base/Core/GreenshotResources.cs index b4de5d007..29248012e 100644 --- a/src/GreenshotPlugin/Core/GreenshotResources.cs +++ b/src/Greenshot.Base/Core/GreenshotResources.cs @@ -1,49 +1,49 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Drawing; - -namespace GreenshotPlugin.Core -{ - /// - /// Centralized storage of the icons & bitmaps - /// - public static class GreenshotResources - { - private static readonly ComponentResourceManager GreenshotResourceManager = new ComponentResourceManager(typeof(GreenshotResources)); - - public static Image GetImage(string imageName) - { - return (Image) GreenshotResourceManager.GetObject(imageName); - } - - public static Icon GetIcon(string imageName) - { - return (Icon) GreenshotResourceManager.GetObject(imageName); - } - - public static Icon GetGreenshotIcon() - { - return GetIcon("Greenshot.Icon"); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Drawing; + +namespace Greenshot.Base.Core +{ + /// + /// Centralized storage of the icons & bitmaps + /// + public static class GreenshotResources + { + private static readonly ComponentResourceManager GreenshotResourceManager = new ComponentResourceManager(typeof(GreenshotResources)); + + public static Image GetImage(string imageName) + { + return (Image) GreenshotResourceManager.GetObject(imageName); + } + + public static Icon GetIcon(string imageName) + { + return (Icon) GreenshotResourceManager.GetObject(imageName); + } + + public static Icon GetGreenshotIcon() + { + return GetIcon("Greenshot.Icon"); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/GreenshotResources.resx b/src/Greenshot.Base/Core/GreenshotResources.resx similarity index 98% rename from src/GreenshotPlugin/Core/GreenshotResources.resx rename to src/Greenshot.Base/Core/GreenshotResources.resx index 521a6125f..ea1760d58 100644 --- a/src/GreenshotPlugin/Core/GreenshotResources.resx +++ b/src/Greenshot.Base/Core/GreenshotResources.resx @@ -1,471 +1,471 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - - AAABAAUAAAAAAAEACAClFwAAVgAAADAwAAABAAgAqA4AAPsXAAAgIAAAAQAIAKgIAACjJgAAGBgAAAEA - CADIBgAASy8AABAQAAABAAgAaAUAABM2AACJUE5HDQoaCgAAAA1JSERSAAABAAAAAQAIBgAAAFxyqGYA - ABdsSURBVHja7Z1fqFVVHsf3YQqnUTJQSJMcujkK3UHuFW5geBXGYK5B0EP6Gto8zIsG8zKY82rCvKXP - 6bv2FqQP9eAfEhS8Eilozo0xTAOFbGycKLjTd9u6nnvvXnuvvff6/dbea30/cEioPPucs9Z3/dbv72By - cnI2I4QkyYACQEi6UAAISRgKACEJQwEgJGEoAIQkDAWAkIShABCSMBQAQhKGAkBIwlAACEkYCgAhCUMB - ICRhKACEJAwFgJCEoQAQkjAUAEIShgJASMJQAAhJGAoAIQlDASAkYSgAhCQMBYCQhKEAEJIwFABCEoYC - QEjCUAAISRgKACEJQwEgJGEoAIQkDAWAkIShABCSMBQAQhKGAkBIwlAACEkYCgAhCUMBICRhKACEJAwF - gJCEoQAQkjAUAEIShgJASMJQAAhJmOgF4MllP2dP/+GH/M8rx77L7t9Ylv304Ins4e0l2X/v/Db04xES - lCgF4Her/pc9v+PbbNXkvezpdT9Y/7uHd5Zkt8+tzL4++Wz2/ZdLQz82IepEJQDY+Ov33Myen/q29v97 - 7/Ly7Nqx32f3ppeH/hiEqBGNAIzsvJVv/ieX/tzq75n5cE12/eja/JpASOxEIQBj715vdOrb+P7G0uyz - fRspAiR6ei8Avje/gSJAUqDXArBh97+z9btviv398AtABAiJld4KwIrx+9kr738u/j5XjoxkMyfWhP64 - hIjQWwF45fDn2Yqx++Lv89MPT2Sf7pzgVYBESS8FQOv0N1w/tjYPERISG70UgIn3rmarttxTez9YAad2 - bA79sQnxTu8EAKm9Ux+fV3/fiwdeyu6cXRH64xPild4JANJ7Jw5eVX9fJAhdOTwS+uMT4pXeCYB06M9G - m5AgfBYoRDJ/BihK+vk/v8nuXn6G6cckGL0TAO37vwGFQ5/setn5v0cFItKTYbFUpSfDx4DrBYqSKAZE - k94JgFb4r4iPtk5W/jcoSBrdN9NYpGBpfHHkRVYnEhUoADWoEgCUIGPzty1IAkxAIhr0TgBCXQFQG3B6 - zybrv8fGH3nzltf3/PrUs9nl99arf1aSDr0TgC46ASWfiSJAJOmdAIQKA9qyATWyEi8fWp87CAnxTe8E - IFQi0Om3Ny1yzOFZth29lD216kfR92Y9ApHCSQDg2cZJh38ivIWFj4aaprEmQleaDTalegDYsIUANa8j - vAoQCawCgE0OrzZi2S4nHJxk8Fojni19UnWhGAjfz/YTF714/F35dNcEOxkTrxQKAE62F3Z902hxw1xF - Tz3pEFbocmCI49j+6+LvPwxDg8Q38wQAJj7CbGWttF2B1/ziuy+JWQN41q3HpsVPYFsRUIhwZFUokpC6 - zAkA7vY4VX1uKNydLxwYFctqkz6Fy+7dUyfPq5r/hlOvbaYzkHgjFwCJzW+ACODUklq0kk1BbactrI/t - xy+KfJ4qPntnY+16ATxvPiTll985d+gOXZ1gqRlHrrYzl4Rn8Kcdm2ex+X2Y/Takm2v6zsK7c25FfvLb - REvbCTlMHQHAc+YFSTWuKvjs8DOwKCkNBn89sWbWdwprEdIOLJxwsAbaWDGuDsyQAuDyPeKUx3fRxkkK - 0YYI0iKIm8E/ZzOVRCCNZBaE5nDiNYlg4L6Pze+y4LtsAfgQQgN+M4gAOyHFi5oAAK3mmhACbAS8sFlt - mwGnHBY3XnVOOtylt31wSetrm0eZAEg5RZmKHC+qAlC3qYYvYBI/tfpxMhOskLaRidfPnFX/HMCWDCRd - I9HE+Ui6j6oAgKKc+j6CGgBJx2kRNgHVyEpkPUKcqAtALNls8DWM7p1RfU9bY1KtpCTWI8SHugA0XUTm - Pr983YNHBUm/nnaI1+NUgnl6+9xKNesiRC5AkfWk7ZCMxYIjj1AXgDo5Adhk8OjDueVq3sJMhoUBp5W0 - uapZlWj73rQrI2kFxEVnBaBNQRKAEKC5pmQIS9MKKHLCheqNwHTkeOicAGBR407rq9JP+sTS6Algu/uH - 6o7EKUnxoC4ASDVFlWAR2PwSacnSIiBZmgwfBwSz6MQN1R/RRz6HaSwDTGMZoo+6ANgWj9TmN0iKgNSz - l21+EKpFepPaDmx4+HIwIcn2PeHvxTUH/hsKgg7qAmBLKNEIZUmGICECcMj5+gwu/RT6IACIUvxx779q - iyPeAwcFk49kURUA25htrVCWRjIL8gPW77nZ2HmJZ/zq+HNOJnaXBcCXLweWG/wfdDrKoCoANjNccyFr - hLGaFCVh48P0xeZ3NX+7KgC++0vgKjR9aAPzDwRQFYCiPPYQlXWaYSxbAhMwzThMQVJdQglAmSNXqrkM - BBKiQxHwy+Dv08tnNRaR7eTVTmQBsVS3dS0KIN2nscopSuoz+PPOiVnp5ppld+8QvfXKTrA+Eaovgc2R - q2GRxPLbdYW8J6B0c03bgglVV29zRvYRbQG1fXeabdJZmuyPua7AIZpJhOysE0s6q8RU4jJsWYmvHr8g - PiLNIN1jMiXmzQXwOd/epZ1UqDssiOUU0a5KLHLkhkhJZlWiHxZNBoJZjsQNjYaSFAA/aH2PNudfiCEp - NkuE1MM6GxDWAF51hKBu9laIphqGmARAOo0alM1JCOHI5ZQkP1ROBzZDJeamAw8tMvwIZqhE3caaIKQP - 4KOtk0HeVwrJ4S5lMfiQDVLb/IZmPeNluH9jWb6GU7paOI0HlyLUhJ1QzUmlkRCBqgScLrdIXwgOMli1 - VdcVfGYcaKgbiV0MggoA0PQeG2LuauNzwCssPMTcyyy7EFOSDa4CgI0Pv1aTdYZrLRrLxCoEgzf2bcwF - IFRNtnYYC6TQ0KLtiHfXgqQu+3F8VmhqzbTQZlEtQNNhGU3RvgbElARUhSlKwintcvrhaoScDZi+rjkS - Xb0C4Do0vv+aV8eo9Mj7EJQWA9UZl9UGzXqAWJW8CmwINOPAgBQUJhng+IL1d/fyM43M3C4mc0nWJMSW - hORUDSi9abSsAOlR5akSYkpSmSNXemhLTDkIzuXA0uaPRjJLTLH/LhGiLNnmyNVKioplLdXqByBdjil5 - FYilBLiLhIgEFG1ATX9SLKHk2g1BpMsxJUQg1Xu/FhqzCYexbT7t3hIxHCqNOgJJz/fzFRqExx93tb7/ - SH1As67DtvG0U5JjcAg2EgCN5ppNu8kaYKlg87O9tA6wAuB8k07qsm26UENS+l5W3rgnoJYn1DV9E6SU - wtlFpEOC+H3P7B4vFPUQCWWg70lljQVAe148Tph5zTV/nSqDxWDi2DF4ZfuOpEOwbLOFapDad/9Sq67A - MThBiH98i4BLc5kQJcmg7z0KWwlAzEU1pB2w1pCK29Yn4DoTIEQyEui7I7CVALRpygAT3qSnDoPUVPzY - dN71nyYDUgx1CpIABaAZrQeD1GnKgAUBpx4WRZV3H7He2+dW1pqUQ7oJfvfckYvGMhX3dJjUMPXrXi1D - lJWDvlvBagLQpjxVqyiJ6LCwGw+sPjiT2zhx6QRshrgA+CrLZFIPKSNUg9m+1wSICgCUHt1pfHpn+25y - ERlC9CaMobdEKwEoK4iQ/EEoAqQIbT9ADOuwlQDYYqDSQyIBcxDIQrSrEouGpPQNkUQgDYdMWVooSRct - KyCG0x+0EoCiQgjNFlGx/AjEHxrrL6bDp7EA2DafdjgmBjOM+EW6MKjvBUDDNBaAoo0XwhMbU3824g+p - 5iCx+Z4aCYBt04UoyYylNRPxj28RiG3zg9oCUNYXMFQ2Fq8BxAbSjyEEbSJSrgVJfaSWAFQ5P0IVZMR0 - JyP+aVqUBOsSab6xnfrDOAsAvowLB0atKogveerj80E+RN/zsYke+cj78fuPhqQUhAtx2qM2wUzHih0n - AUDCDzz+Zd1/Qk6IoQCQpiBpDdOSQs3GDE2pAODUx2RUFyWkABDSPxYJgGms2cQECuUDkG5TTkisDP5y - dG0uAGiqCRO/jaczVF+2vpdkEhKKweTkZKty4GFQ+utjFntd6nQlIoQ8xqsAINQyundG9QP0vSsrISHx - KgAhQoExZmcRooVXAQCaAxq1h5MQEhveBUBzRDPDf4S0w7sAAI0GjW1mEhBCHiEiAECyMAimPwqSYizO - IEQTMQGAQxAi0LYd+EK4+Qnxx+CtwyOzUll0EAHkBviyBLj5CfHL4OCDJ2al+5v58Am4FCQRQuqR1wJo - NNdEdGD9npu1Q4QYvghPP1N9CfHPXDGQVlcdMyA0HxQ5fr+wdgCbHjXZSPChuU+IHHMCELKiztRk85Qn - RJc5AWBcnZD0mNcPgFV1hKTFPAFoUlePWQDos7Z83YNF4T6E7XCHx995+9xK3ucJ6RiNBQCbHuG9OnPY - cM2An4HVe4R0g9oCAM/9+P5rrQYwwsuPXoO0CAgJSy0B8NnwA9cDTBeiNUBIOJwFgLPWCIkPpyiAdKsv - TvYhJAyVeQAaE39jmrdOSJ+ozATUGvjJ5p6E6FNaC4B8/YmDV9Ue5vTbmxgZIESR0mpA7XHfGlWJhJDH - 5AJQdPprNvcchunIhOiRjwYr6qyLTL+x/dfVH4gRAUL0sPYE1OzvPwxbfROih1UAtO//BkYDCNHDKgDb - jl7y3tHXBdQJoPEnIUQeqwC8fuZskAeiABCiR+euABQAQvTonADMfLgmrxIkhMhjFQCN+X5FhGxOSkhq - WAVAOw3YoNWenBBSMRtw6uT5wr79UrAzMSG6lArA6L6ZbOTNW2oPQ/OfEF1KBQD1AFuPTatYAegJ8OnO - Cc7+I0SRyvHgWs5AtgYjRJ9KAQDSWYFM/yUkDE4CIHkVgOMPiT80/QnRx0kAAHoDIjnIpwhw8xMSFmcB - ABjtPfHeVS8ZgjD70f2Hm5+QcNQSAEOTsWCGh3eW5FOB2PSDkPA0EgADhAAvF4sAJz42PT39hHSHVgJg - wNUAPoKVY98t+nd3Lz+Td/qlqU9I9/AiAISQfkIBICRhFglAmTmPKj0MD2W1HiFxMCcAKP+FQ2/VlnuV - /xM8+SjagUOPd3tC+svgjX0bZ8f3X2sU0kMBz1fHn8vFgEJASP+YNx68KbAILhwY5Vw/QnqGFwEAsAaQ - 2ccEH0L6gzcBABAB5PbTEggL/DnL1z3IVow/StBCohasNDhv8cLvA6GmM5d4FQDAxh5hQMXmC7u+yR25 - rgVbaMEORy6zM9PFuwAA1vfrgroMbP6mlZqoypw+tIGWW4KICAD47J2Nec4AkQM5GyjR9tWshT0Z00NM - ADjhRxaJ/gzg61PP5s5ckgZiAgDY418GnPxo09Ykd8MFjmhPB1EBoEkpg8bYNl7h0kBUAOgM9A+8/GP7 - r4u/D8KGn+x6OfTHJcKICgAXkX9ePX5BzPRfCFu1x4+oAICPtk6G/ozRoHX6Gyjg8UMB6BFoyOpSremT - iwdeYnp3xFAAegI8/1Mfn1d/35kP12RXDo+E/vhECApAT0Be/yvvf67+vr4mNpu6BPaH7BaiAsBkIH9o - zWgsoq6Iw1rJu0X/sunxKkpWgrCgYSycjExBDoeoANB89EcfBAAFSev33Myen/q21t8PMTAdpoguogJw - +u1NVHdPdF0AfDwfLEakITN7VA8xAWAIyS9dFQCf4+IAG8voIiYAzCf3y8jOW9no3pkg720TAN/ViMMw - CUkHEQHA6Q/PMb29/ggVBShz5ErWJLC7lA4iAsDkERleP3NW/T1tjlyNKwkPEnm8CwA9/3KEyAQscuTC - 27/12LT3XgRF8Copi1cBYDMJWdDsc+LgVbX3szlyx969XjvU1xT2mJTFmwDw5NchdDUgHH/bT1xUOf0N - 7Cshx+BvZ1fMtjErcUp8ceRF3vmV0HIG2lKAtSsSy56FtCefDYhFhTBTHSHgfMBwaJjgtiSuEH4IcOq1 - zVxnAsybDgznDu6ZEAQMllhoaiIkdP/GsrxVFE/8cEjG30FZDF7zCjJMmxZlWNdPrf5x3sRrrGMzJCVl - Fo0HJ/1ASgSqEnBChCJB3WiAGZSyesvdUsGCkxGHGT5zij0QKQA9BiKA64APk9w1BbfrAoCNP7pvptF3 - kqI/iwIQAXDMITGnqWmO5q2I4LgU4XRZAHylS+P7gBim4HMYvHV4ZJaDIvsPrAH4b7AJXK8FyNuAI7fO - PbirAuDbMYrIAzpax74v5vIA4ODDF5ziPSg2YAbDkYvpQXDmGnCiYbPDAdbUzA0lAGXp5VJRkRRSkRcl - AuFUgDkY84cmzdEYSlKEbcqUdE1C7DkIhZmAUL4LB0aTD5GQxYQoS7alJGslRcVcj2BNBWY5JikC14vt - xy+qvqctzVzTGol1zmVpLUAKdyBSH+1rQNHm0+6PEGuhW2UxEOf7kYVobj7bxtNOSY61KtGpGpCTYslC - NDYgNt2Z3eOLTv9QQ1JibHTjJADs708WolEWbEtLDtUeLcZrgHM/AFoBZCHIM4A/QEIEyjZbqA7JMR6E - zgIQo/qR9kiIQNVa0+xItJDYRt05CwD7/BMbCA3CJ9C2MhF3foT7qtqBh0pGAskKAGjTlAEnBRbKcGoq - ZsM9vL0kyvhqiiBJCKPBmlgDOPWvH13rtBYoAP6oJQB1/QBw1qBSDUUqZYsC1gXEoG5hCukm5jevihLg - d799bmX21fHnah0CKPcdefOW+ueK0QoWEQBsfDhqmqg0HC2oyaYQxAHWAiw/vAxtLT86Af3hVQAQGoIJ - 6EOd2WWY2AgVBoyxJsCbAEi0qILiIgsxtuwr0p6pk+dVW5ODGKdd1xIAW0GEZJPK2Msx+wKcuGiqieaa - w45c9BaAOQ+zXnNzaIcCY7z/A2cBQIjm1I7Nhf9O2ivLHIQwQNjh2YdTz6XdGDYJQnhw5kpbbdpViTGa - /8BZAGxFQVr14THmYXcZONrQVbeJmY3DAp596Q2jZQXEWggEnAUg9JioWE2wrgFTf3z/NS/XOVzfpg9t - ELsaaA0pjfnwcRIAm/mvHY6p6llP2iGR1ivdWEZ6YGrs108nAbDdf7SnxNAhKIdkYY+0CEjNK0xhvVUK - QOh+bAuJtTVTSKRHjQHpzeRbBFJpjlspALbYZ6hsLF4D/KOVWivtScehBP9FG6sU1gpqElIZR14qAGWb - LVRBRtMMQdMr3/zT4KNXfp/RDqdpWHA4nFxDl8PUKUiKBasAVJ20oQSgbj42FgJers+KRZDSoEjtwhrN - eHpekPTLK09gKhADnPZm0jVesZv7RSwSANeZACFSMYGrALQ1B/E+8P7Gfhpo/45lCWXSDFt+WN8pbviF - zAmASd5wzeIKNSfeRQB8nWquDSr6SihHLtvLdYfBP75cOosFjlcdReziFQDebHSm8f1csVYmhnLkxppW - 20cajwfX7stuKFs8ks905chIdJ7hUCLeZNaEmX4MqwXFSAtDljgY4Mg1d3riRmMBCDEjDtjSMjVOs9hM - 1y5acQtBlAI9Jqq6Sg1T9zqbMo0FAJlj2z64pP7ARX0JtZ4ltlFpXReAtqKeWky/CY0FAGw7ekk0e2wh - NtNRcyHHdH/tqgD4zkzEukFEJxbh9kkrAZDKwbZRZIJrJ7KEDGP5posCIJWWjFRkvCdFYD6tBABohQNt - iyZEh9hYykNDdde1WVHSNQkxNvVsS2sB0Iol22oSQuQjxFIiKl1Ka8MmoBqRpZiucD5oLQBA+iSxpSVr - m/+GWJqThJiya7tCaSYlsaL0MV4EAEi1Zyo7bUNlsoEmE2IQrVi95W7+3PjzcFgLd1QsShPH1lqg2s01 - bb+npj8iFgvOB94EAPheTFXmWqhMNlAnJwDOUjxrnasKPNcIX0nnHWiLaNHpG0LIaQU8wqsAANwrIQRt - CkxgYqOXXNXi77oA+KhP1whhaWV12k7eENN+Y8zsbIJ3AQCmnXTdrrJ1M7i6LAA+n026pZZGc9eyzroh - HLmMCDxCRAAMJn/b5HAXLTAzGNTUZNchlBcblE1KljjRpEVA2gy3CWYoRy6IbdJvE0QFoIjhmuy299tQ - 6chlyUCSVklfm2uWNZcJ6ciNcdRXXdQFwDchGpPYUpI1FrN0RpsPH44BgoXvqUzotbNJh4mtuKsJ/wfb - mhgAeoKg9wAAAABJRU5ErkJggigAAAAwAAAAYAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8 - PDwAOkE+ADpEPwA5RUAAN01DADdORAA4SUEAOExDADVRRAA0VUYANFhHADNaSAA0WUgAMl1JAC9nTQAu - ak4ALWxPADFgSwAwY0wAMGRMAC1uUAAscVEAKnRSACp3VAApeVQAKH1WACeAVwAmg1gAJYVZACSIWgAk - i1wAIo1cACGSXgAhlF8AH5lhAB6cYgAdn2QAIJZgACCYYQAcomQAG6ZmABykZQAbqGcAGqpoABmtaQAX - smsAFrVsABixagAVuW4AFLxvABO/cAAUvnAADs52ABLAcQARx3MAEcd0ABDKdAAO0HcADdJ4AAzWeQAL - 2XoADNh6AAndfAAH5X8ACOJ+AAjkfwAH5oAABumBAATuggAD8oUABPCEAAL1hQAB+IcAAfqIAAD+iQBx - /50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAIkAAACrAAAAvPAAAO8AAAIP8SAD3/MQBb - /1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAwcAAAPZAAAEywAABZzwAAZ/AAAHj/EQCK - /zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABAUAAAWnAAAHSQAACOsAAAqc8AAMLwAADR - /xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAvJgAAUEEAAHBbAACQdAAAsI4AAM+pAADw - wwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAAAAAALxQAAFAiAABwMAAAkD4AALBNAADP - WwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD///8AAAAAAC8DAABQBAAAcAYAAJAJAACw - CgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/1NEA////AAAAAAAvAA4AUAAXAHAAIQCQ - ACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/scgA/9HfAP///wAAAAAALwAgAFAANgBw - AEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/kdwA/7HlAP/R8AD///8AAAAAACwALwBL - AFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2cf8A95H/APmx/wD70f8A////AAAAAAAb - AC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0Uf8AwnH/AM+R/wDcsf8A69H/AP///wAA - AAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBYMf8AcVH/AIxx/wCmkf8Av7H/ANrR/wD/ - //8AAAAAAiYwJgIHSkpKSkkzBz1KSkEMAAAAJkpKSkAHPUpKSko7AAAAAAAAAAAAAAAAAAAAOUpKSj0C - SUpKSkoqAAIUFAIAAAACSUpKSkohHkpKSkodAAAAAAAAAAAAAAAAAgAUSkpKSkoXKUpKSkkMAAAAAAAA - AAAMSkpKSkorAB05ORsAAAAAAAAAAAAAAAAARBQZSkpKSkobAB4zLAwAAAAAAAAAAAAAQ0pKSkoZAAAA - BSQxHgIAAAAAAAAAAAAASkIFRUpKSkkFAAAAAAAAAAAAAAAAAAAAD0FKSSoAAAADQEpKSjMAAAAAAAAA - AAAASkoFFUJKQxcAAAAAAAAAAAAAAAAAAAAAAAIRBRMPAQAeSkpKSkoMAAAAAAAAAAAASkYCAAAHAAAA - AAAAAAAAAAAAAAAAAAAAAAAHOUpKQg0mSkpKSkoOAAAAAAAAAAAASR4AAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAApSkpKSjgRSkpKSkMCAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAACKkE9GQA4SkpKSkUB - HERKPhMAAAAAAAAAAAAAOUlBFwAAAAAAAAAAAAAAAAAAAAAvSkpKSRcvSkpKSj0AAAEHAAAAAAAAAAAA - AAAASkpKSREAAAAAAAAAAAAAAAAAAAJFSkpKSjAKQ0pKRxUAAAAAAAAAAAAAAAAAAAAASkpKSiYAAAAA - AAAAAAAAAAAAAAdGSkpKSjAABx4gCQAAAAAAAAAAAAAAAAAAAAAASkpKSh4AAAAAAAAAAAAAAAAAAAAs - SUpKShUAAAAAAAAAAAAAAAAAAAAAAAAAAAAASkpKQwUAAAAAAAAAAAAAAAAAAAACJEE5FwAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAIzcsDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAXMzMXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlKSkpKGwAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADlKSkpKPQAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAj1KSkpKQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAHyNKSkpKKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAALwIqRUUsAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAEXIQ8A - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAATdKSkokAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAF0pKSkpKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAASjcFJkpKSkpKFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIaIREAAAAAAAAA - AAAASko1D0pKSkpJBwAAAAAAAgAAAAAAAAAAAAAAAAAAAAAABj1KSkkeAAAAAAAAAAAASkpKAClKSkke - AgAAAAAAAAAAAAACAAAAAAAAAAACAgAAIUpKSkpFAgAAAAAAAAAASkpDAAAMFQURBQAAAAACAAAAAgAA - AAAAAAAAAjBKSTACL0pKSkpKCQAAAAAAAAAASkohAAAAEUFKSS8CAAAAAAAAAAAAAAAAAAAAKkpKSkoo - HEpKSkpDAAAAAAAAAAAALhcAAAAAPUpKSkoeAAAAAAIAAAAAAh4zLAwAQUpKSko+ATFKSkYVAAAAAAAA - AAAACS09LgkHSkpKSkozAAAAAAAAAAAAL0pKSkYJOkpKSko5AAANFAMAAAAAAAAAAAAAPkpKSkEHRkpK - SkopAAIAAAwXBQIHSUpKSkojGEpKSkkXAAAAAAAAAAAAAAAAAAAASkpKSkoZHkpKSkMFAAAAKUpKSR4M - SkpKSkoqABAtLw8AAAAAAAAAAAAAAAAAAAAASkpKSkoaABQpIQcAAAATSkpKSkkMPUpKSkoUAAAAAAAA - AAAAAAAAAAAAAAAAAAAAQ0pKSkYHAAAAGz5DKwceSkpKSkoXDDlKQx4AAAAAAAAAAAAAAAAAAAAAAAAA - AAAAEThGORMAAAAXSkpKSjAUSkpKSkoMAAICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx - SkpKSkkCMEpKSSoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwSkpKSkUCABUhDgAC - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPSkpKSisCAAAAAAAAAQAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFTg9JgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAgAAAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA - AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA - AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA - AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA - AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA - AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA - AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCKAAAACAAAABA - AAAAAQAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADw9PQA6QT4AOkQ/ADlGQAA3TUMAN05EADhJQQA4 - TEMANVFFADRVRgAzWkgANFhIADJdSQAvZk0ALmlOADFhSgAwY0wAMGRMAC1tUAArc1IALHJRACp1UgAq - d1QAKXlUACh9VgAngFcAJoJYACWGWgAliVsAJItcACOOXAAkjFwAIZJeACGVXwAfmWEAHpxiAB2fZAAg - lmAAIJhhAByhZAAbp2cAHKVmABuoZwAaqWgAF7JrABezbAAXtWwAGLBqABa4bQAUvXAADs52ABLBcQAR - xXMAEch0AA7QdwAN0ngADNV5AAvaegAK3HwACeB9AAjlfwAH5oAABumBAAPyhQAE8YQAA/SFAAH4hwAB - +ogAAP6JAACwNgAAz0AAAPBKABH/WwAx/3EAUf+HAHH/nQCR/7IAsf/JANH/3wD///8AAAAAAAIvAAAE - UAAABnAAAAiQAAAKsAAAC88AAA7wAAAg/xIAPf8xAFv/UQB5/3EAmP+RALX/sQDU/9EA////AAAAAAAU - LwAAIlAAADBwAAA9kAAATLAAAFnPAABn8AAAeP8RAIr/MQCc/1EArv9xAMD/kQDS/7EA5P/RAP///wAA - AAAAJi8AAEBQAABacAAAdJAAAI6wAACpzwAAwvAAANH/EQDY/zEA3v9RAOP/cQDp/5EA7/+xAPb/0QD/ - //8AAAAAAC8mAABQQQAAcFsAAJB0AACwjgAAz6kAAPDDAAD/0hEA/9gxAP/dUQD/5HEA/+qRAP/wsQD/ - 9tEA////AAAAAAAvFAAAUCIAAHAwAACQPgAAsE0AAM9bAADwaQAA/3kRAP+KMQD/nVEA/69xAP/BkQD/ - 0rEA/+XRAP///wAAAAAALwMAAFAEAABwBgAAkAkAALAKAADPDAAA8A4AAP8gEgD/PjEA/1xRAP96cQD/ - l5EA/7axAP/U0QD///8AAAAAAC8ADgBQABcAcAAhAJAAKwCwADYAzwBAAPAASQD/EVoA/zFwAP9RhgD/ - cZwA/5GyAP+xyAD/0d8A////AAAAAAAvACAAUAA2AHAATACQAGIAsAB4AM8AjgDwAKQA/xGzAP8xvgD/ - UccA/3HRAP+R3AD/seUA/9HwAP///wAAAAAALAAvAEsAUABpAHAAhwCQAKUAsADEAM8A4QDwAPAR/wDy - Mf8A9FH/APZx/wD3kf8A+bH/APvR/wD///8AAAAAABsALwAtAFAAPwBwAFIAkABjALAAdgDPAIgA8ACZ - Ef8ApjH/ALRR/wDCcf8Az5H/ANyx/wDr0f8A////AAAAAAAIAC8ADgBQABUAcAAbAJAAIQCwACYAzwAs - APAAPhH/AFgx/wBxUf8AjHH/AKaR/wC/sf8A2tH/AP///wAAABg2KgdEQ0M2DzY4EgAANkRDHDpEQzkA - AAAAAAAAAAEIREREITZDQyYAAAAAAAdDREQ1ETg4EQAAAAAAAAAAOxJEREQpBx8WAAAAAAAAADpERCEA - AB81KQAAAAAAAABEGy1EOwUAAAAAAAAAAAAABx8YDAARQ0REGQAAAAAAAEQNAAIAAAAAAAAAAAAAAAAA - Cz5DORZDQ0MfAAAAAAAAGAAAAAAAAAAAAAAAAAAfKgsmQ0NDFjFDOAcAAAAAAAA+QBsAAAAAAAAAAAAA - JkRDQBlDQ0MLAAIAAAAAAAAAAEREPwAAAAAAAAAAAAAwQ0NDBRwuFAAAAAAAAAAAAAAAREQ+AAAAAAAA - AAAAABRDQzEAAAAAAAAAAAAAAAAAAAA0Ng4AAAAAAAAAAAAAAAcPAAAAAAAAAAAAAAAAAAAAAAAcOC4C - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACURERCYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS - REREKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsrQzkFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAADQAAIS0RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABACFEREEDAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAEMcLURERAsAAAAAAAAAAAAAAAAAAAACJi4LAAAAAAAAREENQUQ0AAAAAAAAAAAAAAAAAAIA - ACpERDwAAAAAAABEPAAHER8YAAAAAAAAAAAAAAAYQUEXNURERAIAAAAAADURAAA2REQjAAAAAAAABx8W - ADxERDsUQ0QvAAAAAAAAHjsxB0RERDYAAAAAAAA6REQhOERENgAHCwAAAAAAAABEREQjNUREHgAAJjsw - CERERDULMzELAAAAAAAAAAAAAERERCQCFhYUAw9EREQhNkRDGwAAAAAAAAAAAAAAAAAAJEA1BwAIQEQ+ - FERERCYCFxEAAAAAAAAAAAAAAAAAAAAAAAAAACFEREQZKUA1AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - DUREQwsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCcNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAGAAAADAAAAAB - AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPDw8ADpBPgA6RD8AOkRAADdPRAA4SkEAOExDADZRRAA1 - VUYAM1pIADJeSQAxYEsAMGRMAC1tUAArc1IALHFRACp1UgAqd1QAKXlUACh9VgAngFcAJoJYACWFWQAk - iVsAJItcACONXAAkjFwAIpFeACGUXwAfmmIAHp5jACCWYAAgmGEAHaFkABumZgAcpGUAGqpoABitaQAV - uW4AFL5wAA/NdgASwXEAEcVzABDJdAAO0HcADdN4AAzVeQAL2HoACdx8AAjhfQAI5H8AB+eAAAbqgQAE - 7oMABPCEAAH4hwAB+ogAAP6JAFH/yABx/9MAkf/cALH/5QDR//AA////AAAAAAAALw4AAFAYAABwIgAA - kCwAALA2AADPQAAA8EoAEf9bADH/cQBR/4cAcf+dAJH/sgCx/8kA0f/fAP///wAAAAAAAi8AAARQAAAG - cAAACJAAAAqwAAALzwAADvAAACD/EgA9/zEAW/9RAHn/cQCY/5EAtf+xANT/0QD///8AAAAAABQvAAAi - UAAAMHAAAD2QAABMsAAAWc8AAGfwAAB4/xEAiv8xAJz/UQCu/3EAwP+RANL/sQDk/9EA////AAAAAAAm - LwAAQFAAAFpwAAB0kAAAjrAAAKnPAADC8AAA0f8RANj/MQDe/1EA4/9xAOn/kQDv/7EA9v/RAP///wAA - AAAALyYAAFBBAABwWwAAkHQAALCOAADPqQAA8MMAAP/SEQD/2DEA/91RAP/kcQD/6pEA//CxAP/20QD/ - //8AAAAAAC8UAABQIgAAcDAAAJA+AACwTQAAz1sAAPBpAAD/eREA/4oxAP+dUQD/r3EA/8GRAP/SsQD/ - 5dEA////AAAAAAAvAwAAUAQAAHAGAACQCQAAsAoAAM8MAADwDgAA/yASAP8+MQD/XFEA/3pxAP+XkQD/ - trEA/9TRAP///wAAAAAALwAOAFAAFwBwACEAkAArALAANgDPAEAA8ABJAP8RWgD/MXAA/1GGAP9xnAD/ - kbIA/7HIAP/R3wD///8AAAAAAC8AIABQADYAcABMAJAAYgCwAHgAzwCOAPAApAD/EbMA/zG+AP9RxwD/ - cdEA/5HcAP+x5QD/0fAA////AAAAAAAsAC8ASwBQAGkAcACHAJAApQCwAMQAzwDhAPAA8BH/APIx/wD0 - Uf8A9nH/APeR/wD5sf8A+9H/AP///wAAAAAAGwAvAC0AUAA/AHAAUgCQAGMAsAB2AM8AiADwAJkR/wCm - Mf8AtFH/AMJx/wDPkf8A3LH/AOvR/wD///8AAAAAAAgALwAOAFAAFQBwABsAkAAhALAAJgDPACwA8AA+ - Ef8AWDH/AHFR/wCMcf8AppH/AL+x/wDa0f8A////AAAMLSQhOTkTISMDADI5JC45LQAAAAAAABEmOTkR - LCcDAAAAAzg5KAYYGAQAAAAAADgUOC0DAAAAAwAAABEkDQMkOTQDAwAAADAAAwAAAwAAAAAAAAAkOScn - OTgGAAAAAB0RAAAAAAAAAAAkNhoyOTYEHg8AAAAAADk5CQAAAAAAAwM4OS8PJxQAAAAAAAMAADk4CAAD - AAAAAAAjMxgDAAADAAAAAAAAABEZDQAAAAAAAAAAAAAAAAAAAAAAAwAAAA85OREAAAADAAAAAAMAAAAA - AAAAAAAAABs5ORQAAAEAAAAAAwAAAAAAAAMAAAAAAA8WIAsAAAAAAAAAAAAAAAMAAAAAAwAAAAEGNjka - AAAAAAAAAAADAAAAAAAAAAAAADYWOTklAAAAAAAAAAAAAAADIycEAAAAADkgGiUKAAAAAAAAAAABGhoO - OTkhAAAAACgHACo5HgAAAAAADwsUOTkbNjgRAwAAACYxDjg5LwAABwMaOTgbOTkPAwYAAAAAADk5Jxoo - DwAbOTEhOTkMDAwAAAAAAAAAACo1EQAZNiQnOTkJHBMBAAMAAAMAAAMAAAAAAAAwOTgLJxwAAAAAAAAA - AAAAAAAAAAAAAAAWNCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQABAAEAAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAQAAAAIAAAAAEACAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8PT0AOkE+ADlGQAA3TUMAOElBADhMQwA1U0UANVVGADNbSQAy - XUkALmtPAC5sTwAxYUsAMGJMAC1vUAArc1IAK3RTACh8VgAngFcAJ4FYACaEWQAkiVsAH5piACGVYAAg - mGEAHKJlABunZwAaqWgAGa1pABa1bAAYsGoAFbtvABS8bwAPzXYAEsJyABHEcgAQynUADtF4AAzVeQAL - 2nsACt18AAjifgAI5X8ABuuCAATvgwAD84UABPCEAAL2hgAB+YgAAP6JAABQNwAAcEwAAJBjAACweQAA - z48AAPCmABH/tAAx/74AUf/IAHH/0wCR/9wAsf/lANH/8AD///8AAAAAAAAvDgAAUBgAAHAiAACQLAAA - sDYAAM9AAADwSgAR/1sAMf9xAFH/hwBx/50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAI - kAAACrAAAAvPAAAO8AAAIP8SAD3/MQBb/1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAw - cAAAPZAAAEywAABZzwAAZ/AAAHj/EQCK/zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABA - UAAAWnAAAHSQAACOsAAAqc8AAMLwAADR/xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAv - JgAAUEEAAHBbAACQdAAAsI4AAM+pAADwwwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAA - AAAALxQAAFAiAABwMAAAkD4AALBNAADPWwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD/ - //8AAAAAAC8DAABQBAAAcAYAAJAJAACwCgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/ - 1NEA////AAAAAAAvAA4AUAAXAHAAIQCQACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/ - scgA/9HfAP///wAAAAAALwAgAFAANgBwAEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/ - kdwA/7HlAP/R8AD///8AAAAAACwALwBLAFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2 - cf8A95H/APmx/wD70f8A////AAAAAAAbAC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0 - Uf8AwnH/AM+R/wDcsf8A69H/AP///wAAAAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBY - Mf8AcVH/AIxx/wCmkf8Av7H/ANrR/wD///8AAiUZLScLDgAtJSQiAAAAAB0rHQcFAAAAHBgFJhgAAAAV - AAAAAAAACwwwHiscAAAALxEAAAAAEDEcJRMAAAAAACoQAAAAAAUbCAAAAAAAAAAUKQcAAAAAAAAAAAAA - AAAAGi0IAAAAAAAAAAAAAAAAAAQWIgAAAAAAAAAAAAAAAAAoIi4CAAAAAAAAABkfAAAAIwAeFwAAAAcF - JiUhKwEAACcaLiYAEQwvJh8fAAEAAAApHgYdEjEkGRUAAAAAAAAAAAAJMR0UDAAAAAAAAAAAAAAAAA0C - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= - - - - - iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAwBQTFRFgICA//// - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODgHVgAAAAlwSFlzAAAOvgAA - Dr4B6kKxwAAAABZJREFUGFdjYAABRhAAs4hlkq4DZDgACywAM12jTsYAAAAASUVORK5CYII= - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAnBJREFUOE+dk11I - k1Ecxs+2q1DLqwRvvCgoM6mLvoTAC6WLSrDUYBcSGK6y6EMzc6a2NnERlVKhSEMTYWSyksTZh7KZGboU - HNmUKemcupnuI5tuqHs6/7cSUenrwMPhPf/n97wPB46IrVrHCwuTxCJR5EbxbHiUZHQnEzE2uhj18Wsw - zPPLGgQmdErli9Ws8C2VX8wFX9y0rmiWnJ9/dg38Qc02dZdKUlQ3DrcuBINIfQTItMDJWiBHByj1gMEK - 0OxY9rkrywEvb7OQdzclR6tKDjRUV522qh7Kl5q6unDqQTnuNbZD89qEyhYTNK9M0PcMwLewgOsFh5oH - 70oSbXfYBmZUiM8P1Se06Z4WBP5UvarFALffj+q6goDjTXJTf7k4nWVmp159ayhDnVYu1Ot7tvmnImB+ - ztX4Y6dZUYMRzrk5VD4uxPueWmTlpVxmCVlZF1wuG8pqVJj0eKA+s5cHRMNm2Iapvn3wjCRirGOHUF2j - 12PY7Ubx/SJ4vJMglsXLZJcWefrI+Ge09PZCGr8V105sQU3xdgx0HYHfJ4O5ebdQXVNXjLb2Csy4x0EM - sexgRka2f2kJvkAAEzz9VmkCatWR0JaEoqkiDJ26cDxRh2LQ6YSyQgGna0zwEkMs25+envON13P7fII+ - 2e3QGo1rVN/RAZPFvOwjhli2RyrNdfNEh9eL0elpdFutsPMmLl55peiMZuQhLzHEsl1paXlf5udhdTjQ - abEIu21mZl2t9BBDLItOSpKP8HSj2Yx+Xn9oauq3Ig95iSGWRcTFKVr57Q/zv9pnZ/9K5CWGWBYaG5sZ - EhNT+j8idt0X+S+H3wE2DYYIXysH6QAAAABJRU5ErkJggg== - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAm1JREFUOE+Nkl9I - U1Ecx39T31o9SBq97cWHiUIimKiQ0zFbbcJ1U2YkBtLuFYkQnMrcdKQyEUIwWk+GDy58EfUhmYoTRtKE - HitI8kGZIkEW/oF0um/nd3OyYUnn8rn3nMPn+733wNXYe3spOTQajVXMb55vpE/CiUTiqyB91+b1Ugry - j3gcWwcH2Nzfx8benspsJALhyII8qaeHUiHJ7U5F+Xl0hM3dXXzZ2cGn7W183NpCcG4OPISrmNvbdQZF - IaZOlolsNhvVOZ1U29XFtO4fH+ObeGtqyYuJCSTJM5s9Aqqqr1ez6s1ut5OtqYksHR1tB6Lg++HhhRL+ - Ej4OO+yqmbOCDLGwCuSsrKznLpcLl8EOu5wRBRkkSdJ1t9vdtyPOrCgK+vv74fV6L+DxeODz+VQnFouh - u7u7j7NksVj0o6Oj42tra3A4HOjs7ITT6URzczMkqQ7V1UaUl1egpOQ2zOZ7qjM/v4yBgcFxzlJNTU3l - 1NTU8urqKoxGowjLMJnMqKioFME7aRiNd1VndnYRIyOBZc6SwWBwRKPR9XA4jKKiIjQ0PBSS9a+YTLWq - 4xTX5OTbdc5SWVnZk1AohGAwCJ1OB7v9EazWB/+EnbGxMUxPT4OzVFxc7IpE3mFmJoS2tqcYHg5gaOgl - /P5ACq/E/A+tre1YXPygwlnS6/XupaUVLCysoLGx8b9IFnCWcnJyWrKzsweZzMzMIf5l7weA1++BN9HP - MPhacEv2o8o1iV8nJ2An6XOWxIK0Wi1dy82lG6Wlz9SfPmWcJhJg4qeniIsnO+xyhrPnBVcLC0lbUPD4 - Sn6+/zLYUd2zgt/AGvcWHCMAZwAAAABJRU5ErkJggg== - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAW1JREFUOE+NkL1L - QlEYh9/b4NzS1BgNShBRQQ3VGEGr/0BDBEG0uLRIFIREIX2ANhgZKphj/4PLASOi0i4SYWWmWH5y/bhv - 5yc4HTl04YHD+z4893AMGvB53S7Hg+1cNQxjBGtm/p4YerrdvXlsDfJ7s7MlCp4ukgD7U3QX8mx+ZDIm - A5wx6+/hKiEs0+drnNiY5WTynlOpZ85mcz1wxgw7OHCVwPECCXlVDoev2ec75EDggiORGMfjCQ5dXrHf - f8LRaAwKw1UCR/MkbLns2Da/mOZAsIMDVwn45ki0pWB1OlrgwFUCBzMkrG6X662WFjhwlcDeNIlGu82/ - zaYWOHCVgHeSRFX+vVSraYEDVwnsuEj8WBbnKxUtcOAqAY+TREleP1cua4EDVwlsj5MoNBr8WixqgQNX - CWyNkfis19ksFLTAgasE1kdJvMsHTOfzWuDAVQLuYRJf8oHeqlUtcOAqgRUHBZcdJP4D3H7gDzdsNup2 - mXizAAAAAElFTkSuQmCC - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAXJJREFUOE+lk0FL - AkEYhlvwv3jzoiDoQdCbdEnYf6CrqCgoHgRRAk/9EQVLdEGyFiQNMS+dvHnoEkgglGAmCL7NO6RMIZvU - wsMO3zzzzGk0ACf/+hjQNO1ccKlXKsYx0OUZeflXoFmtVsUS2P4CHboi0FQDrXK5jM12i/VmYwsduiLQ - UgNmqVTCuzj8tlrZQoeuCJhqoFMsFvG6XmO2WNhCh64IdNRAt1Ao4EXc/jSf20KHrgh01YCVy+Uwnkzw - vFzaQoeuCFhqoJfJZBCLxY6Crgj01EA/lUrB4/HA7XYfhHs78vk8A301MIzH4/B6vRiNHjAY3H+DM+7p - ug6fz4dsNsvAUA2Mo9Eo/H4/LOsOTqdTYprXEs64x0AwGEQ6nWZgrAYeDcNAIBBAu30r/6Reb0t2MwbC - 4TCSySQDj/uAeEyngqnL5fpoNG4QCoUktVpHspsxEIlEkEgk+AKnaoAP8kwwczgcF4fg3g+u9gEu/son - bfJW/NwRDyIAAAAASUVORK5CYII= - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAUNJREFUOE+lk79L - QlEcxW9/gqCrm6vg4uYoOAgOrqLk4ioP0r2Glhp0SSjoF1FE0BIUDU3RdIOGoKBVGlpapaHTObeuCPe6 - 9ITD5fs9n3Pue8JbAWBS/VSQRvPwKR/j3JgaZXVqPv5TzPOXLhYoZDEcQidVWyhw3qzfn3tBAWH7PRjg - uV7HV5JAM6USyX50u86btlrOCwoOCR7Q+Oz1cFcu473dhmbppdFwu8dq1e3EBgU0zB6NXQJvzSaui0U8 - VCq4LZWwn8vhLJ+HPDFiowUEzITADsGrQgFHmYzTSTYL7eSJiRZs0timRoTGhC956wXDXtrJEyM2eAIt - t34Be8NgTPLELCuQYe8Z9tK8ZBf+ieuEnxj20rzB26SYF7zCGsGEoVeW6NTMoJFiXlDAkFllqMOwTs2+ - IOYFBf/9oFJ9ibr0B4f94vVG3bWDAAAAAElFTkSuQmCC - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAUAAAAAAAEACAClFwAAVgAAADAwAAABAAgAqA4AAPsXAAAgIAAAAQAIAKgIAACjJgAAGBgAAAEA + CADIBgAASy8AABAQAAABAAgAaAUAABM2AACJUE5HDQoaCgAAAA1JSERSAAABAAAAAQAIBgAAAFxyqGYA + ABdsSURBVHja7Z1fqFVVHsf3YQqnUTJQSJMcujkK3UHuFW5geBXGYK5B0EP6Gto8zIsG8zKY82rCvKXP + 6bv2FqQP9eAfEhS8Eilozo0xTAOFbGycKLjTd9u6nnvvXnuvvff6/dbea30/cEioPPucs9Z3/dbv72By + cnI2I4QkyYACQEi6UAAISRgKACEJQwEgJGEoAIQkDAWAkIShABCSMBQAQhKGAkBIwlAACEkYCgAhCUMB + ICRhKACEJAwFgJCEoQAQkjAUAEIShgJASMJQAAhJGAoAIQlDASAkYSgAhCQMBYCQhKEAEJIwFABCEoYC + QEjCUAAISRgKACEJQwEgJGEoAIQkDAWAkIShABCSMBQAQhKGAkBIwlAACEkYCgAhCUMBICRhKACEJAwF + gJCEoQAQkjAUAEIShgJASMJQAAhJmOgF4MllP2dP/+GH/M8rx77L7t9Ylv304Ins4e0l2X/v/Db04xES + lCgF4Her/pc9v+PbbNXkvezpdT9Y/7uHd5Zkt8+tzL4++Wz2/ZdLQz82IepEJQDY+Ov33Myen/q29v97 + 7/Ly7Nqx32f3ppeH/hiEqBGNAIzsvJVv/ieX/tzq75n5cE12/eja/JpASOxEIQBj715vdOrb+P7G0uyz + fRspAiR6ei8Avje/gSJAUqDXArBh97+z9btviv398AtABAiJld4KwIrx+9kr738u/j5XjoxkMyfWhP64 + hIjQWwF45fDn2Yqx++Lv89MPT2Sf7pzgVYBESS8FQOv0N1w/tjYPERISG70UgIn3rmarttxTez9YAad2 + bA79sQnxTu8EAKm9Ux+fV3/fiwdeyu6cXRH64xPild4JANJ7Jw5eVX9fJAhdOTwS+uMT4pXeCYB06M9G + m5AgfBYoRDJ/BihK+vk/v8nuXn6G6cckGL0TAO37vwGFQ5/setn5v0cFItKTYbFUpSfDx4DrBYqSKAZE + k94JgFb4r4iPtk5W/jcoSBrdN9NYpGBpfHHkRVYnEhUoADWoEgCUIGPzty1IAkxAIhr0TgBCXQFQG3B6 + zybrv8fGH3nzltf3/PrUs9nl99arf1aSDr0TgC46ASWfiSJAJOmdAIQKA9qyATWyEi8fWp87CAnxTe8E + IFQi0Om3Ny1yzOFZth29lD216kfR92Y9ApHCSQDg2cZJh38ivIWFj4aaprEmQleaDTalegDYsIUANa8j + vAoQCawCgE0OrzZi2S4nHJxk8Fojni19UnWhGAjfz/YTF714/F35dNcEOxkTrxQKAE62F3Z902hxw1xF + Tz3pEFbocmCI49j+6+LvPwxDg8Q38wQAJj7CbGWttF2B1/ziuy+JWQN41q3HpsVPYFsRUIhwZFUokpC6 + zAkA7vY4VX1uKNydLxwYFctqkz6Fy+7dUyfPq5r/hlOvbaYzkHgjFwCJzW+ACODUklq0kk1BbactrI/t + xy+KfJ4qPntnY+16ATxvPiTll985d+gOXZ1gqRlHrrYzl4Rn8Kcdm2ex+X2Y/Takm2v6zsK7c25FfvLb + REvbCTlMHQHAc+YFSTWuKvjs8DOwKCkNBn89sWbWdwprEdIOLJxwsAbaWDGuDsyQAuDyPeKUx3fRxkkK + 0YYI0iKIm8E/ZzOVRCCNZBaE5nDiNYlg4L6Pze+y4LtsAfgQQgN+M4gAOyHFi5oAAK3mmhACbAS8sFlt + mwGnHBY3XnVOOtylt31wSetrm0eZAEg5RZmKHC+qAlC3qYYvYBI/tfpxMhOskLaRidfPnFX/HMCWDCRd + I9HE+Ui6j6oAgKKc+j6CGgBJx2kRNgHVyEpkPUKcqAtALNls8DWM7p1RfU9bY1KtpCTWI8SHugA0XUTm + Pr983YNHBUm/nnaI1+NUgnl6+9xKNesiRC5AkfWk7ZCMxYIjj1AXgDo5Adhk8OjDueVq3sJMhoUBp5W0 + uapZlWj73rQrI2kFxEVnBaBNQRKAEKC5pmQIS9MKKHLCheqNwHTkeOicAGBR407rq9JP+sTS6Algu/uH + 6o7EKUnxoC4ASDVFlWAR2PwSacnSIiBZmgwfBwSz6MQN1R/RRz6HaSwDTGMZoo+6ANgWj9TmN0iKgNSz + l21+EKpFepPaDmx4+HIwIcn2PeHvxTUH/hsKgg7qAmBLKNEIZUmGICECcMj5+gwu/RT6IACIUvxx779q + iyPeAwcFk49kURUA25htrVCWRjIL8gPW77nZ2HmJZ/zq+HNOJnaXBcCXLweWG/wfdDrKoCoANjNccyFr + hLGaFCVh48P0xeZ3NX+7KgC++0vgKjR9aAPzDwRQFYCiPPYQlXWaYSxbAhMwzThMQVJdQglAmSNXqrkM + BBKiQxHwy+Dv08tnNRaR7eTVTmQBsVS3dS0KIN2nscopSuoz+PPOiVnp5ppld+8QvfXKTrA+Eaovgc2R + q2GRxPLbdYW8J6B0c03bgglVV29zRvYRbQG1fXeabdJZmuyPua7AIZpJhOysE0s6q8RU4jJsWYmvHr8g + PiLNIN1jMiXmzQXwOd/epZ1UqDssiOUU0a5KLHLkhkhJZlWiHxZNBoJZjsQNjYaSFAA/aH2PNudfiCEp + NkuE1MM6GxDWAF51hKBu9laIphqGmARAOo0alM1JCOHI5ZQkP1ROBzZDJeamAw8tMvwIZqhE3caaIKQP + 4KOtk0HeVwrJ4S5lMfiQDVLb/IZmPeNluH9jWb6GU7paOI0HlyLUhJ1QzUmlkRCBqgScLrdIXwgOMli1 + VdcVfGYcaKgbiV0MggoA0PQeG2LuauNzwCssPMTcyyy7EFOSDa4CgI0Pv1aTdYZrLRrLxCoEgzf2bcwF + IFRNtnYYC6TQ0KLtiHfXgqQu+3F8VmhqzbTQZlEtQNNhGU3RvgbElARUhSlKwintcvrhaoScDZi+rjkS + Xb0C4Do0vv+aV8eo9Mj7EJQWA9UZl9UGzXqAWJW8CmwINOPAgBQUJhng+IL1d/fyM43M3C4mc0nWJMSW + hORUDSi9abSsAOlR5akSYkpSmSNXemhLTDkIzuXA0uaPRjJLTLH/LhGiLNnmyNVKioplLdXqByBdjil5 + FYilBLiLhIgEFG1ATX9SLKHk2g1BpMsxJUQg1Xu/FhqzCYexbT7t3hIxHCqNOgJJz/fzFRqExx93tb7/ + SH1As67DtvG0U5JjcAg2EgCN5ppNu8kaYKlg87O9tA6wAuB8k07qsm26UENS+l5W3rgnoJYn1DV9E6SU + wtlFpEOC+H3P7B4vFPUQCWWg70lljQVAe148Tph5zTV/nSqDxWDi2DF4ZfuOpEOwbLOFapDad/9Sq67A + MThBiH98i4BLc5kQJcmg7z0KWwlAzEU1pB2w1pCK29Yn4DoTIEQyEui7I7CVALRpygAT3qSnDoPUVPzY + dN71nyYDUgx1CpIABaAZrQeD1GnKgAUBpx4WRZV3H7He2+dW1pqUQ7oJfvfckYvGMhX3dJjUMPXrXi1D + lJWDvlvBagLQpjxVqyiJ6LCwGw+sPjiT2zhx6QRshrgA+CrLZFIPKSNUg9m+1wSICgCUHt1pfHpn+25y + ERlC9CaMobdEKwEoK4iQ/EEoAqQIbT9ADOuwlQDYYqDSQyIBcxDIQrSrEouGpPQNkUQgDYdMWVooSRct + KyCG0x+0EoCiQgjNFlGx/AjEHxrrL6bDp7EA2DafdjgmBjOM+EW6MKjvBUDDNBaAoo0XwhMbU3824g+p + 5iCx+Z4aCYBt04UoyYylNRPxj28RiG3zg9oCUNYXMFQ2Fq8BxAbSjyEEbSJSrgVJfaSWAFQ5P0IVZMR0 + JyP+aVqUBOsSab6xnfrDOAsAvowLB0atKogveerj80E+RN/zsYke+cj78fuPhqQUhAtx2qM2wUzHih0n + AUDCDzz+Zd1/Qk6IoQCQpiBpDdOSQs3GDE2pAODUx2RUFyWkABDSPxYJgGms2cQECuUDkG5TTkisDP5y + dG0uAGiqCRO/jaczVF+2vpdkEhKKweTkZKty4GFQ+utjFntd6nQlIoQ8xqsAINQyundG9QP0vSsrISHx + KgAhQoExZmcRooVXAQCaAxq1h5MQEhveBUBzRDPDf4S0w7sAAI0GjW1mEhBCHiEiAECyMAimPwqSYizO + IEQTMQGAQxAi0LYd+EK4+Qnxx+CtwyOzUll0EAHkBviyBLj5CfHL4OCDJ2al+5v58Am4FCQRQuqR1wJo + NNdEdGD9npu1Q4QYvghPP1N9CfHPXDGQVlcdMyA0HxQ5fr+wdgCbHjXZSPChuU+IHHMCELKiztRk85Qn + RJc5AWBcnZD0mNcPgFV1hKTFPAFoUlePWQDos7Z83YNF4T6E7XCHx995+9xK3ucJ6RiNBQCbHuG9OnPY + cM2An4HVe4R0g9oCAM/9+P5rrQYwwsuPXoO0CAgJSy0B8NnwA9cDTBeiNUBIOJwFgLPWCIkPpyiAdKsv + TvYhJAyVeQAaE39jmrdOSJ+ozATUGvjJ5p6E6FNaC4B8/YmDV9Ue5vTbmxgZIESR0mpA7XHfGlWJhJDH + 5AJQdPprNvcchunIhOiRjwYr6qyLTL+x/dfVH4gRAUL0sPYE1OzvPwxbfROih1UAtO//BkYDCNHDKgDb + jl7y3tHXBdQJoPEnIUQeqwC8fuZskAeiABCiR+euABQAQvTonADMfLgmrxIkhMhjFQCN+X5FhGxOSkhq + WAVAOw3YoNWenBBSMRtw6uT5wr79UrAzMSG6lArA6L6ZbOTNW2oPQ/OfEF1KBQD1AFuPTatYAegJ8OnO + Cc7+I0SRyvHgWs5AtgYjRJ9KAQDSWYFM/yUkDE4CIHkVgOMPiT80/QnRx0kAAHoDIjnIpwhw8xMSFmcB + ABjtPfHeVS8ZgjD70f2Hm5+QcNQSAEOTsWCGh3eW5FOB2PSDkPA0EgADhAAvF4sAJz42PT39hHSHVgJg + wNUAPoKVY98t+nd3Lz+Td/qlqU9I9/AiAISQfkIBICRhFglAmTmPKj0MD2W1HiFxMCcAKP+FQ2/VlnuV + /xM8+SjagUOPd3tC+svgjX0bZ8f3X2sU0kMBz1fHn8vFgEJASP+YNx68KbAILhwY5Vw/QnqGFwEAsAaQ + 2ccEH0L6gzcBABAB5PbTEggL/DnL1z3IVow/StBCohasNDhv8cLvA6GmM5d4FQDAxh5hQMXmC7u+yR25 + rgVbaMEORy6zM9PFuwAA1vfrgroMbP6mlZqoypw+tIGWW4KICAD47J2Nec4AkQM5GyjR9tWshT0Z00NM + ADjhRxaJ/gzg61PP5s5ckgZiAgDY418GnPxo09Ykd8MFjmhPB1EBoEkpg8bYNl7h0kBUAOgM9A+8/GP7 + r4u/D8KGn+x6OfTHJcKICgAXkX9ePX5BzPRfCFu1x4+oAICPtk6G/ozRoHX6Gyjg8UMB6BFoyOpSremT + iwdeYnp3xFAAegI8/1Mfn1d/35kP12RXDo+E/vhECApAT0Be/yvvf67+vr4mNpu6BPaH7BaiAsBkIH9o + zWgsoq6Iw1rJu0X/sunxKkpWgrCgYSycjExBDoeoANB89EcfBAAFSev33Myen/q21t8PMTAdpoguogJw + +u1NVHdPdF0AfDwfLEakITN7VA8xAWAIyS9dFQCf4+IAG8voIiYAzCf3y8jOW9no3pkg720TAN/ViMMw + CUkHEQHA6Q/PMb29/ggVBShz5ErWJLC7lA4iAsDkERleP3NW/T1tjlyNKwkPEnm8CwA9/3KEyAQscuTC + 27/12LT3XgRF8Copi1cBYDMJWdDsc+LgVbX3szlyx969XjvU1xT2mJTFmwDw5NchdDUgHH/bT1xUOf0N + 7Cshx+BvZ1fMtjErcUp8ceRF3vmV0HIG2lKAtSsSy56FtCefDYhFhTBTHSHgfMBwaJjgtiSuEH4IcOq1 + zVxnAsybDgznDu6ZEAQMllhoaiIkdP/GsrxVFE/8cEjG30FZDF7zCjJMmxZlWNdPrf5x3sRrrGMzJCVl + Fo0HJ/1ASgSqEnBChCJB3WiAGZSyesvdUsGCkxGHGT5zij0QKQA9BiKA64APk9w1BbfrAoCNP7pvptF3 + kqI/iwIQAXDMITGnqWmO5q2I4LgU4XRZAHylS+P7gBim4HMYvHV4ZJaDIvsPrAH4b7AJXK8FyNuAI7fO + PbirAuDbMYrIAzpax74v5vIA4ODDF5ziPSg2YAbDkYvpQXDmGnCiYbPDAdbUzA0lAGXp5VJRkRRSkRcl + AuFUgDkY84cmzdEYSlKEbcqUdE1C7DkIhZmAUL4LB0aTD5GQxYQoS7alJGslRcVcj2BNBWY5JikC14vt + xy+qvqctzVzTGol1zmVpLUAKdyBSH+1rQNHm0+6PEGuhW2UxEOf7kYVobj7bxtNOSY61KtGpGpCTYslC + NDYgNt2Z3eOLTv9QQ1JibHTjJADs708WolEWbEtLDtUeLcZrgHM/AFoBZCHIM4A/QEIEyjZbqA7JMR6E + zgIQo/qR9kiIQNVa0+xItJDYRt05CwD7/BMbCA3CJ9C2MhF3foT7qtqBh0pGAskKAGjTlAEnBRbKcGoq + ZsM9vL0kyvhqiiBJCKPBmlgDOPWvH13rtBYoAP6oJQB1/QBw1qBSDUUqZYsC1gXEoG5hCukm5jevihLg + d799bmX21fHnah0CKPcdefOW+ueK0QoWEQBsfDhqmqg0HC2oyaYQxAHWAiw/vAxtLT86Af3hVQAQGoIJ + 6EOd2WWY2AgVBoyxJsCbAEi0qILiIgsxtuwr0p6pk+dVW5ODGKdd1xIAW0GEZJPK2Msx+wKcuGiqieaa + w45c9BaAOQ+zXnNzaIcCY7z/A2cBQIjm1I7Nhf9O2ivLHIQwQNjh2YdTz6XdGDYJQnhw5kpbbdpViTGa + /8BZAGxFQVr14THmYXcZONrQVbeJmY3DAp596Q2jZQXEWggEnAUg9JioWE2wrgFTf3z/NS/XOVzfpg9t + ELsaaA0pjfnwcRIAm/mvHY6p6llP2iGR1ivdWEZ6YGrs108nAbDdf7SnxNAhKIdkYY+0CEjNK0xhvVUK + QOh+bAuJtTVTSKRHjQHpzeRbBFJpjlspALbYZ6hsLF4D/KOVWivtScehBP9FG6sU1gpqElIZR14qAGWb + LVRBRtMMQdMr3/zT4KNXfp/RDqdpWHA4nFxDl8PUKUiKBasAVJ20oQSgbj42FgJers+KRZDSoEjtwhrN + eHpekPTLK09gKhADnPZm0jVesZv7RSwSANeZACFSMYGrALQ1B/E+8P7Gfhpo/45lCWXSDFt+WN8pbviF + zAmASd5wzeIKNSfeRQB8nWquDSr6SihHLtvLdYfBP75cOosFjlcdReziFQDebHSm8f1csVYmhnLkxppW + 20cajwfX7stuKFs8ks905chIdJ7hUCLeZNaEmX4MqwXFSAtDljgY4Mg1d3riRmMBCDEjDtjSMjVOs9hM + 1y5acQtBlAI9Jqq6Sg1T9zqbMo0FAJlj2z64pP7ARX0JtZ4ltlFpXReAtqKeWky/CY0FAGw7ekk0e2wh + NtNRcyHHdH/tqgD4zkzEukFEJxbh9kkrAZDKwbZRZIJrJ7KEDGP5posCIJWWjFRkvCdFYD6tBABohQNt + iyZEh9hYykNDdde1WVHSNQkxNvVsS2sB0Iol22oSQuQjxFIiKl1Ka8MmoBqRpZiucD5oLQBA+iSxpSVr + m/+GWJqThJiya7tCaSYlsaL0MV4EAEi1Zyo7bUNlsoEmE2IQrVi95W7+3PjzcFgLd1QsShPH1lqg2s01 + bb+npj8iFgvOB94EAPheTFXmWqhMNlAnJwDOUjxrnasKPNcIX0nnHWiLaNHpG0LIaQU8wqsAANwrIQRt + CkxgYqOXXNXi77oA+KhP1whhaWV12k7eENN+Y8zsbIJ3AQCmnXTdrrJ1M7i6LAA+n026pZZGc9eyzroh + HLmMCDxCRAAMJn/b5HAXLTAzGNTUZNchlBcblE1KljjRpEVA2gy3CWYoRy6IbdJvE0QFoIjhmuy299tQ + 6chlyUCSVklfm2uWNZcJ6ciNcdRXXdQFwDchGpPYUpI1FrN0RpsPH44BgoXvqUzotbNJh4mtuKsJ/wfb + mhgAeoKg9wAAAABJRU5ErkJggigAAAAwAAAAYAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8 + PDwAOkE+ADpEPwA5RUAAN01DADdORAA4SUEAOExDADVRRAA0VUYANFhHADNaSAA0WUgAMl1JAC9nTQAu + ak4ALWxPADFgSwAwY0wAMGRMAC1uUAAscVEAKnRSACp3VAApeVQAKH1WACeAVwAmg1gAJYVZACSIWgAk + i1wAIo1cACGSXgAhlF8AH5lhAB6cYgAdn2QAIJZgACCYYQAcomQAG6ZmABykZQAbqGcAGqpoABmtaQAX + smsAFrVsABixagAVuW4AFLxvABO/cAAUvnAADs52ABLAcQARx3MAEcd0ABDKdAAO0HcADdJ4AAzWeQAL + 2XoADNh6AAndfAAH5X8ACOJ+AAjkfwAH5oAABumBAATuggAD8oUABPCEAAL1hQAB+IcAAfqIAAD+iQBx + /50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAIkAAACrAAAAvPAAAO8AAAIP8SAD3/MQBb + /1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAwcAAAPZAAAEywAABZzwAAZ/AAAHj/EQCK + /zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABAUAAAWnAAAHSQAACOsAAAqc8AAMLwAADR + /xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAvJgAAUEEAAHBbAACQdAAAsI4AAM+pAADw + wwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAAAAAALxQAAFAiAABwMAAAkD4AALBNAADP + WwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD///8AAAAAAC8DAABQBAAAcAYAAJAJAACw + CgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/1NEA////AAAAAAAvAA4AUAAXAHAAIQCQ + ACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/scgA/9HfAP///wAAAAAALwAgAFAANgBw + AEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/kdwA/7HlAP/R8AD///8AAAAAACwALwBL + AFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2cf8A95H/APmx/wD70f8A////AAAAAAAb + AC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0Uf8AwnH/AM+R/wDcsf8A69H/AP///wAA + AAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBYMf8AcVH/AIxx/wCmkf8Av7H/ANrR/wD/ + //8AAAAAAiYwJgIHSkpKSkkzBz1KSkEMAAAAJkpKSkAHPUpKSko7AAAAAAAAAAAAAAAAAAAAOUpKSj0C + SUpKSkoqAAIUFAIAAAACSUpKSkohHkpKSkodAAAAAAAAAAAAAAAAAgAUSkpKSkoXKUpKSkkMAAAAAAAA + AAAMSkpKSkorAB05ORsAAAAAAAAAAAAAAAAARBQZSkpKSkobAB4zLAwAAAAAAAAAAAAAQ0pKSkoZAAAA + BSQxHgIAAAAAAAAAAAAASkIFRUpKSkkFAAAAAAAAAAAAAAAAAAAAD0FKSSoAAAADQEpKSjMAAAAAAAAA + AAAASkoFFUJKQxcAAAAAAAAAAAAAAAAAAAAAAAIRBRMPAQAeSkpKSkoMAAAAAAAAAAAASkYCAAAHAAAA + AAAAAAAAAAAAAAAAAAAAAAAHOUpKQg0mSkpKSkoOAAAAAAAAAAAASR4AAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAApSkpKSjgRSkpKSkMCAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAACKkE9GQA4SkpKSkUB + HERKPhMAAAAAAAAAAAAAOUlBFwAAAAAAAAAAAAAAAAAAAAAvSkpKSRcvSkpKSj0AAAEHAAAAAAAAAAAA + AAAASkpKSREAAAAAAAAAAAAAAAAAAAJFSkpKSjAKQ0pKRxUAAAAAAAAAAAAAAAAAAAAASkpKSiYAAAAA + AAAAAAAAAAAAAAdGSkpKSjAABx4gCQAAAAAAAAAAAAAAAAAAAAAASkpKSh4AAAAAAAAAAAAAAAAAAAAs + SUpKShUAAAAAAAAAAAAAAAAAAAAAAAAAAAAASkpKQwUAAAAAAAAAAAAAAAAAAAACJEE5FwAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAIzcsDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAXMzMXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlKSkpKGwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADlKSkpKPQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAj1KSkpKQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAHyNKSkpKKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAALwIqRUUsAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAEXIQ8A + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAATdKSkokAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAF0pKSkpKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAASjcFJkpKSkpKFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIaIREAAAAAAAAA + AAAASko1D0pKSkpJBwAAAAAAAgAAAAAAAAAAAAAAAAAAAAAABj1KSkkeAAAAAAAAAAAASkpKAClKSkke + AgAAAAAAAAAAAAACAAAAAAAAAAACAgAAIUpKSkpFAgAAAAAAAAAASkpDAAAMFQURBQAAAAACAAAAAgAA + AAAAAAAAAjBKSTACL0pKSkpKCQAAAAAAAAAASkohAAAAEUFKSS8CAAAAAAAAAAAAAAAAAAAAKkpKSkoo + HEpKSkpDAAAAAAAAAAAALhcAAAAAPUpKSkoeAAAAAAIAAAAAAh4zLAwAQUpKSko+ATFKSkYVAAAAAAAA + AAAACS09LgkHSkpKSkozAAAAAAAAAAAAL0pKSkYJOkpKSko5AAANFAMAAAAAAAAAAAAAPkpKSkEHRkpK + SkopAAIAAAwXBQIHSUpKSkojGEpKSkkXAAAAAAAAAAAAAAAAAAAASkpKSkoZHkpKSkMFAAAAKUpKSR4M + SkpKSkoqABAtLw8AAAAAAAAAAAAAAAAAAAAASkpKSkoaABQpIQcAAAATSkpKSkkMPUpKSkoUAAAAAAAA + AAAAAAAAAAAAAAAAAAAAQ0pKSkYHAAAAGz5DKwceSkpKSkoXDDlKQx4AAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEThGORMAAAAXSkpKSjAUSkpKSkoMAAICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx + SkpKSkkCMEpKSSoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwSkpKSkUCABUhDgAC + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPSkpKSisCAAAAAAAAAQAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFTg9JgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAgAAAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCKAAAACAAAABA + AAAAAQAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADw9PQA6QT4AOkQ/ADlGQAA3TUMAN05EADhJQQA4 + TEMANVFFADRVRgAzWkgANFhIADJdSQAvZk0ALmlOADFhSgAwY0wAMGRMAC1tUAArc1IALHJRACp1UgAq + d1QAKXlUACh9VgAngFcAJoJYACWGWgAliVsAJItcACOOXAAkjFwAIZJeACGVXwAfmWEAHpxiAB2fZAAg + lmAAIJhhAByhZAAbp2cAHKVmABuoZwAaqWgAF7JrABezbAAXtWwAGLBqABa4bQAUvXAADs52ABLBcQAR + xXMAEch0AA7QdwAN0ngADNV5AAvaegAK3HwACeB9AAjlfwAH5oAABumBAAPyhQAE8YQAA/SFAAH4hwAB + +ogAAP6JAACwNgAAz0AAAPBKABH/WwAx/3EAUf+HAHH/nQCR/7IAsf/JANH/3wD///8AAAAAAAIvAAAE + UAAABnAAAAiQAAAKsAAAC88AAA7wAAAg/xIAPf8xAFv/UQB5/3EAmP+RALX/sQDU/9EA////AAAAAAAU + LwAAIlAAADBwAAA9kAAATLAAAFnPAABn8AAAeP8RAIr/MQCc/1EArv9xAMD/kQDS/7EA5P/RAP///wAA + AAAAJi8AAEBQAABacAAAdJAAAI6wAACpzwAAwvAAANH/EQDY/zEA3v9RAOP/cQDp/5EA7/+xAPb/0QD/ + //8AAAAAAC8mAABQQQAAcFsAAJB0AACwjgAAz6kAAPDDAAD/0hEA/9gxAP/dUQD/5HEA/+qRAP/wsQD/ + 9tEA////AAAAAAAvFAAAUCIAAHAwAACQPgAAsE0AAM9bAADwaQAA/3kRAP+KMQD/nVEA/69xAP/BkQD/ + 0rEA/+XRAP///wAAAAAALwMAAFAEAABwBgAAkAkAALAKAADPDAAA8A4AAP8gEgD/PjEA/1xRAP96cQD/ + l5EA/7axAP/U0QD///8AAAAAAC8ADgBQABcAcAAhAJAAKwCwADYAzwBAAPAASQD/EVoA/zFwAP9RhgD/ + cZwA/5GyAP+xyAD/0d8A////AAAAAAAvACAAUAA2AHAATACQAGIAsAB4AM8AjgDwAKQA/xGzAP8xvgD/ + UccA/3HRAP+R3AD/seUA/9HwAP///wAAAAAALAAvAEsAUABpAHAAhwCQAKUAsADEAM8A4QDwAPAR/wDy + Mf8A9FH/APZx/wD3kf8A+bH/APvR/wD///8AAAAAABsALwAtAFAAPwBwAFIAkABjALAAdgDPAIgA8ACZ + Ef8ApjH/ALRR/wDCcf8Az5H/ANyx/wDr0f8A////AAAAAAAIAC8ADgBQABUAcAAbAJAAIQCwACYAzwAs + APAAPhH/AFgx/wBxUf8AjHH/AKaR/wC/sf8A2tH/AP///wAAABg2KgdEQ0M2DzY4EgAANkRDHDpEQzkA + AAAAAAAAAAEIREREITZDQyYAAAAAAAdDREQ1ETg4EQAAAAAAAAAAOxJEREQpBx8WAAAAAAAAADpERCEA + AB81KQAAAAAAAABEGy1EOwUAAAAAAAAAAAAABx8YDAARQ0REGQAAAAAAAEQNAAIAAAAAAAAAAAAAAAAA + Cz5DORZDQ0MfAAAAAAAAGAAAAAAAAAAAAAAAAAAfKgsmQ0NDFjFDOAcAAAAAAAA+QBsAAAAAAAAAAAAA + JkRDQBlDQ0MLAAIAAAAAAAAAAEREPwAAAAAAAAAAAAAwQ0NDBRwuFAAAAAAAAAAAAAAAREQ+AAAAAAAA + AAAAABRDQzEAAAAAAAAAAAAAAAAAAAA0Ng4AAAAAAAAAAAAAAAcPAAAAAAAAAAAAAAAAAAAAAAAcOC4C + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACURERCYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS + REREKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsrQzkFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAADQAAIS0RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABACFEREEDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAEMcLURERAsAAAAAAAAAAAAAAAAAAAACJi4LAAAAAAAAREENQUQ0AAAAAAAAAAAAAAAAAAIA + ACpERDwAAAAAAABEPAAHER8YAAAAAAAAAAAAAAAYQUEXNURERAIAAAAAADURAAA2REQjAAAAAAAABx8W + ADxERDsUQ0QvAAAAAAAAHjsxB0RERDYAAAAAAAA6REQhOERENgAHCwAAAAAAAABEREQjNUREHgAAJjsw + CERERDULMzELAAAAAAAAAAAAAERERCQCFhYUAw9EREQhNkRDGwAAAAAAAAAAAAAAAAAAJEA1BwAIQEQ+ + FERERCYCFxEAAAAAAAAAAAAAAAAAAAAAAAAAACFEREQZKUA1AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + DUREQwsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCcNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAGAAAADAAAAAB + AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPDw8ADpBPgA6RD8AOkRAADdPRAA4SkEAOExDADZRRAA1 + VUYAM1pIADJeSQAxYEsAMGRMAC1tUAArc1IALHFRACp1UgAqd1QAKXlUACh9VgAngFcAJoJYACWFWQAk + iVsAJItcACONXAAkjFwAIpFeACGUXwAfmmIAHp5jACCWYAAgmGEAHaFkABumZgAcpGUAGqpoABitaQAV + uW4AFL5wAA/NdgASwXEAEcVzABDJdAAO0HcADdN4AAzVeQAL2HoACdx8AAjhfQAI5H8AB+eAAAbqgQAE + 7oMABPCEAAH4hwAB+ogAAP6JAFH/yABx/9MAkf/cALH/5QDR//AA////AAAAAAAALw4AAFAYAABwIgAA + kCwAALA2AADPQAAA8EoAEf9bADH/cQBR/4cAcf+dAJH/sgCx/8kA0f/fAP///wAAAAAAAi8AAARQAAAG + cAAACJAAAAqwAAALzwAADvAAACD/EgA9/zEAW/9RAHn/cQCY/5EAtf+xANT/0QD///8AAAAAABQvAAAi + UAAAMHAAAD2QAABMsAAAWc8AAGfwAAB4/xEAiv8xAJz/UQCu/3EAwP+RANL/sQDk/9EA////AAAAAAAm + LwAAQFAAAFpwAAB0kAAAjrAAAKnPAADC8AAA0f8RANj/MQDe/1EA4/9xAOn/kQDv/7EA9v/RAP///wAA + AAAALyYAAFBBAABwWwAAkHQAALCOAADPqQAA8MMAAP/SEQD/2DEA/91RAP/kcQD/6pEA//CxAP/20QD/ + //8AAAAAAC8UAABQIgAAcDAAAJA+AACwTQAAz1sAAPBpAAD/eREA/4oxAP+dUQD/r3EA/8GRAP/SsQD/ + 5dEA////AAAAAAAvAwAAUAQAAHAGAACQCQAAsAoAAM8MAADwDgAA/yASAP8+MQD/XFEA/3pxAP+XkQD/ + trEA/9TRAP///wAAAAAALwAOAFAAFwBwACEAkAArALAANgDPAEAA8ABJAP8RWgD/MXAA/1GGAP9xnAD/ + kbIA/7HIAP/R3wD///8AAAAAAC8AIABQADYAcABMAJAAYgCwAHgAzwCOAPAApAD/EbMA/zG+AP9RxwD/ + cdEA/5HcAP+x5QD/0fAA////AAAAAAAsAC8ASwBQAGkAcACHAJAApQCwAMQAzwDhAPAA8BH/APIx/wD0 + Uf8A9nH/APeR/wD5sf8A+9H/AP///wAAAAAAGwAvAC0AUAA/AHAAUgCQAGMAsAB2AM8AiADwAJkR/wCm + Mf8AtFH/AMJx/wDPkf8A3LH/AOvR/wD///8AAAAAAAgALwAOAFAAFQBwABsAkAAhALAAJgDPACwA8AA+ + Ef8AWDH/AHFR/wCMcf8AppH/AL+x/wDa0f8A////AAAMLSQhOTkTISMDADI5JC45LQAAAAAAABEmOTkR + LCcDAAAAAzg5KAYYGAQAAAAAADgUOC0DAAAAAwAAABEkDQMkOTQDAwAAADAAAwAAAwAAAAAAAAAkOScn + OTgGAAAAAB0RAAAAAAAAAAAkNhoyOTYEHg8AAAAAADk5CQAAAAAAAwM4OS8PJxQAAAAAAAMAADk4CAAD + AAAAAAAjMxgDAAADAAAAAAAAABEZDQAAAAAAAAAAAAAAAAAAAAAAAwAAAA85OREAAAADAAAAAAMAAAAA + AAAAAAAAABs5ORQAAAEAAAAAAwAAAAAAAAMAAAAAAA8WIAsAAAAAAAAAAAAAAAMAAAAAAwAAAAEGNjka + AAAAAAAAAAADAAAAAAAAAAAAADYWOTklAAAAAAAAAAAAAAADIycEAAAAADkgGiUKAAAAAAAAAAABGhoO + OTkhAAAAACgHACo5HgAAAAAADwsUOTkbNjgRAwAAACYxDjg5LwAABwMaOTgbOTkPAwYAAAAAADk5Jxoo + DwAbOTEhOTkMDAwAAAAAAAAAACo1EQAZNiQnOTkJHBMBAAMAAAMAAAMAAAAAAAAwOTgLJxwAAAAAAAAA + AAAAAAAAAAAAAAAWNCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQABAAEAAQAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAQAAAAIAAAAAEACAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8PT0AOkE+ADlGQAA3TUMAOElBADhMQwA1U0UANVVGADNbSQAy + XUkALmtPAC5sTwAxYUsAMGJMAC1vUAArc1IAK3RTACh8VgAngFcAJ4FYACaEWQAkiVsAH5piACGVYAAg + mGEAHKJlABunZwAaqWgAGa1pABa1bAAYsGoAFbtvABS8bwAPzXYAEsJyABHEcgAQynUADtF4AAzVeQAL + 2nsACt18AAjifgAI5X8ABuuCAATvgwAD84UABPCEAAL2hgAB+YgAAP6JAABQNwAAcEwAAJBjAACweQAA + z48AAPCmABH/tAAx/74AUf/IAHH/0wCR/9wAsf/lANH/8AD///8AAAAAAAAvDgAAUBgAAHAiAACQLAAA + sDYAAM9AAADwSgAR/1sAMf9xAFH/hwBx/50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAI + kAAACrAAAAvPAAAO8AAAIP8SAD3/MQBb/1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAw + cAAAPZAAAEywAABZzwAAZ/AAAHj/EQCK/zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABA + UAAAWnAAAHSQAACOsAAAqc8AAMLwAADR/xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAv + JgAAUEEAAHBbAACQdAAAsI4AAM+pAADwwwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAA + AAAALxQAAFAiAABwMAAAkD4AALBNAADPWwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD/ + //8AAAAAAC8DAABQBAAAcAYAAJAJAACwCgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/ + 1NEA////AAAAAAAvAA4AUAAXAHAAIQCQACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/ + scgA/9HfAP///wAAAAAALwAgAFAANgBwAEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/ + kdwA/7HlAP/R8AD///8AAAAAACwALwBLAFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2 + cf8A95H/APmx/wD70f8A////AAAAAAAbAC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0 + Uf8AwnH/AM+R/wDcsf8A69H/AP///wAAAAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBY + Mf8AcVH/AIxx/wCmkf8Av7H/ANrR/wD///8AAiUZLScLDgAtJSQiAAAAAB0rHQcFAAAAHBgFJhgAAAAV + AAAAAAAACwwwHiscAAAALxEAAAAAEDEcJRMAAAAAACoQAAAAAAUbCAAAAAAAAAAUKQcAAAAAAAAAAAAA + AAAAGi0IAAAAAAAAAAAAAAAAAAQWIgAAAAAAAAAAAAAAAAAoIi4CAAAAAAAAABkfAAAAIwAeFwAAAAcF + JiUhKwEAACcaLiYAEQwvJh8fAAEAAAApHgYdEjEkGRUAAAAAAAAAAAAJMR0UDAAAAAAAAAAAAAAAAA0C + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAwBQTFRFgICA//// + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODgHVgAAAAlwSFlzAAAOvgAA + Dr4B6kKxwAAAABZJREFUGFdjYAABRhAAs4hlkq4DZDgACywAM12jTsYAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAnBJREFUOE+dk11I + k1Ecxs+2q1DLqwRvvCgoM6mLvoTAC6WLSrDUYBcSGK6y6EMzc6a2NnERlVKhSEMTYWSyksTZh7KZGboU + HNmUKemcupnuI5tuqHs6/7cSUenrwMPhPf/n97wPB46IrVrHCwuTxCJR5EbxbHiUZHQnEzE2uhj18Wsw + zPPLGgQmdErli9Ws8C2VX8wFX9y0rmiWnJ9/dg38Qc02dZdKUlQ3DrcuBINIfQTItMDJWiBHByj1gMEK + 0OxY9rkrywEvb7OQdzclR6tKDjRUV522qh7Kl5q6unDqQTnuNbZD89qEyhYTNK9M0PcMwLewgOsFh5oH + 70oSbXfYBmZUiM8P1Se06Z4WBP5UvarFALffj+q6goDjTXJTf7k4nWVmp159ayhDnVYu1Ot7tvmnImB+ + ztX4Y6dZUYMRzrk5VD4uxPueWmTlpVxmCVlZF1wuG8pqVJj0eKA+s5cHRMNm2Iapvn3wjCRirGOHUF2j + 12PY7Ubx/SJ4vJMglsXLZJcWefrI+Ge09PZCGr8V105sQU3xdgx0HYHfJ4O5ebdQXVNXjLb2Csy4x0EM + sexgRka2f2kJvkAAEzz9VmkCatWR0JaEoqkiDJ26cDxRh2LQ6YSyQgGna0zwEkMs25+envON13P7fII+ + 2e3QGo1rVN/RAZPFvOwjhli2RyrNdfNEh9eL0elpdFutsPMmLl55peiMZuQhLzHEsl1paXlf5udhdTjQ + abEIu21mZl2t9BBDLItOSpKP8HSj2Yx+Xn9oauq3Ig95iSGWRcTFKVr57Q/zv9pnZ/9K5CWGWBYaG5sZ + EhNT+j8idt0X+S+H3wE2DYYIXysH6QAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAm1JREFUOE+Nkl9I + U1Ecx39T31o9SBq97cWHiUIimKiQ0zFbbcJ1U2YkBtLuFYkQnMrcdKQyEUIwWk+GDy58EfUhmYoTRtKE + HitI8kGZIkEW/oF0um/nd3OyYUnn8rn3nMPn+733wNXYe3spOTQajVXMb55vpE/CiUTiqyB91+b1Ugry + j3gcWwcH2Nzfx8benspsJALhyII8qaeHUiHJ7U5F+Xl0hM3dXXzZ2cGn7W183NpCcG4OPISrmNvbdQZF + IaZOlolsNhvVOZ1U29XFtO4fH+ObeGtqyYuJCSTJM5s9Aqqqr1ez6s1ut5OtqYksHR1tB6Lg++HhhRL+ + Ej4OO+yqmbOCDLGwCuSsrKznLpcLl8EOu5wRBRkkSdJ1t9vdtyPOrCgK+vv74fV6L+DxeODz+VQnFouh + u7u7j7NksVj0o6Oj42tra3A4HOjs7ITT6URzczMkqQ7V1UaUl1egpOQ2zOZ7qjM/v4yBgcFxzlJNTU3l + 1NTU8urqKoxGowjLMJnMqKioFME7aRiNd1VndnYRIyOBZc6SwWBwRKPR9XA4jKKiIjQ0PBSS9a+YTLWq + 4xTX5OTbdc5SWVnZk1AohGAwCJ1OB7v9EazWB/+EnbGxMUxPT4OzVFxc7IpE3mFmJoS2tqcYHg5gaOgl + /P5ACq/E/A+tre1YXPygwlnS6/XupaUVLCysoLGx8b9IFnCWcnJyWrKzsweZzMzMIf5l7weA1++BN9HP + MPhacEv2o8o1iV8nJ2An6XOWxIK0Wi1dy82lG6Wlz9SfPmWcJhJg4qeniIsnO+xyhrPnBVcLC0lbUPD4 + Sn6+/zLYUd2zgt/AGvcWHCMAZwAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAW1JREFUOE+NkL1L + QlEYh9/b4NzS1BgNShBRQQ3VGEGr/0BDBEG0uLRIFIREIX2ANhgZKphj/4PLASOi0i4SYWWmWH5y/bhv + 5yc4HTl04YHD+z4893AMGvB53S7Hg+1cNQxjBGtm/p4YerrdvXlsDfJ7s7MlCp4ukgD7U3QX8mx+ZDIm + A5wx6+/hKiEs0+drnNiY5WTynlOpZ85mcz1wxgw7OHCVwPECCXlVDoev2ec75EDggiORGMfjCQ5dXrHf + f8LRaAwKw1UCR/MkbLns2Da/mOZAsIMDVwn45ki0pWB1OlrgwFUCBzMkrG6X662WFjhwlcDeNIlGu82/ + zaYWOHCVgHeSRFX+vVSraYEDVwnsuEj8WBbnKxUtcOAqAY+TREleP1cua4EDVwlsj5MoNBr8WixqgQNX + CWyNkfis19ksFLTAgasE1kdJvMsHTOfzWuDAVQLuYRJf8oHeqlUtcOAqgRUHBZcdJP4D3H7gDzdsNup2 + mXizAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAXJJREFUOE+lk0FL + AkEYhlvwv3jzoiDoQdCbdEnYf6CrqCgoHgRRAk/9EQVLdEGyFiQNMS+dvHnoEkgglGAmCL7NO6RMIZvU + wsMO3zzzzGk0ACf/+hjQNO1ccKlXKsYx0OUZeflXoFmtVsUS2P4CHboi0FQDrXK5jM12i/VmYwsduiLQ + UgNmqVTCuzj8tlrZQoeuCJhqoFMsFvG6XmO2WNhCh64IdNRAt1Ao4EXc/jSf20KHrgh01YCVy+Uwnkzw + vFzaQoeuCFhqoJfJZBCLxY6Crgj01EA/lUrB4/HA7XYfhHs78vk8A301MIzH4/B6vRiNHjAY3H+DM+7p + ug6fz4dsNsvAUA2Mo9Eo/H4/LOsOTqdTYprXEs64x0AwGEQ6nWZgrAYeDcNAIBBAu30r/6Reb0t2MwbC + 4TCSySQDj/uAeEyngqnL5fpoNG4QCoUktVpHspsxEIlEkEgk+AKnaoAP8kwwczgcF4fg3g+u9gEu/son + bfJW/NwRDyIAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAUNJREFUOE+lk79L + QlEcxW9/gqCrm6vg4uYoOAgOrqLk4ioP0r2Glhp0SSjoF1FE0BIUDU3RdIOGoKBVGlpapaHTObeuCPe6 + 9ITD5fs9n3Pue8JbAWBS/VSQRvPwKR/j3JgaZXVqPv5TzPOXLhYoZDEcQidVWyhw3qzfn3tBAWH7PRjg + uV7HV5JAM6USyX50u86btlrOCwoOCR7Q+Oz1cFcu473dhmbppdFwu8dq1e3EBgU0zB6NXQJvzSaui0U8 + VCq4LZWwn8vhLJ+HPDFiowUEzITADsGrQgFHmYzTSTYL7eSJiRZs0timRoTGhC956wXDXtrJEyM2eAIt + t34Be8NgTPLELCuQYe8Z9tK8ZBf+ieuEnxj20rzB26SYF7zCGsGEoVeW6NTMoJFiXlDAkFllqMOwTs2+ + IOYFBf/9oFJ9ibr0B4f94vVG3bWDAAAAAElFTkSuQmCC + + \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/HResultExtensions.cs b/src/Greenshot.Base/Core/HResultExtensions.cs similarity index 96% rename from src/GreenshotPlugin/Core/HResultExtensions.cs rename to src/Greenshot.Base/Core/HResultExtensions.cs index 891f48908..9550101fd 100644 --- a/src/GreenshotPlugin/Core/HResultExtensions.cs +++ b/src/Greenshot.Base/Core/HResultExtensions.cs @@ -17,10 +17,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using GreenshotPlugin.Core.Enums; using System.Diagnostics.Contracts; +using Greenshot.Base.Core.Enums; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// Extensions to handle the HResult diff --git a/src/GreenshotPlugin/Core/IEHelper.cs b/src/Greenshot.Base/Core/IEHelper.cs similarity index 96% rename from src/GreenshotPlugin/Core/IEHelper.cs rename to src/Greenshot.Base/Core/IEHelper.cs index 5fb52032f..7f01b73a2 100644 --- a/src/GreenshotPlugin/Core/IEHelper.cs +++ b/src/Greenshot.Base/Core/IEHelper.cs @@ -1,203 +1,203 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using log4net; -using Microsoft.Win32; - -namespace GreenshotPlugin.Core -{ - /// - /// Description of IEHelper. - /// - public static class IEHelper - { - private static readonly ILog Log = LogManager.GetLogger(typeof(IEHelper)); - - // Internet explorer Registry key - private const string IeKey = @"Software\Microsoft\Internet Explorer"; - - /// - /// Get the current browser version - /// - /// int with browser version - public static int IEVersion - { - get - { - var maxVer = 7; - using (var ieKey = Registry.LocalMachine.OpenSubKey(IeKey, false)) - { - foreach (var value in new[] - { - "svcVersion", "svcUpdateVersion", "Version", "W2kVersion" - }) - { - var objVal = ieKey.GetValue(value, "0"); - var strVal = Convert.ToString(objVal); - - var iPos = strVal.IndexOf('.'); - if (iPos > 0) - { - strVal = strVal.Substring(0, iPos); - } - - if (int.TryParse(strVal, out var res)) - { - maxVer = Math.Max(maxVer, res); - } - } - } - - return maxVer; - } - } - - /// - /// Get the highest possible version for the embedded browser - /// - /// true to ignore the doctype when loading a page - /// IE Feature - public static int GetEmbVersion(bool ignoreDoctype = true) - { - var ieVersion = IEVersion; - - if (ieVersion > 9) - { - return ieVersion * 1000 + (ignoreDoctype ? 1 : 0); - } - - if (ieVersion > 7) - { - return ieVersion * 1111; - } - - return 7000; - } - - /// - /// Fix browser version to the highest possible - /// - /// true to ignore the doctype when loading a page - public static void FixBrowserVersion(bool ignoreDoctype = true) - { - var applicationName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location); - FixBrowserVersion(applicationName, ignoreDoctype); - } - - /// - /// Fix the browser version for the specified application - /// - /// Name of the process - /// true to ignore the doctype when loading a page - public static void FixBrowserVersion(string applicationName, bool ignoreDoctype = true) - { - FixBrowserVersion(applicationName, GetEmbVersion(ignoreDoctype)); - } - - /// - /// Fix the browser version for the specified application - /// - /// Name of the process - /// - /// Version, see - /// Browser Emulation - /// - public static void FixBrowserVersion(string applicationName, int ieVersion) - { - ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".exe", ieVersion); -#if DEBUG - ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".vshost.exe", ieVersion); -#endif - } - - /// - /// Make the change to the registry - /// - /// HKEY_CURRENT_USER or something - /// Name of the executable - /// Version to use - private static void ModifyRegistry(string root, string applicationName, int ieFeatureVersion) - { - var regKey = root + @"\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION"; - try - { - Registry.SetValue(regKey, applicationName, ieFeatureVersion); - } - catch (Exception ex) - { - // some config will hit access rights exceptions - // this is why we try with both LOCAL_MACHINE and CURRENT_USER - Log.Error(ex); - Log.ErrorFormat("couldn't modify the registry key {0}", regKey); - } - } - - /// - /// Find the DirectUI window for MSAA (Accessible) - /// - /// The browser WindowDetails - /// WindowDetails for the DirectUI window - public static WindowDetails GetDirectUI(WindowDetails browserWindowDetails) - { - if (browserWindowDetails == null) - { - return null; - } - - WindowDetails tmpWd = browserWindowDetails; - // Since IE 9 the TabBandClass is less deep! - if (IEVersion < 9) - { - tmpWd = tmpWd.GetChild("CommandBarClass"); - tmpWd = tmpWd?.GetChild("ReBarWindow32"); - } - - tmpWd = tmpWd?.GetChild("TabBandClass"); - tmpWd = tmpWd?.GetChild("DirectUIHWND"); - return tmpWd; - } - - /// - /// Return an IEnumerable with the currently opened IE urls - /// - /// - public static IEnumerable GetIEUrls() - { - // Find the IE window - foreach (WindowDetails ieWindow in WindowDetails.GetAllWindows("IEFrame")) - { - WindowDetails directUIWD = GetDirectUI(ieWindow); - if (directUIWD != null) - { - Accessible ieAccessible = new Accessible(directUIWD.Handle); - foreach (string url in ieAccessible.IETabUrls) - { - yield return url; - } - } - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using log4net; +using Microsoft.Win32; + +namespace Greenshot.Base.Core +{ + /// + /// Description of IEHelper. + /// + public static class IEHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IEHelper)); + + // Internet explorer Registry key + private const string IeKey = @"Software\Microsoft\Internet Explorer"; + + /// + /// Get the current browser version + /// + /// int with browser version + public static int IEVersion + { + get + { + var maxVer = 7; + using (var ieKey = Registry.LocalMachine.OpenSubKey(IeKey, false)) + { + foreach (var value in new[] + { + "svcVersion", "svcUpdateVersion", "Version", "W2kVersion" + }) + { + var objVal = ieKey.GetValue(value, "0"); + var strVal = Convert.ToString(objVal); + + var iPos = strVal.IndexOf('.'); + if (iPos > 0) + { + strVal = strVal.Substring(0, iPos); + } + + if (int.TryParse(strVal, out var res)) + { + maxVer = Math.Max(maxVer, res); + } + } + } + + return maxVer; + } + } + + /// + /// Get the highest possible version for the embedded browser + /// + /// true to ignore the doctype when loading a page + /// IE Feature + public static int GetEmbVersion(bool ignoreDoctype = true) + { + var ieVersion = IEVersion; + + if (ieVersion > 9) + { + return ieVersion * 1000 + (ignoreDoctype ? 1 : 0); + } + + if (ieVersion > 7) + { + return ieVersion * 1111; + } + + return 7000; + } + + /// + /// Fix browser version to the highest possible + /// + /// true to ignore the doctype when loading a page + public static void FixBrowserVersion(bool ignoreDoctype = true) + { + var applicationName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location); + FixBrowserVersion(applicationName, ignoreDoctype); + } + + /// + /// Fix the browser version for the specified application + /// + /// Name of the process + /// true to ignore the doctype when loading a page + public static void FixBrowserVersion(string applicationName, bool ignoreDoctype = true) + { + FixBrowserVersion(applicationName, GetEmbVersion(ignoreDoctype)); + } + + /// + /// Fix the browser version for the specified application + /// + /// Name of the process + /// + /// Version, see + /// Browser Emulation + /// + public static void FixBrowserVersion(string applicationName, int ieVersion) + { + ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".exe", ieVersion); +#if DEBUG + ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".vshost.exe", ieVersion); +#endif + } + + /// + /// Make the change to the registry + /// + /// HKEY_CURRENT_USER or something + /// Name of the executable + /// Version to use + private static void ModifyRegistry(string root, string applicationName, int ieFeatureVersion) + { + var regKey = root + @"\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION"; + try + { + Registry.SetValue(regKey, applicationName, ieFeatureVersion); + } + catch (Exception ex) + { + // some config will hit access rights exceptions + // this is why we try with both LOCAL_MACHINE and CURRENT_USER + Log.Error(ex); + Log.ErrorFormat("couldn't modify the registry key {0}", regKey); + } + } + + /// + /// Find the DirectUI window for MSAA (Accessible) + /// + /// The browser WindowDetails + /// WindowDetails for the DirectUI window + public static WindowDetails GetDirectUI(WindowDetails browserWindowDetails) + { + if (browserWindowDetails == null) + { + return null; + } + + WindowDetails tmpWd = browserWindowDetails; + // Since IE 9 the TabBandClass is less deep! + if (IEVersion < 9) + { + tmpWd = tmpWd.GetChild("CommandBarClass"); + tmpWd = tmpWd?.GetChild("ReBarWindow32"); + } + + tmpWd = tmpWd?.GetChild("TabBandClass"); + tmpWd = tmpWd?.GetChild("DirectUIHWND"); + return tmpWd; + } + + /// + /// Return an IEnumerable with the currently opened IE urls + /// + /// + public static IEnumerable GetIEUrls() + { + // Find the IE window + foreach (WindowDetails ieWindow in WindowDetails.GetAllWindows("IEFrame")) + { + WindowDetails directUIWD = GetDirectUI(ieWindow); + if (directUIWD != null) + { + Accessible ieAccessible = new Accessible(directUIWD.Handle); + foreach (string url in ieAccessible.IETabUrls) + { + yield return url; + } + } + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/IImage.cs b/src/Greenshot.Base/Core/IImage.cs similarity index 95% rename from src/GreenshotPlugin/Core/IImage.cs rename to src/Greenshot.Base/Core/IImage.cs index ffeff3d24..2204d5739 100644 --- a/src/GreenshotPlugin/Core/IImage.cs +++ b/src/Greenshot.Base/Core/IImage.cs @@ -1,68 +1,68 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Drawing.Imaging; - -namespace GreenshotPlugin.Core -{ - /// - /// The image interface, this abstracts an image - /// - public interface IImage : IDisposable - { - /// - /// Height of the image, can be set to change - /// - int Height { get; set; } - - /// - /// Width of the image, can be set to change. - /// - int Width { get; set; } - - /// - /// Size of the image - /// - Size Size { get; } - - /// - /// Pixelformat of the underlying image - /// - PixelFormat PixelFormat { get; } - - /// - /// Vertical resolution of the underlying image - /// - float VerticalResolution { get; } - - /// - /// Horizontal resolution of the underlying image - /// - float HorizontalResolution { get; } - - /// - /// Unterlying image, or an on demand rendered version with different attributes as the original - /// - Image Image { get; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Imaging; + +namespace Greenshot.Base.Core +{ + /// + /// The image interface, this abstracts an image + /// + public interface IImage : IDisposable + { + /// + /// Height of the image, can be set to change + /// + int Height { get; set; } + + /// + /// Width of the image, can be set to change. + /// + int Width { get; set; } + + /// + /// Size of the image + /// + Size Size { get; } + + /// + /// Pixelformat of the underlying image + /// + PixelFormat PixelFormat { get; } + + /// + /// Vertical resolution of the underlying image + /// + float VerticalResolution { get; } + + /// + /// Horizontal resolution of the underlying image + /// + float HorizontalResolution { get; } + + /// + /// Unterlying image, or an on demand rendered version with different attributes as the original + /// + Image Image { get; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/ImageHelper.cs b/src/Greenshot.Base/Core/ImageHelper.cs similarity index 97% rename from src/GreenshotPlugin/Core/ImageHelper.cs rename to src/Greenshot.Base/Core/ImageHelper.cs index d6263813c..e93307717 100644 --- a/src/GreenshotPlugin/Core/ImageHelper.cs +++ b/src/Greenshot.Base/Core/ImageHelper.cs @@ -1,1807 +1,1807 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using log4net; - -namespace GreenshotPlugin.Core -{ - internal enum ExifOrientations : byte - { - Unknown = 0, - TopLeft = 1, - TopRight = 2, - BottomRight = 3, - BottomLeft = 4, - LeftTop = 5, - RightTop = 6, - RightBottom = 7, - LeftBottom = 8, - } - - /// - /// Description of ImageHelper. - /// - public static class ImageHelper - { - private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const int ExifOrientationId = 0x0112; - - static ImageHelper() - { - StreamConverters["greenshot"] = (stream, s) => - { - var surface = SimpleServiceProvider.Current.GetInstance>().Invoke(); - return surface.GetImageForExport(); - }; - - // Add a SVG converter - StreamConverters["svg"] = (stream, s) => - { - stream.Position = 0; - try - { - return SvgImage.FromStream(stream).Image; - } - catch (Exception ex) - { - Log.Error("Can't load SVG", ex); - } - - return null; - }; - - static Image DefaultConverter(Stream stream, string s) - { - stream.Position = 0; - using var tmpImage = Image.FromStream(stream, true, true); - Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - return Clone(tmpImage, PixelFormat.Format32bppArgb); - } - - // Fallback - StreamConverters[string.Empty] = DefaultConverter; - StreamConverters["gif"] = DefaultConverter; - StreamConverters["bmp"] = DefaultConverter; - StreamConverters["jpg"] = DefaultConverter; - StreamConverters["jpeg"] = DefaultConverter; - StreamConverters["png"] = DefaultConverter; - StreamConverters["wmf"] = DefaultConverter; - - StreamConverters["ico"] = (stream, extension) => - { - // Icon logic, try to get the Vista icon, else the biggest possible - try - { - using Image tmpImage = ExtractVistaIcon(stream); - if (tmpImage != null) - { - return Clone(tmpImage, PixelFormat.Format32bppArgb); - } - } - catch (Exception vistaIconException) - { - Log.Warn("Can't read icon", vistaIconException); - } - - try - { - // No vista icon, try normal icon - stream.Position = 0; - // We create a copy of the bitmap, so everything else can be disposed - using Icon tmpIcon = new Icon(stream, new Size(1024, 1024)); - using Image tmpImage = tmpIcon.ToBitmap(); - return Clone(tmpImage, PixelFormat.Format32bppArgb); - } - catch (Exception iconException) - { - Log.Warn("Can't read icon", iconException); - } - - stream.Position = 0; - return DefaultConverter(stream, extension); - }; - } - - public static IDictionary> StreamConverters { get; } = new Dictionary>(); - - /// - /// Make sure the image is orientated correctly - /// - /// - public static void Orientate(Image image) - { - if (!CoreConfig.ProcessEXIFOrientation) - { - return; - } - - try - { - // Get the index of the orientation property. - int orientationIndex = Array.IndexOf(image.PropertyIdList, ExifOrientationId); - // If there is no such property, return Unknown. - if (orientationIndex < 0) - { - return; - } - - PropertyItem item = image.GetPropertyItem(ExifOrientationId); - - ExifOrientations orientation = (ExifOrientations) item.Value[0]; - // Orient the image. - switch (orientation) - { - case ExifOrientations.Unknown: - case ExifOrientations.TopLeft: - break; - case ExifOrientations.TopRight: - image.RotateFlip(RotateFlipType.RotateNoneFlipX); - break; - case ExifOrientations.BottomRight: - image.RotateFlip(RotateFlipType.Rotate180FlipNone); - break; - case ExifOrientations.BottomLeft: - image.RotateFlip(RotateFlipType.RotateNoneFlipY); - break; - case ExifOrientations.LeftTop: - image.RotateFlip(RotateFlipType.Rotate90FlipX); - break; - case ExifOrientations.RightTop: - image.RotateFlip(RotateFlipType.Rotate90FlipNone); - break; - case ExifOrientations.RightBottom: - image.RotateFlip(RotateFlipType.Rotate90FlipY); - break; - case ExifOrientations.LeftBottom: - image.RotateFlip(RotateFlipType.Rotate270FlipNone); - break; - } - - // Set the orientation to be normal, as we rotated the image. - item.Value[0] = (byte) ExifOrientations.TopLeft; - image.SetPropertyItem(item); - } - catch (Exception orientEx) - { - Log.Warn("Problem orientating the image: ", orientEx); - } - } - - /// - /// Create a Thumbnail - /// - /// - /// - /// - /// - /// - /// - public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight, int maxWidth = -1, int maxHeight = -1) - { - int srcWidth = image.Width; - int srcHeight = image.Height; - if (thumbHeight < 0) - { - thumbHeight = (int) (thumbWidth * (srcHeight / (float) srcWidth)); - } - - if (thumbWidth < 0) - { - thumbWidth = (int) (thumbHeight * (srcWidth / (float) srcHeight)); - } - - if (maxWidth > 0 && thumbWidth > maxWidth) - { - thumbWidth = Math.Min(thumbWidth, maxWidth); - thumbHeight = (int) (thumbWidth * (srcHeight / (float) srcWidth)); - } - - if (maxHeight > 0 && thumbHeight > maxHeight) - { - thumbHeight = Math.Min(thumbHeight, maxHeight); - thumbWidth = (int) (thumbHeight * (srcWidth / (float) srcHeight)); - } - - Bitmap bmp = new Bitmap(thumbWidth, thumbHeight); - using (Graphics graphics = Graphics.FromImage(bmp)) - { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight); - graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); - } - - return bmp; - } - - /// - /// Crops the image to the specified rectangle - /// - /// Image to crop - /// Rectangle with bitmap coordinates, will be "intersected" to the bitmap - public static bool Crop(ref Image image, ref Rectangle cropRectangle) - { - if (image is Bitmap && (image.Width * image.Height > 0)) - { - cropRectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height)); - if (cropRectangle.Width != 0 || cropRectangle.Height != 0) - { - Image returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare); - image.Dispose(); - image = returnImage; - return true; - } - } - - Log.Warn("Can't crop a null/zero size image!"); - return false; - } - - /// - /// Private helper method for the FindAutoCropRectangle - /// - /// - /// - /// - /// Rectangle - private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) - { - Rectangle cropRectangle = Rectangle.Empty; - Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); - Point min = new Point(int.MaxValue, int.MaxValue); - Point max = new Point(int.MinValue, int.MinValue); - - if (cropDifference > 0) - { - for (int y = 0; y < fastBitmap.Height; y++) - { - for (int x = 0; x < fastBitmap.Width; x++) - { - Color currentColor = fastBitmap.GetColorAt(x, y); - int diffR = Math.Abs(currentColor.R - referenceColor.R); - int diffG = Math.Abs(currentColor.G - referenceColor.G); - int diffB = Math.Abs(currentColor.B - referenceColor.B); - if ((diffR + diffG + diffB) / 3 <= cropDifference) - { - continue; - } - - if (x < min.X) min.X = x; - if (y < min.Y) min.Y = y; - if (x > max.X) max.X = x; - if (y > max.Y) max.Y = y; - } - } - } - else - { - for (int y = 0; y < fastBitmap.Height; y++) - { - for (int x = 0; x < fastBitmap.Width; x++) - { - Color currentColor = fastBitmap.GetColorAt(x, y); - if (!referenceColor.Equals(currentColor)) - { - continue; - } - - if (x < min.X) min.X = x; - if (y < min.Y) min.Y = y; - if (x > max.X) max.X = x; - if (y > max.Y) max.Y = y; - } - } - } - - if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) - { - if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) - { - cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); - } - } - - return cropRectangle; - } - - /// - /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 - /// - /// - /// - /// Rectangle - public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) - { - Rectangle cropRectangle = Rectangle.Empty; - var checkPoints = new List - { - new Point(0, 0), - new Point(0, image.Height - 1), - new Point(image.Width - 1, 0), - new Point(image.Width - 1, image.Height - 1) - }; - // Top Left - // Bottom Left - // Top Right - // Bottom Right - using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap) image)) - { - // find biggest area - foreach (Point checkPoint in checkPoints) - { - var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); - if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) - { - cropRectangle = currentRectangle; - } - } - } - - return cropRectangle; - } - - /// - /// Load an image from file - /// - /// - /// - public static Image LoadImage(string filename) - { - if (string.IsNullOrEmpty(filename)) - { - return null; - } - - if (!File.Exists(filename)) - { - return null; - } - - Image fileImage; - Log.InfoFormat("Loading image from file {0}", filename); - // Fixed lock problem Bug #3431881 - using (Stream imageFileStream = File.OpenRead(filename)) - { - fileImage = FromStream(imageFileStream, Path.GetExtension(filename)); - } - - if (fileImage != null) - { - Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat, - fileImage.HorizontalResolution, fileImage.VerticalResolution); - } - - return fileImage; - } - - /// - /// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx - /// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx - /// - /// Stream with the icon information - /// Bitmap with the Vista Icon (256x256) - private static Bitmap ExtractVistaIcon(Stream iconStream) - { - const int sizeIconDir = 6; - const int sizeIconDirEntry = 16; - Bitmap bmpPngExtracted = null; - try - { - byte[] srcBuf = new byte[iconStream.Length]; - iconStream.Read(srcBuf, 0, (int) iconStream.Length); - int iCount = BitConverter.ToInt16(srcBuf, 4); - for (int iIndex = 0; iIndex < iCount; iIndex++) - { - int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex]; - int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1]; - if (iWidth == 0 && iHeight == 0) - { - int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); - int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); - using MemoryStream destStream = new MemoryStream(); - destStream.Write(srcBuf, iImageOffset, iImageSize); - destStream.Seek(0, SeekOrigin.Begin); - bmpPngExtracted = new Bitmap(destStream); // This is PNG! :) - break; - } - } - } - catch - { - return null; - } - - return bmpPngExtracted; - } - - /// - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx - /// - /// The file (EXE or DLL) to get the icon from - /// Index of the icon - /// true if the large icon is wanted - /// Icon - public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) - { - Shell32.ExtractIconEx(location, index, out var large, out var small, 1); - Icon returnIcon = null; - bool isLarge = false; - bool isSmall = false; - try - { - if (takeLarge && !IntPtr.Zero.Equals(large)) - { - returnIcon = Icon.FromHandle(large); - isLarge = true; - } - else if (!IntPtr.Zero.Equals(small)) - { - returnIcon = Icon.FromHandle(small); - isSmall = true; - } - else if (!IntPtr.Zero.Equals(large)) - { - returnIcon = Icon.FromHandle(large); - isLarge = true; - } - } - finally - { - if (isLarge && !IntPtr.Zero.Equals(small)) - { - User32.DestroyIcon(small); - } - - if (isSmall && !IntPtr.Zero.Equals(large)) - { - User32.DestroyIcon(large); - } - } - - return returnIcon; - } - - /// - /// Apply the effect to the bitmap - /// - /// Bitmap - /// IEffect - /// - /// Bitmap - public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix) - { - var effects = new List - { - effect - }; - return ApplyEffects(sourceImage, effects, matrix); - } - - /// - /// Apply the effects in the supplied order to the bitmap - /// - /// Bitmap - /// List of IEffect - /// - /// Bitmap - public static Image ApplyEffects(Image sourceImage, IEnumerable effects, Matrix matrix) - { - var currentImage = sourceImage; - bool disposeImage = false; - foreach (var effect in effects) - { - var tmpImage = effect.Apply(currentImage, matrix); - if (tmpImage != null) - { - if (disposeImage) - { - currentImage.Dispose(); - } - - currentImage = tmpImage; - // Make sure the "new" image is disposed - disposeImage = true; - } - } - - return currentImage; - } - - /// - /// Helper method for the tornedge - /// - /// Path to draw to - /// Points for the lines to draw - private static void DrawLines(GraphicsPath path, List points) - { - path.AddLine(points[0], points[1]); - for (int i = 0; i < points.Count - 1; i++) - { - path.AddLine(points[i], points[i + 1]); - } - } - - /// - /// Make the picture look like it's torn - /// - /// Bitmap to make torn edge off - /// How large (height) is each tooth - /// How wide is a horizontal tooth - /// How wide is a vertical tooth - /// bool[] with information on if the edge needs torn or not. Order is clockwise: 0=top,1=right,2=bottom,3=left - /// Changed bitmap - public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, bool[] edges) - { - Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, - sourceImage.VerticalResolution); - using (var path = new GraphicsPath()) - { - Random random = new Random(); - int horizontalRegions = (int) Math.Round((float) sourceImage.Width / horizontalToothRange); - int verticalRegions = (int) Math.Round((float) sourceImage.Height / verticalToothRange); - - Point topLeft = new Point(0, 0); - Point topRight = new Point(sourceImage.Width, 0); - Point bottomLeft = new Point(0, sourceImage.Height); - Point bottomRight = new Point(sourceImage.Width, sourceImage.Height); - - List points = new List(); - - if (edges[0]) - { - // calculate starting point only if the left edge is torn - if (!edges[3]) - { - points.Add(topLeft); - } - else - { - points.Add(new Point(random.Next(1, toothHeight), random.Next(1, toothHeight))); - } - - for (int i = 1; i < horizontalRegions - 1; i++) - { - points.Add(new Point(i * horizontalToothRange, random.Next(1, toothHeight))); - } - - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight))); - } - else - { - // set start & endpoint to be the default "whole-line" - points.Add(topLeft); - points.Add(topRight); - } - - // Right - if (edges[1]) - { - for (int i = 1; i < verticalRegions - 1; i++) - { - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange)); - } - - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); - } - else - { - // correct previous ending point - points[points.Count - 1] = topRight; - // set endpoint to be the default "whole-line" - points.Add(bottomRight); - } - - // Bottom - if (edges[2]) - { - for (int i = 1; i < horizontalRegions - 1; i++) - { - points.Add(new Point(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight))); - } - - points.Add(new Point(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); - } - else - { - // correct previous ending point - points[points.Count - 1] = bottomRight; - // set endpoint to be the default "whole-line" - points.Add(bottomLeft); - } - - // Left - if (edges[3]) - { - // One fewer as the end point is the starting point - for (int i = 1; i < verticalRegions - 1; i++) - { - points.Add(new Point(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange)); - } - } - else - { - // correct previous ending point - points[points.Count - 1] = bottomLeft; - // set endpoint to be the default "whole-line" - points.Add(topLeft); - } - - // End point always is the starting point - points[points.Count - 1] = points[0]; - - DrawLines(path, points); - - path.CloseFigure(); - - // Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing - using Graphics graphics = Graphics.FromImage(returnImage); - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - using Brush brush = new TextureBrush(sourceImage); - // Important note: If the target wouldn't be at 0,0 we need to translate-transform!! - graphics.FillPath(brush, path); - } - - return returnImage; - } - - /// - /// Apply BoxBlur to the destinationBitmap - /// - /// Bitmap to blur - /// Must be ODD! - public static void ApplyBoxBlur(Bitmap destinationBitmap, int range) - { - // We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V) - using IFastBitmap fastBitmap = FastBitmap.Create(destinationBitmap); - ApplyBoxBlur(fastBitmap, range); - } - - /// - /// Apply BoxBlur to the fastBitmap - /// - /// IFastBitmap to blur - /// Must be ODD! - public static void ApplyBoxBlur(IFastBitmap fastBitmap, int range) - { - // Range must be odd! - if ((range & 1) == 0) - { - range++; - } - - if (range <= 1) - { - return; - } - - // Box blurs are frequently used to approximate a Gaussian blur. - // By the central limit theorem, if applied 3 times on the same image, a box blur approximates the Gaussian kernel to within about 3%, yielding the same result as a quadratic convolution kernel. - // This might be true, but the GDI+ BlurEffect doesn't look the same, a 2x blur is more simular and we only make 2x Box-Blur. - // (Might also be a mistake in our blur, but for now it looks great) - if (fastBitmap.HasAlphaChannel) - { - BoxBlurHorizontalAlpha(fastBitmap, range); - BoxBlurVerticalAlpha(fastBitmap, range); - BoxBlurHorizontalAlpha(fastBitmap, range); - BoxBlurVerticalAlpha(fastBitmap, range); - } - else - { - BoxBlurHorizontal(fastBitmap, range); - BoxBlurVertical(fastBitmap, range); - BoxBlurHorizontal(fastBitmap, range); - BoxBlurVertical(fastBitmap, range); - } - } - - /// - /// BoxBlurHorizontal is a private helper method for the BoxBlur - /// - /// Target BitmapBuffer - /// Range must be odd! - private static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) - { - if (targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel"); - } - - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Width]; - byte[] tmpColor = new byte[3]; - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - int hits = 0; - int r = 0; - int g = 0; - int b = 0; - for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) - { - int oldPixel = x - halfRange - 1; - if (oldPixel >= targetFastBitmap.Left) - { - targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } - - int newPixel = x + halfRange; - if (newPixel < targetFastBitmap.Right) - { - targetFastBitmap.GetColorAt(newPixel, y, tmpColor); - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } - - if (x >= targetFastBitmap.Left) - { - newColors[x - targetFastBitmap.Left] = Color.FromArgb(255, (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); - } - } - - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); - } - } - } - - /// - /// BoxBlurHorizontal is a private helper method for the BoxBlur, only for IFastBitmaps with alpha channel - /// - /// Target BitmapBuffer - /// Range must be odd! - private static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) - { - if (!targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel"); - } - - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Width]; - byte[] tmpColor = new byte[4]; - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - int hits = 0; - int a = 0; - int r = 0; - int g = 0; - int b = 0; - for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) - { - int oldPixel = x - halfRange - 1; - if (oldPixel >= targetFastBitmap.Left) - { - targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); - a -= tmpColor[FastBitmap.ColorIndexA]; - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } - - int newPixel = x + halfRange; - if (newPixel < targetFastBitmap.Right) - { - targetFastBitmap.GetColorAt(newPixel, y, tmpColor); - a += tmpColor[FastBitmap.ColorIndexA]; - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } - - if (x >= targetFastBitmap.Left) - { - newColors[x - targetFastBitmap.Left] = Color.FromArgb((byte) (a / hits), (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); - } - } - - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); - } - } - } - - /// - /// BoxBlurVertical is a private helper method for the BoxBlur - /// - /// BitmapBuffer which previously was created with BoxBlurHorizontal - /// Range must be odd! - private static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) - { - if (targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel"); - } - - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Height]; - byte[] tmpColor = new byte[4]; - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - int hits = 0; - int r = 0; - int g = 0; - int b = 0; - for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) - { - int oldPixel = y - halfRange - 1; - if (oldPixel >= targetFastBitmap.Top) - { - targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } - - int newPixel = y + halfRange; - if (newPixel < targetFastBitmap.Bottom) - { - targetFastBitmap.GetColorAt(x, newPixel, tmpColor); - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } - - if (y >= targetFastBitmap.Top) - { - newColors[y - targetFastBitmap.Top] = Color.FromArgb(255, (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); - } - } - - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); - } - } - } - - /// - /// BoxBlurVertical is a private helper method for the BoxBlur - /// - /// BitmapBuffer which previously was created with BoxBlurHorizontal - /// Range must be odd! - private static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) - { - if (!targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurVerticalAlpha should be called for bitmaps with alpha channel"); - } - - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Height]; - byte[] tmpColor = new byte[4]; - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - int hits = 0; - int a = 0; - int r = 0; - int g = 0; - int b = 0; - for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) - { - int oldPixel = y - halfRange - 1; - if (oldPixel >= targetFastBitmap.Top) - { - targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); - a -= tmpColor[FastBitmap.ColorIndexA]; - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } - - int newPixel = y + halfRange; - if (newPixel < targetFastBitmap.Bottom) - { - //int colorg = pixels[index + newPixelOffset]; - targetFastBitmap.GetColorAt(x, newPixel, tmpColor); - a += tmpColor[FastBitmap.ColorIndexA]; - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } - - if (y >= targetFastBitmap.Top) - { - newColors[y - targetFastBitmap.Top] = Color.FromArgb((byte) (a / hits), (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); - } - } - - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); - } - } - } - - /// - /// This method fixes the problem that we can't apply a filter outside the target bitmap, - /// therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap. - /// It will also account for the Invert flag. - /// - /// - /// - /// - /// - public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) - { - Rectangle myRect; - if (invert) - { - myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); - } - else - { - Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height); - myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); - myRect.Intersect(applyRect); - } - - return myRect; - } - - /// - /// Create a new bitmap where the sourceBitmap has a shadow - /// - /// Bitmap to make a shadow on - /// How dark is the shadow - /// Size of the shadow - /// What pixel format must the returning bitmap have - /// - /// The transform matrix which describes how the elements need to be transformed to stay at the same location - /// Bitmap with the shadow, is bigger than the sourceBitmap!! - public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, Matrix matrix, PixelFormat targetPixelformat) - { - Point offset = shadowOffset; - offset.X += shadowSize - 1; - offset.Y += shadowSize - 1; - matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); - // Create a new "clean" image - Bitmap returnImage = CreateEmpty(sourceBitmap.Width + shadowSize * 2, sourceBitmap.Height + shadowSize * 2, targetPixelformat, Color.Empty, - sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); - // Make sure the shadow is odd, there is no reason for an even blur! - if ((shadowSize & 1) == 0) - { - shadowSize++; - } - - bool useGdiBlur = GDIplus.IsBlurPossible(shadowSize); - // Create "mask" for the shadow - ColorMatrix maskMatrix = new ColorMatrix - { - Matrix00 = 0, - Matrix11 = 0, - Matrix22 = 0 - }; - if (useGdiBlur) - { - maskMatrix.Matrix33 = darkness + 0.1f; - } - else - { - maskMatrix.Matrix33 = darkness; - } - - Rectangle shadowRectangle = new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size); - ApplyColorMatrix((Bitmap) sourceBitmap, Rectangle.Empty, returnImage, shadowRectangle, maskMatrix); - - // blur "shadow", apply to whole new image - if (useGdiBlur) - { - // Use GDI Blur - Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height); - GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize + 1, false); - } - else - { - // try normal software blur - //returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); - ApplyBoxBlur(returnImage, shadowSize); - } - - // Draw the original image over the shadow - using (Graphics graphics = Graphics.FromImage(returnImage)) - { - // Make sure we draw with the best quality! - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - // draw original with a TextureBrush so we have nice antialiasing! - using Brush textureBrush = new TextureBrush(sourceBitmap, WrapMode.Clamp); - // We need to do a translate-transform otherwise the image is wrapped - graphics.TranslateTransform(offset.X, offset.Y); - graphics.FillRectangle(textureBrush, 0, 0, sourceBitmap.Width, sourceBitmap.Height); - } - - return returnImage; - } - - /// - /// Return negative of Bitmap - /// - /// Bitmap to create a negative off - /// Negative bitmap - public static Bitmap CreateNegative(Image sourceImage) - { - Bitmap clone = (Bitmap) Clone(sourceImage); - ColorMatrix invertMatrix = new ColorMatrix(new[] - { - new float[] - { - -1, 0, 0, 0, 0 - }, - new float[] - { - 0, -1, 0, 0, 0 - }, - new float[] - { - 0, 0, -1, 0, 0 - }, - new float[] - { - 0, 0, 0, 1, 0 - }, - new float[] - { - 1, 1, 1, 1, 1 - } - }); - ApplyColorMatrix(clone, invertMatrix); - return clone; - } - - /// - /// Apply a color matrix to the image - /// - /// Image to apply matrix to - /// ColorMatrix to apply - public static void ApplyColorMatrix(Bitmap source, ColorMatrix colorMatrix) - { - ApplyColorMatrix(source, Rectangle.Empty, source, Rectangle.Empty, colorMatrix); - } - - /// - /// Apply a color matrix by copying from the source to the destination - /// - /// Image to copy from - /// Rectangle to copy from - /// Rectangle to copy to - /// Image to copy to - /// ColorMatrix to apply - public static void ApplyColorMatrix(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ColorMatrix colorMatrix) - { - using ImageAttributes imageAttributes = new ImageAttributes(); - imageAttributes.ClearColorMatrix(); - imageAttributes.SetColorMatrix(colorMatrix); - ApplyImageAttributes(source, sourceRect, dest, destRect, imageAttributes); - } - - /// - /// Apply a color matrix by copying from the source to the destination - /// - /// Image to copy from - /// Rectangle to copy from - /// Rectangle to copy to - /// Image to copy to - /// ImageAttributes to apply - public static void ApplyImageAttributes(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ImageAttributes imageAttributes) - { - if (sourceRect == Rectangle.Empty) - { - sourceRect = new Rectangle(0, 0, source.Width, source.Height); - } - - if (dest == null) - { - dest = source; - } - - if (destRect == Rectangle.Empty) - { - destRect = new Rectangle(0, 0, dest.Width, dest.Height); - } - - using Graphics graphics = Graphics.FromImage(dest); - // Make sure we draw with the best quality! - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingMode = CompositingMode.SourceCopy; - - graphics.DrawImage(source, destRect, sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height, GraphicsUnit.Pixel, imageAttributes); - } - - /// - /// Returns a b/w of Bitmap - /// - /// Bitmap to create a b/w of - /// Threshold for monochrome filter (0 - 255), lower value means less black - /// b/w bitmap - public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) - { - using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat); - for (int y = 0; y < fastBitmap.Height; y++) - { - for (int x = 0; x < fastBitmap.Width; x++) - { - Color color = fastBitmap.GetColorAt(x, y); - int colorBrightness = (color.R + color.G + color.B) / 3 > threshold ? 255 : 0; - Color monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness); - fastBitmap.SetColorAt(x, y, monoColor); - } - } - - return fastBitmap.UnlockAndReturnBitmap(); - } - - /// - /// Create a new bitmap where the sourceBitmap has a Simple border around it - /// - /// Bitmap to make a border on - /// Size of the border - /// Color of the border - /// What pixel format must the returning bitmap have - /// The transform matrix which describes how the elements need to be transformed to stay at the same location - /// Bitmap with the shadow, is bigger than the sourceBitmap!! - public static Image CreateBorder(Image sourceImage, int borderSize, Color borderColor, PixelFormat targetPixelformat, Matrix matrix) - { - // "return" the shifted offset, so the caller can e.g. move elements - Point offset = new Point(borderSize, borderSize); - matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); - - // Create a new "clean" image - Bitmap newImage = CreateEmpty(sourceImage.Width + borderSize * 2, sourceImage.Height + borderSize * 2, targetPixelformat, Color.Empty, sourceImage.HorizontalResolution, - sourceImage.VerticalResolution); - using (Graphics graphics = Graphics.FromImage(newImage)) - { - // Make sure we draw with the best quality! - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - using (GraphicsPath path = new GraphicsPath()) - { - path.AddRectangle(new Rectangle(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize)); - using Pen pen = new Pen(borderColor, borderSize) - { - LineJoin = LineJoin.Round, - StartCap = LineCap.Round, - EndCap = LineCap.Round - }; - graphics.DrawPath(pen, path); - } - - // draw original with a TextureBrush so we have nice antialiasing! - using Brush textureBrush = new TextureBrush(sourceImage, WrapMode.Clamp); - // We need to do a translate-tranform otherwise the image is wrapped - graphics.TranslateTransform(offset.X, offset.Y); - graphics.FillRectangle(textureBrush, 0, 0, sourceImage.Width, sourceImage.Height); - } - - return newImage; - } - - /// - /// Create ImageAttributes to modify - /// - /// - /// - /// - /// ImageAttributes - public static ImageAttributes CreateAdjustAttributes(float brightness, float contrast, float gamma) - { - float adjustedBrightness = brightness - 1.0f; - ColorMatrix applyColorMatrix = new ColorMatrix( - new[] - { - new[] - { - contrast, 0, 0, 0, 0 - }, // scale red - new[] - { - 0, contrast, 0, 0, 0 - }, // scale green - new[] - { - 0, 0, contrast, 0, 0 - }, // scale blue - new[] - { - 0, 0, 0, 1.0f, 0 - }, // don't scale alpha - new[] - { - adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1 - } - }); - - //create some image attributes - ImageAttributes attributes = new ImageAttributes(); - attributes.ClearColorMatrix(); - attributes.SetColorMatrix(applyColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); - attributes.SetGamma(gamma, ColorAdjustType.Bitmap); - return attributes; - } - - /// - /// Adjust the brightness, contract or gamma of an image. - /// Use the value "1.0f" for no changes. - /// - /// Original bitmap - /// - /// - /// - /// Bitmap with grayscale - public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) - { - //create a blank bitmap the same size as original - // If using 8bpp than the following exception comes: A Graphics object cannot be created from an image that has an indexed pixel format. - Bitmap newBitmap = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format24bppRgb, Color.Empty, sourceImage.HorizontalResolution, - sourceImage.VerticalResolution); - using (ImageAttributes adjustAttributes = CreateAdjustAttributes(brightness, contrast, gamma)) - { - ApplyImageAttributes((Bitmap) sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, adjustAttributes); - } - - return newBitmap; - } - - /// - /// Create a new bitmap where the sourceBitmap is in grayscale - /// - /// Original bitmap - /// Bitmap with grayscale - public static Image CreateGrayscale(Image sourceImage) - { - Bitmap clone = (Bitmap) Clone(sourceImage); - ColorMatrix grayscaleMatrix = new ColorMatrix(new[] - { - new[] - { - .3f, .3f, .3f, 0, 0 - }, - new[] - { - .59f, .59f, .59f, 0, 0 - }, - new[] - { - .11f, .11f, .11f, 0, 0 - }, - new float[] - { - 0, 0, 0, 1, 0 - }, - new float[] - { - 0, 0, 0, 0, 1 - } - }); - ApplyColorMatrix(clone, grayscaleMatrix); - return clone; - } - - /// - /// Checks if we support the pixel format - /// - /// PixelFormat to check - /// bool if we support it - public static bool SupportsPixelFormat(PixelFormat pixelformat) - { - return pixelformat.Equals(PixelFormat.Format32bppArgb) || - pixelformat.Equals(PixelFormat.Format32bppPArgb) || - pixelformat.Equals(PixelFormat.Format32bppRgb) || - pixelformat.Equals(PixelFormat.Format24bppRgb); - } - - /// - /// Wrapper for just cloning which calls the CloneArea - /// - /// Image to clone - /// Bitmap with clone image data - public static Image Clone(Image sourceImage) - { - if (sourceImage is Metafile) - { - return (Image) sourceImage.Clone(); - } - - return CloneArea(sourceImage, Rectangle.Empty, PixelFormat.DontCare); - } - - /// - /// Wrapper for just cloning & TargetFormat which calls the CloneArea - /// - /// Image to clone - /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) - /// Bitmap with clone image data - public static Bitmap Clone(Image sourceBitmap, PixelFormat targetFormat) - { - return CloneArea(sourceBitmap, Rectangle.Empty, targetFormat); - } - - /// - /// Clone an image, taking some rules into account: - /// 1) When sourceRect is the whole bitmap there is a GDI+ bug in Clone - /// Clone will than return the same PixelFormat as the source - /// a quick workaround is using new Bitmap which uses a default of Format32bppArgb - /// 2) When going from a transparent to a non transparent bitmap, we draw the background white! - /// - /// Source bitmap to clone - /// Rectangle to copy from the source, use Rectangle.Empty for all - /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) - /// - public static Bitmap CloneArea(Image sourceImage, Rectangle sourceRect, PixelFormat targetFormat) - { - Bitmap newImage; - Rectangle bitmapRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); - - // Make sure the source is not Rectangle.Empty - if (Rectangle.Empty.Equals(sourceRect)) - { - sourceRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); - } - else - { - sourceRect.Intersect(bitmapRect); - } - - // If no pixelformat is supplied - if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) - { - if (SupportsPixelFormat(sourceImage.PixelFormat)) - { - targetFormat = sourceImage.PixelFormat; - } - else if (Image.IsAlphaPixelFormat(sourceImage.PixelFormat)) - { - targetFormat = PixelFormat.Format32bppArgb; - } - else - { - targetFormat = PixelFormat.Format24bppRgb; - } - } - - // check the target format - if (!SupportsPixelFormat(targetFormat)) - { - targetFormat = Image.IsAlphaPixelFormat(targetFormat) ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb; - } - - bool destinationIsTransparent = Image.IsAlphaPixelFormat(targetFormat); - bool sourceIsTransparent = Image.IsAlphaPixelFormat(sourceImage.PixelFormat); - bool fromTransparentToNon = !destinationIsTransparent && sourceIsTransparent; - bool isBitmap = sourceImage is Bitmap; - bool isAreaEqual = sourceRect.Equals(bitmapRect); - if (isAreaEqual || fromTransparentToNon || !isBitmap) - { - // Rule 1: if the areas are equal, always copy ourselves - newImage = new Bitmap(bitmapRect.Width, bitmapRect.Height, targetFormat); - // Make sure both images have the same resolution - newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - - using Graphics graphics = Graphics.FromImage(newImage); - if (fromTransparentToNon) - { - // Rule 2: Make sure the background color is white - graphics.Clear(Color.White); - } - - // decide fastest copy method - if (isAreaEqual) - { - graphics.DrawImageUnscaled(sourceImage, 0, 0); - } - else - { - graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel); - } - } - else - { - // Let GDI+ decide how to convert, need to test what is quicker... - newImage = (sourceImage as Bitmap).Clone(sourceRect, targetFormat); - // Make sure both images have the same resolution - newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - } - - // In WINE someone getting the PropertyItems doesn't work - try - { - // Clone property items (EXIF information etc) - foreach (var propertyItem in sourceImage.PropertyItems) - { - try - { - newImage.SetPropertyItem(propertyItem); - } - catch (Exception innerEx) - { - Log.Warn("Problem cloning a propertyItem.", innerEx); - } - } - } - catch (Exception ex) - { - Log.Warn("Problem cloning a propertyItem.", ex); - } - - return newImage; - } - - /// - /// Rotate the bitmap - /// - /// - /// - /// - public static Image RotateFlip(Image sourceImage, RotateFlipType rotateFlipType) - { - Image returnImage = Clone(sourceImage); - returnImage.RotateFlip(rotateFlipType); - return returnImage; - } - - /// - /// A generic way to create an empty image - /// - /// the source bitmap as the specifications for the new bitmap - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - public static Bitmap CreateEmptyLike(Image sourceImage, Color backgroundColor) - { - PixelFormat pixelFormat = sourceImage.PixelFormat; - if (backgroundColor.A < 255) - { - pixelFormat = PixelFormat.Format32bppArgb; - } - - return CreateEmpty(sourceImage.Width, sourceImage.Height, pixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - } - - /// - /// A generic way to create an empty image - /// - /// - /// - /// - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - /// - /// Bitmap - public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution, float verticalResolution) - { - // Create a new "clean" image - Bitmap newImage = new Bitmap(width, height, format); - newImage.SetResolution(horizontalResolution, verticalResolution); - if (format != PixelFormat.Format8bppIndexed) - { - using Graphics graphics = Graphics.FromImage(newImage); - // Make sure the background color is what we want (transparent or white, depending on the pixel format) - if (!Color.Empty.Equals(backgroundColor)) - { - graphics.Clear(backgroundColor); - } - else if (Image.IsAlphaPixelFormat(format)) - { - graphics.Clear(Color.Transparent); - } - else - { - graphics.Clear(Color.White); - } - } - - return newImage; - } - - /// - /// Resize canvas with pixel to the left, right, top and bottom - /// - /// - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - /// - /// - /// - /// - /// a new bitmap with the source copied on it - public static Image ResizeCanvas(Image sourceImage, Color backgroundColor, int left, int right, int top, int bottom, Matrix matrix) - { - matrix.Translate(left, top, MatrixOrder.Append); - Bitmap newBitmap = CreateEmpty(sourceImage.Width + left + right, sourceImage.Height + top + bottom, sourceImage.PixelFormat, backgroundColor, - sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (Graphics graphics = Graphics.FromImage(newBitmap)) - { - graphics.DrawImageUnscaled(sourceImage, left, top); - } - - return newBitmap; - } - - /// - /// Wrapper for the more complex Resize, this resize could be used for e.g. Thumbnails - /// - /// - /// true to maintain the aspect ratio - /// - /// - /// - /// - public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, int newWidth, int newHeight, Matrix matrix) - { - return ResizeImage(sourceImage, maintainAspectRatio, false, Color.Empty, newWidth, newHeight, matrix); - } - - /// - /// Count how many times the supplied color exists - /// - /// Image to count the pixels of - /// Color to count - /// true if Alpha needs to be checked - /// int with the number of pixels which have colorToCount - public static int CountColor(Image sourceImage, Color colorToCount, bool includeAlpha) - { - int colors = 0; - int toCount = colorToCount.ToArgb(); - if (!includeAlpha) - { - toCount &= 0xffffff; - } - - using IFastBitmap bb = FastBitmap.Create((Bitmap) sourceImage); - for (int y = 0; y < bb.Height; y++) - { - for (int x = 0; x < bb.Width; x++) - { - int bitmapcolor = bb.GetColorAt(x, y).ToArgb(); - if (!includeAlpha) - { - bitmapcolor &= 0xffffff; - } - - if (bitmapcolor == toCount) - { - colors++; - } - } - } - - return colors; - } - - /// - /// Scale the bitmap, keeping aspect ratio, but the canvas will always have the specified size. - /// - /// Image to scale - /// true to maintain the aspect ratio - /// Makes the image maintain aspect ratio, but the canvas get's the specified size - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// new width - /// new height - /// - /// a new bitmap with the specified size, the source-Image scaled to fit with aspect ratio locked - public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, bool canvasUseNewSize, Color backgroundColor, int newWidth, int newHeight, Matrix matrix) - { - int destX = 0; - int destY = 0; - - var nPercentW = newWidth / (float) sourceImage.Width; - var nPercentH = newHeight / (float) sourceImage.Height; - if (maintainAspectRatio) - { - if ((int) nPercentW == 1) - { - nPercentW = nPercentH; - if (canvasUseNewSize) - { - destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); - } - } - else if ((int) nPercentH == 1) - { - nPercentH = nPercentW; - if (canvasUseNewSize) - { - destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); - } - } - else if ((int) nPercentH != 0 && nPercentH < nPercentW) - { - nPercentW = nPercentH; - if (canvasUseNewSize) - { - destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); - } - } - else - { - nPercentH = nPercentW; - if (canvasUseNewSize) - { - destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); - } - } - } - - int destWidth = (int) (sourceImage.Width * nPercentW); - int destHeight = (int) (sourceImage.Height * nPercentH); - if (newWidth == 0) - { - newWidth = destWidth; - } - - if (newHeight == 0) - { - newHeight = destHeight; - } - - Image newImage; - if (maintainAspectRatio && canvasUseNewSize) - { - newImage = CreateEmpty(newWidth, newHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - matrix?.Scale((float) newWidth / sourceImage.Width, (float) newHeight / sourceImage.Height, MatrixOrder.Append); - } - else - { - newImage = CreateEmpty(destWidth, destHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - matrix?.Scale((float) destWidth / sourceImage.Width, (float) destHeight / sourceImage.Height, MatrixOrder.Append); - } - - using (Graphics graphics = Graphics.FromImage(newImage)) - { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - using ImageAttributes wrapMode = new ImageAttributes(); - wrapMode.SetWrapMode(WrapMode.TileFlipXY); - graphics.DrawImage(sourceImage, new Rectangle(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode); - } - - return newImage; - } - - /// - /// Load a Greenshot surface from a stream - /// - /// Stream - /// - /// ISurface - public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface) - { - Image fileImage; - // Fixed problem that the bitmap stream is disposed... by Cloning the image - // This also ensures the bitmap is correctly created - - // We create a copy of the bitmap, so everything else can be disposed - surfaceFileStream.Position = 0; - using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) - { - Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - fileImage = Clone(tmpImage); - } - - // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) - const int markerSize = 14; - surfaceFileStream.Seek(-markerSize, SeekOrigin.End); - using (StreamReader streamReader = new StreamReader(surfaceFileStream)) - { - var greenshotMarker = streamReader.ReadToEnd(); - if (!greenshotMarker.StartsWith("Greenshot")) - { - throw new ArgumentException("Stream is not a Greenshot file!"); - } - - Log.InfoFormat("Greenshot file format: {0}", greenshotMarker); - const int filesizeLocation = 8 + markerSize; - surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); - using BinaryReader reader = new BinaryReader(surfaceFileStream); - long bytesWritten = reader.ReadInt64(); - surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End); - returnSurface.LoadElementsFromStream(surfaceFileStream); - } - - if (fileImage != null) - { - returnSurface.Image = fileImage; - Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat, - fileImage.HorizontalResolution, fileImage.VerticalResolution); - } - - return returnSurface; - } - - /// - /// Create an image from a stream, if an extension is supplied more formats are supported. - /// - /// Stream - /// - /// Image - public static Image FromStream(Stream stream, string extension = null) - { - if (stream == null) - { - return null; - } - - if (!string.IsNullOrEmpty(extension)) - { - extension = extension.Replace(".", string.Empty); - } - - // Make sure we can try multiple times - if (!stream.CanSeek) - { - var memoryStream = new MemoryStream(); - stream.CopyTo(memoryStream); - stream = memoryStream; - } - - Image returnImage = null; - if (StreamConverters.TryGetValue(extension ?? string.Empty, out var converter)) - { - returnImage = converter(stream, extension); - } - - // Fallback - if (returnImage == null) - { - // We create a copy of the bitmap, so everything else can be disposed - stream.Position = 0; - using var tmpImage = Image.FromStream(stream, true, true); - Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - returnImage = Clone(tmpImage, PixelFormat.Format32bppArgb); - } - - return returnImage; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using Greenshot.Base.Effects; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.UnmanagedHelpers; +using log4net; + +namespace Greenshot.Base.Core +{ + internal enum ExifOrientations : byte + { + Unknown = 0, + TopLeft = 1, + TopRight = 2, + BottomRight = 3, + BottomLeft = 4, + LeftTop = 5, + RightTop = 6, + RightBottom = 7, + LeftBottom = 8, + } + + /// + /// Description of ImageHelper. + /// + public static class ImageHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private const int ExifOrientationId = 0x0112; + + static ImageHelper() + { + StreamConverters["greenshot"] = (stream, s) => + { + var surface = SimpleServiceProvider.Current.GetInstance>().Invoke(); + return surface.GetImageForExport(); + }; + + // Add a SVG converter + StreamConverters["svg"] = (stream, s) => + { + stream.Position = 0; + try + { + return SvgImage.FromStream(stream).Image; + } + catch (Exception ex) + { + Log.Error("Can't load SVG", ex); + } + + return null; + }; + + static Image DefaultConverter(Stream stream, string s) + { + stream.Position = 0; + using var tmpImage = Image.FromStream(stream, true, true); + Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); + return Clone(tmpImage, PixelFormat.Format32bppArgb); + } + + // Fallback + StreamConverters[string.Empty] = DefaultConverter; + StreamConverters["gif"] = DefaultConverter; + StreamConverters["bmp"] = DefaultConverter; + StreamConverters["jpg"] = DefaultConverter; + StreamConverters["jpeg"] = DefaultConverter; + StreamConverters["png"] = DefaultConverter; + StreamConverters["wmf"] = DefaultConverter; + + StreamConverters["ico"] = (stream, extension) => + { + // Icon logic, try to get the Vista icon, else the biggest possible + try + { + using Image tmpImage = ExtractVistaIcon(stream); + if (tmpImage != null) + { + return Clone(tmpImage, PixelFormat.Format32bppArgb); + } + } + catch (Exception vistaIconException) + { + Log.Warn("Can't read icon", vistaIconException); + } + + try + { + // No vista icon, try normal icon + stream.Position = 0; + // We create a copy of the bitmap, so everything else can be disposed + using Icon tmpIcon = new Icon(stream, new Size(1024, 1024)); + using Image tmpImage = tmpIcon.ToBitmap(); + return Clone(tmpImage, PixelFormat.Format32bppArgb); + } + catch (Exception iconException) + { + Log.Warn("Can't read icon", iconException); + } + + stream.Position = 0; + return DefaultConverter(stream, extension); + }; + } + + public static IDictionary> StreamConverters { get; } = new Dictionary>(); + + /// + /// Make sure the image is orientated correctly + /// + /// + public static void Orientate(Image image) + { + if (!CoreConfig.ProcessEXIFOrientation) + { + return; + } + + try + { + // Get the index of the orientation property. + int orientationIndex = Array.IndexOf(image.PropertyIdList, ExifOrientationId); + // If there is no such property, return Unknown. + if (orientationIndex < 0) + { + return; + } + + PropertyItem item = image.GetPropertyItem(ExifOrientationId); + + ExifOrientations orientation = (ExifOrientations) item.Value[0]; + // Orient the image. + switch (orientation) + { + case ExifOrientations.Unknown: + case ExifOrientations.TopLeft: + break; + case ExifOrientations.TopRight: + image.RotateFlip(RotateFlipType.RotateNoneFlipX); + break; + case ExifOrientations.BottomRight: + image.RotateFlip(RotateFlipType.Rotate180FlipNone); + break; + case ExifOrientations.BottomLeft: + image.RotateFlip(RotateFlipType.RotateNoneFlipY); + break; + case ExifOrientations.LeftTop: + image.RotateFlip(RotateFlipType.Rotate90FlipX); + break; + case ExifOrientations.RightTop: + image.RotateFlip(RotateFlipType.Rotate90FlipNone); + break; + case ExifOrientations.RightBottom: + image.RotateFlip(RotateFlipType.Rotate90FlipY); + break; + case ExifOrientations.LeftBottom: + image.RotateFlip(RotateFlipType.Rotate270FlipNone); + break; + } + + // Set the orientation to be normal, as we rotated the image. + item.Value[0] = (byte) ExifOrientations.TopLeft; + image.SetPropertyItem(item); + } + catch (Exception orientEx) + { + Log.Warn("Problem orientating the image: ", orientEx); + } + } + + /// + /// Create a Thumbnail + /// + /// + /// + /// + /// + /// + /// + public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight, int maxWidth = -1, int maxHeight = -1) + { + int srcWidth = image.Width; + int srcHeight = image.Height; + if (thumbHeight < 0) + { + thumbHeight = (int) (thumbWidth * (srcHeight / (float) srcWidth)); + } + + if (thumbWidth < 0) + { + thumbWidth = (int) (thumbHeight * (srcWidth / (float) srcHeight)); + } + + if (maxWidth > 0 && thumbWidth > maxWidth) + { + thumbWidth = Math.Min(thumbWidth, maxWidth); + thumbHeight = (int) (thumbWidth * (srcHeight / (float) srcWidth)); + } + + if (maxHeight > 0 && thumbHeight > maxHeight) + { + thumbHeight = Math.Min(thumbHeight, maxHeight); + thumbWidth = (int) (thumbHeight * (srcWidth / (float) srcHeight)); + } + + Bitmap bmp = new Bitmap(thumbWidth, thumbHeight); + using (Graphics graphics = Graphics.FromImage(bmp)) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight); + graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); + } + + return bmp; + } + + /// + /// Crops the image to the specified rectangle + /// + /// Image to crop + /// Rectangle with bitmap coordinates, will be "intersected" to the bitmap + public static bool Crop(ref Image image, ref Rectangle cropRectangle) + { + if (image is Bitmap && (image.Width * image.Height > 0)) + { + cropRectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height)); + if (cropRectangle.Width != 0 || cropRectangle.Height != 0) + { + Image returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare); + image.Dispose(); + image = returnImage; + return true; + } + } + + Log.Warn("Can't crop a null/zero size image!"); + return false; + } + + /// + /// Private helper method for the FindAutoCropRectangle + /// + /// + /// + /// + /// Rectangle + private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) + { + Rectangle cropRectangle = Rectangle.Empty; + Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); + Point min = new Point(int.MaxValue, int.MaxValue); + Point max = new Point(int.MinValue, int.MinValue); + + if (cropDifference > 0) + { + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { + Color currentColor = fastBitmap.GetColorAt(x, y); + int diffR = Math.Abs(currentColor.R - referenceColor.R); + int diffG = Math.Abs(currentColor.G - referenceColor.G); + int diffB = Math.Abs(currentColor.B - referenceColor.B); + if ((diffR + diffG + diffB) / 3 <= cropDifference) + { + continue; + } + + if (x < min.X) min.X = x; + if (y < min.Y) min.Y = y; + if (x > max.X) max.X = x; + if (y > max.Y) max.Y = y; + } + } + } + else + { + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { + Color currentColor = fastBitmap.GetColorAt(x, y); + if (!referenceColor.Equals(currentColor)) + { + continue; + } + + if (x < min.X) min.X = x; + if (y < min.Y) min.Y = y; + if (x > max.X) max.X = x; + if (y > max.Y) max.Y = y; + } + } + } + + if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) + { + if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) + { + cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); + } + } + + return cropRectangle; + } + + /// + /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 + /// + /// + /// + /// Rectangle + public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) + { + Rectangle cropRectangle = Rectangle.Empty; + var checkPoints = new List + { + new Point(0, 0), + new Point(0, image.Height - 1), + new Point(image.Width - 1, 0), + new Point(image.Width - 1, image.Height - 1) + }; + // Top Left + // Bottom Left + // Top Right + // Bottom Right + using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap) image)) + { + // find biggest area + foreach (Point checkPoint in checkPoints) + { + var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); + if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) + { + cropRectangle = currentRectangle; + } + } + } + + return cropRectangle; + } + + /// + /// Load an image from file + /// + /// + /// + public static Image LoadImage(string filename) + { + if (string.IsNullOrEmpty(filename)) + { + return null; + } + + if (!File.Exists(filename)) + { + return null; + } + + Image fileImage; + Log.InfoFormat("Loading image from file {0}", filename); + // Fixed lock problem Bug #3431881 + using (Stream imageFileStream = File.OpenRead(filename)) + { + fileImage = FromStream(imageFileStream, Path.GetExtension(filename)); + } + + if (fileImage != null) + { + Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat, + fileImage.HorizontalResolution, fileImage.VerticalResolution); + } + + return fileImage; + } + + /// + /// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx + /// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx + /// + /// Stream with the icon information + /// Bitmap with the Vista Icon (256x256) + private static Bitmap ExtractVistaIcon(Stream iconStream) + { + const int sizeIconDir = 6; + const int sizeIconDirEntry = 16; + Bitmap bmpPngExtracted = null; + try + { + byte[] srcBuf = new byte[iconStream.Length]; + iconStream.Read(srcBuf, 0, (int) iconStream.Length); + int iCount = BitConverter.ToInt16(srcBuf, 4); + for (int iIndex = 0; iIndex < iCount; iIndex++) + { + int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex]; + int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1]; + if (iWidth == 0 && iHeight == 0) + { + int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); + int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); + using MemoryStream destStream = new MemoryStream(); + destStream.Write(srcBuf, iImageOffset, iImageSize); + destStream.Seek(0, SeekOrigin.Begin); + bmpPngExtracted = new Bitmap(destStream); // This is PNG! :) + break; + } + } + } + catch + { + return null; + } + + return bmpPngExtracted; + } + + /// + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx + /// + /// The file (EXE or DLL) to get the icon from + /// Index of the icon + /// true if the large icon is wanted + /// Icon + public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) + { + Shell32.ExtractIconEx(location, index, out var large, out var small, 1); + Icon returnIcon = null; + bool isLarge = false; + bool isSmall = false; + try + { + if (takeLarge && !IntPtr.Zero.Equals(large)) + { + returnIcon = Icon.FromHandle(large); + isLarge = true; + } + else if (!IntPtr.Zero.Equals(small)) + { + returnIcon = Icon.FromHandle(small); + isSmall = true; + } + else if (!IntPtr.Zero.Equals(large)) + { + returnIcon = Icon.FromHandle(large); + isLarge = true; + } + } + finally + { + if (isLarge && !IntPtr.Zero.Equals(small)) + { + User32.DestroyIcon(small); + } + + if (isSmall && !IntPtr.Zero.Equals(large)) + { + User32.DestroyIcon(large); + } + } + + return returnIcon; + } + + /// + /// Apply the effect to the bitmap + /// + /// Bitmap + /// IEffect + /// + /// Bitmap + public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix) + { + var effects = new List + { + effect + }; + return ApplyEffects(sourceImage, effects, matrix); + } + + /// + /// Apply the effects in the supplied order to the bitmap + /// + /// Bitmap + /// List of IEffect + /// + /// Bitmap + public static Image ApplyEffects(Image sourceImage, IEnumerable effects, Matrix matrix) + { + var currentImage = sourceImage; + bool disposeImage = false; + foreach (var effect in effects) + { + var tmpImage = effect.Apply(currentImage, matrix); + if (tmpImage != null) + { + if (disposeImage) + { + currentImage.Dispose(); + } + + currentImage = tmpImage; + // Make sure the "new" image is disposed + disposeImage = true; + } + } + + return currentImage; + } + + /// + /// Helper method for the tornedge + /// + /// Path to draw to + /// Points for the lines to draw + private static void DrawLines(GraphicsPath path, List points) + { + path.AddLine(points[0], points[1]); + for (int i = 0; i < points.Count - 1; i++) + { + path.AddLine(points[i], points[i + 1]); + } + } + + /// + /// Make the picture look like it's torn + /// + /// Bitmap to make torn edge off + /// How large (height) is each tooth + /// How wide is a horizontal tooth + /// How wide is a vertical tooth + /// bool[] with information on if the edge needs torn or not. Order is clockwise: 0=top,1=right,2=bottom,3=left + /// Changed bitmap + public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, bool[] edges) + { + Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, + sourceImage.VerticalResolution); + using (var path = new GraphicsPath()) + { + Random random = new Random(); + int horizontalRegions = (int) Math.Round((float) sourceImage.Width / horizontalToothRange); + int verticalRegions = (int) Math.Round((float) sourceImage.Height / verticalToothRange); + + Point topLeft = new Point(0, 0); + Point topRight = new Point(sourceImage.Width, 0); + Point bottomLeft = new Point(0, sourceImage.Height); + Point bottomRight = new Point(sourceImage.Width, sourceImage.Height); + + List points = new List(); + + if (edges[0]) + { + // calculate starting point only if the left edge is torn + if (!edges[3]) + { + points.Add(topLeft); + } + else + { + points.Add(new Point(random.Next(1, toothHeight), random.Next(1, toothHeight))); + } + + for (int i = 1; i < horizontalRegions - 1; i++) + { + points.Add(new Point(i * horizontalToothRange, random.Next(1, toothHeight))); + } + + points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight))); + } + else + { + // set start & endpoint to be the default "whole-line" + points.Add(topLeft); + points.Add(topRight); + } + + // Right + if (edges[1]) + { + for (int i = 1; i < verticalRegions - 1; i++) + { + points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange)); + } + + points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); + } + else + { + // correct previous ending point + points[points.Count - 1] = topRight; + // set endpoint to be the default "whole-line" + points.Add(bottomRight); + } + + // Bottom + if (edges[2]) + { + for (int i = 1; i < horizontalRegions - 1; i++) + { + points.Add(new Point(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight))); + } + + points.Add(new Point(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); + } + else + { + // correct previous ending point + points[points.Count - 1] = bottomRight; + // set endpoint to be the default "whole-line" + points.Add(bottomLeft); + } + + // Left + if (edges[3]) + { + // One fewer as the end point is the starting point + for (int i = 1; i < verticalRegions - 1; i++) + { + points.Add(new Point(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange)); + } + } + else + { + // correct previous ending point + points[points.Count - 1] = bottomLeft; + // set endpoint to be the default "whole-line" + points.Add(topLeft); + } + + // End point always is the starting point + points[points.Count - 1] = points[0]; + + DrawLines(path, points); + + path.CloseFigure(); + + // Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing + using Graphics graphics = Graphics.FromImage(returnImage); + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + using Brush brush = new TextureBrush(sourceImage); + // Important note: If the target wouldn't be at 0,0 we need to translate-transform!! + graphics.FillPath(brush, path); + } + + return returnImage; + } + + /// + /// Apply BoxBlur to the destinationBitmap + /// + /// Bitmap to blur + /// Must be ODD! + public static void ApplyBoxBlur(Bitmap destinationBitmap, int range) + { + // We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V) + using IFastBitmap fastBitmap = FastBitmap.Create(destinationBitmap); + ApplyBoxBlur(fastBitmap, range); + } + + /// + /// Apply BoxBlur to the fastBitmap + /// + /// IFastBitmap to blur + /// Must be ODD! + public static void ApplyBoxBlur(IFastBitmap fastBitmap, int range) + { + // Range must be odd! + if ((range & 1) == 0) + { + range++; + } + + if (range <= 1) + { + return; + } + + // Box blurs are frequently used to approximate a Gaussian blur. + // By the central limit theorem, if applied 3 times on the same image, a box blur approximates the Gaussian kernel to within about 3%, yielding the same result as a quadratic convolution kernel. + // This might be true, but the GDI+ BlurEffect doesn't look the same, a 2x blur is more simular and we only make 2x Box-Blur. + // (Might also be a mistake in our blur, but for now it looks great) + if (fastBitmap.HasAlphaChannel) + { + BoxBlurHorizontalAlpha(fastBitmap, range); + BoxBlurVerticalAlpha(fastBitmap, range); + BoxBlurHorizontalAlpha(fastBitmap, range); + BoxBlurVerticalAlpha(fastBitmap, range); + } + else + { + BoxBlurHorizontal(fastBitmap, range); + BoxBlurVertical(fastBitmap, range); + BoxBlurHorizontal(fastBitmap, range); + BoxBlurVertical(fastBitmap, range); + } + } + + /// + /// BoxBlurHorizontal is a private helper method for the BoxBlur + /// + /// Target BitmapBuffer + /// Range must be odd! + private static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) + { + if (targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel"); + } + + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Width]; + byte[] tmpColor = new byte[3]; + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + int hits = 0; + int r = 0; + int g = 0; + int b = 0; + for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) + { + int oldPixel = x - halfRange - 1; + if (oldPixel >= targetFastBitmap.Left) + { + targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } + + int newPixel = x + halfRange; + if (newPixel < targetFastBitmap.Right) + { + targetFastBitmap.GetColorAt(newPixel, y, tmpColor); + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } + + if (x >= targetFastBitmap.Left) + { + newColors[x - targetFastBitmap.Left] = Color.FromArgb(255, (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } + + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); + } + } + } + + /// + /// BoxBlurHorizontal is a private helper method for the BoxBlur, only for IFastBitmaps with alpha channel + /// + /// Target BitmapBuffer + /// Range must be odd! + private static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) + { + if (!targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel"); + } + + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Width]; + byte[] tmpColor = new byte[4]; + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + int hits = 0; + int a = 0; + int r = 0; + int g = 0; + int b = 0; + for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) + { + int oldPixel = x - halfRange - 1; + if (oldPixel >= targetFastBitmap.Left) + { + targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); + a -= tmpColor[FastBitmap.ColorIndexA]; + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } + + int newPixel = x + halfRange; + if (newPixel < targetFastBitmap.Right) + { + targetFastBitmap.GetColorAt(newPixel, y, tmpColor); + a += tmpColor[FastBitmap.ColorIndexA]; + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } + + if (x >= targetFastBitmap.Left) + { + newColors[x - targetFastBitmap.Left] = Color.FromArgb((byte) (a / hits), (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } + + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); + } + } + } + + /// + /// BoxBlurVertical is a private helper method for the BoxBlur + /// + /// BitmapBuffer which previously was created with BoxBlurHorizontal + /// Range must be odd! + private static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) + { + if (targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel"); + } + + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Height]; + byte[] tmpColor = new byte[4]; + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + int hits = 0; + int r = 0; + int g = 0; + int b = 0; + for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) + { + int oldPixel = y - halfRange - 1; + if (oldPixel >= targetFastBitmap.Top) + { + targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } + + int newPixel = y + halfRange; + if (newPixel < targetFastBitmap.Bottom) + { + targetFastBitmap.GetColorAt(x, newPixel, tmpColor); + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } + + if (y >= targetFastBitmap.Top) + { + newColors[y - targetFastBitmap.Top] = Color.FromArgb(255, (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } + + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); + } + } + } + + /// + /// BoxBlurVertical is a private helper method for the BoxBlur + /// + /// BitmapBuffer which previously was created with BoxBlurHorizontal + /// Range must be odd! + private static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) + { + if (!targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurVerticalAlpha should be called for bitmaps with alpha channel"); + } + + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Height]; + byte[] tmpColor = new byte[4]; + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + int hits = 0; + int a = 0; + int r = 0; + int g = 0; + int b = 0; + for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) + { + int oldPixel = y - halfRange - 1; + if (oldPixel >= targetFastBitmap.Top) + { + targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); + a -= tmpColor[FastBitmap.ColorIndexA]; + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } + + int newPixel = y + halfRange; + if (newPixel < targetFastBitmap.Bottom) + { + //int colorg = pixels[index + newPixelOffset]; + targetFastBitmap.GetColorAt(x, newPixel, tmpColor); + a += tmpColor[FastBitmap.ColorIndexA]; + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } + + if (y >= targetFastBitmap.Top) + { + newColors[y - targetFastBitmap.Top] = Color.FromArgb((byte) (a / hits), (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } + + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); + } + } + } + + /// + /// This method fixes the problem that we can't apply a filter outside the target bitmap, + /// therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap. + /// It will also account for the Invert flag. + /// + /// + /// + /// + /// + public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) + { + Rectangle myRect; + if (invert) + { + myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); + } + else + { + Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height); + myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); + myRect.Intersect(applyRect); + } + + return myRect; + } + + /// + /// Create a new bitmap where the sourceBitmap has a shadow + /// + /// Bitmap to make a shadow on + /// How dark is the shadow + /// Size of the shadow + /// What pixel format must the returning bitmap have + /// + /// The transform matrix which describes how the elements need to be transformed to stay at the same location + /// Bitmap with the shadow, is bigger than the sourceBitmap!! + public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, Matrix matrix, PixelFormat targetPixelformat) + { + Point offset = shadowOffset; + offset.X += shadowSize - 1; + offset.Y += shadowSize - 1; + matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); + // Create a new "clean" image + Bitmap returnImage = CreateEmpty(sourceBitmap.Width + shadowSize * 2, sourceBitmap.Height + shadowSize * 2, targetPixelformat, Color.Empty, + sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); + // Make sure the shadow is odd, there is no reason for an even blur! + if ((shadowSize & 1) == 0) + { + shadowSize++; + } + + bool useGdiBlur = GDIplus.IsBlurPossible(shadowSize); + // Create "mask" for the shadow + ColorMatrix maskMatrix = new ColorMatrix + { + Matrix00 = 0, + Matrix11 = 0, + Matrix22 = 0 + }; + if (useGdiBlur) + { + maskMatrix.Matrix33 = darkness + 0.1f; + } + else + { + maskMatrix.Matrix33 = darkness; + } + + Rectangle shadowRectangle = new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size); + ApplyColorMatrix((Bitmap) sourceBitmap, Rectangle.Empty, returnImage, shadowRectangle, maskMatrix); + + // blur "shadow", apply to whole new image + if (useGdiBlur) + { + // Use GDI Blur + Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height); + GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize + 1, false); + } + else + { + // try normal software blur + //returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); + ApplyBoxBlur(returnImage, shadowSize); + } + + // Draw the original image over the shadow + using (Graphics graphics = Graphics.FromImage(returnImage)) + { + // Make sure we draw with the best quality! + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + // draw original with a TextureBrush so we have nice antialiasing! + using Brush textureBrush = new TextureBrush(sourceBitmap, WrapMode.Clamp); + // We need to do a translate-transform otherwise the image is wrapped + graphics.TranslateTransform(offset.X, offset.Y); + graphics.FillRectangle(textureBrush, 0, 0, sourceBitmap.Width, sourceBitmap.Height); + } + + return returnImage; + } + + /// + /// Return negative of Bitmap + /// + /// Bitmap to create a negative off + /// Negative bitmap + public static Bitmap CreateNegative(Image sourceImage) + { + Bitmap clone = (Bitmap) Clone(sourceImage); + ColorMatrix invertMatrix = new ColorMatrix(new[] + { + new float[] + { + -1, 0, 0, 0, 0 + }, + new float[] + { + 0, -1, 0, 0, 0 + }, + new float[] + { + 0, 0, -1, 0, 0 + }, + new float[] + { + 0, 0, 0, 1, 0 + }, + new float[] + { + 1, 1, 1, 1, 1 + } + }); + ApplyColorMatrix(clone, invertMatrix); + return clone; + } + + /// + /// Apply a color matrix to the image + /// + /// Image to apply matrix to + /// ColorMatrix to apply + public static void ApplyColorMatrix(Bitmap source, ColorMatrix colorMatrix) + { + ApplyColorMatrix(source, Rectangle.Empty, source, Rectangle.Empty, colorMatrix); + } + + /// + /// Apply a color matrix by copying from the source to the destination + /// + /// Image to copy from + /// Rectangle to copy from + /// Rectangle to copy to + /// Image to copy to + /// ColorMatrix to apply + public static void ApplyColorMatrix(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ColorMatrix colorMatrix) + { + using ImageAttributes imageAttributes = new ImageAttributes(); + imageAttributes.ClearColorMatrix(); + imageAttributes.SetColorMatrix(colorMatrix); + ApplyImageAttributes(source, sourceRect, dest, destRect, imageAttributes); + } + + /// + /// Apply a color matrix by copying from the source to the destination + /// + /// Image to copy from + /// Rectangle to copy from + /// Rectangle to copy to + /// Image to copy to + /// ImageAttributes to apply + public static void ApplyImageAttributes(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ImageAttributes imageAttributes) + { + if (sourceRect == Rectangle.Empty) + { + sourceRect = new Rectangle(0, 0, source.Width, source.Height); + } + + if (dest == null) + { + dest = source; + } + + if (destRect == Rectangle.Empty) + { + destRect = new Rectangle(0, 0, dest.Width, dest.Height); + } + + using Graphics graphics = Graphics.FromImage(dest); + // Make sure we draw with the best quality! + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingMode = CompositingMode.SourceCopy; + + graphics.DrawImage(source, destRect, sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height, GraphicsUnit.Pixel, imageAttributes); + } + + /// + /// Returns a b/w of Bitmap + /// + /// Bitmap to create a b/w of + /// Threshold for monochrome filter (0 - 255), lower value means less black + /// b/w bitmap + public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) + { + using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat); + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { + Color color = fastBitmap.GetColorAt(x, y); + int colorBrightness = (color.R + color.G + color.B) / 3 > threshold ? 255 : 0; + Color monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness); + fastBitmap.SetColorAt(x, y, monoColor); + } + } + + return fastBitmap.UnlockAndReturnBitmap(); + } + + /// + /// Create a new bitmap where the sourceBitmap has a Simple border around it + /// + /// Bitmap to make a border on + /// Size of the border + /// Color of the border + /// What pixel format must the returning bitmap have + /// The transform matrix which describes how the elements need to be transformed to stay at the same location + /// Bitmap with the shadow, is bigger than the sourceBitmap!! + public static Image CreateBorder(Image sourceImage, int borderSize, Color borderColor, PixelFormat targetPixelformat, Matrix matrix) + { + // "return" the shifted offset, so the caller can e.g. move elements + Point offset = new Point(borderSize, borderSize); + matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); + + // Create a new "clean" image + Bitmap newImage = CreateEmpty(sourceImage.Width + borderSize * 2, sourceImage.Height + borderSize * 2, targetPixelformat, Color.Empty, sourceImage.HorizontalResolution, + sourceImage.VerticalResolution); + using (Graphics graphics = Graphics.FromImage(newImage)) + { + // Make sure we draw with the best quality! + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + using (GraphicsPath path = new GraphicsPath()) + { + path.AddRectangle(new Rectangle(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize)); + using Pen pen = new Pen(borderColor, borderSize) + { + LineJoin = LineJoin.Round, + StartCap = LineCap.Round, + EndCap = LineCap.Round + }; + graphics.DrawPath(pen, path); + } + + // draw original with a TextureBrush so we have nice antialiasing! + using Brush textureBrush = new TextureBrush(sourceImage, WrapMode.Clamp); + // We need to do a translate-tranform otherwise the image is wrapped + graphics.TranslateTransform(offset.X, offset.Y); + graphics.FillRectangle(textureBrush, 0, 0, sourceImage.Width, sourceImage.Height); + } + + return newImage; + } + + /// + /// Create ImageAttributes to modify + /// + /// + /// + /// + /// ImageAttributes + public static ImageAttributes CreateAdjustAttributes(float brightness, float contrast, float gamma) + { + float adjustedBrightness = brightness - 1.0f; + ColorMatrix applyColorMatrix = new ColorMatrix( + new[] + { + new[] + { + contrast, 0, 0, 0, 0 + }, // scale red + new[] + { + 0, contrast, 0, 0, 0 + }, // scale green + new[] + { + 0, 0, contrast, 0, 0 + }, // scale blue + new[] + { + 0, 0, 0, 1.0f, 0 + }, // don't scale alpha + new[] + { + adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1 + } + }); + + //create some image attributes + ImageAttributes attributes = new ImageAttributes(); + attributes.ClearColorMatrix(); + attributes.SetColorMatrix(applyColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); + attributes.SetGamma(gamma, ColorAdjustType.Bitmap); + return attributes; + } + + /// + /// Adjust the brightness, contract or gamma of an image. + /// Use the value "1.0f" for no changes. + /// + /// Original bitmap + /// + /// + /// + /// Bitmap with grayscale + public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) + { + //create a blank bitmap the same size as original + // If using 8bpp than the following exception comes: A Graphics object cannot be created from an image that has an indexed pixel format. + Bitmap newBitmap = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format24bppRgb, Color.Empty, sourceImage.HorizontalResolution, + sourceImage.VerticalResolution); + using (ImageAttributes adjustAttributes = CreateAdjustAttributes(brightness, contrast, gamma)) + { + ApplyImageAttributes((Bitmap) sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, adjustAttributes); + } + + return newBitmap; + } + + /// + /// Create a new bitmap where the sourceBitmap is in grayscale + /// + /// Original bitmap + /// Bitmap with grayscale + public static Image CreateGrayscale(Image sourceImage) + { + Bitmap clone = (Bitmap) Clone(sourceImage); + ColorMatrix grayscaleMatrix = new ColorMatrix(new[] + { + new[] + { + .3f, .3f, .3f, 0, 0 + }, + new[] + { + .59f, .59f, .59f, 0, 0 + }, + new[] + { + .11f, .11f, .11f, 0, 0 + }, + new float[] + { + 0, 0, 0, 1, 0 + }, + new float[] + { + 0, 0, 0, 0, 1 + } + }); + ApplyColorMatrix(clone, grayscaleMatrix); + return clone; + } + + /// + /// Checks if we support the pixel format + /// + /// PixelFormat to check + /// bool if we support it + public static bool SupportsPixelFormat(PixelFormat pixelformat) + { + return pixelformat.Equals(PixelFormat.Format32bppArgb) || + pixelformat.Equals(PixelFormat.Format32bppPArgb) || + pixelformat.Equals(PixelFormat.Format32bppRgb) || + pixelformat.Equals(PixelFormat.Format24bppRgb); + } + + /// + /// Wrapper for just cloning which calls the CloneArea + /// + /// Image to clone + /// Bitmap with clone image data + public static Image Clone(Image sourceImage) + { + if (sourceImage is Metafile) + { + return (Image) sourceImage.Clone(); + } + + return CloneArea(sourceImage, Rectangle.Empty, PixelFormat.DontCare); + } + + /// + /// Wrapper for just cloning & TargetFormat which calls the CloneArea + /// + /// Image to clone + /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) + /// Bitmap with clone image data + public static Bitmap Clone(Image sourceBitmap, PixelFormat targetFormat) + { + return CloneArea(sourceBitmap, Rectangle.Empty, targetFormat); + } + + /// + /// Clone an image, taking some rules into account: + /// 1) When sourceRect is the whole bitmap there is a GDI+ bug in Clone + /// Clone will than return the same PixelFormat as the source + /// a quick workaround is using new Bitmap which uses a default of Format32bppArgb + /// 2) When going from a transparent to a non transparent bitmap, we draw the background white! + /// + /// Source bitmap to clone + /// Rectangle to copy from the source, use Rectangle.Empty for all + /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) + /// + public static Bitmap CloneArea(Image sourceImage, Rectangle sourceRect, PixelFormat targetFormat) + { + Bitmap newImage; + Rectangle bitmapRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); + + // Make sure the source is not Rectangle.Empty + if (Rectangle.Empty.Equals(sourceRect)) + { + sourceRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); + } + else + { + sourceRect.Intersect(bitmapRect); + } + + // If no pixelformat is supplied + if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) + { + if (SupportsPixelFormat(sourceImage.PixelFormat)) + { + targetFormat = sourceImage.PixelFormat; + } + else if (Image.IsAlphaPixelFormat(sourceImage.PixelFormat)) + { + targetFormat = PixelFormat.Format32bppArgb; + } + else + { + targetFormat = PixelFormat.Format24bppRgb; + } + } + + // check the target format + if (!SupportsPixelFormat(targetFormat)) + { + targetFormat = Image.IsAlphaPixelFormat(targetFormat) ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb; + } + + bool destinationIsTransparent = Image.IsAlphaPixelFormat(targetFormat); + bool sourceIsTransparent = Image.IsAlphaPixelFormat(sourceImage.PixelFormat); + bool fromTransparentToNon = !destinationIsTransparent && sourceIsTransparent; + bool isBitmap = sourceImage is Bitmap; + bool isAreaEqual = sourceRect.Equals(bitmapRect); + if (isAreaEqual || fromTransparentToNon || !isBitmap) + { + // Rule 1: if the areas are equal, always copy ourselves + newImage = new Bitmap(bitmapRect.Width, bitmapRect.Height, targetFormat); + // Make sure both images have the same resolution + newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + + using Graphics graphics = Graphics.FromImage(newImage); + if (fromTransparentToNon) + { + // Rule 2: Make sure the background color is white + graphics.Clear(Color.White); + } + + // decide fastest copy method + if (isAreaEqual) + { + graphics.DrawImageUnscaled(sourceImage, 0, 0); + } + else + { + graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel); + } + } + else + { + // Let GDI+ decide how to convert, need to test what is quicker... + newImage = (sourceImage as Bitmap).Clone(sourceRect, targetFormat); + // Make sure both images have the same resolution + newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + } + + // In WINE someone getting the PropertyItems doesn't work + try + { + // Clone property items (EXIF information etc) + foreach (var propertyItem in sourceImage.PropertyItems) + { + try + { + newImage.SetPropertyItem(propertyItem); + } + catch (Exception innerEx) + { + Log.Warn("Problem cloning a propertyItem.", innerEx); + } + } + } + catch (Exception ex) + { + Log.Warn("Problem cloning a propertyItem.", ex); + } + + return newImage; + } + + /// + /// Rotate the bitmap + /// + /// + /// + /// + public static Image RotateFlip(Image sourceImage, RotateFlipType rotateFlipType) + { + Image returnImage = Clone(sourceImage); + returnImage.RotateFlip(rotateFlipType); + return returnImage; + } + + /// + /// A generic way to create an empty image + /// + /// the source bitmap as the specifications for the new bitmap + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// + public static Bitmap CreateEmptyLike(Image sourceImage, Color backgroundColor) + { + PixelFormat pixelFormat = sourceImage.PixelFormat; + if (backgroundColor.A < 255) + { + pixelFormat = PixelFormat.Format32bppArgb; + } + + return CreateEmpty(sourceImage.Width, sourceImage.Height, pixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + } + + /// + /// A generic way to create an empty image + /// + /// + /// + /// + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// + /// + /// Bitmap + public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution, float verticalResolution) + { + // Create a new "clean" image + Bitmap newImage = new Bitmap(width, height, format); + newImage.SetResolution(horizontalResolution, verticalResolution); + if (format != PixelFormat.Format8bppIndexed) + { + using Graphics graphics = Graphics.FromImage(newImage); + // Make sure the background color is what we want (transparent or white, depending on the pixel format) + if (!Color.Empty.Equals(backgroundColor)) + { + graphics.Clear(backgroundColor); + } + else if (Image.IsAlphaPixelFormat(format)) + { + graphics.Clear(Color.Transparent); + } + else + { + graphics.Clear(Color.White); + } + } + + return newImage; + } + + /// + /// Resize canvas with pixel to the left, right, top and bottom + /// + /// + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// + /// + /// + /// + /// + /// a new bitmap with the source copied on it + public static Image ResizeCanvas(Image sourceImage, Color backgroundColor, int left, int right, int top, int bottom, Matrix matrix) + { + matrix.Translate(left, top, MatrixOrder.Append); + Bitmap newBitmap = CreateEmpty(sourceImage.Width + left + right, sourceImage.Height + top + bottom, sourceImage.PixelFormat, backgroundColor, + sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + using (Graphics graphics = Graphics.FromImage(newBitmap)) + { + graphics.DrawImageUnscaled(sourceImage, left, top); + } + + return newBitmap; + } + + /// + /// Wrapper for the more complex Resize, this resize could be used for e.g. Thumbnails + /// + /// + /// true to maintain the aspect ratio + /// + /// + /// + /// + public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, int newWidth, int newHeight, Matrix matrix) + { + return ResizeImage(sourceImage, maintainAspectRatio, false, Color.Empty, newWidth, newHeight, matrix); + } + + /// + /// Count how many times the supplied color exists + /// + /// Image to count the pixels of + /// Color to count + /// true if Alpha needs to be checked + /// int with the number of pixels which have colorToCount + public static int CountColor(Image sourceImage, Color colorToCount, bool includeAlpha) + { + int colors = 0; + int toCount = colorToCount.ToArgb(); + if (!includeAlpha) + { + toCount &= 0xffffff; + } + + using IFastBitmap bb = FastBitmap.Create((Bitmap) sourceImage); + for (int y = 0; y < bb.Height; y++) + { + for (int x = 0; x < bb.Width; x++) + { + int bitmapcolor = bb.GetColorAt(x, y).ToArgb(); + if (!includeAlpha) + { + bitmapcolor &= 0xffffff; + } + + if (bitmapcolor == toCount) + { + colors++; + } + } + } + + return colors; + } + + /// + /// Scale the bitmap, keeping aspect ratio, but the canvas will always have the specified size. + /// + /// Image to scale + /// true to maintain the aspect ratio + /// Makes the image maintain aspect ratio, but the canvas get's the specified size + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// new width + /// new height + /// + /// a new bitmap with the specified size, the source-Image scaled to fit with aspect ratio locked + public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, bool canvasUseNewSize, Color backgroundColor, int newWidth, int newHeight, Matrix matrix) + { + int destX = 0; + int destY = 0; + + var nPercentW = newWidth / (float) sourceImage.Width; + var nPercentH = newHeight / (float) sourceImage.Height; + if (maintainAspectRatio) + { + if ((int) nPercentW == 1) + { + nPercentW = nPercentH; + if (canvasUseNewSize) + { + destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); + } + } + else if ((int) nPercentH == 1) + { + nPercentH = nPercentW; + if (canvasUseNewSize) + { + destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); + } + } + else if ((int) nPercentH != 0 && nPercentH < nPercentW) + { + nPercentW = nPercentH; + if (canvasUseNewSize) + { + destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); + } + } + else + { + nPercentH = nPercentW; + if (canvasUseNewSize) + { + destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); + } + } + } + + int destWidth = (int) (sourceImage.Width * nPercentW); + int destHeight = (int) (sourceImage.Height * nPercentH); + if (newWidth == 0) + { + newWidth = destWidth; + } + + if (newHeight == 0) + { + newHeight = destHeight; + } + + Image newImage; + if (maintainAspectRatio && canvasUseNewSize) + { + newImage = CreateEmpty(newWidth, newHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + matrix?.Scale((float) newWidth / sourceImage.Width, (float) newHeight / sourceImage.Height, MatrixOrder.Append); + } + else + { + newImage = CreateEmpty(destWidth, destHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + matrix?.Scale((float) destWidth / sourceImage.Width, (float) destHeight / sourceImage.Height, MatrixOrder.Append); + } + + using (Graphics graphics = Graphics.FromImage(newImage)) + { + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + using ImageAttributes wrapMode = new ImageAttributes(); + wrapMode.SetWrapMode(WrapMode.TileFlipXY); + graphics.DrawImage(sourceImage, new Rectangle(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode); + } + + return newImage; + } + + /// + /// Load a Greenshot surface from a stream + /// + /// Stream + /// + /// ISurface + public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface) + { + Image fileImage; + // Fixed problem that the bitmap stream is disposed... by Cloning the image + // This also ensures the bitmap is correctly created + + // We create a copy of the bitmap, so everything else can be disposed + surfaceFileStream.Position = 0; + using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) + { + Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); + fileImage = Clone(tmpImage); + } + + // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) + const int markerSize = 14; + surfaceFileStream.Seek(-markerSize, SeekOrigin.End); + using (StreamReader streamReader = new StreamReader(surfaceFileStream)) + { + var greenshotMarker = streamReader.ReadToEnd(); + if (!greenshotMarker.StartsWith("Greenshot")) + { + throw new ArgumentException("Stream is not a Greenshot file!"); + } + + Log.InfoFormat("Greenshot file format: {0}", greenshotMarker); + const int filesizeLocation = 8 + markerSize; + surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); + using BinaryReader reader = new BinaryReader(surfaceFileStream); + long bytesWritten = reader.ReadInt64(); + surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End); + returnSurface.LoadElementsFromStream(surfaceFileStream); + } + + if (fileImage != null) + { + returnSurface.Image = fileImage; + Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat, + fileImage.HorizontalResolution, fileImage.VerticalResolution); + } + + return returnSurface; + } + + /// + /// Create an image from a stream, if an extension is supplied more formats are supported. + /// + /// Stream + /// + /// Image + public static Image FromStream(Stream stream, string extension = null) + { + if (stream == null) + { + return null; + } + + if (!string.IsNullOrEmpty(extension)) + { + extension = extension.Replace(".", string.Empty); + } + + // Make sure we can try multiple times + if (!stream.CanSeek) + { + var memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + stream = memoryStream; + } + + Image returnImage = null; + if (StreamConverters.TryGetValue(extension ?? string.Empty, out var converter)) + { + returnImage = converter(stream, extension); + } + + // Fallback + if (returnImage == null) + { + // We create a copy of the bitmap, so everything else can be disposed + stream.Position = 0; + using var tmpImage = Image.FromStream(stream, true, true); + Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); + returnImage = Clone(tmpImage, PixelFormat.Format32bppArgb); + } + + return returnImage; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/ImageOutput.cs b/src/Greenshot.Base/Core/ImageOutput.cs similarity index 97% rename from src/GreenshotPlugin/Core/ImageOutput.cs rename to src/Greenshot.Base/Core/ImageOutput.cs index 233ffe377..d6a42a7d9 100644 --- a/src/GreenshotPlugin/Core/ImageOutput.cs +++ b/src/Greenshot.Base/Core/ImageOutput.cs @@ -1,798 +1,798 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.Controls; -using log4net; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.RegularExpressions; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; -using Encoder = System.Drawing.Imaging.Encoder; - -namespace GreenshotPlugin.Core -{ - /// - /// Description of ImageOutput. - /// - public static class ImageOutput - { - private static readonly ILog Log = LogManager.GetLogger(typeof(ImageOutput)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131; - private static readonly Cache TmpFileCache = new Cache(10 * 60 * 60, RemoveExpiredTmpFile); - - /// - /// Creates a PropertyItem (Metadata) to store with the image. - /// For the possible ID's see: http://msdn.microsoft.com/de-de/library/system.drawing.imaging.propertyitem.id(v=vs.80).aspx - /// This code uses Reflection to create a PropertyItem, although it's not adviced it's not as stupid as having a image in the project so we can read a PropertyItem from that! - /// - /// ID - /// Text - /// - private static PropertyItem CreatePropertyItem(int id, string text) - { - PropertyItem propertyItem = null; - try - { - ConstructorInfo ci = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] - { - }, null); - propertyItem = (PropertyItem) ci.Invoke(null); - // Make sure it's of type string - propertyItem.Type = 2; - // Set the ID - propertyItem.Id = id; - // Set the text - byte[] byteString = Encoding.ASCII.GetBytes(text + " "); - // Set Zero byte for String end. - byteString[byteString.Length - 1] = 0; - propertyItem.Value = byteString; - propertyItem.Len = text.Length + 1; - } - catch (Exception e) - { - Log.WarnFormat("Error creating a PropertyItem: {0}", e.Message); - } - - return propertyItem; - } - - /// - /// Saves ISurface to stream with specified output settings - /// - /// ISurface to save - /// Stream to save to - /// SurfaceOutputSettings - public static void SaveToStream(ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) - { - bool disposeImage = CreateImageFromSurface(surface, outputSettings, out var imageToSave); - SaveToStream(imageToSave, surface, stream, outputSettings); - // cleanup if needed - if (disposeImage) - { - imageToSave?.Dispose(); - } - } - - /// - /// Saves image to stream with specified quality - /// To prevent problems with GDI version of before Windows 7: - /// the stream is checked if it's seekable and if needed a MemoryStream as "cache" is used. - /// - /// image to save - /// surface for the elements, needed if the greenshot format is used - /// Stream to save to - /// SurfaceOutputSettings - public static void SaveToStream(Image imageToSave, ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) - { - bool useMemoryStream = false; - MemoryStream memoryStream = null; - if (outputSettings.Format == OutputFormat.greenshot && surface == null) - { - throw new ArgumentException("Surface needs to be set when using OutputFormat.Greenshot"); - } - - try - { - var imageFormat = outputSettings.Format switch - { - OutputFormat.bmp => ImageFormat.Bmp, - OutputFormat.gif => ImageFormat.Gif, - OutputFormat.jpg => ImageFormat.Jpeg, - OutputFormat.tiff => ImageFormat.Tiff, - OutputFormat.ico => ImageFormat.Icon, - _ => ImageFormat.Png - }; - Log.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat); - - // Check if we want to use a memory stream, to prevent issues with non seakable streams - // The save is made to the targetStream, this is directed to either the MemoryStream or the original - Stream targetStream = stream; - if (!stream.CanSeek) - { - useMemoryStream = true; - Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream."); - memoryStream = new MemoryStream(); - targetStream = memoryStream; - } - - if (Equals(imageFormat, ImageFormat.Jpeg)) - { - bool foundEncoder = false; - foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders()) - { - if (imageCodec.FormatID == imageFormat.Guid) - { - EncoderParameters parameters = new EncoderParameters(1) - { - Param = - { - [0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality) - } - }; - // Removing transparency if it's not supported in the output - if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) - { - Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); - AddTag(nonAlphaImage); - nonAlphaImage.Save(targetStream, imageCodec, parameters); - nonAlphaImage.Dispose(); - } - else - { - AddTag(imageToSave); - imageToSave.Save(targetStream, imageCodec, parameters); - } - - foundEncoder = true; - break; - } - } - - if (!foundEncoder) - { - throw new ApplicationException("No JPG encoder found, this should not happen."); - } - } - else if (Equals(imageFormat, ImageFormat.Icon)) - { - // FEATURE-916: Added Icon support - IList images = new List - { - imageToSave - }; - WriteIcon(stream, images); - } - else - { - bool needsDispose = false; - // Removing transparency if it's not supported in the output - if (!Equals(imageFormat, ImageFormat.Png) && Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) - { - imageToSave = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); - needsDispose = true; - } - - AddTag(imageToSave); - // Added for OptiPNG - bool processed = false; - if (Equals(imageFormat, ImageFormat.Png) && !string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) - { - processed = ProcessPngImageExternally(imageToSave, targetStream); - } - - if (!processed) - { - imageToSave.Save(targetStream, imageFormat); - } - - if (needsDispose) - { - imageToSave.Dispose(); - } - } - - // If we used a memory stream, we need to stream the memory stream to the original stream. - if (useMemoryStream) - { - memoryStream.WriteTo(stream); - } - - // Output the surface elements, size and marker to the stream - if (outputSettings.Format != OutputFormat.greenshot) - { - return; - } - - using MemoryStream tmpStream = new MemoryStream(); - long bytesWritten = surface.SaveElementsToStream(tmpStream); - using BinaryWriter writer = new BinaryWriter(tmpStream); - writer.Write(bytesWritten); - Version v = Assembly.GetExecutingAssembly().GetName().Version; - byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); - writer.Write(marker); - tmpStream.WriteTo(stream); - } - finally - { - memoryStream?.Dispose(); - } - } - - /// - /// Write the passed Image to a tmp-file and call an external process, than read the file back and write it to the targetStream - /// - /// Image to pass to the external process - /// stream to write the processed image to - /// - private static bool ProcessPngImageExternally(Image imageToProcess, Stream targetStream) - { - if (string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) - { - return false; - } - - if (!File.Exists(CoreConfig.OptimizePNGCommand)) - { - Log.WarnFormat("Can't find 'OptimizePNGCommand' {0}", CoreConfig.OptimizePNGCommand); - return false; - } - - string tmpFileName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".png"); - try - { - using (FileStream tmpStream = File.Create(tmpFileName)) - { - Log.DebugFormat("Writing png to tmp file: {0}", tmpFileName); - imageToProcess.Save(tmpStream, ImageFormat.Png); - if (Log.IsDebugEnabled) - { - Log.DebugFormat("File size before processing {0}", new FileInfo(tmpFileName).Length); - } - } - - if (Log.IsDebugEnabled) - { - Log.DebugFormat("Starting : {0}", CoreConfig.OptimizePNGCommand); - } - - ProcessStartInfo processStartInfo = new ProcessStartInfo(CoreConfig.OptimizePNGCommand) - { - Arguments = string.Format(CoreConfig.OptimizePNGCommandArguments, tmpFileName), - CreateNoWindow = true, - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false - }; - using Process process = Process.Start(processStartInfo); - if (process != null) - { - process.WaitForExit(); - if (process.ExitCode == 0) - { - if (Log.IsDebugEnabled) - { - Log.DebugFormat("File size after processing {0}", new FileInfo(tmpFileName).Length); - Log.DebugFormat("Reading back tmp file: {0}", tmpFileName); - } - - byte[] processedImage = File.ReadAllBytes(tmpFileName); - targetStream.Write(processedImage, 0, processedImage.Length); - return true; - } - - Log.ErrorFormat("Error while processing PNG image: {0}", process.ExitCode); - Log.ErrorFormat("Output: {0}", process.StandardOutput.ReadToEnd()); - Log.ErrorFormat("Error: {0}", process.StandardError.ReadToEnd()); - } - } - catch (Exception e) - { - Log.Error("Error while processing PNG image: ", e); - } - finally - { - if (File.Exists(tmpFileName)) - { - Log.DebugFormat("Cleaning up tmp file: {0}", tmpFileName); - File.Delete(tmpFileName); - } - } - - return false; - } - - /// - /// Create an image from a surface with the settings from the output settings applied - /// - /// - /// - /// - /// true if the image must be disposed - public static bool CreateImageFromSurface(ISurface surface, SurfaceOutputSettings outputSettings, out Image imageToSave) - { - bool disposeImage = false; - - if (outputSettings.Format == OutputFormat.greenshot || outputSettings.SaveBackgroundOnly) - { - // We save the image of the surface, this should not be disposed - imageToSave = surface.Image; - } - else - { - // We create the export image of the surface to save - imageToSave = surface.GetImageForExport(); - disposeImage = true; - } - - // The following block of modifications should be skipped when saving the greenshot format, no effects or otherwise! - if (outputSettings.Format == OutputFormat.greenshot) - { - return disposeImage; - } - - Image tmpImage; - if (outputSettings.Effects != null && outputSettings.Effects.Count > 0) - { - // apply effects, if there are any - using (Matrix matrix = new Matrix()) - { - tmpImage = ImageHelper.ApplyEffects(imageToSave, outputSettings.Effects, matrix); - } - - if (tmpImage != null) - { - if (disposeImage) - { - imageToSave.Dispose(); - } - - imageToSave = tmpImage; - disposeImage = true; - } - } - - // check for color reduction, forced or automatically, only when the DisableReduceColors is false - if (outputSettings.DisableReduceColors || (!CoreConfig.OutputFileAutoReduceColors && !outputSettings.ReduceColors)) - { - return disposeImage; - } - - bool isAlpha = Image.IsAlphaPixelFormat(imageToSave.PixelFormat); - if (outputSettings.ReduceColors || (!isAlpha && CoreConfig.OutputFileAutoReduceColors)) - { - using var quantizer = new WuQuantizer((Bitmap) imageToSave); - int colorCount = quantizer.GetColorCount(); - Log.InfoFormat("Image with format {0} has {1} colors", imageToSave.PixelFormat, colorCount); - if (!outputSettings.ReduceColors && colorCount >= 256) - { - return disposeImage; - } - - try - { - Log.Info("Reducing colors on bitmap to 256."); - tmpImage = quantizer.GetQuantizedImage(CoreConfig.OutputFileReduceColorsTo); - if (disposeImage) - { - imageToSave.Dispose(); - } - - imageToSave = tmpImage; - // Make sure the "new" image is disposed - disposeImage = true; - } - catch (Exception e) - { - Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); - } - } - else if (isAlpha && !outputSettings.ReduceColors) - { - Log.Info("Skipping 'optional' color reduction as the image has alpha"); - } - - return disposeImage; - } - - /// - /// Add the greenshot property! - /// - /// - private static void AddTag(Image imageToSave) - { - // Create meta-data - PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot"); - if (softwareUsedPropertyItem != null) - { - try - { - imageToSave.SetPropertyItem(softwareUsedPropertyItem); - } - catch (Exception) - { - Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id); - } - } - } - - /// - /// Load a Greenshot surface - /// - /// - /// - /// - public static ISurface LoadGreenshotSurface(string fullPath, ISurface returnSurface) - { - if (string.IsNullOrEmpty(fullPath)) - { - return null; - } - - Log.InfoFormat("Loading image from file {0}", fullPath); - // Fixed lock problem Bug #3431881 - using (Stream surfaceFileStream = File.OpenRead(fullPath)) - { - returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface); - } - - if (returnSurface != null) - { - Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", fullPath, returnSurface.Image.Width, returnSurface.Image.Height, - returnSurface.Image.PixelFormat, returnSurface.Image.HorizontalResolution, returnSurface.Image.VerticalResolution); - } - - return returnSurface; - } - - /// - /// Saves image to specific path with specified quality - /// - public static void Save(ISurface surface, string fullPath, bool allowOverwrite, SurfaceOutputSettings outputSettings, bool copyPathToClipboard) - { - fullPath = FilenameHelper.MakeFqFilenameSafe(fullPath); - string path = Path.GetDirectoryName(fullPath); - - // check whether path exists - if not create it - if (path != null) - { - DirectoryInfo di = new DirectoryInfo(path); - if (!di.Exists) - { - Directory.CreateDirectory(di.FullName); - } - } - - if (!allowOverwrite && File.Exists(fullPath)) - { - ArgumentException throwingException = new ArgumentException("File '" + fullPath + "' already exists."); - throwingException.Data.Add("fullPath", fullPath); - throw throwingException; - } - - Log.DebugFormat("Saving surface to {0}", fullPath); - // Create the stream and call SaveToStream - using (FileStream stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write)) - { - SaveToStream(surface, stream, outputSettings); - } - - if (copyPathToClipboard) - { - ClipboardHelper.SetClipboardData(fullPath); - } - } - - /// - /// Get the OutputFormat for a filename - /// - /// filename (can be a complete path) - /// OutputFormat - public static OutputFormat FormatForFilename(string fullPath) - { - // Fix for bug 2912959 - string extension = fullPath.Substring(fullPath.LastIndexOf(".", StringComparison.Ordinal) + 1); - OutputFormat format = OutputFormat.png; - try - { - format = (OutputFormat) Enum.Parse(typeof(OutputFormat), extension.ToLower()); - } - catch (ArgumentException ae) - { - Log.Warn("Couldn't parse extension: " + extension, ae); - } - - return format; - } - - /// - /// Save with showing a dialog - /// - /// - /// - /// Path to filename - public static string SaveWithDialog(ISurface surface, ICaptureDetails captureDetails) - { - string returnValue = null; - using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails)) - { - DialogResult dialogResult = saveImageFileDialog.ShowDialog(); - if (dialogResult.Equals(DialogResult.OK)) - { - try - { - string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension)); - if (CoreConfig.OutputFilePromptQuality) - { - QualityDialog qualityDialog = new QualityDialog(outputSettings); - qualityDialog.ShowDialog(); - } - - // TODO: For now we always overwrite, should be changed - Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); - returnValue = fileNameWithExtension; - IniConfig.Save(); - } - catch (ExternalException) - { - MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error")); - } - } - } - - return returnValue; - } - - /// - /// Create a tmpfile which has the name like in the configured pattern. - /// Used e.g. by the email export - /// - /// - /// - /// - /// Path to image file - public static string SaveNamedTmpFile(ISurface surface, ICaptureDetails captureDetails, SurfaceOutputSettings outputSettings) - { - string pattern = CoreConfig.OutputFileFilenamePattern; - if (string.IsNullOrEmpty(pattern?.Trim())) - { - pattern = "greenshot ${capturetime}"; - } - - string filename = FilenameHelper.GetFilenameFromPattern(pattern, outputSettings.Format, captureDetails); - // Prevent problems with "other characters", which causes a problem in e.g. Outlook 2007 or break our HTML - filename = Regex.Replace(filename, @"[^\d\w\.]", "_"); - // Remove multiple "_" - filename = Regex.Replace(filename, @"_+", "_"); - string tmpFile = Path.Combine(Path.GetTempPath(), filename); - - Log.Debug("Creating TMP File: " + tmpFile); - - // Catching any exception to prevent that the user can't write in the directory. - // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218 - try - { - Save(surface, tmpFile, true, outputSettings, false); - TmpFileCache.Add(tmpFile, tmpFile); - } - catch (Exception e) - { - // Show the problem - MessageBox.Show(e.Message, "Error"); - // when save failed we present a SaveWithDialog - tmpFile = SaveWithDialog(surface, captureDetails); - } - - return tmpFile; - } - - /// - /// Remove a tmpfile which was created by SaveNamedTmpFile - /// Used e.g. by the email export - /// - /// - /// true if it worked - public static bool DeleteNamedTmpFile(string tmpfile) - { - Log.Debug("Deleting TMP File: " + tmpfile); - try - { - if (File.Exists(tmpfile)) - { - File.Delete(tmpfile); - TmpFileCache.Remove(tmpfile); - } - - return true; - } - catch (Exception ex) - { - Log.Warn("Error deleting tmp file: ", ex); - } - - return false; - } - - /// - /// Helper method to create a temp image file - /// - /// - /// - /// - /// - public static string SaveToTmpFile(ISurface surface, SurfaceOutputSettings outputSettings, string destinationPath) - { - string tmpFile = Path.GetRandomFileName() + "." + outputSettings.Format; - // Prevent problems with "other characters", which could cause problems - tmpFile = Regex.Replace(tmpFile, @"[^\d\w\.]", string.Empty); - if (destinationPath == null) - { - destinationPath = Path.GetTempPath(); - } - - string tmpPath = Path.Combine(destinationPath, tmpFile); - Log.Debug("Creating TMP File : " + tmpPath); - - try - { - Save(surface, tmpPath, true, outputSettings, false); - TmpFileCache.Add(tmpPath, tmpPath); - } - catch (Exception) - { - return null; - } - - return tmpPath; - } - - /// - /// Cleanup all created tmpfiles - /// - public static void RemoveTmpFiles() - { - foreach (string tmpFile in TmpFileCache.Elements) - { - if (File.Exists(tmpFile)) - { - Log.DebugFormat("Removing old temp file {0}", tmpFile); - File.Delete(tmpFile); - } - - TmpFileCache.Remove(tmpFile); - } - } - - /// - /// Cleanup handler for expired tempfiles - /// - /// - /// - private static void RemoveExpiredTmpFile(string filekey, object filename) - { - if (filename is string path && File.Exists(path)) - { - Log.DebugFormat("Removing expired file {0}", path); - File.Delete(path); - } - } - - /// - /// Write the images to the stream as icon - /// Every image is resized to 256x256 (but the content maintains the aspect ratio) - /// - /// Stream to write to - /// List of images - public static void WriteIcon(Stream stream, IList images) - { - var binaryWriter = new BinaryWriter(stream); - // - // ICONDIR structure - // - binaryWriter.Write((short) 0); // reserved - binaryWriter.Write((short) 1); // image type (icon) - binaryWriter.Write((short) images.Count); // number of images - - IList imageSizes = new List(); - IList encodedImages = new List(); - foreach (var image in images) - { - // Pick the best fit - var sizes = new[] - { - 16, 32, 48 - }; - int size = 256; - foreach (var possibleSize in sizes) - { - if (image.Width <= possibleSize && image.Height <= possibleSize) - { - size = possibleSize; - break; - } - } - - var imageStream = new MemoryStream(); - if (image.Width == size && image.Height == size) - { - using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); - clonedImage.Save(imageStream, ImageFormat.Png); - imageSizes.Add(new Size(size, size)); - } - else - { - // Resize to the specified size, first make sure the image is 32bpp - using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); - using var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null); - resizedImage.Save(imageStream, ImageFormat.Png); - imageSizes.Add(resizedImage.Size); - } - - imageStream.Seek(0, SeekOrigin.Begin); - encodedImages.Add(imageStream); - } - - // - // ICONDIRENTRY structure - // - const int iconDirSize = 6; - const int iconDirEntrySize = 16; - - var offset = iconDirSize + (images.Count * iconDirEntrySize); - for (int i = 0; i < images.Count; i++) - { - var imageSize = imageSizes[i]; - // Write the width / height, 0 means 256 - binaryWriter.Write(imageSize.Width == 256 ? (byte) 0 : (byte) imageSize.Width); - binaryWriter.Write(imageSize.Height == 256 ? (byte) 0 : (byte) imageSize.Height); - binaryWriter.Write((byte) 0); // no pallete - binaryWriter.Write((byte) 0); // reserved - binaryWriter.Write((short) 0); // no color planes - binaryWriter.Write((short) 32); // 32 bpp - binaryWriter.Write((int) encodedImages[i].Length); // image data length - binaryWriter.Write(offset); - offset += (int) encodedImages[i].Length; - } - - binaryWriter.Flush(); - // - // Write image data - // - foreach (var encodedImage in encodedImages) - { - encodedImage.WriteTo(stream); - encodedImage.Dispose(); - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using log4net; +using Encoder = System.Drawing.Imaging.Encoder; + +namespace Greenshot.Base.Core +{ + /// + /// Description of ImageOutput. + /// + public static class ImageOutput + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ImageOutput)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131; + private static readonly Cache TmpFileCache = new Cache(10 * 60 * 60, RemoveExpiredTmpFile); + + /// + /// Creates a PropertyItem (Metadata) to store with the image. + /// For the possible ID's see: http://msdn.microsoft.com/de-de/library/system.drawing.imaging.propertyitem.id(v=vs.80).aspx + /// This code uses Reflection to create a PropertyItem, although it's not adviced it's not as stupid as having a image in the project so we can read a PropertyItem from that! + /// + /// ID + /// Text + /// + private static PropertyItem CreatePropertyItem(int id, string text) + { + PropertyItem propertyItem = null; + try + { + ConstructorInfo ci = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] + { + }, null); + propertyItem = (PropertyItem) ci.Invoke(null); + // Make sure it's of type string + propertyItem.Type = 2; + // Set the ID + propertyItem.Id = id; + // Set the text + byte[] byteString = Encoding.ASCII.GetBytes(text + " "); + // Set Zero byte for String end. + byteString[byteString.Length - 1] = 0; + propertyItem.Value = byteString; + propertyItem.Len = text.Length + 1; + } + catch (Exception e) + { + Log.WarnFormat("Error creating a PropertyItem: {0}", e.Message); + } + + return propertyItem; + } + + /// + /// Saves ISurface to stream with specified output settings + /// + /// ISurface to save + /// Stream to save to + /// SurfaceOutputSettings + public static void SaveToStream(ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) + { + bool disposeImage = CreateImageFromSurface(surface, outputSettings, out var imageToSave); + SaveToStream(imageToSave, surface, stream, outputSettings); + // cleanup if needed + if (disposeImage) + { + imageToSave?.Dispose(); + } + } + + /// + /// Saves image to stream with specified quality + /// To prevent problems with GDI version of before Windows 7: + /// the stream is checked if it's seekable and if needed a MemoryStream as "cache" is used. + /// + /// image to save + /// surface for the elements, needed if the greenshot format is used + /// Stream to save to + /// SurfaceOutputSettings + public static void SaveToStream(Image imageToSave, ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) + { + bool useMemoryStream = false; + MemoryStream memoryStream = null; + if (outputSettings.Format == OutputFormat.greenshot && surface == null) + { + throw new ArgumentException("Surface needs to be set when using OutputFormat.Greenshot"); + } + + try + { + var imageFormat = outputSettings.Format switch + { + OutputFormat.bmp => ImageFormat.Bmp, + OutputFormat.gif => ImageFormat.Gif, + OutputFormat.jpg => ImageFormat.Jpeg, + OutputFormat.tiff => ImageFormat.Tiff, + OutputFormat.ico => ImageFormat.Icon, + _ => ImageFormat.Png + }; + Log.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat); + + // Check if we want to use a memory stream, to prevent issues with non seakable streams + // The save is made to the targetStream, this is directed to either the MemoryStream or the original + Stream targetStream = stream; + if (!stream.CanSeek) + { + useMemoryStream = true; + Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream."); + memoryStream = new MemoryStream(); + targetStream = memoryStream; + } + + if (Equals(imageFormat, ImageFormat.Jpeg)) + { + bool foundEncoder = false; + foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders()) + { + if (imageCodec.FormatID == imageFormat.Guid) + { + EncoderParameters parameters = new EncoderParameters(1) + { + Param = + { + [0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality) + } + }; + // Removing transparency if it's not supported in the output + if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) + { + Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); + AddTag(nonAlphaImage); + nonAlphaImage.Save(targetStream, imageCodec, parameters); + nonAlphaImage.Dispose(); + } + else + { + AddTag(imageToSave); + imageToSave.Save(targetStream, imageCodec, parameters); + } + + foundEncoder = true; + break; + } + } + + if (!foundEncoder) + { + throw new ApplicationException("No JPG encoder found, this should not happen."); + } + } + else if (Equals(imageFormat, ImageFormat.Icon)) + { + // FEATURE-916: Added Icon support + IList images = new List + { + imageToSave + }; + WriteIcon(stream, images); + } + else + { + bool needsDispose = false; + // Removing transparency if it's not supported in the output + if (!Equals(imageFormat, ImageFormat.Png) && Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) + { + imageToSave = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); + needsDispose = true; + } + + AddTag(imageToSave); + // Added for OptiPNG + bool processed = false; + if (Equals(imageFormat, ImageFormat.Png) && !string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) + { + processed = ProcessPngImageExternally(imageToSave, targetStream); + } + + if (!processed) + { + imageToSave.Save(targetStream, imageFormat); + } + + if (needsDispose) + { + imageToSave.Dispose(); + } + } + + // If we used a memory stream, we need to stream the memory stream to the original stream. + if (useMemoryStream) + { + memoryStream.WriteTo(stream); + } + + // Output the surface elements, size and marker to the stream + if (outputSettings.Format != OutputFormat.greenshot) + { + return; + } + + using MemoryStream tmpStream = new MemoryStream(); + long bytesWritten = surface.SaveElementsToStream(tmpStream); + using BinaryWriter writer = new BinaryWriter(tmpStream); + writer.Write(bytesWritten); + Version v = Assembly.GetExecutingAssembly().GetName().Version; + byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); + writer.Write(marker); + tmpStream.WriteTo(stream); + } + finally + { + memoryStream?.Dispose(); + } + } + + /// + /// Write the passed Image to a tmp-file and call an external process, than read the file back and write it to the targetStream + /// + /// Image to pass to the external process + /// stream to write the processed image to + /// + private static bool ProcessPngImageExternally(Image imageToProcess, Stream targetStream) + { + if (string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) + { + return false; + } + + if (!File.Exists(CoreConfig.OptimizePNGCommand)) + { + Log.WarnFormat("Can't find 'OptimizePNGCommand' {0}", CoreConfig.OptimizePNGCommand); + return false; + } + + string tmpFileName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".png"); + try + { + using (FileStream tmpStream = File.Create(tmpFileName)) + { + Log.DebugFormat("Writing png to tmp file: {0}", tmpFileName); + imageToProcess.Save(tmpStream, ImageFormat.Png); + if (Log.IsDebugEnabled) + { + Log.DebugFormat("File size before processing {0}", new FileInfo(tmpFileName).Length); + } + } + + if (Log.IsDebugEnabled) + { + Log.DebugFormat("Starting : {0}", CoreConfig.OptimizePNGCommand); + } + + ProcessStartInfo processStartInfo = new ProcessStartInfo(CoreConfig.OptimizePNGCommand) + { + Arguments = string.Format(CoreConfig.OptimizePNGCommandArguments, tmpFileName), + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false + }; + using Process process = Process.Start(processStartInfo); + if (process != null) + { + process.WaitForExit(); + if (process.ExitCode == 0) + { + if (Log.IsDebugEnabled) + { + Log.DebugFormat("File size after processing {0}", new FileInfo(tmpFileName).Length); + Log.DebugFormat("Reading back tmp file: {0}", tmpFileName); + } + + byte[] processedImage = File.ReadAllBytes(tmpFileName); + targetStream.Write(processedImage, 0, processedImage.Length); + return true; + } + + Log.ErrorFormat("Error while processing PNG image: {0}", process.ExitCode); + Log.ErrorFormat("Output: {0}", process.StandardOutput.ReadToEnd()); + Log.ErrorFormat("Error: {0}", process.StandardError.ReadToEnd()); + } + } + catch (Exception e) + { + Log.Error("Error while processing PNG image: ", e); + } + finally + { + if (File.Exists(tmpFileName)) + { + Log.DebugFormat("Cleaning up tmp file: {0}", tmpFileName); + File.Delete(tmpFileName); + } + } + + return false; + } + + /// + /// Create an image from a surface with the settings from the output settings applied + /// + /// + /// + /// + /// true if the image must be disposed + public static bool CreateImageFromSurface(ISurface surface, SurfaceOutputSettings outputSettings, out Image imageToSave) + { + bool disposeImage = false; + + if (outputSettings.Format == OutputFormat.greenshot || outputSettings.SaveBackgroundOnly) + { + // We save the image of the surface, this should not be disposed + imageToSave = surface.Image; + } + else + { + // We create the export image of the surface to save + imageToSave = surface.GetImageForExport(); + disposeImage = true; + } + + // The following block of modifications should be skipped when saving the greenshot format, no effects or otherwise! + if (outputSettings.Format == OutputFormat.greenshot) + { + return disposeImage; + } + + Image tmpImage; + if (outputSettings.Effects != null && outputSettings.Effects.Count > 0) + { + // apply effects, if there are any + using (Matrix matrix = new Matrix()) + { + tmpImage = ImageHelper.ApplyEffects(imageToSave, outputSettings.Effects, matrix); + } + + if (tmpImage != null) + { + if (disposeImage) + { + imageToSave.Dispose(); + } + + imageToSave = tmpImage; + disposeImage = true; + } + } + + // check for color reduction, forced or automatically, only when the DisableReduceColors is false + if (outputSettings.DisableReduceColors || (!CoreConfig.OutputFileAutoReduceColors && !outputSettings.ReduceColors)) + { + return disposeImage; + } + + bool isAlpha = Image.IsAlphaPixelFormat(imageToSave.PixelFormat); + if (outputSettings.ReduceColors || (!isAlpha && CoreConfig.OutputFileAutoReduceColors)) + { + using var quantizer = new WuQuantizer((Bitmap) imageToSave); + int colorCount = quantizer.GetColorCount(); + Log.InfoFormat("Image with format {0} has {1} colors", imageToSave.PixelFormat, colorCount); + if (!outputSettings.ReduceColors && colorCount >= 256) + { + return disposeImage; + } + + try + { + Log.Info("Reducing colors on bitmap to 256."); + tmpImage = quantizer.GetQuantizedImage(CoreConfig.OutputFileReduceColorsTo); + if (disposeImage) + { + imageToSave.Dispose(); + } + + imageToSave = tmpImage; + // Make sure the "new" image is disposed + disposeImage = true; + } + catch (Exception e) + { + Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); + } + } + else if (isAlpha && !outputSettings.ReduceColors) + { + Log.Info("Skipping 'optional' color reduction as the image has alpha"); + } + + return disposeImage; + } + + /// + /// Add the greenshot property! + /// + /// + private static void AddTag(Image imageToSave) + { + // Create meta-data + PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot"); + if (softwareUsedPropertyItem != null) + { + try + { + imageToSave.SetPropertyItem(softwareUsedPropertyItem); + } + catch (Exception) + { + Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id); + } + } + } + + /// + /// Load a Greenshot surface + /// + /// + /// + /// + public static ISurface LoadGreenshotSurface(string fullPath, ISurface returnSurface) + { + if (string.IsNullOrEmpty(fullPath)) + { + return null; + } + + Log.InfoFormat("Loading image from file {0}", fullPath); + // Fixed lock problem Bug #3431881 + using (Stream surfaceFileStream = File.OpenRead(fullPath)) + { + returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface); + } + + if (returnSurface != null) + { + Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", fullPath, returnSurface.Image.Width, returnSurface.Image.Height, + returnSurface.Image.PixelFormat, returnSurface.Image.HorizontalResolution, returnSurface.Image.VerticalResolution); + } + + return returnSurface; + } + + /// + /// Saves image to specific path with specified quality + /// + public static void Save(ISurface surface, string fullPath, bool allowOverwrite, SurfaceOutputSettings outputSettings, bool copyPathToClipboard) + { + fullPath = FilenameHelper.MakeFqFilenameSafe(fullPath); + string path = Path.GetDirectoryName(fullPath); + + // check whether path exists - if not create it + if (path != null) + { + DirectoryInfo di = new DirectoryInfo(path); + if (!di.Exists) + { + Directory.CreateDirectory(di.FullName); + } + } + + if (!allowOverwrite && File.Exists(fullPath)) + { + ArgumentException throwingException = new ArgumentException("File '" + fullPath + "' already exists."); + throwingException.Data.Add("fullPath", fullPath); + throw throwingException; + } + + Log.DebugFormat("Saving surface to {0}", fullPath); + // Create the stream and call SaveToStream + using (FileStream stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write)) + { + SaveToStream(surface, stream, outputSettings); + } + + if (copyPathToClipboard) + { + ClipboardHelper.SetClipboardData(fullPath); + } + } + + /// + /// Get the OutputFormat for a filename + /// + /// filename (can be a complete path) + /// OutputFormat + public static OutputFormat FormatForFilename(string fullPath) + { + // Fix for bug 2912959 + string extension = fullPath.Substring(fullPath.LastIndexOf(".", StringComparison.Ordinal) + 1); + OutputFormat format = OutputFormat.png; + try + { + format = (OutputFormat) Enum.Parse(typeof(OutputFormat), extension.ToLower()); + } + catch (ArgumentException ae) + { + Log.Warn("Couldn't parse extension: " + extension, ae); + } + + return format; + } + + /// + /// Save with showing a dialog + /// + /// + /// + /// Path to filename + public static string SaveWithDialog(ISurface surface, ICaptureDetails captureDetails) + { + string returnValue = null; + using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails)) + { + DialogResult dialogResult = saveImageFileDialog.ShowDialog(); + if (dialogResult.Equals(DialogResult.OK)) + { + try + { + string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension)); + if (CoreConfig.OutputFilePromptQuality) + { + QualityDialog qualityDialog = new QualityDialog(outputSettings); + qualityDialog.ShowDialog(); + } + + // TODO: For now we always overwrite, should be changed + Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); + returnValue = fileNameWithExtension; + IniConfig.Save(); + } + catch (ExternalException) + { + MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error")); + } + } + } + + return returnValue; + } + + /// + /// Create a tmpfile which has the name like in the configured pattern. + /// Used e.g. by the email export + /// + /// + /// + /// + /// Path to image file + public static string SaveNamedTmpFile(ISurface surface, ICaptureDetails captureDetails, SurfaceOutputSettings outputSettings) + { + string pattern = CoreConfig.OutputFileFilenamePattern; + if (string.IsNullOrEmpty(pattern?.Trim())) + { + pattern = "greenshot ${capturetime}"; + } + + string filename = FilenameHelper.GetFilenameFromPattern(pattern, outputSettings.Format, captureDetails); + // Prevent problems with "other characters", which causes a problem in e.g. Outlook 2007 or break our HTML + filename = Regex.Replace(filename, @"[^\d\w\.]", "_"); + // Remove multiple "_" + filename = Regex.Replace(filename, @"_+", "_"); + string tmpFile = Path.Combine(Path.GetTempPath(), filename); + + Log.Debug("Creating TMP File: " + tmpFile); + + // Catching any exception to prevent that the user can't write in the directory. + // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218 + try + { + Save(surface, tmpFile, true, outputSettings, false); + TmpFileCache.Add(tmpFile, tmpFile); + } + catch (Exception e) + { + // Show the problem + MessageBox.Show(e.Message, "Error"); + // when save failed we present a SaveWithDialog + tmpFile = SaveWithDialog(surface, captureDetails); + } + + return tmpFile; + } + + /// + /// Remove a tmpfile which was created by SaveNamedTmpFile + /// Used e.g. by the email export + /// + /// + /// true if it worked + public static bool DeleteNamedTmpFile(string tmpfile) + { + Log.Debug("Deleting TMP File: " + tmpfile); + try + { + if (File.Exists(tmpfile)) + { + File.Delete(tmpfile); + TmpFileCache.Remove(tmpfile); + } + + return true; + } + catch (Exception ex) + { + Log.Warn("Error deleting tmp file: ", ex); + } + + return false; + } + + /// + /// Helper method to create a temp image file + /// + /// + /// + /// + /// + public static string SaveToTmpFile(ISurface surface, SurfaceOutputSettings outputSettings, string destinationPath) + { + string tmpFile = Path.GetRandomFileName() + "." + outputSettings.Format; + // Prevent problems with "other characters", which could cause problems + tmpFile = Regex.Replace(tmpFile, @"[^\d\w\.]", string.Empty); + if (destinationPath == null) + { + destinationPath = Path.GetTempPath(); + } + + string tmpPath = Path.Combine(destinationPath, tmpFile); + Log.Debug("Creating TMP File : " + tmpPath); + + try + { + Save(surface, tmpPath, true, outputSettings, false); + TmpFileCache.Add(tmpPath, tmpPath); + } + catch (Exception) + { + return null; + } + + return tmpPath; + } + + /// + /// Cleanup all created tmpfiles + /// + public static void RemoveTmpFiles() + { + foreach (string tmpFile in TmpFileCache.Elements) + { + if (File.Exists(tmpFile)) + { + Log.DebugFormat("Removing old temp file {0}", tmpFile); + File.Delete(tmpFile); + } + + TmpFileCache.Remove(tmpFile); + } + } + + /// + /// Cleanup handler for expired tempfiles + /// + /// + /// + private static void RemoveExpiredTmpFile(string filekey, object filename) + { + if (filename is string path && File.Exists(path)) + { + Log.DebugFormat("Removing expired file {0}", path); + File.Delete(path); + } + } + + /// + /// Write the images to the stream as icon + /// Every image is resized to 256x256 (but the content maintains the aspect ratio) + /// + /// Stream to write to + /// List of images + public static void WriteIcon(Stream stream, IList images) + { + var binaryWriter = new BinaryWriter(stream); + // + // ICONDIR structure + // + binaryWriter.Write((short) 0); // reserved + binaryWriter.Write((short) 1); // image type (icon) + binaryWriter.Write((short) images.Count); // number of images + + IList imageSizes = new List(); + IList encodedImages = new List(); + foreach (var image in images) + { + // Pick the best fit + var sizes = new[] + { + 16, 32, 48 + }; + int size = 256; + foreach (var possibleSize in sizes) + { + if (image.Width <= possibleSize && image.Height <= possibleSize) + { + size = possibleSize; + break; + } + } + + var imageStream = new MemoryStream(); + if (image.Width == size && image.Height == size) + { + using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); + clonedImage.Save(imageStream, ImageFormat.Png); + imageSizes.Add(new Size(size, size)); + } + else + { + // Resize to the specified size, first make sure the image is 32bpp + using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); + using var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null); + resizedImage.Save(imageStream, ImageFormat.Png); + imageSizes.Add(resizedImage.Size); + } + + imageStream.Seek(0, SeekOrigin.Begin); + encodedImages.Add(imageStream); + } + + // + // ICONDIRENTRY structure + // + const int iconDirSize = 6; + const int iconDirEntrySize = 16; + + var offset = iconDirSize + (images.Count * iconDirEntrySize); + for (int i = 0; i < images.Count; i++) + { + var imageSize = imageSizes[i]; + // Write the width / height, 0 means 256 + binaryWriter.Write(imageSize.Width == 256 ? (byte) 0 : (byte) imageSize.Width); + binaryWriter.Write(imageSize.Height == 256 ? (byte) 0 : (byte) imageSize.Height); + binaryWriter.Write((byte) 0); // no pallete + binaryWriter.Write((byte) 0); // reserved + binaryWriter.Write((short) 0); // no color planes + binaryWriter.Write((short) 32); // 32 bpp + binaryWriter.Write((int) encodedImages[i].Length); // image data length + binaryWriter.Write(offset); + offset += (int) encodedImages[i].Length; + } + + binaryWriter.Flush(); + // + // Write image data + // + foreach (var encodedImage in encodedImages) + { + encodedImage.WriteTo(stream); + encodedImage.Dispose(); + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/ImageWrapper.cs b/src/Greenshot.Base/Core/ImageWrapper.cs similarity index 95% rename from src/GreenshotPlugin/Core/ImageWrapper.cs rename to src/Greenshot.Base/Core/ImageWrapper.cs index 720d2ce50..517249534 100644 --- a/src/GreenshotPlugin/Core/ImageWrapper.cs +++ b/src/Greenshot.Base/Core/ImageWrapper.cs @@ -1,77 +1,77 @@ -using System.Drawing; -using System.Drawing.Imaging; - -namespace GreenshotPlugin.Core -{ - /// - /// Wrap an image, make it resizeable - /// - public class ImageWrapper : IImage - { - // Underlying image, is used to generate a resized version of it when needed - private readonly Image _image; - private Image _imageClone; - - public ImageWrapper(Image image) - { - // Make sure the orientation is set correctly so Greenshot can process the image correctly - ImageHelper.Orientate(image); - _image = image; - Width = _image.Width; - Height = _image.Height; - } - - public void Dispose() - { - _image.Dispose(); - _imageClone?.Dispose(); - } - - /// - /// Height of the image, can be set to change - /// - public int Height { get; set; } - - /// - /// Width of the image, can be set to change. - /// - public int Width { get; set; } - - /// - /// Size of the image - /// - public Size Size => new Size(Width, Height); - - /// - /// Pixelformat of the underlying image - /// - public PixelFormat PixelFormat => Image.PixelFormat; - - public float HorizontalResolution => Image.HorizontalResolution; - public float VerticalResolution => Image.VerticalResolution; - - public Image Image - { - get - { - if (_imageClone == null) - { - if (_image.Height == Height && _image.Width == Width) - { - return _image; - } - } - - if (_imageClone?.Height == Height && _imageClone?.Width == Width) - { - return _imageClone; - } - - // Calculate new image clone - _imageClone?.Dispose(); - _imageClone = ImageHelper.ResizeImage(_image, false, Width, Height, null); - return _imageClone; - } - } - } +using System.Drawing; +using System.Drawing.Imaging; + +namespace Greenshot.Base.Core +{ + /// + /// Wrap an image, make it resizeable + /// + public class ImageWrapper : IImage + { + // Underlying image, is used to generate a resized version of it when needed + private readonly Image _image; + private Image _imageClone; + + public ImageWrapper(Image image) + { + // Make sure the orientation is set correctly so Greenshot can process the image correctly + ImageHelper.Orientate(image); + _image = image; + Width = _image.Width; + Height = _image.Height; + } + + public void Dispose() + { + _image.Dispose(); + _imageClone?.Dispose(); + } + + /// + /// Height of the image, can be set to change + /// + public int Height { get; set; } + + /// + /// Width of the image, can be set to change. + /// + public int Width { get; set; } + + /// + /// Size of the image + /// + public Size Size => new Size(Width, Height); + + /// + /// Pixelformat of the underlying image + /// + public PixelFormat PixelFormat => Image.PixelFormat; + + public float HorizontalResolution => Image.HorizontalResolution; + public float VerticalResolution => Image.VerticalResolution; + + public Image Image + { + get + { + if (_imageClone == null) + { + if (_image.Height == Height && _image.Width == Width) + { + return _image; + } + } + + if (_imageClone?.Height == Height && _imageClone?.Width == Width) + { + return _imageClone; + } + + // Calculate new image clone + _imageClone?.Dispose(); + _imageClone = ImageHelper.ResizeImage(_image, false, Width, Height, null); + return _imageClone; + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/InterfaceUtils.cs b/src/Greenshot.Base/Core/InterfaceUtils.cs similarity index 96% rename from src/GreenshotPlugin/Core/InterfaceUtils.cs rename to src/Greenshot.Base/Core/InterfaceUtils.cs index c71c7b6ad..c93f24b56 100644 --- a/src/GreenshotPlugin/Core/InterfaceUtils.cs +++ b/src/Greenshot.Base/Core/InterfaceUtils.cs @@ -1,73 +1,73 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Threading; -using log4net; - -namespace GreenshotPlugin.Core -{ - /// - /// Description of InterfaceUtils. - /// - public static class InterfaceUtils - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(InterfaceUtils)); - - public static List GetSubclassesOf(Type type, bool excludeSystemTypes) - { - var list = new List(); - foreach (var currentAssembly in Thread.GetDomain().GetAssemblies()) - { - try - { - Type[] types = currentAssembly.GetTypes(); - if (excludeSystemTypes && (!excludeSystemTypes || currentAssembly.FullName.StartsWith("System."))) - { - continue; - } - - foreach (var currentType in types) - { - if (type.IsInterface) - { - if (currentType.GetInterface(type.FullName) != null) - { - list.Add(currentType); - } - } - else if (currentType.IsSubclassOf(type)) - { - list.Add(currentType); - } - } - } - catch (Exception ex) - { - LOG.WarnFormat("Problem getting subclasses of type: {0}, message: {1}", type.FullName, ex.Message); - } - } - - return list; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// Description of InterfaceUtils. + /// + public static class InterfaceUtils + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(InterfaceUtils)); + + public static List GetSubclassesOf(Type type, bool excludeSystemTypes) + { + var list = new List(); + foreach (var currentAssembly in Thread.GetDomain().GetAssemblies()) + { + try + { + Type[] types = currentAssembly.GetTypes(); + if (excludeSystemTypes && (!excludeSystemTypes || currentAssembly.FullName.StartsWith("System."))) + { + continue; + } + + foreach (var currentType in types) + { + if (type.IsInterface) + { + if (currentType.GetInterface(type.FullName) != null) + { + list.Add(currentType); + } + } + else if (currentType.IsSubclassOf(type)) + { + list.Add(currentType); + } + } + } + catch (Exception ex) + { + LOG.WarnFormat("Problem getting subclasses of type: {0}, message: {1}", type.FullName, ex.Message); + } + } + + return list; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/JSONHelper.cs b/src/Greenshot.Base/Core/JSONHelper.cs similarity index 96% rename from src/GreenshotPlugin/Core/JSONHelper.cs rename to src/Greenshot.Base/Core/JSONHelper.cs index 28a76a71d..37da4972b 100644 --- a/src/GreenshotPlugin/Core/JSONHelper.cs +++ b/src/Greenshot.Base/Core/JSONHelper.cs @@ -1,436 +1,436 @@ -/* -Copyright (C) 2008 Patrick van Bergen - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -using System.Collections.Generic; -using System.Globalization; -using System.Text; - -namespace GreenshotPlugin.Core -{ - /// - /// This parses a JSON response, a modified version of the code found at: - /// See: http://techblog.procurios.nl/k/n618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html - /// - /// This file is under the MIT License, which is GPL Compatible and according to: http://en.wikipedia.org/wiki/MIT_License - /// can be used under the GPL "umbrella". - /// - /// TODO: code should be replaced when upgrading to .NET 3.5 or higher!! - /// - public class JSONHelper - { - public const int TOKEN_NONE = 0; - public const int TOKEN_CURLY_OPEN = 1; - public const int TOKEN_CURLY_CLOSE = 2; - public const int TOKEN_SQUARED_OPEN = 3; - public const int TOKEN_SQUARED_CLOSE = 4; - public const int TOKEN_COLON = 5; - public const int TOKEN_COMMA = 6; - public const int TOKEN_STRING = 7; - public const int TOKEN_NUMBER = 8; - public const int TOKEN_TRUE = 9; - public const int TOKEN_FALSE = 10; - public const int TOKEN_NULL = 11; - - private const int BUILDER_CAPACITY = 2000; - - /// - /// Parses the string json into a value - /// - /// A JSON string. - /// An ArrayList, a Hashtable, a double, a string, null, true, or false - public static IDictionary JsonDecode(string json) - { - bool success = true; - - return JsonDecode(json, ref success); - } - - /// - /// Parses the string json into a value; and fills 'success' with the successfullness of the parse. - /// - /// A JSON string. - /// Successful parse? - /// An ArrayList, a Hashtable, a double, a string, null, true, or false - public static IDictionary JsonDecode(string json, ref bool success) - { - success = true; - if (json != null) - { - char[] charArray = json.ToCharArray(); - int index = 0; - IDictionary value = ParseValue(charArray, ref index, ref success) as IDictionary; - return value; - } - - return null; - } - - protected static IDictionary ParseObject(char[] json, ref int index, ref bool success) - { - IDictionary table = new Dictionary(); - int token; - - // { - NextToken(json, ref index); - - bool done = false; - while (!done) - { - token = LookAhead(json, index); - if (token == TOKEN_NONE) - { - success = false; - return null; - } - else if (token == TOKEN_COMMA) - { - NextToken(json, ref index); - } - else if (token == TOKEN_CURLY_CLOSE) - { - NextToken(json, ref index); - return table; - } - else - { - // name - string name = ParseString(json, ref index, ref success); - if (!success) - { - success = false; - return null; - } - - // : - token = NextToken(json, ref index); - if (token != TOKEN_COLON) - { - success = false; - return null; - } - - // value - object value = ParseValue(json, ref index, ref success); - if (!success) - { - success = false; - return null; - } - - table.Add(name, value); - } - } - - return table; - } - - protected static IList ParseArray(char[] json, ref int index, ref bool success) - { - IList array = new List(); - - // [ - NextToken(json, ref index); - - bool done = false; - while (!done) - { - int token = LookAhead(json, index); - if (token == TOKEN_NONE) - { - success = false; - return null; - } - else if (token == TOKEN_COMMA) - { - NextToken(json, ref index); - } - else if (token == TOKEN_SQUARED_CLOSE) - { - NextToken(json, ref index); - break; - } - else - { - object value = ParseValue(json, ref index, ref success); - if (!success) - { - return null; - } - - array.Add(value); - } - } - - return array; - } - - protected static object ParseValue(char[] json, ref int index, ref bool success) - { - switch (LookAhead(json, index)) - { - case TOKEN_STRING: - return ParseString(json, ref index, ref success); - case TOKEN_NUMBER: - return ParseNumber(json, ref index, ref success); - case TOKEN_CURLY_OPEN: - return ParseObject(json, ref index, ref success); - case TOKEN_SQUARED_OPEN: - return ParseArray(json, ref index, ref success); - case TOKEN_TRUE: - NextToken(json, ref index); - return true; - case TOKEN_FALSE: - NextToken(json, ref index); - return false; - case TOKEN_NULL: - NextToken(json, ref index); - return null; - case TOKEN_NONE: - break; - } - - success = false; - return null; - } - - protected static string ParseString(char[] json, ref int index, ref bool success) - { - StringBuilder s = new StringBuilder(BUILDER_CAPACITY); - - EatWhitespace(json, ref index); - - // " - var c = json[index++]; - - bool complete = false; - while (!complete) - { - if (index == json.Length) - { - break; - } - - c = json[index++]; - if (c == '"') - { - complete = true; - break; - } - else if (c == '\\') - { - if (index == json.Length) - { - break; - } - - c = json[index++]; - if (c == '"') - { - s.Append('"'); - } - else if (c == '\\') - { - s.Append('\\'); - } - else if (c == '/') - { - s.Append('/'); - } - else if (c == 'b') - { - s.Append('\b'); - } - else if (c == 'f') - { - s.Append('\f'); - } - else if (c == 'n') - { - s.Append('\n'); - } - else if (c == 'r') - { - s.Append('\r'); - } - else if (c == 't') - { - s.Append('\t'); - } - else if (c == 'u') - { - int remainingLength = json.Length - index; - if (remainingLength >= 4) - { - // parse the 32 bit hex into an integer codepoint - if (!(success = uint.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var codePoint))) - { - return string.Empty; - } - - // convert the integer codepoint to a unicode char and add to string - s.Append(char.ConvertFromUtf32((int) codePoint)); - // skip 4 chars - index += 4; - } - else - { - break; - } - } - } - else - { - s.Append(c); - } - } - - if (!complete) - { - success = false; - return null; - } - - return s.ToString(); - } - - protected static double ParseNumber(char[] json, ref int index, ref bool success) - { - EatWhitespace(json, ref index); - - int lastIndex = GetLastIndexOfNumber(json, index); - int charLength = (lastIndex - index) + 1; - - success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out var number); - - index = lastIndex + 1; - return number; - } - - protected static int GetLastIndexOfNumber(char[] json, int index) - { - int lastIndex; - - for (lastIndex = index; lastIndex < json.Length; lastIndex++) - { - if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) - { - break; - } - } - - return lastIndex - 1; - } - - protected static void EatWhitespace(char[] json, ref int index) - { - for (; index < json.Length; index++) - { - if (" \t\n\r".IndexOf(json[index]) == -1) - { - break; - } - } - } - - protected static int LookAhead(char[] json, int index) - { - int saveIndex = index; - return NextToken(json, ref saveIndex); - } - - protected static int NextToken(char[] json, ref int index) - { - EatWhitespace(json, ref index); - - if (index == json.Length) - { - return TOKEN_NONE; - } - - char c = json[index]; - index++; - switch (c) - { - case '{': - return TOKEN_CURLY_OPEN; - case '}': - return TOKEN_CURLY_CLOSE; - case '[': - return TOKEN_SQUARED_OPEN; - case ']': - return TOKEN_SQUARED_CLOSE; - case ',': - return TOKEN_COMMA; - case '"': - return TOKEN_STRING; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - return TOKEN_NUMBER; - case ':': - return TOKEN_COLON; - } - - index--; - - int remainingLength = json.Length - index; - - // false - if (remainingLength >= 5) - { - if (json[index] == 'f' && - json[index + 1] == 'a' && - json[index + 2] == 'l' && - json[index + 3] == 's' && - json[index + 4] == 'e') - { - index += 5; - return TOKEN_FALSE; - } - } - - // true - if (remainingLength >= 4) - { - if (json[index] == 't' && - json[index + 1] == 'r' && - json[index + 2] == 'u' && - json[index + 3] == 'e') - { - index += 4; - return TOKEN_TRUE; - } - } - - // null - if (remainingLength >= 4) - { - if (json[index] == 'n' && - json[index + 1] == 'u' && - json[index + 2] == 'l' && - json[index + 3] == 'l') - { - index += 4; - return TOKEN_NULL; - } - } - - return TOKEN_NONE; - } - } +/* +Copyright (C) 2008 Patrick van Bergen + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace Greenshot.Base.Core +{ + /// + /// This parses a JSON response, a modified version of the code found at: + /// See: http://techblog.procurios.nl/k/n618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html + /// + /// This file is under the MIT License, which is GPL Compatible and according to: http://en.wikipedia.org/wiki/MIT_License + /// can be used under the GPL "umbrella". + /// + /// TODO: code should be replaced when upgrading to .NET 3.5 or higher!! + /// + public class JSONHelper + { + public const int TOKEN_NONE = 0; + public const int TOKEN_CURLY_OPEN = 1; + public const int TOKEN_CURLY_CLOSE = 2; + public const int TOKEN_SQUARED_OPEN = 3; + public const int TOKEN_SQUARED_CLOSE = 4; + public const int TOKEN_COLON = 5; + public const int TOKEN_COMMA = 6; + public const int TOKEN_STRING = 7; + public const int TOKEN_NUMBER = 8; + public const int TOKEN_TRUE = 9; + public const int TOKEN_FALSE = 10; + public const int TOKEN_NULL = 11; + + private const int BUILDER_CAPACITY = 2000; + + /// + /// Parses the string json into a value + /// + /// A JSON string. + /// An ArrayList, a Hashtable, a double, a string, null, true, or false + public static IDictionary JsonDecode(string json) + { + bool success = true; + + return JsonDecode(json, ref success); + } + + /// + /// Parses the string json into a value; and fills 'success' with the successfullness of the parse. + /// + /// A JSON string. + /// Successful parse? + /// An ArrayList, a Hashtable, a double, a string, null, true, or false + public static IDictionary JsonDecode(string json, ref bool success) + { + success = true; + if (json != null) + { + char[] charArray = json.ToCharArray(); + int index = 0; + IDictionary value = ParseValue(charArray, ref index, ref success) as IDictionary; + return value; + } + + return null; + } + + protected static IDictionary ParseObject(char[] json, ref int index, ref bool success) + { + IDictionary table = new Dictionary(); + int token; + + // { + NextToken(json, ref index); + + bool done = false; + while (!done) + { + token = LookAhead(json, index); + if (token == TOKEN_NONE) + { + success = false; + return null; + } + else if (token == TOKEN_COMMA) + { + NextToken(json, ref index); + } + else if (token == TOKEN_CURLY_CLOSE) + { + NextToken(json, ref index); + return table; + } + else + { + // name + string name = ParseString(json, ref index, ref success); + if (!success) + { + success = false; + return null; + } + + // : + token = NextToken(json, ref index); + if (token != TOKEN_COLON) + { + success = false; + return null; + } + + // value + object value = ParseValue(json, ref index, ref success); + if (!success) + { + success = false; + return null; + } + + table.Add(name, value); + } + } + + return table; + } + + protected static IList ParseArray(char[] json, ref int index, ref bool success) + { + IList array = new List(); + + // [ + NextToken(json, ref index); + + bool done = false; + while (!done) + { + int token = LookAhead(json, index); + if (token == TOKEN_NONE) + { + success = false; + return null; + } + else if (token == TOKEN_COMMA) + { + NextToken(json, ref index); + } + else if (token == TOKEN_SQUARED_CLOSE) + { + NextToken(json, ref index); + break; + } + else + { + object value = ParseValue(json, ref index, ref success); + if (!success) + { + return null; + } + + array.Add(value); + } + } + + return array; + } + + protected static object ParseValue(char[] json, ref int index, ref bool success) + { + switch (LookAhead(json, index)) + { + case TOKEN_STRING: + return ParseString(json, ref index, ref success); + case TOKEN_NUMBER: + return ParseNumber(json, ref index, ref success); + case TOKEN_CURLY_OPEN: + return ParseObject(json, ref index, ref success); + case TOKEN_SQUARED_OPEN: + return ParseArray(json, ref index, ref success); + case TOKEN_TRUE: + NextToken(json, ref index); + return true; + case TOKEN_FALSE: + NextToken(json, ref index); + return false; + case TOKEN_NULL: + NextToken(json, ref index); + return null; + case TOKEN_NONE: + break; + } + + success = false; + return null; + } + + protected static string ParseString(char[] json, ref int index, ref bool success) + { + StringBuilder s = new StringBuilder(BUILDER_CAPACITY); + + EatWhitespace(json, ref index); + + // " + var c = json[index++]; + + bool complete = false; + while (!complete) + { + if (index == json.Length) + { + break; + } + + c = json[index++]; + if (c == '"') + { + complete = true; + break; + } + else if (c == '\\') + { + if (index == json.Length) + { + break; + } + + c = json[index++]; + if (c == '"') + { + s.Append('"'); + } + else if (c == '\\') + { + s.Append('\\'); + } + else if (c == '/') + { + s.Append('/'); + } + else if (c == 'b') + { + s.Append('\b'); + } + else if (c == 'f') + { + s.Append('\f'); + } + else if (c == 'n') + { + s.Append('\n'); + } + else if (c == 'r') + { + s.Append('\r'); + } + else if (c == 't') + { + s.Append('\t'); + } + else if (c == 'u') + { + int remainingLength = json.Length - index; + if (remainingLength >= 4) + { + // parse the 32 bit hex into an integer codepoint + if (!(success = uint.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var codePoint))) + { + return string.Empty; + } + + // convert the integer codepoint to a unicode char and add to string + s.Append(char.ConvertFromUtf32((int) codePoint)); + // skip 4 chars + index += 4; + } + else + { + break; + } + } + } + else + { + s.Append(c); + } + } + + if (!complete) + { + success = false; + return null; + } + + return s.ToString(); + } + + protected static double ParseNumber(char[] json, ref int index, ref bool success) + { + EatWhitespace(json, ref index); + + int lastIndex = GetLastIndexOfNumber(json, index); + int charLength = (lastIndex - index) + 1; + + success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out var number); + + index = lastIndex + 1; + return number; + } + + protected static int GetLastIndexOfNumber(char[] json, int index) + { + int lastIndex; + + for (lastIndex = index; lastIndex < json.Length; lastIndex++) + { + if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) + { + break; + } + } + + return lastIndex - 1; + } + + protected static void EatWhitespace(char[] json, ref int index) + { + for (; index < json.Length; index++) + { + if (" \t\n\r".IndexOf(json[index]) == -1) + { + break; + } + } + } + + protected static int LookAhead(char[] json, int index) + { + int saveIndex = index; + return NextToken(json, ref saveIndex); + } + + protected static int NextToken(char[] json, ref int index) + { + EatWhitespace(json, ref index); + + if (index == json.Length) + { + return TOKEN_NONE; + } + + char c = json[index]; + index++; + switch (c) + { + case '{': + return TOKEN_CURLY_OPEN; + case '}': + return TOKEN_CURLY_CLOSE; + case '[': + return TOKEN_SQUARED_OPEN; + case ']': + return TOKEN_SQUARED_CLOSE; + case ',': + return TOKEN_COMMA; + case '"': + return TOKEN_STRING; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return TOKEN_NUMBER; + case ':': + return TOKEN_COLON; + } + + index--; + + int remainingLength = json.Length - index; + + // false + if (remainingLength >= 5) + { + if (json[index] == 'f' && + json[index + 1] == 'a' && + json[index + 2] == 'l' && + json[index + 3] == 's' && + json[index + 4] == 'e') + { + index += 5; + return TOKEN_FALSE; + } + } + + // true + if (remainingLength >= 4) + { + if (json[index] == 't' && + json[index + 1] == 'r' && + json[index + 2] == 'u' && + json[index + 3] == 'e') + { + index += 4; + return TOKEN_TRUE; + } + } + + // null + if (remainingLength >= 4) + { + if (json[index] == 'n' && + json[index + 1] == 'u' && + json[index + 2] == 'l' && + json[index + 3] == 'l') + { + index += 4; + return TOKEN_NULL; + } + } + + return TOKEN_NONE; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/Language.cs b/src/Greenshot.Base/Core/Language.cs similarity index 97% rename from src/GreenshotPlugin/Core/Language.cs rename to src/Greenshot.Base/Core/Language.cs index ae0b4ed0f..74ba1b457 100644 --- a/src/GreenshotPlugin/Core/Language.cs +++ b/src/Greenshot.Base/Core/Language.cs @@ -1,807 +1,807 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Text.RegularExpressions; -using System.Xml; -using GreenshotPlugin.IniFile; -using log4net; -using Microsoft.Win32; - -namespace GreenshotPlugin.Core -{ - /// - /// This class supplies the GUI with translations, based upon keys. - /// The language resources are loaded from the language files found on fixed or supplied paths - /// - public class Language - { - private static readonly ILog Log = LogManager.GetLogger(typeof(Language)); - private static readonly List LanguagePaths = new List(); - private static readonly Dictionary> LanguageFiles = new Dictionary>(); - private static readonly Dictionary HelpFiles = new Dictionary(); - private const string DefaultLanguage = "en-US"; - private const string HelpFilenamePattern = @"help-*.html"; - private const string LanguageFilenamePattern = @"language*.xml"; - private static readonly Regex PrefixRegexp = new Regex(@"language_([a-zA-Z0-9]+).*"); - private static readonly Regex IetfCleanRegexp = new Regex(@"[^a-zA-Z]+"); - private static readonly Regex IetfRegexp = new Regex(@"^.*([a-zA-Z]{2,3}-[a-zA-Z]{1,2})\.xml$"); - private const string LanguageGroupsKey = @"SYSTEM\CurrentControlSet\Control\Nls\Language Groups"; - private static readonly List UnsupportedLanguageGroups = new List(); - private static readonly Dictionary Resources = new Dictionary(); - private static string _currentLanguage; - - public static event LanguageChangedHandler LanguageChanged; - - /// - /// Static initializer for the language code - /// - static Language() - { - if (!IniConfig.IsInitialized) - { - Log.Warn("IniConfig hasn't been initialized yet! (Design mode?)"); - IniConfig.Init("greenshot", "greenshot"); - } - - if (!LogHelper.IsInitialized) - { - Log.Warn("Log4net hasn't been initialized yet! (Design mode?)"); - LogHelper.InitializeLog4Net(); - } - - try - { - string applicationFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - - // PAF Path - if (applicationFolder != null) - { - AddPath(Path.Combine(applicationFolder, @"App\Greenshot\Languages")); - } - - // Application data path - string applicationDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - AddPath(Path.Combine(applicationDataFolder, @"Greenshot\Languages\")); - - // Startup path - if (applicationFolder != null) - { - AddPath(Path.Combine(applicationFolder, @"Languages")); - } - } - catch (Exception pathException) - { - Log.Error(pathException); - } - - try - { - using RegistryKey languageGroupsKey = Registry.LocalMachine.OpenSubKey(LanguageGroupsKey, false); - if (languageGroupsKey != null) - { - string[] groups = languageGroupsKey.GetValueNames(); - foreach (string group in groups) - { - string groupValue = (string) languageGroupsKey.GetValue(group); - bool isGroupNotInstalled = "0".Equals(groupValue); - if (isGroupNotInstalled) - { - UnsupportedLanguageGroups.Add(group.ToLower()); - } - } - } - } - catch (Exception e) - { - Log.Warn("Couldn't read the installed language groups.", e); - } - - var coreConfig = IniConfig.GetIniSection(); - ScanFiles(); - if (!string.IsNullOrEmpty(coreConfig.Language)) - { - CurrentLanguage = coreConfig.Language; - if (CurrentLanguage != null && CurrentLanguage != coreConfig.Language) - { - coreConfig.Language = CurrentLanguage; - } - } - - if (CurrentLanguage == null) - { - Log.Warn("Couldn't set language from configuration, changing to default. Installation problem?"); - CurrentLanguage = DefaultLanguage; - if (CurrentLanguage != null) - { - coreConfig.Language = CurrentLanguage; - } - } - - if (CurrentLanguage == null) - { - Log.Error("Couldn't set language, installation problem?"); - } - } - - /// - /// Internal method to add a path to the paths that will be scanned for language files! - /// - /// - /// true if the path exists and is added - private static bool AddPath(string path) - { - if (!LanguagePaths.Contains(path)) - { - if (Directory.Exists(path)) - { - Log.DebugFormat("Adding language path {0}", path); - LanguagePaths.Add(path); - return true; - } - - Log.InfoFormat("Not adding non existing language path {0}", path); - } - - return false; - } - - /// - /// Add a new path to the paths that will be scanned for language files! - /// - /// - /// true if the path exists and is added - public static bool AddLanguageFilePath(string path) - { - if (!LanguagePaths.Contains(path)) - { - Log.DebugFormat("New language path {0}", path); - if (AddPath(path)) - { - ScanFiles(); - Reload(); - } - else - { - return false; - } - } - - return true; - } - - /// - /// Load the files for the specified ietf - /// - /// - private static void LoadFiles(string ietf) - { - ietf = ReformatIetf(ietf); - if (!LanguageFiles.ContainsKey(ietf)) - { - Log.ErrorFormat("No language {0} available.", ietf); - return; - } - - List filesToLoad = LanguageFiles[ietf]; - foreach (LanguageFile fileToLoad in filesToLoad) - { - LoadResources(fileToLoad); - } - } - - /// - /// Load the language resources from the scanned files - /// - private static void Reload() - { - Resources.Clear(); - LoadFiles(DefaultLanguage); - if (_currentLanguage != null && !_currentLanguage.Equals(DefaultLanguage)) - { - LoadFiles(_currentLanguage); - } - } - - /// - /// Get or set the current language - /// - public static string CurrentLanguage - { - get => _currentLanguage; - set - { - string ietf = FindBestIetfMatch(value); - if (!LanguageFiles.ContainsKey(ietf)) - { - Log.WarnFormat("No match for language {0} found!", ietf); - } - else - { - if (_currentLanguage == null || !_currentLanguage.Equals(ietf)) - { - _currentLanguage = ietf; - Reload(); - if (LanguageChanged == null) - { - return; - } - - try - { - LanguageChanged(null, null); - } - catch - { - // ignored - } - - return; - } - } - - Log.Debug("CurrentLanguage not changed!"); - } - } - - /// - /// Try to find the best match for the supplied IETF - /// - /// string - /// IETF - private static string FindBestIetfMatch(string inputIetf) - { - string returnIetf = inputIetf; - if (string.IsNullOrEmpty(returnIetf)) - { - returnIetf = DefaultLanguage; - } - - returnIetf = ReformatIetf(returnIetf); - if (!LanguageFiles.ContainsKey(returnIetf)) - { - Log.WarnFormat("Unknown language {0}, trying best match!", returnIetf); - if (returnIetf.Length == 5) - { - returnIetf = returnIetf.Substring(0, 2); - } - - foreach (string availableIetf in LanguageFiles.Keys) - { - if (!availableIetf.StartsWith(returnIetf)) continue; - - Log.InfoFormat("Found language {0}, best match for {1}!", availableIetf, returnIetf); - returnIetf = availableIetf; - break; - } - } - - return returnIetf; - } - - /// - /// This helper method clears all non alpha characters from the IETF, and does a reformatting. - /// This prevents problems with multiple formats or typos. - /// - /// - /// - private static string ReformatIetf(string inputIetf) - { - string returnIetf = null; - if (!string.IsNullOrEmpty(inputIetf)) - { - returnIetf = inputIetf.ToLower(); - returnIetf = IetfCleanRegexp.Replace(returnIetf, string.Empty); - if (returnIetf.Length == 4) - { - returnIetf = returnIetf.Substring(0, 2) + "-" + returnIetf.Substring(2, 2).ToUpper(); - } - } - - return returnIetf; - } - - /// - /// Return a list of all the supported languages - /// - public static IList SupportedLanguages - { - get - { - IList languages = new List(); - // Loop over all languages with all the files in there - foreach (List langs in LanguageFiles.Values) - { - // Loop over all the files for a language - foreach (LanguageFile langFile in langs) - { - // Only take the ones without prefix, these are the "base" language files - if (langFile.Prefix != null) continue; - languages.Add(langFile); - break; - } - } - - return languages; - } - } - - /// - /// Return the path to the help-file - /// - public static string HelpFilePath - { - get - { - if (HelpFiles.ContainsKey(_currentLanguage)) - { - return HelpFiles[_currentLanguage]; - } - - return HelpFiles[DefaultLanguage]; - } - } - - /// - /// Load the resources from the language file - /// - /// File to load from - private static void LoadResources(LanguageFile languageFile) - { - Log.InfoFormat("Loading language file {0}", languageFile.Filepath); - try - { - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.Load(languageFile.Filepath); - XmlNodeList resourceNodes = xmlDocument.GetElementsByTagName("resource"); - foreach (XmlNode resourceNode in resourceNodes) - { - string key = resourceNode.Attributes["name"].Value; - if (!string.IsNullOrEmpty(languageFile.Prefix)) - { - key = languageFile.Prefix + "." + key; - } - - string text = resourceNode.InnerText; - if (!string.IsNullOrEmpty(text)) - { - text = text.Trim(); - } - - if (!Resources.ContainsKey(key)) - { - Resources.Add(key, text); - } - else - { - Resources[key] = text; - } - } - } - catch (Exception e) - { - Log.Error("Could not load language file " + languageFile.Filepath, e); - } - } - - /// - /// Load the language file information - /// - /// - /// - private static LanguageFile LoadFileInfo(string languageFilePath) - { - try - { - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.Load(languageFilePath); - XmlNodeList nodes = xmlDocument.GetElementsByTagName("language"); - if (nodes.Count > 0) - { - LanguageFile languageFile = new LanguageFile - { - Filepath = languageFilePath - }; - XmlNode node = nodes.Item(0); - if (node?.Attributes != null) - { - languageFile.Description = node.Attributes["description"].Value; - if (node.Attributes["ietf"] != null) - { - languageFile.Ietf = ReformatIetf(node.Attributes["ietf"].Value); - } - - if (node.Attributes["version"] != null) - { - languageFile.Version = new Version(node.Attributes["version"].Value); - } - - if (node.Attributes["prefix"] != null) - { - languageFile.Prefix = node.Attributes["prefix"].Value.ToLower(); - } - - if (node.Attributes["languagegroup"] != null) - { - string languageGroup = node.Attributes["languagegroup"].Value; - languageFile.LanguageGroup = languageGroup.ToLower(); - } - } - - return languageFile; - } - - throw new XmlException("Root element is missing"); - } - catch (Exception e) - { - Log.Error("Could not load language file " + languageFilePath, e); - } - - return null; - } - - /// - /// Scan the files in all directories - /// - private static void ScanFiles() - { - LanguageFiles.Clear(); - HelpFiles.Clear(); - foreach (string languagePath in LanguagePaths) - { - if (!Directory.Exists(languagePath)) - { - Log.InfoFormat("Skipping non existing language path {0}", languagePath); - continue; - } - - Log.InfoFormat("Searching language directory '{0}' for language files with pattern '{1}'", languagePath, LanguageFilenamePattern); - try - { - foreach (string languageFilepath in Directory.GetFiles(languagePath, LanguageFilenamePattern, SearchOption.AllDirectories)) - { - //LOG.DebugFormat("Found language file: {0}", languageFilepath); - LanguageFile languageFile = LoadFileInfo(languageFilepath); - if (languageFile == null) - { - continue; - } - - if (string.IsNullOrEmpty(languageFile.Ietf)) - { - Log.WarnFormat("Fixing missing ietf in language-file {0}", languageFilepath); - string languageFilename = Path.GetFileName(languageFilepath); - if (IetfRegexp.IsMatch(languageFilename)) - { - string replacementIetf = IetfRegexp.Replace(languageFilename, "$1"); - languageFile.Ietf = ReformatIetf(replacementIetf); - Log.InfoFormat("Fixed IETF to {0}", languageFile.Ietf); - } - else - { - Log.ErrorFormat("Missing ietf , no recover possible... skipping language-file {0}!", languageFilepath); - continue; - } - } - - // Check if we can display the file - if (!string.IsNullOrEmpty(languageFile.LanguageGroup) && UnsupportedLanguageGroups.Contains(languageFile.LanguageGroup)) - { - Log.InfoFormat("Skipping unsuported (not able to display) language {0} from file {1}", languageFile.Description, languageFilepath); - continue; - } - - // build prefix, based on the filename, but only if it's not set in the file itself. - if (string.IsNullOrEmpty(languageFile.Prefix)) - { - string languageFilename = Path.GetFileNameWithoutExtension(languageFilepath); - if (PrefixRegexp.IsMatch(languageFilename)) - { - languageFile.Prefix = PrefixRegexp.Replace(languageFilename, "$1"); - if (!string.IsNullOrEmpty(languageFile.Prefix)) - { - languageFile.Prefix = languageFile.Prefix.Replace("plugin", string.Empty).ToLower(); - } - } - } - - List currentFiles; - if (LanguageFiles.ContainsKey(languageFile.Ietf)) - { - currentFiles = LanguageFiles[languageFile.Ietf]; - bool needToAdd = true; - List deleteList = new List(); - foreach (LanguageFile compareWithLangfile in currentFiles) - { - if ((languageFile.Prefix != null || compareWithLangfile.Prefix != null) && - (languageFile.Prefix == null || - !languageFile.Prefix.Equals(compareWithLangfile.Prefix))) continue; - - if (compareWithLangfile.Version > languageFile.Version) - { - Log.WarnFormat("Skipping {0}:{1}:{2} as {3}:{4}:{5} is newer", languageFile.Filepath, languageFile.Prefix, languageFile.Version, - compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); - needToAdd = false; - break; - } - - Log.WarnFormat("Found {0}:{1}:{2} and deleting {3}:{4}:{5}", languageFile.Filepath, languageFile.Prefix, languageFile.Version, - compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); - deleteList.Add(compareWithLangfile); - } - - if (needToAdd) - { - foreach (LanguageFile deleteFile in deleteList) - { - currentFiles.Remove(deleteFile); - } - - Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); - currentFiles.Add(languageFile); - } - } - else - { - currentFiles = new List - { - languageFile - }; - LanguageFiles.Add(languageFile.Ietf, currentFiles); - Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); - } - } - } - catch (DirectoryNotFoundException) - { - Log.InfoFormat("Non existing language directory: {0}", languagePath); - } - catch (Exception e) - { - Log.Error("Error trying for read directory " + languagePath, e); - } - - // Now find the help files - Log.InfoFormat("Searching language directory '{0}' for help files with pattern '{1}'", languagePath, HelpFilenamePattern); - try - { - foreach (string helpFilepath in Directory.GetFiles(languagePath, HelpFilenamePattern, SearchOption.AllDirectories)) - { - Log.DebugFormat("Found help file: {0}", helpFilepath); - string helpFilename = Path.GetFileName(helpFilepath); - string ietf = ReformatIetf(helpFilename.Replace(".html", string.Empty).Replace("help-", "")); - if (!HelpFiles.ContainsKey(ietf)) - { - HelpFiles.Add(ietf, helpFilepath); - } - else - { - Log.WarnFormat("skipping help file {0}, already a file with the same IETF {1} found!", helpFilepath, ietf); - } - } - } - catch (DirectoryNotFoundException) - { - Log.InfoFormat("Non existing language directory: {0}", languagePath); - } - catch (Exception e) - { - Log.Error("Error trying for read directory " + languagePath, e); - } - } - } - - /// - /// Check if a resource with prefix.key exists - /// - /// - /// - /// true if available - public static bool HasKey(string prefix, string key) - { - return HasKey(prefix + "." + key); - } - - /// - /// Check if a resource with key exists - /// - /// - /// true if available - public static bool HasKey(string key) - { - if (key == null) - { - return false; - } - - return Resources.ContainsKey(key); - } - - /// - /// TryGet method which combines HasKey & GetString - /// - /// - /// out string - /// - public static bool TryGetString(string key, out string languageString) - { - return Resources.TryGetValue(key, out languageString); - } - - /// - /// TryGet method which combines HasKey & GetString - /// - /// string with prefix - /// string with key - /// out string - /// - public static bool TryGetString(string prefix, string key, out string languageString) - { - return Resources.TryGetValue(prefix + "." + key, out languageString); - } - - /// - /// TryGet method which combines HasKey & GetString - /// - /// string with prefix - /// Enum with key - /// out string - /// - public static bool TryGetString(string prefix, Enum key, out string languageString) - { - return Resources.TryGetValue(prefix + "." + key, out languageString); - } - - /// - /// Translate - /// - /// object - /// string - public static string Translate(object key) - { - string typename = key.GetType().Name; - string enumKey = typename + "." + key; - if (HasKey(enumKey)) - { - return GetString(enumKey); - } - - return key.ToString(); - } - - /// - /// Get the resource for key - /// - /// Enum - /// resource or a "string ###key### not found" - public static string GetString(Enum key) - { - if (key == null) - { - return null; - } - - return GetString(key.ToString()); - } - - /// - /// Get the resource for prefix.key - /// - /// string - /// Enum - /// resource or a "string ###prefix.key### not found" - public static string GetString(string prefix, Enum key) - { - if (key == null) - { - return null; - } - - return GetString(prefix + "." + key); - } - - /// - /// Get the resource for prefix.key - /// - /// string - /// string - /// resource or a "string ###prefix.key### not found" - public static string GetString(string prefix, string key) - { - return GetString(prefix + "." + key); - } - - /// - /// Get the resource for key - /// - /// string - /// resource or a "string ###key### not found" - public static string GetString(string key) - { - if (key == null) - { - return null; - } - - if (!Resources.TryGetValue(key, out var returnValue)) - { - return "string ###" + key + "### not found"; - } - - return returnValue; - } - - /// - /// Get the resource for key, format with with string.format an supply the parameters - /// - /// Enum - /// object - /// formatted resource or a "string ###key### not found" - public static string GetFormattedString(Enum key, object param) - { - return GetFormattedString(key.ToString(), param); - } - - /// - /// Get the resource for prefix.key, format with with string.format an supply the parameters - /// - /// string - /// Enum - /// object - /// formatted resource or a "string ###prefix.key### not found" - public static string GetFormattedString(string prefix, Enum key, object param) - { - return GetFormattedString(prefix, key.ToString(), param); - } - - /// - /// Get the resource for prefix.key, format with with string.format an supply the parameters - /// - /// string - /// string - /// object - /// formatted resource or a "string ###prefix.key### not found" - public static string GetFormattedString(string prefix, string key, object param) - { - return GetFormattedString(prefix + "." + key, param); - } - - /// - /// Get the resource for key, format with with string.format an supply the parameters - /// - /// string - /// object - /// formatted resource or a "string ###key### not found" - public static string GetFormattedString(string key, object param) - { - if (!Resources.TryGetValue(key, out var returnValue)) - { - return "string ###" + key + "### not found"; - } - - return string.Format(returnValue, param); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Xml; +using Greenshot.Base.IniFile; +using log4net; +using Microsoft.Win32; + +namespace Greenshot.Base.Core +{ + /// + /// This class supplies the GUI with translations, based upon keys. + /// The language resources are loaded from the language files found on fixed or supplied paths + /// + public class Language + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Language)); + private static readonly List LanguagePaths = new List(); + private static readonly Dictionary> LanguageFiles = new Dictionary>(); + private static readonly Dictionary HelpFiles = new Dictionary(); + private const string DefaultLanguage = "en-US"; + private const string HelpFilenamePattern = @"help-*.html"; + private const string LanguageFilenamePattern = @"language*.xml"; + private static readonly Regex PrefixRegexp = new Regex(@"language_([a-zA-Z0-9]+).*"); + private static readonly Regex IetfCleanRegexp = new Regex(@"[^a-zA-Z]+"); + private static readonly Regex IetfRegexp = new Regex(@"^.*([a-zA-Z]{2,3}-[a-zA-Z]{1,2})\.xml$"); + private const string LanguageGroupsKey = @"SYSTEM\CurrentControlSet\Control\Nls\Language Groups"; + private static readonly List UnsupportedLanguageGroups = new List(); + private static readonly Dictionary Resources = new Dictionary(); + private static string _currentLanguage; + + public static event LanguageChangedHandler LanguageChanged; + + /// + /// Static initializer for the language code + /// + static Language() + { + if (!IniConfig.IsInitialized) + { + Log.Warn("IniConfig hasn't been initialized yet! (Design mode?)"); + IniConfig.Init("greenshot", "greenshot"); + } + + if (!LogHelper.IsInitialized) + { + Log.Warn("Log4net hasn't been initialized yet! (Design mode?)"); + LogHelper.InitializeLog4Net(); + } + + try + { + string applicationFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + // PAF Path + if (applicationFolder != null) + { + AddPath(Path.Combine(applicationFolder, @"App\Greenshot\Languages")); + } + + // Application data path + string applicationDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + AddPath(Path.Combine(applicationDataFolder, @"Greenshot\Languages\")); + + // Startup path + if (applicationFolder != null) + { + AddPath(Path.Combine(applicationFolder, @"Languages")); + } + } + catch (Exception pathException) + { + Log.Error(pathException); + } + + try + { + using RegistryKey languageGroupsKey = Registry.LocalMachine.OpenSubKey(LanguageGroupsKey, false); + if (languageGroupsKey != null) + { + string[] groups = languageGroupsKey.GetValueNames(); + foreach (string group in groups) + { + string groupValue = (string) languageGroupsKey.GetValue(group); + bool isGroupNotInstalled = "0".Equals(groupValue); + if (isGroupNotInstalled) + { + UnsupportedLanguageGroups.Add(group.ToLower()); + } + } + } + } + catch (Exception e) + { + Log.Warn("Couldn't read the installed language groups.", e); + } + + var coreConfig = IniConfig.GetIniSection(); + ScanFiles(); + if (!string.IsNullOrEmpty(coreConfig.Language)) + { + CurrentLanguage = coreConfig.Language; + if (CurrentLanguage != null && CurrentLanguage != coreConfig.Language) + { + coreConfig.Language = CurrentLanguage; + } + } + + if (CurrentLanguage == null) + { + Log.Warn("Couldn't set language from configuration, changing to default. Installation problem?"); + CurrentLanguage = DefaultLanguage; + if (CurrentLanguage != null) + { + coreConfig.Language = CurrentLanguage; + } + } + + if (CurrentLanguage == null) + { + Log.Error("Couldn't set language, installation problem?"); + } + } + + /// + /// Internal method to add a path to the paths that will be scanned for language files! + /// + /// + /// true if the path exists and is added + private static bool AddPath(string path) + { + if (!LanguagePaths.Contains(path)) + { + if (Directory.Exists(path)) + { + Log.DebugFormat("Adding language path {0}", path); + LanguagePaths.Add(path); + return true; + } + + Log.InfoFormat("Not adding non existing language path {0}", path); + } + + return false; + } + + /// + /// Add a new path to the paths that will be scanned for language files! + /// + /// + /// true if the path exists and is added + public static bool AddLanguageFilePath(string path) + { + if (!LanguagePaths.Contains(path)) + { + Log.DebugFormat("New language path {0}", path); + if (AddPath(path)) + { + ScanFiles(); + Reload(); + } + else + { + return false; + } + } + + return true; + } + + /// + /// Load the files for the specified ietf + /// + /// + private static void LoadFiles(string ietf) + { + ietf = ReformatIetf(ietf); + if (!LanguageFiles.ContainsKey(ietf)) + { + Log.ErrorFormat("No language {0} available.", ietf); + return; + } + + List filesToLoad = LanguageFiles[ietf]; + foreach (LanguageFile fileToLoad in filesToLoad) + { + LoadResources(fileToLoad); + } + } + + /// + /// Load the language resources from the scanned files + /// + private static void Reload() + { + Resources.Clear(); + LoadFiles(DefaultLanguage); + if (_currentLanguage != null && !_currentLanguage.Equals(DefaultLanguage)) + { + LoadFiles(_currentLanguage); + } + } + + /// + /// Get or set the current language + /// + public static string CurrentLanguage + { + get => _currentLanguage; + set + { + string ietf = FindBestIetfMatch(value); + if (!LanguageFiles.ContainsKey(ietf)) + { + Log.WarnFormat("No match for language {0} found!", ietf); + } + else + { + if (_currentLanguage == null || !_currentLanguage.Equals(ietf)) + { + _currentLanguage = ietf; + Reload(); + if (LanguageChanged == null) + { + return; + } + + try + { + LanguageChanged(null, null); + } + catch + { + // ignored + } + + return; + } + } + + Log.Debug("CurrentLanguage not changed!"); + } + } + + /// + /// Try to find the best match for the supplied IETF + /// + /// string + /// IETF + private static string FindBestIetfMatch(string inputIetf) + { + string returnIetf = inputIetf; + if (string.IsNullOrEmpty(returnIetf)) + { + returnIetf = DefaultLanguage; + } + + returnIetf = ReformatIetf(returnIetf); + if (!LanguageFiles.ContainsKey(returnIetf)) + { + Log.WarnFormat("Unknown language {0}, trying best match!", returnIetf); + if (returnIetf.Length == 5) + { + returnIetf = returnIetf.Substring(0, 2); + } + + foreach (string availableIetf in LanguageFiles.Keys) + { + if (!availableIetf.StartsWith(returnIetf)) continue; + + Log.InfoFormat("Found language {0}, best match for {1}!", availableIetf, returnIetf); + returnIetf = availableIetf; + break; + } + } + + return returnIetf; + } + + /// + /// This helper method clears all non alpha characters from the IETF, and does a reformatting. + /// This prevents problems with multiple formats or typos. + /// + /// + /// + private static string ReformatIetf(string inputIetf) + { + string returnIetf = null; + if (!string.IsNullOrEmpty(inputIetf)) + { + returnIetf = inputIetf.ToLower(); + returnIetf = IetfCleanRegexp.Replace(returnIetf, string.Empty); + if (returnIetf.Length == 4) + { + returnIetf = returnIetf.Substring(0, 2) + "-" + returnIetf.Substring(2, 2).ToUpper(); + } + } + + return returnIetf; + } + + /// + /// Return a list of all the supported languages + /// + public static IList SupportedLanguages + { + get + { + IList languages = new List(); + // Loop over all languages with all the files in there + foreach (List langs in LanguageFiles.Values) + { + // Loop over all the files for a language + foreach (LanguageFile langFile in langs) + { + // Only take the ones without prefix, these are the "base" language files + if (langFile.Prefix != null) continue; + languages.Add(langFile); + break; + } + } + + return languages; + } + } + + /// + /// Return the path to the help-file + /// + public static string HelpFilePath + { + get + { + if (HelpFiles.ContainsKey(_currentLanguage)) + { + return HelpFiles[_currentLanguage]; + } + + return HelpFiles[DefaultLanguage]; + } + } + + /// + /// Load the resources from the language file + /// + /// File to load from + private static void LoadResources(LanguageFile languageFile) + { + Log.InfoFormat("Loading language file {0}", languageFile.Filepath); + try + { + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.Load(languageFile.Filepath); + XmlNodeList resourceNodes = xmlDocument.GetElementsByTagName("resource"); + foreach (XmlNode resourceNode in resourceNodes) + { + string key = resourceNode.Attributes["name"].Value; + if (!string.IsNullOrEmpty(languageFile.Prefix)) + { + key = languageFile.Prefix + "." + key; + } + + string text = resourceNode.InnerText; + if (!string.IsNullOrEmpty(text)) + { + text = text.Trim(); + } + + if (!Resources.ContainsKey(key)) + { + Resources.Add(key, text); + } + else + { + Resources[key] = text; + } + } + } + catch (Exception e) + { + Log.Error("Could not load language file " + languageFile.Filepath, e); + } + } + + /// + /// Load the language file information + /// + /// + /// + private static LanguageFile LoadFileInfo(string languageFilePath) + { + try + { + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.Load(languageFilePath); + XmlNodeList nodes = xmlDocument.GetElementsByTagName("language"); + if (nodes.Count > 0) + { + LanguageFile languageFile = new LanguageFile + { + Filepath = languageFilePath + }; + XmlNode node = nodes.Item(0); + if (node?.Attributes != null) + { + languageFile.Description = node.Attributes["description"].Value; + if (node.Attributes["ietf"] != null) + { + languageFile.Ietf = ReformatIetf(node.Attributes["ietf"].Value); + } + + if (node.Attributes["version"] != null) + { + languageFile.Version = new Version(node.Attributes["version"].Value); + } + + if (node.Attributes["prefix"] != null) + { + languageFile.Prefix = node.Attributes["prefix"].Value.ToLower(); + } + + if (node.Attributes["languagegroup"] != null) + { + string languageGroup = node.Attributes["languagegroup"].Value; + languageFile.LanguageGroup = languageGroup.ToLower(); + } + } + + return languageFile; + } + + throw new XmlException("Root element is missing"); + } + catch (Exception e) + { + Log.Error("Could not load language file " + languageFilePath, e); + } + + return null; + } + + /// + /// Scan the files in all directories + /// + private static void ScanFiles() + { + LanguageFiles.Clear(); + HelpFiles.Clear(); + foreach (string languagePath in LanguagePaths) + { + if (!Directory.Exists(languagePath)) + { + Log.InfoFormat("Skipping non existing language path {0}", languagePath); + continue; + } + + Log.InfoFormat("Searching language directory '{0}' for language files with pattern '{1}'", languagePath, LanguageFilenamePattern); + try + { + foreach (string languageFilepath in Directory.GetFiles(languagePath, LanguageFilenamePattern, SearchOption.AllDirectories)) + { + //LOG.DebugFormat("Found language file: {0}", languageFilepath); + LanguageFile languageFile = LoadFileInfo(languageFilepath); + if (languageFile == null) + { + continue; + } + + if (string.IsNullOrEmpty(languageFile.Ietf)) + { + Log.WarnFormat("Fixing missing ietf in language-file {0}", languageFilepath); + string languageFilename = Path.GetFileName(languageFilepath); + if (IetfRegexp.IsMatch(languageFilename)) + { + string replacementIetf = IetfRegexp.Replace(languageFilename, "$1"); + languageFile.Ietf = ReformatIetf(replacementIetf); + Log.InfoFormat("Fixed IETF to {0}", languageFile.Ietf); + } + else + { + Log.ErrorFormat("Missing ietf , no recover possible... skipping language-file {0}!", languageFilepath); + continue; + } + } + + // Check if we can display the file + if (!string.IsNullOrEmpty(languageFile.LanguageGroup) && UnsupportedLanguageGroups.Contains(languageFile.LanguageGroup)) + { + Log.InfoFormat("Skipping unsuported (not able to display) language {0} from file {1}", languageFile.Description, languageFilepath); + continue; + } + + // build prefix, based on the filename, but only if it's not set in the file itself. + if (string.IsNullOrEmpty(languageFile.Prefix)) + { + string languageFilename = Path.GetFileNameWithoutExtension(languageFilepath); + if (PrefixRegexp.IsMatch(languageFilename)) + { + languageFile.Prefix = PrefixRegexp.Replace(languageFilename, "$1"); + if (!string.IsNullOrEmpty(languageFile.Prefix)) + { + languageFile.Prefix = languageFile.Prefix.Replace("plugin", string.Empty).ToLower(); + } + } + } + + List currentFiles; + if (LanguageFiles.ContainsKey(languageFile.Ietf)) + { + currentFiles = LanguageFiles[languageFile.Ietf]; + bool needToAdd = true; + List deleteList = new List(); + foreach (LanguageFile compareWithLangfile in currentFiles) + { + if ((languageFile.Prefix != null || compareWithLangfile.Prefix != null) && + (languageFile.Prefix == null || + !languageFile.Prefix.Equals(compareWithLangfile.Prefix))) continue; + + if (compareWithLangfile.Version > languageFile.Version) + { + Log.WarnFormat("Skipping {0}:{1}:{2} as {3}:{4}:{5} is newer", languageFile.Filepath, languageFile.Prefix, languageFile.Version, + compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); + needToAdd = false; + break; + } + + Log.WarnFormat("Found {0}:{1}:{2} and deleting {3}:{4}:{5}", languageFile.Filepath, languageFile.Prefix, languageFile.Version, + compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); + deleteList.Add(compareWithLangfile); + } + + if (needToAdd) + { + foreach (LanguageFile deleteFile in deleteList) + { + currentFiles.Remove(deleteFile); + } + + Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); + currentFiles.Add(languageFile); + } + } + else + { + currentFiles = new List + { + languageFile + }; + LanguageFiles.Add(languageFile.Ietf, currentFiles); + Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); + } + } + } + catch (DirectoryNotFoundException) + { + Log.InfoFormat("Non existing language directory: {0}", languagePath); + } + catch (Exception e) + { + Log.Error("Error trying for read directory " + languagePath, e); + } + + // Now find the help files + Log.InfoFormat("Searching language directory '{0}' for help files with pattern '{1}'", languagePath, HelpFilenamePattern); + try + { + foreach (string helpFilepath in Directory.GetFiles(languagePath, HelpFilenamePattern, SearchOption.AllDirectories)) + { + Log.DebugFormat("Found help file: {0}", helpFilepath); + string helpFilename = Path.GetFileName(helpFilepath); + string ietf = ReformatIetf(helpFilename.Replace(".html", string.Empty).Replace("help-", "")); + if (!HelpFiles.ContainsKey(ietf)) + { + HelpFiles.Add(ietf, helpFilepath); + } + else + { + Log.WarnFormat("skipping help file {0}, already a file with the same IETF {1} found!", helpFilepath, ietf); + } + } + } + catch (DirectoryNotFoundException) + { + Log.InfoFormat("Non existing language directory: {0}", languagePath); + } + catch (Exception e) + { + Log.Error("Error trying for read directory " + languagePath, e); + } + } + } + + /// + /// Check if a resource with prefix.key exists + /// + /// + /// + /// true if available + public static bool HasKey(string prefix, string key) + { + return HasKey(prefix + "." + key); + } + + /// + /// Check if a resource with key exists + /// + /// + /// true if available + public static bool HasKey(string key) + { + if (key == null) + { + return false; + } + + return Resources.ContainsKey(key); + } + + /// + /// TryGet method which combines HasKey & GetString + /// + /// + /// out string + /// + public static bool TryGetString(string key, out string languageString) + { + return Resources.TryGetValue(key, out languageString); + } + + /// + /// TryGet method which combines HasKey & GetString + /// + /// string with prefix + /// string with key + /// out string + /// + public static bool TryGetString(string prefix, string key, out string languageString) + { + return Resources.TryGetValue(prefix + "." + key, out languageString); + } + + /// + /// TryGet method which combines HasKey & GetString + /// + /// string with prefix + /// Enum with key + /// out string + /// + public static bool TryGetString(string prefix, Enum key, out string languageString) + { + return Resources.TryGetValue(prefix + "." + key, out languageString); + } + + /// + /// Translate + /// + /// object + /// string + public static string Translate(object key) + { + string typename = key.GetType().Name; + string enumKey = typename + "." + key; + if (HasKey(enumKey)) + { + return GetString(enumKey); + } + + return key.ToString(); + } + + /// + /// Get the resource for key + /// + /// Enum + /// resource or a "string ###key### not found" + public static string GetString(Enum key) + { + if (key == null) + { + return null; + } + + return GetString(key.ToString()); + } + + /// + /// Get the resource for prefix.key + /// + /// string + /// Enum + /// resource or a "string ###prefix.key### not found" + public static string GetString(string prefix, Enum key) + { + if (key == null) + { + return null; + } + + return GetString(prefix + "." + key); + } + + /// + /// Get the resource for prefix.key + /// + /// string + /// string + /// resource or a "string ###prefix.key### not found" + public static string GetString(string prefix, string key) + { + return GetString(prefix + "." + key); + } + + /// + /// Get the resource for key + /// + /// string + /// resource or a "string ###key### not found" + public static string GetString(string key) + { + if (key == null) + { + return null; + } + + if (!Resources.TryGetValue(key, out var returnValue)) + { + return "string ###" + key + "### not found"; + } + + return returnValue; + } + + /// + /// Get the resource for key, format with with string.format an supply the parameters + /// + /// Enum + /// object + /// formatted resource or a "string ###key### not found" + public static string GetFormattedString(Enum key, object param) + { + return GetFormattedString(key.ToString(), param); + } + + /// + /// Get the resource for prefix.key, format with with string.format an supply the parameters + /// + /// string + /// Enum + /// object + /// formatted resource or a "string ###prefix.key### not found" + public static string GetFormattedString(string prefix, Enum key, object param) + { + return GetFormattedString(prefix, key.ToString(), param); + } + + /// + /// Get the resource for prefix.key, format with with string.format an supply the parameters + /// + /// string + /// string + /// object + /// formatted resource or a "string ###prefix.key### not found" + public static string GetFormattedString(string prefix, string key, object param) + { + return GetFormattedString(prefix + "." + key, param); + } + + /// + /// Get the resource for key, format with with string.format an supply the parameters + /// + /// string + /// object + /// formatted resource or a "string ###key### not found" + public static string GetFormattedString(string key, object param) + { + if (!Resources.TryGetValue(key, out var returnValue)) + { + return "string ###" + key + "### not found"; + } + + return string.Format(returnValue, param); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/LanguageChangedHandler.cs b/src/Greenshot.Base/Core/LanguageChangedHandler.cs similarity index 73% rename from src/GreenshotPlugin/Core/LanguageChangedHandler.cs rename to src/Greenshot.Base/Core/LanguageChangedHandler.cs index ab68cb6d4..c9b71532e 100644 --- a/src/GreenshotPlugin/Core/LanguageChangedHandler.cs +++ b/src/Greenshot.Base/Core/LanguageChangedHandler.cs @@ -1,6 +1,6 @@ -using System; - -namespace GreenshotPlugin.Core -{ - public delegate void LanguageChangedHandler(object sender, EventArgs e); +using System; + +namespace Greenshot.Base.Core +{ + public delegate void LanguageChangedHandler(object sender, EventArgs e); } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/LanguageFile.cs b/src/Greenshot.Base/Core/LanguageFile.cs similarity index 94% rename from src/GreenshotPlugin/Core/LanguageFile.cs rename to src/Greenshot.Base/Core/LanguageFile.cs index 3d6552a3c..b9f8a57c4 100644 --- a/src/GreenshotPlugin/Core/LanguageFile.cs +++ b/src/Greenshot.Base/Core/LanguageFile.cs @@ -1,80 +1,80 @@ -using System; - -namespace GreenshotPlugin.Core -{ - /// - /// This class contains the information about a language file - /// - public class LanguageFile : IEquatable - { - public string Description { get; set; } - - public string Ietf { get; set; } - - public Version Version { get; set; } - - public string LanguageGroup { get; set; } - - public string Filepath { get; set; } - - public string Prefix { get; set; } - - /// - /// Overload equals so we can delete a entry from a collection - /// - /// - /// - public bool Equals(LanguageFile other) - { - if (Prefix != null) - { - if (other != null && !Prefix.Equals(other.Prefix)) - { - return false; - } - } - else if (other?.Prefix != null) - { - return false; - } - - if (Ietf != null) - { - if (other != null && !Ietf.Equals(other.Ietf)) - { - return false; - } - } - else if (other?.Ietf != null) - { - return false; - } - - if (Version != null) - { - if (other != null && !Version.Equals(other.Version)) - { - return false; - } - } - else if (other != null && other.Version != null) - { - return false; - } - - if (Filepath != null) - { - if (other != null && !Filepath.Equals(other.Filepath)) - { - return false; - } - } - else if (other?.Filepath != null) - { - return false; - } - - return true; - } - } +using System; + +namespace Greenshot.Base.Core +{ + /// + /// This class contains the information about a language file + /// + public class LanguageFile : IEquatable + { + public string Description { get; set; } + + public string Ietf { get; set; } + + public Version Version { get; set; } + + public string LanguageGroup { get; set; } + + public string Filepath { get; set; } + + public string Prefix { get; set; } + + /// + /// Overload equals so we can delete a entry from a collection + /// + /// + /// + public bool Equals(LanguageFile other) + { + if (Prefix != null) + { + if (other != null && !Prefix.Equals(other.Prefix)) + { + return false; + } + } + else if (other?.Prefix != null) + { + return false; + } + + if (Ietf != null) + { + if (other != null && !Ietf.Equals(other.Ietf)) + { + return false; + } + } + else if (other?.Ietf != null) + { + return false; + } + + if (Version != null) + { + if (other != null && !Version.Equals(other.Version)) + { + return false; + } + } + else if (other != null && other.Version != null) + { + return false; + } + + if (Filepath != null) + { + if (other != null && !Filepath.Equals(other.Filepath)) + { + return false; + } + } + else if (other?.Filepath != null) + { + return false; + } + + return true; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/LogHelper.cs b/src/Greenshot.Base/Core/LogHelper.cs similarity index 95% rename from src/GreenshotPlugin/Core/LogHelper.cs rename to src/Greenshot.Base/Core/LogHelper.cs index 45cd9df0e..eb02423f8 100644 --- a/src/GreenshotPlugin/Core/LogHelper.cs +++ b/src/Greenshot.Base/Core/LogHelper.cs @@ -1,124 +1,124 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.IO; -using System.Reflection; -using System.Windows.Forms; -using log4net; -using log4net.Appender; -using log4net.Config; -using log4net.Repository.Hierarchy; -using System; -using GreenshotPlugin.IniFile; -using log4net.Util; - -namespace GreenshotPlugin.Core -{ - /// - /// Initialize the logger - /// - public class LogHelper - { - private static bool _isLog4NetConfigured; - private const string InitMessage = "Greenshot initialization of log system failed"; - - public static bool IsInitialized => _isLog4NetConfigured; - - // Initialize Log4J - public static string InitializeLog4Net() - { - // Setup log4j, currently the file is called log4net.xml - foreach (var logName in new[] - { - "log4net.xml", @"App\Greenshot\log4net-portable.xml" - }) - { - string log4NetFilename = Path.Combine(Application.StartupPath, logName); - if (File.Exists(log4NetFilename)) - { - try - { - XmlConfigurator.Configure(new FileInfo(log4NetFilename)); - _isLog4NetConfigured = true; - } - catch (Exception ex) - { - MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - } - } - - // Fallback - if (!_isLog4NetConfigured) - { - try - { - Assembly assembly = typeof(LogHelper).Assembly; - using Stream stream = assembly.GetManifestResourceStream("GreenshotPlugin.log4net-embedded.xml"); - XmlConfigurator.Configure(stream); - _isLog4NetConfigured = true; - IniConfig.ForceIniInStartupPath(); - } - catch (Exception ex) - { - MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - } - - if (_isLog4NetConfigured) - { - // Get the logfile name - try - { - if (((Hierarchy) LogManager.GetRepository()).Root.Appenders.Count > 0) - { - foreach (IAppender appender in ((Hierarchy) LogManager.GetRepository()).Root.Appenders) - { - var fileAppender = appender as FileAppender; - if (fileAppender != null) - { - return fileAppender.File; - } - } - } - } - catch - { - // ignored - } - } - - return null; - } - } - - /// - /// A simple helper class to support the logging to the AppData location - /// - public class SpecialFolderPatternConverter : PatternConverter - { - protected override void Convert(TextWriter writer, object state) - { - Environment.SpecialFolder specialFolder = (Environment.SpecialFolder) Enum.Parse(typeof(Environment.SpecialFolder), Option, true); - writer.Write(Environment.GetFolderPath(specialFolder)); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.IO; +using System.Reflection; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using log4net; +using log4net.Appender; +using log4net.Config; +using log4net.Repository.Hierarchy; +using log4net.Util; + +namespace Greenshot.Base.Core +{ + /// + /// Initialize the logger + /// + public class LogHelper + { + private static bool _isLog4NetConfigured; + private const string InitMessage = "Greenshot initialization of log system failed"; + + public static bool IsInitialized => _isLog4NetConfigured; + + // Initialize Log4J + public static string InitializeLog4Net() + { + // Setup log4j, currently the file is called log4net.xml + foreach (var logName in new[] + { + "log4net.xml", @"App\Greenshot\log4net-portable.xml" + }) + { + string log4NetFilename = Path.Combine(Application.StartupPath, logName); + if (File.Exists(log4NetFilename)) + { + try + { + XmlConfigurator.Configure(new FileInfo(log4NetFilename)); + _isLog4NetConfigured = true; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } + } + + // Fallback + if (!_isLog4NetConfigured) + { + try + { + Assembly assembly = typeof(LogHelper).Assembly; + using Stream stream = assembly.GetManifestResourceStream("GreenshotPlugin.log4net-embedded.xml"); + XmlConfigurator.Configure(stream); + _isLog4NetConfigured = true; + IniConfig.ForceIniInStartupPath(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } + + if (_isLog4NetConfigured) + { + // Get the logfile name + try + { + if (((Hierarchy) LogManager.GetRepository()).Root.Appenders.Count > 0) + { + foreach (IAppender appender in ((Hierarchy) LogManager.GetRepository()).Root.Appenders) + { + var fileAppender = appender as FileAppender; + if (fileAppender != null) + { + return fileAppender.File; + } + } + } + } + catch + { + // ignored + } + } + + return null; + } + } + + /// + /// A simple helper class to support the logging to the AppData location + /// + public class SpecialFolderPatternConverter : PatternConverter + { + protected override void Convert(TextWriter writer, object state) + { + Environment.SpecialFolder specialFolder = (Environment.SpecialFolder) Enum.Parse(typeof(Environment.SpecialFolder), Option, true); + writer.Write(Environment.GetFolderPath(specialFolder)); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/NetworkHelper.cs b/src/Greenshot.Base/Core/NetworkHelper.cs similarity index 96% rename from src/GreenshotPlugin/Core/NetworkHelper.cs rename to src/Greenshot.Base/Core/NetworkHelper.cs index 463a9bd19..21899e701 100644 --- a/src/GreenshotPlugin/Core/NetworkHelper.cs +++ b/src/Greenshot.Base/Core/NetworkHelper.cs @@ -1,728 +1,728 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using log4net; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Globalization; -using System.IO; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; - -namespace GreenshotPlugin.Core -{ - /// - /// HTTP Method to make sure we have the correct method - /// - public enum HTTPMethod - { - GET, - POST, - PUT, - DELETE - }; - - /// - /// Description of NetworkHelper. - /// - public static class NetworkHelper - { - private static readonly ILog Log = LogManager.GetLogger(typeof(NetworkHelper)); - private static readonly CoreConfiguration Config = IniConfig.GetIniSection(); - - static NetworkHelper() - { - try - { - // Disable certificate checking - ServicePointManager.ServerCertificateValidationCallback += delegate { return true; }; - } - catch (Exception ex) - { - Log.Warn("An error has occurred while allowing self-signed certificates:", ex); - } - } - - /// - /// Download the uri into a memory stream, without catching exceptions - /// - /// Of an image - /// MemoryStream which is already seek-ed to 0 - public static MemoryStream GetAsMemoryStream(string url) - { - var request = CreateWebRequest(url); - using var response = (HttpWebResponse) request.GetResponse(); - var memoryStream = new MemoryStream(); - using (var responseStream = response.GetResponseStream()) - { - responseStream?.CopyTo(memoryStream); - // Make sure it can be used directly - memoryStream.Seek(0, SeekOrigin.Begin); - } - - return memoryStream; - } - - /// - /// Download the uri to Bitmap - /// - /// Of an image - /// Bitmap - public static Image DownloadImage(string url) - { - var extensions = new StringBuilder(); - foreach (var extension in ImageHelper.StreamConverters.Keys) - { - if (string.IsNullOrEmpty(extension)) - { - continue; - } - - extensions.AppendFormat(@"\.{0}|", extension); - } - - extensions.Length--; - - var imageUrlRegex = new Regex($@"(http|https)://.*(?{extensions})"); - var match = imageUrlRegex.Match(url); - try - { - using var memoryStream = GetAsMemoryStream(url); - try - { - return ImageHelper.FromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null); - } - catch (Exception) - { - // If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead. - string content; - using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true)) - { - content = streamReader.ReadLine(); - } - - if (string.IsNullOrEmpty(content)) - { - throw; - } - - match = imageUrlRegex.Match(content); - if (!match.Success) - { - throw; - } - - using var memoryStream2 = GetAsMemoryStream(match.Value); - return ImageHelper.FromStream(memoryStream2, match.Groups["extension"]?.Value); - } - } - catch (Exception e) - { - Log.Error("Problem downloading the image from: " + url, e); - } - - return null; - } - - /// - /// Helper method to create a web request with a lot of default settings - /// - /// string with uri to connect to - /// WebRequest - public static HttpWebRequest CreateWebRequest(string uri) - { - return CreateWebRequest(new Uri(uri)); - } - - /// - /// Helper method to create a web request with a lot of default settings - /// - /// string with uri to connect to - /// /// Method to use - /// WebRequest - public static HttpWebRequest CreateWebRequest(string uri, HTTPMethod method) - { - return CreateWebRequest(new Uri(uri), method); - } - - /// - /// Helper method to create a web request with a lot of default settings - /// - /// Uri with uri to connect to - /// Method to use - /// WebRequest - public static HttpWebRequest CreateWebRequest(Uri uri, HTTPMethod method) - { - var webRequest = CreateWebRequest(uri); - webRequest.Method = method.ToString(); - return webRequest; - } - - /// - /// Helper method to create a web request, eventually with proxy - /// - /// Uri with uri to connect to - /// WebRequest - public static HttpWebRequest CreateWebRequest(Uri uri) - { - var webRequest = (HttpWebRequest) WebRequest.Create(uri); - webRequest.Proxy = Config.UseProxy ? CreateProxy(uri) : null; - // Make sure the default credentials are available - webRequest.Credentials = CredentialCache.DefaultCredentials; - - // Allow redirect, this is usually needed so that we don't get a problem when a service moves - webRequest.AllowAutoRedirect = true; - // Set default timeouts - webRequest.Timeout = Config.WebRequestTimeout * 1000; - webRequest.ReadWriteTimeout = Config.WebRequestReadWriteTimeout * 1000; - return webRequest; - } - - /// - /// Create a IWebProxy Object which can be used to access the Internet - /// This method will check the configuration if the proxy is allowed to be used. - /// Usages can be found in the DownloadFavIcon or Jira and Confluence plugins - /// - /// - /// IWebProxy filled with all the proxy details or null if none is set/wanted - public static IWebProxy CreateProxy(Uri uri) - { - IWebProxy proxyToUse = null; - if (!Config.UseProxy) - { - return proxyToUse; - } - - proxyToUse = WebRequest.DefaultWebProxy; - if (proxyToUse != null) - { - proxyToUse.Credentials = CredentialCache.DefaultCredentials; - if (!Log.IsDebugEnabled) - { - return proxyToUse; - } - - // check the proxy for the Uri - if (!proxyToUse.IsBypassed(uri)) - { - var proxyUri = proxyToUse.GetProxy(uri); - if (proxyUri != null) - { - Log.Debug("Using proxy: " + proxyUri + " for " + uri); - } - else - { - Log.Debug("No proxy found!"); - } - } - else - { - Log.Debug("Proxy bypass for: " + uri); - } - } - else - { - Log.Debug("No proxy found!"); - } - - return proxyToUse; - } - - /// - /// UrlEncodes a string without the requirement for System.Web - /// - /// - /// - // [Obsolete("Use System.Uri.EscapeDataString instead")] - public static string UrlEncode(string text) - { - if (!string.IsNullOrEmpty(text)) - { - // System.Uri provides reliable parsing, but doesn't encode spaces. - return Uri.EscapeDataString(text).Replace("%20", "+"); - } - - return null; - } - - /// - /// A wrapper around the EscapeDataString, as the limit is 32766 characters - /// See: http://msdn.microsoft.com/en-us/library/system.uri.escapedatastring%28v=vs.110%29.aspx - /// - /// - /// escaped data string - public static string EscapeDataString(string text) - { - if (!string.IsNullOrEmpty(text)) - { - var result = new StringBuilder(); - int currentLocation = 0; - while (currentLocation < text.Length) - { - string process = text.Substring(currentLocation, Math.Min(16384, text.Length - currentLocation)); - result.Append(Uri.EscapeDataString(process)); - currentLocation += 16384; - } - - return result.ToString(); - } - - return null; - } - - /// - /// UrlDecodes a string without requiring System.Web - /// - /// String to decode. - /// decoded string - public static string UrlDecode(string text) - { - // pre-process for + sign space formatting since System.Uri doesn't handle it - // plus literals are encoded as %2b normally so this should be safe - text = text.Replace("+", " "); - return Uri.UnescapeDataString(text); - } - - /// - /// ParseQueryString without the requirement for System.Web - /// - /// - /// IDictionary string, string - public static IDictionary ParseQueryString(string queryString) - { - IDictionary parameters = new SortedDictionary(); - // remove anything other than query string from uri - if (queryString.Contains("?")) - { - queryString = queryString.Substring(queryString.IndexOf('?') + 1); - } - - foreach (string vp in Regex.Split(queryString, "&")) - { - if (string.IsNullOrEmpty(vp)) - { - continue; - } - - string[] singlePair = Regex.Split(vp, "="); - if (parameters.ContainsKey(singlePair[0])) - { - parameters.Remove(singlePair[0]); - } - - parameters.Add(singlePair[0], singlePair.Length == 2 ? singlePair[1] : string.Empty); - } - - return parameters; - } - - /// - /// Generate the query parameters - /// - /// the list of query parameters - /// a string with the query parameters - public static string GenerateQueryParameters(IDictionary queryParameters) - { - if (queryParameters == null || queryParameters.Count == 0) - { - return string.Empty; - } - - queryParameters = new SortedDictionary(queryParameters); - - var sb = new StringBuilder(); - foreach (string key in queryParameters.Keys) - { - sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode($"{queryParameters[key]}")); - } - - sb.Remove(sb.Length - 1, 1); - - return sb.ToString(); - } - - /// - /// Write Multipart Form Data directly to the HttpWebRequest - /// - /// HttpWebRequest to write the multipart form data to - /// Parameters to include in the multipart form data - public static void WriteMultipartFormData(HttpWebRequest webRequest, IDictionary postParameters) - { - string boundary = $"----------{Guid.NewGuid():N}"; - webRequest.ContentType = "multipart/form-data; boundary=" + boundary; - using Stream formDataStream = webRequest.GetRequestStream(); - WriteMultipartFormData(formDataStream, boundary, postParameters); - } - - /// - /// Write Multipart Form Data to a Stream, content-type should be set before this! - /// - /// Stream to write the multipart form data to - /// String boundary for the multipart/form-data - /// Parameters to include in the multipart form data - public static void WriteMultipartFormData(Stream formDataStream, string boundary, IDictionary postParameters) - { - bool needsClrf = false; - foreach (var param in postParameters) - { - // Add a CRLF to allow multiple parameters to be added. - // Skip it on the first parameter, add it to subsequent parameters. - if (needsClrf) - { - formDataStream.Write(Encoding.UTF8.GetBytes("\r\n"), 0, Encoding.UTF8.GetByteCount("\r\n")); - } - - needsClrf = true; - - if (param.Value is IBinaryContainer binaryContainer) - { - binaryContainer.WriteFormDataToStream(boundary, param.Key, formDataStream); - } - else - { - string postData = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{param.Key}\"\r\n\r\n{param.Value}"; - formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData)); - } - } - - // Add the end of the request. Start with a newline - string footer = "\r\n--" + boundary + "--\r\n"; - formDataStream.Write(Encoding.UTF8.GetBytes(footer), 0, Encoding.UTF8.GetByteCount(footer)); - } - - /// - /// Post content HttpWebRequest - /// - /// HttpWebRequest to write the multipart form data to - /// IDictionary with the headers - /// IBinaryContainer - public static void Post(HttpWebRequest webRequest, IDictionary headers, IBinaryContainer binaryContainer = null) - { - foreach (var header in headers) - { - switch (header.Key) - { - case "Content-Type": - webRequest.ContentType = header.Value as string; - break; - case "Accept": - webRequest.Accept = header.Value as string; - break; - default: - webRequest.Headers.Add(header.Key, Convert.ToString(header.Value)); - break; - } - } - - if (!headers.ContainsKey("Content-Type")) - { - webRequest.ContentType = "application/octet-stream"; - } - - if (binaryContainer != null) - { - using var requestStream = webRequest.GetRequestStream(); - binaryContainer.WriteToStream(requestStream); - } - } - - /// - /// Post content HttpWebRequest - /// - /// HttpWebRequest to write the multipart form data to - /// IDictionary with the headers - /// string - public static void Post(HttpWebRequest webRequest, IDictionary headers, string jsonString) - { - if (headers != null) - { - foreach (var header in headers) - { - switch (header.Key) - { - case "Content-Type": - webRequest.ContentType = header.Value as string; - break; - case "Accept": - webRequest.Accept = header.Value as string; - break; - default: - webRequest.Headers.Add(header.Key, Convert.ToString(header.Value)); - break; - } - } - - if (!headers.ContainsKey("Content-Type")) - { - webRequest.ContentType = "application/json"; - } - } - else - { - webRequest.ContentType = "application/json"; - } - - if (jsonString != null) - { - using var requestStream = webRequest.GetRequestStream(); - using var streamWriter = new StreamWriter(requestStream); - streamWriter.Write(jsonString); - } - } - - /// - /// Post the parameters "x-www-form-urlencoded" - /// - /// - /// - public static void UploadFormUrlEncoded(HttpWebRequest webRequest, IDictionary parameters) - { - webRequest.ContentType = "application/x-www-form-urlencoded"; - string urlEncoded = GenerateQueryParameters(parameters); - - byte[] data = Encoding.UTF8.GetBytes(urlEncoded); - using var requestStream = webRequest.GetRequestStream(); - requestStream.Write(data, 0, data.Length); - } - - /// - /// Log the headers of the WebResponse, if IsDebugEnabled - /// - /// WebResponse - private static void DebugHeaders(WebResponse response) - { - if (!Log.IsDebugEnabled) - { - return; - } - - Log.DebugFormat("Debug information on the response from {0} :", response.ResponseUri); - foreach (string key in response.Headers.AllKeys) - { - Log.DebugFormat("Reponse-header: {0}={1}", key, response.Headers[key]); - } - } - - /// - /// Process the web response. - /// - /// The request object. - /// The response data. - /// TODO: This method should handle the StatusCode better! - public static string GetResponseAsString(HttpWebRequest webRequest) - { - return GetResponseAsString(webRequest, false); - } - - /// - /// Read the response as string - /// - /// - /// string or null - private static string GetResponseAsString(HttpWebResponse response) - { - string responseData = null; - if (response == null) - { - return null; - } - - using (response) - { - Stream responseStream = response.GetResponseStream(); - if (responseStream != null) - { - using StreamReader reader = new StreamReader(responseStream, true); - responseData = reader.ReadToEnd(); - } - } - - return responseData; - } - - /// - /// - /// - /// - /// - /// - public static string GetResponseAsString(HttpWebRequest webRequest, bool alsoReturnContentOnError) - { - string responseData = null; - HttpWebResponse response = null; - bool isHttpError = false; - try - { - response = (HttpWebResponse) webRequest.GetResponse(); - Log.InfoFormat("Response status: {0}", response.StatusCode); - isHttpError = (int) response.StatusCode >= 300; - if (isHttpError) - { - Log.ErrorFormat("HTTP error {0}", response.StatusCode); - } - - DebugHeaders(response); - responseData = GetResponseAsString(response); - if (isHttpError) - { - Log.ErrorFormat("HTTP response {0}", responseData); - } - } - catch (WebException e) - { - response = (HttpWebResponse) e.Response; - HttpStatusCode statusCode = HttpStatusCode.Unused; - if (response != null) - { - statusCode = response.StatusCode; - Log.ErrorFormat("HTTP error {0}", statusCode); - string errorContent = GetResponseAsString(response); - if (alsoReturnContentOnError) - { - return errorContent; - } - - Log.ErrorFormat("Content: {0}", errorContent); - } - - Log.Error("WebException: ", e); - if (statusCode == HttpStatusCode.Unauthorized) - { - throw new UnauthorizedAccessException(e.Message); - } - - throw; - } - finally - { - if (response != null) - { - if (isHttpError) - { - Log.ErrorFormat("HTTP error {0} with content: {1}", response.StatusCode, responseData); - } - - response.Close(); - } - } - - return responseData; - } - } - - /// - /// This interface can be used to pass binary information around, like byte[] or Image - /// - public interface IBinaryContainer - { - void WriteFormDataToStream(string boundary, string name, Stream formDataStream); - void WriteToStream(Stream formDataStream); - string ToBase64String(Base64FormattingOptions formattingOptions); - byte[] ToByteArray(); - void Upload(HttpWebRequest webRequest); - - string ContentType { get; } - string Filename { get; set; } - } - - /// A container to supply surfaces to a Multi-part form data upload - /// - public class SurfaceContainer : IBinaryContainer - { - private readonly ISurface _surface; - private readonly SurfaceOutputSettings _outputSettings; - - public SurfaceContainer(ISurface surface, SurfaceOutputSettings outputSettings, string filename) - { - _surface = surface; - _outputSettings = outputSettings; - Filename = filename; - } - - /// - /// Create a Base64String from the Surface by saving it to a memory stream and converting it. - /// Should be avoided if possible, as this uses a lot of memory. - /// - /// string - public string ToBase64String(Base64FormattingOptions formattingOptions) - { - using MemoryStream stream = new MemoryStream(); - ImageOutput.SaveToStream(_surface, stream, _outputSettings); - return Convert.ToBase64String(stream.GetBuffer(), 0, (int) stream.Length, formattingOptions); - } - - /// - /// Create a byte[] from the image by saving it to a memory stream. - /// Should be avoided if possible, as this uses a lot of memory. - /// - /// byte[] - public byte[] ToByteArray() - { - using MemoryStream stream = new MemoryStream(); - ImageOutput.SaveToStream(_surface, stream, _outputSettings); - return stream.ToArray(); - } - - /// - /// Write Multipart Form Data directly to the HttpWebRequest response stream - /// - /// Multipart separator - /// Name of the thing - /// Stream to write to - public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) - { - // Add just the first part of this param, since we will write the file data directly to the Stream - string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n"; - - formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header)); - ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings); - } - - /// - /// A plain "write data to stream" - /// - /// - public void WriteToStream(Stream dataStream) - { - // Write the file data directly to the Stream, rather than serializing it to a string. - ImageOutput.SaveToStream(_surface, dataStream, _outputSettings); - } - - /// - /// Upload the Surface as image to the webrequest - /// - /// - public void Upload(HttpWebRequest webRequest) - { - webRequest.ContentType = ContentType; - using var requestStream = webRequest.GetRequestStream(); - WriteToStream(requestStream); - } - - public string ContentType => "image/" + _outputSettings.Format; - public string Filename { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// HTTP Method to make sure we have the correct method + /// + public enum HTTPMethod + { + GET, + POST, + PUT, + DELETE + }; + + /// + /// Description of NetworkHelper. + /// + public static class NetworkHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(NetworkHelper)); + private static readonly CoreConfiguration Config = IniConfig.GetIniSection(); + + static NetworkHelper() + { + try + { + // Disable certificate checking + ServicePointManager.ServerCertificateValidationCallback += delegate { return true; }; + } + catch (Exception ex) + { + Log.Warn("An error has occurred while allowing self-signed certificates:", ex); + } + } + + /// + /// Download the uri into a memory stream, without catching exceptions + /// + /// Of an image + /// MemoryStream which is already seek-ed to 0 + public static MemoryStream GetAsMemoryStream(string url) + { + var request = CreateWebRequest(url); + using var response = (HttpWebResponse) request.GetResponse(); + var memoryStream = new MemoryStream(); + using (var responseStream = response.GetResponseStream()) + { + responseStream?.CopyTo(memoryStream); + // Make sure it can be used directly + memoryStream.Seek(0, SeekOrigin.Begin); + } + + return memoryStream; + } + + /// + /// Download the uri to Bitmap + /// + /// Of an image + /// Bitmap + public static Image DownloadImage(string url) + { + var extensions = new StringBuilder(); + foreach (var extension in ImageHelper.StreamConverters.Keys) + { + if (string.IsNullOrEmpty(extension)) + { + continue; + } + + extensions.AppendFormat(@"\.{0}|", extension); + } + + extensions.Length--; + + var imageUrlRegex = new Regex($@"(http|https)://.*(?{extensions})"); + var match = imageUrlRegex.Match(url); + try + { + using var memoryStream = GetAsMemoryStream(url); + try + { + return ImageHelper.FromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null); + } + catch (Exception) + { + // If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead. + string content; + using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true)) + { + content = streamReader.ReadLine(); + } + + if (string.IsNullOrEmpty(content)) + { + throw; + } + + match = imageUrlRegex.Match(content); + if (!match.Success) + { + throw; + } + + using var memoryStream2 = GetAsMemoryStream(match.Value); + return ImageHelper.FromStream(memoryStream2, match.Groups["extension"]?.Value); + } + } + catch (Exception e) + { + Log.Error("Problem downloading the image from: " + url, e); + } + + return null; + } + + /// + /// Helper method to create a web request with a lot of default settings + /// + /// string with uri to connect to + /// WebRequest + public static HttpWebRequest CreateWebRequest(string uri) + { + return CreateWebRequest(new Uri(uri)); + } + + /// + /// Helper method to create a web request with a lot of default settings + /// + /// string with uri to connect to + /// /// Method to use + /// WebRequest + public static HttpWebRequest CreateWebRequest(string uri, HTTPMethod method) + { + return CreateWebRequest(new Uri(uri), method); + } + + /// + /// Helper method to create a web request with a lot of default settings + /// + /// Uri with uri to connect to + /// Method to use + /// WebRequest + public static HttpWebRequest CreateWebRequest(Uri uri, HTTPMethod method) + { + var webRequest = CreateWebRequest(uri); + webRequest.Method = method.ToString(); + return webRequest; + } + + /// + /// Helper method to create a web request, eventually with proxy + /// + /// Uri with uri to connect to + /// WebRequest + public static HttpWebRequest CreateWebRequest(Uri uri) + { + var webRequest = (HttpWebRequest) WebRequest.Create(uri); + webRequest.Proxy = Config.UseProxy ? CreateProxy(uri) : null; + // Make sure the default credentials are available + webRequest.Credentials = CredentialCache.DefaultCredentials; + + // Allow redirect, this is usually needed so that we don't get a problem when a service moves + webRequest.AllowAutoRedirect = true; + // Set default timeouts + webRequest.Timeout = Config.WebRequestTimeout * 1000; + webRequest.ReadWriteTimeout = Config.WebRequestReadWriteTimeout * 1000; + return webRequest; + } + + /// + /// Create a IWebProxy Object which can be used to access the Internet + /// This method will check the configuration if the proxy is allowed to be used. + /// Usages can be found in the DownloadFavIcon or Jira and Confluence plugins + /// + /// + /// IWebProxy filled with all the proxy details or null if none is set/wanted + public static IWebProxy CreateProxy(Uri uri) + { + IWebProxy proxyToUse = null; + if (!Config.UseProxy) + { + return proxyToUse; + } + + proxyToUse = WebRequest.DefaultWebProxy; + if (proxyToUse != null) + { + proxyToUse.Credentials = CredentialCache.DefaultCredentials; + if (!Log.IsDebugEnabled) + { + return proxyToUse; + } + + // check the proxy for the Uri + if (!proxyToUse.IsBypassed(uri)) + { + var proxyUri = proxyToUse.GetProxy(uri); + if (proxyUri != null) + { + Log.Debug("Using proxy: " + proxyUri + " for " + uri); + } + else + { + Log.Debug("No proxy found!"); + } + } + else + { + Log.Debug("Proxy bypass for: " + uri); + } + } + else + { + Log.Debug("No proxy found!"); + } + + return proxyToUse; + } + + /// + /// UrlEncodes a string without the requirement for System.Web + /// + /// + /// + // [Obsolete("Use System.Uri.EscapeDataString instead")] + public static string UrlEncode(string text) + { + if (!string.IsNullOrEmpty(text)) + { + // System.Uri provides reliable parsing, but doesn't encode spaces. + return Uri.EscapeDataString(text).Replace("%20", "+"); + } + + return null; + } + + /// + /// A wrapper around the EscapeDataString, as the limit is 32766 characters + /// See: http://msdn.microsoft.com/en-us/library/system.uri.escapedatastring%28v=vs.110%29.aspx + /// + /// + /// escaped data string + public static string EscapeDataString(string text) + { + if (!string.IsNullOrEmpty(text)) + { + var result = new StringBuilder(); + int currentLocation = 0; + while (currentLocation < text.Length) + { + string process = text.Substring(currentLocation, Math.Min(16384, text.Length - currentLocation)); + result.Append(Uri.EscapeDataString(process)); + currentLocation += 16384; + } + + return result.ToString(); + } + + return null; + } + + /// + /// UrlDecodes a string without requiring System.Web + /// + /// String to decode. + /// decoded string + public static string UrlDecode(string text) + { + // pre-process for + sign space formatting since System.Uri doesn't handle it + // plus literals are encoded as %2b normally so this should be safe + text = text.Replace("+", " "); + return Uri.UnescapeDataString(text); + } + + /// + /// ParseQueryString without the requirement for System.Web + /// + /// + /// IDictionary string, string + public static IDictionary ParseQueryString(string queryString) + { + IDictionary parameters = new SortedDictionary(); + // remove anything other than query string from uri + if (queryString.Contains("?")) + { + queryString = queryString.Substring(queryString.IndexOf('?') + 1); + } + + foreach (string vp in Regex.Split(queryString, "&")) + { + if (string.IsNullOrEmpty(vp)) + { + continue; + } + + string[] singlePair = Regex.Split(vp, "="); + if (parameters.ContainsKey(singlePair[0])) + { + parameters.Remove(singlePair[0]); + } + + parameters.Add(singlePair[0], singlePair.Length == 2 ? singlePair[1] : string.Empty); + } + + return parameters; + } + + /// + /// Generate the query parameters + /// + /// the list of query parameters + /// a string with the query parameters + public static string GenerateQueryParameters(IDictionary queryParameters) + { + if (queryParameters == null || queryParameters.Count == 0) + { + return string.Empty; + } + + queryParameters = new SortedDictionary(queryParameters); + + var sb = new StringBuilder(); + foreach (string key in queryParameters.Keys) + { + sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode($"{queryParameters[key]}")); + } + + sb.Remove(sb.Length - 1, 1); + + return sb.ToString(); + } + + /// + /// Write Multipart Form Data directly to the HttpWebRequest + /// + /// HttpWebRequest to write the multipart form data to + /// Parameters to include in the multipart form data + public static void WriteMultipartFormData(HttpWebRequest webRequest, IDictionary postParameters) + { + string boundary = $"----------{Guid.NewGuid():N}"; + webRequest.ContentType = "multipart/form-data; boundary=" + boundary; + using Stream formDataStream = webRequest.GetRequestStream(); + WriteMultipartFormData(formDataStream, boundary, postParameters); + } + + /// + /// Write Multipart Form Data to a Stream, content-type should be set before this! + /// + /// Stream to write the multipart form data to + /// String boundary for the multipart/form-data + /// Parameters to include in the multipart form data + public static void WriteMultipartFormData(Stream formDataStream, string boundary, IDictionary postParameters) + { + bool needsClrf = false; + foreach (var param in postParameters) + { + // Add a CRLF to allow multiple parameters to be added. + // Skip it on the first parameter, add it to subsequent parameters. + if (needsClrf) + { + formDataStream.Write(Encoding.UTF8.GetBytes("\r\n"), 0, Encoding.UTF8.GetByteCount("\r\n")); + } + + needsClrf = true; + + if (param.Value is IBinaryContainer binaryContainer) + { + binaryContainer.WriteFormDataToStream(boundary, param.Key, formDataStream); + } + else + { + string postData = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{param.Key}\"\r\n\r\n{param.Value}"; + formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData)); + } + } + + // Add the end of the request. Start with a newline + string footer = "\r\n--" + boundary + "--\r\n"; + formDataStream.Write(Encoding.UTF8.GetBytes(footer), 0, Encoding.UTF8.GetByteCount(footer)); + } + + /// + /// Post content HttpWebRequest + /// + /// HttpWebRequest to write the multipart form data to + /// IDictionary with the headers + /// IBinaryContainer + public static void Post(HttpWebRequest webRequest, IDictionary headers, IBinaryContainer binaryContainer = null) + { + foreach (var header in headers) + { + switch (header.Key) + { + case "Content-Type": + webRequest.ContentType = header.Value as string; + break; + case "Accept": + webRequest.Accept = header.Value as string; + break; + default: + webRequest.Headers.Add(header.Key, Convert.ToString(header.Value)); + break; + } + } + + if (!headers.ContainsKey("Content-Type")) + { + webRequest.ContentType = "application/octet-stream"; + } + + if (binaryContainer != null) + { + using var requestStream = webRequest.GetRequestStream(); + binaryContainer.WriteToStream(requestStream); + } + } + + /// + /// Post content HttpWebRequest + /// + /// HttpWebRequest to write the multipart form data to + /// IDictionary with the headers + /// string + public static void Post(HttpWebRequest webRequest, IDictionary headers, string jsonString) + { + if (headers != null) + { + foreach (var header in headers) + { + switch (header.Key) + { + case "Content-Type": + webRequest.ContentType = header.Value as string; + break; + case "Accept": + webRequest.Accept = header.Value as string; + break; + default: + webRequest.Headers.Add(header.Key, Convert.ToString(header.Value)); + break; + } + } + + if (!headers.ContainsKey("Content-Type")) + { + webRequest.ContentType = "application/json"; + } + } + else + { + webRequest.ContentType = "application/json"; + } + + if (jsonString != null) + { + using var requestStream = webRequest.GetRequestStream(); + using var streamWriter = new StreamWriter(requestStream); + streamWriter.Write(jsonString); + } + } + + /// + /// Post the parameters "x-www-form-urlencoded" + /// + /// + /// + public static void UploadFormUrlEncoded(HttpWebRequest webRequest, IDictionary parameters) + { + webRequest.ContentType = "application/x-www-form-urlencoded"; + string urlEncoded = GenerateQueryParameters(parameters); + + byte[] data = Encoding.UTF8.GetBytes(urlEncoded); + using var requestStream = webRequest.GetRequestStream(); + requestStream.Write(data, 0, data.Length); + } + + /// + /// Log the headers of the WebResponse, if IsDebugEnabled + /// + /// WebResponse + private static void DebugHeaders(WebResponse response) + { + if (!Log.IsDebugEnabled) + { + return; + } + + Log.DebugFormat("Debug information on the response from {0} :", response.ResponseUri); + foreach (string key in response.Headers.AllKeys) + { + Log.DebugFormat("Reponse-header: {0}={1}", key, response.Headers[key]); + } + } + + /// + /// Process the web response. + /// + /// The request object. + /// The response data. + /// TODO: This method should handle the StatusCode better! + public static string GetResponseAsString(HttpWebRequest webRequest) + { + return GetResponseAsString(webRequest, false); + } + + /// + /// Read the response as string + /// + /// + /// string or null + private static string GetResponseAsString(HttpWebResponse response) + { + string responseData = null; + if (response == null) + { + return null; + } + + using (response) + { + Stream responseStream = response.GetResponseStream(); + if (responseStream != null) + { + using StreamReader reader = new StreamReader(responseStream, true); + responseData = reader.ReadToEnd(); + } + } + + return responseData; + } + + /// + /// + /// + /// + /// + /// + public static string GetResponseAsString(HttpWebRequest webRequest, bool alsoReturnContentOnError) + { + string responseData = null; + HttpWebResponse response = null; + bool isHttpError = false; + try + { + response = (HttpWebResponse) webRequest.GetResponse(); + Log.InfoFormat("Response status: {0}", response.StatusCode); + isHttpError = (int) response.StatusCode >= 300; + if (isHttpError) + { + Log.ErrorFormat("HTTP error {0}", response.StatusCode); + } + + DebugHeaders(response); + responseData = GetResponseAsString(response); + if (isHttpError) + { + Log.ErrorFormat("HTTP response {0}", responseData); + } + } + catch (WebException e) + { + response = (HttpWebResponse) e.Response; + HttpStatusCode statusCode = HttpStatusCode.Unused; + if (response != null) + { + statusCode = response.StatusCode; + Log.ErrorFormat("HTTP error {0}", statusCode); + string errorContent = GetResponseAsString(response); + if (alsoReturnContentOnError) + { + return errorContent; + } + + Log.ErrorFormat("Content: {0}", errorContent); + } + + Log.Error("WebException: ", e); + if (statusCode == HttpStatusCode.Unauthorized) + { + throw new UnauthorizedAccessException(e.Message); + } + + throw; + } + finally + { + if (response != null) + { + if (isHttpError) + { + Log.ErrorFormat("HTTP error {0} with content: {1}", response.StatusCode, responseData); + } + + response.Close(); + } + } + + return responseData; + } + } + + /// + /// This interface can be used to pass binary information around, like byte[] or Image + /// + public interface IBinaryContainer + { + void WriteFormDataToStream(string boundary, string name, Stream formDataStream); + void WriteToStream(Stream formDataStream); + string ToBase64String(Base64FormattingOptions formattingOptions); + byte[] ToByteArray(); + void Upload(HttpWebRequest webRequest); + + string ContentType { get; } + string Filename { get; set; } + } + + /// A container to supply surfaces to a Multi-part form data upload + /// + public class SurfaceContainer : IBinaryContainer + { + private readonly ISurface _surface; + private readonly SurfaceOutputSettings _outputSettings; + + public SurfaceContainer(ISurface surface, SurfaceOutputSettings outputSettings, string filename) + { + _surface = surface; + _outputSettings = outputSettings; + Filename = filename; + } + + /// + /// Create a Base64String from the Surface by saving it to a memory stream and converting it. + /// Should be avoided if possible, as this uses a lot of memory. + /// + /// string + public string ToBase64String(Base64FormattingOptions formattingOptions) + { + using MemoryStream stream = new MemoryStream(); + ImageOutput.SaveToStream(_surface, stream, _outputSettings); + return Convert.ToBase64String(stream.GetBuffer(), 0, (int) stream.Length, formattingOptions); + } + + /// + /// Create a byte[] from the image by saving it to a memory stream. + /// Should be avoided if possible, as this uses a lot of memory. + /// + /// byte[] + public byte[] ToByteArray() + { + using MemoryStream stream = new MemoryStream(); + ImageOutput.SaveToStream(_surface, stream, _outputSettings); + return stream.ToArray(); + } + + /// + /// Write Multipart Form Data directly to the HttpWebRequest response stream + /// + /// Multipart separator + /// Name of the thing + /// Stream to write to + public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) + { + // Add just the first part of this param, since we will write the file data directly to the Stream + string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n"; + + formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header)); + ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings); + } + + /// + /// A plain "write data to stream" + /// + /// + public void WriteToStream(Stream dataStream) + { + // Write the file data directly to the Stream, rather than serializing it to a string. + ImageOutput.SaveToStream(_surface, dataStream, _outputSettings); + } + + /// + /// Upload the Surface as image to the webrequest + /// + /// + public void Upload(HttpWebRequest webRequest) + { + webRequest.ContentType = ContentType; + using var requestStream = webRequest.GetRequestStream(); + WriteToStream(requestStream); + } + + public string ContentType => "image/" + _outputSettings.Format; + public string Filename { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs b/src/Greenshot.Base/Core/OAuth/LocalJsonReceiver.cs similarity index 99% rename from src/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs rename to src/Greenshot.Base/Core/OAuth/LocalJsonReceiver.cs index d837e85c0..c99221d09 100644 --- a/src/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs +++ b/src/Greenshot.Base/Core/OAuth/LocalJsonReceiver.cs @@ -30,7 +30,7 @@ using System.Threading; using log4net; using Newtonsoft.Json; -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// OAuth 2.0 verification code receiver that runs a local server on a free port diff --git a/src/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs b/src/Greenshot.Base/Core/OAuth/LocalServerCodeReceiver.cs similarity index 99% rename from src/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs rename to src/Greenshot.Base/Core/OAuth/LocalServerCodeReceiver.cs index 1bc9670c7..702e3f7fe 100644 --- a/src/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs +++ b/src/Greenshot.Base/Core/OAuth/LocalServerCodeReceiver.cs @@ -29,7 +29,7 @@ using System.Text; using System.Threading; using log4net; -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// OAuth 2.0 verification code receiver that runs a local server on a free port diff --git a/src/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs b/src/Greenshot.Base/Core/OAuth/OAuth2AuthorizeMode.cs similarity index 97% rename from src/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs rename to src/Greenshot.Base/Core/OAuth/OAuth2AuthorizeMode.cs index ed391d9a8..1d761fc96 100644 --- a/src/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs +++ b/src/Greenshot.Base/Core/OAuth/OAuth2AuthorizeMode.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// Specify the authorize mode that is used to get the token from the cloud service. diff --git a/src/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs b/src/Greenshot.Base/Core/OAuth/OAuth2Helper.cs similarity index 99% rename from src/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs rename to src/Greenshot.Base/Core/OAuth/OAuth2Helper.cs index 36704a055..e5d009b96 100644 --- a/src/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs +++ b/src/Greenshot.Base/Core/OAuth/OAuth2Helper.cs @@ -23,9 +23,9 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Net; -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// Code to simplify OAuth 2 diff --git a/src/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs b/src/Greenshot.Base/Core/OAuth/OAuth2Settings.cs similarity index 99% rename from src/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs rename to src/Greenshot.Base/Core/OAuth/OAuth2Settings.cs index d008c6b5b..c4fb6d2e2 100644 --- a/src/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs +++ b/src/Greenshot.Base/Core/OAuth/OAuth2Settings.cs @@ -23,7 +23,7 @@ using System; using System.Collections.Generic; using System.Drawing; -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// Settings for the OAuth 2 protocol diff --git a/src/GreenshotPlugin/Core/OAuth/OAuthSession.cs b/src/Greenshot.Base/Core/OAuth/OAuthSession.cs similarity index 99% rename from src/GreenshotPlugin/Core/OAuth/OAuthSession.cs rename to src/Greenshot.Base/Core/OAuth/OAuthSession.cs index aedff7fe2..f8364df8e 100644 --- a/src/GreenshotPlugin/Core/OAuth/OAuthSession.cs +++ b/src/Greenshot.Base/Core/OAuth/OAuthSession.cs @@ -27,10 +27,10 @@ using System.Net; using System.Security.Cryptography; using System.Text; using System.Threading; -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; using log4net; -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// An OAuth 1 session object diff --git a/src/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs b/src/Greenshot.Base/Core/OAuth/OAuthSignatureTypes.cs similarity index 96% rename from src/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs rename to src/Greenshot.Base/Core/OAuth/OAuthSignatureTypes.cs index 6b07f2de2..eeca8decd 100644 --- a/src/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs +++ b/src/Greenshot.Base/Core/OAuth/OAuthSignatureTypes.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// Provides a predefined set of algorithms that are supported officially by the OAuth 1.x protocol diff --git a/src/GreenshotPlugin/Core/ObjectExtensions.cs b/src/Greenshot.Base/Core/ObjectExtensions.cs similarity index 96% rename from src/GreenshotPlugin/Core/ObjectExtensions.cs rename to src/Greenshot.Base/Core/ObjectExtensions.cs index 5a47a3d08..297015824 100644 --- a/src/GreenshotPlugin/Core/ObjectExtensions.cs +++ b/src/Greenshot.Base/Core/ObjectExtensions.cs @@ -1,118 +1,118 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; - -namespace GreenshotPlugin.Core -{ - /// - /// Extension methods which work for objects - /// - public static class ObjectExtensions - { - /// - /// Perform a deep Copy of the object. - /// - /// The type of object being copied. - /// The object instance to copy. - /// The copied object. - public static T Clone(this T source) - { - var typeparam = typeof(T); - if (!typeparam.IsInterface && !typeparam.IsSerializable) - { - throw new ArgumentException("The type must be serializable.", nameof(source)); - } - - // Don't serialize a null object, simply return the default for that object - if (source == null) - { - return default; - } - - IFormatter formatter = new BinaryFormatter(); - using var stream = new MemoryStream(); - formatter.Serialize(stream, source); - stream.Seek(0, SeekOrigin.Begin); - return (T) formatter.Deserialize(stream); - } - - /// - /// Clone the content from source to destination - /// - /// Type to clone - /// Instance to copy from - /// Instance to copy to - public static void CloneTo(this T source, T destination) - { - var type = typeof(T); - var myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - - foreach (var fieldInfo in myObjectFields) - { - fieldInfo.SetValue(destination, fieldInfo.GetValue(source)); - } - - var myObjectProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - - foreach (var propertyInfo in myObjectProperties) - { - if (propertyInfo.CanWrite) - { - propertyInfo.SetValue(destination, propertyInfo.GetValue(source, null), null); - } - } - } - - /// - /// Compare two lists - /// - /// - /// IList - /// IList - /// true if they are the same - public static bool CompareLists(IList l1, IList l2) - { - if (l1.Count != l2.Count) - { - return false; - } - - int matched = 0; - foreach (T item in l1) - { - if (!l2.Contains(item)) - { - return false; - } - - matched++; - } - - return matched == l1.Count; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; + +namespace Greenshot.Base.Core +{ + /// + /// Extension methods which work for objects + /// + public static class ObjectExtensions + { + /// + /// Perform a deep Copy of the object. + /// + /// The type of object being copied. + /// The object instance to copy. + /// The copied object. + public static T Clone(this T source) + { + var typeparam = typeof(T); + if (!typeparam.IsInterface && !typeparam.IsSerializable) + { + throw new ArgumentException("The type must be serializable.", nameof(source)); + } + + // Don't serialize a null object, simply return the default for that object + if (source == null) + { + return default; + } + + IFormatter formatter = new BinaryFormatter(); + using var stream = new MemoryStream(); + formatter.Serialize(stream, source); + stream.Seek(0, SeekOrigin.Begin); + return (T) formatter.Deserialize(stream); + } + + /// + /// Clone the content from source to destination + /// + /// Type to clone + /// Instance to copy from + /// Instance to copy to + public static void CloneTo(this T source, T destination) + { + var type = typeof(T); + var myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + + foreach (var fieldInfo in myObjectFields) + { + fieldInfo.SetValue(destination, fieldInfo.GetValue(source)); + } + + var myObjectProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + + foreach (var propertyInfo in myObjectProperties) + { + if (propertyInfo.CanWrite) + { + propertyInfo.SetValue(destination, propertyInfo.GetValue(source, null), null); + } + } + } + + /// + /// Compare two lists + /// + /// + /// IList + /// IList + /// true if they are the same + public static bool CompareLists(IList l1, IList l2) + { + if (l1.Count != l2.Count) + { + return false; + } + + int matched = 0; + foreach (T item in l1) + { + if (!l2.Contains(item)) + { + return false; + } + + matched++; + } + + return matched == l1.Count; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/PluginUtils.cs b/src/Greenshot.Base/Core/PluginUtils.cs similarity index 96% rename from src/GreenshotPlugin/Core/PluginUtils.cs rename to src/Greenshot.Base/Core/PluginUtils.cs index 870e2cca7..34fcba5d9 100644 --- a/src/GreenshotPlugin/Core/PluginUtils.cs +++ b/src/Greenshot.Base/Core/PluginUtils.cs @@ -1,228 +1,228 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.UnmanagedHelpers; -using log4net; -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.IO; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; - -namespace GreenshotPlugin.Core -{ - /// - /// Description of PluginUtils. - /// - public static class PluginUtils - { - private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\"; - private static readonly IDictionary ExeIconCache = new Dictionary(); - - static PluginUtils() - { - CoreConfig.PropertyChanged += OnIconSizeChanged; - } - - /// - /// Clear icon cache - /// - /// - /// - private static void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName != "IconSize") return; - var cachedImages = new List(); - lock (ExeIconCache) - { - foreach (string key in ExeIconCache.Keys) - { - cachedImages.Add(ExeIconCache[key]); - } - - ExeIconCache.Clear(); - } - - foreach (Image cachedImage in cachedImages) - { - cachedImage?.Dispose(); - } - } - - /// - /// Get the path of an executable - /// - /// e.g. cmd.exe - /// Path to file - public static string GetExePath(string exeName) - { - using (var key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) - { - if (key != null) - { - // "" is the default key, which should point to the requested location - return (string) key.GetValue(string.Empty); - } - } - - foreach (string pathEntry in (Environment.GetEnvironmentVariable("PATH") ?? string.Empty).Split(';')) - { - try - { - string path = pathEntry.Trim(); - if (!string.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exeName))) - { - return Path.GetFullPath(path); - } - } - catch (Exception) - { - Log.WarnFormat("Problem with path entry '{0}'.", pathEntry); - } - } - - return null; - } - - /// - /// Get icon from resource files, from the cache. - /// Examples can be found here: https://diymediahome.org/windows-icons-reference-list-with-details-locations-images/ - /// - /// path to the exe or dll - /// index of the icon - /// Bitmap with the icon or null if something happended - public static Image GetCachedExeIcon(string path, int index) - { - string cacheKey = $"{path}:{index}"; - Image returnValue; - lock (ExeIconCache) - { - if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) - { - return returnValue; - } - - lock (ExeIconCache) - { - if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) - { - return returnValue; - } - - returnValue = GetExeIcon(path, index); - if (returnValue != null) - { - ExeIconCache.Add(cacheKey, returnValue); - } - } - } - - return returnValue; - } - - /// - /// Get icon for executable - /// - /// path to the exe or dll - /// index of the icon - /// Bitmap with the icon or null if something happended - private static Bitmap GetExeIcon(string path, int index) - { - if (!File.Exists(path)) - { - return null; - } - - try - { - using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) - { - if (appIcon != null) - { - return appIcon.ToBitmap(); - } - } - - using (Icon appIcon = Shell32.GetFileIcon(path, CoreConfig.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false)) - { - if (appIcon != null) - { - return appIcon.ToBitmap(); - } - } - } - catch (Exception exIcon) - { - Log.Error("error retrieving icon: ", exIcon); - } - - return null; - } - - /// - /// Helper method to add a plugin MenuItem to the Greenshot context menu - /// - /// ToolStripMenuItem - public static void AddToContextMenu(ToolStripMenuItem item) - { - // Here we can hang ourselves to the main context menu! - var contextMenu = SimpleServiceProvider.Current.GetInstance(); - bool addedItem = false; - - // Try to find a separator, so we insert ourselves after it - for (int i = 0; i < contextMenu.Items.Count; i++) - { - if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) - { - // Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore" - if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag)) - { - var separator = new ToolStripSeparator - { - Tag = "PluginsAreAddedAfter", - Size = new Size(305, 6) - }; - contextMenu.Items.Insert(i, separator); - } - else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag)) - { - continue; - } - - contextMenu.Items.Insert(i + 1, item); - addedItem = true; - break; - } - } - - // If we didn't insert the item, we just add it... - if (!addedItem) - { - contextMenu.Items.Add(item); - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.UnmanagedHelpers; +using log4net; +using Microsoft.Win32; + +namespace Greenshot.Base.Core +{ + /// + /// Description of PluginUtils. + /// + public static class PluginUtils + { + private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\"; + private static readonly IDictionary ExeIconCache = new Dictionary(); + + static PluginUtils() + { + CoreConfig.PropertyChanged += OnIconSizeChanged; + } + + /// + /// Clear icon cache + /// + /// + /// + private static void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != "IconSize") return; + var cachedImages = new List(); + lock (ExeIconCache) + { + foreach (string key in ExeIconCache.Keys) + { + cachedImages.Add(ExeIconCache[key]); + } + + ExeIconCache.Clear(); + } + + foreach (Image cachedImage in cachedImages) + { + cachedImage?.Dispose(); + } + } + + /// + /// Get the path of an executable + /// + /// e.g. cmd.exe + /// Path to file + public static string GetExePath(string exeName) + { + using (var key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) + { + if (key != null) + { + // "" is the default key, which should point to the requested location + return (string) key.GetValue(string.Empty); + } + } + + foreach (string pathEntry in (Environment.GetEnvironmentVariable("PATH") ?? string.Empty).Split(';')) + { + try + { + string path = pathEntry.Trim(); + if (!string.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exeName))) + { + return Path.GetFullPath(path); + } + } + catch (Exception) + { + Log.WarnFormat("Problem with path entry '{0}'.", pathEntry); + } + } + + return null; + } + + /// + /// Get icon from resource files, from the cache. + /// Examples can be found here: https://diymediahome.org/windows-icons-reference-list-with-details-locations-images/ + /// + /// path to the exe or dll + /// index of the icon + /// Bitmap with the icon or null if something happended + public static Image GetCachedExeIcon(string path, int index) + { + string cacheKey = $"{path}:{index}"; + Image returnValue; + lock (ExeIconCache) + { + if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) + { + return returnValue; + } + + lock (ExeIconCache) + { + if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) + { + return returnValue; + } + + returnValue = GetExeIcon(path, index); + if (returnValue != null) + { + ExeIconCache.Add(cacheKey, returnValue); + } + } + } + + return returnValue; + } + + /// + /// Get icon for executable + /// + /// path to the exe or dll + /// index of the icon + /// Bitmap with the icon or null if something happended + private static Bitmap GetExeIcon(string path, int index) + { + if (!File.Exists(path)) + { + return null; + } + + try + { + using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) + { + if (appIcon != null) + { + return appIcon.ToBitmap(); + } + } + + using (Icon appIcon = Shell32.GetFileIcon(path, CoreConfig.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false)) + { + if (appIcon != null) + { + return appIcon.ToBitmap(); + } + } + } + catch (Exception exIcon) + { + Log.Error("error retrieving icon: ", exIcon); + } + + return null; + } + + /// + /// Helper method to add a plugin MenuItem to the Greenshot context menu + /// + /// ToolStripMenuItem + public static void AddToContextMenu(ToolStripMenuItem item) + { + // Here we can hang ourselves to the main context menu! + var contextMenu = SimpleServiceProvider.Current.GetInstance(); + bool addedItem = false; + + // Try to find a separator, so we insert ourselves after it + for (int i = 0; i < contextMenu.Items.Count; i++) + { + if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) + { + // Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore" + if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag)) + { + var separator = new ToolStripSeparator + { + Tag = "PluginsAreAddedAfter", + Size = new Size(305, 6) + }; + contextMenu.Items.Insert(i, separator); + } + else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag)) + { + continue; + } + + contextMenu.Items.Insert(i + 1, item); + addedItem = true; + break; + } + } + + // If we didn't insert the item, we just add it... + if (!addedItem) + { + contextMenu.Items.Add(item); + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/QuantizerHelper.cs b/src/Greenshot.Base/Core/QuantizerHelper.cs similarity index 97% rename from src/GreenshotPlugin/Core/QuantizerHelper.cs rename to src/Greenshot.Base/Core/QuantizerHelper.cs index 91296005d..9ae5211a1 100644 --- a/src/GreenshotPlugin/Core/QuantizerHelper.cs +++ b/src/Greenshot.Base/Core/QuantizerHelper.cs @@ -1,771 +1,771 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; -using log4net; - -namespace GreenshotPlugin.Core -{ - internal class WuColorCube - { - /// - /// Gets or sets the red minimum. - /// - /// The red minimum. - public int RedMinimum { get; set; } - - /// - /// Gets or sets the red maximum. - /// - /// The red maximum. - public int RedMaximum { get; set; } - - /// - /// Gets or sets the green minimum. - /// - /// The green minimum. - public int GreenMinimum { get; set; } - - /// - /// Gets or sets the green maximum. - /// - /// The green maximum. - public int GreenMaximum { get; set; } - - /// - /// Gets or sets the blue minimum. - /// - /// The blue minimum. - public int BlueMinimum { get; set; } - - /// - /// Gets or sets the blue maximum. - /// - /// The blue maximum. - public int BlueMaximum { get; set; } - - /// - /// Gets or sets the cube volume. - /// - /// The volume. - public int Volume { get; set; } - } - - public class WuQuantizer : IDisposable - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(WuQuantizer)); - - private const int MAXCOLOR = 512; - private const int RED = 2; - private const int GREEN = 1; - private const int BLUE = 0; - private const int SIDESIZE = 33; - private const int MAXSIDEINDEX = 32; - private const int MAXVOLUME = SIDESIZE * SIDESIZE * SIDESIZE; - - // To count the colors - private readonly int colorCount; - - private int[] reds; - private int[] greens; - private int[] blues; - private int[] sums; - - private readonly long[,,] weights; - private readonly long[,,] momentsRed; - private readonly long[,,] momentsGreen; - private readonly long[,,] momentsBlue; - private readonly float[,,] moments; - - private byte[] tag; - - private readonly WuColorCube[] cubes; - private readonly Bitmap sourceBitmap; - private Bitmap resultBitmap; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - if (resultBitmap != null) - { - resultBitmap.Dispose(); - resultBitmap = null; - } - } - } - - /// - /// See for more details. - /// - public WuQuantizer(Bitmap sourceBitmap) - { - this.sourceBitmap = sourceBitmap; - // Make sure the color count variables are reset - BitArray bitArray = new BitArray((int) Math.Pow(2, 24)); - colorCount = 0; - - // creates all the cubes - cubes = new WuColorCube[MAXCOLOR]; - - // initializes all the cubes - for (int cubeIndex = 0; cubeIndex < MAXCOLOR; cubeIndex++) - { - cubes[cubeIndex] = new WuColorCube(); - } - - // resets the reference minimums - cubes[0].RedMinimum = 0; - cubes[0].GreenMinimum = 0; - cubes[0].BlueMinimum = 0; - - // resets the reference maximums - cubes[0].RedMaximum = MAXSIDEINDEX; - cubes[0].GreenMaximum = MAXSIDEINDEX; - cubes[0].BlueMaximum = MAXSIDEINDEX; - - weights = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - momentsRed = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - momentsGreen = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - momentsBlue = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - moments = new float[SIDESIZE, SIDESIZE, SIDESIZE]; - - int[] table = new int[256]; - - for (int tableIndex = 0; tableIndex < 256; ++tableIndex) - { - table[tableIndex] = tableIndex * tableIndex; - } - - // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage - using IFastBitmap sourceFastBitmap = FastBitmap.Create(sourceBitmap); - IFastBitmapWithBlend sourceFastBitmapWithBlend = sourceFastBitmap as IFastBitmapWithBlend; - sourceFastBitmap.Lock(); - using FastChunkyBitmap destinationFastBitmap = FastBitmap.CreateEmpty(sourceBitmap.Size, PixelFormat.Format8bppIndexed, Color.White) as FastChunkyBitmap; - destinationFastBitmap.Lock(); - for (int y = 0; y < sourceFastBitmap.Height; y++) - { - for (int x = 0; x < sourceFastBitmap.Width; x++) - { - Color color; - if (sourceFastBitmapWithBlend == null) - { - color = sourceFastBitmap.GetColorAt(x, y); - } - else - { - color = sourceFastBitmapWithBlend.GetBlendedColorAt(x, y); - } - - // To count the colors - int index = color.ToArgb() & 0x00ffffff; - // Check if we already have this color - if (!bitArray.Get(index)) - { - // If not, add 1 to the single colors - colorCount++; - bitArray.Set(index, true); - } - - int indexRed = (color.R >> 3) + 1; - int indexGreen = (color.G >> 3) + 1; - int indexBlue = (color.B >> 3) + 1; - - weights[indexRed, indexGreen, indexBlue]++; - momentsRed[indexRed, indexGreen, indexBlue] += color.R; - momentsGreen[indexRed, indexGreen, indexBlue] += color.G; - momentsBlue[indexRed, indexGreen, indexBlue] += color.B; - moments[indexRed, indexGreen, indexBlue] += table[color.R] + table[color.G] + table[color.B]; - - // Store the initial "match" - int paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue; - destinationFastBitmap.SetColorIndexAt(x, y, (byte) (paletteIndex & 0xff)); - } - } - - resultBitmap = destinationFastBitmap.UnlockAndReturnBitmap(); - } - - /// - /// See for more details. - /// - public int GetColorCount() - { - return colorCount; - } - - /// - /// Reindex the 24/32 BPP (A)RGB image to a 8BPP - /// - /// Bitmap - public Bitmap SimpleReindex() - { - List colors = new List(); - Dictionary lookup = new Dictionary(); - using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) - { - bbbDest.Lock(); - using IFastBitmap bbbSrc = FastBitmap.Create(sourceBitmap); - IFastBitmapWithBlend bbbSrcBlend = bbbSrc as IFastBitmapWithBlend; - - bbbSrc.Lock(); - byte index; - for (int y = 0; y < bbbSrc.Height; y++) - { - for (int x = 0; x < bbbSrc.Width; x++) - { - Color color; - if (bbbSrcBlend != null) - { - color = bbbSrcBlend.GetBlendedColorAt(x, y); - } - else - { - color = bbbSrc.GetColorAt(x, y); - } - - if (lookup.ContainsKey(color)) - { - index = lookup[color]; - } - else - { - colors.Add(color); - index = (byte) (colors.Count - 1); - lookup.Add(color, index); - } - - bbbDest.SetColorIndexAt(x, y, index); - } - } - } - - // generates palette - ColorPalette imagePalette = resultBitmap.Palette; - Color[] entries = imagePalette.Entries; - for (int paletteIndex = 0; paletteIndex < 256; paletteIndex++) - { - if (paletteIndex < colorCount) - { - entries[paletteIndex] = colors[paletteIndex]; - } - else - { - entries[paletteIndex] = Color.Black; - } - } - - resultBitmap.Palette = imagePalette; - - // Make sure the bitmap is not disposed, as we return it. - Bitmap tmpBitmap = resultBitmap; - resultBitmap = null; - return tmpBitmap; - } - - /// - /// Get the image - /// - public Bitmap GetQuantizedImage(int allowedColorCount) - { - if (allowedColorCount > 256) - { - throw new ArgumentOutOfRangeException(nameof(allowedColorCount), "Quantizing muss be done to get less than 256 colors"); - } - - if (colorCount < allowedColorCount) - { - // Simple logic to reduce to 8 bit - LOG.Info("Colors in the image are already less as whished for, using simple copy to indexed image, no quantizing needed!"); - return SimpleReindex(); - } - - // preprocess the colors - CalculateMoments(); - LOG.Info("Calculated the moments..."); - int next = 0; - float[] volumeVariance = new float[MAXCOLOR]; - - // processes the cubes - for (int cubeIndex = 1; cubeIndex < allowedColorCount; ++cubeIndex) - { - // if cut is possible; make it - if (Cut(cubes[next], cubes[cubeIndex])) - { - volumeVariance[next] = cubes[next].Volume > 1 ? CalculateVariance(cubes[next]) : 0.0f; - volumeVariance[cubeIndex] = cubes[cubeIndex].Volume > 1 ? CalculateVariance(cubes[cubeIndex]) : 0.0f; - } - else - { - // the cut was not possible, revert the index - volumeVariance[next] = 0.0f; - cubeIndex--; - } - - next = 0; - float temp = volumeVariance[0]; - - for (int index = 1; index <= cubeIndex; ++index) - { - if (volumeVariance[index] > temp) - { - temp = volumeVariance[index]; - next = index; - } - } - - if (temp <= 0.0) - { - allowedColorCount = cubeIndex + 1; - break; - } - } - - int[] lookupRed = new int[MAXCOLOR]; - int[] lookupGreen = new int[MAXCOLOR]; - int[] lookupBlue = new int[MAXCOLOR]; - - tag = new byte[MAXVOLUME]; - - // precalculates lookup tables - for (int k = 0; k < allowedColorCount; ++k) - { - Mark(cubes[k], k, tag); - - long weight = Volume(cubes[k], weights); - - if (weight > 0) - { - lookupRed[k] = (int) (Volume(cubes[k], momentsRed) / weight); - lookupGreen[k] = (int) (Volume(cubes[k], momentsGreen) / weight); - lookupBlue[k] = (int) (Volume(cubes[k], momentsBlue) / weight); - } - else - { - lookupRed[k] = 0; - lookupGreen[k] = 0; - lookupBlue[k] = 0; - } - } - - reds = new int[allowedColorCount + 1]; - greens = new int[allowedColorCount + 1]; - blues = new int[allowedColorCount + 1]; - sums = new int[allowedColorCount + 1]; - - LOG.Info("Starting bitmap reconstruction..."); - - using (FastChunkyBitmap dest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) - { - using IFastBitmap src = FastBitmap.Create(sourceBitmap); - IFastBitmapWithBlend srcBlend = src as IFastBitmapWithBlend; - Dictionary lookup = new Dictionary(); - for (int y = 0; y < src.Height; y++) - { - for (int x = 0; x < src.Width; x++) - { - Color color; - if (srcBlend != null) - { - // WithoutAlpha, this makes it possible to ignore the alpha - color = srcBlend.GetBlendedColorAt(x, y); - } - else - { - color = src.GetColorAt(x, y); - } - - // Check if we already matched the color - byte bestMatch; - if (!lookup.ContainsKey(color)) - { - // If not we need to find the best match - - // First get initial match - bestMatch = dest.GetColorIndexAt(x, y); - bestMatch = tag[bestMatch]; - - int bestDistance = 100000000; - for (int lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++) - { - int foundRed = lookupRed[lookupIndex]; - int foundGreen = lookupGreen[lookupIndex]; - int foundBlue = lookupBlue[lookupIndex]; - int deltaRed = color.R - foundRed; - int deltaGreen = color.G - foundGreen; - int deltaBlue = color.B - foundBlue; - - int distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue; - - if (distance < bestDistance) - { - bestDistance = distance; - bestMatch = (byte) lookupIndex; - } - } - - lookup.Add(color, bestMatch); - } - else - { - // Already matched, so we just use the lookup - bestMatch = lookup[color]; - } - - reds[bestMatch] += color.R; - greens[bestMatch] += color.G; - blues[bestMatch] += color.B; - sums[bestMatch]++; - - dest.SetColorIndexAt(x, y, bestMatch); - } - } - } - - - // generates palette - ColorPalette imagePalette = resultBitmap.Palette; - Color[] entries = imagePalette.Entries; - for (int paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++) - { - if (sums[paletteIndex] > 0) - { - reds[paletteIndex] /= sums[paletteIndex]; - greens[paletteIndex] /= sums[paletteIndex]; - blues[paletteIndex] /= sums[paletteIndex]; - } - - entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]); - } - - resultBitmap.Palette = imagePalette; - - // Make sure the bitmap is not disposed, as we return it. - Bitmap tmpBitmap = resultBitmap; - resultBitmap = null; - return tmpBitmap; - } - - /// - /// Converts the histogram to a series of moments. - /// - private void CalculateMoments() - { - long[] area = new long[SIDESIZE]; - long[] areaRed = new long[SIDESIZE]; - long[] areaGreen = new long[SIDESIZE]; - long[] areaBlue = new long[SIDESIZE]; - float[] area2 = new float[SIDESIZE]; - - for (int redIndex = 1; redIndex <= MAXSIDEINDEX; ++redIndex) - { - for (int index = 0; index <= MAXSIDEINDEX; ++index) - { - area[index] = 0; - areaRed[index] = 0; - areaGreen[index] = 0; - areaBlue[index] = 0; - area2[index] = 0; - } - - for (int greenIndex = 1; greenIndex <= MAXSIDEINDEX; ++greenIndex) - { - long line = 0; - long lineRed = 0; - long lineGreen = 0; - long lineBlue = 0; - float line2 = 0.0f; - - for (int blueIndex = 1; blueIndex <= MAXSIDEINDEX; ++blueIndex) - { - line += weights[redIndex, greenIndex, blueIndex]; - lineRed += momentsRed[redIndex, greenIndex, blueIndex]; - lineGreen += momentsGreen[redIndex, greenIndex, blueIndex]; - lineBlue += momentsBlue[redIndex, greenIndex, blueIndex]; - line2 += moments[redIndex, greenIndex, blueIndex]; - - area[blueIndex] += line; - areaRed[blueIndex] += lineRed; - areaGreen[blueIndex] += lineGreen; - areaBlue[blueIndex] += lineBlue; - area2[blueIndex] += line2; - - weights[redIndex, greenIndex, blueIndex] = weights[redIndex - 1, greenIndex, blueIndex] + area[blueIndex]; - momentsRed[redIndex, greenIndex, blueIndex] = momentsRed[redIndex - 1, greenIndex, blueIndex] + areaRed[blueIndex]; - momentsGreen[redIndex, greenIndex, blueIndex] = momentsGreen[redIndex - 1, greenIndex, blueIndex] + areaGreen[blueIndex]; - momentsBlue[redIndex, greenIndex, blueIndex] = momentsBlue[redIndex - 1, greenIndex, blueIndex] + areaBlue[blueIndex]; - moments[redIndex, greenIndex, blueIndex] = moments[redIndex - 1, greenIndex, blueIndex] + area2[blueIndex]; - } - } - } - } - - /// - /// Computes the volume of the cube in a specific moment. - /// - private static long Volume(WuColorCube cube, long[,,] moment) - { - return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - - moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; - } - - /// - /// Computes the volume of the cube in a specific moment. For the floating-point values. - /// - private static float VolumeFloat(WuColorCube cube, float[,,] moment) - { - return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - - moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; - } - - /// - /// Splits the cube in given position, and color direction. - /// - private static long Top(WuColorCube cube, int direction, int position, long[,,] moment) - { - return direction switch - { - RED => (moment[position, cube.GreenMaximum, cube.BlueMaximum] - - moment[position, cube.GreenMaximum, cube.BlueMinimum] - - moment[position, cube.GreenMinimum, cube.BlueMaximum] + - moment[position, cube.GreenMinimum, cube.BlueMinimum]), - GREEN => (moment[cube.RedMaximum, position, cube.BlueMaximum] - - moment[cube.RedMaximum, position, cube.BlueMinimum] - - moment[cube.RedMinimum, position, cube.BlueMaximum] + - moment[cube.RedMinimum, position, cube.BlueMinimum]), - BLUE => (moment[cube.RedMaximum, cube.GreenMaximum, position] - - moment[cube.RedMaximum, cube.GreenMinimum, position] - - moment[cube.RedMinimum, cube.GreenMaximum, position] + - moment[cube.RedMinimum, cube.GreenMinimum, position]), - _ => 0, - }; - } - - /// - /// Splits the cube in a given color direction at its minimum. - /// - private static long Bottom(WuColorCube cube, int direction, long[,,] moment) - { - return direction switch - { - RED => (-moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), - GREEN => (-moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), - BLUE => (-moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] + - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), - _ => 0 - }; - } - - /// - /// Calculates statistical variance for a given cube. - /// - private float CalculateVariance(WuColorCube cube) - { - float volumeRed = Volume(cube, momentsRed); - float volumeGreen = Volume(cube, momentsGreen); - float volumeBlue = Volume(cube, momentsBlue); - float volumeMoment = VolumeFloat(cube, moments); - float volumeWeight = Volume(cube, weights); - - float distance = volumeRed * volumeRed + volumeGreen * volumeGreen + volumeBlue * volumeBlue; - - return volumeMoment - (distance / volumeWeight); - } - - /// - /// Finds the optimal (maximal) position for the cut. - /// - private float Maximize(WuColorCube cube, int direction, int first, int last, int[] cut, long wholeRed, long wholeGreen, long wholeBlue, long wholeWeight) - { - long bottomRed = Bottom(cube, direction, momentsRed); - long bottomGreen = Bottom(cube, direction, momentsGreen); - long bottomBlue = Bottom(cube, direction, momentsBlue); - long bottomWeight = Bottom(cube, direction, weights); - - float result = 0.0f; - cut[0] = -1; - - for (int position = first; position < last; ++position) - { - // determines the cube cut at a certain position - long halfRed = bottomRed + Top(cube, direction, position, momentsRed); - long halfGreen = bottomGreen + Top(cube, direction, position, momentsGreen); - long halfBlue = bottomBlue + Top(cube, direction, position, momentsBlue); - long halfWeight = bottomWeight + Top(cube, direction, position, weights); - - // the cube cannot be cut at bottom (this would lead to empty cube) - if (halfWeight != 0) - { - float halfDistance = (float) halfRed * halfRed + (float) halfGreen * halfGreen + (float) halfBlue * halfBlue; - float temp = halfDistance / halfWeight; - - halfRed = wholeRed - halfRed; - halfGreen = wholeGreen - halfGreen; - halfBlue = wholeBlue - halfBlue; - halfWeight = wholeWeight - halfWeight; - - if (halfWeight != 0) - { - halfDistance = (float) halfRed * halfRed + (float) halfGreen * halfGreen + (float) halfBlue * halfBlue; - temp += halfDistance / halfWeight; - - if (temp > result) - { - result = temp; - cut[0] = position; - } - } - } - } - - return result; - } - - /// - /// Cuts a cube with another one. - /// - private bool Cut(WuColorCube first, WuColorCube second) - { - int direction; - - int[] cutRed = - { - 0 - }; - int[] cutGreen = - { - 0 - }; - int[] cutBlue = - { - 0 - }; - - long wholeRed = Volume(first, momentsRed); - long wholeGreen = Volume(first, momentsGreen); - long wholeBlue = Volume(first, momentsBlue); - long wholeWeight = Volume(first, weights); - - float maxRed = Maximize(first, RED, first.RedMinimum + 1, first.RedMaximum, cutRed, wholeRed, wholeGreen, wholeBlue, wholeWeight); - float maxGreen = Maximize(first, GREEN, first.GreenMinimum + 1, first.GreenMaximum, cutGreen, wholeRed, wholeGreen, wholeBlue, wholeWeight); - float maxBlue = Maximize(first, BLUE, first.BlueMinimum + 1, first.BlueMaximum, cutBlue, wholeRed, wholeGreen, wholeBlue, wholeWeight); - - if ((maxRed >= maxGreen) && (maxRed >= maxBlue)) - { - direction = RED; - - // cannot split empty cube - if (cutRed[0] < 0) return false; - } - else - { - if ((maxGreen >= maxRed) && (maxGreen >= maxBlue)) - { - direction = GREEN; - } - else - { - direction = BLUE; - } - } - - second.RedMaximum = first.RedMaximum; - second.GreenMaximum = first.GreenMaximum; - second.BlueMaximum = first.BlueMaximum; - - // cuts in a certain direction - switch (direction) - { - case RED: - second.RedMinimum = first.RedMaximum = cutRed[0]; - second.GreenMinimum = first.GreenMinimum; - second.BlueMinimum = first.BlueMinimum; - break; - - case GREEN: - second.GreenMinimum = first.GreenMaximum = cutGreen[0]; - second.RedMinimum = first.RedMinimum; - second.BlueMinimum = first.BlueMinimum; - break; - - case BLUE: - second.BlueMinimum = first.BlueMaximum = cutBlue[0]; - second.RedMinimum = first.RedMinimum; - second.GreenMinimum = first.GreenMinimum; - break; - } - - // determines the volumes after cut - first.Volume = (first.RedMaximum - first.RedMinimum) * (first.GreenMaximum - first.GreenMinimum) * (first.BlueMaximum - first.BlueMinimum); - second.Volume = (second.RedMaximum - second.RedMinimum) * (second.GreenMaximum - second.GreenMinimum) * (second.BlueMaximum - second.BlueMinimum); - - // the cut was successfull - return true; - } - - /// - /// Marks all the tags with a given label. - /// - private void Mark(WuColorCube cube, int label, byte[] tag) - { - for (int redIndex = cube.RedMinimum + 1; redIndex <= cube.RedMaximum; ++redIndex) - { - for (int greenIndex = cube.GreenMinimum + 1; greenIndex <= cube.GreenMaximum; ++greenIndex) - { - for (int blueIndex = cube.BlueMinimum + 1; blueIndex <= cube.BlueMaximum; ++blueIndex) - { - tag[(redIndex << 10) + (redIndex << 6) + redIndex + (greenIndex << 5) + greenIndex + blueIndex] = (byte) label; - } - } - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using log4net; + +namespace Greenshot.Base.Core +{ + internal class WuColorCube + { + /// + /// Gets or sets the red minimum. + /// + /// The red minimum. + public int RedMinimum { get; set; } + + /// + /// Gets or sets the red maximum. + /// + /// The red maximum. + public int RedMaximum { get; set; } + + /// + /// Gets or sets the green minimum. + /// + /// The green minimum. + public int GreenMinimum { get; set; } + + /// + /// Gets or sets the green maximum. + /// + /// The green maximum. + public int GreenMaximum { get; set; } + + /// + /// Gets or sets the blue minimum. + /// + /// The blue minimum. + public int BlueMinimum { get; set; } + + /// + /// Gets or sets the blue maximum. + /// + /// The blue maximum. + public int BlueMaximum { get; set; } + + /// + /// Gets or sets the cube volume. + /// + /// The volume. + public int Volume { get; set; } + } + + public class WuQuantizer : IDisposable + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(WuQuantizer)); + + private const int MAXCOLOR = 512; + private const int RED = 2; + private const int GREEN = 1; + private const int BLUE = 0; + private const int SIDESIZE = 33; + private const int MAXSIDEINDEX = 32; + private const int MAXVOLUME = SIDESIZE * SIDESIZE * SIDESIZE; + + // To count the colors + private readonly int colorCount; + + private int[] reds; + private int[] greens; + private int[] blues; + private int[] sums; + + private readonly long[,,] weights; + private readonly long[,,] momentsRed; + private readonly long[,,] momentsGreen; + private readonly long[,,] momentsBlue; + private readonly float[,,] moments; + + private byte[] tag; + + private readonly WuColorCube[] cubes; + private readonly Bitmap sourceBitmap; + private Bitmap resultBitmap; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (resultBitmap != null) + { + resultBitmap.Dispose(); + resultBitmap = null; + } + } + } + + /// + /// See for more details. + /// + public WuQuantizer(Bitmap sourceBitmap) + { + this.sourceBitmap = sourceBitmap; + // Make sure the color count variables are reset + BitArray bitArray = new BitArray((int) Math.Pow(2, 24)); + colorCount = 0; + + // creates all the cubes + cubes = new WuColorCube[MAXCOLOR]; + + // initializes all the cubes + for (int cubeIndex = 0; cubeIndex < MAXCOLOR; cubeIndex++) + { + cubes[cubeIndex] = new WuColorCube(); + } + + // resets the reference minimums + cubes[0].RedMinimum = 0; + cubes[0].GreenMinimum = 0; + cubes[0].BlueMinimum = 0; + + // resets the reference maximums + cubes[0].RedMaximum = MAXSIDEINDEX; + cubes[0].GreenMaximum = MAXSIDEINDEX; + cubes[0].BlueMaximum = MAXSIDEINDEX; + + weights = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + momentsRed = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + momentsGreen = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + momentsBlue = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + moments = new float[SIDESIZE, SIDESIZE, SIDESIZE]; + + int[] table = new int[256]; + + for (int tableIndex = 0; tableIndex < 256; ++tableIndex) + { + table[tableIndex] = tableIndex * tableIndex; + } + + // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage + using IFastBitmap sourceFastBitmap = FastBitmap.Create(sourceBitmap); + IFastBitmapWithBlend sourceFastBitmapWithBlend = sourceFastBitmap as IFastBitmapWithBlend; + sourceFastBitmap.Lock(); + using FastChunkyBitmap destinationFastBitmap = FastBitmap.CreateEmpty(sourceBitmap.Size, PixelFormat.Format8bppIndexed, Color.White) as FastChunkyBitmap; + destinationFastBitmap.Lock(); + for (int y = 0; y < sourceFastBitmap.Height; y++) + { + for (int x = 0; x < sourceFastBitmap.Width; x++) + { + Color color; + if (sourceFastBitmapWithBlend == null) + { + color = sourceFastBitmap.GetColorAt(x, y); + } + else + { + color = sourceFastBitmapWithBlend.GetBlendedColorAt(x, y); + } + + // To count the colors + int index = color.ToArgb() & 0x00ffffff; + // Check if we already have this color + if (!bitArray.Get(index)) + { + // If not, add 1 to the single colors + colorCount++; + bitArray.Set(index, true); + } + + int indexRed = (color.R >> 3) + 1; + int indexGreen = (color.G >> 3) + 1; + int indexBlue = (color.B >> 3) + 1; + + weights[indexRed, indexGreen, indexBlue]++; + momentsRed[indexRed, indexGreen, indexBlue] += color.R; + momentsGreen[indexRed, indexGreen, indexBlue] += color.G; + momentsBlue[indexRed, indexGreen, indexBlue] += color.B; + moments[indexRed, indexGreen, indexBlue] += table[color.R] + table[color.G] + table[color.B]; + + // Store the initial "match" + int paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue; + destinationFastBitmap.SetColorIndexAt(x, y, (byte) (paletteIndex & 0xff)); + } + } + + resultBitmap = destinationFastBitmap.UnlockAndReturnBitmap(); + } + + /// + /// See for more details. + /// + public int GetColorCount() + { + return colorCount; + } + + /// + /// Reindex the 24/32 BPP (A)RGB image to a 8BPP + /// + /// Bitmap + public Bitmap SimpleReindex() + { + List colors = new List(); + Dictionary lookup = new Dictionary(); + using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) + { + bbbDest.Lock(); + using IFastBitmap bbbSrc = FastBitmap.Create(sourceBitmap); + IFastBitmapWithBlend bbbSrcBlend = bbbSrc as IFastBitmapWithBlend; + + bbbSrc.Lock(); + byte index; + for (int y = 0; y < bbbSrc.Height; y++) + { + for (int x = 0; x < bbbSrc.Width; x++) + { + Color color; + if (bbbSrcBlend != null) + { + color = bbbSrcBlend.GetBlendedColorAt(x, y); + } + else + { + color = bbbSrc.GetColorAt(x, y); + } + + if (lookup.ContainsKey(color)) + { + index = lookup[color]; + } + else + { + colors.Add(color); + index = (byte) (colors.Count - 1); + lookup.Add(color, index); + } + + bbbDest.SetColorIndexAt(x, y, index); + } + } + } + + // generates palette + ColorPalette imagePalette = resultBitmap.Palette; + Color[] entries = imagePalette.Entries; + for (int paletteIndex = 0; paletteIndex < 256; paletteIndex++) + { + if (paletteIndex < colorCount) + { + entries[paletteIndex] = colors[paletteIndex]; + } + else + { + entries[paletteIndex] = Color.Black; + } + } + + resultBitmap.Palette = imagePalette; + + // Make sure the bitmap is not disposed, as we return it. + Bitmap tmpBitmap = resultBitmap; + resultBitmap = null; + return tmpBitmap; + } + + /// + /// Get the image + /// + public Bitmap GetQuantizedImage(int allowedColorCount) + { + if (allowedColorCount > 256) + { + throw new ArgumentOutOfRangeException(nameof(allowedColorCount), "Quantizing muss be done to get less than 256 colors"); + } + + if (colorCount < allowedColorCount) + { + // Simple logic to reduce to 8 bit + LOG.Info("Colors in the image are already less as whished for, using simple copy to indexed image, no quantizing needed!"); + return SimpleReindex(); + } + + // preprocess the colors + CalculateMoments(); + LOG.Info("Calculated the moments..."); + int next = 0; + float[] volumeVariance = new float[MAXCOLOR]; + + // processes the cubes + for (int cubeIndex = 1; cubeIndex < allowedColorCount; ++cubeIndex) + { + // if cut is possible; make it + if (Cut(cubes[next], cubes[cubeIndex])) + { + volumeVariance[next] = cubes[next].Volume > 1 ? CalculateVariance(cubes[next]) : 0.0f; + volumeVariance[cubeIndex] = cubes[cubeIndex].Volume > 1 ? CalculateVariance(cubes[cubeIndex]) : 0.0f; + } + else + { + // the cut was not possible, revert the index + volumeVariance[next] = 0.0f; + cubeIndex--; + } + + next = 0; + float temp = volumeVariance[0]; + + for (int index = 1; index <= cubeIndex; ++index) + { + if (volumeVariance[index] > temp) + { + temp = volumeVariance[index]; + next = index; + } + } + + if (temp <= 0.0) + { + allowedColorCount = cubeIndex + 1; + break; + } + } + + int[] lookupRed = new int[MAXCOLOR]; + int[] lookupGreen = new int[MAXCOLOR]; + int[] lookupBlue = new int[MAXCOLOR]; + + tag = new byte[MAXVOLUME]; + + // precalculates lookup tables + for (int k = 0; k < allowedColorCount; ++k) + { + Mark(cubes[k], k, tag); + + long weight = Volume(cubes[k], weights); + + if (weight > 0) + { + lookupRed[k] = (int) (Volume(cubes[k], momentsRed) / weight); + lookupGreen[k] = (int) (Volume(cubes[k], momentsGreen) / weight); + lookupBlue[k] = (int) (Volume(cubes[k], momentsBlue) / weight); + } + else + { + lookupRed[k] = 0; + lookupGreen[k] = 0; + lookupBlue[k] = 0; + } + } + + reds = new int[allowedColorCount + 1]; + greens = new int[allowedColorCount + 1]; + blues = new int[allowedColorCount + 1]; + sums = new int[allowedColorCount + 1]; + + LOG.Info("Starting bitmap reconstruction..."); + + using (FastChunkyBitmap dest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) + { + using IFastBitmap src = FastBitmap.Create(sourceBitmap); + IFastBitmapWithBlend srcBlend = src as IFastBitmapWithBlend; + Dictionary lookup = new Dictionary(); + for (int y = 0; y < src.Height; y++) + { + for (int x = 0; x < src.Width; x++) + { + Color color; + if (srcBlend != null) + { + // WithoutAlpha, this makes it possible to ignore the alpha + color = srcBlend.GetBlendedColorAt(x, y); + } + else + { + color = src.GetColorAt(x, y); + } + + // Check if we already matched the color + byte bestMatch; + if (!lookup.ContainsKey(color)) + { + // If not we need to find the best match + + // First get initial match + bestMatch = dest.GetColorIndexAt(x, y); + bestMatch = tag[bestMatch]; + + int bestDistance = 100000000; + for (int lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++) + { + int foundRed = lookupRed[lookupIndex]; + int foundGreen = lookupGreen[lookupIndex]; + int foundBlue = lookupBlue[lookupIndex]; + int deltaRed = color.R - foundRed; + int deltaGreen = color.G - foundGreen; + int deltaBlue = color.B - foundBlue; + + int distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue; + + if (distance < bestDistance) + { + bestDistance = distance; + bestMatch = (byte) lookupIndex; + } + } + + lookup.Add(color, bestMatch); + } + else + { + // Already matched, so we just use the lookup + bestMatch = lookup[color]; + } + + reds[bestMatch] += color.R; + greens[bestMatch] += color.G; + blues[bestMatch] += color.B; + sums[bestMatch]++; + + dest.SetColorIndexAt(x, y, bestMatch); + } + } + } + + + // generates palette + ColorPalette imagePalette = resultBitmap.Palette; + Color[] entries = imagePalette.Entries; + for (int paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++) + { + if (sums[paletteIndex] > 0) + { + reds[paletteIndex] /= sums[paletteIndex]; + greens[paletteIndex] /= sums[paletteIndex]; + blues[paletteIndex] /= sums[paletteIndex]; + } + + entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]); + } + + resultBitmap.Palette = imagePalette; + + // Make sure the bitmap is not disposed, as we return it. + Bitmap tmpBitmap = resultBitmap; + resultBitmap = null; + return tmpBitmap; + } + + /// + /// Converts the histogram to a series of moments. + /// + private void CalculateMoments() + { + long[] area = new long[SIDESIZE]; + long[] areaRed = new long[SIDESIZE]; + long[] areaGreen = new long[SIDESIZE]; + long[] areaBlue = new long[SIDESIZE]; + float[] area2 = new float[SIDESIZE]; + + for (int redIndex = 1; redIndex <= MAXSIDEINDEX; ++redIndex) + { + for (int index = 0; index <= MAXSIDEINDEX; ++index) + { + area[index] = 0; + areaRed[index] = 0; + areaGreen[index] = 0; + areaBlue[index] = 0; + area2[index] = 0; + } + + for (int greenIndex = 1; greenIndex <= MAXSIDEINDEX; ++greenIndex) + { + long line = 0; + long lineRed = 0; + long lineGreen = 0; + long lineBlue = 0; + float line2 = 0.0f; + + for (int blueIndex = 1; blueIndex <= MAXSIDEINDEX; ++blueIndex) + { + line += weights[redIndex, greenIndex, blueIndex]; + lineRed += momentsRed[redIndex, greenIndex, blueIndex]; + lineGreen += momentsGreen[redIndex, greenIndex, blueIndex]; + lineBlue += momentsBlue[redIndex, greenIndex, blueIndex]; + line2 += moments[redIndex, greenIndex, blueIndex]; + + area[blueIndex] += line; + areaRed[blueIndex] += lineRed; + areaGreen[blueIndex] += lineGreen; + areaBlue[blueIndex] += lineBlue; + area2[blueIndex] += line2; + + weights[redIndex, greenIndex, blueIndex] = weights[redIndex - 1, greenIndex, blueIndex] + area[blueIndex]; + momentsRed[redIndex, greenIndex, blueIndex] = momentsRed[redIndex - 1, greenIndex, blueIndex] + areaRed[blueIndex]; + momentsGreen[redIndex, greenIndex, blueIndex] = momentsGreen[redIndex - 1, greenIndex, blueIndex] + areaGreen[blueIndex]; + momentsBlue[redIndex, greenIndex, blueIndex] = momentsBlue[redIndex - 1, greenIndex, blueIndex] + areaBlue[blueIndex]; + moments[redIndex, greenIndex, blueIndex] = moments[redIndex - 1, greenIndex, blueIndex] + area2[blueIndex]; + } + } + } + } + + /// + /// Computes the volume of the cube in a specific moment. + /// + private static long Volume(WuColorCube cube, long[,,] moment) + { + return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - + moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; + } + + /// + /// Computes the volume of the cube in a specific moment. For the floating-point values. + /// + private static float VolumeFloat(WuColorCube cube, float[,,] moment) + { + return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - + moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; + } + + /// + /// Splits the cube in given position, and color direction. + /// + private static long Top(WuColorCube cube, int direction, int position, long[,,] moment) + { + return direction switch + { + RED => (moment[position, cube.GreenMaximum, cube.BlueMaximum] - + moment[position, cube.GreenMaximum, cube.BlueMinimum] - + moment[position, cube.GreenMinimum, cube.BlueMaximum] + + moment[position, cube.GreenMinimum, cube.BlueMinimum]), + GREEN => (moment[cube.RedMaximum, position, cube.BlueMaximum] - + moment[cube.RedMaximum, position, cube.BlueMinimum] - + moment[cube.RedMinimum, position, cube.BlueMaximum] + + moment[cube.RedMinimum, position, cube.BlueMinimum]), + BLUE => (moment[cube.RedMaximum, cube.GreenMaximum, position] - + moment[cube.RedMaximum, cube.GreenMinimum, position] - + moment[cube.RedMinimum, cube.GreenMaximum, position] + + moment[cube.RedMinimum, cube.GreenMinimum, position]), + _ => 0, + }; + } + + /// + /// Splits the cube in a given color direction at its minimum. + /// + private static long Bottom(WuColorCube cube, int direction, long[,,] moment) + { + return direction switch + { + RED => (-moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), + GREEN => (-moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), + BLUE => (-moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] + + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), + _ => 0 + }; + } + + /// + /// Calculates statistical variance for a given cube. + /// + private float CalculateVariance(WuColorCube cube) + { + float volumeRed = Volume(cube, momentsRed); + float volumeGreen = Volume(cube, momentsGreen); + float volumeBlue = Volume(cube, momentsBlue); + float volumeMoment = VolumeFloat(cube, moments); + float volumeWeight = Volume(cube, weights); + + float distance = volumeRed * volumeRed + volumeGreen * volumeGreen + volumeBlue * volumeBlue; + + return volumeMoment - (distance / volumeWeight); + } + + /// + /// Finds the optimal (maximal) position for the cut. + /// + private float Maximize(WuColorCube cube, int direction, int first, int last, int[] cut, long wholeRed, long wholeGreen, long wholeBlue, long wholeWeight) + { + long bottomRed = Bottom(cube, direction, momentsRed); + long bottomGreen = Bottom(cube, direction, momentsGreen); + long bottomBlue = Bottom(cube, direction, momentsBlue); + long bottomWeight = Bottom(cube, direction, weights); + + float result = 0.0f; + cut[0] = -1; + + for (int position = first; position < last; ++position) + { + // determines the cube cut at a certain position + long halfRed = bottomRed + Top(cube, direction, position, momentsRed); + long halfGreen = bottomGreen + Top(cube, direction, position, momentsGreen); + long halfBlue = bottomBlue + Top(cube, direction, position, momentsBlue); + long halfWeight = bottomWeight + Top(cube, direction, position, weights); + + // the cube cannot be cut at bottom (this would lead to empty cube) + if (halfWeight != 0) + { + float halfDistance = (float) halfRed * halfRed + (float) halfGreen * halfGreen + (float) halfBlue * halfBlue; + float temp = halfDistance / halfWeight; + + halfRed = wholeRed - halfRed; + halfGreen = wholeGreen - halfGreen; + halfBlue = wholeBlue - halfBlue; + halfWeight = wholeWeight - halfWeight; + + if (halfWeight != 0) + { + halfDistance = (float) halfRed * halfRed + (float) halfGreen * halfGreen + (float) halfBlue * halfBlue; + temp += halfDistance / halfWeight; + + if (temp > result) + { + result = temp; + cut[0] = position; + } + } + } + } + + return result; + } + + /// + /// Cuts a cube with another one. + /// + private bool Cut(WuColorCube first, WuColorCube second) + { + int direction; + + int[] cutRed = + { + 0 + }; + int[] cutGreen = + { + 0 + }; + int[] cutBlue = + { + 0 + }; + + long wholeRed = Volume(first, momentsRed); + long wholeGreen = Volume(first, momentsGreen); + long wholeBlue = Volume(first, momentsBlue); + long wholeWeight = Volume(first, weights); + + float maxRed = Maximize(first, RED, first.RedMinimum + 1, first.RedMaximum, cutRed, wholeRed, wholeGreen, wholeBlue, wholeWeight); + float maxGreen = Maximize(first, GREEN, first.GreenMinimum + 1, first.GreenMaximum, cutGreen, wholeRed, wholeGreen, wholeBlue, wholeWeight); + float maxBlue = Maximize(first, BLUE, first.BlueMinimum + 1, first.BlueMaximum, cutBlue, wholeRed, wholeGreen, wholeBlue, wholeWeight); + + if ((maxRed >= maxGreen) && (maxRed >= maxBlue)) + { + direction = RED; + + // cannot split empty cube + if (cutRed[0] < 0) return false; + } + else + { + if ((maxGreen >= maxRed) && (maxGreen >= maxBlue)) + { + direction = GREEN; + } + else + { + direction = BLUE; + } + } + + second.RedMaximum = first.RedMaximum; + second.GreenMaximum = first.GreenMaximum; + second.BlueMaximum = first.BlueMaximum; + + // cuts in a certain direction + switch (direction) + { + case RED: + second.RedMinimum = first.RedMaximum = cutRed[0]; + second.GreenMinimum = first.GreenMinimum; + second.BlueMinimum = first.BlueMinimum; + break; + + case GREEN: + second.GreenMinimum = first.GreenMaximum = cutGreen[0]; + second.RedMinimum = first.RedMinimum; + second.BlueMinimum = first.BlueMinimum; + break; + + case BLUE: + second.BlueMinimum = first.BlueMaximum = cutBlue[0]; + second.RedMinimum = first.RedMinimum; + second.GreenMinimum = first.GreenMinimum; + break; + } + + // determines the volumes after cut + first.Volume = (first.RedMaximum - first.RedMinimum) * (first.GreenMaximum - first.GreenMinimum) * (first.BlueMaximum - first.BlueMinimum); + second.Volume = (second.RedMaximum - second.RedMinimum) * (second.GreenMaximum - second.GreenMinimum) * (second.BlueMaximum - second.BlueMinimum); + + // the cut was successfull + return true; + } + + /// + /// Marks all the tags with a given label. + /// + private void Mark(WuColorCube cube, int label, byte[] tag) + { + for (int redIndex = cube.RedMinimum + 1; redIndex <= cube.RedMaximum; ++redIndex) + { + for (int greenIndex = cube.GreenMinimum + 1; greenIndex <= cube.GreenMaximum; ++greenIndex) + { + for (int blueIndex = cube.BlueMinimum + 1; blueIndex <= cube.BlueMaximum; ++blueIndex) + { + tag[(redIndex << 10) + (redIndex << 6) + redIndex + (greenIndex << 5) + greenIndex + blueIndex] = (byte) label; + } + } + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/RegistryKeyExtensions.cs b/src/Greenshot.Base/Core/RegistryKeyExtensions.cs similarity index 99% rename from src/GreenshotPlugin/Core/RegistryKeyExtensions.cs rename to src/Greenshot.Base/Core/RegistryKeyExtensions.cs index 383c55e67..a1abcea98 100644 --- a/src/GreenshotPlugin/Core/RegistryKeyExtensions.cs +++ b/src/Greenshot.Base/Core/RegistryKeyExtensions.cs @@ -22,7 +22,7 @@ using System; using Microsoft.Win32; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// A helper class for accessing the registry diff --git a/src/GreenshotPlugin/Core/SimpleServiceProvider.cs b/src/Greenshot.Base/Core/SimpleServiceProvider.cs similarity index 92% rename from src/GreenshotPlugin/Core/SimpleServiceProvider.cs rename to src/Greenshot.Base/Core/SimpleServiceProvider.cs index fc197367d..bff814540 100644 --- a/src/GreenshotPlugin/Core/SimpleServiceProvider.cs +++ b/src/Greenshot.Base/Core/SimpleServiceProvider.cs @@ -1,61 +1,61 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using GreenshotPlugin.Interfaces; - -namespace GreenshotPlugin.Core -{ - /// - /// A really cheap and simple DI system - /// - public class SimpleServiceProvider : IServiceLocator - { - private readonly Dictionary> _services = new Dictionary>(); - - public static IServiceLocator Current { get; } = new SimpleServiceProvider(); - - public IEnumerable GetAllInstances() - { - var typeOfService = typeof(TService); - if (!_services.TryGetValue(typeOfService, out var results)) - { - yield break; - } - - foreach (TService result in results) - { - yield return result; - } - } - - public TService GetInstance() - { - return GetAllInstances().SingleOrDefault(); - } - - public void AddService(IEnumerable services) - { - var serviceType = typeof(TService); - if (!_services.TryGetValue(serviceType, out var currentServices)) - { - currentServices = new List(); - _services.Add(serviceType, currentServices); - } - - foreach (var service in services) - { - if (service == null) - { - continue; - } - - currentServices.Add(service); - } - } - - public void AddService(params TService[] services) - { - AddService(services.AsEnumerable()); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Base.Core +{ + /// + /// A really cheap and simple DI system + /// + public class SimpleServiceProvider : IServiceLocator + { + private readonly Dictionary> _services = new Dictionary>(); + + public static IServiceLocator Current { get; } = new SimpleServiceProvider(); + + public IEnumerable GetAllInstances() + { + var typeOfService = typeof(TService); + if (!_services.TryGetValue(typeOfService, out var results)) + { + yield break; + } + + foreach (TService result in results) + { + yield return result; + } + } + + public TService GetInstance() + { + return GetAllInstances().SingleOrDefault(); + } + + public void AddService(IEnumerable services) + { + var serviceType = typeof(TService); + if (!_services.TryGetValue(serviceType, out var currentServices)) + { + currentServices = new List(); + _services.Add(serviceType, currentServices); + } + + foreach (var service in services) + { + if (service == null) + { + continue; + } + + currentServices.Add(service); + } + } + + public void AddService(params TService[] services) + { + AddService(services.AsEnumerable()); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/StringExtensions.cs b/src/Greenshot.Base/Core/StringExtensions.cs similarity index 99% rename from src/GreenshotPlugin/Core/StringExtensions.cs rename to src/Greenshot.Base/Core/StringExtensions.cs index d82f51e14..1265e3616 100644 --- a/src/GreenshotPlugin/Core/StringExtensions.cs +++ b/src/Greenshot.Base/Core/StringExtensions.cs @@ -20,14 +20,14 @@ */ using System; +using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using System.Text; -using log4net; using System.Text.RegularExpressions; -using System.Collections.Generic; +using log4net; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { public static class StringExtensions { diff --git a/src/GreenshotPlugin/Core/SvgImage.cs b/src/Greenshot.Base/Core/SvgImage.cs similarity index 99% rename from src/GreenshotPlugin/Core/SvgImage.cs rename to src/Greenshot.Base/Core/SvgImage.cs index 7924c3480..f04e8c0df 100644 --- a/src/GreenshotPlugin/Core/SvgImage.cs +++ b/src/Greenshot.Base/Core/SvgImage.cs @@ -24,7 +24,7 @@ using System.Drawing.Imaging; using System.IO; using Svg; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// Create an image look like of the SVG diff --git a/src/GreenshotPlugin/Core/WindowCapture.cs b/src/Greenshot.Base/Core/WindowCapture.cs similarity index 96% rename from src/GreenshotPlugin/Core/WindowCapture.cs rename to src/Greenshot.Base/Core/WindowCapture.cs index fafd88a18..7d5c751d9 100644 --- a/src/GreenshotPlugin/Core/WindowCapture.cs +++ b/src/Greenshot.Base/Core/WindowCapture.cs @@ -1,444 +1,444 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.UnmanagedHelpers; -using log4net; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.InteropServices; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace GreenshotPlugin.Core -{ - /// - /// The Window Capture code - /// - public static class WindowCapture - { - private static readonly ILog Log = LogManager.GetLogger(typeof(WindowCapture)); - private static readonly CoreConfiguration Configuration = IniConfig.GetIniSection(); - - /// - /// Used to cleanup the unmanaged resource in the iconInfo for the CaptureCursor method - /// - /// - /// - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); - - /// - /// Get the bounds of all screens combined. - /// - /// A Rectangle of the bounds of the entire display area. - public static Rectangle GetScreenBounds() - { - int left = 0, top = 0, bottom = 0, right = 0; - foreach (Screen screen in Screen.AllScreens) - { - left = Math.Min(left, screen.Bounds.X); - top = Math.Min(top, screen.Bounds.Y); - int screenAbsRight = screen.Bounds.X + screen.Bounds.Width; - int screenAbsBottom = screen.Bounds.Y + screen.Bounds.Height; - right = Math.Max(right, screenAbsRight); - bottom = Math.Max(bottom, screenAbsBottom); - } - - return new Rectangle(left, top, (right + Math.Abs(left)), (bottom + Math.Abs(top))); - } - - /// - /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. This implementation - /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. - /// - /// - /// Point with cursor location, relative to the top left corner of the monitor setup (which itself might actually not be on any screen) - /// - public static Point GetCursorLocationRelativeToScreenBounds() - { - return GetLocationRelativeToScreenBounds(User32.GetCursorLocation()); - } - - /// - /// Converts locationRelativeToScreenOrigin to be relative to top left corner of all screen bounds, which might - /// be different in multi-screen setups. This implementation - /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. - /// - /// - /// Point - public static Point GetLocationRelativeToScreenBounds(Point locationRelativeToScreenOrigin) - { - Point ret = locationRelativeToScreenOrigin; - Rectangle bounds = GetScreenBounds(); - ret.Offset(-bounds.X, -bounds.Y); - return ret; - } - - /// - /// This method will capture the current Cursor by using User32 Code - /// - /// A Capture Object with the Mouse Cursor information in it. - public static ICapture CaptureCursor(ICapture capture) - { - Log.Debug("Capturing the mouse cursor."); - if (capture == null) - { - capture = new Capture(); - } - - var cursorInfo = new CursorInfo(); - cursorInfo.cbSize = Marshal.SizeOf(cursorInfo); - if (!User32.GetCursorInfo(out cursorInfo)) return capture; - if (cursorInfo.flags != User32.CURSOR_SHOWING) return capture; - - using SafeIconHandle safeIcon = User32.CopyIcon(cursorInfo.hCursor); - if (!User32.GetIconInfo(safeIcon, out var iconInfo)) return capture; - - Point cursorLocation = User32.GetCursorLocation(); - // Align cursor location to Bitmap coordinates (instead of Screen coordinates) - var x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X; - var y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y; - // Set the location - capture.CursorLocation = new Point(x, y); - - using (Icon icon = Icon.FromHandle(safeIcon.DangerousGetHandle())) - { - capture.Cursor = icon; - } - - if (iconInfo.hbmMask != IntPtr.Zero) - { - DeleteObject(iconInfo.hbmMask); - } - - if (iconInfo.hbmColor != IntPtr.Zero) - { - DeleteObject(iconInfo.hbmColor); - } - - return capture; - } - - /// - /// This method will call the CaptureRectangle with the screenbounds, therefor Capturing the whole screen. - /// - /// A Capture Object with the Screen as an Image - public static ICapture CaptureScreen(ICapture capture) - { - if (capture == null) - { - capture = new Capture(); - } - - return CaptureRectangle(capture, capture.ScreenBounds); - } - - /// - /// Helper method to create an exception that might explain what is wrong while capturing - /// - /// string with current method - /// Rectangle of what we want to capture - /// - private static Exception CreateCaptureException(string method, Rectangle captureBounds) - { - Exception exceptionToThrow = User32.CreateWin32Exception(method); - if (!captureBounds.IsEmpty) - { - exceptionToThrow.Data.Add("Height", captureBounds.Height); - exceptionToThrow.Data.Add("Width", captureBounds.Width); - } - - return exceptionToThrow; - } - - /// - /// Helper method to check if it is allowed to capture the process using DWM - /// - /// Process owning the window - /// true if it's allowed - public static bool IsDwmAllowed(Process process) - { - if (process == null) return true; - if (Configuration.NoDWMCaptureForProduct == null || - Configuration.NoDWMCaptureForProduct.Count <= 0) return true; - - try - { - string productName = process.MainModule?.FileVersionInfo.ProductName; - if (productName != null && Configuration.NoDWMCaptureForProduct.Contains(productName.ToLower())) - { - return false; - } - } - catch (Exception ex) - { - Log.Warn(ex.Message); - } - - return true; - } - - /// - /// Helper method to check if it is allowed to capture the process using GDI - /// - /// Process owning the window - /// true if it's allowed - public static bool IsGdiAllowed(Process process) - { - if (process == null) return true; - if (Configuration.NoGDICaptureForProduct == null || - Configuration.NoGDICaptureForProduct.Count <= 0) return true; - - try - { - string productName = process.MainModule?.FileVersionInfo.ProductName; - if (productName != null && Configuration.NoGDICaptureForProduct.Contains(productName.ToLower())) - { - return false; - } - } - catch (Exception ex) - { - Log.Warn(ex.Message); - } - - return true; - } - - /// - /// This method will use User32 code to capture the specified captureBounds from the screen - /// - /// ICapture where the captured Bitmap will be stored - /// Rectangle with the bounds to capture - /// A Capture Object with a part of the Screen as an Image - public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds) - { - if (capture == null) - { - capture = new Capture(); - } - - Image capturedImage = null; - // If the CaptureHandler has a handle use this, otherwise use the CaptureRectangle here - if (CaptureHandler.CaptureScreenRectangle != null) - { - try - { - capturedImage = CaptureHandler.CaptureScreenRectangle(captureBounds); - } - catch - { - // ignored - } - } - - // If no capture, use the normal screen capture - if (capturedImage == null) - { - capturedImage = CaptureRectangle(captureBounds); - } - - capture.Image = capturedImage; - capture.Location = captureBounds.Location; - return capture.Image == null ? null : capture; - } - - /// - /// This method will use User32 code to capture the specified captureBounds from the screen - /// - /// ICapture where the captured Bitmap will be stored - /// Rectangle with the bounds to capture - /// A Capture Object with a part of the Screen as an Image - public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, Rectangle captureBounds) - { - if (capture == null) - { - capture = new Capture(); - } - - capture.Image = CaptureRectangle(captureBounds); - capture.Location = captureBounds.Location; - return capture.Image == null ? null : capture; - } - - /// - /// This method will use User32 code to capture the specified captureBounds from the screen - /// - /// Rectangle with the bounds to capture - /// Bitmap which is captured from the screen at the location specified by the captureBounds - public static Bitmap CaptureRectangle(Rectangle captureBounds) - { - Bitmap returnBitmap = null; - if (captureBounds.Height <= 0 || captureBounds.Width <= 0) - { - Log.Warn("Nothing to capture, ignoring!"); - return null; - } - - Log.Debug("CaptureRectangle Called!"); - - // .NET GDI+ Solution, according to some post this has a GDI+ leak... - // See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen - // Bitmap capturedBitmap = new Bitmap(captureBounds.Width, captureBounds.Height); - // using (Graphics graphics = Graphics.FromImage(capturedBitmap)) { - // graphics.CopyFromScreen(captureBounds.Location, Point.Empty, captureBounds.Size, CopyPixelOperation.CaptureBlt); - // } - // capture.Image = capturedBitmap; - // capture.Location = captureBounds.Location; - - using (var desktopDcHandle = SafeWindowDcHandle.FromDesktop()) - { - if (desktopDcHandle.IsInvalid) - { - // Get Exception before the error is lost - Exception exceptionToThrow = CreateCaptureException("desktopDCHandle", captureBounds); - // throw exception - throw exceptionToThrow; - } - - // create a device context we can copy to - using SafeCompatibleDCHandle safeCompatibleDcHandle = GDI32.CreateCompatibleDC(desktopDcHandle); - // Check if the device context is there, if not throw an error with as much info as possible! - if (safeCompatibleDcHandle.IsInvalid) - { - // Get Exception before the error is lost - Exception exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds); - // throw exception - throw exceptionToThrow; - } - - // Create BITMAPINFOHEADER for CreateDIBSection - BITMAPINFOHEADER bmi = new BITMAPINFOHEADER(captureBounds.Width, captureBounds.Height, 24); - - // Make sure the last error is set to 0 - Win32.SetLastError(0); - - // create a bitmap we can copy it to, using GetDeviceCaps to get the width/height - using SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDcHandle, ref bmi, BITMAPINFOHEADER.DIB_RGB_COLORS, out _, IntPtr.Zero, 0); - if (safeDibSectionHandle.IsInvalid) - { - // Get Exception before the error is lost - var exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds); - exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32()); - exceptionToThrow.Data.Add("hdcSrc", desktopDcHandle.DangerousGetHandle().ToInt32()); - - // Throw so people can report the problem - throw exceptionToThrow; - } - - // select the bitmap object and store the old handle - using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle)) - { - // bitblt over (make copy) - // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags - GDI32.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y, - CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt); - } - - // get a .NET image object for it - // A suggestion for the "A generic error occurred in GDI+." E_FAIL/0�80004005 error is to re-try... - bool success = false; - ExternalException exception = null; - for (int i = 0; i < 3; i++) - { - try - { - // Collect all screens inside this capture - List screensInsideCapture = new List(); - foreach (Screen screen in Screen.AllScreens) - { - if (screen.Bounds.IntersectsWith(captureBounds)) - { - screensInsideCapture.Add(screen); - } - } - - // Check all all screens are of an equal size - bool offscreenContent; - using (Region captureRegion = new Region(captureBounds)) - { - // Exclude every visible part - foreach (Screen screen in screensInsideCapture) - { - captureRegion.Exclude(screen.Bounds); - } - - // If the region is not empty, we have "offscreenContent" - using Graphics screenGraphics = Graphics.FromHwnd(User32.GetDesktopWindow()); - offscreenContent = !captureRegion.IsEmpty(screenGraphics); - } - - // Check if we need to have a transparent background, needed for offscreen content - if (offscreenContent) - { - using Bitmap tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); - // Create a new bitmap which has a transparent background - returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, - tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution); - // Content will be copied here - using Graphics graphics = Graphics.FromImage(returnBitmap); - // For all screens copy the content to the new bitmap - foreach (Screen screen in Screen.AllScreens) - { - Rectangle screenBounds = screen.Bounds; - // Make sure the bounds are offsetted to the capture bounds - screenBounds.Offset(-captureBounds.X, -captureBounds.Y); - graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel); - } - } - else - { - // All screens, which are inside the capture, are of equal size - // assign image to Capture, the image will be disposed there.. - returnBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); - } - - // We got through the capture without exception - success = true; - break; - } - catch (ExternalException ee) - { - Log.Warn("Problem getting bitmap at try " + i + " : ", ee); - exception = ee; - } - } - - if (!success) - { - Log.Error("Still couldn't create Bitmap!"); - if (exception != null) - { - throw exception; - } - } - } - - return returnBitmap; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Structs; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// The Window Capture code + /// + public static class WindowCapture + { + private static readonly ILog Log = LogManager.GetLogger(typeof(WindowCapture)); + private static readonly CoreConfiguration Configuration = IniConfig.GetIniSection(); + + /// + /// Used to cleanup the unmanaged resource in the iconInfo for the CaptureCursor method + /// + /// + /// + [DllImport("gdi32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteObject(IntPtr hObject); + + /// + /// Get the bounds of all screens combined. + /// + /// A Rectangle of the bounds of the entire display area. + public static Rectangle GetScreenBounds() + { + int left = 0, top = 0, bottom = 0, right = 0; + foreach (Screen screen in Screen.AllScreens) + { + left = Math.Min(left, screen.Bounds.X); + top = Math.Min(top, screen.Bounds.Y); + int screenAbsRight = screen.Bounds.X + screen.Bounds.Width; + int screenAbsBottom = screen.Bounds.Y + screen.Bounds.Height; + right = Math.Max(right, screenAbsRight); + bottom = Math.Max(bottom, screenAbsBottom); + } + + return new Rectangle(left, top, (right + Math.Abs(left)), (bottom + Math.Abs(top))); + } + + /// + /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. This implementation + /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. + /// + /// + /// Point with cursor location, relative to the top left corner of the monitor setup (which itself might actually not be on any screen) + /// + public static Point GetCursorLocationRelativeToScreenBounds() + { + return GetLocationRelativeToScreenBounds(User32.GetCursorLocation()); + } + + /// + /// Converts locationRelativeToScreenOrigin to be relative to top left corner of all screen bounds, which might + /// be different in multi-screen setups. This implementation + /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. + /// + /// + /// Point + public static Point GetLocationRelativeToScreenBounds(Point locationRelativeToScreenOrigin) + { + Point ret = locationRelativeToScreenOrigin; + Rectangle bounds = GetScreenBounds(); + ret.Offset(-bounds.X, -bounds.Y); + return ret; + } + + /// + /// This method will capture the current Cursor by using User32 Code + /// + /// A Capture Object with the Mouse Cursor information in it. + public static ICapture CaptureCursor(ICapture capture) + { + Log.Debug("Capturing the mouse cursor."); + if (capture == null) + { + capture = new Capture(); + } + + var cursorInfo = new CursorInfo(); + cursorInfo.cbSize = Marshal.SizeOf(cursorInfo); + if (!User32.GetCursorInfo(out cursorInfo)) return capture; + if (cursorInfo.flags != User32.CURSOR_SHOWING) return capture; + + using SafeIconHandle safeIcon = User32.CopyIcon(cursorInfo.hCursor); + if (!User32.GetIconInfo(safeIcon, out var iconInfo)) return capture; + + Point cursorLocation = User32.GetCursorLocation(); + // Align cursor location to Bitmap coordinates (instead of Screen coordinates) + var x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X; + var y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y; + // Set the location + capture.CursorLocation = new Point(x, y); + + using (Icon icon = Icon.FromHandle(safeIcon.DangerousGetHandle())) + { + capture.Cursor = icon; + } + + if (iconInfo.hbmMask != IntPtr.Zero) + { + DeleteObject(iconInfo.hbmMask); + } + + if (iconInfo.hbmColor != IntPtr.Zero) + { + DeleteObject(iconInfo.hbmColor); + } + + return capture; + } + + /// + /// This method will call the CaptureRectangle with the screenbounds, therefor Capturing the whole screen. + /// + /// A Capture Object with the Screen as an Image + public static ICapture CaptureScreen(ICapture capture) + { + if (capture == null) + { + capture = new Capture(); + } + + return CaptureRectangle(capture, capture.ScreenBounds); + } + + /// + /// Helper method to create an exception that might explain what is wrong while capturing + /// + /// string with current method + /// Rectangle of what we want to capture + /// + private static Exception CreateCaptureException(string method, Rectangle captureBounds) + { + Exception exceptionToThrow = User32.CreateWin32Exception(method); + if (!captureBounds.IsEmpty) + { + exceptionToThrow.Data.Add("Height", captureBounds.Height); + exceptionToThrow.Data.Add("Width", captureBounds.Width); + } + + return exceptionToThrow; + } + + /// + /// Helper method to check if it is allowed to capture the process using DWM + /// + /// Process owning the window + /// true if it's allowed + public static bool IsDwmAllowed(Process process) + { + if (process == null) return true; + if (Configuration.NoDWMCaptureForProduct == null || + Configuration.NoDWMCaptureForProduct.Count <= 0) return true; + + try + { + string productName = process.MainModule?.FileVersionInfo.ProductName; + if (productName != null && Configuration.NoDWMCaptureForProduct.Contains(productName.ToLower())) + { + return false; + } + } + catch (Exception ex) + { + Log.Warn(ex.Message); + } + + return true; + } + + /// + /// Helper method to check if it is allowed to capture the process using GDI + /// + /// Process owning the window + /// true if it's allowed + public static bool IsGdiAllowed(Process process) + { + if (process == null) return true; + if (Configuration.NoGDICaptureForProduct == null || + Configuration.NoGDICaptureForProduct.Count <= 0) return true; + + try + { + string productName = process.MainModule?.FileVersionInfo.ProductName; + if (productName != null && Configuration.NoGDICaptureForProduct.Contains(productName.ToLower())) + { + return false; + } + } + catch (Exception ex) + { + Log.Warn(ex.Message); + } + + return true; + } + + /// + /// This method will use User32 code to capture the specified captureBounds from the screen + /// + /// ICapture where the captured Bitmap will be stored + /// Rectangle with the bounds to capture + /// A Capture Object with a part of the Screen as an Image + public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds) + { + if (capture == null) + { + capture = new Capture(); + } + + Image capturedImage = null; + // If the CaptureHandler has a handle use this, otherwise use the CaptureRectangle here + if (CaptureHandler.CaptureScreenRectangle != null) + { + try + { + capturedImage = CaptureHandler.CaptureScreenRectangle(captureBounds); + } + catch + { + // ignored + } + } + + // If no capture, use the normal screen capture + if (capturedImage == null) + { + capturedImage = CaptureRectangle(captureBounds); + } + + capture.Image = capturedImage; + capture.Location = captureBounds.Location; + return capture.Image == null ? null : capture; + } + + /// + /// This method will use User32 code to capture the specified captureBounds from the screen + /// + /// ICapture where the captured Bitmap will be stored + /// Rectangle with the bounds to capture + /// A Capture Object with a part of the Screen as an Image + public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, Rectangle captureBounds) + { + if (capture == null) + { + capture = new Capture(); + } + + capture.Image = CaptureRectangle(captureBounds); + capture.Location = captureBounds.Location; + return capture.Image == null ? null : capture; + } + + /// + /// This method will use User32 code to capture the specified captureBounds from the screen + /// + /// Rectangle with the bounds to capture + /// Bitmap which is captured from the screen at the location specified by the captureBounds + public static Bitmap CaptureRectangle(Rectangle captureBounds) + { + Bitmap returnBitmap = null; + if (captureBounds.Height <= 0 || captureBounds.Width <= 0) + { + Log.Warn("Nothing to capture, ignoring!"); + return null; + } + + Log.Debug("CaptureRectangle Called!"); + + // .NET GDI+ Solution, according to some post this has a GDI+ leak... + // See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen + // Bitmap capturedBitmap = new Bitmap(captureBounds.Width, captureBounds.Height); + // using (Graphics graphics = Graphics.FromImage(capturedBitmap)) { + // graphics.CopyFromScreen(captureBounds.Location, Point.Empty, captureBounds.Size, CopyPixelOperation.CaptureBlt); + // } + // capture.Image = capturedBitmap; + // capture.Location = captureBounds.Location; + + using (var desktopDcHandle = SafeWindowDcHandle.FromDesktop()) + { + if (desktopDcHandle.IsInvalid) + { + // Get Exception before the error is lost + Exception exceptionToThrow = CreateCaptureException("desktopDCHandle", captureBounds); + // throw exception + throw exceptionToThrow; + } + + // create a device context we can copy to + using SafeCompatibleDCHandle safeCompatibleDcHandle = GDI32.CreateCompatibleDC(desktopDcHandle); + // Check if the device context is there, if not throw an error with as much info as possible! + if (safeCompatibleDcHandle.IsInvalid) + { + // Get Exception before the error is lost + Exception exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds); + // throw exception + throw exceptionToThrow; + } + + // Create BITMAPINFOHEADER for CreateDIBSection + BITMAPINFOHEADER bmi = new BITMAPINFOHEADER(captureBounds.Width, captureBounds.Height, 24); + + // Make sure the last error is set to 0 + Win32.SetLastError(0); + + // create a bitmap we can copy it to, using GetDeviceCaps to get the width/height + using SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDcHandle, ref bmi, BITMAPINFOHEADER.DIB_RGB_COLORS, out _, IntPtr.Zero, 0); + if (safeDibSectionHandle.IsInvalid) + { + // Get Exception before the error is lost + var exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds); + exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32()); + exceptionToThrow.Data.Add("hdcSrc", desktopDcHandle.DangerousGetHandle().ToInt32()); + + // Throw so people can report the problem + throw exceptionToThrow; + } + + // select the bitmap object and store the old handle + using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle)) + { + // bitblt over (make copy) + // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags + GDI32.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y, + CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt); + } + + // get a .NET image object for it + // A suggestion for the "A generic error occurred in GDI+." E_FAIL/0�80004005 error is to re-try... + bool success = false; + ExternalException exception = null; + for (int i = 0; i < 3; i++) + { + try + { + // Collect all screens inside this capture + List screensInsideCapture = new List(); + foreach (Screen screen in Screen.AllScreens) + { + if (screen.Bounds.IntersectsWith(captureBounds)) + { + screensInsideCapture.Add(screen); + } + } + + // Check all all screens are of an equal size + bool offscreenContent; + using (Region captureRegion = new Region(captureBounds)) + { + // Exclude every visible part + foreach (Screen screen in screensInsideCapture) + { + captureRegion.Exclude(screen.Bounds); + } + + // If the region is not empty, we have "offscreenContent" + using Graphics screenGraphics = Graphics.FromHwnd(User32.GetDesktopWindow()); + offscreenContent = !captureRegion.IsEmpty(screenGraphics); + } + + // Check if we need to have a transparent background, needed for offscreen content + if (offscreenContent) + { + using Bitmap tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); + // Create a new bitmap which has a transparent background + returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, + tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution); + // Content will be copied here + using Graphics graphics = Graphics.FromImage(returnBitmap); + // For all screens copy the content to the new bitmap + foreach (Screen screen in Screen.AllScreens) + { + Rectangle screenBounds = screen.Bounds; + // Make sure the bounds are offsetted to the capture bounds + screenBounds.Offset(-captureBounds.X, -captureBounds.Y); + graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel); + } + } + else + { + // All screens, which are inside the capture, are of equal size + // assign image to Capture, the image will be disposed there.. + returnBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); + } + + // We got through the capture without exception + success = true; + break; + } + catch (ExternalException ee) + { + Log.Warn("Problem getting bitmap at try " + i + " : ", ee); + exception = ee; + } + } + + if (!success) + { + Log.Error("Still couldn't create Bitmap!"); + if (exception != null) + { + throw exception; + } + } + } + + return returnBitmap; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/WindowDetails.cs b/src/Greenshot.Base/Core/WindowDetails.cs similarity index 96% rename from src/GreenshotPlugin/Core/WindowDetails.cs rename to src/Greenshot.Base/Core/WindowDetails.cs index 641c0db20..c656e586c 100644 --- a/src/GreenshotPlugin/Core/WindowDetails.cs +++ b/src/Greenshot.Base/Core/WindowDetails.cs @@ -1,1876 +1,1874 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.RegularExpressions; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interop; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; -using log4net; - -namespace GreenshotPlugin.Core -{ - /// - /// Code for handling with "windows" - /// Main code is taken from vbAccelerator, location: - /// http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows/Enumerating_Windows/article.asp - /// but a LOT of changes/enhancements were made to adapt it for Greenshot. - /// - /// Provides details about a Window returned by the enumeration - /// - public class WindowDetails : IEquatable - { - private const string AppWindowClass = "Windows.UI.Core.CoreWindow"; //Used for Windows 8(.1) - private const string AppFrameWindowClass = "ApplicationFrameWindow"; // Windows 10 uses ApplicationFrameWindow - private const string ApplauncherClass = "ImmersiveLauncher"; - private const string GutterClass = "ImmersiveGutter"; - - private static readonly IList IgnoreClasses = new List(new[] - { - "Progman", "Button", "Dwm" - }); //"MS-SDIa" - - private static readonly ILog Log = LogManager.GetLogger(typeof(WindowDetails)); - private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); - private static readonly IList IgnoreHandles = new List(); - private static readonly IList ExcludeProcessesFromFreeze = new List(); - private static readonly IAppVisibility AppVisibility; - - static WindowDetails() - { - try - { - // Only try to instantiate when Windows 8 or later. - if (WindowsVersion.IsWindows8OrLater) - { - AppVisibility = COMWrapper.CreateInstance(); - } - } - catch (Exception ex) - { - Log.WarnFormat("Couldn't create instance of IAppVisibility: {0}", ex.Message); - } - } - - public static void AddProcessToExcludeFromFreeze(string processName) - { - if (!ExcludeProcessesFromFreeze.Contains(processName)) - { - ExcludeProcessesFromFreeze.Add(processName); - } - } - - internal static bool IsIgnoreHandle(IntPtr handle) - { - return IgnoreHandles.Contains(handle); - } - - private IList _childWindows; - private IntPtr _parentHandle = IntPtr.Zero; - private WindowDetails _parent; - private bool _frozen; - - /// - /// This checks if the window is a Windows 8 App - /// For Windows 10 most normal code works, as it's hosted inside "ApplicationFrameWindow" - /// - public bool IsApp => AppWindowClass.Equals(ClassName); - - /// - /// This checks if the window is a Windows 10 App - /// For Windows 10 apps are hosted inside "ApplicationFrameWindow" - /// - public bool IsWin10App => AppFrameWindowClass.Equals(ClassName); - - /// - /// Check if this window belongs to a background app - /// - public bool IsBackgroundWin10App => WindowsVersion.IsWindows10OrLater && AppFrameWindowClass.Equals(ClassName) && - !Children.Any(window => string.Equals(window.ClassName, AppWindowClass)); - - /// - /// Check if the window is the metro gutter (sizeable separator) - /// - public bool IsGutter => GutterClass.Equals(ClassName); - - /// - /// Test if this window is for the App-Launcher - /// - public bool IsAppLauncher => ApplauncherClass.Equals(ClassName); - - /// - /// Check if this window is the window of a metro app - /// - public bool IsMetroApp => IsAppLauncher || IsApp; - - /// - /// To allow items to be compared, the hash code - /// is set to the Window handle, so two EnumWindowsItem - /// objects for the same Window will be equal. - /// - /// The Window Handle for this window - public override int GetHashCode() - { - return Handle.ToInt32(); - } - - public override bool Equals(object right) - { - return Equals(right as WindowDetails); - } - - /// - /// Compare two windows details - /// - /// - /// - public bool Equals(WindowDetails other) - { - if (other is null) - { - return false; - } - - if (ReferenceEquals(this, other)) - { - return true; - } - - if (GetType() != other.GetType()) - { - return false; - } - - return other.Handle == Handle; - } - - /// - /// Check if the window has children - /// - public bool HasChildren => (_childWindows != null) && (_childWindows.Count > 0); - - /// - /// Freeze information updates - /// - public void FreezeDetails() - { - _frozen = true; - } - - /// - /// Make the information update again. - /// - public void UnfreezeDetails() - { - _frozen = false; - } - - /// - /// Get the file path to the exe for the process which owns this window - /// - public string ProcessPath - { - get - { - if (Handle == IntPtr.Zero) - { - // not a valid window handle - return string.Empty; - } - - // Get the process id - User32.GetWindowThreadProcessId(Handle, out var processId); - return Kernel32.GetProcessPath(processId); - } - } - - - /// - /// Get the icon belonging to the process - /// - public Image DisplayIcon - { - get - { - try - { - using var appIcon = GetAppIcon(Handle); - if (appIcon != null) - { - return appIcon.ToBitmap(); - } - } - catch (Exception ex) - { - Log.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); - Log.Warn(ex); - } - - if (IsMetroApp) - { - // No method yet to get the metro icon - return null; - } - - try - { - return PluginUtils.GetCachedExeIcon(ProcessPath, 0); - } - catch (Exception ex) - { - Log.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); - Log.Warn(ex); - } - - return null; - } - } - - /// - /// Get the icon for a hWnd - /// - /// - /// - private static Icon GetAppIcon(IntPtr hWnd) - { - IntPtr iconSmall = IntPtr.Zero; - IntPtr iconBig = new IntPtr(1); - IntPtr iconSmall2 = new IntPtr(2); - - IntPtr iconHandle; - if (Conf.UseLargeIcons) - { - iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); - if (iconHandle == IntPtr.Zero) - { - iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICON); - } - } - else - { - iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconSmall2, IntPtr.Zero); - } - - if (iconHandle == IntPtr.Zero) - { - iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconSmall, IntPtr.Zero); - } - - if (iconHandle == IntPtr.Zero) - { - iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICONSM); - } - - if (iconHandle == IntPtr.Zero) - { - iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); - } - - if (iconHandle == IntPtr.Zero) - { - iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICON); - } - - if (iconHandle == IntPtr.Zero) - { - return null; - } - - Icon icon = Icon.FromHandle(iconHandle); - - return icon; - } - - /// - /// Use this to make remove internal windows, like the mainform and the captureforms, invisible - /// - /// - public static void RegisterIgnoreHandle(IntPtr ignoreHandle) - { - IgnoreHandles.Add(ignoreHandle); - } - - /// - /// Use this to remove the with RegisterIgnoreHandle registered handle - /// - /// - public static void UnregisterIgnoreHandle(IntPtr ignoreHandle) - { - IgnoreHandles.Remove(ignoreHandle); - } - - public IList Children - { - get - { - if (_childWindows == null) - { - GetChildren(); - } - - return _childWindows; - } - } - - /// - /// Retrieve the child with matching classname - /// - public WindowDetails GetChild(string childClassname) - { - foreach (var child in Children) - { - if (childClassname.Equals(child.ClassName)) - { - return child; - } - } - - return null; - } - - public IntPtr ParentHandle - { - get - { - if (_parentHandle == IntPtr.Zero) - { - _parentHandle = User32.GetParent(Handle); - _parent = null; - } - - return _parentHandle; - } - set - { - if (_parentHandle != value) - { - _parentHandle = value; - _parent = null; - } - } - } - - /// - /// Get the parent of the current window - /// - /// WindowDetails of the parent, or null if none - public WindowDetails GetParent() - { - if (_parent == null) - { - if (_parentHandle == IntPtr.Zero) - { - _parentHandle = User32.GetParent(Handle); - } - - if (_parentHandle != IntPtr.Zero) - { - _parent = new WindowDetails(_parentHandle); - } - } - - return _parent; - } - - /// - /// Retrieve all the children, this only stores the children internally. - /// One should normally use the getter "Children" - /// - public IList GetChildren() - { - if (_childWindows == null) - { - return GetChildren(0); - } - - return _childWindows; - } - - /// - /// Retrieve all the children, this only stores the children internally, use the "Children" property for the value - /// - /// Specify how many levels we go in - public IList GetChildren(int levelsToGo) - { - if (_childWindows != null) - { - return _childWindows; - } - - _childWindows = new WindowsEnumerator().GetWindows(Handle, null).Items; - foreach (var childWindow in _childWindows) - { - if (levelsToGo > 0) - { - childWindow.GetChildren(levelsToGo - 1); - } - } - - return _childWindows; - } - - /// - /// Gets the window's handle - /// - public IntPtr Handle { get; } - - private string _text; - - /// - /// Gets the window's title (caption) - /// - public string Text - { - set => _text = value; - get - { - if (_text == null) - { - var title = new StringBuilder(260, 260); - User32.GetWindowText(Handle, title, title.Capacity); - _text = title.ToString(); - } - - return _text; - } - } - - private string _className; - - /// - /// Gets the window's class name. - /// - public string ClassName => _className ??= GetClassName(Handle); - - /// - /// Gets/Sets whether the window is iconic (minimized) or not. - /// - public bool Iconic - { - get - { - if (IsMetroApp) - { - return !Visible; - } - - return User32.IsIconic(Handle) || Location.X <= -32000; - } - set - { - if (value) - { - User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MINIMIZE, IntPtr.Zero); - } - else - { - User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_RESTORE, IntPtr.Zero); - } - } - } - - /// - /// Gets/Sets whether the window is maximized or not. - /// - public bool Maximised - { - get - { - if (IsApp) - { - if (Visible) - { - Rectangle windowRectangle = WindowRectangle; - foreach (var screen in Screen.AllScreens) - { - if (screen.Bounds.Contains(windowRectangle)) - { - if (windowRectangle.Equals(screen.Bounds)) - { - return true; - } - } - } - } - - return false; - } - - return User32.IsZoomed(Handle); - } - set - { - if (value) - { - User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MAXIMIZE, IntPtr.Zero); - } - else - { - User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MINIMIZE, IntPtr.Zero); - } - } - } - - /// - /// Returns if this window is cloaked - /// - public bool IsCloaked - { - get => DWM.IsWindowCloaked(Handle); - } - - /// - /// Gets whether the window is visible. - /// - public bool Visible - { - get - { - // Tip from Raymond Chen https://devblogs.microsoft.com/oldnewthing/20200302-00/?p=103507 - if (IsCloaked) - { - return false; - } - - if (IsApp) - { - Rectangle windowRectangle = WindowRectangle; - foreach (Screen screen in Screen.AllScreens) - { - if (screen.Bounds.Contains(windowRectangle)) - { - if (windowRectangle.Equals(screen.Bounds)) - { - // Fullscreen, it's "visible" when AppVisibilityOnMonitor says yes - // Although it might be the other App, this is not "very" important - RECT rect = new RECT(screen.Bounds); - IntPtr monitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONULL); - if (monitor != IntPtr.Zero) - { - MONITOR_APP_VISIBILITY? monitorAppVisibility = AppVisibility?.GetAppVisibilityOnMonitor(monitor); - //LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds); - if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) - { - return true; - } - } - } - else - { - // Is only partly on the screen, when this happens the app is always visible! - return true; - } - } - } - - return false; - } - - if (IsGutter) - { - // gutter is only made available when it's visible - return true; - } - - if (IsAppLauncher) - { - return IsAppLauncherVisible; - } - - return User32.IsWindowVisible(Handle); - } - } - - public bool HasParent - { - get - { - GetParent(); - return _parentHandle != IntPtr.Zero; - } - } - - public int ProcessId - { - get - { - User32.GetWindowThreadProcessId(Handle, out var processId); - return processId; - } - } - - public Process Process - { - get - { - try - { - User32.GetWindowThreadProcessId(Handle, out var processId); - return Process.GetProcessById(processId); - } - catch (Exception ex) - { - Log.Warn(ex); - } - - return null; - } - } - - private Rectangle _previousWindowRectangle = Rectangle.Empty; - private long _lastWindowRectangleRetrieveTime; - private const long CacheTime = TimeSpan.TicksPerSecond * 2; - - /// - /// Gets the bounding rectangle of the window - /// - public Rectangle WindowRectangle - { - get - { - // Try to return a cached value - long now = DateTime.Now.Ticks; - if (_previousWindowRectangle.IsEmpty || !_frozen) - { - if (!_previousWindowRectangle.IsEmpty && now - _lastWindowRectangleRetrieveTime <= CacheTime) - { - return _previousWindowRectangle; - } - - Rectangle windowRect = Rectangle.Empty; - if (DWM.IsDwmEnabled) - { - bool gotFrameBounds = GetExtendedFrameBounds(out windowRect); - if (IsApp) - { - // Pre-Cache for maximized call, this is only on Windows 8 apps (full screen) - if (gotFrameBounds) - { - _previousWindowRectangle = windowRect; - _lastWindowRectangleRetrieveTime = now; - } - } - - if (gotFrameBounds && WindowsVersion.IsWindows10OrLater && !Maximised) - { - // Somehow DWM doesn't calculate it corectly, there is a 1 pixel border around the capture - // Remove this border, currently it's fixed but TODO: Make it depend on the OS? - windowRect.Inflate(Conf.Win10BorderCrop); - _previousWindowRectangle = windowRect; - _lastWindowRectangleRetrieveTime = now; - return windowRect; - } - } - - if (windowRect.IsEmpty) - { - if (!GetWindowRect(out windowRect)) - { - Win32Error error = Win32.GetLastErrorCode(); - Log.WarnFormat("Couldn't retrieve the windows rectangle: {0}", Win32.GetMessage(error)); - } - } - - // Correction for maximized windows, only if it's not an app - if (!HasParent && !IsApp && Maximised) - { - // Only if the border size can be retrieved - if (GetBorderSize(out var size)) - { - windowRect = new Rectangle(windowRect.X + size.Width, windowRect.Y + size.Height, windowRect.Width - (2 * size.Width), - windowRect.Height - (2 * size.Height)); - } - } - - _lastWindowRectangleRetrieveTime = now; - // Try to return something valid, by getting returning the previous size if the window doesn't have a Rectangle anymore - if (windowRect.IsEmpty) - { - return _previousWindowRectangle; - } - - _previousWindowRectangle = windowRect; - return windowRect; - } - - return _previousWindowRectangle; - } - } - - /// - /// Gets the location of the window relative to the screen. - /// - public Point Location - { - get - { - Rectangle tmpRectangle = WindowRectangle; - return new Point(tmpRectangle.Left, tmpRectangle.Top); - } - } - - /// - /// Gets the size of the window. - /// - public Size Size - { - get - { - Rectangle tmpRectangle = WindowRectangle; - return new Size(tmpRectangle.Right - tmpRectangle.Left, tmpRectangle.Bottom - tmpRectangle.Top); - } - } - - /// - /// Get the client rectangle, this is the part of the window inside the borders (drawable area) - /// - public Rectangle ClientRectangle - { - get - { - if (!GetClientRect(out var clientRect)) - { - Win32Error error = Win32.GetLastErrorCode(); - Log.WarnFormat("Couldn't retrieve the client rectangle for {0}, error: {1}", Text, Win32.GetMessage(error)); - } - - return clientRect; - } - } - - /// - /// Check if the supplied point lies in the window - /// - /// Point with the coordinates to check - /// true if the point lies within - public bool Contains(Point p) - { - return WindowRectangle.Contains(p); - } - - /// - /// Restores and Brings the window to the front, - /// assuming it is a visible application window. - /// - public void Restore() - { - if (Iconic) - { - User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_RESTORE, IntPtr.Zero); - } - - User32.BringWindowToTop(Handle); - User32.SetForegroundWindow(Handle); - // Make sure windows has time to perform the action - // TODO: this is BAD practice! - while (Iconic) - { - Application.DoEvents(); - } - } - - /// - /// Get / Set the WindowStyle - /// - public WindowStyleFlags WindowStyle - { - get => (WindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE); - set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE, new IntPtr((long) value)); - } - - /// - /// Get/Set the WindowPlacement - /// - public WindowPlacement WindowPlacement - { - get - { - var placement = WindowPlacement.Default; - User32.GetWindowPlacement(Handle, ref placement); - return placement; - } - set { User32.SetWindowPlacement(Handle, ref value); } - } - - /// - /// Get/Set the Extended WindowStyle - /// - public ExtendedWindowStyleFlags ExtendedWindowStyle - { - get => (ExtendedWindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_EXSTYLE); - set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_EXSTYLE, new IntPtr((uint) value)); - } - - /// - /// Capture Window with GDI+ - /// - /// The capture to fill - /// ICapture - public ICapture CaptureGdiWindow(ICapture capture) - { - Image capturedImage = PrintWindow(); - if (capturedImage != null) - { - capture.Image = capturedImage; - capture.Location = Location; - return capture; - } - - return null; - } - - /// - /// Capture DWM Window - /// - /// Capture to fill - /// Wanted WindowCaptureMode - /// True if auto mode is used - /// ICapture with the capture - public ICapture CaptureDwmWindow(ICapture capture, WindowCaptureMode windowCaptureMode, bool autoMode) - { - IntPtr thumbnailHandle = IntPtr.Zero; - Form tempForm = null; - bool tempFormShown = false; - try - { - tempForm = new Form - { - ShowInTaskbar = false, - FormBorderStyle = FormBorderStyle.None, - TopMost = true - }; - - // Register the Thumbnail - DWM.DwmRegisterThumbnail(tempForm.Handle, Handle, out thumbnailHandle); - - // Get the original size - DWM.DwmQueryThumbnailSourceSize(thumbnailHandle, out var sourceSize); - - if (sourceSize.Width <= 0 || sourceSize.Height <= 0) - { - return null; - } - - // Calculate the location of the temp form - Rectangle windowRectangle = WindowRectangle; - Point formLocation = windowRectangle.Location; - Size borderSize = new Size(); - bool doesCaptureFit = false; - if (!Maximised) - { - // Assume using it's own location - formLocation = windowRectangle.Location; - // TODO: Use Rectangle.Union! - using Region workingArea = new Region(Screen.PrimaryScreen.Bounds); - // Find the screen where the window is and check if it fits - foreach (Screen screen in Screen.AllScreens) - { - if (!Equals(screen, Screen.PrimaryScreen)) - { - workingArea.Union(screen.Bounds); - } - } - - // If the formLocation is not inside the visible area - if (!workingArea.AreRectangleCornersVisisble(windowRectangle)) - { - // If none found we find the biggest screen - foreach (Screen screen in Screen.AllScreens) - { - Rectangle newWindowRectangle = new Rectangle(screen.WorkingArea.Location, windowRectangle.Size); - if (workingArea.AreRectangleCornersVisisble(newWindowRectangle)) - { - formLocation = screen.Bounds.Location; - doesCaptureFit = true; - break; - } - } - } - else - { - doesCaptureFit = true; - } - } - else if (!WindowsVersion.IsWindows8OrLater) - { - //GetClientRect(out windowRectangle); - GetBorderSize(out borderSize); - formLocation = new Point(windowRectangle.X - borderSize.Width, windowRectangle.Y - borderSize.Height); - } - - tempForm.Location = formLocation; - tempForm.Size = sourceSize.ToSize(); - - // Prepare rectangle to capture from the screen. - Rectangle captureRectangle = new Rectangle(formLocation.X, formLocation.Y, sourceSize.Width, sourceSize.Height); - if (Maximised) - { - // Correct capture size for maximized window by offsetting the X,Y with the border size - // and subtracting the border from the size (2 times, as we move right/down for the capture without resizing) - captureRectangle.Inflate(borderSize.Width, borderSize.Height); - } - else - { - // TODO: Also 8.x? - if (WindowsVersion.IsWindows10OrLater) - { - captureRectangle.Inflate(Conf.Win10BorderCrop); - } - - if (autoMode) - { - // check if the capture fits - if (!doesCaptureFit) - { - // if GDI is allowed.. (a screenshot won't be better than we comes if we continue) - using Process thisWindowProcess = Process; - if (!IsMetroApp && WindowCapture.IsGdiAllowed(thisWindowProcess)) - { - // we return null which causes the capturing code to try another method. - return null; - } - } - } - } - - // Prepare the displaying of the Thumbnail - DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES - { - Opacity = 255, - Visible = true, - Destination = new RECT(0, 0, sourceSize.Width, sourceSize.Height) - }; - DWM.DwmUpdateThumbnailProperties(thumbnailHandle, ref props); - tempForm.Show(); - tempFormShown = true; - - // Intersect with screen - captureRectangle.Intersect(capture.ScreenBounds); - - // Destination bitmap for the capture - Bitmap capturedBitmap = null; - bool frozen = false; - try - { - // Check if we make a transparent capture - if (windowCaptureMode == WindowCaptureMode.AeroTransparent) - { - frozen = FreezeWindow(); - // Use white, later black to capture transparent - tempForm.BackColor = Color.White; - // Make sure everything is visible - tempForm.Refresh(); - Application.DoEvents(); - - try - { - using Bitmap whiteBitmap = WindowCapture.CaptureRectangle(captureRectangle); - // Apply a white color - tempForm.BackColor = Color.Black; - // Make sure everything is visible - tempForm.Refresh(); - if (!IsMetroApp) - { - // Make sure the application window is active, so the colors & buttons are right - ToForeground(); - } - - // Make sure all changes are processed and visible - Application.DoEvents(); - using Bitmap blackBitmap = WindowCapture.CaptureRectangle(captureRectangle); - capturedBitmap = ApplyTransparency(blackBitmap, whiteBitmap); - } - catch (Exception e) - { - Log.Debug("Exception: ", e); - // Some problem occurred, cleanup and make a normal capture - if (capturedBitmap != null) - { - capturedBitmap.Dispose(); - capturedBitmap = null; - } - } - } - - // If no capture up till now, create a normal capture. - if (capturedBitmap == null) - { - // Remove transparency, this will break the capturing - if (!autoMode) - { - tempForm.BackColor = Color.FromArgb(255, Conf.DWMBackgroundColor.R, Conf.DWMBackgroundColor.G, Conf.DWMBackgroundColor.B); - } - else - { - Color colorizationColor = DWM.ColorizationColor; - // Modify by losing the transparency and increasing the intensity (as if the background color is white) - colorizationColor = Color.FromArgb(255, (colorizationColor.R + 255) >> 1, (colorizationColor.G + 255) >> 1, (colorizationColor.B + 255) >> 1); - tempForm.BackColor = colorizationColor; - } - - // Make sure everything is visible - tempForm.Refresh(); - if (!IsMetroApp) - { - // Make sure the application window is active, so the colors & buttons are right - ToForeground(); - } - - // Make sure all changes are processed and visible - Application.DoEvents(); - // Capture from the screen - capturedBitmap = WindowCapture.CaptureRectangle(captureRectangle); - } - - if (capturedBitmap != null) - { - // Not needed for Windows 8 - if (!WindowsVersion.IsWindows8OrLater) - { - // Only if the Inivalue is set, not maximized and it's not a tool window. - if (Conf.WindowCaptureRemoveCorners && !Maximised && (ExtendedWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) == 0) - { - // Remove corners - if (!Image.IsAlphaPixelFormat(capturedBitmap.PixelFormat)) - { - Log.Debug("Changing pixelformat to Alpha for the RemoveCorners"); - Bitmap tmpBitmap = ImageHelper.Clone(capturedBitmap, PixelFormat.Format32bppArgb); - capturedBitmap.Dispose(); - capturedBitmap = tmpBitmap; - } - - RemoveCorners(capturedBitmap); - } - } - } - } - finally - { - // Make sure to ALWAYS unfreeze!! - if (frozen) - { - UnfreezeWindow(); - } - } - - capture.Image = capturedBitmap; - // Make sure the capture location is the location of the window, not the copy - capture.Location = Location; - } - finally - { - if (thumbnailHandle != IntPtr.Zero) - { - // Unregister (cleanup), as we are finished we don't need the form or the thumbnail anymore - DWM.DwmUnregisterThumbnail(thumbnailHandle); - } - - if (tempForm != null) - { - if (tempFormShown) - { - tempForm.Close(); - } - - tempForm.Dispose(); - tempForm = null; - } - } - - return capture; - } - - /// - /// Helper method to remove the corners from a DMW capture - /// - /// The bitmap to remove the corners from. - private void RemoveCorners(Bitmap image) - { - using IFastBitmap fastBitmap = FastBitmap.Create(image); - for (int y = 0; y < Conf.WindowCornerCutShape.Count; y++) - { - for (int x = 0; x < Conf.WindowCornerCutShape[y]; x++) - { - fastBitmap.SetColorAt(x, y, Color.Transparent); - fastBitmap.SetColorAt(image.Width - 1 - x, y, Color.Transparent); - fastBitmap.SetColorAt(image.Width - 1 - x, image.Height - 1 - y, Color.Transparent); - fastBitmap.SetColorAt(x, image.Height - 1 - y, Color.Transparent); - } - } - } - - /// - /// Apply transparency by comparing a transparent capture with a black and white background - /// A "Math.min" makes sure there is no overflow, but this could cause the picture to have shifted colors. - /// The pictures should have been taken without differency, except for the colors. - /// - /// Bitmap with the black image - /// Bitmap with the black image - /// Bitmap with transparency - private Bitmap ApplyTransparency(Bitmap blackBitmap, Bitmap whiteBitmap) - { - using IFastBitmap targetBuffer = FastBitmap.CreateEmpty(blackBitmap.Size, PixelFormat.Format32bppArgb, Color.Transparent); - targetBuffer.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution); - using (IFastBitmap blackBuffer = FastBitmap.Create(blackBitmap)) - { - using IFastBitmap whiteBuffer = FastBitmap.Create(whiteBitmap); - for (int y = 0; y < blackBuffer.Height; y++) - { - for (int x = 0; x < blackBuffer.Width; x++) - { - Color c0 = blackBuffer.GetColorAt(x, y); - Color c1 = whiteBuffer.GetColorAt(x, y); - // Calculate alpha as double in range 0-1 - int alpha = c0.R - c1.R + 255; - if (alpha == 255) - { - // Alpha == 255 means no change! - targetBuffer.SetColorAt(x, y, c0); - } - else if (alpha == 0) - { - // Complete transparency, use transparent pixel - targetBuffer.SetColorAt(x, y, Color.Transparent); - } - else - { - // Calculate original color - byte originalAlpha = (byte) Math.Min(255, alpha); - var alphaFactor = alpha / 255d; - //LOG.DebugFormat("Alpha {0} & c0 {1} & c1 {2}", alpha, c0, c1); - byte originalRed = (byte) Math.Min(255, c0.R / alphaFactor); - byte originalGreen = (byte) Math.Min(255, c0.G / alphaFactor); - byte originalBlue = (byte) Math.Min(255, c0.B / alphaFactor); - Color originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue); - //Color originalColor = Color.FromArgb(originalAlpha, originalRed, c0.G, c0.B); - targetBuffer.SetColorAt(x, y, originalColor); - } - } - } - } - - return targetBuffer.UnlockAndReturnBitmap(); - } - - /// - /// Helper method to get the window size for DWM Windows - /// - /// out Rectangle - /// bool true if it worked - private bool GetExtendedFrameBounds(out Rectangle rectangle) - { - int result = DWM.DwmGetWindowAttribute(Handle, DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out RECT rect, Marshal.SizeOf(typeof(RECT))); - if (result >= 0) - { - rectangle = rect.ToRectangle(); - return true; - } - - rectangle = Rectangle.Empty; - return false; - } - - /// - /// Helper method to get the window size for GDI Windows - /// - /// out Rectangle - /// bool true if it worked - private bool GetClientRect(out Rectangle rectangle) - { - var windowInfo = new WindowInfo(); - // Get the Window Info for this window - bool result = User32.GetWindowInfo(Handle, ref windowInfo); - rectangle = result ? windowInfo.rcClient.ToRectangle() : Rectangle.Empty; - return result; - } - - /// - /// Helper method to get the window size for GDI Windows - /// - /// out Rectangle - /// bool true if it worked - private bool GetWindowRect(out Rectangle rectangle) - { - var windowInfo = new WindowInfo(); - // Get the Window Info for this window - bool result = User32.GetWindowInfo(Handle, ref windowInfo); - rectangle = result ? windowInfo.rcWindow.ToRectangle() : Rectangle.Empty; - return result; - } - - /// - /// Helper method to get the Border size for GDI Windows - /// - /// out Size - /// bool true if it worked - private bool GetBorderSize(out Size size) - { - var windowInfo = new WindowInfo(); - // Get the Window Info for this window - bool result = User32.GetWindowInfo(Handle, ref windowInfo); - size = result ? new Size((int) windowInfo.cxWindowBorders, (int) windowInfo.cyWindowBorders) : Size.Empty; - return result; - } - - /// - /// Set the window as foreground window - /// - /// hWnd of the window to bring to the foreground - public static void ToForeground(IntPtr hWnd) - { - var foregroundWindow = User32.GetForegroundWindow(); - if (hWnd == foregroundWindow) - { - return; - } - - var window = new WindowDetails(hWnd); - // Nothing we can do if it's not visible! - if (!window.Visible) - { - return; - } - - var threadId1 = User32.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero); - var threadId2 = User32.GetWindowThreadProcessId(hWnd, IntPtr.Zero); - - // Show window in foreground. - if (threadId1 != threadId2) - { - User32.AttachThreadInput(threadId1, threadId2, 1); - User32.SetForegroundWindow(hWnd); - User32.AttachThreadInput(threadId1, threadId2, 0); - } - else - { - User32.SetForegroundWindow(hWnd); - } - - User32.BringWindowToTop(hWnd); - - if (window.Iconic) - { - window.Iconic = false; - } - } - - /// - /// Set the window as foreground window - /// - public void ToForeground() - { - ToForeground(Handle); - } - - /// - /// Get the region for a window - /// - private Region GetRegion() - { - using (SafeRegionHandle region = GDI32.CreateRectRgn(0, 0, 0, 0)) - { - if (!region.IsInvalid) - { - RegionResult result = User32.GetWindowRgn(Handle, region); - if (result != RegionResult.REGION_ERROR && result != RegionResult.REGION_NULLREGION) - { - return Region.FromHrgn(region.DangerousGetHandle()); - } - } - } - - return null; - } - - private bool CanFreezeOrUnfreeze(string titleOrProcessname) - { - if (string.IsNullOrEmpty(titleOrProcessname)) - { - return false; - } - - if (titleOrProcessname.ToLower().Contains("greenshot")) - { - return false; - } - - foreach (string excludeProcess in ExcludeProcessesFromFreeze) - { - if (titleOrProcessname.ToLower().Contains(excludeProcess)) - { - return false; - } - } - - return true; - } - - /// - /// Freezes the process belonging to the window - /// Warning: Use only if no other way!! - /// - private bool FreezeWindow() - { - bool frozen = false; - using (Process proc = Process.GetProcessById(ProcessId)) - { - string processName = proc.ProcessName; - if (!CanFreezeOrUnfreeze(processName)) - { - Log.DebugFormat("Not freezing {0}", processName); - return false; - } - - if (!CanFreezeOrUnfreeze(Text)) - { - Log.DebugFormat("Not freezing {0}", processName); - return false; - } - - Log.DebugFormat("Freezing process: {0}", processName); - - - foreach (ProcessThread pT in proc.Threads) - { - IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); - - if (pOpenThread == IntPtr.Zero) - { - break; - } - - frozen = true; - Kernel32.SuspendThread(pOpenThread); - pT.Dispose(); - } - } - - return frozen; - } - - /// - /// Unfreeze the process belonging to the window - /// - public void UnfreezeWindow() - { - using Process proc = Process.GetProcessById(ProcessId); - string processName = proc.ProcessName; - if (!CanFreezeOrUnfreeze(processName)) - { - Log.DebugFormat("Not unfreezing {0}", processName); - return; - } - - if (!CanFreezeOrUnfreeze(Text)) - { - Log.DebugFormat("Not unfreezing {0}", processName); - return; - } - - Log.DebugFormat("Unfreezing process: {0}", processName); - - foreach (ProcessThread pT in proc.Threads) - { - IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); - - if (pOpenThread == IntPtr.Zero) - { - break; - } - - Kernel32.ResumeThread(pOpenThread); - } - } - - /// - /// Return an Image representing the Window! - /// As GDI+ draws it, it will be without Aero borders! - /// - public Image PrintWindow() - { - Rectangle windowRect = WindowRectangle; - // Start the capture - Exception exceptionOccured = null; - Image returnImage; - using (Region region = GetRegion()) - { - PixelFormat pixelFormat = PixelFormat.Format24bppRgb; - // Only use 32 bpp ARGB when the window has a region - if (region != null) - { - pixelFormat = PixelFormat.Format32bppArgb; - } - - returnImage = new Bitmap(windowRect.Width, windowRect.Height, pixelFormat); - using Graphics graphics = Graphics.FromImage(returnImage); - using (SafeDeviceContextHandle graphicsDc = graphics.GetSafeDeviceContext()) - { - bool printSucceeded = User32.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), 0x0); - if (!printSucceeded) - { - // something went wrong, most likely a "0x80004005" (Acess Denied) when using UAC - exceptionOccured = User32.CreateWin32Exception("PrintWindow"); - } - } - - // Apply the region "transparency" - if (region != null && !region.IsEmpty(graphics)) - { - graphics.ExcludeClip(region); - graphics.Clear(Color.Transparent); - } - - graphics.Flush(); - } - - // Return null if error - if (exceptionOccured != null) - { - Log.ErrorFormat("Error calling print window: {0}", exceptionOccured.Message); - returnImage.Dispose(); - return null; - } - - if (!HasParent && Maximised) - { - Log.Debug("Correcting for maximalization"); - GetBorderSize(out var borderSize); - Rectangle borderRectangle = new Rectangle(borderSize.Width, borderSize.Height, windowRect.Width - (2 * borderSize.Width), - windowRect.Height - (2 * borderSize.Height)); - ImageHelper.Crop(ref returnImage, ref borderRectangle); - } - - return returnImage; - } - - /// - /// Constructs a new instance of this class for - /// the specified Window Handle. - /// - /// The Window Handle - public WindowDetails(IntPtr hWnd) - { - Handle = hWnd; - } - - /// - /// Gets an instance of the current active foreground window - /// - /// WindowDetails of the current window - public static WindowDetails GetActiveWindow() - { - IntPtr hWnd = User32.GetForegroundWindow(); - if (hWnd != IntPtr.Zero) - { - if (IgnoreHandles.Contains(hWnd)) - { - return GetDesktopWindow(); - } - - WindowDetails activeWindow = new WindowDetails(hWnd); - // Invisible Windows should not be active - if (!activeWindow.Visible) - { - return GetDesktopWindow(); - } - - return activeWindow; - } - - return null; - } - - /// - /// Gets the Desktop window - /// - /// WindowDetails for the desktop window - public static WindowDetails GetDesktopWindow() - { - return new WindowDetails(User32.GetDesktopWindow()); - } - - /// - /// Get all the top level windows - /// - /// List of WindowDetails with all the top level windows - public static IList GetAllWindows() - { - return GetAllWindows(null); - } - - /// - /// Get all the top level windows, with matching classname - /// - /// List WindowDetails with all the top level windows - public static IList GetAllWindows(string classname) - { - return new WindowsEnumerator().GetWindows(IntPtr.Zero, classname).Items; - } - - /// - /// Recursive "find children which" - /// - /// point to check for - /// - public WindowDetails FindChildUnderPoint(Point point) - { - if (!Contains(point)) - { - return null; - } - - var rect = WindowRectangle; - // If the mouse it at the edge, take the whole window - if (rect.X == point.X || rect.Y == point.Y || rect.Right == point.X || rect.Bottom == point.Y) - { - return this; - } - - // Look into the child windows - foreach (var childWindow in Children) - { - if (childWindow.Contains(point)) - { - return childWindow.FindChildUnderPoint(point); - } - } - - return this; - } - - /// - /// Retrieves the classname for a hWnd - /// - /// IntPtr with the windows handle - /// String with ClassName - public static string GetClassName(IntPtr hWnd) - { - var classNameBuilder = new StringBuilder(260, 260); - User32.GetClassName(hWnd, classNameBuilder, classNameBuilder.Capacity); - return classNameBuilder.ToString(); - } - - /// - /// Helper method to decide if a top level window is visible - /// - /// - /// - /// - private static bool IsVisible(WindowDetails window, Rectangle screenBounds) - { - // Ignore invisible - if (!window.Visible) - { - return false; - } - - // Ignore minimized - if (window.Iconic) - { - return false; - } - - if (IgnoreClasses.Contains(window.ClassName)) - { - return false; - } - - // On windows which are visible on the screen - var windowRect = window.WindowRectangle; - windowRect.Intersect(screenBounds); - if (windowRect.IsEmpty) - { - return false; - } - - // Skip everything which is not rendered "normally", trying to fix BUG-2017 - var exWindowStyle = window.ExtendedWindowStyle; - if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) - { - return false; - } - - return true; - } - - /// - /// Get all the visible top level windows - /// - /// List WindowDetails with all the visible top level windows - public static IEnumerable GetVisibleWindows() - { - Rectangle screenBounds = WindowCapture.GetScreenBounds(); - foreach (var window in GetAppWindows()) - { - if (IsVisible(window, screenBounds)) - { - yield return window; - } - } - - foreach (var window in GetAllWindows()) - { - if (IsVisible(window, screenBounds)) - { - yield return window; - } - } - } - - /// - /// Get the WindowDetails for all Metro Apps - /// These are all Windows with Classname "Windows.UI.Core.CoreWindow" - /// - /// List WindowDetails with visible metro apps - public static IEnumerable GetAppWindows() - { - // if the appVisibility != null we have Windows 8. - if (AppVisibility == null) - { - yield break; - } - - var nextHandle = User32.FindWindow(AppWindowClass, null); - while (nextHandle != IntPtr.Zero) - { - var metroApp = new WindowDetails(nextHandle); - yield return metroApp; - // Check if we have a gutter! - if (metroApp.Visible && !metroApp.Maximised) - { - var gutterHandle = User32.FindWindow(GutterClass, null); - if (gutterHandle != IntPtr.Zero) - { - yield return new WindowDetails(gutterHandle); - } - } - - nextHandle = User32.FindWindowEx(IntPtr.Zero, nextHandle, AppWindowClass, null); - } - } - - /// - /// Check if the window is a top level - /// - /// WindowDetails - /// bool - private static bool IsTopLevel(WindowDetails window) - { - if (window.IsCloaked) - { - return false; - } - - // Windows without size - if (window.WindowRectangle.Size.Width * window.WindowRectangle.Size.Height == 0) - { - return false; - } - - if (window.HasParent) - { - return false; - } - - var exWindowStyle = window.ExtendedWindowStyle; - if ((exWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) != 0) - { - return false; - } - - // Skip everything which is not rendered "normally", trying to fix BUG-2017 - if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) - { - return false; - } - - // Skip preview windows, like the one from Firefox - if ((window.WindowStyle & WindowStyleFlags.WS_VISIBLE) == 0) - { - return false; - } - - // Ignore windows without title - if (window.Text.Length == 0) - { - return false; - } - - if (IgnoreClasses.Contains(window.ClassName)) - { - return false; - } - - if (!(window.Visible || window.Iconic)) - { - return false; - } - - return !window.IsBackgroundWin10App; - } - - /// - /// Get all the top level windows - /// - /// List WindowDetails with all the top level windows - public static IEnumerable GetTopLevelWindows() - { - foreach (var possibleTopLevel in GetAppWindows()) - { - if (IsTopLevel(possibleTopLevel)) - { - yield return possibleTopLevel; - } - } - - foreach (var possibleTopLevel in GetAllWindows()) - { - if (IsTopLevel(possibleTopLevel)) - { - yield return possibleTopLevel; - } - } - } - - /// - /// Find a window belonging to the same process as the supplied window. - /// - /// - /// - public static WindowDetails GetLinkedWindow(WindowDetails windowToLinkTo) - { - int processIdSelectedWindow = windowToLinkTo.ProcessId; - foreach (var window in GetAllWindows()) - { - // Ignore windows without title - if (window.Text.Length == 0) - { - continue; - } - - // Ignore invisible - if (!window.Visible) - { - continue; - } - - if (window.Handle == windowToLinkTo.Handle) - { - continue; - } - - if (window.Iconic) - { - continue; - } - - // Windows without size - Size windowSize = window.WindowRectangle.Size; - if (windowSize.Width == 0 || windowSize.Height == 0) - { - continue; - } - - if (window.ProcessId == processIdSelectedWindow) - { - Log.InfoFormat("Found window {0} belonging to same process as the window {1}", window.Text, windowToLinkTo.Text); - return window; - } - } - - return null; - } - - /// - /// Helper method to "active" all windows that are not in the supplied list. - /// One should preferably call "GetVisibleWindows" for the oldWindows. - /// - /// List WindowDetails with old windows - public static void ActiveNewerWindows(IEnumerable oldWindows) - { - var oldWindowsList = new List(oldWindows); - foreach (var window in GetVisibleWindows()) - { - if (!oldWindowsList.Contains(window)) - { - window.ToForeground(); - } - } - } - - /// - /// Get the AppLauncher - /// - /// - public static WindowDetails GetAppLauncher() - { - // Only if Windows 8 (or higher) - if (AppVisibility == null) - { - return null; - } - - IntPtr appLauncher = User32.FindWindow(ApplauncherClass, null); - if (appLauncher != IntPtr.Zero) - { - return new WindowDetails(appLauncher); - } - - return null; - } - - /// - /// Return true if the metro-app-launcher is visible - /// - /// - public static bool IsAppLauncherVisible - { - get - { - if (AppVisibility != null) - { - return AppVisibility.IsLauncherVisible; - } - - return false; - } - } - - /// - /// Make a string representation of the window details - /// - /// string - public override string ToString() - { - var result = new StringBuilder(); - result.AppendLine($"Text: {Text}"); - result.AppendLine($"ClassName: {ClassName}"); - result.AppendLine($"ExtendedWindowStyle: {ExtendedWindowStyle}"); - result.AppendLine($"WindowStyle: {WindowStyle}"); - result.AppendLine($"Size: {WindowRectangle.Size}"); - result.AppendLine($"HasParent: {HasParent}"); - result.AppendLine($"IsWin10App: {IsWin10App}"); - result.AppendLine($"IsApp: {IsApp}"); - result.AppendLine($"Visible: {Visible}"); - result.AppendLine($"IsWindowVisible: {User32.IsWindowVisible(Handle)}"); - result.AppendLine($"IsCloaked: {IsCloaked}"); - result.AppendLine($"Iconic: {Iconic}"); - result.AppendLine($"IsBackgroundWin10App: {IsBackgroundWin10App}"); - if (HasChildren) - { - result.AppendLine($"Children classes: {string.Join(",", Children.Select(c => c.ClassName))}"); - } - - return result.ToString(); - } - } +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interop; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// Code for handling with "windows" + /// Main code is taken from vbAccelerator, location: + /// http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows/Enumerating_Windows/article.asp + /// but a LOT of changes/enhancements were made to adapt it for Greenshot. + /// + /// Provides details about a Window returned by the enumeration + /// + public class WindowDetails : IEquatable + { + private const string AppWindowClass = "Windows.UI.Core.CoreWindow"; //Used for Windows 8(.1) + private const string AppFrameWindowClass = "ApplicationFrameWindow"; // Windows 10 uses ApplicationFrameWindow + private const string ApplauncherClass = "ImmersiveLauncher"; + private const string GutterClass = "ImmersiveGutter"; + + private static readonly IList IgnoreClasses = new List(new[] + { + "Progman", "Button", "Dwm" + }); //"MS-SDIa" + + private static readonly ILog Log = LogManager.GetLogger(typeof(WindowDetails)); + private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); + private static readonly IList IgnoreHandles = new List(); + private static readonly IList ExcludeProcessesFromFreeze = new List(); + private static readonly IAppVisibility AppVisibility; + + static WindowDetails() + { + try + { + // Only try to instantiate when Windows 8 or later. + if (WindowsVersion.IsWindows8OrLater) + { + AppVisibility = COMWrapper.CreateInstance(); + } + } + catch (Exception ex) + { + Log.WarnFormat("Couldn't create instance of IAppVisibility: {0}", ex.Message); + } + } + + public static void AddProcessToExcludeFromFreeze(string processName) + { + if (!ExcludeProcessesFromFreeze.Contains(processName)) + { + ExcludeProcessesFromFreeze.Add(processName); + } + } + + internal static bool IsIgnoreHandle(IntPtr handle) + { + return IgnoreHandles.Contains(handle); + } + + private IList _childWindows; + private IntPtr _parentHandle = IntPtr.Zero; + private WindowDetails _parent; + private bool _frozen; + + /// + /// This checks if the window is a Windows 8 App + /// For Windows 10 most normal code works, as it's hosted inside "ApplicationFrameWindow" + /// + public bool IsApp => AppWindowClass.Equals(ClassName); + + /// + /// This checks if the window is a Windows 10 App + /// For Windows 10 apps are hosted inside "ApplicationFrameWindow" + /// + public bool IsWin10App => AppFrameWindowClass.Equals(ClassName); + + /// + /// Check if this window belongs to a background app + /// + public bool IsBackgroundWin10App => WindowsVersion.IsWindows10OrLater && AppFrameWindowClass.Equals(ClassName) && + !Children.Any(window => string.Equals(window.ClassName, AppWindowClass)); + + /// + /// Check if the window is the metro gutter (sizeable separator) + /// + public bool IsGutter => GutterClass.Equals(ClassName); + + /// + /// Test if this window is for the App-Launcher + /// + public bool IsAppLauncher => ApplauncherClass.Equals(ClassName); + + /// + /// Check if this window is the window of a metro app + /// + public bool IsMetroApp => IsAppLauncher || IsApp; + + /// + /// To allow items to be compared, the hash code + /// is set to the Window handle, so two EnumWindowsItem + /// objects for the same Window will be equal. + /// + /// The Window Handle for this window + public override int GetHashCode() + { + return Handle.ToInt32(); + } + + public override bool Equals(object right) + { + return Equals(right as WindowDetails); + } + + /// + /// Compare two windows details + /// + /// + /// + public bool Equals(WindowDetails other) + { + if (other is null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (GetType() != other.GetType()) + { + return false; + } + + return other.Handle == Handle; + } + + /// + /// Check if the window has children + /// + public bool HasChildren => (_childWindows != null) && (_childWindows.Count > 0); + + /// + /// Freeze information updates + /// + public void FreezeDetails() + { + _frozen = true; + } + + /// + /// Make the information update again. + /// + public void UnfreezeDetails() + { + _frozen = false; + } + + /// + /// Get the file path to the exe for the process which owns this window + /// + public string ProcessPath + { + get + { + if (Handle == IntPtr.Zero) + { + // not a valid window handle + return string.Empty; + } + + // Get the process id + User32.GetWindowThreadProcessId(Handle, out var processId); + return Kernel32.GetProcessPath(processId); + } + } + + + /// + /// Get the icon belonging to the process + /// + public Image DisplayIcon + { + get + { + try + { + using var appIcon = GetAppIcon(Handle); + if (appIcon != null) + { + return appIcon.ToBitmap(); + } + } + catch (Exception ex) + { + Log.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); + Log.Warn(ex); + } + + if (IsMetroApp) + { + // No method yet to get the metro icon + return null; + } + + try + { + return PluginUtils.GetCachedExeIcon(ProcessPath, 0); + } + catch (Exception ex) + { + Log.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); + Log.Warn(ex); + } + + return null; + } + } + + /// + /// Get the icon for a hWnd + /// + /// + /// + private static Icon GetAppIcon(IntPtr hWnd) + { + IntPtr iconSmall = IntPtr.Zero; + IntPtr iconBig = new IntPtr(1); + IntPtr iconSmall2 = new IntPtr(2); + + IntPtr iconHandle; + if (Conf.UseLargeIcons) + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICON); + } + } + else + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconSmall2, IntPtr.Zero); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconSmall, IntPtr.Zero); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICONSM); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICON); + } + + if (iconHandle == IntPtr.Zero) + { + return null; + } + + Icon icon = Icon.FromHandle(iconHandle); + + return icon; + } + + /// + /// Use this to make remove internal windows, like the mainform and the captureforms, invisible + /// + /// + public static void RegisterIgnoreHandle(IntPtr ignoreHandle) + { + IgnoreHandles.Add(ignoreHandle); + } + + /// + /// Use this to remove the with RegisterIgnoreHandle registered handle + /// + /// + public static void UnregisterIgnoreHandle(IntPtr ignoreHandle) + { + IgnoreHandles.Remove(ignoreHandle); + } + + public IList Children + { + get + { + if (_childWindows == null) + { + GetChildren(); + } + + return _childWindows; + } + } + + /// + /// Retrieve the child with matching classname + /// + public WindowDetails GetChild(string childClassname) + { + foreach (var child in Children) + { + if (childClassname.Equals(child.ClassName)) + { + return child; + } + } + + return null; + } + + public IntPtr ParentHandle + { + get + { + if (_parentHandle == IntPtr.Zero) + { + _parentHandle = User32.GetParent(Handle); + _parent = null; + } + + return _parentHandle; + } + set + { + if (_parentHandle != value) + { + _parentHandle = value; + _parent = null; + } + } + } + + /// + /// Get the parent of the current window + /// + /// WindowDetails of the parent, or null if none + public WindowDetails GetParent() + { + if (_parent == null) + { + if (_parentHandle == IntPtr.Zero) + { + _parentHandle = User32.GetParent(Handle); + } + + if (_parentHandle != IntPtr.Zero) + { + _parent = new WindowDetails(_parentHandle); + } + } + + return _parent; + } + + /// + /// Retrieve all the children, this only stores the children internally. + /// One should normally use the getter "Children" + /// + public IList GetChildren() + { + if (_childWindows == null) + { + return GetChildren(0); + } + + return _childWindows; + } + + /// + /// Retrieve all the children, this only stores the children internally, use the "Children" property for the value + /// + /// Specify how many levels we go in + public IList GetChildren(int levelsToGo) + { + if (_childWindows != null) + { + return _childWindows; + } + + _childWindows = new WindowsEnumerator().GetWindows(Handle, null).Items; + foreach (var childWindow in _childWindows) + { + if (levelsToGo > 0) + { + childWindow.GetChildren(levelsToGo - 1); + } + } + + return _childWindows; + } + + /// + /// Gets the window's handle + /// + public IntPtr Handle { get; } + + private string _text; + + /// + /// Gets the window's title (caption) + /// + public string Text + { + set => _text = value; + get + { + if (_text == null) + { + var title = new StringBuilder(260, 260); + User32.GetWindowText(Handle, title, title.Capacity); + _text = title.ToString(); + } + + return _text; + } + } + + private string _className; + + /// + /// Gets the window's class name. + /// + public string ClassName => _className ??= GetClassName(Handle); + + /// + /// Gets/Sets whether the window is iconic (minimized) or not. + /// + public bool Iconic + { + get + { + if (IsMetroApp) + { + return !Visible; + } + + return User32.IsIconic(Handle) || Location.X <= -32000; + } + set + { + if (value) + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MINIMIZE, IntPtr.Zero); + } + else + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_RESTORE, IntPtr.Zero); + } + } + } + + /// + /// Gets/Sets whether the window is maximized or not. + /// + public bool Maximised + { + get + { + if (IsApp) + { + if (Visible) + { + Rectangle windowRectangle = WindowRectangle; + foreach (var screen in Screen.AllScreens) + { + if (screen.Bounds.Contains(windowRectangle)) + { + if (windowRectangle.Equals(screen.Bounds)) + { + return true; + } + } + } + } + + return false; + } + + return User32.IsZoomed(Handle); + } + set + { + if (value) + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MAXIMIZE, IntPtr.Zero); + } + else + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MINIMIZE, IntPtr.Zero); + } + } + } + + /// + /// Returns if this window is cloaked + /// + public bool IsCloaked + { + get => DWM.IsWindowCloaked(Handle); + } + + /// + /// Gets whether the window is visible. + /// + public bool Visible + { + get + { + // Tip from Raymond Chen https://devblogs.microsoft.com/oldnewthing/20200302-00/?p=103507 + if (IsCloaked) + { + return false; + } + + if (IsApp) + { + Rectangle windowRectangle = WindowRectangle; + foreach (Screen screen in Screen.AllScreens) + { + if (screen.Bounds.Contains(windowRectangle)) + { + if (windowRectangle.Equals(screen.Bounds)) + { + // Fullscreen, it's "visible" when AppVisibilityOnMonitor says yes + // Although it might be the other App, this is not "very" important + RECT rect = new RECT(screen.Bounds); + IntPtr monitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONULL); + if (monitor != IntPtr.Zero) + { + MONITOR_APP_VISIBILITY? monitorAppVisibility = AppVisibility?.GetAppVisibilityOnMonitor(monitor); + //LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds); + if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) + { + return true; + } + } + } + else + { + // Is only partly on the screen, when this happens the app is always visible! + return true; + } + } + } + + return false; + } + + if (IsGutter) + { + // gutter is only made available when it's visible + return true; + } + + if (IsAppLauncher) + { + return IsAppLauncherVisible; + } + + return User32.IsWindowVisible(Handle); + } + } + + public bool HasParent + { + get + { + GetParent(); + return _parentHandle != IntPtr.Zero; + } + } + + public int ProcessId + { + get + { + User32.GetWindowThreadProcessId(Handle, out var processId); + return processId; + } + } + + public Process Process + { + get + { + try + { + User32.GetWindowThreadProcessId(Handle, out var processId); + return Process.GetProcessById(processId); + } + catch (Exception ex) + { + Log.Warn(ex); + } + + return null; + } + } + + private Rectangle _previousWindowRectangle = Rectangle.Empty; + private long _lastWindowRectangleRetrieveTime; + private const long CacheTime = TimeSpan.TicksPerSecond * 2; + + /// + /// Gets the bounding rectangle of the window + /// + public Rectangle WindowRectangle + { + get + { + // Try to return a cached value + long now = DateTime.Now.Ticks; + if (_previousWindowRectangle.IsEmpty || !_frozen) + { + if (!_previousWindowRectangle.IsEmpty && now - _lastWindowRectangleRetrieveTime <= CacheTime) + { + return _previousWindowRectangle; + } + + Rectangle windowRect = Rectangle.Empty; + if (DWM.IsDwmEnabled) + { + bool gotFrameBounds = GetExtendedFrameBounds(out windowRect); + if (IsApp) + { + // Pre-Cache for maximized call, this is only on Windows 8 apps (full screen) + if (gotFrameBounds) + { + _previousWindowRectangle = windowRect; + _lastWindowRectangleRetrieveTime = now; + } + } + + if (gotFrameBounds && WindowsVersion.IsWindows10OrLater && !Maximised) + { + // Somehow DWM doesn't calculate it corectly, there is a 1 pixel border around the capture + // Remove this border, currently it's fixed but TODO: Make it depend on the OS? + windowRect.Inflate(Conf.Win10BorderCrop); + _previousWindowRectangle = windowRect; + _lastWindowRectangleRetrieveTime = now; + return windowRect; + } + } + + if (windowRect.IsEmpty) + { + if (!GetWindowRect(out windowRect)) + { + Win32Error error = Win32.GetLastErrorCode(); + Log.WarnFormat("Couldn't retrieve the windows rectangle: {0}", Win32.GetMessage(error)); + } + } + + // Correction for maximized windows, only if it's not an app + if (!HasParent && !IsApp && Maximised) + { + // Only if the border size can be retrieved + if (GetBorderSize(out var size)) + { + windowRect = new Rectangle(windowRect.X + size.Width, windowRect.Y + size.Height, windowRect.Width - (2 * size.Width), + windowRect.Height - (2 * size.Height)); + } + } + + _lastWindowRectangleRetrieveTime = now; + // Try to return something valid, by getting returning the previous size if the window doesn't have a Rectangle anymore + if (windowRect.IsEmpty) + { + return _previousWindowRectangle; + } + + _previousWindowRectangle = windowRect; + return windowRect; + } + + return _previousWindowRectangle; + } + } + + /// + /// Gets the location of the window relative to the screen. + /// + public Point Location + { + get + { + Rectangle tmpRectangle = WindowRectangle; + return new Point(tmpRectangle.Left, tmpRectangle.Top); + } + } + + /// + /// Gets the size of the window. + /// + public Size Size + { + get + { + Rectangle tmpRectangle = WindowRectangle; + return new Size(tmpRectangle.Right - tmpRectangle.Left, tmpRectangle.Bottom - tmpRectangle.Top); + } + } + + /// + /// Get the client rectangle, this is the part of the window inside the borders (drawable area) + /// + public Rectangle ClientRectangle + { + get + { + if (!GetClientRect(out var clientRect)) + { + Win32Error error = Win32.GetLastErrorCode(); + Log.WarnFormat("Couldn't retrieve the client rectangle for {0}, error: {1}", Text, Win32.GetMessage(error)); + } + + return clientRect; + } + } + + /// + /// Check if the supplied point lies in the window + /// + /// Point with the coordinates to check + /// true if the point lies within + public bool Contains(Point p) + { + return WindowRectangle.Contains(p); + } + + /// + /// Restores and Brings the window to the front, + /// assuming it is a visible application window. + /// + public void Restore() + { + if (Iconic) + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_RESTORE, IntPtr.Zero); + } + + User32.BringWindowToTop(Handle); + User32.SetForegroundWindow(Handle); + // Make sure windows has time to perform the action + // TODO: this is BAD practice! + while (Iconic) + { + Application.DoEvents(); + } + } + + /// + /// Get / Set the WindowStyle + /// + public WindowStyleFlags WindowStyle + { + get => (WindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE); + set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE, new IntPtr((long) value)); + } + + /// + /// Get/Set the WindowPlacement + /// + public WindowPlacement WindowPlacement + { + get + { + var placement = WindowPlacement.Default; + User32.GetWindowPlacement(Handle, ref placement); + return placement; + } + set { User32.SetWindowPlacement(Handle, ref value); } + } + + /// + /// Get/Set the Extended WindowStyle + /// + public ExtendedWindowStyleFlags ExtendedWindowStyle + { + get => (ExtendedWindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_EXSTYLE); + set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_EXSTYLE, new IntPtr((uint) value)); + } + + /// + /// Capture Window with GDI+ + /// + /// The capture to fill + /// ICapture + public ICapture CaptureGdiWindow(ICapture capture) + { + Image capturedImage = PrintWindow(); + if (capturedImage != null) + { + capture.Image = capturedImage; + capture.Location = Location; + return capture; + } + + return null; + } + + /// + /// Capture DWM Window + /// + /// Capture to fill + /// Wanted WindowCaptureMode + /// True if auto mode is used + /// ICapture with the capture + public ICapture CaptureDwmWindow(ICapture capture, WindowCaptureMode windowCaptureMode, bool autoMode) + { + IntPtr thumbnailHandle = IntPtr.Zero; + Form tempForm = null; + bool tempFormShown = false; + try + { + tempForm = new Form + { + ShowInTaskbar = false, + FormBorderStyle = FormBorderStyle.None, + TopMost = true + }; + + // Register the Thumbnail + DWM.DwmRegisterThumbnail(tempForm.Handle, Handle, out thumbnailHandle); + + // Get the original size + DWM.DwmQueryThumbnailSourceSize(thumbnailHandle, out var sourceSize); + + if (sourceSize.Width <= 0 || sourceSize.Height <= 0) + { + return null; + } + + // Calculate the location of the temp form + Rectangle windowRectangle = WindowRectangle; + Point formLocation = windowRectangle.Location; + Size borderSize = new Size(); + bool doesCaptureFit = false; + if (!Maximised) + { + // Assume using it's own location + formLocation = windowRectangle.Location; + // TODO: Use Rectangle.Union! + using Region workingArea = new Region(Screen.PrimaryScreen.Bounds); + // Find the screen where the window is and check if it fits + foreach (Screen screen in Screen.AllScreens) + { + if (!Equals(screen, Screen.PrimaryScreen)) + { + workingArea.Union(screen.Bounds); + } + } + + // If the formLocation is not inside the visible area + if (!workingArea.AreRectangleCornersVisisble(windowRectangle)) + { + // If none found we find the biggest screen + foreach (Screen screen in Screen.AllScreens) + { + Rectangle newWindowRectangle = new Rectangle(screen.WorkingArea.Location, windowRectangle.Size); + if (workingArea.AreRectangleCornersVisisble(newWindowRectangle)) + { + formLocation = screen.Bounds.Location; + doesCaptureFit = true; + break; + } + } + } + else + { + doesCaptureFit = true; + } + } + else if (!WindowsVersion.IsWindows8OrLater) + { + //GetClientRect(out windowRectangle); + GetBorderSize(out borderSize); + formLocation = new Point(windowRectangle.X - borderSize.Width, windowRectangle.Y - borderSize.Height); + } + + tempForm.Location = formLocation; + tempForm.Size = sourceSize.ToSize(); + + // Prepare rectangle to capture from the screen. + Rectangle captureRectangle = new Rectangle(formLocation.X, formLocation.Y, sourceSize.Width, sourceSize.Height); + if (Maximised) + { + // Correct capture size for maximized window by offsetting the X,Y with the border size + // and subtracting the border from the size (2 times, as we move right/down for the capture without resizing) + captureRectangle.Inflate(borderSize.Width, borderSize.Height); + } + else + { + // TODO: Also 8.x? + if (WindowsVersion.IsWindows10OrLater) + { + captureRectangle.Inflate(Conf.Win10BorderCrop); + } + + if (autoMode) + { + // check if the capture fits + if (!doesCaptureFit) + { + // if GDI is allowed.. (a screenshot won't be better than we comes if we continue) + using Process thisWindowProcess = Process; + if (!IsMetroApp && WindowCapture.IsGdiAllowed(thisWindowProcess)) + { + // we return null which causes the capturing code to try another method. + return null; + } + } + } + } + + // Prepare the displaying of the Thumbnail + DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES + { + Opacity = 255, + Visible = true, + Destination = new RECT(0, 0, sourceSize.Width, sourceSize.Height) + }; + DWM.DwmUpdateThumbnailProperties(thumbnailHandle, ref props); + tempForm.Show(); + tempFormShown = true; + + // Intersect with screen + captureRectangle.Intersect(capture.ScreenBounds); + + // Destination bitmap for the capture + Bitmap capturedBitmap = null; + bool frozen = false; + try + { + // Check if we make a transparent capture + if (windowCaptureMode == WindowCaptureMode.AeroTransparent) + { + frozen = FreezeWindow(); + // Use white, later black to capture transparent + tempForm.BackColor = Color.White; + // Make sure everything is visible + tempForm.Refresh(); + Application.DoEvents(); + + try + { + using Bitmap whiteBitmap = WindowCapture.CaptureRectangle(captureRectangle); + // Apply a white color + tempForm.BackColor = Color.Black; + // Make sure everything is visible + tempForm.Refresh(); + if (!IsMetroApp) + { + // Make sure the application window is active, so the colors & buttons are right + ToForeground(); + } + + // Make sure all changes are processed and visible + Application.DoEvents(); + using Bitmap blackBitmap = WindowCapture.CaptureRectangle(captureRectangle); + capturedBitmap = ApplyTransparency(blackBitmap, whiteBitmap); + } + catch (Exception e) + { + Log.Debug("Exception: ", e); + // Some problem occurred, cleanup and make a normal capture + if (capturedBitmap != null) + { + capturedBitmap.Dispose(); + capturedBitmap = null; + } + } + } + + // If no capture up till now, create a normal capture. + if (capturedBitmap == null) + { + // Remove transparency, this will break the capturing + if (!autoMode) + { + tempForm.BackColor = Color.FromArgb(255, Conf.DWMBackgroundColor.R, Conf.DWMBackgroundColor.G, Conf.DWMBackgroundColor.B); + } + else + { + Color colorizationColor = DWM.ColorizationColor; + // Modify by losing the transparency and increasing the intensity (as if the background color is white) + colorizationColor = Color.FromArgb(255, (colorizationColor.R + 255) >> 1, (colorizationColor.G + 255) >> 1, (colorizationColor.B + 255) >> 1); + tempForm.BackColor = colorizationColor; + } + + // Make sure everything is visible + tempForm.Refresh(); + if (!IsMetroApp) + { + // Make sure the application window is active, so the colors & buttons are right + ToForeground(); + } + + // Make sure all changes are processed and visible + Application.DoEvents(); + // Capture from the screen + capturedBitmap = WindowCapture.CaptureRectangle(captureRectangle); + } + + if (capturedBitmap != null) + { + // Not needed for Windows 8 + if (!WindowsVersion.IsWindows8OrLater) + { + // Only if the Inivalue is set, not maximized and it's not a tool window. + if (Conf.WindowCaptureRemoveCorners && !Maximised && (ExtendedWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) == 0) + { + // Remove corners + if (!Image.IsAlphaPixelFormat(capturedBitmap.PixelFormat)) + { + Log.Debug("Changing pixelformat to Alpha for the RemoveCorners"); + Bitmap tmpBitmap = ImageHelper.Clone(capturedBitmap, PixelFormat.Format32bppArgb); + capturedBitmap.Dispose(); + capturedBitmap = tmpBitmap; + } + + RemoveCorners(capturedBitmap); + } + } + } + } + finally + { + // Make sure to ALWAYS unfreeze!! + if (frozen) + { + UnfreezeWindow(); + } + } + + capture.Image = capturedBitmap; + // Make sure the capture location is the location of the window, not the copy + capture.Location = Location; + } + finally + { + if (thumbnailHandle != IntPtr.Zero) + { + // Unregister (cleanup), as we are finished we don't need the form or the thumbnail anymore + DWM.DwmUnregisterThumbnail(thumbnailHandle); + } + + if (tempForm != null) + { + if (tempFormShown) + { + tempForm.Close(); + } + + tempForm.Dispose(); + tempForm = null; + } + } + + return capture; + } + + /// + /// Helper method to remove the corners from a DMW capture + /// + /// The bitmap to remove the corners from. + private void RemoveCorners(Bitmap image) + { + using IFastBitmap fastBitmap = FastBitmap.Create(image); + for (int y = 0; y < Conf.WindowCornerCutShape.Count; y++) + { + for (int x = 0; x < Conf.WindowCornerCutShape[y]; x++) + { + fastBitmap.SetColorAt(x, y, Color.Transparent); + fastBitmap.SetColorAt(image.Width - 1 - x, y, Color.Transparent); + fastBitmap.SetColorAt(image.Width - 1 - x, image.Height - 1 - y, Color.Transparent); + fastBitmap.SetColorAt(x, image.Height - 1 - y, Color.Transparent); + } + } + } + + /// + /// Apply transparency by comparing a transparent capture with a black and white background + /// A "Math.min" makes sure there is no overflow, but this could cause the picture to have shifted colors. + /// The pictures should have been taken without differency, except for the colors. + /// + /// Bitmap with the black image + /// Bitmap with the black image + /// Bitmap with transparency + private Bitmap ApplyTransparency(Bitmap blackBitmap, Bitmap whiteBitmap) + { + using IFastBitmap targetBuffer = FastBitmap.CreateEmpty(blackBitmap.Size, PixelFormat.Format32bppArgb, Color.Transparent); + targetBuffer.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution); + using (IFastBitmap blackBuffer = FastBitmap.Create(blackBitmap)) + { + using IFastBitmap whiteBuffer = FastBitmap.Create(whiteBitmap); + for (int y = 0; y < blackBuffer.Height; y++) + { + for (int x = 0; x < blackBuffer.Width; x++) + { + Color c0 = blackBuffer.GetColorAt(x, y); + Color c1 = whiteBuffer.GetColorAt(x, y); + // Calculate alpha as double in range 0-1 + int alpha = c0.R - c1.R + 255; + if (alpha == 255) + { + // Alpha == 255 means no change! + targetBuffer.SetColorAt(x, y, c0); + } + else if (alpha == 0) + { + // Complete transparency, use transparent pixel + targetBuffer.SetColorAt(x, y, Color.Transparent); + } + else + { + // Calculate original color + byte originalAlpha = (byte) Math.Min(255, alpha); + var alphaFactor = alpha / 255d; + //LOG.DebugFormat("Alpha {0} & c0 {1} & c1 {2}", alpha, c0, c1); + byte originalRed = (byte) Math.Min(255, c0.R / alphaFactor); + byte originalGreen = (byte) Math.Min(255, c0.G / alphaFactor); + byte originalBlue = (byte) Math.Min(255, c0.B / alphaFactor); + Color originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue); + //Color originalColor = Color.FromArgb(originalAlpha, originalRed, c0.G, c0.B); + targetBuffer.SetColorAt(x, y, originalColor); + } + } + } + } + + return targetBuffer.UnlockAndReturnBitmap(); + } + + /// + /// Helper method to get the window size for DWM Windows + /// + /// out Rectangle + /// bool true if it worked + private bool GetExtendedFrameBounds(out Rectangle rectangle) + { + int result = DWM.DwmGetWindowAttribute(Handle, DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out RECT rect, Marshal.SizeOf(typeof(RECT))); + if (result >= 0) + { + rectangle = rect.ToRectangle(); + return true; + } + + rectangle = Rectangle.Empty; + return false; + } + + /// + /// Helper method to get the window size for GDI Windows + /// + /// out Rectangle + /// bool true if it worked + private bool GetClientRect(out Rectangle rectangle) + { + var windowInfo = new WindowInfo(); + // Get the Window Info for this window + bool result = User32.GetWindowInfo(Handle, ref windowInfo); + rectangle = result ? windowInfo.rcClient.ToRectangle() : Rectangle.Empty; + return result; + } + + /// + /// Helper method to get the window size for GDI Windows + /// + /// out Rectangle + /// bool true if it worked + private bool GetWindowRect(out Rectangle rectangle) + { + var windowInfo = new WindowInfo(); + // Get the Window Info for this window + bool result = User32.GetWindowInfo(Handle, ref windowInfo); + rectangle = result ? windowInfo.rcWindow.ToRectangle() : Rectangle.Empty; + return result; + } + + /// + /// Helper method to get the Border size for GDI Windows + /// + /// out Size + /// bool true if it worked + private bool GetBorderSize(out Size size) + { + var windowInfo = new WindowInfo(); + // Get the Window Info for this window + bool result = User32.GetWindowInfo(Handle, ref windowInfo); + size = result ? new Size((int) windowInfo.cxWindowBorders, (int) windowInfo.cyWindowBorders) : Size.Empty; + return result; + } + + /// + /// Set the window as foreground window + /// + /// hWnd of the window to bring to the foreground + public static void ToForeground(IntPtr hWnd) + { + var foregroundWindow = User32.GetForegroundWindow(); + if (hWnd == foregroundWindow) + { + return; + } + + var window = new WindowDetails(hWnd); + // Nothing we can do if it's not visible! + if (!window.Visible) + { + return; + } + + var threadId1 = User32.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero); + var threadId2 = User32.GetWindowThreadProcessId(hWnd, IntPtr.Zero); + + // Show window in foreground. + if (threadId1 != threadId2) + { + User32.AttachThreadInput(threadId1, threadId2, 1); + User32.SetForegroundWindow(hWnd); + User32.AttachThreadInput(threadId1, threadId2, 0); + } + else + { + User32.SetForegroundWindow(hWnd); + } + + User32.BringWindowToTop(hWnd); + + if (window.Iconic) + { + window.Iconic = false; + } + } + + /// + /// Set the window as foreground window + /// + public void ToForeground() + { + ToForeground(Handle); + } + + /// + /// Get the region for a window + /// + private Region GetRegion() + { + using (SafeRegionHandle region = GDI32.CreateRectRgn(0, 0, 0, 0)) + { + if (!region.IsInvalid) + { + RegionResult result = User32.GetWindowRgn(Handle, region); + if (result != RegionResult.REGION_ERROR && result != RegionResult.REGION_NULLREGION) + { + return Region.FromHrgn(region.DangerousGetHandle()); + } + } + } + + return null; + } + + private bool CanFreezeOrUnfreeze(string titleOrProcessname) + { + if (string.IsNullOrEmpty(titleOrProcessname)) + { + return false; + } + + if (titleOrProcessname.ToLower().Contains("greenshot")) + { + return false; + } + + foreach (string excludeProcess in ExcludeProcessesFromFreeze) + { + if (titleOrProcessname.ToLower().Contains(excludeProcess)) + { + return false; + } + } + + return true; + } + + /// + /// Freezes the process belonging to the window + /// Warning: Use only if no other way!! + /// + private bool FreezeWindow() + { + bool frozen = false; + using (Process proc = Process.GetProcessById(ProcessId)) + { + string processName = proc.ProcessName; + if (!CanFreezeOrUnfreeze(processName)) + { + Log.DebugFormat("Not freezing {0}", processName); + return false; + } + + if (!CanFreezeOrUnfreeze(Text)) + { + Log.DebugFormat("Not freezing {0}", processName); + return false; + } + + Log.DebugFormat("Freezing process: {0}", processName); + + + foreach (ProcessThread pT in proc.Threads) + { + IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); + + if (pOpenThread == IntPtr.Zero) + { + break; + } + + frozen = true; + Kernel32.SuspendThread(pOpenThread); + pT.Dispose(); + } + } + + return frozen; + } + + /// + /// Unfreeze the process belonging to the window + /// + public void UnfreezeWindow() + { + using Process proc = Process.GetProcessById(ProcessId); + string processName = proc.ProcessName; + if (!CanFreezeOrUnfreeze(processName)) + { + Log.DebugFormat("Not unfreezing {0}", processName); + return; + } + + if (!CanFreezeOrUnfreeze(Text)) + { + Log.DebugFormat("Not unfreezing {0}", processName); + return; + } + + Log.DebugFormat("Unfreezing process: {0}", processName); + + foreach (ProcessThread pT in proc.Threads) + { + IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); + + if (pOpenThread == IntPtr.Zero) + { + break; + } + + Kernel32.ResumeThread(pOpenThread); + } + } + + /// + /// Return an Image representing the Window! + /// As GDI+ draws it, it will be without Aero borders! + /// + public Image PrintWindow() + { + Rectangle windowRect = WindowRectangle; + // Start the capture + Exception exceptionOccured = null; + Image returnImage; + using (Region region = GetRegion()) + { + PixelFormat pixelFormat = PixelFormat.Format24bppRgb; + // Only use 32 bpp ARGB when the window has a region + if (region != null) + { + pixelFormat = PixelFormat.Format32bppArgb; + } + + returnImage = new Bitmap(windowRect.Width, windowRect.Height, pixelFormat); + using Graphics graphics = Graphics.FromImage(returnImage); + using (SafeDeviceContextHandle graphicsDc = graphics.GetSafeDeviceContext()) + { + bool printSucceeded = User32.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), 0x0); + if (!printSucceeded) + { + // something went wrong, most likely a "0x80004005" (Acess Denied) when using UAC + exceptionOccured = User32.CreateWin32Exception("PrintWindow"); + } + } + + // Apply the region "transparency" + if (region != null && !region.IsEmpty(graphics)) + { + graphics.ExcludeClip(region); + graphics.Clear(Color.Transparent); + } + + graphics.Flush(); + } + + // Return null if error + if (exceptionOccured != null) + { + Log.ErrorFormat("Error calling print window: {0}", exceptionOccured.Message); + returnImage.Dispose(); + return null; + } + + if (!HasParent && Maximised) + { + Log.Debug("Correcting for maximalization"); + GetBorderSize(out var borderSize); + Rectangle borderRectangle = new Rectangle(borderSize.Width, borderSize.Height, windowRect.Width - (2 * borderSize.Width), + windowRect.Height - (2 * borderSize.Height)); + ImageHelper.Crop(ref returnImage, ref borderRectangle); + } + + return returnImage; + } + + /// + /// Constructs a new instance of this class for + /// the specified Window Handle. + /// + /// The Window Handle + public WindowDetails(IntPtr hWnd) + { + Handle = hWnd; + } + + /// + /// Gets an instance of the current active foreground window + /// + /// WindowDetails of the current window + public static WindowDetails GetActiveWindow() + { + IntPtr hWnd = User32.GetForegroundWindow(); + if (hWnd != IntPtr.Zero) + { + if (IgnoreHandles.Contains(hWnd)) + { + return GetDesktopWindow(); + } + + WindowDetails activeWindow = new WindowDetails(hWnd); + // Invisible Windows should not be active + if (!activeWindow.Visible) + { + return GetDesktopWindow(); + } + + return activeWindow; + } + + return null; + } + + /// + /// Gets the Desktop window + /// + /// WindowDetails for the desktop window + public static WindowDetails GetDesktopWindow() + { + return new WindowDetails(User32.GetDesktopWindow()); + } + + /// + /// Get all the top level windows + /// + /// List of WindowDetails with all the top level windows + public static IList GetAllWindows() + { + return GetAllWindows(null); + } + + /// + /// Get all the top level windows, with matching classname + /// + /// List WindowDetails with all the top level windows + public static IList GetAllWindows(string classname) + { + return new WindowsEnumerator().GetWindows(IntPtr.Zero, classname).Items; + } + + /// + /// Recursive "find children which" + /// + /// point to check for + /// + public WindowDetails FindChildUnderPoint(Point point) + { + if (!Contains(point)) + { + return null; + } + + var rect = WindowRectangle; + // If the mouse it at the edge, take the whole window + if (rect.X == point.X || rect.Y == point.Y || rect.Right == point.X || rect.Bottom == point.Y) + { + return this; + } + + // Look into the child windows + foreach (var childWindow in Children) + { + if (childWindow.Contains(point)) + { + return childWindow.FindChildUnderPoint(point); + } + } + + return this; + } + + /// + /// Retrieves the classname for a hWnd + /// + /// IntPtr with the windows handle + /// String with ClassName + public static string GetClassName(IntPtr hWnd) + { + var classNameBuilder = new StringBuilder(260, 260); + User32.GetClassName(hWnd, classNameBuilder, classNameBuilder.Capacity); + return classNameBuilder.ToString(); + } + + /// + /// Helper method to decide if a top level window is visible + /// + /// + /// + /// + private static bool IsVisible(WindowDetails window, Rectangle screenBounds) + { + // Ignore invisible + if (!window.Visible) + { + return false; + } + + // Ignore minimized + if (window.Iconic) + { + return false; + } + + if (IgnoreClasses.Contains(window.ClassName)) + { + return false; + } + + // On windows which are visible on the screen + var windowRect = window.WindowRectangle; + windowRect.Intersect(screenBounds); + if (windowRect.IsEmpty) + { + return false; + } + + // Skip everything which is not rendered "normally", trying to fix BUG-2017 + var exWindowStyle = window.ExtendedWindowStyle; + if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) + { + return false; + } + + return true; + } + + /// + /// Get all the visible top level windows + /// + /// List WindowDetails with all the visible top level windows + public static IEnumerable GetVisibleWindows() + { + Rectangle screenBounds = WindowCapture.GetScreenBounds(); + foreach (var window in GetAppWindows()) + { + if (IsVisible(window, screenBounds)) + { + yield return window; + } + } + + foreach (var window in GetAllWindows()) + { + if (IsVisible(window, screenBounds)) + { + yield return window; + } + } + } + + /// + /// Get the WindowDetails for all Metro Apps + /// These are all Windows with Classname "Windows.UI.Core.CoreWindow" + /// + /// List WindowDetails with visible metro apps + public static IEnumerable GetAppWindows() + { + // if the appVisibility != null we have Windows 8. + if (AppVisibility == null) + { + yield break; + } + + var nextHandle = User32.FindWindow(AppWindowClass, null); + while (nextHandle != IntPtr.Zero) + { + var metroApp = new WindowDetails(nextHandle); + yield return metroApp; + // Check if we have a gutter! + if (metroApp.Visible && !metroApp.Maximised) + { + var gutterHandle = User32.FindWindow(GutterClass, null); + if (gutterHandle != IntPtr.Zero) + { + yield return new WindowDetails(gutterHandle); + } + } + + nextHandle = User32.FindWindowEx(IntPtr.Zero, nextHandle, AppWindowClass, null); + } + } + + /// + /// Check if the window is a top level + /// + /// WindowDetails + /// bool + private static bool IsTopLevel(WindowDetails window) + { + if (window.IsCloaked) + { + return false; + } + + // Windows without size + if (window.WindowRectangle.Size.Width * window.WindowRectangle.Size.Height == 0) + { + return false; + } + + if (window.HasParent) + { + return false; + } + + var exWindowStyle = window.ExtendedWindowStyle; + if ((exWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) != 0) + { + return false; + } + + // Skip everything which is not rendered "normally", trying to fix BUG-2017 + if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) + { + return false; + } + + // Skip preview windows, like the one from Firefox + if ((window.WindowStyle & WindowStyleFlags.WS_VISIBLE) == 0) + { + return false; + } + + // Ignore windows without title + if (window.Text.Length == 0) + { + return false; + } + + if (IgnoreClasses.Contains(window.ClassName)) + { + return false; + } + + if (!(window.Visible || window.Iconic)) + { + return false; + } + + return !window.IsBackgroundWin10App; + } + + /// + /// Get all the top level windows + /// + /// List WindowDetails with all the top level windows + public static IEnumerable GetTopLevelWindows() + { + foreach (var possibleTopLevel in GetAppWindows()) + { + if (IsTopLevel(possibleTopLevel)) + { + yield return possibleTopLevel; + } + } + + foreach (var possibleTopLevel in GetAllWindows()) + { + if (IsTopLevel(possibleTopLevel)) + { + yield return possibleTopLevel; + } + } + } + + /// + /// Find a window belonging to the same process as the supplied window. + /// + /// + /// + public static WindowDetails GetLinkedWindow(WindowDetails windowToLinkTo) + { + int processIdSelectedWindow = windowToLinkTo.ProcessId; + foreach (var window in GetAllWindows()) + { + // Ignore windows without title + if (window.Text.Length == 0) + { + continue; + } + + // Ignore invisible + if (!window.Visible) + { + continue; + } + + if (window.Handle == windowToLinkTo.Handle) + { + continue; + } + + if (window.Iconic) + { + continue; + } + + // Windows without size + Size windowSize = window.WindowRectangle.Size; + if (windowSize.Width == 0 || windowSize.Height == 0) + { + continue; + } + + if (window.ProcessId == processIdSelectedWindow) + { + Log.InfoFormat("Found window {0} belonging to same process as the window {1}", window.Text, windowToLinkTo.Text); + return window; + } + } + + return null; + } + + /// + /// Helper method to "active" all windows that are not in the supplied list. + /// One should preferably call "GetVisibleWindows" for the oldWindows. + /// + /// List WindowDetails with old windows + public static void ActiveNewerWindows(IEnumerable oldWindows) + { + var oldWindowsList = new List(oldWindows); + foreach (var window in GetVisibleWindows()) + { + if (!oldWindowsList.Contains(window)) + { + window.ToForeground(); + } + } + } + + /// + /// Get the AppLauncher + /// + /// + public static WindowDetails GetAppLauncher() + { + // Only if Windows 8 (or higher) + if (AppVisibility == null) + { + return null; + } + + IntPtr appLauncher = User32.FindWindow(ApplauncherClass, null); + if (appLauncher != IntPtr.Zero) + { + return new WindowDetails(appLauncher); + } + + return null; + } + + /// + /// Return true if the metro-app-launcher is visible + /// + /// + public static bool IsAppLauncherVisible + { + get + { + if (AppVisibility != null) + { + return AppVisibility.IsLauncherVisible; + } + + return false; + } + } + + /// + /// Make a string representation of the window details + /// + /// string + public override string ToString() + { + var result = new StringBuilder(); + result.AppendLine($"Text: {Text}"); + result.AppendLine($"ClassName: {ClassName}"); + result.AppendLine($"ExtendedWindowStyle: {ExtendedWindowStyle}"); + result.AppendLine($"WindowStyle: {WindowStyle}"); + result.AppendLine($"Size: {WindowRectangle.Size}"); + result.AppendLine($"HasParent: {HasParent}"); + result.AppendLine($"IsWin10App: {IsWin10App}"); + result.AppendLine($"IsApp: {IsApp}"); + result.AppendLine($"Visible: {Visible}"); + result.AppendLine($"IsWindowVisible: {User32.IsWindowVisible(Handle)}"); + result.AppendLine($"IsCloaked: {IsCloaked}"); + result.AppendLine($"Iconic: {Iconic}"); + result.AppendLine($"IsBackgroundWin10App: {IsBackgroundWin10App}"); + if (HasChildren) + { + result.AppendLine($"Children classes: {string.Join(",", Children.Select(c => c.ClassName))}"); + } + + return result.ToString(); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/WindowsEnumerator.cs b/src/Greenshot.Base/Core/WindowsEnumerator.cs similarity index 95% rename from src/GreenshotPlugin/Core/WindowsEnumerator.cs rename to src/Greenshot.Base/Core/WindowsEnumerator.cs index 09eece85f..7278a3131 100644 --- a/src/GreenshotPlugin/Core/WindowsEnumerator.cs +++ b/src/Greenshot.Base/Core/WindowsEnumerator.cs @@ -1,108 +1,108 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.UnmanagedHelpers; -using System; -using System.Collections.Generic; -using System.Text; - -namespace GreenshotPlugin.Core -{ - /// - /// EnumWindows wrapper for .NET - /// - public class WindowsEnumerator - { - /// - /// Returns the collection of windows returned by GetWindows - /// - public IList Items { get; private set; } - - /// - /// Gets all child windows of the specified window - /// - /// Window Handle to get children for - /// Window Classname to copy, use null to copy all - public WindowsEnumerator GetWindows(IntPtr hWndParent, string classname) - { - Items = new List(); - User32.EnumChildWindows(hWndParent, WindowEnum, IntPtr.Zero); - - bool hasParent = !IntPtr.Zero.Equals(hWndParent); - string parentText = null; - if (hasParent) - { - var title = new StringBuilder(260, 260); - User32.GetWindowText(hWndParent, title, title.Capacity); - parentText = title.ToString(); - } - - var windows = new List(); - foreach (var window in Items) - { - if (hasParent) - { - window.Text = parentText; - window.ParentHandle = hWndParent; - } - - if (classname == null || window.ClassName.Equals(classname)) - { - windows.Add(window); - } - } - - Items = windows; - return this; - } - - /// - /// The enum Windows callback. - /// - /// Window Handle - /// Application defined value - /// 1 to continue enumeration, 0 to stop - private int WindowEnum(IntPtr hWnd, int lParam) - { - return OnWindowEnum(hWnd) ? 1 : 0; - } - - /// - /// Called whenever a new window is about to be added - /// by the Window enumeration called from GetWindows. - /// If overriding this function, return true to continue - /// enumeration or false to stop. If you do not call - /// the base implementation the Items collection will - /// be empty. - /// - /// Window handle to add - /// True to continue enumeration, False to stop - private bool OnWindowEnum(IntPtr hWnd) - { - if (!WindowDetails.IsIgnoreHandle(hWnd)) - { - Items.Add(new WindowDetails(hWnd)); - } - - return true; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using Greenshot.Base.UnmanagedHelpers; + +namespace Greenshot.Base.Core +{ + /// + /// EnumWindows wrapper for .NET + /// + public class WindowsEnumerator + { + /// + /// Returns the collection of windows returned by GetWindows + /// + public IList Items { get; private set; } + + /// + /// Gets all child windows of the specified window + /// + /// Window Handle to get children for + /// Window Classname to copy, use null to copy all + public WindowsEnumerator GetWindows(IntPtr hWndParent, string classname) + { + Items = new List(); + User32.EnumChildWindows(hWndParent, WindowEnum, IntPtr.Zero); + + bool hasParent = !IntPtr.Zero.Equals(hWndParent); + string parentText = null; + if (hasParent) + { + var title = new StringBuilder(260, 260); + User32.GetWindowText(hWndParent, title, title.Capacity); + parentText = title.ToString(); + } + + var windows = new List(); + foreach (var window in Items) + { + if (hasParent) + { + window.Text = parentText; + window.ParentHandle = hWndParent; + } + + if (classname == null || window.ClassName.Equals(classname)) + { + windows.Add(window); + } + } + + Items = windows; + return this; + } + + /// + /// The enum Windows callback. + /// + /// Window Handle + /// Application defined value + /// 1 to continue enumeration, 0 to stop + private int WindowEnum(IntPtr hWnd, int lParam) + { + return OnWindowEnum(hWnd) ? 1 : 0; + } + + /// + /// Called whenever a new window is about to be added + /// by the Window enumeration called from GetWindows. + /// If overriding this function, return true to continue + /// enumeration or false to stop. If you do not call + /// the base implementation the Items collection will + /// be empty. + /// + /// Window handle to add + /// True to continue enumeration, False to stop + private bool OnWindowEnum(IntPtr hWnd) + { + if (!WindowDetails.IsIgnoreHandle(hWnd)) + { + Items.Add(new WindowDetails(hWnd)); + } + + return true; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Core/WindowsVersion.cs b/src/Greenshot.Base/Core/WindowsVersion.cs similarity index 98% rename from src/GreenshotPlugin/Core/WindowsVersion.cs rename to src/Greenshot.Base/Core/WindowsVersion.cs index 703fcd206..bf3af14ce 100644 --- a/src/GreenshotPlugin/Core/WindowsVersion.cs +++ b/src/Greenshot.Base/Core/WindowsVersion.cs @@ -3,7 +3,7 @@ using System; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// Extension methods to test the windows version diff --git a/src/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs b/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs similarity index 94% rename from src/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs rename to src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs index fba055f7f..3d59bcb28 100644 --- a/src/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs +++ b/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs @@ -1,66 +1,66 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using log4net; - -namespace GreenshotPlugin.Core -{ - /// - /// This IMessageFilter filters out all WM_INPUTLANGCHANGEREQUEST messages which go to a handle which is >32 bits. - /// The need for this is documented here: http://stackoverflow.com/a/32021586 - /// - public class WmInputLangChangeRequestFilter : IMessageFilter - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(WmInputLangChangeRequestFilter)); - - /// - /// This will do some filtering - /// - /// Message - /// true if the message should be filtered - public bool PreFilterMessage(ref Message m) - { - return PreFilterMessageExternal(ref m); - } - - /// - /// Also used in the MainForm WndProc - /// - /// Message - /// true if the message should be filtered - public static bool PreFilterMessageExternal(ref Message m) - { - WindowsMessages message = (WindowsMessages) m.Msg; - if (message == WindowsMessages.WM_INPUTLANGCHANGEREQUEST || message == WindowsMessages.WM_INPUTLANGCHANGE) - { - LOG.WarnFormat("Filtering: {0}, {1:X} - {2:X} - {3:X}", message, m.LParam.ToInt64(), m.WParam.ToInt64(), m.HWnd.ToInt64()); - // For now we always return true - return true; - // But it could look something like this: - //return (m.LParam.ToInt64() | 0x7FFFFFFF) != 0; - } - - return false; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Windows.Forms; +using Greenshot.Base.UnmanagedHelpers.Enums; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// This IMessageFilter filters out all WM_INPUTLANGCHANGEREQUEST messages which go to a handle which is >32 bits. + /// The need for this is documented here: http://stackoverflow.com/a/32021586 + /// + public class WmInputLangChangeRequestFilter : IMessageFilter + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(WmInputLangChangeRequestFilter)); + + /// + /// This will do some filtering + /// + /// Message + /// true if the message should be filtered + public bool PreFilterMessage(ref Message m) + { + return PreFilterMessageExternal(ref m); + } + + /// + /// Also used in the MainForm WndProc + /// + /// Message + /// true if the message should be filtered + public static bool PreFilterMessageExternal(ref Message m) + { + WindowsMessages message = (WindowsMessages) m.Msg; + if (message == WindowsMessages.WM_INPUTLANGCHANGEREQUEST || message == WindowsMessages.WM_INPUTLANGCHANGE) + { + LOG.WarnFormat("Filtering: {0}, {1:X} - {2:X} - {3:X}", message, m.LParam.ToInt64(), m.WParam.ToInt64(), m.HWnd.ToInt64()); + // For now we always return true + return true; + // But it could look something like this: + //return (m.LParam.ToInt64() | 0x7FFFFFFF) != 0; + } + + return false; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/AdjustEffect.cs b/src/Greenshot.Base/Effects/AdjustEffect.cs similarity index 93% rename from src/GreenshotPlugin/Effects/AdjustEffect.cs rename to src/Greenshot.Base/Effects/AdjustEffect.cs index f2f472805..8445c09a8 100644 --- a/src/GreenshotPlugin/Effects/AdjustEffect.cs +++ b/src/Greenshot.Base/Effects/AdjustEffect.cs @@ -1,54 +1,54 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// AdjustEffect - /// - public class AdjustEffect : IEffect - { - public AdjustEffect() - { - Reset(); - } - - public float Contrast { get; set; } - public float Brightness { get; set; } - public float Gamma { get; set; } - - public void Reset() - { - Contrast = 1f; - Brightness = 1f; - Gamma = 1f; - } - - public Image Apply(Image sourceImage, Matrix matrix) - { - return ImageHelper.Adjust(sourceImage, Brightness, Contrast, Gamma); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// AdjustEffect + /// + public class AdjustEffect : IEffect + { + public AdjustEffect() + { + Reset(); + } + + public float Contrast { get; set; } + public float Brightness { get; set; } + public float Gamma { get; set; } + + public void Reset() + { + Contrast = 1f; + Brightness = 1f; + Gamma = 1f; + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.Adjust(sourceImage, Brightness, Contrast, Gamma); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/BorderEffect.cs b/src/Greenshot.Base/Effects/BorderEffect.cs similarity index 93% rename from src/GreenshotPlugin/Effects/BorderEffect.cs rename to src/Greenshot.Base/Effects/BorderEffect.cs index 650f63fe5..b297dcad8 100644 --- a/src/GreenshotPlugin/Effects/BorderEffect.cs +++ b/src/Greenshot.Base/Effects/BorderEffect.cs @@ -1,52 +1,52 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// BorderEffect - /// - public class BorderEffect : IEffect - { - public BorderEffect() - { - Reset(); - } - - public Color Color { get; set; } - public int Width { get; set; } - - public void Reset() - { - Width = 2; - Color = Color.Black; - } - - public Image Apply(Image sourceImage, Matrix matrix) - { - return ImageHelper.CreateBorder(sourceImage, Width, Color, sourceImage.PixelFormat, matrix); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// BorderEffect + /// + public class BorderEffect : IEffect + { + public BorderEffect() + { + Reset(); + } + + public Color Color { get; set; } + public int Width { get; set; } + + public void Reset() + { + Width = 2; + Color = Color.Black; + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateBorder(sourceImage, Width, Color, sourceImage.PixelFormat, matrix); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/DropShadowEffect.cs b/src/Greenshot.Base/Effects/DropShadowEffect.cs similarity index 93% rename from src/GreenshotPlugin/Effects/DropShadowEffect.cs rename to src/Greenshot.Base/Effects/DropShadowEffect.cs index dd262aa07..2ca91aabf 100644 --- a/src/GreenshotPlugin/Effects/DropShadowEffect.cs +++ b/src/Greenshot.Base/Effects/DropShadowEffect.cs @@ -1,59 +1,59 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// DropShadowEffect - /// - [TypeConverter(typeof(EffectConverter))] - public class DropShadowEffect : IEffect - { - public DropShadowEffect() - { - Reset(); - } - - public float Darkness { get; set; } - - public int ShadowSize { get; set; } - - public Point ShadowOffset { get; set; } - - public virtual void Reset() - { - Darkness = 0.6f; - ShadowSize = 7; - ShadowOffset = new Point(-1, -1); - } - - public virtual Image Apply(Image sourceImage, Matrix matrix) - { - return ImageHelper.CreateShadow(sourceImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// DropShadowEffect + /// + [TypeConverter(typeof(EffectConverter))] + public class DropShadowEffect : IEffect + { + public DropShadowEffect() + { + Reset(); + } + + public float Darkness { get; set; } + + public int ShadowSize { get; set; } + + public Point ShadowOffset { get; set; } + + public virtual void Reset() + { + Darkness = 0.6f; + ShadowSize = 7; + ShadowOffset = new Point(-1, -1); + } + + public virtual Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateShadow(sourceImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/GrayscaleEffect.cs b/src/Greenshot.Base/Effects/GrayscaleEffect.cs similarity index 92% rename from src/GreenshotPlugin/Effects/GrayscaleEffect.cs rename to src/Greenshot.Base/Effects/GrayscaleEffect.cs index 11e0f14a9..b557dbd7d 100644 --- a/src/GreenshotPlugin/Effects/GrayscaleEffect.cs +++ b/src/Greenshot.Base/Effects/GrayscaleEffect.cs @@ -1,43 +1,43 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// GrayscaleEffect - /// - public class GrayscaleEffect : IEffect - { - public Image Apply(Image sourceImage, Matrix matrix) - { - return ImageHelper.CreateGrayscale(sourceImage); - } - - public void Reset() - { - // No settings to reset - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// GrayscaleEffect + /// + public class GrayscaleEffect : IEffect + { + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateGrayscale(sourceImage); + } + + public void Reset() + { + // No settings to reset + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/IEffect.cs b/src/Greenshot.Base/Effects/IEffect.cs similarity index 95% rename from src/GreenshotPlugin/Effects/IEffect.cs rename to src/Greenshot.Base/Effects/IEffect.cs index 26c2d1240..e0a8fb6a0 100644 --- a/src/GreenshotPlugin/Effects/IEffect.cs +++ b/src/Greenshot.Base/Effects/IEffect.cs @@ -1,46 +1,46 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; - -namespace GreenshotPlugin.Effects -{ - /// - /// Interface to describe an effect - /// - public interface IEffect - { - /// - /// Apply this IEffect to the supplied sourceImage. - /// In the process of applying the supplied matrix will be modified to represent the changes. - /// - /// Image to apply the effect to - /// Matrix with the modifications like rotate, translate etc. this can be used to calculate the new location of elements on a canvas - /// new image with applied effect - Image Apply(Image sourceImage, Matrix matrix); - - /// - /// Reset all values to their defaults - /// - void Reset(); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace Greenshot.Base.Effects +{ + /// + /// Interface to describe an effect + /// + public interface IEffect + { + /// + /// Apply this IEffect to the supplied sourceImage. + /// In the process of applying the supplied matrix will be modified to represent the changes. + /// + /// Image to apply the effect to + /// Matrix with the modifications like rotate, translate etc. this can be used to calculate the new location of elements on a canvas + /// new image with applied effect + Image Apply(Image sourceImage, Matrix matrix); + + /// + /// Reset all values to their defaults + /// + void Reset(); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/InvertEffect.cs b/src/Greenshot.Base/Effects/InvertEffect.cs similarity index 92% rename from src/GreenshotPlugin/Effects/InvertEffect.cs rename to src/Greenshot.Base/Effects/InvertEffect.cs index fc5d09178..4d5ce8dc7 100644 --- a/src/GreenshotPlugin/Effects/InvertEffect.cs +++ b/src/Greenshot.Base/Effects/InvertEffect.cs @@ -1,43 +1,43 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// InvertEffect - /// - public class InvertEffect : IEffect - { - public Image Apply(Image sourceImage, Matrix matrix) - { - return ImageHelper.CreateNegative(sourceImage); - } - - public void Reset() - { - // No settings to reset - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// InvertEffect + /// + public class InvertEffect : IEffect + { + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateNegative(sourceImage); + } + + public void Reset() + { + // No settings to reset + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/MonochromeEffect.cs b/src/Greenshot.Base/Effects/MonochromeEffect.cs similarity index 93% rename from src/GreenshotPlugin/Effects/MonochromeEffect.cs rename to src/Greenshot.Base/Effects/MonochromeEffect.cs index 7d3bcec87..5a9be096b 100644 --- a/src/GreenshotPlugin/Effects/MonochromeEffect.cs +++ b/src/Greenshot.Base/Effects/MonochromeEffect.cs @@ -1,51 +1,51 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// MonochromeEffect - /// - public class MonochromeEffect : IEffect - { - private readonly byte _threshold; - - /// Threshold for monochrome filter (0 - 255), lower value means less black - public MonochromeEffect(byte threshold) - { - _threshold = threshold; - } - - public void Reset() - { - // TODO: Modify the threshold to have a default, which is reset here - } - - public Image Apply(Image sourceImage, Matrix matrix) - { - return ImageHelper.CreateMonochrome(sourceImage, _threshold); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// MonochromeEffect + /// + public class MonochromeEffect : IEffect + { + private readonly byte _threshold; + + /// Threshold for monochrome filter (0 - 255), lower value means less black + public MonochromeEffect(byte threshold) + { + _threshold = threshold; + } + + public void Reset() + { + // TODO: Modify the threshold to have a default, which is reset here + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateMonochrome(sourceImage, _threshold); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/ReduceColorsEffect.cs b/src/Greenshot.Base/Effects/ReduceColorsEffect.cs similarity index 94% rename from src/GreenshotPlugin/Effects/ReduceColorsEffect.cs rename to src/Greenshot.Base/Effects/ReduceColorsEffect.cs index be8aad54d..cd119544f 100644 --- a/src/GreenshotPlugin/Effects/ReduceColorsEffect.cs +++ b/src/Greenshot.Base/Effects/ReduceColorsEffect.cs @@ -1,70 +1,70 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; -using log4net; - -namespace GreenshotPlugin.Effects -{ - /// - /// ReduceColorsEffect - /// - public class ReduceColorsEffect : IEffect - { - private static readonly ILog Log = LogManager.GetLogger(typeof(ReduceColorsEffect)); - - public ReduceColorsEffect() - { - Reset(); - } - - public int Colors { get; set; } - - public void Reset() - { - Colors = 256; - } - - public Image Apply(Image sourceImage, Matrix matrix) - { - using (WuQuantizer quantizer = new WuQuantizer((Bitmap) sourceImage)) - { - int colorCount = quantizer.GetColorCount(); - if (colorCount > Colors) - { - try - { - return quantizer.GetQuantizedImage(Colors); - } - catch (Exception e) - { - Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); - } - } - } - - return null; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; +using log4net; + +namespace Greenshot.Base.Effects +{ + /// + /// ReduceColorsEffect + /// + public class ReduceColorsEffect : IEffect + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ReduceColorsEffect)); + + public ReduceColorsEffect() + { + Reset(); + } + + public int Colors { get; set; } + + public void Reset() + { + Colors = 256; + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + using (WuQuantizer quantizer = new WuQuantizer((Bitmap) sourceImage)) + { + int colorCount = quantizer.GetColorCount(); + if (colorCount > Colors) + { + try + { + return quantizer.GetQuantizedImage(Colors); + } + catch (Exception e) + { + Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); + } + } + } + + return null; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/ResizeCanvasEffect.cs b/src/Greenshot.Base/Effects/ResizeCanvasEffect.cs similarity index 94% rename from src/GreenshotPlugin/Effects/ResizeCanvasEffect.cs rename to src/Greenshot.Base/Effects/ResizeCanvasEffect.cs index 5b990f2d4..5a8742f3d 100644 --- a/src/GreenshotPlugin/Effects/ResizeCanvasEffect.cs +++ b/src/Greenshot.Base/Effects/ResizeCanvasEffect.cs @@ -1,58 +1,58 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// ResizeCanvasEffect - /// - public class ResizeCanvasEffect : IEffect - { - public ResizeCanvasEffect(int left, int right, int top, int bottom) - { - Left = left; - Right = right; - Top = top; - Bottom = bottom; - BackgroundColor = Color.Empty; // Uses the default background color depending on the format - } - - public int Left { get; set; } - public int Right { get; set; } - public int Top { get; set; } - public int Bottom { get; set; } - public Color BackgroundColor { get; set; } - - public void Reset() - { - // values don't have a default value - } - - public Image Apply(Image sourceImage, Matrix matrix) - { - return ImageHelper.ResizeCanvas(sourceImage, BackgroundColor, Left, Right, Top, Bottom, matrix); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// ResizeCanvasEffect + /// + public class ResizeCanvasEffect : IEffect + { + public ResizeCanvasEffect(int left, int right, int top, int bottom) + { + Left = left; + Right = right; + Top = top; + Bottom = bottom; + BackgroundColor = Color.Empty; // Uses the default background color depending on the format + } + + public int Left { get; set; } + public int Right { get; set; } + public int Top { get; set; } + public int Bottom { get; set; } + public Color BackgroundColor { get; set; } + + public void Reset() + { + // values don't have a default value + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.ResizeCanvas(sourceImage, BackgroundColor, Left, Right, Top, Bottom, matrix); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/ResizeEffect.cs b/src/Greenshot.Base/Effects/ResizeEffect.cs similarity index 93% rename from src/GreenshotPlugin/Effects/ResizeEffect.cs rename to src/Greenshot.Base/Effects/ResizeEffect.cs index cfcae71cd..b756cbaff 100644 --- a/src/GreenshotPlugin/Effects/ResizeEffect.cs +++ b/src/Greenshot.Base/Effects/ResizeEffect.cs @@ -1,54 +1,54 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// ResizeEffect - /// - public class ResizeEffect : IEffect - { - public ResizeEffect(int width, int height, bool maintainAspectRatio) - { - Width = width; - Height = height; - MaintainAspectRatio = maintainAspectRatio; - } - - public int Width { get; set; } - public int Height { get; set; } - public bool MaintainAspectRatio { get; set; } - - public void Reset() - { - // values don't have a default value - } - - public Image Apply(Image sourceImage, Matrix matrix) - { - return ImageHelper.ResizeImage(sourceImage, MaintainAspectRatio, Width, Height, matrix); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// ResizeEffect + /// + public class ResizeEffect : IEffect + { + public ResizeEffect(int width, int height, bool maintainAspectRatio) + { + Width = width; + Height = height; + MaintainAspectRatio = maintainAspectRatio; + } + + public int Width { get; set; } + public int Height { get; set; } + public bool MaintainAspectRatio { get; set; } + + public void Reset() + { + // values don't have a default value + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.ResizeImage(sourceImage, MaintainAspectRatio, Width, Height, matrix); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/RotateEffect.cs b/src/Greenshot.Base/Effects/RotateEffect.cs similarity index 94% rename from src/GreenshotPlugin/Effects/RotateEffect.cs rename to src/Greenshot.Base/Effects/RotateEffect.cs index 8eb7a6978..09c00d35b 100644 --- a/src/GreenshotPlugin/Effects/RotateEffect.cs +++ b/src/Greenshot.Base/Effects/RotateEffect.cs @@ -1,69 +1,69 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// RotateEffect - /// - public class RotateEffect : IEffect - { - public RotateEffect(int angle) - { - Angle = angle; - } - - public int Angle { get; set; } - - public void Reset() - { - // Angle doesn't have a default value - } - - public Image Apply(Image sourceImage, Matrix matrix) - { - RotateFlipType flipType; - if (Angle == 90) - { - matrix.Rotate(90, MatrixOrder.Append); - matrix.Translate(sourceImage.Height, 0, MatrixOrder.Append); - flipType = RotateFlipType.Rotate90FlipNone; - } - else if (Angle == -90 || Angle == 270) - { - flipType = RotateFlipType.Rotate270FlipNone; - matrix.Rotate(-90, MatrixOrder.Append); - matrix.Translate(0, sourceImage.Width, MatrixOrder.Append); - } - else - { - throw new NotSupportedException("Currently only an angle of 90 or -90 (270) is supported."); - } - - return ImageHelper.RotateFlip(sourceImage, flipType); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// RotateEffect + /// + public class RotateEffect : IEffect + { + public RotateEffect(int angle) + { + Angle = angle; + } + + public int Angle { get; set; } + + public void Reset() + { + // Angle doesn't have a default value + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + RotateFlipType flipType; + if (Angle == 90) + { + matrix.Rotate(90, MatrixOrder.Append); + matrix.Translate(sourceImage.Height, 0, MatrixOrder.Append); + flipType = RotateFlipType.Rotate90FlipNone; + } + else if (Angle == -90 || Angle == 270) + { + flipType = RotateFlipType.Rotate270FlipNone; + matrix.Rotate(-90, MatrixOrder.Append); + matrix.Translate(0, sourceImage.Width, MatrixOrder.Append); + } + else + { + throw new NotSupportedException("Currently only an angle of 90 or -90 (270) is supported."); + } + + return ImageHelper.RotateFlip(sourceImage, flipType); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Effects/TornEdgeEffect.cs b/src/Greenshot.Base/Effects/TornEdgeEffect.cs similarity index 94% rename from src/GreenshotPlugin/Effects/TornEdgeEffect.cs rename to src/Greenshot.Base/Effects/TornEdgeEffect.cs index 70d671287..e283593fc 100644 --- a/src/GreenshotPlugin/Effects/TornEdgeEffect.cs +++ b/src/Greenshot.Base/Effects/TornEdgeEffect.cs @@ -1,75 +1,75 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// TornEdgeEffect extends on DropShadowEffect - /// - [TypeConverter(typeof(EffectConverter))] - public sealed class TornEdgeEffect : DropShadowEffect - { - public TornEdgeEffect() - { - Reset(); - } - - public int ToothHeight { get; set; } - public int HorizontalToothRange { get; set; } - public int VerticalToothRange { get; set; } - public bool[] Edges { get; set; } - public bool GenerateShadow { get; set; } - - public override void Reset() - { - base.Reset(); - ShadowSize = 7; - ToothHeight = 12; - HorizontalToothRange = 20; - VerticalToothRange = 20; - Edges = new[] - { - true, true, true, true - }; - GenerateShadow = true; - } - - public override Image Apply(Image sourceImage, Matrix matrix) - { - Image tmpTornImage = ImageHelper.CreateTornEdge(sourceImage, ToothHeight, HorizontalToothRange, VerticalToothRange, Edges); - if (GenerateShadow) - { - using (tmpTornImage) - { - return ImageHelper.CreateShadow(tmpTornImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); - } - } - - return tmpTornImage; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// TornEdgeEffect extends on DropShadowEffect + /// + [TypeConverter(typeof(EffectConverter))] + public sealed class TornEdgeEffect : DropShadowEffect + { + public TornEdgeEffect() + { + Reset(); + } + + public int ToothHeight { get; set; } + public int HorizontalToothRange { get; set; } + public int VerticalToothRange { get; set; } + public bool[] Edges { get; set; } + public bool GenerateShadow { get; set; } + + public override void Reset() + { + base.Reset(); + ShadowSize = 7; + ToothHeight = 12; + HorizontalToothRange = 20; + VerticalToothRange = 20; + Edges = new[] + { + true, true, true, true + }; + GenerateShadow = true; + } + + public override Image Apply(Image sourceImage, Matrix matrix) + { + Image tmpTornImage = ImageHelper.CreateTornEdge(sourceImage, ToothHeight, HorizontalToothRange, VerticalToothRange, Edges); + if (GenerateShadow) + { + using (tmpTornImage) + { + return ImageHelper.CreateShadow(tmpTornImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); + } + } + + return tmpTornImage; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/FileDescriptorReader.cs b/src/Greenshot.Base/FileDescriptorReader.cs similarity index 98% rename from src/GreenshotPlugin/FileDescriptorReader.cs rename to src/Greenshot.Base/FileDescriptorReader.cs index 3acfcf7a3..90cc3f99a 100644 --- a/src/GreenshotPlugin/FileDescriptorReader.cs +++ b/src/Greenshot.Base/FileDescriptorReader.cs @@ -25,9 +25,9 @@ using System.IO; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Text; -using GreenshotPlugin.UnmanagedHelpers.Structs; +using Greenshot.Base.UnmanagedHelpers.Structs; -namespace GreenshotPlugin +namespace Greenshot.Base { /// /// Specifies which fields are valid in a FileDescriptor Structure diff --git a/src/GreenshotPlugin/GlobalSuppressions.cs b/src/Greenshot.Base/GlobalSuppressions.cs similarity index 100% rename from src/GreenshotPlugin/GlobalSuppressions.cs rename to src/Greenshot.Base/GlobalSuppressions.cs diff --git a/src/GreenshotPlugin/GreenshotPlugin.csproj b/src/Greenshot.Base/Greenshot.Base.csproj similarity index 68% rename from src/GreenshotPlugin/GreenshotPlugin.csproj rename to src/Greenshot.Base/Greenshot.Base.csproj index db8b82b57..2f74649f6 100644 --- a/src/GreenshotPlugin/GreenshotPlugin.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -1,26 +1,18 @@ - - - - GreenshotPlugin - GreenshotPlugin - true - - - - - PreserveNewest - - - - - - - - - - - - - - - + + + + true + + + + + + + + + + + + + + diff --git a/src/GreenshotPlugin/Hooking/WindowsEventHook.cs b/src/Greenshot.Base/Hooking/WindowsEventHook.cs similarity index 98% rename from src/GreenshotPlugin/Hooking/WindowsEventHook.cs rename to src/Greenshot.Base/Hooking/WindowsEventHook.cs index 06ae3a83c..474b15fef 100644 --- a/src/GreenshotPlugin/Hooking/WindowsEventHook.cs +++ b/src/Greenshot.Base/Hooking/WindowsEventHook.cs @@ -22,9 +22,9 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; -using GreenshotPlugin.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Enums; -namespace GreenshotPlugin.Hooking +namespace Greenshot.Base.Hooking { /// /// The WinEventHook can register handlers to become important windows events diff --git a/src/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs b/src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs similarity index 98% rename from src/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs rename to src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs index 626e3424f..2ab54e5de 100644 --- a/src/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs +++ b/src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs @@ -20,10 +20,10 @@ */ using System; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers.Enums; +using Greenshot.Base.Core; +using Greenshot.Base.UnmanagedHelpers.Enums; -namespace GreenshotPlugin.Hooking +namespace Greenshot.Base.Hooking { /// /// Event arguments for the WindowOpenCloseEvent diff --git a/src/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs b/src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs similarity index 97% rename from src/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs rename to src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs index 081b1f28f..194ec4fc3 100644 --- a/src/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs +++ b/src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs @@ -20,10 +20,10 @@ */ using System; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers.Enums; +using Greenshot.Base.Core; +using Greenshot.Base.UnmanagedHelpers.Enums; -namespace GreenshotPlugin.Hooking +namespace Greenshot.Base.Hooking { /// /// Event arguments for the TitleChangeEvent diff --git a/src/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs b/src/Greenshot.Base/IEInterop/IHTMLBodyElement.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs rename to src/Greenshot.Base/IEInterop/IHTMLBodyElement.cs index 234a1ec29..4b79bcc3e 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLBodyElement.cs @@ -1,38 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport, Guid("3050F1D8-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLBodyElement - { - string scroll - { - set; - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F1D8-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLBodyElement + { + string scroll + { + set; + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs b/src/Greenshot.Base/IEInterop/IHTMLCurrentStyle.cs similarity index 95% rename from src/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs rename to src/Greenshot.Base/IEInterop/IHTMLCurrentStyle.cs index 95539a5f7..09ba37f79 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLCurrentStyle.cs @@ -1,81 +1,81 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport, Guid("3050f3db-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLCurrentStyle - { - /// styleFloat property of IHTMLStyle interface. - string styleFloat - { - [DispId(-2147413042)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string left - { - [DispId(-2147418112 + 3)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string top - { - [DispId(-2147418112 + 4)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string width - { - [DispId(-2147418112 + 5)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string height - { - [DispId(-2147418112 + 6)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string right - { - [DispId(-2147418112 + 0x4d)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string bottom - { - [DispId(-2147418112 + 0x4e)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050f3db-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLCurrentStyle + { + /// styleFloat property of IHTMLStyle interface. + string styleFloat + { + [DispId(-2147413042)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string left + { + [DispId(-2147418112 + 3)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string top + { + [DispId(-2147418112 + 4)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string width + { + [DispId(-2147418112 + 5)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string height + { + [DispId(-2147418112 + 6)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string right + { + [DispId(-2147418112 + 0x4d)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string bottom + { + [DispId(-2147418112 + 0x4e)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLDocument.cs b/src/Greenshot.Base/IEInterop/IHTMLDocument.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLDocument.cs rename to src/Greenshot.Base/IEInterop/IHTMLDocument.cs index 3ef5be8a7..affc1530e 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLDocument.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLDocument.cs @@ -1,39 +1,39 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - /// IHTMLDocument interface. - [Guid("626FC520-A41E-11CF-A731-00A0C9082637")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument - { - object Script - { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + /// IHTMLDocument interface. + [Guid("626FC520-A41E-11CF-A731-00A0C9082637")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument + { + object Script + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLDocument2.cs b/src/Greenshot.Base/IEInterop/IHTMLDocument2.cs similarity index 95% rename from src/GreenshotPlugin/IEInterop/IHTMLDocument2.cs rename to src/Greenshot.Base/IEInterop/IHTMLDocument2.cs index 1ee72c537..635aea6dd 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLDocument2.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLDocument2.cs @@ -1,85 +1,85 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - /// IHTMLDocument2 interface. - [Guid("332C4425-26CB-11D0-B483-00C04FD90119")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument2 - { - IHTMLElement body - { - [DispId(1004)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - string title - { - [DispId(1012)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - object frames - { - [DispId(1019)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - string url - { - [DispId(1025)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - IHTMLWindow2 parentWindow - { - [DispId(1034)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - object bgColor { [DispId(-501)] get; } - - IHTMLSelectionObject selection - { - [DispId(1017)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - string designMode - { - [DispId(1014)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - [DispId(1014)] set; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + /// IHTMLDocument2 interface. + [Guid("332C4425-26CB-11D0-B483-00C04FD90119")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument2 + { + IHTMLElement body + { + [DispId(1004)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string title + { + [DispId(1012)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + object frames + { + [DispId(1019)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string url + { + [DispId(1025)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + IHTMLWindow2 parentWindow + { + [DispId(1034)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + object bgColor { [DispId(-501)] get; } + + IHTMLSelectionObject selection + { + [DispId(1017)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string designMode + { + [DispId(1014)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + [DispId(1014)] set; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLDocument3.cs b/src/Greenshot.Base/IEInterop/IHTMLDocument3.cs similarity index 95% rename from src/GreenshotPlugin/IEInterop/IHTMLDocument3.cs rename to src/Greenshot.Base/IEInterop/IHTMLDocument3.cs index 21d73b54a..adcf26e0c 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLDocument3.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLDocument3.cs @@ -1,50 +1,50 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - /// IHTMLDocument3 interface. - [Guid("3050F485-98B5-11CF-BB82-00AA00BDCE0B")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument3 - { - IHTMLElement documentElement - { - [DispId(1075)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(1086)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLElementCollection getElementsByName([MarshalAs(UnmanagedType.BStr)] string v); - - [DispId(1088)] - IHTMLElement getElementById([MarshalAs(UnmanagedType.BStr)] string v); - - [DispId(1087)] - IHTMLElementCollection getElementsByTagName([MarshalAs(UnmanagedType.BStr)] string v); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + /// IHTMLDocument3 interface. + [Guid("3050F485-98B5-11CF-BB82-00AA00BDCE0B")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument3 + { + IHTMLElement documentElement + { + [DispId(1075)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(1086)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLElementCollection getElementsByName([MarshalAs(UnmanagedType.BStr)] string v); + + [DispId(1088)] + IHTMLElement getElementById([MarshalAs(UnmanagedType.BStr)] string v); + + [DispId(1087)] + IHTMLElementCollection getElementsByTagName([MarshalAs(UnmanagedType.BStr)] string v); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLDocument4.cs b/src/Greenshot.Base/IEInterop/IHTMLDocument4.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLDocument4.cs rename to src/Greenshot.Base/IEInterop/IHTMLDocument4.cs index 09f8d7a02..1b543991a 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLDocument4.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLDocument4.cs @@ -1,35 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComVisible(true), Guid("3050f69a-98b5-11cf-bb82-00aa00bdce0b"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDual)] - public interface IHTMLDocument4 - { - [DispId(1090)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool hasFocus(); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComVisible(true), Guid("3050f69a-98b5-11cf-bb82-00aa00bdce0b"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDual)] + public interface IHTMLDocument4 + { + [DispId(1090)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool hasFocus(); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLDocument5.cs b/src/Greenshot.Base/IEInterop/IHTMLDocument5.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLDocument5.cs rename to src/Greenshot.Base/IEInterop/IHTMLDocument5.cs index 628652a37..020249783 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLDocument5.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLDocument5.cs @@ -1,38 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport, ComVisible(true), Guid("3050f80c-98b5-11cf-bb82-00aa00bdce0b"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDual)] - public interface IHTMLDocument5 - { - [DispId(1102)] - string compatMode - { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, ComVisible(true), Guid("3050f80c-98b5-11cf-bb82-00aa00bdce0b"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDual)] + public interface IHTMLDocument5 + { + [DispId(1102)] + string compatMode + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLElement.cs b/src/Greenshot.Base/IEInterop/IHTMLElement.cs similarity index 95% rename from src/GreenshotPlugin/IEInterop/IHTMLElement.cs rename to src/Greenshot.Base/IEInterop/IHTMLElement.cs index df1c5d9f4..9e37d98c6 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLElement.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLElement.cs @@ -1,113 +1,113 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport, Guid("3050F1FF-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLElement - { - [DispId(-2147417611)] - void setAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, object AttributeValue, int lFlags); - - [DispId(-2147417610)] - object getAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); - - long offsetLeft { [DispId(-2147417104)] get; } - - long offsetTop { [DispId(-2147417103)] get; } - - long offsetWidth { [DispId(-2147417102)] get; } - - long offsetHeight { [DispId(-2147417101)] get; } - - IHTMLElement offsetParent { [DispId(-2147417100)] get; } - - string className - { - [DispId(-2147417111)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - IHTMLDocument2 document - { - [DispId(-2147417094)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - string id - { - [DispId(-2147417110)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string innerHTML - { - [DispId(-2147417086)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string innerText - { - [DispId(-2147417085)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - IHTMLStyle style - { - [DispId(-2147418038)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - string tagName - { - [DispId(-2147417108)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string title - { - [DispId(-2147418043)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - [DispId(-2147417093)] - void scrollIntoView(bool varargStart); - - IHTMLElementCollection children - { - [DispId(-2147417075)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F1FF-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLElement + { + [DispId(-2147417611)] + void setAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, object AttributeValue, int lFlags); + + [DispId(-2147417610)] + object getAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); + + long offsetLeft { [DispId(-2147417104)] get; } + + long offsetTop { [DispId(-2147417103)] get; } + + long offsetWidth { [DispId(-2147417102)] get; } + + long offsetHeight { [DispId(-2147417101)] get; } + + IHTMLElement offsetParent { [DispId(-2147417100)] get; } + + string className + { + [DispId(-2147417111)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + IHTMLDocument2 document + { + [DispId(-2147417094)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string id + { + [DispId(-2147417110)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string innerHTML + { + [DispId(-2147417086)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string innerText + { + [DispId(-2147417085)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + IHTMLStyle style + { + [DispId(-2147418038)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string tagName + { + [DispId(-2147417108)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string title + { + [DispId(-2147418043)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + [DispId(-2147417093)] + void scrollIntoView(bool varargStart); + + IHTMLElementCollection children + { + [DispId(-2147417075)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLElement2.cs b/src/Greenshot.Base/IEInterop/IHTMLElement2.cs similarity index 95% rename from src/GreenshotPlugin/IEInterop/IHTMLElement2.cs rename to src/Greenshot.Base/IEInterop/IHTMLElement2.cs index df5a5d9d4..d6b5e794f 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLElement2.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLElement2.cs @@ -1,42 +1,42 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport, Guid("3050F434-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLElement2 - { - [DispId(-2147417067)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLRect getBoundingClientRect(); - - IHTMLCurrentStyle currentStyle - { - [DispId(-2147417105)] - [return: MarshalAs(UnmanagedType.Interface)] //IHTMLCurrentStyle - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F434-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLElement2 + { + [DispId(-2147417067)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLRect getBoundingClientRect(); + + IHTMLCurrentStyle currentStyle + { + [DispId(-2147417105)] + [return: MarshalAs(UnmanagedType.Interface)] //IHTMLCurrentStyle + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs b/src/Greenshot.Base/IEInterop/IHTMLElementCollection.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs rename to src/Greenshot.Base/IEInterop/IHTMLElementCollection.cs index d8ac07646..f0735cc6d 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLElementCollection.cs @@ -1,35 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Collections; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport(), ComVisible(true), - Guid("3050F21F-98B5-11CF-BB82-00AA00BDCE0B"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDispatchable)] - public interface IHTMLElementCollection : IEnumerable - { - new IEnumerator GetEnumerator(); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport(), ComVisible(true), + Guid("3050F21F-98B5-11CF-BB82-00AA00BDCE0B"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDispatchable)] + public interface IHTMLElementCollection : IEnumerable + { + new IEnumerator GetEnumerator(); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs b/src/Greenshot.Base/IEInterop/IHTMLFrameBase.cs similarity index 95% rename from src/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs rename to src/Greenshot.Base/IEInterop/IHTMLFrameBase.cs index db68866d2..c35da0240 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLFrameBase.cs @@ -1,108 +1,108 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComVisible(true), ComImport(), Guid("3050f311-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLFrameBase - { -//dispinterface IHTMLFrameBase { -// properties: -// methods: -// [id(0x80010bb8), propput] -// void src([in] BSTR rhs); -// [id(0x80010bb8), propget] -// BSTR src(); -// [id(0x80010000), propput] -// void name([in] BSTR rhs); -// [id(0x80010000), propget] -// BSTR name(); -// [id(0x80010bba), propput] -// void border([in] VARIANT rhs); -// [id(0x80010bba), propget] -// VARIANT border(); -// [id(0x80010bbb), propput] -// void frameBorder([in] BSTR rhs); -// [id(0x80010bbb), propget] -// BSTR frameBorder(); -// [id(0x80010bbc), propput] -// void frameSpacing([in] VARIANT rhs); -// [id(0x80010bbc), propget] -// VARIANT frameSpacing(); -// [id(0x80010bbd), propput] -// void marginWidth([in] VARIANT rhs); -// [id(0x80010bbd), propget] -// VARIANT marginWidth(); -// [id(0x80010bbe), propput] -// void marginHeight([in] VARIANT rhs); -// [id(0x80010bbe), propget] -// VARIANT marginHeight(); -// [id(0x80010bbf), propput] -// void noResize([in] VARIANT_BOOL rhs); -// [id(0x80010bbf), propget] -// VARIANT_BOOL noResize(); -// [id(0x80010bc0), propput] -// void scrolling([in] BSTR rhs); -// [id(0x80010bc0), propget] -// BSTR scrolling(); -//}; -// [DispId(HTMLDispIDs.DISPID_IHTMLFRAMEBASE_SRC)] - string src - { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string name - { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - object border { get; } - - string frameBorder - { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - object frameSpacing { get; } - object marginWidth { get; } - object marginHeight { get; } - - bool noResize - { - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - string scrolling - { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComVisible(true), ComImport(), Guid("3050f311-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLFrameBase + { +//dispinterface IHTMLFrameBase { +// properties: +// methods: +// [id(0x80010bb8), propput] +// void src([in] BSTR rhs); +// [id(0x80010bb8), propget] +// BSTR src(); +// [id(0x80010000), propput] +// void name([in] BSTR rhs); +// [id(0x80010000), propget] +// BSTR name(); +// [id(0x80010bba), propput] +// void border([in] VARIANT rhs); +// [id(0x80010bba), propget] +// VARIANT border(); +// [id(0x80010bbb), propput] +// void frameBorder([in] BSTR rhs); +// [id(0x80010bbb), propget] +// BSTR frameBorder(); +// [id(0x80010bbc), propput] +// void frameSpacing([in] VARIANT rhs); +// [id(0x80010bbc), propget] +// VARIANT frameSpacing(); +// [id(0x80010bbd), propput] +// void marginWidth([in] VARIANT rhs); +// [id(0x80010bbd), propget] +// VARIANT marginWidth(); +// [id(0x80010bbe), propput] +// void marginHeight([in] VARIANT rhs); +// [id(0x80010bbe), propget] +// VARIANT marginHeight(); +// [id(0x80010bbf), propput] +// void noResize([in] VARIANT_BOOL rhs); +// [id(0x80010bbf), propget] +// VARIANT_BOOL noResize(); +// [id(0x80010bc0), propput] +// void scrolling([in] BSTR rhs); +// [id(0x80010bc0), propget] +// BSTR scrolling(); +//}; +// [DispId(HTMLDispIDs.DISPID_IHTMLFRAMEBASE_SRC)] + string src + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string name + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + object border { get; } + + string frameBorder + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + object frameSpacing { get; } + object marginWidth { get; } + object marginHeight { get; } + + bool noResize + { + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + string scrolling + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs b/src/Greenshot.Base/IEInterop/IHTMLFramesCollection2.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs rename to src/Greenshot.Base/IEInterop/IHTMLFramesCollection2.cs index 41b759aef..3a68b485d 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLFramesCollection2.cs @@ -1,38 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport(), ComVisible(true), - Guid("332C4426-26CB-11D0-B483-00C04FD90119"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDispatchable)] - public interface IHTMLFramesCollection2 - { - [DispId(0)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLWindow2 item(int pvarIndex); - - long length { [DispId(1001)] get; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport(), ComVisible(true), + Guid("332C4426-26CB-11D0-B483-00C04FD90119"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDispatchable)] + public interface IHTMLFramesCollection2 + { + [DispId(0)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLWindow2 item(int pvarIndex); + + long length { [DispId(1001)] get; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLRect.cs b/src/Greenshot.Base/IEInterop/IHTMLRect.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLRect.cs rename to src/Greenshot.Base/IEInterop/IHTMLRect.cs index 1b2f8363c..01a3e886d 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLRect.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLRect.cs @@ -1,39 +1,39 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport, Guid("3050F4A3-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLRect - { - int bottom { [DispId(1004)] get; } - - int left { [DispId(1001)] get; } - - int right { [DispId(1003)] get; } - - int top { [DispId(1002)] get; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F4A3-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLRect + { + int bottom { [DispId(1004)] get; } + + int left { [DispId(1001)] get; } + + int right { [DispId(1003)] get; } + + int top { [DispId(1002)] get; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLScreen.cs b/src/Greenshot.Base/IEInterop/IHTMLScreen.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLScreen.cs rename to src/Greenshot.Base/IEInterop/IHTMLScreen.cs index 082935187..2eab0d041 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLScreen.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLScreen.cs @@ -1,34 +1,34 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport, Guid("3050F35C-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLScreen - { - [DispId(1003)] int width { get; } - [DispId(1004)] int height { get; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F35C-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLScreen + { + [DispId(1003)] int width { get; } + [DispId(1004)] int height { get; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLScreen2.cs b/src/Greenshot.Base/IEInterop/IHTMLScreen2.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLScreen2.cs rename to src/Greenshot.Base/IEInterop/IHTMLScreen2.cs index 9870f889e..3e7d379cc 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLScreen2.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLScreen2.cs @@ -1,39 +1,39 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport, Guid("3050F84A-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLScreen2 - { - int logicalXDPI { [DispId(1009)] get; } - - int logicalYDPI { [DispId(1010)] get; } - - int deviceXDPI { [DispId(1011)] get; } - - int deviceYDPI { [DispId(1012)] get; } - }; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F84A-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLScreen2 + { + int logicalXDPI { [DispId(1009)] get; } + + int logicalYDPI { [DispId(1010)] get; } + + int deviceXDPI { [DispId(1011)] get; } + + int deviceYDPI { [DispId(1012)] get; } + }; } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs b/src/Greenshot.Base/IEInterop/IHTMLSelectionObject.cs similarity index 95% rename from src/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs rename to src/Greenshot.Base/IEInterop/IHTMLSelectionObject.cs index 32982a281..2fa199ab5 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLSelectionObject.cs @@ -1,49 +1,49 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - // See: http://msdn.microsoft.com/en-us/library/aa768849%28v=vs.85%29.aspx - [ComImport, Guid("3050f25A-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLSelectionObject - { - [return: MarshalAs(UnmanagedType.IDispatch)] - [DispId(1001)] - IHTMLTxtRange createRange(); - - [DispId(1002)] - void empty(); - - [DispId(1003)] - void clear(); - - [DispId(1004)] - string EventType - { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + // See: http://msdn.microsoft.com/en-us/library/aa768849%28v=vs.85%29.aspx + [ComImport, Guid("3050f25A-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLSelectionObject + { + [return: MarshalAs(UnmanagedType.IDispatch)] + [DispId(1001)] + IHTMLTxtRange createRange(); + + [DispId(1002)] + void empty(); + + [DispId(1003)] + void clear(); + + [DispId(1004)] + string EventType + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLStyle.cs b/src/Greenshot.Base/IEInterop/IHTMLStyle.cs similarity index 97% rename from src/GreenshotPlugin/IEInterop/IHTMLStyle.cs rename to src/Greenshot.Base/IEInterop/IHTMLStyle.cs index d5cd7f5be..3be39344a 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLStyle.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLStyle.cs @@ -1,1103 +1,1103 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComImport, Guid("3050F25E-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLStyle - { - /// setAttribute method of IHTMLStyle interface. - /// An original IDL definition of setAttribute method was the following: HRESULT setAttribute (BSTR strAttributeName, VARIANT AttributeValue, [optional, defaultvalue(1)] long lFlags); - // IDL: HRESULT setAttribute (BSTR strAttributeName, VARIANT AttributeValue, [optional, defaultvalue(1)] long lFlags); - // VB6: Sub setAttribute (ByVal strAttributeName As String, ByVal AttributeValue As Any, [ByVal lFlags As Long = 1]) - [DispId(-2147417611)] - void setAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, object AttributeValue, int lFlags); - - /// getAttribute method of IHTMLStyle interface. - /// An original IDL definition of getAttribute method was the following: HRESULT getAttribute (BSTR strAttributeName, [optional, defaultvalue(0)] long lFlags, [out, retval] VARIANT* ReturnValue); - // IDL: HRESULT getAttribute (BSTR strAttributeName, [optional, defaultvalue(0)] long lFlags, [out, retval] VARIANT* ReturnValue); - // VB6: Function getAttribute (ByVal strAttributeName As String, [ByVal lFlags As Long = 0]) As Any - [DispId(-2147417610)] - object getAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); - - /// removeAttribute method of IHTMLStyle interface. - /// An original IDL definition of removeAttribute method was the following: HRESULT removeAttribute (BSTR strAttributeName, [optional, defaultvalue(1)] long lFlags, [out, retval] VARIANT_BOOL* ReturnValue); - // IDL: HRESULT removeAttribute (BSTR strAttributeName, [optional, defaultvalue(1)] long lFlags, [out, retval] VARIANT_BOOL* ReturnValue); - // VB6: Function removeAttribute (ByVal strAttributeName As String, [ByVal lFlags As Long = 1]) As Boolean - [DispId(-2147417609)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool removeAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); - - /// toString method of IHTMLStyle interface. - /// An original IDL definition of toString method was the following: HRESULT toString ([out, retval] BSTR* ReturnValue); - // IDL: HRESULT toString ([out, retval] BSTR* ReturnValue); - // VB6: Function toString As String - [DispId(-2147414104)] - [return: MarshalAs(UnmanagedType.BStr)] - string toString(); - - /// background property of IHTMLStyle interface. - /// An original IDL definition of background property was the following: BSTR background; - // IDL: BSTR background; - // VB6: background As String - string background - { - // IDL: HRESULT background ([out, retval] BSTR* ReturnValue); - // VB6: Function background As String - [DispId(-2147413080)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT background (BSTR value); - // VB6: Sub background (ByVal value As String) - [DispId(-2147413080)] set; - } - - /// backgroundAttachment property of IHTMLStyle interface. - /// An original IDL definition of backgroundAttachment property was the following: BSTR backgroundAttachment; - // IDL: BSTR backgroundAttachment; - // VB6: backgroundAttachment As String - string backgroundAttachment - { - // IDL: HRESULT backgroundAttachment ([out, retval] BSTR* ReturnValue); - // VB6: Function backgroundAttachment As String - [DispId(-2147413067)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT backgroundAttachment (BSTR value); - // VB6: Sub backgroundAttachment (ByVal value As String) - [DispId(-2147413067)] set; - } - - /// backgroundColor property of IHTMLStyle interface. - /// An original IDL definition of backgroundColor property was the following: VARIANT backgroundColor; - // IDL: VARIANT backgroundColor; - // VB6: backgroundColor As Any - object backgroundColor - { - // IDL: HRESULT backgroundColor ([out, retval] VARIANT* ReturnValue); - // VB6: Function backgroundColor As Any - [DispId(-501)] get; - // IDL: HRESULT backgroundColor (VARIANT value); - // VB6: Sub backgroundColor (ByVal value As Any) - [DispId(-501)] set; - } - - /// backgroundImage property of IHTMLStyle interface. - /// An original IDL definition of backgroundImage property was the following: BSTR backgroundImage; - // IDL: BSTR backgroundImage; - // VB6: backgroundImage As String - string backgroundImage - { - // IDL: HRESULT backgroundImage ([out, retval] BSTR* ReturnValue); - // VB6: Function backgroundImage As String - [DispId(-2147413111)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT backgroundImage (BSTR value); - // VB6: Sub backgroundImage (ByVal value As String) - [DispId(-2147413111)] set; - } - - /// backgroundPosition property of IHTMLStyle interface. - /// An original IDL definition of backgroundPosition property was the following: BSTR backgroundPosition; - // IDL: BSTR backgroundPosition; - // VB6: backgroundPosition As String - string backgroundPosition - { - // IDL: HRESULT backgroundPosition ([out, retval] BSTR* ReturnValue); - // VB6: Function backgroundPosition As String - [DispId(-2147413066)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT backgroundPosition (BSTR value); - // VB6: Sub backgroundPosition (ByVal value As String) - [DispId(-2147413066)] set; - } - - /// backgroundPositionX property of IHTMLStyle interface. - /// An original IDL definition of backgroundPositionX property was the following: VARIANT backgroundPositionX; - // IDL: VARIANT backgroundPositionX; - // VB6: backgroundPositionX As Any - object backgroundPositionX - { - // IDL: HRESULT backgroundPositionX ([out, retval] VARIANT* ReturnValue); - // VB6: Function backgroundPositionX As Any - [DispId(-2147413079)] get; - // IDL: HRESULT backgroundPositionX (VARIANT value); - // VB6: Sub backgroundPositionX (ByVal value As Any) - [DispId(-2147413079)] set; - } - - /// backgroundPositionY property of IHTMLStyle interface. - /// An original IDL definition of backgroundPositionY property was the following: VARIANT backgroundPositionY; - // IDL: VARIANT backgroundPositionY; - // VB6: backgroundPositionY As Any - object backgroundPositionY - { - // IDL: HRESULT backgroundPositionY ([out, retval] VARIANT* ReturnValue); - // VB6: Function backgroundPositionY As Any - [DispId(-2147413078)] get; - // IDL: HRESULT backgroundPositionY (VARIANT value); - // VB6: Sub backgroundPositionY (ByVal value As Any) - [DispId(-2147413078)] set; - } - - /// backgroundRepeat property of IHTMLStyle interface. - /// An original IDL definition of backgroundRepeat property was the following: BSTR backgroundRepeat; - // IDL: BSTR backgroundRepeat; - // VB6: backgroundRepeat As String - string backgroundRepeat - { - // IDL: HRESULT backgroundRepeat ([out, retval] BSTR* ReturnValue); - // VB6: Function backgroundRepeat As String - [DispId(-2147413068)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT backgroundRepeat (BSTR value); - // VB6: Sub backgroundRepeat (ByVal value As String) - [DispId(-2147413068)] set; - } - - /// border property of IHTMLStyle interface. - /// An original IDL definition of border property was the following: BSTR border; - // IDL: BSTR border; - // VB6: border As String - string border - { - // IDL: HRESULT border ([out, retval] BSTR* ReturnValue); - // VB6: Function border As String - [DispId(-2147413063)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT border (BSTR value); - // VB6: Sub border (ByVal value As String) - [DispId(-2147413063)] set; - } - - /// borderBottom property of IHTMLStyle interface. - /// An original IDL definition of borderBottom property was the following: BSTR borderBottom; - // IDL: BSTR borderBottom; - // VB6: borderBottom As String - string borderBottom - { - // IDL: HRESULT borderBottom ([out, retval] BSTR* ReturnValue); - // VB6: Function borderBottom As String - [DispId(-2147413060)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderBottom (BSTR value); - // VB6: Sub borderBottom (ByVal value As String) - [DispId(-2147413060)] set; - } - - /// borderBottomColor property of IHTMLStyle interface. - /// An original IDL definition of borderBottomColor property was the following: VARIANT borderBottomColor; - // IDL: VARIANT borderBottomColor; - // VB6: borderBottomColor As Any - object borderBottomColor - { - // IDL: HRESULT borderBottomColor ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderBottomColor As Any - [DispId(-2147413055)] get; - // IDL: HRESULT borderBottomColor (VARIANT value); - // VB6: Sub borderBottomColor (ByVal value As Any) - [DispId(-2147413055)] set; - } - - /// borderBottomStyle property of IHTMLStyle interface. - /// An original IDL definition of borderBottomStyle property was the following: BSTR borderBottomStyle; - // IDL: BSTR borderBottomStyle; - // VB6: borderBottomStyle As String - string borderBottomStyle - { - // IDL: HRESULT borderBottomStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function borderBottomStyle As String - [DispId(-2147413045)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderBottomStyle (BSTR value); - // VB6: Sub borderBottomStyle (ByVal value As String) - [DispId(-2147413045)] set; - } - - /// borderBottomWidth property of IHTMLStyle interface. - /// An original IDL definition of borderBottomWidth property was the following: VARIANT borderBottomWidth; - // IDL: VARIANT borderBottomWidth; - // VB6: borderBottomWidth As Any - object borderBottomWidth - { - // IDL: HRESULT borderBottomWidth ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderBottomWidth As Any - [DispId(-2147413050)] get; - // IDL: HRESULT borderBottomWidth (VARIANT value); - // VB6: Sub borderBottomWidth (ByVal value As Any) - [DispId(-2147413050)] set; - } - - /// borderColor property of IHTMLStyle interface. - /// An original IDL definition of borderColor property was the following: BSTR borderColor; - // IDL: BSTR borderColor; - // VB6: borderColor As String - string borderColor - { - // IDL: HRESULT borderColor ([out, retval] BSTR* ReturnValue); - // VB6: Function borderColor As String - [DispId(-2147413058)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderColor (BSTR value); - // VB6: Sub borderColor (ByVal value As String) - [DispId(-2147413058)] set; - } - - /// borderLeft property of IHTMLStyle interface. - /// An original IDL definition of borderLeft property was the following: BSTR borderLeft; - // IDL: BSTR borderLeft; - // VB6: borderLeft As String - string borderLeft - { - // IDL: HRESULT borderLeft ([out, retval] BSTR* ReturnValue); - // VB6: Function borderLeft As String - [DispId(-2147413059)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderLeft (BSTR value); - // VB6: Sub borderLeft (ByVal value As String) - [DispId(-2147413059)] set; - } - - /// borderLeftColor property of IHTMLStyle interface. - /// An original IDL definition of borderLeftColor property was the following: VARIANT borderLeftColor; - // IDL: VARIANT borderLeftColor; - // VB6: borderLeftColor As Any - object borderLeftColor - { - // IDL: HRESULT borderLeftColor ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderLeftColor As Any - [DispId(-2147413054)] get; - // IDL: HRESULT borderLeftColor (VARIANT value); - // VB6: Sub borderLeftColor (ByVal value As Any) - [DispId(-2147413054)] set; - } - - /// borderLeftStyle property of IHTMLStyle interface. - /// An original IDL definition of borderLeftStyle property was the following: BSTR borderLeftStyle; - // IDL: BSTR borderLeftStyle; - // VB6: borderLeftStyle As String - string borderLeftStyle - { - // IDL: HRESULT borderLeftStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function borderLeftStyle As String - [DispId(-2147413044)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderLeftStyle (BSTR value); - // VB6: Sub borderLeftStyle (ByVal value As String) - [DispId(-2147413044)] set; - } - - /// borderLeftWidth property of IHTMLStyle interface. - /// An original IDL definition of borderLeftWidth property was the following: VARIANT borderLeftWidth; - // IDL: VARIANT borderLeftWidth; - // VB6: borderLeftWidth As Any - object borderLeftWidth - { - // IDL: HRESULT borderLeftWidth ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderLeftWidth As Any - [DispId(-2147413049)] get; - // IDL: HRESULT borderLeftWidth (VARIANT value); - // VB6: Sub borderLeftWidth (ByVal value As Any) - [DispId(-2147413049)] set; - } - - /// borderRight property of IHTMLStyle interface. - /// An original IDL definition of borderRight property was the following: BSTR borderRight; - // IDL: BSTR borderRight; - // VB6: borderRight As String - string borderRight - { - // IDL: HRESULT borderRight ([out, retval] BSTR* ReturnValue); - // VB6: Function borderRight As String - [DispId(-2147413061)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderRight (BSTR value); - // VB6: Sub borderRight (ByVal value As String) - [DispId(-2147413061)] set; - } - - /// borderRightColor property of IHTMLStyle interface. - /// An original IDL definition of borderRightColor property was the following: VARIANT borderRightColor; - // IDL: VARIANT borderRightColor; - // VB6: borderRightColor As Any - object borderRightColor - { - // IDL: HRESULT borderRightColor ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderRightColor As Any - [DispId(-2147413056)] get; - // IDL: HRESULT borderRightColor (VARIANT value); - // VB6: Sub borderRightColor (ByVal value As Any) - [DispId(-2147413056)] set; - } - - /// borderRightStyle property of IHTMLStyle interface. - /// An original IDL definition of borderRightStyle property was the following: BSTR borderRightStyle; - // IDL: BSTR borderRightStyle; - // VB6: borderRightStyle As String - string borderRightStyle - { - // IDL: HRESULT borderRightStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function borderRightStyle As String - [DispId(-2147413046)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderRightStyle (BSTR value); - // VB6: Sub borderRightStyle (ByVal value As String) - [DispId(-2147413046)] set; - } - - /// borderRightWidth property of IHTMLStyle interface. - /// An original IDL definition of borderRightWidth property was the following: VARIANT borderRightWidth; - // IDL: VARIANT borderRightWidth; - // VB6: borderRightWidth As Any - object borderRightWidth - { - // IDL: HRESULT borderRightWidth ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderRightWidth As Any - [DispId(-2147413051)] get; - // IDL: HRESULT borderRightWidth (VARIANT value); - // VB6: Sub borderRightWidth (ByVal value As Any) - [DispId(-2147413051)] set; - } - - /// borderStyle property of IHTMLStyle interface. - /// An original IDL definition of borderStyle property was the following: BSTR borderStyle; - // IDL: BSTR borderStyle; - // VB6: borderStyle As String - string borderStyle - { - // IDL: HRESULT borderStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function borderStyle As String - [DispId(-2147413048)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderStyle (BSTR value); - // VB6: Sub borderStyle (ByVal value As String) - [DispId(-2147413048)] set; - } - - /// borderTop property of IHTMLStyle interface. - /// An original IDL definition of borderTop property was the following: BSTR borderTop; - // IDL: BSTR borderTop; - // VB6: borderTop As String - string borderTop - { - // IDL: HRESULT borderTop ([out, retval] BSTR* ReturnValue); - // VB6: Function borderTop As String - [DispId(-2147413062)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderTop (BSTR value); - // VB6: Sub borderTop (ByVal value As String) - [DispId(-2147413062)] set; - } - - /// borderTopColor property of IHTMLStyle interface. - /// An original IDL definition of borderTopColor property was the following: VARIANT borderTopColor; - // IDL: VARIANT borderTopColor; - // VB6: borderTopColor As Any - object borderTopColor - { - // IDL: HRESULT borderTopColor ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderTopColor As Any - [DispId(-2147413057)] get; - // IDL: HRESULT borderTopColor (VARIANT value); - // VB6: Sub borderTopColor (ByVal value As Any) - [DispId(-2147413057)] set; - } - - /// borderTopStyle property of IHTMLStyle interface. - /// An original IDL definition of borderTopStyle property was the following: BSTR borderTopStyle; - // IDL: BSTR borderTopStyle; - // VB6: borderTopStyle As String - string borderTopStyle - { - // IDL: HRESULT borderTopStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function borderTopStyle As String - [DispId(-2147413047)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderTopStyle (BSTR value); - // VB6: Sub borderTopStyle (ByVal value As String) - [DispId(-2147413047)] set; - } - - /// borderTopWidth property of IHTMLStyle interface. - /// An original IDL definition of borderTopWidth property was the following: VARIANT borderTopWidth; - // IDL: VARIANT borderTopWidth; - // VB6: borderTopWidth As Any - object borderTopWidth - { - // IDL: HRESULT borderTopWidth ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderTopWidth As Any - [DispId(-2147413052)] get; - // IDL: HRESULT borderTopWidth (VARIANT value); - // VB6: Sub borderTopWidth (ByVal value As Any) - [DispId(-2147413052)] set; - } - - /// borderWidth property of IHTMLStyle interface. - /// An original IDL definition of borderWidth property was the following: BSTR borderWidth; - // IDL: BSTR borderWidth; - // VB6: borderWidth As String - string borderWidth - { - // IDL: HRESULT borderWidth ([out, retval] BSTR* ReturnValue); - // VB6: Function borderWidth As String - [DispId(-2147413053)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderWidth (BSTR value); - // VB6: Sub borderWidth (ByVal value As String) - [DispId(-2147413053)] set; - } - - /// clear property of IHTMLStyle interface. - /// An original IDL definition of clear property was the following: BSTR clear; - // IDL: BSTR clear; - // VB6: clear As String - string clear - { - // IDL: HRESULT clear ([out, retval] BSTR* ReturnValue); - // VB6: Function clear As String - [DispId(-2147413096)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT clear (BSTR value); - // VB6: Sub clear (ByVal value As String) - [DispId(-2147413096)] set; - } - - /// clip property of IHTMLStyle interface. - /// An original IDL definition of clip property was the following: BSTR clip; - // IDL: BSTR clip; - // VB6: clip As String - string clip - { - // IDL: HRESULT clip ([out, retval] BSTR* ReturnValue); - // VB6: Function clip As String - [DispId(-2147413020)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT clip (BSTR value); - // VB6: Sub clip (ByVal value As String) - [DispId(-2147413020)] set; - } - - /// color property of IHTMLStyle interface. - /// An original IDL definition of color property was the following: VARIANT color; - // IDL: VARIANT color; - // VB6: color As Any - object color - { - // IDL: HRESULT color ([out, retval] VARIANT* ReturnValue); - // VB6: Function color As Any - [DispId(-2147413110)] get; - // IDL: HRESULT color (VARIANT value); - // VB6: Sub color (ByVal value As Any) - [DispId(-2147413110)] set; - } - - /// cssText property of IHTMLStyle interface. - /// An original IDL definition of cssText property was the following: BSTR cssText; - // IDL: BSTR cssText; - // VB6: cssText As String - string cssText - { - // IDL: HRESULT cssText ([out, retval] BSTR* ReturnValue); - // VB6: Function cssText As String - [DispId(-2147413013)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT cssText (BSTR value); - // VB6: Sub cssText (ByVal value As String) - [DispId(-2147413013)] set; - } - - /// cursor property of IHTMLStyle interface. - /// An original IDL definition of cursor property was the following: BSTR cursor; - // IDL: BSTR cursor; - // VB6: cursor As String - string cursor - { - // IDL: HRESULT cursor ([out, retval] BSTR* ReturnValue); - // VB6: Function cursor As String - [DispId(-2147413010)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT cursor (BSTR value); - // VB6: Sub cursor (ByVal value As String) - [DispId(-2147413010)] set; - } - - /// display property of IHTMLStyle interface. - /// An original IDL definition of display property was the following: BSTR display; - // IDL: BSTR display; - // VB6: display As String - string display - { - // IDL: HRESULT display ([out, retval] BSTR* ReturnValue); - // VB6: Function display As String - [DispId(-2147413041)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT display (BSTR value); - // VB6: Sub display (ByVal value As String) - [DispId(-2147413041)] set; - } - - /// filter property of IHTMLStyle interface. - /// An original IDL definition of filter property was the following: BSTR filter; - // IDL: BSTR filter; - // VB6: filter As String - string filter - { - // IDL: HRESULT filter ([out, retval] BSTR* ReturnValue); - // VB6: Function filter As String - [DispId(-2147413030)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT filter (BSTR value); - // VB6: Sub filter (ByVal value As String) - [DispId(-2147413030)] set; - } - - /// font property of IHTMLStyle interface. - /// An original IDL definition of font property was the following: BSTR font; - // IDL: BSTR font; - // VB6: font As String - string font - { - // IDL: HRESULT font ([out, retval] BSTR* ReturnValue); - // VB6: Function font As String - [DispId(-2147413071)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT font (BSTR value); - // VB6: Sub font (ByVal value As String) - [DispId(-2147413071)] set; - } - - /// fontFamily property of IHTMLStyle interface. - /// An original IDL definition of fontFamily property was the following: BSTR fontFamily; - // IDL: BSTR fontFamily; - // VB6: fontFamily As String - string fontFamily - { - // IDL: HRESULT fontFamily ([out, retval] BSTR* ReturnValue); - // VB6: Function fontFamily As String - [DispId(-2147413094)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT fontFamily (BSTR value); - // VB6: Sub fontFamily (ByVal value As String) - [DispId(-2147413094)] set; - } - - /// fontSize property of IHTMLStyle interface. - /// An original IDL definition of fontSize property was the following: VARIANT fontSize; - // IDL: VARIANT fontSize; - // VB6: fontSize As Any - object fontSize - { - // IDL: HRESULT fontSize ([out, retval] VARIANT* ReturnValue); - // VB6: Function fontSize As Any - [DispId(-2147413093)] get; - // IDL: HRESULT fontSize (VARIANT value); - // VB6: Sub fontSize (ByVal value As Any) - [DispId(-2147413093)] set; - } - - /// fontStyle property of IHTMLStyle interface. - /// An original IDL definition of fontStyle property was the following: BSTR fontStyle; - // IDL: BSTR fontStyle; - // VB6: fontStyle As String - string fontStyle - { - // IDL: HRESULT fontStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function fontStyle As String - [DispId(-2147413088)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT fontStyle (BSTR value); - // VB6: Sub fontStyle (ByVal value As String) - [DispId(-2147413088)] set; - } - - /// fontVariant property of IHTMLStyle interface. - /// An original IDL definition of fontVariant property was the following: BSTR fontVariant; - // IDL: BSTR fontVariant; - // VB6: fontVariant As String - string fontVariant - { - // IDL: HRESULT fontVariant ([out, retval] BSTR* ReturnValue); - // VB6: Function fontVariant As String - [DispId(-2147413087)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT fontVariant (BSTR value); - // VB6: Sub fontVariant (ByVal value As String) - [DispId(-2147413087)] set; - } - - /// fontWeight property of IHTMLStyle interface. - /// An original IDL definition of fontWeight property was the following: BSTR fontWeight; - // IDL: BSTR fontWeight; - // VB6: fontWeight As String - string fontWeight - { - // IDL: HRESULT fontWeight ([out, retval] BSTR* ReturnValue); - // VB6: Function fontWeight As String - [DispId(-2147413085)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT fontWeight (BSTR value); - // VB6: Sub fontWeight (ByVal value As String) - [DispId(-2147413085)] set; - } - - /// height property of IHTMLStyle interface. - /// An original IDL definition of height property was the following: VARIANT height; - // IDL: VARIANT height; - // VB6: height As Any - object height - { - // IDL: HRESULT height ([out, retval] VARIANT* ReturnValue); - // VB6: Function height As Any - [DispId(-2147418106)] get; - // IDL: HRESULT height (VARIANT value); - // VB6: Sub height (ByVal value As Any) - [DispId(-2147418106)] set; - } - - /// left property of IHTMLStyle interface. - /// An original IDL definition of left property was the following: VARIANT left; - // IDL: VARIANT left; - // VB6: left As Any - object left - { - // IDL: HRESULT left ([out, retval] VARIANT* ReturnValue); - // VB6: Function left As Any - [DispId(-2147418109)] get; - // IDL: HRESULT left (VARIANT value); - // VB6: Sub left (ByVal value As Any) - [DispId(-2147418109)] set; - } - - /// letterSpacing property of IHTMLStyle interface. - /// An original IDL definition of letterSpacing property was the following: VARIANT letterSpacing; - // IDL: VARIANT letterSpacing; - // VB6: letterSpacing As Any - object letterSpacing - { - // IDL: HRESULT letterSpacing ([out, retval] VARIANT* ReturnValue); - // VB6: Function letterSpacing As Any - [DispId(-2147413104)] get; - // IDL: HRESULT letterSpacing (VARIANT value); - // VB6: Sub letterSpacing (ByVal value As Any) - [DispId(-2147413104)] set; - } - - /// lineHeight property of IHTMLStyle interface. - /// An original IDL definition of lineHeight property was the following: VARIANT lineHeight; - // IDL: VARIANT lineHeight; - // VB6: lineHeight As Any - object lineHeight - { - // IDL: HRESULT lineHeight ([out, retval] VARIANT* ReturnValue); - // VB6: Function lineHeight As Any - [DispId(-2147413106)] get; - // IDL: HRESULT lineHeight (VARIANT value); - // VB6: Sub lineHeight (ByVal value As Any) - [DispId(-2147413106)] set; - } - - /// listStyle property of IHTMLStyle interface. - /// An original IDL definition of listStyle property was the following: BSTR listStyle; - // IDL: BSTR listStyle; - // VB6: listStyle As String - string listStyle - { - // IDL: HRESULT listStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function listStyle As String - [DispId(-2147413037)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT listStyle (BSTR value); - // VB6: Sub listStyle (ByVal value As String) - [DispId(-2147413037)] set; - } - - /// listStyleImage property of IHTMLStyle interface. - /// An original IDL definition of listStyleImage property was the following: BSTR listStyleImage; - // IDL: BSTR listStyleImage; - // VB6: listStyleImage As String - string listStyleImage - { - // IDL: HRESULT listStyleImage ([out, retval] BSTR* ReturnValue); - // VB6: Function listStyleImage As String - [DispId(-2147413038)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT listStyleImage (BSTR value); - // VB6: Sub listStyleImage (ByVal value As String) - [DispId(-2147413038)] set; - } - - /// listStylePosition property of IHTMLStyle interface. - /// An original IDL definition of listStylePosition property was the following: BSTR listStylePosition; - // IDL: BSTR listStylePosition; - // VB6: listStylePosition As String - string listStylePosition - { - // IDL: HRESULT listStylePosition ([out, retval] BSTR* ReturnValue); - // VB6: Function listStylePosition As String - [DispId(-2147413039)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT listStylePosition (BSTR value); - // VB6: Sub listStylePosition (ByVal value As String) - [DispId(-2147413039)] set; - } - - /// listStyleType property of IHTMLStyle interface. - /// An original IDL definition of listStyleType property was the following: BSTR listStyleType; - // IDL: BSTR listStyleType; - // VB6: listStyleType As String - string listStyleType - { - // IDL: HRESULT listStyleType ([out, retval] BSTR* ReturnValue); - // VB6: Function listStyleType As String - [DispId(-2147413040)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT listStyleType (BSTR value); - // VB6: Sub listStyleType (ByVal value As String) - [DispId(-2147413040)] set; - } - - /// margin property of IHTMLStyle interface. - /// An original IDL definition of margin property was the following: BSTR margin; - // IDL: BSTR margin; - // VB6: margin As String - string margin - { - // IDL: HRESULT margin ([out, retval] BSTR* ReturnValue); - // VB6: Function margin As String - [DispId(-2147413076)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT margin (BSTR value); - // VB6: Sub margin (ByVal value As String) - [DispId(-2147413076)] set; - } - - /// marginBottom property of IHTMLStyle interface. - /// An original IDL definition of marginBottom property was the following: VARIANT marginBottom; - // IDL: VARIANT marginBottom; - // VB6: marginBottom As Any - object marginBottom - { - // IDL: HRESULT marginBottom ([out, retval] VARIANT* ReturnValue); - // VB6: Function marginBottom As Any - [DispId(-2147413073)] get; - // IDL: HRESULT marginBottom (VARIANT value); - // VB6: Sub marginBottom (ByVal value As Any) - [DispId(-2147413073)] set; - } - - /// marginLeft property of IHTMLStyle interface. - /// An original IDL definition of marginLeft property was the following: VARIANT marginLeft; - // IDL: VARIANT marginLeft; - // VB6: marginLeft As Any - object marginLeft - { - // IDL: HRESULT marginLeft ([out, retval] VARIANT* ReturnValue); - // VB6: Function marginLeft As Any - [DispId(-2147413072)] get; - // IDL: HRESULT marginLeft (VARIANT value); - // VB6: Sub marginLeft (ByVal value As Any) - [DispId(-2147413072)] set; - } - - /// marginRight property of IHTMLStyle interface. - /// An original IDL definition of marginRight property was the following: VARIANT marginRight; - // IDL: VARIANT marginRight; - // VB6: marginRight As Any - object marginRight - { - // IDL: HRESULT marginRight ([out, retval] VARIANT* ReturnValue); - // VB6: Function marginRight As Any - [DispId(-2147413074)] get; - // IDL: HRESULT marginRight (VARIANT value); - // VB6: Sub marginRight (ByVal value As Any) - [DispId(-2147413074)] set; - } - - /// marginTop property of IHTMLStyle interface. - /// An original IDL definition of marginTop property was the following: VARIANT marginTop; - // IDL: VARIANT marginTop; - // VB6: marginTop As Any - object marginTop - { - // IDL: HRESULT marginTop ([out, retval] VARIANT* ReturnValue); - // VB6: Function marginTop As Any - [DispId(-2147413075)] get; - // IDL: HRESULT marginTop (VARIANT value); - // VB6: Sub marginTop (ByVal value As Any) - [DispId(-2147413075)] set; - } - - /// overflow property of IHTMLStyle interface. - /// An original IDL definition of overflow property was the following: BSTR overflow; - // IDL: BSTR overflow; - // VB6: overflow As String - string overflow - { - // IDL: HRESULT overflow ([out, retval] BSTR* ReturnValue); - // VB6: Function overflow As String - [DispId(-2147413102)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT overflow (BSTR value); - // VB6: Sub overflow (ByVal value As String) - [DispId(-2147413102)] set; - } - - /// padding property of IHTMLStyle interface. - /// An original IDL definition of padding property was the following: BSTR padding; - // IDL: BSTR padding; - // VB6: padding As String - string padding - { - // IDL: HRESULT padding ([out, retval] BSTR* ReturnValue); - // VB6: Function padding As String - [DispId(-2147413101)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT padding (BSTR value); - // VB6: Sub padding (ByVal value As String) - [DispId(-2147413101)] set; - } - - /// paddingBottom property of IHTMLStyle interface. - /// An original IDL definition of paddingBottom property was the following: VARIANT paddingBottom; - // IDL: VARIANT paddingBottom; - // VB6: paddingBottom As Any - object paddingBottom - { - // IDL: HRESULT paddingBottom ([out, retval] VARIANT* ReturnValue); - // VB6: Function paddingBottom As Any - [DispId(-2147413098)] get; - // IDL: HRESULT paddingBottom (VARIANT value); - // VB6: Sub paddingBottom (ByVal value As Any) - [DispId(-2147413098)] set; - } - - /// paddingLeft property of IHTMLStyle interface. - /// An original IDL definition of paddingLeft property was the following: VARIANT paddingLeft; - // IDL: VARIANT paddingLeft; - // VB6: paddingLeft As Any - object paddingLeft - { - // IDL: HRESULT paddingLeft ([out, retval] VARIANT* ReturnValue); - // VB6: Function paddingLeft As Any - [DispId(-2147413097)] get; - // IDL: HRESULT paddingLeft (VARIANT value); - // VB6: Sub paddingLeft (ByVal value As Any) - [DispId(-2147413097)] set; - } - - /// paddingRight property of IHTMLStyle interface. - object paddingRight { [DispId(-2147413099)] get; } - - /// paddingTop property of IHTMLStyle interface. - object paddingTop { [DispId(-2147413100)] get; } - - /// pageBreakAfter property of IHTMLStyle interface. - string pageBreakAfter - { - [DispId(-2147413034)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// pageBreakBefore property of IHTMLStyle interface. - string pageBreakBefore - { - [DispId(-2147413035)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// pixelHeight property of IHTMLStyle interface. - int pixelHeight { [DispId(-2147414109)] get; } - - /// pixelLeft property of IHTMLStyle interface. - int pixelLeft { [DispId(-2147414111)] get; } - - /// pixelTop property of IHTMLStyle interface. - int pixelTop { [DispId(-2147414112)] get; } - - /// pixelWidth property of IHTMLStyle interface. - int pixelWidth { [DispId(-2147414110)] get; } - - /// posHeight property of IHTMLStyle interface. - float posHeight { [DispId(-2147414105)] get; } - - /// position property of IHTMLStyle interface. - string position - { - [DispId(-2147413022)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// posLeft property of IHTMLStyle interface. - float posLeft { [DispId(-2147414107)] get; } - - /// posTop property of IHTMLStyle interface. - float posTop { [DispId(-2147414108)] get; } - - /// posWidth property of IHTMLStyle interface. - float posWidth { [DispId(-2147414106)] get; } - - /// styleFloat property of IHTMLStyle interface. - string styleFloat - { - [DispId(-2147413042)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// textAlign property of IHTMLStyle interface. - string textAlign - { - [DispId(-2147418040)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// textDecoration property of IHTMLStyle interface. - string textDecoration - { - [DispId(-2147413077)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// textDecorationBlink property of IHTMLStyle interface. - bool textDecorationBlink - { - [DispId(-2147413090)] - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - /// textDecorationLineThrough property of IHTMLStyle interface. - bool textDecorationLineThrough - { - [DispId(-2147413092)] - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - /// textDecorationNone property of IHTMLStyle interface. - bool textDecorationNone - { - [DispId(-2147413089)] - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - /// textDecorationOverline property of IHTMLStyle interface. - bool textDecorationOverline - { - [DispId(-2147413043)] - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - /// textDecorationUnderline property of IHTMLStyle interface. - bool textDecorationUnderline - { - [DispId(-2147413091)] - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - /// textIndent property of IHTMLStyle interface. - object textIndent { [DispId(-2147413105)] get; } - - /// textTransform property of IHTMLStyle interface. - string textTransform - { - [DispId(-2147413108)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// top property of IHTMLStyle interface. - object top { [DispId(-2147418108)] get; } - - /// verticalAlign property of IHTMLStyle interface. - object verticalAlign { [DispId(-2147413064)] get; } - - /// visibility property of IHTMLStyle interface. - string visibility - { - [DispId(-2147413032)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// whiteSpace property of IHTMLStyle interface. - string whiteSpace - { - [DispId(-2147413036)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// width property of IHTMLStyle interface. - object width { [DispId(-2147418107)] get; } - - /// wordSpacing property of IHTMLStyle interface. - object wordSpacing { [DispId(-2147413065)] get; } - - /// zIndex property of IHTMLStyle interface. - object zIndex { [DispId(-2147413021)] get; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F25E-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLStyle + { + /// setAttribute method of IHTMLStyle interface. + /// An original IDL definition of setAttribute method was the following: HRESULT setAttribute (BSTR strAttributeName, VARIANT AttributeValue, [optional, defaultvalue(1)] long lFlags); + // IDL: HRESULT setAttribute (BSTR strAttributeName, VARIANT AttributeValue, [optional, defaultvalue(1)] long lFlags); + // VB6: Sub setAttribute (ByVal strAttributeName As String, ByVal AttributeValue As Any, [ByVal lFlags As Long = 1]) + [DispId(-2147417611)] + void setAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, object AttributeValue, int lFlags); + + /// getAttribute method of IHTMLStyle interface. + /// An original IDL definition of getAttribute method was the following: HRESULT getAttribute (BSTR strAttributeName, [optional, defaultvalue(0)] long lFlags, [out, retval] VARIANT* ReturnValue); + // IDL: HRESULT getAttribute (BSTR strAttributeName, [optional, defaultvalue(0)] long lFlags, [out, retval] VARIANT* ReturnValue); + // VB6: Function getAttribute (ByVal strAttributeName As String, [ByVal lFlags As Long = 0]) As Any + [DispId(-2147417610)] + object getAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); + + /// removeAttribute method of IHTMLStyle interface. + /// An original IDL definition of removeAttribute method was the following: HRESULT removeAttribute (BSTR strAttributeName, [optional, defaultvalue(1)] long lFlags, [out, retval] VARIANT_BOOL* ReturnValue); + // IDL: HRESULT removeAttribute (BSTR strAttributeName, [optional, defaultvalue(1)] long lFlags, [out, retval] VARIANT_BOOL* ReturnValue); + // VB6: Function removeAttribute (ByVal strAttributeName As String, [ByVal lFlags As Long = 1]) As Boolean + [DispId(-2147417609)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool removeAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); + + /// toString method of IHTMLStyle interface. + /// An original IDL definition of toString method was the following: HRESULT toString ([out, retval] BSTR* ReturnValue); + // IDL: HRESULT toString ([out, retval] BSTR* ReturnValue); + // VB6: Function toString As String + [DispId(-2147414104)] + [return: MarshalAs(UnmanagedType.BStr)] + string toString(); + + /// background property of IHTMLStyle interface. + /// An original IDL definition of background property was the following: BSTR background; + // IDL: BSTR background; + // VB6: background As String + string background + { + // IDL: HRESULT background ([out, retval] BSTR* ReturnValue); + // VB6: Function background As String + [DispId(-2147413080)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT background (BSTR value); + // VB6: Sub background (ByVal value As String) + [DispId(-2147413080)] set; + } + + /// backgroundAttachment property of IHTMLStyle interface. + /// An original IDL definition of backgroundAttachment property was the following: BSTR backgroundAttachment; + // IDL: BSTR backgroundAttachment; + // VB6: backgroundAttachment As String + string backgroundAttachment + { + // IDL: HRESULT backgroundAttachment ([out, retval] BSTR* ReturnValue); + // VB6: Function backgroundAttachment As String + [DispId(-2147413067)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT backgroundAttachment (BSTR value); + // VB6: Sub backgroundAttachment (ByVal value As String) + [DispId(-2147413067)] set; + } + + /// backgroundColor property of IHTMLStyle interface. + /// An original IDL definition of backgroundColor property was the following: VARIANT backgroundColor; + // IDL: VARIANT backgroundColor; + // VB6: backgroundColor As Any + object backgroundColor + { + // IDL: HRESULT backgroundColor ([out, retval] VARIANT* ReturnValue); + // VB6: Function backgroundColor As Any + [DispId(-501)] get; + // IDL: HRESULT backgroundColor (VARIANT value); + // VB6: Sub backgroundColor (ByVal value As Any) + [DispId(-501)] set; + } + + /// backgroundImage property of IHTMLStyle interface. + /// An original IDL definition of backgroundImage property was the following: BSTR backgroundImage; + // IDL: BSTR backgroundImage; + // VB6: backgroundImage As String + string backgroundImage + { + // IDL: HRESULT backgroundImage ([out, retval] BSTR* ReturnValue); + // VB6: Function backgroundImage As String + [DispId(-2147413111)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT backgroundImage (BSTR value); + // VB6: Sub backgroundImage (ByVal value As String) + [DispId(-2147413111)] set; + } + + /// backgroundPosition property of IHTMLStyle interface. + /// An original IDL definition of backgroundPosition property was the following: BSTR backgroundPosition; + // IDL: BSTR backgroundPosition; + // VB6: backgroundPosition As String + string backgroundPosition + { + // IDL: HRESULT backgroundPosition ([out, retval] BSTR* ReturnValue); + // VB6: Function backgroundPosition As String + [DispId(-2147413066)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT backgroundPosition (BSTR value); + // VB6: Sub backgroundPosition (ByVal value As String) + [DispId(-2147413066)] set; + } + + /// backgroundPositionX property of IHTMLStyle interface. + /// An original IDL definition of backgroundPositionX property was the following: VARIANT backgroundPositionX; + // IDL: VARIANT backgroundPositionX; + // VB6: backgroundPositionX As Any + object backgroundPositionX + { + // IDL: HRESULT backgroundPositionX ([out, retval] VARIANT* ReturnValue); + // VB6: Function backgroundPositionX As Any + [DispId(-2147413079)] get; + // IDL: HRESULT backgroundPositionX (VARIANT value); + // VB6: Sub backgroundPositionX (ByVal value As Any) + [DispId(-2147413079)] set; + } + + /// backgroundPositionY property of IHTMLStyle interface. + /// An original IDL definition of backgroundPositionY property was the following: VARIANT backgroundPositionY; + // IDL: VARIANT backgroundPositionY; + // VB6: backgroundPositionY As Any + object backgroundPositionY + { + // IDL: HRESULT backgroundPositionY ([out, retval] VARIANT* ReturnValue); + // VB6: Function backgroundPositionY As Any + [DispId(-2147413078)] get; + // IDL: HRESULT backgroundPositionY (VARIANT value); + // VB6: Sub backgroundPositionY (ByVal value As Any) + [DispId(-2147413078)] set; + } + + /// backgroundRepeat property of IHTMLStyle interface. + /// An original IDL definition of backgroundRepeat property was the following: BSTR backgroundRepeat; + // IDL: BSTR backgroundRepeat; + // VB6: backgroundRepeat As String + string backgroundRepeat + { + // IDL: HRESULT backgroundRepeat ([out, retval] BSTR* ReturnValue); + // VB6: Function backgroundRepeat As String + [DispId(-2147413068)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT backgroundRepeat (BSTR value); + // VB6: Sub backgroundRepeat (ByVal value As String) + [DispId(-2147413068)] set; + } + + /// border property of IHTMLStyle interface. + /// An original IDL definition of border property was the following: BSTR border; + // IDL: BSTR border; + // VB6: border As String + string border + { + // IDL: HRESULT border ([out, retval] BSTR* ReturnValue); + // VB6: Function border As String + [DispId(-2147413063)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT border (BSTR value); + // VB6: Sub border (ByVal value As String) + [DispId(-2147413063)] set; + } + + /// borderBottom property of IHTMLStyle interface. + /// An original IDL definition of borderBottom property was the following: BSTR borderBottom; + // IDL: BSTR borderBottom; + // VB6: borderBottom As String + string borderBottom + { + // IDL: HRESULT borderBottom ([out, retval] BSTR* ReturnValue); + // VB6: Function borderBottom As String + [DispId(-2147413060)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderBottom (BSTR value); + // VB6: Sub borderBottom (ByVal value As String) + [DispId(-2147413060)] set; + } + + /// borderBottomColor property of IHTMLStyle interface. + /// An original IDL definition of borderBottomColor property was the following: VARIANT borderBottomColor; + // IDL: VARIANT borderBottomColor; + // VB6: borderBottomColor As Any + object borderBottomColor + { + // IDL: HRESULT borderBottomColor ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderBottomColor As Any + [DispId(-2147413055)] get; + // IDL: HRESULT borderBottomColor (VARIANT value); + // VB6: Sub borderBottomColor (ByVal value As Any) + [DispId(-2147413055)] set; + } + + /// borderBottomStyle property of IHTMLStyle interface. + /// An original IDL definition of borderBottomStyle property was the following: BSTR borderBottomStyle; + // IDL: BSTR borderBottomStyle; + // VB6: borderBottomStyle As String + string borderBottomStyle + { + // IDL: HRESULT borderBottomStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function borderBottomStyle As String + [DispId(-2147413045)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderBottomStyle (BSTR value); + // VB6: Sub borderBottomStyle (ByVal value As String) + [DispId(-2147413045)] set; + } + + /// borderBottomWidth property of IHTMLStyle interface. + /// An original IDL definition of borderBottomWidth property was the following: VARIANT borderBottomWidth; + // IDL: VARIANT borderBottomWidth; + // VB6: borderBottomWidth As Any + object borderBottomWidth + { + // IDL: HRESULT borderBottomWidth ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderBottomWidth As Any + [DispId(-2147413050)] get; + // IDL: HRESULT borderBottomWidth (VARIANT value); + // VB6: Sub borderBottomWidth (ByVal value As Any) + [DispId(-2147413050)] set; + } + + /// borderColor property of IHTMLStyle interface. + /// An original IDL definition of borderColor property was the following: BSTR borderColor; + // IDL: BSTR borderColor; + // VB6: borderColor As String + string borderColor + { + // IDL: HRESULT borderColor ([out, retval] BSTR* ReturnValue); + // VB6: Function borderColor As String + [DispId(-2147413058)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderColor (BSTR value); + // VB6: Sub borderColor (ByVal value As String) + [DispId(-2147413058)] set; + } + + /// borderLeft property of IHTMLStyle interface. + /// An original IDL definition of borderLeft property was the following: BSTR borderLeft; + // IDL: BSTR borderLeft; + // VB6: borderLeft As String + string borderLeft + { + // IDL: HRESULT borderLeft ([out, retval] BSTR* ReturnValue); + // VB6: Function borderLeft As String + [DispId(-2147413059)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderLeft (BSTR value); + // VB6: Sub borderLeft (ByVal value As String) + [DispId(-2147413059)] set; + } + + /// borderLeftColor property of IHTMLStyle interface. + /// An original IDL definition of borderLeftColor property was the following: VARIANT borderLeftColor; + // IDL: VARIANT borderLeftColor; + // VB6: borderLeftColor As Any + object borderLeftColor + { + // IDL: HRESULT borderLeftColor ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderLeftColor As Any + [DispId(-2147413054)] get; + // IDL: HRESULT borderLeftColor (VARIANT value); + // VB6: Sub borderLeftColor (ByVal value As Any) + [DispId(-2147413054)] set; + } + + /// borderLeftStyle property of IHTMLStyle interface. + /// An original IDL definition of borderLeftStyle property was the following: BSTR borderLeftStyle; + // IDL: BSTR borderLeftStyle; + // VB6: borderLeftStyle As String + string borderLeftStyle + { + // IDL: HRESULT borderLeftStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function borderLeftStyle As String + [DispId(-2147413044)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderLeftStyle (BSTR value); + // VB6: Sub borderLeftStyle (ByVal value As String) + [DispId(-2147413044)] set; + } + + /// borderLeftWidth property of IHTMLStyle interface. + /// An original IDL definition of borderLeftWidth property was the following: VARIANT borderLeftWidth; + // IDL: VARIANT borderLeftWidth; + // VB6: borderLeftWidth As Any + object borderLeftWidth + { + // IDL: HRESULT borderLeftWidth ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderLeftWidth As Any + [DispId(-2147413049)] get; + // IDL: HRESULT borderLeftWidth (VARIANT value); + // VB6: Sub borderLeftWidth (ByVal value As Any) + [DispId(-2147413049)] set; + } + + /// borderRight property of IHTMLStyle interface. + /// An original IDL definition of borderRight property was the following: BSTR borderRight; + // IDL: BSTR borderRight; + // VB6: borderRight As String + string borderRight + { + // IDL: HRESULT borderRight ([out, retval] BSTR* ReturnValue); + // VB6: Function borderRight As String + [DispId(-2147413061)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderRight (BSTR value); + // VB6: Sub borderRight (ByVal value As String) + [DispId(-2147413061)] set; + } + + /// borderRightColor property of IHTMLStyle interface. + /// An original IDL definition of borderRightColor property was the following: VARIANT borderRightColor; + // IDL: VARIANT borderRightColor; + // VB6: borderRightColor As Any + object borderRightColor + { + // IDL: HRESULT borderRightColor ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderRightColor As Any + [DispId(-2147413056)] get; + // IDL: HRESULT borderRightColor (VARIANT value); + // VB6: Sub borderRightColor (ByVal value As Any) + [DispId(-2147413056)] set; + } + + /// borderRightStyle property of IHTMLStyle interface. + /// An original IDL definition of borderRightStyle property was the following: BSTR borderRightStyle; + // IDL: BSTR borderRightStyle; + // VB6: borderRightStyle As String + string borderRightStyle + { + // IDL: HRESULT borderRightStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function borderRightStyle As String + [DispId(-2147413046)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderRightStyle (BSTR value); + // VB6: Sub borderRightStyle (ByVal value As String) + [DispId(-2147413046)] set; + } + + /// borderRightWidth property of IHTMLStyle interface. + /// An original IDL definition of borderRightWidth property was the following: VARIANT borderRightWidth; + // IDL: VARIANT borderRightWidth; + // VB6: borderRightWidth As Any + object borderRightWidth + { + // IDL: HRESULT borderRightWidth ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderRightWidth As Any + [DispId(-2147413051)] get; + // IDL: HRESULT borderRightWidth (VARIANT value); + // VB6: Sub borderRightWidth (ByVal value As Any) + [DispId(-2147413051)] set; + } + + /// borderStyle property of IHTMLStyle interface. + /// An original IDL definition of borderStyle property was the following: BSTR borderStyle; + // IDL: BSTR borderStyle; + // VB6: borderStyle As String + string borderStyle + { + // IDL: HRESULT borderStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function borderStyle As String + [DispId(-2147413048)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderStyle (BSTR value); + // VB6: Sub borderStyle (ByVal value As String) + [DispId(-2147413048)] set; + } + + /// borderTop property of IHTMLStyle interface. + /// An original IDL definition of borderTop property was the following: BSTR borderTop; + // IDL: BSTR borderTop; + // VB6: borderTop As String + string borderTop + { + // IDL: HRESULT borderTop ([out, retval] BSTR* ReturnValue); + // VB6: Function borderTop As String + [DispId(-2147413062)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderTop (BSTR value); + // VB6: Sub borderTop (ByVal value As String) + [DispId(-2147413062)] set; + } + + /// borderTopColor property of IHTMLStyle interface. + /// An original IDL definition of borderTopColor property was the following: VARIANT borderTopColor; + // IDL: VARIANT borderTopColor; + // VB6: borderTopColor As Any + object borderTopColor + { + // IDL: HRESULT borderTopColor ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderTopColor As Any + [DispId(-2147413057)] get; + // IDL: HRESULT borderTopColor (VARIANT value); + // VB6: Sub borderTopColor (ByVal value As Any) + [DispId(-2147413057)] set; + } + + /// borderTopStyle property of IHTMLStyle interface. + /// An original IDL definition of borderTopStyle property was the following: BSTR borderTopStyle; + // IDL: BSTR borderTopStyle; + // VB6: borderTopStyle As String + string borderTopStyle + { + // IDL: HRESULT borderTopStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function borderTopStyle As String + [DispId(-2147413047)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderTopStyle (BSTR value); + // VB6: Sub borderTopStyle (ByVal value As String) + [DispId(-2147413047)] set; + } + + /// borderTopWidth property of IHTMLStyle interface. + /// An original IDL definition of borderTopWidth property was the following: VARIANT borderTopWidth; + // IDL: VARIANT borderTopWidth; + // VB6: borderTopWidth As Any + object borderTopWidth + { + // IDL: HRESULT borderTopWidth ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderTopWidth As Any + [DispId(-2147413052)] get; + // IDL: HRESULT borderTopWidth (VARIANT value); + // VB6: Sub borderTopWidth (ByVal value As Any) + [DispId(-2147413052)] set; + } + + /// borderWidth property of IHTMLStyle interface. + /// An original IDL definition of borderWidth property was the following: BSTR borderWidth; + // IDL: BSTR borderWidth; + // VB6: borderWidth As String + string borderWidth + { + // IDL: HRESULT borderWidth ([out, retval] BSTR* ReturnValue); + // VB6: Function borderWidth As String + [DispId(-2147413053)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderWidth (BSTR value); + // VB6: Sub borderWidth (ByVal value As String) + [DispId(-2147413053)] set; + } + + /// clear property of IHTMLStyle interface. + /// An original IDL definition of clear property was the following: BSTR clear; + // IDL: BSTR clear; + // VB6: clear As String + string clear + { + // IDL: HRESULT clear ([out, retval] BSTR* ReturnValue); + // VB6: Function clear As String + [DispId(-2147413096)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT clear (BSTR value); + // VB6: Sub clear (ByVal value As String) + [DispId(-2147413096)] set; + } + + /// clip property of IHTMLStyle interface. + /// An original IDL definition of clip property was the following: BSTR clip; + // IDL: BSTR clip; + // VB6: clip As String + string clip + { + // IDL: HRESULT clip ([out, retval] BSTR* ReturnValue); + // VB6: Function clip As String + [DispId(-2147413020)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT clip (BSTR value); + // VB6: Sub clip (ByVal value As String) + [DispId(-2147413020)] set; + } + + /// color property of IHTMLStyle interface. + /// An original IDL definition of color property was the following: VARIANT color; + // IDL: VARIANT color; + // VB6: color As Any + object color + { + // IDL: HRESULT color ([out, retval] VARIANT* ReturnValue); + // VB6: Function color As Any + [DispId(-2147413110)] get; + // IDL: HRESULT color (VARIANT value); + // VB6: Sub color (ByVal value As Any) + [DispId(-2147413110)] set; + } + + /// cssText property of IHTMLStyle interface. + /// An original IDL definition of cssText property was the following: BSTR cssText; + // IDL: BSTR cssText; + // VB6: cssText As String + string cssText + { + // IDL: HRESULT cssText ([out, retval] BSTR* ReturnValue); + // VB6: Function cssText As String + [DispId(-2147413013)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT cssText (BSTR value); + // VB6: Sub cssText (ByVal value As String) + [DispId(-2147413013)] set; + } + + /// cursor property of IHTMLStyle interface. + /// An original IDL definition of cursor property was the following: BSTR cursor; + // IDL: BSTR cursor; + // VB6: cursor As String + string cursor + { + // IDL: HRESULT cursor ([out, retval] BSTR* ReturnValue); + // VB6: Function cursor As String + [DispId(-2147413010)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT cursor (BSTR value); + // VB6: Sub cursor (ByVal value As String) + [DispId(-2147413010)] set; + } + + /// display property of IHTMLStyle interface. + /// An original IDL definition of display property was the following: BSTR display; + // IDL: BSTR display; + // VB6: display As String + string display + { + // IDL: HRESULT display ([out, retval] BSTR* ReturnValue); + // VB6: Function display As String + [DispId(-2147413041)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT display (BSTR value); + // VB6: Sub display (ByVal value As String) + [DispId(-2147413041)] set; + } + + /// filter property of IHTMLStyle interface. + /// An original IDL definition of filter property was the following: BSTR filter; + // IDL: BSTR filter; + // VB6: filter As String + string filter + { + // IDL: HRESULT filter ([out, retval] BSTR* ReturnValue); + // VB6: Function filter As String + [DispId(-2147413030)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT filter (BSTR value); + // VB6: Sub filter (ByVal value As String) + [DispId(-2147413030)] set; + } + + /// font property of IHTMLStyle interface. + /// An original IDL definition of font property was the following: BSTR font; + // IDL: BSTR font; + // VB6: font As String + string font + { + // IDL: HRESULT font ([out, retval] BSTR* ReturnValue); + // VB6: Function font As String + [DispId(-2147413071)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT font (BSTR value); + // VB6: Sub font (ByVal value As String) + [DispId(-2147413071)] set; + } + + /// fontFamily property of IHTMLStyle interface. + /// An original IDL definition of fontFamily property was the following: BSTR fontFamily; + // IDL: BSTR fontFamily; + // VB6: fontFamily As String + string fontFamily + { + // IDL: HRESULT fontFamily ([out, retval] BSTR* ReturnValue); + // VB6: Function fontFamily As String + [DispId(-2147413094)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT fontFamily (BSTR value); + // VB6: Sub fontFamily (ByVal value As String) + [DispId(-2147413094)] set; + } + + /// fontSize property of IHTMLStyle interface. + /// An original IDL definition of fontSize property was the following: VARIANT fontSize; + // IDL: VARIANT fontSize; + // VB6: fontSize As Any + object fontSize + { + // IDL: HRESULT fontSize ([out, retval] VARIANT* ReturnValue); + // VB6: Function fontSize As Any + [DispId(-2147413093)] get; + // IDL: HRESULT fontSize (VARIANT value); + // VB6: Sub fontSize (ByVal value As Any) + [DispId(-2147413093)] set; + } + + /// fontStyle property of IHTMLStyle interface. + /// An original IDL definition of fontStyle property was the following: BSTR fontStyle; + // IDL: BSTR fontStyle; + // VB6: fontStyle As String + string fontStyle + { + // IDL: HRESULT fontStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function fontStyle As String + [DispId(-2147413088)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT fontStyle (BSTR value); + // VB6: Sub fontStyle (ByVal value As String) + [DispId(-2147413088)] set; + } + + /// fontVariant property of IHTMLStyle interface. + /// An original IDL definition of fontVariant property was the following: BSTR fontVariant; + // IDL: BSTR fontVariant; + // VB6: fontVariant As String + string fontVariant + { + // IDL: HRESULT fontVariant ([out, retval] BSTR* ReturnValue); + // VB6: Function fontVariant As String + [DispId(-2147413087)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT fontVariant (BSTR value); + // VB6: Sub fontVariant (ByVal value As String) + [DispId(-2147413087)] set; + } + + /// fontWeight property of IHTMLStyle interface. + /// An original IDL definition of fontWeight property was the following: BSTR fontWeight; + // IDL: BSTR fontWeight; + // VB6: fontWeight As String + string fontWeight + { + // IDL: HRESULT fontWeight ([out, retval] BSTR* ReturnValue); + // VB6: Function fontWeight As String + [DispId(-2147413085)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT fontWeight (BSTR value); + // VB6: Sub fontWeight (ByVal value As String) + [DispId(-2147413085)] set; + } + + /// height property of IHTMLStyle interface. + /// An original IDL definition of height property was the following: VARIANT height; + // IDL: VARIANT height; + // VB6: height As Any + object height + { + // IDL: HRESULT height ([out, retval] VARIANT* ReturnValue); + // VB6: Function height As Any + [DispId(-2147418106)] get; + // IDL: HRESULT height (VARIANT value); + // VB6: Sub height (ByVal value As Any) + [DispId(-2147418106)] set; + } + + /// left property of IHTMLStyle interface. + /// An original IDL definition of left property was the following: VARIANT left; + // IDL: VARIANT left; + // VB6: left As Any + object left + { + // IDL: HRESULT left ([out, retval] VARIANT* ReturnValue); + // VB6: Function left As Any + [DispId(-2147418109)] get; + // IDL: HRESULT left (VARIANT value); + // VB6: Sub left (ByVal value As Any) + [DispId(-2147418109)] set; + } + + /// letterSpacing property of IHTMLStyle interface. + /// An original IDL definition of letterSpacing property was the following: VARIANT letterSpacing; + // IDL: VARIANT letterSpacing; + // VB6: letterSpacing As Any + object letterSpacing + { + // IDL: HRESULT letterSpacing ([out, retval] VARIANT* ReturnValue); + // VB6: Function letterSpacing As Any + [DispId(-2147413104)] get; + // IDL: HRESULT letterSpacing (VARIANT value); + // VB6: Sub letterSpacing (ByVal value As Any) + [DispId(-2147413104)] set; + } + + /// lineHeight property of IHTMLStyle interface. + /// An original IDL definition of lineHeight property was the following: VARIANT lineHeight; + // IDL: VARIANT lineHeight; + // VB6: lineHeight As Any + object lineHeight + { + // IDL: HRESULT lineHeight ([out, retval] VARIANT* ReturnValue); + // VB6: Function lineHeight As Any + [DispId(-2147413106)] get; + // IDL: HRESULT lineHeight (VARIANT value); + // VB6: Sub lineHeight (ByVal value As Any) + [DispId(-2147413106)] set; + } + + /// listStyle property of IHTMLStyle interface. + /// An original IDL definition of listStyle property was the following: BSTR listStyle; + // IDL: BSTR listStyle; + // VB6: listStyle As String + string listStyle + { + // IDL: HRESULT listStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function listStyle As String + [DispId(-2147413037)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT listStyle (BSTR value); + // VB6: Sub listStyle (ByVal value As String) + [DispId(-2147413037)] set; + } + + /// listStyleImage property of IHTMLStyle interface. + /// An original IDL definition of listStyleImage property was the following: BSTR listStyleImage; + // IDL: BSTR listStyleImage; + // VB6: listStyleImage As String + string listStyleImage + { + // IDL: HRESULT listStyleImage ([out, retval] BSTR* ReturnValue); + // VB6: Function listStyleImage As String + [DispId(-2147413038)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT listStyleImage (BSTR value); + // VB6: Sub listStyleImage (ByVal value As String) + [DispId(-2147413038)] set; + } + + /// listStylePosition property of IHTMLStyle interface. + /// An original IDL definition of listStylePosition property was the following: BSTR listStylePosition; + // IDL: BSTR listStylePosition; + // VB6: listStylePosition As String + string listStylePosition + { + // IDL: HRESULT listStylePosition ([out, retval] BSTR* ReturnValue); + // VB6: Function listStylePosition As String + [DispId(-2147413039)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT listStylePosition (BSTR value); + // VB6: Sub listStylePosition (ByVal value As String) + [DispId(-2147413039)] set; + } + + /// listStyleType property of IHTMLStyle interface. + /// An original IDL definition of listStyleType property was the following: BSTR listStyleType; + // IDL: BSTR listStyleType; + // VB6: listStyleType As String + string listStyleType + { + // IDL: HRESULT listStyleType ([out, retval] BSTR* ReturnValue); + // VB6: Function listStyleType As String + [DispId(-2147413040)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT listStyleType (BSTR value); + // VB6: Sub listStyleType (ByVal value As String) + [DispId(-2147413040)] set; + } + + /// margin property of IHTMLStyle interface. + /// An original IDL definition of margin property was the following: BSTR margin; + // IDL: BSTR margin; + // VB6: margin As String + string margin + { + // IDL: HRESULT margin ([out, retval] BSTR* ReturnValue); + // VB6: Function margin As String + [DispId(-2147413076)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT margin (BSTR value); + // VB6: Sub margin (ByVal value As String) + [DispId(-2147413076)] set; + } + + /// marginBottom property of IHTMLStyle interface. + /// An original IDL definition of marginBottom property was the following: VARIANT marginBottom; + // IDL: VARIANT marginBottom; + // VB6: marginBottom As Any + object marginBottom + { + // IDL: HRESULT marginBottom ([out, retval] VARIANT* ReturnValue); + // VB6: Function marginBottom As Any + [DispId(-2147413073)] get; + // IDL: HRESULT marginBottom (VARIANT value); + // VB6: Sub marginBottom (ByVal value As Any) + [DispId(-2147413073)] set; + } + + /// marginLeft property of IHTMLStyle interface. + /// An original IDL definition of marginLeft property was the following: VARIANT marginLeft; + // IDL: VARIANT marginLeft; + // VB6: marginLeft As Any + object marginLeft + { + // IDL: HRESULT marginLeft ([out, retval] VARIANT* ReturnValue); + // VB6: Function marginLeft As Any + [DispId(-2147413072)] get; + // IDL: HRESULT marginLeft (VARIANT value); + // VB6: Sub marginLeft (ByVal value As Any) + [DispId(-2147413072)] set; + } + + /// marginRight property of IHTMLStyle interface. + /// An original IDL definition of marginRight property was the following: VARIANT marginRight; + // IDL: VARIANT marginRight; + // VB6: marginRight As Any + object marginRight + { + // IDL: HRESULT marginRight ([out, retval] VARIANT* ReturnValue); + // VB6: Function marginRight As Any + [DispId(-2147413074)] get; + // IDL: HRESULT marginRight (VARIANT value); + // VB6: Sub marginRight (ByVal value As Any) + [DispId(-2147413074)] set; + } + + /// marginTop property of IHTMLStyle interface. + /// An original IDL definition of marginTop property was the following: VARIANT marginTop; + // IDL: VARIANT marginTop; + // VB6: marginTop As Any + object marginTop + { + // IDL: HRESULT marginTop ([out, retval] VARIANT* ReturnValue); + // VB6: Function marginTop As Any + [DispId(-2147413075)] get; + // IDL: HRESULT marginTop (VARIANT value); + // VB6: Sub marginTop (ByVal value As Any) + [DispId(-2147413075)] set; + } + + /// overflow property of IHTMLStyle interface. + /// An original IDL definition of overflow property was the following: BSTR overflow; + // IDL: BSTR overflow; + // VB6: overflow As String + string overflow + { + // IDL: HRESULT overflow ([out, retval] BSTR* ReturnValue); + // VB6: Function overflow As String + [DispId(-2147413102)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT overflow (BSTR value); + // VB6: Sub overflow (ByVal value As String) + [DispId(-2147413102)] set; + } + + /// padding property of IHTMLStyle interface. + /// An original IDL definition of padding property was the following: BSTR padding; + // IDL: BSTR padding; + // VB6: padding As String + string padding + { + // IDL: HRESULT padding ([out, retval] BSTR* ReturnValue); + // VB6: Function padding As String + [DispId(-2147413101)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT padding (BSTR value); + // VB6: Sub padding (ByVal value As String) + [DispId(-2147413101)] set; + } + + /// paddingBottom property of IHTMLStyle interface. + /// An original IDL definition of paddingBottom property was the following: VARIANT paddingBottom; + // IDL: VARIANT paddingBottom; + // VB6: paddingBottom As Any + object paddingBottom + { + // IDL: HRESULT paddingBottom ([out, retval] VARIANT* ReturnValue); + // VB6: Function paddingBottom As Any + [DispId(-2147413098)] get; + // IDL: HRESULT paddingBottom (VARIANT value); + // VB6: Sub paddingBottom (ByVal value As Any) + [DispId(-2147413098)] set; + } + + /// paddingLeft property of IHTMLStyle interface. + /// An original IDL definition of paddingLeft property was the following: VARIANT paddingLeft; + // IDL: VARIANT paddingLeft; + // VB6: paddingLeft As Any + object paddingLeft + { + // IDL: HRESULT paddingLeft ([out, retval] VARIANT* ReturnValue); + // VB6: Function paddingLeft As Any + [DispId(-2147413097)] get; + // IDL: HRESULT paddingLeft (VARIANT value); + // VB6: Sub paddingLeft (ByVal value As Any) + [DispId(-2147413097)] set; + } + + /// paddingRight property of IHTMLStyle interface. + object paddingRight { [DispId(-2147413099)] get; } + + /// paddingTop property of IHTMLStyle interface. + object paddingTop { [DispId(-2147413100)] get; } + + /// pageBreakAfter property of IHTMLStyle interface. + string pageBreakAfter + { + [DispId(-2147413034)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// pageBreakBefore property of IHTMLStyle interface. + string pageBreakBefore + { + [DispId(-2147413035)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// pixelHeight property of IHTMLStyle interface. + int pixelHeight { [DispId(-2147414109)] get; } + + /// pixelLeft property of IHTMLStyle interface. + int pixelLeft { [DispId(-2147414111)] get; } + + /// pixelTop property of IHTMLStyle interface. + int pixelTop { [DispId(-2147414112)] get; } + + /// pixelWidth property of IHTMLStyle interface. + int pixelWidth { [DispId(-2147414110)] get; } + + /// posHeight property of IHTMLStyle interface. + float posHeight { [DispId(-2147414105)] get; } + + /// position property of IHTMLStyle interface. + string position + { + [DispId(-2147413022)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// posLeft property of IHTMLStyle interface. + float posLeft { [DispId(-2147414107)] get; } + + /// posTop property of IHTMLStyle interface. + float posTop { [DispId(-2147414108)] get; } + + /// posWidth property of IHTMLStyle interface. + float posWidth { [DispId(-2147414106)] get; } + + /// styleFloat property of IHTMLStyle interface. + string styleFloat + { + [DispId(-2147413042)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// textAlign property of IHTMLStyle interface. + string textAlign + { + [DispId(-2147418040)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// textDecoration property of IHTMLStyle interface. + string textDecoration + { + [DispId(-2147413077)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// textDecorationBlink property of IHTMLStyle interface. + bool textDecorationBlink + { + [DispId(-2147413090)] + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + /// textDecorationLineThrough property of IHTMLStyle interface. + bool textDecorationLineThrough + { + [DispId(-2147413092)] + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + /// textDecorationNone property of IHTMLStyle interface. + bool textDecorationNone + { + [DispId(-2147413089)] + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + /// textDecorationOverline property of IHTMLStyle interface. + bool textDecorationOverline + { + [DispId(-2147413043)] + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + /// textDecorationUnderline property of IHTMLStyle interface. + bool textDecorationUnderline + { + [DispId(-2147413091)] + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + /// textIndent property of IHTMLStyle interface. + object textIndent { [DispId(-2147413105)] get; } + + /// textTransform property of IHTMLStyle interface. + string textTransform + { + [DispId(-2147413108)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// top property of IHTMLStyle interface. + object top { [DispId(-2147418108)] get; } + + /// verticalAlign property of IHTMLStyle interface. + object verticalAlign { [DispId(-2147413064)] get; } + + /// visibility property of IHTMLStyle interface. + string visibility + { + [DispId(-2147413032)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// whiteSpace property of IHTMLStyle interface. + string whiteSpace + { + [DispId(-2147413036)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// width property of IHTMLStyle interface. + object width { [DispId(-2147418107)] get; } + + /// wordSpacing property of IHTMLStyle interface. + object wordSpacing { [DispId(-2147413065)] get; } + + /// zIndex property of IHTMLStyle interface. + object zIndex { [DispId(-2147413021)] get; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs b/src/Greenshot.Base/IEInterop/IHTMLTxtRange.cs similarity index 96% rename from src/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs rename to src/Greenshot.Base/IEInterop/IHTMLTxtRange.cs index 2a2cf3986..8f77258f1 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLTxtRange.cs @@ -1,141 +1,141 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - // See: http://msdn.microsoft.com/en-us/library/aa741548%28v=vs.85%29.aspx - [ComImport, Guid("3050F220-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLTxtRange - { - [DispId(1006)] - IHTMLElement parentElement(); - - [DispId(1008)] - IHTMLTxtRange duplicate(); - - [DispId(1010)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool inRange(IHTMLTxtRange range); - - [DispId(1011)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool isEqual(IHTMLTxtRange range); - - [DispId(1012)] - void scrollIntoView([MarshalAs(UnmanagedType.VariantBool)] bool fStart); - - [DispId(1013)] - void collapse([MarshalAs(UnmanagedType.VariantBool)] bool Start); - - [DispId(1014)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool expand([MarshalAs(UnmanagedType.BStr)] string Unit); - - [DispId(1015)] - int move([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); - - [DispId(1016)] - int moveStart([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); - - [DispId(1017)] - int moveEnd([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); - - [DispId(1024)] - void select(); - - [DispId(1026)] - void pasteHTML([MarshalAs(UnmanagedType.BStr)] string html); - - [DispId(1001)] - void moveToElementText(IHTMLElement element); - - [DispId(1025)] - void setEndPoint([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); - - [DispId(1018)] - int compareEndPoints([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); - - [DispId(1019)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool findText([MarshalAs(UnmanagedType.BStr)] string String, int Count, int Flags); - - [DispId(1020)] - void moveToPoint(int x, int y); - - [DispId(1021)] - [return: MarshalAs(UnmanagedType.BStr)] - string getBookmark(); - - [DispId(1009)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool moveToBookmark([MarshalAs(UnmanagedType.BStr)] string Bookmark); - - [DispId(1027)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandSupported([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1028)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandEnabled([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1029)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandState([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1030)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandIndeterm([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1031)] - [return: MarshalAs(UnmanagedType.BStr)] - string queryCommandText([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1032)] - object queryCommandValue([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1033)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool execCommand([MarshalAs(UnmanagedType.BStr)] string cmdID, [MarshalAs(UnmanagedType.VariantBool)] bool showUI, object value); - - [DispId(1034)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool execCommandShowHelp([MarshalAs(UnmanagedType.BStr)] string cmdID); - - string htmlText - { - [DispId(1003)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string text - { - [DispId(1004)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - [DispId(1004)] set; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + // See: http://msdn.microsoft.com/en-us/library/aa741548%28v=vs.85%29.aspx + [ComImport, Guid("3050F220-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLTxtRange + { + [DispId(1006)] + IHTMLElement parentElement(); + + [DispId(1008)] + IHTMLTxtRange duplicate(); + + [DispId(1010)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool inRange(IHTMLTxtRange range); + + [DispId(1011)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool isEqual(IHTMLTxtRange range); + + [DispId(1012)] + void scrollIntoView([MarshalAs(UnmanagedType.VariantBool)] bool fStart); + + [DispId(1013)] + void collapse([MarshalAs(UnmanagedType.VariantBool)] bool Start); + + [DispId(1014)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool expand([MarshalAs(UnmanagedType.BStr)] string Unit); + + [DispId(1015)] + int move([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); + + [DispId(1016)] + int moveStart([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); + + [DispId(1017)] + int moveEnd([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); + + [DispId(1024)] + void select(); + + [DispId(1026)] + void pasteHTML([MarshalAs(UnmanagedType.BStr)] string html); + + [DispId(1001)] + void moveToElementText(IHTMLElement element); + + [DispId(1025)] + void setEndPoint([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); + + [DispId(1018)] + int compareEndPoints([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); + + [DispId(1019)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool findText([MarshalAs(UnmanagedType.BStr)] string String, int Count, int Flags); + + [DispId(1020)] + void moveToPoint(int x, int y); + + [DispId(1021)] + [return: MarshalAs(UnmanagedType.BStr)] + string getBookmark(); + + [DispId(1009)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool moveToBookmark([MarshalAs(UnmanagedType.BStr)] string Bookmark); + + [DispId(1027)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandSupported([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1028)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandEnabled([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1029)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandState([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1030)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandIndeterm([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1031)] + [return: MarshalAs(UnmanagedType.BStr)] + string queryCommandText([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1032)] + object queryCommandValue([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1033)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool execCommand([MarshalAs(UnmanagedType.BStr)] string cmdID, [MarshalAs(UnmanagedType.VariantBool)] bool showUI, object value); + + [DispId(1034)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool execCommandShowHelp([MarshalAs(UnmanagedType.BStr)] string cmdID); + + string htmlText + { + [DispId(1003)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string text + { + [DispId(1004)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + [DispId(1004)] set; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLWindow2.cs b/src/Greenshot.Base/IEInterop/IHTMLWindow2.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLWindow2.cs rename to src/Greenshot.Base/IEInterop/IHTMLWindow2.cs index 316aa821c..c37956cf0 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLWindow2.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLWindow2.cs @@ -1,52 +1,52 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComVisible(true), ComImport(), Guid("332c4427-26cb-11d0-b483-00c04fd90119"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLWindow2 - { - [DispId(1156)] - IHTMLScreen screen - { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(1151)] - IHTMLDocument2 document - { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(11)] - string name - { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComVisible(true), ComImport(), Guid("332c4427-26cb-11d0-b483-00c04fd90119"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLWindow2 + { + [DispId(1156)] + IHTMLScreen screen + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(1151)] + IHTMLDocument2 document + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(11)] + string name + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLWindow3.cs b/src/Greenshot.Base/IEInterop/IHTMLWindow3.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLWindow3.cs rename to src/Greenshot.Base/IEInterop/IHTMLWindow3.cs index 47089f067..2e8e4f095 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLWindow3.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLWindow3.cs @@ -1,35 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComVisible(true), ComImport(), Guid("3050f4ae-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLWindow3 - { - [DispId(1170)] int screenLeft { get; } - - [DispId(1171)] int screenTop { get; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComVisible(true), ComImport(), Guid("3050f4ae-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLWindow3 + { + [DispId(1170)] int screenLeft { get; } + + [DispId(1171)] int screenTop { get; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IHTMLWindow4.cs b/src/Greenshot.Base/IEInterop/IHTMLWindow4.cs similarity index 94% rename from src/GreenshotPlugin/IEInterop/IHTMLWindow4.cs rename to src/Greenshot.Base/IEInterop/IHTMLWindow4.cs index 1409852fb..c97982afc 100644 --- a/src/GreenshotPlugin/IEInterop/IHTMLWindow4.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLWindow4.cs @@ -1,38 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - [ComVisible(true), ComImport(), Guid("3050f6cf-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLWindow4 - { - [DispId(1181)] - IHTMLFrameBase frameElement - { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComVisible(true), ComImport(), Guid("3050f6cf-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLWindow4 + { + [DispId(1181)] + IHTMLFrameBase frameElement + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IEInterop/IWebBrowser2.cs b/src/Greenshot.Base/IEInterop/IWebBrowser2.cs similarity index 96% rename from src/GreenshotPlugin/IEInterop/IWebBrowser2.cs rename to src/Greenshot.Base/IEInterop/IWebBrowser2.cs index 5a4a4c5d5..3a500338a 100644 --- a/src/GreenshotPlugin/IEInterop/IWebBrowser2.cs +++ b/src/Greenshot.Base/IEInterop/IWebBrowser2.cs @@ -1,152 +1,152 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop -{ - // IWebBrowser: EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B -// [ComVisible(true), ComImport(), Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"), -// TypeLibType(TypeLibTypeFlags.FDual), -// InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] -// public interface IWebBrowser2 { -// [DispId(203)] -// object Document { -// [return: MarshalAs(UnmanagedType.IDispatch)] -// get; -// } -// } - [ComImport, /*SuppressUnmanagedCodeSecurity,*/ - TypeLibType(TypeLibTypeFlags.FOleAutomation | - TypeLibTypeFlags.FDual | - TypeLibTypeFlags.FHidden), - Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")] - public interface IWebBrowser2 - { - [DispId(100)] - void GoBack(); - - [DispId(0x65)] - void GoForward(); - - [DispId(0x66)] - void GoHome(); - - [DispId(0x67)] - void GoSearch(); - - [DispId(0x68)] - void Navigate([In] string Url, - [In] ref object flags, - [In] ref object targetFrameName, - [In] ref object postData, - [In] ref object headers); - - [DispId(-550)] - void Refresh(); - - [DispId(0x69)] - void Refresh2([In] ref object level); - - [DispId(0x6a)] - void Stop(); - - [DispId(200)] - object Application - { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(0xc9)] - object Parent - { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(0xca)] - object Container - { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(0xcb)] - object Document - { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(0xcc)] bool TopLevelContainer { get; } - [DispId(0xcd)] string Type { get; } - [DispId(0xce)] int Left { get; set; } - [DispId(0xcf)] int Top { get; set; } - [DispId(0xd0)] int Width { get; set; } - [DispId(0xd1)] int Height { get; set; } - [DispId(210)] string LocationName { get; } - [DispId(0xd3)] string LocationURL { get; } - [DispId(0xd4)] bool Busy { get; } - - [DispId(300)] - void Quit(); - - [DispId(0x12d)] - void ClientToWindow(out int pcx, out int pcy); - - [DispId(0x12e)] - void PutProperty([In] string property, [In] object vtValue); - - [DispId(0x12f)] - object GetProperty([In] string property); - - [DispId(0)] string Name { get; } - [DispId(-515)] int HWND { get; } - [DispId(400)] string FullName { get; } - [DispId(0x191)] string Path { get; } - [DispId(0x192)] bool Visible { get; set; } - [DispId(0x193)] bool StatusBar { get; set; } - [DispId(0x194)] string StatusText { get; set; } - [DispId(0x195)] int ToolBar { get; set; } - [DispId(0x196)] bool MenuBar { get; set; } - [DispId(0x197)] bool FullScreen { get; set; } - - [DispId(500)] - void Navigate2([In] ref object URL, - [In] ref object flags, - [In] ref object targetFrameName, - [In] ref object postData, - [In] ref object headers); - - [DispId(550)] bool Offline { get; set; } - [DispId(0x227)] bool Silent { get; set; } - [DispId(0x228)] bool RegisterAsBrowser { get; set; } - [DispId(0x229)] bool RegisterAsDropTarget { get; set; } - [DispId(0x22a)] bool TheaterMode { get; set; } - [DispId(0x22b)] bool AddressBar { get; set; } - [DispId(0x22c)] bool Resizable { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + // IWebBrowser: EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B +// [ComVisible(true), ComImport(), Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"), +// TypeLibType(TypeLibTypeFlags.FDual), +// InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] +// public interface IWebBrowser2 { +// [DispId(203)] +// object Document { +// [return: MarshalAs(UnmanagedType.IDispatch)] +// get; +// } +// } + [ComImport, /*SuppressUnmanagedCodeSecurity,*/ + TypeLibType(TypeLibTypeFlags.FOleAutomation | + TypeLibTypeFlags.FDual | + TypeLibTypeFlags.FHidden), + Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")] + public interface IWebBrowser2 + { + [DispId(100)] + void GoBack(); + + [DispId(0x65)] + void GoForward(); + + [DispId(0x66)] + void GoHome(); + + [DispId(0x67)] + void GoSearch(); + + [DispId(0x68)] + void Navigate([In] string Url, + [In] ref object flags, + [In] ref object targetFrameName, + [In] ref object postData, + [In] ref object headers); + + [DispId(-550)] + void Refresh(); + + [DispId(0x69)] + void Refresh2([In] ref object level); + + [DispId(0x6a)] + void Stop(); + + [DispId(200)] + object Application + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xc9)] + object Parent + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xca)] + object Container + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xcb)] + object Document + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xcc)] bool TopLevelContainer { get; } + [DispId(0xcd)] string Type { get; } + [DispId(0xce)] int Left { get; set; } + [DispId(0xcf)] int Top { get; set; } + [DispId(0xd0)] int Width { get; set; } + [DispId(0xd1)] int Height { get; set; } + [DispId(210)] string LocationName { get; } + [DispId(0xd3)] string LocationURL { get; } + [DispId(0xd4)] bool Busy { get; } + + [DispId(300)] + void Quit(); + + [DispId(0x12d)] + void ClientToWindow(out int pcx, out int pcy); + + [DispId(0x12e)] + void PutProperty([In] string property, [In] object vtValue); + + [DispId(0x12f)] + object GetProperty([In] string property); + + [DispId(0)] string Name { get; } + [DispId(-515)] int HWND { get; } + [DispId(400)] string FullName { get; } + [DispId(0x191)] string Path { get; } + [DispId(0x192)] bool Visible { get; set; } + [DispId(0x193)] bool StatusBar { get; set; } + [DispId(0x194)] string StatusText { get; set; } + [DispId(0x195)] int ToolBar { get; set; } + [DispId(0x196)] bool MenuBar { get; set; } + [DispId(0x197)] bool FullScreen { get; set; } + + [DispId(500)] + void Navigate2([In] ref object URL, + [In] ref object flags, + [In] ref object targetFrameName, + [In] ref object postData, + [In] ref object headers); + + [DispId(550)] bool Offline { get; set; } + [DispId(0x227)] bool Silent { get; set; } + [DispId(0x228)] bool RegisterAsBrowser { get; set; } + [DispId(0x229)] bool RegisterAsDropTarget { get; set; } + [DispId(0x22a)] bool TheaterMode { get; set; } + [DispId(0x22b)] bool AddressBar { get; set; } + [DispId(0x22c)] bool Resizable { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IniFile/IniAttributes.cs b/src/Greenshot.Base/IniFile/IniAttributes.cs similarity index 95% rename from src/GreenshotPlugin/IniFile/IniAttributes.cs rename to src/Greenshot.Base/IniFile/IniAttributes.cs index 6f41b98b5..4563a406b 100644 --- a/src/GreenshotPlugin/IniFile/IniAttributes.cs +++ b/src/Greenshot.Base/IniFile/IniAttributes.cs @@ -1,71 +1,71 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.IniFile -{ - /// - /// Attribute for telling that this class is linked to a section in the ini-configuration - /// - [AttributeUsage(AttributeTargets.Class)] - public class IniSectionAttribute : Attribute - { - public IniSectionAttribute(string name) - { - Name = name; - } - - public string Description; - public string Name { get; set; } - } - - /// - /// Attribute for telling that a field is linked to a property in the ini-configuration selection - /// - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public class IniPropertyAttribute : Attribute - { - public IniPropertyAttribute() - { - Separator = ","; - } - - public IniPropertyAttribute(string name) : this() - { - Name = name; - } - - public string Description { get; set; } - public string Separator { get; set; } - public string DefaultValue { get; set; } - - public string LanguageKey { get; set; } - - // If Encrypted is set to true, the value will be decrypted on load and encrypted on save - public bool Encrypted { get; set; } - public bool FixedValue { get; set; } - public bool Expert { get; set; } - public bool ExcludeIfNull { get; set; } - - public string Name { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.IniFile +{ + /// + /// Attribute for telling that this class is linked to a section in the ini-configuration + /// + [AttributeUsage(AttributeTargets.Class)] + public class IniSectionAttribute : Attribute + { + public IniSectionAttribute(string name) + { + Name = name; + } + + public string Description; + public string Name { get; set; } + } + + /// + /// Attribute for telling that a field is linked to a property in the ini-configuration selection + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class IniPropertyAttribute : Attribute + { + public IniPropertyAttribute() + { + Separator = ","; + } + + public IniPropertyAttribute(string name) : this() + { + Name = name; + } + + public string Description { get; set; } + public string Separator { get; set; } + public string DefaultValue { get; set; } + + public string LanguageKey { get; set; } + + // If Encrypted is set to true, the value will be decrypted on load and encrypted on save + public bool Encrypted { get; set; } + public bool FixedValue { get; set; } + public bool Expert { get; set; } + public bool ExcludeIfNull { get; set; } + + public string Name { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IniFile/IniConfig.cs b/src/Greenshot.Base/IniFile/IniConfig.cs similarity index 97% rename from src/GreenshotPlugin/IniFile/IniConfig.cs rename to src/Greenshot.Base/IniFile/IniConfig.cs index 691bd6eb2..57bc8f55e 100644 --- a/src/GreenshotPlugin/IniFile/IniConfig.cs +++ b/src/Greenshot.Base/IniFile/IniConfig.cs @@ -1,574 +1,574 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Text; -using System.Threading; -using log4net; - -namespace GreenshotPlugin.IniFile -{ - public class IniConfig - { - private static readonly ILog Log = LogManager.GetLogger(typeof(IniConfig)); - private const string IniExtension = ".ini"; - private const string DefaultsPostfix = "-defaults"; - private const string FixedPostfix = "-fixed"; - - /// - /// A lock object for the ini file saving - /// - private static readonly object IniLock = new object(); - - /// - /// As the ini implementation is kept someone generic, for reusing, this holds the name of the application - /// - private static string _applicationName; - - /// - /// As the ini implementation is kept someone generic, for reusing, this holds the name of the configuration - /// - private static string _configName; - - /// - /// A Dictionary with all the sections stored by section name - /// - private static readonly IDictionary SectionMap = new Dictionary(); - - /// - /// A Dictionary with the properties for a section stored by section name - /// - private static IDictionary> _sections = new Dictionary>(); - - /// - /// A Dictionary with the fixed-properties for a section stored by section name - /// - private static IDictionary> _fixedProperties; - - /// - /// Stores if we checked for portable - /// - private static bool _portableCheckMade; - - /// - /// Is the configuration portable (meaning we don't store it in the AppData directory) - /// - public static bool IsPortable { get; private set; } - - /// - /// Config directory when set from external - /// - public static string IniDirectory { get; set; } - - /// - /// Initialize the ini config - /// - /// - /// - public static void Init(string appName, string configName) - { - _applicationName = appName; - _configName = configName; - Reload(); - } - - /// - /// Checks if we initialized the ini - /// - public static bool IsInitialized => _applicationName != null && _configName != null && SectionMap.Count > 0; - - /// - /// This forces the ini to be stored in the startup path, used for portable applications - /// - public static void ForceIniInStartupPath() - { - if (_portableCheckMade) - { - throw new Exception("ForceLocal should be called before any file is read"); - } - - IsPortable = false; - _portableCheckMade = true; - string applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - if (_applicationName == null || _configName == null) - { - Init(); - } - - if (applicationStartupPath == null) - { - return; - } - - string forcedIni = Path.Combine(applicationStartupPath, _applicationName + IniExtension); - if (!File.Exists(forcedIni)) - { - using (File.Create(forcedIni)) - { - } - } - } - - /// - /// Default init - /// - public static void Init() - { - AssemblyProductAttribute[] assemblyProductAttributes = - Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false) as AssemblyProductAttribute[]; - if (assemblyProductAttributes != null && assemblyProductAttributes.Length > 0) - { - string productName = assemblyProductAttributes[0].Product; - Log.InfoFormat("Using ProductName {0}", productName); - Init(productName, productName); - } - else - { - throw new InvalidOperationException("Assembly ProductName not set."); - } - } - - /// - /// Get the location of the configuration - /// - public static string ConfigLocation - { - get - { - if (IsInitialized) - { - return CreateIniLocation(_configName + IniExtension, false); - } - - throw new InvalidOperationException("Ini configuration was not initialized!"); - } - } - - /// - /// Create the location of the configuration file - /// - private static string CreateIniLocation(string configFilename, bool isReadOnly) - { - if (_applicationName == null || _configName == null) - { - throw new InvalidOperationException("IniConfig.Init not called!"); - } - - string iniFilePath = null; - - // Check if a Ini-Directory was supplied, and it's valid, use this before any others. - try - { - if (IniDirectory != null && Directory.Exists(IniDirectory)) - { - // If the greenshot.ini is requested, use the supplied directory even if empty - if (!isReadOnly) - { - return Path.Combine(IniDirectory, configFilename); - } - - iniFilePath = Path.Combine(IniDirectory, configFilename); - if (File.Exists(iniFilePath)) - { - return iniFilePath; - } - - iniFilePath = null; - } - } - catch (Exception exception) - { - Log.WarnFormat("The ini-directory {0} can't be used due to: {1}", IniDirectory, exception.Message); - } - - string applicationStartupPath; - try - { - applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - } - catch (Exception exception) - { - Log.WarnFormat("Problem retrieving the AssemblyLocation: {0} (Designer mode?)", exception.Message); - applicationStartupPath = @"."; - } - - if (applicationStartupPath != null) - { - string pafPath = Path.Combine(applicationStartupPath, @"App\" + _applicationName); - - if (IsPortable || !_portableCheckMade) - { - if (!IsPortable) - { - Log.Info("Checking for portable mode."); - _portableCheckMade = true; - if (Directory.Exists(pafPath)) - { - IsPortable = true; - Log.Info("Portable mode active!"); - } - } - - if (IsPortable) - { - string pafConfigPath = Path.Combine(applicationStartupPath, @"Data\Settings"); - try - { - if (!Directory.Exists(pafConfigPath)) - { - Directory.CreateDirectory(pafConfigPath); - } - - iniFilePath = Path.Combine(pafConfigPath, configFilename); - } - catch (Exception e) - { - Log.InfoFormat("Portable mode NOT possible, couldn't create directory '{0}'! Reason: {1}", pafConfigPath, e.Message); - } - } - } - } - - if (iniFilePath == null) - { - // check if file is in the same location as started from, if this is the case - // we will use this file instead of the ApplicationData folder - // Done for Feature Request #2741508 - if (applicationStartupPath != null) - { - iniFilePath = Path.Combine(applicationStartupPath, configFilename); - } - - if (!File.Exists(iniFilePath)) - { - string iniDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), _applicationName); - if (!Directory.Exists(iniDirectory)) - { - Directory.CreateDirectory(iniDirectory); - } - - iniFilePath = Path.Combine(iniDirectory, configFilename); - } - } - - Log.InfoFormat("Using ini file {0}", iniFilePath); - return iniFilePath; - } - - /// - /// Reload the Ini file - /// - public static void Reload() - { - // Clear the current properties - _sections = new Dictionary>(); - // Load the defaults - Read(CreateIniLocation(_configName + DefaultsPostfix + IniExtension, true)); - // Load the normal - Read(CreateIniLocation(_configName + IniExtension, false)); - // Load the fixed settings - _fixedProperties = Read(CreateIniLocation(_configName + FixedPostfix + IniExtension, true)); - - foreach (IniSection section in SectionMap.Values) - { - try - { - section.Fill(PropertiesForSection(section)); - FixProperties(section); - } - catch (Exception ex) - { - string sectionName = "unknown"; - if (section?.IniSectionAttribute?.Name != null) - { - sectionName = section.IniSectionAttribute.Name; - } - - Log.WarnFormat("Problem reading the ini section {0}", sectionName); - Log.Warn("Exception", ex); - } - } - } - - /// - /// This "fixes" the properties of the section, meaning any properties in the fixed file can't be changed. - /// - /// IniSection - private static void FixProperties(IniSection section) - { - // Make properties unchangeable - if (_fixedProperties == null) - { - return; - } - - if (!_fixedProperties.TryGetValue(section.IniSectionAttribute.Name, out var fixedPropertiesForSection)) - { - return; - } - - foreach (string fixedPropertyKey in fixedPropertiesForSection.Keys) - { - if (section.Values.ContainsKey(fixedPropertyKey)) - { - section.Values[fixedPropertyKey].IsFixed = true; - } - } - } - - /// - /// Read the ini file into the Dictionary - /// - /// Path & Filename of ini file - private static IDictionary> Read(string iniLocation) - { - if (!File.Exists(iniLocation)) - { - Log.Info("Can't find file: " + iniLocation); - return null; - } - - Log.InfoFormat("Loading ini-file: {0}", iniLocation); - //LOG.Info("Reading ini-properties from file: " + iniLocation); - var newSections = IniReader.Read(iniLocation, Encoding.UTF8); - // Merge the newly loaded properties to the already available - foreach (string section in newSections.Keys) - { - IDictionary newProperties = newSections[section]; - if (!_sections.ContainsKey(section)) - { - // This section is not yet loaded, simply add the complete section - _sections.Add(section, newProperties); - } - else - { - // Overwrite or add every property from the newly loaded section to the available one - var currentProperties = _sections[section]; - foreach (string propertyName in newProperties.Keys) - { - string propertyValue = newProperties[propertyName]; - if (currentProperties.ContainsKey(propertyName)) - { - // Override current value as we are loading in a certain order which insures the default, current and fixed - currentProperties[propertyName] = propertyValue; - } - else - { - // Add "new" value - currentProperties.Add(propertyName, propertyValue); - } - } - } - } - - return newSections; - } - - public static IEnumerable IniSectionNames - { - get - { - foreach (string sectionName in SectionMap.Keys) - { - yield return sectionName; - } - } - } - - /// - /// Method used for internal tricks... - /// - /// - /// - public static IniSection GetIniSection(string sectionName) - { - SectionMap.TryGetValue(sectionName, out var returnValue); - return returnValue; - } - - /// - /// A generic method which returns an instance of the supplied type, filled with it's configuration - /// - /// IniSection Type to get the configuration for - /// Filled instance of IniSection type which was supplied - public static T GetIniSection() where T : IniSection - { - return GetIniSection(true); - } - - /// - /// - /// - /// IniSection Type to get the configuration for - /// false to skip saving - /// IniSection - public static T GetIniSection(bool allowSave) where T : IniSection - { - T section; - - Type iniSectionType = typeof(T); - string sectionName = IniSection.GetIniSectionAttribute(iniSectionType).Name; - if (SectionMap.ContainsKey(sectionName)) - { - //LOG.Debug("Returning pre-mapped section " + sectionName); - section = (T) SectionMap[sectionName]; - } - else - { - // Create instance of this type - section = (T) Activator.CreateInstance(iniSectionType); - - // Store for later save & retrieval - SectionMap.Add(sectionName, section); - section.Fill(PropertiesForSection(section)); - FixProperties(section); - } - - if (allowSave && section.IsDirty) - { - Log.DebugFormat("Section {0} is marked dirty, saving!", sectionName); - Save(); - } - - return section; - } - - /// - /// Get the raw properties for a section - /// - /// - /// - public static IDictionary PropertiesForSection(IniSection section) - { - string sectionName = section.IniSectionAttribute.Name; - // Get the properties for the section - IDictionary properties; - if (_sections.ContainsKey(sectionName)) - { - properties = _sections[sectionName]; - } - else - { - _sections.Add(sectionName, new Dictionary()); - properties = _sections[sectionName]; - } - - return properties; - } - - /// - /// Save the ini file - /// - public static void Save() - { - bool acquiredLock = false; - try - { - acquiredLock = Monitor.TryEnter(IniLock, TimeSpan.FromMilliseconds(200)); - if (acquiredLock) - { - // Code that accesses resources that are protected by the lock. - string iniLocation = CreateIniLocation(_configName + IniExtension, false); - try - { - SaveInternally(iniLocation); - } - catch (Exception ex) - { - Log.Error("A problem occured while writing the configuration file to: " + iniLocation); - Log.Error(ex); - } - } - else - { - // Code to deal with the fact that the lock was not acquired. - Log.Warn("A second thread tried to save the ini-file, we blocked as the first took too long."); - } - } - finally - { - if (acquiredLock) - { - Monitor.Exit(IniLock); - } - } - } - - /// - /// The real save implementation - /// - /// - private static void SaveInternally(string iniLocation) - { - Log.Info("Saving configuration to: " + iniLocation); - var iniPath = Path.GetDirectoryName(iniLocation); - if (iniPath != null && !Directory.Exists(iniPath)) - { - Directory.CreateDirectory(iniPath); - } - - using var memoryStream = new MemoryStream(); - using TextWriter writer = new StreamWriter(memoryStream, Encoding.UTF8); - foreach (var section in SectionMap.Values) - { - section.Write(writer, false); - // Add empty line after section - writer.WriteLine(); - section.IsDirty = false; - } - - writer.WriteLine(); - // Write left over properties - foreach (string sectionName in _sections.Keys) - { - // Check if the section is one that is "registered", if so skip it! - if (SectionMap.ContainsKey(sectionName)) - { - continue; - } - - writer.WriteLine("; The section {0} hasn't been 'claimed' since the last start of Greenshot, therefor it doesn't have additional information here!", sectionName); - writer.WriteLine( - "; The reason could be that the section {0} just hasn't been used, a plugin has an error and can't claim it or maybe the whole section {0} is obsolete.", - sectionName); - // Write section name - writer.WriteLine("[{0}]", sectionName); - var properties = _sections[sectionName]; - // Loop and write properties - foreach (string propertyName in properties.Keys) - { - writer.WriteLine("{0}={1}", propertyName, properties[propertyName]); - } - - writer.WriteLine(); - } - - // Don't forget to flush the buffer - writer.Flush(); - // Now write the created .ini string to the real file - using FileStream fileStream = new FileStream(iniLocation, FileMode.Create, FileAccess.Write); - memoryStream.WriteTo(fileStream); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using System.Threading; +using log4net; + +namespace Greenshot.Base.IniFile +{ + public class IniConfig + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IniConfig)); + private const string IniExtension = ".ini"; + private const string DefaultsPostfix = "-defaults"; + private const string FixedPostfix = "-fixed"; + + /// + /// A lock object for the ini file saving + /// + private static readonly object IniLock = new object(); + + /// + /// As the ini implementation is kept someone generic, for reusing, this holds the name of the application + /// + private static string _applicationName; + + /// + /// As the ini implementation is kept someone generic, for reusing, this holds the name of the configuration + /// + private static string _configName; + + /// + /// A Dictionary with all the sections stored by section name + /// + private static readonly IDictionary SectionMap = new Dictionary(); + + /// + /// A Dictionary with the properties for a section stored by section name + /// + private static IDictionary> _sections = new Dictionary>(); + + /// + /// A Dictionary with the fixed-properties for a section stored by section name + /// + private static IDictionary> _fixedProperties; + + /// + /// Stores if we checked for portable + /// + private static bool _portableCheckMade; + + /// + /// Is the configuration portable (meaning we don't store it in the AppData directory) + /// + public static bool IsPortable { get; private set; } + + /// + /// Config directory when set from external + /// + public static string IniDirectory { get; set; } + + /// + /// Initialize the ini config + /// + /// + /// + public static void Init(string appName, string configName) + { + _applicationName = appName; + _configName = configName; + Reload(); + } + + /// + /// Checks if we initialized the ini + /// + public static bool IsInitialized => _applicationName != null && _configName != null && SectionMap.Count > 0; + + /// + /// This forces the ini to be stored in the startup path, used for portable applications + /// + public static void ForceIniInStartupPath() + { + if (_portableCheckMade) + { + throw new Exception("ForceLocal should be called before any file is read"); + } + + IsPortable = false; + _portableCheckMade = true; + string applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + if (_applicationName == null || _configName == null) + { + Init(); + } + + if (applicationStartupPath == null) + { + return; + } + + string forcedIni = Path.Combine(applicationStartupPath, _applicationName + IniExtension); + if (!File.Exists(forcedIni)) + { + using (File.Create(forcedIni)) + { + } + } + } + + /// + /// Default init + /// + public static void Init() + { + AssemblyProductAttribute[] assemblyProductAttributes = + Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false) as AssemblyProductAttribute[]; + if (assemblyProductAttributes != null && assemblyProductAttributes.Length > 0) + { + string productName = assemblyProductAttributes[0].Product; + Log.InfoFormat("Using ProductName {0}", productName); + Init(productName, productName); + } + else + { + throw new InvalidOperationException("Assembly ProductName not set."); + } + } + + /// + /// Get the location of the configuration + /// + public static string ConfigLocation + { + get + { + if (IsInitialized) + { + return CreateIniLocation(_configName + IniExtension, false); + } + + throw new InvalidOperationException("Ini configuration was not initialized!"); + } + } + + /// + /// Create the location of the configuration file + /// + private static string CreateIniLocation(string configFilename, bool isReadOnly) + { + if (_applicationName == null || _configName == null) + { + throw new InvalidOperationException("IniConfig.Init not called!"); + } + + string iniFilePath = null; + + // Check if a Ini-Directory was supplied, and it's valid, use this before any others. + try + { + if (IniDirectory != null && Directory.Exists(IniDirectory)) + { + // If the greenshot.ini is requested, use the supplied directory even if empty + if (!isReadOnly) + { + return Path.Combine(IniDirectory, configFilename); + } + + iniFilePath = Path.Combine(IniDirectory, configFilename); + if (File.Exists(iniFilePath)) + { + return iniFilePath; + } + + iniFilePath = null; + } + } + catch (Exception exception) + { + Log.WarnFormat("The ini-directory {0} can't be used due to: {1}", IniDirectory, exception.Message); + } + + string applicationStartupPath; + try + { + applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + } + catch (Exception exception) + { + Log.WarnFormat("Problem retrieving the AssemblyLocation: {0} (Designer mode?)", exception.Message); + applicationStartupPath = @"."; + } + + if (applicationStartupPath != null) + { + string pafPath = Path.Combine(applicationStartupPath, @"App\" + _applicationName); + + if (IsPortable || !_portableCheckMade) + { + if (!IsPortable) + { + Log.Info("Checking for portable mode."); + _portableCheckMade = true; + if (Directory.Exists(pafPath)) + { + IsPortable = true; + Log.Info("Portable mode active!"); + } + } + + if (IsPortable) + { + string pafConfigPath = Path.Combine(applicationStartupPath, @"Data\Settings"); + try + { + if (!Directory.Exists(pafConfigPath)) + { + Directory.CreateDirectory(pafConfigPath); + } + + iniFilePath = Path.Combine(pafConfigPath, configFilename); + } + catch (Exception e) + { + Log.InfoFormat("Portable mode NOT possible, couldn't create directory '{0}'! Reason: {1}", pafConfigPath, e.Message); + } + } + } + } + + if (iniFilePath == null) + { + // check if file is in the same location as started from, if this is the case + // we will use this file instead of the ApplicationData folder + // Done for Feature Request #2741508 + if (applicationStartupPath != null) + { + iniFilePath = Path.Combine(applicationStartupPath, configFilename); + } + + if (!File.Exists(iniFilePath)) + { + string iniDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), _applicationName); + if (!Directory.Exists(iniDirectory)) + { + Directory.CreateDirectory(iniDirectory); + } + + iniFilePath = Path.Combine(iniDirectory, configFilename); + } + } + + Log.InfoFormat("Using ini file {0}", iniFilePath); + return iniFilePath; + } + + /// + /// Reload the Ini file + /// + public static void Reload() + { + // Clear the current properties + _sections = new Dictionary>(); + // Load the defaults + Read(CreateIniLocation(_configName + DefaultsPostfix + IniExtension, true)); + // Load the normal + Read(CreateIniLocation(_configName + IniExtension, false)); + // Load the fixed settings + _fixedProperties = Read(CreateIniLocation(_configName + FixedPostfix + IniExtension, true)); + + foreach (IniSection section in SectionMap.Values) + { + try + { + section.Fill(PropertiesForSection(section)); + FixProperties(section); + } + catch (Exception ex) + { + string sectionName = "unknown"; + if (section?.IniSectionAttribute?.Name != null) + { + sectionName = section.IniSectionAttribute.Name; + } + + Log.WarnFormat("Problem reading the ini section {0}", sectionName); + Log.Warn("Exception", ex); + } + } + } + + /// + /// This "fixes" the properties of the section, meaning any properties in the fixed file can't be changed. + /// + /// IniSection + private static void FixProperties(IniSection section) + { + // Make properties unchangeable + if (_fixedProperties == null) + { + return; + } + + if (!_fixedProperties.TryGetValue(section.IniSectionAttribute.Name, out var fixedPropertiesForSection)) + { + return; + } + + foreach (string fixedPropertyKey in fixedPropertiesForSection.Keys) + { + if (section.Values.ContainsKey(fixedPropertyKey)) + { + section.Values[fixedPropertyKey].IsFixed = true; + } + } + } + + /// + /// Read the ini file into the Dictionary + /// + /// Path & Filename of ini file + private static IDictionary> Read(string iniLocation) + { + if (!File.Exists(iniLocation)) + { + Log.Info("Can't find file: " + iniLocation); + return null; + } + + Log.InfoFormat("Loading ini-file: {0}", iniLocation); + //LOG.Info("Reading ini-properties from file: " + iniLocation); + var newSections = IniReader.Read(iniLocation, Encoding.UTF8); + // Merge the newly loaded properties to the already available + foreach (string section in newSections.Keys) + { + IDictionary newProperties = newSections[section]; + if (!_sections.ContainsKey(section)) + { + // This section is not yet loaded, simply add the complete section + _sections.Add(section, newProperties); + } + else + { + // Overwrite or add every property from the newly loaded section to the available one + var currentProperties = _sections[section]; + foreach (string propertyName in newProperties.Keys) + { + string propertyValue = newProperties[propertyName]; + if (currentProperties.ContainsKey(propertyName)) + { + // Override current value as we are loading in a certain order which insures the default, current and fixed + currentProperties[propertyName] = propertyValue; + } + else + { + // Add "new" value + currentProperties.Add(propertyName, propertyValue); + } + } + } + } + + return newSections; + } + + public static IEnumerable IniSectionNames + { + get + { + foreach (string sectionName in SectionMap.Keys) + { + yield return sectionName; + } + } + } + + /// + /// Method used for internal tricks... + /// + /// + /// + public static IniSection GetIniSection(string sectionName) + { + SectionMap.TryGetValue(sectionName, out var returnValue); + return returnValue; + } + + /// + /// A generic method which returns an instance of the supplied type, filled with it's configuration + /// + /// IniSection Type to get the configuration for + /// Filled instance of IniSection type which was supplied + public static T GetIniSection() where T : IniSection + { + return GetIniSection(true); + } + + /// + /// + /// + /// IniSection Type to get the configuration for + /// false to skip saving + /// IniSection + public static T GetIniSection(bool allowSave) where T : IniSection + { + T section; + + Type iniSectionType = typeof(T); + string sectionName = IniSection.GetIniSectionAttribute(iniSectionType).Name; + if (SectionMap.ContainsKey(sectionName)) + { + //LOG.Debug("Returning pre-mapped section " + sectionName); + section = (T) SectionMap[sectionName]; + } + else + { + // Create instance of this type + section = (T) Activator.CreateInstance(iniSectionType); + + // Store for later save & retrieval + SectionMap.Add(sectionName, section); + section.Fill(PropertiesForSection(section)); + FixProperties(section); + } + + if (allowSave && section.IsDirty) + { + Log.DebugFormat("Section {0} is marked dirty, saving!", sectionName); + Save(); + } + + return section; + } + + /// + /// Get the raw properties for a section + /// + /// + /// + public static IDictionary PropertiesForSection(IniSection section) + { + string sectionName = section.IniSectionAttribute.Name; + // Get the properties for the section + IDictionary properties; + if (_sections.ContainsKey(sectionName)) + { + properties = _sections[sectionName]; + } + else + { + _sections.Add(sectionName, new Dictionary()); + properties = _sections[sectionName]; + } + + return properties; + } + + /// + /// Save the ini file + /// + public static void Save() + { + bool acquiredLock = false; + try + { + acquiredLock = Monitor.TryEnter(IniLock, TimeSpan.FromMilliseconds(200)); + if (acquiredLock) + { + // Code that accesses resources that are protected by the lock. + string iniLocation = CreateIniLocation(_configName + IniExtension, false); + try + { + SaveInternally(iniLocation); + } + catch (Exception ex) + { + Log.Error("A problem occured while writing the configuration file to: " + iniLocation); + Log.Error(ex); + } + } + else + { + // Code to deal with the fact that the lock was not acquired. + Log.Warn("A second thread tried to save the ini-file, we blocked as the first took too long."); + } + } + finally + { + if (acquiredLock) + { + Monitor.Exit(IniLock); + } + } + } + + /// + /// The real save implementation + /// + /// + private static void SaveInternally(string iniLocation) + { + Log.Info("Saving configuration to: " + iniLocation); + var iniPath = Path.GetDirectoryName(iniLocation); + if (iniPath != null && !Directory.Exists(iniPath)) + { + Directory.CreateDirectory(iniPath); + } + + using var memoryStream = new MemoryStream(); + using TextWriter writer = new StreamWriter(memoryStream, Encoding.UTF8); + foreach (var section in SectionMap.Values) + { + section.Write(writer, false); + // Add empty line after section + writer.WriteLine(); + section.IsDirty = false; + } + + writer.WriteLine(); + // Write left over properties + foreach (string sectionName in _sections.Keys) + { + // Check if the section is one that is "registered", if so skip it! + if (SectionMap.ContainsKey(sectionName)) + { + continue; + } + + writer.WriteLine("; The section {0} hasn't been 'claimed' since the last start of Greenshot, therefor it doesn't have additional information here!", sectionName); + writer.WriteLine( + "; The reason could be that the section {0} just hasn't been used, a plugin has an error and can't claim it or maybe the whole section {0} is obsolete.", + sectionName); + // Write section name + writer.WriteLine("[{0}]", sectionName); + var properties = _sections[sectionName]; + // Loop and write properties + foreach (string propertyName in properties.Keys) + { + writer.WriteLine("{0}={1}", propertyName, properties[propertyName]); + } + + writer.WriteLine(); + } + + // Don't forget to flush the buffer + writer.Flush(); + // Now write the created .ini string to the real file + using FileStream fileStream = new FileStream(iniLocation, FileMode.Create, FileAccess.Write); + memoryStream.WriteTo(fileStream); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IniFile/IniReader.cs b/src/Greenshot.Base/IniFile/IniReader.cs similarity index 96% rename from src/GreenshotPlugin/IniFile/IniReader.cs rename to src/Greenshot.Base/IniFile/IniReader.cs index de83fde26..e9db1787c 100644 --- a/src/GreenshotPlugin/IniFile/IniReader.cs +++ b/src/Greenshot.Base/IniFile/IniReader.cs @@ -1,104 +1,104 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace GreenshotPlugin.IniFile -{ - /// - /// The IniReader does exactly what it says, it reads the .ini file - /// - public static class IniReader - { - private const char SectionStartToken = '['; - private const char SectionEndToken = ']'; - private const char CommentToken = ';'; - - private static readonly char[] Assignment = - { - '=' - }; - - /// - /// Read an ini file to a Dictionary, each key is a section and the value is a Dictionary with name and values. - /// - /// - /// - /// - public static IDictionary> Read(string path, Encoding encoding) - { - var ini = new Dictionary>(); - using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024)) - { - using var streamReader = new StreamReader(fileStream, encoding); - IDictionary nameValues = new Dictionary(); - while (!streamReader.EndOfStream) - { - string line = streamReader.ReadLine(); - if (line == null) - { - continue; - } - - string cleanLine = line.Trim(); - if (cleanLine.Length == 0 || cleanLine[0] == CommentToken) - { - continue; - } - - if (cleanLine[0] == SectionStartToken) - { - var sectionEndIndex = line.IndexOf(SectionEndToken, 1); - if (sectionEndIndex < 0) - { - continue; - } - - string section = line.Substring(1, sectionEndIndex - 1).Trim(); - if (!ini.TryGetValue(section, out nameValues)) - { - nameValues = new Dictionary(); - ini.Add(section, nameValues); - } - } - else - { - string[] keyvalueSplitter = line.Split(Assignment, 2); - string name = keyvalueSplitter[0]; - string inivalue = keyvalueSplitter.Length > 1 ? keyvalueSplitter[1] : null; - if (nameValues.ContainsKey(name)) - { - nameValues[name] = inivalue; - } - else - { - nameValues.Add(name, inivalue); - } - } - } - } - - return ini; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Greenshot.Base.IniFile +{ + /// + /// The IniReader does exactly what it says, it reads the .ini file + /// + public static class IniReader + { + private const char SectionStartToken = '['; + private const char SectionEndToken = ']'; + private const char CommentToken = ';'; + + private static readonly char[] Assignment = + { + '=' + }; + + /// + /// Read an ini file to a Dictionary, each key is a section and the value is a Dictionary with name and values. + /// + /// + /// + /// + public static IDictionary> Read(string path, Encoding encoding) + { + var ini = new Dictionary>(); + using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024)) + { + using var streamReader = new StreamReader(fileStream, encoding); + IDictionary nameValues = new Dictionary(); + while (!streamReader.EndOfStream) + { + string line = streamReader.ReadLine(); + if (line == null) + { + continue; + } + + string cleanLine = line.Trim(); + if (cleanLine.Length == 0 || cleanLine[0] == CommentToken) + { + continue; + } + + if (cleanLine[0] == SectionStartToken) + { + var sectionEndIndex = line.IndexOf(SectionEndToken, 1); + if (sectionEndIndex < 0) + { + continue; + } + + string section = line.Substring(1, sectionEndIndex - 1).Trim(); + if (!ini.TryGetValue(section, out nameValues)) + { + nameValues = new Dictionary(); + ini.Add(section, nameValues); + } + } + else + { + string[] keyvalueSplitter = line.Split(Assignment, 2); + string name = keyvalueSplitter[0]; + string inivalue = keyvalueSplitter.Length > 1 ? keyvalueSplitter[1] : null; + if (nameValues.ContainsKey(name)) + { + nameValues[name] = inivalue; + } + else + { + nameValues.Add(name, inivalue); + } + } + } + } + + return ini; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IniFile/IniSection.cs b/src/Greenshot.Base/IniFile/IniSection.cs similarity index 96% rename from src/GreenshotPlugin/IniFile/IniSection.cs rename to src/Greenshot.Base/IniFile/IniSection.cs index 1c5b501a9..813534c13 100644 --- a/src/GreenshotPlugin/IniFile/IniSection.cs +++ b/src/Greenshot.Base/IniFile/IniSection.cs @@ -1,235 +1,235 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using GreenshotPlugin.Core; -using log4net; - -namespace GreenshotPlugin.IniFile -{ - /// - /// Base class for all IniSections - /// - [Serializable] - public abstract class IniSection - { - protected static ILog LOG = LogManager.GetLogger(typeof(IniSection)); - - [NonSerialized] private readonly IDictionary values = new Dictionary(); - [NonSerialized] private IniSectionAttribute iniSectionAttribute; - - public IniSectionAttribute IniSectionAttribute - { - get - { - if (iniSectionAttribute == null) - { - iniSectionAttribute = GetIniSectionAttribute(GetType()); - } - - return iniSectionAttribute; - } - } - - /// - /// Get the dictionary with all the IniValues - /// - public IDictionary Values - { - get { return values; } - } - - /// - /// Flag to specify if values have been changed - /// - public bool IsDirty { get; set; } - - /// - /// Supply values we can't put as defaults - /// - /// The property to return a default for - /// object with the default value for the supplied property - public virtual object GetDefault(string property) - { - return null; - } - - /// - /// This method will be called before converting the property, making to possible to correct a certain value - /// Can be used when migration is needed - /// - /// The name of the property - /// The string value of the property - /// string with the propertyValue, modified or not... - public virtual string PreCheckValue(string propertyName, string propertyValue) - { - return propertyValue; - } - - /// - /// This method will be called after reading the configuration, so eventually some corrections can be made - /// - public virtual void AfterLoad() - { - } - - /// - /// This will be called before saving the Section, so we can encrypt passwords etc... - /// - public virtual void BeforeSave() - { - } - - /// - /// This will be called before saving the Section, so we can decrypt passwords etc... - /// - public virtual void AfterSave() - { - } - - /// - /// Helper method to get the IniSectionAttribute of a type - /// - /// - /// - public static IniSectionAttribute GetIniSectionAttribute(Type iniSectionType) - { - Attribute[] classAttributes = Attribute.GetCustomAttributes(iniSectionType); - foreach (Attribute attribute in classAttributes) - { - if (attribute is IniSectionAttribute) - { - return (IniSectionAttribute) attribute; - } - } - - return null; - } - - /// - /// Fill the section with the supplied properties - /// - /// - public void Fill(IDictionary properties) - { - Type iniSectionType = GetType(); - - // Iterate over the members and create IniValueContainers - foreach (FieldInfo fieldInfo in iniSectionType.GetFields()) - { - if (Attribute.IsDefined(fieldInfo, typeof(IniPropertyAttribute))) - { - IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute) fieldInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; - if (!Values.ContainsKey(iniPropertyAttribute.Name)) - { - Values.Add(iniPropertyAttribute.Name, new IniValue(this, fieldInfo, iniPropertyAttribute)); - } - } - } - - foreach (PropertyInfo propertyInfo in iniSectionType.GetProperties()) - { - if (Attribute.IsDefined(propertyInfo, typeof(IniPropertyAttribute))) - { - if (!Values.ContainsKey(propertyInfo.Name)) - { - IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute) propertyInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; - Values.Add(iniPropertyAttribute.Name, new IniValue(this, propertyInfo, iniPropertyAttribute)); - } - } - } - - foreach (string fieldName in Values.Keys) - { - IniValue iniValue = Values[fieldName]; - try - { - iniValue.SetValueFromProperties(properties); - if (iniValue.Attributes.Encrypted) - { - if (iniValue.Value is string stringValue && stringValue.Length > 2) - { - iniValue.Value = stringValue.Decrypt(); - } - } - } - catch (Exception ex) - { - LOG.Error(ex); - } - } - - AfterLoad(); - } - - /// - /// Write the section to the writer - /// - /// - /// - public void Write(TextWriter writer, bool onlyProperties) - { - if (IniSectionAttribute == null) - { - throw new ArgumentException("Section didn't implement the IniSectionAttribute"); - } - - BeforeSave(); - try - { - if (!onlyProperties) - { - writer.WriteLine("; {0}", IniSectionAttribute.Description); - } - - writer.WriteLine("[{0}]", IniSectionAttribute.Name); - - foreach (IniValue value in Values.Values) - { - if (value.Attributes.Encrypted) - { - if (value.Value is string stringValue && stringValue.Length > 2) - { - value.Value = stringValue.Encrypt(); - } - } - - // Write the value - value.Write(writer, onlyProperties); - if (value.Attributes.Encrypted) - { - if (value.Value is string stringValue && stringValue.Length > 2) - { - value.Value = stringValue.Decrypt(); - } - } - } - } - finally - { - AfterSave(); - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Greenshot.Base.Core; +using log4net; + +namespace Greenshot.Base.IniFile +{ + /// + /// Base class for all IniSections + /// + [Serializable] + public abstract class IniSection + { + protected static ILog LOG = LogManager.GetLogger(typeof(IniSection)); + + [NonSerialized] private readonly IDictionary values = new Dictionary(); + [NonSerialized] private IniSectionAttribute iniSectionAttribute; + + public IniSectionAttribute IniSectionAttribute + { + get + { + if (iniSectionAttribute == null) + { + iniSectionAttribute = GetIniSectionAttribute(GetType()); + } + + return iniSectionAttribute; + } + } + + /// + /// Get the dictionary with all the IniValues + /// + public IDictionary Values + { + get { return values; } + } + + /// + /// Flag to specify if values have been changed + /// + public bool IsDirty { get; set; } + + /// + /// Supply values we can't put as defaults + /// + /// The property to return a default for + /// object with the default value for the supplied property + public virtual object GetDefault(string property) + { + return null; + } + + /// + /// This method will be called before converting the property, making to possible to correct a certain value + /// Can be used when migration is needed + /// + /// The name of the property + /// The string value of the property + /// string with the propertyValue, modified or not... + public virtual string PreCheckValue(string propertyName, string propertyValue) + { + return propertyValue; + } + + /// + /// This method will be called after reading the configuration, so eventually some corrections can be made + /// + public virtual void AfterLoad() + { + } + + /// + /// This will be called before saving the Section, so we can encrypt passwords etc... + /// + public virtual void BeforeSave() + { + } + + /// + /// This will be called before saving the Section, so we can decrypt passwords etc... + /// + public virtual void AfterSave() + { + } + + /// + /// Helper method to get the IniSectionAttribute of a type + /// + /// + /// + public static IniSectionAttribute GetIniSectionAttribute(Type iniSectionType) + { + Attribute[] classAttributes = Attribute.GetCustomAttributes(iniSectionType); + foreach (Attribute attribute in classAttributes) + { + if (attribute is IniSectionAttribute) + { + return (IniSectionAttribute) attribute; + } + } + + return null; + } + + /// + /// Fill the section with the supplied properties + /// + /// + public void Fill(IDictionary properties) + { + Type iniSectionType = GetType(); + + // Iterate over the members and create IniValueContainers + foreach (FieldInfo fieldInfo in iniSectionType.GetFields()) + { + if (Attribute.IsDefined(fieldInfo, typeof(IniPropertyAttribute))) + { + IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute) fieldInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; + if (!Values.ContainsKey(iniPropertyAttribute.Name)) + { + Values.Add(iniPropertyAttribute.Name, new IniValue(this, fieldInfo, iniPropertyAttribute)); + } + } + } + + foreach (PropertyInfo propertyInfo in iniSectionType.GetProperties()) + { + if (Attribute.IsDefined(propertyInfo, typeof(IniPropertyAttribute))) + { + if (!Values.ContainsKey(propertyInfo.Name)) + { + IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute) propertyInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; + Values.Add(iniPropertyAttribute.Name, new IniValue(this, propertyInfo, iniPropertyAttribute)); + } + } + } + + foreach (string fieldName in Values.Keys) + { + IniValue iniValue = Values[fieldName]; + try + { + iniValue.SetValueFromProperties(properties); + if (iniValue.Attributes.Encrypted) + { + if (iniValue.Value is string stringValue && stringValue.Length > 2) + { + iniValue.Value = stringValue.Decrypt(); + } + } + } + catch (Exception ex) + { + LOG.Error(ex); + } + } + + AfterLoad(); + } + + /// + /// Write the section to the writer + /// + /// + /// + public void Write(TextWriter writer, bool onlyProperties) + { + if (IniSectionAttribute == null) + { + throw new ArgumentException("Section didn't implement the IniSectionAttribute"); + } + + BeforeSave(); + try + { + if (!onlyProperties) + { + writer.WriteLine("; {0}", IniSectionAttribute.Description); + } + + writer.WriteLine("[{0}]", IniSectionAttribute.Name); + + foreach (IniValue value in Values.Values) + { + if (value.Attributes.Encrypted) + { + if (value.Value is string stringValue && stringValue.Length > 2) + { + value.Value = stringValue.Encrypt(); + } + } + + // Write the value + value.Write(writer, onlyProperties); + if (value.Attributes.Encrypted) + { + if (value.Value is string stringValue && stringValue.Length > 2) + { + value.Value = stringValue.Decrypt(); + } + } + } + } + finally + { + AfterSave(); + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/IniFile/IniValue.cs b/src/Greenshot.Base/IniFile/IniValue.cs similarity index 97% rename from src/GreenshotPlugin/IniFile/IniValue.cs rename to src/Greenshot.Base/IniFile/IniValue.cs index a6599990a..312ce25be 100644 --- a/src/GreenshotPlugin/IniFile/IniValue.cs +++ b/src/Greenshot.Base/IniFile/IniValue.cs @@ -1,621 +1,621 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Reflection; -using System.Text; -using log4net; - -namespace GreenshotPlugin.IniFile -{ - /// - /// A container to be able to pass the value from a IniSection around. - /// - public class IniValue - { - private static readonly ILog Log = LogManager.GetLogger(typeof(IniValue)); - private readonly PropertyInfo _propertyInfo; - private readonly FieldInfo _fieldInfo; - private readonly IniSection _containingIniSection; - private readonly IniPropertyAttribute _attributes; - - public IniValue(IniSection containingIniSection, PropertyInfo propertyInfo, IniPropertyAttribute iniPropertyAttribute) - { - _containingIniSection = containingIniSection; - _propertyInfo = propertyInfo; - _attributes = iniPropertyAttribute; - } - - public IniValue(IniSection containingIniSection, FieldInfo fieldInfo, IniPropertyAttribute iniPropertyAttribute) - { - _containingIniSection = containingIniSection; - _fieldInfo = fieldInfo; - _attributes = iniPropertyAttribute; - } - - /// - /// Return true when the value is fixed - /// - public bool IsFixed - { - get - { - if (_attributes != null) - { - return _attributes.FixedValue; - } - - return false; - } - set - { - if (_attributes != null) - { - _attributes.FixedValue = value; - } - } - } - - /// - /// Return true when the value is for experts - /// - public bool IsExpert - { - get - { - if (_attributes != null) - { - return _attributes.Expert; - } - - return false; - } - set - { - if (_attributes != null) - { - _attributes.Expert = value; - } - } - } - - - /// - /// Return true when the value is can be changed by the GUI - /// - public bool IsEditable => !IsFixed; - - /// - /// Return true when the value is visible in the GUI - /// - public bool IsVisible => !IsExpert; - - public MemberInfo MemberInfo - { - get - { - if (_propertyInfo == null) - { - return _fieldInfo; - } - - return _propertyInfo; - } - } - - /// - /// Returns the IniSection this value is contained in - /// - public IniSection ContainingIniSection => _containingIniSection; - - /// - /// Get the in the ini file defined attributes - /// - public IniPropertyAttribute Attributes => _attributes; - - /// - /// Get the value for this IniValue - /// - public object Value - { - get - { - if (_propertyInfo == null) - { - return _fieldInfo.GetValue(_containingIniSection); - } - - return _propertyInfo.GetValue(_containingIniSection, null); - } - set - { - if (_propertyInfo == null) - { - _fieldInfo.SetValue(_containingIniSection, value); - } - else - { - _propertyInfo.SetValue(_containingIniSection, value, null); - } - } - } - - /// - /// Get the Type of the value - /// - public Type ValueType - { - get - { - var valueType = _propertyInfo?.PropertyType ?? _fieldInfo.FieldType; - if (!valueType.IsGenericType) - { - return valueType; - } - - var genericTypeDefinition = valueType.GetGenericTypeDefinition(); - if (genericTypeDefinition != null && genericTypeDefinition == typeof(Nullable<>)) - { - // We are dealing with a generic type that is nullable - valueType = Nullable.GetUnderlyingType(valueType); - } - - return valueType; - } - } - - /// - /// Write the value to the text writer - /// - /// TextWriter to write to - /// true if we do not want the comment - public void Write(TextWriter writer, bool onlyProperties) - { - object myValue = Value; - Type valueType = ValueType; - if (myValue == null) - { - if (_attributes.ExcludeIfNull) - { - return; - } - - if (_attributes.DefaultValue != null) - { - myValue = _attributes.DefaultValue; - valueType = typeof(string); - } - else - { - myValue = _containingIniSection.GetDefault(_attributes.Name); - if (myValue != null) - { - valueType = myValue.GetType(); - } - } - } - - if (myValue == null) - { - if (_attributes.ExcludeIfNull) - { - return; - } - } - - if (!onlyProperties) - { - writer.WriteLine("; {0}", _attributes.Description); - } - - if (myValue == null) - { - writer.WriteLine("{0}=", _attributes.Name); - return; - } - - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) - { - // Handle dictionaries. - Type valueType1 = valueType.GetGenericArguments()[0]; - Type valueType2 = valueType.GetGenericArguments()[1]; - // Get the methods we need to deal with dictionaries. - var keys = valueType.GetProperty("Keys").GetValue(myValue, null); - var item = valueType.GetProperty("Item"); - var enumerator = keys.GetType().GetMethod("GetEnumerator").Invoke(keys, null); - var moveNext = enumerator.GetType().GetMethod("MoveNext"); - var current = enumerator.GetType().GetProperty("Current").GetGetMethod(); - // Get all the values. - while ((bool) moveNext.Invoke(enumerator, null)) - { - var key = current.Invoke(enumerator, null); - var valueObject = item.GetValue(myValue, new[] - { - key - }); - // Write to ini file! - writer.WriteLine("{0}.{1}={2}", _attributes.Name, ConvertValueToString(valueType1, key, _attributes.Separator), - ConvertValueToString(valueType2, valueObject, _attributes.Separator)); - } - } - else - { - writer.WriteLine("{0}={1}", _attributes.Name, ConvertValueToString(valueType, myValue, _attributes.Separator)); - } - } - - /// - /// Set the value to the value in the ini file, or default - /// - /// - public void SetValueFromProperties(IDictionary properties) - { - string propertyName = _attributes.Name; - string propertyValue = null; - if (properties.ContainsKey(propertyName) && properties[propertyName] != null) - { - propertyValue = _containingIniSection.PreCheckValue(propertyName, properties[propertyName]); - } - - UseValueOrDefault(propertyValue); - } - - /// - /// This method will set the ini value to the supplied value or use the default if non supplied - /// - /// - public void UseValueOrDefault(string propertyValue) - { - Type valueType = ValueType; - string propertyName = _attributes.Name; - string defaultValue = _attributes.DefaultValue; - bool defaultUsed = false; - object defaultValueFromConfig = _containingIniSection.GetDefault(propertyName); - - if (string.IsNullOrEmpty(propertyValue)) - { - if (defaultValue != null && defaultValue.Trim().Length != 0) - { - propertyValue = defaultValue; - defaultUsed = true; - } - else if (defaultValueFromConfig != null) - { - Log.DebugFormat("Default for Property {0} implemented!", propertyName); - } - else - { - if (_attributes.ExcludeIfNull) - { - Value = null; - return; - } - - Log.DebugFormat("Property {0} has no value or default value!", propertyName); - } - } - - // Now set the value - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) - { - // Logic for Dictionary<,> - Type type1 = valueType.GetGenericArguments()[0]; - Type type2 = valueType.GetGenericArguments()[1]; - //LOG.Info(String.Format("Found Dictionary<{0},{1}>", type1.Name, type2.Name)); - object dictionary = Activator.CreateInstance(valueType); - MethodInfo addMethodInfo = valueType.GetMethod("Add"); - bool addedElements = false; - IDictionary properties = IniConfig.PropertiesForSection(_containingIniSection); - foreach (string key in properties.Keys) - { - if (key != null && key.StartsWith(propertyName + ".")) - { - // What "key" do we need to store it under? - string subPropertyName = key.Substring(propertyName.Length + 1); - string stringValue = properties[key]; - object newValue1 = null; - object newValue2 = null; - try - { - newValue1 = ConvertStringToValueType(type1, subPropertyName, _attributes.Separator); - } - catch (Exception ex) - { - Log.Warn(ex); - //LOG.Error("Problem converting " + subPropertyName + " to type " + type1.FullName, e); - } - - try - { - newValue2 = ConvertStringToValueType(type2, stringValue, _attributes.Separator); - } - catch (Exception ex) - { - Log.Warn(ex); - //LOG.Error("Problem converting " + stringValue + " to type " + type2.FullName, e); - } - - addMethodInfo.Invoke(dictionary, new[] - { - newValue1, newValue2 - }); - addedElements = true; - } - } - - // No need to return something that isn't filled! - if (addedElements) - { - Value = dictionary; - return; - } - - if (defaultValueFromConfig != null) - { - Value = defaultValueFromConfig; - return; - } - } - else if (!string.IsNullOrEmpty(propertyValue)) - { - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - // We are dealing with a generic type that is nullable - valueType = Nullable.GetUnderlyingType(valueType); - } - - object newValue; - try - { - newValue = ConvertStringToValueType(valueType, propertyValue, _attributes.Separator); - } - catch (Exception ex1) - { - newValue = null; - if (!defaultUsed) - { - try - { - Log.WarnFormat("Problem '{0}' while converting {1} to type {2} trying fallback...", ex1.Message, propertyValue, valueType.FullName); - newValue = ConvertStringToValueType(valueType, defaultValue, _attributes.Separator); - ContainingIniSection.IsDirty = true; - Log.InfoFormat("Used default value {0} for property {1}", defaultValue, propertyName); - } - catch (Exception ex2) - { - Log.Warn("Problem converting fallback value " + defaultValue + " to type " + valueType.FullName, ex2); - } - } - else - { - Log.Warn("Problem converting " + propertyValue + " to type " + valueType.FullName, ex1); - } - } - - Value = newValue; - return; - } - - // If nothing is set, we can use the default value from the config (if we habe one) - if (defaultValueFromConfig != null) - { - Value = defaultValueFromConfig; - return; - } - - if (ValueType != typeof(string)) - { - try - { - Value = Activator.CreateInstance(ValueType); - } - catch (Exception) - { - Log.WarnFormat("Couldn't create instance of {0} for {1}, using default value.", ValueType.FullName, _attributes.Name); - Value = default(ValueType); - } - } - else - { - Value = default(ValueType); - } - } - - /// - /// Convert a string to a value of type "valueType" - /// - /// Type to convert tp - /// string to convert from - /// - /// Value - private static object ConvertStringToValueType(Type valueType, string valueString, string separator) - { - if (valueString == null) - { - return null; - } - - if (valueType == typeof(string)) - { - return valueString; - } - - if (string.IsNullOrEmpty(valueString)) - { - return null; - } - - // The following makes the enum string values a bit less restrictive - if (valueType.IsEnum) - { - string searchingEnumString = valueString.Replace("_", string.Empty).ToLowerInvariant(); - foreach (var possibleValue in Enum.GetValues(valueType)) - { - var possibleString = possibleValue.ToString().Replace("_", string.Empty).ToLowerInvariant(); - if (possibleString.Equals(searchingEnumString)) - { - return possibleValue; - } - } - } - - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) - { - string arraySeparator = separator; - object list = Activator.CreateInstance(valueType); - // Logic for List<> - string[] arrayValues = valueString.Split(new[] - { - arraySeparator - }, StringSplitOptions.None); - if (arrayValues.Length == 0) - { - return list; - } - - MethodInfo addMethodInfo = valueType.GetMethod("Add"); - - foreach (string arrayValue in arrayValues) - { - if (!string.IsNullOrEmpty(arrayValue)) - { - object newValue = null; - try - { - newValue = ConvertStringToValueType(valueType.GetGenericArguments()[0], arrayValue, separator); - } - catch (Exception ex) - { - Log.Warn("Problem converting " + arrayValue + " to type " + valueType.FullName, ex); - } - - if (newValue != null) - { - addMethodInfo.Invoke(list, new[] - { - newValue - }); - } - } - } - - return list; - } - - //LOG.Debug("No convertor for " + fieldType.ToString()); - if (valueType == typeof(object) && valueString.Length > 0) - { - //LOG.Debug("Parsing: " + valueString); - string[] values = valueString.Split(':'); - //LOG.Debug("Type: " + values[0]); - //LOG.Debug("Value: " + values[1]); - Type fieldTypeForValue = Type.GetType(values[0], true); - //LOG.Debug("Type after GetType: " + fieldTypeForValue); - return ConvertStringToValueType(fieldTypeForValue, values[1], separator); - } - - TypeConverter converter = TypeDescriptor.GetConverter(valueType); - return converter.ConvertFromInvariantString(valueString); - } - - /// - /// Override of ToString which calls the ConvertValueToString - /// - /// string representation of this - public override string ToString() - { - return ConvertValueToString(ValueType, Value, _attributes.Separator); - } - - /// - /// Convert the supplied value to a string - /// - /// Type to convert - /// Value to convert - /// separator for lists - /// string representation of the value - private static string ConvertValueToString(Type valueType, object valueObject, string separator) - { - if (valueObject == null) - { - // If there is nothing, deliver nothing! - return string.Empty; - } - - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) - { - StringBuilder stringBuilder = new StringBuilder(); - Type specificValueType = valueType.GetGenericArguments()[0]; - int listCount = (int) valueType.GetProperty("Count").GetValue(valueObject, null); - // Loop though generic list - for (int index = 0; index < listCount; index++) - { - object item = valueType.GetMethod("get_Item").Invoke(valueObject, new object[] - { - index - }); - - // Now you have an instance of the item in the generic list - if (index < listCount - 1) - { - stringBuilder.AppendFormat("{0}{1}", ConvertValueToString(specificValueType, item, separator), separator); - } - else - { - stringBuilder.AppendFormat("{0}", ConvertValueToString(specificValueType, item, separator)); - } - } - - return stringBuilder.ToString(); - } - - if (valueType == typeof(object)) - { - // object to String, this is the hardest - // Format will be "FQTypename[,Assemblyname]:Value" - - // Get the type so we can call ourselves recursive - Type objectType = valueObject.GetType(); - - // Get the value as string - string ourValue = ConvertValueToString(objectType, valueObject, separator); - - // Get the valuetype as string - string valueTypeName = objectType.FullName; - // Find the assembly name and only append it if it's not already in the fqtypename (like System.Drawing) - string assemblyName = objectType.Assembly.FullName; - // correct assemblyName, this also has version information etc. - if (assemblyName.StartsWith("Green")) - { - assemblyName = assemblyName.Substring(0, assemblyName.IndexOf(',')); - } - - return $"{valueTypeName},{assemblyName}:{ourValue}"; - } - - TypeConverter converter = TypeDescriptor.GetConverter(valueType); - return converter.ConvertToInvariantString(valueObject); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Reflection; +using System.Text; +using log4net; + +namespace Greenshot.Base.IniFile +{ + /// + /// A container to be able to pass the value from a IniSection around. + /// + public class IniValue + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IniValue)); + private readonly PropertyInfo _propertyInfo; + private readonly FieldInfo _fieldInfo; + private readonly IniSection _containingIniSection; + private readonly IniPropertyAttribute _attributes; + + public IniValue(IniSection containingIniSection, PropertyInfo propertyInfo, IniPropertyAttribute iniPropertyAttribute) + { + _containingIniSection = containingIniSection; + _propertyInfo = propertyInfo; + _attributes = iniPropertyAttribute; + } + + public IniValue(IniSection containingIniSection, FieldInfo fieldInfo, IniPropertyAttribute iniPropertyAttribute) + { + _containingIniSection = containingIniSection; + _fieldInfo = fieldInfo; + _attributes = iniPropertyAttribute; + } + + /// + /// Return true when the value is fixed + /// + public bool IsFixed + { + get + { + if (_attributes != null) + { + return _attributes.FixedValue; + } + + return false; + } + set + { + if (_attributes != null) + { + _attributes.FixedValue = value; + } + } + } + + /// + /// Return true when the value is for experts + /// + public bool IsExpert + { + get + { + if (_attributes != null) + { + return _attributes.Expert; + } + + return false; + } + set + { + if (_attributes != null) + { + _attributes.Expert = value; + } + } + } + + + /// + /// Return true when the value is can be changed by the GUI + /// + public bool IsEditable => !IsFixed; + + /// + /// Return true when the value is visible in the GUI + /// + public bool IsVisible => !IsExpert; + + public MemberInfo MemberInfo + { + get + { + if (_propertyInfo == null) + { + return _fieldInfo; + } + + return _propertyInfo; + } + } + + /// + /// Returns the IniSection this value is contained in + /// + public IniSection ContainingIniSection => _containingIniSection; + + /// + /// Get the in the ini file defined attributes + /// + public IniPropertyAttribute Attributes => _attributes; + + /// + /// Get the value for this IniValue + /// + public object Value + { + get + { + if (_propertyInfo == null) + { + return _fieldInfo.GetValue(_containingIniSection); + } + + return _propertyInfo.GetValue(_containingIniSection, null); + } + set + { + if (_propertyInfo == null) + { + _fieldInfo.SetValue(_containingIniSection, value); + } + else + { + _propertyInfo.SetValue(_containingIniSection, value, null); + } + } + } + + /// + /// Get the Type of the value + /// + public Type ValueType + { + get + { + var valueType = _propertyInfo?.PropertyType ?? _fieldInfo.FieldType; + if (!valueType.IsGenericType) + { + return valueType; + } + + var genericTypeDefinition = valueType.GetGenericTypeDefinition(); + if (genericTypeDefinition != null && genericTypeDefinition == typeof(Nullable<>)) + { + // We are dealing with a generic type that is nullable + valueType = Nullable.GetUnderlyingType(valueType); + } + + return valueType; + } + } + + /// + /// Write the value to the text writer + /// + /// TextWriter to write to + /// true if we do not want the comment + public void Write(TextWriter writer, bool onlyProperties) + { + object myValue = Value; + Type valueType = ValueType; + if (myValue == null) + { + if (_attributes.ExcludeIfNull) + { + return; + } + + if (_attributes.DefaultValue != null) + { + myValue = _attributes.DefaultValue; + valueType = typeof(string); + } + else + { + myValue = _containingIniSection.GetDefault(_attributes.Name); + if (myValue != null) + { + valueType = myValue.GetType(); + } + } + } + + if (myValue == null) + { + if (_attributes.ExcludeIfNull) + { + return; + } + } + + if (!onlyProperties) + { + writer.WriteLine("; {0}", _attributes.Description); + } + + if (myValue == null) + { + writer.WriteLine("{0}=", _attributes.Name); + return; + } + + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // Handle dictionaries. + Type valueType1 = valueType.GetGenericArguments()[0]; + Type valueType2 = valueType.GetGenericArguments()[1]; + // Get the methods we need to deal with dictionaries. + var keys = valueType.GetProperty("Keys").GetValue(myValue, null); + var item = valueType.GetProperty("Item"); + var enumerator = keys.GetType().GetMethod("GetEnumerator").Invoke(keys, null); + var moveNext = enumerator.GetType().GetMethod("MoveNext"); + var current = enumerator.GetType().GetProperty("Current").GetGetMethod(); + // Get all the values. + while ((bool) moveNext.Invoke(enumerator, null)) + { + var key = current.Invoke(enumerator, null); + var valueObject = item.GetValue(myValue, new[] + { + key + }); + // Write to ini file! + writer.WriteLine("{0}.{1}={2}", _attributes.Name, ConvertValueToString(valueType1, key, _attributes.Separator), + ConvertValueToString(valueType2, valueObject, _attributes.Separator)); + } + } + else + { + writer.WriteLine("{0}={1}", _attributes.Name, ConvertValueToString(valueType, myValue, _attributes.Separator)); + } + } + + /// + /// Set the value to the value in the ini file, or default + /// + /// + public void SetValueFromProperties(IDictionary properties) + { + string propertyName = _attributes.Name; + string propertyValue = null; + if (properties.ContainsKey(propertyName) && properties[propertyName] != null) + { + propertyValue = _containingIniSection.PreCheckValue(propertyName, properties[propertyName]); + } + + UseValueOrDefault(propertyValue); + } + + /// + /// This method will set the ini value to the supplied value or use the default if non supplied + /// + /// + public void UseValueOrDefault(string propertyValue) + { + Type valueType = ValueType; + string propertyName = _attributes.Name; + string defaultValue = _attributes.DefaultValue; + bool defaultUsed = false; + object defaultValueFromConfig = _containingIniSection.GetDefault(propertyName); + + if (string.IsNullOrEmpty(propertyValue)) + { + if (defaultValue != null && defaultValue.Trim().Length != 0) + { + propertyValue = defaultValue; + defaultUsed = true; + } + else if (defaultValueFromConfig != null) + { + Log.DebugFormat("Default for Property {0} implemented!", propertyName); + } + else + { + if (_attributes.ExcludeIfNull) + { + Value = null; + return; + } + + Log.DebugFormat("Property {0} has no value or default value!", propertyName); + } + } + + // Now set the value + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // Logic for Dictionary<,> + Type type1 = valueType.GetGenericArguments()[0]; + Type type2 = valueType.GetGenericArguments()[1]; + //LOG.Info(String.Format("Found Dictionary<{0},{1}>", type1.Name, type2.Name)); + object dictionary = Activator.CreateInstance(valueType); + MethodInfo addMethodInfo = valueType.GetMethod("Add"); + bool addedElements = false; + IDictionary properties = IniConfig.PropertiesForSection(_containingIniSection); + foreach (string key in properties.Keys) + { + if (key != null && key.StartsWith(propertyName + ".")) + { + // What "key" do we need to store it under? + string subPropertyName = key.Substring(propertyName.Length + 1); + string stringValue = properties[key]; + object newValue1 = null; + object newValue2 = null; + try + { + newValue1 = ConvertStringToValueType(type1, subPropertyName, _attributes.Separator); + } + catch (Exception ex) + { + Log.Warn(ex); + //LOG.Error("Problem converting " + subPropertyName + " to type " + type1.FullName, e); + } + + try + { + newValue2 = ConvertStringToValueType(type2, stringValue, _attributes.Separator); + } + catch (Exception ex) + { + Log.Warn(ex); + //LOG.Error("Problem converting " + stringValue + " to type " + type2.FullName, e); + } + + addMethodInfo.Invoke(dictionary, new[] + { + newValue1, newValue2 + }); + addedElements = true; + } + } + + // No need to return something that isn't filled! + if (addedElements) + { + Value = dictionary; + return; + } + + if (defaultValueFromConfig != null) + { + Value = defaultValueFromConfig; + return; + } + } + else if (!string.IsNullOrEmpty(propertyValue)) + { + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + // We are dealing with a generic type that is nullable + valueType = Nullable.GetUnderlyingType(valueType); + } + + object newValue; + try + { + newValue = ConvertStringToValueType(valueType, propertyValue, _attributes.Separator); + } + catch (Exception ex1) + { + newValue = null; + if (!defaultUsed) + { + try + { + Log.WarnFormat("Problem '{0}' while converting {1} to type {2} trying fallback...", ex1.Message, propertyValue, valueType.FullName); + newValue = ConvertStringToValueType(valueType, defaultValue, _attributes.Separator); + ContainingIniSection.IsDirty = true; + Log.InfoFormat("Used default value {0} for property {1}", defaultValue, propertyName); + } + catch (Exception ex2) + { + Log.Warn("Problem converting fallback value " + defaultValue + " to type " + valueType.FullName, ex2); + } + } + else + { + Log.Warn("Problem converting " + propertyValue + " to type " + valueType.FullName, ex1); + } + } + + Value = newValue; + return; + } + + // If nothing is set, we can use the default value from the config (if we habe one) + if (defaultValueFromConfig != null) + { + Value = defaultValueFromConfig; + return; + } + + if (ValueType != typeof(string)) + { + try + { + Value = Activator.CreateInstance(ValueType); + } + catch (Exception) + { + Log.WarnFormat("Couldn't create instance of {0} for {1}, using default value.", ValueType.FullName, _attributes.Name); + Value = default(ValueType); + } + } + else + { + Value = default(ValueType); + } + } + + /// + /// Convert a string to a value of type "valueType" + /// + /// Type to convert tp + /// string to convert from + /// + /// Value + private static object ConvertStringToValueType(Type valueType, string valueString, string separator) + { + if (valueString == null) + { + return null; + } + + if (valueType == typeof(string)) + { + return valueString; + } + + if (string.IsNullOrEmpty(valueString)) + { + return null; + } + + // The following makes the enum string values a bit less restrictive + if (valueType.IsEnum) + { + string searchingEnumString = valueString.Replace("_", string.Empty).ToLowerInvariant(); + foreach (var possibleValue in Enum.GetValues(valueType)) + { + var possibleString = possibleValue.ToString().Replace("_", string.Empty).ToLowerInvariant(); + if (possibleString.Equals(searchingEnumString)) + { + return possibleValue; + } + } + } + + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) + { + string arraySeparator = separator; + object list = Activator.CreateInstance(valueType); + // Logic for List<> + string[] arrayValues = valueString.Split(new[] + { + arraySeparator + }, StringSplitOptions.None); + if (arrayValues.Length == 0) + { + return list; + } + + MethodInfo addMethodInfo = valueType.GetMethod("Add"); + + foreach (string arrayValue in arrayValues) + { + if (!string.IsNullOrEmpty(arrayValue)) + { + object newValue = null; + try + { + newValue = ConvertStringToValueType(valueType.GetGenericArguments()[0], arrayValue, separator); + } + catch (Exception ex) + { + Log.Warn("Problem converting " + arrayValue + " to type " + valueType.FullName, ex); + } + + if (newValue != null) + { + addMethodInfo.Invoke(list, new[] + { + newValue + }); + } + } + } + + return list; + } + + //LOG.Debug("No convertor for " + fieldType.ToString()); + if (valueType == typeof(object) && valueString.Length > 0) + { + //LOG.Debug("Parsing: " + valueString); + string[] values = valueString.Split(':'); + //LOG.Debug("Type: " + values[0]); + //LOG.Debug("Value: " + values[1]); + Type fieldTypeForValue = Type.GetType(values[0], true); + //LOG.Debug("Type after GetType: " + fieldTypeForValue); + return ConvertStringToValueType(fieldTypeForValue, values[1], separator); + } + + TypeConverter converter = TypeDescriptor.GetConverter(valueType); + return converter.ConvertFromInvariantString(valueString); + } + + /// + /// Override of ToString which calls the ConvertValueToString + /// + /// string representation of this + public override string ToString() + { + return ConvertValueToString(ValueType, Value, _attributes.Separator); + } + + /// + /// Convert the supplied value to a string + /// + /// Type to convert + /// Value to convert + /// separator for lists + /// string representation of the value + private static string ConvertValueToString(Type valueType, object valueObject, string separator) + { + if (valueObject == null) + { + // If there is nothing, deliver nothing! + return string.Empty; + } + + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) + { + StringBuilder stringBuilder = new StringBuilder(); + Type specificValueType = valueType.GetGenericArguments()[0]; + int listCount = (int) valueType.GetProperty("Count").GetValue(valueObject, null); + // Loop though generic list + for (int index = 0; index < listCount; index++) + { + object item = valueType.GetMethod("get_Item").Invoke(valueObject, new object[] + { + index + }); + + // Now you have an instance of the item in the generic list + if (index < listCount - 1) + { + stringBuilder.AppendFormat("{0}{1}", ConvertValueToString(specificValueType, item, separator), separator); + } + else + { + stringBuilder.AppendFormat("{0}", ConvertValueToString(specificValueType, item, separator)); + } + } + + return stringBuilder.ToString(); + } + + if (valueType == typeof(object)) + { + // object to String, this is the hardest + // Format will be "FQTypename[,Assemblyname]:Value" + + // Get the type so we can call ourselves recursive + Type objectType = valueObject.GetType(); + + // Get the value as string + string ourValue = ConvertValueToString(objectType, valueObject, separator); + + // Get the valuetype as string + string valueTypeName = objectType.FullName; + // Find the assembly name and only append it if it's not already in the fqtypename (like System.Drawing) + string assemblyName = objectType.Assembly.FullName; + // correct assemblyName, this also has version information etc. + if (assemblyName.StartsWith("Green")) + { + assemblyName = assemblyName.Substring(0, assemblyName.IndexOf(',')); + } + + return $"{valueTypeName},{assemblyName}:{ourValue}"; + } + + TypeConverter converter = TypeDescriptor.GetConverter(valueType); + return converter.ConvertToInvariantString(valueObject); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/CaptureMode.cs b/src/Greenshot.Base/Interfaces/CaptureMode.cs similarity index 97% rename from src/GreenshotPlugin/Interfaces/CaptureMode.cs rename to src/Greenshot.Base/Interfaces/CaptureMode.cs index 161726a2f..f3a063673 100644 --- a/src/GreenshotPlugin/Interfaces/CaptureMode.cs +++ b/src/Greenshot.Base/Interfaces/CaptureMode.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { /// /// The capture mode for Greenshot diff --git a/src/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs b/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs similarity index 95% rename from src/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs rename to src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs index 60206099a..cbfd004b4 100644 --- a/src/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs @@ -1,102 +1,102 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; - -namespace GreenshotPlugin.Interfaces.Drawing.Adorners -{ - public interface IAdorner - { - /// - /// Returns if this adorner is active - /// - bool IsActive { get; } - - /// - /// These are the bounds of the adorner - /// - Rectangle Bounds { get; } - - /// - /// The current edit status, this is needed to locate the adorner to send events to - /// - EditStatus EditStatus { get; } - - /// - /// The owner of this adorner - /// - IDrawableContainer Owner { get; } - - /// - /// Is the current point "over" the Adorner? - /// If this is the case, the - /// - /// Point to test - /// true if so - bool HitTest(Point point); - - /// - /// Handle the MouseDown event - /// - /// - /// MouseEventArgs - void MouseDown(object sender, MouseEventArgs mouseEventArgs); - - /// - /// Handle the MouseUp event - /// - /// - /// MouseEventArgs - void MouseUp(object sender, MouseEventArgs mouseEventArgs); - - /// - /// Handle the MouseMove event - /// - /// - /// MouseEventArgs - void MouseMove(object sender, MouseEventArgs mouseEventArgs); - - /// - /// Gets the cursor that should be displayed for this behavior. - /// - Cursor Cursor { get; } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - void Paint(PaintEventArgs paintEventArgs); - - /// - /// Called if the owner is transformed - /// - /// Matrix - void Transform(Matrix matrix); - - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// - void AdjustToDpi(uint dpi); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace Greenshot.Base.Interfaces.Drawing.Adorners +{ + public interface IAdorner + { + /// + /// Returns if this adorner is active + /// + bool IsActive { get; } + + /// + /// These are the bounds of the adorner + /// + Rectangle Bounds { get; } + + /// + /// The current edit status, this is needed to locate the adorner to send events to + /// + EditStatus EditStatus { get; } + + /// + /// The owner of this adorner + /// + IDrawableContainer Owner { get; } + + /// + /// Is the current point "over" the Adorner? + /// If this is the case, the + /// + /// Point to test + /// true if so + bool HitTest(Point point); + + /// + /// Handle the MouseDown event + /// + /// + /// MouseEventArgs + void MouseDown(object sender, MouseEventArgs mouseEventArgs); + + /// + /// Handle the MouseUp event + /// + /// + /// MouseEventArgs + void MouseUp(object sender, MouseEventArgs mouseEventArgs); + + /// + /// Handle the MouseMove event + /// + /// + /// MouseEventArgs + void MouseMove(object sender, MouseEventArgs mouseEventArgs); + + /// + /// Gets the cursor that should be displayed for this behavior. + /// + Cursor Cursor { get; } + + /// + /// Draw the adorner + /// + /// PaintEventArgs + void Paint(PaintEventArgs paintEventArgs); + + /// + /// Called if the owner is transformed + /// + /// Matrix + void Transform(Matrix matrix); + + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// + void AdjustToDpi(uint dpi); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Drawing/Container.cs b/src/Greenshot.Base/Interfaces/Drawing/Container.cs similarity index 94% rename from src/GreenshotPlugin/Interfaces/Drawing/Container.cs rename to src/Greenshot.Base/Interfaces/Drawing/Container.cs index 0180886bc..feebb4dfc 100644 --- a/src/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/Container.cs @@ -1,149 +1,149 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing.Adorners; - -namespace GreenshotPlugin.Interfaces.Drawing -{ - public enum RenderMode - { - EDIT, - EXPORT - }; - - public enum EditStatus - { - UNDRAWN, - DRAWING, - MOVING, - RESIZING, - IDLE - }; - - public interface IDrawableContainer : INotifyPropertyChanged, IDisposable - { - ISurface Parent { get; set; } - bool Selected { get; set; } - - int Left { get; set; } - - int Top { get; set; } - - int Width { get; set; } - - int Height { get; set; } - - Point Location { get; } - - Size Size { get; } - - Rectangle Bounds { get; } - - Rectangle DrawingBounds { get; } - - void ApplyBounds(RectangleF newBounds); - - bool hasFilters { get; } - - EditStatus Status { get; set; } - void Invalidate(); - bool ClickableAt(int x, int y); - void MoveBy(int x, int y); - void Transform(Matrix matrix); - bool HandleMouseDown(int x, int y); - void HandleMouseUp(int x, int y); - bool HandleMouseMove(int x, int y); - bool InitContent(); - void MakeBoundsChangeUndoable(bool allowMerge); - EditStatus DefaultEditMode { get; } - - /// - /// Available adorners for the DrawableContainer - /// - IList Adorners { get; } - - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// uint - void AdjustToDpi(uint dpi); - } - - public interface IDrawableContainerList : IList, IDisposable - { - Guid ParentID { get; } - - bool Selected { get; set; } - - ISurface Parent { get; set; } - EditStatus Status { get; set; } - Rectangle DrawingBounds { get; } - void MakeBoundsChangeUndoable(bool allowMerge); - void Transform(Matrix matrix); - void MoveBy(int dx, int dy); - bool ClickableAt(int x, int y); - IDrawableContainer ClickableElementAt(int x, int y); - void OnDoubleClick(); - bool HasIntersectingFilters(Rectangle clipRectangle); - bool IntersectsWith(Rectangle clipRectangle); - void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle); - void Invalidate(); - void PullElementsToTop(IDrawableContainerList elements); - bool CanPushDown(IDrawableContainerList elements); - void PullElementsUp(IDrawableContainerList elements); - bool CanPullUp(IDrawableContainerList elements); - void PushElementsDown(IDrawableContainerList elements); - void PushElementsToBottom(IDrawableContainerList elements); - void ShowContextMenu(MouseEventArgs e, ISurface surface); - void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e); - void AdjustToDpi(uint dpi); - } - - public interface ITextContainer : IDrawableContainer - { - string Text { get; set; } - void FitToText(); - } - - public interface IImageContainer : IDrawableContainer - { - Image Image { get; set; } - void Load(string filename); - } - - public interface ICursorContainer : IDrawableContainer - { - Cursor Cursor { get; set; } - void Load(string filename); - } - - public interface IIconContainer : IDrawableContainer - { - Icon Icon { get; set; } - void Load(string filename); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using Greenshot.Base.Interfaces.Drawing.Adorners; + +namespace Greenshot.Base.Interfaces.Drawing +{ + public enum RenderMode + { + EDIT, + EXPORT + }; + + public enum EditStatus + { + UNDRAWN, + DRAWING, + MOVING, + RESIZING, + IDLE + }; + + public interface IDrawableContainer : INotifyPropertyChanged, IDisposable + { + ISurface Parent { get; set; } + bool Selected { get; set; } + + int Left { get; set; } + + int Top { get; set; } + + int Width { get; set; } + + int Height { get; set; } + + Point Location { get; } + + Size Size { get; } + + Rectangle Bounds { get; } + + Rectangle DrawingBounds { get; } + + void ApplyBounds(RectangleF newBounds); + + bool hasFilters { get; } + + EditStatus Status { get; set; } + void Invalidate(); + bool ClickableAt(int x, int y); + void MoveBy(int x, int y); + void Transform(Matrix matrix); + bool HandleMouseDown(int x, int y); + void HandleMouseUp(int x, int y); + bool HandleMouseMove(int x, int y); + bool InitContent(); + void MakeBoundsChangeUndoable(bool allowMerge); + EditStatus DefaultEditMode { get; } + + /// + /// Available adorners for the DrawableContainer + /// + IList Adorners { get; } + + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// uint + void AdjustToDpi(uint dpi); + } + + public interface IDrawableContainerList : IList, IDisposable + { + Guid ParentID { get; } + + bool Selected { get; set; } + + ISurface Parent { get; set; } + EditStatus Status { get; set; } + Rectangle DrawingBounds { get; } + void MakeBoundsChangeUndoable(bool allowMerge); + void Transform(Matrix matrix); + void MoveBy(int dx, int dy); + bool ClickableAt(int x, int y); + IDrawableContainer ClickableElementAt(int x, int y); + void OnDoubleClick(); + bool HasIntersectingFilters(Rectangle clipRectangle); + bool IntersectsWith(Rectangle clipRectangle); + void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle); + void Invalidate(); + void PullElementsToTop(IDrawableContainerList elements); + bool CanPushDown(IDrawableContainerList elements); + void PullElementsUp(IDrawableContainerList elements); + bool CanPullUp(IDrawableContainerList elements); + void PushElementsDown(IDrawableContainerList elements); + void PushElementsToBottom(IDrawableContainerList elements); + void ShowContextMenu(MouseEventArgs e, ISurface surface); + void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e); + void AdjustToDpi(uint dpi); + } + + public interface ITextContainer : IDrawableContainer + { + string Text { get; set; } + void FitToText(); + } + + public interface IImageContainer : IDrawableContainer + { + Image Image { get; set; } + void Load(string filename); + } + + public interface ICursorContainer : IDrawableContainer + { + Cursor Cursor { get; set; } + void Load(string filename); + } + + public interface IIconContainer : IDrawableContainer + { + Icon Icon { get; set; } + void Load(string filename); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Drawing/IField.cs b/src/Greenshot.Base/Interfaces/Drawing/IField.cs similarity index 94% rename from src/GreenshotPlugin/Interfaces/Drawing/IField.cs rename to src/Greenshot.Base/Interfaces/Drawing/IField.cs index f241e6a53..a848fa7d7 100644 --- a/src/GreenshotPlugin/Interfaces/Drawing/IField.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IField.cs @@ -1,65 +1,65 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.ComponentModel; - -namespace GreenshotPlugin.Interfaces.Drawing -{ - [Flags] - public enum FieldFlag - { - NONE = 0, - CONFIRMABLE = 1, - COUNTER = 2 - } - - public interface IFieldType - { - string Name { get; set; } - } - - public interface IField : INotifyPropertyChanged - { - object Value { get; set; } - IFieldType FieldType { get; set; } - string Scope { get; set; } - bool HasValue { get; } - } - - /// - /// EventHandler to be used when a field value changes - /// - public delegate void FieldChangedEventHandler(object sender, FieldChangedEventArgs e); - - /// - /// EventArgs to be used with FieldChangedEventHandler - /// - public class FieldChangedEventArgs : EventArgs - { - public IField Field { get; private set; } - - public FieldChangedEventArgs(IField field) - { - Field = field; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; + +namespace Greenshot.Base.Interfaces.Drawing +{ + [Flags] + public enum FieldFlag + { + NONE = 0, + CONFIRMABLE = 1, + COUNTER = 2 + } + + public interface IFieldType + { + string Name { get; set; } + } + + public interface IField : INotifyPropertyChanged + { + object Value { get; set; } + IFieldType FieldType { get; set; } + string Scope { get; set; } + bool HasValue { get; } + } + + /// + /// EventHandler to be used when a field value changes + /// + public delegate void FieldChangedEventHandler(object sender, FieldChangedEventArgs e); + + /// + /// EventArgs to be used with FieldChangedEventHandler + /// + public class FieldChangedEventArgs : EventArgs + { + public IField Field { get; private set; } + + public FieldChangedEventArgs(IField field) + { + Field = field; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs b/src/Greenshot.Base/Interfaces/Drawing/IFieldholder.cs similarity index 94% rename from src/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs rename to src/Greenshot.Base/Interfaces/Drawing/IFieldholder.cs index 9cc046b82..7d2a11adb 100644 --- a/src/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IFieldholder.cs @@ -1,39 +1,39 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace GreenshotPlugin.Interfaces.Drawing -{ - /// - /// Any element holding Fields must provide access to it. - /// AbstractFieldHolder is the basic implementation. - /// If you need the fieldHolder to have child fieldHolders, - /// you should consider using IFieldHolderWithChildren. - /// - public interface IFieldHolder - { - event FieldChangedEventHandler FieldChanged; - IList GetFields(); - IField GetField(IFieldType fieldType); - bool HasField(IFieldType fieldType); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; + +namespace Greenshot.Base.Interfaces.Drawing +{ + /// + /// Any element holding Fields must provide access to it. + /// AbstractFieldHolder is the basic implementation. + /// If you need the fieldHolder to have child fieldHolders, + /// you should consider using IFieldHolderWithChildren. + /// + public interface IFieldHolder + { + event FieldChangedEventHandler FieldChanged; + IList GetFields(); + IField GetField(IFieldType fieldType); + bool HasField(IFieldType fieldType); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Drawing/IMemento.cs b/src/Greenshot.Base/Interfaces/Drawing/IMemento.cs similarity index 94% rename from src/GreenshotPlugin/Interfaces/Drawing/IMemento.cs rename to src/Greenshot.Base/Interfaces/Drawing/IMemento.cs index cc5a357f3..1d8e425c4 100644 --- a/src/GreenshotPlugin/Interfaces/Drawing/IMemento.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IMemento.cs @@ -1,46 +1,46 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.Interfaces.Drawing -{ - /// - /// Description of IMemento. - /// - public interface IMemento : IDisposable - { - /// - /// Restores target to the state memorized by this memento. - /// - /// - /// A memento of the state before restoring - /// - IMemento Restore(); - - /// - /// Try to merge the current memento with another, preventing loads of items on the stack - /// - /// The memento to try to merge with - /// - bool Merge(IMemento other); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Interfaces.Drawing +{ + /// + /// Description of IMemento. + /// + public interface IMemento : IDisposable + { + /// + /// Restores target to the state memorized by this memento. + /// + /// + /// A memento of the state before restoring + /// + IMemento Restore(); + + /// + /// Try to merge the current memento with another, preventing loads of items on the stack + /// + /// The memento to try to merge with + /// + bool Merge(IMemento other); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/DrawingModes.cs b/src/Greenshot.Base/Interfaces/DrawingModes.cs similarity index 96% rename from src/GreenshotPlugin/Interfaces/DrawingModes.cs rename to src/Greenshot.Base/Interfaces/DrawingModes.cs index e6d25a359..cc5e91607 100644 --- a/src/GreenshotPlugin/Interfaces/DrawingModes.cs +++ b/src/Greenshot.Base/Interfaces/DrawingModes.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public enum DrawingModes { diff --git a/src/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs b/src/Greenshot.Base/Interfaces/Forms/ImageEditor.cs similarity index 95% rename from src/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs rename to src/Greenshot.Base/Interfaces/Forms/ImageEditor.cs index 912f2987d..617a469de 100644 --- a/src/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs +++ b/src/Greenshot.Base/Interfaces/Forms/ImageEditor.cs @@ -1,46 +1,46 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; - -namespace GreenshotPlugin.Interfaces.Forms -{ - /// - /// The IImageEditor is the Interface that the Greenshot ImageEditor has to implement - /// - public interface IImageEditor - { - /// - /// Get the current Image from the Editor for Exporting (save/upload etc) - /// This is actually a wrapper which calls Surface.GetImageForExport(). - /// Don't forget to call image.Dispose() when finished!!! - /// - /// Bitmap - Image GetImageForExport(); - - /// - /// Make the ICaptureDetails from the current Surface in the EditorForm available. - /// - ICaptureDetails CaptureDetails { get; } - - ISurface Surface { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; + +namespace Greenshot.Base.Interfaces.Forms +{ + /// + /// The IImageEditor is the Interface that the Greenshot ImageEditor has to implement + /// + public interface IImageEditor + { + /// + /// Get the current Image from the Editor for Exporting (save/upload etc) + /// This is actually a wrapper which calls Surface.GetImageForExport(). + /// Don't forget to call image.Dispose() when finished!!! + /// + /// Bitmap + Image GetImageForExport(); + + /// + /// Make the ICaptureDetails from the current Surface in the EditorForm available. + /// + ICaptureDetails CaptureDetails { get; } + + ISurface Surface { get; set; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/ICapture.cs b/src/Greenshot.Base/Interfaces/ICapture.cs similarity index 98% rename from src/GreenshotPlugin/Interfaces/ICapture.cs rename to src/Greenshot.Base/Interfaces/ICapture.cs index 425d936de..f10d49b8b 100644 --- a/src/GreenshotPlugin/Interfaces/ICapture.cs +++ b/src/Greenshot.Base/Interfaces/ICapture.cs @@ -22,7 +22,7 @@ using System; using System.Drawing; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { /// /// The interface to the Capture object, so Plugins can use it. diff --git a/src/GreenshotPlugin/Interfaces/ICaptureDetails.cs b/src/Greenshot.Base/Interfaces/ICaptureDetails.cs similarity index 97% rename from src/GreenshotPlugin/Interfaces/ICaptureDetails.cs rename to src/Greenshot.Base/Interfaces/ICaptureDetails.cs index 5001f7bd0..2dc49d4a7 100644 --- a/src/GreenshotPlugin/Interfaces/ICaptureDetails.cs +++ b/src/Greenshot.Base/Interfaces/ICaptureDetails.cs @@ -21,9 +21,9 @@ using System; using System.Collections.Generic; -using GreenshotPlugin.Interfaces.Ocr; +using Greenshot.Base.Interfaces.Ocr; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { /// /// Details for the capture, like the window title and date/time etc. diff --git a/src/GreenshotPlugin/Interfaces/IDestination.cs b/src/Greenshot.Base/Interfaces/IDestination.cs similarity index 96% rename from src/GreenshotPlugin/Interfaces/IDestination.cs rename to src/Greenshot.Base/Interfaces/IDestination.cs index d57244c69..0e60d04b4 100644 --- a/src/GreenshotPlugin/Interfaces/IDestination.cs +++ b/src/Greenshot.Base/Interfaces/IDestination.cs @@ -1,131 +1,131 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Windows.Forms; - -namespace GreenshotPlugin.Interfaces -{ - public class ExportInformation - { - public ExportInformation(string destinationDesignation, string destinationDescription) - { - DestinationDesignation = destinationDesignation; - DestinationDescription = destinationDescription; - } - - public ExportInformation(string destinationDesignation, string destinationDescription, bool exportMade) : this(destinationDesignation, destinationDescription) - { - ExportMade = exportMade; - } - - public string DestinationDesignation { get; } - - public string DestinationDescription { get; set; } - - /// - /// Set to true to specify if the export worked. - /// - public bool ExportMade { get; set; } - - public string Uri { get; set; } - - public string ErrorMessage { get; set; } - - public string Filepath { get; set; } - } - - /// - /// Description of IDestination. - /// - public interface IDestination : IDisposable, IComparable - { - /// - /// Simple "designation" like "File", "Editor" etc, used to store the configuration - /// - string Designation { get; } - - /// - /// Description which will be shown in the settings form, destination picker etc - /// - string Description { get; } - - /// - /// Priority, used for sorting - /// - int Priority { get; } - - /// - /// Gets an icon for the destination - /// - Image DisplayIcon { get; } - - /// - /// Returns if the destination is active - /// - bool IsActive { get; } - - /// - /// Return a menu item - /// - /// Resolve the dynamic destinations too? - /// The menu for which the item is created - /// Handler which is called when clicked - /// ToolStripMenuItem - ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler); - - /// - /// Gets the ShortcutKeys for the Editor - /// - Keys EditorShortcutKeys { get; } - - /// - /// Gets the dynamic destinations - /// - IEnumerable DynamicDestinations(); - - /// - /// Returns true if this destination can be dynamic - /// - bool IsDynamic { get; } - - /// - /// Returns if the destination is active - /// - bool UseDynamicsOnly { get; } - - /// - /// Returns true if this destination returns a link - /// - bool IsLinkable { get; } - - /// - /// If a capture is made, and the destination is enabled, this method is called. - /// - /// true if the user selected this destination from a GUI, false if it was called as part of a process - /// - /// - /// DestinationExportInformation with information, like if the destination has "exported" the capture - ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +namespace Greenshot.Base.Interfaces +{ + public class ExportInformation + { + public ExportInformation(string destinationDesignation, string destinationDescription) + { + DestinationDesignation = destinationDesignation; + DestinationDescription = destinationDescription; + } + + public ExportInformation(string destinationDesignation, string destinationDescription, bool exportMade) : this(destinationDesignation, destinationDescription) + { + ExportMade = exportMade; + } + + public string DestinationDesignation { get; } + + public string DestinationDescription { get; set; } + + /// + /// Set to true to specify if the export worked. + /// + public bool ExportMade { get; set; } + + public string Uri { get; set; } + + public string ErrorMessage { get; set; } + + public string Filepath { get; set; } + } + + /// + /// Description of IDestination. + /// + public interface IDestination : IDisposable, IComparable + { + /// + /// Simple "designation" like "File", "Editor" etc, used to store the configuration + /// + string Designation { get; } + + /// + /// Description which will be shown in the settings form, destination picker etc + /// + string Description { get; } + + /// + /// Priority, used for sorting + /// + int Priority { get; } + + /// + /// Gets an icon for the destination + /// + Image DisplayIcon { get; } + + /// + /// Returns if the destination is active + /// + bool IsActive { get; } + + /// + /// Return a menu item + /// + /// Resolve the dynamic destinations too? + /// The menu for which the item is created + /// Handler which is called when clicked + /// ToolStripMenuItem + ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler); + + /// + /// Gets the ShortcutKeys for the Editor + /// + Keys EditorShortcutKeys { get; } + + /// + /// Gets the dynamic destinations + /// + IEnumerable DynamicDestinations(); + + /// + /// Returns true if this destination can be dynamic + /// + bool IsDynamic { get; } + + /// + /// Returns if the destination is active + /// + bool UseDynamicsOnly { get; } + + /// + /// Returns true if this destination returns a link + /// + bool IsLinkable { get; } + + /// + /// If a capture is made, and the destination is enabled, this method is called. + /// + /// true if the user selected this destination from a GUI, false if it was called as part of a process + /// + /// + /// DestinationExportInformation with information, like if the destination has "exported" the capture + ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/INotificationService.cs b/src/Greenshot.Base/Interfaces/INotificationService.cs similarity index 98% rename from src/GreenshotPlugin/Interfaces/INotificationService.cs rename to src/Greenshot.Base/Interfaces/INotificationService.cs index 43980a8e2..c4b47849d 100644 --- a/src/GreenshotPlugin/Interfaces/INotificationService.cs +++ b/src/Greenshot.Base/Interfaces/INotificationService.cs @@ -21,7 +21,7 @@ using System; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { /// /// This is the interface for the different notification service implementations diff --git a/src/GreenshotPlugin/Interfaces/IProcessor.cs b/src/Greenshot.Base/Interfaces/IProcessor.cs similarity index 95% rename from src/GreenshotPlugin/Interfaces/IProcessor.cs rename to src/Greenshot.Base/Interfaces/IProcessor.cs index 1e8d8a9eb..47216bbbc 100644 --- a/src/GreenshotPlugin/Interfaces/IProcessor.cs +++ b/src/Greenshot.Base/Interfaces/IProcessor.cs @@ -1,59 +1,59 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.Interfaces -{ - /// - /// Description of IProcessor. - /// - public interface IProcessor : IDisposable, IComparable - { - /// - /// Simple "designation" like "FixTitle" - /// - string Designation { get; } - - /// - /// Description which will be shown in the settings form, destination picker etc - /// - string Description { get; } - - /// - /// Priority, used for sorting - /// - int Priority { get; } - - /// - /// Returns if the destination is active - /// - bool isActive { get; } - - /// - /// If a capture is made, and the destination is enabled, this method is called. - /// - /// - /// - /// true if the processor has "processed" the capture - bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Interfaces +{ + /// + /// Description of IProcessor. + /// + public interface IProcessor : IDisposable, IComparable + { + /// + /// Simple "designation" like "FixTitle" + /// + string Designation { get; } + + /// + /// Description which will be shown in the settings form, destination picker etc + /// + string Description { get; } + + /// + /// Priority, used for sorting + /// + int Priority { get; } + + /// + /// Returns if the destination is active + /// + bool isActive { get; } + + /// + /// If a capture is made, and the destination is enabled, this method is called. + /// + /// + /// + /// true if the processor has "processed" the capture + bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/IServiceLocator.cs b/src/Greenshot.Base/Interfaces/IServiceLocator.cs similarity index 86% rename from src/GreenshotPlugin/Interfaces/IServiceLocator.cs rename to src/Greenshot.Base/Interfaces/IServiceLocator.cs index 10de96ff8..cd107e707 100644 --- a/src/GreenshotPlugin/Interfaces/IServiceLocator.cs +++ b/src/Greenshot.Base/Interfaces/IServiceLocator.cs @@ -1,14 +1,14 @@ -using System.Collections.Generic; - -namespace GreenshotPlugin.Interfaces -{ - public interface IServiceLocator - { - IEnumerable GetAllInstances(); - TService GetInstance(); - - void AddService(params TService[] services); - - void AddService(IEnumerable services); - } +using System.Collections.Generic; + +namespace Greenshot.Base.Interfaces +{ + public interface IServiceLocator + { + IEnumerable GetAllInstances(); + TService GetInstance(); + + void AddService(params TService[] services); + + void AddService(IEnumerable services); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/ISurface.cs b/src/Greenshot.Base/Interfaces/ISurface.cs similarity index 98% rename from src/GreenshotPlugin/Interfaces/ISurface.cs rename to src/Greenshot.Base/Interfaces/ISurface.cs index 51815f580..254d6304f 100644 --- a/src/GreenshotPlugin/Interfaces/ISurface.cs +++ b/src/Greenshot.Base/Interfaces/ISurface.cs @@ -23,11 +23,11 @@ using System; using System.Drawing; using System.IO; using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Effects; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; +using Greenshot.Base.Interfaces.Drawing; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { /// /// The interface to the Surface object, so Plugins can use it. diff --git a/src/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs b/src/Greenshot.Base/Interfaces/Ocr/IOcrProvider.cs similarity index 97% rename from src/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs rename to src/Greenshot.Base/Interfaces/Ocr/IOcrProvider.cs index a70c661c0..09928dbe7 100644 --- a/src/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/IOcrProvider.cs @@ -22,7 +22,7 @@ using System.Drawing; using System.Threading.Tasks; -namespace GreenshotPlugin.Interfaces.Ocr +namespace Greenshot.Base.Interfaces.Ocr { /// /// This interface describes something that can do OCR of a bitmap diff --git a/src/GreenshotPlugin/Interfaces/Ocr/Line.cs b/src/Greenshot.Base/Interfaces/Ocr/Line.cs similarity index 98% rename from src/GreenshotPlugin/Interfaces/Ocr/Line.cs rename to src/Greenshot.Base/Interfaces/Ocr/Line.cs index b00e5a957..fc21f72ae 100644 --- a/src/GreenshotPlugin/Interfaces/Ocr/Line.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/Line.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace GreenshotPlugin.Interfaces.Ocr +namespace Greenshot.Base.Interfaces.Ocr { /// /// Describes a line of words diff --git a/src/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs b/src/Greenshot.Base/Interfaces/Ocr/OcrInformation.cs similarity index 93% rename from src/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs rename to src/Greenshot.Base/Interfaces/Ocr/OcrInformation.cs index f1dd829ff..d7cb82559 100644 --- a/src/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/OcrInformation.cs @@ -1,53 +1,53 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace GreenshotPlugin.Interfaces.Ocr -{ - /// - /// Contains all the information on the OCR result - /// - public class OcrInformation - { - /// - /// Check if there is any content - /// - public bool HasContent => Lines.Any(); - - /// - /// The complete text - /// - public string Text - { - get - { - // Build the text from the lines, otherwise it's just everything concatenated together - var text = new StringBuilder(); - foreach (var line in Lines) - { - text.AppendLine(line.Text); - } - - return text.ToString(); - } - } - - /// - /// The lines of test which the OCR engine found - /// - public IList Lines { get; } = new List(); - - /// - /// Change the offset of the - /// - /// int - /// int - public void Offset(int x, int y) - { - foreach (var line in Lines) - { - line.Offset(x, y); - } - } - } +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Greenshot.Base.Interfaces.Ocr +{ + /// + /// Contains all the information on the OCR result + /// + public class OcrInformation + { + /// + /// Check if there is any content + /// + public bool HasContent => Lines.Any(); + + /// + /// The complete text + /// + public string Text + { + get + { + // Build the text from the lines, otherwise it's just everything concatenated together + var text = new StringBuilder(); + foreach (var line in Lines) + { + text.AppendLine(line.Text); + } + + return text.ToString(); + } + } + + /// + /// The lines of test which the OCR engine found + /// + public IList Lines { get; } = new List(); + + /// + /// Change the offset of the + /// + /// int + /// int + public void Offset(int x, int y) + { + foreach (var line in Lines) + { + line.Offset(x, y); + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Ocr/Word.cs b/src/Greenshot.Base/Interfaces/Ocr/Word.cs similarity index 90% rename from src/GreenshotPlugin/Interfaces/Ocr/Word.cs rename to src/Greenshot.Base/Interfaces/Ocr/Word.cs index 30982caa4..467b5278b 100644 --- a/src/GreenshotPlugin/Interfaces/Ocr/Word.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/Word.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace GreenshotPlugin.Interfaces.Ocr +namespace Greenshot.Base.Interfaces.Ocr { /// /// Contains the information about a word diff --git a/src/Greenshot.Base/Interfaces/Plugin/HotKeyHandler.cs b/src/Greenshot.Base/Interfaces/Plugin/HotKeyHandler.cs new file mode 100644 index 000000000..db59840e2 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Plugin/HotKeyHandler.cs @@ -0,0 +1,4 @@ +namespace Greenshot.Base.Interfaces.Plugin +{ + public delegate void HotKeyHandler(); +} \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs b/src/Greenshot.Base/Interfaces/Plugin/IGreenshotHost.cs similarity index 95% rename from src/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs rename to src/Greenshot.Base/Interfaces/Plugin/IGreenshotHost.cs index fc362436d..5c8457178 100644 --- a/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs +++ b/src/Greenshot.Base/Interfaces/Plugin/IGreenshotHost.cs @@ -1,49 +1,49 @@ -using System.Drawing; - -namespace GreenshotPlugin.Interfaces.Plugin -{ - /// - /// This interface is the GreenshotPluginHost, that which "Hosts" the plugin. - /// For Greenshot this is implemented in the PluginHelper - /// - public interface IGreenshotHost - { - /// - /// Create a Thumbnail - /// - /// Image of which we need a Thumbnail - /// - /// - /// Image with Thumbnail - Image GetThumbnail(Image image, int width, int height); - - /// - /// Export a surface to the destination with has the supplied designation - /// - /// - /// - /// - /// - ExportInformation ExportCapture(bool manuallyInitiated, string designation, ISurface surface, ICaptureDetails captureDetails); - - /// - /// Make region capture with specified Handler - /// - /// bool false if the mouse should not be captured, true if the configuration should be checked - /// IDestination destination - void CaptureRegion(bool captureMouseCursor, IDestination destination); - - /// - /// Use the supplied capture, and handle it as if it's captured. - /// - /// ICapture to import - void ImportCapture(ICapture captureToImport); - - /// - /// Use the supplied image, and ICapture a capture object for it - /// - /// Image to create capture for - /// ICapture - ICapture GetCapture(Image imageToCapture); - } +using System.Drawing; + +namespace Greenshot.Base.Interfaces.Plugin +{ + /// + /// This interface is the GreenshotPluginHost, that which "Hosts" the plugin. + /// For Greenshot this is implemented in the PluginHelper + /// + public interface IGreenshotHost + { + /// + /// Create a Thumbnail + /// + /// Image of which we need a Thumbnail + /// + /// + /// Image with Thumbnail + Image GetThumbnail(Image image, int width, int height); + + /// + /// Export a surface to the destination with has the supplied designation + /// + /// + /// + /// + /// + ExportInformation ExportCapture(bool manuallyInitiated, string designation, ISurface surface, ICaptureDetails captureDetails); + + /// + /// Make region capture with specified Handler + /// + /// bool false if the mouse should not be captured, true if the configuration should be checked + /// IDestination destination + void CaptureRegion(bool captureMouseCursor, IDestination destination); + + /// + /// Use the supplied capture, and handle it as if it's captured. + /// + /// ICapture to import + void ImportCapture(ICapture captureToImport); + + /// + /// Use the supplied image, and ICapture a capture object for it + /// + /// Image to create capture for + /// ICapture + ICapture GetCapture(Image imageToCapture); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs b/src/Greenshot.Base/Interfaces/Plugin/IGreenshotPlugin.cs similarity index 91% rename from src/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs rename to src/Greenshot.Base/Interfaces/Plugin/IGreenshotPlugin.cs index b7863e231..b61f49f44 100644 --- a/src/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs +++ b/src/Greenshot.Base/Interfaces/Plugin/IGreenshotPlugin.cs @@ -1,26 +1,26 @@ -using System; - -namespace GreenshotPlugin.Interfaces.Plugin -{ - /// - /// This defines the plugin - /// - public interface IGreenshotPlugin : IDisposable - { - /// - /// Is called after the plugin is instantiated, the Plugin should keep a copy of the host and pluginAttribute. - /// - /// true if plugin is initialized, false if not (doesn't show) - bool Initialize(); - - /// - /// Unload of the plugin - /// - void Shutdown(); - - /// - /// Open the Configuration Form, will/should not be called before handshaking is done - /// - void Configure(); - } +using System; + +namespace Greenshot.Base.Interfaces.Plugin +{ + /// + /// This defines the plugin + /// + public interface IGreenshotPlugin : IDisposable + { + /// + /// Is called after the plugin is instantiated, the Plugin should keep a copy of the host and pluginAttribute. + /// + /// true if plugin is initialized, false if not (doesn't show) + bool Initialize(); + + /// + /// Unload of the plugin + /// + void Shutdown(); + + /// + /// Open the Configuration Form, will/should not be called before handshaking is done + /// + void Configure(); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs b/src/Greenshot.Base/Interfaces/Plugin/PluginAttribute.cs similarity index 94% rename from src/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs rename to src/Greenshot.Base/Interfaces/Plugin/PluginAttribute.cs index 02f0ee14b..f0f66949a 100644 --- a/src/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs +++ b/src/Greenshot.Base/Interfaces/Plugin/PluginAttribute.cs @@ -1,50 +1,50 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.Interfaces.Plugin -{ - [Serializable] - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] - public sealed class PluginAttribute : Attribute, IComparable - { - public string Name { get; set; } - - public bool Configurable { get; private set; } - - public PluginAttribute(string name, bool configurable) - { - Name = name; - Configurable = configurable; - } - - public int CompareTo(object obj) - { - if (obj is PluginAttribute other) - { - return string.Compare(Name, other.Name, StringComparison.Ordinal); - } - - throw new ArgumentException("object is not a PluginAttribute"); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Interfaces.Plugin +{ + [Serializable] + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public sealed class PluginAttribute : Attribute, IComparable + { + public string Name { get; set; } + + public bool Configurable { get; private set; } + + public PluginAttribute(string name, bool configurable) + { + Name = name; + Configurable = configurable; + } + + public int CompareTo(object obj) + { + if (obj is PluginAttribute other) + { + return string.Compare(Name, other.Name, StringComparison.Ordinal); + } + + throw new ArgumentException("object is not a PluginAttribute"); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs b/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs similarity index 92% rename from src/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs rename to src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs index cf77c866b..82946acdd 100644 --- a/src/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs +++ b/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs @@ -1,91 +1,91 @@ -using System.Collections.Generic; -using GreenshotPlugin.Core; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; - -namespace GreenshotPlugin.Interfaces.Plugin -{ - public class SurfaceOutputSettings - { - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private bool _reduceColors; - private bool _disableReduceColors; - - public SurfaceOutputSettings() - { - _disableReduceColors = false; - Format = CoreConfig.OutputFileFormat; - JPGQuality = CoreConfig.OutputFileJpegQuality; - ReduceColors = CoreConfig.OutputFileReduceColors; - } - - public SurfaceOutputSettings(OutputFormat format) : this() - { - Format = format; - } - - public SurfaceOutputSettings(OutputFormat format, int quality) : this(format) - { - JPGQuality = quality; - } - - public SurfaceOutputSettings(OutputFormat format, int quality, bool reduceColors) : this(format, quality) - { - ReduceColors = reduceColors; - } - - /// - /// BUG-2056 reported a logical issue, using greenshot format as the default causes issues with the external commands. - /// - /// this for fluent API usage - public SurfaceOutputSettings PreventGreenshotFormat() - { - // If OutputFormat is Greenshot, use PNG instead. - if (Format == OutputFormat.greenshot) - { - Format = OutputFormat.png; - } - - return this; - } - - public OutputFormat Format { get; set; } - - public int JPGQuality { get; set; } - - public bool SaveBackgroundOnly { get; set; } - - public List Effects { get; } = new List(); - - public bool ReduceColors - { - get - { - // Fix for Bug #3468436, force quantizing when output format is gif as this has only 256 colors! - if (OutputFormat.gif.Equals(Format)) - { - return true; - } - - return _reduceColors; - } - set { _reduceColors = value; } - } - - /// - /// Disable the reduce colors option, this overrules the enabling - /// - public bool DisableReduceColors - { - get { return _disableReduceColors; } - set - { - // Quantizing os needed when output format is gif as this has only 256 colors! - if (!OutputFormat.gif.Equals(Format)) - { - _disableReduceColors = value; - } - } - } - } +using System.Collections.Generic; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; +using Greenshot.Base.IniFile; + +namespace Greenshot.Base.Interfaces.Plugin +{ + public class SurfaceOutputSettings + { + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private bool _reduceColors; + private bool _disableReduceColors; + + public SurfaceOutputSettings() + { + _disableReduceColors = false; + Format = CoreConfig.OutputFileFormat; + JPGQuality = CoreConfig.OutputFileJpegQuality; + ReduceColors = CoreConfig.OutputFileReduceColors; + } + + public SurfaceOutputSettings(OutputFormat format) : this() + { + Format = format; + } + + public SurfaceOutputSettings(OutputFormat format, int quality) : this(format) + { + JPGQuality = quality; + } + + public SurfaceOutputSettings(OutputFormat format, int quality, bool reduceColors) : this(format, quality) + { + ReduceColors = reduceColors; + } + + /// + /// BUG-2056 reported a logical issue, using greenshot format as the default causes issues with the external commands. + /// + /// this for fluent API usage + public SurfaceOutputSettings PreventGreenshotFormat() + { + // If OutputFormat is Greenshot, use PNG instead. + if (Format == OutputFormat.greenshot) + { + Format = OutputFormat.png; + } + + return this; + } + + public OutputFormat Format { get; set; } + + public int JPGQuality { get; set; } + + public bool SaveBackgroundOnly { get; set; } + + public List Effects { get; } = new List(); + + public bool ReduceColors + { + get + { + // Fix for Bug #3468436, force quantizing when output format is gif as this has only 256 colors! + if (OutputFormat.gif.Equals(Format)) + { + return true; + } + + return _reduceColors; + } + set { _reduceColors = value; } + } + + /// + /// Disable the reduce colors option, this overrules the enabling + /// + public bool DisableReduceColors + { + get { return _disableReduceColors; } + set + { + // Quantizing os needed when output format is gif as this has only 256 colors! + if (!OutputFormat.gif.Equals(Format)) + { + _disableReduceColors = value; + } + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs b/src/Greenshot.Base/Interfaces/ScreenCaptureMode.cs similarity index 96% rename from src/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs rename to src/Greenshot.Base/Interfaces/ScreenCaptureMode.cs index bdcc14d81..5481a58e5 100644 --- a/src/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs +++ b/src/Greenshot.Base/Interfaces/ScreenCaptureMode.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public enum ScreenCaptureMode { diff --git a/src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventArgs.cs similarity index 96% rename from src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs rename to src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventArgs.cs index c3abaa642..32ca381bb 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventArgs.cs @@ -21,7 +21,7 @@ using System; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public class SurfaceDrawingModeEventArgs : EventArgs { diff --git a/src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventHandler.cs similarity index 96% rename from src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs rename to src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventHandler.cs index 5582f77d3..d71508eea 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventHandler.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public delegate void SurfaceDrawingModeEventHandler(object sender, SurfaceDrawingModeEventArgs e); } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceElementEventArgs.cs similarity index 93% rename from src/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs rename to src/Greenshot.Base/Interfaces/SurfaceElementEventArgs.cs index 3212e8613..f081a6fd8 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceElementEventArgs.cs @@ -20,9 +20,9 @@ */ using System; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public class SurfaceElementEventArgs : EventArgs { diff --git a/src/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceElementEventHandler.cs similarity index 96% rename from src/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs rename to src/Greenshot.Base/Interfaces/SurfaceElementEventHandler.cs index eef546545..0d788d854 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceElementEventHandler.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public delegate void SurfaceElementEventHandler(object sender, SurfaceElementEventArgs e); } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceMessageEventArgs.cs similarity index 96% rename from src/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs rename to src/Greenshot.Base/Interfaces/SurfaceMessageEventArgs.cs index 783ce1277..5c2019385 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceMessageEventArgs.cs @@ -21,7 +21,7 @@ using System; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public class SurfaceMessageEventArgs : EventArgs { diff --git a/src/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceMessageEventHandler.cs similarity index 96% rename from src/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs rename to src/Greenshot.Base/Interfaces/SurfaceMessageEventHandler.cs index 1bea86b37..2fb9083ca 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceMessageEventHandler.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public delegate void SurfaceMessageEventHandler(object sender, SurfaceMessageEventArgs e); } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs b/src/Greenshot.Base/Interfaces/SurfaceMessageTyp.cs similarity index 96% rename from src/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs rename to src/Greenshot.Base/Interfaces/SurfaceMessageTyp.cs index 84efe7609..625dc7d36 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceMessageTyp.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public enum SurfaceMessageTyp { diff --git a/src/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceSizeChangeEventHandler.cs similarity index 96% rename from src/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs rename to src/Greenshot.Base/Interfaces/SurfaceSizeChangeEventHandler.cs index f9fe667f3..47d296074 100644 --- a/src/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceSizeChangeEventHandler.cs @@ -21,7 +21,7 @@ using System; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public delegate void SurfaceSizeChangeEventHandler(object sender, EventArgs e); } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/Base.cs b/src/Greenshot.Base/Interop/Base.cs similarity index 80% rename from src/GreenshotPlugin/Interop/Base.cs rename to src/Greenshot.Base/Interop/Base.cs index 117e5be59..ef4e5dfa0 100644 --- a/src/GreenshotPlugin/Interop/Base.cs +++ b/src/Greenshot.Base/Interop/Base.cs @@ -1,11 +1,11 @@ -using System; - -namespace GreenshotPlugin.Interop -{ - /// - /// Common properties that has appreared in almost all objects - /// - public interface ICommon : IDisposable - { - } +using System; + +namespace Greenshot.Base.Interop +{ + /// + /// Common properties that has appreared in almost all objects + /// + public interface ICommon : IDisposable + { + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/COMWrapper.cs b/src/Greenshot.Base/Interop/COMWrapper.cs similarity index 97% rename from src/GreenshotPlugin/Interop/COMWrapper.cs rename to src/Greenshot.Base/Interop/COMWrapper.cs index c215809b0..e33c7ee08 100644 --- a/src/GreenshotPlugin/Interop/COMWrapper.cs +++ b/src/Greenshot.Base/Interop/COMWrapper.cs @@ -1,621 +1,621 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.Remoting; -using System.Runtime.Remoting.Messaging; -using System.Runtime.Remoting.Proxies; -using System.Windows.Forms; -using GreenshotPlugin.Core; -using log4net; - -namespace GreenshotPlugin.Interop -{ - /// - /// Wraps a late-bound COM server. - /// - public sealed class COMWrapper : RealProxy, IDisposable, IRemotingTypeInfo - { - private static readonly ILog Log = LogManager.GetLogger(typeof(COMWrapper)); - public const int RPC_E_CALL_REJECTED = unchecked((int) 0x80010001); - public const int RPC_E_FAIL = unchecked((int) 0x80004005); - - /// - /// Holds reference to the actual COM object which is wrapped by this proxy - /// - private readonly object _comObject; - - /// - /// Type of the COM object, set on constructor after getting the COM reference - /// - private readonly Type _comType; - - /// - /// The type of which method calls are intercepted and executed on the COM object. - /// - private readonly Type _interceptType; - - /// - /// The humanly readable target name - /// - private readonly string _targetName; - - /// - /// A simple create instance, doesn't create a wrapper!! - /// - /// T - public static T CreateInstance() - { - Type type = typeof(T); - if (null == type) - { - throw new ArgumentNullException(nameof(T)); - } - - if (!type.IsInterface) - { - throw new ArgumentException("The specified type must be an interface.", nameof(T)); - } - - ComProgIdAttribute progIdAttribute = ComProgIdAttribute.GetAttribute(type); - if (string.IsNullOrEmpty(progIdAttribute?.Value)) - { - throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T)); - } - - string progId = progIdAttribute.Value; - Type comType = null; - if (progId.StartsWith("clsid:")) - { - Guid guid = new Guid(progId.Substring(6)); - try - { - comType = Type.GetTypeFromCLSID(guid); - } - catch (Exception ex) - { - Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); - } - } - else - { - try - { - comType = Type.GetTypeFromProgID(progId, true); - } - catch (Exception ex) - { - Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); - } - } - - object comObject = null; - if (comType != null) - { - try - { - comObject = Activator.CreateInstance(comType); - if (comObject != null) - { - Log.DebugFormat("Created new instance of {0} object.", progId); - } - } - catch (Exception e) - { - Log.WarnFormat("Error {1} creating object for {0}", progId, e.Message); - throw; - } - } - - if (comObject != null) - { - return (T) comObject; - } - - return default; - } - - /// - /// Wrap an object and return the transparent proxy which intercepts all calls to the object - /// - /// An object to intercept - /// Interface which defines the method and properties to intercept - /// - /// Transparent proxy to the real proxy for the object - private static object Wrap(object comObject, Type type, string targetName) - { - if (null == comObject) - { - throw new ArgumentNullException(nameof(comObject)); - } - - if (null == type) - { - throw new ArgumentNullException(nameof(type)); - } - - COMWrapper wrapper = new COMWrapper(comObject, type, targetName); - return wrapper.GetTransparentProxy(); - } - - /// - /// Constructor - /// - /// - /// The COM object to wrap. - /// - /// - /// The interface type to impersonate. - /// - /// - private COMWrapper(object comObject, Type type, string targetName) : base(type) - { - _comObject = comObject; - _comType = comObject.GetType(); - _interceptType = type; - _targetName = targetName; - } - - /// - /// If is not called, we need to make - /// sure that the COM object is still cleaned up. - /// - ~COMWrapper() - { - Log.DebugFormat("Finalize {0}", _interceptType); - Dispose(false); - } - - /// - /// Cleans up the COM object. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Release the COM reference - /// - /// - /// if this was called from the - /// interface. - /// - private void Dispose(bool disposing) - { - if (null != _comObject) - { - Log.DebugFormat("Disposing {0}", _interceptType); - if (Marshal.IsComObject(_comObject)) - { - try - { - int count; - do - { - count = Marshal.ReleaseComObject(_comObject); - Log.DebugFormat("RCW count for {0} now is {1}", _interceptType, count); - } while (count > 0); - } - catch (Exception ex) - { - Log.WarnFormat("Problem releasing COM object {0}", _comType); - Log.Warn("Error: ", ex); - } - } - else - { - Log.WarnFormat("{0} is not a COM object", _comType); - } - } - } - - /// - /// Returns a string representing the wrapped object. - /// - /// - /// The full name of the intercepted type. - /// - public override string ToString() - { - return _interceptType.FullName; - } - - /// - /// Returns the hash code of the wrapped object. - /// - /// - /// The hash code of the wrapped object. - /// - public override int GetHashCode() - { - return _comObject.GetHashCode(); - } - - /// - /// Compares this object to another. - /// - /// - /// The value to compare to. - /// - /// - /// if the objects are equal. - /// - public override bool Equals(object value) - { - if (null != value && RemotingServices.IsTransparentProxy(value)) - { - COMWrapper wrapper = RemotingServices.GetRealProxy(value) as COMWrapper; - if (null != wrapper) - { - return _comObject == wrapper._comObject; - } - } - - return base.Equals(value); - } - - /// - /// Returns the base type for a reference type. - /// - /// - /// The reference type. - /// - /// - /// The base value type. - /// - /// - /// is . - /// - private static Type GetByValType(Type byRefType) - { - if (null == byRefType) - { - throw new ArgumentNullException(nameof(byRefType)); - } - - if (byRefType.IsByRef) - { - string name = byRefType.FullName; - name = name.Substring(0, name.Length - 1); - byRefType = byRefType.Assembly.GetType(name, true); - } - - return byRefType; - } - - /// - /// Intercept method calls - /// - /// - /// Contains information about the method being called - /// - /// - /// A . - /// - public override IMessage Invoke(IMessage myMessage) - { - if (!(myMessage is IMethodCallMessage callMessage)) - { - Log.DebugFormat("Message type not implemented: {0}", myMessage.GetType()); - return null; - } - - MethodInfo method = callMessage.MethodBase as MethodInfo; - if (null == method) - { - Log.DebugFormat("Unrecognized Invoke call: {0}", callMessage.MethodBase); - return null; - } - - object returnValue = null; - object[] outArgs = null; - int outArgsCount = 0; - - string methodName = method.Name; - Type returnType = method.ReturnType; - BindingFlags flags = BindingFlags.InvokeMethod; - int argCount = callMessage.ArgCount; - - ParameterModifier[] argModifiers = null; - ParameterInfo[] parameters = null; - - if ("Dispose" == methodName && 0 == argCount && typeof(void) == returnType) - { - Dispose(); - } - else if ("ToString" == methodName && 0 == argCount && typeof(string) == returnType) - { - returnValue = ToString(); - } - else if ("GetType" == methodName && 0 == argCount && typeof(Type) == returnType) - { - returnValue = _interceptType; - } - else if ("GetHashCode" == methodName && 0 == argCount && typeof(int) == returnType) - { - returnValue = GetHashCode(); - } - else if ("Equals" == methodName && 1 == argCount && typeof(bool) == returnType) - { - returnValue = Equals(callMessage.Args[0]); - } - else if (1 == argCount && typeof(void) == returnType && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) - { - bool removeHandler = methodName.StartsWith("remove_"); - methodName = methodName.Substring(removeHandler ? 7 : 4); - // TODO: Something is missing here - if (!(callMessage.InArgs[0] is Delegate handler)) - { - return new ReturnMessage(new ArgumentNullException(nameof(handler)), callMessage); - } - } - else - { - var invokeObject = _comObject; - var invokeType = _comType; - - object[] args; - ParameterInfo parameter; - if (methodName.StartsWith("get_")) - { - // Property Get - methodName = methodName.Substring(4); - flags = BindingFlags.GetProperty; - args = callMessage.InArgs; - } - else if (methodName.StartsWith("set_")) - { - // Property Set - methodName = methodName.Substring(4); - flags = BindingFlags.SetProperty; - args = callMessage.InArgs; - } - else - { - args = callMessage.Args; - if (null != args && 0 != args.Length) - { - // Modifiers for ref / out parameters - argModifiers = new ParameterModifier[1]; - argModifiers[0] = new ParameterModifier(args.Length); - - parameters = method.GetParameters(); - for (int i = 0; i < parameters.Length; i++) - { - parameter = parameters[i]; - if (parameter.IsOut || parameter.ParameterType.IsByRef) - { - argModifiers[0][i] = true; - outArgsCount++; - } - } - - if (0 == outArgsCount) - { - argModifiers = null; - } - } - } - - // Un-wrap wrapped COM objects before passing to the method - Type byValType; - COMWrapper wrapper; - COMWrapper[] originalArgs; - if (null == args || 0 == args.Length) - { - originalArgs = null; - } - else - { - originalArgs = new COMWrapper[args.Length]; - for (int i = 0; i < args.Length; i++) - { - if (null != args[i] && RemotingServices.IsTransparentProxy(args[i])) - { - wrapper = RemotingServices.GetRealProxy(args[i]) as COMWrapper; - if (null != wrapper) - { - originalArgs[i] = wrapper; - args[i] = wrapper._comObject; - } - } - else if (0 != outArgsCount && argModifiers[0][i]) - { - byValType = GetByValType(parameters[i].ParameterType); - if (byValType.IsInterface) - { - // If we're passing a COM object by reference, and - // the parameter is null, we need to pass a - // DispatchWrapper to avoid a type mismatch exception. - if (null == args[i]) - { - args[i] = new DispatchWrapper(null); - } - } - else if (typeof(decimal) == byValType) - { - // If we're passing a decimal value by reference, - // we need to pass a CurrencyWrapper to avoid a - // type mismatch exception. - // http://support.microsoft.com/?kbid=837378 - args[i] = new CurrencyWrapper(args[i]); - } - } - } - } - - do - { - try - { - returnValue = invokeType.InvokeMember(methodName, flags, null, invokeObject, args, argModifiers, null, null); - break; - } - catch (InvalidComObjectException icoEx) - { - // Should assist BUG-1616 and others - Log.WarnFormat( - "COM object {0} has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.", - _interceptType.FullName); - return new ReturnMessage(icoEx, callMessage); - } - catch (Exception ex) - { - // Test for rejected - if (!(ex is COMException comEx)) - { - comEx = ex.InnerException as COMException; - } - - if (comEx != null && (comEx.ErrorCode == RPC_E_CALL_REJECTED || comEx.ErrorCode == RPC_E_FAIL)) - { - string destinationName = _targetName; - // Try to find a "catchy" name for the rejecting application - if (destinationName != null && destinationName.Contains(".")) - { - destinationName = destinationName.Substring(0, destinationName.IndexOf(".", StringComparison.Ordinal)); - } - - if (destinationName == null) - { - destinationName = _interceptType.FullName; - } - - var form = SimpleServiceProvider.Current.GetInstance(); - - DialogResult result = MessageBox.Show(form, Language.GetFormattedString("com_rejected", destinationName), Language.GetString("com_rejected_title"), - MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation); - if (result == DialogResult.OK) - { - continue; - } - } - - // Not rejected OR pressed cancel - return new ReturnMessage(ex, callMessage); - } - } while (true); - - // Handle enum and interface return types - if (null != returnValue) - { - if (returnType.IsInterface) - { - // Wrap the returned value in an intercepting COM wrapper - if (Marshal.IsComObject(returnValue)) - { - returnValue = Wrap(returnValue, returnType, _targetName); - } - } - else if (returnType.IsEnum) - { - // Convert to proper Enum type - returnValue = Enum.Parse(returnType, returnValue.ToString()); - } - } - - // Handle out args - if (0 != outArgsCount) - { - outArgs = new object[args.Length]; - for (int i = 0; i < parameters.Length; i++) - { - if (!argModifiers[0][i]) - { - continue; - } - - var arg = args[i]; - if (null == arg) - { - continue; - } - - parameter = parameters[i]; - wrapper = null; - - byValType = GetByValType(parameter.ParameterType); - if (typeof(decimal) == byValType) - { - if (arg is CurrencyWrapper) - { - arg = ((CurrencyWrapper) arg).WrappedObject; - } - } - else if (byValType.IsEnum) - { - arg = Enum.Parse(byValType, arg.ToString()); - } - else if (byValType.IsInterface) - { - if (Marshal.IsComObject(arg)) - { - wrapper = originalArgs[i]; - if (null != wrapper && wrapper._comObject != arg) - { - wrapper.Dispose(); - wrapper = null; - } - - if (null == wrapper) - { - wrapper = new COMWrapper(arg, byValType, _targetName); - } - - arg = wrapper.GetTransparentProxy(); - } - } - - outArgs[i] = arg; - } - } - } - - return new ReturnMessage(returnValue, outArgs, outArgsCount, callMessage.LogicalCallContext, callMessage); - } - - /// - /// Implementation for the interface IRemotingTypeInfo - /// This makes it possible to cast the COMWrapper - /// - /// Type to cast to - /// object to cast - /// - public bool CanCastTo(Type toType, object o) - { - bool returnValue = _interceptType.IsAssignableFrom(toType); - return returnValue; - } - - /// - /// Implementation for the interface IRemotingTypeInfo - /// - public string TypeName - { - get { throw new NotSupportedException(); } - set { throw new NotSupportedException(); } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Proxies; +using System.Windows.Forms; +using Greenshot.Base.Core; +using log4net; + +namespace Greenshot.Base.Interop +{ + /// + /// Wraps a late-bound COM server. + /// + public sealed class COMWrapper : RealProxy, IDisposable, IRemotingTypeInfo + { + private static readonly ILog Log = LogManager.GetLogger(typeof(COMWrapper)); + public const int RPC_E_CALL_REJECTED = unchecked((int) 0x80010001); + public const int RPC_E_FAIL = unchecked((int) 0x80004005); + + /// + /// Holds reference to the actual COM object which is wrapped by this proxy + /// + private readonly object _comObject; + + /// + /// Type of the COM object, set on constructor after getting the COM reference + /// + private readonly Type _comType; + + /// + /// The type of which method calls are intercepted and executed on the COM object. + /// + private readonly Type _interceptType; + + /// + /// The humanly readable target name + /// + private readonly string _targetName; + + /// + /// A simple create instance, doesn't create a wrapper!! + /// + /// T + public static T CreateInstance() + { + Type type = typeof(T); + if (null == type) + { + throw new ArgumentNullException(nameof(T)); + } + + if (!type.IsInterface) + { + throw new ArgumentException("The specified type must be an interface.", nameof(T)); + } + + ComProgIdAttribute progIdAttribute = ComProgIdAttribute.GetAttribute(type); + if (string.IsNullOrEmpty(progIdAttribute?.Value)) + { + throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T)); + } + + string progId = progIdAttribute.Value; + Type comType = null; + if (progId.StartsWith("clsid:")) + { + Guid guid = new Guid(progId.Substring(6)); + try + { + comType = Type.GetTypeFromCLSID(guid); + } + catch (Exception ex) + { + Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); + } + } + else + { + try + { + comType = Type.GetTypeFromProgID(progId, true); + } + catch (Exception ex) + { + Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); + } + } + + object comObject = null; + if (comType != null) + { + try + { + comObject = Activator.CreateInstance(comType); + if (comObject != null) + { + Log.DebugFormat("Created new instance of {0} object.", progId); + } + } + catch (Exception e) + { + Log.WarnFormat("Error {1} creating object for {0}", progId, e.Message); + throw; + } + } + + if (comObject != null) + { + return (T) comObject; + } + + return default; + } + + /// + /// Wrap an object and return the transparent proxy which intercepts all calls to the object + /// + /// An object to intercept + /// Interface which defines the method and properties to intercept + /// + /// Transparent proxy to the real proxy for the object + private static object Wrap(object comObject, Type type, string targetName) + { + if (null == comObject) + { + throw new ArgumentNullException(nameof(comObject)); + } + + if (null == type) + { + throw new ArgumentNullException(nameof(type)); + } + + COMWrapper wrapper = new COMWrapper(comObject, type, targetName); + return wrapper.GetTransparentProxy(); + } + + /// + /// Constructor + /// + /// + /// The COM object to wrap. + /// + /// + /// The interface type to impersonate. + /// + /// + private COMWrapper(object comObject, Type type, string targetName) : base(type) + { + _comObject = comObject; + _comType = comObject.GetType(); + _interceptType = type; + _targetName = targetName; + } + + /// + /// If is not called, we need to make + /// sure that the COM object is still cleaned up. + /// + ~COMWrapper() + { + Log.DebugFormat("Finalize {0}", _interceptType); + Dispose(false); + } + + /// + /// Cleans up the COM object. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Release the COM reference + /// + /// + /// if this was called from the + /// interface. + /// + private void Dispose(bool disposing) + { + if (null != _comObject) + { + Log.DebugFormat("Disposing {0}", _interceptType); + if (Marshal.IsComObject(_comObject)) + { + try + { + int count; + do + { + count = Marshal.ReleaseComObject(_comObject); + Log.DebugFormat("RCW count for {0} now is {1}", _interceptType, count); + } while (count > 0); + } + catch (Exception ex) + { + Log.WarnFormat("Problem releasing COM object {0}", _comType); + Log.Warn("Error: ", ex); + } + } + else + { + Log.WarnFormat("{0} is not a COM object", _comType); + } + } + } + + /// + /// Returns a string representing the wrapped object. + /// + /// + /// The full name of the intercepted type. + /// + public override string ToString() + { + return _interceptType.FullName; + } + + /// + /// Returns the hash code of the wrapped object. + /// + /// + /// The hash code of the wrapped object. + /// + public override int GetHashCode() + { + return _comObject.GetHashCode(); + } + + /// + /// Compares this object to another. + /// + /// + /// The value to compare to. + /// + /// + /// if the objects are equal. + /// + public override bool Equals(object value) + { + if (null != value && RemotingServices.IsTransparentProxy(value)) + { + COMWrapper wrapper = RemotingServices.GetRealProxy(value) as COMWrapper; + if (null != wrapper) + { + return _comObject == wrapper._comObject; + } + } + + return base.Equals(value); + } + + /// + /// Returns the base type for a reference type. + /// + /// + /// The reference type. + /// + /// + /// The base value type. + /// + /// + /// is . + /// + private static Type GetByValType(Type byRefType) + { + if (null == byRefType) + { + throw new ArgumentNullException(nameof(byRefType)); + } + + if (byRefType.IsByRef) + { + string name = byRefType.FullName; + name = name.Substring(0, name.Length - 1); + byRefType = byRefType.Assembly.GetType(name, true); + } + + return byRefType; + } + + /// + /// Intercept method calls + /// + /// + /// Contains information about the method being called + /// + /// + /// A . + /// + public override IMessage Invoke(IMessage myMessage) + { + if (!(myMessage is IMethodCallMessage callMessage)) + { + Log.DebugFormat("Message type not implemented: {0}", myMessage.GetType()); + return null; + } + + MethodInfo method = callMessage.MethodBase as MethodInfo; + if (null == method) + { + Log.DebugFormat("Unrecognized Invoke call: {0}", callMessage.MethodBase); + return null; + } + + object returnValue = null; + object[] outArgs = null; + int outArgsCount = 0; + + string methodName = method.Name; + Type returnType = method.ReturnType; + BindingFlags flags = BindingFlags.InvokeMethod; + int argCount = callMessage.ArgCount; + + ParameterModifier[] argModifiers = null; + ParameterInfo[] parameters = null; + + if ("Dispose" == methodName && 0 == argCount && typeof(void) == returnType) + { + Dispose(); + } + else if ("ToString" == methodName && 0 == argCount && typeof(string) == returnType) + { + returnValue = ToString(); + } + else if ("GetType" == methodName && 0 == argCount && typeof(Type) == returnType) + { + returnValue = _interceptType; + } + else if ("GetHashCode" == methodName && 0 == argCount && typeof(int) == returnType) + { + returnValue = GetHashCode(); + } + else if ("Equals" == methodName && 1 == argCount && typeof(bool) == returnType) + { + returnValue = Equals(callMessage.Args[0]); + } + else if (1 == argCount && typeof(void) == returnType && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) + { + bool removeHandler = methodName.StartsWith("remove_"); + methodName = methodName.Substring(removeHandler ? 7 : 4); + // TODO: Something is missing here + if (!(callMessage.InArgs[0] is Delegate handler)) + { + return new ReturnMessage(new ArgumentNullException(nameof(handler)), callMessage); + } + } + else + { + var invokeObject = _comObject; + var invokeType = _comType; + + object[] args; + ParameterInfo parameter; + if (methodName.StartsWith("get_")) + { + // Property Get + methodName = methodName.Substring(4); + flags = BindingFlags.GetProperty; + args = callMessage.InArgs; + } + else if (methodName.StartsWith("set_")) + { + // Property Set + methodName = methodName.Substring(4); + flags = BindingFlags.SetProperty; + args = callMessage.InArgs; + } + else + { + args = callMessage.Args; + if (null != args && 0 != args.Length) + { + // Modifiers for ref / out parameters + argModifiers = new ParameterModifier[1]; + argModifiers[0] = new ParameterModifier(args.Length); + + parameters = method.GetParameters(); + for (int i = 0; i < parameters.Length; i++) + { + parameter = parameters[i]; + if (parameter.IsOut || parameter.ParameterType.IsByRef) + { + argModifiers[0][i] = true; + outArgsCount++; + } + } + + if (0 == outArgsCount) + { + argModifiers = null; + } + } + } + + // Un-wrap wrapped COM objects before passing to the method + Type byValType; + COMWrapper wrapper; + COMWrapper[] originalArgs; + if (null == args || 0 == args.Length) + { + originalArgs = null; + } + else + { + originalArgs = new COMWrapper[args.Length]; + for (int i = 0; i < args.Length; i++) + { + if (null != args[i] && RemotingServices.IsTransparentProxy(args[i])) + { + wrapper = RemotingServices.GetRealProxy(args[i]) as COMWrapper; + if (null != wrapper) + { + originalArgs[i] = wrapper; + args[i] = wrapper._comObject; + } + } + else if (0 != outArgsCount && argModifiers[0][i]) + { + byValType = GetByValType(parameters[i].ParameterType); + if (byValType.IsInterface) + { + // If we're passing a COM object by reference, and + // the parameter is null, we need to pass a + // DispatchWrapper to avoid a type mismatch exception. + if (null == args[i]) + { + args[i] = new DispatchWrapper(null); + } + } + else if (typeof(decimal) == byValType) + { + // If we're passing a decimal value by reference, + // we need to pass a CurrencyWrapper to avoid a + // type mismatch exception. + // http://support.microsoft.com/?kbid=837378 + args[i] = new CurrencyWrapper(args[i]); + } + } + } + } + + do + { + try + { + returnValue = invokeType.InvokeMember(methodName, flags, null, invokeObject, args, argModifiers, null, null); + break; + } + catch (InvalidComObjectException icoEx) + { + // Should assist BUG-1616 and others + Log.WarnFormat( + "COM object {0} has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.", + _interceptType.FullName); + return new ReturnMessage(icoEx, callMessage); + } + catch (Exception ex) + { + // Test for rejected + if (!(ex is COMException comEx)) + { + comEx = ex.InnerException as COMException; + } + + if (comEx != null && (comEx.ErrorCode == RPC_E_CALL_REJECTED || comEx.ErrorCode == RPC_E_FAIL)) + { + string destinationName = _targetName; + // Try to find a "catchy" name for the rejecting application + if (destinationName != null && destinationName.Contains(".")) + { + destinationName = destinationName.Substring(0, destinationName.IndexOf(".", StringComparison.Ordinal)); + } + + if (destinationName == null) + { + destinationName = _interceptType.FullName; + } + + var form = SimpleServiceProvider.Current.GetInstance(); + + DialogResult result = MessageBox.Show(form, Language.GetFormattedString("com_rejected", destinationName), Language.GetString("com_rejected_title"), + MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation); + if (result == DialogResult.OK) + { + continue; + } + } + + // Not rejected OR pressed cancel + return new ReturnMessage(ex, callMessage); + } + } while (true); + + // Handle enum and interface return types + if (null != returnValue) + { + if (returnType.IsInterface) + { + // Wrap the returned value in an intercepting COM wrapper + if (Marshal.IsComObject(returnValue)) + { + returnValue = Wrap(returnValue, returnType, _targetName); + } + } + else if (returnType.IsEnum) + { + // Convert to proper Enum type + returnValue = Enum.Parse(returnType, returnValue.ToString()); + } + } + + // Handle out args + if (0 != outArgsCount) + { + outArgs = new object[args.Length]; + for (int i = 0; i < parameters.Length; i++) + { + if (!argModifiers[0][i]) + { + continue; + } + + var arg = args[i]; + if (null == arg) + { + continue; + } + + parameter = parameters[i]; + wrapper = null; + + byValType = GetByValType(parameter.ParameterType); + if (typeof(decimal) == byValType) + { + if (arg is CurrencyWrapper) + { + arg = ((CurrencyWrapper) arg).WrappedObject; + } + } + else if (byValType.IsEnum) + { + arg = Enum.Parse(byValType, arg.ToString()); + } + else if (byValType.IsInterface) + { + if (Marshal.IsComObject(arg)) + { + wrapper = originalArgs[i]; + if (null != wrapper && wrapper._comObject != arg) + { + wrapper.Dispose(); + wrapper = null; + } + + if (null == wrapper) + { + wrapper = new COMWrapper(arg, byValType, _targetName); + } + + arg = wrapper.GetTransparentProxy(); + } + } + + outArgs[i] = arg; + } + } + } + + return new ReturnMessage(returnValue, outArgs, outArgsCount, callMessage.LogicalCallContext, callMessage); + } + + /// + /// Implementation for the interface IRemotingTypeInfo + /// This makes it possible to cast the COMWrapper + /// + /// Type to cast to + /// object to cast + /// + public bool CanCastTo(Type toType, object o) + { + bool returnValue = _interceptType.IsAssignableFrom(toType); + return returnValue; + } + + /// + /// Implementation for the interface IRemotingTypeInfo + /// + public string TypeName + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/ComProgIdAttribute.cs b/src/Greenshot.Base/Interop/ComProgIdAttribute.cs similarity index 96% rename from src/GreenshotPlugin/Interop/ComProgIdAttribute.cs rename to src/Greenshot.Base/Interop/ComProgIdAttribute.cs index ecb782773..079bdd149 100644 --- a/src/GreenshotPlugin/Interop/ComProgIdAttribute.cs +++ b/src/Greenshot.Base/Interop/ComProgIdAttribute.cs @@ -1,88 +1,88 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.Interop -{ - /// - /// An attribute to specifiy the ProgID of the COM class to create. (As suggested by Kristen Wegner) - /// - [AttributeUsage(AttributeTargets.Interface)] - public sealed class ComProgIdAttribute : Attribute - { - /// - /// Extracts the attribute from the specified type. - /// - /// - /// The interface type. - /// - /// - /// The . - /// - /// - /// is . - /// - public static ComProgIdAttribute GetAttribute(Type interfaceType) - { - if (null == interfaceType) - { - throw new ArgumentNullException(nameof(interfaceType)); - } - - Type attributeType = typeof(ComProgIdAttribute); - object[] attributes = interfaceType.GetCustomAttributes(attributeType, false); - - if (0 == attributes.Length) - { - Type[] interfaces = interfaceType.GetInterfaces(); - foreach (Type t in interfaces) - { - interfaceType = t; - attributes = interfaceType.GetCustomAttributes(attributeType, false); - if (0 != attributes.Length) - { - break; - } - } - } - - if (0 == attributes.Length) - { - return null; - } - - return (ComProgIdAttribute) attributes[0]; - } - - /// Constructor - /// The COM ProgID. - public ComProgIdAttribute(string value) - { - Value = value; - } - - /// - /// Returns the COM ProgID - /// - public string Value { get; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Interop +{ + /// + /// An attribute to specifiy the ProgID of the COM class to create. (As suggested by Kristen Wegner) + /// + [AttributeUsage(AttributeTargets.Interface)] + public sealed class ComProgIdAttribute : Attribute + { + /// + /// Extracts the attribute from the specified type. + /// + /// + /// The interface type. + /// + /// + /// The . + /// + /// + /// is . + /// + public static ComProgIdAttribute GetAttribute(Type interfaceType) + { + if (null == interfaceType) + { + throw new ArgumentNullException(nameof(interfaceType)); + } + + Type attributeType = typeof(ComProgIdAttribute); + object[] attributes = interfaceType.GetCustomAttributes(attributeType, false); + + if (0 == attributes.Length) + { + Type[] interfaces = interfaceType.GetInterfaces(); + foreach (Type t in interfaces) + { + interfaceType = t; + attributes = interfaceType.GetCustomAttributes(attributeType, false); + if (0 != attributes.Length) + { + break; + } + } + } + + if (0 == attributes.Length) + { + return null; + } + + return (ComProgIdAttribute) attributes[0]; + } + + /// Constructor + /// The COM ProgID. + public ComProgIdAttribute(string value) + { + Value = value; + } + + /// + /// Returns the COM ProgID + /// + public string Value { get; } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IAppVisibility.cs b/src/Greenshot.Base/Interop/IAppVisibility.cs similarity index 95% rename from src/GreenshotPlugin/Interop/IAppVisibility.cs rename to src/Greenshot.Base/Interop/IAppVisibility.cs index f9fa6ed10..b0c392bae 100644 --- a/src/GreenshotPlugin/Interop/IAppVisibility.cs +++ b/src/Greenshot.Base/Interop/IAppVisibility.cs @@ -1,41 +1,41 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Interop -{ - // This is used for Windows 8 to see if the App Launcher is active - // See http://msdn.microsoft.com/en-us/library/windows/desktop/jj554119%28v=vs.85%29.aspx - [ComProgId("clsid:7E5FE3D9-985F-4908-91F9-EE19F9FD1514")] - [ComImport, Guid("2246EA2D-CAEA-4444-A3C4-6DE827E44313"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IAppVisibility - { - MONITOR_APP_VISIBILITY GetAppVisibilityOnMonitor(IntPtr hMonitor); - bool IsLauncherVisible { get; } - } - - public enum MONITOR_APP_VISIBILITY - { - MAV_APP_VISIBLE = 2 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Interop +{ + // This is used for Windows 8 to see if the App Launcher is active + // See http://msdn.microsoft.com/en-us/library/windows/desktop/jj554119%28v=vs.85%29.aspx + [ComProgId("clsid:7E5FE3D9-985F-4908-91F9-EE19F9FD1514")] + [ComImport, Guid("2246EA2D-CAEA-4444-A3C4-6DE827E44313"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IAppVisibility + { + MONITOR_APP_VISIBILITY GetAppVisibilityOnMonitor(IntPtr hMonitor); + bool IsLauncherVisible { get; } + } + + public enum MONITOR_APP_VISIBILITY + { + MAV_APP_VISIBLE = 2 + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IDispatch.cs b/src/Greenshot.Base/Interop/IDispatch.cs similarity index 96% rename from src/GreenshotPlugin/Interop/IDispatch.cs rename to src/Greenshot.Base/Interop/IDispatch.cs index 99edf0a87..5e7c0a563 100644 --- a/src/GreenshotPlugin/Interop/IDispatch.cs +++ b/src/Greenshot.Base/Interop/IDispatch.cs @@ -1,47 +1,47 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.CustomMarshalers; - -namespace GreenshotPlugin.Interop -{ - [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsDual)] - public interface IDispatch : IUnknown - { - [PreserveSig] - int GetTypeInfoCount(out int count); - - [PreserveSig] - int GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo, [MarshalAs(UnmanagedType.U4)] int lcid, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))] - out Type typeInfo); - - [PreserveSig] - int GetIDsOfNames(ref Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] - string[] rgsNames, int cNames, int lcid, [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId); - - [PreserveSig] - int Invoke(int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, - out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.CustomMarshalers; + +namespace Greenshot.Base.Interop +{ + [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsDual)] + public interface IDispatch : IUnknown + { + [PreserveSig] + int GetTypeInfoCount(out int count); + + [PreserveSig] + int GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo, [MarshalAs(UnmanagedType.U4)] int lcid, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))] + out Type typeInfo); + + [PreserveSig] + int GetIDsOfNames(ref Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] + string[] rgsNames, int cNames, int lcid, [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId); + + [PreserveSig] + int Invoke(int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, + out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IOleCommandTarget.cs b/src/Greenshot.Base/Interop/IOleCommandTarget.cs similarity index 95% rename from src/GreenshotPlugin/Interop/IOleCommandTarget.cs rename to src/Greenshot.Base/Interop/IOleCommandTarget.cs index 7e41c51e6..5903bda58 100644 --- a/src/GreenshotPlugin/Interop/IOleCommandTarget.cs +++ b/src/Greenshot.Base/Interop/IOleCommandTarget.cs @@ -1,40 +1,40 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Interop -{ - [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(true), Guid("B722BCCB-4E68-101B-A2BC-00AA00404770")] - public interface IOleCommandTarget - { - [return: MarshalAs(UnmanagedType.I4)] - [PreserveSig] - int QueryStatus([In, MarshalAs(UnmanagedType.LPStruct)] - Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText); - - [return: MarshalAs(UnmanagedType.I4)] - [PreserveSig] - int Exec([In, MarshalAs(UnmanagedType.LPStruct)] - Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Interop +{ + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(true), Guid("B722BCCB-4E68-101B-A2BC-00AA00404770")] + public interface IOleCommandTarget + { + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int QueryStatus([In, MarshalAs(UnmanagedType.LPStruct)] + Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText); + + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int Exec([In, MarshalAs(UnmanagedType.LPStruct)] + Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IOleWindow.cs b/src/Greenshot.Base/Interop/IOleWindow.cs similarity index 95% rename from src/GreenshotPlugin/Interop/IOleWindow.cs rename to src/Greenshot.Base/Interop/IOleWindow.cs index b746dc74d..adefc15ef 100644 --- a/src/GreenshotPlugin/Interop/IOleWindow.cs +++ b/src/Greenshot.Base/Interop/IOleWindow.cs @@ -1,35 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Interop -{ - // Needed to get the Window handle from the IDocument2 - // See: http://msdn.microsoft.com/en-us/library/ms680102%28v=vs.85%29.aspx - [ComImport, Guid("00000114-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IOleWindow - { - void GetWindow(out IntPtr phWnd); - void ContextSensitiveHelp([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Interop +{ + // Needed to get the Window handle from the IDocument2 + // See: http://msdn.microsoft.com/en-us/library/ms680102%28v=vs.85%29.aspx + [ComImport, Guid("00000114-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IOleWindow + { + void GetWindow(out IntPtr phWnd); + void ContextSensitiveHelp([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IServiceProvider.cs b/src/Greenshot.Base/Interop/IServiceProvider.cs similarity index 95% rename from src/GreenshotPlugin/Interop/IServiceProvider.cs rename to src/Greenshot.Base/Interop/IServiceProvider.cs index 9b15b78d5..423541e5e 100644 --- a/src/GreenshotPlugin/Interop/IServiceProvider.cs +++ b/src/Greenshot.Base/Interop/IServiceProvider.cs @@ -1,36 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Interop -{ - // This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface! - [ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IServiceProvider - { - [return: MarshalAs(UnmanagedType.I4)] - [PreserveSig] - int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Interop +{ + // This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface! + [ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IServiceProvider + { + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/Interop/IUnknown.cs b/src/Greenshot.Base/Interop/IUnknown.cs similarity index 94% rename from src/GreenshotPlugin/Interop/IUnknown.cs rename to src/Greenshot.Base/Interop/IUnknown.cs index d7cccb743..bdffb0bf9 100644 --- a/src/GreenshotPlugin/Interop/IUnknown.cs +++ b/src/Greenshot.Base/Interop/IUnknown.cs @@ -1,38 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Interop -{ - [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000000-0000-0000-C000-000000000046")] - public interface IUnknown - { - IntPtr QueryInterface(ref Guid riid); - - [PreserveSig] - uint AddRef(); - - [PreserveSig] - uint Release(); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Interop +{ + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000000-0000-0000-C000-000000000046")] + public interface IUnknown + { + IntPtr QueryInterface(ref Guid riid); + + [PreserveSig] + uint AddRef(); + + [PreserveSig] + uint Release(); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/DWM.cs b/src/Greenshot.Base/UnmanagedHelpers/DWM.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/DWM.cs rename to src/Greenshot.Base/UnmanagedHelpers/DWM.cs index 9e7737289..cf5a2c056 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/DWM.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/DWM.cs @@ -1,123 +1,123 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.Enums; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; -using Microsoft.Win32; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// Desktop Window Manager helper code - /// - public static class DWM - { - // DWM - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb); - - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmUnregisterThumbnail(IntPtr thumb); - - [DllImport("dwmapi", SetLastError = true)] - public static extern HResult DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size); - - [DllImport("dwmapi", SetLastError = true)] - public static extern HResult DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); - - // Deprecated as of Windows 8 Release Preview - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmIsCompositionEnabled(out bool enabled); - - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT lpRect, int size); - - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool pvAttribute, int cbAttribute); - - // Key to ColorizationColor for DWM - private const string COLORIZATION_COLOR_KEY = @"SOFTWARE\Microsoft\Windows\DWM"; - - /// - /// Checks if the window is cloaked, this should solve some issues with the window selection code - /// - /// IntPtr as hWmd - /// bool - public static bool IsWindowCloaked(IntPtr hWnd) - { - if (!WindowsVersion.IsWindows8OrLater) - { - return false; - } - - DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAKED, out bool isCloaked, Marshal.SizeOf(typeof(bool))); - return isCloaked; - } - - /// - /// Helper method for an easy DWM check - /// - /// bool true if DWM is available AND active - public static bool IsDwmEnabled - { - get - { - // According to: http://technet.microsoft.com/en-us/subscriptions/aa969538%28v=vs.85%29.aspx - // And: http://msdn.microsoft.com/en-us/library/windows/desktop/aa969510%28v=vs.85%29.aspx - // DMW is always enabled on Windows 8! So return true and save a check! ;-) - if (WindowsVersion.IsWindows8OrLater) - { - return true; - } - - if (WindowsVersion.IsWindowsVistaOrLater) - { - DwmIsCompositionEnabled(out var dwmEnabled); - return dwmEnabled; - } - - return false; - } - } - - public static Color ColorizationColor - { - get - { - using (RegistryKey key = Registry.CurrentUser.OpenSubKey(COLORIZATION_COLOR_KEY, false)) - { - object dwordValue = key?.GetValue("ColorizationColor"); - if (dwordValue != null) - { - return Color.FromArgb((int) dwordValue); - } - } - - return Color.White; - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; +using Microsoft.Win32; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Desktop Window Manager helper code + /// + public static class DWM + { + // DWM + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb); + + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmUnregisterThumbnail(IntPtr thumb); + + [DllImport("dwmapi", SetLastError = true)] + public static extern HResult DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size); + + [DllImport("dwmapi", SetLastError = true)] + public static extern HResult DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); + + // Deprecated as of Windows 8 Release Preview + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmIsCompositionEnabled(out bool enabled); + + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT lpRect, int size); + + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool pvAttribute, int cbAttribute); + + // Key to ColorizationColor for DWM + private const string COLORIZATION_COLOR_KEY = @"SOFTWARE\Microsoft\Windows\DWM"; + + /// + /// Checks if the window is cloaked, this should solve some issues with the window selection code + /// + /// IntPtr as hWmd + /// bool + public static bool IsWindowCloaked(IntPtr hWnd) + { + if (!WindowsVersion.IsWindows8OrLater) + { + return false; + } + + DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAKED, out bool isCloaked, Marshal.SizeOf(typeof(bool))); + return isCloaked; + } + + /// + /// Helper method for an easy DWM check + /// + /// bool true if DWM is available AND active + public static bool IsDwmEnabled + { + get + { + // According to: http://technet.microsoft.com/en-us/subscriptions/aa969538%28v=vs.85%29.aspx + // And: http://msdn.microsoft.com/en-us/library/windows/desktop/aa969510%28v=vs.85%29.aspx + // DMW is always enabled on Windows 8! So return true and save a check! ;-) + if (WindowsVersion.IsWindows8OrLater) + { + return true; + } + + if (WindowsVersion.IsWindowsVistaOrLater) + { + DwmIsCompositionEnabled(out var dwmEnabled); + return dwmEnabled; + } + + return false; + } + } + + public static Color ColorizationColor + { + get + { + using (RegistryKey key = Registry.CurrentUser.OpenSubKey(COLORIZATION_COLOR_KEY, false)) + { + object dwordValue = key?.GetValue("ColorizationColor"); + if (dwordValue != null) + { + return Color.FromArgb((int) dwordValue); + } + } + + return Color.White; + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs b/src/Greenshot.Base/UnmanagedHelpers/EnumWindowsProc.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs rename to src/Greenshot.Base/UnmanagedHelpers/EnumWindowsProc.cs index db0185e07..d5e97162d 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/EnumWindowsProc.cs @@ -1,33 +1,33 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// Used with EnumWindows or EnumChildWindows - /// - /// IntPtr - /// int - /// int - public delegate int EnumWindowsProc(IntPtr hWnd, int lParam); +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Used with EnumWindows or EnumChildWindows + /// + /// IntPtr + /// int + /// int + public delegate int EnumWindowsProc(IntPtr hWnd, int lParam); } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs index d862d0ee8..6c070a25b 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ClassLongIndex - { - GCL_HICON = -14, // a handle to the icon associated with the class. - GCL_HICONSM = -34, // a handle to the small icon associated with the class. - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum ClassLongIndex + { + GCL_HICON = -14, // a handle to the icon associated with the class. + GCL_HICONSM = -34, // a handle to the small icon associated with the class. + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs similarity index 95% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs index 6c9aeb652..03d1ab7f9 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs @@ -1,46 +1,46 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DWMWINDOWATTRIBUTE : uint - { - DWMWA_NCRENDERING_ENABLED = 1, - DWMWA_NCRENDERING_POLICY, - DWMWA_TRANSITIONS_FORCEDISABLED, - DWMWA_ALLOW_NCPAINT, - DWMWA_CAPTION_BUTTON_BOUNDS, - DWMWA_NONCLIENT_RTL_LAYOUT, - DWMWA_FORCE_ICONIC_REPRESENTATION, - DWMWA_FLIP3D_POLICY, - DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista - DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7 - DWMWA_DISALLOW_PEEK, // Since Windows 7 - DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7 - DWMWA_CLOAK, // Since Windows 8 - DWMWA_CLOAKED, // Since Windows 8 - DWMWA_FREEZE_REPRESENTATION, // Since Windows 8 - DWMWA_LAST - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum DWMWINDOWATTRIBUTE : uint + { + DWMWA_NCRENDERING_ENABLED = 1, + DWMWA_NCRENDERING_POLICY, + DWMWA_TRANSITIONS_FORCEDISABLED, + DWMWA_ALLOW_NCPAINT, + DWMWA_CAPTION_BUTTON_BOUNDS, + DWMWA_NONCLIENT_RTL_LAYOUT, + DWMWA_FORCE_ICONIC_REPRESENTATION, + DWMWA_FLIP3D_POLICY, + DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista + DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7 + DWMWA_DISALLOW_PEEK, // Since Windows 7 + DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7 + DWMWA_CLOAK, // Since Windows 8 + DWMWA_CLOAKED, // Since Windows 8 + DWMWA_FREEZE_REPRESENTATION, // Since Windows 8 + DWMWA_LAST + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs index 37f64de7c..aa808f807 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs @@ -1,111 +1,111 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// See: http://msdn.microsoft.com/en-us/library/aa969502(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DWM_THUMBNAIL_PROPERTIES - { - // A bitwise combination of DWM thumbnail constant values that indicates which members of this structure are set. - public int dwFlags; - - // The area in the destination window where the thumbnail will be rendered. - public RECT rcDestination; - - // The region of the source window to use as the thumbnail. By default, the entire window is used as the thumbnail. - public RECT rcSource; - - // The opacity with which to render the thumbnail. 0 is fully transparent while 255 is fully opaque. The default value is 255. - public byte opacity; - - // TRUE to make the thumbnail visible; otherwise, FALSE. The default is FALSE. - public bool fVisible; - - // TRUE to use only the thumbnail source's client area; otherwise, FALSE. The default is FALSE. - public bool fSourceClientAreaOnly; - - public RECT Destination - { - set - { - dwFlags |= DWM_TNP_RECTDESTINATION; - rcDestination = value; - } - } - - public RECT Source - { - set - { - dwFlags |= DWM_TNP_RECTSOURCE; - rcSource = value; - } - } - - public byte Opacity - { - set - { - dwFlags |= DWM_TNP_OPACITY; - opacity = value; - } - } - - public bool Visible - { - set - { - dwFlags |= DWM_TNP_VISIBLE; - fVisible = value; - } - } - - public bool SourceClientAreaOnly - { - set - { - dwFlags |= DWM_TNP_SOURCECLIENTAREAONLY; - fSourceClientAreaOnly = value; - } - } - - // A value for the rcDestination member has been specified. - public const int DWM_TNP_RECTDESTINATION = 0x00000001; - - // A value for the rcSource member has been specified. - public const int DWM_TNP_RECTSOURCE = 0x00000002; - - // A value for the opacity member has been specified. - public const int DWM_TNP_OPACITY = 0x00000004; - - // A value for the fVisible member has been specified. - public const int DWM_TNP_VISIBLE = 0x00000008; - - // A value for the fSourceClientAreaOnly member has been specified. - public const int DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010; - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; +using Greenshot.Base.UnmanagedHelpers.Structs; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// See: http://msdn.microsoft.com/en-us/library/aa969502(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DWM_THUMBNAIL_PROPERTIES + { + // A bitwise combination of DWM thumbnail constant values that indicates which members of this structure are set. + public int dwFlags; + + // The area in the destination window where the thumbnail will be rendered. + public RECT rcDestination; + + // The region of the source window to use as the thumbnail. By default, the entire window is used as the thumbnail. + public RECT rcSource; + + // The opacity with which to render the thumbnail. 0 is fully transparent while 255 is fully opaque. The default value is 255. + public byte opacity; + + // TRUE to make the thumbnail visible; otherwise, FALSE. The default is FALSE. + public bool fVisible; + + // TRUE to use only the thumbnail source's client area; otherwise, FALSE. The default is FALSE. + public bool fSourceClientAreaOnly; + + public RECT Destination + { + set + { + dwFlags |= DWM_TNP_RECTDESTINATION; + rcDestination = value; + } + } + + public RECT Source + { + set + { + dwFlags |= DWM_TNP_RECTSOURCE; + rcSource = value; + } + } + + public byte Opacity + { + set + { + dwFlags |= DWM_TNP_OPACITY; + opacity = value; + } + } + + public bool Visible + { + set + { + dwFlags |= DWM_TNP_VISIBLE; + fVisible = value; + } + } + + public bool SourceClientAreaOnly + { + set + { + dwFlags |= DWM_TNP_SOURCECLIENTAREAONLY; + fSourceClientAreaOnly = value; + } + } + + // A value for the rcDestination member has been specified. + public const int DWM_TNP_RECTDESTINATION = 0x00000001; + + // A value for the rcSource member has been specified. + public const int DWM_TNP_RECTSOURCE = 0x00000002; + + // A value for the opacity member has been specified. + public const int DWM_TNP_OPACITY = 0x00000004; + + // A value for the fVisible member has been specified. + public const int DWM_TNP_VISIBLE = 0x00000008; + + // A value for the fSourceClientAreaOnly member has been specified. + public const int DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010; + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DesktopAccessRight.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/DesktopAccessRight.cs index a0b5e1be8..219299a35 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/DesktopAccessRight.cs @@ -1,45 +1,45 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DesktopAccessRight : uint - { - DESKTOP_READOBJECTS = 0x00000001, - DESKTOP_CREATEWINDOW = 0x00000002, - DESKTOP_CREATEMENU = 0x00000004, - DESKTOP_HOOKCONTROL = 0x00000008, - DESKTOP_JOURNALRECORD = 0x00000010, - DESKTOP_JOURNALPLAYBACK = 0x00000020, - DESKTOP_ENUMERATE = 0x00000040, - DESKTOP_WRITEOBJECTS = 0x00000080, - DESKTOP_SWITCHDESKTOP = 0x00000100, - - GENERIC_ALL = (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | - DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | - DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP) - }; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum DesktopAccessRight : uint + { + DESKTOP_READOBJECTS = 0x00000001, + DESKTOP_CREATEWINDOW = 0x00000002, + DESKTOP_CREATEMENU = 0x00000004, + DESKTOP_HOOKCONTROL = 0x00000008, + DESKTOP_JOURNALRECORD = 0x00000010, + DESKTOP_JOURNALPLAYBACK = 0x00000020, + DESKTOP_ENUMERATE = 0x00000040, + DESKTOP_WRITEOBJECTS = 0x00000080, + DESKTOP_SWITCHDESKTOP = 0x00000100, + + GENERIC_ALL = (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | + DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | + DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP) + }; } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DeviceCaps.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/DeviceCaps.cs index ff4f3e3e4..126d9de62 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/DeviceCaps.cs @@ -1,43 +1,43 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// Used by GDI32.GetDeviceCaps - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd144877%28v=vs.85%29.aspx - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DeviceCaps - { - /// - /// Logical pixels inch in X - /// - LOGPIXELSX = 88, - - /// - /// Current vertical refresh rate of the display device (for displays only) in Hz - /// - VREFRESH = 116 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// Used by GDI32.GetDeviceCaps + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd144877%28v=vs.85%29.aspx + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum DeviceCaps + { + /// + /// Logical pixels inch in X + /// + LOGPIXELSX = 88, + + /// + /// Current vertical refresh rate of the display device (for displays only) in Hz + /// + VREFRESH = 116 + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs index a1981e644..81532e912 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs @@ -1,35 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// Used for User32.SetWinEventHook - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd373606%28v=vs.85%29.aspx#OBJID_WINDOW - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum EventObjects - { - OBJID_WINDOW = 0 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// Used for User32.SetWinEventHook + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd373606%28v=vs.85%29.aspx#OBJID_WINDOW + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum EventObjects + { + OBJID_WINDOW = 0 + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs index e04af4108..e00166b2d 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs @@ -1,36 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ExtendedWindowStyleFlags : uint - { - WS_EX_TOOLWINDOW = 0x00000080, - - WS_EX_NOREDIRECTIONBITMAP = - 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual. - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum ExtendedWindowStyleFlags : uint + { + WS_EX_TOOLWINDOW = 0x00000080, + + WS_EX_NOREDIRECTIONBITMAP = + 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual. + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ProcessAccessFlags.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/ProcessAccessFlags.cs index 27a89b3b6..d4e593840 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ProcessAccessFlags.cs @@ -1,34 +1,34 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ProcessAccessFlags : uint - { - VMRead = 0x00000010, - QueryInformation = 0x00000400, - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum ProcessAccessFlags : uint + { + VMRead = 0x00000010, + QueryInformation = 0x00000400, + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs index bc1b0f372..4632a6aaf 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum RegionResult - { - REGION_ERROR = 0, - REGION_NULLREGION = 1, - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum RegionResult + { + REGION_ERROR = 0, + REGION_NULLREGION = 1, + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs index 70a6ff104..b6c0b2087 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs @@ -1,36 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// See: http://www.pinvoke.net/default.aspx/Enums/SendMessageTimeoutFlags.html - /// - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SendMessageTimeoutFlags : uint - { - SMTO_NORMAL = 0x0 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// See: http://www.pinvoke.net/default.aspx/Enums/SendMessageTimeoutFlags.html + /// + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum SendMessageTimeoutFlags : uint + { + SMTO_NORMAL = 0x0 + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs similarity index 96% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs index 76ccb3ce4..c09a10f9e 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs @@ -1,110 +1,110 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ShowWindowCommand : uint - { - /// - /// Hides the window and activates another window. - /// - Hide = 0, - - /// - /// Activates and displays a window. If the window is minimized or - /// maximized, the system restores it to its original size and position. - /// An application should specify this flag when displaying the window - /// for the first time. - /// - Normal = 1, - - /// - /// Activates the window and displays it as a minimized window. - /// - ShowMinimized = 2, - - /// - /// Maximizes the specified window. - /// - Maximize = 3, // is this the right value? - - /// - /// Activates the window and displays it as a maximized window. - /// - ShowMaximized = 3, - - /// - /// Displays a window in its most recent size and position. This value - /// is similar to , except - /// the window is not actived. - /// - ShowNoActivate = 4, - - /// - /// Activates the window and displays it in its current size and position. - /// - Show = 5, - - /// - /// Minimizes the specified window and activates the next top-level - /// window in the Z order. - /// - Minimize = 6, - - /// - /// Displays the window as a minimized window. This value is similar to - /// , except the - /// window is not activated. - /// - ShowMinNoActive = 7, - - /// - /// Displays the window in its current size and position. This value is - /// similar to , except the - /// window is not activated. - /// - ShowNA = 8, - - /// - /// Activates and displays the window. If the window is minimized or - /// maximized, the system restores it to its original size and position. - /// An application should specify this flag when restoring a minimized window. - /// - Restore = 9, - - /// - /// Sets the show state based on the SW_* value specified in the - /// STARTUPINFO structure passed to the CreateProcess function by the - /// program that started the application. - /// - ShowDefault = 10, - - /// - /// Windows 2000/XP: Minimizes a window, even if the thread - /// that owns the window is not responding. This flag should only be - /// used when minimizing windows from a different thread. - /// - ForceMinimize = 11 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum ShowWindowCommand : uint + { + /// + /// Hides the window and activates another window. + /// + Hide = 0, + + /// + /// Activates and displays a window. If the window is minimized or + /// maximized, the system restores it to its original size and position. + /// An application should specify this flag when displaying the window + /// for the first time. + /// + Normal = 1, + + /// + /// Activates the window and displays it as a minimized window. + /// + ShowMinimized = 2, + + /// + /// Maximizes the specified window. + /// + Maximize = 3, // is this the right value? + + /// + /// Activates the window and displays it as a maximized window. + /// + ShowMaximized = 3, + + /// + /// Displays a window in its most recent size and position. This value + /// is similar to , except + /// the window is not actived. + /// + ShowNoActivate = 4, + + /// + /// Activates the window and displays it in its current size and position. + /// + Show = 5, + + /// + /// Minimizes the specified window and activates the next top-level + /// window in the Z order. + /// + Minimize = 6, + + /// + /// Displays the window as a minimized window. This value is similar to + /// , except the + /// window is not activated. + /// + ShowMinNoActive = 7, + + /// + /// Displays the window in its current size and position. This value is + /// similar to , except the + /// window is not activated. + /// + ShowNA = 8, + + /// + /// Activates and displays the window. If the window is minimized or + /// maximized, the system restores it to its original size and position. + /// An application should specify this flag when restoring a minimized window. + /// + Restore = 9, + + /// + /// Sets the show state based on the SW_* value specified in the + /// STARTUPINFO structure passed to the CreateProcess function by the + /// program that started the application. + /// + ShowDefault = 10, + + /// + /// Windows 2000/XP: Minimizes a window, even if the thread + /// that owns the window is not responding. This flag should only be + /// used when minimizing windows from a different thread. + /// + ForceMinimize = 11 + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs index 8ad288c68..aebe3d9a6 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs @@ -1,39 +1,39 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// See: http://msdn.microsoft.com/en-us/library/aa909766.aspx - /// - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SoundFlags - { - SND_ASYNC = 0x0001, // play asynchronously - SND_MEMORY = 0x0004, // pszSound points to a memory file - SND_NOSTOP = 0x0010, // don't stop any currently playing sound - SND_NOWAIT = 0x00002000, // don't wait if the driver is busy - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// See: http://msdn.microsoft.com/en-us/library/aa909766.aspx + /// + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum SoundFlags + { + SND_ASYNC = 0x0001, // play asynchronously + SND_MEMORY = 0x0004, // pszSound points to a memory file + SND_NOSTOP = 0x0010, // don't stop any currently playing sound + SND_NOWAIT = 0x00002000, // don't wait if the driver is busy + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ThreadAccess.cs similarity index 92% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/ThreadAccess.cs index 50df23caa..979af5708 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ThreadAccess.cs @@ -1,31 +1,31 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - public enum ThreadAccess : int - { - SUSPEND_RESUME = (0x0002), - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + public enum ThreadAccess : int + { + SUSPEND_RESUME = (0x0002), + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs similarity index 95% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs index be8ea2965..5e814b223 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs @@ -1,89 +1,89 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// A Win32 error code. - /// - public enum Win32Error : uint - { - Success = 0x0, - InvalidFunction = 0x1, - FileNotFound = 0x2, - PathNotFound = 0x3, - TooManyOpenFiles = 0x4, - AccessDenied = 0x5, - InvalidHandle = 0x6, - ArenaTrashed = 0x7, - NotEnoughMemory = 0x8, - InvalidBlock = 0x9, - BadEnvironment = 0xa, - BadFormat = 0xb, - InvalidAccess = 0xc, - InvalidData = 0xd, - OutOfMemory = 0xe, - InvalidDrive = 0xf, - CurrentDirectory = 0x10, - NotSameDevice = 0x11, - NoMoreFiles = 0x12, - WriteProtect = 0x13, - BadUnit = 0x14, - NotReady = 0x15, - BadCommand = 0x16, - Crc = 0x17, - BadLength = 0x18, - Seek = 0x19, - NotDosDisk = 0x1a, - SectorNotFound = 0x1b, - OutOfPaper = 0x1c, - WriteFault = 0x1d, - ReadFault = 0x1e, - GenFailure = 0x1f, - SharingViolation = 0x20, - LockViolation = 0x21, - WrongDisk = 0x22, - SharingBufferExceeded = 0x24, - HandleEof = 0x26, - HandleDiskFull = 0x27, - NotSupported = 0x32, - RemNotList = 0x33, - DupName = 0x34, - BadNetPath = 0x35, - NetworkBusy = 0x36, - DevNotExist = 0x37, - TooManyCmds = 0x38, - FileExists = 0x50, - CannotMake = 0x52, - AlreadyAssigned = 0x55, - InvalidPassword = 0x56, - InvalidParameter = 0x57, - NetWriteFault = 0x58, - NoProcSlots = 0x59, - TooManySemaphores = 0x64, - ExclSemAlreadyOwned = 0x65, - SemIsSet = 0x66, - TooManySemRequests = 0x67, - InvalidAtInterruptTime = 0x68, - SemOwnerDied = 0x69, - SemUserLimit = 0x6a - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// A Win32 error code. + /// + public enum Win32Error : uint + { + Success = 0x0, + InvalidFunction = 0x1, + FileNotFound = 0x2, + PathNotFound = 0x3, + TooManyOpenFiles = 0x4, + AccessDenied = 0x5, + InvalidHandle = 0x6, + ArenaTrashed = 0x7, + NotEnoughMemory = 0x8, + InvalidBlock = 0x9, + BadEnvironment = 0xa, + BadFormat = 0xb, + InvalidAccess = 0xc, + InvalidData = 0xd, + OutOfMemory = 0xe, + InvalidDrive = 0xf, + CurrentDirectory = 0x10, + NotSameDevice = 0x11, + NoMoreFiles = 0x12, + WriteProtect = 0x13, + BadUnit = 0x14, + NotReady = 0x15, + BadCommand = 0x16, + Crc = 0x17, + BadLength = 0x18, + Seek = 0x19, + NotDosDisk = 0x1a, + SectorNotFound = 0x1b, + OutOfPaper = 0x1c, + WriteFault = 0x1d, + ReadFault = 0x1e, + GenFailure = 0x1f, + SharingViolation = 0x20, + LockViolation = 0x21, + WrongDisk = 0x22, + SharingBufferExceeded = 0x24, + HandleEof = 0x26, + HandleDiskFull = 0x27, + NotSupported = 0x32, + RemNotList = 0x33, + DupName = 0x34, + BadNetPath = 0x35, + NetworkBusy = 0x36, + DevNotExist = 0x37, + TooManyCmds = 0x38, + FileExists = 0x50, + CannotMake = 0x52, + AlreadyAssigned = 0x55, + InvalidPassword = 0x56, + InvalidParameter = 0x57, + NetWriteFault = 0x58, + NoProcSlots = 0x59, + TooManySemaphores = 0x64, + ExclSemAlreadyOwned = 0x65, + SemIsSet = 0x66, + TooManySemRequests = 0x67, + InvalidAtInterruptTime = 0x68, + SemOwnerDied = 0x69, + SemUserLimit = 0x6a + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs index aaaf0e8e9..0938d4317 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs @@ -1,37 +1,37 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// Used for User32.SetWinEventHook - /// See MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/dd318066%28v=vs.85%29.aspx - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WinEvent : uint - { - EVENT_OBJECT_CREATE = 32768, - EVENT_OBJECT_DESTROY = 32769, - EVENT_OBJECT_NAMECHANGE = 32780, - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// Used for User32.SetWinEventHook + /// See MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/dd318066%28v=vs.85%29.aspx + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WinEvent : uint + { + EVENT_OBJECT_CREATE = 32768, + EVENT_OBJECT_DESTROY = 32769, + EVENT_OBJECT_NAMECHANGE = 32780, + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEventHookFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEventHookFlags.cs similarity index 87% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEventHookFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WinEventHookFlags.cs index 4ca58d2df..497940960 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WinEventHookFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEventHookFlags.cs @@ -1,18 +1,18 @@ -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// Used for User32.SetWinEventHook - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd373640%28v=vs.85%29.aspx - /// - [SuppressMessage("ReSharper", "InconsistentNaming"), Flags] - public enum WinEventHookFlags - { - WINEVENT_SKIPOWNTHREAD = 1, - WINEVENT_SKIPOWNPROCESS = 2, - WINEVENT_OUTOFCONTEXT = 0, - WINEVENT_INCONTEXT = 4 - } +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// Used for User32.SetWinEventHook + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd373640%28v=vs.85%29.aspx + /// + [SuppressMessage("ReSharper", "InconsistentNaming"), Flags] + public enum WinEventHookFlags + { + WINEVENT_SKIPOWNTHREAD = 1, + WINEVENT_SKIPOWNPROCESS = 2, + WINEVENT_OUTOFCONTEXT = 0, + WINEVENT_INCONTEXT = 4 + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs index 6da1d01b8..09eddbb32 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowLongIndex - { - GWL_EXSTYLE = -20, // Sets a new extended window style. - GWL_STYLE = -16, // Sets a new window style. - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowLongIndex + { + GWL_EXSTYLE = -20, // Sets a new extended window style. + GWL_STYLE = -16, // Sets a new window style. + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPlacementFlags.cs similarity index 95% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPlacementFlags.cs index feb53a499..a6ac06dbf 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPlacementFlags.cs @@ -1,42 +1,42 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowPlacementFlags : uint - { - // The coordinates of the minimized window may be specified. - // This flag must be specified if the coordinates are set in the ptMinPosition member. - WPF_SETMINPOSITION = 0x0001, - - // If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. - WPF_ASYNCWINDOWPLACEMENT = 0x0004, - - // The restored window will be maximized, regardless of whether it was maximized before it was minimized. This setting is only valid the next time the window is restored. It does not change the default restoration behavior. - // This flag is only valid when the SW_SHOWMINIMIZED value is specified for the showCmd member. - WPF_RESTORETOMAXIMIZED = 0x0002 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowPlacementFlags : uint + { + // The coordinates of the minimized window may be specified. + // This flag must be specified if the coordinates are set in the ptMinPosition member. + WPF_SETMINPOSITION = 0x0001, + + // If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. + WPF_ASYNCWINDOWPLACEMENT = 0x0004, + + // The restored window will be maximized, regardless of whether it was maximized before it was minimized. This setting is only valid the next time the window is restored. It does not change the default restoration behavior. + // This flag is only valid when the SW_SHOWMINIMIZED value is specified for the showCmd member. + WPF_RESTORETOMAXIMIZED = 0x0002 + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs index a725e6baf..268819fc4 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs @@ -1,36 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowPos - { - SWP_NOACTIVATE = - 0x0010, // Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). - SWP_NOMOVE = 0x0002, //Retains the current position (ignores X and Y parameters). - SWP_NOSIZE = 0x0001, // Retains the current size (ignores the cx and cy parameters). - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowPos + { + SWP_NOACTIVATE = + 0x0010, // Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). + SWP_NOMOVE = 0x0002, //Retains the current position (ignores X and Y parameters). + SWP_NOSIZE = 0x0001, // Retains the current size (ignores the cx and cy parameters). + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs index de33325d0..914633254 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs @@ -1,36 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// Window Style Flags - /// - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowStyleFlags : long - { - WS_VISIBLE = 0x10000000, - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// Window Style Flags + /// + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowStyleFlags : long + { + WS_VISIBLE = 0x10000000, + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs index d398fbdc3..2aff5fe19 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs @@ -1,26 +1,26 @@ -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// All possible windows messages - /// See also here - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowsMessages : uint - { - WM_MOUSEACTIVATE = 0x0021, - WM_INPUTLANGCHANGEREQUEST = 0x0050, - WM_INPUTLANGCHANGE = 0x0051, - - - /// - /// Sent to a window to retrieve a handle to the large or small icon associated with a window. The system displays the large icon in the ALT+TAB dialog, and the small icon in the window caption. - /// A window receives this message through its WindowProc function. - /// WM_GETICON message - /// - WM_GETICON = 0x007F, - WM_CHAR = 0x0102, - WM_SYSCOMMAND = 0x0112 - } +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// All possible windows messages + /// See also here + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowsMessages : uint + { + WM_MOUSEACTIVATE = 0x0021, + WM_INPUTLANGCHANGEREQUEST = 0x0050, + WM_INPUTLANGCHANGE = 0x0051, + + + /// + /// Sent to a window to retrieve a handle to the large or small icon associated with a window. The system displays the large icon in the ALT+TAB dialog, and the small icon in the window caption. + /// A window receives this message through its WindowProc function. + /// WM_GETICON message + /// + WM_GETICON = 0x007F, + WM_CHAR = 0x0102, + WM_SYSCOMMAND = 0x0112 + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/GDI32.cs b/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs similarity index 96% rename from src/GreenshotPlugin/UnmanagedHelpers/GDI32.cs rename to src/Greenshot.Base/UnmanagedHelpers/GDI32.cs index f2591a1d4..ed15abd1a 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/GDI32.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs @@ -1,425 +1,425 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Security; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using Microsoft.Win32.SafeHandles; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - public static class GDIExtensions - { - /// - /// Check if all the corners of the rectangle are visible in the specified region. - /// Not a perfect check, but this currently a workaround for checking if a window is completely visible - /// - /// - /// - /// - public static bool AreRectangleCornersVisisble(this Region region, Rectangle rectangle) - { - Point topLeft = new Point(rectangle.X, rectangle.Y); - Point topRight = new Point(rectangle.X + rectangle.Width, rectangle.Y); - Point bottomLeft = new Point(rectangle.X, rectangle.Y + rectangle.Height); - Point bottomRight = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height); - bool topLeftVisible = region.IsVisible(topLeft); - bool topRightVisible = region.IsVisible(topRight); - bool bottomLeftVisible = region.IsVisible(bottomLeft); - bool bottomRightVisible = region.IsVisible(bottomRight); - - return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible; - } - - /// - /// Get a SafeHandle for the GetHdc, so one can use using to automatically cleanup the devicecontext - /// - /// - /// SafeDeviceContextHandle - public static SafeDeviceContextHandle GetSafeDeviceContext(this Graphics graphics) - { - return SafeDeviceContextHandle.FromGraphics(graphics); - } - } - - /// - /// Abstract class SafeObjectHandle which contains all handles that are cleaned with DeleteObject - /// - public abstract class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid - { - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); - - protected SafeObjectHandle(bool ownsHandle) : base(ownsHandle) - { - } - - protected override bool ReleaseHandle() - { - return DeleteObject(handle); - } - } - - /// - /// A hbitmap SafeHandle implementation - /// - public class SafeHBitmapHandle : SafeObjectHandle - { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeHBitmapHandle() : base(true) - { - } - - [SecurityCritical] - public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) - { - SetHandle(preexistingHandle); - } - } - - /// - /// A hRegion SafeHandle implementation - /// - public class SafeRegionHandle : SafeObjectHandle - { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeRegionHandle() : base(true) - { - } - - [SecurityCritical] - public SafeRegionHandle(IntPtr preexistingHandle) : base(true) - { - SetHandle(preexistingHandle); - } - } - - /// - /// A dibsection SafeHandle implementation - /// - public class SafeDibSectionHandle : SafeObjectHandle - { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeDibSectionHandle() : base(true) - { - } - - [SecurityCritical] - public SafeDibSectionHandle(IntPtr preexistingHandle) : base(true) - { - SetHandle(preexistingHandle); - } - } - - /// - /// A select object safehandle implementation - /// This impl will select the passed SafeHandle to the HDC and replace the returned value when disposing - /// - public class SafeSelectObjectHandle : SafeHandleZeroOrMinusOneIsInvalid - { - [DllImport("gdi32", SetLastError = true)] - private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); - - private readonly SafeHandle _hdc; - - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeSelectObjectHandle() : base(true) - { - } - - [SecurityCritical] - public SafeSelectObjectHandle(SafeDCHandle hdc, SafeHandle newHandle) : base(true) - { - _hdc = hdc; - SetHandle(SelectObject(hdc.DangerousGetHandle(), newHandle.DangerousGetHandle())); - } - - protected override bool ReleaseHandle() - { - SelectObject(_hdc.DangerousGetHandle(), handle); - return true; - } - } - - public abstract class SafeDCHandle : SafeHandleZeroOrMinusOneIsInvalid - { - protected SafeDCHandle(bool ownsHandle) : base(ownsHandle) - { - } - } - - /// - /// A CompatibleDC SafeHandle implementation - /// - public class SafeCompatibleDCHandle : SafeDCHandle - { - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteDC(IntPtr hDC); - - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeCompatibleDCHandle() : base(true) - { - } - - [SecurityCritical] - public SafeCompatibleDCHandle(IntPtr preexistingHandle) : base(true) - { - SetHandle(preexistingHandle); - } - - public SafeSelectObjectHandle SelectObject(SafeHandle newHandle) - { - return new SafeSelectObjectHandle(this, newHandle); - } - - protected override bool ReleaseHandle() - { - return DeleteDC(handle); - } - } - - /// - /// A DeviceContext SafeHandle implementation - /// - public class SafeDeviceContextHandle : SafeDCHandle - { - private readonly Graphics _graphics; - - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeDeviceContextHandle() : base(true) - { - } - - [SecurityCritical] - public SafeDeviceContextHandle(Graphics graphics, IntPtr preexistingHandle) : base(true) - { - _graphics = graphics; - SetHandle(preexistingHandle); - } - - protected override bool ReleaseHandle() - { - _graphics.ReleaseHdc(handle); - return true; - } - - public static SafeDeviceContextHandle FromGraphics(Graphics graphics) - { - return new SafeDeviceContextHandle(graphics, graphics.GetHdc()); - } - } - - /// - /// GDI32 Helpers - /// - public static class GDI32 - { - [DllImport("gdi32", SetLastError = true)] - public static extern bool BitBlt(SafeHandle hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, SafeHandle hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop); - - [DllImport("gdi32", SetLastError = true)] - public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC); - - [DllImport("gdi32", SetLastError = true)] - public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADER bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset); - - [DllImport("gdi32", SetLastError = true)] - public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); - - [DllImport("gdi32", SetLastError = true)] - public static extern uint GetPixel(SafeHandle hdc, int nXPos, int nYPos); - - [DllImport("gdi32", SetLastError = true)] - public static extern int GetDeviceCaps(SafeHandle hdc, DeviceCaps nIndex); - } - - [StructLayout(LayoutKind.Sequential, Pack = 2)] - public struct BITMAPFILEHEADER - { - public static readonly short BM = 0x4d42; // BM - public short bfType; - public int bfSize; - public short bfReserved1; - public short bfReserved2; - public int bfOffBits; - } - - [StructLayout(LayoutKind.Sequential)] - public struct BitfieldColorMask - { - public uint blue; - public uint green; - public uint red; - - public void InitValues() - { - red = (uint) 255 << 8; - green = (uint) 255 << 16; - blue = (uint) 255 << 24; - } - } - - [StructLayout(LayoutKind.Sequential)] - public struct CIEXYZ - { - public uint ciexyzX; //FXPT2DOT30 - public uint ciexyzY; //FXPT2DOT30 - public uint ciexyzZ; //FXPT2DOT30 - - public CIEXYZ(uint FXPT2DOT30) - { - ciexyzX = FXPT2DOT30; - ciexyzY = FXPT2DOT30; - ciexyzZ = FXPT2DOT30; - } - } - - [StructLayout(LayoutKind.Sequential)] - public struct CIEXYZTRIPLE - { - public CIEXYZ ciexyzRed; - public CIEXYZ ciexyzGreen; - public CIEXYZ ciexyzBlue; - } - - public enum BI_COMPRESSION : uint - { - BI_RGB = 0, // Uncompressed - BI_RLE8 = 1, // RLE 8BPP - BI_RLE4 = 2, // RLE 4BPP - - BI_BITFIELDS = - 3, // Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bpp bitmaps. - BI_JPEG = 4, // Indicates that the image is a JPEG image. - BI_PNG = 5 // Indicates that the image is a PNG image. - } - - [StructLayout(LayoutKind.Explicit)] - public struct BITMAPINFOHEADER - { - [FieldOffset(0)] public uint biSize; - [FieldOffset(4)] public int biWidth; - [FieldOffset(8)] public int biHeight; - [FieldOffset(12)] public ushort biPlanes; - [FieldOffset(14)] public ushort biBitCount; - [FieldOffset(16)] public BI_COMPRESSION biCompression; - [FieldOffset(20)] public uint biSizeImage; - [FieldOffset(24)] public int biXPelsPerMeter; - [FieldOffset(28)] public int biYPelsPerMeter; - [FieldOffset(32)] public uint biClrUsed; - [FieldOffset(36)] public uint biClrImportant; - [FieldOffset(40)] public uint bV5RedMask; - [FieldOffset(44)] public uint bV5GreenMask; - [FieldOffset(48)] public uint bV5BlueMask; - [FieldOffset(52)] public uint bV5AlphaMask; - [FieldOffset(56)] public uint bV5CSType; - [FieldOffset(60)] public CIEXYZTRIPLE bV5Endpoints; - [FieldOffset(96)] public uint bV5GammaRed; - [FieldOffset(100)] public uint bV5GammaGreen; - [FieldOffset(104)] public uint bV5GammaBlue; - [FieldOffset(108)] public uint bV5Intent; // Rendering intent for bitmap - [FieldOffset(112)] public uint bV5ProfileData; - [FieldOffset(116)] public uint bV5ProfileSize; - [FieldOffset(120)] public uint bV5Reserved; - - public const int DIB_RGB_COLORS = 0; - - public BITMAPINFOHEADER(int width, int height, ushort bpp) - { - biSize = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV5 is 40 bytes - biPlanes = 1; // Should allways be 1 - biCompression = BI_COMPRESSION.BI_RGB; - biWidth = width; - biHeight = height; - biBitCount = bpp; - biSizeImage = (uint) (width * height * (bpp >> 3)); - biXPelsPerMeter = 0; - biYPelsPerMeter = 0; - biClrUsed = 0; - biClrImportant = 0; - - // V5 - bV5RedMask = (uint) 255 << 16; - bV5GreenMask = (uint) 255 << 8; - bV5BlueMask = 255; - bV5AlphaMask = (uint) 255 << 24; - bV5CSType = 0x73524742; // LCS_sRGB - bV5Endpoints = new CIEXYZTRIPLE - { - ciexyzBlue = new CIEXYZ(0), - ciexyzGreen = new CIEXYZ(0), - ciexyzRed = new CIEXYZ(0) - }; - bV5GammaRed = 0; - bV5GammaGreen = 0; - bV5GammaBlue = 0; - bV5Intent = 4; - bV5ProfileData = 0; - bV5ProfileSize = 0; - bV5Reserved = 0; - } - - public bool IsDibV5 - { - get - { - uint sizeOfBMI = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADER)); - return biSize >= sizeOfBMI; - } - } - - public uint OffsetToPixels - { - get - { - if (biCompression == BI_COMPRESSION.BI_BITFIELDS) - { - // Add 3x4 bytes for the bitfield color mask - return biSize + 3 * 4; - } - - return biSize; - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Security; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Microsoft.Win32.SafeHandles; + +namespace Greenshot.Base.UnmanagedHelpers +{ + public static class GDIExtensions + { + /// + /// Check if all the corners of the rectangle are visible in the specified region. + /// Not a perfect check, but this currently a workaround for checking if a window is completely visible + /// + /// + /// + /// + public static bool AreRectangleCornersVisisble(this Region region, Rectangle rectangle) + { + Point topLeft = new Point(rectangle.X, rectangle.Y); + Point topRight = new Point(rectangle.X + rectangle.Width, rectangle.Y); + Point bottomLeft = new Point(rectangle.X, rectangle.Y + rectangle.Height); + Point bottomRight = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height); + bool topLeftVisible = region.IsVisible(topLeft); + bool topRightVisible = region.IsVisible(topRight); + bool bottomLeftVisible = region.IsVisible(bottomLeft); + bool bottomRightVisible = region.IsVisible(bottomRight); + + return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible; + } + + /// + /// Get a SafeHandle for the GetHdc, so one can use using to automatically cleanup the devicecontext + /// + /// + /// SafeDeviceContextHandle + public static SafeDeviceContextHandle GetSafeDeviceContext(this Graphics graphics) + { + return SafeDeviceContextHandle.FromGraphics(graphics); + } + } + + /// + /// Abstract class SafeObjectHandle which contains all handles that are cleaned with DeleteObject + /// + public abstract class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [DllImport("gdi32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteObject(IntPtr hObject); + + protected SafeObjectHandle(bool ownsHandle) : base(ownsHandle) + { + } + + protected override bool ReleaseHandle() + { + return DeleteObject(handle); + } + } + + /// + /// A hbitmap SafeHandle implementation + /// + public class SafeHBitmapHandle : SafeObjectHandle + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeHBitmapHandle() : base(true) + { + } + + [SecurityCritical] + public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + } + + /// + /// A hRegion SafeHandle implementation + /// + public class SafeRegionHandle : SafeObjectHandle + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeRegionHandle() : base(true) + { + } + + [SecurityCritical] + public SafeRegionHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + } + + /// + /// A dibsection SafeHandle implementation + /// + public class SafeDibSectionHandle : SafeObjectHandle + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeDibSectionHandle() : base(true) + { + } + + [SecurityCritical] + public SafeDibSectionHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + } + + /// + /// A select object safehandle implementation + /// This impl will select the passed SafeHandle to the HDC and replace the returned value when disposing + /// + public class SafeSelectObjectHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [DllImport("gdi32", SetLastError = true)] + private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); + + private readonly SafeHandle _hdc; + + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeSelectObjectHandle() : base(true) + { + } + + [SecurityCritical] + public SafeSelectObjectHandle(SafeDCHandle hdc, SafeHandle newHandle) : base(true) + { + _hdc = hdc; + SetHandle(SelectObject(hdc.DangerousGetHandle(), newHandle.DangerousGetHandle())); + } + + protected override bool ReleaseHandle() + { + SelectObject(_hdc.DangerousGetHandle(), handle); + return true; + } + } + + public abstract class SafeDCHandle : SafeHandleZeroOrMinusOneIsInvalid + { + protected SafeDCHandle(bool ownsHandle) : base(ownsHandle) + { + } + } + + /// + /// A CompatibleDC SafeHandle implementation + /// + public class SafeCompatibleDCHandle : SafeDCHandle + { + [DllImport("gdi32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteDC(IntPtr hDC); + + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeCompatibleDCHandle() : base(true) + { + } + + [SecurityCritical] + public SafeCompatibleDCHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + + public SafeSelectObjectHandle SelectObject(SafeHandle newHandle) + { + return new SafeSelectObjectHandle(this, newHandle); + } + + protected override bool ReleaseHandle() + { + return DeleteDC(handle); + } + } + + /// + /// A DeviceContext SafeHandle implementation + /// + public class SafeDeviceContextHandle : SafeDCHandle + { + private readonly Graphics _graphics; + + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeDeviceContextHandle() : base(true) + { + } + + [SecurityCritical] + public SafeDeviceContextHandle(Graphics graphics, IntPtr preexistingHandle) : base(true) + { + _graphics = graphics; + SetHandle(preexistingHandle); + } + + protected override bool ReleaseHandle() + { + _graphics.ReleaseHdc(handle); + return true; + } + + public static SafeDeviceContextHandle FromGraphics(Graphics graphics) + { + return new SafeDeviceContextHandle(graphics, graphics.GetHdc()); + } + } + + /// + /// GDI32 Helpers + /// + public static class GDI32 + { + [DllImport("gdi32", SetLastError = true)] + public static extern bool BitBlt(SafeHandle hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, SafeHandle hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop); + + [DllImport("gdi32", SetLastError = true)] + public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC); + + [DllImport("gdi32", SetLastError = true)] + public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADER bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset); + + [DllImport("gdi32", SetLastError = true)] + public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); + + [DllImport("gdi32", SetLastError = true)] + public static extern uint GetPixel(SafeHandle hdc, int nXPos, int nYPos); + + [DllImport("gdi32", SetLastError = true)] + public static extern int GetDeviceCaps(SafeHandle hdc, DeviceCaps nIndex); + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + public struct BITMAPFILEHEADER + { + public static readonly short BM = 0x4d42; // BM + public short bfType; + public int bfSize; + public short bfReserved1; + public short bfReserved2; + public int bfOffBits; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BitfieldColorMask + { + public uint blue; + public uint green; + public uint red; + + public void InitValues() + { + red = (uint) 255 << 8; + green = (uint) 255 << 16; + blue = (uint) 255 << 24; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct CIEXYZ + { + public uint ciexyzX; //FXPT2DOT30 + public uint ciexyzY; //FXPT2DOT30 + public uint ciexyzZ; //FXPT2DOT30 + + public CIEXYZ(uint FXPT2DOT30) + { + ciexyzX = FXPT2DOT30; + ciexyzY = FXPT2DOT30; + ciexyzZ = FXPT2DOT30; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct CIEXYZTRIPLE + { + public CIEXYZ ciexyzRed; + public CIEXYZ ciexyzGreen; + public CIEXYZ ciexyzBlue; + } + + public enum BI_COMPRESSION : uint + { + BI_RGB = 0, // Uncompressed + BI_RLE8 = 1, // RLE 8BPP + BI_RLE4 = 2, // RLE 4BPP + + BI_BITFIELDS = + 3, // Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bpp bitmaps. + BI_JPEG = 4, // Indicates that the image is a JPEG image. + BI_PNG = 5 // Indicates that the image is a PNG image. + } + + [StructLayout(LayoutKind.Explicit)] + public struct BITMAPINFOHEADER + { + [FieldOffset(0)] public uint biSize; + [FieldOffset(4)] public int biWidth; + [FieldOffset(8)] public int biHeight; + [FieldOffset(12)] public ushort biPlanes; + [FieldOffset(14)] public ushort biBitCount; + [FieldOffset(16)] public BI_COMPRESSION biCompression; + [FieldOffset(20)] public uint biSizeImage; + [FieldOffset(24)] public int biXPelsPerMeter; + [FieldOffset(28)] public int biYPelsPerMeter; + [FieldOffset(32)] public uint biClrUsed; + [FieldOffset(36)] public uint biClrImportant; + [FieldOffset(40)] public uint bV5RedMask; + [FieldOffset(44)] public uint bV5GreenMask; + [FieldOffset(48)] public uint bV5BlueMask; + [FieldOffset(52)] public uint bV5AlphaMask; + [FieldOffset(56)] public uint bV5CSType; + [FieldOffset(60)] public CIEXYZTRIPLE bV5Endpoints; + [FieldOffset(96)] public uint bV5GammaRed; + [FieldOffset(100)] public uint bV5GammaGreen; + [FieldOffset(104)] public uint bV5GammaBlue; + [FieldOffset(108)] public uint bV5Intent; // Rendering intent for bitmap + [FieldOffset(112)] public uint bV5ProfileData; + [FieldOffset(116)] public uint bV5ProfileSize; + [FieldOffset(120)] public uint bV5Reserved; + + public const int DIB_RGB_COLORS = 0; + + public BITMAPINFOHEADER(int width, int height, ushort bpp) + { + biSize = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV5 is 40 bytes + biPlanes = 1; // Should allways be 1 + biCompression = BI_COMPRESSION.BI_RGB; + biWidth = width; + biHeight = height; + biBitCount = bpp; + biSizeImage = (uint) (width * height * (bpp >> 3)); + biXPelsPerMeter = 0; + biYPelsPerMeter = 0; + biClrUsed = 0; + biClrImportant = 0; + + // V5 + bV5RedMask = (uint) 255 << 16; + bV5GreenMask = (uint) 255 << 8; + bV5BlueMask = 255; + bV5AlphaMask = (uint) 255 << 24; + bV5CSType = 0x73524742; // LCS_sRGB + bV5Endpoints = new CIEXYZTRIPLE + { + ciexyzBlue = new CIEXYZ(0), + ciexyzGreen = new CIEXYZ(0), + ciexyzRed = new CIEXYZ(0) + }; + bV5GammaRed = 0; + bV5GammaGreen = 0; + bV5GammaBlue = 0; + bV5Intent = 4; + bV5ProfileData = 0; + bV5ProfileSize = 0; + bV5Reserved = 0; + } + + public bool IsDibV5 + { + get + { + uint sizeOfBMI = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADER)); + return biSize >= sizeOfBMI; + } + } + + public uint OffsetToPixels + { + get + { + if (biCompression == BI_COMPRESSION.BI_BITFIELDS) + { + // Add 3x4 bytes for the bitfield color mask + return biSize + 3 * 4; + } + + return biSize; + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs b/src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs similarity index 96% rename from src/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs rename to src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs index 6da5b3850..6fc9f061f 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs @@ -1,387 +1,387 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using log4net; -using System.Reflection; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// Contains members that specify the nature of a Gaussian blur. - /// - /// Cannot be pinned with GCHandle due to bool value. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct BlurParams - { - /// - /// Real number that specifies the blur radius (the radius of the Gaussian convolution kernel) in - /// pixels. The radius must be in the range 0 through 255. As the radius increases, the resulting - /// bitmap becomes more blurry. - /// - public float Radius; - - /// - /// Boolean value that specifies whether the bitmap expands by an amount equal to the blur radius. - /// If TRUE, the bitmap expands by an amount equal to the radius so that it can have soft edges. - /// If FALSE, the bitmap remains the same size and the soft edges are clipped. - /// - public bool ExpandEdges; - } - - /// - /// GDI Plus unit description. - /// - public enum GpUnit - { - /// - /// World coordinate (non-physical unit). - /// - UnitWorld, - - /// - /// Variable - for PageTransform only. - /// - UnitDisplay, - - /// - /// Each unit is one device pixel. - /// - UnitPixel, - - /// - /// Each unit is a printer's point, or 1/72 inch. - /// - UnitPoint, - - /// - /// Each unit is 1 inch. - /// - UnitInch, - - /// - /// Each unit is 1/300 inch. - /// - UnitDocument, - - /// - /// Each unit is 1 millimeter. - /// - UnitMillimeter - } - - /// - /// GDIplus Helpers - /// - public static class GDIplus - { - private static readonly ILog Log = LogManager.GetLogger(typeof(GDIplus)); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipBitmapApplyEffect(IntPtr bitmap, IntPtr effect, ref RECT rectOfInterest, bool useAuxData, IntPtr auxData, int auxDataSize); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipDrawImageFX(IntPtr graphics, IntPtr bitmap, ref RECTF source, IntPtr matrix, IntPtr effect, IntPtr imageAttributes, GpUnit srcUnit); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipSetEffectParameters(IntPtr effect, IntPtr parameters, uint size); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipCreateEffect(Guid guid, out IntPtr effect); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipDeleteEffect(IntPtr effect); - - private static readonly Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}"); - - // Constant "FieldInfo" for getting the nativeImage from the Bitmap - private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGE = typeof(Bitmap).GetField("nativeImage", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - - // Constant "FieldInfo" for getting the NativeGraphics from the Graphics - private static readonly FieldInfo FIELD_INFO_NATIVE_GRAPHICS = - typeof(Graphics).GetField("nativeGraphics", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - - // Constant "FieldInfo" for getting the nativeMatrix from the Matrix - private static readonly FieldInfo FIELD_INFO_NATIVE_MATRIX = - typeof(Matrix).GetField("nativeMatrix", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - - // Constant "FieldInfo" for getting the nativeImageAttributes from the ImageAttributes - private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGEATTRIBUTES = - typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - - private static bool _isBlurEnabled = Environment.OSVersion.Version.Major >= 6; - - /// - /// Get the nativeImage field from the bitmap - /// - /// - /// IntPtr - private static IntPtr GetNativeImage(Bitmap bitmap) - { - if (bitmap == null) - { - return IntPtr.Zero; - } - - return (IntPtr) FIELD_INFO_NATIVE_IMAGE.GetValue(bitmap); - } - - /// - /// Get the NativeGraphics field from the graphics - /// - /// - /// IntPtr - private static IntPtr GetNativeGraphics(Graphics graphics) - { - if (graphics == null) - { - return IntPtr.Zero; - } - - return (IntPtr) FIELD_INFO_NATIVE_GRAPHICS.GetValue(graphics); - } - - /// - /// Get the nativeMatrix field from the matrix - /// - /// - /// IntPtr - private static IntPtr GetNativeMatrix(Matrix matrix) - { - if (matrix == null) - { - return IntPtr.Zero; - } - - return (IntPtr) FIELD_INFO_NATIVE_MATRIX.GetValue(matrix); - } - - /// - /// Get the nativeImageAttributes field from the ImageAttributes - /// - /// - /// IntPtr - private static IntPtr GetNativeImageAttributes(ImageAttributes imageAttributes) - { - if (imageAttributes == null) - { - return IntPtr.Zero; - } - - return (IntPtr) FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes); - } - - /// - /// Returns if a GDIPlus blur can be made for the supplied radius. - /// This accounts for the "bug" I reported here: http://social.technet.microsoft.com/Forums/en/w8itprogeneral/thread/99ddbe9d-556d-475a-8bab-84e25aa13a2c - /// - /// - /// false if blur is not possible - public static bool IsBlurPossible(int radius) - { - if (!_isBlurEnabled) - { - return false; - } - - if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2) - { - return true; - } - - return Environment.OSVersion.Version.Major > 6 && radius >= 20; - } - - /// - /// Use the GDI+ blur effect on the bitmap - /// - /// Bitmap to apply the effect to - /// Rectangle to apply the blur effect to - /// 0-255 - /// bool true if the edges are expanded with the radius - /// false if there is no GDI+ available or an exception occured - public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, int radius, bool expandEdges) - { - if (!IsBlurPossible(radius)) - { - return false; - } - - IntPtr hBlurParams = IntPtr.Zero; - IntPtr hEffect = IntPtr.Zero; - - try - { - // Create the GDI+ BlurEffect, using the Guid - int status = GdipCreateEffect(BlurEffectGuid, out hEffect); - if (status != 0) - { - return false; - } - - // Create a BlurParams struct and set the values - var blurParams = new BlurParams - { - Radius = radius, - ExpandEdges = expandEdges - }; - - // Allocate space in unmanaged memory - hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); - // Copy the structure to the unmanaged memory - Marshal.StructureToPtr(blurParams, hBlurParams, false); - - - // Set the blurParams to the effect - GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams)); - - // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! - // Get the private nativeImage property from the Bitmap - IntPtr hBitmap = GetNativeImage(destinationBitmap); - - // Create a RECT from the Rectangle - RECT rec = new RECT(area); - // Apply the effect to the bitmap in the specified area - GdipBitmapApplyEffect(hBitmap, hEffect, ref rec, false, IntPtr.Zero, 0); - - // Everything worked, return true - return true; - } - catch (Exception ex) - { - _isBlurEnabled = false; - Log.Error("Problem using GdipBitmapApplyEffect: ", ex); - return false; - } - finally - { - try - { - if (hEffect != IntPtr.Zero) - { - // Delete the effect - GdipDeleteEffect(hEffect); - } - - if (hBlurParams != IntPtr.Zero) - { - // Free the memory - Marshal.FreeHGlobal(hBlurParams); - } - } - catch (Exception ex) - { - _isBlurEnabled = false; - Log.Error("Problem cleaning up ApplyBlur: ", ex); - } - } - } - - /// - /// Draw the image on the graphics with GDI+ blur effect - /// - /// false if there is no GDI+ available or an exception occured - public static bool DrawWithBlur(Graphics graphics, Bitmap image, Rectangle source, Matrix transform, ImageAttributes imageAttributes, int radius, bool expandEdges) - { - if (!IsBlurPossible(radius)) - { - return false; - } - - IntPtr hBlurParams = IntPtr.Zero; - IntPtr hEffect = IntPtr.Zero; - - try - { - // Create the GDI+ BlurEffect, using the Guid - int status = GdipCreateEffect(BlurEffectGuid, out hEffect); - if (status != 0) - { - return false; - } - - // Create a BlurParams struct and set the values - var blurParams = new BlurParams - { - Radius = radius, - ExpandEdges = false - }; - //blurParams.Padding = radius; - - // Allocate space in unmanaged memory - hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); - // Copy the structure to the unmanaged memory - Marshal.StructureToPtr(blurParams, hBlurParams, true); - - // Set the blurParams to the effect - GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams)); - - // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! - // Get the private nativeImage property from the Bitmap - IntPtr hBitmap = GetNativeImage(image); - IntPtr hGraphics = GetNativeGraphics(graphics); - IntPtr hMatrix = GetNativeMatrix(transform); - IntPtr hAttributes = GetNativeImageAttributes(imageAttributes); - - // Create a RECT from the Rectangle - RECTF sourceRecf = new RECTF(source); - // Apply the effect to the bitmap in the specified area - GdipDrawImageFX(hGraphics, hBitmap, ref sourceRecf, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel); - - // Everything worked, return true - return true; - } - catch (Exception ex) - { - _isBlurEnabled = false; - Log.Error("Problem using GdipDrawImageFX: ", ex); - return false; - } - finally - { - try - { - if (hEffect != IntPtr.Zero) - { - // Delete the effect - GdipDeleteEffect(hEffect); - } - - if (hBlurParams != IntPtr.Zero) - { - // Free the memory - Marshal.FreeHGlobal(hBlurParams); - } - } - catch (Exception ex) - { - _isBlurEnabled = false; - Log.Error("Problem cleaning up DrawWithBlur: ", ex); - } - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Reflection; +using System.Runtime.InteropServices; +using Greenshot.Base.UnmanagedHelpers.Structs; +using log4net; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Contains members that specify the nature of a Gaussian blur. + /// + /// Cannot be pinned with GCHandle due to bool value. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct BlurParams + { + /// + /// Real number that specifies the blur radius (the radius of the Gaussian convolution kernel) in + /// pixels. The radius must be in the range 0 through 255. As the radius increases, the resulting + /// bitmap becomes more blurry. + /// + public float Radius; + + /// + /// Boolean value that specifies whether the bitmap expands by an amount equal to the blur radius. + /// If TRUE, the bitmap expands by an amount equal to the radius so that it can have soft edges. + /// If FALSE, the bitmap remains the same size and the soft edges are clipped. + /// + public bool ExpandEdges; + } + + /// + /// GDI Plus unit description. + /// + public enum GpUnit + { + /// + /// World coordinate (non-physical unit). + /// + UnitWorld, + + /// + /// Variable - for PageTransform only. + /// + UnitDisplay, + + /// + /// Each unit is one device pixel. + /// + UnitPixel, + + /// + /// Each unit is a printer's point, or 1/72 inch. + /// + UnitPoint, + + /// + /// Each unit is 1 inch. + /// + UnitInch, + + /// + /// Each unit is 1/300 inch. + /// + UnitDocument, + + /// + /// Each unit is 1 millimeter. + /// + UnitMillimeter + } + + /// + /// GDIplus Helpers + /// + public static class GDIplus + { + private static readonly ILog Log = LogManager.GetLogger(typeof(GDIplus)); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipBitmapApplyEffect(IntPtr bitmap, IntPtr effect, ref RECT rectOfInterest, bool useAuxData, IntPtr auxData, int auxDataSize); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipDrawImageFX(IntPtr graphics, IntPtr bitmap, ref RECTF source, IntPtr matrix, IntPtr effect, IntPtr imageAttributes, GpUnit srcUnit); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipSetEffectParameters(IntPtr effect, IntPtr parameters, uint size); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipCreateEffect(Guid guid, out IntPtr effect); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipDeleteEffect(IntPtr effect); + + private static readonly Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}"); + + // Constant "FieldInfo" for getting the nativeImage from the Bitmap + private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGE = typeof(Bitmap).GetField("nativeImage", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + + // Constant "FieldInfo" for getting the NativeGraphics from the Graphics + private static readonly FieldInfo FIELD_INFO_NATIVE_GRAPHICS = + typeof(Graphics).GetField("nativeGraphics", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + + // Constant "FieldInfo" for getting the nativeMatrix from the Matrix + private static readonly FieldInfo FIELD_INFO_NATIVE_MATRIX = + typeof(Matrix).GetField("nativeMatrix", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + + // Constant "FieldInfo" for getting the nativeImageAttributes from the ImageAttributes + private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGEATTRIBUTES = + typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + + private static bool _isBlurEnabled = Environment.OSVersion.Version.Major >= 6; + + /// + /// Get the nativeImage field from the bitmap + /// + /// + /// IntPtr + private static IntPtr GetNativeImage(Bitmap bitmap) + { + if (bitmap == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_IMAGE.GetValue(bitmap); + } + + /// + /// Get the NativeGraphics field from the graphics + /// + /// + /// IntPtr + private static IntPtr GetNativeGraphics(Graphics graphics) + { + if (graphics == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_GRAPHICS.GetValue(graphics); + } + + /// + /// Get the nativeMatrix field from the matrix + /// + /// + /// IntPtr + private static IntPtr GetNativeMatrix(Matrix matrix) + { + if (matrix == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_MATRIX.GetValue(matrix); + } + + /// + /// Get the nativeImageAttributes field from the ImageAttributes + /// + /// + /// IntPtr + private static IntPtr GetNativeImageAttributes(ImageAttributes imageAttributes) + { + if (imageAttributes == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes); + } + + /// + /// Returns if a GDIPlus blur can be made for the supplied radius. + /// This accounts for the "bug" I reported here: http://social.technet.microsoft.com/Forums/en/w8itprogeneral/thread/99ddbe9d-556d-475a-8bab-84e25aa13a2c + /// + /// + /// false if blur is not possible + public static bool IsBlurPossible(int radius) + { + if (!_isBlurEnabled) + { + return false; + } + + if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2) + { + return true; + } + + return Environment.OSVersion.Version.Major > 6 && radius >= 20; + } + + /// + /// Use the GDI+ blur effect on the bitmap + /// + /// Bitmap to apply the effect to + /// Rectangle to apply the blur effect to + /// 0-255 + /// bool true if the edges are expanded with the radius + /// false if there is no GDI+ available or an exception occured + public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, int radius, bool expandEdges) + { + if (!IsBlurPossible(radius)) + { + return false; + } + + IntPtr hBlurParams = IntPtr.Zero; + IntPtr hEffect = IntPtr.Zero; + + try + { + // Create the GDI+ BlurEffect, using the Guid + int status = GdipCreateEffect(BlurEffectGuid, out hEffect); + if (status != 0) + { + return false; + } + + // Create a BlurParams struct and set the values + var blurParams = new BlurParams + { + Radius = radius, + ExpandEdges = expandEdges + }; + + // Allocate space in unmanaged memory + hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); + // Copy the structure to the unmanaged memory + Marshal.StructureToPtr(blurParams, hBlurParams, false); + + + // Set the blurParams to the effect + GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams)); + + // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! + // Get the private nativeImage property from the Bitmap + IntPtr hBitmap = GetNativeImage(destinationBitmap); + + // Create a RECT from the Rectangle + RECT rec = new RECT(area); + // Apply the effect to the bitmap in the specified area + GdipBitmapApplyEffect(hBitmap, hEffect, ref rec, false, IntPtr.Zero, 0); + + // Everything worked, return true + return true; + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem using GdipBitmapApplyEffect: ", ex); + return false; + } + finally + { + try + { + if (hEffect != IntPtr.Zero) + { + // Delete the effect + GdipDeleteEffect(hEffect); + } + + if (hBlurParams != IntPtr.Zero) + { + // Free the memory + Marshal.FreeHGlobal(hBlurParams); + } + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem cleaning up ApplyBlur: ", ex); + } + } + } + + /// + /// Draw the image on the graphics with GDI+ blur effect + /// + /// false if there is no GDI+ available or an exception occured + public static bool DrawWithBlur(Graphics graphics, Bitmap image, Rectangle source, Matrix transform, ImageAttributes imageAttributes, int radius, bool expandEdges) + { + if (!IsBlurPossible(radius)) + { + return false; + } + + IntPtr hBlurParams = IntPtr.Zero; + IntPtr hEffect = IntPtr.Zero; + + try + { + // Create the GDI+ BlurEffect, using the Guid + int status = GdipCreateEffect(BlurEffectGuid, out hEffect); + if (status != 0) + { + return false; + } + + // Create a BlurParams struct and set the values + var blurParams = new BlurParams + { + Radius = radius, + ExpandEdges = false + }; + //blurParams.Padding = radius; + + // Allocate space in unmanaged memory + hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); + // Copy the structure to the unmanaged memory + Marshal.StructureToPtr(blurParams, hBlurParams, true); + + // Set the blurParams to the effect + GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams)); + + // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! + // Get the private nativeImage property from the Bitmap + IntPtr hBitmap = GetNativeImage(image); + IntPtr hGraphics = GetNativeGraphics(graphics); + IntPtr hMatrix = GetNativeMatrix(transform); + IntPtr hAttributes = GetNativeImageAttributes(imageAttributes); + + // Create a RECT from the Rectangle + RECTF sourceRecf = new RECTF(source); + // Apply the effect to the bitmap in the specified area + GdipDrawImageFX(hGraphics, hBitmap, ref sourceRecf, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel); + + // Everything worked, return true + return true; + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem using GdipDrawImageFX: ", ex); + return false; + } + finally + { + try + { + if (hEffect != IntPtr.Zero) + { + // Delete the effect + GdipDeleteEffect(hEffect); + } + + if (hBlurParams != IntPtr.Zero) + { + // Free the memory + Marshal.FreeHGlobal(hBlurParams); + } + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem cleaning up DrawWithBlur: ", ex); + } + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs b/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs similarity index 96% rename from src/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs rename to src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs index df512ee08..9e34b7341 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs @@ -1,131 +1,131 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; -using System.Text; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// Description of Kernel32. - /// - public class Kernel32 - { - public const uint ATTACHCONSOLE_ATTACHPARENTPROCESS = 0x0ffffffff; // default value if not specifing a process ID - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool AttachConsole(uint dwProcessId); - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool AllocConsole(); - - [DllImport("kernel32", SetLastError = true)] - public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); - - [DllImport("kernel32", SetLastError = true)] - public static extern uint SuspendThread(IntPtr hThread); - - [DllImport("kernel32", SetLastError = true)] - public static extern int ResumeThread(IntPtr hThread); - - [DllImport("kernel32", SetLastError = true)] - public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId); - - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize); - - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, uint uuchMax); - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CloseHandle(IntPtr hObject); - - /// - /// Method to get the process path - /// - /// - /// - public static string GetProcessPath(int processid) - { - StringBuilder _PathBuffer = new StringBuilder(512); - // Try the GetModuleFileName method first since it's the fastest. - // May return ACCESS_DENIED (due to VM_READ flag) if the process is not owned by the current user. - // Will fail if we are compiled as x86 and we're trying to open a 64 bit process...not allowed. - IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead, false, processid); - if (hprocess != IntPtr.Zero) - { - try - { - if (PsAPI.GetModuleFileNameEx(hprocess, IntPtr.Zero, _PathBuffer, (uint) _PathBuffer.Capacity) > 0) - { - return _PathBuffer.ToString(); - } - } - finally - { - CloseHandle(hprocess); - } - } - - hprocess = OpenProcess(ProcessAccessFlags.QueryInformation, false, processid); - if (hprocess != IntPtr.Zero) - { - try - { - // Try this method for Vista or higher operating systems - uint size = (uint) _PathBuffer.Capacity; - if ((Environment.OSVersion.Version.Major >= 6) && (QueryFullProcessImageName(hprocess, 0, _PathBuffer, ref size) && (size > 0))) - { - return _PathBuffer.ToString(); - } - - // Try the GetProcessImageFileName method - if (PsAPI.GetProcessImageFileName(hprocess, _PathBuffer, (uint) _PathBuffer.Capacity) > 0) - { - string dospath = _PathBuffer.ToString(); - foreach (string drive in Environment.GetLogicalDrives()) - { - if (QueryDosDevice(drive.TrimEnd('\\'), _PathBuffer, (uint) _PathBuffer.Capacity) > 0) - { - if (dospath.StartsWith(_PathBuffer.ToString())) - { - return drive + dospath.Remove(0, _PathBuffer.Length); - } - } - } - } - } - finally - { - CloseHandle(hprocess); - } - } - - return string.Empty; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; +using System.Text; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Description of Kernel32. + /// + public class Kernel32 + { + public const uint ATTACHCONSOLE_ATTACHPARENTPROCESS = 0x0ffffffff; // default value if not specifing a process ID + + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AttachConsole(uint dwProcessId); + + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AllocConsole(); + + [DllImport("kernel32", SetLastError = true)] + public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); + + [DllImport("kernel32", SetLastError = true)] + public static extern uint SuspendThread(IntPtr hThread); + + [DllImport("kernel32", SetLastError = true)] + public static extern int ResumeThread(IntPtr hThread); + + [DllImport("kernel32", SetLastError = true)] + public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, uint uuchMax); + + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseHandle(IntPtr hObject); + + /// + /// Method to get the process path + /// + /// + /// + public static string GetProcessPath(int processid) + { + StringBuilder _PathBuffer = new StringBuilder(512); + // Try the GetModuleFileName method first since it's the fastest. + // May return ACCESS_DENIED (due to VM_READ flag) if the process is not owned by the current user. + // Will fail if we are compiled as x86 and we're trying to open a 64 bit process...not allowed. + IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead, false, processid); + if (hprocess != IntPtr.Zero) + { + try + { + if (PsAPI.GetModuleFileNameEx(hprocess, IntPtr.Zero, _PathBuffer, (uint) _PathBuffer.Capacity) > 0) + { + return _PathBuffer.ToString(); + } + } + finally + { + CloseHandle(hprocess); + } + } + + hprocess = OpenProcess(ProcessAccessFlags.QueryInformation, false, processid); + if (hprocess != IntPtr.Zero) + { + try + { + // Try this method for Vista or higher operating systems + uint size = (uint) _PathBuffer.Capacity; + if ((Environment.OSVersion.Version.Major >= 6) && (QueryFullProcessImageName(hprocess, 0, _PathBuffer, ref size) && (size > 0))) + { + return _PathBuffer.ToString(); + } + + // Try the GetProcessImageFileName method + if (PsAPI.GetProcessImageFileName(hprocess, _PathBuffer, (uint) _PathBuffer.Capacity) > 0) + { + string dospath = _PathBuffer.ToString(); + foreach (string drive in Environment.GetLogicalDrives()) + { + if (QueryDosDevice(drive.TrimEnd('\\'), _PathBuffer, (uint) _PathBuffer.Capacity) > 0) + { + if (dospath.StartsWith(_PathBuffer.ToString())) + { + return drive + dospath.Remove(0, _PathBuffer.Length); + } + } + } + } + } + finally + { + CloseHandle(hprocess); + } + } + + return string.Empty; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs b/src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs similarity index 95% rename from src/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs rename to src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs index 67bc5f764..bafe9e28c 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs @@ -1,56 +1,56 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; -using log4net; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// Description of PsAPI. - /// - public class PsAPI - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(PsAPI)); - - [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize); - - [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint GetProcessImageFileName(IntPtr hProcess, StringBuilder lpImageFileName, uint nSize); - - [DllImport("psapi")] - private static extern int EmptyWorkingSet(IntPtr hwProc); - - /// - /// Make the process use less memory by emptying the working set - /// - public static void EmptyWorkingSet() - { - LOG.Info("Calling EmptyWorkingSet"); - using Process currentProcess = Process.GetCurrentProcess(); - EmptyWorkingSet(currentProcess.Handle); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; +using log4net; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Description of PsAPI. + /// + public class PsAPI + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(PsAPI)); + + [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize); + + [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint GetProcessImageFileName(IntPtr hProcess, StringBuilder lpImageFileName, uint nSize); + + [DllImport("psapi")] + private static extern int EmptyWorkingSet(IntPtr hwProc); + + /// + /// Make the process use less memory by emptying the working set + /// + public static void EmptyWorkingSet() + { + LOG.Info("Calling EmptyWorkingSet"); + using Process currentProcess = Process.GetCurrentProcess(); + EmptyWorkingSet(currentProcess.Handle); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs b/src/Greenshot.Base/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs similarity index 91% rename from src/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs rename to src/Greenshot.Base/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs index f1178a424..113117eae 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs @@ -1,45 +1,45 @@ -using System; -using System.Security.Permissions; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using log4net; -using Microsoft.Win32.SafeHandles; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// A SafeHandle class implementation for the current input desktop - /// - public class SafeCurrentInputDesktopHandle : SafeHandleZeroOrMinusOneIsInvalid - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(SafeCurrentInputDesktopHandle)); - - public SafeCurrentInputDesktopHandle() : base(true) - { - IntPtr hDesktop = User32.OpenInputDesktop(0, true, DesktopAccessRight.GENERIC_ALL); - if (hDesktop != IntPtr.Zero) - { - SetHandle(hDesktop); - if (User32.SetThreadDesktop(hDesktop)) - { - LOG.DebugFormat("Switched to desktop {0}", hDesktop); - } - else - { - LOG.WarnFormat("Couldn't switch to desktop {0}", hDesktop); - LOG.Error(User32.CreateWin32Exception("SetThreadDesktop")); - } - } - else - { - LOG.Warn("Couldn't get current desktop."); - LOG.Error(User32.CreateWin32Exception("OpenInputDesktop")); - } - } - - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - protected override bool ReleaseHandle() - { - return User32.CloseDesktop(handle); - } - } +using System; +using System.Security.Permissions; +using Greenshot.Base.UnmanagedHelpers.Enums; +using log4net; +using Microsoft.Win32.SafeHandles; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// A SafeHandle class implementation for the current input desktop + /// + public class SafeCurrentInputDesktopHandle : SafeHandleZeroOrMinusOneIsInvalid + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(SafeCurrentInputDesktopHandle)); + + public SafeCurrentInputDesktopHandle() : base(true) + { + IntPtr hDesktop = User32.OpenInputDesktop(0, true, DesktopAccessRight.GENERIC_ALL); + if (hDesktop != IntPtr.Zero) + { + SetHandle(hDesktop); + if (User32.SetThreadDesktop(hDesktop)) + { + LOG.DebugFormat("Switched to desktop {0}", hDesktop); + } + else + { + LOG.WarnFormat("Couldn't switch to desktop {0}", hDesktop); + LOG.Error(User32.CreateWin32Exception("SetThreadDesktop")); + } + } + else + { + LOG.Warn("Couldn't get current desktop."); + LOG.Error(User32.CreateWin32Exception("OpenInputDesktop")); + } + } + + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] + protected override bool ReleaseHandle() + { + return User32.CloseDesktop(handle); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs b/src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs similarity index 91% rename from src/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs rename to src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs index 50f6a4369..acb280287 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs @@ -1,33 +1,33 @@ -using System; -using System.Security; -using System.Security.Permissions; -using Microsoft.Win32.SafeHandles; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// A SafeHandle class implementation for the hIcon - /// - public class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid - { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeIconHandle() : base(true) - { - } - - - public SafeIconHandle(IntPtr hIcon) : base(true) - { - SetHandle(hIcon); - } - - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - protected override bool ReleaseHandle() - { - return User32.DestroyIcon(handle); - } - } +using System; +using System.Security; +using System.Security.Permissions; +using Microsoft.Win32.SafeHandles; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// A SafeHandle class implementation for the hIcon + /// + public class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeIconHandle() : base(true) + { + } + + + public SafeIconHandle(IntPtr hIcon) : base(true) + { + SetHandle(hIcon); + } + + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] + protected override bool ReleaseHandle() + { + return User32.DestroyIcon(handle); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs b/src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs rename to src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs index 671c07a3f..7ccdbf684 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs @@ -1,66 +1,66 @@ -using System; -using System.Runtime.InteropServices; -using System.Security; -using System.Security.Permissions; -using Microsoft.Win32.SafeHandles; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// A WindowDC SafeHandle implementation - /// - public class SafeWindowDcHandle : SafeHandleZeroOrMinusOneIsInvalid - { - [DllImport("user32", SetLastError = true)] - private static extern IntPtr GetWindowDC(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); - - private readonly IntPtr _hWnd; - - /// - /// Needed for marshalling return values - /// - public SafeWindowDcHandle() : base(true) - { - } - - [SecurityCritical] - public SafeWindowDcHandle(IntPtr hWnd, IntPtr preexistingHandle) : base(true) - { - _hWnd = hWnd; - SetHandle(preexistingHandle); - } - - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - protected override bool ReleaseHandle() - { - bool returnValue = ReleaseDC(_hWnd, handle); - return returnValue; - } - - /// - /// Creates a DC as SafeWindowDcHandle for the whole of the specified hWnd - /// - /// IntPtr - /// SafeWindowDcHandle - public static SafeWindowDcHandle FromWindow(IntPtr hWnd) - { - if (hWnd == IntPtr.Zero) - { - return null; - } - - var hDcDesktop = GetWindowDC(hWnd); - return new SafeWindowDcHandle(hWnd, hDcDesktop); - } - - public static SafeWindowDcHandle FromDesktop() - { - IntPtr hWndDesktop = User32.GetDesktopWindow(); - IntPtr hDCDesktop = GetWindowDC(hWndDesktop); - return new SafeWindowDcHandle(hWndDesktop, hDCDesktop); - } - } +using System; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Permissions; +using Microsoft.Win32.SafeHandles; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// A WindowDC SafeHandle implementation + /// + public class SafeWindowDcHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [DllImport("user32", SetLastError = true)] + private static extern IntPtr GetWindowDC(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); + + private readonly IntPtr _hWnd; + + /// + /// Needed for marshalling return values + /// + public SafeWindowDcHandle() : base(true) + { + } + + [SecurityCritical] + public SafeWindowDcHandle(IntPtr hWnd, IntPtr preexistingHandle) : base(true) + { + _hWnd = hWnd; + SetHandle(preexistingHandle); + } + + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] + protected override bool ReleaseHandle() + { + bool returnValue = ReleaseDC(_hWnd, handle); + return returnValue; + } + + /// + /// Creates a DC as SafeWindowDcHandle for the whole of the specified hWnd + /// + /// IntPtr + /// SafeWindowDcHandle + public static SafeWindowDcHandle FromWindow(IntPtr hWnd) + { + if (hWnd == IntPtr.Zero) + { + return null; + } + + var hDcDesktop = GetWindowDC(hWnd); + return new SafeWindowDcHandle(hWnd, hDcDesktop); + } + + public static SafeWindowDcHandle FromDesktop() + { + IntPtr hWndDesktop = User32.GetDesktopWindow(); + IntPtr hDCDesktop = GetWindowDC(hWndDesktop); + return new SafeWindowDcHandle(hWndDesktop, hDCDesktop); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Shell32.cs b/src/Greenshot.Base/UnmanagedHelpers/Shell32.cs similarity index 96% rename from src/GreenshotPlugin/UnmanagedHelpers/Shell32.cs rename to src/Greenshot.Base/UnmanagedHelpers/Shell32.cs index a1eb7e890..14c603225 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Shell32.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Shell32.cs @@ -1,123 +1,123 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using System.IO; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// Description of Shell32. - /// - public static class Shell32 - { - [DllImport("shell32", CharSet = CharSet.Unicode)] - public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons); - - [DllImport("shell32", CharSet = CharSet.Unicode)] - private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - private struct SHFILEINFO - { - public readonly IntPtr hIcon; - public readonly int iIcon; - public readonly uint dwAttributes; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public readonly string szDisplayName; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] - public readonly string szTypeName; - }; - - // Browsing for directory. - - private const uint SHGFI_ICON = 0x000000100; // get icon - private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon - private const uint SHGFI_LARGEICON = 0x000000000; // get large icon - private const uint SHGFI_SMALLICON = 0x000000001; // get small icon - private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute - private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; - - /// - /// Options to specify the size of icons to return. - /// - public enum IconSize - { - /// - /// Specify large icon - 32 pixels by 32 pixels. - /// - Large = 0, - - /// - /// Specify small icon - 16 pixels by 16 pixels. - /// - Small = 1 - } - - /// - /// Returns an icon for a given file extension - indicated by the name parameter. - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx - /// - /// Filename - /// Large or small - /// Whether to include the link icon - /// System.Drawing.Icon - public static Icon GetFileIcon(string filename, IconSize size, bool linkOverlay) - { - SHFILEINFO shfi = new SHFILEINFO(); - // SHGFI_USEFILEATTRIBUTES makes it simulate, just gets the icon for the extension - uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; - - if (linkOverlay) - { - flags += SHGFI_LINKOVERLAY; - } - - // Check the size specified for return. - if (IconSize.Small == size) - { - flags += SHGFI_SMALLICON; - } - else - { - flags += SHGFI_LARGEICON; - } - - SHGetFileInfo(Path.GetFileName(filename), FILE_ATTRIBUTE_NORMAL, ref shfi, (uint) Marshal.SizeOf(shfi), flags); - - // Only return an icon if we really got one - if (shfi.hIcon != IntPtr.Zero) - { - // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly - Icon icon = (Icon) Icon.FromHandle(shfi.hIcon).Clone(); - // Cleanup - User32.DestroyIcon(shfi.hIcon); - return icon; - } - - return null; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Description of Shell32. + /// + public static class Shell32 + { + [DllImport("shell32", CharSet = CharSet.Unicode)] + public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons); + + [DllImport("shell32", CharSet = CharSet.Unicode)] + private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct SHFILEINFO + { + public readonly IntPtr hIcon; + public readonly int iIcon; + public readonly uint dwAttributes; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public readonly string szDisplayName; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] + public readonly string szTypeName; + }; + + // Browsing for directory. + + private const uint SHGFI_ICON = 0x000000100; // get icon + private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon + private const uint SHGFI_LARGEICON = 0x000000000; // get large icon + private const uint SHGFI_SMALLICON = 0x000000001; // get small icon + private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute + private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; + + /// + /// Options to specify the size of icons to return. + /// + public enum IconSize + { + /// + /// Specify large icon - 32 pixels by 32 pixels. + /// + Large = 0, + + /// + /// Specify small icon - 16 pixels by 16 pixels. + /// + Small = 1 + } + + /// + /// Returns an icon for a given file extension - indicated by the name parameter. + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx + /// + /// Filename + /// Large or small + /// Whether to include the link icon + /// System.Drawing.Icon + public static Icon GetFileIcon(string filename, IconSize size, bool linkOverlay) + { + SHFILEINFO shfi = new SHFILEINFO(); + // SHGFI_USEFILEATTRIBUTES makes it simulate, just gets the icon for the extension + uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; + + if (linkOverlay) + { + flags += SHGFI_LINKOVERLAY; + } + + // Check the size specified for return. + if (IconSize.Small == size) + { + flags += SHGFI_SMALLICON; + } + else + { + flags += SHGFI_LARGEICON; + } + + SHGetFileInfo(Path.GetFileName(filename), FILE_ATTRIBUTE_NORMAL, ref shfi, (uint) Marshal.SizeOf(shfi), flags); + + // Only return an icon if we really got one + if (shfi.hIcon != IntPtr.Zero) + { + // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly + Icon icon = (Icon) Icon.FromHandle(shfi.hIcon).Clone(); + // Cleanup + User32.DestroyIcon(shfi.hIcon); + return icon; + } + + return null; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/CursorInfo.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/CursorInfo.cs index 1eae0c0ad..9974ddeb7 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/CursorInfo.cs @@ -1,35 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential)] - public struct CursorInfo - { - public int cbSize; - public int flags; - public IntPtr hCursor; - public POINT ptScreenPos; - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential)] + public struct CursorInfo + { + public int cbSize; + public int flags; + public IntPtr hCursor; + public POINT ptScreenPos; + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs index cd953d244..b7a430449 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs @@ -1,36 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential)] - public struct IconInfo - { - public bool fIcon; - public int xHotspot; - public int yHotspot; - public IntPtr hbmMask; - public IntPtr hbmColor; - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential)] + public struct IconInfo + { + public bool fIcon; + public int xHotspot; + public int yHotspot; + public IntPtr hbmMask; + public IntPtr hbmColor; + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/POINT.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/POINT.cs index f22f34e49..a274933c7 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/POINT.cs @@ -1,66 +1,66 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct POINT - { - public int X; - public int Y; - - public POINT(int x, int y) - { - X = x; - Y = y; - } - - public POINT(Point point) - { - X = point.X; - Y = point.Y; - } - - public static implicit operator Point(POINT p) - { - return new Point(p.X, p.Y); - } - - public static implicit operator POINT(Point p) - { - return new POINT(p.X, p.Y); - } - - public Point ToPoint() - { - return new Point(X, Y); - } - - public override string ToString() - { - return X + "," + Y; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential), Serializable()] + public struct POINT + { + public int X; + public int Y; + + public POINT(int x, int y) + { + X = x; + Y = y; + } + + public POINT(Point point) + { + X = point.X; + Y = point.Y; + } + + public static implicit operator Point(POINT p) + { + return new Point(p.X, p.Y); + } + + public static implicit operator POINT(Point p) + { + return new POINT(p.X, p.Y); + } + + public Point ToPoint() + { + return new Point(X, Y); + } + + public override string ToString() + { + return X + "," + Y; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/RECT.cs similarity index 95% rename from src/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/RECT.cs index 4541c7445..f50b17544 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/RECT.cs @@ -1,176 +1,176 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct RECT - { - private int _Left; - private int _Top; - private int _Right; - private int _Bottom; - - public RECT(RECT rectangle) - : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) - { - } - - public RECT(Rectangle rectangle) - : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) - { - } - - public RECT(int left, int top, int right, int bottom) - { - _Left = left; - _Top = top; - _Right = right; - _Bottom = bottom; - } - - public int X - { - get { return _Left; } - set { _Left = value; } - } - - public int Y - { - get { return _Top; } - set { _Top = value; } - } - - public int Left - { - get { return _Left; } - set { _Left = value; } - } - - public int Top - { - get { return _Top; } - set { _Top = value; } - } - - public int Right - { - get { return _Right; } - set { _Right = value; } - } - - public int Bottom - { - get { return _Bottom; } - set { _Bottom = value; } - } - - public int Height - { - get { return _Bottom - _Top; } - set { _Bottom = value - _Top; } - } - - public int Width - { - get { return _Right - _Left; } - set { _Right = value + _Left; } - } - - public Point Location - { - get { return new Point(Left, Top); } - set - { - _Left = value.X; - _Top = value.Y; - } - } - - public Size Size - { - get { return new Size(Width, Height); } - set - { - _Right = value.Width + _Left; - _Bottom = value.Height + _Top; - } - } - - public static implicit operator Rectangle(RECT rectangle) - { - return new Rectangle(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height); - } - - public static implicit operator RECT(Rectangle rectangle) - { - return new RECT(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); - } - - public static bool operator ==(RECT rectangle1, RECT rectangle2) - { - return rectangle1.Equals(rectangle2); - } - - public static bool operator !=(RECT rectangle1, RECT rectangle2) - { - return !rectangle1.Equals(rectangle2); - } - - public override string ToString() - { - return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}"; - } - - public override int GetHashCode() - { - return ToString().GetHashCode(); - } - - public bool Equals(RECT rectangle) - { - return rectangle.Left == _Left && rectangle.Top == _Top && rectangle.Right == _Right && rectangle.Bottom == _Bottom; - } - - public Rectangle ToRectangle() - { - return new Rectangle(Left, Top, Width, Height); - } - - public override bool Equals(object Object) - { - if (Object is RECT) - { - return Equals((RECT) Object); - } - else if (Object is Rectangle) - { - return Equals(new RECT((Rectangle) Object)); - } - - return false; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential), Serializable()] + public struct RECT + { + private int _Left; + private int _Top; + private int _Right; + private int _Bottom; + + public RECT(RECT rectangle) + : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) + { + } + + public RECT(Rectangle rectangle) + : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) + { + } + + public RECT(int left, int top, int right, int bottom) + { + _Left = left; + _Top = top; + _Right = right; + _Bottom = bottom; + } + + public int X + { + get { return _Left; } + set { _Left = value; } + } + + public int Y + { + get { return _Top; } + set { _Top = value; } + } + + public int Left + { + get { return _Left; } + set { _Left = value; } + } + + public int Top + { + get { return _Top; } + set { _Top = value; } + } + + public int Right + { + get { return _Right; } + set { _Right = value; } + } + + public int Bottom + { + get { return _Bottom; } + set { _Bottom = value; } + } + + public int Height + { + get { return _Bottom - _Top; } + set { _Bottom = value - _Top; } + } + + public int Width + { + get { return _Right - _Left; } + set { _Right = value + _Left; } + } + + public Point Location + { + get { return new Point(Left, Top); } + set + { + _Left = value.X; + _Top = value.Y; + } + } + + public Size Size + { + get { return new Size(Width, Height); } + set + { + _Right = value.Width + _Left; + _Bottom = value.Height + _Top; + } + } + + public static implicit operator Rectangle(RECT rectangle) + { + return new Rectangle(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height); + } + + public static implicit operator RECT(Rectangle rectangle) + { + return new RECT(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); + } + + public static bool operator ==(RECT rectangle1, RECT rectangle2) + { + return rectangle1.Equals(rectangle2); + } + + public static bool operator !=(RECT rectangle1, RECT rectangle2) + { + return !rectangle1.Equals(rectangle2); + } + + public override string ToString() + { + return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}"; + } + + public override int GetHashCode() + { + return ToString().GetHashCode(); + } + + public bool Equals(RECT rectangle) + { + return rectangle.Left == _Left && rectangle.Top == _Top && rectangle.Right == _Right && rectangle.Bottom == _Bottom; + } + + public Rectangle ToRectangle() + { + return new Rectangle(Left, Top, Width, Height); + } + + public override bool Equals(object Object) + { + if (Object is RECT) + { + return Equals((RECT) Object); + } + else if (Object is Rectangle) + { + return Equals(new RECT((Rectangle) Object)); + } + + return false; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/RECTF.cs similarity index 96% rename from src/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/RECTF.cs index 00aa12c09..2434e9266 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/RECTF.cs @@ -1,131 +1,131 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - /// - /// A floating point GDI Plus width/hight based rectangle. - /// - [StructLayout(LayoutKind.Sequential)] - public struct RECTF - { - /// - /// The X corner location of the rectangle. - /// - public float X; - - /// - /// The Y corner location of the rectangle. - /// - public float Y; - - /// - /// The width of the rectangle. - /// - public float Width; - - /// - /// The height of the rectangle. - /// - public float Height; - - /// - /// Creates a new GDI Plus rectangle. - /// - /// The X corner location of the rectangle. - /// The Y corner location of the rectangle. - /// The width of the rectangle. - /// The height of the rectangle. - public RECTF(float x, float y, float width, float height) - { - X = x; - Y = y; - Width = width; - Height = height; - } - - /// - /// Creates a new GDI Plus rectangle from a System.Drawing.RectangleF. - /// - /// The rectangle to base this GDI Plus rectangle on. - public RECTF(RectangleF rect) - { - X = rect.X; - Y = rect.Y; - Width = rect.Width; - Height = rect.Height; - } - - /// - /// Creates a new GDI Plus rectangle from a System.Drawing.Rectangle. - /// - /// The rectangle to base this GDI Plus rectangle on. - public RECTF(Rectangle rect) - { - X = rect.X; - Y = rect.Y; - Width = rect.Width; - Height = rect.Height; - } - - /// - /// Returns a RectangleF for this GDI Plus rectangle. - /// - /// A System.Drawing.RectangleF structure. - public RectangleF ToRectangle() - { - return new RectangleF(X, Y, Width, Height); - } - - /// - /// Returns a RectangleF for a GDI Plus rectangle. - /// - /// The GDI Plus rectangle to get the RectangleF for. - /// A System.Drawing.RectangleF structure. - public static RectangleF ToRectangle(RECTF rect) - { - return rect.ToRectangle(); - } - - /// - /// Returns a GDI Plus rectangle for a RectangleF structure. - /// - /// The RectangleF to get the GDI Plus rectangle for. - /// A GDI Plus rectangle structure. - public static RECTF FromRectangle(RectangleF rect) - { - return new RECTF(rect); - } - - /// - /// Returns a GDI Plus rectangle for a Rectangle structure. - /// - /// The Rectangle to get the GDI Plus rectangle for. - /// A GDI Plus rectangle structure. - public static RECTF FromRectangle(Rectangle rect) - { - return new RECTF(rect); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + /// + /// A floating point GDI Plus width/hight based rectangle. + /// + [StructLayout(LayoutKind.Sequential)] + public struct RECTF + { + /// + /// The X corner location of the rectangle. + /// + public float X; + + /// + /// The Y corner location of the rectangle. + /// + public float Y; + + /// + /// The width of the rectangle. + /// + public float Width; + + /// + /// The height of the rectangle. + /// + public float Height; + + /// + /// Creates a new GDI Plus rectangle. + /// + /// The X corner location of the rectangle. + /// The Y corner location of the rectangle. + /// The width of the rectangle. + /// The height of the rectangle. + public RECTF(float x, float y, float width, float height) + { + X = x; + Y = y; + Width = width; + Height = height; + } + + /// + /// Creates a new GDI Plus rectangle from a System.Drawing.RectangleF. + /// + /// The rectangle to base this GDI Plus rectangle on. + public RECTF(RectangleF rect) + { + X = rect.X; + Y = rect.Y; + Width = rect.Width; + Height = rect.Height; + } + + /// + /// Creates a new GDI Plus rectangle from a System.Drawing.Rectangle. + /// + /// The rectangle to base this GDI Plus rectangle on. + public RECTF(Rectangle rect) + { + X = rect.X; + Y = rect.Y; + Width = rect.Width; + Height = rect.Height; + } + + /// + /// Returns a RectangleF for this GDI Plus rectangle. + /// + /// A System.Drawing.RectangleF structure. + public RectangleF ToRectangle() + { + return new RectangleF(X, Y, Width, Height); + } + + /// + /// Returns a RectangleF for a GDI Plus rectangle. + /// + /// The GDI Plus rectangle to get the RectangleF for. + /// A System.Drawing.RectangleF structure. + public static RectangleF ToRectangle(RECTF rect) + { + return rect.ToRectangle(); + } + + /// + /// Returns a GDI Plus rectangle for a RectangleF structure. + /// + /// The RectangleF to get the GDI Plus rectangle for. + /// A GDI Plus rectangle structure. + public static RECTF FromRectangle(RectangleF rect) + { + return new RECTF(rect); + } + + /// + /// Returns a GDI Plus rectangle for a Rectangle structure. + /// + /// The Rectangle to get the GDI Plus rectangle for. + /// A GDI Plus rectangle structure. + public static RECTF FromRectangle(Rectangle rect) + { + return new RECTF(rect); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/SCROLLINFO.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/SCROLLINFO.cs index d2157e966..718abebcf 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/SCROLLINFO.cs @@ -1,38 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [Serializable, StructLayout(LayoutKind.Sequential)] - public struct SCROLLINFO - { - public int cbSize; - public int fMask; - public int nMin; - public int nMax; - public int nPage; - public int nPos; - public int nTrackPos; - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [Serializable, StructLayout(LayoutKind.Sequential)] + public struct SCROLLINFO + { + public int cbSize; + public int fMask; + public int nMin; + public int nMax; + public int nPage; + public int nPos; + public int nTrackPos; + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/SIZE.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/SIZE.cs index 531fa977d..93d583c4c 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/SIZE.cs @@ -1,51 +1,51 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct SIZE - { - public int Width; - public int Height; - - public SIZE(Size size) : this(size.Width, size.Height) - { - } - - public SIZE(int width, int height) - { - Width = width; - Height = height; - } - - public Size ToSize() - { - return new Size(Width, Height); - } - - public bool IsEmpty => Width * Height == 0; - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential), Serializable()] + public struct SIZE + { + public int Width; + public int Height; + + public SIZE(Size size) : this(size.Width, size.Height) + { + } + + public SIZE(int width, int height) + { + Width = width; + Height = height; + } + + public Size ToSize() + { + return new Size(Width, Height); + } + + public bool IsEmpty => Width * Height == 0; + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowInfo.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/WindowInfo.cs index 237fca4b8..ad8c60812 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowInfo.cs @@ -1,52 +1,52 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - /// - /// The structure for the WindowInfo - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632610%28v=vs.85%29.aspx - /// - [StructLayout(LayoutKind.Sequential), Serializable] - public struct WindowInfo - { - public uint cbSize; - public RECT rcWindow; - public RECT rcClient; - public uint dwStyle; - public uint dwExStyle; - public uint dwWindowStatus; - public uint cxWindowBorders; - public uint cyWindowBorders; - public ushort atomWindowType; - - public ushort wCreatorVersion; - - // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)". - public WindowInfo(bool? filler) : this() - { - cbSize = (uint) (Marshal.SizeOf(typeof(WindowInfo))); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + /// + /// The structure for the WindowInfo + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632610%28v=vs.85%29.aspx + /// + [StructLayout(LayoutKind.Sequential), Serializable] + public struct WindowInfo + { + public uint cbSize; + public RECT rcWindow; + public RECT rcClient; + public uint dwStyle; + public uint dwExStyle; + public uint dwWindowStatus; + public uint cxWindowBorders; + public uint cyWindowBorders; + public ushort atomWindowType; + + public ushort wCreatorVersion; + + // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)". + public WindowInfo(bool? filler) : this() + { + cbSize = (uint) (Marshal.SizeOf(typeof(WindowInfo))); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowPlacement.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/WindowPlacement.cs index c1f064c48..fa981b8bf 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowPlacement.cs @@ -1,80 +1,80 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - /// - /// Contains information about the placement of a window on the screen. - /// - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct WindowPlacement - { - /// - /// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT). - /// - /// GetWindowPlacement and SetWindowPlacement fail if this member is not set correctly. - /// - /// - public int Length; - - /// - /// Specifies flags that control the position of the minimized window and the method by which the window is restored. - /// - public WindowPlacementFlags Flags; - - /// - /// The current show state of the window. - /// - public ShowWindowCommand ShowCmd; - - /// - /// The coordinates of the window's upper-left corner when the window is minimized. - /// - public POINT MinPosition; - - /// - /// The coordinates of the window's upper-left corner when the window is maximized. - /// - public POINT MaxPosition; - - /// - /// The window's coordinates when the window is in the restored position. - /// - public RECT NormalPosition; - - /// - /// Gets the default (empty) value. - /// - public static WindowPlacement Default - { - get - { - WindowPlacement result = new WindowPlacement(); - result.Length = Marshal.SizeOf(result); - return result; - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + /// + /// Contains information about the placement of a window on the screen. + /// + [StructLayout(LayoutKind.Sequential), Serializable()] + public struct WindowPlacement + { + /// + /// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT). + /// + /// GetWindowPlacement and SetWindowPlacement fail if this member is not set correctly. + /// + /// + public int Length; + + /// + /// Specifies flags that control the position of the minimized window and the method by which the window is restored. + /// + public WindowPlacementFlags Flags; + + /// + /// The current show state of the window. + /// + public ShowWindowCommand ShowCmd; + + /// + /// The coordinates of the window's upper-left corner when the window is minimized. + /// + public POINT MinPosition; + + /// + /// The coordinates of the window's upper-left corner when the window is maximized. + /// + public POINT MaxPosition; + + /// + /// The window's coordinates when the window is in the restored position. + /// + public RECT NormalPosition; + + /// + /// Gets the default (empty) value. + /// + public static WindowPlacement Default + { + get + { + WindowPlacement result = new WindowPlacement(); + result.Length = Marshal.SizeOf(result); + return result; + } + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/User32.cs b/src/Greenshot.Base/UnmanagedHelpers/User32.cs similarity index 96% rename from src/GreenshotPlugin/UnmanagedHelpers/User32.cs rename to src/Greenshot.Base/UnmanagedHelpers/User32.cs index 2cedb28f7..1f6c39c24 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/User32.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/User32.cs @@ -1,333 +1,333 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Text; -using System.Windows.Forms; -using log4net; -using GreenshotPlugin.Core.Enums; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// User32 Wrappers - /// - public static class User32 - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(User32)); - private static bool _CanCallGetPhysicalCursorPos = true; - public const int SC_RESTORE = 0xF120; - public const int SC_MAXIMIZE = 0xF030; - public const int SC_MINIMIZE = 0xF020; - - // For MonitorFromWindow - public const int MONITOR_DEFAULTTONULL = 0; - public const int MONITOR_DEFAULTTONEAREST = 2; - public const int CURSOR_SHOWING = 0x00000001; - - /// - /// Determines whether the specified window handle identifies an existing window. - /// - /// A handle to the window to be tested. - /// - /// If the window handle identifies an existing window, the return value is true. - /// If the window handle does not identify an existing window, the return value is false. - /// - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindow(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindowVisible(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId); - - [DllImport("user32", SetLastError = true)] - public static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId); - - [DllImport("user32")] - public static extern IntPtr AttachThreadInput(int idAttach, int idAttachTo, int fAttach); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetParent(IntPtr hWnd); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int cch); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool BringWindowToTop(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetForegroundWindow(); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetDesktopWindow(); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetForegroundWindow(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WindowPlacement lpwndpl); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsIconic(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsZoomed(IntPtr hWnd); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); - - [DllImport("user32", SetLastError = true)] - public static extern uint GetClassLong(IntPtr hWnd, int nIndex); - - [DllImport("user32", SetLastError = true, EntryPoint = "GetClassLongPtr")] - public static extern IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, uint nFlags); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")] - public static extern int GetWindowLong(IntPtr hWnd, int index); - - [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")] - public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int SetWindowLong(IntPtr hWnd, int index, int styleFlags); - - [DllImport("user32", SetLastError = true, EntryPoint = "SetWindowLongPtr")] - public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int index, IntPtr styleFlags); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr MonitorFromWindow(IntPtr hWnd, MonitorFrom dwFlags); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowInfo(IntPtr hWnd, ref WindowInfo pwi); - - [DllImport("user32", SetLastError = true)] - public static extern int EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); - - [DllImport("user32", SetLastError = true)] - public static extern RegionResult GetWindowRgn(IntPtr hWnd, SafeHandle hRgn); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, WindowPos uFlags); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetClipboardOwner(); - - // Added for finding Metro apps, Greenshot 1.1 - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow); - - /// uiFlags: 0 - Count of GDI objects - /// uiFlags: 1 - Count of USER objects - /// - Win32 GDI objects (pens, brushes, fonts, palettes, regions, device contexts, bitmap headers) - /// - Win32 USER objects: - /// - WIN32 resources (accelerator tables, bitmap resources, dialog box templates, font resources, menu resources, raw data resources, string table entries, message table entries, cursors/icons) - /// - Other USER objects (windows, menus) - /// - [DllImport("user32", SetLastError = true)] - public static extern uint GetGuiResources(IntPtr hProcess, uint uiFlags); - - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint RegisterWindowMessage(string lpString); - - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult); - - [DllImport("user32", SetLastError = true)] - private static extern bool GetPhysicalCursorPos(out POINT cursorLocation); - - /// - /// The following is used for Icon handling - /// - /// - /// - [DllImport("user32", SetLastError = true)] - public static extern SafeIconHandle CopyIcon(IntPtr hIcon); - - [DllImport("user32", SetLastError = true)] - public static extern bool DestroyIcon(IntPtr hIcon); - - [DllImport("user32", SetLastError = true)] - public static extern bool GetCursorInfo(out CursorInfo cursorInfo); - - [DllImport("user32", SetLastError = true)] - public static extern bool GetIconInfo(SafeIconHandle iconHandle, out IconInfo iconInfo); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr SetCapture(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool ReleaseCapture(); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr CreateIconIndirect(ref IconInfo icon); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, DesktopAccessRight dwDesiredAccess); - - [DllImport("user32", SetLastError = true)] - public static extern bool SetThreadDesktop(IntPtr hDesktop); - - [DllImport("user32", SetLastError = true)] - public static extern bool CloseDesktop(IntPtr hDesktop); - - /// - /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. - /// - /// Point with cursor location, relative to the origin of the monitor setup - /// (i.e. negative coordinates arepossible in multiscreen setups) - public static Point GetCursorLocation() - { - if (Environment.OSVersion.Version.Major >= 6 && _CanCallGetPhysicalCursorPos) - { - try - { - if (GetPhysicalCursorPos(out var cursorLocation)) - { - return new Point(cursorLocation.X, cursorLocation.Y); - } - - Win32Error error = Win32.GetLastErrorCode(); - LOG.ErrorFormat("Error retrieving PhysicalCursorPos : {0}", Win32.GetMessage(error)); - } - catch (Exception ex) - { - LOG.Error("Exception retrieving PhysicalCursorPos, no longer calling this. Cause :", ex); - _CanCallGetPhysicalCursorPos = false; - } - } - - return new Point(Cursor.Position.X, Cursor.Position.Y); - } - - /// - /// Wrapper for the GetClassLong which decides if the system is 64-bit or not and calls the right one. - /// - /// IntPtr - /// int - /// IntPtr - public static IntPtr GetClassLongWrapper(IntPtr hWnd, int nIndex) - { - if (IntPtr.Size > 4) - { - return GetClassLongPtr(hWnd, nIndex); - } - else - { - return new IntPtr(GetClassLong(hWnd, nIndex)); - } - } - - /// - /// Wrapper for the GetWindowLong which decides if the system is 64-bit or not and calls the right one. - /// - /// - /// - /// - public static long GetWindowLongWrapper(IntPtr hWnd, int nIndex) - { - if (IntPtr.Size == 8) - { - return GetWindowLongPtr(hWnd, nIndex).ToInt64(); - } - else - { - return GetWindowLong(hWnd, nIndex); - } - } - - /// - /// Wrapper for the SetWindowLong which decides if the system is 64-bit or not and calls the right one. - /// - /// - /// - /// - public static void SetWindowLongWrapper(IntPtr hWnd, int nIndex, IntPtr styleFlags) - { - if (IntPtr.Size == 8) - { - SetWindowLongPtr(hWnd, nIndex, styleFlags); - } - else - { - SetWindowLong(hWnd, nIndex, styleFlags.ToInt32()); - } - } - - public static uint GetGuiResourcesGDICount() - { - using var currentProcess = Process.GetCurrentProcess(); - return GetGuiResources(currentProcess.Handle, 0); - } - - public static uint GetGuiResourcesUserCount() - { - using var currentProcess = Process.GetCurrentProcess(); - return GetGuiResources(currentProcess.Handle, 1); - } - - /// - /// Helper method to create a Win32 exception with the windows message in it - /// - /// string with current method - /// Exception - public static Exception CreateWin32Exception(string method) - { - var exceptionToThrow = new Win32Exception(); - exceptionToThrow.Data.Add("Method", method); - return exceptionToThrow; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using Greenshot.Base.Core.Enums; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; +using log4net; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// User32 Wrappers + /// + public static class User32 + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(User32)); + private static bool _CanCallGetPhysicalCursorPos = true; + public const int SC_RESTORE = 0xF120; + public const int SC_MAXIMIZE = 0xF030; + public const int SC_MINIMIZE = 0xF020; + + // For MonitorFromWindow + public const int MONITOR_DEFAULTTONULL = 0; + public const int MONITOR_DEFAULTTONEAREST = 2; + public const int CURSOR_SHOWING = 0x00000001; + + /// + /// Determines whether the specified window handle identifies an existing window. + /// + /// A handle to the window to be tested. + /// + /// If the window handle identifies an existing window, the return value is true. + /// If the window handle does not identify an existing window, the return value is false. + /// + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindow(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindowVisible(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId); + + [DllImport("user32", SetLastError = true)] + public static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId); + + [DllImport("user32")] + public static extern IntPtr AttachThreadInput(int idAttach, int idAttachTo, int fAttach); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetParent(IntPtr hWnd); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int cch); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool BringWindowToTop(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetDesktopWindow(); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetForegroundWindow(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WindowPlacement lpwndpl); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsIconic(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsZoomed(IntPtr hWnd); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); + + [DllImport("user32", SetLastError = true)] + public static extern uint GetClassLong(IntPtr hWnd, int nIndex); + + [DllImport("user32", SetLastError = true, EntryPoint = "GetClassLongPtr")] + public static extern IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, uint nFlags); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); + + [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")] + public static extern int GetWindowLong(IntPtr hWnd, int index); + + [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")] + public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int SetWindowLong(IntPtr hWnd, int index, int styleFlags); + + [DllImport("user32", SetLastError = true, EntryPoint = "SetWindowLongPtr")] + public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int index, IntPtr styleFlags); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr MonitorFromWindow(IntPtr hWnd, MonitorFrom dwFlags); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowInfo(IntPtr hWnd, ref WindowInfo pwi); + + [DllImport("user32", SetLastError = true)] + public static extern int EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); + + [DllImport("user32", SetLastError = true)] + public static extern RegionResult GetWindowRgn(IntPtr hWnd, SafeHandle hRgn); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, WindowPos uFlags); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetClipboardOwner(); + + // Added for finding Metro apps, Greenshot 1.1 + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow); + + /// uiFlags: 0 - Count of GDI objects + /// uiFlags: 1 - Count of USER objects + /// - Win32 GDI objects (pens, brushes, fonts, palettes, regions, device contexts, bitmap headers) + /// - Win32 USER objects: + /// - WIN32 resources (accelerator tables, bitmap resources, dialog box templates, font resources, menu resources, raw data resources, string table entries, message table entries, cursors/icons) + /// - Other USER objects (windows, menus) + /// + [DllImport("user32", SetLastError = true)] + public static extern uint GetGuiResources(IntPtr hProcess, uint uiFlags); + + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint RegisterWindowMessage(string lpString); + + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult); + + [DllImport("user32", SetLastError = true)] + private static extern bool GetPhysicalCursorPos(out POINT cursorLocation); + + /// + /// The following is used for Icon handling + /// + /// + /// + [DllImport("user32", SetLastError = true)] + public static extern SafeIconHandle CopyIcon(IntPtr hIcon); + + [DllImport("user32", SetLastError = true)] + public static extern bool DestroyIcon(IntPtr hIcon); + + [DllImport("user32", SetLastError = true)] + public static extern bool GetCursorInfo(out CursorInfo cursorInfo); + + [DllImport("user32", SetLastError = true)] + public static extern bool GetIconInfo(SafeIconHandle iconHandle, out IconInfo iconInfo); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr SetCapture(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ReleaseCapture(); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr CreateIconIndirect(ref IconInfo icon); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, DesktopAccessRight dwDesiredAccess); + + [DllImport("user32", SetLastError = true)] + public static extern bool SetThreadDesktop(IntPtr hDesktop); + + [DllImport("user32", SetLastError = true)] + public static extern bool CloseDesktop(IntPtr hDesktop); + + /// + /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. + /// + /// Point with cursor location, relative to the origin of the monitor setup + /// (i.e. negative coordinates arepossible in multiscreen setups) + public static Point GetCursorLocation() + { + if (Environment.OSVersion.Version.Major >= 6 && _CanCallGetPhysicalCursorPos) + { + try + { + if (GetPhysicalCursorPos(out var cursorLocation)) + { + return new Point(cursorLocation.X, cursorLocation.Y); + } + + Win32Error error = Win32.GetLastErrorCode(); + LOG.ErrorFormat("Error retrieving PhysicalCursorPos : {0}", Win32.GetMessage(error)); + } + catch (Exception ex) + { + LOG.Error("Exception retrieving PhysicalCursorPos, no longer calling this. Cause :", ex); + _CanCallGetPhysicalCursorPos = false; + } + } + + return new Point(Cursor.Position.X, Cursor.Position.Y); + } + + /// + /// Wrapper for the GetClassLong which decides if the system is 64-bit or not and calls the right one. + /// + /// IntPtr + /// int + /// IntPtr + public static IntPtr GetClassLongWrapper(IntPtr hWnd, int nIndex) + { + if (IntPtr.Size > 4) + { + return GetClassLongPtr(hWnd, nIndex); + } + else + { + return new IntPtr(GetClassLong(hWnd, nIndex)); + } + } + + /// + /// Wrapper for the GetWindowLong which decides if the system is 64-bit or not and calls the right one. + /// + /// + /// + /// + public static long GetWindowLongWrapper(IntPtr hWnd, int nIndex) + { + if (IntPtr.Size == 8) + { + return GetWindowLongPtr(hWnd, nIndex).ToInt64(); + } + else + { + return GetWindowLong(hWnd, nIndex); + } + } + + /// + /// Wrapper for the SetWindowLong which decides if the system is 64-bit or not and calls the right one. + /// + /// + /// + /// + public static void SetWindowLongWrapper(IntPtr hWnd, int nIndex, IntPtr styleFlags) + { + if (IntPtr.Size == 8) + { + SetWindowLongPtr(hWnd, nIndex, styleFlags); + } + else + { + SetWindowLong(hWnd, nIndex, styleFlags.ToInt32()); + } + } + + public static uint GetGuiResourcesGDICount() + { + using var currentProcess = Process.GetCurrentProcess(); + return GetGuiResources(currentProcess.Handle, 0); + } + + public static uint GetGuiResourcesUserCount() + { + using var currentProcess = Process.GetCurrentProcess(); + return GetGuiResources(currentProcess.Handle, 1); + } + + /// + /// Helper method to create a Win32 exception with the windows message in it + /// + /// string with current method + /// Exception + public static Exception CreateWin32Exception(string method) + { + var exceptionToThrow = new Win32Exception(); + exceptionToThrow.Data.Add("Method", method); + return exceptionToThrow; + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/Win32.cs b/src/Greenshot.Base/UnmanagedHelpers/Win32.cs similarity index 93% rename from src/GreenshotPlugin/UnmanagedHelpers/Win32.cs rename to src/Greenshot.Base/UnmanagedHelpers/Win32.cs index 2721572f0..940dc4e95 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/Win32.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Win32.cs @@ -1,69 +1,69 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; -using System.Text; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - public static class Win32 - { - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - private static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer, int nSize, IntPtr arguments); - - [DllImport("kernel32.dll")] - public static extern void SetLastError(uint dwErrCode); - - public static Win32Error GetLastErrorCode() - { - return (Win32Error) Marshal.GetLastWin32Error(); - } - - public static string GetMessage(Win32Error errorCode) - { - var buffer = new StringBuilder(0x100); - - if (FormatMessage(0x3200, IntPtr.Zero, (uint) errorCode, 0, buffer, buffer.Capacity, IntPtr.Zero) == 0) - { - return "Unknown error (0x" + ((int) errorCode).ToString("x") + ")"; - } - - var result = new StringBuilder(); - int i = 0; - - while (i < buffer.Length) - { - if (!char.IsLetterOrDigit(buffer[i]) && - !char.IsPunctuation(buffer[i]) && - !char.IsSymbol(buffer[i]) && - !char.IsWhiteSpace(buffer[i])) - break; - - result.Append(buffer[i]); - i++; - } - - return result.ToString().Replace("\r\n", string.Empty); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; +using System.Text; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.UnmanagedHelpers +{ + public static class Win32 + { + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + private static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer, int nSize, IntPtr arguments); + + [DllImport("kernel32.dll")] + public static extern void SetLastError(uint dwErrCode); + + public static Win32Error GetLastErrorCode() + { + return (Win32Error) Marshal.GetLastWin32Error(); + } + + public static string GetMessage(Win32Error errorCode) + { + var buffer = new StringBuilder(0x100); + + if (FormatMessage(0x3200, IntPtr.Zero, (uint) errorCode, 0, buffer, buffer.Capacity, IntPtr.Zero) == 0) + { + return "Unknown error (0x" + ((int) errorCode).ToString("x") + ")"; + } + + var result = new StringBuilder(); + int i = 0; + + while (i < buffer.Length) + { + if (!char.IsLetterOrDigit(buffer[i]) && + !char.IsPunctuation(buffer[i]) && + !char.IsSymbol(buffer[i]) && + !char.IsWhiteSpace(buffer[i])) + break; + + result.Append(buffer[i]); + i++; + } + + return result.ToString().Replace("\r\n", string.Empty); + } + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs b/src/Greenshot.Base/UnmanagedHelpers/WinEventDelegate.cs similarity index 84% rename from src/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs rename to src/Greenshot.Base/UnmanagedHelpers/WinEventDelegate.cs index 551b75410..bd54923f7 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/WinEventDelegate.cs @@ -1,17 +1,17 @@ -using System; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// Used with SetWinEventHook - /// - /// - /// - /// - /// - /// - /// - /// - public delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); +using System; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Used with SetWinEventHook + /// + /// + /// + /// + /// + /// + /// + /// + public delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); } \ No newline at end of file diff --git a/src/GreenshotPlugin/UnmanagedHelpers/WinMM.cs b/src/Greenshot.Base/UnmanagedHelpers/WinMM.cs similarity index 94% rename from src/GreenshotPlugin/UnmanagedHelpers/WinMM.cs rename to src/Greenshot.Base/UnmanagedHelpers/WinMM.cs index 25bb503b4..411ecdca1 100644 --- a/src/GreenshotPlugin/UnmanagedHelpers/WinMM.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/WinMM.cs @@ -1,38 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// Windows Media - /// - public class WinMM - { - [DllImport("winmm.dll", SetLastError = true)] - public static extern bool PlaySound(byte[] ptrToSound, UIntPtr hmod, uint fdwSound); - - [DllImport("winmm.dll", SetLastError = true)] - public static extern bool PlaySound(IntPtr ptrToSound, UIntPtr hmod, uint fdwSound); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Windows Media + /// + public class WinMM + { + [DllImport("winmm.dll", SetLastError = true)] + public static extern bool PlaySound(byte[] ptrToSound, UIntPtr hmod, uint fdwSound); + + [DllImport("winmm.dll", SetLastError = true)] + public static extern bool PlaySound(IntPtr ptrToSound, UIntPtr hmod, uint fdwSound); + } } \ No newline at end of file diff --git a/src/GreenshotPlugin/log4net-embedded.xml b/src/Greenshot.Base/log4net-embedded.xml similarity index 97% rename from src/GreenshotPlugin/log4net-embedded.xml rename to src/Greenshot.Base/log4net-embedded.xml index ccfa902a7..b4ced5bad 100644 --- a/src/GreenshotPlugin/log4net-embedded.xml +++ b/src/Greenshot.Base/log4net-embedded.xml @@ -1,21 +1,21 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/BoxConfiguration.cs b/src/Greenshot.Plugin.Box/BoxConfiguration.cs index a4d83ef68..15e458109 100644 --- a/src/Greenshot.Plugin.Box/BoxConfiguration.cs +++ b/src/Greenshot.Plugin.Box/BoxConfiguration.cs @@ -21,9 +21,9 @@ using System; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; using Greenshot.Plugin.Box.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; namespace Greenshot.Plugin.Box { diff --git a/src/Greenshot.Plugin.Box/BoxDestination.cs b/src/Greenshot.Plugin.Box/BoxDestination.cs index 0bc547b88..989c0aad0 100644 --- a/src/Greenshot.Plugin.Box/BoxDestination.cs +++ b/src/Greenshot.Plugin.Box/BoxDestination.cs @@ -21,8 +21,8 @@ using System.ComponentModel; using System.Drawing; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; namespace Greenshot.Plugin.Box { diff --git a/src/Greenshot.Plugin.Box/BoxPlugin.cs b/src/Greenshot.Plugin.Box/BoxPlugin.cs index 9918b5e93..8aba68183 100644 --- a/src/Greenshot.Plugin.Box/BoxPlugin.cs +++ b/src/Greenshot.Plugin.Box/BoxPlugin.cs @@ -24,11 +24,11 @@ using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.Box { diff --git a/src/Greenshot.Plugin.Box/BoxUtils.cs b/src/Greenshot.Plugin.Box/BoxUtils.cs index 37a0eac53..4634d845e 100644 --- a/src/Greenshot.Plugin.Box/BoxUtils.cs +++ b/src/Greenshot.Plugin.Box/BoxUtils.cs @@ -23,9 +23,9 @@ using System.Collections.Generic; using System.IO; using System.Runtime.Serialization.Json; using System.Text; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.OAuth; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.Box { diff --git a/src/Greenshot.Plugin.Box/Forms/BoxForm.cs b/src/Greenshot.Plugin.Box/Forms/BoxForm.cs index 646bdf87b..96776ab92 100644 --- a/src/Greenshot.Plugin.Box/Forms/BoxForm.cs +++ b/src/Greenshot.Plugin.Box/Forms/BoxForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Plugin.Box.Forms { diff --git a/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs index 6b8f68242..1714ff65e 100644 --- a/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Plugin.Box.Forms { partial class SettingsForm { /// @@ -46,12 +49,12 @@ namespace Greenshot.Plugin.Box.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.label_AfterUpload = new GreenshotLabel(); + this.checkboxAfterUploadLinkToClipBoard = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -138,11 +141,11 @@ namespace Greenshot.Plugin.Box.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotLabel label_AfterUpload; + private GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; } } diff --git a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj index 990e9ddc4..789ebd424 100644 --- a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj +++ b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj @@ -10,6 +10,6 @@ - + \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Confluence.cs b/src/Greenshot.Plugin.Confluence/Confluence.cs index 79d11a034..b139c041e 100644 --- a/src/Greenshot.Plugin.Confluence/Confluence.cs +++ b/src/Greenshot.Plugin.Confluence/Confluence.cs @@ -22,9 +22,9 @@ using System; using System.Collections.Generic; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; using GreenshotConfluencePlugin.confluence; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; namespace Greenshot.Plugin.Confluence { diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs index df23e7768..400f3c352 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs @@ -20,8 +20,8 @@ */ using System; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.Confluence { diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs index 275ace4d1..70af706bd 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs @@ -26,11 +26,11 @@ using System.Drawing; using System.IO; using System.Threading; using System.Windows; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.Confluence { diff --git a/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs index fbe852691..6878192a1 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs @@ -21,12 +21,12 @@ using System; using System.Windows; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Confluence.Forms; using Greenshot.Plugin.Confluence.Support; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; namespace Greenshot.Plugin.Confluence { diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs b/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs index 2c878d6d9..249b97f77 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs @@ -24,7 +24,7 @@ using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Automation; -using GreenshotPlugin.Core; +using Greenshot.Base.Core; namespace Greenshot.Plugin.Confluence { diff --git a/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs b/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs index c4023a828..3b3e3f95f 100644 --- a/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs +++ b/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs @@ -26,7 +26,7 @@ using System.Collections.ObjectModel; using System.Globalization; using System.Reflection; using System.Windows.Data; -using GreenshotPlugin.Core; +using Greenshot.Base.Core; namespace Greenshot.Plugin.Confluence { diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml index 2b747d831..7ab7933e8 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml @@ -1,8 +1,7 @@  diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs index 2b296f5f0..c5f44014b 100644 --- a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs @@ -23,7 +23,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Windows; -using GreenshotPlugin.IniFile; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.Confluence.Forms { diff --git a/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj b/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj index 79b55313a..f4a7f9c16 100644 --- a/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj +++ b/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj @@ -26,7 +26,7 @@ - + diff --git a/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs b/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs index 926e7ad8e..e15e67555 100644 --- a/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs +++ b/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs @@ -1,4 +1,4 @@ -using GreenshotPlugin.Core; +using Greenshot.Base.Core; namespace Greenshot.Plugin.Confluence.Support { diff --git a/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs index 61f7a8705..715d96ded 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs @@ -21,9 +21,9 @@ using System.ComponentModel; using System.Drawing; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; namespace Greenshot.Plugin.Dropbox { diff --git a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs index 1ec893423..b3c19d1a5 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs @@ -23,11 +23,11 @@ using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.Dropbox { diff --git a/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs b/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs index 4a2bd95d0..5925a1729 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs @@ -21,9 +21,9 @@ using System; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; using Greenshot.Plugin.Dropbox.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; namespace Greenshot.Plugin.Dropbox { diff --git a/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs index ebb7b2685..7307b2a26 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs @@ -22,11 +22,11 @@ using System; using System.Collections.Generic; using System.IO; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.OAuth; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Newtonsoft.Json; namespace Greenshot.Plugin.Dropbox diff --git a/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs b/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs index b39d1e14d..1f1bfd5ea 100644 --- a/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs +++ b/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Plugin.Dropbox.Forms { diff --git a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs index c7f21fd24..e80470dd5 100644 --- a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Plugin.Dropbox.Forms { partial class SettingsForm { /// @@ -45,12 +48,12 @@ namespace Greenshot.Plugin.Dropbox.Forms { /// not be able to load this method if it was changed manually. /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.label_AfterUpload = new GreenshotLabel(); + this.checkboxAfterUploadLinkToClipBoard = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -135,11 +138,11 @@ namespace Greenshot.Plugin.Dropbox.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotLabel label_AfterUpload; + private GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; } } diff --git a/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj index 0ecbf3fec..075667394 100644 --- a/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj +++ b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj @@ -10,6 +10,6 @@ - + \ No newline at end of file diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs index 8d677e200..3cde91406 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs @@ -22,8 +22,8 @@ using System; using System.Collections.Generic; using System.IO; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.ExternalCommand { diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs index c7ab3b957..3814896dd 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs @@ -26,10 +26,10 @@ using System.Diagnostics; using System.Drawing; using System.Text.RegularExpressions; using System.Threading; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.ExternalCommand { diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs index 7fdfffa2a..90ba4bcfb 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Plugin.ExternalCommand { diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs index 43ae03f41..a4a3c20a5 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs @@ -24,10 +24,10 @@ using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.ExternalCommand { diff --git a/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj b/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj index bb0b57ef0..cc3d98fb9 100644 --- a/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj +++ b/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj @@ -6,6 +6,6 @@ - + diff --git a/src/Greenshot.Plugin.ExternalCommand/IconCache.cs b/src/Greenshot.Plugin.ExternalCommand/IconCache.cs index f1b854164..c1c8b2e04 100644 --- a/src/Greenshot.Plugin.ExternalCommand/IconCache.cs +++ b/src/Greenshot.Plugin.ExternalCommand/IconCache.cs @@ -22,8 +22,8 @@ using System; using System.Drawing; using System.IO; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.ExternalCommand { diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs index 9795bd93f..d2fe3b8c3 100644 --- a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Plugin.ExternalCommand { partial class SettingsForm { /// @@ -45,13 +48,13 @@ namespace Greenshot.Plugin.ExternalCommand { /// not be able to load this method if it was changed manually. /// private void InitializeComponent() { - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonOk = new GreenshotPlugin.Controls.GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.buttonOk = new GreenshotButton(); this.listView1 = new System.Windows.Forms.ListView(); this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.button_new = new GreenshotPlugin.Controls.GreenshotButton(); - this.button_delete = new GreenshotPlugin.Controls.GreenshotButton(); - this.button_edit = new GreenshotPlugin.Controls.GreenshotButton(); + this.button_new = new GreenshotButton(); + this.button_delete = new GreenshotButton(); + this.button_edit = new GreenshotButton(); this.SuspendLayout(); // // buttonCancel @@ -146,13 +149,13 @@ namespace Greenshot.Plugin.ExternalCommand { this.ResumeLayout(false); } - private GreenshotPlugin.Controls.GreenshotButton button_edit; - private GreenshotPlugin.Controls.GreenshotButton button_delete; - private GreenshotPlugin.Controls.GreenshotButton button_new; + private GreenshotButton button_edit; + private GreenshotButton button_delete; + private GreenshotButton button_new; private System.Windows.Forms.ColumnHeader columnHeader1; private System.Windows.Forms.ListView listView1; - private GreenshotPlugin.Controls.GreenshotButton buttonOk; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; + private GreenshotButton buttonOk; + private GreenshotButton buttonCancel; } } diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs index 49e872d7f..5325173b5 100644 --- a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs @@ -22,7 +22,7 @@ using System; using System.Drawing; using System.Windows.Forms; -using GreenshotPlugin.IniFile; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.ExternalCommand { diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs index 11d8dc346..ea97436b1 100644 --- a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Plugin.ExternalCommand { partial class SettingsFormDetail { /// @@ -46,16 +49,16 @@ namespace Greenshot.Plugin.ExternalCommand { /// private void InitializeComponent() { - this.buttonOk = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.groupBox1 = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.label4 = new GreenshotPlugin.Controls.GreenshotLabel(); + this.buttonOk = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.groupBox1 = new GreenshotGroupBox(); + this.label4 = new GreenshotLabel(); this.buttonPathSelect = new System.Windows.Forms.Button(); - this.label3 = new GreenshotPlugin.Controls.GreenshotLabel(); + this.label3 = new GreenshotLabel(); this.textBox_name = new System.Windows.Forms.TextBox(); - this.label2 = new GreenshotPlugin.Controls.GreenshotLabel(); + this.label2 = new GreenshotLabel(); this.textBox_arguments = new System.Windows.Forms.TextBox(); - this.label1 = new GreenshotPlugin.Controls.GreenshotLabel(); + this.label1 = new GreenshotLabel(); this.textBox_commandline = new System.Windows.Forms.TextBox(); this.groupBox1.SuspendLayout(); this.SuspendLayout(); @@ -184,13 +187,13 @@ namespace Greenshot.Plugin.ExternalCommand { this.ResumeLayout(false); } - private GreenshotPlugin.Controls.GreenshotLabel label1; - private GreenshotPlugin.Controls.GreenshotLabel label2; - private GreenshotPlugin.Controls.GreenshotLabel label3; - private GreenshotPlugin.Controls.GreenshotLabel label4; - private GreenshotPlugin.Controls.GreenshotGroupBox groupBox1; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOk; + private GreenshotLabel label1; + private GreenshotLabel label2; + private GreenshotLabel label3; + private GreenshotLabel label4; + private GreenshotGroupBox groupBox1; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOk; private System.Windows.Forms.TextBox textBox_commandline; private System.Windows.Forms.TextBox textBox_arguments; private System.Windows.Forms.TextBox textBox_name; diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs index 8aa235a67..c5551b291 100644 --- a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs @@ -23,8 +23,8 @@ using System; using System.Drawing; using System.IO; using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.ExternalCommand { diff --git a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs index 68fc72a3e..5e4f6801f 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs @@ -20,9 +20,9 @@ */ using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; using Greenshot.Plugin.Flickr.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; namespace Greenshot.Plugin.Flickr { diff --git a/src/Greenshot.Plugin.Flickr/FlickrDestination.cs b/src/Greenshot.Plugin.Flickr/FlickrDestination.cs index ec61f3b62..2d432e929 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrDestination.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrDestination.cs @@ -21,8 +21,8 @@ using System.ComponentModel; using System.Drawing; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; namespace Greenshot.Plugin.Flickr { diff --git a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs index 0ce2afaad..25c9095b2 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs @@ -24,11 +24,11 @@ using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using log4net; namespace Greenshot.Plugin.Flickr diff --git a/src/Greenshot.Plugin.Flickr/FlickrUtils.cs b/src/Greenshot.Plugin.Flickr/FlickrUtils.cs index 582484433..29a0417e9 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrUtils.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrUtils.cs @@ -23,11 +23,11 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Xml; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.OAuth; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using log4net; namespace Greenshot.Plugin.Flickr diff --git a/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs b/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs index 0c8f4130e..0fe3dc300 100644 --- a/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Plugin.Flickr.Forms { diff --git a/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs index c58fe2720..95f7c653d 100644 --- a/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Plugin.Flickr.Forms { partial class SettingsForm { /// @@ -46,18 +49,18 @@ namespace Greenshot.Plugin.Flickr.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkBoxPublic = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkBoxFamily = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkBoxFriend = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.label_SafetyLevel = new GreenshotPlugin.Controls.GreenshotLabel(); - this.combobox_safetyLevel = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkBox_hiddenfromsearch = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.checkBoxPublic = new GreenshotCheckBox(); + this.checkBoxFamily = new GreenshotCheckBox(); + this.checkBoxFriend = new GreenshotCheckBox(); + this.label_SafetyLevel = new GreenshotLabel(); + this.combobox_safetyLevel = new GreenshotComboBox(); + this.label_AfterUpload = new GreenshotLabel(); + this.checkboxAfterUploadLinkToClipBoard = new GreenshotCheckBox(); + this.checkBox_hiddenfromsearch = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -213,17 +216,17 @@ namespace Greenshot.Plugin.Flickr.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotCheckBox checkBox_hiddenfromsearch; - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotCheckBox checkBoxPublic; - private GreenshotPlugin.Controls.GreenshotCheckBox checkBoxFamily; - private GreenshotPlugin.Controls.GreenshotCheckBox checkBoxFriend; - private GreenshotPlugin.Controls.GreenshotLabel label_SafetyLevel; - private GreenshotPlugin.Controls.GreenshotComboBox combobox_safetyLevel; - private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; + private GreenshotCheckBox checkBox_hiddenfromsearch; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotCheckBox checkBoxPublic; + private GreenshotCheckBox checkBoxFamily; + private GreenshotCheckBox checkBoxFriend; + private GreenshotLabel label_SafetyLevel; + private GreenshotComboBox combobox_safetyLevel; + private GreenshotLabel label_AfterUpload; + private GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; } } diff --git a/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj index b0acd56db..548307884 100644 --- a/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj +++ b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj @@ -10,6 +10,6 @@ - + \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs index 616398591..9936efcdc 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Plugin.GooglePhotos.Forms { diff --git a/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs index 6b95cbc46..dcc750f55 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs @@ -17,6 +17,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Plugin.GooglePhotos.Forms { partial class SettingsForm { /// @@ -45,12 +48,12 @@ namespace Greenshot.Plugin.GooglePhotos.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.label_AfterUpload = new GreenshotLabel(); + this.checkboxAfterUploadLinkToClipBoard = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -137,11 +140,11 @@ namespace Greenshot.Plugin.GooglePhotos.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotLabel label_AfterUpload; + private GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; } } diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs index 411cf6ba9..34285a7b3 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs @@ -20,9 +20,9 @@ using System; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; using Greenshot.Plugin.GooglePhotos.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; namespace Greenshot.Plugin.GooglePhotos { diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs index 8a66faef7..2080f49c2 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs @@ -20,8 +20,8 @@ using System.ComponentModel; using System.Drawing; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; namespace Greenshot.Plugin.GooglePhotos { diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs index 91978b8ef..6c4d02b8f 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs @@ -23,11 +23,11 @@ using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.GooglePhotos { diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs index 2b4638839..1f225d895 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs @@ -20,11 +20,11 @@ using System; using System.Xml; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.OAuth; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.GooglePhotos { diff --git a/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj index b15368c8e..a798964c1 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj +++ b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj @@ -10,6 +10,6 @@ - + \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs index c94f6d1eb..d80c94f92 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Plugin.Imgur.Forms { diff --git a/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs index 417f5e7d5..c2efa03f4 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs @@ -23,9 +23,9 @@ using System; using System.Globalization; using System.Text; using System.Windows.Forms; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.Imgur.Forms { diff --git a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs index 175c55bb4..2df2be157 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Plugin.Imgur.Forms { partial class SettingsForm { /// @@ -46,13 +49,13 @@ namespace Greenshot.Plugin.Imgur.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.historyButton = new GreenshotPlugin.Controls.GreenshotButton(); - this.checkbox_anonymous_access = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_usepagelink = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.historyButton = new GreenshotButton(); + this.checkbox_anonymous_access = new GreenshotCheckBox(); + this.checkbox_usepagelink = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -150,12 +153,12 @@ namespace Greenshot.Plugin.Imgur.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotButton historyButton; - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_anonymous_access; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_usepagelink; + private GreenshotButton historyButton; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotCheckBox checkbox_anonymous_access; + private GreenshotCheckBox checkbox_usepagelink; } } diff --git a/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj index 170d0aedf..10a7fd241 100644 --- a/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj +++ b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj @@ -6,6 +6,6 @@ - + \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs index fdac54ee3..f5af624ab 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs @@ -22,9 +22,9 @@ using System; using System.Collections.Generic; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; using Greenshot.Plugin.Imgur.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; namespace Greenshot.Plugin.Imgur { diff --git a/src/Greenshot.Plugin.Imgur/ImgurDestination.cs b/src/Greenshot.Plugin.Imgur/ImgurDestination.cs index a0d069f1a..cb747b9bf 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurDestination.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurDestination.cs @@ -21,8 +21,8 @@ using System.ComponentModel; using System.Drawing; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; namespace Greenshot.Plugin.Imgur { diff --git a/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs index a936c80d7..400ebc0d8 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs @@ -25,12 +25,12 @@ using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Imgur.Forms; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; namespace Greenshot.Plugin.Imgur { diff --git a/src/Greenshot.Plugin.Imgur/ImgurUtils.cs b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs index 32b83d6e3..4ec67bd9b 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurUtils.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs @@ -24,11 +24,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.OAuth; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.Imgur { diff --git a/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs index 6eb143889..44b97cc43 100644 --- a/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs +++ b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs @@ -26,9 +26,9 @@ using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; using Dapplo.Jira.Entities; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.Jira.Forms { diff --git a/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs b/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs index 21ab33509..072290ac7 100644 --- a/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs +++ b/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Plugin.Jira.Forms { diff --git a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs index 3e18edb8e..39af09f68 100644 --- a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Plugin.Jira.Forms { partial class SettingsForm { /// @@ -46,12 +49,12 @@ namespace Greenshot.Plugin.Jira.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.label_url = new GreenshotPlugin.Controls.GreenshotLabel(); - this.textBoxUrl = new GreenshotPlugin.Controls.GreenshotTextBox(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.label_url = new GreenshotLabel(); + this.textBoxUrl = new GreenshotTextBox(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); this.SuspendLayout(); // // buttonOK @@ -136,11 +139,11 @@ namespace Greenshot.Plugin.Jira.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotTextBox textBoxUrl; - private GreenshotPlugin.Controls.GreenshotLabel label_url; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotTextBox textBoxUrl; + private GreenshotLabel label_url; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; } } diff --git a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj index cda65dc2f..5d8fde23f 100644 --- a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj +++ b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/Greenshot.Plugin.Jira/JiraConfiguration.cs b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs index cce59453b..64901f3d7 100644 --- a/src/Greenshot.Plugin.Jira/JiraConfiguration.cs +++ b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.Jira { diff --git a/src/Greenshot.Plugin.Jira/JiraConnector.cs b/src/Greenshot.Plugin.Jira/JiraConnector.cs index e25c4fb75..9f9b88835 100644 --- a/src/Greenshot.Plugin.Jira/JiraConnector.cs +++ b/src/Greenshot.Plugin.Jira/JiraConnector.cs @@ -31,8 +31,8 @@ using Dapplo.HttpExtensions.Extensions; using Dapplo.Jira; using Dapplo.Jira.Entities; using Dapplo.Jira.SvgWinForms.Converters; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.Jira { diff --git a/src/Greenshot.Plugin.Jira/JiraDestination.cs b/src/Greenshot.Plugin.Jira/JiraDestination.cs index 2dd871cf3..8b283642e 100644 --- a/src/Greenshot.Plugin.Jira/JiraDestination.cs +++ b/src/Greenshot.Plugin.Jira/JiraDestination.cs @@ -27,12 +27,12 @@ using System.IO; using System.Windows.Forms; using Dapplo.HttpExtensions; using Dapplo.Jira.Entities; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Jira.Forms; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; namespace Greenshot.Plugin.Jira { diff --git a/src/Greenshot.Plugin.Jira/JiraMonitor.cs b/src/Greenshot.Plugin.Jira/JiraMonitor.cs index 43a5e5487..3ccc84a45 100644 --- a/src/Greenshot.Plugin.Jira/JiraMonitor.cs +++ b/src/Greenshot.Plugin.Jira/JiraMonitor.cs @@ -27,7 +27,7 @@ using System.Threading; using System.Threading.Tasks; using Dapplo.Jira; using Dapplo.Log; -using GreenshotPlugin.Hooking; +using Greenshot.Base.Hooking; namespace Greenshot.Plugin.Jira { diff --git a/src/Greenshot.Plugin.Jira/JiraPlugin.cs b/src/Greenshot.Plugin.Jira/JiraPlugin.cs index e00f0263d..de10ba163 100644 --- a/src/Greenshot.Plugin.Jira/JiraPlugin.cs +++ b/src/Greenshot.Plugin.Jira/JiraPlugin.cs @@ -23,11 +23,11 @@ using System; using System.Threading.Tasks; using System.Windows.Forms; using Dapplo.Log; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Jira.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; using log4net; namespace Greenshot.Plugin.Jira diff --git a/src/Greenshot.Plugin.Office/Com/Ole32Api.cs b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs index efbf3614b..07d807ee2 100644 --- a/src/Greenshot.Plugin.Office/Com/Ole32Api.cs +++ b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs @@ -3,8 +3,8 @@ using System; using System.Runtime.InteropServices; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.Enums; +using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; namespace Greenshot.Plugin.Office.Com { diff --git a/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs index 534f8a274..c32b11a19 100644 --- a/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs +++ b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs @@ -3,8 +3,8 @@ using System; using System.Runtime.InteropServices; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.Enums; +using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; namespace Greenshot.Plugin.Office.Com { diff --git a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs index 5df550775..4aeceb12d 100644 --- a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs @@ -23,10 +23,10 @@ using System.Collections.Generic; using System.Drawing; using System.IO; using System.Text.RegularExpressions; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Office.OfficeExport; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; namespace Greenshot.Plugin.Office.Destinations { diff --git a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs index 578f357fb..33f23b58b 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs @@ -23,10 +23,10 @@ using System; using System.Collections.Generic; using System.Drawing; using System.IO; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; using Greenshot.Plugin.Office.OfficeExport; using Greenshot.Plugin.Office.OfficeExport.Entities; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; namespace Greenshot.Plugin.Office.Destinations { diff --git a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs index ae80b6f1e..bfc78dd2f 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs @@ -24,11 +24,11 @@ using System.Drawing; using System.IO; using System.Text.RegularExpressions; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Office.OfficeExport; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; using Microsoft.Office.Interop.Outlook; using Microsoft.Win32; diff --git a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs index bb5a0c453..6e3c22f36 100644 --- a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs @@ -24,10 +24,10 @@ using System.Drawing; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Office.OfficeExport; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; namespace Greenshot.Plugin.Office.Destinations { diff --git a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs index ff9945824..f6d448505 100644 --- a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs @@ -25,10 +25,10 @@ using System.Drawing; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Office.OfficeExport; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; namespace Greenshot.Plugin.Office.Destinations { diff --git a/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj index 2ca43d6fe..0e7d00d67 100644 --- a/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj +++ b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/Greenshot.Plugin.Office/OfficeConfiguration.cs b/src/Greenshot.Plugin.Office/OfficeConfiguration.cs index f2959aa34..897075806 100644 --- a/src/Greenshot.Plugin.Office/OfficeConfiguration.cs +++ b/src/Greenshot.Plugin.Office/OfficeConfiguration.cs @@ -19,8 +19,8 @@ * along with this program. If not, see . */ +using Greenshot.Base.IniFile; using Greenshot.Plugin.Office.OfficeInterop; -using GreenshotPlugin.IniFile; using Microsoft.Office.Interop.PowerPoint; namespace Greenshot.Plugin.Office diff --git a/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs index 4455bfd73..e725439da 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs @@ -20,9 +20,9 @@ using System; using System.Collections.Generic; using System.Drawing; +using Greenshot.Base.UnmanagedHelpers; using Greenshot.Plugin.Office.Com; using Greenshot.Plugin.Office.OfficeInterop; -using GreenshotPlugin.UnmanagedHelpers; using Microsoft.Office.Core; using Microsoft.Office.Interop.Excel; using Version = System.Version; diff --git a/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs index f42622356..68fcf2f6b 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs @@ -22,11 +22,11 @@ using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Xml; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Office.Com; using Greenshot.Plugin.Office.OfficeExport.Entities; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; using Microsoft.Office.Interop.OneNote; namespace Greenshot.Plugin.Office.OfficeExport diff --git a/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs index 55cad605e..ab3db1fdb 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs @@ -21,9 +21,9 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; +using Greenshot.Base.IniFile; using Greenshot.Plugin.Office.Com; using Greenshot.Plugin.Office.OfficeInterop; -using GreenshotPlugin.IniFile; using Microsoft.Office.Interop.Outlook; using Microsoft.Office.Interop.Word; using Microsoft.Win32; diff --git a/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs index c2bc7e2b3..1b76f54bf 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs @@ -20,9 +20,9 @@ using System; using System.Collections.Generic; using System.Drawing; +using Greenshot.Base.IniFile; using Greenshot.Plugin.Office.Com; using Greenshot.Plugin.Office.OfficeInterop; -using GreenshotPlugin.IniFile; using Microsoft.Office.Core; using Microsoft.Office.Interop.PowerPoint; using Shape = Microsoft.Office.Interop.PowerPoint.Shape; diff --git a/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs index 0cef0c696..d4da1cc3a 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs @@ -19,9 +19,9 @@ using System; using System.Collections.Generic; +using Greenshot.Base.IniFile; using Greenshot.Plugin.Office.Com; using Greenshot.Plugin.Office.OfficeInterop; -using GreenshotPlugin.IniFile; using Microsoft.Office.Core; using Microsoft.Office.Interop.Word; using Version = System.Version; diff --git a/src/Greenshot.Plugin.Office/OfficePlugin.cs b/src/Greenshot.Plugin.Office/OfficePlugin.cs index c7e75afcd..bfb10bfa0 100644 --- a/src/Greenshot.Plugin.Office/OfficePlugin.cs +++ b/src/Greenshot.Plugin.Office/OfficePlugin.cs @@ -21,10 +21,10 @@ using System; using System.Collections.Generic; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Office.Destinations; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; namespace Greenshot.Plugin.Office { diff --git a/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs b/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs index 6bf170ca5..99f8150b0 100644 --- a/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs +++ b/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs @@ -19,12 +19,14 @@ * along with this program. If not, see . */ +using Greenshot.Base.Controls; + namespace Greenshot.Plugin.Photobucket.Forms { /// /// This class is needed for design-time resolving of the language files /// - public class PhotobucketForm : GreenshotPlugin.Controls.GreenshotForm + public class PhotobucketForm : GreenshotForm { } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs index 85d3a588b..5e1910690 100644 --- a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Plugin.Photobucket.Forms { partial class SettingsForm { /// @@ -46,11 +49,11 @@ namespace Greenshot.Plugin.Photobucket.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkbox_usepagelink = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.checkbox_usepagelink = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -124,10 +127,10 @@ namespace Greenshot.Plugin.Photobucket.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_usepagelink; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotCheckBox checkbox_usepagelink; } } diff --git a/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj index bb0b57ef0..cc3d98fb9 100644 --- a/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj +++ b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj @@ -6,6 +6,6 @@ - + diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs index 4c1c976d2..0600448f9 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs @@ -20,10 +20,10 @@ */ using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; using Greenshot.Plugin.Photobucket.Forms; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; namespace Greenshot.Plugin.Photobucket { diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs index 34bffa89b..2d10b0864 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs @@ -22,8 +22,8 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; namespace Greenshot.Plugin.Photobucket { diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs index 394707897..fb86aeb93 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs @@ -24,11 +24,11 @@ using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.Photobucket { diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs index 61a61f8a3..c149f1cc0 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs @@ -24,11 +24,11 @@ using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Xml; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.OAuth; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.Photobucket { diff --git a/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs index cc119b70d..9492a2dfa 100644 --- a/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs +++ b/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs @@ -23,9 +23,9 @@ using System; using System.Drawing; using System.Threading.Tasks; using Windows.Media.Ocr; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; namespace Greenshot.Plugin.Win10.Destinations { diff --git a/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs index e8178a8cf..b1be32d61 100644 --- a/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs +++ b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs @@ -29,12 +29,12 @@ using System.Windows.Interop; using System.Windows.Media; using Windows.Storage; using Windows.Storage.Streams; +using Greenshot.Base.Core; +using Greenshot.Base.Hooking; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Win10.Internal; using Greenshot.Plugin.Win10.Native; -using GreenshotPlugin.Core; -using GreenshotPlugin.Hooking; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; using Color = Windows.UI.Color; namespace Greenshot.Plugin.Win10.Destinations diff --git a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj index bd79af992..182da73b6 100644 --- a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj +++ b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj @@ -9,6 +9,6 @@ - + diff --git a/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs index 9f2540694..15b70639f 100644 --- a/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs +++ b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs @@ -22,7 +22,7 @@ using System; using System.Runtime.InteropServices.WindowsRuntime; using Windows.ApplicationModel.DataTransfer; -using GreenshotPlugin.Core; +using Greenshot.Base.Core; namespace Greenshot.Plugin.Win10.Native { diff --git a/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs index 8bdba3366..1cdfa14de 100644 --- a/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs +++ b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs @@ -20,7 +20,7 @@ using System; using System.Runtime.InteropServices; using Windows.ApplicationModel.DataTransfer; -using GreenshotPlugin.Core.Enums; +using Greenshot.Base.Core.Enums; namespace Greenshot.Plugin.Win10.Native { diff --git a/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs b/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs index cfbf88d18..45f511d93 100644 --- a/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs +++ b/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs @@ -20,10 +20,10 @@ */ using System.Threading.Tasks; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; namespace Greenshot.Plugin.Win10.Processors { diff --git a/src/Greenshot.Plugin.Win10/ToastNotificationService.cs b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs index eea987802..1da804c7a 100644 --- a/src/Greenshot.Plugin.Win10/ToastNotificationService.cs +++ b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs @@ -25,9 +25,9 @@ using System.IO; using Windows.Foundation.Collections; using Windows.Foundation.Metadata; using Windows.UI.Notifications; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; using log4net; using Microsoft.Toolkit.Uwp.Notifications; diff --git a/src/Greenshot.Plugin.Win10/Win10Configuration.cs b/src/Greenshot.Plugin.Win10/Win10Configuration.cs index bbd1ff35e..acd1238ea 100644 --- a/src/Greenshot.Plugin.Win10/Win10Configuration.cs +++ b/src/Greenshot.Plugin.Win10/Win10Configuration.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.IniFile; +using Greenshot.Base.IniFile; namespace Greenshot.Plugin.Win10 { diff --git a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs index e6feb8193..7611499f2 100644 --- a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs +++ b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs @@ -26,10 +26,10 @@ using System.Threading.Tasks; using Windows.Graphics.Imaging; using Windows.Media.Ocr; using Windows.Storage.Streams; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Plugin.Win10 { diff --git a/src/Greenshot.Plugin.Win10/Win10Plugin.cs b/src/Greenshot.Plugin.Win10/Win10Plugin.cs index 25d8d048e..aa3342ead 100644 --- a/src/Greenshot.Plugin.Win10/Win10Plugin.cs +++ b/src/Greenshot.Plugin.Win10/Win10Plugin.cs @@ -20,12 +20,12 @@ */ using System; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Win10.Destinations; using Greenshot.Plugin.Win10.Processors; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; -using GreenshotPlugin.Interfaces.Plugin; namespace Greenshot.Plugin.Win10 { diff --git a/src/Greenshot.sln b/src/Greenshot.sln index 40b3169b4..daabf8cf2 100644 --- a/src/Greenshot.sln +++ b/src/Greenshot.sln @@ -18,7 +18,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Gree {1893A2E4-A78A-4713-A8E7-E70058DABEE0} = {1893A2E4-A78A-4713-A8E7-E70058DABEE0} EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPlugin", "GreenshotPlugin\GreenshotPlugin.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Base", "Greenshot.Base\Greenshot.Base.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.ExternalCommand", "Greenshot.Plugin.ExternalCommand\Greenshot.Plugin.ExternalCommand.csproj", "{47F23C86-604E-4CC3-8767-B3D4088F30BB}" EndProject diff --git a/src/Greenshot/Configuration/EditorConfiguration.cs b/src/Greenshot/Configuration/EditorConfiguration.cs index 97856f5d0..b16c7804d 100644 --- a/src/Greenshot/Configuration/EditorConfiguration.cs +++ b/src/Greenshot/Configuration/EditorConfiguration.cs @@ -22,12 +22,12 @@ using System; using System.Collections.Generic; using System.Drawing; +using Greenshot.Base.Effects; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; using Greenshot.Drawing.Fields; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces.Drawing; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; namespace Greenshot.Configuration { diff --git a/src/Greenshot/Controls/BindableToolStripButton.cs b/src/Greenshot/Controls/BindableToolStripButton.cs index 37088476a..51dfe9538 100644 --- a/src/Greenshot/Controls/BindableToolStripButton.cs +++ b/src/Greenshot/Controls/BindableToolStripButton.cs @@ -22,7 +22,7 @@ using System; using System.ComponentModel; using System.Windows.Forms; -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Controls { diff --git a/src/Greenshot/Controls/BindableToolStripComboBox.cs b/src/Greenshot/Controls/BindableToolStripComboBox.cs index b0f87cff8..9f767b1fa 100644 --- a/src/Greenshot/Controls/BindableToolStripComboBox.cs +++ b/src/Greenshot/Controls/BindableToolStripComboBox.cs @@ -22,7 +22,7 @@ using System; using System.ComponentModel; using System.Windows.Forms; -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Controls { diff --git a/src/Greenshot/Controls/BindableToolStripDropDownButton.cs b/src/Greenshot/Controls/BindableToolStripDropDownButton.cs index 428b66bb3..04c1a3ee0 100644 --- a/src/Greenshot/Controls/BindableToolStripDropDownButton.cs +++ b/src/Greenshot/Controls/BindableToolStripDropDownButton.cs @@ -21,7 +21,7 @@ using System.ComponentModel; using System.Windows.Forms; -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Controls { diff --git a/src/Greenshot/Controls/ColorButton.cs b/src/Greenshot/Controls/ColorButton.cs index 068033522..2c762e216 100644 --- a/src/Greenshot/Controls/ColorButton.cs +++ b/src/Greenshot/Controls/ColorButton.cs @@ -24,7 +24,7 @@ using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; using ColorDialog = Greenshot.Forms.ColorDialog; namespace Greenshot.Controls diff --git a/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs b/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs index e85817d7f..b1229a293 100644 --- a/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs +++ b/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs @@ -19,10 +19,10 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core; using System.Drawing; using System.Windows.Forms; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; namespace Greenshot.Controls { diff --git a/src/Greenshot/Controls/MenuStripEx.cs b/src/Greenshot/Controls/MenuStripEx.cs index 34f1d168a..a9c92f2a6 100644 --- a/src/Greenshot/Controls/MenuStripEx.cs +++ b/src/Greenshot/Controls/MenuStripEx.cs @@ -21,7 +21,7 @@ using System; using System.Windows.Forms; -using GreenshotPlugin.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Enums; namespace Greenshot.Controls { diff --git a/src/Greenshot/Controls/Pipette.cs b/src/Greenshot/Controls/Pipette.cs index d4636b017..32c07459e 100644 --- a/src/Greenshot/Controls/Pipette.cs +++ b/src/Greenshot/Controls/Pipette.cs @@ -23,9 +23,9 @@ using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; using Greenshot.Forms; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.UnmanagedHelpers.Enums; using ColorDialog = Greenshot.Forms.ColorDialog; namespace Greenshot.Controls diff --git a/src/Greenshot/Controls/ToolStripColorButton.cs b/src/Greenshot/Controls/ToolStripColorButton.cs index ffc2606f5..1e21d2725 100644 --- a/src/Greenshot/Controls/ToolStripColorButton.cs +++ b/src/Greenshot/Controls/ToolStripColorButton.cs @@ -24,7 +24,7 @@ using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; using ColorDialog = Greenshot.Forms.ColorDialog; namespace Greenshot.Controls diff --git a/src/Greenshot/Destinations/ClipboardDestination.cs b/src/Greenshot/Destinations/ClipboardDestination.cs index 88a2e2ecb..3946be901 100644 --- a/src/Greenshot/Destinations/ClipboardDestination.cs +++ b/src/Greenshot/Destinations/ClipboardDestination.cs @@ -22,9 +22,9 @@ using System; using System.Drawing; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; namespace Greenshot.Destinations { diff --git a/src/Greenshot/Destinations/EditorDestination.cs b/src/Greenshot/Destinations/EditorDestination.cs index b22cc0894..ba74a70ca 100644 --- a/src/Greenshot/Destinations/EditorDestination.cs +++ b/src/Greenshot/Destinations/EditorDestination.cs @@ -22,12 +22,12 @@ using System; using System.Collections.Generic; using System.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Forms; using Greenshot.Configuration; using Greenshot.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Forms; using log4net; namespace Greenshot.Destinations diff --git a/src/Greenshot/Destinations/EmailDestination.cs b/src/Greenshot/Destinations/EmailDestination.cs index c8e99b870..b3f546f34 100644 --- a/src/Greenshot/Destinations/EmailDestination.cs +++ b/src/Greenshot/Destinations/EmailDestination.cs @@ -22,10 +22,10 @@ using System; using System.Drawing; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; using Greenshot.Configuration; using Greenshot.Helpers; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; using Microsoft.Win32; namespace Greenshot.Destinations diff --git a/src/Greenshot/Destinations/FileDestination.cs b/src/Greenshot/Destinations/FileDestination.cs index 95365677a..cf0c4ed28 100644 --- a/src/Greenshot/Destinations/FileDestination.cs +++ b/src/Greenshot/Destinations/FileDestination.cs @@ -23,13 +23,13 @@ using System; using System.Drawing; using System.IO; using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Configuration; using Greenshot.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Controls; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; using log4net; namespace Greenshot.Destinations diff --git a/src/Greenshot/Destinations/FileWithDialogDestination.cs b/src/Greenshot/Destinations/FileWithDialogDestination.cs index 02c5e9bd4..b17659da0 100644 --- a/src/Greenshot/Destinations/FileWithDialogDestination.cs +++ b/src/Greenshot/Destinations/FileWithDialogDestination.cs @@ -21,10 +21,10 @@ using System.Drawing; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; namespace Greenshot.Destinations { diff --git a/src/Greenshot/Destinations/PickerDestination.cs b/src/Greenshot/Destinations/PickerDestination.cs index 2195e1d6b..654726e6a 100644 --- a/src/Greenshot/Destinations/PickerDestination.cs +++ b/src/Greenshot/Destinations/PickerDestination.cs @@ -20,9 +20,9 @@ */ using System.Collections.Generic; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; namespace Greenshot.Destinations { diff --git a/src/Greenshot/Destinations/PrinterDestination.cs b/src/Greenshot/Destinations/PrinterDestination.cs index 09b51880c..7be51bbff 100644 --- a/src/Greenshot/Destinations/PrinterDestination.cs +++ b/src/Greenshot/Destinations/PrinterDestination.cs @@ -24,10 +24,10 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Printing; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; using Greenshot.Configuration; -using GreenshotPlugin.Core; using Greenshot.Helpers; -using GreenshotPlugin.Interfaces; namespace Greenshot.Destinations { diff --git a/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs index 19f531a5c..37057d428 100644 --- a/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ b/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs @@ -22,9 +22,9 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; -using GreenshotPlugin.Interfaces.Drawing.Adorners; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing.Adorners; namespace Greenshot.Drawing.Adorners { diff --git a/src/Greenshot/Drawing/Adorners/MoveAdorner.cs b/src/Greenshot/Drawing/Adorners/MoveAdorner.cs index 73c75141c..9116ff3cf 100644 --- a/src/Greenshot/Drawing/Adorners/MoveAdorner.cs +++ b/src/Greenshot/Drawing/Adorners/MoveAdorner.cs @@ -23,7 +23,7 @@ using Greenshot.Helpers; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Adorners { diff --git a/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs index b6480180d..38c1eb9af 100644 --- a/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs +++ b/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs @@ -23,7 +23,7 @@ using Greenshot.Helpers; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Adorners { diff --git a/src/Greenshot/Drawing/Adorners/TargetAdorner.cs b/src/Greenshot/Drawing/Adorners/TargetAdorner.cs index 546606b66..2569ae8c3 100644 --- a/src/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ b/src/Greenshot/Drawing/Adorners/TargetAdorner.cs @@ -22,7 +22,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Adorners { diff --git a/src/Greenshot/Drawing/ArrowContainer.cs b/src/Greenshot/Drawing/ArrowContainer.cs index a49ffe863..eaed428f0 100644 --- a/src/Greenshot/Drawing/ArrowContainer.cs +++ b/src/Greenshot/Drawing/ArrowContainer.cs @@ -22,8 +22,8 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing.Fields; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/CropContainer.cs b/src/Greenshot/Drawing/CropContainer.cs index 164fd791e..6c89f37d4 100644 --- a/src/Greenshot/Drawing/CropContainer.cs +++ b/src/Greenshot/Drawing/CropContainer.cs @@ -21,9 +21,9 @@ using System.Drawing; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Helpers; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/CursorContainer.cs b/src/Greenshot/Drawing/CursorContainer.cs index d22b5d672..c961c4d22 100644 --- a/src/Greenshot/Drawing/CursorContainer.cs +++ b/src/Greenshot/Drawing/CursorContainer.cs @@ -26,7 +26,7 @@ using System.Windows.Forms; using System.Drawing.Drawing2D; using log4net; using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/DrawableContainer.cs b/src/Greenshot/Drawing/DrawableContainer.cs index 96ef93b9c..4e710e6be 100644 --- a/src/Greenshot/Drawing/DrawableContainer.cs +++ b/src/Greenshot/Drawing/DrawableContainer.cs @@ -25,7 +25,6 @@ using Greenshot.Drawing.Fields; using Greenshot.Drawing.Filters; using Greenshot.Helpers; using Greenshot.Memento; -using GreenshotPlugin.Interfaces.Drawing; using log4net; using System; using System.Collections.Generic; @@ -34,9 +33,10 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Runtime.Serialization; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Drawing.Adorners; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing.Adorners; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/DrawableContainerList.cs b/src/Greenshot/Drawing/DrawableContainerList.cs index c450ebad4..8dc490013 100644 --- a/src/Greenshot/Drawing/DrawableContainerList.cs +++ b/src/Greenshot/Drawing/DrawableContainerList.cs @@ -21,8 +21,6 @@ using Greenshot.Configuration; using Greenshot.Memento; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; using System; using System.Collections.Generic; using System.ComponentModel; @@ -30,8 +28,10 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Threading; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Forms; -using GreenshotPlugin.Interfaces; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/EllipseContainer.cs b/src/Greenshot/Drawing/EllipseContainer.cs index 091c03b17..466cf7a77 100644 --- a/src/Greenshot/Drawing/EllipseContainer.cs +++ b/src/Greenshot/Drawing/EllipseContainer.cs @@ -22,9 +22,9 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Helpers; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs index f4bc0377f..391299d86 100644 --- a/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs +++ b/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs @@ -24,10 +24,10 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Runtime.Serialization; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Configuration; -using GreenshotPlugin.IniFile; using log4net; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing.Fields { diff --git a/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs index 979a80168..9e0593280 100644 --- a/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs +++ b/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs @@ -19,10 +19,10 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Interfaces.Drawing; using System; using System.Collections.Generic; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Fields { diff --git a/src/Greenshot/Drawing/Fields/Field.cs b/src/Greenshot/Drawing/Fields/Field.cs index e58de2122..280c3a519 100644 --- a/src/Greenshot/Drawing/Fields/Field.cs +++ b/src/Greenshot/Drawing/Fields/Field.cs @@ -19,9 +19,9 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Interfaces.Drawing; using System; using System.ComponentModel; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Fields { diff --git a/src/Greenshot/Drawing/Fields/FieldAggregator.cs b/src/Greenshot/Drawing/Fields/FieldAggregator.cs index 39f859503..cda039956 100644 --- a/src/Greenshot/Drawing/Fields/FieldAggregator.cs +++ b/src/Greenshot/Drawing/Fields/FieldAggregator.cs @@ -21,12 +21,12 @@ using System; using Greenshot.Configuration; -using GreenshotPlugin.Interfaces.Drawing; using System.Collections.Generic; using System.ComponentModel; using System.Linq; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Fields { diff --git a/src/Greenshot/Drawing/Fields/FieldType.cs b/src/Greenshot/Drawing/Fields/FieldType.cs index 3e6711898..accd72d4b 100644 --- a/src/Greenshot/Drawing/Fields/FieldType.cs +++ b/src/Greenshot/Drawing/Fields/FieldType.cs @@ -19,8 +19,8 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Interfaces.Drawing; using System; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Fields { diff --git a/src/Greenshot/Drawing/FilterContainer.cs b/src/Greenshot/Drawing/FilterContainer.cs index 93e3352c9..e58363024 100644 --- a/src/Greenshot/Drawing/FilterContainer.cs +++ b/src/Greenshot/Drawing/FilterContainer.cs @@ -25,7 +25,7 @@ using Greenshot.Drawing.Fields; using Greenshot.Helpers; using System.Drawing.Drawing2D; using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/Filters/AbstractFilter.cs b/src/Greenshot/Drawing/Filters/AbstractFilter.cs index 1608fd866..1152956a0 100644 --- a/src/Greenshot/Drawing/Filters/AbstractFilter.cs +++ b/src/Greenshot/Drawing/Filters/AbstractFilter.cs @@ -22,8 +22,8 @@ using System; using System.ComponentModel; using System.Drawing; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing.Fields; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing.Filters { diff --git a/src/Greenshot/Drawing/Filters/BlurFilter.cs b/src/Greenshot/Drawing/Filters/BlurFilter.cs index 9b8c5d0f9..698ffce4b 100644 --- a/src/Greenshot/Drawing/Filters/BlurFilter.cs +++ b/src/Greenshot/Drawing/Filters/BlurFilter.cs @@ -22,10 +22,10 @@ using System; using System.Drawing; using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers; using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.UnmanagedHelpers; namespace Greenshot.Drawing.Filters { diff --git a/src/Greenshot/Drawing/Filters/BrightnessFilter.cs b/src/Greenshot/Drawing/Filters/BrightnessFilter.cs index cba712bbe..4a02e9a7c 100644 --- a/src/Greenshot/Drawing/Filters/BrightnessFilter.cs +++ b/src/Greenshot/Drawing/Filters/BrightnessFilter.cs @@ -22,10 +22,10 @@ using System; using System.Drawing; using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; using System.Drawing.Imaging; using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Filters { diff --git a/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs index 2565999a9..43d8d44c2 100644 --- a/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs +++ b/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs @@ -21,10 +21,10 @@ using System; using System.Drawing; -using GreenshotPlugin.Core; using System.Drawing.Drawing2D; using System.Drawing.Imaging; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Filters { diff --git a/src/Greenshot/Drawing/Filters/HighlightFilter.cs b/src/Greenshot/Drawing/Filters/HighlightFilter.cs index e311293c5..04542575e 100644 --- a/src/Greenshot/Drawing/Filters/HighlightFilter.cs +++ b/src/Greenshot/Drawing/Filters/HighlightFilter.cs @@ -22,9 +22,9 @@ using System; using System.Drawing; using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Filters { diff --git a/src/Greenshot/Drawing/Filters/IFilter.cs b/src/Greenshot/Drawing/Filters/IFilter.cs index bbf255dd1..41e634880 100644 --- a/src/Greenshot/Drawing/Filters/IFilter.cs +++ b/src/Greenshot/Drawing/Filters/IFilter.cs @@ -21,7 +21,7 @@ using System.ComponentModel; using System.Drawing; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Filters { diff --git a/src/Greenshot/Drawing/Filters/MagnifierFilter.cs b/src/Greenshot/Drawing/Filters/MagnifierFilter.cs index c3f9835fa..9b1587d04 100644 --- a/src/Greenshot/Drawing/Filters/MagnifierFilter.cs +++ b/src/Greenshot/Drawing/Filters/MagnifierFilter.cs @@ -22,9 +22,9 @@ using System; using System.Drawing; using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Filters { diff --git a/src/Greenshot/Drawing/Filters/PixelizationFilter.cs b/src/Greenshot/Drawing/Filters/PixelizationFilter.cs index 00a3e2f11..59ca0321f 100644 --- a/src/Greenshot/Drawing/Filters/PixelizationFilter.cs +++ b/src/Greenshot/Drawing/Filters/PixelizationFilter.cs @@ -22,10 +22,10 @@ using System; using System.Collections.Generic; using System.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Helpers; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing.Filters { diff --git a/src/Greenshot/Drawing/FreehandContainer.cs b/src/Greenshot/Drawing/FreehandContainer.cs index a493ee670..3c3fbe92f 100644 --- a/src/Greenshot/Drawing/FreehandContainer.cs +++ b/src/Greenshot/Drawing/FreehandContainer.cs @@ -26,7 +26,7 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/HighlightContainer.cs b/src/Greenshot/Drawing/HighlightContainer.cs index 267e2784b..fb5a78c69 100644 --- a/src/Greenshot/Drawing/HighlightContainer.cs +++ b/src/Greenshot/Drawing/HighlightContainer.cs @@ -21,9 +21,9 @@ using System; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Drawing.Filters; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/IconContainer.cs b/src/Greenshot/Drawing/IconContainer.cs index a89e0a258..fe87c48b9 100644 --- a/src/Greenshot/Drawing/IconContainer.cs +++ b/src/Greenshot/Drawing/IconContainer.cs @@ -25,7 +25,7 @@ using System.IO; using System.Drawing.Drawing2D; using log4net; using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/ImageContainer.cs b/src/Greenshot/Drawing/ImageContainer.cs index 3b99e36af..e4538c0f4 100644 --- a/src/Greenshot/Drawing/ImageContainer.cs +++ b/src/Greenshot/Drawing/ImageContainer.cs @@ -23,12 +23,12 @@ using System; using System.Drawing; using System.IO; using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; using System.Drawing.Drawing2D; using log4net; using System.Runtime.Serialization; -using GreenshotPlugin.Effects; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/LineContainer.cs b/src/Greenshot/Drawing/LineContainer.cs index 6a5229107..1078662ea 100644 --- a/src/Greenshot/Drawing/LineContainer.cs +++ b/src/Greenshot/Drawing/LineContainer.cs @@ -23,10 +23,10 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Drawing.Adorners; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/ObfuscateContainer.cs b/src/Greenshot/Drawing/ObfuscateContainer.cs index 127ff2b61..f45d6b4a2 100644 --- a/src/Greenshot/Drawing/ObfuscateContainer.cs +++ b/src/Greenshot/Drawing/ObfuscateContainer.cs @@ -21,9 +21,9 @@ using System; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Drawing.Filters; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/RectangleContainer.cs b/src/Greenshot/Drawing/RectangleContainer.cs index b26193ee7..73da99983 100644 --- a/src/Greenshot/Drawing/RectangleContainer.cs +++ b/src/Greenshot/Drawing/RectangleContainer.cs @@ -25,7 +25,7 @@ using System.Drawing.Drawing2D; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/SpeechbubbleContainer.cs b/src/Greenshot/Drawing/SpeechbubbleContainer.cs index ce11402b9..50f18f74a 100644 --- a/src/Greenshot/Drawing/SpeechbubbleContainer.cs +++ b/src/Greenshot/Drawing/SpeechbubbleContainer.cs @@ -26,7 +26,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/StepLabelContainer.cs b/src/Greenshot/Drawing/StepLabelContainer.cs index ff01af1c1..3f2c3b7db 100644 --- a/src/Greenshot/Drawing/StepLabelContainer.cs +++ b/src/Greenshot/Drawing/StepLabelContainer.cs @@ -26,7 +26,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/Surface.cs b/src/Greenshot/Drawing/Surface.cs index 4dd3c55bd..8f2356513 100644 --- a/src/Greenshot/Drawing/Surface.cs +++ b/src/Greenshot/Drawing/Surface.cs @@ -23,9 +23,6 @@ using Greenshot.Configuration; using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Memento; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; using log4net; using System; using System.Collections.Generic; @@ -36,10 +33,13 @@ using System.Drawing.Imaging; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Windows.Forms; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Drawing.Adorners; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing.Adorners; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Drawing/TextContainer.cs b/src/Greenshot/Drawing/TextContainer.cs index 8f1a819f6..4888ef463 100644 --- a/src/Greenshot/Drawing/TextContainer.cs +++ b/src/Greenshot/Drawing/TextContainer.cs @@ -22,8 +22,6 @@ using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Memento; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; using System; using System.ComponentModel; using System.Diagnostics; @@ -32,6 +30,8 @@ using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.Serialization; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing { diff --git a/src/Greenshot/Forms/AboutForm.Designer.cs b/src/Greenshot/Forms/AboutForm.Designer.cs index 4112df177..e34b65b03 100644 --- a/src/Greenshot/Forms/AboutForm.Designer.cs +++ b/src/Greenshot/Forms/AboutForm.Designer.cs @@ -20,8 +20,9 @@ */ using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; using Greenshot.Helpers; -using GreenshotPlugin.Core; namespace Greenshot.Forms { partial class AboutForm { @@ -50,19 +51,19 @@ namespace Greenshot.Forms { /// private void InitializeComponent() { this.lblTitle = new System.Windows.Forms.Label(); - this.lblLicense = new GreenshotPlugin.Controls.GreenshotLabel(); - this.lblHost = new GreenshotPlugin.Controls.GreenshotLabel(); + this.lblLicense = new GreenshotLabel(); + this.lblHost = new GreenshotLabel(); this.linkLblLicense = new System.Windows.Forms.LinkLabel(); this.linkLblHost = new System.Windows.Forms.LinkLabel(); this.linkLblBugs = new System.Windows.Forms.LinkLabel(); - this.lblBugs = new GreenshotPlugin.Controls.GreenshotLabel(); + this.lblBugs = new GreenshotLabel(); this.linkLblDonations = new System.Windows.Forms.LinkLabel(); - this.lblDonations = new GreenshotPlugin.Controls.GreenshotLabel(); + this.lblDonations = new GreenshotLabel(); this.linkLblIcons = new System.Windows.Forms.LinkLabel(); - this.lblIcons = new GreenshotPlugin.Controls.GreenshotLabel(); + this.lblIcons = new GreenshotLabel(); this.linkLabel1 = new System.Windows.Forms.LinkLabel(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); - this.lblTranslation = new GreenshotPlugin.Controls.GreenshotLabel(); + this.lblTranslation = new GreenshotLabel(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.SuspendLayout(); // @@ -236,11 +237,11 @@ namespace Greenshot.Forms { private System.Windows.Forms.LinkLabel linkLblIcons; private System.Windows.Forms.Label lblTitle; private System.Windows.Forms.PictureBox pictureBox1; - private GreenshotPlugin.Controls.GreenshotLabel lblTranslation; - private GreenshotPlugin.Controls.GreenshotLabel lblHost; - private GreenshotPlugin.Controls.GreenshotLabel lblDonations; - private GreenshotPlugin.Controls.GreenshotLabel lblBugs; - private GreenshotPlugin.Controls.GreenshotLabel lblIcons; - private GreenshotPlugin.Controls.GreenshotLabel lblLicense; + private GreenshotLabel lblTranslation; + private GreenshotLabel lblHost; + private GreenshotLabel lblDonations; + private GreenshotLabel lblBugs; + private GreenshotLabel lblIcons; + private GreenshotLabel lblLicense; } } diff --git a/src/Greenshot/Forms/AboutForm.cs b/src/Greenshot/Forms/AboutForm.cs index 6fdf4eddd..7ecad5ccc 100644 --- a/src/Greenshot/Forms/AboutForm.cs +++ b/src/Greenshot/Forms/AboutForm.cs @@ -28,10 +28,10 @@ using System.Drawing.Imaging; using System.IO; using System.Security.Permissions; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; using Greenshot.Configuration; using Greenshot.Helpers; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; using log4net; namespace Greenshot.Forms diff --git a/src/Greenshot/Forms/AnimatingBaseForm.cs b/src/Greenshot/Forms/AnimatingBaseForm.cs index 7f9fec60e..6f131381b 100644 --- a/src/Greenshot/Forms/AnimatingBaseForm.cs +++ b/src/Greenshot/Forms/AnimatingBaseForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Forms { diff --git a/src/Greenshot/Forms/BaseForm.cs b/src/Greenshot/Forms/BaseForm.cs index e67654df5..c7ea1341f 100644 --- a/src/Greenshot/Forms/BaseForm.cs +++ b/src/Greenshot/Forms/BaseForm.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; namespace Greenshot.Forms { diff --git a/src/Greenshot/Forms/BugReportForm.Designer.cs b/src/Greenshot/Forms/BugReportForm.Designer.cs index da6da4963..41dcc6447 100644 --- a/src/Greenshot/Forms/BugReportForm.Designer.cs +++ b/src/Greenshot/Forms/BugReportForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Forms { partial class BugReportForm { /// @@ -46,9 +49,9 @@ namespace Greenshot.Forms { /// private void InitializeComponent() { - this.labelBugReportInfo = new GreenshotPlugin.Controls.GreenshotLabel(); + this.labelBugReportInfo = new GreenshotLabel(); this.textBoxDescription = new System.Windows.Forms.TextBox(); - this.btnClose = new GreenshotPlugin.Controls.GreenshotButton(); + this.btnClose = new GreenshotButton(); this.linkLblBugs = new System.Windows.Forms.LinkLabel(); this.SuspendLayout(); // @@ -112,8 +115,8 @@ namespace Greenshot.Forms { } private System.Windows.Forms.LinkLabel linkLblBugs; - private GreenshotPlugin.Controls.GreenshotButton btnClose; + private GreenshotButton btnClose; private System.Windows.Forms.TextBox textBoxDescription; - private GreenshotPlugin.Controls.GreenshotLabel labelBugReportInfo; + private GreenshotLabel labelBugReportInfo; } } diff --git a/src/Greenshot/Forms/BugReportForm.cs b/src/Greenshot/Forms/BugReportForm.cs index b42f20d18..255af0525 100644 --- a/src/Greenshot/Forms/BugReportForm.cs +++ b/src/Greenshot/Forms/BugReportForm.cs @@ -22,8 +22,8 @@ using System; using System.Diagnostics; using System.Windows.Forms; +using Greenshot.Base.Core; using Greenshot.Configuration; -using GreenshotPlugin.Core; namespace Greenshot.Forms { diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs index efdf7583c..f85c57d4a 100644 --- a/src/Greenshot/Forms/CaptureForm.cs +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -21,9 +21,6 @@ using Greenshot.Drawing; using Greenshot.Helpers; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers; using log4net; using System; using System.Collections.Generic; @@ -35,9 +32,12 @@ using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; +using Greenshot.Base.UnmanagedHelpers; namespace Greenshot.Forms { diff --git a/src/Greenshot/Forms/ColorDialog.Designer.cs b/src/Greenshot/Forms/ColorDialog.Designer.cs index d5060d8c0..468edf457 100644 --- a/src/Greenshot/Forms/ColorDialog.Designer.cs +++ b/src/Greenshot/Forms/ColorDialog.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Forms { public partial class ColorDialog { /// @@ -47,20 +50,20 @@ namespace Greenshot.Forms { private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ColorDialog)); - this.btnTransparent = new GreenshotPlugin.Controls.GreenshotButton(); + this.btnTransparent = new GreenshotButton(); this.colorPanel = new System.Windows.Forms.Panel(); - this.labelHtmlColor = new GreenshotPlugin.Controls.GreenshotLabel(); + this.labelHtmlColor = new GreenshotLabel(); this.textBoxHtmlColor = new System.Windows.Forms.TextBox(); - this.labelRed = new GreenshotPlugin.Controls.GreenshotLabel(); - this.labelGreen = new GreenshotPlugin.Controls.GreenshotLabel(); - this.labelBlue = new GreenshotPlugin.Controls.GreenshotLabel(); + this.labelRed = new GreenshotLabel(); + this.labelGreen = new GreenshotLabel(); + this.labelBlue = new GreenshotLabel(); this.textBoxRed = new System.Windows.Forms.TextBox(); this.textBoxGreen = new System.Windows.Forms.TextBox(); this.textBoxBlue = new System.Windows.Forms.TextBox(); - this.labelRecentColors = new GreenshotPlugin.Controls.GreenshotLabel(); + this.labelRecentColors = new GreenshotLabel(); this.textBoxAlpha = new System.Windows.Forms.TextBox(); - this.labelAlpha = new GreenshotPlugin.Controls.GreenshotLabel(); - this.btnApply = new GreenshotPlugin.Controls.GreenshotButton(); + this.labelAlpha = new GreenshotLabel(); + this.btnApply = new GreenshotButton(); this.pipette = new Greenshot.Controls.Pipette(); this.SuspendLayout(); // @@ -260,20 +263,20 @@ namespace Greenshot.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotLabel labelRed; - private GreenshotPlugin.Controls.GreenshotLabel labelGreen; - private GreenshotPlugin.Controls.GreenshotLabel labelBlue; + private GreenshotLabel labelRed; + private GreenshotLabel labelGreen; + private GreenshotLabel labelBlue; private System.Windows.Forms.TextBox textBoxHtmlColor; - private GreenshotPlugin.Controls.GreenshotLabel labelRecentColors; - private GreenshotPlugin.Controls.GreenshotLabel labelAlpha; - private GreenshotPlugin.Controls.GreenshotLabel labelHtmlColor; - private GreenshotPlugin.Controls.GreenshotButton btnApply; + private GreenshotLabel labelRecentColors; + private GreenshotLabel labelAlpha; + private GreenshotLabel labelHtmlColor; + private GreenshotButton btnApply; private System.Windows.Forms.TextBox textBoxAlpha; private System.Windows.Forms.TextBox textBoxRed; private System.Windows.Forms.TextBox textBoxGreen; private System.Windows.Forms.TextBox textBoxBlue; private System.Windows.Forms.Panel colorPanel; - private GreenshotPlugin.Controls.GreenshotButton btnTransparent; + private GreenshotButton btnTransparent; private Greenshot.Controls.Pipette pipette; diff --git a/src/Greenshot/Forms/ColorDialog.cs b/src/Greenshot/Forms/ColorDialog.cs index 91c314cd9..6653ecf08 100644 --- a/src/Greenshot/Forms/ColorDialog.cs +++ b/src/Greenshot/Forms/ColorDialog.cs @@ -25,9 +25,9 @@ using System.Drawing; using System.Globalization; using System.Threading; using System.Windows.Forms; +using Greenshot.Base.IniFile; using Greenshot.Configuration; using Greenshot.Controls; -using GreenshotPlugin.IniFile; namespace Greenshot.Forms { diff --git a/src/Greenshot/Forms/DropShadowSettingsForm.Designer.cs b/src/Greenshot/Forms/DropShadowSettingsForm.Designer.cs index 0f7a89618..489cbfd6f 100644 --- a/src/Greenshot/Forms/DropShadowSettingsForm.Designer.cs +++ b/src/Greenshot/Forms/DropShadowSettingsForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Forms { partial class DropShadowSettingsForm { /// @@ -48,11 +51,11 @@ namespace Greenshot.Forms { this.label3 = new System.Windows.Forms.Label(); this.offsetY = new System.Windows.Forms.NumericUpDown(); this.trackBar1 = new System.Windows.Forms.TrackBar(); - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.labelDarkness = new GreenshotPlugin.Controls.GreenshotLabel(); - this.labelOffset = new GreenshotPlugin.Controls.GreenshotLabel(); - this.labelThickness = new GreenshotPlugin.Controls.GreenshotLabel(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.labelDarkness = new GreenshotLabel(); + this.labelOffset = new GreenshotLabel(); + this.labelThickness = new GreenshotLabel(); ((System.ComponentModel.ISupportInitialize)(this.thickness)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.offsetX)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.offsetY)).BeginInit(); @@ -227,10 +230,10 @@ namespace Greenshot.Forms { private System.Windows.Forms.Label label3; private System.Windows.Forms.NumericUpDown offsetY; private System.Windows.Forms.TrackBar trackBar1; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotLabel labelDarkness; - private GreenshotPlugin.Controls.GreenshotLabel labelOffset; - private GreenshotPlugin.Controls.GreenshotLabel labelThickness; + private GreenshotButton buttonOK; + private GreenshotButton buttonCancel; + private GreenshotLabel labelDarkness; + private GreenshotLabel labelOffset; + private GreenshotLabel labelThickness; } } \ No newline at end of file diff --git a/src/Greenshot/Forms/DropShadowSettingsForm.cs b/src/Greenshot/Forms/DropShadowSettingsForm.cs index 8a1e57f56..c798f8109 100644 --- a/src/Greenshot/Forms/DropShadowSettingsForm.cs +++ b/src/Greenshot/Forms/DropShadowSettingsForm.cs @@ -22,7 +22,7 @@ using System; using System.Drawing; using System.Windows.Forms; -using GreenshotPlugin.Effects; +using Greenshot.Base.Effects; namespace Greenshot.Forms { diff --git a/src/Greenshot/Forms/ImageEditorForm.Designer.cs b/src/Greenshot/Forms/ImageEditorForm.Designer.cs index 0db33a212..3ebcb0ef0 100644 --- a/src/Greenshot/Forms/ImageEditorForm.Designer.cs +++ b/src/Greenshot/Forms/ImageEditorForm.Designer.cs @@ -19,6 +19,7 @@ * along with this program. If not, see . */ +using Greenshot.Base.Controls; using Greenshot.Controls; namespace Greenshot.Forms { @@ -58,142 +59,142 @@ namespace Greenshot.Forms { this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.panel1 = new NonJumpingPanel(); this.toolsToolStrip = new Greenshot.Controls.ToolStripEx(); - this.btnCursor = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnCursor = new GreenshotToolStripButton(); this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); - this.btnRect = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnEllipse = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnLine = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnArrow = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnFreehand = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnText = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnSpeechBubble = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnStepLabel = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnRect = new GreenshotToolStripButton(); + this.btnEllipse = new GreenshotToolStripButton(); + this.btnLine = new GreenshotToolStripButton(); + this.btnArrow = new GreenshotToolStripButton(); + this.btnFreehand = new GreenshotToolStripButton(); + this.btnText = new GreenshotToolStripButton(); + this.btnSpeechBubble = new GreenshotToolStripButton(); + this.btnStepLabel = new GreenshotToolStripButton(); this.toolStripSeparator14 = new System.Windows.Forms.ToolStripSeparator(); - this.btnHighlight = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnObfuscate = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.toolStripSplitButton1 = new GreenshotPlugin.Controls.GreenshotToolStripDropDownButton(); - this.addBorderToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.addDropshadowToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.tornEdgesToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.grayscaleToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.invertToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.btnResize = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnHighlight = new GreenshotToolStripButton(); + this.btnObfuscate = new GreenshotToolStripButton(); + this.toolStripSplitButton1 = new GreenshotToolStripDropDownButton(); + this.addBorderToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.addDropshadowToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.tornEdgesToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.grayscaleToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.invertToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.btnResize = new GreenshotToolStripButton(); this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator(); - this.btnCrop = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.rotateCwToolstripButton = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.rotateCcwToolstripButton = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnCrop = new GreenshotToolStripButton(); + this.rotateCwToolstripButton = new GreenshotToolStripButton(); + this.rotateCcwToolstripButton = new GreenshotToolStripButton(); this.menuStrip1 = new Greenshot.Controls.MenuStripEx(); - this.fileStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.editToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.fileStripMenuItem = new GreenshotToolStripMenuItem(); + this.editToolStripMenuItem = new GreenshotToolStripMenuItem(); this.undoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.redoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator15 = new System.Windows.Forms.ToolStripSeparator(); - this.cutToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.copyToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.pasteToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.cutToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.copyToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.pasteToolStripMenuItem = new GreenshotToolStripMenuItem(); this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); - this.duplicateToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.duplicateToolStripMenuItem = new GreenshotToolStripMenuItem(); this.toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator(); - this.preferencesToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.preferencesToolStripMenuItem = new GreenshotToolStripMenuItem(); this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); - this.autoCropToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.autoCropToolStripMenuItem = new GreenshotToolStripMenuItem(); this.toolStripSeparator17 = new System.Windows.Forms.ToolStripSeparator(); - this.insert_window_toolstripmenuitem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.objectToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.addRectangleToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.addEllipseToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.drawLineToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.drawArrowToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.drawFreehandToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.addTextBoxToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.addSpeechBubbleToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.addCounterToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.insert_window_toolstripmenuitem = new GreenshotToolStripMenuItem(); + this.objectToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.addRectangleToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.addEllipseToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.drawLineToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.drawArrowToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.drawFreehandToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.addTextBoxToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.addSpeechBubbleToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.addCounterToolStripMenuItem = new GreenshotToolStripMenuItem(); this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator(); - this.selectAllToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.removeObjectToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.selectAllToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.removeObjectToolStripMenuItem = new GreenshotToolStripMenuItem(); this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); - this.arrangeToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.upToTopToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.upOneLevelToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.downOneLevelToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.downToBottomToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.saveElementsToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.loadElementsToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.pluginToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.helpToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.helpToolStripMenuItem1 = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.aboutToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.arrangeToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.upToTopToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.upOneLevelToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.downOneLevelToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.downToBottomToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.saveElementsToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.loadElementsToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.pluginToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.helpToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.helpToolStripMenuItem1 = new GreenshotToolStripMenuItem(); + this.aboutToolStripMenuItem = new GreenshotToolStripMenuItem(); this.destinationsToolStrip = new Greenshot.Controls.ToolStripEx(); - this.btnSave = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnClipboard = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnPrint = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnSave = new GreenshotToolStripButton(); + this.btnClipboard = new GreenshotToolStripButton(); + this.btnPrint = new GreenshotToolStripButton(); this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); - this.btnDelete = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnDelete = new GreenshotToolStripButton(); this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); - this.btnCut = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnCopy = new GreenshotPlugin.Controls.GreenshotToolStripButton(); - this.btnPaste = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnCut = new GreenshotToolStripButton(); + this.btnCopy = new GreenshotToolStripButton(); + this.btnPaste = new GreenshotToolStripButton(); this.btnUndo = new System.Windows.Forms.ToolStripButton(); this.btnRedo = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); - this.btnSettings = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnSettings = new GreenshotToolStripButton(); this.toolStripSeparator11 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripSeparator16 = new System.Windows.Forms.ToolStripSeparator(); - this.btnHelp = new GreenshotPlugin.Controls.GreenshotToolStripButton(); + this.btnHelp = new GreenshotToolStripButton(); this.propertiesToolStrip = new Greenshot.Controls.ToolStripEx(); this.obfuscateModeButton = new Greenshot.Controls.BindableToolStripDropDownButton(); - this.pixelizeToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.blurToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.pixelizeToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.blurToolStripMenuItem = new GreenshotToolStripMenuItem(); this.highlightModeButton = new Greenshot.Controls.BindableToolStripDropDownButton(); - this.textHighlightMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.areaHighlightMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.grayscaleHighlightMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.magnifyMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.textHighlightMenuItem = new GreenshotToolStripMenuItem(); + this.areaHighlightMenuItem = new GreenshotToolStripMenuItem(); + this.grayscaleHighlightMenuItem = new GreenshotToolStripMenuItem(); + this.magnifyMenuItem = new GreenshotToolStripMenuItem(); this.btnFillColor = new Greenshot.Controls.ToolStripColorButton(); this.btnLineColor = new Greenshot.Controls.ToolStripColorButton(); - this.lineThicknessLabel = new GreenshotPlugin.Controls.GreenshotToolStripLabel(); + this.lineThicknessLabel = new GreenshotToolStripLabel(); this.lineThicknessUpDown = new Greenshot.Controls.ToolStripNumericUpDown(); - this.counterLabel = new GreenshotPlugin.Controls.GreenshotToolStripLabel(); + this.counterLabel = new GreenshotToolStripLabel(); this.counterUpDown = new Greenshot.Controls.ToolStripNumericUpDown(); this.fontFamilyComboBox = new Greenshot.Controls.FontFamilyComboBox(); - this.fontSizeLabel = new GreenshotPlugin.Controls.GreenshotToolStripLabel(); + this.fontSizeLabel = new GreenshotToolStripLabel(); this.fontSizeUpDown = new Greenshot.Controls.ToolStripNumericUpDown(); this.fontBoldButton = new Greenshot.Controls.BindableToolStripButton(); this.fontItalicButton = new Greenshot.Controls.BindableToolStripButton(); this.textVerticalAlignmentButton = new Greenshot.Controls.BindableToolStripDropDownButton(); - this.alignTopToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.alignMiddleToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.alignBottomToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.blurRadiusLabel = new GreenshotPlugin.Controls.GreenshotToolStripLabel(); + this.alignTopToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.alignMiddleToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.alignBottomToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.blurRadiusLabel = new GreenshotToolStripLabel(); this.blurRadiusUpDown = new Greenshot.Controls.ToolStripNumericUpDown(); - this.brightnessLabel = new GreenshotPlugin.Controls.GreenshotToolStripLabel(); + this.brightnessLabel = new GreenshotToolStripLabel(); this.brightnessUpDown = new Greenshot.Controls.ToolStripNumericUpDown(); - this.previewQualityLabel = new GreenshotPlugin.Controls.GreenshotToolStripLabel(); + this.previewQualityLabel = new GreenshotToolStripLabel(); this.previewQualityUpDown = new Greenshot.Controls.ToolStripNumericUpDown(); - this.magnificationFactorLabel = new GreenshotPlugin.Controls.GreenshotToolStripLabel(); + this.magnificationFactorLabel = new GreenshotToolStripLabel(); this.magnificationFactorUpDown = new Greenshot.Controls.ToolStripNumericUpDown(); - this.pixelSizeLabel = new GreenshotPlugin.Controls.GreenshotToolStripLabel(); + this.pixelSizeLabel = new GreenshotToolStripLabel(); this.pixelSizeUpDown = new Greenshot.Controls.ToolStripNumericUpDown(); - this.arrowHeadsLabel = new GreenshotPlugin.Controls.GreenshotToolStripLabel(); - this.arrowHeadsDropDownButton = new GreenshotPlugin.Controls.GreenshotToolStripDropDownButton(); - this.arrowHeadStartMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.arrowHeadEndMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.arrowHeadBothMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.arrowHeadNoneMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.arrowHeadsLabel = new GreenshotToolStripLabel(); + this.arrowHeadsDropDownButton = new GreenshotToolStripDropDownButton(); + this.arrowHeadStartMenuItem = new GreenshotToolStripMenuItem(); + this.arrowHeadEndMenuItem = new GreenshotToolStripMenuItem(); + this.arrowHeadBothMenuItem = new GreenshotToolStripMenuItem(); + this.arrowHeadNoneMenuItem = new GreenshotToolStripMenuItem(); this.shadowButton = new Greenshot.Controls.BindableToolStripButton(); this.toolStripSeparator = new System.Windows.Forms.ToolStripSeparator(); this.toolStripSeparator10 = new System.Windows.Forms.ToolStripSeparator(); this.btnConfirm = new Greenshot.Controls.BindableToolStripButton(); this.btnCancel = new Greenshot.Controls.BindableToolStripButton(); this.toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator(); - this.closeToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.closeToolStripMenuItem = new GreenshotToolStripMenuItem(); this.fileSavedStatusContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); - this.copyPathMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.openDirectoryMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.copyPathMenuItem = new GreenshotToolStripMenuItem(); + this.openDirectoryMenuItem = new GreenshotToolStripMenuItem(); this.textHorizontalAlignmentButton = new Greenshot.Controls.BindableToolStripDropDownButton(); - this.alignLeftToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.alignCenterToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.alignRightToolStripMenuItem = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.alignLeftToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.alignCenterToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.alignRightToolStripMenuItem = new GreenshotToolStripMenuItem(); this.zoomMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.zoomInMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.zoomOutMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -1839,44 +1840,44 @@ namespace Greenshot.Forms { this.fileSavedStatusContextMenu.ResumeLayout(true); this.ResumeLayout(false); } - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem alignRightToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem alignCenterToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem alignLeftToolStripMenuItem; + private GreenshotToolStripMenuItem alignRightToolStripMenuItem; + private GreenshotToolStripMenuItem alignCenterToolStripMenuItem; + private GreenshotToolStripMenuItem alignLeftToolStripMenuItem; private Greenshot.Controls.BindableToolStripDropDownButton textHorizontalAlignmentButton; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem alignMiddleToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem alignBottomToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem alignTopToolStripMenuItem; + private GreenshotToolStripMenuItem alignMiddleToolStripMenuItem; + private GreenshotToolStripMenuItem alignBottomToolStripMenuItem; + private GreenshotToolStripMenuItem alignTopToolStripMenuItem; private Greenshot.Controls.BindableToolStripDropDownButton textVerticalAlignmentButton; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem invertToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnResize; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem grayscaleToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripButton rotateCcwToolstripButton; - private GreenshotPlugin.Controls.GreenshotToolStripButton rotateCwToolstripButton; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem addBorderToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem tornEdgesToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem addDropshadowToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripDropDownButton toolStripSplitButton1; + private GreenshotToolStripMenuItem invertToolStripMenuItem; + private GreenshotToolStripButton btnResize; + private GreenshotToolStripMenuItem grayscaleToolStripMenuItem; + private GreenshotToolStripButton rotateCcwToolstripButton; + private GreenshotToolStripButton rotateCwToolstripButton; + private GreenshotToolStripMenuItem addBorderToolStripMenuItem; + private GreenshotToolStripMenuItem tornEdgesToolStripMenuItem; + private GreenshotToolStripMenuItem addDropshadowToolStripMenuItem; + private GreenshotToolStripDropDownButton toolStripSplitButton1; private System.Windows.Forms.ToolStripStatusLabel dimensionsLabel; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem insert_window_toolstripmenuitem; + private GreenshotToolStripMenuItem insert_window_toolstripmenuitem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem grayscaleHighlightMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem areaHighlightMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem textHighlightMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem magnifyMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem arrowHeadStartMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem arrowHeadEndMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem arrowHeadBothMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem arrowHeadNoneMenuItem; + private GreenshotToolStripMenuItem grayscaleHighlightMenuItem; + private GreenshotToolStripMenuItem areaHighlightMenuItem; + private GreenshotToolStripMenuItem textHighlightMenuItem; + private GreenshotToolStripMenuItem magnifyMenuItem; + private GreenshotToolStripMenuItem arrowHeadStartMenuItem; + private GreenshotToolStripMenuItem arrowHeadEndMenuItem; + private GreenshotToolStripMenuItem arrowHeadBothMenuItem; + private GreenshotToolStripMenuItem arrowHeadNoneMenuItem; private Greenshot.Controls.BindableToolStripButton btnCancel; private Greenshot.Controls.BindableToolStripButton btnConfirm; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem selectAllToolStripMenuItem; + private GreenshotToolStripMenuItem selectAllToolStripMenuItem; private Greenshot.Controls.BindableToolStripDropDownButton highlightModeButton; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem pixelizeToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem blurToolStripMenuItem; + private GreenshotToolStripMenuItem pixelizeToolStripMenuItem; + private GreenshotToolStripMenuItem blurToolStripMenuItem; private Greenshot.Controls.BindableToolStripDropDownButton obfuscateModeButton; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnHighlight; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem loadElementsToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem saveElementsToolStripMenuItem; + private GreenshotToolStripButton btnHighlight; + private GreenshotToolStripMenuItem loadElementsToolStripMenuItem; + private GreenshotToolStripMenuItem saveElementsToolStripMenuItem; private Greenshot.Controls.FontFamilyComboBox fontFamilyComboBox; private System.Windows.Forms.ToolStripSeparator toolStripSeparator10; private System.Windows.Forms.ToolStripSeparator toolStripSeparator; @@ -1884,103 +1885,103 @@ namespace Greenshot.Forms { private Greenshot.Controls.BindableToolStripButton fontItalicButton; private Greenshot.Controls.BindableToolStripButton fontBoldButton; private Greenshot.Controls.ToolStripNumericUpDown fontSizeUpDown; - private GreenshotPlugin.Controls.GreenshotToolStripLabel fontSizeLabel; + private GreenshotToolStripLabel fontSizeLabel; private Greenshot.Controls.ToolStripNumericUpDown brightnessUpDown; - private GreenshotPlugin.Controls.GreenshotToolStripLabel brightnessLabel; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem pluginToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripDropDownButton arrowHeadsDropDownButton; - private GreenshotPlugin.Controls.GreenshotToolStripLabel arrowHeadsLabel; + private GreenshotToolStripLabel brightnessLabel; + private GreenshotToolStripMenuItem pluginToolStripMenuItem; + private GreenshotToolStripDropDownButton arrowHeadsDropDownButton; + private GreenshotToolStripLabel arrowHeadsLabel; private Greenshot.Controls.ToolStripNumericUpDown pixelSizeUpDown; - private GreenshotPlugin.Controls.GreenshotToolStripLabel pixelSizeLabel; + private GreenshotToolStripLabel pixelSizeLabel; private Greenshot.Controls.ToolStripNumericUpDown magnificationFactorUpDown; - private GreenshotPlugin.Controls.GreenshotToolStripLabel magnificationFactorLabel; + private GreenshotToolStripLabel magnificationFactorLabel; private Greenshot.Controls.ToolStripNumericUpDown previewQualityUpDown; - private GreenshotPlugin.Controls.GreenshotToolStripLabel previewQualityLabel; + private GreenshotToolStripLabel previewQualityLabel; private Greenshot.Controls.ToolStripNumericUpDown blurRadiusUpDown; - private GreenshotPlugin.Controls.GreenshotToolStripLabel blurRadiusLabel; + private GreenshotToolStripLabel blurRadiusLabel; private Greenshot.Controls.ToolStripEx propertiesToolStrip; - private GreenshotPlugin.Controls.GreenshotToolStripLabel lineThicknessLabel; + private GreenshotToolStripLabel lineThicknessLabel; private Greenshot.Controls.ToolStripNumericUpDown lineThicknessUpDown; - private GreenshotPlugin.Controls.GreenshotToolStripLabel counterLabel; + private GreenshotToolStripLabel counterLabel; private Greenshot.Controls.ToolStripNumericUpDown counterUpDown; private System.Windows.Forms.ToolStripSeparator toolStripSeparator14; private System.Windows.Forms.ToolStripSeparator toolStripSeparator15; private System.Windows.Forms.ToolStripSeparator toolStripSeparator16; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnFreehand; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnObfuscate; + private GreenshotToolStripButton btnFreehand; + private GreenshotToolStripButton btnObfuscate; private System.Windows.Forms.ToolStripSeparator toolStripSeparator13; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnCrop; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem openDirectoryMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem copyPathMenuItem; + private GreenshotToolStripButton btnCrop; + private GreenshotToolStripMenuItem openDirectoryMenuItem; + private GreenshotToolStripMenuItem copyPathMenuItem; private System.Windows.Forms.ContextMenuStrip fileSavedStatusContextMenu; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem downToBottomToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem upToTopToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem downOneLevelToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem upOneLevelToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem arrangeToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnCursor; + private GreenshotToolStripMenuItem downToBottomToolStripMenuItem; + private GreenshotToolStripMenuItem upToTopToolStripMenuItem; + private GreenshotToolStripMenuItem downOneLevelToolStripMenuItem; + private GreenshotToolStripMenuItem upOneLevelToolStripMenuItem; + private GreenshotToolStripMenuItem arrangeToolStripMenuItem; + private GreenshotToolStripButton btnCursor; private Greenshot.Controls.ToolStripEx toolsToolStrip; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnArrow; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem drawArrowToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem drawFreehandToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnText; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnSpeechBubble; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnStepLabel; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem drawLineToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnLine; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnSettings; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnHelp; + private GreenshotToolStripButton btnArrow; + private GreenshotToolStripMenuItem drawArrowToolStripMenuItem; + private GreenshotToolStripMenuItem drawFreehandToolStripMenuItem; + private GreenshotToolStripButton btnText; + private GreenshotToolStripButton btnSpeechBubble; + private GreenshotToolStripButton btnStepLabel; + private GreenshotToolStripMenuItem drawLineToolStripMenuItem; + private GreenshotToolStripButton btnLine; + private GreenshotToolStripButton btnSettings; + private GreenshotToolStripButton btnHelp; private System.Windows.Forms.ToolStripSeparator toolStripSeparator11; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem aboutToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem helpToolStripMenuItem1; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem helpToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem preferencesToolStripMenuItem; + private GreenshotToolStripMenuItem aboutToolStripMenuItem; + private GreenshotToolStripMenuItem helpToolStripMenuItem1; + private GreenshotToolStripMenuItem helpToolStripMenuItem; + private GreenshotToolStripMenuItem preferencesToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator12; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem closeToolStripMenuItem; + private GreenshotToolStripMenuItem closeToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator9; private System.Windows.Forms.ToolStripSeparator toolStripSeparator7; private System.Windows.Forms.ToolStripSeparator toolStripSeparator8; private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnPrint; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem duplicateToolStripMenuItem; + private GreenshotToolStripButton btnPrint; + private GreenshotToolStripMenuItem duplicateToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem fileStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem removeObjectToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem addTextBoxToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem addSpeechBubbleToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem addCounterToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem addEllipseToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem addRectangleToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem objectToolStripMenuItem; + private GreenshotToolStripMenuItem fileStripMenuItem; + private GreenshotToolStripMenuItem removeObjectToolStripMenuItem; + private GreenshotToolStripMenuItem addTextBoxToolStripMenuItem; + private GreenshotToolStripMenuItem addSpeechBubbleToolStripMenuItem; + private GreenshotToolStripMenuItem addCounterToolStripMenuItem; + private GreenshotToolStripMenuItem addEllipseToolStripMenuItem; + private GreenshotToolStripMenuItem addRectangleToolStripMenuItem; + private GreenshotToolStripMenuItem objectToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem undoToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem redoToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem pasteToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem copyToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem cutToolStripMenuItem; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem editToolStripMenuItem; + private GreenshotToolStripMenuItem pasteToolStripMenuItem; + private GreenshotToolStripMenuItem copyToolStripMenuItem; + private GreenshotToolStripMenuItem cutToolStripMenuItem; + private GreenshotToolStripMenuItem editToolStripMenuItem; private Greenshot.Controls.MenuStripEx menuStrip1; private System.Windows.Forms.ToolStripStatusLabel statusLabel; private System.Windows.Forms.StatusStrip statusStrip1; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnCut; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnCopy; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnPaste; + private GreenshotToolStripButton btnCut; + private GreenshotToolStripButton btnCopy; + private GreenshotToolStripButton btnPaste; private System.Windows.Forms.ToolStripButton btnUndo; private System.Windows.Forms.ToolStripButton btnRedo; private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnClipboard; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnDelete; + private GreenshotToolStripButton btnClipboard; + private GreenshotToolStripButton btnDelete; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnEllipse; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnSave; - private GreenshotPlugin.Controls.GreenshotToolStripButton btnRect; + private GreenshotToolStripButton btnEllipse; + private GreenshotToolStripButton btnSave; + private GreenshotToolStripButton btnRect; private System.Windows.Forms.ToolStripContainer topToolStripContainer; private Greenshot.Controls.ToolStripEx destinationsToolStrip; private NonJumpingPanel panel1; private Greenshot.Controls.ToolStripColorButton btnFillColor; private Greenshot.Controls.ToolStripColorButton btnLineColor; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem autoCropToolStripMenuItem; + private GreenshotToolStripMenuItem autoCropToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator17; private System.Windows.Forms.ContextMenuStrip zoomMenuStrip; private System.Windows.Forms.ToolStripMenuItem zoomInMenuItem; diff --git a/src/Greenshot/Forms/ImageEditorForm.cs b/src/Greenshot/Forms/ImageEditorForm.cs index 1764ef4f1..6c7530120 100644 --- a/src/Greenshot/Forms/ImageEditorForm.cs +++ b/src/Greenshot/Forms/ImageEditorForm.cs @@ -26,6 +26,15 @@ using System.Drawing.Drawing2D; using System.IO; using System.Threading; using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Forms; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Structs; using Greenshot.Configuration; using Greenshot.Destinations; using Greenshot.Drawing; @@ -33,15 +42,6 @@ using Greenshot.Drawing.Fields; using Greenshot.Drawing.Fields.Binding; using Greenshot.Help; using Greenshot.Helpers; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Drawing; -using GreenshotPlugin.Interfaces.Forms; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.UnmanagedHelpers.Structs; using log4net; namespace Greenshot.Forms diff --git a/src/Greenshot/Forms/LanguageDialog.cs b/src/Greenshot/Forms/LanguageDialog.cs index a55b7f042..7511eff95 100644 --- a/src/Greenshot/Forms/LanguageDialog.cs +++ b/src/Greenshot/Forms/LanguageDialog.cs @@ -22,7 +22,7 @@ using System; using System.Threading; using System.Windows.Forms; -using GreenshotPlugin.Core; +using Greenshot.Base.Core; using log4net; namespace Greenshot.Forms diff --git a/src/Greenshot/Forms/MainForm.Designer.cs b/src/Greenshot/Forms/MainForm.Designer.cs index 281886180..f33e60f05 100644 --- a/src/Greenshot/Forms/MainForm.Designer.cs +++ b/src/Greenshot/Forms/MainForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Forms { partial class MainForm { /// @@ -50,22 +53,22 @@ namespace Greenshot.Forms { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); this.contextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); - this.contextmenu_capturearea = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_capturelastregion = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_capturewindow = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_capturefullscreen = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_captureie = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_capturewindowfromlist = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_captureiefromlist = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_captureclipboard = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_openfile = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_openrecentcapture = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_quicksettings = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_settings = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_help = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_donate = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_about = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); - this.contextmenu_exit = new GreenshotPlugin.Controls.GreenshotToolStripMenuItem(); + this.contextmenu_capturearea = new GreenshotToolStripMenuItem(); + this.contextmenu_capturelastregion = new GreenshotToolStripMenuItem(); + this.contextmenu_capturewindow = new GreenshotToolStripMenuItem(); + this.contextmenu_capturefullscreen = new GreenshotToolStripMenuItem(); + this.contextmenu_captureie = new GreenshotToolStripMenuItem(); + this.contextmenu_capturewindowfromlist = new GreenshotToolStripMenuItem(); + this.contextmenu_captureiefromlist = new GreenshotToolStripMenuItem(); + this.contextmenu_captureclipboard = new GreenshotToolStripMenuItem(); + this.contextmenu_openfile = new GreenshotToolStripMenuItem(); + this.contextmenu_openrecentcapture = new GreenshotToolStripMenuItem(); + this.contextmenu_quicksettings = new GreenshotToolStripMenuItem(); + this.contextmenu_settings = new GreenshotToolStripMenuItem(); + this.contextmenu_help = new GreenshotToolStripMenuItem(); + this.contextmenu_donate = new GreenshotToolStripMenuItem(); + this.contextmenu_about = new GreenshotToolStripMenuItem(); + this.contextmenu_exit = new GreenshotToolStripMenuItem(); this.toolStripListCaptureSeparator = new System.Windows.Forms.ToolStripSeparator(); this.toolStripOtherSourcesSeparator = new System.Windows.Forms.ToolStripSeparator(); this.toolStripOpenFolderSeparator = new System.Windows.Forms.ToolStripSeparator(); @@ -270,29 +273,29 @@ namespace Greenshot.Forms { this.contextMenu.ResumeLayout(false); this.ResumeLayout(false); } - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_captureiefromlist; + private GreenshotToolStripMenuItem contextmenu_captureiefromlist; private System.Windows.Forms.ToolStripSeparator toolStripOtherSourcesSeparator; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_capturewindowfromlist; + private GreenshotToolStripMenuItem contextmenu_capturewindowfromlist; private System.Windows.Forms.ToolStripSeparator toolStripListCaptureSeparator; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_openrecentcapture; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_captureie; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_donate; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_openfile; + private GreenshotToolStripMenuItem contextmenu_openrecentcapture; + private GreenshotToolStripMenuItem contextmenu_captureie; + private GreenshotToolStripMenuItem contextmenu_donate; + private GreenshotToolStripMenuItem contextmenu_openfile; private System.Windows.Forms.ToolStripSeparator toolStripPluginSeparator; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_captureclipboard; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_quicksettings; + private GreenshotToolStripMenuItem contextmenu_captureclipboard; + private GreenshotToolStripMenuItem contextmenu_quicksettings; private System.Windows.Forms.ToolStripSeparator toolStripMiscSeparator; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_help; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_capturewindow; + private GreenshotToolStripMenuItem contextmenu_help; + private GreenshotToolStripMenuItem contextmenu_capturewindow; private System.Windows.Forms.ToolStripSeparator toolStripOpenFolderSeparator; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_about; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_capturefullscreen; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_capturelastregion; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_capturearea; + private GreenshotToolStripMenuItem contextmenu_about; + private GreenshotToolStripMenuItem contextmenu_capturefullscreen; + private GreenshotToolStripMenuItem contextmenu_capturelastregion; + private GreenshotToolStripMenuItem contextmenu_capturearea; private System.Windows.Forms.NotifyIcon notifyIcon; private System.Windows.Forms.ToolStripSeparator toolStripCloseSeparator; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_exit; + private GreenshotToolStripMenuItem contextmenu_exit; private System.Windows.Forms.ContextMenuStrip contextMenu; - private GreenshotPlugin.Controls.GreenshotToolStripMenuItem contextmenu_settings; + private GreenshotToolStripMenuItem contextmenu_settings; } } diff --git a/src/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs index 2b56ab7a7..7c3f461fb 100644 --- a/src/Greenshot/Forms/MainForm.cs +++ b/src/Greenshot/Forms/MainForm.cs @@ -32,17 +32,17 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.Integration; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Base.UnmanagedHelpers; using Greenshot.Configuration; using Greenshot.Destinations; using Greenshot.Drawing; using Greenshot.Help; using Greenshot.Helpers; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; -using GreenshotPlugin.UnmanagedHelpers; using log4net; using Timer = System.Timers.Timer; diff --git a/src/Greenshot/Forms/MovableShowColorForm.cs b/src/Greenshot/Forms/MovableShowColorForm.cs index 1005af9c8..36afe9661 100644 --- a/src/Greenshot/Forms/MovableShowColorForm.cs +++ b/src/Greenshot/Forms/MovableShowColorForm.cs @@ -22,7 +22,7 @@ using System; using System.Windows.Forms; using System.Drawing; -using GreenshotPlugin.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers; namespace Greenshot.Forms { diff --git a/src/Greenshot/Forms/PrintOptionsDialog.Designer.cs b/src/Greenshot/Forms/PrintOptionsDialog.Designer.cs index 0de6ca3a9..cea22b9ac 100644 --- a/src/Greenshot/Forms/PrintOptionsDialog.Designer.cs +++ b/src/Greenshot/Forms/PrintOptionsDialog.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Forms { partial class PrintOptionsDialog @@ -48,20 +51,20 @@ namespace Greenshot.Forms /// private void InitializeComponent() { - this.checkbox_dontaskagain = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkboxAllowShrink = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkboxAllowEnlarge = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkboxAllowCenter = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkboxAllowRotate = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.button_ok = new GreenshotPlugin.Controls.GreenshotButton(); - this.checkboxDateTime = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.button_cancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.checkboxPrintInverted = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.radioBtnGrayScale = new GreenshotPlugin.Controls.GreenshotRadioButton(); - this.radioBtnMonochrome = new GreenshotPlugin.Controls.GreenshotRadioButton(); - this.groupBoxPrintLayout = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.groupBoxColors = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.radioBtnColorPrint = new GreenshotPlugin.Controls.GreenshotRadioButton(); + this.checkbox_dontaskagain = new GreenshotCheckBox(); + this.checkboxAllowShrink = new GreenshotCheckBox(); + this.checkboxAllowEnlarge = new GreenshotCheckBox(); + this.checkboxAllowCenter = new GreenshotCheckBox(); + this.checkboxAllowRotate = new GreenshotCheckBox(); + this.button_ok = new GreenshotButton(); + this.checkboxDateTime = new GreenshotCheckBox(); + this.button_cancel = new GreenshotButton(); + this.checkboxPrintInverted = new GreenshotCheckBox(); + this.radioBtnGrayScale = new GreenshotRadioButton(); + this.radioBtnMonochrome = new GreenshotRadioButton(); + this.groupBoxPrintLayout = new GreenshotGroupBox(); + this.groupBoxColors = new GreenshotGroupBox(); + this.radioBtnColorPrint = new GreenshotRadioButton(); this.groupBoxPrintLayout.SuspendLayout(); this.groupBoxColors.SuspendLayout(); this.SuspendLayout(); @@ -282,19 +285,19 @@ namespace Greenshot.Forms this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotRadioButton radioBtnGrayScale; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxPrintInverted; - private GreenshotPlugin.Controls.GreenshotButton button_cancel; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxDateTime; - private GreenshotPlugin.Controls.GreenshotButton button_ok; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAllowRotate; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAllowCenter; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAllowEnlarge; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAllowShrink; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_dontaskagain; - private GreenshotPlugin.Controls.GreenshotRadioButton radioBtnMonochrome; - private GreenshotPlugin.Controls.GreenshotGroupBox groupBoxPrintLayout; - private GreenshotPlugin.Controls.GreenshotGroupBox groupBoxColors; - private GreenshotPlugin.Controls.GreenshotRadioButton radioBtnColorPrint; + private GreenshotRadioButton radioBtnGrayScale; + private GreenshotCheckBox checkboxPrintInverted; + private GreenshotButton button_cancel; + private GreenshotCheckBox checkboxDateTime; + private GreenshotButton button_ok; + private GreenshotCheckBox checkboxAllowRotate; + private GreenshotCheckBox checkboxAllowCenter; + private GreenshotCheckBox checkboxAllowEnlarge; + private GreenshotCheckBox checkboxAllowShrink; + private GreenshotCheckBox checkbox_dontaskagain; + private GreenshotRadioButton radioBtnMonochrome; + private GreenshotGroupBox groupBoxPrintLayout; + private GreenshotGroupBox groupBoxColors; + private GreenshotRadioButton radioBtnColorPrint; } } diff --git a/src/Greenshot/Forms/PrintOptionsDialog.cs b/src/Greenshot/Forms/PrintOptionsDialog.cs index 537efb352..786b3bfc4 100644 --- a/src/Greenshot/Forms/PrintOptionsDialog.cs +++ b/src/Greenshot/Forms/PrintOptionsDialog.cs @@ -21,7 +21,7 @@ using System; using System.Windows.Forms; -using GreenshotPlugin.IniFile; +using Greenshot.Base.IniFile; namespace Greenshot.Forms { diff --git a/src/Greenshot/Forms/ResizeSettingsForm.Designer.cs b/src/Greenshot/Forms/ResizeSettingsForm.Designer.cs index e7675bb57..3338fa62b 100644 --- a/src/Greenshot/Forms/ResizeSettingsForm.Designer.cs +++ b/src/Greenshot/Forms/ResizeSettingsForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Forms { partial class ResizeSettingsForm { /// @@ -43,11 +46,11 @@ namespace Greenshot.Forms { /// the contents of this method with the code editor. /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.checkbox_aspectratio = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.label_width = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_height = new GreenshotPlugin.Controls.GreenshotLabel(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.checkbox_aspectratio = new GreenshotCheckBox(); + this.label_width = new GreenshotLabel(); + this.label_height = new GreenshotLabel(); this.textbox_height = new System.Windows.Forms.TextBox(); this.textbox_width = new System.Windows.Forms.TextBox(); this.combobox_width = new System.Windows.Forms.ComboBox(); @@ -164,11 +167,11 @@ namespace Greenshot.Forms { #endregion - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_aspectratio; - private GreenshotPlugin.Controls.GreenshotLabel label_width; - private GreenshotPlugin.Controls.GreenshotLabel label_height; + private GreenshotButton buttonOK; + private GreenshotButton buttonCancel; + private GreenshotCheckBox checkbox_aspectratio; + private GreenshotLabel label_width; + private GreenshotLabel label_height; private System.Windows.Forms.TextBox textbox_height; private System.Windows.Forms.TextBox textbox_width; private System.Windows.Forms.ComboBox combobox_width; diff --git a/src/Greenshot/Forms/ResizeSettingsForm.cs b/src/Greenshot/Forms/ResizeSettingsForm.cs index f948b777f..e2d61c71d 100644 --- a/src/Greenshot/Forms/ResizeSettingsForm.cs +++ b/src/Greenshot/Forms/ResizeSettingsForm.cs @@ -22,8 +22,8 @@ using System; using System.Drawing; using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Effects; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; namespace Greenshot.Forms { diff --git a/src/Greenshot/Forms/SettingsForm.Designer.cs b/src/Greenshot/Forms/SettingsForm.Designer.cs index f0cb33f46..803eb37d6 100644 --- a/src/Greenshot/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot/Forms/SettingsForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Forms { partial class SettingsForm { /// @@ -47,103 +50,103 @@ namespace Greenshot.Forms { private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SettingsForm)); - this.textbox_storagelocation = new GreenshotPlugin.Controls.GreenshotTextBox(); - this.label_storagelocation = new GreenshotPlugin.Controls.GreenshotLabel(); - this.settings_cancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.settings_confirm = new GreenshotPlugin.Controls.GreenshotButton(); + this.textbox_storagelocation = new GreenshotTextBox(); + this.label_storagelocation = new GreenshotLabel(); + this.settings_cancel = new GreenshotButton(); + this.settings_confirm = new GreenshotButton(); this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); this.browse = new System.Windows.Forms.Button(); - this.label_screenshotname = new GreenshotPlugin.Controls.GreenshotLabel(); - this.textbox_screenshotname = new GreenshotPlugin.Controls.GreenshotTextBox(); - this.label_language = new GreenshotPlugin.Controls.GreenshotLabel(); + this.label_screenshotname = new GreenshotLabel(); + this.textbox_screenshotname = new GreenshotTextBox(); + this.label_language = new GreenshotLabel(); this.combobox_language = new System.Windows.Forms.ComboBox(); - this.combobox_primaryimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_primaryimageformat = new GreenshotPlugin.Controls.GreenshotLabel(); - this.groupbox_preferredfilesettings = new GreenshotPlugin.Controls.GreenshotGroupBox(); + this.combobox_primaryimageformat = new GreenshotComboBox(); + this.label_primaryimageformat = new GreenshotLabel(); + this.groupbox_preferredfilesettings = new GreenshotGroupBox(); this.btnPatternHelp = new System.Windows.Forms.Button(); - this.checkbox_copypathtoclipboard = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_zoomer = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.groupbox_applicationsettings = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.checkbox_autostartshortcut = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.groupbox_qualitysettings = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.checkbox_reducecolors = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_alwaysshowqualitydialog = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.label_jpegquality = new GreenshotPlugin.Controls.GreenshotLabel(); + this.checkbox_copypathtoclipboard = new GreenshotCheckBox(); + this.checkbox_zoomer = new GreenshotCheckBox(); + this.groupbox_applicationsettings = new GreenshotGroupBox(); + this.checkbox_autostartshortcut = new GreenshotCheckBox(); + this.groupbox_qualitysettings = new GreenshotGroupBox(); + this.checkbox_reducecolors = new GreenshotCheckBox(); + this.checkbox_alwaysshowqualitydialog = new GreenshotCheckBox(); + this.label_jpegquality = new GreenshotLabel(); this.textBoxJpegQuality = new System.Windows.Forms.TextBox(); this.trackBarJpegQuality = new System.Windows.Forms.TrackBar(); - this.groupbox_destination = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.checkbox_picker = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.groupbox_destination = new GreenshotGroupBox(); + this.checkbox_picker = new GreenshotCheckBox(); this.listview_destinations = new System.Windows.Forms.ListView(); this.destination = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.tabcontrol = new System.Windows.Forms.TabControl(); - this.tab_general = new GreenshotPlugin.Controls.GreenshotTabPage(); - this.groupbox_network = new GreenshotPlugin.Controls.GreenshotGroupBox(); + this.tab_general = new GreenshotTabPage(); + this.groupbox_network = new GreenshotGroupBox(); this.numericUpDown_daysbetweencheck = new System.Windows.Forms.NumericUpDown(); - this.label_checkperiod = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkbox_usedefaultproxy = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.groupbox_hotkeys = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.label_lastregion_hotkey = new GreenshotPlugin.Controls.GreenshotLabel(); - this.lastregion_hotkeyControl = new GreenshotPlugin.Controls.HotkeyControl(); - this.label_ie_hotkey = new GreenshotPlugin.Controls.GreenshotLabel(); - this.ie_hotkeyControl = new GreenshotPlugin.Controls.HotkeyControl(); - this.label_region_hotkey = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_window_hotkey = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_fullscreen_hotkey = new GreenshotPlugin.Controls.GreenshotLabel(); - this.region_hotkeyControl = new GreenshotPlugin.Controls.HotkeyControl(); - this.window_hotkeyControl = new GreenshotPlugin.Controls.HotkeyControl(); - this.fullscreen_hotkeyControl = new GreenshotPlugin.Controls.HotkeyControl(); - this.tab_capture = new GreenshotPlugin.Controls.GreenshotTabPage(); - this.groupbox_editor = new GreenshotPlugin.Controls.GreenshotGroupBox(); + this.label_checkperiod = new GreenshotLabel(); + this.checkbox_usedefaultproxy = new GreenshotCheckBox(); + this.groupbox_hotkeys = new GreenshotGroupBox(); + this.label_lastregion_hotkey = new GreenshotLabel(); + this.lastregion_hotkeyControl = new HotkeyControl(); + this.label_ie_hotkey = new GreenshotLabel(); + this.ie_hotkeyControl = new HotkeyControl(); + this.label_region_hotkey = new GreenshotLabel(); + this.label_window_hotkey = new GreenshotLabel(); + this.label_fullscreen_hotkey = new GreenshotLabel(); + this.region_hotkeyControl = new HotkeyControl(); + this.window_hotkeyControl = new HotkeyControl(); + this.fullscreen_hotkeyControl = new HotkeyControl(); + this.tab_capture = new GreenshotTabPage(); + this.groupbox_editor = new GreenshotGroupBox(); this.numericUpdownIconSize = new System.Windows.Forms.NumericUpDown(); - this.label_icon_size = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkbox_editor_match_capture_size = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.groupbox_iecapture = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.checkbox_ie_capture = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.groupbox_windowscapture = new GreenshotPlugin.Controls.GreenshotGroupBox(); + this.label_icon_size = new GreenshotLabel(); + this.checkbox_editor_match_capture_size = new GreenshotCheckBox(); + this.groupbox_iecapture = new GreenshotGroupBox(); + this.checkbox_ie_capture = new GreenshotCheckBox(); + this.groupbox_windowscapture = new GreenshotGroupBox(); this.colorButton_window_background = new Greenshot.Controls.ColorButton(); - this.radiobuttonWindowCapture = new GreenshotPlugin.Controls.GreenshotRadioButton(); - this.radiobuttonInteractiveCapture = new GreenshotPlugin.Controls.GreenshotRadioButton(); + this.radiobuttonWindowCapture = new GreenshotRadioButton(); + this.radiobuttonInteractiveCapture = new GreenshotRadioButton(); this.combobox_window_capture_mode = new System.Windows.Forms.ComboBox(); - this.groupbox_capture = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.checkbox_notifications = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_playsound = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_capture_mousepointer = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.groupbox_capture = new GreenshotGroupBox(); + this.checkbox_notifications = new GreenshotCheckBox(); + this.checkbox_playsound = new GreenshotCheckBox(); + this.checkbox_capture_mousepointer = new GreenshotCheckBox(); this.numericUpDownWaitTime = new System.Windows.Forms.NumericUpDown(); - this.label_waittime = new GreenshotPlugin.Controls.GreenshotLabel(); - this.tab_output = new GreenshotPlugin.Controls.GreenshotTabPage(); - this.tab_destinations = new GreenshotPlugin.Controls.GreenshotTabPage(); - this.tab_printer = new GreenshotPlugin.Controls.GreenshotTabPage(); - this.groupBoxColors = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.checkboxPrintInverted = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.radioBtnColorPrint = new GreenshotPlugin.Controls.GreenshotRadioButton(); - this.radioBtnGrayScale = new GreenshotPlugin.Controls.GreenshotRadioButton(); - this.radioBtnMonochrome = new GreenshotPlugin.Controls.GreenshotRadioButton(); - this.groupBoxPrintLayout = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.checkboxDateTime = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkboxAllowShrink = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkboxAllowEnlarge = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkboxAllowRotate = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkboxAllowCenter = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_alwaysshowprintoptionsdialog = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.tab_plugins = new GreenshotPlugin.Controls.GreenshotTabPage(); - this.groupbox_plugins = new GreenshotPlugin.Controls.GreenshotGroupBox(); + this.label_waittime = new GreenshotLabel(); + this.tab_output = new GreenshotTabPage(); + this.tab_destinations = new GreenshotTabPage(); + this.tab_printer = new GreenshotTabPage(); + this.groupBoxColors = new GreenshotGroupBox(); + this.checkboxPrintInverted = new GreenshotCheckBox(); + this.radioBtnColorPrint = new GreenshotRadioButton(); + this.radioBtnGrayScale = new GreenshotRadioButton(); + this.radioBtnMonochrome = new GreenshotRadioButton(); + this.groupBoxPrintLayout = new GreenshotGroupBox(); + this.checkboxDateTime = new GreenshotCheckBox(); + this.checkboxAllowShrink = new GreenshotCheckBox(); + this.checkboxAllowEnlarge = new GreenshotCheckBox(); + this.checkboxAllowRotate = new GreenshotCheckBox(); + this.checkboxAllowCenter = new GreenshotCheckBox(); + this.checkbox_alwaysshowprintoptionsdialog = new GreenshotCheckBox(); + this.tab_plugins = new GreenshotTabPage(); + this.groupbox_plugins = new GreenshotGroupBox(); this.listview_plugins = new System.Windows.Forms.ListView(); - this.button_pluginconfigure = new GreenshotPlugin.Controls.GreenshotButton(); - this.tab_expert = new GreenshotPlugin.Controls.GreenshotTabPage(); - this.groupbox_expert = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.checkbox_reuseeditor = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_minimizememoryfootprint = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_checkunstableupdates = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_suppresssavedialogatclose = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.label_counter = new GreenshotPlugin.Controls.GreenshotLabel(); - this.textbox_counter = new GreenshotPlugin.Controls.GreenshotTextBox(); - this.label_footerpattern = new GreenshotPlugin.Controls.GreenshotLabel(); - this.textbox_footerpattern = new GreenshotPlugin.Controls.GreenshotTextBox(); - this.checkbox_thumbnailpreview = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_optimizeforrdp = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_autoreducecolors = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.label_clipboardformats = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkbox_enableexpert = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.button_pluginconfigure = new GreenshotButton(); + this.tab_expert = new GreenshotTabPage(); + this.groupbox_expert = new GreenshotGroupBox(); + this.checkbox_reuseeditor = new GreenshotCheckBox(); + this.checkbox_minimizememoryfootprint = new GreenshotCheckBox(); + this.checkbox_checkunstableupdates = new GreenshotCheckBox(); + this.checkbox_suppresssavedialogatclose = new GreenshotCheckBox(); + this.label_counter = new GreenshotLabel(); + this.textbox_counter = new GreenshotTextBox(); + this.label_footerpattern = new GreenshotLabel(); + this.textbox_footerpattern = new GreenshotTextBox(); + this.checkbox_thumbnailpreview = new GreenshotCheckBox(); + this.checkbox_optimizeforrdp = new GreenshotCheckBox(); + this.checkbox_autoreducecolors = new GreenshotCheckBox(); + this.label_clipboardformats = new GreenshotLabel(); + this.checkbox_enableexpert = new GreenshotCheckBox(); this.listview_clipboardformats = new System.Windows.Forms.ListView(); this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.groupbox_preferredfilesettings.SuspendLayout(); @@ -1302,104 +1305,104 @@ namespace Greenshot.Forms { this.ResumeLayout(false); } - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_notifications; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_minimizememoryfootprint; + private GreenshotCheckBox checkbox_notifications; + private GreenshotCheckBox checkbox_minimizememoryfootprint; private System.Windows.Forms.ColumnHeader destination; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_picker; + private GreenshotCheckBox checkbox_picker; private System.Windows.Forms.ListView listview_destinations; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_editor; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_editor_match_capture_size; + private GreenshotGroupBox groupbox_editor; + private GreenshotCheckBox checkbox_editor_match_capture_size; private System.Windows.Forms.NumericUpDown numericUpDown_daysbetweencheck; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_network; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_usedefaultproxy; - private GreenshotPlugin.Controls.GreenshotLabel label_checkperiod; - private GreenshotPlugin.Controls.HotkeyControl fullscreen_hotkeyControl; - private GreenshotPlugin.Controls.HotkeyControl window_hotkeyControl; - private GreenshotPlugin.Controls.HotkeyControl region_hotkeyControl; - private GreenshotPlugin.Controls.GreenshotLabel label_fullscreen_hotkey; - private GreenshotPlugin.Controls.GreenshotLabel label_window_hotkey; - private GreenshotPlugin.Controls.GreenshotLabel label_region_hotkey; - private GreenshotPlugin.Controls.HotkeyControl ie_hotkeyControl; - private GreenshotPlugin.Controls.GreenshotLabel label_ie_hotkey; - private GreenshotPlugin.Controls.HotkeyControl lastregion_hotkeyControl; - private GreenshotPlugin.Controls.GreenshotLabel label_lastregion_hotkey; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_hotkeys; + private GreenshotGroupBox groupbox_network; + private GreenshotCheckBox checkbox_usedefaultproxy; + private GreenshotLabel label_checkperiod; + private HotkeyControl fullscreen_hotkeyControl; + private HotkeyControl window_hotkeyControl; + private HotkeyControl region_hotkeyControl; + private GreenshotLabel label_fullscreen_hotkey; + private GreenshotLabel label_window_hotkey; + private GreenshotLabel label_region_hotkey; + private HotkeyControl ie_hotkeyControl; + private GreenshotLabel label_ie_hotkey; + private HotkeyControl lastregion_hotkeyControl; + private GreenshotLabel label_lastregion_hotkey; + private GreenshotGroupBox groupbox_hotkeys; private Greenshot.Controls.ColorButton colorButton_window_background; - private GreenshotPlugin.Controls.GreenshotRadioButton radiobuttonWindowCapture; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_ie_capture; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_capture; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_windowscapture; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_iecapture; - private GreenshotPlugin.Controls.GreenshotTabPage tab_capture; + private GreenshotRadioButton radiobuttonWindowCapture; + private GreenshotCheckBox checkbox_ie_capture; + private GreenshotGroupBox groupbox_capture; + private GreenshotGroupBox groupbox_windowscapture; + private GreenshotGroupBox groupbox_iecapture; + private GreenshotTabPage tab_capture; private System.Windows.Forms.ComboBox combobox_window_capture_mode; private System.Windows.Forms.NumericUpDown numericUpDownWaitTime; - private GreenshotPlugin.Controls.GreenshotLabel label_waittime; - private GreenshotPlugin.Controls.GreenshotRadioButton radiobuttonInteractiveCapture; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_capture_mousepointer; - private GreenshotPlugin.Controls.GreenshotTabPage tab_printer; + private GreenshotLabel label_waittime; + private GreenshotRadioButton radiobuttonInteractiveCapture; + private GreenshotCheckBox checkbox_capture_mousepointer; + private GreenshotTabPage tab_printer; private System.Windows.Forms.ListView listview_plugins; - private GreenshotPlugin.Controls.GreenshotButton button_pluginconfigure; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_plugins; - private GreenshotPlugin.Controls.GreenshotTabPage tab_plugins; + private GreenshotButton button_pluginconfigure; + private GreenshotGroupBox groupbox_plugins; + private GreenshotTabPage tab_plugins; private System.Windows.Forms.Button btnPatternHelp; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_copypathtoclipboard; - private GreenshotPlugin.Controls.GreenshotTabPage tab_output; - private GreenshotPlugin.Controls.GreenshotTabPage tab_general; + private GreenshotCheckBox checkbox_copypathtoclipboard; + private GreenshotTabPage tab_output; + private GreenshotTabPage tab_general; private System.Windows.Forms.TabControl tabcontrol; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_autostartshortcut; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_destination; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_alwaysshowqualitydialog; + private GreenshotCheckBox checkbox_autostartshortcut; + private GreenshotGroupBox groupbox_destination; + private GreenshotCheckBox checkbox_alwaysshowqualitydialog; private System.Windows.Forms.TextBox textBoxJpegQuality; - private GreenshotPlugin.Controls.GreenshotLabel label_jpegquality; + private GreenshotLabel label_jpegquality; private System.Windows.Forms.TrackBar trackBarJpegQuality; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_qualitysettings; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_applicationsettings; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_preferredfilesettings; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_playsound; - private GreenshotPlugin.Controls.GreenshotLabel label_primaryimageformat; - private GreenshotPlugin.Controls.GreenshotComboBox combobox_primaryimageformat; + private GreenshotGroupBox groupbox_qualitysettings; + private GreenshotGroupBox groupbox_applicationsettings; + private GreenshotGroupBox groupbox_preferredfilesettings; + private GreenshotCheckBox checkbox_playsound; + private GreenshotLabel label_primaryimageformat; + private GreenshotComboBox combobox_primaryimageformat; private System.Windows.Forms.ComboBox combobox_language; - private GreenshotPlugin.Controls.GreenshotLabel label_language; - private GreenshotPlugin.Controls.GreenshotTextBox textbox_screenshotname; - private GreenshotPlugin.Controls.GreenshotLabel label_screenshotname; + private GreenshotLabel label_language; + private GreenshotTextBox textbox_screenshotname; + private GreenshotLabel label_screenshotname; private System.Windows.Forms.Button browse; private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1; - private GreenshotPlugin.Controls.GreenshotButton settings_cancel; - private GreenshotPlugin.Controls.GreenshotButton settings_confirm; - private GreenshotPlugin.Controls.GreenshotTextBox textbox_storagelocation; - private GreenshotPlugin.Controls.GreenshotLabel label_storagelocation; - private GreenshotPlugin.Controls.GreenshotTabPage tab_destinations; - private GreenshotPlugin.Controls.GreenshotTabPage tab_expert; - private GreenshotPlugin.Controls.GreenshotGroupBox groupbox_expert; - private GreenshotPlugin.Controls.GreenshotLabel label_clipboardformats; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_enableexpert; + private GreenshotButton settings_cancel; + private GreenshotButton settings_confirm; + private GreenshotTextBox textbox_storagelocation; + private GreenshotLabel label_storagelocation; + private GreenshotTabPage tab_destinations; + private GreenshotTabPage tab_expert; + private GreenshotGroupBox groupbox_expert; + private GreenshotLabel label_clipboardformats; + private GreenshotCheckBox checkbox_enableexpert; private System.Windows.Forms.ListView listview_clipboardformats; private System.Windows.Forms.ColumnHeader columnHeader1; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_autoreducecolors; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_optimizeforrdp; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_thumbnailpreview; - private GreenshotPlugin.Controls.GreenshotLabel label_footerpattern; - private GreenshotPlugin.Controls.GreenshotTextBox textbox_footerpattern; - private GreenshotPlugin.Controls.GreenshotLabel label_counter; - private GreenshotPlugin.Controls.GreenshotTextBox textbox_counter; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_reducecolors; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_suppresssavedialogatclose; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_checkunstableupdates; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_reuseeditor; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_alwaysshowprintoptionsdialog; - private GreenshotPlugin.Controls.GreenshotGroupBox groupBoxColors; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxPrintInverted; - private GreenshotPlugin.Controls.GreenshotRadioButton radioBtnColorPrint; - private GreenshotPlugin.Controls.GreenshotRadioButton radioBtnGrayScale; - private GreenshotPlugin.Controls.GreenshotRadioButton radioBtnMonochrome; - private GreenshotPlugin.Controls.GreenshotGroupBox groupBoxPrintLayout; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxDateTime; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAllowShrink; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAllowEnlarge; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAllowRotate; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAllowCenter; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_zoomer; - private GreenshotPlugin.Controls.GreenshotLabel label_icon_size; + private GreenshotCheckBox checkbox_autoreducecolors; + private GreenshotCheckBox checkbox_optimizeforrdp; + private GreenshotCheckBox checkbox_thumbnailpreview; + private GreenshotLabel label_footerpattern; + private GreenshotTextBox textbox_footerpattern; + private GreenshotLabel label_counter; + private GreenshotTextBox textbox_counter; + private GreenshotCheckBox checkbox_reducecolors; + private GreenshotCheckBox checkbox_suppresssavedialogatclose; + private GreenshotCheckBox checkbox_checkunstableupdates; + private GreenshotCheckBox checkbox_reuseeditor; + private GreenshotCheckBox checkbox_alwaysshowprintoptionsdialog; + private GreenshotGroupBox groupBoxColors; + private GreenshotCheckBox checkboxPrintInverted; + private GreenshotRadioButton radioBtnColorPrint; + private GreenshotRadioButton radioBtnGrayScale; + private GreenshotRadioButton radioBtnMonochrome; + private GreenshotGroupBox groupBoxPrintLayout; + private GreenshotCheckBox checkboxDateTime; + private GreenshotCheckBox checkboxAllowShrink; + private GreenshotCheckBox checkboxAllowEnlarge; + private GreenshotCheckBox checkboxAllowRotate; + private GreenshotCheckBox checkboxAllowCenter; + private GreenshotCheckBox checkbox_zoomer; + private GreenshotLabel label_icon_size; private System.Windows.Forms.NumericUpDown numericUpdownIconSize; } } diff --git a/src/Greenshot/Forms/SettingsForm.cs b/src/Greenshot/Forms/SettingsForm.cs index 1e08fd54f..6fc2aa094 100644 --- a/src/Greenshot/Forms/SettingsForm.cs +++ b/src/Greenshot/Forms/SettingsForm.cs @@ -28,15 +28,15 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Base.UnmanagedHelpers; using Greenshot.Configuration; using Greenshot.Destinations; using Greenshot.Helpers; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; -using GreenshotPlugin.UnmanagedHelpers; using log4net; namespace Greenshot.Forms @@ -49,7 +49,7 @@ namespace Greenshot.Forms private static readonly ILog Log = LogManager.GetLogger(typeof(SettingsForm)); private readonly ToolTip _toolTip = new ToolTip(); private bool _inHotkey; - private int _daysbetweencheckPreviousValue; + private int _daysBetweenCheckPreviousValue; public SettingsForm() { @@ -92,7 +92,7 @@ namespace Greenshot.Forms // Changes for BUG-2077 numericUpDown_daysbetweencheck.ValueChanged += NumericUpDownDaysbetweencheckOnValueChanged; - _daysbetweencheckPreviousValue = (int) numericUpDown_daysbetweencheck.Value; + _daysBetweenCheckPreviousValue = (int) numericUpDown_daysbetweencheck.Value; DisplayPluginTab(); UpdateUi(); ExpertSettingsEnableState(false); @@ -112,7 +112,7 @@ namespace Greenshot.Forms // Check if we can into the forbidden range if (currentValue > 0 && currentValue < 7) { - if (_daysbetweencheckPreviousValue <= currentValue) + if (_daysBetweenCheckPreviousValue <= currentValue) { numericUpDown_daysbetweencheck.Value = 7; } @@ -132,7 +132,7 @@ namespace Greenshot.Forms numericUpDown_daysbetweencheck.Value = 365; } - _daysbetweencheckPreviousValue = (int) numericUpDown_daysbetweencheck.Value; + _daysBetweenCheckPreviousValue = (int) numericUpDown_daysbetweencheck.Value; } private void EnterHotkeyControl(object sender, EventArgs e) diff --git a/src/Greenshot/Forms/ToolStripMenuSelectList.cs b/src/Greenshot/Forms/ToolStripMenuSelectList.cs index 4880ec696..e2e52e2e4 100644 --- a/src/Greenshot/Forms/ToolStripMenuSelectList.cs +++ b/src/Greenshot/Forms/ToolStripMenuSelectList.cs @@ -19,12 +19,12 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core; using System; using System.Collections; using System.Drawing; using System.Windows.Forms; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; namespace Greenshot.Forms { diff --git a/src/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs b/src/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs index f2692729f..7e198e04f 100644 --- a/src/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs +++ b/src/Greenshot/Forms/TornEdgeSettingsForm.Designer.cs @@ -20,6 +20,7 @@ */ using System.Windows.Forms; +using Greenshot.Base.Controls; namespace Greenshot.Forms { partial class TornEdgeSettingsForm { @@ -51,23 +52,23 @@ namespace Greenshot.Forms { this.label3 = new System.Windows.Forms.Label(); this.offsetY = new System.Windows.Forms.NumericUpDown(); this.shadowDarkness = new System.Windows.Forms.TrackBar(); - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.labelDarkness = new GreenshotPlugin.Controls.GreenshotLabel(); - this.labelOffset = new GreenshotPlugin.Controls.GreenshotLabel(); - this.labelThickness = new GreenshotPlugin.Controls.GreenshotLabel(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.labelDarkness = new GreenshotLabel(); + this.labelOffset = new GreenshotLabel(); + this.labelThickness = new GreenshotLabel(); this.toothsize = new System.Windows.Forms.NumericUpDown(); - this.label_toothsize = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_horizontaltoothrange = new GreenshotPlugin.Controls.GreenshotLabel(); + this.label_toothsize = new GreenshotLabel(); + this.label_horizontaltoothrange = new GreenshotLabel(); this.horizontaltoothrange = new System.Windows.Forms.NumericUpDown(); - this.labelVerticaltoothrange = new GreenshotPlugin.Controls.GreenshotLabel(); + this.labelVerticaltoothrange = new GreenshotLabel(); this.verticaltoothrange = new System.Windows.Forms.NumericUpDown(); - this.top = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.right = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.bottom = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.left = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.shadowCheckbox = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.all = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.top = new GreenshotCheckBox(); + this.right = new GreenshotCheckBox(); + this.bottom = new GreenshotCheckBox(); + this.left = new GreenshotCheckBox(); + this.shadowCheckbox = new GreenshotCheckBox(); + this.all = new GreenshotCheckBox(); ((System.ComponentModel.ISupportInitialize)(this.thickness)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.offsetX)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.offsetY)).BeginInit(); @@ -418,22 +419,22 @@ namespace Greenshot.Forms { private System.Windows.Forms.Label label3; private System.Windows.Forms.NumericUpDown offsetY; private System.Windows.Forms.TrackBar shadowDarkness; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotLabel labelDarkness; - private GreenshotPlugin.Controls.GreenshotLabel labelOffset; - private GreenshotPlugin.Controls.GreenshotLabel labelThickness; + private GreenshotButton buttonOK; + private GreenshotButton buttonCancel; + private GreenshotLabel labelDarkness; + private GreenshotLabel labelOffset; + private GreenshotLabel labelThickness; private System.Windows.Forms.NumericUpDown toothsize; - private GreenshotPlugin.Controls.GreenshotLabel label_toothsize; - private GreenshotPlugin.Controls.GreenshotLabel label_horizontaltoothrange; + private GreenshotLabel label_toothsize; + private GreenshotLabel label_horizontaltoothrange; private System.Windows.Forms.NumericUpDown horizontaltoothrange; - private GreenshotPlugin.Controls.GreenshotLabel labelVerticaltoothrange; + private GreenshotLabel labelVerticaltoothrange; private System.Windows.Forms.NumericUpDown verticaltoothrange; - private GreenshotPlugin.Controls.GreenshotCheckBox top; - private GreenshotPlugin.Controls.GreenshotCheckBox right; - private GreenshotPlugin.Controls.GreenshotCheckBox bottom; - private GreenshotPlugin.Controls.GreenshotCheckBox left; - private GreenshotPlugin.Controls.GreenshotCheckBox shadowCheckbox; - private GreenshotPlugin.Controls.GreenshotCheckBox all; + private GreenshotCheckBox top; + private GreenshotCheckBox right; + private GreenshotCheckBox bottom; + private GreenshotCheckBox left; + private GreenshotCheckBox shadowCheckbox; + private GreenshotCheckBox all; } } \ No newline at end of file diff --git a/src/Greenshot/Forms/TornEdgeSettingsForm.cs b/src/Greenshot/Forms/TornEdgeSettingsForm.cs index dac953bd4..49548ce10 100644 --- a/src/Greenshot/Forms/TornEdgeSettingsForm.cs +++ b/src/Greenshot/Forms/TornEdgeSettingsForm.cs @@ -22,7 +22,7 @@ using System; using System.Drawing; using System.Windows.Forms; -using GreenshotPlugin.Effects; +using Greenshot.Base.Effects; namespace Greenshot.Forms { diff --git a/src/Greenshot/Greenshot.csproj b/src/Greenshot/Greenshot.csproj index a93eff8fc..0ff0f916b 100644 --- a/src/Greenshot/Greenshot.csproj +++ b/src/Greenshot/Greenshot.csproj @@ -37,7 +37,7 @@ - + diff --git a/src/Greenshot/GreenshotMain.cs b/src/Greenshot/GreenshotMain.cs index 753133f8e..a11b33930 100644 --- a/src/Greenshot/GreenshotMain.cs +++ b/src/Greenshot/GreenshotMain.cs @@ -18,46 +18,53 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Globalization; using System.Net; using System.Reflection; using Greenshot.Forms; -namespace Greenshot { - /// - /// Description of Main. - /// - public class GreenshotMain { - static GreenshotMain() { - AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; - } +namespace Greenshot +{ + /// + /// Description of Main. + /// + public class GreenshotMain + { + static GreenshotMain() + { + AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; + } - private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { - Assembly ayResult = null; - string sShortAssemblyName = args.Name.Split(',')[0]; - Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (Assembly ayAssembly in ayAssemblies) - { + private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + { + Assembly ayResult = null; + string sShortAssemblyName = args.Name.Split(',')[0]; + Assembly[] ayAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach (Assembly ayAssembly in ayAssemblies) + { if (sShortAssemblyName != ayAssembly.FullName.Split(',')[0]) { continue; } - ayResult = ayAssembly; - break; - } - return ayResult; - } - [STAThread] - public static void Main(string[] args) - { - // Enable TLS 1.2 support - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + ayResult = ayAssembly; + break; + } - CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; - CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; - MainForm.Start(args); - } - } -} + return ayResult; + } + + [STAThread] + public static void Main(string[] args) + { + // Enable TLS 1.2 support + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; + CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; + MainForm.Start(args); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Help/HelpFileLoader.cs b/src/Greenshot/Help/HelpFileLoader.cs index 69396490a..625d84ccf 100644 --- a/src/Greenshot/Help/HelpFileLoader.cs +++ b/src/Greenshot/Help/HelpFileLoader.cs @@ -19,9 +19,9 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core; using System.Diagnostics; using System.Net; +using Greenshot.Base.Core; using log4net; namespace Greenshot.Help diff --git a/src/Greenshot/Helpers/CaptureHelper.cs b/src/Greenshot/Helpers/CaptureHelper.cs index 5b90092d1..b42f3cc1e 100644 --- a/src/Greenshot/Helpers/CaptureHelper.cs +++ b/src/Greenshot/Helpers/CaptureHelper.cs @@ -23,8 +23,6 @@ using Greenshot.Configuration; using Greenshot.Destinations; using Greenshot.Drawing; using Greenshot.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers; using log4net; using System; using System.Collections.Generic; @@ -35,9 +33,10 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.UnmanagedHelpers.Enums; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.UnmanagedHelpers; namespace Greenshot.Helpers { diff --git a/src/Greenshot/Helpers/CopyData.cs b/src/Greenshot/Helpers/CopyData.cs index e77ba045f..b927caa42 100644 --- a/src/Greenshot/Helpers/CopyData.cs +++ b/src/Greenshot/Helpers/CopyData.cs @@ -26,7 +26,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Runtime.Serialization.Formatters.Binary; using System.Windows.Forms; -using GreenshotPlugin.Core; +using Greenshot.Base.Core; namespace Greenshot.Helpers { diff --git a/src/Greenshot/Helpers/DestinationHelper.cs b/src/Greenshot/Helpers/DestinationHelper.cs index 0e2288e36..671231c06 100644 --- a/src/Greenshot/Helpers/DestinationHelper.cs +++ b/src/Greenshot/Helpers/DestinationHelper.cs @@ -22,9 +22,9 @@ using System; using System.Collections.Generic; using System.Linq; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; using log4net; namespace Greenshot.Helpers diff --git a/src/Greenshot/Helpers/IECaptureHelper.cs b/src/Greenshot/Helpers/IECaptureHelper.cs index 19b020567..bb0601db9 100644 --- a/src/Greenshot/Helpers/IECaptureHelper.cs +++ b/src/Greenshot/Helpers/IECaptureHelper.cs @@ -25,16 +25,16 @@ using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Runtime.InteropServices; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IEInterop; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interop; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; using Greenshot.Configuration; using Greenshot.Helpers.IEInterop; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.IEInterop; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interop; -using GreenshotPlugin.UnmanagedHelpers.Enums; using log4net; namespace Greenshot.Helpers diff --git a/src/Greenshot/Helpers/IEInterop/IEContainer.cs b/src/Greenshot/Helpers/IEInterop/IEContainer.cs index cfae1481e..6ea590289 100644 --- a/src/Greenshot/Helpers/IEInterop/IEContainer.cs +++ b/src/Greenshot/Helpers/IEInterop/IEContainer.cs @@ -24,10 +24,10 @@ using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.Runtime.InteropServices; -using GreenshotPlugin.Core; -using GreenshotPlugin.IEInterop; +using Greenshot.Base.Core; +using Greenshot.Base.IEInterop; using log4net; -using IServiceProvider = GreenshotPlugin.Interop.IServiceProvider; +using IServiceProvider = Greenshot.Base.Interop.IServiceProvider; namespace Greenshot.Helpers.IEInterop { diff --git a/src/Greenshot/Helpers/MailHelper.cs b/src/Greenshot/Helpers/MailHelper.cs index 1f626a2da..17221609b 100644 --- a/src/Greenshot/Helpers/MailHelper.cs +++ b/src/Greenshot/Helpers/MailHelper.cs @@ -19,7 +19,6 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core; using log4net; using System; using System.Collections; @@ -28,9 +27,10 @@ using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; namespace Greenshot.Helpers { diff --git a/src/Greenshot/Helpers/NotifyIconNotificationService.cs b/src/Greenshot/Helpers/NotifyIconNotificationService.cs index a00c3f660..fd9fb592f 100644 --- a/src/Greenshot/Helpers/NotifyIconNotificationService.cs +++ b/src/Greenshot/Helpers/NotifyIconNotificationService.cs @@ -21,9 +21,9 @@ using System; using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; using log4net; namespace Greenshot.Helpers diff --git a/src/Greenshot/Helpers/PluginHelper.cs b/src/Greenshot/Helpers/PluginHelper.cs index d8eb4f811..8c453cead 100644 --- a/src/Greenshot/Helpers/PluginHelper.cs +++ b/src/Greenshot/Helpers/PluginHelper.cs @@ -27,10 +27,10 @@ using System.IO; using System.Linq; using System.Reflection; using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using log4net; namespace Greenshot.Helpers @@ -186,9 +186,7 @@ namespace Greenshot.Helpers if (!Directory.Exists(path)) return pluginFiles; try { - pluginFiles = Directory.GetFiles(path, "*Plugin.dll", SearchOption.AllDirectories) - // Skip the GreenshotPlugin.dll itself - .Where(p => CultureInfo.CurrentCulture.CompareInfo.IndexOf(p, "GreenshotPlugin.dll", CompareOptions.IgnoreCase) < 0); + pluginFiles = Directory.GetFiles(path, "Greenshot.Plugin.*.dll", SearchOption.AllDirectories); } catch (Exception ex) { @@ -203,7 +201,7 @@ namespace Greenshot.Helpers /// public void LoadPlugins() { - List pluginFiles = new List(); + var pluginFiles = new List(); if (IniConfig.IsPortable) { @@ -220,11 +218,11 @@ namespace Greenshot.Helpers { try { - Assembly assembly = Assembly.LoadFrom(pluginFile); + var assembly = Assembly.LoadFrom(pluginFile); var assemblyName = assembly.GetName().Name; - var pluginEntryName = $"{assemblyName}.{assemblyName.Replace("Greenshot", string.Empty)}"; + var pluginEntryName = $"{assemblyName}.{assemblyName.Replace("Greenshot.Plugin.", string.Empty)}Plugin"; var pluginEntryType = assembly.GetType(pluginEntryName, false, true); var pluginAttribute = pluginEntryType.GetCustomAttribute(); @@ -235,7 +233,7 @@ namespace Greenshot.Helpers continue; } - IGreenshotPlugin plugin = (IGreenshotPlugin) Activator.CreateInstance(pluginEntryType); + var plugin = (IGreenshotPlugin) Activator.CreateInstance(pluginEntryType); if (plugin != null) { if (plugin.Initialize()) diff --git a/src/Greenshot/Helpers/PrintHelper.cs b/src/Greenshot/Helpers/PrintHelper.cs index 6ca6cb068..de0bd0eb5 100644 --- a/src/Greenshot/Helpers/PrintHelper.cs +++ b/src/Greenshot/Helpers/PrintHelper.cs @@ -23,13 +23,13 @@ using System; using System.Drawing; using System.Drawing.Printing; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Configuration; using Greenshot.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; using log4net; namespace Greenshot.Helpers diff --git a/src/Greenshot/Helpers/ProcessorHelper.cs b/src/Greenshot/Helpers/ProcessorHelper.cs index d43473103..1532b9d2d 100644 --- a/src/Greenshot/Helpers/ProcessorHelper.cs +++ b/src/Greenshot/Helpers/ProcessorHelper.cs @@ -20,8 +20,8 @@ */ using System; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; using log4net; namespace Greenshot.Helpers diff --git a/src/Greenshot/Helpers/SoundHelper.cs b/src/Greenshot/Helpers/SoundHelper.cs index 54a25df8c..bb9d86499 100644 --- a/src/Greenshot/Helpers/SoundHelper.cs +++ b/src/Greenshot/Helpers/SoundHelper.cs @@ -23,11 +23,11 @@ using System; using System.Reflection; using System.Resources; using System.Runtime.InteropServices; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.Core; using System.IO; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.UnmanagedHelpers.Enums; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; using log4net; namespace Greenshot.Helpers diff --git a/src/Greenshot/Helpers/UpdateService.cs b/src/Greenshot/Helpers/UpdateService.cs index d4cb57a20..1fb10deab 100644 --- a/src/Greenshot/Helpers/UpdateService.cs +++ b/src/Greenshot/Helpers/UpdateService.cs @@ -24,11 +24,11 @@ using System.Threading; using System.Threading.Tasks; using Dapplo.HttpExtensions; using Dapplo.HttpExtensions.JsonNet; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; using Greenshot.Configuration; using Greenshot.Helpers.Entities; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; using log4net; namespace Greenshot.Helpers diff --git a/src/Greenshot/Memento/AddElementMemento.cs b/src/Greenshot/Memento/AddElementMemento.cs index 13b6a5749..23f25fcb4 100644 --- a/src/Greenshot/Memento/AddElementMemento.cs +++ b/src/Greenshot/Memento/AddElementMemento.cs @@ -20,8 +20,8 @@ */ using System; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Memento { diff --git a/src/Greenshot/Memento/AddElementsMemento.cs b/src/Greenshot/Memento/AddElementsMemento.cs index 1701a4d29..f3ad7fee4 100644 --- a/src/Greenshot/Memento/AddElementsMemento.cs +++ b/src/Greenshot/Memento/AddElementsMemento.cs @@ -19,8 +19,8 @@ * along with this program. If not, see . */ +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Memento { diff --git a/src/Greenshot/Memento/ChangeFieldHolderMemento.cs b/src/Greenshot/Memento/ChangeFieldHolderMemento.cs index b8cd718e3..7018557b9 100644 --- a/src/Greenshot/Memento/ChangeFieldHolderMemento.cs +++ b/src/Greenshot/Memento/ChangeFieldHolderMemento.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Memento { diff --git a/src/Greenshot/Memento/DeleteElementMemento.cs b/src/Greenshot/Memento/DeleteElementMemento.cs index b42992007..b7172fd60 100644 --- a/src/Greenshot/Memento/DeleteElementMemento.cs +++ b/src/Greenshot/Memento/DeleteElementMemento.cs @@ -20,8 +20,8 @@ */ using System; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Memento { diff --git a/src/Greenshot/Memento/DeleteElementsMemento.cs b/src/Greenshot/Memento/DeleteElementsMemento.cs index 096df18d3..890831ed5 100644 --- a/src/Greenshot/Memento/DeleteElementsMemento.cs +++ b/src/Greenshot/Memento/DeleteElementsMemento.cs @@ -19,8 +19,8 @@ * along with this program. If not, see . */ +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Memento { diff --git a/src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs b/src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs index 6db480c39..61ba7bdf8 100644 --- a/src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs +++ b/src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs @@ -20,10 +20,10 @@ */ using Greenshot.Drawing; -using GreenshotPlugin.Core; using System.Collections.Generic; using System.Drawing; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Memento { diff --git a/src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs b/src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs index 23e463b1a..72b3de10f 100644 --- a/src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs +++ b/src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs @@ -22,7 +22,7 @@ using Greenshot.Drawing; using System.Drawing; using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Memento { diff --git a/src/Greenshot/Memento/TextChangeMemento.cs b/src/Greenshot/Memento/TextChangeMemento.cs index faabd493f..eb1a3baed 100644 --- a/src/Greenshot/Memento/TextChangeMemento.cs +++ b/src/Greenshot/Memento/TextChangeMemento.cs @@ -19,8 +19,8 @@ * along with this program. If not, see . */ +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing; -using GreenshotPlugin.Interfaces.Drawing; namespace Greenshot.Memento { diff --git a/src/Greenshot/Processors/TitleFixProcessor.cs b/src/Greenshot/Processors/TitleFixProcessor.cs index f4dcba9f9..c5a286eb4 100644 --- a/src/Greenshot/Processors/TitleFixProcessor.cs +++ b/src/Greenshot/Processors/TitleFixProcessor.cs @@ -21,9 +21,9 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; using log4net; namespace Greenshot.Processors diff --git a/src/Greenshot/log4net-debug.xml b/src/Greenshot/log4net-debug.xml index 554edbeb3..f41436235 100644 --- a/src/Greenshot/log4net-debug.xml +++ b/src/Greenshot/log4net-debug.xml @@ -6,7 +6,7 @@ - + diff --git a/src/Greenshot/log4net.xml b/src/Greenshot/log4net.xml index 364756dbf..cc232d052 100644 --- a/src/Greenshot/log4net.xml +++ b/src/Greenshot/log4net.xml @@ -6,7 +6,7 @@ - + diff --git a/src/GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs b/src/GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs deleted file mode 100644 index 2db074f62..000000000 --- a/src/GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace GreenshotPlugin.Interfaces.Plugin -{ - public delegate void HotKeyHandler(); -} \ No newline at end of file From 6dfe7fe849b803f9e8083ccc2cd7428aea084c67 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 28 Mar 2021 21:04:09 +0200 Subject: [PATCH 119/232] Project cleanup (#302) * Renamed the projects * Refactoring of the namespaces * Moving the Inno-Setup files away from the application project. * Code formatting (indents etc.) to get it consistent, simplify it for contributors. * Renamed the GreenshotPlugin to Greenshot.Base --- Greenshot/App.config | 18 - .../Configuration/EditorConfiguration.cs | 151 - Greenshot/Configuration/LanguageKeys.cs | 80 - .../BindableToolStripDropDownButton.cs | 70 - Greenshot/Controls/ColorButton.cs | 90 - ...ontextMenuToolStripProfessionalRenderer.cs | 45 - .../CustomToolStripProfessionalRenderer.cs | 67 - Greenshot/Controls/FontFamilyComboBox.cs | 120 - Greenshot/Controls/MenuStripEx.cs | 62 - Greenshot/Controls/Pipette.cs | 174 - Greenshot/Controls/ToolStripColorButton.cs | 88 - Greenshot/Controls/ToolStripEx.cs | 62 - Greenshot/Controls/ToolStripNumericUpDown.cs | 79 - .../Destinations/ClipboardDestination.cs | 78 - Greenshot/Destinations/EditorDestination.cs | 125 - Greenshot/Destinations/EmailDestination.cs | 88 - Greenshot/Destinations/FileDestination.cs | 143 - .../Destinations/FileWithDialogDestination.cs | 82 - Greenshot/Destinations/PickerDestination.cs | 65 - Greenshot/Destinations/PrinterDestination.cs | 123 - Greenshot/Drawing/Adorners/AbstractAdorner.cs | 170 - Greenshot/Drawing/Adorners/MoveAdorner.cs | 162 - Greenshot/Drawing/Adorners/ResizeAdorner.cs | 182 - Greenshot/Drawing/Adorners/TargetAdorner.cs | 119 - Greenshot/Drawing/ArrowContainer.cs | 141 - Greenshot/Drawing/CropContainer.cs | 98 - Greenshot/Drawing/CursorContainer.cs | 110 - Greenshot/Drawing/DrawableContainer.cs | 563 --- Greenshot/Drawing/DrawableContainerList.cs | 620 --- Greenshot/Drawing/EllipseContainer.cs | 148 - .../Drawing/Fields/AbstractFieldHolder.cs | 200 - .../Fields/AbstractFieldHolderWithChildren.cs | 146 - .../Binding/AbstractBindingConverter.cs | 46 - .../Fields/Binding/BidirectionalBinding.cs | 158 - .../Fields/Binding/DecimalFloatConverter.cs | 47 - .../Fields/Binding/DecimalIntConverter.cs | 47 - .../Fields/Binding/IBindingValidator.cs | 34 - Greenshot/Drawing/Fields/Field.cs | 130 - Greenshot/Drawing/Fields/FieldAggregator.cs | 218 -- Greenshot/Drawing/Fields/FieldType.cs | 123 - Greenshot/Drawing/FilterContainer.cs | 94 - Greenshot/Drawing/Filters/AbstractFilter.cs | 80 - Greenshot/Drawing/Filters/BlurFilter.cs | 66 - Greenshot/Drawing/Filters/BrightnessFilter.cs | 64 - Greenshot/Drawing/Filters/GrayscaleFilter.cs | 64 - Greenshot/Drawing/Filters/HighlightFilter.cs | 68 - Greenshot/Drawing/Filters/MagnifierFilter.cs | 61 - Greenshot/Drawing/FreehandContainer.cs | 285 -- Greenshot/Drawing/HighlightContainer.cs | 99 - Greenshot/Drawing/IconContainer.cs | 109 - Greenshot/Drawing/ImageContainer.cs | 234 -- Greenshot/Drawing/LineContainer.cs | 112 - Greenshot/Drawing/ObfuscateContainer.cs | 76 - Greenshot/Drawing/RectangleContainer.cs | 157 - Greenshot/Drawing/SpeechbubbleContainer.cs | 345 -- Greenshot/Drawing/StepLabelContainer.cs | 206 - Greenshot/Drawing/Surface.cs | 2264 ----------- Greenshot/Forms/AboutForm.cs | 333 -- Greenshot/Forms/BugReportForm.cs | 54 - Greenshot/Forms/CaptureForm.cs | 1034 ----- Greenshot/Forms/ColorDialog.cs | 232 -- Greenshot/Forms/ColorPickerToolStripButton.cs | 97 - Greenshot/Forms/DropShadowSettingsForm.cs | 53 - Greenshot/Forms/ImageEditorForm.cs | 1656 -------- Greenshot/Forms/LanguageDialog.cs | 92 - Greenshot/Forms/MainForm.cs | 1502 -------- Greenshot/Forms/MovableShowColorForm.cs | 100 - Greenshot/Forms/ResizeSettingsForm.cs | 162 - Greenshot/Forms/SettingsForm.cs | 698 ---- Greenshot/Forms/ToolStripMenuSelectList.cs | 156 - Greenshot/Forms/TornEdgeSettingsForm.cs | 102 - Greenshot/GreenshotMain.cs | 62 - Greenshot/Help/HelpFileLoader.cs | 86 - Greenshot/Helpers/CaptureHelper.cs | 1011 ----- Greenshot/Helpers/Colors.cs | 52 - Greenshot/Helpers/CopyData.cs | 527 --- Greenshot/Helpers/DestinationHelper.cs | 111 - Greenshot/Helpers/GeometryHelper.cs | 59 - Greenshot/Helpers/IECaptureHelper.cs | 643 ---- Greenshot/Helpers/IEInterop/IEContainer.cs | 502 --- Greenshot/Helpers/MailHelper.cs | 535 --- Greenshot/Helpers/PluginHelper.cs | 245 -- Greenshot/Helpers/PrintHelper.cs | 240 -- Greenshot/Helpers/ProcessorHelper.cs | 65 - Greenshot/Helpers/ResourceMutex.cs | 175 - Greenshot/Helpers/ScaleHelper.cs | 339 -- Greenshot/Helpers/SoundHelper.cs | 95 - Greenshot/Helpers/StartupHelper.cs | 257 -- Greenshot/Helpers/ToolStripItemEndisabler.cs | 90 - Greenshot/Memento/AddElementMemento.cs | 67 - Greenshot/Memento/AddElementsMemento.cs | 71 - Greenshot/Memento/ChangeFieldHolderMemento.cs | 76 - Greenshot/Memento/DeleteElementMemento.cs | 73 - Greenshot/Memento/DeleteElementsMemento.cs | 69 - .../DrawableContainerBoundsChangeMemento.cs | 108 - .../Memento/SurfaceBackgroundChangeMemento.cs | 74 - Greenshot/Memento/TextChangeMemento.cs | 64 - Greenshot/web/htdocs/Help/index.de-DE.html | 106 - Greenshot/web/htdocs/Help/index.en-US.html | 100 - Greenshot/web/htdocs/favicon.ico | Bin 2550 -> 0 bytes Greenshot/web/htdocs/index.html | 44 - GreenshotBoxPlugin/BoxConfiguration.cs | 80 - GreenshotBoxPlugin/BoxDestination.cs | 55 - GreenshotBoxPlugin/BoxEntities.cs | 59 - GreenshotBoxPlugin/BoxPlugin.cs | 127 - GreenshotBoxPlugin/BoxUtils.cs | 138 - GreenshotBoxPlugin/Forms/SettingsForm.cs | 36 - GreenshotConfluencePlugin/Confluence.cs | 308 -- .../ConfluenceConfiguration.cs | 84 - .../ConfluenceDestination.cs | 204 - GreenshotConfluencePlugin/ConfluencePlugin.cs | 136 - GreenshotConfluencePlugin/ConfluenceUtils.cs | 151 - GreenshotConfluencePlugin/EnumDisplayer.cs | 97 - .../Forms/ConfluencePagePicker.xaml.cs | 56 - .../Forms/ConfluenceSearch.xaml.cs | 93 - .../Forms/ConfluenceTreePicker.xaml.cs | 127 - .../Forms/ConfluenceUpload.xaml.cs | 116 - .../Support/LanguageXMLTranslationProvider.cs | 18 - .../Support/TranslationData.cs | 45 - .../Support/TranslationManager.cs | 40 - GreenshotDropboxPlugin/DropboxDestination.cs | 61 - GreenshotDropboxPlugin/DropboxPlugin.cs | 120 - .../ExternalCommandConfiguration.cs | 154 - .../ExternalCommandDestination.cs | 221 -- .../GreenshotExternalCommandPlugin.csproj | 17 - GreenshotExternalCommandPlugin/IconCache.cs | 47 - .../SettingsForm.cs | 126 - .../SettingsFormDetail.cs | 166 - GreenshotFlickrPlugin/FlickrConfiguration.cs | 81 - GreenshotFlickrPlugin/FlickrDestination.cs | 55 - GreenshotFlickrPlugin/FlickrPlugin.cs | 131 - GreenshotFlickrPlugin/FlickrUtils.cs | 169 - .../GooglePhotosConfiguration.cs | 93 - .../GooglePhotosDestination.cs | 54 - .../GooglePhotosPlugin.cs | 124 - .../GooglePhotosUtils.cs | 120 - GreenshotImgurPlugin/Forms/ImgurHistory.cs | 221 -- GreenshotImgurPlugin/Forms/SettingsForm.cs | 45 - GreenshotImgurPlugin/ImgurConfiguration.cs | 103 - GreenshotImgurPlugin/ImgurInfo.cs | 217 -- GreenshotImgurPlugin/ImgurPlugin.cs | 216 -- GreenshotImgurPlugin/ImgurUtils.cs | 347 -- GreenshotJiraPlugin/AsyncMemoryCache.cs | 191 - GreenshotJiraPlugin/Forms/JiraForm.cs | 236 -- GreenshotJiraPlugin/Forms/SettingsForm.cs | 37 - GreenshotJiraPlugin/JiraConfiguration.cs | 46 - GreenshotJiraPlugin/JiraConnector.cs | 284 -- GreenshotJiraPlugin/JiraDestination.cs | 160 - GreenshotJiraPlugin/JiraMonitor.cs | 218 -- GreenshotJiraPlugin/JiraPlugin.cs | 138 - GreenshotJiraPlugin/LanguageKeys.cs | 38 - GreenshotJiraPlugin/Log4NetLogger.cs | 120 - .../Destinations/ExcelDestination.cs | 97 - .../Destinations/OneNoteDestination.cs | 124 - .../Destinations/OutlookDestination.cs | 183 - .../Destinations/PowerpointDestination.cs | 123 - .../Destinations/WordDestination.cs | 131 - GreenshotOfficePlugin/GlobalSuppressions.cs | Bin 3260 -> 0 bytes GreenshotOfficePlugin/OfficeConfiguration.cs | 54 - GreenshotOfficePlugin/OfficePlugin.cs | 115 - .../Forms/SettingsForm.cs | 37 - .../GreenshotPhotobucketPlugin.csproj | 17 - GreenshotPhotobucketPlugin/LanguageKeys.cs | 29 - .../PhotobucketConfiguration.cs | 69 - .../PhotobucketDestination.cs | 101 - GreenshotPhotobucketPlugin/PhotobucketInfo.cs | 67 - .../PhotobucketPlugin.cs | 141 - .../PhotobucketUtils.cs | 225 -- GreenshotPlugin/Controls/AnimatingForm.cs | 128 - GreenshotPlugin/Controls/BackgroundForm.cs | 84 - .../Controls/ExtendedWebBrowser.cs | 58 - .../Controls/GreenshotColumnSorter.cs | 118 - GreenshotPlugin/Controls/GreenshotComboBox.cs | 104 - GreenshotPlugin/Controls/GreenshotForm.cs | 526 --- .../Controls/GreenshotRadioButton.cs | 45 - GreenshotPlugin/Controls/HotkeyControl.cs | 564 --- .../Controls/IGreenshotLanguageBindable.cs | 36 - GreenshotPlugin/Controls/OAuthLoginForm.cs | 107 - GreenshotPlugin/Controls/PleaseWaitForm.cs | 124 - GreenshotPlugin/Controls/QualityDialog.cs | 67 - .../Controls/SaveImageFileDialog.cs | 199 - GreenshotPlugin/Controls/ThumbnailForm.cs | 141 - GreenshotPlugin/Core/AbstractDestination.cs | 350 -- GreenshotPlugin/Core/AccessibleHelper.cs | 192 - GreenshotPlugin/Core/AnimationHelpers.cs | 547 --- GreenshotPlugin/Core/BinaryStructHelper.cs | 93 - GreenshotPlugin/Core/Cache.cs | 214 -- GreenshotPlugin/Core/CaptureHandler.cs | 44 - GreenshotPlugin/Core/ClipboardHelper.cs | 908 ----- GreenshotPlugin/Core/CoreConfiguration.cs | 530 --- GreenshotPlugin/Core/CredentialsHelper.cs | 469 --- GreenshotPlugin/Core/EffectConverter.cs | 170 - GreenshotPlugin/Core/ExplorerHelper.cs | 52 - GreenshotPlugin/Core/FastBitmap.cs | 1010 ----- GreenshotPlugin/Core/FilenameHelper.cs | 559 --- GreenshotPlugin/Core/IEHelper.cs | 189 - GreenshotPlugin/Core/IImage.cs | 68 - GreenshotPlugin/Core/ImageHelper.cs | 1679 -------- GreenshotPlugin/Core/ImageOutput.cs | 657 ---- GreenshotPlugin/Core/ImageWrapper.cs | 76 - GreenshotPlugin/Core/JSONHelper.cs | 359 -- GreenshotPlugin/Core/Language.cs | 644 ---- GreenshotPlugin/Core/LanguageFile.cs | 76 - GreenshotPlugin/Core/LogHelper.cs | 106 - GreenshotPlugin/Core/OAuth/OAuth2Helper.cs | 372 -- GreenshotPlugin/Core/ObjectExtensions.cs | 104 - GreenshotPlugin/Core/PluginUtils.cs | 183 - GreenshotPlugin/Core/QuantizerHelper.cs | 669 ---- GreenshotPlugin/Core/StringExtensions.cs | 141 - GreenshotPlugin/Core/SvgImage.cs | 117 - GreenshotPlugin/Core/WindowCapture.cs | 369 -- GreenshotPlugin/Core/WindowsEnumerator.cs | 96 - .../Core/WmInputLangChangeRequestFilter.cs | 65 - GreenshotPlugin/Effects/ReduceColorsEffect.cs | 60 - GreenshotPlugin/Effects/ResizeEffect.cs | 56 - GreenshotPlugin/Effects/RotateEffect.cs | 59 - GreenshotPlugin/Effects/TornEdgeEffect.cs | 79 - GreenshotPlugin/GlobalSuppressions.cs | Bin 112958 -> 0 bytes GreenshotPlugin/Hooking/WindowsEventHook.cs | 149 - .../Hooking/WindowsOpenCloseMonitor.cs | 171 - .../Hooking/WindowsTitleMonitor.cs | 164 - GreenshotPlugin/IEInterop/IHTMLDocument2.cs | 77 - GreenshotPlugin/IEInterop/IHTMLDocument3.cs | 47 - GreenshotPlugin/IEInterop/IHTMLElement.cs | 117 - GreenshotPlugin/IEInterop/IHTMLElement2.cs | 39 - .../IEInterop/IHTMLSelectionObject.cs | 40 - GreenshotPlugin/IEInterop/IHTMLTxtRange.cs | 138 - GreenshotPlugin/IEInterop/IWebBrowser2.cs | 154 - GreenshotPlugin/IniFile/IniAttributes.cs | 87 - GreenshotPlugin/IniFile/IniConfig.cs | 464 --- GreenshotPlugin/IniFile/IniSection.cs | 198 - GreenshotPlugin/IniFile/IniValue.cs | 472 --- .../Interfaces/Drawing/Adorners/IAdorner.cs | 102 - .../Interfaces/Drawing/Container.cs | 215 -- GreenshotPlugin/Interfaces/ICaptureDetails.cs | 103 - GreenshotPlugin/Interfaces/IDestination.cs | 143 - GreenshotPlugin/Interfaces/IProcessor.cs | 65 - .../Interfaces/Plugin/HotKeyHandler.cs | 4 - GreenshotPlugin/Interop/Base.cs | 9 - GreenshotPlugin/Interop/COMWrapper.cs | 498 --- GreenshotPlugin/Interop/ComProgIdAttribute.cs | 80 - GreenshotPlugin/UnmanagedHelpers/DWM.cs | 110 - GreenshotPlugin/UnmanagedHelpers/GDI32.cs | 398 -- GreenshotPlugin/UnmanagedHelpers/GDIplus.cs | 329 -- GreenshotPlugin/UnmanagedHelpers/Kernel32.cs | 108 - GreenshotPlugin/UnmanagedHelpers/Shell32.cs | 108 - GreenshotPlugin/UnmanagedHelpers/User32.cs | 277 -- .../Destinations/Win10OcrDestination.cs | 98 - .../Native/DataTransferManagerHelper.cs | 87 - .../additional_files/installer.txt | 0 .../additional_files/license.txt | 0 .../additional_files/readme.txt | 0 .../appinfo.ini.template | 0 .../innosetup/IssProc/IssProc.dll | Bin .../innosetup/IssProc/IssProcLanguage.ini | Bin .../innosetup/Languages/Afrikaans.isl | 0 .../innosetup/Languages/Albanian.isl | 0 .../innosetup/Languages/Arabic.isl | 0 .../innosetup/Languages/Asturian.isl | 0 .../innosetup/Languages/Basque.isl | 0 .../innosetup/Languages/Belarusian.isl | 0 .../innosetup/Languages/Bengali.islu | 0 .../innosetup/Languages/Bosnian.isl | 0 .../innosetup/Languages/Bulgarian.isl | 0 .../innosetup/Languages/ChineseSimplified.isl | 0 .../Languages/ChineseTraditional.isl | 0 .../innosetup/Languages/Croatian.isl | 0 .../innosetup/Languages/EnglishBritish.isl | 0 .../innosetup/Languages/Esperanto.isl | 0 .../innosetup/Languages/Estonian.isl | 0 .../innosetup/Languages/Farsi.isl | 0 .../innosetup/Languages/Galician.isl | 0 .../innosetup/Languages/Georgian.islu | 0 .../innosetup/Languages/Greek.isl | 0 .../innosetup/Languages/Hindi.islu | 0 .../innosetup/Languages/Hungarian.isl | 0 .../innosetup/Languages/Indonesian.isl | 0 .../innosetup/Languages/Kazakh.islu | 0 .../innosetup/Languages/Korean.isl | 0 .../innosetup/Languages/Kurdish.isl | 0 .../innosetup/Languages/Latvian.isl | 0 .../innosetup/Languages/Ligurian.isl | 0 .../innosetup/Languages/Lithuanian.isl | 0 .../innosetup/Languages/Luxemburgish.isl | 0 .../innosetup/Languages/Macedonian.isl | 0 .../innosetup/Languages/Malaysian.isl | 0 .../innosetup/Languages/Marathi.islu | 0 .../innosetup/Languages/Mongolian.isl | 0 .../innosetup/Languages/Montenegrian.isl | 0 .../innosetup/Languages/Nepali.islu | 0 .../innosetup/Languages/NorwegianNynorsk.isl | 0 .../innosetup/Languages/Occitan.isl | 0 .../innosetup/Languages/Romanian.isl | 0 .../innosetup/Languages/ScottishGaelic.isl | 0 .../innosetup/Languages/SerbianCyrillic.isl | 0 .../innosetup/Languages/SerbianLatin.isl | 0 .../innosetup/Languages/Sinhala.islu | 0 .../innosetup/Languages/Swedish.isl | 0 .../innosetup/Languages/Tatar.isl | 0 .../innosetup/Languages/Thai.isl | 0 .../innosetup/Languages/Uyghur.islu | 0 .../innosetup/Languages/Uzbek.isl | 0 .../innosetup/Languages/Valencian.isl | 0 .../innosetup/Languages/Vietnamese.isl | 0 .../innosetup/installer-large.bmp | Bin .../innosetup/installer-small.bmp | Bin .../innosetup/scripts/isxdl/chinese.ini | 0 .../innosetup/scripts/isxdl/czech.ini | 0 .../innosetup/scripts/isxdl/dutch.ini | 0 .../innosetup/scripts/isxdl/english.ini | 0 .../innosetup/scripts/isxdl/french.ini | 0 .../innosetup/scripts/isxdl/french2.ini | 0 .../innosetup/scripts/isxdl/french3.ini | 0 .../innosetup/scripts/isxdl/german.ini | 0 .../innosetup/scripts/isxdl/isxdl.dll | Bin .../innosetup/scripts/isxdl/isxdl.iss | 0 .../innosetup/scripts/isxdl/italian.ini | 0 .../innosetup/scripts/isxdl/japanese.ini | 0 .../innosetup/scripts/isxdl/korean.ini | 0 .../innosetup/scripts/isxdl/norwegian.ini | 0 .../innosetup/scripts/isxdl/polish.ini | 0 .../innosetup/scripts/isxdl/portugues.ini | 0 .../innosetup/scripts/isxdl/portuguese.ini | 0 .../innosetup/scripts/isxdl/russian.ini | 0 .../innosetup/scripts/isxdl/spanish.ini | 0 .../innosetup/scripts/isxdl/swedish.ini | 0 .../innosetup/scripts/lang/chinese.iss | 0 .../innosetup/scripts/lang/dutch.iss | 0 .../innosetup/scripts/lang/english.iss | 0 .../innosetup/scripts/lang/french.iss | 0 .../innosetup/scripts/lang/german.iss | 0 .../innosetup/scripts/lang/italian.iss | 0 .../innosetup/scripts/lang/japanese.iss | 0 .../innosetup/scripts/lang/polish.iss | 0 .../innosetup/scripts/lang/russian.iss | 0 .../innosetup/scripts/products.iss | 0 .../innosetup/scripts/products.pas | 0 .../scripts/products/directxruntime.iss | 0 .../innosetup/scripts/products/dotnetfx11.iss | 0 .../scripts/products/dotnetfx11lp.iss | 0 .../scripts/products/dotnetfx11sp1.iss | 0 .../innosetup/scripts/products/dotnetfx20.iss | 0 .../scripts/products/dotnetfx20lp.iss | 0 .../scripts/products/dotnetfx20sp1.iss | 0 .../scripts/products/dotnetfx20sp1lp.iss | 0 .../scripts/products/dotnetfx20sp2.iss | 0 .../scripts/products/dotnetfx20sp2lp.iss | 0 .../innosetup/scripts/products/dotnetfx35.iss | 0 .../scripts/products/dotnetfx35lp.iss | 0 .../scripts/products/dotnetfx35sp1.iss | 0 .../scripts/products/dotnetfx35sp1lp.iss | 0 .../scripts/products/dotnetfx40client.iss | 0 .../scripts/products/dotnetfx40full.iss | 0 .../innosetup/scripts/products/dotnetfx45.iss | 0 .../innosetup/scripts/products/dotnetfx46.iss | 0 .../innosetup/scripts/products/dotnetfx47.iss | 0 .../innosetup/scripts/products/dotnetfx48.iss | 0 .../scripts/products/dotnetfxversion.iss | 0 .../scripts/products/fileversion.iss | 0 .../innosetup/scripts/products/ie6.iss | 0 .../innosetup/scripts/products/iis.iss | 0 .../innosetup/scripts/products/jet4sp8.iss | 0 .../innosetup/scripts/products/kb835732.iss | 0 .../innosetup/scripts/products/mdac28.iss | 0 .../innosetup/scripts/products/msi20.iss | 0 .../innosetup/scripts/products/msi31.iss | 0 .../innosetup/scripts/products/msi45.iss | 0 .../innosetup/scripts/products/msiproduct.iss | 0 .../scripts/products/sql2005express.iss | 0 .../scripts/products/sql2008express.iss | 0 .../scripts/products/sqlcompact35sp2.iss | 0 .../scripts/products/stringversion.iss | 0 .../scripts/products/vcredist2005.iss | 0 .../scripts/products/vcredist2008.iss | 0 .../scripts/products/vcredist2010.iss | 0 .../scripts/products/vcredist2012.iss | 0 .../scripts/products/vcredist2013.iss | 0 .../scripts/products/vcredist2015.iss | 0 .../scripts/products/vcredist2017.iss | 0 .../innosetup/scripts/products/wic.iss | 0 .../innosetup/scripts/products/winversion.iss | 0 .../innosetup/setup.iss | 138 +- .../portable/App/AppInfo/appicon.ico | Bin .../portable/App/AppInfo/appicon_16.png | Bin .../portable/App/AppInfo/appicon_32.png | Bin .../App/DefaultData/Greenshots/dummy.txt | 0 .../App/DefaultData/Settings/dummy.txt | 0 .../portable/Data/Greenshot/dummy.txt | 0 .../portable/Data/Settings/dummy.txt | 0 .../PortableApps.comInstallerCustom.nsh | 0 .editorconfig => src/.editorconfig | 0 .../Directory.Build.props | 244 +- .../Directory.Build.targets | 0 src/Greenshot.Base/Controls/AnimatingForm.cs | 140 + .../Controls/BackgroundForm.Designer.cs | 192 +- src/Greenshot.Base/Controls/BackgroundForm.cs | 99 + .../Controls/ExtendedWebBrowser.cs | 68 + .../Controls/FormWithoutActivation.cs | 69 +- .../Controls/GreenshotButton.cs | 65 +- .../Controls/GreenshotCheckBox.cs | 77 +- .../Controls/GreenshotColumnSorter.cs | 127 + .../Controls/GreenshotComboBox.cs | 116 + src/Greenshot.Base/Controls/GreenshotForm.cs | 643 ++++ .../Controls/GreenshotGroupBox.cs | 65 +- .../Controls/GreenshotLabel.cs | 65 +- .../Controls/GreenshotRadioButton.cs | 84 +- .../Controls/GreenshotTabPage.cs | 65 +- .../Controls/GreenshotTextBox.cs | 68 +- .../Controls/GreenshotToolDropDownButton.cs | 32 + .../Controls/GreenshotToolStripButton.cs | 65 +- .../Controls/GreenshotToolStripLabel.cs | 65 +- .../Controls/GreenshotToolStripMenuItem.cs | 65 +- src/Greenshot.Base/Controls/HotkeyControl.cs | 686 ++++ .../Controls/IGreenshotConfigBindable.cs | 76 +- .../Controls/IGreenshotLanguageBindable.cs | 33 +- .../Controls/OAuthLoginForm.Designer.cs | 184 +- src/Greenshot.Base/Controls/OAuthLoginForm.cs | 121 + .../Controls/PleaseWaitForm.Designer.cs | 198 +- src/Greenshot.Base/Controls/PleaseWaitForm.cs | 143 + .../Controls/QualityDialog.Designer.cs | 294 +- src/Greenshot.Base/Controls/QualityDialog.cs | 71 + .../Controls/SaveImageFileDialog.cs | 235 ++ src/Greenshot.Base/Controls/ThumbnailForm.cs | 156 + .../Core/AbstractDestination.cs | 416 ++ .../Greenshot.Base}/Core/AbstractProcessor.cs | 131 +- src/Greenshot.Base/Core/AccessibleHelper.cs | 237 ++ src/Greenshot.Base/Core/AnimationHelpers.cs | 610 +++ src/Greenshot.Base/Core/BinaryStructHelper.cs | 108 + src/Greenshot.Base/Core/Cache.cs | 259 ++ .../Greenshot.Base}/Core/Capture.cs | 99 +- .../Greenshot.Base}/Core/CaptureDetails.cs | 80 +- .../Greenshot.Base/Core/CaptureHandler.cs | 98 +- src/Greenshot.Base/Core/ClipboardHelper.cs | 1076 ++++++ src/Greenshot.Base/Core/CoreConfiguration.cs | 737 ++++ src/Greenshot.Base/Core/CredentialsHelper.cs | 525 +++ .../Core/DisplayKeyAttribute.cs | 75 +- .../Greenshot.Base}/Core/DpiHelper.cs | 25 +- src/Greenshot.Base/Core/EffectConverter.cs | 233 ++ .../Greenshot.Base}/Core/Enums/HResult.cs | 4 +- .../Core/Enums/MonitorDpiType.cs | 3 +- .../Greenshot.Base}/Core/Enums/MonitorFrom.cs | 3 +- .../Greenshot.Base}/Core/EnvironmentInfo.cs | 346 +- src/Greenshot.Base/Core/EventDelay.cs | 47 + src/Greenshot.Base/Core/ExplorerHelper.cs | 55 + src/Greenshot.Base/Core/FastBitmap.cs | 1055 +++++ src/Greenshot.Base/Core/FilenameHelper.cs | 705 ++++ .../Greenshot.Base}/Core/Fraction.cs | 10 +- .../Core/GreenshotResources.cs | 92 +- .../Core/GreenshotResources.resx | 940 ++--- .../Greenshot.Base}/Core/HResultExtensions.cs | 6 +- src/Greenshot.Base/Core/IEHelper.cs | 203 + src/Greenshot.Base/Core/IImage.cs | 68 + src/Greenshot.Base/Core/ImageHelper.cs | 1807 +++++++++ src/Greenshot.Base/Core/ImageOutput.cs | 798 ++++ src/Greenshot.Base/Core/ImageWrapper.cs | 77 + .../Greenshot.Base}/Core/InterfaceUtils.cs | 131 +- src/Greenshot.Base/Core/JSONHelper.cs | 436 +++ src/Greenshot.Base/Core/Language.cs | 807 ++++ .../Core/LanguageChangedHandler.cs | 10 +- src/Greenshot.Base/Core/LanguageFile.cs | 80 + src/Greenshot.Base/Core/LogHelper.cs | 124 + .../Greenshot.Base}/Core/NetworkHelper.cs | 1452 +++---- .../Core/OAuth/LocalJsonReceiver.cs | 50 +- .../Core/OAuth/LocalServerCodeReceiver.cs | 73 +- .../Core/OAuth/OAuth2AuthorizeMode.cs | 11 +- src/Greenshot.Base/Core/OAuth/OAuth2Helper.cs | 441 +++ .../Core/OAuth/OAuth2Settings.cs | 95 +- .../Core/OAuth/OAuthSession.cs | 365 +- .../Core/OAuth/OAuthSignatureTypes.cs | 5 +- src/Greenshot.Base/Core/ObjectExtensions.cs | 118 + src/Greenshot.Base/Core/PluginUtils.cs | 228 ++ src/Greenshot.Base/Core/QuantizerHelper.cs | 771 ++++ .../Core/RegistryKeyExtensions.cs | 13 +- .../Core/SimpleServiceProvider.cs | 120 +- src/Greenshot.Base/Core/StringExtensions.cs | 163 + src/Greenshot.Base/Core/SvgImage.cs | 117 + src/Greenshot.Base/Core/WindowCapture.cs | 444 +++ .../Greenshot.Base}/Core/WindowDetails.cs | 3415 +++++++++-------- src/Greenshot.Base/Core/WindowsEnumerator.cs | 108 + .../Greenshot.Base}/Core/WindowsVersion.cs | 2 +- .../Core/WmInputLangChangeRequestFilter.cs | 66 + .../Greenshot.Base/Effects/AdjustEffect.cs | 96 +- .../Greenshot.Base}/Effects/BorderEffect.cs | 101 +- .../Effects/DropShadowEffect.cs | 120 +- .../Effects/GrayscaleEffect.cs | 80 +- src/Greenshot.Base/Effects/IEffect.cs | 46 + .../Greenshot.Base}/Effects/InvertEffect.cs | 80 +- .../Effects/MonochromeEffect.cs | 51 + .../Effects/ReduceColorsEffect.cs | 70 + .../Effects/ResizeCanvasEffect.cs | 122 +- .../Greenshot.Base/Effects/ResizeEffect.cs | 97 +- src/Greenshot.Base/Effects/RotateEffect.cs | 69 + src/Greenshot.Base/Effects/TornEdgeEffect.cs | 75 + .../Greenshot.Base}/FileDescriptorReader.cs | 16 +- src/Greenshot.Base/GlobalSuppressions.cs | Bin 0 -> 119362 bytes .../Greenshot.Base/Greenshot.Base.csproj | 44 +- .../Hooking/WindowsEventHook.cs | 151 + .../Hooking/WindowsOpenCloseMonitor.cs | 180 + .../Hooking/WindowsTitleMonitor.cs | 165 + .../IEInterop/IHTMLBodyElement.cs | 71 +- .../IEInterop/IHTMLCurrentStyle.cs | 148 +- .../IEInterop/IHTMLDocument.cs | 73 +- .../IEInterop/IHTMLDocument2.cs | 85 + .../IEInterop/IHTMLDocument3.cs | 50 + .../IEInterop/IHTMLDocument4.cs | 66 +- .../IEInterop/IHTMLDocument5.cs | 70 +- src/Greenshot.Base/IEInterop/IHTMLElement.cs | 113 + .../Greenshot.Base/IEInterop/IHTMLElement2.cs | 91 +- .../IEInterop/IHTMLElementCollection.cs | 66 +- .../IEInterop/IHTMLFrameBase.cs | 212 +- .../IEInterop/IHTMLFramesCollection2.cs | 75 +- src/Greenshot.Base/IEInterop/IHTMLRect.cs | 39 + .../Greenshot.Base/IEInterop/IHTMLScreen.cs | 69 +- src/Greenshot.Base/IEInterop/IHTMLScreen2.cs | 39 + .../IEInterop/IHTMLSelectionObject.cs | 93 +- .../Greenshot.Base}/IEInterop/IHTMLStyle.cs | 2291 ++++++----- src/Greenshot.Base/IEInterop/IHTMLTxtRange.cs | 141 + .../Greenshot.Base/IEInterop/IHTMLWindow2.cs | 101 +- .../Greenshot.Base/IEInterop/IHTMLWindow3.cs | 73 +- .../Greenshot.Base}/IEInterop/IHTMLWindow4.cs | 71 +- src/Greenshot.Base/IEInterop/IWebBrowser2.cs | 152 + src/Greenshot.Base/IniFile/IniAttributes.cs | 71 + src/Greenshot.Base/IniFile/IniConfig.cs | 574 +++ .../Greenshot.Base}/IniFile/IniReader.cs | 189 +- src/Greenshot.Base/IniFile/IniSection.cs | 235 ++ src/Greenshot.Base/IniFile/IniValue.cs | 621 +++ .../Greenshot.Base}/Interfaces/CaptureMode.cs | 3 +- .../Interfaces/Drawing/Adorners/IAdorner.cs | 102 + .../Interfaces/Drawing/Container.cs | 149 + .../Interfaces/Drawing/IField.cs | 150 +- .../Interfaces/Drawing/IFieldholder.cs | 78 +- .../Interfaces/Drawing/IMemento.cs | 90 +- .../Interfaces/DrawingModes.cs | 2 +- .../Interfaces/Forms/ImageEditor.cs | 95 +- .../Greenshot.Base}/Interfaces/ICapture.cs | 40 +- .../Interfaces/ICaptureDetails.cs | 81 + src/Greenshot.Base/Interfaces/IDestination.cs | 131 + .../Interfaces/INotificationService.cs | 2 +- src/Greenshot.Base/Interfaces/IProcessor.cs | 59 + .../Interfaces/IServiceLocator.cs | 28 +- .../Greenshot.Base}/Interfaces/ISurface.cs | 74 +- .../Interfaces/Ocr/IOcrProvider.cs | 6 +- .../Greenshot.Base}/Interfaces/Ocr/Line.cs | 4 +- .../Interfaces/Ocr/OcrInformation.cs | 11 +- .../Greenshot.Base}/Interfaces/Ocr/Word.cs | 2 +- .../Interfaces/Plugin/HotKeyHandler.cs | 4 + .../Interfaces/Plugin/IGreenshotHost.cs | 95 +- .../Interfaces/Plugin/IGreenshotPlugin.cs | 49 +- .../Interfaces/Plugin/PluginAttribute.cs | 99 +- .../Plugin/SurfaceOutputSettings.cs | 180 +- .../Interfaces/ScreenCaptureMode.cs | 2 +- .../Interfaces/SurfaceDrawingModeEventArgs.cs | 8 +- .../SurfaceDrawingModeEventHandler.cs | 2 +- .../Interfaces/SurfaceElementEventArgs.cs | 10 +- .../Interfaces/SurfaceElementEventHandler.cs | 2 +- .../Interfaces/SurfaceMessageEventArgs.cs | 24 +- .../Interfaces/SurfaceMessageEventHandler.cs | 2 +- .../Interfaces/SurfaceMessageTyp.cs | 2 +- .../SurfaceSizeChangeEventHandler.cs | 2 +- src/Greenshot.Base/Interop/Base.cs | 11 + src/Greenshot.Base/Interop/COMWrapper.cs | 621 +++ .../Interop/ComProgIdAttribute.cs | 88 + .../Greenshot.Base}/Interop/IAppVisibility.cs | 81 +- .../Greenshot.Base}/Interop/IDispatch.cs | 90 +- .../Interop/IOleCommandTarget.cs | 76 +- .../Greenshot.Base}/Interop/IOleWindow.cs | 68 +- .../Interop/IServiceProvider.cs | 69 +- .../Greenshot.Base}/Interop/IUnknown.cs | 74 +- src/Greenshot.Base/UnmanagedHelpers/DWM.cs | 123 + .../UnmanagedHelpers/EnumWindowsProc.cs | 64 +- .../UnmanagedHelpers/Enums/ClassLongIndex.cs | 62 +- .../Enums/DWMWINDOWATTRIBUTE.cs | 90 +- .../Enums/DWM_THUMBNAIL_PROPERTIES.cs | 194 +- .../Enums/DesktopAccessRight.cs | 87 +- .../UnmanagedHelpers/Enums/DeviceCaps.cs | 84 +- .../UnmanagedHelpers/Enums/EventObjects.cs | 68 +- .../Enums/ExtendedWindowStyleFlags.cs | 67 +- .../Enums/ProcessAccessFlags.cs | 65 +- .../UnmanagedHelpers/Enums/RegionResult.cs | 61 +- .../Enums/SendMessageTimeoutFlags.cs | 69 +- .../Enums/ShowWindowCommand.cs | 205 +- .../UnmanagedHelpers/Enums/SoundFlags.cs | 76 +- .../UnmanagedHelpers/Enums/ThreadAccess.cs | 59 +- .../UnmanagedHelpers/Enums/Win32Error.cs | 175 +- .../UnmanagedHelpers/Enums/WinEvent.cs | 70 +- .../Enums/WinEventHookFlags.cs | 34 +- .../UnmanagedHelpers/Enums/WindowLongIndex.cs | 62 +- .../Enums/WindowPlacementFlags.cs | 79 +- .../UnmanagedHelpers/Enums/WindowPos.cs | 69 +- .../Enums/WindowStyleFlags.cs | 70 +- .../UnmanagedHelpers/Enums/WindowsMessages.cs | 50 +- src/Greenshot.Base/UnmanagedHelpers/GDI32.cs | 425 ++ .../UnmanagedHelpers/GDIplus.cs | 387 ++ .../UnmanagedHelpers/Kernel32.cs | 131 + .../Greenshot.Base}/UnmanagedHelpers/PsAPI.cs | 105 +- .../SafeCurrentInputDesktopHandle.cs | 79 +- .../UnmanagedHelpers/SafeIconHandle.cs | 62 +- .../UnmanagedHelpers/SafeWindowDcHandle.cs | 124 +- .../UnmanagedHelpers/Shell32.cs | 123 + .../UnmanagedHelpers/Structs/CursorInfo.cs | 67 +- .../UnmanagedHelpers/Structs/IconInfo.cs | 69 +- .../UnmanagedHelpers/Structs/POINT.cs | 122 +- .../UnmanagedHelpers/Structs/RECT.cs | 343 +- .../UnmanagedHelpers/Structs/RECTF.cs | 252 +- .../UnmanagedHelpers/Structs/SCROLLINFO.cs | 73 +- .../UnmanagedHelpers/Structs/SIZE.cs | 97 +- .../UnmanagedHelpers/Structs/WindowInfo.cs | 98 +- .../Structs/WindowPlacement.cs | 155 +- src/Greenshot.Base/UnmanagedHelpers/User32.cs | 333 ++ .../Greenshot.Base}/UnmanagedHelpers/Win32.cs | 132 +- .../UnmanagedHelpers/WinEventDelegate.cs | 32 +- .../Greenshot.Base}/UnmanagedHelpers/WinMM.cs | 73 +- .../Greenshot.Base}/log4net-embedded.xml | 40 +- .../Greenshot.Plugin.Box}/Box.png | Bin src/Greenshot.Plugin.Box/BoxConfiguration.cs | 79 + src/Greenshot.Plugin.Box/BoxDestination.cs | 65 + src/Greenshot.Plugin.Box/BoxEntities.cs | 56 + src/Greenshot.Plugin.Box/BoxPlugin.cs | 140 + .../Greenshot.Plugin.Box}/BoxPlugin.resx | 0 src/Greenshot.Plugin.Box/BoxUtils.cs | 154 + .../Greenshot.Plugin.Box}/Forms/BoxForm.cs | 11 +- .../Forms/SettingsForm.Designer.cs | 29 +- .../Forms/SettingsForm.cs | 34 +- .../Greenshot.Plugin.Box.Credentials.template | 2 +- .../Greenshot.Plugin.Box.csproj | 8 +- .../Greenshot.Plugin.Box}/LanguageKeys.cs | 17 +- .../Languages/language_boxplugin-cs-CZ.xml | 0 .../Languages/language_boxplugin-de-DE.xml | 0 .../Languages/language_boxplugin-en-US.xml | 0 .../Languages/language_boxplugin-fr-FR.xml | 0 .../Languages/language_boxplugin-id-ID.xml | 0 .../Languages/language_boxplugin-it-IT.xml | 0 .../Languages/language_boxplugin-ja-JP.xml | 0 .../Languages/language_boxplugin-kab-DZ.xml | 0 .../Languages/language_boxplugin-ko-KR.xml | 0 .../Languages/language_boxplugin-lv-LV.xml | 0 .../Languages/language_boxplugin-pl-PL.xml | 0 .../Languages/language_boxplugin-pt-PT.xml | 0 .../Languages/language_boxplugin-ru-RU.xml | 0 .../Languages/language_boxplugin-sr-RS.xml | 0 .../Languages/language_boxplugin-sv-SE.xml | 0 .../Languages/language_boxplugin-uk-UA.xml | 0 .../Languages/language_boxplugin-zh-CN.xml | 0 .../Languages/language_boxplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 2 +- src/Greenshot.Plugin.Confluence/Confluence.cs | 358 ++ .../ConfluenceConfiguration.cs | 67 + .../ConfluenceDestination.cs | 252 ++ .../ConfluencePlugin.cs | 169 + .../ConfluenceUtils.cs | 197 + .../EnumDisplayer.cs | 114 + .../Forms/ConfluenceConfigurationForm.xaml | 10 +- .../Forms/ConfluenceConfigurationForm.xaml.cs | 34 +- .../Forms/ConfluencePagePicker.xaml | 2 +- .../Forms/ConfluencePagePicker.xaml.cs | 64 + .../Forms/ConfluenceSearch.xaml | 4 +- .../Forms/ConfluenceSearch.xaml.cs | 112 + .../Forms/ConfluenceTreePicker.xaml | 4 +- .../Forms/ConfluenceTreePicker.xaml.cs | 157 + .../Forms/ConfluenceUpload.xaml | 4 +- .../Forms/ConfluenceUpload.xaml.cs | 141 + .../Greenshot.Plugin.Confluence.csproj | 8 +- .../Images/Confluence.ico | Bin .../LanguageKeys.cs | 18 +- .../language_confluenceplugin-cs-CZ.xml | 0 .../language_confluenceplugin-de-DE.xml | 0 .../language_confluenceplugin-en-US.xml | 0 .../language_confluenceplugin-fr-FR.xml | 0 .../language_confluenceplugin-id-ID.xml | 0 .../language_confluenceplugin-it-IT.xml | 0 .../language_confluenceplugin-ja-JP.xml | 0 .../language_confluenceplugin-kab-DZ.xml | 0 .../language_confluenceplugin-ko-KR.xml | 0 .../language_confluenceplugin-lv-LV.xml | 0 .../language_confluenceplugin-nl-NL.xml | 0 .../language_confluenceplugin-pl-PL.xml | 0 .../language_confluenceplugin-pt-PT.xml | 0 .../language_confluenceplugin-ru-RU.xml | 0 .../language_confluenceplugin-sr-RS.xml | 0 .../language_confluenceplugin-sv-SE.xml | 0 .../language_confluenceplugin-uk-UA.xml | 0 .../language_confluenceplugin-zh-CN.xml | 0 .../language_confluenceplugin-zh-TW.xml | 0 .../Support/ITranslationProvider.cs | 8 +- .../Support/LanguageChangedEventManager.cs | 14 +- .../Support/LanguageXMLTranslationProvider.cs | 23 + .../Support/TranslateExtension.cs | 12 +- .../Support/TranslationData.cs | 50 + .../Support/TranslationManager.cs | 45 + .../Web References/confluence/Reference.cs | 0 .../Web References/confluence/Reference.map | 0 .../confluence/confluenceservice-v1.wsdl | 0 .../Greenshot.Plugin.Dropbox}/Dropbox.gif | Bin .../DropboxDestination.cs | 72 + src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs | 129 + .../DropboxPlugin.resx | 0 .../DropboxPluginConfiguration.cs | 64 +- .../Greenshot.Plugin.Dropbox}/DropboxUtils.cs | 75 +- .../Forms/DropboxForm.cs | 12 +- .../Forms/SettingsForm.Designer.cs | 29 +- .../Forms/SettingsForm.cs | 39 + ...enshot.Plugin.Dropbox.Credentials.template | 2 +- .../Greenshot.Plugin.Dropbox.csproj | 8 +- src/Greenshot.Plugin.Dropbox/LanguageKeys.cs | 31 + .../language_dropboxplugin-cs-CZ.xml | 0 .../language_dropboxplugin-de-DE.xml | 0 .../language_dropboxplugin-en-US.xml | 0 .../language_dropboxplugin-fr-FR.xml | 0 .../language_dropboxplugin-id-ID.xml | 0 .../language_dropboxplugin-it-IT.xml | 0 .../language_dropboxplugin-ja-JP.xml | 0 .../language_dropboxplugin-kab-DZ.xml | 0 .../language_dropboxplugin-ko-KR.xml | 0 .../language_dropboxplugin-lv-LV.xml | 0 .../language_dropboxplugin-pl-PL.xml | 0 .../language_dropboxplugin-pt-PT.xml | 0 .../language_dropboxplugin-ru-RU.xml | 0 .../language_dropboxplugin-sr-RS.xml | 0 .../language_dropboxplugin-sv-SE.xml | 0 .../language_dropboxplugin-uk-UA.xml | 0 .../language_dropboxplugin-zh-CN.xml | 0 .../language_dropboxplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 2 +- .../ExternalCommandConfiguration.cs | 172 + .../ExternalCommandDestination.cs | 272 ++ .../ExternalCommandForm.cs | 16 +- .../ExternalCommandPlugin.cs | 18 +- .../Greenshot.Plugin.ExternalCommand.csproj | 11 + .../IconCache.cs | 56 + .../language_externalcommandplugin-cs-CZ.xml | 0 .../language_externalcommandplugin-de-DE.xml | 0 .../language_externalcommandplugin-en-US.xml | 0 .../language_externalcommandplugin-fr-FR.xml | 0 .../language_externalcommandplugin-id-ID.xml | 0 .../language_externalcommandplugin-it-IT.xml | 0 .../language_externalcommandplugin-ja-JP.xml | 0 .../language_externalcommandplugin-kab-DZ.xml | 0 .../language_externalcommandplugin-ko-KR.xml | 0 .../language_externalcommandplugin-lv-LV.xml | 0 .../language_externalcommandplugin-pl-PL.xml | 0 .../language_externalcommandplugin-pt-PT.xml | 0 .../language_externalcommandplugin-ru-RU.xml | 0 .../language_externalcommandplugin-sk-SK.xml | 0 .../language_externalcommandplugin-sr-RS.xml | 0 .../language_externalcommandplugin-sv-SE.xml | 0 .../language_externalcommandplugin-uk-UA.xml | 0 .../language_externalcommandplugin-zh-CN.xml | 0 .../language_externalcommandplugin-zh-TW.xml | 0 .../SettingsForm.Designer.cs | 25 +- .../SettingsForm.cs | 152 + .../SettingsFormDetail.Designer.cs | 33 +- .../SettingsFormDetail.cs | 192 + .../FlickrConfiguration.cs | 90 + .../FlickrDestination.cs | 65 + src/Greenshot.Plugin.Flickr/FlickrPlugin.cs | 154 + .../FlickrPlugin.resx | 0 src/Greenshot.Plugin.Flickr/FlickrUtils.cs | 232 ++ .../Forms/FlickrForm.cs | 10 +- .../Forms/SettingsForm.Designer.cs | 53 +- .../Forms/SettingsForm.cs | 34 +- ...eenshot.Plugin.Flickr.Credentials.template | 2 +- .../Greenshot.Plugin.Flickr.csproj | 8 +- .../Greenshot.Plugin.Flickr}/LanguageKeys.cs | 19 +- .../Languages/language_flickrplugin-cs-CZ.xml | 0 .../Languages/language_flickrplugin-de-DE.xml | 0 .../Languages/language_flickrplugin-en-US.xml | 0 .../Languages/language_flickrplugin-fr-FR.xml | 0 .../Languages/language_flickrplugin-id-ID.xml | 0 .../Languages/language_flickrplugin-it-IT.xml | 0 .../Languages/language_flickrplugin-ja-JP.xml | 0 .../language_flickrplugin-kab-DZ.xml | 0 .../Languages/language_flickrplugin-ko-KR.xml | 0 .../Languages/language_flickrplugin-lv-LV.xml | 0 .../Languages/language_flickrplugin-pl-PL.xml | 0 .../Languages/language_flickrplugin-pt-PT.xml | 0 .../Languages/language_flickrplugin-ru-RU.xml | 0 .../Languages/language_flickrplugin-sr-RS.xml | 0 .../Languages/language_flickrplugin-sv-SE.xml | 0 .../Languages/language_flickrplugin-uk-UA.xml | 0 .../Languages/language_flickrplugin-zh-CN.xml | 0 .../Languages/language_flickrplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 2 +- .../Greenshot.Plugin.Flickr}/flickr.png | Bin .../Forms/GooglePhotosForm.cs | 12 +- .../Forms/SettingsForm.Designer.cs | 29 +- .../Forms/SettingsForm.cs | 36 +- .../GooglePhotos.png | Bin .../GooglePhotosConfiguration.cs | 81 + .../GooglePhotosDestination.cs | 64 + .../GooglePhotosPlugin.cs | 141 + .../GooglePhotosPlugin.resx | 0 .../GooglePhotosUtils.cs | 143 + ...t.Plugin.GooglePhotos.Credentials.template | 2 +- .../Greenshot.Plugin.GooglePhotos.csproj | 4 +- .../LanguageKeys.cs | 19 +- .../language_googlephotosplugin-cs-CZ.xml | 0 .../language_googlephotosplugin-de-DE.xml | 0 .../language_googlephotosplugin-en-US.xml | 0 .../language_googlephotosplugin-fr-FR.xml | 0 .../language_googlephotosplugin-id-ID.xml | 0 .../language_googlephotosplugin-it-IT.xml | 0 .../language_googlephotosplugin-ja-JP.xml | 0 .../language_googlephotosplugin-kab-DZ.xml | 0 .../language_googlephotosplugin-ko-KR.xml | 0 .../language_googlephotosplugin-lv-LV.xml | 0 .../language_googlephotosplugin-pl-PL.xml | 0 .../language_googlephotosplugin-pt-PT.xml | 0 .../language_googlephotosplugin-ru-RU.xml | 0 .../language_googlephotosplugin-sr-RS.xml | 0 .../language_googlephotosplugin-sv-SE.xml | 0 .../language_googlephotosplugin-uk-UA.xml | 0 .../language_googlephotosplugin-zh-CN.xml | 0 .../language_googlephotosplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 2 +- .../Greenshot.Plugin.GooglePhotos}/README | 0 .../Forms/ImgurForm.cs | 18 +- .../Forms/ImgurHistory.Designer.cs | 2 +- .../Forms/ImgurHistory.cs | 263 ++ .../Forms/SettingsForm.Designer.cs | 33 +- .../Forms/SettingsForm.cs | 48 + ...reenshot.Plugin.Imgur.Credentials.template | 2 +- .../Greenshot.Plugin.Imgur.csproj | 8 +- .../ImgurConfiguration.cs | 110 + .../ImgurDestination.cs | 60 +- src/Greenshot.Plugin.Imgur/ImgurInfo.cs | 196 + src/Greenshot.Plugin.Imgur/ImgurPlugin.cs | 247 ++ .../Greenshot.Plugin.Imgur}/ImgurPlugin.resx | 0 src/Greenshot.Plugin.Imgur/ImgurUtils.cs | 410 ++ .../Greenshot.Plugin.Imgur}/LanguageKeys.cs | 26 +- .../Languages/language_imgurplugin-cs-CZ.xml | 0 .../Languages/language_imgurplugin-de-DE.xml | 0 .../Languages/language_imgurplugin-en-US.xml | 0 .../Languages/language_imgurplugin-fr-FR.xml | 0 .../Languages/language_imgurplugin-id-ID.xml | 0 .../Languages/language_imgurplugin-it-IT.xml | 0 .../Languages/language_imgurplugin-ja-JP.xml | 0 .../Languages/language_imgurplugin-kab-DZ.xml | 0 .../Languages/language_imgurplugin-ko-KR.xml | 0 .../Languages/language_imgurplugin-lv-LV.xml | 0 .../Languages/language_imgurplugin-nl-NL.xml | 0 .../Languages/language_imgurplugin-pl-PL.xml | 0 .../Languages/language_imgurplugin-pt-PT.xml | 0 .../Languages/language_imgurplugin-ru-RU.xml | 0 .../Languages/language_imgurplugin-sk-SK.xml | 0 .../Languages/language_imgurplugin-sr-RS.xml | 0 .../Languages/language_imgurplugin-sv-SE.xml | 0 .../Languages/language_imgurplugin-uk-UA.xml | 0 .../Languages/language_imgurplugin-zh-CN.xml | 0 .../Languages/language_imgurplugin-zh-TW.xml | 0 .../Properties/AssemblyInfo.cs | 2 +- src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs | 191 + .../Forms/JiraForm.Designer.cs | 2 +- src/Greenshot.Plugin.Jira/Forms/JiraForm.cs | 271 ++ .../Forms/JiraFormBase.cs | 12 +- .../Forms/SettingsForm.Designer.cs | 29 +- .../Forms/SettingsForm.cs | 39 + .../Greenshot.Plugin.Jira.csproj | 8 +- .../IssueTypeBitmapCache.cs | 46 +- .../JiraConfiguration.cs | 48 + src/Greenshot.Plugin.Jira/JiraConnector.cs | 317 ++ src/Greenshot.Plugin.Jira/JiraDestination.cs | 181 + .../Greenshot.Plugin.Jira}/JiraDetails.cs | 56 +- .../Greenshot.Plugin.Jira}/JiraEventArgs.cs | 22 +- .../Greenshot.Plugin.Jira}/JiraEventTypes.cs | 12 +- src/Greenshot.Plugin.Jira/JiraMonitor.cs | 233 ++ src/Greenshot.Plugin.Jira/JiraPlugin.cs | 146 + .../Greenshot.Plugin.Jira}/JiraPlugin.resx | 0 src/Greenshot.Plugin.Jira/LanguageKeys.cs | 40 + .../Languages/language_jiraplugin-cs-CZ.xml | 0 .../Languages/language_jiraplugin-de-DE.xml | 0 .../Languages/language_jiraplugin-en-US.xml | 0 .../Languages/language_jiraplugin-fr-FR.xml | 0 .../Languages/language_jiraplugin-id-ID.xml | 0 .../Languages/language_jiraplugin-it-IT.xml | 0 .../Languages/language_jiraplugin-ja-JP.xml | 0 .../Languages/language_jiraplugin-kab-DZ.xml | 0 .../Languages/language_jiraplugin-ko-KR.xml | 0 .../Languages/language_jiraplugin-lv-LV.xml | 0 .../Languages/language_jiraplugin-nl-NL.xml | 0 .../Languages/language_jiraplugin-pl-PL.xml | 0 .../Languages/language_jiraplugin-pt-PT.xml | 0 .../Languages/language_jiraplugin-ru-RU.xml | 0 .../Languages/language_jiraplugin-sr-RS.xml | 0 .../Languages/language_jiraplugin-sv-SE.xml | 0 .../Languages/language_jiraplugin-uk-UA.xml | 0 .../Languages/language_jiraplugin-zh-CN.xml | 0 .../Languages/language_jiraplugin-zh-TW.xml | 0 src/Greenshot.Plugin.Jira/Log4NetLogger.cs | 121 + .../Com/DisposableCom.cs | 3 +- .../Com/DisposableComImplementation.cs | 4 +- .../Com/IDisposableCom.cs | 2 +- .../Greenshot.Plugin.Office}/Com/Ole32Api.cs | 9 +- .../Com/OleAut32Api.cs | 10 +- .../Destinations/ExcelDestination.cs | 116 + .../Destinations/OneNoteDestination.cs | 144 + .../Destinations/OutlookDestination.cs | 223 ++ .../Destinations/PowerpointDestination.cs | 155 + .../Destinations/WordDestination.cs | 163 + .../GlobalSuppressions.cs | Bin 0 -> 3396 bytes .../Greenshot.Plugin.Office.csproj | 8 +- .../Languages/language_officeplugin-fr-FR.ini | 0 .../OfficeConfiguration.cs | 62 + .../OfficeExport/Entities/OneNoteNotebook.cs | 2 +- .../OfficeExport/Entities/OneNotePage.cs | 3 +- .../OfficeExport/Entities/OneNoteSection.cs | 2 +- .../OfficeExport/ExcelExporter.cs | 19 +- .../OfficeExport/OneNoteExporter.cs | 34 +- .../OfficeExport/OutlookEmailExporter.cs | 102 +- .../OfficeExport/PowerpointExporter.cs | 33 +- .../OfficeExport/WordExporter.cs | 34 +- .../OfficeInterop/EmailFormat.cs | 19 +- .../OfficeInterop/OfficeVersions.cs | 30 +- src/Greenshot.Plugin.Office/OfficePlugin.cs | 148 + .../Properties/AssemblyInfo.cs | 2 +- .../Forms/PhotobucketForm.cs | 18 +- .../Forms/SettingsForm.Designer.cs | 25 +- .../Forms/SettingsForm.cs | 39 + ...ot.Plugin.Photobucket.Credentials.template | 2 +- .../Greenshot.Plugin.Photobucket.csproj | 11 + .../LanguageKeys.cs | 17 +- .../language_photobucketplugin-cs-CZ.xml | 0 .../language_photobucketplugin-de-DE.xml | 0 .../language_photobucketplugin-en-US.xml | 0 .../language_photobucketplugin-fr_FR.xml | 0 .../language_photobucketplugin-id-ID.xml | 0 .../language_photobucketplugin-it-IT.xml | 0 .../language_photobucketplugin-ja-JP.xml | 0 .../language_photobucketplugin-kab-DZ.xml | 0 .../language_photobucketplugin-ko-KR.xml | 0 .../language_photobucketplugin-lv-LV.xml | 0 .../language_photobucketplugin-nl-NL.xml | 0 .../language_photobucketplugin-pl-PL.xml | 0 .../language_photobucketplugin-pt-PT.xml | 0 .../language_photobucketplugin-ru-RU.xml | 0 .../language_photobucketplugin-sv-SE.xml | 0 .../language_photobucketplugin-uk-UA.xml | 0 .../language_photobucketplugin-zh-CN.xml | 0 .../language_photobucketplugin-zh-TW.xml | 0 .../PhotobucketConfiguration.cs | 80 + .../PhotobucketDestination.cs | 119 + .../PhotobucketInfo.cs | 79 + .../PhotobucketPlugin.cs | 158 + .../PhotobucketPlugin.resx | 0 .../PhotobucketUtils.cs | 293 ++ .../Properties/AssemblyInfo.cs | 3 +- .../Destinations/Win10OcrDestination.cs | 98 + .../Destinations/Win10ShareDestination.cs | 33 +- .../Greenshot.Plugin.Win10.csproj | 8 +- .../Internal/MemoryRandomAccessStream.cs | 76 +- .../Internal/ShareInfo.cs | 4 +- .../Native/DataTransferManagerHelper.cs | 84 + .../Native/IDataTransferManagerInterOp.cs | 49 +- .../Processors/Win10OcrProcessor.cs | 26 +- .../Properties/AssemblyInfo.cs | 2 +- .../ToastNotificationService.cs | 20 +- .../Win10Configuration.cs | 23 +- .../Win10OcrProvider.cs | 89 +- .../Greenshot.Plugin.Win10}/Win10Plugin.cs | 75 +- Greenshot.sln => src/Greenshot.sln | 340 +- .../Greenshot.sln.DotSettings | 0 src/Greenshot/App.config | 19 + .../Configuration/EditorConfiguration.cs | 181 + src/Greenshot/Configuration/LanguageKeys.cs | 82 + .../Controls/BindableToolStripButton.cs | 44 +- .../Controls/BindableToolStripComboBox.cs | 44 +- .../BindableToolStripDropDownButton.cs | 82 + src/Greenshot/Controls/ColorButton.cs | 99 + ...ontextMenuToolStripProfessionalRenderer.cs | 50 + .../CustomToolStripProfessionalRenderer.cs | 84 + src/Greenshot/Controls/FontFamilyComboBox.cs | 141 + src/Greenshot/Controls/MenuStripEx.cs | 65 + .../Greenshot}/Controls/NonJumpingPanel.cs | 2 +- src/Greenshot/Controls/Pipette.cs | 204 + .../Controls/ToolStripColorButton.cs | 97 + src/Greenshot/Controls/ToolStripEx.cs | 66 + .../Controls/ToolStripNumericUpDown.cs | 88 + .../Destinations/ClipboardDestination.cs | 81 + .../Destinations/EditorDestination.cs | 154 + .../Destinations/EmailDestination.cs | 99 + src/Greenshot/Destinations/FileDestination.cs | 168 + .../Destinations/FileWithDialogDestination.cs | 81 + .../Destinations/PickerDestination.cs | 73 + .../Destinations/PrinterDestination.cs | 146 + .../Drawing/Adorners/AbstractAdorner.cs | 156 + src/Greenshot/Drawing/Adorners/MoveAdorner.cs | 166 + .../Drawing/Adorners/ResizeAdorner.cs | 186 + .../Drawing/Adorners/TargetAdorner.cs | 125 + src/Greenshot/Drawing/ArrowContainer.cs | 163 + src/Greenshot/Drawing/CropContainer.cs | 108 + src/Greenshot/Drawing/CursorContainer.cs | 128 + src/Greenshot/Drawing/DrawableContainer.cs | 670 ++++ .../Drawing/DrawableContainerList.cs | 728 ++++ src/Greenshot/Drawing/EllipseContainer.cs | 163 + .../Drawing/Fields/AbstractFieldHolder.cs | 192 + .../Fields/AbstractFieldHolderWithChildren.cs | 149 + .../Binding/AbstractBindingConverter.cs | 54 + .../Fields/Binding/BidirectionalBinding.cs | 184 + .../DecimalDoublePercentageConverter.cs | 49 +- .../Fields/Binding/DecimalFloatConverter.cs | 52 + .../Fields/Binding/DecimalIntConverter.cs | 52 + .../Fields/Binding/IBindingConverter.cs | 24 +- .../Fields/Binding/IBindingValidator.cs | 34 + .../Fields/Binding/NotNullValidator.cs | 38 +- src/Greenshot/Drawing/Fields/Field.cs | 128 + .../Drawing/Fields/FieldAggregator.cs | 224 ++ src/Greenshot/Drawing/Fields/FieldType.cs | 106 + src/Greenshot/Drawing/FilterContainer.cs | 115 + .../Drawing/Filters/AbstractFilter.cs | 83 + src/Greenshot/Drawing/Filters/BlurFilter.cs | 83 + .../Drawing/Filters/BrightnessFilter.cs | 73 + .../Drawing/Filters/GrayscaleFilter.cs | 90 + .../Drawing/Filters/HighlightFilter.cs | 82 + .../Greenshot}/Drawing/Filters/IFilter.cs | 17 +- .../Drawing/Filters/MagnifierFilter.cs | 70 + .../Drawing/Filters/PixelizationFilter.cs | 95 +- src/Greenshot/Drawing/FreehandContainer.cs | 323 ++ src/Greenshot/Drawing/HighlightContainer.cs | 112 + src/Greenshot/Drawing/IconContainer.cs | 120 + src/Greenshot/Drawing/ImageContainer.cs | 267 ++ src/Greenshot/Drawing/LineContainer.cs | 123 + src/Greenshot/Drawing/ObfuscateContainer.cs | 89 + .../Greenshot}/Drawing/Positions.cs | 30 +- src/Greenshot/Drawing/RectangleContainer.cs | 167 + .../Drawing/SpeechbubbleContainer.cs | 399 ++ src/Greenshot/Drawing/StepLabelContainer.cs | 225 ++ src/Greenshot/Drawing/Surface.cs | 2367 ++++++++++++ .../Greenshot}/Drawing/TextContainer.cs | 59 +- .../Greenshot}/Forms/AboutForm.Designer.cs | 27 +- src/Greenshot/Forms/AboutForm.cs | 389 ++ .../Greenshot}/Forms/AnimatingBaseForm.cs | 18 +- .../Greenshot}/Forms/BaseForm.cs | 18 +- .../Forms/BugReportForm.Designer.cs | 11 +- src/Greenshot/Forms/BugReportForm.cs | 64 + .../Greenshot}/Forms/CaptureForm.Designer.cs | 0 src/Greenshot/Forms/CaptureForm.cs | 1187 ++++++ .../Greenshot}/Forms/ColorDialog.Designer.cs | 35 +- src/Greenshot/Forms/ColorDialog.cs | 280 ++ .../Greenshot}/Forms/ColorDialog.resx | 0 .../Forms/ColorPickerToolStripButton.cs | 101 + .../Forms/DropShadowSettingsForm.Designer.cs | 23 +- src/Greenshot/Forms/DropShadowSettingsForm.cs | 59 + .../Forms/ImageEditorForm.Designer.cs | 361 +- src/Greenshot/Forms/ImageEditorForm.cs | 1926 ++++++++++ .../Greenshot}/Forms/ImageEditorForm.resx | 0 .../Forms/LanguageDialog.Designer.cs | 0 src/Greenshot/Forms/LanguageDialog.cs | 104 + .../Greenshot}/Forms/MainForm.Designer.cs | 67 +- src/Greenshot/Forms/MainForm.cs | 1814 +++++++++ .../Greenshot}/Forms/MainForm.resx | 0 .../Forms/MovableShowColorForm.Designer.cs | 0 src/Greenshot/Forms/MovableShowColorForm.cs | 117 + .../Forms/PrintOptionsDialog.Designer.cs | 59 +- .../Greenshot}/Forms/PrintOptionsDialog.cs | 53 +- .../Forms/ResizeSettingsForm.Designer.cs | 23 +- src/Greenshot/Forms/ResizeSettingsForm.cs | 212 + .../Greenshot}/Forms/SettingsForm.Designer.cs | 331 +- src/Greenshot/Forms/SettingsForm.cs | 864 +++++ .../Greenshot}/Forms/SettingsForm.resx | 0 .../Forms/ToolStripMenuSelectList.cs | 174 + .../Forms/TornEdgeSettingsForm.Designer.cs | 57 +- src/Greenshot/Forms/TornEdgeSettingsForm.cs | 115 + {Greenshot => src/Greenshot}/Greenshot.csproj | 4 +- src/Greenshot/GreenshotMain.cs | 70 + src/Greenshot/Help/HelpFileLoader.cs | 101 + src/Greenshot/Helpers/CaptureHelper.cs | 1230 ++++++ src/Greenshot/Helpers/Colors.cs | 61 + src/Greenshot/Helpers/CopyData.cs | 598 +++ src/Greenshot/Helpers/DestinationHelper.cs | 132 + .../Greenshot}/Helpers/Entities/UpdateFeed.cs | 8 +- src/Greenshot/Helpers/GeometryHelper.cs | 64 + .../Greenshot}/Helpers/GuiRectangle.cs | 52 +- src/Greenshot/Helpers/IECaptureHelper.cs | 797 ++++ .../Helpers/IEInterop/IEContainer.cs | 576 +++ src/Greenshot/Helpers/MailHelper.cs | 577 +++ .../Helpers/NotifyIconNotificationService.cs | 14 +- src/Greenshot/Helpers/PluginHelper.cs | 261 ++ src/Greenshot/Helpers/PrintHelper.cs | 282 ++ src/Greenshot/Helpers/ProcessorHelper.cs | 83 + src/Greenshot/Helpers/ResourceMutex.cs | 177 + src/Greenshot/Helpers/ScaleHelper.cs | 371 ++ src/Greenshot/Helpers/SoundHelper.cs | 119 + src/Greenshot/Helpers/StartupHelper.cs | 317 ++ .../Helpers/ToolStripItemEndisabler.cs | 108 + .../Greenshot}/Helpers/UpdateService.cs | 12 +- .../Greenshot}/Languages/help-de-DE.html | 0 .../Greenshot}/Languages/help-en-US.html | 0 .../Greenshot}/Languages/help-es-ES.html | 0 .../Greenshot}/Languages/help-fr-FR.html | 0 .../Greenshot}/Languages/help-hu-HU.html | 0 .../Greenshot}/Languages/help-it-IT.html | 0 .../Greenshot}/Languages/help-ko-KR.html | 0 .../Greenshot}/Languages/help-nl-NL.html | 0 .../Greenshot}/Languages/help-nn-NO.html | 0 .../Greenshot}/Languages/help-pl-PL.html | 0 .../Greenshot}/Languages/help-pt-BR.html | 0 .../Greenshot}/Languages/help-pt-PT.html | 0 .../Greenshot}/Languages/help-ru-RU.html | 0 .../Greenshot}/Languages/help-sv-SE.html | 0 .../Greenshot}/Languages/help-tr-TR.html | 0 .../Greenshot}/Languages/help-zh-CN.html | 0 .../installer/language-installer-de-DE.xml | 0 .../installer/language-installer-en-US.xml | 0 .../installer/language-installer-es-ES.xml | 0 .../installer/language-installer-fi-FI.xml | 0 .../installer/language-installer-fr-FR.xml | 0 .../installer/language-installer-it-IT.xml | 0 .../installer/language-installer-lv-LV.xml | 0 .../installer/language-installer-nl-NL.xml | 0 .../installer/language-installer-nn-NO.xml | 0 .../installer/language-installer-sr-RS.xml | 0 .../installer/language-installer-sv-SE.xml | 0 .../installer/language-installer-uk-UA.xml | 0 .../installer/language-installer-zh-CN.xml | 0 .../Greenshot}/Languages/language-ar-SY.xml | 0 .../Greenshot}/Languages/language-ca-CA.xml | 0 .../Greenshot}/Languages/language-cs-CZ.xml | 0 .../Greenshot}/Languages/language-da-DK.xml | 0 .../Greenshot}/Languages/language-de-DE.xml | 0 .../Languages/language-de-x-franconia.xml | 0 .../Greenshot}/Languages/language-el-GR.xml | 0 .../Greenshot}/Languages/language-en-US.xml | 0 .../Greenshot}/Languages/language-es-ES.xml | 0 .../Greenshot}/Languages/language-et-EE.xml | 0 .../Greenshot}/Languages/language-fa-IR.xml | 0 .../Greenshot}/Languages/language-fi-FI.xml | 0 .../Greenshot}/Languages/language-fr-FR.xml | 0 .../Greenshot}/Languages/language-fr-QC.xml | 0 .../Greenshot}/Languages/language-he-IL.xml | 0 .../Greenshot}/Languages/language-hu-HU.xml | 0 .../Greenshot}/Languages/language-id-ID.xml | 0 .../Greenshot}/Languages/language-it-IT.xml | 0 .../Greenshot}/Languages/language-ja-JP.xml | 0 .../Greenshot}/Languages/language-kab-DZ.xml | 0 .../Greenshot}/Languages/language-ko-KR.xml | 0 .../Greenshot}/Languages/language-lt-LT.xml | 0 .../Greenshot}/Languages/language-lv-LV.xml | 0 .../Greenshot}/Languages/language-nl-NL.xml | 0 .../Greenshot}/Languages/language-nn-NO.xml | 0 .../Greenshot}/Languages/language-pl-PL.xml | 0 .../Greenshot}/Languages/language-pt-BR.xml | 0 .../Greenshot}/Languages/language-pt-PT.xml | 0 .../Greenshot}/Languages/language-ro-RO.xml | 0 .../Greenshot}/Languages/language-ru-RU.xml | 0 .../Greenshot}/Languages/language-sk-SK.xml | 0 .../Greenshot}/Languages/language-sl-SI.xml | 0 .../Greenshot}/Languages/language-sr-RS.xml | 0 .../Greenshot}/Languages/language-sv-SE.xml | 0 .../Greenshot}/Languages/language-tr-TR.xml | 0 .../Greenshot}/Languages/language-uk-UA.xml | 0 .../Greenshot}/Languages/language-vi-VN.xml | 0 .../Greenshot}/Languages/language-zh-CN.xml | 0 .../Greenshot}/Languages/language-zh-TW.xml | 0 .../website/language-website-de-DE.xml | 0 .../website/language-website-en-US.xml | 0 .../website/language-website-es-ES.xml | 0 .../website/language-website-fr-FR.xml | 0 .../website/language-website-it-IT.xml | 0 .../website/language-website-lv-LV.xml | 0 .../website/language-website-nn-NO.xml | 0 .../website/language-website-pt-BR.xml | 0 .../website/language-website-sv-SE.xml | 0 .../website/language-website-uk-UA.xml | 0 src/Greenshot/Memento/AddElementMemento.cs | 75 + src/Greenshot/Memento/AddElementsMemento.cs | 73 + .../Memento/ChangeFieldHolderMemento.cs | 77 + src/Greenshot/Memento/DeleteElementMemento.cs | 82 + .../Memento/DeleteElementsMemento.cs | 71 + .../DrawableContainerBoundsChangeMemento.cs | 112 + .../Memento/SurfaceBackgroundChangeMemento.cs | 84 + src/Greenshot/Memento/TextChangeMemento.cs | 72 + .../Processors/TitleFixProcessor.cs | 66 +- {Greenshot => src/Greenshot}/Sounds.resx | 0 .../Greenshot}/greenshot.manifest | 0 .../Greenshot}/icons/applicationIcon/16.ico | Bin .../Greenshot}/icons/applicationIcon/16.png | Bin .../Greenshot}/icons/applicationIcon/32.ico | Bin .../Greenshot}/icons/applicationIcon/32.png | Bin .../Greenshot}/icons/applicationIcon/48.ico | Bin .../Greenshot}/icons/applicationIcon/48.png | Bin .../Greenshot}/icons/applicationIcon/90.png | Bin .../Greenshot}/icons/applicationIcon/icon.ico | Bin .../Greenshot}/icons/arrow_redo.png | Bin .../Greenshot}/icons/arrow_rollback.png | Bin .../Greenshot}/icons/arrow_undo.png | Bin .../Greenshot}/icons/balloon.png | Bin {Greenshot => src/Greenshot}/icons/cancel.png | Bin {Greenshot => src/Greenshot}/icons/cross.png | Bin {Greenshot => src/Greenshot}/icons/cut.png | Bin {Greenshot => src/Greenshot}/icons/delete.png | Bin .../Greenshot}/icons/filter_blur.png | Bin .../Greenshot}/icons/filter_pixelate.png | Bin .../Greenshot}/icons/folder-open-image.png | Bin .../Greenshot}/icons/folder_explore.png | Bin .../Greenshot}/icons/font_color.png | Bin .../Greenshot}/icons/freehand.png | Bin .../Greenshot}/icons/fugue/arrow-resize.png | Bin .../icons/fugue/clipboard-paste-image.png | Bin .../Greenshot}/icons/fugue/clipboard.png | Bin .../Greenshot}/icons/fugue/color-swatch.png | Bin .../Greenshot}/icons/fugue/cross.png | Bin .../Greenshot}/icons/fugue/cursor.png | Bin .../Greenshot}/icons/fugue/disk-black.png | Bin .../icons/fugue/edit-alignment-center.png | Bin .../icons/fugue/edit-alignment-right.png | Bin .../Greenshot}/icons/fugue/edit-alignment.png | Bin .../Greenshot}/icons/fugue/edit-blur.png | Bin .../Greenshot}/icons/fugue/edit-bold.png | Bin .../Greenshot}/icons/fugue/edit-italic.png | Bin .../Greenshot}/icons/fugue/edit-pixelate.png | Bin .../Greenshot}/icons/fugue/edit-underline.png | Bin .../fugue/edit-vertical-alignment-middle.png | Bin .../fugue/edit-vertical-alignment-top.png | Bin .../icons/fugue/edit-vertical-alignment.png | Bin .../Greenshot}/icons/fugue/filter_base.pdn | Bin .../icons/fugue/filter_highlight_area.png | Bin .../fugue/filter_highlight_grayscale.png | Bin .../icons/fugue/filter_highlight_text.png | Bin .../Greenshot}/icons/fugue/gear.png | Bin .../icons/fugue/highlighter-color.png | Bin .../icons/fugue/highlighter-text.png | Bin .../Greenshot}/icons/fugue/image-blur.png | Bin .../Greenshot}/icons/fugue/image-pixelate.png | Bin .../Greenshot}/icons/fugue/images.png | Bin .../icons/fugue/layer-shape-arrow.png | Bin .../icons/fugue/layer-shape-ellipse.png | Bin .../icons/fugue/layer-shape-line.png | Bin .../icons/fugue/layer-shape-text.png | Bin .../Greenshot}/icons/fugue/layer-shape.png | Bin .../icons/fugue/magnifier-zoom-actual.png | Bin .../icons/fugue/magnifier-zoom-fit.png | Bin .../icons/fugue/magnifier-zoom-in.png | Bin .../icons/fugue/magnifier-zoom-out.png | Bin .../Greenshot}/icons/fugue/magnifier-zoom.png | Bin .../Greenshot}/icons/fugue/magnifier.png | Bin .../icons/fugue/mail-open-image.png | Bin .../Greenshot}/icons/fugue/minus-circle.png | Bin .../Greenshot}/icons/fugue/money-coin.png | Bin .../icons/fugue/paint-can-color-bg.png | Bin .../icons/fugue/paint-can-color.png | Bin .../icons/fugue/pencil-color-bg.png | Bin .../Greenshot}/icons/fugue/pencil-color.png | Bin .../Greenshot}/icons/fugue/printer.png | Bin .../Greenshot}/icons/fugue/question.png | Bin .../Greenshot}/icons/fugue/ruler-crop.png | Bin .../Greenshot}/icons/fugue/scissors.png | Bin .../Greenshot}/icons/fugue/slash.png | Bin .../Greenshot}/icons/fugue/tick.png | Bin {Greenshot => src/Greenshot}/icons/heart.png | Bin {Greenshot => src/Greenshot}/icons/help.png | Bin .../Greenshot}/icons/highlighter.png | Bin .../Greenshot}/icons/layer-rotate-left.png | Bin .../Greenshot}/icons/layer-rotate.png | Bin .../icons/notification-counter-01.png | Bin .../icons/notification-counter-02.png | Bin .../icons/notification-counter-03.png | Bin .../icons/notification-counter-04.png | Bin .../icons/notification-counter-05.png | Bin .../icons/notification-counter-06.png | Bin .../icons/notification-counter-07.png | Bin .../icons/notification-counter-08.png | Bin .../icons/notification-counter-09.png | Bin .../icons/notification-counter-10.png | Bin .../icons/notification-counter-11.png | Bin .../icons/notification-counter-12.png | Bin .../icons/notification-counter-13.png | Bin .../icons/notification-counter-14.png | Bin .../icons/notification-counter-15.png | Bin .../icons/notification-counter-16.png | Bin .../icons/notification-counter-17.png | Bin .../icons/notification-counter-18.png | Bin .../icons/notification-counter-19.png | Bin .../icons/notification-counter-20-plus.png | Bin .../icons/notification-counter-20.png | Bin .../Greenshot}/icons/page_copy.png | Bin .../Greenshot}/icons/palette.png | Bin .../Greenshot}/icons/picture_save.png | Bin .../Greenshot}/icons/picture_saveas.png | Bin .../Greenshot}/icons/picture_to_clipboard.png | Bin .../Greenshot}/icons/pipette.png | Bin .../Greenshot}/icons/printer.png | Bin .../icons/propertyitemcontainer.gif | Bin {Greenshot => src/Greenshot}/icons/redo.png | Bin {Greenshot => src/Greenshot}/icons/resize.png | Bin .../Greenshot}/icons/ruler-crop.png | Bin {Greenshot => src/Greenshot}/icons/shadow.png | Bin .../Greenshot}/icons/shape_arrow_add.png | Bin .../Greenshot}/icons/shape_arrowheads.png | Bin .../Greenshot}/icons/shape_copy.png | Bin .../Greenshot}/icons/shape_ellipse_add.png | Bin .../Greenshot}/icons/shape_ellipse_delete.png | Bin .../Greenshot}/icons/shape_line.png | Bin .../Greenshot}/icons/shape_paste.png | Bin .../Greenshot}/icons/shape_square_add.png | Bin .../icons/shape_square_bordercolor.png | Bin .../Greenshot}/icons/shape_square_delete.png | Bin .../icons/shape_square_fillcolor.png | Bin .../Greenshot}/icons/text_bold.png | Bin .../Greenshot}/icons/text_dropcaps.png | Bin .../Greenshot}/icons/text_italic.png | Bin .../Greenshot}/icons/text_underline.png | Bin .../Greenshot}/icons/textfield_delete.png | Bin {Greenshot => src/Greenshot}/icons/undo.png | Bin .../Greenshot}/icons/wand-hat.png | Bin {Greenshot => src/Greenshot}/icons/wrench.png | Bin .../Greenshot}/icons/wrench_orange.png | Bin {Greenshot => src/Greenshot}/icons/zoom.png | Bin .../Greenshot}/log4net-debug.xml | 2 +- .../Greenshot}/log4net-portable.xml | 0 {Greenshot => src/Greenshot}/log4net-zip.xml | 0 {Greenshot => src/Greenshot}/log4net.xml | 2 +- .../Greenshot}/sounds/camera.wav | Bin version.json => src/version.json | 40 +- 1312 files changed, 67150 insertions(+), 59761 deletions(-) delete mode 100644 Greenshot/App.config delete mode 100644 Greenshot/Configuration/EditorConfiguration.cs delete mode 100644 Greenshot/Configuration/LanguageKeys.cs delete mode 100644 Greenshot/Controls/BindableToolStripDropDownButton.cs delete mode 100644 Greenshot/Controls/ColorButton.cs delete mode 100644 Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs delete mode 100644 Greenshot/Controls/CustomToolStripProfessionalRenderer.cs delete mode 100644 Greenshot/Controls/FontFamilyComboBox.cs delete mode 100644 Greenshot/Controls/MenuStripEx.cs delete mode 100644 Greenshot/Controls/Pipette.cs delete mode 100644 Greenshot/Controls/ToolStripColorButton.cs delete mode 100644 Greenshot/Controls/ToolStripEx.cs delete mode 100644 Greenshot/Controls/ToolStripNumericUpDown.cs delete mode 100644 Greenshot/Destinations/ClipboardDestination.cs delete mode 100644 Greenshot/Destinations/EditorDestination.cs delete mode 100644 Greenshot/Destinations/EmailDestination.cs delete mode 100644 Greenshot/Destinations/FileDestination.cs delete mode 100644 Greenshot/Destinations/FileWithDialogDestination.cs delete mode 100644 Greenshot/Destinations/PickerDestination.cs delete mode 100644 Greenshot/Destinations/PrinterDestination.cs delete mode 100644 Greenshot/Drawing/Adorners/AbstractAdorner.cs delete mode 100644 Greenshot/Drawing/Adorners/MoveAdorner.cs delete mode 100644 Greenshot/Drawing/Adorners/ResizeAdorner.cs delete mode 100644 Greenshot/Drawing/Adorners/TargetAdorner.cs delete mode 100644 Greenshot/Drawing/ArrowContainer.cs delete mode 100644 Greenshot/Drawing/CropContainer.cs delete mode 100644 Greenshot/Drawing/CursorContainer.cs delete mode 100644 Greenshot/Drawing/DrawableContainer.cs delete mode 100644 Greenshot/Drawing/DrawableContainerList.cs delete mode 100644 Greenshot/Drawing/EllipseContainer.cs delete mode 100644 Greenshot/Drawing/Fields/AbstractFieldHolder.cs delete mode 100644 Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs delete mode 100644 Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs delete mode 100644 Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs delete mode 100644 Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs delete mode 100644 Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs delete mode 100644 Greenshot/Drawing/Fields/Binding/IBindingValidator.cs delete mode 100644 Greenshot/Drawing/Fields/Field.cs delete mode 100644 Greenshot/Drawing/Fields/FieldAggregator.cs delete mode 100644 Greenshot/Drawing/Fields/FieldType.cs delete mode 100644 Greenshot/Drawing/FilterContainer.cs delete mode 100644 Greenshot/Drawing/Filters/AbstractFilter.cs delete mode 100644 Greenshot/Drawing/Filters/BlurFilter.cs delete mode 100644 Greenshot/Drawing/Filters/BrightnessFilter.cs delete mode 100644 Greenshot/Drawing/Filters/GrayscaleFilter.cs delete mode 100644 Greenshot/Drawing/Filters/HighlightFilter.cs delete mode 100644 Greenshot/Drawing/Filters/MagnifierFilter.cs delete mode 100644 Greenshot/Drawing/FreehandContainer.cs delete mode 100644 Greenshot/Drawing/HighlightContainer.cs delete mode 100644 Greenshot/Drawing/IconContainer.cs delete mode 100644 Greenshot/Drawing/ImageContainer.cs delete mode 100644 Greenshot/Drawing/LineContainer.cs delete mode 100644 Greenshot/Drawing/ObfuscateContainer.cs delete mode 100644 Greenshot/Drawing/RectangleContainer.cs delete mode 100644 Greenshot/Drawing/SpeechbubbleContainer.cs delete mode 100644 Greenshot/Drawing/StepLabelContainer.cs delete mode 100644 Greenshot/Drawing/Surface.cs delete mode 100644 Greenshot/Forms/AboutForm.cs delete mode 100644 Greenshot/Forms/BugReportForm.cs delete mode 100644 Greenshot/Forms/CaptureForm.cs delete mode 100644 Greenshot/Forms/ColorDialog.cs delete mode 100644 Greenshot/Forms/ColorPickerToolStripButton.cs delete mode 100644 Greenshot/Forms/DropShadowSettingsForm.cs delete mode 100644 Greenshot/Forms/ImageEditorForm.cs delete mode 100644 Greenshot/Forms/LanguageDialog.cs delete mode 100644 Greenshot/Forms/MainForm.cs delete mode 100644 Greenshot/Forms/MovableShowColorForm.cs delete mode 100644 Greenshot/Forms/ResizeSettingsForm.cs delete mode 100644 Greenshot/Forms/SettingsForm.cs delete mode 100644 Greenshot/Forms/ToolStripMenuSelectList.cs delete mode 100644 Greenshot/Forms/TornEdgeSettingsForm.cs delete mode 100644 Greenshot/GreenshotMain.cs delete mode 100644 Greenshot/Help/HelpFileLoader.cs delete mode 100644 Greenshot/Helpers/CaptureHelper.cs delete mode 100644 Greenshot/Helpers/Colors.cs delete mode 100644 Greenshot/Helpers/CopyData.cs delete mode 100644 Greenshot/Helpers/DestinationHelper.cs delete mode 100644 Greenshot/Helpers/GeometryHelper.cs delete mode 100644 Greenshot/Helpers/IECaptureHelper.cs delete mode 100644 Greenshot/Helpers/IEInterop/IEContainer.cs delete mode 100644 Greenshot/Helpers/MailHelper.cs delete mode 100644 Greenshot/Helpers/PluginHelper.cs delete mode 100644 Greenshot/Helpers/PrintHelper.cs delete mode 100644 Greenshot/Helpers/ProcessorHelper.cs delete mode 100644 Greenshot/Helpers/ResourceMutex.cs delete mode 100644 Greenshot/Helpers/ScaleHelper.cs delete mode 100644 Greenshot/Helpers/SoundHelper.cs delete mode 100644 Greenshot/Helpers/StartupHelper.cs delete mode 100644 Greenshot/Helpers/ToolStripItemEndisabler.cs delete mode 100644 Greenshot/Memento/AddElementMemento.cs delete mode 100644 Greenshot/Memento/AddElementsMemento.cs delete mode 100644 Greenshot/Memento/ChangeFieldHolderMemento.cs delete mode 100644 Greenshot/Memento/DeleteElementMemento.cs delete mode 100644 Greenshot/Memento/DeleteElementsMemento.cs delete mode 100644 Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs delete mode 100644 Greenshot/Memento/SurfaceBackgroundChangeMemento.cs delete mode 100644 Greenshot/Memento/TextChangeMemento.cs delete mode 100644 Greenshot/web/htdocs/Help/index.de-DE.html delete mode 100644 Greenshot/web/htdocs/Help/index.en-US.html delete mode 100644 Greenshot/web/htdocs/favicon.ico delete mode 100644 Greenshot/web/htdocs/index.html delete mode 100644 GreenshotBoxPlugin/BoxConfiguration.cs delete mode 100644 GreenshotBoxPlugin/BoxDestination.cs delete mode 100644 GreenshotBoxPlugin/BoxEntities.cs delete mode 100644 GreenshotBoxPlugin/BoxPlugin.cs delete mode 100644 GreenshotBoxPlugin/BoxUtils.cs delete mode 100644 GreenshotBoxPlugin/Forms/SettingsForm.cs delete mode 100644 GreenshotConfluencePlugin/Confluence.cs delete mode 100644 GreenshotConfluencePlugin/ConfluenceConfiguration.cs delete mode 100644 GreenshotConfluencePlugin/ConfluenceDestination.cs delete mode 100644 GreenshotConfluencePlugin/ConfluencePlugin.cs delete mode 100644 GreenshotConfluencePlugin/ConfluenceUtils.cs delete mode 100644 GreenshotConfluencePlugin/EnumDisplayer.cs delete mode 100644 GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml.cs delete mode 100644 GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml.cs delete mode 100644 GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml.cs delete mode 100644 GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml.cs delete mode 100644 GreenshotConfluencePlugin/Support/LanguageXMLTranslationProvider.cs delete mode 100644 GreenshotConfluencePlugin/Support/TranslationData.cs delete mode 100644 GreenshotConfluencePlugin/Support/TranslationManager.cs delete mode 100644 GreenshotDropboxPlugin/DropboxDestination.cs delete mode 100644 GreenshotDropboxPlugin/DropboxPlugin.cs delete mode 100644 GreenshotExternalCommandPlugin/ExternalCommandConfiguration.cs delete mode 100644 GreenshotExternalCommandPlugin/ExternalCommandDestination.cs delete mode 100644 GreenshotExternalCommandPlugin/GreenshotExternalCommandPlugin.csproj delete mode 100644 GreenshotExternalCommandPlugin/IconCache.cs delete mode 100644 GreenshotExternalCommandPlugin/SettingsForm.cs delete mode 100644 GreenshotExternalCommandPlugin/SettingsFormDetail.cs delete mode 100644 GreenshotFlickrPlugin/FlickrConfiguration.cs delete mode 100644 GreenshotFlickrPlugin/FlickrDestination.cs delete mode 100644 GreenshotFlickrPlugin/FlickrPlugin.cs delete mode 100644 GreenshotFlickrPlugin/FlickrUtils.cs delete mode 100644 GreenshotGooglePhotosPlugin/GooglePhotosConfiguration.cs delete mode 100644 GreenshotGooglePhotosPlugin/GooglePhotosDestination.cs delete mode 100644 GreenshotGooglePhotosPlugin/GooglePhotosPlugin.cs delete mode 100644 GreenshotGooglePhotosPlugin/GooglePhotosUtils.cs delete mode 100644 GreenshotImgurPlugin/Forms/ImgurHistory.cs delete mode 100644 GreenshotImgurPlugin/Forms/SettingsForm.cs delete mode 100644 GreenshotImgurPlugin/ImgurConfiguration.cs delete mode 100644 GreenshotImgurPlugin/ImgurInfo.cs delete mode 100644 GreenshotImgurPlugin/ImgurPlugin.cs delete mode 100644 GreenshotImgurPlugin/ImgurUtils.cs delete mode 100644 GreenshotJiraPlugin/AsyncMemoryCache.cs delete mode 100644 GreenshotJiraPlugin/Forms/JiraForm.cs delete mode 100644 GreenshotJiraPlugin/Forms/SettingsForm.cs delete mode 100644 GreenshotJiraPlugin/JiraConfiguration.cs delete mode 100644 GreenshotJiraPlugin/JiraConnector.cs delete mode 100644 GreenshotJiraPlugin/JiraDestination.cs delete mode 100644 GreenshotJiraPlugin/JiraMonitor.cs delete mode 100644 GreenshotJiraPlugin/JiraPlugin.cs delete mode 100644 GreenshotJiraPlugin/LanguageKeys.cs delete mode 100644 GreenshotJiraPlugin/Log4NetLogger.cs delete mode 100644 GreenshotOfficePlugin/Destinations/ExcelDestination.cs delete mode 100644 GreenshotOfficePlugin/Destinations/OneNoteDestination.cs delete mode 100644 GreenshotOfficePlugin/Destinations/OutlookDestination.cs delete mode 100644 GreenshotOfficePlugin/Destinations/PowerpointDestination.cs delete mode 100644 GreenshotOfficePlugin/Destinations/WordDestination.cs delete mode 100644 GreenshotOfficePlugin/GlobalSuppressions.cs delete mode 100644 GreenshotOfficePlugin/OfficeConfiguration.cs delete mode 100644 GreenshotOfficePlugin/OfficePlugin.cs delete mode 100644 GreenshotPhotobucketPlugin/Forms/SettingsForm.cs delete mode 100644 GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.csproj delete mode 100644 GreenshotPhotobucketPlugin/LanguageKeys.cs delete mode 100644 GreenshotPhotobucketPlugin/PhotobucketConfiguration.cs delete mode 100644 GreenshotPhotobucketPlugin/PhotobucketDestination.cs delete mode 100644 GreenshotPhotobucketPlugin/PhotobucketInfo.cs delete mode 100644 GreenshotPhotobucketPlugin/PhotobucketPlugin.cs delete mode 100644 GreenshotPhotobucketPlugin/PhotobucketUtils.cs delete mode 100644 GreenshotPlugin/Controls/AnimatingForm.cs delete mode 100644 GreenshotPlugin/Controls/BackgroundForm.cs delete mode 100644 GreenshotPlugin/Controls/ExtendedWebBrowser.cs delete mode 100644 GreenshotPlugin/Controls/GreenshotColumnSorter.cs delete mode 100644 GreenshotPlugin/Controls/GreenshotComboBox.cs delete mode 100644 GreenshotPlugin/Controls/GreenshotForm.cs delete mode 100644 GreenshotPlugin/Controls/GreenshotRadioButton.cs delete mode 100644 GreenshotPlugin/Controls/HotkeyControl.cs delete mode 100644 GreenshotPlugin/Controls/IGreenshotLanguageBindable.cs delete mode 100644 GreenshotPlugin/Controls/OAuthLoginForm.cs delete mode 100644 GreenshotPlugin/Controls/PleaseWaitForm.cs delete mode 100644 GreenshotPlugin/Controls/QualityDialog.cs delete mode 100644 GreenshotPlugin/Controls/SaveImageFileDialog.cs delete mode 100644 GreenshotPlugin/Controls/ThumbnailForm.cs delete mode 100644 GreenshotPlugin/Core/AbstractDestination.cs delete mode 100644 GreenshotPlugin/Core/AccessibleHelper.cs delete mode 100644 GreenshotPlugin/Core/AnimationHelpers.cs delete mode 100644 GreenshotPlugin/Core/BinaryStructHelper.cs delete mode 100644 GreenshotPlugin/Core/Cache.cs delete mode 100644 GreenshotPlugin/Core/CaptureHandler.cs delete mode 100644 GreenshotPlugin/Core/ClipboardHelper.cs delete mode 100644 GreenshotPlugin/Core/CoreConfiguration.cs delete mode 100644 GreenshotPlugin/Core/CredentialsHelper.cs delete mode 100644 GreenshotPlugin/Core/EffectConverter.cs delete mode 100644 GreenshotPlugin/Core/ExplorerHelper.cs delete mode 100644 GreenshotPlugin/Core/FastBitmap.cs delete mode 100644 GreenshotPlugin/Core/FilenameHelper.cs delete mode 100644 GreenshotPlugin/Core/IEHelper.cs delete mode 100644 GreenshotPlugin/Core/IImage.cs delete mode 100644 GreenshotPlugin/Core/ImageHelper.cs delete mode 100644 GreenshotPlugin/Core/ImageOutput.cs delete mode 100644 GreenshotPlugin/Core/ImageWrapper.cs delete mode 100644 GreenshotPlugin/Core/JSONHelper.cs delete mode 100644 GreenshotPlugin/Core/Language.cs delete mode 100644 GreenshotPlugin/Core/LanguageFile.cs delete mode 100644 GreenshotPlugin/Core/LogHelper.cs delete mode 100644 GreenshotPlugin/Core/OAuth/OAuth2Helper.cs delete mode 100644 GreenshotPlugin/Core/ObjectExtensions.cs delete mode 100644 GreenshotPlugin/Core/PluginUtils.cs delete mode 100644 GreenshotPlugin/Core/QuantizerHelper.cs delete mode 100644 GreenshotPlugin/Core/StringExtensions.cs delete mode 100644 GreenshotPlugin/Core/SvgImage.cs delete mode 100644 GreenshotPlugin/Core/WindowCapture.cs delete mode 100644 GreenshotPlugin/Core/WindowsEnumerator.cs delete mode 100644 GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs delete mode 100644 GreenshotPlugin/Effects/ReduceColorsEffect.cs delete mode 100644 GreenshotPlugin/Effects/ResizeEffect.cs delete mode 100644 GreenshotPlugin/Effects/RotateEffect.cs delete mode 100644 GreenshotPlugin/Effects/TornEdgeEffect.cs delete mode 100644 GreenshotPlugin/GlobalSuppressions.cs delete mode 100644 GreenshotPlugin/Hooking/WindowsEventHook.cs delete mode 100644 GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs delete mode 100644 GreenshotPlugin/Hooking/WindowsTitleMonitor.cs delete mode 100644 GreenshotPlugin/IEInterop/IHTMLDocument2.cs delete mode 100644 GreenshotPlugin/IEInterop/IHTMLDocument3.cs delete mode 100644 GreenshotPlugin/IEInterop/IHTMLElement.cs delete mode 100644 GreenshotPlugin/IEInterop/IHTMLElement2.cs delete mode 100644 GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs delete mode 100644 GreenshotPlugin/IEInterop/IHTMLTxtRange.cs delete mode 100644 GreenshotPlugin/IEInterop/IWebBrowser2.cs delete mode 100644 GreenshotPlugin/IniFile/IniAttributes.cs delete mode 100644 GreenshotPlugin/IniFile/IniConfig.cs delete mode 100644 GreenshotPlugin/IniFile/IniSection.cs delete mode 100644 GreenshotPlugin/IniFile/IniValue.cs delete mode 100644 GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs delete mode 100644 GreenshotPlugin/Interfaces/Drawing/Container.cs delete mode 100644 GreenshotPlugin/Interfaces/ICaptureDetails.cs delete mode 100644 GreenshotPlugin/Interfaces/IDestination.cs delete mode 100644 GreenshotPlugin/Interfaces/IProcessor.cs delete mode 100644 GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs delete mode 100644 GreenshotPlugin/Interop/Base.cs delete mode 100644 GreenshotPlugin/Interop/COMWrapper.cs delete mode 100644 GreenshotPlugin/Interop/ComProgIdAttribute.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/DWM.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/GDI32.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/GDIplus.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/Kernel32.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/Shell32.cs delete mode 100644 GreenshotPlugin/UnmanagedHelpers/User32.cs delete mode 100644 GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs delete mode 100644 GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs rename {Greenshot/releases => installer}/additional_files/installer.txt (100%) rename {Greenshot/releases => installer}/additional_files/license.txt (100%) rename {Greenshot/releases => installer}/additional_files/readme.txt (100%) rename {Greenshot/releases => installer}/appinfo.ini.template (100%) rename {Greenshot/releases => installer}/innosetup/IssProc/IssProc.dll (100%) rename {Greenshot/releases => installer}/innosetup/IssProc/IssProcLanguage.ini (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Afrikaans.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Albanian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Arabic.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Asturian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Basque.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Belarusian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Bengali.islu (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Bosnian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Bulgarian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/ChineseSimplified.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/ChineseTraditional.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Croatian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/EnglishBritish.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Esperanto.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Estonian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Farsi.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Galician.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Georgian.islu (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Greek.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Hindi.islu (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Hungarian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Indonesian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Kazakh.islu (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Korean.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Kurdish.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Latvian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Ligurian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Lithuanian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Luxemburgish.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Macedonian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Malaysian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Marathi.islu (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Mongolian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Montenegrian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Nepali.islu (100%) rename {Greenshot/releases => installer}/innosetup/Languages/NorwegianNynorsk.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Occitan.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Romanian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/ScottishGaelic.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/SerbianCyrillic.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/SerbianLatin.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Sinhala.islu (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Swedish.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Tatar.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Thai.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Uyghur.islu (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Uzbek.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Valencian.isl (100%) rename {Greenshot/releases => installer}/innosetup/Languages/Vietnamese.isl (100%) rename {Greenshot/releases => installer}/innosetup/installer-large.bmp (100%) rename {Greenshot/releases => installer}/innosetup/installer-small.bmp (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/chinese.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/czech.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/dutch.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/english.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/french.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/french2.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/french3.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/german.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/isxdl.dll (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/isxdl.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/italian.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/japanese.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/korean.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/norwegian.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/polish.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/portugues.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/portuguese.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/russian.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/spanish.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/isxdl/swedish.ini (100%) rename {Greenshot/releases => installer}/innosetup/scripts/lang/chinese.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/lang/dutch.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/lang/english.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/lang/french.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/lang/german.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/lang/italian.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/lang/japanese.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/lang/polish.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/lang/russian.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products.pas (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/directxruntime.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx11.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx11lp.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx11sp1.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20lp.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20sp1.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20sp1lp.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20sp2.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx20sp2lp.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx35.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx35lp.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx35sp1.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx35sp1lp.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx40client.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx40full.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx45.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx46.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx47.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfx48.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/dotnetfxversion.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/fileversion.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/ie6.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/iis.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/jet4sp8.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/kb835732.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/mdac28.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/msi20.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/msi31.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/msi45.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/msiproduct.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/sql2005express.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/sql2008express.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/sqlcompact35sp2.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/stringversion.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/vcredist2005.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/vcredist2008.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/vcredist2010.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/vcredist2012.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/vcredist2013.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/vcredist2015.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/vcredist2017.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/wic.iss (100%) rename {Greenshot/releases => installer}/innosetup/scripts/products/winversion.iss (100%) rename {Greenshot/releases => installer}/innosetup/setup.iss (81%) rename {Greenshot/releases => installer}/portable/App/AppInfo/appicon.ico (100%) rename {Greenshot/releases => installer}/portable/App/AppInfo/appicon_16.png (100%) rename {Greenshot/releases => installer}/portable/App/AppInfo/appicon_32.png (100%) rename {Greenshot/releases => installer}/portable/App/DefaultData/Greenshots/dummy.txt (100%) rename {Greenshot/releases => installer}/portable/App/DefaultData/Settings/dummy.txt (100%) rename {Greenshot/releases => installer}/portable/Data/Greenshot/dummy.txt (100%) rename {Greenshot/releases => installer}/portable/Data/Settings/dummy.txt (100%) rename {Greenshot/releases => installer}/portable/Other/Source/PortableApps.comInstallerCustom.nsh (100%) rename .editorconfig => src/.editorconfig (100%) rename Directory.Build.props => src/Directory.Build.props (97%) rename Directory.Build.targets => src/Directory.Build.targets (100%) create mode 100644 src/Greenshot.Base/Controls/AnimatingForm.cs rename {GreenshotPlugin => src/Greenshot.Base}/Controls/BackgroundForm.Designer.cs (96%) create mode 100644 src/Greenshot.Base/Controls/BackgroundForm.cs create mode 100644 src/Greenshot.Base/Controls/ExtendedWebBrowser.cs rename {GreenshotPlugin => src/Greenshot.Base}/Controls/FormWithoutActivation.cs (86%) rename {GreenshotPlugin => src/Greenshot.Base}/Controls/GreenshotButton.cs (75%) rename GreenshotPlugin/Controls/GreenshotTextBox.cs => src/Greenshot.Base/Controls/GreenshotCheckBox.cs (56%) create mode 100644 src/Greenshot.Base/Controls/GreenshotColumnSorter.cs create mode 100644 src/Greenshot.Base/Controls/GreenshotComboBox.cs create mode 100644 src/Greenshot.Base/Controls/GreenshotForm.cs rename {GreenshotPlugin => src/Greenshot.Base}/Controls/GreenshotGroupBox.cs (74%) rename {GreenshotPlugin => src/Greenshot.Base}/Controls/GreenshotLabel.cs (75%) rename GreenshotPlugin/Controls/GreenshotCheckBox.cs => src/Greenshot.Base/Controls/GreenshotRadioButton.cs (56%) rename {GreenshotPlugin => src/Greenshot.Base}/Controls/GreenshotTabPage.cs (75%) rename GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs => src/Greenshot.Base/Controls/GreenshotTextBox.cs (67%) create mode 100644 src/Greenshot.Base/Controls/GreenshotToolDropDownButton.cs rename {GreenshotPlugin => src/Greenshot.Base}/Controls/GreenshotToolStripButton.cs (74%) rename {GreenshotPlugin => src/Greenshot.Base}/Controls/GreenshotToolStripLabel.cs (74%) rename {GreenshotPlugin => src/Greenshot.Base}/Controls/GreenshotToolStripMenuItem.cs (73%) create mode 100644 src/Greenshot.Base/Controls/HotkeyControl.cs rename {GreenshotPlugin => src/Greenshot.Base}/Controls/IGreenshotConfigBindable.cs (69%) rename GreenshotPlugin/Core/EventDelay.cs => src/Greenshot.Base/Controls/IGreenshotLanguageBindable.cs (70%) rename {GreenshotPlugin => src/Greenshot.Base}/Controls/OAuthLoginForm.Designer.cs (96%) create mode 100644 src/Greenshot.Base/Controls/OAuthLoginForm.cs rename {GreenshotPlugin => src/Greenshot.Base}/Controls/PleaseWaitForm.Designer.cs (96%) create mode 100644 src/Greenshot.Base/Controls/PleaseWaitForm.cs rename {GreenshotPlugin => src/Greenshot.Base}/Controls/QualityDialog.Designer.cs (90%) create mode 100644 src/Greenshot.Base/Controls/QualityDialog.cs create mode 100644 src/Greenshot.Base/Controls/SaveImageFileDialog.cs create mode 100644 src/Greenshot.Base/Controls/ThumbnailForm.cs create mode 100644 src/Greenshot.Base/Core/AbstractDestination.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/AbstractProcessor.cs (50%) create mode 100644 src/Greenshot.Base/Core/AccessibleHelper.cs create mode 100644 src/Greenshot.Base/Core/AnimationHelpers.cs create mode 100644 src/Greenshot.Base/Core/BinaryStructHelper.cs create mode 100644 src/Greenshot.Base/Core/Cache.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/Capture.cs (84%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/CaptureDetails.cs (69%) rename GreenshotPlugin/Effects/AdjustEffect.cs => src/Greenshot.Base/Core/CaptureHandler.cs (58%) create mode 100644 src/Greenshot.Base/Core/ClipboardHelper.cs create mode 100644 src/Greenshot.Base/Core/CoreConfiguration.cs create mode 100644 src/Greenshot.Base/Core/CredentialsHelper.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/DisplayKeyAttribute.cs (74%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/DpiHelper.cs (93%) create mode 100644 src/Greenshot.Base/Core/EffectConverter.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/Enums/HResult.cs (96%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/Enums/MonitorDpiType.cs (97%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/Enums/MonitorFrom.cs (96%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/EnvironmentInfo.cs (82%) create mode 100644 src/Greenshot.Base/Core/EventDelay.cs create mode 100644 src/Greenshot.Base/Core/ExplorerHelper.cs create mode 100644 src/Greenshot.Base/Core/FastBitmap.cs create mode 100644 src/Greenshot.Base/Core/FilenameHelper.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/Fraction.cs (97%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/GreenshotResources.cs (57%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/GreenshotResources.resx (98%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/HResultExtensions.cs (96%) create mode 100644 src/Greenshot.Base/Core/IEHelper.cs create mode 100644 src/Greenshot.Base/Core/IImage.cs create mode 100644 src/Greenshot.Base/Core/ImageHelper.cs create mode 100644 src/Greenshot.Base/Core/ImageOutput.cs create mode 100644 src/Greenshot.Base/Core/ImageWrapper.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/InterfaceUtils.cs (56%) create mode 100644 src/Greenshot.Base/Core/JSONHelper.cs create mode 100644 src/Greenshot.Base/Core/Language.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/LanguageChangedHandler.cs (73%) create mode 100644 src/Greenshot.Base/Core/LanguageFile.cs create mode 100644 src/Greenshot.Base/Core/LogHelper.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/NetworkHelper.cs (95%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/OAuth/LocalJsonReceiver.cs (89%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/OAuth/LocalServerCodeReceiver.cs (84%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/OAuth/OAuth2AuthorizeMode.cs (76%) create mode 100644 src/Greenshot.Base/Core/OAuth/OAuth2Helper.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/OAuth/OAuth2Settings.cs (74%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/OAuth/OAuthSession.cs (80%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/OAuth/OAuthSignatureTypes.cs (93%) create mode 100644 src/Greenshot.Base/Core/ObjectExtensions.cs create mode 100644 src/Greenshot.Base/Core/PluginUtils.cs create mode 100644 src/Greenshot.Base/Core/QuantizerHelper.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/RegistryKeyExtensions.cs (93%) rename {GreenshotPlugin => src/Greenshot.Base}/Core/SimpleServiceProvider.cs (92%) create mode 100644 src/Greenshot.Base/Core/StringExtensions.cs create mode 100644 src/Greenshot.Base/Core/SvgImage.cs create mode 100644 src/Greenshot.Base/Core/WindowCapture.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/WindowDetails.cs (77%) create mode 100644 src/Greenshot.Base/Core/WindowsEnumerator.cs rename {GreenshotPlugin => src/Greenshot.Base}/Core/WindowsVersion.cs (98%) create mode 100644 src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs rename GreenshotPlugin/Effects/MonochromeEffect.cs => src/Greenshot.Base/Effects/AdjustEffect.cs (59%) rename {GreenshotPlugin => src/Greenshot.Base}/Effects/BorderEffect.cs (61%) rename {GreenshotPlugin => src/Greenshot.Base}/Effects/DropShadowEffect.cs (56%) rename {GreenshotPlugin => src/Greenshot.Base}/Effects/GrayscaleEffect.cs (70%) create mode 100644 src/Greenshot.Base/Effects/IEffect.cs rename {GreenshotPlugin => src/Greenshot.Base}/Effects/InvertEffect.cs (71%) create mode 100644 src/Greenshot.Base/Effects/MonochromeEffect.cs create mode 100644 src/Greenshot.Base/Effects/ReduceColorsEffect.cs rename {GreenshotPlugin => src/Greenshot.Base}/Effects/ResizeCanvasEffect.cs (50%) rename GreenshotPlugin/Effects/IEffect.cs => src/Greenshot.Base/Effects/ResizeEffect.cs (55%) create mode 100644 src/Greenshot.Base/Effects/RotateEffect.cs create mode 100644 src/Greenshot.Base/Effects/TornEdgeEffect.cs rename {GreenshotPlugin => src/Greenshot.Base}/FileDescriptorReader.cs (94%) create mode 100644 src/Greenshot.Base/GlobalSuppressions.cs rename GreenshotPlugin/GreenshotPlugin.csproj => src/Greenshot.Base/Greenshot.Base.csproj (68%) create mode 100644 src/Greenshot.Base/Hooking/WindowsEventHook.cs create mode 100644 src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs create mode 100644 src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs rename GreenshotPlugin/IEInterop/IHTMLWindow3.cs => src/Greenshot.Base/IEInterop/IHTMLBodyElement.cs (71%) rename {GreenshotPlugin => src/Greenshot.Base}/IEInterop/IHTMLCurrentStyle.cs (52%) rename {GreenshotPlugin => src/Greenshot.Base}/IEInterop/IHTMLDocument.cs (68%) create mode 100644 src/Greenshot.Base/IEInterop/IHTMLDocument2.cs create mode 100644 src/Greenshot.Base/IEInterop/IHTMLDocument3.cs rename {GreenshotPlugin => src/Greenshot.Base}/IEInterop/IHTMLDocument4.cs (92%) rename {GreenshotPlugin => src/Greenshot.Base}/IEInterop/IHTMLDocument5.cs (70%) create mode 100644 src/Greenshot.Base/IEInterop/IHTMLElement.cs rename GreenshotPlugin/IEInterop/IHTMLRect.cs => src/Greenshot.Base/IEInterop/IHTMLElement2.cs (64%) rename {GreenshotPlugin => src/Greenshot.Base}/IEInterop/IHTMLElementCollection.cs (73%) rename {GreenshotPlugin => src/Greenshot.Base}/IEInterop/IHTMLFrameBase.cs (70%) rename {GreenshotPlugin => src/Greenshot.Base}/IEInterop/IHTMLFramesCollection2.cs (68%) create mode 100644 src/Greenshot.Base/IEInterop/IHTMLRect.cs rename GreenshotPlugin/IEInterop/IHTMLBodyElement.cs => src/Greenshot.Base/IEInterop/IHTMLScreen.cs (73%) create mode 100644 src/Greenshot.Base/IEInterop/IHTMLScreen2.cs rename GreenshotPlugin/IEInterop/IHTMLWindow2.cs => src/Greenshot.Base/IEInterop/IHTMLSelectionObject.cs (59%) rename {GreenshotPlugin => src/Greenshot.Base}/IEInterop/IHTMLStyle.cs (84%) create mode 100644 src/Greenshot.Base/IEInterop/IHTMLTxtRange.cs rename GreenshotPlugin/IEInterop/IHTMLScreen2.cs => src/Greenshot.Base/IEInterop/IHTMLWindow2.cs (63%) rename GreenshotPlugin/IEInterop/IHTMLScreen.cs => src/Greenshot.Base/IEInterop/IHTMLWindow3.cs (72%) rename {GreenshotPlugin => src/Greenshot.Base}/IEInterop/IHTMLWindow4.cs (72%) create mode 100644 src/Greenshot.Base/IEInterop/IWebBrowser2.cs create mode 100644 src/Greenshot.Base/IniFile/IniAttributes.cs create mode 100644 src/Greenshot.Base/IniFile/IniConfig.cs rename {GreenshotPlugin => src/Greenshot.Base}/IniFile/IniReader.cs (59%) create mode 100644 src/Greenshot.Base/IniFile/IniSection.cs create mode 100644 src/Greenshot.Base/IniFile/IniValue.cs rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/CaptureMode.cs (97%) create mode 100644 src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs create mode 100644 src/Greenshot.Base/Interfaces/Drawing/Container.cs rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Drawing/IField.cs (50%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Drawing/IFieldholder.cs (63%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Drawing/IMemento.cs (57%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/DrawingModes.cs (96%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Forms/ImageEditor.cs (57%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/ICapture.cs (79%) create mode 100644 src/Greenshot.Base/Interfaces/ICaptureDetails.cs create mode 100644 src/Greenshot.Base/Interfaces/IDestination.cs rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/INotificationService.cs (98%) create mode 100644 src/Greenshot.Base/Interfaces/IProcessor.cs rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/IServiceLocator.cs (85%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/ISurface.cs (90%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Ocr/IOcrProvider.cs (95%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Ocr/Line.cs (96%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Ocr/OcrInformation.cs (93%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Ocr/Word.cs (90%) create mode 100644 src/Greenshot.Base/Interfaces/Plugin/HotKeyHandler.cs rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Plugin/IGreenshotHost.cs (93%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Plugin/IGreenshotPlugin.cs (84%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Plugin/PluginAttribute.cs (57%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/Plugin/SurfaceOutputSettings.cs (65%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/ScreenCaptureMode.cs (96%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/SurfaceDrawingModeEventArgs.cs (88%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/SurfaceDrawingModeEventHandler.cs (96%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/SurfaceElementEventArgs.cs (84%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/SurfaceElementEventHandler.cs (96%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/SurfaceMessageEventArgs.cs (82%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/SurfaceMessageEventHandler.cs (96%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/SurfaceMessageTyp.cs (96%) rename {GreenshotPlugin => src/Greenshot.Base}/Interfaces/SurfaceSizeChangeEventHandler.cs (96%) create mode 100644 src/Greenshot.Base/Interop/Base.cs create mode 100644 src/Greenshot.Base/Interop/COMWrapper.cs create mode 100644 src/Greenshot.Base/Interop/ComProgIdAttribute.cs rename {GreenshotPlugin => src/Greenshot.Base}/Interop/IAppVisibility.cs (61%) rename {GreenshotPlugin => src/Greenshot.Base}/Interop/IDispatch.cs (54%) rename {GreenshotPlugin => src/Greenshot.Base}/Interop/IOleCommandTarget.cs (60%) rename {GreenshotPlugin => src/Greenshot.Base}/Interop/IOleWindow.cs (67%) rename {GreenshotPlugin => src/Greenshot.Base}/Interop/IServiceProvider.cs (65%) rename {GreenshotPlugin => src/Greenshot.Base}/Interop/IUnknown.cs (74%) create mode 100644 src/Greenshot.Base/UnmanagedHelpers/DWM.cs rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/EnumWindowsProc.cs (94%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/ClassLongIndex.cs (93%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs (77%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs (85%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/DesktopAccessRight.cs (92%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/DeviceCaps.cs (92%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/EventObjects.cs (93%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs (72%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/ProcessAccessFlags.cs (90%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/RegionResult.cs (90%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs (87%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/ShowWindowCommand.cs (95%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/SoundFlags.cs (77%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/ThreadAccess.cs (89%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/Win32Error.cs (93%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/WinEvent.cs (91%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/WinEventHookFlags.cs (87%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/WindowLongIndex.cs (84%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/WindowPlacementFlags.cs (93%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/WindowPos.cs (71%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/WindowStyleFlags.cs (77%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Enums/WindowsMessages.cs (92%) create mode 100644 src/Greenshot.Base/UnmanagedHelpers/GDI32.cs create mode 100644 src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs create mode 100644 src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/PsAPI.cs (55%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs (69%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/SafeIconHandle.cs (77%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/SafeWindowDcHandle.cs (87%) create mode 100644 src/Greenshot.Base/UnmanagedHelpers/Shell32.cs rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Structs/CursorInfo.cs (90%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Structs/IconInfo.cs (91%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Structs/POINT.cs (77%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Structs/RECT.cs (55%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Structs/RECTF.cs (88%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Structs/SCROLLINFO.cs (91%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Structs/SIZE.cs (64%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Structs/WindowInfo.cs (87%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Structs/WindowPlacement.cs (90%) create mode 100644 src/Greenshot.Base/UnmanagedHelpers/User32.cs rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/Win32.cs (62%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/WinEventDelegate.cs (84%) rename {GreenshotPlugin => src/Greenshot.Base}/UnmanagedHelpers/WinMM.cs (68%) rename {GreenshotPlugin => src/Greenshot.Base}/log4net-embedded.xml (97%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Box.png (100%) create mode 100644 src/Greenshot.Plugin.Box/BoxConfiguration.cs create mode 100644 src/Greenshot.Plugin.Box/BoxDestination.cs create mode 100644 src/Greenshot.Plugin.Box/BoxEntities.cs create mode 100644 src/Greenshot.Plugin.Box/BoxPlugin.cs rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/BoxPlugin.resx (100%) create mode 100644 src/Greenshot.Plugin.Box/BoxUtils.cs rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Forms/BoxForm.cs (86%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Forms/SettingsForm.Designer.cs (85%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Box}/Forms/SettingsForm.cs (64%) rename GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template => src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template (97%) rename GreenshotBoxPlugin/GreenshotBoxPlugin.csproj => src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj (56%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Box}/LanguageKeys.cs (83%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-cs-CZ.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-de-DE.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-en-US.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-fr-FR.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-id-ID.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-it-IT.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-ja-JP.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-kab-DZ.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-ko-KR.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-lv-LV.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-pl-PL.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-pt-PT.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-ru-RU.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-sr-RS.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-sv-SE.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-uk-UA.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-zh-CN.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Languages/language_boxplugin-zh-TW.xml (100%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Box}/Properties/AssemblyInfo.cs (97%) create mode 100644 src/Greenshot.Plugin.Confluence/Confluence.cs create mode 100644 src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs create mode 100644 src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs create mode 100644 src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs create mode 100644 src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs create mode 100644 src/Greenshot.Plugin.Confluence/EnumDisplayer.cs rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Forms/ConfluenceConfigurationForm.xaml (79%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Forms/ConfluenceConfigurationForm.xaml.cs (59%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Forms/ConfluencePagePicker.xaml (85%) create mode 100644 src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Forms/ConfluenceSearch.xaml (90%) create mode 100644 src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Forms/ConfluenceTreePicker.xaml (82%) create mode 100644 src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml.cs rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Forms/ConfluenceUpload.xaml (90%) create mode 100644 src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs rename GreenshotConfluencePlugin/GreenshotConfluencePlugin.csproj => src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj (77%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Images/Confluence.ico (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Confluence}/LanguageKeys.cs (83%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-cs-CZ.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-de-DE.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-en-US.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-fr-FR.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-id-ID.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-it-IT.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-ja-JP.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-kab-DZ.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-ko-KR.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-lv-LV.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-nl-NL.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-pl-PL.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-pt-PT.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-ru-RU.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-sr-RS.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-sv-SE.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-uk-UA.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-zh-CN.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Languages/language_confluenceplugin-zh-TW.xml (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Support/ITranslationProvider.cs (65%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Support/LanguageChangedEventManager.cs (81%) create mode 100644 src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Support/TranslateExtension.cs (82%) create mode 100644 src/Greenshot.Plugin.Confluence/Support/TranslationData.cs create mode 100644 src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Web References/confluence/Reference.cs (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Web References/confluence/Reference.map (100%) rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Confluence}/Web References/confluence/confluenceservice-v1.wsdl (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Dropbox.gif (100%) create mode 100644 src/Greenshot.Plugin.Dropbox/DropboxDestination.cs create mode 100644 src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/DropboxPlugin.resx (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/DropboxPluginConfiguration.cs (50%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/DropboxUtils.cs (66%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Forms/DropboxForm.cs (85%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Forms/SettingsForm.Designer.cs (84%) create mode 100644 src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs rename GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template => src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.Credentials.template (97%) rename GreenshotDropboxPlugin/GreenshotDropboxPlugin.csproj => src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj (56%) create mode 100644 src/Greenshot.Plugin.Dropbox/LanguageKeys.cs rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-cs-CZ.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-de-DE.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-en-US.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-fr-FR.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-id-ID.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-it-IT.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-ja-JP.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-kab-DZ.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-ko-KR.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-lv-LV.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-pl-PL.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-pt-PT.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-ru-RU.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-sr-RS.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-sv-SE.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-uk-UA.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-zh-CN.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Languages/language_dropboxplugin-zh-TW.xml (100%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Dropbox}/Properties/AssemblyInfo.cs (97%) create mode 100644 src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs create mode 100644 src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/ExternalCommandForm.cs (76%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/ExternalCommandPlugin.cs (94%) create mode 100644 src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj create mode 100644 src/Greenshot.Plugin.ExternalCommand/IconCache.cs rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-cs-CZ.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-de-DE.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-en-US.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-fr-FR.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-id-ID.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-it-IT.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-ja-JP.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-kab-DZ.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-ko-KR.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-lv-LV.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-pl-PL.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-pt-PT.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-ru-RU.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-sk-SK.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-sr-RS.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-sv-SE.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-uk-UA.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-zh-CN.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/Languages/language_externalcommandplugin-zh-TW.xml (100%) rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/SettingsForm.Designer.cs (87%) create mode 100644 src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs rename {GreenshotExternalCommandPlugin => src/Greenshot.Plugin.ExternalCommand}/SettingsFormDetail.Designer.cs (86%) create mode 100644 src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs create mode 100644 src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs create mode 100644 src/Greenshot.Plugin.Flickr/FlickrDestination.cs create mode 100644 src/Greenshot.Plugin.Flickr/FlickrPlugin.cs rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/FlickrPlugin.resx (100%) create mode 100644 src/Greenshot.Plugin.Flickr/FlickrUtils.cs rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Forms/FlickrForm.cs (85%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Forms/SettingsForm.Designer.cs (81%) rename {GreenshotDropboxPlugin => src/Greenshot.Plugin.Flickr}/Forms/SettingsForm.cs (64%) rename GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template => src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.Credentials.template (97%) rename GreenshotFlickrPlugin/GreenshotFlickrPlugin.csproj => src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj (56%) rename {GreenshotBoxPlugin => src/Greenshot.Plugin.Flickr}/LanguageKeys.cs (82%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-cs-CZ.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-de-DE.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-en-US.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-fr-FR.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-id-ID.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-it-IT.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-ja-JP.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-kab-DZ.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-ko-KR.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-lv-LV.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-pl-PL.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-pt-PT.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-ru-RU.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-sr-RS.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-sv-SE.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-uk-UA.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-zh-CN.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Languages/language_flickrplugin-zh-TW.xml (100%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/Properties/AssemblyInfo.cs (97%) rename {GreenshotFlickrPlugin => src/Greenshot.Plugin.Flickr}/flickr.png (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Forms/GooglePhotosForm.cs (84%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Forms/SettingsForm.Designer.cs (86%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Forms/SettingsForm.cs (62%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/GooglePhotos.png (100%) create mode 100644 src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs create mode 100644 src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs create mode 100644 src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/GooglePhotosPlugin.resx (100%) create mode 100644 src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs rename GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template => src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.Credentials.template (96%) rename GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj => src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj (68%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/LanguageKeys.cs (81%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-cs-CZ.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-de-DE.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-en-US.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-fr-FR.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-id-ID.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-it-IT.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-ja-JP.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-kab-DZ.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-ko-KR.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-lv-LV.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-pl-PL.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-pt-PT.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-ru-RU.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-sr-RS.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-sv-SE.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-uk-UA.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-zh-CN.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Languages/language_googlephotosplugin-zh-TW.xml (100%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/Properties/AssemblyInfo.cs (97%) rename {GreenshotGooglePhotosPlugin => src/Greenshot.Plugin.GooglePhotos}/README (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Forms/ImgurForm.cs (77%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Forms/ImgurHistory.Designer.cs (97%) create mode 100644 src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Forms/SettingsForm.Designer.cs (83%) create mode 100644 src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs rename GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template => src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.Credentials.template (97%) rename GreenshotImgurPlugin/GreenshotImgurPlugin.csproj => src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj (50%) create mode 100644 src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/ImgurDestination.cs (52%) create mode 100644 src/Greenshot.Plugin.Imgur/ImgurInfo.cs create mode 100644 src/Greenshot.Plugin.Imgur/ImgurPlugin.cs rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/ImgurPlugin.resx (100%) create mode 100644 src/Greenshot.Plugin.Imgur/ImgurUtils.cs rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/LanguageKeys.cs (76%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-cs-CZ.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-de-DE.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-en-US.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-fr-FR.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-id-ID.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-it-IT.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-ja-JP.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-kab-DZ.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-ko-KR.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-lv-LV.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-nl-NL.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-pl-PL.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-pt-PT.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-ru-RU.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-sk-SK.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-sr-RS.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-sv-SE.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-uk-UA.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-zh-CN.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Languages/language_imgurplugin-zh-TW.xml (100%) rename {GreenshotImgurPlugin => src/Greenshot.Plugin.Imgur}/Properties/AssemblyInfo.cs (97%) create mode 100644 src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Forms/JiraForm.Designer.cs (97%) create mode 100644 src/Greenshot.Plugin.Jira/Forms/JiraForm.cs rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Forms/JiraFormBase.cs (87%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Forms/SettingsForm.Designer.cs (84%) create mode 100644 src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs rename GreenshotJiraPlugin/GreenshotJiraPlugin.csproj => src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj (61%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/IssueTypeBitmapCache.cs (53%) create mode 100644 src/Greenshot.Plugin.Jira/JiraConfiguration.cs create mode 100644 src/Greenshot.Plugin.Jira/JiraConnector.cs create mode 100644 src/Greenshot.Plugin.Jira/JiraDestination.cs rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/JiraDetails.cs (58%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/JiraEventArgs.cs (80%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/JiraEventTypes.cs (85%) create mode 100644 src/Greenshot.Plugin.Jira/JiraMonitor.cs create mode 100644 src/Greenshot.Plugin.Jira/JiraPlugin.cs rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/JiraPlugin.resx (100%) create mode 100644 src/Greenshot.Plugin.Jira/LanguageKeys.cs rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-cs-CZ.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-de-DE.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-en-US.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-fr-FR.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-id-ID.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-it-IT.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-ja-JP.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-kab-DZ.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-ko-KR.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-lv-LV.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-nl-NL.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-pl-PL.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-pt-PT.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-ru-RU.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-sr-RS.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-sv-SE.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-uk-UA.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-zh-CN.xml (100%) rename {GreenshotJiraPlugin => src/Greenshot.Plugin.Jira}/Languages/language_jiraplugin-zh-TW.xml (100%) create mode 100644 src/Greenshot.Plugin.Jira/Log4NetLogger.cs rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/Com/DisposableCom.cs (92%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/Com/DisposableComImplementation.cs (94%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/Com/IDisposableCom.cs (90%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/Com/Ole32Api.cs (90%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/Com/OleAut32Api.cs (90%) create mode 100644 src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs create mode 100644 src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs create mode 100644 src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs create mode 100644 src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs create mode 100644 src/Greenshot.Plugin.Office/Destinations/WordDestination.cs create mode 100644 src/Greenshot.Plugin.Office/GlobalSuppressions.cs rename GreenshotOfficePlugin/GreenshotOfficePlugin.csproj => src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj (94%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/Languages/language_officeplugin-fr-FR.ini (100%) create mode 100644 src/Greenshot.Plugin.Office/OfficeConfiguration.cs rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/OfficeExport/Entities/OneNoteNotebook.cs (93%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/OfficeExport/Entities/OneNotePage.cs (94%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/OfficeExport/Entities/OneNoteSection.cs (93%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/OfficeExport/ExcelExporter.cs (93%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/OfficeExport/OneNoteExporter.cs (92%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/OfficeExport/OutlookEmailExporter.cs (92%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/OfficeExport/PowerpointExporter.cs (95%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/OfficeExport/WordExporter.cs (94%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/OfficeInterop/EmailFormat.cs (80%) rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/OfficeInterop/OfficeVersions.cs (79%) create mode 100644 src/Greenshot.Plugin.Office/OfficePlugin.cs rename {GreenshotOfficePlugin => src/Greenshot.Plugin.Office}/Properties/AssemblyInfo.cs (97%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Forms/PhotobucketForm.cs (76%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Forms/SettingsForm.Designer.cs (84%) create mode 100644 src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs rename GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template => src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.Credentials.template (96%) create mode 100644 src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj rename {GreenshotConfluencePlugin => src/Greenshot.Plugin.Photobucket}/LanguageKeys.cs (81%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-cs-CZ.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-de-DE.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-en-US.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-fr_FR.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-id-ID.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-it-IT.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-ja-JP.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-kab-DZ.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-ko-KR.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-lv-LV.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-nl-NL.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-pl-PL.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-pt-PT.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-ru-RU.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-sv-SE.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-uk-UA.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-zh-CN.xml (100%) rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Languages/language_photobucketplugin-zh-TW.xml (100%) create mode 100644 src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs create mode 100644 src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs create mode 100644 src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs create mode 100644 src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/PhotobucketPlugin.resx (100%) create mode 100644 src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs rename {GreenshotPhotobucketPlugin => src/Greenshot.Plugin.Photobucket}/Properties/AssemblyInfo.cs (97%) create mode 100644 src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs rename {GreenshotWin10Plugin => src/Greenshot.Plugin.Win10}/Destinations/Win10ShareDestination.cs (92%) rename GreenshotWin10Plugin/GreenshotWin10Plugin.csproj => src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj (59%) rename {GreenshotWin10Plugin => src/Greenshot.Plugin.Win10}/Internal/MemoryRandomAccessStream.cs (62%) rename {GreenshotWin10Plugin => src/Greenshot.Plugin.Win10}/Internal/ShareInfo.cs (97%) create mode 100644 src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs rename {GreenshotWin10Plugin => src/Greenshot.Plugin.Win10}/Native/IDataTransferManagerInterOp.cs (54%) rename {GreenshotWin10Plugin => src/Greenshot.Plugin.Win10}/Processors/Win10OcrProcessor.cs (85%) rename {GreenshotWin10Plugin => src/Greenshot.Plugin.Win10}/Properties/AssemblyInfo.cs (90%) rename {GreenshotWin10Plugin => src/Greenshot.Plugin.Win10}/ToastNotificationService.cs (96%) rename {GreenshotWin10Plugin => src/Greenshot.Plugin.Win10}/Win10Configuration.cs (65%) rename {GreenshotWin10Plugin => src/Greenshot.Plugin.Win10}/Win10OcrProvider.cs (63%) rename {GreenshotWin10Plugin => src/Greenshot.Plugin.Win10}/Win10Plugin.cs (54%) rename Greenshot.sln => src/Greenshot.sln (82%) rename Greenshot.sln.DotSettings => src/Greenshot.sln.DotSettings (100%) create mode 100644 src/Greenshot/App.config create mode 100644 src/Greenshot/Configuration/EditorConfiguration.cs create mode 100644 src/Greenshot/Configuration/LanguageKeys.cs rename {Greenshot => src/Greenshot}/Controls/BindableToolStripButton.cs (52%) rename {Greenshot => src/Greenshot}/Controls/BindableToolStripComboBox.cs (50%) create mode 100644 src/Greenshot/Controls/BindableToolStripDropDownButton.cs create mode 100644 src/Greenshot/Controls/ColorButton.cs create mode 100644 src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs create mode 100644 src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs create mode 100644 src/Greenshot/Controls/FontFamilyComboBox.cs create mode 100644 src/Greenshot/Controls/MenuStripEx.cs rename {Greenshot => src/Greenshot}/Controls/NonJumpingPanel.cs (97%) create mode 100644 src/Greenshot/Controls/Pipette.cs create mode 100644 src/Greenshot/Controls/ToolStripColorButton.cs create mode 100644 src/Greenshot/Controls/ToolStripEx.cs create mode 100644 src/Greenshot/Controls/ToolStripNumericUpDown.cs create mode 100644 src/Greenshot/Destinations/ClipboardDestination.cs create mode 100644 src/Greenshot/Destinations/EditorDestination.cs create mode 100644 src/Greenshot/Destinations/EmailDestination.cs create mode 100644 src/Greenshot/Destinations/FileDestination.cs create mode 100644 src/Greenshot/Destinations/FileWithDialogDestination.cs create mode 100644 src/Greenshot/Destinations/PickerDestination.cs create mode 100644 src/Greenshot/Destinations/PrinterDestination.cs create mode 100644 src/Greenshot/Drawing/Adorners/AbstractAdorner.cs create mode 100644 src/Greenshot/Drawing/Adorners/MoveAdorner.cs create mode 100644 src/Greenshot/Drawing/Adorners/ResizeAdorner.cs create mode 100644 src/Greenshot/Drawing/Adorners/TargetAdorner.cs create mode 100644 src/Greenshot/Drawing/ArrowContainer.cs create mode 100644 src/Greenshot/Drawing/CropContainer.cs create mode 100644 src/Greenshot/Drawing/CursorContainer.cs create mode 100644 src/Greenshot/Drawing/DrawableContainer.cs create mode 100644 src/Greenshot/Drawing/DrawableContainerList.cs create mode 100644 src/Greenshot/Drawing/EllipseContainer.cs create mode 100644 src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs create mode 100644 src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs create mode 100644 src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs create mode 100644 src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs (57%) create mode 100644 src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs create mode 100644 src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/IBindingConverter.cs (70%) create mode 100644 src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs rename {Greenshot => src/Greenshot}/Drawing/Fields/Binding/NotNullValidator.cs (67%) create mode 100644 src/Greenshot/Drawing/Fields/Field.cs create mode 100644 src/Greenshot/Drawing/Fields/FieldAggregator.cs create mode 100644 src/Greenshot/Drawing/Fields/FieldType.cs create mode 100644 src/Greenshot/Drawing/FilterContainer.cs create mode 100644 src/Greenshot/Drawing/Filters/AbstractFilter.cs create mode 100644 src/Greenshot/Drawing/Filters/BlurFilter.cs create mode 100644 src/Greenshot/Drawing/Filters/BrightnessFilter.cs create mode 100644 src/Greenshot/Drawing/Filters/GrayscaleFilter.cs create mode 100644 src/Greenshot/Drawing/Filters/HighlightFilter.cs rename {Greenshot => src/Greenshot}/Drawing/Filters/IFilter.cs (73%) create mode 100644 src/Greenshot/Drawing/Filters/MagnifierFilter.cs rename {Greenshot => src/Greenshot}/Drawing/Filters/PixelizationFilter.cs (62%) create mode 100644 src/Greenshot/Drawing/FreehandContainer.cs create mode 100644 src/Greenshot/Drawing/HighlightContainer.cs create mode 100644 src/Greenshot/Drawing/IconContainer.cs create mode 100644 src/Greenshot/Drawing/ImageContainer.cs create mode 100644 src/Greenshot/Drawing/LineContainer.cs create mode 100644 src/Greenshot/Drawing/ObfuscateContainer.cs rename {Greenshot => src/Greenshot}/Drawing/Positions.cs (74%) create mode 100644 src/Greenshot/Drawing/RectangleContainer.cs create mode 100644 src/Greenshot/Drawing/SpeechbubbleContainer.cs create mode 100644 src/Greenshot/Drawing/StepLabelContainer.cs create mode 100644 src/Greenshot/Drawing/Surface.cs rename {Greenshot => src/Greenshot}/Drawing/TextContainer.cs (93%) rename {Greenshot => src/Greenshot}/Forms/AboutForm.Designer.cs (90%) create mode 100644 src/Greenshot/Forms/AboutForm.cs rename {Greenshot => src/Greenshot}/Forms/AnimatingBaseForm.cs (75%) rename {Greenshot => src/Greenshot}/Forms/BaseForm.cs (76%) rename {Greenshot => src/Greenshot}/Forms/BugReportForm.Designer.cs (92%) create mode 100644 src/Greenshot/Forms/BugReportForm.cs rename {Greenshot => src/Greenshot}/Forms/CaptureForm.Designer.cs (100%) create mode 100644 src/Greenshot/Forms/CaptureForm.cs rename {Greenshot => src/Greenshot}/Forms/ColorDialog.Designer.cs (89%) create mode 100644 src/Greenshot/Forms/ColorDialog.cs rename {Greenshot => src/Greenshot}/Forms/ColorDialog.resx (100%) create mode 100644 src/Greenshot/Forms/ColorPickerToolStripButton.cs rename {Greenshot => src/Greenshot}/Forms/DropShadowSettingsForm.Designer.cs (89%) create mode 100644 src/Greenshot/Forms/DropShadowSettingsForm.cs rename {Greenshot => src/Greenshot}/Forms/ImageEditorForm.Designer.cs (83%) create mode 100644 src/Greenshot/Forms/ImageEditorForm.cs rename {Greenshot => src/Greenshot}/Forms/ImageEditorForm.resx (100%) rename {Greenshot => src/Greenshot}/Forms/LanguageDialog.Designer.cs (100%) create mode 100644 src/Greenshot/Forms/LanguageDialog.cs rename {Greenshot => src/Greenshot}/Forms/MainForm.Designer.cs (80%) create mode 100644 src/Greenshot/Forms/MainForm.cs rename {Greenshot => src/Greenshot}/Forms/MainForm.resx (100%) rename {Greenshot => src/Greenshot}/Forms/MovableShowColorForm.Designer.cs (100%) create mode 100644 src/Greenshot/Forms/MovableShowColorForm.cs rename {Greenshot => src/Greenshot}/Forms/PrintOptionsDialog.Designer.cs (84%) rename {Greenshot => src/Greenshot}/Forms/PrintOptionsDialog.cs (55%) rename {Greenshot => src/Greenshot}/Forms/ResizeSettingsForm.Designer.cs (88%) create mode 100644 src/Greenshot/Forms/ResizeSettingsForm.cs rename {Greenshot => src/Greenshot}/Forms/SettingsForm.Designer.cs (81%) create mode 100644 src/Greenshot/Forms/SettingsForm.cs rename {Greenshot => src/Greenshot}/Forms/SettingsForm.resx (100%) create mode 100644 src/Greenshot/Forms/ToolStripMenuSelectList.cs rename {Greenshot => src/Greenshot}/Forms/TornEdgeSettingsForm.Designer.cs (86%) create mode 100644 src/Greenshot/Forms/TornEdgeSettingsForm.cs rename {Greenshot => src/Greenshot}/Greenshot.csproj (94%) create mode 100644 src/Greenshot/GreenshotMain.cs create mode 100644 src/Greenshot/Help/HelpFileLoader.cs create mode 100644 src/Greenshot/Helpers/CaptureHelper.cs create mode 100644 src/Greenshot/Helpers/Colors.cs create mode 100644 src/Greenshot/Helpers/CopyData.cs create mode 100644 src/Greenshot/Helpers/DestinationHelper.cs rename {Greenshot => src/Greenshot}/Helpers/Entities/UpdateFeed.cs (85%) create mode 100644 src/Greenshot/Helpers/GeometryHelper.cs rename {Greenshot => src/Greenshot}/Helpers/GuiRectangle.cs (52%) create mode 100644 src/Greenshot/Helpers/IECaptureHelper.cs create mode 100644 src/Greenshot/Helpers/IEInterop/IEContainer.cs create mode 100644 src/Greenshot/Helpers/MailHelper.cs rename {Greenshot => src/Greenshot}/Helpers/NotifyIconNotificationService.cs (94%) create mode 100644 src/Greenshot/Helpers/PluginHelper.cs create mode 100644 src/Greenshot/Helpers/PrintHelper.cs create mode 100644 src/Greenshot/Helpers/ProcessorHelper.cs create mode 100644 src/Greenshot/Helpers/ResourceMutex.cs create mode 100644 src/Greenshot/Helpers/ScaleHelper.cs create mode 100644 src/Greenshot/Helpers/SoundHelper.cs create mode 100644 src/Greenshot/Helpers/StartupHelper.cs create mode 100644 src/Greenshot/Helpers/ToolStripItemEndisabler.cs rename {Greenshot => src/Greenshot}/Helpers/UpdateService.cs (98%) rename {Greenshot => src/Greenshot}/Languages/help-de-DE.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-en-US.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-es-ES.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-fr-FR.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-hu-HU.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-it-IT.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-ko-KR.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-nl-NL.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-nn-NO.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-pl-PL.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-pt-BR.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-pt-PT.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-ru-RU.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-sv-SE.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-tr-TR.html (100%) rename {Greenshot => src/Greenshot}/Languages/help-zh-CN.html (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-de-DE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-en-US.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-es-ES.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-fi-FI.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-fr-FR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-it-IT.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-lv-LV.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-nl-NL.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-nn-NO.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-sr-RS.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-sv-SE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-uk-UA.xml (100%) rename {Greenshot => src/Greenshot}/Languages/installer/language-installer-zh-CN.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ar-SY.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ca-CA.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-cs-CZ.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-da-DK.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-de-DE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-de-x-franconia.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-el-GR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-en-US.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-es-ES.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-et-EE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-fa-IR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-fi-FI.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-fr-FR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-fr-QC.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-he-IL.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-hu-HU.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-id-ID.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-it-IT.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ja-JP.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-kab-DZ.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ko-KR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-lt-LT.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-lv-LV.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-nl-NL.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-nn-NO.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-pl-PL.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-pt-BR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-pt-PT.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ro-RO.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-ru-RU.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-sk-SK.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-sl-SI.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-sr-RS.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-sv-SE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-tr-TR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-uk-UA.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-vi-VN.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-zh-CN.xml (100%) rename {Greenshot => src/Greenshot}/Languages/language-zh-TW.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-de-DE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-en-US.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-es-ES.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-fr-FR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-it-IT.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-lv-LV.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-nn-NO.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-pt-BR.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-sv-SE.xml (100%) rename {Greenshot => src/Greenshot}/Languages/website/language-website-uk-UA.xml (100%) create mode 100644 src/Greenshot/Memento/AddElementMemento.cs create mode 100644 src/Greenshot/Memento/AddElementsMemento.cs create mode 100644 src/Greenshot/Memento/ChangeFieldHolderMemento.cs create mode 100644 src/Greenshot/Memento/DeleteElementMemento.cs create mode 100644 src/Greenshot/Memento/DeleteElementsMemento.cs create mode 100644 src/Greenshot/Memento/DrawableContainerBoundsChangeMemento.cs create mode 100644 src/Greenshot/Memento/SurfaceBackgroundChangeMemento.cs create mode 100644 src/Greenshot/Memento/TextChangeMemento.cs rename {Greenshot => src/Greenshot}/Processors/TitleFixProcessor.cs (59%) rename {Greenshot => src/Greenshot}/Sounds.resx (100%) rename {Greenshot => src/Greenshot}/greenshot.manifest (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/16.ico (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/16.png (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/32.ico (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/32.png (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/48.ico (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/48.png (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/90.png (100%) rename {Greenshot => src/Greenshot}/icons/applicationIcon/icon.ico (100%) rename {Greenshot => src/Greenshot}/icons/arrow_redo.png (100%) rename {Greenshot => src/Greenshot}/icons/arrow_rollback.png (100%) rename {Greenshot => src/Greenshot}/icons/arrow_undo.png (100%) rename {Greenshot => src/Greenshot}/icons/balloon.png (100%) rename {Greenshot => src/Greenshot}/icons/cancel.png (100%) rename {Greenshot => src/Greenshot}/icons/cross.png (100%) rename {Greenshot => src/Greenshot}/icons/cut.png (100%) rename {Greenshot => src/Greenshot}/icons/delete.png (100%) rename {Greenshot => src/Greenshot}/icons/filter_blur.png (100%) rename {Greenshot => src/Greenshot}/icons/filter_pixelate.png (100%) rename {Greenshot => src/Greenshot}/icons/folder-open-image.png (100%) rename {Greenshot => src/Greenshot}/icons/folder_explore.png (100%) rename {Greenshot => src/Greenshot}/icons/font_color.png (100%) rename {Greenshot => src/Greenshot}/icons/freehand.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/arrow-resize.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/clipboard-paste-image.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/clipboard.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/color-swatch.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/cross.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/cursor.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/disk-black.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-alignment-center.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-alignment-right.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-alignment.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-blur.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-bold.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-italic.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-pixelate.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-underline.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-vertical-alignment-middle.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-vertical-alignment-top.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/edit-vertical-alignment.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/filter_base.pdn (100%) rename {Greenshot => src/Greenshot}/icons/fugue/filter_highlight_area.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/filter_highlight_grayscale.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/filter_highlight_text.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/gear.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/highlighter-color.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/highlighter-text.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/image-blur.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/image-pixelate.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/images.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/layer-shape-arrow.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/layer-shape-ellipse.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/layer-shape-line.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/layer-shape-text.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/layer-shape.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier-zoom-actual.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier-zoom-fit.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier-zoom-in.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier-zoom-out.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier-zoom.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/magnifier.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/mail-open-image.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/minus-circle.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/money-coin.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/paint-can-color-bg.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/paint-can-color.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/pencil-color-bg.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/pencil-color.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/printer.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/question.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/ruler-crop.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/scissors.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/slash.png (100%) rename {Greenshot => src/Greenshot}/icons/fugue/tick.png (100%) rename {Greenshot => src/Greenshot}/icons/heart.png (100%) rename {Greenshot => src/Greenshot}/icons/help.png (100%) rename {Greenshot => src/Greenshot}/icons/highlighter.png (100%) rename {Greenshot => src/Greenshot}/icons/layer-rotate-left.png (100%) rename {Greenshot => src/Greenshot}/icons/layer-rotate.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-01.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-02.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-03.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-04.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-05.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-06.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-07.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-08.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-09.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-10.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-11.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-12.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-13.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-14.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-15.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-16.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-17.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-18.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-19.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-20-plus.png (100%) rename {Greenshot => src/Greenshot}/icons/notification-counter-20.png (100%) rename {Greenshot => src/Greenshot}/icons/page_copy.png (100%) rename {Greenshot => src/Greenshot}/icons/palette.png (100%) rename {Greenshot => src/Greenshot}/icons/picture_save.png (100%) rename {Greenshot => src/Greenshot}/icons/picture_saveas.png (100%) rename {Greenshot => src/Greenshot}/icons/picture_to_clipboard.png (100%) rename {Greenshot => src/Greenshot}/icons/pipette.png (100%) rename {Greenshot => src/Greenshot}/icons/printer.png (100%) rename {Greenshot => src/Greenshot}/icons/propertyitemcontainer.gif (100%) rename {Greenshot => src/Greenshot}/icons/redo.png (100%) rename {Greenshot => src/Greenshot}/icons/resize.png (100%) rename {Greenshot => src/Greenshot}/icons/ruler-crop.png (100%) rename {Greenshot => src/Greenshot}/icons/shadow.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_arrow_add.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_arrowheads.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_copy.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_ellipse_add.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_ellipse_delete.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_line.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_paste.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_square_add.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_square_bordercolor.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_square_delete.png (100%) rename {Greenshot => src/Greenshot}/icons/shape_square_fillcolor.png (100%) rename {Greenshot => src/Greenshot}/icons/text_bold.png (100%) rename {Greenshot => src/Greenshot}/icons/text_dropcaps.png (100%) rename {Greenshot => src/Greenshot}/icons/text_italic.png (100%) rename {Greenshot => src/Greenshot}/icons/text_underline.png (100%) rename {Greenshot => src/Greenshot}/icons/textfield_delete.png (100%) rename {Greenshot => src/Greenshot}/icons/undo.png (100%) rename {Greenshot => src/Greenshot}/icons/wand-hat.png (100%) rename {Greenshot => src/Greenshot}/icons/wrench.png (100%) rename {Greenshot => src/Greenshot}/icons/wrench_orange.png (100%) rename {Greenshot => src/Greenshot}/icons/zoom.png (100%) rename {Greenshot => src/Greenshot}/log4net-debug.xml (92%) rename {Greenshot => src/Greenshot}/log4net-portable.xml (100%) rename {Greenshot => src/Greenshot}/log4net-zip.xml (100%) rename {Greenshot => src/Greenshot}/log4net.xml (90%) rename {Greenshot => src/Greenshot}/sounds/camera.wav (100%) rename version.json => src/version.json (96%) diff --git a/Greenshot/App.config b/Greenshot/App.config deleted file mode 100644 index f15ae706e..000000000 --- a/Greenshot/App.config +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/Greenshot/Configuration/EditorConfiguration.cs b/Greenshot/Configuration/EditorConfiguration.cs deleted file mode 100644 index 019ea9ef6..000000000 --- a/Greenshot/Configuration/EditorConfiguration.cs +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.Drawing; - -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces.Drawing; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace Greenshot.Configuration { - /// - /// Description of CoreConfiguration. - /// - [IniSection("Editor", Description="Greenshot editor configuration")] - public class EditorConfiguration : IniSection { - [IniProperty("RecentColors", Separator="|", Description="Last used colors")] - public List RecentColors { get; set; } - - [IniProperty("LastFieldValue", Separator="|", Description="Field values, make sure the last used settings are re-used")] - public Dictionary LastUsedFieldValues { get; set; } - - [IniProperty("MatchSizeToCapture", Description="Match the editor window size to the capture", DefaultValue="True")] - public bool MatchSizeToCapture { get; set; } - [IniProperty("WindowPlacementFlags", Description="Placement flags", DefaultValue="0")] - public WindowPlacementFlags WindowPlacementFlags { get; set; } - [IniProperty("WindowShowCommand", Description="Show command", DefaultValue="Normal")] - public ShowWindowCommand ShowWindowCommand { get; set; } - [IniProperty("WindowMinPosition", Description="Position of minimized window", DefaultValue="-1,-1")] - public Point WindowMinPosition { get; set; } - [IniProperty("WindowMaxPosition", Description="Position of maximized window", DefaultValue="-1,-1")] - public Point WindowMaxPosition { get; set; } - [IniProperty("WindowNormalPosition", Description="Position of normal window", DefaultValue="100,100,400,400")] - public Rectangle WindowNormalPosition { get; set; } - [IniProperty("ReuseEditor", Description = "Reuse already open editor", DefaultValue = "false")] - public bool ReuseEditor { get; set; } - [IniProperty("FreehandSensitivity", Description = "The smaller this number, the less smoothing is used. Decrease for detailed drawing, e.g. when using a pen. Increase for smoother lines. e.g. when you want to draw a smooth line.", DefaultValue = "3")] - public int FreehandSensitivity { get; set; } - [IniProperty("SuppressSaveDialogAtClose", Description="Suppressed the 'do you want to save' dialog when closing the editor.", DefaultValue="False")] - public bool SuppressSaveDialogAtClose { get; set; } - - [IniProperty("DropShadowEffectSettings", Description = "Settings for the drop shadow effect.")] - public DropShadowEffect DropShadowEffectSettings { get; set; } - - [IniProperty("TornEdgeEffectSettings", Description = "Settings for the torn edge effect.")] - public TornEdgeEffect TornEdgeEffectSettings { get; set; } - - public override void AfterLoad() { - base.AfterLoad(); - if (RecentColors == null) { - RecentColors = new List(); - } - } - - /// Type of the class for which to create the field - /// FieldType of the field to construct - /// - /// a new Field of the given fieldType, with the scope of it's value being restricted to the Type scope - public IField CreateField(Type requestingType, IFieldType fieldType, object preferredDefaultValue) - { - string requestingTypeName = requestingType.Name; - string requestedField = requestingTypeName + "." + fieldType.Name; - object fieldValue = preferredDefaultValue; - - // Check if the configuration exists - if (LastUsedFieldValues == null) { - LastUsedFieldValues = new Dictionary(); - } - - // Check if settings for the requesting type exist, if not create! - if (LastUsedFieldValues.ContainsKey(requestedField)) { - // Check if a value is set (not null)! - if (LastUsedFieldValues[requestedField] != null) { - fieldValue = LastUsedFieldValues[requestedField]; - } else { - // Overwrite null value - LastUsedFieldValues[requestedField] = fieldValue; - } - } else { - LastUsedFieldValues.Add(requestedField, fieldValue); - } - return new Field(fieldType, requestingType) - { - Value = fieldValue - }; - } - - public void UpdateLastFieldValue(IField field) - { - string requestedField = field.Scope + "." + field.FieldType.Name; - // Check if the configuration exists - if (LastUsedFieldValues == null) { - LastUsedFieldValues = new Dictionary(); - } - // check if settings for the requesting type exist, if not create! - if (LastUsedFieldValues.ContainsKey(requestedField)) { - LastUsedFieldValues[requestedField] = field.Value; - } else { - LastUsedFieldValues.Add(requestedField, field.Value); - } - } - - public void ResetEditorPlacement() - { - WindowNormalPosition = new Rectangle(100, 100, 400, 400); - WindowMaxPosition = new Point(-1,-1); - WindowMinPosition = new Point(-1, -1); - WindowPlacementFlags = 0; - ShowWindowCommand = ShowWindowCommand.Normal; - } - - public WindowPlacement GetEditorPlacement() { - WindowPlacement placement = WindowPlacement.Default; - placement.NormalPosition = new RECT(WindowNormalPosition); - placement.MaxPosition = new POINT(WindowMaxPosition); - placement.MinPosition = new POINT(WindowMinPosition); - placement.ShowCmd = ShowWindowCommand; - placement.Flags = WindowPlacementFlags; - return placement; - } - - public void SetEditorPlacement(WindowPlacement placement) { - WindowNormalPosition = placement.NormalPosition.ToRectangle(); - WindowMaxPosition = placement.MaxPosition.ToPoint(); - WindowMinPosition = placement.MinPosition.ToPoint(); - ShowWindowCommand = placement.ShowCmd; - WindowPlacementFlags = placement.Flags; - } - } -} diff --git a/Greenshot/Configuration/LanguageKeys.cs b/Greenshot/Configuration/LanguageKeys.cs deleted file mode 100644 index a668218eb..000000000 --- a/Greenshot/Configuration/LanguageKeys.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Configuration { - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum LangKey { - none, - contextmenu_capturefullscreen_all, - contextmenu_capturefullscreen_left, - contextmenu_capturefullscreen_top, - contextmenu_capturefullscreen_right, - contextmenu_capturefullscreen_bottom, - contextmenu_captureie, - editor_clipboardfailed, - editor_close_on_save, - editor_close_on_save_title, - editor_copytoclipboard, - editor_cuttoclipboard, - editor_deleteelement, - editor_downonelevel, - editor_downtobottom, - editor_duplicate, - editor_email, - editor_imagesaved, - editor_title, - editor_uponelevel, - editor_uptotop, - editor_undo, - editor_redo, - editor_resetsize, - error, - error_multipleinstances, - error_openfile, - error_openlink, - error_save, - error_save_invalid_chars, - print_error, - quicksettings_destination_file, - settings_destination, - settings_destination_clipboard, - settings_destination_editor, - settings_destination_fileas, - settings_destination_printer, - settings_destination_picker, - settings_filenamepattern, - settings_message_filenamepattern, - settings_printoptions, - settings_tooltip_filenamepattern, - settings_tooltip_language, - settings_tooltip_primaryimageformat, - settings_tooltip_storagelocation, - settings_visualization, - settings_window_capture_mode, - tooltip_firststart, - warning, - warning_hotkeys, - wait_ie_capture, - update_found - } -} diff --git a/Greenshot/Controls/BindableToolStripDropDownButton.cs b/Greenshot/Controls/BindableToolStripDropDownButton.cs deleted file mode 100644 index 4071d6b81..000000000 --- a/Greenshot/Controls/BindableToolStripDropDownButton.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System.ComponentModel; -using System.Windows.Forms; -using GreenshotPlugin.Controls; - -namespace Greenshot.Controls { - /// - /// A simple ToolStripDropDownButton implementing INotifyPropertyChanged for data binding. - /// Also, when a DropDownItem is selected, the DropDownButton adopts its Tag and Image. - /// The selected tag can be accessed via SelectedTag property. - /// - public class BindableToolStripDropDownButton : ToolStripDropDownButton, INotifyPropertyChanged, IGreenshotLanguageBindable { - - public event PropertyChangedEventHandler PropertyChanged; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - - public object SelectedTag { - get { if(Tag==null && DropDownItems.Count>0) Tag=DropDownItems[0].Tag; return Tag; } - set { AdoptFromTag(value); } - } - - protected override void OnDropDownItemClicked(ToolStripItemClickedEventArgs e) { - ToolStripItem clickedItem = e.ClickedItem; - if(Tag == null || !Tag.Equals(clickedItem.Tag)) { - Tag = clickedItem.Tag; - Image = clickedItem.Image; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag")); - } - base.OnDropDownItemClicked(e); - } - - private void AdoptFromTag(object tag) { - if(Tag == null || !Tag.Equals(tag)) { - Tag = tag; - foreach(ToolStripItem item in DropDownItems) { - if(item.Tag != null && item.Tag.Equals(tag)) { - Image = item.Image; - break; - } - } - Tag = tag; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag")); - } - } - } -} diff --git a/Greenshot/Controls/ColorButton.cs b/Greenshot/Controls/ColorButton.cs deleted file mode 100644 index fe31d2e11..000000000 --- a/Greenshot/Controls/ColorButton.cs +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Controls; -using ColorDialog = Greenshot.Forms.ColorDialog; - -namespace Greenshot.Controls { - /// - /// Description of ColorButton. - /// - public class ColorButton : Button, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; - private Color _selectedColor = Color.White; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - - public ColorButton() { - Click += ColorButtonClick; - } - - public Color SelectedColor { - get {return _selectedColor;} - set { - _selectedColor = value; - - Brush brush; - if(value != Color.Transparent) { - brush = new SolidBrush(value); - } else { - brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray); - } - - if (Image != null) - { - using Graphics graphics = Graphics.FromImage(Image); - graphics.FillRectangle(brush, new Rectangle(4,17,16,3)); - } - - // cleanup GDI Object - brush.Dispose(); - Invalidate(); - } - } - - private void ColorButtonClick(object sender, EventArgs e) { - var colorDialog = new ColorDialog - { - Color = SelectedColor - }; - // Using the parent to make sure the dialog doesn't show on another window - colorDialog.ShowDialog(Parent.Parent); - if (colorDialog.DialogResult == DialogResult.Cancel) - { - return; - } - if (colorDialog.Color.Equals(SelectedColor)) - { - return; - } - SelectedColor = colorDialog.Color; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor")); - } - } -} diff --git a/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs b/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs deleted file mode 100644 index e5ebf5478..000000000 --- a/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.Core; -using System.Drawing; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; - -namespace Greenshot.Controls { - /// - /// ToolStripProfessionalRenderer which draws the Check correctly when the icons are larger - /// - public class ContextMenuToolStripProfessionalRenderer : ToolStripProfessionalRenderer { - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static Image _scaledCheckbox; - - protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) { - if (_scaledCheckbox == null || _scaledCheckbox.Size != CoreConfig.ScaledIconSize) { - _scaledCheckbox?.Dispose(); - _scaledCheckbox = ImageHelper.ResizeImage(e.Image, true, CoreConfig.ScaledIconSize.Width, CoreConfig.ScaledIconSize.Height, null); - } - Rectangle old = e.ImageRectangle; - ToolStripItemImageRenderEventArgs clone = new ToolStripItemImageRenderEventArgs(e.Graphics, e.Item, _scaledCheckbox, new Rectangle(old.X, 0, old.Width, old.Height)); - base.OnRenderItemCheck(clone); - } - } -} diff --git a/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs b/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs deleted file mode 100644 index d559d771b..000000000 --- a/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Windows.Forms; - -namespace Greenshot.Controls { - /// - /// Prevent having a gradient background in the toolstrip, and the overflow button - /// See: http://stackoverflow.com/a/16926979 - /// - internal class CustomProfessionalColorTable : ProfessionalColorTable { - public override Color ToolStripGradientBegin { - get { return SystemColors.Control; } - } - public override Color ToolStripGradientMiddle { - get { return SystemColors.Control; } - } - public override Color ToolStripGradientEnd { - get { return SystemColors.Control; } - } - public override Color OverflowButtonGradientBegin { - get { return SystemColors.Control; } - } - public override Color OverflowButtonGradientMiddle { - get { return SystemColors.Control; } - } - public override Color OverflowButtonGradientEnd { - get { return SystemColors.Control; } - } - } - - /// - /// ToolStripProfessionalRenderer without having a visual artifact - /// See: http://stackoverflow.com/a/16926979 and http://stackoverflow.com/a/13418840 - /// - public class CustomToolStripProfessionalRenderer : ToolStripProfessionalRenderer { - public CustomToolStripProfessionalRenderer() : base(new CustomProfessionalColorTable()) { - RoundedEdges = false; - } - /// - /// By overriding the OnRenderToolStripBorder we can make the ToolStrip without border - /// - /// - protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) { - // Don't draw a border - } - } -} diff --git a/Greenshot/Controls/FontFamilyComboBox.cs b/Greenshot/Controls/FontFamilyComboBox.cs deleted file mode 100644 index d37244eab..000000000 --- a/Greenshot/Controls/FontFamilyComboBox.cs +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.ComponentModel; -using System.Drawing; -using System.Windows.Forms; - -namespace Greenshot.Controls { - /// - /// ToolStripComboBox containing installed font families, - /// implementing INotifyPropertyChanged for data binding - /// - public class FontFamilyComboBox : ToolStripComboBox, INotifyPropertyChanged { - public event PropertyChangedEventHandler PropertyChanged; - - public FontFamily FontFamily { - get { return (FontFamily)SelectedItem; } - set { - if (!SelectedItem.Equals(value)) { - SelectedItem = value; - } - } - } - - public FontFamilyComboBox() - { - if (ComboBox != null) - { - ComboBox.DataSource = FontFamily.Families; - ComboBox.DisplayMember = "Name"; - SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged; - ComboBox.DrawMode = DrawMode.OwnerDrawFixed; - ComboBox.DrawItem += ComboBox_DrawItem; - } - } - - private void ComboBox_DrawItem(object sender, DrawItemEventArgs e) { - // DrawBackground handles drawing the background (i.e,. hot-tracked v. not) - // It uses the system colors (Bluish, and and white, by default) - // same as calling e.Graphics.FillRectangle ( SystemBrushes.Highlight, e.Bounds ); - e.DrawBackground(); - - if (e.Index > -1) { - FontFamily fontFamily = Items[e.Index] as FontFamily; - FontStyle fontStyle = FontStyle.Regular; - if (fontFamily != null && !fontFamily.IsStyleAvailable(FontStyle.Regular)) { - if (fontFamily.IsStyleAvailable(FontStyle.Bold)) { - fontStyle = FontStyle.Bold; - } else if (fontFamily.IsStyleAvailable(FontStyle.Italic)) { - fontStyle = FontStyle.Italic; - } else if (fontFamily.IsStyleAvailable(FontStyle.Strikeout)) { - fontStyle = FontStyle.Strikeout; - } else if (fontFamily.IsStyleAvailable(FontStyle.Underline)) { - fontStyle = FontStyle.Underline; - } - } - try { - if (fontFamily != null) - { - DrawText(e.Graphics, fontFamily, fontStyle, e.Bounds, fontFamily.Name); - } - } catch { - // If the drawing failed, BUG-1770 seems to have a weird case that causes: Font 'Lucida Sans Typewriter' does not support style 'Regular' - if (fontFamily != null) - { - DrawText(e.Graphics, FontFamily.GenericSansSerif, FontStyle.Regular, e.Bounds, fontFamily.Name); - } - } - } - // Uncomment this if you actually like the way the focus rectangle looks - //e.DrawFocusRectangle (); - } - - /// - /// Helper method to draw the string - /// - /// - /// - /// - /// - /// - private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, Rectangle bounds, string text) - { - using Font font = new Font(fontFamily, Font.Size + 5, fontStyle, GraphicsUnit.Pixel); - // Make sure the text is visible by centering it in the line - using StringFormat stringFormat = new StringFormat - { - LineAlignment = StringAlignment.Center - }; - graphics.DrawString(text, font, Brushes.Black, bounds, stringFormat); - } - - private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) { - if (PropertyChanged == null) return; - PropertyChanged(this, new PropertyChangedEventArgs("Text")); - PropertyChanged(this, new PropertyChangedEventArgs("FontFamily")); - PropertyChanged(this, new PropertyChangedEventArgs("SelectedIndex")); - PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem")); - } - } -} diff --git a/Greenshot/Controls/MenuStripEx.cs b/Greenshot/Controls/MenuStripEx.cs deleted file mode 100644 index 7dda22931..000000000 --- a/Greenshot/Controls/MenuStripEx.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Windows.Forms; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace Greenshot.Controls { - /// - /// This is an extension of the default MenuStrip and allows us to click it even when the form doesn't have focus. - /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx - /// - public class MenuStripEx : MenuStrip { - private enum NativeConstants : uint { - MA_ACTIVATE = 1, - MA_ACTIVATEANDEAT = 2, - } - - private bool _clickThrough; - /// - /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus. - /// - /// - /// Default value is false, which is the same behavior provided by the base ToolStrip class. - /// - public bool ClickThrough { - get { - return _clickThrough; - } - - set { - _clickThrough = value; - } - } - - protected override void WndProc(ref Message m) { - base.WndProc(ref m); - var windowsMessage = (WindowsMessages) m.Msg; - if (_clickThrough && windowsMessage == WindowsMessages.WM_MOUSEACTIVATE && m.Result == (IntPtr)NativeConstants.MA_ACTIVATEANDEAT) - { - m.Result = (IntPtr)NativeConstants.MA_ACTIVATE; - } - } - } -} diff --git a/Greenshot/Controls/Pipette.cs b/Greenshot/Controls/Pipette.cs deleted file mode 100644 index ca7333d81..000000000 --- a/Greenshot/Controls/Pipette.cs +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -using System.Drawing; -using System.Windows.Forms; -using Greenshot.Forms; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using ColorDialog = Greenshot.Forms.ColorDialog; - -namespace Greenshot.Controls { - /// - /// This code was supplied by Hi-Coder as a patch for Greenshot - /// Needed some modifications to be stable. - /// - public sealed class Pipette : Label, IMessageFilter, IDisposable { - private MovableShowColorForm _movableShowColorForm; - private bool _dragging; - private Cursor _cursor; - private readonly Bitmap _image; - private const int VkEsc = 27; - - public event EventHandler PipetteUsed; - - public Pipette() { - BorderStyle = BorderStyle.FixedSingle; - _dragging = false; - _image = (Bitmap)new ComponentResourceManager(typeof(ColorDialog)).GetObject("pipette.Image"); - Image = _image; - _cursor = CreateCursor(_image, 1, 14); - _movableShowColorForm = new MovableShowColorForm(); - Application.AddMessageFilter(this); - } - - /// - /// Create a cursor from the supplied bitmap & hotspot coordinates - /// - /// Bitmap to create an icon from - /// Hotspot X coordinate - /// Hotspot Y coordinate - /// Cursor - private static Cursor CreateCursor(Bitmap bitmap, int hotspotX, int hotspotY) - { - using SafeIconHandle iconHandle = new SafeIconHandle( bitmap.GetHicon()); - User32.GetIconInfo(iconHandle, out var iconInfo); - iconInfo.xHotspot = hotspotX; - iconInfo.yHotspot = hotspotY; - iconInfo.fIcon = false; - var icon = User32.CreateIconIndirect(ref iconInfo); - return new Cursor(icon); - } - - /// - /// The bulk of the clean-up code is implemented in Dispose(bool) - /// - public new void Dispose() { - Dispose(true); - } - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// - /// When disposing==true all non-managed resources should be freed too! - protected override void Dispose(bool disposing) { - if (disposing) { - if (_cursor != null) { - _cursor.Dispose(); - } - _movableShowColorForm?.Dispose(); - } - _movableShowColorForm = null; - _cursor = null; - base.Dispose(disposing); - } - - /// - /// Handle the mouse down on the Pipette "label", we take the capture and move the zoomer to the current location - /// - /// MouseEventArgs - protected override void OnMouseDown(MouseEventArgs e) { - if (e.Button == MouseButtons.Left) { - User32.SetCapture(Handle); - _movableShowColorForm.MoveTo(PointToScreen(new Point(e.X, e.Y))); - } - base.OnMouseDown(e); - } - - /// - /// Handle the mouse up on the Pipette "label", we release the capture and fire the PipetteUsed event - /// - /// MouseEventArgs - protected override void OnMouseUp(MouseEventArgs e) { - if (e.Button == MouseButtons.Left) - { - //Release Capture should consume MouseUp when canceled with the escape key - User32.ReleaseCapture(); - PipetteUsed?.Invoke(this, new PipetteUsedArgs(_movableShowColorForm.color)); - } - base.OnMouseUp(e); - } - - /// - /// Handle the mouse Move event, we move the ColorUnderCursor to the current location. - /// - /// MouseEventArgs - protected override void OnMouseMove(MouseEventArgs e) { - if (_dragging) { - //display the form on the right side of the cursor by default; - Point zp = PointToScreen(new Point(e.X, e.Y)); - _movableShowColorForm.MoveTo(zp); - } - base.OnMouseMove(e); - } - - /// - /// Handle the MouseCaptureChanged event - /// - /// - protected override void OnMouseCaptureChanged(EventArgs e) { - if (Capture) { - _dragging = true; - Image = null; - Cursor c = _cursor; - Cursor = c; - _movableShowColorForm.Visible = true; - } else { - _dragging = false; - Image = _image; - Cursor = Cursors.Arrow; - _movableShowColorForm.Visible = false; - } - Update(); - base.OnMouseCaptureChanged(e); - } - - public bool PreFilterMessage(ref Message m) { - if (_dragging) { - if (m.Msg == (int)WindowsMessages.WM_CHAR) { - if ((int)m.WParam == VkEsc) { - User32.ReleaseCapture(); - } - } - } - return false; - } - } - - public class PipetteUsedArgs : EventArgs { - public Color Color; - - public PipetteUsedArgs(Color c) { - Color = c; - } - } -} diff --git a/Greenshot/Controls/ToolStripColorButton.cs b/Greenshot/Controls/ToolStripColorButton.cs deleted file mode 100644 index 951e117fd..000000000 --- a/Greenshot/Controls/ToolStripColorButton.cs +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Controls; -using ColorDialog = Greenshot.Forms.ColorDialog; - -namespace Greenshot.Controls { - public class ToolStripColorButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - - private Color _selectedColor = Color.Transparent; - - public ToolStripColorButton() { - Click+= ColorButtonClick; - } - - public Color SelectedColor { - get {return _selectedColor;} - set { - _selectedColor = value; - - Brush brush; - if(value != Color.Transparent) { - brush = new SolidBrush(value); - } else { - brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray); - } - - if (Image != null) - { - using Graphics graphics = Graphics.FromImage(Image); - graphics.FillRectangle(brush, new Rectangle(0,13,16,3)); - } - - // cleanup GDI Object - brush.Dispose(); - Invalidate(); - } - } - - private void ColorButtonClick(object sender, EventArgs e) { - var colorDialog = new ColorDialog - { - Color = SelectedColor - }; - // Using the parent to make sure the dialog doesn't show on another window - colorDialog.ShowDialog(Parent.Parent); - if (colorDialog.DialogResult == DialogResult.Cancel) - { - return; - } - if (colorDialog.Color.Equals(SelectedColor)) - { - return; - } - SelectedColor = colorDialog.Color; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor")); - } - } -} diff --git a/Greenshot/Controls/ToolStripEx.cs b/Greenshot/Controls/ToolStripEx.cs deleted file mode 100644 index 7d2ca63ed..000000000 --- a/Greenshot/Controls/ToolStripEx.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Windows.Forms; - -namespace Greenshot.Controls { - /// - /// This is an extension of the default ToolStrip and allows us to click it even when the form doesn't have focus. - /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx - /// - internal class ToolStripEx : ToolStrip { - private const int WM_MOUSEACTIVATE = 0x21; - - private enum NativeConstants : uint { - MA_ACTIVATE = 1, - MA_ACTIVATEANDEAT = 2, - } - - private bool _clickThrough; - /// - /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus. - /// - /// - /// Default value is false, which is the same behavior provided by the base ToolStrip class. - /// - - public bool ClickThrough { - get { - return _clickThrough; - } - - set { - _clickThrough = value; - } - } - - protected override void WndProc(ref Message m) { - base.WndProc(ref m); - if (_clickThrough && m.Msg == WM_MOUSEACTIVATE && m.Result == (IntPtr)NativeConstants.MA_ACTIVATEANDEAT) { - m.Result = (IntPtr)NativeConstants.MA_ACTIVATE; - } - } - } -} diff --git a/Greenshot/Controls/ToolStripNumericUpDown.cs b/Greenshot/Controls/ToolStripNumericUpDown.cs deleted file mode 100644 index 13652fc41..000000000 --- a/Greenshot/Controls/ToolStripNumericUpDown.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -using System.Windows.Forms; -using System.Windows.Forms.Design; - -namespace Greenshot.Controls { - - [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)] - public class ToolStripNumericUpDown : ToolStripControlHost, INotifyPropertyChanged - { - public event PropertyChangedEventHandler PropertyChanged; - - public ToolStripNumericUpDown() : base(new NumericUpDown()) - { - } - - public NumericUpDown NumericUpDown => Control as NumericUpDown; - - public decimal Value - { - get { return NumericUpDown.Value; } - set { NumericUpDown.Value = value;} - } - public decimal Minimum { - get { return NumericUpDown.Minimum; } - set { NumericUpDown.Minimum = value; } - } - - public decimal Maximum { - get { return NumericUpDown.Maximum; } - set { NumericUpDown.Maximum = value; } - } - - public decimal Increment { - get { return NumericUpDown.Increment; } - set { NumericUpDown.Increment = value; } - } - - public int DecimalPlaces { - get { return NumericUpDown.DecimalPlaces; } - set { NumericUpDown.DecimalPlaces = value; } - } - - - protected override void OnSubscribeControlEvents(Control control) { - base.OnSubscribeControlEvents(control); - NumericUpDown.ValueChanged += _valueChanged; - } - protected override void OnUnsubscribeControlEvents(Control control) { - base.OnUnsubscribeControlEvents(control); - NumericUpDown.ValueChanged -= _valueChanged; - } - - private void _valueChanged(object sender, EventArgs e) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); - } - } -} diff --git a/Greenshot/Destinations/ClipboardDestination.cs b/Greenshot/Destinations/ClipboardDestination.cs deleted file mode 100644 index a1172ede4..000000000 --- a/Greenshot/Destinations/ClipboardDestination.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// Description of ClipboardDestination. - /// - public class ClipboardDestination : AbstractDestination { - public const string DESIGNATION = "Clipboard"; - - public override string Designation { - get { - return DESIGNATION; - } - } - - public override string Description { - get { - return Language.GetString(LangKey.settings_destination_clipboard); - } - } - public override int Priority { - get { - return 2; - } - } - - public override Keys EditorShortcutKeys { - get { - return Keys.Control | Keys.Shift | Keys.C; - } - } - - public override Image DisplayIcon { - get { - return GreenshotResources.GetImage("Clipboard.Image"); - } - } - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - try { - ClipboardHelper.SetClipboardData(surface); - exportInformation.ExportMade = true; - } catch (Exception) { - // TODO: Change to general logic in ProcessExport - surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetString(LangKey.editor_clipboardfailed)); - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} diff --git a/Greenshot/Destinations/EditorDestination.cs b/Greenshot/Destinations/EditorDestination.cs deleted file mode 100644 index 220359238..000000000 --- a/Greenshot/Destinations/EditorDestination.cs +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.Drawing; -using Greenshot.Configuration; -using Greenshot.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Forms; -using log4net; - -namespace Greenshot.Destinations { - /// - /// Description of EditorDestination. - /// - public class EditorDestination : AbstractDestination { - private static readonly ILog LOG = LogManager.GetLogger(typeof(EditorDestination)); - private static readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection(); - public const string DESIGNATION = "Editor"; - private readonly IImageEditor editor; - private static readonly Image greenshotIcon = GreenshotResources.GetGreenshotIcon().ToBitmap(); - - public EditorDestination() - { - // Do not remove, is needed for the framework - } - - public EditorDestination(IImageEditor editor) { - this.editor = editor; - } - - public override string Designation => DESIGNATION; - - public override string Description { - get { - if (editor == null) { - return Language.GetString(LangKey.settings_destination_editor); - } - return Language.GetString(LangKey.settings_destination_editor) + " - " + editor.CaptureDetails.Title; - } - } - - public override int Priority => 1; - - public override bool IsDynamic => true; - - public override Image DisplayIcon => greenshotIcon; - - public override IEnumerable DynamicDestinations() { - foreach (IImageEditor someEditor in ImageEditorForm.Editors) { - yield return new EditorDestination(someEditor); - } - } - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - // Make sure we collect the garbage before opening the screenshot - GC.Collect(); - GC.WaitForPendingFinalizers(); - - bool modified = surface.Modified; - if (editor == null) { - if (editorConfiguration.ReuseEditor) { - foreach(IImageEditor openedEditor in ImageEditorForm.Editors) { - if (openedEditor.Surface.Modified) continue; - - openedEditor.Surface = surface; - exportInformation.ExportMade = true; - break; - } - } - if (!exportInformation.ExportMade) { - try { - ImageEditorForm editorForm = new ImageEditorForm(surface, !surface.Modified); // Output made?? - - if (!string.IsNullOrEmpty(captureDetails.Filename)) { - editorForm.SetImagePath(captureDetails.Filename); - } - editorForm.Show(); - editorForm.Activate(); - LOG.Debug("Finished opening Editor"); - exportInformation.ExportMade = true; - } catch (Exception e) { - LOG.Error(e); - exportInformation.ErrorMessage = e.Message; - } - } - } else { - try { - using (Image image = surface.GetImageForExport()) { - editor.Surface.AddImageContainer(image, 10, 10); - } - exportInformation.ExportMade = true; - } catch (Exception e) { - LOG.Error(e); - exportInformation.ErrorMessage = e.Message; - } - } - ProcessExport(exportInformation, surface); - // Workaround for the modified flag when using the editor. - surface.Modified = modified; - return exportInformation; - } - } -} diff --git a/Greenshot/Destinations/EmailDestination.cs b/Greenshot/Destinations/EmailDestination.cs deleted file mode 100644 index 326e27e9c..000000000 --- a/Greenshot/Destinations/EmailDestination.cs +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Windows.Forms; - -using Greenshot.Configuration; -using Greenshot.Helpers; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using Microsoft.Win32; - -namespace Greenshot.Destinations { - /// - /// Description of EmailDestination. - /// - public class EmailDestination : AbstractDestination { - private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); - private static bool _isActiveFlag; - private static string _mapiClient; - public const string DESIGNATION = "EMail"; - - static EmailDestination() { - // Logic to decide what email implementation we use - _mapiClient = RegistryHive.LocalMachine.ReadKey64Or32(@"Clients\Mail"); - if (!string.IsNullOrEmpty(_mapiClient)) { - // Active as we have a MAPI client, can be disabled later - _isActiveFlag = true; - } - } - - public override string Designation => DESIGNATION; - - public override string Description { - get - { - // Make sure there is some kind of "mail" name - return _mapiClient ??= Language.GetString(LangKey.editor_email); - } - } - - public override int Priority => 3; - - public override bool IsActive { - get { - if (_isActiveFlag) { - // Disable if the office plugin is installed and the client is outlook - // TODO: Change this! It always creates an exception, as the plugin has not been loaded the type is not there :( - var outlookDestination = Type.GetType("GreenshotOfficePlugin.OutlookDestination,GreenshotOfficePlugin", false); - if (outlookDestination != null && _mapiClient.ToLower().Contains("microsoft outlook")) { - _isActiveFlag = false; - } - } - return base.IsActive && _isActiveFlag; - } - } - - public override Keys EditorShortcutKeys => Keys.Control | Keys.E; - - public override Image DisplayIcon => MailIcon; - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - MapiMailMessage.SendImage(surface, captureDetails); - exportInformation.ExportMade = true; - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} \ No newline at end of file diff --git a/Greenshot/Destinations/FileDestination.cs b/Greenshot/Destinations/FileDestination.cs deleted file mode 100644 index d6e89c0d5..000000000 --- a/Greenshot/Destinations/FileDestination.cs +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.IO; -using System.Windows.Forms; - -using Greenshot.Configuration; -using Greenshot.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Controls; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; -using log4net; - -namespace Greenshot.Destinations { - /// - /// Description of FileSaveAsDestination. - /// - public class FileDestination : AbstractDestination { - private static readonly ILog Log = LogManager.GetLogger(typeof(FileDestination)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - public const string DESIGNATION = "FileNoDialog"; - - public override string Designation => DESIGNATION; - - public override string Description => Language.GetString(LangKey.quicksettings_destination_file); - - public override int Priority => 0; - - public override Keys EditorShortcutKeys => Keys.Control | Keys.S; - - public override Image DisplayIcon => GreenshotResources.GetImage("Save.Image"); - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - bool outputMade; - bool overwrite; - string fullPath; - // Get output settings from the configuration - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); - - if (captureDetails?.Filename != null) { - // As we save a pre-selected file, allow to overwrite. - overwrite = true; - Log.InfoFormat("Using previous filename"); - fullPath = captureDetails.Filename; - outputSettings.Format = ImageOutput.FormatForFilename(fullPath); - } else { - fullPath = CreateNewFilename(captureDetails); - // As we generate a file, the configuration tells us if we allow to overwrite - overwrite = CoreConfig.OutputFileAllowOverwrite; - } - if (CoreConfig.OutputFilePromptQuality) { - QualityDialog qualityDialog = new QualityDialog(outputSettings); - qualityDialog.ShowDialog(); - } - - // Catching any exception to prevent that the user can't write in the directory. - // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 - try { - ImageOutput.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); - outputMade = true; - } catch (ArgumentException ex1) { - // Our generated filename exists, display 'save-as' - Log.InfoFormat("Not overwriting: {0}", ex1.Message); - // when we don't allow to overwrite present a new SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); - outputMade = fullPath != null; - } catch (Exception ex2) { - Log.Error("Error saving screenshot!", ex2); - // Show the problem - MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error)); - // when save failed we present a SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); - outputMade = fullPath != null; - } - // Don't overwrite filename if no output is made - if (outputMade) { - exportInformation.ExportMade = true; - exportInformation.Filepath = fullPath; - if (captureDetails != null) - { - captureDetails.Filename = fullPath; - } - CoreConfig.OutputFileAsFullpath = fullPath; - } - - ProcessExport(exportInformation, surface); - return exportInformation; - } - - private static string CreateNewFilename(ICaptureDetails captureDetails) { - string fullPath; - Log.InfoFormat("Creating new filename"); - string pattern = CoreConfig.OutputFileFilenamePattern; - if (string.IsNullOrEmpty(pattern)) { - pattern = "greenshot ${capturetime}"; - } - string filename = FilenameHelper.GetFilenameFromPattern(pattern, CoreConfig.OutputFileFormat, captureDetails); - CoreConfig.ValidateAndCorrectOutputFilePath(); - string filepath = FilenameHelper.FillVariables(CoreConfig.OutputFilePath, false); - try { - fullPath = Path.Combine(filepath, filename); - } catch (ArgumentException) { - // configured filename or path not valid, show error message... - Log.InfoFormat("Generated path or filename not valid: {0}, {1}", filepath, filename); - - MessageBox.Show(Language.GetString(LangKey.error_save_invalid_chars), Language.GetString(LangKey.error)); - // ... lets get the pattern fixed.... - var dialogResult = new SettingsForm().ShowDialog(); - if (dialogResult == DialogResult.OK) { - // ... OK -> then try again: - fullPath = CreateNewFilename(captureDetails); - } else { - // ... cancelled. - fullPath = null; - } - - } - return fullPath; - } - } -} diff --git a/Greenshot/Destinations/FileWithDialogDestination.cs b/Greenshot/Destinations/FileWithDialogDestination.cs deleted file mode 100644 index b378f5f34..000000000 --- a/Greenshot/Destinations/FileWithDialogDestination.cs +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// Description of FileWithDialog. - /// - public class FileWithDialogDestination : AbstractDestination { - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - public const string DESIGNATION = "FileDialog"; - - public override string Designation { - get { - return DESIGNATION; - } - } - - public override string Description { - get { - return Language.GetString(LangKey.settings_destination_fileas); - } - } - - public override int Priority { - get { - return 0; - } - } - - public override Keys EditorShortcutKeys { - get { - return Keys.Control | Keys.Shift | Keys.S; - } - } - - public override Image DisplayIcon { - get { - return GreenshotResources.GetImage("Save.Image"); - } - } - - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - // Bug #2918756 don't overwrite path if SaveWithDialog returns null! - var savedTo = ImageOutput.SaveWithDialog(surface, captureDetails); - if (savedTo != null) { - exportInformation.ExportMade = true; - exportInformation.Filepath = savedTo; - captureDetails.Filename = savedTo; - conf.OutputFileAsFullpath = savedTo; - } - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} diff --git a/Greenshot/Destinations/PickerDestination.cs b/Greenshot/Destinations/PickerDestination.cs deleted file mode 100644 index e7ea94c83..000000000 --- a/Greenshot/Destinations/PickerDestination.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Collections.Generic; -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// The PickerDestination shows a context menu with all possible destinations, so the user can "pick" one - /// - public class PickerDestination : AbstractDestination { - public const string DESIGNATION = "Picker"; - - public override string Designation => DESIGNATION; - - public override string Description => Language.GetString(LangKey.settings_destination_picker); - - public override int Priority => 1; - - - /// - /// Export the capture with the destination picker - /// - /// Did the user select this destination? - /// Surface to export - /// Details of the capture - /// true if export was made - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - List destinations = new List(); - - foreach(var destination in SimpleServiceProvider.Current.GetAllInstances()) { - if ("Picker".Equals(destination.Designation)) { - continue; - } - if (!destination.IsActive) { - continue; - } - destinations.Add(destination); - } - - // No Processing, this is done in the selected destination (if anything was selected) - return ShowPickerMenu(true, surface, captureDetails, destinations); - } - } -} diff --git a/Greenshot/Destinations/PrinterDestination.cs b/Greenshot/Destinations/PrinterDestination.cs deleted file mode 100644 index 3a45268e2..000000000 --- a/Greenshot/Destinations/PrinterDestination.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Printing; -using System.Windows.Forms; - -using Greenshot.Configuration; -using GreenshotPlugin.Core; -using Greenshot.Helpers; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Destinations { - /// - /// Description of PrinterDestination. - /// - public class PrinterDestination : AbstractDestination { - public const string DESIGNATION = "Printer"; - private readonly string _printerName; - - public PrinterDestination() { - } - - public PrinterDestination(string printerName) { - _printerName = printerName; - } - public override string Designation => DESIGNATION; - - public override string Description { - get { - if (_printerName != null) { - return Language.GetString(LangKey.settings_destination_printer) + " - " + _printerName; - } - return Language.GetString(LangKey.settings_destination_printer); - } - } - - public override int Priority => 2; - - public override Keys EditorShortcutKeys => Keys.Control | Keys.P; - - public override Image DisplayIcon => GreenshotResources.GetImage("Printer.Image"); - - public override bool IsDynamic => true; - - /// - /// Create destinations for all the installed printers - /// - /// IEnumerable of IDestination - public override IEnumerable DynamicDestinations() { - PrinterSettings settings = new PrinterSettings(); - string defaultPrinter = settings.PrinterName; - List printers = new List(); - - foreach (string printer in PrinterSettings.InstalledPrinters) { - printers.Add(printer); - } - printers.Sort(delegate(string p1, string p2) { - if(defaultPrinter.Equals(p1)) { - return -1; - } - if(defaultPrinter.Equals(p2)) { - return 1; - } - return string.Compare(p1, p2, StringComparison.Ordinal); - }); - foreach(string printer in printers) { - yield return new PrinterDestination(printer); - } - } - - /// - /// Export the capture to the printer - /// - /// - /// - /// - /// ExportInformation - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); - PrinterSettings printerSettings; - if (!string.IsNullOrEmpty(_printerName)) - { - using PrintHelper printHelper = new PrintHelper(surface, captureDetails); - printerSettings = printHelper.PrintTo(_printerName); - } else if (!manuallyInitiated) { - PrinterSettings settings = new PrinterSettings(); - using PrintHelper printHelper = new PrintHelper(surface, captureDetails); - printerSettings = printHelper.PrintTo(settings.PrinterName); - } else - { - using PrintHelper printHelper = new PrintHelper(surface, captureDetails); - printerSettings = printHelper.PrintWithDialog(); - } - if (printerSettings != null) { - exportInformation.ExportMade = true; - } - - ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} diff --git a/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/Greenshot/Drawing/Adorners/AbstractAdorner.cs deleted file mode 100644 index 5461b4df4..000000000 --- a/Greenshot/Drawing/Adorners/AbstractAdorner.cs +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; -using GreenshotPlugin.Interfaces.Drawing.Adorners; - -namespace Greenshot.Drawing.Adorners -{ - public class AbstractAdorner : IAdorner - { - public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE; - - private static readonly Size DefaultSize = new Size(6, 6); - protected Size _size; - - public AbstractAdorner(IDrawableContainer owner) - { - _size = DpiHelper.ScaleWithDpi(DefaultSize, 0); - Owner = owner; - } - - /// - /// Returns the cursor for when the mouse is over the adorner - /// - public virtual Cursor Cursor - { - get - { - return Cursors.SizeAll; - } - } - - public virtual IDrawableContainer Owner - { - get; - set; - } - - /// - /// Test if the point is inside the adorner - /// - /// - /// - public virtual bool HitTest(Point point) - { - Rectangle hitBounds = Bounds; - hitBounds.Inflate(3, 3); - return hitBounds.Contains(point); - } - - /// - /// Handle the mouse down - /// - /// - /// - public virtual void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - } - - /// - /// Handle the mouse move - /// - /// - /// - public virtual void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - } - - /// - /// Handle the mouse up - /// - /// - /// - public virtual void MouseUp(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.IDLE; - } - - /// - /// Return the location of the adorner - /// - public virtual Point Location - { - get; - set; - } - - /// - /// Return the bounds of the Adorner - /// - public virtual Rectangle Bounds - { - get - { - Point location = Location; - return new Rectangle(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height); - } - } - - /// - /// Return the bounds of the Adorner as displayed on the parent Surface - /// - protected virtual Rectangle BoundsOnSurface - { - get - { - Point displayLocation = Owner.Parent.ToSurfaceCoordinates(Location); - return new Rectangle(displayLocation.X - _size.Width / 2, displayLocation.Y - _size.Height / 2, _size.Width, _size.Height); - } - } - - /// - /// The adorner is active if the edit status is not idle or undrawn - /// - public virtual bool IsActive - { - get - { - return EditStatus != EditStatus.IDLE && EditStatus != EditStatus.UNDRAWN; - } - } - - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// uint - public void AdjustToDpi(uint dpi) - { - _size = DpiHelper.ScaleWithDpi(DefaultSize, dpi); - } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public virtual void Paint(PaintEventArgs paintEventArgs) - { - } - - /// - /// We ignore the Transform, as the coordinates are directly bound to those of the owner - /// - /// - public virtual void Transform(Matrix matrix) - { - } - } -} diff --git a/Greenshot/Drawing/Adorners/MoveAdorner.cs b/Greenshot/Drawing/Adorners/MoveAdorner.cs deleted file mode 100644 index c8ef3ea22..000000000 --- a/Greenshot/Drawing/Adorners/MoveAdorner.cs +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Helpers; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Adorners -{ - /// - /// This is the adorner for the line based containers - /// - public class MoveAdorner : AbstractAdorner - { - private Rectangle _boundsBeforeResize = Rectangle.Empty; - private RectangleF _boundsAfterResize = RectangleF.Empty; - - public Positions Position { get; private set; } - - public MoveAdorner(IDrawableContainer owner, Positions position) : base(owner) - { - Position = position; - } - - /// - /// Returns the cursor for when the mouse is over the adorner - /// - public override Cursor Cursor => Cursors.SizeAll; - - /// - /// Handle the mouse down - /// - /// - /// - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.RESIZING; - _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); - _boundsAfterResize = _boundsBeforeResize; - } - - /// - /// Handle the mouse move - /// - /// - /// - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.RESIZING) - { - return; - } - Owner.Invalidate(); - Owner.MakeBoundsChangeUndoable(false); - - // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.X; - _boundsAfterResize.Y = _boundsBeforeResize.Y; - _boundsAfterResize.Width = _boundsBeforeResize.Width; - _boundsAfterResize.Height = _boundsBeforeResize.Height; - - // calculate scaled rectangle - ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); - - // apply scaled bounds to this DrawableContainer - Owner.ApplyBounds(_boundsAfterResize); - - Owner.Invalidate(); - } - - /// - /// Return the location of the adorner - /// - public override Point Location { - get - { - int x = 0,y = 0; - switch (Position) - { - case Positions.TopLeft: - x = Owner.Left; - y = Owner.Top; - break; - case Positions.BottomLeft: - x = Owner.Left; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleLeft: - x = Owner.Left; - y = Owner.Top + (Owner.Height / 2); - break; - case Positions.TopCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top; - break; - case Positions.BottomCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top + Owner.Height; - break; - case Positions.TopRight: - x = Owner.Left + Owner.Width; - y = Owner.Top; - break; - case Positions.BottomRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + (Owner.Height / 2); - break; - } - return new Point(x, y); - } - } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = BoundsOnSurface; - GraphicsState state = targetGraphics.Save(); - - targetGraphics.CompositingMode = CompositingMode.SourceCopy; - - try - { - targetGraphics.FillRectangle(Brushes.Black, bounds); - targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); - } - catch - { - // Ignore, BUG-2065 - } - targetGraphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/Greenshot/Drawing/Adorners/ResizeAdorner.cs deleted file mode 100644 index b2e7261a9..000000000 --- a/Greenshot/Drawing/Adorners/ResizeAdorner.cs +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Helpers; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Adorners -{ - /// - /// This is the default "legacy" gripper adorner, not the one used for the tail in the speech-bubble - /// - public class ResizeAdorner : AbstractAdorner - { - private Rectangle _boundsBeforeResize = Rectangle.Empty; - private RectangleF _boundsAfterResize = RectangleF.Empty; - - public Positions Position { get; private set; } - - public ResizeAdorner(IDrawableContainer owner, Positions position) : base(owner) - { - Position = position; - } - - /// - /// Returns the cursor for when the mouse is over the adorner - /// - public override Cursor Cursor - { - get - { - bool isNotSwitched = Owner.Width >= 0; - if (Owner.Height < 0) - { - isNotSwitched = !isNotSwitched; - } - switch (Position) - { - case Positions.TopLeft: - case Positions.BottomRight: - return isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW; - case Positions.TopRight: - case Positions.BottomLeft: - return isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE; - case Positions.MiddleLeft: - case Positions.MiddleRight: - return Cursors.SizeWE; - case Positions.TopCenter: - case Positions.BottomCenter: - return Cursors.SizeNS; - default: - return Cursors.SizeAll; - } - } - } - - /// - /// Handle the mouse down - /// - /// - /// - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.RESIZING; - _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); - _boundsAfterResize = _boundsBeforeResize; - } - - /// - /// Handle the mouse move - /// - /// - /// - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.RESIZING) - { - return; - } - Owner.Invalidate(); - Owner.MakeBoundsChangeUndoable(false); - - // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.X; - _boundsAfterResize.Y = _boundsBeforeResize.Y; - _boundsAfterResize.Width = _boundsBeforeResize.Width; - _boundsAfterResize.Height = _boundsBeforeResize.Height; - - // calculate scaled rectangle - ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); - - // apply scaled bounds to this DrawableContainer - Owner.ApplyBounds(_boundsAfterResize); - - Owner.Invalidate(); - } - - /// - /// Return the location of the adorner - /// - public override Point Location { - get - { - int x = 0,y = 0; - switch (Position) - { - case Positions.TopLeft: - x = Owner.Left; - y = Owner.Top; - break; - case Positions.BottomLeft: - x = Owner.Left; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleLeft: - x = Owner.Left; - y = Owner.Top + (Owner.Height / 2); - break; - case Positions.TopCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top; - break; - case Positions.BottomCenter: - x = Owner.Left + (Owner.Width / 2); - y = Owner.Top + Owner.Height; - break; - case Positions.TopRight: - x = Owner.Left + Owner.Width; - y = Owner.Top; - break; - case Positions.BottomRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + Owner.Height; - break; - case Positions.MiddleRight: - x = Owner.Left + Owner.Width; - y = Owner.Top + (Owner.Height / 2); - break; - } - return new Point(x, y); - } - } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = BoundsOnSurface; - GraphicsState state = targetGraphics.Save(); - - targetGraphics.CompositingMode = CompositingMode.SourceCopy; - - targetGraphics.FillRectangle(Brushes.Black, bounds); - targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); - targetGraphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/Adorners/TargetAdorner.cs b/Greenshot/Drawing/Adorners/TargetAdorner.cs deleted file mode 100644 index e0d0bbf13..000000000 --- a/Greenshot/Drawing/Adorners/TargetAdorner.cs +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Adorners -{ - /// - /// This implements the special "gripper" for the Speech-Bubble tail - /// - public class TargetAdorner : AbstractAdorner - { - - public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) - { - Location = location; - } - - /// - /// Handle the mouse down - /// - /// - /// - public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) - { - EditStatus = EditStatus.MOVING; - } - - /// - /// Handle the mouse move - /// - /// - /// - public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) - { - if (EditStatus != EditStatus.MOVING) - { - return; - } - - Owner.Invalidate(); - Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); - Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height); - // Check if gripper inside the parent (surface), if not we need to move it inside - // This was made for BUG-1682 - if (!imageBounds.Contains(newGripperLocation)) - { - if (newGripperLocation.X > imageBounds.Right) - { - newGripperLocation.X = imageBounds.Right - 5; - } - if (newGripperLocation.X < imageBounds.Left) - { - newGripperLocation.X = imageBounds.Left; - } - if (newGripperLocation.Y > imageBounds.Bottom) - { - newGripperLocation.Y = imageBounds.Bottom - 5; - } - if (newGripperLocation.Y < imageBounds.Top) - { - newGripperLocation.Y = imageBounds.Top; - } - } - - Location = newGripperLocation; - Owner.Invalidate(); - } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = BoundsOnSurface; - targetGraphics.FillRectangle(Brushes.Green, bounds); - targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); - } - - /// - /// Made sure this adorner is transformed - /// - /// Matrix - public override void Transform(Matrix matrix) - { - if (matrix == null) - { - return; - } - Point[] points = new[] { Location }; - matrix.TransformPoints(points); - Location = points[0]; - } - } -} diff --git a/Greenshot/Drawing/ArrowContainer.cs b/Greenshot/Drawing/ArrowContainer.cs deleted file mode 100644 index acfd1ad03..000000000 --- a/Greenshot/Drawing/ArrowContainer.cs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Drawing.Drawing2D; - -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of LineContainer. - /// - [Serializable()] - public class ArrowContainer : LineContainer { - public enum ArrowHeadCombination { NONE, START_POINT, END_POINT, BOTH }; - - private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6); - - public ArrowContainer(Surface parent) : base(parent) { - } - - /// - /// Do not use the base, just override so we have our own defaults - /// - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.ARROWHEADS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, true); - AddField(GetType(), FieldType.ARROWHEADS, ArrowHeadCombination.END_POINT); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - - if (lineThickness > 0 ) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - ArrowHeadCombination heads = (ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS); - if (lineThickness > 0) { - if (shadow) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = 1; - while (currentStep <= steps) - { - using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); - SetArrowHeads(heads, shadowCapPen); - - graphics.DrawLine(shadowCapPen, - Left + currentStep, - Top + currentStep, - Left + currentStep + Width, - Top + currentStep + Height); - - currentStep++; - alpha -= basealpha / steps; - } - - } - - using Pen pen = new Pen(lineColor, lineThickness); - SetArrowHeads(heads, pen); - graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); - } - } - } - - private void SetArrowHeads(ArrowHeadCombination heads, Pen pen) { - if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT ) { - pen.CustomStartCap = ARROW_CAP; - } - if ( heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT ) { - pen.CustomEndCap = ARROW_CAP; - } - } - - public override Rectangle DrawingBounds { - get { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - if (lineThickness > 0) - { - using Pen pen = new Pen(Color.White) - { - Width = lineThickness - }; - SetArrowHeads((ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS), pen); - using GraphicsPath path = new GraphicsPath(); - path.AddLine(Left, Top, Left + Width, Top + Height); - using Matrix matrix = new Matrix(); - Rectangle drawingBounds = Rectangle.Round(path.GetBounds(matrix, pen)); - drawingBounds.Inflate(2, 2); - return drawingBounds; - } - return Rectangle.Empty; - } - } - - public override bool ClickableAt(int x, int y) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; - if (lineThickness > 0) - { - using Pen pen = new Pen(Color.White) - { - Width = lineThickness - }; - SetArrowHeads((ArrowHeadCombination)GetFieldValue(FieldType.ARROWHEADS), pen); - using GraphicsPath path = new GraphicsPath(); - path.AddLine(Left, Top, Left + Width, Top + Height); - return path.IsOutlineVisible(x, y, pen); - } - return false; - } - } -} diff --git a/Greenshot/Drawing/CropContainer.cs b/Greenshot/Drawing/CropContainer.cs deleted file mode 100644 index da160f11e..000000000 --- a/Greenshot/Drawing/CropContainer.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Runtime.Serialization; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of CropContainer. - /// - public class CropContainer : DrawableContainer { - public CropContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - protected override void InitializeFields() { - AddField(GetType(), FieldType.FLAGS, FieldFlag.CONFIRMABLE); - } - - public override void Invalidate() { - _parent?.Invalidate(); - } - - /// - /// We need to override the DrawingBound, return a rectangle in the size of the image, to make sure this element is always draw - /// (we create a transparent brown over the complete picture) - /// - public override Rectangle DrawingBounds { - get - { - if (_parent?.Image is { } image) { - return new Rectangle(0, 0, image.Width, image.Height); - } - - return Rectangle.Empty; - } - } - - public override void Draw(Graphics g, RenderMode rm) { - if (_parent == null) - { - return; - } - - using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100)); - Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Rectangle selectionRect = new Rectangle(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1); - Size imageSize = _parent.Image.Size; - - DrawSelectionBorder(g, selectionRect); - - // top - g.FillRectangle(cropBrush, new Rectangle(0, 0, imageSize.Width, cropRectangle.Top)); - // left - g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); - // right - g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); - // bottom - g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height))); - } - - /// - /// No context menu for the CropContainer - /// - public override bool HasContextMenu => false; - } -} diff --git a/Greenshot/Drawing/CursorContainer.cs b/Greenshot/Drawing/CursorContainer.cs deleted file mode 100644 index 7b3078510..000000000 --- a/Greenshot/Drawing/CursorContainer.cs +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.IO; -using System.Windows.Forms; -using System.Drawing.Drawing2D; -using log4net; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of CursorContainer. - /// - [Serializable] - public class CursorContainer : DrawableContainer, ICursorContainer { - private static readonly ILog LOG = LogManager.GetLogger(typeof(CursorContainer)); - - protected Cursor cursor; - - public CursorContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - public CursorContainer(Surface parent, string filename) : this(parent) { - Load(filename); - } - - public Cursor Cursor { - set { - if (cursor != null) { - cursor.Dispose(); - } - // Clone cursor (is this correct??) - cursor = new Cursor(value.CopyHandle()); - Width = value.Size.Width; - Height = value.Size.Height; - } - get { return cursor; } - } - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected override void Dispose(bool disposing) { - if (disposing) { - if (cursor != null) { - cursor.Dispose(); - } - } - cursor = null; - base.Dispose(disposing); - } - - public void Load(string filename) { - if (!File.Exists(filename)) { - return; - } - - using Cursor fileCursor = new Cursor(filename); - Cursor = fileCursor; - LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - if (cursor == null) { - return; - } - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.Default; - graphics.PixelOffsetMode = PixelOffsetMode.None; - cursor.DrawStretched(graphics, Bounds); - } - - public override Size DefaultSize => cursor?.Size ?? new Size(16, 16); - } -} diff --git a/Greenshot/Drawing/DrawableContainer.cs b/Greenshot/Drawing/DrawableContainer.cs deleted file mode 100644 index bc0973300..000000000 --- a/Greenshot/Drawing/DrawableContainer.cs +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Configuration; -using Greenshot.Drawing.Adorners; -using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; -using Greenshot.Helpers; -using Greenshot.Memento; -using GreenshotPlugin.Interfaces.Drawing; -using log4net; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Linq; -using System.Runtime.Serialization; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Drawing.Adorners; - -namespace Greenshot.Drawing -{ - /// - /// represents a rectangle, ellipse, label or whatever. Can contain filters, too. - /// serializable for clipboard support - /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call - /// OnPropertyChanged whenever a public property has been changed. - /// - [Serializable] - public abstract class DrawableContainer : AbstractFieldHolderWithChildren, IDrawableContainer { - private static readonly ILog LOG = LogManager.GetLogger(typeof(DrawableContainer)); - protected static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - private const int M11 = 0; - private const int M22 = 3; - - [OnDeserialized] - private void OnDeserializedInit(StreamingContext context) - { - _adorners = new List(); - OnDeserialized(context); - } - - /// - /// Override to implement your own deserialization logic, like initializing properties which are not serialized - /// - /// - protected virtual void OnDeserialized(StreamingContext streamingContext) - { - } - - protected EditStatus _defaultEditMode = EditStatus.DRAWING; - public EditStatus DefaultEditMode { - get { - return _defaultEditMode; - } - } - - /// - /// The public accessible Dispose - /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice - /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) { - if (!disposing) { - return; - } - _parent?.FieldAggregator?.UnbindElement(this); - } - - ~DrawableContainer() { - Dispose(false); - } - - [NonSerialized] - private PropertyChangedEventHandler _propertyChanged; - public event PropertyChangedEventHandler PropertyChanged { - add => _propertyChanged += value; - remove => _propertyChanged -= value; - } - - public IList Filters { - get { - List ret = new List(); - foreach(IFieldHolder c in Children) { - if (c is IFilter) { - ret.Add(c as IFilter); - } - } - return ret; - } - } - - [NonSerialized] - internal Surface _parent; - public ISurface Parent { - get => _parent; - set => SwitchParent((Surface)value); - } - - [NonSerialized] - private TargetAdorner _targetAdorner; - public TargetAdorner TargetAdorner => _targetAdorner; - - [NonSerialized] - private bool _selected; - public bool Selected { - get => _selected; - set { - _selected = value; - OnPropertyChanged("Selected"); - } - } - - [NonSerialized] - private EditStatus _status = EditStatus.UNDRAWN; - public EditStatus Status { - get => _status; - set => _status = value; - } - - - private int left; - public int Left { - get => left; - set { - if (value == left) { - return; - } - left = value; - } - } - - private int top; - public int Top { - get => top; - set { - if (value == top) { - return; - } - top = value; - } - } - - private int width; - public int Width { - get => width; - set { - if (value == width) { - return; - } - width = value; - } - } - - private int height; - public int Height { - get => height; - set { - if (value == height) { - return; - } - height = value; - } - } - - public Point Location { - get => new Point(left, top); - set { - left = value.X; - top = value.Y; - } - } - - public Size Size { - get => new Size(width, height); - set { - width = value.Width; - height = value.Height; - } - } - - /// - /// List of available Adorners - /// - [NonSerialized] - private IList _adorners = new List(); - public IList Adorners => _adorners; - - [NonSerialized] - // will store current bounds of this DrawableContainer before starting a resize - protected Rectangle _boundsBeforeResize = Rectangle.Empty; - - [NonSerialized] - // "workbench" rectangle - used for calculating bounds during resizing (to be applied to this DrawableContainer afterwards) - protected RectangleF _boundsAfterResize = RectangleF.Empty; - - public Rectangle Bounds { - get => GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - set { - Left = Round(value.Left); - Top = Round(value.Top); - Width = Round(value.Width); - Height = Round(value.Height); - } - } - - public virtual void ApplyBounds(RectangleF newBounds) { - Left = Round(newBounds.Left); - Top = Round(newBounds.Top); - Width = Round(newBounds.Width); - Height = Round(newBounds.Height); - } - - public DrawableContainer(Surface parent) { - InitializeFields(); - _parent = parent; - } - - public void Add(IFilter filter) { - AddChild(filter); - } - - public void Remove(IFilter filter) { - RemoveChild(filter); - } - - private static int Round(float f) { - if(float.IsPositiveInfinity(f) || f>int.MaxValue/2) return int.MaxValue/2; - if (float.IsNegativeInfinity(f) || f Math.Max(adorner.Bounds.Width, adorner.Bounds.Height)); - - if (HasField(FieldType.LINE_THICKNESS)) { - lineThickness += GetFieldValueAsInt(FieldType.LINE_THICKNESS); - } - int offset = lineThickness/2; - - int shadow = 0; - if (accountForShadowChange || (HasField(FieldType.SHADOW) && GetFieldValueAsBool(FieldType.SHADOW))){ - accountForShadowChange = false; - shadow += 10; - } - return new Rectangle(Bounds.Left-offset, Bounds.Top-offset, Bounds.Width+lineThickness+shadow, Bounds.Height+lineThickness+shadow); - } - } - - public virtual void Invalidate() { - if (Status != EditStatus.UNDRAWN) { - _parent?.InvalidateElements(DrawingBounds); - } - } - - public virtual bool InitContent() { return true; } - - public virtual void OnDoubleClick() {} - - /// - /// Initialize a target gripper - /// - protected void InitAdorner(Color gripperColor, Point location) { - _targetAdorner = new TargetAdorner(this, location); - Adorners.Add(_targetAdorner); - } - - /// - /// Create the default adorners for a rectangle based container - /// - - protected void CreateDefaultAdorners() { - if (Adorners.Count > 0) - { - LOG.Warn("Adorners are already defined!"); - } - // Create the GripperAdorners - Adorners.Add(new ResizeAdorner(this, Positions.TopLeft)); - Adorners.Add(new ResizeAdorner(this, Positions.TopCenter)); - Adorners.Add(new ResizeAdorner(this, Positions.TopRight)); - Adorners.Add(new ResizeAdorner(this, Positions.BottomLeft)); - Adorners.Add(new ResizeAdorner(this, Positions.BottomCenter)); - Adorners.Add(new ResizeAdorner(this, Positions.BottomRight)); - Adorners.Add(new ResizeAdorner(this, Positions.MiddleLeft)); - Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight)); - } - - public bool hasFilters => Filters.Count > 0; - - public abstract void Draw(Graphics graphics, RenderMode renderMode); - - public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle) { - if (Children.Count > 0) { - if (Status != EditStatus.IDLE) { - DrawSelectionBorder(graphics, Bounds); - } else { - if (clipRectangle.Width != 0 && clipRectangle.Height != 0) { - foreach(IFilter filter in Filters) { - if (filter.Invert) { - filter.Apply(graphics, bmp, Bounds, renderMode); - } else { - Rectangle drawingRect = new Rectangle(Bounds.Location, Bounds.Size); - drawingRect.Intersect(clipRectangle); - if(filter is MagnifierFilter) { - // quick&dirty bugfix, because MagnifierFilter behaves differently when drawn only partially - // what we should actually do to resolve this is add a better magnifier which is not that special - filter.Apply(graphics, bmp, Bounds, renderMode); - } else { - filter.Apply(graphics, bmp, drawingRect, renderMode); - } - } - } - } - - } - } - Draw(graphics, renderMode); - } - - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// uint with dpi value - public void AdjustToDpi(uint dpi) - { - foreach(var adorner in Adorners) - { - adorner.AdjustToDpi(dpi); - } - } - - public virtual bool Contains(int x, int y) { - return Bounds.Contains(x , y); - } - - public virtual bool ClickableAt(int x, int y) { - Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - r.Inflate(5, 5); - return r.Contains(x, y); - } - - protected void DrawSelectionBorder(Graphics g, Rectangle rect) - { - using Pen pen = new Pen(Color.MediumSeaGreen) - { - DashPattern = new float[] { 1, 2 }, - Width = 1 - }; - g.DrawRectangle(pen, rect); - } - - - public void ResizeTo(int width, int height, int anchorPosition) { - Width = width; - Height = height; - } - - /// - /// Make a following bounds change on this drawablecontainer undoable! - /// - /// true means allow the moves to be merged - public void MakeBoundsChangeUndoable(bool allowMerge) { - _parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); - } - - public void MoveBy(int dx, int dy) { - Left += dx; - Top += dy; - } - - /// - /// A handler for the MouseDown, used if you don't want the surface to handle this for you - /// - /// current mouse x - /// current mouse y - /// true if the event is handled, false if the surface needs to handle it - public virtual bool HandleMouseDown(int x, int y) { - Left = _boundsBeforeResize.X = x; - Top = _boundsBeforeResize.Y = y; - return true; - } - - /// - /// A handler for the MouseMove, used if you don't want the surface to handle this for you - /// - /// current mouse x - /// current mouse y - /// true if the event is handled, false if the surface needs to handle it - public virtual bool HandleMouseMove(int x, int y) { - Invalidate(); - - // reset "workrbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.Left; - _boundsAfterResize.Y = _boundsBeforeResize.Top; - _boundsAfterResize.Width = x - _boundsAfterResize.Left; - _boundsAfterResize.Height = y - _boundsAfterResize.Top; - - ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); - - // apply scaled bounds to this DrawableContainer - ApplyBounds(_boundsAfterResize); - - Invalidate(); - return true; - } - - /// - /// A handler for the MouseUp - /// - /// current mouse x - /// current mouse y - public virtual void HandleMouseUp(int x, int y) { - } - - protected virtual void SwitchParent(Surface newParent) { - if (newParent == Parent) - { - return; - } - _parent?.FieldAggregator?.UnbindElement(this); - - _parent = newParent; - foreach(IFilter filter in Filters) { - filter.Parent = this; - } - } - - protected void OnPropertyChanged(string propertyName) { - if (_propertyChanged != null) { - _propertyChanged(this, new PropertyChangedEventArgs(propertyName)); - Invalidate(); - } - } - - /// - /// This method will be called before a field is changes. - /// Using this makes it possible to invalidate the object as is before changing. - /// - /// The field to be changed - /// The new value - public virtual void BeforeFieldChange(IField fieldToBeChanged, object newValue) { - _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); - Invalidate(); - } - - /// - /// Handle the field changed event, this should invalidate the correct bounds (e.g. when shadow comes or goes more pixels!) - /// - /// - /// - public void HandleFieldChanged(object sender, FieldChangedEventArgs e) { - LOG.DebugFormat("Field {0} changed", e.Field.FieldType); - if (Equals(e.Field.FieldType, FieldType.SHADOW)) { - accountForShadowChange = true; - } - } - - /// - /// Retrieve the Y scale from the matrix - /// - /// - /// - public static float CalculateScaleY(Matrix matrix) { - return matrix.Elements[M22]; - } - - /// - /// Retrieve the X scale from the matrix - /// - /// - /// - public static float CalculateScaleX(Matrix matrix) { - return matrix.Elements[M11]; - } - - /// - /// Retrieve the rotation angle from the matrix - /// - /// - /// - public static int CalculateAngle(Matrix matrix) { - const int M11 = 0; - const int M21 = 2; - var radians = Math.Atan2(matrix.Elements[M21], matrix.Elements[M11]); - return (int)-Math.Round(radians * 180 / Math.PI); - } - - /// - /// This method is called on a DrawableContainers when: - /// 1) The capture on the surface is modified in such a way, that the elements would not be placed correctly. - /// 2) Currently not implemented: an element needs to be moved, scaled or rotated. - /// This basis implementation makes sure the coordinates of the element, including the TargetGripper, is correctly rotated/scaled/translated. - /// But this implementation doesn't take care of any changes to the content!! - /// - /// - public virtual void Transform(Matrix matrix) { - if (matrix == null) { - return; - } - Point topLeft = new Point(Left, Top); - Point bottomRight = new Point(Left + Width, Top + Height); - Point[] points = new[] { topLeft, bottomRight }; - matrix.TransformPoints(points); - - Left = points[0].X; - Top = points[0].Y; - Width = points[1].X - points[0].X; - Height = points[1].Y - points[0].Y; - - } - - protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() { - return ScaleHelper.ShapeAngleRoundBehavior.Instance; - } - - public virtual bool HasContextMenu => true; - - public virtual bool HasDefaultSize => false; - - public virtual Size DefaultSize => throw new NotSupportedException("Object doesn't have a default size"); - - /// - /// Allows to override the initializing of the fields, so we can actually have our own defaults - /// - protected virtual void InitializeFields() { - } - } -} \ No newline at end of file diff --git a/Greenshot/Drawing/DrawableContainerList.cs b/Greenshot/Drawing/DrawableContainerList.cs deleted file mode 100644 index a7107543e..000000000 --- a/Greenshot/Drawing/DrawableContainerList.cs +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Configuration; -using Greenshot.Memento; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Threading; -using System.Windows.Forms; -using Greenshot.Forms; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Drawing { - /// - /// Dispatches most of a DrawableContainer's public properties and methods to a list of DrawableContainers. - /// - [Serializable] - public class DrawableContainerList : List, IDrawableContainerList - { - private static readonly ComponentResourceManager EditorFormResources = new ComponentResourceManager(typeof(ImageEditorForm)); - - public Guid ParentID { - get; - private set; - } - - public DrawableContainerList() { - } - - public DrawableContainerList(Guid parentId) { - ParentID = parentId; - } - - public EditStatus Status { - get { - return this[Count-1].Status; - } - set { - foreach (var dc in this) { - dc.Status = value; - } - } - } - - public List AsIDrawableContainerList() { - List interfaceList = new List(); - foreach(IDrawableContainer container in this) { - interfaceList.Add(container); - } - return interfaceList; - } - - /// - /// Gets or sets the selection status of the elements. - /// If several elements are in the list, true is only returned when all elements are selected. - /// - public bool Selected { - get { - bool ret = true; - foreach(var dc in this) { - ret &= dc.Selected; - } - return ret; - } - set { - foreach(var dc in this) { - dc.Selected = value; - } - } - } - - /// - /// Gets or sets the parent control of the elements in the list. - /// If there are several elements, the parent control of the last added is returned. - /// - public ISurface Parent { - get { - if (Count > 0) { - return this[Count-1].Parent; - } - return null; - } - set { - ParentID = value?.ID ?? Guid.NewGuid(); - foreach (var drawableContainer in this) { - var dc = (DrawableContainer) drawableContainer; - dc.Parent = value; - } - } - } - - /// - /// Make a following bounds change on this containerlist undoable! - /// - /// true means allow the moves to be merged - public void MakeBoundsChangeUndoable(bool allowMerge) { - if (Count > 0 && Parent != null) - { - var clone = new DrawableContainerList(); - clone.AddRange(this); - Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge); - } - } - - /// - /// Apply matrix to all elements - /// - public void Transform(Matrix matrix) { - // Track modifications - bool modified = false; - Invalidate(); - foreach (var dc in this) { - dc.Transform(matrix); - modified = true; - } - // Invalidate after - Invalidate(); - // If we moved something, tell the surface it's modified! - if (modified) { - Parent.Modified = true; - } - } - - /// - /// Moves all elements in the list by the given amount of pixels. - /// - /// pixels to move horizontally - /// pixels to move vertically - public void MoveBy(int dx, int dy) { - // Track modifications - bool modified = false; - - // Invalidate before moving, otherwise the old locations aren't refreshed - Invalidate(); - foreach(var dc in this) { - dc.Left += dx; - dc.Top += dy; - modified = true; - } - // Invalidate after - Invalidate(); - - // If we moved something, tell the surface it's modified! - if (modified) { - Parent.Modified = true; - } - } - - /// - /// Indicates whether on of the elements is clickable at the given location - /// - /// x coordinate to be checked - /// y coordinate to be checked - /// true if one of the elements in the list is clickable at the given location, false otherwise - public bool ClickableAt(int x, int y) { - bool ret = false; - foreach(var dc in this) { - ret |= dc.ClickableAt(x, y); - } - return ret; - } - - /// - /// retrieves the topmost element being clickable at the given location - /// - /// x coordinate to be checked - /// y coordinate to be checked - /// the topmost element from the list being clickable at the given location, null if there is no clickable element - public IDrawableContainer ClickableElementAt(int x, int y) { - for (int i=Count-1; i>=0; i--) { - if (this[i].ClickableAt(x,y)) { - return this[i]; - } - } - return null; - } - - /// - /// Dispatches OnDoubleClick to all elements in the list. - /// - public void OnDoubleClick() { - foreach(var drawableContainer in this) { - var dc = (DrawableContainer) drawableContainer; - dc.OnDoubleClick(); - } - } - - /// - /// Check if there are any intersecting filters, if so we need to redraw more - /// - /// - /// true if an filter intersects - public bool HasIntersectingFilters(Rectangle clipRectangle) { - foreach(var dc in this) { - if (dc.DrawingBounds.IntersectsWith(clipRectangle) && dc.hasFilters && dc.Status == EditStatus.IDLE) { - return true; - } - } - return false; - } - - /// - /// Check if any of the drawableContainers are inside the rectangle - /// - /// - /// - public bool IntersectsWith(Rectangle clipRectangle) { - foreach(var dc in this) { - if (dc.DrawingBounds.IntersectsWith(clipRectangle)) { - return true; - } - } - return false; - } - - /// - /// A rectangle containing DrawingBounds of all drawableContainers in this list, - /// or empty rectangle if nothing is there. - /// - public Rectangle DrawingBounds - { - get - { - if (Count == 0) - { - return Rectangle.Empty; - } - else - { - var result = this[0].DrawingBounds; - for (int i = 1; i < Count; i++) - { - result = Rectangle.Union(result, this[i].DrawingBounds); - } - return result; - } - } - } - - /// - /// Triggers all elements in the list ot be redrawn. - /// - /// the to the bitmap related Graphics object - /// Bitmap to draw - /// the rendermode in which the element is to be drawn - /// - public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle) { - if (Parent == null) - { - return; - } - foreach (var drawableContainer in this) - { - var dc = (DrawableContainer)drawableContainer; - if (dc.Parent == null) - { - continue; - } - if (dc.DrawingBounds.IntersectsWith(clipRectangle)) - { - dc.DrawContent(g, bitmap, renderMode, clipRectangle); - } - } - } - - /// - /// Pass the field changed event to all elements in the list - /// - /// - /// - public void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e) { - foreach(var drawableContainer in this) { - var dc = (DrawableContainer) drawableContainer; - dc.HandleFieldChanged(sender, e); - } - } - - /// - /// Invalidate the bounds of all the DC's in this list - /// - public void Invalidate() { - if (Parent == null) - { - return; - } - Rectangle region = Rectangle.Empty; - foreach (var dc in this) - { - region = Rectangle.Union(region, dc.DrawingBounds); - } - Parent.InvalidateElements(region); - } - /// - /// Indicates whether the given list of elements can be pulled up, - /// i.e. whether there is at least one unselected element higher in hierarchy - /// - /// list of elements to pull up - /// true if the elements could be pulled up - public bool CanPullUp(IDrawableContainerList elements) { - if (elements.Count == 0 || elements.Count == Count) { - return false; - } - foreach(var element in elements) { - if (IndexOf(element) < Count - elements.Count) { - return true; - } - } - return false; - } - - /// - /// Pulls one or several elements up one level in hierarchy (z-index). - /// - /// list of elements to pull up - public void PullElementsUp(IDrawableContainerList elements) { - for(int i=Count-1; i>=0; i--) { - var dc = this[i]; - if (!elements.Contains(dc)) { - continue; - } - if (Count > i+1 && !elements.Contains(this[i+1])) { - SwapElements(i,i+1); - } - } - } - - /// - /// Pulls one or several elements up to the topmost level(s) in hierarchy (z-index). - /// - /// of elements to pull to top - public void PullElementsToTop(IDrawableContainerList elements) - { - var dcs = ToArray(); - foreach (var dc in dcs) - { - if (!elements.Contains(dc)) { - continue; - } - Remove(dc); - Add(dc); - Parent.Modified = true; - } - } - - /// - /// Indicates whether the given list of elements can be pushed down, - /// i.e. whether there is at least one unselected element lower in hierarchy - /// - /// list of elements to push down - /// true if the elements could be pushed down - public bool CanPushDown(IDrawableContainerList elements) { - if (elements.Count == 0 || elements.Count == Count) { - return false; - } - foreach(var element in elements) { - if (IndexOf(element) >= elements.Count) { - return true; - } - } - return false; - } - - /// - /// Pushes one or several elements down one level in hierarchy (z-index). - /// - /// list of elements to push down - public void PushElementsDown(IDrawableContainerList elements) { - for(int i=0; i0) && !elements.Contains(this[i-1])) { - SwapElements(i,i-1); - } - } - } - - /// - /// Pushes one or several elements down to the bottommost level(s) in hierarchy (z-index). - /// - /// of elements to push to bottom - public void PushElementsToBottom(IDrawableContainerList elements) { - var dcs = ToArray(); - for(int i=dcs.Length-1; i>=0; i--) { - var dc = dcs[i]; - if (!elements.Contains(dc)) { - continue; - } - Remove(dc); - Insert(0, dc); - Parent.Modified = true; - } - } - - /// - /// swaps two elements in hierarchy (z-index), - /// checks both indices to be in range - /// - /// index of the 1st element - /// index of the 2nd element - private void SwapElements(int index1, int index2) { - if (index1 < 0 || index1 >= Count || index2 < 0 || index2 >= Count || index1 == index2) { - return; - } - var dc = this[index1]; - this[index1] = this[index2]; - this[index2] = dc; - Parent.Modified = true; - } - - /// - /// Add items to a context menu for the selected item - /// - /// - /// - public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface) { - bool push = surface.Elements.CanPushDown(this); - bool pull = surface.Elements.CanPullUp(this); - - ToolStripMenuItem item; - - // Pull "up" - if (pull) { - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uptotop)); - item.Click += delegate { - surface.Elements.PullElementsToTop(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uponelevel)); - item.Click += delegate { - surface.Elements.PullElementsUp(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - } - // Push "down" - if (push) { - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downtobottom)); - item.Click += delegate { - surface.Elements.PushElementsToBottom(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downonelevel)); - item.Click += delegate { - surface.Elements.PushElementsDown(this); - surface.Elements.Invalidate(); - }; - menu.Items.Add(item); - } - - // Duplicate - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_duplicate)); - item.Click += delegate { - IDrawableContainerList dcs = this.Clone(); - dcs.Parent = surface; - dcs.MoveBy(10, 10); - surface.AddElements(dcs); - surface.DeselectAllElements(); - surface.SelectElements(dcs); - }; - menu.Items.Add(item); - - // Copy - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_copytoclipboard)) - { - Image = (Image) EditorFormResources.GetObject("copyToolStripMenuItem.Image") - }; - item.Click += delegate { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); - }; - menu.Items.Add(item); - - // Cut - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_cuttoclipboard)) - { - Image = (Image) EditorFormResources.GetObject("btnCut.Image") - }; - item.Click += delegate { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); - surface.RemoveElements(this); - }; - menu.Items.Add(item); - - // Delete - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_deleteelement)) - { - Image = (Image)EditorFormResources.GetObject("removeObjectToolStripMenuItem.Image") - }; - item.Click += delegate { - surface.RemoveElements(this); - }; - menu.Items.Add(item); - - // Reset - bool canReset = false; - foreach (var drawableContainer in this) - { - var container = (DrawableContainer)drawableContainer; - if (container.HasDefaultSize) - { - canReset = true; - } - } - if (canReset) { - item = new ToolStripMenuItem(Language.GetString(LangKey.editor_resetsize)); - //item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("removeObjectToolStripMenuItem.Image"))); - item.Click += delegate { - MakeBoundsChangeUndoable(false); - foreach (var drawableContainer in this) { - var container = (DrawableContainer) drawableContainer; - if (!container.HasDefaultSize) { - continue; - } - Size defaultSize = container.DefaultSize; - container.MakeBoundsChangeUndoable(false); - container.Width = defaultSize.Width; - container.Height = defaultSize.Height; - } - surface.Invalidate(); - }; - menu.Items.Add(item); - } - } - - public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface) - { - if (!(iSurface is Surface surface)) - { - return; - } - bool hasMenu = false; - foreach (var drawableContainer in this) { - var container = (DrawableContainer) drawableContainer; - if (!container.HasContextMenu) { - continue; - } - hasMenu = true; - break; - } - if (hasMenu) { - ContextMenuStrip menu = new ContextMenuStrip(); - AddContextMenuItems(menu, surface); - if (menu.Items.Count > 0) { - menu.Show(surface, surface.ToSurfaceCoordinates(e.Location)); - while (true) { - if (menu.Visible) { - Application.DoEvents(); - Thread.Sleep(100); - } else { - menu.Dispose(); - break; - } - } - } - } - } - - private bool _disposedValue; // To detect redundant calls - - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - foreach (var drawableContainer in this) - { - drawableContainer.Dispose(); - } - } - - _disposedValue = true; - } - } - - // This code added to correctly implement the disposable pattern. - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - } - - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// - public void AdjustToDpi(uint dpi) - { - foreach (var drawableContainer in this) { - drawableContainer.AdjustToDpi(dpi); - } - } - } -} diff --git a/Greenshot/Drawing/EllipseContainer.cs b/Greenshot/Drawing/EllipseContainer.cs deleted file mode 100644 index b7d03ecfe..000000000 --- a/Greenshot/Drawing/EllipseContainer.cs +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Drawing.Drawing2D; - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of EllipseContainer. - /// - [Serializable()] - public class EllipseContainer : DrawableContainer { - public EllipseContainer(Surface parent) : base(parent) { - CreateDefaultAdorners(); - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, true); - } - - public override void Draw(Graphics graphics, RenderMode renderMode) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - DrawEllipse(rect, graphics, renderMode, lineThickness, lineColor, fillColor, shadow); - } - - /// - /// This allows another container to draw an ellipse - /// - /// - /// - /// - /// - /// - /// - /// - public static void DrawEllipse(Rectangle rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow) { - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - // draw shadow before anything else - if (shadow && (lineVisible || Colors.IsVisible(fillColor))) { - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = lineVisible ? 1 : 0; - while (currentStep <= steps) - { - using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)) - { - Width = lineVisible ? lineThickness : 1 - }; - Rectangle shadowRect = GuiRectangle.GetGuiRectangle(rect.Left + currentStep, rect.Top + currentStep, rect.Width, rect.Height); - graphics.DrawEllipse(shadowPen, shadowRect); - currentStep++; - alpha -= basealpha / steps; - } - } - //draw the original shape - if (Colors.IsVisible(fillColor)) - { - using Brush brush = new SolidBrush(fillColor); - graphics.FillEllipse(brush, rect); - } - if (lineVisible) - { - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawEllipse(pen, rect); - } - } - - public override bool Contains(int x, int y) { - return EllipseContains(this, x, y); - } - - /// - /// Allow the code to be used externally - /// - /// - /// - /// - /// - public static bool EllipseContains(DrawableContainer caller, int x, int y) { - double xDistanceFromCenter = x - (caller.Left + caller.Width / 2); - double yDistanceFromCenter = y - (caller.Top + caller.Height / 2); - // ellipse: x^2/a^2 + y^2/b^2 = 1 - return Math.Pow(xDistanceFromCenter, 2) / Math.Pow(caller.Width / 2, 2) + Math.Pow(yDistanceFromCenter, 2) / Math.Pow(caller.Height / 2, 2) < 1; - } - - public override bool ClickableAt(int x, int y) { - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - return EllipseClickableAt(rect, lineThickness, fillColor, x, y); - } - - public static bool EllipseClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) { - // If we clicked inside the rectangle and it's visible we are clickable at. - if (!Color.Transparent.Equals(fillColor)) { - if (rect.Contains(x, y)) { - return true; - } - } - - // check the rest of the lines - if (lineThickness > 0) - { - using Pen pen = new Pen(Color.White, lineThickness); - using GraphicsPath path = new GraphicsPath(); - path.AddEllipse(rect); - return path.IsOutlineVisible(x, y, pen); - } - return false; - } - } -} diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/Greenshot/Drawing/Fields/AbstractFieldHolder.cs deleted file mode 100644 index 48dfd95f9..000000000 --- a/Greenshot/Drawing/Fields/AbstractFieldHolder.cs +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Runtime.Serialization; - -using Greenshot.Configuration; -using GreenshotPlugin.IniFile; -using log4net; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Fields -{ - /// - /// Basic IFieldHolder implementation, providing access to a set of fields - /// - [Serializable] - public abstract class AbstractFieldHolder : IFieldHolder - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(AbstractFieldHolder)); - private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - [NonSerialized] - private readonly IDictionary _handlers = new Dictionary(); - - /// - /// called when a field's value has changed - /// - [NonSerialized] - private FieldChangedEventHandler _fieldChanged; - - public event FieldChangedEventHandler FieldChanged - { - add { _fieldChanged += value; } - remove { _fieldChanged -= value; } - } - - // we keep two Collections of our fields, dictionary for quick access, list for serialization - // this allows us to use default serialization - [NonSerialized] - private IDictionary _fieldsByType = new Dictionary(); - private readonly IList fields = new List(); - - [OnDeserialized] - private void OnDeserialized(StreamingContext context) - { - _fieldsByType = new Dictionary(); - // listen to changing properties - foreach (var field in fields) - { - field.PropertyChanged += delegate { - _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); - }; - _fieldsByType[field.FieldType] = field; - } - } - - public void AddField(Type requestingType, IFieldType fieldType, object fieldValue) - { - AddField(EditorConfig.CreateField(requestingType, fieldType, fieldValue)); - } - - public virtual void AddField(IField field) - { - fields.Add(field); - if (_fieldsByType == null) - { - return; - } - - if (_fieldsByType.ContainsKey(field.FieldType)) - { - if (LOG.IsDebugEnabled) - { - LOG.DebugFormat("A field with of type '{0}' already exists in this {1}, will overwrite.", field.FieldType, GetType()); - } - } - - _fieldsByType[field.FieldType] = field; - - _handlers[field] = (sender, args) => - { - _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); - }; - field.PropertyChanged += _handlers[field]; - } - - public void RemoveField(IField field) - { - fields.Remove(field); - _fieldsByType.Remove(field.FieldType); - field.PropertyChanged -= _handlers[field]; - _handlers.Remove(field); - } - - public IList GetFields() - { - return fields; - } - - - public IField GetField(IFieldType fieldType) - { - try - { - return _fieldsByType[fieldType]; - } - catch (KeyNotFoundException e) - { - throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); - } - } - - public object GetFieldValue(IFieldType fieldType) - { - return GetField(fieldType)?.Value; - } - - public string GetFieldValueAsString(IFieldType fieldType) - { - return Convert.ToString(GetFieldValue(fieldType)); - } - - public int GetFieldValueAsInt(IFieldType fieldType) - { - return Convert.ToInt32(GetFieldValue(fieldType)); - } - - public decimal GetFieldValueAsDecimal(IFieldType fieldType) - { - return Convert.ToDecimal(GetFieldValue(fieldType)); - } - - public double GetFieldValueAsDouble(IFieldType fieldType) - { - return Convert.ToDouble(GetFieldValue(fieldType)); - } - - public float GetFieldValueAsFloat(IFieldType fieldType) - { - return Convert.ToSingle(GetFieldValue(fieldType)); - } - - public bool GetFieldValueAsBool(IFieldType fieldType) - { - return Convert.ToBoolean(GetFieldValue(fieldType)); - } - - public Color GetFieldValueAsColor(IFieldType fieldType, Color defaultColor = default) - { - return (Color)(GetFieldValue(fieldType) ?? defaultColor); - } - - public bool HasField(IFieldType fieldType) - { - return _fieldsByType.ContainsKey(fieldType); - } - - public bool HasFieldValue(IFieldType fieldType) - { - return HasField(fieldType) && _fieldsByType[fieldType].HasValue; - } - - public void SetFieldValue(IFieldType fieldType, object value) - { - try - { - _fieldsByType[fieldType].Value = value; - } - catch (KeyNotFoundException e) - { - throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); - } - } - - protected void OnFieldChanged(object sender, FieldChangedEventArgs e) - { - _fieldChanged?.Invoke(sender, e); - } - } -} diff --git a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs deleted file mode 100644 index bb6ae068c..000000000 --- a/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.Interfaces.Drawing; -using System; -using System.Collections.Generic; -using System.Runtime.Serialization; - -namespace Greenshot.Drawing.Fields -{ - /// - /// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder, - /// but has a List of IFieldHolder for children. - /// Field values are passed to and from children as well. - /// - [Serializable] - public abstract class AbstractFieldHolderWithChildren : AbstractFieldHolder - { - [NonSerialized] - private readonly FieldChangedEventHandler _fieldChangedEventHandler; - - [NonSerialized] - private EventHandler childrenChanged; - public event EventHandler ChildrenChanged - { - add { childrenChanged += value; } - remove { childrenChanged -= value; } - } - - public IList Children = new List(); - - public AbstractFieldHolderWithChildren() - { - _fieldChangedEventHandler = OnFieldChanged; - } - - [OnDeserialized()] - private void OnDeserialized(StreamingContext context) - { - // listen to changing properties - foreach (IFieldHolder fieldHolder in Children) - { - fieldHolder.FieldChanged += _fieldChangedEventHandler; - } - childrenChanged?.Invoke(this, EventArgs.Empty); - } - - public void AddChild(IFieldHolder fieldHolder) - { - Children.Add(fieldHolder); - fieldHolder.FieldChanged += _fieldChangedEventHandler; - childrenChanged?.Invoke(this, EventArgs.Empty); - } - - public void RemoveChild(IFieldHolder fieldHolder) - { - Children.Remove(fieldHolder); - fieldHolder.FieldChanged -= _fieldChangedEventHandler; - childrenChanged?.Invoke(this, EventArgs.Empty); - } - - public new IList GetFields() - { - var ret = new List(); - ret.AddRange(base.GetFields()); - foreach (IFieldHolder fh in Children) - { - ret.AddRange(fh.GetFields()); - } - return ret; - } - - public new IField GetField(IFieldType fieldType) - { - IField ret = null; - if (base.HasField(fieldType)) - { - ret = base.GetField(fieldType); - } - else - { - foreach (IFieldHolder fh in Children) - { - if (fh.HasField(fieldType)) - { - ret = fh.GetField(fieldType); - break; - } - } - } - if (ret == null) - { - throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType()); - } - return ret; - } - - public new bool HasField(IFieldType fieldType) - { - bool ret = base.HasField(fieldType); - if (!ret) - { - foreach (IFieldHolder fh in Children) - { - if (fh.HasField(fieldType)) - { - ret = true; - break; - } - } - } - return ret; - } - - public new bool HasFieldValue(IFieldType fieldType) - { - IField f = GetField(fieldType); - return f != null && f.HasValue; - } - - public new void SetFieldValue(IFieldType fieldType, object value) - { - IField f = GetField(fieldType); - if (f != null) f.Value = value; - } - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs b/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs deleted file mode 100644 index a1ffd80c1..000000000 --- a/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; - -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Basic IBindingConverter implementation - /// - public abstract class AbstractBindingConverter : IBindingConverter - { - public object convert(object o) { - if(o == null) { - return null; - } - if(o is T1) { - return convert((T1)o); - } - if(o is T2) { - return convert((T2)o); - } - throw new ArgumentException("Cannot handle argument of type "+o.GetType()); - } - - protected abstract T2 convert(T1 o); - protected abstract T1 convert(T2 o); - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs b/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs deleted file mode 100644 index 5a9652d5c..000000000 --- a/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -using System.Reflection; - -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Bidirectional binding of properties of two INotifyPropertyChanged instances. - /// This implementation synchronizes null values, too. If you do not want this - /// behavior (e.g. when binding to a - /// - public class BidirectionalBinding { - private readonly INotifyPropertyChanged _controlObject; - private readonly INotifyPropertyChanged _fieldObject; - private readonly string _controlPropertyName; - private readonly string _fieldPropertyName; - private bool _updatingControl; - private bool _updatingField; - private IBindingConverter _converter; - private readonly IBindingValidator _validator; - - /// - /// Whether or not null values are passed on to the other object. - /// - protected bool AllowSynchronizeNull = true; - - /// - /// Bind properties of two objects bidirectionally - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName) { - _controlObject = controlObject; - _fieldObject = fieldObject; - _controlPropertyName = controlPropertyName; - _fieldPropertyName = fieldPropertyName; - - _controlObject.PropertyChanged += ControlPropertyChanged; - _fieldObject.PropertyChanged += FieldPropertyChanged; - } - - /// - /// Bind properties of two objects bidirectionally, converting the values using a converter - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - /// taking care of converting the synchronized value to the correct target format and back - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingConverter converter) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) { - _converter = converter; - } - - /// - /// Bind properties of two objects bidirectionally, converting the values using a converter. - /// Synchronization can be intercepted by adding a validator. - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - /// validator to intercept synchronization if the value does not match certain criteria - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) { - _validator = validator; - } - - /// - /// Bind properties of two objects bidirectionally, converting the values using a converter. - /// Synchronization can be intercepted by adding a validator. - /// - /// Object containing 1st property to bind - /// Property of 1st object to bind - /// Object containing 2nd property to bind - /// Property of 2nd object to bind - /// taking care of converting the synchronized value to the correct target format and back - /// validator to intercept synchronization if the value does not match certain criteria - public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, IBindingConverter converter, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName, converter) { - _validator = validator; - } - - public void ControlPropertyChanged(object sender, PropertyChangedEventArgs e) { - if (!_updatingControl && e.PropertyName.Equals(_controlPropertyName)) { - _updatingField = true; - Synchronize(_controlObject, _controlPropertyName, _fieldObject, _fieldPropertyName); - _updatingField = false; - } - } - - public void FieldPropertyChanged(object sender, PropertyChangedEventArgs e) { - if (!_updatingField && e.PropertyName.Equals(_fieldPropertyName)) { - _updatingControl = true; - Synchronize(_fieldObject, _fieldPropertyName, _controlObject, _controlPropertyName); - _updatingControl = false; - } - } - - private void Synchronize(INotifyPropertyChanged sourceObject, string sourceProperty, INotifyPropertyChanged targetObject, string targetProperty) { - PropertyInfo targetPropertyInfo = ResolvePropertyInfo(targetObject, targetProperty); - PropertyInfo sourcePropertyInfo = ResolvePropertyInfo(sourceObject, sourceProperty); - - if (sourcePropertyInfo != null && targetPropertyInfo != null && targetPropertyInfo.CanWrite) { - object bValue = sourcePropertyInfo.GetValue(sourceObject, null); - if (_converter != null && bValue != null) { - bValue = _converter.convert(bValue); - } - try { - if (_validator == null || _validator.validate(bValue)) { - targetPropertyInfo.SetValue(targetObject, bValue, null); - } - } catch (Exception e) { - throw new MemberAccessException("Could not set property '"+targetProperty+"' to '"+bValue+"' ["+(bValue?.GetType().Name ?? string.Empty)+"] on "+targetObject+". Probably other type than expected, IBindingCoverter to the rescue.", e); - } - - } - } - - private static PropertyInfo ResolvePropertyInfo(object obj, string property) { - PropertyInfo ret = null; - string[] properties = property.Split(".".ToCharArray()); - for(int i=0; i. - */ -using System; - -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Converts decimal to float and vice versa. - /// - public class DecimalFloatConverter : AbstractBindingConverter - { - private static DecimalFloatConverter _uniqueInstance; - - private DecimalFloatConverter() {} - - protected override decimal convert(float o) { - return Convert.ToDecimal(o); - } - - protected override float convert(decimal o) { - return Convert.ToSingle(o); - } - - public static DecimalFloatConverter GetInstance() - { - return _uniqueInstance ??= new DecimalFloatConverter(); - } - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs b/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs deleted file mode 100644 index 6a8ff7e84..000000000 --- a/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; - -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Converts decimal to int and vice versa. - /// - public class DecimalIntConverter : AbstractBindingConverter - { - private static DecimalIntConverter _uniqueInstance; - - private DecimalIntConverter() {} - - protected override decimal convert(int o) { - return Convert.ToDecimal(o); - } - - protected override int convert(decimal o) { - return Convert.ToInt32(o); - } - - public static DecimalIntConverter GetInstance() - { - return _uniqueInstance ??= new DecimalIntConverter(); - } - - } -} diff --git a/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs b/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs deleted file mode 100644 index d21b575a4..000000000 --- a/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -namespace Greenshot.Drawing.Fields.Binding { - - /// - /// Interface for a bidirectional validator, for use with BidirectionalBinding. - /// Useful if you do not want to synchronize values which would be illegal on - /// one of the bound objects (e.g. null value on some form components) - /// see NotNullValidator - /// - public interface IBindingValidator { - bool validate(object o); - } - -} diff --git a/Greenshot/Drawing/Fields/Field.cs b/Greenshot/Drawing/Fields/Field.cs deleted file mode 100644 index f08033fd0..000000000 --- a/Greenshot/Drawing/Fields/Field.cs +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.Interfaces.Drawing; -using System; -using System.ComponentModel; - -namespace Greenshot.Drawing.Fields -{ - /// - /// Represents a single field of a drawable element, i.e. - /// line thickness of a rectangle. - /// - [Serializable] - public class Field : IField - { - [field: NonSerialized] - public event PropertyChangedEventHandler PropertyChanged; - - private object _myValue; - public object Value - { - get - { - return _myValue; - } - set - { - if (!Equals(_myValue, value)) - { - _myValue = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); - } - } - } - public IFieldType FieldType - { - get; - set; - } - public string Scope - { - get; - set; - } - - /// - /// Constructs a new Field instance, usually you should be using FieldFactory - /// to create Fields. - /// - /// FieldType of the Field to be created - /// The scope to which the value of this Field is relevant. - /// Depending on the scope the Field's value may be shared for other elements - /// containing the same FieldType for defaulting to the last used value. - /// When scope is set to a Type (e.g. typeof(RectangleContainer)), its value - /// should not be reused for FieldHolders of another Type (e.g. typeof(EllipseContainer)) - /// - public Field(IFieldType fieldType, Type scope) - { - FieldType = fieldType; - Scope = scope.Name; - } - public Field(IFieldType fieldType, string scope) - { - FieldType = fieldType; - Scope = scope; - } - public Field(IFieldType fieldType) - { - FieldType = fieldType; - } - /// - /// Returns true if this field holds a value other than null. - /// - public bool HasValue => Value != null; - - /// - /// Creates a flat clone of this Field. The fields value itself is not cloned. - /// - /// - public Field Clone() - { - return new Field(FieldType, Scope) {Value = Value}; - } - - public override int GetHashCode() - { - int hashCode = 0; - unchecked - { - hashCode += 1000000009 * FieldType.GetHashCode(); - if (Scope != null) - hashCode += 1000000021 * Scope.GetHashCode(); - } - return hashCode; - } - - public override bool Equals(object obj) - { - if (!(obj is Field other)) - { - return false; - } - return FieldType == other.FieldType && Equals(Scope, other.Scope); - } - - public override string ToString() - { - return string.Format("[Field FieldType={1} Value={0} Scope={2}]", _myValue, FieldType, Scope); - } - } -} diff --git a/Greenshot/Drawing/Fields/FieldAggregator.cs b/Greenshot/Drawing/Fields/FieldAggregator.cs deleted file mode 100644 index 6606a96b1..000000000 --- a/Greenshot/Drawing/Fields/FieldAggregator.cs +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using Greenshot.Configuration; -using GreenshotPlugin.Interfaces.Drawing; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; - -namespace Greenshot.Drawing.Fields -{ - /// - /// Represents the current set of properties for the editor. - /// When one of EditorProperties' properties is updated, the change will be promoted - /// to all bound elements. - /// * If an element is selected: - /// This class represents the element's properties - /// * I n>1 elements are selected: - /// This class represents the properties of all elements. - /// Properties that do not apply for ALL selected elements are null (or 0 respectively) - /// If the property values of the selected elements differ, the value of the last bound element wins. - /// - [Serializable] - public sealed class FieldAggregator : AbstractFieldHolder - { - - private readonly IDrawableContainerList _boundContainers; - private bool _internalUpdateRunning; - - private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - - public FieldAggregator(ISurface parent) - { - foreach (var fieldType in FieldType.Values) - { - var field = new Field(fieldType, GetType()); - AddField(field); - } - _boundContainers = new DrawableContainerList - { - Parent = parent - }; - } - - public override void AddField(IField field) - { - base.AddField(field); - field.PropertyChanged += OwnPropertyChanged; - } - - public void BindElements(IDrawableContainerList dcs) - { - foreach (var dc in dcs) - { - BindElement(dc); - } - } - - public void BindElement(IDrawableContainer dc) - { - if (!(dc is DrawableContainer container) || _boundContainers.Contains(container)) - { - return; - } - _boundContainers.Add(container); - container.ChildrenChanged += delegate { - UpdateFromBoundElements(); - }; - UpdateFromBoundElements(); - } - - public void BindAndUpdateElement(IDrawableContainer dc) - { - UpdateElement(dc); - BindElement(dc); - } - - public void UpdateElement(IDrawableContainer dc) - { - if (!(dc is DrawableContainer container)) - { - return; - } - _internalUpdateRunning = true; - foreach (var field in GetFields()) - { - if (container.HasField(field.FieldType) && field.HasValue) - { - //if(LOG.IsDebugEnabled) LOG.Debug(" "+field+ ": "+field.Value); - container.SetFieldValue(field.FieldType, field.Value); - } - } - _internalUpdateRunning = false; - } - - public void UnbindElement(IDrawableContainer dc) - { - if (_boundContainers.Contains(dc)) - { - _boundContainers.Remove(dc); - UpdateFromBoundElements(); - } - } - - public void Clear() - { - ClearFields(); - _boundContainers.Clear(); - UpdateFromBoundElements(); - } - - /// - /// sets all field values to null, however does not remove fields - /// - private void ClearFields() - { - _internalUpdateRunning = true; - foreach (var field in GetFields()) - { - field.Value = null; - } - _internalUpdateRunning = false; - } - - /// - /// Updates this instance using the respective fields from the bound elements. - /// Fields that do not apply to every bound element are set to null, or 0 respectively. - /// All other fields will be set to the field value of the least bound element. - /// - private void UpdateFromBoundElements() - { - ClearFields(); - _internalUpdateRunning = true; - foreach (var field in FindCommonFields()) - { - SetFieldValue(field.FieldType, field.Value); - } - _internalUpdateRunning = false; - } - - private IList FindCommonFields() - { - IList returnFields = null; - if (_boundContainers.Count > 0) - { - // take all fields from the least selected container... - if (_boundContainers[_boundContainers.Count - 1] is DrawableContainer leastSelectedContainer) - { - returnFields = leastSelectedContainer.GetFields(); - for (int i = 0; i < _boundContainers.Count - 1; i++) - { - if (!(_boundContainers[i] is DrawableContainer dc)) continue; - IList fieldsToRemove = new List(); - foreach (IField field in returnFields) - { - // ... throw out those that do not apply to one of the other containers - if (!dc.HasField(field.FieldType)) - { - fieldsToRemove.Add(field); - } - } - foreach (var field in fieldsToRemove) - { - returnFields.Remove(field); - } - } - } - } - return returnFields ?? new List(); - } - - public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea) - { - IField field = (IField)sender; - if (_internalUpdateRunning || field.Value == null) - { - return; - } - foreach (var drawableContainer1 in _boundContainers.ToList()) - { - var drawableContainer = (DrawableContainer) drawableContainer1; - if (!drawableContainer.HasField(field.FieldType)) - { - continue; - } - IField drawableContainerField = drawableContainer.GetField(field.FieldType); - // Notify before change, so we can e.g. invalidate the area - drawableContainer.BeforeFieldChange(drawableContainerField, field.Value); - - drawableContainerField.Value = field.Value; - // update last used from DC field, so that scope is honored - EditorConfig.UpdateLastFieldValue(drawableContainerField); - } - } - - } -} diff --git a/Greenshot/Drawing/Fields/FieldType.cs b/Greenshot/Drawing/Fields/FieldType.cs deleted file mode 100644 index 7531e5b27..000000000 --- a/Greenshot/Drawing/Fields/FieldType.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using GreenshotPlugin.Interfaces.Drawing; -using System; - -namespace Greenshot.Drawing.Fields -{ - /// - /// Defines all FieldTypes + their default value. - /// (The additional value is why this is not an enum) - /// - [Serializable] - public class FieldType : IFieldType - { - - public static readonly IFieldType ARROWHEADS = new FieldType("ARROWHEADS"); - public static readonly IFieldType BLUR_RADIUS = new FieldType("BLUR_RADIUS"); - public static readonly IFieldType BRIGHTNESS = new FieldType("BRIGHTNESS"); - public static readonly IFieldType FILL_COLOR = new FieldType("FILL_COLOR"); - public static readonly IFieldType FONT_BOLD = new FieldType("FONT_BOLD"); - public static readonly IFieldType FONT_FAMILY = new FieldType("FONT_FAMILY"); - public static readonly IFieldType FONT_ITALIC = new FieldType("FONT_ITALIC"); - public static readonly IFieldType FONT_SIZE = new FieldType("FONT_SIZE"); - public static readonly IFieldType TEXT_HORIZONTAL_ALIGNMENT = new FieldType("TEXT_HORIZONTAL_ALIGNMENT"); - public static readonly IFieldType TEXT_VERTICAL_ALIGNMENT = new FieldType("TEXT_VERTICAL_ALIGNMENT"); - public static readonly IFieldType HIGHLIGHT_COLOR = new FieldType("HIGHLIGHT_COLOR"); - public static readonly IFieldType LINE_COLOR = new FieldType("LINE_COLOR"); - public static readonly IFieldType LINE_THICKNESS = new FieldType("LINE_THICKNESS"); - public static readonly IFieldType MAGNIFICATION_FACTOR = new FieldType("MAGNIFICATION_FACTOR"); - public static readonly IFieldType PIXEL_SIZE = new FieldType("PIXEL_SIZE"); - public static readonly IFieldType PREVIEW_QUALITY = new FieldType("PREVIEW_QUALITY"); - public static readonly IFieldType SHADOW = new FieldType("SHADOW"); - public static readonly IFieldType PREPARED_FILTER_OBFUSCATE = new FieldType("PREPARED_FILTER_OBFUSCATE"); - public static readonly IFieldType PREPARED_FILTER_HIGHLIGHT = new FieldType("PREPARED_FILTER_HIGHLIGHT"); - public static readonly IFieldType FLAGS = new FieldType("FLAGS"); - - public static IFieldType[] Values = { - ARROWHEADS, - BLUR_RADIUS, - BRIGHTNESS, - FILL_COLOR, - FONT_BOLD, - FONT_FAMILY, - FONT_ITALIC, - FONT_SIZE, - TEXT_HORIZONTAL_ALIGNMENT, - TEXT_VERTICAL_ALIGNMENT, - HIGHLIGHT_COLOR, - LINE_COLOR, - LINE_THICKNESS, - MAGNIFICATION_FACTOR, - PIXEL_SIZE, - PREVIEW_QUALITY, - SHADOW, - PREPARED_FILTER_OBFUSCATE, - PREPARED_FILTER_HIGHLIGHT, - FLAGS - }; - - public string Name - { - get; - set; - } - - private FieldType(string name) - { - Name = name; - } - public override string ToString() - { - return Name; - } - public override int GetHashCode() - { - int hashCode = 0; - unchecked - { - if (Name != null) - hashCode += 1000000009 * Name.GetHashCode(); - } - return hashCode; - } - - public override bool Equals(object obj) - { - FieldType other = obj as FieldType; - if (other == null) - { - return false; - } - return Equals(Name, other.Name); - } - - public static bool operator ==(FieldType a, FieldType b) - { - return Equals(a, b); - } - - public static bool operator !=(FieldType a, FieldType b) - { - return !Equals(a, b); - } - } -} diff --git a/Greenshot/Drawing/FilterContainer.cs b/Greenshot/Drawing/FilterContainer.cs deleted file mode 100644 index 631cbed33..000000000 --- a/Greenshot/Drawing/FilterContainer.cs +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// empty container for filter-only elements - /// - [Serializable] - public abstract class FilterContainer : DrawableContainer { - - public enum PreparedFilterMode {OBFUSCATE, HIGHLIGHT}; - public enum PreparedFilter {BLUR, PIXELIZE, TEXT_HIGHTLIGHT, AREA_HIGHLIGHT, GRAYSCALE, MAGNIFICATION}; - - public FilterContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 0); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.SHADOW, false); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - if (lineVisible) { - graphics.SmoothingMode = SmoothingMode.HighSpeed; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - //draw shadow first - if (shadow) { - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = lineVisible ? 1 : 0; - while (currentStep <= steps) - { - using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); - Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + currentStep, Top + currentStep, Width, Height); - graphics.DrawRectangle(shadowPen, shadowRect); - currentStep++; - alpha -= basealpha / steps; - } - } - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - if (lineThickness > 0) - { - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawRectangle(pen, rect); - } - } - } - } -} diff --git a/Greenshot/Drawing/Filters/AbstractFilter.cs b/Greenshot/Drawing/Filters/AbstractFilter.cs deleted file mode 100644 index 419038d40..000000000 --- a/Greenshot/Drawing/Filters/AbstractFilter.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.ComponentModel; -using System.Drawing; - -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - /// - /// Graphical filter which can be added to DrawableContainer. - /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call - /// OnPropertyChanged whenever a public property has been changed. - /// - [Serializable] - public abstract class AbstractFilter : AbstractFieldHolder, IFilter { - - [NonSerialized] - private PropertyChangedEventHandler propertyChanged; - public event PropertyChangedEventHandler PropertyChanged { - add { propertyChanged += value; } - remove{ propertyChanged -= value; } - } - - private bool invert; - public bool Invert { - get { - return invert; - } - set { - invert = value; - OnPropertyChanged("Invert"); - } - } - - protected DrawableContainer parent; - public DrawableContainer Parent { - get { - return parent; - } - set { - parent = value; - } - } - - public AbstractFilter(DrawableContainer parent) { - this.parent = parent; - } - - public DrawableContainer GetParent() { - return parent; - } - - public abstract void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode); - - protected void OnPropertyChanged(string propertyName) - { - propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - } -} diff --git a/Greenshot/Drawing/Filters/BlurFilter.cs b/Greenshot/Drawing/Filters/BlurFilter.cs deleted file mode 100644 index 79f617ac6..000000000 --- a/Greenshot/Drawing/Filters/BlurFilter.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - [Serializable] - public class BlurFilter : AbstractFilter { - public double previewQuality; - public double PreviewQuality { - get { return previewQuality; } - set { previewQuality = value; OnPropertyChanged("PreviewQuality"); } - } - - public BlurFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.BLUR_RADIUS, 3); - AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d); - } - - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - if (applyRect.Width == 0 || applyRect.Height == 0) { - return; - } - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - if (GDIplus.IsBlurPossible(blurRadius)) { - GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false); - } else - { - using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect); - ImageHelper.ApplyBoxBlur(fastBitmap, blurRadius); - fastBitmap.DrawTo(graphics, applyRect); - } - graphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/Filters/BrightnessFilter.cs b/Greenshot/Drawing/Filters/BrightnessFilter.cs deleted file mode 100644 index a43a68f67..000000000 --- a/Greenshot/Drawing/Filters/BrightnessFilter.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Imaging; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - [Serializable()] - public class BrightnessFilter : AbstractFilter { - - public BrightnessFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.BRIGHTNESS, 0.9d); - } - - /// - /// Implements the Apply code for the Brightness Filet - /// - /// - /// - /// - /// - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - float brightness = GetFieldValueAsFloat(FieldType.BRIGHTNESS); - using (ImageAttributes ia = ImageHelper.CreateAdjustAttributes(brightness, 1f, 1f)) { - graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); - } - graphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/Greenshot/Drawing/Filters/GrayscaleFilter.cs deleted file mode 100644 index f66b29fba..000000000 --- a/Greenshot/Drawing/Filters/GrayscaleFilter.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - /// - /// Description of GrayscaleFilter. - /// - [Serializable()] - public class GrayscaleFilter : AbstractFilter { - public GrayscaleFilter(DrawableContainer parent) : base(parent) { - } - - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - ColorMatrix grayscaleMatrix = new ColorMatrix(new[] { - new[] {.3f, .3f, .3f, 0, 0}, - new[] {.59f, .59f, .59f, 0, 0}, - new[] {.11f, .11f, .11f, 0, 0}, - new float[] {0, 0, 0, 1, 0}, - new float[] {0, 0, 0, 0, 1} - }); - using (ImageAttributes ia = new ImageAttributes()) { - ia.SetColorMatrix(grayscaleMatrix); - graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); - } - graphics.Restore(state); - - } - } -} diff --git a/Greenshot/Drawing/Filters/HighlightFilter.cs b/Greenshot/Drawing/Filters/HighlightFilter.cs deleted file mode 100644 index 38b6a8ee7..000000000 --- a/Greenshot/Drawing/Filters/HighlightFilter.cs +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - [Serializable()] - public class HighlightFilter : AbstractFilter { - public HighlightFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.FILL_COLOR, Color.Yellow); - } - - /// - /// Implements the Apply code for the Brightness Filet - /// - /// - /// - /// - /// - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) { - Color highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - for (int y = fastBitmap.Top; y < fastBitmap.Bottom; y++) { - for (int x = fastBitmap.Left; x < fastBitmap.Right; x++) { - Color color = fastBitmap.GetColorAt(x, y); - color = Color.FromArgb(color.A, Math.Min(highlightColor.R, color.R), Math.Min(highlightColor.G, color.G), Math.Min(highlightColor.B, color.B)); - fastBitmap.SetColorAt(x, y, color); - } - } - fastBitmap.DrawTo(graphics, applyRect.Location); - } - graphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/Filters/MagnifierFilter.cs b/Greenshot/Drawing/Filters/MagnifierFilter.cs deleted file mode 100644 index 68b033ef5..000000000 --- a/Greenshot/Drawing/Filters/MagnifierFilter.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing.Filters { - [Serializable] - public class MagnifierFilter : AbstractFilter { - public MagnifierFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.MAGNIFICATION_FACTOR, 2); - } - - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - - if (applyRect.Width == 0 || applyRect.Height == 0) { - // nothing to do - return; - } - int magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR); - GraphicsState state = graphics.Save(); - if (Invert) { - graphics.SetClip(applyRect); - graphics.ExcludeClip(rect); - } - graphics.SmoothingMode = SmoothingMode.None; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - int halfWidth = rect.Width / 2; - int halfHeight = rect.Height / 2; - int newWidth = rect.Width / magnificationFactor; - int newHeight = rect.Height / magnificationFactor; - Rectangle source = new Rectangle(rect.X + halfWidth - newWidth / 2, rect.Y + halfHeight - newHeight / 2, newWidth, newHeight); - graphics.DrawImage(applyBitmap, rect, source, GraphicsUnit.Pixel); - graphics.Restore(state); - } - } -} diff --git a/Greenshot/Drawing/FreehandContainer.cs b/Greenshot/Drawing/FreehandContainer.cs deleted file mode 100644 index 0485f2ae5..000000000 --- a/Greenshot/Drawing/FreehandContainer.cs +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of PathContainer. - /// - [Serializable] - public class FreehandContainer : DrawableContainer { - private static readonly float [] PointOffset = {0.5f, 0.25f, 0.75f}; - - [NonSerialized] - private GraphicsPath freehandPath = new GraphicsPath(); - private Rectangle myBounds = Rectangle.Empty; - private Point lastMouse = Point.Empty; - private readonly List capturePoints = new List(); - private bool isRecalculated; - - /// - /// Constructor - /// - public FreehandContainer(Surface parent) : base(parent) { - Width = parent.Image.Width; - Height = parent.Image.Height; - Top = 0; - Left = 0; - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 3); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - } - - public override void Transform(Matrix matrix) { - Point[] points = capturePoints.ToArray(); - - matrix.TransformPoints(points); - capturePoints.Clear(); - capturePoints.AddRange(points); - RecalculatePath(); - } - - protected override void OnDeserialized(StreamingContext context) { - RecalculatePath(); - } - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// - /// When disposing==true all non-managed resources should be freed too! - protected override void Dispose(bool disposing) { - base.Dispose(disposing); - if (disposing) - { - freehandPath?.Dispose(); - } - freehandPath = null; - } - - /// - /// Called from Surface (the parent) when the drawing begins (mouse-down) - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseDown(int mouseX, int mouseY) { - lastMouse = new Point(mouseX, mouseY); - capturePoints.Add(lastMouse); - return true; - } - - /// - /// Called from Surface (the parent) if a mouse move is made while drawing - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseMove(int mouseX, int mouseY) { - Point previousPoint = capturePoints[capturePoints.Count-1]; - - if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= 2*EditorConfig.FreehandSensitivity) { - capturePoints.Add(new Point(mouseX, mouseY)); - } - if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) < EditorConfig.FreehandSensitivity) - { - return true; - } - //path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)}); - lastMouse = new Point(mouseX, mouseY); - freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY)); - // Only re-calculate the bounds & redraw when we added something to the path - myBounds = Rectangle.Round(freehandPath.GetBounds()); - - Invalidate(); - return true; - } - - /// - /// Called when the surface finishes drawing the element - /// - public override void HandleMouseUp(int mouseX, int mouseY) { - // Make sure we don't loose the ending point - if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) >= EditorConfig.FreehandSensitivity) { - capturePoints.Add(new Point(mouseX, mouseY)); - } - RecalculatePath(); - } - - /// - /// Here we recalculate the freehand path by smoothing out the lines with Beziers. - /// - private void RecalculatePath() { - // Store the previous path, to dispose it later when we are finished - var previousFreehandPath = freehandPath; - var newFreehandPath = new GraphicsPath(); - - // Here we can put some cleanup... like losing all the uninteresting points. - if (capturePoints.Count >= 3) - { - int index = 0; - while ((capturePoints.Count - 1) % 3 != 0) - { - // duplicate points, first at 50% than 25% than 75% - capturePoints.Insert((int)(capturePoints.Count * PointOffset[index]), capturePoints[(int)(capturePoints.Count * PointOffset[index++])]); - } - newFreehandPath.AddBeziers(capturePoints.ToArray()); - } - else if (capturePoints.Count == 2) - { - newFreehandPath.AddLine(capturePoints[0], capturePoints[1]); - } - - // Recalculate the bounds - myBounds = Rectangle.Round(newFreehandPath.GetBounds()); - - // assign - isRecalculated = true; - freehandPath = newFreehandPath; - - // dispose previous - previousFreehandPath?.Dispose(); - } - - /// - /// Do the drawing of the freehand "stroke" - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode renderMode) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - using var pen = new Pen(lineColor) - { - Width = lineThickness - }; - if (!(pen.Width > 0)) - { - return; - } - // Make sure the lines are nicely rounded - pen.EndCap = LineCap.Round; - pen.StartCap = LineCap.Round; - pen.LineJoin = LineJoin.Round; - // Move to where we need to draw - graphics.TranslateTransform(Left, Top); - var currentFreehandPath = freehandPath; - if (currentFreehandPath != null) - { - if (isRecalculated && Selected && renderMode == RenderMode.EDIT) - { - isRecalculated = false; - DrawSelectionBorder(graphics, pen, currentFreehandPath); - } - graphics.DrawPath(pen, currentFreehandPath); - } - - // Move back, otherwise everything is shifted - graphics.TranslateTransform(-Left,-Top); - } - - /// - /// Draw a selectionborder around the freehand path - /// - /// Graphics - /// Pen - /// GraphicsPath - protected static void DrawSelectionBorder(Graphics graphics, Pen linePen, GraphicsPath path) - { - using var selectionPen = (Pen) linePen.Clone(); - using var selectionPath = (GraphicsPath)path.Clone(); - selectionPen.Width += 5; - selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen); - graphics.DrawPath(selectionPen, selectionPath); - selectionPath.Widen(selectionPen); - selectionPen.DashPattern = new float[]{2,2}; - selectionPen.Color = Color.LightSeaGreen; - selectionPen.Width = 1; - graphics.DrawPath(selectionPen, selectionPath); - } - - /// - /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds... - /// - public override Rectangle DrawingBounds { - get { - if (!myBounds.IsEmpty) { - int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS)); - int safetymargin = 10; - return new Rectangle(myBounds.Left + Left - (safetymargin+lineThickness), myBounds.Top + Top - (safetymargin+lineThickness), myBounds.Width + 2*(lineThickness+safetymargin), myBounds.Height + 2*(lineThickness+safetymargin)); - } - if (_parent?.Image is Image image) - { - return new Rectangle(0, 0, image.Width, image.Height); - } - else - { - return Rectangle.Empty; - } - } - } - - /// - /// FreehandContainer are regarded equal if they are of the same type and their paths are equal. - /// - /// object - /// bool - public override bool Equals(object obj) { - bool ret = false; - if (obj == null || GetType() != obj.GetType()) - { - return false; - } - - if (obj is FreehandContainer other && Equals(freehandPath, other.freehandPath)) { - ret = true; - } - return ret; - } - - public override int GetHashCode() { - return freehandPath?.GetHashCode() ?? 0; - } - - public override bool ClickableAt(int x, int y) { - bool returnValue = base.ClickableAt(x, y); - if (returnValue) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - using var pen = new Pen(Color.White) - { - Width = lineThickness + 10 - }; - returnValue = freehandPath.IsOutlineVisible(x - Left, y - Top, pen); - } - return returnValue; - } - } -} diff --git a/Greenshot/Drawing/HighlightContainer.cs b/Greenshot/Drawing/HighlightContainer.cs deleted file mode 100644 index 788360004..000000000 --- a/Greenshot/Drawing/HighlightContainer.cs +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Runtime.Serialization; - -using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of ObfuscateContainer. - /// - [Serializable] - public class HighlightContainer : FilterContainer { - public HighlightContainer(Surface parent) : base(parent) { - Init(); - } - - /// - /// Use settings from base, extend with our own field - /// - protected override void InitializeFields() { - base.InitializeFields(); - AddField(GetType(), FieldType.PREPARED_FILTER_HIGHLIGHT, PreparedFilter.TEXT_HIGHTLIGHT); - } - - protected override void OnDeserialized(StreamingContext context) - { - Init(); - } - - private void Init() { - FieldChanged += HighlightContainer_OnFieldChanged; - ConfigurePreparedFilters(); - } - - protected void HighlightContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { - if (!sender.Equals(this)) { - return; - } - if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_HIGHLIGHT)) { - ConfigurePreparedFilters(); - } - } - - private void ConfigurePreparedFilters() { - PreparedFilter preset = (PreparedFilter)GetFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); - while(Filters.Count>0) { - Remove(Filters[0]); - } - switch(preset) { - case PreparedFilter.TEXT_HIGHTLIGHT: - Add(new HighlightFilter(this)); - break; - case PreparedFilter.AREA_HIGHLIGHT: - var brightnessFilter = new BrightnessFilter(this) - { - Invert = true - }; - Add(brightnessFilter); - var blurFilter = new BlurFilter(this) - { - Invert = true - }; - Add(blurFilter); - break; - case PreparedFilter.GRAYSCALE: - AbstractFilter f = new GrayscaleFilter(this) - { - Invert = true - }; - Add(f); - break; - case PreparedFilter.MAGNIFICATION: - Add(new MagnifierFilter(this)); - break; - } - } - } -} diff --git a/Greenshot/Drawing/IconContainer.cs b/Greenshot/Drawing/IconContainer.cs deleted file mode 100644 index 6d5c90986..000000000 --- a/Greenshot/Drawing/IconContainer.cs +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.IO; -using System.Drawing.Drawing2D; -using log4net; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of IconContainer. - /// - [Serializable] - public class IconContainer : DrawableContainer, IIconContainer { - private static readonly ILog Log = LogManager.GetLogger(typeof(IconContainer)); - - protected Icon icon; - - public IconContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - public IconContainer(Surface parent, string filename) : base(parent) { - Load(filename); - } - - public Icon Icon { - set { - icon?.Dispose(); - icon = (Icon)value.Clone(); - Width = value.Width; - Height = value.Height; - } - get => icon; - } - - /** - * This Dispose is called from the Dispose and the Destructor. - * When disposing==true all non-managed resources should be freed too! - */ - protected override void Dispose(bool disposing) { - if (disposing) - { - icon?.Dispose(); - } - icon = null; - base.Dispose(disposing); - } - - public void Load(string filename) - { - if (!File.Exists(filename)) - { - return; - } - using Icon fileIcon = new Icon(filename); - Icon = fileIcon; - Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); - } - - public override void Draw(Graphics graphics, RenderMode rm) - { - if (icon == null) - { - return; - } - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.Default; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.DrawIcon(icon, Bounds); - } - - public override bool HasDefaultSize => true; - - public override Size DefaultSize => icon?.Size ?? new Size(16,16); - } -} diff --git a/Greenshot/Drawing/ImageContainer.cs b/Greenshot/Drawing/ImageContainer.cs deleted file mode 100644 index 5840c9507..000000000 --- a/Greenshot/Drawing/ImageContainer.cs +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.IO; -using Greenshot.Drawing.Fields; -using GreenshotPlugin.Core; -using System.Drawing.Drawing2D; -using log4net; -using System.Runtime.Serialization; -using GreenshotPlugin.Effects; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of BitmapContainer. - /// - [Serializable] - public class ImageContainer : DrawableContainer, IImageContainer { - private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer)); - - private Image image; - - /// - /// This is the shadow version of the bitmap, rendered once to save performance - /// Do not serialize, as the shadow is recreated from the original bitmap if it's not available - /// - [NonSerialized] - private Image _shadowBitmap; - - /// - /// This is the offset for the shadow version of the bitmap - /// Do not serialize, as the offset is recreated - /// - [NonSerialized] - private Point _shadowOffset = new Point(-1, -1); - - public ImageContainer(Surface parent, string filename) : this(parent) { - Load(filename); - } - - public ImageContainer(Surface parent) : base(parent) { - FieldChanged += BitmapContainer_OnFieldChanged; - Init(); - } - - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.SHADOW, false); - } - - protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) - { - if (!sender.Equals(this)) - { - return; - } - if (FieldType.SHADOW.Equals(e.Field.FieldType)) { - ChangeShadowField(); - } - } - - public void ChangeShadowField() { - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - if (shadow) { - CheckShadow(true); - Width = _shadowBitmap.Width; - Height = _shadowBitmap.Height; - Left -= _shadowOffset.X; - Top -= _shadowOffset.Y; - } else { - Width = image.Width; - Height = image.Height; - if (_shadowBitmap != null) { - Left += _shadowOffset.X; - Top += _shadowOffset.Y; - } - } - } - - public Image Image { - set { - // Remove all current bitmaps - DisposeImage(); - DisposeShadow(); - image = ImageHelper.Clone(value); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - CheckShadow(shadow); - if (!shadow) { - Width = image.Width; - Height = image.Height; - } else { - Width = _shadowBitmap.Width; - Height = _shadowBitmap.Height; - Left -= _shadowOffset.X; - Top -= _shadowOffset.Y; - } - } - get { return image; } - } - - /// - /// The bulk of the clean-up code is implemented in Dispose(bool) - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected override void Dispose(bool disposing) { - if (disposing) { - DisposeImage(); - DisposeShadow(); - } - base.Dispose(disposing); - } - - private void DisposeImage() { - image?.Dispose(); - image = null; - } - private void DisposeShadow() { - _shadowBitmap?.Dispose(); - _shadowBitmap = null; - } - - - - /// - /// Make sure the content is also transformed. - /// - /// - public override void Transform(Matrix matrix) { - int rotateAngle = CalculateAngle(matrix); - // we currently assume only one transformation has been made. - if (rotateAngle != 0) { - Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle); - DisposeShadow(); - using var tmpMatrix = new Matrix(); - using (image) - { - image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix); - } - } - base.Transform(matrix); - } - - /// - /// - /// - /// - public void Load(string filename) { - if (!File.Exists(filename)) - { - return; - } - // Always make sure ImageHelper.LoadBitmap results are disposed some time, - // as we close the bitmap internally, we need to do it afterwards - using (var tmpImage = ImageHelper.LoadImage(filename)) { - Image = tmpImage; - } - Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); - } - - /// - /// This checks if a shadow is already generated - /// - /// - private void CheckShadow(bool shadow) - { - if (!shadow || _shadowBitmap != null) - { - return; - } - using var matrix = new Matrix(); - _shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix); - } - - /// - /// Draw the actual container to the graphics object - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode rm) - { - if (image == null) - { - return; - } - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - if (shadow) { - CheckShadow(true); - graphics.DrawImage(_shadowBitmap, Bounds); - } else { - graphics.DrawImage(image, Bounds); - } - } - - public override bool HasDefaultSize => true; - - public override Size DefaultSize => image?.Size ?? new Size(32, 32); - } -} diff --git a/Greenshot/Drawing/LineContainer.cs b/Greenshot/Drawing/LineContainer.cs deleted file mode 100644 index 93b76ad89..000000000 --- a/Greenshot/Drawing/LineContainer.cs +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using Greenshot.Drawing.Adorners; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of LineContainer. - /// - [Serializable()] - public class LineContainer : DrawableContainer { - public LineContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.SHADOW, true); - } - - protected override void OnDeserialized(StreamingContext context) - { - Init(); - } - - protected void Init() { - Adorners.Add(new MoveAdorner(this, Positions.TopLeft)); - Adorners.Add(new MoveAdorner(this, Positions.BottomRight)); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - - if (lineThickness > 0) { - if (shadow) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = 1; - while (currentStep <= steps) - { - using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); - graphics.DrawLine(shadowCapPen, - Left + currentStep, - Top + currentStep, - Left + currentStep + Width, - Top + currentStep + Height); - - currentStep++; - alpha -= basealpha / steps; - } - } - - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); - } - } - - public override bool ClickableAt(int x, int y) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) +5; - if (lineThickness > 0) - { - using Pen pen = new Pen(Color.White) - { - Width = lineThickness - }; - using GraphicsPath path = new GraphicsPath(); - path.AddLine(Left, Top, Left + Width, Top + Height); - return path.IsOutlineVisible(x, y, pen); - } - return false; - } - - protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() { - return ScaleHelper.LineAngleRoundBehavior.Instance; - } - } -} diff --git a/Greenshot/Drawing/ObfuscateContainer.cs b/Greenshot/Drawing/ObfuscateContainer.cs deleted file mode 100644 index f1fdbf156..000000000 --- a/Greenshot/Drawing/ObfuscateContainer.cs +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Runtime.Serialization; -using Greenshot.Drawing.Fields; -using Greenshot.Drawing.Filters; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Description of ObfuscateContainer. - /// - [Serializable] - public class ObfuscateContainer : FilterContainer { - public ObfuscateContainer(Surface parent) : base(parent) { - Init(); - } - - protected override void InitializeFields() { - base.InitializeFields(); - AddField(GetType(), FieldType.PREPARED_FILTER_OBFUSCATE, PreparedFilter.PIXELIZE); - } - - protected override void OnDeserialized(StreamingContext context) - { - Init(); - } - - private void Init() { - FieldChanged += ObfuscateContainer_OnFieldChanged; - ConfigurePreparedFilters(); - CreateDefaultAdorners(); - } - - protected void ObfuscateContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) { - if(sender.Equals(this)) { - if(Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_OBFUSCATE)) { - ConfigurePreparedFilters(); - } - } - } - - private void ConfigurePreparedFilters() { - PreparedFilter preset = (PreparedFilter)GetFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE); - while(Filters.Count>0) { - Remove(Filters[0]); - } - switch(preset) { - case PreparedFilter.BLUR: - Add(new BlurFilter(this)); - break; - case PreparedFilter.PIXELIZE: - Add(new PixelizationFilter(this)); - break; - } - } - } -} diff --git a/Greenshot/Drawing/RectangleContainer.cs b/Greenshot/Drawing/RectangleContainer.cs deleted file mode 100644 index 2e86fa509..000000000 --- a/Greenshot/Drawing/RectangleContainer.cs +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// Represents a rectangular shape on the Surface - /// - [Serializable] - public class RectangleContainer : DrawableContainer { - - public RectangleContainer(Surface parent) : base(parent) { - Init(); - } - - /// - /// Do some logic to make sure all field are initiated correctly - /// - /// StreamingContext - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); - AddField(GetType(), FieldType.SHADOW, true); - } - - public override void Draw(Graphics graphics, RenderMode rm) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR, Color.Red); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR, Color.Transparent); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - - DrawRectangle(rect, graphics, rm, lineThickness, lineColor, fillColor, shadow); - } - - /// - /// This method can also be used from other containers, if the right values are passed! - /// - /// - /// - /// - /// - /// - /// - /// - public static void DrawRectangle(Rectangle rect, Graphics graphics, RenderMode rm, int lineThickness, Color lineColor, Color fillColor, bool shadow) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - if (shadow && (lineVisible || Colors.IsVisible(fillColor))) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = lineVisible ? 1 : 0; - while (currentStep <= steps) - { - using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)) - { - Width = lineVisible ? lineThickness : 1 - }; - Rectangle shadowRect = GuiRectangle.GetGuiRectangle( - rect.Left + currentStep, - rect.Top + currentStep, - rect.Width, - rect.Height); - graphics.DrawRectangle(shadowPen, shadowRect); - currentStep++; - alpha -= basealpha / steps; - } - } - - - if (Colors.IsVisible(fillColor)) - { - using Brush brush = new SolidBrush(fillColor); - graphics.FillRectangle(brush, rect); - } - - graphics.SmoothingMode = SmoothingMode.HighSpeed; - if (lineVisible) - { - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawRectangle(pen, rect); - } - - } - public override bool ClickableAt(int x, int y) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - - return RectangleClickableAt(rect, lineThickness, fillColor, x, y); - } - - - public static bool RectangleClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) { - - // If we clicked inside the rectangle and it's visible we are clickable at. - if (!Color.Transparent.Equals(fillColor)) { - if (rect.Contains(x,y)) { - return true; - } - } - - // check the rest of the lines - if (lineThickness > 0) - { - using Pen pen = new Pen(Color.White, lineThickness); - using GraphicsPath path = new GraphicsPath(); - path.AddRectangle(rect); - return path.IsOutlineVisible(x, y, pen); - } - return false; - } - } -} diff --git a/Greenshot/Drawing/SpeechbubbleContainer.cs b/Greenshot/Drawing/SpeechbubbleContainer.cs deleted file mode 100644 index ee00714e9..000000000 --- a/Greenshot/Drawing/SpeechbubbleContainer.cs +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Text; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing -{ - /// - /// Description of SpeechbubbleContainer. - /// - [Serializable] - public class SpeechbubbleContainer : TextContainer { - - private Point _initialGripperPoint; - - // Only used for serializing the TargetGripper location - private Point _storedTargetGripperLocation; - - /// - /// Store the current location of the target gripper - /// - /// - [OnSerializing] - private void SetValuesOnSerializing(StreamingContext context) { - if (TargetAdorner != null) { - _storedTargetGripperLocation = TargetAdorner.Location; - } - } - - /// - /// Restore the target gripper - /// - /// StreamingContext - protected override void OnDeserialized(StreamingContext streamingContext) - { - base.OnDeserialized(streamingContext); - InitAdorner(Color.Green, _storedTargetGripperLocation); - } - - public SpeechbubbleContainer(Surface parent) - : base(parent) { - } - - /// - /// We set our own field values - /// - protected override void InitializeFields() { - AddField(GetType(), FieldType.LINE_THICKNESS, 2); - AddField(GetType(), FieldType.LINE_COLOR, Color.Blue); - AddField(GetType(), FieldType.SHADOW, false); - AddField(GetType(), FieldType.FONT_ITALIC, false); - AddField(GetType(), FieldType.FONT_BOLD, true); - AddField(GetType(), FieldType.FILL_COLOR, Color.White); - AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name); - AddField(GetType(), FieldType.FONT_SIZE, 20f); - AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, StringAlignment.Center); - AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, StringAlignment.Center); - } - - /// - /// Called from Surface (the _parent) when the drawing begins (mouse-down) - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseDown(int mouseX, int mouseY) { - if (TargetAdorner == null) { - _initialGripperPoint = new Point(mouseX, mouseY); - InitAdorner(Color.Green, new Point(mouseX, mouseY)); - } - return base.HandleMouseDown(mouseX, mouseY); - } - - /// - /// Overriding the HandleMouseMove will help us to make sure the tail is always visible. - /// Should fix BUG-1682 - /// - /// - /// - /// base.HandleMouseMove - public override bool HandleMouseMove(int x, int y) { - bool returnValue = base.HandleMouseMove(x, y); - - bool leftAligned = _boundsAfterResize.Right - _boundsAfterResize.Left >= 0; - bool topAligned = _boundsAfterResize.Bottom - _boundsAfterResize.Top >= 0; - - int xOffset = leftAligned ? -20 : 20; - int yOffset = topAligned ? -20 : 20; - - Point newGripperLocation = _initialGripperPoint; - newGripperLocation.Offset(xOffset, yOffset); - - if (TargetAdorner.Location != newGripperLocation) { - Invalidate(); - TargetAdorner.Location = newGripperLocation; - Invalidate(); - } - return returnValue; - } - - /// - /// The DrawingBound should be so close as possible to the shape, so we don't invalidate to much. - /// - public override Rectangle DrawingBounds { - get { - if (Status != EditStatus.UNDRAWN) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - using Pen pen = new Pen(lineColor, lineThickness); - int inflateValue = lineThickness + 2 + (shadow ? 6 : 0); - using GraphicsPath tailPath = CreateTail(); - return Rectangle.Inflate(Rectangle.Union(Rectangle.Round(tailPath.GetBounds(new Matrix(), pen)), GuiRectangle.GetGuiRectangle(Left, Top, Width, Height)), inflateValue, inflateValue); - } - return Rectangle.Empty; - } - } - - /// - /// Helper method to create the bubble GraphicsPath, so we can also calculate the bounds - /// - /// - /// - private GraphicsPath CreateBubble(int lineThickness) { - GraphicsPath bubble = new GraphicsPath(); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - - Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height); - // adapt corner radius to small rectangle dimensions - int smallerSideLength = Math.Min(bubbleRect.Width, bubbleRect.Height); - int cornerRadius = Math.Min(30, smallerSideLength / 2 - lineThickness); - if (cornerRadius > 0) { - bubble.AddArc(bubbleRect.X, bubbleRect.Y, cornerRadius, cornerRadius, 180, 90); - bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y, cornerRadius, cornerRadius, 270, 90); - bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 0, 90); - bubble.AddArc(bubbleRect.X, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90); - } else { - bubble.AddRectangle(bubbleRect); - } - bubble.CloseAllFigures(); - using (Matrix bubbleMatrix = new Matrix()) { - bubbleMatrix.Translate(rect.Left, rect.Top); - bubble.Transform(bubbleMatrix); - } - return bubble; - } - - /// - /// Helper method to create the tail of the bubble, so we can also calculate the bounds - /// - /// - private GraphicsPath CreateTail() { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - - int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetAdorner.Location.X, TargetAdorner.Location.Y); - int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20; - - // This should fix a problem with the tail being to wide - tailWidth = Math.Min(Math.Abs(rect.Width) / 2, tailWidth); - tailWidth = Math.Min(Math.Abs(rect.Height) / 2, tailWidth); - - GraphicsPath tail = new GraphicsPath(); - tail.AddLine(-tailWidth, 0, tailWidth, 0); - tail.AddLine(tailWidth, 0, 0, -tailLength); - tail.CloseFigure(); - - int tailAngle = 90 + (int)GeometryHelper.Angle2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetAdorner.Location.X, TargetAdorner.Location.Y); - - using (Matrix tailMatrix = new Matrix()) { - tailMatrix.Translate(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2); - tailMatrix.Rotate(tailAngle); - tail.Transform(tailMatrix); - } - - return tail; - } - - /// - /// This is to draw the actual container - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode renderMode) { - if (TargetAdorner == null) { - return; - } - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; - - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - - bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - - if (Selected && renderMode == RenderMode.EDIT) { - DrawSelectionBorder(graphics, rect); - } - - GraphicsPath bubble = CreateBubble(lineThickness); - - GraphicsPath tail = CreateTail(); - - //draw shadow first - if (shadow && (lineVisible || Colors.IsVisible(fillColor))) { - const int basealpha = 100; - int alpha = basealpha; - const int steps = 5; - int currentStep = lineVisible ? 1 : 0; - using Matrix shadowMatrix = new Matrix(); - using GraphicsPath bubbleClone = (GraphicsPath)bubble.Clone(); - using GraphicsPath tailClone = (GraphicsPath)tail.Clone(); - shadowMatrix.Translate(1, 1); - while (currentStep <= steps) { - using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) { - shadowPen.Width = lineVisible ? lineThickness : 1; - tailClone.Transform(shadowMatrix); - graphics.DrawPath(shadowPen, tailClone); - bubbleClone.Transform(shadowMatrix); - graphics.DrawPath(shadowPen, bubbleClone); - } - currentStep++; - alpha -= basealpha / steps; - } - } - - GraphicsState state = graphics.Save(); - // draw the tail border where the bubble is not visible - using (Region clipRegion = new Region(bubble)) { - graphics.SetClip(clipRegion, CombineMode.Exclude); - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawPath(pen, tail); - } - graphics.Restore(state); - - if (Colors.IsVisible(fillColor)) { - //draw the bubbleshape - state = graphics.Save(); - using (Brush brush = new SolidBrush(fillColor)) { - graphics.FillPath(brush, bubble); - } - graphics.Restore(state); - } - - if (lineVisible) { - //draw the bubble border - state = graphics.Save(); - // Draw bubble where the Tail is not visible. - using (Region clipRegion = new Region(tail)) { - graphics.SetClip(clipRegion, CombineMode.Exclude); - using Pen pen = new Pen(lineColor, lineThickness); - //pen.EndCap = pen.StartCap = LineCap.Round; - graphics.DrawPath(pen, bubble); - } - graphics.Restore(state); - } - - if (Colors.IsVisible(fillColor)) { - // Draw the tail border - state = graphics.Save(); - using (Brush brush = new SolidBrush(fillColor)) { - graphics.FillPath(brush, tail); - } - graphics.Restore(state); - } - - // cleanup the paths - bubble.Dispose(); - tail.Dispose(); - - // Draw the text - DrawText(graphics, rect, lineThickness, lineColor, shadow, StringFormat, Text, Font); - } - - public override bool Contains(int x, int y) { - if (base.Contains(x, y)) { - return true; - } - Point clickedPoint = new Point(x, y); - if (Status != EditStatus.UNDRAWN) { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - using Pen pen = new Pen(lineColor, lineThickness); - using (GraphicsPath bubblePath = CreateBubble(lineThickness)) { - bubblePath.Widen(pen); - if (bubblePath.IsVisible(clickedPoint)) { - return true; - } - } - - using GraphicsPath tailPath = CreateTail(); - tailPath.Widen(pen); - if (tailPath.IsVisible(clickedPoint)) { - return true; - } - } - - return false; - } - - public override bool ClickableAt(int x, int y) { - return Contains(x,y); - } - - /// - /// Additional to the Transform of the TextContainer the bubble tail coordinates also need to be moved - /// - /// Matrix - public override void Transform(Matrix matrix) - { - Point[] points = { TargetAdorner.Location }; - matrix.TransformPoints(points); - TargetAdorner.Location = points[0]; - base.Transform(matrix); - } - } -} diff --git a/Greenshot/Drawing/StepLabelContainer.cs b/Greenshot/Drawing/StepLabelContainer.cs deleted file mode 100644 index b750fcb20..000000000 --- a/Greenshot/Drawing/StepLabelContainer.cs +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Text; -using System.Runtime.Serialization; -using GreenshotPlugin.Interfaces.Drawing; - -namespace Greenshot.Drawing { - /// - /// This is an enumerated label, every single StepLabelContainer shows the number of the order it was created. - /// To make sure that deleting recalculates, we check the location before every draw. - /// - [Serializable] - public sealed class StepLabelContainer : DrawableContainer { - [NonSerialized] - private StringFormat _stringFormat = new StringFormat(); - - private readonly bool _drawAsRectangle = false; - - public StepLabelContainer(Surface parent) : base(parent) { - parent.AddStepLabel(this); - InitContent(); - Init(); - } - - private void Init() - { - CreateDefaultAdorners(); - } - - // Used to store the number of this label, so when deserializing it can be placed back to the StepLabels list in the right location - private int _number; - // Used to store the counter start of the Surface, as the surface is NOT stored. - private int _counterStart = 1; - public int Number { - get { - return _number; - } - set { - _number = value; - } - } - - /// - /// Retrieve the counter before serializing - /// - /// - [OnSerializing] - private void SetValuesOnSerializing(StreamingContext context) { - if (Parent != null) { - Number = ((Surface)Parent).CountStepLabels(this); - _counterStart = ((Surface) Parent).CounterStart; - } - } - - /// - /// Restore values that don't serialize - /// - /// - protected override void OnDeserialized(StreamingContext context) - { - Init(); - _stringFormat = new StringFormat - { - Alignment = StringAlignment.Center, - LineAlignment = StringAlignment.Center - }; - - } - - /// - /// Add the StepLabel to the parent - /// - /// - protected override void SwitchParent(Surface newParent) { - if (newParent == Parent) - { - return; - } - ((Surface) Parent)?.RemoveStepLabel(this); - base.SwitchParent(newParent); - if (newParent == null) - { - return; - } - // Make sure the counter start is restored (this unfortunately happens multiple times... -> hack) - newParent.CounterStart = _counterStart; - newParent.AddStepLabel(this); - } - - public override Size DefaultSize => new Size(30, 30); - - public override bool InitContent() { - _defaultEditMode = EditStatus.IDLE; - _stringFormat.Alignment = StringAlignment.Center; - _stringFormat.LineAlignment = StringAlignment.Center; - - // Set defaults - Width = DefaultSize.Width; - Height = DefaultSize.Height; - - return true; - } - - /// - /// This makes it possible for the label to be placed exactly in the middle of the pointer. - /// - public override bool HandleMouseDown(int mouseX, int mouseY) { - return base.HandleMouseDown(mouseX - Width / 2, mouseY - Height / 2); - } - - /// - /// We set our own field values - /// - protected override void InitializeFields() { - AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed); - AddField(GetType(), FieldType.LINE_COLOR, Color.White); - AddField(GetType(), FieldType.FLAGS, FieldFlag.COUNTER); - } - - /// - /// Make sure this element is no longer referenced from the surface - /// - protected override void Dispose(bool disposing) { - base.Dispose(disposing); - if (!disposing) { - return; - } - ((Surface) Parent)?.RemoveStepLabel(this); - if (_stringFormat == null) - { - return; - } - _stringFormat.Dispose(); - _stringFormat = null; - } - - public override bool HandleMouseMove(int x, int y) { - Invalidate(); - Left = x - Width / 2; - Top = y - Height / 2; - Invalidate(); - return true; - } - - /// - /// Override the parent, calculate the label number, than draw - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode rm) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; - string text = ((Surface)Parent).CountStepLabels(this).ToString(); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - if (_drawAsRectangle) { - RectangleContainer.DrawRectangle(rect, graphics, rm, 0, Color.Transparent, fillColor, false); - } else { - EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false); - } - - float fontSize = Math.Min(Width,Height) / 1.4f; - using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name); - using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel); - TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font); - } - - public override bool ClickableAt(int x, int y) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - if (_drawAsRectangle) { - return RectangleContainer.RectangleClickableAt(rect, 0, fillColor, x, y); - } - - return EllipseContainer.EllipseClickableAt(rect, 0, fillColor, x, y); - } - } -} diff --git a/Greenshot/Drawing/Surface.cs b/Greenshot/Drawing/Surface.cs deleted file mode 100644 index ed3118db6..000000000 --- a/Greenshot/Drawing/Surface.cs +++ /dev/null @@ -1,2264 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Configuration; -using Greenshot.Drawing.Fields; -using Greenshot.Helpers; -using Greenshot.Memento; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; -using log4net; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using System.Runtime.Serialization.Formatters.Binary; -using System.Windows.Forms; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Drawing.Adorners; - -namespace Greenshot.Drawing -{ - /// - /// Description of Surface. - /// - public sealed class Surface : Control, ISurface, INotifyPropertyChanged - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface)); - public static int Count; - private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); - - // Property to identify the Surface ID - private Guid _uniqueId = Guid.NewGuid(); - - /// - /// This value is used to start counting the step labels - /// - private int _counterStart = 1; - - /// - /// The GUID of the surface - /// - public Guid ID - { - get => _uniqueId; - set => _uniqueId = value; - } - - /// - /// Event handlers (do not serialize!) - /// - [NonSerialized] - private PropertyChangedEventHandler _propertyChanged; - public event PropertyChangedEventHandler PropertyChanged - { - add => _propertyChanged += value; - remove => _propertyChanged -= value; - } - - [NonSerialized] - private SurfaceElementEventHandler _movingElementChanged; - public event SurfaceElementEventHandler MovingElementChanged - { - add => _movingElementChanged += value; - remove => _movingElementChanged -= value; - } - - [NonSerialized] - private SurfaceDrawingModeEventHandler _drawingModeChanged; - public event SurfaceDrawingModeEventHandler DrawingModeChanged - { - add => _drawingModeChanged += value; - remove => _drawingModeChanged -= value; - } - [NonSerialized] - private SurfaceSizeChangeEventHandler _surfaceSizeChanged; - public event SurfaceSizeChangeEventHandler SurfaceSizeChanged - { - add => _surfaceSizeChanged += value; - remove => _surfaceSizeChanged -= value; - } - [NonSerialized] - private SurfaceMessageEventHandler _surfaceMessage; - public event SurfaceMessageEventHandler SurfaceMessage - { - add => _surfaceMessage += value; - remove => _surfaceMessage -= value; - } - - /// - /// inUndoRedo makes sure we don't undo/redo while in a undo/redo action - /// - [NonSerialized] - private bool _inUndoRedo; - - /// - /// Make only one surface move cycle undoable, see SurfaceMouseMove - /// - [NonSerialized] - private bool _isSurfaceMoveMadeUndoable; - - /// - /// Undo/Redo stacks, should not be serialized as the file would be way to big - /// - [NonSerialized] - private readonly Stack _undoStack = new Stack(); - [NonSerialized] - private readonly Stack _redoStack = new Stack(); - - /// - /// Last save location, do not serialize! - /// - [NonSerialized] - private string _lastSaveFullPath; - - /// - /// current drawing mode, do not serialize! - /// - [NonSerialized] - private DrawingModes _drawingMode = DrawingModes.None; - - /// - /// the keys-locked flag helps with focus issues - /// - [NonSerialized] - private bool _keysLocked; - - /// - /// Location of the mouse-down (it "starts" here), do not serialize - /// - [NonSerialized] - private Point _mouseStart = Point.Empty; - - /// - /// are we in a mouse down, do not serialize - /// - [NonSerialized] - private bool _mouseDown; - - /// - /// The selected element for the mouse down, do not serialize - /// - [NonSerialized] - private IDrawableContainer _mouseDownElement; - - /// - /// all selected elements, do not serialize - /// - [NonSerialized] - private readonly IDrawableContainerList selectedElements; - - /// - /// the element we are drawing with, do not serialize - /// - [NonSerialized] - private IDrawableContainer _drawingElement; - - /// - /// the element we want to draw with (not yet drawn), do not serialize - /// - [NonSerialized] - private IDrawableContainer _undrawnElement; - - /// - /// the cropcontainer, when cropping this is set, do not serialize - /// - [NonSerialized] - private IDrawableContainer _cropContainer; - - /// - /// the brush which is used for transparent backgrounds, set by the editor, do not serialize - /// - [NonSerialized] - private Brush _transparencyBackgroundBrush; - - /// - /// The buffer is only for drawing on it when using filters (to supply access) - /// This saves a lot of "create new bitmap" commands - /// Should not be serialized, as it's generated. - /// The actual bitmap is in the paintbox... - /// TODO: Check if this buffer is still needed! - /// - [NonSerialized] - private Bitmap _buffer; - - /// - /// all stepLabels for the surface, needed with serialization - /// - private readonly List _stepLabels = new List(); - - public void AddStepLabel(StepLabelContainer stepLabel) - { - if (!_stepLabels.Contains(stepLabel)) - { - _stepLabels.Add(stepLabel); - } - } - - public void RemoveStepLabel(StepLabelContainer stepLabel) - { - _stepLabels.Remove(stepLabel); - } - - /// - /// The start value of the counter objects - /// - public int CounterStart - { - get => _counterStart; - set - { - if (_counterStart == value) - { - return; - } - - _counterStart = value; - Invalidate(); - _propertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CounterStart))); - } - } - - /// - /// Count all the VISIBLE steplabels in the surface, up to the supplied one - /// - /// can be null, if not the counting stops here - /// number of steplabels before the supplied container - public int CountStepLabels(IDrawableContainer stopAtContainer) - { - int number = CounterStart; - foreach (var possibleThis in _stepLabels) - { - if (possibleThis.Equals(stopAtContainer)) - { - break; - } - if (IsOnSurface(possibleThis)) - { - number++; - } - } - return number; - } - - /// - /// all elements on the surface, needed with serialization - /// - private readonly IDrawableContainerList _elements; - - /// - /// all elements on the surface, needed with serialization - /// - private FieldAggregator _fieldAggregator; - - /// - /// the cursor container, needed with serialization as we need a direct acces to it. - /// - private IDrawableContainer _cursorContainer; - - /// - /// the modified flag specifies if the surface has had modifications after the last export. - /// Initial state is modified, as "it's not saved" - /// After serialization this should actually be "false" (the surface came from a stream) - /// For now we just serialize it... - /// - private bool _modified = true; - - /// - /// The image is the actual captured image, needed with serialization - /// - private Image _image; - public Image Image - { - get => _image; - set - { - _image = value; - UpdateSize(); - } - } - - [NonSerialized] - private Matrix _zoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); - [NonSerialized] - private Matrix _inverseZoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); - [NonSerialized] - private Fraction _zoomFactor = Fraction.Identity; - public Fraction ZoomFactor - { - get => _zoomFactor; - set - { - _zoomFactor = value; - var inverse = _zoomFactor.Inverse(); - _zoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0); - _inverseZoomMatrix = new Matrix(inverse, 0, 0, inverse, 0, 0); - UpdateSize(); - } - } - - - /// - /// Sets the surface size as zoomed image size. - /// - private void UpdateSize() - { - var size = _image.Size; - Size = new Size((int)(size.Width * _zoomFactor), (int)(size.Height * _zoomFactor)); - } - - /// - /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements. - /// e.g. used to decided if and which line thickness is shown when multiple elements are selected. - /// - public FieldAggregator FieldAggregator - { - get => _fieldAggregator; - set => _fieldAggregator = value; - } - - /// - /// The cursor container has it's own accessor so we can find and remove this (when needed) - /// - public IDrawableContainer CursorContainer => _cursorContainer; - - /// - /// A simple getter to ask if this surface has a cursor - /// - public bool HasCursor => _cursorContainer != null; - - /// - /// A simple helper method to remove the cursor from the surface - /// - public void RemoveCursor() - { - RemoveElement(_cursorContainer); - _cursorContainer = null; - } - - /// - /// The brush which is used to draw the transparent background - /// - public Brush TransparencyBackgroundBrush - { - get => _transparencyBackgroundBrush; - set => _transparencyBackgroundBrush = value; - } - - /// - /// Are the keys on this surface locked? - /// - public bool KeysLocked - { - get => _keysLocked; - set => _keysLocked = value; - } - - /// - /// Is this surface modified? This is only true if the surface has not been exported. - /// - public bool Modified - { - get => _modified; - set => _modified = value; - } - - /// - /// The DrawingMode property specifies the mode for drawing, more or less the element type. - /// - public DrawingModes DrawingMode - { - get => _drawingMode; - set - { - _drawingMode = value; - if (_drawingModeChanged != null) - { - SurfaceDrawingModeEventArgs eventArgs = new SurfaceDrawingModeEventArgs - { - DrawingMode = _drawingMode - }; - _drawingModeChanged.Invoke(this, eventArgs); - } - DeselectAllElements(); - CreateUndrawnElement(); - } - } - - /// - /// Property for accessing the last save "full" path - /// - public string LastSaveFullPath - { - get => _lastSaveFullPath; - set => _lastSaveFullPath = value; - } - - /// - /// Property for accessing the URL to which the surface was recently uploaded - /// - public string UploadUrl - { - get; - set; - } - - /// - /// Property for accessing the capture details - /// - public ICaptureDetails CaptureDetails { get; set; } - - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// - public void AdjustToDpi(uint dpi) - { - foreach (var element in this._elements) { - element.AdjustToDpi(dpi); - } - } - - /// - /// Base Surface constructor - /// - public Surface() - { - _fieldAggregator = new FieldAggregator(this); - Count++; - _elements = new DrawableContainerList(_uniqueId); - selectedElements = new DrawableContainerList(_uniqueId); - LOG.Debug("Creating surface!"); - MouseDown += SurfaceMouseDown; - MouseUp += SurfaceMouseUp; - MouseMove += SurfaceMouseMove; - MouseDoubleClick += SurfaceDoubleClick; - Paint += SurfacePaint; - AllowDrop = true; - DragDrop += OnDragDrop; - DragEnter += OnDragEnter; - // bind selected & elements to this, otherwise they can't inform of modifications - selectedElements.Parent = this; - _elements.Parent = this; - // Make sure we are visible - Visible = true; - TabStop = false; - // Enable double buffering - DoubleBuffered = true; - SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.ContainerControl | ControlStyles.OptimizedDoubleBuffer | ControlStyles.SupportsTransparentBackColor, true); - } - - /// - /// Private method, the current image is disposed the new one will stay. - /// - /// The new image - /// true if the old image needs to be disposed, when using undo this should not be true!! - private void SetImage(Image newImage, bool dispose) - { - // Dispose - if (_image != null && dispose) - { - _image.Dispose(); - } - - // Set new values - Image = newImage; - - _modified = true; - } - - /// - /// Surface constructor with an image - /// - /// - public Surface(Image newImage) : this() - { - LOG.DebugFormat("Got image with dimensions {0} and format {1}", newImage.Size, newImage.PixelFormat); - SetImage(newImage, true); - } - - /// - /// Surface contructor with a capture - /// - /// - public Surface(ICapture capture) : this(capture.Image) - { - // check if cursor is captured, and visible - if (capture.Cursor != null && capture.CursorVisible) - { - Rectangle cursorRect = new Rectangle(capture.CursorLocation, capture.Cursor.Size); - Rectangle captureRect = new Rectangle(Point.Empty, capture.Image.Size); - // check if cursor is on the capture, otherwise we leave it out. - if (cursorRect.IntersectsWith(captureRect)) - { - _cursorContainer = AddIconContainer(capture.Cursor, capture.CursorLocation.X, capture.CursorLocation.Y); - SelectElement(_cursorContainer); - } - } - // Make sure the image is NOT disposed, we took the reference directly into ourselves - ((Capture)capture).NullImage(); - - CaptureDetails = capture.CaptureDetails; - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - Count--; - LOG.Debug("Disposing surface!"); - if (_buffer != null) - { - _buffer.Dispose(); - _buffer = null; - } - if (_transparencyBackgroundBrush != null) - { - _transparencyBackgroundBrush.Dispose(); - _transparencyBackgroundBrush = null; - } - - // Cleanup undo/redo stacks - while (_undoStack != null && _undoStack.Count > 0) - { - _undoStack.Pop().Dispose(); - } - while (_redoStack != null && _redoStack.Count > 0) - { - _redoStack.Pop().Dispose(); - } - foreach (IDrawableContainer container in _elements) - { - container.Dispose(); - } - if (_undrawnElement != null) - { - _undrawnElement.Dispose(); - _undrawnElement = null; - } - if (_cropContainer != null) - { - _cropContainer.Dispose(); - _cropContainer = null; - } - } - base.Dispose(disposing); - } - - /// - /// Undo the last action - /// - public void Undo() - { - if (_undoStack.Count > 0) - { - _inUndoRedo = true; - IMemento top = _undoStack.Pop(); - _redoStack.Push(top.Restore()); - _inUndoRedo = false; - } - } - - /// - /// Undo an undo (=redo) - /// - public void Redo() - { - if (_redoStack.Count > 0) - { - _inUndoRedo = true; - IMemento top = _redoStack.Pop(); - _undoStack.Push(top.Restore()); - _inUndoRedo = false; - } - } - - /// - /// Returns if the surface can do a undo - /// - public bool CanUndo => _undoStack.Count > 0; - - /// - /// Returns if the surface can do a redo - /// - public bool CanRedo => _redoStack.Count > 0; - - /// - /// Get the language key for the undo action - /// - public LangKey UndoActionLanguageKey => LangKey.none; - - /// - /// Get the language key for redo action - /// - public LangKey RedoActionLanguageKey => LangKey.none; - - /// - /// Make an action undo-able - /// - /// The memento implementing the undo - /// Allow changes to be merged - public void MakeUndoable(IMemento memento, bool allowMerge) - { - if (_inUndoRedo) - { - throw new InvalidOperationException("Invoking do within an undo/redo action."); - } - if (memento != null) - { - bool allowPush = true; - if (_undoStack.Count > 0 && allowMerge) - { - // Check if merge is possible - allowPush = !_undoStack.Peek().Merge(memento); - } - if (allowPush) - { - // Clear the redo-stack and dispose - while (_redoStack.Count > 0) - { - _redoStack.Pop().Dispose(); - } - _undoStack.Push(memento); - } - } - } - - /// - /// This saves the elements of this surface to a stream. - /// Is used to save a template of the complete surface - /// - /// - /// - public long SaveElementsToStream(Stream streamWrite) - { - long bytesWritten = 0; - try - { - long lengtBefore = streamWrite.Length; - BinaryFormatter binaryWrite = new BinaryFormatter(); - binaryWrite.Serialize(streamWrite, _elements); - bytesWritten = streamWrite.Length - lengtBefore; - } - catch (Exception e) - { - LOG.Error("Error serializing elements to stream.", e); - } - return bytesWritten; - } - - /// - /// This loads elements from a stream, among others this is used to load a surface. - /// - /// - public void LoadElementsFromStream(Stream streamRead) - { - try - { - BinaryFormatter binaryRead = new BinaryFormatter(); - IDrawableContainerList loadedElements = (IDrawableContainerList)binaryRead.Deserialize(streamRead); - loadedElements.Parent = this; - // Make sure the steplabels are sorted accoring to their number - _stepLabels.Sort((p1, p2) => p1.Number.CompareTo(p2.Number)); - DeselectAllElements(); - AddElements(loadedElements); - SelectElements(loadedElements); - FieldAggregator.BindElements(loadedElements); - } - catch (Exception e) - { - LOG.Error("Error serializing elements from stream.", e); - } - } - - /// - /// This is called from the DrawingMode setter, which is not very correct... - /// But here an element is created which is not yet draw, thus "undrawnElement". - /// The element is than used while drawing on the surface. - /// - private void CreateUndrawnElement() - { - if (_undrawnElement != null) - { - FieldAggregator.UnbindElement(_undrawnElement); - } - switch (DrawingMode) - { - case DrawingModes.Rect: - _undrawnElement = new RectangleContainer(this); - break; - case DrawingModes.Ellipse: - _undrawnElement = new EllipseContainer(this); - break; - case DrawingModes.Text: - _undrawnElement = new TextContainer(this); - break; - case DrawingModes.SpeechBubble: - _undrawnElement = new SpeechbubbleContainer(this); - break; - case DrawingModes.StepLabel: - _undrawnElement = new StepLabelContainer(this); - break; - case DrawingModes.Line: - _undrawnElement = new LineContainer(this); - break; - case DrawingModes.Arrow: - _undrawnElement = new ArrowContainer(this); - break; - case DrawingModes.Highlight: - _undrawnElement = new HighlightContainer(this); - break; - case DrawingModes.Obfuscate: - _undrawnElement = new ObfuscateContainer(this); - break; - case DrawingModes.Crop: - _cropContainer = new CropContainer(this); - _undrawnElement = _cropContainer; - break; - case DrawingModes.Bitmap: - _undrawnElement = new ImageContainer(this); - break; - case DrawingModes.Path: - _undrawnElement = new FreehandContainer(this); - break; - case DrawingModes.None: - _undrawnElement = null; - break; - } - if (_undrawnElement != null) - { - FieldAggregator.BindElement(_undrawnElement); - } - } - - #region Plugin interface implementations - public IImageContainer AddImageContainer(Image image, int x, int y) - { - ImageContainer bitmapContainer = new ImageContainer(this) - { - Image = image, - Left = x, - Top = y - }; - AddElement(bitmapContainer); - return bitmapContainer; - } - - public IImageContainer AddImageContainer(string filename, int x, int y) - { - ImageContainer bitmapContainer = new ImageContainer(this); - bitmapContainer.Load(filename); - bitmapContainer.Left = x; - bitmapContainer.Top = y; - AddElement(bitmapContainer); - return bitmapContainer; - } - public IIconContainer AddIconContainer(Icon icon, int x, int y) - { - IconContainer iconContainer = new IconContainer(this) - { - Icon = icon, - Left = x, - Top = y - }; - AddElement(iconContainer); - return iconContainer; - } - public IIconContainer AddIconContainer(string filename, int x, int y) - { - IconContainer iconContainer = new IconContainer(this); - iconContainer.Load(filename); - iconContainer.Left = x; - iconContainer.Top = y; - AddElement(iconContainer); - return iconContainer; - } - public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y) - { - CursorContainer cursorContainer = new CursorContainer(this) - { - Cursor = cursor, - Left = x, - Top = y - }; - AddElement(cursorContainer); - return cursorContainer; - } - public ICursorContainer AddCursorContainer(string filename, int x, int y) - { - CursorContainer cursorContainer = new CursorContainer(this); - cursorContainer.Load(filename); - cursorContainer.Left = x; - cursorContainer.Top = y; - AddElement(cursorContainer); - return cursorContainer; - } - - public ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor) - { - TextContainer textContainer = new TextContainer(this) {Text = text, Left = x, Top = y}; - textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name); - textContainer.SetFieldValue(FieldType.FONT_BOLD, bold); - textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic); - textContainer.SetFieldValue(FieldType.FONT_SIZE, size); - textContainer.SetFieldValue(FieldType.FILL_COLOR, fillColor); - textContainer.SetFieldValue(FieldType.LINE_COLOR, color); - textContainer.SetFieldValue(FieldType.LINE_THICKNESS, borderSize); - textContainer.SetFieldValue(FieldType.SHADOW, shadow); - // Make sure the Text fits - textContainer.FitToText(); - - //AggregatedProperties.UpdateElement(textContainer); - AddElement(textContainer); - return textContainer; - } - #endregion - - #region DragDrop - - private void OnDragEnter(object sender, DragEventArgs e) - { - if (LOG.IsDebugEnabled) - { - LOG.Debug("DragEnter got following formats: "); - foreach (string format in ClipboardHelper.GetFormats(e.Data)) - { - LOG.Debug(format); - } - } - if ((e.AllowedEffect & DragDropEffects.Copy) != DragDropEffects.Copy) - { - e.Effect = DragDropEffects.None; - } - else - { - if (ClipboardHelper.ContainsImage(e.Data) || ClipboardHelper.ContainsFormat(e.Data, "DragImageBits")) - { - e.Effect = DragDropEffects.Copy; - } - else - { - e.Effect = DragDropEffects.None; - } - } - } - - /// - /// Handle the drag/drop - /// - /// - /// - private void OnDragDrop(object sender, DragEventArgs e) - { - Point mouse = PointToClient(new Point(e.X, e.Y)); - if (e.Data.GetDataPresent("Text")) - { - string possibleUrl = ClipboardHelper.GetText(e.Data); - // Test if it's an url and try to download the image so we have it in the original form - if (possibleUrl != null && possibleUrl.StartsWith("http")) - { - using Image image = NetworkHelper.DownloadImage(possibleUrl); - if (image != null) - { - AddImageContainer(image, mouse.X, mouse.Y); - return; - } - } - } - - foreach (Image image in ClipboardHelper.GetImages(e.Data)) - { - AddImageContainer(image, mouse.X, mouse.Y); - mouse.Offset(10, 10); - image.Dispose(); - } - } - - #endregion - - /// - /// Auto crop the image - /// - /// true if cropped - public bool AutoCrop() - { - Rectangle cropRectangle; - using (Image tmpImage = GetImageForExport()) - { - cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference); - } - if (!IsCropPossible(ref cropRectangle)) - { - return false; - } - DeselectAllElements(); - // Maybe a bit obscure, but the following line creates a drop container - // It's available as "undrawnElement" - DrawingMode = DrawingModes.Crop; - _undrawnElement.Left = cropRectangle.X; - _undrawnElement.Top = cropRectangle.Y; - _undrawnElement.Width = cropRectangle.Width; - _undrawnElement.Height = cropRectangle.Height; - _undrawnElement.Status = EditStatus.UNDRAWN; - AddElement(_undrawnElement); - SelectElement(_undrawnElement); - _drawingElement = null; - _undrawnElement = null; - return true; - } - - /// - /// A simple clear - /// - /// The color for the background - public void Clear(Color newColor) - { - //create a blank bitmap the same size as original - Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty); - if (newBitmap != null) - { - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false); - SetImage(newBitmap, false); - Invalidate(); - } - } - - /// - /// Apply a bitmap effect to the surface - /// - /// - public void ApplyBitmapEffect(IEffect effect) - { - BackgroundForm backgroundForm = new BackgroundForm("Effect", "Please wait"); - backgroundForm.Show(); - Application.DoEvents(); - try - { - Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); - Matrix matrix = new Matrix(); - Image newImage = ImageHelper.ApplyEffect(Image, effect, matrix); - if (newImage != null) - { - // Make sure the elements move according to the offset the effect made the bitmap move - _elements.Transform(matrix); - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); - SetImage(newImage, false); - Invalidate(); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) - { - _surfaceSizeChanged(this, null); - } - } - else - { - // clean up matrix, as it hasn't been used in the undo stack. - matrix.Dispose(); - } - } - finally - { - // Always close the background form - backgroundForm.CloseDialog(); - } - } - - /// - /// check if a crop is possible - /// - /// - /// true if this is possible - public bool IsCropPossible(ref Rectangle cropRectangle) - { - cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); - if (cropRectangle.Left < 0) - { - cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); - } - if (cropRectangle.Top < 0) - { - cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); - } - if (cropRectangle.Left + cropRectangle.Width > Image.Width) - { - cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height); - } - if (cropRectangle.Top + cropRectangle.Height > Image.Height) - { - cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top); - } - if (cropRectangle.Height > 0 && cropRectangle.Width > 0) - { - return true; - } - return false; - } - - /// - /// Use to send any registered SurfaceMessageEventHandler a message, e.g. used for the notification area - /// - /// Who send - /// Type of message - /// Message itself - public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message) - { - if (_surfaceMessage != null) - { - var eventArgs = new SurfaceMessageEventArgs - { - Message = message, - MessageType = messageType, - Surface = this - }; - _surfaceMessage(source, eventArgs); - } - } - - /// - /// Crop the surface - /// - /// - /// - public bool ApplyCrop(Rectangle cropRectangle) - { - if (IsCropPossible(ref cropRectangle)) - { - Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); - Bitmap tmpImage; - // Make sure we have information, this this fails - try - { - tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); - } - catch (Exception ex) - { - ex.Data.Add("CropRectangle", cropRectangle); - ex.Data.Add("Width", Image.Width); - ex.Data.Add("Height", Image.Height); - ex.Data.Add("Pixelformat", Image.PixelFormat); - throw; - } - - Matrix matrix = new Matrix(); - matrix.Translate(-cropRectangle.Left, -cropRectangle.Top, MatrixOrder.Append); - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); - - // Do not dispose otherwise we can't undo the image! - SetImage(tmpImage, false); - _elements.Transform(matrix); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) - { - _surfaceSizeChanged(this, null); - } - Invalidate(); - return true; - } - return false; - } - - /// - /// The background here is the captured image. - /// This is called from the SurfaceBackgroundChangeMemento. - /// - /// - /// - public void UndoBackgroundChange(Image previous, Matrix matrix) - { - SetImage(previous, false); - if (matrix != null) - { - _elements.Transform(matrix); - } - _surfaceSizeChanged?.Invoke(this, null); - Invalidate(); - } - /// - /// Check if an adorner was "hit", and change the cursor if so - /// - /// MouseEventArgs - /// IAdorner - private IAdorner FindActiveAdorner(MouseEventArgs mouseEventArgs) - { - foreach (IDrawableContainer drawableContainer in selectedElements) - { - foreach (IAdorner adorner in drawableContainer.Adorners) - { - - if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location)) - { - if (adorner.Cursor != null) - { - Cursor = adorner.Cursor; - } - return adorner; - } - } - } - return null; - } - - /// - /// Translate mouse coordinates as if they were applied directly to unscaled image. - /// - private MouseEventArgs InverseZoomMouseCoordinates(MouseEventArgs e) - => new MouseEventArgs(e.Button, e.Clicks, (int)(e.X / _zoomFactor), (int)(e.Y / _zoomFactor), e.Delta); - - /// - /// This event handler is called when someone presses the mouse on a surface. - /// - /// - /// - private void SurfaceMouseDown(object sender, MouseEventArgs e) - { - e = InverseZoomMouseCoordinates(e); - - // Handle Adorners - var adorner = FindActiveAdorner(e); - if (adorner != null) - { - adorner.MouseDown(sender, e); - return; - } - - _mouseStart = e.Location; - - // check contextmenu - if (e.Button == MouseButtons.Right) - { - IDrawableContainerList selectedList = null; - if (selectedElements != null && selectedElements.Count > 0) - { - selectedList = selectedElements; - } - else - { - // Single element - IDrawableContainer rightClickedContainer = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); - if (rightClickedContainer != null) - { - selectedList = new DrawableContainerList(ID) {rightClickedContainer}; - } - } - if (selectedList != null && selectedList.Count > 0) - { - selectedList.ShowContextMenu(e, this); - } - return; - } - - _mouseDown = true; - _isSurfaceMoveMadeUndoable = false; - - if (_cropContainer != null && ((_undrawnElement == null) || (_undrawnElement != null && DrawingMode != DrawingModes.Crop))) - { - RemoveElement(_cropContainer, false); - _cropContainer = null; - _drawingElement = null; - } - - if (_drawingElement == null && DrawingMode != DrawingModes.None) - { - if (_undrawnElement == null) - { - DeselectAllElements(); - if (_undrawnElement == null) - { - CreateUndrawnElement(); - } - } - _drawingElement = _undrawnElement; - // if a new element has been drawn, set location and register it - if (_drawingElement != null) - { - if (_undrawnElement != null) - { - _drawingElement.Status = _undrawnElement.DefaultEditMode; - } - if (!_drawingElement.HandleMouseDown(_mouseStart.X, _mouseStart.Y)) - { - _drawingElement.Left = _mouseStart.X; - _drawingElement.Top = _mouseStart.Y; - } - AddElement(_drawingElement); - _drawingElement.Selected = true; - } - _undrawnElement = null; - } - else - { - // check whether an existing element was clicked - // we save mouse down element separately from selectedElements (checked on mouse up), - // since it could be moved around before it is actually selected - _mouseDownElement = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); - - if (_mouseDownElement != null) - { - _mouseDownElement.Status = EditStatus.MOVING; - } - } - } - - /// - /// This event handle is called when the mouse button is unpressed - /// - /// - /// - private void SurfaceMouseUp(object sender, MouseEventArgs e) - { - e = InverseZoomMouseCoordinates(e); - - // Handle Adorners - var adorner = FindActiveAdorner(e); - if (adorner != null) - { - adorner.MouseUp(sender, e); - return; - } - - Point currentMouse = new Point(e.X, e.Y); - - _elements.Status = EditStatus.IDLE; - if (_mouseDownElement != null) - { - _mouseDownElement.Status = EditStatus.IDLE; - } - _mouseDown = false; - _mouseDownElement = null; - if (DrawingMode == DrawingModes.None) - { - // check whether an existing element was clicked - IDrawableContainer element = _elements.ClickableElementAt(currentMouse.X, currentMouse.Y); - bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; - if (element != null) - { - element.Invalidate(); - bool alreadySelected = selectedElements.Contains(element); - if (shiftModifier) - { - if (alreadySelected) - { - DeselectElement(element); - } - else - { - SelectElement(element); - } - } - else - { - if (!alreadySelected) - { - DeselectAllElements(); - SelectElement(element); - } - } - } - else if (!shiftModifier) - { - DeselectAllElements(); - } - } - - if (selectedElements.Count > 0) - { - selectedElements.Invalidate(); - selectedElements.Selected = true; - } - - if (_drawingElement != null) - { - if (!_drawingElement.InitContent()) - { - _elements.Remove(_drawingElement); - _drawingElement.Invalidate(); - } - else - { - _drawingElement.HandleMouseUp(currentMouse.X, currentMouse.Y); - _drawingElement.Invalidate(); - if (Math.Abs(_drawingElement.Width) < 5 && Math.Abs(_drawingElement.Height) < 5) - { - _drawingElement.Width = 25; - _drawingElement.Height = 25; - } - SelectElement(_drawingElement); - _drawingElement.Selected = true; - } - _drawingElement = null; - } - } - - /// - /// This event handler is called when the mouse moves over the surface - /// - /// - /// - private void SurfaceMouseMove(object sender, MouseEventArgs e) - { - e = InverseZoomMouseCoordinates(e); - - // Handle Adorners - var adorner = FindActiveAdorner(e); - if (adorner != null) - { - adorner.MouseMove(sender, e); - return; - } - - Point currentMouse = e.Location; - - Cursor = DrawingMode != DrawingModes.None ? Cursors.Cross : Cursors.Default; - - if (_mouseDown) - { - if (_mouseDownElement != null) - { // an element is currently dragged - _mouseDownElement.Invalidate(); - selectedElements.Invalidate(); - // Move the element - if (_mouseDownElement.Selected) - { - if (!_isSurfaceMoveMadeUndoable) - { - // Only allow one undoable per mouse-down/move/up "cycle" - _isSurfaceMoveMadeUndoable = true; - selectedElements.MakeBoundsChangeUndoable(false); - } - // dragged element has been selected before -> move all - selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); - } - else - { - if (!_isSurfaceMoveMadeUndoable) - { - // Only allow one undoable per mouse-down/move/up "cycle" - _isSurfaceMoveMadeUndoable = true; - _mouseDownElement.MakeBoundsChangeUndoable(false); - } - // dragged element is not among selected elements -> just move dragged one - _mouseDownElement.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); - } - _mouseStart = currentMouse; - _mouseDownElement.Invalidate(); - _modified = true; - } - else if (_drawingElement != null) - { - _drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); - _modified = true; - } - } - } - - /// - /// This event handler is called when the surface is double clicked. - /// - /// - /// - private void SurfaceDoubleClick(object sender, MouseEventArgs e) - { - selectedElements.OnDoubleClick(); - selectedElements.Invalidate(); - } - - /// - /// Privately used to get the rendered image with all the elements on it. - /// - /// - /// - private Image GetImage(RenderMode renderMode) - { - // Generate a copy of the original image with a dpi equal to the default... - Bitmap clone = ImageHelper.Clone(_image, PixelFormat.DontCare); - // otherwise we would have a problem drawing the image to the surface... :( - using (Graphics graphics = Graphics.FromImage(clone)) - { - // Do not set the following, the containers need to decide themselves - //graphics.SmoothingMode = SmoothingMode.HighQuality; - //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - //graphics.CompositingQuality = CompositingQuality.HighQuality; - //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - _elements.Draw(graphics, clone, renderMode, new Rectangle(Point.Empty, clone.Size)); - } - return clone; - } - - /// - /// This returns the image "result" of this surface, with all the elements rendered on it. - /// - /// - public Image GetImageForExport() - { - return GetImage(RenderMode.EXPORT); - } - - private static Rectangle ZoomClipRectangle(Rectangle rc, double scale, int inflateAmount = 0) - { - rc = new Rectangle( - (int)(rc.X * scale), - (int)(rc.Y * scale), - (int)(rc.Width * scale) + 1, - (int)(rc.Height * scale) + 1 - ); - if (scale > 1) - { - inflateAmount = (int)(inflateAmount * scale); - } - rc.Inflate(inflateAmount, inflateAmount); - return rc; - } - - public void InvalidateElements(Rectangle rc) - => Invalidate(ZoomClipRectangle(rc, _zoomFactor, 1)); - - /// - /// This is the event handler for the Paint Event, try to draw as little as possible! - /// - /// - /// PaintEventArgs - private void SurfacePaint(object sender, PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - Rectangle targetClipRectangle = paintEventArgs.ClipRectangle; - if (Rectangle.Empty.Equals(targetClipRectangle)) - { - LOG.Debug("Empty cliprectangle??"); - return; - } - - // Correction to prevent rounding errors at certain zoom levels. - // When zooming to N/M, clip rectangle top and left coordinates should be multiples of N. - if (_zoomFactor.Numerator > 1 && _zoomFactor.Denominator > 1) - { - int horizontalCorrection = targetClipRectangle.Left % (int)_zoomFactor.Numerator; - int verticalCorrection = targetClipRectangle.Top % (int)_zoomFactor.Numerator; - if (horizontalCorrection != 0) - { - targetClipRectangle.X -= horizontalCorrection; - targetClipRectangle.Width += horizontalCorrection; - } - if (verticalCorrection != 0) - { - targetClipRectangle.Y -= verticalCorrection; - targetClipRectangle.Height += verticalCorrection; - } - } - - Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2); - - if (_elements.HasIntersectingFilters(imageClipRectangle) || _zoomFactor > Fraction.Identity) - { - if (_buffer != null) - { - if (_buffer.Width != Image.Width || _buffer.Height != Image.Height || _buffer.PixelFormat != Image.PixelFormat) - { - _buffer.Dispose(); - _buffer = null; - } - } - if (_buffer == null) - { - _buffer = ImageHelper.CreateEmpty(Image.Width, Image.Height, Image.PixelFormat, Color.Empty, Image.HorizontalResolution, Image.VerticalResolution); - LOG.DebugFormat("Created buffer with size: {0}x{1}", Image.Width, Image.Height); - } - // Elements might need the bitmap, so we copy the part we need - using (Graphics graphics = Graphics.FromImage(_buffer)) - { - // do not set the following, the containers need to decide this themselves! - //graphics.SmoothingMode = SmoothingMode.HighQuality; - //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - //graphics.CompositingQuality = CompositingQuality.HighQuality; - //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - DrawBackground(graphics, imageClipRectangle); - graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), _zoomFactor.Inverse(), 2)); - _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle); - } - if (_zoomFactor == Fraction.Identity) - { - targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - } - else - { - targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); - if (_zoomFactor > Fraction.Identity) - { - DrawSharpImage(targetGraphics, _buffer, imageClipRectangle); - } - else - { - DrawSmoothImage(targetGraphics, _buffer, imageClipRectangle); - } - targetGraphics.ResetTransform(); - } - } - else - { - DrawBackground(targetGraphics, targetClipRectangle); - if (_zoomFactor == Fraction.Identity) - { - targetGraphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); - } - else - { - targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); - DrawSmoothImage(targetGraphics, Image, imageClipRectangle); - _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); - targetGraphics.ResetTransform(); - } - } - - // No clipping for the adorners - targetGraphics.ResetClip(); - // Draw adorners last - foreach (var drawableContainer in selectedElements) - { - foreach (var adorner in drawableContainer.Adorners) - { - adorner.Paint(paintEventArgs); - } - } - } - - private void DrawSmoothImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) - { - var state = targetGraphics.Save(); - targetGraphics.SmoothingMode = SmoothingMode.HighQuality; - targetGraphics.InterpolationMode = InterpolationMode.HighQualityBilinear; - targetGraphics.CompositingQuality = CompositingQuality.HighQuality; - targetGraphics.PixelOffsetMode = PixelOffsetMode.None; - - targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - - targetGraphics.Restore(state); - } - - private void DrawSharpImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) - { - var state = targetGraphics.Save(); - targetGraphics.SmoothingMode = SmoothingMode.None; - targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; - targetGraphics.CompositingQuality = CompositingQuality.HighQuality; - targetGraphics.PixelOffsetMode = PixelOffsetMode.None; - - targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); - - targetGraphics.Restore(state); - } - - private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) - { - // check if we need to draw the checkerboard - if (Image.IsAlphaPixelFormat(Image.PixelFormat) && _transparencyBackgroundBrush != null) - { - targetGraphics.FillRectangle(_transparencyBackgroundBrush, clipRectangle); - } - else - { - targetGraphics.Clear(BackColor); - } - } - - /// - /// Draw a checkboard when capturing with transparency - /// - /// PaintEventArgs - protected override void OnPaintBackground(PaintEventArgs e) - { - } - - /// - /// Add a new element to the surface - /// - /// the new element - /// true if the adding should be undoable - /// true if invalidate needs to be called - public void AddElement(IDrawableContainer element, bool makeUndoable = true, bool invalidate = true) - { - _elements.Add(element); - if (element is DrawableContainer container) - { - container.FieldChanged += Element_FieldChanged; - } - element.Parent = this; - if (element.Status == EditStatus.UNDRAWN) - { - element.Status = EditStatus.IDLE; - } - if (element.Selected) - { - // Use false, as the element is invalidated when invalidate == true anyway - SelectElement(element, false); - } - if (invalidate) - { - element.Invalidate(); - } - if (makeUndoable) - { - MakeUndoable(new AddElementMemento(this, element), false); - } - _modified = true; - } - - /// - /// Remove the list of elements - /// - /// IDrawableContainerList - /// flag specifying if the remove needs to be undoable - public void RemoveElements(IDrawableContainerList elementsToRemove, bool makeUndoable = true) - { - // fix potential issues with iterating a changing list - DrawableContainerList cloned = new DrawableContainerList(); - cloned.AddRange(elementsToRemove); - if (makeUndoable) - { - MakeUndoable(new DeleteElementsMemento(this, cloned), false); - } - SuspendLayout(); - foreach (var drawableContainer in cloned) - { - RemoveElement(drawableContainer, false, false, false); - } - ResumeLayout(); - Invalidate(); - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs {Elements = cloned}; - _movingElementChanged(this, eventArgs); - } - } - - /// - /// Remove an element of the elements list - /// - /// Element to remove - /// flag specifying if the remove needs to be undoable - /// flag specifying if an surface invalidate needs to be called - /// false to skip event generation - public void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable = true, bool invalidate = true, bool generateEvents = true) - { - DeselectElement(elementToRemove, generateEvents); - _elements.Remove(elementToRemove); - if (elementToRemove is DrawableContainer element) - { - element.FieldChanged -= Element_FieldChanged; - } - if (elementToRemove != null) - { - elementToRemove.Parent = null; - } - // Do not dispose, the memento should!! element.Dispose(); - if (invalidate) - { - Invalidate(); - } - if (makeUndoable) - { - MakeUndoable(new DeleteElementMemento(this, elementToRemove), false); - } - _modified = true; - } - - /// - /// Add the supplied elements to the surface - /// - /// DrawableContainerList - /// true if the adding should be undoable - public void AddElements(IDrawableContainerList elementsToAdd, bool makeUndoable = true) - { - // fix potential issues with iterating a changing list - DrawableContainerList cloned = new DrawableContainerList(); - cloned.AddRange(elementsToAdd); - if (makeUndoable) - { - MakeUndoable(new AddElementsMemento(this, cloned), false); - } - SuspendLayout(); - foreach (var element in cloned) - { - element.Selected = true; - AddElement(element, false, false); - } - ResumeLayout(); - Invalidate(); - } - - /// - /// Returns if this surface has selected elements - /// - /// - public bool HasSelectedElements => (selectedElements != null && selectedElements.Count > 0); - - /// - /// Remove all the selected elements - /// - public void RemoveSelectedElements() - { - if (HasSelectedElements) - { - // As RemoveElement will remove the element from the selectedElements list we need to copy the element to another list. - RemoveElements(selectedElements); - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); - _movingElementChanged(this, eventArgs); - } - } - } - - /// - /// Cut the selected elements from the surface to the clipboard - /// - public void CutSelectedElements() - { - if (HasSelectedElements) - { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); - RemoveSelectedElements(); - } - } - - /// - /// Copy the selected elements to the clipboard - /// - public void CopySelectedElements() - { - if (HasSelectedElements) - { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); - } - } - - /// - /// This method is called to confirm/cancel "confirmable" elements, like the crop-container. - /// Called when pressing enter or using the "check" in the editor. - /// - /// - public void ConfirmSelectedConfirmableElements(bool confirm) - { - // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel) - List selectedDCs = new List(selectedElements); - foreach (IDrawableContainer dc in selectedDCs) - { - if (dc.Equals(_cropContainer)) - { - DrawingMode = DrawingModes.None; - // No undo memento for the cropcontainer itself, only for the effect - RemoveElement(_cropContainer, false); - if (confirm) - { - ApplyCrop(_cropContainer.Bounds); - } - _cropContainer.Dispose(); - _cropContainer = null; - break; - } - } - } - - /// - /// Paste all the elements that are on the clipboard - /// - public void PasteElementFromClipboard() - { - IDataObject clipboard = ClipboardHelper.GetDataObject(); - - var formats = ClipboardHelper.GetFormats(clipboard); - if (formats == null || formats.Count == 0) - { - return; - } - if (LOG.IsDebugEnabled) - { - LOG.Debug("List of clipboard formats available for pasting:"); - foreach (string format in formats) - { - LOG.Debug("\tgot format: " + format); - } - } - - if (formats.Contains(typeof(IDrawableContainerList).FullName)) - { - IDrawableContainerList dcs = (IDrawableContainerList)ClipboardHelper.GetFromDataObject(clipboard, typeof(IDrawableContainerList)); - if (dcs != null) - { - // Make element(s) only move 10,10 if the surface is the same - bool isSameSurface = (dcs.ParentID == _uniqueId); - dcs.Parent = this; - var moveOffset = isSameSurface ? new Point(10, 10) : Point.Empty; - // Here a fix for bug #1475, first calculate the bounds of the complete IDrawableContainerList - Rectangle drawableContainerListBounds = Rectangle.Empty; - foreach (var element in dcs) - { - drawableContainerListBounds = drawableContainerListBounds == Rectangle.Empty ? element.DrawingBounds : Rectangle.Union(drawableContainerListBounds, element.DrawingBounds); - } - // And find a location inside the target surface to paste to - bool containersCanFit = drawableContainerListBounds.Width < Bounds.Width && drawableContainerListBounds.Height < Bounds.Height; - if (!containersCanFit) - { - Point containersLocation = drawableContainerListBounds.Location; - containersLocation.Offset(moveOffset); - if (!Bounds.Contains(containersLocation)) - { - // Easy fix for same surface - moveOffset = isSameSurface ? new Point(-10, -10) : new Point(-drawableContainerListBounds.Location.X + 10, -drawableContainerListBounds.Location.Y + 10); - } - } - else - { - Rectangle moveContainerListBounds = drawableContainerListBounds; - moveContainerListBounds.Offset(moveOffset); - // check if the element is inside - if (!Bounds.Contains(moveContainerListBounds)) - { - // Easy fix for same surface - if (isSameSurface) - { - moveOffset = new Point(-10, -10); - } - else - { - // For different surface, which is most likely smaller - int offsetX = 0; - int offsetY = 0; - if (drawableContainerListBounds.Right > Bounds.Right) - { - offsetX = Bounds.Right - drawableContainerListBounds.Right; - // Correction for the correction - if (drawableContainerListBounds.Left + offsetX < 0) - { - offsetX += Math.Abs(drawableContainerListBounds.Left + offsetX); - } - } - if (drawableContainerListBounds.Bottom > Bounds.Bottom) - { - offsetY = Bounds.Bottom - drawableContainerListBounds.Bottom; - // Correction for the correction - if (drawableContainerListBounds.Top + offsetY < 0) - { - offsetY += Math.Abs(drawableContainerListBounds.Top + offsetY); - } - } - moveOffset = new Point(offsetX, offsetY); - } - } - } - dcs.MoveBy(moveOffset.X, moveOffset.Y); - AddElements(dcs); - FieldAggregator.BindElements(dcs); - DeselectAllElements(); - SelectElements(dcs); - } - } - else if (ClipboardHelper.ContainsImage(clipboard)) - { - Point pasteLocation = GetPasteLocation(0.1f, 0.1f); - - foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) - { - if (clipboardImage != null) - { - DeselectAllElements(); - IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y); - SelectElement(container); - clipboardImage.Dispose(); - pasteLocation.X += 10; - pasteLocation.Y += 10; - } - } - } - else if (ClipboardHelper.ContainsText(clipboard)) - { - Point pasteLocation = GetPasteLocation(0.4f, 0.4f); - - string text = ClipboardHelper.GetText(clipboard); - if (text != null) - { - DeselectAllElements(); - ITextContainer textContainer = AddTextContainer(text, pasteLocation.X, pasteLocation.Y, - FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); - SelectElement(textContainer); - } - } - } - - /// - /// Find a location to paste elements. - /// If mouse is over the surface - use it's position, otherwise use the visible area. - /// Return a point in image coordinate space. - /// - /// 0.0f for the left edge of visible area, 1.0f for the right edge of visible area. - /// 0.0f for the top edge of visible area, 1.0f for the bottom edge of visible area. - private Point GetPasteLocation(float horizontalRatio = 0.5f, float verticalRatio = 0.5f) - { - var point = PointToClient(MousePosition); - var rc = GetVisibleRectangle(); - if (!rc.Contains(point)) - { - point = new Point( - rc.Left + (int)(rc.Width * horizontalRatio), - rc.Top + (int)(rc.Height * verticalRatio) - ); - } - return ToImageCoordinates(point); - } - - /// - /// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space). - /// - public Rectangle GetVisibleRectangle() - { - var bounds = Bounds; - var clientArea = Parent.ClientRectangle; - return new Rectangle( - Math.Max(0, -bounds.Left), - Math.Max(0, -bounds.Top), - clientArea.Width, - clientArea.Height - ); - } - - /// - /// Get the rectangle bounding all selected elements (in surface coordinates space), - /// or empty rectangle if nothing is selcted. - /// - public Rectangle GetSelectionRectangle() - => ToSurfaceCoordinates(selectedElements.DrawingBounds); - - /// - /// Duplicate all the selecteded elements - /// - public void DuplicateSelectedElements() - { - LOG.DebugFormat("Duplicating {0} selected elements", selectedElements.Count); - IDrawableContainerList dcs = selectedElements.Clone(); - dcs.Parent = this; - dcs.MoveBy(10, 10); - AddElements(dcs); - DeselectAllElements(); - SelectElements(dcs); - } - - /// - /// Deselect the specified element - /// - /// IDrawableContainerList - /// false to skip event generation - public void DeselectElement(IDrawableContainer container, bool generateEvents = true) - { - container.Selected = false; - selectedElements.Remove(container); - FieldAggregator.UnbindElement(container); - if (generateEvents && _movingElementChanged != null) - { - var eventArgs = new SurfaceElementEventArgs {Elements = selectedElements}; - _movingElementChanged(this, eventArgs); - } - } - - /// - /// Deselect the specified elements - /// - /// IDrawableContainerList - public void DeselectElements(IDrawableContainerList elements) - { - if (elements.Count == 0) - { - return; - } - while (elements.Count > 0) - { - var element = elements[0]; - DeselectElement(element, false); - } - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs - { - Elements = selectedElements - }; - _movingElementChanged(this, eventArgs); - } - Invalidate(); - } - - /// - /// Deselect all the selected elements - /// - public void DeselectAllElements() - { - DeselectElements(selectedElements); - } - - /// - /// Select the supplied element - /// - /// - /// false to skip invalidation - /// false to skip event generation - public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true) - { - if (!selectedElements.Contains(container)) - { - selectedElements.Add(container); - container.Selected = true; - FieldAggregator.BindElement(container); - if (generateEvents && _movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs - { - Elements = selectedElements - }; - _movingElementChanged(this, eventArgs); - } - if (invalidate) - { - container.Invalidate(); - } - } - } - - /// - /// Select all elements, this is called when Ctrl+A is pressed - /// - public void SelectAllElements() - { - SelectElements(_elements); - } - - /// - /// Select the supplied elements - /// - /// - public void SelectElements(IDrawableContainerList elements) - { - SuspendLayout(); - foreach (var drawableContainer in elements) - { - var element = (DrawableContainer) drawableContainer; - SelectElement(element, false, false); - } - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs {Elements = selectedElements}; - _movingElementChanged(this, eventArgs); - } - ResumeLayout(); - Invalidate(); - } - - /// - /// Process key presses on the surface, this is called from the editor (and NOT an override from the Control) - /// - /// Keys - /// false if no keys were processed - public bool ProcessCmdKey(Keys k) - { - if (selectedElements.Count > 0) - { - bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; - int px = shiftModifier ? 10 : 1; - Point moveBy = Point.Empty; - - switch (k) - { - case Keys.Left: - case Keys.Left | Keys.Shift: - moveBy = new Point(-px, 0); - break; - case Keys.Up: - case Keys.Up | Keys.Shift: - moveBy = new Point(0, -px); - break; - case Keys.Right: - case Keys.Right | Keys.Shift: - moveBy = new Point(px, 0); - break; - case Keys.Down: - case Keys.Down | Keys.Shift: - moveBy = new Point(0, px); - break; - case Keys.PageUp: - PullElementsUp(); - break; - case Keys.PageDown: - PushElementsDown(); - break; - case Keys.Home: - PullElementsToTop(); - break; - case Keys.End: - PushElementsToBottom(); - break; - case Keys.Enter: - ConfirmSelectedConfirmableElements(true); - break; - case Keys.Escape: - ConfirmSelectedConfirmableElements(false); - break; - /*case Keys.Delete: - RemoveSelectedElements(); - break;*/ - default: - return false; - } - if (!Point.Empty.Equals(moveBy)) - { - selectedElements.MakeBoundsChangeUndoable(true); - selectedElements.MoveBy(moveBy.X, moveBy.Y); - } - return true; - } - return false; - } - - /// - /// Property for accessing the elements on the surface - /// - public IDrawableContainerList Elements => _elements; - - /// - /// pulls selected elements up one level in hierarchy - /// - public void PullElementsUp() - { - _elements.PullElementsUp(selectedElements); - _elements.Invalidate(); - } - - /// - /// pushes selected elements up to top in hierarchy - /// - public void PullElementsToTop() - { - _elements.PullElementsToTop(selectedElements); - _elements.Invalidate(); - } - - /// - /// pushes selected elements down one level in hierarchy - /// - public void PushElementsDown() - { - _elements.PushElementsDown(selectedElements); - _elements.Invalidate(); - } - - /// - /// pushes selected elements down to bottom in hierarchy - /// - public void PushElementsToBottom() - { - _elements.PushElementsToBottom(selectedElements); - _elements.Invalidate(); - } - - /// - /// indicates whether the selected elements could be pulled up in hierarchy - /// - /// true if selected elements could be pulled up, false otherwise - public bool CanPullSelectionUp() - { - return _elements.CanPullUp(selectedElements); - } - - /// - /// indicates whether the selected elements could be pushed down in hierarchy - /// - /// true if selected elements could be pushed down, false otherwise - public bool CanPushSelectionDown() - { - return _elements.CanPushDown(selectedElements); - } - - public void Element_FieldChanged(object sender, FieldChangedEventArgs e) - { - selectedElements.HandleFieldChangedEvent(sender, e); - } - - public bool IsOnSurface(IDrawableContainer container) - { - return _elements.Contains(container); - } - - public Point ToSurfaceCoordinates(Point point) - { - Point[] points = { point }; - _zoomMatrix.TransformPoints(points); - return points[0]; - } - - public Rectangle ToSurfaceCoordinates(Rectangle rc) - { - if (_zoomMatrix.IsIdentity) - { - return rc; - } - else - { - Point[] points = { rc.Location, rc.Location + rc.Size }; - _zoomMatrix.TransformPoints(points); - return new Rectangle( - points[0].X, - points[0].Y, - points[1].X - points[0].X, - points[1].Y - points[0].Y - ); - } - } - - public Point ToImageCoordinates(Point point) - { - Point[] points = { point }; - _inverseZoomMatrix.TransformPoints(points); - return points[0]; - } - - public Rectangle ToImageCoordinates(Rectangle rc) - { - if (_inverseZoomMatrix.IsIdentity) - { - return rc; - } - else - { - Point[] points = { rc.Location, rc.Location + rc.Size }; - _inverseZoomMatrix.TransformPoints(points); - return new Rectangle( - points[0].X, - points[0].Y, - points[1].X - points[0].X, - points[1].Y - points[0].Y - ); - } - } - } -} diff --git a/Greenshot/Forms/AboutForm.cs b/Greenshot/Forms/AboutForm.cs deleted file mode 100644 index f3c67edd8..000000000 --- a/Greenshot/Forms/AboutForm.cs +++ /dev/null @@ -1,333 +0,0 @@ -/* -* Greenshot - a free and open source screenshot tool -* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom -* -* For more information see: http://getgreenshot.org/ -* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 1 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -*/ - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using System.Security.Permissions; -using System.Windows.Forms; -using Greenshot.Configuration; -using Greenshot.Helpers; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using log4net; - -namespace Greenshot.Forms { - /// - /// The about form - /// - public sealed partial class AboutForm : AnimatingBaseForm { - private static readonly ILog Log = LogManager.GetLogger(typeof(AboutForm)); - private Bitmap _bitmap; - private readonly ColorAnimator _backgroundAnimation; - private readonly List _pixels = new List(); - private readonly List _colorFlow = new List(); - private readonly List _pixelColors = new List(); - private readonly Random _rand = new Random(); - private readonly Color _backColor = Color.FromArgb(61, 61, 61); - private readonly Color _pixelColor = Color.FromArgb(138, 255, 0); - - // Variables used for the color-cycle - private int _waitFrames; - private int _colorIndex; - private int _scrollCount; - private bool _hasAnimationsLeft; - - // Variables are used to define the location of the dots - private const int W = 13; - private const int P1 = 7; - private const int P2 = P1 + W; - private const int P3 = P2 + W; - private const int P4 = P3 + W; - private const int P5 = P4 + W; - private const int P6 = P5 + W; - private const int P7 = P6 + W; - - /// - /// The location of every dot in the "G" - /// - private readonly List _gSpots = new List - { - // Top row - new Point(P2, P1), // 0 - new Point(P3, P1), // 1 - new Point(P4, P1), // 2 - new Point(P5, P1), // 3 - new Point(P6, P1), // 4 - - // Second row - new Point(P1, P2), // 5 - new Point(P2, P2), // 6 - - // Third row - new Point(P1, P3), // 7 - new Point(P2, P3), // 8 - - // Fourth row - new Point(P1, P4), // 9 - new Point(P2, P4), // 10 - new Point(P5, P4), // 11 - new Point(P6, P4), // 12 - new Point(P7, P4), // 13 - - // Fifth row - new Point(P1, P5), // 14 - new Point(P2, P5), // 15 - new Point(P6, P5), // 16 - new Point(P7, P5), // 17 - - // Sixth row - new Point(P1, P6), // 18 - new Point(P2, P6), // 19 - new Point(P3, P6), // 20 - new Point(P4, P6), // 21 - new Point(P5, P6), // 22 - new Point(P6, P6) // 23 - }; - - // 0 1 2 3 4 - // 5 6 - // 7 8 - // 9 10 11 12 13 - // 14 15 16 17 - // 18 19 20 21 22 23 - - // The order in which we draw the dots & flow the colors. - private readonly List _flowOrder = new List{ 4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11 }; - - /// - /// Cleanup all the allocated resources - /// - private void Cleanup(object sender, EventArgs e) { - if (_bitmap == null) return; - _bitmap.Dispose(); - _bitmap = null; - } - - /// - /// Constructor - /// - public AboutForm() { - // Make sure our resources are removed again. - Disposed += Cleanup; - FormClosing += Cleanup; - - // Enable animation for this form, when we don't set this the timer doesn't start as soon as the form is loaded. - EnableAnimation = true; - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - - // Only use double-buffering when we are NOT in a Terminal Server session - DoubleBuffered = !IsTerminalServerSession; - - // Use the self drawn image, first we create the background to be the back-color (as we animate from this) - - _bitmap = ImageHelper.CreateEmpty(90, 90, PixelFormat.Format24bppRgb, BackColor, 96, 96); - pictureBox1.Image = _bitmap; - - lblTitle.Text = $@"Greenshot {EnvironmentInfo.GetGreenshotVersion()} {(IniConfig.IsPortable ? " Portable" : "")} ({OsInfo.Bits}) bit)"; - - // Number of frames the pixel animation takes - int frames = FramesForMillis(2000); - // The number of frames the color-cycle waits before it starts - _waitFrames = FramesForMillis(6000); - - // Every pixel is created after pixelWaitFrames frames, which is increased in the loop. - int pixelWaitFrames = FramesForMillis(2000); - // Create pixels - for (int index = 0; index < _gSpots.Count; index++) { - // Read the pixels in the order of the flow - Point gSpot = _gSpots[_flowOrder[index]]; - // Create the animation, first we do nothing (on the final destination) - RectangleAnimator pixelAnimation; - - // Make the pixel grow from the middle, if this offset isn't used it looks like it's shifted - int offset = (W - 2) / 2; - - // If the optimize for Terminal Server is set we make the animation without much ado - if (IsTerminalServerSession) { - // No animation - pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic, EasingMode.EaseIn); - } else { - // Create the animation, first we do nothing (on the final destination) - Rectangle standingStill = new Rectangle(gSpot.X + offset, gSpot.Y + offset, 0, 0); - pixelAnimation = new RectangleAnimator(standingStill, standingStill, pixelWaitFrames, EasingType.Quintic, EasingMode.EaseIn); - // And than we size to the wanted size. - pixelAnimation.QueueDestinationLeg(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), frames); - } - // Increase the wait frames - pixelWaitFrames += FramesForMillis(100); - // Add to the list of to be animated pixels - _pixels.Add(pixelAnimation); - // Add a color to the list for this pixel. - _pixelColors.Add(_pixelColor); - } - // Make sure the frame "loop" knows we have to animate - _hasAnimationsLeft = true; - - // Pixel Color cycle colors, here we use a pre-animated loop which stores the values. - ColorAnimator pixelColorAnimator = new ColorAnimator(_pixelColor, Color.FromArgb(255, 255, 255), 6, EasingType.Quadratic, EasingMode.EaseIn); - pixelColorAnimator.QueueDestinationLeg(_pixelColor, 6, EasingType.Quadratic, EasingMode.EaseOut); - do { - _colorFlow.Add(pixelColorAnimator.Current); - pixelColorAnimator.Next(); - } while (pixelColorAnimator.HasNext); - - // color animation for the background - _backgroundAnimation = new ColorAnimator(BackColor, _backColor, FramesForMillis(5000), EasingType.Linear, EasingMode.EaseIn); - } - - /// - /// This is called when a link is clicked - /// - /// - /// - private void LinkLabelClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - if (!(sender is LinkLabel linkLabel)) return; - try { - linkLabel.LinkVisited = true; - Process.Start(linkLabel.Text); - } catch (Exception) { - MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, linkLabel.Text), Language.GetString(LangKey.error)); - } - } - - /// - /// Called from the AnimatingForm, for every frame - /// - protected override void Animate() { - if (_bitmap == null) { - return; - } - if (!IsTerminalServerSession) { - // Color cycle - if (_waitFrames != 0) { - _waitFrames--; - // Check if there is something else to do, if not we return so we don't occupy the CPU - if (!_hasAnimationsLeft) { - return; - } - } else if (_scrollCount < _pixelColors.Count + _colorFlow.Count) { - // Scroll colors, the scrollCount is the amount of pixels + the amount of colors to cycle. - for (int index = _pixelColors.Count - 1; index > 0; index--) { - _pixelColors[index] = _pixelColors[index - 1]; - } - // Keep adding from the colors to cycle until there is nothing left - if (_colorIndex < _colorFlow.Count) { - _pixelColors[0] = _colorFlow[_colorIndex++]; - } - _scrollCount++; - } else { - // Reset values, wait X time for the next one - _waitFrames = FramesForMillis(3000 + _rand.Next(35000)); - _colorIndex = 0; - _scrollCount = 0; - // Check if there is something else to do, if not we return so we don't occupy the CPU - if (!_hasAnimationsLeft) { - return; - } - } - } else if (!_hasAnimationsLeft) { - return; - } - - // Draw the "G" - using (Graphics graphics = Graphics.FromImage(_bitmap)) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - graphics.Clear(_backgroundAnimation.Next()); - - graphics.TranslateTransform(2, -2); - graphics.RotateTransform(20); - - using SolidBrush brush = new SolidBrush(_pixelColor); - int index = 0; - // We assume there is nothing to animate in the next Animate loop - _hasAnimationsLeft = false; - // Pixels of the G - foreach (RectangleAnimator pixel in _pixels) { - brush.Color = _pixelColors[index++]; - graphics.FillEllipse(brush, pixel.Current); - // If a pixel still has frames left, the hasAnimationsLeft will be true - _hasAnimationsLeft |= pixel.HasNext; - pixel.Next(); - } - } - pictureBox1.Invalidate(); - } - - /// - /// CmdKey handler - /// - /// - /// - /// - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { - try { - switch (keyData) { - case Keys.Escape: - DialogResult = DialogResult.Cancel; - break; - case Keys.E: - MessageBox.Show(EnvironmentInfo.EnvironmentToString(true)); - break; - case Keys.L: - try { - if (File.Exists(MainForm.LogFileLocation)) { - using (Process.Start("\"" + MainForm.LogFileLocation + "\"")) { - // nothing to do, just using dispose to cleanup - } - } else { - MessageBox.Show(@"Greenshot can't find the logfile, it should have been here: " + MainForm.LogFileLocation); - } - } catch (Exception) { - MessageBox.Show(@"Couldn't open the greenshot.log, it's located here: " + MainForm.LogFileLocation, @"Error opening greenshot.log", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); - } - break; - case Keys.I: - try { - using (Process.Start("\"" + IniConfig.ConfigLocation + "\"")) { - } - } catch (Exception) { - MessageBox.Show(@"Couldn't open the greenshot.ini, it's located here: " + IniConfig.ConfigLocation, @"Error opening greenshot.ini", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); - } - break; - default: - return base.ProcessCmdKey(ref msg, keyData); - } - } catch (Exception ex) { - Log.Error($"Error handling key '{keyData}'", ex); - } - return true; - } - } -} \ No newline at end of file diff --git a/Greenshot/Forms/BugReportForm.cs b/Greenshot/Forms/BugReportForm.cs deleted file mode 100644 index 7c26e1b54..000000000 --- a/Greenshot/Forms/BugReportForm.cs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Diagnostics; -using System.Windows.Forms; -using Greenshot.Configuration; -using GreenshotPlugin.Core; - -namespace Greenshot.Forms { - public partial class BugReportForm : BaseForm { - private BugReportForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - ToFront = true; - } - - public BugReportForm(string bugText) : this() { - textBoxDescription.Text = bugText; - } - - private void LinkLblBugsLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - openLink((LinkLabel)sender); - } - - private void openLink(LinkLabel link) { - try { - link.LinkVisited = true; - Process.Start(link.Text); - } catch (Exception) { - MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, link.Text), Language.GetString(LangKey.error)); - } - } - } -} diff --git a/Greenshot/Forms/CaptureForm.cs b/Greenshot/Forms/CaptureForm.cs deleted file mode 100644 index 3cc04ebf6..000000000 --- a/Greenshot/Forms/CaptureForm.cs +++ /dev/null @@ -1,1034 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Greenshot.Drawing; -using Greenshot.Helpers; -using GreenshotPlugin.Controls; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers; -using log4net; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Globalization; -using System.Security.Permissions; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; - -namespace Greenshot.Forms { - /// - /// The capture form is used to select a part of the capture - /// - public sealed partial class CaptureForm : AnimatingForm { - private enum FixMode {None, Initiated, Horizontal, Vertical}; - - private static readonly ILog Log = LogManager.GetLogger(typeof(CaptureForm)); - private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); - private static readonly Brush GreenOverlayBrush = new SolidBrush(Color.FromArgb(50, Color.MediumSeaGreen)); - private static readonly Pen OverlayPen = new Pen(Color.FromArgb(50, Color.Black)); - private static CaptureForm _currentForm; - private static readonly Brush BackgroundBrush; - - /// - /// Initialize the background brush - /// - static CaptureForm() { - Image backgroundForTransparency = GreenshotResources.GetImage("Checkerboard.Image"); - BackgroundBrush = new TextureBrush(backgroundForTransparency, WrapMode.Tile); - } - - private int _mX; - private int _mY; - private Point _mouseMovePos = Point.Empty; - private Point _cursorPos; - private CaptureMode _captureMode; - private readonly List _windows; - private WindowDetails _selectedCaptureWindow; - private bool _mouseDown; - private Rectangle _captureRect = Rectangle.Empty; - private readonly ICapture _capture; - private Point _previousMousePos = Point.Empty; - private FixMode _fixMode = FixMode.None; - private RectangleAnimator _windowAnimator; - private RectangleAnimator _zoomAnimator; - private readonly bool _isZoomerTransparent = Conf.ZoomerOpacity < 1; - private bool _isCtrlPressed; - private bool _showDebugInfo; - - /// - /// Property to access the selected capture rectangle - /// - public Rectangle CaptureRectangle => _captureRect; - - /// - /// Property to access the used capture mode - /// - public CaptureMode UsedCaptureMode => _captureMode; - - /// - /// Get the selected window - /// - public WindowDetails SelectedCaptureWindow => _selectedCaptureWindow; - - /// - /// This should prevent children to draw backgrounds - /// - protected override CreateParams CreateParams { - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - get { - CreateParams createParams = base.CreateParams; - createParams.ExStyle |= 0x02000000; - return createParams; - } - } - - private void ClosedHandler(object sender, EventArgs e) { - _currentForm = null; - // Change the final mode - if (_captureMode == CaptureMode.Text) - { - _capture.CaptureDetails.CaptureMode = CaptureMode.Text; - } - Log.Debug("Remove CaptureForm from currentForm"); - } - - private void ClosingHandler(object sender, EventArgs e) { - Log.Debug("Closing capture form"); - WindowDetails.UnregisterIgnoreHandle(Handle); - } - - /// - /// This creates the capture form - /// - /// - /// - public CaptureForm(ICapture capture, List windows) { - if (_currentForm != null) { - Log.Warn("Found currentForm, Closing already opened CaptureForm"); - _currentForm.Close(); - _currentForm = null; - Application.DoEvents(); - } - _currentForm = this; - - // Enable the AnimatingForm - EnableAnimation = true; - - // clean up - FormClosed += ClosedHandler; - - _capture = capture; - _windows = windows; - _captureMode = capture.CaptureDetails.CaptureMode; - - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - // Only double-buffer when we are not in a TerminalServerSession - DoubleBuffered = !IsTerminalServerSession; - Text = @"Greenshot capture form"; - - // Make sure we never capture the capture-form - WindowDetails.RegisterIgnoreHandle(Handle); - // Un-register at close - FormClosing += ClosingHandler; - - // set cursor location - _cursorPos = WindowCapture.GetCursorLocationRelativeToScreenBounds(); - - // Initialize the animations, the window capture zooms out from the cursor to the window under the cursor - if (_captureMode == CaptureMode.Window) { - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); - } - - // Set the zoomer animation - InitializeZoomer(Conf.ZoomerEnabled); - - SuspendLayout(); - Bounds = capture.ScreenBounds; - ResumeLayout(); - - // Fix missing focus - ToFront = true; - TopMost = true; - } - - /// - /// Create an animation for the zoomer, depending on if it's active or not. - /// - private void InitializeZoomer(bool isOn) { - if (isOn) { - // Initialize the zoom with a invalid position - _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut); - VerifyZoomAnimation(_cursorPos, false); - } - else - { - _zoomAnimator?.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), FramesForMillis(1000)); - } - } - - private void CaptureFormKeyUp(object sender, KeyEventArgs e) { - switch(e.KeyCode) { - case Keys.ShiftKey: - _fixMode = FixMode.None; - break; - case Keys.ControlKey: - _isCtrlPressed = false; - break; - } - } - - /// - /// Handle the key down event - /// - /// - /// - private void CaptureFormKeyDown(object sender, KeyEventArgs e) { - int step = _isCtrlPressed ? 10 : 1; - - switch (e.KeyCode) { - case Keys.Up: - Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y - step); - break; - case Keys.Down: - Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + step); - break; - case Keys.Left: - Cursor.Position = new Point(Cursor.Position.X - step, Cursor.Position.Y); - break; - case Keys.Right: - Cursor.Position = new Point(Cursor.Position.X + step, Cursor.Position.Y); - break; - case Keys.ShiftKey: - // Fix mode - if (_fixMode == FixMode.None) { - _fixMode = FixMode.Initiated; - } - break; - case Keys.ControlKey: - _isCtrlPressed = true; - break; - case Keys.Escape: - // Cancel - DialogResult = DialogResult.Cancel; - break; - case Keys.M: - // Toggle mouse cursor - _capture.CursorVisible = !_capture.CursorVisible; - Invalidate(); - break; - //// TODO: Enable when the screen capture code works reliable - //case Keys.V: - // // Video - // if (capture.CaptureDetails.CaptureMode != CaptureMode.Video) { - // capture.CaptureDetails.CaptureMode = CaptureMode.Video; - // } else { - // capture.CaptureDetails.CaptureMode = captureMode; - // } - // Invalidate(); - // break; - case Keys.Z: - if (_captureMode == CaptureMode.Region) { - // Toggle zoom - Conf.ZoomerEnabled = !Conf.ZoomerEnabled; - InitializeZoomer(Conf.ZoomerEnabled); - Invalidate(); - } - break; - case Keys.D: - if (_captureMode == CaptureMode.Window) - { - // Toggle debug - _showDebugInfo = !_showDebugInfo; - Invalidate(); - } - break; - case Keys.Space: - // Toggle capture mode - switch (_captureMode) { - case CaptureMode.Region: - // Set the window capture mode - _captureMode = CaptureMode.Window; - // "Fade out" Zoom - InitializeZoomer(false); - // "Fade in" window - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); - _captureRect = Rectangle.Empty; - Invalidate(); - break; - case CaptureMode.Text: - // Set the region capture mode - _captureMode = CaptureMode.Region; - Invalidate(); - break; - case CaptureMode.Window: - // Set the region capture mode - _captureMode = CaptureMode.Region; - // "Fade out" window - _windowAnimator.ChangeDestination(new Rectangle(_cursorPos, Size.Empty), FramesForMillis(700)); - // Fade in zoom - InitializeZoomer(Conf.ZoomerEnabled); - _captureRect = Rectangle.Empty; - Invalidate(); - break; - } - _selectedCaptureWindow = null; - OnMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); - break; - case Keys.Return: - // Confirm - if (_captureMode == CaptureMode.Window) { - DialogResult = DialogResult.OK; - } else if (!_mouseDown) { - HandleMouseDown(); - } else if (_mouseDown) { - HandleMouseUp(); - } - break; - case Keys.F: - ToFront = !ToFront; - TopMost = !TopMost; - break; - case Keys.T: - _captureMode = CaptureMode.Text; - if (_capture.CaptureDetails.OcrInformation is null) - { - var ocrProvider = SimpleServiceProvider.Current.GetInstance(); - if (ocrProvider != null) - { - var uiTaskScheduler = SimpleServiceProvider.Current.GetInstance(); - - Task.Factory.StartNew(async () => - { - _capture.CaptureDetails.OcrInformation = await ocrProvider.DoOcrAsync(_capture.Image); - Invalidate(); - }, CancellationToken.None, TaskCreationOptions.None, uiTaskScheduler); - } - } - else - { - Invalidate(); - } - break; - } - } - - /// - /// The mousedown handler of the capture form - /// - /// - /// - private void OnMouseDown(object sender, MouseEventArgs e) { - if (e.Button == MouseButtons.Left) { - HandleMouseDown(); - } - } - - private void HandleMouseDown() { - Point tmpCursorLocation = WindowCapture.GetCursorLocationRelativeToScreenBounds(); - _mX = tmpCursorLocation.X; - _mY = tmpCursorLocation.Y; - _mouseDown = true; - OnMouseMove(this, null); - Invalidate(); - } - - private void HandleMouseUp() { - // If the mouse goes up we set down to false (nice logic!) - _mouseDown = false; - // Check if anything is selected - if (_captureMode == CaptureMode.Window && _selectedCaptureWindow != null) { - // Go and process the capture - DialogResult = DialogResult.OK; - } else if (_captureRect.Height > 0 && _captureRect.Width > 0) { - // correct the GUI width to real width if Region mode - if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) { - _captureRect.Width += 1; - _captureRect.Height += 1; - } - // Go and process the capture - DialogResult = DialogResult.OK; - } else if (_captureMode == CaptureMode.Text && IsWordUnderCursor(_mouseMovePos)) - { - // Handle a click on a single word - _captureRect = new Rectangle(_mouseMovePos, new Size(1, 1)); - // Go and process the capture - DialogResult = DialogResult.OK; - } else { - Invalidate(); - } - - } - - /// - /// - /// - /// - /// - private bool IsWordUnderCursor(Point cursorLocation) - { - if (_captureMode != CaptureMode.Text || _capture.CaptureDetails.OcrInformation == null) return false; - - var ocrInfo = _capture.CaptureDetails.OcrInformation; - - foreach (var line in ocrInfo.Lines) - { - var lineBounds = line.CalculatedBounds; - if (lineBounds.IsEmpty) continue; - // Highlight the text which is selected - if (!lineBounds.Contains(cursorLocation)) continue; - foreach (var word in line.Words) - { - if (word.Bounds.Contains(cursorLocation)) - { - return true; - } - } - } - - return false; - } - - /// - /// The mouse up handler of the capture form - /// - /// - /// - private void OnMouseUp(object sender, MouseEventArgs e) { - if (_mouseDown) { - HandleMouseUp(); - } - } - - /// - /// This method is used to "fix" the mouse coordinates when keeping shift/ctrl pressed - /// - /// - /// - private Point FixMouseCoordinates(Point currentMouse) { - if (_fixMode == FixMode.Initiated) { - if (_previousMousePos.X != currentMouse.X) { - _fixMode = FixMode.Vertical; - } else if (_previousMousePos.Y != currentMouse.Y) { - _fixMode = FixMode.Horizontal; - } - } else if (_fixMode == FixMode.Vertical) { - currentMouse = new Point(currentMouse.X, _previousMousePos.Y); - } else if (_fixMode == FixMode.Horizontal) { - currentMouse = new Point(_previousMousePos.X, currentMouse.Y); - } - _previousMousePos = currentMouse; - return currentMouse; - } - - /// - /// The mouse move handler of the capture form - /// - /// object - /// MouseEventArgs - private void OnMouseMove(object sender, MouseEventArgs e) { - // Make sure the mouse coordinates are fixed, when pressing shift - var mouseMovePos = FixMouseCoordinates(User32.GetCursorLocation()); - _mouseMovePos = WindowCapture.GetLocationRelativeToScreenBounds(mouseMovePos); - } - - /// - /// Helper method to simplify check - /// - /// - /// - private bool IsAnimating(IAnimator animator) { - if (animator == null) { - return false; - } - return animator.HasNext; - } - - /// - /// update the frame, this only invalidates - /// - protected override void Animate() { - Point lastPos = _cursorPos; - _cursorPos = _mouseMovePos; - - if (_selectedCaptureWindow != null && lastPos.Equals(_cursorPos) && !IsAnimating(_zoomAnimator) && !IsAnimating(_windowAnimator)) { - return; - } - - WindowDetails lastWindow = _selectedCaptureWindow; - bool horizontalMove = false; - bool verticalMove = false; - - if (lastPos.X != _cursorPos.X) { - horizontalMove = true; - } - if (lastPos.Y != _cursorPos.Y) { - verticalMove = true; - } - - if ((_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) && _mouseDown) { - _captureRect = GuiRectangle.GetGuiRectangle(_cursorPos.X, _cursorPos.Y, _mX - _cursorPos.X, _mY - _cursorPos.Y); - } - - // Iterate over the found windows and check if the current location is inside a window - Point cursorPosition = Cursor.Position; - _selectedCaptureWindow = null; - lock (_windows) { - foreach (var window in _windows) { - if (!window.Contains(cursorPosition)) - { - continue; - } - // Only go over the children if we are in window mode - _selectedCaptureWindow = CaptureMode.Window == _captureMode ? window.FindChildUnderPoint(cursorPosition) : window; - break; - } - } - - if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) { - _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; - _capture.CaptureDetails.AddMetaData("windowtitle", _selectedCaptureWindow.Text); - if (_captureMode == CaptureMode.Window) { - // Here we want to capture the window which is under the mouse - _captureRect = _selectedCaptureWindow.WindowRectangle; - // As the ClientRectangle is not in Bitmap coordinates, we need to correct. - _captureRect.Offset(-_capture.ScreenBounds.Location.X, -_capture.ScreenBounds.Location.Y); - } - } - - Rectangle invalidateRectangle; - if (_mouseDown && (_captureMode != CaptureMode.Window)) { - int x1 = Math.Min(_mX, lastPos.X); - int x2 = Math.Max(_mX, lastPos.X); - int y1 = Math.Min(_mY, lastPos.Y); - int y2 = Math.Max(_mY, lastPos.Y); - x1= Math.Min(x1, _cursorPos.X); - x2= Math.Max(x2, _cursorPos.X); - y1= Math.Min(y1, _cursorPos.Y); - y2= Math.Max(y2, _cursorPos.Y); - - // Safety correction - x2 += 2; - y2 += 2; - - // Here we correct for text-size - - // Calculate the size - int textForWidth = Math.Max(Math.Abs(_mX - _cursorPos.X), Math.Abs(_mX - lastPos.X)); - int textForHeight = Math.Max(Math.Abs(_mY - _cursorPos.Y), Math.Abs(_mY - lastPos.Y)); - - using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) { - Size measureWidth = TextRenderer.MeasureText(textForWidth.ToString(CultureInfo.InvariantCulture), rulerFont); - x1 -= measureWidth.Width + 15; - - Size measureHeight = TextRenderer.MeasureText(textForHeight.ToString(CultureInfo.InvariantCulture), rulerFont); - y1 -= measureHeight.Height + 10; - } - invalidateRectangle = new Rectangle(x1,y1, x2-x1, y2-y1); - Invalidate(invalidateRectangle); - } else if (_captureMode != CaptureMode.Window) { - if (!IsTerminalServerSession) { - Rectangle allScreenBounds = WindowCapture.GetScreenBounds(); - allScreenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(allScreenBounds.Location); - if (verticalMove) { - // Before - invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, lastPos.Y - 2, Width + 2, 45); - Invalidate(invalidateRectangle); - // After - invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, _cursorPos.Y - 2, Width + 2, 45); - Invalidate(invalidateRectangle); - } - if (horizontalMove) { - // Before - invalidateRectangle = GuiRectangle.GetGuiRectangle(lastPos.X - 2, allScreenBounds.Top, 75, Height + 2); - Invalidate(invalidateRectangle); - // After - invalidateRectangle = GuiRectangle.GetGuiRectangle(_cursorPos.X - 2, allScreenBounds.Top, 75, Height + 2); - Invalidate(invalidateRectangle); - } - } - } else { - if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) { - // Window changes, make new animation from current to target - _windowAnimator.ChangeDestination(_captureRect, FramesForMillis(700)); - } - } - // always animate the Window area through to the last frame, so we see the fade-in/out untill the end - // Using a safety "offset" to make sure the text is invalidated too - const int safetySize = 30; - // Check if the animation needs to be drawn - if (IsAnimating(_windowAnimator)) { - invalidateRectangle = _windowAnimator.Current; - invalidateRectangle.Inflate(safetySize, safetySize); - Invalidate(invalidateRectangle); - invalidateRectangle = _windowAnimator.Next(); - invalidateRectangle.Inflate(safetySize, safetySize); - Invalidate(invalidateRectangle); - // Check if this was the last of the windows animations in the normal region capture. - if (_captureMode != CaptureMode.Window && !IsAnimating(_windowAnimator)) { - Invalidate(); - } - } - - if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) { - // Make sure we invalidate the old zoom area - invalidateRectangle = _zoomAnimator.Current; - invalidateRectangle.Offset(lastPos); - Invalidate(invalidateRectangle); - // Only verify if we are really showing the zoom, not the outgoing animation - if (Conf.ZoomerEnabled && _captureMode != CaptureMode.Window) { - VerifyZoomAnimation(_cursorPos, false); - } - // The following logic is not needed, next always returns the current if there are no frames left - // but it makes more sense if we want to change something in the logic - invalidateRectangle = IsAnimating(_zoomAnimator) ? _zoomAnimator.Next() : _zoomAnimator.Current; - invalidateRectangle.Offset(_cursorPos); - Invalidate(invalidateRectangle); - } - - // OCR - if (_captureMode == CaptureMode.Text && _capture.CaptureDetails.OcrInformation != null) - { - var ocrInfo = _capture.CaptureDetails.OcrInformation; - - invalidateRectangle = Rectangle.Empty; - foreach (var line in ocrInfo.Lines) - { - var lineBounds = line.CalculatedBounds; - if (!lineBounds.IsEmpty) - { - if (_mouseDown) - { - // Highlight the text which is selected - if (lineBounds.IntersectsWith(_captureRect)) - { - foreach (var word in line.Words) - { - if (word.Bounds.IntersectsWith(_captureRect)) - { - if (invalidateRectangle.IsEmpty) - { - invalidateRectangle = word.Bounds; - } - else - { - invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); - } - } - } - } - } - else if (lineBounds.Contains(_mouseMovePos)) - { - foreach (var word in line.Words) - { - if (!word.Bounds.Contains(_mouseMovePos)) continue; - if (invalidateRectangle.IsEmpty) - { - invalidateRectangle = word.Bounds; - } - else - { - invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); - } - break; - } - } - } - } - if (!invalidateRectangle.IsEmpty) - { - Invalidate(invalidateRectangle); - } - } - // Force update "now" - Update(); - } - - /// - /// This makes sure there is no background painted, as we have complete "paint" control it doesn't make sense to do otherwise. - /// - /// - protected override void OnPaintBackground(PaintEventArgs pevent) { - } - - /// - /// Checks if the Zoom area can move there where it wants to go, change direction if not. - /// - /// preferred destination location for the zoom area - /// false to try to find a location which is neither out of screen bounds nor intersects with the selected rectangle - private void VerifyZoomAnimation(Point pos, bool allowZoomOverCaptureRect) { - Rectangle screenBounds = Screen.GetBounds(MousePosition); - // convert to be relative to top left corner of all screen bounds - screenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(screenBounds.Location); - int relativeZoomSize = Math.Min(screenBounds.Width, screenBounds.Height) / 5; - // Make sure the final size is a plural of 4, this makes it look better - relativeZoomSize -= relativeZoomSize % 4; - Size zoomSize = new Size(relativeZoomSize, relativeZoomSize); - Point zoomOffset = new Point(20, 20); - - Rectangle targetRectangle = _zoomAnimator.Final; - targetRectangle.Offset(pos); - if (!screenBounds.Contains(targetRectangle) || (!allowZoomOverCaptureRect && _captureRect.IntersectsWith(targetRectangle))) { - Point destinationLocation = Point.Empty; - Rectangle tl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); - Rectangle tr = new Rectangle(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); - Rectangle bl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); - Rectangle br = new Rectangle(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); - if (screenBounds.Contains(br) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(br))) { - destinationLocation = new Point(zoomOffset.X, zoomOffset.Y); - } else if (screenBounds.Contains(bl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(bl))) { - destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, zoomOffset.Y); - } else if (screenBounds.Contains(tr) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tr))) { - destinationLocation = new Point(zoomOffset.X, -zoomOffset.Y - zoomSize.Width); - } else if (screenBounds.Contains(tl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tl))) { - destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width); - } - if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect) { - VerifyZoomAnimation(pos, true); - } else { - _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize)); - } - } - } - - /// - /// Draw the zoomed area - /// - /// - /// - /// - private void DrawZoom(Graphics graphics, Rectangle sourceRectangle, Rectangle destinationRectangle) { - if (_capture.Image == null) { - return; - } - ImageAttributes attributes; - - if (_isZoomerTransparent) { - //create a color matrix object to change the opacy - ColorMatrix opacyMatrix = new ColorMatrix - { - Matrix33 = Conf.ZoomerOpacity - }; - attributes = new ImageAttributes(); - attributes.SetColorMatrix(opacyMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); - } else { - attributes = null; - } - - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; - graphics.CompositingQuality = CompositingQuality.HighSpeed; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - using (GraphicsPath path = new GraphicsPath()) { - path.AddEllipse(destinationRectangle); - graphics.SetClip(path); - if (!_isZoomerTransparent) { - graphics.FillRectangle(BackgroundBrush, destinationRectangle); - graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); - } else { - graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, GraphicsUnit.Pixel, attributes); - } - } - int alpha = (int)(255 * Conf.ZoomerOpacity); - Color opacyWhite = Color.FromArgb(alpha, 255, 255, 255); - Color opacyBlack = Color.FromArgb(alpha, 0, 0, 0); - - // Draw the circle around the zoomer - using (Pen pen = new Pen(opacyWhite, 2)) { - graphics.DrawEllipse(pen, destinationRectangle); - } - - // Make sure we don't have a pixeloffsetmode/smoothingmode when drawing the crosshair - graphics.SmoothingMode = SmoothingMode.None; - graphics.PixelOffsetMode = PixelOffsetMode.None; - - // Calculate some values - int pixelThickness = destinationRectangle.Width / sourceRectangle.Width; - int halfWidth = destinationRectangle.Width / 2; - int halfWidthEnd = destinationRectangle.Width / 2 - pixelThickness / 2; - int halfHeight = destinationRectangle.Height / 2; - int halfHeightEnd = destinationRectangle.Height / 2 - pixelThickness / 2; - - int drawAtHeight = destinationRectangle.Y + halfHeight; - int drawAtWidth = destinationRectangle.X + halfWidth; - int padding = pixelThickness; - - // Pen to draw - using (Pen pen = new Pen(opacyBlack, pixelThickness)) { - // Draw the cross-hair-lines - // Vertical top to middle - graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + padding, drawAtWidth, destinationRectangle.Y + halfHeightEnd - padding); - // Vertical middle + 1 to bottom - graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, drawAtWidth, destinationRectangle.Y + destinationRectangle.Width - padding); - // Horizontal left to middle - graphics.DrawLine(pen, destinationRectangle.X + padding, drawAtHeight, destinationRectangle.X + halfWidthEnd - padding, drawAtHeight); - // Horizontal middle + 1 to right - graphics.DrawLine(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, destinationRectangle.X + destinationRectangle.Width - padding, drawAtHeight); - - // Fix offset for drawing the white rectangle around the cross-hair-lines - drawAtHeight -= pixelThickness / 2; - drawAtWidth -= pixelThickness / 2; - // Fix off by one error with the DrawRectangle - pixelThickness -= 1; - // Change the color and the pen width - pen.Color = opacyWhite; - pen.Width = 1; - // Vertical top to middle - graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + padding, pixelThickness, halfHeightEnd - 2 * padding - 1); - // Vertical middle + 1 to bottom - graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, pixelThickness, halfHeightEnd - 2 * padding - 1); - // Horizontal left to middle - graphics.DrawRectangle(pen, destinationRectangle.X + padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); - // Horizontal middle + 1 to right - graphics.DrawRectangle(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); - } - attributes?.Dispose(); - } - - /// - /// Paint the actual visible parts - /// - /// - /// - private void OnPaint(object sender, PaintEventArgs e) { - Graphics graphics = e.Graphics; - Rectangle clipRectangle = e.ClipRectangle; - //graphics.BitBlt((Bitmap)buffer, Point.Empty); - graphics.DrawImageUnscaled(_capture.Image, Point.Empty); - - var ocrInfo = _capture.CaptureDetails.OcrInformation; - if (ocrInfo != null && _captureMode == CaptureMode.Text) - { - using var pen = new Pen(Color.Red); - var highlightColor = Color.FromArgb(128, Color.Yellow); - using var highlightTextBrush = new SolidBrush(highlightColor); - foreach (var line in ocrInfo.Lines) - { - var lineBounds = line.CalculatedBounds; - if (!lineBounds.IsEmpty) - { - graphics.DrawRectangle(pen, line.CalculatedBounds); - if (_mouseDown) - { - // Highlight the text which is selected - if (lineBounds.IntersectsWith(_captureRect)) - { - foreach (var word in line.Words) - { - if (word.Bounds.IntersectsWith(_captureRect)) - { - graphics.FillRectangle(highlightTextBrush, word.Bounds); - } - } - } - } - else if (lineBounds.Contains(_mouseMovePos)) - { - foreach (var word in line.Words) - { - if (!word.Bounds.Contains(_mouseMovePos)) continue; - graphics.FillRectangle(highlightTextBrush, word.Bounds); - break; - } - } - } - } - } - - // Only draw Cursor if it's (partly) visible - if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new Rectangle(_capture.CursorLocation, _capture.Cursor.Size))) { - graphics.DrawIcon(_capture.Cursor, _capture.CursorLocation.X, _capture.CursorLocation.Y); - } - - if (_mouseDown || _captureMode == CaptureMode.Window || IsAnimating(_windowAnimator)) { - _captureRect.Intersect(new Rectangle(Point.Empty, _capture.ScreenBounds.Size)); // crop what is outside the screen - - var fixedRect = IsAnimating(_windowAnimator) ? _windowAnimator.Current : _captureRect; - - // TODO: enable when the screen capture code works reliable - //if (capture.CaptureDetails.CaptureMode == CaptureMode.Video) { - // graphics.FillRectangle(RedOverlayBrush, fixedRect); - //} else { - graphics.FillRectangle(GreenOverlayBrush, fixedRect); - //} - graphics.DrawRectangle(OverlayPen, fixedRect); - - // rulers - const int dist = 8; - - string captureWidth; - string captureHeight; - // The following fixes the very old incorrect size information bug - if (_captureMode == CaptureMode.Window) { - captureWidth = _captureRect.Width.ToString(CultureInfo.InvariantCulture); - captureHeight = _captureRect.Height.ToString(CultureInfo.InvariantCulture); - } else { - captureWidth = (_captureRect.Width + 1).ToString(CultureInfo.InvariantCulture); - captureHeight = (_captureRect.Height + 1).ToString(CultureInfo.InvariantCulture); - } - using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) { - Size measureWidth = TextRenderer.MeasureText(captureWidth, rulerFont); - Size measureHeight = TextRenderer.MeasureText(captureHeight, rulerFont); - int hSpace = measureWidth.Width + 3; - int vSpace = measureHeight.Height + 3; - Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227)); - Pen rulerPen = new Pen(Color.SeaGreen); - - // horizontal ruler - if (fixedRect.Width > hSpace + 3) - { - using GraphicsPath p = CreateRoundedRectangle( - fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, - fixedRect.Y - dist - 7, - measureWidth.Width - 3, - measureWidth.Height, - 3); - graphics.FillPath(bgBrush, p); - graphics.DrawPath(rulerPen, p); - graphics.DrawString(captureWidth, rulerFont, rulerPen.Brush, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, fixedRect.Y - dist - 7); - graphics.DrawLine(rulerPen, fixedRect.X, fixedRect.Y - dist, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2), fixedRect.Y - dist); - graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width / 2 + hSpace / 2, fixedRect.Y - dist, fixedRect.X + fixedRect.Width, fixedRect.Y - dist); - graphics.DrawLine(rulerPen, fixedRect.X, fixedRect.Y - dist - 3, fixedRect.X, fixedRect.Y - dist + 3); - graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width, fixedRect.Y - dist - 3, fixedRect.X + fixedRect.Width, fixedRect.Y - dist + 3); - } - - // vertical ruler - if (fixedRect.Height > vSpace + 3) - { - using GraphicsPath p = CreateRoundedRectangle( - fixedRect.X - measureHeight.Width + 1, - fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2, - measureHeight.Width - 3, - measureHeight.Height - 1, - 3); - graphics.FillPath(bgBrush, p); - graphics.DrawPath(rulerPen, p); - graphics.DrawString(captureHeight, rulerFont, rulerPen.Brush, fixedRect.X - measureHeight.Width + 1, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2); - graphics.DrawLine(rulerPen, fixedRect.X - dist, fixedRect.Y, fixedRect.X - dist, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2)); - graphics.DrawLine(rulerPen, fixedRect.X - dist, fixedRect.Y + fixedRect.Height / 2 + vSpace / 2, fixedRect.X - dist, fixedRect.Y + fixedRect.Height); - graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y, fixedRect.X - dist + 3, fixedRect.Y); - graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y + fixedRect.Height, fixedRect.X - dist + 3, fixedRect.Y + fixedRect.Height); - } - - rulerPen.Dispose(); - bgBrush.Dispose(); - } - - // Display size of selected rectangle - // Prepare the font and text. - using Font sizeFont = new Font( FontFamily.GenericSansSerif, 12 ); - // When capturing a Region we need to add 1 to the height/width for correction - string sizeText; - if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) { - // correct the GUI width to real width for the shown size - sizeText = _captureRect.Width + 1 + " x " + (_captureRect.Height + 1); - } else { - sizeText = _captureRect.Width + " x " + _captureRect.Height; - } - - // Calculate the scaled font size. - SizeF extent = graphics.MeasureString( sizeText, sizeFont ); - float hRatio = _captureRect.Height / (extent.Height * 2); - float wRatio = _captureRect.Width / (extent.Width * 2); - float ratio = hRatio < wRatio ? hRatio : wRatio; - float newSize = sizeFont.Size * ratio; - - if ( newSize >= 4 ) { - // Only show if 4pt or larger. - if (newSize > 20) { - newSize = 20; - } - // Draw the size. - using Font newSizeFont = new Font(FontFamily.GenericSansSerif, newSize, FontStyle.Bold); - PointF sizeLocation = new PointF(fixedRect.X + _captureRect.Width / 2 - extent.Width / 2, fixedRect.Y + _captureRect.Height / 2 - newSizeFont.GetHeight() / 2); - graphics.DrawString(sizeText, newSizeFont, Brushes.LightSeaGreen, sizeLocation); - - if (_showDebugInfo && _selectedCaptureWindow != null) - { - string title = $"#{_selectedCaptureWindow.Handle.ToInt64():X} - {(_selectedCaptureWindow.Text.Length > 0 ? _selectedCaptureWindow.Text : _selectedCaptureWindow.Process.ProcessName)}"; - PointF debugLocation = new PointF(fixedRect.X, fixedRect.Y); - graphics.DrawString(title, sizeFont, Brushes.DarkOrange, debugLocation); - } - } - } else { - if (!IsTerminalServerSession) { - using (Pen pen = new Pen(Color.LightSeaGreen)) { - pen.DashStyle = DashStyle.Dot; - Rectangle screenBounds = _capture.ScreenBounds; - graphics.DrawLine(pen, _cursorPos.X, screenBounds.Y, _cursorPos.X, screenBounds.Height); - graphics.DrawLine(pen, screenBounds.X, _cursorPos.Y, screenBounds.Width, _cursorPos.Y); - } - - string xy = _cursorPos.X + " x " + _cursorPos.Y; - using Font f = new Font(FontFamily.GenericSansSerif, 8); - Size xySize = TextRenderer.MeasureText(xy, f); - using GraphicsPath gp = CreateRoundedRectangle(_cursorPos.X + 5, _cursorPos.Y + 5, xySize.Width - 3, xySize.Height, 3); - using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227))) { - graphics.FillPath(bgBrush, gp); - } - using (Pen pen = new Pen(Color.SeaGreen)) { - graphics.DrawPath(pen, gp); - Point coordinatePosition = new Point(_cursorPos.X + 5, _cursorPos.Y + 5); - graphics.DrawString(xy, f, pen.Brush, coordinatePosition); - } - } - } - - // Zoom - if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) { - const int zoomSourceWidth = 25; - const int zoomSourceHeight = 25; - - Rectangle sourceRectangle = new Rectangle(_cursorPos.X - zoomSourceWidth / 2, _cursorPos.Y - zoomSourceHeight / 2, zoomSourceWidth, zoomSourceHeight); - - Rectangle destinationRectangle = _zoomAnimator.Current; - destinationRectangle.Offset(_cursorPos); - DrawZoom(graphics, sourceRectangle, destinationRectangle); - } - } - - private static GraphicsPath CreateRoundedRectangle(int x, int y, int width, int height, int radius) - { - var gp = new GraphicsPath(); - gp.AddLine(x + radius, y, x + width - radius * 2, y); // Line - gp.AddArc(x + width - radius * 2, y, radius * 2, radius * 2, 270, 90); // Corner - gp.AddLine(x + width, y + radius, x + width, y + height - radius * 2); // Line - gp.AddArc(x + width - radius * 2, y + height - radius * 2, radius * 2, radius * 2, 0, 90); // Corner - gp.AddLine(x + width - radius * 2, y + height, x + radius, y + height); // Line - gp.AddArc(x, y + height - radius * 2, radius * 2, radius * 2, 90, 90); // Corner - gp.AddLine(x, y + height - radius * 2, x, y + radius); // Line - gp.AddArc(x, y, radius * 2, radius * 2, 180, 90); // Corner - gp.CloseFigure(); - - return gp; - } - } -} diff --git a/Greenshot/Forms/ColorDialog.cs b/Greenshot/Forms/ColorDialog.cs deleted file mode 100644 index b93c01258..000000000 --- a/Greenshot/Forms/ColorDialog.cs +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Globalization; -using System.Threading; -using System.Windows.Forms; -using Greenshot.Configuration; -using Greenshot.Controls; -using GreenshotPlugin.IniFile; - -namespace Greenshot.Forms { - /// - /// Description of ColorDialog. - /// - public partial class ColorDialog : BaseForm { - private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); - private static ColorDialog _instance; - public ColorDialog() { - SuspendLayout(); - InitializeComponent(); - SuspendLayout(); - CreateColorPalette(5, 5, 15, 15); - CreateLastUsedColorButtonRow(5, 190, 15, 15); - ResumeLayout(); - UpdateRecentColorsButtonRow(); - _instance = this; - } - - public static ColorDialog GetInstance() => _instance; - - private readonly List - /// string if there is text on the clipboard - public static string GetText(IDataObject dataObject) { - if (ContainsText(dataObject)) { - return (string)dataObject.GetData(DataFormats.Text); - } - return null; - } - - /// - /// Set text to the clipboard - /// - /// - public static void SetClipboardData(string text) { - IDataObject ido = new DataObject(); - ido.SetData(DataFormats.Text, true, text); - SetDataObject(ido, true); - } - - private static string GetHtmlString(ISurface surface, string filename) { - string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardString)); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); - utf8EncodedHtmlString= utf8EncodedHtmlString.Replace("${file}", filename.Replace("\\","/")); - StringBuilder sb=new StringBuilder(); - sb.Append(utf8EncodedHtmlString); - sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); - sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)+"".Length).ToString("D8")); - sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - return sb.ToString(); - } - - private static string GetHtmlDataUrlString(ISurface surface, MemoryStream pngStream) { - string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardBase64String)); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${format}", "png"); - utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${data}", Convert.ToBase64String(pngStream.GetBuffer(),0, (int)pngStream.Length)); - StringBuilder sb=new StringBuilder(); - sb.Append(utf8EncodedHtmlString); - sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); - sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)+"".Length).ToString("D8")); - sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); - return sb.ToString(); - } - - private const int BITMAPFILEHEADER_LENGTH = 14; - /// - /// Set an Image to the clipboard - /// This method will place images to the clipboard depending on the ClipboardFormats setting. - /// e.g. Bitmap which works with pretty much everything and type Dib for e.g. OpenOffice - /// because OpenOffice has a bug http://qa.openoffice.org/issues/show_bug.cgi?id=85661 - /// The Dib (Device Indenpendend Bitmap) in 32bpp actually won't work with Powerpoint 2003! - /// When pasting a Dib in PP 2003 the Bitmap is somehow shifted left! - /// For this problem the user should not use the direct paste (=Dib), but select Bitmap - /// - public static void SetClipboardData(ISurface surface) { - DataObject dataObject = new DataObject(); - - // This will work for Office and most other applications - //ido.SetData(DataFormats.Bitmap, true, image); - - MemoryStream dibStream = null; - MemoryStream dibV5Stream = null; - MemoryStream pngStream = null; - Image imageToSave = null; - bool disposeImage = false; - try { - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); - // Create the image which is going to be saved so we don't create it multiple times - disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave); - try { - // Create PNG stream - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.PNG)) { - pngStream = new MemoryStream(); - // PNG works for e.g. Powerpoint - SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); - ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings); - pngStream.Seek(0, SeekOrigin.Begin); - // Set the PNG stream - dataObject.SetData(FORMAT_PNG, false, pngStream); - } - } catch (Exception pngEx) { - Log.Error("Error creating PNG for the Clipboard.", pngEx); - } - - try { - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIB)) { - using (MemoryStream tmpBmpStream = new MemoryStream()) { - // Save image as BMP - SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false); - ImageOutput.SaveToStream(imageToSave, null, tmpBmpStream, bmpOutputSettings); - - dibStream = new MemoryStream(); - // Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14 - dibStream.Write(tmpBmpStream.GetBuffer(), BITMAPFILEHEADER_LENGTH, (int)tmpBmpStream.Length - BITMAPFILEHEADER_LENGTH); - } - - // Set the DIB to the clipboard DataObject - dataObject.SetData(DataFormats.Dib, true, dibStream); - } - } catch (Exception dibEx) { - Log.Error("Error creating DIB for the Clipboard.", dibEx); - } - - // CF_DibV5 - try { - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIBV5)) { - // Create the stream for the clipboard - dibV5Stream = new MemoryStream(); - - // Create the BITMAPINFOHEADER - BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32) - { - // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? - biCompression = BI_COMPRESSION.BI_BITFIELDS - }; - // Create a byte[] to write - byte[] headerBytes = BinaryStructHelper.ToByteArray(header); - // Write the BITMAPINFOHEADER to the stream - dibV5Stream.Write(headerBytes, 0, headerBytes.Length); - - // As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added - BitfieldColorMask colorMask = new BitfieldColorMask(); - // Make sure the values are set - colorMask.InitValues(); - // Create the byte[] from the struct - byte[] colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask); - Array.Reverse(colorMaskBytes); - // Write to the stream - dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length); - - // Create the raw bytes for the pixels only - byte[] bitmapBytes = BitmapToByteArray((Bitmap)imageToSave); - // Write to the stream - dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length); - - // Set the DIBv5 to the clipboard DataObject - dataObject.SetData(FORMAT_17, true, dibV5Stream); - } - } catch (Exception dibEx) { - Log.Error("Error creating DIB for the Clipboard.", dibEx); - } - - // Set the HTML - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTML)) { - string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null); - string html = GetHtmlString(surface, tmpFile); - dataObject.SetText(html, TextDataFormat.Html); - } else if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTMLDATAURL)) { - string html; - using (MemoryStream tmpPngStream = new MemoryStream()) { - SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false) - { - // Do not allow to reduce the colors, some applications dislike 256 color images - // reported with bug #3594681 - DisableReduceColors = true - }; - // Check if we can use the previously used image - if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) { - ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings); - } else { - ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings); - } - html = GetHtmlDataUrlString(surface, tmpPngStream); - } - dataObject.SetText(html, TextDataFormat.Html); - } - } finally { - // we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone! - // Check if Bitmap is wanted - if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) { - dataObject.SetImage(imageToSave); - // Place the DataObject to the clipboard - SetDataObject(dataObject, true); - } else { - // Place the DataObject to the clipboard - SetDataObject(dataObject, true); - } - - pngStream?.Dispose(); - dibStream?.Dispose(); - dibV5Stream?.Dispose(); - // cleanup if needed - if (disposeImage) { - imageToSave?.Dispose(); - } - } - } - - /// - /// Helper method so get the bitmap bytes - /// See: http://stackoverflow.com/a/6570155 - /// - /// Bitmap - /// byte[] - private static byte[] BitmapToByteArray(Bitmap bitmap) { - // Lock the bitmap's bits. - Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); - BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat); - - int absStride = Math.Abs(bmpData.Stride); - int bytes = absStride * bitmap.Height; - long ptr = bmpData.Scan0.ToInt32(); - // Declare an array to hold the bytes of the bitmap. - byte[] rgbValues = new byte[bytes]; - - for (int i = 0; i < bitmap.Height; i++) { - IntPtr pointer = new IntPtr(ptr + (bmpData.Stride * i)); - Marshal.Copy(pointer, rgbValues, absStride * (bitmap.Height - i - 1), absStride); - } - - // Unlock the bits. - bitmap.UnlockBits(bmpData); - - return rgbValues; - } - - /// - /// Set Object with type Type to the clipboard - /// - /// Type - /// object - public static void SetClipboardData(Type type, object obj) { - DataFormats.Format format = DataFormats.GetFormat(type.FullName); - - //now copy to clipboard - IDataObject dataObj = new DataObject(); - dataObj.SetData(format.Name, false, obj); - // Use false to make the object disappear when the application stops. - SetDataObject(dataObj, true); - } - - /// - /// Retrieve a list of all formats currently in the IDataObject - /// - /// List of string with the current formats - public static List GetFormats(IDataObject dataObj) { - string[] formats = null; - - if (dataObj != null) { - formats = dataObj.GetFormats(); - } - if (formats != null) { - Log.DebugFormat("Got clipboard formats: {0}", string.Join(",", formats)); - return new List(formats); - } - return new List(); - } - - /// - /// Check if there is currently something on the clipboard which has the supplied format - /// - /// IDataObject - /// string with format - /// true if one the format is found - public static bool ContainsFormat(IDataObject dataObject, string format) { - return ContainsFormat(dataObject, new[] { format }); - } - - /// - /// Check if there is currently something on the clipboard which has one of the supplied formats - /// - /// string[] with formats - /// true if one of the formats was found - public static bool ContainsFormat(string[] formats) { - return ContainsFormat(GetDataObject(), formats); - } - - /// - /// Check if there is currently something on the clipboard which has one of the supplied formats - /// - /// IDataObject - /// string[] with formats - /// true if one of the formats was found - public static bool ContainsFormat(IDataObject dataObject, string[] formats) { - bool formatFound = false; - List currentFormats = GetFormats(dataObject); - if (currentFormats == null || currentFormats.Count == 0 || formats == null || formats.Length == 0) { - return false; - } - foreach (string format in formats) { - if (currentFormats.Contains(format)) { - formatFound = true; - break; - } - } - return formatFound; - } - - /// - /// Get Object for format from IDataObject - /// - /// IDataObject - /// Type to get - /// object from IDataObject - public static object GetFromDataObject(IDataObject dataObj, Type type) { - if (type != null) { - return GetFromDataObject(dataObj, type.FullName); - } - return null; - } - - /// - /// Get ImageFilenames from the IDataObject - /// - /// IDataObject - /// - public static IEnumerable GetImageFilenames(IDataObject dataObject) { - string[] dropFileNames = (string[]) dataObject.GetData(DataFormats.FileDrop); - if (dropFileNames != null && dropFileNames.Length > 0) - { - return dropFileNames - .Where(filename => !string.IsNullOrEmpty(filename)) - .Where(Path.HasExtension) - .Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1))); - } - return Enumerable.Empty(); - } - - /// - /// Get Object for format from IDataObject - /// - /// IDataObject - /// format to get - /// object from IDataObject - public static object GetFromDataObject(IDataObject dataObj, string format) { - if (dataObj != null) { - try { - return dataObj.GetData(format); - } catch (Exception e) { - Log.Error("Error in GetClipboardData.", e); - } - } - return null; - } - } -} diff --git a/GreenshotPlugin/Core/CoreConfiguration.cs b/GreenshotPlugin/Core/CoreConfiguration.cs deleted file mode 100644 index 9a5ef5270..000000000 --- a/GreenshotPlugin/Core/CoreConfiguration.cs +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.IO; -using System.Reflection; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; - -namespace GreenshotPlugin.Core { - public enum ClipboardFormat { - PNG, DIB, HTML, HTMLDATAURL, BITMAP, DIBV5 - } - public enum OutputFormat { - bmp, gif, jpg, png, tiff, greenshot, ico - } - public enum WindowCaptureMode { - Screen, GDI, Aero, AeroTransparent, Auto - } - - public enum BuildStates { - UNSTABLE, - RELEASE_CANDIDATE, - RELEASE - } - - public enum ClickActions { - DO_NOTHING, - OPEN_LAST_IN_EXPLORER, - OPEN_LAST_IN_EDITOR, - OPEN_SETTINGS, - SHOW_CONTEXT_MENU - } - - /// - /// Description of CoreConfiguration. - /// - [IniSection("Core", Description="Greenshot core configuration")] - public class CoreConfiguration : IniSection, INotifyPropertyChanged { - public event PropertyChangedEventHandler PropertyChanged; - - [IniProperty("Language", Description = "The language in IETF format (e.g. en-US)")] - public string Language { get; set; } - - [IniProperty("RegionHotkey", Description="Hotkey for starting the region capture", DefaultValue="PrintScreen")] - public string RegionHotkey { get; set; } - [IniProperty("WindowHotkey", Description="Hotkey for starting the window capture", DefaultValue="Alt + PrintScreen")] - public string WindowHotkey { get; set; } - [IniProperty("FullscreenHotkey", Description="Hotkey for starting the fullscreen capture", DefaultValue="Ctrl + PrintScreen")] - public string FullscreenHotkey { get; set; } - [IniProperty("LastregionHotkey", Description="Hotkey for starting the last region capture", DefaultValue="Shift + PrintScreen")] - public string LastregionHotkey { get; set; } - [IniProperty("IEHotkey", Description="Hotkey for starting the IE capture", DefaultValue="Shift + Ctrl + PrintScreen")] - public string IEHotkey { get; set; } - - [IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor")] - public string ClipboardHotkey { get; set; } - - [IniProperty("IsFirstLaunch", Description="Is this the first time launch?", DefaultValue="true")] - public bool IsFirstLaunch { get; set; } - [IniProperty("Destinations", Separator=",", Description="Which destinations? Possible options (more might be added by plugins) are: Editor, FileDefault, FileWithDialog, Clipboard, Printer, EMail, Picker", DefaultValue="Picker")] - public List OutputDestinations { get; set; } = new List(); - [IniProperty("ClipboardFormats", Separator=",", Description="Specify which formats we copy on the clipboard? Options are: PNG, HTML, HTMLDATAURL and DIB", DefaultValue="PNG,DIB")] - public List ClipboardFormats { get; set; } = new List(); - - [IniProperty("CaptureMousepointer", Description="Should the mouse be captured?", DefaultValue="true")] - public bool CaptureMousepointer { get; set; } - [IniProperty("CaptureWindowsInteractive", Description="Use interactive window selection to capture? (false=Capture active window)", DefaultValue="false")] - public bool CaptureWindowsInteractive { get; set; } - [IniProperty("CaptureDelay", Description="Capture delay in millseconds.", DefaultValue="100")] - public int CaptureDelay { get; set; } - [IniProperty("ScreenCaptureMode", Description = "The capture mode used to capture a screen. (Auto, FullScreen, Fixed)", DefaultValue = "Auto")] - public ScreenCaptureMode ScreenCaptureMode { get; set; } - [IniProperty("ScreenToCapture", Description = "The screen number to capture when using ScreenCaptureMode Fixed.", DefaultValue = "1")] - public int ScreenToCapture { get; set; } - [IniProperty("WindowCaptureMode", Description = "The capture mode used to capture a Window (Screen, GDI, Aero, AeroTransparent, Auto).", DefaultValue = "Auto")] - public WindowCaptureMode WindowCaptureMode { get; set; } - [IniProperty("WindowCaptureAllChildLocations", Description="Enable/disable capture all children, very slow but will make it possible to use this information in the editor.", DefaultValue="False")] - public bool WindowCaptureAllChildLocations { get; set; } - - [IniProperty("DWMBackgroundColor", Description="The background color for a DWM window capture.")] - public Color DWMBackgroundColor { get; set; } - - [IniProperty("PlayCameraSound", LanguageKey="settings_playsound",Description="Play a camera sound after taking a capture.", DefaultValue="false")] - public bool PlayCameraSound { get; set; } = false; - [IniProperty("ShowTrayNotification", LanguageKey="settings_shownotify",Description="Show a notification from the systray when a capture is taken.", DefaultValue="true")] - public bool ShowTrayNotification { get; set; } = true; - - [IniProperty("OutputFilePath", Description="Output file path.")] - public string OutputFilePath { get; set; } - [IniProperty("OutputFileAllowOverwrite", Description = "If the target file already exists True will make Greenshot always overwrite and False will display a 'Save-As' dialog.", DefaultValue = "true")] - public bool OutputFileAllowOverwrite { get; set; } - [IniProperty("OutputFileFilenamePattern", Description = "Filename pattern for screenshot.", DefaultValue = "${capturetime:d\"yyyy-MM-dd HH_mm_ss\"}-${title}")] - public string OutputFileFilenamePattern { get; set; } - [IniProperty("OutputFileFormat", Description="Default file type for writing screenshots. (bmp, gif, jpg, png, tiff)", DefaultValue="png")] - public OutputFormat OutputFileFormat { get; set; } = OutputFormat.png; - [IniProperty("OutputFileReduceColors", Description="If set to true, than the colors of the output file are reduced to 256 (8-bit) colors", DefaultValue="false")] - public bool OutputFileReduceColors { get; set; } - [IniProperty("OutputFileAutoReduceColors", Description = "If set to true the amount of colors is counted and if smaller than 256 the color reduction is automatically used.", DefaultValue = "false")] - public bool OutputFileAutoReduceColors { get; set; } - [IniProperty("OutputFileReduceColorsTo", Description = "Amount of colors to reduce to, when reducing", DefaultValue = "256")] - public int OutputFileReduceColorsTo { get; set; } - - [IniProperty("OutputFileCopyPathToClipboard", Description="When saving a screenshot, copy the path to the clipboard?", DefaultValue="true")] - public bool OutputFileCopyPathToClipboard { get; set; } - [IniProperty("OutputFileAsFullpath", Description="SaveAs Full path?")] - public string OutputFileAsFullpath { get; set; } - - [IniProperty("OutputFileJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int OutputFileJpegQuality { get; set; } - [IniProperty("OutputFilePromptQuality", Description="Ask for the quality before saving?", DefaultValue="false")] - public bool OutputFilePromptQuality { get; set; } - [IniProperty("OutputFileIncrementingNumber", Description="The number for the ${NUM} in the filename pattern, is increased automatically after each save.", DefaultValue="1")] - public uint OutputFileIncrementingNumber { get; set; } - - [IniProperty("OutputPrintPromptOptions", LanguageKey="settings_alwaysshowprintoptionsdialog", Description="Ask for print options when printing?", DefaultValue="true")] - public bool OutputPrintPromptOptions { get; set; } - [IniProperty("OutputPrintAllowRotate", LanguageKey="printoptions_allowrotate", Description="Allow rotating the picture for fitting on paper?", DefaultValue="false")] - public bool OutputPrintAllowRotate { get; set; } - [IniProperty("OutputPrintAllowEnlarge", LanguageKey="printoptions_allowenlarge", Description="Allow growing the picture for fitting on paper?", DefaultValue="false")] - public bool OutputPrintAllowEnlarge { get; set; } - [IniProperty("OutputPrintAllowShrink", LanguageKey="printoptions_allowshrink", Description="Allow shrinking the picture for fitting on paper?", DefaultValue="true")] - public bool OutputPrintAllowShrink { get; set; } - [IniProperty("OutputPrintCenter", LanguageKey="printoptions_allowcenter", Description="Center image when printing?", DefaultValue="true")] - public bool OutputPrintCenter { get; set; } - [IniProperty("OutputPrintInverted", LanguageKey="printoptions_inverted", Description="Print image inverted (use e.g. for console captures)", DefaultValue="false")] - public bool OutputPrintInverted { get; set; } - [IniProperty("OutputPrintGrayscale", LanguageKey = "printoptions_printgrayscale", Description = "Force grayscale printing", DefaultValue = "false")] - public bool OutputPrintGrayscale { get; set; } - [IniProperty("OutputPrintMonochrome", LanguageKey = "printoptions_printmonochrome", Description = "Force monorchrome printing", DefaultValue = "false")] - public bool OutputPrintMonochrome { get; set; } - [IniProperty("OutputPrintMonochromeThreshold", Description = "Threshold for monochrome filter (0 - 255), lower value means less black", DefaultValue = "127")] - public byte OutputPrintMonochromeThreshold { get; set; } - [IniProperty("OutputPrintFooter", LanguageKey = "printoptions_timestamp", Description = "Print footer on print?", DefaultValue = "true")] - public bool OutputPrintFooter { get; set; } - [IniProperty("OutputPrintFooterPattern", Description = "Footer pattern", DefaultValue = "${capturetime:d\"D\"} ${capturetime:d\"T\"} - ${title}")] - public string OutputPrintFooterPattern { get; set; } - [IniProperty("NotificationSound", Description = "The wav-file to play when a capture is taken, loaded only once at the Greenshot startup", DefaultValue="default")] - public string NotificationSound { get; set; } - [IniProperty("UseProxy", Description="Use your global proxy?", DefaultValue="True")] - public bool UseProxy { get; set; } - [IniProperty("IECapture", Description="Enable/disable IE capture", DefaultValue="True")] - public bool IECapture { get; set; } - [IniProperty("IEFieldCapture", Description="Enable/disable IE field capture, very slow but will make it possible to annotate the fields of a capture in the editor.", DefaultValue="False")] - public bool IEFieldCapture { get; set; } - [IniProperty("WindowClassesToCheckForIE", Description = "Comma separated list of Window-Classes which need to be checked for a IE instance!", DefaultValue = "AfxFrameOrView70,IMWindowClass")] - public List WindowClassesToCheckForIE { get; set; } - [IniProperty("AutoCropDifference", Description="Sets how to compare the colors for the autocrop detection, the higher the more is 'selected'. Possible values are from 0 to 255, where everything above ~150 doesn't make much sense!", DefaultValue="10")] - public int AutoCropDifference { get; set; } - - [IniProperty("IncludePlugins", Description="Comma separated list of Plugins which are allowed. If something in the list, than every plugin not in the list will not be loaded!")] - public List IncludePlugins { get; set; } - [IniProperty("ExcludePlugins", Description="Comma separated list of Plugins which are NOT allowed.")] - public List ExcludePlugins { get; set; } - [IniProperty("ExcludeDestinations", Description = "Comma separated list of destinations which should be disabled.")] - public List ExcludeDestinations { get; set; } - - [IniProperty("UpdateCheckInterval", Description="How many days between every update check? (0=no checks)", DefaultValue="14")] - public int UpdateCheckInterval { get; set; } - [IniProperty("LastUpdateCheck", Description="Last update check")] - public DateTime LastUpdateCheck { get; set; } - - [IniProperty("DisableSettings", Description = "Enable/disable the access to the settings, can only be changed manually in this .ini", DefaultValue = "False")] - public bool DisableSettings { get; set; } - [IniProperty("DisableQuickSettings", Description = "Enable/disable the access to the quick settings, can only be changed manually in this .ini", DefaultValue = "False")] - public bool DisableQuickSettings { get; set; } - [IniProperty("DisableTrayicon", Description = "Disable the trayicon, can only be changed manually in this .ini", DefaultValue = "False")] - public bool HideTrayicon { get; set; } - [IniProperty("HideExpertSettings", Description = "Hide expert tab in the settings, can only be changed manually in this .ini", DefaultValue = "False")] - public bool HideExpertSettings { get; set; } - - [IniProperty("ThumnailPreview", Description="Enable/disable thumbnail previews", DefaultValue="True")] - public bool ThumnailPreview { get; set; } - - [IniProperty("NoGDICaptureForProduct", Description = "List of productnames for which GDI capturing is skipped (using fallback).", DefaultValue = "IntelliJ IDEA")] - public List NoGDICaptureForProduct { get; set; } - [IniProperty("NoDWMCaptureForProduct", Description = "List of productnames for which DWM capturing is skipped (using fallback).", DefaultValue = "Citrix ICA Client")] - public List NoDWMCaptureForProduct { get; set; } - - [IniProperty("OptimizeForRDP", Description="Make some optimizations for usage with remote desktop", DefaultValue="False")] - public bool OptimizeForRDP { get; set; } - [IniProperty("DisableRDPOptimizing", Description = "Disable all optimizations for usage with remote desktop", DefaultValue = "False")] - public bool DisableRDPOptimizing { get; set; } - - [IniProperty("MinimizeWorkingSetSize", Description="Optimize memory footprint, but with a performance penalty!", DefaultValue="False")] - public bool MinimizeWorkingSetSize { get; set; } - - [IniProperty("WindowCaptureRemoveCorners", Description = "Remove the corners from a window capture", DefaultValue = "True")] - public bool WindowCaptureRemoveCorners { get; set; } - - [IniProperty("CheckForUnstable", Description = "Also check for unstable version updates", DefaultValue = "False")] - public bool CheckForUnstable { get; set; } - - [IniProperty("ActiveTitleFixes", Description="The fixes that are active.")] - public List ActiveTitleFixes { get; set; } - - [IniProperty("TitleFixMatcher", Description="The regular expressions to match the title with.")] - public Dictionary TitleFixMatcher { get; set; } - - [IniProperty("TitleFixReplacer", Description="The replacements for the matchers.")] - public Dictionary TitleFixReplacer { get; set; } - - [IniProperty("ExperimentalFeatures", Description="A list of experimental features, this allows us to test certain features before releasing them.", ExcludeIfNull=true)] - public List ExperimentalFeatures { get; set; } - - [IniProperty("EnableSpecialDIBClipboardReader", Description = "Enable a special DIB clipboard reader", DefaultValue="True")] - public bool EnableSpecialDIBClipboardReader { get; set; } - - [IniProperty("WindowCornerCutShape", Description = "The cutshape which is used to remove the window corners, is mirrorred for all corners", DefaultValue = "5,3,2,1,1")] - public List WindowCornerCutShape { get; set; } - - [IniProperty("LeftClickAction", Description = "Specify what action is made if the tray icon is left clicked, if a double-click action is specified this action is initiated after a delay (configurable via the windows double-click speed)", DefaultValue = "SHOW_CONTEXT_MENU")] - public ClickActions LeftClickAction { get; set; } - - [IniProperty("DoubleClickAction", Description = "Specify what action is made if the tray icon is double clicked", DefaultValue = "OPEN_LAST_IN_EXPLORER")] - public ClickActions DoubleClickAction { get; set; } - - [IniProperty("ZoomerEnabled", Description = "Sets if the zoomer is enabled", DefaultValue = "True")] - public bool ZoomerEnabled { get; set; } - [IniProperty("ZoomerOpacity", Description = "Specify the transparency for the zoomer, from 0-1 (where 1 is no transparency and 0 is complete transparent. An usefull setting would be 0.7)", DefaultValue = "1")] - public float ZoomerOpacity { get; set; } - - [IniProperty("MaxMenuItemLength", Description = "Maximum length of submenu items in the context menu, making this longer might cause context menu issues on dual screen systems.", DefaultValue = "25")] - public int MaxMenuItemLength { get; set; } - - [IniProperty("MailApiTo", Description = "The 'to' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] - public string MailApiTo { get; set; } - [IniProperty("MailApiCC", Description = "The 'CC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] - public string MailApiCC { get; set; } - [IniProperty("MailApiBCC", Description = "The 'BCC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] - public string MailApiBCC { get; set; } - - [IniProperty("OptimizePNGCommand", Description = "Optional command to execute on a temporary PNG file, the command should overwrite the file and Greenshot will read it back. Note: this command is also executed when uploading PNG's!", DefaultValue = "")] - public string OptimizePNGCommand { get; set; } - [IniProperty("OptimizePNGCommandArguments", Description = "Arguments for the optional command to execute on a PNG, {0} is replaced by the temp-filename from Greenshot. Note: Temp-file is deleted afterwards by Greenshot.", DefaultValue = "\"{0}\"")] - public string OptimizePNGCommandArguments { get; set; } - - [IniProperty("LastSaveWithVersion", Description = "Version of Greenshot which created this .ini")] - public string LastSaveWithVersion { get; set; } - - [IniProperty("ProcessEXIFOrientation", Description = "When reading images from files or clipboard, use the EXIF information to correct the orientation", DefaultValue = "True")] - public bool ProcessEXIFOrientation { get; set; } - - [IniProperty("LastCapturedRegion", Description = "The last used region, for reuse in the capture last region")] - public Rectangle LastCapturedRegion { get; set; } - - [IniProperty("Win10BorderCrop", Description = "The capture is cropped with these settings, e.g. when you don't want to color around it -1,-1"), DefaultValue("0,0")] - public Size Win10BorderCrop { get; set; } - - private Size _iconSize; - [IniProperty("BaseIconSize", Description = "Defines the base size of the icons (e.g. for the buttons in the editor), default value 16,16 and it's scaled to the current DPI", DefaultValue = "16,16")] - public Size IconSize { - get { - return _iconSize; - } - set { - Size newSize = value; - if (newSize != Size.Empty) { - if (newSize.Width < 16) { - newSize.Width = 16; - } else if (newSize.Width > 256) { - newSize.Width = 256; - } - newSize.Width = (newSize.Width / 16) * 16; - if (newSize.Height < 16) { - newSize.Height = 16; - } else if (IconSize.Height > 256) { - newSize.Height = 256; - } - newSize.Height = (newSize.Height / 16) * 16; - } - if (_iconSize != newSize) { - _iconSize = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IconSize")); - } - } - } - - public Size ScaledIconSize => DpiHelper.ScaleWithCurrentDpi(_iconSize); - - [IniProperty("WebRequestTimeout", Description = "The connect timeout value for webrequets, these are seconds", DefaultValue = "100")] - public int WebRequestTimeout { get; set; } - [IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")] - public int WebRequestReadWriteTimeout { get; set; } - - public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32; - - /// - /// A helper method which returns true if the supplied experimental feature is enabled - /// - /// - /// - public bool IsExperimentalFeatureEnabled(string experimentalFeature) { - return (ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature)); - } - - /// - /// Supply values we can't put as defaults - /// - /// The property to return a default for - /// object with the default value for the supplied property - public override object GetDefault(string property) { - switch(property) { - case "PluginWhitelist": - case "PluginBacklist": - return new List(); - case "OutputFileAsFullpath": - if (IniConfig.IsPortable) { - return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png"); - } - return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),"dummy.png"); - case "OutputFilePath": - if (IniConfig.IsPortable) { - string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots"); - if (!Directory.Exists(pafOutputFilePath)) { - try { - Directory.CreateDirectory(pafOutputFilePath); - return pafOutputFilePath; - } catch (Exception ex) { - LOG.Warn(ex); - // Problem creating directory, fallback to Desktop - } - } else { - return pafOutputFilePath; - } - } - return Environment.GetFolderPath(Environment.SpecialFolder.Desktop); - case "DWMBackgroundColor": - return Color.Transparent; - case "ActiveTitleFixes": - return new List {"Firefox", "IE", "Chrome"}; - case "TitleFixMatcher": - return new Dictionary {{"Firefox", " - Mozilla Firefox.*"}, {"IE", " - (Microsoft|Windows) Internet Explorer.*"}, {"Chrome", " - Google Chrome.*"}}; - case "TitleFixReplacer": - return new Dictionary {{"Firefox", string.Empty }, {"IE", string.Empty }, {"Chrome", string.Empty } }; - } - return null; - } - - /// - /// This method will be called before converting the property, making to possible to correct a certain value - /// Can be used when migration is needed - /// - /// The name of the property - /// The string value of the property - /// string with the propertyValue, modified or not... - public override string PreCheckValue(string propertyName, string propertyValue) { - // Changed the separator, now we need to correct this - if ("Destinations".Equals(propertyName)) { - if (propertyValue != null) { - return propertyValue.Replace('|',','); - } - } - if("OutputFilePath".Equals(propertyName)) { - if (string.IsNullOrEmpty(propertyValue)) { - return null; - } - } - return base.PreCheckValue(propertyName, propertyValue); - } - - /// - /// This method will be called before writing the configuration - /// - public override void BeforeSave() { - try { - // Store version, this can be used later to fix settings after an update - LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); - } - catch - { - // ignored - } - } - - /// - /// This method will be called after reading the configuration, so eventually some corrections can be made - /// - public override void AfterLoad() { - // Comment with releases - // CheckForUnstable = true; - - if (string.IsNullOrEmpty(LastSaveWithVersion)) { - try { - // Store version, this can be used later to fix settings after an update - LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); - } - catch - { - // ignored - } - // Disable the AutoReduceColors as it causes issues with Mozzila applications and some others - OutputFileAutoReduceColors = false; - } - - // Fix for excessive feed checking - if (UpdateCheckInterval != 0 && UpdateCheckInterval <= 7 && LastSaveWithVersion.StartsWith("1.2")) - { - UpdateCheckInterval = 14; - } - if (UpdateCheckInterval > 365) - { - UpdateCheckInterval = 365; - } - - // Enable OneNote if upgrading from 1.1 - if (ExcludeDestinations != null && ExcludeDestinations.Contains("OneNote")) { - if(LastSaveWithVersion != null && LastSaveWithVersion.StartsWith("1.1")) { - ExcludeDestinations.Remove("OneNote"); - } else { - // TODO: Remove with the release - ExcludeDestinations.Remove("OneNote"); - } - } - - if (OutputDestinations == null) { - OutputDestinations = new List(); - } - - // Make sure there is an output! - if (OutputDestinations.Count == 0) { - OutputDestinations.Add("Editor"); - } - - // Prevent both settings at once, bug #3435056 - if (OutputDestinations.Contains("Clipboard") && OutputFileCopyPathToClipboard) { - OutputFileCopyPathToClipboard = false; - } - - // Make sure we have clipboard formats, otherwise a paste doesn't make sense! - if (ClipboardFormats == null || ClipboardFormats.Count == 0) { - ClipboardFormats = new List {ClipboardFormat.PNG, ClipboardFormat.HTML, ClipboardFormat.DIB}; - } - - // Make sure the lists are lowercase, to speedup the check - if (NoGDICaptureForProduct != null) { - // Fix error in configuration - if (NoGDICaptureForProduct.Count >= 2) { - if ("intellij".Equals(NoGDICaptureForProduct[0]) && "idea".Equals(NoGDICaptureForProduct[1])) { - NoGDICaptureForProduct.RemoveRange(0, 2); - NoGDICaptureForProduct.Add("Intellij Idea"); - IsDirty = true; - } - } - for (int i = 0; i < NoGDICaptureForProduct.Count; i++) { - NoGDICaptureForProduct[i] = NoGDICaptureForProduct[i].ToLower(); - } - } - if (NoDWMCaptureForProduct != null) { - // Fix error in configuration - if (NoDWMCaptureForProduct.Count >= 3) { - if ("citrix".Equals(NoDWMCaptureForProduct[0]) && "ica".Equals(NoDWMCaptureForProduct[1]) && "client".Equals(NoDWMCaptureForProduct[2])) { - NoDWMCaptureForProduct.RemoveRange(0, 3); - NoDWMCaptureForProduct.Add("Citrix ICA Client"); - IsDirty = true; - } - } - for (int i = 0; i < NoDWMCaptureForProduct.Count; i++) { - NoDWMCaptureForProduct[i] = NoDWMCaptureForProduct[i].ToLower(); - } - } - - if (AutoCropDifference < 0) { - AutoCropDifference = 0; - } - if (AutoCropDifference > 255) { - AutoCropDifference = 255; - } - if (OutputFileReduceColorsTo < 2) { - OutputFileReduceColorsTo = 2; - } - if (OutputFileReduceColorsTo > 256) { - OutputFileReduceColorsTo = 256; - } - - if (WebRequestTimeout <= 10) { - WebRequestTimeout = 100; - } - if (WebRequestReadWriteTimeout < 1) { - WebRequestReadWriteTimeout = 100; - } - } - - /// - /// Validate the OutputFilePath, and if this is not correct it will be set to the default - /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) - /// - public void ValidateAndCorrectOutputFilePath() - { - if (!Directory.Exists(OutputFilePath)) - { - OutputFilePath = GetDefault(nameof(OutputFilePath)) as string; - } - } - /// - /// Validate the OutputFileAsFullpath, and if this is not correct it will be set to the default - /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) - /// - public void ValidateAndCorrectOutputFileAsFullpath() - { - var outputFilePath = Path.GetDirectoryName(OutputFileAsFullpath); - if (outputFilePath == null || (!File.Exists(OutputFileAsFullpath) && !Directory.Exists(outputFilePath))) - { - OutputFileAsFullpath = GetDefault(nameof(OutputFileAsFullpath)) as string; - } - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/CredentialsHelper.cs b/GreenshotPlugin/Core/CredentialsHelper.cs deleted file mode 100644 index 49b720b25..000000000 --- a/GreenshotPlugin/Core/CredentialsHelper.cs +++ /dev/null @@ -1,469 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using System.Windows.Forms; - -namespace GreenshotPlugin.Core { - /// - /// The following code comes from: http://www.developerfusion.com/code/4693/using-the-credential-management-api/ - /// and is slightly modified so it works for us. - /// As the "Stored usernames and passwords" which can be accessed by: Start-> Run and type "Control keymgr.dll" - /// doesn't show all credentials use the tool here: http://www.microsoft.com/indonesia/msdn/credmgmt.aspx - /// The following code is an example for a login, it will call the Authenticate with user/password - /// which should return true if the login worked, false if not. - /// private static bool Login(string system, string name) { - /// try { - /// CredentialsDialog dialog = new CredentialsDialog(system); - /// dialog.Name = name; - /// while (dialog.Show(dialog.Name) == DialogResult.OK) { - /// if (Authenticate(dialog.Name, dialog.Password)) { - /// if (dialog.SaveChecked) dialog.Confirm(true); - /// return true; - /// } else { - /// try { - /// dialog.Confirm(false); - /// } catch (ApplicationException) { - /// // exception handling ... - /// } - /// dialog.IncorrectPassword = true; - /// } - /// } - /// } catch (ApplicationException) { - /// // exception handling ... - /// } - /// return false; - /// } - /// - /// Encapsulates dialog functionality from the Credential Management API. - public sealed class CredentialsDialog { - [DllImport("gdi32.dll", SetLastError=true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); - - /// The only valid bitmap height (in pixels) of a user-defined banner. - private const int ValidBannerHeight = 60; - - /// The only valid bitmap width (in pixels) of a user-defined banner. - private const int ValidBannerWidth = 320; - - /// Initializes a new instance of the class - /// with the specified target. - /// The name of the target for the credentials, typically a server name. - public CredentialsDialog(string target) : this(target, null) { - } - - /// Initializes a new instance of the class - /// with the specified target and caption. - /// The name of the target for the credentials, typically a server name. - /// The caption of the dialog (null will cause a system default title to be used). - public CredentialsDialog(string target, string caption) : this(target, caption, null) { - } - - /// Initializes a new instance of the class - /// with the specified target, caption and message. - /// The name of the target for the credentials, typically a server name. - /// The caption of the dialog (null will cause a system default title to be used). - /// The message of the dialog (null will cause a system default message to be used). - public CredentialsDialog(string target, string caption, string message) : this(target, caption, message, null) { - } - - /// Initializes a new instance of the class - /// with the specified target, caption, message and banner. - /// The name of the target for the credentials, typically a server name. - /// The caption of the dialog (null will cause a system default title to be used). - /// The message of the dialog (null will cause a system default message to be used). - /// The image to display on the dialog (null will cause a system default image to be used). - public CredentialsDialog(string target, string caption, string message, Image banner) { - Target = target; - Caption = caption; - Message = message; - Banner = banner; - } - - /// - /// Gets or sets if the dialog will be shown even if the credentials - /// can be returned from an existing credential in the credential manager. - /// - public bool AlwaysDisplay { get; set; } - - /// Gets or sets if the dialog is populated with name/password only. - public bool ExcludeCertificates { get; set; } = true; - - /// Gets or sets if the credentials are to be persisted in the credential manager. - public bool Persist { get; set; } = true; - - /// Gets or sets if the incorrect password balloontip needs to be shown. Introduced AFTER Windows XP - public bool IncorrectPassword { get; set; } - - /// Gets or sets if the name is read-only. - public bool KeepName { get; set; } - - private string _name = string.Empty; - /// Gets or sets the name for the credentials. - public string Name { - get { - return _name; - } - set { - if (value?.Length > CredUi.MAX_USERNAME_LENGTH) { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The name has a maximum length of {0} characters.", - CredUi.MAX_USERNAME_LENGTH); - throw new ArgumentException(message, nameof(Name)); - } - _name = value; - } - } - - private string _password = string.Empty; - /// Gets or sets the password for the credentials. - public string Password { - get { - return _password; - } - set { - if (value?.Length > CredUi.MAX_PASSWORD_LENGTH) { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The password has a maximum length of {0} characters.", - CredUi.MAX_PASSWORD_LENGTH); - throw new ArgumentException(message, nameof(Password)); - } - _password = value; - } - } - - /// Gets or sets if the save checkbox status. - public bool SaveChecked { get; set; } - - /// Gets or sets if the save checkbox is displayed. - /// This value only has effect if Persist is true. - public bool SaveDisplayed { get; set; } = true; - - private string _target = string.Empty; - /// Gets or sets the name of the target for the credentials, typically a server name. - public string Target { - get { - return _target; - } - set { - if (value == null) { - throw new ArgumentException("The target cannot be a null value.", nameof(Target)); - } - if (value.Length > CredUi.MAX_GENERIC_TARGET_LENGTH) { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The target has a maximum length of {0} characters.", - CredUi.MAX_GENERIC_TARGET_LENGTH); - throw new ArgumentException(message, nameof(Target)); - } - _target = value; - } - } - - private string _caption = string.Empty; - /// Gets or sets the caption of the dialog. - /// A null value will cause a system default caption to be used. - public string Caption { - get { - return _caption; - } - set { - if (value?.Length > CredUi.MAX_CAPTION_LENGTH) { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The caption has a maximum length of {0} characters.", - CredUi.MAX_CAPTION_LENGTH); - throw new ArgumentException(message, nameof(Caption)); - } - _caption = value; - } - } - - private string _message = string.Empty; - /// Gets or sets the message of the dialog. - /// A null value will cause a system default message to be used. - public string Message { - get { - return _message; - } - set { - if (value?.Length > CredUi.MAX_MESSAGE_LENGTH) { - string message = string.Format( - Thread.CurrentThread.CurrentUICulture, - "The message has a maximum length of {0} characters.", - CredUi.MAX_MESSAGE_LENGTH); - throw new ArgumentException(message, nameof(Message)); - } - _message = value; - } - } - - private Image _banner; - /// Gets or sets the image to display on the dialog. - /// A null value will cause a system default image to be used. - public Image Banner { - get { - return _banner; - } - set { - if (value != null) { - if (value.Width != ValidBannerWidth) { - throw new ArgumentException("The banner image width must be 320 pixels.", nameof(Banner)); - } - if (value.Height != ValidBannerHeight) { - throw new ArgumentException("The banner image height must be 60 pixels.", nameof(Banner)); - } - } - _banner = value; - } - } - - /// Shows the credentials dialog with the specified name. - /// The name for the credentials. - /// Returns a DialogResult indicating the user action. - public DialogResult Show(string name) { - return Show(null, name, Password, SaveChecked); - } - - /// Shows the credentials dialog with the specified owner, name, password and save checkbox status. - /// The System.Windows.Forms.IWin32Window the dialog will display in front of. - /// The name for the credentials. - /// The password for the credentials. - /// True if the save checkbox is checked. - /// Returns a DialogResult indicating the user action. - public DialogResult Show(IWin32Window owner, string name, string password, bool saveChecked) { - if ((Environment.OSVersion.Version.Major < 5) || ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor < 1))) { - throw new ApplicationException("The Credential Management API requires Windows XP / Windows Server 2003 or later."); - } - Name = name; - Password = password; - SaveChecked = saveChecked; - - return ShowDialog(owner); - } - - /// Confirmation action to be applied. - /// True if the credentials should be persisted. - public void Confirm(bool value) - { - var confirmResult = CredUi.CredUIConfirmCredentials(Target, value); - switch (confirmResult) { - case CredUi.ReturnCodes.NO_ERROR: - break; - case CredUi.ReturnCodes.ERROR_INVALID_PARAMETER: - // for some reason, this is encountered when credentials are overwritten - break; - default: - throw new ApplicationException($"Credential confirmation failed: {confirmResult}"); - } - } - - /// Returns a DialogResult indicating the user action. - /// The System.Windows.Forms.IWin32Window the dialog will display in front of. - /// - /// Sets the name, password and SaveChecked accessors to the state of the dialog as it was dismissed by the user. - /// - private DialogResult ShowDialog(IWin32Window owner) { - // set the api call parameters - StringBuilder name = new StringBuilder(CredUi.MAX_USERNAME_LENGTH); - name.Append(Name); - - StringBuilder password = new StringBuilder(CredUi.MAX_PASSWORD_LENGTH); - password.Append(Password); - - int saveChecked = Convert.ToInt32(SaveChecked); - - CredUi.INFO info = GetInfo(owner); - CredUi.CredFlags credFlags = GetFlags(); - - // make the api call - CredUi.ReturnCodes code = CredUi.CredUIPromptForCredentials( - ref info, - Target, - IntPtr.Zero, 0, - name, CredUi.MAX_USERNAME_LENGTH, - password, CredUi.MAX_PASSWORD_LENGTH, - ref saveChecked, - credFlags - ); - - // clean up resources - if (Banner != null) { - DeleteObject(info.hbmBanner); - } - - // set the accessors from the api call parameters - Name = name.ToString(); - Password = password.ToString(); - SaveChecked = Convert.ToBoolean(saveChecked); - - return GetDialogResult(code); - } - - /// Returns the info structure for dialog display settings. - /// The System.Windows.Forms.IWin32Window the dialog will display in front of. - private CredUi.INFO GetInfo(IWin32Window owner) { - CredUi.INFO info = new CredUi.INFO(); - if (owner != null) info.hWndParent = owner.Handle; - info.pszCaptionText = Caption; - info.pszMessageText = Message; - if (Banner != null) { - info.hbmBanner = new Bitmap(Banner, ValidBannerWidth, ValidBannerHeight).GetHbitmap(); - } - info.cbSize = Marshal.SizeOf(info); - return info; - } - - /// Returns the flags for dialog display options. - private CredUi.CredFlags GetFlags() { - CredUi.CredFlags credFlags = CredUi.CredFlags.GENERIC_CREDENTIALS; - - if (IncorrectPassword) { - credFlags |= CredUi.CredFlags.INCORRECT_PASSWORD; - } - - if (AlwaysDisplay) { - credFlags |= CredUi.CredFlags.ALWAYS_SHOW_UI; - } - - if (ExcludeCertificates) { - credFlags |= CredUi.CredFlags.EXCLUDE_CERTIFICATES; - } - - if (Persist) { - credFlags |= CredUi.CredFlags.EXPECT_CONFIRMATION; - if (SaveDisplayed) { - credFlags |= CredUi.CredFlags.SHOW_SAVE_CHECK_BOX; - } else { - credFlags |= CredUi.CredFlags.PERSIST; - } - } else { - credFlags |= CredUi.CredFlags.DO_NOT_PERSIST; - } - - if (KeepName) { - credFlags |= CredUi.CredFlags.KEEP_USERNAME; - } - - return credFlags; - } - - /// Returns a DialogResult from the specified code. - /// The credential return code. - private DialogResult GetDialogResult(CredUi.ReturnCodes code) => - code switch - { - CredUi.ReturnCodes.NO_ERROR => DialogResult.OK, - CredUi.ReturnCodes.ERROR_CANCELLED => DialogResult.Cancel, - CredUi.ReturnCodes.ERROR_NO_SUCH_LOGON_SESSION => throw new ApplicationException( - "No such logon session."), - CredUi.ReturnCodes.ERROR_NOT_FOUND => throw new ApplicationException("Not found."), - CredUi.ReturnCodes.ERROR_INVALID_ACCOUNT_NAME => - throw new ApplicationException("Invalid account name."), - CredUi.ReturnCodes.ERROR_INSUFFICIENT_BUFFER => throw new ApplicationException("Insufficient buffer."), - CredUi.ReturnCodes.ERROR_INVALID_PARAMETER => throw new ApplicationException("Invalid parameter."), - CredUi.ReturnCodes.ERROR_INVALID_FLAGS => throw new ApplicationException("Invalid flags."), - _ => throw new ApplicationException("Unknown credential result encountered.") - }; - } - - internal static class CredUi { - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/authentication_constants.asp - public const int MAX_MESSAGE_LENGTH = 100; - public const int MAX_CAPTION_LENGTH = 100; - public const int MAX_GENERIC_TARGET_LENGTH = 100; - public const int MAX_USERNAME_LENGTH = 100; - public const int MAX_PASSWORD_LENGTH = 100; - - /// - /// http://www.pinvoke.net/default.aspx/Enums.CREDUI_FLAGS - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/dpapiusercredentials.asp - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp - /// - [Flags] - public enum CredFlags { - INCORRECT_PASSWORD = 0x1, - DO_NOT_PERSIST = 0x2, - EXCLUDE_CERTIFICATES = 0x8, - SHOW_SAVE_CHECK_BOX = 0x40, - ALWAYS_SHOW_UI = 0x80, - PERSIST = 0x1000, - EXPECT_CONFIRMATION = 0x20000, - GENERIC_CREDENTIALS = 0x40000, - KEEP_USERNAME = 0x100000, - } - - /// http://www.pinvoke.net/default.aspx/Enums.CredUIReturnCodes - public enum ReturnCodes { - NO_ERROR = 0, - ERROR_INVALID_PARAMETER = 87, - ERROR_INSUFFICIENT_BUFFER = 122, - ERROR_INVALID_FLAGS = 1004, - ERROR_NOT_FOUND = 1168, - ERROR_CANCELLED = 1223, - ERROR_NO_SUCH_LOGON_SESSION = 1312, - ERROR_INVALID_ACCOUNT_NAME = 1315 - } - - /// - /// http://www.pinvoke.net/default.aspx/Structures.CREDUI_INFO - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/credui_info.asp - /// - public struct INFO { - public int cbSize; - public IntPtr hWndParent; - [MarshalAs(UnmanagedType.LPWStr)] public string pszMessageText; - [MarshalAs(UnmanagedType.LPWStr)] public string pszCaptionText; - public IntPtr hbmBanner; - } - - /// - /// http://www.pinvoke.net/default.aspx/credui.CredUIPromptForCredentialsW - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp - /// - [DllImport("credui", CharSet = CharSet.Unicode)] - public static extern ReturnCodes CredUIPromptForCredentials ( - ref INFO creditUR, - string targetName, - IntPtr reserved1, - int iError, - StringBuilder userName, - int maxUserName, - StringBuilder password, - int maxPassword, - ref int iSave, - CredFlags credFlags - ); - - /// - /// http://www.pinvoke.net/default.aspx/credui.CredUIConfirmCredentials - /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduiconfirmcredentials.asp - /// - [DllImport("credui.dll", CharSet=CharSet.Unicode)] - public static extern ReturnCodes CredUIConfirmCredentials(string targetName, [MarshalAs(UnmanagedType.Bool)] bool confirm); - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/EffectConverter.cs b/GreenshotPlugin/Core/EffectConverter.cs deleted file mode 100644 index f72e271dc..000000000 --- a/GreenshotPlugin/Core/EffectConverter.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System; -using System.ComponentModel; -using System.Drawing; -using System.Globalization; -using System.Text; -using GreenshotPlugin.Effects; - -namespace GreenshotPlugin.Core -{ - public class EffectConverter : TypeConverter { - // Fix to prevent BUG-1753 - private readonly NumberFormatInfo _numberFormatInfo = new NumberFormatInfo(); - - public EffectConverter() - { - _numberFormatInfo.NumberDecimalSeparator = "."; - _numberFormatInfo.NumberGroupSeparator = ","; - } - - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - if (sourceType == typeof(string)) { - return true; - } - return base.CanConvertFrom(context, sourceType); - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { - if (destinationType == typeof(string)) { - return true; - } - if (destinationType == typeof(DropShadowEffect)) { - return true; - } - if (destinationType == typeof(TornEdgeEffect)) { - return true; - } - return base.CanConvertTo(context, destinationType); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { - // to string - if (destinationType == typeof(string)) { - StringBuilder sb = new StringBuilder(); - if (value.GetType() == typeof(DropShadowEffect)) { - DropShadowEffect effect = value as DropShadowEffect; - RetrieveDropShadowEffectValues(effect, sb); - return sb.ToString(); - } - if (value.GetType() == typeof(TornEdgeEffect)) { - TornEdgeEffect effect = value as TornEdgeEffect; - RetrieveDropShadowEffectValues(effect, sb); - sb.Append("|"); - RetrieveTornEdgeEffectValues(effect, sb); - return sb.ToString(); - } - } - // from string - if (value is string) { - string settings = value as string; - if (destinationType == typeof(DropShadowEffect)) { - DropShadowEffect effect = new DropShadowEffect(); - ApplyDropShadowEffectValues(settings, effect); - return effect; - } - if (destinationType == typeof(TornEdgeEffect)) { - TornEdgeEffect effect = new TornEdgeEffect(); - ApplyDropShadowEffectValues(settings, effect); - ApplyTornEdgeEffectValues(settings, effect); - return effect; - } - } - return base.ConvertTo(context, culture, value, destinationType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - if (value is string settings) { - if (settings.Contains("ToothHeight")) { - return ConvertTo(context, culture, settings, typeof(TornEdgeEffect)); - } - return ConvertTo(context, culture, settings, typeof(DropShadowEffect)); - } - return base.ConvertFrom(context, culture, value); - } - - private void ApplyDropShadowEffectValues(string valuesString, DropShadowEffect effect) { - string[] values = valuesString.Split('|'); - foreach(string nameValuePair in values) { - string[] pair = nameValuePair.Split(':'); - switch (pair[0]) { - case "Darkness" : - // Fix to prevent BUG-1753 - if (pair[1] != null && float.TryParse(pair[1], NumberStyles.Float, _numberFormatInfo, out var darkness)) { - if (darkness <= 1.0) { - effect.Darkness = darkness; - } - } - break; - case "ShadowSize": - if (int.TryParse(pair[1], out var shadowSize)) { - effect.ShadowSize = shadowSize; - } - break; - case "ShadowOffset": - Point shadowOffset = new Point(); - string[] coordinates = pair[1].Split(','); - if (int.TryParse(coordinates[0], out var shadowOffsetX)) { - shadowOffset.X = shadowOffsetX; - } - if (int.TryParse(coordinates[1], out var shadowOffsetY)) { - shadowOffset.Y = shadowOffsetY; - } - effect.ShadowOffset = shadowOffset; - break; - } - } - } - - private void ApplyTornEdgeEffectValues(string valuesString, TornEdgeEffect effect) { - string[] values = valuesString.Split('|'); - foreach (string nameValuePair in values) { - string[] pair = nameValuePair.Split(':'); - switch (pair[0]) { - case "GenerateShadow": - if (bool.TryParse(pair[1], out var generateShadow)) { - effect.GenerateShadow = generateShadow; - } - break; - case "ToothHeight": - if (int.TryParse(pair[1], out var toothHeight)) { - effect.ToothHeight = toothHeight; - } - break; - case "HorizontalToothRange": - if (int.TryParse(pair[1], out var horizontalToothRange)) { - effect.HorizontalToothRange = horizontalToothRange; - } - break; - case "VerticalToothRange": - if (int.TryParse(pair[1], out var verticalToothRange)) { - effect.VerticalToothRange = verticalToothRange; - } - break; - case "Edges": - string[] edges = pair[1].Split(','); - if (bool.TryParse(edges[0], out var edge)) { - effect.Edges[0] = edge; - } - if (bool.TryParse(edges[1], out edge)) { - effect.Edges[1] = edge; - } - if (bool.TryParse(edges[2], out edge)) { - effect.Edges[2] = edge; - } - if (bool.TryParse(edges[3], out edge)) { - effect.Edges[3] = edge; - } - break; - } - } - } - - private void RetrieveDropShadowEffectValues(DropShadowEffect effect, StringBuilder sb) { - // Fix to prevent BUG-1753 is to use the numberFormatInfo - sb.AppendFormat("Darkness:{0}|ShadowSize:{1}|ShadowOffset:{2},{3}", effect.Darkness.ToString("F2", _numberFormatInfo), effect.ShadowSize, effect.ShadowOffset.X, effect.ShadowOffset.Y); - } - private void RetrieveTornEdgeEffectValues(TornEdgeEffect effect, StringBuilder sb) { - sb.AppendFormat("GenerateShadow:{0}|ToothHeight:{1}|HorizontalToothRange:{2}|VerticalToothRange:{3}|Edges:{4},{5},{6},{7}", effect.GenerateShadow, effect.ToothHeight, effect.HorizontalToothRange, effect.VerticalToothRange, effect.Edges[0], effect.Edges[1], effect.Edges[2], effect.Edges[3]); - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/ExplorerHelper.cs b/GreenshotPlugin/Core/ExplorerHelper.cs deleted file mode 100644 index 8f67018b1..000000000 --- a/GreenshotPlugin/Core/ExplorerHelper.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; - -namespace GreenshotPlugin.Core -{ - /// - /// Simple utility for the explorer - /// - public static class ExplorerHelper - { - /// - /// Open the path in the windows explorer. - /// If the path is a directory, it will just open the explorer with that directory. - /// If the path is a file, the explorer is opened with the directory and the file is selected. - /// - /// Path to file or directory - public static bool OpenInExplorer(string path) - { - if (path == null) - { - return false; - } - try - { - // Check if path is a directory - if (Directory.Exists(path)) - { - using (Process.Start(path)) - { - return true; - } - } - // Check if path is a file - if (File.Exists(path)) - { - // Start the explorer process and select the file - using var explorer = Process.Start("explorer.exe", $"/select,\"{path}\""); - explorer?.WaitForInputIdle(500); - return true; - } - } - catch (Exception ex) - { - // Make sure we show what we tried to open in the exception - ex.Data.Add("path", path); - throw; - } - return false; - } - } -} diff --git a/GreenshotPlugin/Core/FastBitmap.cs b/GreenshotPlugin/Core/FastBitmap.cs deleted file mode 100644 index 54b11e5ce..000000000 --- a/GreenshotPlugin/Core/FastBitmap.cs +++ /dev/null @@ -1,1010 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; - -namespace GreenshotPlugin.Core { - - /// - /// The interface for the FastBitmap - /// - public interface IFastBitmap : IDisposable { - /// - /// Get the color at x,y - /// The returned Color object depends on the underlying pixel format - /// - /// int x - /// int y - /// Color - Color GetColorAt(int x, int y); - - /// - /// Set the color at the specified location - /// - /// int x - /// int y - /// Color - void SetColorAt(int x, int y, Color color); - - /// - /// Get the color at x,y - /// The returned byte[] color depends on the underlying pixel format - /// - /// int x - /// int y - /// byte array - void GetColorAt(int x, int y, byte[] color); - - /// - /// Set the color at the specified location - /// - /// int x - /// int y - /// byte[] color - void SetColorAt(int x, int y, byte[] color); - - /// - /// Lock the bitmap - /// - void Lock(); - - /// - /// Unlock the bitmap - /// - void Unlock(); - - /// - /// Unlock the bitmap and get the underlying bitmap in one call - /// - /// - Bitmap UnlockAndReturnBitmap(); - - /// - /// Size of the underlying image - /// - Size Size { - get; - } - - /// - /// Height of the image area that this fastbitmap covers - /// - int Height { - get; - } - - /// - /// Width of the image area that this fastbitmap covers - /// - int Width { - get; - } - - /// - /// Top of the image area that this fastbitmap covers - /// - int Top { - get; - } - - /// - /// Left of the image area that this fastbitmap covers - /// - int Left { - get; - } - - /// - /// Right of the image area that this fastbitmap covers - /// - int Right { - get; - } - - /// - /// Bottom of the image area that this fastbitmap covers - /// - int Bottom { - get; - } - - /// - /// Does the underlying image need to be disposed - /// - bool NeedsDispose { - get; - set; - } - - /// - /// Returns if this FastBitmap has an alpha channel - /// - bool HasAlphaChannel { - get; - } - - /// - /// Draw the stored bitmap to the destionation bitmap at the supplied point - /// - /// Graphics - /// Point with location - void DrawTo(Graphics graphics, Point destination); - - /// - /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle - /// Be aware that the stored bitmap will be resized to the specified rectangle!! - /// - /// Graphics - /// Rectangle with destination - void DrawTo(Graphics graphics, Rectangle destinationRect); - - /// - /// Return true if the coordinates are inside the FastBitmap - /// - /// - /// - /// - bool Contains(int x, int y); - - /// - /// Set the bitmap resolution - /// - /// - /// - void SetResolution(float horizontal, float vertical); - } - - /// - /// This interface can be used for when offsetting is needed - /// - public interface IFastBitmapWithOffset : IFastBitmap { - /// - /// Return true if the coordinates are inside the FastBitmap - /// - /// - /// - /// - new bool Contains(int x, int y); - - /// - /// Set the color at the specified location, using offsetting so the original coordinates can be used - /// - /// int x - /// int y - /// Color color - new void SetColorAt(int x, int y, Color color); - - /// - /// Set the color at the specified location, using offsetting so the original coordinates can be used - /// - /// int x - /// int y - /// byte[] color - new void SetColorAt(int x, int y, byte[] color); - - /// - /// Get the color at x,y - /// The returned Color object depends on the underlying pixel format - /// - /// int x - /// int y - /// Color - new Color GetColorAt(int x, int y); - - /// - /// Get the color at x,y, using offsetting so the original coordinates can be used - /// The returned byte[] color depends on the underlying pixel format - /// - /// int x - /// int y - /// byte array - new void GetColorAt(int x, int y, byte[] color); - - new int Left { - get; - set; - } - - new int Top { - get; - set; - } - } - - /// - /// This interface can be used for when clipping is needed - /// - public interface IFastBitmapWithClip : IFastBitmap { - Rectangle Clip { - get; - set; - } - - bool InvertClip { - get; - set; - } - - /// - /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping - /// - /// int x - /// int y - /// Color color - new void SetColorAt(int x, int y, Color color); - - /// - /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping - /// - /// int x - /// int y - /// byte[] color - new void SetColorAt(int x, int y, byte[] color); - - /// - /// Return true if the coordinates are inside the FastBitmap and not clipped - /// - /// - /// - /// - new bool Contains(int x, int y); - } - - /// - /// This interface is implemented when there is a alpha-blending possibility - /// - public interface IFastBitmapWithBlend : IFastBitmap { - Color BackgroundBlendColor { - get; - set; - } - Color GetBlendedColorAt(int x, int y); - } - - /// - /// The base class for the fast bitmap implementation - /// - public abstract unsafe class FastBitmap : IFastBitmapWithClip, IFastBitmapWithOffset { - protected const int PixelformatIndexA = 3; - protected const int PixelformatIndexR = 2; - protected const int PixelformatIndexG = 1; - protected const int PixelformatIndexB = 0; - - public const int ColorIndexR = 0; - public const int ColorIndexG = 1; - public const int ColorIndexB = 2; - public const int ColorIndexA = 3; - - protected Rectangle Area; - /// - /// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap - /// - public bool NeedsDispose { - get; - set; - } - - public Rectangle Clip { - get; - set; - } - - public bool InvertClip { - get; - set; - } - - /// - /// The bitmap for which the FastBitmap is creating access - /// - protected Bitmap Bitmap; - - protected BitmapData BmData; - protected int Stride; /* bytes per pixel row */ - protected bool BitsLocked; - protected byte* Pointer; - - public static IFastBitmap Create(Bitmap source) { - return Create(source, Rectangle.Empty); - } - - public void SetResolution(float horizontal, float vertical) { - Bitmap.SetResolution(horizontal, vertical); - } - - /// - /// Factory for creating a FastBitmap depending on the pixelformat of the source - /// The supplied rectangle specifies the area for which the FastBitmap does its thing - /// - /// Bitmap to access - /// Rectangle which specifies the area to have access to, can be Rectangle.Empty for the whole image - /// IFastBitmap - public static IFastBitmap Create(Bitmap source, Rectangle area) { - switch (source.PixelFormat) { - case PixelFormat.Format8bppIndexed: - return new FastChunkyBitmap(source, area); - case PixelFormat.Format24bppRgb: - return new Fast24RgbBitmap(source, area); - case PixelFormat.Format32bppRgb: - return new Fast32RgbBitmap(source, area); - case PixelFormat.Format32bppArgb: - case PixelFormat.Format32bppPArgb: - return new Fast32ArgbBitmap(source, area); - default: - throw new NotSupportedException($"Not supported Pixelformat {source.PixelFormat}"); - } - } - - /// - /// Factory for creating a FastBitmap as a destination for the source - /// - /// Bitmap to clone - /// new Pixelformat - /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat) { - return CreateCloneOf(source, pixelFormat, Rectangle.Empty); - } - /// - /// Factory for creating a FastBitmap as a destination for the source - /// - /// Bitmap to clone - /// Area of the bitmap to access, can be Rectangle.Empty for the whole - /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, Rectangle area) { - return CreateCloneOf(source, PixelFormat.DontCare, area); - } - - /// - /// Factory for creating a FastBitmap as a destination for the source - /// - /// Bitmap to clone - /// Pixelformat of the cloned bitmap - /// Area of the bitmap to access, can be Rectangle.Empty for the whole - /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) { - Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat); - FastBitmap fastBitmap = Create(destination) as FastBitmap; - if (fastBitmap != null) - { - fastBitmap.NeedsDispose = true; - fastBitmap.Left = area.Left; - fastBitmap.Top = area.Top; - } - return fastBitmap; - } - - /// - /// Factory for creating a FastBitmap as a destination - /// - /// - /// - /// - /// IFastBitmap - public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat, Color backgroundColor) { - Bitmap destination = ImageHelper.CreateEmpty(newSize.Width, newSize.Height, pixelFormat, backgroundColor, 96f, 96f); - IFastBitmap fastBitmap = Create(destination); - fastBitmap.NeedsDispose = true; - return fastBitmap; - } - - /// - /// Constructor which stores the image and locks it when called - /// - /// Bitmap - /// Rectangle - protected FastBitmap(Bitmap bitmap, Rectangle area) { - Bitmap = bitmap; - Rectangle bitmapArea = new Rectangle(Point.Empty, bitmap.Size); - if (area != Rectangle.Empty) { - area.Intersect(bitmapArea); - Area = area; - } else { - Area = bitmapArea; - } - // As the lock takes care that only the specified area is made available we need to calculate the offset - Left = area.Left; - Top = area.Top; - // Default cliping is done to the area without invert - Clip = Area; - InvertClip = false; - // Always lock, so we don't need to do this ourselves - Lock(); - } - - /// - /// Return the size of the image - /// - public Size Size { - get { - if (Area == Rectangle.Empty) { - return Bitmap.Size; - } - return Area.Size; - } - } - - /// - /// Return the width of the image - /// - public int Width { - get { - if (Area == Rectangle.Empty) { - return Bitmap.Width; - } - return Area.Width; - } - } - - /// - /// Return the height of the image - /// - public int Height { - get { - if (Area == Rectangle.Empty) { - return Bitmap.Height; - } - return Area.Height; - } - } - - private int _left; - /// - /// Return the left of the fastbitmap, this is also used as an offset - /// - public int Left { - get { - return 0; - } - set { - _left = value; - } - } - - /// - /// Return the left of the fastbitmap, this is also used as an offset - /// - int IFastBitmapWithOffset.Left { - get { - return _left; - } - set { - _left = value; - } - } - - private int _top; - /// - /// Return the top of the fastbitmap, this is also used as an offset - /// - public int Top { - get { - return 0; - } - set { - _top = value; - } - } - - /// - /// Return the top of the fastbitmap, this is also used as an offset - /// - int IFastBitmapWithOffset.Top { - get { - return _top; - } - set { - _top = value; - } - } - - /// - /// Return the right of the fastbitmap - /// - public int Right => Left + Width; - - /// - /// Return the bottom of the fastbitmap - /// - public int Bottom => Top + Height; - - /// - /// Returns the underlying bitmap, unlocks it and prevents that it will be disposed - /// - public Bitmap UnlockAndReturnBitmap() { - if (BitsLocked) { - Unlock(); - } - NeedsDispose = false; - return Bitmap; - } - - public virtual bool HasAlphaChannel => false; - - /// - /// Destructor - /// - ~FastBitmap() { - Dispose(false); - } - - /// - /// The public accessible Dispose - /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice - /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - // The bulk of the clean-up code is implemented in Dispose(bool) - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// When disposing==true all non-managed resources should be freed too! - /// - /// - protected virtual void Dispose(bool disposing) { - Unlock(); - if (disposing) { - if (Bitmap != null && NeedsDispose) { - Bitmap.Dispose(); - } - } - Bitmap = null; - BmData = null; - Pointer = null; - } - - /// - /// Lock the bitmap so we have direct access to the memory - /// - public void Lock() { - if (Width <= 0 || Height <= 0 || BitsLocked) - { - return; - } - BmData = Bitmap.LockBits(Area, ImageLockMode.ReadWrite, Bitmap.PixelFormat); - BitsLocked = true; - - IntPtr scan0 = BmData.Scan0; - Pointer = (byte*)(void*)scan0; - Stride = BmData.Stride; - } - - /// - /// Unlock the System Memory - /// - public void Unlock() { - if (BitsLocked) { - Bitmap.UnlockBits(BmData); - BitsLocked = false; - } - } - - /// - /// Draw the stored bitmap to the destionation bitmap at the supplied point - /// - /// - /// - public void DrawTo(Graphics graphics, Point destination) { - DrawTo(graphics, new Rectangle(destination, Area.Size)); - } - - /// - /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle - /// Be aware that the stored bitmap will be resized to the specified rectangle!! - /// - /// - /// - public void DrawTo(Graphics graphics, Rectangle destinationRect) { - // Make sure this.bitmap is unlocked, if it was locked - bool isLocked = BitsLocked; - if (isLocked) { - Unlock(); - } - - graphics.DrawImage(Bitmap, destinationRect, Area, GraphicsUnit.Pixel); - } - - /// - /// returns true if x & y are inside the FastBitmap - /// - /// - /// - /// true if x & y are inside the FastBitmap - public bool Contains(int x, int y) { - return Area.Contains(x - Left, y - Top); - } - - public abstract Color GetColorAt(int x, int y); - public abstract void SetColorAt(int x, int y, Color color); - public abstract void GetColorAt(int x, int y, byte[] color); - public abstract void SetColorAt(int x, int y, byte[] color); - - bool IFastBitmapWithClip.Contains(int x, int y) { - bool contains = Clip.Contains(x, y); - if (InvertClip) { - return !contains; - } else { - return contains; - } - } - - void IFastBitmapWithClip.SetColorAt(int x, int y, byte[] color) { - bool contains = Clip.Contains(x, y); - if ((InvertClip && contains) || (!InvertClip && !contains)) { - return; - } - SetColorAt(x, y, color); - } - - void IFastBitmapWithClip.SetColorAt(int x, int y, Color color) { - bool contains = Clip.Contains(x, y); - if ((InvertClip && contains) || (!InvertClip && !contains)) { - return; - } - SetColorAt(x, y, color); - } - - /// - /// returns true if x & y are inside the FastBitmap - /// - /// - /// - /// true if x & y are inside the FastBitmap - bool IFastBitmapWithOffset.Contains(int x, int y) { - return Area.Contains(x - Left, y - Top); - } - - Color IFastBitmapWithOffset.GetColorAt(int x, int y) { - x -= _left; - y -= _top; - return GetColorAt(x, y); - } - void IFastBitmapWithOffset.GetColorAt(int x, int y, byte[] color) { - x -= _left; - y -= _top; - GetColorAt(x, y, color); - } - - void IFastBitmapWithOffset.SetColorAt(int x, int y, byte[] color) { - x -= _left; - y -= _top; - SetColorAt(x, y, color); - } - - void IFastBitmapWithOffset.SetColorAt(int x, int y, Color color) { - x -= _left; - y -= _top; - SetColorAt(x, y, color); - } - } - - /// - /// This is the implementation of the FastBitmat for the 8BPP pixelformat - /// - public unsafe class FastChunkyBitmap : FastBitmap { - // Used for indexed images - private readonly Color[] _colorEntries; - private readonly Dictionary _colorCache = new Dictionary(); - - public FastChunkyBitmap(Bitmap source, Rectangle area) : base(source, area) { - _colorEntries = Bitmap.Palette.Entries; - } - - /// - /// Get the color from the specified location - /// - /// - /// - /// Color - public override Color GetColorAt(int x, int y) { - int offset = x + (y * Stride); - byte colorIndex = Pointer[offset]; - return _colorEntries[colorIndex]; - } - - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference - public override void GetColorAt(int x, int y, byte[] color) { - throw new NotImplementedException("No performance gain!"); - } - - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference - public override void SetColorAt(int x, int y, byte[] color) { - throw new NotImplementedException("No performance gain!"); - } - - /// - /// Get the color-index from the specified location - /// - /// - /// - /// byte with index - public byte GetColorIndexAt(int x, int y) { - int offset = x + (y * Stride); - return Pointer[offset]; - } - - /// - /// Set the color-index at the specified location - /// - /// - /// - /// - public void SetColorIndexAt(int x, int y, byte colorIndex) { - int offset = x + (y * Stride); - Pointer[offset] = colorIndex; - } - - /// - /// Set the supplied color at the specified location. - /// Throws an ArgumentException if the color is not in the palette - /// - /// - /// - /// Color to set - public override void SetColorAt(int x, int y, Color color) { - int offset = x + (y * Stride); - if (!_colorCache.TryGetValue(color, out var colorIndex)) { - bool foundColor = false; - for (colorIndex = 0; colorIndex < _colorEntries.Length; colorIndex++) { - if (color == _colorEntries[colorIndex]) { - _colorCache.Add(color, colorIndex); - foundColor = true; - break; - } - } - if (!foundColor) { - throw new ArgumentException("No such color!"); - } - } - Pointer[offset] = colorIndex; - } - } - - /// - /// This is the implementation of the IFastBitmap for 24 bit images (no Alpha) - /// - public unsafe class Fast24RgbBitmap : FastBitmap { - - public Fast24RgbBitmap(Bitmap source, Rectangle area) : base(source, area) { - } - - /// - /// Retrieve the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public override Color GetColorAt(int x, int y) { - int offset = (x * 3) + (y * Stride); - return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); - } - - /// - /// Set the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public override void SetColorAt(int x, int y, Color color) { - int offset = (x * 3) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color.R; - Pointer[PixelformatIndexG + offset] = color.G; - Pointer[PixelformatIndexB + offset] = color.B; - } - - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b) - public override void GetColorAt(int x, int y, byte[] color) { - int offset = (x * 3) + (y * Stride); - color[PixelformatIndexR] = Pointer[PixelformatIndexR + offset]; - color[PixelformatIndexG] = Pointer[PixelformatIndexG + offset]; - color[PixelformatIndexB] = Pointer[PixelformatIndexB + offset]; - } - - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b) - public override void SetColorAt(int x, int y, byte[] color) { - int offset = (x * 3) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color[PixelformatIndexR]; - Pointer[PixelformatIndexG + offset] = color[PixelformatIndexG]; - Pointer[PixelformatIndexB + offset] = color[PixelformatIndexB]; - } - - } - - /// - /// This is the implementation of the IFastBitmap for 32 bit images (no Alpha) - /// - public unsafe class Fast32RgbBitmap : FastBitmap { - public Fast32RgbBitmap(Bitmap source, Rectangle area) : base(source, area) { - - } - - /// - /// Retrieve the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public override Color GetColorAt(int x, int y) { - int offset = (x * 4) + (y * Stride); - return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); - } - - /// - /// Set the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public override void SetColorAt(int x, int y, Color color) { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color.R; - Pointer[PixelformatIndexG + offset] = color.G; - Pointer[PixelformatIndexB + offset] = color.B; - } - - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference (a,r,g,b) - public override void GetColorAt(int x, int y, byte[] color) { - int offset = (x * 4) + (y * Stride); - color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; - color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; - color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; - } - - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b) - public override void SetColorAt(int x, int y, byte[] color) { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R - Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; - Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; - } - } - - /// - /// This is the implementation of the IFastBitmap for 32 bit images with Alpha - /// - public unsafe class Fast32ArgbBitmap : FastBitmap, IFastBitmapWithBlend { - public override bool HasAlphaChannel => true; - - public Color BackgroundBlendColor { - get; - set; - } - public Fast32ArgbBitmap(Bitmap source, Rectangle area) : base(source, area) { - BackgroundBlendColor = Color.White; - } - - /// - /// Retrieve the color at location x,y - /// - /// X coordinate - /// Y Coordinate - /// Color - public override Color GetColorAt(int x, int y) { - int offset = (x * 4) + (y * Stride); - return Color.FromArgb(Pointer[PixelformatIndexA + offset], Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); - } - - /// - /// Set the color at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// - /// - /// - public override void SetColorAt(int x, int y, Color color) { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexA + offset] = color.A; - Pointer[PixelformatIndexR + offset] = color.R; - Pointer[PixelformatIndexG + offset] = color.G; - Pointer[PixelformatIndexB + offset] = color.B; - } - - /// - /// Get the color from the specified location into the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b,a) - public override void GetColorAt(int x, int y, byte[] color) { - int offset = (x * 4) + (y * Stride); - color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; - color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; - color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; - color[ColorIndexA] = Pointer[PixelformatIndexA + offset]; - } - - /// - /// Set the color at the specified location from the specified array - /// - /// - /// - /// byte[4] as reference (r,g,b,a) - public override void SetColorAt(int x, int y, byte[] color) { - int offset = (x * 4) + (y * Stride); - Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R - Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; - Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; - Pointer[PixelformatIndexA + offset] = color[ColorIndexA]; - } - - /// - /// Retrieve the color, without alpha (is blended), at location x,y - /// Before the first time this is called the Lock() should be called once! - /// - /// X coordinate - /// Y Coordinate - /// Color - public Color GetBlendedColorAt(int x, int y) { - int offset = (x * 4) + (y * Stride); - int a = Pointer[PixelformatIndexA + offset]; - int red = Pointer[PixelformatIndexR + offset]; - int green = Pointer[PixelformatIndexG + offset]; - int blue = Pointer[PixelformatIndexB + offset]; - - if (a < 255) { - // As the request is to get without alpha, we blend. - int rem = 255 - a; - red = (red * a + BackgroundBlendColor.R * rem) / 255; - green = (green * a + BackgroundBlendColor.G * rem) / 255; - blue = (blue * a + BackgroundBlendColor.B * rem) / 255; - } - return Color.FromArgb(255, red, green, blue); - } - } -} diff --git a/GreenshotPlugin/Core/FilenameHelper.cs b/GreenshotPlugin/Core/FilenameHelper.cs deleted file mode 100644 index 5edf92afb..000000000 --- a/GreenshotPlugin/Core/FilenameHelper.cs +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections; -using System.IO; -using System.Text.RegularExpressions; -using System.Windows.Forms; -using log4net; -using System.Collections.Generic; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; - -namespace GreenshotPlugin.Core { - public static class FilenameHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(FilenameHelper)); - // Specify the regular expression for the filename formatting: - // Starting with ${ - // than the varname, which ends with a : or } - // If a parameters needs to be supplied, than a ":" should follow the name... everything from the : until the } is considered to be part of the parameters. - // The parameter format is a single alpha followed by the value belonging to the parameter, e.g. : - // ${capturetime:d"yyyy-MM-dd HH_mm_ss"} - private static readonly Regex VarRegexp = new Regex(@"\${(?[^:}]+)[:]?(?[^}]*)}", RegexOptions.Compiled); - private static readonly Regex CmdVarRegexp = new Regex(@"%(?[^%]+)%", RegexOptions.Compiled); - - private static readonly Regex SplitRegexp = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled); - private const int MaxTitleLength = 80; - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const string UnsafeReplacement = "_"; - private static readonly Random RandomNumberGen = new Random(); - private static readonly Regex RandRegexp = new Regex("^R+$", RegexOptions.Compiled); - - /// - /// Remove invalid characters from the fully qualified filename - /// - /// string with the full path to a file - /// string with the full path to a file, without invalid characters - public static string MakeFqFilenameSafe(string fullPath) { - string path = MakePathSafe(Path.GetDirectoryName(fullPath)); - string filename = MakeFilenameSafe(Path.GetFileName(fullPath)); - // Make the fullpath again and return - return Path.Combine(path, filename); - } - - /// - /// Remove invalid characters from the filename - /// - /// string with the full path to a file - /// string with the full path to a file, without invalid characters - public static string MakeFilenameSafe(string filename) { - // Make the filename save! - if (filename != null) { - foreach (char disallowed in Path.GetInvalidFileNameChars()) { - filename = filename.Replace(disallowed.ToString(), UnsafeReplacement); - } - } - return filename; - } - - /// - /// Remove invalid characters from the path - /// - /// string with the full path to a file - /// string with the full path to a file, without invalid characters - public static string MakePathSafe(string path) { - // Make the path save! - if (path != null) { - foreach (char disallowed in Path.GetInvalidPathChars()) { - path = path.Replace(disallowed.ToString(), UnsafeReplacement); - } - } - return path; - } - - public static string GetFilenameWithoutExtensionFromPattern(string pattern) { - return GetFilenameWithoutExtensionFromPattern(pattern, null); - } - - public static string GetFilenameWithoutExtensionFromPattern(string pattern, ICaptureDetails captureDetails) { - return FillPattern(pattern, captureDetails, true); - } - - public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat) { - return GetFilenameFromPattern(pattern, imageFormat, null); - } - - public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat, ICaptureDetails captureDetails) { - return FillPattern(pattern, captureDetails, true) + "." + imageFormat.ToString().ToLower(); - } - - /// - /// Return a filename for the current image format (png,jpg etc) with the default file pattern - /// that is specified in the configuration - /// - /// A string with the format - /// - /// The filename which should be used to save the image - public static string GetFilename(OutputFormat format, ICaptureDetails captureDetails) { - string pattern = CoreConfig.OutputFileFilenamePattern; - if (string.IsNullOrEmpty(pattern?.Trim())) { - pattern = "greenshot ${capturetime}"; - } - return GetFilenameFromPattern(pattern, format, captureDetails); - } - - - /// - /// This method will be called by the regexp.replace as a MatchEvaluator delegate! - /// Will delegate this to the MatchVarEvaluatorInternal and catch any exceptions - /// - /// What are we matching? - /// The detail, can be null - /// Variables from the process - /// Variables from the user - /// Variables from the machine - /// - /// string with the match replacement - private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, bool filenameSafeMode) { - try { - return MatchVarEvaluatorInternal(match, captureDetails, processVars, userVars, machineVars, filenameSafeMode); - } catch (Exception e) { - Log.Error("Error in MatchVarEvaluatorInternal", e); - } - return string.Empty; - } - - /// - /// This method will be called by the regexp.replace as a MatchEvaluator delegate! - /// - /// What are we matching? - /// The detail, can be null - /// - /// - /// - /// - /// - private static string MatchVarEvaluatorInternal(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, bool filenameSafeMode) { - // some defaults - int padWidth = 0; - int startIndex = 0; - int endIndex = 0; - char padChar = ' '; - string dateFormat = "yyyy-MM-dd HH-mm-ss"; - IDictionary replacements = new Dictionary(); - string replaceValue = string.Empty; - string variable = match.Groups["variable"].Value; - string parameters = match.Groups["parameters"].Value; - string randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - - if (parameters.Length > 0) { - string[] parms = SplitRegexp.Split(parameters); - foreach (string parameter in parms) { - switch (parameter.Substring(0, 1)) { - // Padding p[,pad-character] - case "p": - string[] padParams = parameter.Substring(1).Split(','); - try { - padWidth = int.Parse(padParams[0]); - } - catch - { - // ignored - } - if (padParams.Length > 1) { - padChar = padParams[1][0]; - } - break; - // replace - // r, - case "r": - string[] replaceParameters = parameter.Substring(1).Split(','); - if (replaceParameters != null && replaceParameters.Length == 2) { - replacements.Add(replaceParameters[0], replaceParameters[1]); - } - break; - // Dateformat d - // Format can be anything that is used in C# date formatting - case "d": - dateFormat = parameter.Substring(1); - if (dateFormat.StartsWith("\"")) { - dateFormat = dateFormat.Substring(1); - } - if (dateFormat.EndsWith("\"")) { - dateFormat = dateFormat.Substring(0, dateFormat.Length - 1); - } - break; - // Substring: - // s[,length] - case "s": - string range = parameter.Substring(1); - string[] rangelist = range.Split(','); - if (rangelist.Length > 0) { - try { - startIndex = int.Parse(rangelist[0]); - } catch { - // Ignore - } - } - if (rangelist.Length > 1) { - try { - endIndex = int.Parse(rangelist[1]); - } catch { - // Ignore - } - } - break; - } - } - } - if (processVars != null && processVars.Contains(variable)) { - replaceValue = (string)processVars[variable]; - if (filenameSafeMode) { - replaceValue = MakePathSafe(replaceValue); - } - } else if (userVars != null && userVars.Contains(variable)) { - replaceValue = (string)userVars[variable]; - if (filenameSafeMode) { - replaceValue = MakePathSafe(replaceValue); - } - } else if (machineVars != null && machineVars.Contains(variable)) { - replaceValue = (string)machineVars[variable]; - if (filenameSafeMode) { - replaceValue = MakePathSafe(replaceValue); - } - } else if (captureDetails?.MetaData != null && captureDetails.MetaData.ContainsKey(variable)) { - replaceValue = captureDetails.MetaData[variable]; - if (filenameSafeMode) { - replaceValue = MakePathSafe(replaceValue); - } - } else if (RandRegexp.IsMatch(variable)) { - for (int i = 0; i < variable.Length; i++) { - replaceValue += randomChars[RandomNumberGen.Next(randomChars.Length)]; - } - } else { - // Handle other variables - // Default use "now" for the capture take´n - DateTime capturetime = DateTime.Now; - // Use default application name for title - string title = Application.ProductName; - - // Check if we have capture details - if (captureDetails != null) { - capturetime = captureDetails.DateTime; - if (captureDetails.Title != null) { - title = captureDetails.Title; - if (title.Length > MaxTitleLength) { - title = title.Substring(0, MaxTitleLength); - } - } - } - switch (variable) { - case "domain": - replaceValue = Environment.UserDomainName; - break; - case "user": - replaceValue = Environment.UserName; - break; - case "hostname": - replaceValue = Environment.MachineName; - break; - case "YYYY": - if (padWidth == 0) { - padWidth = -4; - padChar = '0'; - } - replaceValue = capturetime.Year.ToString(); - break; - case "MM": - replaceValue = capturetime.Month.ToString(); - if (padWidth == 0) { - padWidth = -2; - padChar = '0'; - } - break; - case "DD": - replaceValue = capturetime.Day.ToString(); - if (padWidth == 0) { - padWidth = -2; - padChar = '0'; - } - break; - case "hh": - if (padWidth == 0) { - padWidth = -2; - padChar = '0'; - } - replaceValue = capturetime.Hour.ToString(); - break; - case "mm": - if (padWidth == 0) { - padWidth = -2; - padChar = '0'; - } - replaceValue = capturetime.Minute.ToString(); - break; - case "ss": - if (padWidth == 0) { - padWidth = -2; - padChar = '0'; - } - replaceValue = capturetime.Second.ToString(); - break; - case "now": - replaceValue = DateTime.Now.ToString(dateFormat); - if (filenameSafeMode) { - replaceValue = MakeFilenameSafe(replaceValue); - } - break; - case "capturetime": - replaceValue = capturetime.ToString(dateFormat); - if (filenameSafeMode) { - replaceValue = MakeFilenameSafe(replaceValue); - } - break; - case "NUM": - CoreConfig.OutputFileIncrementingNumber++; - IniConfig.Save(); - replaceValue = CoreConfig.OutputFileIncrementingNumber.ToString(); - if (padWidth == 0) { - padWidth = -6; - padChar = '0'; - } - - break; - case "title": - replaceValue = title; - if (filenameSafeMode) { - replaceValue = MakeFilenameSafe(replaceValue); - } - break; - case "MyPictures": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); - break; - case "MyMusic": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic); - break; - case "MyDocuments": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); - break; - case "Personal": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Personal); - break; - case "Desktop": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); - break; - case "ApplicationData": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - break; - case "LocalApplicationData": - replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); - break; - } - } - // do padding - if (padWidth > 0) { - replaceValue = replaceValue.PadRight(padWidth, padChar); - } else if (padWidth < 0) { - replaceValue = replaceValue.PadLeft(-padWidth, padChar); - } - - // do substring - if (startIndex != 0 || endIndex != 0) { - if (startIndex < 0) { - startIndex = replaceValue.Length + startIndex; - } - if (endIndex < 0) { - endIndex = replaceValue.Length + endIndex; - } - if (endIndex != 0) { - try { - replaceValue = replaceValue.Substring(startIndex, endIndex); - } catch { - // Ignore - } - } else { - try { - replaceValue = replaceValue.Substring(startIndex); - } catch { - // Ignore - } - } - } - - // new for feature #697 - if (replacements.Count > 0) { - foreach (string oldValue in replacements.Keys) { - replaceValue = replaceValue.Replace(oldValue, replacements[oldValue]); - } - } - return replaceValue; - } - - /// - /// "Simply" fill the pattern with environment variables - /// - /// String with pattern %var% - /// true to make sure everything is filenamesafe - /// Filled string - public static string FillCmdVariables(string pattern, bool filenameSafeMode = true) - { - IDictionary processVars = null; - IDictionary userVars = null; - IDictionary machineVars = null; - try - { - processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); - } - - try - { - userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.User", e); - } - - try - { - machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); - } - catch (Exception e) - { - Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); - } - - return CmdVarRegexp.Replace(pattern, - m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) - ); - } - - /// - /// "Simply" fill the pattern with environment variables - /// - /// String with pattern ${var} - /// true to make sure everything is filenamesafe - /// Filled string - public static string FillVariables(string pattern, bool filenameSafeMode) { - IDictionary processVars = null; - IDictionary userVars = null; - IDictionary machineVars = null; - try { - processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); - } - - try { - userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.User", e); - } - - try { - machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); - } - - return VarRegexp.Replace(pattern, - m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) - ); - } - - /// - /// Fill the pattern wit the supplied details - /// - /// Pattern - /// CaptureDetails, can be null - /// Should the result be made "filename" safe? - /// Filled pattern - public static string FillPattern(string pattern, ICaptureDetails captureDetails, bool filenameSafeMode) { - IDictionary processVars = null; - IDictionary userVars = null; - IDictionary machineVars = null; - try { - processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); - } - - try { - userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.User", e); - } - - try { - machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); - } catch (Exception e) { - Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); - } - - try { - return VarRegexp.Replace(pattern, - m => MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars, filenameSafeMode) - ); - } catch (Exception e) { - // adding additional data for bug tracking - if (captureDetails != null) { - e.Data.Add("title", captureDetails.Title); - } - e.Data.Add("pattern", pattern); - throw; - } - } - - /// - /// Checks whether a directory name is valid in the current file system - /// - /// directory name (not path!) - /// true if directory name is valid - public static bool IsDirectoryNameValid(string directoryName) { - var forbiddenChars = Path.GetInvalidPathChars(); - foreach (var forbiddenChar in forbiddenChars) { - if (directoryName == null || directoryName.Contains(forbiddenChar.ToString())) { - return false; - } - } - return true; - } - - /// - /// Checks whether a filename is valid in the current file system - /// - /// name of the file - /// true if filename is valid - public static bool IsFilenameValid(string filename) { - var forbiddenChars = Path.GetInvalidFileNameChars(); - foreach (var forbiddenChar in forbiddenChars) { - if (filename == null || filename.Contains(forbiddenChar.ToString())) { - return false; - } - } - return true; - } - } -} diff --git a/GreenshotPlugin/Core/IEHelper.cs b/GreenshotPlugin/Core/IEHelper.cs deleted file mode 100644 index 2a85958fc..000000000 --- a/GreenshotPlugin/Core/IEHelper.cs +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using log4net; -using Microsoft.Win32; - -namespace GreenshotPlugin.Core { - /// - /// Description of IEHelper. - /// - public static class IEHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(IEHelper)); - // Internet explorer Registry key - private const string IeKey = @"Software\Microsoft\Internet Explorer"; - - /// - /// Get the current browser version - /// - /// int with browser version - public static int IEVersion - { - get - { - var maxVer = 7; - using (var ieKey = Registry.LocalMachine.OpenSubKey(IeKey, false)) - { - foreach (var value in new[] { "svcVersion", "svcUpdateVersion", "Version", "W2kVersion" }) - { - var objVal = ieKey.GetValue(value, "0"); - var strVal = Convert.ToString(objVal); - - var iPos = strVal.IndexOf('.'); - if (iPos > 0) - { - strVal = strVal.Substring(0, iPos); - } - - if (int.TryParse(strVal, out var res)) - { - maxVer = Math.Max(maxVer, res); - } - } - } - - return maxVer; - } - } - - /// - /// Get the highest possible version for the embedded browser - /// - /// true to ignore the doctype when loading a page - /// IE Feature - public static int GetEmbVersion(bool ignoreDoctype = true) - { - var ieVersion = IEVersion; - - if (ieVersion > 9) - { - return ieVersion * 1000 + (ignoreDoctype ? 1 : 0); - } - - if (ieVersion > 7) - { - return ieVersion * 1111; - } - - return 7000; - } - - /// - /// Fix browser version to the highest possible - /// - /// true to ignore the doctype when loading a page - public static void FixBrowserVersion(bool ignoreDoctype = true) - { - var applicationName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location); - FixBrowserVersion(applicationName, ignoreDoctype); - } - - /// - /// Fix the browser version for the specified application - /// - /// Name of the process - /// true to ignore the doctype when loading a page - public static void FixBrowserVersion(string applicationName, bool ignoreDoctype = true) - { - FixBrowserVersion(applicationName, GetEmbVersion(ignoreDoctype)); - } - - /// - /// Fix the browser version for the specified application - /// - /// Name of the process - /// - /// Version, see - /// Browser Emulation - /// - public static void FixBrowserVersion(string applicationName, int ieVersion) - { - ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".exe", ieVersion); -#if DEBUG - ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".vshost.exe", ieVersion); -#endif - } - - /// - /// Make the change to the registry - /// - /// HKEY_CURRENT_USER or something - /// Name of the executable - /// Version to use - private static void ModifyRegistry(string root, string applicationName, int ieFeatureVersion) - { - var regKey = root + @"\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION"; - try - { - Registry.SetValue(regKey, applicationName, ieFeatureVersion); - } - catch (Exception ex) - { - // some config will hit access rights exceptions - // this is why we try with both LOCAL_MACHINE and CURRENT_USER - Log.Error(ex); - Log.ErrorFormat("couldn't modify the registry key {0}", regKey); - } - } - - /// - /// Find the DirectUI window for MSAA (Accessible) - /// - /// The browser WindowDetails - /// WindowDetails for the DirectUI window - public static WindowDetails GetDirectUI(WindowDetails browserWindowDetails) { - if (browserWindowDetails == null) { - return null; - } - WindowDetails tmpWd = browserWindowDetails; - // Since IE 9 the TabBandClass is less deep! - if (IEVersion < 9) { - tmpWd = tmpWd.GetChild("CommandBarClass"); - tmpWd = tmpWd?.GetChild("ReBarWindow32"); - } - tmpWd = tmpWd?.GetChild("TabBandClass"); - tmpWd = tmpWd?.GetChild("DirectUIHWND"); - return tmpWd; - } - - /// - /// Return an IEnumerable with the currently opened IE urls - /// - /// - public static IEnumerable GetIEUrls() { - // Find the IE window - foreach (WindowDetails ieWindow in WindowDetails.GetAllWindows("IEFrame")) { - WindowDetails directUIWD = GetDirectUI(ieWindow); - if (directUIWD != null) { - Accessible ieAccessible = new Accessible(directUIWD.Handle); - foreach(string url in ieAccessible.IETabUrls) - { - yield return url; - } - } - } - } - } -} diff --git a/GreenshotPlugin/Core/IImage.cs b/GreenshotPlugin/Core/IImage.cs deleted file mode 100644 index 710a0d04d..000000000 --- a/GreenshotPlugin/Core/IImage.cs +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Drawing.Imaging; - -namespace GreenshotPlugin.Core -{ - /// - /// The image interface, this abstracts an image - /// - public interface IImage : IDisposable - { - /// - /// Height of the image, can be set to change - /// - int Height { get; set; } - - /// - /// Width of the image, can be set to change. - /// - int Width { get; set; } - - /// - /// Size of the image - /// - Size Size { get; } - - /// - /// Pixelformat of the underlying image - /// - PixelFormat PixelFormat { get; } - - /// - /// Vertical resolution of the underlying image - /// - float VerticalResolution { get; } - - /// - /// Horizontal resolution of the underlying image - /// - float HorizontalResolution { get; } - - /// - /// Unterlying image, or an on demand rendered version with different attributes as the original - /// - Image Image { get; } - } -} diff --git a/GreenshotPlugin/Core/ImageHelper.cs b/GreenshotPlugin/Core/ImageHelper.cs deleted file mode 100644 index 0f19462bd..000000000 --- a/GreenshotPlugin/Core/ImageHelper.cs +++ /dev/null @@ -1,1679 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using log4net; - -namespace GreenshotPlugin.Core { - internal enum ExifOrientations : byte { - Unknown = 0, - TopLeft = 1, - TopRight = 2, - BottomRight = 3, - BottomLeft = 4, - LeftTop = 5, - RightTop = 6, - RightBottom = 7, - LeftBottom = 8, - } - - /// - /// Description of ImageHelper. - /// - public static class ImageHelper { - private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const int ExifOrientationId = 0x0112; - - static ImageHelper() - { - StreamConverters["greenshot"] = (stream, s) => - { - var surface = SimpleServiceProvider.Current.GetInstance>().Invoke(); - return surface.GetImageForExport(); - }; - - // Add a SVG converter - StreamConverters["svg"] = (stream, s) => - { - stream.Position = 0; - try - { - return SvgImage.FromStream(stream).Image; - } - catch (Exception ex) - { - Log.Error("Can't load SVG", ex); - } - return null; - }; - - static Image DefaultConverter(Stream stream, string s) - { - stream.Position = 0; - using var tmpImage = Image.FromStream(stream, true, true); - Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - return Clone(tmpImage, PixelFormat.Format32bppArgb); - } - - // Fallback - StreamConverters[string.Empty] = DefaultConverter; - StreamConverters["gif"] = DefaultConverter; - StreamConverters["bmp"] = DefaultConverter; - StreamConverters["jpg"] = DefaultConverter; - StreamConverters["jpeg"] = DefaultConverter; - StreamConverters["png"] = DefaultConverter; - StreamConverters["wmf"] = DefaultConverter; - - StreamConverters["ico"] = (stream, extension) => - { - // Icon logic, try to get the Vista icon, else the biggest possible - try - { - using Image tmpImage = ExtractVistaIcon(stream); - if (tmpImage != null) - { - return Clone(tmpImage, PixelFormat.Format32bppArgb); - } - } - catch (Exception vistaIconException) - { - Log.Warn("Can't read icon", vistaIconException); - } - try - { - // No vista icon, try normal icon - stream.Position = 0; - // We create a copy of the bitmap, so everything else can be disposed - using Icon tmpIcon = new Icon(stream, new Size(1024, 1024)); - using Image tmpImage = tmpIcon.ToBitmap(); - return Clone(tmpImage, PixelFormat.Format32bppArgb); - } - catch (Exception iconException) - { - Log.Warn("Can't read icon", iconException); - } - - stream.Position = 0; - return DefaultConverter(stream, extension); - }; - } - - public static IDictionary> StreamConverters { get; } = new Dictionary>(); - - /// - /// Make sure the image is orientated correctly - /// - /// - public static void Orientate(Image image) - { - if (!CoreConfig.ProcessEXIFOrientation) - { - return; - } - try - { - // Get the index of the orientation property. - int orientationIndex = Array.IndexOf(image.PropertyIdList, ExifOrientationId); - // If there is no such property, return Unknown. - if (orientationIndex < 0) - { - return; - } - PropertyItem item = image.GetPropertyItem(ExifOrientationId); - - ExifOrientations orientation = (ExifOrientations)item.Value[0]; - // Orient the image. - switch (orientation) - { - case ExifOrientations.Unknown: - case ExifOrientations.TopLeft: - break; - case ExifOrientations.TopRight: - image.RotateFlip(RotateFlipType.RotateNoneFlipX); - break; - case ExifOrientations.BottomRight: - image.RotateFlip(RotateFlipType.Rotate180FlipNone); - break; - case ExifOrientations.BottomLeft: - image.RotateFlip(RotateFlipType.RotateNoneFlipY); - break; - case ExifOrientations.LeftTop: - image.RotateFlip(RotateFlipType.Rotate90FlipX); - break; - case ExifOrientations.RightTop: - image.RotateFlip(RotateFlipType.Rotate90FlipNone); - break; - case ExifOrientations.RightBottom: - image.RotateFlip(RotateFlipType.Rotate90FlipY); - break; - case ExifOrientations.LeftBottom: - image.RotateFlip(RotateFlipType.Rotate270FlipNone); - break; - } - // Set the orientation to be normal, as we rotated the image. - item.Value[0] = (byte)ExifOrientations.TopLeft; - image.SetPropertyItem(item); - } - catch (Exception orientEx) - { - Log.Warn("Problem orientating the image: ", orientEx); - } - } - - /// - /// Create a Thumbnail - /// - /// - /// - /// - /// - /// - /// - public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight, int maxWidth = -1, int maxHeight = -1) - { - int srcWidth = image.Width; - int srcHeight = image.Height; - if (thumbHeight < 0) - { - thumbHeight = (int)(thumbWidth * (srcHeight / (float)srcWidth)); - } - if (thumbWidth < 0) - { - thumbWidth = (int)(thumbHeight * (srcWidth / (float)srcHeight)); - } - if (maxWidth > 0 && thumbWidth > maxWidth) - { - thumbWidth = Math.Min(thumbWidth, maxWidth); - thumbHeight = (int)(thumbWidth * (srcHeight / (float)srcWidth)); - } - if (maxHeight > 0 && thumbHeight > maxHeight) - { - thumbHeight = Math.Min(thumbHeight, maxHeight); - thumbWidth = (int)(thumbHeight * (srcWidth / (float)srcHeight)); - } - - Bitmap bmp = new Bitmap(thumbWidth, thumbHeight); - using (Graphics graphics = Graphics.FromImage(bmp)) - { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight); - graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); - } - return bmp; - } - - /// - /// Crops the image to the specified rectangle - /// - /// Image to crop - /// Rectangle with bitmap coordinates, will be "intersected" to the bitmap - public static bool Crop(ref Image image, ref Rectangle cropRectangle) - { - if (image is Bitmap && (image.Width * image.Height > 0)) - { - cropRectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height)); - if (cropRectangle.Width != 0 || cropRectangle.Height != 0) - { - Image returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare); - image.Dispose(); - image = returnImage; - return true; - } - } - Log.Warn("Can't crop a null/zero size image!"); - return false; - } - - /// - /// Private helper method for the FindAutoCropRectangle - /// - /// - /// - /// - /// Rectangle - private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) - { - Rectangle cropRectangle = Rectangle.Empty; - Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); - Point min = new Point(int.MaxValue, int.MaxValue); - Point max = new Point(int.MinValue, int.MinValue); - - if (cropDifference > 0) - { - for (int y = 0; y < fastBitmap.Height; y++) - { - for (int x = 0; x < fastBitmap.Width; x++) - { - Color currentColor = fastBitmap.GetColorAt(x, y); - int diffR = Math.Abs(currentColor.R - referenceColor.R); - int diffG = Math.Abs(currentColor.G - referenceColor.G); - int diffB = Math.Abs(currentColor.B - referenceColor.B); - if ((diffR + diffG + diffB) / 3 <= cropDifference) - { - continue; - } - if (x < min.X) min.X = x; - if (y < min.Y) min.Y = y; - if (x > max.X) max.X = x; - if (y > max.Y) max.Y = y; - } - } - } - else - { - for (int y = 0; y < fastBitmap.Height; y++) - { - for (int x = 0; x < fastBitmap.Width; x++) - { - Color currentColor = fastBitmap.GetColorAt(x, y); - if (!referenceColor.Equals(currentColor)) - { - continue; - } - if (x < min.X) min.X = x; - if (y < min.Y) min.Y = y; - if (x > max.X) max.X = x; - if (y > max.Y) max.Y = y; - } - } - } - - if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) - { - if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) - { - cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); - } - } - return cropRectangle; - } - - /// - /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 - /// - /// - /// - /// Rectangle - public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) - { - Rectangle cropRectangle = Rectangle.Empty; - var checkPoints = new List - { - new Point(0, 0), - new Point(0, image.Height - 1), - new Point(image.Width - 1, 0), - new Point(image.Width - 1, image.Height - 1) - }; - // Top Left - // Bottom Left - // Top Right - // Bottom Right - using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap)image)) - { - // find biggest area - foreach (Point checkPoint in checkPoints) - { - var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); - if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) - { - cropRectangle = currentRectangle; - } - } - } - return cropRectangle; - } - - /// - /// Load an image from file - /// - /// - /// - public static Image LoadImage(string filename) - { - if (string.IsNullOrEmpty(filename)) - { - return null; - } - if (!File.Exists(filename)) - { - return null; - } - Image fileImage; - Log.InfoFormat("Loading image from file {0}", filename); - // Fixed lock problem Bug #3431881 - using (Stream imageFileStream = File.OpenRead(filename)) - { - fileImage = FromStream(imageFileStream, Path.GetExtension(filename)); - } - if (fileImage != null) - { - Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat, fileImage.HorizontalResolution, fileImage.VerticalResolution); - } - return fileImage; - } - - /// - /// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx - /// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx - /// - /// Stream with the icon information - /// Bitmap with the Vista Icon (256x256) - private static Bitmap ExtractVistaIcon(Stream iconStream) - { - const int sizeIconDir = 6; - const int sizeIconDirEntry = 16; - Bitmap bmpPngExtracted = null; - try - { - byte[] srcBuf = new byte[iconStream.Length]; - iconStream.Read(srcBuf, 0, (int)iconStream.Length); - int iCount = BitConverter.ToInt16(srcBuf, 4); - for (int iIndex = 0; iIndex < iCount; iIndex++) - { - int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex]; - int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1]; - if (iWidth == 0 && iHeight == 0) - { - int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); - int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); - using MemoryStream destStream = new MemoryStream(); - destStream.Write(srcBuf, iImageOffset, iImageSize); - destStream.Seek(0, SeekOrigin.Begin); - bmpPngExtracted = new Bitmap(destStream); // This is PNG! :) - break; - } - } - } - catch - { - return null; - } - return bmpPngExtracted; - } - - /// - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx - /// - /// The file (EXE or DLL) to get the icon from - /// Index of the icon - /// true if the large icon is wanted - /// Icon - public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) - { - Shell32.ExtractIconEx(location, index, out var large, out var small, 1); - Icon returnIcon = null; - bool isLarge = false; - bool isSmall = false; - try - { - if (takeLarge && !IntPtr.Zero.Equals(large)) - { - returnIcon = Icon.FromHandle(large); - isLarge = true; - } - else if (!IntPtr.Zero.Equals(small)) - { - returnIcon = Icon.FromHandle(small); - isSmall = true; - } - else if (!IntPtr.Zero.Equals(large)) - { - returnIcon = Icon.FromHandle(large); - isLarge = true; - } - } - finally - { - if (isLarge && !IntPtr.Zero.Equals(small)) - { - User32.DestroyIcon(small); - } - if (isSmall && !IntPtr.Zero.Equals(large)) - { - User32.DestroyIcon(large); - } - } - return returnIcon; - } - - /// - /// Apply the effect to the bitmap - /// - /// Bitmap - /// IEffect - /// - /// Bitmap - public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix) - { - var effects = new List { effect }; - return ApplyEffects(sourceImage, effects, matrix); - } - - /// - /// Apply the effects in the supplied order to the bitmap - /// - /// Bitmap - /// List of IEffect - /// - /// Bitmap - public static Image ApplyEffects(Image sourceImage, IEnumerable effects, Matrix matrix) - { - var currentImage = sourceImage; - bool disposeImage = false; - foreach (var effect in effects) - { - var tmpImage = effect.Apply(currentImage, matrix); - if (tmpImage != null) - { - if (disposeImage) - { - currentImage.Dispose(); - } - currentImage = tmpImage; - // Make sure the "new" image is disposed - disposeImage = true; - } - } - return currentImage; - } - - /// - /// Helper method for the tornedge - /// - /// Path to draw to - /// Points for the lines to draw - private static void DrawLines(GraphicsPath path, List points) - { - path.AddLine(points[0], points[1]); - for (int i = 0; i < points.Count - 1; i++) - { - path.AddLine(points[i], points[i + 1]); - } - } - - /// - /// Make the picture look like it's torn - /// - /// Bitmap to make torn edge off - /// How large (height) is each tooth - /// How wide is a horizontal tooth - /// How wide is a vertical tooth - /// bool[] with information on if the edge needs torn or not. Order is clockwise: 0=top,1=right,2=bottom,3=left - /// Changed bitmap - public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, bool[] edges) - { - Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (var path = new GraphicsPath()) - { - Random random = new Random(); - int horizontalRegions = (int)Math.Round((float)sourceImage.Width / horizontalToothRange); - int verticalRegions = (int)Math.Round((float)sourceImage.Height / verticalToothRange); - - Point topLeft = new Point(0, 0); - Point topRight = new Point(sourceImage.Width, 0); - Point bottomLeft = new Point(0, sourceImage.Height); - Point bottomRight = new Point(sourceImage.Width, sourceImage.Height); - - List points = new List(); - - if (edges[0]) - { - // calculate starting point only if the left edge is torn - if (!edges[3]) - { - points.Add(topLeft); - } - else - { - points.Add(new Point(random.Next(1, toothHeight), random.Next(1, toothHeight))); - } - for (int i = 1; i < horizontalRegions - 1; i++) - { - points.Add(new Point(i * horizontalToothRange, random.Next(1, toothHeight))); - } - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight))); - } - else - { - // set start & endpoint to be the default "whole-line" - points.Add(topLeft); - points.Add(topRight); - } - // Right - if (edges[1]) - { - for (int i = 1; i < verticalRegions - 1; i++) - { - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange)); - } - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); - } - else - { - // correct previous ending point - points[points.Count - 1] = topRight; - // set endpoint to be the default "whole-line" - points.Add(bottomRight); - } - // Bottom - if (edges[2]) - { - for (int i = 1; i < horizontalRegions - 1; i++) - { - points.Add(new Point(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight))); - } - points.Add(new Point(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); - } - else - { - // correct previous ending point - points[points.Count - 1] = bottomRight; - // set endpoint to be the default "whole-line" - points.Add(bottomLeft); - } - // Left - if (edges[3]) - { - // One fewer as the end point is the starting point - for (int i = 1; i < verticalRegions - 1; i++) - { - points.Add(new Point(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange)); - } - } - else - { - // correct previous ending point - points[points.Count - 1] = bottomLeft; - // set endpoint to be the default "whole-line" - points.Add(topLeft); - } - // End point always is the starting point - points[points.Count - 1] = points[0]; - - DrawLines(path, points); - - path.CloseFigure(); - - // Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing - using Graphics graphics = Graphics.FromImage(returnImage); - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - using Brush brush = new TextureBrush(sourceImage); - // Important note: If the target wouldn't be at 0,0 we need to translate-transform!! - graphics.FillPath(brush, path); - } - return returnImage; - } - - /// - /// Apply BoxBlur to the destinationBitmap - /// - /// Bitmap to blur - /// Must be ODD! - public static void ApplyBoxBlur(Bitmap destinationBitmap, int range) - { - // We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V) - using IFastBitmap fastBitmap = FastBitmap.Create(destinationBitmap); - ApplyBoxBlur(fastBitmap, range); - } - - /// - /// Apply BoxBlur to the fastBitmap - /// - /// IFastBitmap to blur - /// Must be ODD! - public static void ApplyBoxBlur(IFastBitmap fastBitmap, int range) - { - // Range must be odd! - if ((range & 1) == 0) - { - range++; - } - if (range <= 1) - { - return; - } - // Box blurs are frequently used to approximate a Gaussian blur. - // By the central limit theorem, if applied 3 times on the same image, a box blur approximates the Gaussian kernel to within about 3%, yielding the same result as a quadratic convolution kernel. - // This might be true, but the GDI+ BlurEffect doesn't look the same, a 2x blur is more simular and we only make 2x Box-Blur. - // (Might also be a mistake in our blur, but for now it looks great) - if (fastBitmap.HasAlphaChannel) - { - BoxBlurHorizontalAlpha(fastBitmap, range); - BoxBlurVerticalAlpha(fastBitmap, range); - BoxBlurHorizontalAlpha(fastBitmap, range); - BoxBlurVerticalAlpha(fastBitmap, range); - } - else - { - BoxBlurHorizontal(fastBitmap, range); - BoxBlurVertical(fastBitmap, range); - BoxBlurHorizontal(fastBitmap, range); - BoxBlurVertical(fastBitmap, range); - } - } - - /// - /// BoxBlurHorizontal is a private helper method for the BoxBlur - /// - /// Target BitmapBuffer - /// Range must be odd! - private static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) - { - if (targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel"); - } - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Width]; - byte[] tmpColor = new byte[3]; - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - int hits = 0; - int r = 0; - int g = 0; - int b = 0; - for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) - { - int oldPixel = x - halfRange - 1; - if (oldPixel >= targetFastBitmap.Left) - { - targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } - - int newPixel = x + halfRange; - if (newPixel < targetFastBitmap.Right) - { - targetFastBitmap.GetColorAt(newPixel, y, tmpColor); - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } - - if (x >= targetFastBitmap.Left) - { - newColors[x - targetFastBitmap.Left] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); - } - } - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); - } - } - } - /// - /// BoxBlurHorizontal is a private helper method for the BoxBlur, only for IFastBitmaps with alpha channel - /// - /// Target BitmapBuffer - /// Range must be odd! - private static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) - { - if (!targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel"); - } - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Width]; - byte[] tmpColor = new byte[4]; - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - int hits = 0; - int a = 0; - int r = 0; - int g = 0; - int b = 0; - for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) - { - int oldPixel = x - halfRange - 1; - if (oldPixel >= targetFastBitmap.Left) - { - targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); - a -= tmpColor[FastBitmap.ColorIndexA]; - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } - - int newPixel = x + halfRange; - if (newPixel < targetFastBitmap.Right) - { - targetFastBitmap.GetColorAt(newPixel, y, tmpColor); - a += tmpColor[FastBitmap.ColorIndexA]; - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } - - if (x >= targetFastBitmap.Left) - { - newColors[x - targetFastBitmap.Left] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); - } - } - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); - } - } - } - - /// - /// BoxBlurVertical is a private helper method for the BoxBlur - /// - /// BitmapBuffer which previously was created with BoxBlurHorizontal - /// Range must be odd! - private static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) - { - if (targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel"); - } - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Height]; - byte[] tmpColor = new byte[4]; - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - int hits = 0; - int r = 0; - int g = 0; - int b = 0; - for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) - { - int oldPixel = y - halfRange - 1; - if (oldPixel >= targetFastBitmap.Top) - { - targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } - - int newPixel = y + halfRange; - if (newPixel < targetFastBitmap.Bottom) - { - targetFastBitmap.GetColorAt(x, newPixel, tmpColor); - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } - - if (y >= targetFastBitmap.Top) - { - newColors[y - targetFastBitmap.Top] = Color.FromArgb(255, (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); - } - } - - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); - } - } - } - - /// - /// BoxBlurVertical is a private helper method for the BoxBlur - /// - /// BitmapBuffer which previously was created with BoxBlurHorizontal - /// Range must be odd! - private static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) - { - if (!targetFastBitmap.HasAlphaChannel) - { - throw new NotSupportedException("BoxBlurVerticalAlpha should be called for bitmaps with alpha channel"); - } - - int halfRange = range / 2; - Color[] newColors = new Color[targetFastBitmap.Height]; - byte[] tmpColor = new byte[4]; - for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) - { - int hits = 0; - int a = 0; - int r = 0; - int g = 0; - int b = 0; - for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) - { - int oldPixel = y - halfRange - 1; - if (oldPixel >= targetFastBitmap.Top) - { - targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); - a -= tmpColor[FastBitmap.ColorIndexA]; - r -= tmpColor[FastBitmap.ColorIndexR]; - g -= tmpColor[FastBitmap.ColorIndexG]; - b -= tmpColor[FastBitmap.ColorIndexB]; - hits--; - } - - int newPixel = y + halfRange; - if (newPixel < targetFastBitmap.Bottom) - { - //int colorg = pixels[index + newPixelOffset]; - targetFastBitmap.GetColorAt(x, newPixel, tmpColor); - a += tmpColor[FastBitmap.ColorIndexA]; - r += tmpColor[FastBitmap.ColorIndexR]; - g += tmpColor[FastBitmap.ColorIndexG]; - b += tmpColor[FastBitmap.ColorIndexB]; - hits++; - } - - if (y >= targetFastBitmap.Top) - { - newColors[y - targetFastBitmap.Top] = Color.FromArgb((byte)(a / hits), (byte)(r / hits), (byte)(g / hits), (byte)(b / hits)); - } - } - - for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) - { - targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); - } - } - } - - /// - /// This method fixes the problem that we can't apply a filter outside the target bitmap, - /// therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap. - /// It will also account for the Invert flag. - /// - /// - /// - /// - /// - public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) - { - Rectangle myRect; - if (invert) - { - myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); - } - else - { - Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height); - myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); - myRect.Intersect(applyRect); - } - return myRect; - } - - /// - /// Create a new bitmap where the sourceBitmap has a shadow - /// - /// Bitmap to make a shadow on - /// How dark is the shadow - /// Size of the shadow - /// What pixel format must the returning bitmap have - /// - /// The transform matrix which describes how the elements need to be transformed to stay at the same location - /// Bitmap with the shadow, is bigger than the sourceBitmap!! - public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, Matrix matrix, PixelFormat targetPixelformat) - { - Point offset = shadowOffset; - offset.X += shadowSize - 1; - offset.Y += shadowSize - 1; - matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); - // Create a new "clean" image - Bitmap returnImage = CreateEmpty(sourceBitmap.Width + shadowSize * 2, sourceBitmap.Height + shadowSize * 2, targetPixelformat, Color.Empty, sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); - // Make sure the shadow is odd, there is no reason for an even blur! - if ((shadowSize & 1) == 0) - { - shadowSize++; - } - bool useGdiBlur = GDIplus.IsBlurPossible(shadowSize); - // Create "mask" for the shadow - ColorMatrix maskMatrix = new ColorMatrix - { - Matrix00 = 0, - Matrix11 = 0, - Matrix22 = 0 - }; - if (useGdiBlur) - { - maskMatrix.Matrix33 = darkness + 0.1f; - } - else - { - maskMatrix.Matrix33 = darkness; - } - Rectangle shadowRectangle = new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size); - ApplyColorMatrix((Bitmap)sourceBitmap, Rectangle.Empty, returnImage, shadowRectangle, maskMatrix); - - // blur "shadow", apply to whole new image - if (useGdiBlur) - { - // Use GDI Blur - Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height); - GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize + 1, false); - } - else - { - // try normal software blur - //returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); - ApplyBoxBlur(returnImage, shadowSize); - } - - // Draw the original image over the shadow - using (Graphics graphics = Graphics.FromImage(returnImage)) - { - // Make sure we draw with the best quality! - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - // draw original with a TextureBrush so we have nice antialiasing! - using Brush textureBrush = new TextureBrush(sourceBitmap, WrapMode.Clamp); - // We need to do a translate-transform otherwise the image is wrapped - graphics.TranslateTransform(offset.X, offset.Y); - graphics.FillRectangle(textureBrush, 0, 0, sourceBitmap.Width, sourceBitmap.Height); - } - return returnImage; - } - - /// - /// Return negative of Bitmap - /// - /// Bitmap to create a negative off - /// Negative bitmap - public static Bitmap CreateNegative(Image sourceImage) - { - Bitmap clone = (Bitmap)Clone(sourceImage); - ColorMatrix invertMatrix = new ColorMatrix(new[] { - new float[] {-1, 0, 0, 0, 0}, - new float[] {0, -1, 0, 0, 0}, - new float[] {0, 0, -1, 0, 0}, - new float[] {0, 0, 0, 1, 0}, - new float[] {1, 1, 1, 1, 1} - }); - ApplyColorMatrix(clone, invertMatrix); - return clone; - } - /// - /// Apply a color matrix to the image - /// - /// Image to apply matrix to - /// ColorMatrix to apply - public static void ApplyColorMatrix(Bitmap source, ColorMatrix colorMatrix) - { - ApplyColorMatrix(source, Rectangle.Empty, source, Rectangle.Empty, colorMatrix); - } - - /// - /// Apply a color matrix by copying from the source to the destination - /// - /// Image to copy from - /// Rectangle to copy from - /// Rectangle to copy to - /// Image to copy to - /// ColorMatrix to apply - public static void ApplyColorMatrix(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ColorMatrix colorMatrix) - { - using ImageAttributes imageAttributes = new ImageAttributes(); - imageAttributes.ClearColorMatrix(); - imageAttributes.SetColorMatrix(colorMatrix); - ApplyImageAttributes(source, sourceRect, dest, destRect, imageAttributes); - } - - /// - /// Apply a color matrix by copying from the source to the destination - /// - /// Image to copy from - /// Rectangle to copy from - /// Rectangle to copy to - /// Image to copy to - /// ImageAttributes to apply - public static void ApplyImageAttributes(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ImageAttributes imageAttributes) - { - if (sourceRect == Rectangle.Empty) - { - sourceRect = new Rectangle(0, 0, source.Width, source.Height); - } - if (dest == null) - { - dest = source; - } - if (destRect == Rectangle.Empty) - { - destRect = new Rectangle(0, 0, dest.Width, dest.Height); - } - - using Graphics graphics = Graphics.FromImage(dest); - // Make sure we draw with the best quality! - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingMode = CompositingMode.SourceCopy; - - graphics.DrawImage(source, destRect, sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height, GraphicsUnit.Pixel, imageAttributes); - } - - /// - /// Returns a b/w of Bitmap - /// - /// Bitmap to create a b/w of - /// Threshold for monochrome filter (0 - 255), lower value means less black - /// b/w bitmap - public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) - { - using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat); - for (int y = 0; y < fastBitmap.Height; y++) - { - for (int x = 0; x < fastBitmap.Width; x++) - { - Color color = fastBitmap.GetColorAt(x, y); - int colorBrightness = (color.R + color.G + color.B) / 3 > threshold ? 255 : 0; - Color monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness); - fastBitmap.SetColorAt(x, y, monoColor); - } - } - return fastBitmap.UnlockAndReturnBitmap(); - } - - /// - /// Create a new bitmap where the sourceBitmap has a Simple border around it - /// - /// Bitmap to make a border on - /// Size of the border - /// Color of the border - /// What pixel format must the returning bitmap have - /// The transform matrix which describes how the elements need to be transformed to stay at the same location - /// Bitmap with the shadow, is bigger than the sourceBitmap!! - public static Image CreateBorder(Image sourceImage, int borderSize, Color borderColor, PixelFormat targetPixelformat, Matrix matrix) - { - // "return" the shifted offset, so the caller can e.g. move elements - Point offset = new Point(borderSize, borderSize); - matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); - - // Create a new "clean" image - Bitmap newImage = CreateEmpty(sourceImage.Width + borderSize * 2, sourceImage.Height + borderSize * 2, targetPixelformat, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (Graphics graphics = Graphics.FromImage(newImage)) - { - // Make sure we draw with the best quality! - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - using (GraphicsPath path = new GraphicsPath()) - { - path.AddRectangle(new Rectangle(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize)); - using Pen pen = new Pen(borderColor, borderSize) - { - LineJoin = LineJoin.Round, - StartCap = LineCap.Round, - EndCap = LineCap.Round - }; - graphics.DrawPath(pen, path); - } - // draw original with a TextureBrush so we have nice antialiasing! - using Brush textureBrush = new TextureBrush(sourceImage, WrapMode.Clamp); - // We need to do a translate-tranform otherwise the image is wrapped - graphics.TranslateTransform(offset.X, offset.Y); - graphics.FillRectangle(textureBrush, 0, 0, sourceImage.Width, sourceImage.Height); - } - return newImage; - } - - /// - /// Create ImageAttributes to modify - /// - /// - /// - /// - /// ImageAttributes - public static ImageAttributes CreateAdjustAttributes(float brightness, float contrast, float gamma) - { - float adjustedBrightness = brightness - 1.0f; - ColorMatrix applyColorMatrix = new ColorMatrix( - new[] - { - new[] {contrast, 0, 0, 0, 0}, // scale red - new[] {0, contrast, 0, 0, 0}, // scale green - new[] {0, 0, contrast, 0, 0}, // scale blue - new[] {0, 0, 0, 1.0f, 0}, // don't scale alpha - new[] {adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1} - }); - - //create some image attributes - ImageAttributes attributes = new ImageAttributes(); - attributes.ClearColorMatrix(); - attributes.SetColorMatrix(applyColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); - attributes.SetGamma(gamma, ColorAdjustType.Bitmap); - return attributes; - } - - /// - /// Adjust the brightness, contract or gamma of an image. - /// Use the value "1.0f" for no changes. - /// - /// Original bitmap - /// - /// - /// - /// Bitmap with grayscale - public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) - { - //create a blank bitmap the same size as original - // If using 8bpp than the following exception comes: A Graphics object cannot be created from an image that has an indexed pixel format. - Bitmap newBitmap = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format24bppRgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (ImageAttributes adjustAttributes = CreateAdjustAttributes(brightness, contrast, gamma)) - { - ApplyImageAttributes((Bitmap)sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, adjustAttributes); - } - return newBitmap; - } - - /// - /// Create a new bitmap where the sourceBitmap is in grayscale - /// - /// Original bitmap - /// Bitmap with grayscale - public static Image CreateGrayscale(Image sourceImage) - { - Bitmap clone = (Bitmap)Clone(sourceImage); - ColorMatrix grayscaleMatrix = new ColorMatrix(new[] - { - new[] {.3f, .3f, .3f, 0, 0}, - new[] {.59f, .59f, .59f, 0, 0}, - new[] {.11f, .11f, .11f, 0, 0}, - new float[] {0, 0, 0, 1, 0}, - new float[] {0, 0, 0, 0, 1} - }); - ApplyColorMatrix(clone, grayscaleMatrix); - return clone; - } - - /// - /// Checks if we support the pixel format - /// - /// PixelFormat to check - /// bool if we support it - public static bool SupportsPixelFormat(PixelFormat pixelformat) - { - return pixelformat.Equals(PixelFormat.Format32bppArgb) || - pixelformat.Equals(PixelFormat.Format32bppPArgb) || - pixelformat.Equals(PixelFormat.Format32bppRgb) || - pixelformat.Equals(PixelFormat.Format24bppRgb); - } - - /// - /// Wrapper for just cloning which calls the CloneArea - /// - /// Image to clone - /// Bitmap with clone image data - public static Image Clone(Image sourceImage) - { - if (sourceImage is Metafile) - { - return (Image)sourceImage.Clone(); - } - return CloneArea(sourceImage, Rectangle.Empty, PixelFormat.DontCare); - } - - /// - /// Wrapper for just cloning & TargetFormat which calls the CloneArea - /// - /// Image to clone - /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) - /// Bitmap with clone image data - public static Bitmap Clone(Image sourceBitmap, PixelFormat targetFormat) - { - return CloneArea(sourceBitmap, Rectangle.Empty, targetFormat); - } - - /// - /// Clone an image, taking some rules into account: - /// 1) When sourceRect is the whole bitmap there is a GDI+ bug in Clone - /// Clone will than return the same PixelFormat as the source - /// a quick workaround is using new Bitmap which uses a default of Format32bppArgb - /// 2) When going from a transparent to a non transparent bitmap, we draw the background white! - /// - /// Source bitmap to clone - /// Rectangle to copy from the source, use Rectangle.Empty for all - /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) - /// - public static Bitmap CloneArea(Image sourceImage, Rectangle sourceRect, PixelFormat targetFormat) - { - Bitmap newImage; - Rectangle bitmapRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); - - // Make sure the source is not Rectangle.Empty - if (Rectangle.Empty.Equals(sourceRect)) - { - sourceRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); - } - else - { - sourceRect.Intersect(bitmapRect); - } - - // If no pixelformat is supplied - if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) - { - if (SupportsPixelFormat(sourceImage.PixelFormat)) - { - targetFormat = sourceImage.PixelFormat; - } - else if (Image.IsAlphaPixelFormat(sourceImage.PixelFormat)) - { - targetFormat = PixelFormat.Format32bppArgb; - } - else - { - targetFormat = PixelFormat.Format24bppRgb; - } - } - - // check the target format - if (!SupportsPixelFormat(targetFormat)) - { - targetFormat = Image.IsAlphaPixelFormat(targetFormat) ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb; - } - - bool destinationIsTransparent = Image.IsAlphaPixelFormat(targetFormat); - bool sourceIsTransparent = Image.IsAlphaPixelFormat(sourceImage.PixelFormat); - bool fromTransparentToNon = !destinationIsTransparent && sourceIsTransparent; - bool isBitmap = sourceImage is Bitmap; - bool isAreaEqual = sourceRect.Equals(bitmapRect); - if (isAreaEqual || fromTransparentToNon || !isBitmap) - { - // Rule 1: if the areas are equal, always copy ourselves - newImage = new Bitmap(bitmapRect.Width, bitmapRect.Height, targetFormat); - // Make sure both images have the same resolution - newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - - using Graphics graphics = Graphics.FromImage(newImage); - if (fromTransparentToNon) - { - // Rule 2: Make sure the background color is white - graphics.Clear(Color.White); - } - // decide fastest copy method - if (isAreaEqual) - { - graphics.DrawImageUnscaled(sourceImage, 0, 0); - } - else - { - graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel); - } - } - else - { - // Let GDI+ decide how to convert, need to test what is quicker... - newImage = (sourceImage as Bitmap).Clone(sourceRect, targetFormat); - // Make sure both images have the same resolution - newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - } - - // In WINE someone getting the PropertyItems doesn't work - try - { - // Clone property items (EXIF information etc) - foreach (var propertyItem in sourceImage.PropertyItems) - { - try - { - newImage.SetPropertyItem(propertyItem); - } - catch (Exception innerEx) - { - Log.Warn("Problem cloning a propertyItem.", innerEx); - } - } - } - catch (Exception ex) - { - Log.Warn("Problem cloning a propertyItem.", ex); - } - return newImage; - } - - /// - /// Rotate the bitmap - /// - /// - /// - /// - public static Image RotateFlip(Image sourceImage, RotateFlipType rotateFlipType) - { - Image returnImage = Clone(sourceImage); - returnImage.RotateFlip(rotateFlipType); - return returnImage; - } - - /// - /// A generic way to create an empty image - /// - /// the source bitmap as the specifications for the new bitmap - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - public static Bitmap CreateEmptyLike(Image sourceImage, Color backgroundColor) - { - PixelFormat pixelFormat = sourceImage.PixelFormat; - if (backgroundColor.A < 255) - { - pixelFormat = PixelFormat.Format32bppArgb; - } - return CreateEmpty(sourceImage.Width, sourceImage.Height, pixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - } - - /// - /// A generic way to create an empty image - /// - /// - /// - /// - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - /// - /// Bitmap - public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution, float verticalResolution) - { - // Create a new "clean" image - Bitmap newImage = new Bitmap(width, height, format); - newImage.SetResolution(horizontalResolution, verticalResolution); - if (format != PixelFormat.Format8bppIndexed) - { - using Graphics graphics = Graphics.FromImage(newImage); - // Make sure the background color is what we want (transparent or white, depending on the pixel format) - if (!Color.Empty.Equals(backgroundColor)) - { - graphics.Clear(backgroundColor); - } - else if (Image.IsAlphaPixelFormat(format)) - { - graphics.Clear(Color.Transparent); - } - else - { - graphics.Clear(Color.White); - } - } - return newImage; - } - - /// - /// Resize canvas with pixel to the left, right, top and bottom - /// - /// - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - /// - /// - /// - /// - /// a new bitmap with the source copied on it - public static Image ResizeCanvas(Image sourceImage, Color backgroundColor, int left, int right, int top, int bottom, Matrix matrix) - { - matrix.Translate(left, top, MatrixOrder.Append); - Bitmap newBitmap = CreateEmpty(sourceImage.Width + left + right, sourceImage.Height + top + bottom, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - using (Graphics graphics = Graphics.FromImage(newBitmap)) - { - graphics.DrawImageUnscaled(sourceImage, left, top); - } - return newBitmap; - } - - /// - /// Wrapper for the more complex Resize, this resize could be used for e.g. Thumbnails - /// - /// - /// true to maintain the aspect ratio - /// - /// - /// - /// - public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, int newWidth, int newHeight, Matrix matrix) - { - return ResizeImage(sourceImage, maintainAspectRatio, false, Color.Empty, newWidth, newHeight, matrix); - } - - /// - /// Count how many times the supplied color exists - /// - /// Image to count the pixels of - /// Color to count - /// true if Alpha needs to be checked - /// int with the number of pixels which have colorToCount - public static int CountColor(Image sourceImage, Color colorToCount, bool includeAlpha) - { - int colors = 0; - int toCount = colorToCount.ToArgb(); - if (!includeAlpha) - { - toCount &= 0xffffff; - } - - using IFastBitmap bb = FastBitmap.Create((Bitmap)sourceImage); - for (int y = 0; y < bb.Height; y++) - { - for (int x = 0; x < bb.Width; x++) - { - int bitmapcolor = bb.GetColorAt(x, y).ToArgb(); - if (!includeAlpha) - { - bitmapcolor &= 0xffffff; - } - if (bitmapcolor == toCount) - { - colors++; - } - } - } - return colors; - } - - /// - /// Scale the bitmap, keeping aspect ratio, but the canvas will always have the specified size. - /// - /// Image to scale - /// true to maintain the aspect ratio - /// Makes the image maintain aspect ratio, but the canvas get's the specified size - /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// new width - /// new height - /// - /// a new bitmap with the specified size, the source-Image scaled to fit with aspect ratio locked - public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, bool canvasUseNewSize, Color backgroundColor, int newWidth, int newHeight, Matrix matrix) - { - int destX = 0; - int destY = 0; - - var nPercentW = newWidth / (float)sourceImage.Width; - var nPercentH = newHeight / (float)sourceImage.Height; - if (maintainAspectRatio) - { - if ((int)nPercentW == 1) - { - nPercentW = nPercentH; - if (canvasUseNewSize) - { - destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); - } - } - else if ((int)nPercentH == 1) - { - nPercentH = nPercentW; - if (canvasUseNewSize) - { - destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); - } - } - else if ((int)nPercentH != 0 && nPercentH < nPercentW) - { - nPercentW = nPercentH; - if (canvasUseNewSize) - { - destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); - } - } - else - { - nPercentH = nPercentW; - if (canvasUseNewSize) - { - destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); - } - } - } - - int destWidth = (int)(sourceImage.Width * nPercentW); - int destHeight = (int)(sourceImage.Height * nPercentH); - if (newWidth == 0) - { - newWidth = destWidth; - } - if (newHeight == 0) - { - newHeight = destHeight; - } - Image newImage; - if (maintainAspectRatio && canvasUseNewSize) - { - newImage = CreateEmpty(newWidth, newHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - matrix?.Scale((float)newWidth / sourceImage.Width, (float)newHeight / sourceImage.Height, MatrixOrder.Append); - } - else - { - newImage = CreateEmpty(destWidth, destHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); - matrix?.Scale((float)destWidth / sourceImage.Width, (float)destHeight / sourceImage.Height, MatrixOrder.Append); - } - - using (Graphics graphics = Graphics.FromImage(newImage)) - { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - using ImageAttributes wrapMode = new ImageAttributes(); - wrapMode.SetWrapMode(WrapMode.TileFlipXY); - graphics.DrawImage(sourceImage, new Rectangle(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode); - } - return newImage; - } - - /// - /// Load a Greenshot surface from a stream - /// - /// Stream - /// - /// ISurface - public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface) - { - Image fileImage; - // Fixed problem that the bitmap stream is disposed... by Cloning the image - // This also ensures the bitmap is correctly created - - // We create a copy of the bitmap, so everything else can be disposed - surfaceFileStream.Position = 0; - using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) - { - Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - fileImage = Clone(tmpImage); - } - // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) - const int markerSize = 14; - surfaceFileStream.Seek(-markerSize, SeekOrigin.End); - using (StreamReader streamReader = new StreamReader(surfaceFileStream)) - { - var greenshotMarker = streamReader.ReadToEnd(); - if (!greenshotMarker.StartsWith("Greenshot")) - { - throw new ArgumentException("Stream is not a Greenshot file!"); - } - Log.InfoFormat("Greenshot file format: {0}", greenshotMarker); - const int filesizeLocation = 8 + markerSize; - surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); - using BinaryReader reader = new BinaryReader(surfaceFileStream); - long bytesWritten = reader.ReadInt64(); - surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End); - returnSurface.LoadElementsFromStream(surfaceFileStream); - } - if (fileImage != null) - { - returnSurface.Image = fileImage; - Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat, fileImage.HorizontalResolution, fileImage.VerticalResolution); - } - return returnSurface; - } - - /// - /// Create an image from a stream, if an extension is supplied more formats are supported. - /// - /// Stream - /// - /// Image - public static Image FromStream(Stream stream, string extension = null) - { - if (stream == null) - { - return null; - } - if (!string.IsNullOrEmpty(extension)) - { - extension = extension.Replace(".", string.Empty); - } - - // Make sure we can try multiple times - if (!stream.CanSeek) - { - var memoryStream = new MemoryStream(); - stream.CopyTo(memoryStream); - stream = memoryStream; - } - - Image returnImage = null; - if (StreamConverters.TryGetValue(extension ?? string.Empty, out var converter)) - { - returnImage = converter(stream, extension); - } - // Fallback - if (returnImage == null) - { - // We create a copy of the bitmap, so everything else can be disposed - stream.Position = 0; - using var tmpImage = Image.FromStream(stream, true, true); - Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - returnImage = Clone(tmpImage, PixelFormat.Format32bppArgb); - } - return returnImage; - } - } -} diff --git a/GreenshotPlugin/Core/ImageOutput.cs b/GreenshotPlugin/Core/ImageOutput.cs deleted file mode 100644 index 4388f2b59..000000000 --- a/GreenshotPlugin/Core/ImageOutput.cs +++ /dev/null @@ -1,657 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.Controls; -using log4net; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.RegularExpressions; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; -using Encoder = System.Drawing.Imaging.Encoder; - -namespace GreenshotPlugin.Core { - /// - /// Description of ImageOutput. - /// - public static class ImageOutput { - private static readonly ILog Log = LogManager.GetLogger(typeof(ImageOutput)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131; - private static readonly Cache TmpFileCache = new Cache(10 * 60 * 60, RemoveExpiredTmpFile); - - /// - /// Creates a PropertyItem (Metadata) to store with the image. - /// For the possible ID's see: http://msdn.microsoft.com/de-de/library/system.drawing.imaging.propertyitem.id(v=vs.80).aspx - /// This code uses Reflection to create a PropertyItem, although it's not adviced it's not as stupid as having a image in the project so we can read a PropertyItem from that! - /// - /// ID - /// Text - /// - private static PropertyItem CreatePropertyItem(int id, string text) { - PropertyItem propertyItem = null; - try { - ConstructorInfo ci = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] { }, null); - propertyItem = (PropertyItem)ci.Invoke(null); - // Make sure it's of type string - propertyItem.Type = 2; - // Set the ID - propertyItem.Id = id; - // Set the text - byte[] byteString = Encoding.ASCII.GetBytes(text + " "); - // Set Zero byte for String end. - byteString[byteString.Length - 1] = 0; - propertyItem.Value = byteString; - propertyItem.Len = text.Length + 1; - } catch (Exception e) { - Log.WarnFormat("Error creating a PropertyItem: {0}", e.Message); - } - return propertyItem; - } - - /// - /// Saves ISurface to stream with specified output settings - /// - /// ISurface to save - /// Stream to save to - /// SurfaceOutputSettings - public static void SaveToStream(ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) { - bool disposeImage = CreateImageFromSurface(surface, outputSettings, out var imageToSave); - SaveToStream(imageToSave, surface, stream, outputSettings); - // cleanup if needed - if (disposeImage) { - imageToSave?.Dispose(); - } - } - - /// - /// Saves image to stream with specified quality - /// To prevent problems with GDI version of before Windows 7: - /// the stream is checked if it's seekable and if needed a MemoryStream as "cache" is used. - /// - /// image to save - /// surface for the elements, needed if the greenshot format is used - /// Stream to save to - /// SurfaceOutputSettings - public static void SaveToStream(Image imageToSave, ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) { - bool useMemoryStream = false; - MemoryStream memoryStream = null; - if (outputSettings.Format == OutputFormat.greenshot && surface == null) { - throw new ArgumentException("Surface needs to be set when using OutputFormat.Greenshot"); - } - - try { - var imageFormat = outputSettings.Format switch - { - OutputFormat.bmp => ImageFormat.Bmp, - OutputFormat.gif => ImageFormat.Gif, - OutputFormat.jpg => ImageFormat.Jpeg, - OutputFormat.tiff => ImageFormat.Tiff, - OutputFormat.ico => ImageFormat.Icon, - _ => ImageFormat.Png - }; - Log.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat); - - // Check if we want to use a memory stream, to prevent issues with non seakable streams - // The save is made to the targetStream, this is directed to either the MemoryStream or the original - Stream targetStream = stream; - if (!stream.CanSeek) - { - useMemoryStream = true; - Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream."); - memoryStream = new MemoryStream(); - targetStream = memoryStream; - } - - if (Equals(imageFormat, ImageFormat.Jpeg)) - { - bool foundEncoder = false; - foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders()) - { - if (imageCodec.FormatID == imageFormat.Guid) - { - EncoderParameters parameters = new EncoderParameters(1) - { - Param = {[0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality)} - }; - // Removing transparency if it's not supported in the output - if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) - { - Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); - AddTag(nonAlphaImage); - nonAlphaImage.Save(targetStream, imageCodec, parameters); - nonAlphaImage.Dispose(); - } - else - { - AddTag(imageToSave); - imageToSave.Save(targetStream, imageCodec, parameters); - } - foundEncoder = true; - break; - } - } - if (!foundEncoder) - { - throw new ApplicationException("No JPG encoder found, this should not happen."); - } - } else if (Equals(imageFormat, ImageFormat.Icon)) { - // FEATURE-916: Added Icon support - IList images = new List - { - imageToSave - }; - WriteIcon(stream, images); - } else { - bool needsDispose = false; - // Removing transparency if it's not supported in the output - if (!Equals(imageFormat, ImageFormat.Png) && Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) { - imageToSave = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); - needsDispose = true; - } - AddTag(imageToSave); - // Added for OptiPNG - bool processed = false; - if (Equals(imageFormat, ImageFormat.Png) && !string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) { - processed = ProcessPngImageExternally(imageToSave, targetStream); - } - if (!processed) { - imageToSave.Save(targetStream, imageFormat); - } - if (needsDispose) { - imageToSave.Dispose(); - } - } - - // If we used a memory stream, we need to stream the memory stream to the original stream. - if (useMemoryStream) { - memoryStream.WriteTo(stream); - } - - // Output the surface elements, size and marker to the stream - if (outputSettings.Format != OutputFormat.greenshot) - { - return; - } - - using MemoryStream tmpStream = new MemoryStream(); - long bytesWritten = surface.SaveElementsToStream(tmpStream); - using BinaryWriter writer = new BinaryWriter(tmpStream); - writer.Write(bytesWritten); - Version v = Assembly.GetExecutingAssembly().GetName().Version; - byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); - writer.Write(marker); - tmpStream.WriteTo(stream); - } - finally - { - memoryStream?.Dispose(); - } - } - - /// - /// Write the passed Image to a tmp-file and call an external process, than read the file back and write it to the targetStream - /// - /// Image to pass to the external process - /// stream to write the processed image to - /// - private static bool ProcessPngImageExternally(Image imageToProcess, Stream targetStream) { - if (string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) { - return false; - } - if (!File.Exists(CoreConfig.OptimizePNGCommand)) { - Log.WarnFormat("Can't find 'OptimizePNGCommand' {0}", CoreConfig.OptimizePNGCommand); - return false; - } - string tmpFileName = Path.Combine(Path.GetTempPath(),Path.GetRandomFileName() + ".png"); - try { - using (FileStream tmpStream = File.Create(tmpFileName)) { - Log.DebugFormat("Writing png to tmp file: {0}", tmpFileName); - imageToProcess.Save(tmpStream, ImageFormat.Png); - if (Log.IsDebugEnabled) { - Log.DebugFormat("File size before processing {0}", new FileInfo(tmpFileName).Length); - } - } - if (Log.IsDebugEnabled) { - Log.DebugFormat("Starting : {0}", CoreConfig.OptimizePNGCommand); - } - - ProcessStartInfo processStartInfo = new ProcessStartInfo(CoreConfig.OptimizePNGCommand) - { - Arguments = string.Format(CoreConfig.OptimizePNGCommandArguments, tmpFileName), - CreateNoWindow = true, - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false - }; - using Process process = Process.Start(processStartInfo); - if (process != null) { - process.WaitForExit(); - if (process.ExitCode == 0) { - if (Log.IsDebugEnabled) { - Log.DebugFormat("File size after processing {0}", new FileInfo(tmpFileName).Length); - Log.DebugFormat("Reading back tmp file: {0}", tmpFileName); - } - byte[] processedImage = File.ReadAllBytes(tmpFileName); - targetStream.Write(processedImage, 0, processedImage.Length); - return true; - } - Log.ErrorFormat("Error while processing PNG image: {0}", process.ExitCode); - Log.ErrorFormat("Output: {0}", process.StandardOutput.ReadToEnd()); - Log.ErrorFormat("Error: {0}", process.StandardError.ReadToEnd()); - } - } catch (Exception e) { - Log.Error("Error while processing PNG image: ", e); - } finally { - if (File.Exists(tmpFileName)) { - Log.DebugFormat("Cleaning up tmp file: {0}", tmpFileName); - File.Delete(tmpFileName); - } - } - return false; - } - - /// - /// Create an image from a surface with the settings from the output settings applied - /// - /// - /// - /// - /// true if the image must be disposed - public static bool CreateImageFromSurface(ISurface surface, SurfaceOutputSettings outputSettings, out Image imageToSave) { - bool disposeImage = false; - - if (outputSettings.Format == OutputFormat.greenshot || outputSettings.SaveBackgroundOnly) { - // We save the image of the surface, this should not be disposed - imageToSave = surface.Image; - } else { - // We create the export image of the surface to save - imageToSave = surface.GetImageForExport(); - disposeImage = true; - } - - // The following block of modifications should be skipped when saving the greenshot format, no effects or otherwise! - if (outputSettings.Format == OutputFormat.greenshot) { - return disposeImage; - } - Image tmpImage; - if (outputSettings.Effects != null && outputSettings.Effects.Count > 0) { - // apply effects, if there are any - using (Matrix matrix = new Matrix()) { - tmpImage = ImageHelper.ApplyEffects(imageToSave, outputSettings.Effects, matrix); - } - if (tmpImage != null) { - if (disposeImage) { - imageToSave.Dispose(); - } - imageToSave = tmpImage; - disposeImage = true; - } - } - - // check for color reduction, forced or automatically, only when the DisableReduceColors is false - if (outputSettings.DisableReduceColors || (!CoreConfig.OutputFileAutoReduceColors && !outputSettings.ReduceColors)) { - return disposeImage; - } - bool isAlpha = Image.IsAlphaPixelFormat(imageToSave.PixelFormat); - if (outputSettings.ReduceColors || (!isAlpha && CoreConfig.OutputFileAutoReduceColors)) - { - using var quantizer = new WuQuantizer((Bitmap)imageToSave); - int colorCount = quantizer.GetColorCount(); - Log.InfoFormat("Image with format {0} has {1} colors", imageToSave.PixelFormat, colorCount); - if (!outputSettings.ReduceColors && colorCount >= 256) { - return disposeImage; - } - try { - Log.Info("Reducing colors on bitmap to 256."); - tmpImage = quantizer.GetQuantizedImage(CoreConfig.OutputFileReduceColorsTo); - if (disposeImage) { - imageToSave.Dispose(); - } - imageToSave = tmpImage; - // Make sure the "new" image is disposed - disposeImage = true; - } catch (Exception e) { - Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); - } - } else if (isAlpha && !outputSettings.ReduceColors) { - Log.Info("Skipping 'optional' color reduction as the image has alpha"); - } - return disposeImage; - } - - /// - /// Add the greenshot property! - /// - /// - private static void AddTag(Image imageToSave) { - // Create meta-data - PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot"); - if (softwareUsedPropertyItem != null) { - try { - imageToSave.SetPropertyItem(softwareUsedPropertyItem); - } catch (Exception) { - Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id); - } - } - } - - /// - /// Load a Greenshot surface - /// - /// - /// - /// - public static ISurface LoadGreenshotSurface(string fullPath, ISurface returnSurface) { - if (string.IsNullOrEmpty(fullPath)) { - return null; - } - Log.InfoFormat("Loading image from file {0}", fullPath); - // Fixed lock problem Bug #3431881 - using (Stream surfaceFileStream = File.OpenRead(fullPath)) { - returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface); - } - if (returnSurface != null) { - Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", fullPath, returnSurface.Image.Width, returnSurface.Image.Height, returnSurface.Image.PixelFormat, returnSurface.Image.HorizontalResolution, returnSurface.Image.VerticalResolution); - } - return returnSurface; - } - - /// - /// Saves image to specific path with specified quality - /// - public static void Save(ISurface surface, string fullPath, bool allowOverwrite, SurfaceOutputSettings outputSettings, bool copyPathToClipboard) { - fullPath = FilenameHelper.MakeFqFilenameSafe(fullPath); - string path = Path.GetDirectoryName(fullPath); - - // check whether path exists - if not create it - if (path != null) { - DirectoryInfo di = new DirectoryInfo(path); - if (!di.Exists) { - Directory.CreateDirectory(di.FullName); - } - } - - if (!allowOverwrite && File.Exists(fullPath)) { - ArgumentException throwingException = new ArgumentException("File '" + fullPath + "' already exists."); - throwingException.Data.Add("fullPath", fullPath); - throw throwingException; - } - Log.DebugFormat("Saving surface to {0}", fullPath); - // Create the stream and call SaveToStream - using (FileStream stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write)) { - SaveToStream(surface, stream, outputSettings); - } - - if (copyPathToClipboard) { - ClipboardHelper.SetClipboardData(fullPath); - } - } - - /// - /// Get the OutputFormat for a filename - /// - /// filename (can be a complete path) - /// OutputFormat - public static OutputFormat FormatForFilename(string fullPath) { - // Fix for bug 2912959 - string extension = fullPath.Substring(fullPath.LastIndexOf(".", StringComparison.Ordinal) + 1); - OutputFormat format = OutputFormat.png; - try { - format = (OutputFormat)Enum.Parse(typeof(OutputFormat), extension.ToLower()); - } catch (ArgumentException ae) { - Log.Warn("Couldn't parse extension: " + extension, ae); - } - return format; - } - - /// - /// Save with showing a dialog - /// - /// - /// - /// Path to filename - public static string SaveWithDialog(ISurface surface, ICaptureDetails captureDetails) { - string returnValue = null; - using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails)) { - DialogResult dialogResult = saveImageFileDialog.ShowDialog(); - if (dialogResult.Equals(DialogResult.OK)) { - try { - string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension)); - if (CoreConfig.OutputFilePromptQuality) { - QualityDialog qualityDialog = new QualityDialog(outputSettings); - qualityDialog.ShowDialog(); - } - // TODO: For now we always overwrite, should be changed - Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); - returnValue = fileNameWithExtension; - IniConfig.Save(); - } catch (ExternalException) { - MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error")); - } - } - } - return returnValue; - } - - /// - /// Create a tmpfile which has the name like in the configured pattern. - /// Used e.g. by the email export - /// - /// - /// - /// - /// Path to image file - public static string SaveNamedTmpFile(ISurface surface, ICaptureDetails captureDetails, SurfaceOutputSettings outputSettings) { - string pattern = CoreConfig.OutputFileFilenamePattern; - if (string.IsNullOrEmpty(pattern?.Trim())) { - pattern = "greenshot ${capturetime}"; - } - string filename = FilenameHelper.GetFilenameFromPattern(pattern, outputSettings.Format, captureDetails); - // Prevent problems with "other characters", which causes a problem in e.g. Outlook 2007 or break our HTML - filename = Regex.Replace(filename, @"[^\d\w\.]", "_"); - // Remove multiple "_" - filename = Regex.Replace(filename, @"_+", "_"); - string tmpFile = Path.Combine(Path.GetTempPath(), filename); - - Log.Debug("Creating TMP File: " + tmpFile); - - // Catching any exception to prevent that the user can't write in the directory. - // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218 - try { - Save(surface, tmpFile, true, outputSettings, false); - TmpFileCache.Add(tmpFile, tmpFile); - } catch (Exception e) { - // Show the problem - MessageBox.Show(e.Message, "Error"); - // when save failed we present a SaveWithDialog - tmpFile = SaveWithDialog(surface, captureDetails); - } - return tmpFile; - } - - /// - /// Remove a tmpfile which was created by SaveNamedTmpFile - /// Used e.g. by the email export - /// - /// - /// true if it worked - public static bool DeleteNamedTmpFile(string tmpfile) { - Log.Debug("Deleting TMP File: " + tmpfile); - try { - if (File.Exists(tmpfile)) { - File.Delete(tmpfile); - TmpFileCache.Remove(tmpfile); - } - return true; - } catch (Exception ex) { - Log.Warn("Error deleting tmp file: ", ex); - } - return false; - } - - /// - /// Helper method to create a temp image file - /// - /// - /// - /// - /// - public static string SaveToTmpFile(ISurface surface, SurfaceOutputSettings outputSettings, string destinationPath) { - string tmpFile = Path.GetRandomFileName() + "." + outputSettings.Format; - // Prevent problems with "other characters", which could cause problems - tmpFile = Regex.Replace(tmpFile, @"[^\d\w\.]", string.Empty); - if (destinationPath == null) { - destinationPath = Path.GetTempPath(); - } - string tmpPath = Path.Combine(destinationPath, tmpFile); - Log.Debug("Creating TMP File : " + tmpPath); - - try { - Save(surface, tmpPath, true, outputSettings, false); - TmpFileCache.Add(tmpPath, tmpPath); - } catch (Exception) { - return null; - } - return tmpPath; - } - - /// - /// Cleanup all created tmpfiles - /// - public static void RemoveTmpFiles() { - foreach (string tmpFile in TmpFileCache.Elements) { - if (File.Exists(tmpFile)) { - Log.DebugFormat("Removing old temp file {0}", tmpFile); - File.Delete(tmpFile); - } - TmpFileCache.Remove(tmpFile); - } - } - - /// - /// Cleanup handler for expired tempfiles - /// - /// - /// - private static void RemoveExpiredTmpFile(string filekey, object filename) { - if (filename is string path && File.Exists(path)) { - Log.DebugFormat("Removing expired file {0}", path); - File.Delete(path); - } - } - - /// - /// Write the images to the stream as icon - /// Every image is resized to 256x256 (but the content maintains the aspect ratio) - /// - /// Stream to write to - /// List of images - public static void WriteIcon(Stream stream, IList images) - { - var binaryWriter = new BinaryWriter(stream); - // - // ICONDIR structure - // - binaryWriter.Write((short)0); // reserved - binaryWriter.Write((short)1); // image type (icon) - binaryWriter.Write((short)images.Count); // number of images - - IList imageSizes = new List(); - IList encodedImages = new List(); - foreach (var image in images) - { - // Pick the best fit - var sizes = new[] { 16, 32, 48 }; - int size = 256; - foreach (var possibleSize in sizes) - { - if (image.Width <= possibleSize && image.Height <= possibleSize) - { - size = possibleSize; - break; - } - } - var imageStream = new MemoryStream(); - if (image.Width == size && image.Height == size) - { - using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); - clonedImage.Save(imageStream, ImageFormat.Png); - imageSizes.Add(new Size(size, size)); - } - else - { - // Resize to the specified size, first make sure the image is 32bpp - using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); - using var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null); - resizedImage.Save(imageStream, ImageFormat.Png); - imageSizes.Add(resizedImage.Size); - } - - imageStream.Seek(0, SeekOrigin.Begin); - encodedImages.Add(imageStream); - } - - // - // ICONDIRENTRY structure - // - const int iconDirSize = 6; - const int iconDirEntrySize = 16; - - var offset = iconDirSize + (images.Count * iconDirEntrySize); - for (int i = 0; i < images.Count; i++) - { - var imageSize = imageSizes[i]; - // Write the width / height, 0 means 256 - binaryWriter.Write(imageSize.Width == 256 ? (byte)0 : (byte)imageSize.Width); - binaryWriter.Write(imageSize.Height == 256 ? (byte)0 : (byte)imageSize.Height); - binaryWriter.Write((byte)0); // no pallete - binaryWriter.Write((byte)0); // reserved - binaryWriter.Write((short)0); // no color planes - binaryWriter.Write((short)32); // 32 bpp - binaryWriter.Write((int)encodedImages[i].Length); // image data length - binaryWriter.Write(offset); - offset += (int)encodedImages[i].Length; - } - - binaryWriter.Flush(); - // - // Write image data - // - foreach (var encodedImage in encodedImages) - { - encodedImage.WriteTo(stream); - encodedImage.Dispose(); - } - } - } -} diff --git a/GreenshotPlugin/Core/ImageWrapper.cs b/GreenshotPlugin/Core/ImageWrapper.cs deleted file mode 100644 index 270164cb7..000000000 --- a/GreenshotPlugin/Core/ImageWrapper.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System.Drawing; -using System.Drawing.Imaging; - -namespace GreenshotPlugin.Core -{ - /// - /// Wrap an image, make it resizeable - /// - public class ImageWrapper : IImage - { - // Underlying image, is used to generate a resized version of it when needed - private readonly Image _image; - private Image _imageClone; - - public ImageWrapper(Image image) - { - // Make sure the orientation is set correctly so Greenshot can process the image correctly - ImageHelper.Orientate(image); - _image = image; - Width = _image.Width; - Height = _image.Height; - } - - public void Dispose() - { - _image.Dispose(); - _imageClone?.Dispose(); - } - - /// - /// Height of the image, can be set to change - /// - public int Height { get; set; } - - /// - /// Width of the image, can be set to change. - /// - public int Width { get; set; } - - /// - /// Size of the image - /// - public Size Size => new Size(Width, Height); - - /// - /// Pixelformat of the underlying image - /// - public PixelFormat PixelFormat => Image.PixelFormat; - - public float HorizontalResolution => Image.HorizontalResolution; - public float VerticalResolution => Image.VerticalResolution; - - public Image Image - { - get - { - if (_imageClone == null) - { - if (_image.Height == Height && _image.Width == Width) - { - return _image; - } - } - if (_imageClone?.Height == Height && _imageClone?.Width == Width) - { - return _imageClone; - } - // Calculate new image clone - _imageClone?.Dispose(); - _imageClone = ImageHelper.ResizeImage(_image, false, Width, Height, null); - return _imageClone; - } - } - - } -} diff --git a/GreenshotPlugin/Core/JSONHelper.cs b/GreenshotPlugin/Core/JSONHelper.cs deleted file mode 100644 index d02845b72..000000000 --- a/GreenshotPlugin/Core/JSONHelper.cs +++ /dev/null @@ -1,359 +0,0 @@ -/* -Copyright (C) 2008 Patrick van Bergen - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -using System.Collections.Generic; -using System.Globalization; -using System.Text; - -namespace GreenshotPlugin.Core { - /// - /// This parses a JSON response, a modified version of the code found at: - /// See: http://techblog.procurios.nl/k/n618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html - /// - /// This file is under the MIT License, which is GPL Compatible and according to: http://en.wikipedia.org/wiki/MIT_License - /// can be used under the GPL "umbrella". - /// - /// TODO: code should be replaced when upgrading to .NET 3.5 or higher!! - /// - public class JSONHelper { - public const int TOKEN_NONE = 0; - public const int TOKEN_CURLY_OPEN = 1; - public const int TOKEN_CURLY_CLOSE = 2; - public const int TOKEN_SQUARED_OPEN = 3; - public const int TOKEN_SQUARED_CLOSE = 4; - public const int TOKEN_COLON = 5; - public const int TOKEN_COMMA = 6; - public const int TOKEN_STRING = 7; - public const int TOKEN_NUMBER = 8; - public const int TOKEN_TRUE = 9; - public const int TOKEN_FALSE = 10; - public const int TOKEN_NULL = 11; - - private const int BUILDER_CAPACITY = 2000; - - /// - /// Parses the string json into a value - /// - /// A JSON string. - /// An ArrayList, a Hashtable, a double, a string, null, true, or false - public static IDictionary JsonDecode(string json) { - bool success = true; - - return JsonDecode(json, ref success); - } - - /// - /// Parses the string json into a value; and fills 'success' with the successfullness of the parse. - /// - /// A JSON string. - /// Successful parse? - /// An ArrayList, a Hashtable, a double, a string, null, true, or false - public static IDictionary JsonDecode(string json, ref bool success) { - success = true; - if (json != null) { - char[] charArray = json.ToCharArray(); - int index = 0; - IDictionary value = ParseValue(charArray, ref index, ref success) as IDictionary; - return value; - } - return null; - } - - protected static IDictionary ParseObject(char[] json, ref int index, ref bool success) { - IDictionary table = new Dictionary(); - int token; - - // { - NextToken(json, ref index); - - bool done = false; - while (!done) { - token = LookAhead(json, index); - if (token == TOKEN_NONE) { - success = false; - return null; - } else if (token == TOKEN_COMMA) { - NextToken(json, ref index); - } else if (token == TOKEN_CURLY_CLOSE) { - NextToken(json, ref index); - return table; - } else { - - // name - string name = ParseString(json, ref index, ref success); - if (!success) { - success = false; - return null; - } - - // : - token = NextToken(json, ref index); - if (token != TOKEN_COLON) { - success = false; - return null; - } - - // value - object value = ParseValue(json, ref index, ref success); - if (!success) { - success = false; - return null; - } - - table.Add(name, value); - } - } - - return table; - } - - protected static IList ParseArray(char[] json, ref int index, ref bool success) { - IList array = new List(); - - // [ - NextToken(json, ref index); - - bool done = false; - while (!done) { - int token = LookAhead(json, index); - if (token == TOKEN_NONE) { - success = false; - return null; - } else if (token == TOKEN_COMMA) { - NextToken(json, ref index); - } else if (token == TOKEN_SQUARED_CLOSE) { - NextToken(json, ref index); - break; - } else { - object value = ParseValue(json, ref index, ref success); - if (!success) { - return null; - } - - array.Add(value); - } - } - - return array; - } - - protected static object ParseValue(char[] json, ref int index, ref bool success) { - switch (LookAhead(json, index)) { - case TOKEN_STRING: - return ParseString(json, ref index, ref success); - case TOKEN_NUMBER: - return ParseNumber(json, ref index, ref success); - case TOKEN_CURLY_OPEN: - return ParseObject(json, ref index, ref success); - case TOKEN_SQUARED_OPEN: - return ParseArray(json, ref index, ref success); - case TOKEN_TRUE: - NextToken(json, ref index); - return true; - case TOKEN_FALSE: - NextToken(json, ref index); - return false; - case TOKEN_NULL: - NextToken(json, ref index); - return null; - case TOKEN_NONE: - break; - } - - success = false; - return null; - } - - protected static string ParseString(char[] json, ref int index, ref bool success) { - StringBuilder s = new StringBuilder(BUILDER_CAPACITY); - - EatWhitespace(json, ref index); - - // " - var c = json[index++]; - - bool complete = false; - while (!complete) { - - if (index == json.Length) { - break; - } - - c = json[index++]; - if (c == '"') { - complete = true; - break; - } else if (c == '\\') { - - if (index == json.Length) { - break; - } - c = json[index++]; - if (c == '"') { - s.Append('"'); - } else if (c == '\\') { - s.Append('\\'); - } else if (c == '/') { - s.Append('/'); - } else if (c == 'b') { - s.Append('\b'); - } else if (c == 'f') { - s.Append('\f'); - } else if (c == 'n') { - s.Append('\n'); - } else if (c == 'r') { - s.Append('\r'); - } else if (c == 't') { - s.Append('\t'); - } else if (c == 'u') { - int remainingLength = json.Length - index; - if (remainingLength >= 4) { - // parse the 32 bit hex into an integer codepoint - if (!(success = uint.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var codePoint))) { - return string.Empty; - } - // convert the integer codepoint to a unicode char and add to string - s.Append(char.ConvertFromUtf32((int)codePoint)); - // skip 4 chars - index += 4; - } else { - break; - } - } - - } else { - s.Append(c); - } - - } - - if (!complete) { - success = false; - return null; - } - - return s.ToString(); - } - - protected static double ParseNumber(char[] json, ref int index, ref bool success) { - EatWhitespace(json, ref index); - - int lastIndex = GetLastIndexOfNumber(json, index); - int charLength = (lastIndex - index) + 1; - - success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out var number); - - index = lastIndex + 1; - return number; - } - - protected static int GetLastIndexOfNumber(char[] json, int index) { - int lastIndex; - - for (lastIndex = index; lastIndex < json.Length; lastIndex++) { - if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) { - break; - } - } - return lastIndex - 1; - } - - protected static void EatWhitespace(char[] json, ref int index) { - for (; index < json.Length; index++) { - if (" \t\n\r".IndexOf(json[index]) == -1) { - break; - } - } - } - - protected static int LookAhead(char[] json, int index) { - int saveIndex = index; - return NextToken(json, ref saveIndex); - } - - protected static int NextToken(char[] json, ref int index) { - EatWhitespace(json, ref index); - - if (index == json.Length) { - return TOKEN_NONE; - } - - char c = json[index]; - index++; - switch (c) { - case '{': - return TOKEN_CURLY_OPEN; - case '}': - return TOKEN_CURLY_CLOSE; - case '[': - return TOKEN_SQUARED_OPEN; - case ']': - return TOKEN_SQUARED_CLOSE; - case ',': - return TOKEN_COMMA; - case '"': - return TOKEN_STRING; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - return TOKEN_NUMBER; - case ':': - return TOKEN_COLON; - } - index--; - - int remainingLength = json.Length - index; - - // false - if (remainingLength >= 5) { - if (json[index] == 'f' && - json[index + 1] == 'a' && - json[index + 2] == 'l' && - json[index + 3] == 's' && - json[index + 4] == 'e') { - index += 5; - return TOKEN_FALSE; - } - } - - // true - if (remainingLength >= 4) { - if (json[index] == 't' && - json[index + 1] == 'r' && - json[index + 2] == 'u' && - json[index + 3] == 'e') { - index += 4; - return TOKEN_TRUE; - } - } - - // null - if (remainingLength >= 4) { - if (json[index] == 'n' && - json[index + 1] == 'u' && - json[index + 2] == 'l' && - json[index + 3] == 'l') { - index += 4; - return TOKEN_NULL; - } - } - - return TOKEN_NONE; - } - } -} diff --git a/GreenshotPlugin/Core/Language.cs b/GreenshotPlugin/Core/Language.cs deleted file mode 100644 index 1b60b6dc8..000000000 --- a/GreenshotPlugin/Core/Language.cs +++ /dev/null @@ -1,644 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Text.RegularExpressions; -using System.Xml; -using GreenshotPlugin.IniFile; -using log4net; -using Microsoft.Win32; - -namespace GreenshotPlugin.Core { - /// - /// This class supplies the GUI with translations, based upon keys. - /// The language resources are loaded from the language files found on fixed or supplied paths - /// - public class Language { - private static readonly ILog Log = LogManager.GetLogger(typeof(Language)); - private static readonly List LanguagePaths = new List(); - private static readonly Dictionary> LanguageFiles = new Dictionary>(); - private static readonly Dictionary HelpFiles = new Dictionary(); - private const string DefaultLanguage = "en-US"; - private const string HelpFilenamePattern = @"help-*.html"; - private const string LanguageFilenamePattern = @"language*.xml"; - private static readonly Regex PrefixRegexp = new Regex(@"language_([a-zA-Z0-9]+).*"); - private static readonly Regex IetfCleanRegexp = new Regex(@"[^a-zA-Z]+"); - private static readonly Regex IetfRegexp = new Regex(@"^.*([a-zA-Z]{2,3}-[a-zA-Z]{1,2})\.xml$"); - private const string LanguageGroupsKey = @"SYSTEM\CurrentControlSet\Control\Nls\Language Groups"; - private static readonly List UnsupportedLanguageGroups = new List(); - private static readonly Dictionary Resources = new Dictionary(); - private static string _currentLanguage; - - public static event LanguageChangedHandler LanguageChanged; - - /// - /// Static initializer for the language code - /// - static Language() { - if (!IniConfig.IsInitialized) { - Log.Warn("IniConfig hasn't been initialized yet! (Design mode?)"); - IniConfig.Init("greenshot", "greenshot"); - } - if (!LogHelper.IsInitialized) { - Log.Warn("Log4net hasn't been initialized yet! (Design mode?)"); - LogHelper.InitializeLog4Net(); - } - - try { - string applicationFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - - // PAF Path - if (applicationFolder != null) - { - AddPath(Path.Combine(applicationFolder, @"App\Greenshot\Languages")); - } - // Application data path - string applicationDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - AddPath(Path.Combine(applicationDataFolder, @"Greenshot\Languages\")); - - // Startup path - if (applicationFolder != null) - { - AddPath(Path.Combine(applicationFolder, @"Languages")); - } - } - catch (Exception pathException) { - Log.Error(pathException); - } - - try - { - using RegistryKey languageGroupsKey = Registry.LocalMachine.OpenSubKey(LanguageGroupsKey, false); - if (languageGroupsKey != null) { - string [] groups = languageGroupsKey.GetValueNames(); - foreach(string group in groups) { - string groupValue = (string)languageGroupsKey.GetValue(group); - bool isGroupNotInstalled = "0".Equals(groupValue); - if (isGroupNotInstalled) { - UnsupportedLanguageGroups.Add(group.ToLower()); - } - } - } - } catch(Exception e) { - Log.Warn("Couldn't read the installed language groups.", e); - } - - var coreConfig = IniConfig.GetIniSection(); - ScanFiles(); - if (!string.IsNullOrEmpty(coreConfig.Language)) { - CurrentLanguage = coreConfig.Language; - if (CurrentLanguage != null && CurrentLanguage != coreConfig.Language) { - coreConfig.Language = CurrentLanguage; - } - } - - if (CurrentLanguage == null) { - Log.Warn("Couldn't set language from configuration, changing to default. Installation problem?"); - CurrentLanguage = DefaultLanguage; - if (CurrentLanguage != null) { - coreConfig.Language = CurrentLanguage; - } - } - - if (CurrentLanguage == null) { - Log.Error("Couldn't set language, installation problem?"); - } - } - - /// - /// Internal method to add a path to the paths that will be scanned for language files! - /// - /// - /// true if the path exists and is added - private static bool AddPath(string path) { - if (!LanguagePaths.Contains(path)) - { - if (Directory.Exists(path)) { - Log.DebugFormat("Adding language path {0}", path); - LanguagePaths.Add(path); - return true; - } - - Log.InfoFormat("Not adding non existing language path {0}", path); - } - return false; - } - - /// - /// Add a new path to the paths that will be scanned for language files! - /// - /// - /// true if the path exists and is added - public static bool AddLanguageFilePath(string path) { - if (!LanguagePaths.Contains(path)) { - Log.DebugFormat("New language path {0}", path); - if (AddPath(path)) { - ScanFiles(); - Reload(); - } else { - return false; - } - } - return true; - } - - /// - /// Load the files for the specified ietf - /// - /// - private static void LoadFiles(string ietf) { - ietf = ReformatIetf(ietf); - if (!LanguageFiles.ContainsKey(ietf)) { - Log.ErrorFormat("No language {0} available.", ietf); - return; - } - List filesToLoad = LanguageFiles[ietf]; - foreach (LanguageFile fileToLoad in filesToLoad) { - LoadResources(fileToLoad); - } - } - - /// - /// Load the language resources from the scanned files - /// - private static void Reload() { - Resources.Clear(); - LoadFiles(DefaultLanguage); - if (_currentLanguage != null && !_currentLanguage.Equals(DefaultLanguage)) { - LoadFiles(_currentLanguage); - } - } - - /// - /// Get or set the current language - /// - public static string CurrentLanguage { - get => _currentLanguage; - set { - string ietf = FindBestIetfMatch(value); - if (!LanguageFiles.ContainsKey(ietf)) { - Log.WarnFormat("No match for language {0} found!", ietf); - } else { - if (_currentLanguage == null || !_currentLanguage.Equals(ietf)) { - _currentLanguage = ietf; - Reload(); - if (LanguageChanged == null) - { - return; - } - try { - LanguageChanged(null, null); - } - catch - { - // ignored - } - return; - } - } - Log.Debug("CurrentLanguage not changed!"); - } - } - - /// - /// Try to find the best match for the supplied IETF - /// - /// string - /// IETF - private static string FindBestIetfMatch(string inputIetf) { - string returnIetf = inputIetf; - if (string.IsNullOrEmpty(returnIetf)) { - returnIetf = DefaultLanguage; - } - returnIetf = ReformatIetf(returnIetf); - if (!LanguageFiles.ContainsKey(returnIetf)) { - Log.WarnFormat("Unknown language {0}, trying best match!", returnIetf); - if (returnIetf.Length == 5) { - returnIetf = returnIetf.Substring(0, 2); - } - foreach (string availableIetf in LanguageFiles.Keys) { - if (!availableIetf.StartsWith(returnIetf)) continue; - - Log.InfoFormat("Found language {0}, best match for {1}!", availableIetf, returnIetf); - returnIetf = availableIetf; - break; - } - } - return returnIetf; - } - - /// - /// This helper method clears all non alpha characters from the IETF, and does a reformatting. - /// This prevents problems with multiple formats or typos. - /// - /// - /// - private static string ReformatIetf(string inputIetf) { - string returnIetf = null; - if (!string.IsNullOrEmpty(inputIetf)) { - returnIetf = inputIetf.ToLower(); - returnIetf = IetfCleanRegexp.Replace(returnIetf, string.Empty); - if (returnIetf.Length == 4) { - returnIetf = returnIetf.Substring(0, 2) + "-" + returnIetf.Substring(2, 2).ToUpper(); - } - } - return returnIetf; - } - - /// - /// Return a list of all the supported languages - /// - public static IList SupportedLanguages { - get { - IList languages = new List(); - // Loop over all languages with all the files in there - foreach (List langs in LanguageFiles.Values) { - // Loop over all the files for a language - foreach (LanguageFile langFile in langs) { - // Only take the ones without prefix, these are the "base" language files - if (langFile.Prefix != null) continue; - languages.Add(langFile); - break; - } - } - return languages; - } - } - - /// - /// Return the path to the help-file - /// - public static string HelpFilePath { - get { - if (HelpFiles.ContainsKey(_currentLanguage)) { - return HelpFiles[_currentLanguage]; - } - return HelpFiles[DefaultLanguage]; - } - } - - /// - /// Load the resources from the language file - /// - /// File to load from - private static void LoadResources(LanguageFile languageFile) { - Log.InfoFormat("Loading language file {0}", languageFile.Filepath); - try { - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.Load(languageFile.Filepath); - XmlNodeList resourceNodes = xmlDocument.GetElementsByTagName("resource"); - foreach (XmlNode resourceNode in resourceNodes) { - string key = resourceNode.Attributes["name"].Value; - if (!string.IsNullOrEmpty(languageFile.Prefix)) { - key = languageFile.Prefix + "." + key; - } - string text = resourceNode.InnerText; - if (!string.IsNullOrEmpty(text)) { - text = text.Trim(); - } - if (!Resources.ContainsKey(key)) { - Resources.Add(key, text); - } else { - Resources[key] = text; - } - } - } catch (Exception e) { - Log.Error("Could not load language file " + languageFile.Filepath, e); - } - } - - /// - /// Load the language file information - /// - /// - /// - private static LanguageFile LoadFileInfo(string languageFilePath) { - try { - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.Load(languageFilePath); - XmlNodeList nodes = xmlDocument.GetElementsByTagName("language"); - if (nodes.Count > 0) { - LanguageFile languageFile = new LanguageFile - { - Filepath = languageFilePath - }; - XmlNode node = nodes.Item(0); - if (node?.Attributes != null) - { - languageFile.Description = node.Attributes["description"].Value; - if (node.Attributes["ietf"] != null) { - languageFile.Ietf = ReformatIetf(node.Attributes["ietf"].Value); - } - if (node.Attributes["version"] != null) { - languageFile.Version = new Version(node.Attributes["version"].Value); - } - if (node.Attributes["prefix"] != null) { - languageFile.Prefix = node.Attributes["prefix"].Value.ToLower(); - } - if (node.Attributes["languagegroup"] != null) { - string languageGroup = node.Attributes["languagegroup"].Value; - languageFile.LanguageGroup = languageGroup.ToLower(); - } - } - return languageFile; - } - throw new XmlException("Root element is missing"); - } catch (Exception e) { - Log.Error("Could not load language file " + languageFilePath, e); - } - return null; - } - - /// - /// Scan the files in all directories - /// - private static void ScanFiles() { - LanguageFiles.Clear(); - HelpFiles.Clear(); - foreach (string languagePath in LanguagePaths) { - if (!Directory.Exists(languagePath)) { - Log.InfoFormat("Skipping non existing language path {0}", languagePath); - continue; - } - Log.InfoFormat("Searching language directory '{0}' for language files with pattern '{1}'", languagePath, LanguageFilenamePattern); - try { - foreach (string languageFilepath in Directory.GetFiles(languagePath, LanguageFilenamePattern, SearchOption.AllDirectories)) { - //LOG.DebugFormat("Found language file: {0}", languageFilepath); - LanguageFile languageFile = LoadFileInfo(languageFilepath); - if (languageFile == null) { - continue; - } - if (string.IsNullOrEmpty(languageFile.Ietf)) { - Log.WarnFormat("Fixing missing ietf in language-file {0}", languageFilepath); - string languageFilename = Path.GetFileName(languageFilepath); - if (IetfRegexp.IsMatch(languageFilename)) { - string replacementIetf = IetfRegexp.Replace(languageFilename, "$1"); - languageFile.Ietf = ReformatIetf(replacementIetf); - Log.InfoFormat("Fixed IETF to {0}", languageFile.Ietf); - } else { - Log.ErrorFormat("Missing ietf , no recover possible... skipping language-file {0}!", languageFilepath); - continue; - } - } - - // Check if we can display the file - if (!string.IsNullOrEmpty(languageFile.LanguageGroup) && UnsupportedLanguageGroups.Contains(languageFile.LanguageGroup)) { - Log.InfoFormat("Skipping unsuported (not able to display) language {0} from file {1}", languageFile.Description, languageFilepath); - continue; - } - - // build prefix, based on the filename, but only if it's not set in the file itself. - if (string.IsNullOrEmpty(languageFile.Prefix)) { - string languageFilename = Path.GetFileNameWithoutExtension(languageFilepath); - if (PrefixRegexp.IsMatch(languageFilename)) { - languageFile.Prefix = PrefixRegexp.Replace(languageFilename, "$1"); - if (!string.IsNullOrEmpty(languageFile.Prefix)) { - languageFile.Prefix = languageFile.Prefix.Replace("plugin", string.Empty).ToLower(); - } - } - } - List currentFiles; - if (LanguageFiles.ContainsKey(languageFile.Ietf)) { - currentFiles = LanguageFiles[languageFile.Ietf]; - bool needToAdd = true; - List deleteList = new List(); - foreach (LanguageFile compareWithLangfile in currentFiles) { - if ((languageFile.Prefix != null || compareWithLangfile.Prefix != null) && - (languageFile.Prefix == null || - !languageFile.Prefix.Equals(compareWithLangfile.Prefix))) continue; - - if (compareWithLangfile.Version > languageFile.Version) { - Log.WarnFormat("Skipping {0}:{1}:{2} as {3}:{4}:{5} is newer", languageFile.Filepath, languageFile.Prefix, languageFile.Version, compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); - needToAdd = false; - break; - } - - Log.WarnFormat("Found {0}:{1}:{2} and deleting {3}:{4}:{5}", languageFile.Filepath, languageFile.Prefix, languageFile.Version, compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); - deleteList.Add(compareWithLangfile); - } - if (needToAdd) { - foreach (LanguageFile deleteFile in deleteList) { - currentFiles.Remove(deleteFile); - } - Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); - currentFiles.Add(languageFile); - } - } else { - currentFiles = new List {languageFile}; - LanguageFiles.Add(languageFile.Ietf, currentFiles); - Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); - } - } - } catch (DirectoryNotFoundException) { - Log.InfoFormat("Non existing language directory: {0}", languagePath); - } catch (Exception e) { - Log.Error("Error trying for read directory " + languagePath, e); - } - - // Now find the help files - Log.InfoFormat("Searching language directory '{0}' for help files with pattern '{1}'", languagePath, HelpFilenamePattern); - try { - foreach (string helpFilepath in Directory.GetFiles(languagePath, HelpFilenamePattern, SearchOption.AllDirectories)) { - Log.DebugFormat("Found help file: {0}", helpFilepath); - string helpFilename = Path.GetFileName(helpFilepath); - string ietf = ReformatIetf(helpFilename.Replace(".html", string.Empty).Replace("help-", "")); - if (!HelpFiles.ContainsKey(ietf)) { - HelpFiles.Add(ietf, helpFilepath); - } else { - Log.WarnFormat("skipping help file {0}, already a file with the same IETF {1} found!", helpFilepath, ietf); - } - } - } catch (DirectoryNotFoundException) { - Log.InfoFormat("Non existing language directory: {0}", languagePath); - } catch (Exception e) { - Log.Error("Error trying for read directory " + languagePath, e); - } - } - } - - /// - /// Check if a resource with prefix.key exists - /// - /// - /// - /// true if available - public static bool HasKey(string prefix, string key) { - return HasKey(prefix + "." + key); - } - - /// - /// Check if a resource with key exists - /// - /// - /// true if available - public static bool HasKey(string key) { - if (key == null) { - return false; - } - return Resources.ContainsKey(key); - } - - /// - /// TryGet method which combines HasKey & GetString - /// - /// - /// out string - /// - public static bool TryGetString(string key, out string languageString) { - return Resources.TryGetValue(key, out languageString); - } - - /// - /// TryGet method which combines HasKey & GetString - /// - /// string with prefix - /// string with key - /// out string - /// - public static bool TryGetString(string prefix, string key, out string languageString) { - return Resources.TryGetValue(prefix + "." + key, out languageString); - } - - /// - /// TryGet method which combines HasKey & GetString - /// - /// string with prefix - /// Enum with key - /// out string - /// - public static bool TryGetString(string prefix, Enum key, out string languageString) - { - return Resources.TryGetValue(prefix + "." + key, out languageString); - } - - /// - /// Translate - /// - /// object - /// string - public static string Translate(object key) { - string typename = key.GetType().Name; - string enumKey = typename + "." + key; - if (HasKey(enumKey)) { - return GetString(enumKey); - } - return key.ToString(); - } - - /// - /// Get the resource for key - /// - /// Enum - /// resource or a "string ###key### not found" - public static string GetString(Enum key) { - if (key == null) { - return null; - } - return GetString(key.ToString()); - } - - /// - /// Get the resource for prefix.key - /// - /// string - /// Enum - /// resource or a "string ###prefix.key### not found" - public static string GetString(string prefix, Enum key) { - if (key == null) { - return null; - } - return GetString(prefix + "." + key); - } - - /// - /// Get the resource for prefix.key - /// - /// string - /// string - /// resource or a "string ###prefix.key### not found" - public static string GetString(string prefix, string key) { - return GetString(prefix + "." + key); - } - - /// - /// Get the resource for key - /// - /// string - /// resource or a "string ###key### not found" - public static string GetString(string key) { - if (key == null) { - return null; - } - - if (!Resources.TryGetValue(key, out var returnValue)) { - return "string ###" + key + "### not found"; - } - return returnValue; - } - - /// - /// Get the resource for key, format with with string.format an supply the parameters - /// - /// Enum - /// object - /// formatted resource or a "string ###key### not found" - public static string GetFormattedString(Enum key, object param) { - return GetFormattedString(key.ToString(), param); - } - - /// - /// Get the resource for prefix.key, format with with string.format an supply the parameters - /// - /// string - /// Enum - /// object - /// formatted resource or a "string ###prefix.key### not found" - public static string GetFormattedString(string prefix, Enum key, object param) { - return GetFormattedString(prefix, key.ToString(), param); - } - - /// - /// Get the resource for prefix.key, format with with string.format an supply the parameters - /// - /// string - /// string - /// object - /// formatted resource or a "string ###prefix.key### not found" - public static string GetFormattedString(string prefix, string key, object param) { - return GetFormattedString(prefix + "." + key, param); - } - - /// - /// Get the resource for key, format with with string.format an supply the parameters - /// - /// string - /// object - /// formatted resource or a "string ###key### not found" - public static string GetFormattedString(string key, object param) { - if (!Resources.TryGetValue(key, out var returnValue)) { - return "string ###" + key + "### not found"; - } - return string.Format(returnValue, param); - } - } -} diff --git a/GreenshotPlugin/Core/LanguageFile.cs b/GreenshotPlugin/Core/LanguageFile.cs deleted file mode 100644 index 8c2c69ff1..000000000 --- a/GreenshotPlugin/Core/LanguageFile.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; - -namespace GreenshotPlugin.Core -{ - /// - /// This class contains the information about a language file - /// - public class LanguageFile : IEquatable { - public string Description { - get; - set; - } - - public string Ietf { - get; - set; - } - - public Version Version { - get; - set; - } - - public string LanguageGroup { - get; - set; - } - - public string Filepath { - get; - set; - } - - public string Prefix { - get; - set; - } - - /// - /// Overload equals so we can delete a entry from a collection - /// - /// - /// - public bool Equals(LanguageFile other) { - if (Prefix != null) { - if (other != null && !Prefix.Equals(other.Prefix)) { - return false; - } - } else if (other?.Prefix != null) { - return false; - } - if (Ietf != null) { - if (other != null && !Ietf.Equals(other.Ietf)) { - return false; - } - } else if (other?.Ietf != null) { - return false; - } - if (Version != null) { - if (other != null && !Version.Equals(other.Version)) { - return false; - } - } else if (other != null && other.Version != null) { - return false; - } - if (Filepath != null) { - if (other != null && !Filepath.Equals(other.Filepath)) { - return false; - } - } else if (other?.Filepath != null) { - return false; - } - return true; - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/LogHelper.cs b/GreenshotPlugin/Core/LogHelper.cs deleted file mode 100644 index c0849537e..000000000 --- a/GreenshotPlugin/Core/LogHelper.cs +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.IO; -using System.Reflection; -using System.Windows.Forms; -using log4net; -using log4net.Appender; -using log4net.Config; -using log4net.Repository.Hierarchy; -using System; -using GreenshotPlugin.IniFile; -using log4net.Util; - -namespace GreenshotPlugin.Core { - /// - /// Initialize the logger - /// - public class LogHelper { - private static bool _isLog4NetConfigured; - private const string InitMessage = "Greenshot initialization of log system failed"; - - public static bool IsInitialized => _isLog4NetConfigured; - - // Initialize Log4J - public static string InitializeLog4Net() { - // Setup log4j, currently the file is called log4net.xml - foreach (var logName in new[] { "log4net.xml" , @"App\Greenshot\log4net-portable.xml"}) - { - string log4NetFilename = Path.Combine(Application.StartupPath, logName); - if (File.Exists(log4NetFilename)) - { - try - { - XmlConfigurator.Configure(new FileInfo(log4NetFilename)); - _isLog4NetConfigured = true; - } - catch (Exception ex) - { - MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - } - } - // Fallback - if (!_isLog4NetConfigured) { - try { - Assembly assembly = typeof(LogHelper).Assembly; - using Stream stream = assembly.GetManifestResourceStream("GreenshotPlugin.log4net-embedded.xml"); - XmlConfigurator.Configure(stream); - _isLog4NetConfigured = true; - IniConfig.ForceIniInStartupPath(); - } catch (Exception ex){ - MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - } - - if (_isLog4NetConfigured) { - // Get the logfile name - try { - if (((Hierarchy)LogManager.GetRepository()).Root.Appenders.Count > 0) { - foreach (IAppender appender in ((Hierarchy)LogManager.GetRepository()).Root.Appenders) - { - var fileAppender = appender as FileAppender; - if (fileAppender != null) { - return fileAppender.File; - } - } - } - } - catch - { - // ignored - } - } - return null; - } - } - - /// - /// A simple helper class to support the logging to the AppData location - /// - public class SpecialFolderPatternConverter : PatternConverter { - protected override void Convert(TextWriter writer, object state) { - Environment.SpecialFolder specialFolder = (Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), Option, true); - writer.Write(Environment.GetFolderPath(specialFolder)); - } - } -} diff --git a/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs b/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs deleted file mode 100644 index b80d62b3d..000000000 --- a/GreenshotPlugin/Core/OAuth/OAuth2Helper.cs +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Net; -using GreenshotPlugin.Controls; - -namespace GreenshotPlugin.Core.OAuth { - /// - /// Code to simplify OAuth 2 - /// - public static class OAuth2Helper { - private const string RefreshToken = "refresh_token"; - private const string AccessToken = "access_token"; - private const string Code = "code"; - private const string Error = "error"; - private const string ClientId = "client_id"; - private const string ClientSecret = "client_secret"; - private const string GrantType = "grant_type"; - private const string AuthorizationCode = "authorization_code"; - private const string RedirectUri = "redirect_uri"; - private const string ExpiresIn = "expires_in"; - - /// - /// Generate an OAuth 2 Token by using the supplied code - /// - /// OAuth2Settings to update with the information that was retrieved - public static void GenerateRefreshToken(OAuth2Settings settings) { - IDictionary data = new Dictionary - { - // Use the returned code to get a refresh code - { Code, settings.Code }, - { ClientId, settings.ClientId }, - { ClientSecret, settings.ClientSecret }, - { GrantType, AuthorizationCode } - }; - foreach (string key in settings.AdditionalAttributes.Keys) { - data.Add(key, settings.AdditionalAttributes[key]); - } - - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); - NetworkHelper.UploadFormUrlEncoded(webRequest, data); - string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); - - IDictionary refreshTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); - if (refreshTokenResult.ContainsKey("error")) - { - if (refreshTokenResult.ContainsKey("error_description")) { - throw new Exception($"{refreshTokenResult["error"]} - {refreshTokenResult["error_description"]}"); - } - throw new Exception((string)refreshTokenResult["error"]); - } - - // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp - // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", - // "expires_in":3920, - // "token_type":"Bearer", - // "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" - if (refreshTokenResult.ContainsKey(AccessToken)) - { - settings.AccessToken = (string)refreshTokenResult[AccessToken]; - } - if (refreshTokenResult.ContainsKey(RefreshToken)) - { - settings.RefreshToken = (string)refreshTokenResult[RefreshToken]; - } - if (refreshTokenResult.ContainsKey(ExpiresIn)) - { - object seconds = refreshTokenResult[ExpiresIn]; - if (seconds != null) - { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double)seconds); - } - } - settings.Code = null; - } - - /// - /// Used to update the settings with the callback information - /// - /// OAuth2Settings - /// IDictionary - /// true if the access token is already in the callback - private static bool UpdateFromCallback(OAuth2Settings settings, IDictionary callbackParameters) - { - if (!callbackParameters.ContainsKey(AccessToken)) - { - return false; - } - if (callbackParameters.ContainsKey(RefreshToken)) - { - // Refresh the refresh token :) - settings.RefreshToken = callbackParameters[RefreshToken]; - } - if (callbackParameters.ContainsKey(ExpiresIn)) - { - var expiresIn = callbackParameters[ExpiresIn]; - settings.AccessTokenExpires = DateTimeOffset.MaxValue; - if (expiresIn != null) - { - if (double.TryParse(expiresIn, out var seconds)) - { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); - } - } - } - settings.AccessToken = callbackParameters[AccessToken]; - return true; - } - - /// - /// Go out and retrieve a new access token via refresh-token with the TokenUrl in the settings - /// Will update the access token, refresh token, expire date - /// - /// - public static void GenerateAccessToken(OAuth2Settings settings) { - IDictionary data = new Dictionary - { - { RefreshToken, settings.RefreshToken }, - { ClientId, settings.ClientId }, - { ClientSecret, settings.ClientSecret }, - { GrantType, RefreshToken } - }; - foreach (string key in settings.AdditionalAttributes.Keys) { - data.Add(key, settings.AdditionalAttributes[key]); - } - - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); - NetworkHelper.UploadFormUrlEncoded(webRequest, data); - string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); - - // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp - // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", - // "expires_in":3920, - // "token_type":"Bearer", - - IDictionary accessTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); - if (accessTokenResult.ContainsKey("error")) - { - if ("invalid_grant" == (string)accessTokenResult["error"]) { - // Refresh token has also expired, we need a new one! - settings.RefreshToken = null; - settings.AccessToken = null; - settings.AccessTokenExpires = DateTimeOffset.MinValue; - settings.Code = null; - return; - } - - if (accessTokenResult.ContainsKey("error_description")) { - throw new Exception($"{accessTokenResult["error"]} - {accessTokenResult["error_description"]}"); - } - - throw new Exception((string)accessTokenResult["error"]); - } - - if (accessTokenResult.ContainsKey(AccessToken)) - { - settings.AccessToken = (string) accessTokenResult[AccessToken]; - settings.AccessTokenExpires = DateTimeOffset.MaxValue; - } - if (accessTokenResult.ContainsKey(RefreshToken)) { - // Refresh the refresh token :) - settings.RefreshToken = (string)accessTokenResult[RefreshToken]; - } - if (accessTokenResult.ContainsKey(ExpiresIn)) - { - object seconds = accessTokenResult[ExpiresIn]; - if (seconds != null) - { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double) seconds); - } - } - } - - /// - /// Authorize by using the mode specified in the settings - /// - /// OAuth2Settings - /// false if it was canceled, true if it worked, exception if not - public static bool Authorize(OAuth2Settings settings) { - var completed = settings.AuthorizeMode switch - { - OAuth2AuthorizeMode.LocalServer => AuthorizeViaLocalServer(settings), - OAuth2AuthorizeMode.EmbeddedBrowser => AuthorizeViaEmbeddedBrowser(settings), - OAuth2AuthorizeMode.JsonReceiver => AuthorizeViaDefaultBrowser(settings), - _ => throw new NotImplementedException($"Authorize mode '{settings.AuthorizeMode}' is not 'yet' implemented."), - }; - return completed; - } - - /// - /// Authorize via the default browser, via the Greenshot website. - /// It will wait for a Json post. - /// If this works, return the code - /// - /// OAuth2Settings with the Auth / Token url etc - /// true if completed, false if canceled - private static bool AuthorizeViaDefaultBrowser(OAuth2Settings settings) - { - var codeReceiver = new LocalJsonReceiver(); - IDictionary result = codeReceiver.ReceiveCode(settings); - - if (result == null || result.Count == 0) - { - return false; - } - foreach (var key in result.Keys) - { - switch (key) - { - case AccessToken: - settings.AccessToken = result[key]; - break; - case ExpiresIn: - if (int.TryParse(result[key], out var seconds)) - { - settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); - } - break; - case RefreshToken: - settings.RefreshToken = result[key]; - break; - } - } - - if (result.TryGetValue("error", out var error)) - { - if (result.TryGetValue("error_description", out var errorDescription)) - { - throw new Exception(errorDescription); - } - if ("access_denied" == error) - { - throw new UnauthorizedAccessException("Access denied"); - } - throw new Exception(error); - } - if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) - { - settings.Code = code; - GenerateRefreshToken(settings); - return !string.IsNullOrEmpty(settings.AccessToken); - } - - return true; - } - - /// - /// Authorize via an embedded browser - /// If this works, return the code - /// - /// OAuth2Settings with the Auth / Token url etc - /// true if completed, false if canceled - private static bool AuthorizeViaEmbeddedBrowser(OAuth2Settings settings) { - if (string.IsNullOrEmpty(settings.CloudServiceName)) { - throw new ArgumentNullException(nameof(settings.CloudServiceName)); - } - if (settings.BrowserSize == Size.Empty) { - throw new ArgumentNullException(nameof(settings.BrowserSize)); - } - OAuthLoginForm loginForm = new OAuthLoginForm($"Authorize {settings.CloudServiceName}", settings.BrowserSize, settings.FormattedAuthUrl, settings.RedirectUrl); - loginForm.ShowDialog(); - if (!loginForm.IsOk) return false; - if (loginForm.CallbackParameters.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) { - settings.Code = code; - GenerateRefreshToken(settings); - return true; - } - return UpdateFromCallback(settings, loginForm.CallbackParameters); - } - - /// - /// Authorize via a local server by using the LocalServerCodeReceiver - /// If this works, return the code - /// - /// OAuth2Settings with the Auth / Token url etc - /// true if completed - private static bool AuthorizeViaLocalServer(OAuth2Settings settings) { - var codeReceiver = new LocalServerCodeReceiver(); - IDictionary result = codeReceiver.ReceiveCode(settings); - - if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) { - settings.Code = code; - GenerateRefreshToken(settings); - return true; - } - - if (result.TryGetValue("error", out var error)) { - if (result.TryGetValue("error_description", out var errorDescription)) { - throw new Exception(errorDescription); - } - if ("access_denied" == error) { - throw new UnauthorizedAccessException("Access denied"); - } - throw new Exception(error); - } - return false; - } - - /// - /// Simple helper to add the Authorization Bearer header - /// - /// WebRequest - /// OAuth2Settings - public static void AddOAuth2Credentials(HttpWebRequest webRequest, OAuth2Settings settings) { - if (!string.IsNullOrEmpty(settings.AccessToken)) { - webRequest.Headers.Add("Authorization", "Bearer " + settings.AccessToken); - } - } - - /// - /// Check and authenticate or refresh tokens - /// - /// OAuth2Settings - public static void CheckAndAuthenticateOrRefresh(OAuth2Settings settings) { - // Get Refresh / Access token - if (string.IsNullOrEmpty(settings.RefreshToken)) { - if (!Authorize(settings)) { - throw new Exception("Authentication cancelled"); - } - } - if (settings.IsAccessTokenExpired) { - GenerateAccessToken(settings); - // Get Refresh / Access token - if (string.IsNullOrEmpty(settings.RefreshToken)) { - if (!Authorize(settings)) { - throw new Exception("Authentication cancelled"); - } - GenerateAccessToken(settings); - } - } - if (settings.IsAccessTokenExpired) { - throw new Exception("Authentication failed"); - } - } - - /// - /// CreateWebRequest ready for OAuth 2 access - /// - /// HTTPMethod - /// - /// OAuth2Settings - /// HttpWebRequest - public static HttpWebRequest CreateOAuth2WebRequest(HTTPMethod method, string url, OAuth2Settings settings) { - CheckAndAuthenticateOrRefresh(settings); - - HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, method); - AddOAuth2Credentials(webRequest, settings); - return webRequest; - } - } -} diff --git a/GreenshotPlugin/Core/ObjectExtensions.cs b/GreenshotPlugin/Core/ObjectExtensions.cs deleted file mode 100644 index a948242b0..000000000 --- a/GreenshotPlugin/Core/ObjectExtensions.cs +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; - -namespace GreenshotPlugin.Core { - /// - /// Extension methods which work for objects - /// - public static class ObjectExtensions { - - /// - /// Perform a deep Copy of the object. - /// - /// The type of object being copied. - /// The object instance to copy. - /// The copied object. - public static T Clone(this T source) - { - var typeparam = typeof(T); - if (!typeparam.IsInterface && !typeparam.IsSerializable) - { - throw new ArgumentException("The type must be serializable.", nameof(source)); - } - - // Don't serialize a null object, simply return the default for that object - if (source == null) { - return default; - } - - IFormatter formatter = new BinaryFormatter(); - using var stream = new MemoryStream(); - formatter.Serialize(stream, source); - stream.Seek(0, SeekOrigin.Begin); - return (T)formatter.Deserialize(stream); - } - - /// - /// Clone the content from source to destination - /// - /// Type to clone - /// Instance to copy from - /// Instance to copy to - public static void CloneTo(this T source, T destination) { - var type = typeof(T); - var myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - - foreach (var fieldInfo in myObjectFields) { - fieldInfo.SetValue(destination, fieldInfo.GetValue(source)); - } - var myObjectProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); - - foreach (var propertyInfo in myObjectProperties) { - if (propertyInfo.CanWrite) { - propertyInfo.SetValue(destination, propertyInfo.GetValue(source, null), null); - } - } - } - - /// - /// Compare two lists - /// - /// - /// IList - /// IList - /// true if they are the same - public static bool CompareLists(IList l1, IList l2) { - if (l1.Count != l2.Count) { - return false; - } - int matched = 0; - foreach(T item in l1) { - if (!l2.Contains(item)) { - return false; - } - matched++; - } - return matched == l1.Count; - } - } -} diff --git a/GreenshotPlugin/Core/PluginUtils.cs b/GreenshotPlugin/Core/PluginUtils.cs deleted file mode 100644 index 51edfffa8..000000000 --- a/GreenshotPlugin/Core/PluginUtils.cs +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.UnmanagedHelpers; -using log4net; -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.IO; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; - -namespace GreenshotPlugin.Core { - /// - /// Description of PluginUtils. - /// - public static class PluginUtils { - private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils)); - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\"; - private static readonly IDictionary ExeIconCache = new Dictionary(); - - static PluginUtils() { - CoreConfig.PropertyChanged += OnIconSizeChanged; - } - - /// - /// Clear icon cache - /// - /// - /// - private static void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName != "IconSize") return; - var cachedImages = new List(); - lock (ExeIconCache) { - foreach (string key in ExeIconCache.Keys) { - cachedImages.Add(ExeIconCache[key]); - } - ExeIconCache.Clear(); - } - foreach (Image cachedImage in cachedImages) - { - cachedImage?.Dispose(); - } - } - - /// - /// Get the path of an executable - /// - /// e.g. cmd.exe - /// Path to file - public static string GetExePath(string exeName) { - using (var key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) { - if (key != null) { - // "" is the default key, which should point to the requested location - return (string)key.GetValue(string.Empty); - } - } - foreach (string pathEntry in (Environment.GetEnvironmentVariable("PATH") ?? string.Empty).Split(';')) { - try { - string path = pathEntry.Trim(); - if (!string.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exeName))) { - return Path.GetFullPath(path); - } - } catch (Exception) { - Log.WarnFormat("Problem with path entry '{0}'.", pathEntry); - } - } - return null; - } - - /// - /// Get icon from resource files, from the cache. - /// Examples can be found here: https://diymediahome.org/windows-icons-reference-list-with-details-locations-images/ - /// - /// path to the exe or dll - /// index of the icon - /// Bitmap with the icon or null if something happended - public static Image GetCachedExeIcon(string path, int index) { - string cacheKey = $"{path}:{index}"; - Image returnValue; - lock (ExeIconCache) - { - if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) - { - return returnValue; - } - lock (ExeIconCache) { - if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) - { - return returnValue; - } - returnValue = GetExeIcon(path, index); - if (returnValue != null) { - ExeIconCache.Add(cacheKey, returnValue); - } - } - } - return returnValue; - } - - /// - /// Get icon for executable - /// - /// path to the exe or dll - /// index of the icon - /// Bitmap with the icon or null if something happended - private static Bitmap GetExeIcon(string path, int index) { - if (!File.Exists(path)) { - return null; - } - try { - using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) { - if (appIcon != null) { - return appIcon.ToBitmap(); - } - } - using (Icon appIcon = Shell32.GetFileIcon(path, CoreConfig.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false)) { - if (appIcon != null) { - return appIcon.ToBitmap(); - } - } - } catch (Exception exIcon) { - Log.Error("error retrieving icon: ", exIcon); - } - return null; - } - - /// - /// Helper method to add a plugin MenuItem to the Greenshot context menu - /// - /// ToolStripMenuItem - public static void AddToContextMenu(ToolStripMenuItem item) { - // Here we can hang ourselves to the main context menu! - var contextMenu = SimpleServiceProvider.Current.GetInstance(); - bool addedItem = false; - - // Try to find a separator, so we insert ourselves after it - for(int i=0; i < contextMenu.Items.Count; i++) { - if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) { - // Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore" - if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag)) { - var separator = new ToolStripSeparator - { - Tag = "PluginsAreAddedAfter", - Size = new Size(305, 6) - }; - contextMenu.Items.Insert(i, separator); - } else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag)) { - continue; - } - contextMenu.Items.Insert(i + 1, item); - addedItem = true; - break; - } - } - // If we didn't insert the item, we just add it... - if (!addedItem) { - contextMenu.Items.Add(item); - } - } - } -} diff --git a/GreenshotPlugin/Core/QuantizerHelper.cs b/GreenshotPlugin/Core/QuantizerHelper.cs deleted file mode 100644 index f5396810f..000000000 --- a/GreenshotPlugin/Core/QuantizerHelper.cs +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Imaging; -using log4net; - -namespace GreenshotPlugin.Core { - internal class WuColorCube { - /// - /// Gets or sets the red minimum. - /// - /// The red minimum. - public int RedMinimum { get; set; } - - /// - /// Gets or sets the red maximum. - /// - /// The red maximum. - public int RedMaximum { get; set; } - - /// - /// Gets or sets the green minimum. - /// - /// The green minimum. - public int GreenMinimum { get; set; } - - /// - /// Gets or sets the green maximum. - /// - /// The green maximum. - public int GreenMaximum { get; set; } - - /// - /// Gets or sets the blue minimum. - /// - /// The blue minimum. - public int BlueMinimum { get; set; } - - /// - /// Gets or sets the blue maximum. - /// - /// The blue maximum. - public int BlueMaximum { get; set; } - - /// - /// Gets or sets the cube volume. - /// - /// The volume. - public int Volume { get; set; } - } - - public class WuQuantizer : IDisposable { - private static readonly ILog LOG = LogManager.GetLogger(typeof(WuQuantizer)); - - private const int MAXCOLOR = 512; - private const int RED = 2; - private const int GREEN = 1; - private const int BLUE = 0; - private const int SIDESIZE = 33; - private const int MAXSIDEINDEX = 32; - private const int MAXVOLUME = SIDESIZE * SIDESIZE * SIDESIZE; - - // To count the colors - private readonly int colorCount; - - private int[] reds; - private int[] greens; - private int[] blues; - private int[] sums; - - private readonly long[,,] weights; - private readonly long[,,] momentsRed; - private readonly long[,,] momentsGreen; - private readonly long[,,] momentsBlue; - private readonly float[,,] moments; - - private byte[] tag; - - private readonly WuColorCube[] cubes; - private readonly Bitmap sourceBitmap; - private Bitmap resultBitmap; - - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) { - if (disposing) { - if (resultBitmap != null) { - resultBitmap.Dispose(); - resultBitmap = null; - } - } - } - - /// - /// See for more details. - /// - public WuQuantizer(Bitmap sourceBitmap) { - this.sourceBitmap = sourceBitmap; - // Make sure the color count variables are reset - BitArray bitArray = new BitArray((int)Math.Pow(2, 24)); - colorCount = 0; - - // creates all the cubes - cubes = new WuColorCube[MAXCOLOR]; - - // initializes all the cubes - for (int cubeIndex = 0; cubeIndex < MAXCOLOR; cubeIndex++) { - cubes[cubeIndex] = new WuColorCube(); - } - - // resets the reference minimums - cubes[0].RedMinimum = 0; - cubes[0].GreenMinimum = 0; - cubes[0].BlueMinimum = 0; - - // resets the reference maximums - cubes[0].RedMaximum = MAXSIDEINDEX; - cubes[0].GreenMaximum = MAXSIDEINDEX; - cubes[0].BlueMaximum = MAXSIDEINDEX; - - weights = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - momentsRed = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - momentsGreen = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - momentsBlue = new long[SIDESIZE, SIDESIZE, SIDESIZE]; - moments = new float[SIDESIZE, SIDESIZE, SIDESIZE]; - - int[] table = new int[256]; - - for (int tableIndex = 0; tableIndex < 256; ++tableIndex) { - table[tableIndex] = tableIndex * tableIndex; - } - - // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage - using IFastBitmap sourceFastBitmap = FastBitmap.Create(sourceBitmap); - IFastBitmapWithBlend sourceFastBitmapWithBlend = sourceFastBitmap as IFastBitmapWithBlend; - sourceFastBitmap.Lock(); - using FastChunkyBitmap destinationFastBitmap = FastBitmap.CreateEmpty(sourceBitmap.Size, PixelFormat.Format8bppIndexed, Color.White) as FastChunkyBitmap; - destinationFastBitmap.Lock(); - for (int y = 0; y < sourceFastBitmap.Height; y++) { - for (int x = 0; x < sourceFastBitmap.Width; x++) { - Color color; - if (sourceFastBitmapWithBlend == null) { - color = sourceFastBitmap.GetColorAt(x, y); - } else { - color = sourceFastBitmapWithBlend.GetBlendedColorAt(x, y); - } - // To count the colors - int index = color.ToArgb() & 0x00ffffff; - // Check if we already have this color - if (!bitArray.Get(index)) { - // If not, add 1 to the single colors - colorCount++; - bitArray.Set(index, true); - } - - int indexRed = (color.R >> 3) + 1; - int indexGreen = (color.G >> 3) + 1; - int indexBlue = (color.B >> 3) + 1; - - weights[indexRed, indexGreen, indexBlue]++; - momentsRed[indexRed, indexGreen, indexBlue] += color.R; - momentsGreen[indexRed, indexGreen, indexBlue] += color.G; - momentsBlue[indexRed, indexGreen, indexBlue] += color.B; - moments[indexRed, indexGreen, indexBlue] += table[color.R] + table[color.G] + table[color.B]; - - // Store the initial "match" - int paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue; - destinationFastBitmap.SetColorIndexAt(x, y, (byte)(paletteIndex & 0xff)); - } - } - resultBitmap = destinationFastBitmap.UnlockAndReturnBitmap(); - } - - /// - /// See for more details. - /// - public int GetColorCount() { - return colorCount; - } - - /// - /// Reindex the 24/32 BPP (A)RGB image to a 8BPP - /// - /// Bitmap - public Bitmap SimpleReindex() { - List colors = new List(); - Dictionary lookup = new Dictionary(); - using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) { - bbbDest.Lock(); - using IFastBitmap bbbSrc = FastBitmap.Create(sourceBitmap); - IFastBitmapWithBlend bbbSrcBlend = bbbSrc as IFastBitmapWithBlend; - - bbbSrc.Lock(); - byte index; - for (int y = 0; y < bbbSrc.Height; y++) { - for (int x = 0; x < bbbSrc.Width; x++) { - Color color; - if (bbbSrcBlend != null) { - color = bbbSrcBlend.GetBlendedColorAt(x, y); - } else { - color = bbbSrc.GetColorAt(x, y); - } - if (lookup.ContainsKey(color)) { - index = lookup[color]; - } else { - colors.Add(color); - index = (byte)(colors.Count - 1); - lookup.Add(color, index); - } - bbbDest.SetColorIndexAt(x, y, index); - } - } - } - - // generates palette - ColorPalette imagePalette = resultBitmap.Palette; - Color[] entries = imagePalette.Entries; - for (int paletteIndex = 0; paletteIndex < 256; paletteIndex++) { - if (paletteIndex < colorCount) { - entries[paletteIndex] = colors[paletteIndex]; - } else { - entries[paletteIndex] = Color.Black; - } - } - resultBitmap.Palette = imagePalette; - - // Make sure the bitmap is not disposed, as we return it. - Bitmap tmpBitmap = resultBitmap; - resultBitmap = null; - return tmpBitmap; - } - - /// - /// Get the image - /// - public Bitmap GetQuantizedImage(int allowedColorCount) { - if (allowedColorCount > 256) { - throw new ArgumentOutOfRangeException(nameof(allowedColorCount), "Quantizing muss be done to get less than 256 colors"); - } - if (colorCount < allowedColorCount) { - // Simple logic to reduce to 8 bit - LOG.Info("Colors in the image are already less as whished for, using simple copy to indexed image, no quantizing needed!"); - return SimpleReindex(); - } - // preprocess the colors - CalculateMoments(); - LOG.Info("Calculated the moments..."); - int next = 0; - float[] volumeVariance = new float[MAXCOLOR]; - - // processes the cubes - for (int cubeIndex = 1; cubeIndex < allowedColorCount; ++cubeIndex) { - // if cut is possible; make it - if (Cut(cubes[next], cubes[cubeIndex])) { - volumeVariance[next] = cubes[next].Volume > 1 ? CalculateVariance(cubes[next]) : 0.0f; - volumeVariance[cubeIndex] = cubes[cubeIndex].Volume > 1 ? CalculateVariance(cubes[cubeIndex]) : 0.0f; - } else { - // the cut was not possible, revert the index - volumeVariance[next] = 0.0f; - cubeIndex--; - } - - next = 0; - float temp = volumeVariance[0]; - - for (int index = 1; index <= cubeIndex; ++index) { - if (volumeVariance[index] > temp) { - temp = volumeVariance[index]; - next = index; - } - } - - if (temp <= 0.0) { - allowedColorCount = cubeIndex + 1; - break; - } - } - - int[] lookupRed = new int[MAXCOLOR]; - int[] lookupGreen = new int[MAXCOLOR]; - int[] lookupBlue = new int[MAXCOLOR]; - - tag = new byte[MAXVOLUME]; - - // precalculates lookup tables - for (int k = 0; k < allowedColorCount; ++k) { - Mark(cubes[k], k, tag); - - long weight = Volume(cubes[k], weights); - - if (weight > 0) { - lookupRed[k] = (int)(Volume(cubes[k], momentsRed) / weight); - lookupGreen[k] = (int)(Volume(cubes[k], momentsGreen) / weight); - lookupBlue[k] = (int)(Volume(cubes[k], momentsBlue) / weight); - } else { - lookupRed[k] = 0; - lookupGreen[k] = 0; - lookupBlue[k] = 0; - } - } - - reds = new int[allowedColorCount + 1]; - greens = new int[allowedColorCount + 1]; - blues = new int[allowedColorCount + 1]; - sums = new int[allowedColorCount + 1]; - - LOG.Info("Starting bitmap reconstruction..."); - - using (FastChunkyBitmap dest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) - { - using IFastBitmap src = FastBitmap.Create(sourceBitmap); - IFastBitmapWithBlend srcBlend = src as IFastBitmapWithBlend; - Dictionary lookup = new Dictionary(); - for (int y = 0; y < src.Height; y++) { - for (int x = 0; x < src.Width; x++) { - Color color; - if (srcBlend != null) { - // WithoutAlpha, this makes it possible to ignore the alpha - color = srcBlend.GetBlendedColorAt(x, y); - } else { - color = src.GetColorAt(x, y); - } - - // Check if we already matched the color - byte bestMatch; - if (!lookup.ContainsKey(color)) { - // If not we need to find the best match - - // First get initial match - bestMatch = dest.GetColorIndexAt(x, y); - bestMatch = tag[bestMatch]; - - int bestDistance = 100000000; - for (int lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++) { - int foundRed = lookupRed[lookupIndex]; - int foundGreen = lookupGreen[lookupIndex]; - int foundBlue = lookupBlue[lookupIndex]; - int deltaRed = color.R - foundRed; - int deltaGreen = color.G - foundGreen; - int deltaBlue = color.B - foundBlue; - - int distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue; - - if (distance < bestDistance) { - bestDistance = distance; - bestMatch = (byte)lookupIndex; - } - } - lookup.Add(color, bestMatch); - } else { - // Already matched, so we just use the lookup - bestMatch = lookup[color]; - } - - reds[bestMatch] += color.R; - greens[bestMatch] += color.G; - blues[bestMatch] += color.B; - sums[bestMatch]++; - - dest.SetColorIndexAt(x, y, bestMatch); - } - } - } - - - // generates palette - ColorPalette imagePalette = resultBitmap.Palette; - Color[] entries = imagePalette.Entries; - for (int paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++) { - if (sums[paletteIndex] > 0) { - reds[paletteIndex] /= sums[paletteIndex]; - greens[paletteIndex] /= sums[paletteIndex]; - blues[paletteIndex] /= sums[paletteIndex]; - } - - entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]); - } - resultBitmap.Palette = imagePalette; - - // Make sure the bitmap is not disposed, as we return it. - Bitmap tmpBitmap = resultBitmap; - resultBitmap = null; - return tmpBitmap; - } - - /// - /// Converts the histogram to a series of moments. - /// - private void CalculateMoments() { - long[] area = new long[SIDESIZE]; - long[] areaRed = new long[SIDESIZE]; - long[] areaGreen = new long[SIDESIZE]; - long[] areaBlue = new long[SIDESIZE]; - float[] area2 = new float[SIDESIZE]; - - for (int redIndex = 1; redIndex <= MAXSIDEINDEX; ++redIndex) { - for (int index = 0; index <= MAXSIDEINDEX; ++index) { - area[index] = 0; - areaRed[index] = 0; - areaGreen[index] = 0; - areaBlue[index] = 0; - area2[index] = 0; - } - - for (int greenIndex = 1; greenIndex <= MAXSIDEINDEX; ++greenIndex) { - long line = 0; - long lineRed = 0; - long lineGreen = 0; - long lineBlue = 0; - float line2 = 0.0f; - - for (int blueIndex = 1; blueIndex <= MAXSIDEINDEX; ++blueIndex) { - line += weights[redIndex, greenIndex, blueIndex]; - lineRed += momentsRed[redIndex, greenIndex, blueIndex]; - lineGreen += momentsGreen[redIndex, greenIndex, blueIndex]; - lineBlue += momentsBlue[redIndex, greenIndex, blueIndex]; - line2 += moments[redIndex, greenIndex, blueIndex]; - - area[blueIndex] += line; - areaRed[blueIndex] += lineRed; - areaGreen[blueIndex] += lineGreen; - areaBlue[blueIndex] += lineBlue; - area2[blueIndex] += line2; - - weights[redIndex, greenIndex, blueIndex] = weights[redIndex - 1, greenIndex, blueIndex] + area[blueIndex]; - momentsRed[redIndex, greenIndex, blueIndex] = momentsRed[redIndex - 1, greenIndex, blueIndex] + areaRed[blueIndex]; - momentsGreen[redIndex, greenIndex, blueIndex] = momentsGreen[redIndex - 1, greenIndex, blueIndex] + areaGreen[blueIndex]; - momentsBlue[redIndex, greenIndex, blueIndex] = momentsBlue[redIndex - 1, greenIndex, blueIndex] + areaBlue[blueIndex]; - moments[redIndex, greenIndex, blueIndex] = moments[redIndex - 1, greenIndex, blueIndex] + area2[blueIndex]; - } - } - } - } - - /// - /// Computes the volume of the cube in a specific moment. - /// - private static long Volume(WuColorCube cube, long[,,] moment) { - return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - - moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; - } - - /// - /// Computes the volume of the cube in a specific moment. For the floating-point values. - /// - private static float VolumeFloat(WuColorCube cube, float[,,] moment) { - return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - - moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; - } - - /// - /// Splits the cube in given position, and color direction. - /// - private static long Top(WuColorCube cube, int direction, int position, long[,,] moment) { - return direction switch - { - RED => (moment[position, cube.GreenMaximum, cube.BlueMaximum] - - moment[position, cube.GreenMaximum, cube.BlueMinimum] - - moment[position, cube.GreenMinimum, cube.BlueMaximum] + - moment[position, cube.GreenMinimum, cube.BlueMinimum]), - GREEN => (moment[cube.RedMaximum, position, cube.BlueMaximum] - - moment[cube.RedMaximum, position, cube.BlueMinimum] - - moment[cube.RedMinimum, position, cube.BlueMaximum] + - moment[cube.RedMinimum, position, cube.BlueMinimum]), - BLUE => (moment[cube.RedMaximum, cube.GreenMaximum, position] - - moment[cube.RedMaximum, cube.GreenMinimum, position] - - moment[cube.RedMinimum, cube.GreenMaximum, position] + - moment[cube.RedMinimum, cube.GreenMinimum, position]), - _ => 0, - }; - } - - /// - /// Splits the cube in a given color direction at its minimum. - /// - private static long Bottom(WuColorCube cube, int direction, long[,,] moment) - { - return direction switch - { - RED => (-moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), - GREEN => (-moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), - BLUE => (-moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] + - moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] + - moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] - - moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), - _ => 0 - }; - } - - /// - /// Calculates statistical variance for a given cube. - /// - private float CalculateVariance(WuColorCube cube) { - float volumeRed = Volume(cube, momentsRed); - float volumeGreen = Volume(cube, momentsGreen); - float volumeBlue = Volume(cube, momentsBlue); - float volumeMoment = VolumeFloat(cube, moments); - float volumeWeight = Volume(cube, weights); - - float distance = volumeRed * volumeRed + volumeGreen * volumeGreen + volumeBlue * volumeBlue; - - return volumeMoment - (distance / volumeWeight); - } - - /// - /// Finds the optimal (maximal) position for the cut. - /// - private float Maximize(WuColorCube cube, int direction, int first, int last, int[] cut, long wholeRed, long wholeGreen, long wholeBlue, long wholeWeight) { - long bottomRed = Bottom(cube, direction, momentsRed); - long bottomGreen = Bottom(cube, direction, momentsGreen); - long bottomBlue = Bottom(cube, direction, momentsBlue); - long bottomWeight = Bottom(cube, direction, weights); - - float result = 0.0f; - cut[0] = -1; - - for (int position = first; position < last; ++position) { - // determines the cube cut at a certain position - long halfRed = bottomRed + Top(cube, direction, position, momentsRed); - long halfGreen = bottomGreen + Top(cube, direction, position, momentsGreen); - long halfBlue = bottomBlue + Top(cube, direction, position, momentsBlue); - long halfWeight = bottomWeight + Top(cube, direction, position, weights); - - // the cube cannot be cut at bottom (this would lead to empty cube) - if (halfWeight != 0) { - float halfDistance = (float)halfRed * halfRed + (float)halfGreen * halfGreen + (float)halfBlue * halfBlue; - float temp = halfDistance / halfWeight; - - halfRed = wholeRed - halfRed; - halfGreen = wholeGreen - halfGreen; - halfBlue = wholeBlue - halfBlue; - halfWeight = wholeWeight - halfWeight; - - if (halfWeight != 0) { - halfDistance = (float)halfRed * halfRed + (float)halfGreen * halfGreen + (float)halfBlue * halfBlue; - temp += halfDistance / halfWeight; - - if (temp > result) { - result = temp; - cut[0] = position; - } - } - } - } - - return result; - } - - /// - /// Cuts a cube with another one. - /// - private bool Cut(WuColorCube first, WuColorCube second) { - int direction; - - int[] cutRed = { 0 }; - int[] cutGreen = { 0 }; - int[] cutBlue = { 0 }; - - long wholeRed = Volume(first, momentsRed); - long wholeGreen = Volume(first, momentsGreen); - long wholeBlue = Volume(first, momentsBlue); - long wholeWeight = Volume(first, weights); - - float maxRed = Maximize(first, RED, first.RedMinimum + 1, first.RedMaximum, cutRed, wholeRed, wholeGreen, wholeBlue, wholeWeight); - float maxGreen = Maximize(first, GREEN, first.GreenMinimum + 1, first.GreenMaximum, cutGreen, wholeRed, wholeGreen, wholeBlue, wholeWeight); - float maxBlue = Maximize(first, BLUE, first.BlueMinimum + 1, first.BlueMaximum, cutBlue, wholeRed, wholeGreen, wholeBlue, wholeWeight); - - if ((maxRed >= maxGreen) && (maxRed >= maxBlue)) { - direction = RED; - - // cannot split empty cube - if (cutRed[0] < 0) return false; - } else { - if ((maxGreen >= maxRed) && (maxGreen >= maxBlue)) { - direction = GREEN; - } else { - direction = BLUE; - } - } - - second.RedMaximum = first.RedMaximum; - second.GreenMaximum = first.GreenMaximum; - second.BlueMaximum = first.BlueMaximum; - - // cuts in a certain direction - switch (direction) { - case RED: - second.RedMinimum = first.RedMaximum = cutRed[0]; - second.GreenMinimum = first.GreenMinimum; - second.BlueMinimum = first.BlueMinimum; - break; - - case GREEN: - second.GreenMinimum = first.GreenMaximum = cutGreen[0]; - second.RedMinimum = first.RedMinimum; - second.BlueMinimum = first.BlueMinimum; - break; - - case BLUE: - second.BlueMinimum = first.BlueMaximum = cutBlue[0]; - second.RedMinimum = first.RedMinimum; - second.GreenMinimum = first.GreenMinimum; - break; - } - - // determines the volumes after cut - first.Volume = (first.RedMaximum - first.RedMinimum) * (first.GreenMaximum - first.GreenMinimum) * (first.BlueMaximum - first.BlueMinimum); - second.Volume = (second.RedMaximum - second.RedMinimum) * (second.GreenMaximum - second.GreenMinimum) * (second.BlueMaximum - second.BlueMinimum); - - // the cut was successfull - return true; - } - - /// - /// Marks all the tags with a given label. - /// - private void Mark(WuColorCube cube, int label, byte[] tag) { - for (int redIndex = cube.RedMinimum + 1; redIndex <= cube.RedMaximum; ++redIndex) { - for (int greenIndex = cube.GreenMinimum + 1; greenIndex <= cube.GreenMaximum; ++greenIndex) { - for (int blueIndex = cube.BlueMinimum + 1; blueIndex <= cube.BlueMaximum; ++blueIndex) { - tag[(redIndex << 10) + (redIndex << 6) + redIndex + (greenIndex << 5) + greenIndex + blueIndex] = (byte)label; - } - } - } - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Core/StringExtensions.cs b/GreenshotPlugin/Core/StringExtensions.cs deleted file mode 100644 index cd957c543..000000000 --- a/GreenshotPlugin/Core/StringExtensions.cs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.IO; -using System.Security.Cryptography; -using System.Text; -using log4net; -using System.Text.RegularExpressions; -using System.Collections.Generic; - -namespace GreenshotPlugin.Core { - public static class StringExtensions { - private static readonly ILog LOG = LogManager.GetLogger(typeof(StringExtensions)); - private const string RGBIV = "dlgjowejgogkklwj"; - private const string KEY = "lsjvkwhvwujkagfauguwcsjgu2wueuff"; - - /// - /// Format a string with the specified object - /// - /// String with formatting, like {name} - /// Object used for the formatting - /// Formatted string - public static string FormatWith(this string format, object source) { - return FormatWith(format, null, source); - } - - /// - /// Format the string "format" with the source - /// - /// - /// - /// object with properties, if a property has the type IDictionary string,string it can used these parameters too - /// Formatted string - public static string FormatWith(this string format, IFormatProvider provider, object source) { - if (format == null) { - throw new ArgumentNullException(nameof(format)); - } - - IDictionary properties = new Dictionary(); - foreach(var propertyInfo in source.GetType().GetProperties()) { - if (propertyInfo.CanRead && propertyInfo.CanWrite) { - object value = propertyInfo.GetValue(source, null); - if (propertyInfo.PropertyType != typeof(IDictionary)) { - properties.Add(propertyInfo.Name, value); - } else { - IDictionary dictionary = (IDictionary)value; - foreach (var propertyKey in dictionary.Keys) { - properties.Add(propertyKey, dictionary[propertyKey]); - } - } - } - } - - Regex r = new Regex(@"(?\{)+(?[\w\.\[\]]+)(?:[^}]+)?(?\})+", RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); - - List values = new List(); - string rewrittenFormat = r.Replace(format, delegate(Match m) { - Group startGroup = m.Groups["start"]; - Group propertyGroup = m.Groups["property"]; - Group formatGroup = m.Groups["format"]; - Group endGroup = m.Groups["end"]; - - values.Add(properties.TryGetValue(propertyGroup.Value, out var value) ? value : source); - return new string('{', startGroup.Captures.Count) + (values.Count - 1) + formatGroup.Value + new string('}', endGroup.Captures.Count); - }); - - return string.Format(provider, rewrittenFormat, values.ToArray()); - } - - /// - /// A simply rijndael aes encryption, can be used to store passwords - /// - /// the string to call upon - /// an encryped string in base64 form - public static string Encrypt(this string clearText) { - string returnValue = clearText; - try { - byte[] clearTextBytes = Encoding.ASCII.GetBytes(clearText); - SymmetricAlgorithm rijn = SymmetricAlgorithm.Create(); - - using MemoryStream ms = new MemoryStream(); - byte[] rgbIV = Encoding.ASCII.GetBytes(RGBIV); - byte[] key = Encoding.ASCII.GetBytes(KEY); - using CryptoStream cs = new CryptoStream(ms, rijn.CreateEncryptor(key, rgbIV), CryptoStreamMode.Write); - cs.Write(clearTextBytes, 0, clearTextBytes.Length); - cs.FlushFinalBlock(); - - returnValue = Convert.ToBase64String(ms.ToArray()); - } catch (Exception ex) { - LOG.ErrorFormat("Error encrypting, error: {0}", ex.Message); - } - return returnValue; - } - - /// - /// A simply rijndael aes decryption, can be used to store passwords - /// - /// a base64 encoded rijndael encrypted string - /// Decrypeted text - public static string Decrypt(this string encryptedText) { - string returnValue = encryptedText; - try { - byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText); - using MemoryStream ms = new MemoryStream(); - SymmetricAlgorithm rijn = SymmetricAlgorithm.Create(); - - - byte[] rgbIV = Encoding.ASCII.GetBytes(RGBIV); - byte[] key = Encoding.ASCII.GetBytes(KEY); - - using CryptoStream cs = new CryptoStream(ms, rijn.CreateDecryptor(key, rgbIV), CryptoStreamMode.Write); - cs.Write(encryptedTextBytes, 0, encryptedTextBytes.Length); - cs.FlushFinalBlock(); - returnValue = Encoding.ASCII.GetString(ms.ToArray()); - } catch (Exception ex) { - LOG.ErrorFormat("Error decrypting {0}, error: {1}", encryptedText, ex.Message); - } - - return returnValue; - } - } -} diff --git a/GreenshotPlugin/Core/SvgImage.cs b/GreenshotPlugin/Core/SvgImage.cs deleted file mode 100644 index d777d30ad..000000000 --- a/GreenshotPlugin/Core/SvgImage.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using Svg; - -namespace GreenshotPlugin.Core -{ - /// - /// Create an image look like of the SVG - /// - public sealed class SvgImage : IImage - { - private readonly SvgDocument _svgDocument; - - private Image _imageClone; - - /// - /// Factory to create via a stream - /// - /// Stream - /// IImage - public static IImage FromStream(Stream stream) - { - return new SvgImage(stream); - } - - /// - /// Default constructor - /// - /// - public SvgImage(Stream stream) - { - _svgDocument = SvgDocument.Open(stream); - Height = (int)_svgDocument.ViewBox.Height; - Width = (int)_svgDocument.ViewBox.Width; - } - - /// - /// Height of the image, can be set to change - /// - public int Height { get; set; } - - /// - /// Width of the image, can be set to change. - /// - public int Width { get; set; } - - /// - /// Size of the image - /// - public Size Size => new Size(Width, Height); - - /// - /// Pixelformat of the underlying image - /// - public PixelFormat PixelFormat => Image.PixelFormat; - - /// - /// Horizontal resolution of the underlying image - /// - public float HorizontalResolution => Image.HorizontalResolution; - - /// - /// Vertical resolution of the underlying image - /// - public float VerticalResolution => Image.VerticalResolution; - - /// - /// Underlying image, or an on demand rendered version with different attributes as the original - /// - public Image Image - { - get - { - if (_imageClone?.Height == Height && _imageClone?.Width == Width) - { - return _imageClone; - } - // Calculate new image clone - _imageClone?.Dispose(); - _imageClone = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent, 96, 96); - _svgDocument.Draw((Bitmap)_imageClone); - return _imageClone; - - } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - _imageClone?.Dispose(); - } - } -} diff --git a/GreenshotPlugin/Core/WindowCapture.cs b/GreenshotPlugin/Core/WindowCapture.cs deleted file mode 100644 index 828851444..000000000 --- a/GreenshotPlugin/Core/WindowCapture.cs +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.UnmanagedHelpers; -using log4net; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.InteropServices; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace GreenshotPlugin.Core { - /// - /// The Window Capture code - /// - public static class WindowCapture { - private static readonly ILog Log = LogManager.GetLogger(typeof(WindowCapture)); - private static readonly CoreConfiguration Configuration = IniConfig.GetIniSection(); - - /// - /// Used to cleanup the unmanaged resource in the iconInfo for the CaptureCursor method - /// - /// - /// - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); - - /// - /// Get the bounds of all screens combined. - /// - /// A Rectangle of the bounds of the entire display area. - public static Rectangle GetScreenBounds() { - int left = 0, top = 0, bottom = 0, right = 0; - foreach (Screen screen in Screen.AllScreens) { - left = Math.Min(left, screen.Bounds.X); - top = Math.Min(top, screen.Bounds.Y); - int screenAbsRight = screen.Bounds.X + screen.Bounds.Width; - int screenAbsBottom = screen.Bounds.Y + screen.Bounds.Height; - right = Math.Max(right, screenAbsRight); - bottom = Math.Max(bottom, screenAbsBottom); - } - return new Rectangle(left, top, (right + Math.Abs(left)), (bottom + Math.Abs(top))); - } - - /// - /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. This implementation - /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. - /// - /// - /// Point with cursor location, relative to the top left corner of the monitor setup (which itself might actually not be on any screen) - /// - public static Point GetCursorLocationRelativeToScreenBounds() { - return GetLocationRelativeToScreenBounds(User32.GetCursorLocation()); - } - - /// - /// Converts locationRelativeToScreenOrigin to be relative to top left corner of all screen bounds, which might - /// be different in multi-screen setups. This implementation - /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. - /// - /// - /// Point - public static Point GetLocationRelativeToScreenBounds(Point locationRelativeToScreenOrigin) { - Point ret = locationRelativeToScreenOrigin; - Rectangle bounds = GetScreenBounds(); - ret.Offset(-bounds.X, -bounds.Y); - return ret; - } - - /// - /// This method will capture the current Cursor by using User32 Code - /// - /// A Capture Object with the Mouse Cursor information in it. - public static ICapture CaptureCursor(ICapture capture) { - Log.Debug("Capturing the mouse cursor."); - if (capture == null) { - capture = new Capture(); - } - var cursorInfo = new CursorInfo(); - cursorInfo.cbSize = Marshal.SizeOf(cursorInfo); - if (!User32.GetCursorInfo(out cursorInfo)) return capture; - if (cursorInfo.flags != User32.CURSOR_SHOWING) return capture; - - using SafeIconHandle safeIcon = User32.CopyIcon(cursorInfo.hCursor); - if (!User32.GetIconInfo(safeIcon, out var iconInfo)) return capture; - - Point cursorLocation = User32.GetCursorLocation(); - // Align cursor location to Bitmap coordinates (instead of Screen coordinates) - var x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X; - var y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y; - // Set the location - capture.CursorLocation = new Point(x, y); - - using (Icon icon = Icon.FromHandle(safeIcon.DangerousGetHandle())) { - capture.Cursor = icon; - } - - if (iconInfo.hbmMask != IntPtr.Zero) { - DeleteObject(iconInfo.hbmMask); - } - if (iconInfo.hbmColor != IntPtr.Zero) { - DeleteObject(iconInfo.hbmColor); - } - return capture; - } - - /// - /// This method will call the CaptureRectangle with the screenbounds, therefor Capturing the whole screen. - /// - /// A Capture Object with the Screen as an Image - public static ICapture CaptureScreen(ICapture capture) { - if (capture == null) { - capture = new Capture(); - } - return CaptureRectangle(capture, capture.ScreenBounds); - } - - /// - /// Helper method to create an exception that might explain what is wrong while capturing - /// - /// string with current method - /// Rectangle of what we want to capture - /// - private static Exception CreateCaptureException(string method, Rectangle captureBounds) { - Exception exceptionToThrow = User32.CreateWin32Exception(method); - if (!captureBounds.IsEmpty) { - exceptionToThrow.Data.Add("Height", captureBounds.Height); - exceptionToThrow.Data.Add("Width", captureBounds.Width); - } - return exceptionToThrow; - } - - /// - /// Helper method to check if it is allowed to capture the process using DWM - /// - /// Process owning the window - /// true if it's allowed - public static bool IsDwmAllowed(Process process) { - if (process == null) return true; - if (Configuration.NoDWMCaptureForProduct == null || - Configuration.NoDWMCaptureForProduct.Count <= 0) return true; - - try { - string productName = process.MainModule?.FileVersionInfo.ProductName; - if (productName != null && Configuration.NoDWMCaptureForProduct.Contains(productName.ToLower())) { - return false; - } - } catch (Exception ex) { - Log.Warn(ex.Message); - } - return true; - } - - /// - /// Helper method to check if it is allowed to capture the process using GDI - /// - /// Process owning the window - /// true if it's allowed - public static bool IsGdiAllowed(Process process) { - if (process == null) return true; - if (Configuration.NoGDICaptureForProduct == null || - Configuration.NoGDICaptureForProduct.Count <= 0) return true; - - try { - string productName = process.MainModule?.FileVersionInfo.ProductName; - if (productName != null && Configuration.NoGDICaptureForProduct.Contains(productName.ToLower())) { - return false; - } - } catch (Exception ex) { - Log.Warn(ex.Message); - } - return true; - } - - /// - /// This method will use User32 code to capture the specified captureBounds from the screen - /// - /// ICapture where the captured Bitmap will be stored - /// Rectangle with the bounds to capture - /// A Capture Object with a part of the Screen as an Image - public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds) { - if (capture == null) { - capture = new Capture(); - } - Image capturedImage = null; - // If the CaptureHandler has a handle use this, otherwise use the CaptureRectangle here - if (CaptureHandler.CaptureScreenRectangle != null) { - try { - capturedImage = CaptureHandler.CaptureScreenRectangle(captureBounds); - } - catch - { - // ignored - } - } - // If no capture, use the normal screen capture - if (capturedImage == null) { - capturedImage = CaptureRectangle(captureBounds); - } - capture.Image = capturedImage; - capture.Location = captureBounds.Location; - return capture.Image == null ? null : capture; - } - - /// - /// This method will use User32 code to capture the specified captureBounds from the screen - /// - /// ICapture where the captured Bitmap will be stored - /// Rectangle with the bounds to capture - /// A Capture Object with a part of the Screen as an Image - public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, Rectangle captureBounds) { - if (capture == null) { - capture = new Capture(); - } - capture.Image = CaptureRectangle(captureBounds); - capture.Location = captureBounds.Location; - return capture.Image == null ? null : capture; - } - - /// - /// This method will use User32 code to capture the specified captureBounds from the screen - /// - /// Rectangle with the bounds to capture - /// Bitmap which is captured from the screen at the location specified by the captureBounds - public static Bitmap CaptureRectangle(Rectangle captureBounds) { - Bitmap returnBitmap = null; - if (captureBounds.Height <= 0 || captureBounds.Width <= 0) { - Log.Warn("Nothing to capture, ignoring!"); - return null; - } - Log.Debug("CaptureRectangle Called!"); - - // .NET GDI+ Solution, according to some post this has a GDI+ leak... - // See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen - // Bitmap capturedBitmap = new Bitmap(captureBounds.Width, captureBounds.Height); - // using (Graphics graphics = Graphics.FromImage(capturedBitmap)) { - // graphics.CopyFromScreen(captureBounds.Location, Point.Empty, captureBounds.Size, CopyPixelOperation.CaptureBlt); - // } - // capture.Image = capturedBitmap; - // capture.Location = captureBounds.Location; - - using (var desktopDcHandle = SafeWindowDcHandle.FromDesktop()) { - if (desktopDcHandle.IsInvalid) { - // Get Exception before the error is lost - Exception exceptionToThrow = CreateCaptureException("desktopDCHandle", captureBounds); - // throw exception - throw exceptionToThrow; - } - - // create a device context we can copy to - using SafeCompatibleDCHandle safeCompatibleDcHandle = GDI32.CreateCompatibleDC(desktopDcHandle); - // Check if the device context is there, if not throw an error with as much info as possible! - if (safeCompatibleDcHandle.IsInvalid) { - // Get Exception before the error is lost - Exception exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds); - // throw exception - throw exceptionToThrow; - } - // Create BITMAPINFOHEADER for CreateDIBSection - BITMAPINFOHEADER bmi = new BITMAPINFOHEADER(captureBounds.Width, captureBounds.Height, 24); - - // Make sure the last error is set to 0 - Win32.SetLastError(0); - - // create a bitmap we can copy it to, using GetDeviceCaps to get the width/height - using SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDcHandle, ref bmi, BITMAPINFOHEADER.DIB_RGB_COLORS, out _, IntPtr.Zero, 0); - if (safeDibSectionHandle.IsInvalid) { - // Get Exception before the error is lost - var exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds); - exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32()); - exceptionToThrow.Data.Add("hdcSrc", desktopDcHandle.DangerousGetHandle().ToInt32()); - - // Throw so people can report the problem - throw exceptionToThrow; - } - // select the bitmap object and store the old handle - using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle)) { - // bitblt over (make copy) - // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags - GDI32.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt); - } - - // get a .NET image object for it - // A suggestion for the "A generic error occurred in GDI+." E_FAIL/0�80004005 error is to re-try... - bool success = false; - ExternalException exception = null; - for (int i = 0; i < 3; i++) { - try { - // Collect all screens inside this capture - List screensInsideCapture = new List(); - foreach (Screen screen in Screen.AllScreens) { - if (screen.Bounds.IntersectsWith(captureBounds)) { - screensInsideCapture.Add(screen); - } - } - // Check all all screens are of an equal size - bool offscreenContent; - using (Region captureRegion = new Region(captureBounds)) { - // Exclude every visible part - foreach (Screen screen in screensInsideCapture) { - captureRegion.Exclude(screen.Bounds); - } - // If the region is not empty, we have "offscreenContent" - using Graphics screenGraphics = Graphics.FromHwnd(User32.GetDesktopWindow()); - offscreenContent = !captureRegion.IsEmpty(screenGraphics); - } - // Check if we need to have a transparent background, needed for offscreen content - if (offscreenContent) - { - using Bitmap tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); - // Create a new bitmap which has a transparent background - returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution); - // Content will be copied here - using Graphics graphics = Graphics.FromImage(returnBitmap); - // For all screens copy the content to the new bitmap - foreach (Screen screen in Screen.AllScreens) { - Rectangle screenBounds = screen.Bounds; - // Make sure the bounds are offsetted to the capture bounds - screenBounds.Offset(-captureBounds.X, -captureBounds.Y); - graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel); - } - } else { - // All screens, which are inside the capture, are of equal size - // assign image to Capture, the image will be disposed there.. - returnBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); - } - // We got through the capture without exception - success = true; - break; - } catch (ExternalException ee) { - Log.Warn("Problem getting bitmap at try " + i + " : ", ee); - exception = ee; - } - } - if (!success) { - Log.Error("Still couldn't create Bitmap!"); - if (exception != null) { - throw exception; - } - } - } - return returnBitmap; - } - } -} diff --git a/GreenshotPlugin/Core/WindowsEnumerator.cs b/GreenshotPlugin/Core/WindowsEnumerator.cs deleted file mode 100644 index 9025cd7b8..000000000 --- a/GreenshotPlugin/Core/WindowsEnumerator.cs +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.UnmanagedHelpers; -using System; -using System.Collections.Generic; -using System.Text; - -namespace GreenshotPlugin.Core { - /// - /// EnumWindows wrapper for .NET - /// - public class WindowsEnumerator { - /// - /// Returns the collection of windows returned by GetWindows - /// - public IList Items { get; private set; } - - /// - /// Gets all child windows of the specified window - /// - /// Window Handle to get children for - /// Window Classname to copy, use null to copy all - public WindowsEnumerator GetWindows(IntPtr hWndParent, string classname) { - Items = new List(); - User32.EnumChildWindows(hWndParent, WindowEnum, IntPtr.Zero); - - bool hasParent = !IntPtr.Zero.Equals(hWndParent); - string parentText = null; - if (hasParent) { - var title = new StringBuilder(260, 260); - User32.GetWindowText(hWndParent, title, title.Capacity); - parentText = title.ToString(); - } - - var windows = new List(); - foreach (var window in Items) { - if (hasParent) { - window.Text = parentText; - window.ParentHandle = hWndParent; - } - if (classname == null || window.ClassName.Equals(classname)) { - windows.Add(window); - } - } - Items = windows; - return this; - } - - /// - /// The enum Windows callback. - /// - /// Window Handle - /// Application defined value - /// 1 to continue enumeration, 0 to stop - private int WindowEnum(IntPtr hWnd, int lParam) - { - return OnWindowEnum(hWnd) ? 1 : 0; - } - - /// - /// Called whenever a new window is about to be added - /// by the Window enumeration called from GetWindows. - /// If overriding this function, return true to continue - /// enumeration or false to stop. If you do not call - /// the base implementation the Items collection will - /// be empty. - /// - /// Window handle to add - /// True to continue enumeration, False to stop - private bool OnWindowEnum(IntPtr hWnd) { - if (!WindowDetails.IsIgnoreHandle(hWnd)) { - Items.Add(new WindowDetails(hWnd)); - } - return true; - } - } -} diff --git a/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs b/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs deleted file mode 100644 index e48062f57..000000000 --- a/GreenshotPlugin/Core/WmInputLangChangeRequestFilter.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using log4net; - -namespace GreenshotPlugin.Core -{ - /// - /// This IMessageFilter filters out all WM_INPUTLANGCHANGEREQUEST messages which go to a handle which is >32 bits. - /// The need for this is documented here: http://stackoverflow.com/a/32021586 - /// - public class WmInputLangChangeRequestFilter : IMessageFilter - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(WmInputLangChangeRequestFilter)); - - /// - /// This will do some filtering - /// - /// Message - /// true if the message should be filtered - public bool PreFilterMessage(ref Message m) - { - return PreFilterMessageExternal(ref m); - } - - /// - /// Also used in the MainForm WndProc - /// - /// Message - /// true if the message should be filtered - public static bool PreFilterMessageExternal(ref Message m) - { - WindowsMessages message = (WindowsMessages)m.Msg; - if (message == WindowsMessages.WM_INPUTLANGCHANGEREQUEST || message == WindowsMessages.WM_INPUTLANGCHANGE) - { - LOG.WarnFormat("Filtering: {0}, {1:X} - {2:X} - {3:X}", message, m.LParam.ToInt64(), m.WParam.ToInt64(), m.HWnd.ToInt64()); - // For now we always return true - return true; - // But it could look something like this: - //return (m.LParam.ToInt64() | 0x7FFFFFFF) != 0; - } - return false; - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Effects/ReduceColorsEffect.cs b/GreenshotPlugin/Effects/ReduceColorsEffect.cs deleted file mode 100644 index a432850b6..000000000 --- a/GreenshotPlugin/Effects/ReduceColorsEffect.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; -using log4net; - -namespace GreenshotPlugin.Effects -{ - /// - /// ReduceColorsEffect - /// - public class ReduceColorsEffect : IEffect { - private static readonly ILog Log = LogManager.GetLogger(typeof(ReduceColorsEffect)); - public ReduceColorsEffect() - { - Reset(); - } - public int Colors { - get; - set; - } - public void Reset() { - Colors = 256; - } - public Image Apply(Image sourceImage, Matrix matrix) { - using (WuQuantizer quantizer = new WuQuantizer((Bitmap)sourceImage)) { - int colorCount = quantizer.GetColorCount(); - if (colorCount > Colors) { - try { - return quantizer.GetQuantizedImage(Colors); - } catch (Exception e) { - Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); - } - } - } - return null; - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Effects/ResizeEffect.cs b/GreenshotPlugin/Effects/ResizeEffect.cs deleted file mode 100644 index 38f997f71..000000000 --- a/GreenshotPlugin/Effects/ResizeEffect.cs +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// ResizeEffect - /// - public class ResizeEffect : IEffect { - public ResizeEffect(int width, int height, bool maintainAspectRatio) { - Width = width; - Height = height; - MaintainAspectRatio = maintainAspectRatio; - } - public int Width { - get; - set; - } - public int Height { - get; - set; - } - public bool MaintainAspectRatio { - get; - set; - } - public void Reset() { - // values don't have a default value - } - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.ResizeImage(sourceImage, MaintainAspectRatio, Width, Height, matrix); - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Effects/RotateEffect.cs b/GreenshotPlugin/Effects/RotateEffect.cs deleted file mode 100644 index 772a41a6a..000000000 --- a/GreenshotPlugin/Effects/RotateEffect.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// RotateEffect - /// - public class RotateEffect : IEffect { - public RotateEffect(int angle) { - Angle = angle; - } - public int Angle { - get; - set; - } - public void Reset() { - // Angle doesn't have a default value - } - public Image Apply(Image sourceImage, Matrix matrix) { - RotateFlipType flipType; - if (Angle == 90) { - matrix.Rotate(90, MatrixOrder.Append); - matrix.Translate(sourceImage.Height, 0, MatrixOrder.Append); - flipType = RotateFlipType.Rotate90FlipNone; - } else if (Angle == -90 || Angle == 270) { - flipType = RotateFlipType.Rotate270FlipNone; - matrix.Rotate(-90, MatrixOrder.Append); - matrix.Translate(0, sourceImage.Width, MatrixOrder.Append); - } else { - throw new NotSupportedException("Currently only an angle of 90 or -90 (270) is supported."); - } - return ImageHelper.RotateFlip(sourceImage, flipType); - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Effects/TornEdgeEffect.cs b/GreenshotPlugin/Effects/TornEdgeEffect.cs deleted file mode 100644 index 682435132..000000000 --- a/GreenshotPlugin/Effects/TornEdgeEffect.cs +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// TornEdgeEffect extends on DropShadowEffect - /// - [TypeConverter(typeof(EffectConverter))] - public sealed class TornEdgeEffect : DropShadowEffect { - public TornEdgeEffect() - { - Reset(); - } - public int ToothHeight { - get; - set; - } - public int HorizontalToothRange { - get; - set; - } - public int VerticalToothRange { - get; - set; - } - public bool[] Edges { - get; - set; - } - public bool GenerateShadow { - get; - set; - } - - public override void Reset() { - base.Reset(); - ShadowSize = 7; - ToothHeight = 12; - HorizontalToothRange = 20; - VerticalToothRange = 20; - Edges = new[] { true, true, true, true }; - GenerateShadow = true; - } - public override Image Apply(Image sourceImage, Matrix matrix) { - Image tmpTornImage = ImageHelper.CreateTornEdge(sourceImage, ToothHeight, HorizontalToothRange, VerticalToothRange, Edges); - if (GenerateShadow) { - using (tmpTornImage) { - return ImageHelper.CreateShadow(tmpTornImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); - } - } - return tmpTornImage; - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/GlobalSuppressions.cs b/GreenshotPlugin/GlobalSuppressions.cs deleted file mode 100644 index c050f5d980bbaf4f7f04fa6cb01422c0eebd5458..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112958 zcmeHQZEqV#lAg~8+p61k3@72}+`u{%_e=4?$)8eui7c>0t9G_Rk2>+9x z@9^7EF~rYri+lXrFDCej<2%JoafWN}afMtv$JkbJjo*$jHh=isDo%>K;ue3VxNn9( z2M?cT#f6*cKa2msD!7g_+%?B_V?6B+|Ks&r_`Gx@9OoSTy$m*&zlXu~tU%qLN7tT+*UEuA^ zi$CHyq|UqIJ$^55PS!*Ed%6=P)*r+Je8dCOuf;q;(xK4JFIHx-YD@wOx)l)ja2`pn-Lcx+P`Pv zuNypryhrX6baUOm;CFn#LUoS)fM=gL4ka&LP49uY*jGs7HL58qN|J;C~gJGP4daZk~xmupUON6DXZ)gFFBnvlOa_q;g5 z%y(EXv9w*h#=n$gH;vRm(pRl&=;w${`1Fn6Iu_3PJn?A*ycaHaX zKXD>*ha5k3-;8hPc|aTDjq9KU{I+Oog>SH$mss6F(ZhS)!Q0+1-ry<6#UcLP#pfx0 zw~MuWUHk!5`a|)nlTg?W@g_*~ z9_aCR%tNHU#qY_@#A-gM`WtY>?|mP^)Cs=B9mXj8Pw)-?51;GC)CsWiGtgpK$qy@( zS(Iv&VU+E}O~Z9)2ZUH#74Vf4SeElJ-X_WMKFnm#u10{2hgDg1=H=Y0FqCo{k0Ankm~Y}_B{Og)1K;6oFn8E>j?=PHtSn*f zHmqW?Jh;z;zrwqrJfH?;MF1leQZum&US{5wHqfx(FAJak)^=qc~zuhi#?EkA($ zmEvoTrzma`x+@922l@NT)ecY=_nfartE`?iJcgwvv2E5@huIGD`4rXKtR|;-%xI&? zevONiA5hIgmX>=P_vEtn0p8IW>N{xZG9y4f>Vq~^5JjeE6UtWu_3EEM{)(SYo^Jz2yKTp%v`9n=eOb)AnG2%I;suJ*)>$tH&V4=H^brTdbNn)QQ_^$Q`1zsq0Z~9oq^Kt^Mfw zoq9C9Q_pI$F%Q|Obt88UP(~iZb6`#II{hWViN#L4+y`2Q5^bOC;AdWQ zk38wQ%j{4ig|aARWmLyjM^SU`zgkTamtgVQ=~C_)9`nPakM+DleUWtLcv1W#3k<%9 z*y>fh$85F~2L0ITe6k0=WjzFIu?*Gup_;zxydqVPfNtgim~D~$L3LgJRCJlI$NJ5# zJH3d7AJe(o?@MV~zc(nQ-K>tXyE>+33hSzu6ooa1o7`TH-0mad#>_VN;d9s4HsWvW z4aII`_bx|Uj?yv?dpO9|e|1+cZwtrv>}dHM^0po`MC5@8T2|Z@p!+VZjtZl09@IT> zkrZ}`W9L5UyBOzo&6~!zpT1|~vXWe)WvNP@kG!%(YQqbs>6P={m@y7M2 zr2WL4_u^gki}{*8Fa3PFJ5s2V(=lQ#@eMaQ;f5W#rF%Mel4xp>Qv-93ovYJxec| z9je6UD*4qY`04HD#S%3}K`*_fGnLf+Ge*67wxT+tmf&TNkL6^!$N{Tp>9V3FhM}^b z#0$s*T5VO@msvjVpQYqOhzYI1!?CCMYqsl(T6fTU8Inj})zL2Za^fPNe2W$TbblP#d3Z#yV^$VH<{kchA zqwiwxW5|h`lA-2KjhXb`)ZH90)HKplq2i)3DM0>0%TwXl$5J8@&#+H# zr}(b;bMZa?{@|*`Hn}rxXoWGm=xZDJK2pdqjgX5*Ak}^bY8g|GomXgjJcnx2kk>?y zvtC$YoxaL6#dBeX$s&ow_HRJ`=MYIOv9OPC#Q5PdSP(9^*i=rjsgTD#T_yTt)ZJ{Z zWu?v-d^!)}9?f2KD8IF44#)H!KC`uQv9;(=F)DfB;$Ac8?hE{H8BW%84QZajgB~+H z7#?(;x#1xfJk+CeUgs|(BZSw@mdnqU(~&e!S+nLo2Oq2+DfRSy8t2A!yYX~RJl#z5 zRd_m1d8;_ctKxt=z2%$%R{FefvH$BQdve;UH)|{xYb;Jz{)qJjtAtK+X zySCzJYx69_w3c5TDY0i-raYfa`7Ut4E`OR%?R1HY&+Pa4nYFM9JHb2+`>5z1BWG8w zOI&o~&Fa#_Kfj7j!w{=47>nHm3`uN=5>HO>xcYdGZd&)m@(J`K+o#s^-~-q@dq?jajxKGnfe-!Gf9tn@#8_quPd>&Cpna5_ZL7 zmH&FOoubLASSyiYG9(unQqOFqPI&ivs7lvmI~$!qnw$fBy2FtnA{Ru|qvy+O72)(a zT1qJp>WfuJR`~v3s=lThflFX_KaHoGupPqK&A2ea>dRu#V@kUkI(m3&^=SKI76V9TQx~ zx;)*=bK8v5a^W|wti2>nFF@Ow)BMv)rCmD1X#AQZJ!t{g_rjin z!q*rf?=I>@Rn_5|YeSAsN&4#8>bafAe6P|@3|E@^7Jf|PomTyuPo0(Mo+J3=_mEHQ zeRKvtrSJ3)_0SaO1WLus>i9ZB9F?_pr&ei~QKj7hC|=DMlHy}XxcQRSN89p9<0X_f z@+{j`nA5I8ktJHUNrf_N2V8f;``~P{1>BIE>x3##ysh9 zVzh(2+PwW0+GeA6l)ZhcOWfGJX2IuX!Fy@jCgpt;d_m1Oz) z&NrAlZ!q2M%QSf|n!H+<7E;jYlnb5uu(en{$ZW8dghN;#9BHdlgPxln)6t_7H=kUHD7!YpqhyQ*^P!FnVtay(OEKrf7OJ=S-Ma6nFjq@}4EK{0w}?H?CSjIunI9nXU{A$22)n7lN`%}}~^zXK;VKUzNR1(v_d(S(h5pz_GbzP(0h%$1BzpOeb`9^2^ ztEa|?xZaEoOrMKPOI!iGQyiv^zT^4N&DO*6sj1F|Q%Xxc^Y3CF{wk z`K6cEuA4>l_pny&T%~KivCA))vh`Ty4rt3t0$OFPg-vIULQXDaeH%H(=03&cb4&}Y zR|_mJEwoJNL9TE&1g(AcAYHU0O6cmnrPb>nM3TM1^Y>x-9piHs@p{&=4l>TA$XnQa zpKCSj#5GPBZSg*s`Ow^<+O;g$17E!=NDKN{J!dIU2Go7$HoB^%v`^LgEcHbj_vEtn z0VL}gEHuj13%qf1468Sf@SESAO?UV)X5%e3)0cVih-&n+4X#dm^LquMP zkT_Op_pV2}#iU0XL57nYal-vlzrn(07FcSm>zz8R z`)G$m&d-3VOXrE-AX74NHhn0K%(nP+bsvjkka1dGfpQbjl0Lbnr14&kyeDz48+50* z1Ye4`&_*{yJ)f={3cZDDrZXHhe$SoXPmraWxmYPPRGR9c?AAV`$$}hZ0X;%i?6IGd zQIhYX`|8W5X<;wb{fUwMF0|BFk1|zf)RMidFAJr3TE>_01d|FmN`=2cBG6{PN3|!b zd9RQqV+E+M1b*deqF4|0BVvt|9Vy8lVnb{AaO^47lzKj^o9aHV9rF=NL=AwW88Y8x zR3XGps^WK5e3-n+QQk;I@&L#fI(bt)4=#ldqi2rv@Hw{~t z$|>G#qZX_FMA@++yQzm}g>}CFER^4p`TS6^#MX_H*fR|$pR(6aI~Lx^d46fMR4am? z67wrPL(?$%YZy=AeP<0`z#hCbixAP0uDW_XmD7c9DV3Sksdrv9t}J__<;Img&}-}> zs#TACf@&}Be@;nkld-u`Q*3JK#>J9^&%_x^AuI|WF6z8sAU_Gk@V9ovYlUKTOy-rx}_{BL(P}a zpDT=~F{|lw;M_l(LWpUK+%yHL_cQD?cJgG$R-@kLMJ`x}%5x)TAFCEqR17m(K7Lj0 z$J>L)#Y)H_P%&-jl44aRIrP^H<*|6rB_{U4+pINP1``(R$~V^4L|@5C8SL zb0F{Q{zi4rK=W*R{ zetV97do%4<;qf>EtbX}ZoG-Y%*T>!fH}LzIIiDgYE9cQ^xxb7Y&|ZL9ZMj)(aa#M{ z#cgynYCbE;kdaeQg3t=6+w;`u=a30$?q9tJmXXz`i- zenzto-ESH_J-2^4jh!|SQsPyfIDjPNzHN5ykn?Io zomTDXX=ut1O{`beSUQ44s-M;%Q80;ggfy;dr0s|5=WEQe4SB-M>j)Os92jjviOe30 zu^E2y-q$H;nXfgw8pB127?UZv$&|XsojN-zE>qe#9mbH68#3xq`Q^1uN)we*A=FW; zj;wAyX)P(=+VGhhK1FiLE>}&jlx1yH%#(_-bA7e!FuLVNH)d;?OJ?=`2;JWM3nKKf zXo%%v^UTGHWMv)w7##%O!pCICw;}w)5AY4SE5dd&=a(4~d#z42`lKUJPUvQQxH;Wf zn7udy$6bJSb-K#v7~?66CvIDtZ5uT%AwJsMgI=yTB|X;hJoZnaRe9m!&!a>YXMAOC<=4V@>*-dWhh`j?8^`g~ ziF&7`s=cFkbA$-eV@BOgpl*N5GzpdyhQhp4HHwQA7u}<2SPZ~F&gpp^_n>KqlH$;hS z(S9whAD+raIn&Nwh^E;M4Y{F#UE6P=WqcpPlteM=*e~+D=aB#^vaE1eb{8IZe*-kOUNO-ERJv&T^m_^JvVIzlfK9-CKCr;d!!D>#YrTF-mX6pOKX=W~Lc;^>bt4Vs43K-!(x0ak`pG@` zU*z>)ieGD0C!VqrZx3T-e$=96IrJ7=mhKYiOj9;JYIM(m?gPZwh1UnDb-pfM!%`kT z=x?4+&z>=F;WwQ@e_uf!P=?=v->2Yu)<-Xj#jozk%L?BhPxBJ1J1Ba{+3di!*e~8- UJ?!Ri1nqK+@mKgf2`qts17z#55C8xG diff --git a/GreenshotPlugin/Hooking/WindowsEventHook.cs b/GreenshotPlugin/Hooking/WindowsEventHook.cs deleted file mode 100644 index 8893bd57e..000000000 --- a/GreenshotPlugin/Hooking/WindowsEventHook.cs +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.Hooking -{ - /// - /// The WinEventHook can register handlers to become important windows events - /// This makes it possible to know a.o. when a window is created, moved, updated and closed. - /// - public class WindowsEventHook : IDisposable - { - private readonly WinEventDelegate _winEventHandler; - private GCHandle _gcHandle; - - /// - /// Used with Register hook - /// - /// - /// - /// - /// - /// - /// - public delegate void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); - - /// - /// Create a WindowsEventHook object - /// - public WindowsEventHook() - { - _winEventHandler = WinEventDelegateHandler; - _gcHandle = GCHandle.Alloc(_winEventHandler); - } - - [DllImport("user32", SetLastError = true)] - private static extern bool UnhookWinEvent(IntPtr hWinEventHook); - [DllImport("user32", SetLastError = true)] - private static extern IntPtr SetWinEventHook(WinEvent eventMin, WinEvent eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, int idProcess, int idThread, WinEventHookFlags dwFlags); - - /// - /// Used with SetWinEventHook - /// - /// - /// - /// - /// - /// - /// - /// - private delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); - - private readonly IDictionary _winEventHandlers = new Dictionary(); - - /// - /// Are hooks active? - /// - public bool IsHooked => _winEventHandlers.Count > 0; - - /// - /// Hook a WinEvent - /// - /// - /// - /// true if success - public void Hook(WinEvent winEvent, WinEventHandler winEventHandler) - { - Hook(winEvent, winEvent, winEventHandler); - } - - /// - /// Hook a WinEvent - /// - /// - /// - /// - public void Hook(WinEvent winEventStart, WinEvent winEventEnd, WinEventHandler winEventHandler) - { - var hookPtr = SetWinEventHook(winEventStart, winEventEnd, IntPtr.Zero, _winEventHandler, 0, 0, WinEventHookFlags.WINEVENT_SKIPOWNPROCESS | WinEventHookFlags.WINEVENT_OUTOFCONTEXT); - _winEventHandlers.Add(hookPtr, winEventHandler); - } - - /// - /// Remove all hooks - /// - private void Unhook() - { - foreach (var hookPtr in _winEventHandlers.Keys) - { - if (hookPtr != IntPtr.Zero) - { - UnhookWinEvent(hookPtr); - } - } - _winEventHandlers.Clear(); - _gcHandle.Free(); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Unhook(); - } - - /// - /// Call the WinEventHandler for this event - /// - /// - /// - /// - /// - /// - /// - /// - private void WinEventDelegateHandler(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) - { - if (_winEventHandlers.TryGetValue(hWinEventHook, out var handler)) - { - handler(eventType, hWnd, idObject, idChild, dwEventThread, dwmsEventTime); - } - } - - } - -} diff --git a/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs b/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs deleted file mode 100644 index 97634b92f..000000000 --- a/GreenshotPlugin/Hooking/WindowsOpenCloseMonitor.cs +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.Hooking -{ - /// - /// Event arguments for the WindowOpenCloseEvent - /// - public class WindowOpenCloseEventArgs : EventArgs - { - public bool IsOpen { get; set; } - /// - /// HWnd of the window which has a changed title - /// - public IntPtr HWnd - { - get; - set; - } - - /// - /// Title which is changed - /// - public string Title - { - get; - set; - } - - public string ClassName { get; set; } - } - /// - /// Delegate for the window open close event - /// - /// - public delegate void WindowOpenCloseEventDelegate(WindowOpenCloseEventArgs eventArgs); - - /// - /// Monitor all new and destroyed windows - /// - public sealed class WindowsOpenCloseMonitor : IDisposable - { - private WindowsEventHook _hook; - private readonly object _lockObject = new object(); - // ReSharper disable once InconsistentNaming - private event WindowOpenCloseEventDelegate _windowOpenCloseEvent; - - /// - /// Add / remove event handler to the title monitor - /// - public event WindowOpenCloseEventDelegate WindowOpenCloseChangeEvent - { - add - { - lock (_lockObject) - { - if (_hook == null) - { - _hook = new WindowsEventHook(); - _hook.Hook(WinEvent.EVENT_OBJECT_CREATE, WinEvent.EVENT_OBJECT_DESTROY, WinEventHandler); - } - _windowOpenCloseEvent += value; - } - } - remove - { - lock (_lockObject) - { - _windowOpenCloseEvent -= value; - if (_windowOpenCloseEvent == null || _windowOpenCloseEvent.GetInvocationList().Length == 0) - { - if (_hook != null) - { - _hook.Dispose(); - _hook = null; - } - } - } - } - } - - /// - /// WinEventDelegate for the creation and destruction - /// - /// - /// - /// - /// - /// - /// - private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) - { - if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) - { - return; - } - if (eventType == WinEvent.EVENT_OBJECT_CREATE) - { - if (_windowOpenCloseEvent != null) - { - var windowsDetails = new WindowDetails(hWnd); - _windowOpenCloseEvent(new WindowOpenCloseEventArgs { HWnd = hWnd, IsOpen = true, Title = windowsDetails.Text, ClassName = windowsDetails.ClassName }); - } - } - if (eventType == WinEvent.EVENT_OBJECT_DESTROY) - { - _windowOpenCloseEvent?.Invoke(new WindowOpenCloseEventArgs { HWnd = hWnd, IsOpen = false }); - } - } - - private bool _disposedValue; // To detect redundant calls - - /// - /// Dispose the underlying hook - /// - public void Dispose(bool disposing) - { - if (_disposedValue) - { - return; - } - lock (_lockObject) - { - _hook?.Dispose(); - } - _disposedValue = true; - } - - /// - /// Make sure the finalizer disposes the underlying hook - /// - ~WindowsOpenCloseMonitor() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(false); - } - - /// - /// Dispose the underlying hook - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - GC.SuppressFinalize(this); - } - } - -} diff --git a/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs b/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs deleted file mode 100644 index c35dbf2e8..000000000 --- a/GreenshotPlugin/Hooking/WindowsTitleMonitor.cs +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using GreenshotPlugin.Core; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.Hooking -{ - /// - /// Event arguments for the TitleChangeEvent - /// - public class TitleChangeEventArgs : EventArgs - { - /// - /// HWnd of the window which has a changed title - /// - public IntPtr HWnd - { - get; - set; - } - - /// - /// Title which is changed - /// - public string Title - { - get; - set; - } - } - /// - /// Delegate for the title change event - /// - /// - public delegate void TitleChangeEventDelegate(TitleChangeEventArgs eventArgs); - - /// - /// Monitor all title changes - /// - public sealed class WindowsTitleMonitor : IDisposable - { - private WindowsEventHook _hook; - private readonly object _lockObject = new object(); - // ReSharper disable once InconsistentNaming - private event TitleChangeEventDelegate _titleChangeEvent; - - /// - /// Add / remove event handler to the title monitor - /// - public event TitleChangeEventDelegate TitleChangeEvent - { - add - { - lock (_lockObject) - { - if (_hook == null) - { - _hook = new WindowsEventHook(); - _hook.Hook(WinEvent.EVENT_OBJECT_NAMECHANGE, WinEventHandler); - } - _titleChangeEvent += value; - } - } - remove - { - lock (_lockObject) - { - _titleChangeEvent -= value; - if (_titleChangeEvent == null || _titleChangeEvent.GetInvocationList().Length == 0) - { - if (_hook != null) - { - _hook.Dispose(); - _hook = null; - } - } - } - } - } - - /// - /// WinEventDelegate for the creation & destruction - /// - /// - /// - /// - /// - /// - /// - private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) - { - if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) - { - return; - } - if (eventType == WinEvent.EVENT_OBJECT_NAMECHANGE) - { - if (_titleChangeEvent != null) - { - string newTitle = new WindowDetails(hWnd).Text; - _titleChangeEvent(new TitleChangeEventArgs { HWnd = hWnd, Title = newTitle }); - } - } - } - - private bool _disposedValue; // To detect redundant calls - - /// - /// Dispose the underlying hook - /// - public void Dispose(bool disposing) - { - if (_disposedValue) - { - return; - } - lock (_lockObject) - { - _hook?.Dispose(); - } - _disposedValue = true; - } - - /// - /// Make sure the finalizer disposes the underlying hook - /// - ~WindowsTitleMonitor() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(false); - } - - /// - /// Dispose the underlying hook - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - GC.SuppressFinalize(this); - } - } - -} diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument2.cs b/GreenshotPlugin/IEInterop/IHTMLDocument2.cs deleted file mode 100644 index 6ca8d9c9b..000000000 --- a/GreenshotPlugin/IEInterop/IHTMLDocument2.cs +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - /// IHTMLDocument2 interface. - [Guid("332C4425-26CB-11D0-B483-00C04FD90119")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument2 { - IHTMLElement body { - [DispId(1004)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - string title { - [DispId(1012)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - object frames { - [DispId(1019)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - string url { - [DispId(1025)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - IHTMLWindow2 parentWindow { - [DispId(1034)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - object bgColor { - [DispId(-501)] - get; - } - - IHTMLSelectionObject selection { - [DispId(1017)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - string designMode { - [DispId(1014)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - [DispId(1014)] - set; - } - } -} diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument3.cs b/GreenshotPlugin/IEInterop/IHTMLDocument3.cs deleted file mode 100644 index e12344f62..000000000 --- a/GreenshotPlugin/IEInterop/IHTMLDocument3.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - /// IHTMLDocument3 interface. - [Guid("3050F485-98B5-11CF-BB82-00AA00BDCE0B")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument3 { - IHTMLElement documentElement { - [DispId(1075)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(1086)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLElementCollection getElementsByName([MarshalAs(UnmanagedType.BStr)] string v); - - [DispId(1088)] - IHTMLElement getElementById([MarshalAs(UnmanagedType.BStr)] string v); - - [DispId(1087)] - IHTMLElementCollection getElementsByTagName([MarshalAs(UnmanagedType.BStr)] string v); - } -} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLElement.cs b/GreenshotPlugin/IEInterop/IHTMLElement.cs deleted file mode 100644 index aa0a54b79..000000000 --- a/GreenshotPlugin/IEInterop/IHTMLElement.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F1FF-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLElement { - [DispId(-2147417611)] - void setAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, object AttributeValue, int lFlags); - - [DispId(-2147417610)] - object getAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); - - long offsetLeft { - [DispId(-2147417104)] - get; - } - - long offsetTop { - [DispId(-2147417103)] - get; - } - - long offsetWidth { - [DispId(-2147417102)] - get; - } - - long offsetHeight { - [DispId(-2147417101)] - get; - } - - IHTMLElement offsetParent { - [DispId(-2147417100)] - get; - } - - string className { - [DispId(-2147417111)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - IHTMLDocument2 document { - [DispId(-2147417094)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - string id { - [DispId(-2147417110)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string innerHTML { - [DispId(-2147417086)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string innerText { - [DispId(-2147417085)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - IHTMLStyle style { - [DispId(-2147418038)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - string tagName { - [DispId(-2147417108)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string title { - [DispId(-2147418043)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - [DispId(-2147417093)] - void scrollIntoView(bool varargStart); - - IHTMLElementCollection children { - [DispId(-2147417075)] - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLElement2.cs b/GreenshotPlugin/IEInterop/IHTMLElement2.cs deleted file mode 100644 index 44ace8d30..000000000 --- a/GreenshotPlugin/IEInterop/IHTMLElement2.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F434-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLElement2 { - [DispId(-2147417067)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLRect getBoundingClientRect(); - - IHTMLCurrentStyle currentStyle { - [DispId(-2147417105)] - [return: MarshalAs(UnmanagedType.Interface)] //IHTMLCurrentStyle - get; - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs b/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs deleted file mode 100644 index fadb35ca0..000000000 --- a/GreenshotPlugin/IEInterop/IHTMLSelectionObject.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - // See: http://msdn.microsoft.com/en-us/library/aa768849%28v=vs.85%29.aspx - [ComImport, Guid("3050f25A-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLSelectionObject { - [return: MarshalAs(UnmanagedType.IDispatch)] - [DispId(1001)] - IHTMLTxtRange createRange(); - [DispId(1002)] - void empty(); - [DispId(1003)] - void clear(); - [DispId(1004)] - string EventType { [return: MarshalAs(UnmanagedType.BStr)] get;} - } -} diff --git a/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs b/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs deleted file mode 100644 index f9ff8d690..000000000 --- a/GreenshotPlugin/IEInterop/IHTMLTxtRange.cs +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - // See: http://msdn.microsoft.com/en-us/library/aa741548%28v=vs.85%29.aspx - [ComImport, Guid("3050F220-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLTxtRange { - [DispId(1006)] - IHTMLElement parentElement(); - - [DispId(1008)] - IHTMLTxtRange duplicate(); - - [DispId(1010)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool inRange(IHTMLTxtRange range); - - [DispId(1011)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool isEqual(IHTMLTxtRange range); - - [DispId(1012)] - void scrollIntoView([MarshalAs(UnmanagedType.VariantBool)] bool fStart); - - [DispId(1013)] - void collapse([MarshalAs(UnmanagedType.VariantBool)] bool Start); - - [DispId(1014)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool expand([MarshalAs(UnmanagedType.BStr)] string Unit); - - [DispId(1015)] - int move([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); - - [DispId(1016)] - int moveStart([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); - - [DispId(1017)] - int moveEnd([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); - - [DispId(1024)] - void select(); - - [DispId(1026)] - void pasteHTML([MarshalAs(UnmanagedType.BStr)] string html); - - [DispId(1001)] - void moveToElementText(IHTMLElement element); - - [DispId(1025)] - void setEndPoint([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); - - [DispId(1018)] - int compareEndPoints([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); - - [DispId(1019)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool findText([MarshalAs(UnmanagedType.BStr)] string String, int Count, int Flags); - - [DispId(1020)] - void moveToPoint(int x, int y); - - [DispId(1021)] - [return: MarshalAs(UnmanagedType.BStr)] - string getBookmark(); - - [DispId(1009)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool moveToBookmark([MarshalAs(UnmanagedType.BStr)] string Bookmark); - - [DispId(1027)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandSupported([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1028)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandEnabled([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1029)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandState([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1030)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool queryCommandIndeterm([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1031)] - [return: MarshalAs(UnmanagedType.BStr)] - string queryCommandText([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1032)] - object queryCommandValue([MarshalAs(UnmanagedType.BStr)] string cmdID); - - [DispId(1033)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool execCommand([MarshalAs(UnmanagedType.BStr)] string cmdID, [MarshalAs(UnmanagedType.VariantBool)] bool showUI, object value); - - [DispId(1034)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool execCommandShowHelp([MarshalAs(UnmanagedType.BStr)] string cmdID); - - string htmlText { - [DispId(1003)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string text { - [DispId(1004)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - [DispId(1004)] - set; - } - } -} diff --git a/GreenshotPlugin/IEInterop/IWebBrowser2.cs b/GreenshotPlugin/IEInterop/IWebBrowser2.cs deleted file mode 100644 index 36b06d6e4..000000000 --- a/GreenshotPlugin/IEInterop/IWebBrowser2.cs +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - // IWebBrowser: EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B -// [ComVisible(true), ComImport(), Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"), -// TypeLibType(TypeLibTypeFlags.FDual), -// InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] -// public interface IWebBrowser2 { -// [DispId(203)] -// object Document { -// [return: MarshalAs(UnmanagedType.IDispatch)] -// get; -// } -// } - [ComImport, /*SuppressUnmanagedCodeSecurity,*/ - TypeLibType(TypeLibTypeFlags.FOleAutomation | - TypeLibTypeFlags.FDual | - TypeLibTypeFlags.FHidden), - Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")] - public interface IWebBrowser2 { - [DispId(100)] - void GoBack(); - [DispId(0x65)] - void GoForward(); - [DispId(0x66)] - void GoHome(); - [DispId(0x67)] - void GoSearch(); - [DispId(0x68)] - void Navigate([In] string Url, - [In] ref object flags, - [In] ref object targetFrameName, - [In] ref object postData, - [In] ref object headers); - [DispId(-550)] - void Refresh(); - [DispId(0x69)] - void Refresh2([In] ref object level); - [DispId(0x6a)] - void Stop(); - [DispId(200)] - object Application { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - [DispId(0xc9)] - object Parent { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - [DispId(0xca)] - object Container { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - [DispId(0xcb)] - object Document { - [return: - MarshalAs(UnmanagedType.IDispatch)] - get; - } - [DispId(0xcc)] - bool TopLevelContainer { get; } - [DispId(0xcd)] - string Type { get; } - [DispId(0xce)] - int Left { get; set; } - [DispId(0xcf)] - int Top { get; set; } - [DispId(0xd0)] - int Width { get; set; } - [DispId(0xd1)] - int Height { get; set; } - [DispId(210)] - string LocationName { get; } - [DispId(0xd3)] - string LocationURL { get; } - [DispId(0xd4)] - bool Busy { get; } - [DispId(300)] - void Quit(); - [DispId(0x12d)] - void ClientToWindow(out int pcx, out int pcy); - [DispId(0x12e)] - void PutProperty([In] string property, [In] object vtValue); - [DispId(0x12f)] - object GetProperty([In] string property); - [DispId(0)] - string Name { get; } - [DispId(-515)] - int HWND { get; } - [DispId(400)] - string FullName { get; } - [DispId(0x191)] - string Path { get; } - [DispId(0x192)] - bool Visible { get; set; } - [DispId(0x193)] - bool StatusBar { get; set; } - [DispId(0x194)] - string StatusText { get; set; } - [DispId(0x195)] - int ToolBar { get; set; } - [DispId(0x196)] - bool MenuBar { get; set; } - [DispId(0x197)] - bool FullScreen { get; set; } - [DispId(500)] - void Navigate2([In] ref object URL, - [In] ref object flags, - [In] ref object targetFrameName, - [In] ref object postData, - [In] ref object headers); - - [DispId(550)] - bool Offline { get; set; } - [DispId(0x227)] - bool Silent { get; set; } - [DispId(0x228)] - bool RegisterAsBrowser { get; set; } - [DispId(0x229)] - bool RegisterAsDropTarget { get; set; } - [DispId(0x22a)] - bool TheaterMode { get; set; } - [DispId(0x22b)] - bool AddressBar { get; set; } - [DispId(0x22c)] - bool Resizable { get; set; } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/IniFile/IniAttributes.cs b/GreenshotPlugin/IniFile/IniAttributes.cs deleted file mode 100644 index 0b23b679e..000000000 --- a/GreenshotPlugin/IniFile/IniAttributes.cs +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.IniFile { - /// - /// Attribute for telling that this class is linked to a section in the ini-configuration - /// - [AttributeUsage(AttributeTargets.Class)] - public class IniSectionAttribute : Attribute { - public IniSectionAttribute(string name) { - Name = name; - } - public string Description; - public string Name { get; set; } - } - - /// - /// Attribute for telling that a field is linked to a property in the ini-configuration selection - /// - [AttributeUsage(AttributeTargets.Field|AttributeTargets.Property)] - public class IniPropertyAttribute : Attribute { - public IniPropertyAttribute() { - Separator = ","; - } - public IniPropertyAttribute(string name) : this() { - Name = name; - } - public string Description { - get; - set; - } - public string Separator { - get; - set; - } - public string DefaultValue { - get; - set; - } - public string LanguageKey { - get; - set; - } - // If Encrypted is set to true, the value will be decrypted on load and encrypted on save - public bool Encrypted { - get; - set; - } - public bool FixedValue { - get; - set; - } - public bool Expert { - get; - set; - } - public bool ExcludeIfNull { - get; - set; - } - - public string Name { - get; - set; - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/IniFile/IniConfig.cs b/GreenshotPlugin/IniFile/IniConfig.cs deleted file mode 100644 index 5ea33f6df..000000000 --- a/GreenshotPlugin/IniFile/IniConfig.cs +++ /dev/null @@ -1,464 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Text; -using System.Threading; -using log4net; - -namespace GreenshotPlugin.IniFile { - public class IniConfig { - private static readonly ILog Log = LogManager.GetLogger(typeof(IniConfig)); - private const string IniExtension = ".ini"; - private const string DefaultsPostfix = "-defaults"; - private const string FixedPostfix = "-fixed"; - - /// - /// A lock object for the ini file saving - /// - private static readonly object IniLock = new object(); - - /// - /// As the ini implementation is kept someone generic, for reusing, this holds the name of the application - /// - private static string _applicationName; - - /// - /// As the ini implementation is kept someone generic, for reusing, this holds the name of the configuration - /// - private static string _configName; - - /// - /// A Dictionary with all the sections stored by section name - /// - private static readonly IDictionary SectionMap = new Dictionary(); - - /// - /// A Dictionary with the properties for a section stored by section name - /// - private static IDictionary> _sections = new Dictionary>(); - - /// - /// A Dictionary with the fixed-properties for a section stored by section name - /// - private static IDictionary> _fixedProperties; - - /// - /// Stores if we checked for portable - /// - private static bool _portableCheckMade; - - /// - /// Is the configuration portable (meaning we don't store it in the AppData directory) - /// - public static bool IsPortable { get; private set; } - - /// - /// Config directory when set from external - /// - public static string IniDirectory { - get; - set; - } - - /// - /// Initialize the ini config - /// - /// - /// - public static void Init(string appName, string configName) { - _applicationName = appName; - _configName = configName; - Reload(); - } - - /// - /// Checks if we initialized the ini - /// - public static bool IsInitialized => _applicationName != null && _configName != null && SectionMap.Count > 0; - - /// - /// This forces the ini to be stored in the startup path, used for portable applications - /// - public static void ForceIniInStartupPath() { - if (_portableCheckMade) { - throw new Exception("ForceLocal should be called before any file is read"); - } - IsPortable = false; - _portableCheckMade = true; - string applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - if (_applicationName == null || _configName == null) { - Init(); - } - if (applicationStartupPath == null) - { - return; - } - string forcedIni = Path.Combine(applicationStartupPath, _applicationName + IniExtension); - if (!File.Exists(forcedIni)) { - using (File.Create(forcedIni)) {} - } - } - - /// - /// Default init - /// - public static void Init() { - AssemblyProductAttribute[] assemblyProductAttributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false) as AssemblyProductAttribute[]; - if (assemblyProductAttributes != null && assemblyProductAttributes.Length > 0) { - string productName = assemblyProductAttributes[0].Product; - Log.InfoFormat("Using ProductName {0}", productName); - Init(productName, productName); - } else { - throw new InvalidOperationException("Assembly ProductName not set."); - } - } - - /// - /// Get the location of the configuration - /// - public static string ConfigLocation { - get { - if (IsInitialized) { - return CreateIniLocation(_configName + IniExtension, false); - } - throw new InvalidOperationException("Ini configuration was not initialized!"); - } - } - - /// - /// Create the location of the configuration file - /// - private static string CreateIniLocation(string configFilename, bool isReadOnly) { - if (_applicationName == null || _configName == null) { - throw new InvalidOperationException("IniConfig.Init not called!"); - } - string iniFilePath = null; - - // Check if a Ini-Directory was supplied, and it's valid, use this before any others. - try { - if (IniDirectory != null && Directory.Exists(IniDirectory)) { - // If the greenshot.ini is requested, use the supplied directory even if empty - if (!isReadOnly) { - return Path.Combine(IniDirectory, configFilename); - } - iniFilePath = Path.Combine(IniDirectory, configFilename); - if (File.Exists(iniFilePath)) { - return iniFilePath; - } - iniFilePath = null; - } - } catch (Exception exception) { - Log.WarnFormat("The ini-directory {0} can't be used due to: {1}", IniDirectory, exception.Message); - } - - string applicationStartupPath; - try { - applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); - } catch (Exception exception) { - Log.WarnFormat("Problem retrieving the AssemblyLocation: {0} (Designer mode?)", exception.Message); - applicationStartupPath = @"."; - } - if (applicationStartupPath != null) - { - string pafPath = Path.Combine(applicationStartupPath, @"App\" + _applicationName); - - if (IsPortable || !_portableCheckMade) { - if (!IsPortable) { - Log.Info("Checking for portable mode."); - _portableCheckMade = true; - if (Directory.Exists(pafPath)) { - IsPortable = true; - Log.Info("Portable mode active!"); - } - } - if (IsPortable) { - string pafConfigPath = Path.Combine(applicationStartupPath, @"Data\Settings"); - try { - if (!Directory.Exists(pafConfigPath)) { - Directory.CreateDirectory(pafConfigPath); - } - iniFilePath = Path.Combine(pafConfigPath, configFilename); - } catch(Exception e) { - Log.InfoFormat("Portable mode NOT possible, couldn't create directory '{0}'! Reason: {1}", pafConfigPath, e.Message); - } - } - } - } - if (iniFilePath == null) - { - // check if file is in the same location as started from, if this is the case - // we will use this file instead of the ApplicationData folder - // Done for Feature Request #2741508 - if (applicationStartupPath != null) - { - iniFilePath = Path.Combine(applicationStartupPath, configFilename); - } - if (!File.Exists(iniFilePath)) { - string iniDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), _applicationName); - if (!Directory.Exists(iniDirectory)) { - Directory.CreateDirectory(iniDirectory); - } - iniFilePath = Path.Combine(iniDirectory, configFilename); - } - } - Log.InfoFormat("Using ini file {0}", iniFilePath); - return iniFilePath; - } - - /// - /// Reload the Ini file - /// - public static void Reload() { - // Clear the current properties - _sections = new Dictionary>(); - // Load the defaults - Read(CreateIniLocation(_configName + DefaultsPostfix + IniExtension, true)); - // Load the normal - Read(CreateIniLocation(_configName + IniExtension, false)); - // Load the fixed settings - _fixedProperties = Read(CreateIniLocation(_configName + FixedPostfix + IniExtension, true)); - - foreach (IniSection section in SectionMap.Values) { - try { - section.Fill(PropertiesForSection(section)); - FixProperties(section); - } catch (Exception ex) { - string sectionName = "unknown"; - if (section?.IniSectionAttribute?.Name != null) { - sectionName = section.IniSectionAttribute.Name; - } - Log.WarnFormat("Problem reading the ini section {0}", sectionName); - Log.Warn("Exception", ex); - } - } - } - - /// - /// This "fixes" the properties of the section, meaning any properties in the fixed file can't be changed. - /// - /// IniSection - private static void FixProperties(IniSection section) { - // Make properties unchangeable - if (_fixedProperties == null) - { - return; - } - - if (!_fixedProperties.TryGetValue(section.IniSectionAttribute.Name, out var fixedPropertiesForSection)) - { - return; - } - foreach (string fixedPropertyKey in fixedPropertiesForSection.Keys) { - if (section.Values.ContainsKey(fixedPropertyKey)) { - section.Values[fixedPropertyKey].IsFixed = true; - } - } - } - - /// - /// Read the ini file into the Dictionary - /// - /// Path & Filename of ini file - private static IDictionary> Read(string iniLocation) { - if (!File.Exists(iniLocation)) { - Log.Info("Can't find file: " + iniLocation); - return null; - } - Log.InfoFormat("Loading ini-file: {0}", iniLocation); - //LOG.Info("Reading ini-properties from file: " + iniLocation); - var newSections = IniReader.Read(iniLocation, Encoding.UTF8); - // Merge the newly loaded properties to the already available - foreach(string section in newSections.Keys) { - IDictionary newProperties = newSections[section]; - if (!_sections.ContainsKey(section)) { - // This section is not yet loaded, simply add the complete section - _sections.Add(section, newProperties); - } else { - // Overwrite or add every property from the newly loaded section to the available one - var currentProperties = _sections[section]; - foreach(string propertyName in newProperties.Keys) { - string propertyValue = newProperties[propertyName]; - if (currentProperties.ContainsKey(propertyName)) { - // Override current value as we are loading in a certain order which insures the default, current and fixed - currentProperties[propertyName] = propertyValue; - } else { - // Add "new" value - currentProperties.Add(propertyName, propertyValue); - } - } - } - } - return newSections; - } - - public static IEnumerable IniSectionNames { - get { - foreach (string sectionName in SectionMap.Keys) { - yield return sectionName; - } - } - } - - /// - /// Method used for internal tricks... - /// - /// - /// - public static IniSection GetIniSection(string sectionName) { - SectionMap.TryGetValue(sectionName, out var returnValue); - return returnValue; - } - - /// - /// A generic method which returns an instance of the supplied type, filled with it's configuration - /// - /// IniSection Type to get the configuration for - /// Filled instance of IniSection type which was supplied - public static T GetIniSection() where T : IniSection { - return GetIniSection(true); - } - - /// - /// - /// - /// IniSection Type to get the configuration for - /// false to skip saving - /// IniSection - public static T GetIniSection(bool allowSave) where T : IniSection { - T section; - - Type iniSectionType = typeof(T); - string sectionName = IniSection.GetIniSectionAttribute(iniSectionType).Name; - if (SectionMap.ContainsKey(sectionName)) { - //LOG.Debug("Returning pre-mapped section " + sectionName); - section = (T)SectionMap[sectionName]; - } else { - // Create instance of this type - section = (T)Activator.CreateInstance(iniSectionType); - - // Store for later save & retrieval - SectionMap.Add(sectionName, section); - section.Fill(PropertiesForSection(section)); - FixProperties(section); - } - if (allowSave && section.IsDirty) { - Log.DebugFormat("Section {0} is marked dirty, saving!", sectionName); - Save(); - } - return section; - } - - /// - /// Get the raw properties for a section - /// - /// - /// - public static IDictionary PropertiesForSection(IniSection section) { - string sectionName = section.IniSectionAttribute.Name; - // Get the properties for the section - IDictionary properties; - if (_sections.ContainsKey(sectionName)) { - properties = _sections[sectionName]; - } else { - _sections.Add(sectionName, new Dictionary()); - properties = _sections[sectionName]; - } - return properties; - } - - /// - /// Save the ini file - /// - public static void Save() { - bool acquiredLock = false; - try { - acquiredLock = Monitor.TryEnter(IniLock, TimeSpan.FromMilliseconds(200)); - if (acquiredLock) { - // Code that accesses resources that are protected by the lock. - string iniLocation = CreateIniLocation(_configName + IniExtension, false); - try { - SaveInternally(iniLocation); - } catch (Exception ex) { - Log.Error("A problem occured while writing the configuration file to: " + iniLocation); - Log.Error(ex); - } - } else { - // Code to deal with the fact that the lock was not acquired. - Log.Warn("A second thread tried to save the ini-file, we blocked as the first took too long."); - } - } finally { - if (acquiredLock) { - Monitor.Exit(IniLock); - } - } - } - - /// - /// The real save implementation - /// - /// - private static void SaveInternally(string iniLocation) { - Log.Info("Saving configuration to: " + iniLocation); - var iniPath = Path.GetDirectoryName(iniLocation); - if (iniPath != null && !Directory.Exists(iniPath)) - { - Directory.CreateDirectory(iniPath); - } - - using var memoryStream = new MemoryStream(); - using TextWriter writer = new StreamWriter(memoryStream, Encoding.UTF8); - foreach (var section in SectionMap.Values) { - section.Write(writer, false); - // Add empty line after section - writer.WriteLine(); - section.IsDirty = false; - } - writer.WriteLine(); - // Write left over properties - foreach (string sectionName in _sections.Keys) { - // Check if the section is one that is "registered", if so skip it! - if (SectionMap.ContainsKey(sectionName)) - { - continue; - } - writer.WriteLine("; The section {0} hasn't been 'claimed' since the last start of Greenshot, therefor it doesn't have additional information here!", sectionName); - writer.WriteLine("; The reason could be that the section {0} just hasn't been used, a plugin has an error and can't claim it or maybe the whole section {0} is obsolete.", sectionName); - // Write section name - writer.WriteLine("[{0}]", sectionName); - var properties = _sections[sectionName]; - // Loop and write properties - foreach (string propertyName in properties.Keys) { - writer.WriteLine("{0}={1}", propertyName, properties[propertyName]); - } - writer.WriteLine(); - } - // Don't forget to flush the buffer - writer.Flush(); - // Now write the created .ini string to the real file - using FileStream fileStream = new FileStream(iniLocation, FileMode.Create, FileAccess.Write); - memoryStream.WriteTo(fileStream); - } - } -} diff --git a/GreenshotPlugin/IniFile/IniSection.cs b/GreenshotPlugin/IniFile/IniSection.cs deleted file mode 100644 index c8c9221dd..000000000 --- a/GreenshotPlugin/IniFile/IniSection.cs +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using GreenshotPlugin.Core; -using log4net; - -namespace GreenshotPlugin.IniFile { - /// - /// Base class for all IniSections - /// - [Serializable] - public abstract class IniSection { - protected static ILog LOG = LogManager.GetLogger(typeof(IniSection)); - - [NonSerialized] - private readonly IDictionary values = new Dictionary(); - [NonSerialized] - private IniSectionAttribute iniSectionAttribute; - public IniSectionAttribute IniSectionAttribute { - get { - if (iniSectionAttribute == null) { - iniSectionAttribute = GetIniSectionAttribute(GetType()); - } - return iniSectionAttribute; - } - } - - /// - /// Get the dictionary with all the IniValues - /// - public IDictionary Values { - get { - return values; - } - } - - /// - /// Flag to specify if values have been changed - /// - public bool IsDirty { - get; - set; - } - - /// - /// Supply values we can't put as defaults - /// - /// The property to return a default for - /// object with the default value for the supplied property - public virtual object GetDefault(string property) { - return null; - } - - /// - /// This method will be called before converting the property, making to possible to correct a certain value - /// Can be used when migration is needed - /// - /// The name of the property - /// The string value of the property - /// string with the propertyValue, modified or not... - public virtual string PreCheckValue(string propertyName, string propertyValue) { - return propertyValue; - } - - /// - /// This method will be called after reading the configuration, so eventually some corrections can be made - /// - public virtual void AfterLoad() { - } - - /// - /// This will be called before saving the Section, so we can encrypt passwords etc... - /// - public virtual void BeforeSave() { - } - - /// - /// This will be called before saving the Section, so we can decrypt passwords etc... - /// - public virtual void AfterSave() { - } - - /// - /// Helper method to get the IniSectionAttribute of a type - /// - /// - /// - public static IniSectionAttribute GetIniSectionAttribute(Type iniSectionType) { - Attribute[] classAttributes = Attribute.GetCustomAttributes(iniSectionType); - foreach (Attribute attribute in classAttributes) { - if (attribute is IniSectionAttribute) { - return (IniSectionAttribute)attribute; - } - } - return null; - } - - /// - /// Fill the section with the supplied properties - /// - /// - public void Fill(IDictionary properties) { - Type iniSectionType = GetType(); - - // Iterate over the members and create IniValueContainers - foreach (FieldInfo fieldInfo in iniSectionType.GetFields()) { - if (Attribute.IsDefined(fieldInfo, typeof(IniPropertyAttribute))) { - IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute)fieldInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; - if (!Values.ContainsKey(iniPropertyAttribute.Name)) { - Values.Add(iniPropertyAttribute.Name, new IniValue(this, fieldInfo, iniPropertyAttribute)); - } - } - } - - foreach (PropertyInfo propertyInfo in iniSectionType.GetProperties()) { - if (Attribute.IsDefined(propertyInfo, typeof(IniPropertyAttribute))) { - if (!Values.ContainsKey(propertyInfo.Name)) { - IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute)propertyInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; - Values.Add(iniPropertyAttribute.Name, new IniValue(this, propertyInfo, iniPropertyAttribute)); - } - } - } - - foreach (string fieldName in Values.Keys) { - IniValue iniValue = Values[fieldName]; - try { - iniValue.SetValueFromProperties(properties); - if (iniValue.Attributes.Encrypted) { - if (iniValue.Value is string stringValue && stringValue.Length > 2) { - iniValue.Value = stringValue.Decrypt(); - } - } - } catch (Exception ex) { - LOG.Error(ex); - } - } - AfterLoad(); - } - - /// - /// Write the section to the writer - /// - /// - /// - public void Write(TextWriter writer, bool onlyProperties) { - if (IniSectionAttribute == null) { - throw new ArgumentException("Section didn't implement the IniSectionAttribute"); - } - BeforeSave(); - try { - - if (!onlyProperties) { - writer.WriteLine("; {0}", IniSectionAttribute.Description); - } - writer.WriteLine("[{0}]", IniSectionAttribute.Name); - - foreach (IniValue value in Values.Values) { - if (value.Attributes.Encrypted) { - if (value.Value is string stringValue && stringValue.Length > 2) { - value.Value = stringValue.Encrypt(); - } - } - // Write the value - value.Write(writer, onlyProperties); - if (value.Attributes.Encrypted) { - if (value.Value is string stringValue && stringValue.Length > 2) { - value.Value = stringValue.Decrypt(); - } - } - } - } finally { - AfterSave(); - } - } - } -} diff --git a/GreenshotPlugin/IniFile/IniValue.cs b/GreenshotPlugin/IniFile/IniValue.cs deleted file mode 100644 index de04c0b44..000000000 --- a/GreenshotPlugin/IniFile/IniValue.cs +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Reflection; -using System.Text; -using log4net; - -namespace GreenshotPlugin.IniFile { - /// - /// A container to be able to pass the value from a IniSection around. - /// - public class IniValue { - private static readonly ILog Log = LogManager.GetLogger(typeof(IniValue)); - private readonly PropertyInfo _propertyInfo; - private readonly FieldInfo _fieldInfo; - private readonly IniSection _containingIniSection; - private readonly IniPropertyAttribute _attributes; - - public IniValue(IniSection containingIniSection, PropertyInfo propertyInfo, IniPropertyAttribute iniPropertyAttribute) { - _containingIniSection = containingIniSection; - _propertyInfo = propertyInfo; - _attributes = iniPropertyAttribute; - } - - public IniValue(IniSection containingIniSection, FieldInfo fieldInfo, IniPropertyAttribute iniPropertyAttribute) { - _containingIniSection = containingIniSection; - _fieldInfo = fieldInfo; - _attributes = iniPropertyAttribute; - } - - /// - /// Return true when the value is fixed - /// - public bool IsFixed { - get { - if (_attributes != null) { - return _attributes.FixedValue; - } - return false; - } - set { - if (_attributes != null) { - _attributes.FixedValue = value; - } - } - } - - /// - /// Return true when the value is for experts - /// - public bool IsExpert { - get { - if (_attributes != null) { - return _attributes.Expert; - } - return false; - } - set { - if (_attributes != null) { - _attributes.Expert = value; - } - } - } - - - /// - /// Return true when the value is can be changed by the GUI - /// - public bool IsEditable => !IsFixed; - - /// - /// Return true when the value is visible in the GUI - /// - public bool IsVisible => !IsExpert; - - public MemberInfo MemberInfo { - get - { - if (_propertyInfo == null) { - return _fieldInfo; - } - return _propertyInfo; - } - } - - /// - /// Returns the IniSection this value is contained in - /// - public IniSection ContainingIniSection => _containingIniSection; - - /// - /// Get the in the ini file defined attributes - /// - public IniPropertyAttribute Attributes => _attributes; - - /// - /// Get the value for this IniValue - /// - public object Value { - get - { - if (_propertyInfo == null) { - return _fieldInfo.GetValue(_containingIniSection); - } - return _propertyInfo.GetValue(_containingIniSection, null); - } - set { - if (_propertyInfo == null) { - _fieldInfo.SetValue(_containingIniSection, value); - } else { - _propertyInfo.SetValue(_containingIniSection, value, null); - } - } - } - - /// - /// Get the Type of the value - /// - public Type ValueType { - get { - var valueType = _propertyInfo?.PropertyType ?? _fieldInfo.FieldType; - if (!valueType.IsGenericType) - { - return valueType; - } - var genericTypeDefinition = valueType.GetGenericTypeDefinition(); - if (genericTypeDefinition != null && genericTypeDefinition == typeof(Nullable<>)) - { - // We are dealing with a generic type that is nullable - valueType = Nullable.GetUnderlyingType(valueType); - } - return valueType; - } - } - - /// - /// Write the value to the text writer - /// - /// TextWriter to write to - /// true if we do not want the comment - public void Write(TextWriter writer, bool onlyProperties) { - object myValue = Value; - Type valueType = ValueType; - if (myValue == null) { - if (_attributes.ExcludeIfNull) { - return; - } - if (_attributes.DefaultValue != null) { - myValue = _attributes.DefaultValue; - valueType = typeof(string); - } else { - myValue = _containingIniSection.GetDefault(_attributes.Name); - if (myValue != null) { - valueType = myValue.GetType(); - } - } - } - if (myValue == null) { - if (_attributes.ExcludeIfNull) { - return; - } - } - if (!onlyProperties) { - writer.WriteLine("; {0}", _attributes.Description); - } - if (myValue == null) { - writer.WriteLine("{0}=", _attributes.Name); - return; - } - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { - // Handle dictionaries. - Type valueType1 = valueType.GetGenericArguments()[0]; - Type valueType2 = valueType.GetGenericArguments()[1]; - // Get the methods we need to deal with dictionaries. - var keys = valueType.GetProperty("Keys").GetValue(myValue, null); - var item = valueType.GetProperty("Item"); - var enumerator = keys.GetType().GetMethod("GetEnumerator").Invoke(keys, null); - var moveNext = enumerator.GetType().GetMethod("MoveNext"); - var current = enumerator.GetType().GetProperty("Current").GetGetMethod(); - // Get all the values. - while ((bool)moveNext.Invoke(enumerator, null)) { - var key = current.Invoke(enumerator, null); - var valueObject = item.GetValue(myValue, new[] { key }); - // Write to ini file! - writer.WriteLine("{0}.{1}={2}", _attributes.Name, ConvertValueToString(valueType1, key, _attributes.Separator), ConvertValueToString(valueType2, valueObject, _attributes.Separator)); - } - } else { - writer.WriteLine("{0}={1}", _attributes.Name, ConvertValueToString(valueType, myValue, _attributes.Separator)); - } - } - - /// - /// Set the value to the value in the ini file, or default - /// - /// - public void SetValueFromProperties(IDictionary properties) { - string propertyName = _attributes.Name; - string propertyValue = null; - if (properties.ContainsKey(propertyName) && properties[propertyName] != null) { - propertyValue = _containingIniSection.PreCheckValue(propertyName, properties[propertyName]); - } - UseValueOrDefault(propertyValue); - } - - /// - /// This method will set the ini value to the supplied value or use the default if non supplied - /// - /// - public void UseValueOrDefault(string propertyValue) { - Type valueType = ValueType; - string propertyName = _attributes.Name; - string defaultValue = _attributes.DefaultValue; - bool defaultUsed = false; - object defaultValueFromConfig = _containingIniSection.GetDefault(propertyName); - - if (string.IsNullOrEmpty(propertyValue)) { - if (defaultValue != null && defaultValue.Trim().Length != 0) { - propertyValue = defaultValue; - defaultUsed = true; - } else if (defaultValueFromConfig != null) { - Log.DebugFormat("Default for Property {0} implemented!", propertyName); - } else { - if (_attributes.ExcludeIfNull) { - Value = null; - return; - } - Log.DebugFormat("Property {0} has no value or default value!", propertyName); - } - } - // Now set the value - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) { - // Logic for Dictionary<,> - Type type1 = valueType.GetGenericArguments()[0]; - Type type2 = valueType.GetGenericArguments()[1]; - //LOG.Info(String.Format("Found Dictionary<{0},{1}>", type1.Name, type2.Name)); - object dictionary = Activator.CreateInstance(valueType); - MethodInfo addMethodInfo = valueType.GetMethod("Add"); - bool addedElements = false; - IDictionary properties = IniConfig.PropertiesForSection(_containingIniSection); - foreach (string key in properties.Keys) { - if (key != null && key.StartsWith(propertyName + ".")) { - // What "key" do we need to store it under? - string subPropertyName = key.Substring(propertyName.Length + 1); - string stringValue = properties[key]; - object newValue1 = null; - object newValue2 = null; - try { - newValue1 = ConvertStringToValueType(type1, subPropertyName, _attributes.Separator); - } catch (Exception ex) { - Log.Warn(ex); - //LOG.Error("Problem converting " + subPropertyName + " to type " + type1.FullName, e); - } - try { - newValue2 = ConvertStringToValueType(type2, stringValue, _attributes.Separator); - } catch (Exception ex) { - Log.Warn(ex); - //LOG.Error("Problem converting " + stringValue + " to type " + type2.FullName, e); - } - addMethodInfo.Invoke(dictionary, new[] { newValue1, newValue2 }); - addedElements = true; - } - } - // No need to return something that isn't filled! - if (addedElements) { - Value = dictionary; - return; - } - if (defaultValueFromConfig != null) { - Value = defaultValueFromConfig; - return; - } - } else if (!string.IsNullOrEmpty(propertyValue)) { - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>)) - { - // We are dealing with a generic type that is nullable - valueType = Nullable.GetUnderlyingType(valueType); - } - object newValue; - try { - newValue = ConvertStringToValueType(valueType, propertyValue, _attributes.Separator); - } catch (Exception ex1) { - newValue = null; - if (!defaultUsed) { - try { - Log.WarnFormat("Problem '{0}' while converting {1} to type {2} trying fallback...", ex1.Message, propertyValue, valueType.FullName); - newValue = ConvertStringToValueType(valueType, defaultValue, _attributes.Separator); - ContainingIniSection.IsDirty = true; - Log.InfoFormat("Used default value {0} for property {1}", defaultValue, propertyName); - } catch (Exception ex2) { - Log.Warn("Problem converting fallback value " + defaultValue + " to type " + valueType.FullName, ex2); - } - } else { - Log.Warn("Problem converting " + propertyValue + " to type " + valueType.FullName, ex1); - } - } - Value = newValue; - return; - } - - // If nothing is set, we can use the default value from the config (if we habe one) - if (defaultValueFromConfig != null) { - Value = defaultValueFromConfig; - return; - } - if (ValueType != typeof(string)) { - try { - Value = Activator.CreateInstance(ValueType); - } catch (Exception) { - Log.WarnFormat("Couldn't create instance of {0} for {1}, using default value.", ValueType.FullName, _attributes.Name); - Value = default(ValueType); - } - } else { - Value = default(ValueType); - } - } - - /// - /// Convert a string to a value of type "valueType" - /// - /// Type to convert tp - /// string to convert from - /// - /// Value - private static object ConvertStringToValueType(Type valueType, string valueString, string separator) { - if (valueString == null) { - return null; - } - if (valueType == typeof(string)) { - return valueString; - } - if (string.IsNullOrEmpty(valueString)) { - return null; - } - - // The following makes the enum string values a bit less restrictive - if (valueType.IsEnum) - { - string searchingEnumString = valueString.Replace("_", string.Empty).ToLowerInvariant(); - foreach (var possibleValue in Enum.GetValues(valueType)) - { - var possibleString = possibleValue.ToString().Replace("_", string.Empty).ToLowerInvariant(); - if (possibleString.Equals(searchingEnumString)) - { - return possibleValue; - } - } - } - - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) { - string arraySeparator = separator; - object list = Activator.CreateInstance(valueType); - // Logic for List<> - string[] arrayValues = valueString.Split(new[] { arraySeparator }, StringSplitOptions.None); - if (arrayValues.Length == 0) { - return list; - } - MethodInfo addMethodInfo = valueType.GetMethod("Add"); - - foreach (string arrayValue in arrayValues) { - if (!string.IsNullOrEmpty(arrayValue)) { - object newValue = null; - try { - newValue = ConvertStringToValueType(valueType.GetGenericArguments()[0], arrayValue, separator); - } catch (Exception ex) { - Log.Warn("Problem converting " + arrayValue + " to type " + valueType.FullName, ex); - } - if (newValue != null) { - addMethodInfo.Invoke(list, new[] { newValue }); - } - } - } - return list; - } - //LOG.Debug("No convertor for " + fieldType.ToString()); - if (valueType == typeof(object) && valueString.Length > 0) { - //LOG.Debug("Parsing: " + valueString); - string[] values = valueString.Split(':'); - //LOG.Debug("Type: " + values[0]); - //LOG.Debug("Value: " + values[1]); - Type fieldTypeForValue = Type.GetType(values[0], true); - //LOG.Debug("Type after GetType: " + fieldTypeForValue); - return ConvertStringToValueType(fieldTypeForValue, values[1], separator); - } - TypeConverter converter = TypeDescriptor.GetConverter(valueType); - return converter.ConvertFromInvariantString(valueString); - } - - /// - /// Override of ToString which calls the ConvertValueToString - /// - /// string representation of this - public override string ToString() { - return ConvertValueToString(ValueType, Value, _attributes.Separator); - } - - /// - /// Convert the supplied value to a string - /// - /// Type to convert - /// Value to convert - /// separator for lists - /// string representation of the value - private static string ConvertValueToString(Type valueType, object valueObject, string separator) { - if (valueObject == null) { - // If there is nothing, deliver nothing! - return string.Empty; - } - - if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) { - StringBuilder stringBuilder = new StringBuilder(); - Type specificValueType = valueType.GetGenericArguments()[0]; - int listCount = (int)valueType.GetProperty("Count").GetValue(valueObject, null); - // Loop though generic list - for (int index = 0; index < listCount; index++) { - object item = valueType.GetMethod("get_Item").Invoke(valueObject, new object[] { index }); - - // Now you have an instance of the item in the generic list - if (index < listCount - 1) { - stringBuilder.AppendFormat("{0}{1}", ConvertValueToString(specificValueType, item, separator), separator); - } else { - stringBuilder.AppendFormat("{0}", ConvertValueToString(specificValueType, item, separator)); - } - } - return stringBuilder.ToString(); - } - if (valueType == typeof(object)) { - // object to String, this is the hardest - // Format will be "FQTypename[,Assemblyname]:Value" - - // Get the type so we can call ourselves recursive - Type objectType = valueObject.GetType(); - - // Get the value as string - string ourValue = ConvertValueToString(objectType, valueObject, separator); - - // Get the valuetype as string - string valueTypeName = objectType.FullName; - // Find the assembly name and only append it if it's not already in the fqtypename (like System.Drawing) - string assemblyName = objectType.Assembly.FullName; - // correct assemblyName, this also has version information etc. - if (assemblyName.StartsWith("Green")) { - assemblyName = assemblyName.Substring(0, assemblyName.IndexOf(',')); - } - return $"{valueTypeName},{assemblyName}:{ourValue}"; - } - TypeConverter converter = TypeDescriptor.GetConverter(valueType); - return converter.ConvertToInvariantString(valueObject); - } - } -} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs b/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs deleted file mode 100644 index db5319e2c..000000000 --- a/GreenshotPlugin/Interfaces/Drawing/Adorners/IAdorner.cs +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; - -namespace GreenshotPlugin.Interfaces.Drawing.Adorners -{ - public interface IAdorner - { - /// - /// Returns if this adorner is active - /// - bool IsActive { get; } - - /// - /// These are the bounds of the adorner - /// - Rectangle Bounds { get; } - - /// - /// The current edit status, this is needed to locate the adorner to send events to - /// - EditStatus EditStatus { get; } - - /// - /// The owner of this adorner - /// - IDrawableContainer Owner { get; } - - /// - /// Is the current point "over" the Adorner? - /// If this is the case, the - /// - /// Point to test - /// true if so - bool HitTest(Point point); - - /// - /// Handle the MouseDown event - /// - /// - /// MouseEventArgs - void MouseDown(object sender, MouseEventArgs mouseEventArgs); - - /// - /// Handle the MouseUp event - /// - /// - /// MouseEventArgs - void MouseUp(object sender, MouseEventArgs mouseEventArgs); - - /// - /// Handle the MouseMove event - /// - /// - /// MouseEventArgs - void MouseMove(object sender, MouseEventArgs mouseEventArgs); - - /// - /// Gets the cursor that should be displayed for this behavior. - /// - Cursor Cursor { get; } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - void Paint(PaintEventArgs paintEventArgs); - - /// - /// Called if the owner is transformed - /// - /// Matrix - void Transform(Matrix matrix); - - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// - void AdjustToDpi(uint dpi); - } -} diff --git a/GreenshotPlugin/Interfaces/Drawing/Container.cs b/GreenshotPlugin/Interfaces/Drawing/Container.cs deleted file mode 100644 index 7b999565a..000000000 --- a/GreenshotPlugin/Interfaces/Drawing/Container.cs +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Windows.Forms; -using GreenshotPlugin.Interfaces.Drawing.Adorners; - -namespace GreenshotPlugin.Interfaces.Drawing -{ - public enum RenderMode { EDIT, EXPORT }; - public enum EditStatus { UNDRAWN, DRAWING, MOVING, RESIZING, IDLE }; - - public interface IDrawableContainer : INotifyPropertyChanged, IDisposable - { - ISurface Parent - { - get; - set; - } - bool Selected - { - get; - set; - } - - int Left - { - get; - set; - } - - int Top - { - get; - set; - } - - int Width - { - get; - set; - } - - int Height - { - get; - set; - } - - Point Location - { - get; - } - - Size Size - { - get; - } - - Rectangle Bounds - { - get; - } - - Rectangle DrawingBounds - { - get; - } - - void ApplyBounds(RectangleF newBounds); - - bool hasFilters - { - get; - } - - EditStatus Status - { - get; - set; - } - void Invalidate(); - bool ClickableAt(int x, int y); - void MoveBy(int x, int y); - void Transform(Matrix matrix); - bool HandleMouseDown(int x, int y); - void HandleMouseUp(int x, int y); - bool HandleMouseMove(int x, int y); - bool InitContent(); - void MakeBoundsChangeUndoable(bool allowMerge); - EditStatus DefaultEditMode - { - get; - } - - /// - /// Available adorners for the DrawableContainer - /// - IList Adorners { get; } - - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// uint - void AdjustToDpi(uint dpi); - } - - public interface IDrawableContainerList : IList, IDisposable - { - Guid ParentID - { - get; - } - - bool Selected - { - get; - set; - } - - ISurface Parent - { - get; - set; - } - EditStatus Status - { - get; - set; - } - Rectangle DrawingBounds - { - get; - } - void MakeBoundsChangeUndoable(bool allowMerge); - void Transform(Matrix matrix); - void MoveBy(int dx, int dy); - bool ClickableAt(int x, int y); - IDrawableContainer ClickableElementAt(int x, int y); - void OnDoubleClick(); - bool HasIntersectingFilters(Rectangle clipRectangle); - bool IntersectsWith(Rectangle clipRectangle); - void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle); - void Invalidate(); - void PullElementsToTop(IDrawableContainerList elements); - bool CanPushDown(IDrawableContainerList elements); - void PullElementsUp(IDrawableContainerList elements); - bool CanPullUp(IDrawableContainerList elements); - void PushElementsDown(IDrawableContainerList elements); - void PushElementsToBottom(IDrawableContainerList elements); - void ShowContextMenu(MouseEventArgs e, ISurface surface); - void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e); - void AdjustToDpi(uint dpi); - } - - public interface ITextContainer : IDrawableContainer - { - string Text - { - get; - set; - } - void FitToText(); - } - - public interface IImageContainer : IDrawableContainer - { - Image Image - { - get; - set; - } - void Load(string filename); - } - public interface ICursorContainer : IDrawableContainer - { - Cursor Cursor - { - get; - set; - } - void Load(string filename); - } - public interface IIconContainer : IDrawableContainer - { - Icon Icon - { - get; - set; - } - void Load(string filename); - } -} diff --git a/GreenshotPlugin/Interfaces/ICaptureDetails.cs b/GreenshotPlugin/Interfaces/ICaptureDetails.cs deleted file mode 100644 index c475283da..000000000 --- a/GreenshotPlugin/Interfaces/ICaptureDetails.cs +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using GreenshotPlugin.Interfaces.Ocr; - -namespace GreenshotPlugin.Interfaces { - /// - /// Details for the capture, like the window title and date/time etc. - /// - public interface ICaptureDetails { - - /// - /// If the capture comes from a file, this contains the filename - /// - string Filename { - get; - set; - } - - /// - /// The title of the capture - /// - string Title { - get; - set; - } - - /// - /// When was the capture taken (or loaded) - /// - DateTime DateTime { - get; - set; - } - - /// - /// Destinations to where this capture goes or went - /// - List CaptureDestinations { - get; - set; - } - - /// - /// The meta data of the capture - /// - Dictionary MetaData { - get; - } - - /// - /// Helper method to prevent complex code which needs to check every key - /// - /// The key for the meta-data - /// The value for the meta-data - void AddMetaData(string key, string value); - - void ClearDestinations(); - void RemoveDestination(IDestination captureDestination); - void AddDestination(IDestination captureDestination); - bool HasDestination(string designation); - - CaptureMode CaptureMode { - get; - set; - } - - float DpiX { - get; - set; - } - - float DpiY { - get; - set; - } - - /// - /// Store the OCR information for this capture - /// - OcrInformation OcrInformation { get; set; } - } -} diff --git a/GreenshotPlugin/Interfaces/IDestination.cs b/GreenshotPlugin/Interfaces/IDestination.cs deleted file mode 100644 index 8bfb72ac3..000000000 --- a/GreenshotPlugin/Interfaces/IDestination.cs +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Windows.Forms; - -namespace GreenshotPlugin.Interfaces { - public class ExportInformation { - public ExportInformation(string destinationDesignation, string destinationDescription) { - DestinationDesignation = destinationDesignation; - DestinationDescription = destinationDescription; - } - public ExportInformation(string destinationDesignation, string destinationDescription, bool exportMade): this(destinationDesignation, destinationDescription) { - ExportMade = exportMade; - } - - public string DestinationDesignation { get; } - - public string DestinationDescription { get; set; } - - /// - /// Set to true to specify if the export worked. - /// - public bool ExportMade { get; set; } - - public string Uri { get; set; } - - public string ErrorMessage { get; set; } - - public string Filepath { get; set; } - } - - /// - /// Description of IDestination. - /// - public interface IDestination : IDisposable, IComparable { - /// - /// Simple "designation" like "File", "Editor" etc, used to store the configuration - /// - string Designation { - get; - } - - /// - /// Description which will be shown in the settings form, destination picker etc - /// - string Description { - get; - } - - /// - /// Priority, used for sorting - /// - int Priority { - get; - } - - /// - /// Gets an icon for the destination - /// - Image DisplayIcon { - get; - } - - /// - /// Returns if the destination is active - /// - bool IsActive { - get; - } - - /// - /// Return a menu item - /// - /// Resolve the dynamic destinations too? - /// The menu for which the item is created - /// Handler which is called when clicked - /// ToolStripMenuItem - ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler); - - /// - /// Gets the ShortcutKeys for the Editor - /// - Keys EditorShortcutKeys { - get; - } - - /// - /// Gets the dynamic destinations - /// - IEnumerable DynamicDestinations(); - - /// - /// Returns true if this destination can be dynamic - /// - bool IsDynamic { - get; - } - - /// - /// Returns if the destination is active - /// - bool UseDynamicsOnly { - get; - } - - /// - /// Returns true if this destination returns a link - /// - bool IsLinkable { - get; - } - - /// - /// If a capture is made, and the destination is enabled, this method is called. - /// - /// true if the user selected this destination from a GUI, false if it was called as part of a process - /// - /// - /// DestinationExportInformation with information, like if the destination has "exported" the capture - ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); - } -} diff --git a/GreenshotPlugin/Interfaces/IProcessor.cs b/GreenshotPlugin/Interfaces/IProcessor.cs deleted file mode 100644 index d5f4c0ba8..000000000 --- a/GreenshotPlugin/Interfaces/IProcessor.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.Interfaces { - /// - /// Description of IProcessor. - /// - public interface IProcessor : IDisposable, IComparable { - /// - /// Simple "designation" like "FixTitle" - /// - string Designation { - get; - } - - /// - /// Description which will be shown in the settings form, destination picker etc - /// - string Description { - get; - } - - /// - /// Priority, used for sorting - /// - int Priority { - get; - } - - /// - /// Returns if the destination is active - /// - bool isActive { - get; - } - - /// - /// If a capture is made, and the destination is enabled, this method is called. - /// - /// - /// - /// true if the processor has "processed" the capture - bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); - } -} diff --git a/GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs b/GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs deleted file mode 100644 index 2db074f62..000000000 --- a/GreenshotPlugin/Interfaces/Plugin/HotKeyHandler.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace GreenshotPlugin.Interfaces.Plugin -{ - public delegate void HotKeyHandler(); -} \ No newline at end of file diff --git a/GreenshotPlugin/Interop/Base.cs b/GreenshotPlugin/Interop/Base.cs deleted file mode 100644 index ec821a6ef..000000000 --- a/GreenshotPlugin/Interop/Base.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace GreenshotPlugin.Interop { - /// - /// Common properties that has appreared in almost all objects - /// - public interface ICommon : IDisposable { - } -} diff --git a/GreenshotPlugin/Interop/COMWrapper.cs b/GreenshotPlugin/Interop/COMWrapper.cs deleted file mode 100644 index c96033de3..000000000 --- a/GreenshotPlugin/Interop/COMWrapper.cs +++ /dev/null @@ -1,498 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.Remoting; -using System.Runtime.Remoting.Messaging; -using System.Runtime.Remoting.Proxies; -using System.Windows.Forms; -using GreenshotPlugin.Core; -using log4net; - -namespace GreenshotPlugin.Interop { - /// - /// Wraps a late-bound COM server. - /// - public sealed class COMWrapper : RealProxy, IDisposable, IRemotingTypeInfo { - private static readonly ILog Log = LogManager.GetLogger(typeof(COMWrapper)); - public const int RPC_E_CALL_REJECTED = unchecked((int)0x80010001); - public const int RPC_E_FAIL = unchecked((int)0x80004005); - - /// - /// Holds reference to the actual COM object which is wrapped by this proxy - /// - private readonly object _comObject; - - /// - /// Type of the COM object, set on constructor after getting the COM reference - /// - private readonly Type _comType; - - /// - /// The type of which method calls are intercepted and executed on the COM object. - /// - private readonly Type _interceptType; - - /// - /// The humanly readable target name - /// - private readonly string _targetName; - - /// - /// A simple create instance, doesn't create a wrapper!! - /// - /// T - public static T CreateInstance() { - Type type = typeof(T); - if (null == type) { - throw new ArgumentNullException(nameof(T)); - } - if (!type.IsInterface) { - throw new ArgumentException("The specified type must be an interface.", nameof(T)); - } - - ComProgIdAttribute progIdAttribute = ComProgIdAttribute.GetAttribute(type); - if (string.IsNullOrEmpty(progIdAttribute?.Value)) { - throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T)); - } - string progId = progIdAttribute.Value; - Type comType = null; - if (progId.StartsWith("clsid:")) { - Guid guid = new Guid(progId.Substring(6)); - try { - comType = Type.GetTypeFromCLSID(guid); - } catch (Exception ex) { - Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); - } - } else { - try { - comType = Type.GetTypeFromProgID(progId, true); - } catch (Exception ex) { - Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); - } - } - object comObject = null; - if (comType != null) { - try { - comObject = Activator.CreateInstance(comType); - if (comObject != null) { - Log.DebugFormat("Created new instance of {0} object.", progId); - } - } catch (Exception e) { - Log.WarnFormat("Error {1} creating object for {0}", progId, e.Message); - throw; - } - } - if (comObject != null) { - return (T)comObject; - } - return default; - } - - /// - /// Wrap an object and return the transparent proxy which intercepts all calls to the object - /// - /// An object to intercept - /// Interface which defines the method and properties to intercept - /// - /// Transparent proxy to the real proxy for the object - private static object Wrap(object comObject, Type type, string targetName) { - if (null == comObject) { - throw new ArgumentNullException(nameof(comObject)); - } - if (null == type) { - throw new ArgumentNullException(nameof(type)); - } - - COMWrapper wrapper = new COMWrapper(comObject, type, targetName); - return wrapper.GetTransparentProxy(); - } - - /// - /// Constructor - /// - /// - /// The COM object to wrap. - /// - /// - /// The interface type to impersonate. - /// - /// - private COMWrapper(object comObject, Type type, string targetName) : base(type) { - _comObject = comObject; - _comType = comObject.GetType(); - _interceptType = type; - _targetName = targetName; - } - - /// - /// If is not called, we need to make - /// sure that the COM object is still cleaned up. - /// - ~COMWrapper() { - Log.DebugFormat("Finalize {0}", _interceptType); - Dispose(false); - } - - /// - /// Cleans up the COM object. - /// - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Release the COM reference - /// - /// - /// if this was called from the - /// interface. - /// - private void Dispose(bool disposing) { - if (null != _comObject) { - Log.DebugFormat("Disposing {0}", _interceptType); - if (Marshal.IsComObject(_comObject)) { - try { - int count; - do { - count = Marshal.ReleaseComObject(_comObject); - Log.DebugFormat("RCW count for {0} now is {1}", _interceptType, count); - } while (count > 0); - } catch (Exception ex) { - Log.WarnFormat("Problem releasing COM object {0}", _comType); - Log.Warn("Error: ", ex); - } - } else { - Log.WarnFormat("{0} is not a COM object", _comType); - } - } - } - - /// - /// Returns a string representing the wrapped object. - /// - /// - /// The full name of the intercepted type. - /// - public override string ToString() { - return _interceptType.FullName; - } - - /// - /// Returns the hash code of the wrapped object. - /// - /// - /// The hash code of the wrapped object. - /// - public override int GetHashCode() { - return _comObject.GetHashCode(); - } - - /// - /// Compares this object to another. - /// - /// - /// The value to compare to. - /// - /// - /// if the objects are equal. - /// - public override bool Equals(object value) { - if (null != value && RemotingServices.IsTransparentProxy(value)) { - COMWrapper wrapper = RemotingServices.GetRealProxy(value) as COMWrapper; - if (null != wrapper) { - return _comObject == wrapper._comObject; - } - } - - return base.Equals(value); - } - - /// - /// Returns the base type for a reference type. - /// - /// - /// The reference type. - /// - /// - /// The base value type. - /// - /// - /// is . - /// - private static Type GetByValType(Type byRefType) { - if (null == byRefType) { - throw new ArgumentNullException(nameof(byRefType)); - } - - if (byRefType.IsByRef) { - string name = byRefType.FullName; - name = name.Substring(0, name.Length - 1); - byRefType = byRefType.Assembly.GetType(name, true); - } - - return byRefType; - } - - /// - /// Intercept method calls - /// - /// - /// Contains information about the method being called - /// - /// - /// A . - /// - public override IMessage Invoke(IMessage myMessage) { - if (!(myMessage is IMethodCallMessage callMessage)) { - Log.DebugFormat("Message type not implemented: {0}", myMessage.GetType()); - return null; - } - - MethodInfo method = callMessage.MethodBase as MethodInfo; - if (null == method) { - Log.DebugFormat("Unrecognized Invoke call: {0}", callMessage.MethodBase); - return null; - } - - object returnValue = null; - object[] outArgs = null; - int outArgsCount = 0; - - string methodName = method.Name; - Type returnType = method.ReturnType; - BindingFlags flags = BindingFlags.InvokeMethod; - int argCount = callMessage.ArgCount; - - ParameterModifier[] argModifiers = null; - ParameterInfo[] parameters = null; - - if ("Dispose" == methodName && 0 == argCount && typeof(void) == returnType) { - Dispose(); - } else if ("ToString" == methodName && 0 == argCount && typeof(string) == returnType) { - returnValue = ToString(); - } else if ("GetType" == methodName && 0 == argCount && typeof(Type) == returnType) { - returnValue = _interceptType; - } else if ("GetHashCode" == methodName && 0 == argCount && typeof(int) == returnType) { - returnValue = GetHashCode(); - } else if ("Equals" == methodName && 1 == argCount && typeof(bool) == returnType) { - returnValue = Equals(callMessage.Args[0]); - } else if (1 == argCount && typeof(void) == returnType && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) { - bool removeHandler = methodName.StartsWith("remove_"); - methodName = methodName.Substring(removeHandler ? 7 : 4); - // TODO: Something is missing here - if (!(callMessage.InArgs[0] is Delegate handler)) { - return new ReturnMessage(new ArgumentNullException(nameof(handler)), callMessage); - } - } else { - var invokeObject = _comObject; - var invokeType = _comType; - - object[] args; - ParameterInfo parameter; - if (methodName.StartsWith("get_")) { - // Property Get - methodName = methodName.Substring(4); - flags = BindingFlags.GetProperty; - args = callMessage.InArgs; - } else if (methodName.StartsWith("set_")) { - // Property Set - methodName = methodName.Substring(4); - flags = BindingFlags.SetProperty; - args = callMessage.InArgs; - } else { - args = callMessage.Args; - if (null != args && 0 != args.Length) { - // Modifiers for ref / out parameters - argModifiers = new ParameterModifier[1]; - argModifiers[0] = new ParameterModifier(args.Length); - - parameters = method.GetParameters(); - for (int i = 0; i < parameters.Length; i++) { - parameter = parameters[i]; - if (parameter.IsOut || parameter.ParameterType.IsByRef) { - argModifiers[0][i] = true; - outArgsCount++; - } - } - - if (0 == outArgsCount) { - argModifiers = null; - } - } - } - - // Un-wrap wrapped COM objects before passing to the method - Type byValType; - COMWrapper wrapper; - COMWrapper[] originalArgs; - if (null == args || 0 == args.Length) { - originalArgs = null; - } else { - originalArgs = new COMWrapper[args.Length]; - for (int i = 0; i < args.Length; i++) { - if (null != args[i] && RemotingServices.IsTransparentProxy(args[i])) { - wrapper = RemotingServices.GetRealProxy(args[i]) as COMWrapper; - if (null != wrapper) { - originalArgs[i] = wrapper; - args[i] = wrapper._comObject; - } - } else if (0 != outArgsCount && argModifiers[0][i]) { - byValType = GetByValType(parameters[i].ParameterType); - if (byValType.IsInterface) { - // If we're passing a COM object by reference, and - // the parameter is null, we need to pass a - // DispatchWrapper to avoid a type mismatch exception. - if (null == args[i]) { - args[i] = new DispatchWrapper(null); - } - } else if (typeof(decimal) == byValType) { - // If we're passing a decimal value by reference, - // we need to pass a CurrencyWrapper to avoid a - // type mismatch exception. - // http://support.microsoft.com/?kbid=837378 - args[i] = new CurrencyWrapper(args[i]); - } - } - } - } - - do { - try { - returnValue = invokeType.InvokeMember(methodName, flags, null, invokeObject, args, argModifiers, null, null); - break; - } catch (InvalidComObjectException icoEx) { - // Should assist BUG-1616 and others - Log.WarnFormat("COM object {0} has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.", _interceptType.FullName); - return new ReturnMessage(icoEx, callMessage); - } catch (Exception ex) { - // Test for rejected - if (!(ex is COMException comEx)) { - comEx = ex.InnerException as COMException; - } - if (comEx != null && (comEx.ErrorCode == RPC_E_CALL_REJECTED || comEx.ErrorCode == RPC_E_FAIL)) { - string destinationName = _targetName; - // Try to find a "catchy" name for the rejecting application - if (destinationName != null && destinationName.Contains(".")) { - destinationName = destinationName.Substring(0, destinationName.IndexOf(".", StringComparison.Ordinal)); - } - if (destinationName == null) { - destinationName = _interceptType.FullName; - } - - var form = SimpleServiceProvider.Current.GetInstance(); - - DialogResult result = MessageBox.Show(form, Language.GetFormattedString("com_rejected", destinationName), Language.GetString("com_rejected_title"), MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation); - if (result == DialogResult.OK) { - continue; - } - } - // Not rejected OR pressed cancel - return new ReturnMessage(ex, callMessage); - } - } while (true); - - // Handle enum and interface return types - if (null != returnValue) { - if (returnType.IsInterface) { - // Wrap the returned value in an intercepting COM wrapper - if (Marshal.IsComObject(returnValue)) { - returnValue = Wrap(returnValue, returnType, _targetName); - } - } else if (returnType.IsEnum) { - // Convert to proper Enum type - returnValue = Enum.Parse(returnType, returnValue.ToString()); - } - } - - // Handle out args - if (0 != outArgsCount) { - outArgs = new object[args.Length]; - for (int i = 0; i < parameters.Length; i++) { - if (!argModifiers[0][i]) { - continue; - } - - var arg = args[i]; - if (null == arg) { - continue; - } - - parameter = parameters[i]; - wrapper = null; - - byValType = GetByValType(parameter.ParameterType); - if (typeof(decimal) == byValType) { - if (arg is CurrencyWrapper) { - arg = ((CurrencyWrapper)arg).WrappedObject; - } - } else if (byValType.IsEnum) { - arg = Enum.Parse(byValType, arg.ToString()); - } else if (byValType.IsInterface) { - if (Marshal.IsComObject(arg)) { - wrapper = originalArgs[i]; - if (null != wrapper && wrapper._comObject != arg) { - wrapper.Dispose(); - wrapper = null; - } - - if (null == wrapper) { - wrapper = new COMWrapper(arg, byValType, _targetName); - } - arg = wrapper.GetTransparentProxy(); - } - } - outArgs[i] = arg; - } - } - } - - return new ReturnMessage(returnValue, outArgs, outArgsCount, callMessage.LogicalCallContext, callMessage); - } - - /// - /// Implementation for the interface IRemotingTypeInfo - /// This makes it possible to cast the COMWrapper - /// - /// Type to cast to - /// object to cast - /// - public bool CanCastTo(Type toType, object o) { - bool returnValue = _interceptType.IsAssignableFrom(toType); - return returnValue; - } - - /// - /// Implementation for the interface IRemotingTypeInfo - /// - public string TypeName { - get { - throw new NotSupportedException(); - } - set { - throw new NotSupportedException(); - } - } - } -} diff --git a/GreenshotPlugin/Interop/ComProgIdAttribute.cs b/GreenshotPlugin/Interop/ComProgIdAttribute.cs deleted file mode 100644 index ed88fa7be..000000000 --- a/GreenshotPlugin/Interop/ComProgIdAttribute.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.Interop { - /// - /// An attribute to specifiy the ProgID of the COM class to create. (As suggested by Kristen Wegner) - /// - [AttributeUsage(AttributeTargets.Interface)] - public sealed class ComProgIdAttribute : Attribute { - /// - /// Extracts the attribute from the specified type. - /// - /// - /// The interface type. - /// - /// - /// The . - /// - /// - /// is . - /// - public static ComProgIdAttribute GetAttribute(Type interfaceType) { - if (null == interfaceType) { - throw new ArgumentNullException(nameof(interfaceType)); - } - - Type attributeType = typeof(ComProgIdAttribute); - object[] attributes = interfaceType.GetCustomAttributes(attributeType, false); - - if (0 == attributes.Length) - { - Type[] interfaces = interfaceType.GetInterfaces(); - foreach (Type t in interfaces) - { - interfaceType = t; - attributes = interfaceType.GetCustomAttributes(attributeType, false); - if (0 != attributes.Length) { - break; - } - } - } - - if (0 == attributes.Length) { - return null; - } - return (ComProgIdAttribute)attributes[0]; - } - - /// Constructor - /// The COM ProgID. - public ComProgIdAttribute(string value) { - Value = value; - } - - /// - /// Returns the COM ProgID - /// - public string Value { get; } - } -} diff --git a/GreenshotPlugin/UnmanagedHelpers/DWM.cs b/GreenshotPlugin/UnmanagedHelpers/DWM.cs deleted file mode 100644 index eed7c71e5..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/DWM.cs +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.Enums; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; -using Microsoft.Win32; - -namespace GreenshotPlugin.UnmanagedHelpers { - - /// - /// Desktop Window Manager helper code - /// - public static class DWM { - - // DWM - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb); - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmUnregisterThumbnail(IntPtr thumb); - [DllImport("dwmapi", SetLastError = true)] - public static extern HResult DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size); - [DllImport("dwmapi", SetLastError = true)] - public static extern HResult DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); - - // Deprecated as of Windows 8 Release Preview - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmIsCompositionEnabled(out bool enabled); - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT lpRect, int size); - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool pvAttribute, int cbAttribute); - - // Key to ColorizationColor for DWM - private const string COLORIZATION_COLOR_KEY = @"SOFTWARE\Microsoft\Windows\DWM"; - - /// - /// Checks if the window is cloaked, this should solve some issues with the window selection code - /// - /// IntPtr as hWmd - /// bool - public static bool IsWindowCloaked(IntPtr hWnd) - { - if (!WindowsVersion.IsWindows8OrLater) - { - return false; - } - - DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAKED, out bool isCloaked, Marshal.SizeOf(typeof(bool))); - return isCloaked; - } - - /// - /// Helper method for an easy DWM check - /// - /// bool true if DWM is available AND active - public static bool IsDwmEnabled { - get - { - // According to: http://technet.microsoft.com/en-us/subscriptions/aa969538%28v=vs.85%29.aspx - // And: http://msdn.microsoft.com/en-us/library/windows/desktop/aa969510%28v=vs.85%29.aspx - // DMW is always enabled on Windows 8! So return true and save a check! ;-) - if (WindowsVersion.IsWindows8OrLater) - { - return true; - } - if (WindowsVersion.IsWindowsVistaOrLater) - { - DwmIsCompositionEnabled(out var dwmEnabled); - return dwmEnabled; - } - return false; - } - } - - public static Color ColorizationColor { - get { - using (RegistryKey key = Registry.CurrentUser.OpenSubKey(COLORIZATION_COLOR_KEY, false)) { - object dwordValue = key?.GetValue("ColorizationColor"); - if (dwordValue != null) { - return Color.FromArgb((int)dwordValue); - } - } - return Color.White; - } - } - } -} diff --git a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs b/GreenshotPlugin/UnmanagedHelpers/GDI32.cs deleted file mode 100644 index 0138d9faa..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/GDI32.cs +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Security; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using Microsoft.Win32.SafeHandles; - -namespace GreenshotPlugin.UnmanagedHelpers { - public static class GDIExtensions { - /// - /// Check if all the corners of the rectangle are visible in the specified region. - /// Not a perfect check, but this currently a workaround for checking if a window is completely visible - /// - /// - /// - /// - public static bool AreRectangleCornersVisisble(this Region region, Rectangle rectangle) { - Point topLeft = new Point(rectangle.X, rectangle.Y); - Point topRight = new Point(rectangle.X + rectangle.Width, rectangle.Y); - Point bottomLeft = new Point(rectangle.X, rectangle.Y + rectangle.Height); - Point bottomRight = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height); - bool topLeftVisible = region.IsVisible(topLeft); - bool topRightVisible = region.IsVisible(topRight); - bool bottomLeftVisible = region.IsVisible(bottomLeft); - bool bottomRightVisible = region.IsVisible(bottomRight); - - return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible; - } - - /// - /// Get a SafeHandle for the GetHdc, so one can use using to automatically cleanup the devicecontext - /// - /// - /// SafeDeviceContextHandle - public static SafeDeviceContextHandle GetSafeDeviceContext(this Graphics graphics) { - return SafeDeviceContextHandle.FromGraphics(graphics); - } - } - - /// - /// Abstract class SafeObjectHandle which contains all handles that are cleaned with DeleteObject - /// - public abstract class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid { - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); - - protected SafeObjectHandle(bool ownsHandle) : base(ownsHandle) { - } - - protected override bool ReleaseHandle() { - return DeleteObject(handle); - } - } - - /// - /// A hbitmap SafeHandle implementation - /// - public class SafeHBitmapHandle : SafeObjectHandle { - - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeHBitmapHandle() : base(true) - { - - } - - [SecurityCritical] - public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) { - SetHandle(preexistingHandle); - } - } - - /// - /// A hRegion SafeHandle implementation - /// - public class SafeRegionHandle : SafeObjectHandle { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeRegionHandle() : base(true) - { - } - - [SecurityCritical] - public SafeRegionHandle(IntPtr preexistingHandle) : base(true) { - SetHandle(preexistingHandle); - } - } - - /// - /// A dibsection SafeHandle implementation - /// - public class SafeDibSectionHandle : SafeObjectHandle { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeDibSectionHandle() : base(true) - { - } - - [SecurityCritical] - public SafeDibSectionHandle(IntPtr preexistingHandle) : base(true) { - SetHandle(preexistingHandle); - } - } - - /// - /// A select object safehandle implementation - /// This impl will select the passed SafeHandle to the HDC and replace the returned value when disposing - /// - public class SafeSelectObjectHandle : SafeHandleZeroOrMinusOneIsInvalid { - [DllImport("gdi32", SetLastError = true)] - private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); - - private readonly SafeHandle _hdc; - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeSelectObjectHandle() : base(true) - { - } - - [SecurityCritical] - public SafeSelectObjectHandle(SafeDCHandle hdc, SafeHandle newHandle) : base(true) { - _hdc = hdc; - SetHandle(SelectObject(hdc.DangerousGetHandle(), newHandle.DangerousGetHandle())); - } - - protected override bool ReleaseHandle() { - SelectObject(_hdc.DangerousGetHandle(), handle); - return true; - } - } - - public abstract class SafeDCHandle : SafeHandleZeroOrMinusOneIsInvalid { - protected SafeDCHandle(bool ownsHandle) : base(ownsHandle) { - } - } - /// - /// A CompatibleDC SafeHandle implementation - /// - public class SafeCompatibleDCHandle : SafeDCHandle { - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteDC(IntPtr hDC); - - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeCompatibleDCHandle() : base(true) - { - } - - [SecurityCritical] - public SafeCompatibleDCHandle(IntPtr preexistingHandle) : base(true) { - SetHandle(preexistingHandle); - } - - public SafeSelectObjectHandle SelectObject(SafeHandle newHandle) { - return new SafeSelectObjectHandle(this, newHandle); - } - - protected override bool ReleaseHandle() { - return DeleteDC(handle); - } - } - - /// - /// A DeviceContext SafeHandle implementation - /// - public class SafeDeviceContextHandle : SafeDCHandle { - private readonly Graphics _graphics; - - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeDeviceContextHandle() : base(true) - { - } - - [SecurityCritical] - public SafeDeviceContextHandle(Graphics graphics, IntPtr preexistingHandle) : base(true) { - _graphics = graphics; - SetHandle(preexistingHandle); - } - - protected override bool ReleaseHandle() { - _graphics.ReleaseHdc(handle); - return true; - } - - public static SafeDeviceContextHandle FromGraphics(Graphics graphics) { - return new SafeDeviceContextHandle(graphics, graphics.GetHdc()); - } - } - - /// - /// GDI32 Helpers - /// - public static class GDI32 { - [DllImport("gdi32", SetLastError=true)] - public static extern bool BitBlt(SafeHandle hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, SafeHandle hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop); - - [DllImport("gdi32", SetLastError=true)] - public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC); - - [DllImport("gdi32", SetLastError=true)] - public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADER bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset); - [DllImport("gdi32", SetLastError=true)] - public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); - [DllImport("gdi32", SetLastError=true)] - public static extern uint GetPixel(SafeHandle hdc, int nXPos, int nYPos); - [DllImport("gdi32", SetLastError=true)] - public static extern int GetDeviceCaps(SafeHandle hdc, DeviceCaps nIndex); - } - - [StructLayout(LayoutKind.Sequential, Pack = 2)] - public struct BITMAPFILEHEADER { - public static readonly short BM = 0x4d42; // BM - public short bfType; - public int bfSize; - public short bfReserved1; - public short bfReserved2; - public int bfOffBits; - } - - [StructLayout(LayoutKind.Sequential)] - public struct BitfieldColorMask { - public uint blue; - public uint green; - public uint red; - public void InitValues() { - red = (uint)255 << 8; - green = (uint)255 << 16; - blue = (uint)255 << 24; - } - } - - [StructLayout(LayoutKind.Sequential)] - public struct CIEXYZ { - public uint ciexyzX; //FXPT2DOT30 - public uint ciexyzY; //FXPT2DOT30 - public uint ciexyzZ; //FXPT2DOT30 - public CIEXYZ(uint FXPT2DOT30) { - ciexyzX = FXPT2DOT30; - ciexyzY = FXPT2DOT30; - ciexyzZ = FXPT2DOT30; - } - } - - [StructLayout(LayoutKind.Sequential)] - public struct CIEXYZTRIPLE { - public CIEXYZ ciexyzRed; - public CIEXYZ ciexyzGreen; - public CIEXYZ ciexyzBlue; - } - - public enum BI_COMPRESSION : uint { - BI_RGB = 0, // Uncompressed - BI_RLE8 = 1, // RLE 8BPP - BI_RLE4 = 2, // RLE 4BPP - BI_BITFIELDS = 3, // Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bpp bitmaps. - BI_JPEG = 4, // Indicates that the image is a JPEG image. - BI_PNG = 5 // Indicates that the image is a PNG image. - } - - [StructLayout(LayoutKind.Explicit)] - public struct BITMAPINFOHEADER { - [FieldOffset(0)] - public uint biSize; - [FieldOffset(4)] - public int biWidth; - [FieldOffset(8)] - public int biHeight; - [FieldOffset(12)] - public ushort biPlanes; - [FieldOffset(14)] - public ushort biBitCount; - [FieldOffset(16)] - public BI_COMPRESSION biCompression; - [FieldOffset(20)] - public uint biSizeImage; - [FieldOffset(24)] - public int biXPelsPerMeter; - [FieldOffset(28)] - public int biYPelsPerMeter; - [FieldOffset(32)] - public uint biClrUsed; - [FieldOffset(36)] - public uint biClrImportant; - [FieldOffset(40)] - public uint bV5RedMask; - [FieldOffset(44)] - public uint bV5GreenMask; - [FieldOffset(48)] - public uint bV5BlueMask; - [FieldOffset(52)] - public uint bV5AlphaMask; - [FieldOffset(56)] - public uint bV5CSType; - [FieldOffset(60)] - public CIEXYZTRIPLE bV5Endpoints; - [FieldOffset(96)] - public uint bV5GammaRed; - [FieldOffset(100)] - public uint bV5GammaGreen; - [FieldOffset(104)] - public uint bV5GammaBlue; - [FieldOffset(108)] - public uint bV5Intent; // Rendering intent for bitmap - [FieldOffset(112)] - public uint bV5ProfileData; - [FieldOffset(116)] - public uint bV5ProfileSize; - [FieldOffset(120)] - public uint bV5Reserved; - - public const int DIB_RGB_COLORS = 0; - - public BITMAPINFOHEADER(int width, int height, ushort bpp) { - biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV5 is 40 bytes - biPlanes = 1; // Should allways be 1 - biCompression = BI_COMPRESSION.BI_RGB; - biWidth = width; - biHeight = height; - biBitCount = bpp; - biSizeImage = (uint)(width*height*(bpp>>3)); - biXPelsPerMeter = 0; - biYPelsPerMeter = 0; - biClrUsed = 0; - biClrImportant = 0; - - // V5 - bV5RedMask = (uint)255 << 16; - bV5GreenMask = (uint)255 << 8; - bV5BlueMask = 255; - bV5AlphaMask = (uint)255 << 24; - bV5CSType = 0x73524742; // LCS_sRGB - bV5Endpoints = new CIEXYZTRIPLE - { - ciexyzBlue = new CIEXYZ(0), - ciexyzGreen = new CIEXYZ(0), - ciexyzRed = new CIEXYZ(0) - }; - bV5GammaRed = 0; - bV5GammaGreen = 0; - bV5GammaBlue = 0; - bV5Intent = 4; - bV5ProfileData = 0; - bV5ProfileSize = 0; - bV5Reserved = 0; - } - public bool IsDibV5 { - get { - uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); - return biSize >= sizeOfBMI; - } - } - public uint OffsetToPixels { - get { - if (biCompression == BI_COMPRESSION.BI_BITFIELDS) { - // Add 3x4 bytes for the bitfield color mask - return biSize + 3 * 4; - } - return biSize; - } - } - } -} diff --git a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs b/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs deleted file mode 100644 index c8caf7700..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/GDIplus.cs +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using log4net; -using System.Reflection; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace GreenshotPlugin.UnmanagedHelpers { - /// - /// Contains members that specify the nature of a Gaussian blur. - /// - /// Cannot be pinned with GCHandle due to bool value. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct BlurParams { - /// - /// Real number that specifies the blur radius (the radius of the Gaussian convolution kernel) in - /// pixels. The radius must be in the range 0 through 255. As the radius increases, the resulting - /// bitmap becomes more blurry. - /// - public float Radius; - - /// - /// Boolean value that specifies whether the bitmap expands by an amount equal to the blur radius. - /// If TRUE, the bitmap expands by an amount equal to the radius so that it can have soft edges. - /// If FALSE, the bitmap remains the same size and the soft edges are clipped. - /// - public bool ExpandEdges; - } - - /// - /// GDI Plus unit description. - /// - public enum GpUnit { - /// - /// World coordinate (non-physical unit). - /// - UnitWorld, - - /// - /// Variable - for PageTransform only. - /// - UnitDisplay, - - /// - /// Each unit is one device pixel. - /// - UnitPixel, - - /// - /// Each unit is a printer's point, or 1/72 inch. - /// - UnitPoint, - - /// - /// Each unit is 1 inch. - /// - UnitInch, - - /// - /// Each unit is 1/300 inch. - /// - UnitDocument, - - /// - /// Each unit is 1 millimeter. - /// - UnitMillimeter - } - - /// - /// GDIplus Helpers - /// - public static class GDIplus { - private static readonly ILog Log = LogManager.GetLogger(typeof(GDIplus)); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipBitmapApplyEffect(IntPtr bitmap, IntPtr effect, ref RECT rectOfInterest, bool useAuxData, IntPtr auxData, int auxDataSize); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipDrawImageFX(IntPtr graphics, IntPtr bitmap, ref RECTF source, IntPtr matrix, IntPtr effect, IntPtr imageAttributes, GpUnit srcUnit); - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipSetEffectParameters(IntPtr effect, IntPtr parameters, uint size); - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipCreateEffect(Guid guid, out IntPtr effect); - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipDeleteEffect(IntPtr effect); - private static readonly Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}"); - - // Constant "FieldInfo" for getting the nativeImage from the Bitmap - private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGE = typeof(Bitmap).GetField("nativeImage", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - // Constant "FieldInfo" for getting the NativeGraphics from the Graphics - private static readonly FieldInfo FIELD_INFO_NATIVE_GRAPHICS = typeof(Graphics).GetField("nativeGraphics", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - // Constant "FieldInfo" for getting the nativeMatrix from the Matrix - private static readonly FieldInfo FIELD_INFO_NATIVE_MATRIX = typeof(Matrix).GetField("nativeMatrix", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - // Constant "FieldInfo" for getting the nativeImageAttributes from the ImageAttributes - private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGEATTRIBUTES = typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - - private static bool _isBlurEnabled = Environment.OSVersion.Version.Major >= 6; - /// - /// Get the nativeImage field from the bitmap - /// - /// - /// IntPtr - private static IntPtr GetNativeImage(Bitmap bitmap) { - if (bitmap == null) { - return IntPtr.Zero; - } - return (IntPtr)FIELD_INFO_NATIVE_IMAGE.GetValue(bitmap); - } - - /// - /// Get the NativeGraphics field from the graphics - /// - /// - /// IntPtr - private static IntPtr GetNativeGraphics(Graphics graphics) { - if (graphics == null) { - return IntPtr.Zero; - } - return (IntPtr)FIELD_INFO_NATIVE_GRAPHICS.GetValue(graphics); - } - - /// - /// Get the nativeMatrix field from the matrix - /// - /// - /// IntPtr - private static IntPtr GetNativeMatrix(Matrix matrix) { - if (matrix == null) { - return IntPtr.Zero; - } - return (IntPtr)FIELD_INFO_NATIVE_MATRIX.GetValue(matrix); - } - - /// - /// Get the nativeImageAttributes field from the ImageAttributes - /// - /// - /// IntPtr - private static IntPtr GetNativeImageAttributes(ImageAttributes imageAttributes) { - if (imageAttributes == null) { - return IntPtr.Zero; - } - return (IntPtr)FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes); - } - - /// - /// Returns if a GDIPlus blur can be made for the supplied radius. - /// This accounts for the "bug" I reported here: http://social.technet.microsoft.com/Forums/en/w8itprogeneral/thread/99ddbe9d-556d-475a-8bab-84e25aa13a2c - /// - /// - /// false if blur is not possible - public static bool IsBlurPossible(int radius) - { - if (!_isBlurEnabled) { - return false; - } - if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2) - { - return true; - } - return Environment.OSVersion.Version.Major > 6 && radius >= 20; - } - - /// - /// Use the GDI+ blur effect on the bitmap - /// - /// Bitmap to apply the effect to - /// Rectangle to apply the blur effect to - /// 0-255 - /// bool true if the edges are expanded with the radius - /// false if there is no GDI+ available or an exception occured - public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, int radius, bool expandEdges) { - if (!IsBlurPossible(radius)) { - return false; - } - IntPtr hBlurParams = IntPtr.Zero; - IntPtr hEffect = IntPtr.Zero; - - try { - // Create the GDI+ BlurEffect, using the Guid - int status = GdipCreateEffect(BlurEffectGuid, out hEffect); - if (status != 0) - { - return false; - } - // Create a BlurParams struct and set the values - var blurParams = new BlurParams - { - Radius = radius, - ExpandEdges = expandEdges - }; - - // Allocate space in unmanaged memory - hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); - // Copy the structure to the unmanaged memory - Marshal.StructureToPtr(blurParams, hBlurParams, false); - - - // Set the blurParams to the effect - GdipSetEffectParameters(hEffect, hBlurParams, (uint)Marshal.SizeOf(blurParams)); - - // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! - // Get the private nativeImage property from the Bitmap - IntPtr hBitmap = GetNativeImage(destinationBitmap); - - // Create a RECT from the Rectangle - RECT rec = new RECT(area); - // Apply the effect to the bitmap in the specified area - GdipBitmapApplyEffect(hBitmap, hEffect, ref rec, false, IntPtr.Zero, 0); - - // Everything worked, return true - return true; - } catch (Exception ex) { - _isBlurEnabled = false; - Log.Error("Problem using GdipBitmapApplyEffect: ", ex); - return false; - } finally { - try { - if (hEffect != IntPtr.Zero) { - // Delete the effect - GdipDeleteEffect(hEffect); - } - if (hBlurParams != IntPtr.Zero) { - // Free the memory - Marshal.FreeHGlobal(hBlurParams); - } - } catch (Exception ex) { - _isBlurEnabled = false; - Log.Error("Problem cleaning up ApplyBlur: ", ex); - } - } - } - - /// - /// Draw the image on the graphics with GDI+ blur effect - /// - /// false if there is no GDI+ available or an exception occured - public static bool DrawWithBlur(Graphics graphics, Bitmap image, Rectangle source, Matrix transform, ImageAttributes imageAttributes, int radius, bool expandEdges) { - if (!IsBlurPossible(radius)) { - return false; - } - - IntPtr hBlurParams = IntPtr.Zero; - IntPtr hEffect = IntPtr.Zero; - - try { - // Create the GDI+ BlurEffect, using the Guid - int status = GdipCreateEffect(BlurEffectGuid, out hEffect); - if (status != 0) - { - return false; - } - - // Create a BlurParams struct and set the values - var blurParams = new BlurParams - { - Radius = radius, - ExpandEdges = false - }; - //blurParams.Padding = radius; - - // Allocate space in unmanaged memory - hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); - // Copy the structure to the unmanaged memory - Marshal.StructureToPtr(blurParams, hBlurParams, true); - - // Set the blurParams to the effect - GdipSetEffectParameters(hEffect, hBlurParams, (uint)Marshal.SizeOf(blurParams)); - - // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! - // Get the private nativeImage property from the Bitmap - IntPtr hBitmap = GetNativeImage(image); - IntPtr hGraphics = GetNativeGraphics(graphics); - IntPtr hMatrix = GetNativeMatrix(transform); - IntPtr hAttributes = GetNativeImageAttributes(imageAttributes); - - // Create a RECT from the Rectangle - RECTF sourceRecf = new RECTF(source); - // Apply the effect to the bitmap in the specified area - GdipDrawImageFX(hGraphics, hBitmap, ref sourceRecf, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel); - - // Everything worked, return true - return true; - } catch (Exception ex) { - _isBlurEnabled = false; - Log.Error("Problem using GdipDrawImageFX: ", ex); - return false; - } finally { - try { - if (hEffect != IntPtr.Zero) { - // Delete the effect - GdipDeleteEffect(hEffect); - } - if (hBlurParams != IntPtr.Zero) { - // Free the memory - Marshal.FreeHGlobal(hBlurParams); - } - } catch (Exception ex) { - _isBlurEnabled = false; - Log.Error("Problem cleaning up DrawWithBlur: ", ex); - } - } - } - - } -} diff --git a/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs b/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs deleted file mode 100644 index 101d74bbf..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/Kernel32.cs +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Runtime.InteropServices; -using System.Text; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.UnmanagedHelpers { - /// - /// Description of Kernel32. - /// - public class Kernel32 { - public const uint ATTACHCONSOLE_ATTACHPARENTPROCESS = 0x0ffffffff; // default value if not specifing a process ID - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool AttachConsole(uint dwProcessId); - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool AllocConsole(); - - [DllImport("kernel32", SetLastError = true)] - public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); - [DllImport("kernel32", SetLastError = true)] - public static extern uint SuspendThread(IntPtr hThread); - [DllImport("kernel32", SetLastError = true)] - public static extern int ResumeThread(IntPtr hThread); - [DllImport("kernel32", SetLastError = true)] - public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId); - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize); - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, uint uuchMax); - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CloseHandle(IntPtr hObject); - - /// - /// Method to get the process path - /// - /// - /// - public static string GetProcessPath(int processid) { - StringBuilder _PathBuffer = new StringBuilder(512); - // Try the GetModuleFileName method first since it's the fastest. - // May return ACCESS_DENIED (due to VM_READ flag) if the process is not owned by the current user. - // Will fail if we are compiled as x86 and we're trying to open a 64 bit process...not allowed. - IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead, false, processid); - if (hprocess != IntPtr.Zero) { - try { - if (PsAPI.GetModuleFileNameEx(hprocess, IntPtr.Zero, _PathBuffer, (uint)_PathBuffer.Capacity) > 0) { - return _PathBuffer.ToString(); - } - } finally { - CloseHandle(hprocess); - } - } - - hprocess = OpenProcess(ProcessAccessFlags.QueryInformation, false, processid); - if (hprocess != IntPtr.Zero) { - try { - // Try this method for Vista or higher operating systems - uint size = (uint)_PathBuffer.Capacity; - if ((Environment.OSVersion.Version.Major >= 6) && (QueryFullProcessImageName(hprocess, 0, _PathBuffer, ref size) && (size > 0))) { - return _PathBuffer.ToString(); - } - - // Try the GetProcessImageFileName method - if (PsAPI.GetProcessImageFileName(hprocess, _PathBuffer, (uint)_PathBuffer.Capacity) > 0) { - string dospath = _PathBuffer.ToString(); - foreach (string drive in Environment.GetLogicalDrives()) { - if (QueryDosDevice(drive.TrimEnd('\\'), _PathBuffer, (uint)_PathBuffer.Capacity) > 0) { - if (dospath.StartsWith(_PathBuffer.ToString())) { - return drive + dospath.Remove(0, _PathBuffer.Length); - } - } - } - } - } finally { - CloseHandle(hprocess); - } - } - - return string.Empty; - } - } -} diff --git a/GreenshotPlugin/UnmanagedHelpers/Shell32.cs b/GreenshotPlugin/UnmanagedHelpers/Shell32.cs deleted file mode 100644 index f16d46cec..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/Shell32.cs +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using System.IO; - -namespace GreenshotPlugin.UnmanagedHelpers { - /// - /// Description of Shell32. - /// - public static class Shell32 { - [DllImport("shell32", CharSet = CharSet.Unicode)] - public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons); - - [DllImport("shell32", CharSet = CharSet.Unicode)] - private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); - - [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] - private struct SHFILEINFO { - public readonly IntPtr hIcon; - public readonly int iIcon; - public readonly uint dwAttributes; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public readonly string szDisplayName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] - public readonly string szTypeName; - }; - - // Browsing for directory. - - private const uint SHGFI_ICON = 0x000000100; // get icon - private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon - private const uint SHGFI_LARGEICON = 0x000000000; // get large icon - private const uint SHGFI_SMALLICON = 0x000000001; // get small icon - private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute - private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; - - /// - /// Options to specify the size of icons to return. - /// - public enum IconSize { - /// - /// Specify large icon - 32 pixels by 32 pixels. - /// - Large = 0, - /// - /// Specify small icon - 16 pixels by 16 pixels. - /// - Small = 1 - } - - /// - /// Returns an icon for a given file extension - indicated by the name parameter. - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx - /// - /// Filename - /// Large or small - /// Whether to include the link icon - /// System.Drawing.Icon - public static Icon GetFileIcon(string filename, IconSize size, bool linkOverlay) { - SHFILEINFO shfi = new SHFILEINFO(); - // SHGFI_USEFILEATTRIBUTES makes it simulate, just gets the icon for the extension - uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; - - if (linkOverlay) { - flags += SHGFI_LINKOVERLAY; - } - - // Check the size specified for return. - if (IconSize.Small == size) { - flags += SHGFI_SMALLICON; - } else { - flags += SHGFI_LARGEICON; - } - - SHGetFileInfo(Path.GetFileName(filename), FILE_ATTRIBUTE_NORMAL, ref shfi, (uint)Marshal.SizeOf(shfi), flags); - - // Only return an icon if we really got one - if (shfi.hIcon != IntPtr.Zero) { - // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly - Icon icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone(); - // Cleanup - User32.DestroyIcon(shfi.hIcon); - return icon; - } - return null; - } - } -} diff --git a/GreenshotPlugin/UnmanagedHelpers/User32.cs b/GreenshotPlugin/UnmanagedHelpers/User32.cs deleted file mode 100644 index 784b7d129..000000000 --- a/GreenshotPlugin/UnmanagedHelpers/User32.cs +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Text; -using System.Windows.Forms; -using log4net; -using GreenshotPlugin.Core.Enums; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace GreenshotPlugin.UnmanagedHelpers { - /// - /// User32 Wrappers - /// - public static class User32 { - private static readonly ILog LOG = LogManager.GetLogger(typeof(User32)); - private static bool _CanCallGetPhysicalCursorPos = true; - public const int SC_RESTORE = 0xF120; - public const int SC_MAXIMIZE = 0xF030; - public const int SC_MINIMIZE = 0xF020; - - // For MonitorFromWindow - public const int MONITOR_DEFAULTTONULL = 0; - public const int MONITOR_DEFAULTTONEAREST = 2; - public const int CURSOR_SHOWING = 0x00000001; - - /// - /// Determines whether the specified window handle identifies an existing window. - /// - /// A handle to the window to be tested. - /// - /// If the window handle identifies an existing window, the return value is true. - /// If the window handle does not identify an existing window, the return value is false. - /// - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindow(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindowVisible(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId); - [DllImport("user32", SetLastError = true)] - public static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId); - [DllImport("user32")] - public static extern IntPtr AttachThreadInput(int idAttach, int idAttachTo, int fAttach); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetParent(IntPtr hWnd); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int cch); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool BringWindowToTop(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetForegroundWindow(); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetDesktopWindow(); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetForegroundWindow(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WindowPlacement lpwndpl); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsIconic(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsZoomed(IntPtr hWnd); - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetClassName (IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); - [DllImport("user32", SetLastError = true)] - public static extern uint GetClassLong(IntPtr hWnd, int nIndex); - [DllImport("user32", SetLastError = true, EntryPoint = "GetClassLongPtr")] - public static extern IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, uint nFlags); - [DllImport("user32", CharSet=CharSet.Unicode, SetLastError=true)] - public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")] - public static extern int GetWindowLong(IntPtr hWnd, int index); - [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")] - public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int SetWindowLong(IntPtr hWnd, int index, int styleFlags); - [DllImport("user32", SetLastError = true, EntryPoint = "SetWindowLongPtr")] - public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int index, IntPtr styleFlags); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr MonitorFromWindow(IntPtr hWnd, MonitorFrom dwFlags); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowInfo(IntPtr hWnd, ref WindowInfo pwi); - - [DllImport("user32", SetLastError = true)] - public static extern int EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); - - [DllImport("user32", SetLastError = true)] - public static extern RegionResult GetWindowRgn(IntPtr hWnd, SafeHandle hRgn); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, WindowPos uFlags); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetClipboardOwner(); - - // Added for finding Metro apps, Greenshot 1.1 - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow); - - /// uiFlags: 0 - Count of GDI objects - /// uiFlags: 1 - Count of USER objects - /// - Win32 GDI objects (pens, brushes, fonts, palettes, regions, device contexts, bitmap headers) - /// - Win32 USER objects: - /// - WIN32 resources (accelerator tables, bitmap resources, dialog box templates, font resources, menu resources, raw data resources, string table entries, message table entries, cursors/icons) - /// - Other USER objects (windows, menus) - /// - [DllImport("user32", SetLastError = true)] - public static extern uint GetGuiResources(IntPtr hProcess, uint uiFlags); - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint RegisterWindowMessage(string lpString); - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult); - [DllImport("user32", SetLastError = true)] - private static extern bool GetPhysicalCursorPos(out POINT cursorLocation); - - /// - /// The following is used for Icon handling - /// - /// - /// - [DllImport("user32", SetLastError = true)] - public static extern SafeIconHandle CopyIcon(IntPtr hIcon); - [DllImport("user32", SetLastError = true)] - public static extern bool DestroyIcon(IntPtr hIcon); - [DllImport("user32", SetLastError = true)] - public static extern bool GetCursorInfo(out CursorInfo cursorInfo); - [DllImport("user32", SetLastError = true)] - public static extern bool GetIconInfo(SafeIconHandle iconHandle, out IconInfo iconInfo); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr SetCapture(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool ReleaseCapture(); - [DllImport("user32", SetLastError = true)] - public static extern IntPtr CreateIconIndirect(ref IconInfo icon); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, DesktopAccessRight dwDesiredAccess); - [DllImport("user32", SetLastError = true)] - public static extern bool SetThreadDesktop(IntPtr hDesktop); - [DllImport("user32", SetLastError = true)] - public static extern bool CloseDesktop(IntPtr hDesktop); - - /// - /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. - /// - /// Point with cursor location, relative to the origin of the monitor setup - /// (i.e. negative coordinates arepossible in multiscreen setups) - public static Point GetCursorLocation() { - if (Environment.OSVersion.Version.Major >= 6 && _CanCallGetPhysicalCursorPos) { - try { - if (GetPhysicalCursorPos(out var cursorLocation)) { - return new Point(cursorLocation.X, cursorLocation.Y); - } - - Win32Error error = Win32.GetLastErrorCode(); - LOG.ErrorFormat("Error retrieving PhysicalCursorPos : {0}", Win32.GetMessage(error)); - } catch (Exception ex) { - LOG.Error("Exception retrieving PhysicalCursorPos, no longer calling this. Cause :", ex); - _CanCallGetPhysicalCursorPos = false; - } - } - return new Point(Cursor.Position.X, Cursor.Position.Y); - } - - /// - /// Wrapper for the GetClassLong which decides if the system is 64-bit or not and calls the right one. - /// - /// IntPtr - /// int - /// IntPtr - public static IntPtr GetClassLongWrapper(IntPtr hWnd, int nIndex) { - if (IntPtr.Size > 4) { - return GetClassLongPtr(hWnd, nIndex); - } else { - return new IntPtr(GetClassLong(hWnd, nIndex)); - } - } - - /// - /// Wrapper for the GetWindowLong which decides if the system is 64-bit or not and calls the right one. - /// - /// - /// - /// - public static long GetWindowLongWrapper(IntPtr hWnd, int nIndex) { - if (IntPtr.Size == 8) { - return GetWindowLongPtr(hWnd, nIndex).ToInt64(); - } else { - return GetWindowLong(hWnd, nIndex); - } - } - - /// - /// Wrapper for the SetWindowLong which decides if the system is 64-bit or not and calls the right one. - /// - /// - /// - /// - public static void SetWindowLongWrapper(IntPtr hWnd, int nIndex, IntPtr styleFlags) { - if (IntPtr.Size == 8) { - SetWindowLongPtr(hWnd, nIndex, styleFlags); - } else { - SetWindowLong(hWnd, nIndex, styleFlags.ToInt32()); - } - } - - public static uint GetGuiResourcesGDICount() - { - using var currentProcess = Process.GetCurrentProcess(); - return GetGuiResources(currentProcess.Handle, 0); - } - - public static uint GetGuiResourcesUserCount() - { - using var currentProcess = Process.GetCurrentProcess(); - return GetGuiResources(currentProcess.Handle, 1); - } - - /// - /// Helper method to create a Win32 exception with the windows message in it - /// - /// string with current method - /// Exception - public static Exception CreateWin32Exception(string method) { - var exceptionToThrow = new Win32Exception(); - exceptionToThrow.Data.Add("Method", method); - return exceptionToThrow; - } - } -} diff --git a/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs b/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs deleted file mode 100644 index 3bcad532d..000000000 --- a/GreenshotWin10Plugin/Destinations/Win10OcrDestination.cs +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Threading.Tasks; -using Windows.Media.Ocr; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; - -namespace GreenshotWin10Plugin.Destinations -{ - /// - /// This uses the OcrEngine from Windows 10 to perform OCR on the captured image. - /// - public class Win10OcrDestination : AbstractDestination - { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10OcrDestination)); - - public override string Designation { get; } = "Windows10OCR"; - public override string Description { get; } = "Windows 10 OCR"; - - /// - /// Icon for the OCR function, the icon was found via: http://help4windows.com/windows_8_imageres_dll.shtml - /// - public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(FilenameHelper.FillCmdVariables(@"%windir%\system32\imageres.dll"), 97); - - /// - /// Constructor, this is only debug information - /// - public Win10OcrDestination() - { - var languages = OcrEngine.AvailableRecognizerLanguages; - foreach (var language in languages) - { - Log.DebugFormat("Found language {0} {1}", language.NativeName, language.LanguageTag); - } - } - - /// - /// Run the Windows 10 OCR engine to process the text on the captured image - /// - /// - /// - /// - /// ExportInformation - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) - { - var exportInformation = new ExportInformation(Designation, Description); - try - { - // TODO: Check if the OcrInformation is for the selected surface... otherwise discard & do it again - var ocrInformation = captureDetails.OcrInformation; - if (captureDetails.OcrInformation == null) - { - var ocrProvider = SimpleServiceProvider.Current.GetInstance(); - ocrInformation = Task.Run(async () => await ocrProvider.DoOcrAsync(surface)).Result; - } - - // Check if we found text - if (!string.IsNullOrWhiteSpace(ocrInformation.Text)) - { - // Place the OCR text on the - ClipboardHelper.SetClipboardData(ocrInformation.Text); - } - exportInformation.ExportMade = true; - } - catch (Exception ex) - { - exportInformation.ExportMade = false; - exportInformation.ErrorMessage = ex.Message; - } - - ProcessExport(exportInformation, surface); - return exportInformation; - - } - } -} diff --git a/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs b/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs deleted file mode 100644 index 2594b4338..000000000 --- a/GreenshotWin10Plugin/Native/DataTransferManagerHelper.cs +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using GreenshotPlugin.Core; -using System; -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.ApplicationModel.DataTransfer; - -namespace GreenshotWin10Plugin.Native -{ - /// - /// Wraps the interop for calling the ShareUI - /// - public class DataTransferManagerHelper - { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DataTransferManagerHelper)); - - private const string DataTransferManagerId = "a5caee9b-8708-49d1-8d36-67d25a8da00c"; - private readonly IDataTransferManagerInterOp _dataTransferManagerInterOp; - private readonly IntPtr _windowHandle; - - /// - /// The DataTransferManager - /// - public DataTransferManager DataTransferManager - { - get; - private set; - } - /// - /// Constructor which takes a handle to initialize - /// - /// - public DataTransferManagerHelper(IntPtr handle) - { - //TODO: Add a check for failure here. This will fail for versions of Windows below Windows 10 - IActivationFactory activationFactory = WindowsRuntimeMarshal.GetActivationFactory(typeof(DataTransferManager)); - - // ReSharper disable once SuspiciousTypeConversion.Global - _dataTransferManagerInterOp = (IDataTransferManagerInterOp)activationFactory; - - _windowHandle = handle; - var riid = new Guid(DataTransferManagerId); - var hresult = _dataTransferManagerInterOp.GetForWindow(_windowHandle, riid, out var dataTransferManager); - if (hresult.Failed()) - { - Log.WarnFormat("HResult for GetForWindow: {0}", hresult); - } - DataTransferManager = dataTransferManager; - } - - /// - /// Show the share UI - /// - public void ShowShareUi() - { - var hresult = _dataTransferManagerInterOp.ShowShareUIForWindow(_windowHandle); - if (hresult.Failed()) - { - Log.WarnFormat("HResult for ShowShareUIForWindow: {0}", hresult); - } - else - { - Log.Debug("ShowShareUIForWindow called"); - } - } - } - -} diff --git a/Greenshot/releases/additional_files/installer.txt b/installer/additional_files/installer.txt similarity index 100% rename from Greenshot/releases/additional_files/installer.txt rename to installer/additional_files/installer.txt diff --git a/Greenshot/releases/additional_files/license.txt b/installer/additional_files/license.txt similarity index 100% rename from Greenshot/releases/additional_files/license.txt rename to installer/additional_files/license.txt diff --git a/Greenshot/releases/additional_files/readme.txt b/installer/additional_files/readme.txt similarity index 100% rename from Greenshot/releases/additional_files/readme.txt rename to installer/additional_files/readme.txt diff --git a/Greenshot/releases/appinfo.ini.template b/installer/appinfo.ini.template similarity index 100% rename from Greenshot/releases/appinfo.ini.template rename to installer/appinfo.ini.template diff --git a/Greenshot/releases/innosetup/IssProc/IssProc.dll b/installer/innosetup/IssProc/IssProc.dll similarity index 100% rename from Greenshot/releases/innosetup/IssProc/IssProc.dll rename to installer/innosetup/IssProc/IssProc.dll diff --git a/Greenshot/releases/innosetup/IssProc/IssProcLanguage.ini b/installer/innosetup/IssProc/IssProcLanguage.ini similarity index 100% rename from Greenshot/releases/innosetup/IssProc/IssProcLanguage.ini rename to installer/innosetup/IssProc/IssProcLanguage.ini diff --git a/Greenshot/releases/innosetup/Languages/Afrikaans.isl b/installer/innosetup/Languages/Afrikaans.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Afrikaans.isl rename to installer/innosetup/Languages/Afrikaans.isl diff --git a/Greenshot/releases/innosetup/Languages/Albanian.isl b/installer/innosetup/Languages/Albanian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Albanian.isl rename to installer/innosetup/Languages/Albanian.isl diff --git a/Greenshot/releases/innosetup/Languages/Arabic.isl b/installer/innosetup/Languages/Arabic.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Arabic.isl rename to installer/innosetup/Languages/Arabic.isl diff --git a/Greenshot/releases/innosetup/Languages/Asturian.isl b/installer/innosetup/Languages/Asturian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Asturian.isl rename to installer/innosetup/Languages/Asturian.isl diff --git a/Greenshot/releases/innosetup/Languages/Basque.isl b/installer/innosetup/Languages/Basque.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Basque.isl rename to installer/innosetup/Languages/Basque.isl diff --git a/Greenshot/releases/innosetup/Languages/Belarusian.isl b/installer/innosetup/Languages/Belarusian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Belarusian.isl rename to installer/innosetup/Languages/Belarusian.isl diff --git a/Greenshot/releases/innosetup/Languages/Bengali.islu b/installer/innosetup/Languages/Bengali.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Bengali.islu rename to installer/innosetup/Languages/Bengali.islu diff --git a/Greenshot/releases/innosetup/Languages/Bosnian.isl b/installer/innosetup/Languages/Bosnian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Bosnian.isl rename to installer/innosetup/Languages/Bosnian.isl diff --git a/Greenshot/releases/innosetup/Languages/Bulgarian.isl b/installer/innosetup/Languages/Bulgarian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Bulgarian.isl rename to installer/innosetup/Languages/Bulgarian.isl diff --git a/Greenshot/releases/innosetup/Languages/ChineseSimplified.isl b/installer/innosetup/Languages/ChineseSimplified.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/ChineseSimplified.isl rename to installer/innosetup/Languages/ChineseSimplified.isl diff --git a/Greenshot/releases/innosetup/Languages/ChineseTraditional.isl b/installer/innosetup/Languages/ChineseTraditional.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/ChineseTraditional.isl rename to installer/innosetup/Languages/ChineseTraditional.isl diff --git a/Greenshot/releases/innosetup/Languages/Croatian.isl b/installer/innosetup/Languages/Croatian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Croatian.isl rename to installer/innosetup/Languages/Croatian.isl diff --git a/Greenshot/releases/innosetup/Languages/EnglishBritish.isl b/installer/innosetup/Languages/EnglishBritish.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/EnglishBritish.isl rename to installer/innosetup/Languages/EnglishBritish.isl diff --git a/Greenshot/releases/innosetup/Languages/Esperanto.isl b/installer/innosetup/Languages/Esperanto.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Esperanto.isl rename to installer/innosetup/Languages/Esperanto.isl diff --git a/Greenshot/releases/innosetup/Languages/Estonian.isl b/installer/innosetup/Languages/Estonian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Estonian.isl rename to installer/innosetup/Languages/Estonian.isl diff --git a/Greenshot/releases/innosetup/Languages/Farsi.isl b/installer/innosetup/Languages/Farsi.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Farsi.isl rename to installer/innosetup/Languages/Farsi.isl diff --git a/Greenshot/releases/innosetup/Languages/Galician.isl b/installer/innosetup/Languages/Galician.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Galician.isl rename to installer/innosetup/Languages/Galician.isl diff --git a/Greenshot/releases/innosetup/Languages/Georgian.islu b/installer/innosetup/Languages/Georgian.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Georgian.islu rename to installer/innosetup/Languages/Georgian.islu diff --git a/Greenshot/releases/innosetup/Languages/Greek.isl b/installer/innosetup/Languages/Greek.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Greek.isl rename to installer/innosetup/Languages/Greek.isl diff --git a/Greenshot/releases/innosetup/Languages/Hindi.islu b/installer/innosetup/Languages/Hindi.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Hindi.islu rename to installer/innosetup/Languages/Hindi.islu diff --git a/Greenshot/releases/innosetup/Languages/Hungarian.isl b/installer/innosetup/Languages/Hungarian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Hungarian.isl rename to installer/innosetup/Languages/Hungarian.isl diff --git a/Greenshot/releases/innosetup/Languages/Indonesian.isl b/installer/innosetup/Languages/Indonesian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Indonesian.isl rename to installer/innosetup/Languages/Indonesian.isl diff --git a/Greenshot/releases/innosetup/Languages/Kazakh.islu b/installer/innosetup/Languages/Kazakh.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Kazakh.islu rename to installer/innosetup/Languages/Kazakh.islu diff --git a/Greenshot/releases/innosetup/Languages/Korean.isl b/installer/innosetup/Languages/Korean.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Korean.isl rename to installer/innosetup/Languages/Korean.isl diff --git a/Greenshot/releases/innosetup/Languages/Kurdish.isl b/installer/innosetup/Languages/Kurdish.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Kurdish.isl rename to installer/innosetup/Languages/Kurdish.isl diff --git a/Greenshot/releases/innosetup/Languages/Latvian.isl b/installer/innosetup/Languages/Latvian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Latvian.isl rename to installer/innosetup/Languages/Latvian.isl diff --git a/Greenshot/releases/innosetup/Languages/Ligurian.isl b/installer/innosetup/Languages/Ligurian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Ligurian.isl rename to installer/innosetup/Languages/Ligurian.isl diff --git a/Greenshot/releases/innosetup/Languages/Lithuanian.isl b/installer/innosetup/Languages/Lithuanian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Lithuanian.isl rename to installer/innosetup/Languages/Lithuanian.isl diff --git a/Greenshot/releases/innosetup/Languages/Luxemburgish.isl b/installer/innosetup/Languages/Luxemburgish.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Luxemburgish.isl rename to installer/innosetup/Languages/Luxemburgish.isl diff --git a/Greenshot/releases/innosetup/Languages/Macedonian.isl b/installer/innosetup/Languages/Macedonian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Macedonian.isl rename to installer/innosetup/Languages/Macedonian.isl diff --git a/Greenshot/releases/innosetup/Languages/Malaysian.isl b/installer/innosetup/Languages/Malaysian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Malaysian.isl rename to installer/innosetup/Languages/Malaysian.isl diff --git a/Greenshot/releases/innosetup/Languages/Marathi.islu b/installer/innosetup/Languages/Marathi.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Marathi.islu rename to installer/innosetup/Languages/Marathi.islu diff --git a/Greenshot/releases/innosetup/Languages/Mongolian.isl b/installer/innosetup/Languages/Mongolian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Mongolian.isl rename to installer/innosetup/Languages/Mongolian.isl diff --git a/Greenshot/releases/innosetup/Languages/Montenegrian.isl b/installer/innosetup/Languages/Montenegrian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Montenegrian.isl rename to installer/innosetup/Languages/Montenegrian.isl diff --git a/Greenshot/releases/innosetup/Languages/Nepali.islu b/installer/innosetup/Languages/Nepali.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Nepali.islu rename to installer/innosetup/Languages/Nepali.islu diff --git a/Greenshot/releases/innosetup/Languages/NorwegianNynorsk.isl b/installer/innosetup/Languages/NorwegianNynorsk.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/NorwegianNynorsk.isl rename to installer/innosetup/Languages/NorwegianNynorsk.isl diff --git a/Greenshot/releases/innosetup/Languages/Occitan.isl b/installer/innosetup/Languages/Occitan.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Occitan.isl rename to installer/innosetup/Languages/Occitan.isl diff --git a/Greenshot/releases/innosetup/Languages/Romanian.isl b/installer/innosetup/Languages/Romanian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Romanian.isl rename to installer/innosetup/Languages/Romanian.isl diff --git a/Greenshot/releases/innosetup/Languages/ScottishGaelic.isl b/installer/innosetup/Languages/ScottishGaelic.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/ScottishGaelic.isl rename to installer/innosetup/Languages/ScottishGaelic.isl diff --git a/Greenshot/releases/innosetup/Languages/SerbianCyrillic.isl b/installer/innosetup/Languages/SerbianCyrillic.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/SerbianCyrillic.isl rename to installer/innosetup/Languages/SerbianCyrillic.isl diff --git a/Greenshot/releases/innosetup/Languages/SerbianLatin.isl b/installer/innosetup/Languages/SerbianLatin.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/SerbianLatin.isl rename to installer/innosetup/Languages/SerbianLatin.isl diff --git a/Greenshot/releases/innosetup/Languages/Sinhala.islu b/installer/innosetup/Languages/Sinhala.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Sinhala.islu rename to installer/innosetup/Languages/Sinhala.islu diff --git a/Greenshot/releases/innosetup/Languages/Swedish.isl b/installer/innosetup/Languages/Swedish.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Swedish.isl rename to installer/innosetup/Languages/Swedish.isl diff --git a/Greenshot/releases/innosetup/Languages/Tatar.isl b/installer/innosetup/Languages/Tatar.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Tatar.isl rename to installer/innosetup/Languages/Tatar.isl diff --git a/Greenshot/releases/innosetup/Languages/Thai.isl b/installer/innosetup/Languages/Thai.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Thai.isl rename to installer/innosetup/Languages/Thai.isl diff --git a/Greenshot/releases/innosetup/Languages/Uyghur.islu b/installer/innosetup/Languages/Uyghur.islu similarity index 100% rename from Greenshot/releases/innosetup/Languages/Uyghur.islu rename to installer/innosetup/Languages/Uyghur.islu diff --git a/Greenshot/releases/innosetup/Languages/Uzbek.isl b/installer/innosetup/Languages/Uzbek.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Uzbek.isl rename to installer/innosetup/Languages/Uzbek.isl diff --git a/Greenshot/releases/innosetup/Languages/Valencian.isl b/installer/innosetup/Languages/Valencian.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Valencian.isl rename to installer/innosetup/Languages/Valencian.isl diff --git a/Greenshot/releases/innosetup/Languages/Vietnamese.isl b/installer/innosetup/Languages/Vietnamese.isl similarity index 100% rename from Greenshot/releases/innosetup/Languages/Vietnamese.isl rename to installer/innosetup/Languages/Vietnamese.isl diff --git a/Greenshot/releases/innosetup/installer-large.bmp b/installer/innosetup/installer-large.bmp similarity index 100% rename from Greenshot/releases/innosetup/installer-large.bmp rename to installer/innosetup/installer-large.bmp diff --git a/Greenshot/releases/innosetup/installer-small.bmp b/installer/innosetup/installer-small.bmp similarity index 100% rename from Greenshot/releases/innosetup/installer-small.bmp rename to installer/innosetup/installer-small.bmp diff --git a/Greenshot/releases/innosetup/scripts/isxdl/chinese.ini b/installer/innosetup/scripts/isxdl/chinese.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/chinese.ini rename to installer/innosetup/scripts/isxdl/chinese.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/czech.ini b/installer/innosetup/scripts/isxdl/czech.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/czech.ini rename to installer/innosetup/scripts/isxdl/czech.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/dutch.ini b/installer/innosetup/scripts/isxdl/dutch.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/dutch.ini rename to installer/innosetup/scripts/isxdl/dutch.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/english.ini b/installer/innosetup/scripts/isxdl/english.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/english.ini rename to installer/innosetup/scripts/isxdl/english.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/french.ini b/installer/innosetup/scripts/isxdl/french.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/french.ini rename to installer/innosetup/scripts/isxdl/french.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/french2.ini b/installer/innosetup/scripts/isxdl/french2.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/french2.ini rename to installer/innosetup/scripts/isxdl/french2.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/french3.ini b/installer/innosetup/scripts/isxdl/french3.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/french3.ini rename to installer/innosetup/scripts/isxdl/french3.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/german.ini b/installer/innosetup/scripts/isxdl/german.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/german.ini rename to installer/innosetup/scripts/isxdl/german.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/isxdl.dll b/installer/innosetup/scripts/isxdl/isxdl.dll similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/isxdl.dll rename to installer/innosetup/scripts/isxdl/isxdl.dll diff --git a/Greenshot/releases/innosetup/scripts/isxdl/isxdl.iss b/installer/innosetup/scripts/isxdl/isxdl.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/isxdl.iss rename to installer/innosetup/scripts/isxdl/isxdl.iss diff --git a/Greenshot/releases/innosetup/scripts/isxdl/italian.ini b/installer/innosetup/scripts/isxdl/italian.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/italian.ini rename to installer/innosetup/scripts/isxdl/italian.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/japanese.ini b/installer/innosetup/scripts/isxdl/japanese.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/japanese.ini rename to installer/innosetup/scripts/isxdl/japanese.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/korean.ini b/installer/innosetup/scripts/isxdl/korean.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/korean.ini rename to installer/innosetup/scripts/isxdl/korean.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/norwegian.ini b/installer/innosetup/scripts/isxdl/norwegian.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/norwegian.ini rename to installer/innosetup/scripts/isxdl/norwegian.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/polish.ini b/installer/innosetup/scripts/isxdl/polish.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/polish.ini rename to installer/innosetup/scripts/isxdl/polish.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/portugues.ini b/installer/innosetup/scripts/isxdl/portugues.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/portugues.ini rename to installer/innosetup/scripts/isxdl/portugues.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/portuguese.ini b/installer/innosetup/scripts/isxdl/portuguese.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/portuguese.ini rename to installer/innosetup/scripts/isxdl/portuguese.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/russian.ini b/installer/innosetup/scripts/isxdl/russian.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/russian.ini rename to installer/innosetup/scripts/isxdl/russian.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/spanish.ini b/installer/innosetup/scripts/isxdl/spanish.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/spanish.ini rename to installer/innosetup/scripts/isxdl/spanish.ini diff --git a/Greenshot/releases/innosetup/scripts/isxdl/swedish.ini b/installer/innosetup/scripts/isxdl/swedish.ini similarity index 100% rename from Greenshot/releases/innosetup/scripts/isxdl/swedish.ini rename to installer/innosetup/scripts/isxdl/swedish.ini diff --git a/Greenshot/releases/innosetup/scripts/lang/chinese.iss b/installer/innosetup/scripts/lang/chinese.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/chinese.iss rename to installer/innosetup/scripts/lang/chinese.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/dutch.iss b/installer/innosetup/scripts/lang/dutch.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/dutch.iss rename to installer/innosetup/scripts/lang/dutch.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/english.iss b/installer/innosetup/scripts/lang/english.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/english.iss rename to installer/innosetup/scripts/lang/english.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/french.iss b/installer/innosetup/scripts/lang/french.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/french.iss rename to installer/innosetup/scripts/lang/french.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/german.iss b/installer/innosetup/scripts/lang/german.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/german.iss rename to installer/innosetup/scripts/lang/german.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/italian.iss b/installer/innosetup/scripts/lang/italian.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/italian.iss rename to installer/innosetup/scripts/lang/italian.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/japanese.iss b/installer/innosetup/scripts/lang/japanese.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/japanese.iss rename to installer/innosetup/scripts/lang/japanese.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/polish.iss b/installer/innosetup/scripts/lang/polish.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/polish.iss rename to installer/innosetup/scripts/lang/polish.iss diff --git a/Greenshot/releases/innosetup/scripts/lang/russian.iss b/installer/innosetup/scripts/lang/russian.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/lang/russian.iss rename to installer/innosetup/scripts/lang/russian.iss diff --git a/Greenshot/releases/innosetup/scripts/products.iss b/installer/innosetup/scripts/products.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products.iss rename to installer/innosetup/scripts/products.iss diff --git a/Greenshot/releases/innosetup/scripts/products.pas b/installer/innosetup/scripts/products.pas similarity index 100% rename from Greenshot/releases/innosetup/scripts/products.pas rename to installer/innosetup/scripts/products.pas diff --git a/Greenshot/releases/innosetup/scripts/products/directxruntime.iss b/installer/innosetup/scripts/products/directxruntime.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/directxruntime.iss rename to installer/innosetup/scripts/products/directxruntime.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx11.iss b/installer/innosetup/scripts/products/dotnetfx11.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx11.iss rename to installer/innosetup/scripts/products/dotnetfx11.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx11lp.iss b/installer/innosetup/scripts/products/dotnetfx11lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx11lp.iss rename to installer/innosetup/scripts/products/dotnetfx11lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx11sp1.iss b/installer/innosetup/scripts/products/dotnetfx11sp1.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx11sp1.iss rename to installer/innosetup/scripts/products/dotnetfx11sp1.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20.iss b/installer/innosetup/scripts/products/dotnetfx20.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20.iss rename to installer/innosetup/scripts/products/dotnetfx20.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20lp.iss b/installer/innosetup/scripts/products/dotnetfx20lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20lp.iss rename to installer/innosetup/scripts/products/dotnetfx20lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1.iss b/installer/innosetup/scripts/products/dotnetfx20sp1.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1.iss rename to installer/innosetup/scripts/products/dotnetfx20sp1.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1lp.iss b/installer/innosetup/scripts/products/dotnetfx20sp1lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20sp1lp.iss rename to installer/innosetup/scripts/products/dotnetfx20sp1lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2.iss b/installer/innosetup/scripts/products/dotnetfx20sp2.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2.iss rename to installer/innosetup/scripts/products/dotnetfx20sp2.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2lp.iss b/installer/innosetup/scripts/products/dotnetfx20sp2lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx20sp2lp.iss rename to installer/innosetup/scripts/products/dotnetfx20sp2lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx35.iss b/installer/innosetup/scripts/products/dotnetfx35.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx35.iss rename to installer/innosetup/scripts/products/dotnetfx35.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx35lp.iss b/installer/innosetup/scripts/products/dotnetfx35lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx35lp.iss rename to installer/innosetup/scripts/products/dotnetfx35lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1.iss b/installer/innosetup/scripts/products/dotnetfx35sp1.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1.iss rename to installer/innosetup/scripts/products/dotnetfx35sp1.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1lp.iss b/installer/innosetup/scripts/products/dotnetfx35sp1lp.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx35sp1lp.iss rename to installer/innosetup/scripts/products/dotnetfx35sp1lp.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx40client.iss b/installer/innosetup/scripts/products/dotnetfx40client.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx40client.iss rename to installer/innosetup/scripts/products/dotnetfx40client.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx40full.iss b/installer/innosetup/scripts/products/dotnetfx40full.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx40full.iss rename to installer/innosetup/scripts/products/dotnetfx40full.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx45.iss b/installer/innosetup/scripts/products/dotnetfx45.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx45.iss rename to installer/innosetup/scripts/products/dotnetfx45.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx46.iss b/installer/innosetup/scripts/products/dotnetfx46.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx46.iss rename to installer/innosetup/scripts/products/dotnetfx46.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx47.iss b/installer/innosetup/scripts/products/dotnetfx47.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx47.iss rename to installer/innosetup/scripts/products/dotnetfx47.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfx48.iss b/installer/innosetup/scripts/products/dotnetfx48.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfx48.iss rename to installer/innosetup/scripts/products/dotnetfx48.iss diff --git a/Greenshot/releases/innosetup/scripts/products/dotnetfxversion.iss b/installer/innosetup/scripts/products/dotnetfxversion.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/dotnetfxversion.iss rename to installer/innosetup/scripts/products/dotnetfxversion.iss diff --git a/Greenshot/releases/innosetup/scripts/products/fileversion.iss b/installer/innosetup/scripts/products/fileversion.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/fileversion.iss rename to installer/innosetup/scripts/products/fileversion.iss diff --git a/Greenshot/releases/innosetup/scripts/products/ie6.iss b/installer/innosetup/scripts/products/ie6.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/ie6.iss rename to installer/innosetup/scripts/products/ie6.iss diff --git a/Greenshot/releases/innosetup/scripts/products/iis.iss b/installer/innosetup/scripts/products/iis.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/iis.iss rename to installer/innosetup/scripts/products/iis.iss diff --git a/Greenshot/releases/innosetup/scripts/products/jet4sp8.iss b/installer/innosetup/scripts/products/jet4sp8.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/jet4sp8.iss rename to installer/innosetup/scripts/products/jet4sp8.iss diff --git a/Greenshot/releases/innosetup/scripts/products/kb835732.iss b/installer/innosetup/scripts/products/kb835732.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/kb835732.iss rename to installer/innosetup/scripts/products/kb835732.iss diff --git a/Greenshot/releases/innosetup/scripts/products/mdac28.iss b/installer/innosetup/scripts/products/mdac28.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/mdac28.iss rename to installer/innosetup/scripts/products/mdac28.iss diff --git a/Greenshot/releases/innosetup/scripts/products/msi20.iss b/installer/innosetup/scripts/products/msi20.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/msi20.iss rename to installer/innosetup/scripts/products/msi20.iss diff --git a/Greenshot/releases/innosetup/scripts/products/msi31.iss b/installer/innosetup/scripts/products/msi31.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/msi31.iss rename to installer/innosetup/scripts/products/msi31.iss diff --git a/Greenshot/releases/innosetup/scripts/products/msi45.iss b/installer/innosetup/scripts/products/msi45.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/msi45.iss rename to installer/innosetup/scripts/products/msi45.iss diff --git a/Greenshot/releases/innosetup/scripts/products/msiproduct.iss b/installer/innosetup/scripts/products/msiproduct.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/msiproduct.iss rename to installer/innosetup/scripts/products/msiproduct.iss diff --git a/Greenshot/releases/innosetup/scripts/products/sql2005express.iss b/installer/innosetup/scripts/products/sql2005express.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/sql2005express.iss rename to installer/innosetup/scripts/products/sql2005express.iss diff --git a/Greenshot/releases/innosetup/scripts/products/sql2008express.iss b/installer/innosetup/scripts/products/sql2008express.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/sql2008express.iss rename to installer/innosetup/scripts/products/sql2008express.iss diff --git a/Greenshot/releases/innosetup/scripts/products/sqlcompact35sp2.iss b/installer/innosetup/scripts/products/sqlcompact35sp2.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/sqlcompact35sp2.iss rename to installer/innosetup/scripts/products/sqlcompact35sp2.iss diff --git a/Greenshot/releases/innosetup/scripts/products/stringversion.iss b/installer/innosetup/scripts/products/stringversion.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/stringversion.iss rename to installer/innosetup/scripts/products/stringversion.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2005.iss b/installer/innosetup/scripts/products/vcredist2005.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2005.iss rename to installer/innosetup/scripts/products/vcredist2005.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2008.iss b/installer/innosetup/scripts/products/vcredist2008.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2008.iss rename to installer/innosetup/scripts/products/vcredist2008.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2010.iss b/installer/innosetup/scripts/products/vcredist2010.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2010.iss rename to installer/innosetup/scripts/products/vcredist2010.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2012.iss b/installer/innosetup/scripts/products/vcredist2012.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2012.iss rename to installer/innosetup/scripts/products/vcredist2012.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2013.iss b/installer/innosetup/scripts/products/vcredist2013.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2013.iss rename to installer/innosetup/scripts/products/vcredist2013.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2015.iss b/installer/innosetup/scripts/products/vcredist2015.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2015.iss rename to installer/innosetup/scripts/products/vcredist2015.iss diff --git a/Greenshot/releases/innosetup/scripts/products/vcredist2017.iss b/installer/innosetup/scripts/products/vcredist2017.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/vcredist2017.iss rename to installer/innosetup/scripts/products/vcredist2017.iss diff --git a/Greenshot/releases/innosetup/scripts/products/wic.iss b/installer/innosetup/scripts/products/wic.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/wic.iss rename to installer/innosetup/scripts/products/wic.iss diff --git a/Greenshot/releases/innosetup/scripts/products/winversion.iss b/installer/innosetup/scripts/products/winversion.iss similarity index 100% rename from Greenshot/releases/innosetup/scripts/products/winversion.iss rename to installer/innosetup/scripts/products/winversion.iss diff --git a/Greenshot/releases/innosetup/setup.iss b/installer/innosetup/setup.iss similarity index 81% rename from Greenshot/releases/innosetup/setup.iss rename to installer/innosetup/setup.iss index d055b7151..f8bd75b1d 100644 --- a/Greenshot/releases/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -1,9 +1,11 @@ #define ExeName "Greenshot" #define Version GetEnv('BuildVersionSimple') #define FileVersion GetEnv('AssemblyInformationalVersion') -#define BaseDir "..\..\.." -#define ReleaseDir "..\..\bin\Release\net472" +#define BaseDir "..\..\src" +#define GreenshotProjectDir "..\..\src\Greenshot" +#define LanguagesDir "..\..\src\Greenshot\Languages" #define BinDir "bin\Release\net472" +#define ReleaseDir "..\..\src\Greenshot\bin\Release\net472" ; Include the scripts to install .NET Framework ; See http://www.codeproject.com/KB/install/dotnetfx_innosetup_instal.aspx @@ -18,7 +20,7 @@ [Files] Source: {#ReleaseDir}\Greenshot.exe; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\GreenshotPlugin.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\Greenshot.Base.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Greenshot.exe.config; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\log4net.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Dapplo.Http*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion @@ -27,7 +29,7 @@ Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: ove Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\HtmlAgilityPack.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Newtonsoft.Json.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: ..\..\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion +Source: {#GreenshotProjectDir}\log4net.xml; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion Source: {#ReleaseDir}\checksum.SHA256; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion ;Source: ..\greenshot-defaults.ini; DestDir: {app}; Flags: overwritereadonly ignoreversion replacesameversion Source: ..\additional_files\installer.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion @@ -35,81 +37,78 @@ Source: ..\additional_files\license.txt; DestDir: {app}; Components: greenshot; Source: ..\additional_files\readme.txt; DestDir: {app}; Components: greenshot; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion ; Core language files -Source: ..\..\Languages\*nl-NL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*en-US*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*de-DE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*nl-NL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*en-US*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*de-DE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion; ; Additional language files -Source: ..\..\Languages\*ar-SY*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\arSY; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ca-CA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\caCA; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*cs-CZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\csCZ; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*da-DK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\daDK; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*de-x-franconia*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\dexfranconia; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*el-GR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\elGR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*es-ES*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\esES; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*et-EE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\etEE; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fa-IR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\faIR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fi-FI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\fiFI; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fr-FR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frFR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*fr-QC*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frQC; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*he-IL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\heIL; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*hu-HU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\huHU; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*id-ID*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\idID; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*it-IT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\itIT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ja-JP*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\jaJP; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ko-KR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\koKR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*kab-DZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\kabDZ; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*lt-LT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ltLT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*lv-LV*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\lvLV; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*nn-NO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\nnNO; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*pl-PL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\plPL; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*pt-BR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptBR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*pt-PT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptPT; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ro-RO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\roRO; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*ru-RU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ruRU; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sk-SK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\skSK; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sl-SI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\slSI; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sr-RS*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\srRS; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*sv-SE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\svSE; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*tr-TR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\trTR; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*uk-UA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ukUA; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*vi-VN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\viVN; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhCN; Flags: overwritereadonly ignoreversion replacesameversion; -Source: ..\..\Languages\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ar-SY*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\arSY; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ca-CA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\caCA; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*cs-CZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\csCZ; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*da-DK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\daDK; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*de-x-franconia*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\dexfranconia; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*el-GR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\elGR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*es-ES*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\esES; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*et-EE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\etEE; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*fa-IR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\faIR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*fi-FI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\fiFI; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*fr-FR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frFR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*fr-QC*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\frQC; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*he-IL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\heIL; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*hu-HU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\huHU; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*id-ID*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\idID; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*it-IT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\itIT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ja-JP*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\jaJP; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ko-KR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\koKR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*kab-DZ*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\kabDZ; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*lt-LT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ltLT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*lv-LV*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\lvLV; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*nn-NO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\nnNO; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*pl-PL*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\plPL; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*pt-BR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptBR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*pt-PT*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ptPT; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ro-RO*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\roRO; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*ru-RU*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ruRU; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*sk-SK*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\skSK; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*sl-SI*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\slSI; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*sr-RS*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\srRS; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*sv-SE*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\svSE; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*tr-TR*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\trTR; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*uk-UA*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\ukUA; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*vi-VN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\viVN; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhCN; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#LanguagesDir}\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion; ;Office Plugin -Source: {#BaseDir}\GreenshotOfficePlugin\{#BinDir}\GreenshotOfficePlugin.dll; DestDir: {app}\Plugins\GreenshotOfficePlugin; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Office\{#BinDir}\Greenshot.Plugin.Office.dll; DestDir: {app}\Plugins\Office; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; ;JIRA Plugin -Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\GreenshotJiraPlugin.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotJiraPlugin\{#BinDir}\Dapplo.Jira*.dll; DestDir: {app}\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotJiraPlugin\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\GreenshotJiraPlugin; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Jira\{#BinDir}\Greenshot.Plugin.Jira.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Jira\{#BinDir}\Dapplo.Jira*.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Jira\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion; ;Imgur Plugin -Source: {#BaseDir}\GreenshotImgurPlugin\{#BinDir}\GreenshotImgurPlugin.dll; DestDir: {app}\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotImgurPlugin\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\GreenshotImgurPlugin; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Imgur\{#BinDir}\Greenshot.Plugin.Imgur.dll; DestDir: {app}\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Imgur\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion; ;Box Plugin -Source: {#BaseDir}\GreenshotBoxPlugin\{#BinDir}\GreenshotBoxPlugin.dll; DestDir: {app}\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotBoxPlugin\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\GreenshotBoxPlugin; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Box\{#BinDir}\Greenshot.Plugin.Box.dll; DestDir: {app}\Plugins\Box; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Box\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\Box; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion; ;DropBox Plugin -Source: {#BaseDir}\GreenshotDropBoxPlugin\{#BinDir}\GreenshotDropboxPlugin.dll; DestDir: {app}\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotDropBoxPlugin\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\GreenshotDropBoxPlugin; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.DropBox\{#BinDir}\Greenshot.Plugin.DropBox.dll; DestDir: {app}\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.DropBox\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion; ;Flickr Plugin -Source: {#BaseDir}\GreenshotFlickrPlugin\{#BinDir}\GreenshotFlickrPlugin.dll; DestDir: {app}\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotFlickrPlugin\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\GreenshotFlickrPlugin; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Flickr\{#BinDir}\Greenshot.Plugin.Flickr.dll; DestDir: {app}\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Flickr\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion; ;Photobucket Plugin -Source: {#BaseDir}\GreenshotPhotobucketPlugin\{#BinDir}\GreenshotPhotobucketPlugin.dll; DestDir: {app}\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotPhotobucketPlugin\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\GreenshotPhotobucketPlugin; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion; -;Picasa Plugin -;Source: {#BaseDir}\GreenshotPicasaPlugin\{#BinDir}\GreenshotPicasaPlugin.dll; DestDir: {app}\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -;Source: {#BaseDir}\GreenshotPicasaPlugin\Languages\language_picasa*.xml; DestDir: {app}\Languages\Plugins\GreenshotPicasaPlugin; Components: plugins\picasa; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Photobucket\{#BinDir}\\Greenshot.Plugin.Photobucket.dll; DestDir: {app}\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Photobucket\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion; ;Confluence Plugin -Source: {#BaseDir}\GreenshotConfluencePlugin\{#BinDir}\GreenshotConfluencePlugin.dll; DestDir: {app}\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotConfluencePlugin\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\GreenshotConfluencePlugin; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Confluence\{#BinDir}\Greenshot.Plugin.Confluence.dll; DestDir: {app}\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Confluence\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; ;ExternalCommand Plugin -Source: {#BaseDir}\GreenshotExternalCommandPlugin\{#BinDir}\GreenshotExternalCommandPlugin.dll; DestDir: {app}\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotExternalCommandPlugin\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\GreenshotExternalCommandPlugin; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.ExternalCommand\{#BinDir}\Greenshot.Plugin.ExternalCommand.dll; DestDir: {app}\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.ExternalCommand\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion; ;Win 10 Plugin -Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\GreenshotWin10Plugin.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\GreenshotWin10Plugin\{#BinDir}\Microsoft.Toolkit.Uwp.Notifications.dll; DestDir: {app}\Plugins\GreenshotWin10Plugin; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Win10\{#BinDir}\Greenshot.Plugin.Win10.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#BaseDir}\Greenshot.Plugin.Win10\{#BinDir}\Microsoft.Toolkit.Uwp.Notifications.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; [Setup] ; changes associations is used when the installer installs new extensions, it clears the explorer icon cache @@ -135,7 +134,7 @@ MinVersion=6.1sp1 OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE OutputDir=..\ PrivilegesRequired=lowest -SetupIconFile=..\..\icons\applicationIcon\icon.ico +SetupIconFile=..\..\src\Greenshot\icons\applicationIcon\icon.ico ; Create a SHA1 signature ; SignTool=SignTool sign /debug /fd sha1 /tr http://time.certum.pl /td sha1 $f ; Append a SHA256 to the previous SHA1 signature (this is what as does) @@ -158,6 +157,8 @@ Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: no Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Root: HKCU32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() Root: HKLM32; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() +Root: HKCU64; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() +Root: HKLM64; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; Check: IsWin64() ; delete filetype mappings ; HKEY_LOCAL_USER - for current user only @@ -261,7 +262,6 @@ en.language=Additional languages en.office=Microsoft Office plug-in en.optimize=Optimizing performance, this may take a while. en.photobucket=Photobucket plug-in -en.picasa=Picasa plug-in en.startgreenshot=Start {#ExeName} en.startup=Start {#ExeName} with Windows start en.win10=Windows 10 plug-in @@ -328,7 +328,6 @@ it.language=Lingue aggiuntive it.office=Plugin Microsoft Office it.optimize=Ottimizzazione prestazioni (può richiedere tempo). it.photobucket=Plugin Photobucket -it.picasa=Plugin Picasa it.startgreenshot=Esegui {#ExeName} it.startup=Esegui {#ExeName} all''avvio di Windows it.win10=Plugin Windows 10 @@ -493,7 +492,6 @@ Name: "plugins\imgur"; Description: {cm:imgur}; Types: default full custom; Flag Name: "plugins\jira"; Description: {cm:jira}; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\office"; Description: {cm:office}; Types: default full custom; Flags: disablenouninstallwarning Name: "plugins\photobucket"; Description: {cm:photobucket}; Types: full custom; Flags: disablenouninstallwarning -;Name: "plugins\picasa"; Description: {cm:picasa}; Types: full custom; Flags: disablenouninstallwarning Name: "plugins\win10"; Description: {cm:win10}; Types: default full custom; Flags: disablenouninstallwarning; Check: IsWindows10OrNewer() Name: "languages"; Description: {cm:language}; Types: full custom; Flags: disablenouninstallwarning Name: "languages\arSY"; Description: {cm:arSY}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('d') diff --git a/Greenshot/releases/portable/App/AppInfo/appicon.ico b/installer/portable/App/AppInfo/appicon.ico similarity index 100% rename from Greenshot/releases/portable/App/AppInfo/appicon.ico rename to installer/portable/App/AppInfo/appicon.ico diff --git a/Greenshot/releases/portable/App/AppInfo/appicon_16.png b/installer/portable/App/AppInfo/appicon_16.png similarity index 100% rename from Greenshot/releases/portable/App/AppInfo/appicon_16.png rename to installer/portable/App/AppInfo/appicon_16.png diff --git a/Greenshot/releases/portable/App/AppInfo/appicon_32.png b/installer/portable/App/AppInfo/appicon_32.png similarity index 100% rename from Greenshot/releases/portable/App/AppInfo/appicon_32.png rename to installer/portable/App/AppInfo/appicon_32.png diff --git a/Greenshot/releases/portable/App/DefaultData/Greenshots/dummy.txt b/installer/portable/App/DefaultData/Greenshots/dummy.txt similarity index 100% rename from Greenshot/releases/portable/App/DefaultData/Greenshots/dummy.txt rename to installer/portable/App/DefaultData/Greenshots/dummy.txt diff --git a/Greenshot/releases/portable/App/DefaultData/Settings/dummy.txt b/installer/portable/App/DefaultData/Settings/dummy.txt similarity index 100% rename from Greenshot/releases/portable/App/DefaultData/Settings/dummy.txt rename to installer/portable/App/DefaultData/Settings/dummy.txt diff --git a/Greenshot/releases/portable/Data/Greenshot/dummy.txt b/installer/portable/Data/Greenshot/dummy.txt similarity index 100% rename from Greenshot/releases/portable/Data/Greenshot/dummy.txt rename to installer/portable/Data/Greenshot/dummy.txt diff --git a/Greenshot/releases/portable/Data/Settings/dummy.txt b/installer/portable/Data/Settings/dummy.txt similarity index 100% rename from Greenshot/releases/portable/Data/Settings/dummy.txt rename to installer/portable/Data/Settings/dummy.txt diff --git a/Greenshot/releases/portable/Other/Source/PortableApps.comInstallerCustom.nsh b/installer/portable/Other/Source/PortableApps.comInstallerCustom.nsh similarity index 100% rename from Greenshot/releases/portable/Other/Source/PortableApps.comInstallerCustom.nsh rename to installer/portable/Other/Source/PortableApps.comInstallerCustom.nsh diff --git a/.editorconfig b/src/.editorconfig similarity index 100% rename from .editorconfig rename to src/.editorconfig diff --git a/Directory.Build.props b/src/Directory.Build.props similarity index 97% rename from Directory.Build.props rename to src/Directory.Build.props index a15044b52..77faddc33 100644 --- a/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,122 +1,122 @@ - - - Copyright © Greenshot 2004-2021 - Greenshot - https://getgreenshot.org/favicon.ico - https://github.com/greenshot/greenshot - git - https://github.com/greenshot/greenshot - https://www.gnu.org/licenses/gpl.html - GPL - 9 - true - true - win10-x64;win10-x86;win-x64;win-x86 - - true - - true - net472 - Off - true - - - - - - - - - false - true - - - - false - true - false - - - - false - false - - - - DEBUG;TRACE - True - true - embedded - false - - - - true - embedded - True - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - $(Box13_ClientId) - - - $(Box13_ClientSecret) - - - $(DropBox13_ClientId) - - - $(DropBox13_ClientSecret) - - - $(Flickr_ClientId) - - - $(Flickr_ClientSecret) - - - $(Imgur13_ClientId) - - - $(Imgur13_ClientSecret) - - - $(Photobucket_ClientId) - - - $(Photobucket_ClientSecret) - - - $(Picasa_ClientId) - - - $(Picasa_ClientSecret) - - - - - - - - - - - - + + + Copyright © Greenshot 2004-2021 + Greenshot + https://getgreenshot.org/favicon.ico + https://github.com/greenshot/greenshot + git + https://github.com/greenshot/greenshot + https://www.gnu.org/licenses/gpl.html + GPL + 9 + true + true + win10-x64;win10-x86;win-x64;win-x86 + + true + + true + net472 + Off + true + + + + + + + + + false + true + + + + false + true + false + + + + false + false + + + + DEBUG;TRACE + True + true + embedded + false + + + + true + embedded + True + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + $(Box13_ClientId) + + + $(Box13_ClientSecret) + + + $(DropBox13_ClientId) + + + $(DropBox13_ClientSecret) + + + $(Flickr_ClientId) + + + $(Flickr_ClientSecret) + + + $(Imgur13_ClientId) + + + $(Imgur13_ClientSecret) + + + $(Photobucket_ClientId) + + + $(Photobucket_ClientSecret) + + + $(Picasa_ClientId) + + + $(Picasa_ClientSecret) + + + + + + + + + + + + diff --git a/Directory.Build.targets b/src/Directory.Build.targets similarity index 100% rename from Directory.Build.targets rename to src/Directory.Build.targets diff --git a/src/Greenshot.Base/Controls/AnimatingForm.cs b/src/Greenshot.Base/Controls/AnimatingForm.cs new file mode 100644 index 000000000..c5a5e3e7e --- /dev/null +++ b/src/Greenshot.Base/Controls/AnimatingForm.cs @@ -0,0 +1,140 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows.Forms; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// Extend this Form to have the possibility for animations on your form + /// + public class AnimatingForm : GreenshotForm + { + private static readonly ILog Log = LogManager.GetLogger(typeof(AnimatingForm)); + private const int DEFAULT_VREFRESH = 60; + private int _vRefresh; + private Timer _timer; + + /// + /// This flag specifies if any animation is used + /// + protected bool EnableAnimation { get; set; } + + /// + /// Vertical Refresh Rate + /// + protected int VRefresh + { + get + { + if (_vRefresh == 0) + { + // get te hDC of the desktop to get the VREFRESH + using SafeWindowDcHandle desktopHandle = SafeWindowDcHandle.FromDesktop(); + _vRefresh = GDI32.GetDeviceCaps(desktopHandle, DeviceCaps.VREFRESH); + } + + // A vertical refresh rate value of 0 or 1 represents the display hardware's default refresh rate. + // As there is currently no know way to get the default, we guess it. + if (_vRefresh <= 1) + { + _vRefresh = DEFAULT_VREFRESH; + } + + return _vRefresh; + } + } + + /// + /// Check if we are in a Terminal Server session OR need to optimize for RDP / remote desktop connections + /// + protected bool IsTerminalServerSession => !coreConfiguration.DisableRDPOptimizing && (coreConfiguration.OptimizeForRDP || SystemInformation.TerminalServerSession); + + /// + /// Calculate the amount of frames that an animation takes + /// + /// + /// Number of frames, 1 if in Terminal Server Session + protected int FramesForMillis(int milliseconds) + { + // If we are in a Terminal Server Session we return 1 + if (IsTerminalServerSession) + { + return 1; + } + + return milliseconds / VRefresh; + } + + /// + /// Initialize the animation + /// + protected AnimatingForm() + { + Load += delegate + { + if (!EnableAnimation) + { + return; + } + + _timer = new Timer + { + Interval = 1000 / VRefresh + }; + _timer.Tick += timer_Tick; + _timer.Start(); + }; + + // Unregister at close + FormClosing += delegate { _timer?.Stop(); }; + } + + /// + /// The tick handler initiates the animation. + /// + /// + /// + private void timer_Tick(object sender, EventArgs e) + { + try + { + Animate(); + } + catch (Exception ex) + { + Log.Warn("An exception occured while animating:", ex); + } + } + + /// + /// This method will be called every frame, so implement your animation/redraw logic here. + /// + protected virtual void Animate() + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/BackgroundForm.Designer.cs b/src/Greenshot.Base/Controls/BackgroundForm.Designer.cs similarity index 96% rename from GreenshotPlugin/Controls/BackgroundForm.Designer.cs rename to src/Greenshot.Base/Controls/BackgroundForm.Designer.cs index cafbb6e18..1bbde20ad 100644 --- a/GreenshotPlugin/Controls/BackgroundForm.Designer.cs +++ b/src/Greenshot.Base/Controls/BackgroundForm.Designer.cs @@ -1,96 +1,96 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -namespace GreenshotPlugin.Controls -{ - partial class BackgroundForm - { - /// - /// Designer variable used to keep track of non-visual components. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Disposes resources used by the form. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing) { - if (components != null) { - components.Dispose(); - } - } - base.Dispose(disposing); - } - - /// - /// This method is required for Windows Forms designer support. - /// Do not change the method contents inside the source code editor. The Forms designer might - /// not be able to load this method if it was changed manually. - /// - private void InitializeComponent() - { - this.components = new System.ComponentModel.Container(); - this.label_pleasewait = new System.Windows.Forms.Label(); - this.timer_checkforclose = new System.Windows.Forms.Timer(this.components); - this.SuspendLayout(); - // - // label_pleasewait - // - this.label_pleasewait.Dock = System.Windows.Forms.DockStyle.Fill; - this.label_pleasewait.Location = new System.Drawing.Point(0, 0); - this.label_pleasewait.Name = "label_pleasewait"; - this.label_pleasewait.Padding = new System.Windows.Forms.Padding(10); - this.label_pleasewait.Size = new System.Drawing.Size(90, 33); - this.label_pleasewait.TabIndex = 0; - this.label_pleasewait.Text = "Please wait..."; - this.label_pleasewait.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - this.label_pleasewait.UseWaitCursor = true; - // - // timer_checkforclose - // - this.timer_checkforclose.Interval = 200; - this.timer_checkforclose.Tick += new System.EventHandler(this.Timer_checkforcloseTick); - // - // BackgroundForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(169, 52); - this.ControlBox = true; - this.Controls.Add(this.label_pleasewait); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "BackgroundForm"; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Greenshot"; - this.TopMost = true; - this.UseWaitCursor = true; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.BackgroundFormFormClosing); - this.ResumeLayout(false); - this.PerformLayout(); - } - private System.Windows.Forms.Timer timer_checkforclose; - private System.Windows.Forms.Label label_pleasewait; - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +namespace Greenshot.Base.Controls +{ + partial class BackgroundForm + { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.label_pleasewait = new System.Windows.Forms.Label(); + this.timer_checkforclose = new System.Windows.Forms.Timer(this.components); + this.SuspendLayout(); + // + // label_pleasewait + // + this.label_pleasewait.Dock = System.Windows.Forms.DockStyle.Fill; + this.label_pleasewait.Location = new System.Drawing.Point(0, 0); + this.label_pleasewait.Name = "label_pleasewait"; + this.label_pleasewait.Padding = new System.Windows.Forms.Padding(10); + this.label_pleasewait.Size = new System.Drawing.Size(90, 33); + this.label_pleasewait.TabIndex = 0; + this.label_pleasewait.Text = "Please wait..."; + this.label_pleasewait.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.label_pleasewait.UseWaitCursor = true; + // + // timer_checkforclose + // + this.timer_checkforclose.Interval = 200; + this.timer_checkforclose.Tick += new System.EventHandler(this.Timer_checkforcloseTick); + // + // BackgroundForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(169, 52); + this.ControlBox = true; + this.Controls.Add(this.label_pleasewait); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "BackgroundForm"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Greenshot"; + this.TopMost = true; + this.UseWaitCursor = true; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.BackgroundFormFormClosing); + this.ResumeLayout(false); + this.PerformLayout(); + } + private System.Windows.Forms.Timer timer_checkforclose; + private System.Windows.Forms.Label label_pleasewait; + } +} diff --git a/src/Greenshot.Base/Controls/BackgroundForm.cs b/src/Greenshot.Base/Controls/BackgroundForm.cs new file mode 100644 index 000000000..45691c8e3 --- /dev/null +++ b/src/Greenshot.Base/Controls/BackgroundForm.cs @@ -0,0 +1,99 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Controls +{ + /// + /// Description of PleaseWaitForm. + /// + public sealed partial class BackgroundForm : Form + { + private volatile bool _shouldClose; + + public BackgroundForm(string title, string text) + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + Icon = GreenshotResources.GetGreenshotIcon(); + _shouldClose = false; + Text = title; + label_pleasewait.Text = text; + FormClosing += PreventFormClose; + timer_checkforclose.Start(); + } + + // Can be used instead of ShowDialog + public new void Show() + { + base.Show(); + bool positioned = false; + foreach (Screen screen in Screen.AllScreens) + { + if (screen.Bounds.Contains(Cursor.Position)) + { + positioned = true; + Location = new Point(screen.Bounds.X + (screen.Bounds.Width / 2) - (Width / 2), screen.Bounds.Y + (screen.Bounds.Height / 2) - (Height / 2)); + break; + } + } + + if (!positioned) + { + Location = new Point(Cursor.Position.X - Width / 2, Cursor.Position.Y - Height / 2); + } + } + + private void PreventFormClose(object sender, FormClosingEventArgs e) + { + if (!_shouldClose) + { + e.Cancel = true; + } + } + + private void Timer_checkforcloseTick(object sender, EventArgs e) + { + if (_shouldClose) + { + timer_checkforclose.Stop(); + BeginInvoke(new EventHandler(delegate { Close(); })); + } + } + + public void CloseDialog() + { + _shouldClose = true; + Application.DoEvents(); + } + + private void BackgroundFormFormClosing(object sender, FormClosingEventArgs e) + { + timer_checkforclose.Stop(); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Controls/ExtendedWebBrowser.cs b/src/Greenshot.Base/Controls/ExtendedWebBrowser.cs new file mode 100644 index 000000000..0e4d439ae --- /dev/null +++ b/src/Greenshot.Base/Controls/ExtendedWebBrowser.cs @@ -0,0 +1,68 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows.Forms; +using Greenshot.Base.Interop; + +namespace Greenshot.Base.Controls +{ + public class ExtendedWebBrowser : WebBrowser + { + protected class ExtendedWebBrowserSite : WebBrowserSite, IOleCommandTarget + { + private const int OLECMDID_SHOWSCRIPTERROR = 40; + + private static readonly Guid CGID_DocHostCommandHandler = new Guid("F38BC242-B950-11D1-8918-00C04FC2C836"); + + private const int S_OK = 0; + private const int OLECMDERR_E_NOTSUPPORTED = (-2147221248); + + public ExtendedWebBrowserSite(WebBrowser wb) : base(wb) + { + } + + public int QueryStatus(Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText) + { + return OLECMDERR_E_NOTSUPPORTED; + } + + public int Exec(Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut) + { + if (pguidCmdGroup == CGID_DocHostCommandHandler) + { + if (nCmdID == OLECMDID_SHOWSCRIPTERROR) + { + // do not need to alter pvaOut as the docs says, enough to return S_OK here + return S_OK; + } + } + + return OLECMDERR_E_NOTSUPPORTED; + } + } + + protected override WebBrowserSiteBase CreateWebBrowserSiteBase() + { + return new ExtendedWebBrowserSite(this); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/FormWithoutActivation.cs b/src/Greenshot.Base/Controls/FormWithoutActivation.cs similarity index 86% rename from GreenshotPlugin/Controls/FormWithoutActivation.cs rename to src/Greenshot.Base/Controls/FormWithoutActivation.cs index 4491bbf2b..f9fee5ef5 100644 --- a/GreenshotPlugin/Controls/FormWithoutActivation.cs +++ b/src/Greenshot.Base/Controls/FormWithoutActivation.cs @@ -1,33 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls { - /// - /// FormWithoutActivation is exactly like a normal form, but doesn't activate (steal focus) - /// - public class FormWithoutActivation : Form { - protected override bool ShowWithoutActivation { - get { return true; } - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + /// + /// FormWithoutActivation is exactly like a normal form, but doesn't activate (steal focus) + /// + public class FormWithoutActivation : Form + { + protected override bool ShowWithoutActivation + { + get { return true; } + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/GreenshotButton.cs b/src/Greenshot.Base/Controls/GreenshotButton.cs similarity index 75% rename from GreenshotPlugin/Controls/GreenshotButton.cs rename to src/Greenshot.Base/Controls/GreenshotButton.cs index 16288ce43..703be11e5 100644 --- a/GreenshotPlugin/Controls/GreenshotButton.cs +++ b/src/Greenshot.Base/Controls/GreenshotButton.cs @@ -1,33 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls { - public class GreenshotButton : Button, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotButton : Button, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/GreenshotTextBox.cs b/src/Greenshot.Base/Controls/GreenshotCheckBox.cs similarity index 56% rename from GreenshotPlugin/Controls/GreenshotTextBox.cs rename to src/Greenshot.Base/Controls/GreenshotCheckBox.cs index a4f743f25..c7552fb74 100644 --- a/GreenshotPlugin/Controls/GreenshotTextBox.cs +++ b/src/Greenshot.Base/Controls/GreenshotCheckBox.cs @@ -1,36 +1,41 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls { - public class GreenshotTextBox : TextBox, IGreenshotConfigBindable { - [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] - public string SectionName { get; set; } = "Core"; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] - public string PropertyName { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + /// + /// Description of GreenshotCheckbox. + /// + public class GreenshotCheckBox : CheckBox, IGreenshotLanguageBindable, IGreenshotConfigBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Controls/GreenshotColumnSorter.cs b/src/Greenshot.Base/Controls/GreenshotColumnSorter.cs new file mode 100644 index 000000000..f33379cda --- /dev/null +++ b/src/Greenshot.Base/Controls/GreenshotColumnSorter.cs @@ -0,0 +1,127 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + /// + /// This class is an implementation of the 'IComparer' interface. + /// + public class GreenshotColumnSorter : IComparer + { + /// + /// Specifies the column to be sorted + /// + private int _columnToSort; + + /// + /// Specifies the order in which to sort (i.e. 'Ascending'). + /// + private SortOrder _orderOfSort; + + /// + /// Case insensitive comparer object + /// + private readonly CaseInsensitiveComparer _objectCompare; + + /// + /// Class constructor. Initializes various elements + /// + public GreenshotColumnSorter() + { + // Initialize the column to '0' + _columnToSort = 0; + + // Initialize the sort order to 'none' + _orderOfSort = SortOrder.None; + + // Initialize the CaseInsensitiveComparer object + _objectCompare = new CaseInsensitiveComparer(); + } + + /// + /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison. + /// + /// First object to be compared + /// Second object to be compared + /// The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y' + public int Compare(object x, object y) + { + if (x == null && y == null) + { + return 0; + } + + if (x == null) + { + return -1; + } + + if (y == null) + { + return 1; + } + + // Cast the objects to be compared to ListViewItem objects + var listviewX = (ListViewItem) x; + var listviewY = (ListViewItem) y; + + // Compare the two items + var compareResult = _objectCompare.Compare(listviewX.SubItems[_columnToSort].Text, listviewY.SubItems[_columnToSort].Text); + + // Calculate correct return value based on object comparison + if (_orderOfSort == SortOrder.Ascending) + { + // Ascending sort is selected, return normal result of compare operation + return compareResult; + } + + if (_orderOfSort == SortOrder.Descending) + { + // Descending sort is selected, return negative result of compare operation + return -compareResult; + } + + // Return '0' to indicate they are equal + return 0; + } + + /// + /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0'). + /// + public int SortColumn + { + set { _columnToSort = value; } + get { return _columnToSort; } + } + + /// + /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending'). + /// + public SortOrder Order + { + set { _orderOfSort = value; } + get { return _orderOfSort; } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Controls/GreenshotComboBox.cs b/src/Greenshot.Base/Controls/GreenshotComboBox.cs new file mode 100644 index 000000000..4c464544c --- /dev/null +++ b/src/Greenshot.Base/Controls/GreenshotComboBox.cs @@ -0,0 +1,116 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Windows.Forms; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Controls +{ + public class GreenshotComboBox : ComboBox, IGreenshotConfigBindable + { + private Type _enumType; + private Enum _selectedEnum; + + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + + public GreenshotComboBox() + { + SelectedIndexChanged += delegate { StoreSelectedEnum(); }; + } + + public void SetValue(Enum currentValue) + { + if (currentValue != null) + { + _selectedEnum = currentValue; + SelectedItem = Language.Translate(currentValue); + } + } + + /// + /// This is a method to popululate the ComboBox + /// with the items from the enumeration + /// + /// TEnum to populate with + public void Populate(Type enumType) + { + // Store the enum-type, so we can work with it + _enumType = enumType; + + var availableValues = Enum.GetValues(enumType); + Items.Clear(); + foreach (var enumValue in availableValues) + { + Items.Add(Language.Translate((Enum) enumValue)); + } + } + + /// + /// Store the selected value internally + /// + private void StoreSelectedEnum() + { + string enumTypeName = _enumType.Name; + string selectedValue = SelectedItem as string; + var availableValues = Enum.GetValues(_enumType); + object returnValue = null; + + try + { + returnValue = Enum.Parse(_enumType, selectedValue); + } + catch (Exception) + { + // Ignore + } + + foreach (Enum enumValue in availableValues) + { + string enumKey = enumTypeName + "." + enumValue; + if (Language.HasKey(enumKey)) + { + string translation = Language.GetString(enumTypeName + "." + enumValue); + if (translation.Equals(selectedValue)) + { + returnValue = enumValue; + } + } + } + + _selectedEnum = (Enum) returnValue; + } + + /// + /// Get the selected enum value from the combobox, uses generics + /// + /// The enum value of the combobox + public Enum GetSelectedEnum() + { + return _selectedEnum; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Controls/GreenshotForm.cs b/src/Greenshot.Base/Controls/GreenshotForm.cs new file mode 100644 index 000000000..9850e71ed --- /dev/null +++ b/src/Greenshot.Base/Controls/GreenshotForm.cs @@ -0,0 +1,643 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.IO; +using System.Reflection; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// This form is used for automatically binding the elements of the form to the language + /// + public class GreenshotForm : Form, IGreenshotLanguageBindable + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(GreenshotForm)); + protected static CoreConfiguration coreConfiguration; + private static readonly IDictionary reflectionCache = new Dictionary(); + private IComponentChangeService m_changeService; + private bool _isDesignModeLanguageSet; + private bool _applyLanguageManually; + private bool _storeFieldsManually; + private IDictionary _designTimeControls; + private IDictionary _designTimeToolStripItems; + + static GreenshotForm() + { + if (!IsInDesignMode) + { + coreConfiguration = IniConfig.GetIniSection(); + } + } + + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + + /// + /// Used to check the designmode during a constructor + /// + /// + protected static bool IsInDesignMode + { + get + { + return (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) > -1) || + (Application.ExecutablePath.IndexOf("sharpdevelop.exe", StringComparison.OrdinalIgnoreCase) > -1 || + (Application.ExecutablePath.IndexOf("wdexpress.exe", StringComparison.OrdinalIgnoreCase) > -1)); + } + } + + protected bool ManualLanguageApply + { + get { return _applyLanguageManually; } + set { _applyLanguageManually = value; } + } + + protected bool ManualStoreFields + { + get { return _storeFieldsManually; } + set { _storeFieldsManually = value; } + } + + /// + /// When this is set, the form will be brought to the foreground as soon as it is shown. + /// + protected bool ToFront { get; set; } + + /// + /// Code to initialize the language etc during design time + /// + protected void InitializeForDesigner() + { + if (!DesignMode) return; + _designTimeControls = new Dictionary(); + _designTimeToolStripItems = new Dictionary(); + try + { + ITypeResolutionService typeResService = GetService(typeof(ITypeResolutionService)) as ITypeResolutionService; + + // Add a hard-path if you are using SharpDevelop + // Language.AddLanguageFilePath(@"C:\Greenshot\Greenshot\Languages"); + + // this "type" + Assembly currentAssembly = GetType().Assembly; + if (typeResService != null) + { + string assemblyPath = typeResService.GetPathOfAssembly(currentAssembly.GetName()); + string assemblyDirectory = Path.GetDirectoryName(assemblyPath); + if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Greenshot\Languages\"))) + { + Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Greenshot\Languages\")); + } + + if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Languages\"))) + { + Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Languages\")); + } + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + + /// + /// This override is only for the design-time of the form + /// + /// + protected override void OnPaint(PaintEventArgs e) + { + if (DesignMode) + { + if (!_isDesignModeLanguageSet) + { + _isDesignModeLanguageSet = true; + try + { + ApplyLanguage(); + } + catch (Exception) + { + // ignored + } + } + } + + base.OnPaint(e); + } + + protected override void OnLoad(EventArgs e) + { + // Every GreenshotForm should have it's default icon + // And it might not ne needed for a Tool Window, but still for the task manager / switcher it's important + Icon = GreenshotResources.GetGreenshotIcon(); + if (!DesignMode) + { + if (!_applyLanguageManually) + { + ApplyLanguage(); + } + + FillFields(); + base.OnLoad(e); + } + else + { + LOG.Info("OnLoad called from designer."); + InitializeForDesigner(); + base.OnLoad(e); + ApplyLanguage(); + } + } + + /// + /// Make sure the form is visible, if this is wanted + /// + /// EventArgs + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + if (ToFront) + { + WindowDetails.ToForeground(Handle); + } + } + + /// + /// check if the form was closed with an OK, if so store the values in the GreenshotControls + /// + /// + protected override void OnClosed(EventArgs e) + { + if (!DesignMode && !_storeFieldsManually) + { + if (DialogResult == DialogResult.OK) + { + LOG.Info("Form was closed with OK: storing field values."); + StoreFields(); + } + } + + base.OnClosed(e); + } + + /// + /// This override allows the control to register event handlers for IComponentChangeService events + /// at the time the control is sited, which happens only in design mode. + /// + public override ISite Site + { + get { return base.Site; } + set + { + // Clear any component change event handlers. + ClearChangeNotifications(); + + // Set the new Site value. + base.Site = value; + + m_changeService = (IComponentChangeService) GetService(typeof(IComponentChangeService)); + + // Register event handlers for component change events. + RegisterChangeNotifications(); + } + } + + private void ClearChangeNotifications() + { + // The m_changeService value is null when not in design mode, + // as the IComponentChangeService is only available at design time. + m_changeService = (IComponentChangeService) GetService(typeof(IComponentChangeService)); + + // Clear our the component change events to prepare for re-siting. + if (m_changeService != null) + { + m_changeService.ComponentChanged -= OnComponentChanged; + m_changeService.ComponentAdded -= OnComponentAdded; + } + } + + private void RegisterChangeNotifications() + { + // Register the event handlers for the IComponentChangeService events + if (m_changeService != null) + { + m_changeService.ComponentChanged += OnComponentChanged; + m_changeService.ComponentAdded += OnComponentAdded; + } + } + + /// + /// This method handles the OnComponentChanged event to display a notification. + /// + /// + /// + private void OnComponentChanged(object sender, ComponentChangedEventArgs ce) + { + if (((IComponent) ce.Component)?.Site == null || ce.Member == null) return; + if (!"LanguageKey".Equals(ce.Member.Name)) return; + if (ce.Component is Control control) + { + LOG.InfoFormat("Changing LanguageKey for {0} to {1}", control.Name, ce.NewValue); + ApplyLanguage(control, (string) ce.NewValue); + } + else + { + if (ce.Component is ToolStripItem item) + { + LOG.InfoFormat("Changing LanguageKey for {0} to {1}", item.Name, ce.NewValue); + ApplyLanguage(item, (string) ce.NewValue); + } + else + { + LOG.InfoFormat("Not possible to changing LanguageKey for {0} to {1}", ce.Component.GetType(), ce.NewValue); + } + } + } + + private void OnComponentAdded(object sender, ComponentEventArgs ce) + { + if (ce.Component?.Site == null) return; + if (ce.Component is Control control) + { + if (!_designTimeControls.ContainsKey(control.Name)) + { + _designTimeControls.Add(control.Name, control); + } + else + { + _designTimeControls[control.Name] = control; + } + } + else + { + if (ce.Component is ToolStripItem stripItem) + { + ToolStripItem item = stripItem; + if (!_designTimeControls.ContainsKey(item.Name)) + { + _designTimeToolStripItems.Add(item.Name, item); + } + else + { + _designTimeToolStripItems[item.Name] = item; + } + } + } + } + + // Clean up any resources being used. + protected override void Dispose(bool disposing) + { + if (disposing) + { + ClearChangeNotifications(); + } + + base.Dispose(disposing); + } + + protected void ApplyLanguage(ToolStripItem applyTo, string languageKey) + { + string langString; + if (!string.IsNullOrEmpty(languageKey)) + { + if (!Language.TryGetString(languageKey, out langString)) + { + LOG.WarnFormat("Unknown language key '{0}' configured for control '{1}', this might be okay.", languageKey, applyTo.Name); + return; + } + + applyTo.Text = langString; + } + else + { + // Fallback to control name! + if (Language.TryGetString(applyTo.Name, out langString)) + { + applyTo.Text = langString; + return; + } + + if (!DesignMode) + { + LOG.DebugFormat("Greenshot control without language key: {0}", applyTo.Name); + } + } + } + + protected void ApplyLanguage(ToolStripItem applyTo) + { + if (applyTo is IGreenshotLanguageBindable languageBindable) + { + ApplyLanguage(applyTo, languageBindable.LanguageKey); + } + } + + protected void ApplyLanguage(Control applyTo) + { + if (!(applyTo is IGreenshotLanguageBindable languageBindable)) + { + // check if it's a menu! + if (!(applyTo is ToolStrip toolStrip)) + { + return; + } + + foreach (ToolStripItem item in toolStrip.Items) + { + ApplyLanguage(item); + } + + return; + } + + // Apply language text to the control + ApplyLanguage(applyTo, languageBindable.LanguageKey); + + // Repopulate the combox boxes + if (applyTo is IGreenshotConfigBindable configBindable && applyTo is GreenshotComboBox comboxBox) + { + if (!string.IsNullOrEmpty(configBindable.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + { + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section != null) + { + // Only update the language, so get the actual value and than repopulate + Enum currentValue = comboxBox.GetSelectedEnum(); + comboxBox.Populate(section.Values[configBindable.PropertyName].ValueType); + comboxBox.SetValue(currentValue); + } + } + } + } + + /// + /// Helper method to cache the fieldinfo values, so we don't need to reflect all the time! + /// + /// + /// + private static FieldInfo[] GetCachedFields(Type typeToGetFieldsFor) + { + if (!reflectionCache.TryGetValue(typeToGetFieldsFor, out var fields)) + { + fields = typeToGetFieldsFor.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + reflectionCache.Add(typeToGetFieldsFor, fields); + } + + return fields; + } + + /// + /// Apply all the language settings to the "Greenshot" Controls on this form + /// + protected void ApplyLanguage() + { + SuspendLayout(); + try + { + // Set title of the form + if (!string.IsNullOrEmpty(LanguageKey) && Language.TryGetString(LanguageKey, out var langString)) + { + Text = langString; + } + + // Reset the text values for all GreenshotControls + foreach (FieldInfo field in GetCachedFields(GetType())) + { + object controlObject = field.GetValue(this); + if (controlObject == null) + { + LOG.DebugFormat("No value: {0}", field.Name); + continue; + } + + if (!(controlObject is Control applyToControl)) + { + ToolStripItem applyToItem = controlObject as ToolStripItem; + if (applyToItem == null) + { + LOG.DebugFormat("No Control or ToolStripItem: {0}", field.Name); + continue; + } + + ApplyLanguage(applyToItem); + } + else + { + ApplyLanguage(applyToControl); + } + } + + if (DesignMode) + { + foreach (Control designControl in _designTimeControls.Values) + { + ApplyLanguage(designControl); + } + + foreach (ToolStripItem designToolStripItem in _designTimeToolStripItems.Values) + { + ApplyLanguage(designToolStripItem); + } + } + } + finally + { + ResumeLayout(); + } + } + + /// + /// Apply the language text to supplied control + /// + protected void ApplyLanguage(Control applyTo, string languageKey) + { + string langString; + if (!string.IsNullOrEmpty(languageKey)) + { + if (!Language.TryGetString(languageKey, out langString)) + { + LOG.WarnFormat("Wrong language key '{0}' configured for control '{1}'", languageKey, applyTo.Name); + return; + } + + applyTo.Text = langString; + } + else + { + // Fallback to control name! + if (Language.TryGetString(applyTo.Name, out langString)) + { + applyTo.Text = langString; + return; + } + + if (!DesignMode) + { + LOG.DebugFormat("Greenshot control without language key: {0}", applyTo.Name); + } + } + } + + /// + /// Fill all GreenshotControls with the values from the configuration + /// + protected void FillFields() + { + foreach (FieldInfo field in GetCachedFields(GetType())) + { + var controlObject = field.GetValue(this); + IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; + if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + { + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section != null) + { + if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) + { + LOG.DebugFormat("Wrong property '{0}' configured for field '{1}'", configBindable.PropertyName, field.Name); + continue; + } + + if (controlObject is CheckBox checkBox) + { + checkBox.Checked = (bool) iniValue.Value; + checkBox.Enabled = !iniValue.IsFixed; + continue; + } + + if (controlObject is RadioButton radíoButton) + { + radíoButton.Checked = (bool) iniValue.Value; + radíoButton.Enabled = !iniValue.IsFixed; + continue; + } + + if (controlObject is TextBox textBox) + { + if (controlObject is HotkeyControl hotkeyControl) + { + string hotkeyValue = (string) iniValue.Value; + if (!string.IsNullOrEmpty(hotkeyValue)) + { + hotkeyControl.SetHotkey(hotkeyValue); + hotkeyControl.Enabled = !iniValue.IsFixed; + } + + continue; + } + + textBox.Text = iniValue.ToString(); + textBox.Enabled = !iniValue.IsFixed; + continue; + } + + if (controlObject is GreenshotComboBox comboxBox) + { + comboxBox.Populate(iniValue.ValueType); + comboxBox.SetValue((Enum) iniValue.Value); + comboxBox.Enabled = !iniValue.IsFixed; + } + } + } + } + + OnFieldsFilled(); + } + + protected virtual void OnFieldsFilled() + { + } + + /// + /// Store all GreenshotControl values to the configuration + /// + protected void StoreFields() + { + bool iniDirty = false; + foreach (FieldInfo field in GetCachedFields(GetType())) + { + var controlObject = field.GetValue(this); + IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; + + if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + { + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section != null) + { + if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) + { + continue; + } + + if (controlObject is CheckBox checkBox) + { + iniValue.Value = checkBox.Checked; + iniDirty = true; + continue; + } + + if (controlObject is RadioButton radioButton) + { + iniValue.Value = radioButton.Checked; + iniDirty = true; + continue; + } + + if (controlObject is TextBox textBox) + { + if (controlObject is HotkeyControl hotkeyControl) + { + iniValue.Value = hotkeyControl.ToString(); + iniDirty = true; + continue; + } + + iniValue.UseValueOrDefault(textBox.Text); + iniDirty = true; + continue; + } + + if (controlObject is GreenshotComboBox comboxBox) + { + iniValue.Value = comboxBox.GetSelectedEnum(); + iniDirty = true; + } + } + } + } + + if (iniDirty) + { + IniConfig.Save(); + } + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/GreenshotGroupBox.cs b/src/Greenshot.Base/Controls/GreenshotGroupBox.cs similarity index 74% rename from GreenshotPlugin/Controls/GreenshotGroupBox.cs rename to src/Greenshot.Base/Controls/GreenshotGroupBox.cs index 954027948..a213f1139 100644 --- a/GreenshotPlugin/Controls/GreenshotGroupBox.cs +++ b/src/Greenshot.Base/Controls/GreenshotGroupBox.cs @@ -1,33 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; -using System.ComponentModel; - -namespace GreenshotPlugin.Controls { - public class GreenshotGroupBox : GroupBox , IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotGroupBox : GroupBox, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/GreenshotLabel.cs b/src/Greenshot.Base/Controls/GreenshotLabel.cs similarity index 75% rename from GreenshotPlugin/Controls/GreenshotLabel.cs rename to src/Greenshot.Base/Controls/GreenshotLabel.cs index 887bdb2ea..152bf5fb1 100644 --- a/GreenshotPlugin/Controls/GreenshotLabel.cs +++ b/src/Greenshot.Base/Controls/GreenshotLabel.cs @@ -1,33 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; -using System.ComponentModel; - -namespace GreenshotPlugin.Controls { - public class GreenshotLabel : Label, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotLabel : Label, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/GreenshotCheckBox.cs b/src/Greenshot.Base/Controls/GreenshotRadioButton.cs similarity index 56% rename from GreenshotPlugin/Controls/GreenshotCheckBox.cs rename to src/Greenshot.Base/Controls/GreenshotRadioButton.cs index e7e3483ab..0e0e87d58 100644 --- a/GreenshotPlugin/Controls/GreenshotCheckBox.cs +++ b/src/Greenshot.Base/Controls/GreenshotRadioButton.cs @@ -1,45 +1,41 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls { - /// - /// Description of GreenshotCheckbox. - /// - public class GreenshotCheckBox : CheckBox, IGreenshotLanguageBindable, IGreenshotConfigBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - - [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] - public string SectionName { get; set; } = "Core"; - - [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] - public string PropertyName { - get; - set; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + /// + /// Description of GreenshotCheckbox. + /// + public class GreenshotRadioButton : RadioButton, IGreenshotLanguageBindable, IGreenshotConfigBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + } } \ No newline at end of file diff --git a/GreenshotPlugin/Controls/GreenshotTabPage.cs b/src/Greenshot.Base/Controls/GreenshotTabPage.cs similarity index 75% rename from GreenshotPlugin/Controls/GreenshotTabPage.cs rename to src/Greenshot.Base/Controls/GreenshotTabPage.cs index 6941a861a..8577368c9 100644 --- a/GreenshotPlugin/Controls/GreenshotTabPage.cs +++ b/src/Greenshot.Base/Controls/GreenshotTabPage.cs @@ -1,33 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; -using System.ComponentModel; - -namespace GreenshotPlugin.Controls { - public class GreenshotTabPage : TabPage, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotTabPage : TabPage, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs b/src/Greenshot.Base/Controls/GreenshotTextBox.cs similarity index 67% rename from GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs rename to src/Greenshot.Base/Controls/GreenshotTextBox.cs index e9a9edb7d..744a479d1 100644 --- a/GreenshotPlugin/Controls/GreenshotToolDropDownButton.cs +++ b/src/Greenshot.Base/Controls/GreenshotTextBox.cs @@ -1,33 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls { - public class GreenshotToolStripDropDownButton : ToolStripDropDownButton, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotTextBox : TextBox, IGreenshotConfigBindable + { + [Category("Greenshot"), DefaultValue("Core"), Description("Specifies the Ini-Section to map this control with.")] + public string SectionName { get; set; } = "Core"; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies the property name to map the configuration.")] + public string PropertyName { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Controls/GreenshotToolDropDownButton.cs b/src/Greenshot.Base/Controls/GreenshotToolDropDownButton.cs new file mode 100644 index 000000000..81f5b7c2f --- /dev/null +++ b/src/Greenshot.Base/Controls/GreenshotToolDropDownButton.cs @@ -0,0 +1,32 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotToolStripDropDownButton : ToolStripDropDownButton, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/GreenshotToolStripButton.cs b/src/Greenshot.Base/Controls/GreenshotToolStripButton.cs similarity index 74% rename from GreenshotPlugin/Controls/GreenshotToolStripButton.cs rename to src/Greenshot.Base/Controls/GreenshotToolStripButton.cs index 06bf59597..68dee4ba6 100644 --- a/GreenshotPlugin/Controls/GreenshotToolStripButton.cs +++ b/src/Greenshot.Base/Controls/GreenshotToolStripButton.cs @@ -1,33 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls { - public class GreenshotToolStripButton : ToolStripButton, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotToolStripButton : ToolStripButton, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs b/src/Greenshot.Base/Controls/GreenshotToolStripLabel.cs similarity index 74% rename from GreenshotPlugin/Controls/GreenshotToolStripLabel.cs rename to src/Greenshot.Base/Controls/GreenshotToolStripLabel.cs index 5bee42167..e47de2955 100644 --- a/GreenshotPlugin/Controls/GreenshotToolStripLabel.cs +++ b/src/Greenshot.Base/Controls/GreenshotToolStripLabel.cs @@ -1,33 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Windows.Forms; -using System.ComponentModel; - -namespace GreenshotPlugin.Controls { - public class GreenshotToolStripLabel : ToolStripLabel, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotToolStripLabel : ToolStripLabel, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs b/src/Greenshot.Base/Controls/GreenshotToolStripMenuItem.cs similarity index 73% rename from GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs rename to src/Greenshot.Base/Controls/GreenshotToolStripMenuItem.cs index 8547b65c8..4feec806b 100644 --- a/GreenshotPlugin/Controls/GreenshotToolStripMenuItem.cs +++ b/src/Greenshot.Base/Controls/GreenshotToolStripMenuItem.cs @@ -1,33 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Windows.Forms; - -namespace GreenshotPlugin.Controls { - public class GreenshotToolStripMenuItem : ToolStripMenuItem, IGreenshotLanguageBindable { - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotToolStripMenuItem : ToolStripMenuItem, IGreenshotLanguageBindable + { + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Controls/HotkeyControl.cs b/src/Greenshot.Base/Controls/HotkeyControl.cs new file mode 100644 index 000000000..da1ae6696 --- /dev/null +++ b/src/Greenshot.Base/Controls/HotkeyControl.cs @@ -0,0 +1,686 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Plugin; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// A simple control that allows the user to select pretty much any valid hotkey combination + /// See: http://www.codeproject.com/KB/buttons/hotkeycontrol.aspx + /// But is modified to fit in Greenshot, and have localized support + /// + public sealed class HotkeyControl : GreenshotTextBox + { + private static readonly ILog Log = LogManager.GetLogger(typeof(HotkeyControl)); + + private static readonly EventDelay EventDelay = new EventDelay(TimeSpan.FromMilliseconds(600).Ticks); + private static readonly bool IsWindows7OrOlder = Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 1; + + // Holds the list of hotkeys + private static readonly IDictionary KeyHandlers = new Dictionary(); + private static int _hotKeyCounter = 1; + private const uint WM_HOTKEY = 0x312; + private static IntPtr _hotkeyHwnd; + + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum Modifiers : uint + { + NONE = 0, + ALT = 1, + CTRL = 2, + SHIFT = 4, + WIN = 8, + NO_REPEAT = 0x4000 + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + private enum MapType : uint + { + MAPVK_VK_TO_VSC = + 0, //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0. + + MAPVK_VSC_TO_VK = + 1, //The uCode parameter is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0. + + MAPVK_VK_TO_CHAR = + 2, //The uCode parameter is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0. + + MAPVK_VSC_TO_VK_EX = + 3, //The uCode parameter is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0. + + MAPVK_VK_TO_VSC_EX = + 4 //The uCode parameter is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If the scan code is an extended scan code, the high byte of the uCode value can contain either 0xe0 or 0xe1 to specify the extended scan code. If there is no translation, the function returns 0. + } + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint virtualKeyCode); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + + [DllImport("user32.dll", SetLastError = true)] + private static extern uint MapVirtualKey(uint uCode, uint uMapType); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern int GetKeyNameText(uint lParam, [Out] StringBuilder lpString, int nSize); + + // These variables store the current hotkey and modifier(s) + private Keys _hotkey = Keys.None; + private Keys _modifiers = Keys.None; + + // ArrayLists used to enforce the use of proper modifiers. + // Shift+A isn't a valid hotkey, for instance, as it would screw up when the user is typing. + private readonly IList _needNonShiftModifier = new List(); + private readonly IList _needNonAltGrModifier = new List(); + + private readonly ContextMenuStrip _dummy = new ContextMenuStrip(); + + /// + /// Used to make sure that there is no right-click menu available + /// + public override ContextMenuStrip ContextMenuStrip + { + get { return _dummy; } + set { base.ContextMenuStrip = _dummy; } + } + + /// + /// Forces the control to be non-multiline + /// + public override bool Multiline + { + get { return base.Multiline; } + set + { + // Ignore what the user wants; force Multiline to false + base.Multiline = false; + } + } + + /// + /// Creates a new HotkeyControl + /// + public HotkeyControl() + { + ContextMenuStrip = _dummy; // Disable right-clicking + Text = "None"; + + // Handle events that occurs when keys are pressed + KeyPress += HotkeyControl_KeyPress; + KeyUp += HotkeyControl_KeyUp; + KeyDown += HotkeyControl_KeyDown; + + PopulateModifierLists(); + } + + /// + /// Populates the ArrayLists specifying disallowed hotkeys + /// such as Shift+A, Ctrl+Alt+4 (would produce a dollar sign) etc + /// + private void PopulateModifierLists() + { + // Shift + 0 - 9, A - Z + for (Keys k = Keys.D0; k <= Keys.Z; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Shift + Numpad keys + for (Keys k = Keys.NumPad0; k <= Keys.NumPad9; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Shift + Misc (,;<./ etc) + for (Keys k = Keys.Oem1; k <= Keys.OemBackslash; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Shift + Space, PgUp, PgDn, End, Home + for (Keys k = Keys.Space; k <= Keys.Home; k++) + { + _needNonShiftModifier.Add((int) k); + } + + // Misc keys that we can't loop through + _needNonShiftModifier.Add((int) Keys.Insert); + _needNonShiftModifier.Add((int) Keys.Help); + _needNonShiftModifier.Add((int) Keys.Multiply); + _needNonShiftModifier.Add((int) Keys.Add); + _needNonShiftModifier.Add((int) Keys.Subtract); + _needNonShiftModifier.Add((int) Keys.Divide); + _needNonShiftModifier.Add((int) Keys.Decimal); + _needNonShiftModifier.Add((int) Keys.Return); + _needNonShiftModifier.Add((int) Keys.Escape); + _needNonShiftModifier.Add((int) Keys.NumLock); + + // Ctrl+Alt + 0 - 9 + for (Keys k = Keys.D0; k <= Keys.D9; k++) + { + _needNonAltGrModifier.Add((int) k); + } + } + + /// + /// Resets this hotkey control to None + /// + public new void Clear() + { + Hotkey = Keys.None; + HotkeyModifiers = Keys.None; + } + + /// + /// Fires when a key is pushed down. Here, we'll want to update the text in the box + /// to notify the user what combination is currently pressed. + /// + private void HotkeyControl_KeyDown(object sender, KeyEventArgs e) + { + // Clear the current hotkey + if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete) + { + ResetHotkey(); + } + else + { + _modifiers = e.Modifiers; + _hotkey = e.KeyCode; + Redraw(); + } + } + + /// + /// Fires when all keys are released. If the current hotkey isn't valid, reset it. + /// Otherwise, do nothing and keep the text and hotkey as it was. + /// + private void HotkeyControl_KeyUp(object sender, KeyEventArgs e) + { + // Somehow the PrintScreen only comes as a keyup, therefore we handle it here. + if (e.KeyCode == Keys.PrintScreen) + { + _modifiers = e.Modifiers; + _hotkey = e.KeyCode; + Redraw(); + } + + if (_hotkey == Keys.None && ModifierKeys == Keys.None) + { + ResetHotkey(); + } + } + + /// + /// Prevents the letter/whatever entered to show up in the TextBox + /// Without this, a "A" key press would appear as "aControl, Alt + A" + /// + private void HotkeyControl_KeyPress(object sender, KeyPressEventArgs e) + { + e.Handled = true; + } + + /// + /// Handles some misc keys, such as Ctrl+Delete and Shift+Insert + /// + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (keyData == Keys.Delete || keyData == (Keys.Control | Keys.Delete)) + { + ResetHotkey(); + return true; + } + + // Paste + if (keyData == (Keys.Shift | Keys.Insert)) + { + return true; // Don't allow + } + + // Allow the rest + return base.ProcessCmdKey(ref msg, keyData); + } + + /// + /// Clears the current hotkey and resets the TextBox + /// + public void ResetHotkey() + { + _hotkey = Keys.None; + _modifiers = Keys.None; + Redraw(); + } + + /// + /// Used to get/set the hotkey (e.g. Keys.A) + /// + public Keys Hotkey + { + get { return _hotkey; } + set + { + _hotkey = value; + Redraw(true); + } + } + + /// + /// Used to get/set the hotkey (e.g. Keys.A) + /// + public void SetHotkey(string hotkey) + { + _hotkey = HotkeyFromString(hotkey); + _modifiers = HotkeyModifiersFromString(hotkey); + Redraw(true); + } + + /// + /// Used to get/set the modifier keys (e.g. Keys.Alt | Keys.Control) + /// + public Keys HotkeyModifiers + { + get { return _modifiers; } + set + { + _modifiers = value; + Redraw(true); + } + } + + /// + /// Redraws the TextBox when necessary. + /// + /// Specifies whether this function was called by the Hotkey/HotkeyModifiers properties or by the user. + private void Redraw(bool bCalledProgramatically = false) + { + // No hotkey set + if (_hotkey == Keys.None) + { + Text = string.Empty; + return; + } + + // LWin/RWin doesn't work as hotkeys (neither do they work as modifier keys in .NET 2.0) + if (_hotkey == Keys.LWin || _hotkey == Keys.RWin) + { + Text = string.Empty; + return; + } + + // Only validate input if it comes from the user + if (bCalledProgramatically == false) + { + // No modifier or shift only, AND a hotkey that needs another modifier + if ((_modifiers == Keys.Shift || _modifiers == Keys.None) && _needNonShiftModifier.Contains((int) _hotkey)) + { + if (_modifiers == Keys.None) + { + // Set Ctrl+Alt as the modifier unless Ctrl+Alt+ won't work... + if (_needNonAltGrModifier.Contains((int) _hotkey) == false) + { + _modifiers = Keys.Alt | Keys.Control; + } + else + { + // ... in that case, use Shift+Alt instead. + _modifiers = Keys.Alt | Keys.Shift; + } + } + else + { + // User pressed Shift and an invalid key (e.g. a letter or a number), + // that needs another set of modifier keys + _hotkey = Keys.None; + Text = string.Empty; + return; + } + } + + // Check all Ctrl+Alt keys + if ((_modifiers == (Keys.Alt | Keys.Control)) && _needNonAltGrModifier.Contains((int) _hotkey)) + { + // Ctrl+Alt+4 etc won't work; reset hotkey and tell the user + _hotkey = Keys.None; + Text = string.Empty; + return; + } + } + + // I have no idea why this is needed, but it is. Without this code, pressing only Ctrl + // will show up as "Control + ControlKey", etc. + if (_hotkey == Keys.Menu /* Alt */ || _hotkey == Keys.ShiftKey || _hotkey == Keys.ControlKey) + { + _hotkey = Keys.None; + } + + Text = HotkeyToLocalizedString(_modifiers, _hotkey); + } + + public override string ToString() + { + return HotkeyToString(HotkeyModifiers, Hotkey); + } + + public static string GetLocalizedHotkeyStringFromString(string hotkeyString) + { + Keys virtualKeyCode = HotkeyFromString(hotkeyString); + Keys modifiers = HotkeyModifiersFromString(hotkeyString); + return HotkeyToLocalizedString(modifiers, virtualKeyCode); + } + + public static string HotkeyToString(Keys modifierKeyCode, Keys virtualKeyCode) + { + return HotkeyModifiersToString(modifierKeyCode) + virtualKeyCode; + } + + public static string HotkeyModifiersToString(Keys modifierKeyCode) + { + StringBuilder hotkeyString = new StringBuilder(); + if ((modifierKeyCode & Keys.Alt) > 0) + { + hotkeyString.Append("Alt").Append(" + "); + } + + if ((modifierKeyCode & Keys.Control) > 0) + { + hotkeyString.Append("Ctrl").Append(" + "); + } + + if ((modifierKeyCode & Keys.Shift) > 0) + { + hotkeyString.Append("Shift").Append(" + "); + } + + if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) + { + hotkeyString.Append("Win").Append(" + "); + } + + return hotkeyString.ToString(); + } + + + public static string HotkeyToLocalizedString(Keys modifierKeyCode, Keys virtualKeyCode) + { + return HotkeyModifiersToLocalizedString(modifierKeyCode) + GetKeyName(virtualKeyCode); + } + + public static string HotkeyModifiersToLocalizedString(Keys modifierKeyCode) + { + StringBuilder hotkeyString = new StringBuilder(); + if ((modifierKeyCode & Keys.Alt) > 0) + { + hotkeyString.Append(GetKeyName(Keys.Alt)).Append(" + "); + } + + if ((modifierKeyCode & Keys.Control) > 0) + { + hotkeyString.Append(GetKeyName(Keys.Control)).Append(" + "); + } + + if ((modifierKeyCode & Keys.Shift) > 0) + { + hotkeyString.Append(GetKeyName(Keys.Shift)).Append(" + "); + } + + if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) + { + hotkeyString.Append("Win").Append(" + "); + } + + return hotkeyString.ToString(); + } + + + public static Keys HotkeyModifiersFromString(string modifiersString) + { + Keys modifiers = Keys.None; + if (!string.IsNullOrEmpty(modifiersString)) + { + if (modifiersString.ToLower().Contains("alt")) + { + modifiers |= Keys.Alt; + } + + if (modifiersString.ToLower().Contains("ctrl")) + { + modifiers |= Keys.Control; + } + + if (modifiersString.ToLower().Contains("shift")) + { + modifiers |= Keys.Shift; + } + + if (modifiersString.ToLower().Contains("win")) + { + modifiers |= Keys.LWin; + } + } + + return modifiers; + } + + public static Keys HotkeyFromString(string hotkey) + { + Keys key = Keys.None; + if (!string.IsNullOrEmpty(hotkey)) + { + if (hotkey.LastIndexOf('+') > 0) + { + hotkey = hotkey.Remove(0, hotkey.LastIndexOf('+') + 1).Trim(); + } + + key = (Keys) Enum.Parse(typeof(Keys), hotkey); + } + + return key; + } + + public static void RegisterHotkeyHwnd(IntPtr hWnd) + { + _hotkeyHwnd = hWnd; + } + + /// + /// Register a hotkey + /// + /// The modifier, e.g.: Modifiers.CTRL, Modifiers.NONE or Modifiers.ALT + /// The virtual key code + /// A HotKeyHandler, this will be called to handle the hotkey press + /// the hotkey number, -1 if failed + public static int RegisterHotKey(Keys modifierKeyCode, Keys virtualKeyCode, HotKeyHandler handler) + { + if (virtualKeyCode == Keys.None) + { + Log.Warn("Trying to register a Keys.none hotkey, ignoring"); + return 0; + } + + // Convert Modifiers to fit HKM_SETHOTKEY + uint modifiers = 0; + if ((modifierKeyCode & Keys.Alt) > 0) + { + modifiers |= (uint) Modifiers.ALT; + } + + if ((modifierKeyCode & Keys.Control) > 0) + { + modifiers |= (uint) Modifiers.CTRL; + } + + if ((modifierKeyCode & Keys.Shift) > 0) + { + modifiers |= (uint) Modifiers.SHIFT; + } + + if (modifierKeyCode == Keys.LWin || modifierKeyCode == Keys.RWin) + { + modifiers |= (uint) Modifiers.WIN; + } + + // Disable repeating hotkey for Windows 7 and beyond, as described in #1559 + if (IsWindows7OrOlder) + { + modifiers |= (uint) Modifiers.NO_REPEAT; + } + + if (RegisterHotKey(_hotkeyHwnd, _hotKeyCounter, modifiers, (uint) virtualKeyCode)) + { + KeyHandlers.Add(_hotKeyCounter, handler); + return _hotKeyCounter++; + } + + Log.Warn($"Couldn't register hotkey modifier {modifierKeyCode} virtualKeyCode {virtualKeyCode}"); + return -1; + } + + public static void UnregisterHotkeys() + { + foreach (int hotkey in KeyHandlers.Keys) + { + UnregisterHotKey(_hotkeyHwnd, hotkey); + } + + // Remove all key handlers + KeyHandlers.Clear(); + } + + /// + /// Handle WndProc messages for the hotkey + /// + /// + /// true if the message was handled + public static bool HandleMessages(ref Message m) + { + if (m.Msg != WM_HOTKEY) + { + return false; + } + + // Call handler + if (!IsWindows7OrOlder && !EventDelay.Check()) + { + return true; + } + + if (KeyHandlers.TryGetValue((int) m.WParam, out var handler)) + { + handler(); + } + + return true; + } + + public static string GetKeyName(Keys givenKey) + { + StringBuilder keyName = new StringBuilder(); + const uint numpad = 55; + + Keys virtualKey = givenKey; + string keyString; + // Make VC's to real keys + switch (virtualKey) + { + case Keys.Alt: + virtualKey = Keys.LMenu; + break; + case Keys.Control: + virtualKey = Keys.ControlKey; + break; + case Keys.Shift: + virtualKey = Keys.LShiftKey; + break; + case Keys.Multiply: + GetKeyNameText(numpad << 16, keyName, 100); + keyString = keyName.ToString().Replace("*", string.Empty).Trim().ToLower(); + if (keyString.IndexOf("(", StringComparison.Ordinal) >= 0) + { + return "* " + keyString; + } + + keyString = keyString.Substring(0, 1).ToUpper() + keyString.Substring(1).ToLower(); + return keyString + " *"; + case Keys.Divide: + GetKeyNameText(numpad << 16, keyName, 100); + keyString = keyName.ToString().Replace("*", string.Empty).Trim().ToLower(); + if (keyString.IndexOf("(", StringComparison.Ordinal) >= 0) + { + return "/ " + keyString; + } + + keyString = keyString.Substring(0, 1).ToUpper() + keyString.Substring(1).ToLower(); + return keyString + " /"; + } + + uint scanCode = MapVirtualKey((uint) virtualKey, (uint) MapType.MAPVK_VK_TO_VSC); + + // because MapVirtualKey strips the extended bit for some keys + switch (virtualKey) + { + case Keys.Left: + case Keys.Up: + case Keys.Right: + case Keys.Down: // arrow keys + case Keys.Prior: + case Keys.Next: // page up and page down + case Keys.End: + case Keys.Home: + case Keys.Insert: + case Keys.Delete: + case Keys.NumLock: + Log.Debug("Modifying Extended bit"); + scanCode |= 0x100; // set extended bit + break; + case Keys.PrintScreen: // PrintScreen + scanCode = 311; + break; + case Keys.Pause: // PrintScreen + scanCode = 69; + break; + } + + scanCode |= 0x200; + if (GetKeyNameText(scanCode << 16, keyName, 100) != 0) + { + string visibleName = keyName.ToString(); + if (visibleName.Length > 1) + { + visibleName = visibleName.Substring(0, 1) + visibleName.Substring(1).ToLower(); + } + + return visibleName; + } + + return givenKey.ToString(); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs b/src/Greenshot.Base/Controls/IGreenshotConfigBindable.cs similarity index 69% rename from GreenshotPlugin/Controls/IGreenshotConfigBindable.cs rename to src/Greenshot.Base/Controls/IGreenshotConfigBindable.cs index d20ed1cd1..7a4865031 100644 --- a/GreenshotPlugin/Controls/IGreenshotConfigBindable.cs +++ b/src/Greenshot.Base/Controls/IGreenshotConfigBindable.cs @@ -1,40 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -namespace GreenshotPlugin.Controls { - public interface IGreenshotConfigBindable { - /// - /// The class where the property-value is stored - /// - string SectionName { - get; - set; - } - - /// - /// Path to the property value which will be mapped with this control - /// - string PropertyName { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Controls +{ + public interface IGreenshotConfigBindable + { + /// + /// The class where the property-value is stored + /// + string SectionName { get; set; } + + /// + /// Path to the property value which will be mapped with this control + /// + string PropertyName { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/EventDelay.cs b/src/Greenshot.Base/Controls/IGreenshotLanguageBindable.cs similarity index 70% rename from GreenshotPlugin/Core/EventDelay.cs rename to src/Greenshot.Base/Controls/IGreenshotLanguageBindable.cs index c00306309..2a06d4f7e 100644 --- a/GreenshotPlugin/Core/EventDelay.cs +++ b/src/Greenshot.Base/Controls/IGreenshotLanguageBindable.cs @@ -19,23 +19,16 @@ * along with this program. If not, see . */ -using System; - -namespace GreenshotPlugin.Core { - public class EventDelay { - private long lastCheck; - private readonly long waitTime; - public EventDelay(long ticks) { - waitTime = ticks; - } - - public bool Check() { - lock (this) { - long now = DateTime.Now.Ticks; - bool isPassed = now - lastCheck > waitTime; - lastCheck = now; - return isPassed; - } - } - } -} +namespace Greenshot.Base.Controls +{ + /// + /// This interface describes the designer fields that need to be implemented for Greenshot controls + /// + public interface IGreenshotLanguageBindable + { + /// + /// Language key to use to fill the Text value with + /// + string LanguageKey { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs b/src/Greenshot.Base/Controls/OAuthLoginForm.Designer.cs similarity index 96% rename from GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs rename to src/Greenshot.Base/Controls/OAuthLoginForm.Designer.cs index abf92060c..f930762af 100644 --- a/GreenshotPlugin/Controls/OAuthLoginForm.Designer.cs +++ b/src/Greenshot.Base/Controls/OAuthLoginForm.Designer.cs @@ -1,92 +1,92 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -namespace GreenshotPlugin.Controls { - partial class OAuthLoginForm { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() { - this._addressTextBox = new System.Windows.Forms.TextBox(); - this._browser = new ExtendedWebBrowser(); - this.SuspendLayout(); - // - // _addressTextBox - // - this._addressTextBox.Cursor = System.Windows.Forms.Cursors.Arrow; - this._addressTextBox.Dock = System.Windows.Forms.DockStyle.Top; - this._addressTextBox.Enabled = false; - this._addressTextBox.Location = new System.Drawing.Point(0, 0); - this._addressTextBox.Name = "addressTextBox"; - this._addressTextBox.Size = new System.Drawing.Size(595, 20); - this._addressTextBox.TabIndex = 3; - this._addressTextBox.TabStop = false; - // - // _browser - // - this._browser.Dock = System.Windows.Forms.DockStyle.Fill; - this._browser.Location = new System.Drawing.Point(0, 20); - this._browser.MinimumSize = new System.Drawing.Size(100, 100); - this._browser.Name = "browser"; - this._browser.Size = new System.Drawing.Size(595, 295); - this._browser.TabIndex = 4; - // - // OAuthLoginForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(595, 315); - this.Controls.Add(this._browser); - this.Controls.Add(this._addressTextBox); - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "OAuthLoginForm"; - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.TextBox _addressTextBox; - private ExtendedWebBrowser _browser; - - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +namespace Greenshot.Base.Controls { + partial class OAuthLoginForm { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() { + this._addressTextBox = new System.Windows.Forms.TextBox(); + this._browser = new ExtendedWebBrowser(); + this.SuspendLayout(); + // + // _addressTextBox + // + this._addressTextBox.Cursor = System.Windows.Forms.Cursors.Arrow; + this._addressTextBox.Dock = System.Windows.Forms.DockStyle.Top; + this._addressTextBox.Enabled = false; + this._addressTextBox.Location = new System.Drawing.Point(0, 0); + this._addressTextBox.Name = "addressTextBox"; + this._addressTextBox.Size = new System.Drawing.Size(595, 20); + this._addressTextBox.TabIndex = 3; + this._addressTextBox.TabStop = false; + // + // _browser + // + this._browser.Dock = System.Windows.Forms.DockStyle.Fill; + this._browser.Location = new System.Drawing.Point(0, 20); + this._browser.MinimumSize = new System.Drawing.Size(100, 100); + this._browser.Name = "browser"; + this._browser.Size = new System.Drawing.Size(595, 295); + this._browser.TabIndex = 4; + // + // OAuthLoginForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(595, 315); + this.Controls.Add(this._browser); + this.Controls.Add(this._addressTextBox); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "OAuthLoginForm"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox _addressTextBox; + private ExtendedWebBrowser _browser; + + } +} diff --git a/src/Greenshot.Base/Controls/OAuthLoginForm.cs b/src/Greenshot.Base/Controls/OAuthLoginForm.cs new file mode 100644 index 000000000..4cbc1dc9c --- /dev/null +++ b/src/Greenshot.Base/Controls/OAuthLoginForm.cs @@ -0,0 +1,121 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Core; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// The OAuthLoginForm is used to allow the user to authorize Greenshot with an "Oauth" application + /// + public sealed partial class OAuthLoginForm : Form + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(OAuthLoginForm)); + private readonly string _callbackUrl; + + public IDictionary CallbackParameters { get; private set; } + + public bool IsOk => DialogResult == DialogResult.OK; + + public OAuthLoginForm(string browserTitle, Size size, string authorizationLink, string callbackUrl) + { + // Make sure Greenshot uses the correct browser version + IEHelper.FixBrowserVersion(false); + + _callbackUrl = callbackUrl; + // Fix for BUG-2071 + if (callbackUrl.EndsWith("/")) + { + _callbackUrl = callbackUrl.Substring(0, callbackUrl.Length - 1); + } + + InitializeComponent(); + ClientSize = size; + Icon = GreenshotResources.GetGreenshotIcon(); + Text = browserTitle; + _addressTextBox.Text = authorizationLink; + + // The script errors are suppressed by using the ExtendedWebBrowser + _browser.ScriptErrorsSuppressed = false; + _browser.DocumentCompleted += Browser_DocumentCompleted; + _browser.Navigated += Browser_Navigated; + _browser.Navigating += Browser_Navigating; + _browser.Navigate(new Uri(authorizationLink)); + } + + /// + /// Make sure the form is visible + /// + /// EventArgs + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + WindowDetails.ToForeground(Handle); + } + + private void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) + { + LOG.DebugFormat("document completed with url: {0}", _browser.Url); + CheckUrl(); + } + + private void Browser_Navigating(object sender, WebBrowserNavigatingEventArgs e) + { + LOG.DebugFormat("Navigating to url: {0}", _browser.Url); + _addressTextBox.Text = e.Url.ToString(); + } + + private void Browser_Navigated(object sender, WebBrowserNavigatedEventArgs e) + { + LOG.DebugFormat("Navigated to url: {0}", _browser.Url); + CheckUrl(); + } + + private void CheckUrl() + { + if (_browser.Url.ToString().StartsWith(_callbackUrl)) + { + var correctedUri = new Uri(_browser.Url.AbsoluteUri.Replace("#", "&")); + + string queryParams = correctedUri.Query; + if (queryParams.Length > 0) + { + queryParams = NetworkHelper.UrlDecode(queryParams); + //Store the Token and Token Secret + CallbackParameters = NetworkHelper.ParseQueryString(queryParams); + } + + DialogResult = DialogResult.OK; + } + } + + private void AddressTextBox_KeyPress(object sender, KeyPressEventArgs e) + { + //Cancel the key press so the user can't enter a new url + e.Handled = true; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs b/src/Greenshot.Base/Controls/PleaseWaitForm.Designer.cs similarity index 96% rename from GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs rename to src/Greenshot.Base/Controls/PleaseWaitForm.Designer.cs index a3ab2832b..3083b7bf2 100644 --- a/GreenshotPlugin/Controls/PleaseWaitForm.Designer.cs +++ b/src/Greenshot.Base/Controls/PleaseWaitForm.Designer.cs @@ -1,99 +1,99 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -namespace GreenshotPlugin.Controls { - partial class PleaseWaitForm { - /// - /// Designer variable used to keep track of non-visual components. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Disposes resources used by the form. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) { - if (disposing) { - if (components != null) { - components.Dispose(); - } - } - base.Dispose(disposing); - } - - /// - /// This method is required for Windows Forms designer support. - /// Do not change the method contents inside the source code editor. The Forms designer might - /// not be able to load this method if it was changed manually. - /// - private void InitializeComponent() { - this.label_pleasewait = new System.Windows.Forms.Label(); - this.cancelButton = new System.Windows.Forms.Button(); - this.SuspendLayout(); - // - // label_pleasewait - // - this.label_pleasewait.Dock = System.Windows.Forms.DockStyle.Fill; - this.label_pleasewait.Location = new System.Drawing.Point(0, 0); - this.label_pleasewait.Name = "label_pleasewait"; - this.label_pleasewait.Padding = new System.Windows.Forms.Padding(10); - this.label_pleasewait.Size = new System.Drawing.Size(90, 33); - this.label_pleasewait.TabIndex = 0; - this.label_pleasewait.Text = "Please wait..."; - this.label_pleasewait.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - this.label_pleasewait.UseWaitCursor = true; - // - // cancelButton - // - this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.cancelButton.Location = new System.Drawing.Point(38, 41); - this.cancelButton.Name = "cancelButton"; - this.cancelButton.Size = new System.Drawing.Size(94, 23); - this.cancelButton.TabIndex = 1; - this.cancelButton.Text = "Cancel"; - this.cancelButton.UseVisualStyleBackColor = true; - this.cancelButton.UseWaitCursor = true; - this.cancelButton.Click += new System.EventHandler(this.CancelButtonClick); - // - // PleaseWaitForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.CancelButton = this.cancelButton; - this.ClientSize = new System.Drawing.Size(169, 76); - this.Controls.Add(this.cancelButton); - this.Controls.Add(this.label_pleasewait); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "PleaseWaitForm"; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Greenshot"; - this.UseWaitCursor = true; - this.ResumeLayout(false); - this.PerformLayout(); - } - private System.Windows.Forms.Button cancelButton; - private System.Windows.Forms.Label label_pleasewait; - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +namespace Greenshot.Base.Controls { + partial class PleaseWaitForm { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() { + this.label_pleasewait = new System.Windows.Forms.Label(); + this.cancelButton = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label_pleasewait + // + this.label_pleasewait.Dock = System.Windows.Forms.DockStyle.Fill; + this.label_pleasewait.Location = new System.Drawing.Point(0, 0); + this.label_pleasewait.Name = "label_pleasewait"; + this.label_pleasewait.Padding = new System.Windows.Forms.Padding(10); + this.label_pleasewait.Size = new System.Drawing.Size(90, 33); + this.label_pleasewait.TabIndex = 0; + this.label_pleasewait.Text = "Please wait..."; + this.label_pleasewait.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.label_pleasewait.UseWaitCursor = true; + // + // cancelButton + // + this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cancelButton.Location = new System.Drawing.Point(38, 41); + this.cancelButton.Name = "cancelButton"; + this.cancelButton.Size = new System.Drawing.Size(94, 23); + this.cancelButton.TabIndex = 1; + this.cancelButton.Text = "Cancel"; + this.cancelButton.UseVisualStyleBackColor = true; + this.cancelButton.UseWaitCursor = true; + this.cancelButton.Click += new System.EventHandler(this.CancelButtonClick); + // + // PleaseWaitForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.CancelButton = this.cancelButton; + this.ClientSize = new System.Drawing.Size(169, 76); + this.Controls.Add(this.cancelButton); + this.Controls.Add(this.label_pleasewait); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "PleaseWaitForm"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Greenshot"; + this.UseWaitCursor = true; + this.ResumeLayout(false); + this.PerformLayout(); + } + private System.Windows.Forms.Button cancelButton; + private System.Windows.Forms.Label label_pleasewait; + } +} diff --git a/src/Greenshot.Base/Controls/PleaseWaitForm.cs b/src/Greenshot.Base/Controls/PleaseWaitForm.cs new file mode 100644 index 000000000..e87ab38ef --- /dev/null +++ b/src/Greenshot.Base/Controls/PleaseWaitForm.cs @@ -0,0 +1,143 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Threading; +using System.Windows.Forms; +using Greenshot.Base.Core; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// Description of PleaseWaitForm. + /// + public partial class PleaseWaitForm : Form + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(PleaseWaitForm)); + private Thread _waitFor; + private string _title; + + public PleaseWaitForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + Icon = GreenshotResources.GetGreenshotIcon(); + } + + /// + /// Prevent the close-window button showing + /// + private const int CP_NOCLOSE_BUTTON = 0x200; + + protected override CreateParams CreateParams + { + get + { + CreateParams createParams = base.CreateParams; + createParams.ClassStyle |= CP_NOCLOSE_BUTTON; + return createParams; + } + } + + /// + /// Show the "please wait" form, execute the code from the delegate and wait until execution finishes. + /// The supplied delegate will be wrapped with a try/catch so this method can return any exception that was thrown. + /// + /// The title of the form (and Thread) + /// The text in the form + /// delegate { with your code } + public void ShowAndWait(string title, string text, ThreadStart waitDelegate) + { + _title = title; + Text = title; + label_pleasewait.Text = text; + cancelButton.Text = Language.GetString("CANCEL"); + + // Make sure the form is shown. + Show(); + + // Variable to store the exception, if one is generated, from inside the thread. + Exception threadException = null; + try + { + // Wrap the passed delegate in a try/catch which makes it possible to save the exception + _waitFor = new Thread(new ThreadStart( + delegate + { + try + { + waitDelegate.Invoke(); + } + catch (Exception ex) + { + LOG.Error("invoke error:", ex); + threadException = ex; + } + }) + ) + { + Name = title, + IsBackground = true + }; + _waitFor.SetApartmentState(ApartmentState.STA); + _waitFor.Start(); + + // Wait until finished + while (!_waitFor.Join(TimeSpan.FromMilliseconds(100))) + { + Application.DoEvents(); + } + + LOG.DebugFormat("Finished {0}", title); + } + catch (Exception ex) + { + LOG.Error(ex); + throw; + } + finally + { + Close(); + } + + // Check if an exception occured, if so throw it + if (threadException != null) + { + throw threadException; + } + } + + /// + /// Called if the cancel button is clicked, will use Thread.Abort() + /// + /// + /// + private void CancelButtonClick(object sender, EventArgs e) + { + LOG.DebugFormat("Cancel clicked on {0}", _title); + cancelButton.Enabled = false; + _waitFor.Abort(); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Controls/QualityDialog.Designer.cs b/src/Greenshot.Base/Controls/QualityDialog.Designer.cs similarity index 90% rename from GreenshotPlugin/Controls/QualityDialog.Designer.cs rename to src/Greenshot.Base/Controls/QualityDialog.Designer.cs index 5f1c03fce..dd67f3358 100644 --- a/GreenshotPlugin/Controls/QualityDialog.Designer.cs +++ b/src/Greenshot.Base/Controls/QualityDialog.Designer.cs @@ -1,147 +1,147 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -namespace GreenshotPlugin.Controls { - partial class QualityDialog { - /// - /// Designer variable used to keep track of non-visual components. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Disposes resources used by the form. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing) { - if (components != null) { - components.Dispose(); - } - } - base.Dispose(disposing); - } - - /// - /// This method is required for Windows Forms designer support. - /// Do not change the method contents inside the source code editor. The Forms designer might - /// not be able to load this method if it was changed manually. - /// - private void InitializeComponent() - { - this.label_choosejpegquality = new GreenshotPlugin.Controls.GreenshotLabel(); - this.textBoxJpegQuality = new System.Windows.Forms.TextBox(); - this.trackBarJpegQuality = new System.Windows.Forms.TrackBar(); - this.checkbox_dontaskagain = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.button_ok = new GreenshotPlugin.Controls.GreenshotButton(); - this.checkBox_reduceColors = new System.Windows.Forms.CheckBox(); - ((System.ComponentModel.ISupportInitialize)(this.trackBarJpegQuality)).BeginInit(); - this.SuspendLayout(); - // - // label_choosejpegquality - // - this.label_choosejpegquality.Location = new System.Drawing.Point(12, 47); - this.label_choosejpegquality.Name = "label_choosejpegquality"; - this.label_choosejpegquality.Size = new System.Drawing.Size(268, 19); - this.label_choosejpegquality.TabIndex = 15; - this.label_choosejpegquality.LanguageKey = "jpegqualitydialog_choosejpegquality"; - // - // textBoxJpegQuality - // - this.textBoxJpegQuality.Location = new System.Drawing.Point(245, 69); - this.textBoxJpegQuality.Name = "textBoxJpegQuality"; - this.textBoxJpegQuality.ReadOnly = true; - this.textBoxJpegQuality.Size = new System.Drawing.Size(35, 20); - this.textBoxJpegQuality.TabIndex = 4; - this.textBoxJpegQuality.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; - // - // trackBarJpegQuality - // - this.trackBarJpegQuality.LargeChange = 10; - this.trackBarJpegQuality.Location = new System.Drawing.Point(12, 69); - this.trackBarJpegQuality.Maximum = 100; - this.trackBarJpegQuality.Name = "trackBarJpegQuality"; - this.trackBarJpegQuality.Size = new System.Drawing.Size(233, 45); - this.trackBarJpegQuality.TabIndex = 3; - this.trackBarJpegQuality.TickFrequency = 10; - this.trackBarJpegQuality.Scroll += new System.EventHandler(this.TrackBarJpegQualityScroll); - // - // checkbox_dontaskagain - // - this.checkbox_dontaskagain.CheckAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_dontaskagain.ImageAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_dontaskagain.Location = new System.Drawing.Point(12, 106); - this.checkbox_dontaskagain.Name = "checkbox_dontaskagain"; - this.checkbox_dontaskagain.LanguageKey = "qualitydialog_dontaskagain"; - this.checkbox_dontaskagain.Size = new System.Drawing.Size(268, 37); - this.checkbox_dontaskagain.TabIndex = 5; - this.checkbox_dontaskagain.TextAlign = System.Drawing.ContentAlignment.TopLeft; - this.checkbox_dontaskagain.UseVisualStyleBackColor = true; - // - // button_ok - // - this.button_ok.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.button_ok.Location = new System.Drawing.Point(205, 149); - this.button_ok.Name = "button_ok"; - this.button_ok.Size = new System.Drawing.Size(75, 23); - this.button_ok.TabIndex = 1; - this.button_ok.LanguageKey = "OK"; - this.button_ok.UseVisualStyleBackColor = true; - this.button_ok.Click += new System.EventHandler(this.Button_okClick); - // - // checkBox_reduceColors - // - this.checkBox_reduceColors.Location = new System.Drawing.Point(12, 11); - this.checkBox_reduceColors.Name = "checkBox_reduceColors"; - this.checkBox_reduceColors.Size = new System.Drawing.Size(95, 17); - this.checkBox_reduceColors.TabIndex = 2; - this.checkBox_reduceColors.Text = "settings_reducecolors"; - this.checkBox_reduceColors.UseVisualStyleBackColor = true; - // - // QualityDialog - // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; - this.ClientSize = new System.Drawing.Size(299, 184); - this.ControlBox = false; - this.Controls.Add(this.checkBox_reduceColors); - this.Controls.Add(this.button_ok); - this.Controls.Add(this.checkbox_dontaskagain); - this.Controls.Add(this.label_choosejpegquality); - this.Controls.Add(this.textBoxJpegQuality); - this.Controls.Add(this.trackBarJpegQuality); - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "QualityDialog"; - this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; - this.LanguageKey = "qualitydialog_title"; - ((System.ComponentModel.ISupportInitialize)(this.trackBarJpegQuality)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - private GreenshotPlugin.Controls.GreenshotButton button_ok; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_dontaskagain; - private System.Windows.Forms.TrackBar trackBarJpegQuality; - private System.Windows.Forms.TextBox textBoxJpegQuality; - private GreenshotPlugin.Controls.GreenshotLabel label_choosejpegquality; - private System.Windows.Forms.CheckBox checkBox_reduceColors; - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +namespace Greenshot.Base.Controls { + partial class QualityDialog { + /// + /// Designer variable used to keep track of non-visual components. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Disposes resources used by the form. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) { + if (components != null) { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + /// + /// This method is required for Windows Forms designer support. + /// Do not change the method contents inside the source code editor. The Forms designer might + /// not be able to load this method if it was changed manually. + /// + private void InitializeComponent() + { + this.label_choosejpegquality = new GreenshotLabel(); + this.textBoxJpegQuality = new System.Windows.Forms.TextBox(); + this.trackBarJpegQuality = new System.Windows.Forms.TrackBar(); + this.checkbox_dontaskagain = new GreenshotCheckBox(); + this.button_ok = new GreenshotButton(); + this.checkBox_reduceColors = new System.Windows.Forms.CheckBox(); + ((System.ComponentModel.ISupportInitialize)(this.trackBarJpegQuality)).BeginInit(); + this.SuspendLayout(); + // + // label_choosejpegquality + // + this.label_choosejpegquality.Location = new System.Drawing.Point(12, 47); + this.label_choosejpegquality.Name = "label_choosejpegquality"; + this.label_choosejpegquality.Size = new System.Drawing.Size(268, 19); + this.label_choosejpegquality.TabIndex = 15; + this.label_choosejpegquality.LanguageKey = "jpegqualitydialog_choosejpegquality"; + // + // textBoxJpegQuality + // + this.textBoxJpegQuality.Location = new System.Drawing.Point(245, 69); + this.textBoxJpegQuality.Name = "textBoxJpegQuality"; + this.textBoxJpegQuality.ReadOnly = true; + this.textBoxJpegQuality.Size = new System.Drawing.Size(35, 20); + this.textBoxJpegQuality.TabIndex = 4; + this.textBoxJpegQuality.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // trackBarJpegQuality + // + this.trackBarJpegQuality.LargeChange = 10; + this.trackBarJpegQuality.Location = new System.Drawing.Point(12, 69); + this.trackBarJpegQuality.Maximum = 100; + this.trackBarJpegQuality.Name = "trackBarJpegQuality"; + this.trackBarJpegQuality.Size = new System.Drawing.Size(233, 45); + this.trackBarJpegQuality.TabIndex = 3; + this.trackBarJpegQuality.TickFrequency = 10; + this.trackBarJpegQuality.Scroll += new System.EventHandler(this.TrackBarJpegQualityScroll); + // + // checkbox_dontaskagain + // + this.checkbox_dontaskagain.CheckAlign = System.Drawing.ContentAlignment.TopLeft; + this.checkbox_dontaskagain.ImageAlign = System.Drawing.ContentAlignment.TopLeft; + this.checkbox_dontaskagain.Location = new System.Drawing.Point(12, 106); + this.checkbox_dontaskagain.Name = "checkbox_dontaskagain"; + this.checkbox_dontaskagain.LanguageKey = "qualitydialog_dontaskagain"; + this.checkbox_dontaskagain.Size = new System.Drawing.Size(268, 37); + this.checkbox_dontaskagain.TabIndex = 5; + this.checkbox_dontaskagain.TextAlign = System.Drawing.ContentAlignment.TopLeft; + this.checkbox_dontaskagain.UseVisualStyleBackColor = true; + // + // button_ok + // + this.button_ok.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button_ok.Location = new System.Drawing.Point(205, 149); + this.button_ok.Name = "button_ok"; + this.button_ok.Size = new System.Drawing.Size(75, 23); + this.button_ok.TabIndex = 1; + this.button_ok.LanguageKey = "OK"; + this.button_ok.UseVisualStyleBackColor = true; + this.button_ok.Click += new System.EventHandler(this.Button_okClick); + // + // checkBox_reduceColors + // + this.checkBox_reduceColors.Location = new System.Drawing.Point(12, 11); + this.checkBox_reduceColors.Name = "checkBox_reduceColors"; + this.checkBox_reduceColors.Size = new System.Drawing.Size(95, 17); + this.checkBox_reduceColors.TabIndex = 2; + this.checkBox_reduceColors.Text = "settings_reducecolors"; + this.checkBox_reduceColors.UseVisualStyleBackColor = true; + // + // QualityDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.ClientSize = new System.Drawing.Size(299, 184); + this.ControlBox = false; + this.Controls.Add(this.checkBox_reduceColors); + this.Controls.Add(this.button_ok); + this.Controls.Add(this.checkbox_dontaskagain); + this.Controls.Add(this.label_choosejpegquality); + this.Controls.Add(this.textBoxJpegQuality); + this.Controls.Add(this.trackBarJpegQuality); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "QualityDialog"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.LanguageKey = "qualitydialog_title"; + ((System.ComponentModel.ISupportInitialize)(this.trackBarJpegQuality)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + private GreenshotButton button_ok; + private GreenshotCheckBox checkbox_dontaskagain; + private System.Windows.Forms.TrackBar trackBarJpegQuality; + private System.Windows.Forms.TextBox textBoxJpegQuality; + private GreenshotLabel label_choosejpegquality; + private System.Windows.Forms.CheckBox checkBox_reduceColors; + } +} diff --git a/src/Greenshot.Base/Controls/QualityDialog.cs b/src/Greenshot.Base/Controls/QualityDialog.cs new file mode 100644 index 000000000..1da67eb2b --- /dev/null +++ b/src/Greenshot.Base/Controls/QualityDialog.cs @@ -0,0 +1,71 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Base.Controls +{ + /// + /// Description of JpegQualityDialog. + /// + public partial class QualityDialog : GreenshotForm + { + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + public SurfaceOutputSettings Settings { get; set; } + + public QualityDialog(SurfaceOutputSettings outputSettings) + { + Settings = outputSettings; + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + + checkBox_reduceColors.Checked = Settings.ReduceColors; + trackBarJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); + trackBarJpegQuality.Value = Settings.JPGQuality; + textBoxJpegQuality.Enabled = OutputFormat.jpg.Equals(outputSettings.Format); + textBoxJpegQuality.Text = Settings.JPGQuality.ToString(); + ToFront = true; + } + + private void Button_okClick(object sender, EventArgs e) + { + Settings.JPGQuality = trackBarJpegQuality.Value; + Settings.ReduceColors = checkBox_reduceColors.Checked; + if (checkbox_dontaskagain.Checked) + { + conf.OutputFileJpegQuality = Settings.JPGQuality; + conf.OutputFilePromptQuality = false; + conf.OutputFileReduceColors = Settings.ReduceColors; + IniConfig.Save(); + } + } + + private void TrackBarJpegQualityScroll(object sender, EventArgs e) + { + textBoxJpegQuality.Text = trackBarJpegQuality.Value.ToString(); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Controls/SaveImageFileDialog.cs b/src/Greenshot.Base/Controls/SaveImageFileDialog.cs new file mode 100644 index 000000000..d95702547 --- /dev/null +++ b/src/Greenshot.Base/Controls/SaveImageFileDialog.cs @@ -0,0 +1,235 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using log4net; + +namespace Greenshot.Base.Controls +{ + /// + /// Custom dialog for saving images, wraps SaveFileDialog. + /// For some reason SFD is sealed :( + /// + public class SaveImageFileDialog : IDisposable + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(SaveImageFileDialog)); + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + protected SaveFileDialog SaveFileDialog; + private FilterOption[] _filterOptions; + private DirectoryInfo _eagerlyCreatedDirectory; + private readonly ICaptureDetails _captureDetails; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (SaveFileDialog != null) + { + SaveFileDialog.Dispose(); + SaveFileDialog = null; + } + } + } + + public SaveImageFileDialog(ICaptureDetails captureDetails) + { + _captureDetails = captureDetails; + Init(); + } + + private void Init() + { + SaveFileDialog = new SaveFileDialog(); + ApplyFilterOptions(); + string initialDirectory = null; + try + { + conf.ValidateAndCorrectOutputFileAsFullpath(); + initialDirectory = Path.GetDirectoryName(conf.OutputFileAsFullpath); + } + catch + { + LOG.WarnFormat("OutputFileAsFullpath was set to {0}, ignoring due to problem in path.", conf.OutputFileAsFullpath); + } + + if (!string.IsNullOrEmpty(initialDirectory) && Directory.Exists(initialDirectory)) + { + SaveFileDialog.InitialDirectory = initialDirectory; + } + else if (Directory.Exists(conf.OutputFilePath)) + { + SaveFileDialog.InitialDirectory = conf.OutputFilePath; + } + + // The following property fixes a problem that the directory where we save is locked (bug #2899790) + SaveFileDialog.RestoreDirectory = true; + SaveFileDialog.OverwritePrompt = true; + SaveFileDialog.CheckPathExists = false; + SaveFileDialog.AddExtension = true; + ApplySuggestedValues(); + } + + private void ApplyFilterOptions() + { + PrepareFilterOptions(); + string fdf = string.Empty; + int preselect = 0; + var outputFileFormatAsString = Enum.GetName(typeof(OutputFormat), conf.OutputFileFormat); + for (int i = 0; i < _filterOptions.Length; i++) + { + FilterOption fo = _filterOptions[i]; + fdf += fo.Label + "|*." + fo.Extension + "|"; + if (outputFileFormatAsString == fo.Extension) + preselect = i; + } + + fdf = fdf.Substring(0, fdf.Length - 1); + SaveFileDialog.Filter = fdf; + SaveFileDialog.FilterIndex = preselect + 1; + } + + private void PrepareFilterOptions() + { + OutputFormat[] supportedImageFormats = (OutputFormat[]) Enum.GetValues(typeof(OutputFormat)); + _filterOptions = new FilterOption[supportedImageFormats.Length]; + for (int i = 0; i < _filterOptions.Length; i++) + { + string ifo = supportedImageFormats[i].ToString(); + if (ifo.ToLower().Equals("jpeg")) ifo = "Jpg"; // we dont want no jpeg files, so let the dialog check for jpg + FilterOption fo = new FilterOption + { + Label = ifo.ToUpper(), + Extension = ifo.ToLower() + }; + _filterOptions.SetValue(fo, i); + } + } + + /// + /// filename exactly as typed in the filename field + /// + public string FileName + { + get { return SaveFileDialog.FileName; } + set { SaveFileDialog.FileName = value; } + } + + /// + /// initial directory of the dialog + /// + public string InitialDirectory + { + get { return SaveFileDialog.InitialDirectory; } + set { SaveFileDialog.InitialDirectory = value; } + } + + /// + /// returns filename as typed in the filename field with extension. + /// if filename field value ends with selected extension, the value is just returned. + /// otherwise, the selected extension is appended to the filename. + /// + public string FileNameWithExtension + { + get + { + string fn = SaveFileDialog.FileName; + // if the filename contains a valid extension, which is the same like the selected filter item's extension, the filename is okay + if (fn.EndsWith(Extension, StringComparison.CurrentCultureIgnoreCase)) return fn; + // otherwise we just add the selected filter item's extension + else return fn + "." + Extension; + } + set + { + FileName = Path.GetFileNameWithoutExtension(value); + Extension = Path.GetExtension(value); + } + } + + /// + /// gets or sets selected extension + /// + public string Extension + { + get { return _filterOptions[SaveFileDialog.FilterIndex - 1].Extension; } + set + { + for (int i = 0; i < _filterOptions.Length; i++) + { + if (value.Equals(_filterOptions[i].Extension, StringComparison.CurrentCultureIgnoreCase)) + { + SaveFileDialog.FilterIndex = i + 1; + } + } + } + } + + public DialogResult ShowDialog() + { + DialogResult ret = SaveFileDialog.ShowDialog(); + CleanUp(); + return ret; + } + + /// + /// sets InitialDirectory and FileName property of a SaveFileDialog smartly, considering default pattern and last used path + /// + private void ApplySuggestedValues() + { + // build the full path and set dialog properties + FileName = FilenameHelper.GetFilenameWithoutExtensionFromPattern(conf.OutputFileFilenamePattern, _captureDetails); + } + + private class FilterOption + { + public string Label; + public string Extension; + } + + private void CleanUp() + { + // fix for bug #3379053 + try + { + if (_eagerlyCreatedDirectory != null && _eagerlyCreatedDirectory.GetFiles().Length == 0 && _eagerlyCreatedDirectory.GetDirectories().Length == 0) + { + _eagerlyCreatedDirectory.Delete(); + _eagerlyCreatedDirectory = null; + } + } + catch (Exception e) + { + LOG.WarnFormat("Couldn't cleanup directory due to: {0}", e.Message); + _eagerlyCreatedDirectory = null; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Controls/ThumbnailForm.cs b/src/Greenshot.Base/Controls/ThumbnailForm.cs new file mode 100644 index 000000000..16d597f3c --- /dev/null +++ b/src/Greenshot.Base/Controls/ThumbnailForm.cs @@ -0,0 +1,156 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; + +namespace Greenshot.Base.Controls +{ + /// + /// This form allows us to show a Thumbnail preview of a window near the context menu when selecting a window to capture. + /// Didn't make it completely "generic" yet, but at least most logic is in here so we don't have it in the mainform. + /// + public sealed class ThumbnailForm : FormWithoutActivation + { + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + + private IntPtr _thumbnailHandle = IntPtr.Zero; + + public ThumbnailForm() + { + ShowInTaskbar = false; + FormBorderStyle = FormBorderStyle.None; + TopMost = false; + Enabled = false; + if (conf.WindowCaptureMode == WindowCaptureMode.Auto || conf.WindowCaptureMode == WindowCaptureMode.Aero) + { + BackColor = Color.FromArgb(255, conf.DWMBackgroundColor.R, conf.DWMBackgroundColor.G, conf.DWMBackgroundColor.B); + } + else + { + BackColor = Color.White; + } + + // cleanup at close + FormClosing += delegate { UnregisterThumbnail(); }; + } + + public new void Hide() + { + UnregisterThumbnail(); + base.Hide(); + } + + private void UnregisterThumbnail() + { + if (_thumbnailHandle == IntPtr.Zero) return; + + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + _thumbnailHandle = IntPtr.Zero; + } + + /// + /// Show the thumbnail of the supplied window above (or under) the parent Control + /// + /// WindowDetails + /// Control + public void ShowThumbnail(WindowDetails window, Control parentControl) + { + UnregisterThumbnail(); + + DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle); + if (_thumbnailHandle == IntPtr.Zero) return; + + var result = DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize); + if (result.Failed()) + { + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + return; + } + + if (sourceSize.IsEmpty) + { + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + return; + } + + int thumbnailHeight = 200; + int thumbnailWidth = (int) (thumbnailHeight * (sourceSize.Width / (float) sourceSize.Height)); + if (parentControl != null && thumbnailWidth > parentControl.Width) + { + thumbnailWidth = parentControl.Width; + thumbnailHeight = (int) (thumbnailWidth * (sourceSize.Height / (float) sourceSize.Width)); + } + + Width = thumbnailWidth; + Height = thumbnailHeight; + // Prepare the displaying of the Thumbnail + var dwmThumbnailProperties = new DWM_THUMBNAIL_PROPERTIES + { + Opacity = 255, + Visible = true, + SourceClientAreaOnly = false, + Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight) + }; + result = DWM.DwmUpdateThumbnailProperties(_thumbnailHandle, ref dwmThumbnailProperties); + if (result.Failed()) + { + DWM.DwmUnregisterThumbnail(_thumbnailHandle); + return; + } + + if (parentControl != null) + { + AlignToControl(parentControl); + } + + if (!Visible) + { + Show(); + } + + // Make sure it's on "top"! + if (parentControl != null) + { + User32.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE); + } + } + + public void AlignToControl(Control alignTo) + { + var screenBounds = WindowCapture.GetScreenBounds(); + if (screenBounds.Contains(alignTo.Left, alignTo.Top - Height)) + { + Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Top - Height); + } + else + { + Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Bottom); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/AbstractDestination.cs b/src/Greenshot.Base/Core/AbstractDestination.cs new file mode 100644 index 000000000..c9864f99b --- /dev/null +++ b/src/Greenshot.Base/Core/AbstractDestination.cs @@ -0,0 +1,416 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Threading; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.UnmanagedHelpers; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// Description of AbstractDestination. + /// + public abstract class AbstractDestination : IDestination + { + private static readonly ILog Log = LogManager.GetLogger(typeof(AbstractDestination)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + + public virtual int CompareTo(object obj) + { + if (!(obj is IDestination other)) + { + return 1; + } + + if (Priority == other.Priority) + { + return string.Compare(Description, other.Description, StringComparison.Ordinal); + } + + return Priority - other.Priority; + } + + public abstract string Designation { get; } + + public abstract string Description { get; } + + public virtual int Priority => 10; + + public virtual Image DisplayIcon => null; + + public virtual Keys EditorShortcutKeys => Keys.None; + + public virtual IEnumerable DynamicDestinations() + { + yield break; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + //if (disposing) {} + } + + public virtual bool IsDynamic => false; + + public virtual bool UseDynamicsOnly => false; + + public virtual bool IsLinkable => false; + + public virtual bool IsActive + { + get + { + if (CoreConfig.ExcludeDestinations != null && CoreConfig.ExcludeDestinations.Contains(Designation)) + { + return false; + } + + return true; + } + } + + public abstract ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); + + /// + /// A small helper method to perform some default destination actions, like inform the surface of the export + /// + /// + /// + public void ProcessExport(ExportInformation exportInformation, ISurface surface) + { + if (exportInformation != null && exportInformation.ExportMade) + { + if (!string.IsNullOrEmpty(exportInformation.Uri)) + { + surface.UploadUrl = exportInformation.Uri; + surface.SendMessageEvent(this, SurfaceMessageTyp.UploadedUri, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); + } + else if (!string.IsNullOrEmpty(exportInformation.Filepath)) + { + surface.LastSaveFullPath = exportInformation.Filepath; + surface.SendMessageEvent(this, SurfaceMessageTyp.FileSaved, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); + } + else + { + surface.SendMessageEvent(this, SurfaceMessageTyp.Info, Language.GetFormattedString("exported_to", exportInformation.DestinationDescription)); + } + + surface.Modified = false; + } + else if (!string.IsNullOrEmpty(exportInformation?.ErrorMessage)) + { + surface.SendMessageEvent(this, SurfaceMessageTyp.Error, + Language.GetFormattedString("exported_to_error", exportInformation.DestinationDescription) + " " + exportInformation.ErrorMessage); + } + } + + public override string ToString() + { + return Description; + } + + /// + /// Helper method to add events which set the tag, this way we can see why there might be a close. + /// + /// Item to add the events to + /// Menu to set the tag + /// Value for the tag + private void AddTagEvents(ToolStripMenuItem menuItem, ContextMenuStrip menu, string tagValue) + { + if (menuItem != null && menu != null) + { + menuItem.MouseDown += delegate + { + Log.DebugFormat("Setting tag to '{0}'", tagValue); + menu.Tag = tagValue; + }; + menuItem.MouseUp += delegate + { + Log.Debug("Deleting tag"); + menu.Tag = null; + }; + } + } + + /// + /// This method will create and show the destination picker menu + /// + /// Boolean if the dynamic values also need to be added + /// The surface which can be exported + /// Details for the surface + /// The list of destinations to show + /// + public ExportInformation ShowPickerMenu(bool addDynamics, ISurface surface, ICaptureDetails captureDetails, IEnumerable destinations) + { + // Generate an empty ExportInformation object, for when nothing was selected. + ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker")); + var menu = new ContextMenuStrip + { + ImageScalingSize = CoreConfig.ScaledIconSize, + Tag = null, + TopLevel = true + }; + + menu.Opening += (sender, args) => + { + // find the DPI settings for the screen where this is going to land + var screenDpi = DpiHelper.GetDpi(menu.Location); + var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, screenDpi); + menu.SuspendLayout(); + var fontSize = DpiHelper.ScaleWithDpi(12f, screenDpi); + menu.Font = new Font(FontFamily.GenericSansSerif, fontSize, FontStyle.Regular, GraphicsUnit.Pixel); + menu.ImageScalingSize = scaledIconSize; + menu.ResumeLayout(); + }; + + menu.Closing += delegate(object source, ToolStripDropDownClosingEventArgs eventArgs) + { + Log.DebugFormat("Close reason: {0}", eventArgs.CloseReason); + switch (eventArgs.CloseReason) + { + case ToolStripDropDownCloseReason.AppFocusChange: + if (menu.Tag == null) + { + // Do not allow the close if the tag is not set, this means the user clicked somewhere else. + eventArgs.Cancel = true; + } + else + { + Log.DebugFormat("Letting the menu 'close' as the tag is set to '{0}'", menu.Tag); + } + + break; + case ToolStripDropDownCloseReason.ItemClicked: + case ToolStripDropDownCloseReason.CloseCalled: + // The ContextMenuStrip can be "closed" for these reasons. + break; + case ToolStripDropDownCloseReason.Keyboard: + // Dispose as the close is clicked + if (!captureDetails.HasDestination("Editor")) + { + surface.Dispose(); + surface = null; + } + + break; + default: + eventArgs.Cancel = true; + break; + } + }; + menu.MouseEnter += delegate + { + // in case the menu has been unfocused, focus again so that dropdown menus will still open on mouseenter + if (!menu.ContainsFocus) + { + menu.Focus(); + } + }; + foreach (IDestination destination in destinations) + { + // Fix foreach loop variable for the delegate + ToolStripMenuItem item = destination.GetMenuItem(addDynamics, menu, + delegate(object sender, EventArgs e) + { + ToolStripMenuItem toolStripMenuItem = sender as ToolStripMenuItem; + IDestination clickedDestination = (IDestination) toolStripMenuItem?.Tag; + if (clickedDestination == null) + { + return; + } + + menu.Tag = clickedDestination.Designation; + // Export + exportInformation = clickedDestination.ExportCapture(true, surface, captureDetails); + if (exportInformation != null && exportInformation.ExportMade) + { + Log.InfoFormat("Export to {0} success, closing menu", exportInformation.DestinationDescription); + // close menu if the destination wasn't the editor + menu.Close(); + + // Cleanup surface, only if there is no editor in the destinations and we didn't export to the editor + if (!captureDetails.HasDestination("Editor") && !"Editor".Equals(clickedDestination.Designation)) + { + surface.Dispose(); + surface = null; + } + } + else + { + Log.Info("Export cancelled or failed, showing menu again"); + + // Make sure a click besides the menu don't close it. + menu.Tag = null; + + // This prevents the problem that the context menu shows in the task-bar + ShowMenuAtCursor(menu); + } + } + ); + if (item != null) + { + menu.Items.Add(item); + } + } + + // Close + menu.Items.Add(new ToolStripSeparator()); + ToolStripMenuItem closeItem = new ToolStripMenuItem(Language.GetString("editor_close")) + { + Image = GreenshotResources.GetImage("Close.Image") + }; + closeItem.Click += delegate + { + // This menu entry is the close itself, we can dispose the surface + menu.Close(); + if (!captureDetails.HasDestination("Editor")) + { + surface.Dispose(); + surface = null; + } + }; + menu.Items.Add(closeItem); + + ShowMenuAtCursor(menu); + return exportInformation; + } + + /// + /// This method will show the supplied context menu at the mouse cursor, also makes sure it has focus and it's not visible in the taskbar. + /// + /// + private static void ShowMenuAtCursor(ContextMenuStrip menu) + { + // find a suitable location + Point location = Cursor.Position; + Rectangle menuRectangle = new Rectangle(location, menu.Size); + + menuRectangle.Intersect(WindowCapture.GetScreenBounds()); + if (menuRectangle.Height < menu.Height) + { + location.Offset(-40, -(menuRectangle.Height - menu.Height)); + } + else + { + location.Offset(-40, -10); + } + + // This prevents the problem that the context menu shows in the task-bar + User32.SetForegroundWindow(SimpleServiceProvider.Current.GetInstance().ContextMenuStrip.Handle); + menu.Show(location); + menu.Focus(); + + // Wait for the menu to close, so we can dispose it. + while (true) + { + if (menu.Visible) + { + Application.DoEvents(); + Thread.Sleep(100); + } + else + { + menu.Dispose(); + break; + } + } + } + + /// + /// Return a menu item + /// + /// + /// + /// + /// ToolStripMenuItem + public virtual ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler) + { + var basisMenuItem = new ToolStripMenuItem(Description) + { + Image = DisplayIcon, + Tag = this, + Text = Description + }; + AddTagEvents(basisMenuItem, menu, Description); + basisMenuItem.Click -= destinationClickHandler; + basisMenuItem.Click += destinationClickHandler; + + if (IsDynamic && addDynamics) + { + basisMenuItem.DropDownOpening += delegate + { + if (basisMenuItem.DropDownItems.Count == 0) + { + List subDestinations = new List(); + // Fixing Bug #3536968 by catching the COMException (every exception) and not displaying the "subDestinations" + try + { + subDestinations.AddRange(DynamicDestinations()); + } + catch (Exception ex) + { + Log.ErrorFormat("Skipping {0}, due to the following error: {1}", Description, ex.Message); + } + + if (subDestinations.Count > 0) + { + if (UseDynamicsOnly && subDestinations.Count == 1) + { + basisMenuItem.Tag = subDestinations[0]; + basisMenuItem.Text = subDestinations[0].Description; + basisMenuItem.Click -= destinationClickHandler; + basisMenuItem.Click += destinationClickHandler; + } + else + { + foreach (IDestination subDestination in subDestinations) + { + var destinationMenuItem = new ToolStripMenuItem(subDestination.Description) + { + Tag = subDestination, + Image = subDestination.DisplayIcon + }; + destinationMenuItem.Click += destinationClickHandler; + AddTagEvents(destinationMenuItem, menu, subDestination.Description); + basisMenuItem.DropDownItems.Add(destinationMenuItem); + } + } + } + } + }; + } + + return basisMenuItem; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/AbstractProcessor.cs b/src/Greenshot.Base/Core/AbstractProcessor.cs similarity index 50% rename from GreenshotPlugin/Core/AbstractProcessor.cs rename to src/Greenshot.Base/Core/AbstractProcessor.cs index f93a405fb..b82d11e46 100644 --- a/GreenshotPlugin/Core/AbstractProcessor.cs +++ b/src/Greenshot.Base/Core/AbstractProcessor.cs @@ -1,63 +1,68 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using GreenshotPlugin.Interfaces; - -namespace GreenshotPlugin.Core { - /// - /// Description of AbstractProcessor. - /// - public abstract class AbstractProcessor : IProcessor { - - public virtual int CompareTo(object obj) { - if (!(obj is IProcessor other)) { - return 1; - } - if (Priority == other.Priority) { - return string.Compare(Description, other.Description, StringComparison.Ordinal); - } - return Priority - other.Priority; - } - - public abstract string Designation { - get; - } - - public abstract string Description { - get; - } - - public virtual int Priority => 10; - - public void Dispose() { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) { - //if (disposing) {} - } - - public virtual bool isActive => true; - - public abstract bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Base.Core +{ + /// + /// Description of AbstractProcessor. + /// + public abstract class AbstractProcessor : IProcessor + { + public virtual int CompareTo(object obj) + { + if (!(obj is IProcessor other)) + { + return 1; + } + + if (Priority == other.Priority) + { + return string.Compare(Description, other.Description, StringComparison.Ordinal); + } + + return Priority - other.Priority; + } + + public abstract string Designation { get; } + + public abstract string Description { get; } + + public virtual int Priority => 10; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + //if (disposing) {} + } + + public virtual bool isActive => true; + + public abstract bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/AccessibleHelper.cs b/src/Greenshot.Base/Core/AccessibleHelper.cs new file mode 100644 index 000000000..31fca4e83 --- /dev/null +++ b/src/Greenshot.Base/Core/AccessibleHelper.cs @@ -0,0 +1,237 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Accessibility; + +namespace Greenshot.Base.Core +{ + /// + /// See: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/03a8c835-e9e4-405b-8345-6c3d36bc8941 + /// This should really be cleaned up, there is little OO behind this class! + /// Maybe move the basic Accessible functions to WindowDetails!? + /// + public class Accessible + { + private static int AccessibleObjectFromWindow(IntPtr hWnd, OBJID idObject, ref IAccessible acc) + { + var guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible + object obj = null; + int num = AccessibleObjectFromWindow(hWnd, (uint) idObject, ref guid, ref obj); + acc = (IAccessible) obj; + return num; + } + + [DllImport("oleacc.dll")] + private static extern int AccessibleObjectFromWindow(IntPtr hWnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] + ref object ppvObject); + + [DllImport("oleacc.dll")] + private static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] + object[] rgvarChildren, out int pcObtained); + + [DllImport("oleacc.dll", PreserveSig = false)] + [return: MarshalAs(UnmanagedType.Interface)] + public static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam); + + private enum OBJID : uint + { + OBJID_WINDOW = 0x00000000, + } + + private const int IE_ACTIVE_TAB = 2097154; + private const int CHILDID_SELF = 0; + private readonly IAccessible accessible; + + private Accessible[] Children + { + get + { + object[] res = GetAccessibleChildren(accessible, out var num); + if (res == null) + { + return new Accessible[0]; + } + + List list = new List(res.Length); + foreach (object obj in res) + { + if (obj is IAccessible acc) + { + list.Add(new Accessible(acc)); + } + } + + return list.ToArray(); + } + } + + private string Name + { + get { return accessible.get_accName(CHILDID_SELF); } + } + + private int ChildCount + { + get { return accessible.accChildCount; } + } + + public Accessible(IntPtr hWnd) + { + AccessibleObjectFromWindow(hWnd, OBJID.OBJID_WINDOW, ref accessible); + if (accessible == null) + { + throw new Exception(); + } + } + + public void ActivateIETab(int tabIndexToActivate) + { + var index = 0; + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + if (tabIndexToActivate >= child.ChildCount - 1) + { + return; + } + + if (index == tabIndexToActivate) + { + tab.Activate(); + return; + } + + index++; + } + } + } + } + + public string IEActiveTabCaption + { + get + { + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + object tabIndex = tab.accessible.get_accState(0); + + if ((int) tabIndex == IE_ACTIVE_TAB) + { + return tab.Name; + } + } + } + } + + return string.Empty; + } + } + + public List IETabCaptions + { + get + { + var captionList = new List(); + + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + captionList.Add(tab.Name); + } + } + } + + // TODO: Why again? + if (captionList.Count > 0) + { + captionList.RemoveAt(captionList.Count - 1); + } + + return captionList; + } + } + + + public IEnumerable IETabUrls + { + get + { + foreach (Accessible accessor in Children) + { + foreach (var child in accessor.Children) + { + foreach (var tab in child.Children) + { + object tabIndex = tab.accessible.get_accState(CHILDID_SELF); + var description = tab.accessible.get_accDescription(CHILDID_SELF); + if (!string.IsNullOrEmpty(description)) + { + if (description.Contains(Environment.NewLine)) + { + var url = description.Substring(description.IndexOf(Environment.NewLine)).Trim(); + yield return url; + } + } + } + } + } + } + } + + private Accessible(IAccessible acc) + { + accessible = acc ?? throw new Exception(); + } + + private void Activate() + { + accessible.accDoDefaultAction(CHILDID_SELF); + } + + private static object[] GetAccessibleChildren(IAccessible ao, out int childs) + { + childs = 0; + object[] ret = null; + int count = ao.accChildCount; + + if (count > 0) + { + ret = new object[count]; + AccessibleChildren(ao, 0, count, ret, out childs); + } + + return ret; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/AnimationHelpers.cs b/src/Greenshot.Base/Core/AnimationHelpers.cs new file mode 100644 index 000000000..0d96016ab --- /dev/null +++ b/src/Greenshot.Base/Core/AnimationHelpers.cs @@ -0,0 +1,610 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; + +namespace Greenshot.Base.Core +{ + /// + /// Helper interface for passing base type + /// + public interface IAnimator + { + /// + /// Is there a next frame? + /// + bool HasNext { get; } + + /// + /// The amount of frames + /// + int Frames { get; } + + /// + /// Current frame number + /// + int CurrentFrameNr { get; } + } + + /// + /// This class is used to store a animation leg + /// + internal class AnimationLeg + { + public T Destination { get; set; } + + public int Frames { get; set; } + + public EasingType EasingType { get; set; } + + public EasingMode EasingMode { get; set; } + } + + /// + /// Base class for the animation logic, this only implements Properties and a constructor + /// + /// Type for the animation, like Point/Rectangle/Size + public abstract class AnimatorBase : IAnimator + { + private readonly Queue> _queue = new Queue>(); + + /// + /// Constructor + /// + /// + /// + /// + /// + /// + public AnimatorBase(T first, T last, int frames, EasingType easingType, EasingMode easingMode) + { + First = first; + Last = last; + Frames = frames; + Current = first; + EasingType = easingType; + EasingMode = easingMode; + } + + /// + /// The amount of frames + /// + public int Frames { get; private set; } + + /// + /// Current frame number + /// + public int CurrentFrameNr { get; private set; } + + /// + /// First animation value + /// + public T First { get; private set; } + + /// + /// Last animation value, of this "leg" + /// + public T Last { get; private set; } + + /// + /// Final animation value, this is including the legs + /// + public T Final + { + get + { + if (_queue.Count == 0) + { + return Last; + } + + return _queue.ToArray()[_queue.Count - 1].Destination; + } + } + + /// + /// This restarts the current animation and changes the last frame + /// + /// + public void ChangeDestination(T newDestination) + { + ChangeDestination(newDestination, Frames); + } + + /// + /// This restarts the current animation and changes the last frame + /// + /// + /// + public void ChangeDestination(T newDestination, int frames) + { + _queue.Clear(); + First = Current; + CurrentFrameNr = 0; + Frames = frames; + Last = newDestination; + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// All values will stay the same + /// + /// + public void QueueDestinationLeg(T queuedDestination) + { + QueueDestinationLeg(queuedDestination, Frames, EasingType, EasingMode); + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// + /// + /// + public void QueueDestinationLeg(T queuedDestination, int frames) + { + QueueDestinationLeg(queuedDestination, frames, EasingType, EasingMode); + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// + /// + /// + /// EasingType + public void QueueDestinationLeg(T queuedDestination, int frames, EasingType easingType) + { + QueueDestinationLeg(queuedDestination, frames, easingType, EasingMode); + } + + /// + /// Queue the destination, it will be used to continue at the last frame + /// + /// + /// + /// + /// + public void QueueDestinationLeg(T queuedDestination, int frames, EasingType easingType, EasingMode easingMode) + { + AnimationLeg leg = new AnimationLeg + { + Destination = queuedDestination, + Frames = frames, + EasingType = easingType, + EasingMode = easingMode + }; + _queue.Enqueue(leg); + } + + /// + /// The EasingType to use for the animation + /// + public EasingType EasingType { get; set; } + + /// + /// The EasingMode to use for the animation + /// + public EasingMode EasingMode { get; set; } + + /// + /// Get the easing value, which is from 0-1 and depends on the frame + /// + protected double EasingValue + { + get => + EasingMode switch + { + EasingMode.EaseOut => Easing.EaseOut(CurrentFrameNr / (double) Frames, EasingType), + EasingMode.EaseInOut => Easing.EaseInOut(CurrentFrameNr / (double) Frames, EasingType), + EasingMode.EaseIn => Easing.EaseIn(CurrentFrameNr / (double) Frames, EasingType), + _ => Easing.EaseIn(CurrentFrameNr / (double) Frames, EasingType) + }; + } + + /// + /// Get the current (previous) frame object + /// + public virtual T Current { get; set; } + + /// + /// Returns if there are any frame left, and if this is the case than the frame is increased. + /// + public virtual bool NextFrame + { + get + { + if (CurrentFrameNr < Frames) + { + CurrentFrameNr++; + return true; + } + + if (_queue.Count > 0) + { + First = Current; + CurrentFrameNr = 0; + AnimationLeg nextLeg = _queue.Dequeue(); + Last = nextLeg.Destination; + Frames = nextLeg.Frames; + EasingType = nextLeg.EasingType; + EasingMode = nextLeg.EasingMode; + return true; + } + + return false; + } + } + + /// + /// Are there more frames to animate? + /// + public virtual bool HasNext + { + get + { + if (CurrentFrameNr < Frames) + { + return true; + } + + return _queue.Count > 0; + } + } + + /// + /// Get the next animation frame value object + /// + /// + public abstract T Next(); + } + + /// + /// Implementation of the RectangleAnimator + /// + public class RectangleAnimator : AnimatorBase + { + public RectangleAnimator(Rectangle first, Rectangle last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame object + /// + /// Rectangle + public override Rectangle Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double dx = Last.X - First.X; + double dy = Last.Y - First.Y; + + int x = First.X + (int) (easingValue * dx); + int y = First.Y + (int) (easingValue * dy); + double dw = Last.Width - First.Width; + double dh = Last.Height - First.Height; + int width = First.Width + (int) (easingValue * dw); + int height = First.Height + (int) (easingValue * dh); + Current = new Rectangle(x, y, width, height); + } + + return Current; + } + } + + /// + /// Implementation of the PointAnimator + /// + public class PointAnimator : AnimatorBase + { + public PointAnimator(Point first, Point last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public PointAnimator(Point first, Point last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public PointAnimator(Point first, Point last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame value + /// + /// Point + public override Point Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double dx = Last.X - First.X; + double dy = Last.Y - First.Y; + + int x = First.X + (int) (easingValue * dx); + int y = First.Y + (int) (easingValue * dy); + Current = new Point(x, y); + } + + return Current; + } + } + + /// + /// Implementation of the SizeAnimator + /// + public class SizeAnimator : AnimatorBase + { + public SizeAnimator(Size first, Size last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public SizeAnimator(Size first, Size last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public SizeAnimator(Size first, Size last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame values + /// + /// Size + public override Size Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double dw = Last.Width - First.Width; + double dh = Last.Height - First.Height; + int width = First.Width + (int) (easingValue * dw); + int height = First.Height + (int) (easingValue * dh); + Current = new Size(width, height); + } + + return Current; + } + } + + /// + /// Implementation of the ColorAnimator + /// + public class ColorAnimator : AnimatorBase + { + public ColorAnimator(Color first, Color last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public ColorAnimator(Color first, Color last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public ColorAnimator(Color first, Color last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame values + /// + /// Color + public override Color Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double da = Last.A - First.A; + double dr = Last.R - First.R; + double dg = Last.G - First.G; + double db = Last.B - First.B; + int a = First.A + (int) (easingValue * da); + int r = First.R + (int) (easingValue * dr); + int g = First.G + (int) (easingValue * dg); + int b = First.B + (int) (easingValue * db); + Current = Color.FromArgb(a, r, g, b); + } + + return Current; + } + } + + /// + /// Implementation of the IntAnimator + /// + public class IntAnimator : AnimatorBase + { + public IntAnimator(int first, int last, int frames) + : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) + { + } + + public IntAnimator(int first, int last, int frames, EasingType easingType) + : base(first, last, frames, easingType, EasingMode.EaseIn) + { + } + + public IntAnimator(int first, int last, int frames, EasingType easingType, EasingMode easingMode) + : base(first, last, frames, easingType, easingMode) + { + } + + /// + /// Calculate the next frame values + /// + /// int + public override int Next() + { + if (NextFrame) + { + double easingValue = EasingValue; + double delta = Last - First; + Current = First + (int) (easingValue * delta); + } + + return Current; + } + } + + /// + /// Easing logic, to make the animations more "fluent" + /// + public static class Easing + { + // Adapted from http://www.robertpenner.com/easing/penner_chapter7_tweening.pdf + + public static double Ease(double linearStep, double acceleration, EasingType type) + { + double easedStep = acceleration > 0 ? EaseIn(linearStep, type) : acceleration < 0 ? EaseOut(linearStep, type) : linearStep; + // Lerp: + return ((easedStep - linearStep) * Math.Abs(acceleration) + linearStep); + } + + public static double EaseIn(double linearStep, EasingType type) => + type switch + { + EasingType.Step => (linearStep < 0.5 ? 0 : 1), + EasingType.Linear => linearStep, + EasingType.Sine => Sine.EaseIn(linearStep), + EasingType.Quadratic => Power.EaseIn(linearStep, 2), + EasingType.Cubic => Power.EaseIn(linearStep, 3), + EasingType.Quartic => Power.EaseIn(linearStep, 4), + EasingType.Quintic => Power.EaseIn(linearStep, 5), + _ => throw new NotImplementedException() + }; + + public static double EaseOut(double linearStep, EasingType type) => + type switch + { + EasingType.Step => (linearStep < 0.5 ? 0 : 1), + EasingType.Linear => linearStep, + EasingType.Sine => Sine.EaseOut(linearStep), + EasingType.Quadratic => Power.EaseOut(linearStep, 2), + EasingType.Cubic => Power.EaseOut(linearStep, 3), + EasingType.Quartic => Power.EaseOut(linearStep, 4), + EasingType.Quintic => Power.EaseOut(linearStep, 5), + _ => throw new NotImplementedException() + }; + + public static double EaseInOut(double linearStep, EasingType easeInType, EasingType easeOutType) + { + return linearStep < 0.5 ? EaseInOut(linearStep, easeInType) : EaseInOut(linearStep, easeOutType); + } + + public static double EaseInOut(double linearStep, EasingType type) => + type switch + { + EasingType.Step => (linearStep < 0.5 ? 0 : 1), + EasingType.Linear => linearStep, + EasingType.Sine => Sine.EaseInOut(linearStep), + EasingType.Quadratic => Power.EaseInOut(linearStep, 2), + EasingType.Cubic => Power.EaseInOut(linearStep, 3), + EasingType.Quartic => Power.EaseInOut(linearStep, 4), + EasingType.Quintic => Power.EaseInOut(linearStep, 5), + _ => throw new NotImplementedException() + }; + + private static class Sine + { + public static double EaseIn(double s) + { + return Math.Sin(s * (Math.PI / 2) - (Math.PI / 2)) + 1; + } + + public static double EaseOut(double s) + { + return Math.Sin(s * (Math.PI / 2)); + } + + public static double EaseInOut(double s) + { + return Math.Sin(s * Math.PI - (Math.PI / 2) + 1) / 2; + } + } + + private static class Power + { + public static double EaseIn(double s, int power) + { + return Math.Pow(s, power); + } + + public static double EaseOut(double s, int power) + { + var sign = power % 2 == 0 ? -1 : 1; + return sign * (Math.Pow(s - 1, power) + sign); + } + + public static double EaseInOut(double s, int power) + { + s *= 2; + if (s < 1) + { + return EaseIn(s, power) / 2; + } + + var sign = power % 2 == 0 ? -1 : 1; + return (sign / 2.0 * (Math.Pow(s - 2, power) + sign * 2)); + } + } + } + + /// + /// This defines the way the animation works + /// + public enum EasingType + { + Step, + Linear, + Sine, + Quadratic, + Cubic, + Quartic, + Quintic + } + + public enum EasingMode + { + EaseIn, + EaseOut, + EaseInOut + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/BinaryStructHelper.cs b/src/Greenshot.Base/Core/BinaryStructHelper.cs new file mode 100644 index 000000000..257d8dd2c --- /dev/null +++ b/src/Greenshot.Base/Core/BinaryStructHelper.cs @@ -0,0 +1,108 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Core +{ + /// + /// A helper class which does the mashalling for structs + /// + public static class BinaryStructHelper + { + /// + /// Get a struct from a byte array + /// + /// typeof struct + /// byte[] + /// struct + public static T FromByteArray(byte[] bytes) where T : struct + { + IntPtr ptr = IntPtr.Zero; + try + { + int size = Marshal.SizeOf(typeof(T)); + ptr = Marshal.AllocHGlobal(size); + Marshal.Copy(bytes, 0, ptr, size); + return FromIntPtr(ptr); + } + finally + { + if (ptr != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptr); + } + } + } + + /// + /// Get a struct from a byte array + /// + /// typeof struct + /// Pointer to the structor to return + /// struct + public static T FromIntPtr(IntPtr intPtr) where T : struct + { + object obj = Marshal.PtrToStructure(intPtr, typeof(T)); + return (T) obj; + } + + /// + /// copy a struct to a byte array + /// + /// typeof struct + /// struct + /// byte[] + public static byte[] ToByteArray(T obj) where T : struct + { + IntPtr ptr = IntPtr.Zero; + try + { + int size = Marshal.SizeOf(typeof(T)); + ptr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(obj, ptr, true); + return FromPtrToByteArray(ptr); + } + finally + { + if (ptr != IntPtr.Zero) + { + Marshal.FreeHGlobal(ptr); + } + } + } + + /// + /// copy a struct from a pointer to a byte array + /// + /// typeof struct + /// IntPtr to struct + /// byte[] + public static byte[] FromPtrToByteArray(IntPtr ptr) where T : struct + { + int size = Marshal.SizeOf(typeof(T)); + byte[] bytes = new byte[size]; + Marshal.Copy(ptr, bytes, 0, size); + return bytes; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/Cache.cs b/src/Greenshot.Base/Core/Cache.cs new file mode 100644 index 000000000..f761b8b89 --- /dev/null +++ b/src/Greenshot.Base/Core/Cache.cs @@ -0,0 +1,259 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Timers; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// Cache class + /// + /// Type of key + /// Type of value + public class Cache + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Cache)); + private readonly IDictionary _internalCache = new Dictionary(); + private readonly object _lockObject = new object(); + private readonly int _secondsToExpire = 10; + private readonly CacheObjectExpired _expiredCallback; + + public delegate void CacheObjectExpired(TK key, TV cacheValue); + + /// + /// Initialize the cache + /// + public Cache() + { + } + + /// + /// Initialize the cache + /// + /// + public Cache(CacheObjectExpired expiredCallback) : this() + { + _expiredCallback = expiredCallback; + } + + /// + /// Initialize the cache with a expire setting + /// + /// + public Cache(int secondsToExpire) : this() + { + _secondsToExpire = secondsToExpire; + } + + /// + /// Initialize the cache with a expire setting + /// + /// + /// + public Cache(int secondsToExpire, CacheObjectExpired expiredCallback) : this(expiredCallback) + { + _secondsToExpire = secondsToExpire; + } + + /// + /// Enumerable for the values in the cache + /// + public IEnumerable Elements + { + get + { + List elements = new List(); + + lock (_lockObject) + { + foreach (TV element in _internalCache.Values) + { + elements.Add(element); + } + } + + foreach (TV element in elements) + { + yield return element; + } + } + } + + /// + /// Get the value by key from the cache + /// + /// + /// + public TV this[TK key] + { + get + { + TV result = default; + lock (_lockObject) + { + if (_internalCache.ContainsKey(key)) + { + result = _internalCache[key]; + } + } + + return result; + } + } + + /// + /// Contains + /// + /// + /// true if the cache contains the key + public bool Contains(TK key) + { + lock (_lockObject) + { + return _internalCache.ContainsKey(key); + } + } + + /// + /// Add a value to the cache + /// + /// + /// + public void Add(TK key, TV value) + { + Add(key, value, null); + } + + /// + /// Add a value to the cache + /// + /// + /// + /// optional value for the seconds to expire + public void Add(TK key, TV value, int? secondsToExpire) + { + lock (_lockObject) + { + var cachedItem = new CachedItem(key, value, secondsToExpire ?? _secondsToExpire); + cachedItem.Expired += delegate(TK cacheKey, TV cacheValue) + { + if (_internalCache.ContainsKey(cacheKey)) + { + Log.DebugFormat("Expiring object with Key: {0}", cacheKey); + _expiredCallback?.Invoke(cacheKey, cacheValue); + Remove(cacheKey); + } + else + { + Log.DebugFormat("Expired old object with Key: {0}", cacheKey); + } + }; + + if (_internalCache.ContainsKey(key)) + { + _internalCache[key] = value; + Log.DebugFormat("Updated item with Key: {0}", key); + } + else + { + _internalCache.Add(key, cachedItem); + Log.DebugFormat("Added item with Key: {0}", key); + } + } + } + + /// + /// Remove item from cache + /// + /// + public void Remove(TK key) + { + lock (_lockObject) + { + if (!_internalCache.ContainsKey(key)) + { + throw new ApplicationException($"An object with key ‘{key}’ does not exists in cache"); + } + + _internalCache.Remove(key); + Log.DebugFormat("Removed item with Key: {0}", key); + } + } + + /// + /// A cache item + /// + private class CachedItem + { + public event CacheObjectExpired Expired; + private readonly int _secondsToExpire; + private readonly Timer _timerEvent; + + public CachedItem(TK key, TV item, int secondsToExpire) + { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + Key = key; + Item = item; + _secondsToExpire = secondsToExpire; + if (secondsToExpire <= 0) + { + return; + } + + _timerEvent = new Timer(secondsToExpire * 1000) + { + AutoReset = false + }; + _timerEvent.Elapsed += timerEvent_Elapsed; + _timerEvent.Start(); + } + + private void ExpireNow() + { + _timerEvent.Stop(); + if (_secondsToExpire > 0) + { + Expired?.Invoke(Key, Item); + } + } + + private void timerEvent_Elapsed(object sender, ElapsedEventArgs e) + { + ExpireNow(); + } + + public TK Key { get; private set; } + public TV Item { get; private set; } + + public static implicit operator TV(CachedItem a) + { + return a.Item; + } + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/Capture.cs b/src/Greenshot.Base/Core/Capture.cs similarity index 84% rename from GreenshotPlugin/Core/Capture.cs rename to src/Greenshot.Base/Core/Capture.cs index 2b0180de2..b4d172dc2 100644 --- a/GreenshotPlugin/Core/Capture.cs +++ b/src/Greenshot.Base/Core/Capture.cs @@ -22,73 +22,95 @@ using System; using System.Drawing; using System.Drawing.Imaging; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; using log4net; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// This class is used to pass an instance of the "Capture" around /// Having the Bitmap, eventually the Windows Title and cursor all together. /// - public class Capture : ICapture { + public class Capture : ICapture + { private static readonly ILog Log = LogManager.GetLogger(typeof(Capture)); private Rectangle _screenBounds; + /// /// Get/Set the screen bounds /// - public Rectangle ScreenBounds { - get { - if (_screenBounds == Rectangle.Empty) { + public Rectangle ScreenBounds + { + get + { + if (_screenBounds == Rectangle.Empty) + { _screenBounds = WindowCapture.GetScreenBounds(); } + return _screenBounds; } set => _screenBounds = value; } private Image _image; + /// /// Get/Set the Image /// - public Image Image { + public Image Image + { get => _image; - set { + set + { _image?.Dispose(); _image = value; - if (value != null) { - if (value.PixelFormat.Equals(PixelFormat.Format8bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format1bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format4bppIndexed)) { + if (value != null) + { + if (value.PixelFormat.Equals(PixelFormat.Format8bppIndexed) || value.PixelFormat.Equals(PixelFormat.Format1bppIndexed) || + value.PixelFormat.Equals(PixelFormat.Format4bppIndexed)) + { Log.Debug("Converting Bitmap to PixelFormat.Format32bppArgb as we don't support: " + value.PixelFormat); - try { + try + { // Default Bitmap PixelFormat is Format32bppArgb _image = new Bitmap(value); - } finally { + } + finally + { // Always dispose, even when a exception occured value.Dispose(); } } + Log.DebugFormat("Image is set with the following specifications: {0} - {1}", _image.Size, _image.PixelFormat); - } else { + } + else + { Log.Debug("Image is removed."); } } } - public void NullImage() { + public void NullImage() + { _image = null; } private Icon _cursor; + /// /// Get/Set the image for the Cursor /// - public Icon Cursor { + public Icon Cursor + { get => _cursor; - set { + set + { _cursor?.Dispose(); - _cursor = (Icon)value.Clone(); + _cursor = (Icon) value.Clone(); } } @@ -103,36 +125,43 @@ namespace GreenshotPlugin.Core public bool CursorVisible { get; set; } private Point _cursorLocation = Point.Empty; + /// /// Get/Set the CursorLocation /// - public Point CursorLocation { + public Point CursorLocation + { get => _cursorLocation; set => _cursorLocation = value; } private Point _location = Point.Empty; + /// /// Get/set the Location /// - public Point Location { + public Point Location + { get => _location; set => _location = value; } private CaptureDetails _captureDetails; + /// /// Get/set the CaptureDetails /// - public ICaptureDetails CaptureDetails { + public ICaptureDetails CaptureDetails + { get => _captureDetails; - set => _captureDetails = (CaptureDetails)value; + set => _captureDetails = (CaptureDetails) value; } /// /// Default Constructor /// - public Capture() { + public Capture() + { _screenBounds = WindowCapture.GetScreenBounds(); _captureDetails = new CaptureDetails(); } @@ -142,14 +171,16 @@ namespace GreenshotPlugin.Core /// Note: the supplied bitmap can be disposed immediately or when constructor is called. /// /// Image - public Capture(Image newImage) : this() { + public Capture(Image newImage) : this() + { Image = newImage; } /// /// Destructor /// - ~Capture() { + ~Capture() + { Dispose(false); } @@ -157,7 +188,8 @@ namespace GreenshotPlugin.Core /// The public accessible Dispose /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice /// - public void Dispose() { + public void Dispose() + { Dispose(true); GC.SuppressFinalize(this); } @@ -167,11 +199,14 @@ namespace GreenshotPlugin.Core /// When disposing==true all non-managed resources should be freed too! /// /// - protected virtual void Dispose(bool disposing) { - if (disposing) { + protected virtual void Dispose(bool disposing) + { + if (disposing) + { _image?.Dispose(); _cursor?.Dispose(); } + _image = null; _cursor = null; } @@ -180,12 +215,14 @@ namespace GreenshotPlugin.Core /// Crops the capture to the specified rectangle (with Bitmap coordinates!) /// /// Rectangle with bitmap coordinates - public bool Crop(Rectangle cropRectangle) { + public bool Crop(Rectangle cropRectangle) + { Log.Debug("Cropping to: " + cropRectangle); if (!ImageHelper.Crop(ref _image, ref cropRectangle)) { return false; } + _location = cropRectangle.Location; // Change mouse location according to the cropRectangle (including screenbounds) offset MoveMouseLocation(-cropRectangle.Location.X, -cropRectangle.Location.Y); @@ -206,7 +243,8 @@ namespace GreenshotPlugin.Core /// /// x coordinates to move the mouse /// y coordinates to move the mouse - public void MoveMouseLocation(int x, int y) { + public void MoveMouseLocation(int x, int y) + { _cursorLocation.Offset(x, y); } @@ -257,6 +295,5 @@ namespace GreenshotPlugin.Core // elements = value; // } //} - } } \ No newline at end of file diff --git a/GreenshotPlugin/Core/CaptureDetails.cs b/src/Greenshot.Base/Core/CaptureDetails.cs similarity index 69% rename from GreenshotPlugin/Core/CaptureDetails.cs rename to src/Greenshot.Base/Core/CaptureDetails.cs index c600ced26..58e3f19be 100644 --- a/GreenshotPlugin/Core/CaptureDetails.cs +++ b/src/Greenshot.Base/Core/CaptureDetails.cs @@ -21,46 +21,31 @@ using System; using System.Collections.Generic; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// This Class is used to pass details about the capture around. /// The time the Capture was taken and the Title of the window (or a region of) that is captured /// - public class CaptureDetails : ICaptureDetails { + public class CaptureDetails : ICaptureDetails + { + /// + public string Title { get; set; } /// - public string Title { - get; - set; - } + public string Filename { get; set; } /// - public string Filename { - get; - set; - } + public DateTime DateTime { get; set; } /// - public DateTime DateTime { - get; - set; - } + public float DpiX { get; set; } /// - public float DpiX { - get; - set; - } - - /// - public float DpiY { - get; - set; - } + public float DpiY { get; set; } /// public OcrInformation OcrInformation { get; set; } @@ -69,53 +54,64 @@ namespace GreenshotPlugin.Core public Dictionary MetaData { get; } = new Dictionary(); /// - public void AddMetaData(string key, string value) { - if (MetaData.ContainsKey(key)) { + public void AddMetaData(string key, string value) + { + if (MetaData.ContainsKey(key)) + { MetaData[key] = value; - } else { + } + else + { MetaData.Add(key, value); } } /// - public CaptureMode CaptureMode { - get; - set; - } + public CaptureMode CaptureMode { get; set; } /// public List CaptureDestinations { get; set; } = new List(); /// - public void ClearDestinations() { + public void ClearDestinations() + { CaptureDestinations.Clear(); } /// - public void RemoveDestination(IDestination destination) { - if (CaptureDestinations.Contains(destination)) { + public void RemoveDestination(IDestination destination) + { + if (CaptureDestinations.Contains(destination)) + { CaptureDestinations.Remove(destination); } } /// - public void AddDestination(IDestination captureDestination) { - if (!CaptureDestinations.Contains(captureDestination)) { + public void AddDestination(IDestination captureDestination) + { + if (!CaptureDestinations.Contains(captureDestination)) + { CaptureDestinations.Add(captureDestination); } } /// - public bool HasDestination(string designation) { - foreach(IDestination destination in CaptureDestinations) { - if (designation.Equals(destination.Designation)) { + public bool HasDestination(string designation) + { + foreach (IDestination destination in CaptureDestinations) + { + if (designation.Equals(destination.Designation)) + { return true; } } + return false; } - public CaptureDetails() { + public CaptureDetails() + { DateTime = DateTime.Now; } } diff --git a/GreenshotPlugin/Effects/AdjustEffect.cs b/src/Greenshot.Base/Core/CaptureHandler.cs similarity index 58% rename from GreenshotPlugin/Effects/AdjustEffect.cs rename to src/Greenshot.Base/Core/CaptureHandler.cs index a01dd16d2..ea11c464d 100644 --- a/GreenshotPlugin/Effects/AdjustEffect.cs +++ b/src/Greenshot.Base/Core/CaptureHandler.cs @@ -1,57 +1,43 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// AdjustEffect - /// - public class AdjustEffect : IEffect { - public AdjustEffect() - { - Reset(); - } - public float Contrast { - get; - set; - } - public float Brightness { - get; - set; - } - public float Gamma { - get; - set; - } - public void Reset() { - Contrast = 1f; - Brightness = 1f; - Gamma = 1f; - } - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.Adjust(sourceImage, Brightness, Contrast, Gamma); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; + +namespace Greenshot.Base.Core +{ + /// + /// This is the method signature which is used to capture a rectangle from the screen. + /// + /// + /// Captured Bitmap + public delegate Bitmap CaptureScreenRectangleHandler(Rectangle captureBounds); + + /// + /// This is a hack to experiment with different screen capture routines + /// + public static class CaptureHandler + { + /// + /// By changing this value, null is default + /// + public static CaptureScreenRectangleHandler CaptureScreenRectangle { get; set; } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs new file mode 100644 index 000000000..cb10a7be3 --- /dev/null +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -0,0 +1,1076 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Base.UnmanagedHelpers; +using log4net; +using HtmlDocument = HtmlAgilityPack.HtmlDocument; + +namespace Greenshot.Base.Core +{ + /// + /// Description of ClipboardHelper. + /// + public static class ClipboardHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ClipboardHelper)); + private static readonly object ClipboardLockObject = new object(); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static readonly string FORMAT_FILECONTENTS = "FileContents"; + private static readonly string FORMAT_HTML = "text/html"; + private static readonly string FORMAT_PNG = "PNG"; + private static readonly string FORMAT_PNG_OFFICEART = "PNG+Office Art"; + private static readonly string FORMAT_17 = "Format17"; + private static readonly string FORMAT_JPG = "JPG"; + private static readonly string FORMAT_JPEG = "JPEG"; + private static readonly string FORMAT_JFIF = "JFIF"; + private static readonly string FORMAT_JFIF_OFFICEART = "JFIF+Office Art"; + private static readonly string FORMAT_GIF = "GIF"; + + private static readonly string FORMAT_BITMAP = "System.Drawing.Bitmap"; + //private static readonly string FORMAT_HTML = "HTML Format"; + + // Template for the HTML Text on the clipboard + // see: http://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx + // or: http://msdn.microsoft.com/en-us/library/Aa767917.aspx + private const string HtmlClipboardString = @"Version:0.9 +StartHTML:<<<<<<<1 +EndHTML:<<<<<<<2 +StartFragment:<<<<<<<3 +EndFragment:<<<<<<<4 +StartSelection:<<<<<<<3 +EndSelection:<<<<<<<4 + + + +Greenshot capture + + + + + + +"; + + private const string HtmlClipboardBase64String = @"Version:0.9 +StartHTML:<<<<<<<1 +EndHTML:<<<<<<<2 +StartFragment:<<<<<<<3 +EndFragment:<<<<<<<4 +StartSelection:<<<<<<<3 +EndSelection:<<<<<<<4 + + + +Greenshot capture + + + + + + +"; + + /// + /// Get the current "ClipboardOwner" but only if it isn't us! + /// + /// current clipboard owner + private static string GetClipboardOwner() + { + string owner = null; + try + { + IntPtr hWnd = User32.GetClipboardOwner(); + if (hWnd != IntPtr.Zero) + { + try + { + User32.GetWindowThreadProcessId(hWnd, out var pid); + using Process me = Process.GetCurrentProcess(); + using Process ownerProcess = Process.GetProcessById(pid); + // Exclude myself + if (me.Id != ownerProcess.Id) + { + // Get Process Name + owner = ownerProcess.ProcessName; + // Try to get the starting Process Filename, this might fail. + try + { + owner = ownerProcess.Modules[0].FileName; + } + catch (Exception) + { + // Ignore + } + } + } + catch (Exception e) + { + Log.Warn("Non critical error: Couldn't get clipboard process, trying to use the title.", e); + var title = new StringBuilder(260, 260); + User32.GetWindowText(hWnd, title, title.Capacity); + owner = title.ToString(); + } + } + } + catch (Exception e) + { + Log.Warn("Non critical error: Couldn't get clipboard owner.", e); + } + + return owner; + } + + /// + /// The SetDataObject will lock/try/catch clipboard operations making it save and not show exceptions. + /// The bool "copy" is used to decided if the information stays on the clipboard after exit. + /// + /// + /// + private static void SetDataObject(IDataObject ido, bool copy) + { + lock (ClipboardLockObject) + { + // Clear first, this seems to solve some issues + try + { + Clipboard.Clear(); + } + catch (Exception clearException) + { + Log.Warn(clearException.Message); + } + + try + { + // For BUG-1935 this was changed from looping ourselfs, or letting MS retry... + Clipboard.SetDataObject(ido, copy, 15, 200); + } + catch (Exception clipboardSetException) + { + string messageText; + string clipboardOwner = GetClipboardOwner(); + if (clipboardOwner != null) + { + messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner); + } + else + { + messageText = Language.GetString("clipboard_error"); + } + + Log.Error(messageText, clipboardSetException); + } + } + } + + /// + /// The GetDataObject will lock/try/catch clipboard operations making it save and not show exceptions. + /// + public static IDataObject GetDataObject() + { + lock (ClipboardLockObject) + { + int retryCount = 2; + while (retryCount >= 0) + { + try + { + return Clipboard.GetDataObject(); + } + catch (Exception ee) + { + if (retryCount == 0) + { + string messageText; + string clipboardOwner = GetClipboardOwner(); + if (clipboardOwner != null) + { + messageText = Language.GetFormattedString("clipboard_inuse", clipboardOwner); + } + else + { + messageText = Language.GetString("clipboard_error"); + } + + Log.Error(messageText, ee); + } + else + { + Thread.Sleep(100); + } + } + finally + { + --retryCount; + } + } + } + + return null; + } + + /// + /// Test if the IDataObject contains Text + /// + /// + /// + public static bool ContainsText(IDataObject dataObject) + { + if (dataObject != null) + { + if (dataObject.GetDataPresent(DataFormats.Text) || dataObject.GetDataPresent(DataFormats.UnicodeText)) + { + return true; + } + } + + return false; + } + + /// + /// Wrapper for Clipboard.ContainsImage, specialized for Greenshot, Created for Bug #3432313 + /// + /// boolean if there is an image on the clipboard + public static bool ContainsImage() + { + IDataObject clipboardData = GetDataObject(); + return ContainsImage(clipboardData); + } + + /// + /// Check if the IDataObject has an image + /// + /// + /// true if an image is there + public static bool ContainsImage(IDataObject dataObject) + { + if (dataObject == null) return false; + + if (dataObject.GetDataPresent(DataFormats.Bitmap) + || dataObject.GetDataPresent(DataFormats.Dib) + || dataObject.GetDataPresent(DataFormats.Tiff) + || dataObject.GetDataPresent(DataFormats.EnhancedMetafile) + || dataObject.GetDataPresent(FORMAT_PNG) + || dataObject.GetDataPresent(FORMAT_17) + || dataObject.GetDataPresent(FORMAT_JPG) + || dataObject.GetDataPresent(FORMAT_JFIF) + || dataObject.GetDataPresent(FORMAT_JPEG) + || dataObject.GetDataPresent(FORMAT_GIF)) + { + return true; + } + + var imageFiles = GetImageFilenames(dataObject); + if (imageFiles.Any()) + { + return true; + } + + var fileDescriptor = (MemoryStream) dataObject.GetData("FileGroupDescriptorW"); + var files = FileDescriptorReader.Read(fileDescriptor); + var fileIndex = 0; + foreach (var fileContentFile in files) + { + if ((fileContentFile.FileAttributes & FileAttributes.Directory) != 0) + { + //Do something with directories? + //Note that directories do not have FileContents + //And will throw if we try to read them + continue; + } + + var fileData = FileDescriptorReader.GetFileContents(dataObject, fileIndex); + try + { + //Do something with the fileContent Stream + if (IsValidStream(fileData)) + { + fileData.Position = 0; + using (ImageHelper.FromStream(fileData)) + { + // If we get here, there is an image + return true; + } + } + } + finally + { + fileData?.Dispose(); + } + + fileIndex++; + } + + if (dataObject.GetDataPresent(FORMAT_FILECONTENTS)) + { + try + { + var clipboardContent = dataObject.GetData(FORMAT_FILECONTENTS, true); + var imageStream = clipboardContent as MemoryStream; + if (IsValidStream(imageStream)) + { + using (ImageHelper.FromStream(imageStream)) + { + // If we get here, there is an image + return true; + } + } + } + catch (Exception) + { + // Ignore + } + } + + // Try to get the image from the HTML code + var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); + if (textObject != null) + { + var doc = new HtmlDocument(); + doc.LoadHtml(textObject); + var imgNodes = doc.DocumentNode.SelectNodes("//img"); + if (imgNodes != null) + { + foreach (var imgNode in imgNodes) + { + var srcAttribute = imgNode.Attributes["src"]; + var imageUrl = srcAttribute.Value; + if (!string.IsNullOrEmpty(imageUrl)) + { + return true; + } + } + } + } + + return false; + } + + /// + /// Get the specified IDataObject format as a string + /// + /// IDataObject + /// string + /// Encoding + /// sting + private static string ContentAsString(IDataObject dataObject, string format, Encoding encoding = null) + { + encoding ??= Encoding.Unicode; + var objectAsFormat = dataObject.GetData(format); + return objectAsFormat switch + { + null => null, + string text => text, + MemoryStream ms => encoding.GetString(ms.ToArray()), + _ => null + }; + } + + /// + /// Simple helper to check the stream + /// + /// + /// + private static bool IsValidStream(MemoryStream memoryStream) + { + return memoryStream != null && memoryStream.Length > 0; + } + + /// + /// Wrapper for Clipboard.GetImage, Created for Bug #3432313 + /// + /// Image if there is an image on the clipboard + public static Image GetImage() + { + IDataObject clipboardData = GetDataObject(); + // Return the first image + foreach (Image clipboardImage in GetImages(clipboardData)) + { + return clipboardImage; + } + + return null; + } + + /// + /// Get all images (multiple if filenames are available) from the dataObject + /// Returned images must be disposed by the calling code! + /// + /// + /// IEnumerable of Image + public static IEnumerable GetImages(IDataObject dataObject) + { + // Get single image, this takes the "best" match + Image singleImage = GetImage(dataObject); + if (singleImage != null) + { + Log.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat); + yield return singleImage; + } + else + { + // check if files are supplied + foreach (string imageFile in GetImageFilenames(dataObject)) + { + Image returnImage = null; + try + { + returnImage = ImageHelper.LoadImage(imageFile); + } + catch (Exception streamImageEx) + { + Log.Error("Problem retrieving Image from clipboard.", streamImageEx); + } + + if (returnImage != null) + { + Log.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat); + yield return returnImage; + } + } + } + } + + /// + /// Get an Image from the IDataObject, don't check for FileDrop + /// + /// + /// Image or null + private static Image GetImage(IDataObject dataObject) + { + Image returnImage = null; + if (dataObject != null) + { + IList formats = GetFormats(dataObject); + string[] retrieveFormats; + + // Found a weird bug, where PNG's from Outlook 2010 are clipped + // So I build some special logik to get the best format: + if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) + { + // Outlook ?? + Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front..."); + retrieveFormats = new[] + { + DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, + DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML + }; + } + else + { + retrieveFormats = new[] + { + FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, + FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML + }; + } + + foreach (string currentFormat in retrieveFormats) + { + if (formats != null && formats.Contains(currentFormat)) + { + Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat); + returnImage = GetImageForFormat(currentFormat, dataObject); + } + else + { + Log.DebugFormat("Couldn't find format {0}.", currentFormat); + } + + if (returnImage != null) + { + return returnImage; + } + } + } + + return null; + } + + /// + /// Helper method to try to get an image in the specified format from the dataObject + /// the DIB reader should solve some issues + /// It also supports Format17/DibV5, by using the following information: http://stackoverflow.com/a/14335591 + /// + /// string with the format + /// IDataObject + /// Image or null + private static Image GetImageForFormat(string format, IDataObject dataObject) + { + if (format == FORMAT_HTML) + { + var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); + if (textObject != null) + { + var doc = new HtmlDocument(); + doc.LoadHtml(textObject); + var imgNodes = doc.DocumentNode.SelectNodes("//img"); + if (imgNodes != null) + { + foreach (var imgNode in imgNodes) + { + var srcAttribute = imgNode.Attributes["src"]; + var imageUrl = srcAttribute.Value; + Log.Debug(imageUrl); + var image = NetworkHelper.DownloadImage(imageUrl); + if (image != null) + { + return image; + } + } + } + } + } + + object clipboardObject = GetFromDataObject(dataObject, format); + var imageStream = clipboardObject as MemoryStream; + if (!IsValidStream(imageStream)) + { + // TODO: add "HTML Format" support here... + return clipboardObject as Image; + } + + if (CoreConfig.EnableSpecialDIBClipboardReader) + { + if (format == FORMAT_17 || format == DataFormats.Dib) + { + Log.Info("Found DIB stream, trying to process it."); + try + { + if (imageStream != null) + { + byte[] dibBuffer = new byte[imageStream.Length]; + imageStream.Read(dibBuffer, 0, dibBuffer.Length); + var infoHeader = BinaryStructHelper.FromByteArray(dibBuffer); + if (!infoHeader.IsDibV5) + { + Log.InfoFormat("Using special DIB + /// Get Text from the DataObject + /// + /// string if there is text on the clipboard + public static string GetText(IDataObject dataObject) + { + if (ContainsText(dataObject)) + { + return (string) dataObject.GetData(DataFormats.Text); + } + + return null; + } + + /// + /// Set text to the clipboard + /// + /// + public static void SetClipboardData(string text) + { + IDataObject ido = new DataObject(); + ido.SetData(DataFormats.Text, true, text); + SetDataObject(ido, true); + } + + private static string GetHtmlString(ISurface surface, string filename) + { + string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardString)); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${file}", filename.Replace("\\", "/")); + StringBuilder sb = new StringBuilder(); + sb.Append(utf8EncodedHtmlString); + sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + return sb.ToString(); + } + + private static string GetHtmlDataUrlString(ISurface surface, MemoryStream pngStream) + { + string utf8EncodedHtmlString = Encoding.GetEncoding(0).GetString(Encoding.UTF8.GetBytes(HtmlClipboardBase64String)); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${width}", surface.Image.Width.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${height}", surface.Image.Height.ToString()); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${format}", "png"); + utf8EncodedHtmlString = utf8EncodedHtmlString.Replace("${data}", Convert.ToBase64String(pngStream.GetBuffer(), 0, (int) pngStream.Length)); + StringBuilder sb = new StringBuilder(); + sb.Append(utf8EncodedHtmlString); + sb.Replace("<<<<<<<1", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<2", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + sb.Replace("<<<<<<<3", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal) + "".Length).ToString("D8")); + sb.Replace("<<<<<<<4", (utf8EncodedHtmlString.IndexOf("", StringComparison.Ordinal)).ToString("D8")); + return sb.ToString(); + } + + private const int BITMAPFILEHEADER_LENGTH = 14; + + /// + /// Set an Image to the clipboard + /// This method will place images to the clipboard depending on the ClipboardFormats setting. + /// e.g. Bitmap which works with pretty much everything and type Dib for e.g. OpenOffice + /// because OpenOffice has a bug http://qa.openoffice.org/issues/show_bug.cgi?id=85661 + /// The Dib (Device Indenpendend Bitmap) in 32bpp actually won't work with Powerpoint 2003! + /// When pasting a Dib in PP 2003 the Bitmap is somehow shifted left! + /// For this problem the user should not use the direct paste (=Dib), but select Bitmap + /// + public static void SetClipboardData(ISurface surface) + { + DataObject dataObject = new DataObject(); + + // This will work for Office and most other applications + //ido.SetData(DataFormats.Bitmap, true, image); + + MemoryStream dibStream = null; + MemoryStream dibV5Stream = null; + MemoryStream pngStream = null; + Image imageToSave = null; + bool disposeImage = false; + try + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); + // Create the image which is going to be saved so we don't create it multiple times + disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave); + try + { + // Create PNG stream + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.PNG)) + { + pngStream = new MemoryStream(); + // PNG works for e.g. Powerpoint + SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); + ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings); + pngStream.Seek(0, SeekOrigin.Begin); + // Set the PNG stream + dataObject.SetData(FORMAT_PNG, false, pngStream); + } + } + catch (Exception pngEx) + { + Log.Error("Error creating PNG for the Clipboard.", pngEx); + } + + try + { + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIB)) + { + using (MemoryStream tmpBmpStream = new MemoryStream()) + { + // Save image as BMP + SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false); + ImageOutput.SaveToStream(imageToSave, null, tmpBmpStream, bmpOutputSettings); + + dibStream = new MemoryStream(); + // Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14 + dibStream.Write(tmpBmpStream.GetBuffer(), BITMAPFILEHEADER_LENGTH, (int) tmpBmpStream.Length - BITMAPFILEHEADER_LENGTH); + } + + // Set the DIB to the clipboard DataObject + dataObject.SetData(DataFormats.Dib, true, dibStream); + } + } + catch (Exception dibEx) + { + Log.Error("Error creating DIB for the Clipboard.", dibEx); + } + + // CF_DibV5 + try + { + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIBV5)) + { + // Create the stream for the clipboard + dibV5Stream = new MemoryStream(); + + // Create the BITMAPINFOHEADER + BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32) + { + // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? + biCompression = BI_COMPRESSION.BI_BITFIELDS + }; + // Create a byte[] to write + byte[] headerBytes = BinaryStructHelper.ToByteArray(header); + // Write the BITMAPINFOHEADER to the stream + dibV5Stream.Write(headerBytes, 0, headerBytes.Length); + + // As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added + BitfieldColorMask colorMask = new BitfieldColorMask(); + // Make sure the values are set + colorMask.InitValues(); + // Create the byte[] from the struct + byte[] colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask); + Array.Reverse(colorMaskBytes); + // Write to the stream + dibV5Stream.Write(colorMaskBytes, 0, colorMaskBytes.Length); + + // Create the raw bytes for the pixels only + byte[] bitmapBytes = BitmapToByteArray((Bitmap) imageToSave); + // Write to the stream + dibV5Stream.Write(bitmapBytes, 0, bitmapBytes.Length); + + // Set the DIBv5 to the clipboard DataObject + dataObject.SetData(FORMAT_17, true, dibV5Stream); + } + } + catch (Exception dibEx) + { + Log.Error("Error creating DIB for the Clipboard.", dibEx); + } + + // Set the HTML + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTML)) + { + string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null); + string html = GetHtmlString(surface, tmpFile); + dataObject.SetText(html, TextDataFormat.Html); + } + else if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTMLDATAURL)) + { + string html; + using (MemoryStream tmpPngStream = new MemoryStream()) + { + SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false) + { + // Do not allow to reduce the colors, some applications dislike 256 color images + // reported with bug #3594681 + DisableReduceColors = true + }; + // Check if we can use the previously used image + if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) + { + ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings); + } + else + { + ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings); + } + + html = GetHtmlDataUrlString(surface, tmpPngStream); + } + + dataObject.SetText(html, TextDataFormat.Html); + } + } + finally + { + // we need to use the SetDataOject before the streams are closed otherwise the buffer will be gone! + // Check if Bitmap is wanted + if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.BITMAP)) + { + dataObject.SetImage(imageToSave); + // Place the DataObject to the clipboard + SetDataObject(dataObject, true); + } + else + { + // Place the DataObject to the clipboard + SetDataObject(dataObject, true); + } + + pngStream?.Dispose(); + dibStream?.Dispose(); + dibV5Stream?.Dispose(); + // cleanup if needed + if (disposeImage) + { + imageToSave?.Dispose(); + } + } + } + + /// + /// Helper method so get the bitmap bytes + /// See: http://stackoverflow.com/a/6570155 + /// + /// Bitmap + /// byte[] + private static byte[] BitmapToByteArray(Bitmap bitmap) + { + // Lock the bitmap's bits. + Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); + BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat); + + int absStride = Math.Abs(bmpData.Stride); + int bytes = absStride * bitmap.Height; + long ptr = bmpData.Scan0.ToInt32(); + // Declare an array to hold the bytes of the bitmap. + byte[] rgbValues = new byte[bytes]; + + for (int i = 0; i < bitmap.Height; i++) + { + IntPtr pointer = new IntPtr(ptr + (bmpData.Stride * i)); + Marshal.Copy(pointer, rgbValues, absStride * (bitmap.Height - i - 1), absStride); + } + + // Unlock the bits. + bitmap.UnlockBits(bmpData); + + return rgbValues; + } + + /// + /// Set Object with type Type to the clipboard + /// + /// Type + /// object + public static void SetClipboardData(Type type, object obj) + { + DataFormats.Format format = DataFormats.GetFormat(type.FullName); + + //now copy to clipboard + IDataObject dataObj = new DataObject(); + dataObj.SetData(format.Name, false, obj); + // Use false to make the object disappear when the application stops. + SetDataObject(dataObj, true); + } + + /// + /// Retrieve a list of all formats currently in the IDataObject + /// + /// List of string with the current formats + public static List GetFormats(IDataObject dataObj) + { + string[] formats = null; + + if (dataObj != null) + { + formats = dataObj.GetFormats(); + } + + if (formats != null) + { + Log.DebugFormat("Got clipboard formats: {0}", string.Join(",", formats)); + return new List(formats); + } + + return new List(); + } + + /// + /// Check if there is currently something on the clipboard which has the supplied format + /// + /// IDataObject + /// string with format + /// true if one the format is found + public static bool ContainsFormat(IDataObject dataObject, string format) + { + return ContainsFormat(dataObject, new[] + { + format + }); + } + + /// + /// Check if there is currently something on the clipboard which has one of the supplied formats + /// + /// string[] with formats + /// true if one of the formats was found + public static bool ContainsFormat(string[] formats) + { + return ContainsFormat(GetDataObject(), formats); + } + + /// + /// Check if there is currently something on the clipboard which has one of the supplied formats + /// + /// IDataObject + /// string[] with formats + /// true if one of the formats was found + public static bool ContainsFormat(IDataObject dataObject, string[] formats) + { + bool formatFound = false; + List currentFormats = GetFormats(dataObject); + if (currentFormats == null || currentFormats.Count == 0 || formats == null || formats.Length == 0) + { + return false; + } + + foreach (string format in formats) + { + if (currentFormats.Contains(format)) + { + formatFound = true; + break; + } + } + + return formatFound; + } + + /// + /// Get Object for format from IDataObject + /// + /// IDataObject + /// Type to get + /// object from IDataObject + public static object GetFromDataObject(IDataObject dataObj, Type type) + { + if (type != null) + { + return GetFromDataObject(dataObj, type.FullName); + } + + return null; + } + + /// + /// Get ImageFilenames from the IDataObject + /// + /// IDataObject + /// + public static IEnumerable GetImageFilenames(IDataObject dataObject) + { + string[] dropFileNames = (string[]) dataObject.GetData(DataFormats.FileDrop); + if (dropFileNames != null && dropFileNames.Length > 0) + { + return dropFileNames + .Where(filename => !string.IsNullOrEmpty(filename)) + .Where(Path.HasExtension) + .Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1))); + } + + return Enumerable.Empty(); + } + + /// + /// Get Object for format from IDataObject + /// + /// IDataObject + /// format to get + /// object from IDataObject + public static object GetFromDataObject(IDataObject dataObj, string format) + { + if (dataObj != null) + { + try + { + return dataObj.GetData(format); + } + catch (Exception e) + { + Log.Error("Error in GetClipboardData.", e); + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/CoreConfiguration.cs b/src/Greenshot.Base/Core/CoreConfiguration.cs new file mode 100644 index 000000000..638613011 --- /dev/null +++ b/src/Greenshot.Base/Core/CoreConfiguration.cs @@ -0,0 +1,737 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Reflection; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Base.Core +{ + public enum ClipboardFormat + { + PNG, + DIB, + HTML, + HTMLDATAURL, + BITMAP, + DIBV5 + } + + public enum OutputFormat + { + bmp, + gif, + jpg, + png, + tiff, + greenshot, + ico + } + + public enum WindowCaptureMode + { + Screen, + GDI, + Aero, + AeroTransparent, + Auto + } + + public enum BuildStates + { + UNSTABLE, + RELEASE_CANDIDATE, + RELEASE + } + + public enum ClickActions + { + DO_NOTHING, + OPEN_LAST_IN_EXPLORER, + OPEN_LAST_IN_EDITOR, + OPEN_SETTINGS, + SHOW_CONTEXT_MENU + } + + /// + /// Description of CoreConfiguration. + /// + [IniSection("Core", Description = "Greenshot core configuration")] + public class CoreConfiguration : IniSection, INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + [IniProperty("Language", Description = "The language in IETF format (e.g. en-US)")] + public string Language { get; set; } + + [IniProperty("RegionHotkey", Description = "Hotkey for starting the region capture", DefaultValue = "PrintScreen")] + public string RegionHotkey { get; set; } + + [IniProperty("WindowHotkey", Description = "Hotkey for starting the window capture", DefaultValue = "Alt + PrintScreen")] + public string WindowHotkey { get; set; } + + [IniProperty("FullscreenHotkey", Description = "Hotkey for starting the fullscreen capture", DefaultValue = "Ctrl + PrintScreen")] + public string FullscreenHotkey { get; set; } + + [IniProperty("LastregionHotkey", Description = "Hotkey for starting the last region capture", DefaultValue = "Shift + PrintScreen")] + public string LastregionHotkey { get; set; } + + [IniProperty("IEHotkey", Description = "Hotkey for starting the IE capture", DefaultValue = "Shift + Ctrl + PrintScreen")] + public string IEHotkey { get; set; } + + [IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor")] + public string ClipboardHotkey { get; set; } + + [IniProperty("IsFirstLaunch", Description = "Is this the first time launch?", DefaultValue = "true")] + public bool IsFirstLaunch { get; set; } + + [IniProperty("Destinations", Separator = ",", + Description = "Which destinations? Possible options (more might be added by plugins) are: Editor, FileDefault, FileWithDialog, Clipboard, Printer, EMail, Picker", + DefaultValue = "Picker")] + public List OutputDestinations { get; set; } = new List(); + + [IniProperty("ClipboardFormats", Separator = ",", Description = "Specify which formats we copy on the clipboard? Options are: PNG, HTML, HTMLDATAURL and DIB", + DefaultValue = "PNG,DIB")] + public List ClipboardFormats { get; set; } = new List(); + + [IniProperty("CaptureMousepointer", Description = "Should the mouse be captured?", DefaultValue = "true")] + public bool CaptureMousepointer { get; set; } + + [IniProperty("CaptureWindowsInteractive", Description = "Use interactive window selection to capture? (false=Capture active window)", DefaultValue = "false")] + public bool CaptureWindowsInteractive { get; set; } + + [IniProperty("CaptureDelay", Description = "Capture delay in millseconds.", DefaultValue = "100")] + public int CaptureDelay { get; set; } + + [IniProperty("ScreenCaptureMode", Description = "The capture mode used to capture a screen. (Auto, FullScreen, Fixed)", DefaultValue = "Auto")] + public ScreenCaptureMode ScreenCaptureMode { get; set; } + + [IniProperty("ScreenToCapture", Description = "The screen number to capture when using ScreenCaptureMode Fixed.", DefaultValue = "1")] + public int ScreenToCapture { get; set; } + + [IniProperty("WindowCaptureMode", Description = "The capture mode used to capture a Window (Screen, GDI, Aero, AeroTransparent, Auto).", DefaultValue = "Auto")] + public WindowCaptureMode WindowCaptureMode { get; set; } + + [IniProperty("WindowCaptureAllChildLocations", + Description = "Enable/disable capture all children, very slow but will make it possible to use this information in the editor.", DefaultValue = "False")] + public bool WindowCaptureAllChildLocations { get; set; } + + [IniProperty("DWMBackgroundColor", Description = "The background color for a DWM window capture.")] + public Color DWMBackgroundColor { get; set; } + + [IniProperty("PlayCameraSound", LanguageKey = "settings_playsound", Description = "Play a camera sound after taking a capture.", DefaultValue = "false")] + public bool PlayCameraSound { get; set; } = false; + + [IniProperty("ShowTrayNotification", LanguageKey = "settings_shownotify", Description = "Show a notification from the systray when a capture is taken.", + DefaultValue = "true")] + public bool ShowTrayNotification { get; set; } = true; + + [IniProperty("OutputFilePath", Description = "Output file path.")] + public string OutputFilePath { get; set; } + + [IniProperty("OutputFileAllowOverwrite", + Description = "If the target file already exists True will make Greenshot always overwrite and False will display a 'Save-As' dialog.", DefaultValue = "true")] + public bool OutputFileAllowOverwrite { get; set; } + + [IniProperty("OutputFileFilenamePattern", Description = "Filename pattern for screenshot.", DefaultValue = "${capturetime:d\"yyyy-MM-dd HH_mm_ss\"}-${title}")] + public string OutputFileFilenamePattern { get; set; } + + [IniProperty("OutputFileFormat", Description = "Default file type for writing screenshots. (bmp, gif, jpg, png, tiff)", DefaultValue = "png")] + public OutputFormat OutputFileFormat { get; set; } = OutputFormat.png; + + [IniProperty("OutputFileReduceColors", Description = "If set to true, than the colors of the output file are reduced to 256 (8-bit) colors", DefaultValue = "false")] + public bool OutputFileReduceColors { get; set; } + + [IniProperty("OutputFileAutoReduceColors", + Description = "If set to true the amount of colors is counted and if smaller than 256 the color reduction is automatically used.", DefaultValue = "false")] + public bool OutputFileAutoReduceColors { get; set; } + + [IniProperty("OutputFileReduceColorsTo", Description = "Amount of colors to reduce to, when reducing", DefaultValue = "256")] + public int OutputFileReduceColorsTo { get; set; } + + [IniProperty("OutputFileCopyPathToClipboard", Description = "When saving a screenshot, copy the path to the clipboard?", DefaultValue = "true")] + public bool OutputFileCopyPathToClipboard { get; set; } + + [IniProperty("OutputFileAsFullpath", Description = "SaveAs Full path?")] + public string OutputFileAsFullpath { get; set; } + + [IniProperty("OutputFileJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int OutputFileJpegQuality { get; set; } + + [IniProperty("OutputFilePromptQuality", Description = "Ask for the quality before saving?", DefaultValue = "false")] + public bool OutputFilePromptQuality { get; set; } + + [IniProperty("OutputFileIncrementingNumber", Description = "The number for the ${NUM} in the filename pattern, is increased automatically after each save.", + DefaultValue = "1")] + public uint OutputFileIncrementingNumber { get; set; } + + [IniProperty("OutputPrintPromptOptions", LanguageKey = "settings_alwaysshowprintoptionsdialog", Description = "Ask for print options when printing?", + DefaultValue = "true")] + public bool OutputPrintPromptOptions { get; set; } + + [IniProperty("OutputPrintAllowRotate", LanguageKey = "printoptions_allowrotate", Description = "Allow rotating the picture for fitting on paper?", DefaultValue = "false")] + public bool OutputPrintAllowRotate { get; set; } + + [IniProperty("OutputPrintAllowEnlarge", LanguageKey = "printoptions_allowenlarge", Description = "Allow growing the picture for fitting on paper?", DefaultValue = "false")] + public bool OutputPrintAllowEnlarge { get; set; } + + [IniProperty("OutputPrintAllowShrink", LanguageKey = "printoptions_allowshrink", Description = "Allow shrinking the picture for fitting on paper?", DefaultValue = "true")] + public bool OutputPrintAllowShrink { get; set; } + + [IniProperty("OutputPrintCenter", LanguageKey = "printoptions_allowcenter", Description = "Center image when printing?", DefaultValue = "true")] + public bool OutputPrintCenter { get; set; } + + [IniProperty("OutputPrintInverted", LanguageKey = "printoptions_inverted", Description = "Print image inverted (use e.g. for console captures)", DefaultValue = "false")] + public bool OutputPrintInverted { get; set; } + + [IniProperty("OutputPrintGrayscale", LanguageKey = "printoptions_printgrayscale", Description = "Force grayscale printing", DefaultValue = "false")] + public bool OutputPrintGrayscale { get; set; } + + [IniProperty("OutputPrintMonochrome", LanguageKey = "printoptions_printmonochrome", Description = "Force monorchrome printing", DefaultValue = "false")] + public bool OutputPrintMonochrome { get; set; } + + [IniProperty("OutputPrintMonochromeThreshold", Description = "Threshold for monochrome filter (0 - 255), lower value means less black", DefaultValue = "127")] + public byte OutputPrintMonochromeThreshold { get; set; } + + [IniProperty("OutputPrintFooter", LanguageKey = "printoptions_timestamp", Description = "Print footer on print?", DefaultValue = "true")] + public bool OutputPrintFooter { get; set; } + + [IniProperty("OutputPrintFooterPattern", Description = "Footer pattern", DefaultValue = "${capturetime:d\"D\"} ${capturetime:d\"T\"} - ${title}")] + public string OutputPrintFooterPattern { get; set; } + + [IniProperty("NotificationSound", Description = "The wav-file to play when a capture is taken, loaded only once at the Greenshot startup", DefaultValue = "default")] + public string NotificationSound { get; set; } + + [IniProperty("UseProxy", Description = "Use your global proxy?", DefaultValue = "True")] + public bool UseProxy { get; set; } + + [IniProperty("IECapture", Description = "Enable/disable IE capture", DefaultValue = "True")] + public bool IECapture { get; set; } + + [IniProperty("IEFieldCapture", Description = "Enable/disable IE field capture, very slow but will make it possible to annotate the fields of a capture in the editor.", + DefaultValue = "False")] + public bool IEFieldCapture { get; set; } + + [IniProperty("WindowClassesToCheckForIE", Description = "Comma separated list of Window-Classes which need to be checked for a IE instance!", + DefaultValue = "AfxFrameOrView70,IMWindowClass")] + public List WindowClassesToCheckForIE { get; set; } + + [IniProperty("AutoCropDifference", + Description = + "Sets how to compare the colors for the autocrop detection, the higher the more is 'selected'. Possible values are from 0 to 255, where everything above ~150 doesn't make much sense!", + DefaultValue = "10")] + public int AutoCropDifference { get; set; } + + [IniProperty("IncludePlugins", + Description = "Comma separated list of Plugins which are allowed. If something in the list, than every plugin not in the list will not be loaded!")] + public List IncludePlugins { get; set; } + + [IniProperty("ExcludePlugins", Description = "Comma separated list of Plugins which are NOT allowed.")] + public List ExcludePlugins { get; set; } + + [IniProperty("ExcludeDestinations", Description = "Comma separated list of destinations which should be disabled.")] + public List ExcludeDestinations { get; set; } + + [IniProperty("UpdateCheckInterval", Description = "How many days between every update check? (0=no checks)", DefaultValue = "14")] + public int UpdateCheckInterval { get; set; } + + [IniProperty("LastUpdateCheck", Description = "Last update check")] + public DateTime LastUpdateCheck { get; set; } + + [IniProperty("DisableSettings", Description = "Enable/disable the access to the settings, can only be changed manually in this .ini", DefaultValue = "False")] + public bool DisableSettings { get; set; } + + [IniProperty("DisableQuickSettings", Description = "Enable/disable the access to the quick settings, can only be changed manually in this .ini", DefaultValue = "False")] + public bool DisableQuickSettings { get; set; } + + [IniProperty("DisableTrayicon", Description = "Disable the trayicon, can only be changed manually in this .ini", DefaultValue = "False")] + public bool HideTrayicon { get; set; } + + [IniProperty("HideExpertSettings", Description = "Hide expert tab in the settings, can only be changed manually in this .ini", DefaultValue = "False")] + public bool HideExpertSettings { get; set; } + + [IniProperty("ThumnailPreview", Description = "Enable/disable thumbnail previews", DefaultValue = "True")] + public bool ThumnailPreview { get; set; } + + [IniProperty("NoGDICaptureForProduct", Description = "List of productnames for which GDI capturing is skipped (using fallback).", DefaultValue = "IntelliJ IDEA")] + public List NoGDICaptureForProduct { get; set; } + + [IniProperty("NoDWMCaptureForProduct", Description = "List of productnames for which DWM capturing is skipped (using fallback).", DefaultValue = "Citrix ICA Client")] + public List NoDWMCaptureForProduct { get; set; } + + [IniProperty("OptimizeForRDP", Description = "Make some optimizations for usage with remote desktop", DefaultValue = "False")] + public bool OptimizeForRDP { get; set; } + + [IniProperty("DisableRDPOptimizing", Description = "Disable all optimizations for usage with remote desktop", DefaultValue = "False")] + public bool DisableRDPOptimizing { get; set; } + + [IniProperty("MinimizeWorkingSetSize", Description = "Optimize memory footprint, but with a performance penalty!", DefaultValue = "False")] + public bool MinimizeWorkingSetSize { get; set; } + + [IniProperty("WindowCaptureRemoveCorners", Description = "Remove the corners from a window capture", DefaultValue = "True")] + public bool WindowCaptureRemoveCorners { get; set; } + + [IniProperty("CheckForUnstable", Description = "Also check for unstable version updates", DefaultValue = "False")] + public bool CheckForUnstable { get; set; } + + [IniProperty("ActiveTitleFixes", Description = "The fixes that are active.")] + public List ActiveTitleFixes { get; set; } + + [IniProperty("TitleFixMatcher", Description = "The regular expressions to match the title with.")] + public Dictionary TitleFixMatcher { get; set; } + + [IniProperty("TitleFixReplacer", Description = "The replacements for the matchers.")] + public Dictionary TitleFixReplacer { get; set; } + + [IniProperty("ExperimentalFeatures", Description = "A list of experimental features, this allows us to test certain features before releasing them.", ExcludeIfNull = true)] + public List ExperimentalFeatures { get; set; } + + [IniProperty("EnableSpecialDIBClipboardReader", Description = "Enable a special DIB clipboard reader", DefaultValue = "True")] + public bool EnableSpecialDIBClipboardReader { get; set; } + + [IniProperty("WindowCornerCutShape", Description = "The cutshape which is used to remove the window corners, is mirrorred for all corners", DefaultValue = "5,3,2,1,1")] + public List WindowCornerCutShape { get; set; } + + [IniProperty("LeftClickAction", + Description = + "Specify what action is made if the tray icon is left clicked, if a double-click action is specified this action is initiated after a delay (configurable via the windows double-click speed)", + DefaultValue = "SHOW_CONTEXT_MENU")] + public ClickActions LeftClickAction { get; set; } + + [IniProperty("DoubleClickAction", Description = "Specify what action is made if the tray icon is double clicked", DefaultValue = "OPEN_LAST_IN_EXPLORER")] + public ClickActions DoubleClickAction { get; set; } + + [IniProperty("ZoomerEnabled", Description = "Sets if the zoomer is enabled", DefaultValue = "True")] + public bool ZoomerEnabled { get; set; } + + [IniProperty("ZoomerOpacity", + Description = "Specify the transparency for the zoomer, from 0-1 (where 1 is no transparency and 0 is complete transparent. An usefull setting would be 0.7)", + DefaultValue = "1")] + public float ZoomerOpacity { get; set; } + + [IniProperty("MaxMenuItemLength", + Description = "Maximum length of submenu items in the context menu, making this longer might cause context menu issues on dual screen systems.", DefaultValue = "25")] + public int MaxMenuItemLength { get; set; } + + [IniProperty("MailApiTo", Description = "The 'to' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] + public string MailApiTo { get; set; } + + [IniProperty("MailApiCC", Description = "The 'CC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] + public string MailApiCC { get; set; } + + [IniProperty("MailApiBCC", Description = "The 'BCC' field for the email destination (settings for Outlook can be found under the Office section)", DefaultValue = "")] + public string MailApiBCC { get; set; } + + [IniProperty("OptimizePNGCommand", + Description = + "Optional command to execute on a temporary PNG file, the command should overwrite the file and Greenshot will read it back. Note: this command is also executed when uploading PNG's!", + DefaultValue = "")] + public string OptimizePNGCommand { get; set; } + + [IniProperty("OptimizePNGCommandArguments", + Description = + "Arguments for the optional command to execute on a PNG, {0} is replaced by the temp-filename from Greenshot. Note: Temp-file is deleted afterwards by Greenshot.", + DefaultValue = "\"{0}\"")] + public string OptimizePNGCommandArguments { get; set; } + + [IniProperty("LastSaveWithVersion", Description = "Version of Greenshot which created this .ini")] + public string LastSaveWithVersion { get; set; } + + [IniProperty("ProcessEXIFOrientation", Description = "When reading images from files or clipboard, use the EXIF information to correct the orientation", + DefaultValue = "True")] + public bool ProcessEXIFOrientation { get; set; } + + [IniProperty("LastCapturedRegion", Description = "The last used region, for reuse in the capture last region")] + public Rectangle LastCapturedRegion { get; set; } + + [IniProperty("Win10BorderCrop", Description = "The capture is cropped with these settings, e.g. when you don't want to color around it -1,-1"), DefaultValue("0,0")] + public Size Win10BorderCrop { get; set; } + + private Size _iconSize; + + [IniProperty("BaseIconSize", + Description = "Defines the base size of the icons (e.g. for the buttons in the editor), default value 16,16 and it's scaled to the current DPI", + DefaultValue = "16,16")] + public Size IconSize + { + get { return _iconSize; } + set + { + Size newSize = value; + if (newSize != Size.Empty) + { + if (newSize.Width < 16) + { + newSize.Width = 16; + } + else if (newSize.Width > 256) + { + newSize.Width = 256; + } + + newSize.Width = (newSize.Width / 16) * 16; + if (newSize.Height < 16) + { + newSize.Height = 16; + } + else if (IconSize.Height > 256) + { + newSize.Height = 256; + } + + newSize.Height = (newSize.Height / 16) * 16; + } + + if (_iconSize != newSize) + { + _iconSize = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IconSize")); + } + } + } + + public Size ScaledIconSize => DpiHelper.ScaleWithCurrentDpi(_iconSize); + + [IniProperty("WebRequestTimeout", Description = "The connect timeout value for webrequets, these are seconds", DefaultValue = "100")] + public int WebRequestTimeout { get; set; } + + [IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")] + public int WebRequestReadWriteTimeout { get; set; } + + public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32; + + /// + /// A helper method which returns true if the supplied experimental feature is enabled + /// + /// + /// + public bool IsExperimentalFeatureEnabled(string experimentalFeature) + { + return (ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature)); + } + + /// + /// Supply values we can't put as defaults + /// + /// The property to return a default for + /// object with the default value for the supplied property + public override object GetDefault(string property) + { + switch (property) + { + case "PluginWhitelist": + case "PluginBacklist": + return new List(); + case "OutputFileAsFullpath": + if (IniConfig.IsPortable) + { + return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png"); + } + + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "dummy.png"); + case "OutputFilePath": + if (IniConfig.IsPortable) + { + string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots"); + if (!Directory.Exists(pafOutputFilePath)) + { + try + { + Directory.CreateDirectory(pafOutputFilePath); + return pafOutputFilePath; + } + catch (Exception ex) + { + LOG.Warn(ex); + // Problem creating directory, fallback to Desktop + } + } + else + { + return pafOutputFilePath; + } + } + + return Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + case "DWMBackgroundColor": + return Color.Transparent; + case "ActiveTitleFixes": + return new List + { + "Firefox", + "IE", + "Chrome" + }; + case "TitleFixMatcher": + return new Dictionary + { + { + "Firefox", " - Mozilla Firefox.*" + }, + { + "IE", " - (Microsoft|Windows) Internet Explorer.*" + }, + { + "Chrome", " - Google Chrome.*" + } + }; + case "TitleFixReplacer": + return new Dictionary + { + { + "Firefox", string.Empty + }, + { + "IE", string.Empty + }, + { + "Chrome", string.Empty + } + }; + } + + return null; + } + + /// + /// This method will be called before converting the property, making to possible to correct a certain value + /// Can be used when migration is needed + /// + /// The name of the property + /// The string value of the property + /// string with the propertyValue, modified or not... + public override string PreCheckValue(string propertyName, string propertyValue) + { + // Changed the separator, now we need to correct this + if ("Destinations".Equals(propertyName)) + { + if (propertyValue != null) + { + return propertyValue.Replace('|', ','); + } + } + + if ("OutputFilePath".Equals(propertyName)) + { + if (string.IsNullOrEmpty(propertyValue)) + { + return null; + } + } + + return base.PreCheckValue(propertyName, propertyValue); + } + + /// + /// This method will be called before writing the configuration + /// + public override void BeforeSave() + { + try + { + // Store version, this can be used later to fix settings after an update + LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); + } + catch + { + // ignored + } + } + + /// + /// This method will be called after reading the configuration, so eventually some corrections can be made + /// + public override void AfterLoad() + { + // Comment with releases + // CheckForUnstable = true; + + if (string.IsNullOrEmpty(LastSaveWithVersion)) + { + try + { + // Store version, this can be used later to fix settings after an update + LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); + } + catch + { + // ignored + } + + // Disable the AutoReduceColors as it causes issues with Mozzila applications and some others + OutputFileAutoReduceColors = false; + } + + // Fix for excessive feed checking + if (UpdateCheckInterval != 0 && UpdateCheckInterval <= 7 && LastSaveWithVersion.StartsWith("1.2")) + { + UpdateCheckInterval = 14; + } + + if (UpdateCheckInterval > 365) + { + UpdateCheckInterval = 365; + } + + // Enable OneNote if upgrading from 1.1 + if (ExcludeDestinations != null && ExcludeDestinations.Contains("OneNote")) + { + if (LastSaveWithVersion != null && LastSaveWithVersion.StartsWith("1.1")) + { + ExcludeDestinations.Remove("OneNote"); + } + else + { + // TODO: Remove with the release + ExcludeDestinations.Remove("OneNote"); + } + } + + if (OutputDestinations == null) + { + OutputDestinations = new List(); + } + + // Make sure there is an output! + if (OutputDestinations.Count == 0) + { + OutputDestinations.Add("Editor"); + } + + // Prevent both settings at once, bug #3435056 + if (OutputDestinations.Contains("Clipboard") && OutputFileCopyPathToClipboard) + { + OutputFileCopyPathToClipboard = false; + } + + // Make sure we have clipboard formats, otherwise a paste doesn't make sense! + if (ClipboardFormats == null || ClipboardFormats.Count == 0) + { + ClipboardFormats = new List + { + ClipboardFormat.PNG, + ClipboardFormat.HTML, + ClipboardFormat.DIB + }; + } + + // Make sure the lists are lowercase, to speedup the check + if (NoGDICaptureForProduct != null) + { + // Fix error in configuration + if (NoGDICaptureForProduct.Count >= 2) + { + if ("intellij".Equals(NoGDICaptureForProduct[0]) && "idea".Equals(NoGDICaptureForProduct[1])) + { + NoGDICaptureForProduct.RemoveRange(0, 2); + NoGDICaptureForProduct.Add("Intellij Idea"); + IsDirty = true; + } + } + + for (int i = 0; i < NoGDICaptureForProduct.Count; i++) + { + NoGDICaptureForProduct[i] = NoGDICaptureForProduct[i].ToLower(); + } + } + + if (NoDWMCaptureForProduct != null) + { + // Fix error in configuration + if (NoDWMCaptureForProduct.Count >= 3) + { + if ("citrix".Equals(NoDWMCaptureForProduct[0]) && "ica".Equals(NoDWMCaptureForProduct[1]) && "client".Equals(NoDWMCaptureForProduct[2])) + { + NoDWMCaptureForProduct.RemoveRange(0, 3); + NoDWMCaptureForProduct.Add("Citrix ICA Client"); + IsDirty = true; + } + } + + for (int i = 0; i < NoDWMCaptureForProduct.Count; i++) + { + NoDWMCaptureForProduct[i] = NoDWMCaptureForProduct[i].ToLower(); + } + } + + if (AutoCropDifference < 0) + { + AutoCropDifference = 0; + } + + if (AutoCropDifference > 255) + { + AutoCropDifference = 255; + } + + if (OutputFileReduceColorsTo < 2) + { + OutputFileReduceColorsTo = 2; + } + + if (OutputFileReduceColorsTo > 256) + { + OutputFileReduceColorsTo = 256; + } + + if (WebRequestTimeout <= 10) + { + WebRequestTimeout = 100; + } + + if (WebRequestReadWriteTimeout < 1) + { + WebRequestReadWriteTimeout = 100; + } + } + + /// + /// Validate the OutputFilePath, and if this is not correct it will be set to the default + /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) + /// + public void ValidateAndCorrectOutputFilePath() + { + if (!Directory.Exists(OutputFilePath)) + { + OutputFilePath = GetDefault(nameof(OutputFilePath)) as string; + } + } + + /// + /// Validate the OutputFileAsFullpath, and if this is not correct it will be set to the default + /// Added for BUG-1992, reset the OutputFilePath / OutputFileAsFullpath if they don't exist (e.g. the configuration is used on a different PC) + /// + public void ValidateAndCorrectOutputFileAsFullpath() + { + var outputFilePath = Path.GetDirectoryName(OutputFileAsFullpath); + if (outputFilePath == null || (!File.Exists(OutputFileAsFullpath) && !Directory.Exists(outputFilePath))) + { + OutputFileAsFullpath = GetDefault(nameof(OutputFileAsFullpath)) as string; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/CredentialsHelper.cs b/src/Greenshot.Base/Core/CredentialsHelper.cs new file mode 100644 index 000000000..cc02113a0 --- /dev/null +++ b/src/Greenshot.Base/Core/CredentialsHelper.cs @@ -0,0 +1,525 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +namespace Greenshot.Base.Core +{ + /// + /// The following code comes from: http://www.developerfusion.com/code/4693/using-the-credential-management-api/ + /// and is slightly modified so it works for us. + /// As the "Stored usernames and passwords" which can be accessed by: Start-> Run and type "Control keymgr.dll" + /// doesn't show all credentials use the tool here: http://www.microsoft.com/indonesia/msdn/credmgmt.aspx + /// The following code is an example for a login, it will call the Authenticate with user/password + /// which should return true if the login worked, false if not. + /// private static bool Login(string system, string name) { + /// try { + /// CredentialsDialog dialog = new CredentialsDialog(system); + /// dialog.Name = name; + /// while (dialog.Show(dialog.Name) == DialogResult.OK) { + /// if (Authenticate(dialog.Name, dialog.Password)) { + /// if (dialog.SaveChecked) dialog.Confirm(true); + /// return true; + /// } else { + /// try { + /// dialog.Confirm(false); + /// } catch (ApplicationException) { + /// // exception handling ... + /// } + /// dialog.IncorrectPassword = true; + /// } + /// } + /// } catch (ApplicationException) { + /// // exception handling ... + /// } + /// return false; + /// } + /// + /// Encapsulates dialog functionality from the Credential Management API. + public sealed class CredentialsDialog + { + [DllImport("gdi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteObject(IntPtr hObject); + + /// The only valid bitmap height (in pixels) of a user-defined banner. + private const int ValidBannerHeight = 60; + + /// The only valid bitmap width (in pixels) of a user-defined banner. + private const int ValidBannerWidth = 320; + + /// Initializes a new instance of the class + /// with the specified target. + /// The name of the target for the credentials, typically a server name. + public CredentialsDialog(string target) : this(target, null) + { + } + + /// Initializes a new instance of the class + /// with the specified target and caption. + /// The name of the target for the credentials, typically a server name. + /// The caption of the dialog (null will cause a system default title to be used). + public CredentialsDialog(string target, string caption) : this(target, caption, null) + { + } + + /// Initializes a new instance of the class + /// with the specified target, caption and message. + /// The name of the target for the credentials, typically a server name. + /// The caption of the dialog (null will cause a system default title to be used). + /// The message of the dialog (null will cause a system default message to be used). + public CredentialsDialog(string target, string caption, string message) : this(target, caption, message, null) + { + } + + /// Initializes a new instance of the class + /// with the specified target, caption, message and banner. + /// The name of the target for the credentials, typically a server name. + /// The caption of the dialog (null will cause a system default title to be used). + /// The message of the dialog (null will cause a system default message to be used). + /// The image to display on the dialog (null will cause a system default image to be used). + public CredentialsDialog(string target, string caption, string message, Image banner) + { + Target = target; + Caption = caption; + Message = message; + Banner = banner; + } + + /// + /// Gets or sets if the dialog will be shown even if the credentials + /// can be returned from an existing credential in the credential manager. + /// + public bool AlwaysDisplay { get; set; } + + /// Gets or sets if the dialog is populated with name/password only. + public bool ExcludeCertificates { get; set; } = true; + + /// Gets or sets if the credentials are to be persisted in the credential manager. + public bool Persist { get; set; } = true; + + /// Gets or sets if the incorrect password balloontip needs to be shown. Introduced AFTER Windows XP + public bool IncorrectPassword { get; set; } + + /// Gets or sets if the name is read-only. + public bool KeepName { get; set; } + + private string _name = string.Empty; + + /// Gets or sets the name for the credentials. + public string Name + { + get { return _name; } + set + { + if (value?.Length > CredUi.MAX_USERNAME_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The name has a maximum length of {0} characters.", + CredUi.MAX_USERNAME_LENGTH); + throw new ArgumentException(message, nameof(Name)); + } + + _name = value; + } + } + + private string _password = string.Empty; + + /// Gets or sets the password for the credentials. + public string Password + { + get { return _password; } + set + { + if (value?.Length > CredUi.MAX_PASSWORD_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The password has a maximum length of {0} characters.", + CredUi.MAX_PASSWORD_LENGTH); + throw new ArgumentException(message, nameof(Password)); + } + + _password = value; + } + } + + /// Gets or sets if the save checkbox status. + public bool SaveChecked { get; set; } + + /// Gets or sets if the save checkbox is displayed. + /// This value only has effect if Persist is true. + public bool SaveDisplayed { get; set; } = true; + + private string _target = string.Empty; + + /// Gets or sets the name of the target for the credentials, typically a server name. + public string Target + { + get { return _target; } + set + { + if (value == null) + { + throw new ArgumentException("The target cannot be a null value.", nameof(Target)); + } + + if (value.Length > CredUi.MAX_GENERIC_TARGET_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The target has a maximum length of {0} characters.", + CredUi.MAX_GENERIC_TARGET_LENGTH); + throw new ArgumentException(message, nameof(Target)); + } + + _target = value; + } + } + + private string _caption = string.Empty; + + /// Gets or sets the caption of the dialog. + /// A null value will cause a system default caption to be used. + public string Caption + { + get { return _caption; } + set + { + if (value?.Length > CredUi.MAX_CAPTION_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The caption has a maximum length of {0} characters.", + CredUi.MAX_CAPTION_LENGTH); + throw new ArgumentException(message, nameof(Caption)); + } + + _caption = value; + } + } + + private string _message = string.Empty; + + /// Gets or sets the message of the dialog. + /// A null value will cause a system default message to be used. + public string Message + { + get { return _message; } + set + { + if (value?.Length > CredUi.MAX_MESSAGE_LENGTH) + { + string message = string.Format( + Thread.CurrentThread.CurrentUICulture, + "The message has a maximum length of {0} characters.", + CredUi.MAX_MESSAGE_LENGTH); + throw new ArgumentException(message, nameof(Message)); + } + + _message = value; + } + } + + private Image _banner; + + /// Gets or sets the image to display on the dialog. + /// A null value will cause a system default image to be used. + public Image Banner + { + get { return _banner; } + set + { + if (value != null) + { + if (value.Width != ValidBannerWidth) + { + throw new ArgumentException("The banner image width must be 320 pixels.", nameof(Banner)); + } + + if (value.Height != ValidBannerHeight) + { + throw new ArgumentException("The banner image height must be 60 pixels.", nameof(Banner)); + } + } + + _banner = value; + } + } + + /// Shows the credentials dialog with the specified name. + /// The name for the credentials. + /// Returns a DialogResult indicating the user action. + public DialogResult Show(string name) + { + return Show(null, name, Password, SaveChecked); + } + + /// Shows the credentials dialog with the specified owner, name, password and save checkbox status. + /// The System.Windows.Forms.IWin32Window the dialog will display in front of. + /// The name for the credentials. + /// The password for the credentials. + /// True if the save checkbox is checked. + /// Returns a DialogResult indicating the user action. + public DialogResult Show(IWin32Window owner, string name, string password, bool saveChecked) + { + if ((Environment.OSVersion.Version.Major < 5) || ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor < 1))) + { + throw new ApplicationException("The Credential Management API requires Windows XP / Windows Server 2003 or later."); + } + + Name = name; + Password = password; + SaveChecked = saveChecked; + + return ShowDialog(owner); + } + + /// Confirmation action to be applied. + /// True if the credentials should be persisted. + public void Confirm(bool value) + { + var confirmResult = CredUi.CredUIConfirmCredentials(Target, value); + switch (confirmResult) + { + case CredUi.ReturnCodes.NO_ERROR: + break; + case CredUi.ReturnCodes.ERROR_INVALID_PARAMETER: + // for some reason, this is encountered when credentials are overwritten + break; + default: + throw new ApplicationException($"Credential confirmation failed: {confirmResult}"); + } + } + + /// Returns a DialogResult indicating the user action. + /// The System.Windows.Forms.IWin32Window the dialog will display in front of. + /// + /// Sets the name, password and SaveChecked accessors to the state of the dialog as it was dismissed by the user. + /// + private DialogResult ShowDialog(IWin32Window owner) + { + // set the api call parameters + StringBuilder name = new StringBuilder(CredUi.MAX_USERNAME_LENGTH); + name.Append(Name); + + StringBuilder password = new StringBuilder(CredUi.MAX_PASSWORD_LENGTH); + password.Append(Password); + + int saveChecked = Convert.ToInt32(SaveChecked); + + CredUi.INFO info = GetInfo(owner); + CredUi.CredFlags credFlags = GetFlags(); + + // make the api call + CredUi.ReturnCodes code = CredUi.CredUIPromptForCredentials( + ref info, + Target, + IntPtr.Zero, 0, + name, CredUi.MAX_USERNAME_LENGTH, + password, CredUi.MAX_PASSWORD_LENGTH, + ref saveChecked, + credFlags + ); + + // clean up resources + if (Banner != null) + { + DeleteObject(info.hbmBanner); + } + + // set the accessors from the api call parameters + Name = name.ToString(); + Password = password.ToString(); + SaveChecked = Convert.ToBoolean(saveChecked); + + return GetDialogResult(code); + } + + /// Returns the info structure for dialog display settings. + /// The System.Windows.Forms.IWin32Window the dialog will display in front of. + private CredUi.INFO GetInfo(IWin32Window owner) + { + CredUi.INFO info = new CredUi.INFO(); + if (owner != null) info.hWndParent = owner.Handle; + info.pszCaptionText = Caption; + info.pszMessageText = Message; + if (Banner != null) + { + info.hbmBanner = new Bitmap(Banner, ValidBannerWidth, ValidBannerHeight).GetHbitmap(); + } + + info.cbSize = Marshal.SizeOf(info); + return info; + } + + /// Returns the flags for dialog display options. + private CredUi.CredFlags GetFlags() + { + CredUi.CredFlags credFlags = CredUi.CredFlags.GENERIC_CREDENTIALS; + + if (IncorrectPassword) + { + credFlags |= CredUi.CredFlags.INCORRECT_PASSWORD; + } + + if (AlwaysDisplay) + { + credFlags |= CredUi.CredFlags.ALWAYS_SHOW_UI; + } + + if (ExcludeCertificates) + { + credFlags |= CredUi.CredFlags.EXCLUDE_CERTIFICATES; + } + + if (Persist) + { + credFlags |= CredUi.CredFlags.EXPECT_CONFIRMATION; + if (SaveDisplayed) + { + credFlags |= CredUi.CredFlags.SHOW_SAVE_CHECK_BOX; + } + else + { + credFlags |= CredUi.CredFlags.PERSIST; + } + } + else + { + credFlags |= CredUi.CredFlags.DO_NOT_PERSIST; + } + + if (KeepName) + { + credFlags |= CredUi.CredFlags.KEEP_USERNAME; + } + + return credFlags; + } + + /// Returns a DialogResult from the specified code. + /// The credential return code. + private DialogResult GetDialogResult(CredUi.ReturnCodes code) => + code switch + { + CredUi.ReturnCodes.NO_ERROR => DialogResult.OK, + CredUi.ReturnCodes.ERROR_CANCELLED => DialogResult.Cancel, + CredUi.ReturnCodes.ERROR_NO_SUCH_LOGON_SESSION => throw new ApplicationException( + "No such logon session."), + CredUi.ReturnCodes.ERROR_NOT_FOUND => throw new ApplicationException("Not found."), + CredUi.ReturnCodes.ERROR_INVALID_ACCOUNT_NAME => + throw new ApplicationException("Invalid account name."), + CredUi.ReturnCodes.ERROR_INSUFFICIENT_BUFFER => throw new ApplicationException("Insufficient buffer."), + CredUi.ReturnCodes.ERROR_INVALID_PARAMETER => throw new ApplicationException("Invalid parameter."), + CredUi.ReturnCodes.ERROR_INVALID_FLAGS => throw new ApplicationException("Invalid flags."), + _ => throw new ApplicationException("Unknown credential result encountered.") + }; + } + + internal static class CredUi + { + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/authentication_constants.asp + public const int MAX_MESSAGE_LENGTH = 100; + + public const int MAX_CAPTION_LENGTH = 100; + public const int MAX_GENERIC_TARGET_LENGTH = 100; + public const int MAX_USERNAME_LENGTH = 100; + public const int MAX_PASSWORD_LENGTH = 100; + + /// + /// http://www.pinvoke.net/default.aspx/Enums.CREDUI_FLAGS + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/dpapiusercredentials.asp + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp + /// + [Flags] + public enum CredFlags + { + INCORRECT_PASSWORD = 0x1, + DO_NOT_PERSIST = 0x2, + EXCLUDE_CERTIFICATES = 0x8, + SHOW_SAVE_CHECK_BOX = 0x40, + ALWAYS_SHOW_UI = 0x80, + PERSIST = 0x1000, + EXPECT_CONFIRMATION = 0x20000, + GENERIC_CREDENTIALS = 0x40000, + KEEP_USERNAME = 0x100000, + } + + /// http://www.pinvoke.net/default.aspx/Enums.CredUIReturnCodes + public enum ReturnCodes + { + NO_ERROR = 0, + ERROR_INVALID_PARAMETER = 87, + ERROR_INSUFFICIENT_BUFFER = 122, + ERROR_INVALID_FLAGS = 1004, + ERROR_NOT_FOUND = 1168, + ERROR_CANCELLED = 1223, + ERROR_NO_SUCH_LOGON_SESSION = 1312, + ERROR_INVALID_ACCOUNT_NAME = 1315 + } + + /// + /// http://www.pinvoke.net/default.aspx/Structures.CREDUI_INFO + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/credui_info.asp + /// + public struct INFO + { + public int cbSize; + public IntPtr hWndParent; + [MarshalAs(UnmanagedType.LPWStr)] public string pszMessageText; + [MarshalAs(UnmanagedType.LPWStr)] public string pszCaptionText; + public IntPtr hbmBanner; + } + + /// + /// http://www.pinvoke.net/default.aspx/credui.CredUIPromptForCredentialsW + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduipromptforcredentials.asp + /// + [DllImport("credui", CharSet = CharSet.Unicode)] + public static extern ReturnCodes CredUIPromptForCredentials( + ref INFO creditUR, + string targetName, + IntPtr reserved1, + int iError, + StringBuilder userName, + int maxUserName, + StringBuilder password, + int maxPassword, + ref int iSave, + CredFlags credFlags + ); + + /// + /// http://www.pinvoke.net/default.aspx/credui.CredUIConfirmCredentials + /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthn/security/creduiconfirmcredentials.asp + /// + [DllImport("credui.dll", CharSet = CharSet.Unicode)] + public static extern ReturnCodes CredUIConfirmCredentials(string targetName, [MarshalAs(UnmanagedType.Bool)] bool confirm); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/DisplayKeyAttribute.cs b/src/Greenshot.Base/Core/DisplayKeyAttribute.cs similarity index 74% rename from GreenshotPlugin/Core/DisplayKeyAttribute.cs rename to src/Greenshot.Base/Core/DisplayKeyAttribute.cs index 8f1b81b68..39ac43b13 100644 --- a/GreenshotPlugin/Core/DisplayKeyAttribute.cs +++ b/src/Greenshot.Base/Core/DisplayKeyAttribute.cs @@ -1,35 +1,40 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; - -namespace GreenshotPlugin.Core { - [AttributeUsage(AttributeTargets.Field)] - public sealed class DisplayKeyAttribute : Attribute { - public string Value { get; } - - public DisplayKeyAttribute(string v) { - Value = v; - } - - public DisplayKeyAttribute() { - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Core +{ + [AttributeUsage(AttributeTargets.Field)] + public sealed class DisplayKeyAttribute : Attribute + { + public string Value { get; } + + public DisplayKeyAttribute(string v) + { + Value = v; + } + + public DisplayKeyAttribute() + { + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/DpiHelper.cs b/src/Greenshot.Base/Core/DpiHelper.cs similarity index 93% rename from GreenshotPlugin/Core/DpiHelper.cs rename to src/Greenshot.Base/Core/DpiHelper.cs index 7f98f69a6..bcb3314b6 100644 --- a/GreenshotPlugin/Core/DpiHelper.cs +++ b/src/Greenshot.Base/Core/DpiHelper.cs @@ -19,15 +19,15 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Core.Enums; -using GreenshotPlugin.UnmanagedHelpers; using System; using System.Drawing; using System.Runtime.InteropServices; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; +using Greenshot.Base.Core.Enums; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// This handles DPI changes see @@ -56,7 +56,8 @@ namespace GreenshotPlugin.Core { dpi = Dpi; } - return (float)dpi / DefaultScreenDpi; + + return (float) dpi / DefaultScreenDpi; } /// @@ -73,6 +74,7 @@ namespace GreenshotPlugin.Core { dpiScaleFactor = scaleModifier(dpiScaleFactor); } + return dpiScaleFactor * someNumber; } @@ -90,7 +92,8 @@ namespace GreenshotPlugin.Core { dpiScaleFactor = scaleModifier(dpiScaleFactor); } - return new Size((int)(dpiScaleFactor * size.Width), (int)(dpiScaleFactor * size.Height)); + + return new Size((int) (dpiScaleFactor * size.Width), (int) (dpiScaleFactor * size.Height)); } /// @@ -111,13 +114,14 @@ namespace GreenshotPlugin.Core /// uint public static uint GetDpi(POINT location) { - RECT rect = new RECT(location.X, location.Y, 1,1); + RECT rect = new RECT(location.X, location.Y, 1, 1); IntPtr hMonitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONEAREST); var result = GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY); if (result.Succeeded()) { return dpiX; } + return DefaultScreenDpi; } @@ -158,7 +162,8 @@ namespace GreenshotPlugin.Core { return DefaultScreenDpi; } - return (uint)GDI32.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX); + + return (uint) GDI32.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX); } /// @@ -191,4 +196,4 @@ namespace GreenshotPlugin.Core [DllImport("User32.dll")] private static extern uint GetDpiForSystem(); } -} +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/EffectConverter.cs b/src/Greenshot.Base/Core/EffectConverter.cs new file mode 100644 index 000000000..40cb1f5ae --- /dev/null +++ b/src/Greenshot.Base/Core/EffectConverter.cs @@ -0,0 +1,233 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Globalization; +using System.Text; +using Greenshot.Base.Effects; + +namespace Greenshot.Base.Core +{ + public class EffectConverter : TypeConverter + { + // Fix to prevent BUG-1753 + private readonly NumberFormatInfo _numberFormatInfo = new NumberFormatInfo(); + + public EffectConverter() + { + _numberFormatInfo.NumberDecimalSeparator = "."; + _numberFormatInfo.NumberGroupSeparator = ","; + } + + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + + return base.CanConvertFrom(context, sourceType); + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + { + return true; + } + + if (destinationType == typeof(DropShadowEffect)) + { + return true; + } + + if (destinationType == typeof(TornEdgeEffect)) + { + return true; + } + + return base.CanConvertTo(context, destinationType); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + // to string + if (destinationType == typeof(string)) + { + StringBuilder sb = new StringBuilder(); + if (value.GetType() == typeof(DropShadowEffect)) + { + DropShadowEffect effect = value as DropShadowEffect; + RetrieveDropShadowEffectValues(effect, sb); + return sb.ToString(); + } + + if (value.GetType() == typeof(TornEdgeEffect)) + { + TornEdgeEffect effect = value as TornEdgeEffect; + RetrieveDropShadowEffectValues(effect, sb); + sb.Append("|"); + RetrieveTornEdgeEffectValues(effect, sb); + return sb.ToString(); + } + } + + // from string + if (value is string) + { + string settings = value as string; + if (destinationType == typeof(DropShadowEffect)) + { + DropShadowEffect effect = new DropShadowEffect(); + ApplyDropShadowEffectValues(settings, effect); + return effect; + } + + if (destinationType == typeof(TornEdgeEffect)) + { + TornEdgeEffect effect = new TornEdgeEffect(); + ApplyDropShadowEffectValues(settings, effect); + ApplyTornEdgeEffectValues(settings, effect); + return effect; + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string settings) + { + if (settings.Contains("ToothHeight")) + { + return ConvertTo(context, culture, settings, typeof(TornEdgeEffect)); + } + + return ConvertTo(context, culture, settings, typeof(DropShadowEffect)); + } + + return base.ConvertFrom(context, culture, value); + } + + private void ApplyDropShadowEffectValues(string valuesString, DropShadowEffect effect) + { + string[] values = valuesString.Split('|'); + foreach (string nameValuePair in values) + { + string[] pair = nameValuePair.Split(':'); + switch (pair[0]) + { + case "Darkness": + // Fix to prevent BUG-1753 + if (pair[1] != null && float.TryParse(pair[1], NumberStyles.Float, _numberFormatInfo, out var darkness)) + { + if (darkness <= 1.0) + { + effect.Darkness = darkness; + } + } + + break; + case "ShadowSize": + if (int.TryParse(pair[1], out var shadowSize)) + { + effect.ShadowSize = shadowSize; + } + + break; + case "ShadowOffset": + Point shadowOffset = new Point(); + string[] coordinates = pair[1].Split(','); + if (int.TryParse(coordinates[0], out var shadowOffsetX)) + { + shadowOffset.X = shadowOffsetX; + } + + if (int.TryParse(coordinates[1], out var shadowOffsetY)) + { + shadowOffset.Y = shadowOffsetY; + } + + effect.ShadowOffset = shadowOffset; + break; + } + } + } + + private void ApplyTornEdgeEffectValues(string valuesString, TornEdgeEffect effect) + { + string[] values = valuesString.Split('|'); + foreach (string nameValuePair in values) + { + string[] pair = nameValuePair.Split(':'); + switch (pair[0]) + { + case "GenerateShadow": + if (bool.TryParse(pair[1], out var generateShadow)) + { + effect.GenerateShadow = generateShadow; + } + + break; + case "ToothHeight": + if (int.TryParse(pair[1], out var toothHeight)) + { + effect.ToothHeight = toothHeight; + } + + break; + case "HorizontalToothRange": + if (int.TryParse(pair[1], out var horizontalToothRange)) + { + effect.HorizontalToothRange = horizontalToothRange; + } + + break; + case "VerticalToothRange": + if (int.TryParse(pair[1], out var verticalToothRange)) + { + effect.VerticalToothRange = verticalToothRange; + } + + break; + case "Edges": + string[] edges = pair[1].Split(','); + if (bool.TryParse(edges[0], out var edge)) + { + effect.Edges[0] = edge; + } + + if (bool.TryParse(edges[1], out edge)) + { + effect.Edges[1] = edge; + } + + if (bool.TryParse(edges[2], out edge)) + { + effect.Edges[2] = edge; + } + + if (bool.TryParse(edges[3], out edge)) + { + effect.Edges[3] = edge; + } + + break; + } + } + } + + private void RetrieveDropShadowEffectValues(DropShadowEffect effect, StringBuilder sb) + { + // Fix to prevent BUG-1753 is to use the numberFormatInfo + sb.AppendFormat("Darkness:{0}|ShadowSize:{1}|ShadowOffset:{2},{3}", effect.Darkness.ToString("F2", _numberFormatInfo), effect.ShadowSize, effect.ShadowOffset.X, + effect.ShadowOffset.Y); + } + + private void RetrieveTornEdgeEffectValues(TornEdgeEffect effect, StringBuilder sb) + { + sb.AppendFormat("GenerateShadow:{0}|ToothHeight:{1}|HorizontalToothRange:{2}|VerticalToothRange:{3}|Edges:{4},{5},{6},{7}", effect.GenerateShadow, effect.ToothHeight, + effect.HorizontalToothRange, effect.VerticalToothRange, effect.Edges[0], effect.Edges[1], effect.Edges[2], effect.Edges[3]); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/Enums/HResult.cs b/src/Greenshot.Base/Core/Enums/HResult.cs similarity index 96% rename from GreenshotPlugin/Core/Enums/HResult.cs rename to src/Greenshot.Base/Core/Enums/HResult.cs index a1d2036d7..e278162f9 100644 --- a/GreenshotPlugin/Core/Enums/HResult.cs +++ b/src/Greenshot.Base/Core/Enums/HResult.cs @@ -19,7 +19,7 @@ using System.Diagnostics.CodeAnalysis; -namespace GreenshotPlugin.Core.Enums +namespace Greenshot.Base.Core.Enums { /// /// The HRESULT represents Windows error codes @@ -30,4 +30,4 @@ namespace GreenshotPlugin.Core.Enums { S_OK = 0, } -} +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/Enums/MonitorDpiType.cs b/src/Greenshot.Base/Core/Enums/MonitorDpiType.cs similarity index 97% rename from GreenshotPlugin/Core/Enums/MonitorDpiType.cs rename to src/Greenshot.Base/Core/Enums/MonitorDpiType.cs index ebe0033b4..e434f5bb3 100644 --- a/GreenshotPlugin/Core/Enums/MonitorDpiType.cs +++ b/src/Greenshot.Base/Core/Enums/MonitorDpiType.cs @@ -1,8 +1,9 @@ // Copyright (c) Dapplo and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System; -namespace GreenshotPlugin.Core.Enums +namespace Greenshot.Base.Core.Enums { /// /// See diff --git a/GreenshotPlugin/Core/Enums/MonitorFrom.cs b/src/Greenshot.Base/Core/Enums/MonitorFrom.cs similarity index 96% rename from GreenshotPlugin/Core/Enums/MonitorFrom.cs rename to src/Greenshot.Base/Core/Enums/MonitorFrom.cs index 57e57a390..f9d9fcc2b 100644 --- a/GreenshotPlugin/Core/Enums/MonitorFrom.cs +++ b/src/Greenshot.Base/Core/Enums/MonitorFrom.cs @@ -1,8 +1,9 @@ // Copyright (c) Dapplo and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System; -namespace GreenshotPlugin.Core.Enums +namespace Greenshot.Base.Core.Enums { /// /// Flags for the MonitorFromRect / MonitorFromWindow "flags" field diff --git a/GreenshotPlugin/Core/EnvironmentInfo.cs b/src/Greenshot.Base/Core/EnvironmentInfo.cs similarity index 82% rename from GreenshotPlugin/Core/EnvironmentInfo.cs rename to src/Greenshot.Base/Core/EnvironmentInfo.cs index 01eb11772..9c23cd2df 100644 --- a/GreenshotPlugin/Core/EnvironmentInfo.cs +++ b/src/Greenshot.Base/Core/EnvironmentInfo.cs @@ -23,37 +23,38 @@ using System; using System.Reflection; using System.Runtime.InteropServices; using System.Text; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.UnmanagedHelpers; +using Greenshot.Base.IniFile; +using Greenshot.Base.UnmanagedHelpers; using Microsoft.Win32; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { - /// - /// Description of EnvironmentInfo. - /// - public static class EnvironmentInfo - { - private static bool? _isWindows; + /// + /// Description of EnvironmentInfo. + /// + public static class EnvironmentInfo + { + private static bool? _isWindows; - public static bool IsWindows - { - get - { - if (_isWindows.HasValue) - { - return _isWindows.Value; - } - _isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win"); - return _isWindows.Value; - } - } + public static bool IsWindows + { + get + { + if (_isWindows.HasValue) + { + return _isWindows.Value; + } - public static bool IsNet45OrNewer() - { - // Class "ReflectionContext" exists from .NET 4.5 onwards. - return Type.GetType("System.Reflection.ReflectionContext", false) != null; - } + _isWindows = Environment.OSVersion.Platform.ToString().StartsWith("Win"); + return _isWindows.Value; + } + } + + public static bool IsNet45OrNewer() + { + // Class "ReflectionContext" exists from .NET 4.5 onwards. + return Type.GetType("System.Reflection.ReflectionContext", false) != null; + } public static string GetGreenshotVersion(bool shortVersion = false) { @@ -66,8 +67,8 @@ namespace GreenshotPlugin.Core var assemblyFileVersionAttribute = executingAssembly.GetCustomAttribute(); if (!string.IsNullOrEmpty(assemblyFileVersionAttribute?.Version)) { - var assemblyFileVersion = new Version(assemblyFileVersionAttribute.Version); - greenshotVersion = assemblyFileVersion.ToString(3); + var assemblyFileVersion = new Version(assemblyFileVersionAttribute.Version); + greenshotVersion = assemblyFileVersion.ToString(3); } if (!shortVersion) @@ -78,171 +79,181 @@ namespace GreenshotPlugin.Core { greenshotVersion = informationalVersionAttribute.InformationalVersion; } - } + } - return greenshotVersion.Replace("+", " - "); - } + return greenshotVersion.Replace("+", " - "); + } - public static string EnvironmentToString(bool newline) - { - StringBuilder environment = new StringBuilder(); - environment.Append("Software version: " + GetGreenshotVersion()); - if (IniConfig.IsPortable) { - environment.Append(" Portable"); - } - environment.Append(" (" + OsInfo.Bits + " bit)"); + public static string EnvironmentToString(bool newline) + { + StringBuilder environment = new StringBuilder(); + environment.Append("Software version: " + GetGreenshotVersion()); + if (IniConfig.IsPortable) + { + environment.Append(" Portable"); + } - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.Append(".NET runtime version: " + Environment.Version); - if (IsNet45OrNewer()) - { - environment.Append("+"); + environment.Append(" (" + OsInfo.Bits + " bit)"); - } - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.Append("Time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz")); + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } - if (IsWindows) - { - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } + environment.Append(".NET runtime version: " + Environment.Version); + if (IsNet45OrNewer()) + { + environment.Append("+"); + } + + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + + environment.Append("Time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss zzz")); + + if (IsWindows) + { + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } environment.Append($"OS: {OsInfo.Name}"); if (!string.IsNullOrEmpty(OsInfo.Edition)) { environment.Append($" {OsInfo.Edition}"); + } - } if (!string.IsNullOrEmpty(OsInfo.ServicePack)) { environment.Append($" {OsInfo.ServicePack}"); - } + environment.Append($" x{OsInfo.Bits}"); environment.Append($" {OsInfo.VersionString}"); - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - // Get some important information for fixing GDI related Problems - environment.AppendFormat("GDI object count: {0}", User32.GetGuiResourcesGDICount()); - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.AppendFormat("User object count: {0}", User32.GetGuiResourcesUserCount()); - } - else - { - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - environment.AppendFormat("OS: {0}", Environment.OSVersion.Platform); - } - if (newline) - { - environment.AppendLine(); - } - else - { - environment.Append(", "); - } - // TODO: Is this needed? - // environment.AppendFormat("Surface count: {0}", Surface.Count); + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } - return environment.ToString(); - } + // Get some important information for fixing GDI related Problems + environment.AppendFormat("GDI object count: {0}", User32.GetGuiResourcesGDICount()); + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } - public static string ExceptionToString(Exception ex) - { - if (ex == null) - return "null\r\n"; + environment.AppendFormat("User object count: {0}", User32.GetGuiResourcesUserCount()); + } + else + { + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } - StringBuilder report = new StringBuilder(); + environment.AppendFormat("OS: {0}", Environment.OSVersion.Platform); + } - report.AppendLine("Exception: " + ex.GetType()); - report.AppendLine("Message: " + ex.Message); - if (ex.Data.Count > 0) - { - report.AppendLine(); - report.AppendLine("Additional Information:"); - foreach (object key in ex.Data.Keys) - { - object data = ex.Data[key]; - if (data != null) - { - report.AppendLine(key + " : " + data); - } - } - } - if (ex is ExternalException externalException) - { - // e.g. COMException - report.AppendLine().AppendLine("ErrorCode: 0x" + externalException.ErrorCode.ToString("X")); - } + if (newline) + { + environment.AppendLine(); + } + else + { + environment.Append(", "); + } + // TODO: Is this needed? + // environment.AppendFormat("Surface count: {0}", Surface.Count); - report.AppendLine().AppendLine("Stack:").AppendLine(ex.StackTrace); + return environment.ToString(); + } - if (ex is ReflectionTypeLoadException reflectionTypeLoadException) - { - report.AppendLine().AppendLine("LoaderExceptions: "); - foreach (Exception cbE in reflectionTypeLoadException.LoaderExceptions) - { - report.AppendLine(cbE.Message); - } - } + public static string ExceptionToString(Exception ex) + { + if (ex == null) + return "null\r\n"; - if (ex.InnerException != null) - { - report.AppendLine("--- InnerException: ---"); - report.AppendLine(ExceptionToString(ex.InnerException)); - } - return report.ToString(); - } + StringBuilder report = new StringBuilder(); - public static string BuildReport(Exception exception) - { - StringBuilder exceptionText = new StringBuilder(); - exceptionText.AppendLine(EnvironmentToString(true)); - exceptionText.AppendLine(ExceptionToString(exception)); - exceptionText.AppendLine("Configuration dump:"); + report.AppendLine("Exception: " + ex.GetType()); + report.AppendLine("Message: " + ex.Message); + if (ex.Data.Count > 0) + { + report.AppendLine(); + report.AppendLine("Additional Information:"); + foreach (object key in ex.Data.Keys) + { + object data = ex.Data[key]; + if (data != null) + { + report.AppendLine(key + " : " + data); + } + } + } - return exceptionText.ToString(); - } - } + if (ex is ExternalException externalException) + { + // e.g. COMException + report.AppendLine().AppendLine("ErrorCode: 0x" + externalException.ErrorCode.ToString("X")); + } + + report.AppendLine().AppendLine("Stack:").AppendLine(ex.StackTrace); + + if (ex is ReflectionTypeLoadException reflectionTypeLoadException) + { + report.AppendLine().AppendLine("LoaderExceptions: "); + foreach (Exception cbE in reflectionTypeLoadException.LoaderExceptions) + { + report.AppendLine(cbE.Message); + } + } + + if (ex.InnerException != null) + { + report.AppendLine("--- InnerException: ---"); + report.AppendLine(ExceptionToString(ex.InnerException)); + } + + return report.ToString(); + } + + public static string BuildReport(Exception exception) + { + StringBuilder exceptionText = new StringBuilder(); + exceptionText.AppendLine(EnvironmentToString(true)); + exceptionText.AppendLine(ExceptionToString(exception)); + exceptionText.AppendLine("Configuration dump:"); + + return exceptionText.ToString(); + } + } /// /// Provides detailed information about the host operating system. @@ -664,7 +675,6 @@ namespace GreenshotPlugin.Core { return new string(servicePackVersion); } - } } diff --git a/src/Greenshot.Base/Core/EventDelay.cs b/src/Greenshot.Base/Core/EventDelay.cs new file mode 100644 index 000000000..c1a41a1be --- /dev/null +++ b/src/Greenshot.Base/Core/EventDelay.cs @@ -0,0 +1,47 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Core +{ + public class EventDelay + { + private long lastCheck; + private readonly long waitTime; + + public EventDelay(long ticks) + { + waitTime = ticks; + } + + public bool Check() + { + lock (this) + { + long now = DateTime.Now.Ticks; + bool isPassed = now - lastCheck > waitTime; + lastCheck = now; + return isPassed; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/ExplorerHelper.cs b/src/Greenshot.Base/Core/ExplorerHelper.cs new file mode 100644 index 000000000..0ebb88db3 --- /dev/null +++ b/src/Greenshot.Base/Core/ExplorerHelper.cs @@ -0,0 +1,55 @@ +using System; +using System.Diagnostics; +using System.IO; + +namespace Greenshot.Base.Core +{ + /// + /// Simple utility for the explorer + /// + public static class ExplorerHelper + { + /// + /// Open the path in the windows explorer. + /// If the path is a directory, it will just open the explorer with that directory. + /// If the path is a file, the explorer is opened with the directory and the file is selected. + /// + /// Path to file or directory + public static bool OpenInExplorer(string path) + { + if (path == null) + { + return false; + } + + try + { + // Check if path is a directory + if (Directory.Exists(path)) + { + using (Process.Start(path)) + { + return true; + } + } + + // Check if path is a file + if (File.Exists(path)) + { + // Start the explorer process and select the file + using var explorer = Process.Start("explorer.exe", $"/select,\"{path}\""); + explorer?.WaitForInputIdle(500); + return true; + } + } + catch (Exception ex) + { + // Make sure we show what we tried to open in the exception + ex.Data.Add("path", path); + throw; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/FastBitmap.cs b/src/Greenshot.Base/Core/FastBitmap.cs new file mode 100644 index 000000000..3b6685dd0 --- /dev/null +++ b/src/Greenshot.Base/Core/FastBitmap.cs @@ -0,0 +1,1055 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; + +namespace Greenshot.Base.Core +{ + /// + /// The interface for the FastBitmap + /// + public interface IFastBitmap : IDisposable + { + /// + /// Get the color at x,y + /// The returned Color object depends on the underlying pixel format + /// + /// int x + /// int y + /// Color + Color GetColorAt(int x, int y); + + /// + /// Set the color at the specified location + /// + /// int x + /// int y + /// Color + void SetColorAt(int x, int y, Color color); + + /// + /// Get the color at x,y + /// The returned byte[] color depends on the underlying pixel format + /// + /// int x + /// int y + /// byte array + void GetColorAt(int x, int y, byte[] color); + + /// + /// Set the color at the specified location + /// + /// int x + /// int y + /// byte[] color + void SetColorAt(int x, int y, byte[] color); + + /// + /// Lock the bitmap + /// + void Lock(); + + /// + /// Unlock the bitmap + /// + void Unlock(); + + /// + /// Unlock the bitmap and get the underlying bitmap in one call + /// + /// + Bitmap UnlockAndReturnBitmap(); + + /// + /// Size of the underlying image + /// + Size Size { get; } + + /// + /// Height of the image area that this fastbitmap covers + /// + int Height { get; } + + /// + /// Width of the image area that this fastbitmap covers + /// + int Width { get; } + + /// + /// Top of the image area that this fastbitmap covers + /// + int Top { get; } + + /// + /// Left of the image area that this fastbitmap covers + /// + int Left { get; } + + /// + /// Right of the image area that this fastbitmap covers + /// + int Right { get; } + + /// + /// Bottom of the image area that this fastbitmap covers + /// + int Bottom { get; } + + /// + /// Does the underlying image need to be disposed + /// + bool NeedsDispose { get; set; } + + /// + /// Returns if this FastBitmap has an alpha channel + /// + bool HasAlphaChannel { get; } + + /// + /// Draw the stored bitmap to the destionation bitmap at the supplied point + /// + /// Graphics + /// Point with location + void DrawTo(Graphics graphics, Point destination); + + /// + /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle + /// Be aware that the stored bitmap will be resized to the specified rectangle!! + /// + /// Graphics + /// Rectangle with destination + void DrawTo(Graphics graphics, Rectangle destinationRect); + + /// + /// Return true if the coordinates are inside the FastBitmap + /// + /// + /// + /// + bool Contains(int x, int y); + + /// + /// Set the bitmap resolution + /// + /// + /// + void SetResolution(float horizontal, float vertical); + } + + /// + /// This interface can be used for when offsetting is needed + /// + public interface IFastBitmapWithOffset : IFastBitmap + { + /// + /// Return true if the coordinates are inside the FastBitmap + /// + /// + /// + /// + new bool Contains(int x, int y); + + /// + /// Set the color at the specified location, using offsetting so the original coordinates can be used + /// + /// int x + /// int y + /// Color color + new void SetColorAt(int x, int y, Color color); + + /// + /// Set the color at the specified location, using offsetting so the original coordinates can be used + /// + /// int x + /// int y + /// byte[] color + new void SetColorAt(int x, int y, byte[] color); + + /// + /// Get the color at x,y + /// The returned Color object depends on the underlying pixel format + /// + /// int x + /// int y + /// Color + new Color GetColorAt(int x, int y); + + /// + /// Get the color at x,y, using offsetting so the original coordinates can be used + /// The returned byte[] color depends on the underlying pixel format + /// + /// int x + /// int y + /// byte array + new void GetColorAt(int x, int y, byte[] color); + + new int Left { get; set; } + + new int Top { get; set; } + } + + /// + /// This interface can be used for when clipping is needed + /// + public interface IFastBitmapWithClip : IFastBitmap + { + Rectangle Clip { get; set; } + + bool InvertClip { get; set; } + + /// + /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping + /// + /// int x + /// int y + /// Color color + new void SetColorAt(int x, int y, Color color); + + /// + /// Set the color at the specified location, this doesn't do anything if the location is excluded due to clipping + /// + /// int x + /// int y + /// byte[] color + new void SetColorAt(int x, int y, byte[] color); + + /// + /// Return true if the coordinates are inside the FastBitmap and not clipped + /// + /// + /// + /// + new bool Contains(int x, int y); + } + + /// + /// This interface is implemented when there is a alpha-blending possibility + /// + public interface IFastBitmapWithBlend : IFastBitmap + { + Color BackgroundBlendColor { get; set; } + Color GetBlendedColorAt(int x, int y); + } + + /// + /// The base class for the fast bitmap implementation + /// + public abstract unsafe class FastBitmap : IFastBitmapWithClip, IFastBitmapWithOffset + { + protected const int PixelformatIndexA = 3; + protected const int PixelformatIndexR = 2; + protected const int PixelformatIndexG = 1; + protected const int PixelformatIndexB = 0; + + public const int ColorIndexR = 0; + public const int ColorIndexG = 1; + public const int ColorIndexB = 2; + public const int ColorIndexA = 3; + + protected Rectangle Area; + + /// + /// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap + /// + public bool NeedsDispose { get; set; } + + public Rectangle Clip { get; set; } + + public bool InvertClip { get; set; } + + /// + /// The bitmap for which the FastBitmap is creating access + /// + protected Bitmap Bitmap; + + protected BitmapData BmData; + protected int Stride; /* bytes per pixel row */ + protected bool BitsLocked; + protected byte* Pointer; + + public static IFastBitmap Create(Bitmap source) + { + return Create(source, Rectangle.Empty); + } + + public void SetResolution(float horizontal, float vertical) + { + Bitmap.SetResolution(horizontal, vertical); + } + + /// + /// Factory for creating a FastBitmap depending on the pixelformat of the source + /// The supplied rectangle specifies the area for which the FastBitmap does its thing + /// + /// Bitmap to access + /// Rectangle which specifies the area to have access to, can be Rectangle.Empty for the whole image + /// IFastBitmap + public static IFastBitmap Create(Bitmap source, Rectangle area) + { + switch (source.PixelFormat) + { + case PixelFormat.Format8bppIndexed: + return new FastChunkyBitmap(source, area); + case PixelFormat.Format24bppRgb: + return new Fast24RgbBitmap(source, area); + case PixelFormat.Format32bppRgb: + return new Fast32RgbBitmap(source, area); + case PixelFormat.Format32bppArgb: + case PixelFormat.Format32bppPArgb: + return new Fast32ArgbBitmap(source, area); + default: + throw new NotSupportedException($"Not supported Pixelformat {source.PixelFormat}"); + } + } + + /// + /// Factory for creating a FastBitmap as a destination for the source + /// + /// Bitmap to clone + /// new Pixelformat + /// IFastBitmap + public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat) + { + return CreateCloneOf(source, pixelFormat, Rectangle.Empty); + } + + /// + /// Factory for creating a FastBitmap as a destination for the source + /// + /// Bitmap to clone + /// Area of the bitmap to access, can be Rectangle.Empty for the whole + /// IFastBitmap + public static IFastBitmap CreateCloneOf(Image source, Rectangle area) + { + return CreateCloneOf(source, PixelFormat.DontCare, area); + } + + /// + /// Factory for creating a FastBitmap as a destination for the source + /// + /// Bitmap to clone + /// Pixelformat of the cloned bitmap + /// Area of the bitmap to access, can be Rectangle.Empty for the whole + /// IFastBitmap + public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) + { + Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat); + FastBitmap fastBitmap = Create(destination) as FastBitmap; + if (fastBitmap != null) + { + fastBitmap.NeedsDispose = true; + fastBitmap.Left = area.Left; + fastBitmap.Top = area.Top; + } + + return fastBitmap; + } + + /// + /// Factory for creating a FastBitmap as a destination + /// + /// + /// + /// + /// IFastBitmap + public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat, Color backgroundColor) + { + Bitmap destination = ImageHelper.CreateEmpty(newSize.Width, newSize.Height, pixelFormat, backgroundColor, 96f, 96f); + IFastBitmap fastBitmap = Create(destination); + fastBitmap.NeedsDispose = true; + return fastBitmap; + } + + /// + /// Constructor which stores the image and locks it when called + /// + /// Bitmap + /// Rectangle + protected FastBitmap(Bitmap bitmap, Rectangle area) + { + Bitmap = bitmap; + Rectangle bitmapArea = new Rectangle(Point.Empty, bitmap.Size); + if (area != Rectangle.Empty) + { + area.Intersect(bitmapArea); + Area = area; + } + else + { + Area = bitmapArea; + } + + // As the lock takes care that only the specified area is made available we need to calculate the offset + Left = area.Left; + Top = area.Top; + // Default cliping is done to the area without invert + Clip = Area; + InvertClip = false; + // Always lock, so we don't need to do this ourselves + Lock(); + } + + /// + /// Return the size of the image + /// + public Size Size + { + get + { + if (Area == Rectangle.Empty) + { + return Bitmap.Size; + } + + return Area.Size; + } + } + + /// + /// Return the width of the image + /// + public int Width + { + get + { + if (Area == Rectangle.Empty) + { + return Bitmap.Width; + } + + return Area.Width; + } + } + + /// + /// Return the height of the image + /// + public int Height + { + get + { + if (Area == Rectangle.Empty) + { + return Bitmap.Height; + } + + return Area.Height; + } + } + + private int _left; + + /// + /// Return the left of the fastbitmap, this is also used as an offset + /// + public int Left + { + get { return 0; } + set { _left = value; } + } + + /// + /// Return the left of the fastbitmap, this is also used as an offset + /// + int IFastBitmapWithOffset.Left + { + get { return _left; } + set { _left = value; } + } + + private int _top; + + /// + /// Return the top of the fastbitmap, this is also used as an offset + /// + public int Top + { + get { return 0; } + set { _top = value; } + } + + /// + /// Return the top of the fastbitmap, this is also used as an offset + /// + int IFastBitmapWithOffset.Top + { + get { return _top; } + set { _top = value; } + } + + /// + /// Return the right of the fastbitmap + /// + public int Right => Left + Width; + + /// + /// Return the bottom of the fastbitmap + /// + public int Bottom => Top + Height; + + /// + /// Returns the underlying bitmap, unlocks it and prevents that it will be disposed + /// + public Bitmap UnlockAndReturnBitmap() + { + if (BitsLocked) + { + Unlock(); + } + + NeedsDispose = false; + return Bitmap; + } + + public virtual bool HasAlphaChannel => false; + + /// + /// Destructor + /// + ~FastBitmap() + { + Dispose(false); + } + + /// + /// The public accessible Dispose + /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // The bulk of the clean-up code is implemented in Dispose(bool) + + /// + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + protected virtual void Dispose(bool disposing) + { + Unlock(); + if (disposing) + { + if (Bitmap != null && NeedsDispose) + { + Bitmap.Dispose(); + } + } + + Bitmap = null; + BmData = null; + Pointer = null; + } + + /// + /// Lock the bitmap so we have direct access to the memory + /// + public void Lock() + { + if (Width <= 0 || Height <= 0 || BitsLocked) + { + return; + } + + BmData = Bitmap.LockBits(Area, ImageLockMode.ReadWrite, Bitmap.PixelFormat); + BitsLocked = true; + + IntPtr scan0 = BmData.Scan0; + Pointer = (byte*) (void*) scan0; + Stride = BmData.Stride; + } + + /// + /// Unlock the System Memory + /// + public void Unlock() + { + if (BitsLocked) + { + Bitmap.UnlockBits(BmData); + BitsLocked = false; + } + } + + /// + /// Draw the stored bitmap to the destionation bitmap at the supplied point + /// + /// + /// + public void DrawTo(Graphics graphics, Point destination) + { + DrawTo(graphics, new Rectangle(destination, Area.Size)); + } + + /// + /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle + /// Be aware that the stored bitmap will be resized to the specified rectangle!! + /// + /// + /// + public void DrawTo(Graphics graphics, Rectangle destinationRect) + { + // Make sure this.bitmap is unlocked, if it was locked + bool isLocked = BitsLocked; + if (isLocked) + { + Unlock(); + } + + graphics.DrawImage(Bitmap, destinationRect, Area, GraphicsUnit.Pixel); + } + + /// + /// returns true if x & y are inside the FastBitmap + /// + /// + /// + /// true if x & y are inside the FastBitmap + public bool Contains(int x, int y) + { + return Area.Contains(x - Left, y - Top); + } + + public abstract Color GetColorAt(int x, int y); + public abstract void SetColorAt(int x, int y, Color color); + public abstract void GetColorAt(int x, int y, byte[] color); + public abstract void SetColorAt(int x, int y, byte[] color); + + bool IFastBitmapWithClip.Contains(int x, int y) + { + bool contains = Clip.Contains(x, y); + if (InvertClip) + { + return !contains; + } + else + { + return contains; + } + } + + void IFastBitmapWithClip.SetColorAt(int x, int y, byte[] color) + { + bool contains = Clip.Contains(x, y); + if ((InvertClip && contains) || (!InvertClip && !contains)) + { + return; + } + + SetColorAt(x, y, color); + } + + void IFastBitmapWithClip.SetColorAt(int x, int y, Color color) + { + bool contains = Clip.Contains(x, y); + if ((InvertClip && contains) || (!InvertClip && !contains)) + { + return; + } + + SetColorAt(x, y, color); + } + + /// + /// returns true if x & y are inside the FastBitmap + /// + /// + /// + /// true if x & y are inside the FastBitmap + bool IFastBitmapWithOffset.Contains(int x, int y) + { + return Area.Contains(x - Left, y - Top); + } + + Color IFastBitmapWithOffset.GetColorAt(int x, int y) + { + x -= _left; + y -= _top; + return GetColorAt(x, y); + } + + void IFastBitmapWithOffset.GetColorAt(int x, int y, byte[] color) + { + x -= _left; + y -= _top; + GetColorAt(x, y, color); + } + + void IFastBitmapWithOffset.SetColorAt(int x, int y, byte[] color) + { + x -= _left; + y -= _top; + SetColorAt(x, y, color); + } + + void IFastBitmapWithOffset.SetColorAt(int x, int y, Color color) + { + x -= _left; + y -= _top; + SetColorAt(x, y, color); + } + } + + /// + /// This is the implementation of the FastBitmat for the 8BPP pixelformat + /// + public unsafe class FastChunkyBitmap : FastBitmap + { + // Used for indexed images + private readonly Color[] _colorEntries; + private readonly Dictionary _colorCache = new Dictionary(); + + public FastChunkyBitmap(Bitmap source, Rectangle area) : base(source, area) + { + _colorEntries = Bitmap.Palette.Entries; + } + + /// + /// Get the color from the specified location + /// + /// + /// + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = x + (y * Stride); + byte colorIndex = Pointer[offset]; + return _colorEntries[colorIndex]; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference + public override void GetColorAt(int x, int y, byte[] color) + { + throw new NotImplementedException("No performance gain!"); + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference + public override void SetColorAt(int x, int y, byte[] color) + { + throw new NotImplementedException("No performance gain!"); + } + + /// + /// Get the color-index from the specified location + /// + /// + /// + /// byte with index + public byte GetColorIndexAt(int x, int y) + { + int offset = x + (y * Stride); + return Pointer[offset]; + } + + /// + /// Set the color-index at the specified location + /// + /// + /// + /// + public void SetColorIndexAt(int x, int y, byte colorIndex) + { + int offset = x + (y * Stride); + Pointer[offset] = colorIndex; + } + + /// + /// Set the supplied color at the specified location. + /// Throws an ArgumentException if the color is not in the palette + /// + /// + /// + /// Color to set + public override void SetColorAt(int x, int y, Color color) + { + int offset = x + (y * Stride); + if (!_colorCache.TryGetValue(color, out var colorIndex)) + { + bool foundColor = false; + for (colorIndex = 0; colorIndex < _colorEntries.Length; colorIndex++) + { + if (color == _colorEntries[colorIndex]) + { + _colorCache.Add(color, colorIndex); + foundColor = true; + break; + } + } + + if (!foundColor) + { + throw new ArgumentException("No such color!"); + } + } + + Pointer[offset] = colorIndex; + } + } + + /// + /// This is the implementation of the IFastBitmap for 24 bit images (no Alpha) + /// + public unsafe class Fast24RgbBitmap : FastBitmap + { + public Fast24RgbBitmap(Bitmap source, Rectangle area) : base(source, area) + { + } + + /// + /// Retrieve the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// X coordinate + /// Y Coordinate + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = (x * 3) + (y * Stride); + return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); + } + + /// + /// Set the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// + public override void SetColorAt(int x, int y, Color color) + { + int offset = (x * 3) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color.R; + Pointer[PixelformatIndexG + offset] = color.G; + Pointer[PixelformatIndexB + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b) + public override void GetColorAt(int x, int y, byte[] color) + { + int offset = (x * 3) + (y * Stride); + color[PixelformatIndexR] = Pointer[PixelformatIndexR + offset]; + color[PixelformatIndexG] = Pointer[PixelformatIndexG + offset]; + color[PixelformatIndexB] = Pointer[PixelformatIndexB + offset]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b) + public override void SetColorAt(int x, int y, byte[] color) + { + int offset = (x * 3) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color[PixelformatIndexR]; + Pointer[PixelformatIndexG + offset] = color[PixelformatIndexG]; + Pointer[PixelformatIndexB + offset] = color[PixelformatIndexB]; + } + } + + /// + /// This is the implementation of the IFastBitmap for 32 bit images (no Alpha) + /// + public unsafe class Fast32RgbBitmap : FastBitmap + { + public Fast32RgbBitmap(Bitmap source, Rectangle area) : base(source, area) + { + } + + /// + /// Retrieve the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// X coordinate + /// Y Coordinate + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = (x * 4) + (y * Stride); + return Color.FromArgb(255, Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], Pointer[PixelformatIndexB + offset]); + } + + /// + /// Set the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// + public override void SetColorAt(int x, int y, Color color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color.R; + Pointer[PixelformatIndexG + offset] = color.G; + Pointer[PixelformatIndexB + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference (a,r,g,b) + public override void GetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; + color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; + color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b) + public override void SetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R + Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; + Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; + } + } + + /// + /// This is the implementation of the IFastBitmap for 32 bit images with Alpha + /// + public unsafe class Fast32ArgbBitmap : FastBitmap, IFastBitmapWithBlend + { + public override bool HasAlphaChannel => true; + + public Color BackgroundBlendColor { get; set; } + + public Fast32ArgbBitmap(Bitmap source, Rectangle area) : base(source, area) + { + BackgroundBlendColor = Color.White; + } + + /// + /// Retrieve the color at location x,y + /// + /// X coordinate + /// Y Coordinate + /// Color + public override Color GetColorAt(int x, int y) + { + int offset = (x * 4) + (y * Stride); + return Color.FromArgb(Pointer[PixelformatIndexA + offset], Pointer[PixelformatIndexR + offset], Pointer[PixelformatIndexG + offset], + Pointer[PixelformatIndexB + offset]); + } + + /// + /// Set the color at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// + /// + /// + public override void SetColorAt(int x, int y, Color color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexA + offset] = color.A; + Pointer[PixelformatIndexR + offset] = color.R; + Pointer[PixelformatIndexG + offset] = color.G; + Pointer[PixelformatIndexB + offset] = color.B; + } + + /// + /// Get the color from the specified location into the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b,a) + public override void GetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + color[ColorIndexR] = Pointer[PixelformatIndexR + offset]; + color[ColorIndexG] = Pointer[PixelformatIndexG + offset]; + color[ColorIndexB] = Pointer[PixelformatIndexB + offset]; + color[ColorIndexA] = Pointer[PixelformatIndexA + offset]; + } + + /// + /// Set the color at the specified location from the specified array + /// + /// + /// + /// byte[4] as reference (r,g,b,a) + public override void SetColorAt(int x, int y, byte[] color) + { + int offset = (x * 4) + (y * Stride); + Pointer[PixelformatIndexR + offset] = color[ColorIndexR]; // R + Pointer[PixelformatIndexG + offset] = color[ColorIndexG]; + Pointer[PixelformatIndexB + offset] = color[ColorIndexB]; + Pointer[PixelformatIndexA + offset] = color[ColorIndexA]; + } + + /// + /// Retrieve the color, without alpha (is blended), at location x,y + /// Before the first time this is called the Lock() should be called once! + /// + /// X coordinate + /// Y Coordinate + /// Color + public Color GetBlendedColorAt(int x, int y) + { + int offset = (x * 4) + (y * Stride); + int a = Pointer[PixelformatIndexA + offset]; + int red = Pointer[PixelformatIndexR + offset]; + int green = Pointer[PixelformatIndexG + offset]; + int blue = Pointer[PixelformatIndexB + offset]; + + if (a < 255) + { + // As the request is to get without alpha, we blend. + int rem = 255 - a; + red = (red * a + BackgroundBlendColor.R * rem) / 255; + green = (green * a + BackgroundBlendColor.G * rem) / 255; + blue = (blue * a + BackgroundBlendColor.B * rem) / 255; + } + + return Color.FromArgb(255, red, green, blue); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/FilenameHelper.cs b/src/Greenshot.Base/Core/FilenameHelper.cs new file mode 100644 index 000000000..83a76f438 --- /dev/null +++ b/src/Greenshot.Base/Core/FilenameHelper.cs @@ -0,0 +1,705 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using log4net; + +namespace Greenshot.Base.Core +{ + public static class FilenameHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(FilenameHelper)); + + // Specify the regular expression for the filename formatting: + // Starting with ${ + // than the varname, which ends with a : or } + // If a parameters needs to be supplied, than a ":" should follow the name... everything from the : until the } is considered to be part of the parameters. + // The parameter format is a single alpha followed by the value belonging to the parameter, e.g. : + // ${capturetime:d"yyyy-MM-dd HH_mm_ss"} + private static readonly Regex VarRegexp = new Regex(@"\${(?[^:}]+)[:]?(?[^}]*)}", RegexOptions.Compiled); + private static readonly Regex CmdVarRegexp = new Regex(@"%(?[^%]+)%", RegexOptions.Compiled); + + private static readonly Regex SplitRegexp = new Regex(";(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)", RegexOptions.Compiled); + private const int MaxTitleLength = 80; + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private const string UnsafeReplacement = "_"; + private static readonly Random RandomNumberGen = new Random(); + private static readonly Regex RandRegexp = new Regex("^R+$", RegexOptions.Compiled); + + /// + /// Remove invalid characters from the fully qualified filename + /// + /// string with the full path to a file + /// string with the full path to a file, without invalid characters + public static string MakeFqFilenameSafe(string fullPath) + { + string path = MakePathSafe(Path.GetDirectoryName(fullPath)); + string filename = MakeFilenameSafe(Path.GetFileName(fullPath)); + // Make the fullpath again and return + return Path.Combine(path, filename); + } + + /// + /// Remove invalid characters from the filename + /// + /// string with the full path to a file + /// string with the full path to a file, without invalid characters + public static string MakeFilenameSafe(string filename) + { + // Make the filename save! + if (filename != null) + { + foreach (char disallowed in Path.GetInvalidFileNameChars()) + { + filename = filename.Replace(disallowed.ToString(), UnsafeReplacement); + } + } + + return filename; + } + + /// + /// Remove invalid characters from the path + /// + /// string with the full path to a file + /// string with the full path to a file, without invalid characters + public static string MakePathSafe(string path) + { + // Make the path save! + if (path != null) + { + foreach (char disallowed in Path.GetInvalidPathChars()) + { + path = path.Replace(disallowed.ToString(), UnsafeReplacement); + } + } + + return path; + } + + public static string GetFilenameWithoutExtensionFromPattern(string pattern) + { + return GetFilenameWithoutExtensionFromPattern(pattern, null); + } + + public static string GetFilenameWithoutExtensionFromPattern(string pattern, ICaptureDetails captureDetails) + { + return FillPattern(pattern, captureDetails, true); + } + + public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat) + { + return GetFilenameFromPattern(pattern, imageFormat, null); + } + + public static string GetFilenameFromPattern(string pattern, OutputFormat imageFormat, ICaptureDetails captureDetails) + { + return FillPattern(pattern, captureDetails, true) + "." + imageFormat.ToString().ToLower(); + } + + /// + /// Return a filename for the current image format (png,jpg etc) with the default file pattern + /// that is specified in the configuration + /// + /// A string with the format + /// + /// The filename which should be used to save the image + public static string GetFilename(OutputFormat format, ICaptureDetails captureDetails) + { + string pattern = CoreConfig.OutputFileFilenamePattern; + if (string.IsNullOrEmpty(pattern?.Trim())) + { + pattern = "greenshot ${capturetime}"; + } + + return GetFilenameFromPattern(pattern, format, captureDetails); + } + + + /// + /// This method will be called by the regexp.replace as a MatchEvaluator delegate! + /// Will delegate this to the MatchVarEvaluatorInternal and catch any exceptions + /// + /// What are we matching? + /// The detail, can be null + /// Variables from the process + /// Variables from the user + /// Variables from the machine + /// + /// string with the match replacement + private static string MatchVarEvaluator(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, + bool filenameSafeMode) + { + try + { + return MatchVarEvaluatorInternal(match, captureDetails, processVars, userVars, machineVars, filenameSafeMode); + } + catch (Exception e) + { + Log.Error("Error in MatchVarEvaluatorInternal", e); + } + + return string.Empty; + } + + /// + /// This method will be called by the regexp.replace as a MatchEvaluator delegate! + /// + /// What are we matching? + /// The detail, can be null + /// + /// + /// + /// + /// + private static string MatchVarEvaluatorInternal(Match match, ICaptureDetails captureDetails, IDictionary processVars, IDictionary userVars, IDictionary machineVars, + bool filenameSafeMode) + { + // some defaults + int padWidth = 0; + int startIndex = 0; + int endIndex = 0; + char padChar = ' '; + string dateFormat = "yyyy-MM-dd HH-mm-ss"; + IDictionary replacements = new Dictionary(); + string replaceValue = string.Empty; + string variable = match.Groups["variable"].Value; + string parameters = match.Groups["parameters"].Value; + string randomChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + if (parameters.Length > 0) + { + string[] parms = SplitRegexp.Split(parameters); + foreach (string parameter in parms) + { + switch (parameter.Substring(0, 1)) + { + // Padding p[,pad-character] + case "p": + string[] padParams = parameter.Substring(1).Split(','); + try + { + padWidth = int.Parse(padParams[0]); + } + catch + { + // ignored + } + + if (padParams.Length > 1) + { + padChar = padParams[1][0]; + } + + break; + // replace + // r, + case "r": + string[] replaceParameters = parameter.Substring(1).Split(','); + if (replaceParameters != null && replaceParameters.Length == 2) + { + replacements.Add(replaceParameters[0], replaceParameters[1]); + } + + break; + // Dateformat d + // Format can be anything that is used in C# date formatting + case "d": + dateFormat = parameter.Substring(1); + if (dateFormat.StartsWith("\"")) + { + dateFormat = dateFormat.Substring(1); + } + + if (dateFormat.EndsWith("\"")) + { + dateFormat = dateFormat.Substring(0, dateFormat.Length - 1); + } + + break; + // Substring: + // s[,length] + case "s": + string range = parameter.Substring(1); + string[] rangelist = range.Split(','); + if (rangelist.Length > 0) + { + try + { + startIndex = int.Parse(rangelist[0]); + } + catch + { + // Ignore + } + } + + if (rangelist.Length > 1) + { + try + { + endIndex = int.Parse(rangelist[1]); + } + catch + { + // Ignore + } + } + + break; + } + } + } + + if (processVars != null && processVars.Contains(variable)) + { + replaceValue = (string) processVars[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (userVars != null && userVars.Contains(variable)) + { + replaceValue = (string) userVars[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (machineVars != null && machineVars.Contains(variable)) + { + replaceValue = (string) machineVars[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (captureDetails?.MetaData != null && captureDetails.MetaData.ContainsKey(variable)) + { + replaceValue = captureDetails.MetaData[variable]; + if (filenameSafeMode) + { + replaceValue = MakePathSafe(replaceValue); + } + } + else if (RandRegexp.IsMatch(variable)) + { + for (int i = 0; i < variable.Length; i++) + { + replaceValue += randomChars[RandomNumberGen.Next(randomChars.Length)]; + } + } + else + { + // Handle other variables + // Default use "now" for the capture take´n + DateTime capturetime = DateTime.Now; + // Use default application name for title + string title = Application.ProductName; + + // Check if we have capture details + if (captureDetails != null) + { + capturetime = captureDetails.DateTime; + if (captureDetails.Title != null) + { + title = captureDetails.Title; + if (title.Length > MaxTitleLength) + { + title = title.Substring(0, MaxTitleLength); + } + } + } + + switch (variable) + { + case "domain": + replaceValue = Environment.UserDomainName; + break; + case "user": + replaceValue = Environment.UserName; + break; + case "hostname": + replaceValue = Environment.MachineName; + break; + case "YYYY": + if (padWidth == 0) + { + padWidth = -4; + padChar = '0'; + } + + replaceValue = capturetime.Year.ToString(); + break; + case "MM": + replaceValue = capturetime.Month.ToString(); + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } + + break; + case "DD": + replaceValue = capturetime.Day.ToString(); + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } + + break; + case "hh": + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } + + replaceValue = capturetime.Hour.ToString(); + break; + case "mm": + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } + + replaceValue = capturetime.Minute.ToString(); + break; + case "ss": + if (padWidth == 0) + { + padWidth = -2; + padChar = '0'; + } + + replaceValue = capturetime.Second.ToString(); + break; + case "now": + replaceValue = DateTime.Now.ToString(dateFormat); + if (filenameSafeMode) + { + replaceValue = MakeFilenameSafe(replaceValue); + } + + break; + case "capturetime": + replaceValue = capturetime.ToString(dateFormat); + if (filenameSafeMode) + { + replaceValue = MakeFilenameSafe(replaceValue); + } + + break; + case "NUM": + CoreConfig.OutputFileIncrementingNumber++; + IniConfig.Save(); + replaceValue = CoreConfig.OutputFileIncrementingNumber.ToString(); + if (padWidth == 0) + { + padWidth = -6; + padChar = '0'; + } + + break; + case "title": + replaceValue = title; + if (filenameSafeMode) + { + replaceValue = MakeFilenameSafe(replaceValue); + } + + break; + case "MyPictures": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); + break; + case "MyMusic": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic); + break; + case "MyDocuments": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + break; + case "Personal": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Personal); + break; + case "Desktop": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + break; + case "ApplicationData": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + break; + case "LocalApplicationData": + replaceValue = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + break; + } + } + + // do padding + if (padWidth > 0) + { + replaceValue = replaceValue.PadRight(padWidth, padChar); + } + else if (padWidth < 0) + { + replaceValue = replaceValue.PadLeft(-padWidth, padChar); + } + + // do substring + if (startIndex != 0 || endIndex != 0) + { + if (startIndex < 0) + { + startIndex = replaceValue.Length + startIndex; + } + + if (endIndex < 0) + { + endIndex = replaceValue.Length + endIndex; + } + + if (endIndex != 0) + { + try + { + replaceValue = replaceValue.Substring(startIndex, endIndex); + } + catch + { + // Ignore + } + } + else + { + try + { + replaceValue = replaceValue.Substring(startIndex); + } + catch + { + // Ignore + } + } + } + + // new for feature #697 + if (replacements.Count > 0) + { + foreach (string oldValue in replacements.Keys) + { + replaceValue = replaceValue.Replace(oldValue, replacements[oldValue]); + } + } + + return replaceValue; + } + + /// + /// "Simply" fill the pattern with environment variables + /// + /// String with pattern %var% + /// true to make sure everything is filenamesafe + /// Filled string + public static string FillCmdVariables(string pattern, bool filenameSafeMode = true) + { + IDictionary processVars = null; + IDictionary userVars = null; + IDictionary machineVars = null; + try + { + processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); + } + + try + { + userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.User", e); + } + + try + { + machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); + } + + return CmdVarRegexp.Replace(pattern, + m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) + ); + } + + /// + /// "Simply" fill the pattern with environment variables + /// + /// String with pattern ${var} + /// true to make sure everything is filenamesafe + /// Filled string + public static string FillVariables(string pattern, bool filenameSafeMode) + { + IDictionary processVars = null; + IDictionary userVars = null; + IDictionary machineVars = null; + try + { + processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); + } + + try + { + userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.User", e); + } + + try + { + machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); + } + + return VarRegexp.Replace(pattern, + m => MatchVarEvaluator(m, null, processVars, userVars, machineVars, filenameSafeMode) + ); + } + + /// + /// Fill the pattern wit the supplied details + /// + /// Pattern + /// CaptureDetails, can be null + /// Should the result be made "filename" safe? + /// Filled pattern + public static string FillPattern(string pattern, ICaptureDetails captureDetails, bool filenameSafeMode) + { + IDictionary processVars = null; + IDictionary userVars = null; + IDictionary machineVars = null; + try + { + processVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Process", e); + } + + try + { + userVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.User", e); + } + + try + { + machineVars = Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine); + } + catch (Exception e) + { + Log.Error("Error retrieving EnvironmentVariableTarget.Machine", e); + } + + try + { + return VarRegexp.Replace(pattern, + m => MatchVarEvaluator(m, captureDetails, processVars, userVars, machineVars, filenameSafeMode) + ); + } + catch (Exception e) + { + // adding additional data for bug tracking + if (captureDetails != null) + { + e.Data.Add("title", captureDetails.Title); + } + + e.Data.Add("pattern", pattern); + throw; + } + } + + /// + /// Checks whether a directory name is valid in the current file system + /// + /// directory name (not path!) + /// true if directory name is valid + public static bool IsDirectoryNameValid(string directoryName) + { + var forbiddenChars = Path.GetInvalidPathChars(); + foreach (var forbiddenChar in forbiddenChars) + { + if (directoryName == null || directoryName.Contains(forbiddenChar.ToString())) + { + return false; + } + } + + return true; + } + + /// + /// Checks whether a filename is valid in the current file system + /// + /// name of the file + /// true if filename is valid + public static bool IsFilenameValid(string filename) + { + var forbiddenChars = Path.GetInvalidFileNameChars(); + foreach (var forbiddenChar in forbiddenChars) + { + if (filename == null || filename.Contains(forbiddenChar.ToString())) + { + return false; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/Fraction.cs b/src/Greenshot.Base/Core/Fraction.cs similarity index 97% rename from GreenshotPlugin/Core/Fraction.cs rename to src/Greenshot.Base/Core/Fraction.cs index 312b91bb8..e7d999445 100644 --- a/GreenshotPlugin/Core/Fraction.cs +++ b/src/Greenshot.Base/Core/Fraction.cs @@ -1,7 +1,7 @@ using System; using System.Text.RegularExpressions; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// Basic Fraction (Rational) numbers with features only needed to represent scale factors. @@ -19,10 +19,12 @@ namespace GreenshotPlugin.Core { throw new ArgumentException("Can't divide by zero.", nameof(denominator)); } + if (numerator == 0) { throw new ArgumentException("Zero is not supported by this implementation.", nameof(numerator)); } + var gcd = GreatestCommonDivisor(numerator, denominator); Numerator = numerator / gcd; Denominator = denominator / gcd; @@ -34,6 +36,7 @@ namespace GreenshotPlugin.Core #region Parse private static readonly Regex PARSE_REGEX = new Regex(@"^([1-9][0-9]*)\/([1-9][0-9]*)$", RegexOptions.Compiled); + public static bool TryParse(string str, out Fraction result) { var match = PARSE_REGEX.Match(str); @@ -42,6 +45,7 @@ namespace GreenshotPlugin.Core result = Identity; return false; } + var numerator = uint.Parse(match.Groups[1].Value); var denominator = uint.Parse(match.Groups[2].Value); result = new Fraction(numerator, denominator); @@ -78,7 +82,7 @@ namespace GreenshotPlugin.Core } public int CompareTo(Fraction other) - => (int)(Numerator * other.Denominator) - (int)(other.Numerator * Denominator); + => (int) (Numerator * other.Denominator) - (int) (other.Numerator * Denominator); #endregion @@ -149,4 +153,4 @@ namespace GreenshotPlugin.Core private static uint GreatestCommonDivisor(uint a, uint b) => (b != 0) ? GreatestCommonDivisor(b, a % b) : a; } -} +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/GreenshotResources.cs b/src/Greenshot.Base/Core/GreenshotResources.cs similarity index 57% rename from GreenshotPlugin/Core/GreenshotResources.cs rename to src/Greenshot.Base/Core/GreenshotResources.cs index 6b80acf3f..29248012e 100644 --- a/GreenshotPlugin/Core/GreenshotResources.cs +++ b/src/Greenshot.Base/Core/GreenshotResources.cs @@ -1,43 +1,49 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System.ComponentModel; -using System.Drawing; - -namespace GreenshotPlugin.Core { - /// - /// Centralized storage of the icons & bitmaps - /// - public static class GreenshotResources { - private static readonly ComponentResourceManager GreenshotResourceManager = new ComponentResourceManager(typeof(GreenshotResources)); - - public static Image GetImage(string imageName) { - return (Image)GreenshotResourceManager.GetObject(imageName); - } - public static Icon GetIcon(string imageName) { - return (Icon)GreenshotResourceManager.GetObject(imageName); - } - - public static Icon GetGreenshotIcon() { - return GetIcon("Greenshot.Icon"); - } - - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Drawing; + +namespace Greenshot.Base.Core +{ + /// + /// Centralized storage of the icons & bitmaps + /// + public static class GreenshotResources + { + private static readonly ComponentResourceManager GreenshotResourceManager = new ComponentResourceManager(typeof(GreenshotResources)); + + public static Image GetImage(string imageName) + { + return (Image) GreenshotResourceManager.GetObject(imageName); + } + + public static Icon GetIcon(string imageName) + { + return (Icon) GreenshotResourceManager.GetObject(imageName); + } + + public static Icon GetGreenshotIcon() + { + return GetIcon("Greenshot.Icon"); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/GreenshotResources.resx b/src/Greenshot.Base/Core/GreenshotResources.resx similarity index 98% rename from GreenshotPlugin/Core/GreenshotResources.resx rename to src/Greenshot.Base/Core/GreenshotResources.resx index 521a6125f..ea1760d58 100644 --- a/GreenshotPlugin/Core/GreenshotResources.resx +++ b/src/Greenshot.Base/Core/GreenshotResources.resx @@ -1,471 +1,471 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - - AAABAAUAAAAAAAEACAClFwAAVgAAADAwAAABAAgAqA4AAPsXAAAgIAAAAQAIAKgIAACjJgAAGBgAAAEA - CADIBgAASy8AABAQAAABAAgAaAUAABM2AACJUE5HDQoaCgAAAA1JSERSAAABAAAAAQAIBgAAAFxyqGYA - ABdsSURBVHja7Z1fqFVVHsf3YQqnUTJQSJMcujkK3UHuFW5geBXGYK5B0EP6Gto8zIsG8zKY82rCvKXP - 6bv2FqQP9eAfEhS8Eilozo0xTAOFbGycKLjTd9u6nnvvXnuvvff6/dbea30/cEioPPucs9Z3/dbv72By - cnI2I4QkyYACQEi6UAAISRgKACEJQwEgJGEoAIQkDAWAkIShABCSMBQAQhKGAkBIwlAACEkYCgAhCUMB - ICRhKACEJAwFgJCEoQAQkjAUAEIShgJASMJQAAhJGAoAIQlDASAkYSgAhCQMBYCQhKEAEJIwFABCEoYC - QEjCUAAISRgKACEJQwEgJGEoAIQkDAWAkIShABCSMBQAQhKGAkBIwlAACEkYCgAhCUMBICRhKACEJAwF - gJCEoQAQkjAUAEIShgJASMJQAAhJmOgF4MllP2dP/+GH/M8rx77L7t9Ylv304Ins4e0l2X/v/Db04xES - lCgF4Her/pc9v+PbbNXkvezpdT9Y/7uHd5Zkt8+tzL4++Wz2/ZdLQz82IepEJQDY+Ov33Myen/q29v97 - 7/Ly7Nqx32f3ppeH/hiEqBGNAIzsvJVv/ieX/tzq75n5cE12/eja/JpASOxEIQBj715vdOrb+P7G0uyz - fRspAiR6ei8Avje/gSJAUqDXArBh97+z9btviv398AtABAiJld4KwIrx+9kr738u/j5XjoxkMyfWhP64 - hIjQWwF45fDn2Yqx++Lv89MPT2Sf7pzgVYBESS8FQOv0N1w/tjYPERISG70UgIn3rmarttxTez9YAad2 - bA79sQnxTu8EAKm9Ux+fV3/fiwdeyu6cXRH64xPild4JANJ7Jw5eVX9fJAhdOTwS+uMT4pXeCYB06M9G - m5AgfBYoRDJ/BihK+vk/v8nuXn6G6cckGL0TAO37vwGFQ5/setn5v0cFItKTYbFUpSfDx4DrBYqSKAZE - k94JgFb4r4iPtk5W/jcoSBrdN9NYpGBpfHHkRVYnEhUoADWoEgCUIGPzty1IAkxAIhr0TgBCXQFQG3B6 - zybrv8fGH3nzltf3/PrUs9nl99arf1aSDr0TgC46ASWfiSJAJOmdAIQKA9qyATWyEi8fWp87CAnxTe8E - IFQi0Om3Ny1yzOFZth29lD216kfR92Y9ApHCSQDg2cZJh38ivIWFj4aaprEmQleaDTalegDYsIUANa8j - vAoQCawCgE0OrzZi2S4nHJxk8Fojni19UnWhGAjfz/YTF714/F35dNcEOxkTrxQKAE62F3Z902hxw1xF - Tz3pEFbocmCI49j+6+LvPwxDg8Q38wQAJj7CbGWttF2B1/ziuy+JWQN41q3HpsVPYFsRUIhwZFUokpC6 - zAkA7vY4VX1uKNydLxwYFctqkz6Fy+7dUyfPq5r/hlOvbaYzkHgjFwCJzW+ACODUklq0kk1BbactrI/t - xy+KfJ4qPntnY+16ATxvPiTll985d+gOXZ1gqRlHrrYzl4Rn8Kcdm2ex+X2Y/Takm2v6zsK7c25FfvLb - REvbCTlMHQHAc+YFSTWuKvjs8DOwKCkNBn89sWbWdwprEdIOLJxwsAbaWDGuDsyQAuDyPeKUx3fRxkkK - 0YYI0iKIm8E/ZzOVRCCNZBaE5nDiNYlg4L6Pze+y4LtsAfgQQgN+M4gAOyHFi5oAAK3mmhACbAS8sFlt - mwGnHBY3XnVOOtylt31wSetrm0eZAEg5RZmKHC+qAlC3qYYvYBI/tfpxMhOskLaRidfPnFX/HMCWDCRd - I9HE+Ui6j6oAgKKc+j6CGgBJx2kRNgHVyEpkPUKcqAtALNls8DWM7p1RfU9bY1KtpCTWI8SHugA0XUTm - Pr983YNHBUm/nnaI1+NUgnl6+9xKNesiRC5AkfWk7ZCMxYIjj1AXgDo5Adhk8OjDueVq3sJMhoUBp5W0 - uapZlWj73rQrI2kFxEVnBaBNQRKAEKC5pmQIS9MKKHLCheqNwHTkeOicAGBR407rq9JP+sTS6Algu/uH - 6o7EKUnxoC4ASDVFlWAR2PwSacnSIiBZmgwfBwSz6MQN1R/RRz6HaSwDTGMZoo+6ANgWj9TmN0iKgNSz - l21+EKpFepPaDmx4+HIwIcn2PeHvxTUH/hsKgg7qAmBLKNEIZUmGICECcMj5+gwu/RT6IACIUvxx779q - iyPeAwcFk49kURUA25htrVCWRjIL8gPW77nZ2HmJZ/zq+HNOJnaXBcCXLweWG/wfdDrKoCoANjNccyFr - hLGaFCVh48P0xeZ3NX+7KgC++0vgKjR9aAPzDwRQFYCiPPYQlXWaYSxbAhMwzThMQVJdQglAmSNXqrkM - BBKiQxHwy+Dv08tnNRaR7eTVTmQBsVS3dS0KIN2nscopSuoz+PPOiVnp5ppld+8QvfXKTrA+Eaovgc2R - q2GRxPLbdYW8J6B0c03bgglVV29zRvYRbQG1fXeabdJZmuyPua7AIZpJhOysE0s6q8RU4jJsWYmvHr8g - PiLNIN1jMiXmzQXwOd/epZ1UqDssiOUU0a5KLHLkhkhJZlWiHxZNBoJZjsQNjYaSFAA/aH2PNudfiCEp - NkuE1MM6GxDWAF51hKBu9laIphqGmARAOo0alM1JCOHI5ZQkP1ROBzZDJeamAw8tMvwIZqhE3caaIKQP - 4KOtk0HeVwrJ4S5lMfiQDVLb/IZmPeNluH9jWb6GU7paOI0HlyLUhJ1QzUmlkRCBqgScLrdIXwgOMli1 - VdcVfGYcaKgbiV0MggoA0PQeG2LuauNzwCssPMTcyyy7EFOSDa4CgI0Pv1aTdYZrLRrLxCoEgzf2bcwF - IFRNtnYYC6TQ0KLtiHfXgqQu+3F8VmhqzbTQZlEtQNNhGU3RvgbElARUhSlKwintcvrhaoScDZi+rjkS - Xb0C4Do0vv+aV8eo9Mj7EJQWA9UZl9UGzXqAWJW8CmwINOPAgBQUJhng+IL1d/fyM43M3C4mc0nWJMSW - hORUDSi9abSsAOlR5akSYkpSmSNXemhLTDkIzuXA0uaPRjJLTLH/LhGiLNnmyNVKioplLdXqByBdjil5 - FYilBLiLhIgEFG1ATX9SLKHk2g1BpMsxJUQg1Xu/FhqzCYexbT7t3hIxHCqNOgJJz/fzFRqExx93tb7/ - SH1As67DtvG0U5JjcAg2EgCN5ppNu8kaYKlg87O9tA6wAuB8k07qsm26UENS+l5W3rgnoJYn1DV9E6SU - wtlFpEOC+H3P7B4vFPUQCWWg70lljQVAe148Tph5zTV/nSqDxWDi2DF4ZfuOpEOwbLOFapDad/9Sq67A - MThBiH98i4BLc5kQJcmg7z0KWwlAzEU1pB2w1pCK29Yn4DoTIEQyEui7I7CVALRpygAT3qSnDoPUVPzY - dN71nyYDUgx1CpIABaAZrQeD1GnKgAUBpx4WRZV3H7He2+dW1pqUQ7oJfvfckYvGMhX3dJjUMPXrXi1D - lJWDvlvBagLQpjxVqyiJ6LCwGw+sPjiT2zhx6QRshrgA+CrLZFIPKSNUg9m+1wSICgCUHt1pfHpn+25y - ERlC9CaMobdEKwEoK4iQ/EEoAqQIbT9ADOuwlQDYYqDSQyIBcxDIQrSrEouGpPQNkUQgDYdMWVooSRct - KyCG0x+0EoCiQgjNFlGx/AjEHxrrL6bDp7EA2DafdjgmBjOM+EW6MKjvBUDDNBaAoo0XwhMbU3824g+p - 5iCx+Z4aCYBt04UoyYylNRPxj28RiG3zg9oCUNYXMFQ2Fq8BxAbSjyEEbSJSrgVJfaSWAFQ5P0IVZMR0 - JyP+aVqUBOsSab6xnfrDOAsAvowLB0atKogveerj80E+RN/zsYke+cj78fuPhqQUhAtx2qM2wUzHih0n - AUDCDzz+Zd1/Qk6IoQCQpiBpDdOSQs3GDE2pAODUx2RUFyWkABDSPxYJgGms2cQECuUDkG5TTkisDP5y - dG0uAGiqCRO/jaczVF+2vpdkEhKKweTkZKty4GFQ+utjFntd6nQlIoQ8xqsAINQyundG9QP0vSsrISHx - KgAhQoExZmcRooVXAQCaAxq1h5MQEhveBUBzRDPDf4S0w7sAAI0GjW1mEhBCHiEiAECyMAimPwqSYizO - IEQTMQGAQxAi0LYd+EK4+Qnxx+CtwyOzUll0EAHkBviyBLj5CfHL4OCDJ2al+5v58Am4FCQRQuqR1wJo - NNdEdGD9npu1Q4QYvghPP1N9CfHPXDGQVlcdMyA0HxQ5fr+wdgCbHjXZSPChuU+IHHMCELKiztRk85Qn - RJc5AWBcnZD0mNcPgFV1hKTFPAFoUlePWQDos7Z83YNF4T6E7XCHx995+9xK3ucJ6RiNBQCbHuG9OnPY - cM2An4HVe4R0g9oCAM/9+P5rrQYwwsuPXoO0CAgJSy0B8NnwA9cDTBeiNUBIOJwFgLPWCIkPpyiAdKsv - TvYhJAyVeQAaE39jmrdOSJ+ozATUGvjJ5p6E6FNaC4B8/YmDV9Ue5vTbmxgZIESR0mpA7XHfGlWJhJDH - 5AJQdPprNvcchunIhOiRjwYr6qyLTL+x/dfVH4gRAUL0sPYE1OzvPwxbfROih1UAtO//BkYDCNHDKgDb - jl7y3tHXBdQJoPEnIUQeqwC8fuZskAeiABCiR+euABQAQvTonADMfLgmrxIkhMhjFQCN+X5FhGxOSkhq - WAVAOw3YoNWenBBSMRtw6uT5wr79UrAzMSG6lArA6L6ZbOTNW2oPQ/OfEF1KBQD1AFuPTatYAegJ8OnO - Cc7+I0SRyvHgWs5AtgYjRJ9KAQDSWYFM/yUkDE4CIHkVgOMPiT80/QnRx0kAAHoDIjnIpwhw8xMSFmcB - ABjtPfHeVS8ZgjD70f2Hm5+QcNQSAEOTsWCGh3eW5FOB2PSDkPA0EgADhAAvF4sAJz42PT39hHSHVgJg - wNUAPoKVY98t+nd3Lz+Td/qlqU9I9/AiAISQfkIBICRhFglAmTmPKj0MD2W1HiFxMCcAKP+FQ2/VlnuV - /xM8+SjagUOPd3tC+svgjX0bZ8f3X2sU0kMBz1fHn8vFgEJASP+YNx68KbAILhwY5Vw/QnqGFwEAsAaQ - 2ccEH0L6gzcBABAB5PbTEggL/DnL1z3IVow/StBCohasNDhv8cLvA6GmM5d4FQDAxh5hQMXmC7u+yR25 - rgVbaMEORy6zM9PFuwAA1vfrgroMbP6mlZqoypw+tIGWW4KICAD47J2Nec4AkQM5GyjR9tWshT0Z00NM - ADjhRxaJ/gzg61PP5s5ckgZiAgDY418GnPxo09Ykd8MFjmhPB1EBoEkpg8bYNl7h0kBUAOgM9A+8/GP7 - r4u/D8KGn+x6OfTHJcKICgAXkX9ePX5BzPRfCFu1x4+oAICPtk6G/ozRoHX6Gyjg8UMB6BFoyOpSremT - iwdeYnp3xFAAegI8/1Mfn1d/35kP12RXDo+E/vhECApAT0Be/yvvf67+vr4mNpu6BPaH7BaiAsBkIH9o - zWgsoq6Iw1rJu0X/sunxKkpWgrCgYSycjExBDoeoANB89EcfBAAFSev33Myen/q21t8PMTAdpoguogJw - +u1NVHdPdF0AfDwfLEakITN7VA8xAWAIyS9dFQCf4+IAG8voIiYAzCf3y8jOW9no3pkg720TAN/ViMMw - CUkHEQHA6Q/PMb29/ggVBShz5ErWJLC7lA4iAsDkERleP3NW/T1tjlyNKwkPEnm8CwA9/3KEyAQscuTC - 27/12LT3XgRF8Copi1cBYDMJWdDsc+LgVbX3szlyx969XjvU1xT2mJTFmwDw5NchdDUgHH/bT1xUOf0N - 7Cshx+BvZ1fMtjErcUp8ceRF3vmV0HIG2lKAtSsSy56FtCefDYhFhTBTHSHgfMBwaJjgtiSuEH4IcOq1 - zVxnAsybDgznDu6ZEAQMllhoaiIkdP/GsrxVFE/8cEjG30FZDF7zCjJMmxZlWNdPrf5x3sRrrGMzJCVl - Fo0HJ/1ASgSqEnBChCJB3WiAGZSyesvdUsGCkxGHGT5zij0QKQA9BiKA64APk9w1BbfrAoCNP7pvptF3 - kqI/iwIQAXDMITGnqWmO5q2I4LgU4XRZAHylS+P7gBim4HMYvHV4ZJaDIvsPrAH4b7AJXK8FyNuAI7fO - PbirAuDbMYrIAzpax74v5vIA4ODDF5ziPSg2YAbDkYvpQXDmGnCiYbPDAdbUzA0lAGXp5VJRkRRSkRcl - AuFUgDkY84cmzdEYSlKEbcqUdE1C7DkIhZmAUL4LB0aTD5GQxYQoS7alJGslRcVcj2BNBWY5JikC14vt - xy+qvqctzVzTGol1zmVpLUAKdyBSH+1rQNHm0+6PEGuhW2UxEOf7kYVobj7bxtNOSY61KtGpGpCTYslC - NDYgNt2Z3eOLTv9QQ1JibHTjJADs708WolEWbEtLDtUeLcZrgHM/AFoBZCHIM4A/QEIEyjZbqA7JMR6E - zgIQo/qR9kiIQNVa0+xItJDYRt05CwD7/BMbCA3CJ9C2MhF3foT7qtqBh0pGAskKAGjTlAEnBRbKcGoq - ZsM9vL0kyvhqiiBJCKPBmlgDOPWvH13rtBYoAP6oJQB1/QBw1qBSDUUqZYsC1gXEoG5hCukm5jevihLg - d799bmX21fHnah0CKPcdefOW+ueK0QoWEQBsfDhqmqg0HC2oyaYQxAHWAiw/vAxtLT86Af3hVQAQGoIJ - 6EOd2WWY2AgVBoyxJsCbAEi0qILiIgsxtuwr0p6pk+dVW5ODGKdd1xIAW0GEZJPK2Msx+wKcuGiqieaa - w45c9BaAOQ+zXnNzaIcCY7z/A2cBQIjm1I7Nhf9O2ivLHIQwQNjh2YdTz6XdGDYJQnhw5kpbbdpViTGa - /8BZAGxFQVr14THmYXcZONrQVbeJmY3DAp596Q2jZQXEWggEnAUg9JioWE2wrgFTf3z/NS/XOVzfpg9t - ELsaaA0pjfnwcRIAm/mvHY6p6llP2iGR1ivdWEZ6YGrs108nAbDdf7SnxNAhKIdkYY+0CEjNK0xhvVUK - QOh+bAuJtTVTSKRHjQHpzeRbBFJpjlspALbYZ6hsLF4D/KOVWivtScehBP9FG6sU1gpqElIZR14qAGWb - LVRBRtMMQdMr3/zT4KNXfp/RDqdpWHA4nFxDl8PUKUiKBasAVJ20oQSgbj42FgJers+KRZDSoEjtwhrN - eHpekPTLK09gKhADnPZm0jVesZv7RSwSANeZACFSMYGrALQ1B/E+8P7Gfhpo/45lCWXSDFt+WN8pbviF - zAmASd5wzeIKNSfeRQB8nWquDSr6SihHLtvLdYfBP75cOosFjlcdReziFQDebHSm8f1csVYmhnLkxppW - 20cajwfX7stuKFs8ks905chIdJ7hUCLeZNaEmX4MqwXFSAtDljgY4Mg1d3riRmMBCDEjDtjSMjVOs9hM - 1y5acQtBlAI9Jqq6Sg1T9zqbMo0FAJlj2z64pP7ARX0JtZ4ltlFpXReAtqKeWky/CY0FAGw7ekk0e2wh - NtNRcyHHdH/tqgD4zkzEukFEJxbh9kkrAZDKwbZRZIJrJ7KEDGP5posCIJWWjFRkvCdFYD6tBABohQNt - iyZEh9hYykNDdde1WVHSNQkxNvVsS2sB0Iol22oSQuQjxFIiKl1Ka8MmoBqRpZiucD5oLQBA+iSxpSVr - m/+GWJqThJiya7tCaSYlsaL0MV4EAEi1Zyo7bUNlsoEmE2IQrVi95W7+3PjzcFgLd1QsShPH1lqg2s01 - bb+npj8iFgvOB94EAPheTFXmWqhMNlAnJwDOUjxrnasKPNcIX0nnHWiLaNHpG0LIaQU8wqsAANwrIQRt - CkxgYqOXXNXi77oA+KhP1whhaWV12k7eENN+Y8zsbIJ3AQCmnXTdrrJ1M7i6LAA+n026pZZGc9eyzroh - HLmMCDxCRAAMJn/b5HAXLTAzGNTUZNchlBcblE1KljjRpEVA2gy3CWYoRy6IbdJvE0QFoIjhmuy299tQ - 6chlyUCSVklfm2uWNZcJ6ciNcdRXXdQFwDchGpPYUpI1FrN0RpsPH44BgoXvqUzotbNJh4mtuKsJ/wfb - mhgAeoKg9wAAAABJRU5ErkJggigAAAAwAAAAYAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8 - PDwAOkE+ADpEPwA5RUAAN01DADdORAA4SUEAOExDADVRRAA0VUYANFhHADNaSAA0WUgAMl1JAC9nTQAu - ak4ALWxPADFgSwAwY0wAMGRMAC1uUAAscVEAKnRSACp3VAApeVQAKH1WACeAVwAmg1gAJYVZACSIWgAk - i1wAIo1cACGSXgAhlF8AH5lhAB6cYgAdn2QAIJZgACCYYQAcomQAG6ZmABykZQAbqGcAGqpoABmtaQAX - smsAFrVsABixagAVuW4AFLxvABO/cAAUvnAADs52ABLAcQARx3MAEcd0ABDKdAAO0HcADdJ4AAzWeQAL - 2XoADNh6AAndfAAH5X8ACOJ+AAjkfwAH5oAABumBAATuggAD8oUABPCEAAL1hQAB+IcAAfqIAAD+iQBx - /50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAIkAAACrAAAAvPAAAO8AAAIP8SAD3/MQBb - /1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAwcAAAPZAAAEywAABZzwAAZ/AAAHj/EQCK - /zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABAUAAAWnAAAHSQAACOsAAAqc8AAMLwAADR - /xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAvJgAAUEEAAHBbAACQdAAAsI4AAM+pAADw - wwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAAAAAALxQAAFAiAABwMAAAkD4AALBNAADP - WwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD///8AAAAAAC8DAABQBAAAcAYAAJAJAACw - CgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/1NEA////AAAAAAAvAA4AUAAXAHAAIQCQ - ACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/scgA/9HfAP///wAAAAAALwAgAFAANgBw - AEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/kdwA/7HlAP/R8AD///8AAAAAACwALwBL - AFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2cf8A95H/APmx/wD70f8A////AAAAAAAb - AC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0Uf8AwnH/AM+R/wDcsf8A69H/AP///wAA - AAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBYMf8AcVH/AIxx/wCmkf8Av7H/ANrR/wD/ - //8AAAAAAiYwJgIHSkpKSkkzBz1KSkEMAAAAJkpKSkAHPUpKSko7AAAAAAAAAAAAAAAAAAAAOUpKSj0C - SUpKSkoqAAIUFAIAAAACSUpKSkohHkpKSkodAAAAAAAAAAAAAAAAAgAUSkpKSkoXKUpKSkkMAAAAAAAA - AAAMSkpKSkorAB05ORsAAAAAAAAAAAAAAAAARBQZSkpKSkobAB4zLAwAAAAAAAAAAAAAQ0pKSkoZAAAA - BSQxHgIAAAAAAAAAAAAASkIFRUpKSkkFAAAAAAAAAAAAAAAAAAAAD0FKSSoAAAADQEpKSjMAAAAAAAAA - AAAASkoFFUJKQxcAAAAAAAAAAAAAAAAAAAAAAAIRBRMPAQAeSkpKSkoMAAAAAAAAAAAASkYCAAAHAAAA - AAAAAAAAAAAAAAAAAAAAAAAHOUpKQg0mSkpKSkoOAAAAAAAAAAAASR4AAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAApSkpKSjgRSkpKSkMCAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAACKkE9GQA4SkpKSkUB - HERKPhMAAAAAAAAAAAAAOUlBFwAAAAAAAAAAAAAAAAAAAAAvSkpKSRcvSkpKSj0AAAEHAAAAAAAAAAAA - AAAASkpKSREAAAAAAAAAAAAAAAAAAAJFSkpKSjAKQ0pKRxUAAAAAAAAAAAAAAAAAAAAASkpKSiYAAAAA - AAAAAAAAAAAAAAdGSkpKSjAABx4gCQAAAAAAAAAAAAAAAAAAAAAASkpKSh4AAAAAAAAAAAAAAAAAAAAs - SUpKShUAAAAAAAAAAAAAAAAAAAAAAAAAAAAASkpKQwUAAAAAAAAAAAAAAAAAAAACJEE5FwAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAIzcsDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAXMzMXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlKSkpKGwAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADlKSkpKPQAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAj1KSkpKQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAHyNKSkpKKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAALwIqRUUsAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAEXIQ8A - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAATdKSkokAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAF0pKSkpKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAASjcFJkpKSkpKFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIaIREAAAAAAAAA - AAAASko1D0pKSkpJBwAAAAAAAgAAAAAAAAAAAAAAAAAAAAAABj1KSkkeAAAAAAAAAAAASkpKAClKSkke - AgAAAAAAAAAAAAACAAAAAAAAAAACAgAAIUpKSkpFAgAAAAAAAAAASkpDAAAMFQURBQAAAAACAAAAAgAA - AAAAAAAAAjBKSTACL0pKSkpKCQAAAAAAAAAASkohAAAAEUFKSS8CAAAAAAAAAAAAAAAAAAAAKkpKSkoo - HEpKSkpDAAAAAAAAAAAALhcAAAAAPUpKSkoeAAAAAAIAAAAAAh4zLAwAQUpKSko+ATFKSkYVAAAAAAAA - AAAACS09LgkHSkpKSkozAAAAAAAAAAAAL0pKSkYJOkpKSko5AAANFAMAAAAAAAAAAAAAPkpKSkEHRkpK - SkopAAIAAAwXBQIHSUpKSkojGEpKSkkXAAAAAAAAAAAAAAAAAAAASkpKSkoZHkpKSkMFAAAAKUpKSR4M - SkpKSkoqABAtLw8AAAAAAAAAAAAAAAAAAAAASkpKSkoaABQpIQcAAAATSkpKSkkMPUpKSkoUAAAAAAAA - AAAAAAAAAAAAAAAAAAAAQ0pKSkYHAAAAGz5DKwceSkpKSkoXDDlKQx4AAAAAAAAAAAAAAAAAAAAAAAAA - AAAAEThGORMAAAAXSkpKSjAUSkpKSkoMAAICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx - SkpKSkkCMEpKSSoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwSkpKSkUCABUhDgAC - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPSkpKSisCAAAAAAAAAQAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFTg9JgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAgAAAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA - AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA - AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA - AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA - AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA - AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA - AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCKAAAACAAAABA - AAAAAQAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADw9PQA6QT4AOkQ/ADlGQAA3TUMAN05EADhJQQA4 - TEMANVFFADRVRgAzWkgANFhIADJdSQAvZk0ALmlOADFhSgAwY0wAMGRMAC1tUAArc1IALHJRACp1UgAq - d1QAKXlUACh9VgAngFcAJoJYACWGWgAliVsAJItcACOOXAAkjFwAIZJeACGVXwAfmWEAHpxiAB2fZAAg - lmAAIJhhAByhZAAbp2cAHKVmABuoZwAaqWgAF7JrABezbAAXtWwAGLBqABa4bQAUvXAADs52ABLBcQAR - xXMAEch0AA7QdwAN0ngADNV5AAvaegAK3HwACeB9AAjlfwAH5oAABumBAAPyhQAE8YQAA/SFAAH4hwAB - +ogAAP6JAACwNgAAz0AAAPBKABH/WwAx/3EAUf+HAHH/nQCR/7IAsf/JANH/3wD///8AAAAAAAIvAAAE - UAAABnAAAAiQAAAKsAAAC88AAA7wAAAg/xIAPf8xAFv/UQB5/3EAmP+RALX/sQDU/9EA////AAAAAAAU - LwAAIlAAADBwAAA9kAAATLAAAFnPAABn8AAAeP8RAIr/MQCc/1EArv9xAMD/kQDS/7EA5P/RAP///wAA - AAAAJi8AAEBQAABacAAAdJAAAI6wAACpzwAAwvAAANH/EQDY/zEA3v9RAOP/cQDp/5EA7/+xAPb/0QD/ - //8AAAAAAC8mAABQQQAAcFsAAJB0AACwjgAAz6kAAPDDAAD/0hEA/9gxAP/dUQD/5HEA/+qRAP/wsQD/ - 9tEA////AAAAAAAvFAAAUCIAAHAwAACQPgAAsE0AAM9bAADwaQAA/3kRAP+KMQD/nVEA/69xAP/BkQD/ - 0rEA/+XRAP///wAAAAAALwMAAFAEAABwBgAAkAkAALAKAADPDAAA8A4AAP8gEgD/PjEA/1xRAP96cQD/ - l5EA/7axAP/U0QD///8AAAAAAC8ADgBQABcAcAAhAJAAKwCwADYAzwBAAPAASQD/EVoA/zFwAP9RhgD/ - cZwA/5GyAP+xyAD/0d8A////AAAAAAAvACAAUAA2AHAATACQAGIAsAB4AM8AjgDwAKQA/xGzAP8xvgD/ - UccA/3HRAP+R3AD/seUA/9HwAP///wAAAAAALAAvAEsAUABpAHAAhwCQAKUAsADEAM8A4QDwAPAR/wDy - Mf8A9FH/APZx/wD3kf8A+bH/APvR/wD///8AAAAAABsALwAtAFAAPwBwAFIAkABjALAAdgDPAIgA8ACZ - Ef8ApjH/ALRR/wDCcf8Az5H/ANyx/wDr0f8A////AAAAAAAIAC8ADgBQABUAcAAbAJAAIQCwACYAzwAs - APAAPhH/AFgx/wBxUf8AjHH/AKaR/wC/sf8A2tH/AP///wAAABg2KgdEQ0M2DzY4EgAANkRDHDpEQzkA - AAAAAAAAAAEIREREITZDQyYAAAAAAAdDREQ1ETg4EQAAAAAAAAAAOxJEREQpBx8WAAAAAAAAADpERCEA - AB81KQAAAAAAAABEGy1EOwUAAAAAAAAAAAAABx8YDAARQ0REGQAAAAAAAEQNAAIAAAAAAAAAAAAAAAAA - Cz5DORZDQ0MfAAAAAAAAGAAAAAAAAAAAAAAAAAAfKgsmQ0NDFjFDOAcAAAAAAAA+QBsAAAAAAAAAAAAA - JkRDQBlDQ0MLAAIAAAAAAAAAAEREPwAAAAAAAAAAAAAwQ0NDBRwuFAAAAAAAAAAAAAAAREQ+AAAAAAAA - AAAAABRDQzEAAAAAAAAAAAAAAAAAAAA0Ng4AAAAAAAAAAAAAAAcPAAAAAAAAAAAAAAAAAAAAAAAcOC4C - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACURERCYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS - REREKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsrQzkFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAADQAAIS0RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABACFEREEDAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAEMcLURERAsAAAAAAAAAAAAAAAAAAAACJi4LAAAAAAAAREENQUQ0AAAAAAAAAAAAAAAAAAIA - ACpERDwAAAAAAABEPAAHER8YAAAAAAAAAAAAAAAYQUEXNURERAIAAAAAADURAAA2REQjAAAAAAAABx8W - ADxERDsUQ0QvAAAAAAAAHjsxB0RERDYAAAAAAAA6REQhOERENgAHCwAAAAAAAABEREQjNUREHgAAJjsw - CERERDULMzELAAAAAAAAAAAAAERERCQCFhYUAw9EREQhNkRDGwAAAAAAAAAAAAAAAAAAJEA1BwAIQEQ+ - FERERCYCFxEAAAAAAAAAAAAAAAAAAAAAAAAAACFEREQZKUA1AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - DUREQwsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCcNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAGAAAADAAAAAB - AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPDw8ADpBPgA6RD8AOkRAADdPRAA4SkEAOExDADZRRAA1 - VUYAM1pIADJeSQAxYEsAMGRMAC1tUAArc1IALHFRACp1UgAqd1QAKXlUACh9VgAngFcAJoJYACWFWQAk - iVsAJItcACONXAAkjFwAIpFeACGUXwAfmmIAHp5jACCWYAAgmGEAHaFkABumZgAcpGUAGqpoABitaQAV - uW4AFL5wAA/NdgASwXEAEcVzABDJdAAO0HcADdN4AAzVeQAL2HoACdx8AAjhfQAI5H8AB+eAAAbqgQAE - 7oMABPCEAAH4hwAB+ogAAP6JAFH/yABx/9MAkf/cALH/5QDR//AA////AAAAAAAALw4AAFAYAABwIgAA - kCwAALA2AADPQAAA8EoAEf9bADH/cQBR/4cAcf+dAJH/sgCx/8kA0f/fAP///wAAAAAAAi8AAARQAAAG - cAAACJAAAAqwAAALzwAADvAAACD/EgA9/zEAW/9RAHn/cQCY/5EAtf+xANT/0QD///8AAAAAABQvAAAi - UAAAMHAAAD2QAABMsAAAWc8AAGfwAAB4/xEAiv8xAJz/UQCu/3EAwP+RANL/sQDk/9EA////AAAAAAAm - LwAAQFAAAFpwAAB0kAAAjrAAAKnPAADC8AAA0f8RANj/MQDe/1EA4/9xAOn/kQDv/7EA9v/RAP///wAA - AAAALyYAAFBBAABwWwAAkHQAALCOAADPqQAA8MMAAP/SEQD/2DEA/91RAP/kcQD/6pEA//CxAP/20QD/ - //8AAAAAAC8UAABQIgAAcDAAAJA+AACwTQAAz1sAAPBpAAD/eREA/4oxAP+dUQD/r3EA/8GRAP/SsQD/ - 5dEA////AAAAAAAvAwAAUAQAAHAGAACQCQAAsAoAAM8MAADwDgAA/yASAP8+MQD/XFEA/3pxAP+XkQD/ - trEA/9TRAP///wAAAAAALwAOAFAAFwBwACEAkAArALAANgDPAEAA8ABJAP8RWgD/MXAA/1GGAP9xnAD/ - kbIA/7HIAP/R3wD///8AAAAAAC8AIABQADYAcABMAJAAYgCwAHgAzwCOAPAApAD/EbMA/zG+AP9RxwD/ - cdEA/5HcAP+x5QD/0fAA////AAAAAAAsAC8ASwBQAGkAcACHAJAApQCwAMQAzwDhAPAA8BH/APIx/wD0 - Uf8A9nH/APeR/wD5sf8A+9H/AP///wAAAAAAGwAvAC0AUAA/AHAAUgCQAGMAsAB2AM8AiADwAJkR/wCm - Mf8AtFH/AMJx/wDPkf8A3LH/AOvR/wD///8AAAAAAAgALwAOAFAAFQBwABsAkAAhALAAJgDPACwA8AA+ - Ef8AWDH/AHFR/wCMcf8AppH/AL+x/wDa0f8A////AAAMLSQhOTkTISMDADI5JC45LQAAAAAAABEmOTkR - LCcDAAAAAzg5KAYYGAQAAAAAADgUOC0DAAAAAwAAABEkDQMkOTQDAwAAADAAAwAAAwAAAAAAAAAkOScn - OTgGAAAAAB0RAAAAAAAAAAAkNhoyOTYEHg8AAAAAADk5CQAAAAAAAwM4OS8PJxQAAAAAAAMAADk4CAAD - AAAAAAAjMxgDAAADAAAAAAAAABEZDQAAAAAAAAAAAAAAAAAAAAAAAwAAAA85OREAAAADAAAAAAMAAAAA - AAAAAAAAABs5ORQAAAEAAAAAAwAAAAAAAAMAAAAAAA8WIAsAAAAAAAAAAAAAAAMAAAAAAwAAAAEGNjka - AAAAAAAAAAADAAAAAAAAAAAAADYWOTklAAAAAAAAAAAAAAADIycEAAAAADkgGiUKAAAAAAAAAAABGhoO - OTkhAAAAACgHACo5HgAAAAAADwsUOTkbNjgRAwAAACYxDjg5LwAABwMaOTgbOTkPAwYAAAAAADk5Jxoo - DwAbOTEhOTkMDAwAAAAAAAAAACo1EQAZNiQnOTkJHBMBAAMAAAMAAAMAAAAAAAAwOTgLJxwAAAAAAAAA - AAAAAAAAAAAAAAAWNCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQABAAEAAQAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAQAAAAIAAAAAEACAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8PT0AOkE+ADlGQAA3TUMAOElBADhMQwA1U0UANVVGADNbSQAy - XUkALmtPAC5sTwAxYUsAMGJMAC1vUAArc1IAK3RTACh8VgAngFcAJ4FYACaEWQAkiVsAH5piACGVYAAg - mGEAHKJlABunZwAaqWgAGa1pABa1bAAYsGoAFbtvABS8bwAPzXYAEsJyABHEcgAQynUADtF4AAzVeQAL - 2nsACt18AAjifgAI5X8ABuuCAATvgwAD84UABPCEAAL2hgAB+YgAAP6JAABQNwAAcEwAAJBjAACweQAA - z48AAPCmABH/tAAx/74AUf/IAHH/0wCR/9wAsf/lANH/8AD///8AAAAAAAAvDgAAUBgAAHAiAACQLAAA - sDYAAM9AAADwSgAR/1sAMf9xAFH/hwBx/50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAI - kAAACrAAAAvPAAAO8AAAIP8SAD3/MQBb/1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAw - cAAAPZAAAEywAABZzwAAZ/AAAHj/EQCK/zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABA - UAAAWnAAAHSQAACOsAAAqc8AAMLwAADR/xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAv - JgAAUEEAAHBbAACQdAAAsI4AAM+pAADwwwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAA - AAAALxQAAFAiAABwMAAAkD4AALBNAADPWwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD/ - //8AAAAAAC8DAABQBAAAcAYAAJAJAACwCgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/ - 1NEA////AAAAAAAvAA4AUAAXAHAAIQCQACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/ - scgA/9HfAP///wAAAAAALwAgAFAANgBwAEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/ - kdwA/7HlAP/R8AD///8AAAAAACwALwBLAFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2 - cf8A95H/APmx/wD70f8A////AAAAAAAbAC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0 - Uf8AwnH/AM+R/wDcsf8A69H/AP///wAAAAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBY - Mf8AcVH/AIxx/wCmkf8Av7H/ANrR/wD///8AAiUZLScLDgAtJSQiAAAAAB0rHQcFAAAAHBgFJhgAAAAV - AAAAAAAACwwwHiscAAAALxEAAAAAEDEcJRMAAAAAACoQAAAAAAUbCAAAAAAAAAAUKQcAAAAAAAAAAAAA - AAAAGi0IAAAAAAAAAAAAAAAAAAQWIgAAAAAAAAAAAAAAAAAoIi4CAAAAAAAAABkfAAAAIwAeFwAAAAcF - JiUhKwEAACcaLiYAEQwvJh8fAAEAAAApHgYdEjEkGRUAAAAAAAAAAAAJMR0UDAAAAAAAAAAAAAAAAA0C - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= - - - - - iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAwBQTFRFgICA//// - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODgHVgAAAAlwSFlzAAAOvgAA - Dr4B6kKxwAAAABZJREFUGFdjYAABRhAAs4hlkq4DZDgACywAM12jTsYAAAAASUVORK5CYII= - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAnBJREFUOE+dk11I - k1Ecxs+2q1DLqwRvvCgoM6mLvoTAC6WLSrDUYBcSGK6y6EMzc6a2NnERlVKhSEMTYWSyksTZh7KZGboU - HNmUKemcupnuI5tuqHs6/7cSUenrwMPhPf/n97wPB46IrVrHCwuTxCJR5EbxbHiUZHQnEzE2uhj18Wsw - zPPLGgQmdErli9Ws8C2VX8wFX9y0rmiWnJ9/dg38Qc02dZdKUlQ3DrcuBINIfQTItMDJWiBHByj1gMEK - 0OxY9rkrywEvb7OQdzclR6tKDjRUV522qh7Kl5q6unDqQTnuNbZD89qEyhYTNK9M0PcMwLewgOsFh5oH - 70oSbXfYBmZUiM8P1Se06Z4WBP5UvarFALffj+q6goDjTXJTf7k4nWVmp159ayhDnVYu1Ot7tvmnImB+ - ztX4Y6dZUYMRzrk5VD4uxPueWmTlpVxmCVlZF1wuG8pqVJj0eKA+s5cHRMNm2Iapvn3wjCRirGOHUF2j - 12PY7Ubx/SJ4vJMglsXLZJcWefrI+Ge09PZCGr8V105sQU3xdgx0HYHfJ4O5ebdQXVNXjLb2Csy4x0EM - sexgRka2f2kJvkAAEzz9VmkCatWR0JaEoqkiDJ26cDxRh2LQ6YSyQgGna0zwEkMs25+envON13P7fII+ - 2e3QGo1rVN/RAZPFvOwjhli2RyrNdfNEh9eL0elpdFutsPMmLl55peiMZuQhLzHEsl1paXlf5udhdTjQ - abEIu21mZl2t9BBDLItOSpKP8HSj2Yx+Xn9oauq3Ig95iSGWRcTFKVr57Q/zv9pnZ/9K5CWGWBYaG5sZ - EhNT+j8idt0X+S+H3wE2DYYIXysH6QAAAABJRU5ErkJggg== - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAm1JREFUOE+Nkl9I - U1Ecx39T31o9SBq97cWHiUIimKiQ0zFbbcJ1U2YkBtLuFYkQnMrcdKQyEUIwWk+GDy58EfUhmYoTRtKE - HitI8kGZIkEW/oF0um/nd3OyYUnn8rn3nMPn+733wNXYe3spOTQajVXMb55vpE/CiUTiqyB91+b1Ugry - j3gcWwcH2Nzfx8benspsJALhyII8qaeHUiHJ7U5F+Xl0hM3dXXzZ2cGn7W183NpCcG4OPISrmNvbdQZF - IaZOlolsNhvVOZ1U29XFtO4fH+ObeGtqyYuJCSTJM5s9Aqqqr1ez6s1ut5OtqYksHR1tB6Lg++HhhRL+ - Ej4OO+yqmbOCDLGwCuSsrKznLpcLl8EOu5wRBRkkSdJ1t9vdtyPOrCgK+vv74fV6L+DxeODz+VQnFouh - u7u7j7NksVj0o6Oj42tra3A4HOjs7ITT6URzczMkqQ7V1UaUl1egpOQ2zOZ7qjM/v4yBgcFxzlJNTU3l - 1NTU8urqKoxGowjLMJnMqKioFME7aRiNd1VndnYRIyOBZc6SwWBwRKPR9XA4jKKiIjQ0PBSS9a+YTLWq - 4xTX5OTbdc5SWVnZk1AohGAwCJ1OB7v9EazWB/+EnbGxMUxPT4OzVFxc7IpE3mFmJoS2tqcYHg5gaOgl - /P5ACq/E/A+tre1YXPygwlnS6/XupaUVLCysoLGx8b9IFnCWcnJyWrKzsweZzMzMIf5l7weA1++BN9HP - MPhacEv2o8o1iV8nJ2An6XOWxIK0Wi1dy82lG6Wlz9SfPmWcJhJg4qeniIsnO+xyhrPnBVcLC0lbUPD4 - Sn6+/zLYUd2zgt/AGvcWHCMAZwAAAABJRU5ErkJggg== - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAW1JREFUOE+NkL1L - QlEYh9/b4NzS1BgNShBRQQ3VGEGr/0BDBEG0uLRIFIREIX2ANhgZKphj/4PLASOi0i4SYWWmWH5y/bhv - 5yc4HTl04YHD+z4893AMGvB53S7Hg+1cNQxjBGtm/p4YerrdvXlsDfJ7s7MlCp4ukgD7U3QX8mx+ZDIm - A5wx6+/hKiEs0+drnNiY5WTynlOpZ85mcz1wxgw7OHCVwPECCXlVDoev2ec75EDggiORGMfjCQ5dXrHf - f8LRaAwKw1UCR/MkbLns2Da/mOZAsIMDVwn45ki0pWB1OlrgwFUCBzMkrG6X662WFjhwlcDeNIlGu82/ - zaYWOHCVgHeSRFX+vVSraYEDVwnsuEj8WBbnKxUtcOAqAY+TREleP1cua4EDVwlsj5MoNBr8WixqgQNX - CWyNkfis19ksFLTAgasE1kdJvMsHTOfzWuDAVQLuYRJf8oHeqlUtcOAqgRUHBZcdJP4D3H7gDzdsNup2 - mXizAAAAAElFTkSuQmCC - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAXJJREFUOE+lk0FL - AkEYhlvwv3jzoiDoQdCbdEnYf6CrqCgoHgRRAk/9EQVLdEGyFiQNMS+dvHnoEkgglGAmCL7NO6RMIZvU - wsMO3zzzzGk0ACf/+hjQNO1ccKlXKsYx0OUZeflXoFmtVsUS2P4CHboi0FQDrXK5jM12i/VmYwsduiLQ - UgNmqVTCuzj8tlrZQoeuCJhqoFMsFvG6XmO2WNhCh64IdNRAt1Ao4EXc/jSf20KHrgh01YCVy+Uwnkzw - vFzaQoeuCFhqoJfJZBCLxY6Crgj01EA/lUrB4/HA7XYfhHs78vk8A301MIzH4/B6vRiNHjAY3H+DM+7p - ug6fz4dsNsvAUA2Mo9Eo/H4/LOsOTqdTYprXEs64x0AwGEQ6nWZgrAYeDcNAIBBAu30r/6Reb0t2MwbC - 4TCSySQDj/uAeEyngqnL5fpoNG4QCoUktVpHspsxEIlEkEgk+AKnaoAP8kwwczgcF4fg3g+u9gEu/son - bfJW/NwRDyIAAAAASUVORK5CYII= - - - - - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAUNJREFUOE+lk79L - QlEcxW9/gqCrm6vg4uYoOAgOrqLk4ioP0r2Glhp0SSjoF1FE0BIUDU3RdIOGoKBVGlpapaHTObeuCPe6 - 9ITD5fs9n3Pue8JbAWBS/VSQRvPwKR/j3JgaZXVqPv5TzPOXLhYoZDEcQidVWyhw3qzfn3tBAWH7PRjg - uV7HV5JAM6USyX50u86btlrOCwoOCR7Q+Oz1cFcu473dhmbppdFwu8dq1e3EBgU0zB6NXQJvzSaui0U8 - VCq4LZWwn8vhLJ+HPDFiowUEzITADsGrQgFHmYzTSTYL7eSJiRZs0timRoTGhC956wXDXtrJEyM2eAIt - t34Be8NgTPLELCuQYe8Z9tK8ZBf+ieuEnxj20rzB26SYF7zCGsGEoVeW6NTMoJFiXlDAkFllqMOwTs2+ - IOYFBf/9oFJ9ibr0B4f94vVG3bWDAAAAAElFTkSuQmCC - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAUAAAAAAAEACAClFwAAVgAAADAwAAABAAgAqA4AAPsXAAAgIAAAAQAIAKgIAACjJgAAGBgAAAEA + CADIBgAASy8AABAQAAABAAgAaAUAABM2AACJUE5HDQoaCgAAAA1JSERSAAABAAAAAQAIBgAAAFxyqGYA + ABdsSURBVHja7Z1fqFVVHsf3YQqnUTJQSJMcujkK3UHuFW5geBXGYK5B0EP6Gto8zIsG8zKY82rCvKXP + 6bv2FqQP9eAfEhS8Eilozo0xTAOFbGycKLjTd9u6nnvvXnuvvff6/dbea30/cEioPPucs9Z3/dbv72By + cnI2I4QkyYACQEi6UAAISRgKACEJQwEgJGEoAIQkDAWAkIShABCSMBQAQhKGAkBIwlAACEkYCgAhCUMB + ICRhKACEJAwFgJCEoQAQkjAUAEIShgJASMJQAAhJGAoAIQlDASAkYSgAhCQMBYCQhKEAEJIwFABCEoYC + QEjCUAAISRgKACEJQwEgJGEoAIQkDAWAkIShABCSMBQAQhKGAkBIwlAACEkYCgAhCUMBICRhKACEJAwF + gJCEoQAQkjAUAEIShgJASMJQAAhJmOgF4MllP2dP/+GH/M8rx77L7t9Ylv304Ins4e0l2X/v/Db04xES + lCgF4Her/pc9v+PbbNXkvezpdT9Y/7uHd5Zkt8+tzL4++Wz2/ZdLQz82IepEJQDY+Ov33Myen/q29v97 + 7/Ly7Nqx32f3ppeH/hiEqBGNAIzsvJVv/ieX/tzq75n5cE12/eja/JpASOxEIQBj715vdOrb+P7G0uyz + fRspAiR6ei8Avje/gSJAUqDXArBh97+z9btviv398AtABAiJld4KwIrx+9kr738u/j5XjoxkMyfWhP64 + hIjQWwF45fDn2Yqx++Lv89MPT2Sf7pzgVYBESS8FQOv0N1w/tjYPERISG70UgIn3rmarttxTez9YAad2 + bA79sQnxTu8EAKm9Ux+fV3/fiwdeyu6cXRH64xPild4JANJ7Jw5eVX9fJAhdOTwS+uMT4pXeCYB06M9G + m5AgfBYoRDJ/BihK+vk/v8nuXn6G6cckGL0TAO37vwGFQ5/setn5v0cFItKTYbFUpSfDx4DrBYqSKAZE + k94JgFb4r4iPtk5W/jcoSBrdN9NYpGBpfHHkRVYnEhUoADWoEgCUIGPzty1IAkxAIhr0TgBCXQFQG3B6 + zybrv8fGH3nzltf3/PrUs9nl99arf1aSDr0TgC46ASWfiSJAJOmdAIQKA9qyATWyEi8fWp87CAnxTe8E + IFQi0Om3Ny1yzOFZth29lD216kfR92Y9ApHCSQDg2cZJh38ivIWFj4aaprEmQleaDTalegDYsIUANa8j + vAoQCawCgE0OrzZi2S4nHJxk8Fojni19UnWhGAjfz/YTF714/F35dNcEOxkTrxQKAE62F3Z902hxw1xF + Tz3pEFbocmCI49j+6+LvPwxDg8Q38wQAJj7CbGWttF2B1/ziuy+JWQN41q3HpsVPYFsRUIhwZFUokpC6 + zAkA7vY4VX1uKNydLxwYFctqkz6Fy+7dUyfPq5r/hlOvbaYzkHgjFwCJzW+ACODUklq0kk1BbactrI/t + xy+KfJ4qPntnY+16ATxvPiTll985d+gOXZ1gqRlHrrYzl4Rn8Kcdm2ex+X2Y/Takm2v6zsK7c25FfvLb + REvbCTlMHQHAc+YFSTWuKvjs8DOwKCkNBn89sWbWdwprEdIOLJxwsAbaWDGuDsyQAuDyPeKUx3fRxkkK + 0YYI0iKIm8E/ZzOVRCCNZBaE5nDiNYlg4L6Pze+y4LtsAfgQQgN+M4gAOyHFi5oAAK3mmhACbAS8sFlt + mwGnHBY3XnVOOtylt31wSetrm0eZAEg5RZmKHC+qAlC3qYYvYBI/tfpxMhOskLaRidfPnFX/HMCWDCRd + I9HE+Ui6j6oAgKKc+j6CGgBJx2kRNgHVyEpkPUKcqAtALNls8DWM7p1RfU9bY1KtpCTWI8SHugA0XUTm + Pr983YNHBUm/nnaI1+NUgnl6+9xKNesiRC5AkfWk7ZCMxYIjj1AXgDo5Adhk8OjDueVq3sJMhoUBp5W0 + uapZlWj73rQrI2kFxEVnBaBNQRKAEKC5pmQIS9MKKHLCheqNwHTkeOicAGBR407rq9JP+sTS6Algu/uH + 6o7EKUnxoC4ASDVFlWAR2PwSacnSIiBZmgwfBwSz6MQN1R/RRz6HaSwDTGMZoo+6ANgWj9TmN0iKgNSz + l21+EKpFepPaDmx4+HIwIcn2PeHvxTUH/hsKgg7qAmBLKNEIZUmGICECcMj5+gwu/RT6IACIUvxx779q + iyPeAwcFk49kURUA25htrVCWRjIL8gPW77nZ2HmJZ/zq+HNOJnaXBcCXLweWG/wfdDrKoCoANjNccyFr + hLGaFCVh48P0xeZ3NX+7KgC++0vgKjR9aAPzDwRQFYCiPPYQlXWaYSxbAhMwzThMQVJdQglAmSNXqrkM + BBKiQxHwy+Dv08tnNRaR7eTVTmQBsVS3dS0KIN2nscopSuoz+PPOiVnp5ppld+8QvfXKTrA+Eaovgc2R + q2GRxPLbdYW8J6B0c03bgglVV29zRvYRbQG1fXeabdJZmuyPua7AIZpJhOysE0s6q8RU4jJsWYmvHr8g + PiLNIN1jMiXmzQXwOd/epZ1UqDssiOUU0a5KLHLkhkhJZlWiHxZNBoJZjsQNjYaSFAA/aH2PNudfiCEp + NkuE1MM6GxDWAF51hKBu9laIphqGmARAOo0alM1JCOHI5ZQkP1ROBzZDJeamAw8tMvwIZqhE3caaIKQP + 4KOtk0HeVwrJ4S5lMfiQDVLb/IZmPeNluH9jWb6GU7paOI0HlyLUhJ1QzUmlkRCBqgScLrdIXwgOMli1 + VdcVfGYcaKgbiV0MggoA0PQeG2LuauNzwCssPMTcyyy7EFOSDa4CgI0Pv1aTdYZrLRrLxCoEgzf2bcwF + IFRNtnYYC6TQ0KLtiHfXgqQu+3F8VmhqzbTQZlEtQNNhGU3RvgbElARUhSlKwintcvrhaoScDZi+rjkS + Xb0C4Do0vv+aV8eo9Mj7EJQWA9UZl9UGzXqAWJW8CmwINOPAgBQUJhng+IL1d/fyM43M3C4mc0nWJMSW + hORUDSi9abSsAOlR5akSYkpSmSNXemhLTDkIzuXA0uaPRjJLTLH/LhGiLNnmyNVKioplLdXqByBdjil5 + FYilBLiLhIgEFG1ATX9SLKHk2g1BpMsxJUQg1Xu/FhqzCYexbT7t3hIxHCqNOgJJz/fzFRqExx93tb7/ + SH1As67DtvG0U5JjcAg2EgCN5ppNu8kaYKlg87O9tA6wAuB8k07qsm26UENS+l5W3rgnoJYn1DV9E6SU + wtlFpEOC+H3P7B4vFPUQCWWg70lljQVAe148Tph5zTV/nSqDxWDi2DF4ZfuOpEOwbLOFapDad/9Sq67A + MThBiH98i4BLc5kQJcmg7z0KWwlAzEU1pB2w1pCK29Yn4DoTIEQyEui7I7CVALRpygAT3qSnDoPUVPzY + dN71nyYDUgx1CpIABaAZrQeD1GnKgAUBpx4WRZV3H7He2+dW1pqUQ7oJfvfckYvGMhX3dJjUMPXrXi1D + lJWDvlvBagLQpjxVqyiJ6LCwGw+sPjiT2zhx6QRshrgA+CrLZFIPKSNUg9m+1wSICgCUHt1pfHpn+25y + ERlC9CaMobdEKwEoK4iQ/EEoAqQIbT9ADOuwlQDYYqDSQyIBcxDIQrSrEouGpPQNkUQgDYdMWVooSRct + KyCG0x+0EoCiQgjNFlGx/AjEHxrrL6bDp7EA2DafdjgmBjOM+EW6MKjvBUDDNBaAoo0XwhMbU3824g+p + 5iCx+Z4aCYBt04UoyYylNRPxj28RiG3zg9oCUNYXMFQ2Fq8BxAbSjyEEbSJSrgVJfaSWAFQ5P0IVZMR0 + JyP+aVqUBOsSab6xnfrDOAsAvowLB0atKogveerj80E+RN/zsYke+cj78fuPhqQUhAtx2qM2wUzHih0n + AUDCDzz+Zd1/Qk6IoQCQpiBpDdOSQs3GDE2pAODUx2RUFyWkABDSPxYJgGms2cQECuUDkG5TTkisDP5y + dG0uAGiqCRO/jaczVF+2vpdkEhKKweTkZKty4GFQ+utjFntd6nQlIoQ8xqsAINQyundG9QP0vSsrISHx + KgAhQoExZmcRooVXAQCaAxq1h5MQEhveBUBzRDPDf4S0w7sAAI0GjW1mEhBCHiEiAECyMAimPwqSYizO + IEQTMQGAQxAi0LYd+EK4+Qnxx+CtwyOzUll0EAHkBviyBLj5CfHL4OCDJ2al+5v58Am4FCQRQuqR1wJo + NNdEdGD9npu1Q4QYvghPP1N9CfHPXDGQVlcdMyA0HxQ5fr+wdgCbHjXZSPChuU+IHHMCELKiztRk85Qn + RJc5AWBcnZD0mNcPgFV1hKTFPAFoUlePWQDos7Z83YNF4T6E7XCHx995+9xK3ucJ6RiNBQCbHuG9OnPY + cM2An4HVe4R0g9oCAM/9+P5rrQYwwsuPXoO0CAgJSy0B8NnwA9cDTBeiNUBIOJwFgLPWCIkPpyiAdKsv + TvYhJAyVeQAaE39jmrdOSJ+ozATUGvjJ5p6E6FNaC4B8/YmDV9Ue5vTbmxgZIESR0mpA7XHfGlWJhJDH + 5AJQdPprNvcchunIhOiRjwYr6qyLTL+x/dfVH4gRAUL0sPYE1OzvPwxbfROih1UAtO//BkYDCNHDKgDb + jl7y3tHXBdQJoPEnIUQeqwC8fuZskAeiABCiR+euABQAQvTonADMfLgmrxIkhMhjFQCN+X5FhGxOSkhq + WAVAOw3YoNWenBBSMRtw6uT5wr79UrAzMSG6lArA6L6ZbOTNW2oPQ/OfEF1KBQD1AFuPTatYAegJ8OnO + Cc7+I0SRyvHgWs5AtgYjRJ9KAQDSWYFM/yUkDE4CIHkVgOMPiT80/QnRx0kAAHoDIjnIpwhw8xMSFmcB + ABjtPfHeVS8ZgjD70f2Hm5+QcNQSAEOTsWCGh3eW5FOB2PSDkPA0EgADhAAvF4sAJz42PT39hHSHVgJg + wNUAPoKVY98t+nd3Lz+Td/qlqU9I9/AiAISQfkIBICRhFglAmTmPKj0MD2W1HiFxMCcAKP+FQ2/VlnuV + /xM8+SjagUOPd3tC+svgjX0bZ8f3X2sU0kMBz1fHn8vFgEJASP+YNx68KbAILhwY5Vw/QnqGFwEAsAaQ + 2ccEH0L6gzcBABAB5PbTEggL/DnL1z3IVow/StBCohasNDhv8cLvA6GmM5d4FQDAxh5hQMXmC7u+yR25 + rgVbaMEORy6zM9PFuwAA1vfrgroMbP6mlZqoypw+tIGWW4KICAD47J2Nec4AkQM5GyjR9tWshT0Z00NM + ADjhRxaJ/gzg61PP5s5ckgZiAgDY418GnPxo09Ykd8MFjmhPB1EBoEkpg8bYNl7h0kBUAOgM9A+8/GP7 + r4u/D8KGn+x6OfTHJcKICgAXkX9ePX5BzPRfCFu1x4+oAICPtk6G/ozRoHX6Gyjg8UMB6BFoyOpSremT + iwdeYnp3xFAAegI8/1Mfn1d/35kP12RXDo+E/vhECApAT0Be/yvvf67+vr4mNpu6BPaH7BaiAsBkIH9o + zWgsoq6Iw1rJu0X/sunxKkpWgrCgYSycjExBDoeoANB89EcfBAAFSev33Myen/q21t8PMTAdpoguogJw + +u1NVHdPdF0AfDwfLEakITN7VA8xAWAIyS9dFQCf4+IAG8voIiYAzCf3y8jOW9no3pkg720TAN/ViMMw + CUkHEQHA6Q/PMb29/ggVBShz5ErWJLC7lA4iAsDkERleP3NW/T1tjlyNKwkPEnm8CwA9/3KEyAQscuTC + 27/12LT3XgRF8Copi1cBYDMJWdDsc+LgVbX3szlyx969XjvU1xT2mJTFmwDw5NchdDUgHH/bT1xUOf0N + 7Cshx+BvZ1fMtjErcUp8ceRF3vmV0HIG2lKAtSsSy56FtCefDYhFhTBTHSHgfMBwaJjgtiSuEH4IcOq1 + zVxnAsybDgznDu6ZEAQMllhoaiIkdP/GsrxVFE/8cEjG30FZDF7zCjJMmxZlWNdPrf5x3sRrrGMzJCVl + Fo0HJ/1ASgSqEnBChCJB3WiAGZSyesvdUsGCkxGHGT5zij0QKQA9BiKA64APk9w1BbfrAoCNP7pvptF3 + kqI/iwIQAXDMITGnqWmO5q2I4LgU4XRZAHylS+P7gBim4HMYvHV4ZJaDIvsPrAH4b7AJXK8FyNuAI7fO + PbirAuDbMYrIAzpax74v5vIA4ODDF5ziPSg2YAbDkYvpQXDmGnCiYbPDAdbUzA0lAGXp5VJRkRRSkRcl + AuFUgDkY84cmzdEYSlKEbcqUdE1C7DkIhZmAUL4LB0aTD5GQxYQoS7alJGslRcVcj2BNBWY5JikC14vt + xy+qvqctzVzTGol1zmVpLUAKdyBSH+1rQNHm0+6PEGuhW2UxEOf7kYVobj7bxtNOSY61KtGpGpCTYslC + NDYgNt2Z3eOLTv9QQ1JibHTjJADs708WolEWbEtLDtUeLcZrgHM/AFoBZCHIM4A/QEIEyjZbqA7JMR6E + zgIQo/qR9kiIQNVa0+xItJDYRt05CwD7/BMbCA3CJ9C2MhF3foT7qtqBh0pGAskKAGjTlAEnBRbKcGoq + ZsM9vL0kyvhqiiBJCKPBmlgDOPWvH13rtBYoAP6oJQB1/QBw1qBSDUUqZYsC1gXEoG5hCukm5jevihLg + d799bmX21fHnah0CKPcdefOW+ueK0QoWEQBsfDhqmqg0HC2oyaYQxAHWAiw/vAxtLT86Af3hVQAQGoIJ + 6EOd2WWY2AgVBoyxJsCbAEi0qILiIgsxtuwr0p6pk+dVW5ODGKdd1xIAW0GEZJPK2Msx+wKcuGiqieaa + w45c9BaAOQ+zXnNzaIcCY7z/A2cBQIjm1I7Nhf9O2ivLHIQwQNjh2YdTz6XdGDYJQnhw5kpbbdpViTGa + /8BZAGxFQVr14THmYXcZONrQVbeJmY3DAp596Q2jZQXEWggEnAUg9JioWE2wrgFTf3z/NS/XOVzfpg9t + ELsaaA0pjfnwcRIAm/mvHY6p6llP2iGR1ivdWEZ6YGrs108nAbDdf7SnxNAhKIdkYY+0CEjNK0xhvVUK + QOh+bAuJtTVTSKRHjQHpzeRbBFJpjlspALbYZ6hsLF4D/KOVWivtScehBP9FG6sU1gpqElIZR14qAGWb + LVRBRtMMQdMr3/zT4KNXfp/RDqdpWHA4nFxDl8PUKUiKBasAVJ20oQSgbj42FgJers+KRZDSoEjtwhrN + eHpekPTLK09gKhADnPZm0jVesZv7RSwSANeZACFSMYGrALQ1B/E+8P7Gfhpo/45lCWXSDFt+WN8pbviF + zAmASd5wzeIKNSfeRQB8nWquDSr6SihHLtvLdYfBP75cOosFjlcdReziFQDebHSm8f1csVYmhnLkxppW + 20cajwfX7stuKFs8ks905chIdJ7hUCLeZNaEmX4MqwXFSAtDljgY4Mg1d3riRmMBCDEjDtjSMjVOs9hM + 1y5acQtBlAI9Jqq6Sg1T9zqbMo0FAJlj2z64pP7ARX0JtZ4ltlFpXReAtqKeWky/CY0FAGw7ekk0e2wh + NtNRcyHHdH/tqgD4zkzEukFEJxbh9kkrAZDKwbZRZIJrJ7KEDGP5posCIJWWjFRkvCdFYD6tBABohQNt + iyZEh9hYykNDdde1WVHSNQkxNvVsS2sB0Iol22oSQuQjxFIiKl1Ka8MmoBqRpZiucD5oLQBA+iSxpSVr + m/+GWJqThJiya7tCaSYlsaL0MV4EAEi1Zyo7bUNlsoEmE2IQrVi95W7+3PjzcFgLd1QsShPH1lqg2s01 + bb+npj8iFgvOB94EAPheTFXmWqhMNlAnJwDOUjxrnasKPNcIX0nnHWiLaNHpG0LIaQU8wqsAANwrIQRt + CkxgYqOXXNXi77oA+KhP1whhaWV12k7eENN+Y8zsbIJ3AQCmnXTdrrJ1M7i6LAA+n026pZZGc9eyzroh + HLmMCDxCRAAMJn/b5HAXLTAzGNTUZNchlBcblE1KljjRpEVA2gy3CWYoRy6IbdJvE0QFoIjhmuy299tQ + 6chlyUCSVklfm2uWNZcJ6ciNcdRXXdQFwDchGpPYUpI1FrN0RpsPH44BgoXvqUzotbNJh4mtuKsJ/wfb + mhgAeoKg9wAAAABJRU5ErkJggigAAAAwAAAAYAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8 + PDwAOkE+ADpEPwA5RUAAN01DADdORAA4SUEAOExDADVRRAA0VUYANFhHADNaSAA0WUgAMl1JAC9nTQAu + ak4ALWxPADFgSwAwY0wAMGRMAC1uUAAscVEAKnRSACp3VAApeVQAKH1WACeAVwAmg1gAJYVZACSIWgAk + i1wAIo1cACGSXgAhlF8AH5lhAB6cYgAdn2QAIJZgACCYYQAcomQAG6ZmABykZQAbqGcAGqpoABmtaQAX + smsAFrVsABixagAVuW4AFLxvABO/cAAUvnAADs52ABLAcQARx3MAEcd0ABDKdAAO0HcADdJ4AAzWeQAL + 2XoADNh6AAndfAAH5X8ACOJ+AAjkfwAH5oAABumBAATuggAD8oUABPCEAAL1hQAB+IcAAfqIAAD+iQBx + /50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAIkAAACrAAAAvPAAAO8AAAIP8SAD3/MQBb + /1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAwcAAAPZAAAEywAABZzwAAZ/AAAHj/EQCK + /zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABAUAAAWnAAAHSQAACOsAAAqc8AAMLwAADR + /xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAvJgAAUEEAAHBbAACQdAAAsI4AAM+pAADw + wwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAAAAAALxQAAFAiAABwMAAAkD4AALBNAADP + WwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD///8AAAAAAC8DAABQBAAAcAYAAJAJAACw + CgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/1NEA////AAAAAAAvAA4AUAAXAHAAIQCQ + ACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/scgA/9HfAP///wAAAAAALwAgAFAANgBw + AEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/kdwA/7HlAP/R8AD///8AAAAAACwALwBL + AFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2cf8A95H/APmx/wD70f8A////AAAAAAAb + AC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0Uf8AwnH/AM+R/wDcsf8A69H/AP///wAA + AAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBYMf8AcVH/AIxx/wCmkf8Av7H/ANrR/wD/ + //8AAAAAAiYwJgIHSkpKSkkzBz1KSkEMAAAAJkpKSkAHPUpKSko7AAAAAAAAAAAAAAAAAAAAOUpKSj0C + SUpKSkoqAAIUFAIAAAACSUpKSkohHkpKSkodAAAAAAAAAAAAAAAAAgAUSkpKSkoXKUpKSkkMAAAAAAAA + AAAMSkpKSkorAB05ORsAAAAAAAAAAAAAAAAARBQZSkpKSkobAB4zLAwAAAAAAAAAAAAAQ0pKSkoZAAAA + BSQxHgIAAAAAAAAAAAAASkIFRUpKSkkFAAAAAAAAAAAAAAAAAAAAD0FKSSoAAAADQEpKSjMAAAAAAAAA + AAAASkoFFUJKQxcAAAAAAAAAAAAAAAAAAAAAAAIRBRMPAQAeSkpKSkoMAAAAAAAAAAAASkYCAAAHAAAA + AAAAAAAAAAAAAAAAAAAAAAAHOUpKQg0mSkpKSkoOAAAAAAAAAAAASR4AAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAApSkpKSjgRSkpKSkMCAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAACKkE9GQA4SkpKSkUB + HERKPhMAAAAAAAAAAAAAOUlBFwAAAAAAAAAAAAAAAAAAAAAvSkpKSRcvSkpKSj0AAAEHAAAAAAAAAAAA + AAAASkpKSREAAAAAAAAAAAAAAAAAAAJFSkpKSjAKQ0pKRxUAAAAAAAAAAAAAAAAAAAAASkpKSiYAAAAA + AAAAAAAAAAAAAAdGSkpKSjAABx4gCQAAAAAAAAAAAAAAAAAAAAAASkpKSh4AAAAAAAAAAAAAAAAAAAAs + SUpKShUAAAAAAAAAAAAAAAAAAAAAAAAAAAAASkpKQwUAAAAAAAAAAAAAAAAAAAACJEE5FwAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAIzcsDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAXMzMXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlKSkpKGwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADlKSkpKPQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAj1KSkpKQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAHyNKSkpKKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAALwIqRUUsAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAEXIQ8A + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAATdKSkokAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAF0pKSkpKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAASjcFJkpKSkpKFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIaIREAAAAAAAAA + AAAASko1D0pKSkpJBwAAAAAAAgAAAAAAAAAAAAAAAAAAAAAABj1KSkkeAAAAAAAAAAAASkpKAClKSkke + AgAAAAAAAAAAAAACAAAAAAAAAAACAgAAIUpKSkpFAgAAAAAAAAAASkpDAAAMFQURBQAAAAACAAAAAgAA + AAAAAAAAAjBKSTACL0pKSkpKCQAAAAAAAAAASkohAAAAEUFKSS8CAAAAAAAAAAAAAAAAAAAAKkpKSkoo + HEpKSkpDAAAAAAAAAAAALhcAAAAAPUpKSkoeAAAAAAIAAAAAAh4zLAwAQUpKSko+ATFKSkYVAAAAAAAA + AAAACS09LgkHSkpKSkozAAAAAAAAAAAAL0pKSkYJOkpKSko5AAANFAMAAAAAAAAAAAAAPkpKSkEHRkpK + SkopAAIAAAwXBQIHSUpKSkojGEpKSkkXAAAAAAAAAAAAAAAAAAAASkpKSkoZHkpKSkMFAAAAKUpKSR4M + SkpKSkoqABAtLw8AAAAAAAAAAAAAAAAAAAAASkpKSkoaABQpIQcAAAATSkpKSkkMPUpKSkoUAAAAAAAA + AAAAAAAAAAAAAAAAAAAAQ0pKSkYHAAAAGz5DKwceSkpKSkoXDDlKQx4AAAAAAAAAAAAAAAAAAAAAAAAA + AAAAEThGORMAAAAXSkpKSjAUSkpKSkoMAAICAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx + SkpKSkkCMEpKSSoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwSkpKSkUCABUhDgAC + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPSkpKSisCAAAAAAAAAQAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFTg9JgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAgAAAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIA + AAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAA + AKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCAAAAAAAApEIAAAAAAACkQgAAAAAAAKRCKAAAACAAAABA + AAAAAQAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADw9PQA6QT4AOkQ/ADlGQAA3TUMAN05EADhJQQA4 + TEMANVFFADRVRgAzWkgANFhIADJdSQAvZk0ALmlOADFhSgAwY0wAMGRMAC1tUAArc1IALHJRACp1UgAq + d1QAKXlUACh9VgAngFcAJoJYACWGWgAliVsAJItcACOOXAAkjFwAIZJeACGVXwAfmWEAHpxiAB2fZAAg + lmAAIJhhAByhZAAbp2cAHKVmABuoZwAaqWgAF7JrABezbAAXtWwAGLBqABa4bQAUvXAADs52ABLBcQAR + xXMAEch0AA7QdwAN0ngADNV5AAvaegAK3HwACeB9AAjlfwAH5oAABumBAAPyhQAE8YQAA/SFAAH4hwAB + +ogAAP6JAACwNgAAz0AAAPBKABH/WwAx/3EAUf+HAHH/nQCR/7IAsf/JANH/3wD///8AAAAAAAIvAAAE + UAAABnAAAAiQAAAKsAAAC88AAA7wAAAg/xIAPf8xAFv/UQB5/3EAmP+RALX/sQDU/9EA////AAAAAAAU + LwAAIlAAADBwAAA9kAAATLAAAFnPAABn8AAAeP8RAIr/MQCc/1EArv9xAMD/kQDS/7EA5P/RAP///wAA + AAAAJi8AAEBQAABacAAAdJAAAI6wAACpzwAAwvAAANH/EQDY/zEA3v9RAOP/cQDp/5EA7/+xAPb/0QD/ + //8AAAAAAC8mAABQQQAAcFsAAJB0AACwjgAAz6kAAPDDAAD/0hEA/9gxAP/dUQD/5HEA/+qRAP/wsQD/ + 9tEA////AAAAAAAvFAAAUCIAAHAwAACQPgAAsE0AAM9bAADwaQAA/3kRAP+KMQD/nVEA/69xAP/BkQD/ + 0rEA/+XRAP///wAAAAAALwMAAFAEAABwBgAAkAkAALAKAADPDAAA8A4AAP8gEgD/PjEA/1xRAP96cQD/ + l5EA/7axAP/U0QD///8AAAAAAC8ADgBQABcAcAAhAJAAKwCwADYAzwBAAPAASQD/EVoA/zFwAP9RhgD/ + cZwA/5GyAP+xyAD/0d8A////AAAAAAAvACAAUAA2AHAATACQAGIAsAB4AM8AjgDwAKQA/xGzAP8xvgD/ + UccA/3HRAP+R3AD/seUA/9HwAP///wAAAAAALAAvAEsAUABpAHAAhwCQAKUAsADEAM8A4QDwAPAR/wDy + Mf8A9FH/APZx/wD3kf8A+bH/APvR/wD///8AAAAAABsALwAtAFAAPwBwAFIAkABjALAAdgDPAIgA8ACZ + Ef8ApjH/ALRR/wDCcf8Az5H/ANyx/wDr0f8A////AAAAAAAIAC8ADgBQABUAcAAbAJAAIQCwACYAzwAs + APAAPhH/AFgx/wBxUf8AjHH/AKaR/wC/sf8A2tH/AP///wAAABg2KgdEQ0M2DzY4EgAANkRDHDpEQzkA + AAAAAAAAAAEIREREITZDQyYAAAAAAAdDREQ1ETg4EQAAAAAAAAAAOxJEREQpBx8WAAAAAAAAADpERCEA + AB81KQAAAAAAAABEGy1EOwUAAAAAAAAAAAAABx8YDAARQ0REGQAAAAAAAEQNAAIAAAAAAAAAAAAAAAAA + Cz5DORZDQ0MfAAAAAAAAGAAAAAAAAAAAAAAAAAAfKgsmQ0NDFjFDOAcAAAAAAAA+QBsAAAAAAAAAAAAA + JkRDQBlDQ0MLAAIAAAAAAAAAAEREPwAAAAAAAAAAAAAwQ0NDBRwuFAAAAAAAAAAAAAAAREQ+AAAAAAAA + AAAAABRDQzEAAAAAAAAAAAAAAAAAAAA0Ng4AAAAAAAAAAAAAAAcPAAAAAAAAAAAAAAAAAAAAAAAcOC4C + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACURERCYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAS + REREKQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsrQzkFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAADQAAIS0RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABACFEREEDAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAEMcLURERAsAAAAAAAAAAAAAAAAAAAACJi4LAAAAAAAAREENQUQ0AAAAAAAAAAAAAAAAAAIA + ACpERDwAAAAAAABEPAAHER8YAAAAAAAAAAAAAAAYQUEXNURERAIAAAAAADURAAA2REQjAAAAAAAABx8W + ADxERDsUQ0QvAAAAAAAAHjsxB0RERDYAAAAAAAA6REQhOERENgAHCwAAAAAAAABEREQjNUREHgAAJjsw + CERERDULMzELAAAAAAAAAAAAAERERCQCFhYUAw9EREQhNkRDGwAAAAAAAAAAAAAAAAAAJEA1BwAIQEQ+ + FERERCYCFxEAAAAAAAAAAAAAAAAAAAAAAAAAACFEREQZKUA1AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + DUREQwsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCcNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAGAAAADAAAAAB + AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPDw8ADpBPgA6RD8AOkRAADdPRAA4SkEAOExDADZRRAA1 + VUYAM1pIADJeSQAxYEsAMGRMAC1tUAArc1IALHFRACp1UgAqd1QAKXlUACh9VgAngFcAJoJYACWFWQAk + iVsAJItcACONXAAkjFwAIpFeACGUXwAfmmIAHp5jACCWYAAgmGEAHaFkABumZgAcpGUAGqpoABitaQAV + uW4AFL5wAA/NdgASwXEAEcVzABDJdAAO0HcADdN4AAzVeQAL2HoACdx8AAjhfQAI5H8AB+eAAAbqgQAE + 7oMABPCEAAH4hwAB+ogAAP6JAFH/yABx/9MAkf/cALH/5QDR//AA////AAAAAAAALw4AAFAYAABwIgAA + kCwAALA2AADPQAAA8EoAEf9bADH/cQBR/4cAcf+dAJH/sgCx/8kA0f/fAP///wAAAAAAAi8AAARQAAAG + cAAACJAAAAqwAAALzwAADvAAACD/EgA9/zEAW/9RAHn/cQCY/5EAtf+xANT/0QD///8AAAAAABQvAAAi + UAAAMHAAAD2QAABMsAAAWc8AAGfwAAB4/xEAiv8xAJz/UQCu/3EAwP+RANL/sQDk/9EA////AAAAAAAm + LwAAQFAAAFpwAAB0kAAAjrAAAKnPAADC8AAA0f8RANj/MQDe/1EA4/9xAOn/kQDv/7EA9v/RAP///wAA + AAAALyYAAFBBAABwWwAAkHQAALCOAADPqQAA8MMAAP/SEQD/2DEA/91RAP/kcQD/6pEA//CxAP/20QD/ + //8AAAAAAC8UAABQIgAAcDAAAJA+AACwTQAAz1sAAPBpAAD/eREA/4oxAP+dUQD/r3EA/8GRAP/SsQD/ + 5dEA////AAAAAAAvAwAAUAQAAHAGAACQCQAAsAoAAM8MAADwDgAA/yASAP8+MQD/XFEA/3pxAP+XkQD/ + trEA/9TRAP///wAAAAAALwAOAFAAFwBwACEAkAArALAANgDPAEAA8ABJAP8RWgD/MXAA/1GGAP9xnAD/ + kbIA/7HIAP/R3wD///8AAAAAAC8AIABQADYAcABMAJAAYgCwAHgAzwCOAPAApAD/EbMA/zG+AP9RxwD/ + cdEA/5HcAP+x5QD/0fAA////AAAAAAAsAC8ASwBQAGkAcACHAJAApQCwAMQAzwDhAPAA8BH/APIx/wD0 + Uf8A9nH/APeR/wD5sf8A+9H/AP///wAAAAAAGwAvAC0AUAA/AHAAUgCQAGMAsAB2AM8AiADwAJkR/wCm + Mf8AtFH/AMJx/wDPkf8A3LH/AOvR/wD///8AAAAAAAgALwAOAFAAFQBwABsAkAAhALAAJgDPACwA8AA+ + Ef8AWDH/AHFR/wCMcf8AppH/AL+x/wDa0f8A////AAAMLSQhOTkTISMDADI5JC45LQAAAAAAABEmOTkR + LCcDAAAAAzg5KAYYGAQAAAAAADgUOC0DAAAAAwAAABEkDQMkOTQDAwAAADAAAwAAAwAAAAAAAAAkOScn + OTgGAAAAAB0RAAAAAAAAAAAkNhoyOTYEHg8AAAAAADk5CQAAAAAAAwM4OS8PJxQAAAAAAAMAADk4CAAD + AAAAAAAjMxgDAAADAAAAAAAAABEZDQAAAAAAAAAAAAAAAAAAAAAAAwAAAA85OREAAAADAAAAAAMAAAAA + AAAAAAAAABs5ORQAAAEAAAAAAwAAAAAAAAMAAAAAAA8WIAsAAAAAAAAAAAAAAAMAAAAAAwAAAAEGNjka + AAAAAAAAAAADAAAAAAAAAAAAADYWOTklAAAAAAAAAAAAAAADIycEAAAAADkgGiUKAAAAAAAAAAABGhoO + OTkhAAAAACgHACo5HgAAAAAADwsUOTkbNjgRAwAAACYxDjg5LwAABwMaOTgbOTkPAwYAAAAAADk5Jxoo + DwAbOTEhOTkMDAwAAAAAAAAAACo1EQAZNiQnOTkJHBMBAAMAAAMAAAMAAAAAAAAwOTgLJxwAAAAAAAAA + AAAAAAAAAAAAAAAWNCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQABAAEAAQAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAQAAAAIAAAAAEACAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8PT0AOkE+ADlGQAA3TUMAOElBADhMQwA1U0UANVVGADNbSQAy + XUkALmtPAC5sTwAxYUsAMGJMAC1vUAArc1IAK3RTACh8VgAngFcAJ4FYACaEWQAkiVsAH5piACGVYAAg + mGEAHKJlABunZwAaqWgAGa1pABa1bAAYsGoAFbtvABS8bwAPzXYAEsJyABHEcgAQynUADtF4AAzVeQAL + 2nsACt18AAjifgAI5X8ABuuCAATvgwAD84UABPCEAAL2hgAB+YgAAP6JAABQNwAAcEwAAJBjAACweQAA + z48AAPCmABH/tAAx/74AUf/IAHH/0wCR/9wAsf/lANH/8AD///8AAAAAAAAvDgAAUBgAAHAiAACQLAAA + sDYAAM9AAADwSgAR/1sAMf9xAFH/hwBx/50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAI + kAAACrAAAAvPAAAO8AAAIP8SAD3/MQBb/1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAw + cAAAPZAAAEywAABZzwAAZ/AAAHj/EQCK/zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABA + UAAAWnAAAHSQAACOsAAAqc8AAMLwAADR/xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAv + JgAAUEEAAHBbAACQdAAAsI4AAM+pAADwwwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAA + AAAALxQAAFAiAABwMAAAkD4AALBNAADPWwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD/ + //8AAAAAAC8DAABQBAAAcAYAAJAJAACwCgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/ + 1NEA////AAAAAAAvAA4AUAAXAHAAIQCQACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/ + scgA/9HfAP///wAAAAAALwAgAFAANgBwAEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/ + kdwA/7HlAP/R8AD///8AAAAAACwALwBLAFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2 + cf8A95H/APmx/wD70f8A////AAAAAAAbAC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0 + Uf8AwnH/AM+R/wDcsf8A69H/AP///wAAAAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBY + Mf8AcVH/AIxx/wCmkf8Av7H/ANrR/wD///8AAiUZLScLDgAtJSQiAAAAAB0rHQcFAAAAHBgFJhgAAAAV + AAAAAAAACwwwHiscAAAALxEAAAAAEDEcJRMAAAAAACoQAAAAAAUbCAAAAAAAAAAUKQcAAAAAAAAAAAAA + AAAAGi0IAAAAAAAAAAAAAAAAAAQWIgAAAAAAAAAAAAAAAAAoIi4CAAAAAAAAABkfAAAAIwAeFwAAAAcF + JiUhKwEAACcaLiYAEQwvJh8fAAEAAAApHgYdEjEkGRUAAAAAAAAAAAAJMR0UDAAAAAAAAAAAAAAAAA0C + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAwBQTFRFgICA//// + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAODgHVgAAAAlwSFlzAAAOvgAA + Dr4B6kKxwAAAABZJREFUGFdjYAABRhAAs4hlkq4DZDgACywAM12jTsYAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAnBJREFUOE+dk11I + k1Ecxs+2q1DLqwRvvCgoM6mLvoTAC6WLSrDUYBcSGK6y6EMzc6a2NnERlVKhSEMTYWSyksTZh7KZGboU + HNmUKemcupnuI5tuqHs6/7cSUenrwMPhPf/n97wPB46IrVrHCwuTxCJR5EbxbHiUZHQnEzE2uhj18Wsw + zPPLGgQmdErli9Ws8C2VX8wFX9y0rmiWnJ9/dg38Qc02dZdKUlQ3DrcuBINIfQTItMDJWiBHByj1gMEK + 0OxY9rkrywEvb7OQdzclR6tKDjRUV522qh7Kl5q6unDqQTnuNbZD89qEyhYTNK9M0PcMwLewgOsFh5oH + 70oSbXfYBmZUiM8P1Se06Z4WBP5UvarFALffj+q6goDjTXJTf7k4nWVmp159ayhDnVYu1Ot7tvmnImB+ + ztX4Y6dZUYMRzrk5VD4uxPueWmTlpVxmCVlZF1wuG8pqVJj0eKA+s5cHRMNm2Iapvn3wjCRirGOHUF2j + 12PY7Ubx/SJ4vJMglsXLZJcWefrI+Ge09PZCGr8V105sQU3xdgx0HYHfJ4O5ebdQXVNXjLb2Csy4x0EM + sexgRka2f2kJvkAAEzz9VmkCatWR0JaEoqkiDJ26cDxRh2LQ6YSyQgGna0zwEkMs25+envON13P7fII+ + 2e3QGo1rVN/RAZPFvOwjhli2RyrNdfNEh9eL0elpdFutsPMmLl55peiMZuQhLzHEsl1paXlf5udhdTjQ + abEIu21mZl2t9BBDLItOSpKP8HSj2Yx+Xn9oauq3Ig95iSGWRcTFKVr57Q/zv9pnZ/9K5CWGWBYaG5sZ + EhNT+j8idt0X+S+H3wE2DYYIXysH6QAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAm1JREFUOE+Nkl9I + U1Ecx39T31o9SBq97cWHiUIimKiQ0zFbbcJ1U2YkBtLuFYkQnMrcdKQyEUIwWk+GDy58EfUhmYoTRtKE + HitI8kGZIkEW/oF0um/nd3OyYUnn8rn3nMPn+733wNXYe3spOTQajVXMb55vpE/CiUTiqyB91+b1Ugry + j3gcWwcH2Nzfx8benspsJALhyII8qaeHUiHJ7U5F+Xl0hM3dXXzZ2cGn7W183NpCcG4OPISrmNvbdQZF + IaZOlolsNhvVOZ1U29XFtO4fH+ObeGtqyYuJCSTJM5s9Aqqqr1ez6s1ut5OtqYksHR1tB6Lg++HhhRL+ + Ej4OO+yqmbOCDLGwCuSsrKznLpcLl8EOu5wRBRkkSdJ1t9vdtyPOrCgK+vv74fV6L+DxeODz+VQnFouh + u7u7j7NksVj0o6Oj42tra3A4HOjs7ITT6URzczMkqQ7V1UaUl1egpOQ2zOZ7qjM/v4yBgcFxzlJNTU3l + 1NTU8urqKoxGowjLMJnMqKioFME7aRiNd1VndnYRIyOBZc6SwWBwRKPR9XA4jKKiIjQ0PBSS9a+YTLWq + 4xTX5OTbdc5SWVnZk1AohGAwCJ1OB7v9EazWB/+EnbGxMUxPT4OzVFxc7IpE3mFmJoS2tqcYHg5gaOgl + /P5ACq/E/A+tre1YXPygwlnS6/XupaUVLCysoLGx8b9IFnCWcnJyWrKzsweZzMzMIf5l7weA1++BN9HP + MPhacEv2o8o1iV8nJ2An6XOWxIK0Wi1dy82lG6Wlz9SfPmWcJhJg4qeniIsnO+xyhrPnBVcLC0lbUPD4 + Sn6+/zLYUd2zgt/AGvcWHCMAZwAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAW1JREFUOE+NkL1L + QlEYh9/b4NzS1BgNShBRQQ3VGEGr/0BDBEG0uLRIFIREIX2ANhgZKphj/4PLASOi0i4SYWWmWH5y/bhv + 5yc4HTl04YHD+z4893AMGvB53S7Hg+1cNQxjBGtm/p4YerrdvXlsDfJ7s7MlCp4ukgD7U3QX8mx+ZDIm + A5wx6+/hKiEs0+drnNiY5WTynlOpZ85mcz1wxgw7OHCVwPECCXlVDoev2ec75EDggiORGMfjCQ5dXrHf + f8LRaAwKw1UCR/MkbLns2Da/mOZAsIMDVwn45ki0pWB1OlrgwFUCBzMkrG6X662WFjhwlcDeNIlGu82/ + zaYWOHCVgHeSRFX+vVSraYEDVwnsuEj8WBbnKxUtcOAqAY+TREleP1cua4EDVwlsj5MoNBr8WixqgQNX + CWyNkfis19ksFLTAgasE1kdJvMsHTOfzWuDAVQLuYRJf8oHeqlUtcOAqgRUHBZcdJP4D3H7gDzdsNup2 + mXizAAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAXJJREFUOE+lk0FL + AkEYhlvwv3jzoiDoQdCbdEnYf6CrqCgoHgRRAk/9EQVLdEGyFiQNMS+dvHnoEkgglGAmCL7NO6RMIZvU + wsMO3zzzzGk0ACf/+hjQNO1ccKlXKsYx0OUZeflXoFmtVsUS2P4CHboi0FQDrXK5jM12i/VmYwsduiLQ + UgNmqVTCuzj8tlrZQoeuCJhqoFMsFvG6XmO2WNhCh64IdNRAt1Ao4EXc/jSf20KHrgh01YCVy+Uwnkzw + vFzaQoeuCFhqoJfJZBCLxY6Crgj01EA/lUrB4/HA7XYfhHs78vk8A301MIzH4/B6vRiNHjAY3H+DM+7p + ug6fz4dsNsvAUA2Mo9Eo/H4/LOsOTqdTYprXEs64x0AwGEQ6nWZgrAYeDcNAIBBAu30r/6Reb0t2MwbC + 4TCSySQDj/uAeEyngqnL5fpoNG4QCoUktVpHspsxEIlEkEgk+AKnaoAP8kwwczgcF4fg3g+u9gEu/son + bfJW/NwRDyIAAAAASUVORK5CYII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAUNJREFUOE+lk79L + QlEcxW9/gqCrm6vg4uYoOAgOrqLk4ioP0r2Glhp0SSjoF1FE0BIUDU3RdIOGoKBVGlpapaHTObeuCPe6 + 9ITD5fs9n3Pue8JbAWBS/VSQRvPwKR/j3JgaZXVqPv5TzPOXLhYoZDEcQidVWyhw3qzfn3tBAWH7PRjg + uV7HV5JAM6USyX50u86btlrOCwoOCR7Q+Oz1cFcu473dhmbppdFwu8dq1e3EBgU0zB6NXQJvzSaui0U8 + VCq4LZWwn8vhLJ+HPDFiowUEzITADsGrQgFHmYzTSTYL7eSJiRZs0timRoTGhC956wXDXtrJEyM2eAIt + t34Be8NgTPLELCuQYe8Z9tK8ZBf+ieuEnxj20rzB26SYF7zCGsGEoVeW6NTMoJFiXlDAkFllqMOwTs2+ + IOYFBf/9oFJ9ibr0B4f94vVG3bWDAAAAAElFTkSuQmCC + + \ No newline at end of file diff --git a/GreenshotPlugin/Core/HResultExtensions.cs b/src/Greenshot.Base/Core/HResultExtensions.cs similarity index 96% rename from GreenshotPlugin/Core/HResultExtensions.cs rename to src/Greenshot.Base/Core/HResultExtensions.cs index 450636ef7..9550101fd 100644 --- a/GreenshotPlugin/Core/HResultExtensions.cs +++ b/src/Greenshot.Base/Core/HResultExtensions.cs @@ -17,10 +17,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using GreenshotPlugin.Core.Enums; using System.Diagnostics.Contracts; +using Greenshot.Base.Core.Enums; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// Extensions to handle the HResult @@ -49,4 +49,4 @@ namespace GreenshotPlugin.Core return hResult >= HResult.S_OK; } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/IEHelper.cs b/src/Greenshot.Base/Core/IEHelper.cs new file mode 100644 index 000000000..7f01b73a2 --- /dev/null +++ b/src/Greenshot.Base/Core/IEHelper.cs @@ -0,0 +1,203 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using log4net; +using Microsoft.Win32; + +namespace Greenshot.Base.Core +{ + /// + /// Description of IEHelper. + /// + public static class IEHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IEHelper)); + + // Internet explorer Registry key + private const string IeKey = @"Software\Microsoft\Internet Explorer"; + + /// + /// Get the current browser version + /// + /// int with browser version + public static int IEVersion + { + get + { + var maxVer = 7; + using (var ieKey = Registry.LocalMachine.OpenSubKey(IeKey, false)) + { + foreach (var value in new[] + { + "svcVersion", "svcUpdateVersion", "Version", "W2kVersion" + }) + { + var objVal = ieKey.GetValue(value, "0"); + var strVal = Convert.ToString(objVal); + + var iPos = strVal.IndexOf('.'); + if (iPos > 0) + { + strVal = strVal.Substring(0, iPos); + } + + if (int.TryParse(strVal, out var res)) + { + maxVer = Math.Max(maxVer, res); + } + } + } + + return maxVer; + } + } + + /// + /// Get the highest possible version for the embedded browser + /// + /// true to ignore the doctype when loading a page + /// IE Feature + public static int GetEmbVersion(bool ignoreDoctype = true) + { + var ieVersion = IEVersion; + + if (ieVersion > 9) + { + return ieVersion * 1000 + (ignoreDoctype ? 1 : 0); + } + + if (ieVersion > 7) + { + return ieVersion * 1111; + } + + return 7000; + } + + /// + /// Fix browser version to the highest possible + /// + /// true to ignore the doctype when loading a page + public static void FixBrowserVersion(bool ignoreDoctype = true) + { + var applicationName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location); + FixBrowserVersion(applicationName, ignoreDoctype); + } + + /// + /// Fix the browser version for the specified application + /// + /// Name of the process + /// true to ignore the doctype when loading a page + public static void FixBrowserVersion(string applicationName, bool ignoreDoctype = true) + { + FixBrowserVersion(applicationName, GetEmbVersion(ignoreDoctype)); + } + + /// + /// Fix the browser version for the specified application + /// + /// Name of the process + /// + /// Version, see + /// Browser Emulation + /// + public static void FixBrowserVersion(string applicationName, int ieVersion) + { + ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".exe", ieVersion); +#if DEBUG + ModifyRegistry("HKEY_CURRENT_USER", applicationName + ".vshost.exe", ieVersion); +#endif + } + + /// + /// Make the change to the registry + /// + /// HKEY_CURRENT_USER or something + /// Name of the executable + /// Version to use + private static void ModifyRegistry(string root, string applicationName, int ieFeatureVersion) + { + var regKey = root + @"\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION"; + try + { + Registry.SetValue(regKey, applicationName, ieFeatureVersion); + } + catch (Exception ex) + { + // some config will hit access rights exceptions + // this is why we try with both LOCAL_MACHINE and CURRENT_USER + Log.Error(ex); + Log.ErrorFormat("couldn't modify the registry key {0}", regKey); + } + } + + /// + /// Find the DirectUI window for MSAA (Accessible) + /// + /// The browser WindowDetails + /// WindowDetails for the DirectUI window + public static WindowDetails GetDirectUI(WindowDetails browserWindowDetails) + { + if (browserWindowDetails == null) + { + return null; + } + + WindowDetails tmpWd = browserWindowDetails; + // Since IE 9 the TabBandClass is less deep! + if (IEVersion < 9) + { + tmpWd = tmpWd.GetChild("CommandBarClass"); + tmpWd = tmpWd?.GetChild("ReBarWindow32"); + } + + tmpWd = tmpWd?.GetChild("TabBandClass"); + tmpWd = tmpWd?.GetChild("DirectUIHWND"); + return tmpWd; + } + + /// + /// Return an IEnumerable with the currently opened IE urls + /// + /// + public static IEnumerable GetIEUrls() + { + // Find the IE window + foreach (WindowDetails ieWindow in WindowDetails.GetAllWindows("IEFrame")) + { + WindowDetails directUIWD = GetDirectUI(ieWindow); + if (directUIWD != null) + { + Accessible ieAccessible = new Accessible(directUIWD.Handle); + foreach (string url in ieAccessible.IETabUrls) + { + yield return url; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/IImage.cs b/src/Greenshot.Base/Core/IImage.cs new file mode 100644 index 000000000..2204d5739 --- /dev/null +++ b/src/Greenshot.Base/Core/IImage.cs @@ -0,0 +1,68 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Imaging; + +namespace Greenshot.Base.Core +{ + /// + /// The image interface, this abstracts an image + /// + public interface IImage : IDisposable + { + /// + /// Height of the image, can be set to change + /// + int Height { get; set; } + + /// + /// Width of the image, can be set to change. + /// + int Width { get; set; } + + /// + /// Size of the image + /// + Size Size { get; } + + /// + /// Pixelformat of the underlying image + /// + PixelFormat PixelFormat { get; } + + /// + /// Vertical resolution of the underlying image + /// + float VerticalResolution { get; } + + /// + /// Horizontal resolution of the underlying image + /// + float HorizontalResolution { get; } + + /// + /// Unterlying image, or an on demand rendered version with different attributes as the original + /// + Image Image { get; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/ImageHelper.cs b/src/Greenshot.Base/Core/ImageHelper.cs new file mode 100644 index 000000000..e93307717 --- /dev/null +++ b/src/Greenshot.Base/Core/ImageHelper.cs @@ -0,0 +1,1807 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using Greenshot.Base.Effects; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.UnmanagedHelpers; +using log4net; + +namespace Greenshot.Base.Core +{ + internal enum ExifOrientations : byte + { + Unknown = 0, + TopLeft = 1, + TopRight = 2, + BottomRight = 3, + BottomLeft = 4, + LeftTop = 5, + RightTop = 6, + RightBottom = 7, + LeftBottom = 8, + } + + /// + /// Description of ImageHelper. + /// + public static class ImageHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ImageHelper)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private const int ExifOrientationId = 0x0112; + + static ImageHelper() + { + StreamConverters["greenshot"] = (stream, s) => + { + var surface = SimpleServiceProvider.Current.GetInstance>().Invoke(); + return surface.GetImageForExport(); + }; + + // Add a SVG converter + StreamConverters["svg"] = (stream, s) => + { + stream.Position = 0; + try + { + return SvgImage.FromStream(stream).Image; + } + catch (Exception ex) + { + Log.Error("Can't load SVG", ex); + } + + return null; + }; + + static Image DefaultConverter(Stream stream, string s) + { + stream.Position = 0; + using var tmpImage = Image.FromStream(stream, true, true); + Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); + return Clone(tmpImage, PixelFormat.Format32bppArgb); + } + + // Fallback + StreamConverters[string.Empty] = DefaultConverter; + StreamConverters["gif"] = DefaultConverter; + StreamConverters["bmp"] = DefaultConverter; + StreamConverters["jpg"] = DefaultConverter; + StreamConverters["jpeg"] = DefaultConverter; + StreamConverters["png"] = DefaultConverter; + StreamConverters["wmf"] = DefaultConverter; + + StreamConverters["ico"] = (stream, extension) => + { + // Icon logic, try to get the Vista icon, else the biggest possible + try + { + using Image tmpImage = ExtractVistaIcon(stream); + if (tmpImage != null) + { + return Clone(tmpImage, PixelFormat.Format32bppArgb); + } + } + catch (Exception vistaIconException) + { + Log.Warn("Can't read icon", vistaIconException); + } + + try + { + // No vista icon, try normal icon + stream.Position = 0; + // We create a copy of the bitmap, so everything else can be disposed + using Icon tmpIcon = new Icon(stream, new Size(1024, 1024)); + using Image tmpImage = tmpIcon.ToBitmap(); + return Clone(tmpImage, PixelFormat.Format32bppArgb); + } + catch (Exception iconException) + { + Log.Warn("Can't read icon", iconException); + } + + stream.Position = 0; + return DefaultConverter(stream, extension); + }; + } + + public static IDictionary> StreamConverters { get; } = new Dictionary>(); + + /// + /// Make sure the image is orientated correctly + /// + /// + public static void Orientate(Image image) + { + if (!CoreConfig.ProcessEXIFOrientation) + { + return; + } + + try + { + // Get the index of the orientation property. + int orientationIndex = Array.IndexOf(image.PropertyIdList, ExifOrientationId); + // If there is no such property, return Unknown. + if (orientationIndex < 0) + { + return; + } + + PropertyItem item = image.GetPropertyItem(ExifOrientationId); + + ExifOrientations orientation = (ExifOrientations) item.Value[0]; + // Orient the image. + switch (orientation) + { + case ExifOrientations.Unknown: + case ExifOrientations.TopLeft: + break; + case ExifOrientations.TopRight: + image.RotateFlip(RotateFlipType.RotateNoneFlipX); + break; + case ExifOrientations.BottomRight: + image.RotateFlip(RotateFlipType.Rotate180FlipNone); + break; + case ExifOrientations.BottomLeft: + image.RotateFlip(RotateFlipType.RotateNoneFlipY); + break; + case ExifOrientations.LeftTop: + image.RotateFlip(RotateFlipType.Rotate90FlipX); + break; + case ExifOrientations.RightTop: + image.RotateFlip(RotateFlipType.Rotate90FlipNone); + break; + case ExifOrientations.RightBottom: + image.RotateFlip(RotateFlipType.Rotate90FlipY); + break; + case ExifOrientations.LeftBottom: + image.RotateFlip(RotateFlipType.Rotate270FlipNone); + break; + } + + // Set the orientation to be normal, as we rotated the image. + item.Value[0] = (byte) ExifOrientations.TopLeft; + image.SetPropertyItem(item); + } + catch (Exception orientEx) + { + Log.Warn("Problem orientating the image: ", orientEx); + } + } + + /// + /// Create a Thumbnail + /// + /// + /// + /// + /// + /// + /// + public static Image CreateThumbnail(Image image, int thumbWidth, int thumbHeight, int maxWidth = -1, int maxHeight = -1) + { + int srcWidth = image.Width; + int srcHeight = image.Height; + if (thumbHeight < 0) + { + thumbHeight = (int) (thumbWidth * (srcHeight / (float) srcWidth)); + } + + if (thumbWidth < 0) + { + thumbWidth = (int) (thumbHeight * (srcWidth / (float) srcHeight)); + } + + if (maxWidth > 0 && thumbWidth > maxWidth) + { + thumbWidth = Math.Min(thumbWidth, maxWidth); + thumbHeight = (int) (thumbWidth * (srcHeight / (float) srcWidth)); + } + + if (maxHeight > 0 && thumbHeight > maxHeight) + { + thumbHeight = Math.Min(thumbHeight, maxHeight); + thumbWidth = (int) (thumbHeight * (srcWidth / (float) srcHeight)); + } + + Bitmap bmp = new Bitmap(thumbWidth, thumbHeight); + using (Graphics graphics = Graphics.FromImage(bmp)) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight); + graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); + } + + return bmp; + } + + /// + /// Crops the image to the specified rectangle + /// + /// Image to crop + /// Rectangle with bitmap coordinates, will be "intersected" to the bitmap + public static bool Crop(ref Image image, ref Rectangle cropRectangle) + { + if (image is Bitmap && (image.Width * image.Height > 0)) + { + cropRectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height)); + if (cropRectangle.Width != 0 || cropRectangle.Height != 0) + { + Image returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare); + image.Dispose(); + image = returnImage; + return true; + } + } + + Log.Warn("Can't crop a null/zero size image!"); + return false; + } + + /// + /// Private helper method for the FindAutoCropRectangle + /// + /// + /// + /// + /// Rectangle + private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) + { + Rectangle cropRectangle = Rectangle.Empty; + Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); + Point min = new Point(int.MaxValue, int.MaxValue); + Point max = new Point(int.MinValue, int.MinValue); + + if (cropDifference > 0) + { + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { + Color currentColor = fastBitmap.GetColorAt(x, y); + int diffR = Math.Abs(currentColor.R - referenceColor.R); + int diffG = Math.Abs(currentColor.G - referenceColor.G); + int diffB = Math.Abs(currentColor.B - referenceColor.B); + if ((diffR + diffG + diffB) / 3 <= cropDifference) + { + continue; + } + + if (x < min.X) min.X = x; + if (y < min.Y) min.Y = y; + if (x > max.X) max.X = x; + if (y > max.Y) max.Y = y; + } + } + } + else + { + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { + Color currentColor = fastBitmap.GetColorAt(x, y); + if (!referenceColor.Equals(currentColor)) + { + continue; + } + + if (x < min.X) min.X = x; + if (y < min.Y) min.Y = y; + if (x > max.X) max.X = x; + if (y > max.Y) max.Y = y; + } + } + } + + if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) + { + if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) + { + cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); + } + } + + return cropRectangle; + } + + /// + /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 + /// + /// + /// + /// Rectangle + public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) + { + Rectangle cropRectangle = Rectangle.Empty; + var checkPoints = new List + { + new Point(0, 0), + new Point(0, image.Height - 1), + new Point(image.Width - 1, 0), + new Point(image.Width - 1, image.Height - 1) + }; + // Top Left + // Bottom Left + // Top Right + // Bottom Right + using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap) image)) + { + // find biggest area + foreach (Point checkPoint in checkPoints) + { + var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); + if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) + { + cropRectangle = currentRectangle; + } + } + } + + return cropRectangle; + } + + /// + /// Load an image from file + /// + /// + /// + public static Image LoadImage(string filename) + { + if (string.IsNullOrEmpty(filename)) + { + return null; + } + + if (!File.Exists(filename)) + { + return null; + } + + Image fileImage; + Log.InfoFormat("Loading image from file {0}", filename); + // Fixed lock problem Bug #3431881 + using (Stream imageFileStream = File.OpenRead(filename)) + { + fileImage = FromStream(imageFileStream, Path.GetExtension(filename)); + } + + if (fileImage != null) + { + Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat, + fileImage.HorizontalResolution, fileImage.VerticalResolution); + } + + return fileImage; + } + + /// + /// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx + /// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx + /// + /// Stream with the icon information + /// Bitmap with the Vista Icon (256x256) + private static Bitmap ExtractVistaIcon(Stream iconStream) + { + const int sizeIconDir = 6; + const int sizeIconDirEntry = 16; + Bitmap bmpPngExtracted = null; + try + { + byte[] srcBuf = new byte[iconStream.Length]; + iconStream.Read(srcBuf, 0, (int) iconStream.Length); + int iCount = BitConverter.ToInt16(srcBuf, 4); + for (int iIndex = 0; iIndex < iCount; iIndex++) + { + int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex]; + int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1]; + if (iWidth == 0 && iHeight == 0) + { + int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); + int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); + using MemoryStream destStream = new MemoryStream(); + destStream.Write(srcBuf, iImageOffset, iImageSize); + destStream.Seek(0, SeekOrigin.Begin); + bmpPngExtracted = new Bitmap(destStream); // This is PNG! :) + break; + } + } + } + catch + { + return null; + } + + return bmpPngExtracted; + } + + /// + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx + /// + /// The file (EXE or DLL) to get the icon from + /// Index of the icon + /// true if the large icon is wanted + /// Icon + public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) + { + Shell32.ExtractIconEx(location, index, out var large, out var small, 1); + Icon returnIcon = null; + bool isLarge = false; + bool isSmall = false; + try + { + if (takeLarge && !IntPtr.Zero.Equals(large)) + { + returnIcon = Icon.FromHandle(large); + isLarge = true; + } + else if (!IntPtr.Zero.Equals(small)) + { + returnIcon = Icon.FromHandle(small); + isSmall = true; + } + else if (!IntPtr.Zero.Equals(large)) + { + returnIcon = Icon.FromHandle(large); + isLarge = true; + } + } + finally + { + if (isLarge && !IntPtr.Zero.Equals(small)) + { + User32.DestroyIcon(small); + } + + if (isSmall && !IntPtr.Zero.Equals(large)) + { + User32.DestroyIcon(large); + } + } + + return returnIcon; + } + + /// + /// Apply the effect to the bitmap + /// + /// Bitmap + /// IEffect + /// + /// Bitmap + public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix) + { + var effects = new List + { + effect + }; + return ApplyEffects(sourceImage, effects, matrix); + } + + /// + /// Apply the effects in the supplied order to the bitmap + /// + /// Bitmap + /// List of IEffect + /// + /// Bitmap + public static Image ApplyEffects(Image sourceImage, IEnumerable effects, Matrix matrix) + { + var currentImage = sourceImage; + bool disposeImage = false; + foreach (var effect in effects) + { + var tmpImage = effect.Apply(currentImage, matrix); + if (tmpImage != null) + { + if (disposeImage) + { + currentImage.Dispose(); + } + + currentImage = tmpImage; + // Make sure the "new" image is disposed + disposeImage = true; + } + } + + return currentImage; + } + + /// + /// Helper method for the tornedge + /// + /// Path to draw to + /// Points for the lines to draw + private static void DrawLines(GraphicsPath path, List points) + { + path.AddLine(points[0], points[1]); + for (int i = 0; i < points.Count - 1; i++) + { + path.AddLine(points[i], points[i + 1]); + } + } + + /// + /// Make the picture look like it's torn + /// + /// Bitmap to make torn edge off + /// How large (height) is each tooth + /// How wide is a horizontal tooth + /// How wide is a vertical tooth + /// bool[] with information on if the edge needs torn or not. Order is clockwise: 0=top,1=right,2=bottom,3=left + /// Changed bitmap + public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, bool[] edges) + { + Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, + sourceImage.VerticalResolution); + using (var path = new GraphicsPath()) + { + Random random = new Random(); + int horizontalRegions = (int) Math.Round((float) sourceImage.Width / horizontalToothRange); + int verticalRegions = (int) Math.Round((float) sourceImage.Height / verticalToothRange); + + Point topLeft = new Point(0, 0); + Point topRight = new Point(sourceImage.Width, 0); + Point bottomLeft = new Point(0, sourceImage.Height); + Point bottomRight = new Point(sourceImage.Width, sourceImage.Height); + + List points = new List(); + + if (edges[0]) + { + // calculate starting point only if the left edge is torn + if (!edges[3]) + { + points.Add(topLeft); + } + else + { + points.Add(new Point(random.Next(1, toothHeight), random.Next(1, toothHeight))); + } + + for (int i = 1; i < horizontalRegions - 1; i++) + { + points.Add(new Point(i * horizontalToothRange, random.Next(1, toothHeight))); + } + + points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight))); + } + else + { + // set start & endpoint to be the default "whole-line" + points.Add(topLeft); + points.Add(topRight); + } + + // Right + if (edges[1]) + { + for (int i = 1; i < verticalRegions - 1; i++) + { + points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange)); + } + + points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); + } + else + { + // correct previous ending point + points[points.Count - 1] = topRight; + // set endpoint to be the default "whole-line" + points.Add(bottomRight); + } + + // Bottom + if (edges[2]) + { + for (int i = 1; i < horizontalRegions - 1; i++) + { + points.Add(new Point(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight))); + } + + points.Add(new Point(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); + } + else + { + // correct previous ending point + points[points.Count - 1] = bottomRight; + // set endpoint to be the default "whole-line" + points.Add(bottomLeft); + } + + // Left + if (edges[3]) + { + // One fewer as the end point is the starting point + for (int i = 1; i < verticalRegions - 1; i++) + { + points.Add(new Point(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange)); + } + } + else + { + // correct previous ending point + points[points.Count - 1] = bottomLeft; + // set endpoint to be the default "whole-line" + points.Add(topLeft); + } + + // End point always is the starting point + points[points.Count - 1] = points[0]; + + DrawLines(path, points); + + path.CloseFigure(); + + // Draw the created figure with the original image by using a TextureBrush so we have anti-aliasing + using Graphics graphics = Graphics.FromImage(returnImage); + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + using Brush brush = new TextureBrush(sourceImage); + // Important note: If the target wouldn't be at 0,0 we need to translate-transform!! + graphics.FillPath(brush, path); + } + + return returnImage; + } + + /// + /// Apply BoxBlur to the destinationBitmap + /// + /// Bitmap to blur + /// Must be ODD! + public static void ApplyBoxBlur(Bitmap destinationBitmap, int range) + { + // We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V) + using IFastBitmap fastBitmap = FastBitmap.Create(destinationBitmap); + ApplyBoxBlur(fastBitmap, range); + } + + /// + /// Apply BoxBlur to the fastBitmap + /// + /// IFastBitmap to blur + /// Must be ODD! + public static void ApplyBoxBlur(IFastBitmap fastBitmap, int range) + { + // Range must be odd! + if ((range & 1) == 0) + { + range++; + } + + if (range <= 1) + { + return; + } + + // Box blurs are frequently used to approximate a Gaussian blur. + // By the central limit theorem, if applied 3 times on the same image, a box blur approximates the Gaussian kernel to within about 3%, yielding the same result as a quadratic convolution kernel. + // This might be true, but the GDI+ BlurEffect doesn't look the same, a 2x blur is more simular and we only make 2x Box-Blur. + // (Might also be a mistake in our blur, but for now it looks great) + if (fastBitmap.HasAlphaChannel) + { + BoxBlurHorizontalAlpha(fastBitmap, range); + BoxBlurVerticalAlpha(fastBitmap, range); + BoxBlurHorizontalAlpha(fastBitmap, range); + BoxBlurVerticalAlpha(fastBitmap, range); + } + else + { + BoxBlurHorizontal(fastBitmap, range); + BoxBlurVertical(fastBitmap, range); + BoxBlurHorizontal(fastBitmap, range); + BoxBlurVertical(fastBitmap, range); + } + } + + /// + /// BoxBlurHorizontal is a private helper method for the BoxBlur + /// + /// Target BitmapBuffer + /// Range must be odd! + private static void BoxBlurHorizontal(IFastBitmap targetFastBitmap, int range) + { + if (targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurHorizontal should NOT be called for bitmaps with alpha channel"); + } + + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Width]; + byte[] tmpColor = new byte[3]; + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + int hits = 0; + int r = 0; + int g = 0; + int b = 0; + for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) + { + int oldPixel = x - halfRange - 1; + if (oldPixel >= targetFastBitmap.Left) + { + targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } + + int newPixel = x + halfRange; + if (newPixel < targetFastBitmap.Right) + { + targetFastBitmap.GetColorAt(newPixel, y, tmpColor); + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } + + if (x >= targetFastBitmap.Left) + { + newColors[x - targetFastBitmap.Left] = Color.FromArgb(255, (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } + + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); + } + } + } + + /// + /// BoxBlurHorizontal is a private helper method for the BoxBlur, only for IFastBitmaps with alpha channel + /// + /// Target BitmapBuffer + /// Range must be odd! + private static void BoxBlurHorizontalAlpha(IFastBitmap targetFastBitmap, int range) + { + if (!targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurHorizontalAlpha should be called for bitmaps with alpha channel"); + } + + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Width]; + byte[] tmpColor = new byte[4]; + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + int hits = 0; + int a = 0; + int r = 0; + int g = 0; + int b = 0; + for (int x = targetFastBitmap.Left - halfRange; x < targetFastBitmap.Right; x++) + { + int oldPixel = x - halfRange - 1; + if (oldPixel >= targetFastBitmap.Left) + { + targetFastBitmap.GetColorAt(oldPixel, y, tmpColor); + a -= tmpColor[FastBitmap.ColorIndexA]; + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } + + int newPixel = x + halfRange; + if (newPixel < targetFastBitmap.Right) + { + targetFastBitmap.GetColorAt(newPixel, y, tmpColor); + a += tmpColor[FastBitmap.ColorIndexA]; + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } + + if (x >= targetFastBitmap.Left) + { + newColors[x - targetFastBitmap.Left] = Color.FromArgb((byte) (a / hits), (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } + + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + targetFastBitmap.SetColorAt(x, y, newColors[x - targetFastBitmap.Left]); + } + } + } + + /// + /// BoxBlurVertical is a private helper method for the BoxBlur + /// + /// BitmapBuffer which previously was created with BoxBlurHorizontal + /// Range must be odd! + private static void BoxBlurVertical(IFastBitmap targetFastBitmap, int range) + { + if (targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurVertical should NOT be called for bitmaps with alpha channel"); + } + + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Height]; + byte[] tmpColor = new byte[4]; + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + int hits = 0; + int r = 0; + int g = 0; + int b = 0; + for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) + { + int oldPixel = y - halfRange - 1; + if (oldPixel >= targetFastBitmap.Top) + { + targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } + + int newPixel = y + halfRange; + if (newPixel < targetFastBitmap.Bottom) + { + targetFastBitmap.GetColorAt(x, newPixel, tmpColor); + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } + + if (y >= targetFastBitmap.Top) + { + newColors[y - targetFastBitmap.Top] = Color.FromArgb(255, (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } + + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); + } + } + } + + /// + /// BoxBlurVertical is a private helper method for the BoxBlur + /// + /// BitmapBuffer which previously was created with BoxBlurHorizontal + /// Range must be odd! + private static void BoxBlurVerticalAlpha(IFastBitmap targetFastBitmap, int range) + { + if (!targetFastBitmap.HasAlphaChannel) + { + throw new NotSupportedException("BoxBlurVerticalAlpha should be called for bitmaps with alpha channel"); + } + + int halfRange = range / 2; + Color[] newColors = new Color[targetFastBitmap.Height]; + byte[] tmpColor = new byte[4]; + for (int x = targetFastBitmap.Left; x < targetFastBitmap.Right; x++) + { + int hits = 0; + int a = 0; + int r = 0; + int g = 0; + int b = 0; + for (int y = targetFastBitmap.Top - halfRange; y < targetFastBitmap.Bottom; y++) + { + int oldPixel = y - halfRange - 1; + if (oldPixel >= targetFastBitmap.Top) + { + targetFastBitmap.GetColorAt(x, oldPixel, tmpColor); + a -= tmpColor[FastBitmap.ColorIndexA]; + r -= tmpColor[FastBitmap.ColorIndexR]; + g -= tmpColor[FastBitmap.ColorIndexG]; + b -= tmpColor[FastBitmap.ColorIndexB]; + hits--; + } + + int newPixel = y + halfRange; + if (newPixel < targetFastBitmap.Bottom) + { + //int colorg = pixels[index + newPixelOffset]; + targetFastBitmap.GetColorAt(x, newPixel, tmpColor); + a += tmpColor[FastBitmap.ColorIndexA]; + r += tmpColor[FastBitmap.ColorIndexR]; + g += tmpColor[FastBitmap.ColorIndexG]; + b += tmpColor[FastBitmap.ColorIndexB]; + hits++; + } + + if (y >= targetFastBitmap.Top) + { + newColors[y - targetFastBitmap.Top] = Color.FromArgb((byte) (a / hits), (byte) (r / hits), (byte) (g / hits), (byte) (b / hits)); + } + } + + for (int y = targetFastBitmap.Top; y < targetFastBitmap.Bottom; y++) + { + targetFastBitmap.SetColorAt(x, y, newColors[y - targetFastBitmap.Top]); + } + } + } + + /// + /// This method fixes the problem that we can't apply a filter outside the target bitmap, + /// therefor the filtered-bitmap will be shifted if we try to draw it outside the target bitmap. + /// It will also account for the Invert flag. + /// + /// + /// + /// + /// + public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) + { + Rectangle myRect; + if (invert) + { + myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); + } + else + { + Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height); + myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); + myRect.Intersect(applyRect); + } + + return myRect; + } + + /// + /// Create a new bitmap where the sourceBitmap has a shadow + /// + /// Bitmap to make a shadow on + /// How dark is the shadow + /// Size of the shadow + /// What pixel format must the returning bitmap have + /// + /// The transform matrix which describes how the elements need to be transformed to stay at the same location + /// Bitmap with the shadow, is bigger than the sourceBitmap!! + public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, Matrix matrix, PixelFormat targetPixelformat) + { + Point offset = shadowOffset; + offset.X += shadowSize - 1; + offset.Y += shadowSize - 1; + matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); + // Create a new "clean" image + Bitmap returnImage = CreateEmpty(sourceBitmap.Width + shadowSize * 2, sourceBitmap.Height + shadowSize * 2, targetPixelformat, Color.Empty, + sourceBitmap.HorizontalResolution, sourceBitmap.VerticalResolution); + // Make sure the shadow is odd, there is no reason for an even blur! + if ((shadowSize & 1) == 0) + { + shadowSize++; + } + + bool useGdiBlur = GDIplus.IsBlurPossible(shadowSize); + // Create "mask" for the shadow + ColorMatrix maskMatrix = new ColorMatrix + { + Matrix00 = 0, + Matrix11 = 0, + Matrix22 = 0 + }; + if (useGdiBlur) + { + maskMatrix.Matrix33 = darkness + 0.1f; + } + else + { + maskMatrix.Matrix33 = darkness; + } + + Rectangle shadowRectangle = new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size); + ApplyColorMatrix((Bitmap) sourceBitmap, Rectangle.Empty, returnImage, shadowRectangle, maskMatrix); + + // blur "shadow", apply to whole new image + if (useGdiBlur) + { + // Use GDI Blur + Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height); + GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize + 1, false); + } + else + { + // try normal software blur + //returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); + ApplyBoxBlur(returnImage, shadowSize); + } + + // Draw the original image over the shadow + using (Graphics graphics = Graphics.FromImage(returnImage)) + { + // Make sure we draw with the best quality! + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + // draw original with a TextureBrush so we have nice antialiasing! + using Brush textureBrush = new TextureBrush(sourceBitmap, WrapMode.Clamp); + // We need to do a translate-transform otherwise the image is wrapped + graphics.TranslateTransform(offset.X, offset.Y); + graphics.FillRectangle(textureBrush, 0, 0, sourceBitmap.Width, sourceBitmap.Height); + } + + return returnImage; + } + + /// + /// Return negative of Bitmap + /// + /// Bitmap to create a negative off + /// Negative bitmap + public static Bitmap CreateNegative(Image sourceImage) + { + Bitmap clone = (Bitmap) Clone(sourceImage); + ColorMatrix invertMatrix = new ColorMatrix(new[] + { + new float[] + { + -1, 0, 0, 0, 0 + }, + new float[] + { + 0, -1, 0, 0, 0 + }, + new float[] + { + 0, 0, -1, 0, 0 + }, + new float[] + { + 0, 0, 0, 1, 0 + }, + new float[] + { + 1, 1, 1, 1, 1 + } + }); + ApplyColorMatrix(clone, invertMatrix); + return clone; + } + + /// + /// Apply a color matrix to the image + /// + /// Image to apply matrix to + /// ColorMatrix to apply + public static void ApplyColorMatrix(Bitmap source, ColorMatrix colorMatrix) + { + ApplyColorMatrix(source, Rectangle.Empty, source, Rectangle.Empty, colorMatrix); + } + + /// + /// Apply a color matrix by copying from the source to the destination + /// + /// Image to copy from + /// Rectangle to copy from + /// Rectangle to copy to + /// Image to copy to + /// ColorMatrix to apply + public static void ApplyColorMatrix(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ColorMatrix colorMatrix) + { + using ImageAttributes imageAttributes = new ImageAttributes(); + imageAttributes.ClearColorMatrix(); + imageAttributes.SetColorMatrix(colorMatrix); + ApplyImageAttributes(source, sourceRect, dest, destRect, imageAttributes); + } + + /// + /// Apply a color matrix by copying from the source to the destination + /// + /// Image to copy from + /// Rectangle to copy from + /// Rectangle to copy to + /// Image to copy to + /// ImageAttributes to apply + public static void ApplyImageAttributes(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ImageAttributes imageAttributes) + { + if (sourceRect == Rectangle.Empty) + { + sourceRect = new Rectangle(0, 0, source.Width, source.Height); + } + + if (dest == null) + { + dest = source; + } + + if (destRect == Rectangle.Empty) + { + destRect = new Rectangle(0, 0, dest.Width, dest.Height); + } + + using Graphics graphics = Graphics.FromImage(dest); + // Make sure we draw with the best quality! + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingMode = CompositingMode.SourceCopy; + + graphics.DrawImage(source, destRect, sourceRect.X, sourceRect.Y, sourceRect.Width, sourceRect.Height, GraphicsUnit.Pixel, imageAttributes); + } + + /// + /// Returns a b/w of Bitmap + /// + /// Bitmap to create a b/w of + /// Threshold for monochrome filter (0 - 255), lower value means less black + /// b/w bitmap + public static Bitmap CreateMonochrome(Image sourceImage, byte threshold) + { + using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(sourceImage, sourceImage.PixelFormat); + for (int y = 0; y < fastBitmap.Height; y++) + { + for (int x = 0; x < fastBitmap.Width; x++) + { + Color color = fastBitmap.GetColorAt(x, y); + int colorBrightness = (color.R + color.G + color.B) / 3 > threshold ? 255 : 0; + Color monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness); + fastBitmap.SetColorAt(x, y, monoColor); + } + } + + return fastBitmap.UnlockAndReturnBitmap(); + } + + /// + /// Create a new bitmap where the sourceBitmap has a Simple border around it + /// + /// Bitmap to make a border on + /// Size of the border + /// Color of the border + /// What pixel format must the returning bitmap have + /// The transform matrix which describes how the elements need to be transformed to stay at the same location + /// Bitmap with the shadow, is bigger than the sourceBitmap!! + public static Image CreateBorder(Image sourceImage, int borderSize, Color borderColor, PixelFormat targetPixelformat, Matrix matrix) + { + // "return" the shifted offset, so the caller can e.g. move elements + Point offset = new Point(borderSize, borderSize); + matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); + + // Create a new "clean" image + Bitmap newImage = CreateEmpty(sourceImage.Width + borderSize * 2, sourceImage.Height + borderSize * 2, targetPixelformat, Color.Empty, sourceImage.HorizontalResolution, + sourceImage.VerticalResolution); + using (Graphics graphics = Graphics.FromImage(newImage)) + { + // Make sure we draw with the best quality! + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + using (GraphicsPath path = new GraphicsPath()) + { + path.AddRectangle(new Rectangle(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize)); + using Pen pen = new Pen(borderColor, borderSize) + { + LineJoin = LineJoin.Round, + StartCap = LineCap.Round, + EndCap = LineCap.Round + }; + graphics.DrawPath(pen, path); + } + + // draw original with a TextureBrush so we have nice antialiasing! + using Brush textureBrush = new TextureBrush(sourceImage, WrapMode.Clamp); + // We need to do a translate-tranform otherwise the image is wrapped + graphics.TranslateTransform(offset.X, offset.Y); + graphics.FillRectangle(textureBrush, 0, 0, sourceImage.Width, sourceImage.Height); + } + + return newImage; + } + + /// + /// Create ImageAttributes to modify + /// + /// + /// + /// + /// ImageAttributes + public static ImageAttributes CreateAdjustAttributes(float brightness, float contrast, float gamma) + { + float adjustedBrightness = brightness - 1.0f; + ColorMatrix applyColorMatrix = new ColorMatrix( + new[] + { + new[] + { + contrast, 0, 0, 0, 0 + }, // scale red + new[] + { + 0, contrast, 0, 0, 0 + }, // scale green + new[] + { + 0, 0, contrast, 0, 0 + }, // scale blue + new[] + { + 0, 0, 0, 1.0f, 0 + }, // don't scale alpha + new[] + { + adjustedBrightness, adjustedBrightness, adjustedBrightness, 0, 1 + } + }); + + //create some image attributes + ImageAttributes attributes = new ImageAttributes(); + attributes.ClearColorMatrix(); + attributes.SetColorMatrix(applyColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); + attributes.SetGamma(gamma, ColorAdjustType.Bitmap); + return attributes; + } + + /// + /// Adjust the brightness, contract or gamma of an image. + /// Use the value "1.0f" for no changes. + /// + /// Original bitmap + /// + /// + /// + /// Bitmap with grayscale + public static Image Adjust(Image sourceImage, float brightness, float contrast, float gamma) + { + //create a blank bitmap the same size as original + // If using 8bpp than the following exception comes: A Graphics object cannot be created from an image that has an indexed pixel format. + Bitmap newBitmap = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format24bppRgb, Color.Empty, sourceImage.HorizontalResolution, + sourceImage.VerticalResolution); + using (ImageAttributes adjustAttributes = CreateAdjustAttributes(brightness, contrast, gamma)) + { + ApplyImageAttributes((Bitmap) sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, adjustAttributes); + } + + return newBitmap; + } + + /// + /// Create a new bitmap where the sourceBitmap is in grayscale + /// + /// Original bitmap + /// Bitmap with grayscale + public static Image CreateGrayscale(Image sourceImage) + { + Bitmap clone = (Bitmap) Clone(sourceImage); + ColorMatrix grayscaleMatrix = new ColorMatrix(new[] + { + new[] + { + .3f, .3f, .3f, 0, 0 + }, + new[] + { + .59f, .59f, .59f, 0, 0 + }, + new[] + { + .11f, .11f, .11f, 0, 0 + }, + new float[] + { + 0, 0, 0, 1, 0 + }, + new float[] + { + 0, 0, 0, 0, 1 + } + }); + ApplyColorMatrix(clone, grayscaleMatrix); + return clone; + } + + /// + /// Checks if we support the pixel format + /// + /// PixelFormat to check + /// bool if we support it + public static bool SupportsPixelFormat(PixelFormat pixelformat) + { + return pixelformat.Equals(PixelFormat.Format32bppArgb) || + pixelformat.Equals(PixelFormat.Format32bppPArgb) || + pixelformat.Equals(PixelFormat.Format32bppRgb) || + pixelformat.Equals(PixelFormat.Format24bppRgb); + } + + /// + /// Wrapper for just cloning which calls the CloneArea + /// + /// Image to clone + /// Bitmap with clone image data + public static Image Clone(Image sourceImage) + { + if (sourceImage is Metafile) + { + return (Image) sourceImage.Clone(); + } + + return CloneArea(sourceImage, Rectangle.Empty, PixelFormat.DontCare); + } + + /// + /// Wrapper for just cloning & TargetFormat which calls the CloneArea + /// + /// Image to clone + /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) + /// Bitmap with clone image data + public static Bitmap Clone(Image sourceBitmap, PixelFormat targetFormat) + { + return CloneArea(sourceBitmap, Rectangle.Empty, targetFormat); + } + + /// + /// Clone an image, taking some rules into account: + /// 1) When sourceRect is the whole bitmap there is a GDI+ bug in Clone + /// Clone will than return the same PixelFormat as the source + /// a quick workaround is using new Bitmap which uses a default of Format32bppArgb + /// 2) When going from a transparent to a non transparent bitmap, we draw the background white! + /// + /// Source bitmap to clone + /// Rectangle to copy from the source, use Rectangle.Empty for all + /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) + /// + public static Bitmap CloneArea(Image sourceImage, Rectangle sourceRect, PixelFormat targetFormat) + { + Bitmap newImage; + Rectangle bitmapRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); + + // Make sure the source is not Rectangle.Empty + if (Rectangle.Empty.Equals(sourceRect)) + { + sourceRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); + } + else + { + sourceRect.Intersect(bitmapRect); + } + + // If no pixelformat is supplied + if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) + { + if (SupportsPixelFormat(sourceImage.PixelFormat)) + { + targetFormat = sourceImage.PixelFormat; + } + else if (Image.IsAlphaPixelFormat(sourceImage.PixelFormat)) + { + targetFormat = PixelFormat.Format32bppArgb; + } + else + { + targetFormat = PixelFormat.Format24bppRgb; + } + } + + // check the target format + if (!SupportsPixelFormat(targetFormat)) + { + targetFormat = Image.IsAlphaPixelFormat(targetFormat) ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb; + } + + bool destinationIsTransparent = Image.IsAlphaPixelFormat(targetFormat); + bool sourceIsTransparent = Image.IsAlphaPixelFormat(sourceImage.PixelFormat); + bool fromTransparentToNon = !destinationIsTransparent && sourceIsTransparent; + bool isBitmap = sourceImage is Bitmap; + bool isAreaEqual = sourceRect.Equals(bitmapRect); + if (isAreaEqual || fromTransparentToNon || !isBitmap) + { + // Rule 1: if the areas are equal, always copy ourselves + newImage = new Bitmap(bitmapRect.Width, bitmapRect.Height, targetFormat); + // Make sure both images have the same resolution + newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + + using Graphics graphics = Graphics.FromImage(newImage); + if (fromTransparentToNon) + { + // Rule 2: Make sure the background color is white + graphics.Clear(Color.White); + } + + // decide fastest copy method + if (isAreaEqual) + { + graphics.DrawImageUnscaled(sourceImage, 0, 0); + } + else + { + graphics.DrawImage(sourceImage, 0, 0, sourceRect, GraphicsUnit.Pixel); + } + } + else + { + // Let GDI+ decide how to convert, need to test what is quicker... + newImage = (sourceImage as Bitmap).Clone(sourceRect, targetFormat); + // Make sure both images have the same resolution + newImage.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + } + + // In WINE someone getting the PropertyItems doesn't work + try + { + // Clone property items (EXIF information etc) + foreach (var propertyItem in sourceImage.PropertyItems) + { + try + { + newImage.SetPropertyItem(propertyItem); + } + catch (Exception innerEx) + { + Log.Warn("Problem cloning a propertyItem.", innerEx); + } + } + } + catch (Exception ex) + { + Log.Warn("Problem cloning a propertyItem.", ex); + } + + return newImage; + } + + /// + /// Rotate the bitmap + /// + /// + /// + /// + public static Image RotateFlip(Image sourceImage, RotateFlipType rotateFlipType) + { + Image returnImage = Clone(sourceImage); + returnImage.RotateFlip(rotateFlipType); + return returnImage; + } + + /// + /// A generic way to create an empty image + /// + /// the source bitmap as the specifications for the new bitmap + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// + public static Bitmap CreateEmptyLike(Image sourceImage, Color backgroundColor) + { + PixelFormat pixelFormat = sourceImage.PixelFormat; + if (backgroundColor.A < 255) + { + pixelFormat = PixelFormat.Format32bppArgb; + } + + return CreateEmpty(sourceImage.Width, sourceImage.Height, pixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + } + + /// + /// A generic way to create an empty image + /// + /// + /// + /// + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// + /// + /// Bitmap + public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution, float verticalResolution) + { + // Create a new "clean" image + Bitmap newImage = new Bitmap(width, height, format); + newImage.SetResolution(horizontalResolution, verticalResolution); + if (format != PixelFormat.Format8bppIndexed) + { + using Graphics graphics = Graphics.FromImage(newImage); + // Make sure the background color is what we want (transparent or white, depending on the pixel format) + if (!Color.Empty.Equals(backgroundColor)) + { + graphics.Clear(backgroundColor); + } + else if (Image.IsAlphaPixelFormat(format)) + { + graphics.Clear(Color.Transparent); + } + else + { + graphics.Clear(Color.White); + } + } + + return newImage; + } + + /// + /// Resize canvas with pixel to the left, right, top and bottom + /// + /// + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// + /// + /// + /// + /// + /// a new bitmap with the source copied on it + public static Image ResizeCanvas(Image sourceImage, Color backgroundColor, int left, int right, int top, int bottom, Matrix matrix) + { + matrix.Translate(left, top, MatrixOrder.Append); + Bitmap newBitmap = CreateEmpty(sourceImage.Width + left + right, sourceImage.Height + top + bottom, sourceImage.PixelFormat, backgroundColor, + sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + using (Graphics graphics = Graphics.FromImage(newBitmap)) + { + graphics.DrawImageUnscaled(sourceImage, left, top); + } + + return newBitmap; + } + + /// + /// Wrapper for the more complex Resize, this resize could be used for e.g. Thumbnails + /// + /// + /// true to maintain the aspect ratio + /// + /// + /// + /// + public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, int newWidth, int newHeight, Matrix matrix) + { + return ResizeImage(sourceImage, maintainAspectRatio, false, Color.Empty, newWidth, newHeight, matrix); + } + + /// + /// Count how many times the supplied color exists + /// + /// Image to count the pixels of + /// Color to count + /// true if Alpha needs to be checked + /// int with the number of pixels which have colorToCount + public static int CountColor(Image sourceImage, Color colorToCount, bool includeAlpha) + { + int colors = 0; + int toCount = colorToCount.ToArgb(); + if (!includeAlpha) + { + toCount &= 0xffffff; + } + + using IFastBitmap bb = FastBitmap.Create((Bitmap) sourceImage); + for (int y = 0; y < bb.Height; y++) + { + for (int x = 0; x < bb.Width; x++) + { + int bitmapcolor = bb.GetColorAt(x, y).ToArgb(); + if (!includeAlpha) + { + bitmapcolor &= 0xffffff; + } + + if (bitmapcolor == toCount) + { + colors++; + } + } + } + + return colors; + } + + /// + /// Scale the bitmap, keeping aspect ratio, but the canvas will always have the specified size. + /// + /// Image to scale + /// true to maintain the aspect ratio + /// Makes the image maintain aspect ratio, but the canvas get's the specified size + /// The color to fill with, or Color.Empty to take the default depending on the pixel format + /// new width + /// new height + /// + /// a new bitmap with the specified size, the source-Image scaled to fit with aspect ratio locked + public static Image ResizeImage(Image sourceImage, bool maintainAspectRatio, bool canvasUseNewSize, Color backgroundColor, int newWidth, int newHeight, Matrix matrix) + { + int destX = 0; + int destY = 0; + + var nPercentW = newWidth / (float) sourceImage.Width; + var nPercentH = newHeight / (float) sourceImage.Height; + if (maintainAspectRatio) + { + if ((int) nPercentW == 1) + { + nPercentW = nPercentH; + if (canvasUseNewSize) + { + destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); + } + } + else if ((int) nPercentH == 1) + { + nPercentH = nPercentW; + if (canvasUseNewSize) + { + destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); + } + } + else if ((int) nPercentH != 0 && nPercentH < nPercentW) + { + nPercentW = nPercentH; + if (canvasUseNewSize) + { + destX = Math.Max(0, Convert.ToInt32((newWidth - sourceImage.Width * nPercentW) / 2)); + } + } + else + { + nPercentH = nPercentW; + if (canvasUseNewSize) + { + destY = Math.Max(0, Convert.ToInt32((newHeight - sourceImage.Height * nPercentH) / 2)); + } + } + } + + int destWidth = (int) (sourceImage.Width * nPercentW); + int destHeight = (int) (sourceImage.Height * nPercentH); + if (newWidth == 0) + { + newWidth = destWidth; + } + + if (newHeight == 0) + { + newHeight = destHeight; + } + + Image newImage; + if (maintainAspectRatio && canvasUseNewSize) + { + newImage = CreateEmpty(newWidth, newHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + matrix?.Scale((float) newWidth / sourceImage.Width, (float) newHeight / sourceImage.Height, MatrixOrder.Append); + } + else + { + newImage = CreateEmpty(destWidth, destHeight, sourceImage.PixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + matrix?.Scale((float) destWidth / sourceImage.Width, (float) destHeight / sourceImage.Height, MatrixOrder.Append); + } + + using (Graphics graphics = Graphics.FromImage(newImage)) + { + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + using ImageAttributes wrapMode = new ImageAttributes(); + wrapMode.SetWrapMode(WrapMode.TileFlipXY); + graphics.DrawImage(sourceImage, new Rectangle(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode); + } + + return newImage; + } + + /// + /// Load a Greenshot surface from a stream + /// + /// Stream + /// + /// ISurface + public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface) + { + Image fileImage; + // Fixed problem that the bitmap stream is disposed... by Cloning the image + // This also ensures the bitmap is correctly created + + // We create a copy of the bitmap, so everything else can be disposed + surfaceFileStream.Position = 0; + using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) + { + Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); + fileImage = Clone(tmpImage); + } + + // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) + const int markerSize = 14; + surfaceFileStream.Seek(-markerSize, SeekOrigin.End); + using (StreamReader streamReader = new StreamReader(surfaceFileStream)) + { + var greenshotMarker = streamReader.ReadToEnd(); + if (!greenshotMarker.StartsWith("Greenshot")) + { + throw new ArgumentException("Stream is not a Greenshot file!"); + } + + Log.InfoFormat("Greenshot file format: {0}", greenshotMarker); + const int filesizeLocation = 8 + markerSize; + surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); + using BinaryReader reader = new BinaryReader(surfaceFileStream); + long bytesWritten = reader.ReadInt64(); + surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End); + returnSurface.LoadElementsFromStream(surfaceFileStream); + } + + if (fileImage != null) + { + returnSurface.Image = fileImage; + Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat, + fileImage.HorizontalResolution, fileImage.VerticalResolution); + } + + return returnSurface; + } + + /// + /// Create an image from a stream, if an extension is supplied more formats are supported. + /// + /// Stream + /// + /// Image + public static Image FromStream(Stream stream, string extension = null) + { + if (stream == null) + { + return null; + } + + if (!string.IsNullOrEmpty(extension)) + { + extension = extension.Replace(".", string.Empty); + } + + // Make sure we can try multiple times + if (!stream.CanSeek) + { + var memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + stream = memoryStream; + } + + Image returnImage = null; + if (StreamConverters.TryGetValue(extension ?? string.Empty, out var converter)) + { + returnImage = converter(stream, extension); + } + + // Fallback + if (returnImage == null) + { + // We create a copy of the bitmap, so everything else can be disposed + stream.Position = 0; + using var tmpImage = Image.FromStream(stream, true, true); + Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); + returnImage = Clone(tmpImage, PixelFormat.Format32bppArgb); + } + + return returnImage; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/ImageOutput.cs b/src/Greenshot.Base/Core/ImageOutput.cs new file mode 100644 index 000000000..d6a42a7d9 --- /dev/null +++ b/src/Greenshot.Base/Core/ImageOutput.cs @@ -0,0 +1,798 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using log4net; +using Encoder = System.Drawing.Imaging.Encoder; + +namespace Greenshot.Base.Core +{ + /// + /// Description of ImageOutput. + /// + public static class ImageOutput + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ImageOutput)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131; + private static readonly Cache TmpFileCache = new Cache(10 * 60 * 60, RemoveExpiredTmpFile); + + /// + /// Creates a PropertyItem (Metadata) to store with the image. + /// For the possible ID's see: http://msdn.microsoft.com/de-de/library/system.drawing.imaging.propertyitem.id(v=vs.80).aspx + /// This code uses Reflection to create a PropertyItem, although it's not adviced it's not as stupid as having a image in the project so we can read a PropertyItem from that! + /// + /// ID + /// Text + /// + private static PropertyItem CreatePropertyItem(int id, string text) + { + PropertyItem propertyItem = null; + try + { + ConstructorInfo ci = typeof(PropertyItem).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] + { + }, null); + propertyItem = (PropertyItem) ci.Invoke(null); + // Make sure it's of type string + propertyItem.Type = 2; + // Set the ID + propertyItem.Id = id; + // Set the text + byte[] byteString = Encoding.ASCII.GetBytes(text + " "); + // Set Zero byte for String end. + byteString[byteString.Length - 1] = 0; + propertyItem.Value = byteString; + propertyItem.Len = text.Length + 1; + } + catch (Exception e) + { + Log.WarnFormat("Error creating a PropertyItem: {0}", e.Message); + } + + return propertyItem; + } + + /// + /// Saves ISurface to stream with specified output settings + /// + /// ISurface to save + /// Stream to save to + /// SurfaceOutputSettings + public static void SaveToStream(ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) + { + bool disposeImage = CreateImageFromSurface(surface, outputSettings, out var imageToSave); + SaveToStream(imageToSave, surface, stream, outputSettings); + // cleanup if needed + if (disposeImage) + { + imageToSave?.Dispose(); + } + } + + /// + /// Saves image to stream with specified quality + /// To prevent problems with GDI version of before Windows 7: + /// the stream is checked if it's seekable and if needed a MemoryStream as "cache" is used. + /// + /// image to save + /// surface for the elements, needed if the greenshot format is used + /// Stream to save to + /// SurfaceOutputSettings + public static void SaveToStream(Image imageToSave, ISurface surface, Stream stream, SurfaceOutputSettings outputSettings) + { + bool useMemoryStream = false; + MemoryStream memoryStream = null; + if (outputSettings.Format == OutputFormat.greenshot && surface == null) + { + throw new ArgumentException("Surface needs to be set when using OutputFormat.Greenshot"); + } + + try + { + var imageFormat = outputSettings.Format switch + { + OutputFormat.bmp => ImageFormat.Bmp, + OutputFormat.gif => ImageFormat.Gif, + OutputFormat.jpg => ImageFormat.Jpeg, + OutputFormat.tiff => ImageFormat.Tiff, + OutputFormat.ico => ImageFormat.Icon, + _ => ImageFormat.Png + }; + Log.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat); + + // Check if we want to use a memory stream, to prevent issues with non seakable streams + // The save is made to the targetStream, this is directed to either the MemoryStream or the original + Stream targetStream = stream; + if (!stream.CanSeek) + { + useMemoryStream = true; + Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream."); + memoryStream = new MemoryStream(); + targetStream = memoryStream; + } + + if (Equals(imageFormat, ImageFormat.Jpeg)) + { + bool foundEncoder = false; + foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders()) + { + if (imageCodec.FormatID == imageFormat.Guid) + { + EncoderParameters parameters = new EncoderParameters(1) + { + Param = + { + [0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality) + } + }; + // Removing transparency if it's not supported in the output + if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) + { + Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); + AddTag(nonAlphaImage); + nonAlphaImage.Save(targetStream, imageCodec, parameters); + nonAlphaImage.Dispose(); + } + else + { + AddTag(imageToSave); + imageToSave.Save(targetStream, imageCodec, parameters); + } + + foundEncoder = true; + break; + } + } + + if (!foundEncoder) + { + throw new ApplicationException("No JPG encoder found, this should not happen."); + } + } + else if (Equals(imageFormat, ImageFormat.Icon)) + { + // FEATURE-916: Added Icon support + IList images = new List + { + imageToSave + }; + WriteIcon(stream, images); + } + else + { + bool needsDispose = false; + // Removing transparency if it's not supported in the output + if (!Equals(imageFormat, ImageFormat.Png) && Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) + { + imageToSave = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); + needsDispose = true; + } + + AddTag(imageToSave); + // Added for OptiPNG + bool processed = false; + if (Equals(imageFormat, ImageFormat.Png) && !string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) + { + processed = ProcessPngImageExternally(imageToSave, targetStream); + } + + if (!processed) + { + imageToSave.Save(targetStream, imageFormat); + } + + if (needsDispose) + { + imageToSave.Dispose(); + } + } + + // If we used a memory stream, we need to stream the memory stream to the original stream. + if (useMemoryStream) + { + memoryStream.WriteTo(stream); + } + + // Output the surface elements, size and marker to the stream + if (outputSettings.Format != OutputFormat.greenshot) + { + return; + } + + using MemoryStream tmpStream = new MemoryStream(); + long bytesWritten = surface.SaveElementsToStream(tmpStream); + using BinaryWriter writer = new BinaryWriter(tmpStream); + writer.Write(bytesWritten); + Version v = Assembly.GetExecutingAssembly().GetName().Version; + byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); + writer.Write(marker); + tmpStream.WriteTo(stream); + } + finally + { + memoryStream?.Dispose(); + } + } + + /// + /// Write the passed Image to a tmp-file and call an external process, than read the file back and write it to the targetStream + /// + /// Image to pass to the external process + /// stream to write the processed image to + /// + private static bool ProcessPngImageExternally(Image imageToProcess, Stream targetStream) + { + if (string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) + { + return false; + } + + if (!File.Exists(CoreConfig.OptimizePNGCommand)) + { + Log.WarnFormat("Can't find 'OptimizePNGCommand' {0}", CoreConfig.OptimizePNGCommand); + return false; + } + + string tmpFileName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".png"); + try + { + using (FileStream tmpStream = File.Create(tmpFileName)) + { + Log.DebugFormat("Writing png to tmp file: {0}", tmpFileName); + imageToProcess.Save(tmpStream, ImageFormat.Png); + if (Log.IsDebugEnabled) + { + Log.DebugFormat("File size before processing {0}", new FileInfo(tmpFileName).Length); + } + } + + if (Log.IsDebugEnabled) + { + Log.DebugFormat("Starting : {0}", CoreConfig.OptimizePNGCommand); + } + + ProcessStartInfo processStartInfo = new ProcessStartInfo(CoreConfig.OptimizePNGCommand) + { + Arguments = string.Format(CoreConfig.OptimizePNGCommandArguments, tmpFileName), + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false + }; + using Process process = Process.Start(processStartInfo); + if (process != null) + { + process.WaitForExit(); + if (process.ExitCode == 0) + { + if (Log.IsDebugEnabled) + { + Log.DebugFormat("File size after processing {0}", new FileInfo(tmpFileName).Length); + Log.DebugFormat("Reading back tmp file: {0}", tmpFileName); + } + + byte[] processedImage = File.ReadAllBytes(tmpFileName); + targetStream.Write(processedImage, 0, processedImage.Length); + return true; + } + + Log.ErrorFormat("Error while processing PNG image: {0}", process.ExitCode); + Log.ErrorFormat("Output: {0}", process.StandardOutput.ReadToEnd()); + Log.ErrorFormat("Error: {0}", process.StandardError.ReadToEnd()); + } + } + catch (Exception e) + { + Log.Error("Error while processing PNG image: ", e); + } + finally + { + if (File.Exists(tmpFileName)) + { + Log.DebugFormat("Cleaning up tmp file: {0}", tmpFileName); + File.Delete(tmpFileName); + } + } + + return false; + } + + /// + /// Create an image from a surface with the settings from the output settings applied + /// + /// + /// + /// + /// true if the image must be disposed + public static bool CreateImageFromSurface(ISurface surface, SurfaceOutputSettings outputSettings, out Image imageToSave) + { + bool disposeImage = false; + + if (outputSettings.Format == OutputFormat.greenshot || outputSettings.SaveBackgroundOnly) + { + // We save the image of the surface, this should not be disposed + imageToSave = surface.Image; + } + else + { + // We create the export image of the surface to save + imageToSave = surface.GetImageForExport(); + disposeImage = true; + } + + // The following block of modifications should be skipped when saving the greenshot format, no effects or otherwise! + if (outputSettings.Format == OutputFormat.greenshot) + { + return disposeImage; + } + + Image tmpImage; + if (outputSettings.Effects != null && outputSettings.Effects.Count > 0) + { + // apply effects, if there are any + using (Matrix matrix = new Matrix()) + { + tmpImage = ImageHelper.ApplyEffects(imageToSave, outputSettings.Effects, matrix); + } + + if (tmpImage != null) + { + if (disposeImage) + { + imageToSave.Dispose(); + } + + imageToSave = tmpImage; + disposeImage = true; + } + } + + // check for color reduction, forced or automatically, only when the DisableReduceColors is false + if (outputSettings.DisableReduceColors || (!CoreConfig.OutputFileAutoReduceColors && !outputSettings.ReduceColors)) + { + return disposeImage; + } + + bool isAlpha = Image.IsAlphaPixelFormat(imageToSave.PixelFormat); + if (outputSettings.ReduceColors || (!isAlpha && CoreConfig.OutputFileAutoReduceColors)) + { + using var quantizer = new WuQuantizer((Bitmap) imageToSave); + int colorCount = quantizer.GetColorCount(); + Log.InfoFormat("Image with format {0} has {1} colors", imageToSave.PixelFormat, colorCount); + if (!outputSettings.ReduceColors && colorCount >= 256) + { + return disposeImage; + } + + try + { + Log.Info("Reducing colors on bitmap to 256."); + tmpImage = quantizer.GetQuantizedImage(CoreConfig.OutputFileReduceColorsTo); + if (disposeImage) + { + imageToSave.Dispose(); + } + + imageToSave = tmpImage; + // Make sure the "new" image is disposed + disposeImage = true; + } + catch (Exception e) + { + Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); + } + } + else if (isAlpha && !outputSettings.ReduceColors) + { + Log.Info("Skipping 'optional' color reduction as the image has alpha"); + } + + return disposeImage; + } + + /// + /// Add the greenshot property! + /// + /// + private static void AddTag(Image imageToSave) + { + // Create meta-data + PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot"); + if (softwareUsedPropertyItem != null) + { + try + { + imageToSave.SetPropertyItem(softwareUsedPropertyItem); + } + catch (Exception) + { + Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id); + } + } + } + + /// + /// Load a Greenshot surface + /// + /// + /// + /// + public static ISurface LoadGreenshotSurface(string fullPath, ISurface returnSurface) + { + if (string.IsNullOrEmpty(fullPath)) + { + return null; + } + + Log.InfoFormat("Loading image from file {0}", fullPath); + // Fixed lock problem Bug #3431881 + using (Stream surfaceFileStream = File.OpenRead(fullPath)) + { + returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface); + } + + if (returnSurface != null) + { + Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", fullPath, returnSurface.Image.Width, returnSurface.Image.Height, + returnSurface.Image.PixelFormat, returnSurface.Image.HorizontalResolution, returnSurface.Image.VerticalResolution); + } + + return returnSurface; + } + + /// + /// Saves image to specific path with specified quality + /// + public static void Save(ISurface surface, string fullPath, bool allowOverwrite, SurfaceOutputSettings outputSettings, bool copyPathToClipboard) + { + fullPath = FilenameHelper.MakeFqFilenameSafe(fullPath); + string path = Path.GetDirectoryName(fullPath); + + // check whether path exists - if not create it + if (path != null) + { + DirectoryInfo di = new DirectoryInfo(path); + if (!di.Exists) + { + Directory.CreateDirectory(di.FullName); + } + } + + if (!allowOverwrite && File.Exists(fullPath)) + { + ArgumentException throwingException = new ArgumentException("File '" + fullPath + "' already exists."); + throwingException.Data.Add("fullPath", fullPath); + throw throwingException; + } + + Log.DebugFormat("Saving surface to {0}", fullPath); + // Create the stream and call SaveToStream + using (FileStream stream = new FileStream(fullPath, FileMode.Create, FileAccess.Write)) + { + SaveToStream(surface, stream, outputSettings); + } + + if (copyPathToClipboard) + { + ClipboardHelper.SetClipboardData(fullPath); + } + } + + /// + /// Get the OutputFormat for a filename + /// + /// filename (can be a complete path) + /// OutputFormat + public static OutputFormat FormatForFilename(string fullPath) + { + // Fix for bug 2912959 + string extension = fullPath.Substring(fullPath.LastIndexOf(".", StringComparison.Ordinal) + 1); + OutputFormat format = OutputFormat.png; + try + { + format = (OutputFormat) Enum.Parse(typeof(OutputFormat), extension.ToLower()); + } + catch (ArgumentException ae) + { + Log.Warn("Couldn't parse extension: " + extension, ae); + } + + return format; + } + + /// + /// Save with showing a dialog + /// + /// + /// + /// Path to filename + public static string SaveWithDialog(ISurface surface, ICaptureDetails captureDetails) + { + string returnValue = null; + using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails)) + { + DialogResult dialogResult = saveImageFileDialog.ShowDialog(); + if (dialogResult.Equals(DialogResult.OK)) + { + try + { + string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension)); + if (CoreConfig.OutputFilePromptQuality) + { + QualityDialog qualityDialog = new QualityDialog(outputSettings); + qualityDialog.ShowDialog(); + } + + // TODO: For now we always overwrite, should be changed + Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); + returnValue = fileNameWithExtension; + IniConfig.Save(); + } + catch (ExternalException) + { + MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error")); + } + } + } + + return returnValue; + } + + /// + /// Create a tmpfile which has the name like in the configured pattern. + /// Used e.g. by the email export + /// + /// + /// + /// + /// Path to image file + public static string SaveNamedTmpFile(ISurface surface, ICaptureDetails captureDetails, SurfaceOutputSettings outputSettings) + { + string pattern = CoreConfig.OutputFileFilenamePattern; + if (string.IsNullOrEmpty(pattern?.Trim())) + { + pattern = "greenshot ${capturetime}"; + } + + string filename = FilenameHelper.GetFilenameFromPattern(pattern, outputSettings.Format, captureDetails); + // Prevent problems with "other characters", which causes a problem in e.g. Outlook 2007 or break our HTML + filename = Regex.Replace(filename, @"[^\d\w\.]", "_"); + // Remove multiple "_" + filename = Regex.Replace(filename, @"_+", "_"); + string tmpFile = Path.Combine(Path.GetTempPath(), filename); + + Log.Debug("Creating TMP File: " + tmpFile); + + // Catching any exception to prevent that the user can't write in the directory. + // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218 + try + { + Save(surface, tmpFile, true, outputSettings, false); + TmpFileCache.Add(tmpFile, tmpFile); + } + catch (Exception e) + { + // Show the problem + MessageBox.Show(e.Message, "Error"); + // when save failed we present a SaveWithDialog + tmpFile = SaveWithDialog(surface, captureDetails); + } + + return tmpFile; + } + + /// + /// Remove a tmpfile which was created by SaveNamedTmpFile + /// Used e.g. by the email export + /// + /// + /// true if it worked + public static bool DeleteNamedTmpFile(string tmpfile) + { + Log.Debug("Deleting TMP File: " + tmpfile); + try + { + if (File.Exists(tmpfile)) + { + File.Delete(tmpfile); + TmpFileCache.Remove(tmpfile); + } + + return true; + } + catch (Exception ex) + { + Log.Warn("Error deleting tmp file: ", ex); + } + + return false; + } + + /// + /// Helper method to create a temp image file + /// + /// + /// + /// + /// + public static string SaveToTmpFile(ISurface surface, SurfaceOutputSettings outputSettings, string destinationPath) + { + string tmpFile = Path.GetRandomFileName() + "." + outputSettings.Format; + // Prevent problems with "other characters", which could cause problems + tmpFile = Regex.Replace(tmpFile, @"[^\d\w\.]", string.Empty); + if (destinationPath == null) + { + destinationPath = Path.GetTempPath(); + } + + string tmpPath = Path.Combine(destinationPath, tmpFile); + Log.Debug("Creating TMP File : " + tmpPath); + + try + { + Save(surface, tmpPath, true, outputSettings, false); + TmpFileCache.Add(tmpPath, tmpPath); + } + catch (Exception) + { + return null; + } + + return tmpPath; + } + + /// + /// Cleanup all created tmpfiles + /// + public static void RemoveTmpFiles() + { + foreach (string tmpFile in TmpFileCache.Elements) + { + if (File.Exists(tmpFile)) + { + Log.DebugFormat("Removing old temp file {0}", tmpFile); + File.Delete(tmpFile); + } + + TmpFileCache.Remove(tmpFile); + } + } + + /// + /// Cleanup handler for expired tempfiles + /// + /// + /// + private static void RemoveExpiredTmpFile(string filekey, object filename) + { + if (filename is string path && File.Exists(path)) + { + Log.DebugFormat("Removing expired file {0}", path); + File.Delete(path); + } + } + + /// + /// Write the images to the stream as icon + /// Every image is resized to 256x256 (but the content maintains the aspect ratio) + /// + /// Stream to write to + /// List of images + public static void WriteIcon(Stream stream, IList images) + { + var binaryWriter = new BinaryWriter(stream); + // + // ICONDIR structure + // + binaryWriter.Write((short) 0); // reserved + binaryWriter.Write((short) 1); // image type (icon) + binaryWriter.Write((short) images.Count); // number of images + + IList imageSizes = new List(); + IList encodedImages = new List(); + foreach (var image in images) + { + // Pick the best fit + var sizes = new[] + { + 16, 32, 48 + }; + int size = 256; + foreach (var possibleSize in sizes) + { + if (image.Width <= possibleSize && image.Height <= possibleSize) + { + size = possibleSize; + break; + } + } + + var imageStream = new MemoryStream(); + if (image.Width == size && image.Height == size) + { + using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); + clonedImage.Save(imageStream, ImageFormat.Png); + imageSizes.Add(new Size(size, size)); + } + else + { + // Resize to the specified size, first make sure the image is 32bpp + using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); + using var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null); + resizedImage.Save(imageStream, ImageFormat.Png); + imageSizes.Add(resizedImage.Size); + } + + imageStream.Seek(0, SeekOrigin.Begin); + encodedImages.Add(imageStream); + } + + // + // ICONDIRENTRY structure + // + const int iconDirSize = 6; + const int iconDirEntrySize = 16; + + var offset = iconDirSize + (images.Count * iconDirEntrySize); + for (int i = 0; i < images.Count; i++) + { + var imageSize = imageSizes[i]; + // Write the width / height, 0 means 256 + binaryWriter.Write(imageSize.Width == 256 ? (byte) 0 : (byte) imageSize.Width); + binaryWriter.Write(imageSize.Height == 256 ? (byte) 0 : (byte) imageSize.Height); + binaryWriter.Write((byte) 0); // no pallete + binaryWriter.Write((byte) 0); // reserved + binaryWriter.Write((short) 0); // no color planes + binaryWriter.Write((short) 32); // 32 bpp + binaryWriter.Write((int) encodedImages[i].Length); // image data length + binaryWriter.Write(offset); + offset += (int) encodedImages[i].Length; + } + + binaryWriter.Flush(); + // + // Write image data + // + foreach (var encodedImage in encodedImages) + { + encodedImage.WriteTo(stream); + encodedImage.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/ImageWrapper.cs b/src/Greenshot.Base/Core/ImageWrapper.cs new file mode 100644 index 000000000..517249534 --- /dev/null +++ b/src/Greenshot.Base/Core/ImageWrapper.cs @@ -0,0 +1,77 @@ +using System.Drawing; +using System.Drawing.Imaging; + +namespace Greenshot.Base.Core +{ + /// + /// Wrap an image, make it resizeable + /// + public class ImageWrapper : IImage + { + // Underlying image, is used to generate a resized version of it when needed + private readonly Image _image; + private Image _imageClone; + + public ImageWrapper(Image image) + { + // Make sure the orientation is set correctly so Greenshot can process the image correctly + ImageHelper.Orientate(image); + _image = image; + Width = _image.Width; + Height = _image.Height; + } + + public void Dispose() + { + _image.Dispose(); + _imageClone?.Dispose(); + } + + /// + /// Height of the image, can be set to change + /// + public int Height { get; set; } + + /// + /// Width of the image, can be set to change. + /// + public int Width { get; set; } + + /// + /// Size of the image + /// + public Size Size => new Size(Width, Height); + + /// + /// Pixelformat of the underlying image + /// + public PixelFormat PixelFormat => Image.PixelFormat; + + public float HorizontalResolution => Image.HorizontalResolution; + public float VerticalResolution => Image.VerticalResolution; + + public Image Image + { + get + { + if (_imageClone == null) + { + if (_image.Height == Height && _image.Width == Width) + { + return _image; + } + } + + if (_imageClone?.Height == Height && _imageClone?.Width == Width) + { + return _imageClone; + } + + // Calculate new image clone + _imageClone?.Dispose(); + _imageClone = ImageHelper.ResizeImage(_image, false, Width, Height, null); + return _imageClone; + } + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/InterfaceUtils.cs b/src/Greenshot.Base/Core/InterfaceUtils.cs similarity index 56% rename from GreenshotPlugin/Core/InterfaceUtils.cs rename to src/Greenshot.Base/Core/InterfaceUtils.cs index 7dca0f172..c93f24b56 100644 --- a/GreenshotPlugin/Core/InterfaceUtils.cs +++ b/src/Greenshot.Base/Core/InterfaceUtils.cs @@ -1,58 +1,73 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.Threading; -using log4net; - -namespace GreenshotPlugin.Core { - /// - /// Description of InterfaceUtils. - /// - public static class InterfaceUtils { - private static readonly ILog LOG = LogManager.GetLogger(typeof(InterfaceUtils)); - - public static List GetSubclassesOf(Type type, bool excludeSystemTypes) { - var list = new List(); - foreach(var currentAssembly in Thread.GetDomain().GetAssemblies()) { - try { - Type[] types = currentAssembly.GetTypes(); - if (excludeSystemTypes && (!excludeSystemTypes || currentAssembly.FullName.StartsWith("System."))) - { - continue; - } - foreach(var currentType in types) { - if (type.IsInterface) { - if (currentType.GetInterface(type.FullName) != null) { - list.Add(currentType); - } - } else if (currentType.IsSubclassOf(type)) { - list.Add(currentType); - } - } - } catch (Exception ex) { - LOG.WarnFormat("Problem getting subclasses of type: {0}, message: {1}", type.FullName, ex.Message); - } - } - return list; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// Description of InterfaceUtils. + /// + public static class InterfaceUtils + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(InterfaceUtils)); + + public static List GetSubclassesOf(Type type, bool excludeSystemTypes) + { + var list = new List(); + foreach (var currentAssembly in Thread.GetDomain().GetAssemblies()) + { + try + { + Type[] types = currentAssembly.GetTypes(); + if (excludeSystemTypes && (!excludeSystemTypes || currentAssembly.FullName.StartsWith("System."))) + { + continue; + } + + foreach (var currentType in types) + { + if (type.IsInterface) + { + if (currentType.GetInterface(type.FullName) != null) + { + list.Add(currentType); + } + } + else if (currentType.IsSubclassOf(type)) + { + list.Add(currentType); + } + } + } + catch (Exception ex) + { + LOG.WarnFormat("Problem getting subclasses of type: {0}, message: {1}", type.FullName, ex.Message); + } + } + + return list; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/JSONHelper.cs b/src/Greenshot.Base/Core/JSONHelper.cs new file mode 100644 index 000000000..37da4972b --- /dev/null +++ b/src/Greenshot.Base/Core/JSONHelper.cs @@ -0,0 +1,436 @@ +/* +Copyright (C) 2008 Patrick van Bergen + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace Greenshot.Base.Core +{ + /// + /// This parses a JSON response, a modified version of the code found at: + /// See: http://techblog.procurios.nl/k/n618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html + /// + /// This file is under the MIT License, which is GPL Compatible and according to: http://en.wikipedia.org/wiki/MIT_License + /// can be used under the GPL "umbrella". + /// + /// TODO: code should be replaced when upgrading to .NET 3.5 or higher!! + /// + public class JSONHelper + { + public const int TOKEN_NONE = 0; + public const int TOKEN_CURLY_OPEN = 1; + public const int TOKEN_CURLY_CLOSE = 2; + public const int TOKEN_SQUARED_OPEN = 3; + public const int TOKEN_SQUARED_CLOSE = 4; + public const int TOKEN_COLON = 5; + public const int TOKEN_COMMA = 6; + public const int TOKEN_STRING = 7; + public const int TOKEN_NUMBER = 8; + public const int TOKEN_TRUE = 9; + public const int TOKEN_FALSE = 10; + public const int TOKEN_NULL = 11; + + private const int BUILDER_CAPACITY = 2000; + + /// + /// Parses the string json into a value + /// + /// A JSON string. + /// An ArrayList, a Hashtable, a double, a string, null, true, or false + public static IDictionary JsonDecode(string json) + { + bool success = true; + + return JsonDecode(json, ref success); + } + + /// + /// Parses the string json into a value; and fills 'success' with the successfullness of the parse. + /// + /// A JSON string. + /// Successful parse? + /// An ArrayList, a Hashtable, a double, a string, null, true, or false + public static IDictionary JsonDecode(string json, ref bool success) + { + success = true; + if (json != null) + { + char[] charArray = json.ToCharArray(); + int index = 0; + IDictionary value = ParseValue(charArray, ref index, ref success) as IDictionary; + return value; + } + + return null; + } + + protected static IDictionary ParseObject(char[] json, ref int index, ref bool success) + { + IDictionary table = new Dictionary(); + int token; + + // { + NextToken(json, ref index); + + bool done = false; + while (!done) + { + token = LookAhead(json, index); + if (token == TOKEN_NONE) + { + success = false; + return null; + } + else if (token == TOKEN_COMMA) + { + NextToken(json, ref index); + } + else if (token == TOKEN_CURLY_CLOSE) + { + NextToken(json, ref index); + return table; + } + else + { + // name + string name = ParseString(json, ref index, ref success); + if (!success) + { + success = false; + return null; + } + + // : + token = NextToken(json, ref index); + if (token != TOKEN_COLON) + { + success = false; + return null; + } + + // value + object value = ParseValue(json, ref index, ref success); + if (!success) + { + success = false; + return null; + } + + table.Add(name, value); + } + } + + return table; + } + + protected static IList ParseArray(char[] json, ref int index, ref bool success) + { + IList array = new List(); + + // [ + NextToken(json, ref index); + + bool done = false; + while (!done) + { + int token = LookAhead(json, index); + if (token == TOKEN_NONE) + { + success = false; + return null; + } + else if (token == TOKEN_COMMA) + { + NextToken(json, ref index); + } + else if (token == TOKEN_SQUARED_CLOSE) + { + NextToken(json, ref index); + break; + } + else + { + object value = ParseValue(json, ref index, ref success); + if (!success) + { + return null; + } + + array.Add(value); + } + } + + return array; + } + + protected static object ParseValue(char[] json, ref int index, ref bool success) + { + switch (LookAhead(json, index)) + { + case TOKEN_STRING: + return ParseString(json, ref index, ref success); + case TOKEN_NUMBER: + return ParseNumber(json, ref index, ref success); + case TOKEN_CURLY_OPEN: + return ParseObject(json, ref index, ref success); + case TOKEN_SQUARED_OPEN: + return ParseArray(json, ref index, ref success); + case TOKEN_TRUE: + NextToken(json, ref index); + return true; + case TOKEN_FALSE: + NextToken(json, ref index); + return false; + case TOKEN_NULL: + NextToken(json, ref index); + return null; + case TOKEN_NONE: + break; + } + + success = false; + return null; + } + + protected static string ParseString(char[] json, ref int index, ref bool success) + { + StringBuilder s = new StringBuilder(BUILDER_CAPACITY); + + EatWhitespace(json, ref index); + + // " + var c = json[index++]; + + bool complete = false; + while (!complete) + { + if (index == json.Length) + { + break; + } + + c = json[index++]; + if (c == '"') + { + complete = true; + break; + } + else if (c == '\\') + { + if (index == json.Length) + { + break; + } + + c = json[index++]; + if (c == '"') + { + s.Append('"'); + } + else if (c == '\\') + { + s.Append('\\'); + } + else if (c == '/') + { + s.Append('/'); + } + else if (c == 'b') + { + s.Append('\b'); + } + else if (c == 'f') + { + s.Append('\f'); + } + else if (c == 'n') + { + s.Append('\n'); + } + else if (c == 'r') + { + s.Append('\r'); + } + else if (c == 't') + { + s.Append('\t'); + } + else if (c == 'u') + { + int remainingLength = json.Length - index; + if (remainingLength >= 4) + { + // parse the 32 bit hex into an integer codepoint + if (!(success = uint.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var codePoint))) + { + return string.Empty; + } + + // convert the integer codepoint to a unicode char and add to string + s.Append(char.ConvertFromUtf32((int) codePoint)); + // skip 4 chars + index += 4; + } + else + { + break; + } + } + } + else + { + s.Append(c); + } + } + + if (!complete) + { + success = false; + return null; + } + + return s.ToString(); + } + + protected static double ParseNumber(char[] json, ref int index, ref bool success) + { + EatWhitespace(json, ref index); + + int lastIndex = GetLastIndexOfNumber(json, index); + int charLength = (lastIndex - index) + 1; + + success = double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out var number); + + index = lastIndex + 1; + return number; + } + + protected static int GetLastIndexOfNumber(char[] json, int index) + { + int lastIndex; + + for (lastIndex = index; lastIndex < json.Length; lastIndex++) + { + if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) + { + break; + } + } + + return lastIndex - 1; + } + + protected static void EatWhitespace(char[] json, ref int index) + { + for (; index < json.Length; index++) + { + if (" \t\n\r".IndexOf(json[index]) == -1) + { + break; + } + } + } + + protected static int LookAhead(char[] json, int index) + { + int saveIndex = index; + return NextToken(json, ref saveIndex); + } + + protected static int NextToken(char[] json, ref int index) + { + EatWhitespace(json, ref index); + + if (index == json.Length) + { + return TOKEN_NONE; + } + + char c = json[index]; + index++; + switch (c) + { + case '{': + return TOKEN_CURLY_OPEN; + case '}': + return TOKEN_CURLY_CLOSE; + case '[': + return TOKEN_SQUARED_OPEN; + case ']': + return TOKEN_SQUARED_CLOSE; + case ',': + return TOKEN_COMMA; + case '"': + return TOKEN_STRING; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return TOKEN_NUMBER; + case ':': + return TOKEN_COLON; + } + + index--; + + int remainingLength = json.Length - index; + + // false + if (remainingLength >= 5) + { + if (json[index] == 'f' && + json[index + 1] == 'a' && + json[index + 2] == 'l' && + json[index + 3] == 's' && + json[index + 4] == 'e') + { + index += 5; + return TOKEN_FALSE; + } + } + + // true + if (remainingLength >= 4) + { + if (json[index] == 't' && + json[index + 1] == 'r' && + json[index + 2] == 'u' && + json[index + 3] == 'e') + { + index += 4; + return TOKEN_TRUE; + } + } + + // null + if (remainingLength >= 4) + { + if (json[index] == 'n' && + json[index + 1] == 'u' && + json[index + 2] == 'l' && + json[index + 3] == 'l') + { + index += 4; + return TOKEN_NULL; + } + } + + return TOKEN_NONE; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/Language.cs b/src/Greenshot.Base/Core/Language.cs new file mode 100644 index 000000000..74ba1b457 --- /dev/null +++ b/src/Greenshot.Base/Core/Language.cs @@ -0,0 +1,807 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Xml; +using Greenshot.Base.IniFile; +using log4net; +using Microsoft.Win32; + +namespace Greenshot.Base.Core +{ + /// + /// This class supplies the GUI with translations, based upon keys. + /// The language resources are loaded from the language files found on fixed or supplied paths + /// + public class Language + { + private static readonly ILog Log = LogManager.GetLogger(typeof(Language)); + private static readonly List LanguagePaths = new List(); + private static readonly Dictionary> LanguageFiles = new Dictionary>(); + private static readonly Dictionary HelpFiles = new Dictionary(); + private const string DefaultLanguage = "en-US"; + private const string HelpFilenamePattern = @"help-*.html"; + private const string LanguageFilenamePattern = @"language*.xml"; + private static readonly Regex PrefixRegexp = new Regex(@"language_([a-zA-Z0-9]+).*"); + private static readonly Regex IetfCleanRegexp = new Regex(@"[^a-zA-Z]+"); + private static readonly Regex IetfRegexp = new Regex(@"^.*([a-zA-Z]{2,3}-[a-zA-Z]{1,2})\.xml$"); + private const string LanguageGroupsKey = @"SYSTEM\CurrentControlSet\Control\Nls\Language Groups"; + private static readonly List UnsupportedLanguageGroups = new List(); + private static readonly Dictionary Resources = new Dictionary(); + private static string _currentLanguage; + + public static event LanguageChangedHandler LanguageChanged; + + /// + /// Static initializer for the language code + /// + static Language() + { + if (!IniConfig.IsInitialized) + { + Log.Warn("IniConfig hasn't been initialized yet! (Design mode?)"); + IniConfig.Init("greenshot", "greenshot"); + } + + if (!LogHelper.IsInitialized) + { + Log.Warn("Log4net hasn't been initialized yet! (Design mode?)"); + LogHelper.InitializeLog4Net(); + } + + try + { + string applicationFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + // PAF Path + if (applicationFolder != null) + { + AddPath(Path.Combine(applicationFolder, @"App\Greenshot\Languages")); + } + + // Application data path + string applicationDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + AddPath(Path.Combine(applicationDataFolder, @"Greenshot\Languages\")); + + // Startup path + if (applicationFolder != null) + { + AddPath(Path.Combine(applicationFolder, @"Languages")); + } + } + catch (Exception pathException) + { + Log.Error(pathException); + } + + try + { + using RegistryKey languageGroupsKey = Registry.LocalMachine.OpenSubKey(LanguageGroupsKey, false); + if (languageGroupsKey != null) + { + string[] groups = languageGroupsKey.GetValueNames(); + foreach (string group in groups) + { + string groupValue = (string) languageGroupsKey.GetValue(group); + bool isGroupNotInstalled = "0".Equals(groupValue); + if (isGroupNotInstalled) + { + UnsupportedLanguageGroups.Add(group.ToLower()); + } + } + } + } + catch (Exception e) + { + Log.Warn("Couldn't read the installed language groups.", e); + } + + var coreConfig = IniConfig.GetIniSection(); + ScanFiles(); + if (!string.IsNullOrEmpty(coreConfig.Language)) + { + CurrentLanguage = coreConfig.Language; + if (CurrentLanguage != null && CurrentLanguage != coreConfig.Language) + { + coreConfig.Language = CurrentLanguage; + } + } + + if (CurrentLanguage == null) + { + Log.Warn("Couldn't set language from configuration, changing to default. Installation problem?"); + CurrentLanguage = DefaultLanguage; + if (CurrentLanguage != null) + { + coreConfig.Language = CurrentLanguage; + } + } + + if (CurrentLanguage == null) + { + Log.Error("Couldn't set language, installation problem?"); + } + } + + /// + /// Internal method to add a path to the paths that will be scanned for language files! + /// + /// + /// true if the path exists and is added + private static bool AddPath(string path) + { + if (!LanguagePaths.Contains(path)) + { + if (Directory.Exists(path)) + { + Log.DebugFormat("Adding language path {0}", path); + LanguagePaths.Add(path); + return true; + } + + Log.InfoFormat("Not adding non existing language path {0}", path); + } + + return false; + } + + /// + /// Add a new path to the paths that will be scanned for language files! + /// + /// + /// true if the path exists and is added + public static bool AddLanguageFilePath(string path) + { + if (!LanguagePaths.Contains(path)) + { + Log.DebugFormat("New language path {0}", path); + if (AddPath(path)) + { + ScanFiles(); + Reload(); + } + else + { + return false; + } + } + + return true; + } + + /// + /// Load the files for the specified ietf + /// + /// + private static void LoadFiles(string ietf) + { + ietf = ReformatIetf(ietf); + if (!LanguageFiles.ContainsKey(ietf)) + { + Log.ErrorFormat("No language {0} available.", ietf); + return; + } + + List filesToLoad = LanguageFiles[ietf]; + foreach (LanguageFile fileToLoad in filesToLoad) + { + LoadResources(fileToLoad); + } + } + + /// + /// Load the language resources from the scanned files + /// + private static void Reload() + { + Resources.Clear(); + LoadFiles(DefaultLanguage); + if (_currentLanguage != null && !_currentLanguage.Equals(DefaultLanguage)) + { + LoadFiles(_currentLanguage); + } + } + + /// + /// Get or set the current language + /// + public static string CurrentLanguage + { + get => _currentLanguage; + set + { + string ietf = FindBestIetfMatch(value); + if (!LanguageFiles.ContainsKey(ietf)) + { + Log.WarnFormat("No match for language {0} found!", ietf); + } + else + { + if (_currentLanguage == null || !_currentLanguage.Equals(ietf)) + { + _currentLanguage = ietf; + Reload(); + if (LanguageChanged == null) + { + return; + } + + try + { + LanguageChanged(null, null); + } + catch + { + // ignored + } + + return; + } + } + + Log.Debug("CurrentLanguage not changed!"); + } + } + + /// + /// Try to find the best match for the supplied IETF + /// + /// string + /// IETF + private static string FindBestIetfMatch(string inputIetf) + { + string returnIetf = inputIetf; + if (string.IsNullOrEmpty(returnIetf)) + { + returnIetf = DefaultLanguage; + } + + returnIetf = ReformatIetf(returnIetf); + if (!LanguageFiles.ContainsKey(returnIetf)) + { + Log.WarnFormat("Unknown language {0}, trying best match!", returnIetf); + if (returnIetf.Length == 5) + { + returnIetf = returnIetf.Substring(0, 2); + } + + foreach (string availableIetf in LanguageFiles.Keys) + { + if (!availableIetf.StartsWith(returnIetf)) continue; + + Log.InfoFormat("Found language {0}, best match for {1}!", availableIetf, returnIetf); + returnIetf = availableIetf; + break; + } + } + + return returnIetf; + } + + /// + /// This helper method clears all non alpha characters from the IETF, and does a reformatting. + /// This prevents problems with multiple formats or typos. + /// + /// + /// + private static string ReformatIetf(string inputIetf) + { + string returnIetf = null; + if (!string.IsNullOrEmpty(inputIetf)) + { + returnIetf = inputIetf.ToLower(); + returnIetf = IetfCleanRegexp.Replace(returnIetf, string.Empty); + if (returnIetf.Length == 4) + { + returnIetf = returnIetf.Substring(0, 2) + "-" + returnIetf.Substring(2, 2).ToUpper(); + } + } + + return returnIetf; + } + + /// + /// Return a list of all the supported languages + /// + public static IList SupportedLanguages + { + get + { + IList languages = new List(); + // Loop over all languages with all the files in there + foreach (List langs in LanguageFiles.Values) + { + // Loop over all the files for a language + foreach (LanguageFile langFile in langs) + { + // Only take the ones without prefix, these are the "base" language files + if (langFile.Prefix != null) continue; + languages.Add(langFile); + break; + } + } + + return languages; + } + } + + /// + /// Return the path to the help-file + /// + public static string HelpFilePath + { + get + { + if (HelpFiles.ContainsKey(_currentLanguage)) + { + return HelpFiles[_currentLanguage]; + } + + return HelpFiles[DefaultLanguage]; + } + } + + /// + /// Load the resources from the language file + /// + /// File to load from + private static void LoadResources(LanguageFile languageFile) + { + Log.InfoFormat("Loading language file {0}", languageFile.Filepath); + try + { + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.Load(languageFile.Filepath); + XmlNodeList resourceNodes = xmlDocument.GetElementsByTagName("resource"); + foreach (XmlNode resourceNode in resourceNodes) + { + string key = resourceNode.Attributes["name"].Value; + if (!string.IsNullOrEmpty(languageFile.Prefix)) + { + key = languageFile.Prefix + "." + key; + } + + string text = resourceNode.InnerText; + if (!string.IsNullOrEmpty(text)) + { + text = text.Trim(); + } + + if (!Resources.ContainsKey(key)) + { + Resources.Add(key, text); + } + else + { + Resources[key] = text; + } + } + } + catch (Exception e) + { + Log.Error("Could not load language file " + languageFile.Filepath, e); + } + } + + /// + /// Load the language file information + /// + /// + /// + private static LanguageFile LoadFileInfo(string languageFilePath) + { + try + { + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.Load(languageFilePath); + XmlNodeList nodes = xmlDocument.GetElementsByTagName("language"); + if (nodes.Count > 0) + { + LanguageFile languageFile = new LanguageFile + { + Filepath = languageFilePath + }; + XmlNode node = nodes.Item(0); + if (node?.Attributes != null) + { + languageFile.Description = node.Attributes["description"].Value; + if (node.Attributes["ietf"] != null) + { + languageFile.Ietf = ReformatIetf(node.Attributes["ietf"].Value); + } + + if (node.Attributes["version"] != null) + { + languageFile.Version = new Version(node.Attributes["version"].Value); + } + + if (node.Attributes["prefix"] != null) + { + languageFile.Prefix = node.Attributes["prefix"].Value.ToLower(); + } + + if (node.Attributes["languagegroup"] != null) + { + string languageGroup = node.Attributes["languagegroup"].Value; + languageFile.LanguageGroup = languageGroup.ToLower(); + } + } + + return languageFile; + } + + throw new XmlException("Root element is missing"); + } + catch (Exception e) + { + Log.Error("Could not load language file " + languageFilePath, e); + } + + return null; + } + + /// + /// Scan the files in all directories + /// + private static void ScanFiles() + { + LanguageFiles.Clear(); + HelpFiles.Clear(); + foreach (string languagePath in LanguagePaths) + { + if (!Directory.Exists(languagePath)) + { + Log.InfoFormat("Skipping non existing language path {0}", languagePath); + continue; + } + + Log.InfoFormat("Searching language directory '{0}' for language files with pattern '{1}'", languagePath, LanguageFilenamePattern); + try + { + foreach (string languageFilepath in Directory.GetFiles(languagePath, LanguageFilenamePattern, SearchOption.AllDirectories)) + { + //LOG.DebugFormat("Found language file: {0}", languageFilepath); + LanguageFile languageFile = LoadFileInfo(languageFilepath); + if (languageFile == null) + { + continue; + } + + if (string.IsNullOrEmpty(languageFile.Ietf)) + { + Log.WarnFormat("Fixing missing ietf in language-file {0}", languageFilepath); + string languageFilename = Path.GetFileName(languageFilepath); + if (IetfRegexp.IsMatch(languageFilename)) + { + string replacementIetf = IetfRegexp.Replace(languageFilename, "$1"); + languageFile.Ietf = ReformatIetf(replacementIetf); + Log.InfoFormat("Fixed IETF to {0}", languageFile.Ietf); + } + else + { + Log.ErrorFormat("Missing ietf , no recover possible... skipping language-file {0}!", languageFilepath); + continue; + } + } + + // Check if we can display the file + if (!string.IsNullOrEmpty(languageFile.LanguageGroup) && UnsupportedLanguageGroups.Contains(languageFile.LanguageGroup)) + { + Log.InfoFormat("Skipping unsuported (not able to display) language {0} from file {1}", languageFile.Description, languageFilepath); + continue; + } + + // build prefix, based on the filename, but only if it's not set in the file itself. + if (string.IsNullOrEmpty(languageFile.Prefix)) + { + string languageFilename = Path.GetFileNameWithoutExtension(languageFilepath); + if (PrefixRegexp.IsMatch(languageFilename)) + { + languageFile.Prefix = PrefixRegexp.Replace(languageFilename, "$1"); + if (!string.IsNullOrEmpty(languageFile.Prefix)) + { + languageFile.Prefix = languageFile.Prefix.Replace("plugin", string.Empty).ToLower(); + } + } + } + + List currentFiles; + if (LanguageFiles.ContainsKey(languageFile.Ietf)) + { + currentFiles = LanguageFiles[languageFile.Ietf]; + bool needToAdd = true; + List deleteList = new List(); + foreach (LanguageFile compareWithLangfile in currentFiles) + { + if ((languageFile.Prefix != null || compareWithLangfile.Prefix != null) && + (languageFile.Prefix == null || + !languageFile.Prefix.Equals(compareWithLangfile.Prefix))) continue; + + if (compareWithLangfile.Version > languageFile.Version) + { + Log.WarnFormat("Skipping {0}:{1}:{2} as {3}:{4}:{5} is newer", languageFile.Filepath, languageFile.Prefix, languageFile.Version, + compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); + needToAdd = false; + break; + } + + Log.WarnFormat("Found {0}:{1}:{2} and deleting {3}:{4}:{5}", languageFile.Filepath, languageFile.Prefix, languageFile.Version, + compareWithLangfile.Filepath, compareWithLangfile.Prefix, compareWithLangfile.Version); + deleteList.Add(compareWithLangfile); + } + + if (needToAdd) + { + foreach (LanguageFile deleteFile in deleteList) + { + currentFiles.Remove(deleteFile); + } + + Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); + currentFiles.Add(languageFile); + } + } + else + { + currentFiles = new List + { + languageFile + }; + LanguageFiles.Add(languageFile.Ietf, currentFiles); + Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); + } + } + } + catch (DirectoryNotFoundException) + { + Log.InfoFormat("Non existing language directory: {0}", languagePath); + } + catch (Exception e) + { + Log.Error("Error trying for read directory " + languagePath, e); + } + + // Now find the help files + Log.InfoFormat("Searching language directory '{0}' for help files with pattern '{1}'", languagePath, HelpFilenamePattern); + try + { + foreach (string helpFilepath in Directory.GetFiles(languagePath, HelpFilenamePattern, SearchOption.AllDirectories)) + { + Log.DebugFormat("Found help file: {0}", helpFilepath); + string helpFilename = Path.GetFileName(helpFilepath); + string ietf = ReformatIetf(helpFilename.Replace(".html", string.Empty).Replace("help-", "")); + if (!HelpFiles.ContainsKey(ietf)) + { + HelpFiles.Add(ietf, helpFilepath); + } + else + { + Log.WarnFormat("skipping help file {0}, already a file with the same IETF {1} found!", helpFilepath, ietf); + } + } + } + catch (DirectoryNotFoundException) + { + Log.InfoFormat("Non existing language directory: {0}", languagePath); + } + catch (Exception e) + { + Log.Error("Error trying for read directory " + languagePath, e); + } + } + } + + /// + /// Check if a resource with prefix.key exists + /// + /// + /// + /// true if available + public static bool HasKey(string prefix, string key) + { + return HasKey(prefix + "." + key); + } + + /// + /// Check if a resource with key exists + /// + /// + /// true if available + public static bool HasKey(string key) + { + if (key == null) + { + return false; + } + + return Resources.ContainsKey(key); + } + + /// + /// TryGet method which combines HasKey & GetString + /// + /// + /// out string + /// + public static bool TryGetString(string key, out string languageString) + { + return Resources.TryGetValue(key, out languageString); + } + + /// + /// TryGet method which combines HasKey & GetString + /// + /// string with prefix + /// string with key + /// out string + /// + public static bool TryGetString(string prefix, string key, out string languageString) + { + return Resources.TryGetValue(prefix + "." + key, out languageString); + } + + /// + /// TryGet method which combines HasKey & GetString + /// + /// string with prefix + /// Enum with key + /// out string + /// + public static bool TryGetString(string prefix, Enum key, out string languageString) + { + return Resources.TryGetValue(prefix + "." + key, out languageString); + } + + /// + /// Translate + /// + /// object + /// string + public static string Translate(object key) + { + string typename = key.GetType().Name; + string enumKey = typename + "." + key; + if (HasKey(enumKey)) + { + return GetString(enumKey); + } + + return key.ToString(); + } + + /// + /// Get the resource for key + /// + /// Enum + /// resource or a "string ###key### not found" + public static string GetString(Enum key) + { + if (key == null) + { + return null; + } + + return GetString(key.ToString()); + } + + /// + /// Get the resource for prefix.key + /// + /// string + /// Enum + /// resource or a "string ###prefix.key### not found" + public static string GetString(string prefix, Enum key) + { + if (key == null) + { + return null; + } + + return GetString(prefix + "." + key); + } + + /// + /// Get the resource for prefix.key + /// + /// string + /// string + /// resource or a "string ###prefix.key### not found" + public static string GetString(string prefix, string key) + { + return GetString(prefix + "." + key); + } + + /// + /// Get the resource for key + /// + /// string + /// resource or a "string ###key### not found" + public static string GetString(string key) + { + if (key == null) + { + return null; + } + + if (!Resources.TryGetValue(key, out var returnValue)) + { + return "string ###" + key + "### not found"; + } + + return returnValue; + } + + /// + /// Get the resource for key, format with with string.format an supply the parameters + /// + /// Enum + /// object + /// formatted resource or a "string ###key### not found" + public static string GetFormattedString(Enum key, object param) + { + return GetFormattedString(key.ToString(), param); + } + + /// + /// Get the resource for prefix.key, format with with string.format an supply the parameters + /// + /// string + /// Enum + /// object + /// formatted resource or a "string ###prefix.key### not found" + public static string GetFormattedString(string prefix, Enum key, object param) + { + return GetFormattedString(prefix, key.ToString(), param); + } + + /// + /// Get the resource for prefix.key, format with with string.format an supply the parameters + /// + /// string + /// string + /// object + /// formatted resource or a "string ###prefix.key### not found" + public static string GetFormattedString(string prefix, string key, object param) + { + return GetFormattedString(prefix + "." + key, param); + } + + /// + /// Get the resource for key, format with with string.format an supply the parameters + /// + /// string + /// object + /// formatted resource or a "string ###key### not found" + public static string GetFormattedString(string key, object param) + { + if (!Resources.TryGetValue(key, out var returnValue)) + { + return "string ###" + key + "### not found"; + } + + return string.Format(returnValue, param); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/LanguageChangedHandler.cs b/src/Greenshot.Base/Core/LanguageChangedHandler.cs similarity index 73% rename from GreenshotPlugin/Core/LanguageChangedHandler.cs rename to src/Greenshot.Base/Core/LanguageChangedHandler.cs index ab68cb6d4..c9b71532e 100644 --- a/GreenshotPlugin/Core/LanguageChangedHandler.cs +++ b/src/Greenshot.Base/Core/LanguageChangedHandler.cs @@ -1,6 +1,6 @@ -using System; - -namespace GreenshotPlugin.Core -{ - public delegate void LanguageChangedHandler(object sender, EventArgs e); +using System; + +namespace Greenshot.Base.Core +{ + public delegate void LanguageChangedHandler(object sender, EventArgs e); } \ No newline at end of file diff --git a/src/Greenshot.Base/Core/LanguageFile.cs b/src/Greenshot.Base/Core/LanguageFile.cs new file mode 100644 index 000000000..b9f8a57c4 --- /dev/null +++ b/src/Greenshot.Base/Core/LanguageFile.cs @@ -0,0 +1,80 @@ +using System; + +namespace Greenshot.Base.Core +{ + /// + /// This class contains the information about a language file + /// + public class LanguageFile : IEquatable + { + public string Description { get; set; } + + public string Ietf { get; set; } + + public Version Version { get; set; } + + public string LanguageGroup { get; set; } + + public string Filepath { get; set; } + + public string Prefix { get; set; } + + /// + /// Overload equals so we can delete a entry from a collection + /// + /// + /// + public bool Equals(LanguageFile other) + { + if (Prefix != null) + { + if (other != null && !Prefix.Equals(other.Prefix)) + { + return false; + } + } + else if (other?.Prefix != null) + { + return false; + } + + if (Ietf != null) + { + if (other != null && !Ietf.Equals(other.Ietf)) + { + return false; + } + } + else if (other?.Ietf != null) + { + return false; + } + + if (Version != null) + { + if (other != null && !Version.Equals(other.Version)) + { + return false; + } + } + else if (other != null && other.Version != null) + { + return false; + } + + if (Filepath != null) + { + if (other != null && !Filepath.Equals(other.Filepath)) + { + return false; + } + } + else if (other?.Filepath != null) + { + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/LogHelper.cs b/src/Greenshot.Base/Core/LogHelper.cs new file mode 100644 index 000000000..eb02423f8 --- /dev/null +++ b/src/Greenshot.Base/Core/LogHelper.cs @@ -0,0 +1,124 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.IO; +using System.Reflection; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using log4net; +using log4net.Appender; +using log4net.Config; +using log4net.Repository.Hierarchy; +using log4net.Util; + +namespace Greenshot.Base.Core +{ + /// + /// Initialize the logger + /// + public class LogHelper + { + private static bool _isLog4NetConfigured; + private const string InitMessage = "Greenshot initialization of log system failed"; + + public static bool IsInitialized => _isLog4NetConfigured; + + // Initialize Log4J + public static string InitializeLog4Net() + { + // Setup log4j, currently the file is called log4net.xml + foreach (var logName in new[] + { + "log4net.xml", @"App\Greenshot\log4net-portable.xml" + }) + { + string log4NetFilename = Path.Combine(Application.StartupPath, logName); + if (File.Exists(log4NetFilename)) + { + try + { + XmlConfigurator.Configure(new FileInfo(log4NetFilename)); + _isLog4NetConfigured = true; + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } + } + + // Fallback + if (!_isLog4NetConfigured) + { + try + { + Assembly assembly = typeof(LogHelper).Assembly; + using Stream stream = assembly.GetManifestResourceStream("GreenshotPlugin.log4net-embedded.xml"); + XmlConfigurator.Configure(stream); + _isLog4NetConfigured = true; + IniConfig.ForceIniInStartupPath(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, InitMessage, MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } + + if (_isLog4NetConfigured) + { + // Get the logfile name + try + { + if (((Hierarchy) LogManager.GetRepository()).Root.Appenders.Count > 0) + { + foreach (IAppender appender in ((Hierarchy) LogManager.GetRepository()).Root.Appenders) + { + var fileAppender = appender as FileAppender; + if (fileAppender != null) + { + return fileAppender.File; + } + } + } + } + catch + { + // ignored + } + } + + return null; + } + } + + /// + /// A simple helper class to support the logging to the AppData location + /// + public class SpecialFolderPatternConverter : PatternConverter + { + protected override void Convert(TextWriter writer, object state) + { + Environment.SpecialFolder specialFolder = (Environment.SpecialFolder) Enum.Parse(typeof(Environment.SpecialFolder), Option, true); + writer.Write(Environment.GetFolderPath(specialFolder)); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/NetworkHelper.cs b/src/Greenshot.Base/Core/NetworkHelper.cs similarity index 95% rename from GreenshotPlugin/Core/NetworkHelper.cs rename to src/Greenshot.Base/Core/NetworkHelper.cs index 3159c9dcc..21899e701 100644 --- a/GreenshotPlugin/Core/NetworkHelper.cs +++ b/src/Greenshot.Base/Core/NetworkHelper.cs @@ -1,726 +1,728 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using log4net; -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Globalization; -using System.IO; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; - -namespace GreenshotPlugin.Core -{ - /// - /// HTTP Method to make sure we have the correct method - /// - public enum HTTPMethod - { - GET, - POST, - PUT, - DELETE - }; - - /// - /// Description of NetworkHelper. - /// - public static class NetworkHelper - { - private static readonly ILog Log = LogManager.GetLogger(typeof(NetworkHelper)); - private static readonly CoreConfiguration Config = IniConfig.GetIniSection(); - - static NetworkHelper() - { - try - { - // Disable certificate checking - ServicePointManager.ServerCertificateValidationCallback += delegate { return true; }; - } - catch (Exception ex) - { - Log.Warn("An error has occurred while allowing self-signed certificates:", ex); - } - } - - /// - /// Download the uri into a memory stream, without catching exceptions - /// - /// Of an image - /// MemoryStream which is already seek-ed to 0 - public static MemoryStream GetAsMemoryStream(string url) - { - var request = CreateWebRequest(url); - using var response = (HttpWebResponse)request.GetResponse(); - var memoryStream = new MemoryStream(); - using (var responseStream = response.GetResponseStream()) - { - responseStream?.CopyTo(memoryStream); - // Make sure it can be used directly - memoryStream.Seek(0, SeekOrigin.Begin); - } - - return memoryStream; - } - - /// - /// Download the uri to Bitmap - /// - /// Of an image - /// Bitmap - public static Image DownloadImage(string url) - { - var extensions = new StringBuilder(); - foreach (var extension in ImageHelper.StreamConverters.Keys) - { - if (string.IsNullOrEmpty(extension)) - { - continue; - } - - extensions.AppendFormat(@"\.{0}|", extension); - } - - extensions.Length--; - - var imageUrlRegex = new Regex($@"(http|https)://.*(?{extensions})"); - var match = imageUrlRegex.Match(url); - try - { - using var memoryStream = GetAsMemoryStream(url); - try - { - return ImageHelper.FromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null); - } - catch (Exception) - { - // If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead. - string content; - using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true)) - { - content = streamReader.ReadLine(); - } - - if (string.IsNullOrEmpty(content)) - { - throw; - } - - match = imageUrlRegex.Match(content); - if (!match.Success) - { - throw; - } - - using var memoryStream2 = GetAsMemoryStream(match.Value); - return ImageHelper.FromStream(memoryStream2, match.Groups["extension"]?.Value); - } - } - catch (Exception e) - { - Log.Error("Problem downloading the image from: " + url, e); - } - - return null; - } - - /// - /// Helper method to create a web request with a lot of default settings - /// - /// string with uri to connect to - /// WebRequest - public static HttpWebRequest CreateWebRequest(string uri) - { - return CreateWebRequest(new Uri(uri)); - } - - /// - /// Helper method to create a web request with a lot of default settings - /// - /// string with uri to connect to - /// /// Method to use - /// WebRequest - public static HttpWebRequest CreateWebRequest(string uri, HTTPMethod method) - { - return CreateWebRequest(new Uri(uri), method); - } - - /// - /// Helper method to create a web request with a lot of default settings - /// - /// Uri with uri to connect to - /// Method to use - /// WebRequest - public static HttpWebRequest CreateWebRequest(Uri uri, HTTPMethod method) - { - var webRequest = CreateWebRequest(uri); - webRequest.Method = method.ToString(); - return webRequest; - } - - /// - /// Helper method to create a web request, eventually with proxy - /// - /// Uri with uri to connect to - /// WebRequest - public static HttpWebRequest CreateWebRequest(Uri uri) - { - var webRequest = (HttpWebRequest)WebRequest.Create(uri); - webRequest.Proxy = Config.UseProxy ? CreateProxy(uri) : null; - // Make sure the default credentials are available - webRequest.Credentials = CredentialCache.DefaultCredentials; - - // Allow redirect, this is usually needed so that we don't get a problem when a service moves - webRequest.AllowAutoRedirect = true; - // Set default timeouts - webRequest.Timeout = Config.WebRequestTimeout * 1000; - webRequest.ReadWriteTimeout = Config.WebRequestReadWriteTimeout * 1000; - return webRequest; - } - - /// - /// Create a IWebProxy Object which can be used to access the Internet - /// This method will check the configuration if the proxy is allowed to be used. - /// Usages can be found in the DownloadFavIcon or Jira and Confluence plugins - /// - /// - /// IWebProxy filled with all the proxy details or null if none is set/wanted - public static IWebProxy CreateProxy(Uri uri) - { - IWebProxy proxyToUse = null; - if (!Config.UseProxy) - { - return proxyToUse; - } - - proxyToUse = WebRequest.DefaultWebProxy; - if (proxyToUse != null) - { - proxyToUse.Credentials = CredentialCache.DefaultCredentials; - if (!Log.IsDebugEnabled) - { - return proxyToUse; - } - - // check the proxy for the Uri - if (!proxyToUse.IsBypassed(uri)) - { - var proxyUri = proxyToUse.GetProxy(uri); - if (proxyUri != null) - { - Log.Debug("Using proxy: " + proxyUri + " for " + uri); - } - else - { - Log.Debug("No proxy found!"); - } - } - else - { - Log.Debug("Proxy bypass for: " + uri); - } - } - else - { - Log.Debug("No proxy found!"); - } - - return proxyToUse; - } - - /// - /// UrlEncodes a string without the requirement for System.Web - /// - /// - /// - // [Obsolete("Use System.Uri.EscapeDataString instead")] - public static string UrlEncode(string text) - { - if (!string.IsNullOrEmpty(text)) - { - // System.Uri provides reliable parsing, but doesn't encode spaces. - return Uri.EscapeDataString(text).Replace("%20", "+"); - } - - return null; - } - - /// - /// A wrapper around the EscapeDataString, as the limit is 32766 characters - /// See: http://msdn.microsoft.com/en-us/library/system.uri.escapedatastring%28v=vs.110%29.aspx - /// - /// - /// escaped data string - public static string EscapeDataString(string text) - { - if (!string.IsNullOrEmpty(text)) - { - var result = new StringBuilder(); - int currentLocation = 0; - while (currentLocation < text.Length) - { - string process = text.Substring(currentLocation, Math.Min(16384, text.Length - currentLocation)); - result.Append(Uri.EscapeDataString(process)); - currentLocation += 16384; - } - - return result.ToString(); - } - - return null; - } - - /// - /// UrlDecodes a string without requiring System.Web - /// - /// String to decode. - /// decoded string - public static string UrlDecode(string text) - { - // pre-process for + sign space formatting since System.Uri doesn't handle it - // plus literals are encoded as %2b normally so this should be safe - text = text.Replace("+", " "); - return Uri.UnescapeDataString(text); - } - - /// - /// ParseQueryString without the requirement for System.Web - /// - /// - /// IDictionary string, string - public static IDictionary ParseQueryString(string queryString) - { - IDictionary parameters = new SortedDictionary(); - // remove anything other than query string from uri - if (queryString.Contains("?")) - { - queryString = queryString.Substring(queryString.IndexOf('?') + 1); - } - - foreach (string vp in Regex.Split(queryString, "&")) - { - if (string.IsNullOrEmpty(vp)) - { - continue; - } - - string[] singlePair = Regex.Split(vp, "="); - if (parameters.ContainsKey(singlePair[0])) - { - parameters.Remove(singlePair[0]); - } - - parameters.Add(singlePair[0], singlePair.Length == 2 ? singlePair[1] : string.Empty); - } - - return parameters; - } - - /// - /// Generate the query parameters - /// - /// the list of query parameters - /// a string with the query parameters - public static string GenerateQueryParameters(IDictionary queryParameters) - { - if (queryParameters == null || queryParameters.Count == 0) - { - return string.Empty; - } - - queryParameters = new SortedDictionary(queryParameters); - - var sb = new StringBuilder(); - foreach (string key in queryParameters.Keys) - { - sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode($"{queryParameters[key]}")); - } - - sb.Remove(sb.Length - 1, 1); - - return sb.ToString(); - } - - /// - /// Write Multipart Form Data directly to the HttpWebRequest - /// - /// HttpWebRequest to write the multipart form data to - /// Parameters to include in the multipart form data - public static void WriteMultipartFormData(HttpWebRequest webRequest, IDictionary postParameters) - { - string boundary = $"----------{Guid.NewGuid():N}"; - webRequest.ContentType = "multipart/form-data; boundary=" + boundary; - using Stream formDataStream = webRequest.GetRequestStream(); - WriteMultipartFormData(formDataStream, boundary, postParameters); - } - - /// - /// Write Multipart Form Data to a Stream, content-type should be set before this! - /// - /// Stream to write the multipart form data to - /// String boundary for the multipart/form-data - /// Parameters to include in the multipart form data - public static void WriteMultipartFormData(Stream formDataStream, string boundary, IDictionary postParameters) - { - bool needsClrf = false; - foreach (var param in postParameters) - { - // Add a CRLF to allow multiple parameters to be added. - // Skip it on the first parameter, add it to subsequent parameters. - if (needsClrf) - { - formDataStream.Write(Encoding.UTF8.GetBytes("\r\n"), 0, Encoding.UTF8.GetByteCount("\r\n")); - } - - needsClrf = true; - - if (param.Value is IBinaryContainer binaryContainer) - { - binaryContainer.WriteFormDataToStream(boundary, param.Key, formDataStream); - } - else - { - string postData = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{param.Key}\"\r\n\r\n{param.Value}"; - formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData)); - } - } - - // Add the end of the request. Start with a newline - string footer = "\r\n--" + boundary + "--\r\n"; - formDataStream.Write(Encoding.UTF8.GetBytes(footer), 0, Encoding.UTF8.GetByteCount(footer)); - } - - /// - /// Post content HttpWebRequest - /// - /// HttpWebRequest to write the multipart form data to - /// IDictionary with the headers - /// IBinaryContainer - public static void Post(HttpWebRequest webRequest, IDictionary headers, IBinaryContainer binaryContainer = null) - { - foreach (var header in headers) - { - switch (header.Key) - { - case "Content-Type": - webRequest.ContentType = header.Value as string; - break; - case "Accept": - webRequest.Accept = header.Value as string; - break; - default: - webRequest.Headers.Add(header.Key, Convert.ToString(header.Value)); - break; - } - } - if (!headers.ContainsKey("Content-Type")) - { - webRequest.ContentType = "application/octet-stream"; - } - - if (binaryContainer != null) - { - using var requestStream = webRequest.GetRequestStream(); - binaryContainer.WriteToStream(requestStream); - } - } - - /// - /// Post content HttpWebRequest - /// - /// HttpWebRequest to write the multipart form data to - /// IDictionary with the headers - /// string - public static void Post(HttpWebRequest webRequest, IDictionary headers, string jsonString) - { - if (headers != null) - { - foreach (var header in headers) - { - switch (header.Key) - { - case "Content-Type": - webRequest.ContentType = header.Value as string; - break; - case "Accept": - webRequest.Accept = header.Value as string; - break; - default: - webRequest.Headers.Add(header.Key, Convert.ToString(header.Value)); - break; - } - } - if (!headers.ContainsKey("Content-Type")) - { - webRequest.ContentType = "application/json"; - } - } - else - { - webRequest.ContentType = "application/json"; - } - - if (jsonString != null) - { - using var requestStream = webRequest.GetRequestStream(); - using var streamWriter = new StreamWriter(requestStream); - streamWriter.Write(jsonString); - } - } - - /// - /// Post the parameters "x-www-form-urlencoded" - /// - /// - /// - public static void UploadFormUrlEncoded(HttpWebRequest webRequest, IDictionary parameters) - { - webRequest.ContentType = "application/x-www-form-urlencoded"; - string urlEncoded = GenerateQueryParameters(parameters); - - byte[] data = Encoding.UTF8.GetBytes(urlEncoded); - using var requestStream = webRequest.GetRequestStream(); - requestStream.Write(data, 0, data.Length); - } - - /// - /// Log the headers of the WebResponse, if IsDebugEnabled - /// - /// WebResponse - private static void DebugHeaders(WebResponse response) - { - if (!Log.IsDebugEnabled) - { - return; - } - - Log.DebugFormat("Debug information on the response from {0} :", response.ResponseUri); - foreach (string key in response.Headers.AllKeys) - { - Log.DebugFormat("Reponse-header: {0}={1}", key, response.Headers[key]); - } - } - - /// - /// Process the web response. - /// - /// The request object. - /// The response data. - /// TODO: This method should handle the StatusCode better! - public static string GetResponseAsString(HttpWebRequest webRequest) - { - return GetResponseAsString(webRequest, false); - } - - /// - /// Read the response as string - /// - /// - /// string or null - private static string GetResponseAsString(HttpWebResponse response) - { - string responseData = null; - if (response == null) - { - return null; - } - - using (response) - { - Stream responseStream = response.GetResponseStream(); - if (responseStream != null) - { - using StreamReader reader = new StreamReader(responseStream, true); - responseData = reader.ReadToEnd(); - } - } - - return responseData; - } - - /// - /// - /// - /// - /// - /// - public static string GetResponseAsString(HttpWebRequest webRequest, bool alsoReturnContentOnError) - { - string responseData = null; - HttpWebResponse response = null; - bool isHttpError = false; - try - { - response = (HttpWebResponse)webRequest.GetResponse(); - Log.InfoFormat("Response status: {0}", response.StatusCode); - isHttpError = (int)response.StatusCode >= 300; - if (isHttpError) - { - Log.ErrorFormat("HTTP error {0}", response.StatusCode); - } - - DebugHeaders(response); - responseData = GetResponseAsString(response); - if (isHttpError) - { - Log.ErrorFormat("HTTP response {0}", responseData); - } - } - catch (WebException e) - { - response = (HttpWebResponse)e.Response; - HttpStatusCode statusCode = HttpStatusCode.Unused; - if (response != null) - { - statusCode = response.StatusCode; - Log.ErrorFormat("HTTP error {0}", statusCode); - string errorContent = GetResponseAsString(response); - if (alsoReturnContentOnError) - { - return errorContent; - } - - Log.ErrorFormat("Content: {0}", errorContent); - } - - Log.Error("WebException: ", e); - if (statusCode == HttpStatusCode.Unauthorized) - { - throw new UnauthorizedAccessException(e.Message); - } - - throw; - } - finally - { - if (response != null) - { - if (isHttpError) - { - Log.ErrorFormat("HTTP error {0} with content: {1}", response.StatusCode, responseData); - } - - response.Close(); - } - } - - return responseData; - } - - } - /// - /// This interface can be used to pass binary information around, like byte[] or Image - /// - public interface IBinaryContainer - { - void WriteFormDataToStream(string boundary, string name, Stream formDataStream); - void WriteToStream(Stream formDataStream); - string ToBase64String(Base64FormattingOptions formattingOptions); - byte[] ToByteArray(); - void Upload(HttpWebRequest webRequest); - - string ContentType { get; } - string Filename { get; set; } - } - - /// A container to supply surfaces to a Multi-part form data upload - /// - public class SurfaceContainer : IBinaryContainer - { - private readonly ISurface _surface; - private readonly SurfaceOutputSettings _outputSettings; - - public SurfaceContainer(ISurface surface, SurfaceOutputSettings outputSettings, string filename) - { - _surface = surface; - _outputSettings = outputSettings; - Filename = filename; - } - - /// - /// Create a Base64String from the Surface by saving it to a memory stream and converting it. - /// Should be avoided if possible, as this uses a lot of memory. - /// - /// string - public string ToBase64String(Base64FormattingOptions formattingOptions) - { - using MemoryStream stream = new MemoryStream(); - ImageOutput.SaveToStream(_surface, stream, _outputSettings); - return Convert.ToBase64String(stream.GetBuffer(), 0, (int)stream.Length, formattingOptions); - } - - /// - /// Create a byte[] from the image by saving it to a memory stream. - /// Should be avoided if possible, as this uses a lot of memory. - /// - /// byte[] - public byte[] ToByteArray() - { - using MemoryStream stream = new MemoryStream(); - ImageOutput.SaveToStream(_surface, stream, _outputSettings); - return stream.ToArray(); - } - - /// - /// Write Multipart Form Data directly to the HttpWebRequest response stream - /// - /// Multipart separator - /// Name of the thing - /// Stream to write to - public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) - { - // Add just the first part of this param, since we will write the file data directly to the Stream - string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n"; - - formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header)); - ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings); - } - - /// - /// A plain "write data to stream" - /// - /// - public void WriteToStream(Stream dataStream) - { - // Write the file data directly to the Stream, rather than serializing it to a string. - ImageOutput.SaveToStream(_surface, dataStream, _outputSettings); - } - - /// - /// Upload the Surface as image to the webrequest - /// - /// - public void Upload(HttpWebRequest webRequest) - { - webRequest.ContentType = ContentType; - using var requestStream = webRequest.GetRequestStream(); - WriteToStream(requestStream); - } - - public string ContentType => "image/" + _outputSettings.Format; - public string Filename { get; set; } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// HTTP Method to make sure we have the correct method + /// + public enum HTTPMethod + { + GET, + POST, + PUT, + DELETE + }; + + /// + /// Description of NetworkHelper. + /// + public static class NetworkHelper + { + private static readonly ILog Log = LogManager.GetLogger(typeof(NetworkHelper)); + private static readonly CoreConfiguration Config = IniConfig.GetIniSection(); + + static NetworkHelper() + { + try + { + // Disable certificate checking + ServicePointManager.ServerCertificateValidationCallback += delegate { return true; }; + } + catch (Exception ex) + { + Log.Warn("An error has occurred while allowing self-signed certificates:", ex); + } + } + + /// + /// Download the uri into a memory stream, without catching exceptions + /// + /// Of an image + /// MemoryStream which is already seek-ed to 0 + public static MemoryStream GetAsMemoryStream(string url) + { + var request = CreateWebRequest(url); + using var response = (HttpWebResponse) request.GetResponse(); + var memoryStream = new MemoryStream(); + using (var responseStream = response.GetResponseStream()) + { + responseStream?.CopyTo(memoryStream); + // Make sure it can be used directly + memoryStream.Seek(0, SeekOrigin.Begin); + } + + return memoryStream; + } + + /// + /// Download the uri to Bitmap + /// + /// Of an image + /// Bitmap + public static Image DownloadImage(string url) + { + var extensions = new StringBuilder(); + foreach (var extension in ImageHelper.StreamConverters.Keys) + { + if (string.IsNullOrEmpty(extension)) + { + continue; + } + + extensions.AppendFormat(@"\.{0}|", extension); + } + + extensions.Length--; + + var imageUrlRegex = new Regex($@"(http|https)://.*(?{extensions})"); + var match = imageUrlRegex.Match(url); + try + { + using var memoryStream = GetAsMemoryStream(url); + try + { + return ImageHelper.FromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null); + } + catch (Exception) + { + // If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead. + string content; + using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true)) + { + content = streamReader.ReadLine(); + } + + if (string.IsNullOrEmpty(content)) + { + throw; + } + + match = imageUrlRegex.Match(content); + if (!match.Success) + { + throw; + } + + using var memoryStream2 = GetAsMemoryStream(match.Value); + return ImageHelper.FromStream(memoryStream2, match.Groups["extension"]?.Value); + } + } + catch (Exception e) + { + Log.Error("Problem downloading the image from: " + url, e); + } + + return null; + } + + /// + /// Helper method to create a web request with a lot of default settings + /// + /// string with uri to connect to + /// WebRequest + public static HttpWebRequest CreateWebRequest(string uri) + { + return CreateWebRequest(new Uri(uri)); + } + + /// + /// Helper method to create a web request with a lot of default settings + /// + /// string with uri to connect to + /// /// Method to use + /// WebRequest + public static HttpWebRequest CreateWebRequest(string uri, HTTPMethod method) + { + return CreateWebRequest(new Uri(uri), method); + } + + /// + /// Helper method to create a web request with a lot of default settings + /// + /// Uri with uri to connect to + /// Method to use + /// WebRequest + public static HttpWebRequest CreateWebRequest(Uri uri, HTTPMethod method) + { + var webRequest = CreateWebRequest(uri); + webRequest.Method = method.ToString(); + return webRequest; + } + + /// + /// Helper method to create a web request, eventually with proxy + /// + /// Uri with uri to connect to + /// WebRequest + public static HttpWebRequest CreateWebRequest(Uri uri) + { + var webRequest = (HttpWebRequest) WebRequest.Create(uri); + webRequest.Proxy = Config.UseProxy ? CreateProxy(uri) : null; + // Make sure the default credentials are available + webRequest.Credentials = CredentialCache.DefaultCredentials; + + // Allow redirect, this is usually needed so that we don't get a problem when a service moves + webRequest.AllowAutoRedirect = true; + // Set default timeouts + webRequest.Timeout = Config.WebRequestTimeout * 1000; + webRequest.ReadWriteTimeout = Config.WebRequestReadWriteTimeout * 1000; + return webRequest; + } + + /// + /// Create a IWebProxy Object which can be used to access the Internet + /// This method will check the configuration if the proxy is allowed to be used. + /// Usages can be found in the DownloadFavIcon or Jira and Confluence plugins + /// + /// + /// IWebProxy filled with all the proxy details or null if none is set/wanted + public static IWebProxy CreateProxy(Uri uri) + { + IWebProxy proxyToUse = null; + if (!Config.UseProxy) + { + return proxyToUse; + } + + proxyToUse = WebRequest.DefaultWebProxy; + if (proxyToUse != null) + { + proxyToUse.Credentials = CredentialCache.DefaultCredentials; + if (!Log.IsDebugEnabled) + { + return proxyToUse; + } + + // check the proxy for the Uri + if (!proxyToUse.IsBypassed(uri)) + { + var proxyUri = proxyToUse.GetProxy(uri); + if (proxyUri != null) + { + Log.Debug("Using proxy: " + proxyUri + " for " + uri); + } + else + { + Log.Debug("No proxy found!"); + } + } + else + { + Log.Debug("Proxy bypass for: " + uri); + } + } + else + { + Log.Debug("No proxy found!"); + } + + return proxyToUse; + } + + /// + /// UrlEncodes a string without the requirement for System.Web + /// + /// + /// + // [Obsolete("Use System.Uri.EscapeDataString instead")] + public static string UrlEncode(string text) + { + if (!string.IsNullOrEmpty(text)) + { + // System.Uri provides reliable parsing, but doesn't encode spaces. + return Uri.EscapeDataString(text).Replace("%20", "+"); + } + + return null; + } + + /// + /// A wrapper around the EscapeDataString, as the limit is 32766 characters + /// See: http://msdn.microsoft.com/en-us/library/system.uri.escapedatastring%28v=vs.110%29.aspx + /// + /// + /// escaped data string + public static string EscapeDataString(string text) + { + if (!string.IsNullOrEmpty(text)) + { + var result = new StringBuilder(); + int currentLocation = 0; + while (currentLocation < text.Length) + { + string process = text.Substring(currentLocation, Math.Min(16384, text.Length - currentLocation)); + result.Append(Uri.EscapeDataString(process)); + currentLocation += 16384; + } + + return result.ToString(); + } + + return null; + } + + /// + /// UrlDecodes a string without requiring System.Web + /// + /// String to decode. + /// decoded string + public static string UrlDecode(string text) + { + // pre-process for + sign space formatting since System.Uri doesn't handle it + // plus literals are encoded as %2b normally so this should be safe + text = text.Replace("+", " "); + return Uri.UnescapeDataString(text); + } + + /// + /// ParseQueryString without the requirement for System.Web + /// + /// + /// IDictionary string, string + public static IDictionary ParseQueryString(string queryString) + { + IDictionary parameters = new SortedDictionary(); + // remove anything other than query string from uri + if (queryString.Contains("?")) + { + queryString = queryString.Substring(queryString.IndexOf('?') + 1); + } + + foreach (string vp in Regex.Split(queryString, "&")) + { + if (string.IsNullOrEmpty(vp)) + { + continue; + } + + string[] singlePair = Regex.Split(vp, "="); + if (parameters.ContainsKey(singlePair[0])) + { + parameters.Remove(singlePair[0]); + } + + parameters.Add(singlePair[0], singlePair.Length == 2 ? singlePair[1] : string.Empty); + } + + return parameters; + } + + /// + /// Generate the query parameters + /// + /// the list of query parameters + /// a string with the query parameters + public static string GenerateQueryParameters(IDictionary queryParameters) + { + if (queryParameters == null || queryParameters.Count == 0) + { + return string.Empty; + } + + queryParameters = new SortedDictionary(queryParameters); + + var sb = new StringBuilder(); + foreach (string key in queryParameters.Keys) + { + sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode($"{queryParameters[key]}")); + } + + sb.Remove(sb.Length - 1, 1); + + return sb.ToString(); + } + + /// + /// Write Multipart Form Data directly to the HttpWebRequest + /// + /// HttpWebRequest to write the multipart form data to + /// Parameters to include in the multipart form data + public static void WriteMultipartFormData(HttpWebRequest webRequest, IDictionary postParameters) + { + string boundary = $"----------{Guid.NewGuid():N}"; + webRequest.ContentType = "multipart/form-data; boundary=" + boundary; + using Stream formDataStream = webRequest.GetRequestStream(); + WriteMultipartFormData(formDataStream, boundary, postParameters); + } + + /// + /// Write Multipart Form Data to a Stream, content-type should be set before this! + /// + /// Stream to write the multipart form data to + /// String boundary for the multipart/form-data + /// Parameters to include in the multipart form data + public static void WriteMultipartFormData(Stream formDataStream, string boundary, IDictionary postParameters) + { + bool needsClrf = false; + foreach (var param in postParameters) + { + // Add a CRLF to allow multiple parameters to be added. + // Skip it on the first parameter, add it to subsequent parameters. + if (needsClrf) + { + formDataStream.Write(Encoding.UTF8.GetBytes("\r\n"), 0, Encoding.UTF8.GetByteCount("\r\n")); + } + + needsClrf = true; + + if (param.Value is IBinaryContainer binaryContainer) + { + binaryContainer.WriteFormDataToStream(boundary, param.Key, formDataStream); + } + else + { + string postData = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{param.Key}\"\r\n\r\n{param.Value}"; + formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, Encoding.UTF8.GetByteCount(postData)); + } + } + + // Add the end of the request. Start with a newline + string footer = "\r\n--" + boundary + "--\r\n"; + formDataStream.Write(Encoding.UTF8.GetBytes(footer), 0, Encoding.UTF8.GetByteCount(footer)); + } + + /// + /// Post content HttpWebRequest + /// + /// HttpWebRequest to write the multipart form data to + /// IDictionary with the headers + /// IBinaryContainer + public static void Post(HttpWebRequest webRequest, IDictionary headers, IBinaryContainer binaryContainer = null) + { + foreach (var header in headers) + { + switch (header.Key) + { + case "Content-Type": + webRequest.ContentType = header.Value as string; + break; + case "Accept": + webRequest.Accept = header.Value as string; + break; + default: + webRequest.Headers.Add(header.Key, Convert.ToString(header.Value)); + break; + } + } + + if (!headers.ContainsKey("Content-Type")) + { + webRequest.ContentType = "application/octet-stream"; + } + + if (binaryContainer != null) + { + using var requestStream = webRequest.GetRequestStream(); + binaryContainer.WriteToStream(requestStream); + } + } + + /// + /// Post content HttpWebRequest + /// + /// HttpWebRequest to write the multipart form data to + /// IDictionary with the headers + /// string + public static void Post(HttpWebRequest webRequest, IDictionary headers, string jsonString) + { + if (headers != null) + { + foreach (var header in headers) + { + switch (header.Key) + { + case "Content-Type": + webRequest.ContentType = header.Value as string; + break; + case "Accept": + webRequest.Accept = header.Value as string; + break; + default: + webRequest.Headers.Add(header.Key, Convert.ToString(header.Value)); + break; + } + } + + if (!headers.ContainsKey("Content-Type")) + { + webRequest.ContentType = "application/json"; + } + } + else + { + webRequest.ContentType = "application/json"; + } + + if (jsonString != null) + { + using var requestStream = webRequest.GetRequestStream(); + using var streamWriter = new StreamWriter(requestStream); + streamWriter.Write(jsonString); + } + } + + /// + /// Post the parameters "x-www-form-urlencoded" + /// + /// + /// + public static void UploadFormUrlEncoded(HttpWebRequest webRequest, IDictionary parameters) + { + webRequest.ContentType = "application/x-www-form-urlencoded"; + string urlEncoded = GenerateQueryParameters(parameters); + + byte[] data = Encoding.UTF8.GetBytes(urlEncoded); + using var requestStream = webRequest.GetRequestStream(); + requestStream.Write(data, 0, data.Length); + } + + /// + /// Log the headers of the WebResponse, if IsDebugEnabled + /// + /// WebResponse + private static void DebugHeaders(WebResponse response) + { + if (!Log.IsDebugEnabled) + { + return; + } + + Log.DebugFormat("Debug information on the response from {0} :", response.ResponseUri); + foreach (string key in response.Headers.AllKeys) + { + Log.DebugFormat("Reponse-header: {0}={1}", key, response.Headers[key]); + } + } + + /// + /// Process the web response. + /// + /// The request object. + /// The response data. + /// TODO: This method should handle the StatusCode better! + public static string GetResponseAsString(HttpWebRequest webRequest) + { + return GetResponseAsString(webRequest, false); + } + + /// + /// Read the response as string + /// + /// + /// string or null + private static string GetResponseAsString(HttpWebResponse response) + { + string responseData = null; + if (response == null) + { + return null; + } + + using (response) + { + Stream responseStream = response.GetResponseStream(); + if (responseStream != null) + { + using StreamReader reader = new StreamReader(responseStream, true); + responseData = reader.ReadToEnd(); + } + } + + return responseData; + } + + /// + /// + /// + /// + /// + /// + public static string GetResponseAsString(HttpWebRequest webRequest, bool alsoReturnContentOnError) + { + string responseData = null; + HttpWebResponse response = null; + bool isHttpError = false; + try + { + response = (HttpWebResponse) webRequest.GetResponse(); + Log.InfoFormat("Response status: {0}", response.StatusCode); + isHttpError = (int) response.StatusCode >= 300; + if (isHttpError) + { + Log.ErrorFormat("HTTP error {0}", response.StatusCode); + } + + DebugHeaders(response); + responseData = GetResponseAsString(response); + if (isHttpError) + { + Log.ErrorFormat("HTTP response {0}", responseData); + } + } + catch (WebException e) + { + response = (HttpWebResponse) e.Response; + HttpStatusCode statusCode = HttpStatusCode.Unused; + if (response != null) + { + statusCode = response.StatusCode; + Log.ErrorFormat("HTTP error {0}", statusCode); + string errorContent = GetResponseAsString(response); + if (alsoReturnContentOnError) + { + return errorContent; + } + + Log.ErrorFormat("Content: {0}", errorContent); + } + + Log.Error("WebException: ", e); + if (statusCode == HttpStatusCode.Unauthorized) + { + throw new UnauthorizedAccessException(e.Message); + } + + throw; + } + finally + { + if (response != null) + { + if (isHttpError) + { + Log.ErrorFormat("HTTP error {0} with content: {1}", response.StatusCode, responseData); + } + + response.Close(); + } + } + + return responseData; + } + } + + /// + /// This interface can be used to pass binary information around, like byte[] or Image + /// + public interface IBinaryContainer + { + void WriteFormDataToStream(string boundary, string name, Stream formDataStream); + void WriteToStream(Stream formDataStream); + string ToBase64String(Base64FormattingOptions formattingOptions); + byte[] ToByteArray(); + void Upload(HttpWebRequest webRequest); + + string ContentType { get; } + string Filename { get; set; } + } + + /// A container to supply surfaces to a Multi-part form data upload + /// + public class SurfaceContainer : IBinaryContainer + { + private readonly ISurface _surface; + private readonly SurfaceOutputSettings _outputSettings; + + public SurfaceContainer(ISurface surface, SurfaceOutputSettings outputSettings, string filename) + { + _surface = surface; + _outputSettings = outputSettings; + Filename = filename; + } + + /// + /// Create a Base64String from the Surface by saving it to a memory stream and converting it. + /// Should be avoided if possible, as this uses a lot of memory. + /// + /// string + public string ToBase64String(Base64FormattingOptions formattingOptions) + { + using MemoryStream stream = new MemoryStream(); + ImageOutput.SaveToStream(_surface, stream, _outputSettings); + return Convert.ToBase64String(stream.GetBuffer(), 0, (int) stream.Length, formattingOptions); + } + + /// + /// Create a byte[] from the image by saving it to a memory stream. + /// Should be avoided if possible, as this uses a lot of memory. + /// + /// byte[] + public byte[] ToByteArray() + { + using MemoryStream stream = new MemoryStream(); + ImageOutput.SaveToStream(_surface, stream, _outputSettings); + return stream.ToArray(); + } + + /// + /// Write Multipart Form Data directly to the HttpWebRequest response stream + /// + /// Multipart separator + /// Name of the thing + /// Stream to write to + public void WriteFormDataToStream(string boundary, string name, Stream formDataStream) + { + // Add just the first part of this param, since we will write the file data directly to the Stream + string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n"; + + formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header)); + ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings); + } + + /// + /// A plain "write data to stream" + /// + /// + public void WriteToStream(Stream dataStream) + { + // Write the file data directly to the Stream, rather than serializing it to a string. + ImageOutput.SaveToStream(_surface, dataStream, _outputSettings); + } + + /// + /// Upload the Surface as image to the webrequest + /// + /// + public void Upload(HttpWebRequest webRequest) + { + webRequest.ContentType = ContentType; + using var requestStream = webRequest.GetRequestStream(); + WriteToStream(requestStream); + } + + public string ContentType => "image/" + _outputSettings.Format; + public string Filename { get; set; } + } } \ No newline at end of file diff --git a/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs b/src/Greenshot.Base/Core/OAuth/LocalJsonReceiver.cs similarity index 89% rename from GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs rename to src/Greenshot.Base/Core/OAuth/LocalJsonReceiver.cs index 7b363b2fa..c99221d09 100644 --- a/GreenshotPlugin/Core/OAuth/LocalJsonReceiver.cs +++ b/src/Greenshot.Base/Core/OAuth/LocalJsonReceiver.cs @@ -30,7 +30,7 @@ using System.Threading; using log4net; using Newtonsoft.Json; -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// OAuth 2.0 verification code receiver that runs a local server on a free port @@ -49,15 +49,19 @@ namespace GreenshotPlugin.Core.OAuth public string ListeningUrlFormat { get; set; } = "http://localhost:{0}/authorize/"; private string _listeningUri; + /// /// The URL where the server is listening /// - public string ListeningUri { - get { + public string ListeningUri + { + get + { if (string.IsNullOrEmpty(_listeningUri)) { _listeningUri = string.Format(ListeningUrlFormat, GetRandomUnusedPort()); } + return _listeningUri; } set => _listeningUri = value; @@ -66,11 +70,7 @@ namespace GreenshotPlugin.Core.OAuth /// /// This action is called when the URI must be opened, default is just to run Process.Start /// - public Action OpenUriAction - { - set; - get; - } = authorizationUrl => + public Action OpenUriAction { set; get; } = authorizationUrl => { Log.DebugFormat("Open a browser with: {0}", authorizationUrl); using var process = Process.Start(authorizationUrl); @@ -86,23 +86,29 @@ namespace GreenshotPlugin.Core.OAuth /// /// OAuth2Settings /// Dictionary with values - public IDictionary ReceiveCode(OAuth2Settings oauth2Settings) { + public IDictionary ReceiveCode(OAuth2Settings oauth2Settings) + { using var listener = new HttpListener(); // Make sure the port is stored in the state, so the website can process this. oauth2Settings.State = new Uri(ListeningUri).Port.ToString(); listener.Prefixes.Add(ListeningUri); - try { + try + { listener.Start(); _ready.Reset(); listener.BeginGetContext(ListenerCallback, listener); OpenUriAction(oauth2Settings.FormattedAuthUrl); _ready.WaitOne(Timeout, true); - } catch (Exception) { + } + catch (Exception) + { // Make sure we can clean up, also if the thead is aborted _ready.Set(); throw; - } finally { + } + finally + { listener.Close(); } @@ -113,11 +119,13 @@ namespace GreenshotPlugin.Core.OAuth /// Handle a connection async, this allows us to break the waiting /// /// IAsyncResult - private void ListenerCallback(IAsyncResult result) { - HttpListener listener = (HttpListener)result.AsyncState; + private void ListenerCallback(IAsyncResult result) + { + HttpListener listener = (HttpListener) result.AsyncState; //If not listening return immediately as this method is called one last time after Close() - if (!listener.IsListening) { + if (!listener.IsListening) + { return; } @@ -178,12 +186,16 @@ namespace GreenshotPlugin.Core.OAuth /// Returns a random, unused port. /// /// port to use - private static int GetRandomUnusedPort() { + private static int GetRandomUnusedPort() + { var listener = new TcpListener(IPAddress.Loopback, 0); - try { + try + { listener.Start(); - return ((IPEndPoint)listener.LocalEndpoint).Port; - } finally { + return ((IPEndPoint) listener.LocalEndpoint).Port; + } + finally + { listener.Stop(); } } diff --git a/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs b/src/Greenshot.Base/Core/OAuth/LocalServerCodeReceiver.cs similarity index 84% rename from GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs rename to src/Greenshot.Base/Core/OAuth/LocalServerCodeReceiver.cs index a4915e8b6..702e3f7fe 100644 --- a/GreenshotPlugin/Core/OAuth/LocalServerCodeReceiver.cs +++ b/src/Greenshot.Base/Core/OAuth/LocalServerCodeReceiver.cs @@ -29,13 +29,14 @@ using System.Text; using System.Threading; using log4net; -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// OAuth 2.0 verification code receiver that runs a local server on a free port /// and waits for a call with the authorization verification code. /// - public class LocalServerCodeReceiver { + public class LocalServerCodeReceiver + { private static readonly ILog Log = LogManager.GetLogger(typeof(LocalServerCodeReceiver)); private readonly ManualResetEvent _ready = new ManualResetEvent(true); @@ -66,12 +67,16 @@ Greenshot received information from CloudServiceName. You can close this browser "; private string _redirectUri; + /// /// The URL to redirect to /// - protected string RedirectUri { - get { - if (!string.IsNullOrEmpty(_redirectUri)) { + protected string RedirectUri + { + get + { + if (!string.IsNullOrEmpty(_redirectUri)) + { return _redirectUri; } @@ -89,13 +94,16 @@ Greenshot received information from CloudServiceName. You can close this browser /// /// /// Dictionary with values - public IDictionary ReceiveCode(OAuth2Settings oauth2Settings) { + public IDictionary ReceiveCode(OAuth2Settings oauth2Settings) + { // Set the redirect URL on the settings oauth2Settings.RedirectUrl = RedirectUri; _cloudServiceName = oauth2Settings.CloudServiceName; - using (var listener = new HttpListener()) { + using (var listener = new HttpListener()) + { listener.Prefixes.Add(oauth2Settings.RedirectUrl); - try { + try + { listener.Start(); // Get the formatted FormattedAuthUrl @@ -107,18 +115,24 @@ Greenshot received information from CloudServiceName. You can close this browser var context = listener.BeginGetContext(ListenerCallback, listener); _ready.Reset(); - while (!context.AsyncWaitHandle.WaitOne(1000, true)) { + while (!context.AsyncWaitHandle.WaitOne(1000, true)) + { Log.Debug("Waiting for response"); } - } catch (Exception) { + } + catch (Exception) + { // Make sure we can clean up, also if the thead is aborted _ready.Set(); throw; - } finally { + } + finally + { _ready.WaitOne(); listener.Close(); } } + return _returnValues; } @@ -126,11 +140,13 @@ Greenshot received information from CloudServiceName. You can close this browser /// Handle a connection async, this allows us to break the waiting /// /// IAsyncResult - private void ListenerCallback(IAsyncResult result) { - HttpListener listener = (HttpListener)result.AsyncState; + private void ListenerCallback(IAsyncResult result) + { + HttpListener listener = (HttpListener) result.AsyncState; //If not listening return immediately as this method is called one last time after Close() - if (!listener.IsListening) { + if (!listener.IsListening) + { return; } @@ -140,11 +156,13 @@ Greenshot received information from CloudServiceName. You can close this browser // Handle request HttpListenerRequest request = context.Request; - try { + try + { NameValueCollection nameValueCollection = request.QueryString; // Get response object. - using (HttpListenerResponse response = context.Response) { + using (HttpListenerResponse response = context.Response) + { // Write a "close" response. byte[] buffer = Encoding.UTF8.GetBytes(ClosePageResponse.Replace("CloudServiceName", _cloudServiceName)); // Write to response stream. @@ -154,15 +172,20 @@ Greenshot received information from CloudServiceName. You can close this browser } // Create a new response URL with a dictionary that contains all the response query parameters. - foreach (var name in nameValueCollection.AllKeys) { - if (!_returnValues.ContainsKey(name)) { + foreach (var name in nameValueCollection.AllKeys) + { + if (!_returnValues.ContainsKey(name)) + { _returnValues.Add(name, nameValueCollection[name]); } } - } catch (Exception) { + } + catch (Exception) + { context.Response.OutputStream.Close(); throw; } + _ready.Set(); } @@ -170,12 +193,16 @@ Greenshot received information from CloudServiceName. You can close this browser /// Returns a random, unused port. /// /// port to use - private static int GetRandomUnusedPort() { + private static int GetRandomUnusedPort() + { var listener = new TcpListener(IPAddress.Loopback, 0); - try { + try + { listener.Start(); - return ((IPEndPoint)listener.LocalEndpoint).Port; - } finally { + return ((IPEndPoint) listener.LocalEndpoint).Port; + } + finally + { listener.Stop(); } } diff --git a/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs b/src/Greenshot.Base/Core/OAuth/OAuth2AuthorizeMode.cs similarity index 76% rename from GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs rename to src/Greenshot.Base/Core/OAuth/OAuth2AuthorizeMode.cs index 98d4515f9..1d761fc96 100644 --- a/GreenshotPlugin/Core/OAuth/OAuth2AuthorizeMode.cs +++ b/src/Greenshot.Base/Core/OAuth/OAuth2AuthorizeMode.cs @@ -19,15 +19,16 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// Specify the authorize mode that is used to get the token from the cloud service. /// - public enum OAuth2AuthorizeMode { - Unknown, // Will give an exception, caller needs to specify another value - LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener - JsonReceiver, // Will start a local HttpListener and wait for a Json post + public enum OAuth2AuthorizeMode + { + Unknown, // Will give an exception, caller needs to specify another value + LocalServer, // Will specify a redirect URL to http://localhost:port/authorize, while having a HttpListener + JsonReceiver, // Will start a local HttpListener and wait for a Json post EmbeddedBrowser // Will open into an embedded _browser (OAuthLoginForm), and catch the redirect } } \ No newline at end of file diff --git a/src/Greenshot.Base/Core/OAuth/OAuth2Helper.cs b/src/Greenshot.Base/Core/OAuth/OAuth2Helper.cs new file mode 100644 index 000000000..e5d009b96 --- /dev/null +++ b/src/Greenshot.Base/Core/OAuth/OAuth2Helper.cs @@ -0,0 +1,441 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2020 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Net; +using Greenshot.Base.Controls; + +namespace Greenshot.Base.Core.OAuth +{ + /// + /// Code to simplify OAuth 2 + /// + public static class OAuth2Helper + { + private const string RefreshToken = "refresh_token"; + private const string AccessToken = "access_token"; + private const string Code = "code"; + private const string Error = "error"; + private const string ClientId = "client_id"; + private const string ClientSecret = "client_secret"; + private const string GrantType = "grant_type"; + private const string AuthorizationCode = "authorization_code"; + private const string RedirectUri = "redirect_uri"; + private const string ExpiresIn = "expires_in"; + + /// + /// Generate an OAuth 2 Token by using the supplied code + /// + /// OAuth2Settings to update with the information that was retrieved + public static void GenerateRefreshToken(OAuth2Settings settings) + { + IDictionary data = new Dictionary + { + // Use the returned code to get a refresh code + { + Code, settings.Code + }, + { + ClientId, settings.ClientId + }, + { + ClientSecret, settings.ClientSecret + }, + { + GrantType, AuthorizationCode + } + }; + foreach (string key in settings.AdditionalAttributes.Keys) + { + data.Add(key, settings.AdditionalAttributes[key]); + } + + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); + NetworkHelper.UploadFormUrlEncoded(webRequest, data); + string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); + + IDictionary refreshTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); + if (refreshTokenResult.ContainsKey("error")) + { + if (refreshTokenResult.ContainsKey("error_description")) + { + throw new Exception($"{refreshTokenResult["error"]} - {refreshTokenResult["error_description"]}"); + } + + throw new Exception((string) refreshTokenResult["error"]); + } + + // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp + // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", + // "expires_in":3920, + // "token_type":"Bearer", + // "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" + if (refreshTokenResult.ContainsKey(AccessToken)) + { + settings.AccessToken = (string) refreshTokenResult[AccessToken]; + } + + if (refreshTokenResult.ContainsKey(RefreshToken)) + { + settings.RefreshToken = (string) refreshTokenResult[RefreshToken]; + } + + if (refreshTokenResult.ContainsKey(ExpiresIn)) + { + object seconds = refreshTokenResult[ExpiresIn]; + if (seconds != null) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double) seconds); + } + } + + settings.Code = null; + } + + /// + /// Used to update the settings with the callback information + /// + /// OAuth2Settings + /// IDictionary + /// true if the access token is already in the callback + private static bool UpdateFromCallback(OAuth2Settings settings, IDictionary callbackParameters) + { + if (!callbackParameters.ContainsKey(AccessToken)) + { + return false; + } + + if (callbackParameters.ContainsKey(RefreshToken)) + { + // Refresh the refresh token :) + settings.RefreshToken = callbackParameters[RefreshToken]; + } + + if (callbackParameters.ContainsKey(ExpiresIn)) + { + var expiresIn = callbackParameters[ExpiresIn]; + settings.AccessTokenExpires = DateTimeOffset.MaxValue; + if (expiresIn != null) + { + if (double.TryParse(expiresIn, out var seconds)) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); + } + } + } + + settings.AccessToken = callbackParameters[AccessToken]; + return true; + } + + /// + /// Go out and retrieve a new access token via refresh-token with the TokenUrl in the settings + /// Will update the access token, refresh token, expire date + /// + /// + public static void GenerateAccessToken(OAuth2Settings settings) + { + IDictionary data = new Dictionary + { + { + RefreshToken, settings.RefreshToken + }, + { + ClientId, settings.ClientId + }, + { + ClientSecret, settings.ClientSecret + }, + { + GrantType, RefreshToken + } + }; + foreach (string key in settings.AdditionalAttributes.Keys) + { + data.Add(key, settings.AdditionalAttributes[key]); + } + + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(settings.TokenUrl, HTTPMethod.POST); + NetworkHelper.UploadFormUrlEncoded(webRequest, data); + string accessTokenJsonResult = NetworkHelper.GetResponseAsString(webRequest, true); + + // gives as described here: https://developers.google.com/identity/protocols/OAuth2InstalledApp + // "access_token":"1/fFAGRNJru1FTz70BzhT3Zg", + // "expires_in":3920, + // "token_type":"Bearer", + + IDictionary accessTokenResult = JSONHelper.JsonDecode(accessTokenJsonResult); + if (accessTokenResult.ContainsKey("error")) + { + if ("invalid_grant" == (string) accessTokenResult["error"]) + { + // Refresh token has also expired, we need a new one! + settings.RefreshToken = null; + settings.AccessToken = null; + settings.AccessTokenExpires = DateTimeOffset.MinValue; + settings.Code = null; + return; + } + + if (accessTokenResult.ContainsKey("error_description")) + { + throw new Exception($"{accessTokenResult["error"]} - {accessTokenResult["error_description"]}"); + } + + throw new Exception((string) accessTokenResult["error"]); + } + + if (accessTokenResult.ContainsKey(AccessToken)) + { + settings.AccessToken = (string) accessTokenResult[AccessToken]; + settings.AccessTokenExpires = DateTimeOffset.MaxValue; + } + + if (accessTokenResult.ContainsKey(RefreshToken)) + { + // Refresh the refresh token :) + settings.RefreshToken = (string) accessTokenResult[RefreshToken]; + } + + if (accessTokenResult.ContainsKey(ExpiresIn)) + { + object seconds = accessTokenResult[ExpiresIn]; + if (seconds != null) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds((double) seconds); + } + } + } + + /// + /// Authorize by using the mode specified in the settings + /// + /// OAuth2Settings + /// false if it was canceled, true if it worked, exception if not + public static bool Authorize(OAuth2Settings settings) + { + var completed = settings.AuthorizeMode switch + { + OAuth2AuthorizeMode.LocalServer => AuthorizeViaLocalServer(settings), + OAuth2AuthorizeMode.EmbeddedBrowser => AuthorizeViaEmbeddedBrowser(settings), + OAuth2AuthorizeMode.JsonReceiver => AuthorizeViaDefaultBrowser(settings), + _ => throw new NotImplementedException($"Authorize mode '{settings.AuthorizeMode}' is not 'yet' implemented."), + }; + return completed; + } + + /// + /// Authorize via the default browser, via the Greenshot website. + /// It will wait for a Json post. + /// If this works, return the code + /// + /// OAuth2Settings with the Auth / Token url etc + /// true if completed, false if canceled + private static bool AuthorizeViaDefaultBrowser(OAuth2Settings settings) + { + var codeReceiver = new LocalJsonReceiver(); + IDictionary result = codeReceiver.ReceiveCode(settings); + + if (result == null || result.Count == 0) + { + return false; + } + + foreach (var key in result.Keys) + { + switch (key) + { + case AccessToken: + settings.AccessToken = result[key]; + break; + case ExpiresIn: + if (int.TryParse(result[key], out var seconds)) + { + settings.AccessTokenExpires = DateTimeOffset.Now.AddSeconds(seconds); + } + + break; + case RefreshToken: + settings.RefreshToken = result[key]; + break; + } + } + + if (result.TryGetValue("error", out var error)) + { + if (result.TryGetValue("error_description", out var errorDescription)) + { + throw new Exception(errorDescription); + } + + if ("access_denied" == error) + { + throw new UnauthorizedAccessException("Access denied"); + } + + throw new Exception(error); + } + + if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) + { + settings.Code = code; + GenerateRefreshToken(settings); + return !string.IsNullOrEmpty(settings.AccessToken); + } + + return true; + } + + /// + /// Authorize via an embedded browser + /// If this works, return the code + /// + /// OAuth2Settings with the Auth / Token url etc + /// true if completed, false if canceled + private static bool AuthorizeViaEmbeddedBrowser(OAuth2Settings settings) + { + if (string.IsNullOrEmpty(settings.CloudServiceName)) + { + throw new ArgumentNullException(nameof(settings.CloudServiceName)); + } + + if (settings.BrowserSize == Size.Empty) + { + throw new ArgumentNullException(nameof(settings.BrowserSize)); + } + + OAuthLoginForm loginForm = new OAuthLoginForm($"Authorize {settings.CloudServiceName}", settings.BrowserSize, settings.FormattedAuthUrl, settings.RedirectUrl); + loginForm.ShowDialog(); + if (!loginForm.IsOk) return false; + if (loginForm.CallbackParameters.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) + { + settings.Code = code; + GenerateRefreshToken(settings); + return true; + } + + return UpdateFromCallback(settings, loginForm.CallbackParameters); + } + + /// + /// Authorize via a local server by using the LocalServerCodeReceiver + /// If this works, return the code + /// + /// OAuth2Settings with the Auth / Token url etc + /// true if completed + private static bool AuthorizeViaLocalServer(OAuth2Settings settings) + { + var codeReceiver = new LocalServerCodeReceiver(); + IDictionary result = codeReceiver.ReceiveCode(settings); + + if (result.TryGetValue(Code, out var code) && !string.IsNullOrEmpty(code)) + { + settings.Code = code; + GenerateRefreshToken(settings); + return true; + } + + if (result.TryGetValue("error", out var error)) + { + if (result.TryGetValue("error_description", out var errorDescription)) + { + throw new Exception(errorDescription); + } + + if ("access_denied" == error) + { + throw new UnauthorizedAccessException("Access denied"); + } + + throw new Exception(error); + } + + return false; + } + + /// + /// Simple helper to add the Authorization Bearer header + /// + /// WebRequest + /// OAuth2Settings + public static void AddOAuth2Credentials(HttpWebRequest webRequest, OAuth2Settings settings) + { + if (!string.IsNullOrEmpty(settings.AccessToken)) + { + webRequest.Headers.Add("Authorization", "Bearer " + settings.AccessToken); + } + } + + /// + /// Check and authenticate or refresh tokens + /// + /// OAuth2Settings + public static void CheckAndAuthenticateOrRefresh(OAuth2Settings settings) + { + // Get Refresh / Access token + if (string.IsNullOrEmpty(settings.RefreshToken)) + { + if (!Authorize(settings)) + { + throw new Exception("Authentication cancelled"); + } + } + + if (settings.IsAccessTokenExpired) + { + GenerateAccessToken(settings); + // Get Refresh / Access token + if (string.IsNullOrEmpty(settings.RefreshToken)) + { + if (!Authorize(settings)) + { + throw new Exception("Authentication cancelled"); + } + + GenerateAccessToken(settings); + } + } + + if (settings.IsAccessTokenExpired) + { + throw new Exception("Authentication failed"); + } + } + + /// + /// CreateWebRequest ready for OAuth 2 access + /// + /// HTTPMethod + /// + /// OAuth2Settings + /// HttpWebRequest + public static HttpWebRequest CreateOAuth2WebRequest(HTTPMethod method, string url, OAuth2Settings settings) + { + CheckAndAuthenticateOrRefresh(settings); + + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, method); + AddOAuth2Credentials(webRequest, settings); + return webRequest; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs b/src/Greenshot.Base/Core/OAuth/OAuth2Settings.cs similarity index 74% rename from GreenshotPlugin/Core/OAuth/OAuth2Settings.cs rename to src/Greenshot.Base/Core/OAuth/OAuth2Settings.cs index 57b566aaa..c4fb6d2e2 100644 --- a/GreenshotPlugin/Core/OAuth/OAuth2Settings.cs +++ b/src/Greenshot.Base/Core/OAuth/OAuth2Settings.cs @@ -23,75 +23,56 @@ using System; using System.Collections.Generic; using System.Drawing; -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// Settings for the OAuth 2 protocol /// - public class OAuth2Settings { - public OAuth2Settings() { + public class OAuth2Settings + { + public OAuth2Settings() + { AdditionalAttributes = new Dictionary(); // Create a default state var state = Guid.NewGuid().ToString(); // Only store a small part of the GUID - State = state.Substring(0, state.IndexOf('-')-1); + State = state.Substring(0, state.IndexOf('-') - 1); AuthorizeMode = OAuth2AuthorizeMode.Unknown; } - public OAuth2AuthorizeMode AuthorizeMode { - get; - set; - } + public OAuth2AuthorizeMode AuthorizeMode { get; set; } /// /// Specify the name of the cloud service, so it can be used in window titles, logs etc /// - public string CloudServiceName { - get; - set; - } + public string CloudServiceName { get; set; } /// /// Specify the size of the embedded Browser, if using this /// - public Size BrowserSize { - get; - set; - } + public Size BrowserSize { get; set; } /// /// The OAuth 2 client id /// - public string ClientId { - get; - set; - } + public string ClientId { get; set; } /// /// The OAuth 2 client secret /// - public string ClientSecret { - get; - set; - } + public string ClientSecret { get; set; } /// /// The OAuth 2 state, this is something that is passed to the server, is not processed but returned back to the client. /// e.g. a correlation ID /// Default this is filled with a new Guid /// - public string State { - get; - set; - } + public string State { get; set; } /// /// The authorization URL where the values of this class can be "injected" /// - public string AuthUrlPattern { - get; - set; - } + public string AuthUrlPattern { get; set; } /// /// Get formatted Auth url (this will call a FormatWith(this) on the AuthUrlPattern @@ -101,54 +82,49 @@ namespace GreenshotPlugin.Core.OAuth /// /// The URL to get a Token /// - public string TokenUrl { - get; - set; - } + public string TokenUrl { get; set; } /// /// This is the redirect URL, in some implementations this is automatically set (LocalServerCodeReceiver) /// In some implementations this could be e.g. urn:ietf:wg:oauth:2.0:oob or urn:ietf:wg:oauth:2.0:oob:auto /// - public string RedirectUrl { - get; - set; - } + public string RedirectUrl { get; set; } /// /// Bearer token for accessing OAuth 2 services /// - public string AccessToken { - get; - set; - } + public string AccessToken { get; set; } /// /// Expire time for the AccessToken, this this time (-60 seconds) is passed a new AccessToken needs to be generated with the RefreshToken /// - public DateTimeOffset AccessTokenExpires { - get; - set; - } + public DateTimeOffset AccessTokenExpires { get; set; } /// /// Return true if the access token is expired. /// Important "side-effect": if true is returned the AccessToken will be set to null! /// - public bool IsAccessTokenExpired { - get { + public bool IsAccessTokenExpired + { + get + { if (AccessTokenExpires == default) { return false; } + bool expired = true; - if (!string.IsNullOrEmpty(AccessToken)) { + if (!string.IsNullOrEmpty(AccessToken)) + { expired = DateTimeOffset.Now.AddSeconds(60) > AccessTokenExpires; } + // Make sure the token is not usable - if (expired) { + if (expired) + { AccessToken = null; } + return expired; } } @@ -156,26 +132,17 @@ namespace GreenshotPlugin.Core.OAuth /// /// Token used to get a new Access Token /// - public string RefreshToken { - get; - set; - } + public string RefreshToken { get; set; } /// /// Put anything in here which is needed for the OAuth 2 implementation of this specific service but isn't generic, e.g. for Google there is a "scope" /// - public IDictionary AdditionalAttributes { - get; - set; - } + public IDictionary AdditionalAttributes { get; set; } /// /// This contains the code returned from the authorization, but only shortly after it was received. /// It will be cleared as soon as it was used. /// - public string Code { - get; - set; - } + public string Code { get; set; } } } \ No newline at end of file diff --git a/GreenshotPlugin/Core/OAuth/OAuthSession.cs b/src/Greenshot.Base/Core/OAuth/OAuthSession.cs similarity index 80% rename from GreenshotPlugin/Core/OAuth/OAuthSession.cs rename to src/Greenshot.Base/Core/OAuth/OAuthSession.cs index 9a40c0b8d..f8364df8e 100644 --- a/GreenshotPlugin/Core/OAuth/OAuthSession.cs +++ b/src/Greenshot.Base/Core/OAuth/OAuthSession.cs @@ -27,15 +27,16 @@ using System.Net; using System.Security.Cryptography; using System.Text; using System.Threading; -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; using log4net; -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// An OAuth 1 session object /// - public class OAuthSession { + public class OAuthSession + { private static readonly ILog Log = LogManager.GetLogger(typeof(OAuthSession)); protected const string OAUTH_VERSION = "1.0"; protected const string OAUTH_PARAMETER_PREFIX = "oauth_"; @@ -81,52 +82,24 @@ namespace GreenshotPlugin.Core.OAuth // default _browser size - public HTTPMethod RequestTokenMethod { - get; - set; - } - public HTTPMethod AccessTokenMethod { - get; - set; - } - public string RequestTokenUrl { - get; - set; - } - public string AuthorizeUrl { - get; - set; - } - public string AccessTokenUrl { - get; - set; - } - public string Token { - get; - set; - } - public string TokenSecret { - get; - set; - } - public string Verifier { - get; - set; - } - public OAuthSignatureTypes SignatureType { - get; - set; - } + public HTTPMethod RequestTokenMethod { get; set; } + public HTTPMethod AccessTokenMethod { get; set; } + public string RequestTokenUrl { get; set; } + public string AuthorizeUrl { get; set; } + public string AccessTokenUrl { get; set; } + public string Token { get; set; } + public string TokenSecret { get; set; } + public string Verifier { get; set; } + public OAuthSignatureTypes SignatureType { get; set; } public bool UseMultipartFormData { get; set; } - public string UserAgent { - get { - return _userAgent; - } - set { - _userAgent = value; - } + + public string UserAgent + { + get { return _userAgent; } + set { _userAgent = value; } } + public string CallbackUrl { get; set; } = "http://getgreenshot.org"; public bool CheckVerifier { get; set; } = true; @@ -137,17 +110,15 @@ namespace GreenshotPlugin.Core.OAuth public bool UseHttpHeadersForAuthorization { get; set; } = true; - public bool AutoLogin { - get; - set; - } + public bool AutoLogin { get; set; } /// /// Create an OAuthSession with the consumerKey / consumerSecret /// /// "Public" key for the encoding. When using RSASHA1 this is the path to the private key file /// "Private" key for the encoding. when usin RSASHA1 this is the password for the private key file - public OAuthSession(string consumerKey, string consumerSecret) { + public OAuthSession(string consumerKey, string consumerSecret) + { _consumerKey = consumerKey; _consumerSecret = consumerSecret; UseMultipartFormData = true; @@ -163,12 +134,15 @@ namespace GreenshotPlugin.Core.OAuth /// The hashing algorithm used. If that algorithm needs some initialization, like HMAC and its derivatives, they should be initialized prior to passing it to this function /// The data to hash /// a Base64 string of the hash value - private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) { - if (hashAlgorithm == null) { + private static string ComputeHash(HashAlgorithm hashAlgorithm, string data) + { + if (hashAlgorithm == null) + { throw new ArgumentNullException(nameof(hashAlgorithm)); } - if (string.IsNullOrEmpty(data)) { + if (string.IsNullOrEmpty(data)) + { throw new ArgumentNullException(nameof(data)); } @@ -183,19 +157,24 @@ namespace GreenshotPlugin.Core.OAuth /// /// the list of query parameters /// a string with the normalized query parameters - private static string GenerateNormalizedParametersString(IDictionary queryParameters) { - if (queryParameters == null || queryParameters.Count == 0) { + private static string GenerateNormalizedParametersString(IDictionary queryParameters) + { + if (queryParameters == null || queryParameters.Count == 0) + { return string.Empty; } queryParameters = new SortedDictionary(queryParameters); StringBuilder sb = new StringBuilder(); - foreach (string key in queryParameters.Keys) { - if (queryParameters[key] is string) { + foreach (string key in queryParameters.Keys) + { + if (queryParameters[key] is string) + { sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", key, UrlEncode3986($"{queryParameters[key]}")); } } + sb.Remove(sb.Length - 1, 1); return sb.ToString(); @@ -208,15 +187,21 @@ namespace GreenshotPlugin.Core.OAuth /// /// The value to Url encode /// Returns a Url encoded string (unicode) with UTF-8 encoded % values - public static string UrlEncode3986(string value) { + public static string UrlEncode3986(string value) + { StringBuilder result = new StringBuilder(); - foreach (char symbol in value) { - if (UnreservedChars.IndexOf(symbol) != -1) { + foreach (char symbol in value) + { + if (UnreservedChars.IndexOf(symbol) != -1) + { result.Append(symbol); - } else { + } + else + { byte[] utf8Bytes = Encoding.UTF8.GetBytes(symbol.ToString()); - foreach(byte utf8Byte in utf8Bytes) { + foreach (byte utf8Byte in utf8Bytes) + { result.AppendFormat("%{0:X2}", utf8Byte); } } @@ -229,7 +214,8 @@ namespace GreenshotPlugin.Core.OAuth /// Generate the timestamp for the signature /// /// - public static string GenerateTimeStamp() { + public static string GenerateTimeStamp() + { // Default implementation of UNIX time of the current UTC time TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); @@ -239,7 +225,8 @@ namespace GreenshotPlugin.Core.OAuth /// Generate a nonce /// /// - public static string GenerateNonce() { + public static string GenerateNonce() + { // Just a simple implementation of a random number between 123400 and 9999999 return random.Next(123400, 9999999).ToString(); } @@ -248,22 +235,28 @@ namespace GreenshotPlugin.Core.OAuth /// Get the request token using the consumer key and secret. Also initializes tokensecret /// /// response, this doesn't need to be used!! - private string GetRequestToken() { + private string GetRequestToken() + { IDictionary parameters = new Dictionary(); - foreach(var value in RequestTokenParameters) { + foreach (var value in RequestTokenParameters) + { parameters.Add(value); } + Sign(RequestTokenMethod, RequestTokenUrl, parameters); string response = MakeRequest(RequestTokenMethod, RequestTokenUrl, null, parameters, null); - if (!string.IsNullOrEmpty(response)) { + if (!string.IsNullOrEmpty(response)) + { response = NetworkHelper.UrlDecode(response); Log.DebugFormat("Request token response: {0}", response); _requestTokenResponseParameters = NetworkHelper.ParseQueryString(response); - if (_requestTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var value)) { + if (_requestTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var value)) + { Token = value; TokenSecret = _requestTokenResponseParameters[OAUTH_TOKEN_SECRET_KEY]; } } + return response; } @@ -272,31 +265,43 @@ namespace GreenshotPlugin.Core.OAuth /// /// Pass the response from the server's request token, so if there is something wrong we can show it. /// The request token. - private string GetAuthorizeToken(string requestTokenResponse) { - if (string.IsNullOrEmpty(Token)) { + private string GetAuthorizeToken(string requestTokenResponse) + { + if (string.IsNullOrEmpty(Token)) + { Exception e = new Exception("The request token is not set, service responded with: " + requestTokenResponse); throw e; } + Log.DebugFormat("Opening AuthorizationLink: {0}", AuthorizationLink); OAuthLoginForm oAuthLoginForm = new OAuthLoginForm(LoginTitle, BrowserSize, AuthorizationLink, CallbackUrl); oAuthLoginForm.ShowDialog(); - if (oAuthLoginForm.IsOk) { - if (oAuthLoginForm.CallbackParameters != null) { - if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue)) { + if (oAuthLoginForm.IsOk) + { + if (oAuthLoginForm.CallbackParameters != null) + { + if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue)) + { Token = tokenValue; } - if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_VERIFIER_KEY, out var verifierValue)) { + if (oAuthLoginForm.CallbackParameters.TryGetValue(OAUTH_VERIFIER_KEY, out var verifierValue)) + { Verifier = verifierValue; } } } - if (CheckVerifier) { - if (!string.IsNullOrEmpty(Verifier)) { + + if (CheckVerifier) + { + if (!string.IsNullOrEmpty(Verifier)) + { return Token; } + return null; } + return Token; } @@ -304,8 +309,10 @@ namespace GreenshotPlugin.Core.OAuth /// Get the access token /// /// The access token. - private string GetAccessToken() { - if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) { + private string GetAccessToken() + { + if (string.IsNullOrEmpty(Token) || (CheckVerifier && string.IsNullOrEmpty(Verifier))) + { Exception e = new Exception("The request token and verifier were not set"); throw e; } @@ -313,15 +320,18 @@ namespace GreenshotPlugin.Core.OAuth IDictionary parameters = new Dictionary(); Sign(AccessTokenMethod, AccessTokenUrl, parameters); string response = MakeRequest(AccessTokenMethod, AccessTokenUrl, null, parameters, null); - if (!string.IsNullOrEmpty(response)) { + if (!string.IsNullOrEmpty(response)) + { response = NetworkHelper.UrlDecode(response); Log.DebugFormat("Access token response: {0}", response); AccessTokenResponseParameters = NetworkHelper.ParseQueryString(response); - if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue) && tokenValue != null) { + if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_KEY, out var tokenValue) && tokenValue != null) + { Token = tokenValue; } - if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_SECRET_KEY, out var secretValue) && secretValue != null) { + if (AccessTokenResponseParameters.TryGetValue(OAUTH_TOKEN_SECRET_KEY, out var secretValue) && secretValue != null) + { TokenSecret = secretValue; } } @@ -333,26 +343,36 @@ namespace GreenshotPlugin.Core.OAuth /// This method goes through the whole authorize process, including a Authorization window. /// /// true if the process is completed - public bool Authorize() { + public bool Authorize() + { Token = null; TokenSecret = null; Verifier = null; Log.Debug("Creating Token"); string requestTokenResponse; - try { + try + { requestTokenResponse = GetRequestToken(); - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Error(ex); throw new NotSupportedException("Service is not available: " + ex.Message); } - if (string.IsNullOrEmpty(GetAuthorizeToken(requestTokenResponse))) { + + if (string.IsNullOrEmpty(GetAuthorizeToken(requestTokenResponse))) + { Log.Debug("User didn't authenticate!"); return false; } - try { + + try + { Thread.Sleep(1000); return GetAccessToken() != null; - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Error(ex); throw; } @@ -373,7 +393,9 @@ namespace GreenshotPlugin.Core.OAuth /// Parameters for the request, which do not need to be signed /// Data to post (MemoryStream) /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { + public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary parametersToSign, IDictionary additionalParameters, + IBinaryContainer postData) + { return MakeOAuthRequest(method, requestUrl, requestUrl, null, parametersToSign, additionalParameters, postData); } @@ -387,7 +409,9 @@ namespace GreenshotPlugin.Core.OAuth /// Parameters for the request, which do not need to be signed /// Data to post (MemoryStream) /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { + public string MakeOAuthRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parametersToSign, + IDictionary additionalParameters, IBinaryContainer postData) + { return MakeOAuthRequest(method, requestUrl, requestUrl, headers, parametersToSign, additionalParameters, postData); } @@ -401,7 +425,9 @@ namespace GreenshotPlugin.Core.OAuth /// Parameters for the request, which do not need to be signed /// Data to post (MemoryStream) /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { + public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary parametersToSign, + IDictionary additionalParameters, IBinaryContainer postData) + { return MakeOAuthRequest(method, signUrl, requestUrl, null, parametersToSign, additionalParameters, postData); } @@ -416,34 +442,50 @@ namespace GreenshotPlugin.Core.OAuth /// Parameters for the request, which do not need to be signed /// Data to post (MemoryStream) /// The web server response. - public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary headers, IDictionary parametersToSign, IDictionary additionalParameters, IBinaryContainer postData) { - if (parametersToSign == null) { + public string MakeOAuthRequest(HTTPMethod method, string signUrl, string requestUrl, IDictionary headers, IDictionary parametersToSign, + IDictionary additionalParameters, IBinaryContainer postData) + { + if (parametersToSign == null) + { parametersToSign = new Dictionary(); } + int retries = 2; Exception lastException = null; - while (retries-- > 0) { + while (retries-- > 0) + { // If we are not trying to get a Authorization or Accestoken, and we don't have a token, create one - if (string.IsNullOrEmpty(Token)) { - if (!AutoLogin || !Authorize()) { + if (string.IsNullOrEmpty(Token)) + { + if (!AutoLogin || !Authorize()) + { throw new Exception("Not authorized"); } } - try { + + try + { Sign(method, signUrl, parametersToSign); // Join all parameters IDictionary newParameters = new Dictionary(); - foreach (var parameter in parametersToSign) { + foreach (var parameter in parametersToSign) + { newParameters.Add(parameter); } - if (additionalParameters != null) { - foreach (var parameter in additionalParameters) { + + if (additionalParameters != null) + { + foreach (var parameter in additionalParameters) + { newParameters.Add(parameter); } } + return MakeRequest(method, requestUrl, headers, newParameters, postData); - } catch (UnauthorizedAccessException uaEx) { + } + catch (UnauthorizedAccessException uaEx) + { lastException = uaEx; Token = null; TokenSecret = null; @@ -456,15 +498,19 @@ namespace GreenshotPlugin.Core.OAuth keysToDelete.Add(parameterKey); } } + foreach (string keyToDelete in keysToDelete) { parametersToSign.Remove(keyToDelete); } } } - if (lastException != null) { + + if (lastException != null) + { throw lastException; } + throw new Exception("Not authorized"); } @@ -475,10 +521,13 @@ namespace GreenshotPlugin.Core.OAuth /// Method (POST,PUT,GET) /// Url to call /// IDictionary of string and string - private void Sign(HTTPMethod method, string requestUrl, IDictionary parameters) { - if (parameters == null) { + private void Sign(HTTPMethod method, string requestUrl, IDictionary parameters) + { + if (parameters == null) + { throw new ArgumentNullException(nameof(parameters)); } + // Build the signature base StringBuilder signatureBase = new StringBuilder(); @@ -488,9 +537,11 @@ namespace GreenshotPlugin.Core.OAuth // Add normalized URL Uri url = new Uri(requestUrl); string normalizedUrl = string.Format(CultureInfo.InvariantCulture, "{0}://{1}", url.Scheme, url.Host); - if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) { + if (!((url.Scheme == "http" && url.Port == 80) || (url.Scheme == "https" && url.Port == 443))) + { normalizedUrl += ":" + url.Port; } + normalizedUrl += url.AbsolutePath; signatureBase.Append(UrlEncode3986(normalizedUrl)).Append("&"); @@ -498,7 +549,8 @@ namespace GreenshotPlugin.Core.OAuth parameters.Add(OAUTH_VERSION_KEY, OAUTH_VERSION); parameters.Add(OAUTH_NONCE_KEY, GenerateNonce()); parameters.Add(OAUTH_TIMESTAMP_KEY, GenerateTimeStamp()); - switch(SignatureType) { + switch (SignatureType) + { case OAuthSignatureTypes.PLAINTEXT: parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, PlainTextSignatureType); break; @@ -506,26 +558,38 @@ namespace GreenshotPlugin.Core.OAuth parameters.Add(OAUTH_SIGNATURE_METHOD_KEY, HMACSHA1SignatureType); break; } + parameters.Add(OAUTH_CONSUMER_KEY_KEY, _consumerKey); - if (CallbackUrl != null && RequestTokenUrl != null && requestUrl.StartsWith(RequestTokenUrl)) { + if (CallbackUrl != null && RequestTokenUrl != null && requestUrl.StartsWith(RequestTokenUrl)) + { parameters.Add(OAUTH_CALLBACK_KEY, CallbackUrl); } - if (!string.IsNullOrEmpty(Verifier)) { + + if (!string.IsNullOrEmpty(Verifier)) + { parameters.Add(OAUTH_VERIFIER_KEY, Verifier); } - if (!string.IsNullOrEmpty(Token)) { + + if (!string.IsNullOrEmpty(Token)) + { parameters.Add(OAUTH_TOKEN_KEY, Token); } + signatureBase.Append(UrlEncode3986(GenerateNormalizedParametersString(parameters))); Log.DebugFormat("Signature base: {0}", signatureBase); - string key = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", UrlEncode3986(_consumerSecret), string.IsNullOrEmpty(TokenSecret) ? string.Empty : UrlEncode3986(TokenSecret)); - switch (SignatureType) { + string key = string.Format(CultureInfo.InvariantCulture, "{0}&{1}", UrlEncode3986(_consumerSecret), + string.IsNullOrEmpty(TokenSecret) ? string.Empty : UrlEncode3986(TokenSecret)); + switch (SignatureType) + { case OAuthSignatureTypes.PLAINTEXT: parameters.Add(OAUTH_SIGNATURE_KEY, key); break; default: // Generate Signature and add it to the parameters - HMACSHA1 hmacsha1 = new HMACSHA1 {Key = Encoding.UTF8.GetBytes(key)}; + HMACSHA1 hmacsha1 = new HMACSHA1 + { + Key = Encoding.UTF8.GetBytes(key) + }; string signature = ComputeHash(hmacsha1, signatureBase.ToString()); parameters.Add(OAUTH_SIGNATURE_KEY, signature); break; @@ -542,83 +606,116 @@ namespace GreenshotPlugin.Core.OAuth /// /// IBinaryParameter /// Response from server - private string MakeRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parameters, IBinaryContainer postData) { - if (parameters == null) { + private string MakeRequest(HTTPMethod method, string requestUrl, IDictionary headers, IDictionary parameters, IBinaryContainer postData) + { + if (parameters == null) + { throw new ArgumentNullException(nameof(parameters)); } + IDictionary requestParameters; // Add oAuth values as HTTP headers, if this is allowed StringBuilder authHeader = null; - if (UseHttpHeadersForAuthorization) { + if (UseHttpHeadersForAuthorization) + { authHeader = new StringBuilder(); requestParameters = new Dictionary(); - foreach (string parameterKey in parameters.Keys) { - if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) { + foreach (string parameterKey in parameters.Keys) + { + if (parameterKey.StartsWith(OAUTH_PARAMETER_PREFIX)) + { authHeader.AppendFormat(CultureInfo.InvariantCulture, "{0}=\"{1}\", ", parameterKey, UrlEncode3986($"{parameters[parameterKey]}")); - } else if (!requestParameters.ContainsKey(parameterKey)) { + } + else if (!requestParameters.ContainsKey(parameterKey)) + { requestParameters.Add(parameterKey, parameters[parameterKey]); } } + // Remove trailing comma and space and add it to the headers - if (authHeader.Length > 0) { + if (authHeader.Length > 0) + { authHeader.Remove(authHeader.Length - 2, 2); } - } else { + } + else + { requestParameters = parameters; } - if (HTTPMethod.GET == method || postData != null) { - if (requestParameters.Count > 0) { + if (HTTPMethod.GET == method || postData != null) + { + if (requestParameters.Count > 0) + { // Add the parameters to the request requestUrl += "?" + NetworkHelper.GenerateQueryParameters(requestParameters); } } + // Create webrequest HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(requestUrl, method); webRequest.ServicePoint.Expect100Continue = false; webRequest.UserAgent = _userAgent; - if (UseHttpHeadersForAuthorization && authHeader != null) { + if (UseHttpHeadersForAuthorization && authHeader != null) + { Log.DebugFormat("Authorization: OAuth {0}", authHeader); webRequest.Headers.Add("Authorization: OAuth " + authHeader); } - if (headers != null) { - foreach(string key in headers.Keys) { + if (headers != null) + { + foreach (string key in headers.Keys) + { webRequest.Headers.Add(key, headers[key]); } } - if ((HTTPMethod.POST == method || HTTPMethod.PUT == method) && postData == null && requestParameters.Count > 0) { - if (UseMultipartFormData) { + if ((HTTPMethod.POST == method || HTTPMethod.PUT == method) && postData == null && requestParameters.Count > 0) + { + if (UseMultipartFormData) + { NetworkHelper.WriteMultipartFormData(webRequest, requestParameters); - } else { + } + else + { StringBuilder form = new StringBuilder(); foreach (string parameterKey in requestParameters.Keys) { var binaryParameter = parameters[parameterKey] as IBinaryContainer; - form.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), binaryParameter != null ? UrlEncode3986(binaryParameter.ToBase64String(Base64FormattingOptions.None)) : UrlEncode3986($"{parameters[parameterKey]}")); + form.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}&", UrlEncode3986(parameterKey), + binaryParameter != null ? UrlEncode3986(binaryParameter.ToBase64String(Base64FormattingOptions.None)) : UrlEncode3986($"{parameters[parameterKey]}")); } + // Remove trailing & - if (form.Length > 0) { + if (form.Length > 0) + { form.Remove(form.Length - 1, 1); } + webRequest.ContentType = "application/x-www-form-urlencoded"; byte[] data = Encoding.UTF8.GetBytes(form.ToString()); using var requestStream = webRequest.GetRequestStream(); requestStream.Write(data, 0, data.Length); } - } else if (postData != null) { + } + else if (postData != null) + { postData.Upload(webRequest); - } else { + } + else + { webRequest.ContentLength = 0; } string responseData; - try { + try + { responseData = NetworkHelper.GetResponseAsString(webRequest); Log.DebugFormat("Response: {0}", responseData); - } catch (Exception ex) { + } + catch (Exception ex) + { Log.Error("Couldn't retrieve response: ", ex); throw; } diff --git a/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs b/src/Greenshot.Base/Core/OAuth/OAuthSignatureTypes.cs similarity index 93% rename from GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs rename to src/Greenshot.Base/Core/OAuth/OAuthSignatureTypes.cs index af2bfc710..eeca8decd 100644 --- a/GreenshotPlugin/Core/OAuth/OAuthSignatureTypes.cs +++ b/src/Greenshot.Base/Core/OAuth/OAuthSignatureTypes.cs @@ -19,12 +19,13 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Core.OAuth +namespace Greenshot.Base.Core.OAuth { /// /// Provides a predefined set of algorithms that are supported officially by the OAuth 1.x protocol /// - public enum OAuthSignatureTypes { + public enum OAuthSignatureTypes + { HMACSHA1, PLAINTEXT, } diff --git a/src/Greenshot.Base/Core/ObjectExtensions.cs b/src/Greenshot.Base/Core/ObjectExtensions.cs new file mode 100644 index 000000000..297015824 --- /dev/null +++ b/src/Greenshot.Base/Core/ObjectExtensions.cs @@ -0,0 +1,118 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; + +namespace Greenshot.Base.Core +{ + /// + /// Extension methods which work for objects + /// + public static class ObjectExtensions + { + /// + /// Perform a deep Copy of the object. + /// + /// The type of object being copied. + /// The object instance to copy. + /// The copied object. + public static T Clone(this T source) + { + var typeparam = typeof(T); + if (!typeparam.IsInterface && !typeparam.IsSerializable) + { + throw new ArgumentException("The type must be serializable.", nameof(source)); + } + + // Don't serialize a null object, simply return the default for that object + if (source == null) + { + return default; + } + + IFormatter formatter = new BinaryFormatter(); + using var stream = new MemoryStream(); + formatter.Serialize(stream, source); + stream.Seek(0, SeekOrigin.Begin); + return (T) formatter.Deserialize(stream); + } + + /// + /// Clone the content from source to destination + /// + /// Type to clone + /// Instance to copy from + /// Instance to copy to + public static void CloneTo(this T source, T destination) + { + var type = typeof(T); + var myObjectFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + + foreach (var fieldInfo in myObjectFields) + { + fieldInfo.SetValue(destination, fieldInfo.GetValue(source)); + } + + var myObjectProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + + foreach (var propertyInfo in myObjectProperties) + { + if (propertyInfo.CanWrite) + { + propertyInfo.SetValue(destination, propertyInfo.GetValue(source, null), null); + } + } + } + + /// + /// Compare two lists + /// + /// + /// IList + /// IList + /// true if they are the same + public static bool CompareLists(IList l1, IList l2) + { + if (l1.Count != l2.Count) + { + return false; + } + + int matched = 0; + foreach (T item in l1) + { + if (!l2.Contains(item)) + { + return false; + } + + matched++; + } + + return matched == l1.Count; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/PluginUtils.cs b/src/Greenshot.Base/Core/PluginUtils.cs new file mode 100644 index 000000000..34fcba5d9 --- /dev/null +++ b/src/Greenshot.Base/Core/PluginUtils.cs @@ -0,0 +1,228 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.UnmanagedHelpers; +using log4net; +using Microsoft.Win32; + +namespace Greenshot.Base.Core +{ + /// + /// Description of PluginUtils. + /// + public static class PluginUtils + { + private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\"; + private static readonly IDictionary ExeIconCache = new Dictionary(); + + static PluginUtils() + { + CoreConfig.PropertyChanged += OnIconSizeChanged; + } + + /// + /// Clear icon cache + /// + /// + /// + private static void OnIconSizeChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != "IconSize") return; + var cachedImages = new List(); + lock (ExeIconCache) + { + foreach (string key in ExeIconCache.Keys) + { + cachedImages.Add(ExeIconCache[key]); + } + + ExeIconCache.Clear(); + } + + foreach (Image cachedImage in cachedImages) + { + cachedImage?.Dispose(); + } + } + + /// + /// Get the path of an executable + /// + /// e.g. cmd.exe + /// Path to file + public static string GetExePath(string exeName) + { + using (var key = Registry.LocalMachine.OpenSubKey(PathKey + exeName, false)) + { + if (key != null) + { + // "" is the default key, which should point to the requested location + return (string) key.GetValue(string.Empty); + } + } + + foreach (string pathEntry in (Environment.GetEnvironmentVariable("PATH") ?? string.Empty).Split(';')) + { + try + { + string path = pathEntry.Trim(); + if (!string.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, exeName))) + { + return Path.GetFullPath(path); + } + } + catch (Exception) + { + Log.WarnFormat("Problem with path entry '{0}'.", pathEntry); + } + } + + return null; + } + + /// + /// Get icon from resource files, from the cache. + /// Examples can be found here: https://diymediahome.org/windows-icons-reference-list-with-details-locations-images/ + /// + /// path to the exe or dll + /// index of the icon + /// Bitmap with the icon or null if something happended + public static Image GetCachedExeIcon(string path, int index) + { + string cacheKey = $"{path}:{index}"; + Image returnValue; + lock (ExeIconCache) + { + if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) + { + return returnValue; + } + + lock (ExeIconCache) + { + if (ExeIconCache.TryGetValue(cacheKey, out returnValue)) + { + return returnValue; + } + + returnValue = GetExeIcon(path, index); + if (returnValue != null) + { + ExeIconCache.Add(cacheKey, returnValue); + } + } + } + + return returnValue; + } + + /// + /// Get icon for executable + /// + /// path to the exe or dll + /// index of the icon + /// Bitmap with the icon or null if something happended + private static Bitmap GetExeIcon(string path, int index) + { + if (!File.Exists(path)) + { + return null; + } + + try + { + using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) + { + if (appIcon != null) + { + return appIcon.ToBitmap(); + } + } + + using (Icon appIcon = Shell32.GetFileIcon(path, CoreConfig.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false)) + { + if (appIcon != null) + { + return appIcon.ToBitmap(); + } + } + } + catch (Exception exIcon) + { + Log.Error("error retrieving icon: ", exIcon); + } + + return null; + } + + /// + /// Helper method to add a plugin MenuItem to the Greenshot context menu + /// + /// ToolStripMenuItem + public static void AddToContextMenu(ToolStripMenuItem item) + { + // Here we can hang ourselves to the main context menu! + var contextMenu = SimpleServiceProvider.Current.GetInstance(); + bool addedItem = false; + + // Try to find a separator, so we insert ourselves after it + for (int i = 0; i < contextMenu.Items.Count; i++) + { + if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) + { + // Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore" + if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag)) + { + var separator = new ToolStripSeparator + { + Tag = "PluginsAreAddedAfter", + Size = new Size(305, 6) + }; + contextMenu.Items.Insert(i, separator); + } + else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag)) + { + continue; + } + + contextMenu.Items.Insert(i + 1, item); + addedItem = true; + break; + } + } + + // If we didn't insert the item, we just add it... + if (!addedItem) + { + contextMenu.Items.Add(item); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/QuantizerHelper.cs b/src/Greenshot.Base/Core/QuantizerHelper.cs new file mode 100644 index 000000000..9ae5211a1 --- /dev/null +++ b/src/Greenshot.Base/Core/QuantizerHelper.cs @@ -0,0 +1,771 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using log4net; + +namespace Greenshot.Base.Core +{ + internal class WuColorCube + { + /// + /// Gets or sets the red minimum. + /// + /// The red minimum. + public int RedMinimum { get; set; } + + /// + /// Gets or sets the red maximum. + /// + /// The red maximum. + public int RedMaximum { get; set; } + + /// + /// Gets or sets the green minimum. + /// + /// The green minimum. + public int GreenMinimum { get; set; } + + /// + /// Gets or sets the green maximum. + /// + /// The green maximum. + public int GreenMaximum { get; set; } + + /// + /// Gets or sets the blue minimum. + /// + /// The blue minimum. + public int BlueMinimum { get; set; } + + /// + /// Gets or sets the blue maximum. + /// + /// The blue maximum. + public int BlueMaximum { get; set; } + + /// + /// Gets or sets the cube volume. + /// + /// The volume. + public int Volume { get; set; } + } + + public class WuQuantizer : IDisposable + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(WuQuantizer)); + + private const int MAXCOLOR = 512; + private const int RED = 2; + private const int GREEN = 1; + private const int BLUE = 0; + private const int SIDESIZE = 33; + private const int MAXSIDEINDEX = 32; + private const int MAXVOLUME = SIDESIZE * SIDESIZE * SIDESIZE; + + // To count the colors + private readonly int colorCount; + + private int[] reds; + private int[] greens; + private int[] blues; + private int[] sums; + + private readonly long[,,] weights; + private readonly long[,,] momentsRed; + private readonly long[,,] momentsGreen; + private readonly long[,,] momentsBlue; + private readonly float[,,] moments; + + private byte[] tag; + + private readonly WuColorCube[] cubes; + private readonly Bitmap sourceBitmap; + private Bitmap resultBitmap; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (resultBitmap != null) + { + resultBitmap.Dispose(); + resultBitmap = null; + } + } + } + + /// + /// See for more details. + /// + public WuQuantizer(Bitmap sourceBitmap) + { + this.sourceBitmap = sourceBitmap; + // Make sure the color count variables are reset + BitArray bitArray = new BitArray((int) Math.Pow(2, 24)); + colorCount = 0; + + // creates all the cubes + cubes = new WuColorCube[MAXCOLOR]; + + // initializes all the cubes + for (int cubeIndex = 0; cubeIndex < MAXCOLOR; cubeIndex++) + { + cubes[cubeIndex] = new WuColorCube(); + } + + // resets the reference minimums + cubes[0].RedMinimum = 0; + cubes[0].GreenMinimum = 0; + cubes[0].BlueMinimum = 0; + + // resets the reference maximums + cubes[0].RedMaximum = MAXSIDEINDEX; + cubes[0].GreenMaximum = MAXSIDEINDEX; + cubes[0].BlueMaximum = MAXSIDEINDEX; + + weights = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + momentsRed = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + momentsGreen = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + momentsBlue = new long[SIDESIZE, SIDESIZE, SIDESIZE]; + moments = new float[SIDESIZE, SIDESIZE, SIDESIZE]; + + int[] table = new int[256]; + + for (int tableIndex = 0; tableIndex < 256; ++tableIndex) + { + table[tableIndex] = tableIndex * tableIndex; + } + + // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage + using IFastBitmap sourceFastBitmap = FastBitmap.Create(sourceBitmap); + IFastBitmapWithBlend sourceFastBitmapWithBlend = sourceFastBitmap as IFastBitmapWithBlend; + sourceFastBitmap.Lock(); + using FastChunkyBitmap destinationFastBitmap = FastBitmap.CreateEmpty(sourceBitmap.Size, PixelFormat.Format8bppIndexed, Color.White) as FastChunkyBitmap; + destinationFastBitmap.Lock(); + for (int y = 0; y < sourceFastBitmap.Height; y++) + { + for (int x = 0; x < sourceFastBitmap.Width; x++) + { + Color color; + if (sourceFastBitmapWithBlend == null) + { + color = sourceFastBitmap.GetColorAt(x, y); + } + else + { + color = sourceFastBitmapWithBlend.GetBlendedColorAt(x, y); + } + + // To count the colors + int index = color.ToArgb() & 0x00ffffff; + // Check if we already have this color + if (!bitArray.Get(index)) + { + // If not, add 1 to the single colors + colorCount++; + bitArray.Set(index, true); + } + + int indexRed = (color.R >> 3) + 1; + int indexGreen = (color.G >> 3) + 1; + int indexBlue = (color.B >> 3) + 1; + + weights[indexRed, indexGreen, indexBlue]++; + momentsRed[indexRed, indexGreen, indexBlue] += color.R; + momentsGreen[indexRed, indexGreen, indexBlue] += color.G; + momentsBlue[indexRed, indexGreen, indexBlue] += color.B; + moments[indexRed, indexGreen, indexBlue] += table[color.R] + table[color.G] + table[color.B]; + + // Store the initial "match" + int paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue; + destinationFastBitmap.SetColorIndexAt(x, y, (byte) (paletteIndex & 0xff)); + } + } + + resultBitmap = destinationFastBitmap.UnlockAndReturnBitmap(); + } + + /// + /// See for more details. + /// + public int GetColorCount() + { + return colorCount; + } + + /// + /// Reindex the 24/32 BPP (A)RGB image to a 8BPP + /// + /// Bitmap + public Bitmap SimpleReindex() + { + List colors = new List(); + Dictionary lookup = new Dictionary(); + using (FastChunkyBitmap bbbDest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) + { + bbbDest.Lock(); + using IFastBitmap bbbSrc = FastBitmap.Create(sourceBitmap); + IFastBitmapWithBlend bbbSrcBlend = bbbSrc as IFastBitmapWithBlend; + + bbbSrc.Lock(); + byte index; + for (int y = 0; y < bbbSrc.Height; y++) + { + for (int x = 0; x < bbbSrc.Width; x++) + { + Color color; + if (bbbSrcBlend != null) + { + color = bbbSrcBlend.GetBlendedColorAt(x, y); + } + else + { + color = bbbSrc.GetColorAt(x, y); + } + + if (lookup.ContainsKey(color)) + { + index = lookup[color]; + } + else + { + colors.Add(color); + index = (byte) (colors.Count - 1); + lookup.Add(color, index); + } + + bbbDest.SetColorIndexAt(x, y, index); + } + } + } + + // generates palette + ColorPalette imagePalette = resultBitmap.Palette; + Color[] entries = imagePalette.Entries; + for (int paletteIndex = 0; paletteIndex < 256; paletteIndex++) + { + if (paletteIndex < colorCount) + { + entries[paletteIndex] = colors[paletteIndex]; + } + else + { + entries[paletteIndex] = Color.Black; + } + } + + resultBitmap.Palette = imagePalette; + + // Make sure the bitmap is not disposed, as we return it. + Bitmap tmpBitmap = resultBitmap; + resultBitmap = null; + return tmpBitmap; + } + + /// + /// Get the image + /// + public Bitmap GetQuantizedImage(int allowedColorCount) + { + if (allowedColorCount > 256) + { + throw new ArgumentOutOfRangeException(nameof(allowedColorCount), "Quantizing muss be done to get less than 256 colors"); + } + + if (colorCount < allowedColorCount) + { + // Simple logic to reduce to 8 bit + LOG.Info("Colors in the image are already less as whished for, using simple copy to indexed image, no quantizing needed!"); + return SimpleReindex(); + } + + // preprocess the colors + CalculateMoments(); + LOG.Info("Calculated the moments..."); + int next = 0; + float[] volumeVariance = new float[MAXCOLOR]; + + // processes the cubes + for (int cubeIndex = 1; cubeIndex < allowedColorCount; ++cubeIndex) + { + // if cut is possible; make it + if (Cut(cubes[next], cubes[cubeIndex])) + { + volumeVariance[next] = cubes[next].Volume > 1 ? CalculateVariance(cubes[next]) : 0.0f; + volumeVariance[cubeIndex] = cubes[cubeIndex].Volume > 1 ? CalculateVariance(cubes[cubeIndex]) : 0.0f; + } + else + { + // the cut was not possible, revert the index + volumeVariance[next] = 0.0f; + cubeIndex--; + } + + next = 0; + float temp = volumeVariance[0]; + + for (int index = 1; index <= cubeIndex; ++index) + { + if (volumeVariance[index] > temp) + { + temp = volumeVariance[index]; + next = index; + } + } + + if (temp <= 0.0) + { + allowedColorCount = cubeIndex + 1; + break; + } + } + + int[] lookupRed = new int[MAXCOLOR]; + int[] lookupGreen = new int[MAXCOLOR]; + int[] lookupBlue = new int[MAXCOLOR]; + + tag = new byte[MAXVOLUME]; + + // precalculates lookup tables + for (int k = 0; k < allowedColorCount; ++k) + { + Mark(cubes[k], k, tag); + + long weight = Volume(cubes[k], weights); + + if (weight > 0) + { + lookupRed[k] = (int) (Volume(cubes[k], momentsRed) / weight); + lookupGreen[k] = (int) (Volume(cubes[k], momentsGreen) / weight); + lookupBlue[k] = (int) (Volume(cubes[k], momentsBlue) / weight); + } + else + { + lookupRed[k] = 0; + lookupGreen[k] = 0; + lookupBlue[k] = 0; + } + } + + reds = new int[allowedColorCount + 1]; + greens = new int[allowedColorCount + 1]; + blues = new int[allowedColorCount + 1]; + sums = new int[allowedColorCount + 1]; + + LOG.Info("Starting bitmap reconstruction..."); + + using (FastChunkyBitmap dest = FastBitmap.Create(resultBitmap) as FastChunkyBitmap) + { + using IFastBitmap src = FastBitmap.Create(sourceBitmap); + IFastBitmapWithBlend srcBlend = src as IFastBitmapWithBlend; + Dictionary lookup = new Dictionary(); + for (int y = 0; y < src.Height; y++) + { + for (int x = 0; x < src.Width; x++) + { + Color color; + if (srcBlend != null) + { + // WithoutAlpha, this makes it possible to ignore the alpha + color = srcBlend.GetBlendedColorAt(x, y); + } + else + { + color = src.GetColorAt(x, y); + } + + // Check if we already matched the color + byte bestMatch; + if (!lookup.ContainsKey(color)) + { + // If not we need to find the best match + + // First get initial match + bestMatch = dest.GetColorIndexAt(x, y); + bestMatch = tag[bestMatch]; + + int bestDistance = 100000000; + for (int lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++) + { + int foundRed = lookupRed[lookupIndex]; + int foundGreen = lookupGreen[lookupIndex]; + int foundBlue = lookupBlue[lookupIndex]; + int deltaRed = color.R - foundRed; + int deltaGreen = color.G - foundGreen; + int deltaBlue = color.B - foundBlue; + + int distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue; + + if (distance < bestDistance) + { + bestDistance = distance; + bestMatch = (byte) lookupIndex; + } + } + + lookup.Add(color, bestMatch); + } + else + { + // Already matched, so we just use the lookup + bestMatch = lookup[color]; + } + + reds[bestMatch] += color.R; + greens[bestMatch] += color.G; + blues[bestMatch] += color.B; + sums[bestMatch]++; + + dest.SetColorIndexAt(x, y, bestMatch); + } + } + } + + + // generates palette + ColorPalette imagePalette = resultBitmap.Palette; + Color[] entries = imagePalette.Entries; + for (int paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++) + { + if (sums[paletteIndex] > 0) + { + reds[paletteIndex] /= sums[paletteIndex]; + greens[paletteIndex] /= sums[paletteIndex]; + blues[paletteIndex] /= sums[paletteIndex]; + } + + entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]); + } + + resultBitmap.Palette = imagePalette; + + // Make sure the bitmap is not disposed, as we return it. + Bitmap tmpBitmap = resultBitmap; + resultBitmap = null; + return tmpBitmap; + } + + /// + /// Converts the histogram to a series of moments. + /// + private void CalculateMoments() + { + long[] area = new long[SIDESIZE]; + long[] areaRed = new long[SIDESIZE]; + long[] areaGreen = new long[SIDESIZE]; + long[] areaBlue = new long[SIDESIZE]; + float[] area2 = new float[SIDESIZE]; + + for (int redIndex = 1; redIndex <= MAXSIDEINDEX; ++redIndex) + { + for (int index = 0; index <= MAXSIDEINDEX; ++index) + { + area[index] = 0; + areaRed[index] = 0; + areaGreen[index] = 0; + areaBlue[index] = 0; + area2[index] = 0; + } + + for (int greenIndex = 1; greenIndex <= MAXSIDEINDEX; ++greenIndex) + { + long line = 0; + long lineRed = 0; + long lineGreen = 0; + long lineBlue = 0; + float line2 = 0.0f; + + for (int blueIndex = 1; blueIndex <= MAXSIDEINDEX; ++blueIndex) + { + line += weights[redIndex, greenIndex, blueIndex]; + lineRed += momentsRed[redIndex, greenIndex, blueIndex]; + lineGreen += momentsGreen[redIndex, greenIndex, blueIndex]; + lineBlue += momentsBlue[redIndex, greenIndex, blueIndex]; + line2 += moments[redIndex, greenIndex, blueIndex]; + + area[blueIndex] += line; + areaRed[blueIndex] += lineRed; + areaGreen[blueIndex] += lineGreen; + areaBlue[blueIndex] += lineBlue; + area2[blueIndex] += line2; + + weights[redIndex, greenIndex, blueIndex] = weights[redIndex - 1, greenIndex, blueIndex] + area[blueIndex]; + momentsRed[redIndex, greenIndex, blueIndex] = momentsRed[redIndex - 1, greenIndex, blueIndex] + areaRed[blueIndex]; + momentsGreen[redIndex, greenIndex, blueIndex] = momentsGreen[redIndex - 1, greenIndex, blueIndex] + areaGreen[blueIndex]; + momentsBlue[redIndex, greenIndex, blueIndex] = momentsBlue[redIndex - 1, greenIndex, blueIndex] + areaBlue[blueIndex]; + moments[redIndex, greenIndex, blueIndex] = moments[redIndex - 1, greenIndex, blueIndex] + area2[blueIndex]; + } + } + } + } + + /// + /// Computes the volume of the cube in a specific moment. + /// + private static long Volume(WuColorCube cube, long[,,] moment) + { + return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - + moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; + } + + /// + /// Computes the volume of the cube in a specific moment. For the floating-point values. + /// + private static float VolumeFloat(WuColorCube cube, float[,,] moment) + { + return moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMaximum] - + moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] - + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] - + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]; + } + + /// + /// Splits the cube in given position, and color direction. + /// + private static long Top(WuColorCube cube, int direction, int position, long[,,] moment) + { + return direction switch + { + RED => (moment[position, cube.GreenMaximum, cube.BlueMaximum] - + moment[position, cube.GreenMaximum, cube.BlueMinimum] - + moment[position, cube.GreenMinimum, cube.BlueMaximum] + + moment[position, cube.GreenMinimum, cube.BlueMinimum]), + GREEN => (moment[cube.RedMaximum, position, cube.BlueMaximum] - + moment[cube.RedMaximum, position, cube.BlueMinimum] - + moment[cube.RedMinimum, position, cube.BlueMaximum] + + moment[cube.RedMinimum, position, cube.BlueMinimum]), + BLUE => (moment[cube.RedMaximum, cube.GreenMaximum, position] - + moment[cube.RedMaximum, cube.GreenMinimum, position] - + moment[cube.RedMinimum, cube.GreenMaximum, position] + + moment[cube.RedMinimum, cube.GreenMinimum, position]), + _ => 0, + }; + } + + /// + /// Splits the cube in a given color direction at its minimum. + /// + private static long Bottom(WuColorCube cube, int direction, long[,,] moment) + { + return direction switch + { + RED => (-moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMaximum] + + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), + GREEN => (-moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMaximum] + + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMaximum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), + BLUE => (-moment[cube.RedMaximum, cube.GreenMaximum, cube.BlueMinimum] + + moment[cube.RedMaximum, cube.GreenMinimum, cube.BlueMinimum] + + moment[cube.RedMinimum, cube.GreenMaximum, cube.BlueMinimum] - + moment[cube.RedMinimum, cube.GreenMinimum, cube.BlueMinimum]), + _ => 0 + }; + } + + /// + /// Calculates statistical variance for a given cube. + /// + private float CalculateVariance(WuColorCube cube) + { + float volumeRed = Volume(cube, momentsRed); + float volumeGreen = Volume(cube, momentsGreen); + float volumeBlue = Volume(cube, momentsBlue); + float volumeMoment = VolumeFloat(cube, moments); + float volumeWeight = Volume(cube, weights); + + float distance = volumeRed * volumeRed + volumeGreen * volumeGreen + volumeBlue * volumeBlue; + + return volumeMoment - (distance / volumeWeight); + } + + /// + /// Finds the optimal (maximal) position for the cut. + /// + private float Maximize(WuColorCube cube, int direction, int first, int last, int[] cut, long wholeRed, long wholeGreen, long wholeBlue, long wholeWeight) + { + long bottomRed = Bottom(cube, direction, momentsRed); + long bottomGreen = Bottom(cube, direction, momentsGreen); + long bottomBlue = Bottom(cube, direction, momentsBlue); + long bottomWeight = Bottom(cube, direction, weights); + + float result = 0.0f; + cut[0] = -1; + + for (int position = first; position < last; ++position) + { + // determines the cube cut at a certain position + long halfRed = bottomRed + Top(cube, direction, position, momentsRed); + long halfGreen = bottomGreen + Top(cube, direction, position, momentsGreen); + long halfBlue = bottomBlue + Top(cube, direction, position, momentsBlue); + long halfWeight = bottomWeight + Top(cube, direction, position, weights); + + // the cube cannot be cut at bottom (this would lead to empty cube) + if (halfWeight != 0) + { + float halfDistance = (float) halfRed * halfRed + (float) halfGreen * halfGreen + (float) halfBlue * halfBlue; + float temp = halfDistance / halfWeight; + + halfRed = wholeRed - halfRed; + halfGreen = wholeGreen - halfGreen; + halfBlue = wholeBlue - halfBlue; + halfWeight = wholeWeight - halfWeight; + + if (halfWeight != 0) + { + halfDistance = (float) halfRed * halfRed + (float) halfGreen * halfGreen + (float) halfBlue * halfBlue; + temp += halfDistance / halfWeight; + + if (temp > result) + { + result = temp; + cut[0] = position; + } + } + } + } + + return result; + } + + /// + /// Cuts a cube with another one. + /// + private bool Cut(WuColorCube first, WuColorCube second) + { + int direction; + + int[] cutRed = + { + 0 + }; + int[] cutGreen = + { + 0 + }; + int[] cutBlue = + { + 0 + }; + + long wholeRed = Volume(first, momentsRed); + long wholeGreen = Volume(first, momentsGreen); + long wholeBlue = Volume(first, momentsBlue); + long wholeWeight = Volume(first, weights); + + float maxRed = Maximize(first, RED, first.RedMinimum + 1, first.RedMaximum, cutRed, wholeRed, wholeGreen, wholeBlue, wholeWeight); + float maxGreen = Maximize(first, GREEN, first.GreenMinimum + 1, first.GreenMaximum, cutGreen, wholeRed, wholeGreen, wholeBlue, wholeWeight); + float maxBlue = Maximize(first, BLUE, first.BlueMinimum + 1, first.BlueMaximum, cutBlue, wholeRed, wholeGreen, wholeBlue, wholeWeight); + + if ((maxRed >= maxGreen) && (maxRed >= maxBlue)) + { + direction = RED; + + // cannot split empty cube + if (cutRed[0] < 0) return false; + } + else + { + if ((maxGreen >= maxRed) && (maxGreen >= maxBlue)) + { + direction = GREEN; + } + else + { + direction = BLUE; + } + } + + second.RedMaximum = first.RedMaximum; + second.GreenMaximum = first.GreenMaximum; + second.BlueMaximum = first.BlueMaximum; + + // cuts in a certain direction + switch (direction) + { + case RED: + second.RedMinimum = first.RedMaximum = cutRed[0]; + second.GreenMinimum = first.GreenMinimum; + second.BlueMinimum = first.BlueMinimum; + break; + + case GREEN: + second.GreenMinimum = first.GreenMaximum = cutGreen[0]; + second.RedMinimum = first.RedMinimum; + second.BlueMinimum = first.BlueMinimum; + break; + + case BLUE: + second.BlueMinimum = first.BlueMaximum = cutBlue[0]; + second.RedMinimum = first.RedMinimum; + second.GreenMinimum = first.GreenMinimum; + break; + } + + // determines the volumes after cut + first.Volume = (first.RedMaximum - first.RedMinimum) * (first.GreenMaximum - first.GreenMinimum) * (first.BlueMaximum - first.BlueMinimum); + second.Volume = (second.RedMaximum - second.RedMinimum) * (second.GreenMaximum - second.GreenMinimum) * (second.BlueMaximum - second.BlueMinimum); + + // the cut was successfull + return true; + } + + /// + /// Marks all the tags with a given label. + /// + private void Mark(WuColorCube cube, int label, byte[] tag) + { + for (int redIndex = cube.RedMinimum + 1; redIndex <= cube.RedMaximum; ++redIndex) + { + for (int greenIndex = cube.GreenMinimum + 1; greenIndex <= cube.GreenMaximum; ++greenIndex) + { + for (int blueIndex = cube.BlueMinimum + 1; blueIndex <= cube.BlueMaximum; ++blueIndex) + { + tag[(redIndex << 10) + (redIndex << 6) + redIndex + (greenIndex << 5) + greenIndex + blueIndex] = (byte) label; + } + } + } + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/RegistryKeyExtensions.cs b/src/Greenshot.Base/Core/RegistryKeyExtensions.cs similarity index 93% rename from GreenshotPlugin/Core/RegistryKeyExtensions.cs rename to src/Greenshot.Base/Core/RegistryKeyExtensions.cs index bfdb63e10..a1abcea98 100644 --- a/GreenshotPlugin/Core/RegistryKeyExtensions.cs +++ b/src/Greenshot.Base/Core/RegistryKeyExtensions.cs @@ -22,7 +22,7 @@ using System; using Microsoft.Win32; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// A helper class for accessing the registry @@ -50,22 +50,26 @@ namespace GreenshotPlugin.Core if (key != null) { - result = (string)key.GetValue(value); + result = (string) key.GetValue(value); } + if (string.IsNullOrEmpty(result)) { result = defaultValue; } + return result; } + using var registryKey64 = RegistryKey.OpenBaseKey(registryHive, RegistryView.Registry64); // Logic for 64 bit Windows, is trying the key which is 64 bit using (var key = registryKey64.OpenSubKey($@"SOFTWARE\{keyName}", false)) { if (key != null) { - result = (string)key.GetValue(value); + result = (string) key.GetValue(value); } + if (!string.IsNullOrEmpty(result)) return result; } @@ -74,7 +78,7 @@ namespace GreenshotPlugin.Core { if (key != null) { - result = (string)key.GetValue(value); + result = (string) key.GetValue(value); } } @@ -82,6 +86,7 @@ namespace GreenshotPlugin.Core { result = defaultValue; } + return result; } } diff --git a/GreenshotPlugin/Core/SimpleServiceProvider.cs b/src/Greenshot.Base/Core/SimpleServiceProvider.cs similarity index 92% rename from GreenshotPlugin/Core/SimpleServiceProvider.cs rename to src/Greenshot.Base/Core/SimpleServiceProvider.cs index 9ffd9d590..bff814540 100644 --- a/GreenshotPlugin/Core/SimpleServiceProvider.cs +++ b/src/Greenshot.Base/Core/SimpleServiceProvider.cs @@ -1,59 +1,61 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using GreenshotPlugin.Interfaces; - -namespace GreenshotPlugin.Core -{ - /// - /// A really cheap and simple DI system - /// - public class SimpleServiceProvider : IServiceLocator - { - private readonly Dictionary> _services = new Dictionary>(); - - public static IServiceLocator Current { get; } = new SimpleServiceProvider(); - - public IEnumerable GetAllInstances() - { - var typeOfService = typeof(TService); - if (!_services.TryGetValue(typeOfService, out var results)) - { - yield break; - } - foreach (TService result in results) - { - yield return result; - } - } - - public TService GetInstance() - { - return GetAllInstances().SingleOrDefault(); - } - - public void AddService(IEnumerable services) - { - var serviceType = typeof(TService); - if (!_services.TryGetValue(serviceType, out var currentServices)) - { - currentServices = new List(); - _services.Add(serviceType, currentServices); - } - - foreach (var service in services) - { - if (service == null) - { - continue; - } - currentServices.Add(service); - } - } - - public void AddService(params TService[] services) - { - AddService(services.AsEnumerable()); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Base.Core +{ + /// + /// A really cheap and simple DI system + /// + public class SimpleServiceProvider : IServiceLocator + { + private readonly Dictionary> _services = new Dictionary>(); + + public static IServiceLocator Current { get; } = new SimpleServiceProvider(); + + public IEnumerable GetAllInstances() + { + var typeOfService = typeof(TService); + if (!_services.TryGetValue(typeOfService, out var results)) + { + yield break; + } + + foreach (TService result in results) + { + yield return result; + } + } + + public TService GetInstance() + { + return GetAllInstances().SingleOrDefault(); + } + + public void AddService(IEnumerable services) + { + var serviceType = typeof(TService); + if (!_services.TryGetValue(serviceType, out var currentServices)) + { + currentServices = new List(); + _services.Add(serviceType, currentServices); + } + + foreach (var service in services) + { + if (service == null) + { + continue; + } + + currentServices.Add(service); + } + } + + public void AddService(params TService[] services) + { + AddService(services.AsEnumerable()); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/StringExtensions.cs b/src/Greenshot.Base/Core/StringExtensions.cs new file mode 100644 index 000000000..1265e3616 --- /dev/null +++ b/src/Greenshot.Base/Core/StringExtensions.cs @@ -0,0 +1,163 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using log4net; + +namespace Greenshot.Base.Core +{ + public static class StringExtensions + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(StringExtensions)); + private const string RGBIV = "dlgjowejgogkklwj"; + private const string KEY = "lsjvkwhvwujkagfauguwcsjgu2wueuff"; + + /// + /// Format a string with the specified object + /// + /// String with formatting, like {name} + /// Object used for the formatting + /// Formatted string + public static string FormatWith(this string format, object source) + { + return FormatWith(format, null, source); + } + + /// + /// Format the string "format" with the source + /// + /// + /// + /// object with properties, if a property has the type IDictionary string,string it can used these parameters too + /// Formatted string + public static string FormatWith(this string format, IFormatProvider provider, object source) + { + if (format == null) + { + throw new ArgumentNullException(nameof(format)); + } + + IDictionary properties = new Dictionary(); + foreach (var propertyInfo in source.GetType().GetProperties()) + { + if (propertyInfo.CanRead && propertyInfo.CanWrite) + { + object value = propertyInfo.GetValue(source, null); + if (propertyInfo.PropertyType != typeof(IDictionary)) + { + properties.Add(propertyInfo.Name, value); + } + else + { + IDictionary dictionary = (IDictionary) value; + foreach (var propertyKey in dictionary.Keys) + { + properties.Add(propertyKey, dictionary[propertyKey]); + } + } + } + } + + Regex r = new Regex(@"(?\{)+(?[\w\.\[\]]+)(?:[^}]+)?(?\})+", + RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); + + List values = new List(); + string rewrittenFormat = r.Replace(format, delegate(Match m) + { + Group startGroup = m.Groups["start"]; + Group propertyGroup = m.Groups["property"]; + Group formatGroup = m.Groups["format"]; + Group endGroup = m.Groups["end"]; + + values.Add(properties.TryGetValue(propertyGroup.Value, out var value) ? value : source); + return new string('{', startGroup.Captures.Count) + (values.Count - 1) + formatGroup.Value + new string('}', endGroup.Captures.Count); + }); + + return string.Format(provider, rewrittenFormat, values.ToArray()); + } + + /// + /// A simply rijndael aes encryption, can be used to store passwords + /// + /// the string to call upon + /// an encryped string in base64 form + public static string Encrypt(this string clearText) + { + string returnValue = clearText; + try + { + byte[] clearTextBytes = Encoding.ASCII.GetBytes(clearText); + SymmetricAlgorithm rijn = SymmetricAlgorithm.Create(); + + using MemoryStream ms = new MemoryStream(); + byte[] rgbIV = Encoding.ASCII.GetBytes(RGBIV); + byte[] key = Encoding.ASCII.GetBytes(KEY); + using CryptoStream cs = new CryptoStream(ms, rijn.CreateEncryptor(key, rgbIV), CryptoStreamMode.Write); + cs.Write(clearTextBytes, 0, clearTextBytes.Length); + cs.FlushFinalBlock(); + + returnValue = Convert.ToBase64String(ms.ToArray()); + } + catch (Exception ex) + { + LOG.ErrorFormat("Error encrypting, error: {0}", ex.Message); + } + + return returnValue; + } + + /// + /// A simply rijndael aes decryption, can be used to store passwords + /// + /// a base64 encoded rijndael encrypted string + /// Decrypeted text + public static string Decrypt(this string encryptedText) + { + string returnValue = encryptedText; + try + { + byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText); + using MemoryStream ms = new MemoryStream(); + SymmetricAlgorithm rijn = SymmetricAlgorithm.Create(); + + + byte[] rgbIV = Encoding.ASCII.GetBytes(RGBIV); + byte[] key = Encoding.ASCII.GetBytes(KEY); + + using CryptoStream cs = new CryptoStream(ms, rijn.CreateDecryptor(key, rgbIV), CryptoStreamMode.Write); + cs.Write(encryptedTextBytes, 0, encryptedTextBytes.Length); + cs.FlushFinalBlock(); + returnValue = Encoding.ASCII.GetString(ms.ToArray()); + } + catch (Exception ex) + { + LOG.ErrorFormat("Error decrypting {0}, error: {1}", encryptedText, ex.Message); + } + + return returnValue; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/SvgImage.cs b/src/Greenshot.Base/Core/SvgImage.cs new file mode 100644 index 000000000..f04e8c0df --- /dev/null +++ b/src/Greenshot.Base/Core/SvgImage.cs @@ -0,0 +1,117 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using Svg; + +namespace Greenshot.Base.Core +{ + /// + /// Create an image look like of the SVG + /// + public sealed class SvgImage : IImage + { + private readonly SvgDocument _svgDocument; + + private Image _imageClone; + + /// + /// Factory to create via a stream + /// + /// Stream + /// IImage + public static IImage FromStream(Stream stream) + { + return new SvgImage(stream); + } + + /// + /// Default constructor + /// + /// + public SvgImage(Stream stream) + { + _svgDocument = SvgDocument.Open(stream); + Height = (int) _svgDocument.ViewBox.Height; + Width = (int) _svgDocument.ViewBox.Width; + } + + /// + /// Height of the image, can be set to change + /// + public int Height { get; set; } + + /// + /// Width of the image, can be set to change. + /// + public int Width { get; set; } + + /// + /// Size of the image + /// + public Size Size => new Size(Width, Height); + + /// + /// Pixelformat of the underlying image + /// + public PixelFormat PixelFormat => Image.PixelFormat; + + /// + /// Horizontal resolution of the underlying image + /// + public float HorizontalResolution => Image.HorizontalResolution; + + /// + /// Vertical resolution of the underlying image + /// + public float VerticalResolution => Image.VerticalResolution; + + /// + /// Underlying image, or an on demand rendered version with different attributes as the original + /// + public Image Image + { + get + { + if (_imageClone?.Height == Height && _imageClone?.Width == Width) + { + return _imageClone; + } + + // Calculate new image clone + _imageClone?.Dispose(); + _imageClone = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent, 96, 96); + _svgDocument.Draw((Bitmap) _imageClone); + return _imageClone; + } + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + _imageClone?.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/WindowCapture.cs b/src/Greenshot.Base/Core/WindowCapture.cs new file mode 100644 index 000000000..7d5c751d9 --- /dev/null +++ b/src/Greenshot.Base/Core/WindowCapture.cs @@ -0,0 +1,444 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Structs; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// The Window Capture code + /// + public static class WindowCapture + { + private static readonly ILog Log = LogManager.GetLogger(typeof(WindowCapture)); + private static readonly CoreConfiguration Configuration = IniConfig.GetIniSection(); + + /// + /// Used to cleanup the unmanaged resource in the iconInfo for the CaptureCursor method + /// + /// + /// + [DllImport("gdi32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteObject(IntPtr hObject); + + /// + /// Get the bounds of all screens combined. + /// + /// A Rectangle of the bounds of the entire display area. + public static Rectangle GetScreenBounds() + { + int left = 0, top = 0, bottom = 0, right = 0; + foreach (Screen screen in Screen.AllScreens) + { + left = Math.Min(left, screen.Bounds.X); + top = Math.Min(top, screen.Bounds.Y); + int screenAbsRight = screen.Bounds.X + screen.Bounds.Width; + int screenAbsBottom = screen.Bounds.Y + screen.Bounds.Height; + right = Math.Max(right, screenAbsRight); + bottom = Math.Max(bottom, screenAbsBottom); + } + + return new Rectangle(left, top, (right + Math.Abs(left)), (bottom + Math.Abs(top))); + } + + /// + /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. This implementation + /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. + /// + /// + /// Point with cursor location, relative to the top left corner of the monitor setup (which itself might actually not be on any screen) + /// + public static Point GetCursorLocationRelativeToScreenBounds() + { + return GetLocationRelativeToScreenBounds(User32.GetCursorLocation()); + } + + /// + /// Converts locationRelativeToScreenOrigin to be relative to top left corner of all screen bounds, which might + /// be different in multi-screen setups. This implementation + /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. + /// + /// + /// Point + public static Point GetLocationRelativeToScreenBounds(Point locationRelativeToScreenOrigin) + { + Point ret = locationRelativeToScreenOrigin; + Rectangle bounds = GetScreenBounds(); + ret.Offset(-bounds.X, -bounds.Y); + return ret; + } + + /// + /// This method will capture the current Cursor by using User32 Code + /// + /// A Capture Object with the Mouse Cursor information in it. + public static ICapture CaptureCursor(ICapture capture) + { + Log.Debug("Capturing the mouse cursor."); + if (capture == null) + { + capture = new Capture(); + } + + var cursorInfo = new CursorInfo(); + cursorInfo.cbSize = Marshal.SizeOf(cursorInfo); + if (!User32.GetCursorInfo(out cursorInfo)) return capture; + if (cursorInfo.flags != User32.CURSOR_SHOWING) return capture; + + using SafeIconHandle safeIcon = User32.CopyIcon(cursorInfo.hCursor); + if (!User32.GetIconInfo(safeIcon, out var iconInfo)) return capture; + + Point cursorLocation = User32.GetCursorLocation(); + // Align cursor location to Bitmap coordinates (instead of Screen coordinates) + var x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X; + var y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y; + // Set the location + capture.CursorLocation = new Point(x, y); + + using (Icon icon = Icon.FromHandle(safeIcon.DangerousGetHandle())) + { + capture.Cursor = icon; + } + + if (iconInfo.hbmMask != IntPtr.Zero) + { + DeleteObject(iconInfo.hbmMask); + } + + if (iconInfo.hbmColor != IntPtr.Zero) + { + DeleteObject(iconInfo.hbmColor); + } + + return capture; + } + + /// + /// This method will call the CaptureRectangle with the screenbounds, therefor Capturing the whole screen. + /// + /// A Capture Object with the Screen as an Image + public static ICapture CaptureScreen(ICapture capture) + { + if (capture == null) + { + capture = new Capture(); + } + + return CaptureRectangle(capture, capture.ScreenBounds); + } + + /// + /// Helper method to create an exception that might explain what is wrong while capturing + /// + /// string with current method + /// Rectangle of what we want to capture + /// + private static Exception CreateCaptureException(string method, Rectangle captureBounds) + { + Exception exceptionToThrow = User32.CreateWin32Exception(method); + if (!captureBounds.IsEmpty) + { + exceptionToThrow.Data.Add("Height", captureBounds.Height); + exceptionToThrow.Data.Add("Width", captureBounds.Width); + } + + return exceptionToThrow; + } + + /// + /// Helper method to check if it is allowed to capture the process using DWM + /// + /// Process owning the window + /// true if it's allowed + public static bool IsDwmAllowed(Process process) + { + if (process == null) return true; + if (Configuration.NoDWMCaptureForProduct == null || + Configuration.NoDWMCaptureForProduct.Count <= 0) return true; + + try + { + string productName = process.MainModule?.FileVersionInfo.ProductName; + if (productName != null && Configuration.NoDWMCaptureForProduct.Contains(productName.ToLower())) + { + return false; + } + } + catch (Exception ex) + { + Log.Warn(ex.Message); + } + + return true; + } + + /// + /// Helper method to check if it is allowed to capture the process using GDI + /// + /// Process owning the window + /// true if it's allowed + public static bool IsGdiAllowed(Process process) + { + if (process == null) return true; + if (Configuration.NoGDICaptureForProduct == null || + Configuration.NoGDICaptureForProduct.Count <= 0) return true; + + try + { + string productName = process.MainModule?.FileVersionInfo.ProductName; + if (productName != null && Configuration.NoGDICaptureForProduct.Contains(productName.ToLower())) + { + return false; + } + } + catch (Exception ex) + { + Log.Warn(ex.Message); + } + + return true; + } + + /// + /// This method will use User32 code to capture the specified captureBounds from the screen + /// + /// ICapture where the captured Bitmap will be stored + /// Rectangle with the bounds to capture + /// A Capture Object with a part of the Screen as an Image + public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds) + { + if (capture == null) + { + capture = new Capture(); + } + + Image capturedImage = null; + // If the CaptureHandler has a handle use this, otherwise use the CaptureRectangle here + if (CaptureHandler.CaptureScreenRectangle != null) + { + try + { + capturedImage = CaptureHandler.CaptureScreenRectangle(captureBounds); + } + catch + { + // ignored + } + } + + // If no capture, use the normal screen capture + if (capturedImage == null) + { + capturedImage = CaptureRectangle(captureBounds); + } + + capture.Image = capturedImage; + capture.Location = captureBounds.Location; + return capture.Image == null ? null : capture; + } + + /// + /// This method will use User32 code to capture the specified captureBounds from the screen + /// + /// ICapture where the captured Bitmap will be stored + /// Rectangle with the bounds to capture + /// A Capture Object with a part of the Screen as an Image + public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, Rectangle captureBounds) + { + if (capture == null) + { + capture = new Capture(); + } + + capture.Image = CaptureRectangle(captureBounds); + capture.Location = captureBounds.Location; + return capture.Image == null ? null : capture; + } + + /// + /// This method will use User32 code to capture the specified captureBounds from the screen + /// + /// Rectangle with the bounds to capture + /// Bitmap which is captured from the screen at the location specified by the captureBounds + public static Bitmap CaptureRectangle(Rectangle captureBounds) + { + Bitmap returnBitmap = null; + if (captureBounds.Height <= 0 || captureBounds.Width <= 0) + { + Log.Warn("Nothing to capture, ignoring!"); + return null; + } + + Log.Debug("CaptureRectangle Called!"); + + // .NET GDI+ Solution, according to some post this has a GDI+ leak... + // See http://connect.microsoft.com/VisualStudio/feedback/details/344752/gdi-object-leak-when-calling-graphics-copyfromscreen + // Bitmap capturedBitmap = new Bitmap(captureBounds.Width, captureBounds.Height); + // using (Graphics graphics = Graphics.FromImage(capturedBitmap)) { + // graphics.CopyFromScreen(captureBounds.Location, Point.Empty, captureBounds.Size, CopyPixelOperation.CaptureBlt); + // } + // capture.Image = capturedBitmap; + // capture.Location = captureBounds.Location; + + using (var desktopDcHandle = SafeWindowDcHandle.FromDesktop()) + { + if (desktopDcHandle.IsInvalid) + { + // Get Exception before the error is lost + Exception exceptionToThrow = CreateCaptureException("desktopDCHandle", captureBounds); + // throw exception + throw exceptionToThrow; + } + + // create a device context we can copy to + using SafeCompatibleDCHandle safeCompatibleDcHandle = GDI32.CreateCompatibleDC(desktopDcHandle); + // Check if the device context is there, if not throw an error with as much info as possible! + if (safeCompatibleDcHandle.IsInvalid) + { + // Get Exception before the error is lost + Exception exceptionToThrow = CreateCaptureException("CreateCompatibleDC", captureBounds); + // throw exception + throw exceptionToThrow; + } + + // Create BITMAPINFOHEADER for CreateDIBSection + BITMAPINFOHEADER bmi = new BITMAPINFOHEADER(captureBounds.Width, captureBounds.Height, 24); + + // Make sure the last error is set to 0 + Win32.SetLastError(0); + + // create a bitmap we can copy it to, using GetDeviceCaps to get the width/height + using SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDcHandle, ref bmi, BITMAPINFOHEADER.DIB_RGB_COLORS, out _, IntPtr.Zero, 0); + if (safeDibSectionHandle.IsInvalid) + { + // Get Exception before the error is lost + var exceptionToThrow = CreateCaptureException("CreateDIBSection", captureBounds); + exceptionToThrow.Data.Add("hdcDest", safeCompatibleDcHandle.DangerousGetHandle().ToInt32()); + exceptionToThrow.Data.Add("hdcSrc", desktopDcHandle.DangerousGetHandle().ToInt32()); + + // Throw so people can report the problem + throw exceptionToThrow; + } + + // select the bitmap object and store the old handle + using (safeCompatibleDcHandle.SelectObject(safeDibSectionHandle)) + { + // bitblt over (make copy) + // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags + GDI32.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y, + CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt); + } + + // get a .NET image object for it + // A suggestion for the "A generic error occurred in GDI+." E_FAIL/0�80004005 error is to re-try... + bool success = false; + ExternalException exception = null; + for (int i = 0; i < 3; i++) + { + try + { + // Collect all screens inside this capture + List screensInsideCapture = new List(); + foreach (Screen screen in Screen.AllScreens) + { + if (screen.Bounds.IntersectsWith(captureBounds)) + { + screensInsideCapture.Add(screen); + } + } + + // Check all all screens are of an equal size + bool offscreenContent; + using (Region captureRegion = new Region(captureBounds)) + { + // Exclude every visible part + foreach (Screen screen in screensInsideCapture) + { + captureRegion.Exclude(screen.Bounds); + } + + // If the region is not empty, we have "offscreenContent" + using Graphics screenGraphics = Graphics.FromHwnd(User32.GetDesktopWindow()); + offscreenContent = !captureRegion.IsEmpty(screenGraphics); + } + + // Check if we need to have a transparent background, needed for offscreen content + if (offscreenContent) + { + using Bitmap tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); + // Create a new bitmap which has a transparent background + returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, + tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution); + // Content will be copied here + using Graphics graphics = Graphics.FromImage(returnBitmap); + // For all screens copy the content to the new bitmap + foreach (Screen screen in Screen.AllScreens) + { + Rectangle screenBounds = screen.Bounds; + // Make sure the bounds are offsetted to the capture bounds + screenBounds.Offset(-captureBounds.X, -captureBounds.Y); + graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel); + } + } + else + { + // All screens, which are inside the capture, are of equal size + // assign image to Capture, the image will be disposed there.. + returnBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); + } + + // We got through the capture without exception + success = true; + break; + } + catch (ExternalException ee) + { + Log.Warn("Problem getting bitmap at try " + i + " : ", ee); + exception = ee; + } + } + + if (!success) + { + Log.Error("Still couldn't create Bitmap!"); + if (exception != null) + { + throw exception; + } + } + } + + return returnBitmap; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/WindowDetails.cs b/src/Greenshot.Base/Core/WindowDetails.cs similarity index 77% rename from GreenshotPlugin/Core/WindowDetails.cs rename to src/Greenshot.Base/Core/WindowDetails.cs index 7c9a2b905..c656e586c 100644 --- a/GreenshotPlugin/Core/WindowDetails.cs +++ b/src/Greenshot.Base/Core/WindowDetails.cs @@ -1,1543 +1,1874 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.RegularExpressions; -using System.Windows.Forms; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interop; -using GreenshotPlugin.UnmanagedHelpers; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using GreenshotPlugin.UnmanagedHelpers.Structs; -using log4net; - -namespace GreenshotPlugin.Core -{ - /// - /// Code for handling with "windows" - /// Main code is taken from vbAccelerator, location: - /// http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows/Enumerating_Windows/article.asp - /// but a LOT of changes/enhancements were made to adapt it for Greenshot. - /// - /// Provides details about a Window returned by the enumeration - /// - public class WindowDetails : IEquatable { - private const string AppWindowClass = "Windows.UI.Core.CoreWindow"; //Used for Windows 8(.1) - private const string AppFrameWindowClass = "ApplicationFrameWindow"; // Windows 10 uses ApplicationFrameWindow - private const string ApplauncherClass = "ImmersiveLauncher"; - private const string GutterClass = "ImmersiveGutter"; - private static readonly IList IgnoreClasses = new List(new[] { "Progman", "Button", "Dwm" }); //"MS-SDIa" - - private static readonly ILog Log = LogManager.GetLogger(typeof(WindowDetails)); - private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); - private static readonly IList IgnoreHandles = new List(); - private static readonly IList ExcludeProcessesFromFreeze = new List(); - private static readonly IAppVisibility AppVisibility; - - static WindowDetails() { - try - { - // Only try to instantiate when Windows 8 or later. - if (WindowsVersion.IsWindows8OrLater) - { - AppVisibility = COMWrapper.CreateInstance(); - } - } - catch (Exception ex) - { - Log.WarnFormat("Couldn't create instance of IAppVisibility: {0}", ex.Message); - } - } - - public static void AddProcessToExcludeFromFreeze(string processName) { - if (!ExcludeProcessesFromFreeze.Contains(processName)) { - ExcludeProcessesFromFreeze.Add(processName); - } - } - - internal static bool IsIgnoreHandle(IntPtr handle) { - return IgnoreHandles.Contains(handle); - } - - private IList _childWindows; - private IntPtr _parentHandle = IntPtr.Zero; - private WindowDetails _parent; - private bool _frozen; - - /// - /// This checks if the window is a Windows 8 App - /// For Windows 10 most normal code works, as it's hosted inside "ApplicationFrameWindow" - /// - public bool IsApp => AppWindowClass.Equals(ClassName); - - /// - /// This checks if the window is a Windows 10 App - /// For Windows 10 apps are hosted inside "ApplicationFrameWindow" - /// - public bool IsWin10App => AppFrameWindowClass.Equals(ClassName); - - /// - /// Check if this window belongs to a background app - /// - public bool IsBackgroundWin10App => WindowsVersion.IsWindows10OrLater && AppFrameWindowClass.Equals(ClassName) && !Children.Any(window => string.Equals(window.ClassName, AppWindowClass)); - - /// - /// Check if the window is the metro gutter (sizeable separator) - /// - public bool IsGutter => GutterClass.Equals(ClassName); - - /// - /// Test if this window is for the App-Launcher - /// - public bool IsAppLauncher => ApplauncherClass.Equals(ClassName); - - /// - /// Check if this window is the window of a metro app - /// - public bool IsMetroApp => IsAppLauncher || IsApp; - - /// - /// To allow items to be compared, the hash code - /// is set to the Window handle, so two EnumWindowsItem - /// objects for the same Window will be equal. - /// - /// The Window Handle for this window - public override int GetHashCode() { - return Handle.ToInt32(); - } - - public override bool Equals(object right) { - return Equals(right as WindowDetails); - } - - /// - /// Compare two windows details - /// - /// - /// - public bool Equals(WindowDetails other) { - if (other is null) { - return false; - } - - if (ReferenceEquals(this, other)) { - return true; - } - - if (GetType() != other.GetType()){ - return false; - } - return other.Handle == Handle; - } - - /// - /// Check if the window has children - /// - public bool HasChildren => (_childWindows != null) && (_childWindows.Count > 0); - - /// - /// Freeze information updates - /// - public void FreezeDetails() { - _frozen = true; - } - - /// - /// Make the information update again. - /// - public void UnfreezeDetails() { - _frozen = false; - } - - /// - /// Get the file path to the exe for the process which owns this window - /// - public string ProcessPath { - get { - if (Handle == IntPtr.Zero) { - // not a valid window handle - return string.Empty; - } - // Get the process id - User32.GetWindowThreadProcessId(Handle, out var processId); - return Kernel32.GetProcessPath(processId); - } - } - - - /// - /// Get the icon belonging to the process - /// - public Image DisplayIcon { - get { - try - { - using var appIcon = GetAppIcon(Handle); - if (appIcon != null) { - return appIcon.ToBitmap(); - } - } catch (Exception ex) { - Log.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); - Log.Warn(ex); - } - if (IsMetroApp) { - // No method yet to get the metro icon - return null; - } - try { - return PluginUtils.GetCachedExeIcon(ProcessPath, 0); - } catch (Exception ex) { - Log.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); - Log.Warn(ex); - } - return null; - } - } - - /// - /// Get the icon for a hWnd - /// - /// - /// - private static Icon GetAppIcon(IntPtr hWnd) { - IntPtr iconSmall = IntPtr.Zero; - IntPtr iconBig = new IntPtr(1); - IntPtr iconSmall2 = new IntPtr(2); - - IntPtr iconHandle; - if (Conf.UseLargeIcons) { - iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); - if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hWnd, (int)ClassLongIndex.GCL_HICON); - } - } else { - iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconSmall2, IntPtr.Zero); - } - if (iconHandle == IntPtr.Zero) { - iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconSmall, IntPtr.Zero); - } - if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hWnd, (int)ClassLongIndex.GCL_HICONSM); - } - if (iconHandle == IntPtr.Zero) { - iconHandle = User32.SendMessage(hWnd, (int)WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); - } - if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hWnd, (int)ClassLongIndex.GCL_HICON); - } - - if (iconHandle == IntPtr.Zero) { - return null; - } - - Icon icon = Icon.FromHandle(iconHandle); - - return icon; - } - - /// - /// Use this to make remove internal windows, like the mainform and the captureforms, invisible - /// - /// - public static void RegisterIgnoreHandle(IntPtr ignoreHandle) { - IgnoreHandles.Add(ignoreHandle); - } - - /// - /// Use this to remove the with RegisterIgnoreHandle registered handle - /// - /// - public static void UnregisterIgnoreHandle(IntPtr ignoreHandle) { - IgnoreHandles.Remove(ignoreHandle); - } - - public IList Children { - get { - if (_childWindows == null) { - GetChildren(); - } - return _childWindows; - } - } - - /// - /// Retrieve the child with matching classname - /// - public WindowDetails GetChild(string childClassname) { - foreach(var child in Children) { - if (childClassname.Equals(child.ClassName)) { - return child; - } - } - return null; - } - - public IntPtr ParentHandle { - get { - if (_parentHandle == IntPtr.Zero) { - _parentHandle = User32.GetParent(Handle); - _parent = null; - } - return _parentHandle; - } - set { - if (_parentHandle != value) { - _parentHandle = value; - _parent = null; - } - } - } - /// - /// Get the parent of the current window - /// - /// WindowDetails of the parent, or null if none - public WindowDetails GetParent() { - if (_parent == null) { - if (_parentHandle == IntPtr.Zero) { - _parentHandle = User32.GetParent(Handle); - } - if (_parentHandle != IntPtr.Zero) { - _parent = new WindowDetails(_parentHandle); - } - } - return _parent; - } - - /// - /// Retrieve all the children, this only stores the children internally. - /// One should normally use the getter "Children" - /// - public IList GetChildren() { - if (_childWindows == null) { - return GetChildren(0); - } - return _childWindows; - } - - /// - /// Retrieve all the children, this only stores the children internally, use the "Children" property for the value - /// - /// Specify how many levels we go in - public IList GetChildren(int levelsToGo) { - if (_childWindows != null) - { - return _childWindows; - } - _childWindows = new WindowsEnumerator().GetWindows(Handle, null).Items; - foreach(var childWindow in _childWindows) { - if (levelsToGo > 0) { - childWindow.GetChildren(levelsToGo-1); - } - } - return _childWindows; - } - - /// - /// Gets the window's handle - /// - public IntPtr Handle { get; } - - private string _text; - /// - /// Gets the window's title (caption) - /// - public string Text { - set => _text = value; - get { - if (_text == null) { - var title = new StringBuilder(260, 260); - User32.GetWindowText(Handle, title, title.Capacity); - _text = title.ToString(); - } - return _text; - } - } - - private string _className; - /// - /// Gets the window's class name. - /// - public string ClassName => _className ??= GetClassName(Handle); - - /// - /// Gets/Sets whether the window is iconic (minimized) or not. - /// - public bool Iconic { - get { - if (IsMetroApp) { - return !Visible; - } - return User32.IsIconic(Handle) || Location.X <= -32000; - } - set { - if (value) { - User32.SendMessage(Handle, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_MINIMIZE, IntPtr.Zero); - } else { - User32.SendMessage(Handle, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_RESTORE, IntPtr.Zero); - } - } - } - - /// - /// Gets/Sets whether the window is maximized or not. - /// - public bool Maximised { - get { - if (IsApp) - { - if (Visible) { - Rectangle windowRectangle = WindowRectangle; - foreach (var screen in Screen.AllScreens) { - if (screen.Bounds.Contains(windowRectangle)) { - if (windowRectangle.Equals(screen.Bounds)) { - return true; - } - } - } - } - return false; - } - return User32.IsZoomed(Handle); - } - set { - if (value) { - User32.SendMessage(Handle, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_MAXIMIZE, IntPtr.Zero); - } else { - User32.SendMessage(Handle, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_MINIMIZE, IntPtr.Zero); - } - } - } - - /// - /// Returns if this window is cloaked - /// - public bool IsCloaked - { - get => DWM.IsWindowCloaked(Handle); - } - - /// - /// Gets whether the window is visible. - /// - public bool Visible { - get { - // Tip from Raymond Chen https://devblogs.microsoft.com/oldnewthing/20200302-00/?p=103507 - if (IsCloaked) - { - return false; - } - if (IsApp) { - Rectangle windowRectangle = WindowRectangle; - foreach (Screen screen in Screen.AllScreens) { - if (screen.Bounds.Contains(windowRectangle)) { - if (windowRectangle.Equals(screen.Bounds)) { - // Fullscreen, it's "visible" when AppVisibilityOnMonitor says yes - // Although it might be the other App, this is not "very" important - RECT rect = new RECT(screen.Bounds); - IntPtr monitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONULL); - if (monitor != IntPtr.Zero) { - MONITOR_APP_VISIBILITY? monitorAppVisibility = AppVisibility?.GetAppVisibilityOnMonitor(monitor); - //LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds); - if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) { - return true; - } - } - } else { - // Is only partly on the screen, when this happens the app is always visible! - return true; - } - } - } - return false; - } - if (IsGutter) { - // gutter is only made available when it's visible - return true; - } - if (IsAppLauncher) { - return IsAppLauncherVisible; - } - return User32.IsWindowVisible(Handle); - } - } - - public bool HasParent { - get { - GetParent(); - return _parentHandle != IntPtr.Zero; - } - } - - public int ProcessId { - get { - User32.GetWindowThreadProcessId(Handle, out var processId); - return processId; - } - } - - public Process Process { - get { - try { - User32.GetWindowThreadProcessId(Handle, out var processId); - return Process.GetProcessById(processId); - } catch (Exception ex) { - Log.Warn(ex); - } - return null; - } - } - - private Rectangle _previousWindowRectangle = Rectangle.Empty; - private long _lastWindowRectangleRetrieveTime; - private const long CacheTime = TimeSpan.TicksPerSecond * 2; - - /// - /// Gets the bounding rectangle of the window - /// - public Rectangle WindowRectangle { - get { - // Try to return a cached value - long now = DateTime.Now.Ticks; - if (_previousWindowRectangle.IsEmpty || !_frozen) { - if (!_previousWindowRectangle.IsEmpty && now - _lastWindowRectangleRetrieveTime <= CacheTime) - { - return _previousWindowRectangle; - } - Rectangle windowRect = Rectangle.Empty; - if (DWM.IsDwmEnabled) - { - bool gotFrameBounds = GetExtendedFrameBounds(out windowRect); - if (IsApp) - { - // Pre-Cache for maximized call, this is only on Windows 8 apps (full screen) - if (gotFrameBounds) - { - _previousWindowRectangle = windowRect; - _lastWindowRectangleRetrieveTime = now; - } - } - if (gotFrameBounds && WindowsVersion.IsWindows10OrLater && !Maximised) - { - // Somehow DWM doesn't calculate it corectly, there is a 1 pixel border around the capture - // Remove this border, currently it's fixed but TODO: Make it depend on the OS? - windowRect.Inflate(Conf.Win10BorderCrop); - _previousWindowRectangle = windowRect; - _lastWindowRectangleRetrieveTime = now; - return windowRect; - } - } - - if (windowRect.IsEmpty) { - if (!GetWindowRect(out windowRect)) - { - Win32Error error = Win32.GetLastErrorCode(); - Log.WarnFormat("Couldn't retrieve the windows rectangle: {0}", Win32.GetMessage(error)); - } - } - - // Correction for maximized windows, only if it's not an app - if (!HasParent && !IsApp && Maximised) { - // Only if the border size can be retrieved - if (GetBorderSize(out var size)) - { - windowRect = new Rectangle(windowRect.X + size.Width, windowRect.Y + size.Height, windowRect.Width - (2 * size.Width), windowRect.Height - (2 * size.Height)); - } - } - _lastWindowRectangleRetrieveTime = now; - // Try to return something valid, by getting returning the previous size if the window doesn't have a Rectangle anymore - if (windowRect.IsEmpty) { - return _previousWindowRectangle; - } - _previousWindowRectangle = windowRect; - return windowRect; - } - return _previousWindowRectangle; - } - } - - /// - /// Gets the location of the window relative to the screen. - /// - public Point Location { - get { - Rectangle tmpRectangle = WindowRectangle; - return new Point(tmpRectangle.Left, tmpRectangle.Top); - } - } - - /// - /// Gets the size of the window. - /// - public Size Size { - get { - Rectangle tmpRectangle = WindowRectangle; - return new Size(tmpRectangle.Right - tmpRectangle.Left, tmpRectangle.Bottom - tmpRectangle.Top); - } - } - - /// - /// Get the client rectangle, this is the part of the window inside the borders (drawable area) - /// - public Rectangle ClientRectangle { - get { - if (!GetClientRect(out var clientRect)) - { - Win32Error error = Win32.GetLastErrorCode(); - Log.WarnFormat("Couldn't retrieve the client rectangle for {0}, error: {1}", Text, Win32.GetMessage(error)); - } - return clientRect; - } - } - - /// - /// Check if the supplied point lies in the window - /// - /// Point with the coordinates to check - /// true if the point lies within - public bool Contains(Point p) { - return WindowRectangle.Contains(p); - } - - /// - /// Restores and Brings the window to the front, - /// assuming it is a visible application window. - /// - public void Restore() { - if (Iconic) { - User32.SendMessage(Handle, (int)WindowsMessages.WM_SYSCOMMAND, (IntPtr)User32.SC_RESTORE, IntPtr.Zero); - } - User32.BringWindowToTop(Handle); - User32.SetForegroundWindow(Handle); - // Make sure windows has time to perform the action - // TODO: this is BAD practice! - while(Iconic) { - Application.DoEvents(); - } - } - - /// - /// Get / Set the WindowStyle - /// - public WindowStyleFlags WindowStyle { - get => (WindowStyleFlags)User32.GetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_STYLE); - set => User32.SetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_STYLE, new IntPtr((long)value)); - } - - /// - /// Get/Set the WindowPlacement - /// - public WindowPlacement WindowPlacement { - get { - var placement = WindowPlacement.Default; - User32.GetWindowPlacement(Handle, ref placement); - return placement; - } - set { - User32.SetWindowPlacement(Handle, ref value); - } - } - - /// - /// Get/Set the Extended WindowStyle - /// - public ExtendedWindowStyleFlags ExtendedWindowStyle { - get => (ExtendedWindowStyleFlags)User32.GetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_EXSTYLE); - set => User32.SetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_EXSTYLE, new IntPtr((uint)value)); - } - - /// - /// Capture Window with GDI+ - /// - /// The capture to fill - /// ICapture - public ICapture CaptureGdiWindow(ICapture capture) { - Image capturedImage = PrintWindow(); - if (capturedImage != null) { - capture.Image = capturedImage; - capture.Location = Location; - return capture; - } - return null; - } - - /// - /// Capture DWM Window - /// - /// Capture to fill - /// Wanted WindowCaptureMode - /// True if auto mode is used - /// ICapture with the capture - public ICapture CaptureDwmWindow(ICapture capture, WindowCaptureMode windowCaptureMode, bool autoMode) { - IntPtr thumbnailHandle = IntPtr.Zero; - Form tempForm = null; - bool tempFormShown = false; - try { - tempForm = new Form - { - ShowInTaskbar = false, - FormBorderStyle = FormBorderStyle.None, - TopMost = true - }; - - // Register the Thumbnail - DWM.DwmRegisterThumbnail(tempForm.Handle, Handle, out thumbnailHandle); - - // Get the original size - DWM.DwmQueryThumbnailSourceSize(thumbnailHandle, out var sourceSize); - - if (sourceSize.Width <= 0 || sourceSize.Height <= 0) { - return null; - } - - // Calculate the location of the temp form - Rectangle windowRectangle = WindowRectangle; - Point formLocation = windowRectangle.Location; - Size borderSize = new Size(); - bool doesCaptureFit = false; - if (!Maximised) { - // Assume using it's own location - formLocation = windowRectangle.Location; - // TODO: Use Rectangle.Union! - using Region workingArea = new Region(Screen.PrimaryScreen.Bounds); - // Find the screen where the window is and check if it fits - foreach (Screen screen in Screen.AllScreens) { - if (!Equals(screen, Screen.PrimaryScreen)) { - workingArea.Union(screen.Bounds); - } - } - - // If the formLocation is not inside the visible area - if (!workingArea.AreRectangleCornersVisisble(windowRectangle)) { - // If none found we find the biggest screen - foreach (Screen screen in Screen.AllScreens) { - Rectangle newWindowRectangle = new Rectangle(screen.WorkingArea.Location, windowRectangle.Size); - if (workingArea.AreRectangleCornersVisisble(newWindowRectangle)) { - formLocation = screen.Bounds.Location; - doesCaptureFit = true; - break; - } - } - } else { - doesCaptureFit = true; - } - } else if (!WindowsVersion.IsWindows8OrLater) { - //GetClientRect(out windowRectangle); - GetBorderSize(out borderSize); - formLocation = new Point(windowRectangle.X - borderSize.Width, windowRectangle.Y - borderSize.Height); - } - - tempForm.Location = formLocation; - tempForm.Size = sourceSize.ToSize(); - - // Prepare rectangle to capture from the screen. - Rectangle captureRectangle = new Rectangle(formLocation.X, formLocation.Y, sourceSize.Width, sourceSize.Height); - if (Maximised) { - // Correct capture size for maximized window by offsetting the X,Y with the border size - // and subtracting the border from the size (2 times, as we move right/down for the capture without resizing) - captureRectangle.Inflate(borderSize.Width, borderSize.Height); - } else { - // TODO: Also 8.x? - if (WindowsVersion.IsWindows10OrLater) - { - captureRectangle.Inflate(Conf.Win10BorderCrop); - } - - if (autoMode) { - // check if the capture fits - if (!doesCaptureFit) - { - // if GDI is allowed.. (a screenshot won't be better than we comes if we continue) - using Process thisWindowProcess = Process; - if (!IsMetroApp && WindowCapture.IsGdiAllowed(thisWindowProcess)) { - // we return null which causes the capturing code to try another method. - return null; - } - } - } - } - // Prepare the displaying of the Thumbnail - DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES - { - Opacity = 255, - Visible = true, - Destination = new RECT(0, 0, sourceSize.Width, sourceSize.Height) - }; - DWM.DwmUpdateThumbnailProperties(thumbnailHandle, ref props); - tempForm.Show(); - tempFormShown = true; - - // Intersect with screen - captureRectangle.Intersect(capture.ScreenBounds); - - // Destination bitmap for the capture - Bitmap capturedBitmap = null; - bool frozen = false; - try { - // Check if we make a transparent capture - if (windowCaptureMode == WindowCaptureMode.AeroTransparent) { - frozen = FreezeWindow(); - // Use white, later black to capture transparent - tempForm.BackColor = Color.White; - // Make sure everything is visible - tempForm.Refresh(); - Application.DoEvents(); - - try - { - using Bitmap whiteBitmap = WindowCapture.CaptureRectangle(captureRectangle); - // Apply a white color - tempForm.BackColor = Color.Black; - // Make sure everything is visible - tempForm.Refresh(); - if (!IsMetroApp) { - // Make sure the application window is active, so the colors & buttons are right - ToForeground(); - } - // Make sure all changes are processed and visible - Application.DoEvents(); - using Bitmap blackBitmap = WindowCapture.CaptureRectangle(captureRectangle); - capturedBitmap = ApplyTransparency(blackBitmap, whiteBitmap); - } catch (Exception e) { - Log.Debug("Exception: ", e); - // Some problem occurred, cleanup and make a normal capture - if (capturedBitmap != null) { - capturedBitmap.Dispose(); - capturedBitmap = null; - } - } - } - // If no capture up till now, create a normal capture. - if (capturedBitmap == null) { - // Remove transparency, this will break the capturing - if (!autoMode) { - tempForm.BackColor = Color.FromArgb(255, Conf.DWMBackgroundColor.R, Conf.DWMBackgroundColor.G, Conf.DWMBackgroundColor.B); - } else { - Color colorizationColor = DWM.ColorizationColor; - // Modify by losing the transparency and increasing the intensity (as if the background color is white) - colorizationColor = Color.FromArgb(255, (colorizationColor.R + 255) >> 1, (colorizationColor.G + 255) >> 1, (colorizationColor.B + 255) >> 1); - tempForm.BackColor = colorizationColor; - } - // Make sure everything is visible - tempForm.Refresh(); - if (!IsMetroApp) { - // Make sure the application window is active, so the colors & buttons are right - ToForeground(); - } - // Make sure all changes are processed and visible - Application.DoEvents(); - // Capture from the screen - capturedBitmap = WindowCapture.CaptureRectangle(captureRectangle); - } - if (capturedBitmap != null) { - // Not needed for Windows 8 - if (!WindowsVersion.IsWindows8OrLater) { - // Only if the Inivalue is set, not maximized and it's not a tool window. - if (Conf.WindowCaptureRemoveCorners && !Maximised && (ExtendedWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) == 0) { - // Remove corners - if (!Image.IsAlphaPixelFormat(capturedBitmap.PixelFormat)) { - Log.Debug("Changing pixelformat to Alpha for the RemoveCorners"); - Bitmap tmpBitmap = ImageHelper.Clone(capturedBitmap, PixelFormat.Format32bppArgb); - capturedBitmap.Dispose(); - capturedBitmap = tmpBitmap; - } - RemoveCorners(capturedBitmap); - } - } - } - } finally { - // Make sure to ALWAYS unfreeze!! - if (frozen) { - UnfreezeWindow(); - } - } - - capture.Image = capturedBitmap; - // Make sure the capture location is the location of the window, not the copy - capture.Location = Location; - } finally { - if (thumbnailHandle != IntPtr.Zero) { - // Unregister (cleanup), as we are finished we don't need the form or the thumbnail anymore - DWM.DwmUnregisterThumbnail(thumbnailHandle); - } - if (tempForm != null) { - if (tempFormShown) { - tempForm.Close(); - } - tempForm.Dispose(); - tempForm = null; - } - } - - return capture; - } - - /// - /// Helper method to remove the corners from a DMW capture - /// - /// The bitmap to remove the corners from. - private void RemoveCorners(Bitmap image) - { - using IFastBitmap fastBitmap = FastBitmap.Create(image); - for (int y = 0; y < Conf.WindowCornerCutShape.Count; y++) { - for (int x = 0; x < Conf.WindowCornerCutShape[y]; x++) { - fastBitmap.SetColorAt(x, y, Color.Transparent); - fastBitmap.SetColorAt(image.Width-1-x, y, Color.Transparent); - fastBitmap.SetColorAt(image.Width-1-x, image.Height-1-y, Color.Transparent); - fastBitmap.SetColorAt(x, image.Height-1-y, Color.Transparent); - } - } - } - - /// - /// Apply transparency by comparing a transparent capture with a black and white background - /// A "Math.min" makes sure there is no overflow, but this could cause the picture to have shifted colors. - /// The pictures should have been taken without differency, except for the colors. - /// - /// Bitmap with the black image - /// Bitmap with the black image - /// Bitmap with transparency - private Bitmap ApplyTransparency(Bitmap blackBitmap, Bitmap whiteBitmap) - { - using IFastBitmap targetBuffer = FastBitmap.CreateEmpty(blackBitmap.Size, PixelFormat.Format32bppArgb, Color.Transparent); - targetBuffer.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution); - using (IFastBitmap blackBuffer = FastBitmap.Create(blackBitmap)) - { - using IFastBitmap whiteBuffer = FastBitmap.Create(whiteBitmap); - for (int y = 0; y < blackBuffer.Height; y++) { - for (int x = 0; x < blackBuffer.Width; x++) { - Color c0 = blackBuffer.GetColorAt(x, y); - Color c1 = whiteBuffer.GetColorAt(x, y); - // Calculate alpha as double in range 0-1 - int alpha = c0.R - c1.R + 255; - if (alpha == 255) { - // Alpha == 255 means no change! - targetBuffer.SetColorAt(x, y, c0); - } else if (alpha == 0) { - // Complete transparency, use transparent pixel - targetBuffer.SetColorAt(x, y, Color.Transparent); - } else { - // Calculate original color - byte originalAlpha = (byte)Math.Min(255, alpha); - var alphaFactor = alpha/255d; - //LOG.DebugFormat("Alpha {0} & c0 {1} & c1 {2}", alpha, c0, c1); - byte originalRed = (byte)Math.Min(255, c0.R / alphaFactor); - byte originalGreen = (byte)Math.Min(255, c0.G / alphaFactor); - byte originalBlue = (byte)Math.Min(255, c0.B / alphaFactor); - Color originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue); - //Color originalColor = Color.FromArgb(originalAlpha, originalRed, c0.G, c0.B); - targetBuffer.SetColorAt(x, y, originalColor); - } - } - } - } - return targetBuffer.UnlockAndReturnBitmap(); - } - - /// - /// Helper method to get the window size for DWM Windows - /// - /// out Rectangle - /// bool true if it worked - private bool GetExtendedFrameBounds(out Rectangle rectangle) { - int result = DWM.DwmGetWindowAttribute(Handle, DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out RECT rect, Marshal.SizeOf(typeof(RECT))); - if (result >= 0) { - rectangle = rect.ToRectangle(); - return true; - } - rectangle = Rectangle.Empty; - return false; - } - - /// - /// Helper method to get the window size for GDI Windows - /// - /// out Rectangle - /// bool true if it worked - private bool GetClientRect(out Rectangle rectangle) { - var windowInfo = new WindowInfo(); - // Get the Window Info for this window - bool result = User32.GetWindowInfo(Handle, ref windowInfo); - rectangle = result ? windowInfo.rcClient.ToRectangle() : Rectangle.Empty; - return result; - } - - /// - /// Helper method to get the window size for GDI Windows - /// - /// out Rectangle - /// bool true if it worked - private bool GetWindowRect(out Rectangle rectangle) { - var windowInfo = new WindowInfo(); - // Get the Window Info for this window - bool result = User32.GetWindowInfo(Handle, ref windowInfo); - rectangle = result ? windowInfo.rcWindow.ToRectangle() : Rectangle.Empty; - return result; - } - - /// - /// Helper method to get the Border size for GDI Windows - /// - /// out Size - /// bool true if it worked - private bool GetBorderSize(out Size size) { - var windowInfo = new WindowInfo(); - // Get the Window Info for this window - bool result = User32.GetWindowInfo(Handle, ref windowInfo); - size = result ? new Size((int)windowInfo.cxWindowBorders, (int)windowInfo.cyWindowBorders) : Size.Empty; - return result; - } - - /// - /// Set the window as foreground window - /// - /// hWnd of the window to bring to the foreground - public static void ToForeground(IntPtr hWnd) - { - var foregroundWindow = User32.GetForegroundWindow(); - if (hWnd == foregroundWindow) - { - return; - } - - var window = new WindowDetails(hWnd); - // Nothing we can do if it's not visible! - if (!window.Visible) - { - return; - } - - var threadId1 = User32.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero); - var threadId2 = User32.GetWindowThreadProcessId(hWnd, IntPtr.Zero); - - // Show window in foreground. - if (threadId1 != threadId2) - { - User32.AttachThreadInput(threadId1, threadId2, 1); - User32.SetForegroundWindow(hWnd); - User32.AttachThreadInput(threadId1, threadId2, 0); - } - else - { - User32.SetForegroundWindow(hWnd); - } - - User32.BringWindowToTop(hWnd); - - if (window.Iconic) - { - window.Iconic = false; - } - } - - /// - /// Set the window as foreground window - /// - public void ToForeground() { - ToForeground(Handle); - } - - /// - /// Get the region for a window - /// - private Region GetRegion() { - using (SafeRegionHandle region = GDI32.CreateRectRgn(0, 0, 0, 0)) { - if (!region.IsInvalid) { - RegionResult result = User32.GetWindowRgn(Handle, region); - if (result != RegionResult.REGION_ERROR && result != RegionResult.REGION_NULLREGION) { - return Region.FromHrgn(region.DangerousGetHandle()); - } - } - } - return null; - } - - private bool CanFreezeOrUnfreeze(string titleOrProcessname) { - if (string.IsNullOrEmpty(titleOrProcessname)) { - return false; - } - if (titleOrProcessname.ToLower().Contains("greenshot")) { - return false; - } - - foreach (string excludeProcess in ExcludeProcessesFromFreeze) { - if (titleOrProcessname.ToLower().Contains(excludeProcess)) { - return false; - } - } - return true; - } - - /// - /// Freezes the process belonging to the window - /// Warning: Use only if no other way!! - /// - private bool FreezeWindow() { - bool frozen = false; - using (Process proc = Process.GetProcessById(ProcessId)) { - string processName = proc.ProcessName; - if (!CanFreezeOrUnfreeze(processName)) { - Log.DebugFormat("Not freezing {0}", processName); - return false; - } - if (!CanFreezeOrUnfreeze(Text)) { - Log.DebugFormat("Not freezing {0}", processName); - return false; - } - Log.DebugFormat("Freezing process: {0}", processName); - - - foreach (ProcessThread pT in proc.Threads) { - IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id); - - if (pOpenThread == IntPtr.Zero) { - break; - } - frozen = true; - Kernel32.SuspendThread(pOpenThread); - pT.Dispose(); - } - } - return frozen; - } - - /// - /// Unfreeze the process belonging to the window - /// - public void UnfreezeWindow() - { - using Process proc = Process.GetProcessById(ProcessId); - string processName = proc.ProcessName; - if (!CanFreezeOrUnfreeze(processName)) { - Log.DebugFormat("Not unfreezing {0}", processName); - return; - } - if (!CanFreezeOrUnfreeze(Text)) { - Log.DebugFormat("Not unfreezing {0}", processName); - return; - } - Log.DebugFormat("Unfreezing process: {0}", processName); - - foreach (ProcessThread pT in proc.Threads) { - IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id); - - if (pOpenThread == IntPtr.Zero) { - break; - } - - Kernel32.ResumeThread(pOpenThread); - } - } - - /// - /// Return an Image representing the Window! - /// As GDI+ draws it, it will be without Aero borders! - /// - public Image PrintWindow() { - Rectangle windowRect = WindowRectangle; - // Start the capture - Exception exceptionOccured = null; - Image returnImage; - using (Region region = GetRegion()) { - PixelFormat pixelFormat = PixelFormat.Format24bppRgb; - // Only use 32 bpp ARGB when the window has a region - if (region != null) { - pixelFormat = PixelFormat.Format32bppArgb; - } - returnImage = new Bitmap(windowRect.Width, windowRect.Height, pixelFormat); - using Graphics graphics = Graphics.FromImage(returnImage); - using (SafeDeviceContextHandle graphicsDc = graphics.GetSafeDeviceContext()) { - bool printSucceeded = User32.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), 0x0); - if (!printSucceeded) { - // something went wrong, most likely a "0x80004005" (Acess Denied) when using UAC - exceptionOccured = User32.CreateWin32Exception("PrintWindow"); - } - } - - // Apply the region "transparency" - if (region != null && !region.IsEmpty(graphics)) { - graphics.ExcludeClip(region); - graphics.Clear(Color.Transparent); - } - - graphics.Flush(); - } - - // Return null if error - if (exceptionOccured != null) { - Log.ErrorFormat("Error calling print window: {0}", exceptionOccured.Message); - returnImage.Dispose(); - return null; - } - if (!HasParent && Maximised) { - Log.Debug("Correcting for maximalization"); - GetBorderSize(out var borderSize); - Rectangle borderRectangle = new Rectangle(borderSize.Width, borderSize.Height, windowRect.Width - (2 * borderSize.Width), windowRect.Height - (2 * borderSize.Height)); - ImageHelper.Crop(ref returnImage, ref borderRectangle); - } - return returnImage; - } - - /// - /// Constructs a new instance of this class for - /// the specified Window Handle. - /// - /// The Window Handle - public WindowDetails(IntPtr hWnd) { - Handle = hWnd; - } - - /// - /// Gets an instance of the current active foreground window - /// - /// WindowDetails of the current window - public static WindowDetails GetActiveWindow() { - IntPtr hWnd = User32.GetForegroundWindow(); - if (hWnd != IntPtr.Zero) { - if (IgnoreHandles.Contains(hWnd)) { - return GetDesktopWindow(); - } - - WindowDetails activeWindow = new WindowDetails(hWnd); - // Invisible Windows should not be active - if (!activeWindow.Visible) { - return GetDesktopWindow(); - } - return activeWindow; - } - return null; - } - - /// - /// Gets the Desktop window - /// - /// WindowDetails for the desktop window - public static WindowDetails GetDesktopWindow() { - return new WindowDetails(User32.GetDesktopWindow()); - } - - /// - /// Get all the top level windows - /// - /// List of WindowDetails with all the top level windows - public static IList GetAllWindows() { - return GetAllWindows(null); - } - - /// - /// Get all the top level windows, with matching classname - /// - /// List WindowDetails with all the top level windows - public static IList GetAllWindows(string classname) { - return new WindowsEnumerator().GetWindows(IntPtr.Zero, classname).Items; - } - - /// - /// Recursive "find children which" - /// - /// point to check for - /// - public WindowDetails FindChildUnderPoint(Point point) { - if (!Contains(point)) { - return null; - } - var rect = WindowRectangle; - // If the mouse it at the edge, take the whole window - if (rect.X == point.X || rect.Y == point.Y || rect.Right == point.X || rect.Bottom == point.Y) - { - return this; - } - // Look into the child windows - foreach(var childWindow in Children) { - if (childWindow.Contains(point)) { - return childWindow.FindChildUnderPoint(point); - } - } - return this; - } - - /// - /// Retrieves the classname for a hWnd - /// - /// IntPtr with the windows handle - /// String with ClassName - public static string GetClassName(IntPtr hWnd) { - var classNameBuilder = new StringBuilder(260, 260); - User32.GetClassName(hWnd, classNameBuilder, classNameBuilder.Capacity); - return classNameBuilder.ToString(); - } - - /// - /// Helper method to decide if a top level window is visible - /// - /// - /// - /// - private static bool IsVisible(WindowDetails window, Rectangle screenBounds) - { - // Ignore invisible - if (!window.Visible) - { - return false; - } - // Ignore minimized - if (window.Iconic) - { - return false; - } - if (IgnoreClasses.Contains(window.ClassName)) - { - return false; - } - // On windows which are visible on the screen - var windowRect = window.WindowRectangle; - windowRect.Intersect(screenBounds); - if (windowRect.IsEmpty) - { - return false; - } - // Skip everything which is not rendered "normally", trying to fix BUG-2017 - var exWindowStyle = window.ExtendedWindowStyle; - if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) - { - return false; - } - - return true; - } - - /// - /// Get all the visible top level windows - /// - /// List WindowDetails with all the visible top level windows - public static IEnumerable GetVisibleWindows() { - Rectangle screenBounds = WindowCapture.GetScreenBounds(); - foreach(var window in GetAppWindows()) { - if (IsVisible(window, screenBounds)) - { - yield return window; - } - } - foreach (var window in GetAllWindows()) - { - if (IsVisible(window, screenBounds)) - { - yield return window; - } - } - } - - /// - /// Get the WindowDetails for all Metro Apps - /// These are all Windows with Classname "Windows.UI.Core.CoreWindow" - /// - /// List WindowDetails with visible metro apps - public static IEnumerable GetAppWindows() { - // if the appVisibility != null we have Windows 8. - if (AppVisibility == null) - { - yield break; - } - var nextHandle = User32.FindWindow(AppWindowClass, null); - while (nextHandle != IntPtr.Zero) { - var metroApp = new WindowDetails(nextHandle); - yield return metroApp; - // Check if we have a gutter! - if (metroApp.Visible && !metroApp.Maximised) { - var gutterHandle = User32.FindWindow(GutterClass, null); - if (gutterHandle != IntPtr.Zero) { - yield return new WindowDetails(gutterHandle); - } - } - nextHandle = User32.FindWindowEx(IntPtr.Zero, nextHandle, AppWindowClass, null); - } - } - - /// - /// Check if the window is a top level - /// - /// WindowDetails - /// bool - private static bool IsTopLevel(WindowDetails window) - { - if (window.IsCloaked) - { - return false; - } - // Windows without size - if (window.WindowRectangle.Size.Width * window.WindowRectangle.Size.Height == 0) - { - return false; - } - if (window.HasParent) - { - return false; - } - var exWindowStyle = window.ExtendedWindowStyle; - if ((exWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) != 0) - { - return false; - } - // Skip everything which is not rendered "normally", trying to fix BUG-2017 - if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) - { - return false; - } - // Skip preview windows, like the one from Firefox - if ((window.WindowStyle & WindowStyleFlags.WS_VISIBLE) == 0) - { - return false; - } - // Ignore windows without title - if (window.Text.Length == 0) - { - return false; - } - if (IgnoreClasses.Contains(window.ClassName)) - { - return false; - } - if (!(window.Visible || window.Iconic)) - { - return false; - } - - return !window.IsBackgroundWin10App; - } - - /// - /// Get all the top level windows - /// - /// List WindowDetails with all the top level windows - public static IEnumerable GetTopLevelWindows() { - foreach (var possibleTopLevel in GetAppWindows()) - { - if (IsTopLevel(possibleTopLevel)) - { - yield return possibleTopLevel; - } - } - - foreach (var possibleTopLevel in GetAllWindows()) - { - if (IsTopLevel(possibleTopLevel)) - { - yield return possibleTopLevel; - } - } - } - - /// - /// Find a window belonging to the same process as the supplied window. - /// - /// - /// - public static WindowDetails GetLinkedWindow(WindowDetails windowToLinkTo) { - int processIdSelectedWindow = windowToLinkTo.ProcessId; - foreach(var window in GetAllWindows()) { - // Ignore windows without title - if (window.Text.Length == 0) { - continue; - } - // Ignore invisible - if (!window.Visible) { - continue; - } - if (window.Handle == windowToLinkTo.Handle) { - continue; - } - if (window.Iconic) { - continue; - } - - // Windows without size - Size windowSize = window.WindowRectangle.Size; - if (windowSize.Width == 0 || windowSize.Height == 0) { - continue; - } - - if (window.ProcessId == processIdSelectedWindow) { - Log.InfoFormat("Found window {0} belonging to same process as the window {1}", window.Text, windowToLinkTo.Text); - return window; - } - } - return null; - } - - /// - /// Helper method to "active" all windows that are not in the supplied list. - /// One should preferably call "GetVisibleWindows" for the oldWindows. - /// - /// List WindowDetails with old windows - public static void ActiveNewerWindows(IEnumerable oldWindows) - { - var oldWindowsList = new List(oldWindows); - foreach(var window in GetVisibleWindows()) { - if (!oldWindowsList.Contains(window)) { - window.ToForeground(); - } - } - } - - /// - /// Get the AppLauncher - /// - /// - public static WindowDetails GetAppLauncher() { - // Only if Windows 8 (or higher) - if (AppVisibility == null) { - return null; - } - IntPtr appLauncher = User32.FindWindow(ApplauncherClass, null); - if (appLauncher != IntPtr.Zero) { - return new WindowDetails (appLauncher); - } - return null; - } - - /// - /// Return true if the metro-app-launcher is visible - /// - /// - public static bool IsAppLauncherVisible { - get { - if (AppVisibility != null) { - return AppVisibility.IsLauncherVisible; - } - return false; - } - } - - /// - /// Make a string representation of the window details - /// - /// string - public override string ToString() - { - var result = new StringBuilder(); - result.AppendLine($"Text: {Text}"); - result.AppendLine($"ClassName: {ClassName}"); - result.AppendLine($"ExtendedWindowStyle: {ExtendedWindowStyle}"); - result.AppendLine($"WindowStyle: {WindowStyle}"); - result.AppendLine($"Size: {WindowRectangle.Size}"); - result.AppendLine($"HasParent: {HasParent}"); - result.AppendLine($"IsWin10App: {IsWin10App}"); - result.AppendLine($"IsApp: {IsApp}"); - result.AppendLine($"Visible: {Visible}"); - result.AppendLine($"IsWindowVisible: {User32.IsWindowVisible(Handle)}"); - result.AppendLine($"IsCloaked: {IsCloaked}"); - result.AppendLine($"Iconic: {Iconic}"); - result.AppendLine($"IsBackgroundWin10App: {IsBackgroundWin10App}"); - if (HasChildren) - { - result.AppendLine($"Children classes: {string.Join(",", Children.Select(c => c.ClassName))}"); - } - return result.ToString(); - } - } +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interop; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// Code for handling with "windows" + /// Main code is taken from vbAccelerator, location: + /// http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows/Enumerating_Windows/article.asp + /// but a LOT of changes/enhancements were made to adapt it for Greenshot. + /// + /// Provides details about a Window returned by the enumeration + /// + public class WindowDetails : IEquatable + { + private const string AppWindowClass = "Windows.UI.Core.CoreWindow"; //Used for Windows 8(.1) + private const string AppFrameWindowClass = "ApplicationFrameWindow"; // Windows 10 uses ApplicationFrameWindow + private const string ApplauncherClass = "ImmersiveLauncher"; + private const string GutterClass = "ImmersiveGutter"; + + private static readonly IList IgnoreClasses = new List(new[] + { + "Progman", "Button", "Dwm" + }); //"MS-SDIa" + + private static readonly ILog Log = LogManager.GetLogger(typeof(WindowDetails)); + private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); + private static readonly IList IgnoreHandles = new List(); + private static readonly IList ExcludeProcessesFromFreeze = new List(); + private static readonly IAppVisibility AppVisibility; + + static WindowDetails() + { + try + { + // Only try to instantiate when Windows 8 or later. + if (WindowsVersion.IsWindows8OrLater) + { + AppVisibility = COMWrapper.CreateInstance(); + } + } + catch (Exception ex) + { + Log.WarnFormat("Couldn't create instance of IAppVisibility: {0}", ex.Message); + } + } + + public static void AddProcessToExcludeFromFreeze(string processName) + { + if (!ExcludeProcessesFromFreeze.Contains(processName)) + { + ExcludeProcessesFromFreeze.Add(processName); + } + } + + internal static bool IsIgnoreHandle(IntPtr handle) + { + return IgnoreHandles.Contains(handle); + } + + private IList _childWindows; + private IntPtr _parentHandle = IntPtr.Zero; + private WindowDetails _parent; + private bool _frozen; + + /// + /// This checks if the window is a Windows 8 App + /// For Windows 10 most normal code works, as it's hosted inside "ApplicationFrameWindow" + /// + public bool IsApp => AppWindowClass.Equals(ClassName); + + /// + /// This checks if the window is a Windows 10 App + /// For Windows 10 apps are hosted inside "ApplicationFrameWindow" + /// + public bool IsWin10App => AppFrameWindowClass.Equals(ClassName); + + /// + /// Check if this window belongs to a background app + /// + public bool IsBackgroundWin10App => WindowsVersion.IsWindows10OrLater && AppFrameWindowClass.Equals(ClassName) && + !Children.Any(window => string.Equals(window.ClassName, AppWindowClass)); + + /// + /// Check if the window is the metro gutter (sizeable separator) + /// + public bool IsGutter => GutterClass.Equals(ClassName); + + /// + /// Test if this window is for the App-Launcher + /// + public bool IsAppLauncher => ApplauncherClass.Equals(ClassName); + + /// + /// Check if this window is the window of a metro app + /// + public bool IsMetroApp => IsAppLauncher || IsApp; + + /// + /// To allow items to be compared, the hash code + /// is set to the Window handle, so two EnumWindowsItem + /// objects for the same Window will be equal. + /// + /// The Window Handle for this window + public override int GetHashCode() + { + return Handle.ToInt32(); + } + + public override bool Equals(object right) + { + return Equals(right as WindowDetails); + } + + /// + /// Compare two windows details + /// + /// + /// + public bool Equals(WindowDetails other) + { + if (other is null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (GetType() != other.GetType()) + { + return false; + } + + return other.Handle == Handle; + } + + /// + /// Check if the window has children + /// + public bool HasChildren => (_childWindows != null) && (_childWindows.Count > 0); + + /// + /// Freeze information updates + /// + public void FreezeDetails() + { + _frozen = true; + } + + /// + /// Make the information update again. + /// + public void UnfreezeDetails() + { + _frozen = false; + } + + /// + /// Get the file path to the exe for the process which owns this window + /// + public string ProcessPath + { + get + { + if (Handle == IntPtr.Zero) + { + // not a valid window handle + return string.Empty; + } + + // Get the process id + User32.GetWindowThreadProcessId(Handle, out var processId); + return Kernel32.GetProcessPath(processId); + } + } + + + /// + /// Get the icon belonging to the process + /// + public Image DisplayIcon + { + get + { + try + { + using var appIcon = GetAppIcon(Handle); + if (appIcon != null) + { + return appIcon.ToBitmap(); + } + } + catch (Exception ex) + { + Log.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); + Log.Warn(ex); + } + + if (IsMetroApp) + { + // No method yet to get the metro icon + return null; + } + + try + { + return PluginUtils.GetCachedExeIcon(ProcessPath, 0); + } + catch (Exception ex) + { + Log.WarnFormat("Couldn't get icon for window {0} due to: {1}", Text, ex.Message); + Log.Warn(ex); + } + + return null; + } + } + + /// + /// Get the icon for a hWnd + /// + /// + /// + private static Icon GetAppIcon(IntPtr hWnd) + { + IntPtr iconSmall = IntPtr.Zero; + IntPtr iconBig = new IntPtr(1); + IntPtr iconSmall2 = new IntPtr(2); + + IntPtr iconHandle; + if (Conf.UseLargeIcons) + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICON); + } + } + else + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconSmall2, IntPtr.Zero); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconSmall, IntPtr.Zero); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICONSM); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); + } + + if (iconHandle == IntPtr.Zero) + { + iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICON); + } + + if (iconHandle == IntPtr.Zero) + { + return null; + } + + Icon icon = Icon.FromHandle(iconHandle); + + return icon; + } + + /// + /// Use this to make remove internal windows, like the mainform and the captureforms, invisible + /// + /// + public static void RegisterIgnoreHandle(IntPtr ignoreHandle) + { + IgnoreHandles.Add(ignoreHandle); + } + + /// + /// Use this to remove the with RegisterIgnoreHandle registered handle + /// + /// + public static void UnregisterIgnoreHandle(IntPtr ignoreHandle) + { + IgnoreHandles.Remove(ignoreHandle); + } + + public IList Children + { + get + { + if (_childWindows == null) + { + GetChildren(); + } + + return _childWindows; + } + } + + /// + /// Retrieve the child with matching classname + /// + public WindowDetails GetChild(string childClassname) + { + foreach (var child in Children) + { + if (childClassname.Equals(child.ClassName)) + { + return child; + } + } + + return null; + } + + public IntPtr ParentHandle + { + get + { + if (_parentHandle == IntPtr.Zero) + { + _parentHandle = User32.GetParent(Handle); + _parent = null; + } + + return _parentHandle; + } + set + { + if (_parentHandle != value) + { + _parentHandle = value; + _parent = null; + } + } + } + + /// + /// Get the parent of the current window + /// + /// WindowDetails of the parent, or null if none + public WindowDetails GetParent() + { + if (_parent == null) + { + if (_parentHandle == IntPtr.Zero) + { + _parentHandle = User32.GetParent(Handle); + } + + if (_parentHandle != IntPtr.Zero) + { + _parent = new WindowDetails(_parentHandle); + } + } + + return _parent; + } + + /// + /// Retrieve all the children, this only stores the children internally. + /// One should normally use the getter "Children" + /// + public IList GetChildren() + { + if (_childWindows == null) + { + return GetChildren(0); + } + + return _childWindows; + } + + /// + /// Retrieve all the children, this only stores the children internally, use the "Children" property for the value + /// + /// Specify how many levels we go in + public IList GetChildren(int levelsToGo) + { + if (_childWindows != null) + { + return _childWindows; + } + + _childWindows = new WindowsEnumerator().GetWindows(Handle, null).Items; + foreach (var childWindow in _childWindows) + { + if (levelsToGo > 0) + { + childWindow.GetChildren(levelsToGo - 1); + } + } + + return _childWindows; + } + + /// + /// Gets the window's handle + /// + public IntPtr Handle { get; } + + private string _text; + + /// + /// Gets the window's title (caption) + /// + public string Text + { + set => _text = value; + get + { + if (_text == null) + { + var title = new StringBuilder(260, 260); + User32.GetWindowText(Handle, title, title.Capacity); + _text = title.ToString(); + } + + return _text; + } + } + + private string _className; + + /// + /// Gets the window's class name. + /// + public string ClassName => _className ??= GetClassName(Handle); + + /// + /// Gets/Sets whether the window is iconic (minimized) or not. + /// + public bool Iconic + { + get + { + if (IsMetroApp) + { + return !Visible; + } + + return User32.IsIconic(Handle) || Location.X <= -32000; + } + set + { + if (value) + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MINIMIZE, IntPtr.Zero); + } + else + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_RESTORE, IntPtr.Zero); + } + } + } + + /// + /// Gets/Sets whether the window is maximized or not. + /// + public bool Maximised + { + get + { + if (IsApp) + { + if (Visible) + { + Rectangle windowRectangle = WindowRectangle; + foreach (var screen in Screen.AllScreens) + { + if (screen.Bounds.Contains(windowRectangle)) + { + if (windowRectangle.Equals(screen.Bounds)) + { + return true; + } + } + } + } + + return false; + } + + return User32.IsZoomed(Handle); + } + set + { + if (value) + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MAXIMIZE, IntPtr.Zero); + } + else + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MINIMIZE, IntPtr.Zero); + } + } + } + + /// + /// Returns if this window is cloaked + /// + public bool IsCloaked + { + get => DWM.IsWindowCloaked(Handle); + } + + /// + /// Gets whether the window is visible. + /// + public bool Visible + { + get + { + // Tip from Raymond Chen https://devblogs.microsoft.com/oldnewthing/20200302-00/?p=103507 + if (IsCloaked) + { + return false; + } + + if (IsApp) + { + Rectangle windowRectangle = WindowRectangle; + foreach (Screen screen in Screen.AllScreens) + { + if (screen.Bounds.Contains(windowRectangle)) + { + if (windowRectangle.Equals(screen.Bounds)) + { + // Fullscreen, it's "visible" when AppVisibilityOnMonitor says yes + // Although it might be the other App, this is not "very" important + RECT rect = new RECT(screen.Bounds); + IntPtr monitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONULL); + if (monitor != IntPtr.Zero) + { + MONITOR_APP_VISIBILITY? monitorAppVisibility = AppVisibility?.GetAppVisibilityOnMonitor(monitor); + //LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds); + if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) + { + return true; + } + } + } + else + { + // Is only partly on the screen, when this happens the app is always visible! + return true; + } + } + } + + return false; + } + + if (IsGutter) + { + // gutter is only made available when it's visible + return true; + } + + if (IsAppLauncher) + { + return IsAppLauncherVisible; + } + + return User32.IsWindowVisible(Handle); + } + } + + public bool HasParent + { + get + { + GetParent(); + return _parentHandle != IntPtr.Zero; + } + } + + public int ProcessId + { + get + { + User32.GetWindowThreadProcessId(Handle, out var processId); + return processId; + } + } + + public Process Process + { + get + { + try + { + User32.GetWindowThreadProcessId(Handle, out var processId); + return Process.GetProcessById(processId); + } + catch (Exception ex) + { + Log.Warn(ex); + } + + return null; + } + } + + private Rectangle _previousWindowRectangle = Rectangle.Empty; + private long _lastWindowRectangleRetrieveTime; + private const long CacheTime = TimeSpan.TicksPerSecond * 2; + + /// + /// Gets the bounding rectangle of the window + /// + public Rectangle WindowRectangle + { + get + { + // Try to return a cached value + long now = DateTime.Now.Ticks; + if (_previousWindowRectangle.IsEmpty || !_frozen) + { + if (!_previousWindowRectangle.IsEmpty && now - _lastWindowRectangleRetrieveTime <= CacheTime) + { + return _previousWindowRectangle; + } + + Rectangle windowRect = Rectangle.Empty; + if (DWM.IsDwmEnabled) + { + bool gotFrameBounds = GetExtendedFrameBounds(out windowRect); + if (IsApp) + { + // Pre-Cache for maximized call, this is only on Windows 8 apps (full screen) + if (gotFrameBounds) + { + _previousWindowRectangle = windowRect; + _lastWindowRectangleRetrieveTime = now; + } + } + + if (gotFrameBounds && WindowsVersion.IsWindows10OrLater && !Maximised) + { + // Somehow DWM doesn't calculate it corectly, there is a 1 pixel border around the capture + // Remove this border, currently it's fixed but TODO: Make it depend on the OS? + windowRect.Inflate(Conf.Win10BorderCrop); + _previousWindowRectangle = windowRect; + _lastWindowRectangleRetrieveTime = now; + return windowRect; + } + } + + if (windowRect.IsEmpty) + { + if (!GetWindowRect(out windowRect)) + { + Win32Error error = Win32.GetLastErrorCode(); + Log.WarnFormat("Couldn't retrieve the windows rectangle: {0}", Win32.GetMessage(error)); + } + } + + // Correction for maximized windows, only if it's not an app + if (!HasParent && !IsApp && Maximised) + { + // Only if the border size can be retrieved + if (GetBorderSize(out var size)) + { + windowRect = new Rectangle(windowRect.X + size.Width, windowRect.Y + size.Height, windowRect.Width - (2 * size.Width), + windowRect.Height - (2 * size.Height)); + } + } + + _lastWindowRectangleRetrieveTime = now; + // Try to return something valid, by getting returning the previous size if the window doesn't have a Rectangle anymore + if (windowRect.IsEmpty) + { + return _previousWindowRectangle; + } + + _previousWindowRectangle = windowRect; + return windowRect; + } + + return _previousWindowRectangle; + } + } + + /// + /// Gets the location of the window relative to the screen. + /// + public Point Location + { + get + { + Rectangle tmpRectangle = WindowRectangle; + return new Point(tmpRectangle.Left, tmpRectangle.Top); + } + } + + /// + /// Gets the size of the window. + /// + public Size Size + { + get + { + Rectangle tmpRectangle = WindowRectangle; + return new Size(tmpRectangle.Right - tmpRectangle.Left, tmpRectangle.Bottom - tmpRectangle.Top); + } + } + + /// + /// Get the client rectangle, this is the part of the window inside the borders (drawable area) + /// + public Rectangle ClientRectangle + { + get + { + if (!GetClientRect(out var clientRect)) + { + Win32Error error = Win32.GetLastErrorCode(); + Log.WarnFormat("Couldn't retrieve the client rectangle for {0}, error: {1}", Text, Win32.GetMessage(error)); + } + + return clientRect; + } + } + + /// + /// Check if the supplied point lies in the window + /// + /// Point with the coordinates to check + /// true if the point lies within + public bool Contains(Point p) + { + return WindowRectangle.Contains(p); + } + + /// + /// Restores and Brings the window to the front, + /// assuming it is a visible application window. + /// + public void Restore() + { + if (Iconic) + { + User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_RESTORE, IntPtr.Zero); + } + + User32.BringWindowToTop(Handle); + User32.SetForegroundWindow(Handle); + // Make sure windows has time to perform the action + // TODO: this is BAD practice! + while (Iconic) + { + Application.DoEvents(); + } + } + + /// + /// Get / Set the WindowStyle + /// + public WindowStyleFlags WindowStyle + { + get => (WindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE); + set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE, new IntPtr((long) value)); + } + + /// + /// Get/Set the WindowPlacement + /// + public WindowPlacement WindowPlacement + { + get + { + var placement = WindowPlacement.Default; + User32.GetWindowPlacement(Handle, ref placement); + return placement; + } + set { User32.SetWindowPlacement(Handle, ref value); } + } + + /// + /// Get/Set the Extended WindowStyle + /// + public ExtendedWindowStyleFlags ExtendedWindowStyle + { + get => (ExtendedWindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_EXSTYLE); + set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_EXSTYLE, new IntPtr((uint) value)); + } + + /// + /// Capture Window with GDI+ + /// + /// The capture to fill + /// ICapture + public ICapture CaptureGdiWindow(ICapture capture) + { + Image capturedImage = PrintWindow(); + if (capturedImage != null) + { + capture.Image = capturedImage; + capture.Location = Location; + return capture; + } + + return null; + } + + /// + /// Capture DWM Window + /// + /// Capture to fill + /// Wanted WindowCaptureMode + /// True if auto mode is used + /// ICapture with the capture + public ICapture CaptureDwmWindow(ICapture capture, WindowCaptureMode windowCaptureMode, bool autoMode) + { + IntPtr thumbnailHandle = IntPtr.Zero; + Form tempForm = null; + bool tempFormShown = false; + try + { + tempForm = new Form + { + ShowInTaskbar = false, + FormBorderStyle = FormBorderStyle.None, + TopMost = true + }; + + // Register the Thumbnail + DWM.DwmRegisterThumbnail(tempForm.Handle, Handle, out thumbnailHandle); + + // Get the original size + DWM.DwmQueryThumbnailSourceSize(thumbnailHandle, out var sourceSize); + + if (sourceSize.Width <= 0 || sourceSize.Height <= 0) + { + return null; + } + + // Calculate the location of the temp form + Rectangle windowRectangle = WindowRectangle; + Point formLocation = windowRectangle.Location; + Size borderSize = new Size(); + bool doesCaptureFit = false; + if (!Maximised) + { + // Assume using it's own location + formLocation = windowRectangle.Location; + // TODO: Use Rectangle.Union! + using Region workingArea = new Region(Screen.PrimaryScreen.Bounds); + // Find the screen where the window is and check if it fits + foreach (Screen screen in Screen.AllScreens) + { + if (!Equals(screen, Screen.PrimaryScreen)) + { + workingArea.Union(screen.Bounds); + } + } + + // If the formLocation is not inside the visible area + if (!workingArea.AreRectangleCornersVisisble(windowRectangle)) + { + // If none found we find the biggest screen + foreach (Screen screen in Screen.AllScreens) + { + Rectangle newWindowRectangle = new Rectangle(screen.WorkingArea.Location, windowRectangle.Size); + if (workingArea.AreRectangleCornersVisisble(newWindowRectangle)) + { + formLocation = screen.Bounds.Location; + doesCaptureFit = true; + break; + } + } + } + else + { + doesCaptureFit = true; + } + } + else if (!WindowsVersion.IsWindows8OrLater) + { + //GetClientRect(out windowRectangle); + GetBorderSize(out borderSize); + formLocation = new Point(windowRectangle.X - borderSize.Width, windowRectangle.Y - borderSize.Height); + } + + tempForm.Location = formLocation; + tempForm.Size = sourceSize.ToSize(); + + // Prepare rectangle to capture from the screen. + Rectangle captureRectangle = new Rectangle(formLocation.X, formLocation.Y, sourceSize.Width, sourceSize.Height); + if (Maximised) + { + // Correct capture size for maximized window by offsetting the X,Y with the border size + // and subtracting the border from the size (2 times, as we move right/down for the capture without resizing) + captureRectangle.Inflate(borderSize.Width, borderSize.Height); + } + else + { + // TODO: Also 8.x? + if (WindowsVersion.IsWindows10OrLater) + { + captureRectangle.Inflate(Conf.Win10BorderCrop); + } + + if (autoMode) + { + // check if the capture fits + if (!doesCaptureFit) + { + // if GDI is allowed.. (a screenshot won't be better than we comes if we continue) + using Process thisWindowProcess = Process; + if (!IsMetroApp && WindowCapture.IsGdiAllowed(thisWindowProcess)) + { + // we return null which causes the capturing code to try another method. + return null; + } + } + } + } + + // Prepare the displaying of the Thumbnail + DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES + { + Opacity = 255, + Visible = true, + Destination = new RECT(0, 0, sourceSize.Width, sourceSize.Height) + }; + DWM.DwmUpdateThumbnailProperties(thumbnailHandle, ref props); + tempForm.Show(); + tempFormShown = true; + + // Intersect with screen + captureRectangle.Intersect(capture.ScreenBounds); + + // Destination bitmap for the capture + Bitmap capturedBitmap = null; + bool frozen = false; + try + { + // Check if we make a transparent capture + if (windowCaptureMode == WindowCaptureMode.AeroTransparent) + { + frozen = FreezeWindow(); + // Use white, later black to capture transparent + tempForm.BackColor = Color.White; + // Make sure everything is visible + tempForm.Refresh(); + Application.DoEvents(); + + try + { + using Bitmap whiteBitmap = WindowCapture.CaptureRectangle(captureRectangle); + // Apply a white color + tempForm.BackColor = Color.Black; + // Make sure everything is visible + tempForm.Refresh(); + if (!IsMetroApp) + { + // Make sure the application window is active, so the colors & buttons are right + ToForeground(); + } + + // Make sure all changes are processed and visible + Application.DoEvents(); + using Bitmap blackBitmap = WindowCapture.CaptureRectangle(captureRectangle); + capturedBitmap = ApplyTransparency(blackBitmap, whiteBitmap); + } + catch (Exception e) + { + Log.Debug("Exception: ", e); + // Some problem occurred, cleanup and make a normal capture + if (capturedBitmap != null) + { + capturedBitmap.Dispose(); + capturedBitmap = null; + } + } + } + + // If no capture up till now, create a normal capture. + if (capturedBitmap == null) + { + // Remove transparency, this will break the capturing + if (!autoMode) + { + tempForm.BackColor = Color.FromArgb(255, Conf.DWMBackgroundColor.R, Conf.DWMBackgroundColor.G, Conf.DWMBackgroundColor.B); + } + else + { + Color colorizationColor = DWM.ColorizationColor; + // Modify by losing the transparency and increasing the intensity (as if the background color is white) + colorizationColor = Color.FromArgb(255, (colorizationColor.R + 255) >> 1, (colorizationColor.G + 255) >> 1, (colorizationColor.B + 255) >> 1); + tempForm.BackColor = colorizationColor; + } + + // Make sure everything is visible + tempForm.Refresh(); + if (!IsMetroApp) + { + // Make sure the application window is active, so the colors & buttons are right + ToForeground(); + } + + // Make sure all changes are processed and visible + Application.DoEvents(); + // Capture from the screen + capturedBitmap = WindowCapture.CaptureRectangle(captureRectangle); + } + + if (capturedBitmap != null) + { + // Not needed for Windows 8 + if (!WindowsVersion.IsWindows8OrLater) + { + // Only if the Inivalue is set, not maximized and it's not a tool window. + if (Conf.WindowCaptureRemoveCorners && !Maximised && (ExtendedWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) == 0) + { + // Remove corners + if (!Image.IsAlphaPixelFormat(capturedBitmap.PixelFormat)) + { + Log.Debug("Changing pixelformat to Alpha for the RemoveCorners"); + Bitmap tmpBitmap = ImageHelper.Clone(capturedBitmap, PixelFormat.Format32bppArgb); + capturedBitmap.Dispose(); + capturedBitmap = tmpBitmap; + } + + RemoveCorners(capturedBitmap); + } + } + } + } + finally + { + // Make sure to ALWAYS unfreeze!! + if (frozen) + { + UnfreezeWindow(); + } + } + + capture.Image = capturedBitmap; + // Make sure the capture location is the location of the window, not the copy + capture.Location = Location; + } + finally + { + if (thumbnailHandle != IntPtr.Zero) + { + // Unregister (cleanup), as we are finished we don't need the form or the thumbnail anymore + DWM.DwmUnregisterThumbnail(thumbnailHandle); + } + + if (tempForm != null) + { + if (tempFormShown) + { + tempForm.Close(); + } + + tempForm.Dispose(); + tempForm = null; + } + } + + return capture; + } + + /// + /// Helper method to remove the corners from a DMW capture + /// + /// The bitmap to remove the corners from. + private void RemoveCorners(Bitmap image) + { + using IFastBitmap fastBitmap = FastBitmap.Create(image); + for (int y = 0; y < Conf.WindowCornerCutShape.Count; y++) + { + for (int x = 0; x < Conf.WindowCornerCutShape[y]; x++) + { + fastBitmap.SetColorAt(x, y, Color.Transparent); + fastBitmap.SetColorAt(image.Width - 1 - x, y, Color.Transparent); + fastBitmap.SetColorAt(image.Width - 1 - x, image.Height - 1 - y, Color.Transparent); + fastBitmap.SetColorAt(x, image.Height - 1 - y, Color.Transparent); + } + } + } + + /// + /// Apply transparency by comparing a transparent capture with a black and white background + /// A "Math.min" makes sure there is no overflow, but this could cause the picture to have shifted colors. + /// The pictures should have been taken without differency, except for the colors. + /// + /// Bitmap with the black image + /// Bitmap with the black image + /// Bitmap with transparency + private Bitmap ApplyTransparency(Bitmap blackBitmap, Bitmap whiteBitmap) + { + using IFastBitmap targetBuffer = FastBitmap.CreateEmpty(blackBitmap.Size, PixelFormat.Format32bppArgb, Color.Transparent); + targetBuffer.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution); + using (IFastBitmap blackBuffer = FastBitmap.Create(blackBitmap)) + { + using IFastBitmap whiteBuffer = FastBitmap.Create(whiteBitmap); + for (int y = 0; y < blackBuffer.Height; y++) + { + for (int x = 0; x < blackBuffer.Width; x++) + { + Color c0 = blackBuffer.GetColorAt(x, y); + Color c1 = whiteBuffer.GetColorAt(x, y); + // Calculate alpha as double in range 0-1 + int alpha = c0.R - c1.R + 255; + if (alpha == 255) + { + // Alpha == 255 means no change! + targetBuffer.SetColorAt(x, y, c0); + } + else if (alpha == 0) + { + // Complete transparency, use transparent pixel + targetBuffer.SetColorAt(x, y, Color.Transparent); + } + else + { + // Calculate original color + byte originalAlpha = (byte) Math.Min(255, alpha); + var alphaFactor = alpha / 255d; + //LOG.DebugFormat("Alpha {0} & c0 {1} & c1 {2}", alpha, c0, c1); + byte originalRed = (byte) Math.Min(255, c0.R / alphaFactor); + byte originalGreen = (byte) Math.Min(255, c0.G / alphaFactor); + byte originalBlue = (byte) Math.Min(255, c0.B / alphaFactor); + Color originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue); + //Color originalColor = Color.FromArgb(originalAlpha, originalRed, c0.G, c0.B); + targetBuffer.SetColorAt(x, y, originalColor); + } + } + } + } + + return targetBuffer.UnlockAndReturnBitmap(); + } + + /// + /// Helper method to get the window size for DWM Windows + /// + /// out Rectangle + /// bool true if it worked + private bool GetExtendedFrameBounds(out Rectangle rectangle) + { + int result = DWM.DwmGetWindowAttribute(Handle, DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out RECT rect, Marshal.SizeOf(typeof(RECT))); + if (result >= 0) + { + rectangle = rect.ToRectangle(); + return true; + } + + rectangle = Rectangle.Empty; + return false; + } + + /// + /// Helper method to get the window size for GDI Windows + /// + /// out Rectangle + /// bool true if it worked + private bool GetClientRect(out Rectangle rectangle) + { + var windowInfo = new WindowInfo(); + // Get the Window Info for this window + bool result = User32.GetWindowInfo(Handle, ref windowInfo); + rectangle = result ? windowInfo.rcClient.ToRectangle() : Rectangle.Empty; + return result; + } + + /// + /// Helper method to get the window size for GDI Windows + /// + /// out Rectangle + /// bool true if it worked + private bool GetWindowRect(out Rectangle rectangle) + { + var windowInfo = new WindowInfo(); + // Get the Window Info for this window + bool result = User32.GetWindowInfo(Handle, ref windowInfo); + rectangle = result ? windowInfo.rcWindow.ToRectangle() : Rectangle.Empty; + return result; + } + + /// + /// Helper method to get the Border size for GDI Windows + /// + /// out Size + /// bool true if it worked + private bool GetBorderSize(out Size size) + { + var windowInfo = new WindowInfo(); + // Get the Window Info for this window + bool result = User32.GetWindowInfo(Handle, ref windowInfo); + size = result ? new Size((int) windowInfo.cxWindowBorders, (int) windowInfo.cyWindowBorders) : Size.Empty; + return result; + } + + /// + /// Set the window as foreground window + /// + /// hWnd of the window to bring to the foreground + public static void ToForeground(IntPtr hWnd) + { + var foregroundWindow = User32.GetForegroundWindow(); + if (hWnd == foregroundWindow) + { + return; + } + + var window = new WindowDetails(hWnd); + // Nothing we can do if it's not visible! + if (!window.Visible) + { + return; + } + + var threadId1 = User32.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero); + var threadId2 = User32.GetWindowThreadProcessId(hWnd, IntPtr.Zero); + + // Show window in foreground. + if (threadId1 != threadId2) + { + User32.AttachThreadInput(threadId1, threadId2, 1); + User32.SetForegroundWindow(hWnd); + User32.AttachThreadInput(threadId1, threadId2, 0); + } + else + { + User32.SetForegroundWindow(hWnd); + } + + User32.BringWindowToTop(hWnd); + + if (window.Iconic) + { + window.Iconic = false; + } + } + + /// + /// Set the window as foreground window + /// + public void ToForeground() + { + ToForeground(Handle); + } + + /// + /// Get the region for a window + /// + private Region GetRegion() + { + using (SafeRegionHandle region = GDI32.CreateRectRgn(0, 0, 0, 0)) + { + if (!region.IsInvalid) + { + RegionResult result = User32.GetWindowRgn(Handle, region); + if (result != RegionResult.REGION_ERROR && result != RegionResult.REGION_NULLREGION) + { + return Region.FromHrgn(region.DangerousGetHandle()); + } + } + } + + return null; + } + + private bool CanFreezeOrUnfreeze(string titleOrProcessname) + { + if (string.IsNullOrEmpty(titleOrProcessname)) + { + return false; + } + + if (titleOrProcessname.ToLower().Contains("greenshot")) + { + return false; + } + + foreach (string excludeProcess in ExcludeProcessesFromFreeze) + { + if (titleOrProcessname.ToLower().Contains(excludeProcess)) + { + return false; + } + } + + return true; + } + + /// + /// Freezes the process belonging to the window + /// Warning: Use only if no other way!! + /// + private bool FreezeWindow() + { + bool frozen = false; + using (Process proc = Process.GetProcessById(ProcessId)) + { + string processName = proc.ProcessName; + if (!CanFreezeOrUnfreeze(processName)) + { + Log.DebugFormat("Not freezing {0}", processName); + return false; + } + + if (!CanFreezeOrUnfreeze(Text)) + { + Log.DebugFormat("Not freezing {0}", processName); + return false; + } + + Log.DebugFormat("Freezing process: {0}", processName); + + + foreach (ProcessThread pT in proc.Threads) + { + IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); + + if (pOpenThread == IntPtr.Zero) + { + break; + } + + frozen = true; + Kernel32.SuspendThread(pOpenThread); + pT.Dispose(); + } + } + + return frozen; + } + + /// + /// Unfreeze the process belonging to the window + /// + public void UnfreezeWindow() + { + using Process proc = Process.GetProcessById(ProcessId); + string processName = proc.ProcessName; + if (!CanFreezeOrUnfreeze(processName)) + { + Log.DebugFormat("Not unfreezing {0}", processName); + return; + } + + if (!CanFreezeOrUnfreeze(Text)) + { + Log.DebugFormat("Not unfreezing {0}", processName); + return; + } + + Log.DebugFormat("Unfreezing process: {0}", processName); + + foreach (ProcessThread pT in proc.Threads) + { + IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); + + if (pOpenThread == IntPtr.Zero) + { + break; + } + + Kernel32.ResumeThread(pOpenThread); + } + } + + /// + /// Return an Image representing the Window! + /// As GDI+ draws it, it will be without Aero borders! + /// + public Image PrintWindow() + { + Rectangle windowRect = WindowRectangle; + // Start the capture + Exception exceptionOccured = null; + Image returnImage; + using (Region region = GetRegion()) + { + PixelFormat pixelFormat = PixelFormat.Format24bppRgb; + // Only use 32 bpp ARGB when the window has a region + if (region != null) + { + pixelFormat = PixelFormat.Format32bppArgb; + } + + returnImage = new Bitmap(windowRect.Width, windowRect.Height, pixelFormat); + using Graphics graphics = Graphics.FromImage(returnImage); + using (SafeDeviceContextHandle graphicsDc = graphics.GetSafeDeviceContext()) + { + bool printSucceeded = User32.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), 0x0); + if (!printSucceeded) + { + // something went wrong, most likely a "0x80004005" (Acess Denied) when using UAC + exceptionOccured = User32.CreateWin32Exception("PrintWindow"); + } + } + + // Apply the region "transparency" + if (region != null && !region.IsEmpty(graphics)) + { + graphics.ExcludeClip(region); + graphics.Clear(Color.Transparent); + } + + graphics.Flush(); + } + + // Return null if error + if (exceptionOccured != null) + { + Log.ErrorFormat("Error calling print window: {0}", exceptionOccured.Message); + returnImage.Dispose(); + return null; + } + + if (!HasParent && Maximised) + { + Log.Debug("Correcting for maximalization"); + GetBorderSize(out var borderSize); + Rectangle borderRectangle = new Rectangle(borderSize.Width, borderSize.Height, windowRect.Width - (2 * borderSize.Width), + windowRect.Height - (2 * borderSize.Height)); + ImageHelper.Crop(ref returnImage, ref borderRectangle); + } + + return returnImage; + } + + /// + /// Constructs a new instance of this class for + /// the specified Window Handle. + /// + /// The Window Handle + public WindowDetails(IntPtr hWnd) + { + Handle = hWnd; + } + + /// + /// Gets an instance of the current active foreground window + /// + /// WindowDetails of the current window + public static WindowDetails GetActiveWindow() + { + IntPtr hWnd = User32.GetForegroundWindow(); + if (hWnd != IntPtr.Zero) + { + if (IgnoreHandles.Contains(hWnd)) + { + return GetDesktopWindow(); + } + + WindowDetails activeWindow = new WindowDetails(hWnd); + // Invisible Windows should not be active + if (!activeWindow.Visible) + { + return GetDesktopWindow(); + } + + return activeWindow; + } + + return null; + } + + /// + /// Gets the Desktop window + /// + /// WindowDetails for the desktop window + public static WindowDetails GetDesktopWindow() + { + return new WindowDetails(User32.GetDesktopWindow()); + } + + /// + /// Get all the top level windows + /// + /// List of WindowDetails with all the top level windows + public static IList GetAllWindows() + { + return GetAllWindows(null); + } + + /// + /// Get all the top level windows, with matching classname + /// + /// List WindowDetails with all the top level windows + public static IList GetAllWindows(string classname) + { + return new WindowsEnumerator().GetWindows(IntPtr.Zero, classname).Items; + } + + /// + /// Recursive "find children which" + /// + /// point to check for + /// + public WindowDetails FindChildUnderPoint(Point point) + { + if (!Contains(point)) + { + return null; + } + + var rect = WindowRectangle; + // If the mouse it at the edge, take the whole window + if (rect.X == point.X || rect.Y == point.Y || rect.Right == point.X || rect.Bottom == point.Y) + { + return this; + } + + // Look into the child windows + foreach (var childWindow in Children) + { + if (childWindow.Contains(point)) + { + return childWindow.FindChildUnderPoint(point); + } + } + + return this; + } + + /// + /// Retrieves the classname for a hWnd + /// + /// IntPtr with the windows handle + /// String with ClassName + public static string GetClassName(IntPtr hWnd) + { + var classNameBuilder = new StringBuilder(260, 260); + User32.GetClassName(hWnd, classNameBuilder, classNameBuilder.Capacity); + return classNameBuilder.ToString(); + } + + /// + /// Helper method to decide if a top level window is visible + /// + /// + /// + /// + private static bool IsVisible(WindowDetails window, Rectangle screenBounds) + { + // Ignore invisible + if (!window.Visible) + { + return false; + } + + // Ignore minimized + if (window.Iconic) + { + return false; + } + + if (IgnoreClasses.Contains(window.ClassName)) + { + return false; + } + + // On windows which are visible on the screen + var windowRect = window.WindowRectangle; + windowRect.Intersect(screenBounds); + if (windowRect.IsEmpty) + { + return false; + } + + // Skip everything which is not rendered "normally", trying to fix BUG-2017 + var exWindowStyle = window.ExtendedWindowStyle; + if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) + { + return false; + } + + return true; + } + + /// + /// Get all the visible top level windows + /// + /// List WindowDetails with all the visible top level windows + public static IEnumerable GetVisibleWindows() + { + Rectangle screenBounds = WindowCapture.GetScreenBounds(); + foreach (var window in GetAppWindows()) + { + if (IsVisible(window, screenBounds)) + { + yield return window; + } + } + + foreach (var window in GetAllWindows()) + { + if (IsVisible(window, screenBounds)) + { + yield return window; + } + } + } + + /// + /// Get the WindowDetails for all Metro Apps + /// These are all Windows with Classname "Windows.UI.Core.CoreWindow" + /// + /// List WindowDetails with visible metro apps + public static IEnumerable GetAppWindows() + { + // if the appVisibility != null we have Windows 8. + if (AppVisibility == null) + { + yield break; + } + + var nextHandle = User32.FindWindow(AppWindowClass, null); + while (nextHandle != IntPtr.Zero) + { + var metroApp = new WindowDetails(nextHandle); + yield return metroApp; + // Check if we have a gutter! + if (metroApp.Visible && !metroApp.Maximised) + { + var gutterHandle = User32.FindWindow(GutterClass, null); + if (gutterHandle != IntPtr.Zero) + { + yield return new WindowDetails(gutterHandle); + } + } + + nextHandle = User32.FindWindowEx(IntPtr.Zero, nextHandle, AppWindowClass, null); + } + } + + /// + /// Check if the window is a top level + /// + /// WindowDetails + /// bool + private static bool IsTopLevel(WindowDetails window) + { + if (window.IsCloaked) + { + return false; + } + + // Windows without size + if (window.WindowRectangle.Size.Width * window.WindowRectangle.Size.Height == 0) + { + return false; + } + + if (window.HasParent) + { + return false; + } + + var exWindowStyle = window.ExtendedWindowStyle; + if ((exWindowStyle & ExtendedWindowStyleFlags.WS_EX_TOOLWINDOW) != 0) + { + return false; + } + + // Skip everything which is not rendered "normally", trying to fix BUG-2017 + if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) + { + return false; + } + + // Skip preview windows, like the one from Firefox + if ((window.WindowStyle & WindowStyleFlags.WS_VISIBLE) == 0) + { + return false; + } + + // Ignore windows without title + if (window.Text.Length == 0) + { + return false; + } + + if (IgnoreClasses.Contains(window.ClassName)) + { + return false; + } + + if (!(window.Visible || window.Iconic)) + { + return false; + } + + return !window.IsBackgroundWin10App; + } + + /// + /// Get all the top level windows + /// + /// List WindowDetails with all the top level windows + public static IEnumerable GetTopLevelWindows() + { + foreach (var possibleTopLevel in GetAppWindows()) + { + if (IsTopLevel(possibleTopLevel)) + { + yield return possibleTopLevel; + } + } + + foreach (var possibleTopLevel in GetAllWindows()) + { + if (IsTopLevel(possibleTopLevel)) + { + yield return possibleTopLevel; + } + } + } + + /// + /// Find a window belonging to the same process as the supplied window. + /// + /// + /// + public static WindowDetails GetLinkedWindow(WindowDetails windowToLinkTo) + { + int processIdSelectedWindow = windowToLinkTo.ProcessId; + foreach (var window in GetAllWindows()) + { + // Ignore windows without title + if (window.Text.Length == 0) + { + continue; + } + + // Ignore invisible + if (!window.Visible) + { + continue; + } + + if (window.Handle == windowToLinkTo.Handle) + { + continue; + } + + if (window.Iconic) + { + continue; + } + + // Windows without size + Size windowSize = window.WindowRectangle.Size; + if (windowSize.Width == 0 || windowSize.Height == 0) + { + continue; + } + + if (window.ProcessId == processIdSelectedWindow) + { + Log.InfoFormat("Found window {0} belonging to same process as the window {1}", window.Text, windowToLinkTo.Text); + return window; + } + } + + return null; + } + + /// + /// Helper method to "active" all windows that are not in the supplied list. + /// One should preferably call "GetVisibleWindows" for the oldWindows. + /// + /// List WindowDetails with old windows + public static void ActiveNewerWindows(IEnumerable oldWindows) + { + var oldWindowsList = new List(oldWindows); + foreach (var window in GetVisibleWindows()) + { + if (!oldWindowsList.Contains(window)) + { + window.ToForeground(); + } + } + } + + /// + /// Get the AppLauncher + /// + /// + public static WindowDetails GetAppLauncher() + { + // Only if Windows 8 (or higher) + if (AppVisibility == null) + { + return null; + } + + IntPtr appLauncher = User32.FindWindow(ApplauncherClass, null); + if (appLauncher != IntPtr.Zero) + { + return new WindowDetails(appLauncher); + } + + return null; + } + + /// + /// Return true if the metro-app-launcher is visible + /// + /// + public static bool IsAppLauncherVisible + { + get + { + if (AppVisibility != null) + { + return AppVisibility.IsLauncherVisible; + } + + return false; + } + } + + /// + /// Make a string representation of the window details + /// + /// string + public override string ToString() + { + var result = new StringBuilder(); + result.AppendLine($"Text: {Text}"); + result.AppendLine($"ClassName: {ClassName}"); + result.AppendLine($"ExtendedWindowStyle: {ExtendedWindowStyle}"); + result.AppendLine($"WindowStyle: {WindowStyle}"); + result.AppendLine($"Size: {WindowRectangle.Size}"); + result.AppendLine($"HasParent: {HasParent}"); + result.AppendLine($"IsWin10App: {IsWin10App}"); + result.AppendLine($"IsApp: {IsApp}"); + result.AppendLine($"Visible: {Visible}"); + result.AppendLine($"IsWindowVisible: {User32.IsWindowVisible(Handle)}"); + result.AppendLine($"IsCloaked: {IsCloaked}"); + result.AppendLine($"Iconic: {Iconic}"); + result.AppendLine($"IsBackgroundWin10App: {IsBackgroundWin10App}"); + if (HasChildren) + { + result.AppendLine($"Children classes: {string.Join(",", Children.Select(c => c.ClassName))}"); + } + + return result.ToString(); + } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/Core/WindowsEnumerator.cs b/src/Greenshot.Base/Core/WindowsEnumerator.cs new file mode 100644 index 000000000..7278a3131 --- /dev/null +++ b/src/Greenshot.Base/Core/WindowsEnumerator.cs @@ -0,0 +1,108 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using Greenshot.Base.UnmanagedHelpers; + +namespace Greenshot.Base.Core +{ + /// + /// EnumWindows wrapper for .NET + /// + public class WindowsEnumerator + { + /// + /// Returns the collection of windows returned by GetWindows + /// + public IList Items { get; private set; } + + /// + /// Gets all child windows of the specified window + /// + /// Window Handle to get children for + /// Window Classname to copy, use null to copy all + public WindowsEnumerator GetWindows(IntPtr hWndParent, string classname) + { + Items = new List(); + User32.EnumChildWindows(hWndParent, WindowEnum, IntPtr.Zero); + + bool hasParent = !IntPtr.Zero.Equals(hWndParent); + string parentText = null; + if (hasParent) + { + var title = new StringBuilder(260, 260); + User32.GetWindowText(hWndParent, title, title.Capacity); + parentText = title.ToString(); + } + + var windows = new List(); + foreach (var window in Items) + { + if (hasParent) + { + window.Text = parentText; + window.ParentHandle = hWndParent; + } + + if (classname == null || window.ClassName.Equals(classname)) + { + windows.Add(window); + } + } + + Items = windows; + return this; + } + + /// + /// The enum Windows callback. + /// + /// Window Handle + /// Application defined value + /// 1 to continue enumeration, 0 to stop + private int WindowEnum(IntPtr hWnd, int lParam) + { + return OnWindowEnum(hWnd) ? 1 : 0; + } + + /// + /// Called whenever a new window is about to be added + /// by the Window enumeration called from GetWindows. + /// If overriding this function, return true to continue + /// enumeration or false to stop. If you do not call + /// the base implementation the Items collection will + /// be empty. + /// + /// Window handle to add + /// True to continue enumeration, False to stop + private bool OnWindowEnum(IntPtr hWnd) + { + if (!WindowDetails.IsIgnoreHandle(hWnd)) + { + Items.Add(new WindowDetails(hWnd)); + } + + return true; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Core/WindowsVersion.cs b/src/Greenshot.Base/Core/WindowsVersion.cs similarity index 98% rename from GreenshotPlugin/Core/WindowsVersion.cs rename to src/Greenshot.Base/Core/WindowsVersion.cs index 703fcd206..bf3af14ce 100644 --- a/GreenshotPlugin/Core/WindowsVersion.cs +++ b/src/Greenshot.Base/Core/WindowsVersion.cs @@ -3,7 +3,7 @@ using System; -namespace GreenshotPlugin.Core +namespace Greenshot.Base.Core { /// /// Extension methods to test the windows version diff --git a/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs b/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs new file mode 100644 index 000000000..3d59bcb28 --- /dev/null +++ b/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs @@ -0,0 +1,66 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Windows.Forms; +using Greenshot.Base.UnmanagedHelpers.Enums; +using log4net; + +namespace Greenshot.Base.Core +{ + /// + /// This IMessageFilter filters out all WM_INPUTLANGCHANGEREQUEST messages which go to a handle which is >32 bits. + /// The need for this is documented here: http://stackoverflow.com/a/32021586 + /// + public class WmInputLangChangeRequestFilter : IMessageFilter + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(WmInputLangChangeRequestFilter)); + + /// + /// This will do some filtering + /// + /// Message + /// true if the message should be filtered + public bool PreFilterMessage(ref Message m) + { + return PreFilterMessageExternal(ref m); + } + + /// + /// Also used in the MainForm WndProc + /// + /// Message + /// true if the message should be filtered + public static bool PreFilterMessageExternal(ref Message m) + { + WindowsMessages message = (WindowsMessages) m.Msg; + if (message == WindowsMessages.WM_INPUTLANGCHANGEREQUEST || message == WindowsMessages.WM_INPUTLANGCHANGE) + { + LOG.WarnFormat("Filtering: {0}, {1:X} - {2:X} - {3:X}", message, m.LParam.ToInt64(), m.WParam.ToInt64(), m.HWnd.ToInt64()); + // For now we always return true + return true; + // But it could look something like this: + //return (m.LParam.ToInt64() | 0x7FFFFFFF) != 0; + } + + return false; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Effects/MonochromeEffect.cs b/src/Greenshot.Base/Effects/AdjustEffect.cs similarity index 59% rename from GreenshotPlugin/Effects/MonochromeEffect.cs rename to src/Greenshot.Base/Effects/AdjustEffect.cs index 8e0b69c7b..8445c09a8 100644 --- a/GreenshotPlugin/Effects/MonochromeEffect.cs +++ b/src/Greenshot.Base/Effects/AdjustEffect.cs @@ -1,44 +1,54 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// MonochromeEffect - /// - public class MonochromeEffect : IEffect { - private readonly byte _threshold; - /// Threshold for monochrome filter (0 - 255), lower value means less black - public MonochromeEffect(byte threshold) { - _threshold = threshold; - } - public void Reset() { - // TODO: Modify the threshold to have a default, which is reset here - } - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.CreateMonochrome(sourceImage, _threshold); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// AdjustEffect + /// + public class AdjustEffect : IEffect + { + public AdjustEffect() + { + Reset(); + } + + public float Contrast { get; set; } + public float Brightness { get; set; } + public float Gamma { get; set; } + + public void Reset() + { + Contrast = 1f; + Brightness = 1f; + Gamma = 1f; + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.Adjust(sourceImage, Brightness, Contrast, Gamma); + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/Effects/BorderEffect.cs b/src/Greenshot.Base/Effects/BorderEffect.cs similarity index 61% rename from GreenshotPlugin/Effects/BorderEffect.cs rename to src/Greenshot.Base/Effects/BorderEffect.cs index 4e45f920c..b297dcad8 100644 --- a/GreenshotPlugin/Effects/BorderEffect.cs +++ b/src/Greenshot.Base/Effects/BorderEffect.cs @@ -1,51 +1,52 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// BorderEffect - /// - public class BorderEffect : IEffect { - public BorderEffect() { - Reset(); - } - public Color Color { - get; - set; - } - public int Width { - get; - set; - } - public void Reset() { - Width = 2; - Color = Color.Black; - } - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.CreateBorder(sourceImage, Width, Color, sourceImage.PixelFormat, matrix); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// BorderEffect + /// + public class BorderEffect : IEffect + { + public BorderEffect() + { + Reset(); + } + + public Color Color { get; set; } + public int Width { get; set; } + + public void Reset() + { + Width = 2; + Color = Color.Black; + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateBorder(sourceImage, Width, Color, sourceImage.PixelFormat, matrix); + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/Effects/DropShadowEffect.cs b/src/Greenshot.Base/Effects/DropShadowEffect.cs similarity index 56% rename from GreenshotPlugin/Effects/DropShadowEffect.cs rename to src/Greenshot.Base/Effects/DropShadowEffect.cs index 5f05b889f..2ca91aabf 100644 --- a/GreenshotPlugin/Effects/DropShadowEffect.cs +++ b/src/Greenshot.Base/Effects/DropShadowEffect.cs @@ -1,63 +1,59 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects { - /// - /// DropShadowEffect - /// - [TypeConverter(typeof(EffectConverter))] - public class DropShadowEffect : IEffect { - public DropShadowEffect() { - Reset(); - } - - public float Darkness { - get; - set; - } - - public int ShadowSize { - get; - set; - } - - public Point ShadowOffset { - get; - set; - } - - public virtual void Reset() { - Darkness = 0.6f; - ShadowSize = 7; - ShadowOffset = new Point(-1, -1); - } - - public virtual Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.CreateShadow(sourceImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// DropShadowEffect + /// + [TypeConverter(typeof(EffectConverter))] + public class DropShadowEffect : IEffect + { + public DropShadowEffect() + { + Reset(); + } + + public float Darkness { get; set; } + + public int ShadowSize { get; set; } + + public Point ShadowOffset { get; set; } + + public virtual void Reset() + { + Darkness = 0.6f; + ShadowSize = 7; + ShadowOffset = new Point(-1, -1); + } + + public virtual Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateShadow(sourceImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/Effects/GrayscaleEffect.cs b/src/Greenshot.Base/Effects/GrayscaleEffect.cs similarity index 70% rename from GreenshotPlugin/Effects/GrayscaleEffect.cs rename to src/Greenshot.Base/Effects/GrayscaleEffect.cs index 7c8e5c7b2..b557dbd7d 100644 --- a/GreenshotPlugin/Effects/GrayscaleEffect.cs +++ b/src/Greenshot.Base/Effects/GrayscaleEffect.cs @@ -1,39 +1,43 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// GrayscaleEffect - /// - public class GrayscaleEffect : IEffect { - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.CreateGrayscale(sourceImage); - } - public void Reset() { - // No settings to reset - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// GrayscaleEffect + /// + public class GrayscaleEffect : IEffect + { + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateGrayscale(sourceImage); + } + + public void Reset() + { + // No settings to reset + } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/Effects/IEffect.cs b/src/Greenshot.Base/Effects/IEffect.cs new file mode 100644 index 000000000..e0a8fb6a0 --- /dev/null +++ b/src/Greenshot.Base/Effects/IEffect.cs @@ -0,0 +1,46 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; + +namespace Greenshot.Base.Effects +{ + /// + /// Interface to describe an effect + /// + public interface IEffect + { + /// + /// Apply this IEffect to the supplied sourceImage. + /// In the process of applying the supplied matrix will be modified to represent the changes. + /// + /// Image to apply the effect to + /// Matrix with the modifications like rotate, translate etc. this can be used to calculate the new location of elements on a canvas + /// new image with applied effect + Image Apply(Image sourceImage, Matrix matrix); + + /// + /// Reset all values to their defaults + /// + void Reset(); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Effects/InvertEffect.cs b/src/Greenshot.Base/Effects/InvertEffect.cs similarity index 71% rename from GreenshotPlugin/Effects/InvertEffect.cs rename to src/Greenshot.Base/Effects/InvertEffect.cs index f890f5dd5..4d5ce8dc7 100644 --- a/GreenshotPlugin/Effects/InvertEffect.cs +++ b/src/Greenshot.Base/Effects/InvertEffect.cs @@ -1,39 +1,43 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// InvertEffect - /// - public class InvertEffect : IEffect { - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.CreateNegative(sourceImage); - } - public void Reset() { - // No settings to reset - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// InvertEffect + /// + public class InvertEffect : IEffect + { + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateNegative(sourceImage); + } + + public void Reset() + { + // No settings to reset + } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/Effects/MonochromeEffect.cs b/src/Greenshot.Base/Effects/MonochromeEffect.cs new file mode 100644 index 000000000..5a9be096b --- /dev/null +++ b/src/Greenshot.Base/Effects/MonochromeEffect.cs @@ -0,0 +1,51 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// MonochromeEffect + /// + public class MonochromeEffect : IEffect + { + private readonly byte _threshold; + + /// Threshold for monochrome filter (0 - 255), lower value means less black + public MonochromeEffect(byte threshold) + { + _threshold = threshold; + } + + public void Reset() + { + // TODO: Modify the threshold to have a default, which is reset here + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.CreateMonochrome(sourceImage, _threshold); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Effects/ReduceColorsEffect.cs b/src/Greenshot.Base/Effects/ReduceColorsEffect.cs new file mode 100644 index 000000000..cd119544f --- /dev/null +++ b/src/Greenshot.Base/Effects/ReduceColorsEffect.cs @@ -0,0 +1,70 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; +using log4net; + +namespace Greenshot.Base.Effects +{ + /// + /// ReduceColorsEffect + /// + public class ReduceColorsEffect : IEffect + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ReduceColorsEffect)); + + public ReduceColorsEffect() + { + Reset(); + } + + public int Colors { get; set; } + + public void Reset() + { + Colors = 256; + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + using (WuQuantizer quantizer = new WuQuantizer((Bitmap) sourceImage)) + { + int colorCount = quantizer.GetColorCount(); + if (colorCount > Colors) + { + try + { + return quantizer.GetQuantizedImage(Colors); + } + catch (Exception e) + { + Log.Warn("Error occurred while Quantizing the image, ignoring and using original. Error: ", e); + } + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Effects/ResizeCanvasEffect.cs b/src/Greenshot.Base/Effects/ResizeCanvasEffect.cs similarity index 50% rename from GreenshotPlugin/Effects/ResizeCanvasEffect.cs rename to src/Greenshot.Base/Effects/ResizeCanvasEffect.cs index 67bbf6e7d..5a8742f3d 100644 --- a/GreenshotPlugin/Effects/ResizeCanvasEffect.cs +++ b/src/Greenshot.Base/Effects/ResizeCanvasEffect.cs @@ -1,66 +1,58 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; -using GreenshotPlugin.Core; - -namespace GreenshotPlugin.Effects -{ - /// - /// ResizeCanvasEffect - /// - public class ResizeCanvasEffect : IEffect { - public ResizeCanvasEffect(int left, int right, int top, int bottom) { - Left = left; - Right = right; - Top = top; - Bottom = bottom; - BackgroundColor = Color.Empty; // Uses the default background color depending on the format - } - public int Left { - get; - set; - } - public int Right { - get; - set; - } - public int Top { - get; - set; - } - public int Bottom { - get; - set; - } - public Color BackgroundColor { - get; - set; - } - public void Reset() { - // values don't have a default value - } - public Image Apply(Image sourceImage, Matrix matrix) { - return ImageHelper.ResizeCanvas(sourceImage, BackgroundColor, Left, Right, Top, Bottom, matrix); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// ResizeCanvasEffect + /// + public class ResizeCanvasEffect : IEffect + { + public ResizeCanvasEffect(int left, int right, int top, int bottom) + { + Left = left; + Right = right; + Top = top; + Bottom = bottom; + BackgroundColor = Color.Empty; // Uses the default background color depending on the format + } + + public int Left { get; set; } + public int Right { get; set; } + public int Top { get; set; } + public int Bottom { get; set; } + public Color BackgroundColor { get; set; } + + public void Reset() + { + // values don't have a default value + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.ResizeCanvas(sourceImage, BackgroundColor, Left, Right, Top, Bottom, matrix); + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/Effects/IEffect.cs b/src/Greenshot.Base/Effects/ResizeEffect.cs similarity index 55% rename from GreenshotPlugin/Effects/IEffect.cs rename to src/Greenshot.Base/Effects/ResizeEffect.cs index 1beeb1aa5..b756cbaff 100644 --- a/GreenshotPlugin/Effects/IEffect.cs +++ b/src/Greenshot.Base/Effects/ResizeEffect.cs @@ -1,45 +1,54 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Drawing2D; - -namespace GreenshotPlugin.Effects -{ - /// - /// Interface to describe an effect - /// - public interface IEffect { - /// - /// Apply this IEffect to the supplied sourceImage. - /// In the process of applying the supplied matrix will be modified to represent the changes. - /// - /// Image to apply the effect to - /// Matrix with the modifications like rotate, translate etc. this can be used to calculate the new location of elements on a canvas - /// new image with applied effect - Image Apply(Image sourceImage, Matrix matrix); - - /// - /// Reset all values to their defaults - /// - void Reset(); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// ResizeEffect + /// + public class ResizeEffect : IEffect + { + public ResizeEffect(int width, int height, bool maintainAspectRatio) + { + Width = width; + Height = height; + MaintainAspectRatio = maintainAspectRatio; + } + + public int Width { get; set; } + public int Height { get; set; } + public bool MaintainAspectRatio { get; set; } + + public void Reset() + { + // values don't have a default value + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + return ImageHelper.ResizeImage(sourceImage, MaintainAspectRatio, Width, Height, matrix); + } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/Effects/RotateEffect.cs b/src/Greenshot.Base/Effects/RotateEffect.cs new file mode 100644 index 000000000..09c00d35b --- /dev/null +++ b/src/Greenshot.Base/Effects/RotateEffect.cs @@ -0,0 +1,69 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// RotateEffect + /// + public class RotateEffect : IEffect + { + public RotateEffect(int angle) + { + Angle = angle; + } + + public int Angle { get; set; } + + public void Reset() + { + // Angle doesn't have a default value + } + + public Image Apply(Image sourceImage, Matrix matrix) + { + RotateFlipType flipType; + if (Angle == 90) + { + matrix.Rotate(90, MatrixOrder.Append); + matrix.Translate(sourceImage.Height, 0, MatrixOrder.Append); + flipType = RotateFlipType.Rotate90FlipNone; + } + else if (Angle == -90 || Angle == 270) + { + flipType = RotateFlipType.Rotate270FlipNone; + matrix.Rotate(-90, MatrixOrder.Append); + matrix.Translate(0, sourceImage.Width, MatrixOrder.Append); + } + else + { + throw new NotSupportedException("Currently only an angle of 90 or -90 (270) is supported."); + } + + return ImageHelper.RotateFlip(sourceImage, flipType); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Effects/TornEdgeEffect.cs b/src/Greenshot.Base/Effects/TornEdgeEffect.cs new file mode 100644 index 000000000..e283593fc --- /dev/null +++ b/src/Greenshot.Base/Effects/TornEdgeEffect.cs @@ -0,0 +1,75 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using Greenshot.Base.Core; + +namespace Greenshot.Base.Effects +{ + /// + /// TornEdgeEffect extends on DropShadowEffect + /// + [TypeConverter(typeof(EffectConverter))] + public sealed class TornEdgeEffect : DropShadowEffect + { + public TornEdgeEffect() + { + Reset(); + } + + public int ToothHeight { get; set; } + public int HorizontalToothRange { get; set; } + public int VerticalToothRange { get; set; } + public bool[] Edges { get; set; } + public bool GenerateShadow { get; set; } + + public override void Reset() + { + base.Reset(); + ShadowSize = 7; + ToothHeight = 12; + HorizontalToothRange = 20; + VerticalToothRange = 20; + Edges = new[] + { + true, true, true, true + }; + GenerateShadow = true; + } + + public override Image Apply(Image sourceImage, Matrix matrix) + { + Image tmpTornImage = ImageHelper.CreateTornEdge(sourceImage, ToothHeight, HorizontalToothRange, VerticalToothRange, Edges); + if (GenerateShadow) + { + using (tmpTornImage) + { + return ImageHelper.CreateShadow(tmpTornImage, Darkness, ShadowSize, ShadowOffset, matrix, PixelFormat.Format32bppArgb); + } + } + + return tmpTornImage; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/FileDescriptorReader.cs b/src/Greenshot.Base/FileDescriptorReader.cs similarity index 94% rename from GreenshotPlugin/FileDescriptorReader.cs rename to src/Greenshot.Base/FileDescriptorReader.cs index 93b94f834..90cc3f99a 100644 --- a/GreenshotPlugin/FileDescriptorReader.cs +++ b/src/Greenshot.Base/FileDescriptorReader.cs @@ -25,11 +25,10 @@ using System.IO; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Text; -using GreenshotPlugin.UnmanagedHelpers.Structs; +using Greenshot.Base.UnmanagedHelpers.Structs; -namespace GreenshotPlugin.Interop +namespace Greenshot.Base { - /// /// Specifies which fields are valid in a FileDescriptor Structure /// @@ -113,6 +112,7 @@ namespace GreenshotPlugin.Interop { yield break; } + var reader = new BinaryReader(fileDescriptorStream); var count = reader.ReadUInt32(); while (count > 0) @@ -128,7 +128,7 @@ namespace GreenshotPlugin.Interop internal static MemoryStream GetFileContents(System.Windows.Forms.IDataObject dataObject, int index) { //cast the default IDataObject to a com IDataObject - var comDataObject = (IDataObject)dataObject; + var comDataObject = (IDataObject) dataObject; var format = System.Windows.DataFormats.GetDataFormat("FileContents"); if (format == null) @@ -143,7 +143,7 @@ namespace GreenshotPlugin.Interop { var formatetc = new FORMATETC { - cfFormat = (short)format.Id, + cfFormat = (short) format.Id, dwAspect = DVASPECT.DVASPECT_CONTENT, lindex = index, tymed = TYMED.TYMED_ISTREAM | TYMED.TYMED_HGLOBAL @@ -152,7 +152,7 @@ namespace GreenshotPlugin.Interop //using the com IDataObject interface get the data using the defined FORMATETC comDataObject.GetData(ref formatetc, out medium); } - + return medium.tymed switch { TYMED.TYMED_ISTREAM => GetIStream(medium), @@ -163,13 +163,13 @@ namespace GreenshotPlugin.Interop private static MemoryStream GetIStream(STGMEDIUM medium) { //marshal the returned pointer to a IStream object - IStream iStream = (IStream)Marshal.GetObjectForIUnknown(medium.unionmember); + IStream iStream = (IStream) Marshal.GetObjectForIUnknown(medium.unionmember); Marshal.Release(medium.unionmember); //get the STATSTG of the IStream to determine how many bytes are in it var iStreamStat = new System.Runtime.InteropServices.ComTypes.STATSTG(); iStream.Stat(out iStreamStat, 0); - int iStreamSize = (int)iStreamStat.cbSize; + int iStreamSize = (int) iStreamStat.cbSize; //read the data from the IStream into a managed byte array byte[] iStreamContent = new byte[iStreamSize]; diff --git a/src/Greenshot.Base/GlobalSuppressions.cs b/src/Greenshot.Base/GlobalSuppressions.cs new file mode 100644 index 0000000000000000000000000000000000000000..148f8734d4145c7536cec4062f00e77f26868c14 GIT binary patch literal 119362 zcmeHQU2hx7mF?#M`455v3>?fv$z+2(1lR{rlw~8*m=Wcj-5CrFT9jnQq9~A*J<5;Y z-E-=y+|||9MNwUpx|j>Wro>`@u@Co_s5@S2X6z@(jw!DAcDTc*uaf6>Zj$7d8 z`2KZNT$(few)hS1g7-1PQA>Pof~(!)H-3HxuOH0_$9WFE@_bkLoZOpSnV*w8;k9PP zKQVfSqj!t)3WLhXAIx|CjL%)+tPAfxCpgEoxr1|@muEl6(L3gDc+3t)`HlHa=jOXC z@z>0J#@^{Aj^t;rF;d>e2!Ac`4S0VO^UTj`=NaJ`KKBJaGc%v%U-C_PJfHp)XW)58 z_{@3nof*F~pXKiyo#ILIuKD*ljy`jqMtMJ{=6j5AJzhiZt|~Km7WVq(leT!_`6;(c zJe_6n2V95JIV(QleR*yy^|^UGQe_?nMo8J09j< zm?P~IcJH;kix0fd!5#2tXyz(s)f7kdasQMA?{R^yRtGM{*XZVclv#_tH zI7c~m<+wwdtfNS028xUu^#XI~@mg5X0gN=*V`2WhxyE%^Gcm5G~yIcGY zzkR`H-(hTwPxINI;+(f;Uh;TiNH~dXFgM?o&+DZpEn<=PL3aGENOgzraW}7VcgIB! zPkIl}|EPG6tDF>X@&5r{Px0OX?&X`}_mJD~i(kxB>?YFW8SyC!4(52iAIuXbd*6BJ z`wOu5J<#W)ZfImqh8g3TQ2ISc=D%lbZ*nMpnU(rEt#kVWF>dnyKqlVvw{eNa`Li&)_(j{Yr-hT^A*v400 z;rJOmnjdi#V-_>`JTZ&F$HzP4_brS6DE7huv8~F=Qp(x_YRa-D6^;bN*;%t zefU@OddCKJ*FcJoFOG`GwhLtVqx8Rgl!%TA;iq}T#m~?1Yn#uh=;|iATnSnZIx?tY zT#XSzpM@;b*f>g?4ZBctgJ?|7LA6#MKzTzJ{l(^ZjY&`@^Mt2qY|xCa|$!ckcVMyjjYEs_^W0&!`A^ z8U$41>ZLugZ&;jpMzR3&6j!isBx7*}`||QWw$7+Kk#P=oDD6=n53baezti$}D5qj` zD=${&De4k`2WgkQK1JSS30|j%62`>KM_%Jw=!YM0=C=XQ!qo*aTOd3ZvO-UR&|mRQ zm_sY|Owaf>w1lb6p6hHfJ9yXhu~uc4!V>%Tt8`vrMlvh5$RJ;|eUYB9bU2?la&0ON z=J3>;=2F!jcCqTCvxoD|4Er(D6?a{vxtuASD{xaM_Lxk7F0=di8UXAAMU+?ehjsWebWz4bSQi)I1UJg_8t;)GXmilRp*N?|plzt0wbCBm zOO!SIG08W5&Y$OE8HA(1?wE2wmpQ<4y3~b>&(Vi17~=zu$Ize>Pb=|uQQ_6r{~_4^ zjj0zQ^Y@G=O53rX@jZb(DLDkL2JkaZWR5x37I5tYtL_;c5KZHvDdx#kBW9)Vk>Z%H z+vV4Gdel;BZ7Ju_e%A91RQD;=nGfE=AvR>>X=9kW_?y!Q+ zMzZWS*tu0LCOH{dBi3Z&_%=)m4WUe(mZ{U^ZmQULsE3mR55DD+;+%@Hv>1C@``TqD z+TA@^$+EIuvOk+(r4%^=@e8<8_Xc;(?Dx#9)aB}HTC4Tkfg1_*=YiPv55lqG zx@Xmykai|)f^A*Ab0rMpPbctvSgXECe@`%^QE2I6@YJgr){Qzyezf#~eQc!An?942 z2x%TshUq@T2zHpUu(79oqowM7AJU*GMP{^quZpy^NP8Nqj(wBZ)rpbQLs&u+SVyj< zw1>a>nLFgZFHF{r`p;*#n7vaSYmdF=T90aFQJ52B`5x7^>2>Y%q1Z;o-k?HFYT8~E z|J@1Xz6$sn)majvrv2OqXf}Z#OI9nx*g7M#ZG>GK1=Zr`H9{`>?=*7+O@m`N)?Y!)K7MFi9z0 zm0>P2luFxc(}S0`9BUa?_rO@q2khx<&*yer^KJfk#NE{*im6;M#TD_g8wJ->xk&JN zU*iK^j{t`BI->;ah$r@6InPzPx$P?vlCISV(g{!2u`uS}J~LE3qpKClEZiwsD8O5TcswQXgIGAWPA+{pdMBWaI{n zbcbGJ>@@rdc~W*dkm|Y^TGW#0q9wr{9GTZDGh5Urtg2ydYl*dhXOQzX>L%-2Cgxj+ zmI+nKxcVo)Hn3?_V#pW;yU;L-dr_;;dW?Q5 zajX%NZbnGn8J}nVH8ao7yKW!M>Ta|?%3L;54b?>r<;z!M8LougESzuG);lb_5)b=E z)Gs>Q^O)^|23g4=JD}(c&n;8u&v5Z29xBuD9F{d-%IJAAdTb7-=yp=qA*}M6;z#=A zDsFPX4ZRKSpX%BIn?_FPnu;CfmAKyp_cO}LZg7!fy~8+ys%ww!FKh)Q=ElVC-`V9*UtxwMh=zMC2^bya&8iCA(=X;Rh#LUtv*U!w#rJDx% zs`rqaCYOCLxn7g&fo~yke>WUu;e1$_6>SUT7MGCajc4Dh9CMJP#Bf&6%Bnr>#%5K{ zImo$g9S@8b$l7|Yp1_r;%zzvACERw(%%J2SwxZiP=Mh8oo}IcOP5 z^e14PG5XN1xoS7$8GkJ!#py!AQUS(V5J_lRJ)REOh1EXx7WI8mbzM&+b;Whbh+J(_jQ2i z2lX*?@iCk6(1r`bsL*PXe5y&P1!aF1R)4)R*_G*|y;0ZuP|Gj}%P=f|t|yh9z1nw* zYu=$t(UNBt!_8UK4&dIo@hD|`6osy-l@57SIvfBa>@e!eFijWA@R{wJShY@aUm0oT zyN?wI6VzE%Yg||DUe=yBetl2?4~)OMu3M_K>YisrOvPP5yEk6Gb9 z?*8bn&kSKtGhq2-z(lfrc-=8Qrn5AMS<1W>_oQT2{v2z=;xY|u2c5gQ&0SW`Pr%C` zz|M@djN!$8fd|W7OkWl{b90!v64$6plHF|2Ax)8`>e{>`4b0=Pk6n2QKSOYYX0#KR6zu{S{-3NwQ2FE~dX0e@e|GS~Xv-0FKN?@P#iVJwY# zB}Ws_4!aznS|P1gcn&+gz6$*mxR?STWP?>b?yA;=%LBfCc(~4KpL=7BY1Q{Cty%w0 zW8cD#iGI|&^gQa)Mbixsi?{>hv2)r8p4Pt6cGP-vtPPghs`l6$ASTUf&Qq=B#IsJz zkDKw6j)8`1u9s+_@3h4IuVV*QIW8@he3p`H>AKup*5wKZx%yJ-2w8=BW^mRXFHL7x zJ1qwu;@%85&``F+XN-ANqB%%Zy1jGH;hD`TFJnEBUH3zxh0Bek)tj&0B4q4TPz zk%uiQ$gm8a5*4;S+Me63lTMNKvFEk-tcc44akid@KFrd1wCthoT7tV~t>Y3tE;W%_ z4mns3)%wPL^qsFKOnBmAC&c!uOtUvf*>b#%2%MtTS^gDO4 zYu*`tqz8z-8#2OM+}S_zK0Q<0A@;}|vp{6&3h(+15oZCZEgaXl!^Kkf*&$Cvw6k4H ztVk4NT)YErMQd=ELQso=_NG5e7Sm1K0ADkZ%y@#^g{D3N4NISA9FDk9t&B^ zX)W8dXOnNlyZ+_@{pOmUrj<@v@1`@Z3mk0aV&@g*#~dPKgHzO|k*UY{$10?9PF3Uj zvH6f&&$m2THcdrZANAK_llQR#dI|h-wq9^}rP9c?t$V#hOkF|F6WDxtZ%d#R^Xvpk<>S=|%YXBn4EdSDc;{h^n_ z4$Q084T{XIztwGh;7-F3`x)ejXVTfxAKf@1T{$ADv)Yqt|u+CDfDGJ@IBCgAb`#VrIhc!gcg3Q5K zj$|Q5K-@S$e9&fHUM201h0;7VENY;JQ_qJP&|bNvzX zS-hGQeOKM{xm9GoS5wVI`=iPeIrGF2nZkvME;CE$BEr`PuHUO1k{gH6t7Y9Md%>xc ziRI7Gi=WI>>0*8FaU8-!78=L$COhVt{ z4wdDsCBH(hl9j}^4*d;yW@Pq@V2>DbPE4ElxN$8Cf9x?;x$gP2j_x^EEj*6ZO0@NX zu?1=q%BYEtt5_9nTkI%L<;GJIsXYd2#)hY=JCeq*qq5FT*4&wh>=2i+dNH|ps{_b# z&#c8`+_FBCxg!QECai^#a&H9H6tbT21)_(0SQDAk%E;9=MhIC=_N$LFUuU>{lG;{P z9n@tVR7KGNyqp_U4cuY%4_D@X0z0vqQ~E8$P@_`rvXmJcV*aempi$3o9S?J8OH>=3 zLEhI`;qYtC$Bp?SW%R>m4VO{k)kjUE8dKR^<$ap!BY&TAt`U@e9%G>Ci`QE~*<%47 z<=&Is>cOzu((vV6Ulr)a;(Z&Wz9!V=hA?k%?rV&z+cB;%DhALf%@f7uWb=@LsjhKmHZeQ_}6Mn?r`BJe8H;tgs zH5Ef$>G-w2?x{0^jcdk{RINO>$Lzuem;M!uYxH1?Gycl1HuHuxGU|us=7%;T=Ezv4 zmq5VBTAai6N>t0_q-8|jGT+Jc%%IhK!HRr!Hs>~*dywVCM4??f^b|7YzZ;#$h`Mc4 zTuC}OaxZAsV%-|6-y#(OFOG%SrfY|(wibGY6FYD^nm05|?S*w{PETBYt&7R9=W;=GoRT za2M@RU~cI~fPFWXX+YvsI;6%(>j#>Y}D%C0!OL{#u4GPK8d zdS|AhnVsq{U=7+xp{_74J7W#+pAkEiSe+Bsb0PH6hfYy-I7D9k1pAmB;fMRazQXUS z0rS#;b~UJrte)vn5XV(}=Bi(@4-Q~&1a{n!z0-X?S?x8f{#{P~oy37$sSm*P^__4e z0w|FjU;b6yx(mi(%wUSM?1Fok0cW;z3H&x8NX{+{Smj2=R=#U41WC({X1PO{Dbb`{ zloJ=#vz4)Z0K;6AV#h8;&1O)u>HSpw>Z^K=V}0Eg(|aY)_!_b8NP9cZ)yeX$71f(T z^=7&f3Kz;+aaWcx`(GuTpM*pE&%2zXGR;Y*%!{!vI@gArW3P<;75R>;ucLC$JKx1h z{|S0~e1QMUev)H&zhB__GFGbnA99Ppog-RNmniFe&LLHism|Z+=;6XV5j!<9?@^bz zj7~5fv%bPUfYv_cSNp_jDR#W(9))6iA7IBqiDAYNptjm(Y_;c%8My)`p?12t=ub9=jmqV>1HA!+y#hhk_f-}H@{kxG&6vgft;tjNm? zc~T3$Z+xDm@r1d;)wLMy%2ut|$gg6fT6gJ7S*^sJti*lThpeDwX`?8kcbm~Ahr`GZSKbSs9|0%K@f-jd^eXE6C)!B1MvS`Np-$v`jMbu)uk4p} z2RYl_^n7jIgAYlL___F{R%>LX9$q78M->y>h6#xd$E6-0RZMgp6Mf_?gd_T>!=D!K z5G@?v+Y6`2d9icU2l##?*b7(S5$c5-@WdQ!!P@;*xsCRb3c17g$ceqi-5q1U?jMRh Z*fK}Od)yCuvkaiIPB8ukuS3W3_ - - - GreenshotPlugin - GreenshotPlugin - true - - - - - PreserveNewest - - - - - - - - - - - - - - - + + + + true + + + + + + + + + + + + + + diff --git a/src/Greenshot.Base/Hooking/WindowsEventHook.cs b/src/Greenshot.Base/Hooking/WindowsEventHook.cs new file mode 100644 index 000000000..474b15fef --- /dev/null +++ b/src/Greenshot.Base/Hooking/WindowsEventHook.cs @@ -0,0 +1,151 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.Hooking +{ + /// + /// The WinEventHook can register handlers to become important windows events + /// This makes it possible to know a.o. when a window is created, moved, updated and closed. + /// + public class WindowsEventHook : IDisposable + { + private readonly WinEventDelegate _winEventHandler; + private GCHandle _gcHandle; + + /// + /// Used with Register hook + /// + /// + /// + /// + /// + /// + /// + public delegate void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); + + /// + /// Create a WindowsEventHook object + /// + public WindowsEventHook() + { + _winEventHandler = WinEventDelegateHandler; + _gcHandle = GCHandle.Alloc(_winEventHandler); + } + + [DllImport("user32", SetLastError = true)] + private static extern bool UnhookWinEvent(IntPtr hWinEventHook); + + [DllImport("user32", SetLastError = true)] + private static extern IntPtr SetWinEventHook(WinEvent eventMin, WinEvent eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, int idProcess, int idThread, + WinEventHookFlags dwFlags); + + /// + /// Used with SetWinEventHook + /// + /// + /// + /// + /// + /// + /// + /// + private delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); + + private readonly IDictionary _winEventHandlers = new Dictionary(); + + /// + /// Are hooks active? + /// + public bool IsHooked => _winEventHandlers.Count > 0; + + /// + /// Hook a WinEvent + /// + /// + /// + /// true if success + public void Hook(WinEvent winEvent, WinEventHandler winEventHandler) + { + Hook(winEvent, winEvent, winEventHandler); + } + + /// + /// Hook a WinEvent + /// + /// + /// + /// + public void Hook(WinEvent winEventStart, WinEvent winEventEnd, WinEventHandler winEventHandler) + { + var hookPtr = SetWinEventHook(winEventStart, winEventEnd, IntPtr.Zero, _winEventHandler, 0, 0, + WinEventHookFlags.WINEVENT_SKIPOWNPROCESS | WinEventHookFlags.WINEVENT_OUTOFCONTEXT); + _winEventHandlers.Add(hookPtr, winEventHandler); + } + + /// + /// Remove all hooks + /// + private void Unhook() + { + foreach (var hookPtr in _winEventHandlers.Keys) + { + if (hookPtr != IntPtr.Zero) + { + UnhookWinEvent(hookPtr); + } + } + + _winEventHandlers.Clear(); + _gcHandle.Free(); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Unhook(); + } + + /// + /// Call the WinEventHandler for this event + /// + /// + /// + /// + /// + /// + /// + /// + private void WinEventDelegateHandler(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) + { + if (_winEventHandlers.TryGetValue(hWinEventHook, out var handler)) + { + handler(eventType, hWnd, idObject, idChild, dwEventThread, dwmsEventTime); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs b/src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs new file mode 100644 index 000000000..2ab54e5de --- /dev/null +++ b/src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs @@ -0,0 +1,180 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using Greenshot.Base.Core; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.Hooking +{ + /// + /// Event arguments for the WindowOpenCloseEvent + /// + public class WindowOpenCloseEventArgs : EventArgs + { + public bool IsOpen { get; set; } + + /// + /// HWnd of the window which has a changed title + /// + public IntPtr HWnd { get; set; } + + /// + /// Title which is changed + /// + public string Title { get; set; } + + public string ClassName { get; set; } + } + + /// + /// Delegate for the window open close event + /// + /// + public delegate void WindowOpenCloseEventDelegate(WindowOpenCloseEventArgs eventArgs); + + /// + /// Monitor all new and destroyed windows + /// + public sealed class WindowsOpenCloseMonitor : IDisposable + { + private WindowsEventHook _hook; + private readonly object _lockObject = new object(); + + // ReSharper disable once InconsistentNaming + private event WindowOpenCloseEventDelegate _windowOpenCloseEvent; + + /// + /// Add / remove event handler to the title monitor + /// + public event WindowOpenCloseEventDelegate WindowOpenCloseChangeEvent + { + add + { + lock (_lockObject) + { + if (_hook == null) + { + _hook = new WindowsEventHook(); + _hook.Hook(WinEvent.EVENT_OBJECT_CREATE, WinEvent.EVENT_OBJECT_DESTROY, WinEventHandler); + } + + _windowOpenCloseEvent += value; + } + } + remove + { + lock (_lockObject) + { + _windowOpenCloseEvent -= value; + if (_windowOpenCloseEvent == null || _windowOpenCloseEvent.GetInvocationList().Length == 0) + { + if (_hook != null) + { + _hook.Dispose(); + _hook = null; + } + } + } + } + } + + /// + /// WinEventDelegate for the creation and destruction + /// + /// + /// + /// + /// + /// + /// + private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) + { + if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) + { + return; + } + + if (eventType == WinEvent.EVENT_OBJECT_CREATE) + { + if (_windowOpenCloseEvent != null) + { + var windowsDetails = new WindowDetails(hWnd); + _windowOpenCloseEvent(new WindowOpenCloseEventArgs + { + HWnd = hWnd, + IsOpen = true, + Title = windowsDetails.Text, + ClassName = windowsDetails.ClassName + }); + } + } + + if (eventType == WinEvent.EVENT_OBJECT_DESTROY) + { + _windowOpenCloseEvent?.Invoke(new WindowOpenCloseEventArgs + { + HWnd = hWnd, + IsOpen = false + }); + } + } + + private bool _disposedValue; // To detect redundant calls + + /// + /// Dispose the underlying hook + /// + public void Dispose(bool disposing) + { + if (_disposedValue) + { + return; + } + + lock (_lockObject) + { + _hook?.Dispose(); + } + + _disposedValue = true; + } + + /// + /// Make sure the finalizer disposes the underlying hook + /// + ~WindowsOpenCloseMonitor() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(false); + } + + /// + /// Dispose the underlying hook + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs b/src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs new file mode 100644 index 000000000..194ec4fc3 --- /dev/null +++ b/src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs @@ -0,0 +1,165 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using Greenshot.Base.Core; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.Hooking +{ + /// + /// Event arguments for the TitleChangeEvent + /// + public class TitleChangeEventArgs : EventArgs + { + /// + /// HWnd of the window which has a changed title + /// + public IntPtr HWnd { get; set; } + + /// + /// Title which is changed + /// + public string Title { get; set; } + } + + /// + /// Delegate for the title change event + /// + /// + public delegate void TitleChangeEventDelegate(TitleChangeEventArgs eventArgs); + + /// + /// Monitor all title changes + /// + public sealed class WindowsTitleMonitor : IDisposable + { + private WindowsEventHook _hook; + private readonly object _lockObject = new object(); + + // ReSharper disable once InconsistentNaming + private event TitleChangeEventDelegate _titleChangeEvent; + + /// + /// Add / remove event handler to the title monitor + /// + public event TitleChangeEventDelegate TitleChangeEvent + { + add + { + lock (_lockObject) + { + if (_hook == null) + { + _hook = new WindowsEventHook(); + _hook.Hook(WinEvent.EVENT_OBJECT_NAMECHANGE, WinEventHandler); + } + + _titleChangeEvent += value; + } + } + remove + { + lock (_lockObject) + { + _titleChangeEvent -= value; + if (_titleChangeEvent == null || _titleChangeEvent.GetInvocationList().Length == 0) + { + if (_hook != null) + { + _hook.Dispose(); + _hook = null; + } + } + } + } + } + + /// + /// WinEventDelegate for the creation & destruction + /// + /// + /// + /// + /// + /// + /// + private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) + { + if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) + { + return; + } + + if (eventType == WinEvent.EVENT_OBJECT_NAMECHANGE) + { + if (_titleChangeEvent != null) + { + string newTitle = new WindowDetails(hWnd).Text; + _titleChangeEvent(new TitleChangeEventArgs + { + HWnd = hWnd, + Title = newTitle + }); + } + } + } + + private bool _disposedValue; // To detect redundant calls + + /// + /// Dispose the underlying hook + /// + public void Dispose(bool disposing) + { + if (_disposedValue) + { + return; + } + + lock (_lockObject) + { + _hook?.Dispose(); + } + + _disposedValue = true; + } + + /// + /// Make sure the finalizer disposes the underlying hook + /// + ~WindowsTitleMonitor() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(false); + } + + /// + /// Dispose the underlying hook + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLWindow3.cs b/src/Greenshot.Base/IEInterop/IHTMLBodyElement.cs similarity index 71% rename from GreenshotPlugin/IEInterop/IHTMLWindow3.cs rename to src/Greenshot.Base/IEInterop/IHTMLBodyElement.cs index f3c872f5a..4b79bcc3e 100644 --- a/GreenshotPlugin/IEInterop/IHTMLWindow3.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLBodyElement.cs @@ -1,35 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComVisible(true), ComImport(), Guid("3050f4ae-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLWindow3 { - [DispId(1170)] - int screenLeft { get;} - - [DispId(1171)] - int screenTop { get;} - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F1D8-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLBodyElement + { + string scroll + { + set; + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs b/src/Greenshot.Base/IEInterop/IHTMLCurrentStyle.cs similarity index 52% rename from GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs rename to src/Greenshot.Base/IEInterop/IHTMLCurrentStyle.cs index cfbab4b3f..09ba37f79 100644 --- a/GreenshotPlugin/IEInterop/IHTMLCurrentStyle.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLCurrentStyle.cs @@ -1,67 +1,81 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050f3db-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLCurrentStyle { - /// styleFloat property of IHTMLStyle interface. - string styleFloat { - [DispId(-2147413042)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - string left { - [DispId(-2147418112 + 3)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - string top { - [DispId(-2147418112 + 4)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - string width { - [DispId(-2147418112 + 5)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - string height { - [DispId(-2147418112 + 6)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - string right { - [DispId(-2147418112 + 0x4d)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - string bottom { - [DispId(-2147418112 + 0x4e)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050f3db-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLCurrentStyle + { + /// styleFloat property of IHTMLStyle interface. + string styleFloat + { + [DispId(-2147413042)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string left + { + [DispId(-2147418112 + 3)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string top + { + [DispId(-2147418112 + 4)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string width + { + [DispId(-2147418112 + 5)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string height + { + [DispId(-2147418112 + 6)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string right + { + [DispId(-2147418112 + 0x4d)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string bottom + { + [DispId(-2147418112 + 0x4e)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument.cs b/src/Greenshot.Base/IEInterop/IHTMLDocument.cs similarity index 68% rename from GreenshotPlugin/IEInterop/IHTMLDocument.cs rename to src/Greenshot.Base/IEInterop/IHTMLDocument.cs index 5faeda803..affc1530e 100644 --- a/GreenshotPlugin/IEInterop/IHTMLDocument.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLDocument.cs @@ -1,36 +1,39 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - /// IHTMLDocument interface. - [Guid("626FC520-A41E-11CF-A731-00A0C9082637")] - [ComImport] - [TypeLibType(TypeLibTypeFlags.FDual)] - [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLDocument { - object Script { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + /// IHTMLDocument interface. + [Guid("626FC520-A41E-11CF-A731-00A0C9082637")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument + { + object Script + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/IEInterop/IHTMLDocument2.cs b/src/Greenshot.Base/IEInterop/IHTMLDocument2.cs new file mode 100644 index 000000000..635aea6dd --- /dev/null +++ b/src/Greenshot.Base/IEInterop/IHTMLDocument2.cs @@ -0,0 +1,85 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + /// IHTMLDocument2 interface. + [Guid("332C4425-26CB-11D0-B483-00C04FD90119")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument2 + { + IHTMLElement body + { + [DispId(1004)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string title + { + [DispId(1012)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + object frames + { + [DispId(1019)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string url + { + [DispId(1025)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + IHTMLWindow2 parentWindow + { + [DispId(1034)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + object bgColor { [DispId(-501)] get; } + + IHTMLSelectionObject selection + { + [DispId(1017)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string designMode + { + [DispId(1014)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + [DispId(1014)] set; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/IEInterop/IHTMLDocument3.cs b/src/Greenshot.Base/IEInterop/IHTMLDocument3.cs new file mode 100644 index 000000000..adcf26e0c --- /dev/null +++ b/src/Greenshot.Base/IEInterop/IHTMLDocument3.cs @@ -0,0 +1,50 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + /// IHTMLDocument3 interface. + [Guid("3050F485-98B5-11CF-BB82-00AA00BDCE0B")] + [ComImport] + [TypeLibType(TypeLibTypeFlags.FDual)] + [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLDocument3 + { + IHTMLElement documentElement + { + [DispId(1075)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(1086)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLElementCollection getElementsByName([MarshalAs(UnmanagedType.BStr)] string v); + + [DispId(1088)] + IHTMLElement getElementById([MarshalAs(UnmanagedType.BStr)] string v); + + [DispId(1087)] + IHTMLElementCollection getElementsByTagName([MarshalAs(UnmanagedType.BStr)] string v); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument4.cs b/src/Greenshot.Base/IEInterop/IHTMLDocument4.cs similarity index 92% rename from GreenshotPlugin/IEInterop/IHTMLDocument4.cs rename to src/Greenshot.Base/IEInterop/IHTMLDocument4.cs index 57e4a32ee..1b543991a 100644 --- a/GreenshotPlugin/IEInterop/IHTMLDocument4.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLDocument4.cs @@ -1,33 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComVisible(true), Guid("3050f69a-98b5-11cf-bb82-00aa00bdce0b"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDual)] - public interface IHTMLDocument4 { - [DispId(1090)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool hasFocus(); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComVisible(true), Guid("3050f69a-98b5-11cf-bb82-00aa00bdce0b"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDual)] + public interface IHTMLDocument4 + { + [DispId(1090)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool hasFocus(); + } } \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLDocument5.cs b/src/Greenshot.Base/IEInterop/IHTMLDocument5.cs similarity index 70% rename from GreenshotPlugin/IEInterop/IHTMLDocument5.cs rename to src/Greenshot.Base/IEInterop/IHTMLDocument5.cs index 60b5aab8c..020249783 100644 --- a/GreenshotPlugin/IEInterop/IHTMLDocument5.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLDocument5.cs @@ -1,34 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport, ComVisible(true), Guid("3050f80c-98b5-11cf-bb82-00aa00bdce0b"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDual)] - public interface IHTMLDocument5 { - [DispId(1102)] - string compatMode { - [return: MarshalAs(UnmanagedType.BStr)] get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, ComVisible(true), Guid("3050f80c-98b5-11cf-bb82-00aa00bdce0b"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDual)] + public interface IHTMLDocument5 + { + [DispId(1102)] + string compatMode + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/IEInterop/IHTMLElement.cs b/src/Greenshot.Base/IEInterop/IHTMLElement.cs new file mode 100644 index 000000000..9e37d98c6 --- /dev/null +++ b/src/Greenshot.Base/IEInterop/IHTMLElement.cs @@ -0,0 +1,113 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F1FF-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLElement + { + [DispId(-2147417611)] + void setAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, object AttributeValue, int lFlags); + + [DispId(-2147417610)] + object getAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); + + long offsetLeft { [DispId(-2147417104)] get; } + + long offsetTop { [DispId(-2147417103)] get; } + + long offsetWidth { [DispId(-2147417102)] get; } + + long offsetHeight { [DispId(-2147417101)] get; } + + IHTMLElement offsetParent { [DispId(-2147417100)] get; } + + string className + { + [DispId(-2147417111)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + IHTMLDocument2 document + { + [DispId(-2147417094)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string id + { + [DispId(-2147417110)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string innerHTML + { + [DispId(-2147417086)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string innerText + { + [DispId(-2147417085)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + IHTMLStyle style + { + [DispId(-2147418038)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + string tagName + { + [DispId(-2147417108)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string title + { + [DispId(-2147418043)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + [DispId(-2147417093)] + void scrollIntoView(bool varargStart); + + IHTMLElementCollection children + { + [DispId(-2147417075)] + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLRect.cs b/src/Greenshot.Base/IEInterop/IHTMLElement2.cs similarity index 64% rename from GreenshotPlugin/IEInterop/IHTMLRect.cs rename to src/Greenshot.Base/IEInterop/IHTMLElement2.cs index c2d6d375a..d6b5e794f 100644 --- a/GreenshotPlugin/IEInterop/IHTMLRect.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLElement2.cs @@ -1,49 +1,42 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F4A3-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLRect { - int bottom { - [DispId(1004)] - get; - } - - int left { - [DispId(1001)] - get; - } - - int right { - [DispId(1003)] - get; - } - - int top { - [DispId(1002)] - get; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F434-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLElement2 + { + [DispId(-2147417067)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLRect getBoundingClientRect(); + + IHTMLCurrentStyle currentStyle + { + [DispId(-2147417105)] + [return: MarshalAs(UnmanagedType.Interface)] //IHTMLCurrentStyle + get; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs b/src/Greenshot.Base/IEInterop/IHTMLElementCollection.cs similarity index 73% rename from GreenshotPlugin/IEInterop/IHTMLElementCollection.cs rename to src/Greenshot.Base/IEInterop/IHTMLElementCollection.cs index d9a7211dc..f0735cc6d 100644 --- a/GreenshotPlugin/IEInterop/IHTMLElementCollection.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLElementCollection.cs @@ -1,33 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Collections; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport(), ComVisible(true), - Guid("3050F21F-98B5-11CF-BB82-00AA00BDCE0B"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDispatchable)] - public interface IHTMLElementCollection : IEnumerable { - new IEnumerator GetEnumerator(); - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport(), ComVisible(true), + Guid("3050F21F-98B5-11CF-BB82-00AA00BDCE0B"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDispatchable)] + public interface IHTMLElementCollection : IEnumerable + { + new IEnumerator GetEnumerator(); + } } \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs b/src/Greenshot.Base/IEInterop/IHTMLFrameBase.cs similarity index 70% rename from GreenshotPlugin/IEInterop/IHTMLFrameBase.cs rename to src/Greenshot.Base/IEInterop/IHTMLFrameBase.cs index d9566c0cc..c35da0240 100644 --- a/GreenshotPlugin/IEInterop/IHTMLFrameBase.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLFrameBase.cs @@ -1,104 +1,108 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComVisible(true), ComImport(), Guid("3050f311-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLFrameBase { -//dispinterface IHTMLFrameBase { -// properties: -// methods: -// [id(0x80010bb8), propput] -// void src([in] BSTR rhs); -// [id(0x80010bb8), propget] -// BSTR src(); -// [id(0x80010000), propput] -// void name([in] BSTR rhs); -// [id(0x80010000), propget] -// BSTR name(); -// [id(0x80010bba), propput] -// void border([in] VARIANT rhs); -// [id(0x80010bba), propget] -// VARIANT border(); -// [id(0x80010bbb), propput] -// void frameBorder([in] BSTR rhs); -// [id(0x80010bbb), propget] -// BSTR frameBorder(); -// [id(0x80010bbc), propput] -// void frameSpacing([in] VARIANT rhs); -// [id(0x80010bbc), propget] -// VARIANT frameSpacing(); -// [id(0x80010bbd), propput] -// void marginWidth([in] VARIANT rhs); -// [id(0x80010bbd), propget] -// VARIANT marginWidth(); -// [id(0x80010bbe), propput] -// void marginHeight([in] VARIANT rhs); -// [id(0x80010bbe), propget] -// VARIANT marginHeight(); -// [id(0x80010bbf), propput] -// void noResize([in] VARIANT_BOOL rhs); -// [id(0x80010bbf), propget] -// VARIANT_BOOL noResize(); -// [id(0x80010bc0), propput] -// void scrolling([in] BSTR rhs); -// [id(0x80010bc0), propget] -// BSTR scrolling(); -//}; -// [DispId(HTMLDispIDs.DISPID_IHTMLFRAMEBASE_SRC)] - string src { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - string name { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - object border { - get; - } - string frameBorder { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - object frameSpacing { - get; - } - object marginWidth { - get; - } - object marginHeight { - get; - } - bool noResize { - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - string scrolling { - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - } - -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComVisible(true), ComImport(), Guid("3050f311-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLFrameBase + { +//dispinterface IHTMLFrameBase { +// properties: +// methods: +// [id(0x80010bb8), propput] +// void src([in] BSTR rhs); +// [id(0x80010bb8), propget] +// BSTR src(); +// [id(0x80010000), propput] +// void name([in] BSTR rhs); +// [id(0x80010000), propget] +// BSTR name(); +// [id(0x80010bba), propput] +// void border([in] VARIANT rhs); +// [id(0x80010bba), propget] +// VARIANT border(); +// [id(0x80010bbb), propput] +// void frameBorder([in] BSTR rhs); +// [id(0x80010bbb), propget] +// BSTR frameBorder(); +// [id(0x80010bbc), propput] +// void frameSpacing([in] VARIANT rhs); +// [id(0x80010bbc), propget] +// VARIANT frameSpacing(); +// [id(0x80010bbd), propput] +// void marginWidth([in] VARIANT rhs); +// [id(0x80010bbd), propget] +// VARIANT marginWidth(); +// [id(0x80010bbe), propput] +// void marginHeight([in] VARIANT rhs); +// [id(0x80010bbe), propget] +// VARIANT marginHeight(); +// [id(0x80010bbf), propput] +// void noResize([in] VARIANT_BOOL rhs); +// [id(0x80010bbf), propget] +// VARIANT_BOOL noResize(); +// [id(0x80010bc0), propput] +// void scrolling([in] BSTR rhs); +// [id(0x80010bc0), propget] +// BSTR scrolling(); +//}; +// [DispId(HTMLDispIDs.DISPID_IHTMLFRAMEBASE_SRC)] + string src + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string name + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + object border { get; } + + string frameBorder + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + object frameSpacing { get; } + object marginWidth { get; } + object marginHeight { get; } + + bool noResize + { + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + string scrolling + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs b/src/Greenshot.Base/IEInterop/IHTMLFramesCollection2.cs similarity index 68% rename from GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs rename to src/Greenshot.Base/IEInterop/IHTMLFramesCollection2.cs index 2c651db26..3a68b485d 100644 --- a/GreenshotPlugin/IEInterop/IHTMLFramesCollection2.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLFramesCollection2.cs @@ -1,39 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport(), ComVisible(true), - Guid("332C4426-26CB-11D0-B483-00C04FD90119"), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FDispatchable)] - public interface IHTMLFramesCollection2 { - [DispId(0)] - [return: MarshalAs(UnmanagedType.IDispatch)] - IHTMLWindow2 item(int pvarIndex); - - long length { - [DispId(1001)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport(), ComVisible(true), + Guid("332C4426-26CB-11D0-B483-00C04FD90119"), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FDispatchable)] + public interface IHTMLFramesCollection2 + { + [DispId(0)] + [return: MarshalAs(UnmanagedType.IDispatch)] + IHTMLWindow2 item(int pvarIndex); + + long length { [DispId(1001)] get; } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/IEInterop/IHTMLRect.cs b/src/Greenshot.Base/IEInterop/IHTMLRect.cs new file mode 100644 index 000000000..01a3e886d --- /dev/null +++ b/src/Greenshot.Base/IEInterop/IHTMLRect.cs @@ -0,0 +1,39 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F4A3-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLRect + { + int bottom { [DispId(1004)] get; } + + int left { [DispId(1001)] get; } + + int right { [DispId(1003)] get; } + + int top { [DispId(1002)] get; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs b/src/Greenshot.Base/IEInterop/IHTMLScreen.cs similarity index 73% rename from GreenshotPlugin/IEInterop/IHTMLBodyElement.cs rename to src/Greenshot.Base/IEInterop/IHTMLScreen.cs index 0890cc628..2eab0d041 100644 --- a/GreenshotPlugin/IEInterop/IHTMLBodyElement.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLScreen.cs @@ -1,35 +1,34 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F1D8-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLBodyElement { - string scroll { - set; - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F35C-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLScreen + { + [DispId(1003)] int width { get; } + [DispId(1004)] int height { get; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/IEInterop/IHTMLScreen2.cs b/src/Greenshot.Base/IEInterop/IHTMLScreen2.cs new file mode 100644 index 000000000..3e7d379cc --- /dev/null +++ b/src/Greenshot.Base/IEInterop/IHTMLScreen2.cs @@ -0,0 +1,39 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F84A-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLScreen2 + { + int logicalXDPI { [DispId(1009)] get; } + + int logicalYDPI { [DispId(1010)] get; } + + int deviceXDPI { [DispId(1011)] get; } + + int deviceYDPI { [DispId(1012)] get; } + }; +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLWindow2.cs b/src/Greenshot.Base/IEInterop/IHTMLSelectionObject.cs similarity index 59% rename from GreenshotPlugin/IEInterop/IHTMLWindow2.cs rename to src/Greenshot.Base/IEInterop/IHTMLSelectionObject.cs index 02b2a756c..2fa199ab5 100644 --- a/GreenshotPlugin/IEInterop/IHTMLWindow2.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLSelectionObject.cs @@ -1,46 +1,49 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComVisible(true), ComImport(), Guid("332c4427-26cb-11d0-b483-00c04fd90119"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLWindow2 { - [DispId(1156)] - IHTMLScreen screen { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(1151)] - IHTMLDocument2 document { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - - [DispId(11)] - string name { - [return: MarshalAs(UnmanagedType.BStr)] get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + // See: http://msdn.microsoft.com/en-us/library/aa768849%28v=vs.85%29.aspx + [ComImport, Guid("3050f25A-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLSelectionObject + { + [return: MarshalAs(UnmanagedType.IDispatch)] + [DispId(1001)] + IHTMLTxtRange createRange(); + + [DispId(1002)] + void empty(); + + [DispId(1003)] + void clear(); + + [DispId(1004)] + string EventType + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLStyle.cs b/src/Greenshot.Base/IEInterop/IHTMLStyle.cs similarity index 84% rename from GreenshotPlugin/IEInterop/IHTMLStyle.cs rename to src/Greenshot.Base/IEInterop/IHTMLStyle.cs index 43d10fa84..3be39344a 100644 --- a/GreenshotPlugin/IEInterop/IHTMLStyle.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLStyle.cs @@ -1,1188 +1,1103 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F25E-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLStyle { - /// setAttribute method of IHTMLStyle interface. - /// An original IDL definition of setAttribute method was the following: HRESULT setAttribute (BSTR strAttributeName, VARIANT AttributeValue, [optional, defaultvalue(1)] long lFlags); - // IDL: HRESULT setAttribute (BSTR strAttributeName, VARIANT AttributeValue, [optional, defaultvalue(1)] long lFlags); - // VB6: Sub setAttribute (ByVal strAttributeName As String, ByVal AttributeValue As Any, [ByVal lFlags As Long = 1]) - [DispId(-2147417611)] - void setAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, object AttributeValue, int lFlags); - - /// getAttribute method of IHTMLStyle interface. - /// An original IDL definition of getAttribute method was the following: HRESULT getAttribute (BSTR strAttributeName, [optional, defaultvalue(0)] long lFlags, [out, retval] VARIANT* ReturnValue); - // IDL: HRESULT getAttribute (BSTR strAttributeName, [optional, defaultvalue(0)] long lFlags, [out, retval] VARIANT* ReturnValue); - // VB6: Function getAttribute (ByVal strAttributeName As String, [ByVal lFlags As Long = 0]) As Any - [DispId(-2147417610)] - object getAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); - - /// removeAttribute method of IHTMLStyle interface. - /// An original IDL definition of removeAttribute method was the following: HRESULT removeAttribute (BSTR strAttributeName, [optional, defaultvalue(1)] long lFlags, [out, retval] VARIANT_BOOL* ReturnValue); - // IDL: HRESULT removeAttribute (BSTR strAttributeName, [optional, defaultvalue(1)] long lFlags, [out, retval] VARIANT_BOOL* ReturnValue); - // VB6: Function removeAttribute (ByVal strAttributeName As String, [ByVal lFlags As Long = 1]) As Boolean - [DispId(-2147417609)] - [return: MarshalAs(UnmanagedType.VariantBool)] - bool removeAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); - - /// toString method of IHTMLStyle interface. - /// An original IDL definition of toString method was the following: HRESULT toString ([out, retval] BSTR* ReturnValue); - // IDL: HRESULT toString ([out, retval] BSTR* ReturnValue); - // VB6: Function toString As String - [DispId(-2147414104)] - [return: MarshalAs(UnmanagedType.BStr)] - string toString(); - - /// background property of IHTMLStyle interface. - /// An original IDL definition of background property was the following: BSTR background; - // IDL: BSTR background; - // VB6: background As String - string background { - // IDL: HRESULT background ([out, retval] BSTR* ReturnValue); - // VB6: Function background As String - [DispId(-2147413080)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT background (BSTR value); - // VB6: Sub background (ByVal value As String) - [DispId(-2147413080)] - set; - } - - /// backgroundAttachment property of IHTMLStyle interface. - /// An original IDL definition of backgroundAttachment property was the following: BSTR backgroundAttachment; - // IDL: BSTR backgroundAttachment; - // VB6: backgroundAttachment As String - string backgroundAttachment { - // IDL: HRESULT backgroundAttachment ([out, retval] BSTR* ReturnValue); - // VB6: Function backgroundAttachment As String - [DispId(-2147413067)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT backgroundAttachment (BSTR value); - // VB6: Sub backgroundAttachment (ByVal value As String) - [DispId(-2147413067)] - set; - } - - /// backgroundColor property of IHTMLStyle interface. - /// An original IDL definition of backgroundColor property was the following: VARIANT backgroundColor; - // IDL: VARIANT backgroundColor; - // VB6: backgroundColor As Any - object backgroundColor { - // IDL: HRESULT backgroundColor ([out, retval] VARIANT* ReturnValue); - // VB6: Function backgroundColor As Any - [DispId(-501)] - get; - // IDL: HRESULT backgroundColor (VARIANT value); - // VB6: Sub backgroundColor (ByVal value As Any) - [DispId(-501)] - set; - } - - /// backgroundImage property of IHTMLStyle interface. - /// An original IDL definition of backgroundImage property was the following: BSTR backgroundImage; - // IDL: BSTR backgroundImage; - // VB6: backgroundImage As String - string backgroundImage { - // IDL: HRESULT backgroundImage ([out, retval] BSTR* ReturnValue); - // VB6: Function backgroundImage As String - [DispId(-2147413111)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT backgroundImage (BSTR value); - // VB6: Sub backgroundImage (ByVal value As String) - [DispId(-2147413111)] - set; - } - - /// backgroundPosition property of IHTMLStyle interface. - /// An original IDL definition of backgroundPosition property was the following: BSTR backgroundPosition; - // IDL: BSTR backgroundPosition; - // VB6: backgroundPosition As String - string backgroundPosition { - // IDL: HRESULT backgroundPosition ([out, retval] BSTR* ReturnValue); - // VB6: Function backgroundPosition As String - [DispId(-2147413066)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT backgroundPosition (BSTR value); - // VB6: Sub backgroundPosition (ByVal value As String) - [DispId(-2147413066)] - set; - } - - /// backgroundPositionX property of IHTMLStyle interface. - /// An original IDL definition of backgroundPositionX property was the following: VARIANT backgroundPositionX; - // IDL: VARIANT backgroundPositionX; - // VB6: backgroundPositionX As Any - object backgroundPositionX { - // IDL: HRESULT backgroundPositionX ([out, retval] VARIANT* ReturnValue); - // VB6: Function backgroundPositionX As Any - [DispId(-2147413079)] - get; - // IDL: HRESULT backgroundPositionX (VARIANT value); - // VB6: Sub backgroundPositionX (ByVal value As Any) - [DispId(-2147413079)] - set; - } - - /// backgroundPositionY property of IHTMLStyle interface. - /// An original IDL definition of backgroundPositionY property was the following: VARIANT backgroundPositionY; - // IDL: VARIANT backgroundPositionY; - // VB6: backgroundPositionY As Any - object backgroundPositionY { - // IDL: HRESULT backgroundPositionY ([out, retval] VARIANT* ReturnValue); - // VB6: Function backgroundPositionY As Any - [DispId(-2147413078)] - get; - // IDL: HRESULT backgroundPositionY (VARIANT value); - // VB6: Sub backgroundPositionY (ByVal value As Any) - [DispId(-2147413078)] - set; - } - - /// backgroundRepeat property of IHTMLStyle interface. - /// An original IDL definition of backgroundRepeat property was the following: BSTR backgroundRepeat; - // IDL: BSTR backgroundRepeat; - // VB6: backgroundRepeat As String - string backgroundRepeat { - // IDL: HRESULT backgroundRepeat ([out, retval] BSTR* ReturnValue); - // VB6: Function backgroundRepeat As String - [DispId(-2147413068)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT backgroundRepeat (BSTR value); - // VB6: Sub backgroundRepeat (ByVal value As String) - [DispId(-2147413068)] - set; - } - - /// border property of IHTMLStyle interface. - /// An original IDL definition of border property was the following: BSTR border; - // IDL: BSTR border; - // VB6: border As String - string border { - // IDL: HRESULT border ([out, retval] BSTR* ReturnValue); - // VB6: Function border As String - [DispId(-2147413063)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT border (BSTR value); - // VB6: Sub border (ByVal value As String) - [DispId(-2147413063)] - set; - } - - /// borderBottom property of IHTMLStyle interface. - /// An original IDL definition of borderBottom property was the following: BSTR borderBottom; - // IDL: BSTR borderBottom; - // VB6: borderBottom As String - string borderBottom { - // IDL: HRESULT borderBottom ([out, retval] BSTR* ReturnValue); - // VB6: Function borderBottom As String - [DispId(-2147413060)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderBottom (BSTR value); - // VB6: Sub borderBottom (ByVal value As String) - [DispId(-2147413060)] - set; - } - - /// borderBottomColor property of IHTMLStyle interface. - /// An original IDL definition of borderBottomColor property was the following: VARIANT borderBottomColor; - // IDL: VARIANT borderBottomColor; - // VB6: borderBottomColor As Any - object borderBottomColor { - // IDL: HRESULT borderBottomColor ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderBottomColor As Any - [DispId(-2147413055)] - get; - // IDL: HRESULT borderBottomColor (VARIANT value); - // VB6: Sub borderBottomColor (ByVal value As Any) - [DispId(-2147413055)] - set; - } - - /// borderBottomStyle property of IHTMLStyle interface. - /// An original IDL definition of borderBottomStyle property was the following: BSTR borderBottomStyle; - // IDL: BSTR borderBottomStyle; - // VB6: borderBottomStyle As String - string borderBottomStyle { - // IDL: HRESULT borderBottomStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function borderBottomStyle As String - [DispId(-2147413045)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderBottomStyle (BSTR value); - // VB6: Sub borderBottomStyle (ByVal value As String) - [DispId(-2147413045)] - set; - } - - /// borderBottomWidth property of IHTMLStyle interface. - /// An original IDL definition of borderBottomWidth property was the following: VARIANT borderBottomWidth; - // IDL: VARIANT borderBottomWidth; - // VB6: borderBottomWidth As Any - object borderBottomWidth { - // IDL: HRESULT borderBottomWidth ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderBottomWidth As Any - [DispId(-2147413050)] - get; - // IDL: HRESULT borderBottomWidth (VARIANT value); - // VB6: Sub borderBottomWidth (ByVal value As Any) - [DispId(-2147413050)] - set; - } - - /// borderColor property of IHTMLStyle interface. - /// An original IDL definition of borderColor property was the following: BSTR borderColor; - // IDL: BSTR borderColor; - // VB6: borderColor As String - string borderColor { - // IDL: HRESULT borderColor ([out, retval] BSTR* ReturnValue); - // VB6: Function borderColor As String - [DispId(-2147413058)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderColor (BSTR value); - // VB6: Sub borderColor (ByVal value As String) - [DispId(-2147413058)] - set; - } - - /// borderLeft property of IHTMLStyle interface. - /// An original IDL definition of borderLeft property was the following: BSTR borderLeft; - // IDL: BSTR borderLeft; - // VB6: borderLeft As String - string borderLeft { - // IDL: HRESULT borderLeft ([out, retval] BSTR* ReturnValue); - // VB6: Function borderLeft As String - [DispId(-2147413059)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderLeft (BSTR value); - // VB6: Sub borderLeft (ByVal value As String) - [DispId(-2147413059)] - set; - } - - /// borderLeftColor property of IHTMLStyle interface. - /// An original IDL definition of borderLeftColor property was the following: VARIANT borderLeftColor; - // IDL: VARIANT borderLeftColor; - // VB6: borderLeftColor As Any - object borderLeftColor { - // IDL: HRESULT borderLeftColor ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderLeftColor As Any - [DispId(-2147413054)] - get; - // IDL: HRESULT borderLeftColor (VARIANT value); - // VB6: Sub borderLeftColor (ByVal value As Any) - [DispId(-2147413054)] - set; - } - - /// borderLeftStyle property of IHTMLStyle interface. - /// An original IDL definition of borderLeftStyle property was the following: BSTR borderLeftStyle; - // IDL: BSTR borderLeftStyle; - // VB6: borderLeftStyle As String - string borderLeftStyle { - // IDL: HRESULT borderLeftStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function borderLeftStyle As String - [DispId(-2147413044)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderLeftStyle (BSTR value); - // VB6: Sub borderLeftStyle (ByVal value As String) - [DispId(-2147413044)] - set; - } - - /// borderLeftWidth property of IHTMLStyle interface. - /// An original IDL definition of borderLeftWidth property was the following: VARIANT borderLeftWidth; - // IDL: VARIANT borderLeftWidth; - // VB6: borderLeftWidth As Any - object borderLeftWidth { - // IDL: HRESULT borderLeftWidth ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderLeftWidth As Any - [DispId(-2147413049)] - get; - // IDL: HRESULT borderLeftWidth (VARIANT value); - // VB6: Sub borderLeftWidth (ByVal value As Any) - [DispId(-2147413049)] - set; - } - - /// borderRight property of IHTMLStyle interface. - /// An original IDL definition of borderRight property was the following: BSTR borderRight; - // IDL: BSTR borderRight; - // VB6: borderRight As String - string borderRight { - // IDL: HRESULT borderRight ([out, retval] BSTR* ReturnValue); - // VB6: Function borderRight As String - [DispId(-2147413061)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderRight (BSTR value); - // VB6: Sub borderRight (ByVal value As String) - [DispId(-2147413061)] - set; - } - - /// borderRightColor property of IHTMLStyle interface. - /// An original IDL definition of borderRightColor property was the following: VARIANT borderRightColor; - // IDL: VARIANT borderRightColor; - // VB6: borderRightColor As Any - object borderRightColor { - // IDL: HRESULT borderRightColor ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderRightColor As Any - [DispId(-2147413056)] - get; - // IDL: HRESULT borderRightColor (VARIANT value); - // VB6: Sub borderRightColor (ByVal value As Any) - [DispId(-2147413056)] - set; - } - - /// borderRightStyle property of IHTMLStyle interface. - /// An original IDL definition of borderRightStyle property was the following: BSTR borderRightStyle; - // IDL: BSTR borderRightStyle; - // VB6: borderRightStyle As String - string borderRightStyle { - // IDL: HRESULT borderRightStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function borderRightStyle As String - [DispId(-2147413046)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderRightStyle (BSTR value); - // VB6: Sub borderRightStyle (ByVal value As String) - [DispId(-2147413046)] - set; - } - - /// borderRightWidth property of IHTMLStyle interface. - /// An original IDL definition of borderRightWidth property was the following: VARIANT borderRightWidth; - // IDL: VARIANT borderRightWidth; - // VB6: borderRightWidth As Any - object borderRightWidth { - // IDL: HRESULT borderRightWidth ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderRightWidth As Any - [DispId(-2147413051)] - get; - // IDL: HRESULT borderRightWidth (VARIANT value); - // VB6: Sub borderRightWidth (ByVal value As Any) - [DispId(-2147413051)] - set; - } - - /// borderStyle property of IHTMLStyle interface. - /// An original IDL definition of borderStyle property was the following: BSTR borderStyle; - // IDL: BSTR borderStyle; - // VB6: borderStyle As String - string borderStyle { - // IDL: HRESULT borderStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function borderStyle As String - [DispId(-2147413048)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderStyle (BSTR value); - // VB6: Sub borderStyle (ByVal value As String) - [DispId(-2147413048)] - set; - } - - /// borderTop property of IHTMLStyle interface. - /// An original IDL definition of borderTop property was the following: BSTR borderTop; - // IDL: BSTR borderTop; - // VB6: borderTop As String - string borderTop { - // IDL: HRESULT borderTop ([out, retval] BSTR* ReturnValue); - // VB6: Function borderTop As String - [DispId(-2147413062)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderTop (BSTR value); - // VB6: Sub borderTop (ByVal value As String) - [DispId(-2147413062)] - set; - } - - /// borderTopColor property of IHTMLStyle interface. - /// An original IDL definition of borderTopColor property was the following: VARIANT borderTopColor; - // IDL: VARIANT borderTopColor; - // VB6: borderTopColor As Any - object borderTopColor { - // IDL: HRESULT borderTopColor ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderTopColor As Any - [DispId(-2147413057)] - get; - // IDL: HRESULT borderTopColor (VARIANT value); - // VB6: Sub borderTopColor (ByVal value As Any) - [DispId(-2147413057)] - set; - } - - /// borderTopStyle property of IHTMLStyle interface. - /// An original IDL definition of borderTopStyle property was the following: BSTR borderTopStyle; - // IDL: BSTR borderTopStyle; - // VB6: borderTopStyle As String - string borderTopStyle { - // IDL: HRESULT borderTopStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function borderTopStyle As String - [DispId(-2147413047)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderTopStyle (BSTR value); - // VB6: Sub borderTopStyle (ByVal value As String) - [DispId(-2147413047)] - set; - } - - /// borderTopWidth property of IHTMLStyle interface. - /// An original IDL definition of borderTopWidth property was the following: VARIANT borderTopWidth; - // IDL: VARIANT borderTopWidth; - // VB6: borderTopWidth As Any - object borderTopWidth { - // IDL: HRESULT borderTopWidth ([out, retval] VARIANT* ReturnValue); - // VB6: Function borderTopWidth As Any - [DispId(-2147413052)] - get; - // IDL: HRESULT borderTopWidth (VARIANT value); - // VB6: Sub borderTopWidth (ByVal value As Any) - [DispId(-2147413052)] - set; - } - - /// borderWidth property of IHTMLStyle interface. - /// An original IDL definition of borderWidth property was the following: BSTR borderWidth; - // IDL: BSTR borderWidth; - // VB6: borderWidth As String - string borderWidth { - // IDL: HRESULT borderWidth ([out, retval] BSTR* ReturnValue); - // VB6: Function borderWidth As String - [DispId(-2147413053)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT borderWidth (BSTR value); - // VB6: Sub borderWidth (ByVal value As String) - [DispId(-2147413053)] - set; - } - - /// clear property of IHTMLStyle interface. - /// An original IDL definition of clear property was the following: BSTR clear; - // IDL: BSTR clear; - // VB6: clear As String - string clear - { - // IDL: HRESULT clear ([out, retval] BSTR* ReturnValue); - // VB6: Function clear As String - [DispId(-2147413096)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT clear (BSTR value); - // VB6: Sub clear (ByVal value As String) - [DispId(-2147413096)] - set; - } - - /// clip property of IHTMLStyle interface. - /// An original IDL definition of clip property was the following: BSTR clip; - // IDL: BSTR clip; - // VB6: clip As String - string clip - { - // IDL: HRESULT clip ([out, retval] BSTR* ReturnValue); - // VB6: Function clip As String - [DispId(-2147413020)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT clip (BSTR value); - // VB6: Sub clip (ByVal value As String) - [DispId(-2147413020)] - set; - } - - /// color property of IHTMLStyle interface. - /// An original IDL definition of color property was the following: VARIANT color; - // IDL: VARIANT color; - // VB6: color As Any - object color - { - // IDL: HRESULT color ([out, retval] VARIANT* ReturnValue); - // VB6: Function color As Any - [DispId(-2147413110)] - get; - // IDL: HRESULT color (VARIANT value); - // VB6: Sub color (ByVal value As Any) - [DispId(-2147413110)] - set; - } - - /// cssText property of IHTMLStyle interface. - /// An original IDL definition of cssText property was the following: BSTR cssText; - // IDL: BSTR cssText; - // VB6: cssText As String - string cssText - { - // IDL: HRESULT cssText ([out, retval] BSTR* ReturnValue); - // VB6: Function cssText As String - [DispId(-2147413013)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT cssText (BSTR value); - // VB6: Sub cssText (ByVal value As String) - [DispId(-2147413013)] - set; - } - - /// cursor property of IHTMLStyle interface. - /// An original IDL definition of cursor property was the following: BSTR cursor; - // IDL: BSTR cursor; - // VB6: cursor As String - string cursor - { - // IDL: HRESULT cursor ([out, retval] BSTR* ReturnValue); - // VB6: Function cursor As String - [DispId(-2147413010)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT cursor (BSTR value); - // VB6: Sub cursor (ByVal value As String) - [DispId(-2147413010)] - set; - } - - /// display property of IHTMLStyle interface. - /// An original IDL definition of display property was the following: BSTR display; - // IDL: BSTR display; - // VB6: display As String - string display - { - // IDL: HRESULT display ([out, retval] BSTR* ReturnValue); - // VB6: Function display As String - [DispId(-2147413041)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT display (BSTR value); - // VB6: Sub display (ByVal value As String) - [DispId(-2147413041)] - set; - } - - /// filter property of IHTMLStyle interface. - /// An original IDL definition of filter property was the following: BSTR filter; - // IDL: BSTR filter; - // VB6: filter As String - string filter - { - // IDL: HRESULT filter ([out, retval] BSTR* ReturnValue); - // VB6: Function filter As String - [DispId(-2147413030)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT filter (BSTR value); - // VB6: Sub filter (ByVal value As String) - [DispId(-2147413030)] - set; - } - - /// font property of IHTMLStyle interface. - /// An original IDL definition of font property was the following: BSTR font; - // IDL: BSTR font; - // VB6: font As String - string font - { - // IDL: HRESULT font ([out, retval] BSTR* ReturnValue); - // VB6: Function font As String - [DispId(-2147413071)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT font (BSTR value); - // VB6: Sub font (ByVal value As String) - [DispId(-2147413071)] - set; - } - - /// fontFamily property of IHTMLStyle interface. - /// An original IDL definition of fontFamily property was the following: BSTR fontFamily; - // IDL: BSTR fontFamily; - // VB6: fontFamily As String - string fontFamily - { - // IDL: HRESULT fontFamily ([out, retval] BSTR* ReturnValue); - // VB6: Function fontFamily As String - [DispId(-2147413094)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT fontFamily (BSTR value); - // VB6: Sub fontFamily (ByVal value As String) - [DispId(-2147413094)] - set; - } - - /// fontSize property of IHTMLStyle interface. - /// An original IDL definition of fontSize property was the following: VARIANT fontSize; - // IDL: VARIANT fontSize; - // VB6: fontSize As Any - object fontSize - { - // IDL: HRESULT fontSize ([out, retval] VARIANT* ReturnValue); - // VB6: Function fontSize As Any - [DispId(-2147413093)] - get; - // IDL: HRESULT fontSize (VARIANT value); - // VB6: Sub fontSize (ByVal value As Any) - [DispId(-2147413093)] - set; - } - - /// fontStyle property of IHTMLStyle interface. - /// An original IDL definition of fontStyle property was the following: BSTR fontStyle; - // IDL: BSTR fontStyle; - // VB6: fontStyle As String - string fontStyle - { - // IDL: HRESULT fontStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function fontStyle As String - [DispId(-2147413088)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT fontStyle (BSTR value); - // VB6: Sub fontStyle (ByVal value As String) - [DispId(-2147413088)] - set; - } - - /// fontVariant property of IHTMLStyle interface. - /// An original IDL definition of fontVariant property was the following: BSTR fontVariant; - // IDL: BSTR fontVariant; - // VB6: fontVariant As String - string fontVariant - { - // IDL: HRESULT fontVariant ([out, retval] BSTR* ReturnValue); - // VB6: Function fontVariant As String - [DispId(-2147413087)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT fontVariant (BSTR value); - // VB6: Sub fontVariant (ByVal value As String) - [DispId(-2147413087)] - set; - } - - /// fontWeight property of IHTMLStyle interface. - /// An original IDL definition of fontWeight property was the following: BSTR fontWeight; - // IDL: BSTR fontWeight; - // VB6: fontWeight As String - string fontWeight - { - // IDL: HRESULT fontWeight ([out, retval] BSTR* ReturnValue); - // VB6: Function fontWeight As String - [DispId(-2147413085)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT fontWeight (BSTR value); - // VB6: Sub fontWeight (ByVal value As String) - [DispId(-2147413085)] - set; - } - - /// height property of IHTMLStyle interface. - /// An original IDL definition of height property was the following: VARIANT height; - // IDL: VARIANT height; - // VB6: height As Any - object height - { - // IDL: HRESULT height ([out, retval] VARIANT* ReturnValue); - // VB6: Function height As Any - [DispId(-2147418106)] - get; - // IDL: HRESULT height (VARIANT value); - // VB6: Sub height (ByVal value As Any) - [DispId(-2147418106)] - set; - } - - /// left property of IHTMLStyle interface. - /// An original IDL definition of left property was the following: VARIANT left; - // IDL: VARIANT left; - // VB6: left As Any - object left - { - // IDL: HRESULT left ([out, retval] VARIANT* ReturnValue); - // VB6: Function left As Any - [DispId(-2147418109)] - get; - // IDL: HRESULT left (VARIANT value); - // VB6: Sub left (ByVal value As Any) - [DispId(-2147418109)] - set; - } - - /// letterSpacing property of IHTMLStyle interface. - /// An original IDL definition of letterSpacing property was the following: VARIANT letterSpacing; - // IDL: VARIANT letterSpacing; - // VB6: letterSpacing As Any - object letterSpacing - { - // IDL: HRESULT letterSpacing ([out, retval] VARIANT* ReturnValue); - // VB6: Function letterSpacing As Any - [DispId(-2147413104)] - get; - // IDL: HRESULT letterSpacing (VARIANT value); - // VB6: Sub letterSpacing (ByVal value As Any) - [DispId(-2147413104)] - set; - } - - /// lineHeight property of IHTMLStyle interface. - /// An original IDL definition of lineHeight property was the following: VARIANT lineHeight; - // IDL: VARIANT lineHeight; - // VB6: lineHeight As Any - object lineHeight - { - // IDL: HRESULT lineHeight ([out, retval] VARIANT* ReturnValue); - // VB6: Function lineHeight As Any - [DispId(-2147413106)] - get; - // IDL: HRESULT lineHeight (VARIANT value); - // VB6: Sub lineHeight (ByVal value As Any) - [DispId(-2147413106)] - set; - } - - /// listStyle property of IHTMLStyle interface. - /// An original IDL definition of listStyle property was the following: BSTR listStyle; - // IDL: BSTR listStyle; - // VB6: listStyle As String - string listStyle - { - // IDL: HRESULT listStyle ([out, retval] BSTR* ReturnValue); - // VB6: Function listStyle As String - [DispId(-2147413037)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT listStyle (BSTR value); - // VB6: Sub listStyle (ByVal value As String) - [DispId(-2147413037)] - set; - } - - /// listStyleImage property of IHTMLStyle interface. - /// An original IDL definition of listStyleImage property was the following: BSTR listStyleImage; - // IDL: BSTR listStyleImage; - // VB6: listStyleImage As String - string listStyleImage - { - // IDL: HRESULT listStyleImage ([out, retval] BSTR* ReturnValue); - // VB6: Function listStyleImage As String - [DispId(-2147413038)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT listStyleImage (BSTR value); - // VB6: Sub listStyleImage (ByVal value As String) - [DispId(-2147413038)] - set; - } - - /// listStylePosition property of IHTMLStyle interface. - /// An original IDL definition of listStylePosition property was the following: BSTR listStylePosition; - // IDL: BSTR listStylePosition; - // VB6: listStylePosition As String - string listStylePosition - { - // IDL: HRESULT listStylePosition ([out, retval] BSTR* ReturnValue); - // VB6: Function listStylePosition As String - [DispId(-2147413039)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT listStylePosition (BSTR value); - // VB6: Sub listStylePosition (ByVal value As String) - [DispId(-2147413039)] - set; - } - - /// listStyleType property of IHTMLStyle interface. - /// An original IDL definition of listStyleType property was the following: BSTR listStyleType; - // IDL: BSTR listStyleType; - // VB6: listStyleType As String - string listStyleType - { - // IDL: HRESULT listStyleType ([out, retval] BSTR* ReturnValue); - // VB6: Function listStyleType As String - [DispId(-2147413040)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT listStyleType (BSTR value); - // VB6: Sub listStyleType (ByVal value As String) - [DispId(-2147413040)] - set; - } - - /// margin property of IHTMLStyle interface. - /// An original IDL definition of margin property was the following: BSTR margin; - // IDL: BSTR margin; - // VB6: margin As String - string margin - { - // IDL: HRESULT margin ([out, retval] BSTR* ReturnValue); - // VB6: Function margin As String - [DispId(-2147413076)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT margin (BSTR value); - // VB6: Sub margin (ByVal value As String) - [DispId(-2147413076)] - set; - } - - /// marginBottom property of IHTMLStyle interface. - /// An original IDL definition of marginBottom property was the following: VARIANT marginBottom; - // IDL: VARIANT marginBottom; - // VB6: marginBottom As Any - object marginBottom - { - // IDL: HRESULT marginBottom ([out, retval] VARIANT* ReturnValue); - // VB6: Function marginBottom As Any - [DispId(-2147413073)] - get; - // IDL: HRESULT marginBottom (VARIANT value); - // VB6: Sub marginBottom (ByVal value As Any) - [DispId(-2147413073)] - set; - } - - /// marginLeft property of IHTMLStyle interface. - /// An original IDL definition of marginLeft property was the following: VARIANT marginLeft; - // IDL: VARIANT marginLeft; - // VB6: marginLeft As Any - object marginLeft - { - // IDL: HRESULT marginLeft ([out, retval] VARIANT* ReturnValue); - // VB6: Function marginLeft As Any - [DispId(-2147413072)] - get; - // IDL: HRESULT marginLeft (VARIANT value); - // VB6: Sub marginLeft (ByVal value As Any) - [DispId(-2147413072)] - set; - } - - /// marginRight property of IHTMLStyle interface. - /// An original IDL definition of marginRight property was the following: VARIANT marginRight; - // IDL: VARIANT marginRight; - // VB6: marginRight As Any - object marginRight - { - // IDL: HRESULT marginRight ([out, retval] VARIANT* ReturnValue); - // VB6: Function marginRight As Any - [DispId(-2147413074)] - get; - // IDL: HRESULT marginRight (VARIANT value); - // VB6: Sub marginRight (ByVal value As Any) - [DispId(-2147413074)] - set; - } - - /// marginTop property of IHTMLStyle interface. - /// An original IDL definition of marginTop property was the following: VARIANT marginTop; - // IDL: VARIANT marginTop; - // VB6: marginTop As Any - object marginTop - { - // IDL: HRESULT marginTop ([out, retval] VARIANT* ReturnValue); - // VB6: Function marginTop As Any - [DispId(-2147413075)] - get; - // IDL: HRESULT marginTop (VARIANT value); - // VB6: Sub marginTop (ByVal value As Any) - [DispId(-2147413075)] - set; - } - - /// overflow property of IHTMLStyle interface. - /// An original IDL definition of overflow property was the following: BSTR overflow; - // IDL: BSTR overflow; - // VB6: overflow As String - string overflow - { - // IDL: HRESULT overflow ([out, retval] BSTR* ReturnValue); - // VB6: Function overflow As String - [DispId(-2147413102)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT overflow (BSTR value); - // VB6: Sub overflow (ByVal value As String) - [DispId(-2147413102)] - set; - } - - /// padding property of IHTMLStyle interface. - /// An original IDL definition of padding property was the following: BSTR padding; - // IDL: BSTR padding; - // VB6: padding As String - string padding - { - // IDL: HRESULT padding ([out, retval] BSTR* ReturnValue); - // VB6: Function padding As String - [DispId(-2147413101)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - // IDL: HRESULT padding (BSTR value); - // VB6: Sub padding (ByVal value As String) - [DispId(-2147413101)] - set; - } - - /// paddingBottom property of IHTMLStyle interface. - /// An original IDL definition of paddingBottom property was the following: VARIANT paddingBottom; - // IDL: VARIANT paddingBottom; - // VB6: paddingBottom As Any - object paddingBottom - { - // IDL: HRESULT paddingBottom ([out, retval] VARIANT* ReturnValue); - // VB6: Function paddingBottom As Any - [DispId(-2147413098)] - get; - // IDL: HRESULT paddingBottom (VARIANT value); - // VB6: Sub paddingBottom (ByVal value As Any) - [DispId(-2147413098)] - set; - } - - /// paddingLeft property of IHTMLStyle interface. - /// An original IDL definition of paddingLeft property was the following: VARIANT paddingLeft; - // IDL: VARIANT paddingLeft; - // VB6: paddingLeft As Any - object paddingLeft - { - // IDL: HRESULT paddingLeft ([out, retval] VARIANT* ReturnValue); - // VB6: Function paddingLeft As Any - [DispId(-2147413097)] - get; - // IDL: HRESULT paddingLeft (VARIANT value); - // VB6: Sub paddingLeft (ByVal value As Any) - [DispId(-2147413097)] - set; - } - - /// paddingRight property of IHTMLStyle interface. - object paddingRight { - [DispId(-2147413099)] - get; - } - - /// paddingTop property of IHTMLStyle interface. - object paddingTop { - [DispId(-2147413100)] - get; - } - - /// pageBreakAfter property of IHTMLStyle interface. - string pageBreakAfter { - [DispId(-2147413034)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// pageBreakBefore property of IHTMLStyle interface. - string pageBreakBefore { - [DispId(-2147413035)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// pixelHeight property of IHTMLStyle interface. - int pixelHeight { - [DispId(-2147414109)] - get; - } - - /// pixelLeft property of IHTMLStyle interface. - int pixelLeft { - [DispId(-2147414111)] - get; - } - - /// pixelTop property of IHTMLStyle interface. - int pixelTop { - [DispId(-2147414112)] - get; - } - - /// pixelWidth property of IHTMLStyle interface. - int pixelWidth { - [DispId(-2147414110)] - get; - } - - /// posHeight property of IHTMLStyle interface. - float posHeight { - [DispId(-2147414105)] - get; - } - - /// position property of IHTMLStyle interface. - string position { - [DispId(-2147413022)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// posLeft property of IHTMLStyle interface. - float posLeft { - [DispId(-2147414107)] - get; - } - - /// posTop property of IHTMLStyle interface. - float posTop { - [DispId(-2147414108)] - get; - } - - /// posWidth property of IHTMLStyle interface. - float posWidth { - [DispId(-2147414106)] - get; - } - - /// styleFloat property of IHTMLStyle interface. - string styleFloat { - [DispId(-2147413042)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// textAlign property of IHTMLStyle interface. - string textAlign { - [DispId(-2147418040)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// textDecoration property of IHTMLStyle interface. - string textDecoration { - [DispId(-2147413077)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// textDecorationBlink property of IHTMLStyle interface. - bool textDecorationBlink { - [DispId(-2147413090)] - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - /// textDecorationLineThrough property of IHTMLStyle interface. - bool textDecorationLineThrough { - [DispId(-2147413092)] - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - /// textDecorationNone property of IHTMLStyle interface. - bool textDecorationNone { - [DispId(-2147413089)] - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - /// textDecorationOverline property of IHTMLStyle interface. - bool textDecorationOverline { - [DispId(-2147413043)] - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - /// textDecorationUnderline property of IHTMLStyle interface. - bool textDecorationUnderline { - [DispId(-2147413091)] - [return: MarshalAs(UnmanagedType.VariantBool)] - get; - } - - /// textIndent property of IHTMLStyle interface. - object textIndent { - [DispId(-2147413105)] - get; - } - - /// textTransform property of IHTMLStyle interface. - string textTransform { - [DispId(-2147413108)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// top property of IHTMLStyle interface. - object top { - [DispId(-2147418108)] - get; - } - - /// verticalAlign property of IHTMLStyle interface. - object verticalAlign { - [DispId(-2147413064)] - get; - } - - /// visibility property of IHTMLStyle interface. - string visibility { - [DispId(-2147413032)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// whiteSpace property of IHTMLStyle interface. - string whiteSpace { - [DispId(-2147413036)] - [return: MarshalAs(UnmanagedType.BStr)] - get; - } - - /// width property of IHTMLStyle interface. - object width { - [DispId(-2147418107)] - get; - } - - /// wordSpacing property of IHTMLStyle interface. - object wordSpacing { - [DispId(-2147413065)] - get; - } - - /// zIndex property of IHTMLStyle interface. - object zIndex { - [DispId(-2147413021)] - get; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComImport, Guid("3050F25E-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLStyle + { + /// setAttribute method of IHTMLStyle interface. + /// An original IDL definition of setAttribute method was the following: HRESULT setAttribute (BSTR strAttributeName, VARIANT AttributeValue, [optional, defaultvalue(1)] long lFlags); + // IDL: HRESULT setAttribute (BSTR strAttributeName, VARIANT AttributeValue, [optional, defaultvalue(1)] long lFlags); + // VB6: Sub setAttribute (ByVal strAttributeName As String, ByVal AttributeValue As Any, [ByVal lFlags As Long = 1]) + [DispId(-2147417611)] + void setAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, object AttributeValue, int lFlags); + + /// getAttribute method of IHTMLStyle interface. + /// An original IDL definition of getAttribute method was the following: HRESULT getAttribute (BSTR strAttributeName, [optional, defaultvalue(0)] long lFlags, [out, retval] VARIANT* ReturnValue); + // IDL: HRESULT getAttribute (BSTR strAttributeName, [optional, defaultvalue(0)] long lFlags, [out, retval] VARIANT* ReturnValue); + // VB6: Function getAttribute (ByVal strAttributeName As String, [ByVal lFlags As Long = 0]) As Any + [DispId(-2147417610)] + object getAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); + + /// removeAttribute method of IHTMLStyle interface. + /// An original IDL definition of removeAttribute method was the following: HRESULT removeAttribute (BSTR strAttributeName, [optional, defaultvalue(1)] long lFlags, [out, retval] VARIANT_BOOL* ReturnValue); + // IDL: HRESULT removeAttribute (BSTR strAttributeName, [optional, defaultvalue(1)] long lFlags, [out, retval] VARIANT_BOOL* ReturnValue); + // VB6: Function removeAttribute (ByVal strAttributeName As String, [ByVal lFlags As Long = 1]) As Boolean + [DispId(-2147417609)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool removeAttribute([MarshalAs(UnmanagedType.BStr)] string strAttributeName, int lFlags); + + /// toString method of IHTMLStyle interface. + /// An original IDL definition of toString method was the following: HRESULT toString ([out, retval] BSTR* ReturnValue); + // IDL: HRESULT toString ([out, retval] BSTR* ReturnValue); + // VB6: Function toString As String + [DispId(-2147414104)] + [return: MarshalAs(UnmanagedType.BStr)] + string toString(); + + /// background property of IHTMLStyle interface. + /// An original IDL definition of background property was the following: BSTR background; + // IDL: BSTR background; + // VB6: background As String + string background + { + // IDL: HRESULT background ([out, retval] BSTR* ReturnValue); + // VB6: Function background As String + [DispId(-2147413080)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT background (BSTR value); + // VB6: Sub background (ByVal value As String) + [DispId(-2147413080)] set; + } + + /// backgroundAttachment property of IHTMLStyle interface. + /// An original IDL definition of backgroundAttachment property was the following: BSTR backgroundAttachment; + // IDL: BSTR backgroundAttachment; + // VB6: backgroundAttachment As String + string backgroundAttachment + { + // IDL: HRESULT backgroundAttachment ([out, retval] BSTR* ReturnValue); + // VB6: Function backgroundAttachment As String + [DispId(-2147413067)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT backgroundAttachment (BSTR value); + // VB6: Sub backgroundAttachment (ByVal value As String) + [DispId(-2147413067)] set; + } + + /// backgroundColor property of IHTMLStyle interface. + /// An original IDL definition of backgroundColor property was the following: VARIANT backgroundColor; + // IDL: VARIANT backgroundColor; + // VB6: backgroundColor As Any + object backgroundColor + { + // IDL: HRESULT backgroundColor ([out, retval] VARIANT* ReturnValue); + // VB6: Function backgroundColor As Any + [DispId(-501)] get; + // IDL: HRESULT backgroundColor (VARIANT value); + // VB6: Sub backgroundColor (ByVal value As Any) + [DispId(-501)] set; + } + + /// backgroundImage property of IHTMLStyle interface. + /// An original IDL definition of backgroundImage property was the following: BSTR backgroundImage; + // IDL: BSTR backgroundImage; + // VB6: backgroundImage As String + string backgroundImage + { + // IDL: HRESULT backgroundImage ([out, retval] BSTR* ReturnValue); + // VB6: Function backgroundImage As String + [DispId(-2147413111)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT backgroundImage (BSTR value); + // VB6: Sub backgroundImage (ByVal value As String) + [DispId(-2147413111)] set; + } + + /// backgroundPosition property of IHTMLStyle interface. + /// An original IDL definition of backgroundPosition property was the following: BSTR backgroundPosition; + // IDL: BSTR backgroundPosition; + // VB6: backgroundPosition As String + string backgroundPosition + { + // IDL: HRESULT backgroundPosition ([out, retval] BSTR* ReturnValue); + // VB6: Function backgroundPosition As String + [DispId(-2147413066)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT backgroundPosition (BSTR value); + // VB6: Sub backgroundPosition (ByVal value As String) + [DispId(-2147413066)] set; + } + + /// backgroundPositionX property of IHTMLStyle interface. + /// An original IDL definition of backgroundPositionX property was the following: VARIANT backgroundPositionX; + // IDL: VARIANT backgroundPositionX; + // VB6: backgroundPositionX As Any + object backgroundPositionX + { + // IDL: HRESULT backgroundPositionX ([out, retval] VARIANT* ReturnValue); + // VB6: Function backgroundPositionX As Any + [DispId(-2147413079)] get; + // IDL: HRESULT backgroundPositionX (VARIANT value); + // VB6: Sub backgroundPositionX (ByVal value As Any) + [DispId(-2147413079)] set; + } + + /// backgroundPositionY property of IHTMLStyle interface. + /// An original IDL definition of backgroundPositionY property was the following: VARIANT backgroundPositionY; + // IDL: VARIANT backgroundPositionY; + // VB6: backgroundPositionY As Any + object backgroundPositionY + { + // IDL: HRESULT backgroundPositionY ([out, retval] VARIANT* ReturnValue); + // VB6: Function backgroundPositionY As Any + [DispId(-2147413078)] get; + // IDL: HRESULT backgroundPositionY (VARIANT value); + // VB6: Sub backgroundPositionY (ByVal value As Any) + [DispId(-2147413078)] set; + } + + /// backgroundRepeat property of IHTMLStyle interface. + /// An original IDL definition of backgroundRepeat property was the following: BSTR backgroundRepeat; + // IDL: BSTR backgroundRepeat; + // VB6: backgroundRepeat As String + string backgroundRepeat + { + // IDL: HRESULT backgroundRepeat ([out, retval] BSTR* ReturnValue); + // VB6: Function backgroundRepeat As String + [DispId(-2147413068)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT backgroundRepeat (BSTR value); + // VB6: Sub backgroundRepeat (ByVal value As String) + [DispId(-2147413068)] set; + } + + /// border property of IHTMLStyle interface. + /// An original IDL definition of border property was the following: BSTR border; + // IDL: BSTR border; + // VB6: border As String + string border + { + // IDL: HRESULT border ([out, retval] BSTR* ReturnValue); + // VB6: Function border As String + [DispId(-2147413063)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT border (BSTR value); + // VB6: Sub border (ByVal value As String) + [DispId(-2147413063)] set; + } + + /// borderBottom property of IHTMLStyle interface. + /// An original IDL definition of borderBottom property was the following: BSTR borderBottom; + // IDL: BSTR borderBottom; + // VB6: borderBottom As String + string borderBottom + { + // IDL: HRESULT borderBottom ([out, retval] BSTR* ReturnValue); + // VB6: Function borderBottom As String + [DispId(-2147413060)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderBottom (BSTR value); + // VB6: Sub borderBottom (ByVal value As String) + [DispId(-2147413060)] set; + } + + /// borderBottomColor property of IHTMLStyle interface. + /// An original IDL definition of borderBottomColor property was the following: VARIANT borderBottomColor; + // IDL: VARIANT borderBottomColor; + // VB6: borderBottomColor As Any + object borderBottomColor + { + // IDL: HRESULT borderBottomColor ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderBottomColor As Any + [DispId(-2147413055)] get; + // IDL: HRESULT borderBottomColor (VARIANT value); + // VB6: Sub borderBottomColor (ByVal value As Any) + [DispId(-2147413055)] set; + } + + /// borderBottomStyle property of IHTMLStyle interface. + /// An original IDL definition of borderBottomStyle property was the following: BSTR borderBottomStyle; + // IDL: BSTR borderBottomStyle; + // VB6: borderBottomStyle As String + string borderBottomStyle + { + // IDL: HRESULT borderBottomStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function borderBottomStyle As String + [DispId(-2147413045)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderBottomStyle (BSTR value); + // VB6: Sub borderBottomStyle (ByVal value As String) + [DispId(-2147413045)] set; + } + + /// borderBottomWidth property of IHTMLStyle interface. + /// An original IDL definition of borderBottomWidth property was the following: VARIANT borderBottomWidth; + // IDL: VARIANT borderBottomWidth; + // VB6: borderBottomWidth As Any + object borderBottomWidth + { + // IDL: HRESULT borderBottomWidth ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderBottomWidth As Any + [DispId(-2147413050)] get; + // IDL: HRESULT borderBottomWidth (VARIANT value); + // VB6: Sub borderBottomWidth (ByVal value As Any) + [DispId(-2147413050)] set; + } + + /// borderColor property of IHTMLStyle interface. + /// An original IDL definition of borderColor property was the following: BSTR borderColor; + // IDL: BSTR borderColor; + // VB6: borderColor As String + string borderColor + { + // IDL: HRESULT borderColor ([out, retval] BSTR* ReturnValue); + // VB6: Function borderColor As String + [DispId(-2147413058)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderColor (BSTR value); + // VB6: Sub borderColor (ByVal value As String) + [DispId(-2147413058)] set; + } + + /// borderLeft property of IHTMLStyle interface. + /// An original IDL definition of borderLeft property was the following: BSTR borderLeft; + // IDL: BSTR borderLeft; + // VB6: borderLeft As String + string borderLeft + { + // IDL: HRESULT borderLeft ([out, retval] BSTR* ReturnValue); + // VB6: Function borderLeft As String + [DispId(-2147413059)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderLeft (BSTR value); + // VB6: Sub borderLeft (ByVal value As String) + [DispId(-2147413059)] set; + } + + /// borderLeftColor property of IHTMLStyle interface. + /// An original IDL definition of borderLeftColor property was the following: VARIANT borderLeftColor; + // IDL: VARIANT borderLeftColor; + // VB6: borderLeftColor As Any + object borderLeftColor + { + // IDL: HRESULT borderLeftColor ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderLeftColor As Any + [DispId(-2147413054)] get; + // IDL: HRESULT borderLeftColor (VARIANT value); + // VB6: Sub borderLeftColor (ByVal value As Any) + [DispId(-2147413054)] set; + } + + /// borderLeftStyle property of IHTMLStyle interface. + /// An original IDL definition of borderLeftStyle property was the following: BSTR borderLeftStyle; + // IDL: BSTR borderLeftStyle; + // VB6: borderLeftStyle As String + string borderLeftStyle + { + // IDL: HRESULT borderLeftStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function borderLeftStyle As String + [DispId(-2147413044)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderLeftStyle (BSTR value); + // VB6: Sub borderLeftStyle (ByVal value As String) + [DispId(-2147413044)] set; + } + + /// borderLeftWidth property of IHTMLStyle interface. + /// An original IDL definition of borderLeftWidth property was the following: VARIANT borderLeftWidth; + // IDL: VARIANT borderLeftWidth; + // VB6: borderLeftWidth As Any + object borderLeftWidth + { + // IDL: HRESULT borderLeftWidth ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderLeftWidth As Any + [DispId(-2147413049)] get; + // IDL: HRESULT borderLeftWidth (VARIANT value); + // VB6: Sub borderLeftWidth (ByVal value As Any) + [DispId(-2147413049)] set; + } + + /// borderRight property of IHTMLStyle interface. + /// An original IDL definition of borderRight property was the following: BSTR borderRight; + // IDL: BSTR borderRight; + // VB6: borderRight As String + string borderRight + { + // IDL: HRESULT borderRight ([out, retval] BSTR* ReturnValue); + // VB6: Function borderRight As String + [DispId(-2147413061)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderRight (BSTR value); + // VB6: Sub borderRight (ByVal value As String) + [DispId(-2147413061)] set; + } + + /// borderRightColor property of IHTMLStyle interface. + /// An original IDL definition of borderRightColor property was the following: VARIANT borderRightColor; + // IDL: VARIANT borderRightColor; + // VB6: borderRightColor As Any + object borderRightColor + { + // IDL: HRESULT borderRightColor ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderRightColor As Any + [DispId(-2147413056)] get; + // IDL: HRESULT borderRightColor (VARIANT value); + // VB6: Sub borderRightColor (ByVal value As Any) + [DispId(-2147413056)] set; + } + + /// borderRightStyle property of IHTMLStyle interface. + /// An original IDL definition of borderRightStyle property was the following: BSTR borderRightStyle; + // IDL: BSTR borderRightStyle; + // VB6: borderRightStyle As String + string borderRightStyle + { + // IDL: HRESULT borderRightStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function borderRightStyle As String + [DispId(-2147413046)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderRightStyle (BSTR value); + // VB6: Sub borderRightStyle (ByVal value As String) + [DispId(-2147413046)] set; + } + + /// borderRightWidth property of IHTMLStyle interface. + /// An original IDL definition of borderRightWidth property was the following: VARIANT borderRightWidth; + // IDL: VARIANT borderRightWidth; + // VB6: borderRightWidth As Any + object borderRightWidth + { + // IDL: HRESULT borderRightWidth ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderRightWidth As Any + [DispId(-2147413051)] get; + // IDL: HRESULT borderRightWidth (VARIANT value); + // VB6: Sub borderRightWidth (ByVal value As Any) + [DispId(-2147413051)] set; + } + + /// borderStyle property of IHTMLStyle interface. + /// An original IDL definition of borderStyle property was the following: BSTR borderStyle; + // IDL: BSTR borderStyle; + // VB6: borderStyle As String + string borderStyle + { + // IDL: HRESULT borderStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function borderStyle As String + [DispId(-2147413048)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderStyle (BSTR value); + // VB6: Sub borderStyle (ByVal value As String) + [DispId(-2147413048)] set; + } + + /// borderTop property of IHTMLStyle interface. + /// An original IDL definition of borderTop property was the following: BSTR borderTop; + // IDL: BSTR borderTop; + // VB6: borderTop As String + string borderTop + { + // IDL: HRESULT borderTop ([out, retval] BSTR* ReturnValue); + // VB6: Function borderTop As String + [DispId(-2147413062)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderTop (BSTR value); + // VB6: Sub borderTop (ByVal value As String) + [DispId(-2147413062)] set; + } + + /// borderTopColor property of IHTMLStyle interface. + /// An original IDL definition of borderTopColor property was the following: VARIANT borderTopColor; + // IDL: VARIANT borderTopColor; + // VB6: borderTopColor As Any + object borderTopColor + { + // IDL: HRESULT borderTopColor ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderTopColor As Any + [DispId(-2147413057)] get; + // IDL: HRESULT borderTopColor (VARIANT value); + // VB6: Sub borderTopColor (ByVal value As Any) + [DispId(-2147413057)] set; + } + + /// borderTopStyle property of IHTMLStyle interface. + /// An original IDL definition of borderTopStyle property was the following: BSTR borderTopStyle; + // IDL: BSTR borderTopStyle; + // VB6: borderTopStyle As String + string borderTopStyle + { + // IDL: HRESULT borderTopStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function borderTopStyle As String + [DispId(-2147413047)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderTopStyle (BSTR value); + // VB6: Sub borderTopStyle (ByVal value As String) + [DispId(-2147413047)] set; + } + + /// borderTopWidth property of IHTMLStyle interface. + /// An original IDL definition of borderTopWidth property was the following: VARIANT borderTopWidth; + // IDL: VARIANT borderTopWidth; + // VB6: borderTopWidth As Any + object borderTopWidth + { + // IDL: HRESULT borderTopWidth ([out, retval] VARIANT* ReturnValue); + // VB6: Function borderTopWidth As Any + [DispId(-2147413052)] get; + // IDL: HRESULT borderTopWidth (VARIANT value); + // VB6: Sub borderTopWidth (ByVal value As Any) + [DispId(-2147413052)] set; + } + + /// borderWidth property of IHTMLStyle interface. + /// An original IDL definition of borderWidth property was the following: BSTR borderWidth; + // IDL: BSTR borderWidth; + // VB6: borderWidth As String + string borderWidth + { + // IDL: HRESULT borderWidth ([out, retval] BSTR* ReturnValue); + // VB6: Function borderWidth As String + [DispId(-2147413053)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT borderWidth (BSTR value); + // VB6: Sub borderWidth (ByVal value As String) + [DispId(-2147413053)] set; + } + + /// clear property of IHTMLStyle interface. + /// An original IDL definition of clear property was the following: BSTR clear; + // IDL: BSTR clear; + // VB6: clear As String + string clear + { + // IDL: HRESULT clear ([out, retval] BSTR* ReturnValue); + // VB6: Function clear As String + [DispId(-2147413096)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT clear (BSTR value); + // VB6: Sub clear (ByVal value As String) + [DispId(-2147413096)] set; + } + + /// clip property of IHTMLStyle interface. + /// An original IDL definition of clip property was the following: BSTR clip; + // IDL: BSTR clip; + // VB6: clip As String + string clip + { + // IDL: HRESULT clip ([out, retval] BSTR* ReturnValue); + // VB6: Function clip As String + [DispId(-2147413020)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT clip (BSTR value); + // VB6: Sub clip (ByVal value As String) + [DispId(-2147413020)] set; + } + + /// color property of IHTMLStyle interface. + /// An original IDL definition of color property was the following: VARIANT color; + // IDL: VARIANT color; + // VB6: color As Any + object color + { + // IDL: HRESULT color ([out, retval] VARIANT* ReturnValue); + // VB6: Function color As Any + [DispId(-2147413110)] get; + // IDL: HRESULT color (VARIANT value); + // VB6: Sub color (ByVal value As Any) + [DispId(-2147413110)] set; + } + + /// cssText property of IHTMLStyle interface. + /// An original IDL definition of cssText property was the following: BSTR cssText; + // IDL: BSTR cssText; + // VB6: cssText As String + string cssText + { + // IDL: HRESULT cssText ([out, retval] BSTR* ReturnValue); + // VB6: Function cssText As String + [DispId(-2147413013)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT cssText (BSTR value); + // VB6: Sub cssText (ByVal value As String) + [DispId(-2147413013)] set; + } + + /// cursor property of IHTMLStyle interface. + /// An original IDL definition of cursor property was the following: BSTR cursor; + // IDL: BSTR cursor; + // VB6: cursor As String + string cursor + { + // IDL: HRESULT cursor ([out, retval] BSTR* ReturnValue); + // VB6: Function cursor As String + [DispId(-2147413010)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT cursor (BSTR value); + // VB6: Sub cursor (ByVal value As String) + [DispId(-2147413010)] set; + } + + /// display property of IHTMLStyle interface. + /// An original IDL definition of display property was the following: BSTR display; + // IDL: BSTR display; + // VB6: display As String + string display + { + // IDL: HRESULT display ([out, retval] BSTR* ReturnValue); + // VB6: Function display As String + [DispId(-2147413041)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT display (BSTR value); + // VB6: Sub display (ByVal value As String) + [DispId(-2147413041)] set; + } + + /// filter property of IHTMLStyle interface. + /// An original IDL definition of filter property was the following: BSTR filter; + // IDL: BSTR filter; + // VB6: filter As String + string filter + { + // IDL: HRESULT filter ([out, retval] BSTR* ReturnValue); + // VB6: Function filter As String + [DispId(-2147413030)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT filter (BSTR value); + // VB6: Sub filter (ByVal value As String) + [DispId(-2147413030)] set; + } + + /// font property of IHTMLStyle interface. + /// An original IDL definition of font property was the following: BSTR font; + // IDL: BSTR font; + // VB6: font As String + string font + { + // IDL: HRESULT font ([out, retval] BSTR* ReturnValue); + // VB6: Function font As String + [DispId(-2147413071)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT font (BSTR value); + // VB6: Sub font (ByVal value As String) + [DispId(-2147413071)] set; + } + + /// fontFamily property of IHTMLStyle interface. + /// An original IDL definition of fontFamily property was the following: BSTR fontFamily; + // IDL: BSTR fontFamily; + // VB6: fontFamily As String + string fontFamily + { + // IDL: HRESULT fontFamily ([out, retval] BSTR* ReturnValue); + // VB6: Function fontFamily As String + [DispId(-2147413094)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT fontFamily (BSTR value); + // VB6: Sub fontFamily (ByVal value As String) + [DispId(-2147413094)] set; + } + + /// fontSize property of IHTMLStyle interface. + /// An original IDL definition of fontSize property was the following: VARIANT fontSize; + // IDL: VARIANT fontSize; + // VB6: fontSize As Any + object fontSize + { + // IDL: HRESULT fontSize ([out, retval] VARIANT* ReturnValue); + // VB6: Function fontSize As Any + [DispId(-2147413093)] get; + // IDL: HRESULT fontSize (VARIANT value); + // VB6: Sub fontSize (ByVal value As Any) + [DispId(-2147413093)] set; + } + + /// fontStyle property of IHTMLStyle interface. + /// An original IDL definition of fontStyle property was the following: BSTR fontStyle; + // IDL: BSTR fontStyle; + // VB6: fontStyle As String + string fontStyle + { + // IDL: HRESULT fontStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function fontStyle As String + [DispId(-2147413088)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT fontStyle (BSTR value); + // VB6: Sub fontStyle (ByVal value As String) + [DispId(-2147413088)] set; + } + + /// fontVariant property of IHTMLStyle interface. + /// An original IDL definition of fontVariant property was the following: BSTR fontVariant; + // IDL: BSTR fontVariant; + // VB6: fontVariant As String + string fontVariant + { + // IDL: HRESULT fontVariant ([out, retval] BSTR* ReturnValue); + // VB6: Function fontVariant As String + [DispId(-2147413087)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT fontVariant (BSTR value); + // VB6: Sub fontVariant (ByVal value As String) + [DispId(-2147413087)] set; + } + + /// fontWeight property of IHTMLStyle interface. + /// An original IDL definition of fontWeight property was the following: BSTR fontWeight; + // IDL: BSTR fontWeight; + // VB6: fontWeight As String + string fontWeight + { + // IDL: HRESULT fontWeight ([out, retval] BSTR* ReturnValue); + // VB6: Function fontWeight As String + [DispId(-2147413085)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT fontWeight (BSTR value); + // VB6: Sub fontWeight (ByVal value As String) + [DispId(-2147413085)] set; + } + + /// height property of IHTMLStyle interface. + /// An original IDL definition of height property was the following: VARIANT height; + // IDL: VARIANT height; + // VB6: height As Any + object height + { + // IDL: HRESULT height ([out, retval] VARIANT* ReturnValue); + // VB6: Function height As Any + [DispId(-2147418106)] get; + // IDL: HRESULT height (VARIANT value); + // VB6: Sub height (ByVal value As Any) + [DispId(-2147418106)] set; + } + + /// left property of IHTMLStyle interface. + /// An original IDL definition of left property was the following: VARIANT left; + // IDL: VARIANT left; + // VB6: left As Any + object left + { + // IDL: HRESULT left ([out, retval] VARIANT* ReturnValue); + // VB6: Function left As Any + [DispId(-2147418109)] get; + // IDL: HRESULT left (VARIANT value); + // VB6: Sub left (ByVal value As Any) + [DispId(-2147418109)] set; + } + + /// letterSpacing property of IHTMLStyle interface. + /// An original IDL definition of letterSpacing property was the following: VARIANT letterSpacing; + // IDL: VARIANT letterSpacing; + // VB6: letterSpacing As Any + object letterSpacing + { + // IDL: HRESULT letterSpacing ([out, retval] VARIANT* ReturnValue); + // VB6: Function letterSpacing As Any + [DispId(-2147413104)] get; + // IDL: HRESULT letterSpacing (VARIANT value); + // VB6: Sub letterSpacing (ByVal value As Any) + [DispId(-2147413104)] set; + } + + /// lineHeight property of IHTMLStyle interface. + /// An original IDL definition of lineHeight property was the following: VARIANT lineHeight; + // IDL: VARIANT lineHeight; + // VB6: lineHeight As Any + object lineHeight + { + // IDL: HRESULT lineHeight ([out, retval] VARIANT* ReturnValue); + // VB6: Function lineHeight As Any + [DispId(-2147413106)] get; + // IDL: HRESULT lineHeight (VARIANT value); + // VB6: Sub lineHeight (ByVal value As Any) + [DispId(-2147413106)] set; + } + + /// listStyle property of IHTMLStyle interface. + /// An original IDL definition of listStyle property was the following: BSTR listStyle; + // IDL: BSTR listStyle; + // VB6: listStyle As String + string listStyle + { + // IDL: HRESULT listStyle ([out, retval] BSTR* ReturnValue); + // VB6: Function listStyle As String + [DispId(-2147413037)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT listStyle (BSTR value); + // VB6: Sub listStyle (ByVal value As String) + [DispId(-2147413037)] set; + } + + /// listStyleImage property of IHTMLStyle interface. + /// An original IDL definition of listStyleImage property was the following: BSTR listStyleImage; + // IDL: BSTR listStyleImage; + // VB6: listStyleImage As String + string listStyleImage + { + // IDL: HRESULT listStyleImage ([out, retval] BSTR* ReturnValue); + // VB6: Function listStyleImage As String + [DispId(-2147413038)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT listStyleImage (BSTR value); + // VB6: Sub listStyleImage (ByVal value As String) + [DispId(-2147413038)] set; + } + + /// listStylePosition property of IHTMLStyle interface. + /// An original IDL definition of listStylePosition property was the following: BSTR listStylePosition; + // IDL: BSTR listStylePosition; + // VB6: listStylePosition As String + string listStylePosition + { + // IDL: HRESULT listStylePosition ([out, retval] BSTR* ReturnValue); + // VB6: Function listStylePosition As String + [DispId(-2147413039)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT listStylePosition (BSTR value); + // VB6: Sub listStylePosition (ByVal value As String) + [DispId(-2147413039)] set; + } + + /// listStyleType property of IHTMLStyle interface. + /// An original IDL definition of listStyleType property was the following: BSTR listStyleType; + // IDL: BSTR listStyleType; + // VB6: listStyleType As String + string listStyleType + { + // IDL: HRESULT listStyleType ([out, retval] BSTR* ReturnValue); + // VB6: Function listStyleType As String + [DispId(-2147413040)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT listStyleType (BSTR value); + // VB6: Sub listStyleType (ByVal value As String) + [DispId(-2147413040)] set; + } + + /// margin property of IHTMLStyle interface. + /// An original IDL definition of margin property was the following: BSTR margin; + // IDL: BSTR margin; + // VB6: margin As String + string margin + { + // IDL: HRESULT margin ([out, retval] BSTR* ReturnValue); + // VB6: Function margin As String + [DispId(-2147413076)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT margin (BSTR value); + // VB6: Sub margin (ByVal value As String) + [DispId(-2147413076)] set; + } + + /// marginBottom property of IHTMLStyle interface. + /// An original IDL definition of marginBottom property was the following: VARIANT marginBottom; + // IDL: VARIANT marginBottom; + // VB6: marginBottom As Any + object marginBottom + { + // IDL: HRESULT marginBottom ([out, retval] VARIANT* ReturnValue); + // VB6: Function marginBottom As Any + [DispId(-2147413073)] get; + // IDL: HRESULT marginBottom (VARIANT value); + // VB6: Sub marginBottom (ByVal value As Any) + [DispId(-2147413073)] set; + } + + /// marginLeft property of IHTMLStyle interface. + /// An original IDL definition of marginLeft property was the following: VARIANT marginLeft; + // IDL: VARIANT marginLeft; + // VB6: marginLeft As Any + object marginLeft + { + // IDL: HRESULT marginLeft ([out, retval] VARIANT* ReturnValue); + // VB6: Function marginLeft As Any + [DispId(-2147413072)] get; + // IDL: HRESULT marginLeft (VARIANT value); + // VB6: Sub marginLeft (ByVal value As Any) + [DispId(-2147413072)] set; + } + + /// marginRight property of IHTMLStyle interface. + /// An original IDL definition of marginRight property was the following: VARIANT marginRight; + // IDL: VARIANT marginRight; + // VB6: marginRight As Any + object marginRight + { + // IDL: HRESULT marginRight ([out, retval] VARIANT* ReturnValue); + // VB6: Function marginRight As Any + [DispId(-2147413074)] get; + // IDL: HRESULT marginRight (VARIANT value); + // VB6: Sub marginRight (ByVal value As Any) + [DispId(-2147413074)] set; + } + + /// marginTop property of IHTMLStyle interface. + /// An original IDL definition of marginTop property was the following: VARIANT marginTop; + // IDL: VARIANT marginTop; + // VB6: marginTop As Any + object marginTop + { + // IDL: HRESULT marginTop ([out, retval] VARIANT* ReturnValue); + // VB6: Function marginTop As Any + [DispId(-2147413075)] get; + // IDL: HRESULT marginTop (VARIANT value); + // VB6: Sub marginTop (ByVal value As Any) + [DispId(-2147413075)] set; + } + + /// overflow property of IHTMLStyle interface. + /// An original IDL definition of overflow property was the following: BSTR overflow; + // IDL: BSTR overflow; + // VB6: overflow As String + string overflow + { + // IDL: HRESULT overflow ([out, retval] BSTR* ReturnValue); + // VB6: Function overflow As String + [DispId(-2147413102)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT overflow (BSTR value); + // VB6: Sub overflow (ByVal value As String) + [DispId(-2147413102)] set; + } + + /// padding property of IHTMLStyle interface. + /// An original IDL definition of padding property was the following: BSTR padding; + // IDL: BSTR padding; + // VB6: padding As String + string padding + { + // IDL: HRESULT padding ([out, retval] BSTR* ReturnValue); + // VB6: Function padding As String + [DispId(-2147413101)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + // IDL: HRESULT padding (BSTR value); + // VB6: Sub padding (ByVal value As String) + [DispId(-2147413101)] set; + } + + /// paddingBottom property of IHTMLStyle interface. + /// An original IDL definition of paddingBottom property was the following: VARIANT paddingBottom; + // IDL: VARIANT paddingBottom; + // VB6: paddingBottom As Any + object paddingBottom + { + // IDL: HRESULT paddingBottom ([out, retval] VARIANT* ReturnValue); + // VB6: Function paddingBottom As Any + [DispId(-2147413098)] get; + // IDL: HRESULT paddingBottom (VARIANT value); + // VB6: Sub paddingBottom (ByVal value As Any) + [DispId(-2147413098)] set; + } + + /// paddingLeft property of IHTMLStyle interface. + /// An original IDL definition of paddingLeft property was the following: VARIANT paddingLeft; + // IDL: VARIANT paddingLeft; + // VB6: paddingLeft As Any + object paddingLeft + { + // IDL: HRESULT paddingLeft ([out, retval] VARIANT* ReturnValue); + // VB6: Function paddingLeft As Any + [DispId(-2147413097)] get; + // IDL: HRESULT paddingLeft (VARIANT value); + // VB6: Sub paddingLeft (ByVal value As Any) + [DispId(-2147413097)] set; + } + + /// paddingRight property of IHTMLStyle interface. + object paddingRight { [DispId(-2147413099)] get; } + + /// paddingTop property of IHTMLStyle interface. + object paddingTop { [DispId(-2147413100)] get; } + + /// pageBreakAfter property of IHTMLStyle interface. + string pageBreakAfter + { + [DispId(-2147413034)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// pageBreakBefore property of IHTMLStyle interface. + string pageBreakBefore + { + [DispId(-2147413035)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// pixelHeight property of IHTMLStyle interface. + int pixelHeight { [DispId(-2147414109)] get; } + + /// pixelLeft property of IHTMLStyle interface. + int pixelLeft { [DispId(-2147414111)] get; } + + /// pixelTop property of IHTMLStyle interface. + int pixelTop { [DispId(-2147414112)] get; } + + /// pixelWidth property of IHTMLStyle interface. + int pixelWidth { [DispId(-2147414110)] get; } + + /// posHeight property of IHTMLStyle interface. + float posHeight { [DispId(-2147414105)] get; } + + /// position property of IHTMLStyle interface. + string position + { + [DispId(-2147413022)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// posLeft property of IHTMLStyle interface. + float posLeft { [DispId(-2147414107)] get; } + + /// posTop property of IHTMLStyle interface. + float posTop { [DispId(-2147414108)] get; } + + /// posWidth property of IHTMLStyle interface. + float posWidth { [DispId(-2147414106)] get; } + + /// styleFloat property of IHTMLStyle interface. + string styleFloat + { + [DispId(-2147413042)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// textAlign property of IHTMLStyle interface. + string textAlign + { + [DispId(-2147418040)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// textDecoration property of IHTMLStyle interface. + string textDecoration + { + [DispId(-2147413077)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// textDecorationBlink property of IHTMLStyle interface. + bool textDecorationBlink + { + [DispId(-2147413090)] + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + /// textDecorationLineThrough property of IHTMLStyle interface. + bool textDecorationLineThrough + { + [DispId(-2147413092)] + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + /// textDecorationNone property of IHTMLStyle interface. + bool textDecorationNone + { + [DispId(-2147413089)] + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + /// textDecorationOverline property of IHTMLStyle interface. + bool textDecorationOverline + { + [DispId(-2147413043)] + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + /// textDecorationUnderline property of IHTMLStyle interface. + bool textDecorationUnderline + { + [DispId(-2147413091)] + [return: MarshalAs(UnmanagedType.VariantBool)] + get; + } + + /// textIndent property of IHTMLStyle interface. + object textIndent { [DispId(-2147413105)] get; } + + /// textTransform property of IHTMLStyle interface. + string textTransform + { + [DispId(-2147413108)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// top property of IHTMLStyle interface. + object top { [DispId(-2147418108)] get; } + + /// verticalAlign property of IHTMLStyle interface. + object verticalAlign { [DispId(-2147413064)] get; } + + /// visibility property of IHTMLStyle interface. + string visibility + { + [DispId(-2147413032)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// whiteSpace property of IHTMLStyle interface. + string whiteSpace + { + [DispId(-2147413036)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + /// width property of IHTMLStyle interface. + object width { [DispId(-2147418107)] get; } + + /// wordSpacing property of IHTMLStyle interface. + object wordSpacing { [DispId(-2147413065)] get; } + + /// zIndex property of IHTMLStyle interface. + object zIndex { [DispId(-2147413021)] get; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/IEInterop/IHTMLTxtRange.cs b/src/Greenshot.Base/IEInterop/IHTMLTxtRange.cs new file mode 100644 index 000000000..8f77258f1 --- /dev/null +++ b/src/Greenshot.Base/IEInterop/IHTMLTxtRange.cs @@ -0,0 +1,141 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + // See: http://msdn.microsoft.com/en-us/library/aa741548%28v=vs.85%29.aspx + [ComImport, Guid("3050F220-98B5-11CF-BB82-00AA00BDCE0B"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLTxtRange + { + [DispId(1006)] + IHTMLElement parentElement(); + + [DispId(1008)] + IHTMLTxtRange duplicate(); + + [DispId(1010)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool inRange(IHTMLTxtRange range); + + [DispId(1011)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool isEqual(IHTMLTxtRange range); + + [DispId(1012)] + void scrollIntoView([MarshalAs(UnmanagedType.VariantBool)] bool fStart); + + [DispId(1013)] + void collapse([MarshalAs(UnmanagedType.VariantBool)] bool Start); + + [DispId(1014)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool expand([MarshalAs(UnmanagedType.BStr)] string Unit); + + [DispId(1015)] + int move([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); + + [DispId(1016)] + int moveStart([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); + + [DispId(1017)] + int moveEnd([MarshalAs(UnmanagedType.BStr)] string Unit, int Count); + + [DispId(1024)] + void select(); + + [DispId(1026)] + void pasteHTML([MarshalAs(UnmanagedType.BStr)] string html); + + [DispId(1001)] + void moveToElementText(IHTMLElement element); + + [DispId(1025)] + void setEndPoint([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); + + [DispId(1018)] + int compareEndPoints([MarshalAs(UnmanagedType.BStr)] string how, IHTMLTxtRange SourceRange); + + [DispId(1019)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool findText([MarshalAs(UnmanagedType.BStr)] string String, int Count, int Flags); + + [DispId(1020)] + void moveToPoint(int x, int y); + + [DispId(1021)] + [return: MarshalAs(UnmanagedType.BStr)] + string getBookmark(); + + [DispId(1009)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool moveToBookmark([MarshalAs(UnmanagedType.BStr)] string Bookmark); + + [DispId(1027)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandSupported([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1028)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandEnabled([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1029)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandState([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1030)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool queryCommandIndeterm([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1031)] + [return: MarshalAs(UnmanagedType.BStr)] + string queryCommandText([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1032)] + object queryCommandValue([MarshalAs(UnmanagedType.BStr)] string cmdID); + + [DispId(1033)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool execCommand([MarshalAs(UnmanagedType.BStr)] string cmdID, [MarshalAs(UnmanagedType.VariantBool)] bool showUI, object value); + + [DispId(1034)] + [return: MarshalAs(UnmanagedType.VariantBool)] + bool execCommandShowHelp([MarshalAs(UnmanagedType.BStr)] string cmdID); + + string htmlText + { + [DispId(1003)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + + string text + { + [DispId(1004)] + [return: MarshalAs(UnmanagedType.BStr)] + get; + [DispId(1004)] set; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLScreen2.cs b/src/Greenshot.Base/IEInterop/IHTMLWindow2.cs similarity index 63% rename from GreenshotPlugin/IEInterop/IHTMLScreen2.cs rename to src/Greenshot.Base/IEInterop/IHTMLWindow2.cs index 3814da360..c37956cf0 100644 --- a/GreenshotPlugin/IEInterop/IHTMLScreen2.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLWindow2.cs @@ -1,49 +1,52 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F84A-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLScreen2 { - int logicalXDPI { - [DispId(1009)] - get; - } - - int logicalYDPI { - [DispId(1010)] - get; - } - - int deviceXDPI { - [DispId(1011)] - get; - } - - int deviceYDPI { - [DispId(1012)] - get; - } - }; -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComVisible(true), ComImport(), Guid("332c4427-26cb-11d0-b483-00c04fd90119"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLWindow2 + { + [DispId(1156)] + IHTMLScreen screen + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(1151)] + IHTMLDocument2 document + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(11)] + string name + { + [return: MarshalAs(UnmanagedType.BStr)] + get; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLScreen.cs b/src/Greenshot.Base/IEInterop/IHTMLWindow3.cs similarity index 72% rename from GreenshotPlugin/IEInterop/IHTMLScreen.cs rename to src/Greenshot.Base/IEInterop/IHTMLWindow3.cs index f65b77da7..2e8e4f095 100644 --- a/GreenshotPlugin/IEInterop/IHTMLScreen.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLWindow3.cs @@ -1,38 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComImport, Guid("3050F35C-98B5-11CF-BB82-00AA00BDCE0B"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLScreen { - [DispId(1003)] - int width { - get; - } - [DispId(1004)] - int height { - get; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComVisible(true), ComImport(), Guid("3050f4ae-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLWindow3 + { + [DispId(1170)] int screenLeft { get; } + + [DispId(1171)] int screenTop { get; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IEInterop/IHTMLWindow4.cs b/src/Greenshot.Base/IEInterop/IHTMLWindow4.cs similarity index 72% rename from GreenshotPlugin/IEInterop/IHTMLWindow4.cs rename to src/Greenshot.Base/IEInterop/IHTMLWindow4.cs index 8643c88c1..c97982afc 100644 --- a/GreenshotPlugin/IEInterop/IHTMLWindow4.cs +++ b/src/Greenshot.Base/IEInterop/IHTMLWindow4.cs @@ -1,35 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.IEInterop { - [ComVisible(true), ComImport(), Guid("3050f6cf-98b5-11cf-bb82-00aa00bdce0b"), - TypeLibType(TypeLibTypeFlags.FDual), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface IHTMLWindow4 { - [DispId(1181)] - IHTMLFrameBase frameElement { - [return: MarshalAs(UnmanagedType.IDispatch)] - get; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + [ComVisible(true), ComImport(), Guid("3050f6cf-98b5-11cf-bb82-00aa00bdce0b"), + TypeLibType(TypeLibTypeFlags.FDual), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] + public interface IHTMLWindow4 + { + [DispId(1181)] + IHTMLFrameBase frameElement + { + [return: MarshalAs(UnmanagedType.IDispatch)] + get; + } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/IEInterop/IWebBrowser2.cs b/src/Greenshot.Base/IEInterop/IWebBrowser2.cs new file mode 100644 index 000000000..3a500338a --- /dev/null +++ b/src/Greenshot.Base/IEInterop/IWebBrowser2.cs @@ -0,0 +1,152 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; + +namespace Greenshot.Base.IEInterop +{ + // IWebBrowser: EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B +// [ComVisible(true), ComImport(), Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"), +// TypeLibType(TypeLibTypeFlags.FDual), +// InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)] +// public interface IWebBrowser2 { +// [DispId(203)] +// object Document { +// [return: MarshalAs(UnmanagedType.IDispatch)] +// get; +// } +// } + [ComImport, /*SuppressUnmanagedCodeSecurity,*/ + TypeLibType(TypeLibTypeFlags.FOleAutomation | + TypeLibTypeFlags.FDual | + TypeLibTypeFlags.FHidden), + Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")] + public interface IWebBrowser2 + { + [DispId(100)] + void GoBack(); + + [DispId(0x65)] + void GoForward(); + + [DispId(0x66)] + void GoHome(); + + [DispId(0x67)] + void GoSearch(); + + [DispId(0x68)] + void Navigate([In] string Url, + [In] ref object flags, + [In] ref object targetFrameName, + [In] ref object postData, + [In] ref object headers); + + [DispId(-550)] + void Refresh(); + + [DispId(0x69)] + void Refresh2([In] ref object level); + + [DispId(0x6a)] + void Stop(); + + [DispId(200)] + object Application + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xc9)] + object Parent + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xca)] + object Container + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xcb)] + object Document + { + [return: + MarshalAs(UnmanagedType.IDispatch)] + get; + } + + [DispId(0xcc)] bool TopLevelContainer { get; } + [DispId(0xcd)] string Type { get; } + [DispId(0xce)] int Left { get; set; } + [DispId(0xcf)] int Top { get; set; } + [DispId(0xd0)] int Width { get; set; } + [DispId(0xd1)] int Height { get; set; } + [DispId(210)] string LocationName { get; } + [DispId(0xd3)] string LocationURL { get; } + [DispId(0xd4)] bool Busy { get; } + + [DispId(300)] + void Quit(); + + [DispId(0x12d)] + void ClientToWindow(out int pcx, out int pcy); + + [DispId(0x12e)] + void PutProperty([In] string property, [In] object vtValue); + + [DispId(0x12f)] + object GetProperty([In] string property); + + [DispId(0)] string Name { get; } + [DispId(-515)] int HWND { get; } + [DispId(400)] string FullName { get; } + [DispId(0x191)] string Path { get; } + [DispId(0x192)] bool Visible { get; set; } + [DispId(0x193)] bool StatusBar { get; set; } + [DispId(0x194)] string StatusText { get; set; } + [DispId(0x195)] int ToolBar { get; set; } + [DispId(0x196)] bool MenuBar { get; set; } + [DispId(0x197)] bool FullScreen { get; set; } + + [DispId(500)] + void Navigate2([In] ref object URL, + [In] ref object flags, + [In] ref object targetFrameName, + [In] ref object postData, + [In] ref object headers); + + [DispId(550)] bool Offline { get; set; } + [DispId(0x227)] bool Silent { get; set; } + [DispId(0x228)] bool RegisterAsBrowser { get; set; } + [DispId(0x229)] bool RegisterAsDropTarget { get; set; } + [DispId(0x22a)] bool TheaterMode { get; set; } + [DispId(0x22b)] bool AddressBar { get; set; } + [DispId(0x22c)] bool Resizable { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/IniFile/IniAttributes.cs b/src/Greenshot.Base/IniFile/IniAttributes.cs new file mode 100644 index 000000000..4563a406b --- /dev/null +++ b/src/Greenshot.Base/IniFile/IniAttributes.cs @@ -0,0 +1,71 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.IniFile +{ + /// + /// Attribute for telling that this class is linked to a section in the ini-configuration + /// + [AttributeUsage(AttributeTargets.Class)] + public class IniSectionAttribute : Attribute + { + public IniSectionAttribute(string name) + { + Name = name; + } + + public string Description; + public string Name { get; set; } + } + + /// + /// Attribute for telling that a field is linked to a property in the ini-configuration selection + /// + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class IniPropertyAttribute : Attribute + { + public IniPropertyAttribute() + { + Separator = ","; + } + + public IniPropertyAttribute(string name) : this() + { + Name = name; + } + + public string Description { get; set; } + public string Separator { get; set; } + public string DefaultValue { get; set; } + + public string LanguageKey { get; set; } + + // If Encrypted is set to true, the value will be decrypted on load and encrypted on save + public bool Encrypted { get; set; } + public bool FixedValue { get; set; } + public bool Expert { get; set; } + public bool ExcludeIfNull { get; set; } + + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/IniFile/IniConfig.cs b/src/Greenshot.Base/IniFile/IniConfig.cs new file mode 100644 index 000000000..57bc8f55e --- /dev/null +++ b/src/Greenshot.Base/IniFile/IniConfig.cs @@ -0,0 +1,574 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using System.Threading; +using log4net; + +namespace Greenshot.Base.IniFile +{ + public class IniConfig + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IniConfig)); + private const string IniExtension = ".ini"; + private const string DefaultsPostfix = "-defaults"; + private const string FixedPostfix = "-fixed"; + + /// + /// A lock object for the ini file saving + /// + private static readonly object IniLock = new object(); + + /// + /// As the ini implementation is kept someone generic, for reusing, this holds the name of the application + /// + private static string _applicationName; + + /// + /// As the ini implementation is kept someone generic, for reusing, this holds the name of the configuration + /// + private static string _configName; + + /// + /// A Dictionary with all the sections stored by section name + /// + private static readonly IDictionary SectionMap = new Dictionary(); + + /// + /// A Dictionary with the properties for a section stored by section name + /// + private static IDictionary> _sections = new Dictionary>(); + + /// + /// A Dictionary with the fixed-properties for a section stored by section name + /// + private static IDictionary> _fixedProperties; + + /// + /// Stores if we checked for portable + /// + private static bool _portableCheckMade; + + /// + /// Is the configuration portable (meaning we don't store it in the AppData directory) + /// + public static bool IsPortable { get; private set; } + + /// + /// Config directory when set from external + /// + public static string IniDirectory { get; set; } + + /// + /// Initialize the ini config + /// + /// + /// + public static void Init(string appName, string configName) + { + _applicationName = appName; + _configName = configName; + Reload(); + } + + /// + /// Checks if we initialized the ini + /// + public static bool IsInitialized => _applicationName != null && _configName != null && SectionMap.Count > 0; + + /// + /// This forces the ini to be stored in the startup path, used for portable applications + /// + public static void ForceIniInStartupPath() + { + if (_portableCheckMade) + { + throw new Exception("ForceLocal should be called before any file is read"); + } + + IsPortable = false; + _portableCheckMade = true; + string applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + if (_applicationName == null || _configName == null) + { + Init(); + } + + if (applicationStartupPath == null) + { + return; + } + + string forcedIni = Path.Combine(applicationStartupPath, _applicationName + IniExtension); + if (!File.Exists(forcedIni)) + { + using (File.Create(forcedIni)) + { + } + } + } + + /// + /// Default init + /// + public static void Init() + { + AssemblyProductAttribute[] assemblyProductAttributes = + Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false) as AssemblyProductAttribute[]; + if (assemblyProductAttributes != null && assemblyProductAttributes.Length > 0) + { + string productName = assemblyProductAttributes[0].Product; + Log.InfoFormat("Using ProductName {0}", productName); + Init(productName, productName); + } + else + { + throw new InvalidOperationException("Assembly ProductName not set."); + } + } + + /// + /// Get the location of the configuration + /// + public static string ConfigLocation + { + get + { + if (IsInitialized) + { + return CreateIniLocation(_configName + IniExtension, false); + } + + throw new InvalidOperationException("Ini configuration was not initialized!"); + } + } + + /// + /// Create the location of the configuration file + /// + private static string CreateIniLocation(string configFilename, bool isReadOnly) + { + if (_applicationName == null || _configName == null) + { + throw new InvalidOperationException("IniConfig.Init not called!"); + } + + string iniFilePath = null; + + // Check if a Ini-Directory was supplied, and it's valid, use this before any others. + try + { + if (IniDirectory != null && Directory.Exists(IniDirectory)) + { + // If the greenshot.ini is requested, use the supplied directory even if empty + if (!isReadOnly) + { + return Path.Combine(IniDirectory, configFilename); + } + + iniFilePath = Path.Combine(IniDirectory, configFilename); + if (File.Exists(iniFilePath)) + { + return iniFilePath; + } + + iniFilePath = null; + } + } + catch (Exception exception) + { + Log.WarnFormat("The ini-directory {0} can't be used due to: {1}", IniDirectory, exception.Message); + } + + string applicationStartupPath; + try + { + applicationStartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + } + catch (Exception exception) + { + Log.WarnFormat("Problem retrieving the AssemblyLocation: {0} (Designer mode?)", exception.Message); + applicationStartupPath = @"."; + } + + if (applicationStartupPath != null) + { + string pafPath = Path.Combine(applicationStartupPath, @"App\" + _applicationName); + + if (IsPortable || !_portableCheckMade) + { + if (!IsPortable) + { + Log.Info("Checking for portable mode."); + _portableCheckMade = true; + if (Directory.Exists(pafPath)) + { + IsPortable = true; + Log.Info("Portable mode active!"); + } + } + + if (IsPortable) + { + string pafConfigPath = Path.Combine(applicationStartupPath, @"Data\Settings"); + try + { + if (!Directory.Exists(pafConfigPath)) + { + Directory.CreateDirectory(pafConfigPath); + } + + iniFilePath = Path.Combine(pafConfigPath, configFilename); + } + catch (Exception e) + { + Log.InfoFormat("Portable mode NOT possible, couldn't create directory '{0}'! Reason: {1}", pafConfigPath, e.Message); + } + } + } + } + + if (iniFilePath == null) + { + // check if file is in the same location as started from, if this is the case + // we will use this file instead of the ApplicationData folder + // Done for Feature Request #2741508 + if (applicationStartupPath != null) + { + iniFilePath = Path.Combine(applicationStartupPath, configFilename); + } + + if (!File.Exists(iniFilePath)) + { + string iniDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), _applicationName); + if (!Directory.Exists(iniDirectory)) + { + Directory.CreateDirectory(iniDirectory); + } + + iniFilePath = Path.Combine(iniDirectory, configFilename); + } + } + + Log.InfoFormat("Using ini file {0}", iniFilePath); + return iniFilePath; + } + + /// + /// Reload the Ini file + /// + public static void Reload() + { + // Clear the current properties + _sections = new Dictionary>(); + // Load the defaults + Read(CreateIniLocation(_configName + DefaultsPostfix + IniExtension, true)); + // Load the normal + Read(CreateIniLocation(_configName + IniExtension, false)); + // Load the fixed settings + _fixedProperties = Read(CreateIniLocation(_configName + FixedPostfix + IniExtension, true)); + + foreach (IniSection section in SectionMap.Values) + { + try + { + section.Fill(PropertiesForSection(section)); + FixProperties(section); + } + catch (Exception ex) + { + string sectionName = "unknown"; + if (section?.IniSectionAttribute?.Name != null) + { + sectionName = section.IniSectionAttribute.Name; + } + + Log.WarnFormat("Problem reading the ini section {0}", sectionName); + Log.Warn("Exception", ex); + } + } + } + + /// + /// This "fixes" the properties of the section, meaning any properties in the fixed file can't be changed. + /// + /// IniSection + private static void FixProperties(IniSection section) + { + // Make properties unchangeable + if (_fixedProperties == null) + { + return; + } + + if (!_fixedProperties.TryGetValue(section.IniSectionAttribute.Name, out var fixedPropertiesForSection)) + { + return; + } + + foreach (string fixedPropertyKey in fixedPropertiesForSection.Keys) + { + if (section.Values.ContainsKey(fixedPropertyKey)) + { + section.Values[fixedPropertyKey].IsFixed = true; + } + } + } + + /// + /// Read the ini file into the Dictionary + /// + /// Path & Filename of ini file + private static IDictionary> Read(string iniLocation) + { + if (!File.Exists(iniLocation)) + { + Log.Info("Can't find file: " + iniLocation); + return null; + } + + Log.InfoFormat("Loading ini-file: {0}", iniLocation); + //LOG.Info("Reading ini-properties from file: " + iniLocation); + var newSections = IniReader.Read(iniLocation, Encoding.UTF8); + // Merge the newly loaded properties to the already available + foreach (string section in newSections.Keys) + { + IDictionary newProperties = newSections[section]; + if (!_sections.ContainsKey(section)) + { + // This section is not yet loaded, simply add the complete section + _sections.Add(section, newProperties); + } + else + { + // Overwrite or add every property from the newly loaded section to the available one + var currentProperties = _sections[section]; + foreach (string propertyName in newProperties.Keys) + { + string propertyValue = newProperties[propertyName]; + if (currentProperties.ContainsKey(propertyName)) + { + // Override current value as we are loading in a certain order which insures the default, current and fixed + currentProperties[propertyName] = propertyValue; + } + else + { + // Add "new" value + currentProperties.Add(propertyName, propertyValue); + } + } + } + } + + return newSections; + } + + public static IEnumerable IniSectionNames + { + get + { + foreach (string sectionName in SectionMap.Keys) + { + yield return sectionName; + } + } + } + + /// + /// Method used for internal tricks... + /// + /// + /// + public static IniSection GetIniSection(string sectionName) + { + SectionMap.TryGetValue(sectionName, out var returnValue); + return returnValue; + } + + /// + /// A generic method which returns an instance of the supplied type, filled with it's configuration + /// + /// IniSection Type to get the configuration for + /// Filled instance of IniSection type which was supplied + public static T GetIniSection() where T : IniSection + { + return GetIniSection(true); + } + + /// + /// + /// + /// IniSection Type to get the configuration for + /// false to skip saving + /// IniSection + public static T GetIniSection(bool allowSave) where T : IniSection + { + T section; + + Type iniSectionType = typeof(T); + string sectionName = IniSection.GetIniSectionAttribute(iniSectionType).Name; + if (SectionMap.ContainsKey(sectionName)) + { + //LOG.Debug("Returning pre-mapped section " + sectionName); + section = (T) SectionMap[sectionName]; + } + else + { + // Create instance of this type + section = (T) Activator.CreateInstance(iniSectionType); + + // Store for later save & retrieval + SectionMap.Add(sectionName, section); + section.Fill(PropertiesForSection(section)); + FixProperties(section); + } + + if (allowSave && section.IsDirty) + { + Log.DebugFormat("Section {0} is marked dirty, saving!", sectionName); + Save(); + } + + return section; + } + + /// + /// Get the raw properties for a section + /// + /// + /// + public static IDictionary PropertiesForSection(IniSection section) + { + string sectionName = section.IniSectionAttribute.Name; + // Get the properties for the section + IDictionary properties; + if (_sections.ContainsKey(sectionName)) + { + properties = _sections[sectionName]; + } + else + { + _sections.Add(sectionName, new Dictionary()); + properties = _sections[sectionName]; + } + + return properties; + } + + /// + /// Save the ini file + /// + public static void Save() + { + bool acquiredLock = false; + try + { + acquiredLock = Monitor.TryEnter(IniLock, TimeSpan.FromMilliseconds(200)); + if (acquiredLock) + { + // Code that accesses resources that are protected by the lock. + string iniLocation = CreateIniLocation(_configName + IniExtension, false); + try + { + SaveInternally(iniLocation); + } + catch (Exception ex) + { + Log.Error("A problem occured while writing the configuration file to: " + iniLocation); + Log.Error(ex); + } + } + else + { + // Code to deal with the fact that the lock was not acquired. + Log.Warn("A second thread tried to save the ini-file, we blocked as the first took too long."); + } + } + finally + { + if (acquiredLock) + { + Monitor.Exit(IniLock); + } + } + } + + /// + /// The real save implementation + /// + /// + private static void SaveInternally(string iniLocation) + { + Log.Info("Saving configuration to: " + iniLocation); + var iniPath = Path.GetDirectoryName(iniLocation); + if (iniPath != null && !Directory.Exists(iniPath)) + { + Directory.CreateDirectory(iniPath); + } + + using var memoryStream = new MemoryStream(); + using TextWriter writer = new StreamWriter(memoryStream, Encoding.UTF8); + foreach (var section in SectionMap.Values) + { + section.Write(writer, false); + // Add empty line after section + writer.WriteLine(); + section.IsDirty = false; + } + + writer.WriteLine(); + // Write left over properties + foreach (string sectionName in _sections.Keys) + { + // Check if the section is one that is "registered", if so skip it! + if (SectionMap.ContainsKey(sectionName)) + { + continue; + } + + writer.WriteLine("; The section {0} hasn't been 'claimed' since the last start of Greenshot, therefor it doesn't have additional information here!", sectionName); + writer.WriteLine( + "; The reason could be that the section {0} just hasn't been used, a plugin has an error and can't claim it or maybe the whole section {0} is obsolete.", + sectionName); + // Write section name + writer.WriteLine("[{0}]", sectionName); + var properties = _sections[sectionName]; + // Loop and write properties + foreach (string propertyName in properties.Keys) + { + writer.WriteLine("{0}={1}", propertyName, properties[propertyName]); + } + + writer.WriteLine(); + } + + // Don't forget to flush the buffer + writer.Flush(); + // Now write the created .ini string to the real file + using FileStream fileStream = new FileStream(iniLocation, FileMode.Create, FileAccess.Write); + memoryStream.WriteTo(fileStream); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/IniFile/IniReader.cs b/src/Greenshot.Base/IniFile/IniReader.cs similarity index 59% rename from GreenshotPlugin/IniFile/IniReader.cs rename to src/Greenshot.Base/IniFile/IniReader.cs index 641b5414e..e9db1787c 100644 --- a/GreenshotPlugin/IniFile/IniReader.cs +++ b/src/Greenshot.Base/IniFile/IniReader.cs @@ -1,85 +1,104 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace GreenshotPlugin.IniFile { - /// - /// The IniReader does exactly what it says, it reads the .ini file - /// - public static class IniReader { - private const char SectionStartToken = '['; - private const char SectionEndToken = ']'; - private const char CommentToken = ';'; - private static readonly char[] Assignment = { '=' }; - - /// - /// Read an ini file to a Dictionary, each key is a section and the value is a Dictionary with name and values. - /// - /// - /// - /// - public static IDictionary> Read(string path, Encoding encoding) { - var ini = new Dictionary>(); - using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024)) - { - using var streamReader = new StreamReader(fileStream, encoding); - IDictionary nameValues = new Dictionary(); - while (!streamReader.EndOfStream) { - string line = streamReader.ReadLine(); - if (line == null) - { - continue; - } - string cleanLine = line.Trim(); - if (cleanLine.Length == 0 || cleanLine[0] == CommentToken) { - continue; - } - if (cleanLine[0] == SectionStartToken) { - var sectionEndIndex = line.IndexOf(SectionEndToken,1); - if (sectionEndIndex <0) - { - continue; - } - string section = line.Substring(1,sectionEndIndex-1).Trim(); - if (!ini.TryGetValue(section, out nameValues)) - { - nameValues = new Dictionary(); - ini.Add(section, nameValues); - } - } else { - string[] keyvalueSplitter = line.Split(Assignment, 2); - string name = keyvalueSplitter[0]; - string inivalue = keyvalueSplitter.Length > 1 ? keyvalueSplitter[1] : null; - if (nameValues.ContainsKey(name)) { - nameValues[name] = inivalue; - } else { - nameValues.Add(name, inivalue); - } - } - } - } - return ini; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Greenshot.Base.IniFile +{ + /// + /// The IniReader does exactly what it says, it reads the .ini file + /// + public static class IniReader + { + private const char SectionStartToken = '['; + private const char SectionEndToken = ']'; + private const char CommentToken = ';'; + + private static readonly char[] Assignment = + { + '=' + }; + + /// + /// Read an ini file to a Dictionary, each key is a section and the value is a Dictionary with name and values. + /// + /// + /// + /// + public static IDictionary> Read(string path, Encoding encoding) + { + var ini = new Dictionary>(); + using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 1024)) + { + using var streamReader = new StreamReader(fileStream, encoding); + IDictionary nameValues = new Dictionary(); + while (!streamReader.EndOfStream) + { + string line = streamReader.ReadLine(); + if (line == null) + { + continue; + } + + string cleanLine = line.Trim(); + if (cleanLine.Length == 0 || cleanLine[0] == CommentToken) + { + continue; + } + + if (cleanLine[0] == SectionStartToken) + { + var sectionEndIndex = line.IndexOf(SectionEndToken, 1); + if (sectionEndIndex < 0) + { + continue; + } + + string section = line.Substring(1, sectionEndIndex - 1).Trim(); + if (!ini.TryGetValue(section, out nameValues)) + { + nameValues = new Dictionary(); + ini.Add(section, nameValues); + } + } + else + { + string[] keyvalueSplitter = line.Split(Assignment, 2); + string name = keyvalueSplitter[0]; + string inivalue = keyvalueSplitter.Length > 1 ? keyvalueSplitter[1] : null; + if (nameValues.ContainsKey(name)) + { + nameValues[name] = inivalue; + } + else + { + nameValues.Add(name, inivalue); + } + } + } + } + + return ini; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/IniFile/IniSection.cs b/src/Greenshot.Base/IniFile/IniSection.cs new file mode 100644 index 000000000..813534c13 --- /dev/null +++ b/src/Greenshot.Base/IniFile/IniSection.cs @@ -0,0 +1,235 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using Greenshot.Base.Core; +using log4net; + +namespace Greenshot.Base.IniFile +{ + /// + /// Base class for all IniSections + /// + [Serializable] + public abstract class IniSection + { + protected static ILog LOG = LogManager.GetLogger(typeof(IniSection)); + + [NonSerialized] private readonly IDictionary values = new Dictionary(); + [NonSerialized] private IniSectionAttribute iniSectionAttribute; + + public IniSectionAttribute IniSectionAttribute + { + get + { + if (iniSectionAttribute == null) + { + iniSectionAttribute = GetIniSectionAttribute(GetType()); + } + + return iniSectionAttribute; + } + } + + /// + /// Get the dictionary with all the IniValues + /// + public IDictionary Values + { + get { return values; } + } + + /// + /// Flag to specify if values have been changed + /// + public bool IsDirty { get; set; } + + /// + /// Supply values we can't put as defaults + /// + /// The property to return a default for + /// object with the default value for the supplied property + public virtual object GetDefault(string property) + { + return null; + } + + /// + /// This method will be called before converting the property, making to possible to correct a certain value + /// Can be used when migration is needed + /// + /// The name of the property + /// The string value of the property + /// string with the propertyValue, modified or not... + public virtual string PreCheckValue(string propertyName, string propertyValue) + { + return propertyValue; + } + + /// + /// This method will be called after reading the configuration, so eventually some corrections can be made + /// + public virtual void AfterLoad() + { + } + + /// + /// This will be called before saving the Section, so we can encrypt passwords etc... + /// + public virtual void BeforeSave() + { + } + + /// + /// This will be called before saving the Section, so we can decrypt passwords etc... + /// + public virtual void AfterSave() + { + } + + /// + /// Helper method to get the IniSectionAttribute of a type + /// + /// + /// + public static IniSectionAttribute GetIniSectionAttribute(Type iniSectionType) + { + Attribute[] classAttributes = Attribute.GetCustomAttributes(iniSectionType); + foreach (Attribute attribute in classAttributes) + { + if (attribute is IniSectionAttribute) + { + return (IniSectionAttribute) attribute; + } + } + + return null; + } + + /// + /// Fill the section with the supplied properties + /// + /// + public void Fill(IDictionary properties) + { + Type iniSectionType = GetType(); + + // Iterate over the members and create IniValueContainers + foreach (FieldInfo fieldInfo in iniSectionType.GetFields()) + { + if (Attribute.IsDefined(fieldInfo, typeof(IniPropertyAttribute))) + { + IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute) fieldInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; + if (!Values.ContainsKey(iniPropertyAttribute.Name)) + { + Values.Add(iniPropertyAttribute.Name, new IniValue(this, fieldInfo, iniPropertyAttribute)); + } + } + } + + foreach (PropertyInfo propertyInfo in iniSectionType.GetProperties()) + { + if (Attribute.IsDefined(propertyInfo, typeof(IniPropertyAttribute))) + { + if (!Values.ContainsKey(propertyInfo.Name)) + { + IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute) propertyInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; + Values.Add(iniPropertyAttribute.Name, new IniValue(this, propertyInfo, iniPropertyAttribute)); + } + } + } + + foreach (string fieldName in Values.Keys) + { + IniValue iniValue = Values[fieldName]; + try + { + iniValue.SetValueFromProperties(properties); + if (iniValue.Attributes.Encrypted) + { + if (iniValue.Value is string stringValue && stringValue.Length > 2) + { + iniValue.Value = stringValue.Decrypt(); + } + } + } + catch (Exception ex) + { + LOG.Error(ex); + } + } + + AfterLoad(); + } + + /// + /// Write the section to the writer + /// + /// + /// + public void Write(TextWriter writer, bool onlyProperties) + { + if (IniSectionAttribute == null) + { + throw new ArgumentException("Section didn't implement the IniSectionAttribute"); + } + + BeforeSave(); + try + { + if (!onlyProperties) + { + writer.WriteLine("; {0}", IniSectionAttribute.Description); + } + + writer.WriteLine("[{0}]", IniSectionAttribute.Name); + + foreach (IniValue value in Values.Values) + { + if (value.Attributes.Encrypted) + { + if (value.Value is string stringValue && stringValue.Length > 2) + { + value.Value = stringValue.Encrypt(); + } + } + + // Write the value + value.Write(writer, onlyProperties); + if (value.Attributes.Encrypted) + { + if (value.Value is string stringValue && stringValue.Length > 2) + { + value.Value = stringValue.Decrypt(); + } + } + } + } + finally + { + AfterSave(); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/IniFile/IniValue.cs b/src/Greenshot.Base/IniFile/IniValue.cs new file mode 100644 index 000000000..312ce25be --- /dev/null +++ b/src/Greenshot.Base/IniFile/IniValue.cs @@ -0,0 +1,621 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Reflection; +using System.Text; +using log4net; + +namespace Greenshot.Base.IniFile +{ + /// + /// A container to be able to pass the value from a IniSection around. + /// + public class IniValue + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IniValue)); + private readonly PropertyInfo _propertyInfo; + private readonly FieldInfo _fieldInfo; + private readonly IniSection _containingIniSection; + private readonly IniPropertyAttribute _attributes; + + public IniValue(IniSection containingIniSection, PropertyInfo propertyInfo, IniPropertyAttribute iniPropertyAttribute) + { + _containingIniSection = containingIniSection; + _propertyInfo = propertyInfo; + _attributes = iniPropertyAttribute; + } + + public IniValue(IniSection containingIniSection, FieldInfo fieldInfo, IniPropertyAttribute iniPropertyAttribute) + { + _containingIniSection = containingIniSection; + _fieldInfo = fieldInfo; + _attributes = iniPropertyAttribute; + } + + /// + /// Return true when the value is fixed + /// + public bool IsFixed + { + get + { + if (_attributes != null) + { + return _attributes.FixedValue; + } + + return false; + } + set + { + if (_attributes != null) + { + _attributes.FixedValue = value; + } + } + } + + /// + /// Return true when the value is for experts + /// + public bool IsExpert + { + get + { + if (_attributes != null) + { + return _attributes.Expert; + } + + return false; + } + set + { + if (_attributes != null) + { + _attributes.Expert = value; + } + } + } + + + /// + /// Return true when the value is can be changed by the GUI + /// + public bool IsEditable => !IsFixed; + + /// + /// Return true when the value is visible in the GUI + /// + public bool IsVisible => !IsExpert; + + public MemberInfo MemberInfo + { + get + { + if (_propertyInfo == null) + { + return _fieldInfo; + } + + return _propertyInfo; + } + } + + /// + /// Returns the IniSection this value is contained in + /// + public IniSection ContainingIniSection => _containingIniSection; + + /// + /// Get the in the ini file defined attributes + /// + public IniPropertyAttribute Attributes => _attributes; + + /// + /// Get the value for this IniValue + /// + public object Value + { + get + { + if (_propertyInfo == null) + { + return _fieldInfo.GetValue(_containingIniSection); + } + + return _propertyInfo.GetValue(_containingIniSection, null); + } + set + { + if (_propertyInfo == null) + { + _fieldInfo.SetValue(_containingIniSection, value); + } + else + { + _propertyInfo.SetValue(_containingIniSection, value, null); + } + } + } + + /// + /// Get the Type of the value + /// + public Type ValueType + { + get + { + var valueType = _propertyInfo?.PropertyType ?? _fieldInfo.FieldType; + if (!valueType.IsGenericType) + { + return valueType; + } + + var genericTypeDefinition = valueType.GetGenericTypeDefinition(); + if (genericTypeDefinition != null && genericTypeDefinition == typeof(Nullable<>)) + { + // We are dealing with a generic type that is nullable + valueType = Nullable.GetUnderlyingType(valueType); + } + + return valueType; + } + } + + /// + /// Write the value to the text writer + /// + /// TextWriter to write to + /// true if we do not want the comment + public void Write(TextWriter writer, bool onlyProperties) + { + object myValue = Value; + Type valueType = ValueType; + if (myValue == null) + { + if (_attributes.ExcludeIfNull) + { + return; + } + + if (_attributes.DefaultValue != null) + { + myValue = _attributes.DefaultValue; + valueType = typeof(string); + } + else + { + myValue = _containingIniSection.GetDefault(_attributes.Name); + if (myValue != null) + { + valueType = myValue.GetType(); + } + } + } + + if (myValue == null) + { + if (_attributes.ExcludeIfNull) + { + return; + } + } + + if (!onlyProperties) + { + writer.WriteLine("; {0}", _attributes.Description); + } + + if (myValue == null) + { + writer.WriteLine("{0}=", _attributes.Name); + return; + } + + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // Handle dictionaries. + Type valueType1 = valueType.GetGenericArguments()[0]; + Type valueType2 = valueType.GetGenericArguments()[1]; + // Get the methods we need to deal with dictionaries. + var keys = valueType.GetProperty("Keys").GetValue(myValue, null); + var item = valueType.GetProperty("Item"); + var enumerator = keys.GetType().GetMethod("GetEnumerator").Invoke(keys, null); + var moveNext = enumerator.GetType().GetMethod("MoveNext"); + var current = enumerator.GetType().GetProperty("Current").GetGetMethod(); + // Get all the values. + while ((bool) moveNext.Invoke(enumerator, null)) + { + var key = current.Invoke(enumerator, null); + var valueObject = item.GetValue(myValue, new[] + { + key + }); + // Write to ini file! + writer.WriteLine("{0}.{1}={2}", _attributes.Name, ConvertValueToString(valueType1, key, _attributes.Separator), + ConvertValueToString(valueType2, valueObject, _attributes.Separator)); + } + } + else + { + writer.WriteLine("{0}={1}", _attributes.Name, ConvertValueToString(valueType, myValue, _attributes.Separator)); + } + } + + /// + /// Set the value to the value in the ini file, or default + /// + /// + public void SetValueFromProperties(IDictionary properties) + { + string propertyName = _attributes.Name; + string propertyValue = null; + if (properties.ContainsKey(propertyName) && properties[propertyName] != null) + { + propertyValue = _containingIniSection.PreCheckValue(propertyName, properties[propertyName]); + } + + UseValueOrDefault(propertyValue); + } + + /// + /// This method will set the ini value to the supplied value or use the default if non supplied + /// + /// + public void UseValueOrDefault(string propertyValue) + { + Type valueType = ValueType; + string propertyName = _attributes.Name; + string defaultValue = _attributes.DefaultValue; + bool defaultUsed = false; + object defaultValueFromConfig = _containingIniSection.GetDefault(propertyName); + + if (string.IsNullOrEmpty(propertyValue)) + { + if (defaultValue != null && defaultValue.Trim().Length != 0) + { + propertyValue = defaultValue; + defaultUsed = true; + } + else if (defaultValueFromConfig != null) + { + Log.DebugFormat("Default for Property {0} implemented!", propertyName); + } + else + { + if (_attributes.ExcludeIfNull) + { + Value = null; + return; + } + + Log.DebugFormat("Property {0} has no value or default value!", propertyName); + } + } + + // Now set the value + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + // Logic for Dictionary<,> + Type type1 = valueType.GetGenericArguments()[0]; + Type type2 = valueType.GetGenericArguments()[1]; + //LOG.Info(String.Format("Found Dictionary<{0},{1}>", type1.Name, type2.Name)); + object dictionary = Activator.CreateInstance(valueType); + MethodInfo addMethodInfo = valueType.GetMethod("Add"); + bool addedElements = false; + IDictionary properties = IniConfig.PropertiesForSection(_containingIniSection); + foreach (string key in properties.Keys) + { + if (key != null && key.StartsWith(propertyName + ".")) + { + // What "key" do we need to store it under? + string subPropertyName = key.Substring(propertyName.Length + 1); + string stringValue = properties[key]; + object newValue1 = null; + object newValue2 = null; + try + { + newValue1 = ConvertStringToValueType(type1, subPropertyName, _attributes.Separator); + } + catch (Exception ex) + { + Log.Warn(ex); + //LOG.Error("Problem converting " + subPropertyName + " to type " + type1.FullName, e); + } + + try + { + newValue2 = ConvertStringToValueType(type2, stringValue, _attributes.Separator); + } + catch (Exception ex) + { + Log.Warn(ex); + //LOG.Error("Problem converting " + stringValue + " to type " + type2.FullName, e); + } + + addMethodInfo.Invoke(dictionary, new[] + { + newValue1, newValue2 + }); + addedElements = true; + } + } + + // No need to return something that isn't filled! + if (addedElements) + { + Value = dictionary; + return; + } + + if (defaultValueFromConfig != null) + { + Value = defaultValueFromConfig; + return; + } + } + else if (!string.IsNullOrEmpty(propertyValue)) + { + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + // We are dealing with a generic type that is nullable + valueType = Nullable.GetUnderlyingType(valueType); + } + + object newValue; + try + { + newValue = ConvertStringToValueType(valueType, propertyValue, _attributes.Separator); + } + catch (Exception ex1) + { + newValue = null; + if (!defaultUsed) + { + try + { + Log.WarnFormat("Problem '{0}' while converting {1} to type {2} trying fallback...", ex1.Message, propertyValue, valueType.FullName); + newValue = ConvertStringToValueType(valueType, defaultValue, _attributes.Separator); + ContainingIniSection.IsDirty = true; + Log.InfoFormat("Used default value {0} for property {1}", defaultValue, propertyName); + } + catch (Exception ex2) + { + Log.Warn("Problem converting fallback value " + defaultValue + " to type " + valueType.FullName, ex2); + } + } + else + { + Log.Warn("Problem converting " + propertyValue + " to type " + valueType.FullName, ex1); + } + } + + Value = newValue; + return; + } + + // If nothing is set, we can use the default value from the config (if we habe one) + if (defaultValueFromConfig != null) + { + Value = defaultValueFromConfig; + return; + } + + if (ValueType != typeof(string)) + { + try + { + Value = Activator.CreateInstance(ValueType); + } + catch (Exception) + { + Log.WarnFormat("Couldn't create instance of {0} for {1}, using default value.", ValueType.FullName, _attributes.Name); + Value = default(ValueType); + } + } + else + { + Value = default(ValueType); + } + } + + /// + /// Convert a string to a value of type "valueType" + /// + /// Type to convert tp + /// string to convert from + /// + /// Value + private static object ConvertStringToValueType(Type valueType, string valueString, string separator) + { + if (valueString == null) + { + return null; + } + + if (valueType == typeof(string)) + { + return valueString; + } + + if (string.IsNullOrEmpty(valueString)) + { + return null; + } + + // The following makes the enum string values a bit less restrictive + if (valueType.IsEnum) + { + string searchingEnumString = valueString.Replace("_", string.Empty).ToLowerInvariant(); + foreach (var possibleValue in Enum.GetValues(valueType)) + { + var possibleString = possibleValue.ToString().Replace("_", string.Empty).ToLowerInvariant(); + if (possibleString.Equals(searchingEnumString)) + { + return possibleValue; + } + } + } + + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) + { + string arraySeparator = separator; + object list = Activator.CreateInstance(valueType); + // Logic for List<> + string[] arrayValues = valueString.Split(new[] + { + arraySeparator + }, StringSplitOptions.None); + if (arrayValues.Length == 0) + { + return list; + } + + MethodInfo addMethodInfo = valueType.GetMethod("Add"); + + foreach (string arrayValue in arrayValues) + { + if (!string.IsNullOrEmpty(arrayValue)) + { + object newValue = null; + try + { + newValue = ConvertStringToValueType(valueType.GetGenericArguments()[0], arrayValue, separator); + } + catch (Exception ex) + { + Log.Warn("Problem converting " + arrayValue + " to type " + valueType.FullName, ex); + } + + if (newValue != null) + { + addMethodInfo.Invoke(list, new[] + { + newValue + }); + } + } + } + + return list; + } + + //LOG.Debug("No convertor for " + fieldType.ToString()); + if (valueType == typeof(object) && valueString.Length > 0) + { + //LOG.Debug("Parsing: " + valueString); + string[] values = valueString.Split(':'); + //LOG.Debug("Type: " + values[0]); + //LOG.Debug("Value: " + values[1]); + Type fieldTypeForValue = Type.GetType(values[0], true); + //LOG.Debug("Type after GetType: " + fieldTypeForValue); + return ConvertStringToValueType(fieldTypeForValue, values[1], separator); + } + + TypeConverter converter = TypeDescriptor.GetConverter(valueType); + return converter.ConvertFromInvariantString(valueString); + } + + /// + /// Override of ToString which calls the ConvertValueToString + /// + /// string representation of this + public override string ToString() + { + return ConvertValueToString(ValueType, Value, _attributes.Separator); + } + + /// + /// Convert the supplied value to a string + /// + /// Type to convert + /// Value to convert + /// separator for lists + /// string representation of the value + private static string ConvertValueToString(Type valueType, object valueObject, string separator) + { + if (valueObject == null) + { + // If there is nothing, deliver nothing! + return string.Empty; + } + + if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(List<>)) + { + StringBuilder stringBuilder = new StringBuilder(); + Type specificValueType = valueType.GetGenericArguments()[0]; + int listCount = (int) valueType.GetProperty("Count").GetValue(valueObject, null); + // Loop though generic list + for (int index = 0; index < listCount; index++) + { + object item = valueType.GetMethod("get_Item").Invoke(valueObject, new object[] + { + index + }); + + // Now you have an instance of the item in the generic list + if (index < listCount - 1) + { + stringBuilder.AppendFormat("{0}{1}", ConvertValueToString(specificValueType, item, separator), separator); + } + else + { + stringBuilder.AppendFormat("{0}", ConvertValueToString(specificValueType, item, separator)); + } + } + + return stringBuilder.ToString(); + } + + if (valueType == typeof(object)) + { + // object to String, this is the hardest + // Format will be "FQTypename[,Assemblyname]:Value" + + // Get the type so we can call ourselves recursive + Type objectType = valueObject.GetType(); + + // Get the value as string + string ourValue = ConvertValueToString(objectType, valueObject, separator); + + // Get the valuetype as string + string valueTypeName = objectType.FullName; + // Find the assembly name and only append it if it's not already in the fqtypename (like System.Drawing) + string assemblyName = objectType.Assembly.FullName; + // correct assemblyName, this also has version information etc. + if (assemblyName.StartsWith("Green")) + { + assemblyName = assemblyName.Substring(0, assemblyName.IndexOf(',')); + } + + return $"{valueTypeName},{assemblyName}:{ourValue}"; + } + + TypeConverter converter = TypeDescriptor.GetConverter(valueType); + return converter.ConvertToInvariantString(valueObject); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/CaptureMode.cs b/src/Greenshot.Base/Interfaces/CaptureMode.cs similarity index 97% rename from GreenshotPlugin/Interfaces/CaptureMode.cs rename to src/Greenshot.Base/Interfaces/CaptureMode.cs index 8c9c9e268..f3a063673 100644 --- a/GreenshotPlugin/Interfaces/CaptureMode.cs +++ b/src/Greenshot.Base/Interfaces/CaptureMode.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { /// /// The capture mode for Greenshot @@ -36,6 +36,7 @@ namespace GreenshotPlugin.Interfaces File, IE, Import, + Text // Video }; diff --git a/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs b/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs new file mode 100644 index 000000000..cbfd004b4 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs @@ -0,0 +1,102 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + +namespace Greenshot.Base.Interfaces.Drawing.Adorners +{ + public interface IAdorner + { + /// + /// Returns if this adorner is active + /// + bool IsActive { get; } + + /// + /// These are the bounds of the adorner + /// + Rectangle Bounds { get; } + + /// + /// The current edit status, this is needed to locate the adorner to send events to + /// + EditStatus EditStatus { get; } + + /// + /// The owner of this adorner + /// + IDrawableContainer Owner { get; } + + /// + /// Is the current point "over" the Adorner? + /// If this is the case, the + /// + /// Point to test + /// true if so + bool HitTest(Point point); + + /// + /// Handle the MouseDown event + /// + /// + /// MouseEventArgs + void MouseDown(object sender, MouseEventArgs mouseEventArgs); + + /// + /// Handle the MouseUp event + /// + /// + /// MouseEventArgs + void MouseUp(object sender, MouseEventArgs mouseEventArgs); + + /// + /// Handle the MouseMove event + /// + /// + /// MouseEventArgs + void MouseMove(object sender, MouseEventArgs mouseEventArgs); + + /// + /// Gets the cursor that should be displayed for this behavior. + /// + Cursor Cursor { get; } + + /// + /// Draw the adorner + /// + /// PaintEventArgs + void Paint(PaintEventArgs paintEventArgs); + + /// + /// Called if the owner is transformed + /// + /// Matrix + void Transform(Matrix matrix); + + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// + void AdjustToDpi(uint dpi); + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Drawing/Container.cs b/src/Greenshot.Base/Interfaces/Drawing/Container.cs new file mode 100644 index 000000000..feebb4dfc --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Drawing/Container.cs @@ -0,0 +1,149 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using Greenshot.Base.Interfaces.Drawing.Adorners; + +namespace Greenshot.Base.Interfaces.Drawing +{ + public enum RenderMode + { + EDIT, + EXPORT + }; + + public enum EditStatus + { + UNDRAWN, + DRAWING, + MOVING, + RESIZING, + IDLE + }; + + public interface IDrawableContainer : INotifyPropertyChanged, IDisposable + { + ISurface Parent { get; set; } + bool Selected { get; set; } + + int Left { get; set; } + + int Top { get; set; } + + int Width { get; set; } + + int Height { get; set; } + + Point Location { get; } + + Size Size { get; } + + Rectangle Bounds { get; } + + Rectangle DrawingBounds { get; } + + void ApplyBounds(RectangleF newBounds); + + bool hasFilters { get; } + + EditStatus Status { get; set; } + void Invalidate(); + bool ClickableAt(int x, int y); + void MoveBy(int x, int y); + void Transform(Matrix matrix); + bool HandleMouseDown(int x, int y); + void HandleMouseUp(int x, int y); + bool HandleMouseMove(int x, int y); + bool InitContent(); + void MakeBoundsChangeUndoable(bool allowMerge); + EditStatus DefaultEditMode { get; } + + /// + /// Available adorners for the DrawableContainer + /// + IList Adorners { get; } + + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// uint + void AdjustToDpi(uint dpi); + } + + public interface IDrawableContainerList : IList, IDisposable + { + Guid ParentID { get; } + + bool Selected { get; set; } + + ISurface Parent { get; set; } + EditStatus Status { get; set; } + Rectangle DrawingBounds { get; } + void MakeBoundsChangeUndoable(bool allowMerge); + void Transform(Matrix matrix); + void MoveBy(int dx, int dy); + bool ClickableAt(int x, int y); + IDrawableContainer ClickableElementAt(int x, int y); + void OnDoubleClick(); + bool HasIntersectingFilters(Rectangle clipRectangle); + bool IntersectsWith(Rectangle clipRectangle); + void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle); + void Invalidate(); + void PullElementsToTop(IDrawableContainerList elements); + bool CanPushDown(IDrawableContainerList elements); + void PullElementsUp(IDrawableContainerList elements); + bool CanPullUp(IDrawableContainerList elements); + void PushElementsDown(IDrawableContainerList elements); + void PushElementsToBottom(IDrawableContainerList elements); + void ShowContextMenu(MouseEventArgs e, ISurface surface); + void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e); + void AdjustToDpi(uint dpi); + } + + public interface ITextContainer : IDrawableContainer + { + string Text { get; set; } + void FitToText(); + } + + public interface IImageContainer : IDrawableContainer + { + Image Image { get; set; } + void Load(string filename); + } + + public interface ICursorContainer : IDrawableContainer + { + Cursor Cursor { get; set; } + void Load(string filename); + } + + public interface IIconContainer : IDrawableContainer + { + Icon Icon { get; set; } + void Load(string filename); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/Drawing/IField.cs b/src/Greenshot.Base/Interfaces/Drawing/IField.cs similarity index 50% rename from GreenshotPlugin/Interfaces/Drawing/IField.cs rename to src/Greenshot.Base/Interfaces/Drawing/IField.cs index 97c13c2d9..a848fa7d7 100644 --- a/GreenshotPlugin/Interfaces/Drawing/IField.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IField.cs @@ -1,85 +1,65 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.ComponentModel; - -namespace GreenshotPlugin.Interfaces.Drawing -{ - [Flags] - public enum FieldFlag - { - NONE = 0, - CONFIRMABLE = 1, - COUNTER = 2 - } - public interface IFieldType - { - string Name - { - get; - set; - } - } - - public interface IField : INotifyPropertyChanged - { - object Value - { - get; - set; - } - IFieldType FieldType - { - get; - set; - } - string Scope - { - get; - set; - } - bool HasValue - { - get; - } - } - /// - /// EventHandler to be used when a field value changes - /// - public delegate void FieldChangedEventHandler(object sender, FieldChangedEventArgs e); - - /// - /// EventArgs to be used with FieldChangedEventHandler - /// - public class FieldChangedEventArgs : EventArgs - { - public IField Field - { - get; - private set; - } - public FieldChangedEventArgs(IField field) - { - Field = field; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; + +namespace Greenshot.Base.Interfaces.Drawing +{ + [Flags] + public enum FieldFlag + { + NONE = 0, + CONFIRMABLE = 1, + COUNTER = 2 + } + + public interface IFieldType + { + string Name { get; set; } + } + + public interface IField : INotifyPropertyChanged + { + object Value { get; set; } + IFieldType FieldType { get; set; } + string Scope { get; set; } + bool HasValue { get; } + } + + /// + /// EventHandler to be used when a field value changes + /// + public delegate void FieldChangedEventHandler(object sender, FieldChangedEventArgs e); + + /// + /// EventArgs to be used with FieldChangedEventHandler + /// + public class FieldChangedEventArgs : EventArgs + { + public IField Field { get; private set; } + + public FieldChangedEventArgs(IField field) + { + Field = field; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs b/src/Greenshot.Base/Interfaces/Drawing/IFieldholder.cs similarity index 63% rename from GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs rename to src/Greenshot.Base/Interfaces/Drawing/IFieldholder.cs index df0f779d5..7d2a11adb 100644 --- a/GreenshotPlugin/Interfaces/Drawing/IFieldholder.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IFieldholder.cs @@ -1,39 +1,39 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace GreenshotPlugin.Interfaces.Drawing -{ - /// - /// Any element holding Fields must provide access to it. - /// AbstractFieldHolder is the basic implementation. - /// If you need the fieldHolder to have child fieldHolders, - /// you should consider using IFieldHolderWithChildren. - /// - public interface IFieldHolder - { - event FieldChangedEventHandler FieldChanged; - IList GetFields(); - IField GetField(IFieldType fieldType); - bool HasField(IFieldType fieldType); - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; + +namespace Greenshot.Base.Interfaces.Drawing +{ + /// + /// Any element holding Fields must provide access to it. + /// AbstractFieldHolder is the basic implementation. + /// If you need the fieldHolder to have child fieldHolders, + /// you should consider using IFieldHolderWithChildren. + /// + public interface IFieldHolder + { + event FieldChangedEventHandler FieldChanged; + IList GetFields(); + IField GetField(IFieldType fieldType); + bool HasField(IFieldType fieldType); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/Drawing/IMemento.cs b/src/Greenshot.Base/Interfaces/Drawing/IMemento.cs similarity index 57% rename from GreenshotPlugin/Interfaces/Drawing/IMemento.cs rename to src/Greenshot.Base/Interfaces/Drawing/IMemento.cs index bb64237fe..1d8e425c4 100644 --- a/GreenshotPlugin/Interfaces/Drawing/IMemento.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IMemento.cs @@ -1,44 +1,46 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.Interfaces.Drawing { - /// - /// Description of IMemento. - /// - public interface IMemento : IDisposable { - /// - /// Restores target to the state memorized by this memento. - /// - /// - /// A memento of the state before restoring - /// - IMemento Restore(); - - /// - /// Try to merge the current memento with another, preventing loads of items on the stack - /// - /// The memento to try to merge with - /// - bool Merge(IMemento other); - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Interfaces.Drawing +{ + /// + /// Description of IMemento. + /// + public interface IMemento : IDisposable + { + /// + /// Restores target to the state memorized by this memento. + /// + /// + /// A memento of the state before restoring + /// + IMemento Restore(); + + /// + /// Try to merge the current memento with another, preventing loads of items on the stack + /// + /// The memento to try to merge with + /// + bool Merge(IMemento other); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/DrawingModes.cs b/src/Greenshot.Base/Interfaces/DrawingModes.cs similarity index 96% rename from GreenshotPlugin/Interfaces/DrawingModes.cs rename to src/Greenshot.Base/Interfaces/DrawingModes.cs index e6d25a359..cc5e91607 100644 --- a/GreenshotPlugin/Interfaces/DrawingModes.cs +++ b/src/Greenshot.Base/Interfaces/DrawingModes.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public enum DrawingModes { diff --git a/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs b/src/Greenshot.Base/Interfaces/Forms/ImageEditor.cs similarity index 57% rename from GreenshotPlugin/Interfaces/Forms/ImageEditor.cs rename to src/Greenshot.Base/Interfaces/Forms/ImageEditor.cs index 808951234..617a469de 100644 --- a/GreenshotPlugin/Interfaces/Forms/ImageEditor.cs +++ b/src/Greenshot.Base/Interfaces/Forms/ImageEditor.cs @@ -1,49 +1,46 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; - -namespace GreenshotPlugin.Interfaces.Forms { - /// - /// The IImageEditor is the Interface that the Greenshot ImageEditor has to implement - /// - public interface IImageEditor { - /// - /// Get the current Image from the Editor for Exporting (save/upload etc) - /// This is actually a wrapper which calls Surface.GetImageForExport(). - /// Don't forget to call image.Dispose() when finished!!! - /// - /// Bitmap - Image GetImageForExport(); - - /// - /// Make the ICaptureDetails from the current Surface in the EditorForm available. - /// - ICaptureDetails CaptureDetails { - get; - } - - ISurface Surface { - get; - set; - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; + +namespace Greenshot.Base.Interfaces.Forms +{ + /// + /// The IImageEditor is the Interface that the Greenshot ImageEditor has to implement + /// + public interface IImageEditor + { + /// + /// Get the current Image from the Editor for Exporting (save/upload etc) + /// This is actually a wrapper which calls Surface.GetImageForExport(). + /// Don't forget to call image.Dispose() when finished!!! + /// + /// Bitmap + Image GetImageForExport(); + + /// + /// Make the ICaptureDetails from the current Surface in the EditorForm available. + /// + ICaptureDetails CaptureDetails { get; } + + ISurface Surface { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/ICapture.cs b/src/Greenshot.Base/Interfaces/ICapture.cs similarity index 79% rename from GreenshotPlugin/Interfaces/ICapture.cs rename to src/Greenshot.Base/Interfaces/ICapture.cs index 24f67a9f0..f10d49b8b 100644 --- a/GreenshotPlugin/Interfaces/ICapture.cs +++ b/src/Greenshot.Base/Interfaces/ICapture.cs @@ -22,27 +22,22 @@ using System; using System.Drawing; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { /// /// The interface to the Capture object, so Plugins can use it. /// - public interface ICapture : IDisposable { + public interface ICapture : IDisposable + { /// /// The Capture Details /// - ICaptureDetails CaptureDetails { - get; - set; - } + ICaptureDetails CaptureDetails { get; set; } /// /// The captured Image /// - Image Image { - get; - set; - } + Image Image { get; set; } /// /// Null the image @@ -52,42 +47,27 @@ namespace GreenshotPlugin.Interfaces /// /// Bounds on the screen from which the capture comes /// - Rectangle ScreenBounds { - get; - set; - } + Rectangle ScreenBounds { get; set; } /// /// The cursor /// - Icon Cursor { - get; - set; - } + Icon Cursor { get; set; } /// /// Boolean to specify if the cursor is available /// - bool CursorVisible { - get; - set; - } + bool CursorVisible { get; set; } /// /// Location of the cursor /// - Point CursorLocation { - get; - set; - } + Point CursorLocation { get; set; } /// /// Location of the capture /// - Point Location { - get; - set; - } + Point Location { get; set; } /// /// Crops the capture to the specified rectangle (with Bitmap coordinates!) diff --git a/src/Greenshot.Base/Interfaces/ICaptureDetails.cs b/src/Greenshot.Base/Interfaces/ICaptureDetails.cs new file mode 100644 index 000000000..2dc49d4a7 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/ICaptureDetails.cs @@ -0,0 +1,81 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using Greenshot.Base.Interfaces.Ocr; + +namespace Greenshot.Base.Interfaces +{ + /// + /// Details for the capture, like the window title and date/time etc. + /// + public interface ICaptureDetails + { + /// + /// If the capture comes from a file, this contains the filename + /// + string Filename { get; set; } + + /// + /// The title of the capture + /// + string Title { get; set; } + + /// + /// When was the capture taken (or loaded) + /// + DateTime DateTime { get; set; } + + /// + /// Destinations to where this capture goes or went + /// + List CaptureDestinations { get; set; } + + /// + /// The meta data of the capture + /// + Dictionary MetaData { get; } + + /// + /// Helper method to prevent complex code which needs to check every key + /// + /// The key for the meta-data + /// The value for the meta-data + void AddMetaData(string key, string value); + + void ClearDestinations(); + void RemoveDestination(IDestination captureDestination); + void AddDestination(IDestination captureDestination); + bool HasDestination(string designation); + + CaptureMode CaptureMode { get; set; } + + float DpiX { get; set; } + + float DpiY { get; set; } + + /// + /// Store the OCR information for this capture + /// + OcrInformation OcrInformation { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/IDestination.cs b/src/Greenshot.Base/Interfaces/IDestination.cs new file mode 100644 index 000000000..0e60d04b4 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/IDestination.cs @@ -0,0 +1,131 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; + +namespace Greenshot.Base.Interfaces +{ + public class ExportInformation + { + public ExportInformation(string destinationDesignation, string destinationDescription) + { + DestinationDesignation = destinationDesignation; + DestinationDescription = destinationDescription; + } + + public ExportInformation(string destinationDesignation, string destinationDescription, bool exportMade) : this(destinationDesignation, destinationDescription) + { + ExportMade = exportMade; + } + + public string DestinationDesignation { get; } + + public string DestinationDescription { get; set; } + + /// + /// Set to true to specify if the export worked. + /// + public bool ExportMade { get; set; } + + public string Uri { get; set; } + + public string ErrorMessage { get; set; } + + public string Filepath { get; set; } + } + + /// + /// Description of IDestination. + /// + public interface IDestination : IDisposable, IComparable + { + /// + /// Simple "designation" like "File", "Editor" etc, used to store the configuration + /// + string Designation { get; } + + /// + /// Description which will be shown in the settings form, destination picker etc + /// + string Description { get; } + + /// + /// Priority, used for sorting + /// + int Priority { get; } + + /// + /// Gets an icon for the destination + /// + Image DisplayIcon { get; } + + /// + /// Returns if the destination is active + /// + bool IsActive { get; } + + /// + /// Return a menu item + /// + /// Resolve the dynamic destinations too? + /// The menu for which the item is created + /// Handler which is called when clicked + /// ToolStripMenuItem + ToolStripMenuItem GetMenuItem(bool addDynamics, ContextMenuStrip menu, EventHandler destinationClickHandler); + + /// + /// Gets the ShortcutKeys for the Editor + /// + Keys EditorShortcutKeys { get; } + + /// + /// Gets the dynamic destinations + /// + IEnumerable DynamicDestinations(); + + /// + /// Returns true if this destination can be dynamic + /// + bool IsDynamic { get; } + + /// + /// Returns if the destination is active + /// + bool UseDynamicsOnly { get; } + + /// + /// Returns true if this destination returns a link + /// + bool IsLinkable { get; } + + /// + /// If a capture is made, and the destination is enabled, this method is called. + /// + /// true if the user selected this destination from a GUI, false if it was called as part of a process + /// + /// + /// DestinationExportInformation with information, like if the destination has "exported" the capture + ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/INotificationService.cs b/src/Greenshot.Base/Interfaces/INotificationService.cs similarity index 98% rename from GreenshotPlugin/Interfaces/INotificationService.cs rename to src/Greenshot.Base/Interfaces/INotificationService.cs index 43980a8e2..c4b47849d 100644 --- a/GreenshotPlugin/Interfaces/INotificationService.cs +++ b/src/Greenshot.Base/Interfaces/INotificationService.cs @@ -21,7 +21,7 @@ using System; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { /// /// This is the interface for the different notification service implementations diff --git a/src/Greenshot.Base/Interfaces/IProcessor.cs b/src/Greenshot.Base/Interfaces/IProcessor.cs new file mode 100644 index 000000000..47216bbbc --- /dev/null +++ b/src/Greenshot.Base/Interfaces/IProcessor.cs @@ -0,0 +1,59 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Interfaces +{ + /// + /// Description of IProcessor. + /// + public interface IProcessor : IDisposable, IComparable + { + /// + /// Simple "designation" like "FixTitle" + /// + string Designation { get; } + + /// + /// Description which will be shown in the settings form, destination picker etc + /// + string Description { get; } + + /// + /// Priority, used for sorting + /// + int Priority { get; } + + /// + /// Returns if the destination is active + /// + bool isActive { get; } + + /// + /// If a capture is made, and the destination is enabled, this method is called. + /// + /// + /// + /// true if the processor has "processed" the capture + bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/IServiceLocator.cs b/src/Greenshot.Base/Interfaces/IServiceLocator.cs similarity index 85% rename from GreenshotPlugin/Interfaces/IServiceLocator.cs rename to src/Greenshot.Base/Interfaces/IServiceLocator.cs index 1ef9df723..cd107e707 100644 --- a/GreenshotPlugin/Interfaces/IServiceLocator.cs +++ b/src/Greenshot.Base/Interfaces/IServiceLocator.cs @@ -1,14 +1,14 @@ -using System.Collections.Generic; - -namespace GreenshotPlugin.Interfaces -{ - public interface IServiceLocator - { - IEnumerable GetAllInstances(); - TService GetInstance(); - - void AddService(params TService[] services); - - void AddService(IEnumerable services); - } -} +using System.Collections.Generic; + +namespace Greenshot.Base.Interfaces +{ + public interface IServiceLocator + { + IEnumerable GetAllInstances(); + TService GetInstance(); + + void AddService(params TService[] services); + + void AddService(IEnumerable services); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/ISurface.cs b/src/Greenshot.Base/Interfaces/ISurface.cs similarity index 90% rename from GreenshotPlugin/Interfaces/ISurface.cs rename to src/Greenshot.Base/Interfaces/ISurface.cs index d6928b87e..254d6304f 100644 --- a/GreenshotPlugin/Interfaces/ISurface.cs +++ b/src/Greenshot.Base/Interfaces/ISurface.cs @@ -23,11 +23,11 @@ using System; using System.Drawing; using System.IO; using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.Effects; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; +using Greenshot.Base.Interfaces.Drawing; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { /// /// The interface to the Surface object, so Plugins can use it. @@ -47,16 +47,9 @@ namespace GreenshotPlugin.Interfaces /// /// Unique ID of the Surface /// - Guid ID - { - get; - set; - } + Guid ID { get; set; } - IDrawableContainerList Elements - { - get; - } + IDrawableContainerList Elements { get; } /// /// Get/Set the image to the Surface @@ -67,11 +60,7 @@ namespace GreenshotPlugin.Interfaces /// The setter will clone the passed bitmap and dispose it when the Surface is disposed /// This means that the supplied image needs to be disposed by the calling code (if needed!) /// - Image Image - { - get; - set; - } + Image Image { get; set; } /// /// Get the current Image from the Editor for Exporting (save/upload etc) @@ -95,7 +84,8 @@ namespace GreenshotPlugin.Interfaces /// size of border (0 for none) /// Color of string /// Color of background (e.g. Color.Transparent) - ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, Color fillColor); + ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, + Color fillColor); IImageContainer AddImageContainer(Image image, int x, int y); ICursorContainer AddCursorContainer(Cursor cursor, int x, int y); @@ -106,10 +96,7 @@ namespace GreenshotPlugin.Interfaces long SaveElementsToStream(Stream stream); void LoadElementsFromStream(Stream stream); - bool HasSelectedElements - { - get; - } + bool HasSelectedElements { get; } void RemoveSelectedElements(); void CutSelectedElements(); void CopySelectedElements(); @@ -124,6 +111,7 @@ namespace GreenshotPlugin.Interfaces /// IDrawableContainerList /// Should it be placed on the undo stack? void AddElements(IDrawableContainerList elements, bool makeUndoable = true); + void RemoveElements(IDrawableContainerList elements, bool makeUndoable = true); void SelectElements(IDrawableContainerList elements); @@ -142,34 +130,27 @@ namespace GreenshotPlugin.Interfaces /// false to skip invalidation /// false to skip event generation void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true); + /// /// Is the supplied container "on" the surface? /// /// /// This returns false if the container is deleted but still in the undo stack bool IsOnSurface(IDrawableContainer container); + void Invalidate(); + /// /// Invalidates the specified region of the Surface. /// Takes care of the Surface zoom level, accepts rectangle in the coordinate space of the Image. /// /// Bounding rectangle for updated elements, in the coordinate space of the Image. void InvalidateElements(Rectangle rectangleToInvalidate); - bool Modified - { - get; - set; - } - string LastSaveFullPath - { - get; - set; - } - string UploadUrl - { - get; - set; - } + + bool Modified { get; set; } + string LastSaveFullPath { get; set; } + string UploadUrl { get; set; } + /// /// Remove an element of the elements list /// @@ -182,36 +163,33 @@ namespace GreenshotPlugin.Interfaces void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message); void ApplyBitmapEffect(IEffect effect); void RemoveCursor(); - bool HasCursor - { - get; - } + bool HasCursor { get; } - ICaptureDetails CaptureDetails - { - get; - set; - } + ICaptureDetails CaptureDetails { get; set; } /// /// Zoom value applied to the surface. /// Fraction ZoomFactor { get; set; } + /// /// Translate a point from image coorditate space to surface coordinate space. /// /// A point in the coordinate space of the image. Point ToSurfaceCoordinates(Point point); + /// /// Translate a rectangle from image coorditate space to surface coordinate space. /// /// A rectangle in the coordinate space of the image. Rectangle ToSurfaceCoordinates(Rectangle rc); + /// /// Translate a point from surface coorditate space to image coordinate space. /// /// A point in the coordinate space of the surface. Point ToImageCoordinates(Point point); + /// /// Translate a rectangle from surface coorditate space to image coordinate space. /// @@ -220,4 +198,4 @@ namespace GreenshotPlugin.Interfaces void MakeUndoable(IMemento memento, bool allowMerge); } -} +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs b/src/Greenshot.Base/Interfaces/Ocr/IOcrProvider.cs similarity index 95% rename from GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs rename to src/Greenshot.Base/Interfaces/Ocr/IOcrProvider.cs index 4a9fd657e..09928dbe7 100644 --- a/GreenshotPlugin/Interfaces/Ocr/IOcrProvider.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/IOcrProvider.cs @@ -22,7 +22,7 @@ using System.Drawing; using System.Threading.Tasks; -namespace GreenshotPlugin.Interfaces.Ocr +namespace Greenshot.Base.Interfaces.Ocr { /// /// This interface describes something that can do OCR of a bitmap @@ -36,11 +36,11 @@ namespace GreenshotPlugin.Interfaces.Ocr /// OcrInformation Task DoOcrAsync(Image image); - /// + /// /// Start the actual OCR /// /// ISurface /// OcrInformation Task DoOcrAsync(ISurface surface); } -} +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/Ocr/Line.cs b/src/Greenshot.Base/Interfaces/Ocr/Line.cs similarity index 96% rename from GreenshotPlugin/Interfaces/Ocr/Line.cs rename to src/Greenshot.Base/Interfaces/Ocr/Line.cs index c4f1dccb7..fc21f72ae 100644 --- a/GreenshotPlugin/Interfaces/Ocr/Line.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/Line.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace GreenshotPlugin.Interfaces.Ocr +namespace Greenshot.Base.Interfaces.Ocr { /// /// Describes a line of words @@ -70,7 +70,7 @@ namespace GreenshotPlugin.Interfaces.Ocr foreach (var word in Words) { var location = word.Bounds; - location.Offset(x,y); + location.Offset(x, y); word.Bounds = location; } diff --git a/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs b/src/Greenshot.Base/Interfaces/Ocr/OcrInformation.cs similarity index 93% rename from GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs rename to src/Greenshot.Base/Interfaces/Ocr/OcrInformation.cs index cd20eab00..d7cb82559 100644 --- a/GreenshotPlugin/Interfaces/Ocr/OcrInformation.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/OcrInformation.cs @@ -2,18 +2,18 @@ using System.Linq; using System.Text; -namespace GreenshotPlugin.Interfaces.Ocr +namespace Greenshot.Base.Interfaces.Ocr { /// /// Contains all the information on the OCR result /// public class OcrInformation { - /// - /// Check if there is any content + /// + /// Check if there is any content /// public bool HasContent => Lines.Any(); - + /// /// The complete text /// @@ -27,6 +27,7 @@ namespace GreenshotPlugin.Interfaces.Ocr { text.AppendLine(line.Text); } + return text.ToString(); } } @@ -45,7 +46,7 @@ namespace GreenshotPlugin.Interfaces.Ocr { foreach (var line in Lines) { - line.Offset(x,y); + line.Offset(x, y); } } } diff --git a/GreenshotPlugin/Interfaces/Ocr/Word.cs b/src/Greenshot.Base/Interfaces/Ocr/Word.cs similarity index 90% rename from GreenshotPlugin/Interfaces/Ocr/Word.cs rename to src/Greenshot.Base/Interfaces/Ocr/Word.cs index 30982caa4..467b5278b 100644 --- a/GreenshotPlugin/Interfaces/Ocr/Word.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/Word.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace GreenshotPlugin.Interfaces.Ocr +namespace Greenshot.Base.Interfaces.Ocr { /// /// Contains the information about a word diff --git a/src/Greenshot.Base/Interfaces/Plugin/HotKeyHandler.cs b/src/Greenshot.Base/Interfaces/Plugin/HotKeyHandler.cs new file mode 100644 index 000000000..db59840e2 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Plugin/HotKeyHandler.cs @@ -0,0 +1,4 @@ +namespace Greenshot.Base.Interfaces.Plugin +{ + public delegate void HotKeyHandler(); +} \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs b/src/Greenshot.Base/Interfaces/Plugin/IGreenshotHost.cs similarity index 93% rename from GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs rename to src/Greenshot.Base/Interfaces/Plugin/IGreenshotHost.cs index b502a5ba2..5c8457178 100644 --- a/GreenshotPlugin/Interfaces/Plugin/IGreenshotHost.cs +++ b/src/Greenshot.Base/Interfaces/Plugin/IGreenshotHost.cs @@ -1,48 +1,49 @@ -using System.Drawing; - -namespace GreenshotPlugin.Interfaces.Plugin -{ - /// - /// This interface is the GreenshotPluginHost, that which "Hosts" the plugin. - /// For Greenshot this is implemented in the PluginHelper - /// - public interface IGreenshotHost { - /// - /// Create a Thumbnail - /// - /// Image of which we need a Thumbnail - /// - /// - /// Image with Thumbnail - Image GetThumbnail(Image image, int width, int height); - - /// - /// Export a surface to the destination with has the supplied designation - /// - /// - /// - /// - /// - ExportInformation ExportCapture(bool manuallyInitiated, string designation, ISurface surface, ICaptureDetails captureDetails); - - /// - /// Make region capture with specified Handler - /// - /// bool false if the mouse should not be captured, true if the configuration should be checked - /// IDestination destination - void CaptureRegion(bool captureMouseCursor, IDestination destination); - - /// - /// Use the supplied capture, and handle it as if it's captured. - /// - /// ICapture to import - void ImportCapture(ICapture captureToImport); - - /// - /// Use the supplied image, and ICapture a capture object for it - /// - /// Image to create capture for - /// ICapture - ICapture GetCapture(Image imageToCapture); - } +using System.Drawing; + +namespace Greenshot.Base.Interfaces.Plugin +{ + /// + /// This interface is the GreenshotPluginHost, that which "Hosts" the plugin. + /// For Greenshot this is implemented in the PluginHelper + /// + public interface IGreenshotHost + { + /// + /// Create a Thumbnail + /// + /// Image of which we need a Thumbnail + /// + /// + /// Image with Thumbnail + Image GetThumbnail(Image image, int width, int height); + + /// + /// Export a surface to the destination with has the supplied designation + /// + /// + /// + /// + /// + ExportInformation ExportCapture(bool manuallyInitiated, string designation, ISurface surface, ICaptureDetails captureDetails); + + /// + /// Make region capture with specified Handler + /// + /// bool false if the mouse should not be captured, true if the configuration should be checked + /// IDestination destination + void CaptureRegion(bool captureMouseCursor, IDestination destination); + + /// + /// Use the supplied capture, and handle it as if it's captured. + /// + /// ICapture to import + void ImportCapture(ICapture captureToImport); + + /// + /// Use the supplied image, and ICapture a capture object for it + /// + /// Image to create capture for + /// ICapture + ICapture GetCapture(Image imageToCapture); + } } \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs b/src/Greenshot.Base/Interfaces/Plugin/IGreenshotPlugin.cs similarity index 84% rename from GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs rename to src/Greenshot.Base/Interfaces/Plugin/IGreenshotPlugin.cs index 697a52a56..b61f49f44 100644 --- a/GreenshotPlugin/Interfaces/Plugin/IGreenshotPlugin.cs +++ b/src/Greenshot.Base/Interfaces/Plugin/IGreenshotPlugin.cs @@ -1,25 +1,26 @@ -using System; - -namespace GreenshotPlugin.Interfaces.Plugin -{ - /// - /// This defines the plugin - /// - public interface IGreenshotPlugin : IDisposable { - /// - /// Is called after the plugin is instantiated, the Plugin should keep a copy of the host and pluginAttribute. - /// - /// true if plugin is initialized, false if not (doesn't show) - bool Initialize(); - - /// - /// Unload of the plugin - /// - void Shutdown(); - - /// - /// Open the Configuration Form, will/should not be called before handshaking is done - /// - void Configure(); - } +using System; + +namespace Greenshot.Base.Interfaces.Plugin +{ + /// + /// This defines the plugin + /// + public interface IGreenshotPlugin : IDisposable + { + /// + /// Is called after the plugin is instantiated, the Plugin should keep a copy of the host and pluginAttribute. + /// + /// true if plugin is initialized, false if not (doesn't show) + bool Initialize(); + + /// + /// Unload of the plugin + /// + void Shutdown(); + + /// + /// Open the Configuration Form, will/should not be called before handshaking is done + /// + void Configure(); + } } \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs b/src/Greenshot.Base/Interfaces/Plugin/PluginAttribute.cs similarity index 57% rename from GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs rename to src/Greenshot.Base/Interfaces/Plugin/PluginAttribute.cs index c44d7f120..f0f66949a 100644 --- a/GreenshotPlugin/Interfaces/Plugin/PluginAttribute.cs +++ b/src/Greenshot.Base/Interfaces/Plugin/PluginAttribute.cs @@ -1,51 +1,50 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.Interfaces.Plugin { - [Serializable] - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] - public sealed class PluginAttribute : Attribute, IComparable { - public string Name { - get; - set; - } - - public bool Configurable { - get; - private set; - } - - public PluginAttribute(string name, bool configurable) - { - Name = name; - Configurable = configurable; - } - - public int CompareTo(object obj) { - if (obj is PluginAttribute other) { - return string.Compare(Name, other.Name, StringComparison.Ordinal); - } - throw new ArgumentException("object is not a PluginAttribute"); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Interfaces.Plugin +{ + [Serializable] + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public sealed class PluginAttribute : Attribute, IComparable + { + public string Name { get; set; } + + public bool Configurable { get; private set; } + + public PluginAttribute(string name, bool configurable) + { + Name = name; + Configurable = configurable; + } + + public int CompareTo(object obj) + { + if (obj is PluginAttribute other) + { + return string.Compare(Name, other.Name, StringComparison.Ordinal); + } + + throw new ArgumentException("object is not a PluginAttribute"); + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs b/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs similarity index 65% rename from GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs rename to src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs index c3429b2b1..82946acdd 100644 --- a/GreenshotPlugin/Interfaces/Plugin/SurfaceOutputSettings.cs +++ b/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs @@ -1,91 +1,91 @@ -using System.Collections.Generic; -using GreenshotPlugin.Core; -using GreenshotPlugin.Effects; -using GreenshotPlugin.IniFile; - -namespace GreenshotPlugin.Interfaces.Plugin -{ - public class SurfaceOutputSettings { - private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private bool _reduceColors; - private bool _disableReduceColors; - - public SurfaceOutputSettings() { - _disableReduceColors = false; - Format = CoreConfig.OutputFileFormat; - JPGQuality = CoreConfig.OutputFileJpegQuality; - ReduceColors = CoreConfig.OutputFileReduceColors; - } - - public SurfaceOutputSettings(OutputFormat format) : this() { - Format = format; - } - - public SurfaceOutputSettings(OutputFormat format, int quality) : this(format) { - JPGQuality = quality; - } - - public SurfaceOutputSettings(OutputFormat format, int quality, bool reduceColors) : this(format, quality) { - ReduceColors = reduceColors; - } - - /// - /// BUG-2056 reported a logical issue, using greenshot format as the default causes issues with the external commands. - /// - /// this for fluent API usage - public SurfaceOutputSettings PreventGreenshotFormat() - { - // If OutputFormat is Greenshot, use PNG instead. - if (Format == OutputFormat.greenshot) - { - Format = OutputFormat.png; - } - return this; - } - - public OutputFormat Format { - get; - set; - } - - public int JPGQuality { - get; - set; - } - - public bool SaveBackgroundOnly { - get; - set; - } - - public List Effects { get; } = new List(); - - public bool ReduceColors { - get { - // Fix for Bug #3468436, force quantizing when output format is gif as this has only 256 colors! - if (OutputFormat.gif.Equals(Format)) { - return true; - } - return _reduceColors; - } - set { - _reduceColors = value; - } - } - - /// - /// Disable the reduce colors option, this overrules the enabling - /// - public bool DisableReduceColors { - get { - return _disableReduceColors; - } - set { - // Quantizing os needed when output format is gif as this has only 256 colors! - if (!OutputFormat.gif.Equals(Format)) { - _disableReduceColors = value; - } - } - } - } +using System.Collections.Generic; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; +using Greenshot.Base.IniFile; + +namespace Greenshot.Base.Interfaces.Plugin +{ + public class SurfaceOutputSettings + { + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private bool _reduceColors; + private bool _disableReduceColors; + + public SurfaceOutputSettings() + { + _disableReduceColors = false; + Format = CoreConfig.OutputFileFormat; + JPGQuality = CoreConfig.OutputFileJpegQuality; + ReduceColors = CoreConfig.OutputFileReduceColors; + } + + public SurfaceOutputSettings(OutputFormat format) : this() + { + Format = format; + } + + public SurfaceOutputSettings(OutputFormat format, int quality) : this(format) + { + JPGQuality = quality; + } + + public SurfaceOutputSettings(OutputFormat format, int quality, bool reduceColors) : this(format, quality) + { + ReduceColors = reduceColors; + } + + /// + /// BUG-2056 reported a logical issue, using greenshot format as the default causes issues with the external commands. + /// + /// this for fluent API usage + public SurfaceOutputSettings PreventGreenshotFormat() + { + // If OutputFormat is Greenshot, use PNG instead. + if (Format == OutputFormat.greenshot) + { + Format = OutputFormat.png; + } + + return this; + } + + public OutputFormat Format { get; set; } + + public int JPGQuality { get; set; } + + public bool SaveBackgroundOnly { get; set; } + + public List Effects { get; } = new List(); + + public bool ReduceColors + { + get + { + // Fix for Bug #3468436, force quantizing when output format is gif as this has only 256 colors! + if (OutputFormat.gif.Equals(Format)) + { + return true; + } + + return _reduceColors; + } + set { _reduceColors = value; } + } + + /// + /// Disable the reduce colors option, this overrules the enabling + /// + public bool DisableReduceColors + { + get { return _disableReduceColors; } + set + { + // Quantizing os needed when output format is gif as this has only 256 colors! + if (!OutputFormat.gif.Equals(Format)) + { + _disableReduceColors = value; + } + } + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs b/src/Greenshot.Base/Interfaces/ScreenCaptureMode.cs similarity index 96% rename from GreenshotPlugin/Interfaces/ScreenCaptureMode.cs rename to src/Greenshot.Base/Interfaces/ScreenCaptureMode.cs index bdcc14d81..5481a58e5 100644 --- a/GreenshotPlugin/Interfaces/ScreenCaptureMode.cs +++ b/src/Greenshot.Base/Interfaces/ScreenCaptureMode.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public enum ScreenCaptureMode { diff --git a/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventArgs.cs similarity index 88% rename from GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs rename to src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventArgs.cs index b30a68828..32ca381bb 100644 --- a/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventArgs.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventArgs.cs @@ -21,14 +21,10 @@ using System; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public class SurfaceDrawingModeEventArgs : EventArgs { - public DrawingModes DrawingMode - { - get; - set; - } + public DrawingModes DrawingMode { get; set; } } } \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventHandler.cs similarity index 96% rename from GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs rename to src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventHandler.cs index 5582f77d3..d71508eea 100644 --- a/GreenshotPlugin/Interfaces/SurfaceDrawingModeEventHandler.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceDrawingModeEventHandler.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public delegate void SurfaceDrawingModeEventHandler(object sender, SurfaceDrawingModeEventArgs e); } \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceElementEventArgs.cs similarity index 84% rename from GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs rename to src/Greenshot.Base/Interfaces/SurfaceElementEventArgs.cs index f53241447..f081a6fd8 100644 --- a/GreenshotPlugin/Interfaces/SurfaceElementEventArgs.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceElementEventArgs.cs @@ -20,16 +20,12 @@ */ using System; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public class SurfaceElementEventArgs : EventArgs { - public IDrawableContainerList Elements - { - get; - set; - } + public IDrawableContainerList Elements { get; set; } } } \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceElementEventHandler.cs similarity index 96% rename from GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs rename to src/Greenshot.Base/Interfaces/SurfaceElementEventHandler.cs index eef546545..0d788d854 100644 --- a/GreenshotPlugin/Interfaces/SurfaceElementEventHandler.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceElementEventHandler.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public delegate void SurfaceElementEventHandler(object sender, SurfaceElementEventArgs e); } \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceMessageEventArgs.cs similarity index 82% rename from GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs rename to src/Greenshot.Base/Interfaces/SurfaceMessageEventArgs.cs index 2908e9ffb..5c2019385 100644 --- a/GreenshotPlugin/Interfaces/SurfaceMessageEventArgs.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceMessageEventArgs.cs @@ -21,24 +21,12 @@ using System; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public class SurfaceMessageEventArgs : EventArgs - { - public SurfaceMessageTyp MessageType - { - get; - set; - } - public string Message - { - get; - set; - } - public ISurface Surface - { - get; - set; - } - } + { + public SurfaceMessageTyp MessageType { get; set; } + public string Message { get; set; } + public ISurface Surface { get; set; } + } } \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceMessageEventHandler.cs similarity index 96% rename from GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs rename to src/Greenshot.Base/Interfaces/SurfaceMessageEventHandler.cs index 1bea86b37..2fb9083ca 100644 --- a/GreenshotPlugin/Interfaces/SurfaceMessageEventHandler.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceMessageEventHandler.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public delegate void SurfaceMessageEventHandler(object sender, SurfaceMessageEventArgs e); } \ No newline at end of file diff --git a/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs b/src/Greenshot.Base/Interfaces/SurfaceMessageTyp.cs similarity index 96% rename from GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs rename to src/Greenshot.Base/Interfaces/SurfaceMessageTyp.cs index 84efe7609..625dc7d36 100644 --- a/GreenshotPlugin/Interfaces/SurfaceMessageTyp.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceMessageTyp.cs @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public enum SurfaceMessageTyp { diff --git a/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceSizeChangeEventHandler.cs similarity index 96% rename from GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs rename to src/Greenshot.Base/Interfaces/SurfaceSizeChangeEventHandler.cs index f9fe667f3..47d296074 100644 --- a/GreenshotPlugin/Interfaces/SurfaceSizeChangeEventHandler.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceSizeChangeEventHandler.cs @@ -21,7 +21,7 @@ using System; -namespace GreenshotPlugin.Interfaces +namespace Greenshot.Base.Interfaces { public delegate void SurfaceSizeChangeEventHandler(object sender, EventArgs e); } \ No newline at end of file diff --git a/src/Greenshot.Base/Interop/Base.cs b/src/Greenshot.Base/Interop/Base.cs new file mode 100644 index 000000000..ef4e5dfa0 --- /dev/null +++ b/src/Greenshot.Base/Interop/Base.cs @@ -0,0 +1,11 @@ +using System; + +namespace Greenshot.Base.Interop +{ + /// + /// Common properties that has appreared in almost all objects + /// + public interface ICommon : IDisposable + { + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interop/COMWrapper.cs b/src/Greenshot.Base/Interop/COMWrapper.cs new file mode 100644 index 000000000..e33c7ee08 --- /dev/null +++ b/src/Greenshot.Base/Interop/COMWrapper.cs @@ -0,0 +1,621 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Proxies; +using System.Windows.Forms; +using Greenshot.Base.Core; +using log4net; + +namespace Greenshot.Base.Interop +{ + /// + /// Wraps a late-bound COM server. + /// + public sealed class COMWrapper : RealProxy, IDisposable, IRemotingTypeInfo + { + private static readonly ILog Log = LogManager.GetLogger(typeof(COMWrapper)); + public const int RPC_E_CALL_REJECTED = unchecked((int) 0x80010001); + public const int RPC_E_FAIL = unchecked((int) 0x80004005); + + /// + /// Holds reference to the actual COM object which is wrapped by this proxy + /// + private readonly object _comObject; + + /// + /// Type of the COM object, set on constructor after getting the COM reference + /// + private readonly Type _comType; + + /// + /// The type of which method calls are intercepted and executed on the COM object. + /// + private readonly Type _interceptType; + + /// + /// The humanly readable target name + /// + private readonly string _targetName; + + /// + /// A simple create instance, doesn't create a wrapper!! + /// + /// T + public static T CreateInstance() + { + Type type = typeof(T); + if (null == type) + { + throw new ArgumentNullException(nameof(T)); + } + + if (!type.IsInterface) + { + throw new ArgumentException("The specified type must be an interface.", nameof(T)); + } + + ComProgIdAttribute progIdAttribute = ComProgIdAttribute.GetAttribute(type); + if (string.IsNullOrEmpty(progIdAttribute?.Value)) + { + throw new ArgumentException("The specified type must define a ComProgId attribute.", nameof(T)); + } + + string progId = progIdAttribute.Value; + Type comType = null; + if (progId.StartsWith("clsid:")) + { + Guid guid = new Guid(progId.Substring(6)); + try + { + comType = Type.GetTypeFromCLSID(guid); + } + catch (Exception ex) + { + Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); + } + } + else + { + try + { + comType = Type.GetTypeFromProgID(progId, true); + } + catch (Exception ex) + { + Log.WarnFormat("Error {1} type for {0}", progId, ex.Message); + } + } + + object comObject = null; + if (comType != null) + { + try + { + comObject = Activator.CreateInstance(comType); + if (comObject != null) + { + Log.DebugFormat("Created new instance of {0} object.", progId); + } + } + catch (Exception e) + { + Log.WarnFormat("Error {1} creating object for {0}", progId, e.Message); + throw; + } + } + + if (comObject != null) + { + return (T) comObject; + } + + return default; + } + + /// + /// Wrap an object and return the transparent proxy which intercepts all calls to the object + /// + /// An object to intercept + /// Interface which defines the method and properties to intercept + /// + /// Transparent proxy to the real proxy for the object + private static object Wrap(object comObject, Type type, string targetName) + { + if (null == comObject) + { + throw new ArgumentNullException(nameof(comObject)); + } + + if (null == type) + { + throw new ArgumentNullException(nameof(type)); + } + + COMWrapper wrapper = new COMWrapper(comObject, type, targetName); + return wrapper.GetTransparentProxy(); + } + + /// + /// Constructor + /// + /// + /// The COM object to wrap. + /// + /// + /// The interface type to impersonate. + /// + /// + private COMWrapper(object comObject, Type type, string targetName) : base(type) + { + _comObject = comObject; + _comType = comObject.GetType(); + _interceptType = type; + _targetName = targetName; + } + + /// + /// If is not called, we need to make + /// sure that the COM object is still cleaned up. + /// + ~COMWrapper() + { + Log.DebugFormat("Finalize {0}", _interceptType); + Dispose(false); + } + + /// + /// Cleans up the COM object. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Release the COM reference + /// + /// + /// if this was called from the + /// interface. + /// + private void Dispose(bool disposing) + { + if (null != _comObject) + { + Log.DebugFormat("Disposing {0}", _interceptType); + if (Marshal.IsComObject(_comObject)) + { + try + { + int count; + do + { + count = Marshal.ReleaseComObject(_comObject); + Log.DebugFormat("RCW count for {0} now is {1}", _interceptType, count); + } while (count > 0); + } + catch (Exception ex) + { + Log.WarnFormat("Problem releasing COM object {0}", _comType); + Log.Warn("Error: ", ex); + } + } + else + { + Log.WarnFormat("{0} is not a COM object", _comType); + } + } + } + + /// + /// Returns a string representing the wrapped object. + /// + /// + /// The full name of the intercepted type. + /// + public override string ToString() + { + return _interceptType.FullName; + } + + /// + /// Returns the hash code of the wrapped object. + /// + /// + /// The hash code of the wrapped object. + /// + public override int GetHashCode() + { + return _comObject.GetHashCode(); + } + + /// + /// Compares this object to another. + /// + /// + /// The value to compare to. + /// + /// + /// if the objects are equal. + /// + public override bool Equals(object value) + { + if (null != value && RemotingServices.IsTransparentProxy(value)) + { + COMWrapper wrapper = RemotingServices.GetRealProxy(value) as COMWrapper; + if (null != wrapper) + { + return _comObject == wrapper._comObject; + } + } + + return base.Equals(value); + } + + /// + /// Returns the base type for a reference type. + /// + /// + /// The reference type. + /// + /// + /// The base value type. + /// + /// + /// is . + /// + private static Type GetByValType(Type byRefType) + { + if (null == byRefType) + { + throw new ArgumentNullException(nameof(byRefType)); + } + + if (byRefType.IsByRef) + { + string name = byRefType.FullName; + name = name.Substring(0, name.Length - 1); + byRefType = byRefType.Assembly.GetType(name, true); + } + + return byRefType; + } + + /// + /// Intercept method calls + /// + /// + /// Contains information about the method being called + /// + /// + /// A . + /// + public override IMessage Invoke(IMessage myMessage) + { + if (!(myMessage is IMethodCallMessage callMessage)) + { + Log.DebugFormat("Message type not implemented: {0}", myMessage.GetType()); + return null; + } + + MethodInfo method = callMessage.MethodBase as MethodInfo; + if (null == method) + { + Log.DebugFormat("Unrecognized Invoke call: {0}", callMessage.MethodBase); + return null; + } + + object returnValue = null; + object[] outArgs = null; + int outArgsCount = 0; + + string methodName = method.Name; + Type returnType = method.ReturnType; + BindingFlags flags = BindingFlags.InvokeMethod; + int argCount = callMessage.ArgCount; + + ParameterModifier[] argModifiers = null; + ParameterInfo[] parameters = null; + + if ("Dispose" == methodName && 0 == argCount && typeof(void) == returnType) + { + Dispose(); + } + else if ("ToString" == methodName && 0 == argCount && typeof(string) == returnType) + { + returnValue = ToString(); + } + else if ("GetType" == methodName && 0 == argCount && typeof(Type) == returnType) + { + returnValue = _interceptType; + } + else if ("GetHashCode" == methodName && 0 == argCount && typeof(int) == returnType) + { + returnValue = GetHashCode(); + } + else if ("Equals" == methodName && 1 == argCount && typeof(bool) == returnType) + { + returnValue = Equals(callMessage.Args[0]); + } + else if (1 == argCount && typeof(void) == returnType && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) + { + bool removeHandler = methodName.StartsWith("remove_"); + methodName = methodName.Substring(removeHandler ? 7 : 4); + // TODO: Something is missing here + if (!(callMessage.InArgs[0] is Delegate handler)) + { + return new ReturnMessage(new ArgumentNullException(nameof(handler)), callMessage); + } + } + else + { + var invokeObject = _comObject; + var invokeType = _comType; + + object[] args; + ParameterInfo parameter; + if (methodName.StartsWith("get_")) + { + // Property Get + methodName = methodName.Substring(4); + flags = BindingFlags.GetProperty; + args = callMessage.InArgs; + } + else if (methodName.StartsWith("set_")) + { + // Property Set + methodName = methodName.Substring(4); + flags = BindingFlags.SetProperty; + args = callMessage.InArgs; + } + else + { + args = callMessage.Args; + if (null != args && 0 != args.Length) + { + // Modifiers for ref / out parameters + argModifiers = new ParameterModifier[1]; + argModifiers[0] = new ParameterModifier(args.Length); + + parameters = method.GetParameters(); + for (int i = 0; i < parameters.Length; i++) + { + parameter = parameters[i]; + if (parameter.IsOut || parameter.ParameterType.IsByRef) + { + argModifiers[0][i] = true; + outArgsCount++; + } + } + + if (0 == outArgsCount) + { + argModifiers = null; + } + } + } + + // Un-wrap wrapped COM objects before passing to the method + Type byValType; + COMWrapper wrapper; + COMWrapper[] originalArgs; + if (null == args || 0 == args.Length) + { + originalArgs = null; + } + else + { + originalArgs = new COMWrapper[args.Length]; + for (int i = 0; i < args.Length; i++) + { + if (null != args[i] && RemotingServices.IsTransparentProxy(args[i])) + { + wrapper = RemotingServices.GetRealProxy(args[i]) as COMWrapper; + if (null != wrapper) + { + originalArgs[i] = wrapper; + args[i] = wrapper._comObject; + } + } + else if (0 != outArgsCount && argModifiers[0][i]) + { + byValType = GetByValType(parameters[i].ParameterType); + if (byValType.IsInterface) + { + // If we're passing a COM object by reference, and + // the parameter is null, we need to pass a + // DispatchWrapper to avoid a type mismatch exception. + if (null == args[i]) + { + args[i] = new DispatchWrapper(null); + } + } + else if (typeof(decimal) == byValType) + { + // If we're passing a decimal value by reference, + // we need to pass a CurrencyWrapper to avoid a + // type mismatch exception. + // http://support.microsoft.com/?kbid=837378 + args[i] = new CurrencyWrapper(args[i]); + } + } + } + } + + do + { + try + { + returnValue = invokeType.InvokeMember(methodName, flags, null, invokeObject, args, argModifiers, null, null); + break; + } + catch (InvalidComObjectException icoEx) + { + // Should assist BUG-1616 and others + Log.WarnFormat( + "COM object {0} has been separated from its underlying RCW cannot be used. The COM object was released while it was still in use on another thread.", + _interceptType.FullName); + return new ReturnMessage(icoEx, callMessage); + } + catch (Exception ex) + { + // Test for rejected + if (!(ex is COMException comEx)) + { + comEx = ex.InnerException as COMException; + } + + if (comEx != null && (comEx.ErrorCode == RPC_E_CALL_REJECTED || comEx.ErrorCode == RPC_E_FAIL)) + { + string destinationName = _targetName; + // Try to find a "catchy" name for the rejecting application + if (destinationName != null && destinationName.Contains(".")) + { + destinationName = destinationName.Substring(0, destinationName.IndexOf(".", StringComparison.Ordinal)); + } + + if (destinationName == null) + { + destinationName = _interceptType.FullName; + } + + var form = SimpleServiceProvider.Current.GetInstance(); + + DialogResult result = MessageBox.Show(form, Language.GetFormattedString("com_rejected", destinationName), Language.GetString("com_rejected_title"), + MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation); + if (result == DialogResult.OK) + { + continue; + } + } + + // Not rejected OR pressed cancel + return new ReturnMessage(ex, callMessage); + } + } while (true); + + // Handle enum and interface return types + if (null != returnValue) + { + if (returnType.IsInterface) + { + // Wrap the returned value in an intercepting COM wrapper + if (Marshal.IsComObject(returnValue)) + { + returnValue = Wrap(returnValue, returnType, _targetName); + } + } + else if (returnType.IsEnum) + { + // Convert to proper Enum type + returnValue = Enum.Parse(returnType, returnValue.ToString()); + } + } + + // Handle out args + if (0 != outArgsCount) + { + outArgs = new object[args.Length]; + for (int i = 0; i < parameters.Length; i++) + { + if (!argModifiers[0][i]) + { + continue; + } + + var arg = args[i]; + if (null == arg) + { + continue; + } + + parameter = parameters[i]; + wrapper = null; + + byValType = GetByValType(parameter.ParameterType); + if (typeof(decimal) == byValType) + { + if (arg is CurrencyWrapper) + { + arg = ((CurrencyWrapper) arg).WrappedObject; + } + } + else if (byValType.IsEnum) + { + arg = Enum.Parse(byValType, arg.ToString()); + } + else if (byValType.IsInterface) + { + if (Marshal.IsComObject(arg)) + { + wrapper = originalArgs[i]; + if (null != wrapper && wrapper._comObject != arg) + { + wrapper.Dispose(); + wrapper = null; + } + + if (null == wrapper) + { + wrapper = new COMWrapper(arg, byValType, _targetName); + } + + arg = wrapper.GetTransparentProxy(); + } + } + + outArgs[i] = arg; + } + } + } + + return new ReturnMessage(returnValue, outArgs, outArgsCount, callMessage.LogicalCallContext, callMessage); + } + + /// + /// Implementation for the interface IRemotingTypeInfo + /// This makes it possible to cast the COMWrapper + /// + /// Type to cast to + /// object to cast + /// + public bool CanCastTo(Type toType, object o) + { + bool returnValue = _interceptType.IsAssignableFrom(toType); + return returnValue; + } + + /// + /// Implementation for the interface IRemotingTypeInfo + /// + public string TypeName + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interop/ComProgIdAttribute.cs b/src/Greenshot.Base/Interop/ComProgIdAttribute.cs new file mode 100644 index 000000000..079bdd149 --- /dev/null +++ b/src/Greenshot.Base/Interop/ComProgIdAttribute.cs @@ -0,0 +1,88 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Interop +{ + /// + /// An attribute to specifiy the ProgID of the COM class to create. (As suggested by Kristen Wegner) + /// + [AttributeUsage(AttributeTargets.Interface)] + public sealed class ComProgIdAttribute : Attribute + { + /// + /// Extracts the attribute from the specified type. + /// + /// + /// The interface type. + /// + /// + /// The . + /// + /// + /// is . + /// + public static ComProgIdAttribute GetAttribute(Type interfaceType) + { + if (null == interfaceType) + { + throw new ArgumentNullException(nameof(interfaceType)); + } + + Type attributeType = typeof(ComProgIdAttribute); + object[] attributes = interfaceType.GetCustomAttributes(attributeType, false); + + if (0 == attributes.Length) + { + Type[] interfaces = interfaceType.GetInterfaces(); + foreach (Type t in interfaces) + { + interfaceType = t; + attributes = interfaceType.GetCustomAttributes(attributeType, false); + if (0 != attributes.Length) + { + break; + } + } + } + + if (0 == attributes.Length) + { + return null; + } + + return (ComProgIdAttribute) attributes[0]; + } + + /// Constructor + /// The COM ProgID. + public ComProgIdAttribute(string value) + { + Value = value; + } + + /// + /// Returns the COM ProgID + /// + public string Value { get; } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interop/IAppVisibility.cs b/src/Greenshot.Base/Interop/IAppVisibility.cs similarity index 61% rename from GreenshotPlugin/Interop/IAppVisibility.cs rename to src/Greenshot.Base/Interop/IAppVisibility.cs index 58fddc8b8..b0c392bae 100644 --- a/GreenshotPlugin/Interop/IAppVisibility.cs +++ b/src/Greenshot.Base/Interop/IAppVisibility.cs @@ -1,40 +1,41 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Interop { - // This is used for Windows 8 to see if the App Launcher is active - // See http://msdn.microsoft.com/en-us/library/windows/desktop/jj554119%28v=vs.85%29.aspx - [ComProgId("clsid:7E5FE3D9-985F-4908-91F9-EE19F9FD1514")] - [ComImport, Guid("2246EA2D-CAEA-4444-A3C4-6DE827E44313"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IAppVisibility { - MONITOR_APP_VISIBILITY GetAppVisibilityOnMonitor(IntPtr hMonitor); - bool IsLauncherVisible { - get; - } - } - - public enum MONITOR_APP_VISIBILITY { - MAV_APP_VISIBLE = 2 - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Interop +{ + // This is used for Windows 8 to see if the App Launcher is active + // See http://msdn.microsoft.com/en-us/library/windows/desktop/jj554119%28v=vs.85%29.aspx + [ComProgId("clsid:7E5FE3D9-985F-4908-91F9-EE19F9FD1514")] + [ComImport, Guid("2246EA2D-CAEA-4444-A3C4-6DE827E44313"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IAppVisibility + { + MONITOR_APP_VISIBILITY GetAppVisibilityOnMonitor(IntPtr hMonitor); + bool IsLauncherVisible { get; } + } + + public enum MONITOR_APP_VISIBILITY + { + MAV_APP_VISIBLE = 2 + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interop/IDispatch.cs b/src/Greenshot.Base/Interop/IDispatch.cs similarity index 54% rename from GreenshotPlugin/Interop/IDispatch.cs rename to src/Greenshot.Base/Interop/IDispatch.cs index b4391c621..5e7c0a563 100644 --- a/GreenshotPlugin/Interop/IDispatch.cs +++ b/src/Greenshot.Base/Interop/IDispatch.cs @@ -1,43 +1,47 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.CustomMarshalers; - -namespace GreenshotPlugin.Interop { - [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsDual)] - public interface IDispatch : IUnknown { - [PreserveSig] - int GetTypeInfoCount(out int count); - - [PreserveSig] - int GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo, [MarshalAs(UnmanagedType.U4)] int lcid, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))] out Type typeInfo); - - [PreserveSig] - int GetIDsOfNames(ref Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] - string[] rgsNames, int cNames, int lcid, [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId); - - [PreserveSig] - int Invoke(int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, - out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr); - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.CustomMarshalers; + +namespace Greenshot.Base.Interop +{ + [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsDual)] + public interface IDispatch : IUnknown + { + [PreserveSig] + int GetTypeInfoCount(out int count); + + [PreserveSig] + int GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo, [MarshalAs(UnmanagedType.U4)] int lcid, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))] + out Type typeInfo); + + [PreserveSig] + int GetIDsOfNames(ref Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] + string[] rgsNames, int cNames, int lcid, [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId); + + [PreserveSig] + int Invoke(int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, + out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interop/IOleCommandTarget.cs b/src/Greenshot.Base/Interop/IOleCommandTarget.cs similarity index 60% rename from GreenshotPlugin/Interop/IOleCommandTarget.cs rename to src/Greenshot.Base/Interop/IOleCommandTarget.cs index 6207d196e..5903bda58 100644 --- a/GreenshotPlugin/Interop/IOleCommandTarget.cs +++ b/src/Greenshot.Base/Interop/IOleCommandTarget.cs @@ -1,36 +1,40 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Interop { - [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(true), Guid("B722BCCB-4E68-101B-A2BC-00AA00404770")] - public interface IOleCommandTarget { - [return: MarshalAs(UnmanagedType.I4)] - [PreserveSig] - int QueryStatus([In, MarshalAs(UnmanagedType.LPStruct)] Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText); - - [return: MarshalAs(UnmanagedType.I4)] - [PreserveSig] - int Exec([In, MarshalAs(UnmanagedType.LPStruct)] Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut); - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Interop +{ + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(true), Guid("B722BCCB-4E68-101B-A2BC-00AA00404770")] + public interface IOleCommandTarget + { + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int QueryStatus([In, MarshalAs(UnmanagedType.LPStruct)] + Guid pguidCmdGroup, int cCmds, IntPtr prgCmds, IntPtr pCmdText); + + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int Exec([In, MarshalAs(UnmanagedType.LPStruct)] + Guid pguidCmdGroup, int nCmdID, int nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interop/IOleWindow.cs b/src/Greenshot.Base/Interop/IOleWindow.cs similarity index 67% rename from GreenshotPlugin/Interop/IOleWindow.cs rename to src/Greenshot.Base/Interop/IOleWindow.cs index c5361dc0d..adefc15ef 100644 --- a/GreenshotPlugin/Interop/IOleWindow.cs +++ b/src/Greenshot.Base/Interop/IOleWindow.cs @@ -1,33 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Interop { - // Needed to get the Window handle from the IDocument2 - // See: http://msdn.microsoft.com/en-us/library/ms680102%28v=vs.85%29.aspx - [ComImport, Guid("00000114-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IOleWindow { - void GetWindow(out IntPtr phWnd); - void ContextSensitiveHelp([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode); - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Interop +{ + // Needed to get the Window handle from the IDocument2 + // See: http://msdn.microsoft.com/en-us/library/ms680102%28v=vs.85%29.aspx + [ComImport, Guid("00000114-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IOleWindow + { + void GetWindow(out IntPtr phWnd); + void ContextSensitiveHelp([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interop/IServiceProvider.cs b/src/Greenshot.Base/Interop/IServiceProvider.cs similarity index 65% rename from GreenshotPlugin/Interop/IServiceProvider.cs rename to src/Greenshot.Base/Interop/IServiceProvider.cs index d058f81c3..423541e5e 100644 --- a/GreenshotPlugin/Interop/IServiceProvider.cs +++ b/src/Greenshot.Base/Interop/IServiceProvider.cs @@ -1,33 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Interop { - // This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface! - [ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IServiceProvider { - [return: MarshalAs(UnmanagedType.I4)][PreserveSig] - int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject); - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Interop +{ + // This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface! + [ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IServiceProvider + { + [return: MarshalAs(UnmanagedType.I4)] + [PreserveSig] + int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/Interop/IUnknown.cs b/src/Greenshot.Base/Interop/IUnknown.cs similarity index 74% rename from GreenshotPlugin/Interop/IUnknown.cs rename to src/Greenshot.Base/Interop/IUnknown.cs index bee0da243..bdffb0bf9 100644 --- a/GreenshotPlugin/Interop/IUnknown.cs +++ b/src/Greenshot.Base/Interop/IUnknown.cs @@ -1,36 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.Interop { - [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000000-0000-0000-C000-000000000046")] - public interface IUnknown { - IntPtr QueryInterface(ref Guid riid); - - [PreserveSig] - uint AddRef(); - - [PreserveSig] - uint Release(); - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.Interop +{ + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000000-0000-0000-C000-000000000046")] + public interface IUnknown + { + IntPtr QueryInterface(ref Guid riid); + + [PreserveSig] + uint AddRef(); + + [PreserveSig] + uint Release(); + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/DWM.cs b/src/Greenshot.Base/UnmanagedHelpers/DWM.cs new file mode 100644 index 000000000..cf5a2c056 --- /dev/null +++ b/src/Greenshot.Base/UnmanagedHelpers/DWM.cs @@ -0,0 +1,123 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; +using Microsoft.Win32; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Desktop Window Manager helper code + /// + public static class DWM + { + // DWM + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb); + + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmUnregisterThumbnail(IntPtr thumb); + + [DllImport("dwmapi", SetLastError = true)] + public static extern HResult DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size); + + [DllImport("dwmapi", SetLastError = true)] + public static extern HResult DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); + + // Deprecated as of Windows 8 Release Preview + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmIsCompositionEnabled(out bool enabled); + + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT lpRect, int size); + + [DllImport("dwmapi", SetLastError = true)] + public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool pvAttribute, int cbAttribute); + + // Key to ColorizationColor for DWM + private const string COLORIZATION_COLOR_KEY = @"SOFTWARE\Microsoft\Windows\DWM"; + + /// + /// Checks if the window is cloaked, this should solve some issues with the window selection code + /// + /// IntPtr as hWmd + /// bool + public static bool IsWindowCloaked(IntPtr hWnd) + { + if (!WindowsVersion.IsWindows8OrLater) + { + return false; + } + + DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAKED, out bool isCloaked, Marshal.SizeOf(typeof(bool))); + return isCloaked; + } + + /// + /// Helper method for an easy DWM check + /// + /// bool true if DWM is available AND active + public static bool IsDwmEnabled + { + get + { + // According to: http://technet.microsoft.com/en-us/subscriptions/aa969538%28v=vs.85%29.aspx + // And: http://msdn.microsoft.com/en-us/library/windows/desktop/aa969510%28v=vs.85%29.aspx + // DMW is always enabled on Windows 8! So return true and save a check! ;-) + if (WindowsVersion.IsWindows8OrLater) + { + return true; + } + + if (WindowsVersion.IsWindowsVistaOrLater) + { + DwmIsCompositionEnabled(out var dwmEnabled); + return dwmEnabled; + } + + return false; + } + } + + public static Color ColorizationColor + { + get + { + using (RegistryKey key = Registry.CurrentUser.OpenSubKey(COLORIZATION_COLOR_KEY, false)) + { + object dwordValue = key?.GetValue("ColorizationColor"); + if (dwordValue != null) + { + return Color.FromArgb((int) dwordValue); + } + } + + return Color.White; + } + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs b/src/Greenshot.Base/UnmanagedHelpers/EnumWindowsProc.cs similarity index 94% rename from GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs rename to src/Greenshot.Base/UnmanagedHelpers/EnumWindowsProc.cs index db0185e07..d5e97162d 100644 --- a/GreenshotPlugin/UnmanagedHelpers/EnumWindowsProc.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/EnumWindowsProc.cs @@ -1,33 +1,33 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// Used with EnumWindows or EnumChildWindows - /// - /// IntPtr - /// int - /// int - public delegate int EnumWindowsProc(IntPtr hWnd, int lParam); +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Used with EnumWindows or EnumChildWindows + /// + /// IntPtr + /// int + /// int + public delegate int EnumWindowsProc(IntPtr hWnd, int lParam); } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs similarity index 93% rename from GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs index d862d0ee8..6c070a25b 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ClassLongIndex.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ClassLongIndex - { - GCL_HICON = -14, // a handle to the icon associated with the class. - GCL_HICONSM = -34, // a handle to the small icon associated with the class. - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum ClassLongIndex + { + GCL_HICON = -14, // a handle to the icon associated with the class. + GCL_HICONSM = -34, // a handle to the small icon associated with the class. + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs similarity index 77% rename from GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs index e58bde613..03d1ab7f9 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs @@ -1,46 +1,46 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DWMWINDOWATTRIBUTE : uint - { - DWMWA_NCRENDERING_ENABLED = 1, - DWMWA_NCRENDERING_POLICY, - DWMWA_TRANSITIONS_FORCEDISABLED, - DWMWA_ALLOW_NCPAINT, - DWMWA_CAPTION_BUTTON_BOUNDS, - DWMWA_NONCLIENT_RTL_LAYOUT, - DWMWA_FORCE_ICONIC_REPRESENTATION, - DWMWA_FLIP3D_POLICY, - DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista - DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7 - DWMWA_DISALLOW_PEEK, // Since Windows 7 - DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7 - DWMWA_CLOAK, // Since Windows 8 - DWMWA_CLOAKED, // Since Windows 8 - DWMWA_FREEZE_REPRESENTATION, // Since Windows 8 - DWMWA_LAST - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum DWMWINDOWATTRIBUTE : uint + { + DWMWA_NCRENDERING_ENABLED = 1, + DWMWA_NCRENDERING_POLICY, + DWMWA_TRANSITIONS_FORCEDISABLED, + DWMWA_ALLOW_NCPAINT, + DWMWA_CAPTION_BUTTON_BOUNDS, + DWMWA_NONCLIENT_RTL_LAYOUT, + DWMWA_FORCE_ICONIC_REPRESENTATION, + DWMWA_FLIP3D_POLICY, + DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista + DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7 + DWMWA_DISALLOW_PEEK, // Since Windows 7 + DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7 + DWMWA_CLOAK, // Since Windows 8 + DWMWA_CLOAKED, // Since Windows 8 + DWMWA_FREEZE_REPRESENTATION, // Since Windows 8 + DWMWA_LAST + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs similarity index 85% rename from GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs index e442abfd5..aa808f807 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs @@ -1,85 +1,111 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; -using GreenshotPlugin.UnmanagedHelpers.Structs; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// See: http://msdn.microsoft.com/en-us/library/aa969502(v=vs.85).aspx - /// - [StructLayout(LayoutKind.Sequential)] - public struct DWM_THUMBNAIL_PROPERTIES { - // A bitwise combination of DWM thumbnail constant values that indicates which members of this structure are set. - public int dwFlags; - // The area in the destination window where the thumbnail will be rendered. - public RECT rcDestination; - // The region of the source window to use as the thumbnail. By default, the entire window is used as the thumbnail. - public RECT rcSource; - // The opacity with which to render the thumbnail. 0 is fully transparent while 255 is fully opaque. The default value is 255. - public byte opacity; - // TRUE to make the thumbnail visible; otherwise, FALSE. The default is FALSE. - public bool fVisible; - // TRUE to use only the thumbnail source's client area; otherwise, FALSE. The default is FALSE. - public bool fSourceClientAreaOnly; - public RECT Destination { - set { - dwFlags |= DWM_TNP_RECTDESTINATION; - rcDestination = value; - } - } - public RECT Source { - set { - dwFlags |= DWM_TNP_RECTSOURCE; - rcSource = value; - } - } - public byte Opacity { - set { - dwFlags |= DWM_TNP_OPACITY; - opacity = value; - } - } - public bool Visible { - set { - dwFlags |= DWM_TNP_VISIBLE; - fVisible = value; - } - } - public bool SourceClientAreaOnly { - set { - dwFlags |= DWM_TNP_SOURCECLIENTAREAONLY; - fSourceClientAreaOnly = value; - } - } - // A value for the rcDestination member has been specified. - public const int DWM_TNP_RECTDESTINATION = 0x00000001; - // A value for the rcSource member has been specified. - public const int DWM_TNP_RECTSOURCE = 0x00000002; - // A value for the opacity member has been specified. - public const int DWM_TNP_OPACITY = 0x00000004; - // A value for the fVisible member has been specified. - public const int DWM_TNP_VISIBLE = 0x00000008; - // A value for the fSourceClientAreaOnly member has been specified. - public const int DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010; - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Runtime.InteropServices; +using Greenshot.Base.UnmanagedHelpers.Structs; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// See: http://msdn.microsoft.com/en-us/library/aa969502(v=vs.85).aspx + /// + [StructLayout(LayoutKind.Sequential)] + public struct DWM_THUMBNAIL_PROPERTIES + { + // A bitwise combination of DWM thumbnail constant values that indicates which members of this structure are set. + public int dwFlags; + + // The area in the destination window where the thumbnail will be rendered. + public RECT rcDestination; + + // The region of the source window to use as the thumbnail. By default, the entire window is used as the thumbnail. + public RECT rcSource; + + // The opacity with which to render the thumbnail. 0 is fully transparent while 255 is fully opaque. The default value is 255. + public byte opacity; + + // TRUE to make the thumbnail visible; otherwise, FALSE. The default is FALSE. + public bool fVisible; + + // TRUE to use only the thumbnail source's client area; otherwise, FALSE. The default is FALSE. + public bool fSourceClientAreaOnly; + + public RECT Destination + { + set + { + dwFlags |= DWM_TNP_RECTDESTINATION; + rcDestination = value; + } + } + + public RECT Source + { + set + { + dwFlags |= DWM_TNP_RECTSOURCE; + rcSource = value; + } + } + + public byte Opacity + { + set + { + dwFlags |= DWM_TNP_OPACITY; + opacity = value; + } + } + + public bool Visible + { + set + { + dwFlags |= DWM_TNP_VISIBLE; + fVisible = value; + } + } + + public bool SourceClientAreaOnly + { + set + { + dwFlags |= DWM_TNP_SOURCECLIENTAREAONLY; + fSourceClientAreaOnly = value; + } + } + + // A value for the rcDestination member has been specified. + public const int DWM_TNP_RECTDESTINATION = 0x00000001; + + // A value for the rcSource member has been specified. + public const int DWM_TNP_RECTSOURCE = 0x00000002; + + // A value for the opacity member has been specified. + public const int DWM_TNP_OPACITY = 0x00000004; + + // A value for the fVisible member has been specified. + public const int DWM_TNP_VISIBLE = 0x00000008; + + // A value for the fSourceClientAreaOnly member has been specified. + public const int DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010; + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DesktopAccessRight.cs similarity index 92% rename from GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/DesktopAccessRight.cs index a52871fa4..219299a35 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DesktopAccessRight.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/DesktopAccessRight.cs @@ -1,44 +1,45 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DesktopAccessRight : uint { - DESKTOP_READOBJECTS = 0x00000001, - DESKTOP_CREATEWINDOW = 0x00000002, - DESKTOP_CREATEMENU = 0x00000004, - DESKTOP_HOOKCONTROL = 0x00000008, - DESKTOP_JOURNALRECORD = 0x00000010, - DESKTOP_JOURNALPLAYBACK = 0x00000020, - DESKTOP_ENUMERATE = 0x00000040, - DESKTOP_WRITEOBJECTS = 0x00000080, - DESKTOP_SWITCHDESKTOP = 0x00000100, - - GENERIC_ALL = (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | - DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | - DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP) - }; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum DesktopAccessRight : uint + { + DESKTOP_READOBJECTS = 0x00000001, + DESKTOP_CREATEWINDOW = 0x00000002, + DESKTOP_CREATEMENU = 0x00000004, + DESKTOP_HOOKCONTROL = 0x00000008, + DESKTOP_JOURNALRECORD = 0x00000010, + DESKTOP_JOURNALPLAYBACK = 0x00000020, + DESKTOP_ENUMERATE = 0x00000040, + DESKTOP_WRITEOBJECTS = 0x00000080, + DESKTOP_SWITCHDESKTOP = 0x00000100, + + GENERIC_ALL = (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | + DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | + DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP) + }; } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DeviceCaps.cs similarity index 92% rename from GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/DeviceCaps.cs index d83bf89a0..126d9de62 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/DeviceCaps.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/DeviceCaps.cs @@ -1,43 +1,43 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// Used by GDI32.GetDeviceCaps - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd144877%28v=vs.85%29.aspx - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DeviceCaps { - - /// - /// Logical pixels inch in X - /// - LOGPIXELSX = 88, - - /// - /// Current vertical refresh rate of the display device (for displays only) in Hz - /// - VREFRESH = 116 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// Used by GDI32.GetDeviceCaps + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd144877%28v=vs.85%29.aspx + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum DeviceCaps + { + /// + /// Logical pixels inch in X + /// + LOGPIXELSX = 88, + + /// + /// Current vertical refresh rate of the display device (for displays only) in Hz + /// + VREFRESH = 116 + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs similarity index 93% rename from GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs index a1981e644..81532e912 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/EventObjects.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs @@ -1,35 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// Used for User32.SetWinEventHook - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd373606%28v=vs.85%29.aspx#OBJID_WINDOW - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum EventObjects - { - OBJID_WINDOW = 0 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// Used for User32.SetWinEventHook + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd373606%28v=vs.85%29.aspx#OBJID_WINDOW + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum EventObjects + { + OBJID_WINDOW = 0 + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs similarity index 72% rename from GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs index 6bc87e3f7..e00166b2d 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs @@ -1,33 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ExtendedWindowStyleFlags : uint { - WS_EX_TOOLWINDOW = 0x00000080, - WS_EX_NOREDIRECTIONBITMAP = 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual. - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum ExtendedWindowStyleFlags : uint + { + WS_EX_TOOLWINDOW = 0x00000080, + + WS_EX_NOREDIRECTIONBITMAP = + 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual. + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ProcessAccessFlags.cs similarity index 90% rename from GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/ProcessAccessFlags.cs index 063623e25..d4e593840 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ProcessAccessFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ProcessAccessFlags.cs @@ -1,33 +1,34 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ProcessAccessFlags : uint { - VMRead = 0x00000010, - QueryInformation = 0x00000400, - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum ProcessAccessFlags : uint + { + VMRead = 0x00000010, + QueryInformation = 0x00000400, + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs similarity index 90% rename from GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs index b9ef9536f..4632a6aaf 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/RegionResult.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs @@ -1,31 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum RegionResult { - REGION_ERROR = 0, - REGION_NULLREGION = 1, - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum RegionResult + { + REGION_ERROR = 0, + REGION_NULLREGION = 1, + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs similarity index 87% rename from GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs index e8cbd4390..b6c0b2087 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs @@ -1,35 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// See: http://www.pinvoke.net/default.aspx/Enums/SendMessageTimeoutFlags.html - /// - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SendMessageTimeoutFlags : uint { - SMTO_NORMAL = 0x0 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// See: http://www.pinvoke.net/default.aspx/Enums/SendMessageTimeoutFlags.html + /// + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum SendMessageTimeoutFlags : uint + { + SMTO_NORMAL = 0x0 + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs similarity index 95% rename from GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs index 7962650d3..c09a10f9e 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ShowWindowCommand.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs @@ -1,97 +1,110 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ShowWindowCommand : uint { - /// - /// Hides the window and activates another window. - /// - Hide = 0, - /// - /// Activates and displays a window. If the window is minimized or - /// maximized, the system restores it to its original size and position. - /// An application should specify this flag when displaying the window - /// for the first time. - /// - Normal = 1, - /// - /// Activates the window and displays it as a minimized window. - /// - ShowMinimized = 2, - /// - /// Maximizes the specified window. - /// - Maximize = 3, // is this the right value? - /// - /// Activates the window and displays it as a maximized window. - /// - ShowMaximized = 3, - /// - /// Displays a window in its most recent size and position. This value - /// is similar to , except - /// the window is not actived. - /// - ShowNoActivate = 4, - /// - /// Activates the window and displays it in its current size and position. - /// - Show = 5, - /// - /// Minimizes the specified window and activates the next top-level - /// window in the Z order. - /// - Minimize = 6, - /// - /// Displays the window as a minimized window. This value is similar to - /// , except the - /// window is not activated. - /// - ShowMinNoActive = 7, - /// - /// Displays the window in its current size and position. This value is - /// similar to , except the - /// window is not activated. - /// - ShowNA = 8, - /// - /// Activates and displays the window. If the window is minimized or - /// maximized, the system restores it to its original size and position. - /// An application should specify this flag when restoring a minimized window. - /// - Restore = 9, - /// - /// Sets the show state based on the SW_* value specified in the - /// STARTUPINFO structure passed to the CreateProcess function by the - /// program that started the application. - /// - ShowDefault = 10, - /// - /// Windows 2000/XP: Minimizes a window, even if the thread - /// that owns the window is not responding. This flag should only be - /// used when minimizing windows from a different thread. - /// - ForceMinimize = 11 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum ShowWindowCommand : uint + { + /// + /// Hides the window and activates another window. + /// + Hide = 0, + + /// + /// Activates and displays a window. If the window is minimized or + /// maximized, the system restores it to its original size and position. + /// An application should specify this flag when displaying the window + /// for the first time. + /// + Normal = 1, + + /// + /// Activates the window and displays it as a minimized window. + /// + ShowMinimized = 2, + + /// + /// Maximizes the specified window. + /// + Maximize = 3, // is this the right value? + + /// + /// Activates the window and displays it as a maximized window. + /// + ShowMaximized = 3, + + /// + /// Displays a window in its most recent size and position. This value + /// is similar to , except + /// the window is not actived. + /// + ShowNoActivate = 4, + + /// + /// Activates the window and displays it in its current size and position. + /// + Show = 5, + + /// + /// Minimizes the specified window and activates the next top-level + /// window in the Z order. + /// + Minimize = 6, + + /// + /// Displays the window as a minimized window. This value is similar to + /// , except the + /// window is not activated. + /// + ShowMinNoActive = 7, + + /// + /// Displays the window in its current size and position. This value is + /// similar to , except the + /// window is not activated. + /// + ShowNA = 8, + + /// + /// Activates and displays the window. If the window is minimized or + /// maximized, the system restores it to its original size and position. + /// An application should specify this flag when restoring a minimized window. + /// + Restore = 9, + + /// + /// Sets the show state based on the SW_* value specified in the + /// STARTUPINFO structure passed to the CreateProcess function by the + /// program that started the application. + /// + ShowDefault = 10, + + /// + /// Windows 2000/XP: Minimizes a window, even if the thread + /// that owns the window is not responding. This flag should only be + /// used when minimizing windows from a different thread. + /// + ForceMinimize = 11 + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs similarity index 77% rename from GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs index 8104a5dea..aebe3d9a6 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/SoundFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs @@ -1,39 +1,39 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// See: http://msdn.microsoft.com/en-us/library/aa909766.aspx - /// - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SoundFlags - { - SND_ASYNC = 0x0001, // play asynchronously - SND_MEMORY = 0x0004, // pszSound points to a memory file - SND_NOSTOP = 0x0010, // don't stop any currently playing sound - SND_NOWAIT = 0x00002000, // don't wait if the driver is busy - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// See: http://msdn.microsoft.com/en-us/library/aa909766.aspx + /// + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum SoundFlags + { + SND_ASYNC = 0x0001, // play asynchronously + SND_MEMORY = 0x0004, // pszSound points to a memory file + SND_NOSTOP = 0x0010, // don't stop any currently playing sound + SND_NOWAIT = 0x00002000, // don't wait if the driver is busy + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ThreadAccess.cs similarity index 89% rename from GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/ThreadAccess.cs index fc5495304..979af5708 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/ThreadAccess.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ThreadAccess.cs @@ -1,30 +1,31 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - public enum ThreadAccess : int { - SUSPEND_RESUME = (0x0002), - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + public enum ThreadAccess : int + { + SUSPEND_RESUME = (0x0002), + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs similarity index 93% rename from GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs index 987bc5654..5e814b223 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/Win32Error.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs @@ -1,88 +1,89 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// A Win32 error code. - /// - public enum Win32Error : uint { - Success = 0x0, - InvalidFunction = 0x1, - FileNotFound = 0x2, - PathNotFound = 0x3, - TooManyOpenFiles = 0x4, - AccessDenied = 0x5, - InvalidHandle = 0x6, - ArenaTrashed = 0x7, - NotEnoughMemory = 0x8, - InvalidBlock = 0x9, - BadEnvironment = 0xa, - BadFormat = 0xb, - InvalidAccess = 0xc, - InvalidData = 0xd, - OutOfMemory = 0xe, - InvalidDrive = 0xf, - CurrentDirectory = 0x10, - NotSameDevice = 0x11, - NoMoreFiles = 0x12, - WriteProtect = 0x13, - BadUnit = 0x14, - NotReady = 0x15, - BadCommand = 0x16, - Crc = 0x17, - BadLength = 0x18, - Seek = 0x19, - NotDosDisk = 0x1a, - SectorNotFound = 0x1b, - OutOfPaper = 0x1c, - WriteFault = 0x1d, - ReadFault = 0x1e, - GenFailure = 0x1f, - SharingViolation = 0x20, - LockViolation = 0x21, - WrongDisk = 0x22, - SharingBufferExceeded = 0x24, - HandleEof = 0x26, - HandleDiskFull = 0x27, - NotSupported = 0x32, - RemNotList = 0x33, - DupName = 0x34, - BadNetPath = 0x35, - NetworkBusy = 0x36, - DevNotExist = 0x37, - TooManyCmds = 0x38, - FileExists = 0x50, - CannotMake = 0x52, - AlreadyAssigned = 0x55, - InvalidPassword = 0x56, - InvalidParameter = 0x57, - NetWriteFault = 0x58, - NoProcSlots = 0x59, - TooManySemaphores = 0x64, - ExclSemAlreadyOwned = 0x65, - SemIsSet = 0x66, - TooManySemRequests = 0x67, - InvalidAtInterruptTime = 0x68, - SemOwnerDied = 0x69, - SemUserLimit = 0x6a - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// A Win32 error code. + /// + public enum Win32Error : uint + { + Success = 0x0, + InvalidFunction = 0x1, + FileNotFound = 0x2, + PathNotFound = 0x3, + TooManyOpenFiles = 0x4, + AccessDenied = 0x5, + InvalidHandle = 0x6, + ArenaTrashed = 0x7, + NotEnoughMemory = 0x8, + InvalidBlock = 0x9, + BadEnvironment = 0xa, + BadFormat = 0xb, + InvalidAccess = 0xc, + InvalidData = 0xd, + OutOfMemory = 0xe, + InvalidDrive = 0xf, + CurrentDirectory = 0x10, + NotSameDevice = 0x11, + NoMoreFiles = 0x12, + WriteProtect = 0x13, + BadUnit = 0x14, + NotReady = 0x15, + BadCommand = 0x16, + Crc = 0x17, + BadLength = 0x18, + Seek = 0x19, + NotDosDisk = 0x1a, + SectorNotFound = 0x1b, + OutOfPaper = 0x1c, + WriteFault = 0x1d, + ReadFault = 0x1e, + GenFailure = 0x1f, + SharingViolation = 0x20, + LockViolation = 0x21, + WrongDisk = 0x22, + SharingBufferExceeded = 0x24, + HandleEof = 0x26, + HandleDiskFull = 0x27, + NotSupported = 0x32, + RemNotList = 0x33, + DupName = 0x34, + BadNetPath = 0x35, + NetworkBusy = 0x36, + DevNotExist = 0x37, + TooManyCmds = 0x38, + FileExists = 0x50, + CannotMake = 0x52, + AlreadyAssigned = 0x55, + InvalidPassword = 0x56, + InvalidParameter = 0x57, + NetWriteFault = 0x58, + NoProcSlots = 0x59, + TooManySemaphores = 0x64, + ExclSemAlreadyOwned = 0x65, + SemIsSet = 0x66, + TooManySemRequests = 0x67, + InvalidAtInterruptTime = 0x68, + SemOwnerDied = 0x69, + SemUserLimit = 0x6a + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs similarity index 91% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs index a170af781..0938d4317 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WinEvent.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs @@ -1,35 +1,37 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// Used for User32.SetWinEventHook - /// See MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/dd318066%28v=vs.85%29.aspx - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WinEvent : uint { - EVENT_OBJECT_CREATE = 32768, - EVENT_OBJECT_DESTROY = 32769, - EVENT_OBJECT_NAMECHANGE = 32780, - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// Used for User32.SetWinEventHook + /// See MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/dd318066%28v=vs.85%29.aspx + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WinEvent : uint + { + EVENT_OBJECT_CREATE = 32768, + EVENT_OBJECT_DESTROY = 32769, + EVENT_OBJECT_NAMECHANGE = 32780, + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WinEventHookFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEventHookFlags.cs similarity index 87% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WinEventHookFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WinEventHookFlags.cs index 4ca58d2df..497940960 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WinEventHookFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEventHookFlags.cs @@ -1,18 +1,18 @@ -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// Used for User32.SetWinEventHook - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd373640%28v=vs.85%29.aspx - /// - [SuppressMessage("ReSharper", "InconsistentNaming"), Flags] - public enum WinEventHookFlags - { - WINEVENT_SKIPOWNTHREAD = 1, - WINEVENT_SKIPOWNPROCESS = 2, - WINEVENT_OUTOFCONTEXT = 0, - WINEVENT_INCONTEXT = 4 - } +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// Used for User32.SetWinEventHook + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/dd373640%28v=vs.85%29.aspx + /// + [SuppressMessage("ReSharper", "InconsistentNaming"), Flags] + public enum WinEventHookFlags + { + WINEVENT_SKIPOWNTHREAD = 1, + WINEVENT_SKIPOWNPROCESS = 2, + WINEVENT_OUTOFCONTEXT = 0, + WINEVENT_INCONTEXT = 4 + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs similarity index 84% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs index d71a3803e..09eddbb32 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowLongIndex.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs @@ -1,32 +1,32 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowLongIndex - { - GWL_EXSTYLE = -20, // Sets a new extended window style. - GWL_STYLE = -16, // Sets a new window style. - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowLongIndex + { + GWL_EXSTYLE = -20, // Sets a new extended window style. + GWL_STYLE = -16, // Sets a new window style. + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPlacementFlags.cs similarity index 93% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPlacementFlags.cs index ecdc92fe4..a6ac06dbf 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPlacementFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPlacementFlags.cs @@ -1,39 +1,42 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowPlacementFlags : uint { - // The coordinates of the minimized window may be specified. - // This flag must be specified if the coordinates are set in the ptMinPosition member. - WPF_SETMINPOSITION = 0x0001, - // If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. - WPF_ASYNCWINDOWPLACEMENT = 0x0004, - // The restored window will be maximized, regardless of whether it was maximized before it was minimized. This setting is only valid the next time the window is restored. It does not change the default restoration behavior. - // This flag is only valid when the SW_SHOWMINIMIZED value is specified for the showCmd member. - WPF_RESTORETOMAXIMIZED = 0x0002 - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowPlacementFlags : uint + { + // The coordinates of the minimized window may be specified. + // This flag must be specified if the coordinates are set in the ptMinPosition member. + WPF_SETMINPOSITION = 0x0001, + + // If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. + WPF_ASYNCWINDOWPLACEMENT = 0x0004, + + // The restored window will be maximized, regardless of whether it was maximized before it was minimized. This setting is only valid the next time the window is restored. It does not change the default restoration behavior. + // This flag is only valid when the SW_SHOWMINIMIZED value is specified for the showCmd member. + WPF_RESTORETOMAXIMIZED = 0x0002 + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs similarity index 71% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs index d343962ae..268819fc4 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowPos.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs @@ -1,35 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowPos - { - SWP_NOACTIVATE = 0x0010, // Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). - SWP_NOMOVE = 0x0002, //Retains the current position (ignores X and Y parameters). - SWP_NOSIZE = 0x0001, // Retains the current size (ignores the cx and cy parameters). - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowPos + { + SWP_NOACTIVATE = + 0x0010, // Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). + SWP_NOMOVE = 0x0002, //Retains the current position (ignores X and Y parameters). + SWP_NOSIZE = 0x0001, // Retains the current size (ignores the cx and cy parameters). + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs similarity index 77% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs index 48988c643..914633254 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowStyleFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs @@ -1,34 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums { - /// - /// Window Style Flags - /// - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowStyleFlags : long { - WS_VISIBLE = 0x10000000, - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// Window Style Flags + /// + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowStyleFlags : long + { + WS_VISIBLE = 0x10000000, + } +} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs similarity index 92% rename from GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs rename to src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs index 8029ccd30..2aff5fe19 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Enums/WindowsMessages.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs @@ -1,26 +1,26 @@ -using System.Diagnostics.CodeAnalysis; - -namespace GreenshotPlugin.UnmanagedHelpers.Enums -{ - /// - /// All possible windows messages - /// See also here - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowsMessages : uint - { - WM_MOUSEACTIVATE = 0x0021, - WM_INPUTLANGCHANGEREQUEST = 0x0050, - WM_INPUTLANGCHANGE = 0x0051, - - - /// - /// Sent to a window to retrieve a handle to the large or small icon associated with a window. The system displays the large icon in the ALT+TAB dialog, and the small icon in the window caption. - /// A window receives this message through its WindowProc function. - /// WM_GETICON message - /// - WM_GETICON = 0x007F, - WM_CHAR = 0x0102, - WM_SYSCOMMAND = 0x0112 - } +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Base.UnmanagedHelpers.Enums +{ + /// + /// All possible windows messages + /// See also here + /// + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum WindowsMessages : uint + { + WM_MOUSEACTIVATE = 0x0021, + WM_INPUTLANGCHANGEREQUEST = 0x0050, + WM_INPUTLANGCHANGE = 0x0051, + + + /// + /// Sent to a window to retrieve a handle to the large or small icon associated with a window. The system displays the large icon in the ALT+TAB dialog, and the small icon in the window caption. + /// A window receives this message through its WindowProc function. + /// WM_GETICON message + /// + WM_GETICON = 0x007F, + WM_CHAR = 0x0102, + WM_SYSCOMMAND = 0x0112 + } } \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs b/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs new file mode 100644 index 000000000..ed15abd1a --- /dev/null +++ b/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs @@ -0,0 +1,425 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Security; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Microsoft.Win32.SafeHandles; + +namespace Greenshot.Base.UnmanagedHelpers +{ + public static class GDIExtensions + { + /// + /// Check if all the corners of the rectangle are visible in the specified region. + /// Not a perfect check, but this currently a workaround for checking if a window is completely visible + /// + /// + /// + /// + public static bool AreRectangleCornersVisisble(this Region region, Rectangle rectangle) + { + Point topLeft = new Point(rectangle.X, rectangle.Y); + Point topRight = new Point(rectangle.X + rectangle.Width, rectangle.Y); + Point bottomLeft = new Point(rectangle.X, rectangle.Y + rectangle.Height); + Point bottomRight = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height); + bool topLeftVisible = region.IsVisible(topLeft); + bool topRightVisible = region.IsVisible(topRight); + bool bottomLeftVisible = region.IsVisible(bottomLeft); + bool bottomRightVisible = region.IsVisible(bottomRight); + + return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible; + } + + /// + /// Get a SafeHandle for the GetHdc, so one can use using to automatically cleanup the devicecontext + /// + /// + /// SafeDeviceContextHandle + public static SafeDeviceContextHandle GetSafeDeviceContext(this Graphics graphics) + { + return SafeDeviceContextHandle.FromGraphics(graphics); + } + } + + /// + /// Abstract class SafeObjectHandle which contains all handles that are cleaned with DeleteObject + /// + public abstract class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [DllImport("gdi32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteObject(IntPtr hObject); + + protected SafeObjectHandle(bool ownsHandle) : base(ownsHandle) + { + } + + protected override bool ReleaseHandle() + { + return DeleteObject(handle); + } + } + + /// + /// A hbitmap SafeHandle implementation + /// + public class SafeHBitmapHandle : SafeObjectHandle + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeHBitmapHandle() : base(true) + { + } + + [SecurityCritical] + public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + } + + /// + /// A hRegion SafeHandle implementation + /// + public class SafeRegionHandle : SafeObjectHandle + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeRegionHandle() : base(true) + { + } + + [SecurityCritical] + public SafeRegionHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + } + + /// + /// A dibsection SafeHandle implementation + /// + public class SafeDibSectionHandle : SafeObjectHandle + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeDibSectionHandle() : base(true) + { + } + + [SecurityCritical] + public SafeDibSectionHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + } + + /// + /// A select object safehandle implementation + /// This impl will select the passed SafeHandle to the HDC and replace the returned value when disposing + /// + public class SafeSelectObjectHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [DllImport("gdi32", SetLastError = true)] + private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); + + private readonly SafeHandle _hdc; + + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeSelectObjectHandle() : base(true) + { + } + + [SecurityCritical] + public SafeSelectObjectHandle(SafeDCHandle hdc, SafeHandle newHandle) : base(true) + { + _hdc = hdc; + SetHandle(SelectObject(hdc.DangerousGetHandle(), newHandle.DangerousGetHandle())); + } + + protected override bool ReleaseHandle() + { + SelectObject(_hdc.DangerousGetHandle(), handle); + return true; + } + } + + public abstract class SafeDCHandle : SafeHandleZeroOrMinusOneIsInvalid + { + protected SafeDCHandle(bool ownsHandle) : base(ownsHandle) + { + } + } + + /// + /// A CompatibleDC SafeHandle implementation + /// + public class SafeCompatibleDCHandle : SafeDCHandle + { + [DllImport("gdi32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool DeleteDC(IntPtr hDC); + + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeCompatibleDCHandle() : base(true) + { + } + + [SecurityCritical] + public SafeCompatibleDCHandle(IntPtr preexistingHandle) : base(true) + { + SetHandle(preexistingHandle); + } + + public SafeSelectObjectHandle SelectObject(SafeHandle newHandle) + { + return new SafeSelectObjectHandle(this, newHandle); + } + + protected override bool ReleaseHandle() + { + return DeleteDC(handle); + } + } + + /// + /// A DeviceContext SafeHandle implementation + /// + public class SafeDeviceContextHandle : SafeDCHandle + { + private readonly Graphics _graphics; + + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeDeviceContextHandle() : base(true) + { + } + + [SecurityCritical] + public SafeDeviceContextHandle(Graphics graphics, IntPtr preexistingHandle) : base(true) + { + _graphics = graphics; + SetHandle(preexistingHandle); + } + + protected override bool ReleaseHandle() + { + _graphics.ReleaseHdc(handle); + return true; + } + + public static SafeDeviceContextHandle FromGraphics(Graphics graphics) + { + return new SafeDeviceContextHandle(graphics, graphics.GetHdc()); + } + } + + /// + /// GDI32 Helpers + /// + public static class GDI32 + { + [DllImport("gdi32", SetLastError = true)] + public static extern bool BitBlt(SafeHandle hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, SafeHandle hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop); + + [DllImport("gdi32", SetLastError = true)] + public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC); + + [DllImport("gdi32", SetLastError = true)] + public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADER bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset); + + [DllImport("gdi32", SetLastError = true)] + public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); + + [DllImport("gdi32", SetLastError = true)] + public static extern uint GetPixel(SafeHandle hdc, int nXPos, int nYPos); + + [DllImport("gdi32", SetLastError = true)] + public static extern int GetDeviceCaps(SafeHandle hdc, DeviceCaps nIndex); + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + public struct BITMAPFILEHEADER + { + public static readonly short BM = 0x4d42; // BM + public short bfType; + public int bfSize; + public short bfReserved1; + public short bfReserved2; + public int bfOffBits; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BitfieldColorMask + { + public uint blue; + public uint green; + public uint red; + + public void InitValues() + { + red = (uint) 255 << 8; + green = (uint) 255 << 16; + blue = (uint) 255 << 24; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct CIEXYZ + { + public uint ciexyzX; //FXPT2DOT30 + public uint ciexyzY; //FXPT2DOT30 + public uint ciexyzZ; //FXPT2DOT30 + + public CIEXYZ(uint FXPT2DOT30) + { + ciexyzX = FXPT2DOT30; + ciexyzY = FXPT2DOT30; + ciexyzZ = FXPT2DOT30; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct CIEXYZTRIPLE + { + public CIEXYZ ciexyzRed; + public CIEXYZ ciexyzGreen; + public CIEXYZ ciexyzBlue; + } + + public enum BI_COMPRESSION : uint + { + BI_RGB = 0, // Uncompressed + BI_RLE8 = 1, // RLE 8BPP + BI_RLE4 = 2, // RLE 4BPP + + BI_BITFIELDS = + 3, // Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bpp bitmaps. + BI_JPEG = 4, // Indicates that the image is a JPEG image. + BI_PNG = 5 // Indicates that the image is a PNG image. + } + + [StructLayout(LayoutKind.Explicit)] + public struct BITMAPINFOHEADER + { + [FieldOffset(0)] public uint biSize; + [FieldOffset(4)] public int biWidth; + [FieldOffset(8)] public int biHeight; + [FieldOffset(12)] public ushort biPlanes; + [FieldOffset(14)] public ushort biBitCount; + [FieldOffset(16)] public BI_COMPRESSION biCompression; + [FieldOffset(20)] public uint biSizeImage; + [FieldOffset(24)] public int biXPelsPerMeter; + [FieldOffset(28)] public int biYPelsPerMeter; + [FieldOffset(32)] public uint biClrUsed; + [FieldOffset(36)] public uint biClrImportant; + [FieldOffset(40)] public uint bV5RedMask; + [FieldOffset(44)] public uint bV5GreenMask; + [FieldOffset(48)] public uint bV5BlueMask; + [FieldOffset(52)] public uint bV5AlphaMask; + [FieldOffset(56)] public uint bV5CSType; + [FieldOffset(60)] public CIEXYZTRIPLE bV5Endpoints; + [FieldOffset(96)] public uint bV5GammaRed; + [FieldOffset(100)] public uint bV5GammaGreen; + [FieldOffset(104)] public uint bV5GammaBlue; + [FieldOffset(108)] public uint bV5Intent; // Rendering intent for bitmap + [FieldOffset(112)] public uint bV5ProfileData; + [FieldOffset(116)] public uint bV5ProfileSize; + [FieldOffset(120)] public uint bV5Reserved; + + public const int DIB_RGB_COLORS = 0; + + public BITMAPINFOHEADER(int width, int height, ushort bpp) + { + biSize = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV5 is 40 bytes + biPlanes = 1; // Should allways be 1 + biCompression = BI_COMPRESSION.BI_RGB; + biWidth = width; + biHeight = height; + biBitCount = bpp; + biSizeImage = (uint) (width * height * (bpp >> 3)); + biXPelsPerMeter = 0; + biYPelsPerMeter = 0; + biClrUsed = 0; + biClrImportant = 0; + + // V5 + bV5RedMask = (uint) 255 << 16; + bV5GreenMask = (uint) 255 << 8; + bV5BlueMask = 255; + bV5AlphaMask = (uint) 255 << 24; + bV5CSType = 0x73524742; // LCS_sRGB + bV5Endpoints = new CIEXYZTRIPLE + { + ciexyzBlue = new CIEXYZ(0), + ciexyzGreen = new CIEXYZ(0), + ciexyzRed = new CIEXYZ(0) + }; + bV5GammaRed = 0; + bV5GammaGreen = 0; + bV5GammaBlue = 0; + bV5Intent = 4; + bV5ProfileData = 0; + bV5ProfileSize = 0; + bV5Reserved = 0; + } + + public bool IsDibV5 + { + get + { + uint sizeOfBMI = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADER)); + return biSize >= sizeOfBMI; + } + } + + public uint OffsetToPixels + { + get + { + if (biCompression == BI_COMPRESSION.BI_BITFIELDS) + { + // Add 3x4 bytes for the bitfield color mask + return biSize + 3 * 4; + } + + return biSize; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs b/src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs new file mode 100644 index 000000000..6fc9f061f --- /dev/null +++ b/src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs @@ -0,0 +1,387 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Reflection; +using System.Runtime.InteropServices; +using Greenshot.Base.UnmanagedHelpers.Structs; +using log4net; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Contains members that specify the nature of a Gaussian blur. + /// + /// Cannot be pinned with GCHandle due to bool value. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct BlurParams + { + /// + /// Real number that specifies the blur radius (the radius of the Gaussian convolution kernel) in + /// pixels. The radius must be in the range 0 through 255. As the radius increases, the resulting + /// bitmap becomes more blurry. + /// + public float Radius; + + /// + /// Boolean value that specifies whether the bitmap expands by an amount equal to the blur radius. + /// If TRUE, the bitmap expands by an amount equal to the radius so that it can have soft edges. + /// If FALSE, the bitmap remains the same size and the soft edges are clipped. + /// + public bool ExpandEdges; + } + + /// + /// GDI Plus unit description. + /// + public enum GpUnit + { + /// + /// World coordinate (non-physical unit). + /// + UnitWorld, + + /// + /// Variable - for PageTransform only. + /// + UnitDisplay, + + /// + /// Each unit is one device pixel. + /// + UnitPixel, + + /// + /// Each unit is a printer's point, or 1/72 inch. + /// + UnitPoint, + + /// + /// Each unit is 1 inch. + /// + UnitInch, + + /// + /// Each unit is 1/300 inch. + /// + UnitDocument, + + /// + /// Each unit is 1 millimeter. + /// + UnitMillimeter + } + + /// + /// GDIplus Helpers + /// + public static class GDIplus + { + private static readonly ILog Log = LogManager.GetLogger(typeof(GDIplus)); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipBitmapApplyEffect(IntPtr bitmap, IntPtr effect, ref RECT rectOfInterest, bool useAuxData, IntPtr auxData, int auxDataSize); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipDrawImageFX(IntPtr graphics, IntPtr bitmap, ref RECTF source, IntPtr matrix, IntPtr effect, IntPtr imageAttributes, GpUnit srcUnit); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipSetEffectParameters(IntPtr effect, IntPtr parameters, uint size); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipCreateEffect(Guid guid, out IntPtr effect); + + [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] + private static extern int GdipDeleteEffect(IntPtr effect); + + private static readonly Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}"); + + // Constant "FieldInfo" for getting the nativeImage from the Bitmap + private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGE = typeof(Bitmap).GetField("nativeImage", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + + // Constant "FieldInfo" for getting the NativeGraphics from the Graphics + private static readonly FieldInfo FIELD_INFO_NATIVE_GRAPHICS = + typeof(Graphics).GetField("nativeGraphics", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + + // Constant "FieldInfo" for getting the nativeMatrix from the Matrix + private static readonly FieldInfo FIELD_INFO_NATIVE_MATRIX = + typeof(Matrix).GetField("nativeMatrix", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + + // Constant "FieldInfo" for getting the nativeImageAttributes from the ImageAttributes + private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGEATTRIBUTES = + typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); + + private static bool _isBlurEnabled = Environment.OSVersion.Version.Major >= 6; + + /// + /// Get the nativeImage field from the bitmap + /// + /// + /// IntPtr + private static IntPtr GetNativeImage(Bitmap bitmap) + { + if (bitmap == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_IMAGE.GetValue(bitmap); + } + + /// + /// Get the NativeGraphics field from the graphics + /// + /// + /// IntPtr + private static IntPtr GetNativeGraphics(Graphics graphics) + { + if (graphics == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_GRAPHICS.GetValue(graphics); + } + + /// + /// Get the nativeMatrix field from the matrix + /// + /// + /// IntPtr + private static IntPtr GetNativeMatrix(Matrix matrix) + { + if (matrix == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_MATRIX.GetValue(matrix); + } + + /// + /// Get the nativeImageAttributes field from the ImageAttributes + /// + /// + /// IntPtr + private static IntPtr GetNativeImageAttributes(ImageAttributes imageAttributes) + { + if (imageAttributes == null) + { + return IntPtr.Zero; + } + + return (IntPtr) FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes); + } + + /// + /// Returns if a GDIPlus blur can be made for the supplied radius. + /// This accounts for the "bug" I reported here: http://social.technet.microsoft.com/Forums/en/w8itprogeneral/thread/99ddbe9d-556d-475a-8bab-84e25aa13a2c + /// + /// + /// false if blur is not possible + public static bool IsBlurPossible(int radius) + { + if (!_isBlurEnabled) + { + return false; + } + + if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2) + { + return true; + } + + return Environment.OSVersion.Version.Major > 6 && radius >= 20; + } + + /// + /// Use the GDI+ blur effect on the bitmap + /// + /// Bitmap to apply the effect to + /// Rectangle to apply the blur effect to + /// 0-255 + /// bool true if the edges are expanded with the radius + /// false if there is no GDI+ available or an exception occured + public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, int radius, bool expandEdges) + { + if (!IsBlurPossible(radius)) + { + return false; + } + + IntPtr hBlurParams = IntPtr.Zero; + IntPtr hEffect = IntPtr.Zero; + + try + { + // Create the GDI+ BlurEffect, using the Guid + int status = GdipCreateEffect(BlurEffectGuid, out hEffect); + if (status != 0) + { + return false; + } + + // Create a BlurParams struct and set the values + var blurParams = new BlurParams + { + Radius = radius, + ExpandEdges = expandEdges + }; + + // Allocate space in unmanaged memory + hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); + // Copy the structure to the unmanaged memory + Marshal.StructureToPtr(blurParams, hBlurParams, false); + + + // Set the blurParams to the effect + GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams)); + + // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! + // Get the private nativeImage property from the Bitmap + IntPtr hBitmap = GetNativeImage(destinationBitmap); + + // Create a RECT from the Rectangle + RECT rec = new RECT(area); + // Apply the effect to the bitmap in the specified area + GdipBitmapApplyEffect(hBitmap, hEffect, ref rec, false, IntPtr.Zero, 0); + + // Everything worked, return true + return true; + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem using GdipBitmapApplyEffect: ", ex); + return false; + } + finally + { + try + { + if (hEffect != IntPtr.Zero) + { + // Delete the effect + GdipDeleteEffect(hEffect); + } + + if (hBlurParams != IntPtr.Zero) + { + // Free the memory + Marshal.FreeHGlobal(hBlurParams); + } + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem cleaning up ApplyBlur: ", ex); + } + } + } + + /// + /// Draw the image on the graphics with GDI+ blur effect + /// + /// false if there is no GDI+ available or an exception occured + public static bool DrawWithBlur(Graphics graphics, Bitmap image, Rectangle source, Matrix transform, ImageAttributes imageAttributes, int radius, bool expandEdges) + { + if (!IsBlurPossible(radius)) + { + return false; + } + + IntPtr hBlurParams = IntPtr.Zero; + IntPtr hEffect = IntPtr.Zero; + + try + { + // Create the GDI+ BlurEffect, using the Guid + int status = GdipCreateEffect(BlurEffectGuid, out hEffect); + if (status != 0) + { + return false; + } + + // Create a BlurParams struct and set the values + var blurParams = new BlurParams + { + Radius = radius, + ExpandEdges = false + }; + //blurParams.Padding = radius; + + // Allocate space in unmanaged memory + hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); + // Copy the structure to the unmanaged memory + Marshal.StructureToPtr(blurParams, hBlurParams, true); + + // Set the blurParams to the effect + GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams)); + + // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! + // Get the private nativeImage property from the Bitmap + IntPtr hBitmap = GetNativeImage(image); + IntPtr hGraphics = GetNativeGraphics(graphics); + IntPtr hMatrix = GetNativeMatrix(transform); + IntPtr hAttributes = GetNativeImageAttributes(imageAttributes); + + // Create a RECT from the Rectangle + RECTF sourceRecf = new RECTF(source); + // Apply the effect to the bitmap in the specified area + GdipDrawImageFX(hGraphics, hBitmap, ref sourceRecf, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel); + + // Everything worked, return true + return true; + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem using GdipDrawImageFX: ", ex); + return false; + } + finally + { + try + { + if (hEffect != IntPtr.Zero) + { + // Delete the effect + GdipDeleteEffect(hEffect); + } + + if (hBlurParams != IntPtr.Zero) + { + // Free the memory + Marshal.FreeHGlobal(hBlurParams); + } + } + catch (Exception ex) + { + _isBlurEnabled = false; + Log.Error("Problem cleaning up DrawWithBlur: ", ex); + } + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs b/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs new file mode 100644 index 000000000..9e34b7341 --- /dev/null +++ b/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs @@ -0,0 +1,131 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; +using System.Text; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Description of Kernel32. + /// + public class Kernel32 + { + public const uint ATTACHCONSOLE_ATTACHPARENTPROCESS = 0x0ffffffff; // default value if not specifing a process ID + + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AttachConsole(uint dwProcessId); + + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AllocConsole(); + + [DllImport("kernel32", SetLastError = true)] + public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); + + [DllImport("kernel32", SetLastError = true)] + public static extern uint SuspendThread(IntPtr hThread); + + [DllImport("kernel32", SetLastError = true)] + public static extern int ResumeThread(IntPtr hThread); + + [DllImport("kernel32", SetLastError = true)] + public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, uint uuchMax); + + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseHandle(IntPtr hObject); + + /// + /// Method to get the process path + /// + /// + /// + public static string GetProcessPath(int processid) + { + StringBuilder _PathBuffer = new StringBuilder(512); + // Try the GetModuleFileName method first since it's the fastest. + // May return ACCESS_DENIED (due to VM_READ flag) if the process is not owned by the current user. + // Will fail if we are compiled as x86 and we're trying to open a 64 bit process...not allowed. + IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead, false, processid); + if (hprocess != IntPtr.Zero) + { + try + { + if (PsAPI.GetModuleFileNameEx(hprocess, IntPtr.Zero, _PathBuffer, (uint) _PathBuffer.Capacity) > 0) + { + return _PathBuffer.ToString(); + } + } + finally + { + CloseHandle(hprocess); + } + } + + hprocess = OpenProcess(ProcessAccessFlags.QueryInformation, false, processid); + if (hprocess != IntPtr.Zero) + { + try + { + // Try this method for Vista or higher operating systems + uint size = (uint) _PathBuffer.Capacity; + if ((Environment.OSVersion.Version.Major >= 6) && (QueryFullProcessImageName(hprocess, 0, _PathBuffer, ref size) && (size > 0))) + { + return _PathBuffer.ToString(); + } + + // Try the GetProcessImageFileName method + if (PsAPI.GetProcessImageFileName(hprocess, _PathBuffer, (uint) _PathBuffer.Capacity) > 0) + { + string dospath = _PathBuffer.ToString(); + foreach (string drive in Environment.GetLogicalDrives()) + { + if (QueryDosDevice(drive.TrimEnd('\\'), _PathBuffer, (uint) _PathBuffer.Capacity) > 0) + { + if (dospath.StartsWith(_PathBuffer.ToString())) + { + return drive + dospath.Remove(0, _PathBuffer.Length); + } + } + } + } + } + finally + { + CloseHandle(hprocess); + } + } + + return string.Empty; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs b/src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs similarity index 55% rename from GreenshotPlugin/UnmanagedHelpers/PsAPI.cs rename to src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs index 8b77f8d97..bafe9e28c 100644 --- a/GreenshotPlugin/UnmanagedHelpers/PsAPI.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs @@ -1,49 +1,56 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; -using log4net; - -namespace GreenshotPlugin.UnmanagedHelpers { - /// - /// Description of PsAPI. - /// - public class PsAPI { - private static readonly ILog LOG = LogManager.GetLogger(typeof(PsAPI)); - [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize); - [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint GetProcessImageFileName(IntPtr hProcess, StringBuilder lpImageFileName, uint nSize); - [DllImport("psapi")] - private static extern int EmptyWorkingSet(IntPtr hwProc); - - /// - /// Make the process use less memory by emptying the working set - /// - public static void EmptyWorkingSet() { - LOG.Info("Calling EmptyWorkingSet"); - using Process currentProcess = Process.GetCurrentProcess(); - EmptyWorkingSet(currentProcess.Handle); - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; +using log4net; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Description of PsAPI. + /// + public class PsAPI + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(PsAPI)); + + [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize); + + [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint GetProcessImageFileName(IntPtr hProcess, StringBuilder lpImageFileName, uint nSize); + + [DllImport("psapi")] + private static extern int EmptyWorkingSet(IntPtr hwProc); + + /// + /// Make the process use less memory by emptying the working set + /// + public static void EmptyWorkingSet() + { + LOG.Info("Calling EmptyWorkingSet"); + using Process currentProcess = Process.GetCurrentProcess(); + EmptyWorkingSet(currentProcess.Handle); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs b/src/Greenshot.Base/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs similarity index 69% rename from GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs rename to src/Greenshot.Base/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs index 6a4d02617..113117eae 100644 --- a/GreenshotPlugin/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs @@ -1,36 +1,45 @@ -using System; -using System.Security.Permissions; -using GreenshotPlugin.UnmanagedHelpers.Enums; -using log4net; -using Microsoft.Win32.SafeHandles; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// A SafeHandle class implementation for the current input desktop - /// - public class SafeCurrentInputDesktopHandle : SafeHandleZeroOrMinusOneIsInvalid { - private static readonly ILog LOG = LogManager.GetLogger(typeof(SafeCurrentInputDesktopHandle)); - - public SafeCurrentInputDesktopHandle() : base(true) { - IntPtr hDesktop = User32.OpenInputDesktop(0, true, DesktopAccessRight.GENERIC_ALL); - if (hDesktop != IntPtr.Zero) { - SetHandle(hDesktop); - if (User32.SetThreadDesktop(hDesktop)) { - LOG.DebugFormat("Switched to desktop {0}", hDesktop); - } else { - LOG.WarnFormat("Couldn't switch to desktop {0}", hDesktop); - LOG.Error(User32.CreateWin32Exception("SetThreadDesktop")); - } - } else { - LOG.Warn("Couldn't get current desktop."); - LOG.Error(User32.CreateWin32Exception("OpenInputDesktop")); - } - } - - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - protected override bool ReleaseHandle() { - return User32.CloseDesktop(handle); - } - } +using System; +using System.Security.Permissions; +using Greenshot.Base.UnmanagedHelpers.Enums; +using log4net; +using Microsoft.Win32.SafeHandles; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// A SafeHandle class implementation for the current input desktop + /// + public class SafeCurrentInputDesktopHandle : SafeHandleZeroOrMinusOneIsInvalid + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(SafeCurrentInputDesktopHandle)); + + public SafeCurrentInputDesktopHandle() : base(true) + { + IntPtr hDesktop = User32.OpenInputDesktop(0, true, DesktopAccessRight.GENERIC_ALL); + if (hDesktop != IntPtr.Zero) + { + SetHandle(hDesktop); + if (User32.SetThreadDesktop(hDesktop)) + { + LOG.DebugFormat("Switched to desktop {0}", hDesktop); + } + else + { + LOG.WarnFormat("Couldn't switch to desktop {0}", hDesktop); + LOG.Error(User32.CreateWin32Exception("SetThreadDesktop")); + } + } + else + { + LOG.Warn("Couldn't get current desktop."); + LOG.Error(User32.CreateWin32Exception("OpenInputDesktop")); + } + } + + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] + protected override bool ReleaseHandle() + { + return User32.CloseDesktop(handle); + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs b/src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs similarity index 77% rename from GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs rename to src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs index dbd3ef2a3..acb280287 100644 --- a/GreenshotPlugin/UnmanagedHelpers/SafeIconHandle.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs @@ -1,31 +1,33 @@ -using System; -using System.Security; -using System.Security.Permissions; -using Microsoft.Win32.SafeHandles; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// A SafeHandle class implementation for the hIcon - /// - public class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid { - - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeIconHandle() : base(true) - { - } - - - public SafeIconHandle(IntPtr hIcon) : base(true) { - SetHandle(hIcon); - } - - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - protected override bool ReleaseHandle() { - return User32.DestroyIcon(handle); - } - } +using System; +using System.Security; +using System.Security.Permissions; +using Microsoft.Win32.SafeHandles; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// A SafeHandle class implementation for the hIcon + /// + public class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid + { + /// + /// Needed for marshalling return values + /// + [SecurityCritical] + public SafeIconHandle() : base(true) + { + } + + + public SafeIconHandle(IntPtr hIcon) : base(true) + { + SetHandle(hIcon); + } + + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] + protected override bool ReleaseHandle() + { + return User32.DestroyIcon(handle); + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs b/src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs similarity index 87% rename from GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs rename to src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs index d9371ee4b..7ccdbf684 100644 --- a/GreenshotPlugin/UnmanagedHelpers/SafeWindowDcHandle.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs @@ -1,60 +1,66 @@ -using System; -using System.Runtime.InteropServices; -using System.Security; -using System.Security.Permissions; -using Microsoft.Win32.SafeHandles; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// A WindowDC SafeHandle implementation - /// - public class SafeWindowDcHandle : SafeHandleZeroOrMinusOneIsInvalid { - [DllImport("user32", SetLastError = true)] - private static extern IntPtr GetWindowDC(IntPtr hWnd); - [DllImport("user32", SetLastError = true)] - private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); - - private readonly IntPtr _hWnd; - - /// - /// Needed for marshalling return values - /// - public SafeWindowDcHandle() : base(true) - { - } - - [SecurityCritical] - public SafeWindowDcHandle(IntPtr hWnd, IntPtr preexistingHandle) : base(true) { - _hWnd = hWnd; - SetHandle(preexistingHandle); - } - - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)] - protected override bool ReleaseHandle() { - bool returnValue = ReleaseDC(_hWnd, handle); - return returnValue; - } - - /// - /// Creates a DC as SafeWindowDcHandle for the whole of the specified hWnd - /// - /// IntPtr - /// SafeWindowDcHandle - public static SafeWindowDcHandle FromWindow(IntPtr hWnd) - { - if (hWnd == IntPtr.Zero) - { - return null; - } - var hDcDesktop = GetWindowDC(hWnd); - return new SafeWindowDcHandle(hWnd, hDcDesktop); - } - - public static SafeWindowDcHandle FromDesktop() { - IntPtr hWndDesktop = User32.GetDesktopWindow(); - IntPtr hDCDesktop = GetWindowDC(hWndDesktop); - return new SafeWindowDcHandle(hWndDesktop, hDCDesktop); - } - } +using System; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Permissions; +using Microsoft.Win32.SafeHandles; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// A WindowDC SafeHandle implementation + /// + public class SafeWindowDcHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [DllImport("user32", SetLastError = true)] + private static extern IntPtr GetWindowDC(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); + + private readonly IntPtr _hWnd; + + /// + /// Needed for marshalling return values + /// + public SafeWindowDcHandle() : base(true) + { + } + + [SecurityCritical] + public SafeWindowDcHandle(IntPtr hWnd, IntPtr preexistingHandle) : base(true) + { + _hWnd = hWnd; + SetHandle(preexistingHandle); + } + + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] + protected override bool ReleaseHandle() + { + bool returnValue = ReleaseDC(_hWnd, handle); + return returnValue; + } + + /// + /// Creates a DC as SafeWindowDcHandle for the whole of the specified hWnd + /// + /// IntPtr + /// SafeWindowDcHandle + public static SafeWindowDcHandle FromWindow(IntPtr hWnd) + { + if (hWnd == IntPtr.Zero) + { + return null; + } + + var hDcDesktop = GetWindowDC(hWnd); + return new SafeWindowDcHandle(hWnd, hDcDesktop); + } + + public static SafeWindowDcHandle FromDesktop() + { + IntPtr hWndDesktop = User32.GetDesktopWindow(); + IntPtr hDCDesktop = GetWindowDC(hWndDesktop); + return new SafeWindowDcHandle(hWndDesktop, hDCDesktop); + } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Shell32.cs b/src/Greenshot.Base/UnmanagedHelpers/Shell32.cs new file mode 100644 index 000000000..14c603225 --- /dev/null +++ b/src/Greenshot.Base/UnmanagedHelpers/Shell32.cs @@ -0,0 +1,123 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Description of Shell32. + /// + public static class Shell32 + { + [DllImport("shell32", CharSet = CharSet.Unicode)] + public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons); + + [DllImport("shell32", CharSet = CharSet.Unicode)] + private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct SHFILEINFO + { + public readonly IntPtr hIcon; + public readonly int iIcon; + public readonly uint dwAttributes; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public readonly string szDisplayName; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] + public readonly string szTypeName; + }; + + // Browsing for directory. + + private const uint SHGFI_ICON = 0x000000100; // get icon + private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon + private const uint SHGFI_LARGEICON = 0x000000000; // get large icon + private const uint SHGFI_SMALLICON = 0x000000001; // get small icon + private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute + private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; + + /// + /// Options to specify the size of icons to return. + /// + public enum IconSize + { + /// + /// Specify large icon - 32 pixels by 32 pixels. + /// + Large = 0, + + /// + /// Specify small icon - 16 pixels by 16 pixels. + /// + Small = 1 + } + + /// + /// Returns an icon for a given file extension - indicated by the name parameter. + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx + /// + /// Filename + /// Large or small + /// Whether to include the link icon + /// System.Drawing.Icon + public static Icon GetFileIcon(string filename, IconSize size, bool linkOverlay) + { + SHFILEINFO shfi = new SHFILEINFO(); + // SHGFI_USEFILEATTRIBUTES makes it simulate, just gets the icon for the extension + uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; + + if (linkOverlay) + { + flags += SHGFI_LINKOVERLAY; + } + + // Check the size specified for return. + if (IconSize.Small == size) + { + flags += SHGFI_SMALLICON; + } + else + { + flags += SHGFI_LARGEICON; + } + + SHGetFileInfo(Path.GetFileName(filename), FILE_ATTRIBUTE_NORMAL, ref shfi, (uint) Marshal.SizeOf(shfi), flags); + + // Only return an icon if we really got one + if (shfi.hIcon != IntPtr.Zero) + { + // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly + Icon icon = (Icon) Icon.FromHandle(shfi.hIcon).Clone(); + // Cleanup + User32.DestroyIcon(shfi.hIcon); + return icon; + } + + return null; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/CursorInfo.cs similarity index 90% rename from GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/CursorInfo.cs index 7f18bf9ec..9974ddeb7 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/CursorInfo.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/CursorInfo.cs @@ -1,34 +1,35 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential)] - public struct CursorInfo { - public int cbSize; - public int flags; - public IntPtr hCursor; - public POINT ptScreenPos; - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential)] + public struct CursorInfo + { + public int cbSize; + public int flags; + public IntPtr hCursor; + public POINT ptScreenPos; + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs similarity index 91% rename from GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs index ae8629b4d..b7a430449 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/IconInfo.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs @@ -1,35 +1,36 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential)] - public struct IconInfo { - public bool fIcon; - public int xHotspot; - public int yHotspot; - public IntPtr hbmMask; - public IntPtr hbmColor; - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential)] + public struct IconInfo + { + public bool fIcon; + public int xHotspot; + public int yHotspot; + public IntPtr hbmMask; + public IntPtr hbmColor; + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/POINT.cs similarity index 77% rename from GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/POINT.cs index b94be1de4..a274933c7 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/POINT.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/POINT.cs @@ -1,58 +1,66 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct POINT { - public int X; - public int Y; - - public POINT(int x, int y) { - X = x; - Y = y; - } - public POINT(Point point) { - X = point.X; - Y = point.Y; - } - - public static implicit operator Point(POINT p) { - return new Point(p.X, p.Y); - } - - public static implicit operator POINT(Point p) { - return new POINT(p.X, p.Y); - } - - public Point ToPoint() { - return new Point(X, Y); - } - - public override string ToString() { - return X + "," + Y; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential), Serializable()] + public struct POINT + { + public int X; + public int Y; + + public POINT(int x, int y) + { + X = x; + Y = y; + } + + public POINT(Point point) + { + X = point.X; + Y = point.Y; + } + + public static implicit operator Point(POINT p) + { + return new Point(p.X, p.Y); + } + + public static implicit operator POINT(Point p) + { + return new POINT(p.X, p.Y); + } + + public Point ToPoint() + { + return new Point(X, Y); + } + + public override string ToString() + { + return X + "," + Y; + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/RECT.cs similarity index 55% rename from GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/RECT.cs index 5186f072b..f50b17544 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/RECT.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/RECT.cs @@ -1,169 +1,176 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct RECT { - private int _Left; - private int _Top; - private int _Right; - private int _Bottom; - - public RECT(RECT rectangle) - : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) { - } - public RECT(Rectangle rectangle) - : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) { - } - public RECT(int left, int top, int right, int bottom) { - _Left = left; - _Top = top; - _Right = right; - _Bottom = bottom; - } - - public int X { - get { - return _Left; - } - set { - _Left = value; - } - } - public int Y { - get { - return _Top; - } - set { - _Top = value; - } - } - public int Left { - get { - return _Left; - } - set { - _Left = value; - } - } - public int Top { - get { - return _Top; - } - set { - _Top = value; - } - } - public int Right { - get { - return _Right; - } - set { - _Right = value; - } - } - public int Bottom { - get { - return _Bottom; - } - set { - _Bottom = value; - } - } - public int Height { - get { - return _Bottom - _Top; - } - set { - _Bottom = value - _Top; - } - } - public int Width { - get { - return _Right - _Left; - } - set { - _Right = value + _Left; - } - } - public Point Location { - get { - return new Point(Left, Top); - } - set { - _Left = value.X; - _Top = value.Y; - } - } - public Size Size { - get { - return new Size(Width, Height); - } - set { - _Right = value.Width + _Left; - _Bottom = value.Height + _Top; - } - } - - public static implicit operator Rectangle(RECT rectangle) { - return new Rectangle(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height); - } - public static implicit operator RECT(Rectangle rectangle) { - return new RECT(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); - } - public static bool operator ==(RECT rectangle1, RECT rectangle2) { - return rectangle1.Equals(rectangle2); - } - public static bool operator !=(RECT rectangle1, RECT rectangle2) { - return !rectangle1.Equals(rectangle2); - } - - public override string ToString() { - return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}"; - } - - public override int GetHashCode() { - return ToString().GetHashCode(); - } - - public bool Equals(RECT rectangle) { - return rectangle.Left == _Left && rectangle.Top == _Top && rectangle.Right == _Right && rectangle.Bottom == _Bottom; - } - - public Rectangle ToRectangle() { - return new Rectangle(Left, Top, Width, Height); - } - public override bool Equals(object Object) { - if (Object is RECT) { - return Equals((RECT)Object); - } else if (Object is Rectangle) { - return Equals(new RECT((Rectangle)Object)); - } - - return false; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential), Serializable()] + public struct RECT + { + private int _Left; + private int _Top; + private int _Right; + private int _Bottom; + + public RECT(RECT rectangle) + : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) + { + } + + public RECT(Rectangle rectangle) + : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) + { + } + + public RECT(int left, int top, int right, int bottom) + { + _Left = left; + _Top = top; + _Right = right; + _Bottom = bottom; + } + + public int X + { + get { return _Left; } + set { _Left = value; } + } + + public int Y + { + get { return _Top; } + set { _Top = value; } + } + + public int Left + { + get { return _Left; } + set { _Left = value; } + } + + public int Top + { + get { return _Top; } + set { _Top = value; } + } + + public int Right + { + get { return _Right; } + set { _Right = value; } + } + + public int Bottom + { + get { return _Bottom; } + set { _Bottom = value; } + } + + public int Height + { + get { return _Bottom - _Top; } + set { _Bottom = value - _Top; } + } + + public int Width + { + get { return _Right - _Left; } + set { _Right = value + _Left; } + } + + public Point Location + { + get { return new Point(Left, Top); } + set + { + _Left = value.X; + _Top = value.Y; + } + } + + public Size Size + { + get { return new Size(Width, Height); } + set + { + _Right = value.Width + _Left; + _Bottom = value.Height + _Top; + } + } + + public static implicit operator Rectangle(RECT rectangle) + { + return new Rectangle(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height); + } + + public static implicit operator RECT(Rectangle rectangle) + { + return new RECT(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); + } + + public static bool operator ==(RECT rectangle1, RECT rectangle2) + { + return rectangle1.Equals(rectangle2); + } + + public static bool operator !=(RECT rectangle1, RECT rectangle2) + { + return !rectangle1.Equals(rectangle2); + } + + public override string ToString() + { + return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}"; + } + + public override int GetHashCode() + { + return ToString().GetHashCode(); + } + + public bool Equals(RECT rectangle) + { + return rectangle.Left == _Left && rectangle.Top == _Top && rectangle.Right == _Right && rectangle.Bottom == _Bottom; + } + + public Rectangle ToRectangle() + { + return new Rectangle(Left, Top, Width, Height); + } + + public override bool Equals(object Object) + { + if (Object is RECT) + { + return Equals((RECT) Object); + } + else if (Object is Rectangle) + { + return Equals(new RECT((Rectangle) Object)); + } + + return false; + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/RECTF.cs similarity index 88% rename from GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/RECTF.cs index 471d0c4cb..2434e9266 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/RECTF.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/RECTF.cs @@ -1,123 +1,131 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - /// - /// A floating point GDI Plus width/hight based rectangle. - /// - [StructLayout(LayoutKind.Sequential)] - public struct RECTF { - /// - /// The X corner location of the rectangle. - /// - public float X; - - /// - /// The Y corner location of the rectangle. - /// - public float Y; - - /// - /// The width of the rectangle. - /// - public float Width; - - /// - /// The height of the rectangle. - /// - public float Height; - - /// - /// Creates a new GDI Plus rectangle. - /// - /// The X corner location of the rectangle. - /// The Y corner location of the rectangle. - /// The width of the rectangle. - /// The height of the rectangle. - public RECTF(float x, float y, float width, float height) { - X = x; - Y = y; - Width = width; - Height = height; - } - - /// - /// Creates a new GDI Plus rectangle from a System.Drawing.RectangleF. - /// - /// The rectangle to base this GDI Plus rectangle on. - public RECTF(RectangleF rect) { - X = rect.X; - Y = rect.Y; - Width = rect.Width; - Height = rect.Height; - } - - /// - /// Creates a new GDI Plus rectangle from a System.Drawing.Rectangle. - /// - /// The rectangle to base this GDI Plus rectangle on. - public RECTF(Rectangle rect) { - X = rect.X; - Y = rect.Y; - Width = rect.Width; - Height = rect.Height; - } - - /// - /// Returns a RectangleF for this GDI Plus rectangle. - /// - /// A System.Drawing.RectangleF structure. - public RectangleF ToRectangle() { - return new RectangleF(X, Y, Width, Height); - } - - /// - /// Returns a RectangleF for a GDI Plus rectangle. - /// - /// The GDI Plus rectangle to get the RectangleF for. - /// A System.Drawing.RectangleF structure. - public static RectangleF ToRectangle(RECTF rect) { - return rect.ToRectangle(); - } - - /// - /// Returns a GDI Plus rectangle for a RectangleF structure. - /// - /// The RectangleF to get the GDI Plus rectangle for. - /// A GDI Plus rectangle structure. - public static RECTF FromRectangle(RectangleF rect) { - return new RECTF(rect); - } - - /// - /// Returns a GDI Plus rectangle for a Rectangle structure. - /// - /// The Rectangle to get the GDI Plus rectangle for. - /// A GDI Plus rectangle structure. - public static RECTF FromRectangle(Rectangle rect) { - return new RECTF(rect); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + /// + /// A floating point GDI Plus width/hight based rectangle. + /// + [StructLayout(LayoutKind.Sequential)] + public struct RECTF + { + /// + /// The X corner location of the rectangle. + /// + public float X; + + /// + /// The Y corner location of the rectangle. + /// + public float Y; + + /// + /// The width of the rectangle. + /// + public float Width; + + /// + /// The height of the rectangle. + /// + public float Height; + + /// + /// Creates a new GDI Plus rectangle. + /// + /// The X corner location of the rectangle. + /// The Y corner location of the rectangle. + /// The width of the rectangle. + /// The height of the rectangle. + public RECTF(float x, float y, float width, float height) + { + X = x; + Y = y; + Width = width; + Height = height; + } + + /// + /// Creates a new GDI Plus rectangle from a System.Drawing.RectangleF. + /// + /// The rectangle to base this GDI Plus rectangle on. + public RECTF(RectangleF rect) + { + X = rect.X; + Y = rect.Y; + Width = rect.Width; + Height = rect.Height; + } + + /// + /// Creates a new GDI Plus rectangle from a System.Drawing.Rectangle. + /// + /// The rectangle to base this GDI Plus rectangle on. + public RECTF(Rectangle rect) + { + X = rect.X; + Y = rect.Y; + Width = rect.Width; + Height = rect.Height; + } + + /// + /// Returns a RectangleF for this GDI Plus rectangle. + /// + /// A System.Drawing.RectangleF structure. + public RectangleF ToRectangle() + { + return new RectangleF(X, Y, Width, Height); + } + + /// + /// Returns a RectangleF for a GDI Plus rectangle. + /// + /// The GDI Plus rectangle to get the RectangleF for. + /// A System.Drawing.RectangleF structure. + public static RectangleF ToRectangle(RECTF rect) + { + return rect.ToRectangle(); + } + + /// + /// Returns a GDI Plus rectangle for a RectangleF structure. + /// + /// The RectangleF to get the GDI Plus rectangle for. + /// A GDI Plus rectangle structure. + public static RECTF FromRectangle(RectangleF rect) + { + return new RECTF(rect); + } + + /// + /// Returns a GDI Plus rectangle for a Rectangle structure. + /// + /// The Rectangle to get the GDI Plus rectangle for. + /// A GDI Plus rectangle structure. + public static RECTF FromRectangle(Rectangle rect) + { + return new RECTF(rect); + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/SCROLLINFO.cs similarity index 91% rename from GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/SCROLLINFO.cs index 0a6451b23..718abebcf 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/SCROLLINFO.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/SCROLLINFO.cs @@ -1,37 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - [Serializable, StructLayout(LayoutKind.Sequential)] - public struct SCROLLINFO { - public int cbSize; - public int fMask; - public int nMin; - public int nMax; - public int nPage; - public int nPos; - public int nTrackPos; - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [Serializable, StructLayout(LayoutKind.Sequential)] + public struct SCROLLINFO + { + public int cbSize; + public int fMask; + public int nMin; + public int nMax; + public int nPage; + public int nPos; + public int nTrackPos; + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/SIZE.cs similarity index 64% rename from GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/SIZE.cs index bd1b78699..93d583c4c 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/SIZE.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/SIZE.cs @@ -1,46 +1,51 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs { - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct SIZE { - public int Width; - public int Height; - public SIZE(Size size) : this(size.Width, size.Height) { - - } - - public SIZE(int width, int height) { - Width = width; - Height = height; - } - - public Size ToSize() { - return new Size(Width, Height); - } - - public bool IsEmpty => Width * Height == 0; - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + [StructLayout(LayoutKind.Sequential), Serializable()] + public struct SIZE + { + public int Width; + public int Height; + + public SIZE(Size size) : this(size.Width, size.Height) + { + } + + public SIZE(int width, int height) + { + Width = width; + Height = height; + } + + public Size ToSize() + { + return new Size(Width, Height); + } + + public bool IsEmpty => Width * Height == 0; + } +} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowInfo.cs similarity index 87% rename from GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/WindowInfo.cs index 532d597a3..ad8c60812 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/WindowInfo.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowInfo.cs @@ -1,48 +1,52 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - /// - /// The structure for the WindowInfo - /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632610%28v=vs.85%29.aspx - /// - [StructLayout(LayoutKind.Sequential), Serializable] - public struct WindowInfo { - public uint cbSize; - public RECT rcWindow; - public RECT rcClient; - public uint dwStyle; - public uint dwExStyle; - public uint dwWindowStatus; - public uint cxWindowBorders; - public uint cyWindowBorders; - public ushort atomWindowType; - public ushort wCreatorVersion; - // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)". - public WindowInfo(bool? filler) : this() { - cbSize = (uint)(Marshal.SizeOf(typeof(WindowInfo))); - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + /// + /// The structure for the WindowInfo + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632610%28v=vs.85%29.aspx + /// + [StructLayout(LayoutKind.Sequential), Serializable] + public struct WindowInfo + { + public uint cbSize; + public RECT rcWindow; + public RECT rcClient; + public uint dwStyle; + public uint dwExStyle; + public uint dwWindowStatus; + public uint cxWindowBorders; + public uint cyWindowBorders; + public ushort atomWindowType; + + public ushort wCreatorVersion; + + // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)". + public WindowInfo(bool? filler) : this() + { + cbSize = (uint) (Marshal.SizeOf(typeof(WindowInfo))); + } + } } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowPlacement.cs similarity index 90% rename from GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs rename to src/Greenshot.Base/UnmanagedHelpers/Structs/WindowPlacement.cs index 1a7de8ebb..fa981b8bf 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Structs/WindowPlacement.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowPlacement.cs @@ -1,77 +1,80 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.UnmanagedHelpers.Structs -{ - /// - /// Contains information about the placement of a window on the screen. - /// - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct WindowPlacement { - /// - /// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT). - /// - /// GetWindowPlacement and SetWindowPlacement fail if this member is not set correctly. - /// - /// - public int Length; - - /// - /// Specifies flags that control the position of the minimized window and the method by which the window is restored. - /// - public WindowPlacementFlags Flags; - - /// - /// The current show state of the window. - /// - public ShowWindowCommand ShowCmd; - - /// - /// The coordinates of the window's upper-left corner when the window is minimized. - /// - public POINT MinPosition; - - /// - /// The coordinates of the window's upper-left corner when the window is maximized. - /// - public POINT MaxPosition; - - /// - /// The window's coordinates when the window is in the restored position. - /// - public RECT NormalPosition; - - /// - /// Gets the default (empty) value. - /// - public static WindowPlacement Default { - get { - WindowPlacement result = new WindowPlacement(); - result.Length = Marshal.SizeOf(result); - return result; - } - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.UnmanagedHelpers.Structs +{ + /// + /// Contains information about the placement of a window on the screen. + /// + [StructLayout(LayoutKind.Sequential), Serializable()] + public struct WindowPlacement + { + /// + /// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT). + /// + /// GetWindowPlacement and SetWindowPlacement fail if this member is not set correctly. + /// + /// + public int Length; + + /// + /// Specifies flags that control the position of the minimized window and the method by which the window is restored. + /// + public WindowPlacementFlags Flags; + + /// + /// The current show state of the window. + /// + public ShowWindowCommand ShowCmd; + + /// + /// The coordinates of the window's upper-left corner when the window is minimized. + /// + public POINT MinPosition; + + /// + /// The coordinates of the window's upper-left corner when the window is maximized. + /// + public POINT MaxPosition; + + /// + /// The window's coordinates when the window is in the restored position. + /// + public RECT NormalPosition; + + /// + /// Gets the default (empty) value. + /// + public static WindowPlacement Default + { + get + { + WindowPlacement result = new WindowPlacement(); + result.Length = Marshal.SizeOf(result); + return result; + } + } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/User32.cs b/src/Greenshot.Base/UnmanagedHelpers/User32.cs new file mode 100644 index 000000000..1f6c39c24 --- /dev/null +++ b/src/Greenshot.Base/UnmanagedHelpers/User32.cs @@ -0,0 +1,333 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using Greenshot.Base.Core.Enums; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; +using log4net; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// User32 Wrappers + /// + public static class User32 + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(User32)); + private static bool _CanCallGetPhysicalCursorPos = true; + public const int SC_RESTORE = 0xF120; + public const int SC_MAXIMIZE = 0xF030; + public const int SC_MINIMIZE = 0xF020; + + // For MonitorFromWindow + public const int MONITOR_DEFAULTTONULL = 0; + public const int MONITOR_DEFAULTTONEAREST = 2; + public const int CURSOR_SHOWING = 0x00000001; + + /// + /// Determines whether the specified window handle identifies an existing window. + /// + /// A handle to the window to be tested. + /// + /// If the window handle identifies an existing window, the return value is true. + /// If the window handle does not identify an existing window, the return value is false. + /// + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindow(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindowVisible(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId); + + [DllImport("user32", SetLastError = true)] + public static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId); + + [DllImport("user32")] + public static extern IntPtr AttachThreadInput(int idAttach, int idAttachTo, int fAttach); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetParent(IntPtr hWnd); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int cch); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool BringWindowToTop(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetDesktopWindow(); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetForegroundWindow(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WindowPlacement lpwndpl); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsIconic(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsZoomed(IntPtr hWnd); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); + + [DllImport("user32", SetLastError = true)] + public static extern uint GetClassLong(IntPtr hWnd, int nIndex); + + [DllImport("user32", SetLastError = true, EntryPoint = "GetClassLongPtr")] + public static extern IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, uint nFlags); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); + + [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")] + public static extern int GetWindowLong(IntPtr hWnd, int index); + + [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")] + public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); + + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int SetWindowLong(IntPtr hWnd, int index, int styleFlags); + + [DllImport("user32", SetLastError = true, EntryPoint = "SetWindowLongPtr")] + public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int index, IntPtr styleFlags); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr MonitorFromWindow(IntPtr hWnd, MonitorFrom dwFlags); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowInfo(IntPtr hWnd, ref WindowInfo pwi); + + [DllImport("user32", SetLastError = true)] + public static extern int EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); + + [DllImport("user32", SetLastError = true)] + public static extern RegionResult GetWindowRgn(IntPtr hWnd, SafeHandle hRgn); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, WindowPos uFlags); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr GetClipboardOwner(); + + // Added for finding Metro apps, Greenshot 1.1 + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow); + + /// uiFlags: 0 - Count of GDI objects + /// uiFlags: 1 - Count of USER objects + /// - Win32 GDI objects (pens, brushes, fonts, palettes, regions, device contexts, bitmap headers) + /// - Win32 USER objects: + /// - WIN32 resources (accelerator tables, bitmap resources, dialog box templates, font resources, menu resources, raw data resources, string table entries, message table entries, cursors/icons) + /// - Other USER objects (windows, menus) + /// + [DllImport("user32", SetLastError = true)] + public static extern uint GetGuiResources(IntPtr hProcess, uint uiFlags); + + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern uint RegisterWindowMessage(string lpString); + + [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult); + + [DllImport("user32", SetLastError = true)] + private static extern bool GetPhysicalCursorPos(out POINT cursorLocation); + + /// + /// The following is used for Icon handling + /// + /// + /// + [DllImport("user32", SetLastError = true)] + public static extern SafeIconHandle CopyIcon(IntPtr hIcon); + + [DllImport("user32", SetLastError = true)] + public static extern bool DestroyIcon(IntPtr hIcon); + + [DllImport("user32", SetLastError = true)] + public static extern bool GetCursorInfo(out CursorInfo cursorInfo); + + [DllImport("user32", SetLastError = true)] + public static extern bool GetIconInfo(SafeIconHandle iconHandle, out IconInfo iconInfo); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr SetCapture(IntPtr hWnd); + + [DllImport("user32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ReleaseCapture(); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr CreateIconIndirect(ref IconInfo icon); + + [DllImport("user32", SetLastError = true)] + public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, DesktopAccessRight dwDesiredAccess); + + [DllImport("user32", SetLastError = true)] + public static extern bool SetThreadDesktop(IntPtr hDesktop); + + [DllImport("user32", SetLastError = true)] + public static extern bool CloseDesktop(IntPtr hDesktop); + + /// + /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. + /// + /// Point with cursor location, relative to the origin of the monitor setup + /// (i.e. negative coordinates arepossible in multiscreen setups) + public static Point GetCursorLocation() + { + if (Environment.OSVersion.Version.Major >= 6 && _CanCallGetPhysicalCursorPos) + { + try + { + if (GetPhysicalCursorPos(out var cursorLocation)) + { + return new Point(cursorLocation.X, cursorLocation.Y); + } + + Win32Error error = Win32.GetLastErrorCode(); + LOG.ErrorFormat("Error retrieving PhysicalCursorPos : {0}", Win32.GetMessage(error)); + } + catch (Exception ex) + { + LOG.Error("Exception retrieving PhysicalCursorPos, no longer calling this. Cause :", ex); + _CanCallGetPhysicalCursorPos = false; + } + } + + return new Point(Cursor.Position.X, Cursor.Position.Y); + } + + /// + /// Wrapper for the GetClassLong which decides if the system is 64-bit or not and calls the right one. + /// + /// IntPtr + /// int + /// IntPtr + public static IntPtr GetClassLongWrapper(IntPtr hWnd, int nIndex) + { + if (IntPtr.Size > 4) + { + return GetClassLongPtr(hWnd, nIndex); + } + else + { + return new IntPtr(GetClassLong(hWnd, nIndex)); + } + } + + /// + /// Wrapper for the GetWindowLong which decides if the system is 64-bit or not and calls the right one. + /// + /// + /// + /// + public static long GetWindowLongWrapper(IntPtr hWnd, int nIndex) + { + if (IntPtr.Size == 8) + { + return GetWindowLongPtr(hWnd, nIndex).ToInt64(); + } + else + { + return GetWindowLong(hWnd, nIndex); + } + } + + /// + /// Wrapper for the SetWindowLong which decides if the system is 64-bit or not and calls the right one. + /// + /// + /// + /// + public static void SetWindowLongWrapper(IntPtr hWnd, int nIndex, IntPtr styleFlags) + { + if (IntPtr.Size == 8) + { + SetWindowLongPtr(hWnd, nIndex, styleFlags); + } + else + { + SetWindowLong(hWnd, nIndex, styleFlags.ToInt32()); + } + } + + public static uint GetGuiResourcesGDICount() + { + using var currentProcess = Process.GetCurrentProcess(); + return GetGuiResources(currentProcess.Handle, 0); + } + + public static uint GetGuiResourcesUserCount() + { + using var currentProcess = Process.GetCurrentProcess(); + return GetGuiResources(currentProcess.Handle, 1); + } + + /// + /// Helper method to create a Win32 exception with the windows message in it + /// + /// string with current method + /// Exception + public static Exception CreateWin32Exception(string method) + { + var exceptionToThrow = new Win32Exception(); + exceptionToThrow.Data.Add("Method", method); + return exceptionToThrow; + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/Win32.cs b/src/Greenshot.Base/UnmanagedHelpers/Win32.cs similarity index 62% rename from GreenshotPlugin/UnmanagedHelpers/Win32.cs rename to src/Greenshot.Base/UnmanagedHelpers/Win32.cs index 7efb73292..940dc4e95 100644 --- a/GreenshotPlugin/UnmanagedHelpers/Win32.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Win32.cs @@ -1,63 +1,69 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Runtime.InteropServices; -using System.Text; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.UnmanagedHelpers { - public static class Win32 { - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - private static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer, int nSize, IntPtr arguments); - - [DllImport("kernel32.dll")] - public static extern void SetLastError(uint dwErrCode); - - public static Win32Error GetLastErrorCode() { - return (Win32Error)Marshal.GetLastWin32Error(); - } - - public static string GetMessage(Win32Error errorCode) { - var buffer = new StringBuilder(0x100); - - if (FormatMessage(0x3200, IntPtr.Zero, (uint)errorCode, 0, buffer, buffer.Capacity, IntPtr.Zero) == 0) { - return "Unknown error (0x" + ((int)errorCode).ToString("x") + ")"; - } - - var result = new StringBuilder(); - int i = 0; - - while (i < buffer.Length) { - if (!char.IsLetterOrDigit(buffer[i]) && - !char.IsPunctuation(buffer[i]) && - !char.IsSymbol(buffer[i]) && - !char.IsWhiteSpace(buffer[i])) - break; - - result.Append(buffer[i]); - i++; - } - - return result.ToString().Replace("\r\n", string.Empty); - } - } -} - +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; +using System.Text; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.UnmanagedHelpers +{ + public static class Win32 + { + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + private static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer, int nSize, IntPtr arguments); + + [DllImport("kernel32.dll")] + public static extern void SetLastError(uint dwErrCode); + + public static Win32Error GetLastErrorCode() + { + return (Win32Error) Marshal.GetLastWin32Error(); + } + + public static string GetMessage(Win32Error errorCode) + { + var buffer = new StringBuilder(0x100); + + if (FormatMessage(0x3200, IntPtr.Zero, (uint) errorCode, 0, buffer, buffer.Capacity, IntPtr.Zero) == 0) + { + return "Unknown error (0x" + ((int) errorCode).ToString("x") + ")"; + } + + var result = new StringBuilder(); + int i = 0; + + while (i < buffer.Length) + { + if (!char.IsLetterOrDigit(buffer[i]) && + !char.IsPunctuation(buffer[i]) && + !char.IsSymbol(buffer[i]) && + !char.IsWhiteSpace(buffer[i])) + break; + + result.Append(buffer[i]); + i++; + } + + return result.ToString().Replace("\r\n", string.Empty); + } + } +} \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs b/src/Greenshot.Base/UnmanagedHelpers/WinEventDelegate.cs similarity index 84% rename from GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs rename to src/Greenshot.Base/UnmanagedHelpers/WinEventDelegate.cs index 551b75410..bd54923f7 100644 --- a/GreenshotPlugin/UnmanagedHelpers/WinEventDelegate.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/WinEventDelegate.cs @@ -1,17 +1,17 @@ -using System; -using GreenshotPlugin.UnmanagedHelpers.Enums; - -namespace GreenshotPlugin.UnmanagedHelpers -{ - /// - /// Used with SetWinEventHook - /// - /// - /// - /// - /// - /// - /// - /// - public delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); +using System; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Used with SetWinEventHook + /// + /// + /// + /// + /// + /// + /// + /// + public delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); } \ No newline at end of file diff --git a/GreenshotPlugin/UnmanagedHelpers/WinMM.cs b/src/Greenshot.Base/UnmanagedHelpers/WinMM.cs similarity index 68% rename from GreenshotPlugin/UnmanagedHelpers/WinMM.cs rename to src/Greenshot.Base/UnmanagedHelpers/WinMM.cs index 71e8f6b7b..411ecdca1 100644 --- a/GreenshotPlugin/UnmanagedHelpers/WinMM.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/WinMM.cs @@ -1,35 +1,38 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: http://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -using System; -using System.Runtime.InteropServices; - -namespace GreenshotPlugin.UnmanagedHelpers { - /// - /// Windows Media - /// - public class WinMM { - [DllImport("winmm.dll", SetLastError = true)] - public static extern bool PlaySound(byte[] ptrToSound, UIntPtr hmod, uint fdwSound); - - [DllImport("winmm.dll", SetLastError = true)] - public static extern bool PlaySound(IntPtr ptrToSound, UIntPtr hmod, uint fdwSound); - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices; + +namespace Greenshot.Base.UnmanagedHelpers +{ + /// + /// Windows Media + /// + public class WinMM + { + [DllImport("winmm.dll", SetLastError = true)] + public static extern bool PlaySound(byte[] ptrToSound, UIntPtr hmod, uint fdwSound); + + [DllImport("winmm.dll", SetLastError = true)] + public static extern bool PlaySound(IntPtr ptrToSound, UIntPtr hmod, uint fdwSound); + } +} \ No newline at end of file diff --git a/GreenshotPlugin/log4net-embedded.xml b/src/Greenshot.Base/log4net-embedded.xml similarity index 97% rename from GreenshotPlugin/log4net-embedded.xml rename to src/Greenshot.Base/log4net-embedded.xml index ccfa902a7..b4ced5bad 100644 --- a/GreenshotPlugin/log4net-embedded.xml +++ b/src/Greenshot.Base/log4net-embedded.xml @@ -1,21 +1,21 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/GreenshotBoxPlugin/Box.png b/src/Greenshot.Plugin.Box/Box.png similarity index 100% rename from GreenshotBoxPlugin/Box.png rename to src/Greenshot.Plugin.Box/Box.png diff --git a/src/Greenshot.Plugin.Box/BoxConfiguration.cs b/src/Greenshot.Plugin.Box/BoxConfiguration.cs new file mode 100644 index 000000000..15e458109 --- /dev/null +++ b/src/Greenshot.Plugin.Box/BoxConfiguration.cs @@ -0,0 +1,79 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Plugin.Box.Forms; + +namespace Greenshot.Plugin.Box +{ + /// + /// Description of ImgurConfiguration. + /// + [IniSection("Box", Description = "Greenshot Box Plugin configuration")] + public class BoxConfiguration : IniSection + { + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Box link to clipboard.", DefaultValue = "true")] + public bool AfterUploadLinkToClipBoard { get; set; } + + [IniProperty("UseSharedLink", Description = "Use the shared link, instead of the private, on the clipboard", DefaultValue = "True")] + public bool UseSharedLink { get; set; } + + [IniProperty("FolderId", Description = "Folder ID to upload to, only change if you know what you are doing!", DefaultValue = "0")] + public string FolderId { get; set; } + + [IniProperty("RefreshToken", Description = "Box authorization refresh Token", Encrypted = true)] + public string RefreshToken { get; set; } + + /// + /// Not stored + /// + public string AccessToken { get; set; } + + /// + /// Not stored + /// + public DateTimeOffset AccessTokenExpires { get; set; } + + /// + /// A form for token + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + DialogResult result = new SettingsForm().ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/BoxDestination.cs b/src/Greenshot.Plugin.Box/BoxDestination.cs new file mode 100644 index 000000000..989c0aad0 --- /dev/null +++ b/src/Greenshot.Plugin.Box/BoxDestination.cs @@ -0,0 +1,65 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Plugin.Box +{ + public class BoxDestination : AbstractDestination + { + private readonly BoxPlugin _plugin; + + public BoxDestination(BoxPlugin plugin) + { + _plugin = plugin; + } + + public override string Designation => "Box"; + + public override string Description => Language.GetString("box", LangKey.upload_menu_item); + + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(BoxPlugin)); + return (Image) resources.GetObject("Box"); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + string uploadUrl = _plugin.Upload(captureDetails, surface); + if (uploadUrl != null) + { + exportInformation.ExportMade = true; + exportInformation.Uri = uploadUrl; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/BoxEntities.cs b/src/Greenshot.Plugin.Box/BoxEntities.cs new file mode 100644 index 000000000..d99612377 --- /dev/null +++ b/src/Greenshot.Plugin.Box/BoxEntities.cs @@ -0,0 +1,56 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Greenshot.Plugin.Box +{ + [DataContract] + public class Authorization + { + [DataMember(Name = "access_token")] public string AccessToken { get; set; } + [DataMember(Name = "expires_in")] public int ExpiresIn { get; set; } + [DataMember(Name = "refresh_token")] public string RefreshToken { get; set; } + [DataMember(Name = "token_type")] public string TokenType { get; set; } + } + + [DataContract] + public class SharedLink + { + [DataMember(Name = "url")] public string Url { get; set; } + [DataMember(Name = "download_url")] public string DownloadUrl { get; set; } + } + + [DataContract] + public class FileEntry + { + [DataMember(Name = "id")] public string Id { get; set; } + [DataMember(Name = "name")] public string Name { get; set; } + [DataMember(Name = "shared_link")] public SharedLink SharedLink { get; set; } + } + + [DataContract] + public class Upload + { + [DataMember(Name = "entries")] public List Entries { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/BoxPlugin.cs b/src/Greenshot.Plugin.Box/BoxPlugin.cs new file mode 100644 index 000000000..8aba68183 --- /dev/null +++ b/src/Greenshot.Plugin.Box/BoxPlugin.cs @@ -0,0 +1,140 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Plugin.Box +{ + /// + /// This is the Box base code + /// + [Plugin("Box", true)] + public class BoxPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BoxPlugin)); + private static BoxConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInConfig; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + if (!disposing) return; + + if (_itemPlugInConfig == null) return; + + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + public bool Initialize() + { + // Register configuration (don't need the configuration itself) + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(BoxPlugin)); + SimpleServiceProvider.Current.AddService(new BoxDestination(this)); + _itemPlugInConfig = new ToolStripMenuItem + { + Image = (Image) _resources.GetObject("Box"), + Text = Language.GetString("box", LangKey.Configure) + }; + _itemPlugInConfig.Click += ConfigMenuClick; + + PluginUtils.AddToContextMenu(_itemPlugInConfig); + Language.LanguageChanged += OnLanguageChanged; + return true; + } + + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Text = Language.GetString("box", LangKey.Configure); + } + } + + public void Shutdown() + { + LOG.Debug("Box Plugin shutdown."); + } + + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + _config.ShowConfigDialog(); + } + + public void ConfigMenuClick(object sender, EventArgs eventArgs) + { + _config.ShowConfigDialog(); + } + + /// + /// This will be called when the menu item in the Editor is clicked + /// + public string Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload) + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); + try + { + string url = null; + string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); + SurfaceContainer imageToUpload = new SurfaceContainer(surfaceToUpload, outputSettings, filename); + + new PleaseWaitForm().ShowAndWait("Box", Language.GetString("box", LangKey.communication_wait), + delegate { url = BoxUtils.UploadToBox(imageToUpload, captureDetails.Title, filename); } + ); + + if (url != null && _config.AfterUploadLinkToClipBoard) + { + ClipboardHelper.SetClipboardData(url); + } + + return url; + } + catch (Exception ex) + { + LOG.Error("Error uploading.", ex); + MessageBox.Show(Language.GetString("box", LangKey.upload_failure) + " " + ex.Message); + return null; + } + } + } +} \ No newline at end of file diff --git a/GreenshotBoxPlugin/BoxPlugin.resx b/src/Greenshot.Plugin.Box/BoxPlugin.resx similarity index 100% rename from GreenshotBoxPlugin/BoxPlugin.resx rename to src/Greenshot.Plugin.Box/BoxPlugin.resx diff --git a/src/Greenshot.Plugin.Box/BoxUtils.cs b/src/Greenshot.Plugin.Box/BoxUtils.cs new file mode 100644 index 000000000..4634d845e --- /dev/null +++ b/src/Greenshot.Plugin.Box/BoxUtils.cs @@ -0,0 +1,154 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization.Json; +using System.Text; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.Box +{ + /// + /// Description of BoxUtils. + /// + public static class BoxUtils + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(BoxUtils)); + private static readonly BoxConfiguration Config = IniConfig.GetIniSection(); + private const string UploadFileUri = "https://upload.box.com/api/2.0/files/content"; + private const string FilesUri = "https://www.box.com/api/2.0/files/{0}"; + + /// + /// Put string + /// + /// + /// + /// OAuth2Settings + /// response + public static string HttpPut(string url, string content, OAuth2Settings settings) + { + var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.PUT, url, settings); + + byte[] data = Encoding.UTF8.GetBytes(content); + using (var requestStream = webRequest.GetRequestStream()) + { + requestStream.Write(data, 0, data.Length); + } + + return NetworkHelper.GetResponseAsString(webRequest); + } + + /// + /// Do the actual upload to Box + /// For more details on the available parameters, see: http://developers.box.net/w/page/12923951/ApiFunction_Upload%20and%20Download + /// + /// Image for box upload + /// Title of box upload + /// Filename of box upload + /// url to uploaded image + public static string UploadToBox(SurfaceContainer image, string title, string filename) + { + // Fill the OAuth2Settings + var settings = new OAuth2Settings + { + AuthUrlPattern = "https://app.box.com/api/oauth2/authorize?client_id={ClientId}&response_type=code&state={State}&redirect_uri={RedirectUrl}", + TokenUrl = "https://api.box.com/oauth2/token", + CloudServiceName = "Box", + ClientId = BoxCredentials.ClientId, + ClientSecret = BoxCredentials.ClientSecret, + RedirectUrl = "https://getgreenshot.org/authorize/box", + AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, + RefreshToken = Config.RefreshToken, + AccessToken = Config.AccessToken, + AccessTokenExpires = Config.AccessTokenExpires + }; + + + // Copy the settings from the config, which is kept in memory and on the disk + + try + { + var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, UploadFileUri, settings); + IDictionary parameters = new Dictionary + { + { + "file", image + }, + { + "parent_id", Config.FolderId + } + }; + + NetworkHelper.WriteMultipartFormData(webRequest, parameters); + + var response = NetworkHelper.GetResponseAsString(webRequest); + + Log.DebugFormat("Box response: {0}", response); + + var upload = JsonSerializer.Deserialize(response); + if (upload?.Entries == null || upload.Entries.Count == 0) return null; + + if (Config.UseSharedLink) + { + string filesResponse = HttpPut(string.Format(FilesUri, upload.Entries[0].Id), "{\"shared_link\": {\"access\": \"open\"}}", settings); + var file = JsonSerializer.Deserialize(filesResponse); + return file.SharedLink.Url; + } + + return $"http://www.box.com/files/0/f/0/1/f_{upload.Entries[0].Id}"; + } + finally + { + // Copy the settings back to the config, so they are stored. + Config.RefreshToken = settings.RefreshToken; + Config.AccessToken = settings.AccessToken; + Config.AccessTokenExpires = settings.AccessTokenExpires; + Config.IsDirty = true; + IniConfig.Save(); + } + } + } + + /// + /// A simple helper class for the DataContractJsonSerializer + /// + internal static class JsonSerializer + { + /// + /// Helper method to parse JSON to object + /// + /// + /// + /// + public static T Deserialize(string jsonString) + { + var deserializer = new DataContractJsonSerializer(typeof(T)); + using var stream = new MemoryStream(); + byte[] content = Encoding.UTF8.GetBytes(jsonString); + stream.Write(content, 0, content.Length); + stream.Seek(0, SeekOrigin.Begin); + return (T) deserializer.ReadObject(stream); + } + } +} \ No newline at end of file diff --git a/GreenshotBoxPlugin/Forms/BoxForm.cs b/src/Greenshot.Plugin.Box/Forms/BoxForm.cs similarity index 86% rename from GreenshotBoxPlugin/Forms/BoxForm.cs rename to src/Greenshot.Plugin.Box/Forms/BoxForm.cs index 1ab7aed75..96776ab92 100644 --- a/GreenshotBoxPlugin/Forms/BoxForm.cs +++ b/src/Greenshot.Plugin.Box/Forms/BoxForm.cs @@ -18,9 +18,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -using GreenshotPlugin.Controls; -namespace GreenshotBoxPlugin.Forms { - public class BoxForm : GreenshotForm { - } +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.Box.Forms +{ + public class BoxForm : GreenshotForm + { + } } \ No newline at end of file diff --git a/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs similarity index 85% rename from GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs index 556cfe413..1714ff65e 100644 --- a/GreenshotBoxPlugin/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs @@ -18,7 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotBoxPlugin.Forms { + +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.Box.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. @@ -46,12 +49,12 @@ namespace GreenshotBoxPlugin.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.label_AfterUpload = new GreenshotLabel(); + this.checkboxAfterUploadLinkToClipBoard = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -138,11 +141,11 @@ namespace GreenshotBoxPlugin.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotLabel label_AfterUpload; + private GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; } } diff --git a/GreenshotFlickrPlugin/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs similarity index 64% rename from GreenshotFlickrPlugin/Forms/SettingsForm.cs rename to src/Greenshot.Plugin.Box/Forms/SettingsForm.cs index 59d0e3cbf..588350c76 100644 --- a/GreenshotFlickrPlugin/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Box/Forms/SettingsForm.cs @@ -19,19 +19,21 @@ * along with this program. If not, see . */ -namespace GreenshotFlickrPlugin.Forms { - /// - /// Description of PasswordRequestForm. - /// - public partial class SettingsForm : FlickrForm { - public SettingsForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - CancelButton = buttonCancel; - AcceptButton = buttonOK; - } - - } -} +namespace Greenshot.Plugin.Box.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : BoxForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = buttonOK; + CancelButton = buttonCancel; + } + } +} \ No newline at end of file diff --git a/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template similarity index 97% rename from GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template rename to src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template index 72cfa4b79..df6eaa0bd 100644 --- a/GreenshotBoxPlugin/GreenshotBoxPlugin.Credentials.template +++ b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotBoxPlugin { +namespace Greenshot.Plugin.Box { /// /// This class is merely a placeholder for the file keeping the API key and secret for Box integration. /// You can set your own values here diff --git a/GreenshotBoxPlugin/GreenshotBoxPlugin.csproj b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj similarity index 56% rename from GreenshotBoxPlugin/GreenshotBoxPlugin.csproj rename to src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj index 47724aa87..789ebd424 100644 --- a/GreenshotBoxPlugin/GreenshotBoxPlugin.csproj +++ b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj @@ -1,10 +1,4 @@  - - - GreenshotBoxPlugin - GreenshotBoxPlugin - - PreserveNewest @@ -16,6 +10,6 @@ - + \ No newline at end of file diff --git a/GreenshotFlickrPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Box/LanguageKeys.cs similarity index 83% rename from GreenshotFlickrPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Box/LanguageKeys.cs index ae3a6af02..c6c64bfdf 100644 --- a/GreenshotFlickrPlugin/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Box/LanguageKeys.cs @@ -18,11 +18,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotFlickrPlugin { - public enum LangKey { - upload_menu_item, - upload_failure, - communication_wait, - Configure + +namespace Greenshot.Plugin.Box +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + Configure } -} +} \ No newline at end of file diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-cs-CZ.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-cs-CZ.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-cs-CZ.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-de-DE.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-de-DE.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-de-DE.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-de-DE.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-en-US.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-en-US.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-en-US.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-en-US.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-fr-FR.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-fr-FR.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-fr-FR.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-fr-FR.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-id-ID.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-id-ID.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-id-ID.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-id-ID.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-it-IT.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-it-IT.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-it-IT.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-ja-JP.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-ja-JP.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-ja-JP.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-ja-JP.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-kab-DZ.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-kab-DZ.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-kab-DZ.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-ko-KR.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-ko-KR.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-ko-KR.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-ko-KR.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-lv-LV.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-lv-LV.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-lv-LV.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-lv-LV.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-pl-PL.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-pl-PL.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-pl-PL.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-pl-PL.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-pt-PT.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-pt-PT.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-pt-PT.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-pt-PT.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-ru-RU.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-ru-RU.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-ru-RU.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-ru-RU.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-sr-RS.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-sr-RS.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-sr-RS.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-sr-RS.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-sv-SE.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-sv-SE.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-sv-SE.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-sv-SE.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-uk-UA.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-uk-UA.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-uk-UA.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-uk-UA.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-zh-CN.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-zh-CN.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-zh-CN.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-zh-CN.xml diff --git a/GreenshotBoxPlugin/Languages/language_boxplugin-zh-TW.xml b/src/Greenshot.Plugin.Box/Languages/language_boxplugin-zh-TW.xml similarity index 100% rename from GreenshotBoxPlugin/Languages/language_boxplugin-zh-TW.xml rename to src/Greenshot.Plugin.Box/Languages/language_boxplugin-zh-TW.xml diff --git a/GreenshotBoxPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs similarity index 97% rename from GreenshotBoxPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs index b6b19f1c8..8af36d000 100644 --- a/GreenshotBoxPlugin/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Confluence.cs b/src/Greenshot.Plugin.Confluence/Confluence.cs new file mode 100644 index 000000000..b139c041e --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/Confluence.cs @@ -0,0 +1,358 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using GreenshotConfluencePlugin.confluence; + +namespace Greenshot.Plugin.Confluence +{ + public class Page + { + public Page(RemotePage page) + { + Id = page.id; + Title = page.title; + SpaceKey = page.space; + Url = page.url; + Content = page.content; + } + + public Page(RemoteSearchResult searchResult, string space) + { + Id = searchResult.id; + Title = searchResult.title; + SpaceKey = space; + Url = searchResult.url; + Content = searchResult.excerpt; + } + + public Page(RemotePageSummary pageSummary) + { + Id = pageSummary.id; + Title = pageSummary.title; + SpaceKey = pageSummary.space; + Url = pageSummary.url; + } + + public long Id { get; set; } + public string Title { get; set; } + public string Url { get; set; } + public string Content { get; set; } + public string SpaceKey { get; set; } + } + + public class Space + { + public Space(RemoteSpaceSummary space) + { + Key = space.key; + Name = space.name; + } + + public string Key { get; set; } + public string Name { get; set; } + } + + /// + /// For details see the Confluence API site + /// See: http://confluence.atlassian.com/display/CONFDEV/Remote+API+Specification + /// + public class ConfluenceConnector : IDisposable + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceConnector)); + private const string AuthFailedExceptionName = "com.atlassian.confluence.rpc.AuthenticationFailedException"; + private const string V2Failed = "AXIS"; + private static readonly ConfluenceConfiguration Config = IniConfig.GetIniSection(); + private string _credentials; + private DateTime _loggedInTime = DateTime.Now; + private bool _loggedIn; + private ConfluenceSoapServiceService _confluence; + private readonly int _timeout; + private string _url; + private readonly Cache _pageCache = new Cache(60 * Config.Timeout); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + if (_confluence != null) + { + Logout(); + } + + if (disposing) + { + if (_confluence != null) + { + _confluence.Dispose(); + _confluence = null; + } + } + } + + public ConfluenceConnector(string url, int timeout) + { + _timeout = timeout; + Init(url); + } + + private void Init(string url) + { + _url = url; + _confluence = new ConfluenceSoapServiceService + { + Url = url, + Proxy = NetworkHelper.CreateProxy(new Uri(url)) + }; + } + + ~ConfluenceConnector() + { + Dispose(false); + } + + /// + /// Internal login which catches the exceptions + /// + /// true if login was done sucessfully + private bool DoLogin(string user, string password) + { + try + { + _credentials = _confluence.login(user, password); + _loggedInTime = DateTime.Now; + _loggedIn = true; + } + catch (Exception e) + { + // Check if confluence-v2 caused an error, use v1 instead + if (e.Message.Contains(V2Failed) && _url.Contains("v2")) + { + Init(_url.Replace("v2", "v1")); + return DoLogin(user, password); + } + + // check if auth failed + if (e.Message.Contains(AuthFailedExceptionName)) + { + return false; + } + + // Not an authentication issue + _loggedIn = false; + _credentials = null; + e.Data.Add("user", user); + e.Data.Add("url", _url); + throw; + } + + return true; + } + + public void Login() + { + Logout(); + try + { + // Get the system name, so the user knows where to login to + string systemName = _url.Replace(ConfluenceConfiguration.DEFAULT_POSTFIX1, ""); + systemName = systemName.Replace(ConfluenceConfiguration.DEFAULT_POSTFIX2, ""); + CredentialsDialog dialog = new CredentialsDialog(systemName) + { + Name = null + }; + while (dialog.Show(dialog.Name) == DialogResult.OK) + { + if (DoLogin(dialog.Name, dialog.Password)) + { + if (dialog.SaveChecked) + { + dialog.Confirm(true); + } + + return; + } + else + { + try + { + dialog.Confirm(false); + } + catch (ApplicationException e) + { + // exception handling ... + Log.Error("Problem using the credentials dialog", e); + } + + // For every windows version after XP show an incorrect password baloon + dialog.IncorrectPassword = true; + // Make sure the dialog is display, the password was false! + dialog.AlwaysDisplay = true; + } + } + } + catch (ApplicationException e) + { + // exception handling ... + Log.Error("Problem using the credentials dialog", e); + } + } + + public void Logout() + { + if (_credentials != null) + { + _confluence.logout(_credentials); + _credentials = null; + _loggedIn = false; + } + } + + private void CheckCredentials() + { + if (_loggedIn) + { + if (_loggedInTime.AddMinutes(_timeout - 1).CompareTo(DateTime.Now) < 0) + { + Logout(); + Login(); + } + } + else + { + Login(); + } + } + + public bool IsLoggedIn => _loggedIn; + + public void AddAttachment(long pageId, string mime, string comment, string filename, IBinaryContainer image) + { + CheckCredentials(); + // Comment is ignored, see: http://jira.atlassian.com/browse/CONF-9395 + var attachment = new RemoteAttachment + { + comment = comment, + fileName = filename, + contentType = mime + }; + _confluence.addAttachment(_credentials, pageId, attachment, image.ToByteArray()); + } + + public Page GetPage(string spaceKey, string pageTitle) + { + RemotePage page = null; + string cacheKey = spaceKey + pageTitle; + if (_pageCache.Contains(cacheKey)) + { + page = _pageCache[cacheKey]; + } + + if (page == null) + { + CheckCredentials(); + page = _confluence.getPage(_credentials, spaceKey, pageTitle); + _pageCache.Add(cacheKey, page); + } + + return new Page(page); + } + + public Page GetPage(long pageId) + { + RemotePage page = null; + string cacheKey = pageId.ToString(); + + if (_pageCache.Contains(cacheKey)) + { + page = _pageCache[cacheKey]; + } + + if (page == null) + { + CheckCredentials(); + page = _confluence.getPage(_credentials, pageId); + _pageCache.Add(cacheKey, page); + } + + return new Page(page); + } + + public Page GetSpaceHomepage(Space spaceSummary) + { + CheckCredentials(); + RemoteSpace spaceDetail = _confluence.getSpace(_credentials, spaceSummary.Key); + RemotePage page = _confluence.getPage(_credentials, spaceDetail.homePage); + return new Page(page); + } + + public IEnumerable GetSpaceSummaries() + { + CheckCredentials(); + RemoteSpaceSummary[] spaces = _confluence.getSpaces(_credentials); + foreach (RemoteSpaceSummary space in spaces) + { + yield return new Space(space); + } + } + + public IEnumerable GetPageChildren(Page parentPage) + { + CheckCredentials(); + RemotePageSummary[] pages = _confluence.getChildren(_credentials, parentPage.Id); + foreach (RemotePageSummary page in pages) + { + yield return new Page(page); + } + } + + public IEnumerable GetPageSummaries(Space space) + { + CheckCredentials(); + RemotePageSummary[] pages = _confluence.getPages(_credentials, space.Key); + foreach (RemotePageSummary page in pages) + { + yield return new Page(page); + } + } + + public IEnumerable SearchPages(string query, string space) + { + CheckCredentials(); + foreach (var searchResult in _confluence.search(_credentials, query, 20)) + { + Log.DebugFormat("Got result of type {0}", searchResult.type); + if ("page".Equals(searchResult.type)) + { + yield return new Page(searchResult, space); + } + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs new file mode 100644 index 000000000..400f3c352 --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs @@ -0,0 +1,67 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.Confluence +{ + /// + /// Description of ConfluenceConfiguration. + /// + [Serializable] + [IniSection("Confluence", Description = "Greenshot Confluence Plugin configuration")] + public class ConfluenceConfiguration : IniSection + { + public const string DEFAULT_POSTFIX1 = "/rpc/soap-axis/confluenceservice-v1?wsdl"; + public const string DEFAULT_POSTFIX2 = "/rpc/soap-axis/confluenceservice-v2?wsdl"; + public const string DEFAULT_PREFIX = "http://"; + private const string DEFAULT_URL = DEFAULT_PREFIX + "confluence"; + + [IniProperty("Url", Description = "Url to Confluence system, including wsdl.", DefaultValue = DEFAULT_URL)] + public string Url { get; set; } + + [IniProperty("Timeout", Description = "Session timeout in minutes", DefaultValue = "30")] + public int Timeout { get; set; } + + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] + public bool UploadReduceColors { get; set; } + + [IniProperty("OpenPageAfterUpload", Description = "Open the page where the picture is uploaded after upload", DefaultValue = "True")] + public bool OpenPageAfterUpload { get; set; } + + [IniProperty("CopyWikiMarkupForImageToClipboard", Description = "Copy the Wikimarkup for the recently uploaded image to the Clipboard", DefaultValue = "True")] + public bool CopyWikiMarkupForImageToClipboard { get; set; } + + [IniProperty("SearchSpaceKey", Description = "Key of last space that was searched for")] + public string SearchSpaceKey { get; set; } + + [IniProperty("IncludePersonSpaces", Description = "Include personal spaces in the search & browse spaces list", DefaultValue = "False")] + public bool IncludePersonSpaces { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs new file mode 100644 index 000000000..70af706bd --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs @@ -0,0 +1,252 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Threading; +using System.Windows; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Plugin.Confluence +{ + /// + /// Description of ConfluenceDestination. + /// + public class ConfluenceDestination : AbstractDestination + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceDestination)); + private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection(); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static readonly Image ConfluenceIcon; + private readonly Page _page; + + static ConfluenceDestination() + { + IsInitialized = false; + try + { + Uri confluenceIconUri = new Uri("/GreenshotConfluencePlugin;component/Images/Confluence.ico", UriKind.Relative); + using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream) + { + // TODO: Check what to do with the IImage + ConfluenceIcon = ImageHelper.FromStream(iconStream); + } + + IsInitialized = true; + } + catch (Exception ex) + { + Log.ErrorFormat("Problem in the confluence static initializer: {0}", ex.Message); + } + } + + public static bool IsInitialized { get; private set; } + + public ConfluenceDestination() + { + } + + public ConfluenceDestination(Page page) + { + _page = page; + } + + public override string Designation + { + get { return "Confluence"; } + } + + public override string Description + { + get + { + if (_page == null) + { + return Language.GetString("confluence", LangKey.upload_menu_item); + } + else + { + return Language.GetString("confluence", LangKey.upload_menu_item) + ": \"" + _page.Title + "\""; + } + } + } + + public override bool IsDynamic + { + get { return true; } + } + + public override bool IsActive + { + get { return base.IsActive && !string.IsNullOrEmpty(ConfluenceConfig.Url); } + } + + public override Image DisplayIcon + { + get { return ConfluenceIcon; } + } + + public override IEnumerable DynamicDestinations() + { + if (ConfluencePlugin.ConfluenceConnectorNoLogin == null || !ConfluencePlugin.ConfluenceConnectorNoLogin.IsLoggedIn) + { + yield break; + } + + List currentPages = ConfluenceUtils.GetCurrentPages(); + if (currentPages == null || currentPages.Count == 0) + { + yield break; + } + + foreach (Page currentPage in currentPages) + { + yield return new ConfluenceDestination(currentPage); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + // force password check to take place before the pages load + if (!ConfluencePlugin.ConfluenceConnector.IsLoggedIn) + { + return exportInformation; + } + + Page selectedPage = _page; + bool openPage = (_page == null) && ConfluenceConfig.OpenPageAfterUpload; + string filename = FilenameHelper.GetFilenameWithoutExtensionFromPattern(CoreConfig.OutputFileFilenamePattern, captureDetails); + if (selectedPage == null) + { + Forms.ConfluenceUpload confluenceUpload = new Forms.ConfluenceUpload(filename); + bool? dialogResult = confluenceUpload.ShowDialog(); + if (dialogResult.HasValue && dialogResult.Value) + { + selectedPage = confluenceUpload.SelectedPage; + if (confluenceUpload.IsOpenPageSelected) + { + openPage = false; + } + + filename = confluenceUpload.Filename; + } + } + + string extension = "." + ConfluenceConfig.UploadFormat; + if (!filename.ToLower().EndsWith(extension)) + { + filename += extension; + } + + if (selectedPage != null) + { + bool uploaded = Upload(surface, selectedPage, filename, out var errorMessage); + if (uploaded) + { + if (openPage) + { + try + { + Process.Start(selectedPage.Url); + } + catch + { + // Ignore + } + } + + exportInformation.ExportMade = true; + exportInformation.Uri = selectedPage.Url; + } + else + { + exportInformation.ErrorMessage = errorMessage; + } + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + + private bool Upload(ISurface surfaceToUpload, Page page, string filename, out string errorMessage) + { + SurfaceOutputSettings outputSettings = + new SurfaceOutputSettings(ConfluenceConfig.UploadFormat, ConfluenceConfig.UploadJpegQuality, ConfluenceConfig.UploadReduceColors); + errorMessage = null; + try + { + new PleaseWaitForm().ShowAndWait(Description, Language.GetString("confluence", LangKey.communication_wait), + delegate + { + ConfluencePlugin.ConfluenceConnector.AddAttachment(page.Id, "image/" + ConfluenceConfig.UploadFormat.ToString().ToLower(), null, filename, + new SurfaceContainer(surfaceToUpload, outputSettings, filename)); + } + ); + Log.Debug("Uploaded to Confluence."); + if (!ConfluenceConfig.CopyWikiMarkupForImageToClipboard) + { + return true; + } + + int retryCount = 2; + while (retryCount >= 0) + { + try + { + Clipboard.SetText("!" + filename + "!"); + break; + } + catch (Exception ee) + { + if (retryCount == 0) + { + Log.Error(ee); + } + else + { + Thread.Sleep(100); + } + } + finally + { + --retryCount; + } + } + + return true; + } + catch (Exception e) + { + errorMessage = e.Message; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs new file mode 100644 index 000000000..6878192a1 --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs @@ -0,0 +1,169 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Confluence.Forms; +using Greenshot.Plugin.Confluence.Support; + +namespace Greenshot.Plugin.Confluence +{ + /// + /// This is the ConfluencePlugin base code + /// + [Plugin("Confluence", true)] + public class ConfluencePlugin : IGreenshotPlugin + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluencePlugin)); + private static ConfluenceConnector _confluenceConnector; + private static ConfluenceConfiguration _config; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + //if (disposing) {} + } + + private static void CreateConfluenceConnector() + { + if (_confluenceConnector == null) + { + if (_config.Url.Contains("soap-axis")) + { + _confluenceConnector = new ConfluenceConnector(_config.Url, _config.Timeout); + } + else + { + _confluenceConnector = new ConfluenceConnector(_config.Url + ConfluenceConfiguration.DEFAULT_POSTFIX2, _config.Timeout); + } + } + } + + public static ConfluenceConnector ConfluenceConnectorNoLogin + { + get { return _confluenceConnector; } + } + + public static ConfluenceConnector ConfluenceConnector + { + get + { + if (_confluenceConnector == null) + { + CreateConfluenceConnector(); + } + + try + { + if (_confluenceConnector != null && !_confluenceConnector.IsLoggedIn) + { + _confluenceConnector.Login(); + } + } + catch (Exception e) + { + MessageBox.Show(Language.GetFormattedString("confluence", LangKey.login_error, e.Message)); + } + + return _confluenceConnector; + } + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + public bool Initialize() + { + // Register configuration (don't need the configuration itself) + _config = IniConfig.GetIniSection(); + if (_config.IsDirty) + { + IniConfig.Save(); + } + + try + { + TranslationManager.Instance.TranslationProvider = new LanguageXMLTranslationProvider(); + //resources = new ComponentResourceManager(typeof(ConfluencePlugin)); + } + catch (Exception ex) + { + LOG.ErrorFormat("Problem in ConfluencePlugin.Initialize: {0}", ex.Message); + return false; + } + + if (ConfluenceDestination.IsInitialized) + { + SimpleServiceProvider.Current.AddService(new ConfluenceDestination()); + } + + return true; + } + + public void Shutdown() + { + LOG.Debug("Confluence Plugin shutdown."); + if (_confluenceConnector != null) + { + _confluenceConnector.Logout(); + _confluenceConnector = null; + } + } + + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + ConfluenceConfiguration clonedConfig = _config.Clone(); + ConfluenceConfigurationForm configForm = new ConfluenceConfigurationForm(clonedConfig); + string url = _config.Url; + bool? dialogResult = configForm.ShowDialog(); + if (dialogResult.HasValue && dialogResult.Value) + { + // copy the new object to the old... + clonedConfig.CloneTo(_config); + IniConfig.Save(); + if (_confluenceConnector != null) + { + if (!url.Equals(_config.Url)) + { + if (_confluenceConnector.IsLoggedIn) + { + _confluenceConnector.Logout(); + } + + _confluenceConnector = null; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs b/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs new file mode 100644 index 000000000..249b97f77 --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/ConfluenceUtils.cs @@ -0,0 +1,197 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Windows.Automation; +using Greenshot.Base.Core; + +namespace Greenshot.Plugin.Confluence +{ + /// + /// Description of ConfluenceUtils. + /// + public class ConfluenceUtils + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluenceUtils)); + + public static List GetCurrentPages() + { + List pages = new List(); + Regex pageIdRegex = new Regex(@"pageId=(\d+)"); + Regex spacePageRegex = new Regex(@"\/display\/([^\/]+)\/([^#]+)"); + foreach (string browserurl in GetBrowserUrls()) + { + string url; + try + { + url = Uri.UnescapeDataString(browserurl).Replace("+", " "); + } + catch + { + LOG.WarnFormat("Error processing URL: {0}", browserurl); + continue; + } + + MatchCollection pageIdMatch = pageIdRegex.Matches(url); + if (pageIdMatch != null && pageIdMatch.Count > 0) + { + long pageId = long.Parse(pageIdMatch[0].Groups[1].Value); + try + { + bool pageDouble = false; + foreach (Page page in pages) + { + if (page.Id == pageId) + { + pageDouble = true; + LOG.DebugFormat("Skipping double page with ID {0}", pageId); + break; + } + } + + if (!pageDouble) + { + Page page = ConfluencePlugin.ConfluenceConnector.GetPage(pageId); + LOG.DebugFormat("Adding page {0}", page.Title); + pages.Add(page); + } + + continue; + } + catch (Exception ex) + { + // Preventing security problems + LOG.DebugFormat("Couldn't get page details for PageID {0}", pageId); + LOG.Warn(ex); + } + } + + MatchCollection spacePageMatch = spacePageRegex.Matches(url); + if (spacePageMatch != null && spacePageMatch.Count > 0) + { + if (spacePageMatch[0].Groups.Count >= 2) + { + string space = spacePageMatch[0].Groups[1].Value; + string title = spacePageMatch[0].Groups[2].Value; + if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(space)) + { + continue; + } + + if (title.EndsWith("#")) + { + title = title.Substring(0, title.Length - 1); + } + + try + { + bool pageDouble = false; + foreach (Page page in pages) + { + if (page.Title.Equals(title)) + { + LOG.DebugFormat("Skipping double page with title {0}", title); + pageDouble = true; + break; + } + } + + if (!pageDouble) + { + Page page = ConfluencePlugin.ConfluenceConnector.GetPage(space, title); + LOG.DebugFormat("Adding page {0}", page.Title); + pages.Add(page); + } + } + catch (Exception ex) + { + // Preventing security problems + LOG.DebugFormat("Couldn't get page details for space {0} / title {1}", space, title); + LOG.Warn(ex); + } + } + } + } + + return pages; + } + + private static IEnumerable GetBrowserUrls() + { + HashSet urls = new HashSet(); + + // FireFox + foreach (WindowDetails window in WindowDetails.GetAllWindows("MozillaWindowClass")) + { + if (window.Text.Length == 0) + { + continue; + } + + AutomationElement currentElement = AutomationElement.FromHandle(window.Handle); + Condition conditionCustom = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Custom), + new PropertyCondition(AutomationElement.IsOffscreenProperty, false)); + for (int i = 5; i > 0 && currentElement != null; i--) + { + currentElement = currentElement.FindFirst(TreeScope.Children, conditionCustom); + } + + if (currentElement == null) + { + continue; + } + + Condition conditionDocument = new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document), + new PropertyCondition(AutomationElement.IsOffscreenProperty, false)); + AutomationElement docElement = currentElement.FindFirst(TreeScope.Children, conditionDocument); + if (docElement == null) + { + continue; + } + + foreach (AutomationPattern pattern in docElement.GetSupportedPatterns()) + { + if (pattern.ProgrammaticName != "ValuePatternIdentifiers.Pattern") + { + continue; + } + + string url = (docElement.GetCurrentPattern(pattern) as ValuePattern).Current.Value; + if (!string.IsNullOrEmpty(url)) + { + urls.Add(url); + break; + } + } + } + + foreach (string url in IEHelper.GetIEUrls().Distinct()) + { + urls.Add(url); + } + + return urls; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs b/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs new file mode 100644 index 000000000..3b3e3f95f --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/EnumDisplayer.cs @@ -0,0 +1,114 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Reflection; +using System.Windows.Data; +using Greenshot.Base.Core; + +namespace Greenshot.Plugin.Confluence +{ + public class EnumDisplayer : IValueConverter + { + private Type _type; + private IDictionary _displayValues; + private IDictionary _reverseValues; + + public Type Type + { + get { return _type; } + set + { + if (!value.IsEnum) + { + throw new ArgumentException("parameter is not an Enumerated type", nameof(value)); + } + + _type = value; + } + } + + public ReadOnlyCollection DisplayNames + { + get + { + var genericTypeDefinition = typeof(Dictionary<,>).GetGenericTypeDefinition(); + if (genericTypeDefinition != null) + { + _reverseValues = (IDictionary) Activator.CreateInstance(genericTypeDefinition.MakeGenericType(typeof(string), _type)); + } + + var typeDefinition = typeof(Dictionary<,>).GetGenericTypeDefinition(); + if (typeDefinition != null) + { + _displayValues = (IDictionary) Activator.CreateInstance(typeDefinition.MakeGenericType(_type, typeof(string))); + } + + var fields = _type.GetFields(BindingFlags.Public | BindingFlags.Static); + foreach (var field in fields) + { + DisplayKeyAttribute[] a = (DisplayKeyAttribute[]) field.GetCustomAttributes(typeof(DisplayKeyAttribute), false); + + string displayKey = GetDisplayKeyValue(a); + object enumValue = field.GetValue(null); + + string displayString; + if (displayKey != null && Language.HasKey(displayKey)) + { + displayString = Language.GetString(displayKey); + } + + displayString = displayKey ?? enumValue.ToString(); + + _displayValues.Add(enumValue, displayString); + _reverseValues.Add(displayString, enumValue); + } + + return new List((IEnumerable) _displayValues.Values).AsReadOnly(); + } + } + + private static string GetDisplayKeyValue(DisplayKeyAttribute[] a) + { + if (a == null || a.Length == 0) + { + return null; + } + + DisplayKeyAttribute dka = a[0]; + return dka.Value; + } + + object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return _displayValues[value]; + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return _reverseValues[value]; + } + } +} \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml similarity index 79% rename from GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml index c6b6b48a6..7ab7933e8 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml @@ -1,12 +1,12 @@ - - + diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs similarity index 59% rename from GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs index 9269072d4..dd9d46a1b 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceConfigurationForm.xaml.cs +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceConfigurationForm.xaml.cs @@ -21,21 +21,25 @@ using System.Windows; -namespace GreenshotConfluencePlugin.Forms { - /// - /// Interaction logic for ConfluenceConfigurationForm.xaml - /// - public partial class ConfluenceConfigurationForm : Window { - public ConfluenceConfiguration Config { get; } +namespace Greenshot.Plugin.Confluence.Forms +{ + /// + /// Interaction logic for ConfluenceConfigurationForm.xaml + /// + public partial class ConfluenceConfigurationForm : Window + { + public ConfluenceConfiguration Config { get; } - public ConfluenceConfigurationForm(ConfluenceConfiguration config) { - DataContext = config; - Config = config; - InitializeComponent(); - } + public ConfluenceConfigurationForm(ConfluenceConfiguration config) + { + DataContext = config; + Config = config; + InitializeComponent(); + } - private void Button_OK_Click(object sender, RoutedEventArgs e) { - DialogResult = true; - } - } + private void Button_OK_Click(object sender, RoutedEventArgs e) + { + DialogResult = true; + } + } } \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml similarity index 85% rename from GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml rename to src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml index e9ae3f97b..194d31080 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluencePagePicker.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml @@ -1,4 +1,4 @@ - diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs new file mode 100644 index 000000000..de3ffc934 --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluencePagePicker.xaml.cs @@ -0,0 +1,64 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; + +namespace Greenshot.Plugin.Confluence.Forms +{ + /// + /// Interaction logic for ConfluencePagePicker.xaml + /// + public partial class ConfluencePagePicker + { + private readonly ConfluenceUpload _confluenceUpload; + + public ConfluencePagePicker(ConfluenceUpload confluenceUpload, List pagesToPick) + { + _confluenceUpload = confluenceUpload; + DataContext = pagesToPick; + InitializeComponent(); + } + + private void PageListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) + { + SelectionChanged(); + } + + private void SelectionChanged() + { + if (PageListView.HasItems && PageListView.SelectedItems.Count > 0) + { + _confluenceUpload.SelectedPage = (Page) PageListView.SelectedItem; + // Make sure the uploader knows we selected an already opened page + _confluenceUpload.IsOpenPageSelected = true; + } + else + { + _confluenceUpload.SelectedPage = null; + } + } + + private void Page_Loaded(object sender, System.Windows.RoutedEventArgs e) + { + SelectionChanged(); + } + } +} \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml similarity index 90% rename from GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml index 073a437fe..f63185d34 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceSearch.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml @@ -1,8 +1,8 @@  - diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs new file mode 100644 index 000000000..c5f44014b --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceSearch.xaml.cs @@ -0,0 +1,112 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Windows; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.Confluence.Forms +{ + public partial class ConfluenceSearch + { + private static readonly ConfluenceConfiguration ConfluenceConfig = IniConfig.GetIniSection(); + private readonly ConfluenceUpload _confluenceUpload; + + public IEnumerable Spaces => _confluenceUpload.Spaces; + + public ObservableCollection Pages { get; } = new ObservableCollection(); + + public ConfluenceSearch(ConfluenceUpload confluenceUpload) + { + _confluenceUpload = confluenceUpload; + DataContext = this; + InitializeComponent(); + if (ConfluenceConfig.SearchSpaceKey == null) + { + SpaceComboBox.SelectedItem = Spaces.FirstOrDefault(); + } + else + { + foreach (var space in Spaces) + { + if (space.Key.Equals(ConfluenceConfig.SearchSpaceKey)) + { + SpaceComboBox.SelectedItem = space; + } + } + } + } + + private void PageListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) + { + SelectionChanged(); + } + + private void SelectionChanged() + { + if (PageListView.HasItems && PageListView.SelectedItems.Count > 0) + { + _confluenceUpload.SelectedPage = (Page) PageListView.SelectedItem; + } + else + { + _confluenceUpload.SelectedPage = null; + } + } + + private void Search_Click(object sender, RoutedEventArgs e) + { + DoSearch(); + } + + private void DoSearch() + { + string spaceKey = (string) SpaceComboBox.SelectedValue; + ConfluenceConfig.SearchSpaceKey = spaceKey; + Pages.Clear(); + foreach (var page in ConfluencePlugin.ConfluenceConnector.SearchPages(searchText.Text, spaceKey).OrderBy(p => p.Title)) + { + Pages.Add(page); + } + } + + private void SearchText_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) + { + if (e.Key == System.Windows.Input.Key.Return && Search.IsEnabled) + { + DoSearch(); + e.Handled = true; + } + } + + private void Page_Loaded(object sender, RoutedEventArgs e) + { + SelectionChanged(); + } + + private void SearchText_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) + { + Search.IsEnabled = !string.IsNullOrEmpty(searchText.Text); + } + } +} \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml similarity index 82% rename from GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml index 4ca2a11ad..27e2a0004 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceTreePicker.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceTreePicker.xaml @@ -1,8 +1,8 @@  - . + */ + +using System; +using System.Linq; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Threading; + +namespace Greenshot.Plugin.Confluence.Forms +{ + /// + /// Interaction logic for ConfluenceTreePicker.xaml + /// + public partial class ConfluenceTreePicker + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ConfluenceTreePicker)); + private readonly ConfluenceConnector _confluenceConnector; + private readonly ConfluenceUpload _confluenceUpload; + private bool _isInitDone; + + public ConfluenceTreePicker(ConfluenceUpload confluenceUpload) + { + _confluenceConnector = ConfluencePlugin.ConfluenceConnector; + _confluenceUpload = confluenceUpload; + InitializeComponent(); + } + + private void PageTreeViewItem_DoubleClick(object sender, MouseButtonEventArgs eventArgs) + { + Log.Debug("spaceTreeViewItem_MouseLeftButtonDown is called!"); + TreeViewItem clickedItem = eventArgs.Source as TreeViewItem; + if (clickedItem?.Tag is not Page page) + { + return; + } + + if (clickedItem.HasItems) + { + return; + } + + Log.Debug("Loading pages for page: " + page.Title); + new Thread(() => + { + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() => { ShowBusy.Visibility = Visibility.Visible; })); + var pages = _confluenceConnector.GetPageChildren(page).OrderBy(p => p.Title); + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() => + { + foreach (var childPage in pages) + { + Log.Debug("Adding page: " + childPage.Title); + var pageTreeViewItem = new TreeViewItem + { + Header = childPage.Title, + Tag = childPage + }; + clickedItem.Items.Add(pageTreeViewItem); + pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick; + pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click; + } + + ShowBusy.Visibility = Visibility.Collapsed; + })); + }) + { + Name = "Loading childpages for confluence page " + page.Title + }.Start(); + } + + private void PageTreeViewItem_Click(object sender, MouseButtonEventArgs eventArgs) + { + Log.Debug("pageTreeViewItem_PreviewMouseDoubleClick is called!"); + if (eventArgs.Source is not TreeViewItem clickedItem) + { + return; + } + + Page page = clickedItem.Tag as Page; + _confluenceUpload.SelectedPage = page; + if (page != null) + { + Log.Debug("Page selected: " + page.Title); + } + } + + private void Page_Loaded(object sender, RoutedEventArgs e) + { + _confluenceUpload.SelectedPage = null; + if (_isInitDone) + { + return; + } + + ShowBusy.Visibility = Visibility.Visible; + new Thread(() => + { + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart) (() => + { + foreach (Space space in _confluenceUpload.Spaces) + { + TreeViewItem spaceTreeViewItem = new TreeViewItem + { + Header = space.Name, + Tag = space + }; + + // Get homepage + try + { + Page page = _confluenceConnector.GetSpaceHomepage(space); + TreeViewItem pageTreeViewItem = new TreeViewItem + { + Header = page.Title, + Tag = page + }; + pageTreeViewItem.PreviewMouseDoubleClick += PageTreeViewItem_DoubleClick; + pageTreeViewItem.PreviewMouseLeftButtonDown += PageTreeViewItem_Click; + spaceTreeViewItem.Items.Add(pageTreeViewItem); + ConfluenceTreeView.Items.Add(spaceTreeViewItem); + } + catch (Exception ex) + { + Log.Error("Can't get homepage for space : " + space.Name + " (" + ex.Message + ")"); + } + } + + ShowBusy.Visibility = Visibility.Collapsed; + _isInitDone = true; + })); + }) + { + Name = "Loading spaces for confluence" + }.Start(); + } + } +} \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml similarity index 90% rename from GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml rename to src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml index f6ec6f13a..e53ae07ac 100644 --- a/GreenshotConfluencePlugin/Forms/ConfluenceUpload.xaml +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml @@ -1,7 +1,7 @@ - diff --git a/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs new file mode 100644 index 000000000..494036c24 --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/Forms/ConfluenceUpload.xaml.cs @@ -0,0 +1,141 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Windows; + +namespace Greenshot.Plugin.Confluence.Forms +{ + /// + /// Interaction logic for ConfluenceUpload.xaml + /// + public partial class ConfluenceUpload : Window + { + private System.Windows.Controls.Page _pickerPage; + + public System.Windows.Controls.Page PickerPage + { + get + { + if (_pickerPage == null) + { + List pages = ConfluenceUtils.GetCurrentPages(); + if (pages != null && pages.Count > 0) + { + _pickerPage = new ConfluencePagePicker(this, pages); + } + } + + return _pickerPage; + } + } + + private System.Windows.Controls.Page _searchPage; + + public System.Windows.Controls.Page SearchPage + { + get { return _searchPage ??= new ConfluenceSearch(this); } + } + + private System.Windows.Controls.Page _browsePage; + + public System.Windows.Controls.Page BrowsePage + { + get { return _browsePage ??= new ConfluenceTreePicker(this); } + } + + private Page _selectedPage; + + public Page SelectedPage + { + get => _selectedPage; + set + { + _selectedPage = value; + Upload.IsEnabled = _selectedPage != null; + IsOpenPageSelected = false; + } + } + + public bool IsOpenPageSelected { get; set; } + public string Filename { get; set; } + + private static DateTime _lastLoad = DateTime.Now; + private static IList _spaces; + + public IList Spaces + { + get + { + UpdateSpaces(); + while (_spaces == null) + { + Thread.Sleep(300); + } + + return _spaces; + } + } + + public ConfluenceUpload(string filename) + { + Filename = filename; + InitializeComponent(); + DataContext = this; + UpdateSpaces(); + if (PickerPage == null) + { + PickerTab.Visibility = Visibility.Collapsed; + SearchTab.IsSelected = true; + } + } + + private void UpdateSpaces() + { + if (_spaces != null && DateTime.Now.AddMinutes(-60).CompareTo(_lastLoad) > 0) + { + // Reset + _spaces = null; + } + + // Check if load is needed + if (_spaces == null) + { + (new Thread(() => + { + _spaces = ConfluencePlugin.ConfluenceConnector.GetSpaceSummaries().OrderBy(s => s.Name).ToList(); + _lastLoad = DateTime.Now; + }) + { + Name = "Loading spaces for confluence" + }).Start(); + } + } + + private void Upload_Click(object sender, RoutedEventArgs e) + { + DialogResult = true; + } + } +} \ No newline at end of file diff --git a/GreenshotConfluencePlugin/GreenshotConfluencePlugin.csproj b/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj similarity index 77% rename from GreenshotConfluencePlugin/GreenshotConfluencePlugin.csproj rename to src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj index 259eb96b2..f4a7f9c16 100644 --- a/GreenshotConfluencePlugin/GreenshotConfluencePlugin.csproj +++ b/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj @@ -1,10 +1,4 @@  - - - GreenshotConfluencePlugin - GreenshotConfluencePlugin - - PreserveNewest @@ -32,7 +26,7 @@ - + diff --git a/GreenshotConfluencePlugin/Images/Confluence.ico b/src/Greenshot.Plugin.Confluence/Images/Confluence.ico similarity index 100% rename from GreenshotConfluencePlugin/Images/Confluence.ico rename to src/Greenshot.Plugin.Confluence/Images/Confluence.ico diff --git a/GreenshotDropboxPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Confluence/LanguageKeys.cs similarity index 83% rename from GreenshotDropboxPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Confluence/LanguageKeys.cs index 0b1ae489e..bfee1cea8 100644 --- a/GreenshotDropboxPlugin/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Confluence/LanguageKeys.cs @@ -1,6 +1,6 @@ /* * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * * For more information see: http://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot @@ -18,11 +18,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotDropboxPlugin { - public enum LangKey { - upload_menu_item, - upload_failure, - communication_wait, - Configure + +namespace Greenshot.Plugin.Confluence +{ + public enum LangKey + { + login_error, + upload_menu_item, + communication_wait } -} +} \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-cs-CZ.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-cs-CZ.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-cs-CZ.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-de-DE.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-de-DE.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-de-DE.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-de-DE.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-en-US.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-en-US.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-en-US.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-en-US.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-fr-FR.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-fr-FR.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-fr-FR.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-fr-FR.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-id-ID.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-id-ID.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-id-ID.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-id-ID.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-it-IT.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-it-IT.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-it-IT.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ja-JP.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ja-JP.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-ja-JP.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ja-JP.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-kab-DZ.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-kab-DZ.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-kab-DZ.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ko-KR.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ko-KR.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-ko-KR.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ko-KR.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-lv-LV.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-lv-LV.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-lv-LV.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-lv-LV.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-nl-NL.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-nl-NL.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-nl-NL.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-nl-NL.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pl-PL.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-pl-PL.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-pl-PL.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-pl-PL.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-pt-PT.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-pt-PT.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-pt-PT.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-pt-PT.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-ru-RU.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ru-RU.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-ru-RU.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-ru-RU.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sr-RS.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-sr-RS.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-sr-RS.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-sr-RS.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-sv-SE.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-sv-SE.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-sv-SE.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-sv-SE.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-uk-UA.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-uk-UA.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-uk-UA.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-uk-UA.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-CN.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-zh-CN.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-CN.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-zh-CN.xml diff --git a/GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-TW.xml b/src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-zh-TW.xml similarity index 100% rename from GreenshotConfluencePlugin/Languages/language_confluenceplugin-zh-TW.xml rename to src/Greenshot.Plugin.Confluence/Languages/language_confluenceplugin-zh-TW.xml diff --git a/GreenshotConfluencePlugin/Support/ITranslationProvider.cs b/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs similarity index 65% rename from GreenshotConfluencePlugin/Support/ITranslationProvider.cs rename to src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs index 02180f036..d189db670 100644 --- a/GreenshotConfluencePlugin/Support/ITranslationProvider.cs +++ b/src/Greenshot.Plugin.Confluence/Support/ITranslationProvider.cs @@ -1,5 +1,7 @@ -namespace GreenshotConfluencePlugin.Support { - public interface ITranslationProvider { +namespace Greenshot.Plugin.Confluence.Support +{ + public interface ITranslationProvider + { /// /// Translates the specified key. /// @@ -7,4 +9,4 @@ /// object Translate(string key); } -} +} \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs b/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs similarity index 81% rename from GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs rename to src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs index c9fb55704..6ca4ec384 100644 --- a/GreenshotConfluencePlugin/Support/LanguageChangedEventManager.cs +++ b/src/Greenshot.Plugin.Confluence/Support/LanguageChangedEventManager.cs @@ -1,7 +1,7 @@ using System; using System.Windows; -namespace GreenshotConfluencePlugin.Support +namespace Greenshot.Plugin.Confluence.Support { public class LanguageChangedEventManager : WeakEventManager { @@ -22,13 +22,13 @@ namespace GreenshotConfluencePlugin.Support protected override void StartListening(object source) { - var manager = (TranslationManager)source; + var manager = (TranslationManager) source; manager.LanguageChanged += OnLanguageChanged; } protected override void StopListening(object source) { - var manager = (TranslationManager)source; + var manager = (TranslationManager) source; manager.LanguageChanged -= OnLanguageChanged; } @@ -37,15 +37,15 @@ namespace GreenshotConfluencePlugin.Support get { Type managerType = typeof(LanguageChangedEventManager); - var manager = (LanguageChangedEventManager)GetCurrentManager(managerType); + var manager = (LanguageChangedEventManager) GetCurrentManager(managerType); if (manager == null) { manager = new LanguageChangedEventManager(); SetCurrentManager(managerType, manager); } + return manager; } - } - + } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs b/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs new file mode 100644 index 000000000..e15e67555 --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/Support/LanguageXMLTranslationProvider.cs @@ -0,0 +1,23 @@ +using Greenshot.Base.Core; + +namespace Greenshot.Plugin.Confluence.Support +{ + /// + /// + /// + public class LanguageXMLTranslationProvider : ITranslationProvider + { + /// + /// See + /// + public object Translate(string key) + { + if (Language.HasKey("confluence", key)) + { + return Language.GetString("confluence", key); + } + + return key; + } + } +} \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Support/TranslateExtension.cs b/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs similarity index 82% rename from GreenshotConfluencePlugin/Support/TranslateExtension.cs rename to src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs index 3730e7baa..012f0c552 100644 --- a/GreenshotConfluencePlugin/Support/TranslateExtension.cs +++ b/src/Greenshot.Plugin.Confluence/Support/TranslateExtension.cs @@ -2,7 +2,7 @@ using System.Windows.Data; using System.Windows.Markup; -namespace GreenshotConfluencePlugin.Support +namespace Greenshot.Plugin.Confluence.Support { /// /// The Translate Markup extension returns a binding to a TranslationData @@ -25,7 +25,7 @@ namespace GreenshotConfluencePlugin.Support public string Key { get { return _key; } - set { _key = value;} + set { _key = value; } } /// @@ -34,10 +34,10 @@ namespace GreenshotConfluencePlugin.Support public override object ProvideValue(IServiceProvider serviceProvider) { var binding = new Binding("Value") - { - Source = new TranslationData(_key) - }; + { + Source = new TranslationData(_key) + }; return binding.ProvideValue(serviceProvider); } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs b/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs new file mode 100644 index 000000000..0ebce8300 --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/Support/TranslationData.cs @@ -0,0 +1,50 @@ +using System; +using System.ComponentModel; +using System.Windows; + +namespace Greenshot.Plugin.Confluence.Support +{ + public class TranslationData : IWeakEventListener, INotifyPropertyChanged + { + private readonly string _key; + + /// + /// Initializes a new instance of the class. + /// + /// The key. + public TranslationData(string key) + { + _key = key; + LanguageChangedEventManager.AddListener(TranslationManager.Instance, this); + } + + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// is reclaimed by garbage collection. + /// + ~TranslationData() + { + LanguageChangedEventManager.RemoveListener(TranslationManager.Instance, this); + } + + public object Value => TranslationManager.Instance.Translate(_key); + + public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + if (managerType == typeof(LanguageChangedEventManager)) + { + OnLanguageChanged(sender, e); + return true; + } + + return false; + } + + private void OnLanguageChanged(object sender, EventArgs e) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); + } + + public event PropertyChangedEventHandler PropertyChanged; + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs b/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs new file mode 100644 index 000000000..825d1aae7 --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs @@ -0,0 +1,45 @@ +using System; + +namespace Greenshot.Plugin.Confluence.Support +{ + public class TranslationManager + { + private static TranslationManager _translationManager; + + public event EventHandler LanguageChanged; + + /*public CultureInfo CurrentLanguage { + get { return Thread.CurrentThread.CurrentUICulture; } + set { + if( value != Thread.CurrentThread.CurrentUICulture) { + Thread.CurrentThread.CurrentUICulture = value; + OnLanguageChanged(); + } + } + } + + public IEnumerable Languages { + get { + if( TranslationProvider != null) { + return TranslationProvider.Languages; + } + return Enumerable.Empty(); + } + }*/ + + public static TranslationManager Instance => _translationManager ??= new TranslationManager(); + + public ITranslationProvider TranslationProvider { get; set; } + + public object Translate(string key) + { + object translatedValue = TranslationProvider?.Translate(key); + if (translatedValue != null) + { + return translatedValue; + } + + return $"!{key}!"; + } + } +} \ No newline at end of file diff --git a/GreenshotConfluencePlugin/Web References/confluence/Reference.cs b/src/Greenshot.Plugin.Confluence/Web References/confluence/Reference.cs similarity index 100% rename from GreenshotConfluencePlugin/Web References/confluence/Reference.cs rename to src/Greenshot.Plugin.Confluence/Web References/confluence/Reference.cs diff --git a/GreenshotConfluencePlugin/Web References/confluence/Reference.map b/src/Greenshot.Plugin.Confluence/Web References/confluence/Reference.map similarity index 100% rename from GreenshotConfluencePlugin/Web References/confluence/Reference.map rename to src/Greenshot.Plugin.Confluence/Web References/confluence/Reference.map diff --git a/GreenshotConfluencePlugin/Web References/confluence/confluenceservice-v1.wsdl b/src/Greenshot.Plugin.Confluence/Web References/confluence/confluenceservice-v1.wsdl similarity index 100% rename from GreenshotConfluencePlugin/Web References/confluence/confluenceservice-v1.wsdl rename to src/Greenshot.Plugin.Confluence/Web References/confluence/confluenceservice-v1.wsdl diff --git a/GreenshotDropboxPlugin/Dropbox.gif b/src/Greenshot.Plugin.Dropbox/Dropbox.gif similarity index 100% rename from GreenshotDropboxPlugin/Dropbox.gif rename to src/Greenshot.Plugin.Dropbox/Dropbox.gif diff --git a/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs new file mode 100644 index 000000000..715d96ded --- /dev/null +++ b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs @@ -0,0 +1,72 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Plugin.Dropbox +{ + internal class DropboxDestination : AbstractDestination + { + private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection(); + + private readonly DropboxPlugin _plugin; + + public DropboxDestination(DropboxPlugin plugin) + { + _plugin = plugin; + } + + public override string Designation => "Dropbox"; + + public override string Description => Language.GetString("dropbox", LangKey.upload_menu_item); + + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(DropboxPlugin)); + return (Image) resources.GetObject("Dropbox"); + } + } + + public override ExportInformation ExportCapture(bool manually, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); + if (uploaded) + { + exportInformation.Uri = uploadUrl; + exportInformation.ExportMade = true; + if (DropboxConfig.AfterUploadLinkToClipBoard) + { + ClipboardHelper.SetClipboardData(uploadUrl); + } + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs new file mode 100644 index 000000000..b3c19d1a5 --- /dev/null +++ b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs @@ -0,0 +1,129 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Plugin.Dropbox +{ + /// + /// This is the Dropbox base code + /// + [Plugin("Dropbox", true)] + public class DropboxPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxPlugin)); + private static DropboxPluginConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInConfig; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (!disposing) return; + if (_itemPlugInConfig == null) return; + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + public bool Initialize() + { + // Register configuration (don't need the configuration itself) + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(DropboxPlugin)); + SimpleServiceProvider.Current.AddService(new DropboxDestination(this)); + _itemPlugInConfig = new ToolStripMenuItem + { + Text = Language.GetString("dropbox", LangKey.Configure), + Image = (Image) _resources.GetObject("Dropbox") + }; + _itemPlugInConfig.Click += ConfigMenuClick; + + PluginUtils.AddToContextMenu(_itemPlugInConfig); + Language.LanguageChanged += OnLanguageChanged; + return true; + } + + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Text = Language.GetString("dropbox", LangKey.Configure); + } + } + + public void Shutdown() + { + Log.Debug("Dropbox Plugin shutdown."); + } + + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + _config.ShowConfigDialog(); + } + + public void ConfigMenuClick(object sender, EventArgs eventArgs) + { + _config.ShowConfigDialog(); + } + + /// + /// This will be called when the menu item in the Editor is clicked + /// + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) + { + uploadUrl = null; + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); + try + { + bool result = false; + new PleaseWaitForm().ShowAndWait("Dropbox", Language.GetString("dropbox", LangKey.communication_wait), + delegate { result = DropboxUtils.UploadToDropbox(surfaceToUpload, outputSettings, captureDetails); } + ); + return result; + } + catch (Exception e) + { + Log.Error(e); + MessageBox.Show(Language.GetString("dropbox", LangKey.upload_failure) + " " + e.Message); + return false; + } + } + } +} \ No newline at end of file diff --git a/GreenshotDropboxPlugin/DropboxPlugin.resx b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.resx similarity index 100% rename from GreenshotDropboxPlugin/DropboxPlugin.resx rename to src/Greenshot.Plugin.Dropbox/DropboxPlugin.resx diff --git a/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs b/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs similarity index 50% rename from GreenshotDropboxPlugin/DropboxPluginConfiguration.cs rename to src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs index b13622db2..5925a1729 100644 --- a/GreenshotDropboxPlugin/DropboxPluginConfiguration.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs @@ -21,30 +21,31 @@ using System; using System.Windows.Forms; -using GreenshotDropboxPlugin.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Plugin.Dropbox.Forms; +namespace Greenshot.Plugin.Dropbox +{ + /// + /// Description of ImgurConfiguration. + /// + [IniSection("Dropbox", Description = "Greenshot Dropbox Plugin configuration")] + public class DropboxPluginConfiguration : IniSection + { + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } -namespace GreenshotDropboxPlugin { - /// - /// Description of ImgurConfiguration. - /// - [IniSection("Dropbox", Description = "Greenshot Dropbox Plugin configuration")] - public class DropboxPluginConfiguration : IniSection { - [IniProperty("UploadFormat", Description="What file type to use for uploading", DefaultValue="png")] - public OutputFormat UploadFormat { get; set; } + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } - [IniProperty("UploadJpegQuality", Description="JPEG file save quality in %.", DefaultValue="80")] - public int UploadJpegQuality { get; set; } - - [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Dropbox link to clipboard.", DefaultValue = "true")] - public bool AfterUploadLinkToClipBoard { get; set; } + [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Dropbox link to clipboard.", DefaultValue = "true")] + public bool AfterUploadLinkToClipBoard { get; set; } [IniProperty("RefreshToken", Description = "Dropbox refresh Token", Encrypted = true, ExcludeIfNull = true)] public string RefreshToken { get; set; } - /// + /// /// AccessToken, not stored /// public string AccessToken { get; set; } @@ -54,16 +55,19 @@ namespace GreenshotDropboxPlugin { /// public DateTimeOffset AccessTokenExpires { get; set; } - /// - /// A form for token - /// - /// bool true if OK was pressed, false if cancel - public bool ShowConfigDialog() { - DialogResult result = new SettingsForm().ShowDialog(); - if (result == DialogResult.OK) { - return true; - } - return false; - } - } -} + /// + /// A form for token + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + DialogResult result = new SettingsForm().ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/GreenshotDropboxPlugin/DropboxUtils.cs b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs similarity index 66% rename from GreenshotDropboxPlugin/DropboxUtils.cs rename to src/Greenshot.Plugin.Dropbox/DropboxUtils.cs index 8bf1d57b5..7307b2a26 100644 --- a/GreenshotDropboxPlugin/DropboxUtils.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs @@ -18,29 +18,33 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.IO; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.OAuth; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Newtonsoft.Json; -namespace GreenshotDropboxPlugin { - /// - /// Description of DropboxUtils. - /// - public class DropboxUtils { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxUtils)); - private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection(); +namespace Greenshot.Plugin.Dropbox +{ + /// + /// Description of DropboxUtils. + /// + public class DropboxUtils + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxUtils)); + private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection(); - private DropboxUtils() { - } + private DropboxUtils() + { + } - public static bool UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, ICaptureDetails captureDetails) - { + public static bool UploadToDropbox(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, ICaptureDetails captureDetails) + { var oauth2Settings = new OAuth2Settings { AuthUrlPattern = "https://api.dropbox.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}&redirect_uri={RedirectUrl}", @@ -50,24 +54,32 @@ namespace GreenshotDropboxPlugin { ClientId = DropBoxCredentials.CONSUMER_KEY, ClientSecret = DropBoxCredentials.CONSUMER_SECRET, AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, - RefreshToken = DropboxConfig.RefreshToken, + RefreshToken = DropboxConfig.RefreshToken, AccessToken = DropboxConfig.AccessToken, AccessTokenExpires = DropboxConfig.AccessTokenExpires - }; + }; try - { + { string filename = Path.GetFileName(FilenameHelper.GetFilename(DropboxConfig.UploadFormat, captureDetails)); SurfaceContainer image = new SurfaceContainer(surfaceToUpload, outputSettings, filename); IDictionary arguments = new Dictionary { - { "autorename", true }, - { "mute", true }, - { "path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\')} + { + "autorename", true + }, + { + "mute", true + }, + { + "path", "/" + filename.Replace(Path.DirectorySeparatorChar, '\\') + } }; IDictionary headers = new Dictionary { - { "Dropbox-API-Arg", JsonConvert.SerializeObject(arguments)} + { + "Dropbox-API-Arg", JsonConvert.SerializeObject(arguments) + } }; var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, "https://content.dropboxapi.com/2/files/upload", oauth2Settings); @@ -77,16 +89,19 @@ namespace GreenshotDropboxPlugin { var response = JsonConvert.DeserializeObject>(responseString); return response.ContainsKey("id"); } - catch (Exception ex) { - Log.Error("Upload error: ", ex); - throw; - } finally { + catch (Exception ex) + { + Log.Error("Upload error: ", ex); + throw; + } + finally + { DropboxConfig.RefreshToken = oauth2Settings.RefreshToken; DropboxConfig.AccessToken = oauth2Settings.AccessToken; DropboxConfig.AccessTokenExpires = oauth2Settings.AccessTokenExpires; DropboxConfig.IsDirty = true; IniConfig.Save(); } - } - } -} + } + } +} \ No newline at end of file diff --git a/GreenshotDropboxPlugin/Forms/DropboxForm.cs b/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs similarity index 85% rename from GreenshotDropboxPlugin/Forms/DropboxForm.cs rename to src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs index e0a96b5bf..1f1bfd5ea 100644 --- a/GreenshotDropboxPlugin/Forms/DropboxForm.cs +++ b/src/Greenshot.Plugin.Dropbox/Forms/DropboxForm.cs @@ -19,9 +19,11 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace GreenshotDropboxPlugin.Forms { - public class DropboxForm : GreenshotForm { - } -} +namespace Greenshot.Plugin.Dropbox.Forms +{ + public class DropboxForm : GreenshotForm + { + } +} \ No newline at end of file diff --git a/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs similarity index 84% rename from GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs index 1baae2160..e80470dd5 100644 --- a/GreenshotDropboxPlugin/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs @@ -18,7 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotDropboxPlugin.Forms { + +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.Dropbox.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. @@ -45,12 +48,12 @@ namespace GreenshotDropboxPlugin.Forms { /// not be able to load this method if it was changed manually. /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.label_AfterUpload = new GreenshotLabel(); + this.checkboxAfterUploadLinkToClipBoard = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -135,11 +138,11 @@ namespace GreenshotDropboxPlugin.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotLabel label_AfterUpload; + private GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; } } diff --git a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs new file mode 100644 index 000000000..c79844e6d --- /dev/null +++ b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.cs @@ -0,0 +1,39 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Plugin.Dropbox.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : DropboxForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = buttonOK; + CancelButton = buttonCancel; + } + } +} \ No newline at end of file diff --git a/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.Credentials.template similarity index 97% rename from GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template rename to src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.Credentials.template index f674f1bb7..56cde680f 100644 --- a/GreenshotDropboxPlugin/GreenshotDropboxPlugin.Credentials.template +++ b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotDropboxPlugin { +namespace Greenshot.Plugin.Dropbox { /// /// This class is merely a placeholder for the file keeping the API key and secret for dropbox integration. /// You can set your own values here diff --git a/GreenshotDropboxPlugin/GreenshotDropboxPlugin.csproj b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj similarity index 56% rename from GreenshotDropboxPlugin/GreenshotDropboxPlugin.csproj rename to src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj index b24217779..075667394 100644 --- a/GreenshotDropboxPlugin/GreenshotDropboxPlugin.csproj +++ b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj @@ -1,10 +1,4 @@  - - - GreenshotDropboxPlugin - GreenshotDropboxPlugin - - PreserveNewest @@ -16,6 +10,6 @@ - + \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs b/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs new file mode 100644 index 000000000..37d6b50e3 --- /dev/null +++ b/src/Greenshot.Plugin.Dropbox/LanguageKeys.cs @@ -0,0 +1,31 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Plugin.Dropbox +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + Configure + } +} \ No newline at end of file diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-cs-CZ.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-cs-CZ.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-cs-CZ.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-de-DE.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-de-DE.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-de-DE.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-de-DE.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-en-US.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-en-US.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-en-US.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-en-US.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-fr-FR.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-fr-FR.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-fr-FR.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-fr-FR.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-id-ID.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-id-ID.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-id-ID.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-id-ID.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-it-IT.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-it-IT.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-it-IT.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ja-JP.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ja-JP.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-ja-JP.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ja-JP.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-kab-DZ.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-kab-DZ.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-kab-DZ.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ko-KR.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ko-KR.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-ko-KR.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ko-KR.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-lv-LV.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-lv-LV.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-lv-LV.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-lv-LV.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pl-PL.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-pl-PL.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-pl-PL.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-pl-PL.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-pt-PT.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-pt-PT.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-pt-PT.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-pt-PT.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-ru-RU.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ru-RU.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-ru-RU.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-ru-RU.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sr-RS.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-sr-RS.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-sr-RS.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-sr-RS.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-sv-SE.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-sv-SE.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-sv-SE.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-sv-SE.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-uk-UA.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-uk-UA.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-uk-UA.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-uk-UA.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-CN.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-zh-CN.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-CN.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-zh-CN.xml diff --git a/GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-TW.xml b/src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-zh-TW.xml similarity index 100% rename from GreenshotDropboxPlugin/Languages/language_dropboxplugin-zh-TW.xml rename to src/Greenshot.Plugin.Dropbox/Languages/language_dropboxplugin-zh-TW.xml diff --git a/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs similarity index 97% rename from GreenshotDropboxPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs index 9e9b18e04..5870d89ea 100644 --- a/GreenshotDropboxPlugin/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs new file mode 100644 index 000000000..3cde91406 --- /dev/null +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandConfiguration.cs @@ -0,0 +1,172 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.ExternalCommand +{ + /// + /// Description of FlickrConfiguration. + /// + [IniSection("ExternalCommand", Description = "Greenshot ExternalCommand Plugin configuration")] + public class ExternalCommandConfiguration : IniSection + { + [IniProperty("Commands", Description = "The commands that are available.")] + public List Commands { get; set; } + + [IniProperty("RedirectStandardError", Description = "Redirect the standard error of all external commands, used to output as warning to the greenshot.log.", + DefaultValue = "true")] + public bool RedirectStandardError { get; set; } + + [IniProperty("RedirectStandardOutput", Description = "Redirect the standard output of all external commands, used for different other functions (more below).", + DefaultValue = "true")] + public bool RedirectStandardOutput { get; set; } + + [IniProperty("ShowStandardOutputInLog", + Description = "Depends on 'RedirectStandardOutput': Show standard output of all external commands to the Greenshot log, this can be usefull for debugging.", + DefaultValue = "false")] + public bool ShowStandardOutputInLog { get; set; } + + [IniProperty("ParseForUri", + Description = "Depends on 'RedirectStandardOutput': Parse the output and take the first found URI, if a URI is found than clicking on the notify bubble goes there.", + DefaultValue = "true")] + public bool ParseOutputForUri { get; set; } + + [IniProperty("OutputToClipboard", Description = "Depends on 'RedirectStandardOutput': Place the standard output on the clipboard.", DefaultValue = "false")] + public bool OutputToClipboard { get; set; } + + [IniProperty("UriToClipboard", + Description = + "Depends on 'RedirectStandardOutput' & 'ParseForUri': If an URI is found in the standard input, place it on the clipboard. (This overwrites the output from OutputToClipboard setting.)", + DefaultValue = "true")] + public bool UriToClipboard { get; set; } + + [IniProperty("Commandline", Description = "The commandline for the output command.")] + public Dictionary Commandline { get; set; } + + [IniProperty("Argument", Description = "The arguments for the output command.")] + public Dictionary Argument { get; set; } + + [IniProperty("RunInbackground", Description = "Should the command be started in the background.")] + public Dictionary RunInbackground { get; set; } + + [IniProperty("DeletedBuildInCommands", Description = "If a build in command was deleted manually, it should not be recreated.")] + public List DeletedBuildInCommands { get; set; } + + private const string MsPaint = "MS Paint"; + private static readonly string PaintPath; + private static readonly bool HasPaint; + + private const string PaintDotNet = "Paint.NET"; + private static readonly string PaintDotNetPath; + private static readonly bool HasPaintDotNet; + + static ExternalCommandConfiguration() + { + try + { + PaintPath = PluginUtils.GetExePath("pbrush.exe"); + HasPaint = !string.IsNullOrEmpty(PaintPath) && File.Exists(PaintPath); + } + catch + { + // Ignore + } + + try + { + PaintDotNetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Paint.NET\PaintDotNet.exe"); + HasPaintDotNet = !string.IsNullOrEmpty(PaintDotNetPath) && File.Exists(PaintDotNetPath); + } + catch + { + // Ignore + } + } + + /// + /// Delete the configuration for the specified command + /// + /// string with command + public void Delete(string command) + { + if (string.IsNullOrEmpty(command)) + { + return; + } + + Commands.Remove(command); + Commandline.Remove(command); + Argument.Remove(command); + RunInbackground.Remove(command); + if (MsPaint.Equals(command) || PaintDotNet.Equals(command)) + { + if (!DeletedBuildInCommands.Contains(command)) + { + DeletedBuildInCommands.Add(command); + } + } + } + + public override void AfterLoad() + { + base.AfterLoad(); + + // Check if we need to add MsPaint + if (HasPaint && !Commands.Contains(MsPaint) && !DeletedBuildInCommands.Contains(MsPaint)) + { + Commands.Add(MsPaint); + Commandline.Add(MsPaint, PaintPath); + Argument.Add(MsPaint, "\"{0}\""); + RunInbackground.Add(MsPaint, true); + } + + // Check if we need to add Paint.NET + if (HasPaintDotNet && !Commands.Contains(PaintDotNet) && !DeletedBuildInCommands.Contains(PaintDotNet)) + { + Commands.Add(PaintDotNet); + Commandline.Add(PaintDotNet, PaintDotNetPath); + Argument.Add(PaintDotNet, "\"{0}\""); + RunInbackground.Add(PaintDotNet, true); + } + } + + /// + /// Supply values we can't put as defaults + /// + /// The property to return a default for + /// object with the default value for the supplied property + public override object GetDefault(string property) => + property switch + { + nameof(DeletedBuildInCommands) => (object) new List(), + nameof(Commands) => new List(), + nameof(Commandline) => new Dictionary(), + nameof(Argument) => new Dictionary(), + nameof(RunInbackground) => new Dictionary(), + _ => null + }; + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs new file mode 100644 index 000000000..3814896dd --- /dev/null +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs @@ -0,0 +1,272 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Text.RegularExpressions; +using System.Threading; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Plugin.ExternalCommand +{ + /// + /// Description of OCRDestination. + /// + public class ExternalCommandDestination : AbstractDestination + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ExternalCommandDestination)); + + private static readonly Regex URI_REGEXP = + new Regex( + @"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)"); + + private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection(); + private readonly string _presetCommand; + + public ExternalCommandDestination(string commando) + { + _presetCommand = commando; + } + + public override string Designation => "External " + _presetCommand.Replace(',', '_'); + + public override string Description => _presetCommand; + + public override IEnumerable DynamicDestinations() + { + yield break; + } + + public override Image DisplayIcon => IconCache.IconForCommand(_presetCommand); + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); + outputSettings.PreventGreenshotFormat(); + + if (_presetCommand != null) + { + if (!config.RunInbackground.ContainsKey(_presetCommand)) + { + config.RunInbackground.Add(_presetCommand, true); + } + + bool runInBackground = config.RunInbackground[_presetCommand]; + string fullPath = captureDetails.Filename ?? ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings); + + string output; + string error; + if (runInBackground) + { + Thread commandThread = new Thread(delegate() + { + CallExternalCommand(exportInformation, fullPath, out output, out error); + ProcessExport(exportInformation, surface); + }) + { + Name = "Running " + _presetCommand, + IsBackground = true + }; + commandThread.SetApartmentState(ApartmentState.STA); + commandThread.Start(); + exportInformation.ExportMade = true; + } + else + { + CallExternalCommand(exportInformation, fullPath, out output, out error); + ProcessExport(exportInformation, surface); + } + } + + return exportInformation; + } + + /// + /// Wrapper method for the background and normal call, this does all the logic: + /// Call the external command, parse for URI, place to clipboard and set the export information + /// + /// + /// + /// + /// + private void CallExternalCommand(ExportInformation exportInformation, string fullPath, out string output, out string error) + { + output = null; + error = null; + try + { + if (CallExternalCommand(_presetCommand, fullPath, out output, out error) == 0) + { + exportInformation.ExportMade = true; + if (!string.IsNullOrEmpty(output)) + { + MatchCollection uriMatches = URI_REGEXP.Matches(output); + // Place output on the clipboard before the URI, so if one is found this overwrites + if (config.OutputToClipboard) + { + ClipboardHelper.SetClipboardData(output); + } + + if (uriMatches.Count > 0) + { + exportInformation.Uri = uriMatches[0].Groups[1].Value; + LOG.InfoFormat("Got URI : {0} ", exportInformation.Uri); + if (config.UriToClipboard) + { + ClipboardHelper.SetClipboardData(exportInformation.Uri); + } + } + } + } + else + { + LOG.WarnFormat("Error calling external command: {0} ", output); + exportInformation.ExportMade = false; + exportInformation.ErrorMessage = error; + } + } + catch (Exception ex) + { + exportInformation.ExportMade = false; + exportInformation.ErrorMessage = ex.Message; + LOG.WarnFormat("Error calling external command: {0} ", exportInformation.ErrorMessage); + } + } + + /// + /// Wrapper to retry with a runas + /// + /// + /// + /// + /// + /// + private int CallExternalCommand(string commando, string fullPath, out string output, out string error) + { + try + { + return CallExternalCommand(commando, fullPath, null, out output, out error); + } + catch (Win32Exception w32Ex) + { + try + { + return CallExternalCommand(commando, fullPath, "runas", out output, out error); + } + catch + { + w32Ex.Data.Add("commandline", config.Commandline[_presetCommand]); + w32Ex.Data.Add("arguments", config.Argument[_presetCommand]); + throw; + } + } + catch (Exception ex) + { + ex.Data.Add("commandline", config.Commandline[_presetCommand]); + ex.Data.Add("arguments", config.Argument[_presetCommand]); + throw; + } + } + + /// + /// The actual executing code for the external command + /// + /// + /// + /// + /// + /// + /// + private int CallExternalCommand(string commando, string fullPath, string verb, out string output, out string error) + { + string commandline = config.Commandline[commando]; + string arguments = config.Argument[commando]; + output = null; + error = null; + if (!string.IsNullOrEmpty(commandline)) + { + using Process process = new Process(); + // Fix variables + commandline = FilenameHelper.FillVariables(commandline, true); + commandline = FilenameHelper.FillCmdVariables(commandline, true); + + arguments = FilenameHelper.FillVariables(arguments, false); + arguments = FilenameHelper.FillCmdVariables(arguments, false); + + process.StartInfo.FileName = FilenameHelper.FillCmdVariables(commandline, true); + process.StartInfo.Arguments = FormatArguments(arguments, fullPath); + process.StartInfo.UseShellExecute = false; + if (config.RedirectStandardOutput) + { + process.StartInfo.RedirectStandardOutput = true; + } + + if (config.RedirectStandardError) + { + process.StartInfo.RedirectStandardError = true; + } + + if (verb != null) + { + process.StartInfo.Verb = verb; + } + + LOG.InfoFormat("Starting : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); + process.Start(); + process.WaitForExit(); + if (config.RedirectStandardOutput) + { + output = process.StandardOutput.ReadToEnd(); + if (config.ShowStandardOutputInLog && output.Trim().Length > 0) + { + LOG.InfoFormat("Output:\n{0}", output); + } + } + + if (config.RedirectStandardError) + { + error = process.StandardError.ReadToEnd(); + if (error.Trim().Length > 0) + { + LOG.WarnFormat("Error:\n{0}", error); + } + } + + LOG.InfoFormat("Finished : {0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); + return process.ExitCode; + } + + return -1; + } + + public static string FormatArguments(string arguments, string fullpath) + { + return string.Format(arguments, fullpath); + } + } +} \ No newline at end of file diff --git a/GreenshotExternalCommandPlugin/ExternalCommandForm.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs similarity index 76% rename from GreenshotExternalCommandPlugin/ExternalCommandForm.cs rename to src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs index 6436fc988..90ba4bcfb 100644 --- a/GreenshotExternalCommandPlugin/ExternalCommandForm.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandForm.cs @@ -19,12 +19,14 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace GreenshotExternalCommandPlugin { - /// - /// This class is needed for design-time resolving of the language files - /// - public class ExternalCommandForm : GreenshotForm { - } +namespace Greenshot.Plugin.ExternalCommand +{ + /// + /// This class is needed for design-time resolving of the language files + /// + public class ExternalCommandForm : GreenshotForm + { + } } \ No newline at end of file diff --git a/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs similarity index 94% rename from GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs rename to src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs index 9389705b8..a4a3c20a5 100644 --- a/GreenshotExternalCommandPlugin/ExternalCommandPlugin.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs @@ -24,12 +24,12 @@ using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Windows.Forms; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; -namespace GreenshotExternalCommandPlugin +namespace Greenshot.Plugin.ExternalCommand { /// /// An Plugin to run commands after an image was written @@ -55,6 +55,7 @@ namespace GreenshotExternalCommandPlugin _itemPlugInRoot.Dispose(); _itemPlugInRoot = null; } + private IEnumerable Destinations() { foreach (string command in ExternalCommandConfig.Commands) @@ -77,17 +78,20 @@ namespace GreenshotExternalCommandPlugin // Fix it ExternalCommandConfig.RunInbackground.Add(command, true); } + if (!ExternalCommandConfig.Argument.ContainsKey(command)) { Log.WarnFormat("Found missing argument for {0}", command); // Fix it ExternalCommandConfig.Argument.Add(command, "{0}"); } + if (!ExternalCommandConfig.Commandline.ContainsKey(command)) { Log.WarnFormat("Found missing commandline for {0}", command); return false; } + string commandline = FilenameHelper.FillVariables(ExternalCommandConfig.Commandline[command], true); commandline = FilenameHelper.FillCmdVariables(commandline, true); @@ -96,8 +100,10 @@ namespace GreenshotExternalCommandPlugin Log.WarnFormat("Found 'invalid' commandline {0} for command {1}", ExternalCommandConfig.Commandline[command], command); return false; } + return true; } + /// /// Implementation of the IGreenshotPlugin.Initialize /// @@ -114,11 +120,13 @@ namespace GreenshotExternalCommandPlugin commandsToDelete.Add(command); } } + // cleanup foreach (string command in commandsToDelete) { ExternalCommandConfig.Delete(command); } + SimpleServiceProvider.Current.AddService(Destinations()); _itemPlugInRoot = new ToolStripMenuItem(); diff --git a/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj b/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj new file mode 100644 index 000000000..cc3d98fb9 --- /dev/null +++ b/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj @@ -0,0 +1,11 @@ + + + + PreserveNewest + + + + + + + diff --git a/src/Greenshot.Plugin.ExternalCommand/IconCache.cs b/src/Greenshot.Plugin.ExternalCommand/IconCache.cs new file mode 100644 index 000000000..c1c8b2e04 --- /dev/null +++ b/src/Greenshot.Plugin.ExternalCommand/IconCache.cs @@ -0,0 +1,56 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.IO; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.ExternalCommand +{ + public static class IconCache + { + private static readonly ExternalCommandConfiguration config = IniConfig.GetIniSection(); + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(IconCache)); + + public static Image IconForCommand(string commandName) + { + Image icon = null; + if (commandName != null) + { + if (config.Commandline.ContainsKey(commandName) && File.Exists(config.Commandline[commandName])) + { + try + { + icon = PluginUtils.GetCachedExeIcon(config.Commandline[commandName], 0); + } + catch (Exception ex) + { + LOG.Warn("Problem loading icon for " + config.Commandline[commandName], ex); + } + } + } + + return icon; + } + } +} \ No newline at end of file diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-cs-CZ.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-cs-CZ.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-cs-CZ.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-cs-CZ.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-de-DE.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-de-DE.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-de-DE.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-de-DE.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-en-US.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-en-US.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-en-US.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-en-US.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-fr-FR.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-fr-FR.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-fr-FR.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-fr-FR.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-id-ID.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-id-ID.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-id-ID.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-id-ID.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-it-IT.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-it-IT.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-it-IT.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ja-JP.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ja-JP.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ja-JP.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ja-JP.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-kab-DZ.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-kab-DZ.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-kab-DZ.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-kab-DZ.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ko-KR.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ko-KR.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ko-KR.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ko-KR.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-lv-LV.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-lv-LV.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-lv-LV.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-lv-LV.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pl-PL.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-pl-PL.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pl-PL.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-pl-PL.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pt-PT.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-pt-PT.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-pt-PT.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-pt-PT.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ru-RU.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ru-RU.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-ru-RU.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-ru-RU.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sk-SK.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sk-SK.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sk-SK.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sk-SK.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sr-RS.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sr-RS.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sr-RS.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sr-RS.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sv-SE.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sv-SE.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-sv-SE.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-sv-SE.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-uk-UA.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-uk-UA.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-uk-UA.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-uk-UA.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-CN.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-zh-CN.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-CN.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-zh-CN.xml diff --git a/GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-TW.xml b/src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-zh-TW.xml similarity index 100% rename from GreenshotExternalCommandPlugin/Languages/language_externalcommandplugin-zh-TW.xml rename to src/Greenshot.Plugin.ExternalCommand/Languages/language_externalcommandplugin-zh-TW.xml diff --git a/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs similarity index 87% rename from GreenshotExternalCommandPlugin/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs index f0a000f9b..d2fe3b8c3 100644 --- a/GreenshotExternalCommandPlugin/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.Designer.cs @@ -18,7 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotExternalCommandPlugin { + +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.ExternalCommand { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. @@ -45,13 +48,13 @@ namespace GreenshotExternalCommandPlugin { /// not be able to load this method if it was changed manually. /// private void InitializeComponent() { - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonOk = new GreenshotPlugin.Controls.GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.buttonOk = new GreenshotButton(); this.listView1 = new System.Windows.Forms.ListView(); this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.button_new = new GreenshotPlugin.Controls.GreenshotButton(); - this.button_delete = new GreenshotPlugin.Controls.GreenshotButton(); - this.button_edit = new GreenshotPlugin.Controls.GreenshotButton(); + this.button_new = new GreenshotButton(); + this.button_delete = new GreenshotButton(); + this.button_edit = new GreenshotButton(); this.SuspendLayout(); // // buttonCancel @@ -146,13 +149,13 @@ namespace GreenshotExternalCommandPlugin { this.ResumeLayout(false); } - private GreenshotPlugin.Controls.GreenshotButton button_edit; - private GreenshotPlugin.Controls.GreenshotButton button_delete; - private GreenshotPlugin.Controls.GreenshotButton button_new; + private GreenshotButton button_edit; + private GreenshotButton button_delete; + private GreenshotButton button_new; private System.Windows.Forms.ColumnHeader columnHeader1; private System.Windows.Forms.ListView listView1; - private GreenshotPlugin.Controls.GreenshotButton buttonOk; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; + private GreenshotButton buttonOk; + private GreenshotButton buttonCancel; } } diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs new file mode 100644 index 000000000..5325173b5 --- /dev/null +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsForm.cs @@ -0,0 +1,152 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.ExternalCommand +{ + /// + /// Description of SettingsForm. + /// + public partial class SettingsForm : ExternalCommandForm + { + private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection(); + + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = buttonOk; + CancelButton = buttonCancel; + UpdateView(); + } + + private void ButtonOkClick(object sender, EventArgs e) + { + IniConfig.Save(); + } + + private void ButtonAddClick(object sender, EventArgs e) + { + var form = new SettingsFormDetail(null); + form.ShowDialog(); + + UpdateView(); + } + + private void ButtonDeleteClick(object sender, EventArgs e) + { + foreach (ListViewItem item in listView1.SelectedItems) + { + string commando = item.Tag as string; + + ExternalCommandConfig.Delete(commando); + } + + UpdateView(); + } + + private void UpdateView() + { + listView1.Items.Clear(); + if (ExternalCommandConfig.Commands != null) + { + listView1.ListViewItemSorter = new ListviewComparer(); + ImageList imageList = new ImageList(); + listView1.SmallImageList = imageList; + int imageNr = 0; + foreach (string commando in ExternalCommandConfig.Commands) + { + ListViewItem item; + Image iconForExe = IconCache.IconForCommand(commando); + if (iconForExe != null) + { + imageList.Images.Add(iconForExe); + item = new ListViewItem(commando, imageNr++); + } + else + { + item = new ListViewItem(commando); + } + + item.Tag = commando; + listView1.Items.Add(item); + } + } + + // Fix for bug #1484, getting an ArgumentOutOfRangeException as there is nothing selected but the edit button was still active. + button_edit.Enabled = listView1.SelectedItems.Count > 0; + } + + private void ListView1ItemSelectionChanged(object sender, EventArgs e) + { + button_edit.Enabled = listView1.SelectedItems.Count > 0; + } + + private void ButtonEditClick(object sender, EventArgs e) + { + ListView1DoubleClick(sender, e); + } + + private void ListView1DoubleClick(object sender, EventArgs e) + { + // Safety check for bug #1484 + bool selectionActive = listView1.SelectedItems.Count > 0; + if (!selectionActive) + { + button_edit.Enabled = false; + return; + } + + string commando = listView1.SelectedItems[0].Tag as string; + + var form = new SettingsFormDetail(commando); + form.ShowDialog(); + + UpdateView(); + } + } + + public class ListviewComparer : System.Collections.IComparer + { + public int Compare(object x, object y) + { + if (!(x is ListViewItem)) + { + return (0); + } + + if (!(y is ListViewItem)) + { + return (0); + } + + var l1 = (ListViewItem) x; + var l2 = (ListViewItem) y; + return string.Compare(l1.Text, l2.Text, StringComparison.Ordinal); + } + } +} \ No newline at end of file diff --git a/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs similarity index 86% rename from GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs rename to src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs index dd928449d..ea97436b1 100644 --- a/GreenshotExternalCommandPlugin/SettingsFormDetail.Designer.cs +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.Designer.cs @@ -18,7 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotExternalCommandPlugin { + +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.ExternalCommand { partial class SettingsFormDetail { /// /// Designer variable used to keep track of non-visual components. @@ -46,16 +49,16 @@ namespace GreenshotExternalCommandPlugin { /// private void InitializeComponent() { - this.buttonOk = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.groupBox1 = new GreenshotPlugin.Controls.GreenshotGroupBox(); - this.label4 = new GreenshotPlugin.Controls.GreenshotLabel(); + this.buttonOk = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.groupBox1 = new GreenshotGroupBox(); + this.label4 = new GreenshotLabel(); this.buttonPathSelect = new System.Windows.Forms.Button(); - this.label3 = new GreenshotPlugin.Controls.GreenshotLabel(); + this.label3 = new GreenshotLabel(); this.textBox_name = new System.Windows.Forms.TextBox(); - this.label2 = new GreenshotPlugin.Controls.GreenshotLabel(); + this.label2 = new GreenshotLabel(); this.textBox_arguments = new System.Windows.Forms.TextBox(); - this.label1 = new GreenshotPlugin.Controls.GreenshotLabel(); + this.label1 = new GreenshotLabel(); this.textBox_commandline = new System.Windows.Forms.TextBox(); this.groupBox1.SuspendLayout(); this.SuspendLayout(); @@ -184,13 +187,13 @@ namespace GreenshotExternalCommandPlugin { this.ResumeLayout(false); } - private GreenshotPlugin.Controls.GreenshotLabel label1; - private GreenshotPlugin.Controls.GreenshotLabel label2; - private GreenshotPlugin.Controls.GreenshotLabel label3; - private GreenshotPlugin.Controls.GreenshotLabel label4; - private GreenshotPlugin.Controls.GreenshotGroupBox groupBox1; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOk; + private GreenshotLabel label1; + private GreenshotLabel label2; + private GreenshotLabel label3; + private GreenshotLabel label4; + private GreenshotGroupBox groupBox1; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOk; private System.Windows.Forms.TextBox textBox_commandline; private System.Windows.Forms.TextBox textBox_arguments; private System.Windows.Forms.TextBox textBox_name; diff --git a/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs new file mode 100644 index 000000000..c5551b291 --- /dev/null +++ b/src/Greenshot.Plugin.ExternalCommand/SettingsFormDetail.cs @@ -0,0 +1,192 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.ExternalCommand +{ + /// + /// Description of SettingsFormDetail. + /// + public partial class SettingsFormDetail : ExternalCommandForm + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(SettingsFormDetail)); + private static readonly ExternalCommandConfiguration ExternalCommandConfig = IniConfig.GetIniSection(); + + private readonly string _commando; + private readonly int _commandIndex; + + public SettingsFormDetail(string commando) + { + InitializeComponent(); + AcceptButton = buttonOk; + CancelButton = buttonCancel; + _commando = commando; + + if (commando != null) + { + textBox_name.Text = commando; + textBox_commandline.Text = ExternalCommandConfig.Commandline[commando]; + textBox_arguments.Text = ExternalCommandConfig.Argument[commando]; + _commandIndex = ExternalCommandConfig.Commands.FindIndex(s => s == commando); + } + else + { + textBox_arguments.Text = "\"{0}\""; + } + + OkButtonState(); + } + + private void ButtonOkClick(object sender, EventArgs e) + { + string commandName = textBox_name.Text; + string commandLine = textBox_commandline.Text; + string arguments = textBox_arguments.Text; + if (_commando != null) + { + ExternalCommandConfig.Commands[_commandIndex] = commandName; + ExternalCommandConfig.Commandline.Remove(_commando); + ExternalCommandConfig.Commandline.Add(commandName, commandLine); + ExternalCommandConfig.Argument.Remove(_commando); + ExternalCommandConfig.Argument.Add(commandName, arguments); + } + else + { + ExternalCommandConfig.Commands.Add(commandName); + ExternalCommandConfig.Commandline.Add(commandName, commandLine); + ExternalCommandConfig.Argument.Add(commandName, arguments); + } + } + + private void Button3Click(object sender, EventArgs e) + { + var openFileDialog = new OpenFileDialog + { + Filter = "Executables (*.exe, *.bat, *.com)|*.exe; *.bat; *.com|All files (*)|*", + FilterIndex = 1, + CheckFileExists = true, + Multiselect = false + }; + string initialPath = null; + try + { + initialPath = Path.GetDirectoryName(textBox_commandline.Text); + } + catch (Exception ex) + { + Log.WarnFormat("Can't get the initial path via {0}", textBox_commandline.Text); + Log.Warn("Exception: ", ex); + } + + if (initialPath != null && Directory.Exists(initialPath)) + { + openFileDialog.InitialDirectory = initialPath; + } + else + { + initialPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + openFileDialog.InitialDirectory = initialPath; + } + + Log.DebugFormat("Starting OpenFileDialog at {0}", initialPath); + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + textBox_commandline.Text = openFileDialog.FileName; + } + } + + private void OkButtonState() + { + // Assume OK + buttonOk.Enabled = true; + textBox_name.BackColor = Color.White; + textBox_commandline.BackColor = Color.White; + textBox_arguments.BackColor = Color.White; + // Is there a text in the name field + if (string.IsNullOrEmpty(textBox_name.Text)) + { + buttonOk.Enabled = false; + } + + // Check if commandname is unique + if (_commando == null && !string.IsNullOrEmpty(textBox_name.Text) && ExternalCommandConfig.Commands.Contains(textBox_name.Text)) + { + buttonOk.Enabled = false; + textBox_name.BackColor = Color.Red; + } + + // Is there a text in the commandline field + if (string.IsNullOrEmpty(textBox_commandline.Text)) + { + buttonOk.Enabled = false; + } + + if (!string.IsNullOrEmpty(textBox_commandline.Text)) + { + // Added this to be more flexible, using the Greenshot var format + string cmdPath = FilenameHelper.FillVariables(textBox_commandline.Text, true); + // And also replace the "DOS" Variables + cmdPath = FilenameHelper.FillCmdVariables(cmdPath, true); + // Is the command available? + if (!File.Exists(cmdPath)) + { + buttonOk.Enabled = false; + textBox_commandline.BackColor = Color.Red; + } + } + + // Are the arguments in a valid format? + try + { + string arguments = FilenameHelper.FillVariables(textBox_arguments.Text, false); + arguments = FilenameHelper.FillCmdVariables(arguments, false); + + ExternalCommandDestination.FormatArguments(arguments, string.Empty); + } + catch + { + buttonOk.Enabled = false; + textBox_arguments.BackColor = Color.Red; + } + } + + private void textBox_name_TextChanged(object sender, EventArgs e) + { + OkButtonState(); + } + + private void textBox_commandline_TextChanged(object sender, EventArgs e) + { + OkButtonState(); + } + + private void textBox_arguments_TextChanged(object sender, EventArgs e) + { + OkButtonState(); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs new file mode 100644 index 000000000..5e4f6801f --- /dev/null +++ b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs @@ -0,0 +1,90 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Plugin.Flickr.Forms; + +namespace Greenshot.Plugin.Flickr +{ + public enum SafetyLevel + { + Safe = 1, + Moderate = 2, + Restricted = 3 + } + + /// + /// Description of FlickrConfiguration. + /// + [IniSection("Flickr", Description = "Greenshot Flickr Plugin configuration")] + public class FlickrConfiguration : IniSection + { + [IniProperty("flickrIsPublic", Description = "IsPublic.", DefaultValue = "true")] + public bool IsPublic { get; set; } + + [IniProperty("flickrIsFamily", Description = "IsFamily.", DefaultValue = "true")] + public bool IsFamily { get; set; } + + [IniProperty("flickrIsFriend", Description = "IsFriend.", DefaultValue = "true")] + public bool IsFriend { get; set; } + + [IniProperty("SafetyLevel", Description = "Safety level", DefaultValue = "Safe")] + public SafetyLevel SafetyLevel { get; set; } + + [IniProperty("HiddenFromSearch", Description = "Hidden from search", DefaultValue = "false")] + public bool HiddenFromSearch { get; set; } + + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send flickr link to clipboard.", DefaultValue = "true")] + public bool AfterUploadLinkToClipBoard { get; set; } + + [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] + public bool UsePageLink { get; set; } + + [IniProperty("FlickrToken", Description = "The Flickr token", Encrypted = true, ExcludeIfNull = true)] + public string FlickrToken { get; set; } + + [IniProperty("FlickrTokenSecret", Description = "The Flickr token secret", Encrypted = true, ExcludeIfNull = true)] + public string FlickrTokenSecret { get; set; } + + /// + /// A form for token + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + DialogResult result = new SettingsForm().ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/FlickrDestination.cs b/src/Greenshot.Plugin.Flickr/FlickrDestination.cs new file mode 100644 index 000000000..2d432e929 --- /dev/null +++ b/src/Greenshot.Plugin.Flickr/FlickrDestination.cs @@ -0,0 +1,65 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Plugin.Flickr +{ + public class FlickrDestination : AbstractDestination + { + private readonly FlickrPlugin _plugin; + + public FlickrDestination(FlickrPlugin plugin) + { + _plugin = plugin; + } + + public override string Designation => "Flickr"; + + public override string Description => Language.GetString("flickr", LangKey.upload_menu_item); + + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(FlickrPlugin)); + return (Image) resources.GetObject("flickr"); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); + if (uploaded) + { + exportInformation.ExportMade = true; + exportInformation.Uri = uploadUrl; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs new file mode 100644 index 000000000..25c9095b2 --- /dev/null +++ b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs @@ -0,0 +1,154 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using log4net; + +namespace Greenshot.Plugin.Flickr +{ + /// + /// This is the Flickr base code + /// + [Plugin("Flickr", true)] + public class FlickrPlugin : IGreenshotPlugin + { + private static readonly ILog Log = LogManager.GetLogger(typeof(FlickrPlugin)); + private static FlickrConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInConfig; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + if (!disposing) + { + return; + } + + if (_itemPlugInConfig == null) + { + return; + } + + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + public bool Initialize() + { + // Register configuration (don't need the configuration itself) + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(FlickrPlugin)); + + _itemPlugInConfig = new ToolStripMenuItem + { + Text = Language.GetString("flickr", LangKey.Configure), + Image = (Image) _resources.GetObject("flickr") + }; + _itemPlugInConfig.Click += ConfigMenuClick; + SimpleServiceProvider.Current.AddService(new FlickrDestination(this)); + PluginUtils.AddToContextMenu(_itemPlugInConfig); + Language.LanguageChanged += OnLanguageChanged; + return true; + } + + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Text = Language.GetString("flickr", LangKey.Configure); + } + } + + public void Shutdown() + { + Log.Debug("Flickr Plugin shutdown."); + } + + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + _config.ShowConfigDialog(); + } + + public void ConfigMenuClick(object sender, EventArgs eventArgs) + { + _config.ShowConfigDialog(); + } + + public bool Upload(ICaptureDetails captureDetails, ISurface surface, out string uploadUrl) + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, false); + uploadUrl = null; + try + { + string flickrUrl = null; + new PleaseWaitForm().ShowAndWait("Flickr", Language.GetString("flickr", LangKey.communication_wait), + delegate + { + string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); + flickrUrl = FlickrUtils.UploadToFlickr(surface, outputSettings, captureDetails.Title, filename); + } + ); + + if (flickrUrl == null) + { + return false; + } + + uploadUrl = flickrUrl; + + if (_config.AfterUploadLinkToClipBoard) + { + ClipboardHelper.SetClipboardData(flickrUrl); + } + + return true; + } + catch (Exception e) + { + Log.Error("Error uploading.", e); + MessageBox.Show(Language.GetString("flickr", LangKey.upload_failure) + " " + e.Message); + } + + return false; + } + } +} \ No newline at end of file diff --git a/GreenshotFlickrPlugin/FlickrPlugin.resx b/src/Greenshot.Plugin.Flickr/FlickrPlugin.resx similarity index 100% rename from GreenshotFlickrPlugin/FlickrPlugin.resx rename to src/Greenshot.Plugin.Flickr/FlickrPlugin.resx diff --git a/src/Greenshot.Plugin.Flickr/FlickrUtils.cs b/src/Greenshot.Plugin.Flickr/FlickrUtils.cs new file mode 100644 index 000000000..29a0417e9 --- /dev/null +++ b/src/Greenshot.Plugin.Flickr/FlickrUtils.cs @@ -0,0 +1,232 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Xml; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using log4net; + +namespace Greenshot.Plugin.Flickr +{ + /// + /// Description of FlickrUtils. + /// + public static class FlickrUtils + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(FlickrUtils)); + private static readonly FlickrConfiguration config = IniConfig.GetIniSection(); + private const string FLICKR_API_BASE_URL = "https://api.flickr.com/services/"; + + private const string FLICKR_UPLOAD_URL = FLICKR_API_BASE_URL + "upload/"; + + // OAUTH + private const string FLICKR_OAUTH_BASE_URL = FLICKR_API_BASE_URL + "oauth/"; + private const string FLICKR_ACCESS_TOKEN_URL = FLICKR_OAUTH_BASE_URL + "access_token"; + private const string FLICKR_AUTHORIZE_URL = FLICKR_OAUTH_BASE_URL + "authorize"; + private const string FLICKR_REQUEST_TOKEN_URL = FLICKR_OAUTH_BASE_URL + "request_token"; + + private const string FLICKR_FARM_URL = "https://farm{0}.staticflickr.com/{1}/{2}_{3}_o.{4}"; + + // REST + private const string FLICKR_REST_URL = FLICKR_API_BASE_URL + "rest/"; + private const string FLICKR_GET_INFO_URL = FLICKR_REST_URL + "?method=flickr.photos.getInfo"; + + /// + /// Do the actual upload to Flickr + /// For more details on the available parameters, see: http://flickrnet.codeplex.com + /// + /// + /// + /// + /// + /// url to image + public static string UploadToFlickr(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) + { + var oAuth = new OAuthSession(FlickrCredentials.ConsumerKey, FlickrCredentials.ConsumerSecret) + { + BrowserSize = new Size(520, 800), + CheckVerifier = false, + AccessTokenUrl = FLICKR_ACCESS_TOKEN_URL, + AuthorizeUrl = FLICKR_AUTHORIZE_URL, + RequestTokenUrl = FLICKR_REQUEST_TOKEN_URL, + LoginTitle = "Flickr authorization", + Token = config.FlickrToken, + TokenSecret = config.FlickrTokenSecret + }; + if (string.IsNullOrEmpty(oAuth.Token)) + { + if (!oAuth.Authorize()) + { + return null; + } + + if (!string.IsNullOrEmpty(oAuth.Token)) + { + config.FlickrToken = oAuth.Token; + } + + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) + { + config.FlickrTokenSecret = oAuth.TokenSecret; + } + + IniConfig.Save(); + } + + try + { + IDictionary signedParameters = new Dictionary + { + { + "content_type", "2" + }, // Screenshot + { + "tags", "Greenshot" + }, + { + "is_public", config.IsPublic ? "1" : "0" + }, + { + "is_friend", config.IsFriend ? "1" : "0" + }, + { + "is_family", config.IsFamily ? "1" : "0" + }, + { + "safety_level", $"{(int) config.SafetyLevel}" + }, + { + "hidden", config.HiddenFromSearch ? "1" : "2" + } + }; + IDictionary otherParameters = new Dictionary + { + { + "photo", new SurfaceContainer(surfaceToUpload, outputSettings, filename) + } + }; + string response = oAuth.MakeOAuthRequest(HTTPMethod.POST, FLICKR_UPLOAD_URL, signedParameters, otherParameters, null); + string photoId = GetPhotoId(response); + + // Get Photo Info + signedParameters = new Dictionary + { + { + "photo_id", photoId + } + }; + string photoInfo = oAuth.MakeOAuthRequest(HTTPMethod.POST, FLICKR_GET_INFO_URL, signedParameters, null, null); + return GetUrl(photoInfo); + } + catch (Exception ex) + { + LOG.Error("Upload error: ", ex); + throw; + } + finally + { + if (!string.IsNullOrEmpty(oAuth.Token)) + { + config.FlickrToken = oAuth.Token; + } + + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) + { + config.FlickrTokenSecret = oAuth.TokenSecret; + } + } + } + + private static string GetUrl(string response) + { + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + if (config.UsePageLink) + { + XmlNodeList nodes = doc.GetElementsByTagName("url"); + if (nodes.Count > 0) + { + var xmlNode = nodes.Item(0); + if (xmlNode != null) + { + return xmlNode.InnerText; + } + } + } + else + { + XmlNodeList nodes = doc.GetElementsByTagName("photo"); + if (nodes.Count > 0) + { + var item = nodes.Item(0); + if (item?.Attributes != null) + { + string farmId = item.Attributes["farm"].Value; + string serverId = item.Attributes["server"].Value; + string photoId = item.Attributes["id"].Value; + string originalsecret = item.Attributes["originalsecret"].Value; + string originalFormat = item.Attributes["originalformat"].Value; + return string.Format(FLICKR_FARM_URL, farmId, serverId, photoId, originalsecret, originalFormat); + } + } + } + } + catch (Exception ex) + { + LOG.Error("Error parsing Flickr Response.", ex); + } + + return null; + } + + private static string GetPhotoId(string response) + { + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + XmlNodeList nodes = doc.GetElementsByTagName("photoid"); + if (nodes.Count > 0) + { + var xmlNode = nodes.Item(0); + if (xmlNode != null) + { + return xmlNode.InnerText; + } + } + } + catch (Exception ex) + { + LOG.Error("Error parsing Flickr Response.", ex); + } + + return null; + } + } +} \ No newline at end of file diff --git a/GreenshotFlickrPlugin/Forms/FlickrForm.cs b/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs similarity index 85% rename from GreenshotFlickrPlugin/Forms/FlickrForm.cs rename to src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs index 94e161d64..0fe3dc300 100644 --- a/GreenshotFlickrPlugin/Forms/FlickrForm.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/FlickrForm.cs @@ -19,9 +19,11 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace GreenshotFlickrPlugin.Forms { - public class FlickrForm : GreenshotForm { - } +namespace Greenshot.Plugin.Flickr.Forms +{ + public class FlickrForm : GreenshotForm + { + } } \ No newline at end of file diff --git a/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs similarity index 81% rename from GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs index 18001eab2..95f7c653d 100644 --- a/GreenshotFlickrPlugin/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs @@ -18,7 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotFlickrPlugin.Forms { + +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.Flickr.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. @@ -46,18 +49,18 @@ namespace GreenshotFlickrPlugin.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkBoxPublic = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkBoxFamily = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkBoxFriend = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.label_SafetyLevel = new GreenshotPlugin.Controls.GreenshotLabel(); - this.combobox_safetyLevel = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkBox_hiddenfromsearch = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.checkBoxPublic = new GreenshotCheckBox(); + this.checkBoxFamily = new GreenshotCheckBox(); + this.checkBoxFriend = new GreenshotCheckBox(); + this.label_SafetyLevel = new GreenshotLabel(); + this.combobox_safetyLevel = new GreenshotComboBox(); + this.label_AfterUpload = new GreenshotLabel(); + this.checkboxAfterUploadLinkToClipBoard = new GreenshotCheckBox(); + this.checkBox_hiddenfromsearch = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -213,17 +216,17 @@ namespace GreenshotFlickrPlugin.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotCheckBox checkBox_hiddenfromsearch; - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotCheckBox checkBoxPublic; - private GreenshotPlugin.Controls.GreenshotCheckBox checkBoxFamily; - private GreenshotPlugin.Controls.GreenshotCheckBox checkBoxFriend; - private GreenshotPlugin.Controls.GreenshotLabel label_SafetyLevel; - private GreenshotPlugin.Controls.GreenshotComboBox combobox_safetyLevel; - private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; + private GreenshotCheckBox checkBox_hiddenfromsearch; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotCheckBox checkBoxPublic; + private GreenshotCheckBox checkBoxFamily; + private GreenshotCheckBox checkBoxFriend; + private GreenshotLabel label_SafetyLevel; + private GreenshotComboBox combobox_safetyLevel; + private GreenshotLabel label_AfterUpload; + private GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; } } diff --git a/GreenshotDropboxPlugin/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs similarity index 64% rename from GreenshotDropboxPlugin/Forms/SettingsForm.cs rename to src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs index 98e1147ce..332f28664 100644 --- a/GreenshotDropboxPlugin/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.cs @@ -19,19 +19,21 @@ * along with this program. If not, see . */ -namespace GreenshotDropboxPlugin.Forms { - /// - /// Description of PasswordRequestForm. - /// - public partial class SettingsForm : DropboxForm { - public SettingsForm() { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - AcceptButton = buttonOK; - CancelButton = buttonCancel; - } - - } -} +namespace Greenshot.Plugin.Flickr.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : FlickrForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + CancelButton = buttonCancel; + AcceptButton = buttonOK; + } + } +} \ No newline at end of file diff --git a/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.Credentials.template similarity index 97% rename from GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template rename to src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.Credentials.template index fb69e4460..0d7c50529 100644 --- a/GreenshotFlickrPlugin/GreenshotFlickrPlugin.Credentials.template +++ b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotFlickrPlugin { +namespace Greenshot.Plugin.Flickr { /// /// This class is merely a placeholder for the file keeping the API key and secret for dropbox integration. /// You can set your own values here diff --git a/GreenshotFlickrPlugin/GreenshotFlickrPlugin.csproj b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj similarity index 56% rename from GreenshotFlickrPlugin/GreenshotFlickrPlugin.csproj rename to src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj index 9c7a8c597..548307884 100644 --- a/GreenshotFlickrPlugin/GreenshotFlickrPlugin.csproj +++ b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj @@ -1,10 +1,4 @@  - - - GreenshotFlickrPlugin - GreenshotFlickrPlugin - - PreserveNewest @@ -16,6 +10,6 @@ - + \ No newline at end of file diff --git a/GreenshotBoxPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Flickr/LanguageKeys.cs similarity index 82% rename from GreenshotBoxPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Flickr/LanguageKeys.cs index 5d2491ae3..da634aabe 100644 --- a/GreenshotBoxPlugin/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Flickr/LanguageKeys.cs @@ -18,11 +18,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotBoxPlugin { - public enum LangKey { - upload_menu_item, - upload_failure, - communication_wait, - Configure - } -} + +namespace Greenshot.Plugin.Flickr +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + Configure + } +} \ No newline at end of file diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-cs-CZ.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-cs-CZ.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-cs-CZ.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-de-DE.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-de-DE.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-de-DE.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-de-DE.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-en-US.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-en-US.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-en-US.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-en-US.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-fr-FR.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-fr-FR.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-fr-FR.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-fr-FR.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-id-ID.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-id-ID.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-id-ID.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-id-ID.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-it-IT.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-it-IT.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-it-IT.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-ja-JP.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ja-JP.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-ja-JP.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ja-JP.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-kab-DZ.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-kab-DZ.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-kab-DZ.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-ko-KR.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ko-KR.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-ko-KR.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ko-KR.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-lv-LV.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-lv-LV.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-lv-LV.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-lv-LV.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-pl-PL.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-pl-PL.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-pl-PL.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-pl-PL.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-pt-PT.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-pt-PT.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-pt-PT.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-pt-PT.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-ru-RU.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ru-RU.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-ru-RU.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-ru-RU.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-sr-RS.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-sr-RS.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-sr-RS.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-sr-RS.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-sv-SE.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-sv-SE.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-sv-SE.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-sv-SE.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-uk-UA.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-uk-UA.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-uk-UA.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-uk-UA.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-CN.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-zh-CN.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-CN.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-zh-CN.xml diff --git a/GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-TW.xml b/src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-zh-TW.xml similarity index 100% rename from GreenshotFlickrPlugin/Languages/language_flickrplugin-zh-TW.xml rename to src/Greenshot.Plugin.Flickr/Languages/language_flickrplugin-zh-TW.xml diff --git a/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs similarity index 97% rename from GreenshotFlickrPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs index 7cc8b4a3a..84938a6ab 100644 --- a/GreenshotFlickrPlugin/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/GreenshotFlickrPlugin/flickr.png b/src/Greenshot.Plugin.Flickr/flickr.png similarity index 100% rename from GreenshotFlickrPlugin/flickr.png rename to src/Greenshot.Plugin.Flickr/flickr.png diff --git a/GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs similarity index 84% rename from GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs rename to src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs index 10b18bebe..9936efcdc 100644 --- a/GreenshotGooglePhotosPlugin/Forms/GooglePhotosForm.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/GooglePhotosForm.cs @@ -18,9 +18,11 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace GreenshotGooglePhotosPlugin.Forms { - public class GooglePhotosForm : GreenshotForm { - } -} +namespace Greenshot.Plugin.GooglePhotos.Forms +{ + public class GooglePhotosForm : GreenshotForm + { + } +} \ No newline at end of file diff --git a/GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs similarity index 86% rename from GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs index cea2b6acf..dcc750f55 100644 --- a/GreenshotGooglePhotosPlugin/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs @@ -17,7 +17,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotGooglePhotosPlugin.Forms { + +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.GooglePhotos.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. @@ -45,12 +48,12 @@ namespace GreenshotGooglePhotosPlugin.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.label_AfterUpload = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkboxAfterUploadLinkToClipBoard = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.label_AfterUpload = new GreenshotLabel(); + this.checkboxAfterUploadLinkToClipBoard = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -137,11 +140,11 @@ namespace GreenshotGooglePhotosPlugin.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotLabel label_AfterUpload; - private GreenshotPlugin.Controls.GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotLabel label_AfterUpload; + private GreenshotCheckBox checkboxAfterUploadLinkToClipBoard; } } diff --git a/GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs similarity index 62% rename from GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs rename to src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs index be31f1d44..6029212f9 100644 --- a/GreenshotGooglePhotosPlugin/Forms/SettingsForm.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.cs @@ -18,21 +18,21 @@ * along with this program. If not, see . */ -namespace GreenshotGooglePhotosPlugin.Forms { - /// - /// Description of PasswordRequestForm. - /// - public partial class SettingsForm : GooglePhotosForm { - - public SettingsForm() - { - // - // The InitializeComponent() call is required for Windows Forms designer support. - // - InitializeComponent(); - CancelButton = buttonCancel; - AcceptButton = buttonOK; - } - - } -} +namespace Greenshot.Plugin.GooglePhotos.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : GooglePhotosForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + CancelButton = buttonCancel; + AcceptButton = buttonOK; + } + } +} \ No newline at end of file diff --git a/GreenshotGooglePhotosPlugin/GooglePhotos.png b/src/Greenshot.Plugin.GooglePhotos/GooglePhotos.png similarity index 100% rename from GreenshotGooglePhotosPlugin/GooglePhotos.png rename to src/Greenshot.Plugin.GooglePhotos/GooglePhotos.png diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs new file mode 100644 index 000000000..34285a7b3 --- /dev/null +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs @@ -0,0 +1,81 @@ +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Plugin.GooglePhotos.Forms; + +namespace Greenshot.Plugin.GooglePhotos +{ + /// + /// Description of GooglePhotosConfiguration. + /// + [IniSection("GooglePhotos", Description = "Greenshot GooglePhotos Plugin configuration")] + public class GooglePhotosConfiguration : IniSection + { + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send GooglePhotos link to clipboard.", DefaultValue = "true")] + public bool AfterUploadLinkToClipBoard { get; set; } + + [IniProperty("AddFilename", Description = "Is the filename passed on to GooglePhotos", DefaultValue = "False")] + public bool AddFilename { get; set; } + + [IniProperty("UploadUser", Description = "The GooglePhotos user to upload to", DefaultValue = "default")] + public string UploadUser { get; set; } + + [IniProperty("UploadAlbum", Description = "The GooglePhotos album to upload to", DefaultValue = "default")] + public string UploadAlbum { get; set; } + + [IniProperty("RefreshToken", Description = "GooglePhotos authorization refresh Token", Encrypted = true)] + public string RefreshToken { get; set; } + + /// + /// Not stored + /// + public string AccessToken { get; set; } + + /// + /// Not stored + /// + public DateTimeOffset AccessTokenExpires { get; set; } + + /// + /// A form for token + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + DialogResult result = new SettingsForm().ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs new file mode 100644 index 000000000..2080f49c2 --- /dev/null +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosDestination.cs @@ -0,0 +1,64 @@ +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Plugin.GooglePhotos +{ + public class GooglePhotosDestination : AbstractDestination + { + private readonly GooglePhotosPlugin _plugin; + + public GooglePhotosDestination(GooglePhotosPlugin plugin) + { + _plugin = plugin; + } + + public override string Designation => "GooglePhotos"; + + public override string Description => Language.GetString("googlephotos", LangKey.upload_menu_item); + + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(GooglePhotosPlugin)); + return (Image) resources.GetObject("GooglePhotos"); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + bool uploaded = _plugin.Upload(captureDetails, surface, out var uploadUrl); + if (uploaded) + { + exportInformation.ExportMade = true; + exportInformation.Uri = uploadUrl; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs new file mode 100644 index 000000000..6c4d02b8f --- /dev/null +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs @@ -0,0 +1,141 @@ +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Plugin.GooglePhotos +{ + /// + /// This is the GooglePhotos base code + /// + [Plugin("GooglePhotos", true)] + public class GooglePhotosPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosPlugin)); + private static GooglePhotosConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInRoot; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (!disposing) return; + if (_itemPlugInRoot == null) return; + _itemPlugInRoot.Dispose(); + _itemPlugInRoot = null; + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + public bool Initialize() + { + SimpleServiceProvider.Current.AddService(new GooglePhotosDestination(this)); + + // Get configuration + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(GooglePhotosPlugin)); + + _itemPlugInRoot = new ToolStripMenuItem + { + Text = Language.GetString("googlephotos", LangKey.Configure), + Image = (Image) _resources.GetObject("GooglePhotos") + }; + _itemPlugInRoot.Click += ConfigMenuClick; + PluginUtils.AddToContextMenu(_itemPlugInRoot); + Language.LanguageChanged += OnLanguageChanged; + return true; + } + + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInRoot != null) + { + _itemPlugInRoot.Text = Language.GetString("googlephotos", LangKey.Configure); + } + } + + public void Shutdown() + { + Log.Debug("GooglePhotos Plugin shutdown."); + Language.LanguageChanged -= OnLanguageChanged; + //host.OnImageEditorOpen -= new OnImageEditorOpenHandler(ImageEditorOpened); + } + + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + _config.ShowConfigDialog(); + } + + public void ConfigMenuClick(object sender, EventArgs eventArgs) + { + Configure(); + } + + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality); + try + { + string url = null; + new PleaseWaitForm().ShowAndWait("GooglePhotos", Language.GetString("googlephotos", LangKey.communication_wait), + delegate + { + string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); + url = GooglePhotosUtils.UploadToGooglePhotos(surfaceToUpload, outputSettings, captureDetails.Title, filename); + } + ); + uploadUrl = url; + + if (uploadUrl != null && _config.AfterUploadLinkToClipBoard) + { + ClipboardHelper.SetClipboardData(uploadUrl); + } + + return true; + } + catch (Exception e) + { + Log.Error("Error uploading.", e); + MessageBox.Show(Language.GetString("googlephotos", LangKey.upload_failure) + " " + e.Message); + } + + uploadUrl = null; + return false; + } + } +} \ No newline at end of file diff --git a/GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.resx similarity index 100% rename from GreenshotGooglePhotosPlugin/GooglePhotosPlugin.resx rename to src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.resx diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs new file mode 100644 index 000000000..1f225d895 --- /dev/null +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosUtils.cs @@ -0,0 +1,143 @@ +/* + * A GooglePhotos Plugin for Greenshot + * Copyright (C) 2011 Francis Noel + * + * For more information see: http://getgreenshot.org/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Xml; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Plugin.GooglePhotos +{ + /// + /// Description of GooglePhotosUtils. + /// + public static class GooglePhotosUtils + { + private const string GooglePhotosScope = "https://picasaweb.google.com/data/"; + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosUtils)); + private static readonly GooglePhotosConfiguration Config = IniConfig.GetIniSection(); + + private const string AuthUrl = "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={ClientId}&redirect_uri={RedirectUrl}&state={State}&scope=" + + GooglePhotosScope; + + private const string TokenUrl = "https://www.googleapis.com/oauth2/v3/token"; + private const string UploadUrl = "https://picasaweb.google.com/data/feed/api/user/{0}/albumid/{1}"; + + /// + /// Do the actual upload to GooglePhotos + /// + /// Image to upload + /// SurfaceOutputSettings + /// string + /// string + /// GooglePhotosResponse + public static string UploadToGooglePhotos(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) + { + // Fill the OAuth2Settings + var settings = new OAuth2Settings + { + AuthUrlPattern = AuthUrl, + TokenUrl = TokenUrl, + CloudServiceName = "GooglePhotos", + ClientId = GooglePhotosCredentials.ClientId, + ClientSecret = GooglePhotosCredentials.ClientSecret, + AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, + RefreshToken = Config.RefreshToken, + AccessToken = Config.AccessToken, + AccessTokenExpires = Config.AccessTokenExpires + }; + + // Copy the settings from the config, which is kept in memory and on the disk + + try + { + var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, string.Format(UploadUrl, Config.UploadUser, Config.UploadAlbum), settings); + if (Config.AddFilename) + { + webRequest.Headers.Add("Slug", NetworkHelper.EscapeDataString(filename)); + } + + SurfaceContainer container = new SurfaceContainer(surfaceToUpload, outputSettings, filename); + container.Upload(webRequest); + + string response = NetworkHelper.GetResponseAsString(webRequest); + + return ParseResponse(response); + } + finally + { + // Copy the settings back to the config, so they are stored. + Config.RefreshToken = settings.RefreshToken; + Config.AccessToken = settings.AccessToken; + Config.AccessTokenExpires = settings.AccessTokenExpires; + Config.IsDirty = true; + IniConfig.Save(); + } + } + + /// + /// Parse the upload URL from the response + /// + /// + /// + public static string ParseResponse(string response) + { + if (response == null) + { + return null; + } + + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + XmlNodeList nodes = doc.GetElementsByTagName("link", "*"); + if (nodes.Count > 0) + { + string url = null; + foreach (XmlNode node in nodes) + { + if (node.Attributes != null) + { + url = node.Attributes["href"].Value; + string rel = node.Attributes["rel"].Value; + // Pictures with rel="http://schemas.google.com/photos/2007#canonical" are the direct link + if (rel != null && rel.EndsWith("canonical")) + { + break; + } + } + } + + return url; + } + } + catch (Exception e) + { + Log.ErrorFormat("Could not parse GooglePhotos response due to error {0}, response was: {1}", e.Message, response); + } + + return null; + } + } +} \ No newline at end of file diff --git a/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.Credentials.template similarity index 96% rename from GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template rename to src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.Credentials.template index 452922112..c4ff6bfc6 100644 --- a/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.Credentials.template +++ b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotGooglePhotosPlugin { +namespace Greenshot.Plugin.GooglePhotos { /// /// This class is merely a placeholder for the file keeping the API key and secret for dropbox integration. /// You can set your own values here diff --git a/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj similarity index 68% rename from GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj rename to src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj index 3fb62aa99..a798964c1 100644 --- a/GreenshotGooglePhotosPlugin/GreenshotGooglePhotosPlugin.csproj +++ b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj @@ -6,10 +6,10 @@ - + - + \ No newline at end of file diff --git a/GreenshotGooglePhotosPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs similarity index 81% rename from GreenshotGooglePhotosPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs index 1a7a73996..7eaab1020 100644 --- a/GreenshotGooglePhotosPlugin/LanguageKeys.cs +++ b/src/Greenshot.Plugin.GooglePhotos/LanguageKeys.cs @@ -18,12 +18,13 @@ * along with this program. If not, see . */ -namespace GreenshotGooglePhotosPlugin { - public enum LangKey - { - upload_menu_item, - upload_failure, - communication_wait, - Configure - } -} +namespace Greenshot.Plugin.GooglePhotos +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + Configure + } +} \ No newline at end of file diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-cs-CZ.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-cs-CZ.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-cs-CZ.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-de-DE.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-de-DE.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-de-DE.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-en-US.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-en-US.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-en-US.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-fr-FR.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-fr-FR.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-fr-FR.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-id-ID.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-id-ID.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-id-ID.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-it-IT.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-it-IT.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-it-IT.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ja-JP.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ja-JP.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ja-JP.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-kab-DZ.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-kab-DZ.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-kab-DZ.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ko-KR.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ko-KR.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ko-KR.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-lv-LV.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-lv-LV.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-lv-LV.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-pl-PL.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pl-PL.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-pl-PL.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-pt-PT.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-pt-PT.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-pt-PT.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ru-RU.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-ru-RU.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-ru-RU.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-sr-RS.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sr-RS.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-sr-RS.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-sv-SE.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-sv-SE.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-sv-SE.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-uk-UA.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-uk-UA.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-uk-UA.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-zh-CN.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-CN.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-zh-CN.xml diff --git a/GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml b/src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-zh-TW.xml similarity index 100% rename from GreenshotGooglePhotosPlugin/Languages/language_googlephotosplugin-zh-TW.xml rename to src/Greenshot.Plugin.GooglePhotos/Languages/language_googlephotosplugin-zh-TW.xml diff --git a/GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs similarity index 97% rename from GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs index d4fa2878a..d04662538 100644 --- a/GreenshotGooglePhotosPlugin/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/GreenshotGooglePhotosPlugin/README b/src/Greenshot.Plugin.GooglePhotos/README similarity index 100% rename from GreenshotGooglePhotosPlugin/README rename to src/Greenshot.Plugin.GooglePhotos/README diff --git a/GreenshotImgurPlugin/Forms/ImgurForm.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs similarity index 77% rename from GreenshotImgurPlugin/Forms/ImgurForm.cs rename to src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs index 37316ac99..d80c94f92 100644 --- a/GreenshotImgurPlugin/Forms/ImgurForm.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/ImgurForm.cs @@ -19,12 +19,14 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace GreenshotImgurPlugin.Forms { - /// - /// This class is needed for design-time resolving of the language files - /// - public class ImgurForm : GreenshotForm { - } -} +namespace Greenshot.Plugin.Imgur.Forms +{ + /// + /// This class is needed for design-time resolving of the language files + /// + public class ImgurForm : GreenshotForm + { + } +} \ No newline at end of file diff --git a/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.Designer.cs similarity index 97% rename from GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs rename to src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.Designer.cs index f8fb05dd2..9b0b5d923 100644 --- a/GreenshotImgurPlugin/Forms/ImgurHistory.Designer.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotImgurPlugin.Forms +namespace Greenshot.Plugin.Imgur.Forms { partial class ImgurHistory { diff --git a/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs new file mode 100644 index 000000000..c2efa03f4 --- /dev/null +++ b/src/Greenshot.Plugin.Imgur/Forms/ImgurHistory.cs @@ -0,0 +1,263 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Globalization; +using System.Text; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.Imgur.Forms +{ + /// + /// Imgur history form + /// + public sealed partial class ImgurHistory : ImgurForm + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurHistory)); + private readonly GreenshotColumnSorter _columnSorter; + private static readonly object Lock = new object(); + private static readonly ImgurConfiguration Config = IniConfig.GetIniSection(); + private static ImgurHistory _instance; + + public static void ShowHistory() + { + lock (Lock) + { + if (ImgurUtils.IsHistoryLoadingNeeded()) + { + // Run upload in the background + new PleaseWaitForm().ShowAndWait("Imgur " + Language.GetString("imgur", LangKey.history), Language.GetString("imgur", LangKey.communication_wait), + ImgurUtils.LoadHistory + ); + } + + // Make sure the history is loaded, will be done only once + if (_instance == null) + { + _instance = new ImgurHistory(); + } + + if (!_instance.Visible) + { + _instance.Show(); + } + + _instance.Redraw(); + } + } + + private ImgurHistory() + { + ManualLanguageApply = true; + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = finishedButton; + CancelButton = finishedButton; + // Init sorting + _columnSorter = new GreenshotColumnSorter(); + listview_imgur_uploads.ListViewItemSorter = _columnSorter; + _columnSorter.SortColumn = 3; + _columnSorter.Order = SortOrder.Descending; + Redraw(); + if (listview_imgur_uploads.Items.Count > 0) + { + listview_imgur_uploads.Items[0].Selected = true; + } + + ApplyLanguage(); + if (Config.Credits > 0) + { + Text = Text + " (" + Config.Credits + " credits)"; + } + } + + private void Redraw() + { + // Should fix Bug #3378699 + pictureBox1.Image = pictureBox1.ErrorImage; + listview_imgur_uploads.BeginUpdate(); + listview_imgur_uploads.Items.Clear(); + listview_imgur_uploads.Columns.Clear(); + string[] columns = + { + "hash", "title", "deleteHash", "Date" + }; + foreach (string column in columns) + { + listview_imgur_uploads.Columns.Add(column); + } + + foreach (ImgurInfo imgurInfo in Config.runtimeImgurHistory.Values) + { + var item = new ListViewItem(imgurInfo.Hash) + { + Tag = imgurInfo + }; + item.SubItems.Add(imgurInfo.Title); + item.SubItems.Add(imgurInfo.DeleteHash); + item.SubItems.Add(imgurInfo.Timestamp.ToString("yyyy-MM-dd HH:mm:ss", DateTimeFormatInfo.InvariantInfo)); + listview_imgur_uploads.Items.Add(item); + } + + for (int i = 0; i < columns.Length; i++) + { + listview_imgur_uploads.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent); + } + + listview_imgur_uploads.EndUpdate(); + listview_imgur_uploads.Refresh(); + deleteButton.Enabled = false; + openButton.Enabled = false; + clipboardButton.Enabled = false; + } + + private void Listview_imgur_uploadsSelectedIndexChanged(object sender, EventArgs e) + { + pictureBox1.Image = pictureBox1.ErrorImage; + if (listview_imgur_uploads.SelectedItems.Count > 0) + { + deleteButton.Enabled = true; + openButton.Enabled = true; + clipboardButton.Enabled = true; + if (listview_imgur_uploads.SelectedItems.Count == 1) + { + ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[0].Tag; + pictureBox1.Image = imgurInfo.Image; + } + } + else + { + pictureBox1.Image = pictureBox1.ErrorImage; + deleteButton.Enabled = false; + openButton.Enabled = false; + clipboardButton.Enabled = false; + } + } + + private void DeleteButtonClick(object sender, EventArgs e) + { + if (listview_imgur_uploads.SelectedItems.Count > 0) + { + for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) + { + ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag; + DialogResult result = MessageBox.Show(Language.GetFormattedString("imgur", LangKey.delete_question, imgurInfo.Title), + Language.GetFormattedString("imgur", LangKey.delete_title, imgurInfo.Hash), MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (result != DialogResult.Yes) + { + continue; + } + + // Should fix Bug #3378699 + pictureBox1.Image = pictureBox1.ErrorImage; + try + { + new PleaseWaitForm().ShowAndWait("Imgur", Language.GetString("imgur", LangKey.communication_wait), + delegate { ImgurUtils.DeleteImgurImage(imgurInfo); } + ); + } + catch (Exception ex) + { + Log.Warn("Problem communicating with Imgur: ", ex); + } + + imgurInfo.Dispose(); + } + } + + Redraw(); + } + + private void ClipboardButtonClick(object sender, EventArgs e) + { + StringBuilder links = new StringBuilder(); + if (listview_imgur_uploads.SelectedItems.Count > 0) + { + for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) + { + ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag; + links.AppendLine(Config.UsePageLink ? imgurInfo.Page : imgurInfo.Original); + } + } + + ClipboardHelper.SetClipboardData(links.ToString()); + } + + private void ClearHistoryButtonClick(object sender, EventArgs e) + { + DialogResult result = MessageBox.Show(Language.GetString("imgur", LangKey.clear_question), "Imgur", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + if (result == DialogResult.Yes) + { + Config.runtimeImgurHistory.Clear(); + Config.ImgurUploadHistory.Clear(); + IniConfig.Save(); + Redraw(); + } + } + + private void FinishedButtonClick(object sender, EventArgs e) + { + Hide(); + } + + private void OpenButtonClick(object sender, EventArgs e) + { + if (listview_imgur_uploads.SelectedItems.Count > 0) + { + for (int i = 0; i < listview_imgur_uploads.SelectedItems.Count; i++) + { + ImgurInfo imgurInfo = (ImgurInfo) listview_imgur_uploads.SelectedItems[i].Tag; + System.Diagnostics.Process.Start(imgurInfo.Page); + } + } + } + + private void listview_imgur_uploads_ColumnClick(object sender, ColumnClickEventArgs e) + { + // Determine if clicked column is already the column that is being sorted. + if (e.Column == _columnSorter.SortColumn) + { + // Reverse the current sort direction for this column. + _columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; + } + else + { + // Set the column number that is to be sorted; default to ascending. + _columnSorter.SortColumn = e.Column; + _columnSorter.Order = SortOrder.Ascending; + } + + // Perform the sort with these new sort options. + listview_imgur_uploads.Sort(); + } + + + private void ImgurHistoryFormClosing(object sender, FormClosingEventArgs e) + { + _instance = null; + } + } +} \ No newline at end of file diff --git a/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs similarity index 83% rename from GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs index 79192da09..2df2be157 100644 --- a/GreenshotImgurPlugin/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs @@ -18,7 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotImgurPlugin.Forms { + +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.Imgur.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. @@ -46,13 +49,13 @@ namespace GreenshotImgurPlugin.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.historyButton = new GreenshotPlugin.Controls.GreenshotButton(); - this.checkbox_anonymous_access = new GreenshotPlugin.Controls.GreenshotCheckBox(); - this.checkbox_usepagelink = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.historyButton = new GreenshotButton(); + this.checkbox_anonymous_access = new GreenshotCheckBox(); + this.checkbox_usepagelink = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -150,12 +153,12 @@ namespace GreenshotImgurPlugin.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotButton historyButton; - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_anonymous_access; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_usepagelink; + private GreenshotButton historyButton; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotCheckBox checkbox_anonymous_access; + private GreenshotCheckBox checkbox_usepagelink; } } diff --git a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs new file mode 100644 index 000000000..4958f897c --- /dev/null +++ b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.cs @@ -0,0 +1,48 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Plugin.Imgur.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : ImgurForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + CancelButton = buttonCancel; + AcceptButton = buttonOK; + + historyButton.Enabled = ImgurUtils.IsHistoryLoadingNeeded(); + } + + private void ButtonHistoryClick(object sender, EventArgs e) + { + ImgurHistory.ShowHistory(); + } + } +} \ No newline at end of file diff --git a/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.Credentials.template similarity index 97% rename from GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template rename to src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.Credentials.template index 4c6948fea..eaf70d311 100644 --- a/GreenshotImgurPlugin/GreenshotImgurPlugin.Credentials.template +++ b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotImgurPlugin { +namespace Greenshot.Plugin.Imgur { /// /// This class is merely a placeholder for the file keeping the API key and secret for imgur integration. /// You can set your own values here diff --git a/GreenshotImgurPlugin/GreenshotImgurPlugin.csproj b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj similarity index 50% rename from GreenshotImgurPlugin/GreenshotImgurPlugin.csproj rename to src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj index 9e75ecc5b..10a7fd241 100644 --- a/GreenshotImgurPlugin/GreenshotImgurPlugin.csproj +++ b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj @@ -1,10 +1,4 @@  - - - GreenshotImgurPlugin - GreenshotImgurPlugin - - PreserveNewest @@ -12,6 +6,6 @@ - + \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs new file mode 100644 index 000000000..f5af624ab --- /dev/null +++ b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs @@ -0,0 +1,110 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Plugin.Imgur.Forms; + +namespace Greenshot.Plugin.Imgur +{ + /// + /// Description of ImgurConfiguration. + /// + [IniSection("Imgur", Description = "Greenshot Imgur Plugin configuration")] + public class ImgurConfiguration : IniSection + { + [IniProperty("ImgurApi3Url", Description = "Url to Imgur system.", DefaultValue = "https://api.imgur.com/3")] + public string ImgurApi3Url { get; set; } + + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] + public bool UploadReduceColors { get; set; } + + [IniProperty("CopyLinkToClipboard", Description = "Copy the link, which one is controlled by the UsePageLink, on the clipboard", DefaultValue = "True")] + public bool CopyLinkToClipboard { get; set; } + + [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] + public bool UsePageLink { get; set; } + + [IniProperty("AnonymousAccess", Description = "Use anonymous access to Imgur", DefaultValue = "true")] + public bool AnonymousAccess { get; set; } + + [IniProperty("RefreshToken", Description = "Imgur refresh Token", Encrypted = true, ExcludeIfNull = true)] + public string RefreshToken { get; set; } + + /// + /// AccessToken, not stored + /// + public string AccessToken { get; set; } + + /// + /// AccessTokenExpires, not stored + /// + public DateTimeOffset AccessTokenExpires { get; set; } + + [IniProperty("AddTitle", Description = "Is the title passed on to Imgur", DefaultValue = "False")] + public bool AddTitle { get; set; } + + [IniProperty("AddFilename", Description = "Is the filename passed on to Imgur", DefaultValue = "False")] + public bool AddFilename { get; set; } + + [IniProperty("FilenamePattern", Description = "Filename for the Imgur upload", DefaultValue = "${capturetime:d\"yyyyMMdd-HHmm\"}")] + public string FilenamePattern { get; set; } + + [IniProperty("ImgurUploadHistory", Description = "Imgur upload history (ImgurUploadHistory.hash=deleteHash)")] + public Dictionary ImgurUploadHistory { get; set; } + + // Not stored, only run-time! + public Dictionary runtimeImgurHistory = new Dictionary(); + public int Credits { get; set; } + + /// + /// Supply values we can't put as defaults + /// + /// The property to return a default for + /// object with the default value for the supplied property + public override object GetDefault(string property) => + property switch + { + "ImgurUploadHistory" => new Dictionary(), + _ => null + }; + + /// + /// A form for username/password + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + SettingsForm settingsForm = new SettingsForm(); + DialogResult result = settingsForm.ShowDialog(); + return result == DialogResult.OK; + } + } +} \ No newline at end of file diff --git a/GreenshotImgurPlugin/ImgurDestination.cs b/src/Greenshot.Plugin.Imgur/ImgurDestination.cs similarity index 52% rename from GreenshotImgurPlugin/ImgurDestination.cs rename to src/Greenshot.Plugin.Imgur/ImgurDestination.cs index 5303ac295..cb747b9bf 100644 --- a/GreenshotImgurPlugin/ImgurDestination.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurDestination.cs @@ -18,40 +18,48 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System.ComponentModel; using System.Drawing; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; -namespace GreenshotImgurPlugin { - /// - /// Description of ImgurDestination. - /// - public class ImgurDestination : AbstractDestination { - private readonly ImgurPlugin _plugin; +namespace Greenshot.Plugin.Imgur +{ + /// + /// Description of ImgurDestination. + /// + public class ImgurDestination : AbstractDestination + { + private readonly ImgurPlugin _plugin; - public ImgurDestination(ImgurPlugin plugin) { - _plugin = plugin; - } - - public override string Designation => "Imgur"; + public ImgurDestination(ImgurPlugin plugin) + { + _plugin = plugin; + } - public override string Description => Language.GetString("imgur", LangKey.upload_menu_item); + public override string Designation => "Imgur"; - public override Image DisplayIcon { - get { - ComponentResourceManager resources = new ComponentResourceManager(typeof(ImgurPlugin)); - return (Image)resources.GetObject("Imgur"); - } - } + public override string Description => Language.GetString("imgur", LangKey.upload_menu_item); - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(ImgurPlugin)); + return (Image) resources.GetObject("Imgur"); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { ExportInformation exportInformation = new ExportInformation(Designation, Description) { - ExportMade = _plugin.Upload(captureDetails, surface, out var uploadUrl), Uri = uploadUrl + ExportMade = _plugin.Upload(captureDetails, surface, out var uploadUrl), + Uri = uploadUrl }; ProcessExport(exportInformation, surface); - return exportInformation; - } - } -} + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/ImgurInfo.cs b/src/Greenshot.Plugin.Imgur/ImgurInfo.cs new file mode 100644 index 000000000..4fdfb7a86 --- /dev/null +++ b/src/Greenshot.Plugin.Imgur/ImgurInfo.cs @@ -0,0 +1,196 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Xml; + +namespace Greenshot.Plugin.Imgur +{ + /// + /// Description of ImgurInfo. + /// + public class ImgurInfo : IDisposable + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurInfo)); + + public string Hash { get; set; } + + private string _deleteHash; + + public string DeleteHash + { + get { return _deleteHash; } + set + { + _deleteHash = value; + DeletePage = "https://imgur.com/delete/" + value; + } + } + + public string Title { get; set; } + + public string ImageType { get; set; } + + public DateTime Timestamp { get; set; } + + public string Original { get; set; } + + public string Page { get; set; } + + public string SmallSquare { get; set; } + + public string LargeThumbnail { get; set; } + + public string DeletePage { get; set; } + + private Image _image; + + public Image Image + { + get { return _image; } + set + { + _image?.Dispose(); + _image = value; + } + } + + /// + /// The public accessible Dispose + /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _image?.Dispose(); + } + + _image = null; + } + + public static ImgurInfo ParseResponse(string response) + { + Log.Debug(response); + // This is actually a hack for BUG-1695 + // The problem is the (C) sign, we send it HTML encoded "®" to Imgur and get it HTML encoded in the XML back + // Added all the encodings I found quickly, I guess these are not all... but it should fix the issue for now. + response = response.Replace("¢", "¢"); + response = response.Replace("£", "£"); + response = response.Replace("¥", "¥"); + response = response.Replace("€", "€"); + response = response.Replace("©", "©"); + response = response.Replace("®", "®"); + + ImgurInfo imgurInfo = new ImgurInfo(); + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + XmlNodeList nodes = doc.GetElementsByTagName("id"); + if (nodes.Count > 0) + { + imgurInfo.Hash = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("hash"); + if (nodes.Count > 0) + { + imgurInfo.Hash = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("deletehash"); + if (nodes.Count > 0) + { + imgurInfo.DeleteHash = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("type"); + if (nodes.Count > 0) + { + imgurInfo.ImageType = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("title"); + if (nodes.Count > 0) + { + imgurInfo.Title = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("datetime"); + if (nodes.Count > 0) + { + // Version 3 has seconds since Epoch + if (double.TryParse(nodes.Item(0)?.InnerText, out var secondsSince)) + { + var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + imgurInfo.Timestamp = epoch.AddSeconds(secondsSince).DateTime; + } + } + + nodes = doc.GetElementsByTagName("original"); + if (nodes.Count > 0) + { + imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:"); + } + + // Version 3 API only has Link + nodes = doc.GetElementsByTagName("link"); + if (nodes.Count > 0) + { + imgurInfo.Original = nodes.Item(0)?.InnerText.Replace("http:", "https:"); + } + + nodes = doc.GetElementsByTagName("imgur_page"); + if (nodes.Count > 0) + { + imgurInfo.Page = nodes.Item(0)?.InnerText.Replace("http:", "https:"); + } + else + { + // Version 3 doesn't have a page link in the response + imgurInfo.Page = $"https://imgur.com/{imgurInfo.Hash}"; + } + + nodes = doc.GetElementsByTagName("small_square"); + imgurInfo.SmallSquare = nodes.Count > 0 ? nodes.Item(0)?.InnerText : $"http://i.imgur.com/{imgurInfo.Hash}s.png"; + } + catch (Exception e) + { + Log.ErrorFormat("Could not parse Imgur response due to error {0}, response was: {1}", e.Message, response); + } + + return imgurInfo; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs new file mode 100644 index 000000000..400ebc0d8 --- /dev/null +++ b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs @@ -0,0 +1,247 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Imgur.Forms; + +namespace Greenshot.Plugin.Imgur +{ + /// + /// This is the ImgurPlugin code + /// + [Plugin("Imgur", true)] + public class ImgurPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurPlugin)); + private static ImgurConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _historyMenuItem; + private ToolStripMenuItem _itemPlugInConfig; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + if (_historyMenuItem != null) + { + _historyMenuItem.Dispose(); + _historyMenuItem = null; + } + + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; + } + } + } + + private IEnumerable Destinations() + { + yield return new ImgurDestination(this); + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// true if plugin is initialized, false if not (doesn't show) + public bool Initialize() + { + // Get configuration + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(ImgurPlugin)); + + ToolStripMenuItem itemPlugInRoot = new ToolStripMenuItem("Imgur") + { + Image = (Image) _resources.GetObject("Imgur") + }; + + // Provide the IDestination + SimpleServiceProvider.Current.AddService(Destinations()); + _historyMenuItem = new ToolStripMenuItem(Language.GetString("imgur", LangKey.history)); + _historyMenuItem.Click += delegate { ImgurHistory.ShowHistory(); }; + itemPlugInRoot.DropDownItems.Add(_historyMenuItem); + + _itemPlugInConfig = new ToolStripMenuItem(Language.GetString("imgur", LangKey.configure)); + _itemPlugInConfig.Click += delegate { _config.ShowConfigDialog(); }; + itemPlugInRoot.DropDownItems.Add(_itemPlugInConfig); + + PluginUtils.AddToContextMenu(itemPlugInRoot); + Language.LanguageChanged += OnLanguageChanged; + + // Enable history if there are items available + UpdateHistoryMenuItem(); + return true; + } + + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Text = Language.GetString("imgur", LangKey.configure); + } + + if (_historyMenuItem != null) + { + _historyMenuItem.Text = Language.GetString("imgur", LangKey.history); + } + } + + private void UpdateHistoryMenuItem() + { + if (_historyMenuItem == null) + { + return; + } + + try + { + var form = SimpleServiceProvider.Current.GetInstance(); + form.BeginInvoke((MethodInvoker) delegate + { + var historyMenuItem = _historyMenuItem; + if (historyMenuItem == null) + { + return; + } + + if (_config?.ImgurUploadHistory != null && _config.ImgurUploadHistory.Count > 0) + { + historyMenuItem.Enabled = true; + } + else + { + historyMenuItem.Enabled = false; + } + }); + } + catch (Exception ex) + { + Log.Error("Error loading history", ex); + } + } + + public virtual void Shutdown() + { + Log.Debug("Imgur Plugin shutdown."); + Language.LanguageChanged -= OnLanguageChanged; + } + + /// + /// Implementation of the IPlugin.Configure + /// + public virtual void Configure() + { + _config.ShowConfigDialog(); + } + + /// + /// Upload the capture to imgur + /// + /// ICaptureDetails + /// ISurface + /// out string for the url + /// true if the upload succeeded + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, out string uploadUrl) + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, _config.UploadReduceColors); + try + { + string filename = Path.GetFileName(FilenameHelper.GetFilenameFromPattern(_config.FilenamePattern, _config.UploadFormat, captureDetails)); + ImgurInfo imgurInfo = null; + + // Run upload in the background + new PleaseWaitForm().ShowAndWait("Imgur plug-in", Language.GetString("imgur", LangKey.communication_wait), + delegate + { + imgurInfo = ImgurUtils.UploadToImgur(surfaceToUpload, outputSettings, captureDetails.Title, filename); + if (imgurInfo != null && _config.AnonymousAccess) + { + Log.InfoFormat("Storing imgur upload for hash {0} and delete hash {1}", imgurInfo.Hash, imgurInfo.DeleteHash); + _config.ImgurUploadHistory.Add(imgurInfo.Hash, imgurInfo.DeleteHash); + _config.runtimeImgurHistory.Add(imgurInfo.Hash, imgurInfo); + UpdateHistoryMenuItem(); + } + } + ); + + if (imgurInfo != null) + { + // TODO: Optimize a second call for export + using (Image tmpImage = surfaceToUpload.GetImageForExport()) + { + imgurInfo.Image = ImageHelper.CreateThumbnail(tmpImage, 90, 90); + } + + IniConfig.Save(); + + if (_config.UsePageLink) + { + uploadUrl = imgurInfo.Page; + } + else + { + uploadUrl = imgurInfo.Original; + } + + if (!string.IsNullOrEmpty(uploadUrl) && _config.CopyLinkToClipboard) + { + try + { + ClipboardHelper.SetClipboardData(uploadUrl); + } + catch (Exception ex) + { + Log.Error("Can't write to clipboard: ", ex); + uploadUrl = null; + } + } + + return true; + } + } + catch (Exception e) + { + Log.Error("Error uploading.", e); + MessageBox.Show(Language.GetString("imgur", LangKey.upload_failure) + " " + e.Message); + } + + uploadUrl = null; + return false; + } + } +} \ No newline at end of file diff --git a/GreenshotImgurPlugin/ImgurPlugin.resx b/src/Greenshot.Plugin.Imgur/ImgurPlugin.resx similarity index 100% rename from GreenshotImgurPlugin/ImgurPlugin.resx rename to src/Greenshot.Plugin.Imgur/ImgurPlugin.resx diff --git a/src/Greenshot.Plugin.Imgur/ImgurUtils.cs b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs new file mode 100644 index 000000000..4ec67bd9b --- /dev/null +++ b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs @@ -0,0 +1,410 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Plugin.Imgur +{ + /// + /// A collection of Imgur helper methods + /// + public static class ImgurUtils + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurUtils)); + private const string SmallUrlPattern = "http://i.imgur.com/{0}s.jpg"; + private static readonly ImgurConfiguration Config = IniConfig.GetIniSection(); + + /// + /// Check if we need to load the history + /// + /// + public static bool IsHistoryLoadingNeeded() + { + Log.InfoFormat("Checking if imgur cache loading needed, configuration has {0} imgur hashes, loaded are {1} hashes.", Config.ImgurUploadHistory.Count, + Config.runtimeImgurHistory.Count); + return Config.runtimeImgurHistory.Count != Config.ImgurUploadHistory.Count; + } + + /// + /// Load the complete history of the imgur uploads, with the corresponding information + /// + public static void LoadHistory() + { + if (!IsHistoryLoadingNeeded()) + { + return; + } + + bool saveNeeded = false; + + // Load the ImUr history + foreach (string hash in Config.ImgurUploadHistory.Keys.ToList()) + { + if (Config.runtimeImgurHistory.ContainsKey(hash)) + { + // Already loaded + continue; + } + + try + { + var deleteHash = Config.ImgurUploadHistory[hash]; + ImgurInfo imgurInfo = RetrieveImgurInfo(hash, deleteHash); + if (imgurInfo != null) + { + RetrieveImgurThumbnail(imgurInfo); + Config.runtimeImgurHistory[hash] = imgurInfo; + } + else + { + Log.InfoFormat("Deleting unknown ImgUr {0} from config, delete hash was {1}.", hash, deleteHash); + Config.ImgurUploadHistory.Remove(hash); + Config.runtimeImgurHistory.Remove(hash); + saveNeeded = true; + } + } + catch (WebException wE) + { + bool redirected = false; + if (wE.Status == WebExceptionStatus.ProtocolError) + { + HttpWebResponse response = (HttpWebResponse) wE.Response; + + if (response.StatusCode == HttpStatusCode.Forbidden) + { + Log.Error("Imgur loading forbidden", wE); + break; + } + + // Image no longer available? + if (response.StatusCode == HttpStatusCode.Redirect) + { + Log.InfoFormat("ImgUr image for hash {0} is no longer available, removing it from the history", hash); + Config.ImgurUploadHistory.Remove(hash); + Config.runtimeImgurHistory.Remove(hash); + redirected = true; + } + } + + if (!redirected) + { + Log.Error("Problem loading ImgUr history for hash " + hash, wE); + } + } + catch (Exception e) + { + Log.Error("Problem loading ImgUr history for hash " + hash, e); + } + } + + if (saveNeeded) + { + // Save needed changes + IniConfig.Save(); + } + } + + /// + /// Use this to make sure Imgur knows from where the upload comes. + /// + /// + private static void SetClientId(HttpWebRequest webRequest) + { + webRequest.Headers.Add("Authorization", "Client-ID " + ImgurCredentials.CONSUMER_KEY); + } + + /// + /// Do the actual upload to Imgur + /// For more details on the available parameters, see: http://api.imgur.com/resources_anon + /// + /// ISurface to upload + /// OutputSettings for the image file format + /// Title + /// Filename + /// ImgurInfo with details + public static ImgurInfo UploadToImgur(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string title, string filename) + { + IDictionary otherParameters = new Dictionary(); + // add title + if (title != null && Config.AddTitle) + { + otherParameters["title"] = title; + } + + // add filename + if (filename != null && Config.AddFilename) + { + otherParameters["name"] = filename; + } + + string responseString = null; + if (Config.AnonymousAccess) + { + // add key, we only use the other parameters for the AnonymousAccess + //otherParameters.Add("key", IMGUR_ANONYMOUS_API_KEY); + HttpWebRequest webRequest = + NetworkHelper.CreateWebRequest(Config.ImgurApi3Url + "/upload.xml?" + NetworkHelper.GenerateQueryParameters(otherParameters), HTTPMethod.POST); + webRequest.ContentType = "image/" + outputSettings.Format; + webRequest.ServicePoint.Expect100Continue = false; + + SetClientId(webRequest); + try + { + using (var requestStream = webRequest.GetRequestStream()) + { + ImageOutput.SaveToStream(surfaceToUpload, requestStream, outputSettings); + } + + using WebResponse response = webRequest.GetResponse(); + LogRateLimitInfo(response); + var responseStream = response.GetResponseStream(); + if (responseStream != null) + { + using StreamReader reader = new StreamReader(responseStream, true); + responseString = reader.ReadToEnd(); + } + } + catch (Exception ex) + { + Log.Error("Upload to imgur gave an exception: ", ex); + throw; + } + } + else + { + var oauth2Settings = new OAuth2Settings + { + AuthUrlPattern = "https://api.imgur.com/oauth2/authorize?response_type=token&client_id={ClientId}&state={State}", + TokenUrl = "https://api.imgur.com/oauth2/token", + RedirectUrl = "https://getgreenshot.org/authorize/imgur", + CloudServiceName = "Imgur", + ClientId = ImgurCredentials.CONSUMER_KEY, + ClientSecret = ImgurCredentials.CONSUMER_SECRET, + AuthorizeMode = OAuth2AuthorizeMode.JsonReceiver, + RefreshToken = Config.RefreshToken, + AccessToken = Config.AccessToken, + AccessTokenExpires = Config.AccessTokenExpires + }; + + // Copy the settings from the config, which is kept in memory and on the disk + + try + { + var webRequest = OAuth2Helper.CreateOAuth2WebRequest(HTTPMethod.POST, Config.ImgurApi3Url + "/upload.xml", oauth2Settings); + otherParameters["image"] = new SurfaceContainer(surfaceToUpload, outputSettings, filename); + + NetworkHelper.WriteMultipartFormData(webRequest, otherParameters); + + responseString = NetworkHelper.GetResponseAsString(webRequest); + } + finally + { + // Copy the settings back to the config, so they are stored. + Config.RefreshToken = oauth2Settings.RefreshToken; + Config.AccessToken = oauth2Settings.AccessToken; + Config.AccessTokenExpires = oauth2Settings.AccessTokenExpires; + Config.IsDirty = true; + IniConfig.Save(); + } + } + + if (string.IsNullOrEmpty(responseString)) + { + return null; + } + + return ImgurInfo.ParseResponse(responseString); + } + + /// + /// Retrieve the thumbnail of an imgur image + /// + /// + public static void RetrieveImgurThumbnail(ImgurInfo imgurInfo) + { + if (imgurInfo.SmallSquare == null) + { + Log.Warn("Imgur URL was null, not retrieving thumbnail."); + return; + } + + Log.InfoFormat("Retrieving Imgur image for {0} with url {1}", imgurInfo.Hash, imgurInfo.SmallSquare); + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(string.Format(SmallUrlPattern, imgurInfo.Hash), HTTPMethod.GET); + webRequest.ServicePoint.Expect100Continue = false; + // Not for getting the thumbnail, in anonymous mode + //SetClientId(webRequest); + using WebResponse response = webRequest.GetResponse(); + LogRateLimitInfo(response); + Stream responseStream = response.GetResponseStream(); + if (responseStream != null) + { + imgurInfo.Image = ImageHelper.FromStream(responseStream); + } + } + + /// + /// Retrieve information on an imgur image + /// + /// + /// + /// ImgurInfo + public static ImgurInfo RetrieveImgurInfo(string hash, string deleteHash) + { + string url = Config.ImgurApi3Url + "/image/" + hash + ".xml"; + Log.InfoFormat("Retrieving Imgur info for {0} with url {1}", hash, url); + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.GET); + webRequest.ServicePoint.Expect100Continue = false; + SetClientId(webRequest); + string responseString = null; + try + { + using WebResponse response = webRequest.GetResponse(); + LogRateLimitInfo(response); + var responseStream = response.GetResponseStream(); + if (responseStream != null) + { + using StreamReader reader = new StreamReader(responseStream, true); + responseString = reader.ReadToEnd(); + } + } + catch (WebException wE) + { + if (wE.Status == WebExceptionStatus.ProtocolError) + { + if (((HttpWebResponse) wE.Response).StatusCode == HttpStatusCode.NotFound) + { + return null; + } + } + + throw; + } + + ImgurInfo imgurInfo = null; + if (responseString != null) + { + Log.Debug(responseString); + imgurInfo = ImgurInfo.ParseResponse(responseString); + imgurInfo.DeleteHash = deleteHash; + } + + return imgurInfo; + } + + /// + /// Delete an imgur image, this is done by specifying the delete hash + /// + /// + public static void DeleteImgurImage(ImgurInfo imgurInfo) + { + Log.InfoFormat("Deleting Imgur image for {0}", imgurInfo.DeleteHash); + + try + { + string url = Config.ImgurApi3Url + "/image/" + imgurInfo.DeleteHash + ".xml"; + HttpWebRequest webRequest = NetworkHelper.CreateWebRequest(url, HTTPMethod.DELETE); + webRequest.ServicePoint.Expect100Continue = false; + SetClientId(webRequest); + string responseString = null; + using (WebResponse response = webRequest.GetResponse()) + { + LogRateLimitInfo(response); + var responseStream = response.GetResponseStream(); + if (responseStream != null) + { + using StreamReader reader = new StreamReader(responseStream, true); + responseString = reader.ReadToEnd(); + } + } + + Log.InfoFormat("Delete result: {0}", responseString); + } + catch (WebException wE) + { + // Allow "Bad request" this means we already deleted it + if (wE.Status == WebExceptionStatus.ProtocolError) + { + if (((HttpWebResponse) wE.Response).StatusCode != HttpStatusCode.BadRequest) + { + throw; + } + } + } + + // Make sure we remove it from the history, if no error occurred + Config.runtimeImgurHistory.Remove(imgurInfo.Hash); + Config.ImgurUploadHistory.Remove(imgurInfo.Hash); + imgurInfo.Image = null; + } + + /// + /// Helper for logging + /// + /// + /// + private static void LogHeader(IDictionary nameValues, string key) + { + if (nameValues.ContainsKey(key)) + { + Log.InfoFormat("{0}={1}", key, nameValues[key]); + } + } + + /// + /// Log the current rate-limit information + /// + /// + private static void LogRateLimitInfo(WebResponse response) + { + IDictionary nameValues = new Dictionary(); + foreach (string key in response.Headers.AllKeys) + { + if (!nameValues.ContainsKey(key)) + { + nameValues.Add(key, response.Headers[key]); + } + } + + LogHeader(nameValues, "X-RateLimit-Limit"); + LogHeader(nameValues, "X-RateLimit-Remaining"); + LogHeader(nameValues, "X-RateLimit-UserLimit"); + LogHeader(nameValues, "X-RateLimit-UserRemaining"); + LogHeader(nameValues, "X-RateLimit-UserReset"); + LogHeader(nameValues, "X-RateLimit-ClientLimit"); + LogHeader(nameValues, "X-RateLimit-ClientRemaining"); + + // Update the credits in the config, this is shown in a form + if (nameValues.ContainsKey("X-RateLimit-Remaining") && int.TryParse(nameValues["X-RateLimit-Remaining"], out var credits)) + { + Config.Credits = credits; + } + } + } +} \ No newline at end of file diff --git a/GreenshotImgurPlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Imgur/LanguageKeys.cs similarity index 76% rename from GreenshotImgurPlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Imgur/LanguageKeys.cs index cfde3c940..7b8a0ee3e 100644 --- a/GreenshotImgurPlugin/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Imgur/LanguageKeys.cs @@ -19,15 +19,17 @@ * along with this program. If not, see . */ -namespace GreenshotImgurPlugin { - public enum LangKey { - upload_menu_item, - upload_failure, - communication_wait, - delete_question, - clear_question, - delete_title, - history, - configure - } -} +namespace Greenshot.Plugin.Imgur +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + delete_question, + clear_question, + delete_title, + history, + configure + } +} \ No newline at end of file diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-cs-CZ.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-cs-CZ.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-cs-CZ.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-de-DE.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-de-DE.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-de-DE.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-de-DE.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-en-US.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-en-US.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-en-US.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-en-US.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-fr-FR.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-fr-FR.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-fr-FR.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-fr-FR.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-id-ID.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-id-ID.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-id-ID.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-id-ID.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-it-IT.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-it-IT.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-it-IT.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-ja-JP.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ja-JP.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-ja-JP.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ja-JP.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-kab-DZ.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-kab-DZ.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-kab-DZ.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-ko-KR.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ko-KR.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-ko-KR.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ko-KR.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-lv-LV.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-lv-LV.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-lv-LV.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-lv-LV.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-nl-NL.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-nl-NL.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-nl-NL.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-nl-NL.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-pl-PL.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-pl-PL.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-pl-PL.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-pl-PL.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-pt-PT.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-pt-PT.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-pt-PT.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-pt-PT.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-ru-RU.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ru-RU.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-ru-RU.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-ru-RU.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-sk-SK.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sk-SK.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-sk-SK.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sk-SK.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-sr-RS.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sr-RS.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-sr-RS.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sr-RS.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-sv-SE.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sv-SE.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-sv-SE.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-sv-SE.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-uk-UA.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-uk-UA.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-uk-UA.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-uk-UA.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-CN.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-zh-CN.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-zh-CN.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-zh-CN.xml diff --git a/GreenshotImgurPlugin/Languages/language_imgurplugin-zh-TW.xml b/src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-zh-TW.xml similarity index 100% rename from GreenshotImgurPlugin/Languages/language_imgurplugin-zh-TW.xml rename to src/Greenshot.Plugin.Imgur/Languages/language_imgurplugin-zh-TW.xml diff --git a/GreenshotImgurPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs similarity index 97% rename from GreenshotImgurPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs index 6818a420b..31ecce89a 100644 --- a/GreenshotImgurPlugin/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs b/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs new file mode 100644 index 000000000..5445fafde --- /dev/null +++ b/src/Greenshot.Plugin.Jira/AsyncMemoryCache.cs @@ -0,0 +1,191 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.Caching; +using System.Threading; +using System.Threading.Tasks; +using Dapplo.Log; + +namespace Greenshot.Plugin.Jira +{ + /// + /// This abstract class builds a base for a simple async memory cache. + /// + /// Type for the key + /// Type for the stored value + public abstract class AsyncMemoryCache where TResult : class + { + private static readonly Task EmptyValueTask = Task.FromResult(null); + private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1); + private readonly MemoryCache _cache = new MemoryCache(Guid.NewGuid().ToString()); + private readonly LogSource _log = new LogSource(); + + /// + /// Set the timespan for items to expire. + /// + public TimeSpan? ExpireTimeSpan { get; set; } + + /// + /// Set the timespan for items to slide. + /// + public TimeSpan? SlidingTimeSpan { get; set; } + + /// + /// Specifies if the RemovedCallback needs to be called + /// If this is active, ActivateUpdateCallback should be false + /// + protected bool ActivateRemovedCallback { get; set; } = true; + + /// + /// Specifies if the UpdateCallback needs to be called. + /// If this is active, ActivateRemovedCallback should be false + /// + protected bool ActivateUpdateCallback { get; set; } = false; + + /// + /// Implement this method, it should create an instance of TResult via the supplied TKey. + /// + /// TKey + /// CancellationToken + /// TResult + protected abstract Task CreateAsync(TKey key, CancellationToken cancellationToken = default); + + /// + /// Creates a key under which the object is stored or retrieved, default is a toString on the object. + /// + /// TKey + /// string + protected virtual string CreateKey(TKey keyObject) + { + return keyObject.ToString(); + } + + /// + /// Get a task element from the cache, if this is not available call the create function. + /// + /// object for the key + /// CancellationToken + /// Task with TResult + public Task GetOrCreateAsync(TKey keyObject, CancellationToken cancellationToken = default) + { + var key = CreateKey(keyObject); + return _cache.Get(key) as Task ?? GetOrCreateInternalAsync(keyObject, null, cancellationToken); + } + + /// + /// This takes care of the real async part of the code. + /// + /// + /// CacheItemPolicy for when you want more control over the item + /// CancellationToken + /// TResult + private async Task GetOrCreateInternalAsync(TKey keyObject, CacheItemPolicy cacheItemPolicy = null, CancellationToken cancellationToken = default) + { + var key = CreateKey(keyObject); + var completionSource = new TaskCompletionSource(); + + if (cacheItemPolicy == null) + { + cacheItemPolicy = new CacheItemPolicy + { + AbsoluteExpiration = ExpireTimeSpan.HasValue ? DateTimeOffset.Now.Add(ExpireTimeSpan.Value) : ObjectCache.InfiniteAbsoluteExpiration, + SlidingExpiration = SlidingTimeSpan ?? ObjectCache.NoSlidingExpiration + }; + if (ActivateUpdateCallback) + { + cacheItemPolicy.UpdateCallback = UpdateCallback; + } + + if (ActivateRemovedCallback) + { + cacheItemPolicy.RemovedCallback = RemovedCallback; + } + } + + // Test if we got an existing object or our own + if (_cache.AddOrGetExisting(key, completionSource.Task, cacheItemPolicy) is Task result && !completionSource.Task.Equals(result)) + { + return await result.ConfigureAwait(false); + } + + await _semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false); + try + { + result = _cache.AddOrGetExisting(key, completionSource.Task, cacheItemPolicy) as Task; + if (result != null && !completionSource.Task.Equals(result)) + { + return await result.ConfigureAwait(false); + } + + // Now, start the background task, which will set the completionSource with the correct response + // ReSharper disable once MethodSupportsCancellation + // ReSharper disable once UnusedVariable + var ignoreBackgroundTask = Task.Run(async () => + { + try + { + var backgroundResult = await CreateAsync(keyObject, cancellationToken).ConfigureAwait(false); + completionSource.TrySetResult(backgroundResult); + } + catch (TaskCanceledException) + { + completionSource.TrySetCanceled(); + } + catch (Exception ex) + { + completionSource.TrySetException(ex); + } + }); + } + finally + { + _semaphoreSlim.Release(); + } + + return await completionSource.Task.ConfigureAwait(false); + } + + /// + /// Override to know when an item is removed, make sure to configure ActivateUpdateCallback / ActivateRemovedCallback + /// + /// CacheEntryRemovedArguments + protected void RemovedCallback(CacheEntryRemovedArguments cacheEntryRemovedArguments) + { + _log.Verbose().WriteLine("Item {0} removed due to {1}.", cacheEntryRemovedArguments.CacheItem.Key, cacheEntryRemovedArguments.RemovedReason); + if (cacheEntryRemovedArguments.CacheItem.Value is IDisposable disposable) + { + _log.Debug().WriteLine("Disposed cached item."); + disposable.Dispose(); + } + } + + /// + /// Override to modify the cache behaviour when an item is about to be removed, make sure to configure + /// ActivateUpdateCallback / ActivateRemovedCallback + /// + /// CacheEntryUpdateArguments + protected void UpdateCallback(CacheEntryUpdateArguments cacheEntryUpdateArguments) + { + _log.Verbose().WriteLine("Update request for {0} due to {1}.", cacheEntryUpdateArguments.Key, cacheEntryUpdateArguments.RemovedReason); + } + } +} \ No newline at end of file diff --git a/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs b/src/Greenshot.Plugin.Jira/Forms/JiraForm.Designer.cs similarity index 97% rename from GreenshotJiraPlugin/Forms/JiraForm.Designer.cs rename to src/Greenshot.Plugin.Jira/Forms/JiraForm.Designer.cs index bcd10427a..d63fea453 100644 --- a/GreenshotJiraPlugin/Forms/JiraForm.Designer.cs +++ b/src/Greenshot.Plugin.Jira/Forms/JiraForm.Designer.cs @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotJiraPlugin.Forms { +namespace Greenshot.Plugin.Jira.Forms { partial class JiraForm { /// /// Required designer variable. diff --git a/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs new file mode 100644 index 000000000..44b97cc43 --- /dev/null +++ b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs @@ -0,0 +1,271 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; +using Dapplo.Jira.Entities; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.Jira.Forms +{ + public partial class JiraForm : Form + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraForm)); + private readonly JiraConnector _jiraConnector; + private Issue _selectedIssue; + private readonly GreenshotColumnSorter _columnSorter; + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + + public JiraForm(JiraConnector jiraConnector) + { + InitializeComponent(); + Icon = GreenshotResources.GetGreenshotIcon(); + AcceptButton = uploadButton; + CancelButton = cancelButton; + + InitializeComponentText(); + + _columnSorter = new GreenshotColumnSorter(); + jiraListView.ListViewItemSorter = _columnSorter; + + _jiraConnector = jiraConnector; + + ChangeModus(false); + + uploadButton.Enabled = false; + Load += OnLoad; + } + + private async void OnLoad(object sender, EventArgs eventArgs) + { + try + { + if (!_jiraConnector.IsLoggedIn) + { + await _jiraConnector.LoginAsync(); + } + } + catch (Exception e) + { + MessageBox.Show(Language.GetFormattedString("jira", LangKey.login_error, e.Message)); + } + + if (_jiraConnector.IsLoggedIn) + { + var filters = await _jiraConnector.GetFavoriteFiltersAsync(); + if (filters.Count > 0) + { + foreach (var filter in filters) + { + jiraFilterBox.Items.Add(filter); + } + + jiraFilterBox.SelectedIndex = 0; + } + + ChangeModus(true); + if (_jiraConnector.Monitor.RecentJiras.Any()) + { + _selectedIssue = _jiraConnector.Monitor.RecentJiras.First().JiraIssue; + jiraKey.Text = _selectedIssue.Key; + uploadButton.Enabled = true; + } + } + } + + private void InitializeComponentText() + { + label_jirafilter.Text = Language.GetString("jira", LangKey.label_jirafilter); + label_comment.Text = Language.GetString("jira", LangKey.label_comment); + label_filename.Text = Language.GetString("jira", LangKey.label_filename); + } + + private void ChangeModus(bool enabled) + { + jiraFilterBox.Enabled = enabled; + jiraListView.Enabled = enabled; + jiraFilenameBox.Enabled = enabled; + jiraCommentBox.Enabled = enabled; + } + + public void SetFilename(string filename) + { + jiraFilenameBox.Text = filename; + } + + public Issue GetJiraIssue() + { + return _selectedIssue; + } + + public async Task UploadAsync(IBinaryContainer attachment) + { + attachment.Filename = jiraFilenameBox.Text; + await _jiraConnector.AttachAsync(_selectedIssue.Key, attachment); + + if (!string.IsNullOrEmpty(jiraCommentBox.Text)) + { + await _jiraConnector.AddCommentAsync(_selectedIssue.Key, jiraCommentBox.Text); + } + } + + private async void JiraFilterBox_SelectedIndexChanged(object sender, EventArgs e) + { + if (_jiraConnector.IsLoggedIn) + { + uploadButton.Enabled = false; + var filter = (Filter) jiraFilterBox.SelectedItem; + if (filter == null) + { + return; + } + + IList issues = null; + try + { + issues = await _jiraConnector.SearchAsync(filter); + } + catch (Exception ex) + { + Log.Error(ex); + MessageBox.Show(this, ex.Message, "Error in filter", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + jiraListView.Items.Clear(); + if (issues?.Count > 0) + { + jiraListView.Columns.Clear(); + LangKey[] columns = + { + LangKey.column_issueType, LangKey.column_id, LangKey.column_created, LangKey.column_assignee, LangKey.column_reporter, LangKey.column_summary + }; + foreach (LangKey column in columns) + { + if (!Language.TryGetString("jira", column, out var translation)) + { + translation = string.Empty; + } + + jiraListView.Columns.Add(translation); + } + + var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, DpiHelper.GetDpi(Handle)); + var imageList = new ImageList + { + ImageSize = scaledIconSize + }; + jiraListView.SmallImageList = imageList; + jiraListView.LargeImageList = imageList; + + foreach (var issue in issues) + { + var item = new ListViewItem + { + Tag = issue + }; + try + { + var issueIcon = await _jiraConnector.GetIssueTypeBitmapAsync(issue); + imageList.Images.Add(issueIcon); + item.ImageIndex = imageList.Images.Count - 1; + } + catch (Exception ex) + { + Log.Warn("Problem loading issue type, ignoring", ex); + } + + item.SubItems.Add(issue.Key); + item.SubItems.Add(issue.Fields.Created.HasValue + ? issue.Fields.Created.Value.ToString("d", DateTimeFormatInfo.InvariantInfo) + : string.Empty); + item.SubItems.Add(issue.Fields.Assignee?.DisplayName); + item.SubItems.Add(issue.Fields.Reporter?.DisplayName); + item.SubItems.Add(issue.Fields.Summary); + jiraListView.Items.Add(item); + for (int i = 0; i < columns.Length; i++) + { + jiraListView.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent); + } + + jiraListView.Invalidate(); + jiraListView.Update(); + } + + jiraListView.Refresh(); + } + } + } + + private void JiraListView_SelectedIndexChanged(object sender, EventArgs e) + { + if (jiraListView.SelectedItems.Count > 0) + { + _selectedIssue = (Issue) jiraListView.SelectedItems[0].Tag; + jiraKey.Text = _selectedIssue.Key; + uploadButton.Enabled = true; + } + else + { + uploadButton.Enabled = false; + } + } + + private void JiraListView_ColumnClick(object sender, ColumnClickEventArgs e) + { + // Determine if clicked column is already the column that is being sorted. + if (e.Column == _columnSorter.SortColumn) + { + // Reverse the current sort direction for this column. + _columnSorter.Order = _columnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; + } + else + { + // Set the column number that is to be sorted; default to ascending. + _columnSorter.SortColumn = e.Column; + _columnSorter.Order = SortOrder.Ascending; + } + + // Perform the sort with these new sort options. + jiraListView.Sort(); + } + + private async void JiraKeyTextChanged(object sender, EventArgs e) + { + string jiranumber = jiraKey.Text; + uploadButton.Enabled = false; + int dashIndex = jiranumber.IndexOf('-'); + if (dashIndex > 0 && jiranumber.Length > dashIndex + 1) + { + _selectedIssue = await _jiraConnector.GetIssueAsync(jiraKey.Text); + if (_selectedIssue != null) + { + uploadButton.Enabled = true; + } + } + } + } +} \ No newline at end of file diff --git a/GreenshotJiraPlugin/Forms/JiraFormBase.cs b/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs similarity index 87% rename from GreenshotJiraPlugin/Forms/JiraFormBase.cs rename to src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs index efc4d0201..072290ac7 100644 --- a/GreenshotJiraPlugin/Forms/JiraFormBase.cs +++ b/src/Greenshot.Plugin.Jira/Forms/JiraFormBase.cs @@ -19,9 +19,11 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace GreenshotJiraPlugin.Forms { - public class JiraFormBase : GreenshotForm { - } -} +namespace Greenshot.Plugin.Jira.Forms +{ + public class JiraFormBase : GreenshotForm + { + } +} \ No newline at end of file diff --git a/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs similarity index 84% rename from GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs index 0b0195cf4..39af09f68 100644 --- a/GreenshotJiraPlugin/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs @@ -18,7 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotJiraPlugin.Forms { + +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.Jira.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. @@ -46,12 +49,12 @@ namespace GreenshotJiraPlugin.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.label_url = new GreenshotPlugin.Controls.GreenshotLabel(); - this.textBoxUrl = new GreenshotPlugin.Controls.GreenshotTextBox(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.label_url = new GreenshotLabel(); + this.textBoxUrl = new GreenshotTextBox(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); this.SuspendLayout(); // // buttonOK @@ -136,11 +139,11 @@ namespace GreenshotJiraPlugin.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotTextBox textBoxUrl; - private GreenshotPlugin.Controls.GreenshotLabel label_url; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotTextBox textBoxUrl; + private GreenshotLabel label_url; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; } } diff --git a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs new file mode 100644 index 000000000..9009b70e1 --- /dev/null +++ b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.cs @@ -0,0 +1,39 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Plugin.Jira.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : JiraFormBase + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = buttonOK; + CancelButton = buttonCancel; + } + } +} \ No newline at end of file diff --git a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj similarity index 61% rename from GreenshotJiraPlugin/GreenshotJiraPlugin.csproj rename to src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj index d37465111..5d8fde23f 100644 --- a/GreenshotJiraPlugin/GreenshotJiraPlugin.csproj +++ b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj @@ -1,17 +1,11 @@  - - - GreenshotJiraPlugin - GreenshotJiraPlugin - - PreserveNewest - + diff --git a/GreenshotJiraPlugin/IssueTypeBitmapCache.cs b/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs similarity index 53% rename from GreenshotJiraPlugin/IssueTypeBitmapCache.cs rename to src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs index c37cee314..26d63e7c0 100644 --- a/GreenshotJiraPlugin/IssueTypeBitmapCache.cs +++ b/src/Greenshot.Plugin.Jira/IssueTypeBitmapCache.cs @@ -26,30 +26,30 @@ using System.Threading.Tasks; using Dapplo.Jira; using Dapplo.Jira.Entities; -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { - /// - /// This is the bach for the IssueType bitmaps - /// - public class IssueTypeBitmapCache : AsyncMemoryCache - { - private readonly IJiraClient _jiraClient; + /// + /// This is the bach for the IssueType bitmaps + /// + public class IssueTypeBitmapCache : AsyncMemoryCache + { + private readonly IJiraClient _jiraClient; - public IssueTypeBitmapCache(IJiraClient jiraClient) - { - _jiraClient = jiraClient; - // Set the expire timeout to an hour - ExpireTimeSpan = TimeSpan.FromHours(4); - } + public IssueTypeBitmapCache(IJiraClient jiraClient) + { + _jiraClient = jiraClient; + // Set the expire timeout to an hour + ExpireTimeSpan = TimeSpan.FromHours(4); + } - protected override string CreateKey(IssueType keyObject) - { - return keyObject.Name; - } + protected override string CreateKey(IssueType keyObject) + { + return keyObject.Name; + } - protected override async Task CreateAsync(IssueType issueType, CancellationToken cancellationToken = new CancellationToken()) - { - return await _jiraClient.Server.GetUriContentAsync(issueType.IconUri, cancellationToken).ConfigureAwait(false); - } - } -} + protected override async Task CreateAsync(IssueType issueType, CancellationToken cancellationToken = new CancellationToken()) + { + return await _jiraClient.Server.GetUriContentAsync(issueType.IconUri, cancellationToken).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraConfiguration.cs b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs new file mode 100644 index 000000000..64901f3d7 --- /dev/null +++ b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs @@ -0,0 +1,48 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.Jira +{ + /// + /// Description of JiraConfiguration. + /// + [IniSection("Jira", Description = "Greenshot Jira Plugin configuration")] + public class JiraConfiguration : IniSection + { + public const string DefaultPrefix = "http://"; + private const string DefaultUrl = DefaultPrefix + "jira"; + + [IniProperty("Url", Description = "Base url to Jira system, without anything else", DefaultValue = DefaultUrl)] + public string Url { get; set; } + + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] + public bool UploadReduceColors { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraConnector.cs b/src/Greenshot.Plugin.Jira/JiraConnector.cs new file mode 100644 index 000000000..9f9b88835 --- /dev/null +++ b/src/Greenshot.Plugin.Jira/JiraConnector.cs @@ -0,0 +1,317 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using Dapplo.HttpExtensions; +using Dapplo.HttpExtensions.Extensions; +using Dapplo.Jira; +using Dapplo.Jira.Entities; +using Dapplo.Jira.SvgWinForms.Converters; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; + +namespace Greenshot.Plugin.Jira +{ + /// + /// This encapsulates the JiraClient to make it possible to change as less old Greenshot code as needed + /// + public sealed class JiraConnector : IDisposable + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraConnector)); + private static readonly JiraConfiguration JiraConfig = IniConfig.GetIniSection(); + + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + + // Used to remove the wsdl information from the old SOAP Uri + public const string DefaultPostfix = "/rpc/soap/jirasoapservice-v2?wsdl"; + private IJiraClient _jiraClient; + private IssueTypeBitmapCache _issueTypeBitmapCache; + + /// + /// Initialize some basic stuff, in the case the SVG to bitmap converter + /// + static JiraConnector() + { + CoreConfig.PropertyChanged += (sender, args) => + { + if (args.PropertyName == nameof(CoreConfig.IconSize)) + { + var jiraConnector = SimpleServiceProvider.Current.GetInstance(); + jiraConnector._jiraClient?.Behaviour.SetConfig(new SvgConfiguration + { + Width = CoreConfig.ScaledIconSize.Width, + Height = CoreConfig.ScaledIconSize.Height + }); + } + }; + } + + /// + /// Dispose, logout the users + /// + public void Dispose() + { + if (_jiraClient != null) + { + Logout(); + } + + FavIcon?.Dispose(); + } + + /// + /// Constructor + /// + public JiraConnector() + { + JiraConfig.Url = JiraConfig.Url.Replace(DefaultPostfix, string.Empty); + } + + /// + /// Access the jira monitor + /// + public JiraMonitor Monitor { get; private set; } + + public Bitmap FavIcon { get; private set; } + + /// + /// Internal login which catches the exceptions + /// + /// true if login was done successfully + private async Task DoLoginAsync(string user, string password, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(password)) + { + return false; + } + + _jiraClient = JiraClient.Create(new Uri(JiraConfig.Url)); + _jiraClient.Behaviour.SetConfig(new SvgConfiguration + { + Width = CoreConfig.ScaledIconSize.Width, + Height = CoreConfig.ScaledIconSize.Height + }); + _jiraClient.SetBasicAuthentication(user, password); + + _issueTypeBitmapCache = new IssueTypeBitmapCache(_jiraClient); + try + { + Monitor = new JiraMonitor(); + await Monitor.AddJiraInstanceAsync(_jiraClient, cancellationToken); + + var favIconUri = _jiraClient.JiraBaseUri.AppendSegments("favicon.ico"); + try + { + FavIcon = await _jiraClient.Server.GetUriContentAsync(favIconUri, cancellationToken); + } + catch (Exception ex) + { + Log.WarnFormat("Couldn't load favicon from {0}", favIconUri); + Log.Warn("Exception details: ", ex); + } + } + catch (Exception ex2) + { + Log.WarnFormat("Couldn't connect to JIRA {0}", JiraConfig.Url); + Log.Warn("Exception details: ", ex2); + return false; + } + + return true; + } + + /// + /// Use the credentials dialog, this will show if there are not correct credentials. + /// If there are credentials, call the real login. + /// + /// Task + public async Task LoginAsync(CancellationToken cancellationToken = default) + { + Logout(); + try + { + // Get the system name, so the user knows where to login to + var credentialsDialog = new CredentialsDialog(JiraConfig.Url) + { + Name = null + }; + while (credentialsDialog.Show(credentialsDialog.Name) == DialogResult.OK) + { + if (await DoLoginAsync(credentialsDialog.Name, credentialsDialog.Password, cancellationToken)) + { + if (credentialsDialog.SaveChecked) + { + credentialsDialog.Confirm(true); + } + + IsLoggedIn = true; + return; + } + + // Login failed, confirm this + try + { + credentialsDialog.Confirm(false); + } + catch (ApplicationException e) + { + // exception handling ... + Log.Error("Problem using the credentials dialog", e); + } + + // For every windows version after XP show an incorrect password baloon + credentialsDialog.IncorrectPassword = true; + // Make sure the dialog is display, the password was false! + credentialsDialog.AlwaysDisplay = true; + } + } + catch (ApplicationException e) + { + // exception handling ... + Log.Error("Problem using the credentials dialog", e); + } + } + + /// + /// End the session, if there was one + /// + public void Logout() + { + if (_jiraClient == null || !IsLoggedIn) return; + Monitor.Dispose(); + IsLoggedIn = false; + } + + /// + /// check the login credentials, to prevent timeouts of the session, or makes a login + /// Do not use ConfigureAwait to call this, as it will move await from the UI thread. + /// + /// + private async Task CheckCredentialsAsync(CancellationToken cancellationToken = default) + { + if (!IsLoggedIn) + { + await LoginAsync(cancellationToken); + } + } + + /// + /// Get the favorite filters + /// + /// List with filters + public async Task> GetFavoriteFiltersAsync(CancellationToken cancellationToken = default) + { + await CheckCredentialsAsync(cancellationToken); + return await _jiraClient.Filter.GetFavoritesAsync(cancellationToken).ConfigureAwait(false); + } + + /// + /// Get the issue for a key + /// + /// Jira issue key + /// CancellationToken + /// Issue + public async Task GetIssueAsync(string issueKey, CancellationToken cancellationToken = default) + { + await CheckCredentialsAsync(cancellationToken); + try + { + return await _jiraClient.Issue.GetAsync(issueKey, cancellationToken: cancellationToken).ConfigureAwait(false); + } + catch + { + return null; + } + } + + /// + /// Attach the content to the jira + /// + /// + /// IBinaryContainer + /// + /// + public async Task AttachAsync(string issueKey, IBinaryContainer content, CancellationToken cancellationToken = default) + { + await CheckCredentialsAsync(cancellationToken); + using var memoryStream = new MemoryStream(); + content.WriteToStream(memoryStream); + memoryStream.Seek(0, SeekOrigin.Begin); + await _jiraClient.Attachment.AttachAsync(issueKey, memoryStream, content.Filename, content.ContentType, cancellationToken).ConfigureAwait(false); + } + + /// + /// Add a comment to the supplied issue + /// + /// Jira issue key + /// text + /// the visibility role + /// CancellationToken + public async Task AddCommentAsync(string issueKey, string body, Visibility visibility = null, CancellationToken cancellationToken = default) + { + await CheckCredentialsAsync(cancellationToken); + await _jiraClient.Issue.AddCommentAsync(issueKey, body, visibility, cancellationToken).ConfigureAwait(false); + } + + /// + /// Get the search results for the specified filter + /// + /// Filter + /// + /// + public async Task> SearchAsync(Filter filter, CancellationToken cancellationToken = default) + { + await CheckCredentialsAsync(cancellationToken); + var searchResult = await _jiraClient.Issue.SearchAsync(filter.Jql, null, new[] + { + "summary", "reporter", "assignee", "created", "issuetype" + }, null, cancellationToken).ConfigureAwait(false); + return searchResult.Issues; + } + + /// + /// Get the bitmap representing the issue type of an issue, from cache. + /// + /// Issue + /// CancellationToken + /// Bitmap + public async Task GetIssueTypeBitmapAsync(Issue issue, CancellationToken cancellationToken = default) + { + return await _issueTypeBitmapCache.GetOrCreateAsync(issue.Fields.IssueType, cancellationToken).ConfigureAwait(false); + } + + /// + /// Get the base uri + /// + public Uri JiraBaseUri => _jiraClient.JiraBaseUri; + + /// + /// Is the user "logged in? + /// + public bool IsLoggedIn { get; private set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraDestination.cs b/src/Greenshot.Plugin.Jira/JiraDestination.cs new file mode 100644 index 000000000..8b283642e --- /dev/null +++ b/src/Greenshot.Plugin.Jira/JiraDestination.cs @@ -0,0 +1,181 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Dapplo.HttpExtensions; +using Dapplo.Jira.Entities; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Jira.Forms; + +namespace Greenshot.Plugin.Jira +{ + /// + /// Description of JiraDestination. + /// + public class JiraDestination : AbstractDestination + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(JiraDestination)); + private static readonly JiraConfiguration Config = IniConfig.GetIniSection(); + private readonly Issue _jiraIssue; + + public JiraDestination(Issue jiraIssue = null) + { + _jiraIssue = jiraIssue; + } + + public override string Designation => "Jira"; + + public override string Description + { + get + { + if (_jiraIssue?.Fields?.Summary == null) + { + return Language.GetString("jira", LangKey.upload_menu_item); + } + + // Format the title of this destination + return _jiraIssue.Key + ": " + _jiraIssue.Fields.Summary.Substring(0, Math.Min(20, _jiraIssue.Fields.Summary.Length)); + } + } + + public override bool IsActive => base.IsActive && !string.IsNullOrEmpty(Config.Url); + + public override bool IsDynamic => true; + + public override Image DisplayIcon + { + get + { + Image displayIcon = null; + var jiraConnector = SimpleServiceProvider.Current.GetInstance(); + if (jiraConnector != null) + { + if (_jiraIssue != null) + { + // Try to get the issue type as icon + try + { + displayIcon = jiraConnector.GetIssueTypeBitmapAsync(_jiraIssue).Result; + } + catch (Exception ex) + { + Log.Warn($"Problem loading issue type for {_jiraIssue.Key}, ignoring", ex); + } + } + + if (displayIcon == null) + { + displayIcon = jiraConnector.FavIcon; + } + } + + if (displayIcon == null) + { + var resources = new ComponentResourceManager(typeof(JiraPlugin)); + displayIcon = (Image) resources.GetObject("Jira"); + } + + return displayIcon; + } + } + + public override IEnumerable DynamicDestinations() + { + var jiraConnector = SimpleServiceProvider.Current.GetInstance(); + if (jiraConnector == null || !jiraConnector.IsLoggedIn) + { + yield break; + } + + foreach (var jiraDetails in jiraConnector.Monitor.RecentJiras) + { + yield return new JiraDestination(jiraDetails.JiraIssue); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surfaceToUpload, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + string filename = Path.GetFileName(FilenameHelper.GetFilename(Config.UploadFormat, captureDetails)); + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(Config.UploadFormat, Config.UploadJpegQuality, Config.UploadReduceColors); + var jiraConnector = SimpleServiceProvider.Current.GetInstance(); + if (_jiraIssue != null) + { + try + { + // Run upload in the background + new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait), + async () => + { + var surfaceContainer = new SurfaceContainer(surfaceToUpload, outputSettings, filename); + await jiraConnector.AttachAsync(_jiraIssue.Key, surfaceContainer); + surfaceToUpload.UploadUrl = jiraConnector.JiraBaseUri.AppendSegments("browse", _jiraIssue.Key).AbsoluteUri; + } + ); + Log.DebugFormat("Uploaded to Jira {0}", _jiraIssue.Key); + exportInformation.ExportMade = true; + exportInformation.Uri = surfaceToUpload.UploadUrl; + } + catch (Exception e) + { + MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message); + } + } + else + { + var jiraForm = new JiraForm(jiraConnector); + jiraForm.SetFilename(filename); + var dialogResult = jiraForm.ShowDialog(); + if (dialogResult == DialogResult.OK) + { + try + { + surfaceToUpload.UploadUrl = jiraConnector.JiraBaseUri.AppendSegments("browse", jiraForm.GetJiraIssue().Key).AbsoluteUri; + // Run upload in the background + new PleaseWaitForm().ShowAndWait(Description, Language.GetString("jira", LangKey.communication_wait), + async () => { await jiraForm.UploadAsync(new SurfaceContainer(surfaceToUpload, outputSettings, filename)); } + ); + Log.DebugFormat("Uploaded to Jira {0}", jiraForm.GetJiraIssue().Key); + exportInformation.ExportMade = true; + exportInformation.Uri = surfaceToUpload.UploadUrl; + } + catch (Exception e) + { + MessageBox.Show(Language.GetString("jira", LangKey.upload_failure) + " " + e.Message); + } + } + } + + ProcessExport(exportInformation, surfaceToUpload); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/GreenshotJiraPlugin/JiraDetails.cs b/src/Greenshot.Plugin.Jira/JiraDetails.cs similarity index 58% rename from GreenshotJiraPlugin/JiraDetails.cs rename to src/Greenshot.Plugin.Jira/JiraDetails.cs index 67bbc0f61..d3ebf0255 100644 --- a/GreenshotJiraPlugin/JiraDetails.cs +++ b/src/Greenshot.Plugin.Jira/JiraDetails.cs @@ -22,50 +22,30 @@ using System; using Dapplo.Jira.Entities; -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { - public class JiraDetails : IComparable - { - public JiraDetails() - { - FirstSeenAt = SeenAt = DateTimeOffset.Now; - } + public class JiraDetails : IComparable + { + public JiraDetails() + { + FirstSeenAt = SeenAt = DateTimeOffset.Now; + } - public string ProjectKey - { - get; - set; - } + public string ProjectKey { get; set; } - public string Id - { - get; - set; - } + public string Id { get; set; } - public string JiraKey => ProjectKey + "-" + Id; + public string JiraKey => ProjectKey + "-" + Id; - public Issue JiraIssue - { - get; - set; - } + public Issue JiraIssue { get; set; } - public DateTimeOffset FirstSeenAt - { - get; - private set; - } + public DateTimeOffset FirstSeenAt { get; private set; } - public DateTimeOffset SeenAt - { - get; - set; - } + public DateTimeOffset SeenAt { get; set; } - public int CompareTo(JiraDetails other) - { - return SeenAt.CompareTo(other.SeenAt); - } - } + public int CompareTo(JiraDetails other) + { + return SeenAt.CompareTo(other.SeenAt); + } + } } \ No newline at end of file diff --git a/GreenshotJiraPlugin/JiraEventArgs.cs b/src/Greenshot.Plugin.Jira/JiraEventArgs.cs similarity index 80% rename from GreenshotJiraPlugin/JiraEventArgs.cs rename to src/Greenshot.Plugin.Jira/JiraEventArgs.cs index eb60e5fcf..203194fca 100644 --- a/GreenshotJiraPlugin/JiraEventArgs.cs +++ b/src/Greenshot.Plugin.Jira/JiraEventArgs.cs @@ -21,20 +21,12 @@ using System; -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { - public class JiraEventArgs : EventArgs - { - public JiraEventTypes EventType - { - get; - set; - } + public class JiraEventArgs : EventArgs + { + public JiraEventTypes EventType { get; set; } - public JiraDetails Details - { - get; - set; - } - } -} + public JiraDetails Details { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotJiraPlugin/JiraEventTypes.cs b/src/Greenshot.Plugin.Jira/JiraEventTypes.cs similarity index 85% rename from GreenshotJiraPlugin/JiraEventTypes.cs rename to src/Greenshot.Plugin.Jira/JiraEventTypes.cs index 37e62cab1..3e3c80093 100644 --- a/GreenshotJiraPlugin/JiraEventTypes.cs +++ b/src/Greenshot.Plugin.Jira/JiraEventTypes.cs @@ -19,11 +19,11 @@ * along with this program. If not, see . */ -namespace GreenshotJiraPlugin +namespace Greenshot.Plugin.Jira { - public enum JiraEventTypes - { - OrderChanged, - DetectedNewJiraIssue - } + public enum JiraEventTypes + { + OrderChanged, + DetectedNewJiraIssue + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraMonitor.cs b/src/Greenshot.Plugin.Jira/JiraMonitor.cs new file mode 100644 index 000000000..3ccc84a45 --- /dev/null +++ b/src/Greenshot.Plugin.Jira/JiraMonitor.cs @@ -0,0 +1,233 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub: https://github.com/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using Dapplo.Jira; +using Dapplo.Log; +using Greenshot.Base.Hooking; + +namespace Greenshot.Plugin.Jira +{ + /// + /// This class will monitor all _jira activity by registering for title changes + /// It keeps a list of the last "accessed" jiras, and makes it easy to upload to one. + /// Make sure this is instanciated on the UI thread! + /// + public class JiraMonitor : IDisposable + { + private static readonly LogSource Log = new LogSource(); + private readonly Regex _jiraKeyPattern = new Regex(@"[A-Z][A-Z0-9]+\-[0-9]+"); + private readonly WindowsTitleMonitor _monitor; + private readonly IList _jiraInstances = new List(); + private readonly IDictionary _projectJiraClientMap = new Dictionary(); + + private readonly int _maxEntries; + + // TODO: Add issues from issueHistory (JQL -> Where.IssueKey.InIssueHistory()) + private IDictionary _recentJiras = new Dictionary(); + + /// + /// Register to this event to get events when new jira issues are detected + /// + public event EventHandler JiraEvent; + + public JiraMonitor(int maxEntries = 40) + { + _maxEntries = maxEntries; + _monitor = new WindowsTitleMonitor(); + _monitor.TitleChangeEvent += MonitorTitleChangeEvent; + } + + /// + /// Dispose + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Dispose all managed resources + /// + /// when true is passed all managed resources are disposed. + protected void Dispose(bool disposing) + { + if (!disposing) + { + return; + } + + // free managed resources + _monitor.TitleChangeEvent -= MonitorTitleChangeEvent; + _monitor.Dispose(); + // free native resources if there are any. + } + + /// + /// Retrieve the API belonging to a JiraDetails + /// + /// + /// IJiraClient + public IJiraClient GetJiraClientForKey(JiraDetails jiraDetails) + { + return _projectJiraClientMap[jiraDetails.ProjectKey]; + } + + /// + /// Get the "list" of recently seen Jiras + /// + public IEnumerable RecentJiras => + (from jiraDetails in _recentJiras.Values + orderby jiraDetails.SeenAt descending + select jiraDetails); + + /// + /// Check if this monitor has active instances + /// + public bool HasJiraInstances => _jiraInstances.Count > 0; + + /// + /// Add an instance of a JIRA system + /// + /// IJiraClient + /// CancellationToken + public async Task AddJiraInstanceAsync(IJiraClient jiraInstance, CancellationToken token = default) + { + _jiraInstances.Add(jiraInstance); + var projects = await jiraInstance.Project.GetAllAsync(cancellationToken: token).ConfigureAwait(false); + if (projects != null) + { + foreach (var project in projects) + { + if (!_projectJiraClientMap.ContainsKey(project.Key)) + { + _projectJiraClientMap.Add(project.Key, jiraInstance); + } + } + } + } + + /// + /// This method will update details, like the title, and send an event to registed listeners of the JiraEvent + /// + /// Contains the jira key to retrieve the title (XYZ-1234) + /// Task + private async Task DetectedNewJiraIssueAsync(JiraDetails jiraDetails) + { + try + { + if (_projectJiraClientMap.TryGetValue(jiraDetails.ProjectKey, out var jiraClient)) + { + var issue = await jiraClient.Issue.GetAsync(jiraDetails.JiraKey).ConfigureAwait(false); + jiraDetails.JiraIssue = issue; + } + + // Send event + JiraEvent?.Invoke(this, new JiraEventArgs + { + Details = jiraDetails, + EventType = JiraEventTypes.DetectedNewJiraIssue + }); + } + catch (Exception ex) + { + Log.Warn().WriteLine("Couldn't retrieve JIRA title: {0}", ex.Message); + } + } + + /// + /// Handle title changes, check for JIRA + /// + /// + private void MonitorTitleChangeEvent(TitleChangeEventArgs eventArgs) + { + string windowTitle = eventArgs.Title; + if (string.IsNullOrEmpty(windowTitle)) + { + return; + } + + var jiraKeyMatch = _jiraKeyPattern.Match(windowTitle); + if (!jiraKeyMatch.Success) + { + return; + } + + // Found a possible JIRA title + var jiraKey = jiraKeyMatch.Value; + var jiraKeyParts = jiraKey.Split('-'); + var projectKey = jiraKeyParts[0]; + var jiraId = jiraKeyParts[1]; + + // Check if we have a JIRA instance with a project for this key + if (_projectJiraClientMap.TryGetValue(projectKey, out var jiraClient)) + { + // We have found a project for this _jira key, so it must be a valid & known JIRA + if (_recentJiras.TryGetValue(jiraKey, out var currentJiraDetails)) + { + // update + currentJiraDetails.SeenAt = DateTimeOffset.Now; + + // Notify the order change + JiraEvent?.Invoke(this, new JiraEventArgs + { + Details = currentJiraDetails, + EventType = JiraEventTypes.OrderChanged + }); + // Nothing else to do + + return; + } + + // We detected an unknown JIRA, so add it to our list + currentJiraDetails = new JiraDetails + { + Id = jiraId, + ProjectKey = projectKey + }; + _recentJiras.Add(currentJiraDetails.JiraKey, currentJiraDetails); + + // Make sure we don't collect _jira's until the memory is full + if (_recentJiras.Count > _maxEntries) + { + // Add it to the list of recent Jiras + _recentJiras = (from jiraDetails in _recentJiras.Values.ToList() + orderby jiraDetails.SeenAt descending + select jiraDetails).Take(_maxEntries).ToDictionary(jd => jd.JiraKey, jd => jd); + } + + // Now we can get the title from JIRA itself + // ReSharper disable once UnusedVariable + var updateTitleTask = DetectedNewJiraIssueAsync(currentJiraDetails); + } + else + { + Log.Info().WriteLine("Couldn't match possible JIRA key {0} to projects in a configured JIRA instance, ignoring", projectKey); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraPlugin.cs b/src/Greenshot.Plugin.Jira/JiraPlugin.cs new file mode 100644 index 000000000..de10ba163 --- /dev/null +++ b/src/Greenshot.Plugin.Jira/JiraPlugin.cs @@ -0,0 +1,146 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Threading.Tasks; +using System.Windows.Forms; +using Dapplo.Log; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Jira.Forms; +using log4net; + +namespace Greenshot.Plugin.Jira +{ + /// + /// This is the JiraPlugin base code + /// + [Plugin("Jira", true)] + public class JiraPlugin : IGreenshotPlugin + { + private static readonly ILog Log = LogManager.GetLogger(typeof(JiraPlugin)); + private JiraConfiguration _config; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + if (disposing) + { + var jiraConnector = SimpleServiceProvider.Current.GetInstance(); + jiraConnector?.Dispose(); + } + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// true if plugin is initialized, false if not (doesn't show) + public bool Initialize() + { + // Register configuration (don't need the configuration itself) + _config = IniConfig.GetIniSection(); + + // Provide the JiraConnector + SimpleServiceProvider.Current.AddService(new JiraConnector()); + // Provide the IDestination + SimpleServiceProvider.Current.AddService(new JiraDestination()); + + // Make sure the log is enabled for the correct level. + if (Log.IsDebugEnabled) + { + LogSettings.RegisterDefaultLogger(LogLevels.Verbose); + } + else if (Log.IsInfoEnabled) + { + LogSettings.RegisterDefaultLogger(LogLevels.Info); + } + else if (Log.IsWarnEnabled) + { + LogSettings.RegisterDefaultLogger(LogLevels.Warn); + } + else if (Log.IsErrorEnabled) + { + LogSettings.RegisterDefaultLogger(LogLevels.Error); + } + else if (Log.IsErrorEnabled) + { + LogSettings.RegisterDefaultLogger(LogLevels.Error); + } + else + { + LogSettings.RegisterDefaultLogger(LogLevels.Fatal); + } + + return true; + } + + public void Shutdown() + { + Log.Debug("Jira Plugin shutdown."); + var jiraConnector = SimpleServiceProvider.Current.GetInstance(); + jiraConnector?.Logout(); + } + + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + string url = _config.Url; + if (ShowConfigDialog()) + { + // check for re-login + var jiraConnector = SimpleServiceProvider.Current.GetInstance(); + if (jiraConnector != null && jiraConnector.IsLoggedIn && !string.IsNullOrEmpty(url)) + { + if (!url.Equals(_config.Url)) + { + jiraConnector.Logout(); + Task.Run(async () => { await jiraConnector.LoginAsync(); }); + } + } + } + } + + /// + /// A form for username/password + /// + /// bool true if OK was pressed, false if cancel + private bool ShowConfigDialog() + { + var settingsForm = new SettingsForm(); + var result = settingsForm.ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/GreenshotJiraPlugin/JiraPlugin.resx b/src/Greenshot.Plugin.Jira/JiraPlugin.resx similarity index 100% rename from GreenshotJiraPlugin/JiraPlugin.resx rename to src/Greenshot.Plugin.Jira/JiraPlugin.resx diff --git a/src/Greenshot.Plugin.Jira/LanguageKeys.cs b/src/Greenshot.Plugin.Jira/LanguageKeys.cs new file mode 100644 index 000000000..fd3fae242 --- /dev/null +++ b/src/Greenshot.Plugin.Jira/LanguageKeys.cs @@ -0,0 +1,40 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Plugin.Jira +{ + public enum LangKey + { + upload_menu_item, + column_assignee, + column_created, + column_issueType, + column_id, + column_reporter, + column_summary, + label_comment, + label_filename, + label_jirafilter, + login_error, + upload_failure, + communication_wait, + } +} \ No newline at end of file diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-cs-CZ.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-cs-CZ.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-cs-CZ.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-de-DE.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-de-DE.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-de-DE.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-de-DE.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-en-US.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-en-US.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-en-US.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-en-US.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-fr-FR.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-fr-FR.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-fr-FR.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-fr-FR.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-id-ID.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-id-ID.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-id-ID.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-id-ID.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-it-IT.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-it-IT.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-it-IT.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-ja-JP.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ja-JP.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-ja-JP.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ja-JP.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-kab-DZ.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-kab-DZ.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-kab-DZ.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-ko-KR.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ko-KR.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-ko-KR.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ko-KR.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-lv-LV.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-lv-LV.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-lv-LV.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-lv-LV.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-nl-NL.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-nl-NL.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-nl-NL.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-nl-NL.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-pl-PL.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-pl-PL.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-pl-PL.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-pl-PL.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-pt-PT.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-pt-PT.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-pt-PT.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-pt-PT.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-ru-RU.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ru-RU.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-ru-RU.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-ru-RU.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-sr-RS.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-sr-RS.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-sr-RS.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-sr-RS.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-sv-SE.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-sv-SE.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-sv-SE.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-sv-SE.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-uk-UA.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-uk-UA.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-uk-UA.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-uk-UA.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-CN.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-zh-CN.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-zh-CN.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-zh-CN.xml diff --git a/GreenshotJiraPlugin/Languages/language_jiraplugin-zh-TW.xml b/src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-zh-TW.xml similarity index 100% rename from GreenshotJiraPlugin/Languages/language_jiraplugin-zh-TW.xml rename to src/Greenshot.Plugin.Jira/Languages/language_jiraplugin-zh-TW.xml diff --git a/src/Greenshot.Plugin.Jira/Log4NetLogger.cs b/src/Greenshot.Plugin.Jira/Log4NetLogger.cs new file mode 100644 index 000000000..125fbcbcc --- /dev/null +++ b/src/Greenshot.Plugin.Jira/Log4NetLogger.cs @@ -0,0 +1,121 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Dapplo.Log; +using log4net; + +namespace Greenshot.Plugin.Jira +{ + /// + /// Used to make Dapplo.Log, used in Dapplo.Jira, write to Log4net + /// + public class Log4NetLogger : AbstractLogger + { + private ILog GetLogger(LogSource logSource) + { + return logSource.SourceType != null ? LogManager.GetLogger(logSource.SourceType) : LogManager.GetLogger(logSource.Source); + } + + /// + /// Write the supplied information to a log4net.ILog + /// + /// LogInfo + /// string + /// params object[] + public override void Write(LogInfo logInfo, string messageTemplate, params object[] propertyValues) + { + var log = GetLogger(logInfo.Source); + + switch (logInfo.LogLevel) + { + case LogLevels.Verbose: + case LogLevels.Debug: + if (propertyValues != null) + log.DebugFormat(messageTemplate, propertyValues); + else + log.Debug(messageTemplate); + break; + case LogLevels.Error: + if (propertyValues != null) + log.ErrorFormat(messageTemplate, propertyValues); + else + log.Error(messageTemplate); + break; + case LogLevels.Fatal: + if (propertyValues != null) + log.FatalFormat(messageTemplate, propertyValues); + else + log.Fatal(messageTemplate); + break; + case LogLevels.Info: + if (propertyValues != null) + log.InfoFormat(messageTemplate, propertyValues); + else + log.Info(messageTemplate); + break; + case LogLevels.Warn: + if (propertyValues != null) + log.WarnFormat(messageTemplate, propertyValues); + else + log.Warn(messageTemplate); + break; + } + } + + /// + /// Make sure there are no newlines passed + /// + /// + /// + /// + public override void WriteLine(LogInfo logInfo, string messageTemplate, params object[] logParameters) + { + Write(logInfo, messageTemplate, logParameters); + } + + /// + /// Test if a certain LogLevels enum is enabled + /// + /// LogLevels value + /// LogSource to check for + /// bool true if the LogLevels enum is enabled + public override bool IsLogLevelEnabled(LogLevels level, LogSource logSource = null) + { + var log = GetLogger(logSource); + switch (level) + { + case LogLevels.Verbose: + case LogLevels.Debug: + return log.IsDebugEnabled; + case LogLevels.Error: + return log.IsErrorEnabled; + case LogLevels.Fatal: + return log.IsFatalEnabled; + case LogLevels.Info: + return log.IsInfoEnabled; + case LogLevels.Warn: + return log.IsWarnEnabled; + } + + return false; + } + } +} \ No newline at end of file diff --git a/GreenshotOfficePlugin/Com/DisposableCom.cs b/src/Greenshot.Plugin.Office/Com/DisposableCom.cs similarity index 92% rename from GreenshotOfficePlugin/Com/DisposableCom.cs rename to src/Greenshot.Plugin.Office/Com/DisposableCom.cs index 1fc17a78b..e722f48e3 100644 --- a/GreenshotOfficePlugin/Com/DisposableCom.cs +++ b/src/Greenshot.Plugin.Office/Com/DisposableCom.cs @@ -1,6 +1,7 @@ // Copyright (c) Dapplo and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace GreenshotOfficePlugin.Com + +namespace Greenshot.Plugin.Office.Com { /// /// A factory for IDisposableCom diff --git a/GreenshotOfficePlugin/Com/DisposableComImplementation.cs b/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs similarity index 94% rename from GreenshotOfficePlugin/Com/DisposableComImplementation.cs rename to src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs index e7a52baac..572de52d8 100644 --- a/GreenshotOfficePlugin/Com/DisposableComImplementation.cs +++ b/src/Greenshot.Plugin.Office/Com/DisposableComImplementation.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.InteropServices; -namespace GreenshotOfficePlugin.Com +namespace Greenshot.Plugin.Office.Com { /// /// Implementation of the IDisposableCom, this is internal to prevent other code to use it directly @@ -38,6 +38,7 @@ namespace GreenshotOfficePlugin.Com { return; } + // Do not catch an exception from this. // You may want to remove these guards depending on // what you think the semantics should be. @@ -45,6 +46,7 @@ namespace GreenshotOfficePlugin.Com { Marshal.ReleaseComObject(ComObject); } + ComObject = default; } } diff --git a/GreenshotOfficePlugin/Com/IDisposableCom.cs b/src/Greenshot.Plugin.Office/Com/IDisposableCom.cs similarity index 90% rename from GreenshotOfficePlugin/Com/IDisposableCom.cs rename to src/Greenshot.Plugin.Office/Com/IDisposableCom.cs index 6bf1327c7..d99b6f4c6 100644 --- a/GreenshotOfficePlugin/Com/IDisposableCom.cs +++ b/src/Greenshot.Plugin.Office/Com/IDisposableCom.cs @@ -3,7 +3,7 @@ using System; -namespace GreenshotOfficePlugin.Com +namespace Greenshot.Plugin.Office.Com { /// /// A simple com wrapper which helps with "using" diff --git a/GreenshotOfficePlugin/Com/Ole32Api.cs b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs similarity index 90% rename from GreenshotOfficePlugin/Com/Ole32Api.cs rename to src/Greenshot.Plugin.Office/Com/Ole32Api.cs index d80167022..07d807ee2 100644 --- a/GreenshotOfficePlugin/Com/Ole32Api.cs +++ b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs @@ -3,10 +3,10 @@ using System; using System.Runtime.InteropServices; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.Enums; +using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; -namespace GreenshotOfficePlugin.Com +namespace Greenshot.Plugin.Office.Com { /// /// This provides an API for OLE32 @@ -24,6 +24,7 @@ namespace GreenshotOfficePlugin.Com { return clsId; } + return clsId; } @@ -36,4 +37,4 @@ namespace GreenshotOfficePlugin.Com [DllImport("ole32.dll", ExactSpelling = true)] private static extern HResult CLSIDFromProgID([In] [MarshalAs(UnmanagedType.LPWStr)] string progId, [Out] out Guid clsId); } -} +} \ No newline at end of file diff --git a/GreenshotOfficePlugin/Com/OleAut32Api.cs b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs similarity index 90% rename from GreenshotOfficePlugin/Com/OleAut32Api.cs rename to src/Greenshot.Plugin.Office/Com/OleAut32Api.cs index 6a3e4284c..c32b11a19 100644 --- a/GreenshotOfficePlugin/Com/OleAut32Api.cs +++ b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs @@ -3,10 +3,10 @@ using System; using System.Runtime.InteropServices; -using GreenshotPlugin.Core; -using GreenshotPlugin.Core.Enums; +using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; -namespace GreenshotOfficePlugin.Com +namespace Greenshot.Plugin.Office.Com { /// /// API for OLEAUT32 @@ -23,7 +23,7 @@ namespace GreenshotOfficePlugin.Com { if (GetActiveObject(ref clsId, IntPtr.Zero, out object comObject).Succeeded()) { - return DisposableCom.Create((T)comObject); + return DisposableCom.Create((T) comObject); } return null; @@ -51,4 +51,4 @@ namespace GreenshotOfficePlugin.Com [DllImport("oleaut32.dll")] private static extern HResult GetActiveObject(ref Guid rclsId, IntPtr pvReserved, [MarshalAs(UnmanagedType.IUnknown)] out object ppunk); } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs new file mode 100644 index 000000000..4aeceb12d --- /dev/null +++ b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs @@ -0,0 +1,116 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text.RegularExpressions; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Office.OfficeExport; + +namespace Greenshot.Plugin.Office.Destinations +{ + /// + /// Description of PowerpointDestination. + /// + public class ExcelDestination : AbstractDestination + { + private const int IconApplication = 0; + private const int IconWorkbook = 1; + private static readonly string ExePath; + private readonly string _workbookName; + + static ExcelDestination() + { + ExePath = PluginUtils.GetExePath("EXCEL.EXE"); + if (ExePath != null && File.Exists(ExePath)) + { + WindowDetails.AddProcessToExcludeFromFreeze("excel"); + } + else + { + ExePath = null; + } + } + + public ExcelDestination() + { + } + + public ExcelDestination(string workbookName) + { + _workbookName = workbookName; + } + + public override string Designation => "Excel"; + + public override string Description => _workbookName ?? "Microsoft Excel"; + + public override int Priority => 5; + + public override bool IsDynamic => true; + + public override bool IsActive => base.IsActive && ExePath != null; + + public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(ExePath, !string.IsNullOrEmpty(_workbookName) ? IconWorkbook : IconApplication); + + public override IEnumerable DynamicDestinations() + { + foreach (string workbookName in ExcelExporter.GetWorkbooks()) + { + yield return new ExcelDestination(workbookName); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + bool createdFile = false; + string imageFile = captureDetails.Filename; + if (imageFile == null || surface.Modified || !Regex.IsMatch(imageFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) + { + imageFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + createdFile = true; + } + + if (_workbookName != null) + { + ExcelExporter.InsertIntoExistingWorkbook(_workbookName, imageFile, surface.Image.Size); + } + else + { + ExcelExporter.InsertIntoNewWorkbook(imageFile, surface.Image.Size); + } + + exportInformation.ExportMade = true; + ProcessExport(exportInformation, surface); + // Cleanup imageFile if we created it here, so less tmp-files are generated and left + if (createdFile) + { + ImageOutput.DeleteNamedTmpFile(imageFile); + } + + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs new file mode 100644 index 000000000..33f23b58b --- /dev/null +++ b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs @@ -0,0 +1,144 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Plugin.Office.OfficeExport; +using Greenshot.Plugin.Office.OfficeExport.Entities; + +namespace Greenshot.Plugin.Office.Destinations +{ + public class OneNoteDestination : AbstractDestination + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(WordDestination)); + private const int ICON_APPLICATION = 0; + public const string DESIGNATION = "OneNote"; + private static readonly string exePath; + private readonly OneNotePage page; + private readonly OneNoteExporter _oneNoteExporter = new OneNoteExporter(); + + static OneNoteDestination() + { + exePath = PluginUtils.GetExePath("ONENOTE.EXE"); + if (exePath != null && File.Exists(exePath)) + { + WindowDetails.AddProcessToExcludeFromFreeze("onenote"); + } + else + { + exePath = null; + } + } + + public OneNoteDestination() + { + } + + public OneNoteDestination(OneNotePage page) + { + this.page = page; + } + + public override string Designation + { + get { return DESIGNATION; } + } + + public override string Description + { + get + { + if (page == null) + { + return "Microsoft OneNote"; + } + else + { + return page.DisplayName; + } + } + } + + public override int Priority + { + get { return 4; } + } + + public override bool IsDynamic + { + get { return true; } + } + + public override bool IsActive + { + get { return base.IsActive && exePath != null; } + } + + public override Image DisplayIcon + { + get { return PluginUtils.GetCachedExeIcon(exePath, ICON_APPLICATION); } + } + + public override IEnumerable DynamicDestinations() + { + foreach (OneNotePage page in _oneNoteExporter.GetPages()) + { + yield return new OneNoteDestination(page); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + + if (page == null) + { + try + { + exportInformation.ExportMade = _oneNoteExporter.ExportToNewPage(surface); + } + catch (Exception ex) + { + exportInformation.ErrorMessage = ex.Message; + LOG.Error(ex); + } + } + else + { + try + { + exportInformation.ExportMade = _oneNoteExporter.ExportToPage(surface, page); + } + catch (Exception ex) + { + exportInformation.ErrorMessage = ex.Message; + LOG.Error(ex); + } + } + + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs new file mode 100644 index 000000000..bfc78dd2f --- /dev/null +++ b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs @@ -0,0 +1,223 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Office.OfficeExport; +using Microsoft.Office.Interop.Outlook; +using Microsoft.Win32; + +namespace Greenshot.Plugin.Office.Destinations +{ + /// + /// Description of OutlookDestination. + /// + public class OutlookDestination : AbstractDestination + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(OutlookDestination)); + private const int IconApplication = 0; + private const int IconMeeting = 2; + + private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); + private static readonly OfficeConfiguration OfficeConfig = IniConfig.GetIniSection(); + private static readonly string ExePath; + private static readonly bool IsActiveFlag; + private const string MapiClient = "Microsoft Outlook"; + private readonly string _outlookInspectorCaption; + private readonly OlObjectClass _outlookInspectorType; + private readonly OutlookEmailExporter _outlookEmailExporter = new(); + + static OutlookDestination() + { + if (HasOutlook()) + { + IsActiveFlag = true; + } + + ExePath = PluginUtils.GetExePath("OUTLOOK.EXE"); + if (ExePath != null && File.Exists(ExePath)) + { + WindowDetails.AddProcessToExcludeFromFreeze("outlook"); + } + else + { + ExePath = GetOutlookExePath(); + } + + if (ExePath == null) + { + IsActiveFlag = false; + } + } + + + private static string GetOutlookExePath() => RegistryHive.LocalMachine.ReadKey64Or32(@"Microsoft\Windows\CurrentVersion\App Paths\OUTLOOK.EXE"); + + /// + /// Check if Outlook is installed + /// + /// Returns true if outlook is installed + private static bool HasOutlook() + { + string outlookPath = GetOutlookExePath(); + if (outlookPath == null) + { + return false; + } + + return File.Exists(outlookPath); + } + + public OutlookDestination() + { + } + + public OutlookDestination(string outlookInspectorCaption, OlObjectClass outlookInspectorType) + { + _outlookInspectorCaption = outlookInspectorCaption; + _outlookInspectorType = outlookInspectorType; + } + + public override string Designation => "Outlook"; + + public override string Description => _outlookInspectorCaption ?? MapiClient; + + public override int Priority => 3; + + public override bool IsActive => base.IsActive && IsActiveFlag; + + public override bool IsDynamic => true; + + public override Keys EditorShortcutKeys => Keys.Control | Keys.E; + + public override Image DisplayIcon + { + get + { + if (_outlookInspectorCaption == null) + { + return PluginUtils.GetCachedExeIcon(ExePath, IconApplication); + } + + if (OlObjectClass.olAppointment.Equals(_outlookInspectorType)) + { + // Make sure we loaded the icon, maybe the configuration has been changed! + return PluginUtils.GetCachedExeIcon(ExePath, IconMeeting); + } + + return MailIcon; + } + } + + public override IEnumerable DynamicDestinations() + { + IDictionary inspectorCaptions = _outlookEmailExporter.RetrievePossibleTargets(); + if (inspectorCaptions != null) + { + foreach (string inspectorCaption in inspectorCaptions.Keys) + { + yield return new OutlookDestination(inspectorCaption, inspectorCaptions[inspectorCaption]); + } + } + } + + /// + /// Export the capture to outlook + /// + /// + /// + /// + /// + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + // Outlook logic + string tmpFile = captureDetails.Filename; + if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) + { + tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + } + else + { + Log.InfoFormat("Using already available file: {0}", tmpFile); + } + + // Create a attachment name for the image + string attachmentName = captureDetails.Title; + if (!string.IsNullOrEmpty(attachmentName)) + { + attachmentName = attachmentName.Trim(); + } + + // Set default if non is set + if (string.IsNullOrEmpty(attachmentName)) + { + attachmentName = "Greenshot Capture"; + } + + // Make sure it's "clean" so it doesn't corrupt the header + attachmentName = Regex.Replace(attachmentName, @"[^\x20\d\w]", string.Empty); + + if (_outlookInspectorCaption != null) + { + _outlookEmailExporter.ExportToInspector(_outlookInspectorCaption, tmpFile, attachmentName); + exportInformation.ExportMade = true; + } + else + { + if (!manuallyInitiated) + { + var inspectorCaptions = _outlookEmailExporter.RetrievePossibleTargets(); + if (inspectorCaptions != null && inspectorCaptions.Count > 0) + { + var destinations = new List + { + new OutlookDestination() + }; + foreach (string inspectorCaption in inspectorCaptions.Keys) + { + destinations.Add(new OutlookDestination(inspectorCaption, inspectorCaptions[inspectorCaption])); + } + + // Return the ExportInformation from the picker without processing, as this indirectly comes from us self + return ShowPickerMenu(false, surface, captureDetails, destinations); + } + } + else + { + exportInformation.ExportMade = _outlookEmailExporter.ExportToOutlook(OfficeConfig.OutlookEmailFormat, tmpFile, + FilenameHelper.FillPattern(OfficeConfig.EmailSubjectPattern, captureDetails, false), attachmentName, OfficeConfig.EmailTo, OfficeConfig.EmailCC, + OfficeConfig.EmailBCC, null); + } + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs new file mode 100644 index 000000000..6e3c22f36 --- /dev/null +++ b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs @@ -0,0 +1,155 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Office.OfficeExport; + +namespace Greenshot.Plugin.Office.Destinations +{ + /// + /// Description of PowerpointDestination. + /// + public class PowerpointDestination : AbstractDestination + { + private const int IconApplication = 0; + private const int IconPresentation = 1; + + private static readonly string ExePath; + private readonly string _presentationName; + private readonly PowerpointExporter _powerpointExporter = new PowerpointExporter(); + + static PowerpointDestination() + { + ExePath = PluginUtils.GetExePath("POWERPNT.EXE"); + if (ExePath != null && File.Exists(ExePath)) + { + WindowDetails.AddProcessToExcludeFromFreeze("powerpnt"); + } + else + { + ExePath = null; + } + } + + public PowerpointDestination() + { + } + + public PowerpointDestination(string presentationName) + { + _presentationName = presentationName; + } + + public override string Designation => "Powerpoint"; + + public override string Description + { + get + { + if (_presentationName == null) + { + return "Microsoft Powerpoint"; + } + + return _presentationName; + } + } + + public override int Priority => 4; + + public override bool IsDynamic => true; + + public override bool IsActive => base.IsActive && ExePath != null; + + public override Image DisplayIcon + { + get + { + if (!string.IsNullOrEmpty(_presentationName)) + { + return PluginUtils.GetCachedExeIcon(ExePath, IconPresentation); + } + + return PluginUtils.GetCachedExeIcon(ExePath, IconApplication); + } + } + + public override IEnumerable DynamicDestinations() + { + foreach (string presentationName in _powerpointExporter.GetPowerpointPresentations()) + { + yield return new PowerpointDestination(presentationName); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + string tmpFile = captureDetails.Filename; + Size imageSize = Size.Empty; + if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) + { + tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + imageSize = surface.Image.Size; + } + + if (_presentationName != null) + { + exportInformation.ExportMade = _powerpointExporter.ExportToPresentation(_presentationName, tmpFile, imageSize, captureDetails.Title); + } + else + { + if (!manuallyInitiated) + { + var presentations = _powerpointExporter.GetPowerpointPresentations().ToList(); + if (presentations != null && presentations.Count > 0) + { + var destinations = new List + { + new PowerpointDestination() + }; + foreach (string presentation in presentations) + { + destinations.Add(new PowerpointDestination(presentation)); + } + + // Return the ExportInformation from the picker without processing, as this indirectly comes from us self + return ShowPickerMenu(false, surface, captureDetails, destinations); + } + } + else if (!exportInformation.ExportMade) + { + exportInformation.ExportMade = _powerpointExporter.InsertIntoNewPresentation(tmpFile, imageSize, captureDetails.Title); + } + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs new file mode 100644 index 000000000..f6d448505 --- /dev/null +++ b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs @@ -0,0 +1,163 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Office.OfficeExport; + +namespace Greenshot.Plugin.Office.Destinations +{ + /// + /// Description of EmailDestination. + /// + public class WordDestination : AbstractDestination + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(WordDestination)); + private const int IconApplication = 0; + private const int IconDocument = 1; + private static readonly string ExePath; + private readonly string _documentCaption; + private readonly WordExporter _wordExporter = new WordExporter(); + + static WordDestination() + { + ExePath = PluginUtils.GetExePath("WINWORD.EXE"); + if (ExePath != null && !File.Exists(ExePath)) + { + ExePath = null; + } + } + + public WordDestination() + { + } + + public WordDestination(string wordCaption) + { + _documentCaption = wordCaption; + } + + public override string Designation => "Word"; + + public override string Description => _documentCaption ?? "Microsoft Word"; + + public override int Priority => 4; + + public override bool IsDynamic => true; + + public override bool IsActive => base.IsActive && ExePath != null; + + public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(ExePath, !string.IsNullOrEmpty(_documentCaption) ? IconDocument : IconApplication); + + public override IEnumerable DynamicDestinations() + { + foreach (string wordCaption in _wordExporter.GetWordDocuments()) + { + yield return new WordDestination(wordCaption); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + string tmpFile = captureDetails.Filename; + if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) + { + tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + } + + if (_documentCaption != null) + { + try + { + _wordExporter.InsertIntoExistingDocument(_documentCaption, tmpFile); + exportInformation.ExportMade = true; + } + catch (Exception) + { + try + { + _wordExporter.InsertIntoExistingDocument(_documentCaption, tmpFile); + exportInformation.ExportMade = true; + } + catch (Exception ex) + { + Log.Error(ex); + // TODO: Change to general logic in ProcessExport + surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description)); + } + } + } + else + { + if (!manuallyInitiated) + { + var documents = _wordExporter.GetWordDocuments().ToList(); + if (documents != null && documents.Count > 0) + { + var destinations = new List + { + new WordDestination() + }; + foreach (string document in documents) + { + destinations.Add(new WordDestination(document)); + } + + // Return the ExportInformation from the picker without processing, as this indirectly comes from us self + return ShowPickerMenu(false, surface, captureDetails, destinations); + } + } + + try + { + _wordExporter.InsertIntoNewDocument(tmpFile, null, null); + exportInformation.ExportMade = true; + } + catch (Exception) + { + // Retry once, just in case + try + { + _wordExporter.InsertIntoNewDocument(tmpFile, null, null); + exportInformation.ExportMade = true; + } + catch (Exception ex) + { + Log.Error(ex); + // TODO: Change to general logic in ProcessExport + surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetFormattedString("destination_exportfailed", Description)); + } + } + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/GlobalSuppressions.cs b/src/Greenshot.Plugin.Office/GlobalSuppressions.cs new file mode 100644 index 0000000000000000000000000000000000000000..0adf57f14d766987b7b593f86de6b34d72bad816 GIT binary patch literal 3396 zcmeH}OK;Oq5QS%r#DB1Ygj$KVJftovu_&Mx7J*1f7N}xjQa25CoTzpxg&z-mXRfd8 zIM5B7R*I~|zMj{)XU^Q@_pc*6vcyJqZ8Ix*y5gQ&##30Yc$?WJ>+iPa`@Jn#$$n~u zrTDJ#2)-4z#OA!6VXNwUVnbWmlIxbZlB-|eQ=59Gr}hLC!jTeH;Wwk&iYNIe+^^jt zyK?BRd^vsrTc|9*fJC(x_5dwS& zcpsPxc+~&ccd4YYHfZkCSkTal>=l_*bqV&Mw}`H{rMRS{xt>QxhTB*h6g~Uo_`2$i zOq@|wlhSK3n%Gy+tUz_?j7lHUM1fyhsgdb_E3T{P$a9#lf*P7VOVzgF8p!9?G)X!c4zS7cQkX;jK6 z@KDEk)Ht|>s#4YB#m zJ`!_|SA~~!5Kf?_?REMQDh%+`v~KolT-SeNueWUNxaYPHyZiRd_qx-=L)F9ZKlRY= z`L5$-eXcyz6QIv&r?c&>K3CpxTIlr9X>#8wu8$2a{}AFutwkNHHGuaMM4Gu literal 0 HcmV?d00001 diff --git a/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj similarity index 94% rename from GreenshotOfficePlugin/GreenshotOfficePlugin.csproj rename to src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj index f6f07e98d..0e7d00d67 100644 --- a/GreenshotOfficePlugin/GreenshotOfficePlugin.csproj +++ b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj @@ -1,17 +1,11 @@  - - - GreenshotOfficePlugin - GreenshotOfficePlugin - - PreserveNewest - + diff --git a/GreenshotOfficePlugin/Languages/language_officeplugin-fr-FR.ini b/src/Greenshot.Plugin.Office/Languages/language_officeplugin-fr-FR.ini similarity index 100% rename from GreenshotOfficePlugin/Languages/language_officeplugin-fr-FR.ini rename to src/Greenshot.Plugin.Office/Languages/language_officeplugin-fr-FR.ini diff --git a/src/Greenshot.Plugin.Office/OfficeConfiguration.cs b/src/Greenshot.Plugin.Office/OfficeConfiguration.cs new file mode 100644 index 000000000..897075806 --- /dev/null +++ b/src/Greenshot.Plugin.Office/OfficeConfiguration.cs @@ -0,0 +1,62 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Base.IniFile; +using Greenshot.Plugin.Office.OfficeInterop; +using Microsoft.Office.Interop.PowerPoint; + +namespace Greenshot.Plugin.Office +{ + /// + /// Description of CoreConfiguration. + /// + [IniSection("Office", Description = "Greenshot Office configuration")] + public class OfficeConfiguration : IniSection + { + [IniProperty("OutlookEmailFormat", Description = "Default type for emails. (Text, HTML)", DefaultValue = "HTML")] + public EmailFormat OutlookEmailFormat { get; set; } + + [IniProperty("EmailSubjectPattern", Description = "Email subject pattern, works like the OutputFileFilenamePattern", DefaultValue = "${title}")] + public string EmailSubjectPattern { get; set; } + + [IniProperty("EmailTo", Description = "Default value for the to in emails that are created", DefaultValue = "")] + public string EmailTo { get; set; } + + [IniProperty("EmailCC", Description = "Default value for the CC in emails that are created", DefaultValue = "")] + public string EmailCC { get; set; } + + [IniProperty("EmailBCC", Description = "Default value for the BCC in emails that are created", DefaultValue = "")] + public string EmailBCC { get; set; } + + [IniProperty("OutlookAllowExportInMeetings", Description = "For Outlook: Allow export in meeting items", DefaultValue = "False")] + public bool OutlookAllowExportInMeetings { get; set; } + + [IniProperty("WordLockAspectRatio", Description = "For Word: Lock the aspect ratio of the image", DefaultValue = "True")] + public bool WordLockAspectRatio { get; set; } + + [IniProperty("PowerpointLockAspectRatio", Description = "For Powerpoint: Lock the aspect ratio of the image", DefaultValue = "True")] + public bool PowerpointLockAspectRatio { get; set; } + + [IniProperty("PowerpointSlideLayout", Description = "For Powerpoint: Slide layout, changing this to a wrong value will fallback on ppLayoutBlank!!", + DefaultValue = "ppLayoutPictureWithCaption")] + public PpSlideLayout PowerpointSlideLayout { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteNotebook.cs similarity index 93% rename from GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs rename to src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteNotebook.cs index 40bf4255e..861ad8927 100644 --- a/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteNotebook.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteNotebook.cs @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -namespace GreenshotOfficePlugin.OfficeExport.Entities +namespace Greenshot.Plugin.Office.OfficeExport.Entities { /// /// Container for transporting notebook information diff --git a/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs similarity index 94% rename from GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs rename to src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs index 6bc67084b..2a0904870 100644 --- a/GreenshotOfficePlugin/OfficeExport/Entities/OneNotePage.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNotePage.cs @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -namespace GreenshotOfficePlugin.OfficeExport.Entities +namespace Greenshot.Plugin.Office.OfficeExport.Entities { /// /// Container for transporting Page information @@ -34,6 +34,7 @@ namespace GreenshotOfficePlugin.OfficeExport.Entities { return string.Format("{0} / {1}", Parent.Name, Name); } + return string.Format("{0} / {1} / {2}", Parent.Parent.Name, Parent.Name, Name); } } diff --git a/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteSection.cs similarity index 93% rename from GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs rename to src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteSection.cs index 00eafb5ae..6464ee2c4 100644 --- a/GreenshotOfficePlugin/OfficeExport/Entities/OneNoteSection.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/Entities/OneNoteSection.cs @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -namespace GreenshotOfficePlugin.OfficeExport.Entities +namespace Greenshot.Plugin.Office.OfficeExport.Entities { /// /// Container for transporting section information diff --git a/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs similarity index 93% rename from GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs rename to src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs index ad92c6743..e725439da 100644 --- a/GreenshotOfficePlugin/OfficeExport/ExcelExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs @@ -20,14 +20,14 @@ using System; using System.Collections.Generic; using System.Drawing; -using GreenshotOfficePlugin.Com; -using GreenshotOfficePlugin.OfficeInterop; -using GreenshotPlugin.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Plugin.Office.Com; +using Greenshot.Plugin.Office.OfficeInterop; using Microsoft.Office.Core; using Microsoft.Office.Interop.Excel; using Version = System.Version; -namespace GreenshotOfficePlugin.OfficeExport +namespace Greenshot.Plugin.Office.OfficeExport { /// /// Excel exporter @@ -53,10 +53,12 @@ namespace GreenshotOfficePlugin.OfficeExport // Ignore, probably no excel running return null; } + if (excelApplication?.ComObject != null) { InitializeVariables(excelApplication); } + return excelApplication; } @@ -71,6 +73,7 @@ namespace GreenshotOfficePlugin.OfficeExport { excelApplication = DisposableCom.Create(new Application()); } + InitializeVariables(excelApplication); return excelApplication; } @@ -108,10 +111,11 @@ namespace GreenshotOfficePlugin.OfficeExport { return; } + if (!Version.TryParse(excelApplication.ComObject.Version, out _excelVersion)) { LOG.Warn("Assuming Excel version 1997."); - _excelVersion = new Version((int)OfficeVersions.Office97, 0, 0, 0); + _excelVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0); } } @@ -132,7 +136,7 @@ namespace GreenshotOfficePlugin.OfficeExport using var workbooks = DisposableCom.Create(excelApplication.ComObject.Workbooks); for (int i = 1; i <= workbooks.ComObject.Count; i++) { - using var workbook = DisposableCom.Create((_Workbook)workbooks.ComObject[i]); + using var workbook = DisposableCom.Create((_Workbook) workbooks.ComObject[i]); if ((workbook != null) && workbook.ComObject.Name.StartsWith(workbookName)) { InsertIntoExistingWorkbook(workbook, tmpFile, imageSize); @@ -191,9 +195,8 @@ namespace GreenshotOfficePlugin.OfficeExport excelApplication.ComObject.Visible = true; using var workbooks = DisposableCom.Create(excelApplication.ComObject.Workbooks); - using var workbook = DisposableCom.Create((_Workbook)workbooks.ComObject.Add()); + using var workbook = DisposableCom.Create((_Workbook) workbooks.ComObject.Add()); InsertIntoExistingWorkbook(workbook, tmpFile, imageSize); } } - } \ No newline at end of file diff --git a/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs similarity index 92% rename from GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs rename to src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs index 5b0fcb8c5..68fcf2f6b 100644 --- a/GreenshotOfficePlugin/OfficeExport/OneNoteExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs @@ -22,14 +22,14 @@ using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Xml; -using GreenshotOfficePlugin.Com; -using GreenshotOfficePlugin.OfficeExport.Entities; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Office.Com; +using Greenshot.Plugin.Office.OfficeExport.Entities; using Microsoft.Office.Interop.OneNote; -namespace GreenshotOfficePlugin.OfficeExport +namespace Greenshot.Plugin.Office.OfficeExport { /// /// OneNote exporter @@ -38,7 +38,10 @@ namespace GreenshotOfficePlugin.OfficeExport public class OneNoteExporter { private const string XmlImageContent = "{0}"; - private const string XmlOutline = "{0}"; + + private const string XmlOutline = + "{0}"; + private const string OnenoteNamespace2010 = "http://schemas.microsoft.com/office/onenote/2010/onenote"; private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OneNoteExporter)); @@ -107,6 +110,7 @@ namespace GreenshotOfficePlugin.OfficeExport { LOG.Warn("Unable to navigate to the target page", ex); } + return true; } @@ -126,6 +130,7 @@ namespace GreenshotOfficePlugin.OfficeExport // Ignore, probably no OneNote running return null; } + return oneNoteApplication; } @@ -140,6 +145,7 @@ namespace GreenshotOfficePlugin.OfficeExport { oneNoteApplication = DisposableCom.Create(new Application()); } + return oneNoteApplication; } @@ -183,6 +189,7 @@ namespace GreenshotOfficePlugin.OfficeExport }; } } + if ("one:Section".Equals(xmlReader.Name)) { string id = xmlReader.GetAttribute("ID"); @@ -196,6 +203,7 @@ namespace GreenshotOfficePlugin.OfficeExport }; } } + if ("one:Page".Equals(xmlReader.Name)) { // Skip deleted items @@ -214,6 +222,7 @@ namespace GreenshotOfficePlugin.OfficeExport { continue; } + page.IsCurrentlyViewed = "true".Equals(xmlReader.GetAttribute("isCurrentlyViewed")); pages.Add(page); } @@ -231,22 +240,26 @@ namespace GreenshotOfficePlugin.OfficeExport } catch (COMException cEx) { - if (cEx.ErrorCode == unchecked((int)0x8002801D)) + if (cEx.ErrorCode == unchecked((int) 0x8002801D)) { - LOG.Warn("Wrong registry keys, to solve this remove the OneNote key as described here: http://microsoftmercenary.com/wp/outlook-excel-interop-calls-breaking-solved/"); + LOG.Warn( + "Wrong registry keys, to solve this remove the OneNote key as described here: http://microsoftmercenary.com/wp/outlook-excel-interop-calls-breaking-solved/"); } + LOG.Warn("Problem retrieving onenote destinations, ignoring: ", cEx); } catch (Exception ex) { LOG.Warn("Problem retrieving onenote destinations, ignoring: ", ex); } + pages.Sort((page1, page2) => { if (page1.IsCurrentlyViewed || page2.IsCurrentlyViewed) { return page2.IsCurrentlyViewed.CompareTo(page1.IsCurrentlyViewed); } + return string.Compare(page1.DisplayName, page2.DisplayName, StringComparison.Ordinal); }); return pages; @@ -264,6 +277,7 @@ namespace GreenshotOfficePlugin.OfficeExport { return null; } + // ReSharper disable once RedundantAssignment string unfiledNotesPath = ""; oneNoteApplication.ComObject.GetSpecialLocation(specialLocation, out unfiledNotesPath); @@ -285,6 +299,7 @@ namespace GreenshotOfficePlugin.OfficeExport { continue; } + string id = xmlReader.GetAttribute("ID"); string path = xmlReader.GetAttribute("path"); if (unfiledNotesPath.Equals(path)) @@ -301,6 +316,7 @@ namespace GreenshotOfficePlugin.OfficeExport } } } + return null; } } diff --git a/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs similarity index 92% rename from GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs rename to src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs index 40306ecf7..ab3db1fdb 100644 --- a/GreenshotOfficePlugin/OfficeExport/OutlookEmailExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/OutlookEmailExporter.cs @@ -21,9 +21,9 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; -using GreenshotOfficePlugin.Com; -using GreenshotOfficePlugin.OfficeInterop; -using GreenshotPlugin.IniFile; +using Greenshot.Base.IniFile; +using Greenshot.Plugin.Office.Com; +using Greenshot.Plugin.Office.OfficeInterop; using Microsoft.Office.Interop.Outlook; using Microsoft.Office.Interop.Word; using Microsoft.Win32; @@ -32,7 +32,7 @@ using Application = Microsoft.Office.Interop.Outlook.Application; using Exception = System.Exception; using Version = System.Version; -namespace GreenshotOfficePlugin.OfficeExport +namespace Greenshot.Plugin.Office.OfficeExport { /// /// Outlook exporter has all the functionality to export to outlook @@ -47,7 +47,9 @@ namespace GreenshotOfficePlugin.OfficeExport private const string ProfilesKey = @"Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\"; private const string AccountKey = "9375CFF0413111d3B88A00104B2A6676"; private const string NewSignatureValue = "New Signature"; + private const string DefaultProfileValue = "DefaultProfile"; + // Schema definitions for the MAPI properties, see: http://msdn.microsoft.com/en-us/library/aa454438.aspx and: http://msdn.microsoft.com/en-us/library/bb446117.aspx private const string AttachmentContentId = @"http://schemas.microsoft.com/mapi/proptag/0x3712001E"; @@ -73,10 +75,10 @@ namespace GreenshotOfficePlugin.OfficeExport } // The activeexplorer inline response only works with >= 2013, Microsoft Outlook 15.0 Object Library - if (_outlookVersion.Major >= (int)OfficeVersions.Office2013) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2013) { // Check inline "panel" for Outlook 2013 - using var activeExplorer = DisposableCom.Create((_Explorer)outlookApplication.ComObject.ActiveExplorer()); + using var activeExplorer = DisposableCom.Create((_Explorer) outlookApplication.ComObject.ActiveExplorer()); // Only if we have one and if the capture is the one we selected if ((activeExplorer != null) && activeExplorer.ComObject.Caption.StartsWith(inspectorCaption)) { @@ -90,15 +92,17 @@ namespace GreenshotOfficePlugin.OfficeExport { return ExportToInspector(null, activeExplorer, mailItem.Class, mailItem, tmpFile, attachmentName); } + break; case AppointmentItem appointmentItem: - if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) + if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) { if (!string.IsNullOrEmpty(appointmentItem.Organizer) && appointmentItem.Organizer.Equals(_currentUser)) { return ExportToInspector(null, activeExplorer, appointmentItem.Class, null, tmpFile, attachmentName); } } + break; } } @@ -110,10 +114,11 @@ namespace GreenshotOfficePlugin.OfficeExport { return false; } + LOG.DebugFormat("Got {0} inspectors to check", inspectors.ComObject.Count); for (int i = 1; i <= inspectors.ComObject.Count; i++) { - using var inspector = DisposableCom.Create((_Inspector)inspectors.ComObject[i]); + using var inspector = DisposableCom.Create((_Inspector) inspectors.ComObject[i]); string currentCaption = inspector.ComObject.Caption; if (!currentCaption.StartsWith(inspectorCaption)) { @@ -130,6 +135,7 @@ namespace GreenshotOfficePlugin.OfficeExport { continue; } + try { return ExportToInspector(inspector, null, mailItem.Class, mailItem, tmpFile, attachmentName); @@ -138,9 +144,10 @@ namespace GreenshotOfficePlugin.OfficeExport { LOG.Error($"Export to {currentCaption} failed.", exExport); } + break; case AppointmentItem appointmentItem: - if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) + if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) { if (!string.IsNullOrEmpty(appointmentItem.Organizer) && !appointmentItem.Organizer.Equals(_currentUser)) { @@ -153,6 +160,7 @@ namespace GreenshotOfficePlugin.OfficeExport // skip, can't export to olAppointment continue; } + try { return ExportToInspector(inspector, null, appointmentItem.Class, null, tmpFile, attachmentName); @@ -161,6 +169,7 @@ namespace GreenshotOfficePlugin.OfficeExport { LOG.Error($"Export to {currentCaption} failed.", exExport); } + break; default: continue; @@ -168,6 +177,7 @@ namespace GreenshotOfficePlugin.OfficeExport } } } + return false; } @@ -181,7 +191,8 @@ namespace GreenshotOfficePlugin.OfficeExport /// /// /// - private bool ExportToInspector(IDisposableCom<_Inspector> inspector, IDisposableCom<_Explorer> explorer, OlObjectClass itemClass, MailItem mailItem, string tmpFile, string attachmentName) + private bool ExportToInspector(IDisposableCom<_Inspector> inspector, IDisposableCom<_Explorer> explorer, OlObjectClass itemClass, MailItem mailItem, string tmpFile, + string attachmentName) { bool isMail = OlObjectClass.olMail.Equals(itemClass); bool isAppointment = OlObjectClass.olAppointment.Equals(itemClass); @@ -190,6 +201,7 @@ namespace GreenshotOfficePlugin.OfficeExport LOG.Warn("Item is no mail or appointment."); return false; } + try { // Make sure the inspector is activated, only this way the word editor is active! @@ -200,25 +212,27 @@ namespace GreenshotOfficePlugin.OfficeExport { isTextFormat = OlBodyFormat.olFormatPlain.Equals(mailItem.BodyFormat); } + if (isAppointment || !isTextFormat) { // Check for wordmail, if so use the wordexporter // http://msdn.microsoft.com/en-us/library/dd492012%28v=office.12%29.aspx // Earlier versions of Outlook also supported an Inspector.HTMLEditor object property, but since Internet Explorer is no longer the rendering engine for HTML messages and posts, HTMLEditor is no longer supported. IDisposableCom<_Document> wordDocument = null; - if ((explorer != null) && (_outlookVersion.Major >= (int)OfficeVersions.Office2013)) + if ((explorer != null) && (_outlookVersion.Major >= (int) OfficeVersions.Office2013)) { // TODO: Needs to have the Microsoft Outlook 15.0 Object Library installed - wordDocument = DisposableCom.Create((_Document)explorer.ComObject.ActiveInlineResponseWordEditor); + wordDocument = DisposableCom.Create((_Document) explorer.ComObject.ActiveInlineResponseWordEditor); } else if (inspector != null) { if (inspector.ComObject.IsWordMail() && (inspector.ComObject.EditorType == OlEditorType.olEditorWord)) { - var tmpWordDocument = (_Document)inspector.ComObject.WordEditor; + var tmpWordDocument = (_Document) inspector.ComObject.WordEditor; wordDocument = DisposableCom.Create(tmpWordDocument); } } + if (wordDocument != null) { using (wordDocument) @@ -248,6 +262,7 @@ namespace GreenshotOfficePlugin.OfficeExport LOG.Info("Trying export for outlook < 2007."); } } + // Only use mailitem as it should be filled!! if (mailItem != null) { @@ -255,7 +270,7 @@ namespace GreenshotOfficePlugin.OfficeExport } string contentId; - if (_outlookVersion.Major >= (int)OfficeVersions.Office2007) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2007) { contentId = Guid.NewGuid().ToString(); } @@ -283,7 +298,7 @@ namespace GreenshotOfficePlugin.OfficeExport var selection = document2.selection; if (selection != null) { - var range = (IHTMLTxtRange)selection.createRange(); + var range = (IHTMLTxtRange) selection.createRange(); if (range != null) { // First paste, than attach (otherwise the range is wrong!) @@ -315,7 +330,7 @@ namespace GreenshotOfficePlugin.OfficeExport // Create the attachment (if inlined the attachment isn't visible as attachment!) using var attachments = DisposableCom.Create(mailItem.Attachments); using var attachment = DisposableCom.Create(attachments.ComObject.Add(tmpFile, OlAttachmentType.olByValue, inlinePossible ? 0 : 1, attachmentName)); - if (_outlookVersion.Major >= (int)OfficeVersions.Office2007) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2007) { // Add the content id to the attachment, this only works for Outlook >= 2007 try @@ -341,9 +356,11 @@ namespace GreenshotOfficePlugin.OfficeExport { caption = explorer.ComObject.Caption; } + LOG.Warn($"Problem while trying to add attachment to Item '{caption}'", ex); return false; } + try { if (inspector != null) @@ -360,6 +377,7 @@ namespace GreenshotOfficePlugin.OfficeExport LOG.Warn("Problem activating inspector/explorer: ", ex); return false; } + LOG.Debug("Finished!"); return true; } @@ -376,27 +394,32 @@ namespace GreenshotOfficePlugin.OfficeExport /// /// /// - private void ExportToNewEmail(IDisposableCom outlookApplication, EmailFormat format, string tmpFile, string subject, string attachmentName, string to, string cc, string bcc, string url) + private void ExportToNewEmail(IDisposableCom outlookApplication, EmailFormat format, string tmpFile, string subject, string attachmentName, string to, + string cc, string bcc, string url) { - using var newItem = DisposableCom.Create((MailItem)outlookApplication.ComObject.CreateItem(OlItemType.olMailItem)); + using var newItem = DisposableCom.Create((MailItem) outlookApplication.ComObject.CreateItem(OlItemType.olMailItem)); if (newItem == null) { return; } + var newMail = newItem.ComObject; newMail.Subject = subject; if (!string.IsNullOrEmpty(to)) { newMail.To = to; } + if (!string.IsNullOrEmpty(cc)) { newMail.CC = cc; } + if (!string.IsNullOrEmpty(bcc)) { newMail.BCC = bcc; } + newMail.BodyFormat = OlBodyFormat.olFormatHTML; string bodyString = null; // Read the default signature, if nothing found use empty email @@ -408,6 +431,7 @@ namespace GreenshotOfficePlugin.OfficeExport { LOG.Error("Problem reading signature!", e); } + switch (format) { case EmailFormat.Text: @@ -421,9 +445,11 @@ namespace GreenshotOfficePlugin.OfficeExport { bodyString = ""; } + newMail.Body = bodyString; } } + break; default: string contentId = Path.GetFileName(tmpFile); @@ -432,7 +458,7 @@ namespace GreenshotOfficePlugin.OfficeExport { using var attachment = DisposableCom.Create(attachments.ComObject.Add(tmpFile, OlAttachmentType.olByValue, 0, attachmentName)); // add content ID to the attachment - if (_outlookVersion.Major >= (int)OfficeVersions.Office2007) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2007) { try { @@ -456,6 +482,7 @@ namespace GreenshotOfficePlugin.OfficeExport href = $""; hrefEnd = ""; } + string htmlImgEmbedded = $"
{href}\"{attachmentName}\"{hrefEnd}
"; string fallbackBody = $"{htmlImgEmbedded}"; if (bodyString == null) @@ -482,13 +509,15 @@ namespace GreenshotOfficePlugin.OfficeExport bodyString = fallbackBody; } } + newMail.HTMLBody = bodyString; break; } + // So not save, otherwise the email is always stored in Draft folder.. (newMail.Save();) newMail.Display(false); - using var inspector = DisposableCom.Create((_Inspector)newMail.GetInspector); + using var inspector = DisposableCom.Create((_Inspector) newMail.GetInspector); if (inspector != null) { try @@ -528,12 +557,14 @@ namespace GreenshotOfficePlugin.OfficeExport exported = true; } } + return exported; } catch (Exception e) { LOG.Error("Error while creating an outlook mail item: ", e); } + return exported; } @@ -548,6 +579,7 @@ namespace GreenshotOfficePlugin.OfficeExport { outlookApplication = DisposableCom.Create(new Application()); } + InitializeVariables(outlookApplication); return outlookApplication; } @@ -568,10 +600,12 @@ namespace GreenshotOfficePlugin.OfficeExport // Ignore, probably no outlook running return null; } + if ((outlookApplication != null) && (outlookApplication.ComObject != null)) { InitializeVariables(outlookApplication); } + return outlookApplication; } @@ -587,7 +621,8 @@ namespace GreenshotOfficePlugin.OfficeExport { return null; } - string defaultProfile = (string)profilesKey.GetValue(DefaultProfileValue); + + string defaultProfile = (string) profilesKey.GetValue(DefaultProfileValue); LOG.DebugFormat("defaultProfile={0}", defaultProfile); using var profileKey = profilesKey.OpenSubKey(defaultProfile + @"\" + AccountKey, false); if (profileKey != null) @@ -599,19 +634,21 @@ namespace GreenshotOfficePlugin.OfficeExport using var numberKey = profileKey.OpenSubKey(number, false); if (numberKey != null) { - byte[] val = (byte[])numberKey.GetValue(NewSignatureValue); + byte[] val = (byte[]) numberKey.GetValue(NewSignatureValue); if (val == null) { continue; } + string signatureName = ""; foreach (byte b in val) { if (b != 0) { - signatureName += (char)b; + signatureName += (char) b; } } + LOG.DebugFormat("Found email signature: {0}", signatureName); var extension = format switch { @@ -628,6 +665,7 @@ namespace GreenshotOfficePlugin.OfficeExport } } } + return null; } @@ -642,13 +680,15 @@ namespace GreenshotOfficePlugin.OfficeExport { return; } + if (!Version.TryParse(outlookApplication.ComObject.Version, out _outlookVersion)) { LOG.Warn("Assuming outlook version 1997."); - _outlookVersion = new Version((int)OfficeVersions.Office97, 0, 0, 0); + _outlookVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0); } + // Preventing retrieval of currentUser if Outlook is older than 2007 - if (_outlookVersion.Major >= (int)OfficeVersions.Office2007) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2007) { try { @@ -657,6 +697,7 @@ namespace GreenshotOfficePlugin.OfficeExport using var currentUser = DisposableCom.Create(mapiNamespace.ComObject.CurrentUser); _currentUser = currentUser.ComObject.Name; } + LOG.InfoFormat("Current user: {0}", _currentUser); } catch (Exception exNs) @@ -682,7 +723,7 @@ namespace GreenshotOfficePlugin.OfficeExport } // The activeexplorer inline response only works with >= 2013, Microsoft Outlook 15.0 Object Library - if (_outlookVersion.Major >= (int)OfficeVersions.Office2013) + if (_outlookVersion.Major >= (int) OfficeVersions.Office2013) { // Check inline "panel" for Outlook 2013 using var activeExplorer = DisposableCom.Create(outlookApplication.ComObject.ActiveExplorer()); @@ -701,15 +742,17 @@ namespace GreenshotOfficePlugin.OfficeExport { inspectorCaptions.Add(caption, mailItem.Class); } + break; case AppointmentItem appointmentItem: - if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) + if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) { if (!string.IsNullOrEmpty(appointmentItem.Organizer) && appointmentItem.Organizer.Equals(_currentUser)) { inspectorCaptions.Add(caption, appointmentItem.Class); } } + break; } } @@ -740,10 +783,11 @@ namespace GreenshotOfficePlugin.OfficeExport { continue; } + inspectorCaptions.Add(caption, mailItem.Class); break; case AppointmentItem appointmentItem: - if ((_outlookVersion.Major >= (int)OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) + if ((_outlookVersion.Major >= (int) OfficeVersions.Office2010) && _officeConfiguration.OutlookAllowExportInMeetings) { if (!string.IsNullOrEmpty(appointmentItem.Organizer) && !appointmentItem.Organizer.Equals(_currentUser)) { @@ -756,6 +800,7 @@ namespace GreenshotOfficePlugin.OfficeExport // skip, can't export to olAppointment continue; } + inspectorCaptions.Add(caption, appointmentItem.Class); break; default: @@ -769,6 +814,7 @@ namespace GreenshotOfficePlugin.OfficeExport { LOG.Warn("Problem retrieving word destinations, ignoring: ", ex); } + return inspectorCaptions; } } diff --git a/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs similarity index 95% rename from GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs rename to src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs index 7f87ff111..1b76f54bf 100644 --- a/GreenshotOfficePlugin/OfficeExport/PowerpointExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/PowerpointExporter.cs @@ -20,14 +20,14 @@ using System; using System.Collections.Generic; using System.Drawing; -using GreenshotOfficePlugin.Com; -using GreenshotOfficePlugin.OfficeInterop; -using GreenshotPlugin.IniFile; +using Greenshot.Base.IniFile; +using Greenshot.Plugin.Office.Com; +using Greenshot.Plugin.Office.OfficeInterop; using Microsoft.Office.Core; using Microsoft.Office.Interop.PowerPoint; using Shape = Microsoft.Office.Interop.PowerPoint.Shape; -namespace GreenshotOfficePlugin.OfficeExport +namespace Greenshot.Plugin.Office.OfficeExport { /// /// Export logic for powerpoint @@ -60,6 +60,7 @@ namespace GreenshotOfficePlugin.OfficeExport left = pageSetup.ComObject.SlideWidth / 2 - imageSize.Width / 2f; top = pageSetup.ComObject.SlideHeight / 2 - imageSize.Height / 2f; } + float width = imageSize.Width; float height = imageSize.Height; IDisposableCom shapeForCaption = null; @@ -86,6 +87,7 @@ namespace GreenshotOfficePlugin.OfficeExport { shapeForLocation.ComObject.Left = left; } + shapeForLocation.ComObject.Width = imageSize.Width; if (height > shapeForLocation.ComObject.Height) @@ -98,6 +100,7 @@ namespace GreenshotOfficePlugin.OfficeExport { top = shapeForLocation.ComObject.Top + shapeForLocation.ComObject.Height / 2 - imageSize.Height / 2f; } + shapeForLocation.ComObject.Height = imageSize.Height; } catch (Exception e) @@ -106,6 +109,7 @@ namespace GreenshotOfficePlugin.OfficeExport using var slides = DisposableCom.Create(presentation.ComObject.Slides); slide = DisposableCom.Create(slides.ComObject.Add(slides.ComObject.Count + 1, PpSlideLayout.ppLayoutBlank)); } + using (var shapes = DisposableCom.Create(slide.ComObject.Shapes)) { using var shape = DisposableCom.Create(shapes.ComObject.AddPicture(tmpFile, MsoTriState.msoFalse, MsoTriState.msoTrue, 0, 0, width, height)); @@ -117,20 +121,24 @@ namespace GreenshotOfficePlugin.OfficeExport { shape.ComObject.LockAspectRatio = MsoTriState.msoFalse; } + shape.ComObject.ScaleHeight(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle); shape.ComObject.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromMiddle); if (hasScaledWidth) { shape.ComObject.Width = width; } + if (hasScaledHeight) { shape.ComObject.Height = height; } + shape.ComObject.Left = left; shape.ComObject.Top = top; shape.ComObject.AlternativeText = title; } + if (shapeForCaption != null) { try @@ -148,6 +156,7 @@ namespace GreenshotOfficePlugin.OfficeExport LOG.Warn("Problem setting the title to a text-range", ex); } } + // Activate/Goto the slide try { @@ -194,10 +203,12 @@ namespace GreenshotOfficePlugin.OfficeExport { continue; } + if (!presentation.ComObject.Name.StartsWith(presentationName)) { continue; } + try { AddPictureToPresentation(presentation, tmpFile, imageSize, title); @@ -209,6 +220,7 @@ namespace GreenshotOfficePlugin.OfficeExport } } } + return false; } @@ -223,6 +235,7 @@ namespace GreenshotOfficePlugin.OfficeExport { powerPointApplication = DisposableCom.Create(new Application()); } + InitializeVariables(powerPointApplication); return powerPointApplication; } @@ -243,10 +256,12 @@ namespace GreenshotOfficePlugin.OfficeExport // Ignore, probably no PowerPoint running return null; } + if (powerPointApplication?.ComObject != null) { InitializeVariables(powerPointApplication); } + return powerPointApplication; } @@ -271,10 +286,12 @@ namespace GreenshotOfficePlugin.OfficeExport { continue; } + if (presentation.ComObject.ReadOnly == MsoTriState.msoTrue) { continue; } + if (IsAfter2003()) { if (presentation.ComObject.Final) @@ -282,6 +299,7 @@ namespace GreenshotOfficePlugin.OfficeExport continue; } } + yield return presentation.ComObject.Name; } } @@ -296,10 +314,11 @@ namespace GreenshotOfficePlugin.OfficeExport { return; } + if (!Version.TryParse(powerpointApplication.ComObject.Version, out _powerpointVersion)) { LOG.Warn("Assuming Powerpoint version 1997."); - _powerpointVersion = new Version((int)OfficeVersions.Office97, 0, 0, 0); + _powerpointVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0); } } @@ -332,13 +351,13 @@ namespace GreenshotOfficePlugin.OfficeExport } } } + return isPictureAdded; } private bool IsAfter2003() { - return _powerpointVersion.Major > (int)OfficeVersions.Office2003; + return _powerpointVersion.Major > (int) OfficeVersions.Office2003; } } - } \ No newline at end of file diff --git a/GreenshotOfficePlugin/OfficeExport/WordExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs similarity index 94% rename from GreenshotOfficePlugin/OfficeExport/WordExporter.cs rename to src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs index b44f08161..d4da1cc3a 100644 --- a/GreenshotOfficePlugin/OfficeExport/WordExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/WordExporter.cs @@ -19,14 +19,14 @@ using System; using System.Collections.Generic; -using GreenshotOfficePlugin.Com; -using GreenshotOfficePlugin.OfficeInterop; -using GreenshotPlugin.IniFile; +using Greenshot.Base.IniFile; +using Greenshot.Plugin.Office.Com; +using Greenshot.Plugin.Office.OfficeInterop; using Microsoft.Office.Core; using Microsoft.Office.Interop.Word; using Version = System.Version; -namespace GreenshotOfficePlugin.OfficeExport +namespace Greenshot.Plugin.Office.OfficeExport { /// /// This makes it possible to export to word @@ -53,6 +53,7 @@ namespace GreenshotOfficePlugin.OfficeExport { shape.ComObject.LockAspectRatio = MsoTriState.msoTrue; } + selection.ComObject.InsertAfter("\r\n"); selection.ComObject.MoveDown(WdUnits.wdLine, 1, Type.Missing); return shape; @@ -69,6 +70,7 @@ namespace GreenshotOfficePlugin.OfficeExport { wordApplication = DisposableCom.Create(new Application()); } + InitializeVariables(wordApplication); return wordApplication; } @@ -89,10 +91,12 @@ namespace GreenshotOfficePlugin.OfficeExport // Ignore, probably no word running return null; } + if ((wordApplication != null) && (wordApplication.ComObject != null)) { InitializeVariables(wordApplication); } + return wordApplication; } @@ -116,6 +120,7 @@ namespace GreenshotOfficePlugin.OfficeExport { continue; } + if (IsAfter2003()) { if (document.ComObject.Final) @@ -139,10 +144,11 @@ namespace GreenshotOfficePlugin.OfficeExport { return; } + if (!Version.TryParse(wordApplication.ComObject.Version, out _wordVersion)) { LOG.Warn("Assuming Word version 1997."); - _wordVersion = new Version((int)OfficeVersions.Office97, 0, 0, 0); + _wordVersion = new Version((int) OfficeVersions.Office97, 0, 0, 0); } } @@ -164,7 +170,7 @@ namespace GreenshotOfficePlugin.OfficeExport using var documents = DisposableCom.Create(wordApplication.ComObject.Documents); for (int i = 1; i <= documents.ComObject.Count; i++) { - using var wordDocument = DisposableCom.Create((_Document)documents.ComObject[i]); + using var wordDocument = DisposableCom.Create((_Document) documents.ComObject[i]); using var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow); if (activeWindow.ComObject.Caption.StartsWith(wordCaption)) { @@ -172,6 +178,7 @@ namespace GreenshotOfficePlugin.OfficeExport } } } + return false; } @@ -184,7 +191,8 @@ namespace GreenshotOfficePlugin.OfficeExport /// string /// string with the tooltip of the image /// bool - internal bool InsertIntoExistingDocument(IDisposableCom wordApplication, IDisposableCom<_Document> wordDocument, string tmpFile, string address, string tooltip) + internal bool InsertIntoExistingDocument(IDisposableCom wordApplication, IDisposableCom<_Document> wordDocument, string tmpFile, string address, + string tooltip) { // Bug #1517: image will be inserted into that document, where the focus was last. It will not inserted into the chosen one. // Solution: Make sure the selected document is active, otherwise the insert will be made in a different document! @@ -204,6 +212,7 @@ namespace GreenshotOfficePlugin.OfficeExport LOG.InfoFormat("No selection to insert {0} into found.", tmpFile); return false; } + // Add Picture using (var shape = AddPictureToSelection(selection, tmpFile)) { @@ -214,6 +223,7 @@ namespace GreenshotOfficePlugin.OfficeExport { screentip = tooltip; } + try { using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks); @@ -225,6 +235,7 @@ namespace GreenshotOfficePlugin.OfficeExport } } } + try { // When called for Outlook, the follow error is created: This object model command is not available in e-mail @@ -245,6 +256,7 @@ namespace GreenshotOfficePlugin.OfficeExport LOG.WarnFormat("Couldn't set zoom to 100, error: {0}", e.Message); } } + try { wordApplication.ComObject.Activate(); @@ -254,6 +266,7 @@ namespace GreenshotOfficePlugin.OfficeExport { LOG.Warn("Error activating word application", ex); } + try { wordDocument.ComObject.Activate(); @@ -263,6 +276,7 @@ namespace GreenshotOfficePlugin.OfficeExport { LOG.Warn("Error activating word document", ex); } + return true; } @@ -279,6 +293,7 @@ namespace GreenshotOfficePlugin.OfficeExport { return; } + wordApplication.ComObject.Visible = true; wordApplication.ComObject.Activate(); // Create new Document @@ -299,6 +314,7 @@ namespace GreenshotOfficePlugin.OfficeExport { screentip = tooltip; } + try { using var hyperlinks = DisposableCom.Create(wordDocument.ComObject.Hyperlinks); @@ -313,6 +329,7 @@ namespace GreenshotOfficePlugin.OfficeExport } } } + try { wordDocument.ComObject.Activate(); @@ -322,6 +339,7 @@ namespace GreenshotOfficePlugin.OfficeExport { LOG.Warn("Error activating word document", ex); } + try { using var activeWindow = DisposableCom.Create(wordDocument.ComObject.ActiveWindow); @@ -340,7 +358,7 @@ namespace GreenshotOfficePlugin.OfficeExport /// private bool IsAfter2003() { - return _wordVersion.Major > (int)OfficeVersions.Office2003; + return _wordVersion.Major > (int) OfficeVersions.Office2003; } } } \ No newline at end of file diff --git a/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs b/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs similarity index 80% rename from GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs rename to src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs index 2de5cbf71..ea78fce8b 100644 --- a/GreenshotOfficePlugin/OfficeInterop/EmailFormat.cs +++ b/src/Greenshot.Plugin.Office/OfficeInterop/EmailFormat.cs @@ -17,20 +17,21 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -namespace GreenshotOfficePlugin.OfficeInterop +namespace Greenshot.Plugin.Office.OfficeInterop { - /// - /// Specifies which EmailFormat the email needs to use - /// - public enum EmailFormat - { + /// + /// Specifies which EmailFormat the email needs to use + /// + public enum EmailFormat + { /// /// Use the plain text format /// - Text, + Text, + /// /// Use HTML format /// - Html - } + Html + } } \ No newline at end of file diff --git a/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs b/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs similarity index 79% rename from GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs rename to src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs index 3988148c5..321e6de2f 100644 --- a/GreenshotOfficePlugin/OfficeInterop/OfficeVersions.cs +++ b/src/Greenshot.Plugin.Office/OfficeInterop/OfficeVersions.cs @@ -17,40 +17,46 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -namespace GreenshotOfficePlugin.OfficeInterop +namespace Greenshot.Plugin.Office.OfficeInterop { - /// - /// A mapping between the version and a usable name - /// - public enum OfficeVersions - { + /// + /// A mapping between the version and a usable name + /// + public enum OfficeVersions + { /// /// Office 97 /// - Office97 = 8, + Office97 = 8, + /// /// Office 2003 /// - Office2003 = 11, + Office2003 = 11, + /// /// Office 2007 /// - Office2007 = 12, + Office2007 = 12, + /// /// Office 2010 /// - Office2010 = 14, + Office2010 = 14, + /// /// Office 2013 /// - Office2013 = 15, + Office2013 = 15, + /// /// Office 2016 /// Office2016 = 16, + /// /// Office 2019 /// Office2019 = 17 - } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/OfficePlugin.cs b/src/Greenshot.Plugin.Office/OfficePlugin.cs new file mode 100644 index 000000000..bfb10bfa0 --- /dev/null +++ b/src/Greenshot.Plugin.Office/OfficePlugin.cs @@ -0,0 +1,148 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Office.Destinations; + +namespace Greenshot.Plugin.Office +{ + /// + /// This is the OfficePlugin base code + /// + [Plugin("Office", false)] + public class OfficePlugin : IGreenshotPlugin + { + private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OfficePlugin)); + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + // Do nothing + } + + private IEnumerable Destinations() + { + IDestination destination; + try + { + destination = new ExcelDestination(); + } + catch + { + destination = null; + } + + if (destination != null) + { + yield return destination; + } + + try + { + destination = new PowerpointDestination(); + } + catch + { + destination = null; + } + + if (destination != null) + { + yield return destination; + } + + try + { + destination = new WordDestination(); + } + catch + { + destination = null; + } + + if (destination != null) + { + yield return destination; + } + + try + { + destination = new OutlookDestination(); + } + catch + { + destination = null; + } + + if (destination != null) + { + yield return destination; + } + + try + { + destination = new OneNoteDestination(); + } + catch + { + destination = null; + } + + if (destination != null) + { + yield return destination; + } + } + + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// true if plugin is initialized, false if not (doesn't show) + public bool Initialize() + { + SimpleServiceProvider.Current.AddService(Destinations()); + return true; + } + + public void Shutdown() + { + LOG.Debug("Office Plugin shutdown."); + } + + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/GreenshotOfficePlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs similarity index 97% rename from GreenshotOfficePlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs index 3e2563a07..a65ac387f 100644 --- a/GreenshotOfficePlugin/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs @@ -29,4 +29,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs b/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs similarity index 76% rename from GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs rename to src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs index 70971ca61..99f8150b0 100644 --- a/GreenshotPhotobucketPlugin/Forms/PhotobucketForm.cs +++ b/src/Greenshot.Plugin.Photobucket/Forms/PhotobucketForm.cs @@ -19,10 +19,14 @@ * along with this program. If not, see . */ -namespace GreenshotPhotobucketPlugin.Forms { - /// - /// This class is needed for design-time resolving of the language files - /// - public class PhotobucketForm : GreenshotPlugin.Controls.GreenshotForm { - } -} +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.Photobucket.Forms +{ + /// + /// This class is needed for design-time resolving of the language files + /// + public class PhotobucketForm : GreenshotForm + { + } +} \ No newline at end of file diff --git a/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs similarity index 84% rename from GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs rename to src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs index 4a0486dd1..5e1910690 100644 --- a/GreenshotPhotobucketPlugin/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs @@ -18,7 +18,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -namespace GreenshotPhotobucketPlugin.Forms { + +using Greenshot.Base.Controls; + +namespace Greenshot.Plugin.Photobucket.Forms { partial class SettingsForm { /// /// Designer variable used to keep track of non-visual components. @@ -46,11 +49,11 @@ namespace GreenshotPhotobucketPlugin.Forms { /// private void InitializeComponent() { - this.buttonOK = new GreenshotPlugin.Controls.GreenshotButton(); - this.buttonCancel = new GreenshotPlugin.Controls.GreenshotButton(); - this.combobox_uploadimageformat = new GreenshotPlugin.Controls.GreenshotComboBox(); - this.label_upload_format = new GreenshotPlugin.Controls.GreenshotLabel(); - this.checkbox_usepagelink = new GreenshotPlugin.Controls.GreenshotCheckBox(); + this.buttonOK = new GreenshotButton(); + this.buttonCancel = new GreenshotButton(); + this.combobox_uploadimageformat = new GreenshotComboBox(); + this.label_upload_format = new GreenshotLabel(); + this.checkbox_usepagelink = new GreenshotCheckBox(); this.SuspendLayout(); // // buttonOK @@ -124,10 +127,10 @@ namespace GreenshotPhotobucketPlugin.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotComboBox combobox_uploadimageformat; - private GreenshotPlugin.Controls.GreenshotLabel label_upload_format; - private GreenshotPlugin.Controls.GreenshotButton buttonCancel; - private GreenshotPlugin.Controls.GreenshotButton buttonOK; - private GreenshotPlugin.Controls.GreenshotCheckBox checkbox_usepagelink; + private GreenshotComboBox combobox_uploadimageformat; + private GreenshotLabel label_upload_format; + private GreenshotButton buttonCancel; + private GreenshotButton buttonOK; + private GreenshotCheckBox checkbox_usepagelink; } } diff --git a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs new file mode 100644 index 000000000..b6a51f8ae --- /dev/null +++ b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.cs @@ -0,0 +1,39 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Plugin.Photobucket.Forms +{ + /// + /// Description of PasswordRequestForm. + /// + public partial class SettingsForm : PhotobucketForm + { + public SettingsForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + AcceptButton = buttonOK; + CancelButton = buttonCancel; + } + } +} \ No newline at end of file diff --git a/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.Credentials.template similarity index 96% rename from GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template rename to src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.Credentials.template index 312099888..8895f5a73 100644 --- a/GreenshotPhotobucketPlugin/GreenshotPhotobucketPlugin.Credentials.template +++ b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.Credentials.template @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -namespace GreenshotPhotobucketPlugin { +namespace Greenshot.Plugin.Photobucket { /// /// This class is merely a placeholder for the file keeping the API key and secret for photobucket integration. /// You can set your own values here diff --git a/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj new file mode 100644 index 000000000..cc3d98fb9 --- /dev/null +++ b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj @@ -0,0 +1,11 @@ + + + + PreserveNewest + + + + + + + diff --git a/GreenshotConfluencePlugin/LanguageKeys.cs b/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs similarity index 81% rename from GreenshotConfluencePlugin/LanguageKeys.cs rename to src/Greenshot.Plugin.Photobucket/LanguageKeys.cs index 5ba0b2cbe..e9ac6058b 100644 --- a/GreenshotConfluencePlugin/LanguageKeys.cs +++ b/src/Greenshot.Plugin.Photobucket/LanguageKeys.cs @@ -19,10 +19,13 @@ * along with this program. If not, see . */ -namespace GreenshotConfluencePlugin { - public enum LangKey { - login_error, - upload_menu_item, - communication_wait - } -} +namespace Greenshot.Plugin.Photobucket +{ + public enum LangKey + { + upload_menu_item, + upload_failure, + communication_wait, + configure + } +} \ No newline at end of file diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-cs-CZ.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-cs-CZ.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-cs-CZ.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-cs-CZ.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-de-DE.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-de-DE.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-de-DE.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-de-DE.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-en-US.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-en-US.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-en-US.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-en-US.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-fr_FR.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-fr_FR.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-fr_FR.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-fr_FR.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-id-ID.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-id-ID.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-id-ID.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-id-ID.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-it-IT.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-it-IT.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-it-IT.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ja-JP.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ja-JP.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ja-JP.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ja-JP.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-kab-DZ.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-kab-DZ.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-kab-DZ.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-kab-DZ.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ko-KR.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ko-KR.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ko-KR.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ko-KR.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-lv-LV.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-lv-LV.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-lv-LV.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-lv-LV.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-nl-NL.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-nl-NL.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-nl-NL.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-nl-NL.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pl-PL.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-pl-PL.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pl-PL.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-pl-PL.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pt-PT.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-pt-PT.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-pt-PT.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-pt-PT.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ru-RU.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ru-RU.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-ru-RU.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-ru-RU.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-sv-SE.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-sv-SE.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-sv-SE.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-sv-SE.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-uk-UA.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-uk-UA.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-uk-UA.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-uk-UA.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-CN.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-zh-CN.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-CN.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-zh-CN.xml diff --git a/GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-TW.xml b/src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-zh-TW.xml similarity index 100% rename from GreenshotPhotobucketPlugin/Languages/language_photobucketplugin-zh-TW.xml rename to src/Greenshot.Plugin.Photobucket/Languages/language_photobucketplugin-zh-TW.xml diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs new file mode 100644 index 000000000..0600448f9 --- /dev/null +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketConfiguration.cs @@ -0,0 +1,80 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Plugin.Photobucket.Forms; + +namespace Greenshot.Plugin.Photobucket +{ + /// + /// Description of PhotobucketConfiguration. + /// + [IniSection("Photobucket", Description = "Greenshot Photobucket Plugin configuration")] + public class PhotobucketConfiguration : IniSection + { + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("UploadReduceColors", Description = "Reduce color amount of the uploaded image to 256", DefaultValue = "False")] + public bool UploadReduceColors { get; set; } + + [IniProperty("UsePageLink", Description = "Use pagelink instead of direct link on the clipboard", DefaultValue = "False")] + public bool UsePageLink { get; set; } + + [IniProperty("Token", Description = "The Photobucket token", Encrypted = true, ExcludeIfNull = true)] + public string Token { get; set; } + + [IniProperty("TokenSecret", Description = "The Photobucket token secret", Encrypted = true, ExcludeIfNull = true)] + public string TokenSecret { get; set; } + + [IniProperty("SubDomain", Description = "The Photobucket api subdomain", Encrypted = true, ExcludeIfNull = true)] + public string SubDomain { get; set; } + + [IniProperty("Username", Description = "The Photobucket api username", ExcludeIfNull = true)] + public string Username { get; set; } + + /// + /// A form for username/password + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + SettingsForm settingsForm = null; + + new PleaseWaitForm().ShowAndWait("Photobucket", Language.GetString("photobucket", LangKey.communication_wait), + delegate { settingsForm = new SettingsForm(); } + ); + DialogResult result = settingsForm.ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs new file mode 100644 index 000000000..2d10b0864 --- /dev/null +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketDestination.cs @@ -0,0 +1,119 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; + +namespace Greenshot.Plugin.Photobucket +{ + /// + /// Description of PhotobucketDestination. + /// + public class PhotobucketDestination : AbstractDestination + { + private readonly PhotobucketPlugin _plugin; + private readonly string _albumPath; + + /// + /// Create a Photobucket destination, which also has the path to the album in it + /// + /// + /// path to the album, null for default + public PhotobucketDestination(PhotobucketPlugin plugin, string albumPath = null) + { + _plugin = plugin; + _albumPath = albumPath; + } + + public override string Designation => "Photobucket"; + + public override string Description + { + get + { + if (_albumPath != null) + { + return _albumPath; + } + + return Language.GetString("photobucket", LangKey.upload_menu_item); + } + } + + public override Image DisplayIcon + { + get + { + ComponentResourceManager resources = new ComponentResourceManager(typeof(PhotobucketPlugin)); + return (Image) resources.GetObject("Photobucket"); + } + } + + public override bool IsDynamic => true; + + public override IEnumerable DynamicDestinations() + { + IList albums = null; + try + { + albums = PhotobucketUtils.RetrievePhotobucketAlbums(); + } + catch + { + // ignored + } + + if (albums == null || albums.Count == 0) + { + yield break; + } + + foreach (string album in albums) + { + yield return new PhotobucketDestination(_plugin, album); + } + } + + /// + /// Export the capture to Photobucket + /// + /// + /// + /// + /// + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + bool uploaded = _plugin.Upload(captureDetails, surface, _albumPath, out var uploadUrl); + if (uploaded) + { + exportInformation.ExportMade = true; + exportInformation.Uri = uploadUrl; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs new file mode 100644 index 000000000..7cb584b72 --- /dev/null +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketInfo.cs @@ -0,0 +1,79 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Xml; + +namespace Greenshot.Plugin.Photobucket +{ + /// + /// Description of PhotobucketInfo. + /// + public class PhotobucketInfo + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketInfo)); + + public string Original { get; set; } + + public string Page { get; set; } + + public string Thumbnail { get; set; } + + /// + /// Parse the upload response + /// + /// XML + /// PhotobucketInfo object + public static PhotobucketInfo FromUploadResponse(string response) + { + Log.Debug(response); + PhotobucketInfo photobucketInfo = new PhotobucketInfo(); + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(response); + var nodes = doc.GetElementsByTagName("url"); + if (nodes.Count > 0) + { + photobucketInfo.Original = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("browseurl"); + if (nodes.Count > 0) + { + photobucketInfo.Page = nodes.Item(0)?.InnerText; + } + + nodes = doc.GetElementsByTagName("thumb"); + if (nodes.Count > 0) + { + photobucketInfo.Thumbnail = nodes.Item(0)?.InnerText; + } + } + catch (Exception e) + { + Log.ErrorFormat("Could not parse Photobucket response due to error {0}, response was: {1}", e.Message, response); + } + + return photobucketInfo; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs new file mode 100644 index 000000000..fb86aeb93 --- /dev/null +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs @@ -0,0 +1,158 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Plugin.Photobucket +{ + /// + /// This is the GreenshotPhotobucketPlugin base code + /// + [Plugin("Photobucket", true)] + public class PhotobucketPlugin : IGreenshotPlugin + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketPlugin)); + private static PhotobucketConfiguration _config; + private ComponentResourceManager _resources; + private ToolStripMenuItem _itemPlugInConfig; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + if (!disposing) return; + if (_itemPlugInConfig == null) return; + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; + } + + /// + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// true if plugin is initialized, false if not (doesn't show) + public bool Initialize() + { + SimpleServiceProvider.Current.AddService(new PhotobucketDestination(this)); + + // Get configuration + _config = IniConfig.GetIniSection(); + _resources = new ComponentResourceManager(typeof(PhotobucketPlugin)); + + _itemPlugInConfig = new ToolStripMenuItem(Language.GetString("photobucket", LangKey.configure)) + { + Image = (Image) _resources.GetObject("Photobucket") + }; + _itemPlugInConfig.Click += delegate { _config.ShowConfigDialog(); }; + + PluginUtils.AddToContextMenu(_itemPlugInConfig); + Language.LanguageChanged += OnLanguageChanged; + return true; + } + + public void OnLanguageChanged(object sender, EventArgs e) + { + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Text = Language.GetString("photobucket", LangKey.configure); + } + } + + public void Shutdown() + { + Log.Debug("Photobucket Plugin shutdown."); + Language.LanguageChanged -= OnLanguageChanged; + } + + /// + /// Implementation of the IPlugin.Configure + /// + public void Configure() + { + _config.ShowConfigDialog(); + } + + /// + /// Upload the capture to Photobucket + /// + /// + /// ISurface + /// Path to the album + /// out string for the url + /// true if the upload succeeded + public bool Upload(ICaptureDetails captureDetails, ISurface surfaceToUpload, string albumPath, out string uploadUrl) + { + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(_config.UploadFormat, _config.UploadJpegQuality, _config.UploadReduceColors); + try + { + string filename = Path.GetFileName(FilenameHelper.GetFilename(_config.UploadFormat, captureDetails)); + PhotobucketInfo photobucketInfo = null; + + // Run upload in the background + new PleaseWaitForm().ShowAndWait("Photobucket", Language.GetString("photobucket", LangKey.communication_wait), + delegate { photobucketInfo = PhotobucketUtils.UploadToPhotobucket(surfaceToUpload, outputSettings, albumPath, captureDetails.Title, filename); } + ); + // This causes an exeption if the upload failed :) + Log.DebugFormat("Uploaded to Photobucket page: " + photobucketInfo.Page); + uploadUrl = null; + try + { + if (_config.UsePageLink) + { + uploadUrl = photobucketInfo.Page; + Clipboard.SetText(photobucketInfo.Page); + } + else + { + uploadUrl = photobucketInfo.Original; + Clipboard.SetText(photobucketInfo.Original); + } + } + catch (Exception ex) + { + Log.Error("Can't write to clipboard: ", ex); + } + + return true; + } + catch (Exception e) + { + Log.Error(e); + MessageBox.Show(Language.GetString("photobucket", LangKey.upload_failure) + " " + e.Message); + } + + uploadUrl = null; + return false; + } + } +} \ No newline at end of file diff --git a/GreenshotPhotobucketPlugin/PhotobucketPlugin.resx b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.resx similarity index 100% rename from GreenshotPhotobucketPlugin/PhotobucketPlugin.resx rename to src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.resx diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs new file mode 100644 index 000000000..c149f1cc0 --- /dev/null +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketUtils.cs @@ -0,0 +1,293 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Xml; +using Greenshot.Base.Core; +using Greenshot.Base.Core.OAuth; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Plugin.Photobucket +{ + /// + /// Description of PhotobucketUtils. + /// + public static class PhotobucketUtils + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketUtils)); + private static readonly PhotobucketConfiguration PhotobucketConfig = IniConfig.GetIniSection(); + private static List _albumsCache; + + /// + /// Do the actual upload to Photobucket + /// For more details on the available parameters, see: http://api.Photobucket.com/resources_anon + /// + /// PhotobucketResponse + public static PhotobucketInfo UploadToPhotobucket(ISurface surfaceToUpload, SurfaceOutputSettings outputSettings, string albumPath, string title, string filename) + { + string responseString; + + var oAuth = CreateSession(true); + if (oAuth == null) + { + return null; + } + + IDictionary signedParameters = new Dictionary(); + // add album + if (string.IsNullOrEmpty(albumPath)) + { + signedParameters.Add("id", string.IsNullOrEmpty(PhotobucketConfig.Username) ? "!" : PhotobucketConfig.Username); + } + else + { + signedParameters.Add("id", albumPath); + } + + // add type + signedParameters.Add("type", "image"); + // add title + if (title != null) + { + signedParameters.Add("title", title); + } + + // add filename + if (filename != null) + { + signedParameters.Add("filename", filename); + } + + IDictionary unsignedParameters = new Dictionary + { + // Add image + { + "uploadfile", new SurfaceContainer(surfaceToUpload, outputSettings, filename) + } + }; + try + { + string apiUrl = "http://api.photobucket.com/album/!/upload"; + responseString = oAuth.MakeOAuthRequest(HTTPMethod.POST, apiUrl, apiUrl.Replace("api.photobucket.com", PhotobucketConfig.SubDomain), signedParameters, + unsignedParameters, null); + } + catch (Exception ex) + { + Log.Error("Error uploading to Photobucket.", ex); + throw; + } + finally + { + if (!string.IsNullOrEmpty(oAuth.Token)) + { + PhotobucketConfig.Token = oAuth.Token; + } + + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) + { + PhotobucketConfig.TokenSecret = oAuth.TokenSecret; + } + } + + if (responseString == null) + { + return null; + } + + Log.Info(responseString); + var photobucketInfo = PhotobucketInfo.FromUploadResponse(responseString); + Log.Debug("Upload to Photobucket was finished"); + return photobucketInfo; + } + + /// + /// Helper method to create an OAuth session object for contacting the Photobucket API + /// + /// OAuthSession + private static OAuthSession CreateSession(bool autoLogin) + { + var oAuth = new OAuthSession(PhotobucketCredentials.ConsumerKey, PhotobucketCredentials.ConsumerSecret) + { + AutoLogin = autoLogin, + CheckVerifier = false, + CallbackUrl = "http://getgreenshot.org", + AccessTokenUrl = "http://api.photobucket.com/login/access", + AuthorizeUrl = "http://photobucket.com/apilogin/login", + RequestTokenUrl = "http://api.photobucket.com/login/request", + BrowserSize = new Size(1010, 400), + RequestTokenMethod = HTTPMethod.POST, + AccessTokenMethod = HTTPMethod.POST, + LoginTitle = "Photobucket authorization" + }; + // This url is configured in the Photobucket API settings in the Photobucket site!! + // Photobucket is very particular about the used methods! + + if (string.IsNullOrEmpty(PhotobucketConfig.SubDomain) || string.IsNullOrEmpty(PhotobucketConfig.Token) || string.IsNullOrEmpty(PhotobucketConfig.Username)) + { + if (!autoLogin) + { + return null; + } + + if (!oAuth.Authorize()) + { + return null; + } + + if (!string.IsNullOrEmpty(oAuth.Token)) + { + PhotobucketConfig.Token = oAuth.Token; + } + + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) + { + PhotobucketConfig.TokenSecret = oAuth.TokenSecret; + } + + if (oAuth.AccessTokenResponseParameters?["subdomain"] != null) + { + PhotobucketConfig.SubDomain = oAuth.AccessTokenResponseParameters["subdomain"]; + } + + if (oAuth.AccessTokenResponseParameters?["username"] != null) + { + PhotobucketConfig.Username = oAuth.AccessTokenResponseParameters["username"]; + } + + IniConfig.Save(); + } + + oAuth.Token = PhotobucketConfig.Token; + oAuth.TokenSecret = PhotobucketConfig.TokenSecret; + return oAuth; + } + + /// + /// Get list of photobucket albums + /// + /// List of string + public static IList RetrievePhotobucketAlbums() + { + if (_albumsCache != null) + { + return _albumsCache; + } + + string responseString; + + OAuthSession oAuth = CreateSession(false); + if (oAuth == null) + { + return null; + } + + IDictionary signedParameters = new Dictionary(); + try + { + string apiUrl = $"http://api.photobucket.com/album/{PhotobucketConfig.Username}"; + responseString = oAuth.MakeOAuthRequest(HTTPMethod.GET, apiUrl, apiUrl.Replace("api.photobucket.com", PhotobucketConfig.SubDomain), signedParameters, null, null); + } + catch (Exception ex) + { + Log.Error("Error uploading to Photobucket.", ex); + throw; + } + finally + { + if (!string.IsNullOrEmpty(oAuth.Token)) + { + PhotobucketConfig.Token = oAuth.Token; + } + + if (!string.IsNullOrEmpty(oAuth.TokenSecret)) + { + PhotobucketConfig.TokenSecret = oAuth.TokenSecret; + } + } + + if (responseString == null) + { + return null; + } + + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(responseString); + List albums = new List(); + var xmlNode = doc.GetElementsByTagName("content").Item(0); + if (xmlNode != null) + { + RecurseAlbums(albums, null, xmlNode.ChildNodes); + } + + Log.DebugFormat("Albums: {0}", string.Join(",", albums.ToArray())); + _albumsCache = albums; + return albums; + } + catch (Exception e) + { + Log.Error("Error while Reading albums: ", e); + } + + Log.Debug("Upload to Photobucket was finished"); + return null; + } + + /// + /// Parse the album nodes recursively + /// + /// + /// + /// + private static void RecurseAlbums(ICollection albums, string path, IEnumerable nodes) + { + foreach (XmlNode node in nodes) + { + if (node.Name != "album") + { + continue; + } + + if (node.Attributes != null) + { + string currentAlbum = node.Attributes["name"].Value; + string currentPath = currentAlbum; + if (!string.IsNullOrEmpty(path)) + { + currentPath = $"{path}/{currentAlbum}"; + } + + albums.Add(currentPath); + if (node.Attributes["subalbum_count"] != null && node.Attributes["subalbum_count"].Value != "0") + { + RecurseAlbums(albums, currentPath, node.ChildNodes); + } + } + } + } + } +} \ No newline at end of file diff --git a/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs similarity index 97% rename from GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs index 99952c5c0..470ed7174 100644 --- a/GreenshotPhotobucketPlugin/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs @@ -30,5 +30,4 @@ using System.Runtime.InteropServices; // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] - +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs new file mode 100644 index 000000000..9492a2dfa --- /dev/null +++ b/src/Greenshot.Plugin.Win10/Destinations/Win10OcrDestination.cs @@ -0,0 +1,98 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Threading.Tasks; +using Windows.Media.Ocr; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; + +namespace Greenshot.Plugin.Win10.Destinations +{ + /// + /// This uses the OcrEngine from Windows 10 to perform OCR on the captured image. + /// + public class Win10OcrDestination : AbstractDestination + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10OcrDestination)); + + public override string Designation { get; } = "Windows10OCR"; + public override string Description { get; } = "Windows 10 OCR"; + + /// + /// Icon for the OCR function, the icon was found via: http://help4windows.com/windows_8_imageres_dll.shtml + /// + public override Image DisplayIcon => PluginUtils.GetCachedExeIcon(FilenameHelper.FillCmdVariables(@"%windir%\system32\imageres.dll"), 97); + + /// + /// Constructor, this is only debug information + /// + public Win10OcrDestination() + { + var languages = OcrEngine.AvailableRecognizerLanguages; + foreach (var language in languages) + { + Log.DebugFormat("Found language {0} {1}", language.NativeName, language.LanguageTag); + } + } + + /// + /// Run the Windows 10 OCR engine to process the text on the captured image + /// + /// + /// + /// + /// ExportInformation + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + var exportInformation = new ExportInformation(Designation, Description); + try + { + // TODO: Check if the OcrInformation is for the selected surface... otherwise discard & do it again + var ocrInformation = captureDetails.OcrInformation; + if (captureDetails.OcrInformation == null) + { + var ocrProvider = SimpleServiceProvider.Current.GetInstance(); + ocrInformation = Task.Run(async () => await ocrProvider.DoOcrAsync(surface)).Result; + } + + // Check if we found text + if (!string.IsNullOrWhiteSpace(ocrInformation.Text)) + { + // Place the OCR text on the + ClipboardHelper.SetClipboardData(ocrInformation.Text); + } + + exportInformation.ExportMade = true; + } + catch (Exception ex) + { + exportInformation.ExportMade = false; + exportInformation.ErrorMessage = ex.Message; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs similarity index 92% rename from GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs rename to src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs index fb52ef925..b1be32d61 100644 --- a/GreenshotWin10Plugin/Destinations/Win10ShareDestination.cs +++ b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs @@ -29,15 +29,15 @@ using System.Windows.Interop; using System.Windows.Media; using Windows.Storage; using Windows.Storage.Streams; -using GreenshotPlugin.Core; -using GreenshotPlugin.Hooking; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Plugin; -using GreenshotWin10Plugin.Internal; -using GreenshotWin10Plugin.Native; +using Greenshot.Base.Core; +using Greenshot.Base.Hooking; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Win10.Internal; +using Greenshot.Plugin.Win10.Native; using Color = Windows.UI.Color; -namespace GreenshotWin10Plugin.Destinations +namespace Greenshot.Plugin.Win10.Destinations { /// /// This uses the Share from Windows 10 to make the capture available to apps. @@ -61,7 +61,7 @@ namespace GreenshotWin10Plugin.Destinations /// ISurface /// ICaptureDetails /// ExportInformation - public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { var exportInformation = new ExportInformation(Designation, Description); try @@ -88,13 +88,13 @@ namespace GreenshotWin10Plugin.Destinations // Wait for the focus to return, and depending on the state close the window! focusMonitor.WindowOpenCloseChangeEvent += e => { - if (e.IsOpen) { if ("Windows Shell Experience Host" == e.Title) { shareInfo.SharingHwnd = e.HWnd; } + return; } @@ -104,6 +104,7 @@ namespace GreenshotWin10Plugin.Destinations { return; } + shareInfo.ShareTask.TrySetResult(false); } }; @@ -130,8 +131,8 @@ namespace GreenshotWin10Plugin.Destinations ProcessExport(exportInformation, surface); return exportInformation; - } + /// /// Share the surface by using the Share-UI of Windows 10 /// @@ -191,8 +192,8 @@ namespace GreenshotWin10Plugin.Destinations var storageFile = await StorageFile.CreateStreamedFileAsync(filename, async streamedFileDataRequest => { shareInfo.IsDeferredFileCreated = true; - // Information on the "how" was found here: https://socialeboladev.wordpress.com/2013/03/15/how-to-use-createstreamedfileasync/ - Log.DebugFormat("Creating deferred file {0}", filename); + // Information on the "how" was found here: https://socialeboladev.wordpress.com/2013/03/15/how-to-use-createstreamedfileasync/ + Log.DebugFormat("Creating deferred file {0}", filename); try { using (var deferredStream = streamedFileDataRequest.AsStreamForWrite()) @@ -200,6 +201,7 @@ namespace GreenshotWin10Plugin.Destinations await imageStream.CopyToAsync(deferredStream).ConfigureAwait(false); await imageStream.FlushAsync().ConfigureAwait(false); } + // Signal that the stream is ready streamedFileDataRequest.Dispose(); // Signal that the action is ready, bitmap was exported @@ -245,7 +247,10 @@ namespace GreenshotWin10Plugin.Destinations dataPackage.Properties.Thumbnail = thumbnailRandomAccessStreamReference; dataPackage.Properties.Square30x30Logo = logoRandomAccessStreamReference; dataPackage.Properties.LogoBackgroundColor = Color.FromArgb(0xff, 0x3d, 0x3d, 0x3d); - dataPackage.SetStorageItems(new[] { storageFile }); + dataPackage.SetStorageItems(new[] + { + storageFile + }); dataPackage.SetBitmap(imageRandomAccessStreamReference); } finally @@ -259,4 +264,4 @@ namespace GreenshotWin10Plugin.Destinations await shareInfo.ShareTask.Task.ConfigureAwait(false); } } -} +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj similarity index 59% rename from GreenshotWin10Plugin/GreenshotWin10Plugin.csproj rename to src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj index 2c8237637..182da73b6 100644 --- a/GreenshotWin10Plugin/GreenshotWin10Plugin.csproj +++ b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj @@ -1,10 +1,4 @@  - - - GreenshotWin10Plugin - GreenshotWin10Plugin - - PreserveNewest @@ -15,6 +9,6 @@ - + diff --git a/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs b/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs similarity index 62% rename from GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs rename to src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs index e342f87ae..230c76ed7 100644 --- a/GreenshotWin10Plugin/Internal/MemoryRandomAccessStream.cs +++ b/src/Greenshot.Plugin.Win10/Internal/MemoryRandomAccessStream.cs @@ -22,72 +22,72 @@ using System.IO; using Windows.Storage.Streams; -namespace GreenshotWin10Plugin.Internal +namespace Greenshot.Plugin.Win10.Internal { /// /// This is an IRandomAccessStream implementation which uses a MemoryStream /// - internal sealed class MemoryRandomAccessStream : MemoryStream, IRandomAccessStream - { + internal sealed class MemoryRandomAccessStream : MemoryStream, IRandomAccessStream + { /// public IInputStream GetInputStreamAt(ulong position) - { - Seek((long)position, SeekOrigin.Begin); + { + Seek((long) position, SeekOrigin.Begin); - return this.AsInputStream(); - } + return this.AsInputStream(); + } /// public IOutputStream GetOutputStreamAt(ulong position) - { - Seek((long)position, SeekOrigin.Begin); + { + Seek((long) position, SeekOrigin.Begin); - return this.AsOutputStream(); - } + return this.AsOutputStream(); + } /// - ulong IRandomAccessStream.Position => (ulong)Position; + ulong IRandomAccessStream.Position => (ulong) Position; /// public ulong Size - { - get { return (ulong)Length; } - set { SetLength((long)value); } - } + { + get { return (ulong) Length; } + set { SetLength((long) value); } + } /// public IRandomAccessStream CloneStream() - { - var cloned = new MemoryRandomAccessStream(); - CopyTo(cloned); - return cloned; - } + { + var cloned = new MemoryRandomAccessStream(); + CopyTo(cloned); + return cloned; + } /// public void Seek(ulong position) - { - Seek((long)position, SeekOrigin.Begin); - } + { + Seek((long) position, SeekOrigin.Begin); + } /// public Windows.Foundation.IAsyncOperationWithProgress ReadAsync(IBuffer buffer, uint count, InputStreamOptions options) - { - var inputStream = GetInputStreamAt(0); - return inputStream.ReadAsync(buffer, count, options); - } + { + var inputStream = GetInputStreamAt(0); + return inputStream.ReadAsync(buffer, count, options); + } /// Windows.Foundation.IAsyncOperation IOutputStream.FlushAsync() - { - var outputStream = GetOutputStreamAt(0); - return outputStream.FlushAsync(); - } + { + var outputStream = GetOutputStreamAt(0); + return outputStream.FlushAsync(); + } /// public Windows.Foundation.IAsyncOperationWithProgress WriteAsync(IBuffer buffer) - { - var outputStream = GetOutputStreamAt(0); - return outputStream.WriteAsync(buffer); - } - } -} + { + var outputStream = GetOutputStreamAt(0); + return outputStream.WriteAsync(buffer); + } + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Internal/ShareInfo.cs b/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs similarity index 97% rename from GreenshotWin10Plugin/Internal/ShareInfo.cs rename to src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs index 7516de371..f28370e06 100644 --- a/GreenshotWin10Plugin/Internal/ShareInfo.cs +++ b/src/Greenshot.Plugin.Win10/Internal/ShareInfo.cs @@ -23,7 +23,7 @@ using System; using System.Threading.Tasks; using Windows.ApplicationModel.DataTransfer; -namespace GreenshotWin10Plugin.Internal +namespace Greenshot.Plugin.Win10.Internal { internal class ShareInfo { @@ -40,4 +40,4 @@ namespace GreenshotWin10Plugin.Internal public IntPtr SharingHwnd { get; set; } } -} +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs new file mode 100644 index 000000000..15b70639f --- /dev/null +++ b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs @@ -0,0 +1,84 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2015 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.ApplicationModel.DataTransfer; +using Greenshot.Base.Core; + +namespace Greenshot.Plugin.Win10.Native +{ + /// + /// Wraps the interop for calling the ShareUI + /// + public class DataTransferManagerHelper + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DataTransferManagerHelper)); + + private const string DataTransferManagerId = "a5caee9b-8708-49d1-8d36-67d25a8da00c"; + private readonly IDataTransferManagerInterOp _dataTransferManagerInterOp; + private readonly IntPtr _windowHandle; + + /// + /// The DataTransferManager + /// + public DataTransferManager DataTransferManager { get; private set; } + + /// + /// Constructor which takes a handle to initialize + /// + /// + public DataTransferManagerHelper(IntPtr handle) + { + //TODO: Add a check for failure here. This will fail for versions of Windows below Windows 10 + IActivationFactory activationFactory = WindowsRuntimeMarshal.GetActivationFactory(typeof(DataTransferManager)); + + // ReSharper disable once SuspiciousTypeConversion.Global + _dataTransferManagerInterOp = (IDataTransferManagerInterOp) activationFactory; + + _windowHandle = handle; + var riid = new Guid(DataTransferManagerId); + var hresult = _dataTransferManagerInterOp.GetForWindow(_windowHandle, riid, out var dataTransferManager); + if (hresult.Failed()) + { + Log.WarnFormat("HResult for GetForWindow: {0}", hresult); + } + + DataTransferManager = dataTransferManager; + } + + /// + /// Show the share UI + /// + public void ShowShareUi() + { + var hresult = _dataTransferManagerInterOp.ShowShareUIForWindow(_windowHandle); + if (hresult.Failed()) + { + Log.WarnFormat("HResult for ShowShareUIForWindow: {0}", hresult); + } + else + { + Log.Debug("ShowShareUIForWindow called"); + } + } + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs similarity index 54% rename from GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs rename to src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs index 14fb4c8eb..1cdfa14de 100644 --- a/GreenshotWin10Plugin/Native/IDataTransferManagerInterOp.cs +++ b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs @@ -17,12 +17,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using GreenshotPlugin.Core.Enums; using System; using System.Runtime.InteropServices; using Windows.ApplicationModel.DataTransfer; +using Greenshot.Base.Core.Enums; -namespace GreenshotWin10Plugin.Native +namespace Greenshot.Plugin.Win10.Native { /// /// The IDataTransferManagerInterOp is documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/jj542488(v=vs.85).aspx. @@ -30,27 +30,26 @@ namespace GreenshotWin10Plugin.Native /// window using a window handle. Useful for Win32 apps. /// [ComImport, Guid("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IDataTransferManagerInterOp - { - /// - /// Get an instance of Windows.ApplicationModel.DataTransfer.DataTransferManager - /// for the window identified by a window handle - /// - /// The window handle - /// ID of the DataTransferManager interface - /// The DataTransferManager instance for this window handle - /// HRESULT - [PreserveSig] - HResult GetForWindow([In] IntPtr appWindow, [In] ref Guid riid, [Out] out DataTransferManager pDataTransferManager); + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IDataTransferManagerInterOp + { + /// + /// Get an instance of Windows.ApplicationModel.DataTransfer.DataTransferManager + /// for the window identified by a window handle + /// + /// The window handle + /// ID of the DataTransferManager interface + /// The DataTransferManager instance for this window handle + /// HRESULT + [PreserveSig] + HResult GetForWindow([In] IntPtr appWindow, [In] ref Guid riid, [Out] out DataTransferManager pDataTransferManager); - /// - /// Show the share flyout for the window identified by a window handle - /// - /// The window handle - /// HRESULT - [PreserveSig] - HResult ShowShareUIForWindow(IntPtr appWindow); - } - -} + /// + /// Show the share flyout for the window identified by a window handle + /// + /// The window handle + /// HRESULT + [PreserveSig] + HResult ShowShareUIForWindow(IntPtr appWindow); + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs b/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs similarity index 85% rename from GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs rename to src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs index 341153eab..45f511d93 100644 --- a/GreenshotWin10Plugin/Processors/Win10OcrProcessor.cs +++ b/src/Greenshot.Plugin.Win10/Processors/Win10OcrProcessor.cs @@ -20,16 +20,18 @@ */ using System.Threading.Tasks; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; -namespace GreenshotWin10Plugin.Processors { - /// - /// This processor processes a capture to see if there is text on it - /// - public class Win10OcrProcessor : AbstractProcessor { +namespace Greenshot.Plugin.Win10.Processors +{ + /// + /// This processor processes a capture to see if there is text on it + /// + public class Win10OcrProcessor : AbstractProcessor + { private static readonly Win10Configuration Win10Configuration = IniConfig.GetIniSection(); public override string Designation => "Windows10OcrProcessor"; @@ -46,10 +48,12 @@ namespace GreenshotWin10Plugin.Processors { { return false; } + if (captureDetails == null || captureDetails.OcrInformation != null) { return false; } + var ocrProvider = SimpleServiceProvider.Current.GetInstance(); if (ocrProvider == null) @@ -68,5 +72,5 @@ namespace GreenshotWin10Plugin.Processors { return true; } - } -} + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs similarity index 90% rename from GreenshotWin10Plugin/Properties/AssemblyInfo.cs rename to src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs index 7c2dc1d2c..d1b6cbd1b 100644 --- a/GreenshotWin10Plugin/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs @@ -12,4 +12,4 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("9801f62c-540f-4bfe-9211-6405dede563b")] +[assembly: Guid("9801f62c-540f-4bfe-9211-6405dede563b")] \ No newline at end of file diff --git a/GreenshotWin10Plugin/ToastNotificationService.cs b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs similarity index 96% rename from GreenshotWin10Plugin/ToastNotificationService.cs rename to src/Greenshot.Plugin.Win10/ToastNotificationService.cs index e7c932ab7..1da804c7a 100644 --- a/GreenshotWin10Plugin/ToastNotificationService.cs +++ b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs @@ -25,13 +25,13 @@ using System.IO; using Windows.Foundation.Collections; using Windows.Foundation.Metadata; using Windows.UI.Notifications; -using GreenshotPlugin.Core; -using GreenshotPlugin.IniFile; -using GreenshotPlugin.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; using log4net; using Microsoft.Toolkit.Uwp.Notifications; -namespace GreenshotWin10Plugin +namespace Greenshot.Plugin.Win10 { /// /// This service provides a way to inform (notify) the user. @@ -42,12 +42,14 @@ namespace GreenshotWin10Plugin private static readonly CoreConfiguration CoreConfiguration = IniConfig.GetIniSection(); private readonly string _imageFilePath; + public ToastNotificationService() { if (ToastNotificationManagerCompat.WasCurrentProcessToastActivated()) { Log.Info("Greenshot was activated due to a toast."); } + // Listen to notification activation ToastNotificationManagerCompat.OnActivated += toastArgs => { @@ -65,6 +67,7 @@ namespace GreenshotWin10Plugin { Directory.CreateDirectory(localAppData); } + _imageFilePath = Path.Combine(localAppData, "greenshot.png"); if (File.Exists(_imageFilePath)) @@ -90,6 +93,7 @@ namespace GreenshotWin10Plugin { return; } + // Prepare the toast notifier. Be sure to specify the AppUserModelId on your application's shortcut! var toastNotifier = ToastNotificationManagerCompat.CreateToastNotifier(); @@ -109,7 +113,6 @@ namespace GreenshotWin10Plugin // Generate the toast and send it off new ToastContentBuilder() - .AddArgument("ToastID", 100) // Inline image .AddText(message) @@ -119,6 +122,7 @@ namespace GreenshotWin10Plugin { // Windows 10 first with 1903: ExpiresOnReboot = true toast.ExpirationTime = timeout.HasValue ? DateTimeOffset.Now.Add(timeout.Value) : (DateTimeOffset?) null; + void ToastActivatedHandler(ToastNotification toastNotification, object sender) { try @@ -145,6 +149,7 @@ namespace GreenshotWin10Plugin { return; } + try { onClosedAction?.Invoke(); @@ -158,8 +163,8 @@ namespace GreenshotWin10Plugin // Remove the other handler too toast.Activated -= ToastActivatedHandler; toast.Failed -= ToastOnFailed; - } + toast.Dismissed += ToastDismissedHandler; toast.Failed += ToastOnFailed; }); @@ -196,9 +201,10 @@ namespace GreenshotWin10Plugin { return new ToastNotificationService(); } + Log.Warn("ToastNotificationActionTrigger not available."); return null; } } -} +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Win10Configuration.cs b/src/Greenshot.Plugin.Win10/Win10Configuration.cs similarity index 65% rename from GreenshotWin10Plugin/Win10Configuration.cs rename to src/Greenshot.Plugin.Win10/Win10Configuration.cs index ba3091909..acd1238ea 100644 --- a/GreenshotWin10Plugin/Win10Configuration.cs +++ b/src/Greenshot.Plugin.Win10/Win10Configuration.cs @@ -19,16 +19,17 @@ * along with this program. If not, see . */ -using GreenshotPlugin.IniFile; +using Greenshot.Base.IniFile; -namespace GreenshotWin10Plugin +namespace Greenshot.Plugin.Win10 { - /// - /// Description of Win10Configuration. - /// - [IniSection("Win10", Description = "Greenshot Win10 Plugin configuration")] - public class Win10Configuration : IniSection { - [IniProperty("AlwaysRunOCROnCapture", Description="Determines if OCR is run automatically on every capture", DefaultValue="False")] - public bool AlwaysRunOCROnCapture { get; set; } - } -} + /// + /// Description of Win10Configuration. + /// + [IniSection("Win10", Description = "Greenshot Win10 Plugin configuration")] + public class Win10Configuration : IniSection + { + [IniProperty("AlwaysRunOCROnCapture", Description = "Determines if OCR is run automatically on every capture", DefaultValue = "False")] + public bool AlwaysRunOCROnCapture { get; set; } + } +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Win10OcrProvider.cs b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs similarity index 63% rename from GreenshotWin10Plugin/Win10OcrProvider.cs rename to src/Greenshot.Plugin.Win10/Win10OcrProvider.cs index 81fd442e8..7611499f2 100644 --- a/GreenshotWin10Plugin/Win10OcrProvider.cs +++ b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs @@ -26,31 +26,31 @@ using System.Threading.Tasks; using Windows.Graphics.Imaging; using Windows.Media.Ocr; using Windows.Storage.Streams; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; -using GreenshotPlugin.Interfaces.Plugin; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; +using Greenshot.Base.Interfaces.Plugin; -namespace GreenshotWin10Plugin +namespace Greenshot.Plugin.Win10 { - /// - /// This uses the OcrEngine from Windows 10 to perform OCR on the captured image. - /// - public class Win10OcrProvider : IOcrProvider - { - private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10OcrProvider)); + /// + /// This uses the OcrEngine from Windows 10 to perform OCR on the captured image. + /// + public class Win10OcrProvider : IOcrProvider + { + private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10OcrProvider)); - /// - /// Constructor, this is only debug information - /// - public Win10OcrProvider() - { - var languages = OcrEngine.AvailableRecognizerLanguages; - foreach (var language in languages) - { - Log.DebugFormat("Found language {0} {1}", language.NativeName, language.LanguageTag); - } - } + /// + /// Constructor, this is only debug information + /// + public Win10OcrProvider() + { + var languages = OcrEngine.AvailableRecognizerLanguages; + foreach (var language in languages) + { + Log.DebugFormat("Found language {0} {1}", language.NativeName, language.LanguageTag); + } + } /// /// Scan the surface bitmap for text, and get the OcrResult @@ -68,15 +68,16 @@ namespace GreenshotWin10Plugin result = await DoOcrAsync(randomAccessStream); } + return result; } - /// - /// Scan the Image for text, and get the OcrResult - /// - /// Image - /// OcrResult sync - public async Task DoOcrAsync(Image image) + /// + /// Scan the Image for text, and get the OcrResult + /// + /// Image + /// OcrResult sync + public async Task DoOcrAsync(Image image) { OcrInformation result; using (var imageStream = new MemoryStream()) @@ -86,29 +87,31 @@ namespace GreenshotWin10Plugin var randomAccessStream = imageStream.AsRandomAccessStream(); result = await DoOcrAsync(randomAccessStream); - } - return result; + } + + return result; } - /// - /// Scan the surface bitmap for text, and get the OcrResult - /// - /// IRandomAccessStream - /// OcrResult sync - public async Task DoOcrAsync(IRandomAccessStream randomAccessStream) + /// + /// Scan the surface bitmap for text, and get the OcrResult + /// + /// IRandomAccessStream + /// OcrResult sync + public async Task DoOcrAsync(IRandomAccessStream randomAccessStream) { var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages(); if (ocrEngine is null) { return null; } - var decoder = await BitmapDecoder.CreateAsync(randomAccessStream); - var softwareBitmap = await decoder.GetSoftwareBitmapAsync(); - var ocrResult = await ocrEngine.RecognizeAsync(softwareBitmap); + var decoder = await BitmapDecoder.CreateAsync(randomAccessStream); + var softwareBitmap = await decoder.GetSoftwareBitmapAsync(); + + var ocrResult = await ocrEngine.RecognizeAsync(softwareBitmap); return CreateOcrInformation(ocrResult); - } + } /// /// Create the OcrInformation @@ -131,8 +134,8 @@ namespace GreenshotWin10Plugin for (var index = 0; index < ocrLine.Words.Count; index++) { var ocrWord = ocrLine.Words[index]; - var location = new Rectangle((int)ocrWord.BoundingRect.X, (int)ocrWord.BoundingRect.Y, - (int)ocrWord.BoundingRect.Width, (int)ocrWord.BoundingRect.Height); + var location = new Rectangle((int) ocrWord.BoundingRect.X, (int) ocrWord.BoundingRect.Y, + (int) ocrWord.BoundingRect.Width, (int) ocrWord.BoundingRect.Height); var word = line.Words[index]; word.Text = ocrWord.Text; @@ -143,4 +146,4 @@ namespace GreenshotWin10Plugin return result; } } -} +} \ No newline at end of file diff --git a/GreenshotWin10Plugin/Win10Plugin.cs b/src/Greenshot.Plugin.Win10/Win10Plugin.cs similarity index 54% rename from GreenshotWin10Plugin/Win10Plugin.cs rename to src/Greenshot.Plugin.Win10/Win10Plugin.cs index dc5190bbe..aa3342ead 100644 --- a/GreenshotWin10Plugin/Win10Plugin.cs +++ b/src/Greenshot.Plugin.Win10/Win10Plugin.cs @@ -20,62 +20,61 @@ */ using System; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces; -using GreenshotPlugin.Interfaces.Ocr; -using GreenshotPlugin.Interfaces.Plugin; -using GreenshotWin10Plugin.Destinations; -using GreenshotWin10Plugin.Processors; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Plugin.Win10.Destinations; +using Greenshot.Plugin.Win10.Processors; -namespace GreenshotWin10Plugin +namespace Greenshot.Plugin.Win10 { - /// - /// This is the Win10Plugin - /// - [Plugin("Win10", false)] - public sealed class Win10Plugin : IGreenshotPlugin - { + /// + /// This is the Win10Plugin + /// + [Plugin("Win10", false)] + public sealed class Win10Plugin : IGreenshotPlugin + { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10Plugin)); public void Dispose() - { - // Nothing to dispose - } + { + // Nothing to dispose + } public void Configure() - { - throw new NotImplementedException(); - } + { + throw new NotImplementedException(); + } /// - /// Implementation of the IGreenshotPlugin.Initialize - /// - /// true if plugin is initialized, false if not (doesn't show) - public bool Initialize() - { - // Here we check if the build version of Windows is actually what we support + /// Implementation of the IGreenshotPlugin.Initialize + /// + /// true if plugin is initialized, false if not (doesn't show) + public bool Initialize() + { + // Here we check if the build version of Windows is actually what we support if (!WindowsVersion.IsWindows10BuildOrLater(17763)) { - Log.WarnFormat("No support for Windows build {0}", WindowsVersion.BuildVersion); + Log.WarnFormat("No support for Windows build {0}", WindowsVersion.BuildVersion); return false; } SimpleServiceProvider.Current.AddService(ToastNotificationService.Create()); - // Set this as IOcrProvider - SimpleServiceProvider.Current.AddService(new Win10OcrProvider()); + // Set this as IOcrProvider + SimpleServiceProvider.Current.AddService(new Win10OcrProvider()); // Add the processor SimpleServiceProvider.Current.AddService(new Win10OcrProcessor()); // Add the destinations - SimpleServiceProvider.Current.AddService(new Win10OcrDestination()); + SimpleServiceProvider.Current.AddService(new Win10OcrDestination()); SimpleServiceProvider.Current.AddService(new Win10ShareDestination()); - return true; - } + return true; + } - public void Shutdown() - { - // Nothing to shutdown - } - } - -} + public void Shutdown() + { + // Nothing to shutdown + } + } +} \ No newline at end of file diff --git a/Greenshot.sln b/src/Greenshot.sln similarity index 82% rename from Greenshot.sln rename to src/Greenshot.sln index f815631e2..daabf8cf2 100644 --- a/Greenshot.sln +++ b/src/Greenshot.sln @@ -1,170 +1,170 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29728.190 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Greenshot.csproj", "{CD642BF4-D815-4D67-A0B5-C69F0B8231AF}" - ProjectSection(ProjectDependencies) = postProject - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} = {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} - {19FEEF09-313F-43C7-819D-F1BCA782B08B} = {19FEEF09-313F-43C7-819D-F1BCA782B08B} - {9801F62C-540F-4BFE-9211-6405DEDE563B} = {9801F62C-540F-4BFE-9211-6405DEDE563B} - {9C0ECC4C-7807-4111-916A-4F57BB29788A} = {9C0ECC4C-7807-4111-916A-4F57BB29788A} - {C3052651-598A-44E2-AAB3-2E41311D50F9} = {C3052651-598A-44E2-AAB3-2E41311D50F9} - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} = {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} - {697CF066-9077-4F22-99D9-D989CCE7282B} = {697CF066-9077-4F22-99D9-D989CCE7282B} - {47F23C86-604E-4CC3-8767-B3D4088F30BB} = {47F23C86-604E-4CC3-8767-B3D4088F30BB} - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} = {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} = {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} - {1893A2E4-A78A-4713-A8E7-E70058DABEE0} = {1893A2E4-A78A-4713-A8E7-E70058DABEE0} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPlugin", "GreenshotPlugin\GreenshotPlugin.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotExternalCommandPlugin", "GreenshotExternalCommandPlugin\GreenshotExternalCommandPlugin.csproj", "{47F23C86-604E-4CC3-8767-B3D4088F30BB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotConfluencePlugin", "GreenshotConfluencePlugin\GreenshotConfluencePlugin.csproj", "{C3052651-598A-44E2-AAB3-2E41311D50F9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotImgurPlugin", "GreenshotImgurPlugin\GreenshotImgurPlugin.csproj", "{80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotJiraPlugin", "GreenshotJiraPlugin\GreenshotJiraPlugin.csproj", "{19FEEF09-313F-43C7-819D-F1BCA782B08B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotBoxPlugin", "GreenshotBoxPlugin\GreenshotBoxPlugin.csproj", "{697CF066-9077-4F22-99D9-D989CCE7282B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotDropboxPlugin", "GreenshotDropboxPlugin\GreenshotDropboxPlugin.csproj", "{AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotFlickrPlugin", "GreenshotFlickrPlugin\GreenshotFlickrPlugin.csproj", "{7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotGooglePhotosPlugin", "GreenshotGooglePhotosPlugin\GreenshotGooglePhotosPlugin.csproj", "{1893A2E4-A78A-4713-A8E7-E70058DABEE0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotOfficePlugin", "GreenshotOfficePlugin\GreenshotOfficePlugin.csproj", "{92599C09-FF29-4ABD-B6E6-C48ECD781BAB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotPhotobucketPlugin", "GreenshotPhotobucketPlugin\GreenshotPhotobucketPlugin.csproj", "{9C0ECC4C-7807-4111-916A-4F57BB29788A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GreenshotWin10Plugin", "GreenshotWin10Plugin\GreenshotWin10Plugin.csproj", "{9801F62C-540F-4BFE-9211-6405DEDE563B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{82987F1E-D7E6-4C44-B934-981D366E4672}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - azure-pipelines.yml = azure-pipelines.yml - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|x86.ActiveCfg = Debug|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|x86.Build.0 = Debug|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Any CPU.Build.0 = Release|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|x86.ActiveCfg = Release|Any CPU - {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|x86.Build.0 = Release|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.ActiveCfg = Debug|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.Build.0 = Debug|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Any CPU.Build.0 = Release|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.ActiveCfg = Release|Any CPU - {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.Build.0 = Release|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.ActiveCfg = Debug|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.Build.0 = Debug|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.Build.0 = Release|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.ActiveCfg = Release|Any CPU - {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.Build.0 = Release|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.ActiveCfg = Debug|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.Build.0 = Debug|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.Build.0 = Release|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.ActiveCfg = Release|Any CPU - {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.Build.0 = Release|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.Build.0 = Debug|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.ActiveCfg = Debug|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.Build.0 = Debug|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.ActiveCfg = Release|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.Build.0 = Release|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.ActiveCfg = Release|Any CPU - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.Build.0 = Release|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.ActiveCfg = Debug|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.Build.0 = Debug|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.Build.0 = Release|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.ActiveCfg = Release|Any CPU - {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.Build.0 = Release|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.ActiveCfg = Debug|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.Build.0 = Debug|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Any CPU.Build.0 = Release|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|x86.ActiveCfg = Release|Any CPU - {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|x86.Build.0 = Release|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|x86.ActiveCfg = Debug|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|x86.Build.0 = Debug|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Any CPU.Build.0 = Release|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|x86.ActiveCfg = Release|Any CPU - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|x86.Build.0 = Release|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|x86.ActiveCfg = Debug|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|x86.Build.0 = Debug|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Any CPU.Build.0 = Release|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|x86.ActiveCfg = Release|Any CPU - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|x86.Build.0 = Release|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|x86.ActiveCfg = Debug|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|x86.Build.0 = Debug|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Any CPU.Build.0 = Release|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|x86.ActiveCfg = Release|Any CPU - {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|x86.Build.0 = Release|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|x86.ActiveCfg = Debug|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|x86.Build.0 = Debug|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Any CPU.Build.0 = Release|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|x86.ActiveCfg = Release|Any CPU - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|x86.Build.0 = Release|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|x86.ActiveCfg = Debug|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|x86.Build.0 = Debug|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Any CPU.Build.0 = Release|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|x86.ActiveCfg = Release|Any CPU - {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|x86.Build.0 = Release|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|x86.ActiveCfg = Debug|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|x86.Build.0 = Debug|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Any CPU.Build.0 = Release|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|x86.ActiveCfg = Release|Any CPU - {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {970967C0-60BE-4F70-9332-9ACC04B93A15} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29728.190 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Greenshot.csproj", "{CD642BF4-D815-4D67-A0B5-C69F0B8231AF}" + ProjectSection(ProjectDependencies) = postProject + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} = {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} + {19FEEF09-313F-43C7-819D-F1BCA782B08B} = {19FEEF09-313F-43C7-819D-F1BCA782B08B} + {9801F62C-540F-4BFE-9211-6405DEDE563B} = {9801F62C-540F-4BFE-9211-6405DEDE563B} + {9C0ECC4C-7807-4111-916A-4F57BB29788A} = {9C0ECC4C-7807-4111-916A-4F57BB29788A} + {C3052651-598A-44E2-AAB3-2E41311D50F9} = {C3052651-598A-44E2-AAB3-2E41311D50F9} + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} = {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} + {697CF066-9077-4F22-99D9-D989CCE7282B} = {697CF066-9077-4F22-99D9-D989CCE7282B} + {47F23C86-604E-4CC3-8767-B3D4088F30BB} = {47F23C86-604E-4CC3-8767-B3D4088F30BB} + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} = {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} = {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} + {1893A2E4-A78A-4713-A8E7-E70058DABEE0} = {1893A2E4-A78A-4713-A8E7-E70058DABEE0} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Base", "Greenshot.Base\Greenshot.Base.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.ExternalCommand", "Greenshot.Plugin.ExternalCommand\Greenshot.Plugin.ExternalCommand.csproj", "{47F23C86-604E-4CC3-8767-B3D4088F30BB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Confluence", "Greenshot.Plugin.Confluence\Greenshot.Plugin.Confluence.csproj", "{C3052651-598A-44E2-AAB3-2E41311D50F9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Imgur", "Greenshot.Plugin.Imgur\Greenshot.Plugin.Imgur.csproj", "{80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Jira", "Greenshot.Plugin.Jira\Greenshot.Plugin.Jira.csproj", "{19FEEF09-313F-43C7-819D-F1BCA782B08B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Box", "Greenshot.Plugin.Box\Greenshot.Plugin.Box.csproj", "{697CF066-9077-4F22-99D9-D989CCE7282B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Dropbox", "Greenshot.Plugin.Dropbox\Greenshot.Plugin.Dropbox.csproj", "{AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Flickr", "Greenshot.Plugin.Flickr\Greenshot.Plugin.Flickr.csproj", "{7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.GooglePhotos", "Greenshot.Plugin.GooglePhotos\Greenshot.Plugin.GooglePhotos.csproj", "{1893A2E4-A78A-4713-A8E7-E70058DABEE0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Office", "Greenshot.Plugin.Office\Greenshot.Plugin.Office.csproj", "{92599C09-FF29-4ABD-B6E6-C48ECD781BAB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Photobucket", "Greenshot.Plugin.Photobucket\Greenshot.Plugin.Photobucket.csproj", "{9C0ECC4C-7807-4111-916A-4F57BB29788A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Plugin.Win10", "Greenshot.Plugin.Win10\Greenshot.Plugin.Win10.csproj", "{9801F62C-540F-4BFE-9211-6405DEDE563B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{82987F1E-D7E6-4C44-B934-981D366E4672}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + azure-pipelines.yml = azure-pipelines.yml + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|x86.ActiveCfg = Debug|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Debug|x86.Build.0 = Debug|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|Any CPU.Build.0 = Release|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|x86.ActiveCfg = Release|Any CPU + {CD642BF4-D815-4D67-A0B5-C69F0B8231AF}.Release|x86.Build.0 = Release|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.ActiveCfg = Debug|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Debug|x86.Build.0 = Debug|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|Any CPU.Build.0 = Release|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.ActiveCfg = Release|Any CPU + {5B924697-4DCD-4F98-85F1-105CB84B7341}.Release|x86.Build.0 = Release|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.ActiveCfg = Debug|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Debug|x86.Build.0 = Debug|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|Any CPU.Build.0 = Release|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.ActiveCfg = Release|Any CPU + {47F23C86-604E-4CC3-8767-B3D4088F30BB}.Release|x86.Build.0 = Release|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.ActiveCfg = Debug|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Debug|x86.Build.0 = Debug|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|Any CPU.Build.0 = Release|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.ActiveCfg = Release|Any CPU + {C3052651-598A-44E2-AAB3-2E41311D50F9}.Release|x86.Build.0 = Release|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.ActiveCfg = Debug|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Debug|x86.Build.0 = Debug|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.ActiveCfg = Release|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|Any CPU.Build.0 = Release|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.ActiveCfg = Release|Any CPU + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50}.Release|x86.Build.0 = Release|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.ActiveCfg = Debug|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Debug|x86.Build.0 = Debug|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|Any CPU.Build.0 = Release|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.ActiveCfg = Release|Any CPU + {19FEEF09-313F-43C7-819D-F1BCA782B08B}.Release|x86.Build.0 = Release|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.ActiveCfg = Debug|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Debug|x86.Build.0 = Debug|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|Any CPU.Build.0 = Release|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|x86.ActiveCfg = Release|Any CPU + {697CF066-9077-4F22-99D9-D989CCE7282B}.Release|x86.Build.0 = Release|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|x86.ActiveCfg = Debug|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Debug|x86.Build.0 = Debug|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|Any CPU.Build.0 = Release|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|x86.ActiveCfg = Release|Any CPU + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12}.Release|x86.Build.0 = Release|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|x86.ActiveCfg = Debug|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Debug|x86.Build.0 = Debug|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|Any CPU.Build.0 = Release|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|x86.ActiveCfg = Release|Any CPU + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E}.Release|x86.Build.0 = Release|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|x86.ActiveCfg = Debug|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Debug|x86.Build.0 = Debug|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|Any CPU.Build.0 = Release|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|x86.ActiveCfg = Release|Any CPU + {1893A2E4-A78A-4713-A8E7-E70058DABEE0}.Release|x86.Build.0 = Release|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|x86.ActiveCfg = Debug|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Debug|x86.Build.0 = Debug|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|Any CPU.Build.0 = Release|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|x86.ActiveCfg = Release|Any CPU + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB}.Release|x86.Build.0 = Release|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|x86.ActiveCfg = Debug|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Debug|x86.Build.0 = Debug|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|Any CPU.Build.0 = Release|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|x86.ActiveCfg = Release|Any CPU + {9C0ECC4C-7807-4111-916A-4F57BB29788A}.Release|x86.Build.0 = Release|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|x86.ActiveCfg = Debug|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Debug|x86.Build.0 = Debug|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|Any CPU.Build.0 = Release|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|x86.ActiveCfg = Release|Any CPU + {9801F62C-540F-4BFE-9211-6405DEDE563B}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {970967C0-60BE-4F70-9332-9ACC04B93A15} + EndGlobalSection +EndGlobal diff --git a/Greenshot.sln.DotSettings b/src/Greenshot.sln.DotSettings similarity index 100% rename from Greenshot.sln.DotSettings rename to src/Greenshot.sln.DotSettings diff --git a/src/Greenshot/App.config b/src/Greenshot/App.config new file mode 100644 index 000000000..3b81b058d --- /dev/null +++ b/src/Greenshot/App.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Greenshot/Configuration/EditorConfiguration.cs b/src/Greenshot/Configuration/EditorConfiguration.cs new file mode 100644 index 000000000..b16c7804d --- /dev/null +++ b/src/Greenshot/Configuration/EditorConfiguration.cs @@ -0,0 +1,181 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using Greenshot.Base.Effects; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Base.UnmanagedHelpers.Structs; +using Greenshot.Drawing.Fields; + +namespace Greenshot.Configuration +{ + /// + /// Description of CoreConfiguration. + /// + [IniSection("Editor", Description = "Greenshot editor configuration")] + public class EditorConfiguration : IniSection + { + [IniProperty("RecentColors", Separator = "|", Description = "Last used colors")] + public List RecentColors { get; set; } + + [IniProperty("LastFieldValue", Separator = "|", Description = "Field values, make sure the last used settings are re-used")] + public Dictionary LastUsedFieldValues { get; set; } + + [IniProperty("MatchSizeToCapture", Description = "Match the editor window size to the capture", DefaultValue = "True")] + public bool MatchSizeToCapture { get; set; } + + [IniProperty("WindowPlacementFlags", Description = "Placement flags", DefaultValue = "0")] + public WindowPlacementFlags WindowPlacementFlags { get; set; } + + [IniProperty("WindowShowCommand", Description = "Show command", DefaultValue = "Normal")] + public ShowWindowCommand ShowWindowCommand { get; set; } + + [IniProperty("WindowMinPosition", Description = "Position of minimized window", DefaultValue = "-1,-1")] + public Point WindowMinPosition { get; set; } + + [IniProperty("WindowMaxPosition", Description = "Position of maximized window", DefaultValue = "-1,-1")] + public Point WindowMaxPosition { get; set; } + + [IniProperty("WindowNormalPosition", Description = "Position of normal window", DefaultValue = "100,100,400,400")] + public Rectangle WindowNormalPosition { get; set; } + + [IniProperty("ReuseEditor", Description = "Reuse already open editor", DefaultValue = "false")] + public bool ReuseEditor { get; set; } + + [IniProperty("FreehandSensitivity", + Description = + "The smaller this number, the less smoothing is used. Decrease for detailed drawing, e.g. when using a pen. Increase for smoother lines. e.g. when you want to draw a smooth line.", + DefaultValue = "3")] + public int FreehandSensitivity { get; set; } + + [IniProperty("SuppressSaveDialogAtClose", Description = "Suppressed the 'do you want to save' dialog when closing the editor.", DefaultValue = "False")] + public bool SuppressSaveDialogAtClose { get; set; } + + [IniProperty("DropShadowEffectSettings", Description = "Settings for the drop shadow effect.")] + public DropShadowEffect DropShadowEffectSettings { get; set; } + + [IniProperty("TornEdgeEffectSettings", Description = "Settings for the torn edge effect.")] + public TornEdgeEffect TornEdgeEffectSettings { get; set; } + + public override void AfterLoad() + { + base.AfterLoad(); + if (RecentColors == null) + { + RecentColors = new List(); + } + } + + /// Type of the class for which to create the field + /// FieldType of the field to construct + /// + /// a new Field of the given fieldType, with the scope of it's value being restricted to the Type scope + public IField CreateField(Type requestingType, IFieldType fieldType, object preferredDefaultValue) + { + string requestingTypeName = requestingType.Name; + string requestedField = requestingTypeName + "." + fieldType.Name; + object fieldValue = preferredDefaultValue; + + // Check if the configuration exists + if (LastUsedFieldValues == null) + { + LastUsedFieldValues = new Dictionary(); + } + + // Check if settings for the requesting type exist, if not create! + if (LastUsedFieldValues.ContainsKey(requestedField)) + { + // Check if a value is set (not null)! + if (LastUsedFieldValues[requestedField] != null) + { + fieldValue = LastUsedFieldValues[requestedField]; + } + else + { + // Overwrite null value + LastUsedFieldValues[requestedField] = fieldValue; + } + } + else + { + LastUsedFieldValues.Add(requestedField, fieldValue); + } + + return new Field(fieldType, requestingType) + { + Value = fieldValue + }; + } + + public void UpdateLastFieldValue(IField field) + { + string requestedField = field.Scope + "." + field.FieldType.Name; + // Check if the configuration exists + if (LastUsedFieldValues == null) + { + LastUsedFieldValues = new Dictionary(); + } + + // check if settings for the requesting type exist, if not create! + if (LastUsedFieldValues.ContainsKey(requestedField)) + { + LastUsedFieldValues[requestedField] = field.Value; + } + else + { + LastUsedFieldValues.Add(requestedField, field.Value); + } + } + + public void ResetEditorPlacement() + { + WindowNormalPosition = new Rectangle(100, 100, 400, 400); + WindowMaxPosition = new Point(-1, -1); + WindowMinPosition = new Point(-1, -1); + WindowPlacementFlags = 0; + ShowWindowCommand = ShowWindowCommand.Normal; + } + + public WindowPlacement GetEditorPlacement() + { + WindowPlacement placement = WindowPlacement.Default; + placement.NormalPosition = new RECT(WindowNormalPosition); + placement.MaxPosition = new POINT(WindowMaxPosition); + placement.MinPosition = new POINT(WindowMinPosition); + placement.ShowCmd = ShowWindowCommand; + placement.Flags = WindowPlacementFlags; + return placement; + } + + public void SetEditorPlacement(WindowPlacement placement) + { + WindowNormalPosition = placement.NormalPosition.ToRectangle(); + WindowMaxPosition = placement.MaxPosition.ToPoint(); + WindowMinPosition = placement.MinPosition.ToPoint(); + ShowWindowCommand = placement.ShowCmd; + WindowPlacementFlags = placement.Flags; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Configuration/LanguageKeys.cs b/src/Greenshot/Configuration/LanguageKeys.cs new file mode 100644 index 000000000..e156261b7 --- /dev/null +++ b/src/Greenshot/Configuration/LanguageKeys.cs @@ -0,0 +1,82 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Diagnostics.CodeAnalysis; + +namespace Greenshot.Configuration +{ + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum LangKey + { + none, + contextmenu_capturefullscreen_all, + contextmenu_capturefullscreen_left, + contextmenu_capturefullscreen_top, + contextmenu_capturefullscreen_right, + contextmenu_capturefullscreen_bottom, + contextmenu_captureie, + editor_clipboardfailed, + editor_close_on_save, + editor_close_on_save_title, + editor_copytoclipboard, + editor_cuttoclipboard, + editor_deleteelement, + editor_downonelevel, + editor_downtobottom, + editor_duplicate, + editor_email, + editor_imagesaved, + editor_title, + editor_uponelevel, + editor_uptotop, + editor_undo, + editor_redo, + editor_resetsize, + error, + error_multipleinstances, + error_openfile, + error_openlink, + error_save, + error_save_invalid_chars, + print_error, + quicksettings_destination_file, + settings_destination, + settings_destination_clipboard, + settings_destination_editor, + settings_destination_fileas, + settings_destination_printer, + settings_destination_picker, + settings_filenamepattern, + settings_message_filenamepattern, + settings_printoptions, + settings_tooltip_filenamepattern, + settings_tooltip_language, + settings_tooltip_primaryimageformat, + settings_tooltip_storagelocation, + settings_visualization, + settings_window_capture_mode, + tooltip_firststart, + warning, + warning_hotkeys, + wait_ie_capture, + update_found + } +} \ No newline at end of file diff --git a/Greenshot/Controls/BindableToolStripButton.cs b/src/Greenshot/Controls/BindableToolStripButton.cs similarity index 52% rename from Greenshot/Controls/BindableToolStripButton.cs rename to src/Greenshot/Controls/BindableToolStripButton.cs index b44a1a31c..51dfe9538 100644 --- a/Greenshot/Controls/BindableToolStripButton.cs +++ b/src/Greenshot/Controls/BindableToolStripButton.cs @@ -18,32 +18,32 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Windows.Forms; -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace Greenshot.Controls { - /// - /// Description of BindableToolStripButton. - /// - public class BindableToolStripButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; +namespace Greenshot.Controls +{ + /// + /// Description of BindableToolStripButton. + /// + public class BindableToolStripButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable + { + public event PropertyChangedEventHandler PropertyChanged; - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } - public BindableToolStripButton() - { - CheckedChanged += BindableToolStripButton_CheckedChanged; - } + public BindableToolStripButton() + { + CheckedChanged += BindableToolStripButton_CheckedChanged; + } - private void BindableToolStripButton_CheckedChanged(object sender, EventArgs e) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Checked")); - } - } -} + private void BindableToolStripButton_CheckedChanged(object sender, EventArgs e) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Checked")); + } + } +} \ No newline at end of file diff --git a/Greenshot/Controls/BindableToolStripComboBox.cs b/src/Greenshot/Controls/BindableToolStripComboBox.cs similarity index 50% rename from Greenshot/Controls/BindableToolStripComboBox.cs rename to src/Greenshot/Controls/BindableToolStripComboBox.cs index 3637f2380..9f767b1fa 100644 --- a/Greenshot/Controls/BindableToolStripComboBox.cs +++ b/src/Greenshot/Controls/BindableToolStripComboBox.cs @@ -18,32 +18,32 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.ComponentModel; using System.Windows.Forms; -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace Greenshot.Controls { - /// - /// A simple ToolStripComboBox implementing INotifyPropertyChanged for data binding - /// - public class BindableToolStripComboBox : ToolStripComboBox, INotifyPropertyChanged, IGreenshotLanguageBindable { - public event PropertyChangedEventHandler PropertyChanged; +namespace Greenshot.Controls +{ + /// + /// A simple ToolStripComboBox implementing INotifyPropertyChanged for data binding + /// + public class BindableToolStripComboBox : ToolStripComboBox, INotifyPropertyChanged, IGreenshotLanguageBindable + { + public event PropertyChangedEventHandler PropertyChanged; - [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] - public string LanguageKey { - get; - set; - } + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } - public BindableToolStripComboBox() - { - SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged; - } + public BindableToolStripComboBox() + { + SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged; + } - private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedItem")); - } - } -} + private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedItem")); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/BindableToolStripDropDownButton.cs b/src/Greenshot/Controls/BindableToolStripDropDownButton.cs new file mode 100644 index 000000000..04c1a3ee0 --- /dev/null +++ b/src/Greenshot/Controls/BindableToolStripDropDownButton.cs @@ -0,0 +1,82 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.ComponentModel; +using System.Windows.Forms; +using Greenshot.Base.Controls; + +namespace Greenshot.Controls +{ + /// + /// A simple ToolStripDropDownButton implementing INotifyPropertyChanged for data binding. + /// Also, when a DropDownItem is selected, the DropDownButton adopts its Tag and Image. + /// The selected tag can be accessed via SelectedTag property. + /// + public class BindableToolStripDropDownButton : ToolStripDropDownButton, INotifyPropertyChanged, IGreenshotLanguageBindable + { + public event PropertyChangedEventHandler PropertyChanged; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + + public object SelectedTag + { + get + { + if (Tag == null && DropDownItems.Count > 0) Tag = DropDownItems[0].Tag; + return Tag; + } + set { AdoptFromTag(value); } + } + + protected override void OnDropDownItemClicked(ToolStripItemClickedEventArgs e) + { + ToolStripItem clickedItem = e.ClickedItem; + if (Tag == null || !Tag.Equals(clickedItem.Tag)) + { + Tag = clickedItem.Tag; + Image = clickedItem.Image; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag")); + } + + base.OnDropDownItemClicked(e); + } + + private void AdoptFromTag(object tag) + { + if (Tag == null || !Tag.Equals(tag)) + { + Tag = tag; + foreach (ToolStripItem item in DropDownItems) + { + if (item.Tag != null && item.Tag.Equals(tag)) + { + Image = item.Image; + break; + } + } + + Tag = tag; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTag")); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/ColorButton.cs b/src/Greenshot/Controls/ColorButton.cs new file mode 100644 index 000000000..2c762e216 --- /dev/null +++ b/src/Greenshot/Controls/ColorButton.cs @@ -0,0 +1,99 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using ColorDialog = Greenshot.Forms.ColorDialog; + +namespace Greenshot.Controls +{ + /// + /// Description of ColorButton. + /// + public class ColorButton : Button, IGreenshotLanguageBindable + { + public event PropertyChangedEventHandler PropertyChanged; + private Color _selectedColor = Color.White; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + + public ColorButton() + { + Click += ColorButtonClick; + } + + public Color SelectedColor + { + get { return _selectedColor; } + set + { + _selectedColor = value; + + Brush brush; + if (value != Color.Transparent) + { + brush = new SolidBrush(value); + } + else + { + brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray); + } + + if (Image != null) + { + using Graphics graphics = Graphics.FromImage(Image); + graphics.FillRectangle(brush, new Rectangle(4, 17, 16, 3)); + } + + // cleanup GDI Object + brush.Dispose(); + Invalidate(); + } + } + + private void ColorButtonClick(object sender, EventArgs e) + { + var colorDialog = new ColorDialog + { + Color = SelectedColor + }; + // Using the parent to make sure the dialog doesn't show on another window + colorDialog.ShowDialog(Parent.Parent); + if (colorDialog.DialogResult == DialogResult.Cancel) + { + return; + } + + if (colorDialog.Color.Equals(SelectedColor)) + { + return; + } + + SelectedColor = colorDialog.Color; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor")); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs b/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs new file mode 100644 index 000000000..b1229a293 --- /dev/null +++ b/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs @@ -0,0 +1,50 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; + +namespace Greenshot.Controls +{ + /// + /// ToolStripProfessionalRenderer which draws the Check correctly when the icons are larger + /// + public class ContextMenuToolStripProfessionalRenderer : ToolStripProfessionalRenderer + { + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + private static Image _scaledCheckbox; + + protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) + { + if (_scaledCheckbox == null || _scaledCheckbox.Size != CoreConfig.ScaledIconSize) + { + _scaledCheckbox?.Dispose(); + _scaledCheckbox = ImageHelper.ResizeImage(e.Image, true, CoreConfig.ScaledIconSize.Width, CoreConfig.ScaledIconSize.Height, null); + } + + Rectangle old = e.ImageRectangle; + ToolStripItemImageRenderEventArgs clone = new ToolStripItemImageRenderEventArgs(e.Graphics, e.Item, _scaledCheckbox, new Rectangle(old.X, 0, old.Width, old.Height)); + base.OnRenderItemCheck(clone); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs b/src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs new file mode 100644 index 000000000..90f3a7818 --- /dev/null +++ b/src/Greenshot/Controls/CustomToolStripProfessionalRenderer.cs @@ -0,0 +1,84 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Windows.Forms; + +namespace Greenshot.Controls +{ + /// + /// Prevent having a gradient background in the toolstrip, and the overflow button + /// See: http://stackoverflow.com/a/16926979 + /// + internal class CustomProfessionalColorTable : ProfessionalColorTable + { + public override Color ToolStripGradientBegin + { + get { return SystemColors.Control; } + } + + public override Color ToolStripGradientMiddle + { + get { return SystemColors.Control; } + } + + public override Color ToolStripGradientEnd + { + get { return SystemColors.Control; } + } + + public override Color OverflowButtonGradientBegin + { + get { return SystemColors.Control; } + } + + public override Color OverflowButtonGradientMiddle + { + get { return SystemColors.Control; } + } + + public override Color OverflowButtonGradientEnd + { + get { return SystemColors.Control; } + } + } + + /// + /// ToolStripProfessionalRenderer without having a visual artifact + /// See: http://stackoverflow.com/a/16926979 and http://stackoverflow.com/a/13418840 + /// + public class CustomToolStripProfessionalRenderer : ToolStripProfessionalRenderer + { + public CustomToolStripProfessionalRenderer() : base(new CustomProfessionalColorTable()) + { + RoundedEdges = false; + } + + /// + /// By overriding the OnRenderToolStripBorder we can make the ToolStrip without border + /// + /// + protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) + { + // Don't draw a border + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/FontFamilyComboBox.cs b/src/Greenshot/Controls/FontFamilyComboBox.cs new file mode 100644 index 000000000..db1cef03e --- /dev/null +++ b/src/Greenshot/Controls/FontFamilyComboBox.cs @@ -0,0 +1,141 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace Greenshot.Controls +{ + /// + /// ToolStripComboBox containing installed font families, + /// implementing INotifyPropertyChanged for data binding + /// + public class FontFamilyComboBox : ToolStripComboBox, INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + public FontFamily FontFamily + { + get { return (FontFamily) SelectedItem; } + set + { + if (!SelectedItem.Equals(value)) + { + SelectedItem = value; + } + } + } + + public FontFamilyComboBox() + { + if (ComboBox != null) + { + ComboBox.DataSource = FontFamily.Families; + ComboBox.DisplayMember = "Name"; + SelectedIndexChanged += BindableToolStripComboBox_SelectedIndexChanged; + ComboBox.DrawMode = DrawMode.OwnerDrawFixed; + ComboBox.DrawItem += ComboBox_DrawItem; + } + } + + private void ComboBox_DrawItem(object sender, DrawItemEventArgs e) + { + // DrawBackground handles drawing the background (i.e,. hot-tracked v. not) + // It uses the system colors (Bluish, and and white, by default) + // same as calling e.Graphics.FillRectangle ( SystemBrushes.Highlight, e.Bounds ); + e.DrawBackground(); + + if (e.Index > -1) + { + FontFamily fontFamily = Items[e.Index] as FontFamily; + FontStyle fontStyle = FontStyle.Regular; + if (fontFamily != null && !fontFamily.IsStyleAvailable(FontStyle.Regular)) + { + if (fontFamily.IsStyleAvailable(FontStyle.Bold)) + { + fontStyle = FontStyle.Bold; + } + else if (fontFamily.IsStyleAvailable(FontStyle.Italic)) + { + fontStyle = FontStyle.Italic; + } + else if (fontFamily.IsStyleAvailable(FontStyle.Strikeout)) + { + fontStyle = FontStyle.Strikeout; + } + else if (fontFamily.IsStyleAvailable(FontStyle.Underline)) + { + fontStyle = FontStyle.Underline; + } + } + + try + { + if (fontFamily != null) + { + DrawText(e.Graphics, fontFamily, fontStyle, e.Bounds, fontFamily.Name); + } + } + catch + { + // If the drawing failed, BUG-1770 seems to have a weird case that causes: Font 'Lucida Sans Typewriter' does not support style 'Regular' + if (fontFamily != null) + { + DrawText(e.Graphics, FontFamily.GenericSansSerif, FontStyle.Regular, e.Bounds, fontFamily.Name); + } + } + } + + // Uncomment this if you actually like the way the focus rectangle looks + //e.DrawFocusRectangle (); + } + + /// + /// Helper method to draw the string + /// + /// + /// + /// + /// + /// + private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, Rectangle bounds, string text) + { + using Font font = new Font(fontFamily, Font.Size + 5, fontStyle, GraphicsUnit.Pixel); + // Make sure the text is visible by centering it in the line + using StringFormat stringFormat = new StringFormat + { + LineAlignment = StringAlignment.Center + }; + graphics.DrawString(text, font, Brushes.Black, bounds, stringFormat); + } + + private void BindableToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e) + { + if (PropertyChanged == null) return; + PropertyChanged(this, new PropertyChangedEventArgs("Text")); + PropertyChanged(this, new PropertyChangedEventArgs("FontFamily")); + PropertyChanged(this, new PropertyChangedEventArgs("SelectedIndex")); + PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem")); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/MenuStripEx.cs b/src/Greenshot/Controls/MenuStripEx.cs new file mode 100644 index 000000000..a9c92f2a6 --- /dev/null +++ b/src/Greenshot/Controls/MenuStripEx.cs @@ -0,0 +1,65 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows.Forms; +using Greenshot.Base.UnmanagedHelpers.Enums; + +namespace Greenshot.Controls +{ + /// + /// This is an extension of the default MenuStrip and allows us to click it even when the form doesn't have focus. + /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx + /// + public class MenuStripEx : MenuStrip + { + private enum NativeConstants : uint + { + MA_ACTIVATE = 1, + MA_ACTIVATEANDEAT = 2, + } + + private bool _clickThrough; + + /// + /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus. + /// + /// + /// Default value is false, which is the same behavior provided by the base ToolStrip class. + /// + public bool ClickThrough + { + get { return _clickThrough; } + + set { _clickThrough = value; } + } + + protected override void WndProc(ref Message m) + { + base.WndProc(ref m); + var windowsMessage = (WindowsMessages) m.Msg; + if (_clickThrough && windowsMessage == WindowsMessages.WM_MOUSEACTIVATE && m.Result == (IntPtr) NativeConstants.MA_ACTIVATEANDEAT) + { + m.Result = (IntPtr) NativeConstants.MA_ACTIVATE; + } + } + } +} \ No newline at end of file diff --git a/Greenshot/Controls/NonJumpingPanel.cs b/src/Greenshot/Controls/NonJumpingPanel.cs similarity index 97% rename from Greenshot/Controls/NonJumpingPanel.cs rename to src/Greenshot/Controls/NonJumpingPanel.cs index d5565c637..8f14303a8 100644 --- a/Greenshot/Controls/NonJumpingPanel.cs +++ b/src/Greenshot/Controls/NonJumpingPanel.cs @@ -67,4 +67,4 @@ namespace Greenshot.Controls } } } -} +} \ No newline at end of file diff --git a/src/Greenshot/Controls/Pipette.cs b/src/Greenshot/Controls/Pipette.cs new file mode 100644 index 000000000..32c07459e --- /dev/null +++ b/src/Greenshot/Controls/Pipette.cs @@ -0,0 +1,204 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; +using Greenshot.Forms; +using ColorDialog = Greenshot.Forms.ColorDialog; + +namespace Greenshot.Controls +{ + /// + /// This code was supplied by Hi-Coder as a patch for Greenshot + /// Needed some modifications to be stable. + /// + public sealed class Pipette : Label, IMessageFilter, IDisposable + { + private MovableShowColorForm _movableShowColorForm; + private bool _dragging; + private Cursor _cursor; + private readonly Bitmap _image; + private const int VkEsc = 27; + + public event EventHandler PipetteUsed; + + public Pipette() + { + BorderStyle = BorderStyle.FixedSingle; + _dragging = false; + _image = (Bitmap) new ComponentResourceManager(typeof(ColorDialog)).GetObject("pipette.Image"); + Image = _image; + _cursor = CreateCursor(_image, 1, 14); + _movableShowColorForm = new MovableShowColorForm(); + Application.AddMessageFilter(this); + } + + /// + /// Create a cursor from the supplied bitmap & hotspot coordinates + /// + /// Bitmap to create an icon from + /// Hotspot X coordinate + /// Hotspot Y coordinate + /// Cursor + private static Cursor CreateCursor(Bitmap bitmap, int hotspotX, int hotspotY) + { + using SafeIconHandle iconHandle = new SafeIconHandle(bitmap.GetHicon()); + User32.GetIconInfo(iconHandle, out var iconInfo); + iconInfo.xHotspot = hotspotX; + iconInfo.yHotspot = hotspotY; + iconInfo.fIcon = false; + var icon = User32.CreateIconIndirect(ref iconInfo); + return new Cursor(icon); + } + + /// + /// The bulk of the clean-up code is implemented in Dispose(bool) + /// + public new void Dispose() + { + Dispose(true); + } + + /// + /// This Dispose is called from the Dispose and the Destructor. + /// + /// When disposing==true all non-managed resources should be freed too! + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_cursor != null) + { + _cursor.Dispose(); + } + + _movableShowColorForm?.Dispose(); + } + + _movableShowColorForm = null; + _cursor = null; + base.Dispose(disposing); + } + + /// + /// Handle the mouse down on the Pipette "label", we take the capture and move the zoomer to the current location + /// + /// MouseEventArgs + protected override void OnMouseDown(MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + User32.SetCapture(Handle); + _movableShowColorForm.MoveTo(PointToScreen(new Point(e.X, e.Y))); + } + + base.OnMouseDown(e); + } + + /// + /// Handle the mouse up on the Pipette "label", we release the capture and fire the PipetteUsed event + /// + /// MouseEventArgs + protected override void OnMouseUp(MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + //Release Capture should consume MouseUp when canceled with the escape key + User32.ReleaseCapture(); + PipetteUsed?.Invoke(this, new PipetteUsedArgs(_movableShowColorForm.color)); + } + + base.OnMouseUp(e); + } + + /// + /// Handle the mouse Move event, we move the ColorUnderCursor to the current location. + /// + /// MouseEventArgs + protected override void OnMouseMove(MouseEventArgs e) + { + if (_dragging) + { + //display the form on the right side of the cursor by default; + Point zp = PointToScreen(new Point(e.X, e.Y)); + _movableShowColorForm.MoveTo(zp); + } + + base.OnMouseMove(e); + } + + /// + /// Handle the MouseCaptureChanged event + /// + /// + protected override void OnMouseCaptureChanged(EventArgs e) + { + if (Capture) + { + _dragging = true; + Image = null; + Cursor c = _cursor; + Cursor = c; + _movableShowColorForm.Visible = true; + } + else + { + _dragging = false; + Image = _image; + Cursor = Cursors.Arrow; + _movableShowColorForm.Visible = false; + } + + Update(); + base.OnMouseCaptureChanged(e); + } + + public bool PreFilterMessage(ref Message m) + { + if (_dragging) + { + if (m.Msg == (int) WindowsMessages.WM_CHAR) + { + if ((int) m.WParam == VkEsc) + { + User32.ReleaseCapture(); + } + } + } + + return false; + } + } + + public class PipetteUsedArgs : EventArgs + { + public Color Color; + + public PipetteUsedArgs(Color c) + { + Color = c; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/ToolStripColorButton.cs b/src/Greenshot/Controls/ToolStripColorButton.cs new file mode 100644 index 000000000..1e21d2725 --- /dev/null +++ b/src/Greenshot/Controls/ToolStripColorButton.cs @@ -0,0 +1,97 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using ColorDialog = Greenshot.Forms.ColorDialog; + +namespace Greenshot.Controls +{ + public class ToolStripColorButton : ToolStripButton, INotifyPropertyChanged, IGreenshotLanguageBindable + { + public event PropertyChangedEventHandler PropertyChanged; + + [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] + public string LanguageKey { get; set; } + + private Color _selectedColor = Color.Transparent; + + public ToolStripColorButton() + { + Click += ColorButtonClick; + } + + public Color SelectedColor + { + get { return _selectedColor; } + set + { + _selectedColor = value; + + Brush brush; + if (value != Color.Transparent) + { + brush = new SolidBrush(value); + } + else + { + brush = new HatchBrush(HatchStyle.Percent50, Color.White, Color.Gray); + } + + if (Image != null) + { + using Graphics graphics = Graphics.FromImage(Image); + graphics.FillRectangle(brush, new Rectangle(0, 13, 16, 3)); + } + + // cleanup GDI Object + brush.Dispose(); + Invalidate(); + } + } + + private void ColorButtonClick(object sender, EventArgs e) + { + var colorDialog = new ColorDialog + { + Color = SelectedColor + }; + // Using the parent to make sure the dialog doesn't show on another window + colorDialog.ShowDialog(Parent.Parent); + if (colorDialog.DialogResult == DialogResult.Cancel) + { + return; + } + + if (colorDialog.Color.Equals(SelectedColor)) + { + return; + } + + SelectedColor = colorDialog.Color; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedColor")); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/ToolStripEx.cs b/src/Greenshot/Controls/ToolStripEx.cs new file mode 100644 index 000000000..c7ff79048 --- /dev/null +++ b/src/Greenshot/Controls/ToolStripEx.cs @@ -0,0 +1,66 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows.Forms; + +namespace Greenshot.Controls +{ + /// + /// This is an extension of the default ToolStrip and allows us to click it even when the form doesn't have focus. + /// See: http://blogs.msdn.com/b/rickbrew/archive/2006/01/09/511003.aspx + /// + internal class ToolStripEx : ToolStrip + { + private const int WM_MOUSEACTIVATE = 0x21; + + private enum NativeConstants : uint + { + MA_ACTIVATE = 1, + MA_ACTIVATEANDEAT = 2, + } + + private bool _clickThrough; + + /// + /// Gets or sets whether the ToolStripEx honors item clicks when its containing form does not have input focus. + /// + /// + /// Default value is false, which is the same behavior provided by the base ToolStrip class. + /// + + public bool ClickThrough + { + get { return _clickThrough; } + + set { _clickThrough = value; } + } + + protected override void WndProc(ref Message m) + { + base.WndProc(ref m); + if (_clickThrough && m.Msg == WM_MOUSEACTIVATE && m.Result == (IntPtr) NativeConstants.MA_ACTIVATEANDEAT) + { + m.Result = (IntPtr) NativeConstants.MA_ACTIVATE; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Controls/ToolStripNumericUpDown.cs b/src/Greenshot/Controls/ToolStripNumericUpDown.cs new file mode 100644 index 000000000..ecbc470ca --- /dev/null +++ b/src/Greenshot/Controls/ToolStripNumericUpDown.cs @@ -0,0 +1,88 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace Greenshot.Controls +{ + [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)] + public class ToolStripNumericUpDown : ToolStripControlHost, INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + public ToolStripNumericUpDown() : base(new NumericUpDown()) + { + } + + public NumericUpDown NumericUpDown => Control as NumericUpDown; + + public decimal Value + { + get { return NumericUpDown.Value; } + set { NumericUpDown.Value = value; } + } + + public decimal Minimum + { + get { return NumericUpDown.Minimum; } + set { NumericUpDown.Minimum = value; } + } + + public decimal Maximum + { + get { return NumericUpDown.Maximum; } + set { NumericUpDown.Maximum = value; } + } + + public decimal Increment + { + get { return NumericUpDown.Increment; } + set { NumericUpDown.Increment = value; } + } + + public int DecimalPlaces + { + get { return NumericUpDown.DecimalPlaces; } + set { NumericUpDown.DecimalPlaces = value; } + } + + + protected override void OnSubscribeControlEvents(Control control) + { + base.OnSubscribeControlEvents(control); + NumericUpDown.ValueChanged += _valueChanged; + } + + protected override void OnUnsubscribeControlEvents(Control control) + { + base.OnUnsubscribeControlEvents(control); + NumericUpDown.ValueChanged -= _valueChanged; + } + + private void _valueChanged(object sender, EventArgs e) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/ClipboardDestination.cs b/src/Greenshot/Destinations/ClipboardDestination.cs new file mode 100644 index 000000000..3946be901 --- /dev/null +++ b/src/Greenshot/Destinations/ClipboardDestination.cs @@ -0,0 +1,81 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Configuration; + +namespace Greenshot.Destinations +{ + /// + /// Description of ClipboardDestination. + /// + public class ClipboardDestination : AbstractDestination + { + public const string DESIGNATION = "Clipboard"; + + public override string Designation + { + get { return DESIGNATION; } + } + + public override string Description + { + get { return Language.GetString(LangKey.settings_destination_clipboard); } + } + + public override int Priority + { + get { return 2; } + } + + public override Keys EditorShortcutKeys + { + get { return Keys.Control | Keys.Shift | Keys.C; } + } + + public override Image DisplayIcon + { + get { return GreenshotResources.GetImage("Clipboard.Image"); } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + try + { + ClipboardHelper.SetClipboardData(surface); + exportInformation.ExportMade = true; + } + catch (Exception) + { + // TODO: Change to general logic in ProcessExport + surface.SendMessageEvent(this, SurfaceMessageTyp.Error, Language.GetString(LangKey.editor_clipboardfailed)); + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/EditorDestination.cs b/src/Greenshot/Destinations/EditorDestination.cs new file mode 100644 index 000000000..ba74a70ca --- /dev/null +++ b/src/Greenshot/Destinations/EditorDestination.cs @@ -0,0 +1,154 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Forms; +using Greenshot.Configuration; +using Greenshot.Forms; +using log4net; + +namespace Greenshot.Destinations +{ + /// + /// Description of EditorDestination. + /// + public class EditorDestination : AbstractDestination + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(EditorDestination)); + private static readonly EditorConfiguration editorConfiguration = IniConfig.GetIniSection(); + public const string DESIGNATION = "Editor"; + private readonly IImageEditor editor; + private static readonly Image greenshotIcon = GreenshotResources.GetGreenshotIcon().ToBitmap(); + + public EditorDestination() + { + // Do not remove, is needed for the framework + } + + public EditorDestination(IImageEditor editor) + { + this.editor = editor; + } + + public override string Designation => DESIGNATION; + + public override string Description + { + get + { + if (editor == null) + { + return Language.GetString(LangKey.settings_destination_editor); + } + + return Language.GetString(LangKey.settings_destination_editor) + " - " + editor.CaptureDetails.Title; + } + } + + public override int Priority => 1; + + public override bool IsDynamic => true; + + public override Image DisplayIcon => greenshotIcon; + + public override IEnumerable DynamicDestinations() + { + foreach (IImageEditor someEditor in ImageEditorForm.Editors) + { + yield return new EditorDestination(someEditor); + } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + // Make sure we collect the garbage before opening the screenshot + GC.Collect(); + GC.WaitForPendingFinalizers(); + + bool modified = surface.Modified; + if (editor == null) + { + if (editorConfiguration.ReuseEditor) + { + foreach (IImageEditor openedEditor in ImageEditorForm.Editors) + { + if (openedEditor.Surface.Modified) continue; + + openedEditor.Surface = surface; + exportInformation.ExportMade = true; + break; + } + } + + if (!exportInformation.ExportMade) + { + try + { + ImageEditorForm editorForm = new ImageEditorForm(surface, !surface.Modified); // Output made?? + + if (!string.IsNullOrEmpty(captureDetails.Filename)) + { + editorForm.SetImagePath(captureDetails.Filename); + } + + editorForm.Show(); + editorForm.Activate(); + LOG.Debug("Finished opening Editor"); + exportInformation.ExportMade = true; + } + catch (Exception e) + { + LOG.Error(e); + exportInformation.ErrorMessage = e.Message; + } + } + } + else + { + try + { + using (Image image = surface.GetImageForExport()) + { + editor.Surface.AddImageContainer(image, 10, 10); + } + + exportInformation.ExportMade = true; + } + catch (Exception e) + { + LOG.Error(e); + exportInformation.ErrorMessage = e.Message; + } + } + + ProcessExport(exportInformation, surface); + // Workaround for the modified flag when using the editor. + surface.Modified = modified; + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/EmailDestination.cs b/src/Greenshot/Destinations/EmailDestination.cs new file mode 100644 index 000000000..b3f546f34 --- /dev/null +++ b/src/Greenshot/Destinations/EmailDestination.cs @@ -0,0 +1,99 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Configuration; +using Greenshot.Helpers; +using Microsoft.Win32; + +namespace Greenshot.Destinations +{ + /// + /// Description of EmailDestination. + /// + public class EmailDestination : AbstractDestination + { + private static readonly Image MailIcon = GreenshotResources.GetImage("Email.Image"); + private static bool _isActiveFlag; + private static string _mapiClient; + public const string DESIGNATION = "EMail"; + + static EmailDestination() + { + // Logic to decide what email implementation we use + _mapiClient = RegistryHive.LocalMachine.ReadKey64Or32(@"Clients\Mail"); + if (!string.IsNullOrEmpty(_mapiClient)) + { + // Active as we have a MAPI client, can be disabled later + _isActiveFlag = true; + } + } + + public override string Designation => DESIGNATION; + + public override string Description + { + get + { + // Make sure there is some kind of "mail" name + return _mapiClient ??= Language.GetString(LangKey.editor_email); + } + } + + public override int Priority => 3; + + public override bool IsActive + { + get + { + if (_isActiveFlag) + { + // Disable if the office plugin is installed and the client is outlook + // TODO: Change this! It always creates an exception, as the plugin has not been loaded the type is not there :( + var outlookDestination = Type.GetType("GreenshotOfficePlugin.OutlookDestination,GreenshotOfficePlugin", false); + if (outlookDestination != null && _mapiClient.ToLower().Contains("microsoft outlook")) + { + _isActiveFlag = false; + } + } + + return base.IsActive && _isActiveFlag; + } + } + + public override Keys EditorShortcutKeys => Keys.Control | Keys.E; + + public override Image DisplayIcon => MailIcon; + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + MapiMailMessage.SendImage(surface, captureDetails); + exportInformation.ExportMade = true; + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/FileDestination.cs b/src/Greenshot/Destinations/FileDestination.cs new file mode 100644 index 000000000..cf0c4ed28 --- /dev/null +++ b/src/Greenshot/Destinations/FileDestination.cs @@ -0,0 +1,168 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Configuration; +using Greenshot.Forms; +using log4net; + +namespace Greenshot.Destinations +{ + /// + /// Description of FileSaveAsDestination. + /// + public class FileDestination : AbstractDestination + { + private static readonly ILog Log = LogManager.GetLogger(typeof(FileDestination)); + private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); + public const string DESIGNATION = "FileNoDialog"; + + public override string Designation => DESIGNATION; + + public override string Description => Language.GetString(LangKey.quicksettings_destination_file); + + public override int Priority => 0; + + public override Keys EditorShortcutKeys => Keys.Control | Keys.S; + + public override Image DisplayIcon => GreenshotResources.GetImage("Save.Image"); + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + bool outputMade; + bool overwrite; + string fullPath; + // Get output settings from the configuration + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); + + if (captureDetails?.Filename != null) + { + // As we save a pre-selected file, allow to overwrite. + overwrite = true; + Log.InfoFormat("Using previous filename"); + fullPath = captureDetails.Filename; + outputSettings.Format = ImageOutput.FormatForFilename(fullPath); + } + else + { + fullPath = CreateNewFilename(captureDetails); + // As we generate a file, the configuration tells us if we allow to overwrite + overwrite = CoreConfig.OutputFileAllowOverwrite; + } + + if (CoreConfig.OutputFilePromptQuality) + { + QualityDialog qualityDialog = new QualityDialog(outputSettings); + qualityDialog.ShowDialog(); + } + + // Catching any exception to prevent that the user can't write in the directory. + // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 + try + { + ImageOutput.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); + outputMade = true; + } + catch (ArgumentException ex1) + { + // Our generated filename exists, display 'save-as' + Log.InfoFormat("Not overwriting: {0}", ex1.Message); + // when we don't allow to overwrite present a new SaveWithDialog + fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); + outputMade = fullPath != null; + } + catch (Exception ex2) + { + Log.Error("Error saving screenshot!", ex2); + // Show the problem + MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error)); + // when save failed we present a SaveWithDialog + fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); + outputMade = fullPath != null; + } + + // Don't overwrite filename if no output is made + if (outputMade) + { + exportInformation.ExportMade = true; + exportInformation.Filepath = fullPath; + if (captureDetails != null) + { + captureDetails.Filename = fullPath; + } + + CoreConfig.OutputFileAsFullpath = fullPath; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + + private static string CreateNewFilename(ICaptureDetails captureDetails) + { + string fullPath; + Log.InfoFormat("Creating new filename"); + string pattern = CoreConfig.OutputFileFilenamePattern; + if (string.IsNullOrEmpty(pattern)) + { + pattern = "greenshot ${capturetime}"; + } + + string filename = FilenameHelper.GetFilenameFromPattern(pattern, CoreConfig.OutputFileFormat, captureDetails); + CoreConfig.ValidateAndCorrectOutputFilePath(); + string filepath = FilenameHelper.FillVariables(CoreConfig.OutputFilePath, false); + try + { + fullPath = Path.Combine(filepath, filename); + } + catch (ArgumentException) + { + // configured filename or path not valid, show error message... + Log.InfoFormat("Generated path or filename not valid: {0}, {1}", filepath, filename); + + MessageBox.Show(Language.GetString(LangKey.error_save_invalid_chars), Language.GetString(LangKey.error)); + // ... lets get the pattern fixed.... + var dialogResult = new SettingsForm().ShowDialog(); + if (dialogResult == DialogResult.OK) + { + // ... OK -> then try again: + fullPath = CreateNewFilename(captureDetails); + } + else + { + // ... cancelled. + fullPath = null; + } + } + + return fullPath; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/FileWithDialogDestination.cs b/src/Greenshot/Destinations/FileWithDialogDestination.cs new file mode 100644 index 000000000..b17659da0 --- /dev/null +++ b/src/Greenshot/Destinations/FileWithDialogDestination.cs @@ -0,0 +1,81 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Configuration; + +namespace Greenshot.Destinations +{ + /// + /// Description of FileWithDialog. + /// + public class FileWithDialogDestination : AbstractDestination + { + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + public const string DESIGNATION = "FileDialog"; + + public override string Designation + { + get { return DESIGNATION; } + } + + public override string Description + { + get { return Language.GetString(LangKey.settings_destination_fileas); } + } + + public override int Priority + { + get { return 0; } + } + + public override Keys EditorShortcutKeys + { + get { return Keys.Control | Keys.Shift | Keys.S; } + } + + public override Image DisplayIcon + { + get { return GreenshotResources.GetImage("Save.Image"); } + } + + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + // Bug #2918756 don't overwrite path if SaveWithDialog returns null! + var savedTo = ImageOutput.SaveWithDialog(surface, captureDetails); + if (savedTo != null) + { + exportInformation.ExportMade = true; + exportInformation.Filepath = savedTo; + captureDetails.Filename = savedTo; + conf.OutputFileAsFullpath = savedTo; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/PickerDestination.cs b/src/Greenshot/Destinations/PickerDestination.cs new file mode 100644 index 000000000..654726e6a --- /dev/null +++ b/src/Greenshot/Destinations/PickerDestination.cs @@ -0,0 +1,73 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Configuration; + +namespace Greenshot.Destinations +{ + /// + /// The PickerDestination shows a context menu with all possible destinations, so the user can "pick" one + /// + public class PickerDestination : AbstractDestination + { + public const string DESIGNATION = "Picker"; + + public override string Designation => DESIGNATION; + + public override string Description => Language.GetString(LangKey.settings_destination_picker); + + public override int Priority => 1; + + + /// + /// Export the capture with the destination picker + /// + /// Did the user select this destination? + /// Surface to export + /// Details of the capture + /// true if export was made + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + List destinations = new List(); + + foreach (var destination in SimpleServiceProvider.Current.GetAllInstances()) + { + if ("Picker".Equals(destination.Designation)) + { + continue; + } + + if (!destination.IsActive) + { + continue; + } + + destinations.Add(destination); + } + + // No Processing, this is done in the selected destination (if anything was selected) + return ShowPickerMenu(true, surface, captureDetails, destinations); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Destinations/PrinterDestination.cs b/src/Greenshot/Destinations/PrinterDestination.cs new file mode 100644 index 000000000..7be51bbff --- /dev/null +++ b/src/Greenshot/Destinations/PrinterDestination.cs @@ -0,0 +1,146 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Printing; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Configuration; +using Greenshot.Helpers; + +namespace Greenshot.Destinations +{ + /// + /// Description of PrinterDestination. + /// + public class PrinterDestination : AbstractDestination + { + public const string DESIGNATION = "Printer"; + private readonly string _printerName; + + public PrinterDestination() + { + } + + public PrinterDestination(string printerName) + { + _printerName = printerName; + } + + public override string Designation => DESIGNATION; + + public override string Description + { + get + { + if (_printerName != null) + { + return Language.GetString(LangKey.settings_destination_printer) + " - " + _printerName; + } + + return Language.GetString(LangKey.settings_destination_printer); + } + } + + public override int Priority => 2; + + public override Keys EditorShortcutKeys => Keys.Control | Keys.P; + + public override Image DisplayIcon => GreenshotResources.GetImage("Printer.Image"); + + public override bool IsDynamic => true; + + /// + /// Create destinations for all the installed printers + /// + /// IEnumerable of IDestination + public override IEnumerable DynamicDestinations() + { + PrinterSettings settings = new PrinterSettings(); + string defaultPrinter = settings.PrinterName; + List printers = new List(); + + foreach (string printer in PrinterSettings.InstalledPrinters) + { + printers.Add(printer); + } + + printers.Sort(delegate(string p1, string p2) + { + if (defaultPrinter.Equals(p1)) + { + return -1; + } + + if (defaultPrinter.Equals(p2)) + { + return 1; + } + + return string.Compare(p1, p2, StringComparison.Ordinal); + }); + foreach (string printer in printers) + { + yield return new PrinterDestination(printer); + } + } + + /// + /// Export the capture to the printer + /// + /// + /// + /// + /// ExportInformation + public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) + { + ExportInformation exportInformation = new ExportInformation(Designation, Description); + PrinterSettings printerSettings; + if (!string.IsNullOrEmpty(_printerName)) + { + using PrintHelper printHelper = new PrintHelper(surface, captureDetails); + printerSettings = printHelper.PrintTo(_printerName); + } + else if (!manuallyInitiated) + { + PrinterSettings settings = new PrinterSettings(); + using PrintHelper printHelper = new PrintHelper(surface, captureDetails); + printerSettings = printHelper.PrintTo(settings.PrinterName); + } + else + { + using PrintHelper printHelper = new PrintHelper(surface, captureDetails); + printerSettings = printHelper.PrintWithDialog(); + } + + if (printerSettings != null) + { + exportInformation.ExportMade = true; + } + + ProcessExport(exportInformation, surface); + return exportInformation; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs b/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs new file mode 100644 index 000000000..37057d428 --- /dev/null +++ b/src/Greenshot/Drawing/Adorners/AbstractAdorner.cs @@ -0,0 +1,156 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing.Adorners; + +namespace Greenshot.Drawing.Adorners +{ + public class AbstractAdorner : IAdorner + { + public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE; + + private static readonly Size DefaultSize = new Size(6, 6); + protected Size _size; + + public AbstractAdorner(IDrawableContainer owner) + { + _size = DpiHelper.ScaleWithDpi(DefaultSize, 0); + Owner = owner; + } + + /// + /// Returns the cursor for when the mouse is over the adorner + /// + public virtual Cursor Cursor + { + get { return Cursors.SizeAll; } + } + + public virtual IDrawableContainer Owner { get; set; } + + /// + /// Test if the point is inside the adorner + /// + /// + /// + public virtual bool HitTest(Point point) + { + Rectangle hitBounds = Bounds; + hitBounds.Inflate(3, 3); + return hitBounds.Contains(point); + } + + /// + /// Handle the mouse down + /// + /// + /// + public virtual void MouseDown(object sender, MouseEventArgs mouseEventArgs) + { + } + + /// + /// Handle the mouse move + /// + /// + /// + public virtual void MouseMove(object sender, MouseEventArgs mouseEventArgs) + { + } + + /// + /// Handle the mouse up + /// + /// + /// + public virtual void MouseUp(object sender, MouseEventArgs mouseEventArgs) + { + EditStatus = EditStatus.IDLE; + } + + /// + /// Return the location of the adorner + /// + public virtual Point Location { get; set; } + + /// + /// Return the bounds of the Adorner + /// + public virtual Rectangle Bounds + { + get + { + Point location = Location; + return new Rectangle(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height); + } + } + + /// + /// Return the bounds of the Adorner as displayed on the parent Surface + /// + protected virtual Rectangle BoundsOnSurface + { + get + { + Point displayLocation = Owner.Parent.ToSurfaceCoordinates(Location); + return new Rectangle(displayLocation.X - _size.Width / 2, displayLocation.Y - _size.Height / 2, _size.Width, _size.Height); + } + } + + /// + /// The adorner is active if the edit status is not idle or undrawn + /// + public virtual bool IsActive + { + get { return EditStatus != EditStatus.IDLE && EditStatus != EditStatus.UNDRAWN; } + } + + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// uint + public void AdjustToDpi(uint dpi) + { + _size = DpiHelper.ScaleWithDpi(DefaultSize, dpi); + } + + /// + /// Draw the adorner + /// + /// PaintEventArgs + public virtual void Paint(PaintEventArgs paintEventArgs) + { + } + + /// + /// We ignore the Transform, as the coordinates are directly bound to those of the owner + /// + /// + public virtual void Transform(Matrix matrix) + { + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Adorners/MoveAdorner.cs b/src/Greenshot/Drawing/Adorners/MoveAdorner.cs new file mode 100644 index 000000000..9116ff3cf --- /dev/null +++ b/src/Greenshot/Drawing/Adorners/MoveAdorner.cs @@ -0,0 +1,166 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Helpers; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Adorners +{ + /// + /// This is the adorner for the line based containers + /// + public class MoveAdorner : AbstractAdorner + { + private Rectangle _boundsBeforeResize = Rectangle.Empty; + private RectangleF _boundsAfterResize = RectangleF.Empty; + + public Positions Position { get; private set; } + + public MoveAdorner(IDrawableContainer owner, Positions position) : base(owner) + { + Position = position; + } + + /// + /// Returns the cursor for when the mouse is over the adorner + /// + public override Cursor Cursor => Cursors.SizeAll; + + /// + /// Handle the mouse down + /// + /// + /// + public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) + { + EditStatus = EditStatus.RESIZING; + _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); + _boundsAfterResize = _boundsBeforeResize; + } + + /// + /// Handle the mouse move + /// + /// + /// + public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) + { + if (EditStatus != EditStatus.RESIZING) + { + return; + } + + Owner.Invalidate(); + Owner.MakeBoundsChangeUndoable(false); + + // reset "workbench" rectangle to current bounds + _boundsAfterResize.X = _boundsBeforeResize.X; + _boundsAfterResize.Y = _boundsBeforeResize.Y; + _boundsAfterResize.Width = _boundsBeforeResize.Width; + _boundsAfterResize.Height = _boundsBeforeResize.Height; + + // calculate scaled rectangle + ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); + + // apply scaled bounds to this DrawableContainer + Owner.ApplyBounds(_boundsAfterResize); + + Owner.Invalidate(); + } + + /// + /// Return the location of the adorner + /// + public override Point Location + { + get + { + int x = 0, y = 0; + switch (Position) + { + case Positions.TopLeft: + x = Owner.Left; + y = Owner.Top; + break; + case Positions.BottomLeft: + x = Owner.Left; + y = Owner.Top + Owner.Height; + break; + case Positions.MiddleLeft: + x = Owner.Left; + y = Owner.Top + (Owner.Height / 2); + break; + case Positions.TopCenter: + x = Owner.Left + (Owner.Width / 2); + y = Owner.Top; + break; + case Positions.BottomCenter: + x = Owner.Left + (Owner.Width / 2); + y = Owner.Top + Owner.Height; + break; + case Positions.TopRight: + x = Owner.Left + Owner.Width; + y = Owner.Top; + break; + case Positions.BottomRight: + x = Owner.Left + Owner.Width; + y = Owner.Top + Owner.Height; + break; + case Positions.MiddleRight: + x = Owner.Left + Owner.Width; + y = Owner.Top + (Owner.Height / 2); + break; + } + + return new Point(x, y); + } + } + + /// + /// Draw the adorner + /// + /// PaintEventArgs + public override void Paint(PaintEventArgs paintEventArgs) + { + Graphics targetGraphics = paintEventArgs.Graphics; + + var bounds = BoundsOnSurface; + GraphicsState state = targetGraphics.Save(); + + targetGraphics.CompositingMode = CompositingMode.SourceCopy; + + try + { + targetGraphics.FillRectangle(Brushes.Black, bounds); + targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); + } + catch + { + // Ignore, BUG-2065 + } + + targetGraphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs b/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs new file mode 100644 index 000000000..38c1eb9af --- /dev/null +++ b/src/Greenshot/Drawing/Adorners/ResizeAdorner.cs @@ -0,0 +1,186 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Helpers; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Adorners +{ + /// + /// This is the default "legacy" gripper adorner, not the one used for the tail in the speech-bubble + /// + public class ResizeAdorner : AbstractAdorner + { + private Rectangle _boundsBeforeResize = Rectangle.Empty; + private RectangleF _boundsAfterResize = RectangleF.Empty; + + public Positions Position { get; private set; } + + public ResizeAdorner(IDrawableContainer owner, Positions position) : base(owner) + { + Position = position; + } + + /// + /// Returns the cursor for when the mouse is over the adorner + /// + public override Cursor Cursor + { + get + { + bool isNotSwitched = Owner.Width >= 0; + if (Owner.Height < 0) + { + isNotSwitched = !isNotSwitched; + } + + switch (Position) + { + case Positions.TopLeft: + case Positions.BottomRight: + return isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW; + case Positions.TopRight: + case Positions.BottomLeft: + return isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE; + case Positions.MiddleLeft: + case Positions.MiddleRight: + return Cursors.SizeWE; + case Positions.TopCenter: + case Positions.BottomCenter: + return Cursors.SizeNS; + default: + return Cursors.SizeAll; + } + } + } + + /// + /// Handle the mouse down + /// + /// + /// + public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) + { + EditStatus = EditStatus.RESIZING; + _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); + _boundsAfterResize = _boundsBeforeResize; + } + + /// + /// Handle the mouse move + /// + /// + /// + public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) + { + if (EditStatus != EditStatus.RESIZING) + { + return; + } + + Owner.Invalidate(); + Owner.MakeBoundsChangeUndoable(false); + + // reset "workbench" rectangle to current bounds + _boundsAfterResize.X = _boundsBeforeResize.X; + _boundsAfterResize.Y = _boundsBeforeResize.Y; + _boundsAfterResize.Width = _boundsBeforeResize.Width; + _boundsAfterResize.Height = _boundsBeforeResize.Height; + + // calculate scaled rectangle + ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); + + // apply scaled bounds to this DrawableContainer + Owner.ApplyBounds(_boundsAfterResize); + + Owner.Invalidate(); + } + + /// + /// Return the location of the adorner + /// + public override Point Location + { + get + { + int x = 0, y = 0; + switch (Position) + { + case Positions.TopLeft: + x = Owner.Left; + y = Owner.Top; + break; + case Positions.BottomLeft: + x = Owner.Left; + y = Owner.Top + Owner.Height; + break; + case Positions.MiddleLeft: + x = Owner.Left; + y = Owner.Top + (Owner.Height / 2); + break; + case Positions.TopCenter: + x = Owner.Left + (Owner.Width / 2); + y = Owner.Top; + break; + case Positions.BottomCenter: + x = Owner.Left + (Owner.Width / 2); + y = Owner.Top + Owner.Height; + break; + case Positions.TopRight: + x = Owner.Left + Owner.Width; + y = Owner.Top; + break; + case Positions.BottomRight: + x = Owner.Left + Owner.Width; + y = Owner.Top + Owner.Height; + break; + case Positions.MiddleRight: + x = Owner.Left + Owner.Width; + y = Owner.Top + (Owner.Height / 2); + break; + } + + return new Point(x, y); + } + } + + /// + /// Draw the adorner + /// + /// PaintEventArgs + public override void Paint(PaintEventArgs paintEventArgs) + { + Graphics targetGraphics = paintEventArgs.Graphics; + + var bounds = BoundsOnSurface; + GraphicsState state = targetGraphics.Save(); + + targetGraphics.CompositingMode = CompositingMode.SourceCopy; + + targetGraphics.FillRectangle(Brushes.Black, bounds); + targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); + targetGraphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Adorners/TargetAdorner.cs b/src/Greenshot/Drawing/Adorners/TargetAdorner.cs new file mode 100644 index 000000000..2569ae8c3 --- /dev/null +++ b/src/Greenshot/Drawing/Adorners/TargetAdorner.cs @@ -0,0 +1,125 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on Sourceforge: http://sourceforge.net/projects/greenshot/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Adorners +{ + /// + /// This implements the special "gripper" for the Speech-Bubble tail + /// + public class TargetAdorner : AbstractAdorner + { + public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) + { + Location = location; + } + + /// + /// Handle the mouse down + /// + /// + /// + public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) + { + EditStatus = EditStatus.MOVING; + } + + /// + /// Handle the mouse move + /// + /// + /// + public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) + { + if (EditStatus != EditStatus.MOVING) + { + return; + } + + Owner.Invalidate(); + Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); + Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height); + // Check if gripper inside the parent (surface), if not we need to move it inside + // This was made for BUG-1682 + if (!imageBounds.Contains(newGripperLocation)) + { + if (newGripperLocation.X > imageBounds.Right) + { + newGripperLocation.X = imageBounds.Right - 5; + } + + if (newGripperLocation.X < imageBounds.Left) + { + newGripperLocation.X = imageBounds.Left; + } + + if (newGripperLocation.Y > imageBounds.Bottom) + { + newGripperLocation.Y = imageBounds.Bottom - 5; + } + + if (newGripperLocation.Y < imageBounds.Top) + { + newGripperLocation.Y = imageBounds.Top; + } + } + + Location = newGripperLocation; + Owner.Invalidate(); + } + + /// + /// Draw the adorner + /// + /// PaintEventArgs + public override void Paint(PaintEventArgs paintEventArgs) + { + Graphics targetGraphics = paintEventArgs.Graphics; + + var bounds = BoundsOnSurface; + targetGraphics.FillRectangle(Brushes.Green, bounds); + targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); + } + + /// + /// Made sure this adorner is transformed + /// + /// Matrix + public override void Transform(Matrix matrix) + { + if (matrix == null) + { + return; + } + + Point[] points = new[] + { + Location + }; + matrix.TransformPoints(points); + Location = points[0]; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/ArrowContainer.cs b/src/Greenshot/Drawing/ArrowContainer.cs new file mode 100644 index 000000000..eaed428f0 --- /dev/null +++ b/src/Greenshot/Drawing/ArrowContainer.cs @@ -0,0 +1,163 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Drawing.Fields; + +namespace Greenshot.Drawing +{ + /// + /// Description of LineContainer. + /// + [Serializable()] + public class ArrowContainer : LineContainer + { + public enum ArrowHeadCombination + { + NONE, + START_POINT, + END_POINT, + BOTH + }; + + private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6); + + public ArrowContainer(Surface parent) : base(parent) + { + } + + /// + /// Do not use the base, just override so we have our own defaults + /// + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.ARROWHEADS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); + AddField(GetType(), FieldType.SHADOW, true); + AddField(GetType(), FieldType.ARROWHEADS, ArrowHeadCombination.END_POINT); + } + + public override void Draw(Graphics graphics, RenderMode rm) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + + if (lineThickness > 0) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + ArrowHeadCombination heads = (ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS); + if (lineThickness > 0) + { + if (shadow) + { + //draw shadow first + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = 1; + while (currentStep <= steps) + { + using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); + SetArrowHeads(heads, shadowCapPen); + + graphics.DrawLine(shadowCapPen, + Left + currentStep, + Top + currentStep, + Left + currentStep + Width, + Top + currentStep + Height); + + currentStep++; + alpha -= basealpha / steps; + } + } + + using Pen pen = new Pen(lineColor, lineThickness); + SetArrowHeads(heads, pen); + graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); + } + } + } + + private void SetArrowHeads(ArrowHeadCombination heads, Pen pen) + { + if (heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.START_POINT) + { + pen.CustomStartCap = ARROW_CAP; + } + + if (heads == ArrowHeadCombination.BOTH || heads == ArrowHeadCombination.END_POINT) + { + pen.CustomEndCap = ARROW_CAP; + } + } + + public override Rectangle DrawingBounds + { + get + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + if (lineThickness > 0) + { + using Pen pen = new Pen(Color.White) + { + Width = lineThickness + }; + SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS), pen); + using GraphicsPath path = new GraphicsPath(); + path.AddLine(Left, Top, Left + Width, Top + Height); + using Matrix matrix = new Matrix(); + Rectangle drawingBounds = Rectangle.Round(path.GetBounds(matrix, pen)); + drawingBounds.Inflate(2, 2); + return drawingBounds; + } + + return Rectangle.Empty; + } + } + + public override bool ClickableAt(int x, int y) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; + if (lineThickness > 0) + { + using Pen pen = new Pen(Color.White) + { + Width = lineThickness + }; + SetArrowHeads((ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS), pen); + using GraphicsPath path = new GraphicsPath(); + path.AddLine(Left, Top, Left + Width, Top + Height); + return path.IsOutlineVisible(x, y, pen); + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/CropContainer.cs b/src/Greenshot/Drawing/CropContainer.cs new file mode 100644 index 000000000..6c89f37d4 --- /dev/null +++ b/src/Greenshot/Drawing/CropContainer.cs @@ -0,0 +1,108 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; + +namespace Greenshot.Drawing +{ + /// + /// Description of CropContainer. + /// + public class CropContainer : DrawableContainer + { + public CropContainer(Surface parent) : base(parent) + { + Init(); + } + + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } + + private void Init() + { + CreateDefaultAdorners(); + } + + protected override void InitializeFields() + { + AddField(GetType(), FieldType.FLAGS, FieldFlag.CONFIRMABLE); + } + + public override void Invalidate() + { + _parent?.Invalidate(); + } + + /// + /// We need to override the DrawingBound, return a rectangle in the size of the image, to make sure this element is always draw + /// (we create a transparent brown over the complete picture) + /// + public override Rectangle DrawingBounds + { + get + { + if (_parent?.Image is { } image) + { + return new Rectangle(0, 0, image.Width, image.Height); + } + + return Rectangle.Empty; + } + } + + public override void Draw(Graphics g, RenderMode rm) + { + if (_parent == null) + { + return; + } + + using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100)); + Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + Rectangle selectionRect = new Rectangle(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1); + Size imageSize = _parent.Image.Size; + + DrawSelectionBorder(g, selectionRect); + + // top + g.FillRectangle(cropBrush, new Rectangle(0, 0, imageSize.Width, cropRectangle.Top)); + // left + g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); + // right + g.FillRectangle(cropBrush, + new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); + // bottom + g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height))); + } + + /// + /// No context menu for the CropContainer + /// + public override bool HasContextMenu => false; + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/CursorContainer.cs b/src/Greenshot/Drawing/CursorContainer.cs new file mode 100644 index 000000000..c961c4d22 --- /dev/null +++ b/src/Greenshot/Drawing/CursorContainer.cs @@ -0,0 +1,128 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using System.Drawing.Drawing2D; +using log4net; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing +{ + /// + /// Description of CursorContainer. + /// + [Serializable] + public class CursorContainer : DrawableContainer, ICursorContainer + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(CursorContainer)); + + protected Cursor cursor; + + public CursorContainer(Surface parent) : base(parent) + { + Init(); + } + + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } + + private void Init() + { + CreateDefaultAdorners(); + } + + public CursorContainer(Surface parent, string filename) : this(parent) + { + Load(filename); + } + + public Cursor Cursor + { + set + { + if (cursor != null) + { + cursor.Dispose(); + } + + // Clone cursor (is this correct??) + cursor = new Cursor(value.CopyHandle()); + Width = value.Size.Width; + Height = value.Size.Height; + } + get { return cursor; } + } + + /// + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (cursor != null) + { + cursor.Dispose(); + } + } + + cursor = null; + base.Dispose(disposing); + } + + public void Load(string filename) + { + if (!File.Exists(filename)) + { + return; + } + + using Cursor fileCursor = new Cursor(filename); + Cursor = fileCursor; + LOG.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); + } + + public override void Draw(Graphics graphics, RenderMode rm) + { + if (cursor == null) + { + return; + } + + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.CompositingQuality = CompositingQuality.Default; + graphics.PixelOffsetMode = PixelOffsetMode.None; + cursor.DrawStretched(graphics, Bounds); + } + + public override Size DefaultSize => cursor?.Size ?? new Size(16, 16); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/DrawableContainer.cs b/src/Greenshot/Drawing/DrawableContainer.cs new file mode 100644 index 000000000..4e710e6be --- /dev/null +++ b/src/Greenshot/Drawing/DrawableContainer.cs @@ -0,0 +1,670 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Configuration; +using Greenshot.Drawing.Adorners; +using Greenshot.Drawing.Fields; +using Greenshot.Drawing.Filters; +using Greenshot.Helpers; +using Greenshot.Memento; +using log4net; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Runtime.Serialization; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing.Adorners; + +namespace Greenshot.Drawing +{ + /// + /// represents a rectangle, ellipse, label or whatever. Can contain filters, too. + /// serializable for clipboard support + /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call + /// OnPropertyChanged whenever a public property has been changed. + /// + [Serializable] + public abstract class DrawableContainer : AbstractFieldHolderWithChildren, IDrawableContainer + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(DrawableContainer)); + protected static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); + private const int M11 = 0; + private const int M22 = 3; + + [OnDeserialized] + private void OnDeserializedInit(StreamingContext context) + { + _adorners = new List(); + OnDeserialized(context); + } + + /// + /// Override to implement your own deserialization logic, like initializing properties which are not serialized + /// + /// + protected virtual void OnDeserialized(StreamingContext streamingContext) + { + } + + protected EditStatus _defaultEditMode = EditStatus.DRAWING; + + public EditStatus DefaultEditMode + { + get { return _defaultEditMode; } + } + + /// + /// The public accessible Dispose + /// Will call the GarbageCollector to SuppressFinalize, preventing being cleaned twice + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!disposing) + { + return; + } + + _parent?.FieldAggregator?.UnbindElement(this); + } + + ~DrawableContainer() + { + Dispose(false); + } + + [NonSerialized] private PropertyChangedEventHandler _propertyChanged; + + public event PropertyChangedEventHandler PropertyChanged + { + add => _propertyChanged += value; + remove => _propertyChanged -= value; + } + + public IList Filters + { + get + { + List ret = new List(); + foreach (IFieldHolder c in Children) + { + if (c is IFilter) + { + ret.Add(c as IFilter); + } + } + + return ret; + } + } + + [NonSerialized] internal Surface _parent; + + public ISurface Parent + { + get => _parent; + set => SwitchParent((Surface) value); + } + + [NonSerialized] private TargetAdorner _targetAdorner; + public TargetAdorner TargetAdorner => _targetAdorner; + + [NonSerialized] private bool _selected; + + public bool Selected + { + get => _selected; + set + { + _selected = value; + OnPropertyChanged("Selected"); + } + } + + [NonSerialized] private EditStatus _status = EditStatus.UNDRAWN; + + public EditStatus Status + { + get => _status; + set => _status = value; + } + + + private int left; + + public int Left + { + get => left; + set + { + if (value == left) + { + return; + } + + left = value; + } + } + + private int top; + + public int Top + { + get => top; + set + { + if (value == top) + { + return; + } + + top = value; + } + } + + private int width; + + public int Width + { + get => width; + set + { + if (value == width) + { + return; + } + + width = value; + } + } + + private int height; + + public int Height + { + get => height; + set + { + if (value == height) + { + return; + } + + height = value; + } + } + + public Point Location + { + get => new Point(left, top); + set + { + left = value.X; + top = value.Y; + } + } + + public Size Size + { + get => new Size(width, height); + set + { + width = value.Width; + height = value.Height; + } + } + + /// + /// List of available Adorners + /// + [NonSerialized] private IList _adorners = new List(); + + public IList Adorners => _adorners; + + [NonSerialized] + // will store current bounds of this DrawableContainer before starting a resize + protected Rectangle _boundsBeforeResize = Rectangle.Empty; + + [NonSerialized] + // "workbench" rectangle - used for calculating bounds during resizing (to be applied to this DrawableContainer afterwards) + protected RectangleF _boundsAfterResize = RectangleF.Empty; + + public Rectangle Bounds + { + get => GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + set + { + Left = Round(value.Left); + Top = Round(value.Top); + Width = Round(value.Width); + Height = Round(value.Height); + } + } + + public virtual void ApplyBounds(RectangleF newBounds) + { + Left = Round(newBounds.Left); + Top = Round(newBounds.Top); + Width = Round(newBounds.Width); + Height = Round(newBounds.Height); + } + + public DrawableContainer(Surface parent) + { + InitializeFields(); + _parent = parent; + } + + public void Add(IFilter filter) + { + AddChild(filter); + } + + public void Remove(IFilter filter) + { + RemoveChild(filter); + } + + private static int Round(float f) + { + if (float.IsPositiveInfinity(f) || f > int.MaxValue / 2) return int.MaxValue / 2; + if (float.IsNegativeInfinity(f) || f < int.MinValue / 2) return int.MinValue / 2; + return (int) Math.Round(f); + } + + private bool accountForShadowChange; + + public virtual Rectangle DrawingBounds + { + get + { + foreach (IFilter filter in Filters) + { + if (filter.Invert) + { + return new Rectangle(Point.Empty, _parent.Image.Size); + } + } + + // Take a base safety margin + int lineThickness = 5; + + // add adorner size + lineThickness += Adorners.Max(adorner => Math.Max(adorner.Bounds.Width, adorner.Bounds.Height)); + + if (HasField(FieldType.LINE_THICKNESS)) + { + lineThickness += GetFieldValueAsInt(FieldType.LINE_THICKNESS); + } + + int offset = lineThickness / 2; + + int shadow = 0; + if (accountForShadowChange || (HasField(FieldType.SHADOW) && GetFieldValueAsBool(FieldType.SHADOW))) + { + accountForShadowChange = false; + shadow += 10; + } + + return new Rectangle(Bounds.Left - offset, Bounds.Top - offset, Bounds.Width + lineThickness + shadow, Bounds.Height + lineThickness + shadow); + } + } + + public virtual void Invalidate() + { + if (Status != EditStatus.UNDRAWN) + { + _parent?.InvalidateElements(DrawingBounds); + } + } + + public virtual bool InitContent() + { + return true; + } + + public virtual void OnDoubleClick() + { + } + + /// + /// Initialize a target gripper + /// + protected void InitAdorner(Color gripperColor, Point location) + { + _targetAdorner = new TargetAdorner(this, location); + Adorners.Add(_targetAdorner); + } + + /// + /// Create the default adorners for a rectangle based container + /// + protected void CreateDefaultAdorners() + { + if (Adorners.Count > 0) + { + LOG.Warn("Adorners are already defined!"); + } + + // Create the GripperAdorners + Adorners.Add(new ResizeAdorner(this, Positions.TopLeft)); + Adorners.Add(new ResizeAdorner(this, Positions.TopCenter)); + Adorners.Add(new ResizeAdorner(this, Positions.TopRight)); + Adorners.Add(new ResizeAdorner(this, Positions.BottomLeft)); + Adorners.Add(new ResizeAdorner(this, Positions.BottomCenter)); + Adorners.Add(new ResizeAdorner(this, Positions.BottomRight)); + Adorners.Add(new ResizeAdorner(this, Positions.MiddleLeft)); + Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight)); + } + + public bool hasFilters => Filters.Count > 0; + + public abstract void Draw(Graphics graphics, RenderMode renderMode); + + public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle) + { + if (Children.Count > 0) + { + if (Status != EditStatus.IDLE) + { + DrawSelectionBorder(graphics, Bounds); + } + else + { + if (clipRectangle.Width != 0 && clipRectangle.Height != 0) + { + foreach (IFilter filter in Filters) + { + if (filter.Invert) + { + filter.Apply(graphics, bmp, Bounds, renderMode); + } + else + { + Rectangle drawingRect = new Rectangle(Bounds.Location, Bounds.Size); + drawingRect.Intersect(clipRectangle); + if (filter is MagnifierFilter) + { + // quick&dirty bugfix, because MagnifierFilter behaves differently when drawn only partially + // what we should actually do to resolve this is add a better magnifier which is not that special + filter.Apply(graphics, bmp, Bounds, renderMode); + } + else + { + filter.Apply(graphics, bmp, drawingRect, renderMode); + } + } + } + } + } + } + + Draw(graphics, renderMode); + } + + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// uint with dpi value + public void AdjustToDpi(uint dpi) + { + foreach (var adorner in Adorners) + { + adorner.AdjustToDpi(dpi); + } + } + + public virtual bool Contains(int x, int y) + { + return Bounds.Contains(x, y); + } + + public virtual bool ClickableAt(int x, int y) + { + Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + r.Inflate(5, 5); + return r.Contains(x, y); + } + + protected void DrawSelectionBorder(Graphics g, Rectangle rect) + { + using Pen pen = new Pen(Color.MediumSeaGreen) + { + DashPattern = new float[] + { + 1, 2 + }, + Width = 1 + }; + g.DrawRectangle(pen, rect); + } + + + public void ResizeTo(int width, int height, int anchorPosition) + { + Width = width; + Height = height; + } + + /// + /// Make a following bounds change on this drawablecontainer undoable! + /// + /// true means allow the moves to be merged + public void MakeBoundsChangeUndoable(bool allowMerge) + { + _parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); + } + + public void MoveBy(int dx, int dy) + { + Left += dx; + Top += dy; + } + + /// + /// A handler for the MouseDown, used if you don't want the surface to handle this for you + /// + /// current mouse x + /// current mouse y + /// true if the event is handled, false if the surface needs to handle it + public virtual bool HandleMouseDown(int x, int y) + { + Left = _boundsBeforeResize.X = x; + Top = _boundsBeforeResize.Y = y; + return true; + } + + /// + /// A handler for the MouseMove, used if you don't want the surface to handle this for you + /// + /// current mouse x + /// current mouse y + /// true if the event is handled, false if the surface needs to handle it + public virtual bool HandleMouseMove(int x, int y) + { + Invalidate(); + + // reset "workrbench" rectangle to current bounds + _boundsAfterResize.X = _boundsBeforeResize.Left; + _boundsAfterResize.Y = _boundsBeforeResize.Top; + _boundsAfterResize.Width = x - _boundsAfterResize.Left; + _boundsAfterResize.Height = y - _boundsAfterResize.Top; + + ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); + + // apply scaled bounds to this DrawableContainer + ApplyBounds(_boundsAfterResize); + + Invalidate(); + return true; + } + + /// + /// A handler for the MouseUp + /// + /// current mouse x + /// current mouse y + public virtual void HandleMouseUp(int x, int y) + { + } + + protected virtual void SwitchParent(Surface newParent) + { + if (newParent == Parent) + { + return; + } + + _parent?.FieldAggregator?.UnbindElement(this); + + _parent = newParent; + foreach (IFilter filter in Filters) + { + filter.Parent = this; + } + } + + protected void OnPropertyChanged(string propertyName) + { + if (_propertyChanged != null) + { + _propertyChanged(this, new PropertyChangedEventArgs(propertyName)); + Invalidate(); + } + } + + /// + /// This method will be called before a field is changes. + /// Using this makes it possible to invalidate the object as is before changing. + /// + /// The field to be changed + /// The new value + public virtual void BeforeFieldChange(IField fieldToBeChanged, object newValue) + { + _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); + Invalidate(); + } + + /// + /// Handle the field changed event, this should invalidate the correct bounds (e.g. when shadow comes or goes more pixels!) + /// + /// + /// + public void HandleFieldChanged(object sender, FieldChangedEventArgs e) + { + LOG.DebugFormat("Field {0} changed", e.Field.FieldType); + if (Equals(e.Field.FieldType, FieldType.SHADOW)) + { + accountForShadowChange = true; + } + } + + /// + /// Retrieve the Y scale from the matrix + /// + /// + /// + public static float CalculateScaleY(Matrix matrix) + { + return matrix.Elements[M22]; + } + + /// + /// Retrieve the X scale from the matrix + /// + /// + /// + public static float CalculateScaleX(Matrix matrix) + { + return matrix.Elements[M11]; + } + + /// + /// Retrieve the rotation angle from the matrix + /// + /// + /// + public static int CalculateAngle(Matrix matrix) + { + const int M11 = 0; + const int M21 = 2; + var radians = Math.Atan2(matrix.Elements[M21], matrix.Elements[M11]); + return (int) -Math.Round(radians * 180 / Math.PI); + } + + /// + /// This method is called on a DrawableContainers when: + /// 1) The capture on the surface is modified in such a way, that the elements would not be placed correctly. + /// 2) Currently not implemented: an element needs to be moved, scaled or rotated. + /// This basis implementation makes sure the coordinates of the element, including the TargetGripper, is correctly rotated/scaled/translated. + /// But this implementation doesn't take care of any changes to the content!! + /// + /// + public virtual void Transform(Matrix matrix) + { + if (matrix == null) + { + return; + } + + Point topLeft = new Point(Left, Top); + Point bottomRight = new Point(Left + Width, Top + Height); + Point[] points = new[] + { + topLeft, bottomRight + }; + matrix.TransformPoints(points); + + Left = points[0].X; + Top = points[0].Y; + Width = points[1].X - points[0].X; + Height = points[1].Y - points[0].Y; + } + + protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() + { + return ScaleHelper.ShapeAngleRoundBehavior.Instance; + } + + public virtual bool HasContextMenu => true; + + public virtual bool HasDefaultSize => false; + + public virtual Size DefaultSize => throw new NotSupportedException("Object doesn't have a default size"); + + /// + /// Allows to override the initializing of the fields, so we can actually have our own defaults + /// + protected virtual void InitializeFields() + { + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/DrawableContainerList.cs b/src/Greenshot/Drawing/DrawableContainerList.cs new file mode 100644 index 000000000..8dc490013 --- /dev/null +++ b/src/Greenshot/Drawing/DrawableContainerList.cs @@ -0,0 +1,728 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Configuration; +using Greenshot.Memento; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Threading; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Forms; + +namespace Greenshot.Drawing +{ + /// + /// Dispatches most of a DrawableContainer's public properties and methods to a list of DrawableContainers. + /// + [Serializable] + public class DrawableContainerList : List, IDrawableContainerList + { + private static readonly ComponentResourceManager EditorFormResources = new ComponentResourceManager(typeof(ImageEditorForm)); + + public Guid ParentID { get; private set; } + + public DrawableContainerList() + { + } + + public DrawableContainerList(Guid parentId) + { + ParentID = parentId; + } + + public EditStatus Status + { + get { return this[Count - 1].Status; } + set + { + foreach (var dc in this) + { + dc.Status = value; + } + } + } + + public List AsIDrawableContainerList() + { + List interfaceList = new List(); + foreach (IDrawableContainer container in this) + { + interfaceList.Add(container); + } + + return interfaceList; + } + + /// + /// Gets or sets the selection status of the elements. + /// If several elements are in the list, true is only returned when all elements are selected. + /// + public bool Selected + { + get + { + bool ret = true; + foreach (var dc in this) + { + ret &= dc.Selected; + } + + return ret; + } + set + { + foreach (var dc in this) + { + dc.Selected = value; + } + } + } + + /// + /// Gets or sets the parent control of the elements in the list. + /// If there are several elements, the parent control of the last added is returned. + /// + public ISurface Parent + { + get + { + if (Count > 0) + { + return this[Count - 1].Parent; + } + + return null; + } + set + { + ParentID = value?.ID ?? Guid.NewGuid(); + foreach (var drawableContainer in this) + { + var dc = (DrawableContainer) drawableContainer; + dc.Parent = value; + } + } + } + + /// + /// Make a following bounds change on this containerlist undoable! + /// + /// true means allow the moves to be merged + public void MakeBoundsChangeUndoable(bool allowMerge) + { + if (Count > 0 && Parent != null) + { + var clone = new DrawableContainerList(); + clone.AddRange(this); + Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge); + } + } + + /// + /// Apply matrix to all elements + /// + public void Transform(Matrix matrix) + { + // Track modifications + bool modified = false; + Invalidate(); + foreach (var dc in this) + { + dc.Transform(matrix); + modified = true; + } + + // Invalidate after + Invalidate(); + // If we moved something, tell the surface it's modified! + if (modified) + { + Parent.Modified = true; + } + } + + /// + /// Moves all elements in the list by the given amount of pixels. + /// + /// pixels to move horizontally + /// pixels to move vertically + public void MoveBy(int dx, int dy) + { + // Track modifications + bool modified = false; + + // Invalidate before moving, otherwise the old locations aren't refreshed + Invalidate(); + foreach (var dc in this) + { + dc.Left += dx; + dc.Top += dy; + modified = true; + } + + // Invalidate after + Invalidate(); + + // If we moved something, tell the surface it's modified! + if (modified) + { + Parent.Modified = true; + } + } + + /// + /// Indicates whether on of the elements is clickable at the given location + /// + /// x coordinate to be checked + /// y coordinate to be checked + /// true if one of the elements in the list is clickable at the given location, false otherwise + public bool ClickableAt(int x, int y) + { + bool ret = false; + foreach (var dc in this) + { + ret |= dc.ClickableAt(x, y); + } + + return ret; + } + + /// + /// retrieves the topmost element being clickable at the given location + /// + /// x coordinate to be checked + /// y coordinate to be checked + /// the topmost element from the list being clickable at the given location, null if there is no clickable element + public IDrawableContainer ClickableElementAt(int x, int y) + { + for (int i = Count - 1; i >= 0; i--) + { + if (this[i].ClickableAt(x, y)) + { + return this[i]; + } + } + + return null; + } + + /// + /// Dispatches OnDoubleClick to all elements in the list. + /// + public void OnDoubleClick() + { + foreach (var drawableContainer in this) + { + var dc = (DrawableContainer) drawableContainer; + dc.OnDoubleClick(); + } + } + + /// + /// Check if there are any intersecting filters, if so we need to redraw more + /// + /// + /// true if an filter intersects + public bool HasIntersectingFilters(Rectangle clipRectangle) + { + foreach (var dc in this) + { + if (dc.DrawingBounds.IntersectsWith(clipRectangle) && dc.hasFilters && dc.Status == EditStatus.IDLE) + { + return true; + } + } + + return false; + } + + /// + /// Check if any of the drawableContainers are inside the rectangle + /// + /// + /// + public bool IntersectsWith(Rectangle clipRectangle) + { + foreach (var dc in this) + { + if (dc.DrawingBounds.IntersectsWith(clipRectangle)) + { + return true; + } + } + + return false; + } + + /// + /// A rectangle containing DrawingBounds of all drawableContainers in this list, + /// or empty rectangle if nothing is there. + /// + public Rectangle DrawingBounds + { + get + { + if (Count == 0) + { + return Rectangle.Empty; + } + else + { + var result = this[0].DrawingBounds; + for (int i = 1; i < Count; i++) + { + result = Rectangle.Union(result, this[i].DrawingBounds); + } + + return result; + } + } + } + + /// + /// Triggers all elements in the list ot be redrawn. + /// + /// the to the bitmap related Graphics object + /// Bitmap to draw + /// the rendermode in which the element is to be drawn + /// + public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle) + { + if (Parent == null) + { + return; + } + + foreach (var drawableContainer in this) + { + var dc = (DrawableContainer) drawableContainer; + if (dc.Parent == null) + { + continue; + } + + if (dc.DrawingBounds.IntersectsWith(clipRectangle)) + { + dc.DrawContent(g, bitmap, renderMode, clipRectangle); + } + } + } + + /// + /// Pass the field changed event to all elements in the list + /// + /// + /// + public void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e) + { + foreach (var drawableContainer in this) + { + var dc = (DrawableContainer) drawableContainer; + dc.HandleFieldChanged(sender, e); + } + } + + /// + /// Invalidate the bounds of all the DC's in this list + /// + public void Invalidate() + { + if (Parent == null) + { + return; + } + + Rectangle region = Rectangle.Empty; + foreach (var dc in this) + { + region = Rectangle.Union(region, dc.DrawingBounds); + } + + Parent.InvalidateElements(region); + } + + /// + /// Indicates whether the given list of elements can be pulled up, + /// i.e. whether there is at least one unselected element higher in hierarchy + /// + /// list of elements to pull up + /// true if the elements could be pulled up + public bool CanPullUp(IDrawableContainerList elements) + { + if (elements.Count == 0 || elements.Count == Count) + { + return false; + } + + foreach (var element in elements) + { + if (IndexOf(element) < Count - elements.Count) + { + return true; + } + } + + return false; + } + + /// + /// Pulls one or several elements up one level in hierarchy (z-index). + /// + /// list of elements to pull up + public void PullElementsUp(IDrawableContainerList elements) + { + for (int i = Count - 1; i >= 0; i--) + { + var dc = this[i]; + if (!elements.Contains(dc)) + { + continue; + } + + if (Count > i + 1 && !elements.Contains(this[i + 1])) + { + SwapElements(i, i + 1); + } + } + } + + /// + /// Pulls one or several elements up to the topmost level(s) in hierarchy (z-index). + /// + /// of elements to pull to top + public void PullElementsToTop(IDrawableContainerList elements) + { + var dcs = ToArray(); + foreach (var dc in dcs) + { + if (!elements.Contains(dc)) + { + continue; + } + + Remove(dc); + Add(dc); + Parent.Modified = true; + } + } + + /// + /// Indicates whether the given list of elements can be pushed down, + /// i.e. whether there is at least one unselected element lower in hierarchy + /// + /// list of elements to push down + /// true if the elements could be pushed down + public bool CanPushDown(IDrawableContainerList elements) + { + if (elements.Count == 0 || elements.Count == Count) + { + return false; + } + + foreach (var element in elements) + { + if (IndexOf(element) >= elements.Count) + { + return true; + } + } + + return false; + } + + /// + /// Pushes one or several elements down one level in hierarchy (z-index). + /// + /// list of elements to push down + public void PushElementsDown(IDrawableContainerList elements) + { + for (int i = 0; i < Count; i++) + { + var dc = this[i]; + if (!elements.Contains(dc)) + { + continue; + } + + if ((i > 0) && !elements.Contains(this[i - 1])) + { + SwapElements(i, i - 1); + } + } + } + + /// + /// Pushes one or several elements down to the bottommost level(s) in hierarchy (z-index). + /// + /// of elements to push to bottom + public void PushElementsToBottom(IDrawableContainerList elements) + { + var dcs = ToArray(); + for (int i = dcs.Length - 1; i >= 0; i--) + { + var dc = dcs[i]; + if (!elements.Contains(dc)) + { + continue; + } + + Remove(dc); + Insert(0, dc); + Parent.Modified = true; + } + } + + /// + /// swaps two elements in hierarchy (z-index), + /// checks both indices to be in range + /// + /// index of the 1st element + /// index of the 2nd element + private void SwapElements(int index1, int index2) + { + if (index1 < 0 || index1 >= Count || index2 < 0 || index2 >= Count || index1 == index2) + { + return; + } + + var dc = this[index1]; + this[index1] = this[index2]; + this[index2] = dc; + Parent.Modified = true; + } + + /// + /// Add items to a context menu for the selected item + /// + /// + /// + public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface) + { + bool push = surface.Elements.CanPushDown(this); + bool pull = surface.Elements.CanPullUp(this); + + ToolStripMenuItem item; + + // Pull "up" + if (pull) + { + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uptotop)); + item.Click += delegate + { + surface.Elements.PullElementsToTop(this); + surface.Elements.Invalidate(); + }; + menu.Items.Add(item); + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_uponelevel)); + item.Click += delegate + { + surface.Elements.PullElementsUp(this); + surface.Elements.Invalidate(); + }; + menu.Items.Add(item); + } + + // Push "down" + if (push) + { + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downtobottom)); + item.Click += delegate + { + surface.Elements.PushElementsToBottom(this); + surface.Elements.Invalidate(); + }; + menu.Items.Add(item); + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_downonelevel)); + item.Click += delegate + { + surface.Elements.PushElementsDown(this); + surface.Elements.Invalidate(); + }; + menu.Items.Add(item); + } + + // Duplicate + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_duplicate)); + item.Click += delegate + { + IDrawableContainerList dcs = this.Clone(); + dcs.Parent = surface; + dcs.MoveBy(10, 10); + surface.AddElements(dcs); + surface.DeselectAllElements(); + surface.SelectElements(dcs); + }; + menu.Items.Add(item); + + // Copy + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_copytoclipboard)) + { + Image = (Image) EditorFormResources.GetObject("copyToolStripMenuItem.Image") + }; + item.Click += delegate { ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); }; + menu.Items.Add(item); + + // Cut + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_cuttoclipboard)) + { + Image = (Image) EditorFormResources.GetObject("btnCut.Image") + }; + item.Click += delegate + { + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), this); + surface.RemoveElements(this); + }; + menu.Items.Add(item); + + // Delete + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_deleteelement)) + { + Image = (Image) EditorFormResources.GetObject("removeObjectToolStripMenuItem.Image") + }; + item.Click += delegate { surface.RemoveElements(this); }; + menu.Items.Add(item); + + // Reset + bool canReset = false; + foreach (var drawableContainer in this) + { + var container = (DrawableContainer) drawableContainer; + if (container.HasDefaultSize) + { + canReset = true; + } + } + + if (canReset) + { + item = new ToolStripMenuItem(Language.GetString(LangKey.editor_resetsize)); + //item.Image = ((System.Drawing.Image)(editorFormResources.GetObject("removeObjectToolStripMenuItem.Image"))); + item.Click += delegate + { + MakeBoundsChangeUndoable(false); + foreach (var drawableContainer in this) + { + var container = (DrawableContainer) drawableContainer; + if (!container.HasDefaultSize) + { + continue; + } + + Size defaultSize = container.DefaultSize; + container.MakeBoundsChangeUndoable(false); + container.Width = defaultSize.Width; + container.Height = defaultSize.Height; + } + + surface.Invalidate(); + }; + menu.Items.Add(item); + } + } + + public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface) + { + if (!(iSurface is Surface surface)) + { + return; + } + + bool hasMenu = false; + foreach (var drawableContainer in this) + { + var container = (DrawableContainer) drawableContainer; + if (!container.HasContextMenu) + { + continue; + } + + hasMenu = true; + break; + } + + if (hasMenu) + { + ContextMenuStrip menu = new ContextMenuStrip(); + AddContextMenuItems(menu, surface); + if (menu.Items.Count > 0) + { + menu.Show(surface, surface.ToSurfaceCoordinates(e.Location)); + while (true) + { + if (menu.Visible) + { + Application.DoEvents(); + Thread.Sleep(100); + } + else + { + menu.Dispose(); + break; + } + } + } + } + } + + private bool _disposedValue; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!_disposedValue) + { + if (disposing) + { + foreach (var drawableContainer in this) + { + drawableContainer.Dispose(); + } + } + + _disposedValue = true; + } + } + + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + } + + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// + public void AdjustToDpi(uint dpi) + { + foreach (var drawableContainer in this) + { + drawableContainer.AdjustToDpi(dpi); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/EllipseContainer.cs b/src/Greenshot/Drawing/EllipseContainer.cs new file mode 100644 index 000000000..466cf7a77 --- /dev/null +++ b/src/Greenshot/Drawing/EllipseContainer.cs @@ -0,0 +1,163 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; + +namespace Greenshot.Drawing +{ + /// + /// Description of EllipseContainer. + /// + [Serializable()] + public class EllipseContainer : DrawableContainer + { + public EllipseContainer(Surface parent) : base(parent) + { + CreateDefaultAdorners(); + } + + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); + AddField(GetType(), FieldType.SHADOW, true); + } + + public override void Draw(Graphics graphics, RenderMode renderMode) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + DrawEllipse(rect, graphics, renderMode, lineThickness, lineColor, fillColor, shadow); + } + + /// + /// This allows another container to draw an ellipse + /// + /// + /// + /// + /// + /// + /// + /// + public static void DrawEllipse(Rectangle rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow) + { + bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); + // draw shadow before anything else + if (shadow && (lineVisible || Colors.IsVisible(fillColor))) + { + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = lineVisible ? 1 : 0; + while (currentStep <= steps) + { + using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)) + { + Width = lineVisible ? lineThickness : 1 + }; + Rectangle shadowRect = GuiRectangle.GetGuiRectangle(rect.Left + currentStep, rect.Top + currentStep, rect.Width, rect.Height); + graphics.DrawEllipse(shadowPen, shadowRect); + currentStep++; + alpha -= basealpha / steps; + } + } + + //draw the original shape + if (Colors.IsVisible(fillColor)) + { + using Brush brush = new SolidBrush(fillColor); + graphics.FillEllipse(brush, rect); + } + + if (lineVisible) + { + using Pen pen = new Pen(lineColor, lineThickness); + graphics.DrawEllipse(pen, rect); + } + } + + public override bool Contains(int x, int y) + { + return EllipseContains(this, x, y); + } + + /// + /// Allow the code to be used externally + /// + /// + /// + /// + /// + public static bool EllipseContains(DrawableContainer caller, int x, int y) + { + double xDistanceFromCenter = x - (caller.Left + caller.Width / 2); + double yDistanceFromCenter = y - (caller.Top + caller.Height / 2); + // ellipse: x^2/a^2 + y^2/b^2 = 1 + return Math.Pow(xDistanceFromCenter, 2) / Math.Pow(caller.Width / 2, 2) + Math.Pow(yDistanceFromCenter, 2) / Math.Pow(caller.Height / 2, 2) < 1; + } + + public override bool ClickableAt(int x, int y) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + return EllipseClickableAt(rect, lineThickness, fillColor, x, y); + } + + public static bool EllipseClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) + { + // If we clicked inside the rectangle and it's visible we are clickable at. + if (!Color.Transparent.Equals(fillColor)) + { + if (rect.Contains(x, y)) + { + return true; + } + } + + // check the rest of the lines + if (lineThickness > 0) + { + using Pen pen = new Pen(Color.White, lineThickness); + using GraphicsPath path = new GraphicsPath(); + path.AddEllipse(rect); + return path.IsOutlineVisible(x, y, pen); + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs b/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs new file mode 100644 index 000000000..391299d86 --- /dev/null +++ b/src/Greenshot/Drawing/Fields/AbstractFieldHolder.cs @@ -0,0 +1,192 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Runtime.Serialization; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Configuration; +using log4net; + +namespace Greenshot.Drawing.Fields +{ + /// + /// Basic IFieldHolder implementation, providing access to a set of fields + /// + [Serializable] + public abstract class AbstractFieldHolder : IFieldHolder + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(AbstractFieldHolder)); + private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); + [NonSerialized] private readonly IDictionary _handlers = new Dictionary(); + + /// + /// called when a field's value has changed + /// + [NonSerialized] private FieldChangedEventHandler _fieldChanged; + + public event FieldChangedEventHandler FieldChanged + { + add { _fieldChanged += value; } + remove { _fieldChanged -= value; } + } + + // we keep two Collections of our fields, dictionary for quick access, list for serialization + // this allows us to use default serialization + [NonSerialized] private IDictionary _fieldsByType = new Dictionary(); + private readonly IList fields = new List(); + + [OnDeserialized] + private void OnDeserialized(StreamingContext context) + { + _fieldsByType = new Dictionary(); + // listen to changing properties + foreach (var field in fields) + { + field.PropertyChanged += delegate { _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); }; + _fieldsByType[field.FieldType] = field; + } + } + + public void AddField(Type requestingType, IFieldType fieldType, object fieldValue) + { + AddField(EditorConfig.CreateField(requestingType, fieldType, fieldValue)); + } + + public virtual void AddField(IField field) + { + fields.Add(field); + if (_fieldsByType == null) + { + return; + } + + if (_fieldsByType.ContainsKey(field.FieldType)) + { + if (LOG.IsDebugEnabled) + { + LOG.DebugFormat("A field with of type '{0}' already exists in this {1}, will overwrite.", field.FieldType, GetType()); + } + } + + _fieldsByType[field.FieldType] = field; + + _handlers[field] = (sender, args) => { _fieldChanged?.Invoke(this, new FieldChangedEventArgs(field)); }; + field.PropertyChanged += _handlers[field]; + } + + public void RemoveField(IField field) + { + fields.Remove(field); + _fieldsByType.Remove(field.FieldType); + field.PropertyChanged -= _handlers[field]; + _handlers.Remove(field); + } + + public IList GetFields() + { + return fields; + } + + + public IField GetField(IFieldType fieldType) + { + try + { + return _fieldsByType[fieldType]; + } + catch (KeyNotFoundException e) + { + throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); + } + } + + public object GetFieldValue(IFieldType fieldType) + { + return GetField(fieldType)?.Value; + } + + public string GetFieldValueAsString(IFieldType fieldType) + { + return Convert.ToString(GetFieldValue(fieldType)); + } + + public int GetFieldValueAsInt(IFieldType fieldType) + { + return Convert.ToInt32(GetFieldValue(fieldType)); + } + + public decimal GetFieldValueAsDecimal(IFieldType fieldType) + { + return Convert.ToDecimal(GetFieldValue(fieldType)); + } + + public double GetFieldValueAsDouble(IFieldType fieldType) + { + return Convert.ToDouble(GetFieldValue(fieldType)); + } + + public float GetFieldValueAsFloat(IFieldType fieldType) + { + return Convert.ToSingle(GetFieldValue(fieldType)); + } + + public bool GetFieldValueAsBool(IFieldType fieldType) + { + return Convert.ToBoolean(GetFieldValue(fieldType)); + } + + public Color GetFieldValueAsColor(IFieldType fieldType, Color defaultColor = default) + { + return (Color) (GetFieldValue(fieldType) ?? defaultColor); + } + + public bool HasField(IFieldType fieldType) + { + return _fieldsByType.ContainsKey(fieldType); + } + + public bool HasFieldValue(IFieldType fieldType) + { + return HasField(fieldType) && _fieldsByType[fieldType].HasValue; + } + + public void SetFieldValue(IFieldType fieldType, object value) + { + try + { + _fieldsByType[fieldType].Value = value; + } + catch (KeyNotFoundException e) + { + throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType(), e); + } + } + + protected void OnFieldChanged(object sender, FieldChangedEventArgs e) + { + _fieldChanged?.Invoke(sender, e); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs b/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs new file mode 100644 index 000000000..9e0593280 --- /dev/null +++ b/src/Greenshot/Drawing/Fields/AbstractFieldHolderWithChildren.cs @@ -0,0 +1,149 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Fields +{ + /// + /// Basic IFieldHolderWithChildren implementation. Similar to IFieldHolder, + /// but has a List of IFieldHolder for children. + /// Field values are passed to and from children as well. + /// + [Serializable] + public abstract class AbstractFieldHolderWithChildren : AbstractFieldHolder + { + [NonSerialized] private readonly FieldChangedEventHandler _fieldChangedEventHandler; + + [NonSerialized] private EventHandler childrenChanged; + + public event EventHandler ChildrenChanged + { + add { childrenChanged += value; } + remove { childrenChanged -= value; } + } + + public IList Children = new List(); + + public AbstractFieldHolderWithChildren() + { + _fieldChangedEventHandler = OnFieldChanged; + } + + [OnDeserialized()] + private void OnDeserialized(StreamingContext context) + { + // listen to changing properties + foreach (IFieldHolder fieldHolder in Children) + { + fieldHolder.FieldChanged += _fieldChangedEventHandler; + } + + childrenChanged?.Invoke(this, EventArgs.Empty); + } + + public void AddChild(IFieldHolder fieldHolder) + { + Children.Add(fieldHolder); + fieldHolder.FieldChanged += _fieldChangedEventHandler; + childrenChanged?.Invoke(this, EventArgs.Empty); + } + + public void RemoveChild(IFieldHolder fieldHolder) + { + Children.Remove(fieldHolder); + fieldHolder.FieldChanged -= _fieldChangedEventHandler; + childrenChanged?.Invoke(this, EventArgs.Empty); + } + + public new IList GetFields() + { + var ret = new List(); + ret.AddRange(base.GetFields()); + foreach (IFieldHolder fh in Children) + { + ret.AddRange(fh.GetFields()); + } + + return ret; + } + + public new IField GetField(IFieldType fieldType) + { + IField ret = null; + if (base.HasField(fieldType)) + { + ret = base.GetField(fieldType); + } + else + { + foreach (IFieldHolder fh in Children) + { + if (fh.HasField(fieldType)) + { + ret = fh.GetField(fieldType); + break; + } + } + } + + if (ret == null) + { + throw new ArgumentException("Field '" + fieldType + "' does not exist in " + GetType()); + } + + return ret; + } + + public new bool HasField(IFieldType fieldType) + { + bool ret = base.HasField(fieldType); + if (!ret) + { + foreach (IFieldHolder fh in Children) + { + if (fh.HasField(fieldType)) + { + ret = true; + break; + } + } + } + + return ret; + } + + public new bool HasFieldValue(IFieldType fieldType) + { + IField f = GetField(fieldType); + return f != null && f.HasValue; + } + + public new void SetFieldValue(IFieldType fieldType, object value) + { + IField f = GetField(fieldType); + if (f != null) f.Value = value; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs b/src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs new file mode 100644 index 000000000..9870db505 --- /dev/null +++ b/src/Greenshot/Drawing/Fields/Binding/AbstractBindingConverter.cs @@ -0,0 +1,54 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Basic IBindingConverter implementation + /// + public abstract class AbstractBindingConverter : IBindingConverter + { + public object convert(object o) + { + if (o == null) + { + return null; + } + + if (o is T1) + { + return convert((T1) o); + } + + if (o is T2) + { + return convert((T2) o); + } + + throw new ArgumentException("Cannot handle argument of type " + o.GetType()); + } + + protected abstract T2 convert(T1 o); + protected abstract T1 convert(T2 o); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs b/src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs new file mode 100644 index 000000000..d9a69140d --- /dev/null +++ b/src/Greenshot/Drawing/Fields/Binding/BidirectionalBinding.cs @@ -0,0 +1,184 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Reflection; + +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Bidirectional binding of properties of two INotifyPropertyChanged instances. + /// This implementation synchronizes null values, too. If you do not want this + /// behavior (e.g. when binding to a + /// + public class BidirectionalBinding + { + private readonly INotifyPropertyChanged _controlObject; + private readonly INotifyPropertyChanged _fieldObject; + private readonly string _controlPropertyName; + private readonly string _fieldPropertyName; + private bool _updatingControl; + private bool _updatingField; + private IBindingConverter _converter; + private readonly IBindingValidator _validator; + + /// + /// Whether or not null values are passed on to the other object. + /// + protected bool AllowSynchronizeNull = true; + + /// + /// Bind properties of two objects bidirectionally + /// + /// Object containing 1st property to bind + /// Property of 1st object to bind + /// Object containing 2nd property to bind + /// Property of 2nd object to bind + public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName) + { + _controlObject = controlObject; + _fieldObject = fieldObject; + _controlPropertyName = controlPropertyName; + _fieldPropertyName = fieldPropertyName; + + _controlObject.PropertyChanged += ControlPropertyChanged; + _fieldObject.PropertyChanged += FieldPropertyChanged; + } + + /// + /// Bind properties of two objects bidirectionally, converting the values using a converter + /// + /// Object containing 1st property to bind + /// Property of 1st object to bind + /// Object containing 2nd property to bind + /// Property of 2nd object to bind + /// taking care of converting the synchronized value to the correct target format and back + public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, + IBindingConverter converter) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) + { + _converter = converter; + } + + /// + /// Bind properties of two objects bidirectionally, converting the values using a converter. + /// Synchronization can be intercepted by adding a validator. + /// + /// Object containing 1st property to bind + /// Property of 1st object to bind + /// Object containing 2nd property to bind + /// Property of 2nd object to bind + /// validator to intercept synchronization if the value does not match certain criteria + public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, + IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName) + { + _validator = validator; + } + + /// + /// Bind properties of two objects bidirectionally, converting the values using a converter. + /// Synchronization can be intercepted by adding a validator. + /// + /// Object containing 1st property to bind + /// Property of 1st object to bind + /// Object containing 2nd property to bind + /// Property of 2nd object to bind + /// taking care of converting the synchronized value to the correct target format and back + /// validator to intercept synchronization if the value does not match certain criteria + public BidirectionalBinding(INotifyPropertyChanged controlObject, string controlPropertyName, INotifyPropertyChanged fieldObject, string fieldPropertyName, + IBindingConverter converter, IBindingValidator validator) : this(controlObject, controlPropertyName, fieldObject, fieldPropertyName, converter) + { + _validator = validator; + } + + public void ControlPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (!_updatingControl && e.PropertyName.Equals(_controlPropertyName)) + { + _updatingField = true; + Synchronize(_controlObject, _controlPropertyName, _fieldObject, _fieldPropertyName); + _updatingField = false; + } + } + + public void FieldPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (!_updatingField && e.PropertyName.Equals(_fieldPropertyName)) + { + _updatingControl = true; + Synchronize(_fieldObject, _fieldPropertyName, _controlObject, _controlPropertyName); + _updatingControl = false; + } + } + + private void Synchronize(INotifyPropertyChanged sourceObject, string sourceProperty, INotifyPropertyChanged targetObject, string targetProperty) + { + PropertyInfo targetPropertyInfo = ResolvePropertyInfo(targetObject, targetProperty); + PropertyInfo sourcePropertyInfo = ResolvePropertyInfo(sourceObject, sourceProperty); + + if (sourcePropertyInfo != null && targetPropertyInfo != null && targetPropertyInfo.CanWrite) + { + object bValue = sourcePropertyInfo.GetValue(sourceObject, null); + if (_converter != null && bValue != null) + { + bValue = _converter.convert(bValue); + } + + try + { + if (_validator == null || _validator.validate(bValue)) + { + targetPropertyInfo.SetValue(targetObject, bValue, null); + } + } + catch (Exception e) + { + throw new MemberAccessException( + "Could not set property '" + targetProperty + "' to '" + bValue + "' [" + (bValue?.GetType().Name ?? string.Empty) + "] on " + targetObject + + ". Probably other type than expected, IBindingCoverter to the rescue.", e); + } + } + } + + private static PropertyInfo ResolvePropertyInfo(object obj, string property) + { + PropertyInfo ret = null; + string[] properties = property.Split(".".ToCharArray()); + for (int i = 0; i < properties.Length; i++) + { + string prop = properties[i]; + ret = obj.GetType().GetProperty(prop); + if (ret != null && ret.CanRead && i < prop.Length - 1) + { + obj = ret.GetValue(obj, null); + } + } + + return ret; + } + + public IBindingConverter Converter + { + get { return _converter; } + set { _converter = value; } + } + } +} \ No newline at end of file diff --git a/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs b/src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs similarity index 57% rename from Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs rename to src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs index 0ac7d02bb..b7e1849f0 100644 --- a/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs +++ b/src/Greenshot/Drawing/Fields/Binding/DecimalDoublePercentageConverter.cs @@ -18,30 +18,35 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Converts decimal to double (%) and vice versa, e.g. 95f to 0.95d - /// - public class DecimalDoublePercentageConverter : AbstractBindingConverter - { - private static DecimalDoublePercentageConverter _uniqueInstance; - - private DecimalDoublePercentageConverter() {} - - protected override decimal convert(double o) { - return Convert.ToDecimal(o)*100; - } - - protected override double convert(decimal o) { - return Convert.ToDouble(o)/100; - } - - public static DecimalDoublePercentageConverter GetInstance() +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Converts decimal to double (%) and vice versa, e.g. 95f to 0.95d + /// + public class DecimalDoublePercentageConverter : AbstractBindingConverter + { + private static DecimalDoublePercentageConverter _uniqueInstance; + + private DecimalDoublePercentageConverter() + { + } + + protected override decimal convert(double o) + { + return Convert.ToDecimal(o) * 100; + } + + protected override double convert(decimal o) + { + return Convert.ToDouble(o) / 100; + } + + public static DecimalDoublePercentageConverter GetInstance() { return _uniqueInstance ??= new DecimalDoublePercentageConverter(); } - - } -} + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs b/src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs new file mode 100644 index 000000000..0c2cbe5e5 --- /dev/null +++ b/src/Greenshot/Drawing/Fields/Binding/DecimalFloatConverter.cs @@ -0,0 +1,52 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Converts decimal to float and vice versa. + /// + public class DecimalFloatConverter : AbstractBindingConverter + { + private static DecimalFloatConverter _uniqueInstance; + + private DecimalFloatConverter() + { + } + + protected override decimal convert(float o) + { + return Convert.ToDecimal(o); + } + + protected override float convert(decimal o) + { + return Convert.ToSingle(o); + } + + public static DecimalFloatConverter GetInstance() + { + return _uniqueInstance ??= new DecimalFloatConverter(); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs b/src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs new file mode 100644 index 000000000..8e1b4e42f --- /dev/null +++ b/src/Greenshot/Drawing/Fields/Binding/DecimalIntConverter.cs @@ -0,0 +1,52 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Converts decimal to int and vice versa. + /// + public class DecimalIntConverter : AbstractBindingConverter + { + private static DecimalIntConverter _uniqueInstance; + + private DecimalIntConverter() + { + } + + protected override decimal convert(int o) + { + return Convert.ToDecimal(o); + } + + protected override int convert(decimal o) + { + return Convert.ToInt32(o); + } + + public static DecimalIntConverter GetInstance() + { + return _uniqueInstance ??= new DecimalIntConverter(); + } + } +} \ No newline at end of file diff --git a/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs b/src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs similarity index 70% rename from Greenshot/Drawing/Fields/Binding/IBindingConverter.cs rename to src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs index cdb573470..9c45dd044 100644 --- a/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs +++ b/src/Greenshot/Drawing/Fields/Binding/IBindingConverter.cs @@ -19,15 +19,15 @@ * along with this program. If not, see . */ -namespace Greenshot.Drawing.Fields.Binding { - - /// - /// Interface for a bidirectional converter, for use with BidirectionalBinding. - /// convert(object) implementation must deal with both directions. - /// see DecimalIntConverter - /// - public interface IBindingConverter { - object convert(object o); - } - -} +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Interface for a bidirectional converter, for use with BidirectionalBinding. + /// convert(object) implementation must deal with both directions. + /// see DecimalIntConverter + /// + public interface IBindingConverter + { + object convert(object o); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs b/src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs new file mode 100644 index 000000000..6406e80ab --- /dev/null +++ b/src/Greenshot/Drawing/Fields/Binding/IBindingValidator.cs @@ -0,0 +1,34 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Interface for a bidirectional validator, for use with BidirectionalBinding. + /// Useful if you do not want to synchronize values which would be illegal on + /// one of the bound objects (e.g. null value on some form components) + /// see NotNullValidator + /// + public interface IBindingValidator + { + bool validate(object o); + } +} \ No newline at end of file diff --git a/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs b/src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs similarity index 67% rename from Greenshot/Drawing/Fields/Binding/NotNullValidator.cs rename to src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs index 5d15b6699..e2089ab05 100644 --- a/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs +++ b/src/Greenshot/Drawing/Fields/Binding/NotNullValidator.cs @@ -19,23 +19,27 @@ * along with this program. If not, see . */ -namespace Greenshot.Drawing.Fields.Binding { - /// - /// Validates a value not to be null. - /// - public class NotNullValidator : IBindingValidator { - private static NotNullValidator _uniqueInstance; - - private NotNullValidator() { - } - - public bool validate(object o) { - return o != null; - } - - public static NotNullValidator GetInstance() +namespace Greenshot.Drawing.Fields.Binding +{ + /// + /// Validates a value not to be null. + /// + public class NotNullValidator : IBindingValidator + { + private static NotNullValidator _uniqueInstance; + + private NotNullValidator() + { + } + + public bool validate(object o) + { + return o != null; + } + + public static NotNullValidator GetInstance() { return _uniqueInstance ??= new NotNullValidator(); } - } -} + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/Field.cs b/src/Greenshot/Drawing/Fields/Field.cs new file mode 100644 index 000000000..280c3a519 --- /dev/null +++ b/src/Greenshot/Drawing/Fields/Field.cs @@ -0,0 +1,128 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Fields +{ + /// + /// Represents a single field of a drawable element, i.e. + /// line thickness of a rectangle. + /// + [Serializable] + public class Field : IField + { + [field: NonSerialized] public event PropertyChangedEventHandler PropertyChanged; + + private object _myValue; + + public object Value + { + get { return _myValue; } + set + { + if (!Equals(_myValue, value)) + { + _myValue = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value")); + } + } + } + + public IFieldType FieldType { get; set; } + public string Scope { get; set; } + + /// + /// Constructs a new Field instance, usually you should be using FieldFactory + /// to create Fields. + /// + /// FieldType of the Field to be created + /// The scope to which the value of this Field is relevant. + /// Depending on the scope the Field's value may be shared for other elements + /// containing the same FieldType for defaulting to the last used value. + /// When scope is set to a Type (e.g. typeof(RectangleContainer)), its value + /// should not be reused for FieldHolders of another Type (e.g. typeof(EllipseContainer)) + /// + public Field(IFieldType fieldType, Type scope) + { + FieldType = fieldType; + Scope = scope.Name; + } + + public Field(IFieldType fieldType, string scope) + { + FieldType = fieldType; + Scope = scope; + } + + public Field(IFieldType fieldType) + { + FieldType = fieldType; + } + + /// + /// Returns true if this field holds a value other than null. + /// + public bool HasValue => Value != null; + + /// + /// Creates a flat clone of this Field. The fields value itself is not cloned. + /// + /// + public Field Clone() + { + return new Field(FieldType, Scope) + { + Value = Value + }; + } + + public override int GetHashCode() + { + int hashCode = 0; + unchecked + { + hashCode += 1000000009 * FieldType.GetHashCode(); + if (Scope != null) + hashCode += 1000000021 * Scope.GetHashCode(); + } + + return hashCode; + } + + public override bool Equals(object obj) + { + if (!(obj is Field other)) + { + return false; + } + + return FieldType == other.FieldType && Equals(Scope, other.Scope); + } + + public override string ToString() + { + return string.Format("[Field FieldType={1} Value={0} Scope={2}]", _myValue, FieldType, Scope); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/FieldAggregator.cs b/src/Greenshot/Drawing/Fields/FieldAggregator.cs new file mode 100644 index 000000000..cda039956 --- /dev/null +++ b/src/Greenshot/Drawing/Fields/FieldAggregator.cs @@ -0,0 +1,224 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using Greenshot.Configuration; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Fields +{ + /// + /// Represents the current set of properties for the editor. + /// When one of EditorProperties' properties is updated, the change will be promoted + /// to all bound elements. + /// * If an element is selected: + /// This class represents the element's properties + /// * I n>1 elements are selected: + /// This class represents the properties of all elements. + /// Properties that do not apply for ALL selected elements are null (or 0 respectively) + /// If the property values of the selected elements differ, the value of the last bound element wins. + /// + [Serializable] + public sealed class FieldAggregator : AbstractFieldHolder + { + private readonly IDrawableContainerList _boundContainers; + private bool _internalUpdateRunning; + + private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); + + public FieldAggregator(ISurface parent) + { + foreach (var fieldType in FieldType.Values) + { + var field = new Field(fieldType, GetType()); + AddField(field); + } + + _boundContainers = new DrawableContainerList + { + Parent = parent + }; + } + + public override void AddField(IField field) + { + base.AddField(field); + field.PropertyChanged += OwnPropertyChanged; + } + + public void BindElements(IDrawableContainerList dcs) + { + foreach (var dc in dcs) + { + BindElement(dc); + } + } + + public void BindElement(IDrawableContainer dc) + { + if (!(dc is DrawableContainer container) || _boundContainers.Contains(container)) + { + return; + } + + _boundContainers.Add(container); + container.ChildrenChanged += delegate { UpdateFromBoundElements(); }; + UpdateFromBoundElements(); + } + + public void BindAndUpdateElement(IDrawableContainer dc) + { + UpdateElement(dc); + BindElement(dc); + } + + public void UpdateElement(IDrawableContainer dc) + { + if (!(dc is DrawableContainer container)) + { + return; + } + + _internalUpdateRunning = true; + foreach (var field in GetFields()) + { + if (container.HasField(field.FieldType) && field.HasValue) + { + //if(LOG.IsDebugEnabled) LOG.Debug(" "+field+ ": "+field.Value); + container.SetFieldValue(field.FieldType, field.Value); + } + } + + _internalUpdateRunning = false; + } + + public void UnbindElement(IDrawableContainer dc) + { + if (_boundContainers.Contains(dc)) + { + _boundContainers.Remove(dc); + UpdateFromBoundElements(); + } + } + + public void Clear() + { + ClearFields(); + _boundContainers.Clear(); + UpdateFromBoundElements(); + } + + /// + /// sets all field values to null, however does not remove fields + /// + private void ClearFields() + { + _internalUpdateRunning = true; + foreach (var field in GetFields()) + { + field.Value = null; + } + + _internalUpdateRunning = false; + } + + /// + /// Updates this instance using the respective fields from the bound elements. + /// Fields that do not apply to every bound element are set to null, or 0 respectively. + /// All other fields will be set to the field value of the least bound element. + /// + private void UpdateFromBoundElements() + { + ClearFields(); + _internalUpdateRunning = true; + foreach (var field in FindCommonFields()) + { + SetFieldValue(field.FieldType, field.Value); + } + + _internalUpdateRunning = false; + } + + private IList FindCommonFields() + { + IList returnFields = null; + if (_boundContainers.Count > 0) + { + // take all fields from the least selected container... + if (_boundContainers[_boundContainers.Count - 1] is DrawableContainer leastSelectedContainer) + { + returnFields = leastSelectedContainer.GetFields(); + for (int i = 0; i < _boundContainers.Count - 1; i++) + { + if (!(_boundContainers[i] is DrawableContainer dc)) continue; + IList fieldsToRemove = new List(); + foreach (IField field in returnFields) + { + // ... throw out those that do not apply to one of the other containers + if (!dc.HasField(field.FieldType)) + { + fieldsToRemove.Add(field); + } + } + + foreach (var field in fieldsToRemove) + { + returnFields.Remove(field); + } + } + } + } + + return returnFields ?? new List(); + } + + public void OwnPropertyChanged(object sender, PropertyChangedEventArgs ea) + { + IField field = (IField) sender; + if (_internalUpdateRunning || field.Value == null) + { + return; + } + + foreach (var drawableContainer1 in _boundContainers.ToList()) + { + var drawableContainer = (DrawableContainer) drawableContainer1; + if (!drawableContainer.HasField(field.FieldType)) + { + continue; + } + + IField drawableContainerField = drawableContainer.GetField(field.FieldType); + // Notify before change, so we can e.g. invalidate the area + drawableContainer.BeforeFieldChange(drawableContainerField, field.Value); + + drawableContainerField.Value = field.Value; + // update last used from DC field, so that scope is honored + EditorConfig.UpdateLastFieldValue(drawableContainerField); + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Fields/FieldType.cs b/src/Greenshot/Drawing/Fields/FieldType.cs new file mode 100644 index 000000000..accd72d4b --- /dev/null +++ b/src/Greenshot/Drawing/Fields/FieldType.cs @@ -0,0 +1,106 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Fields +{ + /// + /// Defines all FieldTypes + their default value. + /// (The additional value is why this is not an enum) + /// + [Serializable] + public class FieldType : IFieldType + { + public static readonly IFieldType ARROWHEADS = new FieldType("ARROWHEADS"); + public static readonly IFieldType BLUR_RADIUS = new FieldType("BLUR_RADIUS"); + public static readonly IFieldType BRIGHTNESS = new FieldType("BRIGHTNESS"); + public static readonly IFieldType FILL_COLOR = new FieldType("FILL_COLOR"); + public static readonly IFieldType FONT_BOLD = new FieldType("FONT_BOLD"); + public static readonly IFieldType FONT_FAMILY = new FieldType("FONT_FAMILY"); + public static readonly IFieldType FONT_ITALIC = new FieldType("FONT_ITALIC"); + public static readonly IFieldType FONT_SIZE = new FieldType("FONT_SIZE"); + public static readonly IFieldType TEXT_HORIZONTAL_ALIGNMENT = new FieldType("TEXT_HORIZONTAL_ALIGNMENT"); + public static readonly IFieldType TEXT_VERTICAL_ALIGNMENT = new FieldType("TEXT_VERTICAL_ALIGNMENT"); + public static readonly IFieldType HIGHLIGHT_COLOR = new FieldType("HIGHLIGHT_COLOR"); + public static readonly IFieldType LINE_COLOR = new FieldType("LINE_COLOR"); + public static readonly IFieldType LINE_THICKNESS = new FieldType("LINE_THICKNESS"); + public static readonly IFieldType MAGNIFICATION_FACTOR = new FieldType("MAGNIFICATION_FACTOR"); + public static readonly IFieldType PIXEL_SIZE = new FieldType("PIXEL_SIZE"); + public static readonly IFieldType PREVIEW_QUALITY = new FieldType("PREVIEW_QUALITY"); + public static readonly IFieldType SHADOW = new FieldType("SHADOW"); + public static readonly IFieldType PREPARED_FILTER_OBFUSCATE = new FieldType("PREPARED_FILTER_OBFUSCATE"); + public static readonly IFieldType PREPARED_FILTER_HIGHLIGHT = new FieldType("PREPARED_FILTER_HIGHLIGHT"); + public static readonly IFieldType FLAGS = new FieldType("FLAGS"); + + public static IFieldType[] Values = + { + ARROWHEADS, BLUR_RADIUS, BRIGHTNESS, FILL_COLOR, FONT_BOLD, FONT_FAMILY, FONT_ITALIC, FONT_SIZE, TEXT_HORIZONTAL_ALIGNMENT, TEXT_VERTICAL_ALIGNMENT, HIGHLIGHT_COLOR, + LINE_COLOR, LINE_THICKNESS, MAGNIFICATION_FACTOR, PIXEL_SIZE, PREVIEW_QUALITY, SHADOW, PREPARED_FILTER_OBFUSCATE, PREPARED_FILTER_HIGHLIGHT, FLAGS + }; + + public string Name { get; set; } + + private FieldType(string name) + { + Name = name; + } + + public override string ToString() + { + return Name; + } + + public override int GetHashCode() + { + int hashCode = 0; + unchecked + { + if (Name != null) + hashCode += 1000000009 * Name.GetHashCode(); + } + + return hashCode; + } + + public override bool Equals(object obj) + { + FieldType other = obj as FieldType; + if (other == null) + { + return false; + } + + return Equals(Name, other.Name); + } + + public static bool operator ==(FieldType a, FieldType b) + { + return Equals(a, b); + } + + public static bool operator !=(FieldType a, FieldType b) + { + return !Equals(a, b); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/FilterContainer.cs b/src/Greenshot/Drawing/FilterContainer.cs new file mode 100644 index 000000000..e58363024 --- /dev/null +++ b/src/Greenshot/Drawing/FilterContainer.cs @@ -0,0 +1,115 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using System.Drawing.Drawing2D; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing +{ + /// + /// empty container for filter-only elements + /// + [Serializable] + public abstract class FilterContainer : DrawableContainer + { + public enum PreparedFilterMode + { + OBFUSCATE, + HIGHLIGHT + }; + + public enum PreparedFilter + { + BLUR, + PIXELIZE, + TEXT_HIGHTLIGHT, + AREA_HIGHLIGHT, + GRAYSCALE, + MAGNIFICATION + }; + + public FilterContainer(Surface parent) : base(parent) + { + Init(); + } + + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } + + private void Init() + { + CreateDefaultAdorners(); + } + + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 0); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + AddField(GetType(), FieldType.SHADOW, false); + } + + public override void Draw(Graphics graphics, RenderMode rm) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); + if (lineVisible) + { + graphics.SmoothingMode = SmoothingMode.HighSpeed; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + //draw shadow first + if (shadow) + { + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = lineVisible ? 1 : 0; + while (currentStep <= steps) + { + using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); + Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + currentStep, Top + currentStep, Width, Height); + graphics.DrawRectangle(shadowPen, shadowRect); + currentStep++; + alpha -= basealpha / steps; + } + } + + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + if (lineThickness > 0) + { + using Pen pen = new Pen(lineColor, lineThickness); + graphics.DrawRectangle(pen, rect); + } + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/AbstractFilter.cs b/src/Greenshot/Drawing/Filters/AbstractFilter.cs new file mode 100644 index 000000000..1152956a0 --- /dev/null +++ b/src/Greenshot/Drawing/Filters/AbstractFilter.cs @@ -0,0 +1,83 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Drawing.Fields; + +namespace Greenshot.Drawing.Filters +{ + /// + /// Graphical filter which can be added to DrawableContainer. + /// Subclasses should fulfill INotifyPropertyChanged contract, i.e. call + /// OnPropertyChanged whenever a public property has been changed. + /// + [Serializable] + public abstract class AbstractFilter : AbstractFieldHolder, IFilter + { + [NonSerialized] private PropertyChangedEventHandler propertyChanged; + + public event PropertyChangedEventHandler PropertyChanged + { + add { propertyChanged += value; } + remove { propertyChanged -= value; } + } + + private bool invert; + + public bool Invert + { + get { return invert; } + set + { + invert = value; + OnPropertyChanged("Invert"); + } + } + + protected DrawableContainer parent; + + public DrawableContainer Parent + { + get { return parent; } + set { parent = value; } + } + + public AbstractFilter(DrawableContainer parent) + { + this.parent = parent; + } + + public DrawableContainer GetParent() + { + return parent; + } + + public abstract void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode); + + protected void OnPropertyChanged(string propertyName) + { + propertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/BlurFilter.cs b/src/Greenshot/Drawing/Filters/BlurFilter.cs new file mode 100644 index 000000000..698ffce4b --- /dev/null +++ b/src/Greenshot/Drawing/Filters/BlurFilter.cs @@ -0,0 +1,83 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using Greenshot.Drawing.Fields; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.UnmanagedHelpers; + +namespace Greenshot.Drawing.Filters +{ + [Serializable] + public class BlurFilter : AbstractFilter + { + public double previewQuality; + + public double PreviewQuality + { + get { return previewQuality; } + set + { + previewQuality = value; + OnPropertyChanged("PreviewQuality"); + } + } + + public BlurFilter(DrawableContainer parent) : base(parent) + { + AddField(GetType(), FieldType.BLUR_RADIUS, 3); + AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d); + } + + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); + Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + if (applyRect.Width == 0 || applyRect.Height == 0) + { + return; + } + + GraphicsState state = graphics.Save(); + if (Invert) + { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + + if (GDIplus.IsBlurPossible(blurRadius)) + { + GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false); + } + else + { + using IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect); + ImageHelper.ApplyBoxBlur(fastBitmap, blurRadius); + fastBitmap.DrawTo(graphics, applyRect); + } + + graphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/BrightnessFilter.cs b/src/Greenshot/Drawing/Filters/BrightnessFilter.cs new file mode 100644 index 000000000..4a02e9a7c --- /dev/null +++ b/src/Greenshot/Drawing/Filters/BrightnessFilter.cs @@ -0,0 +1,73 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using Greenshot.Drawing.Fields; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Filters +{ + [Serializable()] + public class BrightnessFilter : AbstractFilter + { + public BrightnessFilter(DrawableContainer parent) : base(parent) + { + AddField(GetType(), FieldType.BRIGHTNESS, 0.9d); + } + + /// + /// Implements the Apply code for the Brightness Filet + /// + /// + /// + /// + /// + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + + if (applyRect.Width == 0 || applyRect.Height == 0) + { + // nothing to do + return; + } + + GraphicsState state = graphics.Save(); + if (Invert) + { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + + float brightness = GetFieldValueAsFloat(FieldType.BRIGHTNESS); + using (ImageAttributes ia = ImageHelper.CreateAdjustAttributes(brightness, 1f, 1f)) + { + graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); + } + + graphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs b/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs new file mode 100644 index 000000000..43d8d44c2 --- /dev/null +++ b/src/Greenshot/Drawing/Filters/GrayscaleFilter.cs @@ -0,0 +1,90 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Filters +{ + /// + /// Description of GrayscaleFilter. + /// + [Serializable()] + public class GrayscaleFilter : AbstractFilter + { + public GrayscaleFilter(DrawableContainer parent) : base(parent) + { + } + + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + + if (applyRect.Width == 0 || applyRect.Height == 0) + { + // nothing to do + return; + } + + GraphicsState state = graphics.Save(); + if (Invert) + { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + + ColorMatrix grayscaleMatrix = new ColorMatrix(new[] + { + new[] + { + .3f, .3f, .3f, 0, 0 + }, + new[] + { + .59f, .59f, .59f, 0, 0 + }, + new[] + { + .11f, .11f, .11f, 0, 0 + }, + new float[] + { + 0, 0, 0, 1, 0 + }, + new float[] + { + 0, 0, 0, 0, 1 + } + }); + using (ImageAttributes ia = new ImageAttributes()) + { + ia.SetColorMatrix(grayscaleMatrix); + graphics.DrawImage(applyBitmap, applyRect, applyRect.X, applyRect.Y, applyRect.Width, applyRect.Height, GraphicsUnit.Pixel, ia); + } + + graphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/HighlightFilter.cs b/src/Greenshot/Drawing/Filters/HighlightFilter.cs new file mode 100644 index 000000000..04542575e --- /dev/null +++ b/src/Greenshot/Drawing/Filters/HighlightFilter.cs @@ -0,0 +1,82 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using Greenshot.Drawing.Fields; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Filters +{ + [Serializable()] + public class HighlightFilter : AbstractFilter + { + public HighlightFilter(DrawableContainer parent) : base(parent) + { + AddField(GetType(), FieldType.FILL_COLOR, Color.Yellow); + } + + /// + /// Implements the Apply code for the Brightness Filet + /// + /// + /// + /// + /// + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + + if (applyRect.Width == 0 || applyRect.Height == 0) + { + // nothing to do + return; + } + + GraphicsState state = graphics.Save(); + if (Invert) + { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + + using (IFastBitmap fastBitmap = FastBitmap.CreateCloneOf(applyBitmap, applyRect)) + { + Color highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + for (int y = fastBitmap.Top; y < fastBitmap.Bottom; y++) + { + for (int x = fastBitmap.Left; x < fastBitmap.Right; x++) + { + Color color = fastBitmap.GetColorAt(x, y); + color = Color.FromArgb(color.A, Math.Min(highlightColor.R, color.R), Math.Min(highlightColor.G, color.G), Math.Min(highlightColor.B, color.B)); + fastBitmap.SetColorAt(x, y, color); + } + } + + fastBitmap.DrawTo(graphics, applyRect.Location); + } + + graphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/Greenshot/Drawing/Filters/IFilter.cs b/src/Greenshot/Drawing/Filters/IFilter.cs similarity index 73% rename from Greenshot/Drawing/Filters/IFilter.cs rename to src/Greenshot/Drawing/Filters/IFilter.cs index 8c3b5b23e..41e634880 100644 --- a/Greenshot/Drawing/Filters/IFilter.cs +++ b/src/Greenshot/Drawing/Filters/IFilter.cs @@ -21,14 +21,15 @@ using System.ComponentModel; using System.Drawing; -using GreenshotPlugin.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing.Filters { - public interface IFilter : INotifyPropertyChanged, IFieldHolder { - DrawableContainer Parent {get; set; } - void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode); - DrawableContainer GetParent(); - bool Invert {get; set;} - } -} + public interface IFilter : INotifyPropertyChanged, IFieldHolder + { + DrawableContainer Parent { get; set; } + void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode); + DrawableContainer GetParent(); + bool Invert { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Filters/MagnifierFilter.cs b/src/Greenshot/Drawing/Filters/MagnifierFilter.cs new file mode 100644 index 000000000..9b1587d04 --- /dev/null +++ b/src/Greenshot/Drawing/Filters/MagnifierFilter.cs @@ -0,0 +1,70 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using Greenshot.Drawing.Fields; +using System.Drawing.Drawing2D; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing.Filters +{ + [Serializable] + public class MagnifierFilter : AbstractFilter + { + public MagnifierFilter(DrawableContainer parent) : base(parent) + { + AddField(GetType(), FieldType.MAGNIFICATION_FACTOR, 2); + } + + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + + if (applyRect.Width == 0 || applyRect.Height == 0) + { + // nothing to do + return; + } + + int magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR); + GraphicsState state = graphics.Save(); + if (Invert) + { + graphics.SetClip(applyRect); + graphics.ExcludeClip(rect); + } + + graphics.SmoothingMode = SmoothingMode.None; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + int halfWidth = rect.Width / 2; + int halfHeight = rect.Height / 2; + int newWidth = rect.Width / magnificationFactor; + int newHeight = rect.Height / magnificationFactor; + Rectangle source = new Rectangle(rect.X + halfWidth - newWidth / 2, rect.Y + halfHeight - newHeight / 2, newWidth, newHeight); + graphics.DrawImage(applyBitmap, rect, source, GraphicsUnit.Pixel); + graphics.Restore(state); + } + } +} \ No newline at end of file diff --git a/Greenshot/Drawing/Filters/PixelizationFilter.cs b/src/Greenshot/Drawing/Filters/PixelizationFilter.cs similarity index 62% rename from Greenshot/Drawing/Filters/PixelizationFilter.cs rename to src/Greenshot/Drawing/Filters/PixelizationFilter.cs index dbf19d3f7..59ca0321f 100644 --- a/Greenshot/Drawing/Filters/PixelizationFilter.cs +++ b/src/Greenshot/Drawing/Filters/PixelizationFilter.cs @@ -18,58 +18,78 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + using System; using System.Collections.Generic; using System.Drawing; - +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Drawing.Fields; using Greenshot.Helpers; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; -namespace Greenshot.Drawing.Filters { - [Serializable()] - public class PixelizationFilter : AbstractFilter { - - public PixelizationFilter(DrawableContainer parent) : base(parent) { - AddField(GetType(), FieldType.PIXEL_SIZE, 5); - } - - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { - int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE); - ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); - if (pixelSize <= 1 || rect.Width == 0 || rect.Height == 0) { - // Nothing to do - return; - } - if (rect.Width < pixelSize) { - pixelSize = rect.Width; - } - if (rect.Height < pixelSize) { - pixelSize = rect.Height; - } +namespace Greenshot.Drawing.Filters +{ + [Serializable()] + public class PixelizationFilter : AbstractFilter + { + public PixelizationFilter(DrawableContainer parent) : base(parent) + { + AddField(GetType(), FieldType.PIXEL_SIZE, 5); + } + + public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + { + int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE); + ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + if (pixelSize <= 1 || rect.Width == 0 || rect.Height == 0) + { + // Nothing to do + return; + } + + if (rect.Width < pixelSize) + { + pixelSize = rect.Width; + } + + if (rect.Height < pixelSize) + { + pixelSize = rect.Height; + } using IFastBitmap dest = FastBitmap.CreateCloneOf(applyBitmap, rect); - using (IFastBitmap src = FastBitmap.Create(applyBitmap, rect)) { + using (IFastBitmap src = FastBitmap.Create(applyBitmap, rect)) + { List colors = new List(); int halbPixelSize = pixelSize / 2; - for (int y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y += pixelSize) { - for (int x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x += pixelSize) { + for (int y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y += pixelSize) + { + for (int x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x += pixelSize) + { colors.Clear(); - for (int yy = y; yy < y + pixelSize; yy++) { - if (yy >= src.Top && yy < src.Bottom) { - for (int xx = x; xx < x + pixelSize; xx++) { - if (xx >= src.Left && xx < src.Right) { + for (int yy = y; yy < y + pixelSize; yy++) + { + if (yy >= src.Top && yy < src.Bottom) + { + for (int xx = x; xx < x + pixelSize; xx++) + { + if (xx >= src.Left && xx < src.Right) + { colors.Add(src.GetColorAt(xx, yy)); } } } } + Color currentAvgColor = Colors.Mix(colors); - for (int yy = y; yy <= y + pixelSize; yy++) { - if (yy >= src.Top && yy < src.Bottom) { - for (int xx = x; xx <= x + pixelSize; xx++) { - if (xx >= src.Left && xx < src.Right) { + for (int yy = y; yy <= y + pixelSize; yy++) + { + if (yy >= src.Top && yy < src.Bottom) + { + for (int xx = x; xx <= x + pixelSize; xx++) + { + if (xx >= src.Left && xx < src.Right) + { dest.SetColorAt(xx, yy, currentAvgColor); } } @@ -78,7 +98,8 @@ namespace Greenshot.Drawing.Filters { } } } + dest.DrawTo(graphics, rect.Location); } - } -} + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/FreehandContainer.cs b/src/Greenshot/Drawing/FreehandContainer.cs new file mode 100644 index 000000000..3c3fbe92f --- /dev/null +++ b/src/Greenshot/Drawing/FreehandContainer.cs @@ -0,0 +1,323 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing +{ + /// + /// Description of PathContainer. + /// + [Serializable] + public class FreehandContainer : DrawableContainer + { + private static readonly float[] PointOffset = + { + 0.5f, 0.25f, 0.75f + }; + + [NonSerialized] private GraphicsPath freehandPath = new GraphicsPath(); + private Rectangle myBounds = Rectangle.Empty; + private Point lastMouse = Point.Empty; + private readonly List capturePoints = new List(); + private bool isRecalculated; + + /// + /// Constructor + /// + public FreehandContainer(Surface parent) : base(parent) + { + Width = parent.Image.Width; + Height = parent.Image.Height; + Top = 0; + Left = 0; + } + + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 3); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + } + + public override void Transform(Matrix matrix) + { + Point[] points = capturePoints.ToArray(); + + matrix.TransformPoints(points); + capturePoints.Clear(); + capturePoints.AddRange(points); + RecalculatePath(); + } + + protected override void OnDeserialized(StreamingContext context) + { + RecalculatePath(); + } + + /// + /// This Dispose is called from the Dispose and the Destructor. + /// + /// When disposing==true all non-managed resources should be freed too! + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + freehandPath?.Dispose(); + } + + freehandPath = null; + } + + /// + /// Called from Surface (the parent) when the drawing begins (mouse-down) + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseDown(int mouseX, int mouseY) + { + lastMouse = new Point(mouseX, mouseY); + capturePoints.Add(lastMouse); + return true; + } + + /// + /// Called from Surface (the parent) if a mouse move is made while drawing + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseMove(int mouseX, int mouseY) + { + Point previousPoint = capturePoints[capturePoints.Count - 1]; + + if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= 2 * EditorConfig.FreehandSensitivity) + { + capturePoints.Add(new Point(mouseX, mouseY)); + } + + if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) < EditorConfig.FreehandSensitivity) + { + return true; + } + + //path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)}); + lastMouse = new Point(mouseX, mouseY); + freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY)); + // Only re-calculate the bounds & redraw when we added something to the path + myBounds = Rectangle.Round(freehandPath.GetBounds()); + + Invalidate(); + return true; + } + + /// + /// Called when the surface finishes drawing the element + /// + public override void HandleMouseUp(int mouseX, int mouseY) + { + // Make sure we don't loose the ending point + if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) >= EditorConfig.FreehandSensitivity) + { + capturePoints.Add(new Point(mouseX, mouseY)); + } + + RecalculatePath(); + } + + /// + /// Here we recalculate the freehand path by smoothing out the lines with Beziers. + /// + private void RecalculatePath() + { + // Store the previous path, to dispose it later when we are finished + var previousFreehandPath = freehandPath; + var newFreehandPath = new GraphicsPath(); + + // Here we can put some cleanup... like losing all the uninteresting points. + if (capturePoints.Count >= 3) + { + int index = 0; + while ((capturePoints.Count - 1) % 3 != 0) + { + // duplicate points, first at 50% than 25% than 75% + capturePoints.Insert((int) (capturePoints.Count * PointOffset[index]), capturePoints[(int) (capturePoints.Count * PointOffset[index++])]); + } + + newFreehandPath.AddBeziers(capturePoints.ToArray()); + } + else if (capturePoints.Count == 2) + { + newFreehandPath.AddLine(capturePoints[0], capturePoints[1]); + } + + // Recalculate the bounds + myBounds = Rectangle.Round(newFreehandPath.GetBounds()); + + // assign + isRecalculated = true; + freehandPath = newFreehandPath; + + // dispose previous + previousFreehandPath?.Dispose(); + } + + /// + /// Do the drawing of the freehand "stroke" + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode renderMode) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + using var pen = new Pen(lineColor) + { + Width = lineThickness + }; + if (!(pen.Width > 0)) + { + return; + } + + // Make sure the lines are nicely rounded + pen.EndCap = LineCap.Round; + pen.StartCap = LineCap.Round; + pen.LineJoin = LineJoin.Round; + // Move to where we need to draw + graphics.TranslateTransform(Left, Top); + var currentFreehandPath = freehandPath; + if (currentFreehandPath != null) + { + if (isRecalculated && Selected && renderMode == RenderMode.EDIT) + { + isRecalculated = false; + DrawSelectionBorder(graphics, pen, currentFreehandPath); + } + + graphics.DrawPath(pen, currentFreehandPath); + } + + // Move back, otherwise everything is shifted + graphics.TranslateTransform(-Left, -Top); + } + + /// + /// Draw a selectionborder around the freehand path + /// + /// Graphics + /// Pen + /// GraphicsPath + protected static void DrawSelectionBorder(Graphics graphics, Pen linePen, GraphicsPath path) + { + using var selectionPen = (Pen) linePen.Clone(); + using var selectionPath = (GraphicsPath) path.Clone(); + selectionPen.Width += 5; + selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen); + graphics.DrawPath(selectionPen, selectionPath); + selectionPath.Widen(selectionPen); + selectionPen.DashPattern = new float[] + { + 2, 2 + }; + selectionPen.Color = Color.LightSeaGreen; + selectionPen.Width = 1; + graphics.DrawPath(selectionPen, selectionPath); + } + + /// + /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds... + /// + public override Rectangle DrawingBounds + { + get + { + if (!myBounds.IsEmpty) + { + int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS)); + int safetymargin = 10; + return new Rectangle(myBounds.Left + Left - (safetymargin + lineThickness), myBounds.Top + Top - (safetymargin + lineThickness), + myBounds.Width + 2 * (lineThickness + safetymargin), myBounds.Height + 2 * (lineThickness + safetymargin)); + } + + if (_parent?.Image is Image image) + { + return new Rectangle(0, 0, image.Width, image.Height); + } + else + { + return Rectangle.Empty; + } + } + } + + /// + /// FreehandContainer are regarded equal if they are of the same type and their paths are equal. + /// + /// object + /// bool + public override bool Equals(object obj) + { + bool ret = false; + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + + if (obj is FreehandContainer other && Equals(freehandPath, other.freehandPath)) + { + ret = true; + } + + return ret; + } + + public override int GetHashCode() + { + return freehandPath?.GetHashCode() ?? 0; + } + + public override bool ClickableAt(int x, int y) + { + bool returnValue = base.ClickableAt(x, y); + if (returnValue) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + using var pen = new Pen(Color.White) + { + Width = lineThickness + 10 + }; + returnValue = freehandPath.IsOutlineVisible(x - Left, y - Top, pen); + } + + return returnValue; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/HighlightContainer.cs b/src/Greenshot/Drawing/HighlightContainer.cs new file mode 100644 index 000000000..fb5a78c69 --- /dev/null +++ b/src/Greenshot/Drawing/HighlightContainer.cs @@ -0,0 +1,112 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Drawing.Fields; +using Greenshot.Drawing.Filters; + +namespace Greenshot.Drawing +{ + /// + /// Description of ObfuscateContainer. + /// + [Serializable] + public class HighlightContainer : FilterContainer + { + public HighlightContainer(Surface parent) : base(parent) + { + Init(); + } + + /// + /// Use settings from base, extend with our own field + /// + protected override void InitializeFields() + { + base.InitializeFields(); + AddField(GetType(), FieldType.PREPARED_FILTER_HIGHLIGHT, PreparedFilter.TEXT_HIGHTLIGHT); + } + + protected override void OnDeserialized(StreamingContext context) + { + Init(); + } + + private void Init() + { + FieldChanged += HighlightContainer_OnFieldChanged; + ConfigurePreparedFilters(); + } + + protected void HighlightContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) + { + if (!sender.Equals(this)) + { + return; + } + + if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_HIGHLIGHT)) + { + ConfigurePreparedFilters(); + } + } + + private void ConfigurePreparedFilters() + { + PreparedFilter preset = (PreparedFilter) GetFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); + while (Filters.Count > 0) + { + Remove(Filters[0]); + } + + switch (preset) + { + case PreparedFilter.TEXT_HIGHTLIGHT: + Add(new HighlightFilter(this)); + break; + case PreparedFilter.AREA_HIGHLIGHT: + var brightnessFilter = new BrightnessFilter(this) + { + Invert = true + }; + Add(brightnessFilter); + var blurFilter = new BlurFilter(this) + { + Invert = true + }; + Add(blurFilter); + break; + case PreparedFilter.GRAYSCALE: + AbstractFilter f = new GrayscaleFilter(this) + { + Invert = true + }; + Add(f); + break; + case PreparedFilter.MAGNIFICATION: + Add(new MagnifierFilter(this)); + break; + } + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/IconContainer.cs b/src/Greenshot/Drawing/IconContainer.cs new file mode 100644 index 000000000..fe87c48b9 --- /dev/null +++ b/src/Greenshot/Drawing/IconContainer.cs @@ -0,0 +1,120 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.IO; +using System.Drawing.Drawing2D; +using log4net; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing +{ + /// + /// Description of IconContainer. + /// + [Serializable] + public class IconContainer : DrawableContainer, IIconContainer + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IconContainer)); + + protected Icon icon; + + public IconContainer(Surface parent) : base(parent) + { + Init(); + } + + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } + + private void Init() + { + CreateDefaultAdorners(); + } + + public IconContainer(Surface parent, string filename) : base(parent) + { + Load(filename); + } + + public Icon Icon + { + set + { + icon?.Dispose(); + icon = (Icon) value.Clone(); + Width = value.Width; + Height = value.Height; + } + get => icon; + } + + /** + * This Dispose is called from the Dispose and the Destructor. + * When disposing==true all non-managed resources should be freed too! + */ + protected override void Dispose(bool disposing) + { + if (disposing) + { + icon?.Dispose(); + } + + icon = null; + base.Dispose(disposing); + } + + public void Load(string filename) + { + if (!File.Exists(filename)) + { + return; + } + + using Icon fileIcon = new Icon(filename); + Icon = fileIcon; + Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); + } + + public override void Draw(Graphics graphics, RenderMode rm) + { + if (icon == null) + { + return; + } + + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.CompositingQuality = CompositingQuality.Default; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.DrawIcon(icon, Bounds); + } + + public override bool HasDefaultSize => true; + + public override Size DefaultSize => icon?.Size ?? new Size(16, 16); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/ImageContainer.cs b/src/Greenshot/Drawing/ImageContainer.cs new file mode 100644 index 000000000..e4538c0f4 --- /dev/null +++ b/src/Greenshot/Drawing/ImageContainer.cs @@ -0,0 +1,267 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.IO; +using Greenshot.Drawing.Fields; +using System.Drawing.Drawing2D; +using log4net; +using System.Runtime.Serialization; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing +{ + /// + /// Description of BitmapContainer. + /// + [Serializable] + public class ImageContainer : DrawableContainer, IImageContainer + { + private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer)); + + private Image image; + + /// + /// This is the shadow version of the bitmap, rendered once to save performance + /// Do not serialize, as the shadow is recreated from the original bitmap if it's not available + /// + [NonSerialized] private Image _shadowBitmap; + + /// + /// This is the offset for the shadow version of the bitmap + /// Do not serialize, as the offset is recreated + /// + [NonSerialized] private Point _shadowOffset = new Point(-1, -1); + + public ImageContainer(Surface parent, string filename) : this(parent) + { + Load(filename); + } + + public ImageContainer(Surface parent) : base(parent) + { + FieldChanged += BitmapContainer_OnFieldChanged; + Init(); + } + + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } + + private void Init() + { + CreateDefaultAdorners(); + } + + protected override void InitializeFields() + { + AddField(GetType(), FieldType.SHADOW, false); + } + + protected void BitmapContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) + { + if (!sender.Equals(this)) + { + return; + } + + if (FieldType.SHADOW.Equals(e.Field.FieldType)) + { + ChangeShadowField(); + } + } + + public void ChangeShadowField() + { + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + if (shadow) + { + CheckShadow(true); + Width = _shadowBitmap.Width; + Height = _shadowBitmap.Height; + Left -= _shadowOffset.X; + Top -= _shadowOffset.Y; + } + else + { + Width = image.Width; + Height = image.Height; + if (_shadowBitmap != null) + { + Left += _shadowOffset.X; + Top += _shadowOffset.Y; + } + } + } + + public Image Image + { + set + { + // Remove all current bitmaps + DisposeImage(); + DisposeShadow(); + image = ImageHelper.Clone(value); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + CheckShadow(shadow); + if (!shadow) + { + Width = image.Width; + Height = image.Height; + } + else + { + Width = _shadowBitmap.Width; + Height = _shadowBitmap.Height; + Left -= _shadowOffset.X; + Top -= _shadowOffset.Y; + } + } + get { return image; } + } + + /// + /// The bulk of the clean-up code is implemented in Dispose(bool) + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + DisposeImage(); + DisposeShadow(); + } + + base.Dispose(disposing); + } + + private void DisposeImage() + { + image?.Dispose(); + image = null; + } + + private void DisposeShadow() + { + _shadowBitmap?.Dispose(); + _shadowBitmap = null; + } + + + /// + /// Make sure the content is also transformed. + /// + /// + public override void Transform(Matrix matrix) + { + int rotateAngle = CalculateAngle(matrix); + // we currently assume only one transformation has been made. + if (rotateAngle != 0) + { + Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle); + DisposeShadow(); + using var tmpMatrix = new Matrix(); + using (image) + { + image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix); + } + } + + base.Transform(matrix); + } + + /// + /// + /// + /// + public void Load(string filename) + { + if (!File.Exists(filename)) + { + return; + } + + // Always make sure ImageHelper.LoadBitmap results are disposed some time, + // as we close the bitmap internally, we need to do it afterwards + using (var tmpImage = ImageHelper.LoadImage(filename)) + { + Image = tmpImage; + } + + Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); + } + + /// + /// This checks if a shadow is already generated + /// + /// + private void CheckShadow(bool shadow) + { + if (!shadow || _shadowBitmap != null) + { + return; + } + + using var matrix = new Matrix(); + _shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix); + } + + /// + /// Draw the actual container to the graphics object + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode rm) + { + if (image == null) + { + return; + } + + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + if (shadow) + { + CheckShadow(true); + graphics.DrawImage(_shadowBitmap, Bounds); + } + else + { + graphics.DrawImage(image, Bounds); + } + } + + public override bool HasDefaultSize => true; + + public override Size DefaultSize => image?.Size ?? new Size(32, 32); + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/LineContainer.cs b/src/Greenshot/Drawing/LineContainer.cs new file mode 100644 index 000000000..1078662ea --- /dev/null +++ b/src/Greenshot/Drawing/LineContainer.cs @@ -0,0 +1,123 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Drawing.Adorners; + +namespace Greenshot.Drawing +{ + /// + /// Description of LineContainer. + /// + [Serializable()] + public class LineContainer : DrawableContainer + { + public LineContainer(Surface parent) : base(parent) + { + Init(); + } + + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + AddField(GetType(), FieldType.SHADOW, true); + } + + protected override void OnDeserialized(StreamingContext context) + { + Init(); + } + + protected void Init() + { + Adorners.Add(new MoveAdorner(this, Positions.TopLeft)); + Adorners.Add(new MoveAdorner(this, Positions.BottomRight)); + } + + public override void Draw(Graphics graphics, RenderMode rm) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + + if (lineThickness > 0) + { + if (shadow) + { + //draw shadow first + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = 1; + while (currentStep <= steps) + { + using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); + graphics.DrawLine(shadowCapPen, + Left + currentStep, + Top + currentStep, + Left + currentStep + Width, + Top + currentStep + Height); + + currentStep++; + alpha -= basealpha / steps; + } + } + + using Pen pen = new Pen(lineColor, lineThickness); + graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); + } + } + + public override bool ClickableAt(int x, int y) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 5; + if (lineThickness > 0) + { + using Pen pen = new Pen(Color.White) + { + Width = lineThickness + }; + using GraphicsPath path = new GraphicsPath(); + path.AddLine(Left, Top, Left + Width, Top + Height); + return path.IsOutlineVisible(x, y, pen); + } + + return false; + } + + protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() + { + return ScaleHelper.LineAngleRoundBehavior.Instance; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/ObfuscateContainer.cs b/src/Greenshot/Drawing/ObfuscateContainer.cs new file mode 100644 index 000000000..f45d6b4a2 --- /dev/null +++ b/src/Greenshot/Drawing/ObfuscateContainer.cs @@ -0,0 +1,89 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Drawing.Fields; +using Greenshot.Drawing.Filters; + +namespace Greenshot.Drawing +{ + /// + /// Description of ObfuscateContainer. + /// + [Serializable] + public class ObfuscateContainer : FilterContainer + { + public ObfuscateContainer(Surface parent) : base(parent) + { + Init(); + } + + protected override void InitializeFields() + { + base.InitializeFields(); + AddField(GetType(), FieldType.PREPARED_FILTER_OBFUSCATE, PreparedFilter.PIXELIZE); + } + + protected override void OnDeserialized(StreamingContext context) + { + Init(); + } + + private void Init() + { + FieldChanged += ObfuscateContainer_OnFieldChanged; + ConfigurePreparedFilters(); + CreateDefaultAdorners(); + } + + protected void ObfuscateContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) + { + if (sender.Equals(this)) + { + if (Equals(e.Field.FieldType, FieldType.PREPARED_FILTER_OBFUSCATE)) + { + ConfigurePreparedFilters(); + } + } + } + + private void ConfigurePreparedFilters() + { + PreparedFilter preset = (PreparedFilter) GetFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE); + while (Filters.Count > 0) + { + Remove(Filters[0]); + } + + switch (preset) + { + case PreparedFilter.BLUR: + Add(new BlurFilter(this)); + break; + case PreparedFilter.PIXELIZE: + Add(new PixelizationFilter(this)); + break; + } + } + } +} \ No newline at end of file diff --git a/Greenshot/Drawing/Positions.cs b/src/Greenshot/Drawing/Positions.cs similarity index 74% rename from Greenshot/Drawing/Positions.cs rename to src/Greenshot/Drawing/Positions.cs index f7061d023..ca42ee728 100644 --- a/Greenshot/Drawing/Positions.cs +++ b/src/Greenshot/Drawing/Positions.cs @@ -21,18 +21,18 @@ namespace Greenshot.Drawing { - /// - /// Position - /// - public enum Positions : int - { - TopLeft = 0, - TopCenter = 1, - TopRight = 2, - MiddleRight = 3, - BottomRight = 4, - BottomCenter = 5, - BottomLeft = 6, - MiddleLeft = 7 - } -} + /// + /// Position + /// + public enum Positions : int + { + TopLeft = 0, + TopCenter = 1, + TopRight = 2, + MiddleRight = 3, + BottomRight = 4, + BottomCenter = 5, + BottomLeft = 6, + MiddleLeft = 7 + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/RectangleContainer.cs b/src/Greenshot/Drawing/RectangleContainer.cs new file mode 100644 index 000000000..73da99983 --- /dev/null +++ b/src/Greenshot/Drawing/RectangleContainer.cs @@ -0,0 +1,167 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing +{ + /// + /// Represents a rectangular shape on the Surface + /// + [Serializable] + public class RectangleContainer : DrawableContainer + { + public RectangleContainer(Surface parent) : base(parent) + { + Init(); + } + + /// + /// Do some logic to make sure all field are initiated correctly + /// + /// StreamingContext + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } + + private void Init() + { + CreateDefaultAdorners(); + } + + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + AddField(GetType(), FieldType.FILL_COLOR, Color.Transparent); + AddField(GetType(), FieldType.SHADOW, true); + } + + public override void Draw(Graphics graphics, RenderMode rm) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR, Color.Red); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR, Color.Transparent); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + + DrawRectangle(rect, graphics, rm, lineThickness, lineColor, fillColor, shadow); + } + + /// + /// This method can also be used from other containers, if the right values are passed! + /// + /// + /// + /// + /// + /// + /// + /// + public static void DrawRectangle(Rectangle rect, Graphics graphics, RenderMode rm, int lineThickness, Color lineColor, Color fillColor, bool shadow) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + + bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); + if (shadow && (lineVisible || Colors.IsVisible(fillColor))) + { + //draw shadow first + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = lineVisible ? 1 : 0; + while (currentStep <= steps) + { + using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100)) + { + Width = lineVisible ? lineThickness : 1 + }; + Rectangle shadowRect = GuiRectangle.GetGuiRectangle( + rect.Left + currentStep, + rect.Top + currentStep, + rect.Width, + rect.Height); + graphics.DrawRectangle(shadowPen, shadowRect); + currentStep++; + alpha -= basealpha / steps; + } + } + + + if (Colors.IsVisible(fillColor)) + { + using Brush brush = new SolidBrush(fillColor); + graphics.FillRectangle(brush, rect); + } + + graphics.SmoothingMode = SmoothingMode.HighSpeed; + if (lineVisible) + { + using Pen pen = new Pen(lineColor, lineThickness); + graphics.DrawRectangle(pen, rect); + } + } + + public override bool ClickableAt(int x, int y) + { + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + + return RectangleClickableAt(rect, lineThickness, fillColor, x, y); + } + + + public static bool RectangleClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) + { + // If we clicked inside the rectangle and it's visible we are clickable at. + if (!Color.Transparent.Equals(fillColor)) + { + if (rect.Contains(x, y)) + { + return true; + } + } + + // check the rest of the lines + if (lineThickness > 0) + { + using Pen pen = new Pen(Color.White, lineThickness); + using GraphicsPath path = new GraphicsPath(); + path.AddRectangle(rect); + return path.IsOutlineVisible(x, y, pen); + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/SpeechbubbleContainer.cs b/src/Greenshot/Drawing/SpeechbubbleContainer.cs new file mode 100644 index 000000000..50f18f74a --- /dev/null +++ b/src/Greenshot/Drawing/SpeechbubbleContainer.cs @@ -0,0 +1,399 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Text; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing +{ + /// + /// Description of SpeechbubbleContainer. + /// + [Serializable] + public class SpeechbubbleContainer : TextContainer + { + private Point _initialGripperPoint; + + // Only used for serializing the TargetGripper location + private Point _storedTargetGripperLocation; + + /// + /// Store the current location of the target gripper + /// + /// + [OnSerializing] + private void SetValuesOnSerializing(StreamingContext context) + { + if (TargetAdorner != null) + { + _storedTargetGripperLocation = TargetAdorner.Location; + } + } + + /// + /// Restore the target gripper + /// + /// StreamingContext + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + InitAdorner(Color.Green, _storedTargetGripperLocation); + } + + public SpeechbubbleContainer(Surface parent) + : base(parent) + { + } + + /// + /// We set our own field values + /// + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 2); + AddField(GetType(), FieldType.LINE_COLOR, Color.Blue); + AddField(GetType(), FieldType.SHADOW, false); + AddField(GetType(), FieldType.FONT_ITALIC, false); + AddField(GetType(), FieldType.FONT_BOLD, true); + AddField(GetType(), FieldType.FILL_COLOR, Color.White); + AddField(GetType(), FieldType.FONT_FAMILY, FontFamily.GenericSansSerif.Name); + AddField(GetType(), FieldType.FONT_SIZE, 20f); + AddField(GetType(), FieldType.TEXT_HORIZONTAL_ALIGNMENT, StringAlignment.Center); + AddField(GetType(), FieldType.TEXT_VERTICAL_ALIGNMENT, StringAlignment.Center); + } + + /// + /// Called from Surface (the _parent) when the drawing begins (mouse-down) + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseDown(int mouseX, int mouseY) + { + if (TargetAdorner == null) + { + _initialGripperPoint = new Point(mouseX, mouseY); + InitAdorner(Color.Green, new Point(mouseX, mouseY)); + } + + return base.HandleMouseDown(mouseX, mouseY); + } + + /// + /// Overriding the HandleMouseMove will help us to make sure the tail is always visible. + /// Should fix BUG-1682 + /// + /// + /// + /// base.HandleMouseMove + public override bool HandleMouseMove(int x, int y) + { + bool returnValue = base.HandleMouseMove(x, y); + + bool leftAligned = _boundsAfterResize.Right - _boundsAfterResize.Left >= 0; + bool topAligned = _boundsAfterResize.Bottom - _boundsAfterResize.Top >= 0; + + int xOffset = leftAligned ? -20 : 20; + int yOffset = topAligned ? -20 : 20; + + Point newGripperLocation = _initialGripperPoint; + newGripperLocation.Offset(xOffset, yOffset); + + if (TargetAdorner.Location != newGripperLocation) + { + Invalidate(); + TargetAdorner.Location = newGripperLocation; + Invalidate(); + } + + return returnValue; + } + + /// + /// The DrawingBound should be so close as possible to the shape, so we don't invalidate to much. + /// + public override Rectangle DrawingBounds + { + get + { + if (Status != EditStatus.UNDRAWN) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + using Pen pen = new Pen(lineColor, lineThickness); + int inflateValue = lineThickness + 2 + (shadow ? 6 : 0); + using GraphicsPath tailPath = CreateTail(); + return Rectangle.Inflate(Rectangle.Union(Rectangle.Round(tailPath.GetBounds(new Matrix(), pen)), GuiRectangle.GetGuiRectangle(Left, Top, Width, Height)), + inflateValue, inflateValue); + } + + return Rectangle.Empty; + } + } + + /// + /// Helper method to create the bubble GraphicsPath, so we can also calculate the bounds + /// + /// + /// + private GraphicsPath CreateBubble(int lineThickness) + { + GraphicsPath bubble = new GraphicsPath(); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + + Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height); + // adapt corner radius to small rectangle dimensions + int smallerSideLength = Math.Min(bubbleRect.Width, bubbleRect.Height); + int cornerRadius = Math.Min(30, smallerSideLength / 2 - lineThickness); + if (cornerRadius > 0) + { + bubble.AddArc(bubbleRect.X, bubbleRect.Y, cornerRadius, cornerRadius, 180, 90); + bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y, cornerRadius, cornerRadius, 270, 90); + bubble.AddArc(bubbleRect.X + bubbleRect.Width - cornerRadius, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 0, 90); + bubble.AddArc(bubbleRect.X, bubbleRect.Y + bubbleRect.Height - cornerRadius, cornerRadius, cornerRadius, 90, 90); + } + else + { + bubble.AddRectangle(bubbleRect); + } + + bubble.CloseAllFigures(); + using (Matrix bubbleMatrix = new Matrix()) + { + bubbleMatrix.Translate(rect.Left, rect.Top); + bubble.Transform(bubbleMatrix); + } + + return bubble; + } + + /// + /// Helper method to create the tail of the bubble, so we can also calculate the bounds + /// + /// + private GraphicsPath CreateTail() + { + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + + int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetAdorner.Location.X, TargetAdorner.Location.Y); + int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20; + + // This should fix a problem with the tail being to wide + tailWidth = Math.Min(Math.Abs(rect.Width) / 2, tailWidth); + tailWidth = Math.Min(Math.Abs(rect.Height) / 2, tailWidth); + + GraphicsPath tail = new GraphicsPath(); + tail.AddLine(-tailWidth, 0, tailWidth, 0); + tail.AddLine(tailWidth, 0, 0, -tailLength); + tail.CloseFigure(); + + int tailAngle = 90 + (int) GeometryHelper.Angle2D(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2, TargetAdorner.Location.X, TargetAdorner.Location.Y); + + using (Matrix tailMatrix = new Matrix()) + { + tailMatrix.Translate(rect.Left + rect.Width / 2, rect.Top + rect.Height / 2); + tailMatrix.Rotate(tailAngle); + tail.Transform(tailMatrix); + } + + return tail; + } + + /// + /// This is to draw the actual container + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode renderMode) + { + if (TargetAdorner == null) + { + return; + } + + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; + + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + + bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + + if (Selected && renderMode == RenderMode.EDIT) + { + DrawSelectionBorder(graphics, rect); + } + + GraphicsPath bubble = CreateBubble(lineThickness); + + GraphicsPath tail = CreateTail(); + + //draw shadow first + if (shadow && (lineVisible || Colors.IsVisible(fillColor))) + { + const int basealpha = 100; + int alpha = basealpha; + const int steps = 5; + int currentStep = lineVisible ? 1 : 0; + using Matrix shadowMatrix = new Matrix(); + using GraphicsPath bubbleClone = (GraphicsPath) bubble.Clone(); + using GraphicsPath tailClone = (GraphicsPath) tail.Clone(); + shadowMatrix.Translate(1, 1); + while (currentStep <= steps) + { + using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100))) + { + shadowPen.Width = lineVisible ? lineThickness : 1; + tailClone.Transform(shadowMatrix); + graphics.DrawPath(shadowPen, tailClone); + bubbleClone.Transform(shadowMatrix); + graphics.DrawPath(shadowPen, bubbleClone); + } + + currentStep++; + alpha -= basealpha / steps; + } + } + + GraphicsState state = graphics.Save(); + // draw the tail border where the bubble is not visible + using (Region clipRegion = new Region(bubble)) + { + graphics.SetClip(clipRegion, CombineMode.Exclude); + using Pen pen = new Pen(lineColor, lineThickness); + graphics.DrawPath(pen, tail); + } + + graphics.Restore(state); + + if (Colors.IsVisible(fillColor)) + { + //draw the bubbleshape + state = graphics.Save(); + using (Brush brush = new SolidBrush(fillColor)) + { + graphics.FillPath(brush, bubble); + } + + graphics.Restore(state); + } + + if (lineVisible) + { + //draw the bubble border + state = graphics.Save(); + // Draw bubble where the Tail is not visible. + using (Region clipRegion = new Region(tail)) + { + graphics.SetClip(clipRegion, CombineMode.Exclude); + using Pen pen = new Pen(lineColor, lineThickness); + //pen.EndCap = pen.StartCap = LineCap.Round; + graphics.DrawPath(pen, bubble); + } + + graphics.Restore(state); + } + + if (Colors.IsVisible(fillColor)) + { + // Draw the tail border + state = graphics.Save(); + using (Brush brush = new SolidBrush(fillColor)) + { + graphics.FillPath(brush, tail); + } + + graphics.Restore(state); + } + + // cleanup the paths + bubble.Dispose(); + tail.Dispose(); + + // Draw the text + DrawText(graphics, rect, lineThickness, lineColor, shadow, StringFormat, Text, Font); + } + + public override bool Contains(int x, int y) + { + if (base.Contains(x, y)) + { + return true; + } + + Point clickedPoint = new Point(x, y); + if (Status != EditStatus.UNDRAWN) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + using Pen pen = new Pen(lineColor, lineThickness); + using (GraphicsPath bubblePath = CreateBubble(lineThickness)) + { + bubblePath.Widen(pen); + if (bubblePath.IsVisible(clickedPoint)) + { + return true; + } + } + + using GraphicsPath tailPath = CreateTail(); + tailPath.Widen(pen); + if (tailPath.IsVisible(clickedPoint)) + { + return true; + } + } + + return false; + } + + public override bool ClickableAt(int x, int y) + { + return Contains(x, y); + } + + /// + /// Additional to the Transform of the TextContainer the bubble tail coordinates also need to be moved + /// + /// Matrix + public override void Transform(Matrix matrix) + { + Point[] points = + { + TargetAdorner.Location + }; + matrix.TransformPoints(points); + TargetAdorner.Location = points[0]; + base.Transform(matrix); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/StepLabelContainer.cs b/src/Greenshot/Drawing/StepLabelContainer.cs new file mode 100644 index 000000000..3f2c3b7db --- /dev/null +++ b/src/Greenshot/Drawing/StepLabelContainer.cs @@ -0,0 +1,225 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2012 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Text; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Drawing +{ + /// + /// This is an enumerated label, every single StepLabelContainer shows the number of the order it was created. + /// To make sure that deleting recalculates, we check the location before every draw. + /// + [Serializable] + public sealed class StepLabelContainer : DrawableContainer + { + [NonSerialized] private StringFormat _stringFormat = new StringFormat(); + + private readonly bool _drawAsRectangle = false; + + public StepLabelContainer(Surface parent) : base(parent) + { + parent.AddStepLabel(this); + InitContent(); + Init(); + } + + private void Init() + { + CreateDefaultAdorners(); + } + + // Used to store the number of this label, so when deserializing it can be placed back to the StepLabels list in the right location + private int _number; + + // Used to store the counter start of the Surface, as the surface is NOT stored. + private int _counterStart = 1; + + public int Number + { + get { return _number; } + set { _number = value; } + } + + /// + /// Retrieve the counter before serializing + /// + /// + [OnSerializing] + private void SetValuesOnSerializing(StreamingContext context) + { + if (Parent != null) + { + Number = ((Surface) Parent).CountStepLabels(this); + _counterStart = ((Surface) Parent).CounterStart; + } + } + + /// + /// Restore values that don't serialize + /// + /// + protected override void OnDeserialized(StreamingContext context) + { + Init(); + _stringFormat = new StringFormat + { + Alignment = StringAlignment.Center, + LineAlignment = StringAlignment.Center + }; + } + + /// + /// Add the StepLabel to the parent + /// + /// + protected override void SwitchParent(Surface newParent) + { + if (newParent == Parent) + { + return; + } + + ((Surface) Parent)?.RemoveStepLabel(this); + base.SwitchParent(newParent); + if (newParent == null) + { + return; + } + + // Make sure the counter start is restored (this unfortunately happens multiple times... -> hack) + newParent.CounterStart = _counterStart; + newParent.AddStepLabel(this); + } + + public override Size DefaultSize => new Size(30, 30); + + public override bool InitContent() + { + _defaultEditMode = EditStatus.IDLE; + _stringFormat.Alignment = StringAlignment.Center; + _stringFormat.LineAlignment = StringAlignment.Center; + + // Set defaults + Width = DefaultSize.Width; + Height = DefaultSize.Height; + + return true; + } + + /// + /// This makes it possible for the label to be placed exactly in the middle of the pointer. + /// + public override bool HandleMouseDown(int mouseX, int mouseY) + { + return base.HandleMouseDown(mouseX - Width / 2, mouseY - Height / 2); + } + + /// + /// We set our own field values + /// + protected override void InitializeFields() + { + AddField(GetType(), FieldType.FILL_COLOR, Color.DarkRed); + AddField(GetType(), FieldType.LINE_COLOR, Color.White); + AddField(GetType(), FieldType.FLAGS, FieldFlag.COUNTER); + } + + /// + /// Make sure this element is no longer referenced from the surface + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + { + return; + } + + ((Surface) Parent)?.RemoveStepLabel(this); + if (_stringFormat == null) + { + return; + } + + _stringFormat.Dispose(); + _stringFormat = null; + } + + public override bool HandleMouseMove(int x, int y) + { + Invalidate(); + Left = x - Width / 2; + Top = y - Height / 2; + Invalidate(); + return true; + } + + /// + /// Override the parent, calculate the label number, than draw + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode rm) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; + string text = ((Surface) Parent).CountStepLabels(this).ToString(); + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + if (_drawAsRectangle) + { + RectangleContainer.DrawRectangle(rect, graphics, rm, 0, Color.Transparent, fillColor, false); + } + else + { + EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false); + } + + float fontSize = Math.Min(Width, Height) / 1.4f; + using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name); + using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel); + TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font); + } + + public override bool ClickableAt(int x, int y) + { + Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); + if (_drawAsRectangle) + { + return RectangleContainer.RectangleClickableAt(rect, 0, fillColor, x, y); + } + + return EllipseContainer.EllipseClickableAt(rect, 0, fillColor, x, y); + } + } +} \ No newline at end of file diff --git a/src/Greenshot/Drawing/Surface.cs b/src/Greenshot/Drawing/Surface.cs new file mode 100644 index 000000000..8f2356513 --- /dev/null +++ b/src/Greenshot/Drawing/Surface.cs @@ -0,0 +1,2367 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Configuration; +using Greenshot.Drawing.Fields; +using Greenshot.Helpers; +using Greenshot.Memento; +using log4net; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.Effects; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Drawing.Adorners; + +namespace Greenshot.Drawing +{ + /// + /// Description of Surface. + /// + public sealed class Surface : Control, ISurface, INotifyPropertyChanged + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface)); + public static int Count; + private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); + + // Property to identify the Surface ID + private Guid _uniqueId = Guid.NewGuid(); + + /// + /// This value is used to start counting the step labels + /// + private int _counterStart = 1; + + /// + /// The GUID of the surface + /// + public Guid ID + { + get => _uniqueId; + set => _uniqueId = value; + } + + /// + /// Event handlers (do not serialize!) + /// + [NonSerialized] private PropertyChangedEventHandler _propertyChanged; + + public event PropertyChangedEventHandler PropertyChanged + { + add => _propertyChanged += value; + remove => _propertyChanged -= value; + } + + [NonSerialized] private SurfaceElementEventHandler _movingElementChanged; + + public event SurfaceElementEventHandler MovingElementChanged + { + add => _movingElementChanged += value; + remove => _movingElementChanged -= value; + } + + [NonSerialized] private SurfaceDrawingModeEventHandler _drawingModeChanged; + + public event SurfaceDrawingModeEventHandler DrawingModeChanged + { + add => _drawingModeChanged += value; + remove => _drawingModeChanged -= value; + } + + [NonSerialized] private SurfaceSizeChangeEventHandler _surfaceSizeChanged; + + public event SurfaceSizeChangeEventHandler SurfaceSizeChanged + { + add => _surfaceSizeChanged += value; + remove => _surfaceSizeChanged -= value; + } + + [NonSerialized] private SurfaceMessageEventHandler _surfaceMessage; + + public event SurfaceMessageEventHandler SurfaceMessage + { + add => _surfaceMessage += value; + remove => _surfaceMessage -= value; + } + + /// + /// inUndoRedo makes sure we don't undo/redo while in a undo/redo action + /// + [NonSerialized] private bool _inUndoRedo; + + /// + /// Make only one surface move cycle undoable, see SurfaceMouseMove + /// + [NonSerialized] private bool _isSurfaceMoveMadeUndoable; + + /// + /// Undo/Redo stacks, should not be serialized as the file would be way to big + /// + [NonSerialized] private readonly Stack _undoStack = new Stack(); + + [NonSerialized] private readonly Stack _redoStack = new Stack(); + + /// + /// Last save location, do not serialize! + /// + [NonSerialized] private string _lastSaveFullPath; + + /// + /// current drawing mode, do not serialize! + /// + [NonSerialized] private DrawingModes _drawingMode = DrawingModes.None; + + /// + /// the keys-locked flag helps with focus issues + /// + [NonSerialized] private bool _keysLocked; + + /// + /// Location of the mouse-down (it "starts" here), do not serialize + /// + [NonSerialized] private Point _mouseStart = Point.Empty; + + /// + /// are we in a mouse down, do not serialize + /// + [NonSerialized] private bool _mouseDown; + + /// + /// The selected element for the mouse down, do not serialize + /// + [NonSerialized] private IDrawableContainer _mouseDownElement; + + /// + /// all selected elements, do not serialize + /// + [NonSerialized] private readonly IDrawableContainerList selectedElements; + + /// + /// the element we are drawing with, do not serialize + /// + [NonSerialized] private IDrawableContainer _drawingElement; + + /// + /// the element we want to draw with (not yet drawn), do not serialize + /// + [NonSerialized] private IDrawableContainer _undrawnElement; + + /// + /// the cropcontainer, when cropping this is set, do not serialize + /// + [NonSerialized] private IDrawableContainer _cropContainer; + + /// + /// the brush which is used for transparent backgrounds, set by the editor, do not serialize + /// + [NonSerialized] private Brush _transparencyBackgroundBrush; + + /// + /// The buffer is only for drawing on it when using filters (to supply access) + /// This saves a lot of "create new bitmap" commands + /// Should not be serialized, as it's generated. + /// The actual bitmap is in the paintbox... + /// TODO: Check if this buffer is still needed! + /// + [NonSerialized] private Bitmap _buffer; + + /// + /// all stepLabels for the surface, needed with serialization + /// + private readonly List _stepLabels = new List(); + + public void AddStepLabel(StepLabelContainer stepLabel) + { + if (!_stepLabels.Contains(stepLabel)) + { + _stepLabels.Add(stepLabel); + } + } + + public void RemoveStepLabel(StepLabelContainer stepLabel) + { + _stepLabels.Remove(stepLabel); + } + + /// + /// The start value of the counter objects + /// + public int CounterStart + { + get => _counterStart; + set + { + if (_counterStart == value) + { + return; + } + + _counterStart = value; + Invalidate(); + _propertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CounterStart))); + } + } + + /// + /// Count all the VISIBLE steplabels in the surface, up to the supplied one + /// + /// can be null, if not the counting stops here + /// number of steplabels before the supplied container + public int CountStepLabels(IDrawableContainer stopAtContainer) + { + int number = CounterStart; + foreach (var possibleThis in _stepLabels) + { + if (possibleThis.Equals(stopAtContainer)) + { + break; + } + + if (IsOnSurface(possibleThis)) + { + number++; + } + } + + return number; + } + + /// + /// all elements on the surface, needed with serialization + /// + private readonly IDrawableContainerList _elements; + + /// + /// all elements on the surface, needed with serialization + /// + private FieldAggregator _fieldAggregator; + + /// + /// the cursor container, needed with serialization as we need a direct acces to it. + /// + private IDrawableContainer _cursorContainer; + + /// + /// the modified flag specifies if the surface has had modifications after the last export. + /// Initial state is modified, as "it's not saved" + /// After serialization this should actually be "false" (the surface came from a stream) + /// For now we just serialize it... + /// + private bool _modified = true; + + /// + /// The image is the actual captured image, needed with serialization + /// + private Image _image; + + public Image Image + { + get => _image; + set + { + _image = value; + UpdateSize(); + } + } + + [NonSerialized] private Matrix _zoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); + [NonSerialized] private Matrix _inverseZoomMatrix = new Matrix(1, 0, 0, 1, 0, 0); + [NonSerialized] private Fraction _zoomFactor = Fraction.Identity; + + public Fraction ZoomFactor + { + get => _zoomFactor; + set + { + _zoomFactor = value; + var inverse = _zoomFactor.Inverse(); + _zoomMatrix = new Matrix(_zoomFactor, 0, 0, _zoomFactor, 0, 0); + _inverseZoomMatrix = new Matrix(inverse, 0, 0, inverse, 0, 0); + UpdateSize(); + } + } + + + /// + /// Sets the surface size as zoomed image size. + /// + private void UpdateSize() + { + var size = _image.Size; + Size = new Size((int) (size.Width * _zoomFactor), (int) (size.Height * _zoomFactor)); + } + + /// + /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements. + /// e.g. used to decided if and which line thickness is shown when multiple elements are selected. + /// + public FieldAggregator FieldAggregator + { + get => _fieldAggregator; + set => _fieldAggregator = value; + } + + /// + /// The cursor container has it's own accessor so we can find and remove this (when needed) + /// + public IDrawableContainer CursorContainer => _cursorContainer; + + /// + /// A simple getter to ask if this surface has a cursor + /// + public bool HasCursor => _cursorContainer != null; + + /// + /// A simple helper method to remove the cursor from the surface + /// + public void RemoveCursor() + { + RemoveElement(_cursorContainer); + _cursorContainer = null; + } + + /// + /// The brush which is used to draw the transparent background + /// + public Brush TransparencyBackgroundBrush + { + get => _transparencyBackgroundBrush; + set => _transparencyBackgroundBrush = value; + } + + /// + /// Are the keys on this surface locked? + /// + public bool KeysLocked + { + get => _keysLocked; + set => _keysLocked = value; + } + + /// + /// Is this surface modified? This is only true if the surface has not been exported. + /// + public bool Modified + { + get => _modified; + set => _modified = value; + } + + /// + /// The DrawingMode property specifies the mode for drawing, more or less the element type. + /// + public DrawingModes DrawingMode + { + get => _drawingMode; + set + { + _drawingMode = value; + if (_drawingModeChanged != null) + { + SurfaceDrawingModeEventArgs eventArgs = new SurfaceDrawingModeEventArgs + { + DrawingMode = _drawingMode + }; + _drawingModeChanged.Invoke(this, eventArgs); + } + + DeselectAllElements(); + CreateUndrawnElement(); + } + } + + /// + /// Property for accessing the last save "full" path + /// + public string LastSaveFullPath + { + get => _lastSaveFullPath; + set => _lastSaveFullPath = value; + } + + /// + /// Property for accessing the URL to which the surface was recently uploaded + /// + public string UploadUrl { get; set; } + + /// + /// Property for accessing the capture details + /// + public ICaptureDetails CaptureDetails { get; set; } + + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// + public void AdjustToDpi(uint dpi) + { + foreach (var element in this._elements) + { + element.AdjustToDpi(dpi); + } + } + + /// + /// Base Surface constructor + /// + public Surface() + { + _fieldAggregator = new FieldAggregator(this); + Count++; + _elements = new DrawableContainerList(_uniqueId); + selectedElements = new DrawableContainerList(_uniqueId); + LOG.Debug("Creating surface!"); + MouseDown += SurfaceMouseDown; + MouseUp += SurfaceMouseUp; + MouseMove += SurfaceMouseMove; + MouseDoubleClick += SurfaceDoubleClick; + Paint += SurfacePaint; + AllowDrop = true; + DragDrop += OnDragDrop; + DragEnter += OnDragEnter; + // bind selected & elements to this, otherwise they can't inform of modifications + selectedElements.Parent = this; + _elements.Parent = this; + // Make sure we are visible + Visible = true; + TabStop = false; + // Enable double buffering + DoubleBuffered = true; + SetStyle( + ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.ContainerControl | ControlStyles.OptimizedDoubleBuffer | + ControlStyles.SupportsTransparentBackColor, true); + } + + /// + /// Private method, the current image is disposed the new one will stay. + /// + /// The new image + /// true if the old image needs to be disposed, when using undo this should not be true!! + private void SetImage(Image newImage, bool dispose) + { + // Dispose + if (_image != null && dispose) + { + _image.Dispose(); + } + + // Set new values + Image = newImage; + + _modified = true; + } + + /// + /// Surface constructor with an image + /// + /// + public Surface(Image newImage) : this() + { + LOG.DebugFormat("Got image with dimensions {0} and format {1}", newImage.Size, newImage.PixelFormat); + SetImage(newImage, true); + } + + /// + /// Surface contructor with a capture + /// + /// + public Surface(ICapture capture) : this(capture.Image) + { + // check if cursor is captured, and visible + if (capture.Cursor != null && capture.CursorVisible) + { + Rectangle cursorRect = new Rectangle(capture.CursorLocation, capture.Cursor.Size); + Rectangle captureRect = new Rectangle(Point.Empty, capture.Image.Size); + // check if cursor is on the capture, otherwise we leave it out. + if (cursorRect.IntersectsWith(captureRect)) + { + _cursorContainer = AddIconContainer(capture.Cursor, capture.CursorLocation.X, capture.CursorLocation.Y); + SelectElement(_cursorContainer); + } + } + + // Make sure the image is NOT disposed, we took the reference directly into ourselves + ((Capture) capture).NullImage(); + + CaptureDetails = capture.CaptureDetails; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + Count--; + LOG.Debug("Disposing surface!"); + if (_buffer != null) + { + _buffer.Dispose(); + _buffer = null; + } + + if (_transparencyBackgroundBrush != null) + { + _transparencyBackgroundBrush.Dispose(); + _transparencyBackgroundBrush = null; + } + + // Cleanup undo/redo stacks + while (_undoStack != null && _undoStack.Count > 0) + { + _undoStack.Pop().Dispose(); + } + + while (_redoStack != null && _redoStack.Count > 0) + { + _redoStack.Pop().Dispose(); + } + + foreach (IDrawableContainer container in _elements) + { + container.Dispose(); + } + + if (_undrawnElement != null) + { + _undrawnElement.Dispose(); + _undrawnElement = null; + } + + if (_cropContainer != null) + { + _cropContainer.Dispose(); + _cropContainer = null; + } + } + + base.Dispose(disposing); + } + + /// + /// Undo the last action + /// + public void Undo() + { + if (_undoStack.Count > 0) + { + _inUndoRedo = true; + IMemento top = _undoStack.Pop(); + _redoStack.Push(top.Restore()); + _inUndoRedo = false; + } + } + + /// + /// Undo an undo (=redo) + /// + public void Redo() + { + if (_redoStack.Count > 0) + { + _inUndoRedo = true; + IMemento top = _redoStack.Pop(); + _undoStack.Push(top.Restore()); + _inUndoRedo = false; + } + } + + /// + /// Returns if the surface can do a undo + /// + public bool CanUndo => _undoStack.Count > 0; + + /// + /// Returns if the surface can do a redo + /// + public bool CanRedo => _redoStack.Count > 0; + + /// + /// Get the language key for the undo action + /// + public LangKey UndoActionLanguageKey => LangKey.none; + + /// + /// Get the language key for redo action + /// + public LangKey RedoActionLanguageKey => LangKey.none; + + /// + /// Make an action undo-able + /// + /// The memento implementing the undo + /// Allow changes to be merged + public void MakeUndoable(IMemento memento, bool allowMerge) + { + if (_inUndoRedo) + { + throw new InvalidOperationException("Invoking do within an undo/redo action."); + } + + if (memento != null) + { + bool allowPush = true; + if (_undoStack.Count > 0 && allowMerge) + { + // Check if merge is possible + allowPush = !_undoStack.Peek().Merge(memento); + } + + if (allowPush) + { + // Clear the redo-stack and dispose + while (_redoStack.Count > 0) + { + _redoStack.Pop().Dispose(); + } + + _undoStack.Push(memento); + } + } + } + + /// + /// This saves the elements of this surface to a stream. + /// Is used to save a template of the complete surface + /// + /// + /// + public long SaveElementsToStream(Stream streamWrite) + { + long bytesWritten = 0; + try + { + long lengtBefore = streamWrite.Length; + BinaryFormatter binaryWrite = new BinaryFormatter(); + binaryWrite.Serialize(streamWrite, _elements); + bytesWritten = streamWrite.Length - lengtBefore; + } + catch (Exception e) + { + LOG.Error("Error serializing elements to stream.", e); + } + + return bytesWritten; + } + + /// + /// This loads elements from a stream, among others this is used to load a surface. + /// + /// + public void LoadElementsFromStream(Stream streamRead) + { + try + { + BinaryFormatter binaryRead = new BinaryFormatter(); + IDrawableContainerList loadedElements = (IDrawableContainerList) binaryRead.Deserialize(streamRead); + loadedElements.Parent = this; + // Make sure the steplabels are sorted accoring to their number + _stepLabels.Sort((p1, p2) => p1.Number.CompareTo(p2.Number)); + DeselectAllElements(); + AddElements(loadedElements); + SelectElements(loadedElements); + FieldAggregator.BindElements(loadedElements); + } + catch (Exception e) + { + LOG.Error("Error serializing elements from stream.", e); + } + } + + /// + /// This is called from the DrawingMode setter, which is not very correct... + /// But here an element is created which is not yet draw, thus "undrawnElement". + /// The element is than used while drawing on the surface. + /// + private void CreateUndrawnElement() + { + if (_undrawnElement != null) + { + FieldAggregator.UnbindElement(_undrawnElement); + } + + switch (DrawingMode) + { + case DrawingModes.Rect: + _undrawnElement = new RectangleContainer(this); + break; + case DrawingModes.Ellipse: + _undrawnElement = new EllipseContainer(this); + break; + case DrawingModes.Text: + _undrawnElement = new TextContainer(this); + break; + case DrawingModes.SpeechBubble: + _undrawnElement = new SpeechbubbleContainer(this); + break; + case DrawingModes.StepLabel: + _undrawnElement = new StepLabelContainer(this); + break; + case DrawingModes.Line: + _undrawnElement = new LineContainer(this); + break; + case DrawingModes.Arrow: + _undrawnElement = new ArrowContainer(this); + break; + case DrawingModes.Highlight: + _undrawnElement = new HighlightContainer(this); + break; + case DrawingModes.Obfuscate: + _undrawnElement = new ObfuscateContainer(this); + break; + case DrawingModes.Crop: + _cropContainer = new CropContainer(this); + _undrawnElement = _cropContainer; + break; + case DrawingModes.Bitmap: + _undrawnElement = new ImageContainer(this); + break; + case DrawingModes.Path: + _undrawnElement = new FreehandContainer(this); + break; + case DrawingModes.None: + _undrawnElement = null; + break; + } + + if (_undrawnElement != null) + { + FieldAggregator.BindElement(_undrawnElement); + } + } + + #region Plugin interface implementations + + public IImageContainer AddImageContainer(Image image, int x, int y) + { + ImageContainer bitmapContainer = new ImageContainer(this) + { + Image = image, + Left = x, + Top = y + }; + AddElement(bitmapContainer); + return bitmapContainer; + } + + public IImageContainer AddImageContainer(string filename, int x, int y) + { + ImageContainer bitmapContainer = new ImageContainer(this); + bitmapContainer.Load(filename); + bitmapContainer.Left = x; + bitmapContainer.Top = y; + AddElement(bitmapContainer); + return bitmapContainer; + } + + public IIconContainer AddIconContainer(Icon icon, int x, int y) + { + IconContainer iconContainer = new IconContainer(this) + { + Icon = icon, + Left = x, + Top = y + }; + AddElement(iconContainer); + return iconContainer; + } + + public IIconContainer AddIconContainer(string filename, int x, int y) + { + IconContainer iconContainer = new IconContainer(this); + iconContainer.Load(filename); + iconContainer.Left = x; + iconContainer.Top = y; + AddElement(iconContainer); + return iconContainer; + } + + public ICursorContainer AddCursorContainer(Cursor cursor, int x, int y) + { + CursorContainer cursorContainer = new CursorContainer(this) + { + Cursor = cursor, + Left = x, + Top = y + }; + AddElement(cursorContainer); + return cursorContainer; + } + + public ICursorContainer AddCursorContainer(string filename, int x, int y) + { + CursorContainer cursorContainer = new CursorContainer(this); + cursorContainer.Load(filename); + cursorContainer.Left = x; + cursorContainer.Top = y; + AddElement(cursorContainer); + return cursorContainer; + } + + public ITextContainer AddTextContainer(string text, int x, int y, FontFamily family, float size, bool italic, bool bold, bool shadow, int borderSize, Color color, + Color fillColor) + { + TextContainer textContainer = new TextContainer(this) + { + Text = text, + Left = x, + Top = y + }; + textContainer.SetFieldValue(FieldType.FONT_FAMILY, family.Name); + textContainer.SetFieldValue(FieldType.FONT_BOLD, bold); + textContainer.SetFieldValue(FieldType.FONT_ITALIC, italic); + textContainer.SetFieldValue(FieldType.FONT_SIZE, size); + textContainer.SetFieldValue(FieldType.FILL_COLOR, fillColor); + textContainer.SetFieldValue(FieldType.LINE_COLOR, color); + textContainer.SetFieldValue(FieldType.LINE_THICKNESS, borderSize); + textContainer.SetFieldValue(FieldType.SHADOW, shadow); + // Make sure the Text fits + textContainer.FitToText(); + + //AggregatedProperties.UpdateElement(textContainer); + AddElement(textContainer); + return textContainer; + } + + #endregion + + #region DragDrop + + private void OnDragEnter(object sender, DragEventArgs e) + { + if (LOG.IsDebugEnabled) + { + LOG.Debug("DragEnter got following formats: "); + foreach (string format in ClipboardHelper.GetFormats(e.Data)) + { + LOG.Debug(format); + } + } + + if ((e.AllowedEffect & DragDropEffects.Copy) != DragDropEffects.Copy) + { + e.Effect = DragDropEffects.None; + } + else + { + if (ClipboardHelper.ContainsImage(e.Data) || ClipboardHelper.ContainsFormat(e.Data, "DragImageBits")) + { + e.Effect = DragDropEffects.Copy; + } + else + { + e.Effect = DragDropEffects.None; + } + } + } + + /// + /// Handle the drag/drop + /// + /// + /// + private void OnDragDrop(object sender, DragEventArgs e) + { + Point mouse = PointToClient(new Point(e.X, e.Y)); + if (e.Data.GetDataPresent("Text")) + { + string possibleUrl = ClipboardHelper.GetText(e.Data); + // Test if it's an url and try to download the image so we have it in the original form + if (possibleUrl != null && possibleUrl.StartsWith("http")) + { + using Image image = NetworkHelper.DownloadImage(possibleUrl); + if (image != null) + { + AddImageContainer(image, mouse.X, mouse.Y); + return; + } + } + } + + foreach (Image image in ClipboardHelper.GetImages(e.Data)) + { + AddImageContainer(image, mouse.X, mouse.Y); + mouse.Offset(10, 10); + image.Dispose(); + } + } + + #endregion + + /// + /// Auto crop the image + /// + /// true if cropped + public bool AutoCrop() + { + Rectangle cropRectangle; + using (Image tmpImage = GetImageForExport()) + { + cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference); + } + + if (!IsCropPossible(ref cropRectangle)) + { + return false; + } + + DeselectAllElements(); + // Maybe a bit obscure, but the following line creates a drop container + // It's available as "undrawnElement" + DrawingMode = DrawingModes.Crop; + _undrawnElement.Left = cropRectangle.X; + _undrawnElement.Top = cropRectangle.Y; + _undrawnElement.Width = cropRectangle.Width; + _undrawnElement.Height = cropRectangle.Height; + _undrawnElement.Status = EditStatus.UNDRAWN; + AddElement(_undrawnElement); + SelectElement(_undrawnElement); + _drawingElement = null; + _undrawnElement = null; + return true; + } + + /// + /// A simple clear + /// + /// The color for the background + public void Clear(Color newColor) + { + //create a blank bitmap the same size as original + Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty); + if (newBitmap != null) + { + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false); + SetImage(newBitmap, false); + Invalidate(); + } + } + + /// + /// Apply a bitmap effect to the surface + /// + /// + public void ApplyBitmapEffect(IEffect effect) + { + BackgroundForm backgroundForm = new BackgroundForm("Effect", "Please wait"); + backgroundForm.Show(); + Application.DoEvents(); + try + { + Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); + Matrix matrix = new Matrix(); + Image newImage = ImageHelper.ApplyEffect(Image, effect, matrix); + if (newImage != null) + { + // Make sure the elements move according to the offset the effect made the bitmap move + _elements.Transform(matrix); + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); + SetImage(newImage, false); + Invalidate(); + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) + { + _surfaceSizeChanged(this, null); + } + } + else + { + // clean up matrix, as it hasn't been used in the undo stack. + matrix.Dispose(); + } + } + finally + { + // Always close the background form + backgroundForm.CloseDialog(); + } + } + + /// + /// check if a crop is possible + /// + /// + /// true if this is possible + public bool IsCropPossible(ref Rectangle cropRectangle) + { + cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); + if (cropRectangle.Left < 0) + { + cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); + } + + if (cropRectangle.Top < 0) + { + cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); + } + + if (cropRectangle.Left + cropRectangle.Width > Image.Width) + { + cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height); + } + + if (cropRectangle.Top + cropRectangle.Height > Image.Height) + { + cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top); + } + + if (cropRectangle.Height > 0 && cropRectangle.Width > 0) + { + return true; + } + + return false; + } + + /// + /// Use to send any registered SurfaceMessageEventHandler a message, e.g. used for the notification area + /// + /// Who send + /// Type of message + /// Message itself + public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message) + { + if (_surfaceMessage != null) + { + var eventArgs = new SurfaceMessageEventArgs + { + Message = message, + MessageType = messageType, + Surface = this + }; + _surfaceMessage(source, eventArgs); + } + } + + /// + /// Crop the surface + /// + /// + /// + public bool ApplyCrop(Rectangle cropRectangle) + { + if (IsCropPossible(ref cropRectangle)) + { + Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); + Bitmap tmpImage; + // Make sure we have information, this this fails + try + { + tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); + } + catch (Exception ex) + { + ex.Data.Add("CropRectangle", cropRectangle); + ex.Data.Add("Width", Image.Width); + ex.Data.Add("Height", Image.Height); + ex.Data.Add("Pixelformat", Image.PixelFormat); + throw; + } + + Matrix matrix = new Matrix(); + matrix.Translate(-cropRectangle.Left, -cropRectangle.Top, MatrixOrder.Append); + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); + + // Do not dispose otherwise we can't undo the image! + SetImage(tmpImage, false); + _elements.Transform(matrix); + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) + { + _surfaceSizeChanged(this, null); + } + + Invalidate(); + return true; + } + + return false; + } + + /// + /// The background here is the captured image. + /// This is called from the SurfaceBackgroundChangeMemento. + /// + /// + /// + public void UndoBackgroundChange(Image previous, Matrix matrix) + { + SetImage(previous, false); + if (matrix != null) + { + _elements.Transform(matrix); + } + + _surfaceSizeChanged?.Invoke(this, null); + Invalidate(); + } + + /// + /// Check if an adorner was "hit", and change the cursor if so + /// + /// MouseEventArgs + /// IAdorner + private IAdorner FindActiveAdorner(MouseEventArgs mouseEventArgs) + { + foreach (IDrawableContainer drawableContainer in selectedElements) + { + foreach (IAdorner adorner in drawableContainer.Adorners) + { + if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location)) + { + if (adorner.Cursor != null) + { + Cursor = adorner.Cursor; + } + + return adorner; + } + } + } + + return null; + } + + /// + /// Translate mouse coordinates as if they were applied directly to unscaled image. + /// + private MouseEventArgs InverseZoomMouseCoordinates(MouseEventArgs e) + => new MouseEventArgs(e.Button, e.Clicks, (int) (e.X / _zoomFactor), (int) (e.Y / _zoomFactor), e.Delta); + + /// + /// This event handler is called when someone presses the mouse on a surface. + /// + /// + /// + private void SurfaceMouseDown(object sender, MouseEventArgs e) + { + e = InverseZoomMouseCoordinates(e); + + // Handle Adorners + var adorner = FindActiveAdorner(e); + if (adorner != null) + { + adorner.MouseDown(sender, e); + return; + } + + _mouseStart = e.Location; + + // check contextmenu + if (e.Button == MouseButtons.Right) + { + IDrawableContainerList selectedList = null; + if (selectedElements != null && selectedElements.Count > 0) + { + selectedList = selectedElements; + } + else + { + // Single element + IDrawableContainer rightClickedContainer = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); + if (rightClickedContainer != null) + { + selectedList = new DrawableContainerList(ID) + { + rightClickedContainer + }; + } + } + + if (selectedList != null && selectedList.Count > 0) + { + selectedList.ShowContextMenu(e, this); + } + + return; + } + + _mouseDown = true; + _isSurfaceMoveMadeUndoable = false; + + if (_cropContainer != null && ((_undrawnElement == null) || (_undrawnElement != null && DrawingMode != DrawingModes.Crop))) + { + RemoveElement(_cropContainer, false); + _cropContainer = null; + _drawingElement = null; + } + + if (_drawingElement == null && DrawingMode != DrawingModes.None) + { + if (_undrawnElement == null) + { + DeselectAllElements(); + if (_undrawnElement == null) + { + CreateUndrawnElement(); + } + } + + _drawingElement = _undrawnElement; + // if a new element has been drawn, set location and register it + if (_drawingElement != null) + { + if (_undrawnElement != null) + { + _drawingElement.Status = _undrawnElement.DefaultEditMode; + } + + if (!_drawingElement.HandleMouseDown(_mouseStart.X, _mouseStart.Y)) + { + _drawingElement.Left = _mouseStart.X; + _drawingElement.Top = _mouseStart.Y; + } + + AddElement(_drawingElement); + _drawingElement.Selected = true; + } + + _undrawnElement = null; + } + else + { + // check whether an existing element was clicked + // we save mouse down element separately from selectedElements (checked on mouse up), + // since it could be moved around before it is actually selected + _mouseDownElement = _elements.ClickableElementAt(_mouseStart.X, _mouseStart.Y); + + if (_mouseDownElement != null) + { + _mouseDownElement.Status = EditStatus.MOVING; + } + } + } + + /// + /// This event handle is called when the mouse button is unpressed + /// + /// + /// + private void SurfaceMouseUp(object sender, MouseEventArgs e) + { + e = InverseZoomMouseCoordinates(e); + + // Handle Adorners + var adorner = FindActiveAdorner(e); + if (adorner != null) + { + adorner.MouseUp(sender, e); + return; + } + + Point currentMouse = new Point(e.X, e.Y); + + _elements.Status = EditStatus.IDLE; + if (_mouseDownElement != null) + { + _mouseDownElement.Status = EditStatus.IDLE; + } + + _mouseDown = false; + _mouseDownElement = null; + if (DrawingMode == DrawingModes.None) + { + // check whether an existing element was clicked + IDrawableContainer element = _elements.ClickableElementAt(currentMouse.X, currentMouse.Y); + bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; + if (element != null) + { + element.Invalidate(); + bool alreadySelected = selectedElements.Contains(element); + if (shiftModifier) + { + if (alreadySelected) + { + DeselectElement(element); + } + else + { + SelectElement(element); + } + } + else + { + if (!alreadySelected) + { + DeselectAllElements(); + SelectElement(element); + } + } + } + else if (!shiftModifier) + { + DeselectAllElements(); + } + } + + if (selectedElements.Count > 0) + { + selectedElements.Invalidate(); + selectedElements.Selected = true; + } + + if (_drawingElement != null) + { + if (!_drawingElement.InitContent()) + { + _elements.Remove(_drawingElement); + _drawingElement.Invalidate(); + } + else + { + _drawingElement.HandleMouseUp(currentMouse.X, currentMouse.Y); + _drawingElement.Invalidate(); + if (Math.Abs(_drawingElement.Width) < 5 && Math.Abs(_drawingElement.Height) < 5) + { + _drawingElement.Width = 25; + _drawingElement.Height = 25; + } + + SelectElement(_drawingElement); + _drawingElement.Selected = true; + } + + _drawingElement = null; + } + } + + /// + /// This event handler is called when the mouse moves over the surface + /// + /// + /// + private void SurfaceMouseMove(object sender, MouseEventArgs e) + { + e = InverseZoomMouseCoordinates(e); + + // Handle Adorners + var adorner = FindActiveAdorner(e); + if (adorner != null) + { + adorner.MouseMove(sender, e); + return; + } + + Point currentMouse = e.Location; + + Cursor = DrawingMode != DrawingModes.None ? Cursors.Cross : Cursors.Default; + + if (_mouseDown) + { + if (_mouseDownElement != null) + { + // an element is currently dragged + _mouseDownElement.Invalidate(); + selectedElements.Invalidate(); + // Move the element + if (_mouseDownElement.Selected) + { + if (!_isSurfaceMoveMadeUndoable) + { + // Only allow one undoable per mouse-down/move/up "cycle" + _isSurfaceMoveMadeUndoable = true; + selectedElements.MakeBoundsChangeUndoable(false); + } + + // dragged element has been selected before -> move all + selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); + } + else + { + if (!_isSurfaceMoveMadeUndoable) + { + // Only allow one undoable per mouse-down/move/up "cycle" + _isSurfaceMoveMadeUndoable = true; + _mouseDownElement.MakeBoundsChangeUndoable(false); + } + + // dragged element is not among selected elements -> just move dragged one + _mouseDownElement.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); + } + + _mouseStart = currentMouse; + _mouseDownElement.Invalidate(); + _modified = true; + } + else if (_drawingElement != null) + { + _drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); + _modified = true; + } + } + } + + /// + /// This event handler is called when the surface is double clicked. + /// + /// + /// + private void SurfaceDoubleClick(object sender, MouseEventArgs e) + { + selectedElements.OnDoubleClick(); + selectedElements.Invalidate(); + } + + /// + /// Privately used to get the rendered image with all the elements on it. + /// + /// + /// + private Image GetImage(RenderMode renderMode) + { + // Generate a copy of the original image with a dpi equal to the default... + Bitmap clone = ImageHelper.Clone(_image, PixelFormat.DontCare); + // otherwise we would have a problem drawing the image to the surface... :( + using (Graphics graphics = Graphics.FromImage(clone)) + { + // Do not set the following, the containers need to decide themselves + //graphics.SmoothingMode = SmoothingMode.HighQuality; + //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + //graphics.CompositingQuality = CompositingQuality.HighQuality; + //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + _elements.Draw(graphics, clone, renderMode, new Rectangle(Point.Empty, clone.Size)); + } + + return clone; + } + + /// + /// This returns the image "result" of this surface, with all the elements rendered on it. + /// + /// + public Image GetImageForExport() + { + return GetImage(RenderMode.EXPORT); + } + + private static Rectangle ZoomClipRectangle(Rectangle rc, double scale, int inflateAmount = 0) + { + rc = new Rectangle( + (int) (rc.X * scale), + (int) (rc.Y * scale), + (int) (rc.Width * scale) + 1, + (int) (rc.Height * scale) + 1 + ); + if (scale > 1) + { + inflateAmount = (int) (inflateAmount * scale); + } + + rc.Inflate(inflateAmount, inflateAmount); + return rc; + } + + public void InvalidateElements(Rectangle rc) + => Invalidate(ZoomClipRectangle(rc, _zoomFactor, 1)); + + /// + /// This is the event handler for the Paint Event, try to draw as little as possible! + /// + /// + /// PaintEventArgs + private void SurfacePaint(object sender, PaintEventArgs paintEventArgs) + { + Graphics targetGraphics = paintEventArgs.Graphics; + Rectangle targetClipRectangle = paintEventArgs.ClipRectangle; + if (Rectangle.Empty.Equals(targetClipRectangle)) + { + LOG.Debug("Empty cliprectangle??"); + return; + } + + // Correction to prevent rounding errors at certain zoom levels. + // When zooming to N/M, clip rectangle top and left coordinates should be multiples of N. + if (_zoomFactor.Numerator > 1 && _zoomFactor.Denominator > 1) + { + int horizontalCorrection = targetClipRectangle.Left % (int) _zoomFactor.Numerator; + int verticalCorrection = targetClipRectangle.Top % (int) _zoomFactor.Numerator; + if (horizontalCorrection != 0) + { + targetClipRectangle.X -= horizontalCorrection; + targetClipRectangle.Width += horizontalCorrection; + } + + if (verticalCorrection != 0) + { + targetClipRectangle.Y -= verticalCorrection; + targetClipRectangle.Height += verticalCorrection; + } + } + + Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2); + + if (_elements.HasIntersectingFilters(imageClipRectangle) || _zoomFactor > Fraction.Identity) + { + if (_buffer != null) + { + if (_buffer.Width != Image.Width || _buffer.Height != Image.Height || _buffer.PixelFormat != Image.PixelFormat) + { + _buffer.Dispose(); + _buffer = null; + } + } + + if (_buffer == null) + { + _buffer = ImageHelper.CreateEmpty(Image.Width, Image.Height, Image.PixelFormat, Color.Empty, Image.HorizontalResolution, Image.VerticalResolution); + LOG.DebugFormat("Created buffer with size: {0}x{1}", Image.Width, Image.Height); + } + + // Elements might need the bitmap, so we copy the part we need + using (Graphics graphics = Graphics.FromImage(_buffer)) + { + // do not set the following, the containers need to decide this themselves! + //graphics.SmoothingMode = SmoothingMode.HighQuality; + //graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + //graphics.CompositingQuality = CompositingQuality.HighQuality; + //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + DrawBackground(graphics, imageClipRectangle); + graphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + graphics.SetClip(ZoomClipRectangle(Rectangle.Round(targetGraphics.ClipBounds), _zoomFactor.Inverse(), 2)); + _elements.Draw(graphics, _buffer, RenderMode.EDIT, imageClipRectangle); + } + + if (_zoomFactor == Fraction.Identity) + { + targetGraphics.DrawImage(_buffer, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + } + else + { + targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); + if (_zoomFactor > Fraction.Identity) + { + DrawSharpImage(targetGraphics, _buffer, imageClipRectangle); + } + else + { + DrawSmoothImage(targetGraphics, _buffer, imageClipRectangle); + } + + targetGraphics.ResetTransform(); + } + } + else + { + DrawBackground(targetGraphics, targetClipRectangle); + if (_zoomFactor == Fraction.Identity) + { + targetGraphics.DrawImage(Image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); + } + else + { + targetGraphics.ScaleTransform(_zoomFactor, _zoomFactor); + DrawSmoothImage(targetGraphics, Image, imageClipRectangle); + _elements.Draw(targetGraphics, null, RenderMode.EDIT, imageClipRectangle); + targetGraphics.ResetTransform(); + } + } + + // No clipping for the adorners + targetGraphics.ResetClip(); + // Draw adorners last + foreach (var drawableContainer in selectedElements) + { + foreach (var adorner in drawableContainer.Adorners) + { + adorner.Paint(paintEventArgs); + } + } + } + + private void DrawSmoothImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) + { + var state = targetGraphics.Save(); + targetGraphics.SmoothingMode = SmoothingMode.HighQuality; + targetGraphics.InterpolationMode = InterpolationMode.HighQualityBilinear; + targetGraphics.CompositingQuality = CompositingQuality.HighQuality; + targetGraphics.PixelOffsetMode = PixelOffsetMode.None; + + targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + + targetGraphics.Restore(state); + } + + private void DrawSharpImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) + { + var state = targetGraphics.Save(); + targetGraphics.SmoothingMode = SmoothingMode.None; + targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; + targetGraphics.CompositingQuality = CompositingQuality.HighQuality; + targetGraphics.PixelOffsetMode = PixelOffsetMode.None; + + targetGraphics.DrawImage(image, imageClipRectangle, imageClipRectangle, GraphicsUnit.Pixel); + + targetGraphics.Restore(state); + } + + private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) + { + // check if we need to draw the checkerboard + if (Image.IsAlphaPixelFormat(Image.PixelFormat) && _transparencyBackgroundBrush != null) + { + targetGraphics.FillRectangle(_transparencyBackgroundBrush, clipRectangle); + } + else + { + targetGraphics.Clear(BackColor); + } + } + + /// + /// Draw a checkboard when capturing with transparency + /// + /// PaintEventArgs + protected override void OnPaintBackground(PaintEventArgs e) + { + } + + /// + /// Add a new element to the surface + /// + /// the new element + /// true if the adding should be undoable + /// true if invalidate needs to be called + public void AddElement(IDrawableContainer element, bool makeUndoable = true, bool invalidate = true) + { + _elements.Add(element); + if (element is DrawableContainer container) + { + container.FieldChanged += Element_FieldChanged; + } + + element.Parent = this; + if (element.Status == EditStatus.UNDRAWN) + { + element.Status = EditStatus.IDLE; + } + + if (element.Selected) + { + // Use false, as the element is invalidated when invalidate == true anyway + SelectElement(element, false); + } + + if (invalidate) + { + element.Invalidate(); + } + + if (makeUndoable) + { + MakeUndoable(new AddElementMemento(this, element), false); + } + + _modified = true; + } + + /// + /// Remove the list of elements + /// + /// IDrawableContainerList + /// flag specifying if the remove needs to be undoable + public void RemoveElements(IDrawableContainerList elementsToRemove, bool makeUndoable = true) + { + // fix potential issues with iterating a changing list + DrawableContainerList cloned = new DrawableContainerList(); + cloned.AddRange(elementsToRemove); + if (makeUndoable) + { + MakeUndoable(new DeleteElementsMemento(this, cloned), false); + } + + SuspendLayout(); + foreach (var drawableContainer in cloned) + { + RemoveElement(drawableContainer, false, false, false); + } + + ResumeLayout(); + Invalidate(); + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs + { + Elements = cloned + }; + _movingElementChanged(this, eventArgs); + } + } + + /// + /// Remove an element of the elements list + /// + /// Element to remove + /// flag specifying if the remove needs to be undoable + /// flag specifying if an surface invalidate needs to be called + /// false to skip event generation + public void RemoveElement(IDrawableContainer elementToRemove, bool makeUndoable = true, bool invalidate = true, bool generateEvents = true) + { + DeselectElement(elementToRemove, generateEvents); + _elements.Remove(elementToRemove); + if (elementToRemove is DrawableContainer element) + { + element.FieldChanged -= Element_FieldChanged; + } + + if (elementToRemove != null) + { + elementToRemove.Parent = null; + } + + // Do not dispose, the memento should!! element.Dispose(); + if (invalidate) + { + Invalidate(); + } + + if (makeUndoable) + { + MakeUndoable(new DeleteElementMemento(this, elementToRemove), false); + } + + _modified = true; + } + + /// + /// Add the supplied elements to the surface + /// + /// DrawableContainerList + /// true if the adding should be undoable + public void AddElements(IDrawableContainerList elementsToAdd, bool makeUndoable = true) + { + // fix potential issues with iterating a changing list + DrawableContainerList cloned = new DrawableContainerList(); + cloned.AddRange(elementsToAdd); + if (makeUndoable) + { + MakeUndoable(new AddElementsMemento(this, cloned), false); + } + + SuspendLayout(); + foreach (var element in cloned) + { + element.Selected = true; + AddElement(element, false, false); + } + + ResumeLayout(); + Invalidate(); + } + + /// + /// Returns if this surface has selected elements + /// + /// + public bool HasSelectedElements => (selectedElements != null && selectedElements.Count > 0); + + /// + /// Remove all the selected elements + /// + public void RemoveSelectedElements() + { + if (HasSelectedElements) + { + // As RemoveElement will remove the element from the selectedElements list we need to copy the element to another list. + RemoveElements(selectedElements); + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); + _movingElementChanged(this, eventArgs); + } + } + } + + /// + /// Cut the selected elements from the surface to the clipboard + /// + public void CutSelectedElements() + { + if (HasSelectedElements) + { + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); + RemoveSelectedElements(); + } + } + + /// + /// Copy the selected elements to the clipboard + /// + public void CopySelectedElements() + { + if (HasSelectedElements) + { + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); + } + } + + /// + /// This method is called to confirm/cancel "confirmable" elements, like the crop-container. + /// Called when pressing enter or using the "check" in the editor. + /// + /// + public void ConfirmSelectedConfirmableElements(bool confirm) + { + // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel) + List selectedDCs = new List(selectedElements); + foreach (IDrawableContainer dc in selectedDCs) + { + if (dc.Equals(_cropContainer)) + { + DrawingMode = DrawingModes.None; + // No undo memento for the cropcontainer itself, only for the effect + RemoveElement(_cropContainer, false); + if (confirm) + { + ApplyCrop(_cropContainer.Bounds); + } + + _cropContainer.Dispose(); + _cropContainer = null; + break; + } + } + } + + /// + /// Paste all the elements that are on the clipboard + /// + public void PasteElementFromClipboard() + { + IDataObject clipboard = ClipboardHelper.GetDataObject(); + + var formats = ClipboardHelper.GetFormats(clipboard); + if (formats == null || formats.Count == 0) + { + return; + } + + if (LOG.IsDebugEnabled) + { + LOG.Debug("List of clipboard formats available for pasting:"); + foreach (string format in formats) + { + LOG.Debug("\tgot format: " + format); + } + } + + if (formats.Contains(typeof(IDrawableContainerList).FullName)) + { + IDrawableContainerList dcs = (IDrawableContainerList) ClipboardHelper.GetFromDataObject(clipboard, typeof(IDrawableContainerList)); + if (dcs != null) + { + // Make element(s) only move 10,10 if the surface is the same + bool isSameSurface = (dcs.ParentID == _uniqueId); + dcs.Parent = this; + var moveOffset = isSameSurface ? new Point(10, 10) : Point.Empty; + // Here a fix for bug #1475, first calculate the bounds of the complete IDrawableContainerList + Rectangle drawableContainerListBounds = Rectangle.Empty; + foreach (var element in dcs) + { + drawableContainerListBounds = drawableContainerListBounds == Rectangle.Empty + ? element.DrawingBounds + : Rectangle.Union(drawableContainerListBounds, element.DrawingBounds); + } + + // And find a location inside the target surface to paste to + bool containersCanFit = drawableContainerListBounds.Width < Bounds.Width && drawableContainerListBounds.Height < Bounds.Height; + if (!containersCanFit) + { + Point containersLocation = drawableContainerListBounds.Location; + containersLocation.Offset(moveOffset); + if (!Bounds.Contains(containersLocation)) + { + // Easy fix for same surface + moveOffset = isSameSurface + ? new Point(-10, -10) + : new Point(-drawableContainerListBounds.Location.X + 10, -drawableContainerListBounds.Location.Y + 10); + } + } + else + { + Rectangle moveContainerListBounds = drawableContainerListBounds; + moveContainerListBounds.Offset(moveOffset); + // check if the element is inside + if (!Bounds.Contains(moveContainerListBounds)) + { + // Easy fix for same surface + if (isSameSurface) + { + moveOffset = new Point(-10, -10); + } + else + { + // For different surface, which is most likely smaller + int offsetX = 0; + int offsetY = 0; + if (drawableContainerListBounds.Right > Bounds.Right) + { + offsetX = Bounds.Right - drawableContainerListBounds.Right; + // Correction for the correction + if (drawableContainerListBounds.Left + offsetX < 0) + { + offsetX += Math.Abs(drawableContainerListBounds.Left + offsetX); + } + } + + if (drawableContainerListBounds.Bottom > Bounds.Bottom) + { + offsetY = Bounds.Bottom - drawableContainerListBounds.Bottom; + // Correction for the correction + if (drawableContainerListBounds.Top + offsetY < 0) + { + offsetY += Math.Abs(drawableContainerListBounds.Top + offsetY); + } + } + + moveOffset = new Point(offsetX, offsetY); + } + } + } + + dcs.MoveBy(moveOffset.X, moveOffset.Y); + AddElements(dcs); + FieldAggregator.BindElements(dcs); + DeselectAllElements(); + SelectElements(dcs); + } + } + else if (ClipboardHelper.ContainsImage(clipboard)) + { + Point pasteLocation = GetPasteLocation(0.1f, 0.1f); + + foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) + { + if (clipboardImage != null) + { + DeselectAllElements(); + IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y); + SelectElement(container); + clipboardImage.Dispose(); + pasteLocation.X += 10; + pasteLocation.Y += 10; + } + } + } + else if (ClipboardHelper.ContainsText(clipboard)) + { + Point pasteLocation = GetPasteLocation(0.4f, 0.4f); + + string text = ClipboardHelper.GetText(clipboard); + if (text != null) + { + DeselectAllElements(); + ITextContainer textContainer = AddTextContainer(text, pasteLocation.X, pasteLocation.Y, + FontFamily.GenericSansSerif, 12f, false, false, false, 2, Color.Black, Color.Transparent); + SelectElement(textContainer); + } + } + } + + /// + /// Find a location to paste elements. + /// If mouse is over the surface - use it's position, otherwise use the visible area. + /// Return a point in image coordinate space. + /// + /// 0.0f for the left edge of visible area, 1.0f for the right edge of visible area. + /// 0.0f for the top edge of visible area, 1.0f for the bottom edge of visible area. + private Point GetPasteLocation(float horizontalRatio = 0.5f, float verticalRatio = 0.5f) + { + var point = PointToClient(MousePosition); + var rc = GetVisibleRectangle(); + if (!rc.Contains(point)) + { + point = new Point( + rc.Left + (int) (rc.Width * horizontalRatio), + rc.Top + (int) (rc.Height * verticalRatio) + ); + } + + return ToImageCoordinates(point); + } + + /// + /// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space). + /// + public Rectangle GetVisibleRectangle() + { + var bounds = Bounds; + var clientArea = Parent.ClientRectangle; + return new Rectangle( + Math.Max(0, -bounds.Left), + Math.Max(0, -bounds.Top), + clientArea.Width, + clientArea.Height + ); + } + + /// + /// Get the rectangle bounding all selected elements (in surface coordinates space), + /// or empty rectangle if nothing is selcted. + /// + public Rectangle GetSelectionRectangle() + => ToSurfaceCoordinates(selectedElements.DrawingBounds); + + /// + /// Duplicate all the selecteded elements + /// + public void DuplicateSelectedElements() + { + LOG.DebugFormat("Duplicating {0} selected elements", selectedElements.Count); + IDrawableContainerList dcs = selectedElements.Clone(); + dcs.Parent = this; + dcs.MoveBy(10, 10); + AddElements(dcs); + DeselectAllElements(); + SelectElements(dcs); + } + + /// + /// Deselect the specified element + /// + /// IDrawableContainerList + /// false to skip event generation + public void DeselectElement(IDrawableContainer container, bool generateEvents = true) + { + container.Selected = false; + selectedElements.Remove(container); + FieldAggregator.UnbindElement(container); + if (generateEvents && _movingElementChanged != null) + { + var eventArgs = new SurfaceElementEventArgs + { + Elements = selectedElements + }; + _movingElementChanged(this, eventArgs); + } + } + + /// + /// Deselect the specified elements + /// + /// IDrawableContainerList + public void DeselectElements(IDrawableContainerList elements) + { + if (elements.Count == 0) + { + return; + } + + while (elements.Count > 0) + { + var element = elements[0]; + DeselectElement(element, false); + } + + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs + { + Elements = selectedElements + }; + _movingElementChanged(this, eventArgs); + } + + Invalidate(); + } + + /// + /// Deselect all the selected elements + /// + public void DeselectAllElements() + { + DeselectElements(selectedElements); + } + + /// + /// Select the supplied element + /// + /// + /// false to skip invalidation + /// false to skip event generation + public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true) + { + if (!selectedElements.Contains(container)) + { + selectedElements.Add(container); + container.Selected = true; + FieldAggregator.BindElement(container); + if (generateEvents && _movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs + { + Elements = selectedElements + }; + _movingElementChanged(this, eventArgs); + } + + if (invalidate) + { + container.Invalidate(); + } + } + } + + /// + /// Select all elements, this is called when Ctrl+A is pressed + /// + public void SelectAllElements() + { + SelectElements(_elements); + } + + /// + /// Select the supplied elements + /// + /// + public void SelectElements(IDrawableContainerList elements) + { + SuspendLayout(); + foreach (var drawableContainer in elements) + { + var element = (DrawableContainer) drawableContainer; + SelectElement(element, false, false); + } + + if (_movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs + { + Elements = selectedElements + }; + _movingElementChanged(this, eventArgs); + } + + ResumeLayout(); + Invalidate(); + } + + /// + /// Process key presses on the surface, this is called from the editor (and NOT an override from the Control) + /// + /// Keys + /// false if no keys were processed + public bool ProcessCmdKey(Keys k) + { + if (selectedElements.Count > 0) + { + bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; + int px = shiftModifier ? 10 : 1; + Point moveBy = Point.Empty; + + switch (k) + { + case Keys.Left: + case Keys.Left | Keys.Shift: + moveBy = new Point(-px, 0); + break; + case Keys.Up: + case Keys.Up | Keys.Shift: + moveBy = new Point(0, -px); + break; + case Keys.Right: + case Keys.Right | Keys.Shift: + moveBy = new Point(px, 0); + break; + case Keys.Down: + case Keys.Down | Keys.Shift: + moveBy = new Point(0, px); + break; + case Keys.PageUp: + PullElementsUp(); + break; + case Keys.PageDown: + PushElementsDown(); + break; + case Keys.Home: + PullElementsToTop(); + break; + case Keys.End: + PushElementsToBottom(); + break; + case Keys.Enter: + ConfirmSelectedConfirmableElements(true); + break; + case Keys.Escape: + ConfirmSelectedConfirmableElements(false); + break; + /*case Keys.Delete: + RemoveSelectedElements(); + break;*/ + default: + return false; + } + + if (!Point.Empty.Equals(moveBy)) + { + selectedElements.MakeBoundsChangeUndoable(true); + selectedElements.MoveBy(moveBy.X, moveBy.Y); + } + + return true; + } + + return false; + } + + /// + /// Property for accessing the elements on the surface + /// + public IDrawableContainerList Elements => _elements; + + /// + /// pulls selected elements up one level in hierarchy + /// + public void PullElementsUp() + { + _elements.PullElementsUp(selectedElements); + _elements.Invalidate(); + } + + /// + /// pushes selected elements up to top in hierarchy + /// + public void PullElementsToTop() + { + _elements.PullElementsToTop(selectedElements); + _elements.Invalidate(); + } + + /// + /// pushes selected elements down one level in hierarchy + /// + public void PushElementsDown() + { + _elements.PushElementsDown(selectedElements); + _elements.Invalidate(); + } + + /// + /// pushes selected elements down to bottom in hierarchy + /// + public void PushElementsToBottom() + { + _elements.PushElementsToBottom(selectedElements); + _elements.Invalidate(); + } + + /// + /// indicates whether the selected elements could be pulled up in hierarchy + /// + /// true if selected elements could be pulled up, false otherwise + public bool CanPullSelectionUp() + { + return _elements.CanPullUp(selectedElements); + } + + /// + /// indicates whether the selected elements could be pushed down in hierarchy + /// + /// true if selected elements could be pushed down, false otherwise + public bool CanPushSelectionDown() + { + return _elements.CanPushDown(selectedElements); + } + + public void Element_FieldChanged(object sender, FieldChangedEventArgs e) + { + selectedElements.HandleFieldChangedEvent(sender, e); + } + + public bool IsOnSurface(IDrawableContainer container) + { + return _elements.Contains(container); + } + + public Point ToSurfaceCoordinates(Point point) + { + Point[] points = + { + point + }; + _zoomMatrix.TransformPoints(points); + return points[0]; + } + + public Rectangle ToSurfaceCoordinates(Rectangle rc) + { + if (_zoomMatrix.IsIdentity) + { + return rc; + } + else + { + Point[] points = + { + rc.Location, rc.Location + rc.Size + }; + _zoomMatrix.TransformPoints(points); + return new Rectangle( + points[0].X, + points[0].Y, + points[1].X - points[0].X, + points[1].Y - points[0].Y + ); + } + } + + public Point ToImageCoordinates(Point point) + { + Point[] points = + { + point + }; + _inverseZoomMatrix.TransformPoints(points); + return points[0]; + } + + public Rectangle ToImageCoordinates(Rectangle rc) + { + if (_inverseZoomMatrix.IsIdentity) + { + return rc; + } + else + { + Point[] points = + { + rc.Location, rc.Location + rc.Size + }; + _inverseZoomMatrix.TransformPoints(points); + return new Rectangle( + points[0].X, + points[0].Y, + points[1].X - points[0].X, + points[1].Y - points[0].Y + ); + } + } + } +} \ No newline at end of file diff --git a/Greenshot/Drawing/TextContainer.cs b/src/Greenshot/Drawing/TextContainer.cs similarity index 93% rename from Greenshot/Drawing/TextContainer.cs rename to src/Greenshot/Drawing/TextContainer.cs index 9d3838580..4888ef463 100644 --- a/Greenshot/Drawing/TextContainer.cs +++ b/src/Greenshot/Drawing/TextContainer.cs @@ -22,8 +22,6 @@ using Greenshot.Drawing.Fields; using Greenshot.Helpers; using Greenshot.Memento; -using GreenshotPlugin.Core; -using GreenshotPlugin.Interfaces.Drawing; using System; using System.ComponentModel; using System.Diagnostics; @@ -32,6 +30,8 @@ using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.Serialization; using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Drawing { @@ -46,24 +46,22 @@ namespace Greenshot.Drawing // Although the name is wrong, we can't change it due to file serialization // ReSharper disable once InconsistentNaming private bool makeUndoable; - [NonSerialized] - private Font _font; + [NonSerialized] private Font _font; public Font Font => _font; - [NonSerialized] - private TextBox _textBox; + [NonSerialized] private TextBox _textBox; /// /// The StringFormat object is not serializable!! /// - [NonSerialized] - private StringFormat _stringFormat = new StringFormat(); + [NonSerialized] private StringFormat _stringFormat = new StringFormat(); public StringFormat StringFormat => _stringFormat; // Although the name is wrong, we can't change it due to file serialization // ReSharper disable once InconsistentNaming private string text; + // there is a binding on the following property! public string Text { @@ -74,12 +72,13 @@ namespace Greenshot.Drawing internal void ChangeText(string newText, bool allowUndoable) { if ((text != null || newText == null) && string.Equals(text, newText)) return; - + if (makeUndoable && allowUndoable) { makeUndoable = false; _parent.MakeUndoable(new TextChangeMemento(this), false); } + text = newText; OnPropertyChanged("Text"); } @@ -122,17 +121,20 @@ namespace Greenshot.Drawing _font.Dispose(); _font = null; } + if (_stringFormat != null) { _stringFormat.Dispose(); _stringFormat = null; } + if (_textBox != null) { _textBox.Dispose(); _textBox = null; } } + base.Dispose(disposing); } @@ -158,6 +160,7 @@ namespace Greenshot.Drawing { _parent.SizeChanged -= Parent_SizeChanged; } + base.SwitchParent(newParent); if (_parent != null) { @@ -224,6 +227,7 @@ namespace Greenshot.Drawing _parent.KeysLocked = true; } } + if (_textBox.Visible) { _textBox.Invalidate(); @@ -236,10 +240,12 @@ namespace Greenshot.Drawing { return; } + if (_textBox.Visible) { _textBox.Invalidate(); } + // Only dispose the font, and re-create it, when a font field has changed. if (e.Field.FieldType.Name.StartsWith("FONT")) { @@ -248,12 +254,14 @@ namespace Greenshot.Drawing _font.Dispose(); _font = null; } + UpdateFormat(); } else { UpdateAlignment(); } + UpdateTextBoxFormat(); if (_textBox.Visible) @@ -292,6 +300,7 @@ namespace Greenshot.Drawing _parent.KeysLocked = true; _parent.Controls.Add(_textBox); } + EnsureTextBoxContrast(); if (_textBox != null) { @@ -309,6 +318,7 @@ namespace Greenshot.Drawing { return; } + Color lc = GetFieldValueAsColor(FieldType.LINE_COLOR); if (lc.R > 203 && lc.G > 203 && lc.B > 203) { @@ -328,6 +338,7 @@ namespace Greenshot.Drawing { return; } + _parent.KeysLocked = false; _parent.Controls.Remove(_textBox); } @@ -346,7 +357,7 @@ namespace Greenshot.Drawing rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); int pixelsAfter = rect.Width * rect.Height; - float factor = pixelsAfter / (float)pixelsBefore; + float factor = pixelsAfter / (float) pixelsBefore; float fontSize = GetFieldValueAsFloat(FieldType.FONT_SIZE); fontSize *= factor; @@ -393,6 +404,7 @@ namespace Greenshot.Drawing } } } + return new Font(fontFamily, fontSize, fontStyle, GraphicsUnit.Pixel); } @@ -405,6 +417,7 @@ namespace Greenshot.Drawing { return; } + string fontFamily = GetFieldValueAsString(FieldType.FONT_FAMILY); bool fontBold = GetFieldValueAsBool(FieldType.FONT_BOLD); bool fontItalic = GetFieldValueAsBool(FieldType.FONT_ITALIC); @@ -444,8 +457,8 @@ namespace Greenshot.Drawing private void UpdateAlignment() { - _stringFormat.Alignment = (StringAlignment)GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); - _stringFormat.LineAlignment = (StringAlignment)GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT); + _stringFormat.Alignment = (StringAlignment) GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); + _stringFormat.LineAlignment = (StringAlignment) GetFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT); } /// @@ -465,7 +478,7 @@ namespace Greenshot.Drawing _font.Size * textBoxFontScale, _font.Style, GraphicsUnit.Pixel - ); + ); _textBox.Font.Dispose(); _textBox.Font = newFont; } @@ -480,15 +493,17 @@ namespace Greenshot.Drawing { return; } + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - int lineWidth = (int)Math.Floor(lineThickness / 2d); + int lineWidth = (int) Math.Floor(lineThickness / 2d); int correction = (lineThickness + 1) % 2; if (lineThickness <= 1) { lineWidth = 1; correction = -1; } + Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); Rectangle displayRectangle = Parent.ToSurfaceCoordinates(absRectangle); _textBox.Left = displayRectangle.X + lineWidth; @@ -497,6 +512,7 @@ namespace Greenshot.Drawing { lineWidth = 0; } + _textBox.Width = displayRectangle.Width - 2 * lineWidth + correction; _textBox.Height = displayRectangle.Height - 2 * lineWidth + correction; } @@ -510,7 +526,8 @@ namespace Greenshot.Drawing { return; } - var alignment = (StringAlignment)GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); + + var alignment = (StringAlignment) GetFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); switch (alignment) { case StringAlignment.Near: @@ -541,6 +558,7 @@ namespace Greenshot.Drawing { _textBox.SelectAll(); } + // Added for FEATURE-1064 if (e.KeyCode == Keys.Back && e.Control) { @@ -550,11 +568,13 @@ namespace Greenshot.Drawing { selStart--; } + int prevSpacePos = -1; if (selStart != 0) { prevSpacePos = _textBox.Text.LastIndexOf(' ', selStart - 1); } + _textBox.Select(prevSpacePos + 1, _textBox.SelectionStart - prevSpacePos - 1); _textBox.SelectedText = string.Empty; } @@ -611,6 +631,7 @@ namespace Greenshot.Drawing { return flags; } + switch (stringFormat.LineAlignment) { case StringAlignment.Center: @@ -623,6 +644,7 @@ namespace Greenshot.Drawing flags |= TextFormatFlags.Top; break; } + switch (stringFormat.Alignment) { case StringAlignment.Center: @@ -650,7 +672,8 @@ namespace Greenshot.Drawing /// /// /// - public static void DrawText(Graphics graphics, Rectangle drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text, Font font) + public static void DrawText(Graphics graphics, Rectangle drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text, + Font font) { #if DEBUG Debug.Assert(font != null); @@ -660,7 +683,7 @@ namespace Greenshot.Drawing return; } #endif - int textOffset = lineThickness > 0 ? (int)Math.Ceiling(lineThickness / 2d) : 0; + int textOffset = lineThickness > 0 ? (int) Math.Ceiling(lineThickness / 2d) : 0; // draw shadow before anything else if (drawShadow) { @@ -699,4 +722,4 @@ namespace Greenshot.Drawing return r.Contains(x, y); } } -} +} \ No newline at end of file diff --git a/Greenshot/Forms/AboutForm.Designer.cs b/src/Greenshot/Forms/AboutForm.Designer.cs similarity index 90% rename from Greenshot/Forms/AboutForm.Designer.cs rename to src/Greenshot/Forms/AboutForm.Designer.cs index 4112df177..e34b65b03 100644 --- a/Greenshot/Forms/AboutForm.Designer.cs +++ b/src/Greenshot/Forms/AboutForm.Designer.cs @@ -20,8 +20,9 @@ */ using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; using Greenshot.Helpers; -using GreenshotPlugin.Core; namespace Greenshot.Forms { partial class AboutForm { @@ -50,19 +51,19 @@ namespace Greenshot.Forms { /// private void InitializeComponent() { this.lblTitle = new System.Windows.Forms.Label(); - this.lblLicense = new GreenshotPlugin.Controls.GreenshotLabel(); - this.lblHost = new GreenshotPlugin.Controls.GreenshotLabel(); + this.lblLicense = new GreenshotLabel(); + this.lblHost = new GreenshotLabel(); this.linkLblLicense = new System.Windows.Forms.LinkLabel(); this.linkLblHost = new System.Windows.Forms.LinkLabel(); this.linkLblBugs = new System.Windows.Forms.LinkLabel(); - this.lblBugs = new GreenshotPlugin.Controls.GreenshotLabel(); + this.lblBugs = new GreenshotLabel(); this.linkLblDonations = new System.Windows.Forms.LinkLabel(); - this.lblDonations = new GreenshotPlugin.Controls.GreenshotLabel(); + this.lblDonations = new GreenshotLabel(); this.linkLblIcons = new System.Windows.Forms.LinkLabel(); - this.lblIcons = new GreenshotPlugin.Controls.GreenshotLabel(); + this.lblIcons = new GreenshotLabel(); this.linkLabel1 = new System.Windows.Forms.LinkLabel(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); - this.lblTranslation = new GreenshotPlugin.Controls.GreenshotLabel(); + this.lblTranslation = new GreenshotLabel(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.SuspendLayout(); // @@ -236,11 +237,11 @@ namespace Greenshot.Forms { private System.Windows.Forms.LinkLabel linkLblIcons; private System.Windows.Forms.Label lblTitle; private System.Windows.Forms.PictureBox pictureBox1; - private GreenshotPlugin.Controls.GreenshotLabel lblTranslation; - private GreenshotPlugin.Controls.GreenshotLabel lblHost; - private GreenshotPlugin.Controls.GreenshotLabel lblDonations; - private GreenshotPlugin.Controls.GreenshotLabel lblBugs; - private GreenshotPlugin.Controls.GreenshotLabel lblIcons; - private GreenshotPlugin.Controls.GreenshotLabel lblLicense; + private GreenshotLabel lblTranslation; + private GreenshotLabel lblHost; + private GreenshotLabel lblDonations; + private GreenshotLabel lblBugs; + private GreenshotLabel lblIcons; + private GreenshotLabel lblLicense; } } diff --git a/src/Greenshot/Forms/AboutForm.cs b/src/Greenshot/Forms/AboutForm.cs new file mode 100644 index 000000000..7ecad5ccc --- /dev/null +++ b/src/Greenshot/Forms/AboutForm.cs @@ -0,0 +1,389 @@ +/* +* Greenshot - a free and open source screenshot tool +* Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom +* +* For more information see: http://getgreenshot.org/ +* The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 1 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Security.Permissions; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Configuration; +using Greenshot.Helpers; +using log4net; + +namespace Greenshot.Forms +{ + /// + /// The about form + /// + public sealed partial class AboutForm : AnimatingBaseForm + { + private static readonly ILog Log = LogManager.GetLogger(typeof(AboutForm)); + private Bitmap _bitmap; + private readonly ColorAnimator _backgroundAnimation; + private readonly List _pixels = new List(); + private readonly List _colorFlow = new List(); + private readonly List _pixelColors = new List(); + private readonly Random _rand = new Random(); + private readonly Color _backColor = Color.FromArgb(61, 61, 61); + private readonly Color _pixelColor = Color.FromArgb(138, 255, 0); + + // Variables used for the color-cycle + private int _waitFrames; + private int _colorIndex; + private int _scrollCount; + private bool _hasAnimationsLeft; + + // Variables are used to define the location of the dots + private const int W = 13; + private const int P1 = 7; + private const int P2 = P1 + W; + private const int P3 = P2 + W; + private const int P4 = P3 + W; + private const int P5 = P4 + W; + private const int P6 = P5 + W; + private const int P7 = P6 + W; + + /// + /// The location of every dot in the "G" + /// + private readonly List _gSpots = new List + { + // Top row + new Point(P2, P1), // 0 + new Point(P3, P1), // 1 + new Point(P4, P1), // 2 + new Point(P5, P1), // 3 + new Point(P6, P1), // 4 + + // Second row + new Point(P1, P2), // 5 + new Point(P2, P2), // 6 + + // Third row + new Point(P1, P3), // 7 + new Point(P2, P3), // 8 + + // Fourth row + new Point(P1, P4), // 9 + new Point(P2, P4), // 10 + new Point(P5, P4), // 11 + new Point(P6, P4), // 12 + new Point(P7, P4), // 13 + + // Fifth row + new Point(P1, P5), // 14 + new Point(P2, P5), // 15 + new Point(P6, P5), // 16 + new Point(P7, P5), // 17 + + // Sixth row + new Point(P1, P6), // 18 + new Point(P2, P6), // 19 + new Point(P3, P6), // 20 + new Point(P4, P6), // 21 + new Point(P5, P6), // 22 + new Point(P6, P6) // 23 + }; + + // 0 1 2 3 4 + // 5 6 + // 7 8 + // 9 10 11 12 13 + // 14 15 16 17 + // 18 19 20 21 22 23 + + // The order in which we draw the dots & flow the colors. + private readonly List _flowOrder = new List{ 4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11 }; + + /// + /// Cleanup all the allocated resources + /// + private void Cleanup(object sender, EventArgs e) + { + if (_bitmap == null) return; + _bitmap.Dispose(); + _bitmap = null; + } + + /// + /// Constructor + /// + public AboutForm() + { + // Make sure our resources are removed again. + Disposed += Cleanup; + FormClosing += Cleanup; + + // Enable animation for this form, when we don't set this the timer doesn't start as soon as the form is loaded. + EnableAnimation = true; + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + + // Only use double-buffering when we are NOT in a Terminal Server session + DoubleBuffered = !IsTerminalServerSession; + + // Use the self drawn image, first we create the background to be the back-color (as we animate from this) + + _bitmap = ImageHelper.CreateEmpty(90, 90, PixelFormat.Format24bppRgb, BackColor, 96, 96); + pictureBox1.Image = _bitmap; + + lblTitle.Text = $@"Greenshot {EnvironmentInfo.GetGreenshotVersion()} {(IniConfig.IsPortable ? " Portable" : "")} ({OsInfo.Bits}) bit)"; + + // Number of frames the pixel animation takes + int frames = FramesForMillis(2000); + // The number of frames the color-cycle waits before it starts + _waitFrames = FramesForMillis(6000); + + // Every pixel is created after pixelWaitFrames frames, which is increased in the loop. + int pixelWaitFrames = FramesForMillis(2000); + // Create pixels + for (int index = 0; index < _gSpots.Count; index++) + { + // Read the pixels in the order of the flow + Point gSpot = _gSpots[_flowOrder[index]]; + // Create the animation, first we do nothing (on the final destination) + RectangleAnimator pixelAnimation; + + // Make the pixel grow from the middle, if this offset isn't used it looks like it's shifted + int offset = (W - 2) / 2; + + // If the optimize for Terminal Server is set we make the animation without much ado + if (IsTerminalServerSession) + { + // No animation + pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic, + EasingMode.EaseIn); + } + else + { + // Create the animation, first we do nothing (on the final destination) + Rectangle standingStill = new Rectangle(gSpot.X + offset, gSpot.Y + offset, 0, 0); + pixelAnimation = new RectangleAnimator(standingStill, standingStill, pixelWaitFrames, EasingType.Quintic, EasingMode.EaseIn); + // And than we size to the wanted size. + pixelAnimation.QueueDestinationLeg(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), frames); + } + + // Increase the wait frames + pixelWaitFrames += FramesForMillis(100); + // Add to the list of to be animated pixels + _pixels.Add(pixelAnimation); + // Add a color to the list for this pixel. + _pixelColors.Add(_pixelColor); + } + + // Make sure the frame "loop" knows we have to animate + _hasAnimationsLeft = true; + + // Pixel Color cycle colors, here we use a pre-animated loop which stores the values. + ColorAnimator pixelColorAnimator = new ColorAnimator(_pixelColor, Color.FromArgb(255, 255, 255), 6, EasingType.Quadratic, EasingMode.EaseIn); + pixelColorAnimator.QueueDestinationLeg(_pixelColor, 6, EasingType.Quadratic, EasingMode.EaseOut); + do + { + _colorFlow.Add(pixelColorAnimator.Current); + pixelColorAnimator.Next(); + } while (pixelColorAnimator.HasNext); + + // color animation for the background + _backgroundAnimation = new ColorAnimator(BackColor, _backColor, FramesForMillis(5000), EasingType.Linear, EasingMode.EaseIn); + } + + /// + /// This is called when a link is clicked + /// + /// + /// + private void LinkLabelClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (!(sender is LinkLabel linkLabel)) return; + try + { + linkLabel.LinkVisited = true; + Process.Start(linkLabel.Text); + } + catch (Exception) + { + MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, linkLabel.Text), Language.GetString(LangKey.error)); + } + } + + /// + /// Called from the AnimatingForm, for every frame + /// + protected override void Animate() + { + if (_bitmap == null) + { + return; + } + + if (!IsTerminalServerSession) + { + // Color cycle + if (_waitFrames != 0) + { + _waitFrames--; + // Check if there is something else to do, if not we return so we don't occupy the CPU + if (!_hasAnimationsLeft) + { + return; + } + } + else if (_scrollCount < _pixelColors.Count + _colorFlow.Count) + { + // Scroll colors, the scrollCount is the amount of pixels + the amount of colors to cycle. + for (int index = _pixelColors.Count - 1; index > 0; index--) + { + _pixelColors[index] = _pixelColors[index - 1]; + } + + // Keep adding from the colors to cycle until there is nothing left + if (_colorIndex < _colorFlow.Count) + { + _pixelColors[0] = _colorFlow[_colorIndex++]; + } + + _scrollCount++; + } + else + { + // Reset values, wait X time for the next one + _waitFrames = FramesForMillis(3000 + _rand.Next(35000)); + _colorIndex = 0; + _scrollCount = 0; + // Check if there is something else to do, if not we return so we don't occupy the CPU + if (!_hasAnimationsLeft) + { + return; + } + } + } + else if (!_hasAnimationsLeft) + { + return; + } + + // Draw the "G" + using (Graphics graphics = Graphics.FromImage(_bitmap)) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + graphics.Clear(_backgroundAnimation.Next()); + + graphics.TranslateTransform(2, -2); + graphics.RotateTransform(20); + + using SolidBrush brush = new SolidBrush(_pixelColor); + int index = 0; + // We assume there is nothing to animate in the next Animate loop + _hasAnimationsLeft = false; + // Pixels of the G + foreach (RectangleAnimator pixel in _pixels) + { + brush.Color = _pixelColors[index++]; + graphics.FillEllipse(brush, pixel.Current); + // If a pixel still has frames left, the hasAnimationsLeft will be true + _hasAnimationsLeft |= pixel.HasNext; + pixel.Next(); + } + } + + pictureBox1.Invalidate(); + } + + /// + /// CmdKey handler + /// + /// + /// + /// + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + try + { + switch (keyData) + { + case Keys.Escape: + DialogResult = DialogResult.Cancel; + break; + case Keys.E: + MessageBox.Show(EnvironmentInfo.EnvironmentToString(true)); + break; + case Keys.L: + try + { + if (File.Exists(MainForm.LogFileLocation)) + { + using (Process.Start("\"" + MainForm.LogFileLocation + "\"")) + { + // nothing to do, just using dispose to cleanup + } + } + else + { + MessageBox.Show(@"Greenshot can't find the logfile, it should have been here: " + MainForm.LogFileLocation); + } + } + catch (Exception) + { + MessageBox.Show(@"Couldn't open the greenshot.log, it's located here: " + MainForm.LogFileLocation, @"Error opening greenshot.log", + MessageBoxButtons.OK, MessageBoxIcon.Asterisk); + } + + break; + case Keys.I: + try + { + using (Process.Start("\"" + IniConfig.ConfigLocation + "\"")) + { + } + } + catch (Exception) + { + MessageBox.Show(@"Couldn't open the greenshot.ini, it's located here: " + IniConfig.ConfigLocation, @"Error opening greenshot.ini", + MessageBoxButtons.OK, MessageBoxIcon.Asterisk); + } + + break; + default: + return base.ProcessCmdKey(ref msg, keyData); + } + } + catch (Exception ex) + { + Log.Error($"Error handling key '{keyData}'", ex); + } + + return true; + } + } +} \ No newline at end of file diff --git a/Greenshot/Forms/AnimatingBaseForm.cs b/src/Greenshot/Forms/AnimatingBaseForm.cs similarity index 75% rename from Greenshot/Forms/AnimatingBaseForm.cs rename to src/Greenshot/Forms/AnimatingBaseForm.cs index 5456ba037..6f131381b 100644 --- a/Greenshot/Forms/AnimatingBaseForm.cs +++ b/src/Greenshot/Forms/AnimatingBaseForm.cs @@ -19,12 +19,14 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace Greenshot.Forms { - /// - /// This class is only here to help in the Designer mode, so it's clear where the language files are - /// - public class AnimatingBaseForm : AnimatingForm { - } -} +namespace Greenshot.Forms +{ + /// + /// This class is only here to help in the Designer mode, so it's clear where the language files are + /// + public class AnimatingBaseForm : AnimatingForm + { + } +} \ No newline at end of file diff --git a/Greenshot/Forms/BaseForm.cs b/src/Greenshot/Forms/BaseForm.cs similarity index 76% rename from Greenshot/Forms/BaseForm.cs rename to src/Greenshot/Forms/BaseForm.cs index ffc0e86db..c7ea1341f 100644 --- a/Greenshot/Forms/BaseForm.cs +++ b/src/Greenshot/Forms/BaseForm.cs @@ -19,12 +19,14 @@ * along with this program. If not, see . */ -using GreenshotPlugin.Controls; +using Greenshot.Base.Controls; -namespace Greenshot.Forms { - /// - /// This class is only here to help in the Designer mode, so it's clear where the language files are - /// - public class BaseForm : GreenshotForm { - } -} +namespace Greenshot.Forms +{ + /// + /// This class is only here to help in the Designer mode, so it's clear where the language files are + /// + public class BaseForm : GreenshotForm + { + } +} \ No newline at end of file diff --git a/Greenshot/Forms/BugReportForm.Designer.cs b/src/Greenshot/Forms/BugReportForm.Designer.cs similarity index 92% rename from Greenshot/Forms/BugReportForm.Designer.cs rename to src/Greenshot/Forms/BugReportForm.Designer.cs index da6da4963..41dcc6447 100644 --- a/Greenshot/Forms/BugReportForm.Designer.cs +++ b/src/Greenshot/Forms/BugReportForm.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Forms { partial class BugReportForm { /// @@ -46,9 +49,9 @@ namespace Greenshot.Forms { /// private void InitializeComponent() { - this.labelBugReportInfo = new GreenshotPlugin.Controls.GreenshotLabel(); + this.labelBugReportInfo = new GreenshotLabel(); this.textBoxDescription = new System.Windows.Forms.TextBox(); - this.btnClose = new GreenshotPlugin.Controls.GreenshotButton(); + this.btnClose = new GreenshotButton(); this.linkLblBugs = new System.Windows.Forms.LinkLabel(); this.SuspendLayout(); // @@ -112,8 +115,8 @@ namespace Greenshot.Forms { } private System.Windows.Forms.LinkLabel linkLblBugs; - private GreenshotPlugin.Controls.GreenshotButton btnClose; + private GreenshotButton btnClose; private System.Windows.Forms.TextBox textBoxDescription; - private GreenshotPlugin.Controls.GreenshotLabel labelBugReportInfo; + private GreenshotLabel labelBugReportInfo; } } diff --git a/src/Greenshot/Forms/BugReportForm.cs b/src/Greenshot/Forms/BugReportForm.cs new file mode 100644 index 000000000..255af0525 --- /dev/null +++ b/src/Greenshot/Forms/BugReportForm.cs @@ -0,0 +1,64 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Diagnostics; +using System.Windows.Forms; +using Greenshot.Base.Core; +using Greenshot.Configuration; + +namespace Greenshot.Forms +{ + public partial class BugReportForm : BaseForm + { + private BugReportForm() + { + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + ToFront = true; + } + + public BugReportForm(string bugText) : this() + { + textBoxDescription.Text = bugText; + } + + private void LinkLblBugsLinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + openLink((LinkLabel) sender); + } + + private void openLink(LinkLabel link) + { + try + { + link.LinkVisited = true; + Process.Start(link.Text); + } + catch (Exception) + { + MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, link.Text), Language.GetString(LangKey.error)); + } + } + } +} \ No newline at end of file diff --git a/Greenshot/Forms/CaptureForm.Designer.cs b/src/Greenshot/Forms/CaptureForm.Designer.cs similarity index 100% rename from Greenshot/Forms/CaptureForm.Designer.cs rename to src/Greenshot/Forms/CaptureForm.Designer.cs diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs new file mode 100644 index 000000000..f85c57d4a --- /dev/null +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -0,0 +1,1187 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Drawing; +using Greenshot.Helpers; +using log4net; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Globalization; +using System.Security.Permissions; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Ocr; +using Greenshot.Base.UnmanagedHelpers; + +namespace Greenshot.Forms +{ + /// + /// The capture form is used to select a part of the capture + /// + public sealed partial class CaptureForm : AnimatingForm + { + private enum FixMode + { + None, + Initiated, + Horizontal, + Vertical + }; + + private static readonly ILog Log = LogManager.GetLogger(typeof(CaptureForm)); + private static readonly CoreConfiguration Conf = IniConfig.GetIniSection(); + private static readonly Brush GreenOverlayBrush = new SolidBrush(Color.FromArgb(50, Color.MediumSeaGreen)); + private static readonly Pen OverlayPen = new Pen(Color.FromArgb(50, Color.Black)); + private static CaptureForm _currentForm; + private static readonly Brush BackgroundBrush; + + /// + /// Initialize the background brush + /// + static CaptureForm() + { + Image backgroundForTransparency = GreenshotResources.GetImage("Checkerboard.Image"); + BackgroundBrush = new TextureBrush(backgroundForTransparency, WrapMode.Tile); + } + + private int _mX; + private int _mY; + private Point _mouseMovePos = Point.Empty; + private Point _cursorPos; + private CaptureMode _captureMode; + private readonly List _windows; + private WindowDetails _selectedCaptureWindow; + private bool _mouseDown; + private Rectangle _captureRect = Rectangle.Empty; + private readonly ICapture _capture; + private Point _previousMousePos = Point.Empty; + private FixMode _fixMode = FixMode.None; + private RectangleAnimator _windowAnimator; + private RectangleAnimator _zoomAnimator; + private readonly bool _isZoomerTransparent = Conf.ZoomerOpacity < 1; + private bool _isCtrlPressed; + private bool _showDebugInfo; + + /// + /// Property to access the selected capture rectangle + /// + public Rectangle CaptureRectangle => _captureRect; + + /// + /// Property to access the used capture mode + /// + public CaptureMode UsedCaptureMode => _captureMode; + + /// + /// Get the selected window + /// + public WindowDetails SelectedCaptureWindow => _selectedCaptureWindow; + + /// + /// This should prevent children to draw backgrounds + /// + protected override CreateParams CreateParams + { + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + get + { + CreateParams createParams = base.CreateParams; + createParams.ExStyle |= 0x02000000; + return createParams; + } + } + + private void ClosedHandler(object sender, EventArgs e) + { + _currentForm = null; + // Change the final mode + if (_captureMode == CaptureMode.Text) + { + _capture.CaptureDetails.CaptureMode = CaptureMode.Text; + } + + Log.Debug("Remove CaptureForm from currentForm"); + } + + private void ClosingHandler(object sender, EventArgs e) + { + Log.Debug("Closing capture form"); + WindowDetails.UnregisterIgnoreHandle(Handle); + } + + /// + /// This creates the capture form + /// + /// + /// + public CaptureForm(ICapture capture, List windows) + { + if (_currentForm != null) + { + Log.Warn("Found currentForm, Closing already opened CaptureForm"); + _currentForm.Close(); + _currentForm = null; + Application.DoEvents(); + } + + _currentForm = this; + + // Enable the AnimatingForm + EnableAnimation = true; + + // clean up + FormClosed += ClosedHandler; + + _capture = capture; + _windows = windows; + _captureMode = capture.CaptureDetails.CaptureMode; + + // + // The InitializeComponent() call is required for Windows Forms designer support. + // + InitializeComponent(); + // Only double-buffer when we are not in a TerminalServerSession + DoubleBuffered = !IsTerminalServerSession; + Text = @"Greenshot capture form"; + + // Make sure we never capture the capture-form + WindowDetails.RegisterIgnoreHandle(Handle); + // Un-register at close + FormClosing += ClosingHandler; + + // set cursor location + _cursorPos = WindowCapture.GetCursorLocationRelativeToScreenBounds(); + + // Initialize the animations, the window capture zooms out from the cursor to the window under the cursor + if (_captureMode == CaptureMode.Window) + { + _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); + } + + // Set the zoomer animation + InitializeZoomer(Conf.ZoomerEnabled); + + SuspendLayout(); + Bounds = capture.ScreenBounds; + ResumeLayout(); + + // Fix missing focus + ToFront = true; + TopMost = true; + } + + /// + /// Create an animation for the zoomer, depending on if it's active or not. + /// + private void InitializeZoomer(bool isOn) + { + if (isOn) + { + // Initialize the zoom with a invalid position + _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, + EasingMode.EaseOut); + VerifyZoomAnimation(_cursorPos, false); + } + else + { + _zoomAnimator?.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), FramesForMillis(1000)); + } + } + + private void CaptureFormKeyUp(object sender, KeyEventArgs e) + { + switch (e.KeyCode) + { + case Keys.ShiftKey: + _fixMode = FixMode.None; + break; + case Keys.ControlKey: + _isCtrlPressed = false; + break; + } + } + + /// + /// Handle the key down event + /// + /// + /// + private void CaptureFormKeyDown(object sender, KeyEventArgs e) + { + int step = _isCtrlPressed ? 10 : 1; + + switch (e.KeyCode) + { + case Keys.Up: + Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y - step); + break; + case Keys.Down: + Cursor.Position = new Point(Cursor.Position.X, Cursor.Position.Y + step); + break; + case Keys.Left: + Cursor.Position = new Point(Cursor.Position.X - step, Cursor.Position.Y); + break; + case Keys.Right: + Cursor.Position = new Point(Cursor.Position.X + step, Cursor.Position.Y); + break; + case Keys.ShiftKey: + // Fix mode + if (_fixMode == FixMode.None) + { + _fixMode = FixMode.Initiated; + } + + break; + case Keys.ControlKey: + _isCtrlPressed = true; + break; + case Keys.Escape: + // Cancel + DialogResult = DialogResult.Cancel; + break; + case Keys.M: + // Toggle mouse cursor + _capture.CursorVisible = !_capture.CursorVisible; + Invalidate(); + break; + //// TODO: Enable when the screen capture code works reliable + //case Keys.V: + // // Video + // if (capture.CaptureDetails.CaptureMode != CaptureMode.Video) { + // capture.CaptureDetails.CaptureMode = CaptureMode.Video; + // } else { + // capture.CaptureDetails.CaptureMode = captureMode; + // } + // Invalidate(); + // break; + case Keys.Z: + if (_captureMode == CaptureMode.Region) + { + // Toggle zoom + Conf.ZoomerEnabled = !Conf.ZoomerEnabled; + InitializeZoomer(Conf.ZoomerEnabled); + Invalidate(); + } + + break; + case Keys.D: + if (_captureMode == CaptureMode.Window) + { + // Toggle debug + _showDebugInfo = !_showDebugInfo; + Invalidate(); + } + + break; + case Keys.Space: + // Toggle capture mode + switch (_captureMode) + { + case CaptureMode.Region: + // Set the window capture mode + _captureMode = CaptureMode.Window; + // "Fade out" Zoom + InitializeZoomer(false); + // "Fade in" window + _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, + EasingMode.EaseOut); + _captureRect = Rectangle.Empty; + Invalidate(); + break; + case CaptureMode.Text: + // Set the region capture mode + _captureMode = CaptureMode.Region; + Invalidate(); + break; + case CaptureMode.Window: + // Set the region capture mode + _captureMode = CaptureMode.Region; + // "Fade out" window + _windowAnimator.ChangeDestination(new Rectangle(_cursorPos, Size.Empty), FramesForMillis(700)); + // Fade in zoom + InitializeZoomer(Conf.ZoomerEnabled); + _captureRect = Rectangle.Empty; + Invalidate(); + break; + } + + _selectedCaptureWindow = null; + OnMouseMove(this, new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0)); + break; + case Keys.Return: + // Confirm + if (_captureMode == CaptureMode.Window) + { + DialogResult = DialogResult.OK; + } + else if (!_mouseDown) + { + HandleMouseDown(); + } + else if (_mouseDown) + { + HandleMouseUp(); + } + + break; + case Keys.F: + ToFront = !ToFront; + TopMost = !TopMost; + break; + case Keys.T: + _captureMode = CaptureMode.Text; + if (_capture.CaptureDetails.OcrInformation is null) + { + var ocrProvider = SimpleServiceProvider.Current.GetInstance(); + if (ocrProvider != null) + { + var uiTaskScheduler = SimpleServiceProvider.Current.GetInstance(); + + Task.Factory.StartNew(async () => + { + _capture.CaptureDetails.OcrInformation = await ocrProvider.DoOcrAsync(_capture.Image); + Invalidate(); + }, CancellationToken.None, TaskCreationOptions.None, uiTaskScheduler); + } + } + else + { + Invalidate(); + } + + break; + } + } + + /// + /// The mousedown handler of the capture form + /// + /// + /// + private void OnMouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + HandleMouseDown(); + } + } + + private void HandleMouseDown() + { + Point tmpCursorLocation = WindowCapture.GetCursorLocationRelativeToScreenBounds(); + _mX = tmpCursorLocation.X; + _mY = tmpCursorLocation.Y; + _mouseDown = true; + OnMouseMove(this, null); + Invalidate(); + } + + private void HandleMouseUp() + { + // If the mouse goes up we set down to false (nice logic!) + _mouseDown = false; + // Check if anything is selected + if (_captureMode == CaptureMode.Window && _selectedCaptureWindow != null) + { + // Go and process the capture + DialogResult = DialogResult.OK; + } + else if (_captureRect.Height > 0 && _captureRect.Width > 0) + { + // correct the GUI width to real width if Region mode + if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) + { + _captureRect.Width += 1; + _captureRect.Height += 1; + } + + // Go and process the capture + DialogResult = DialogResult.OK; + } + else if (_captureMode == CaptureMode.Text && IsWordUnderCursor(_mouseMovePos)) + { + // Handle a click on a single word + _captureRect = new Rectangle(_mouseMovePos, new Size(1, 1)); + // Go and process the capture + DialogResult = DialogResult.OK; + } + else + { + Invalidate(); + } + } + + /// + /// + /// + /// + /// + private bool IsWordUnderCursor(Point cursorLocation) + { + if (_captureMode != CaptureMode.Text || _capture.CaptureDetails.OcrInformation == null) return false; + + var ocrInfo = _capture.CaptureDetails.OcrInformation; + + foreach (var line in ocrInfo.Lines) + { + var lineBounds = line.CalculatedBounds; + if (lineBounds.IsEmpty) continue; + // Highlight the text which is selected + if (!lineBounds.Contains(cursorLocation)) continue; + foreach (var word in line.Words) + { + if (word.Bounds.Contains(cursorLocation)) + { + return true; + } + } + } + + return false; + } + + /// + /// The mouse up handler of the capture form + /// + /// + /// + private void OnMouseUp(object sender, MouseEventArgs e) + { + if (_mouseDown) + { + HandleMouseUp(); + } + } + + /// + /// This method is used to "fix" the mouse coordinates when keeping shift/ctrl pressed + /// + /// + /// + private Point FixMouseCoordinates(Point currentMouse) + { + if (_fixMode == FixMode.Initiated) + { + if (_previousMousePos.X != currentMouse.X) + { + _fixMode = FixMode.Vertical; + } + else if (_previousMousePos.Y != currentMouse.Y) + { + _fixMode = FixMode.Horizontal; + } + } + else if (_fixMode == FixMode.Vertical) + { + currentMouse = new Point(currentMouse.X, _previousMousePos.Y); + } + else if (_fixMode == FixMode.Horizontal) + { + currentMouse = new Point(_previousMousePos.X, currentMouse.Y); + } + + _previousMousePos = currentMouse; + return currentMouse; + } + + /// + /// The mouse move handler of the capture form + /// + /// object + /// MouseEventArgs + private void OnMouseMove(object sender, MouseEventArgs e) + { + // Make sure the mouse coordinates are fixed, when pressing shift + var mouseMovePos = FixMouseCoordinates(User32.GetCursorLocation()); + _mouseMovePos = WindowCapture.GetLocationRelativeToScreenBounds(mouseMovePos); + } + + /// + /// Helper method to simplify check + /// + /// + /// + private bool IsAnimating(IAnimator animator) + { + if (animator == null) + { + return false; + } + + return animator.HasNext; + } + + /// + /// update the frame, this only invalidates + /// + protected override void Animate() + { + Point lastPos = _cursorPos; + _cursorPos = _mouseMovePos; + + if (_selectedCaptureWindow != null && lastPos.Equals(_cursorPos) && !IsAnimating(_zoomAnimator) && !IsAnimating(_windowAnimator)) + { + return; + } + + WindowDetails lastWindow = _selectedCaptureWindow; + bool horizontalMove = false; + bool verticalMove = false; + + if (lastPos.X != _cursorPos.X) + { + horizontalMove = true; + } + + if (lastPos.Y != _cursorPos.Y) + { + verticalMove = true; + } + + if ((_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) && _mouseDown) + { + _captureRect = GuiRectangle.GetGuiRectangle(_cursorPos.X, _cursorPos.Y, _mX - _cursorPos.X, _mY - _cursorPos.Y); + } + + // Iterate over the found windows and check if the current location is inside a window + Point cursorPosition = Cursor.Position; + _selectedCaptureWindow = null; + lock (_windows) + { + foreach (var window in _windows) + { + if (!window.Contains(cursorPosition)) + { + continue; + } + + // Only go over the children if we are in window mode + _selectedCaptureWindow = CaptureMode.Window == _captureMode ? window.FindChildUnderPoint(cursorPosition) : window; + break; + } + } + + if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) + { + _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; + _capture.CaptureDetails.AddMetaData("windowtitle", _selectedCaptureWindow.Text); + if (_captureMode == CaptureMode.Window) + { + // Here we want to capture the window which is under the mouse + _captureRect = _selectedCaptureWindow.WindowRectangle; + // As the ClientRectangle is not in Bitmap coordinates, we need to correct. + _captureRect.Offset(-_capture.ScreenBounds.Location.X, -_capture.ScreenBounds.Location.Y); + } + } + + Rectangle invalidateRectangle; + if (_mouseDown && (_captureMode != CaptureMode.Window)) + { + int x1 = Math.Min(_mX, lastPos.X); + int x2 = Math.Max(_mX, lastPos.X); + int y1 = Math.Min(_mY, lastPos.Y); + int y2 = Math.Max(_mY, lastPos.Y); + x1 = Math.Min(x1, _cursorPos.X); + x2 = Math.Max(x2, _cursorPos.X); + y1 = Math.Min(y1, _cursorPos.Y); + y2 = Math.Max(y2, _cursorPos.Y); + + // Safety correction + x2 += 2; + y2 += 2; + + // Here we correct for text-size + + // Calculate the size + int textForWidth = Math.Max(Math.Abs(_mX - _cursorPos.X), Math.Abs(_mX - lastPos.X)); + int textForHeight = Math.Max(Math.Abs(_mY - _cursorPos.Y), Math.Abs(_mY - lastPos.Y)); + + using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) + { + Size measureWidth = TextRenderer.MeasureText(textForWidth.ToString(CultureInfo.InvariantCulture), rulerFont); + x1 -= measureWidth.Width + 15; + + Size measureHeight = TextRenderer.MeasureText(textForHeight.ToString(CultureInfo.InvariantCulture), rulerFont); + y1 -= measureHeight.Height + 10; + } + + invalidateRectangle = new Rectangle(x1, y1, x2 - x1, y2 - y1); + Invalidate(invalidateRectangle); + } + else if (_captureMode != CaptureMode.Window) + { + if (!IsTerminalServerSession) + { + Rectangle allScreenBounds = WindowCapture.GetScreenBounds(); + allScreenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(allScreenBounds.Location); + if (verticalMove) + { + // Before + invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, lastPos.Y - 2, Width + 2, 45); + Invalidate(invalidateRectangle); + // After + invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, _cursorPos.Y - 2, Width + 2, 45); + Invalidate(invalidateRectangle); + } + + if (horizontalMove) + { + // Before + invalidateRectangle = GuiRectangle.GetGuiRectangle(lastPos.X - 2, allScreenBounds.Top, 75, Height + 2); + Invalidate(invalidateRectangle); + // After + invalidateRectangle = GuiRectangle.GetGuiRectangle(_cursorPos.X - 2, allScreenBounds.Top, 75, Height + 2); + Invalidate(invalidateRectangle); + } + } + } + else + { + if (_selectedCaptureWindow != null && !_selectedCaptureWindow.Equals(lastWindow)) + { + // Window changes, make new animation from current to target + _windowAnimator.ChangeDestination(_captureRect, FramesForMillis(700)); + } + } + + // always animate the Window area through to the last frame, so we see the fade-in/out untill the end + // Using a safety "offset" to make sure the text is invalidated too + const int safetySize = 30; + // Check if the animation needs to be drawn + if (IsAnimating(_windowAnimator)) + { + invalidateRectangle = _windowAnimator.Current; + invalidateRectangle.Inflate(safetySize, safetySize); + Invalidate(invalidateRectangle); + invalidateRectangle = _windowAnimator.Next(); + invalidateRectangle.Inflate(safetySize, safetySize); + Invalidate(invalidateRectangle); + // Check if this was the last of the windows animations in the normal region capture. + if (_captureMode != CaptureMode.Window && !IsAnimating(_windowAnimator)) + { + Invalidate(); + } + } + + if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) + { + // Make sure we invalidate the old zoom area + invalidateRectangle = _zoomAnimator.Current; + invalidateRectangle.Offset(lastPos); + Invalidate(invalidateRectangle); + // Only verify if we are really showing the zoom, not the outgoing animation + if (Conf.ZoomerEnabled && _captureMode != CaptureMode.Window) + { + VerifyZoomAnimation(_cursorPos, false); + } + + // The following logic is not needed, next always returns the current if there are no frames left + // but it makes more sense if we want to change something in the logic + invalidateRectangle = IsAnimating(_zoomAnimator) ? _zoomAnimator.Next() : _zoomAnimator.Current; + invalidateRectangle.Offset(_cursorPos); + Invalidate(invalidateRectangle); + } + + // OCR + if (_captureMode == CaptureMode.Text && _capture.CaptureDetails.OcrInformation != null) + { + var ocrInfo = _capture.CaptureDetails.OcrInformation; + + invalidateRectangle = Rectangle.Empty; + foreach (var line in ocrInfo.Lines) + { + var lineBounds = line.CalculatedBounds; + if (!lineBounds.IsEmpty) + { + if (_mouseDown) + { + // Highlight the text which is selected + if (lineBounds.IntersectsWith(_captureRect)) + { + foreach (var word in line.Words) + { + if (word.Bounds.IntersectsWith(_captureRect)) + { + if (invalidateRectangle.IsEmpty) + { + invalidateRectangle = word.Bounds; + } + else + { + invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); + } + } + } + } + } + else if (lineBounds.Contains(_mouseMovePos)) + { + foreach (var word in line.Words) + { + if (!word.Bounds.Contains(_mouseMovePos)) continue; + if (invalidateRectangle.IsEmpty) + { + invalidateRectangle = word.Bounds; + } + else + { + invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); + } + + break; + } + } + } + } + + if (!invalidateRectangle.IsEmpty) + { + Invalidate(invalidateRectangle); + } + } + + // Force update "now" + Update(); + } + + /// + /// This makes sure there is no background painted, as we have complete "paint" control it doesn't make sense to do otherwise. + /// + /// + protected override void OnPaintBackground(PaintEventArgs pevent) + { + } + + /// + /// Checks if the Zoom area can move there where it wants to go, change direction if not. + /// + /// preferred destination location for the zoom area + /// false to try to find a location which is neither out of screen bounds nor intersects with the selected rectangle + private void VerifyZoomAnimation(Point pos, bool allowZoomOverCaptureRect) + { + Rectangle screenBounds = Screen.GetBounds(MousePosition); + // convert to be relative to top left corner of all screen bounds + screenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(screenBounds.Location); + int relativeZoomSize = Math.Min(screenBounds.Width, screenBounds.Height) / 5; + // Make sure the final size is a plural of 4, this makes it look better + relativeZoomSize -= relativeZoomSize % 4; + Size zoomSize = new Size(relativeZoomSize, relativeZoomSize); + Point zoomOffset = new Point(20, 20); + + Rectangle targetRectangle = _zoomAnimator.Final; + targetRectangle.Offset(pos); + if (!screenBounds.Contains(targetRectangle) || (!allowZoomOverCaptureRect && _captureRect.IntersectsWith(targetRectangle))) + { + Point destinationLocation = Point.Empty; + Rectangle tl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); + Rectangle tr = new Rectangle(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); + Rectangle bl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); + Rectangle br = new Rectangle(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); + if (screenBounds.Contains(br) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(br))) + { + destinationLocation = new Point(zoomOffset.X, zoomOffset.Y); + } + else if (screenBounds.Contains(bl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(bl))) + { + destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, zoomOffset.Y); + } + else if (screenBounds.Contains(tr) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tr))) + { + destinationLocation = new Point(zoomOffset.X, -zoomOffset.Y - zoomSize.Width); + } + else if (screenBounds.Contains(tl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tl))) + { + destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width); + } + + if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect) + { + VerifyZoomAnimation(pos, true); + } + else + { + _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize)); + } + } + } + + /// + /// Draw the zoomed area + /// + /// + /// + /// + private void DrawZoom(Graphics graphics, Rectangle sourceRectangle, Rectangle destinationRectangle) + { + if (_capture.Image == null) + { + return; + } + + ImageAttributes attributes; + + if (_isZoomerTransparent) + { + //create a color matrix object to change the opacy + ColorMatrix opacyMatrix = new ColorMatrix + { + Matrix33 = Conf.ZoomerOpacity + }; + attributes = new ImageAttributes(); + attributes.SetColorMatrix(opacyMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); + } + else + { + attributes = null; + } + + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.CompositingQuality = CompositingQuality.HighSpeed; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + using (GraphicsPath path = new GraphicsPath()) + { + path.AddEllipse(destinationRectangle); + graphics.SetClip(path); + if (!_isZoomerTransparent) + { + graphics.FillRectangle(BackgroundBrush, destinationRectangle); + graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle, GraphicsUnit.Pixel); + } + else + { + graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, + GraphicsUnit.Pixel, attributes); + } + } + + int alpha = (int) (255 * Conf.ZoomerOpacity); + Color opacyWhite = Color.FromArgb(alpha, 255, 255, 255); + Color opacyBlack = Color.FromArgb(alpha, 0, 0, 0); + + // Draw the circle around the zoomer + using (Pen pen = new Pen(opacyWhite, 2)) + { + graphics.DrawEllipse(pen, destinationRectangle); + } + + // Make sure we don't have a pixeloffsetmode/smoothingmode when drawing the crosshair + graphics.SmoothingMode = SmoothingMode.None; + graphics.PixelOffsetMode = PixelOffsetMode.None; + + // Calculate some values + int pixelThickness = destinationRectangle.Width / sourceRectangle.Width; + int halfWidth = destinationRectangle.Width / 2; + int halfWidthEnd = destinationRectangle.Width / 2 - pixelThickness / 2; + int halfHeight = destinationRectangle.Height / 2; + int halfHeightEnd = destinationRectangle.Height / 2 - pixelThickness / 2; + + int drawAtHeight = destinationRectangle.Y + halfHeight; + int drawAtWidth = destinationRectangle.X + halfWidth; + int padding = pixelThickness; + + // Pen to draw + using (Pen pen = new Pen(opacyBlack, pixelThickness)) + { + // Draw the cross-hair-lines + // Vertical top to middle + graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + padding, drawAtWidth, destinationRectangle.Y + halfHeightEnd - padding); + // Vertical middle + 1 to bottom + graphics.DrawLine(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, drawAtWidth, + destinationRectangle.Y + destinationRectangle.Width - padding); + // Horizontal left to middle + graphics.DrawLine(pen, destinationRectangle.X + padding, drawAtHeight, destinationRectangle.X + halfWidthEnd - padding, drawAtHeight); + // Horizontal middle + 1 to right + graphics.DrawLine(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, destinationRectangle.X + destinationRectangle.Width - padding, + drawAtHeight); + + // Fix offset for drawing the white rectangle around the cross-hair-lines + drawAtHeight -= pixelThickness / 2; + drawAtWidth -= pixelThickness / 2; + // Fix off by one error with the DrawRectangle + pixelThickness -= 1; + // Change the color and the pen width + pen.Color = opacyWhite; + pen.Width = 1; + // Vertical top to middle + graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + padding, pixelThickness, halfHeightEnd - 2 * padding - 1); + // Vertical middle + 1 to bottom + graphics.DrawRectangle(pen, drawAtWidth, destinationRectangle.Y + halfHeightEnd + 2 * padding, pixelThickness, halfHeightEnd - 2 * padding - 1); + // Horizontal left to middle + graphics.DrawRectangle(pen, destinationRectangle.X + padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); + // Horizontal middle + 1 to right + graphics.DrawRectangle(pen, destinationRectangle.X + halfWidthEnd + 2 * padding, drawAtHeight, halfWidthEnd - 2 * padding - 1, pixelThickness); + } + + attributes?.Dispose(); + } + + /// + /// Paint the actual visible parts + /// + /// + /// + private void OnPaint(object sender, PaintEventArgs e) + { + Graphics graphics = e.Graphics; + Rectangle clipRectangle = e.ClipRectangle; + //graphics.BitBlt((Bitmap)buffer, Point.Empty); + graphics.DrawImageUnscaled(_capture.Image, Point.Empty); + + var ocrInfo = _capture.CaptureDetails.OcrInformation; + if (ocrInfo != null && _captureMode == CaptureMode.Text) + { + using var pen = new Pen(Color.Red); + var highlightColor = Color.FromArgb(128, Color.Yellow); + using var highlightTextBrush = new SolidBrush(highlightColor); + foreach (var line in ocrInfo.Lines) + { + var lineBounds = line.CalculatedBounds; + if (!lineBounds.IsEmpty) + { + graphics.DrawRectangle(pen, line.CalculatedBounds); + if (_mouseDown) + { + // Highlight the text which is selected + if (lineBounds.IntersectsWith(_captureRect)) + { + foreach (var word in line.Words) + { + if (word.Bounds.IntersectsWith(_captureRect)) + { + graphics.FillRectangle(highlightTextBrush, word.Bounds); + } + } + } + } + else if (lineBounds.Contains(_mouseMovePos)) + { + foreach (var word in line.Words) + { + if (!word.Bounds.Contains(_mouseMovePos)) continue; + graphics.FillRectangle(highlightTextBrush, word.Bounds); + break; + } + } + } + } + } + + // Only draw Cursor if it's (partly) visible + if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new Rectangle(_capture.CursorLocation, _capture.Cursor.Size))) + { + graphics.DrawIcon(_capture.Cursor, _capture.CursorLocation.X, _capture.CursorLocation.Y); + } + + if (_mouseDown || _captureMode == CaptureMode.Window || IsAnimating(_windowAnimator)) + { + _captureRect.Intersect(new Rectangle(Point.Empty, _capture.ScreenBounds.Size)); // crop what is outside the screen + + var fixedRect = IsAnimating(_windowAnimator) ? _windowAnimator.Current : _captureRect; + + // TODO: enable when the screen capture code works reliable + //if (capture.CaptureDetails.CaptureMode == CaptureMode.Video) { + // graphics.FillRectangle(RedOverlayBrush, fixedRect); + //} else { + graphics.FillRectangle(GreenOverlayBrush, fixedRect); + //} + graphics.DrawRectangle(OverlayPen, fixedRect); + + // rulers + const int dist = 8; + + string captureWidth; + string captureHeight; + // The following fixes the very old incorrect size information bug + if (_captureMode == CaptureMode.Window) + { + captureWidth = _captureRect.Width.ToString(CultureInfo.InvariantCulture); + captureHeight = _captureRect.Height.ToString(CultureInfo.InvariantCulture); + } + else + { + captureWidth = (_captureRect.Width + 1).ToString(CultureInfo.InvariantCulture); + captureHeight = (_captureRect.Height + 1).ToString(CultureInfo.InvariantCulture); + } + + using (Font rulerFont = new Font(FontFamily.GenericSansSerif, 8)) + { + Size measureWidth = TextRenderer.MeasureText(captureWidth, rulerFont); + Size measureHeight = TextRenderer.MeasureText(captureHeight, rulerFont); + int hSpace = measureWidth.Width + 3; + int vSpace = measureHeight.Height + 3; + Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227)); + Pen rulerPen = new Pen(Color.SeaGreen); + + // horizontal ruler + if (fixedRect.Width > hSpace + 3) + { + using GraphicsPath p = CreateRoundedRectangle( + fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, + fixedRect.Y - dist - 7, + measureWidth.Width - 3, + measureWidth.Height, + 3); + graphics.FillPath(bgBrush, p); + graphics.DrawPath(rulerPen, p); + graphics.DrawString(captureWidth, rulerFont, rulerPen.Brush, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2) + 3, fixedRect.Y - dist - 7); + graphics.DrawLine(rulerPen, fixedRect.X, fixedRect.Y - dist, fixedRect.X + (fixedRect.Width / 2 - hSpace / 2), fixedRect.Y - dist); + graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width / 2 + hSpace / 2, fixedRect.Y - dist, fixedRect.X + fixedRect.Width, fixedRect.Y - dist); + graphics.DrawLine(rulerPen, fixedRect.X, fixedRect.Y - dist - 3, fixedRect.X, fixedRect.Y - dist + 3); + graphics.DrawLine(rulerPen, fixedRect.X + fixedRect.Width, fixedRect.Y - dist - 3, fixedRect.X + fixedRect.Width, fixedRect.Y - dist + 3); + } + + // vertical ruler + if (fixedRect.Height > vSpace + 3) + { + using GraphicsPath p = CreateRoundedRectangle( + fixedRect.X - measureHeight.Width + 1, + fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2, + measureHeight.Width - 3, + measureHeight.Height - 1, + 3); + graphics.FillPath(bgBrush, p); + graphics.DrawPath(rulerPen, p); + graphics.DrawString(captureHeight, rulerFont, rulerPen.Brush, fixedRect.X - measureHeight.Width + 1, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2) + 2); + graphics.DrawLine(rulerPen, fixedRect.X - dist, fixedRect.Y, fixedRect.X - dist, fixedRect.Y + (fixedRect.Height / 2 - vSpace / 2)); + graphics.DrawLine(rulerPen, fixedRect.X - dist, fixedRect.Y + fixedRect.Height / 2 + vSpace / 2, fixedRect.X - dist, fixedRect.Y + fixedRect.Height); + graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y, fixedRect.X - dist + 3, fixedRect.Y); + graphics.DrawLine(rulerPen, fixedRect.X - dist - 3, fixedRect.Y + fixedRect.Height, fixedRect.X - dist + 3, fixedRect.Y + fixedRect.Height); + } + + rulerPen.Dispose(); + bgBrush.Dispose(); + } + + // Display size of selected rectangle + // Prepare the font and text. + using Font sizeFont = new Font(FontFamily.GenericSansSerif, 12); + // When capturing a Region we need to add 1 to the height/width for correction + string sizeText; + if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) + { + // correct the GUI width to real width for the shown size + sizeText = _captureRect.Width + 1 + " x " + (_captureRect.Height + 1); + } + else + { + sizeText = _captureRect.Width + " x " + _captureRect.Height; + } + + // Calculate the scaled font size. + SizeF extent = graphics.MeasureString(sizeText, sizeFont); + float hRatio = _captureRect.Height / (extent.Height * 2); + float wRatio = _captureRect.Width / (extent.Width * 2); + float ratio = hRatio < wRatio ? hRatio : wRatio; + float newSize = sizeFont.Size * ratio; + + if (newSize >= 4) + { + // Only show if 4pt or larger. + if (newSize > 20) + { + newSize = 20; + } + + // Draw the size. + using Font newSizeFont = new Font(FontFamily.GenericSansSerif, newSize, FontStyle.Bold); + PointF sizeLocation = new PointF(fixedRect.X + _captureRect.Width / 2 - extent.Width / 2, fixedRect.Y + _captureRect.Height / 2 - newSizeFont.GetHeight() / 2); + graphics.DrawString(sizeText, newSizeFont, Brushes.LightSeaGreen, sizeLocation); + + if (_showDebugInfo && _selectedCaptureWindow != null) + { + string title = + $"#{_selectedCaptureWindow.Handle.ToInt64():X} - {(_selectedCaptureWindow.Text.Length > 0 ? _selectedCaptureWindow.Text : _selectedCaptureWindow.Process.ProcessName)}"; + PointF debugLocation = new PointF(fixedRect.X, fixedRect.Y); + graphics.DrawString(title, sizeFont, Brushes.DarkOrange, debugLocation); + } + } + } + else + { + if (!IsTerminalServerSession) + { + using (Pen pen = new Pen(Color.LightSeaGreen)) + { + pen.DashStyle = DashStyle.Dot; + Rectangle screenBounds = _capture.ScreenBounds; + graphics.DrawLine(pen, _cursorPos.X, screenBounds.Y, _cursorPos.X, screenBounds.Height); + graphics.DrawLine(pen, screenBounds.X, _cursorPos.Y, screenBounds.Width, _cursorPos.Y); + } + + string xy = _cursorPos.X + " x " + _cursorPos.Y; + using Font f = new Font(FontFamily.GenericSansSerif, 8); + Size xySize = TextRenderer.MeasureText(xy, f); + using GraphicsPath gp = CreateRoundedRectangle(_cursorPos.X + 5, _cursorPos.Y + 5, xySize.Width - 3, xySize.Height, 3); + using (Brush bgBrush = new SolidBrush(Color.FromArgb(200, 217, 240, 227))) + { + graphics.FillPath(bgBrush, gp); + } + + using (Pen pen = new Pen(Color.SeaGreen)) + { + graphics.DrawPath(pen, gp); + Point coordinatePosition = new Point(_cursorPos.X + 5, _cursorPos.Y + 5); + graphics.DrawString(xy, f, pen.Brush, coordinatePosition); + } + } + } + + // Zoom + if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) + { + const int zoomSourceWidth = 25; + const int zoomSourceHeight = 25; + + Rectangle sourceRectangle = new Rectangle(_cursorPos.X - zoomSourceWidth / 2, _cursorPos.Y - zoomSourceHeight / 2, zoomSourceWidth, zoomSourceHeight); + + Rectangle destinationRectangle = _zoomAnimator.Current; + destinationRectangle.Offset(_cursorPos); + DrawZoom(graphics, sourceRectangle, destinationRectangle); + } + } + + private static GraphicsPath CreateRoundedRectangle(int x, int y, int width, int height, int radius) + { + var gp = new GraphicsPath(); + gp.AddLine(x + radius, y, x + width - radius * 2, y); // Line + gp.AddArc(x + width - radius * 2, y, radius * 2, radius * 2, 270, 90); // Corner + gp.AddLine(x + width, y + radius, x + width, y + height - radius * 2); // Line + gp.AddArc(x + width - radius * 2, y + height - radius * 2, radius * 2, radius * 2, 0, 90); // Corner + gp.AddLine(x + width - radius * 2, y + height, x + radius, y + height); // Line + gp.AddArc(x, y + height - radius * 2, radius * 2, radius * 2, 90, 90); // Corner + gp.AddLine(x, y + height - radius * 2, x, y + radius); // Line + gp.AddArc(x, y, radius * 2, radius * 2, 180, 90); // Corner + gp.CloseFigure(); + + return gp; + } + } +} \ No newline at end of file diff --git a/Greenshot/Forms/ColorDialog.Designer.cs b/src/Greenshot/Forms/ColorDialog.Designer.cs similarity index 89% rename from Greenshot/Forms/ColorDialog.Designer.cs rename to src/Greenshot/Forms/ColorDialog.Designer.cs index d5060d8c0..468edf457 100644 --- a/Greenshot/Forms/ColorDialog.Designer.cs +++ b/src/Greenshot/Forms/ColorDialog.Designer.cs @@ -18,6 +18,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +using Greenshot.Base.Controls; + namespace Greenshot.Forms { public partial class ColorDialog { /// @@ -47,20 +50,20 @@ namespace Greenshot.Forms { private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ColorDialog)); - this.btnTransparent = new GreenshotPlugin.Controls.GreenshotButton(); + this.btnTransparent = new GreenshotButton(); this.colorPanel = new System.Windows.Forms.Panel(); - this.labelHtmlColor = new GreenshotPlugin.Controls.GreenshotLabel(); + this.labelHtmlColor = new GreenshotLabel(); this.textBoxHtmlColor = new System.Windows.Forms.TextBox(); - this.labelRed = new GreenshotPlugin.Controls.GreenshotLabel(); - this.labelGreen = new GreenshotPlugin.Controls.GreenshotLabel(); - this.labelBlue = new GreenshotPlugin.Controls.GreenshotLabel(); + this.labelRed = new GreenshotLabel(); + this.labelGreen = new GreenshotLabel(); + this.labelBlue = new GreenshotLabel(); this.textBoxRed = new System.Windows.Forms.TextBox(); this.textBoxGreen = new System.Windows.Forms.TextBox(); this.textBoxBlue = new System.Windows.Forms.TextBox(); - this.labelRecentColors = new GreenshotPlugin.Controls.GreenshotLabel(); + this.labelRecentColors = new GreenshotLabel(); this.textBoxAlpha = new System.Windows.Forms.TextBox(); - this.labelAlpha = new GreenshotPlugin.Controls.GreenshotLabel(); - this.btnApply = new GreenshotPlugin.Controls.GreenshotButton(); + this.labelAlpha = new GreenshotLabel(); + this.btnApply = new GreenshotButton(); this.pipette = new Greenshot.Controls.Pipette(); this.SuspendLayout(); // @@ -260,20 +263,20 @@ namespace Greenshot.Forms { this.PerformLayout(); } - private GreenshotPlugin.Controls.GreenshotLabel labelRed; - private GreenshotPlugin.Controls.GreenshotLabel labelGreen; - private GreenshotPlugin.Controls.GreenshotLabel labelBlue; + private GreenshotLabel labelRed; + private GreenshotLabel labelGreen; + private GreenshotLabel labelBlue; private System.Windows.Forms.TextBox textBoxHtmlColor; - private GreenshotPlugin.Controls.GreenshotLabel labelRecentColors; - private GreenshotPlugin.Controls.GreenshotLabel labelAlpha; - private GreenshotPlugin.Controls.GreenshotLabel labelHtmlColor; - private GreenshotPlugin.Controls.GreenshotButton btnApply; + private GreenshotLabel labelRecentColors; + private GreenshotLabel labelAlpha; + private GreenshotLabel labelHtmlColor; + private GreenshotButton btnApply; private System.Windows.Forms.TextBox textBoxAlpha; private System.Windows.Forms.TextBox textBoxRed; private System.Windows.Forms.TextBox textBoxGreen; private System.Windows.Forms.TextBox textBoxBlue; private System.Windows.Forms.Panel colorPanel; - private GreenshotPlugin.Controls.GreenshotButton btnTransparent; + private GreenshotButton btnTransparent; private Greenshot.Controls.Pipette pipette; diff --git a/src/Greenshot/Forms/ColorDialog.cs b/src/Greenshot/Forms/ColorDialog.cs new file mode 100644 index 000000000..6653ecf08 --- /dev/null +++ b/src/Greenshot/Forms/ColorDialog.cs @@ -0,0 +1,280 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: http://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.Threading; +using System.Windows.Forms; +using Greenshot.Base.IniFile; +using Greenshot.Configuration; +using Greenshot.Controls; + +namespace Greenshot.Forms +{ + /// + /// Description of ColorDialog. + /// + public partial class ColorDialog : BaseForm + { + private static readonly EditorConfiguration EditorConfig = IniConfig.GetIniSection(); + private static ColorDialog _instance; + + public ColorDialog() + { + SuspendLayout(); + InitializeComponent(); + SuspendLayout(); + CreateColorPalette(5, 5, 15, 15); + CreateLastUsedColorButtonRow(5, 190, 15, 15); + ResumeLayout(); + UpdateRecentColorsButtonRow(); + _instance = this; + } + + public static ColorDialog GetInstance() => _instance; + + private readonly List public class PickerDestination : AbstractDestination { - public const string DESIGNATION = "Picker"; - - public override string Designation => DESIGNATION; + public override string Designation => nameof(WellKnownDestinations.Picker); public override string Description => Language.GetString(LangKey.settings_destination_picker); diff --git a/src/Greenshot/Destinations/PrinterDestination.cs b/src/Greenshot/Destinations/PrinterDestination.cs index 6a85a1e83..7265c4576 100644 --- a/src/Greenshot/Destinations/PrinterDestination.cs +++ b/src/Greenshot/Destinations/PrinterDestination.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Printing; using System.Windows.Forms; +using Greenshot.Base; using Greenshot.Base.Core; using Greenshot.Base.Interfaces; using Greenshot.Configuration; @@ -36,7 +37,6 @@ namespace Greenshot.Destinations /// public class PrinterDestination : AbstractDestination { - public const string DESIGNATION = "Printer"; private readonly string _printerName; public PrinterDestination() @@ -48,7 +48,7 @@ namespace Greenshot.Destinations _printerName = printerName; } - public override string Designation => DESIGNATION; + public override string Designation => nameof(WellKnownDestinations.Printer); public override string Description { diff --git a/src/Greenshot/Forms/AboutForm.cs b/src/Greenshot/Forms/AboutForm.cs index b0e9781d0..a801cc63e 100644 --- a/src/Greenshot/Forms/AboutForm.cs +++ b/src/Greenshot/Forms/AboutForm.cs @@ -31,7 +31,6 @@ using System.Windows.Forms; using Greenshot.Base.Core; using Greenshot.Base.IniFile; using Greenshot.Configuration; -using Greenshot.Helpers; using log4net; namespace Greenshot.Forms @@ -44,10 +43,10 @@ namespace Greenshot.Forms private static readonly ILog Log = LogManager.GetLogger(typeof(AboutForm)); private Bitmap _bitmap; private readonly ColorAnimator _backgroundAnimation; - private readonly List _pixels = new List(); - private readonly List _colorFlow = new List(); - private readonly List _pixelColors = new List(); - private readonly Random _rand = new Random(); + private readonly List _pixels = new(); + private readonly List _colorFlow = new(); + private readonly List _pixelColors = new(); + private readonly Random _rand = new(); private readonly Color _backColor = Color.FromArgb(61, 61, 61); private readonly Color _pixelColor = Color.FromArgb(138, 255, 0); @@ -117,7 +116,7 @@ namespace Greenshot.Forms // 18 19 20 21 22 23 // The order in which we draw the dots & flow the colors. - private readonly List _flowOrder = new List{ 4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11 }; + private readonly List _flowOrder = new() { 4, 3, 2, 1, 0, 5, 6, 7, 8, 9, 10, 14, 15, 18, 19, 20, 21, 22, 23, 16, 17, 13, 12, 11 }; /// /// Cleanup all the allocated resources @@ -177,8 +176,7 @@ namespace Greenshot.Forms if (IsTerminalServerSession) { // No animation - pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic, - EasingMode.EaseIn); + pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic, EasingMode.EaseIn); } else { diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs index f06419949..6176c732e 100644 --- a/src/Greenshot/Forms/CaptureForm.cs +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -19,8 +19,6 @@ * along with this program. If not, see . */ -using Greenshot.Drawing; -using Greenshot.Helpers; using log4net; using System; using System.Collections.Generic; @@ -38,6 +36,7 @@ using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Ocr; using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Editor.Helpers; namespace Greenshot.Forms { @@ -204,8 +203,7 @@ namespace Greenshot.Forms if (isOn) { // Initialize the zoom with a invalid position - _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, - EasingMode.EaseOut); + _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut); VerifyZoomAnimation(_cursorPos, false); } else @@ -270,16 +268,6 @@ namespace Greenshot.Forms _capture.CursorVisible = !_capture.CursorVisible; Invalidate(); break; - //// TODO: Enable when the screen capture code works reliable - //case Keys.V: - // // Video - // if (capture.CaptureDetails.CaptureMode != CaptureMode.Video) { - // capture.CaptureDetails.CaptureMode = CaptureMode.Video; - // } else { - // capture.CaptureDetails.CaptureMode = captureMode; - // } - // Invalidate(); - // break; case Keys.Z: if (_captureMode == CaptureMode.Region) { @@ -309,8 +297,7 @@ namespace Greenshot.Forms // "Fade out" Zoom InitializeZoomer(false); // "Fade in" window - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, - EasingMode.EaseOut); + _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); _captureRect = Rectangle.Empty; Invalidate(); break; @@ -670,7 +657,7 @@ namespace Greenshot.Forms } } - // always animate the Window area through to the last frame, so we see the fade-in/out untill the end + // always animate the Window area through to the last frame, so we see the fade-in/out until the end // Using a safety "offset" to make sure the text is invalidated too const int safetySize = 30; // Check if the animation needs to be drawn @@ -717,34 +704,21 @@ namespace Greenshot.Forms foreach (var line in ocrInfo.Lines) { var lineBounds = line.CalculatedBounds; - if (!lineBounds.IsEmpty) + if (lineBounds.IsEmpty) { - if (_mouseDown) - { - // Highlight the text which is selected - if (lineBounds.IntersectsWith(_captureRect)) - { - foreach (var word in line.Words) - { - if (word.Bounds.IntersectsWith(_captureRect)) - { - if (invalidateRectangle.IsEmpty) - { - invalidateRectangle = word.Bounds; - } - else - { - invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); - } - } - } - } - } - else if (lineBounds.Contains(_mouseMovePos)) + continue; + } + if (_mouseDown) + { + // Highlight the text which is selected + if (lineBounds.IntersectsWith(_captureRect)) { foreach (var word in line.Words) { - if (!word.Bounds.Contains(_mouseMovePos)) continue; + if (!word.Bounds.IntersectsWith(_captureRect)) + { + continue; + } if (invalidateRectangle.IsEmpty) { invalidateRectangle = word.Bounds; @@ -753,11 +727,26 @@ namespace Greenshot.Forms { invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); } - - break; } } } + else if (lineBounds.Contains(_mouseMovePos)) + { + foreach (var word in line.Words) + { + if (!word.Bounds.Contains(_mouseMovePos)) continue; + if (invalidateRectangle.IsEmpty) + { + invalidateRectangle = word.Bounds; + } + else + { + invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); + } + + break; + } + } } if (!invalidateRectangle.IsEmpty) @@ -796,38 +785,39 @@ namespace Greenshot.Forms Rectangle targetRectangle = _zoomAnimator.Final; targetRectangle.Offset(pos); - if (!screenBounds.Contains(targetRectangle) || (!allowZoomOverCaptureRect && _captureRect.IntersectsWith(targetRectangle))) + if (screenBounds.Contains(targetRectangle) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(targetRectangle))) { - Point destinationLocation = Point.Empty; - Rectangle tl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); - Rectangle tr = new Rectangle(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); - Rectangle bl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); - Rectangle br = new Rectangle(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); - if (screenBounds.Contains(br) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(br))) - { - destinationLocation = new Point(zoomOffset.X, zoomOffset.Y); - } - else if (screenBounds.Contains(bl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(bl))) - { - destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, zoomOffset.Y); - } - else if (screenBounds.Contains(tr) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tr))) - { - destinationLocation = new Point(zoomOffset.X, -zoomOffset.Y - zoomSize.Width); - } - else if (screenBounds.Contains(tl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tl))) - { - destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width); - } + return; + } + Point destinationLocation = Point.Empty; + Rectangle tl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); + Rectangle tr = new Rectangle(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); + Rectangle bl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); + Rectangle br = new Rectangle(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); + if (screenBounds.Contains(br) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(br))) + { + destinationLocation = new Point(zoomOffset.X, zoomOffset.Y); + } + else if (screenBounds.Contains(bl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(bl))) + { + destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, zoomOffset.Y); + } + else if (screenBounds.Contains(tr) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tr))) + { + destinationLocation = new Point(zoomOffset.X, -zoomOffset.Y - zoomSize.Width); + } + else if (screenBounds.Contains(tl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tl))) + { + destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width); + } - if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect) - { - VerifyZoomAnimation(pos, true); - } - else - { - _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize)); - } + if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect) + { + VerifyZoomAnimation(pos, true); + } + else + { + _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize)); } } @@ -877,8 +867,7 @@ namespace Greenshot.Forms } else { - graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, - GraphicsUnit.Pixel, attributes); + graphics.DrawImage(_capture.Image, destinationRectangle, sourceRectangle.X, sourceRectangle.Y, sourceRectangle.Width, sourceRectangle.Height, GraphicsUnit.Pixel, attributes); } } @@ -964,33 +953,37 @@ namespace Greenshot.Forms foreach (var line in ocrInfo.Lines) { var lineBounds = line.CalculatedBounds; - if (!lineBounds.IsEmpty) + if (lineBounds.IsEmpty) { - graphics.DrawRectangle(pen, line.CalculatedBounds); - if (_mouseDown) - { - // Highlight the text which is selected - if (lineBounds.IntersectsWith(_captureRect)) - { - foreach (var word in line.Words) - { - if (word.Bounds.IntersectsWith(_captureRect)) - { - graphics.FillRectangle(highlightTextBrush, word.Bounds); - } - } - } - } - else if (lineBounds.Contains(_mouseMovePos)) + continue; + } + graphics.DrawRectangle(pen, line.CalculatedBounds); + if (_mouseDown) + { + // Highlight the text which is selected + if (lineBounds.IntersectsWith(_captureRect)) { foreach (var word in line.Words) { - if (!word.Bounds.Contains(_mouseMovePos)) continue; - graphics.FillRectangle(highlightTextBrush, word.Bounds); - break; + if (word.Bounds.IntersectsWith(_captureRect)) + { + graphics.FillRectangle(highlightTextBrush, word.Bounds); + } } } } + else if (lineBounds.Contains(_mouseMovePos)) + { + foreach (var word in line.Words) + { + if (!word.Bounds.Contains(_mouseMovePos)) + { + continue; + } + graphics.FillRectangle(highlightTextBrush, word.Bounds); + break; + } + } } } diff --git a/src/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs index c95a9e66a..b775149cb 100644 --- a/src/Greenshot/Forms/MainForm.cs +++ b/src/Greenshot/Forms/MainForm.cs @@ -32,26 +32,31 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.Integration; +using Greenshot.Base; using Greenshot.Base.Controls; using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; +using Greenshot.Base.Help; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.UnmanagedHelpers; using Greenshot.Configuration; using Greenshot.Destinations; -using Greenshot.Drawing; -using Greenshot.Help; +using Greenshot.Editor.Destinations; +using Greenshot.Editor.Drawing; +using Greenshot.Editor.Forms; using Greenshot.Helpers; +using Greenshot.Processors; using log4net; using Timer = System.Timers.Timer; namespace Greenshot.Forms { /// - /// Description of MainForm. + /// This is the MainForm, the shell of Greenshot /// - public partial class MainForm : BaseForm + public partial class MainForm : BaseForm, IGreenshotMainForm, ICaptureHelper { private static ILog LOG; private static ResourceMutex _applicationMutex; @@ -336,17 +341,18 @@ namespace Greenshot.Forms private static void FreeMutex() { // Remove the application mutex - if (_applicationMutex != null) + if (_applicationMutex == null) { - try - { - _applicationMutex.Dispose(); - _applicationMutex = null; - } - catch (Exception ex) - { - LOG.Error("Error releasing Mutex!", ex); - } + return; + } + try + { + _applicationMutex.Dispose(); + _applicationMutex = null; + } + catch (Exception ex) + { + LOG.Error("Error releasing Mutex!", ex); } } @@ -376,6 +382,8 @@ namespace Greenshot.Forms SimpleServiceProvider.Current.AddService(this); // Also as itself SimpleServiceProvider.Current.AddService(this); + SimpleServiceProvider.Current.AddService(this); + SimpleServiceProvider.Current.AddService(this); _instance = this; @@ -417,9 +425,9 @@ namespace Greenshot.Forms UpdateUi(); // This forces the registration of all destinations inside Greenshot itself. - DestinationHelper.RegisterInternalDestinations(); + RegisterInternalDestinations(); // This forces the registration of all processors inside Greenshot itself. - ProcessorHelper.RegisterInternalProcessors(); + RegisterInternalProcessors(); // Load all the plugins PluginHelper.Instance.LoadPlugins(); @@ -495,6 +503,62 @@ namespace Greenshot.Forms } } + /// + /// Create all the internal destinations + /// + private void RegisterInternalDestinations() + { + var internalDestinations = new List + { + new FileDestination(), + new FileWithDialogDestination(), + new ClipboardDestination(), + new PrinterDestination(), + new EmailDestination(), + new PickerDestination() + }; + + int len = 250; + var stringBuilder = new StringBuilder(len); + using var proc = Process.GetCurrentProcess(); + var err = Kernel32.GetPackageFullName(proc.Handle, ref len, stringBuilder); + if (err != 0) + { + internalDestinations.Add(new EditorDestination()); + } + foreach (var internalDestination in internalDestinations) + { + if (internalDestination.IsActive) + { + SimpleServiceProvider.Current.AddService(internalDestination); + } + else + { + internalDestination.Dispose(); + } + } + } + + private void RegisterInternalProcessors() + { + var internalProcessors = new List + { + new TitleFixProcessor() + }; + + foreach (var internalProcessor in internalProcessors) + { + if (internalProcessor.isActive) + { + SimpleServiceProvider.Current.AddService(internalProcessor); + } + else + { + internalProcessor.Dispose(); + } + } + } + /// /// DataReceivedEventHandler /// @@ -845,6 +909,11 @@ namespace Greenshot.Forms { Hide(); ShowInTaskbar = false; + + + using var loProcess = Process.GetCurrentProcess(); + loProcess.MaxWorkingSet = (IntPtr)750000; + loProcess.MinWorkingSet = (IntPtr)300000; } private void CaptureRegion() @@ -1505,7 +1574,7 @@ namespace Greenshot.Forms IDestination selectedDestination = (IDestination) item.Data; if (item.Checked) { - if (selectedDestination.Designation.Equals(PickerDestination.DESIGNATION)) + if (selectedDestination.Designation.Equals(nameof(WellKnownDestinations.Picker))) { // If the item is the destination picker, remove all others _conf.OutputDestinations.Clear(); @@ -1513,7 +1582,7 @@ namespace Greenshot.Forms else { // If the item is not the destination picker, remove the picker - _conf.OutputDestinations.Remove(PickerDestination.DESIGNATION); + _conf.OutputDestinations.Remove(nameof(WellKnownDestinations.Picker)); } // Checked an item, add if the destination is not yet selected @@ -1534,7 +1603,7 @@ namespace Greenshot.Forms // Check if something was selected, if not make the picker the default if (_conf.OutputDestinations == null || _conf.OutputDestinations.Count == 0) { - _conf.OutputDestinations.Add(PickerDestination.DESIGNATION); + _conf.OutputDestinations.Add(nameof(WellKnownDestinations.Picker)); } IniConfig.Save(); @@ -1810,5 +1879,27 @@ namespace Greenshot.Forms notifyIcon = null; } } + + /// + /// TODO: Delete when the ICaptureHelper can be solve someway else + /// + /// WindowDetails + /// WindowDetails + public WindowDetails SelectCaptureWindow(WindowDetails windowToCapture) + { + return CaptureHelper.SelectCaptureWindow(windowToCapture); + } + + /// + /// TODO: Delete when the ICaptureHelper can be solve someway else + /// + /// WindowDetails + /// ICapture + /// WindowCaptureMode + /// ICapture + public ICapture CaptureWindow(WindowDetails windowToCapture, ICapture capture, WindowCaptureMode coreConfigurationWindowCaptureMode) + { + return CaptureHelper.CaptureWindow(windowToCapture, capture, coreConfigurationWindowCaptureMode); + } } } \ No newline at end of file diff --git a/src/Greenshot/Forms/SettingsForm.Designer.cs b/src/Greenshot/Forms/SettingsForm.Designer.cs index c6adb66e7..92eb61eef 100644 --- a/src/Greenshot/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot/Forms/SettingsForm.Designer.cs @@ -20,6 +20,7 @@ */ using Greenshot.Base.Controls; +using Greenshot.Editor.Controls; namespace Greenshot.Forms { partial class SettingsForm { @@ -103,7 +104,7 @@ namespace Greenshot.Forms { this.groupbox_iecapture = new GreenshotGroupBox(); this.checkbox_ie_capture = new GreenshotCheckBox(); this.groupbox_windowscapture = new GreenshotGroupBox(); - this.colorButton_window_background = new Greenshot.Controls.ColorButton(); + this.colorButton_window_background = new ColorButton(); this.radiobuttonWindowCapture = new GreenshotRadioButton(); this.radiobuttonInteractiveCapture = new GreenshotRadioButton(); this.combobox_window_capture_mode = new System.Windows.Forms.ComboBox(); @@ -1327,7 +1328,7 @@ namespace Greenshot.Forms { private HotkeyControl lastregion_hotkeyControl; private GreenshotLabel label_lastregion_hotkey; private GreenshotGroupBox groupbox_hotkeys; - private Greenshot.Controls.ColorButton colorButton_window_background; + private ColorButton colorButton_window_background; private GreenshotRadioButton radiobuttonWindowCapture; private GreenshotCheckBox checkbox_ie_capture; private GreenshotGroupBox groupbox_capture; diff --git a/src/Greenshot/Forms/SettingsForm.cs b/src/Greenshot/Forms/SettingsForm.cs index 7305ffdad..e236360d1 100644 --- a/src/Greenshot/Forms/SettingsForm.cs +++ b/src/Greenshot/Forms/SettingsForm.cs @@ -28,8 +28,10 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; +using Greenshot.Base; using Greenshot.Base.Controls; using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; @@ -428,7 +430,7 @@ namespace Greenshot.Forms imageNr++; } - if (PickerDestination.DESIGNATION.Equals(currentDestination.Designation)) + if (nameof(WellKnownDestinations.Picker).Equals(currentDestination.Designation)) { checkbox_picker.Checked = coreConfiguration.OutputDestinations.Contains(currentDestination.Designation); checkbox_picker.Text = currentDestination.Description; @@ -571,7 +573,7 @@ namespace Greenshot.Forms List destinations = new List(); if (checkbox_picker.Checked) { - destinations.Add(PickerDestination.DESIGNATION); + destinations.Add(nameof(WellKnownDestinations.Picker)); } foreach (int index in listview_destinations.CheckedIndices) @@ -742,7 +744,7 @@ namespace Greenshot.Forms foreach (int index in listview_destinations.CheckedIndices) { ListViewItem item = listview_destinations.Items[index]; - if (item.Tag is IDestination destinationFromTag && destinationFromTag.Designation.Equals(ClipboardDestination.DESIGNATION)) + if (item.Tag is IDestination destinationFromTag && destinationFromTag.Designation.Equals(nameof(WellKnownDestinations.Clipboard))) { clipboardDestinationChecked = true; break; diff --git a/src/Greenshot/Greenshot.csproj b/src/Greenshot/Greenshot.csproj index 39fd2fb5c..da2c79714 100644 --- a/src/Greenshot/Greenshot.csproj +++ b/src/Greenshot/Greenshot.csproj @@ -21,12 +21,6 @@ - - ColorDialog.cs - - - ImageEditorForm.cs - MainForm.cs @@ -38,6 +32,7 @@ + diff --git a/src/Greenshot/GreenshotMain.cs b/src/Greenshot/GreenshotMain.cs index 3269d9fec..2d42d4b11 100644 --- a/src/Greenshot/GreenshotMain.cs +++ b/src/Greenshot/GreenshotMain.cs @@ -64,6 +64,7 @@ namespace Greenshot CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; + MainForm.Start(args); } } diff --git a/src/Greenshot/Helpers/CaptureHelper.cs b/src/Greenshot/Helpers/CaptureHelper.cs index 1e2fd23ee..c55cc2946 100644 --- a/src/Greenshot/Helpers/CaptureHelper.cs +++ b/src/Greenshot/Helpers/CaptureHelper.cs @@ -19,24 +19,25 @@ * along with this program. If not, see . */ -using Greenshot.Configuration; -using Greenshot.Destinations; -using Greenshot.Drawing; -using Greenshot.Forms; using log4net; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; -using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Windows.Forms; +using Greenshot.Base; using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Configuration; +using Greenshot.Editor.Destinations; +using Greenshot.Editor.Drawing; +using Greenshot.Forms; namespace Greenshot.Helpers { @@ -48,10 +49,8 @@ namespace Greenshot.Helpers private static readonly ILog Log = LogManager.GetLogger(typeof(CaptureHelper)); private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - - // TODO: when we get the screen capture code working correctly, this needs to be enabled - //private static ScreenCaptureHelper screenCapture = null; - private List _windows = new List(); + + private List _windows = new(); private WindowDetails _selectedCaptureWindow; private Rectangle _captureRect = Rectangle.Empty; private readonly bool _captureMouseCursor; @@ -411,11 +410,11 @@ namespace Greenshot.Helpers _capture.CaptureDetails.Title = "Clipboard"; _capture.CaptureDetails.AddMetaData("source", "Clipboard"); // Force Editor, keep picker - if (_capture.CaptureDetails.HasDestination(PickerDestination.DESIGNATION)) + if (_capture.CaptureDetails.HasDestination(nameof(WellKnownDestinations.Picker))) { _capture.CaptureDetails.ClearDestinations(); _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); - _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(PickerDestination.DESIGNATION)); + _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(nameof(WellKnownDestinations.Picker))); } else { @@ -480,11 +479,11 @@ namespace Greenshot.Helpers } // Force Editor, keep picker, this is currently the only usefull destination - if (_capture.CaptureDetails.HasDestination(PickerDestination.DESIGNATION)) + if (_capture.CaptureDetails.HasDestination(nameof(WellKnownDestinations.Picker))) { _capture.CaptureDetails.ClearDestinations(); _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); - _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(PickerDestination.DESIGNATION)); + _capture.CaptureDetails.AddDestination(DestinationHelper.GetDestination(nameof(WellKnownDestinations.Picker))); } else { @@ -567,7 +566,7 @@ namespace Greenshot.Helpers { _windows = new List(); - // If the App Launcher is visisble, no other windows are active + // If the App Launcher is visible, no other windows are active WindowDetails appLauncherWindow = WindowDetails.GetAppLauncher(); if (appLauncherWindow != null && appLauncherWindow.Visible) { @@ -779,9 +778,9 @@ namespace Greenshot.Helpers ICaptureDetails captureDetails = _capture.CaptureDetails; bool canDisposeSurface = true; - if (captureDetails.HasDestination(PickerDestination.DESIGNATION)) + if (captureDetails.HasDestination(nameof(WellKnownDestinations.Picker))) { - DestinationHelper.ExportCapture(false, PickerDestination.DESIGNATION, surface, captureDetails); + DestinationHelper.ExportCapture(false, nameof(WellKnownDestinations.Picker), surface, captureDetails); captureDetails.CaptureDestinations.Clear(); canDisposeSurface = false; } @@ -799,7 +798,7 @@ namespace Greenshot.Helpers // or use the file that was written foreach (IDestination destination in captureDetails.CaptureDestinations) { - if (PickerDestination.DESIGNATION.Equals(destination.Designation)) + if (nameof(WellKnownDestinations.Picker).Equals(destination.Designation)) { continue; } @@ -899,30 +898,32 @@ namespace Greenshot.Helpers /// /// Check if Process uses PresentationFramework.dll -> meaning it uses WPF /// - /// Proces to check for the presentation framework + /// Process to check for the presentation framework /// true if the process uses WPF private static bool IsWpf(Process process) { - if (process != null) + if (process == null) { - try + return false; + } + try + { + foreach (ProcessModule module in process.Modules) { - foreach (ProcessModule module in process.Modules) + if (!module.ModuleName.StartsWith("PresentationFramework")) { - if (module.ModuleName.StartsWith("PresentationFramework")) - { - Log.InfoFormat("Found that Process {0} uses {1}, assuming it's using WPF", process.ProcessName, module.FileName); - return true; - } + continue; } - } - catch (Exception) - { - // Access denied on the modules - Log.WarnFormat("No access on the modules from process {0}, assuming WPF is used.", process.ProcessName); + Log.InfoFormat("Found that Process {0} uses {1}, assuming it's using WPF", process.ProcessName, module.FileName); return true; } } + catch (Exception) + { + // Access denied on the modules + Log.WarnFormat("No access on the modules from process {0}, assuming WPF is used.", process.ProcessName); + return true; + } return false; } @@ -933,7 +934,7 @@ namespace Greenshot.Helpers /// Window to capture /// The capture to store the details /// What WindowCaptureMode to use - /// + /// ICapture public static ICapture CaptureWindow(WindowDetails windowToCapture, ICapture captureForWindow, WindowCaptureMode windowCaptureMode) { if (captureForWindow == null) @@ -1163,7 +1164,7 @@ namespace Greenshot.Helpers // Workaround for problem with DPI retrieval, the FromHwnd activates the window... WindowDetails previouslyActiveWindow = WindowDetails.GetActiveWindow(); // Workaround for changed DPI settings in Windows 7 - var mainForm = SimpleServiceProvider.Current.GetInstance(); + var mainForm = SimpleServiceProvider.Current.GetInstance(); using (Graphics graphics = Graphics.FromHwnd(mainForm.Handle)) { _capture.CaptureDetails.DpiX = graphics.DpiX; @@ -1180,21 +1181,12 @@ namespace Greenshot.Helpers private void CaptureWithFeedback() { - // The following, to be precise the HideApp, causes the app to close as described in BUG-1620 - // Added check for metro (Modern UI) apps, which might be maximized and cover the screen. - - //foreach(WindowDetails app in WindowDetails.GetAppWindows()) { - // if (app.Maximised) { - // app.HideApp(); - // } - //} - using CaptureForm captureForm = new CaptureForm(_capture, _windows); // Make sure the form is hidden after showing, even if an exception occurs, so all errors will be shown DialogResult result; try { - var mainForm = SimpleServiceProvider.Current.GetInstance(); + var mainForm = SimpleServiceProvider.Current.GetInstance(); result = captureForm.ShowDialog(mainForm); } finally diff --git a/src/Greenshot/Helpers/PrintHelper.cs b/src/Greenshot/Helpers/PrintHelper.cs index e7dd9fe99..9e6a43a7f 100644 --- a/src/Greenshot/Helpers/PrintHelper.cs +++ b/src/Greenshot/Helpers/PrintHelper.cs @@ -24,11 +24,13 @@ using System.Drawing; using System.Drawing.Printing; using System.Windows.Forms; using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; using Greenshot.Base.Effects; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; using Greenshot.Configuration; +using Greenshot.Editor.Helpers; using Greenshot.Forms; using log4net; diff --git a/src/Greenshot/Helpers/ProcessorHelper.cs b/src/Greenshot/Helpers/ProcessorHelper.cs deleted file mode 100644 index daae56bc4..000000000 --- a/src/Greenshot/Helpers/ProcessorHelper.cs +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using Greenshot.Base.Core; -using Greenshot.Base.Interfaces; -using log4net; - -namespace Greenshot.Helpers -{ - /// - /// Description of ProcessorHelper. - /// - public static class ProcessorHelper - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(ProcessorHelper)); - - /// - /// Register the internal processors - /// - public static void RegisterInternalProcessors() - { - foreach (Type processorType in InterfaceUtils.GetSubclassesOf(typeof(IProcessor), true)) - { - // Only take our own - if (!"Greenshot.Processors".Equals(processorType.Namespace)) - { - continue; - } - - try - { - if (!processorType.IsAbstract) - { - IProcessor processor; - try - { - processor = (IProcessor) Activator.CreateInstance(processorType); - } - catch (Exception e) - { - LOG.ErrorFormat("Can't create instance of {0}", processorType); - LOG.Error(e); - continue; - } - - if (processor.isActive) - { - LOG.DebugFormat("Found Processor {0} with designation {1}", processorType.Name, processor.Designation); - SimpleServiceProvider.Current.AddService(processor); - } - else - { - LOG.DebugFormat("Ignoring Processor {0} with designation {1}", processorType.Name, processor.Designation); - } - } - } - catch (Exception ex) - { - LOG.ErrorFormat("Error loading processor {0}, message: ", processorType.FullName, ex.Message); - } - } - } - } -} \ No newline at end of file From 95c4ea5cbe03306dede1cce993d43187bb7e0e0a Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 15 Apr 2021 11:13:34 +0200 Subject: [PATCH 128/232] This simple workaround fixes that the animations are not at the right speed (it's a workaround as it would be much nicer if the number of frames is correctly calculated.) --- src/Greenshot.Base/Controls/AnimatingForm.cs | 23 +------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/Greenshot.Base/Controls/AnimatingForm.cs b/src/Greenshot.Base/Controls/AnimatingForm.cs index e9eb526d6..60d5e7ce9 100644 --- a/src/Greenshot.Base/Controls/AnimatingForm.cs +++ b/src/Greenshot.Base/Controls/AnimatingForm.cs @@ -34,7 +34,6 @@ namespace Greenshot.Base.Controls { private static readonly ILog Log = LogManager.GetLogger(typeof(AnimatingForm)); private const int DEFAULT_VREFRESH = 60; - private int _vRefresh; private Timer _timer; /// @@ -45,27 +44,7 @@ namespace Greenshot.Base.Controls /// /// Vertical Refresh Rate /// - protected int VRefresh - { - get - { - if (_vRefresh == 0) - { - // get te hDC of the desktop to get the V-REFRESH - using var desktopHandle = SafeWindowDcHandle.FromDesktop(); - _vRefresh = GDI32.GetDeviceCaps(desktopHandle, DeviceCaps.VREFRESH); - } - - // A vertical refresh rate value of 0 or 1 represents the display hardware's default refresh rate. - // As there is currently no know way to get the default, we guess it. - if (_vRefresh <= 1) - { - _vRefresh = DEFAULT_VREFRESH; - } - - return _vRefresh; - } - } + protected int VRefresh => DEFAULT_VREFRESH; /// /// Check if we are in a Terminal Server session OR need to optimize for RDP / remote desktop connections From 8e121f25f03fe9d249ad4fabd837d84d2e820e8e Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 18 May 2021 10:56:39 +0200 Subject: [PATCH 129/232] Fix for clipboard issues #307, this caused all kind of problems throughout the editor whenever the clipboard contents where checked. [skip ci] --- src/Greenshot.Base/Core/ClipboardHelper.cs | 177 +++++++++++++----- src/Greenshot.Base/Core/FileDescriptor.cs | 76 ++++++++ .../Core/FileDescriptorReader.cs | 52 +---- src/Greenshot/Destinations/FileDestination.cs | 6 +- 4 files changed, 215 insertions(+), 96 deletions(-) create mode 100644 src/Greenshot.Base/Core/FileDescriptor.cs diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs index 7da99f216..02a7f03f1 100644 --- a/src/Greenshot.Base/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -299,39 +299,24 @@ EndSelection:<<<<<<<4 return true; } - var fileDescriptor = (MemoryStream) dataObject.GetData("FileGroupDescriptorW"); - var files = FileDescriptorReader.Read(fileDescriptor); - var fileIndex = 0; - foreach (var fileContentFile in files) + foreach (var fileData in IterateClipboardContent(dataObject)) { - if ((fileContentFile.FileAttributes & FileAttributes.Directory) != 0) - { - //Do something with directories? - //Note that directories do not have FileContents - //And will throw if we try to read them - continue; - } - - var fileData = FileDescriptorReader.GetFileContents(dataObject, fileIndex); try { - //Do something with the fileContent Stream - if (IsValidStream(fileData)) + using (ImageHelper.FromStream(fileData)) { - fileData.Position = 0; - using (ImageHelper.FromStream(fileData)) - { - // If we get here, there is an image - return true; - } + // If we get here, there is an image + return true; } } + catch (Exception ex) + { + Log.Error("Couldn't read file contents", ex); + } finally { fileData?.Dispose(); } - - fileIndex++; } if (dataObject.GetDataPresent(FORMAT_FILECONTENTS)) @@ -357,28 +342,116 @@ EndSelection:<<<<<<<4 // Try to get the image from the HTML code var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); - if (textObject != null) + if (textObject == null) { - var doc = new HtmlDocument(); - doc.LoadHtml(textObject); - var imgNodes = doc.DocumentNode.SelectNodes("//img"); - if (imgNodes != null) + return false; + } + + var doc = new HtmlDocument(); + doc.LoadHtml(textObject); + var imgNodes = doc.DocumentNode.SelectNodes("//img"); + + if (imgNodes == null) + { + return false; + } + + foreach (var imgNode in imgNodes) + { + var srcAttribute = imgNode.Attributes["src"]; + var imageUrl = srcAttribute.Value; + if (!string.IsNullOrEmpty(imageUrl)) { - foreach (var imgNode in imgNodes) - { - var srcAttribute = imgNode.Attributes["src"]; - var imageUrl = srcAttribute.Value; - if (!string.IsNullOrEmpty(imageUrl)) - { - return true; - } - } + return true; } } return false; } + /// + /// Iterate the clipboard content + /// + /// IDataObject + /// IEnumerable{MemoryStream} + private static IEnumerable IterateClipboardContent(IDataObject dataObject) + { + var fileDescriptors = AvailableFileDescriptors(dataObject); + if (fileDescriptors == null) yield break; + + foreach (var fileData in IterateFileDescriptors(fileDescriptors, dataObject)) + { + yield return fileData; + } + } + + /// + /// Retrieve the FileDescriptor on the clipboard + /// + /// IDataObject + /// IEnumerable{FileDescriptor} + private static IEnumerable AvailableFileDescriptors(IDataObject dataObject) + { + var fileDescriptor = (MemoryStream) dataObject.GetData("FileGroupDescriptorW"); + if (fileDescriptor != null) + { + try + { + return FileDescriptorReader.Read(fileDescriptor); + } + catch (Exception ex) + { + Log.Error("Couldn't use FileDescriptorReader.", ex); + } + } + + return Enumerable.Empty(); + } + + /// + /// Iterate the file descriptors on the clipboard + /// + /// IEnumerable{FileDescriptor} + /// IDataObject + /// IEnumerable{MemoryStream} + private static IEnumerable IterateFileDescriptors(IEnumerable fileDescriptors, IDataObject dataObject) + { + if (fileDescriptors == null) + { + yield break; + } + + var fileIndex = 0; + foreach (var fileDescriptor in fileDescriptors) + { + if ((fileDescriptor.FileAttributes & FileAttributes.Directory) != 0) + { + //Do something with directories? + //Note that directories do not have FileContents + //And will throw if we try to read them + continue; + } + + MemoryStream fileData = null; + try + { + fileData = FileDescriptorReader.GetFileContents(dataObject, fileIndex); + //Do something with the fileContent Stream + } + catch (Exception ex) + { + Log.Error($"Couldn't read file contents for {fileDescriptor.FileName}.", ex); + } + if (fileData?.Length > 0) + { + fileData.Position = 0; + yield return fileData; + } + + fileIndex++; + } + } + /// /// Get the specified IDataObject format as a string /// @@ -403,10 +476,10 @@ EndSelection:<<<<<<<4 /// Simple helper to check the stream /// /// - /// + /// true if there is a valid stream private static bool IsValidStream(MemoryStream memoryStream) { - return memoryStream != null && memoryStream.Length > 0; + return memoryStream?.Length > 0; } /// @@ -426,7 +499,7 @@ EndSelection:<<<<<<<4 } /// - /// Get all images (multiple if filenames are available) from the dataObject + /// Get all images (multiple if file names are available) from the dataObject /// Returned images must be disposed by the calling code! /// /// @@ -442,6 +515,26 @@ EndSelection:<<<<<<<4 } else { + foreach (var fileData in IterateClipboardContent(dataObject)) + { + Image image; + try + { + image = ImageHelper.FromStream(fileData); + } + catch (Exception ex) + { + Log.Error("Couldn't read file contents", ex); + continue; + } + finally + { + fileData?.Dispose(); + } + // If we get here, there is an image + yield return image; + } + // check if files are supplied foreach (string imageFile in GetImageFilenames(dataObject)) { @@ -478,7 +571,7 @@ EndSelection:<<<<<<<4 string[] retrieveFormats; // Found a weird bug, where PNG's from Outlook 2010 are clipped - // So I build some special logik to get the best format: + // So I build some special logic to get the best format: if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) { // Outlook ?? @@ -729,7 +822,7 @@ EndSelection:<<<<<<<4 /// This method will place images to the clipboard depending on the ClipboardFormats setting. /// e.g. Bitmap which works with pretty much everything and type Dib for e.g. OpenOffice /// because OpenOffice has a bug https://qa.openoffice.org/issues/show_bug.cgi?id=85661 - /// The Dib (Device Indenpendend Bitmap) in 32bpp actually won't work with Powerpoint 2003! + /// The Dib (Device Independent Bitmap) in 32bpp actually won't work with Powerpoint 2003! /// When pasting a Dib in PP 2003 the Bitmap is somehow shifted left! /// For this problem the user should not use the direct paste (=Dib), but select Bitmap /// diff --git a/src/Greenshot.Base/Core/FileDescriptor.cs b/src/Greenshot.Base/Core/FileDescriptor.cs new file mode 100644 index 000000000..5306cf3b8 --- /dev/null +++ b/src/Greenshot.Base/Core/FileDescriptor.cs @@ -0,0 +1,76 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.IO; +using System.Text; +using Greenshot.Base.UnmanagedHelpers.Structs; + +namespace Greenshot.Base.Core +{ + public sealed class FileDescriptor + { + public FileDescriptorFlags Flags { get; set; } + public Guid ClassId { get; set; } + public SIZE Size { get; set; } + public POINT Point { get; set; } + public FileAttributes FileAttributes { get; set; } + public DateTime CreationTime { get; set; } + public DateTime LastAccessTime { get; set; } + public DateTime LastWriteTime { get; set; } + public Int64 FileSize { get; set; } + public string FileName { get; set; } + + public FileDescriptor(BinaryReader reader) + { + //Flags + Flags = (FileDescriptorFlags)reader.ReadUInt32(); + //ClassID + ClassId = new Guid(reader.ReadBytes(16)); + //Size + Size = new SIZE(reader.ReadInt32(), reader.ReadInt32()); + //Point + Point = new POINT(reader.ReadInt32(), reader.ReadInt32()); + //FileAttributes + FileAttributes = (FileAttributes)reader.ReadUInt32(); + //CreationTime + CreationTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64()); + //LastAccessTime + LastAccessTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64()); + //LastWriteTime + LastWriteTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64()); + //FileSize + FileSize = reader.ReadInt64(); + //FileName + byte[] nameBytes = reader.ReadBytes(520); + int i = 0; + while (i < nameBytes.Length) + { + if (nameBytes[i] == 0 && nameBytes[i + 1] == 0) + break; + i++; + i++; + } + + FileName = Encoding.Unicode.GetString(nameBytes, 0, i); + } + } +} diff --git a/src/Greenshot.Base/Core/FileDescriptorReader.cs b/src/Greenshot.Base/Core/FileDescriptorReader.cs index 628e6d81a..69ad0af7d 100644 --- a/src/Greenshot.Base/Core/FileDescriptorReader.cs +++ b/src/Greenshot.Base/Core/FileDescriptorReader.cs @@ -24,8 +24,6 @@ using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; -using System.Text; -using Greenshot.Base.UnmanagedHelpers.Structs; namespace Greenshot.Base.Core { @@ -33,60 +31,12 @@ namespace Greenshot.Base.Core /// Specifies which fields are valid in a FileDescriptor Structure /// [Flags] - internal enum FileDescriptorFlags : uint + public enum FileDescriptorFlags : uint { } internal static class FileDescriptorReader { - internal sealed class FileDescriptor - { - public FileDescriptorFlags Flags { get; set; } - public Guid ClassId { get; set; } - public SIZE Size { get; set; } - public POINT Point { get; set; } - public FileAttributes FileAttributes { get; set; } - public DateTime CreationTime { get; set; } - public DateTime LastAccessTime { get; set; } - public DateTime LastWriteTime { get; set; } - public Int64 FileSize { get; set; } - public string FileName { get; set; } - - public FileDescriptor(BinaryReader reader) - { - //Flags - Flags = (FileDescriptorFlags) reader.ReadUInt32(); - //ClassID - ClassId = new Guid(reader.ReadBytes(16)); - //Size - Size = new SIZE(reader.ReadInt32(), reader.ReadInt32()); - //Point - Point = new POINT(reader.ReadInt32(), reader.ReadInt32()); - //FileAttributes - FileAttributes = (FileAttributes) reader.ReadUInt32(); - //CreationTime - CreationTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64()); - //LastAccessTime - LastAccessTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64()); - //LastWriteTime - LastWriteTime = new DateTime(1601, 1, 1).AddTicks(reader.ReadInt64()); - //FileSize - FileSize = reader.ReadInt64(); - //FileName - byte[] nameBytes = reader.ReadBytes(520); - int i = 0; - while (i < nameBytes.Length) - { - if (nameBytes[i] == 0 && nameBytes[i + 1] == 0) - break; - i++; - i++; - } - - FileName = Encoding.Unicode.GetString(nameBytes, 0, i); - } - } - public static IEnumerable Read(Stream fileDescriptorStream) { if (fileDescriptorStream == null) diff --git a/src/Greenshot/Destinations/FileDestination.cs b/src/Greenshot/Destinations/FileDestination.cs index 677fc0e18..9389c3d26 100644 --- a/src/Greenshot/Destinations/FileDestination.cs +++ b/src/Greenshot/Destinations/FileDestination.cs @@ -55,12 +55,12 @@ namespace Greenshot.Destinations public override ExportInformation ExportCapture(bool manuallyInitiated, ISurface surface, ICaptureDetails captureDetails) { - ExportInformation exportInformation = new ExportInformation(Designation, Description); + var exportInformation = new ExportInformation(Designation, Description); bool outputMade; bool overwrite; string fullPath; // Get output settings from the configuration - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(); + var outputSettings = new SurfaceOutputSettings(); if (captureDetails?.Filename != null) { @@ -79,7 +79,7 @@ namespace Greenshot.Destinations if (CoreConfig.OutputFilePromptQuality) { - QualityDialog qualityDialog = new QualityDialog(outputSettings); + var qualityDialog = new QualityDialog(outputSettings); qualityDialog.ShowDialog(); } From d429e4f6afa7725f75bbfb6e5a8e17a4329519db Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 18 May 2021 13:51:00 +0200 Subject: [PATCH 130/232] Removed the plugin attribute, and changed the way the plugins are copied to their destination. This should simplify the packaging, for InnoSetup but also the .zip & protable (which are still missing at this moment) --- installer/innosetup/setup.iss | 26 +++++---- src/Directory.Build.props | 31 +++++------ src/Greenshot.Base/GlobalSuppressions.cs | Bin 119362 -> 0 bytes src/Greenshot.Base/Greenshot.Base.csproj | 2 +- .../Interfaces/Plugin/IGreenshotPlugin.cs | 10 ++++ .../Interfaces/Plugin/PluginAttribute.cs | 50 ------------------ src/Greenshot.Plugin.Box/BoxPlugin.cs | 11 +++- src/Greenshot.Plugin.Box/BoxUtils.cs | 1 + .../Greenshot.Plugin.Box.csproj | 2 +- .../ConfluencePlugin.cs | 13 ++++- src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs | 11 +++- .../Greenshot.Plugin.Dropbox.csproj | 2 +- .../ExternalCommandPlugin.cs | 13 ++++- src/Greenshot.Plugin.Flickr/FlickrPlugin.cs | 14 ++++- .../Greenshot.Plugin.Flickr.csproj | 2 +- .../GooglePhotosPlugin.cs | 11 +++- src/Greenshot.Plugin.Imgur/ImgurPlugin.cs | 33 +++++++----- .../Greenshot.Plugin.Jira.csproj | 4 +- src/Greenshot.Plugin.Jira/JiraPlugin.cs | 21 +++++--- src/Greenshot.Plugin.Office/OfficePlugin.cs | 13 ++++- .../PhotobucketPlugin.cs | 13 ++++- .../Greenshot.Plugin.Win10.csproj | 3 +- src/Greenshot.Plugin.Win10/Win10Plugin.cs | 11 +++- src/Greenshot.sln | 15 +----- src/Greenshot/Greenshot.csproj | 2 +- src/Greenshot/Helpers/PluginHelper.cs | 26 +++++---- 26 files changed, 189 insertions(+), 151 deletions(-) delete mode 100644 src/Greenshot.Base/GlobalSuppressions.cs delete mode 100644 src/Greenshot.Base/Interfaces/Plugin/PluginAttribute.cs diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index c08588ca5..ef2a2fc50 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -6,6 +6,7 @@ #define LanguagesDir "..\..\src\Greenshot\Languages" #define BinDir "bin\Release\net472" #define ReleaseDir "..\..\src\Greenshot\bin\Release\net472" +#define PluginDir "..\..\src\Greenshot\bin\Release\net472\Plugins" ; Include the scripts to install .NET Framework ; See https://www.codeproject.com/KB/install/dotnetfx_innosetup_instal.aspx @@ -24,8 +25,7 @@ Source: {#ReleaseDir}\Greenshot.Base.dll; DestDir: {app}; Components: greenshot; Source: {#ReleaseDir}\Greenshot.Editor.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Greenshot.exe.config; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\log4net.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\Dapplo.Http*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion -Source: {#ReleaseDir}\Dapplo.Log.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\Dapplo.*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\HtmlAgilityPack.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion @@ -81,35 +81,33 @@ Source: {#LanguagesDir}\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {ap Source: {#LanguagesDir}\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion; ;Office Plugin -Source: {#BaseDir}\Greenshot.Plugin.Office\{#BinDir}\Greenshot.Plugin.Office.dll; DestDir: {app}\Plugins\Office; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Office\*.dll; DestDir: {app}\Plugins\Office; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; ;JIRA Plugin -Source: {#BaseDir}\Greenshot.Plugin.Jira\{#BinDir}\Greenshot.Plugin.Jira.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\Greenshot.Plugin.Jira\{#BinDir}\Dapplo.Jira*.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Jira\*.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Jira\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion; ;Imgur Plugin -Source: {#BaseDir}\Greenshot.Plugin.Imgur\{#BinDir}\Greenshot.Plugin.Imgur.dll; DestDir: {app}\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Imgur\*.dll; DestDir: {app}\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Imgur\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion; ;Box Plugin -Source: {#BaseDir}\Greenshot.Plugin.Box\{#BinDir}\Greenshot.Plugin.Box.dll; DestDir: {app}\Plugins\Box; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Box\*.dll; DestDir: {app}\Plugins\Box; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Box\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\Box; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion; ;DropBox Plugin -Source: {#BaseDir}\Greenshot.Plugin.DropBox\{#BinDir}\Greenshot.Plugin.DropBox.dll; DestDir: {app}\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.DropBox\*.dll; DestDir: {app}\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.DropBox\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion; ;Flickr Plugin -Source: {#BaseDir}\Greenshot.Plugin.Flickr\{#BinDir}\Greenshot.Plugin.Flickr.dll; DestDir: {app}\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Flickr\*.dll; DestDir: {app}\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Flickr\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion; ;Photobucket Plugin -Source: {#BaseDir}\Greenshot.Plugin.Photobucket\{#BinDir}\\Greenshot.Plugin.Photobucket.dll; DestDir: {app}\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Photobucket\*.dll; DestDir: {app}\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Photobucket\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion; ;Confluence Plugin -Source: {#BaseDir}\Greenshot.Plugin.Confluence\{#BinDir}\Greenshot.Plugin.Confluence.dll; DestDir: {app}\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Confluence\*.dll; DestDir: {app}\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Confluence\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; ;ExternalCommand Plugin -Source: {#BaseDir}\Greenshot.Plugin.ExternalCommand\{#BinDir}\Greenshot.Plugin.ExternalCommand.dll; DestDir: {app}\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.ExternalCommand\*.dll; DestDir: {app}\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.ExternalCommand\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion; ;Win 10 Plugin -Source: {#BaseDir}\Greenshot.Plugin.Win10\{#BinDir}\Greenshot.Plugin.Win10.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; -Source: {#BaseDir}\Greenshot.Plugin.Win10\{#BinDir}\Microsoft.Toolkit.Uwp.Notifications.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Win10\*.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; [Setup] ; changes associations is used when the installer installs new extensions, it clears the explorer icon cache diff --git a/src/Directory.Build.props b/src/Directory.Build.props index e56ca9d63..f19f03423 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -21,16 +21,6 @@ true - - - - - - - false - true - - false true @@ -57,7 +47,7 @@ - + all runtime; build; native; contentfiles; analyzers @@ -110,13 +100,18 @@ + xcopy /f /y /d "$(TargetDir)$(TargetName).*" "$(SolutionDir)$(SolutionName)\$(OutDir)\Plugins\$(TargetName)" + xcopy /f /y /d "$(TargetDir)*.dll" "$(SolutionDir)$(SolutionName)\$(OutDir)\Plugins\$(TargetName)" + IF EXIST "$(TargetDir)Languages" ( + IF NOT EXIST "$(SolutionDir)$(SolutionName)\$(OutDir)Languages\$(TargetName)" ( + mkdir "$(SolutionDir)$(SolutionName)\$(OutDir)Languages\$(TargetName)" + ) + xcopy /f /y /d "$(TargetDir)Languages\*en-US.xml" "$(SolutionDir)$(SolutionName)\$(OutDir)Languages\$(TargetName)" + ) + for /f "tokens=*" %%F in ('dir /b /A-D $(SolutionDir)$(SolutionName)\$(OutDir)') do if EXIST "$(SolutionDir)$(SolutionName)\$(OutDir)\Plugins\$(TargetName)\%%F" ( echo %%F del "$(SolutionDir)$(SolutionName)\$(OutDir)\Plugins\$(TargetName)\%%F" ) + " /> diff --git a/src/Greenshot.Base/GlobalSuppressions.cs b/src/Greenshot.Base/GlobalSuppressions.cs deleted file mode 100644 index 148f8734d4145c7536cec4062f00e77f26868c14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 119362 zcmeHQU2hx7mF?#M`455v3>?fv$z+2(1lR{rlw~8*m=Wcj-5CrFT9jnQq9~A*J<5;Y z-E-=y+|||9MNwUpx|j>Wro>`@u@Co_s5@S2X6z@(jw!DAcDTc*uaf6>Zj$7d8 z`2KZNT$(few)hS1g7-1PQA>Pof~(!)H-3HxuOH0_$9WFE@_bkLoZOpSnV*w8;k9PP zKQVfSqj!t)3WLhXAIx|CjL%)+tPAfxCpgEoxr1|@muEl6(L3gDc+3t)`HlHa=jOXC z@z>0J#@^{Aj^t;rF;d>e2!Ac`4S0VO^UTj`=NaJ`KKBJaGc%v%U-C_PJfHp)XW)58 z_{@3nof*F~pXKiyo#ILIuKD*ljy`jqMtMJ{=6j5AJzhiZt|~Km7WVq(leT!_`6;(c zJe_6n2V95JIV(QleR*yy^|^UGQe_?nMo8J09j< zm?P~IcJH;kix0fd!5#2tXyz(s)f7kdasQMA?{R^yRtGM{*XZVclv#_tH zI7c~m<+wwdtfNS028xUu^#XI~@mg5X0gN=*V`2WhxyE%^Gcm5G~yIcGY zzkR`H-(hTwPxINI;+(f;Uh;TiNH~dXFgM?o&+DZpEn<=PL3aGENOgzraW}7VcgIB! zPkIl}|EPG6tDF>X@&5r{Px0OX?&X`}_mJD~i(kxB>?YFW8SyC!4(52iAIuXbd*6BJ z`wOu5J<#W)ZfImqh8g3TQ2ISc=D%lbZ*nMpnU(rEt#kVWF>dnyKqlVvw{eNa`Li&)_(j{Yr-hT^A*v400 z;rJOmnjdi#V-_>`JTZ&F$HzP4_brS6DE7huv8~F=Qp(x_YRa-D6^;bN*;%t zefU@OddCKJ*FcJoFOG`GwhLtVqx8Rgl!%TA;iq}T#m~?1Yn#uh=;|iATnSnZIx?tY zT#XSzpM@;b*f>g?4ZBctgJ?|7LA6#MKzTzJ{l(^ZjY&`@^Mt2qY|xCa|$!ckcVMyjjYEs_^W0&!`A^ z8U$41>ZLugZ&;jpMzR3&6j!isBx7*}`||QWw$7+Kk#P=oDD6=n53baezti$}D5qj` zD=${&De4k`2WgkQK1JSS30|j%62`>KM_%Jw=!YM0=C=XQ!qo*aTOd3ZvO-UR&|mRQ zm_sY|Owaf>w1lb6p6hHfJ9yXhu~uc4!V>%Tt8`vrMlvh5$RJ;|eUYB9bU2?la&0ON z=J3>;=2F!jcCqTCvxoD|4Er(D6?a{vxtuASD{xaM_Lxk7F0=di8UXAAMU+?ehjsWebWz4bSQi)I1UJg_8t;)GXmilRp*N?|plzt0wbCBm zOO!SIG08W5&Y$OE8HA(1?wE2wmpQ<4y3~b>&(Vi17~=zu$Ize>Pb=|uQQ_6r{~_4^ zjj0zQ^Y@G=O53rX@jZb(DLDkL2JkaZWR5x37I5tYtL_;c5KZHvDdx#kBW9)Vk>Z%H z+vV4Gdel;BZ7Ju_e%A91RQD;=nGfE=AvR>>X=9kW_?y!Q+ zMzZWS*tu0LCOH{dBi3Z&_%=)m4WUe(mZ{U^ZmQULsE3mR55DD+;+%@Hv>1C@``TqD z+TA@^$+EIuvOk+(r4%^=@e8<8_Xc;(?Dx#9)aB}HTC4Tkfg1_*=YiPv55lqG zx@Xmykai|)f^A*Ab0rMpPbctvSgXECe@`%^QE2I6@YJgr){Qzyezf#~eQc!An?942 z2x%TshUq@T2zHpUu(79oqowM7AJU*GMP{^quZpy^NP8Nqj(wBZ)rpbQLs&u+SVyj< zw1>a>nLFgZFHF{r`p;*#n7vaSYmdF=T90aFQJ52B`5x7^>2>Y%q1Z;o-k?HFYT8~E z|J@1Xz6$sn)majvrv2OqXf}Z#OI9nx*g7M#ZG>GK1=Zr`H9{`>?=*7+O@m`N)?Y!)K7MFi9z0 zm0>P2luFxc(}S0`9BUa?_rO@q2khx<&*yer^KJfk#NE{*im6;M#TD_g8wJ->xk&JN zU*iK^j{t`BI->;ah$r@6InPzPx$P?vlCISV(g{!2u`uS}J~LE3qpKClEZiwsD8O5TcswQXgIGAWPA+{pdMBWaI{n zbcbGJ>@@rdc~W*dkm|Y^TGW#0q9wr{9GTZDGh5Urtg2ydYl*dhXOQzX>L%-2Cgxj+ zmI+nKxcVo)Hn3?_V#pW;yU;L-dr_;;dW?Q5 zajX%NZbnGn8J}nVH8ao7yKW!M>Ta|?%3L;54b?>r<;z!M8LougESzuG);lb_5)b=E z)Gs>Q^O)^|23g4=JD}(c&n;8u&v5Z29xBuD9F{d-%IJAAdTb7-=yp=qA*}M6;z#=A zDsFPX4ZRKSpX%BIn?_FPnu;CfmAKyp_cO}LZg7!fy~8+ys%ww!FKh)Q=ElVC-`V9*UtxwMh=zMC2^bya&8iCA(=X;Rh#LUtv*U!w#rJDx% zs`rqaCYOCLxn7g&fo~yke>WUu;e1$_6>SUT7MGCajc4Dh9CMJP#Bf&6%Bnr>#%5K{ zImo$g9S@8b$l7|Yp1_r;%zzvACERw(%%J2SwxZiP=Mh8oo}IcOP5 z^e14PG5XN1xoS7$8GkJ!#py!AQUS(V5J_lRJ)REOh1EXx7WI8mbzM&+b;Whbh+J(_jQ2i z2lX*?@iCk6(1r`bsL*PXe5y&P1!aF1R)4)R*_G*|y;0ZuP|Gj}%P=f|t|yh9z1nw* zYu=$t(UNBt!_8UK4&dIo@hD|`6osy-l@57SIvfBa>@e!eFijWA@R{wJShY@aUm0oT zyN?wI6VzE%Yg||DUe=yBetl2?4~)OMu3M_K>YisrOvPP5yEk6Gb9 z?*8bn&kSKtGhq2-z(lfrc-=8Qrn5AMS<1W>_oQT2{v2z=;xY|u2c5gQ&0SW`Pr%C` zz|M@djN!$8fd|W7OkWl{b90!v64$6plHF|2Ax)8`>e{>`4b0=Pk6n2QKSOYYX0#KR6zu{S{-3NwQ2FE~dX0e@e|GS~Xv-0FKN?@P#iVJwY# zB}Ws_4!aznS|P1gcn&+gz6$*mxR?STWP?>b?yA;=%LBfCc(~4KpL=7BY1Q{Cty%w0 zW8cD#iGI|&^gQa)Mbixsi?{>hv2)r8p4Pt6cGP-vtPPghs`l6$ASTUf&Qq=B#IsJz zkDKw6j)8`1u9s+_@3h4IuVV*QIW8@he3p`H>AKup*5wKZx%yJ-2w8=BW^mRXFHL7x zJ1qwu;@%85&``F+XN-ANqB%%Zy1jGH;hD`TFJnEBUH3zxh0Bek)tj&0B4q4TPz zk%uiQ$gm8a5*4;S+Me63lTMNKvFEk-tcc44akid@KFrd1wCthoT7tV~t>Y3tE;W%_ z4mns3)%wPL^qsFKOnBmAC&c!uOtUvf*>b#%2%MtTS^gDO4 zYu*`tqz8z-8#2OM+}S_zK0Q<0A@;}|vp{6&3h(+15oZCZEgaXl!^Kkf*&$Cvw6k4H ztVk4NT)YErMQd=ELQso=_NG5e7Sm1K0ADkZ%y@#^g{D3N4NISA9FDk9t&B^ zX)W8dXOnNlyZ+_@{pOmUrj<@v@1`@Z3mk0aV&@g*#~dPKgHzO|k*UY{$10?9PF3Uj zvH6f&&$m2THcdrZANAK_llQR#dI|h-wq9^}rP9c?t$V#hOkF|F6WDxtZ%d#R^Xvpk<>S=|%YXBn4EdSDc;{h^n_ z4$Q084T{XIztwGh;7-F3`x)ejXVTfxAKf@1T{$ADv)Yqt|u+CDfDGJ@IBCgAb`#VrIhc!gcg3Q5K zj$|Q5K-@S$e9&fHUM201h0;7VENY;JQ_qJP&|bNvzX zS-hGQeOKM{xm9GoS5wVI`=iPeIrGF2nZkvME;CE$BEr`PuHUO1k{gH6t7Y9Md%>xc ziRI7Gi=WI>>0*8FaU8-!78=L$COhVt{ z4wdDsCBH(hl9j}^4*d;yW@Pq@V2>DbPE4ElxN$8Cf9x?;x$gP2j_x^EEj*6ZO0@NX zu?1=q%BYEtt5_9nTkI%L<;GJIsXYd2#)hY=JCeq*qq5FT*4&wh>=2i+dNH|ps{_b# z&#c8`+_FBCxg!QECai^#a&H9H6tbT21)_(0SQDAk%E;9=MhIC=_N$LFUuU>{lG;{P z9n@tVR7KGNyqp_U4cuY%4_D@X0z0vqQ~E8$P@_`rvXmJcV*aempi$3o9S?J8OH>=3 zLEhI`;qYtC$Bp?SW%R>m4VO{k)kjUE8dKR^<$ap!BY&TAt`U@e9%G>Ci`QE~*<%47 z<=&Is>cOzu((vV6Ulr)a;(Z&Wz9!V=hA?k%?rV&z+cB;%DhALf%@f7uWb=@LsjhKmHZeQ_}6Mn?r`BJe8H;tgs zH5Ef$>G-w2?x{0^jcdk{RINO>$Lzuem;M!uYxH1?Gycl1HuHuxGU|us=7%;T=Ezv4 zmq5VBTAai6N>t0_q-8|jGT+Jc%%IhK!HRr!Hs>~*dywVCM4??f^b|7YzZ;#$h`Mc4 zTuC}OaxZAsV%-|6-y#(OFOG%SrfY|(wibGY6FYD^nm05|?S*w{PETBYt&7R9=W;=GoRT za2M@RU~cI~fPFWXX+YvsI;6%(>j#>Y}D%C0!OL{#u4GPK8d zdS|AhnVsq{U=7+xp{_74J7W#+pAkEiSe+Bsb0PH6hfYy-I7D9k1pAmB;fMRazQXUS z0rS#;b~UJrte)vn5XV(}=Bi(@4-Q~&1a{n!z0-X?S?x8f{#{P~oy37$sSm*P^__4e z0w|FjU;b6yx(mi(%wUSM?1Fok0cW;z3H&x8NX{+{Smj2=R=#U41WC({X1PO{Dbb`{ zloJ=#vz4)Z0K;6AV#h8;&1O)u>HSpw>Z^K=V}0Eg(|aY)_!_b8NP9cZ)yeX$71f(T z^=7&f3Kz;+aaWcx`(GuTpM*pE&%2zXGR;Y*%!{!vI@gArW3P<;75R>;ucLC$JKx1h z{|S0~e1QMUev)H&zhB__GFGbnA99Ppog-RNmniFe&LLHism|Z+=;6XV5j!<9?@^bz zj7~5fv%bPUfYv_cSNp_jDR#W(9))6iA7IBqiDAYNptjm(Y_;c%8My)`p?12t=ub9=jmqV>1HA!+y#hhk_f-}H@{kxG&6vgft;tjNm? zc~T3$Z+xDm@r1d;)wLMy%2ut|$gg6fT6gJ7S*^sJti*lThpeDwX`?8kcbm~Ahr`GZSKbSs9|0%K@f-jd^eXE6C)!B1MvS`Np-$v`jMbu)uk4p} z2RYl_^n7jIgAYlL___F{R%>LX9$q78M->y>h6#xd$E6-0RZMgp6Mf_?gd_T>!=D!K z5G@?v+Y6`2d9icU2l##?*b7(S5$c5-@WdQ!!P@;*xsCRb3c17g$ceqi-5q1U?jMRh Z*fK}Od)yCuvkaiIPB8ukuS3W3_ - + diff --git a/src/Greenshot.Base/Interfaces/Plugin/IGreenshotPlugin.cs b/src/Greenshot.Base/Interfaces/Plugin/IGreenshotPlugin.cs index b61f49f44..ad968a5c3 100644 --- a/src/Greenshot.Base/Interfaces/Plugin/IGreenshotPlugin.cs +++ b/src/Greenshot.Base/Interfaces/Plugin/IGreenshotPlugin.cs @@ -22,5 +22,15 @@ namespace Greenshot.Base.Interfaces.Plugin /// Open the Configuration Form, will/should not be called before handshaking is done /// void Configure(); + + /// + /// Define the name of the plugin + /// + string Name { get; } + + /// + /// Specifies if the plugin can be configured + /// + bool IsConfigurable { get; } } } \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Plugin/PluginAttribute.cs b/src/Greenshot.Base/Interfaces/Plugin/PluginAttribute.cs deleted file mode 100644 index dd5fed129..000000000 --- a/src/Greenshot.Base/Interfaces/Plugin/PluginAttribute.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace Greenshot.Base.Interfaces.Plugin -{ - [Serializable] - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] - public sealed class PluginAttribute : Attribute, IComparable - { - public string Name { get; set; } - - public bool Configurable { get; private set; } - - public PluginAttribute(string name, bool configurable) - { - Name = name; - Configurable = configurable; - } - - public int CompareTo(object obj) - { - if (obj is PluginAttribute other) - { - return string.Compare(Name, other.Name, StringComparison.Ordinal); - } - - throw new ArgumentException("object is not a PluginAttribute"); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/BoxPlugin.cs b/src/Greenshot.Plugin.Box/BoxPlugin.cs index f94f0ed4a..71b2ad93b 100644 --- a/src/Greenshot.Plugin.Box/BoxPlugin.cs +++ b/src/Greenshot.Plugin.Box/BoxPlugin.cs @@ -35,7 +35,6 @@ namespace Greenshot.Plugin.Box /// /// This is the Box base code /// - [Plugin("Box", true)] public class BoxPlugin : IGreenshotPlugin { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(BoxPlugin)); @@ -49,6 +48,16 @@ namespace Greenshot.Plugin.Box GC.SuppressFinalize(this); } + /// + /// Name of the plugin + /// + public string Name => "Box"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => true; + private void Dispose(bool disposing) { if (!disposing) return; diff --git a/src/Greenshot.Plugin.Box/BoxUtils.cs b/src/Greenshot.Plugin.Box/BoxUtils.cs index 57dcc6ac8..af135fa2e 100644 --- a/src/Greenshot.Plugin.Box/BoxUtils.cs +++ b/src/Greenshot.Plugin.Box/BoxUtils.cs @@ -67,6 +67,7 @@ namespace Greenshot.Plugin.Box /// Title of box upload /// Filename of box upload /// url to uploaded image + /// TODO: Remove title und filename? public static string UploadToBox(SurfaceContainer image, string title, string filename) { // Fill the OAuth2Settings diff --git a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj index 2b055bf08..fced869ad 100644 --- a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj +++ b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs index 6226493c0..e9dc34d41 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluencePlugin.cs @@ -33,7 +33,6 @@ namespace Greenshot.Plugin.Confluence /// /// This is the ConfluencePlugin base code /// - [Plugin("Confluence", true)] public class ConfluencePlugin : IGreenshotPlugin { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(ConfluencePlugin)); @@ -46,11 +45,21 @@ namespace Greenshot.Plugin.Confluence GC.SuppressFinalize(this); } - protected void Dispose(bool disposing) + private void Dispose(bool disposing) { //if (disposing) {} } + /// + /// Name of the plugin + /// + public string Name => "Confluence"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => true; + private static void CreateConfluenceConnector() { if (_confluenceConnector == null) diff --git a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs index 4ee388ceb..9a82b0f40 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs @@ -34,7 +34,6 @@ namespace Greenshot.Plugin.Dropbox /// /// This is the Dropbox base code /// - [Plugin("Dropbox", true)] public class DropboxPlugin : IGreenshotPlugin { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxPlugin)); @@ -56,6 +55,16 @@ namespace Greenshot.Plugin.Dropbox _itemPlugInConfig = null; } + /// + /// Name of the plugin + /// + public string Name => "Dropbox"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => true; + /// /// Implementation of the IGreenshotPlugin.Initialize /// diff --git a/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj index 28b675749..09eb988a5 100644 --- a/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj +++ b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs index 966965029..7f576ccdd 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandPlugin.cs @@ -34,7 +34,6 @@ namespace Greenshot.Plugin.ExternalCommand /// /// An Plugin to run commands after an image was written /// - [Plugin("ExternalCommand", true)] public class ExternalCommandPlugin : IGreenshotPlugin { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ExternalCommandPlugin)); @@ -48,7 +47,7 @@ namespace Greenshot.Plugin.ExternalCommand GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!disposing) return; if (_itemPlugInRoot == null) return; @@ -56,6 +55,16 @@ namespace Greenshot.Plugin.ExternalCommand _itemPlugInRoot = null; } + /// + /// Name of the plugin + /// + public string Name => "ExternalCommand"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => true; + private IEnumerable Destinations() { foreach (string command in ExternalCommandConfig.Commands) diff --git a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs index dff2a9f14..1939fba22 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs @@ -30,13 +30,13 @@ using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; using log4net; +using log4net.Config; namespace Greenshot.Plugin.Flickr { /// /// This is the Flickr base code /// - [Plugin("Flickr", true)] public class FlickrPlugin : IGreenshotPlugin { private static readonly ILog Log = LogManager.GetLogger(typeof(FlickrPlugin)); @@ -50,7 +50,7 @@ namespace Greenshot.Plugin.Flickr GC.SuppressFinalize(this); } - protected void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!disposing) { @@ -66,6 +66,16 @@ namespace Greenshot.Plugin.Flickr _itemPlugInConfig = null; } + /// + /// Name of the plugin + /// + public string Name => "Flickr"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => true; + /// /// Implementation of the IGreenshotPlugin.Initialize /// diff --git a/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj index 6fc040026..5bc629bf1 100644 --- a/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj +++ b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs index 89b0b6aa5..fae06e516 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosPlugin.cs @@ -34,7 +34,6 @@ namespace Greenshot.Plugin.GooglePhotos /// /// This is the GooglePhotos base code /// - [Plugin("GooglePhotos", true)] public class GooglePhotosPlugin : IGreenshotPlugin { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(GooglePhotosPlugin)); @@ -56,6 +55,16 @@ namespace Greenshot.Plugin.GooglePhotos _itemPlugInRoot = null; } + /// + /// Name of the plugin + /// + public string Name => "GooglePhotos"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => true; + /// /// Implementation of the IGreenshotPlugin.Initialize /// diff --git a/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs index ee4a51b1f..d105916a2 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurPlugin.cs @@ -37,7 +37,6 @@ namespace Greenshot.Plugin.Imgur /// /// This is the ImgurPlugin code /// - [Plugin("Imgur", true)] public class ImgurPlugin : IGreenshotPlugin { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(ImgurPlugin)); @@ -52,24 +51,32 @@ namespace Greenshot.Plugin.Imgur GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { - if (disposing) + if (!disposing) return; + if (_historyMenuItem != null) { - if (_historyMenuItem != null) - { - _historyMenuItem.Dispose(); - _historyMenuItem = null; - } + _historyMenuItem.Dispose(); + _historyMenuItem = null; + } - if (_itemPlugInConfig != null) - { - _itemPlugInConfig.Dispose(); - _itemPlugInConfig = null; - } + if (_itemPlugInConfig != null) + { + _itemPlugInConfig.Dispose(); + _itemPlugInConfig = null; } } + /// + /// Name of the plugin + /// + public string Name => "Imgur"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => true; + private IEnumerable Destinations() { yield return new ImgurDestination(this); diff --git a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj index 38d4d4073..a39835600 100644 --- a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj +++ b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj @@ -6,7 +6,7 @@ - - + + \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraPlugin.cs b/src/Greenshot.Plugin.Jira/JiraPlugin.cs index 162589527..e784f0ef8 100644 --- a/src/Greenshot.Plugin.Jira/JiraPlugin.cs +++ b/src/Greenshot.Plugin.Jira/JiraPlugin.cs @@ -35,7 +35,6 @@ namespace Greenshot.Plugin.Jira /// /// This is the JiraPlugin base code /// - [Plugin("Jira", true)] public class JiraPlugin : IGreenshotPlugin { private static readonly ILog Log = LogManager.GetLogger(typeof(JiraPlugin)); @@ -47,15 +46,23 @@ namespace Greenshot.Plugin.Jira GC.SuppressFinalize(this); } - protected void Dispose(bool disposing) + private void Dispose(bool disposing) { - if (disposing) - { - var jiraConnector = SimpleServiceProvider.Current.GetInstance(); - jiraConnector?.Dispose(); - } + if (!disposing) return; + var jiraConnector = SimpleServiceProvider.Current.GetInstance(); + jiraConnector?.Dispose(); } + /// + /// Name of the plugin + /// + public string Name => "Jira"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => true; + /// /// Implementation of the IGreenshotPlugin.Initialize /// diff --git a/src/Greenshot.Plugin.Office/OfficePlugin.cs b/src/Greenshot.Plugin.Office/OfficePlugin.cs index 78d2fb6f3..54eb25c22 100644 --- a/src/Greenshot.Plugin.Office/OfficePlugin.cs +++ b/src/Greenshot.Plugin.Office/OfficePlugin.cs @@ -31,7 +31,6 @@ namespace Greenshot.Plugin.Office /// /// This is the OfficePlugin base code /// - [Plugin("Office", false)] public class OfficePlugin : IGreenshotPlugin { private static readonly log4net.ILog LOG = log4net.LogManager.GetLogger(typeof(OfficePlugin)); @@ -42,11 +41,21 @@ namespace Greenshot.Plugin.Office GC.SuppressFinalize(this); } - protected void Dispose(bool disposing) + private void Dispose(bool disposing) { // Do nothing } + /// + /// Name of the plugin + /// + public string Name => "Office"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => false; + private IEnumerable Destinations() { IDestination destination; diff --git a/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs index 7b6b51425..62a933a63 100644 --- a/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs +++ b/src/Greenshot.Plugin.Photobucket/PhotobucketPlugin.cs @@ -35,7 +35,6 @@ namespace Greenshot.Plugin.Photobucket /// /// This is the GreenshotPhotobucketPlugin base code /// - [Plugin("Photobucket", true)] public class PhotobucketPlugin : IGreenshotPlugin { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(PhotobucketPlugin)); @@ -49,7 +48,7 @@ namespace Greenshot.Plugin.Photobucket GC.SuppressFinalize(this); } - protected void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!disposing) return; if (_itemPlugInConfig == null) return; @@ -57,6 +56,16 @@ namespace Greenshot.Plugin.Photobucket _itemPlugInConfig = null; } + /// + /// Name of the plugin + /// + public string Name => "Photobucket"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => true; + /// /// Implementation of the IGreenshotPlugin.Initialize /// diff --git a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj index 822370739..349b4d79e 100644 --- a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj +++ b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj @@ -6,9 +6,10 @@ - + + diff --git a/src/Greenshot.Plugin.Win10/Win10Plugin.cs b/src/Greenshot.Plugin.Win10/Win10Plugin.cs index a89620ed2..6b15ff3c5 100644 --- a/src/Greenshot.Plugin.Win10/Win10Plugin.cs +++ b/src/Greenshot.Plugin.Win10/Win10Plugin.cs @@ -32,7 +32,6 @@ namespace Greenshot.Plugin.Win10 /// /// This is the Win10Plugin /// - [Plugin("Win10", false)] public sealed class Win10Plugin : IGreenshotPlugin { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10Plugin)); @@ -47,6 +46,16 @@ namespace Greenshot.Plugin.Win10 throw new NotImplementedException(); } + /// + /// Name of the plugin + /// + public string Name => "Win10"; + + /// + /// Specifies if the plugin can be configured + /// + public bool IsConfigurable => false; + /// /// Implementation of the IGreenshotPlugin.Initialize /// diff --git a/src/Greenshot.sln b/src/Greenshot.sln index aae6365da..7013d3e41 100644 --- a/src/Greenshot.sln +++ b/src/Greenshot.sln @@ -4,19 +4,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 16.0.29728.190 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Greenshot.csproj", "{CD642BF4-D815-4D67-A0B5-C69F0B8231AF}" - ProjectSection(ProjectDependencies) = postProject - {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} = {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} - {19FEEF09-313F-43C7-819D-F1BCA782B08B} = {19FEEF09-313F-43C7-819D-F1BCA782B08B} - {9801F62C-540F-4BFE-9211-6405DEDE563B} = {9801F62C-540F-4BFE-9211-6405DEDE563B} - {9C0ECC4C-7807-4111-916A-4F57BB29788A} = {9C0ECC4C-7807-4111-916A-4F57BB29788A} - {C3052651-598A-44E2-AAB3-2E41311D50F9} = {C3052651-598A-44E2-AAB3-2E41311D50F9} - {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} = {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} - {697CF066-9077-4F22-99D9-D989CCE7282B} = {697CF066-9077-4F22-99D9-D989CCE7282B} - {47F23C86-604E-4CC3-8767-B3D4088F30BB} = {47F23C86-604E-4CC3-8767-B3D4088F30BB} - {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} = {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} - {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} = {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} - {1893A2E4-A78A-4713-A8E7-E70058DABEE0} = {1893A2E4-A78A-4713-A8E7-E70058DABEE0} - EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Base", "Greenshot.Base\Greenshot.Base.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" EndProject @@ -46,6 +33,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig ..\azure-pipelines.yml = ..\azure-pipelines.yml + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Editor", "Greenshot.Editor\Greenshot.Editor.csproj", "{148D3C8B-D6EC-4A7D-80E9-243A81F19DD2}" diff --git a/src/Greenshot/Greenshot.csproj b/src/Greenshot/Greenshot.csproj index da2c79714..757714790 100644 --- a/src/Greenshot/Greenshot.csproj +++ b/src/Greenshot/Greenshot.csproj @@ -72,7 +72,7 @@ - + diff --git a/src/Greenshot/Helpers/PluginHelper.cs b/src/Greenshot/Helpers/PluginHelper.cs index 86c4d2d2b..3ed3d97c3 100644 --- a/src/Greenshot/Helpers/PluginHelper.cs +++ b/src/Greenshot/Helpers/PluginHelper.cs @@ -22,7 +22,6 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -67,10 +66,9 @@ namespace Greenshot.Helpers { foreach (var plugin in SimpleServiceProvider.Current.GetAllInstances()) { - var pluginAttribute = plugin.GetType().GetCustomAttribute(); - var item = new ListViewItem(pluginAttribute.Name) + var item = new ListViewItem(plugin.Name) { - Tag = pluginAttribute + Tag = plugin }; var assembly = plugin.GetType().Assembly; @@ -89,8 +87,8 @@ namespace Greenshot.Helpers return false; } - var pluginAttribute = (PluginAttribute) listView.SelectedItems[0].Tag; - return pluginAttribute != null && pluginAttribute.Configurable; + var greenshotPlugin = (IGreenshotPlugin) listView.SelectedItems[0].Tag; + return greenshotPlugin?.IsConfigurable == true; } public void ConfigureSelectedItem(ListView listView) @@ -100,14 +98,15 @@ namespace Greenshot.Helpers return; } - var pluginAttribute = (PluginAttribute) listView.SelectedItems[0].Tag; - if (pluginAttribute == null) + var greenshotPlugin = (IGreenshotPlugin) listView.SelectedItems[0].Tag; + if (greenshotPlugin == null) { return; } - var plugin = SimpleServiceProvider.Current.GetAllInstances().FirstOrDefault(p => - p.GetType().GetCustomAttribute().Name == pluginAttribute.Name); + var plugin = SimpleServiceProvider.Current + .GetAllInstances() + .FirstOrDefault(p => p.Name == greenshotPlugin.Name); plugin?.Configure(); } @@ -224,12 +223,11 @@ namespace Greenshot.Helpers var pluginEntryName = $"{assemblyName}.{assemblyName.Replace("Greenshot.Plugin.", string.Empty)}Plugin"; var pluginEntryType = assembly.GetType(pluginEntryName, false, true); - var pluginAttribute = pluginEntryType.GetCustomAttribute(); - if (CoreConfig.ExcludePlugins != null && CoreConfig.ExcludePlugins.Contains(pluginAttribute.Name)) + if (CoreConfig.ExcludePlugins != null && CoreConfig.ExcludePlugins.Contains(pluginEntryName)) { Log.WarnFormat("Exclude list: {0}", string.Join(",", CoreConfig.ExcludePlugins)); - Log.WarnFormat("Skipping the excluded plugin {0} with version {1} from {2}", pluginAttribute.Name, assembly.GetName().Version, pluginFile); + Log.WarnFormat("Skipping the excluded plugin {0} with version {1} from {2}", pluginEntryName, assembly.GetName().Version, pluginFile); continue; } @@ -242,7 +240,7 @@ namespace Greenshot.Helpers } else { - Log.InfoFormat("Plugin {0} not initialized!", pluginAttribute.Name); + Log.InfoFormat("Plugin {0} not initialized!", plugin.Name); } } else From cf2d9d4148c3574ba66c8b7506ac1daebebd178b Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 19 May 2021 16:24:29 +0200 Subject: [PATCH 131/232] #314 Added additional click actions to support capture region, not satisfied with the empty editor option though --- src/Greenshot.Base/Core/Enums/ClickActions.cs | 7 ++++++- .../Configuration/EditorConfiguration.cs | 4 ++++ src/Greenshot.Editor/Forms/ImageEditorForm.cs | 17 +++++++++++++++-- src/Greenshot/Forms/MainForm.cs | 17 +++++++++++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/Greenshot.Base/Core/Enums/ClickActions.cs b/src/Greenshot.Base/Core/Enums/ClickActions.cs index 7c7fb5ee8..ef836442f 100644 --- a/src/Greenshot.Base/Core/Enums/ClickActions.cs +++ b/src/Greenshot.Base/Core/Enums/ClickActions.cs @@ -30,6 +30,11 @@ namespace Greenshot.Base.Core.Enums OPEN_LAST_IN_EXPLORER, OPEN_LAST_IN_EDITOR, OPEN_SETTINGS, - SHOW_CONTEXT_MENU + SHOW_CONTEXT_MENU, + CAPTURE_REGION, + CAPTURE_SCREEN, + CAPTURE_CLIPBOARD, + CAPTURE_WINDOW, + OPEN_EMPTY_EDITOR } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Configuration/EditorConfiguration.cs b/src/Greenshot.Editor/Configuration/EditorConfiguration.cs index 91a5bc335..c36794a5d 100644 --- a/src/Greenshot.Editor/Configuration/EditorConfiguration.cs +++ b/src/Greenshot.Editor/Configuration/EditorConfiguration.cs @@ -79,6 +79,10 @@ namespace Greenshot.Editor.Configuration [IniProperty("TornEdgeEffectSettings", Description = "Settings for the torn edge effect.")] public TornEdgeEffect TornEdgeEffectSettings { get; set; } + [IniProperty("DefaultEditorSize", Description = "The size for the editor when it's opened without a capture", DefaultValue = "500,500")] + public Size DefaultEditorSize { get; set; } + + public override void AfterLoad() { base.AfterLoad(); diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index 9fc410de4..ffbea1a8b 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; +using System.Drawing.Imaging; using System.IO; using System.Threading; using System.Windows.Forms; @@ -124,7 +125,19 @@ namespace Greenshot.Editor.Forms UpdateUi(); } - public ImageEditorForm(ISurface iSurface, bool outputMade) + public ImageEditorForm() + { + var image = ImageHelper.CreateEmpty(EditorConfiguration.DefaultEditorSize.Width, EditorConfiguration.DefaultEditorSize.Height, PixelFormat.Format32bppArgb, Color.White, 96f, 96f); + ISurface surface = new Surface(image); + Initialize(surface, false); + } + + public ImageEditorForm(ISurface surface, bool outputMade) + { + Initialize(surface, outputMade); + } + + private void Initialize(ISurface surface, bool outputMade) { EditorList.Add(this); @@ -162,7 +175,7 @@ namespace Greenshot.Editor.Forms }; // init surface - Surface = iSurface; + Surface = surface; // Initial "saved" flag for asking if the image needs to be save _surface.Modified = !outputMade; diff --git a/src/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs index b775149cb..9fcaadc97 100644 --- a/src/Greenshot/Forms/MainForm.cs +++ b/src/Greenshot/Forms/MainForm.cs @@ -1735,6 +1735,23 @@ namespace Greenshot.Forms MethodInfo oMethodInfo = typeof(NotifyIcon).GetMethod("ShowContextMenu", BindingFlags.Instance | BindingFlags.NonPublic); oMethodInfo.Invoke(notifyIcon, null); break; + case ClickActions.CAPTURE_CLIPBOARD: + CaptureHelper.CaptureClipboard(); + break; + case ClickActions.CAPTURE_REGION: + CaptureHelper.CaptureRegion(false); + break; + case ClickActions.CAPTURE_SCREEN: + CaptureHelper.CaptureFullscreen(false, ScreenCaptureMode.FullScreen); + break; + case ClickActions.CAPTURE_WINDOW: + CaptureHelper.CaptureWindowInteractive(false); + break; + case ClickActions.OPEN_EMPTY_EDITOR: + var imageEditor = new ImageEditorForm(); + imageEditor.Show(); + imageEditor.Activate(); + break; } } From 5935a435b55b9687e672d854391caec2085e3dd4 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 19 May 2021 16:35:55 +0200 Subject: [PATCH 132/232] Solving the build order by making Greenshot depending on all other projects. --- src/Greenshot.sln | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Greenshot.sln b/src/Greenshot.sln index 7013d3e41..91ddf4314 100644 --- a/src/Greenshot.sln +++ b/src/Greenshot.sln @@ -4,6 +4,19 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 16.0.29728.190 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Greenshot.csproj", "{CD642BF4-D815-4D67-A0B5-C69F0B8231AF}" + ProjectSection(ProjectDependencies) = postProject + {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} = {92599C09-FF29-4ABD-B6E6-C48ECD781BAB} + {19FEEF09-313F-43C7-819D-F1BCA782B08B} = {19FEEF09-313F-43C7-819D-F1BCA782B08B} + {9801F62C-540F-4BFE-9211-6405DEDE563B} = {9801F62C-540F-4BFE-9211-6405DEDE563B} + {9C0ECC4C-7807-4111-916A-4F57BB29788A} = {9C0ECC4C-7807-4111-916A-4F57BB29788A} + {C3052651-598A-44E2-AAB3-2E41311D50F9} = {C3052651-598A-44E2-AAB3-2E41311D50F9} + {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} = {7EC72A5A-D73A-4B4B-9CA1-2216C7D92D5E} + {697CF066-9077-4F22-99D9-D989CCE7282B} = {697CF066-9077-4F22-99D9-D989CCE7282B} + {47F23C86-604E-4CC3-8767-B3D4088F30BB} = {47F23C86-604E-4CC3-8767-B3D4088F30BB} + {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} = {80D8DEB9-94E3-4876-8CCA-2DF1ED5F2C50} + {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} = {AD7CFFE2-40E7-46CF-A172-D48CF7AE9A12} + {1893A2E4-A78A-4713-A8E7-E70058DABEE0} = {1893A2E4-A78A-4713-A8E7-E70058DABEE0} + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Base", "Greenshot.Base\Greenshot.Base.csproj", "{5B924697-4DCD-4F98-85F1-105CB84B7341}" EndProject From fa0ed4a53bd7baca7139794fc91d3195b5384e9b Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 26 May 2021 12:04:20 +0200 Subject: [PATCH 133/232] #315 made sure that with a small capture the canvas is enlarged so OCR can still work. --- .../Win10OcrProvider.cs | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs index 34c0b6c7a..77aa0d663 100644 --- a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs +++ b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs @@ -27,6 +27,8 @@ using Windows.Graphics.Imaging; using Windows.Media.Ocr; using Windows.Storage.Streams; using Greenshot.Base.Core; +using Greenshot.Base.Core.Enums; +using Greenshot.Base.Effects; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Ocr; using Greenshot.Base.Interfaces.Plugin; @@ -39,6 +41,8 @@ namespace Greenshot.Plugin.Win10 public class Win10OcrProvider : IOcrProvider { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(Win10OcrProvider)); + private const int MinWidth = 130; + private const int MinHeight = 130; /// /// Constructor, this is only debug information @@ -62,7 +66,38 @@ namespace Greenshot.Plugin.Win10 OcrInformation result; using (var imageStream = new MemoryStream()) { - ImageOutput.SaveToStream(surface, imageStream, new SurfaceOutputSettings()); + // We only want the background + var outputSettings = new SurfaceOutputSettings(OutputFormat.png, 0, true) + { + ReduceColors = true, + SaveBackgroundOnly = true + }; + // Force Grayscale output + outputSettings.Effects.Add(new GrayscaleEffect()); + if (surface.Image.Width < MinWidth || surface.Image.Height < MinHeight) + { + int addedWidth = MinWidth - surface.Image.Width; + if (addedWidth < 0) + { + addedWidth = 0; + } + else + { + addedWidth /= 2; + } + int addedHeight = MinHeight - surface.Image.Height; + if (addedHeight < 0) + { + addedHeight = 0; + } + else + { + addedHeight /= 2; + } + IEffect effect = new ResizeCanvasEffect(addedWidth, addedWidth, addedHeight, addedHeight); + outputSettings.Effects.Add(effect); + } + ImageOutput.SaveToStream(surface, imageStream, outputSettings); imageStream.Position = 0; var randomAccessStream = imageStream.AsRandomAccessStream(); From 2330d6af57d3c991c1945d28ab3f0765209b4f7e Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 27 May 2021 09:12:28 +0200 Subject: [PATCH 134/232] #258 In the settings form there was DPI scaling done on the icon size, this seems to have unfortunate side effects, so I removed this. --- src/Greenshot/Forms/SettingsForm.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Greenshot/Forms/SettingsForm.cs b/src/Greenshot/Forms/SettingsForm.cs index e236360d1..4ac354aca 100644 --- a/src/Greenshot/Forms/SettingsForm.cs +++ b/src/Greenshot/Forms/SettingsForm.cs @@ -533,8 +533,7 @@ namespace Greenshot.Forms numericUpDown_daysbetweencheck.Value = coreConfiguration.UpdateCheckInterval; numericUpDown_daysbetweencheck.Enabled = !coreConfiguration.Values["UpdateCheckInterval"].IsFixed; - var scaledIconSize = DpiHelper.ScaleWithDpi(coreConfiguration.IconSize, DpiHelper.GetDpi(Handle)); - numericUpdownIconSize.Value = scaledIconSize.Width / 16 * 16; + numericUpdownIconSize.Value = coreConfiguration.IconSize.Width; CheckDestinationSettings(); } From 99fb245537076827dafa5507b381d19006db53aa Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Fri, 28 May 2021 00:20:26 +0200 Subject: [PATCH 135/232] BUG-2786 Fixing a startup issue with Windows 7 --- src/Greenshot/Forms/MainForm.cs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs index 9fcaadc97..fa45cb04d 100644 --- a/src/Greenshot/Forms/MainForm.cs +++ b/src/Greenshot/Forms/MainForm.cs @@ -517,15 +517,25 @@ namespace Greenshot.Forms new EmailDestination(), new PickerDestination() }; + + bool useEditor = true; + if (WindowsVersion.IsWindows10OrLater) + { + int len = 250; + var stringBuilder = new StringBuilder(len); + using var proc = Process.GetCurrentProcess(); + var err = Kernel32.GetPackageFullName(proc.Handle, ref len, stringBuilder); + if (err != 0) + { + useEditor = false; + } + } - int len = 250; - var stringBuilder = new StringBuilder(len); - using var proc = Process.GetCurrentProcess(); - var err = Kernel32.GetPackageFullName(proc.Handle, ref len, stringBuilder); - if (err != 0) + if (useEditor) { internalDestinations.Add(new EditorDestination()); } + foreach (var internalDestination in internalDestinations) { if (internalDestination.IsActive) From 973cf871c85f46314328a00ad4929572fae69317 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 29 May 2021 16:06:58 +0200 Subject: [PATCH 136/232] Additional improvements for the ClickActions, now possible to open a file directly in the editor. Inspired by FEATURE-1321 --- src/Greenshot.Base/Core/Enums/ClickActions.cs | 4 +++- src/Greenshot/Forms/MainForm.cs | 21 +++++++++++++----- src/Greenshot/Helpers/CaptureHelper.cs | 22 +++++++------------ 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/Greenshot.Base/Core/Enums/ClickActions.cs b/src/Greenshot.Base/Core/Enums/ClickActions.cs index ef836442f..a4e048a4b 100644 --- a/src/Greenshot.Base/Core/Enums/ClickActions.cs +++ b/src/Greenshot.Base/Core/Enums/ClickActions.cs @@ -35,6 +35,8 @@ namespace Greenshot.Base.Core.Enums CAPTURE_SCREEN, CAPTURE_CLIPBOARD, CAPTURE_WINDOW, - OPEN_EMPTY_EDITOR + OPEN_EMPTY_EDITOR, + OPEN_FILE_IN_EDITOR, + OPEN_CLIPBOARD_IN_EDITOR } } \ No newline at end of file diff --git a/src/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs index fa45cb04d..f00174843 100644 --- a/src/Greenshot/Forms/MainForm.cs +++ b/src/Greenshot/Forms/MainForm.cs @@ -518,7 +518,7 @@ namespace Greenshot.Forms new PickerDestination() }; - bool useEditor = true; + bool useEditor = false; if (WindowsVersion.IsWindows10OrLater) { int len = 250; @@ -527,8 +527,11 @@ namespace Greenshot.Forms var err = Kernel32.GetPackageFullName(proc.Handle, ref len, stringBuilder); if (err != 0) { - useEditor = false; + useEditor = true; } + } else + { + useEditor = true; } if (useEditor) @@ -931,7 +934,7 @@ namespace Greenshot.Forms CaptureHelper.CaptureRegion(true); } - private void CaptureFile() + private void CaptureFile(IDestination destination = null) { var openFileDialog = new OpenFileDialog { @@ -944,7 +947,7 @@ namespace Greenshot.Forms if (File.Exists(openFileDialog.FileName)) { - CaptureHelper.CaptureFile(openFileDialog.FileName); + CaptureHelper.CaptureFile(openFileDialog.FileName, destination); } } @@ -1255,12 +1258,12 @@ namespace Greenshot.Forms private void CaptureClipboardToolStripMenuItemClick(object sender, EventArgs e) { - BeginInvoke((MethodInvoker) CaptureHelper.CaptureClipboard); + BeginInvoke((MethodInvoker) delegate { CaptureHelper.CaptureClipboard(); }); } private void OpenFileToolStripMenuItemClick(object sender, EventArgs e) { - BeginInvoke((MethodInvoker) CaptureFile); + BeginInvoke((MethodInvoker) delegate { CaptureFile(); }); } private void CaptureFullScreenToolStripMenuItemClick(object sender, EventArgs e) @@ -1748,6 +1751,12 @@ namespace Greenshot.Forms case ClickActions.CAPTURE_CLIPBOARD: CaptureHelper.CaptureClipboard(); break; + case ClickActions.OPEN_CLIPBOARD_IN_EDITOR: + CaptureHelper.CaptureClipboard(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); + break; + case ClickActions.OPEN_FILE_IN_EDITOR: + CaptureFile(DestinationHelper.GetDestination(EditorDestination.DESIGNATION)); + break; case ClickActions.CAPTURE_REGION: CaptureHelper.CaptureRegion(false); break; diff --git a/src/Greenshot/Helpers/CaptureHelper.cs b/src/Greenshot/Helpers/CaptureHelper.cs index c55cc2946..662f3439a 100644 --- a/src/Greenshot/Helpers/CaptureHelper.cs +++ b/src/Greenshot/Helpers/CaptureHelper.cs @@ -93,13 +93,7 @@ namespace Greenshot.Helpers } } - public static void CaptureClipboard() - { - using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Clipboard); - captureHelper.MakeCapture(); - } - - public static void CaptureClipboard(IDestination destination) + public static void CaptureClipboard(IDestination destination = null) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Clipboard); if (destination != null) @@ -173,16 +167,16 @@ namespace Greenshot.Helpers captureHelper.MakeCapture(); } - public static void CaptureFile(string filename) + public static void CaptureFile(string filename, IDestination destination = null) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.File); - captureHelper.MakeCapture(filename); - } - public static void CaptureFile(string filename, IDestination destination) - { - using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.File); - captureHelper.AddDestination(destination).MakeCapture(filename); + if (destination != null) + { + captureHelper.AddDestination(destination); + } + + captureHelper.MakeCapture(filename); } public static void ImportCapture(ICapture captureToImport) From 3350120b5536883cd1b6d7ce89d969b69f52e1b0 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Fri, 4 Jun 2021 01:00:55 +0200 Subject: [PATCH 137/232] BUG-2792: Fixed the issue that PowerToys is interacting with our region selection window. --- .../Enums/ExtendedWindowStyleFlags.cs | 41 +++++++++++++++++-- .../Enums/WindowStyleFlags.cs | 18 +++++++- src/Greenshot/Forms/CaptureForm.cs | 4 +- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs index cbd81219c..aaeb23fa9 100644 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs @@ -28,9 +28,44 @@ namespace Greenshot.Base.UnmanagedHelpers.Enums [SuppressMessage("ReSharper", "InconsistentNaming")] public enum ExtendedWindowStyleFlags : uint { - WS_EX_TOOLWINDOW = 0x00000080, + WS_EX_DLGMODALFRAME = 0x00000001, + WS_EX_NOPARENTNOTIFY = 0x00000004, + WS_EX_TOPMOST = 0x00000008, + WS_EX_ACCEPTFILES = 0x00000010, + WS_EX_TRANSPARENT = 0x00000020, - WS_EX_NOREDIRECTIONBITMAP = - 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual. + //#if(WINVER >= 0x0400) + WS_EX_MDICHILD = 0x00000040, + WS_EX_TOOLWINDOW = 0x00000080, + WS_EX_WINDOWEDGE = 0x00000100, + WS_EX_CLIENTEDGE = 0x00000200, + WS_EX_CONTEXTHELP = 0x00000400, + + WS_EX_RIGHT = 0x00001000, + WS_EX_LEFT = 0x00000000, + WS_EX_RTLREADING = 0x00002000, + WS_EX_LTRREADING = 0x00000000, + WS_EX_LEFTSCROLLBAR = 0x00004000, + WS_EX_RIGHTSCROLLBAR = 0x00000000, + + WS_EX_CONTROLPARENT = 0x00010000, + WS_EX_STATICEDGE = 0x00020000, + WS_EX_APPWINDOW = 0x00040000, + + //WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE), + //WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST), + + WS_EX_LAYERED = 0x00080000, + WS_EX_NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children + WS_EX_NOREDIRECTIONBITMAP = 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual. + WS_EX_LAYOUTRTL = 0x00400000, // Right to left mirroring + /// + /// Paints all descendants of a window in bottom-to-top painting order using double-buffering. + /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects, but only if the descendent window also has the WS_EX_TRANSPARENT bit set. + /// Double-buffering allows the window and its descendents to be painted without flicker. + /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. + /// + WS_EX_COMPOSITED = 0x02000000, + WS_EX_NOACTIVATE = 0x08000000 // A top-level window created with this style does not become the foreground window when the user clicks it. The system does not bring this window to the foreground when the user minimizes or closes the foreground window. } } \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs index 8c64ee09a..603e58196 100644 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs @@ -29,8 +29,24 @@ namespace Greenshot.Base.UnmanagedHelpers.Enums /// [Flags] [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowStyleFlags : long + public enum WindowStyleFlags : int { + //WS_OVERLAPPED = 0x00000000, + WS_POPUP = -2147483648, + WS_CHILD = 0x40000000, + WS_MINIMIZE = 0x20000000, WS_VISIBLE = 0x10000000, + WS_DISABLED = 0x08000000, + WS_CLIPSIBLINGS = 0x04000000, + WS_CLIPCHILDREN = 0x02000000, + WS_MAXIMIZE = 0x01000000, + WS_BORDER = 0x00800000, + WS_DLGFRAME = 0x00400000, + WS_VSCROLL = 0x00200000, + WS_HSCROLL = 0x00100000, + WS_SYSMENU = 0x00080000, + WS_THICKFRAME = 0x00040000, + WS_GROUP = 0x00020000, + WS_TABSTOP = 0x00010000 } } \ No newline at end of file diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs index 6176c732e..a737ba3b0 100644 --- a/src/Greenshot/Forms/CaptureForm.cs +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -36,6 +36,7 @@ using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Ocr; using Greenshot.Base.UnmanagedHelpers; +using Greenshot.Base.UnmanagedHelpers.Enums; using Greenshot.Editor.Helpers; namespace Greenshot.Forms @@ -111,7 +112,8 @@ namespace Greenshot.Forms get { CreateParams createParams = base.CreateParams; - createParams.ExStyle |= 0x02000000; + createParams.ExStyle |= (int)ExtendedWindowStyleFlags.WS_EX_COMPOSITED; + createParams.Style = (int)WindowStyleFlags.WS_POPUP; return createParams; } } From e9d1e278e6b238ab2b8ec6e0a3bd6e4dbff1088c Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 5 Jun 2021 22:27:23 +0200 Subject: [PATCH 138/232] Small update of GitVersioning [skip ci] --- src/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index f19f03423..0a4cf9e28 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -47,7 +47,7 @@ - + all runtime; build; native; contentfiles; analyzers From f71499c9c62393a1758a6f9497f23f456dd3b4e5 Mon Sep 17 00:00:00 2001 From: Ishmaeel Date: Sat, 2 Oct 2021 21:56:46 +0300 Subject: [PATCH 139/232] Fix Ellipse and Highlight duplication bug (#322). (#331) Fixes #322. Ellipse only created default adorners in constructor, never after deserialization. Having zero adorners triggered a Linq exception down the code path. Fixed by duplicating the deserialization logic from RectangleContainer. Highlight also failed to create its default adorners. Fixed by just adding a correct call to CreateDefaultAdorners call in the existing Init method. --- src/Greenshot.Editor/Drawing/EllipseContainer.cs | 12 ++++++++++++ src/Greenshot.Editor/Drawing/HighlightContainer.cs | 1 + 2 files changed, 13 insertions(+) diff --git a/src/Greenshot.Editor/Drawing/EllipseContainer.cs b/src/Greenshot.Editor/Drawing/EllipseContainer.cs index d2c854cb1..f7799ac71 100644 --- a/src/Greenshot.Editor/Drawing/EllipseContainer.cs +++ b/src/Greenshot.Editor/Drawing/EllipseContainer.cs @@ -22,6 +22,7 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using System.Runtime.Serialization; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -35,6 +36,17 @@ namespace Greenshot.Editor.Drawing public class EllipseContainer : DrawableContainer { public EllipseContainer(Surface parent) : base(parent) + { + Init(); + } + + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } + + private void Init() { CreateDefaultAdorners(); } diff --git a/src/Greenshot.Editor/Drawing/HighlightContainer.cs b/src/Greenshot.Editor/Drawing/HighlightContainer.cs index 3e104b85f..417725322 100644 --- a/src/Greenshot.Editor/Drawing/HighlightContainer.cs +++ b/src/Greenshot.Editor/Drawing/HighlightContainer.cs @@ -56,6 +56,7 @@ namespace Greenshot.Editor.Drawing { FieldChanged += HighlightContainer_OnFieldChanged; ConfigurePreparedFilters(); + CreateDefaultAdorners(); } protected void HighlightContainer_OnFieldChanged(object sender, FieldChangedEventArgs e) From 77d4db59c1925f66a72cf84270315b17c22ab700 Mon Sep 17 00:00:00 2001 From: Masv-MiR <83816788+Masv-MiR@users.noreply.github.com> Date: Sat, 2 Oct 2021 20:58:22 +0200 Subject: [PATCH 140/232] Corrected czech translation (#330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed from Ceština into Čeština. --- installer/innosetup/setup.iss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index ef2a2fc50..aa39d99fd 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -215,7 +215,7 @@ Name: startup; Description: {cm:startup} dexfranconia=Frängisch (Deutsch) arSY=العربية caCA=Català -csCZ=Ceština +csCZ=Čeština daDK=Dansk elGR=ελληνικά esES=Español From 26e4aee892e61f3a355d4e0eb58066e1ec497163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Svatopluk=20V=C3=ADt?= Date: Sat, 2 Oct 2021 20:59:40 +0200 Subject: [PATCH 141/232] Update of Czech language file (#332) * Update language-cs-CZ.xml Review of language file --- src/Greenshot/Languages/language-cs-CZ.xml | 106 +++++++++++---------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/src/Greenshot/Languages/language-cs-CZ.xml b/src/Greenshot/Languages/language-cs-CZ.xml index c34389ebf..915fd3fe0 100644 --- a/src/Greenshot/Languages/language-cs-CZ.xml +++ b/src/Greenshot/Languages/language-cs-CZ.xml @@ -1,33 +1,34 @@ - + Chyby prosím hlaste na adrese Pokud se vám Greenshot líbí, uvítáme Vaší podporu - Greenshot je hostován na sourceforge.net + Greenshot je hostován na github.com Ikony pochází ze sady Yusuke Kamiyamane's Fugue (licence Creative Commons Attribution 3.0) Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom Greenshot je ABSOLUTNĚ BEZ ZÁRUKY. Toto je svobodný software, můžete jej dále šířit za určitých podmínek. Podrobnosti o GNU General Public License: O programu Greenshot - Překlad: Zdeněk Chalupský <chalzd@gmail.com>. Korektura: Petr Toman + Překlad: Zdeněk Chalupský <chalzd@gmail.com>. Korektura: Petr Toman a Svatopluk Vít Greenshot - revoluční utilita pro snímání obrazovky Zavřít Omlouváme se, ale došlo k neočekávané chybě. + Dobrá zpráva: můžete nám pomoci odstranit chybu, když o ní podáte hlášení. Navštivte prosím níže uvedenou adresu, vytvořte nové hlášení o chybě a vložte popis chyby. Zadejte prosím smysluplné shrnutí a připojte informace, které považujete za užitečné pro popis hlášeného problému. Také bychom velmi ocenili, kdybyste zkontrolovali, zda tato chyba již není evidována. (Můžete použít rychlé vyhledávání.) Děkujeme :-) Chyba - Zrušit + Zrušit Neočekávaná chyba při zápisu do schránky. Greenshot nemohl zapsat data do schránky, je {0} blokován přístup. Obrázek ve schránce nebyl nalezen. Windows Bitmap - Zařízení Independent Bitmap (DIB) + Device Independent Bitmap (DIB) HTML HTML s vloženými obrázky - PNG + PNG Alfa Použít Modrá @@ -44,17 +45,17 @@ Také bychom velmi ocenili, kdybyste zkontrolovali, zda tato chyba již není ev Označit oblast snímání Otevřít obrázek ze schránky Zachytit celou obrazovku - vše - spodní - vlevo - vpravo - horní - Zachytávat aplikaci Internet Explorer + Vše + Spodní + Vlevo + Vpravo + Nahoře + Zachytávat aplikaci Internet Explorer Zachytit Internet Explorer ze seznamu - Zachycení poslední oblasti - Vybrat okno pro zachycení - Zachytit okno ze seznamu - Podpora pro Greenshot + Zachycení posledně snímané oblasti + Vybrat snímané okno + Snímat okno ze seznamu + Podpora Greenshotu Konec Nápověda Otevřít obrázek ze souboru @@ -70,22 +71,22 @@ Také bychom velmi ocenili, kdybyste zkontrolovali, zda tato chyba již není ev Vpravo Nahoře Vertikální zarovnání - Uspořádat + Uspořádat Tvar šipky Oba Koncový bod Žádný Počáteční bod - Automatické oříznutí + Automatické oříznutí Barva výplně Poloměr rozostření Tučné - Hranice + Okraj Jas Zrušit Chyba při přístupu do schránky. Zkuste to prosím znovu. Zavřít - Přejete si uložit snímek? + Chcete uložit snímek? Uložit snímek? Potvrdit Kopírovat obrázek do schránky @@ -99,15 +100,15 @@ Také bychom velmi ocenili, kdybyste zkontrolovali, zda tato chyba již není ev Úplně dolů Nakreslit šipku (A) Nakreslit elipsu (E) - Kreslení od ruky (F) + Kreslení od ruky (F) Zvýraznit (H) Nakreslit linku (L) Nakreslit obdélník (R) - Přidat textbox (T) + Přidat textový rámec (T) Duplikovat vybraný prvek Úpravy Efekty - E-Mail + E-mail Soubor Velikost Barva čáry @@ -120,20 +121,20 @@ Také bychom velmi ocenili, kdybyste zkontrolovali, zda tato chyba již není ev Vržený stín Obrázek uložen do {0}. Vložit okno - Invertovat - Italika + Invertovat + Skloněné Načíst objekty ze souboru Faktor zvětšení - Přizpůsobit velikosti snímku + Přizpůsobit velikosti snímku Zamlžit (O) Rozmazat Ztížení rozeznání obsahu Pixelizace Objekt - Otevřít složku v prohlížeči Windows + Otevřít složku v průzkumníkovi Windows Vložit Velikost pixelu - Náhled kvality + Kvalita náhledu Tisk Znovu {0} Obnovit velikost @@ -151,7 +152,7 @@ Také bychom velmi ocenili, kdybyste zkontrolovali, zda tato chyba již není ev Tloušťka linky Greenshot editor obrázků Potrhané okraje - Zpět {0} + Zpět {0} Nahoru o jednu úroveň Posunout úplně nahoru MAPI klient @@ -159,7 +160,7 @@ Také bychom velmi ocenili, kdybyste zkontrolovali, zda tato chyba již není ev Aplikace Outlook s prostým textem Chyba Program Greenshot je již spuštěn - Nelze uložit soubor do {0}. + Nelze uložit soubor do {0}. Zkontrolujte prosím dostupnost vybraného cíle. Soubor "{0}" nelze otevřít. Nelze otevřít odkaz. @@ -167,7 +168,7 @@ Zkontrolujte prosím dostupnost vybraného cíle. Vygenerovaný název souboru nebo složky není platný. Opravte prosím vzor názvu a zkuste to znovu. Expert Vytvořit 8bitový obrázek, pokud má méně než 256 barev - Kontrolovat nestabilní aktualizace + Kontrolovat aktualizace nestabilních verzí Formáty schránky Číslo pro ${NUM} ve vzoru pro název souboru Vím, co dělám! @@ -177,12 +178,12 @@ Zkontrolujte prosím dostupnost vybraného cíle. Znovu použít editor, je-li to možné Potlačit dialog Uložit při zavírání editoru Zobrazovat miniatury oken v kontextové nabídce (pro Vista a Windows 7) - Exportovat do: {0} + Exportovat do: {0} Došlo k chybě při exportu do{0}: Nápověda Greenshot - Klávesové zkratky - Vyberte nastavení kvality obrázku v JPEG formátu - Ok + Klávesové zkratky + Nastavte kvalitu obrázku v JPEG formátu + Ok Nastala chyba při pokusu o tisk. Centrovat obrázek na stránce Zvětšit oblast tisku, aby odpovídala velikosti papíru @@ -213,15 +214,15 @@ Zkontrolujte prosím dostupnost vybraného cíle. Cíl snímku Kopírovat do schránky Otevřít v editoru obrázků - E-Mail + E-mail Uložit přímo (pomocí nastavení níže) Uložit jako (zobrazit dialog) Vybrat cíl dynamicky Odeslat na tiskárnu - Editor + Editor Vzor pro název souboru Obecné - Snímek aplikace Internet Explorer + Snímek aplikace Internet Explorer Kvalita JPEG Jazyk Následující symboly budou automaticky nahrazeny: @@ -232,17 +233,20 @@ ${hh} hodina, 2 číslice ${mm} minuta, 2 číslice ${ss} sekunda, 2 číslice ${NUM} počítadlo, 6 číslic +${RRR...} náhodný alfanumerický znak, délka dle počtu použitých znaků R ${title} titulek okna ${user} uživatel Windows -${domain} doména Windows +${domain} doména Windows ${hostname} název počítače Složky také můžete vytvářet dynamicky pomocí zpětného lomítka (symbol \). -Například: ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} vytvoří ve výchozím úložišti složku pro dnešní den, např. 2008-06-29, a název souboru snímku bude odvozen od aktuálního času, např. 11_58_32 (plus rozšíření uvedené v nastavení). - Síť a aktualizace +Například: ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} +vytvoří ve výchozím úložišti složku pro dnešní den, např. 2008-06-29, a název souboru snímku bude odvozen od aktuálního času, +např. 11_58_32 (plus rozšíření uvedené v nastavení). + Síť a aktualizace Výstup - Přehrát zvuk uzávěrky fotoaparátu - Pluginy + Přehrát zvuk závěrky fotoaparátu + Zásuvné moduly Autor Cesta k DLL Název @@ -252,10 +256,10 @@ Například: ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} vytvoří ve výchozím úlo Tisk Možnosti tisku Nastavení kvality - Snížit počet barev na maximálně 256 + Snížit počet barev na maximálně 256 Registrovat klávesové zkratky Použít blesk - Zobrazovat upozornění + Zobrazovat upozornění Zobrazit lupu Cíl Nastavení @@ -264,14 +268,14 @@ Například: ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} vytvoří ve výchozím úlo Výchozí formát obrázku Definuje klávesové zkratky Prnt, Ctrl + Print, Alt + Prnt, které jsou vyhrazeny pro globální použití od startu do ukončení Greenshotu. Výchozí místo pro uložení snímků (ponechte prázdné pro uložení do počítače) - Použít výchozí systémovou proxy + Použít výchozí systémovou proxy Efekty Před zachycením počkat daný počet milisekund Režim zachycování okna - Snímek okna + Snímek okna Klikněte pravým tlačítkem myši nebo stiskněte klávesu PrtSc. - K dispozici je novější verze Greenshot! Přejete si stáhnout Greenshot {0}? - Počkejte prosím než bude zachycena stránka v aplikaci Internet Explorer... + K dispozici je novější verze aplikace Greenshot! Přejete si stáhnout Greenshot {0}? + Počkejte prosím než bude zachycena stránka v aplikaci Internet Explorer... Upozornění Klávesovou(é) zkratku(y) "{0}" nelze použít. Tento problém je pravděpodobně způsoben jiným programem používajícím tytéž klávesové zkratky! Můžete změnit nastavení klávesových zkratek, deaktivovat je nebo změnit nastavení softwaru využívajícího shodné klávesové zkratky. @@ -281,7 +285,7 @@ Všechny funkce Greenshotu jsou stále dostupné přímo z místní nabídky bez Automaticky Použít výchozí barvu Jak je zobrazeno - + Intenzita stínu Vyrovnání stínu @@ -298,7 +302,7 @@ Všechny funkce Greenshotu jsou stále dostupné přímo z místní nabídky bez Horní strana Dolní strana Vytvořit stín - + Přidat počítadlo (I) Přidat textovou bublinu (S) From a7c3b8579b1ecf6902f0f6c801c469034ceba64d Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 4 Oct 2021 20:38:45 +0200 Subject: [PATCH 142/232] Dependency updates --- src/Directory.Build.props | 2 +- src/Greenshot.Base/Core/CoreConfiguration.cs | 5 ----- src/Greenshot.Base/Greenshot.Base.csproj | 6 ++--- src/Greenshot.Base/IniFile/IniConfig.cs | 2 +- .../Greenshot.Plugin.Win10.csproj | 2 +- src/Greenshot/Forms/MainForm.Designer.cs | 4 ++-- src/Greenshot/Forms/MainForm.cs | 22 ++++++++++++++----- src/Greenshot/Greenshot.csproj | 2 +- 8 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 0a4cf9e28..76a173ee5 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -47,7 +47,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/src/Greenshot.Base/Core/CoreConfiguration.cs b/src/Greenshot.Base/Core/CoreConfiguration.cs index 9c1fbd913..3b3484afc 100644 --- a/src/Greenshot.Base/Core/CoreConfiguration.cs +++ b/src/Greenshot.Base/Core/CoreConfiguration.cs @@ -559,11 +559,6 @@ namespace Greenshot.Base.Core { ExcludeDestinations.Remove("OneNote"); } - else - { - // TODO: Remove with the release - ExcludeDestinations.Remove("OneNote"); - } } if (OutputDestinations == null) diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index c0bb88aff..1726e831e 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -5,10 +5,10 @@ - - + + - + diff --git a/src/Greenshot.Base/IniFile/IniConfig.cs b/src/Greenshot.Base/IniFile/IniConfig.cs index 08bcd1217..cbe04e11b 100644 --- a/src/Greenshot.Base/IniFile/IniConfig.cs +++ b/src/Greenshot.Base/IniFile/IniConfig.cs @@ -137,7 +137,7 @@ namespace Greenshot.Base.IniFile { AssemblyProductAttribute[] assemblyProductAttributes = Assembly.GetEntryAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false) as AssemblyProductAttribute[]; - if (assemblyProductAttributes != null && assemblyProductAttributes.Length > 0) + if (assemblyProductAttributes is { Length: > 0 }) { string productName = assemblyProductAttributes[0].Product; Log.InfoFormat("Using ProductName {0}", productName); diff --git a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj index 349b4d79e..b7e629dd1 100644 --- a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj +++ b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Greenshot/Forms/MainForm.Designer.cs b/src/Greenshot/Forms/MainForm.Designer.cs index eed646231..015e0060b 100644 --- a/src/Greenshot/Forms/MainForm.Designer.cs +++ b/src/Greenshot/Forms/MainForm.Designer.cs @@ -223,7 +223,7 @@ namespace Greenshot.Forms { this.contextmenu_help.Image = ((System.Drawing.Image)(resources.GetObject("contextmenu_help.Image"))); this.contextmenu_help.Name = "contextmenu_help"; this.contextmenu_help.Size = new System.Drawing.Size(170, 22); - this.contextmenu_help.Click += new System.EventHandler(this.Contextmenu_helpClick); + this.contextmenu_help.Click += new System.EventHandler(this.Contextmenu_HelpClick); // // contextmenu_donate // @@ -248,7 +248,7 @@ namespace Greenshot.Forms { this.contextmenu_exit.Image = ((System.Drawing.Image)(resources.GetObject("contextmenu_exit.Image"))); this.contextmenu_exit.Name = "contextmenu_exit"; this.contextmenu_exit.Size = new System.Drawing.Size(170, 22); - this.contextmenu_exit.Click += new System.EventHandler(this.Contextmenu_exitClick); + this.contextmenu_exit.Click += new System.EventHandler(this.Contextmenu_ExitClick); // // notifyIcon // diff --git a/src/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs index f00174843..f1c4f8bbc 100644 --- a/src/Greenshot/Forms/MainForm.cs +++ b/src/Greenshot/Forms/MainForm.cs @@ -1122,12 +1122,18 @@ namespace Greenshot.Forms Rectangle allScreensBounds = WindowCapture.GetScreenBounds(); var captureScreenItem = new ToolStripMenuItem(Language.GetString(LangKey.contextmenu_capturefullscreen_all)); - captureScreenItem.Click += delegate { BeginInvoke((MethodInvoker) delegate { CaptureHelper.CaptureFullscreen(false, ScreenCaptureMode.FullScreen); }); }; + captureScreenItem.Click += delegate { + BeginInvoke((MethodInvoker) delegate { + CaptureHelper.CaptureFullscreen(false, ScreenCaptureMode.FullScreen); + }); + }; + captureScreenMenuItem.DropDownItems.Add(captureScreenItem); foreach (Screen screen in Screen.AllScreens) { Screen screenToCapture = screen; - string deviceAlignment = string.Empty; + string deviceAlignment = screenToCapture.DeviceName; + if (screen.Bounds.Top == allScreensBounds.Top && screen.Bounds.Bottom != allScreensBounds.Bottom) { deviceAlignment += " " + Language.GetString(LangKey.contextmenu_capturefullscreen_top); @@ -1147,7 +1153,13 @@ namespace Greenshot.Forms } captureScreenItem = new ToolStripMenuItem(deviceAlignment); - captureScreenItem.Click += delegate { BeginInvoke((MethodInvoker) delegate { CaptureHelper.CaptureRegion(false, screenToCapture.Bounds); }); }; + captureScreenItem.Click += delegate + { + BeginInvoke((MethodInvoker) delegate + { + CaptureHelper.CaptureRegion(false, screenToCapture.Bounds); + }); + }; captureScreenMenuItem.DropDownItems.Add(captureScreenItem); } } @@ -1426,7 +1438,7 @@ namespace Greenshot.Forms /// /// /// - private void Contextmenu_helpClick(object sender, EventArgs e) + private void Contextmenu_HelpClick(object sender, EventArgs e) { HelpFileLoader.LoadHelp(); } @@ -1436,7 +1448,7 @@ namespace Greenshot.Forms /// /// /// - private void Contextmenu_exitClick(object sender, EventArgs e) + private void Contextmenu_ExitClick(object sender, EventArgs e) { Exit(); } diff --git a/src/Greenshot/Greenshot.csproj b/src/Greenshot/Greenshot.csproj index 757714790..78fa3f6c6 100644 --- a/src/Greenshot/Greenshot.csproj +++ b/src/Greenshot/Greenshot.csproj @@ -17,7 +17,7 @@ - + From 7839fe5e2f9b22ee4b12c7017a7d866dbf0c0bd5 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 4 Oct 2021 21:07:05 +0200 Subject: [PATCH 143/232] Security fix for SUPPORT-407, used quotes for the path --- installer/innosetup/setup.iss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index aa39d99fd..449cf2014 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -169,20 +169,20 @@ Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#Ex ; Create the startup entries if requested to do so ; HKEY_LOCAL_USER - for current user only -Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: users-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: IsRegularUser +Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: """{app}\{#ExeName}.exe"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: IsRegularUser ; HKEY_LOCAL_MACHINE - for all users when admin -Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: {app}\{#ExeName}.exe; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: not IsRegularUser +Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: """{app}\{#ExeName}.exe"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: not IsRegularUser ; Register our own filetype for all users ; HKEY_LOCAL_USER - for current user only Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser -Root: HKCU; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser +Root: HKCU; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE,0"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser Root: HKCU; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser ; HKEY_LOCAL_MACHINE - for all users when admin Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser -Root: HKLM; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: "{app}\Greenshot.EXE,0"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser +Root: HKLM; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE,0"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser Root: HKLM; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser [Icons] From e06c3e8510674dc042d2819c5b286fb9f803aea0 Mon Sep 17 00:00:00 2001 From: Eric Cogen Date: Wed, 13 Oct 2021 02:18:13 -0400 Subject: [PATCH 144/232] FEATURE-1196 (#339) * FEATURE-1196: Double clicking on the colour square chooses the color and closes the color window * BUG-2565: Tooltip on recent colors is not representing the color. --- .../Controls/GreenshotDoubleClickButton.cs | 12 +++++++++ src/Greenshot.Editor/Forms/ColorDialog.cs | 27 ++++++++++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 src/Greenshot.Base/Controls/GreenshotDoubleClickButton.cs diff --git a/src/Greenshot.Base/Controls/GreenshotDoubleClickButton.cs b/src/Greenshot.Base/Controls/GreenshotDoubleClickButton.cs new file mode 100644 index 000000000..a70fff93c --- /dev/null +++ b/src/Greenshot.Base/Controls/GreenshotDoubleClickButton.cs @@ -0,0 +1,12 @@ +using System.Windows.Forms; + +namespace Greenshot.Base.Controls +{ + public class GreenshotDoubleClickButton : Button + { + public GreenshotDoubleClickButton() + { + SetStyle(ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, true); + } + } +} diff --git a/src/Greenshot.Editor/Forms/ColorDialog.cs b/src/Greenshot.Editor/Forms/ColorDialog.cs index 50211782f..ce8dd4b4c 100644 --- a/src/Greenshot.Editor/Forms/ColorDialog.cs +++ b/src/Greenshot.Editor/Forms/ColorDialog.cs @@ -21,10 +21,12 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.Globalization; using System.Threading; using System.Windows.Forms; +using Greenshot.Base.Controls; using Greenshot.Base.IniFile; using Greenshot.Editor.Configuration; using Greenshot.Editor.Controls; @@ -114,7 +116,7 @@ namespace Greenshot.Editor.Forms private Button CreateColorButton(Color color, int x, int y, int w, int h) { - Button b = new Button + Button b = new GreenshotDoubleClickButton { BackColor = color, FlatStyle = FlatStyle.Flat, @@ -124,10 +126,17 @@ namespace Greenshot.Editor.Forms }; b.FlatAppearance.BorderSize = 0; b.Click += ColorButtonClick; - _toolTip.SetToolTip(b, ColorTranslator.ToHtml(color) + " | R:" + color.R + ", G:" + color.G + ", B:" + color.B); + b.DoubleClick += ColorButtonDoubleClick; + SetButtonTooltip(b, color); return b; } + private void ColorButtonDoubleClick(object sender, EventArgs e) + { + ColorButtonClick(sender, e); + BtnApplyClick(sender, e); + } + private void CreateLastUsedColorButtonRow(int x, int y, int w, int h) { for (int i = 0; i < 12; i++) @@ -147,6 +156,7 @@ namespace Greenshot.Editor.Forms { _recentColorButtons[i].BackColor = EditorConfig.RecentColors[i]; _recentColorButtons[i].Enabled = true; + SetButtonTooltip(_recentColorButtons[i], EditorConfig.RecentColors[i]); } } @@ -189,7 +199,7 @@ namespace Greenshot.Editor.Forms return; } - TextBox textBox = (TextBox) sender; + TextBox textBox = (TextBox)sender; string text = textBox.Text.Replace("#", string.Empty); Color c; if (int.TryParse(text, NumberStyles.AllowHexSpecifier, Thread.CurrentThread.CurrentCulture, out var i)) @@ -200,7 +210,7 @@ namespace Greenshot.Editor.Forms { try { - var knownColor = (KnownColor) Enum.Parse(typeof(KnownColor), text, true); + var knownColor = (KnownColor)Enum.Parse(typeof(KnownColor), text, true); c = Color.FromKnownColor(knownColor); } catch (Exception) @@ -220,7 +230,7 @@ namespace Greenshot.Editor.Forms return; } - TextBox textBox = (TextBox) sender; + TextBox textBox = (TextBox)sender; PreviewColor( Color.FromArgb(GetColorPartIntFromString(textBoxAlpha.Text), GetColorPartIntFromString(textBoxRed.Text), GetColorPartIntFromString(textBoxGreen.Text), GetColorPartIntFromString(textBoxBlue.Text)), textBox); @@ -241,10 +251,15 @@ namespace Greenshot.Editor.Forms private void ColorButtonClick(object sender, EventArgs e) { - Button b = (Button) sender; + Button b = (Button)sender; PreviewColor(b.BackColor, b); } + private void SetButtonTooltip(Button colorButton, Color color) + { + _toolTip.SetToolTip(colorButton, ColorTranslator.ToHtml(color) + " | R:" + color.R + ", G:" + color.G + ", B:" + color.B); + } + private void BtnTransparentClick(object sender, EventArgs e) { ColorButtonClick(sender, e); From 7557041fe67a5168f6e18ca2a5bd2ef7f726c316 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 13 Oct 2021 09:47:32 +0200 Subject: [PATCH 145/232] Fixed a small build warning, about the license url. --- src/Directory.Build.props | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 76a173ee5..9061c877b 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -6,8 +6,7 @@ https://github.com/greenshot/greenshot git https://github.com/greenshot/greenshot - https://www.gnu.org/licenses/gpl.html - GPL + GPL-3.0-only 9 true true From caeaf12d1f043a5a6490aafecf5946f0d729fa56 Mon Sep 17 00:00:00 2001 From: SiderealArt Date: Sun, 17 Oct 2021 04:11:02 +0800 Subject: [PATCH 146/232] Add Traditional Chinese to website and installer (#343) * Add Traditional Chinese to website * Create language-installer-zh-TW.xml --- .../installer/language-installer-zh-TW.xml | 14 ++++++++++++++ .../website/language-website-zh-TW.xml | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/Greenshot/Languages/installer/language-installer-zh-TW.xml create mode 100644 src/Greenshot/Languages/website/language-website-zh-TW.xml diff --git a/src/Greenshot/Languages/installer/language-installer-zh-TW.xml b/src/Greenshot/Languages/installer/language-installer-zh-TW.xml new file mode 100644 index 000000000..3ab339773 --- /dev/null +++ b/src/Greenshot/Languages/installer/language-installer-zh-TW.xml @@ -0,0 +1,14 @@ + + + + 讓 {#ExeName} 隨 Windows 自動啟動 + 啟動 {#ExeName} + Jira 擴充功能 + Confluence 擴充功能 + 使用外部指令擴充功能開啟 + OCR 擴充功能 (需要 Microsoft Office Document Imaging (MODI)) + Imgur 擴充功能 (請見:https://imgur.com) + 其他語言 + 正在最佳化性能,這可能需要一點時間。 + + diff --git a/src/Greenshot/Languages/website/language-website-zh-TW.xml b/src/Greenshot/Languages/website/language-website-zh-TW.xml new file mode 100644 index 000000000..f0427212a --- /dev/null +++ b/src/Greenshot/Languages/website/language-website-zh-TW.xml @@ -0,0 +1,19 @@ + + + + 下載 + Greenshot - 為生產力最佳化的免費截圖工具 + Greenshot 免費且開源 + 如果 Greenshot 為您節省了許多時間和/或金錢,歡迎 <a href="/support/">贊助</a> Greenshot 的開發。 + Greenshot 採用 <a href="https://zh.wikipedia.org/zh-tw/GNU通用公共许可证" target="_blank">GPL</a> 授權,這表示該軟體能夠免費下載使用,即使是在商業環境中。 + 想要了解更多嗎? + Greenshot 當然不只有這些功能而已。看看 Greenshot 的 <a title="Screenshots of Greenshot in action" href="/screenshots/">使用截圖</a>,或者試試 <a title="下載 Greenshot 的最新版本" href="/downloads/">Greenshot 的最新版本</a>。 + 什麼是 Greenshot???? + 快速擷取指定區域、視窗、或是全螢幕;您甚至可以在 Internet Explorer 中完整擷取整個網頁。 + 輕鬆地在截圖上作註解、醒目提示、及模糊區域。 + Greenshot 是輕量化的截圖軟體,專為 Windows 設計,並有以下重點功能: + ...還有更多功能幫助您簡化截圖流程。 + 以多種方式匯出截圖:儲存成檔案,傳送至印表機、複製到剪貼簿、作為附件傳送、傳送至 Office 程式、或是上傳到網路相簿,像是 Flickr 或 Picasa...等。 + 容易上手,又能客製化,對於專案經理、軟體開發者、技術寫作人員、測試人員以及其他需要經常截圖的工作者來說,Greenshot 絕對是幫助他們提升效率的好工具。 + + From 8958401a7c4cd683639e79b1fb6b4ab153770c64 Mon Sep 17 00:00:00 2001 From: SiderealArt Date: Sun, 17 Oct 2021 04:11:24 +0800 Subject: [PATCH 147/232] fix typo (#344) --- src/Greenshot/Languages/website/language-website-en-US.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Greenshot/Languages/website/language-website-en-US.xml b/src/Greenshot/Languages/website/language-website-en-US.xml index 45267679b..3920492ef 100644 --- a/src/Greenshot/Languages/website/language-website-en-US.xml +++ b/src/Greenshot/Languages/website/language-website-en-US.xml @@ -12,8 +12,8 @@ Quickly create screenshots of a selected region, window or fullscreen; you can even capture complete (scrolling) web pages from Internet Explorer. Easily annotate, highlight or obfuscate parts of the screenshot. Greenshot is a light-weight screenshot software tool for Windows with the following key features: - ...and a lot more options simplyfying creation of and work with screenshots every day. + ...and a lot more options simplifying creation of and work with screenshots every day. Export the screenshot in various ways: save to file, send to printer, copy to clipboard, attach to e-mail, send Office programs or upload to photo sites like Flickr or Picasa, and others. Being easy to understand and configurable, Greenshot is an efficient tool for project managers, software developers, technical writers, testers and anyone else creating screenshots. - \ No newline at end of file + From 5ba390abf0b3d28b72ba1b18380ef63b7fc36e53 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 16 Oct 2021 22:32:38 +0200 Subject: [PATCH 148/232] Fixed #335 --- src/Greenshot.Editor/Forms/ImageEditorForm.cs | 2 +- .../Memento/SurfaceBackgroundChangeMemento.cs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index ffbea1a8b..e3b65b980 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -995,7 +995,7 @@ namespace Greenshot.Editor.Forms case Keys.G: // Grayscale Ctrl + G GrayscaleToolStripMenuItemClick(sender, e); break; - case Keys.Delete: // Grayscale Ctrl + Delete + case Keys.Delete: // Clear capture, use transparent background Ctrl + Delete ClearToolStripMenuItemClick(sender, e); break; case Keys.Oemcomma: // Rotate CCW Ctrl + , diff --git a/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs b/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs index 8bb9c229c..71d2e9f36 100644 --- a/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs +++ b/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs @@ -39,9 +39,12 @@ namespace Greenshot.Editor.Memento { _surface = surface; _image = surface.Image; - _matrix = matrix.Clone(); - // Make sure the reverse is applied - _matrix.Invert(); + if (matrix != null) + { + _matrix = matrix.Clone(); + // Make sure the reverse is applied + _matrix.Invert(); + } } public void Dispose() From b37b123e8eb62c0bc5745cc7b9b4053dc6491e80 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 16 Oct 2021 23:06:25 +0200 Subject: [PATCH 149/232] Fixed an issue which was introduced by renaming the assemblies, the confluence icon could not be found. --- src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs index 7f7a90f62..ddcb66530 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs @@ -51,7 +51,7 @@ namespace Greenshot.Plugin.Confluence IsInitialized = false; try { - Uri confluenceIconUri = new Uri("/GreenshotConfluencePlugin;component/Images/Confluence.ico", UriKind.Relative); + Uri confluenceIconUri = new Uri("/Greenshot.Plugin.Confluence;component/Images/Confluence.ico", UriKind.Relative); using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream) { // TODO: Check what to do with the IImage From ce56ee1cb6eaeab303907a89a6704af58e4c9619 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 16 Oct 2021 23:07:22 +0200 Subject: [PATCH 150/232] With #321 it as reported that the reload functionality didn't work, there was actually a bug in the code replacing the values. --- src/Greenshot.Base/IniFile/IniSection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Greenshot.Base/IniFile/IniSection.cs b/src/Greenshot.Base/IniFile/IniSection.cs index a55ffe504..73a02ee1e 100644 --- a/src/Greenshot.Base/IniFile/IniSection.cs +++ b/src/Greenshot.Base/IniFile/IniSection.cs @@ -143,7 +143,7 @@ namespace Greenshot.Base.IniFile IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute) fieldInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; if (!Values.ContainsKey(iniPropertyAttribute.Name)) { - Values.Add(iniPropertyAttribute.Name, new IniValue(this, fieldInfo, iniPropertyAttribute)); + Values[iniPropertyAttribute.Name] = new IniValue(this, fieldInfo, iniPropertyAttribute); } } } @@ -155,7 +155,7 @@ namespace Greenshot.Base.IniFile if (!Values.ContainsKey(propertyInfo.Name)) { IniPropertyAttribute iniPropertyAttribute = (IniPropertyAttribute) propertyInfo.GetCustomAttributes(typeof(IniPropertyAttribute), false)[0]; - Values.Add(iniPropertyAttribute.Name, new IniValue(this, propertyInfo, iniPropertyAttribute)); + Values[iniPropertyAttribute.Name] = new IniValue(this, propertyInfo, iniPropertyAttribute); } } } From 24d4e926ad657d12c41709563db26c3983eea4b7 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 1 Nov 2021 19:02:18 +0100 Subject: [PATCH 151/232] Fix for BUG-2851, Windows 7 doesn't have the used API yet. --- src/Greenshot.Base/Core/DpiHelper.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Greenshot.Base/Core/DpiHelper.cs b/src/Greenshot.Base/Core/DpiHelper.cs index a9cbe9a34..d3c7e61b6 100644 --- a/src/Greenshot.Base/Core/DpiHelper.cs +++ b/src/Greenshot.Base/Core/DpiHelper.cs @@ -114,6 +114,10 @@ namespace Greenshot.Base.Core /// uint public static uint GetDpi(POINT location) { + if (!WindowsVersion.IsWindows81OrLater) + { + return DefaultScreenDpi; + } RECT rect = new RECT(location.X, location.Y, 1, 1); IntPtr hMonitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONEAREST); var result = GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY); @@ -172,7 +176,7 @@ namespace Greenshot.Base.Core /// /// IntPtr /// uint with dpi - [DllImport("User32.dll")] + [DllImport("user32.dll")] private static extern uint GetDpiForWindow(IntPtr hWnd); /// @@ -193,7 +197,7 @@ namespace Greenshot.Base.Core /// Returns the system DPI. /// /// uint with the system DPI - [DllImport("User32.dll")] + [DllImport("user32.dll")] private static extern uint GetDpiForSystem(); } } \ No newline at end of file From 82b37bcaa4b051313dbe28cab84863fc0c048dd5 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 16 Dec 2021 10:59:20 +0100 Subject: [PATCH 152/232] Updated dependencies and added a log entry to help troubleshooting #320 --- src/Directory.Build.props | 4 ++-- src/Greenshot.Base/Greenshot.Base.csproj | 4 ++-- src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj | 4 ++-- src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj | 2 +- src/Greenshot/Forms/CaptureForm.cs | 1 + 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 9061c877b..2c8fc1892 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -46,11 +46,11 @@ - + all runtime; build; native; contentfiles; analyzers - + diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index 1726e831e..d6702cc92 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -6,8 +6,8 @@ - - + + diff --git a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj index a39835600..3b0407fce 100644 --- a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj +++ b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj @@ -6,7 +6,7 @@ - - + + \ No newline at end of file diff --git a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj index b7e629dd1..c1c1729e0 100644 --- a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj +++ b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs index a737ba3b0..6c14fdf16 100644 --- a/src/Greenshot/Forms/CaptureForm.cs +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -188,6 +188,7 @@ namespace Greenshot.Forms // Set the zoomer animation InitializeZoomer(Conf.ZoomerEnabled); + Log.DebugFormat("Opening CaptureForm with dimensions {0}", capture.ScreenBounds); SuspendLayout(); Bounds = capture.ScreenBounds; ResumeLayout(); From 6622bec15818f49a790b6bb85b5dcf22bd9a309f Mon Sep 17 00:00:00 2001 From: Laurent Eriksen <92094519+laurent-eriksen-loepfe@users.noreply.github.com> Date: Sun, 16 Jan 2022 16:17:50 +0100 Subject: [PATCH 153/232] Update README.md (#351) Change 'planed' to 'planned' source: https://wikidiff.com/planed/planned --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c43544eec..1f47983e3 100644 --- a/README.md +++ b/README.md @@ -21,4 +21,4 @@ Being easy to understand and configurable, Greenshot is an efficient tool for pr About this repository --------------------- -This repository is for Greenshot 1.3, currently in development, but is the next planed release +This repository is for Greenshot 1.3, currently in development, but is the next planned release From a498a80fb8059436fc705a10d444f1db37e09d66 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 23 Jan 2022 01:03:31 +0100 Subject: [PATCH 154/232] Small stability improvemnt [skip ci] --- src/Greenshot.Base/Core/EnvironmentInfo.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Greenshot.Base/Core/EnvironmentInfo.cs b/src/Greenshot.Base/Core/EnvironmentInfo.cs index 6bf0adc01..3452180fa 100644 --- a/src/Greenshot.Base/Core/EnvironmentInfo.cs +++ b/src/Greenshot.Base/Core/EnvironmentInfo.cs @@ -68,7 +68,15 @@ namespace Greenshot.Base.Core if (!string.IsNullOrEmpty(assemblyFileVersionAttribute?.Version)) { var assemblyFileVersion = new Version(assemblyFileVersionAttribute.Version); - greenshotVersion = assemblyFileVersion.ToString(3); + greenshotVersion = assemblyFileVersion.ToString(2); + try + { + greenshotVersion = assemblyFileVersion.ToString(3); + } + catch (Exception ex) + { + // Ignore + } } if (!shortVersion) From d57fe900e53ed1e972f396a4ec4adb9676c1976a Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 24 Jan 2022 23:32:30 +0100 Subject: [PATCH 155/232] Trying out a workaround for the Slack issue, the capture form will be resized back to the desired size. --- src/Greenshot/Forms/CaptureForm.cs | 34 +++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs index 6c14fdf16..7be9c8d6a 100644 --- a/src/Greenshot/Forms/CaptureForm.cs +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -153,12 +153,9 @@ namespace Greenshot.Forms _currentForm = this; - // Enable the AnimatingForm - EnableAnimation = true; - // clean up FormClosed += ClosedHandler; - + Resize += CaptureForm_Resize; _capture = capture; _windows = windows; _captureMode = capture.CaptureDetails.CaptureMode; @@ -171,6 +168,8 @@ namespace Greenshot.Forms DoubleBuffered = !IsTerminalServerSession; Text = @"Greenshot capture form"; + SetSize(); + // Make sure we never capture the capture-form WindowDetails.RegisterIgnoreHandle(Handle); // Un-register at close @@ -188,9 +187,27 @@ namespace Greenshot.Forms // Set the zoomer animation InitializeZoomer(Conf.ZoomerEnabled); - Log.DebugFormat("Opening CaptureForm with dimensions {0}", capture.ScreenBounds); + // Enable the AnimatingForm + EnableAnimation = true; + } + + private void CaptureForm_Resize(object sender, EventArgs e) + { + Log.DebugFormat("Resize was called, new size: {0}", this.Bounds); + if (Bounds.Equals(_capture.ScreenBounds)) + { + // We have the correct size + return; + } + // Initiate resize + SetSize(); + } + + private void SetSize() + { + Log.DebugFormat("Setting CaptureForm with dimensions {0}", _capture.ScreenBounds); SuspendLayout(); - Bounds = capture.ScreenBounds; + Bounds = _capture.ScreenBounds; ResumeLayout(); // Fix missing focus @@ -203,15 +220,16 @@ namespace Greenshot.Forms /// private void InitializeZoomer(bool isOn) { + var startingPosition = new Rectangle(_cursorPos, Size.Empty); if (isOn) { // Initialize the zoom with a invalid position - _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut); + _zoomAnimator = new RectangleAnimator( startingPosition , new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut); VerifyZoomAnimation(_cursorPos, false); } else { - _zoomAnimator?.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), FramesForMillis(1000)); + _zoomAnimator?.ChangeDestination(startingPosition, FramesForMillis(1000)); } } From fda0cd9555c94b8d7c0ed14f90cb7905c704b614 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 25 Jan 2022 10:40:36 +0100 Subject: [PATCH 156/232] Added a way to test for Windows 11. --- src/Greenshot.Base/Core/WindowsVersion.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Greenshot.Base/Core/WindowsVersion.cs b/src/Greenshot.Base/Core/WindowsVersion.cs index bf3af14ce..ca9e96d47 100644 --- a/src/Greenshot.Base/Core/WindowsVersion.cs +++ b/src/Greenshot.Base/Core/WindowsVersion.cs @@ -21,6 +21,12 @@ namespace Greenshot.Base.Core /// true if we are running on Windows 10 public static bool IsWindows10 { get; } = WinVersion.Major == 10; + /// + /// Test if the current OS is Windows 11 or later + /// + /// true if we are running on Windows 11 or later + public static bool IsWindows11OrLater { get; } = WinVersion.Major == 10 && WinVersion.Build >= 22000; + /// /// Test if the current OS is Windows 10 or later /// From 46a302f5e83b05e82661530dbded3fc78782f732 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 25 Jan 2022 10:45:38 +0100 Subject: [PATCH 157/232] This adds a workaround for #348, removing the usage of the DIB format and replace it with BITMAP. This might break transparency for some applications, but it's not used much in Windows 11 yet. --- src/Greenshot.Base/Core/CoreConfiguration.cs | 33 +++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/Greenshot.Base/Core/CoreConfiguration.cs b/src/Greenshot.Base/Core/CoreConfiguration.cs index 3b3484afc..4776a3985 100644 --- a/src/Greenshot.Base/Core/CoreConfiguration.cs +++ b/src/Greenshot.Base/Core/CoreConfiguration.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; +using System.Linq; using System.Reflection; using System.Windows.Forms; using Greenshot.Base.Core.Enums; @@ -386,7 +387,7 @@ namespace Greenshot.Base.Core /// public bool IsExperimentalFeatureEnabled(string experimentalFeature) { - return (ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature)); + return ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature); } /// @@ -398,17 +399,17 @@ namespace Greenshot.Base.Core { switch (property) { - case "PluginWhitelist": - case "PluginBacklist": + case nameof(ExcludePlugins): + case nameof(IncludePlugins): return new List(); - case "OutputFileAsFullpath": + case nameof(OutputFileAsFullpath): if (IniConfig.IsPortable) { return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png"); } return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "dummy.png"); - case "OutputFilePath": + case nameof(OutputFilePath): if (IniConfig.IsPortable) { string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots"); @@ -432,16 +433,16 @@ namespace Greenshot.Base.Core } return Environment.GetFolderPath(Environment.SpecialFolder.Desktop); - case "DWMBackgroundColor": + case nameof(DWMBackgroundColor): return Color.Transparent; - case "ActiveTitleFixes": + case nameof(ActiveTitleFixes): return new List { "Firefox", "IE", "Chrome" }; - case "TitleFixMatcher": + case nameof(TitleFixMatcher): return new Dictionary { { @@ -454,7 +455,7 @@ namespace Greenshot.Base.Core "Chrome", " - Google Chrome.*" } }; - case "TitleFixReplacer": + case nameof(TitleFixReplacer): return new Dictionary { { @@ -509,7 +510,7 @@ namespace Greenshot.Base.Core try { // Store version, this can be used later to fix settings after an update - LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); + LastSaveWithVersion = Assembly.GetEntryAssembly()?.GetName().Version.ToString(); } catch { @@ -530,7 +531,7 @@ namespace Greenshot.Base.Core try { // Store version, this can be used later to fix settings after an update - LastSaveWithVersion = Assembly.GetEntryAssembly().GetName().Version.ToString(); + LastSaveWithVersion = Assembly.GetEntryAssembly()?.GetName().Version.ToString(); } catch { @@ -657,6 +658,16 @@ namespace Greenshot.Base.Core { WebRequestReadWriteTimeout = 100; } + + // Workaround for the Windows 11 clipboard issue found here: https://github.com/greenshot/greenshot/issues/348 + if (WindowsVersion.IsWindows11OrLater) + { + // If the format DIB is used, remove it and replace it with BITMAP. + if (ClipboardFormats.Contains(ClipboardFormat.DIB)) + { + ClipboardFormats = ClipboardFormats.Where(cf => cf != ClipboardFormat.DIB).Append(ClipboardFormat.BITMAP).ToList(); + } + } } /// From ac8545c8484547c0fc6446b2416ac502bd8d70d9 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 25 Jan 2022 11:22:11 +0100 Subject: [PATCH 158/232] Dependency updates --- src/Directory.Build.props | 2 +- src/Greenshot.Base/Greenshot.Base.csproj | 8 ++++---- src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 2c8fc1892..b6533ddd7 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -46,7 +46,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index d6702cc92..958e14fcf 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -5,10 +5,10 @@ - - - - + + + + diff --git a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj index 3b0407fce..e75002ed7 100644 --- a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj +++ b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj @@ -6,7 +6,7 @@ - - + + \ No newline at end of file From 10e3049087590c07c3276a5c891b770bfced60ba Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 25 Jan 2022 11:37:13 +0100 Subject: [PATCH 159/232] Optimized the GreenshotForm by removing the designer support in release mode. --- src/Greenshot.Base/Controls/GreenshotForm.cs | 223 ++++++++++--------- src/Greenshot/greenshot.manifest | 2 +- 2 files changed, 121 insertions(+), 104 deletions(-) diff --git a/src/Greenshot.Base/Controls/GreenshotForm.cs b/src/Greenshot.Base/Controls/GreenshotForm.cs index 9393362e3..eff79e975 100644 --- a/src/Greenshot.Base/Controls/GreenshotForm.cs +++ b/src/Greenshot.Base/Controls/GreenshotForm.cs @@ -19,11 +19,14 @@ * along with this program. If not, see . */ -using System; -using System.Collections.Generic; + +#if DEBUG using System.ComponentModel; using System.ComponentModel.Design; using System.IO; +#endif +using System; +using System.Collections.Generic; using System.Reflection; using System.Windows.Forms; using Greenshot.Base.Core; @@ -40,24 +43,33 @@ namespace Greenshot.Base.Controls private static readonly ILog LOG = LogManager.GetLogger(typeof(GreenshotForm)); protected static CoreConfiguration coreConfiguration; private static readonly IDictionary reflectionCache = new Dictionary(); +#if DEBUG private IComponentChangeService m_changeService; private bool _isDesignModeLanguageSet; - private bool _applyLanguageManually; - private bool _storeFieldsManually; private IDictionary _designTimeControls; private IDictionary _designTimeToolStripItems; +#endif + private bool _applyLanguageManually; + private bool _storeFieldsManually; static GreenshotForm() { +#if DEBUG if (!IsInDesignMode) { +#endif coreConfiguration = IniConfig.GetIniSection(); +#if DEBUG } +#endif } +#if DEBUG [Category("Greenshot"), DefaultValue(null), Description("Specifies key of the language file to use when displaying the text.")] +#endif public string LanguageKey { get; set; } +#if DEBUG /// /// Used to check the designmode during a constructor /// @@ -71,6 +83,7 @@ namespace Greenshot.Base.Controls (Application.ExecutablePath.IndexOf("wdexpress.exe", StringComparison.OrdinalIgnoreCase) > -1)); } } +#endif protected bool ManualLanguageApply { @@ -89,6 +102,7 @@ namespace Greenshot.Base.Controls /// protected bool ToFront { get; set; } +#if DEBUG /// /// Code to initialize the language etc during design time /// @@ -106,19 +120,18 @@ namespace Greenshot.Base.Controls // this "type" Assembly currentAssembly = GetType().Assembly; - if (typeResService != null) - { - string assemblyPath = typeResService.GetPathOfAssembly(currentAssembly.GetName()); - string assemblyDirectory = Path.GetDirectoryName(assemblyPath); - if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Greenshot\Languages\"))) - { - Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Greenshot\Languages\")); - } + if (typeResService == null) return; - if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Languages\"))) - { - Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Languages\")); - } + string assemblyPath = typeResService.GetPathOfAssembly(currentAssembly.GetName()); + string assemblyDirectory = Path.GetDirectoryName(assemblyPath); + if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Greenshot\Languages\"))) + { + Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Greenshot\Languages\")); + } + + if (assemblyDirectory != null && !Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\Languages\"))) + { + Language.AddLanguageFilePath(Path.Combine(assemblyDirectory, @"..\..\..\Languages\")); } } catch (Exception ex) @@ -151,14 +164,17 @@ namespace Greenshot.Base.Controls base.OnPaint(e); } +#endif protected override void OnLoad(EventArgs e) { // Every GreenshotForm should have it's default icon // And it might not ne needed for a Tool Window, but still for the task manager / switcher it's important Icon = GreenshotResources.GetGreenshotIcon(); +#if DEBUG if (!DesignMode) { +#endif if (!_applyLanguageManually) { ApplyLanguage(); @@ -166,6 +182,7 @@ namespace Greenshot.Base.Controls FillFields(); base.OnLoad(e); +#if DEBUG } else { @@ -174,6 +191,7 @@ namespace Greenshot.Base.Controls base.OnLoad(e); ApplyLanguage(); } +#endif } /// @@ -207,6 +225,7 @@ namespace Greenshot.Base.Controls base.OnClosed(e); } +#if DEBUG /// /// This override allows the control to register event handlers for IComponentChangeService events /// at the time the control is sited, which happens only in design mode. @@ -322,6 +341,7 @@ namespace Greenshot.Base.Controls base.Dispose(disposing); } +#endif protected void ApplyLanguage(ToolStripItem applyTo, string languageKey) { @@ -454,7 +474,7 @@ namespace Greenshot.Base.Controls ApplyLanguage(applyToControl); } } - +#if DEBUG if (DesignMode) { foreach (Control designControl in _designTimeControls.Values) @@ -467,6 +487,7 @@ namespace Greenshot.Base.Controls ApplyLanguage(designToolStripItem); } } +#endif } finally { @@ -515,57 +536,55 @@ namespace Greenshot.Base.Controls { var controlObject = field.GetValue(this); IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; - if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + if (string.IsNullOrEmpty(configBindable?.SectionName) || string.IsNullOrEmpty(configBindable.PropertyName)) continue; + + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section == null) continue; + + if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) { - IniSection section = IniConfig.GetIniSection(configBindable.SectionName); - if (section != null) + LOG.DebugFormat("Wrong property '{0}' configured for field '{1}'", configBindable.PropertyName, field.Name); + continue; + } + + if (controlObject is CheckBox checkBox) + { + checkBox.Checked = (bool) iniValue.Value; + checkBox.Enabled = !iniValue.IsFixed; + continue; + } + + if (controlObject is RadioButton radíoButton) + { + radíoButton.Checked = (bool) iniValue.Value; + radíoButton.Enabled = !iniValue.IsFixed; + continue; + } + + if (controlObject is TextBox textBox) + { + if (controlObject is HotkeyControl hotkeyControl) { - if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) + string hotkeyValue = (string) iniValue.Value; + if (!string.IsNullOrEmpty(hotkeyValue)) { - LOG.DebugFormat("Wrong property '{0}' configured for field '{1}'", configBindable.PropertyName, field.Name); - continue; + hotkeyControl.SetHotkey(hotkeyValue); + hotkeyControl.Enabled = !iniValue.IsFixed; } - if (controlObject is CheckBox checkBox) - { - checkBox.Checked = (bool) iniValue.Value; - checkBox.Enabled = !iniValue.IsFixed; - continue; - } - - if (controlObject is RadioButton radíoButton) - { - radíoButton.Checked = (bool) iniValue.Value; - radíoButton.Enabled = !iniValue.IsFixed; - continue; - } - - if (controlObject is TextBox textBox) - { - if (controlObject is HotkeyControl hotkeyControl) - { - string hotkeyValue = (string) iniValue.Value; - if (!string.IsNullOrEmpty(hotkeyValue)) - { - hotkeyControl.SetHotkey(hotkeyValue); - hotkeyControl.Enabled = !iniValue.IsFixed; - } - - continue; - } - - textBox.Text = iniValue.ToString(); - textBox.Enabled = !iniValue.IsFixed; - continue; - } - - if (controlObject is GreenshotComboBox comboxBox) - { - comboxBox.Populate(iniValue.ValueType); - comboxBox.SetValue((Enum) iniValue.Value); - comboxBox.Enabled = !iniValue.IsFixed; - } + continue; } + + textBox.Text = iniValue.ToString(); + textBox.Enabled = !iniValue.IsFixed; + continue; + } + + if (controlObject is GreenshotComboBox comboxBox) + { + comboxBox.Populate(iniValue.ValueType); + comboxBox.SetValue((Enum) iniValue.Value); + comboxBox.Enabled = !iniValue.IsFixed; } } @@ -587,50 +606,48 @@ namespace Greenshot.Base.Controls var controlObject = field.GetValue(this); IGreenshotConfigBindable configBindable = controlObject as IGreenshotConfigBindable; - if (!string.IsNullOrEmpty(configBindable?.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) + if (string.IsNullOrEmpty(configBindable?.SectionName) || string.IsNullOrEmpty(configBindable.PropertyName)) continue; + + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section == null) continue; + + if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) { - IniSection section = IniConfig.GetIniSection(configBindable.SectionName); - if (section != null) + continue; + } + + if (controlObject is CheckBox checkBox) + { + iniValue.Value = checkBox.Checked; + iniDirty = true; + continue; + } + + if (controlObject is RadioButton radioButton) + { + iniValue.Value = radioButton.Checked; + iniDirty = true; + continue; + } + + if (controlObject is TextBox textBox) + { + if (controlObject is HotkeyControl hotkeyControl) { - if (!section.Values.TryGetValue(configBindable.PropertyName, out var iniValue)) - { - continue; - } - - if (controlObject is CheckBox checkBox) - { - iniValue.Value = checkBox.Checked; - iniDirty = true; - continue; - } - - if (controlObject is RadioButton radioButton) - { - iniValue.Value = radioButton.Checked; - iniDirty = true; - continue; - } - - if (controlObject is TextBox textBox) - { - if (controlObject is HotkeyControl hotkeyControl) - { - iniValue.Value = hotkeyControl.ToString(); - iniDirty = true; - continue; - } - - iniValue.UseValueOrDefault(textBox.Text); - iniDirty = true; - continue; - } - - if (controlObject is GreenshotComboBox comboxBox) - { - iniValue.Value = comboxBox.GetSelectedEnum(); - iniDirty = true; - } + iniValue.Value = hotkeyControl.ToString(); + iniDirty = true; + continue; } + + iniValue.UseValueOrDefault(textBox.Text); + iniDirty = true; + continue; + } + + if (controlObject is GreenshotComboBox comboxBox) + { + iniValue.Value = comboxBox.GetSelectedEnum(); + iniDirty = true; } } diff --git a/src/Greenshot/greenshot.manifest b/src/Greenshot/greenshot.manifest index 89cf7a2b6..fa9d5520d 100644 --- a/src/Greenshot/greenshot.manifest +++ b/src/Greenshot/greenshot.manifest @@ -16,7 +16,7 @@ - + From 09d310da78b73c07b33bb43d1b6065217d40c0d6 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 25 Jan 2022 12:12:03 +0100 Subject: [PATCH 160/232] Improvement on the DPI issue in the AboutForm and hopefully fixed a drawing issue where something is animating while the form is being closed. --- src/Greenshot.Base/Controls/AnimatingForm.cs | 4 +++ src/Greenshot/Forms/AboutForm.Designer.cs | 29 ++++++++++++-------- src/Greenshot/Forms/AboutForm.cs | 5 ++-- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/Greenshot.Base/Controls/AnimatingForm.cs b/src/Greenshot.Base/Controls/AnimatingForm.cs index 60d5e7ce9..4a2135606 100644 --- a/src/Greenshot.Base/Controls/AnimatingForm.cs +++ b/src/Greenshot.Base/Controls/AnimatingForm.cs @@ -104,6 +104,10 @@ namespace Greenshot.Base.Controls /// private void Timer_Tick(object sender, EventArgs e) { + if (!Visible) + { + return; + } try { Animate(); diff --git a/src/Greenshot/Forms/AboutForm.Designer.cs b/src/Greenshot/Forms/AboutForm.Designer.cs index fe22ee423..1dbdbdc2d 100644 --- a/src/Greenshot/Forms/AboutForm.Designer.cs +++ b/src/Greenshot/Forms/AboutForm.Designer.cs @@ -69,8 +69,10 @@ namespace Greenshot.Forms { // // lblTitle // - this.lblTitle.Font = new System.Drawing.Font(System.Drawing.FontFamily.GenericSansSerif, 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.lblTitle.Location = new System.Drawing.Point(108, 12); + var fontsize = (this.DeviceDpi / 96) * lblTitle.Font.Size; + this.lblTitle.AutoSize = true; + this.lblTitle.Font = new System.Drawing.Font(System.Drawing.FontFamily.GenericSansSerif, fontsize, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblTitle.Location = new System.Drawing.Point(108, 12); this.lblTitle.Name = "lblTitle"; this.lblTitle.Size = new System.Drawing.Size(263, 19); this.lblTitle.TabIndex = 2; @@ -119,8 +121,9 @@ namespace Greenshot.Forms { this.linkLblBugs.Size = new System.Drawing.Size(465, 23); this.linkLblBugs.TabIndex = 8; this.linkLblBugs.TabStop = true; - this.linkLblBugs.Text = "https://getgreenshot.org/tickets/?version=" + EnvironmentInfo.GetGreenshotVersion(true); - this.linkLblBugs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); + this.linkLblBugs.Text = "https://getgreenshot.org/tickets"; + this.linkLblBugs.Tag = "https://getgreenshot.org/tickets/?version=" + EnvironmentInfo.GetGreenshotVersion(true); + this.linkLblBugs.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); // // lblBugs // @@ -137,8 +140,9 @@ namespace Greenshot.Forms { this.linkLblDonations.Size = new System.Drawing.Size(465, 23); this.linkLblDonations.TabIndex = 10; this.linkLblDonations.TabStop = true; - this.linkLblDonations.Text = "https://getgreenshot.org/support/?version=" + EnvironmentInfo.GetGreenshotVersion(true); - this.linkLblDonations.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); + this.linkLblDonations.Text = "https://getgreenshot.org/support"; + this.linkLblDonations.Tag = "https://getgreenshot.org/support/?version=" + EnvironmentInfo.GetGreenshotVersion(true); + this.linkLblDonations.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); // // lblDonations // @@ -173,9 +177,10 @@ namespace Greenshot.Forms { this.linkLabel1.Size = new System.Drawing.Size(130, 23); this.linkLabel1.TabIndex = 13; this.linkLabel1.TabStop = true; - this.linkLabel1.Text = "https://getgreenshot.org/?version=" + EnvironmentInfo.GetGreenshotVersion(true); + this.linkLabel1.Text = "https://getgreenshot.org"; this.linkLabel1.TextAlign = System.Drawing.ContentAlignment.TopRight; - this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); + this.linkLabel1.Tag = "https://getgreenshot.org/?version=" + EnvironmentInfo.GetGreenshotVersion(true); + this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelClicked); // // pictureBox1 // @@ -197,10 +202,10 @@ namespace Greenshot.Forms { // // AboutForm // - //this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - //this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoScaleDimensions = new System.Drawing.SizeF(96, 96); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + //this.AutoScaleDimensions = new System.Drawing.SizeF(96, 96); + //this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.ClientSize = new System.Drawing.Size(530, 293); this.Controls.Add(this.lblTranslation); diff --git a/src/Greenshot/Forms/AboutForm.cs b/src/Greenshot/Forms/AboutForm.cs index a801cc63e..edb00a6ac 100644 --- a/src/Greenshot/Forms/AboutForm.cs +++ b/src/Greenshot/Forms/AboutForm.cs @@ -219,14 +219,15 @@ namespace Greenshot.Forms private void LinkLabelClicked(object sender, LinkLabelLinkClickedEventArgs e) { if (!(sender is LinkLabel linkLabel)) return; + var link = linkLabel.Tag?.ToString() ?? linkLabel.Text; try { linkLabel.LinkVisited = true; - Process.Start(linkLabel.Text); + Process.Start(link); } catch (Exception) { - MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, linkLabel.Text), Language.GetString(LangKey.error)); + MessageBox.Show(Language.GetFormattedString(LangKey.error_openlink, link), Language.GetString(LangKey.error)); } } From 82fa94f566307ae3d851ae616857c010516b8e1d Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 25 Jan 2022 12:33:06 +0100 Subject: [PATCH 161/232] Fixed some more DPI issues, this time in the settings. --- src/Greenshot.Base/Controls/AnimatingForm.cs | 2 -- src/Greenshot/Forms/SettingsForm.Designer.cs | 4 ++-- src/Greenshot/Forms/SettingsForm.cs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Greenshot.Base/Controls/AnimatingForm.cs b/src/Greenshot.Base/Controls/AnimatingForm.cs index 4a2135606..cde3997ae 100644 --- a/src/Greenshot.Base/Controls/AnimatingForm.cs +++ b/src/Greenshot.Base/Controls/AnimatingForm.cs @@ -21,8 +21,6 @@ using System; using System.Windows.Forms; -using Greenshot.Base.UnmanagedHelpers; -using Greenshot.Base.UnmanagedHelpers.Enums; using log4net; namespace Greenshot.Base.Controls diff --git a/src/Greenshot/Forms/SettingsForm.Designer.cs b/src/Greenshot/Forms/SettingsForm.Designer.cs index 92eb61eef..e8f284850 100644 --- a/src/Greenshot/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot/Forms/SettingsForm.Designer.cs @@ -1257,8 +1257,8 @@ namespace Greenshot.Forms { // // SettingsForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(451, 431); this.Controls.Add(this.tabcontrol); this.Controls.Add(this.settings_confirm); diff --git a/src/Greenshot/Forms/SettingsForm.cs b/src/Greenshot/Forms/SettingsForm.cs index 4ac354aca..7fecda8e2 100644 --- a/src/Greenshot/Forms/SettingsForm.cs +++ b/src/Greenshot/Forms/SettingsForm.cs @@ -94,6 +94,14 @@ namespace Greenshot.Forms // Changes for BUG-2077 numericUpDown_daysbetweencheck.ValueChanged += NumericUpDownDaysbetweencheckOnValueChanged; + // Expert mode, the clipboard formats + foreach (ClipboardFormat clipboardFormat in Enum.GetValues(typeof(ClipboardFormat))) + { + ListViewItem item = listview_clipboardformats.Items.Add(Language.Translate(clipboardFormat)); + item.Tag = clipboardFormat; + item.Checked = coreConfiguration.ClipboardFormats.Contains(clipboardFormat); + } + _daysBetweenCheckPreviousValue = (int) numericUpDown_daysbetweencheck.Value; DisplayPluginTab(); UpdateUi(); @@ -470,14 +478,6 @@ namespace Greenshot.Forms { colorButton_window_background.SelectedColor = coreConfiguration.DWMBackgroundColor; - // Expert mode, the clipboard formats - foreach (ClipboardFormat clipboardFormat in Enum.GetValues(typeof(ClipboardFormat))) - { - ListViewItem item = listview_clipboardformats.Items.Add(Language.Translate(clipboardFormat)); - item.Tag = clipboardFormat; - item.Checked = coreConfiguration.ClipboardFormats.Contains(clipboardFormat); - } - if (Language.CurrentLanguage != null) { combobox_language.SelectedValue = Language.CurrentLanguage; From 8985eb58fa545f6d1b75182fac876ac727388ad8 Mon Sep 17 00:00:00 2001 From: SiderealArt Date: Sat, 29 Jan 2022 00:18:28 +0800 Subject: [PATCH 162/232] Update language-zh-TW.xml (#345) * Update language-zh-TW.xml * Update version Attribute for Translation Update Co-authored-by: jklingen --- src/Greenshot/Languages/language-zh-TW.xml | 61 +++++++++++++++------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/src/Greenshot/Languages/language-zh-TW.xml b/src/Greenshot/Languages/language-zh-TW.xml index 590ec8f05..da3881d2c 100644 --- a/src/Greenshot/Languages/language-zh-TW.xml +++ b/src/Greenshot/Languages/language-zh-TW.xml @@ -1,14 +1,15 @@  - + 請回報錯誤到以下網址 如果您喜歡 Greenshot,歡迎您支持我們: Greenshot 的主機在 GitHub 網址是 圖片來源: Yusuke Kamiyamane's Fugue 圖示集 (Creative Commons Attribution 3.0 授權) Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom -Greenshot 不對這個程式做任何擔保。 這個程式是自由軟體,您可以在 GNU General Public License 下任意散佈本軟體。 -關於GNU General Public License 詳細資料: +Greenshot 不對這個程式做任何擔保。這個程式是自由軟體,您可以在 GNU General Public License 下任意散佈本軟體。 +關於 GNU General Public License 詳細資料: 關於 Greenshot + Greenshot - 革命性的螢幕截圖工具 關閉 很抱歉,發生未預期錯誤。 @@ -24,7 +25,7 @@ Greenshot 不對這個程式做任何擔保。 這個程式是自由軟體,您 Greenshot 無法將資料寫入剪貼簿,因為 {0} 已將剪貼簿鎖定。 找不到剪貼簿圖片。 Windows 點陣圖 - Device Independend Bitmap (DIB) + Device Independent Bitmap (DIB) HTML HTML 含內嵌圖像 PNG @@ -104,10 +105,6 @@ Greenshot 不對這個程式做任何擔保。 這個程式是自由軟體,您 繪製直線 (L) 繪製矩形 (R) 加入文字方塊 (T) - 陰影黑暗 - 陰影偏移 - 陰影設定 - 陰影厚度 複製選取的元素 編輯 效果 @@ -155,12 +152,8 @@ Greenshot 不對這個程式做任何擔保。 這個程式是自由軟體,您 直線粗細 Greenshot 圖片編輯器 撕裂邊緣 - 水平鋸齒範圍 - 撕裂邊緣設定 - 鋸齒大小 - 垂直鋸齒範圍 - 復原 {0} - 上移一層 + 復原 {0} + 上移一層 移到最上層 MAPI 用戶端 Outlook 使用 HTML @@ -172,12 +165,13 @@ Greenshot 不對這個程式做任何擔保。 這個程式是自由軟體,您 無法開啟檔案「{0}」。 無法開啟連結「{0}」。 無法儲存螢幕擷圖,請尋找適合的位置。 + 產生的檔名或是路徑名稱無效。請修正檔名樣式並重試。 專家 在 > 8 位元圖像時,如果色彩小於 256 則建立 8 位元圖像 檢查 Beta 版更新 剪貼簿格式 檔案名稱樣式中 ${NUM} 的數字 - 我明白我所做的動作! + 我知道我在做什麼! 印表機頁尾樣式 最小化記憶體佔用空間,但降低效能 (不建議)。 進行使用遠端桌面的一些最佳化 @@ -188,7 +182,7 @@ Greenshot 不對這個程式做任何擔保。 這個程式是自由軟體,您 匯出到 {0} 時發生錯誤: Greenshot 說明 熱鍵 - 請選擇圖片的 JPEG品質。 + 請選擇圖片的 JPEG 品質。 確定 嘗試列印時發生錯誤。 列印在紙張的正中央 @@ -231,7 +225,7 @@ Greenshot 不對這個程式做任何擔保。 這個程式是自由軟體,您 Internet Explorer 擷取 JPEG 品質 語言 - 在樣式定義中以下預留位置將自動取代: + 在樣式定義中以下預留位置將自動取代: ${YYYY} 年,4 位數字 ${MM} 月,2 位數字 ${DD} 日,2 位數字 @@ -239,6 +233,7 @@ ${hh} 時,2 位數字 ${mm} 分,2 位數字 ${ss} 秒,2 位數字 ${NUM} 自動編號,6 位數字 +${RRR...} 隨機編號, 與 R 的長度相同 ${title} 視窗標題 ${user} Windows 使用者名稱 ${domain} Windows 網域名稱 @@ -278,7 +273,7 @@ ${hostname} 電腦名稱 視窗擷取 顯示放大鏡 右鍵按一下這裡或是按下 {0} 鍵。 - Greenshot 的新版本可以使用! 您要下載 Greenshot {0} 嗎? + Greenshot 的新版本可以使用! 您要下載 Greenshot {0} 嗎? 擷取 Internet Explorer 中頁面時請稍候... 警告 無法註冊熱鍵「{0}」。 這個問題可能是另一個工具要求使用相同的熱鍵。 您可以變更熱鍵設定或停用/變更軟體使用熱鍵。 @@ -289,5 +284,33 @@ Greenshot 所有功能仍然可以直接從通知區圖示的內容功能表動 自動 使用預設色彩 如顯示 + + + 陰影黑暗 + 陰影偏移 + 陰影設定 + 陰影厚度 + + 水平鋸齒範圍 + 撕裂邊緣設定 + 鋸齒大小 + 垂直鋸齒範圍 + 撕裂所有邊緣 + 左側 + 右側 + 上方 + 下方 + 產生陰影 + + 加入計數器 (I) + 加入對話框 (S) + + 縮放 + 縮放設定 + 維持長寬比 + 長度 + 寬度 + 圖示大小 + - \ No newline at end of file + From f98cbd1c44bee00dce08b5c0f11e9f881395feb4 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Fri, 28 Jan 2022 22:15:45 +0100 Subject: [PATCH 163/232] Add shortcuts (0-9, +/-) for foreground color, background color, line thickness, bold and shadow (#338) (#366) Co-authored-by: meschi89 <45665020+meschi89@users.noreply.github.com> --- .../Interfaces/Drawing/Container.cs | 4 + src/Greenshot.Base/Interfaces/ISurface.cs | 4 + .../SurfaceBackgroundColorEventArgs.cs | 31 +++ .../SurfaceBackgroundColorEventHandler.cs | 25 +++ .../SurfaceForegroundColorEventArgs.cs | 31 +++ .../SurfaceForegroundColorEventHandler.cs | 25 +++ .../SurfaceLineThicknessEventArgs.cs | 31 +++ .../SurfaceLineThicknessEventHandler.cs | 25 +++ .../Interfaces/SurfaceShadowEventArgs.cs | 31 +++ .../Interfaces/SurfaceShadowEventHandler.cs | 25 +++ .../Drawing/DrawableContainerList.cs | 65 ++++++ src/Greenshot.Editor/Drawing/Surface.cs | 211 ++++++++++++++++++ src/Greenshot.Editor/Forms/ImageEditorForm.cs | 44 ++++ src/Greenshot/Languages/language-da-DK.xml | 1 + src/Greenshot/Languages/language-de-DE.xml | 6 +- src/Greenshot/Languages/language-en-US.xml | 6 +- src/Greenshot/Languages/language-nl-NL.xml | 6 +- src/Greenshot/Languages/language-ro-RO.xml | 1 + 18 files changed, 563 insertions(+), 9 deletions(-) create mode 100644 src/Greenshot.Base/Interfaces/SurfaceBackgroundColorEventArgs.cs create mode 100644 src/Greenshot.Base/Interfaces/SurfaceBackgroundColorEventHandler.cs create mode 100644 src/Greenshot.Base/Interfaces/SurfaceForegroundColorEventArgs.cs create mode 100644 src/Greenshot.Base/Interfaces/SurfaceForegroundColorEventHandler.cs create mode 100644 src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventArgs.cs create mode 100644 src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventHandler.cs create mode 100644 src/Greenshot.Base/Interfaces/SurfaceShadowEventArgs.cs create mode 100644 src/Greenshot.Base/Interfaces/SurfaceShadowEventHandler.cs diff --git a/src/Greenshot.Base/Interfaces/Drawing/Container.cs b/src/Greenshot.Base/Interfaces/Drawing/Container.cs index 7eb595fdf..4f653ac8a 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/Container.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/Container.cs @@ -111,6 +111,10 @@ namespace Greenshot.Base.Interfaces.Drawing bool HasIntersectingFilters(Rectangle clipRectangle); bool IntersectsWith(Rectangle clipRectangle); void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle); + void SetForegroundColor(Color color); + void SetBackgroundColor(Color color); + int IncreaseLineThickness(int increaseBy); + bool FlipShadow(); void Invalidate(); void PullElementsToTop(IDrawableContainerList elements); bool CanPushDown(IDrawableContainerList elements); diff --git a/src/Greenshot.Base/Interfaces/ISurface.cs b/src/Greenshot.Base/Interfaces/ISurface.cs index 7b8d6884e..d5df7ff44 100644 --- a/src/Greenshot.Base/Interfaces/ISurface.cs +++ b/src/Greenshot.Base/Interfaces/ISurface.cs @@ -38,6 +38,10 @@ namespace Greenshot.Base.Interfaces event SurfaceMessageEventHandler SurfaceMessage; event SurfaceDrawingModeEventHandler DrawingModeChanged; event SurfaceElementEventHandler MovingElementChanged; + event SurfaceForegroundColorEventHandler ForegroundColorChanged; + event SurfaceBackgroundColorEventHandler BackgroundColorChanged; + event SurfaceLineThicknessEventHandler LineThicknessChanged; + event SurfaceShadowEventHandler ShadowChanged; /// /// Start value of the step-labels (counts) diff --git a/src/Greenshot.Base/Interfaces/SurfaceBackgroundColorEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceBackgroundColorEventArgs.cs new file mode 100644 index 000000000..6972d52d0 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/SurfaceBackgroundColorEventArgs.cs @@ -0,0 +1,31 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; + +namespace Greenshot.Base.Interfaces +{ + public class SurfaceBackgroundColorEventArgs : EventArgs + { + public Color Color { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/SurfaceBackgroundColorEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceBackgroundColorEventHandler.cs new file mode 100644 index 000000000..a2a93703b --- /dev/null +++ b/src/Greenshot.Base/Interfaces/SurfaceBackgroundColorEventHandler.cs @@ -0,0 +1,25 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Interfaces +{ + public delegate void SurfaceBackgroundColorEventHandler (object sender, SurfaceBackgroundColorEventArgs e); +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/SurfaceForegroundColorEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceForegroundColorEventArgs.cs new file mode 100644 index 000000000..00de9aec4 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/SurfaceForegroundColorEventArgs.cs @@ -0,0 +1,31 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; + +namespace Greenshot.Base.Interfaces +{ + public class SurfaceForegroundColorEventArgs : EventArgs + { + public Color Color { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/SurfaceForegroundColorEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceForegroundColorEventHandler.cs new file mode 100644 index 000000000..9c62cee2d --- /dev/null +++ b/src/Greenshot.Base/Interfaces/SurfaceForegroundColorEventHandler.cs @@ -0,0 +1,25 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Interfaces +{ + public delegate void SurfaceForegroundColorEventHandler (object sender, SurfaceForegroundColorEventArgs e); +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventArgs.cs new file mode 100644 index 000000000..5fd5694ba --- /dev/null +++ b/src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventArgs.cs @@ -0,0 +1,31 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; + +namespace Greenshot.Base.Interfaces +{ + public class SurfaceLineThicknessEventArgs : EventArgs + { + public int Thickness { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventHandler.cs new file mode 100644 index 000000000..9f8ac3ebe --- /dev/null +++ b/src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventHandler.cs @@ -0,0 +1,25 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Interfaces +{ + public delegate void SurfaceLineThicknessEventHandler (object sender, SurfaceLineThicknessEventArgs e); +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/SurfaceShadowEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceShadowEventArgs.cs new file mode 100644 index 000000000..a7bd682b7 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/SurfaceShadowEventArgs.cs @@ -0,0 +1,31 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; + +namespace Greenshot.Base.Interfaces +{ + public class SurfaceShadowEventArgs : EventArgs + { + public bool HasShadow { get; set; } + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/SurfaceShadowEventHandler.cs b/src/Greenshot.Base/Interfaces/SurfaceShadowEventHandler.cs new file mode 100644 index 000000000..a303aea62 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/SurfaceShadowEventHandler.cs @@ -0,0 +1,25 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Interfaces +{ + public delegate void SurfaceShadowEventHandler (object sender, SurfaceShadowEventArgs e); +} \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs index 9465d7779..a7ed4f75b 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs @@ -30,6 +30,7 @@ using Greenshot.Base.Core; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Configuration; +using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Forms; using Greenshot.Editor.Memento; @@ -430,6 +431,70 @@ namespace Greenshot.Editor.Drawing } } + public void SetForegroundColor(Color color) + { + var dcs = ToArray(); + var field = FieldType.LINE_COLOR; + foreach (var dc in dcs) + { + if (dc is not AbstractFieldHolderWithChildren fh) continue; + if (!fh.HasField(field)) continue; + + fh.SetFieldValue(field, color); + } + } + + public void SetBackgroundColor(Color color) + { + var dcs = ToArray(); + var field = FieldType.FILL_COLOR; + foreach (var dc in dcs) + { + if (dc is not AbstractFieldHolderWithChildren fh) continue; + if (!fh.HasField(field)) continue; + + fh.SetFieldValue(field, color); + } + } + + public int IncreaseLineThickness(int increaseBy) + { + var dcs = ToArray(); + var field = FieldType.LINE_THICKNESS; + var lastThickness = 0; + foreach (var dc in dcs) + { + if (dc is not AbstractFieldHolderWithChildren fh) continue; + if (!fh.HasField(field)) continue; + + var currentThickness = (int)fh.GetFieldValue(field); + var thickness = Math.Max(0, currentThickness + increaseBy); + fh.SetFieldValue(field, thickness); + lastThickness = thickness; + } + + return lastThickness; + } + + public bool FlipShadow() + { + var dcs = ToArray(); + var field = FieldType.SHADOW; + var lastShadow = false; + foreach (var dc in dcs) + { + if (dc is not AbstractFieldHolderWithChildren fh) continue; + if (!fh.HasField(field)) continue; + + var currentShadow = (bool)fh.GetFieldValue(field); + var shadow = !currentShadow; + fh.SetFieldValue(field, shadow); + lastShadow = shadow; + } + + return lastShadow; + } + /// /// Indicates whether the given list of elements can be pushed down, /// i.e. whether there is at least one unselected element lower in hierarchy diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index 7fd7485d0..2f956d132 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -112,6 +112,38 @@ namespace Greenshot.Editor.Drawing remove => _surfaceMessage -= value; } + [NonSerialized] private SurfaceForegroundColorEventHandler _foregroundColorChanged; + + public event SurfaceForegroundColorEventHandler ForegroundColorChanged + { + add => _foregroundColorChanged += value; + remove => _foregroundColorChanged -= value; + } + + [NonSerialized] private SurfaceBackgroundColorEventHandler _backgroundColorChanged; + + public event SurfaceBackgroundColorEventHandler BackgroundColorChanged + { + add => _backgroundColorChanged += value; + remove => _backgroundColorChanged -= value; + } + + [NonSerialized] private SurfaceLineThicknessEventHandler _lineThicknessChanged; + + public event SurfaceLineThicknessEventHandler LineThicknessChanged + { + add => _lineThicknessChanged += value; + remove => _lineThicknessChanged -= value; + } + + [NonSerialized] private SurfaceShadowEventHandler _shadowChanged; + + public event SurfaceShadowEventHandler ShadowChanged + { + add => _shadowChanged += value; + remove => _shadowChanged -= value; + } + /// /// inUndoRedo makes sure we don't undo/redo while in a undo/redo action /// @@ -1060,6 +1092,74 @@ namespace Greenshot.Editor.Drawing } } + /// + /// Use to update UI when pressing a key to change the foreground color + /// + /// Who send + /// new color + public void UpdateForegroundColorEvent(object source, Color color) + { + if (_foregroundColorChanged != null) + { + var eventArgs = new SurfaceForegroundColorEventArgs + { + Color = color, + }; + _foregroundColorChanged(source, eventArgs); + } + } + + /// + /// Use to update UI when pressing a key to change the background color + /// + /// Who send + /// new color + public void UpdateBackgroundColorEvent(object source, Color color) + { + if (_lineThicknessChanged != null) + { + var eventArgs = new SurfaceBackgroundColorEventArgs + { + Color = color, + }; + _backgroundColorChanged(source, eventArgs); + } + } + + /// + /// Use to update UI when pressing a key to change the line thickness + /// + /// Who send + /// new thickness + public void UpdateLineThicknessEvent(object source, int thickness) + { + if (_lineThicknessChanged != null) + { + var eventArgs = new SurfaceLineThicknessEventArgs + { + Thickness = thickness, + }; + _lineThicknessChanged(source, eventArgs); + } + } + + /// + /// Use to update UI when pressing the key to show/hide the shadow + /// + /// Who send + /// has shadow + public void UpdateShadowEvent(object source, bool hasShadow) + { + if (_shadowChanged != null) + { + var eventArgs = new SurfaceShadowEventArgs + { + HasShadow = hasShadow, + }; + _shadowChanged(source, eventArgs); + } + } + /// /// Crop the surface /// @@ -2212,6 +2312,87 @@ namespace Greenshot.Editor.Drawing case Keys.Escape: ConfirmSelectedConfirmableElements(false); break; + case Keys.NumPad0: + SetSelectedElementColor(Color.Orange, true, shiftModifier); + break; + case Keys.NumPad1: + SetSelectedElementColor(Color.Red, true, shiftModifier); + break; + case Keys.NumPad2: + SetSelectedElementColor(Color.FromArgb(0,255,0), true, shiftModifier); // Color.Green is #008000 and not #00FF00 + break; + case Keys.NumPad3: + SetSelectedElementColor(Color.Blue, true, shiftModifier); + break; + case Keys.NumPad4: + SetSelectedElementColor(Color.Cyan, true, shiftModifier); + break; + case Keys.NumPad5: + SetSelectedElementColor(Color.Magenta, true, shiftModifier); + break; + case Keys.NumPad6: + SetSelectedElementColor(Color.Yellow, true, shiftModifier); + break; + case Keys.NumPad7: + SetSelectedElementColor(Color.Black, true, shiftModifier); + break; + case Keys.NumPad8: + SetSelectedElementColor(Color.Gray, true, shiftModifier); + break; + case Keys.NumPad9: + SetSelectedElementColor(Color.White, true, shiftModifier); + break; + case Keys.D0: + case Keys.D0 | Keys.Shift: + SetSelectedElementColor(shiftModifier ? Color.Orange : Color.Transparent, false, shiftModifier); + break; + case Keys.D1: + case Keys.D1 | Keys.Shift: + SetSelectedElementColor(Color.Red, false, shiftModifier); + break; + case Keys.D2: + case Keys.D2 | Keys.Shift: + SetSelectedElementColor(Color.Green, false, shiftModifier); + break; + case Keys.D3: + case Keys.D3 | Keys.Shift: + SetSelectedElementColor(Color.Blue, false, shiftModifier); + break; + case Keys.D4: + case Keys.D4 | Keys.Shift: + SetSelectedElementColor(Color.Cyan, false, shiftModifier); + break; + case Keys.D5: + case Keys.D5 | Keys.Shift: + SetSelectedElementColor(Color.Magenta, false, shiftModifier); + break; + case Keys.D6: + case Keys.D6 | Keys.Shift: + SetSelectedElementColor(Color.Yellow, false, shiftModifier); + break; + case Keys.D7: + case Keys.D7 | Keys.Shift: + SetSelectedElementColor(Color.Black, false, shiftModifier); + break; + case Keys.D8: + case Keys.D8 | Keys.Shift: + SetSelectedElementColor(Color.Gray, false, shiftModifier); + break; + case Keys.D9: + case Keys.D9 | Keys.Shift: + SetSelectedElementColor(Color.White, false, shiftModifier); + break; + case Keys.Add: + case Keys.Add | Keys.Shift: + ChangeLineThickness(shiftModifier ? 5 : 1); + break; + case Keys.Subtract: + case Keys.Subtract | Keys.Shift: + ChangeLineThickness(shiftModifier ? -5 : -1); + break; + case Keys.Divide: + FlipShadow(); + break; /*case Keys.Delete: RemoveSelectedElements(); break;*/ @@ -2231,6 +2412,36 @@ namespace Greenshot.Editor.Drawing return false; } + // for laptops without numPads, also allow shift modifier + private void SetSelectedElementColor(Color color, bool numPad, bool shift) + { + if (numPad || shift) + { + selectedElements.SetForegroundColor(color); + UpdateForegroundColorEvent(this, color); + } + else + { + selectedElements.SetBackgroundColor(color); + UpdateBackgroundColorEvent(this, color); + } + selectedElements.Invalidate(); + } + + private void ChangeLineThickness(int increaseBy) + { + var newThickness = selectedElements.IncreaseLineThickness(increaseBy); + UpdateLineThicknessEvent(this, newThickness); + selectedElements.Invalidate(); + } + + private void FlipShadow() + { + var shadow = selectedElements.FlipShadow(); + UpdateShadowEvent(this, shadow); + selectedElements.Invalidate(); + } + /// /// Property for accessing the elements on the surface /// diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index e3b65b980..4cae6f8e5 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -230,6 +230,10 @@ namespace Greenshot.Editor.Forms _surface.DrawingModeChanged += Surface_DrawingModeChanged; _surface.SurfaceSizeChanged += SurfaceSizeChanged; _surface.SurfaceMessage += SurfaceMessageReceived; + _surface.ForegroundColorChanged += ForegroundColorChanged; + _surface.BackgroundColorChanged += BackgroundColorChanged; + _surface.LineThicknessChanged += LineThicknessChanged; + _surface.ShadowChanged += ShadowChanged; _surface.FieldAggregator.FieldChanged += FieldAggregatorFieldChanged; SurfaceSizeChanged(Surface, null); @@ -498,6 +502,46 @@ namespace Greenshot.Editor.Forms } } + /// + /// This is called when the foreground color of the select element chances, used for shortcuts + /// + /// + /// + private void ForegroundColorChanged(object sender, SurfaceForegroundColorEventArgs eventArgs) + { + btnLineColor.SelectedColor = eventArgs.Color; + } + + /// + /// This is called when the background color of the select element chances, used for shortcuts + /// + /// + /// + private void BackgroundColorChanged(object sender, SurfaceBackgroundColorEventArgs eventArgs) + { + btnFillColor.SelectedColor = eventArgs.Color; + } + + /// + /// This is called when the line thickness of the select element chances, used for shortcuts + /// + /// + /// + private void LineThicknessChanged(object sender, SurfaceLineThicknessEventArgs eventArgs) + { + lineThicknessUpDown.Value = eventArgs.Thickness; + } + + /// + /// This is called when the shadow of the select element chances, used for shortcuts + /// + /// + /// + private void ShadowChanged(object sender, SurfaceShadowEventArgs eventArgs) + { + shadowButton.Checked = eventArgs.HasShadow; + } + /// /// This is called when the size of the surface chances, used for resizing and displaying the size information /// diff --git a/src/Greenshot/Languages/language-da-DK.xml b/src/Greenshot/Languages/language-da-DK.xml index 7e8b6c01a..166774d34 100644 --- a/src/Greenshot/Languages/language-da-DK.xml +++ b/src/Greenshot/Languages/language-da-DK.xml @@ -4,6 +4,7 @@ Dansk oversættelse af Jens Jacob Thomsen diff --git a/src/Greenshot/Languages/language-de-DE.xml b/src/Greenshot/Languages/language-de-DE.xml index 9ece82568..30ffcb30d 100644 --- a/src/Greenshot/Languages/language-de-DE.xml +++ b/src/Greenshot/Languages/language-de-DE.xml @@ -77,7 +77,7 @@ schnell zu finden. Vielen Dank :) Keine Anfangspunkt Automatisch zuschneiden - Hintergrundfarbe + Hintergrundfarbe (0-9) Weichzeichner-Radius Fett Rand @@ -110,7 +110,7 @@ schnell zu finden. Vielen Dank :) E-Mail Datei Größe - Rahmenfarbe + Rahmenfarbe (NumPad0-9, Shift+0-9) Graustufe Bereich hervorheben Graustufen @@ -146,7 +146,7 @@ schnell zu finden. Vielen Dank :) Speichern unter... Alle Objekte auswählen Druckauftrag wurde an '{0}' gesendet. - Schatten An/Aus + Schatten An/Aus (/) Bild wurde in Zwischenablage kopiert. Linienstärke Greenshot Editor diff --git a/src/Greenshot/Languages/language-en-US.xml b/src/Greenshot/Languages/language-en-US.xml index 3db9fbf0e..b575f549b 100644 --- a/src/Greenshot/Languages/language-en-US.xml +++ b/src/Greenshot/Languages/language-en-US.xml @@ -78,7 +78,7 @@ Also, we would highly appreciate if you checked whether a tracker item already e None Start point Auto crop - Fill color + Fill color (0-9) Blur radius Bold Border @@ -111,7 +111,7 @@ Also, we would highly appreciate if you checked whether a tracker item already e E-Mail File Size - Line color + Line color (NumPad0-9, Shift+0-9) Grayscale Highlight area Grayscale @@ -147,7 +147,7 @@ Also, we would highly appreciate if you checked whether a tracker item already e Save as... Select all Print job was sent to '{0}'. - Drop shadow + Drop shadow (/) Image stored to clipboard. Line thickness Greenshot image editor diff --git a/src/Greenshot/Languages/language-nl-NL.xml b/src/Greenshot/Languages/language-nl-NL.xml index 507ece7dc..52e12a895 100644 --- a/src/Greenshot/Languages/language-nl-NL.xml +++ b/src/Greenshot/Languages/language-nl-NL.xml @@ -78,7 +78,7 @@ Controleer ook even of dit probleem mogelijk al gemeld is! Gebruik de zoekfuncti Geen Startpunt Automatisch bijsnijden - Vulkleur + Vulkleur (0-9) Vervagingsradius Vet Rand @@ -111,7 +111,7 @@ Controleer ook even of dit probleem mogelijk al gemeld is! Gebruik de zoekfuncti E-mail Bestand Grootte - Lijnkleur + Lijnkleur (NumPad0-9, Shift+0-9) Grijstinten Gebied markeren Grijstinten @@ -147,7 +147,7 @@ Controleer ook even of dit probleem mogelijk al gemeld is! Gebruik de zoekfuncti Opslaan als… Alles selecteren Afdruktaak verzonden naar '{0}'. - Schaduw + Schaduw (/) Afbeelding opgeslagen op het klembord. Lijndikte Greenshot beeldbewerker diff --git a/src/Greenshot/Languages/language-ro-RO.xml b/src/Greenshot/Languages/language-ro-RO.xml index 11f17a736..7e67ecb52 100644 --- a/src/Greenshot/Languages/language-ro-RO.xml +++ b/src/Greenshot/Languages/language-ro-RO.xml @@ -4,6 +4,7 @@ Traducere în limba română - Radu Mogoș From fdbaca6c3f92d907ff81d7557108b303302a8b1a Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 29 Jan 2022 21:49:20 +0100 Subject: [PATCH 164/232] Fixed the field changing for #338, this should trigger undo and also changes to the default field values (meaning storing in the configuration)- Added the CTRL modifier for the feature for now. --- src/Greenshot.Editor/Drawing/Surface.cs | 237 ++++++++---------- src/Greenshot.Editor/Forms/ImageEditorForm.cs | 26 +- 2 files changed, 115 insertions(+), 148 deletions(-) diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index 2f956d132..5093ed201 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -2270,146 +2270,113 @@ namespace Greenshot.Editor.Drawing /// false if no keys were processed public bool ProcessCmdKey(Keys k) { - if (selectedElements.Count > 0) - { - bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; - int px = shiftModifier ? 10 : 1; - Point moveBy = Point.Empty; + if (selectedElements.Count <= 0) return false; - switch (k) - { - case Keys.Left: - case Keys.Left | Keys.Shift: - moveBy = new Point(-px, 0); - break; - case Keys.Up: - case Keys.Up | Keys.Shift: - moveBy = new Point(0, -px); - break; - case Keys.Right: - case Keys.Right | Keys.Shift: - moveBy = new Point(px, 0); - break; - case Keys.Down: - case Keys.Down | Keys.Shift: - moveBy = new Point(0, px); - break; - case Keys.PageUp: - PullElementsUp(); - break; - case Keys.PageDown: - PushElementsDown(); - break; - case Keys.Home: - PullElementsToTop(); - break; - case Keys.End: - PushElementsToBottom(); - break; - case Keys.Enter: - ConfirmSelectedConfirmableElements(true); - break; - case Keys.Escape: - ConfirmSelectedConfirmableElements(false); - break; - case Keys.NumPad0: - SetSelectedElementColor(Color.Orange, true, shiftModifier); - break; - case Keys.NumPad1: - SetSelectedElementColor(Color.Red, true, shiftModifier); - break; - case Keys.NumPad2: - SetSelectedElementColor(Color.FromArgb(0,255,0), true, shiftModifier); // Color.Green is #008000 and not #00FF00 - break; - case Keys.NumPad3: - SetSelectedElementColor(Color.Blue, true, shiftModifier); - break; - case Keys.NumPad4: - SetSelectedElementColor(Color.Cyan, true, shiftModifier); - break; - case Keys.NumPad5: - SetSelectedElementColor(Color.Magenta, true, shiftModifier); - break; - case Keys.NumPad6: - SetSelectedElementColor(Color.Yellow, true, shiftModifier); - break; - case Keys.NumPad7: - SetSelectedElementColor(Color.Black, true, shiftModifier); - break; - case Keys.NumPad8: - SetSelectedElementColor(Color.Gray, true, shiftModifier); - break; - case Keys.NumPad9: - SetSelectedElementColor(Color.White, true, shiftModifier); - break; - case Keys.D0: - case Keys.D0 | Keys.Shift: - SetSelectedElementColor(shiftModifier ? Color.Orange : Color.Transparent, false, shiftModifier); - break; - case Keys.D1: - case Keys.D1 | Keys.Shift: - SetSelectedElementColor(Color.Red, false, shiftModifier); - break; - case Keys.D2: - case Keys.D2 | Keys.Shift: - SetSelectedElementColor(Color.Green, false, shiftModifier); - break; - case Keys.D3: - case Keys.D3 | Keys.Shift: - SetSelectedElementColor(Color.Blue, false, shiftModifier); - break; - case Keys.D4: - case Keys.D4 | Keys.Shift: - SetSelectedElementColor(Color.Cyan, false, shiftModifier); - break; - case Keys.D5: - case Keys.D5 | Keys.Shift: - SetSelectedElementColor(Color.Magenta, false, shiftModifier); - break; - case Keys.D6: - case Keys.D6 | Keys.Shift: - SetSelectedElementColor(Color.Yellow, false, shiftModifier); - break; - case Keys.D7: - case Keys.D7 | Keys.Shift: - SetSelectedElementColor(Color.Black, false, shiftModifier); - break; - case Keys.D8: - case Keys.D8 | Keys.Shift: - SetSelectedElementColor(Color.Gray, false, shiftModifier); - break; - case Keys.D9: - case Keys.D9 | Keys.Shift: - SetSelectedElementColor(Color.White, false, shiftModifier); - break; - case Keys.Add: - case Keys.Add | Keys.Shift: - ChangeLineThickness(shiftModifier ? 5 : 1); - break; - case Keys.Subtract: - case Keys.Subtract | Keys.Shift: - ChangeLineThickness(shiftModifier ? -5 : -1); - break; - case Keys.Divide: - FlipShadow(); - break; - /*case Keys.Delete: + bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; + int px = shiftModifier ? 10 : 1; + Point moveBy = Point.Empty; + switch (k) + { + case Keys.Left: + case Keys.Left | Keys.Shift: + moveBy = new Point(-px, 0); + break; + case Keys.Up: + case Keys.Up | Keys.Shift: + moveBy = new Point(0, -px); + break; + case Keys.Right: + case Keys.Right | Keys.Shift: + moveBy = new Point(px, 0); + break; + case Keys.Down: + case Keys.Down | Keys.Shift: + moveBy = new Point(0, px); + break; + case Keys.PageUp: + PullElementsUp(); + break; + case Keys.PageDown: + PushElementsDown(); + break; + case Keys.Home: + PullElementsToTop(); + break; + case Keys.End: + PushElementsToBottom(); + break; + case Keys.Enter: + ConfirmSelectedConfirmableElements(true); + break; + case Keys.Escape: + ConfirmSelectedConfirmableElements(false); + break; + case Keys.D0 | Keys.Control: + case Keys.D0 | Keys.Shift | Keys.Control: + SetSelectedElementColor(shiftModifier ? Color.Orange : Color.Transparent, false, shiftModifier); + break; + case Keys.D1 | Keys.Control: + case Keys.D1 | Keys.Shift | Keys.Control: + SetSelectedElementColor(Color.Red, false, shiftModifier); + break; + case Keys.D2 | Keys.Control: + case Keys.D2 | Keys.Shift | Keys.Control: + SetSelectedElementColor(Color.Green, false, shiftModifier); + break; + case Keys.D3 | Keys.Control: + case Keys.D3 | Keys.Shift | Keys.Control: + SetSelectedElementColor(Color.Blue, false, shiftModifier); + break; + case Keys.D4 | Keys.Control: + case Keys.D4 | Keys.Shift | Keys.Control: + SetSelectedElementColor(Color.Cyan, false, shiftModifier); + break; + case Keys.D5 | Keys.Control: + case Keys.D5 | Keys.Shift | Keys.Control: + SetSelectedElementColor(Color.Magenta, false, shiftModifier); + break; + case Keys.D6 | Keys.Control: + case Keys.D6 | Keys.Shift | Keys.Control: + SetSelectedElementColor(Color.Yellow, false, shiftModifier); + break; + case Keys.D7 | Keys.Control: + case Keys.D7 | Keys.Shift | Keys.Control: + SetSelectedElementColor(Color.Black, false, shiftModifier); + break; + case Keys.D8 | Keys.Control: + case Keys.D8 | Keys.Shift | Keys.Control: + SetSelectedElementColor(Color.Gray, false, shiftModifier); + break; + case Keys.D9 | Keys.Control: + case Keys.D9 | Keys.Shift | Keys.Control: + SetSelectedElementColor(Color.White, false, shiftModifier); + break; + case Keys.Add | Keys.Control: + case Keys.Add | Keys.Shift | Keys.Control: + ChangeLineThickness(shiftModifier ? 5 : 1); + break; + case Keys.Subtract | Keys.Control: + case Keys.Subtract | Keys.Shift | Keys.Control: + ChangeLineThickness(shiftModifier ? -5 : -1); + break; + case Keys.Divide | Keys.Control: + FlipShadow(); + break; + /*case Keys.Delete: RemoveSelectedElements(); break;*/ - default: - return false; - } - - if (!Point.Empty.Equals(moveBy)) - { - selectedElements.MakeBoundsChangeUndoable(true); - selectedElements.MoveBy(moveBy.X, moveBy.Y); - } - - return true; + default: + return false; } - return false; + if (!Point.Empty.Equals(moveBy)) + { + selectedElements.MakeBoundsChangeUndoable(true); + selectedElements.MoveBy(moveBy.X, moveBy.Y); + } + + return true; + } // for laptops without numPads, also allow shift modifier diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index 4cae6f8e5..3e1be9489 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -471,7 +471,7 @@ namespace Greenshot.Editor.Forms private delegate void SurfaceMessageReceivedThreadSafeDelegate(object sender, SurfaceMessageEventArgs eventArgs); /// - /// This is the SufraceMessageEvent receiver which display a message in the status bar if the + /// This is the SurfaceMessageEvent receiver which display a message in the status bar if the /// surface is exported. It also updates the title to represent the filename, if there is one. /// /// @@ -505,41 +505,41 @@ namespace Greenshot.Editor.Forms /// /// This is called when the foreground color of the select element chances, used for shortcuts /// - /// - /// + /// object + /// SurfaceForegroundColorEventArgs private void ForegroundColorChanged(object sender, SurfaceForegroundColorEventArgs eventArgs) { - btnLineColor.SelectedColor = eventArgs.Color; + _surface.FieldAggregator.GetField(FieldType.LINE_COLOR).Value = eventArgs.Color; } /// /// This is called when the background color of the select element chances, used for shortcuts /// - /// - /// + /// object + /// SurfaceBackgroundColorEventArgs private void BackgroundColorChanged(object sender, SurfaceBackgroundColorEventArgs eventArgs) { - btnFillColor.SelectedColor = eventArgs.Color; + _surface.FieldAggregator.GetField(FieldType.FILL_COLOR).Value = eventArgs.Color; } /// /// This is called when the line thickness of the select element chances, used for shortcuts /// - /// - /// + /// object + /// SurfaceLineThicknessEventArgs private void LineThicknessChanged(object sender, SurfaceLineThicknessEventArgs eventArgs) { - lineThicknessUpDown.Value = eventArgs.Thickness; + _surface.FieldAggregator.GetField(FieldType.LINE_THICKNESS).Value = eventArgs.Thickness; } /// /// This is called when the shadow of the select element chances, used for shortcuts /// - /// - /// + /// object + /// SurfaceShadowEventArgs private void ShadowChanged(object sender, SurfaceShadowEventArgs eventArgs) { - shadowButton.Checked = eventArgs.HasShadow; + _surface.FieldAggregator.GetField(FieldType.SHADOW).Value = eventArgs.HasShadow; } /// From c701aad58ccd1c7d1deb8e11b95a63d4741ba4a5 Mon Sep 17 00:00:00 2001 From: Mr-Update <37781396+Mr-Update@users.noreply.github.com> Date: Sat, 29 Jan 2022 22:57:37 +0100 Subject: [PATCH 165/232] Update language-de-DE.xml (#316) --- src/Greenshot/Languages/language-de-DE.xml | 76 +++++++++++----------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/src/Greenshot/Languages/language-de-DE.xml b/src/Greenshot/Languages/language-de-DE.xml index 30ffcb30d..062cdd6a5 100644 --- a/src/Greenshot/Languages/language-de-DE.xml +++ b/src/Greenshot/Languages/language-de-DE.xml @@ -57,8 +57,8 @@ schnell zu finden. Vielen Dank :) Greenshot unterstützen Schließen Hilfe - Datei öffnen - Letzten Screenshot im Explorer anzeigen + Datei öffnen... + Letzten Speicherort im Explorer öffnen Schnelleinstellungen Einstellungen... Fehler beim Exportieren nach '{0}'. Bitte wiederholen Sie den Vorgang. @@ -92,14 +92,14 @@ schnell zu finden. Vielen Dank :) Pfad in Zwischenablage kopieren Kopieren Zuschneiden (C) - Auswahlwerkzeug (ESC) + Auswahlwerkzeug (Esc) Ausschneiden Gewähltes Element löschen Eine Ebene nach hinten In den Hintergrund Pfeil zeichnen (A) Ellipse zeichnen (E) - Freihand zeichnen (F) + Frei Hand zeichnen (F) Hervorheben (H) Linie zeichnen (L) Rechteck zeichnen (R) @@ -110,7 +110,7 @@ schnell zu finden. Vielen Dank :) E-Mail Datei Größe - Rahmenfarbe (NumPad0-9, Shift+0-9) + Rahmenfarbe (Num+0-9, Umschalt+0-9) Graustufe Bereich hervorheben Graustufen @@ -130,7 +130,7 @@ schnell zu finden. Vielen Dank :) Unkenntlich machen - Modus Verpixeln Objekt - Verzeichnis in Windows Explorer öffnen + Verzeichnis im Windows Explorer öffnen Einfügen Pixelgröße Vorschauqualität @@ -146,10 +146,10 @@ schnell zu finden. Vielen Dank :) Speichern unter... Alle Objekte auswählen Druckauftrag wurde an '{0}' gesendet. - Schatten An/Aus (/) + Schatten an/aus (/) Bild wurde in Zwischenablage kopiert. Linienstärke - Greenshot Editor + Greenshot - Editor Gerissene Kanten Rückgängig {0} Eine Ebene nach vorne @@ -164,12 +164,12 @@ Bitte überprüfen Sie die Schreibrechte oder wählen Sie einen anderen Speicher Die Datei '{0}' konnte nicht geöffnet werden. Konnte Link '{0}' nicht öffnen. Screenshot konnte nicht gespeichert werden, bitte wählen Sie einen anderen Speicherort. - Der generierte Datei- oder Verzeichnisname ist nicht gültig. Bitte korrigieren Sie das Dateiname-Muster und versuchen Sie es erneut. + Der generierte Datei- oder Verzeichnisname ist nicht gültig. Bitte korrigieren Sie das Dateinamensmuster und versuchen Sie es erneut. Experten 8-Bit-Bilder bei weniger als 256 Farben erstellen Auch instabile Updates anbieten Zwischenablage-Formate - Wert für ${NUM} im Dateiname-Muster + Wert für ${NUM} im Dateinamensmuster Ich weiß, was ich tue! Fußzeile für Druck Speicherverbrauch reduzieren (auf Kosten der Performance - nicht empfohlen) @@ -184,10 +184,10 @@ Bitte überprüfen Sie die Schreibrechte oder wählen Sie einen anderen Speicher Bitte wählen Sie die Qualität Ihres JPEG-Bildes. OK Beim Versuch zu drucken ist ein Fehler aufgetreten. - Ausdruck auf der Seite zentrieren - Ausdruck auf Seitengröße vergrößern - Drehung des Ausdrucks an das Seitenformat anpassen - Ausdruck auf Seitengröße verkleinern + Auf der Seite zentrieren + Auf Seitengröße vergrößern + In die Seitenausrichtung drehen + Auf Seitengröße verkleinern Farb-Einstellungen Als Standard speichern und nicht wieder fragen Farben umkehren @@ -195,7 +195,7 @@ Bitte überprüfen Sie die Schreibrechte oder wählen Sie einen anderen Speicher Farbdruck Nur in Graustufen ausdrucken Schwarz-Weiß-Druck erzwingen - Datum und Uhrzeit am Ende der Seite einfügen + Datum/Uhrzeit am Seitenende Greenshot - Druckeinstellungen Als Standardqualität speichern und nicht wieder fragen Greenshot - Qualität @@ -207,7 +207,7 @@ Bitte überprüfen Sie die Schreibrechte oder wählen Sie einen anderen Speicher Abfotografieren Mauszeiger mitfotografieren Fensterteile einzeln abfotografieren - Prüfen auf Updates alle X Tage (0=keine Prüfung) + Prüfen auf Updates alle x Tage (0 = keine Prüfung) Konfigurieren... Dateipfad in die Zwischenablage kopieren, wenn ein Bild gespeichert wird Ziele @@ -219,29 +219,29 @@ Bitte überprüfen Sie die Schreibrechte oder wählen Sie einen anderen Speicher Ziel dynamisch auswählen An Drucker senden Editor - Dateiname-Muster + Dateinamensmuster Allgemein Internet Explorer abfotografieren JPEG-Qualität Sprache Die folgenden Platzhalter werden im festgelegten Muster automatisch ersetzt: -${YYYY} Jahr, 4-stellig -${MM} Monat, 2-stellig -${DD} Tag, 2-stellig -${hh} Stunde, 2-stellig -${mm} Minute, 2-stellig -${ss} Sekunde, 2-stellig -${NUM} inkrementierende Zahl, 6-stellig -${title} Fenstertitel -${user} Windows-Benutzername -${domain} Windows-Domäne -${hostname} Computername +${YYYY} Jahr, 4-stellig +${MM} Monat, 2-stellig +${DD} Tag, 2-stellig +${hh} Stunde, 2-stellig +${mm} Minute, 2-stellig +${ss} Sekunde, 2-stellig +${NUM} inkrementierende Zahl, 6-stellig +${title} Fenstertitel +${user} Windows-Benutzername +${domain} Windows-Domäne +${hostname} Computername Greenshot kann auch Verzeichnisse dynamisch erstellen. -Verwenden Sie den Backslash \ um Verzeichnisse vom Dateinamen zu trennen. -Zum Beispiel: ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} -Dieses Muster legt ein Verzeichnis für den aktuellen Tag im Standard-Speicherort an und speichert die Bilddateien im Uhrzeit-Format, mit der vorgegebenen Dateiendung ab. -z.B. C:\Users\MaxMustermann\Desktop\2012-08-13\12-58-32.png +Verwenden Sie den Backslash \, um Verzeichnisse vom Dateinamen zu trennen. +Beispiel: ${YYYY}-${MM}-${DD}\${hh}-${mm}-${ss} +Dieses Muster legt ein Verzeichnis für den aktuellen Tag im Standard-Speicherort an und speichert die Bilddateien im Uhrzeit-Format mit der vorgegebenen Dateiendung ab. +Beispiel: C:\Users\MaxMustermann\Desktop\2012-08-13\12-58-32.png Netzwerk und Aktualisierungen Ausgabe Kameraton abspielen @@ -254,7 +254,7 @@ z.B. C:\Users\MaxMustermann\Desktop\2012-08-13\12-58-32.png Bildformat Drucker Druckeinstellungen - Qualitätseinstellungen + JPEG-Qualitätseinstellungen Maximal 256 Farben verwenden Globale Tastenkombinationen aktivieren Blitzlicht anzeigen @@ -264,21 +264,21 @@ z.B. C:\Users\MaxMustermann\Desktop\2012-08-13\12-58-32.png Muster, das beim Speichern von Screenshots zum Generieren von Dateinamen verwendet wird Sprache der Benutzeroberfläche Standard-Bildformat - Legt fest, ob beim Programmstart die Tastenkombinationen Druck, Strg + Druck, Alt + Druck beim Betriebssystem zur globalen Verwendung durch Greenshot reserviert werden, bis das Programm geschlossen wird. + Legt fest, ob beim Programmstart die Tastenkombinationen Druck, Strg+Druck, Alt+Druck beim Betriebssystem zur globalen Verwendung durch Greenshot reserviert werden, bis das Programm geschlossen wird. Standardpfad für Bildschirmausdrucke. Leer lassen für Desktop. Standard-Proxyserver des Betriebssystems verwenden Effekte Millisekunden vor dem Abfotografieren warten - Abfotografiermodus-Fenster + Aufnahmemodus Fenster abfotografieren Lupe anzeigen Klicken Sie hier mit der rechten Maustaste oder drücken Sie die Taste {0}. Eine neuere Greenshot-Version steht zur Verfügung. Wollen Sie Greenshot {0} herunterladen? Bitte warten Sie, während die Seite im Internet Explorer abfotografiert wird... Hinweis - Die globale Tastenkombination "{0}" konnte nicht aktiviert werden. -Vermutlich wurde dieselbe Tastenkombination bereits von einem anderen Programm{1} reserviert. -Sie können die Tastenkombination für Greenshot ändern, oder das Programm, das die Tastenkombination verwendet, deaktivieren. + Die globale Tastenkombination {0} konnte nicht aktiviert werden. +Vermutlich wurde dieselbe Tastenkombination bereits von einem anderen Programm {1} reserviert. +Sie können die Tastenkombination für Greenshot ändern oder das Programm, das die Tastenkombination verwendet, deaktivieren. Sie können aber auch alle Greenshot-Funktionen über das Kontextmenü des Greenshot-Icons im Infobereich verwenden. Benutzerdefinierte Farbe verwenden From 8ce4735aad067de3b664934a021d1477c2a4d43d Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 31 Jan 2022 13:24:25 +0100 Subject: [PATCH 166/232] This should keep the slack workaround but fix #367 --- src/Greenshot/Forms/CaptureForm.cs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs index 7be9c8d6a..f8b2c004b 100644 --- a/src/Greenshot/Forms/CaptureForm.cs +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -153,9 +153,11 @@ namespace Greenshot.Forms _currentForm = this; + // Enable the AnimatingForm + EnableAnimation = true; + // clean up FormClosed += ClosedHandler; - Resize += CaptureForm_Resize; _capture = capture; _windows = windows; _captureMode = capture.CaptureDetails.CaptureMode; @@ -168,8 +170,6 @@ namespace Greenshot.Forms DoubleBuffered = !IsTerminalServerSession; Text = @"Greenshot capture form"; - SetSize(); - // Make sure we never capture the capture-form WindowDetails.RegisterIgnoreHandle(Handle); // Un-register at close @@ -187,8 +187,10 @@ namespace Greenshot.Forms // Set the zoomer animation InitializeZoomer(Conf.ZoomerEnabled); - // Enable the AnimatingForm - EnableAnimation = true; + // Make sure the size is set correctly + SetSize(); + + Resize += CaptureForm_Resize; } private void CaptureForm_Resize(object sender, EventArgs e) @@ -205,12 +207,12 @@ namespace Greenshot.Forms private void SetSize() { - Log.DebugFormat("Setting CaptureForm with dimensions {0}", _capture.ScreenBounds); + Log.DebugFormat("Setting CaptureForm to dimensions {0}", _capture.ScreenBounds); SuspendLayout(); Bounds = _capture.ScreenBounds; ResumeLayout(); - // Fix missing focus + // Make sure it's visible and has focus ToFront = true; TopMost = true; } @@ -220,16 +222,15 @@ namespace Greenshot.Forms /// private void InitializeZoomer(bool isOn) { - var startingPosition = new Rectangle(_cursorPos, Size.Empty); if (isOn) { // Initialize the zoom with a invalid position - _zoomAnimator = new RectangleAnimator( startingPosition , new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut); + _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut); VerifyZoomAnimation(_cursorPos, false); } else { - _zoomAnimator?.ChangeDestination(startingPosition, FramesForMillis(1000)); + _zoomAnimator?.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), FramesForMillis(1000)); } } From b94d9139f292679e20da51456aac77fc3e932b0e Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 1 Feb 2022 22:36:16 +0100 Subject: [PATCH 167/232] I found some research about using the DIB format on the clipboard, which suggests to do it differently. This implements that change, and potentially solves #348, BUG-2892 and more (maybe SUPPORT-135, #172, #365) --- src/Greenshot.Base/Core/ClipboardHelper.cs | 18 ++--- src/Greenshot.Base/Core/CoreConfiguration.cs | 10 --- src/Greenshot.Base/Core/DibHelper.cs | 85 ++++++++++++++++++++ src/Greenshot.Base/Core/ImageHelper.cs | 9 ++- 4 files changed, 96 insertions(+), 26 deletions(-) create mode 100644 src/Greenshot.Base/Core/DibHelper.cs diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs index 02a7f03f1..e87f3d1d6 100644 --- a/src/Greenshot.Base/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -175,7 +175,7 @@ EndSelection:<<<<<<<4 try { - // For BUG-1935 this was changed from looping ourselfs, or letting MS retry... + // For BUG-1935 this was changed from looping ourselves, or letting MS retry... Clipboard.SetDataObject(ido, copy, 15, 200); } catch (Exception clipboardSetException) @@ -866,19 +866,13 @@ EndSelection:<<<<<<<4 { if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.DIB)) { - using (MemoryStream tmpBmpStream = new MemoryStream()) - { - // Save image as BMP - SurfaceOutputSettings bmpOutputSettings = new SurfaceOutputSettings(OutputFormat.bmp, 100, false); - ImageOutput.SaveToStream(imageToSave, null, tmpBmpStream, bmpOutputSettings); - - dibStream = new MemoryStream(); - // Copy the source, but skip the "BITMAPFILEHEADER" which has a size of 14 - dibStream.Write(tmpBmpStream.GetBuffer(), BITMAPFILEHEADER_LENGTH, (int) tmpBmpStream.Length - BITMAPFILEHEADER_LENGTH); - } + // Create the stream for the clipboard + dibStream = new MemoryStream(); + var dibBytes = DibHelper.ConvertToDib(imageToSave); + dibStream.Write(dibBytes,0, dibBytes.Length); // Set the DIB to the clipboard DataObject - dataObject.SetData(DataFormats.Dib, true, dibStream); + dataObject.SetData(DataFormats.Dib, false, dibStream); } } catch (Exception dibEx) diff --git a/src/Greenshot.Base/Core/CoreConfiguration.cs b/src/Greenshot.Base/Core/CoreConfiguration.cs index 4776a3985..ead32a464 100644 --- a/src/Greenshot.Base/Core/CoreConfiguration.cs +++ b/src/Greenshot.Base/Core/CoreConfiguration.cs @@ -658,16 +658,6 @@ namespace Greenshot.Base.Core { WebRequestReadWriteTimeout = 100; } - - // Workaround for the Windows 11 clipboard issue found here: https://github.com/greenshot/greenshot/issues/348 - if (WindowsVersion.IsWindows11OrLater) - { - // If the format DIB is used, remove it and replace it with BITMAP. - if (ClipboardFormats.Contains(ClipboardFormat.DIB)) - { - ClipboardFormats = ClipboardFormats.Where(cf => cf != ClipboardFormat.DIB).Append(ClipboardFormat.BITMAP).ToList(); - } - } } /// diff --git a/src/Greenshot.Base/Core/DibHelper.cs b/src/Greenshot.Base/Core/DibHelper.cs new file mode 100644 index 000000000..70708a0b5 --- /dev/null +++ b/src/Greenshot.Base/Core/DibHelper.cs @@ -0,0 +1,85 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using Greenshot.Base.UnmanagedHelpers; + +namespace Greenshot.Base.Core +{ + /// + /// Though Greenshot implements the specs for the DIB image format, + /// it seems to cause a lot of issues when using the clipboard. + /// There is some research done about the DIB on the clipboard, this code was taking from: + /// here + /// + internal static class DibHelper + { + /// + /// Converts the image to Device Independent Bitmap format of type BITFIELDS. + /// This is (wrongly) accepted by many applications as containing transparency, + /// so I'm abusing it for that. + /// + /// Image to convert to DIB + /// The image converted to DIB, in bytes. + public static byte[] ConvertToDib(Image image) + { + byte[] bm32bData; + int width = image.Width; + int height = image.Height; + // Ensure image is 32bppARGB by painting it on a new 32bppARGB image. + using (var bm32b = ImageHelper.CreateEmptyLike(image, Color.Transparent, PixelFormat.Format32bppArgb)) + { + using (var graphics = Graphics.FromImage(bm32b)) + { + graphics.DrawImage(image, new Rectangle(0, 0, bm32b.Width, bm32b.Height)); + } + // Bitmap format has its lines reversed. + bm32b.RotateFlip(RotateFlipType.Rotate180FlipX); + bm32bData = GetImageData(bm32b, out var stride); + } + // BITMAPINFOHEADER struct for DIB. + uint hdrSize = 0x28; + var fullImage = new byte[hdrSize + 12 + bm32bData.Length]; + var bitmapInfoHeader = MemoryMarshal.Cast(fullImage.AsSpan()); + + bitmapInfoHeader[0].biSize = hdrSize; + bitmapInfoHeader[0].biWidth = width; + bitmapInfoHeader[0].biHeight = height; + bitmapInfoHeader[0].biPlanes = 1; + bitmapInfoHeader[0].biBitCount = 32; + bitmapInfoHeader[0].biCompression = BI_COMPRESSION.BI_BITFIELDS; + bitmapInfoHeader[0].biSizeImage = (uint)bm32bData.Length; + bitmapInfoHeader[0].biXPelsPerMeter = (int)(image.HorizontalResolution * 39.3701); + bitmapInfoHeader[0].biYPelsPerMeter = (int)(image.VerticalResolution * 39.3701); + + + // The aforementioned "BITFIELDS": colour masks applied to the Int32 pixel value to get the R, G and B values. + bitmapInfoHeader[0].bV5RedMask = 0x00FF0000; + bitmapInfoHeader[0].bV5GreenMask = 0x0000FF00; + bitmapInfoHeader[0].bV5BlueMask = 0x000000FF; + + // These are all 0. Since .net clears new arrays, don't bother writing them. + //Int32 biClrUsed = 0; + //Int32 biClrImportant = 0; + + Array.Copy(bm32bData, 0, fullImage, hdrSize + 12, bm32bData.Length); + return fullImage; + } + + /// + /// Gets the raw bytes from an image. + /// + /// The image to get the bytes from. + /// Stride of the retrieved image data. + /// The raw bytes of the image + public static byte[] GetImageData(Bitmap sourceImage, out int stride) + { + BitmapData sourceData = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, sourceImage.PixelFormat); + stride = sourceData.Stride; + byte[] data = new byte[stride * sourceImage.Height]; + Marshal.Copy(sourceData.Scan0, data, 0, data.Length); + sourceImage.UnlockBits(sourceData); + return data; + } + } +} diff --git a/src/Greenshot.Base/Core/ImageHelper.cs b/src/Greenshot.Base/Core/ImageHelper.cs index 60d846eac..7565694e3 100644 --- a/src/Greenshot.Base/Core/ImageHelper.cs +++ b/src/Greenshot.Base/Core/ImageHelper.cs @@ -1497,16 +1497,17 @@ namespace Greenshot.Base.Core /// /// the source bitmap as the specifications for the new bitmap /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - public static Bitmap CreateEmptyLike(Image sourceImage, Color backgroundColor) + /// PixelFormat + /// Bitmap + public static Bitmap CreateEmptyLike(Image sourceImage, Color backgroundColor, PixelFormat? pixelFormat = null) { - PixelFormat pixelFormat = sourceImage.PixelFormat; + pixelFormat ??= sourceImage.PixelFormat; if (backgroundColor.A < 255) { pixelFormat = PixelFormat.Format32bppArgb; } - return CreateEmpty(sourceImage.Width, sourceImage.Height, pixelFormat, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); + return CreateEmpty(sourceImage.Width, sourceImage.Height, pixelFormat.Value, backgroundColor, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); } /// From 9ac6d22c961a61c3ce4eb6ebe8f2ea94fe562ef7 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 3 Feb 2022 00:09:08 +0100 Subject: [PATCH 168/232] Made the DIB code easier to work with, saving memory allocations where possible. --- src/Greenshot.Base/Core/ClipboardHelper.cs | 12 +- src/Greenshot.Base/Core/DibHelper.cs | 147 ++++++++----- src/Greenshot.Base/Core/WindowCapture.cs | 4 +- src/Greenshot.Base/UnmanagedHelpers/GDI32.cs | 217 +++++++++++++++++-- 4 files changed, 292 insertions(+), 88 deletions(-) diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs index e87f3d1d6..02911f058 100644 --- a/src/Greenshot.Base/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -666,8 +666,8 @@ EndSelection:<<<<<<<4 if (imageStream != null) { byte[] dibBuffer = new byte[imageStream.Length]; - imageStream.Read(dibBuffer, 0, dibBuffer.Length); - var infoHeader = BinaryStructHelper.FromByteArray(dibBuffer); + _ = imageStream.Read(dibBuffer, 0, dibBuffer.Length); + var infoHeader = BinaryStructHelper.FromByteArray(dibBuffer); if (!infoHeader.IsDibV5) { Log.InfoFormat("Using special DIB /// Set an Image to the clipboard /// This method will place images to the clipboard depending on the ClipboardFormats setting. @@ -868,7 +866,7 @@ EndSelection:<<<<<<<4 { // Create the stream for the clipboard dibStream = new MemoryStream(); - var dibBytes = DibHelper.ConvertToDib(imageToSave); + var dibBytes = ((Bitmap)imageToSave).ConvertToDib(); dibStream.Write(dibBytes,0, dibBytes.Length); // Set the DIB to the clipboard DataObject @@ -889,7 +887,7 @@ EndSelection:<<<<<<<4 dibV5Stream = new MemoryStream(); // Create the BITMAPINFOHEADER - BITMAPINFOHEADER header = new BITMAPINFOHEADER(imageToSave.Width, imageToSave.Height, 32) + var header = new BITMAPINFOHEADERV5(imageToSave.Width, imageToSave.Height, 32) { // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? biCompression = BI_COMPRESSION.BI_BITFIELDS @@ -1126,7 +1124,7 @@ EndSelection:<<<<<<<4 /// public static IEnumerable GetImageFilenames(IDataObject dataObject) { - string[] dropFileNames = (string[]) dataObject.GetData(DataFormats.FileDrop); + string[] dropFileNames = (string[])dataObject.GetData(DataFormats.FileDrop); if (dropFileNames != null && dropFileNames.Length > 0) { return dropFileNames diff --git a/src/Greenshot.Base/Core/DibHelper.cs b/src/Greenshot.Base/Core/DibHelper.cs index 70708a0b5..61cb84411 100644 --- a/src/Greenshot.Base/Core/DibHelper.cs +++ b/src/Greenshot.Base/Core/DibHelper.cs @@ -1,4 +1,25 @@ -using System; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; @@ -9,77 +30,91 @@ namespace Greenshot.Base.Core /// /// Though Greenshot implements the specs for the DIB image format, /// it seems to cause a lot of issues when using the clipboard. - /// There is some research done about the DIB on the clipboard, this code was taking from: + /// There is some research done about the DIB on the clipboard, this code is based upon the information /// here /// internal static class DibHelper { /// - /// Converts the image to Device Independent Bitmap format of type BITFIELDS. - /// This is (wrongly) accepted by many applications as containing transparency, - /// so I'm abusing it for that. + /// Converts the Bitmap to a Device Independent Bitmap format of type BITFIELDS. /// - /// Image to convert to DIB + /// Bitmap to convert to DIB /// The image converted to DIB, in bytes. - public static byte[] ConvertToDib(Image image) + public static byte[] ConvertToDib(this Bitmap sourceBitmap) { - byte[] bm32bData; - int width = image.Width; - int height = image.Height; - // Ensure image is 32bppARGB by painting it on a new 32bppARGB image. - using (var bm32b = ImageHelper.CreateEmptyLike(image, Color.Transparent, PixelFormat.Format32bppArgb)) - { - using (var graphics = Graphics.FromImage(bm32b)) - { - graphics.DrawImage(image, new Rectangle(0, 0, bm32b.Width, bm32b.Height)); - } - // Bitmap format has its lines reversed. - bm32b.RotateFlip(RotateFlipType.Rotate180FlipX); - bm32bData = GetImageData(bm32b, out var stride); - } - // BITMAPINFOHEADER struct for DIB. - uint hdrSize = 0x28; - var fullImage = new byte[hdrSize + 12 + bm32bData.Length]; - var bitmapInfoHeader = MemoryMarshal.Cast(fullImage.AsSpan()); + if (sourceBitmap == null) throw new ArgumentNullException(nameof(sourceBitmap)); - bitmapInfoHeader[0].biSize = hdrSize; - bitmapInfoHeader[0].biWidth = width; - bitmapInfoHeader[0].biHeight = height; + bool needsDisposal = false; + if (sourceBitmap.PixelFormat != PixelFormat.Format32bppArgb) + { + needsDisposal = true; + var clonedImage = ImageHelper.CreateEmptyLike(sourceBitmap, Color.Transparent, PixelFormat.Format32bppArgb); + using (var graphics = Graphics.FromImage(clonedImage)) + { + graphics.DrawImage(sourceBitmap, new Rectangle(0, 0, clonedImage.Width, clonedImage.Height)); + } + sourceBitmap = clonedImage; + } + + var bitmapSize = 4 * sourceBitmap.Width * sourceBitmap.Height; + var bitmapInfoHeaderSize = Marshal.SizeOf(typeof(BITMAPINFOHEADER)); + var bitmapInfoSize = bitmapInfoHeaderSize + 3 * Marshal.SizeOf(typeof(RGBQUAD)); + + // Create a byte [] to contain the DIB + var fullBmpBytes = new byte[bitmapInfoSize + bitmapSize]; + var fullBmpSpan = fullBmpBytes.AsSpan(); + // Cast the span to be of type BITMAPINFOHEADER so we can assign values + // TODO: in .NET 6 we could do a AsRef + var bitmapInfoHeader = MemoryMarshal.Cast(fullBmpSpan); + + bitmapInfoHeader[0].biSize = (uint)bitmapInfoHeaderSize; + bitmapInfoHeader[0].biWidth = sourceBitmap.Width; + bitmapInfoHeader[0].biHeight = sourceBitmap.Height; bitmapInfoHeader[0].biPlanes = 1; bitmapInfoHeader[0].biBitCount = 32; bitmapInfoHeader[0].biCompression = BI_COMPRESSION.BI_BITFIELDS; - bitmapInfoHeader[0].biSizeImage = (uint)bm32bData.Length; - bitmapInfoHeader[0].biXPelsPerMeter = (int)(image.HorizontalResolution * 39.3701); - bitmapInfoHeader[0].biYPelsPerMeter = (int)(image.VerticalResolution * 39.3701); + bitmapInfoHeader[0].biSizeImage = (uint)bitmapSize; + bitmapInfoHeader[0].biXPelsPerMeter = (int)(sourceBitmap.HorizontalResolution * 39.3701); + bitmapInfoHeader[0].biYPelsPerMeter = (int)(sourceBitmap.VerticalResolution * 39.3701); + // The aforementioned "BITFIELDS": color masks applied to the Int32 pixel value to get the R, G and B values. + var rgbQuads = MemoryMarshal.Cast(fullBmpSpan.Slice(Marshal.SizeOf(typeof(BITMAPINFOHEADER)))); + rgbQuads[0].rgbRed = 255; + rgbQuads[1].rgbGreen = 255; + rgbQuads[2].rgbBlue = 255; - // The aforementioned "BITFIELDS": colour masks applied to the Int32 pixel value to get the R, G and B values. - bitmapInfoHeader[0].bV5RedMask = 0x00FF0000; - bitmapInfoHeader[0].bV5GreenMask = 0x0000FF00; - bitmapInfoHeader[0].bV5BlueMask = 0x000000FF; + // Now copy the lines, in reverse to the byte array + var sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, sourceBitmap.PixelFormat); + try + { + // Get a span for the real bitmap bytes, which starts after the header + var bitmapSpan = fullBmpSpan.Slice(bitmapInfoSize); + // Make sure we also have a span to copy from + Span bitmapSourceSpan; + unsafe + { + bitmapSourceSpan = new Span(sourceBitmapData.Scan0.ToPointer(), sourceBitmapData.Stride * sourceBitmapData.Height); + } - // These are all 0. Since .net clears new arrays, don't bother writing them. - //Int32 biClrUsed = 0; - //Int32 biClrImportant = 0; + // Loop over all the lines and copy the top line to the bottom (flipping the image) + for (int y = 0; y < sourceBitmap.Height; y++) + { + var sourceY = (sourceBitmap.Height - 1) - y; + var sourceLine = bitmapSourceSpan.Slice(sourceBitmapData.Stride * sourceY, 4 * sourceBitmap.Width); + var destinationLine = bitmapSpan.Slice(y * 4 * sourceBitmap.Width); + sourceLine.CopyTo(destinationLine); + } + } + finally + { + sourceBitmap.UnlockBits(sourceBitmapData); + } - Array.Copy(bm32bData, 0, fullImage, hdrSize + 12, bm32bData.Length); - return fullImage; - } - - /// - /// Gets the raw bytes from an image. - /// - /// The image to get the bytes from. - /// Stride of the retrieved image data. - /// The raw bytes of the image - public static byte[] GetImageData(Bitmap sourceImage, out int stride) - { - BitmapData sourceData = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, sourceImage.PixelFormat); - stride = sourceData.Stride; - byte[] data = new byte[stride * sourceImage.Height]; - Marshal.Copy(sourceData.Scan0, data, 0, data.Length); - sourceImage.UnlockBits(sourceData); - return data; + if (needsDisposal) + { + sourceBitmap.Dispose(); + } + return fullBmpBytes; } } } diff --git a/src/Greenshot.Base/Core/WindowCapture.cs b/src/Greenshot.Base/Core/WindowCapture.cs index 3b5bfdbe4..a6b846fd4 100644 --- a/src/Greenshot.Base/Core/WindowCapture.cs +++ b/src/Greenshot.Base/Core/WindowCapture.cs @@ -332,13 +332,13 @@ namespace Greenshot.Base.Core } // Create BITMAPINFOHEADER for CreateDIBSection - BITMAPINFOHEADER bmi = new BITMAPINFOHEADER(captureBounds.Width, captureBounds.Height, 24); + BITMAPINFOHEADERV5 bmi = new BITMAPINFOHEADERV5(captureBounds.Width, captureBounds.Height, 24); // Make sure the last error is set to 0 Win32.SetLastError(0); // create a bitmap we can copy it to, using GetDeviceCaps to get the width/height - using SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDcHandle, ref bmi, BITMAPINFOHEADER.DIB_RGB_COLORS, out _, IntPtr.Zero, 0); + using SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDcHandle, ref bmi, BITMAPINFOHEADERV5.DIB_RGB_COLORS, out _, IntPtr.Zero, 0); if (safeDibSectionHandle.IsInvalid) { // Get Exception before the error is lost diff --git a/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs b/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs index 224ab954a..3f483ff20 100644 --- a/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs @@ -261,7 +261,7 @@ namespace Greenshot.Base.UnmanagedHelpers public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC); [DllImport("gdi32", SetLastError = true)] - public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADER bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset); + public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADERV5 bmi, uint usage, out IntPtr bits, IntPtr hSection, uint dwOffset); [DllImport("gdi32", SetLastError = true)] public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); @@ -314,6 +314,15 @@ namespace Greenshot.Base.UnmanagedHelpers } } + [StructLayout(LayoutKind.Sequential)] + public struct RGBQUAD + { + public byte rgbBlue; + public byte rgbGreen; + public byte rgbRed; + public byte rgbReserved; + } + [StructLayout(LayoutKind.Sequential)] public struct CIEXYZTRIPLE { @@ -348,15 +357,168 @@ namespace Greenshot.Base.UnmanagedHelpers [FieldOffset(28)] public int biYPelsPerMeter; [FieldOffset(32)] public uint biClrUsed; [FieldOffset(36)] public uint biClrImportant; - [FieldOffset(40)] public uint bV5RedMask; - [FieldOffset(44)] public uint bV5GreenMask; - [FieldOffset(48)] public uint bV5BlueMask; - [FieldOffset(52)] public uint bV5AlphaMask; - [FieldOffset(56)] public uint bV5CSType; - [FieldOffset(60)] public CIEXYZTRIPLE bV5Endpoints; - [FieldOffset(96)] public uint bV5GammaRed; - [FieldOffset(100)] public uint bV5GammaGreen; - [FieldOffset(104)] public uint bV5GammaBlue; + + public const int DIB_RGB_COLORS = 0; + + public BITMAPINFOHEADER(int width, int height, ushort bpp) + { + biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV4 is 40 bytes + biPlanes = 1; // Should allways be 1 + biCompression = BI_COMPRESSION.BI_RGB; + biWidth = width; + biHeight = height; + biBitCount = bpp; + biSizeImage = (uint)(width * height * (bpp >> 3)); + biXPelsPerMeter = 0; + biYPelsPerMeter = 0; + biClrUsed = 0; + biClrImportant = 0; + } + + public bool IsDibV4 + { + get + { + uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4)); + return biSize >= sizeOfBMI; + } + } + public bool IsDibV5 + { + get + { + uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV5)); + return biSize >= sizeOfBMI; + } + } + + public uint OffsetToPixels + { + get + { + if (biCompression == BI_COMPRESSION.BI_BITFIELDS) + { + // Add 3x4 bytes for the bitfield color mask + return biSize + 3 * 4; + } + + return biSize; + } + } + } + + [StructLayout(LayoutKind.Explicit)] + public struct BITMAPINFOHEADERV4 + { + [FieldOffset(0)] public uint biSize; + [FieldOffset(4)] public int biWidth; + [FieldOffset(8)] public int biHeight; + [FieldOffset(12)] public ushort biPlanes; + [FieldOffset(14)] public ushort biBitCount; + [FieldOffset(16)] public BI_COMPRESSION biCompression; + [FieldOffset(20)] public uint biSizeImage; + [FieldOffset(24)] public int biXPelsPerMeter; + [FieldOffset(28)] public int biYPelsPerMeter; + [FieldOffset(32)] public uint biClrUsed; + [FieldOffset(36)] public uint biClrImportant; + [FieldOffset(40)] public uint bV4RedMask; + [FieldOffset(44)] public uint bV4GreenMask; + [FieldOffset(48)] public uint bV4BlueMask; + [FieldOffset(52)] public uint bV4AlphaMask; + [FieldOffset(56)] public uint bV4CSType; + [FieldOffset(60)] public CIEXYZTRIPLE bV4Endpoints; + [FieldOffset(96)] public uint bV4GammaRed; + [FieldOffset(100)] public uint bV4GammaGreen; + [FieldOffset(104)] public uint bV4GammaBlue; + + public const int DIB_RGB_COLORS = 0; + + public BITMAPINFOHEADERV4(int width, int height, ushort bpp) + { + biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4)); // BITMAPINFOHEADER < DIBV5 is 40 bytes + biPlanes = 1; // Should allways be 1 + biCompression = BI_COMPRESSION.BI_RGB; + biWidth = width; + biHeight = height; + biBitCount = bpp; + biSizeImage = (uint)(width * height * (bpp >> 3)); + biXPelsPerMeter = 0; + biYPelsPerMeter = 0; + biClrUsed = 0; + biClrImportant = 0; + + // V4 + bV4RedMask = (uint)255 << 16; + bV4GreenMask = (uint)255 << 8; + bV4BlueMask = 255; + bV4AlphaMask = (uint)255 << 24; + bV4CSType = 0x73524742; // LCS_sRGB + bV4Endpoints = new CIEXYZTRIPLE + { + ciexyzBlue = new CIEXYZ(0), + ciexyzGreen = new CIEXYZ(0), + ciexyzRed = new CIEXYZ(0) + }; + bV4GammaRed = 0; + bV4GammaGreen = 0; + bV4GammaBlue = 0; + } + + public bool IsDibV4 + { + get + { + uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4)); + return biSize >= sizeOfBMI; + } + } + public bool IsDibV5 + { + get + { + uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV5)); + return biSize >= sizeOfBMI; + } + } + + public uint OffsetToPixels + { + get + { + if (biCompression == BI_COMPRESSION.BI_BITFIELDS) + { + // Add 3x4 bytes for the bitfield color mask + return biSize + 3 * 4; + } + + return biSize; + } + } + } + + [StructLayout(LayoutKind.Explicit)] + public struct BITMAPINFOHEADERV5 + { + [FieldOffset(0)] public uint biSize; + [FieldOffset(4)] public int biWidth; + [FieldOffset(8)] public int biHeight; + [FieldOffset(12)] public ushort biPlanes; + [FieldOffset(14)] public ushort biBitCount; + [FieldOffset(16)] public BI_COMPRESSION biCompression; + [FieldOffset(20)] public uint biSizeImage; + [FieldOffset(24)] public int biXPelsPerMeter; + [FieldOffset(28)] public int biYPelsPerMeter; + [FieldOffset(32)] public uint biClrUsed; + [FieldOffset(36)] public uint biClrImportant; + [FieldOffset(40)] public uint bV4RedMask; + [FieldOffset(44)] public uint bV4GreenMask; + [FieldOffset(48)] public uint bV4BlueMask; + [FieldOffset(52)] public uint bV4AlphaMask; + [FieldOffset(56)] public uint bV4CSType; + [FieldOffset(60)] public CIEXYZTRIPLE bV4Endpoints; + [FieldOffset(96)] public uint bV4GammaRed; + [FieldOffset(100)] public uint bV4GammaGreen; + [FieldOffset(104)] public uint bV4GammaBlue; [FieldOffset(108)] public uint bV5Intent; // Rendering intent for bitmap [FieldOffset(112)] public uint bV5ProfileData; [FieldOffset(116)] public uint bV5ProfileSize; @@ -364,9 +526,9 @@ namespace Greenshot.Base.UnmanagedHelpers public const int DIB_RGB_COLORS = 0; - public BITMAPINFOHEADER(int width, int height, ushort bpp) + public BITMAPINFOHEADERV5(int width, int height, ushort bpp) { - biSize = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV5 is 40 bytes + biSize = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADERV5)); // BITMAPINFOHEADER < DIBV5 is 40 bytes biPlanes = 1; // Should allways be 1 biCompression = BI_COMPRESSION.BI_RGB; biWidth = width; @@ -378,32 +540,41 @@ namespace Greenshot.Base.UnmanagedHelpers biClrUsed = 0; biClrImportant = 0; - // V5 - bV5RedMask = (uint) 255 << 16; - bV5GreenMask = (uint) 255 << 8; - bV5BlueMask = 255; - bV5AlphaMask = (uint) 255 << 24; - bV5CSType = 0x73524742; // LCS_sRGB - bV5Endpoints = new CIEXYZTRIPLE + // V4 + bV4RedMask = (uint) 255 << 16; + bV4GreenMask = (uint) 255 << 8; + bV4BlueMask = 255; + bV4AlphaMask = (uint) 255 << 24; + bV4CSType = 0x73524742; // LCS_sRGB + bV4Endpoints = new CIEXYZTRIPLE { ciexyzBlue = new CIEXYZ(0), ciexyzGreen = new CIEXYZ(0), ciexyzRed = new CIEXYZ(0) }; - bV5GammaRed = 0; - bV5GammaGreen = 0; - bV5GammaBlue = 0; + bV4GammaRed = 0; + bV4GammaGreen = 0; + bV4GammaBlue = 0; + // V5 bV5Intent = 4; bV5ProfileData = 0; bV5ProfileSize = 0; bV5Reserved = 0; } + public bool IsDibV4 + { + get + { + uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4)); + return biSize >= sizeOfBMI; + } + } public bool IsDibV5 { get { - uint sizeOfBMI = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADER)); + uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV5)); return biSize >= sizeOfBMI; } } From 6b90f2c3ff7149bea01f86b03ca987aa2086d7ae Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 3 Feb 2022 09:10:05 +0100 Subject: [PATCH 169/232] Better documentation for the DibHelper [skip ci] --- src/Greenshot.Base/Core/DibHelper.cs | 44 ++++++++++++++++++---------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/Greenshot.Base/Core/DibHelper.cs b/src/Greenshot.Base/Core/DibHelper.cs index 61cb84411..59af37414 100644 --- a/src/Greenshot.Base/Core/DibHelper.cs +++ b/src/Greenshot.Base/Core/DibHelper.cs @@ -35,15 +35,20 @@ namespace Greenshot.Base.Core /// internal static class DibHelper { + private const double DpiToPelsPerMeter = 39.3701; + /// /// Converts the Bitmap to a Device Independent Bitmap format of type BITFIELDS. /// /// Bitmap to convert to DIB - /// The image converted to DIB, in bytes. + /// byte{} with the image converted to DIB public static byte[] ConvertToDib(this Bitmap sourceBitmap) { if (sourceBitmap == null) throw new ArgumentNullException(nameof(sourceBitmap)); + var area = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height); + + // If the supplied format doesn't match 32bpp, we need to convert it first, and dispose the new bitmap afterwards bool needsDisposal = false; if (sourceBitmap.PixelFormat != PixelFormat.Format32bppArgb) { @@ -51,22 +56,27 @@ namespace Greenshot.Base.Core var clonedImage = ImageHelper.CreateEmptyLike(sourceBitmap, Color.Transparent, PixelFormat.Format32bppArgb); using (var graphics = Graphics.FromImage(clonedImage)) { - graphics.DrawImage(sourceBitmap, new Rectangle(0, 0, clonedImage.Width, clonedImage.Height)); + graphics.DrawImage(sourceBitmap, area); } sourceBitmap = clonedImage; } + // All the pixels take this many bytes: var bitmapSize = 4 * sourceBitmap.Width * sourceBitmap.Height; + // The bitmap info hear takes this many bytes: var bitmapInfoHeaderSize = Marshal.SizeOf(typeof(BITMAPINFOHEADER)); + // The bitmap info size is the header + 3 RGBQUADs var bitmapInfoSize = bitmapInfoHeaderSize + 3 * Marshal.SizeOf(typeof(RGBQUAD)); - // Create a byte [] to contain the DIB + // Create a byte [] to contain the complete DIB (with .NET 5 and upwards, we could write the pixels directly to a stream) var fullBmpBytes = new byte[bitmapInfoSize + bitmapSize]; + // Get a span for this, this simplifies the code a bit var fullBmpSpan = fullBmpBytes.AsSpan(); // Cast the span to be of type BITMAPINFOHEADER so we can assign values - // TODO: in .NET 6 we could do a AsRef + // TODO: in .NET 6 we could do a AsRef, and even write to a stream directly var bitmapInfoHeader = MemoryMarshal.Cast(fullBmpSpan); + // Fill up the bitmap info header bitmapInfoHeader[0].biSize = (uint)bitmapInfoHeaderSize; bitmapInfoHeader[0].biWidth = sourceBitmap.Width; bitmapInfoHeader[0].biHeight = sourceBitmap.Height; @@ -74,34 +84,37 @@ namespace Greenshot.Base.Core bitmapInfoHeader[0].biBitCount = 32; bitmapInfoHeader[0].biCompression = BI_COMPRESSION.BI_BITFIELDS; bitmapInfoHeader[0].biSizeImage = (uint)bitmapSize; - bitmapInfoHeader[0].biXPelsPerMeter = (int)(sourceBitmap.HorizontalResolution * 39.3701); - bitmapInfoHeader[0].biYPelsPerMeter = (int)(sourceBitmap.VerticalResolution * 39.3701); + bitmapInfoHeader[0].biXPelsPerMeter = (int)(sourceBitmap.HorizontalResolution * DpiToPelsPerMeter); + bitmapInfoHeader[0].biYPelsPerMeter = (int)(sourceBitmap.VerticalResolution * DpiToPelsPerMeter); - // The aforementioned "BITFIELDS": color masks applied to the Int32 pixel value to get the R, G and B values. + // Specify the color masks applied to the Int32 pixel value to get the R, G and B values. var rgbQuads = MemoryMarshal.Cast(fullBmpSpan.Slice(Marshal.SizeOf(typeof(BITMAPINFOHEADER)))); rgbQuads[0].rgbRed = 255; rgbQuads[1].rgbGreen = 255; rgbQuads[2].rgbBlue = 255; - // Now copy the lines, in reverse to the byte array - var sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, sourceBitmap.PixelFormat); + // Now copy the lines, in reverse (bmp is upside down) to the byte array + var sourceBitmapData = sourceBitmap.LockBits(area, ImageLockMode.ReadOnly, sourceBitmap.PixelFormat); try { - // Get a span for the real bitmap bytes, which starts after the header + // Get a span for the real bitmap bytes, which starts after the bitmapinfo (header + 3xRGBQuad) var bitmapSpan = fullBmpSpan.Slice(bitmapInfoSize); - // Make sure we also have a span to copy from + // Make sure we also have a span to copy from, by taking the pointer from the locked bitmap Span bitmapSourceSpan; unsafe { bitmapSourceSpan = new Span(sourceBitmapData.Scan0.ToPointer(), sourceBitmapData.Stride * sourceBitmapData.Height); } - // Loop over all the lines and copy the top line to the bottom (flipping the image) - for (int y = 0; y < sourceBitmap.Height; y++) + // Loop over all the bitmap lines + for (int destinationY = 0; destinationY < sourceBitmap.Height; destinationY++) { - var sourceY = (sourceBitmap.Height - 1) - y; + // Calculate the y coordinate for the bottom up. (flipping the image) + var sourceY = (sourceBitmap.Height - 1) - destinationY; + // Make a Span for the source bitmap pixels var sourceLine = bitmapSourceSpan.Slice(sourceBitmapData.Stride * sourceY, 4 * sourceBitmap.Width); - var destinationLine = bitmapSpan.Slice(y * 4 * sourceBitmap.Width); + // Make a Span for the destination dib pixels + var destinationLine = bitmapSpan.Slice(destinationY * 4 * sourceBitmap.Width); sourceLine.CopyTo(destinationLine); } } @@ -110,6 +123,7 @@ namespace Greenshot.Base.Core sourceBitmap.UnlockBits(sourceBitmapData); } + // If we created a new bitmap, we need to dispose this if (needsDisposal) { sourceBitmap.Dispose(); From 4f3920d61a61ddd6cca9f671b65ab8e89c9f4b1a Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 6 Feb 2022 21:21:40 +0100 Subject: [PATCH 170/232] Changed the default window capture for Windows 11 to use User32.PrintWindow (called GDI internally), which should solve #326. The background for this can be read in #373 --- .../Core/Enums/PrintWindowFlags.cs | 38 +++++++++++++++++ src/Greenshot.Base/Core/WindowDetails.cs | 22 ++++++---- src/Greenshot.Base/UnmanagedHelpers/User32.cs | 2 +- src/Greenshot/Helpers/CaptureHelper.cs | 42 +++++++++++-------- 4 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs diff --git a/src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs b/src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs new file mode 100644 index 000000000..6d18cdbe6 --- /dev/null +++ b/src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs @@ -0,0 +1,38 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Core.Enums +{ + [Flags] + public enum PrintWindowFlags : uint + { + /// Render the entire window. + PW_ENTIREWINDOW = 0, + + /// Only the client area of the window is copied to hdcBlt. By default, the entire window is copied. + PW_CLIENTONLY = 1, + + /// Undocumented + PW_RENDERFULLCONTENT = 0x00000002, + } +} diff --git a/src/Greenshot.Base/Core/WindowDetails.cs b/src/Greenshot.Base/Core/WindowDetails.cs index 91ee52de1..be244bb6f 100644 --- a/src/Greenshot.Base/Core/WindowDetails.cs +++ b/src/Greenshot.Base/Core/WindowDetails.cs @@ -1392,32 +1392,36 @@ namespace Greenshot.Base.Core /// /// Return an Image representing the Window! - /// As GDI+ draws it, it will be without Aero borders! + /// For Windows 7, as GDI+ draws it, it will be without Aero borders! + /// For Windows 10+, there is an option PW_RENDERFULLCONTENT, which makes sure the capture is "as is". /// public Image PrintWindow() { Rectangle windowRect = WindowRectangle; // Start the capture - Exception exceptionOccured = null; + Exception exceptionOccurred = null; Image returnImage; using (Region region = GetRegion()) { + var backgroundColor = Color.Black; PixelFormat pixelFormat = PixelFormat.Format24bppRgb; // Only use 32 bpp ARGB when the window has a region if (region != null) { pixelFormat = PixelFormat.Format32bppArgb; + backgroundColor = Color.Transparent; } - - returnImage = new Bitmap(windowRect.Width, windowRect.Height, pixelFormat); + + returnImage = ImageHelper.CreateEmpty(windowRect.Width, windowRect.Height, pixelFormat, backgroundColor, 96,96); using Graphics graphics = Graphics.FromImage(returnImage); using (SafeDeviceContextHandle graphicsDc = graphics.GetSafeDeviceContext()) { - bool printSucceeded = User32.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), 0x0); + var pwFlags = WindowsVersion.IsWindows10OrLater ? PrintWindowFlags.PW_RENDERFULLCONTENT : PrintWindowFlags.PW_ENTIREWINDOW; + bool printSucceeded = User32.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), pwFlags); if (!printSucceeded) { - // something went wrong, most likely a "0x80004005" (Acess Denied) when using UAC - exceptionOccured = User32.CreateWin32Exception("PrintWindow"); + // something went wrong, most likely a "0x80004005" (Access Denied) when using UAC + exceptionOccurred = User32.CreateWin32Exception("PrintWindow"); } } @@ -1432,9 +1436,9 @@ namespace Greenshot.Base.Core } // Return null if error - if (exceptionOccured != null) + if (exceptionOccurred != null) { - Log.ErrorFormat("Error calling print window: {0}", exceptionOccured.Message); + Log.ErrorFormat("Error calling print window: {0}", exceptionOccurred.Message); returnImage.Dispose(); return null; } diff --git a/src/Greenshot.Base/UnmanagedHelpers/User32.cs b/src/Greenshot.Base/UnmanagedHelpers/User32.cs index 67a18ffeb..9764c3a89 100644 --- a/src/Greenshot.Base/UnmanagedHelpers/User32.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/User32.cs @@ -121,7 +121,7 @@ namespace Greenshot.Base.UnmanagedHelpers [DllImport("user32", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, uint nFlags); + public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, PrintWindowFlags pwFlags); [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); diff --git a/src/Greenshot/Helpers/CaptureHelper.cs b/src/Greenshot/Helpers/CaptureHelper.cs index 662f3439a..3d0d3385d 100644 --- a/src/Greenshot/Helpers/CaptureHelper.cs +++ b/src/Greenshot/Helpers/CaptureHelper.cs @@ -969,26 +969,34 @@ namespace Greenshot.Helpers // Take default screen windowCaptureMode = WindowCaptureMode.Screen; - // Change to GDI, if allowed - if (!windowToCapture.IsMetroApp && WindowCapture.IsGdiAllowed(process)) + // In https://github.com/greenshot/greenshot/issues/373 it was shown that PrintWindow (GDI) works great with Windows 11 + if (WindowsVersion.IsWindows11OrLater) { - if (!dwmEnabled && IsWpf(process)) - { - // do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF - Log.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName); - } - else - { - windowCaptureMode = WindowCaptureMode.GDI; - } + windowCaptureMode = WindowCaptureMode.GDI; } - - // Change to DWM, if enabled and allowed - if (dwmEnabled) + else { - if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) + // Change to GDI, if allowed + if (!windowToCapture.IsMetroApp && WindowCapture.IsGdiAllowed(process)) { - windowCaptureMode = WindowCaptureMode.Aero; + if (!dwmEnabled && IsWpf(process)) + { + // do not use GDI, as DWM is not enabled and the application uses PresentationFramework.dll -> isWPF + Log.InfoFormat("Not using GDI for windows of process {0}, as the process uses WPF", process.ProcessName); + } + else + { + windowCaptureMode = WindowCaptureMode.GDI; + } + } + + // Change to DWM, if enabled and allowed + if (dwmEnabled) + { + if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) + { + windowCaptureMode = WindowCaptureMode.Aero; + } } } } @@ -1034,7 +1042,7 @@ namespace Greenshot.Helpers } tmpCapture = windowToCapture.CaptureGdiWindow(captureForWindow); - if (tmpCapture != null) + if (tmpCapture != null && !WindowsVersion.IsWindows11OrLater) { // check if GDI capture any good, by comparing it with the screen content int blackCountGdi = ImageHelper.CountColor(tmpCapture.Image, Color.Black, false); From 2e13c57e2dcb805b6a662da00654d28fc27b0038 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 8 Feb 2022 14:00:49 +0100 Subject: [PATCH 171/232] Doing a bit of cleanup on the code, and fixing #374 --- installer/innosetup/Languages/Arabic.isl | 31 +- installer/innosetup/Languages/Armenian.isl | 376 +++++++++++ installer/innosetup/Languages/Bosnian.isl | 303 +++++---- .../Languages/BrazilianPortuguese.isl | 384 +++++++++++ installer/innosetup/Languages/Bulgarian.isl | 49 +- installer/innosetup/Languages/Catalan.isl | 371 +++++++++++ .../innosetup/Languages/ChineseSimplified.isl | 225 ++++--- .../Languages/ChineseTraditional.isl | 149 +++-- installer/innosetup/Languages/Corsican.isl | 399 ++++++++++++ installer/innosetup/Languages/Croatian.isl | 233 +++---- installer/innosetup/Languages/Czech.isl | 378 +++++++++++ installer/innosetup/Languages/Danish.isl | 379 +++++++++++ installer/innosetup/Languages/Dutch.isl | 359 +++++++++++ .../innosetup/Languages/EnglishBritish.isl | 64 +- installer/innosetup/Languages/Esperanto.isl | 299 +++++---- installer/innosetup/Languages/Farsi.isl | 535 +++++++++------- installer/innosetup/Languages/Finnish.isl | 359 +++++++++++ installer/innosetup/Languages/French.isl | 404 ++++++++++++ installer/innosetup/Languages/Galician.isl | 29 +- installer/innosetup/Languages/Georgian.isl | 384 +++++++++++ installer/innosetup/Languages/German.isl | 406 ++++++++++++ installer/innosetup/Languages/Greek.isl | 36 +- installer/innosetup/Languages/Hebrew.isl | 377 +++++++++++ installer/innosetup/Languages/Hungarian.isl | 488 +++++++------- installer/innosetup/Languages/Icelandic.isl | 361 +++++++++++ installer/innosetup/Languages/Indonesian.isl | 449 +++++++------ installer/innosetup/Languages/Italian.isl | 390 ++++++++++++ installer/innosetup/Languages/Japanese.isl | 367 +++++++++++ installer/innosetup/Languages/Lithuanian.isl | 51 +- installer/innosetup/Languages/Montenegrin.isl | 386 ++++++++++++ installer/innosetup/Languages/Norwegian.isl | 378 +++++++++++ installer/innosetup/Languages/Polish.isl | 377 +++++++++++ installer/innosetup/Languages/Portuguese.isl | 366 +++++++++++ installer/innosetup/Languages/Russian.isl | 370 +++++++++++ .../innosetup/Languages/SerbianCyrillic.isl | 67 +- .../innosetup/Languages/SerbianLatin.isl | 80 ++- installer/innosetup/Languages/Slovak.isl | 385 ++++++++++++ installer/innosetup/Languages/Slovenian.isl | 370 +++++++++++ installer/innosetup/Languages/Spanish.isl | 383 +++++++++++ installer/innosetup/Languages/Swedish.isl | 106 +++- installer/innosetup/Languages/Turkish.isl | 384 +++++++++++ installer/innosetup/Languages/Ukrainian.isl | 385 ++++++++++++ installer/innosetup/Languages/Urdu.isl | 388 ++++++++++++ installer/innosetup/Languages/Uyghur.islu | 595 ++++++++++-------- installer/innosetup/setup.iss | 1 + src/.editorconfig | 5 - src/Greenshot.Base/Core/ClipboardHelper.cs | 2 +- src/Greenshot.Base/Core/EnvironmentInfo.cs | 8 +- src/Greenshot.Base/Core/WindowDetails.cs | 14 +- src/Greenshot.Base/Greenshot.Base.csproj | 2 +- .../Interfaces/Drawing/EditStatus.cs | 32 + .../Interfaces/Drawing/ICursorContainer.cs | 31 + .../Interfaces/Drawing/IDrawableContainer.cs | 79 +++ ...Container.cs => IDrawableContainerList.cs} | 90 --- .../Interfaces/Drawing/IIconContainer.cs | 31 + .../Interfaces/Drawing/IImageContainer.cs | 31 + .../Interfaces/Drawing/ITextContainer.cs | 29 + .../Interfaces/Drawing/RenderMode.cs | 29 + .../Drawing/DrawableContainer.cs | 9 +- .../Drawing/DrawableContainerList.cs | 6 +- .../Support/TranslationManager.cs | 19 - 61 files changed, 12354 insertions(+), 1719 deletions(-) create mode 100644 installer/innosetup/Languages/Armenian.isl create mode 100644 installer/innosetup/Languages/BrazilianPortuguese.isl create mode 100644 installer/innosetup/Languages/Catalan.isl create mode 100644 installer/innosetup/Languages/Corsican.isl create mode 100644 installer/innosetup/Languages/Czech.isl create mode 100644 installer/innosetup/Languages/Danish.isl create mode 100644 installer/innosetup/Languages/Dutch.isl create mode 100644 installer/innosetup/Languages/Finnish.isl create mode 100644 installer/innosetup/Languages/French.isl create mode 100644 installer/innosetup/Languages/Georgian.isl create mode 100644 installer/innosetup/Languages/German.isl create mode 100644 installer/innosetup/Languages/Hebrew.isl create mode 100644 installer/innosetup/Languages/Icelandic.isl create mode 100644 installer/innosetup/Languages/Italian.isl create mode 100644 installer/innosetup/Languages/Japanese.isl create mode 100644 installer/innosetup/Languages/Montenegrin.isl create mode 100644 installer/innosetup/Languages/Norwegian.isl create mode 100644 installer/innosetup/Languages/Polish.isl create mode 100644 installer/innosetup/Languages/Portuguese.isl create mode 100644 installer/innosetup/Languages/Russian.isl create mode 100644 installer/innosetup/Languages/Slovak.isl create mode 100644 installer/innosetup/Languages/Slovenian.isl create mode 100644 installer/innosetup/Languages/Spanish.isl create mode 100644 installer/innosetup/Languages/Turkish.isl create mode 100644 installer/innosetup/Languages/Ukrainian.isl create mode 100644 installer/innosetup/Languages/Urdu.isl create mode 100644 src/Greenshot.Base/Interfaces/Drawing/EditStatus.cs create mode 100644 src/Greenshot.Base/Interfaces/Drawing/ICursorContainer.cs create mode 100644 src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs rename src/Greenshot.Base/Interfaces/Drawing/{Container.cs => IDrawableContainerList.cs} (55%) create mode 100644 src/Greenshot.Base/Interfaces/Drawing/IIconContainer.cs create mode 100644 src/Greenshot.Base/Interfaces/Drawing/IImageContainer.cs create mode 100644 src/Greenshot.Base/Interfaces/Drawing/ITextContainer.cs create mode 100644 src/Greenshot.Base/Interfaces/Drawing/RenderMode.cs diff --git a/installer/innosetup/Languages/Arabic.isl b/installer/innosetup/Languages/Arabic.isl index cc25fe2cd..03f29258d 100644 --- a/installer/innosetup/Languages/Arabic.isl +++ b/installer/innosetup/Languages/Arabic.isl @@ -1,4 +1,4 @@ -; *** Inno Setup version 6.0.3+ arabic messages *** +; *** Inno Setup version 6.1.0+ arabic messages *** ; ; Translated by nacer baaziz (nacerstile@gmail.com) ; http://www.jrsoftware.org/files/istrans/ @@ -14,6 +14,7 @@ LanguageName=arabic LanguageID=$0401 LanguageCodePage=0 +RightToLeft=yes ; If the language you are translating to requires special font faces or ; sizes, uncomment any of the following entries and change them accordingly. ;DialogFontName= @@ -70,8 +71,8 @@ PrivilegesRequiredOverrideText1=يمكن ل %1 أن يُثَبَّت على جم PrivilegesRequiredOverrideText2=.يمكن ل %1 أن يُثَبَّت لك فقط, أو أن يُثَبَّت على جميع المستخدمين (يتطلب إمتيازات المسؤول). PrivilegesRequiredOverrideAllUsers=التثبيت ل&كافة المستخدمين PrivilegesRequiredOverrideAllUsersRecommended=تثبيت ل&كافة المستخدمين (مستحسن) -PrivilegesRequiredOverrideCurrentUser=تثبيت &لي فقط -PrivilegesRequiredOverrideCurrentUserRecommended=تثبيت بالنسبة &لي فقط (مستحسن) +PrivilegesRequiredOverrideCurrentUser=تثبيت لي &فقط +PrivilegesRequiredOverrideCurrentUserRecommended=تثبيت بالنسبة لي &فقط (مستحسن) ; *** Misc. errors ErrorCreatingDir=تعذر على برنامج الإعداد إنشاء الدليل "%1" @@ -210,6 +211,18 @@ ReadyMemoComponents=المكونات المحددة: ReadyMemoGroup=مجلد قائمة ابدأ: ReadyMemoTasks=مهام إضافية: +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=تحميل الملفات الإضافية... +ButtonStopDownload=إي&قاف التحميل +StopDownload=هل أنت متأكد من أنك ترغب في إيقاف التحميل؟ +ErrorDownloadAborted=تم إلغاء التحميل +ErrorDownloadFailed=فشل التحميل: %1 %2 +ErrorDownloadSizeFailed=خطأ في قراءة الحجم: %1 %2 +ErrorFileHash1=خطأ في قراءة الهاش الخاص بالملف: %1 +ErrorFileHash2=خطأ في هاش الملف: كان من المتوقع أن يكن : %1, بينما تم إيجاد : %2 +ErrorProgress=خطأ في الحصول على نسبة التقدم: %1 من %2 +ErrorFileSize=خطأ في حجم الملف: المتوقع هو : %1, الحجم الذي وجدناه هو : %2 + ; *** "Preparing to Install" wizard page WizardPreparing=التحضير للتثبيت PreparingDesc=الإعداد يستعد لتثبيت [name] على جهازك. @@ -292,8 +305,16 @@ ExistingFileReadOnly2=تعذر استبدال الملف الموجود لأنه ExistingFileReadOnlyRetry=&أزل القراءة فقط عن الملفات ثم حاول مرة أخرى ExistingFileReadOnlyKeepExisting=&إحتفظ بالملفات الموجودة ErrorReadingExistingDest=حدث خطأ أثناء محاولة قراءة الملف الموجود: -FileExists=الملف موجود مسبقاً.%n%nهل تريد لبرنامج الإعداد أن يكتب استبداله؟ -ExistingFileNewer=الملف الموجود أحدث من الذي يحاول الإعداد تثبيته. من المستحسن الاحتفاظ بالملف الموجود.%n%nهل تريد الاحتفاظ بالملف الموجود؟ +FileExistsSelectAction=اختر إجراء +FileExists2=الملف موجود بالفعل. +FileExistsOverwriteExisting=&استبدال الملف الموجود +FileExistsKeepExisting=ا&بقاء الملف الموجود +FileExistsOverwriteOrKeepAll=ا&فعل هذا للنزاعات القادمة +ExistingFileNewerSelectAction=اختر إجراء +ExistingFileNewer2=الملف الموجود أحدث من الملف الذي سيقوم معالج الإعداد بتثبيته. +ExistingFileNewerOverwriteExisting=&&استبدال الملف الموجود +ExistingFileNewerKeepExisting=ال&ابقاء على الملف الموجود (مستحسن) +ExistingFileNewerOverwriteOrKeepAll=ا&فعل هذا مع النزاعات القادمة ErrorChangingAttr=حدث خطأ أثناء محاولة تغيير سمات الملف الموجود: ErrorCreatingTemp=حدث خطأ أثناء محاولة إنشاء ملف في الدليل الوجهة: ErrorReadingSource=حدث خطأ أثناء محاولة قراءة ملف مصدر: diff --git a/installer/innosetup/Languages/Armenian.isl b/installer/innosetup/Languages/Armenian.isl new file mode 100644 index 000000000..148db9559 --- /dev/null +++ b/installer/innosetup/Languages/Armenian.isl @@ -0,0 +1,376 @@ +; *** Inno Setup version 6.1.0+ Armenian messages *** +; +; Armenian translation by Hrant Ohanyan +; E-mail: h.ohanyan@haysoft.org +; Translation home page: http://www.haysoft.org +; Last modification date: 2020-10-06 +; +[LangOptions] +LanguageName=Հայերեն +LanguageID=$042B +LanguageCodePage=0 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=Տեղադրում +SetupWindowTitle=%1-ի տեղադրում +UninstallAppTitle=Ապատեղադրում +UninstallAppFullTitle=%1-ի ապատեղադրում + +; *** Misc. common +InformationTitle=Տեղեկություն +ConfirmTitle=Հաստատել +ErrorTitle=Սխալ + +; *** SetupLdr messages +SetupLdrStartupMessage=Այս ծրագիրը կտեղադրի %1-ը Ձեր համակարգչում։ Շարունակե՞լ։ +LdrCannotCreateTemp=Հնարավոր չէ ստեղծել ժամանակավոր ֆայլ։ Տեղադրումը կասեցված է +LdrCannotExecTemp=Հնարավոր չէ կատարել ֆայլը ժամանակավոր պանակից։ Տեղադրումը կասեցված է + +; *** Startup error messages +LastErrorMessage=%1.%n%nՍխալ %2: %3 +SetupFileMissing=%1 ֆայլը բացակայում է տեղադրման պանակից։ Ուղղեք խնդիրը կամ ստացեք ծրագրի նոր տարբերակը։ +SetupFileCorrupt=Տեղադրվող ֆայլերը վնասված են։ +SetupFileCorruptOrWrongVer=Տեղադրվող ֆայլերը վնասված են կամ անհամատեղելի են տեղակայիչի այս տարբերակի հետ։ Ուղղեք խնդիրը կամ ստացեք ծրագրի նոր տարբերակը։ +InvalidParameter=Հրամանատողում նշված է սխալ հրաման.%n%n%1 +SetupAlreadyRunning=Տեղակայիչը արդեն աշխատեցված է։ +WindowsVersionNotSupported=Ծրագիրը չի աջակցում այս համակարգչում աշխատող Windows-ի տարբերակը։ +WindowsServicePackRequired=Ծրագիրը պահանջում է %1-ի Service Pack %2 կամ ավելի նոր։ +NotOnThisPlatform=Այս ծրագիրը չի աշխատի %1-ում։ +OnlyOnThisPlatform=Այս ծրագիրը հնարավոր է բացել միայն %1-ում։ +OnlyOnTheseArchitectures=Այս ծրագրի տեղադրումը հնարավոր է միայն Windows-ի մշակիչի հետևյալ կառուցվածքներում՝ %n%n%1 +WinVersionTooLowError=Այս ծրագիրը պահանջում է %1-ի տարբերակ %2 կամ ավելի նորը։ +WinVersionTooHighError=Ծրագիրը չի կարող տեղադրվել %1-ի տարբերակ %2 կամ ավելի նորում +AdminPrivilegesRequired=Ծրագիրը տեղադրելու համար պահանջվում են Վարիչի իրավունքներ։ +PowerUserPrivilegesRequired=Ծրագիրը տեղադրելու համար պետք է մուտք գործել համակարգ որպես Վարիչ կամ «Փորձառու օգտագործող» (Power Users): +SetupAppRunningError=Տեղակայիչը հայտնաբերել է, որ %1-ը աշխատում է։%n%nՓակեք այն և սեղմեք «Լավ»՝ շարունակելու համար կամ «Չեղարկել»՝ փակելու համար։ +UninstallAppRunningError=Ապատեղադրող ծրագիրը հայտնաբերել է, որ %1-ը աշխատում է։%n%nՓակեք այն և սեղմեք «Լավ»՝ շարունակելու համար կամ «Չեղարկել»՝ փակելու համար։ + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Ընտրեք տեղակայիչի տեղադրման կերպը +PrivilegesRequiredOverrideInstruction=Ընտրեք տեղադրման կերպը +PrivilegesRequiredOverrideText1=%1-ը կարող է տեղադրվել բոլոր օգտվողների համար (պահանջում է վարիչի արտոնություններ) կամ միայն ձեզ համար: +PrivilegesRequiredOverrideText2=%1-ը կարող է տեղադրվել միայն ձեզ համար կամ բոլոր օգտվողների համար (պահանջում է վարիչի արտոնություններ): +PrivilegesRequiredOverrideAllUsers=Տեղադրել &բոլոր օգտվողների համար +PrivilegesRequiredOverrideAllUsersRecommended=Տեղադրել &բոլոր օգտվողների համար (հանձնարարելի) +PrivilegesRequiredOverrideCurrentUser=Տեղադրել միայն &ինձ համար +PrivilegesRequiredOverrideCurrentUserRecommended=Տեղադրել միայն &ինձ համար (հանձնարարելի) + +; *** Misc. errors +ErrorCreatingDir=Հնարավոր չէ ստեղծել "%1" պանակը +ErrorTooManyFilesInDir=Հնարավոր չէ ստեղծել ֆայլ "%1" պանակում, որովհետև նրանում կան չափից ավելի շատ ֆայլեր + +; *** Setup common messages +ExitSetupTitle=Տեղակայման ընդհատում +ExitSetupMessage=Տեղակայումը չի ավարատվել։ Եթե ընդհատեք, ապա ծրագիրը չի տեղադրվի։%n%nԱվարտե՞լ։ +AboutSetupMenuItem=&Ծրագրի մասին... +AboutSetupTitle=Ծրագրի մասին +AboutSetupMessage=%1, տարբերակ՝ %2%n%3%n%nՎեբ կայք՝ %1:%n%4 +AboutSetupNote= +TranslatorNote=Armenian translation by Hrant Ohanyan »»» http://www.haysoft.org + +; *** Buttons +ButtonBack=« &Նախորդ +ButtonNext=&Հաջորդ » +ButtonInstall=&Տեղադրել +ButtonOK=Լավ +ButtonCancel=Չեղարկել +ButtonYes=&Այո +ButtonYesToAll=Այո բոլորի &համար +ButtonNo=&Ոչ +ButtonNoToAll=Ո&չ բոլորի համար +ButtonFinish=&Ավարտել +ButtonBrowse=&Ընտրել... +ButtonWizardBrowse=&Ընտրել... +ButtonNewFolder=&Ստեղծել պանակ + +; *** "Select Language" dialog messages +SelectLanguageTitle=Ընտրել տեղակայիչի լեզուն +SelectLanguageLabel=Ընտրեք այն լեզուն, որը օգտագործվելու է տեղադրման ընթացքում: + +; *** Common wizard text +ClickNext=Սեղմեք «Հաջորդ»՝ շարունակելու համար կամ «Չեղարկել»՝ տեղակայիչը փակելու համար։ +BeveledLabel= +BrowseDialogTitle=Ընտրել պանակ +BrowseDialogLabel=Ընտրեք պանակը ցանկից և սեղմեք «Լավ»։ +NewFolderName=Նոր պանակ + +; *** "Welcome" wizard page +WelcomeLabel1=Ձեզ ողջունում է [name]-ի տեղակայման օգնականը +WelcomeLabel2=Ծրագիրը կտեղադրի [name/ver]-ը Ձեր համակարգչում։%n%nՇարունակելուց առաջ խորհուրդ ենք տալիս փակել բոլոր աշխատող ծրագրերը։ + +; *** "Password" wizard page +WizardPassword=Գաղտնաբառ +PasswordLabel1=Ծրագիրը պաշտպանված է գաղտնաբառով։ +PasswordLabel3=Մուտքագրեք գաղտնաբառը և սեղմեք «Հաջորդ»։ +PasswordEditLabel=&Գաղտնաբառ. +IncorrectPassword=Մուտքագրված գաղտնաբառը սխալ է, կրկին փորձեք։ + +; *** "License Agreement" wizard page +WizardLicense=Արտոնագրային համաձայնագիր +LicenseLabel=Խնդրում ենք շարունակելուց առաջ կարդալ հետևյալ տեղեկությունը։ +LicenseLabel3=Կարդացեք արտոնագրային համաձայնագիրը։ Շարունակելուց առաջ պետք է ընդունեք նշված պայմանները։ +LicenseAccepted=&Ընդունում եմ արտոնագրային համաձայնագիրը +LicenseNotAccepted=&Չեմ ընդունում արտոնագրային համաձայնագիրը + +; *** "Information" wizard pages +WizardInfoBefore=Տեղեկություն +InfoBeforeLabel=Շարունակելուց առաջ կարդացեք այս տեղեկությունը։ +InfoBeforeClickLabel=Եթե պատրաստ եք սեղմեք «Հաջորդը»։ +WizardInfoAfter=Տեղեկություն +InfoAfterLabel=Շարունակելուց առաջ կարդացեք այս տեղեկությունը։ +InfoAfterClickLabel=Երբ պատրաստ լինեք շարունակելու՝ սեղմեք «Հաջորդ»։ + +; *** "User Information" wizard page +WizardUserInfo=Տեղեկություն օգտվողի մասին +UserInfoDesc=Գրեք տվյալներ Ձեր մասին +UserInfoName=&Օգտվողի անուն և ազգանուն. +UserInfoOrg=&Կազմակերպություն. +UserInfoSerial=&Հերթական համար. +UserInfoNameRequired=Պետք է գրեք Ձեր անունը։ + +; *** "Select Destination Location" wizard page +WizardSelectDir=Ընտրել տեղակադրման պանակը +SelectDirDesc=Ո՞ր պանակում տեղադրել [name]-ը։ +SelectDirLabel3=Ծրագիրը կտեղադրի [name]-ը հետևյալ պանակում։ +SelectDirBrowseLabel=Սեղմեք «Հաջորդ»՝ շարունակելու համար։ Եթե ցանկանում եք ընտրել այլ պանակ՝ սեղմեք «Ընտրել»։ +DiskSpaceGBLabel=Առնվազն [gb] ԳԲ ազատ տեղ է պահանջվում: +DiskSpaceMBLabel=Առնվազն [mb] ՄԲ ազատ տեղ է պահանջվում: +CannotInstallToNetworkDrive=Հնարավոր չէ տեղադրել Ցանցային հիշասարքում։ +CannotInstallToUNCPath=Հնարավոր չէ տեղադրել UNC ուղիում։ +InvalidPath=Պետք է նշեք ամբողջական ուղին՝ հիշասարքի տառով, օրինակ՝%n%nC:\APP%n%nկամ UNC ուղի՝ %n%n\\սպասարկիչի_անունը\ռեսուրսի_անունը +InvalidDrive=Ընտրված հիշասարքը կամ ցանցային ուղին գոյություն չունեն կամ անհասանելի են։ Ընտրեք այլ ուղի։ +DiskSpaceWarningTitle=Չկա պահանջվող չափով ազատ տեղ +DiskSpaceWarning=Առնվազն %1 ԿԲ ազատ տեղ է պահանջվում, մինչդեռ հասանելի է ընդամենը %2 ԿԲ։%n%nԱյնուհանդերձ, շարունակե՞լ։ +DirNameTooLong=Պանակի անունը կամ ուղին երկար են: +InvalidDirName=Պանակի նշված անունը անընդունելի է։ +BadDirName32=Անվան մեջ չպետք է լինեն հետևյալ գրանշանները՝ %n%n%1 +DirExistsTitle=Թղթապանակը գոյություն ունի +DirExists=%n%n%1%n%n պանակը արդեն գոյություն ունի։ Այնուհանդերձ, տեղադրե՞լ այստեղ։ +DirDoesntExistTitle=Պանակ գոյություն չունի +DirDoesntExist=%n%n%1%n%n պանակը գոյություն չունի։ Ստեղծե՞լ այն։ + +; *** "Select Components" wizard page +WizardSelectComponents=Ընտրել բաղադրիչներ +SelectComponentsDesc=Ո՞ր ֆայլերը պետք է տեղադրվեն։ +SelectComponentsLabel2=Նշեք այն ֆայլերը, որոնք պետք է տեղադրվեն, ապանշեք նրանք, որոնք չպետք է տեղադրվեն։ Սեղմեք «Հաջորդ»՝ շարունակելու համար։ +FullInstallation=Լրիվ տեղադրում +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Սեղմված տեղադրում +CustomInstallation=Ընտրովի տեղադրում +NoUninstallWarningTitle=Տեղակայվող ֆայլերը +NoUninstallWarning=Տեղակայիչ ծրագիրը հայտնաբերել է, որ հետևյալ բաղադրիչները արդեն տեղադրված են Ձեր համակարգչում։ %n%n%1%n%nԱյս բաղադրիչների ընտրության վերակայումը չի ջնջի դրանք։%n%nՇարունակե՞լ։ +ComponentSize1=%1 ԿԲ +ComponentSize2=%1 ՄԲ +ComponentsDiskSpaceGBLabel=Ընթացիկ ընտրումը պահանջում է առնվազն [gb] ԳԲ տեղ հիշասարքում: +ComponentsDiskSpaceMBLabel=Տվյալ ընտրությունը պահանջում է ամենաքիչը [mb] ՄԲ տեղ հիշասարքում: + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Լրացուցիչ առաջադրանքներ +SelectTasksDesc=Ի՞նչ լրացուցիչ առաջադրանքներ պետք է կատարվեն։ +SelectTasksLabel2=Ընտրեք լրացուցիչ առաջադրանքներ, որոնք պետք է կատարվեն [name]-ի տեղադրման ընթացքում, ապա սեղմեք «Հաջորդ». + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Ընտրել «Մեկնարկ» ցանկի պանակը +SelectStartMenuFolderDesc=Որտե՞ղ ստեղծել դյուրանցումներ. +SelectStartMenuFolderLabel3=Ծրագիրը կստեղծի դյուրանցումներ «Մեկնարկ» ցանկի հետևյալ պանակում։ +SelectStartMenuFolderBrowseLabel=Սեղմեք «Հաջորդ»՝ շարունակելու համար։ Եթե ցանկանում եք ընտրեք այլ պանակ՝ սեղմեք «Ընտրել»։ +MustEnterGroupName=Պետք է գրել պանակի անունը։ +GroupNameTooLong=Պանակի անունը կամ ուղին շատ երկար են։ +InvalidGroupName=Նշված անունը անընդունելի է։ +BadGroupName=Անվան մեջ չպետք է լինեն հետևյալ գրանշանները՝ %n%n%1 +NoProgramGroupCheck2=&Չստեղծել պանակ «Մեկնարկ» ցանկում + +; *** "Ready to Install" wizard page +WizardReady=Պատրաստ է +ReadyLabel1=Տեղակայիչը պատրաստ է սկսել [name]-ի տեղադրումը։ +ReadyLabel2a=Սեղմեք «Տեղադրել»՝ շարունակելու համար կամ «Նախորդ»՝ եթե ցանկանում եք դիտել կամ փոփոխել տեղադրելու կարգավորումները։ +ReadyLabel2b=Սեղմեք «Տեղադրել»՝ շարունակելու համար։ +ReadyMemoUserInfo=Տեղեկություն օգտվողի մասին. +ReadyMemoDir=Տեղադրելու պանակ. +ReadyMemoType=Տեղադրման ձև. +ReadyMemoComponents=Ընտրված բաղադրիչներ. +ReadyMemoGroup=Թղթապանակ «Մեկնարկ» ցանկում. +ReadyMemoTasks=Լրացուցիչ առաջադրանքներ. +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Լրացուցիչ ֆայլերի ներբեռնում... +ButtonStopDownload=&Կանգնեցնել ներբեռնումը +StopDownload=Համոզվա՞ծ եք, որ պետք է կանգնեցնել ներբեռնումը: +ErrorDownloadAborted=Ներբեռնումը կասեցված է +ErrorDownloadFailed=Ներբեռնումը ձախողվեց. %1 %2 +ErrorDownloadSizeFailed=Չափի ստացումը ձախողվեց. %1 %2 +ErrorFileHash1=Ֆահլի հաշվեգումարը ձախողվեց. %1 +ErrorFileHash2=Ֆայլի անվավեր հաշվեգումար. ակընկալվում էր %1, գտնվել է %2 +ErrorProgress=Անվավեր ընթացք. %1-ը %2-ից +ErrorFileSize=Ֆայլի անվավեր աչփ. ակընկալվում էր %1, գտնվել է %2 +; *** "Preparing to Install" wizard page +WizardPreparing=Նախատրաստում է տեղադրումը +PreparingDesc=Տեղակայիչը պատրաստվում է տեղադրել [name]-ը ձեր համակարգչում։ +PreviousInstallNotCompleted=Այլ ծրագրի տեղադրումը կամ ապատեղադրումը չի ավարտվել։ Այն ավարտելու համար պետք է վերամեկնարկեք համակարգիչը։%n%nՎերամեկնարկելուց հետո կրկին բացեք տեղակայման փաթեթը՝ [name]-ի տեղադրումը ավարտելու համար։ +CannotContinue=Հնարավոր չէ շարունակել։ Սեղմեք «Չեղարկել»՝ ծրագիրը փակելու համար։ +ApplicationsFound=Հետևյալ ծրագրերը օգտագործում են ֆայլեր, որոնք պետք է թարմացվեն տեղակայիչի կողմից։ Թույլատրեք տեղակայիչին ինքնաբար փակելու այդ ծրագրերը։ +ApplicationsFound2=Հետևյալ ծրագրերը օգտագործում են ֆայլեր, որոնք պետք է թարմացվեն տեղակայիչի կողմից։ Թույլատրեք տեղակայիչին ինքնաբար փակելու այդ ծրագրերը։ Տեղադրումը ավարտելուց հետո տեղակայիչը կփորձի վերամեկնարկել այդ ծրագրերը։ +CloseApplications=&Ինքնաբար փակել ծրագրերը +DontCloseApplications=&Չփակել ծրագրերը +ErrorCloseApplications=Տեղակայիչը չկարողացավ ինքնաբար փակել բոլոր ծրագրերը: Խորհուրդ ենք տալիս փակել այն բոլոր ծրագրերը, որոնք պետք է թարմացվեն տեղակայիչի կողմից: +PrepareToInstallNeedsRestart=Տեղակայիչը պետք է վերամեկնարկի ձեր համակարգիչը: Դրանից հետո կրկին աշխատեցրեք այն՝ ավարտելու համար [name]-ի տեղադրումը:%n%nՑանկանո՞ւմ եք վերամեկնարկել հիմա: + +; *** "Installing" wizard page +WizardInstalling=Տեղադրում +InstallingLabel=Խնդրում ենք սպասել մինչ [name]-ը կտեղադրվի Ձեր համակարգչում։ + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name]-ի տեղադրման ավարտ +FinishedLabelNoIcons=[name] ծրագիրը տեղադրվել է Ձեր համակարգչում։ +FinishedLabel=[name] ծրագիրը տեղադրվել է Ձեր համակարգչում։ +ClickFinish=Սեղմեք «Ավարտել»՝ տեղակայիչը փակելու համար։ +FinishedRestartLabel=[name]-ի տեղադրումը ավարտելու համար պետք է վերամեկնարկել համակարգիչը։ վերամեկնարկե՞լ հիմա։ +FinishedRestartMessage=[name]-ի տեղադրումը ավարտելու համար պետք է վերամեկնարկել համակարգիչը։ %n%վերամեկնարկե՞լ հիմա։ +ShowReadmeCheck=Նայել README ֆայլը։ +YesRadio=&Այո, վերամեկնարկել +NoRadio=&Ոչ, ես հետո վերամեկնարկեմ +; used for example as 'Run MyProg.exe' +RunEntryExec=Աշխատեցնել %1-ը +; used for example as 'View Readme.txt' +RunEntryShellExec=Նայել %1-ը + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Տեղակայիչը պահանջում է հաջորդ սկավառակը +SelectDiskLabel2=Զետեղեք %1 սկավառակը և սեղմեք «Լավ»։ %n%nԵթե ֆայլերի պանակը գտնվում է այլ տեղ, ապա ընտրեք ճիշտ ուղին կամ սեղմեք «Ընտրել»։ +PathLabel=&Ուղին. +FileNotInDir2="%1" ֆայլը չի գտնվել "%2"-ում։ Զետեղեք ճիշտ սկավառակ կամ ընտրեք այլ պանակ։ +SelectDirectoryLabel=Խնդրում ենք նշել հաջորդ սկավառակի տեղադրությունը։ + +; *** Installation phase messages +SetupAborted=Տեղակայումը չի ավարտվել։ %n%nՈւղղեք խնդիրը և կրկին փորձեք։ +AbortRetryIgnoreSelectAction=Ընտրեք գործողություն +AbortRetryIgnoreRetry=&Կրկին փորձել +AbortRetryIgnoreIgnore=&Անտեսել սխալը և շարունակել +AbortRetryIgnoreCancel=Չեղարկել տեղադրումը + +; *** Installation status messages +StatusClosingApplications=Փակում է ծրագրերը... +StatusCreateDirs=Պանակների ստեղծում... +StatusExtractFiles=Ֆայլերի դուրս բերում... +StatusCreateIcons=Դյուրանցումների ստեղծում... +StatusCreateIniEntries=INI ֆայլերի ստեղծում... +StatusCreateRegistryEntries=Գրանցամատյանի գրանցումների ստեղծում... +StatusRegisterFiles=Ֆայլերի գրանցում... +StatusSavingUninstall=Ապատեղադրելու տեղեկության պահում... +StatusRunProgram=Տեղադրելու ավարտ... +StatusRestartingApplications=Ծրագրերի վերամեկնարկում... +StatusRollback=Փոփոխությունների հետ բերում... + +; *** Misc. errors +ErrorInternal2=Ներքին սխալ %1 +ErrorFunctionFailedNoCode=%1. վթար +ErrorFunctionFailed=%1. վթար, կոդը՝ %2 +ErrorFunctionFailedWithMessage=%1. վթար, կոդը՝ %2.%n%3 +ErrorExecutingProgram=Հնարավոր չէ կատարել %n%1 ֆայլը + +; *** Registry errors +ErrorRegOpenKey=Գրանցամատյանի բանալին բացելու սխալ՝ %n%1\%2 +ErrorRegCreateKey=Գրանցամատյանի բանալին ստեղծելու սխալ՝ %n%1\%2 +ErrorRegWriteKey=Գրանցամատյանի բանալիում գրանցում կատարելու սխալ՝ %n%1\%2 + +; *** INI errors +ErrorIniEntry=Սխալ՝ "%1" INI ֆայլում գրառում կատարելիս։ + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=Բաց թողնել այս ֆայլը (խորհուրդ չի տրվում) +FileAbortRetryIgnoreIgnoreNotRecommended=Անտեսել սխալը և շարունակել (խորհուրդ չի տրվում) +SourceIsCorrupted=Սկզբնական ֆայլը վնասված է։ +SourceDoesntExist=Սկզբնական "%1" ֆայլը գոյություն չունի +ExistingFileReadOnly2=Առկա ֆայլը չի կարող փոխարինվել, քանի որ այն նշված է որպես միայն կարդալու: +ExistingFileReadOnlyRetry=&Հեռացրեք միայն կարդալ հատկանիշը և կրկին փորձեք +ExistingFileReadOnlyKeepExisting=&Պահել առկա ֆայլը +ErrorReadingExistingDest=Սխալ՝ ֆայլը կարդալիս. +FileExistsSelectAction=Ընտրեք գործողություն +FileExists2=Ֆայլը գոյություն չունի +FileExistsOverwriteExisting=&Վրագրել առկա ֆայլը +FileExistsKeepExisting=&Պահել առկա ֆայլը +FileExistsOverwriteOrKeepAll=&Անել սա հաջորդ բախման ժամանակ +ExistingFileNewerSelectAction=Ընտրեք գործողություն +ExistingFileNewer2=Առկա ֆայլը ավելի նոր է, քան այն, որ տեղակայիչը փորձում է տեղադրել: +ExistingFileNewerOverwriteExisting=&Վրագրել առկա ֆայլը +ExistingFileNewerKeepExisting=&Պահել առկա ֆայլը (հանձնարարելի) +ExistingFileNewerOverwriteOrKeepAll=&Անել սա հաջորդ բախման ժամանակ +ErrorChangingAttr=Սխալ՝ ընթացիկ ֆայլի հատկանիշները փոխելիս. +ErrorCreatingTemp=Սխալ՝ նշված պանակում ֆայլ ստեղծելիս. +ErrorReadingSource=Սխալ՝ ֆայլը կարդալիս. +ErrorCopying=Սխալ՝ ֆայլը պատճենելիս. +ErrorReplacingExistingFile=Սխալ՝ գոյություն ունեցող ֆայլը փոխարինելիս. +ErrorRestartReplace=RestartReplace ձախողում. +ErrorRenamingTemp=Սխալ՝ նպատակակետ պանակում՝ ֆայլը վերանվանելիս. +ErrorRegisterServer=Հնարավոր չէ գրանցել DLL/OCX-ը. %1 +ErrorRegSvr32Failed=RegSvr32-ի ձախողում, կոդ՝ %1 +ErrorRegisterTypeLib=Հնարավոր չէ գրանցել դարանները՝ %1 +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32 բիթային +UninstallDisplayNameMark64Bit=64 բիթային +UninstallDisplayNameMarkAllUsers=Բոլոր օգտվողները +UninstallDisplayNameMarkCurrentUser=Ընթացիկ օգտվողը + +; *** Post-installation errors +ErrorOpeningReadme=Սխալ՝ README ֆայլը բացելիս։ +ErrorRestartingComputer=Հնարավոր չեղավ վերամեկնարկել համակարգիչը։ Ինքներդ փորձեք։ + +; *** Uninstaller messages +UninstallNotFound="%1" ֆայլը գոյություն չունի։ Հնարավոր չէ ապատեղադրել։ +UninstallOpenError="%1" ֆայլը հնարավոր չէ բացել: Հնարավոր չէ ապատեղադրել +UninstallUnsupportedVer=Ապատեղադրելու "%1" մատյանի ֆայլը անճանաչելի է ապատեղադրող ծրագրի այս տարբերակի համար։ Հնարավոր չէ ապատեղադրել +UninstallUnknownEntry=Անհայտ գրառում է (%1)՝ հայնաբերվել ապատեղադրելու մատյանում +ConfirmUninstall=Ապատեղադրե՞լ %1-ը և նրա բոլոր բաղադրիչները։ +UninstallOnlyOnWin64=Հնարավոր է ապատեղադրել միայն 64 բիթանոց Windows-ում։ +OnlyAdminCanUninstall=Հնարավոր է ապատեղադրել միայն Ադմինի իրավունքներով։ +UninstallStatusLabel=Խնդրում ենք սպասել, մինչև %1-ը ապատեղադրվում է Ձեր համակարգչից։ +UninstalledAll=%1 ծրագիրը ապատեղադրվել է համակարգչից։ +UninstalledMost=%1-ը ապատեղադրվեց Ձեր համակարգչից։%n%nՈրոշ ֆայլեր հնարավոր չեղավ հեռացնել։ Ինքներդ հեռացրեք դրանք։ +UninstalledAndNeedsRestart=%1-ի ապատեղադրումը ավարտելու համար պետք է վերամեկնարկել համակարգիչը։%n%nՎերամեկնարկե՞լ։ +UninstallDataCorrupted="%1" ֆայլը վնասված է։ Հնարավոր չէ ապատեղադրել + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Հեռացնե՞լ համատեղ օգտագործվող ֆայլը։ +ConfirmDeleteSharedFile2=Համակարգը նշում է, որ հետևյալ համատեղ օգտագործվող ֆայլը այլևս չի օգտագործվում այլ ծրագրի կողմից։ Ապատեղադրե՞լ այն։ %n%nԵթե համոզված չեք սեղմեք «Ոչ»։ +SharedFileNameLabel=Ֆայլի անուն. +SharedFileLocationLabel=Տեղադրություն. +WizardUninstalling=Ապատեղադրելու վիճակ +StatusUninstalling=%1-ի ապատեղադրում... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=%1-ի տեղադրում։ +ShutdownBlockReasonUninstallingApp=%1-ի ապատեղադրում։ + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 տարբերակ՝ %2 +AdditionalIcons=Լրացուցիչ դյուրանցումներ +CreateDesktopIcon=Ստեղծել դյուրանցում &Աշխատասեղանին +CreateQuickLaunchIcon=Ստեղծել դյուրանցում &Արագ թողարկման գոտում +ProgramOnTheWeb=%1-ի վեբ կայքը +UninstallProgram=%1-ի ապատեղադրում +LaunchProgram=Բացել %1-ը +AssocFileExtension=Հա&մակցել %1-ը %2 ֆայլերի հետ։ +AssocingFileExtension=%1-ը համակցվում է %2 ընդլայնումով ֆայլերի հետ... +AutoStartProgramGroupDescription=Ինքնամեկնարկ. +AutoStartProgram=Ինքնաբար մեկնարկել %1-ը +AddonHostProgramNotFound=%1 չի կարող տեղադրվել Ձեր ընտրած պանակում։%n%nՇարունակե՞լ։ + diff --git a/installer/innosetup/Languages/Bosnian.isl b/installer/innosetup/Languages/Bosnian.isl index 93488c918..d3080c044 100644 --- a/installer/innosetup/Languages/Bosnian.isl +++ b/installer/innosetup/Languages/Bosnian.isl @@ -1,9 +1,18 @@ -; *** Inno Setup version 5.5.3+ Bosnian messages *** +; *** Inno Setup version 6.1.0+ Bosnian messages *** +; Translated by: Almedin Maleškić (malmedin@gmail.com) +; Based on translation by Kenan Dervisevic (kenan3008@gmail.com) ; -; Bosnian translation by Kenan Dervisevic (kenan3008@gmail.com) +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ ; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). [LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. LanguageName=Bosanski LanguageID=$141a LanguageCodePage=1250 @@ -29,43 +38,53 @@ UninstallAppFullTitle=%1 Deinstalacija ; *** Misc. common InformationTitle=Informacija ConfirmTitle=Potvrda -ErrorTitle=Greka +ErrorTitle=Greška ; *** SetupLdr messages -SetupLdrStartupMessage=Zapoeli ste instalaciju programa %1. elite li nastaviti? +SetupLdrStartupMessage=Započeli ste instalaciju programa %1. Želite li nastaviti? LdrCannotCreateTemp=Ne mogu kreirati privremenu datoteku. Instalacija prekinuta -LdrCannotExecTemp=Ne mogu izvriti datoteku u privremenom folderu. Instalacija prekinuta +LdrCannotExecTemp=Ne mogu izvršiti datoteku u privremenom folderu. Instalacija prekinuta +HelpTextNote= ; *** Startup error messages -LastErrorMessage=%1.%n%nGreka %2: %3 -SetupFileMissing=Datoteka %1 se ne nalazi u instalacijskom folderu. Molimo vas da rijeite problem ili nabavite novu kopiju programa. -SetupFileCorrupt=Instalacijske datoteke sadre greku. Molimo vas da nabavite novu kopiju programa. -SetupFileCorruptOrWrongVer=Instalacijske datoteke sadre greku, ili nisu kompatibilne sa ovom verzijom instalacije. Molimo vas rijeite problem ili nabavite novu kopiju programa. -InvalidParameter=Neispravan parametar je proslijeen komandnoj liniji:%n%n%1 -SetupAlreadyRunning=Instalacija je ve pokrenuta. -WindowsVersionNotSupported=Ovaj program ne podrava verziju Windowsa koja je instalirana na ovom raunaru. +LastErrorMessage=%1.%n%nGreška %2: %3 +SetupFileMissing=Datoteka %1 se ne nalazi u instalacijskom folderu. Molimo vas da riješite problem ili nabavite novu kopiju programa. +SetupFileCorrupt=Instalacijske datoteke sadrže grešku. Molimo vas da nabavite novu kopiju programa. +SetupFileCorruptOrWrongVer=Instalacijske datoteke sadrže grešku, ili nisu kompatibilne sa ovom verzijom instalacije. Molimo vas riješite problem ili nabavite novu kopiju programa. +InvalidParameter=Neispravan parametar je proslijeđen komandnoj liniji:%n%n%1 +SetupAlreadyRunning=Instalacija je već pokrenuta. +WindowsVersionNotSupported=Ovaj program ne podržava verziju Windowsa koja je instalirana na ovom računaru. WindowsServicePackRequired=Ovaj program zahtjeva %1 Service Pack %2 ili noviji. NotOnThisPlatform=Ovaj program ne radi na %1. OnlyOnThisPlatform=Ovaj program se mora pokrenuti na %1. -OnlyOnTheseArchitectures=Ovaj program se moe instalirati samo na verzijama Windowsa napravljenim za sljedee arhitekture procesora:%n%n%1 -MissingWOW64APIs=Verzija Windowsa koju koristite ne sadri funkcionalnosti potrebne da bi instalacijski program mogao instalirati 64-bitnu verziju. Da bi ispravili taj problem, molimo instalirajte Service Pack %1. +OnlyOnTheseArchitectures=Ovaj program se može instalirati samo na verzijama Windowsa napravljenim za sljedeće arhitekture procesora:%n%n%1 WinVersionTooLowError=Ovaj program zahtjeva %1 verzije %2 ili noviju. -WinVersionTooHighError=Ovaj program se ne moe instalirati na %1 verziji %2 ili novijoj. +WinVersionTooHighError=Ovaj program se ne može instalirati na %1 verziji %2 ili novijoj. AdminPrivilegesRequired=Morate imati administratorska prava pri instaliranju ovog programa. -PowerUserPrivilegesRequired=Morate imati administratorska prava ili biti lan grupe Power Users prilikom instaliranja ovog programa. -SetupAppRunningError=Instalacija je detektovala da je %1 pokrenut.%n%nMolimo zatvorite program i sve njegove kopije i potom kliknite Dalje za nastavak ili Odustani za prekid. -UninstallAppRunningError=Deinstalacija je detektovala da je %1 trenutno pokrenut.%n%nMolimo zatvorite program i sve njegove kopije i potom kliknite Dalje za nastavak ili Odustani za prekid. +PowerUserPrivilegesRequired=Morate imati administratorska prava ili biti član grupe Power Users prilikom instaliranja ovog programa. +SetupAppRunningError=Instalacija je detektovala da je %1 pokrenut.%n%nMolimo zatvorite program i sve njegove kopije i potom kliknite Dalje za nastavak ili Otkaži za prekid. +UninstallAppRunningError=Deinstalacija je detektovala da je %1 trenutno pokrenut.%n%nMolimo zatvorite program i sve njegove kopije i potom kliknite Dalje za nastavak ili Otkaži za prekid. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Odaberite način instalacije +PrivilegesRequiredOverrideInstruction=Odaberite način instalacije +PrivilegesRequiredOverrideText1=%1 može biti instaliran za sve korisnike (zahtijeva administrativne privilegije) ili samo za vas. +PrivilegesRequiredOverrideText2=%1 može da se instalira samo za vas ili za sve korisnike (zahtijeva administrativne privilegije). +PrivilegesRequiredOverrideAllUsers=Instaliraj za &sve korisnike +PrivilegesRequiredOverrideAllUsersRecommended=Instaliraj za &sve korisnike (preporučeno) +PrivilegesRequiredOverrideCurrentUser=Instaliraj samo za &mene +PrivilegesRequiredOverrideCurrentUserRecommended=Instaliraj samo za &mene (preporučeno) ; *** Misc. errors ErrorCreatingDir=Instalacija nije mogla kreirati folder "%1" -ErrorTooManyFilesInDir=Instalacija nije mogla kreirati datoteku u folderu "%1" zato to on sadri previe datoteka +ErrorTooManyFilesInDir=Instalacija nije mogla kreirati datoteku u folderu "%1" zato što on sadrži previše datoteka ; *** Setup common messages ExitSetupTitle=Prekid instalacije -ExitSetupMessage=Instalacija nije zavrena. Ako sada izaete, program nee biti instaliran.%n%nInstalaciju moete pokrenuti kasnije u sluaju da je elite zavriti.%n%nPrekid instalacije? +ExitSetupMessage=Instalacija nije završena. Ako sada izađete, program neće biti instaliran.%n%nInstalaciju možete pokrenuti kasnije u slučaju da je želite završiti.%n%nPrekid instalacije? AboutSetupMenuItem=&O instalaciji... AboutSetupTitle=O instalaciji -AboutSetupMessage=%1 verzija %2%n%3%n%n%1 poetna stranica:%n%4 +AboutSetupMessage=%1 verzija %2%n%3%n%n%1 početna stranica:%n%4 AboutSetupNote= TranslatorNote= @@ -74,233 +93,271 @@ ButtonBack=< Na&zad ButtonNext=Da&lje > ButtonInstall=&Instaliraj ButtonOK=U redu -ButtonCancel=Otkai +ButtonCancel=Otkaži ButtonYes=&Da ButtonYesToAll=Da za &sve ButtonNo=&Ne ButtonNoToAll=N&e za sve -ButtonFinish=&Zavri +ButtonFinish=&Završi ButtonBrowse=&Izaberi... ButtonWizardBrowse=Iza&beri... ButtonNewFolder=&Napravi novi folder ; *** "Select Language" dialog messages SelectLanguageTitle=Izaberite jezik instalacije -SelectLanguageLabel=Izaberite jezik koji elite koristiti pri instalaciji: +SelectLanguageLabel=Izaberite jezik koji želite koristiti pri instalaciji: ; *** Common wizard text -ClickNext=Kliknite na Dalje za nastavak ili Otkai za prekid instalacije. +ClickNext=Kliknite na Dalje za nastavak ili Otkaži za prekid instalacije. BeveledLabel= BrowseDialogTitle=Izaberite folder BrowseDialogLabel=Izaberite folder iz liste ispod, pa onda kliknite na U redu. NewFolderName=Novi folder ; *** "Welcome" wizard page -WelcomeLabel1=Dobro doli u instalaciju programa [name] -WelcomeLabel2=Ovaj program e instalirati [name/ver] na va raunar.%n%nPreporuujemo da zatvorite sve druge programe prije nastavka i da privremeno onemoguite va antivirus i firewall. +WelcomeLabel1=Dobro došli u instalaciju programa [name] +WelcomeLabel2=Ovaj program će instalirati [name/ver] na vaš računar.%n%nPreporučujemo da zatvorite sve druge programe prije nastavka i da privremeno onemogućite vaš antivirus i firewall. ; *** "Password" wizard page -WizardPassword=ifra -PasswordLabel1=Instalacija je zatiena ifrom. -PasswordLabel3=Upiite ifru i kliknite Dalje za nastavak. ifre su osjetljive na mala i velika slova. -PasswordEditLabel=&ifra: -IncorrectPassword=Upisali ste pogrenu ifru. Pokuajte ponovo. +WizardPassword=Šifra +PasswordLabel1=Instalacija je zaštićena šifrom. +PasswordLabel3=Upišite šifru i kliknite Dalje za nastavak. Šifre su osjetljive na mala i velika slova. +PasswordEditLabel=&Šifra: +IncorrectPassword=Upisali ste pogrešnu šifru. Pokušajte ponovo. ; *** "License Agreement" wizard page -WizardLicense=Ugovor o koritenju -LicenseLabel=Molimo vas da, prije nastavka, paljivo proitajte sljedee informacije. -LicenseLabel3=Molimo vas da paljivo proitate Ugovor o koritenju. Morate prihvatiti uslove ugovora kako biste mogli nastaviti s instalacijom. +WizardLicense=Ugovor o korištenju +LicenseLabel=Molimo vas da, prije nastavka, pažljivo pročitajte sljedeće informacije. +LicenseLabel3=Molimo vas da pažljivo pročitate Ugovor o korištenju. Morate prihvatiti uslove ugovora kako biste mogli nastaviti s instalacijom. LicenseAccepted=&Prihvatam ugovor LicenseNotAccepted=&Ne prihvatam ugovor ; *** "Information" wizard pages WizardInfoBefore=Informacija -InfoBeforeLabel=Molimo vas da, prije nastavka, proitate sljedee informacije. +InfoBeforeLabel=Molimo vas da, prije nastavka, pročitate sljedeće informacije. InfoBeforeClickLabel=Kada budete spremni nastaviti instalaciju, kliknite na Dalje. WizardInfoAfter=Informacija -InfoAfterLabel=Molimo vas da, prije nastavka, proitate sljedee informacije. +InfoAfterLabel=Molimo vas da, prije nastavka, pročitate sljedeće informacije. InfoAfterClickLabel=Kada budete spremni nastaviti instalaciju, kliknite na Dalje. ; *** "User Information" wizard page WizardUserInfo=Informacije o korisniku -UserInfoDesc=Upiite vae line informacije. +UserInfoDesc=Upišite vaše lične informacije. UserInfoName=&Ime korisnika: UserInfoOrg=&Organizacija: UserInfoSerial=&Serijski broj: UserInfoNameRequired=Morate upisati ime. ; *** "Select Destination Location" wizard page -WizardSelectDir=Odaberite odredini folder -SelectDirDesc=Gdje elite da instalirate [name]? -SelectDirLabel3=Instalacija e instalirati [name] u sljedei folder. -SelectDirBrowseLabel=Za nastavak, kliknite Dalje. Ako elite izabrati drugi folder, kliknite Izaberi. -DiskSpaceMBLabel=Ovaj program zahtjeva najmanje [mb] MB slobodnog prostora na disku. -CannotInstallToNetworkDrive=Instalacija nije mogua na mrenom disku. -CannotInstallToUNCPath=Instalacija nije mogua za UNC putanju. +WizardSelectDir=Odaberite odredišni folder +SelectDirDesc=Gdje želite da instalirate [name]? +SelectDirLabel3=Instalacija će instalirati [name] u sljedeći folder. +SelectDirBrowseLabel=Za nastavak, kliknite Dalje. Ako želite izabrati drugi folder, kliknite Izaberi. +DiskSpaceGBLabel=Potrebno je najmanje [gb] GB slobodnog prostora na disku. +DiskSpaceMBLabel=Potrebno je najmanje [mb] MB slobodnog prostora na disku. +CannotInstallToNetworkDrive=Instalacija nije moguća na mrežnom disku. +CannotInstallToUNCPath=Instalacija nije moguća za UNC putanju. InvalidPath=Morate unijeti punu putanju zajedno sa slovom diska; npr:%n%nC:\APP%n%nili UNC putanju u obliku:%n%n\\server\share InvalidDrive=Disk ili UNC share koji ste odabrali ne postoji ili je nedostupan. Odaberite neki drugi. DiskSpaceWarningTitle=Nedovoljno prostora na disku -DiskSpaceWarning=Instalacija zahtjeva bar %1 KB slobodnog prostora, a odabrani disk ima samo %2 KB na raspolaganju.%n%nDa li elite nastaviti? +DiskSpaceWarning=Instalacija zahtjeva bar %1 KB slobodnog prostora, a odabrani disk ima samo %2 KB na raspolaganju.%n%nŽelite li nastaviti? DirNameTooLong=Naziv ili putanja do foldera su predugi. InvalidDirName=Naziv foldera nije ispravan. -BadDirName32=Naziv foldera ne smije sadravati niti jedan od sljedeih znakova:%n%n%1 +BadDirName32=Naziv foldera ne smije sadržavati niti jedan od sljedećih znakova:%n%n%1 DirExistsTitle=Folder postoji -DirExists=Folder:%n%n%1%n%nve postoji. elite li i dalje izvriti instalaciju u njega? +DirExists=Folder:%n%n%1%n%nveć postoji. Želite li i dalje izvršiti instalaciju u njega? DirDoesntExistTitle=Folder ne postoji -DirDoesntExist=Folder:%n%n%1%n%nne postoji. elite li ga napraviti? +DirDoesntExist=Folder:%n%n%1%n%nne postoji. Želite li ga napraviti? ; *** "Select Components" wizard page WizardSelectComponents=Odaberite komponente -SelectComponentsDesc=Koje komponente elite instalirati? -SelectComponentsLabel2=Odaberite komponente koje elite instalirati ili uklonite kvaicu pored komponenti koje ne elite. Kliknite Dalje kad budete spremni da nastavite. +SelectComponentsDesc=Koje komponente želite instalirati? +SelectComponentsLabel2=Odaberite komponente koje želite instalirati ili uklonite kvačicu pored komponenti koje ne želite. Kliknite Dalje kad budete spremni da nastavite. FullInstallation=Puna instalacija ; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) CompactInstallation=Kompaktna instalacija -CustomInstallation=Instalacija prema elji +CustomInstallation=Instalacija prema želji NoUninstallWarningTitle=Komponente postoje -NoUninstallWarning=Instalacija je detektovala da na vaem raunaru ve postoje sljedee komponente:%n%n%1%n%nAko ove komponente ne odaberete, nee doi do njihove deinstalacije.%n%nelite li ipak nastaviti? +NoUninstallWarning=Instalacija je detektovala da na vašem računaru već postoje sljedeće komponente:%n%n%1%n%nAko ove komponente ne odaberete, neće doći do njihove deinstalacije.%n%nŽelite li ipak nastaviti? ComponentSize1=%1 KB ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel=Trenutni izbor zahtjeva bar [mb] MB prostora na disku. +ComponentsDiskSpaceGBLabel=Trenutni izbor zahtijeva najmanje [mb] GB prostora na disku. +ComponentsDiskSpaceMBLabel=Trenutni izbor zahtijeva najmanje [mb] MB prostora na disku. ; *** "Select Additional Tasks" wizard page WizardSelectTasks=Izaberite dodatne radnje -SelectTasksDesc=Koje dodatne radnje elite da se izvre? -SelectTasksLabel2=Izaberite radnje koje e se izvriti tokom instalacije programa [name], onda kliknite Dalje. +SelectTasksDesc=Koje dodatne radnje želite da se izvrše? +SelectTasksLabel2=Izaberite radnje koje će se izvršiti tokom instalacije programa [name], onda kliknite Dalje. ; *** "Select Start Menu Folder" wizard page WizardSelectProgramGroup=Izaberite programsku grupu -SelectStartMenuFolderDesc=Gdje instalacija treba da napravi preice? -SelectStartMenuFolderLabel3=Izaberite folder iz Start menija u koji elite da instalacija kreira preicu, a zatim kliknite na Dalje. -SelectStartMenuFolderBrowseLabel=Za nastavak, kliknite Dalje. Ako elite da izaberete drugi folder, kliknite Izaberi. +SelectStartMenuFolderDesc=Gdje instalacija treba da napravi prečice? +SelectStartMenuFolderLabel3=Izaberite folder iz Start menija u koji želite da instalacija kreira prečicu, a zatim kliknite na Dalje. +SelectStartMenuFolderBrowseLabel=Za nastavak, kliknite Dalje. Ako želite da izaberete drugi folder, kliknite Izaberi. MustEnterGroupName=Morate unijeti ime programske grupe. GroupNameTooLong=Naziv foldera ili putanje je predug. InvalidGroupName=Naziv foldera nije ispravan. -BadGroupName=Naziv foldera ne smije sadravati niti jedan od sljedeih znakova:%n%n%1 +BadGroupName=Naziv foldera ne smije sadržavati niti jedan od sljedećih znakova:%n%n%1 NoProgramGroupCheck2=&Ne kreiraj programsku grupu ; *** "Ready to Install" wizard page WizardReady=Spreman za instalaciju -ReadyLabel1=Sada smo spremni za instalaciju [name] na va raunar. -ReadyLabel2a=Kliknite na Instaliraj ako elite instalirati program ili na Nazad ako elite pregledati ili promjeniti postavke. -ReadyLabel2b=Kliknite na Instaliraj ako elite nastaviti sa instalacijom programa. +ReadyLabel1=Sada smo spremni za instalaciju [name] na vaš računar. +ReadyLabel2a=Kliknite na Instaliraj ako želite instalirati program ili na Nazad ako želite pregledati ili promjeniti postavke. +ReadyLabel2b=Kliknite na Instaliraj ako želite nastaviti sa instalacijom programa. ReadyMemoUserInfo=Informacije o korisniku: -ReadyMemoDir=Odredini folder: +ReadyMemoDir=Odredišni folder: ReadyMemoType=Tip instalacije: ReadyMemoComponents=Odabrane komponente: ReadyMemoGroup=Programska grupa: ReadyMemoTasks=Dodatne radnje: +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Preuzimanje dodatnih datoteka... +ButtonStopDownload=&Zaustavi preuzimanje +StopDownload=Jeste li sigurni da želite zaustaviti preuzimanje? +ErrorDownloadAborted=Preuzimanje je prekinuto +ErrorDownloadFailed=Preuzimanje nije uspjelo: %1 %2 +ErrorDownloadSizeFailed=Dobijanje veličine nije uspjelo: %1 %2 +ErrorFileHash1=Heš datoteke nije uspio: %1 +ErrorFileHash2=Neispravan heš datoteke: očekivan %1, pronađen %2 +ErrorProgress=Neispravan napredak: %1 od %2 +ErrorFileSize=Neispravna veličina datoteke: očekivana %1, pronađena %2 + ; *** "Preparing to Install" wizard page WizardPreparing=Pripremam instalaciju -PreparingDesc=Pripreme za instalaciju [name] na va raunar. -PreviousInstallNotCompleted=Instalacija/deinstalacija prethodnog programa nije zavrena. Morate restartovati va raunar kako bi zavrili tu instalaciju.%n%nNakon toga, ponovno pokrenite ovaj program kako bi dovrili instalaciju za [name]. -CannotContinue=Instalacija ne moe nastaviti. Molimo vas da kliknete na Odustani za izlaz. -ApplicationsFound=Sljedee aplikacije koriste datoteke koje ova instalacija treba da nadogradi. Preporuujemo vam da omoguite instalaciji da automatski zatvori ove aplikacije. -ApplicationsFound2=Sljedee aplikacije koriste datoteke koje ova instalacija treba da nadogradi. Preporuujemo vam da omoguite instalaciji da automatski zatvori ove aplikacije. Nakon to se sve zavri, bit e izvren pokuaj ponovnog pokretanja ovih aplikacija. +PreparingDesc=Pripreme za instalaciju [name] na vaš računar. +PreviousInstallNotCompleted=Instalacija/deinstalacija prethodnog programa nije završena. Morate restartovati vaš računar kako bi završili tu instalaciju.%n%nNakon toga, ponovno pokrenite ovaj program kako bi dovršili instalaciju za [name]. +CannotContinue=Instalacija ne može nastaviti. Molimo vas da kliknete na Otkaži za izlaz. +ApplicationsFound=Sljedeće aplikacije koriste datoteke koje ova instalacija treba da nadogradi. Preporučujemo vam da omogućite instalaciji da automatski zatvori ove aplikacije. +ApplicationsFound2=Sljedeće aplikacije koriste datoteke koje ova instalacija treba da nadogradi. Preporučujemo vam da omogućite instalaciji da automatski zatvori ove aplikacije. Nakon što se sve završi, bit će izvršen pokušaj ponovnog pokretanja ovih aplikacija. CloseApplications=&Automatski zatvori aplikacije DontCloseApplications=&Ne zatvaraj aplikacije -ErrorCloseApplications=Instalacija nije mogla automatski zatvoriti sve aplikacije. Prije nego nastavite, preporuujemo vam da zatvorite sve aplikacije koje koriste datoteke koje e ova instalacija trebati da aurira. +ErrorCloseApplications=Instalacija nije mogla automatski zatvoriti sve aplikacije. Prije nego nastavite, preporučujemo vam da zatvorite sve aplikacije koje koriste datoteke koje će ova instalacija trebati da ažurira. +PrepareToInstallNeedsRestart=Instalacija mora ponovo pokrenuti vaš računar. Nakon ponovnog pokretanja vašeg računara, pokrenite instalaciju ponovo da biste završili instalaciju [name].%n%nŽelite li da ponovo pokrenete računar sada? ; *** "Installing" wizard page WizardInstalling=Instaliram -InstallingLabel=Priekajte dok se ne zavri instalacija programa [name] na va raunar. +InstallingLabel=Pričekajte dok se ne završi instalacija programa [name] na vaš računar. ; *** "Setup Completed" wizard page -FinishedHeadingLabel=Zavravam instalaciju [name] -FinishedLabelNoIcons=Instalacija programa [name] je zavrena. -FinishedLabel=Instalacija programa [name] je zavrena. Program moete pokrenuti koristei instalirane ikone. -ClickFinish=Kliknite na Zavri da biste izali iz instalacije. -FinishedRestartLabel=Da biste instalaciju programa [name] zavrili, potrebno je restartovati raunar. elite li to sada uiniti? -FinishedRestartMessage=Zavretak instalacije programa [name] zahtjeva restart vaeg raunara.%n%nelite li to sada uiniti? -ShowReadmeCheck=Da, elim proitati README datoteku. -YesRadio=&Da, restartuj raunar sada -NoRadio=&Ne, restartovat u raunar kasnije +FinishedHeadingLabel=Završavam instalaciju [name] +FinishedLabelNoIcons=Instalacija programa [name] je završena. +FinishedLabel=Instalacija programa [name] je završena. Program možete pokrenuti koristeći instalirane ikone. +ClickFinish=Kliknite na Završi da biste izašli iz instalacije. +FinishedRestartLabel=Da biste instalaciju programa [name] završili, potrebno je restartovati računar. Želite li to sada učiniti? +FinishedRestartMessage=Završetak instalacije programa [name] zahtjeva restart vašeg računara.%n%nŽelite li to sada učiniti? +ShowReadmeCheck=Da, želim pročitati README datoteku. +YesRadio=&Da, restartuj računar sada +NoRadio=&Ne, restartovat ću računar kasnije ; used for example as 'Run MyProg.exe' RunEntryExec=Pokreni %1 ; used for example as 'View Readme.txt' -RunEntryShellExec=Proitaj %1 +RunEntryShellExec=Pročitaj %1 ; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=Instalacija treba sljedei disk +ChangeDiskTitle=Instalacija treba sljedeći disk SelectDiskLabel2=Molimo ubacite Disk %1 i kliknite U redu.%n%nAko se datoteke na ovom disku nalaze u drugom folderu a ne u onom prikazanom ispod, unesite ispravnu putanju ili kliknite na Izaberi. PathLabel=&Putanja: -FileNotInDir2=Datoteka "%1" ne postoji u "%2". Molimo vas ubacite odgovorajui disk ili odaberete drugi folder. -SelectDirectoryLabel=Molimo odaberite lokaciju sljedeeg diska. +FileNotInDir2=Datoteka "%1" ne postoji u "%2". Molimo vas ubacite odgovorajući disk ili odaberete drugi folder. +SelectDirectoryLabel=Molimo odaberite lokaciju sljedećeg diska. ; *** Installation phase messages -SetupAborted=Instalacija nije zavrena.%n%nMolimo vas da rijeite problem i opet pokrenete instalaciju. -EntryAbortRetryIgnore=Kliknite na Retry da pokuate opet, Ignore da nastavite, ili Abort da prekinete instalaciju. +SetupAborted=Instalacija nije završena.%n%nMolimo vas da riješite problem i ponovo pokrenete instalaciju. +AbortRetryIgnoreSelectAction=Izaberi radnju +AbortRetryIgnoreRetry=&Pokušaj ponovo +AbortRetryIgnoreIgnore=&Zanemari grešku i nastavi +AbortRetryIgnoreCancel=Prekini instalaciju ; *** Installation status messages StatusClosingApplications=Zatvaram aplikacije... StatusCreateDirs=Kreiram foldere... StatusExtractFiles=Raspakujem datoteke... -StatusCreateIcons=Kreiram preice... +StatusCreateIcons=Kreiram prečice... StatusCreateIniEntries=Kreiram INI datoteke... StatusCreateRegistryEntries=Kreiram podatke za registracijsku bazu... StatusRegisterFiles=Registrujem datoteke... StatusSavingUninstall=Snimam deinstalacijske informacije... -StatusRunProgram=Zavravam instalaciju... +StatusRunProgram=Završavam instalaciju... StatusRestartingApplications=Restartujem aplikaciju... -StatusRollback=Ponitavam promjene... +StatusRollback=Poništavam promjene... ; *** Misc. errors -ErrorInternal2=Interna greka: %1 +ErrorInternal2=Interna greška: %1 ErrorFunctionFailedNoCode=%1 nije uspjelo ErrorFunctionFailed=%1 nije uspjelo; kod %2 ErrorFunctionFailedWithMessage=%1 nije uspjelo; kod %2.%n%3 ErrorExecutingProgram=Ne mogu pokrenuti datoteku:%n%1 ; *** Registry errors -ErrorRegOpenKey=Greka pri otvaranju registracijskog kljua:%n%1\%2 -ErrorRegCreateKey=Greka pri kreiranju registracijskog kljua:%n%1\%2 -ErrorRegWriteKey=Greka pri zapisivanju registracijskog kljua:%n%1\%2 +ErrorRegOpenKey=Greška pri otvaranju registracijskog ključa:%n%1\%2 +ErrorRegCreateKey=Greška pri kreiranju registracijskog ključa:%n%1\%2 +ErrorRegWriteKey=Greška pri zapisivanju registracijskog ključa:%n%1\%2 ; *** INI errors -ErrorIniEntry=Greka pri kreiranju INI podataka u datoteci "%1". +ErrorIniEntry=Greška pri kreiranju INI podataka u datoteci "%1". ; *** File copying errors -FileAbortRetryIgnore=Kliknite Retry da pokuate ponovo, Ignore da preskoite ovu datoteku (nije preporueno), ili Abort da prekinete instalaciju. -FileAbortRetryIgnore2=Kliknite Retry da pokuate ponovo, Ignore da preskoite ovu datoteku (nije preporueno), ili Abort da prekinete instalaciju. -SourceIsCorrupted=Izvorna datoteka je oteena +FileAbortRetryIgnoreSkipNotRecommended=&Preskočite ovu datoteku (nije preporučeno) +FileAbortRetryIgnoreIgnoreNotRecommended=&Zanemari grešku i nastavi (nije preporučeno) +SourceIsCorrupted=Izvorna datoteka je oštećena SourceDoesntExist=Izvorna datoteka "%1" ne postoji -ExistingFileReadOnly=Postojea datoteka je oznaena kao samo za itanje.%n%nKliknite Retry da uklonite ovu oznaku i pokuate ponovo, Ignore da preskoite ovu datoteku, ili Abort da prekinete instalaciju. -ErrorReadingExistingDest=Dolo je do greke prilikom pokuaja itanja postojee datoteke: -FileExists=Datoteka ve postoji.%n%nelite li pisati preko nje? -ExistingFileNewer=Postojea datoteka je novija od one koju pokuavate instalirati. Preporuujemo vam da zadrite postojeu datoteku.%n%nelite li zadrati postojeu datoteku? -ErrorChangingAttr=Pojavila se greka prilikom pokuaja promjene atributa postojee datoteke: -ErrorCreatingTemp=Pojavila se greka prilikom pokuaja kreiranja datoteke u odredinom folderu: -ErrorReadingSource=Pojavila se greka prilikom pokuaja itanja izvorne datoteke: -ErrorCopying=Pojavila se greka prilikom pokuaja kopiranja datoteke: -ErrorReplacingExistingFile=Pojavila se greka prilikom pokuaja zamjene datoteke: +ExistingFileReadOnly2=Postojeća datoteka ne može biti zamijenjena jer je označena samo za čitanje. +ExistingFileReadOnlyRetry=&Uklonite atribut samo za čitanje i pokušajte ponovo +ExistingFileReadOnlyKeepExisting=&Zadržite postojeću datoteku +ErrorReadingExistingDest=Došlo je do greške prilikom pokušaja čitanja postojeće datoteke: +FileExistsSelectAction=Izaberite radnju +FileExists2=Datoteka već postoji. +FileExistsOverwriteExisting=&Zamijeni postojeću datoteku +FileExistsKeepExisting=&Zadrži postojeću datoteku +FileExistsOverwriteOrKeepAll=&Uradi ovo i za sljedeća neslaganja +ExistingFileNewerSelectAction=Izaberi radnju +ExistingFileNewer2=Postojeća datoteka je novija od one koja se pokušava instalirati. +ExistingFileNewerOverwriteExisting=&Zamijeni postojeću datoteku +ExistingFileNewerKeepExisting=&Zadrži postojeću datoteku (preporučeno) +ExistingFileNewerOverwriteOrKeepAll=&Uradi ovo i za sljedeća neslaganja +ErrorChangingAttr=Pojavila se greška prilikom pokušaja promjene atributa postojeće datoteke: +ErrorCreatingTemp=Pojavila se greška prilikom pokušaja kreiranja datoteke u odredišnom folderu: +ErrorReadingSource=Pojavila se greška prilikom pokušaja čitanja izvorne datoteke: +ErrorCopying=Pojavila se greška prilikom pokušaja kopiranja datoteke: +ErrorReplacingExistingFile=Pojavila se greška prilikom pokušaja zamjene datoteke: ErrorRestartReplace=Ponovno pokretanje i zamjena nije uspjela: -ErrorRenamingTemp=Pojavila se greka prilikom pokuaja preimenovanja datoteke u odredinom folderu: +ErrorRenamingTemp=Pojavila se greška prilikom pokušaja preimenovanja datoteke u odredišnom folderu: ErrorRegisterServer=Ne mogu registrovati DLL/OCX: %1 -ErrorRegSvr32Failed=RegSvr32 nije ispravno izvren, kod na kraju izvravanja %1 +ErrorRegSvr32Failed=RegSvr32 nije ispravno izvršen, kod na kraju izvršavanja %1 ErrorRegisterTypeLib=Ne mogu registrovati tip biblioteke: %1 +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Svi korisnici +UninstallDisplayNameMarkCurrentUser=Trenutni korisnik + ; *** Post-installation errors -ErrorOpeningReadme=Pojavila se greka prilikom pokuaja otvaranja README datoteke. -ErrorRestartingComputer=Instalacija ne moe restartovati va raunar. Molimo vas da to uinite runo. +ErrorOpeningReadme=Pojavila se greška prilikom pokušaja otvaranja README datoteke. +ErrorRestartingComputer=Instalacija ne može restartovati vaš računar. Molimo vas da to učinite ručno. ; *** Uninstaller messages UninstallNotFound=Datoteka "%1" ne postoji. Deinstalacija prekinuta. -UninstallOpenError=Datoteka "%1" se ne moe otvoriti. Deinstalacija nije mogua -UninstallUnsupportedVer=Deinstalacijska log datoteka "%1" je u formatu koji nije prepoznat od ove verzije deinstalera. Nije mogua deinstalacija +UninstallOpenError=Datoteka "%1" se ne može otvoriti. Deinstalacija nije moguća +UninstallUnsupportedVer=Deinstalacijska log datoteka "%1" je u formatu koji nije prepoznat od ove verzije deinstalera. Nije moguća deinstalacija UninstallUnknownEntry=Nepoznat zapis (%1) je pronadjen u deinstalacijskoj log datoteci -ConfirmUninstall=Da li ste sigurni da elite ukloniti %1 i sve njegove komponente? -UninstallOnlyOnWin64=Ovaj program se moe deinstalirati samo na 64-bitnom Windowsu. -OnlyAdminCanUninstall=Ova instalacija moe biti uklonjena samo od korisnika sa administratorskim privilegijama. -UninstallStatusLabel=Molimo priekajte dok %1 ne bude uklonjen s vaeg raunara. -UninstalledAll=Program %1 je uspjeno uklonjen sa vaeg raunara. -UninstalledMost=Deinstalacija programa %1 je zavrena.%n%nNeke elemente nije bilo mogue ukloniti. Molimo vas da to uinite runo. -UninstalledAndNeedsRestart=Da bi zavrili deinstalaciju %1, Va raunar morate restartati%n%nelite li to uiniti sada? -UninstallDataCorrupted="%1" datoteka je oteena. Deinstalacija nije mogua. +ConfirmUninstall=Jeste li sigurni da želite ukloniti %1 i sve njegove komponente? +UninstallOnlyOnWin64=Ovaj program se može deinstalirati samo na 64-bitnom Windowsu. +OnlyAdminCanUninstall=Ova instalacija može biti uklonjena samo od korisnika sa administratorskim privilegijama. +UninstallStatusLabel=Molimo pričekajte dok %1 ne bude uklonjen s vašeg računara. +UninstalledAll=Program %1 je uspješno uklonjen sa vašeg računara. +UninstalledMost=Deinstalacija programa %1 je završena.%n%nNeke elemente nije bilo moguće ukloniti. Molimo vas da to učinite ručno. +UninstalledAndNeedsRestart=Da bi završili deinstalaciju %1, Vaš računar morate restartati%n%nŽelite li to učiniti sada? +UninstallDataCorrupted="%1" datoteka je oštećena. Deinstalacija nije moguća. ; *** Uninstallation phase messages ConfirmDeleteSharedFileTitle=Ukloni dijeljenu datoteku -ConfirmDeleteSharedFile2=Sistem smatra da sljedee dijeljene datoteke ne koristi nijedan drugi program. elite li ukloniti te dijeljene datoteke?%n%nAko neki programi i dalje koriste ove datoteke, a one se obriu, ti programi nee raditi ispravno. Ako niste sigurni, odaberite Ne. Ostavljanje datoteka nee uzrokovati tetu vaem sistemu. +ConfirmDeleteSharedFile2=Sistem smatra da sljedeće dijeljene datoteke ne koristi nijedan drugi program. Želite li ukloniti te dijeljene datoteke?%n%nAko neki programi i dalje koriste ove datoteke, a one se obrišu, ti programi neće raditi ispravno. Ako niste sigurni, odaberite Ne. Ostavljanje datoteka neće uzrokovati štetu vašem sistemu. SharedFileNameLabel=Datoteka: SharedFileLocationLabel=Putanja: WizardUninstalling=Status deinstalacije @@ -325,5 +382,5 @@ LaunchProgram=Pokreni %1 AssocFileExtension=&Asociraj %1 sa %2 ekstenzijom AssocingFileExtension=Asociram %1 sa %2 ekstenzijom... AutoStartProgramGroupDescription=Pokretanje: -AutoStartProgram=Automatski pokrei %1 -AddonHostProgramNotFound=%1 nije mogao biti pronaen u folderu koji ste odabrali.%n%nDa li i dalje elite nastaviti s ovom akcijom? +AutoStartProgram=Automatski pokreći %1 +AddonHostProgramNotFound=%1 nije mogao biti pronađen u folderu koji ste odabrali.%n%nŽelite li nastaviti s ovom akcijom? diff --git a/installer/innosetup/Languages/BrazilianPortuguese.isl b/installer/innosetup/Languages/BrazilianPortuguese.isl new file mode 100644 index 000000000..69edb37f2 --- /dev/null +++ b/installer/innosetup/Languages/BrazilianPortuguese.isl @@ -0,0 +1,384 @@ +; *** Inno Setup version 6.1.0+ Brazilian Portuguese messages made by Cesar82 cesar.zanetti.82@gmail.com *** +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Portugus Brasileiro +LanguageID=$0416 +LanguageCodePage=1252 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=Instalador +SetupWindowTitle=%1 - Instalador +UninstallAppTitle=Desinstalar +UninstallAppFullTitle=Desinstalar %1 + +; *** Misc. common +InformationTitle=Informao +ConfirmTitle=Confirmar +ErrorTitle=Erro + +; *** SetupLdr messages +SetupLdrStartupMessage=Isto instalar o %1. Voc deseja continuar? +LdrCannotCreateTemp=Incapaz de criar um arquivo temporrio. Instalao abortada +LdrCannotExecTemp=Incapaz de executar o arquivo no diretrio temporrio. Instalao abortada +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nErro %2: %3 +SetupFileMissing=Est faltando o arquivo %1 do diretrio de instalao. Por favor corrija o problema ou obtenha uma nova cpia do programa. +SetupFileCorrupt=Os arquivos de instalao esto corrompidos. Por favor obtenha uma nova cpia do programa. +SetupFileCorruptOrWrongVer=Os arquivos de instalao esto corrompidos ou so incompatveis com esta verso do instalador. Por favor corrija o problema ou obtenha uma nova cpia do programa. +InvalidParameter=Um parmetro invlido foi passado na linha de comando:%n%n%1 +SetupAlreadyRunning=O instalador j est em execuo. +WindowsVersionNotSupported=Este programa no suporta a verso do Windows que seu computador est executando. +WindowsServicePackRequired=Este programa requer o %1 Service Pack %2 ou superior. +NotOnThisPlatform=Este programa no executar no %1. +OnlyOnThisPlatform=Este programa deve ser executado no %1. +OnlyOnTheseArchitectures=Este programa s pode ser instalado em verses do Windows projetadas para as seguintes arquiteturas de processadores:%n%n% 1 +WinVersionTooLowError=Este programa requer a %1 verso %2 ou superior. +WinVersionTooHighError=Este programa no pode ser instalado na %1 verso %2 ou superior. +AdminPrivilegesRequired=Voc deve estar logado como administrador quando instalar este programa. +PowerUserPrivilegesRequired=Voc deve estar logado como administrador ou como um membro do grupo de Usurios Power quando instalar este programa. +SetupAppRunningError=O instalador detectou que o %1 est atualmente em execuo.%n%nPor favor feche todas as instncias dele agora, ento clique em OK pra continuar ou em Cancelar pra sair. +UninstallAppRunningError=O Desinstalador detectou que o %1 est atualmente em execuo.%n%nPor favor feche todas as instncias dele agora, ento clique em OK pra continuar ou em Cancelar pra sair. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Selecione o Modo de Instalao do Instalador +PrivilegesRequiredOverrideInstruction=Selecione o modo de instalao +PrivilegesRequiredOverrideText1=O %1 pode ser instalado pra todos os usurios (requer privilgios administrativos) ou s pra voc. +PrivilegesRequiredOverrideText2=O %1 pode ser instalado s pra voc ou pra todos os usurios (requer privilgios administrativos). +PrivilegesRequiredOverrideAllUsers=Instalar pra &todos os usurios +PrivilegesRequiredOverrideAllUsersRecommended=Instalar pra &todos os usurios (recomendado) +PrivilegesRequiredOverrideCurrentUser=Instalar s &pra mim +PrivilegesRequiredOverrideCurrentUserRecommended=Instalar s &pra mim (recomendado) + +; *** Misc. errors +ErrorCreatingDir=O instalador foi incapaz de criar o diretrio "%1" +ErrorTooManyFilesInDir=Incapaz de criar um arquivo no diretrio "%1" porque ele contm arquivos demais + +; *** Setup common messages +ExitSetupTitle=Sair do Instalador +ExitSetupMessage=A Instalao no est completa. Se voc sair agora o programa no ser instalado.%n%nVoc pode executar o instalador de novo outra hora pra completar a instalao.%n%nSair do instalador? +AboutSetupMenuItem=&Sobre o Instalador... +AboutSetupTitle=Sobre o Instalador +AboutSetupMessage=%1 verso %2%n%3%n%n%1 home page:%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< &Voltar +ButtonNext=&Avanar > +ButtonInstall=&Instalar +ButtonOK=OK +ButtonCancel=Cancelar +ButtonYes=&Sim +ButtonYesToAll=Sim pra &Todos +ButtonNo=&No +ButtonNoToAll=N&o pra Todos +ButtonFinish=&Concluir +ButtonBrowse=&Procurar... +ButtonWizardBrowse=P&rocurar... +ButtonNewFolder=&Criar Nova Pasta + +; *** "Select Language" dialog messages +SelectLanguageTitle=Selecione o Idioma do Instalador +SelectLanguageLabel=Selecione o idioma pra usar durante a instalao: + +; *** Common wizard text +ClickNext=Clique em Avanar pra continuar ou em Cancelar pra sair do instalador. +BeveledLabel= +BrowseDialogTitle=Procurar Pasta +BrowseDialogLabel=Selecione uma pasta na lista abaixo, ento clique em OK. +NewFolderName=Nova Pasta + +; *** "Welcome" wizard page +WelcomeLabel1=Bem-vindo ao Assistente do Instalador do [name] +WelcomeLabel2=Isto instalar o [name/ver] no seu computador.%n%n recomendado que voc feche todos os outros aplicativos antes de continuar. + +; *** "Password" wizard page +WizardPassword=Senha +PasswordLabel1=Esta instalao est protegida por senha. +PasswordLabel3=Por favor fornea a senha, ento clique em Avanar pra continuar. As senhas so caso-sensitivo. +PasswordEditLabel=&Senha: +IncorrectPassword=A senha que voc inseriu no est correta. Por favor tente de novo. + +; *** "License Agreement" wizard page +WizardLicense=Acordo de Licena +LicenseLabel=Por favor leia as seguintes informaes importantes antes de continuar. +LicenseLabel3=Por favor leia o seguinte Acordo de Licena. Voc deve aceitar os termos deste acordo antes de continuar com a instalao. +LicenseAccepted=Eu &aceito o acordo +LicenseNotAccepted=Eu &no aceito o acordo + +; *** "Information" wizard pages +WizardInfoBefore=Informao +InfoBeforeLabel=Por favor leia as seguintes informaes importantes antes de continuar. +InfoBeforeClickLabel=Quando voc estiver pronto pra continuar com o instalador, clique em Avanar. +WizardInfoAfter=Informao +InfoAfterLabel=Por favor leia as seguintes informaes importantes antes de continuar. +InfoAfterClickLabel=Quando voc estiver pronto pra continuar com o instalador, clique em Avanar. + +; *** "User Information" wizard page +WizardUserInfo=Informao do Usurio +UserInfoDesc=Por favor insira suas informaes. +UserInfoName=&Nome do Usurio: +UserInfoOrg=&Organizao: +UserInfoSerial=&Nmero de Srie: +UserInfoNameRequired=Voc deve inserir um nome. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Selecione o Local de Destino +SelectDirDesc=Aonde o [name] deve ser instalado? +SelectDirLabel3=O instalador instalar o [name] na seguinte pasta. +SelectDirBrowseLabel=Pra continuar clique em Avanar. Se voc gostaria de selecionar uma pasta diferente, clique em Procurar. +DiskSpaceGBLabel=Pelo menos [gb] MBs de espao livre em disco so requeridos. +DiskSpaceMBLabel=Pelo menos [mb] MBs de espao livre em disco so requeridos. +CannotInstallToNetworkDrive=O instalador no pode instalar em um drive de rede. +CannotInstallToUNCPath=O instalador no pode instalar em um caminho UNC. +InvalidPath=Voc deve inserir um caminho completo com a letra do drive; por exemplo:%n%nC:\APP%n%no um caminho UNC no formulrio:%n%n\\server\share +InvalidDrive=O drive ou compartilhamento UNC que voc selecionou no existe ou no est acessvel. Por favor selecione outro. +DiskSpaceWarningTitle=Sem Espao em Disco o Bastante +DiskSpaceWarning=O instalador requer pelo menos %1 KBs de espao livre pra instalar mas o drive selecionado s tem %2 KBs disponveis.%n%nVoc quer continuar de qualquer maneira? +DirNameTooLong=O nome ou caminho da pasta muito longo. +InvalidDirName=O nome da pasta no vlido. +BadDirName32=Os nomes das pastas no pode incluir quaisquer dos seguintes caracteres:%n%n%1 +DirExistsTitle=A Pasta Existe +DirExists=A pasta:%n%n%1%n%nj existe. Voc gostaria de instalar nesta pasta de qualquer maneira? +DirDoesntExistTitle=A Pasta No Existe +DirDoesntExist=A pasta:%n%n%1%n%nno existe. Voc gostaria quer a pasta fosse criada? + +; *** "Select Components" wizard page +WizardSelectComponents=Selecionar Componentes +SelectComponentsDesc=Quais componentes devem ser instalados? +SelectComponentsLabel2=Selecione os componentes que voc quer instalar; desmarque os componentes que voc no quer instalar. Clique em Avanar quando voc estiver pronto pra continuar. +FullInstallation=Instalao completa +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Instalao compacta +CustomInstallation=Instalao personalizada +NoUninstallWarningTitle=O Componente Existe +NoUninstallWarning=O instalador detectou que os seguintes componentes j esto instalados no seu computador:%n%n%1%n%nNo selecionar estes componentes no desinstalar eles.%n%nVoc gostaria de continuar de qualquer maneira? +ComponentSize1=%1 KBs +ComponentSize2=%1 MBs +ComponentsDiskSpaceGBLabel=A seleo atual requer pelo menos [gb] MBs de espao em disco. +ComponentsDiskSpaceMBLabel=A seleo atual requer pelo menos [mb] MBs de espao em disco. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Selecionar Tarefas Adicionais +SelectTasksDesc=Quais tarefas adicionais devem ser executadas? +SelectTasksLabel2=Selecione as tarefas adicionais que voc gostaria que o instalador executasse enquanto instala o [name], ento clique em Avanar. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Selecionar a Pasta do Menu Iniciar +SelectStartMenuFolderDesc=Aonde o instalador deve colocar os atalhos do programa? +SelectStartMenuFolderLabel3=O instalador criar os atalhos do programa na seguinte pasta do Menu Iniciar. +SelectStartMenuFolderBrowseLabel=Pra continuar clique em Avanar. Se voc gostaria de selecionar uma pasta diferente, clique em Procurar. +MustEnterGroupName=Voc deve inserir um nome de pasta. +GroupNameTooLong=O nome ou caminho da pasta muito longo. +InvalidGroupName=O nome da pasta no vlido. +BadGroupName=O nome da pasta no pode incluir quaisquer dos seguintes caracteres:%n%n%1 +NoProgramGroupCheck2=&No criar uma pasta no Menu Iniciar + +; *** "Ready to Install" wizard page +WizardReady=Pronto pra Instalar +ReadyLabel1=O instalador est agora pronto pra comear a instalar o [name] no seu computador. +ReadyLabel2a=Clique em Instalar pra continuar com a instalao ou clique em Voltar se voc quer revisar ou mudar quaisquer configuraes. +ReadyLabel2b=Clique em Instalar pra continuar com a instalao. +ReadyMemoUserInfo=Informao do usurio: +ReadyMemoDir=Local de destino: +ReadyMemoType=Tipo de instalao: +ReadyMemoComponents=Componentes selecionados: +ReadyMemoGroup=Pasta do Menu Iniciar: +ReadyMemoTasks=Tarefas adicionais: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Baixando arquivos adicionais... +ButtonStopDownload=&Parar download +StopDownload=Tem certeza que deseja parar o download? +ErrorDownloadAborted=Download abortado +ErrorDownloadFailed=Download falhou: %1 %2 +ErrorDownloadSizeFailed=Falha ao obter o tamanho: %1 %2 +ErrorFileHash1=Falha no hash do arquivo: %1 +ErrorFileHash2=Hash de arquivo invlido: esperado %1, encontrado %2 +ErrorProgress=Progresso invlido: %1 de %2 +ErrorFileSize=Tamanho de arquivo invlido: esperado %1, encontrado %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Preparando pra Instalar +PreparingDesc=O instalador est se preparando pra instalar o [name] no seu computador. +PreviousInstallNotCompleted=A instalao/remoo de um programa anterior no foi completada. Voc precisar reiniciar o computador pra completar essa instalao.%n%nAps reiniciar seu computador execute o instalador de novo pra completar a instalao do [name]. +CannotContinue=O instalador no pode continuar. Por favor clique em Cancelar pra sair. +ApplicationsFound=Os aplicativos a seguir esto usando arquivos que precisam ser atualizados pelo instalador. recomendados que voc permita ao instalador fechar automaticamente estes aplicativos. +ApplicationsFound2=Os aplicativos a seguir esto usando arquivos que precisam ser atualizados pelo instalador. recomendados que voc permita ao instalador fechar automaticamente estes aplicativos. Aps a instalao ter completado, o instalador tentar reiniciar os aplicativos. +CloseApplications=&Fechar os aplicativos automaticamente +DontCloseApplications=&No fechar os aplicativos +ErrorCloseApplications=O instalador foi incapaz de fechar automaticamente todos os aplicativos. recomendado que voc feche todos os aplicativos usando os arquivos que precisam ser atualizados pelo instalador antes de continuar. +PrepareToInstallNeedsRestart=A instalao deve reiniciar seu computador. Depois de reiniciar o computador, execute a Instalao novamente para concluir a instalao de [name].%n%nDeseja reiniciar agora? + +; *** "Installing" wizard page +WizardInstalling=Instalando +InstallingLabel=Por favor espere enquanto o instalador instala o [name] no seu computador. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Completando o Assistente do Instalador do [name] +FinishedLabelNoIcons=O instalador terminou de instalar o [name] no seu computador. +FinishedLabel=O instalador terminou de instalar o [name] no seu computador. O aplicativo pode ser iniciado selecionando os atalhos instalados. +ClickFinish=Clique em Concluir pra sair do Instalador. +FinishedRestartLabel=Pra completar a instalao do [name], o instalador deve reiniciar seu computador. Voc gostaria de reiniciar agora? +FinishedRestartMessage=Pra completar a instalao do [name], o instalador deve reiniciar seu computador.%n%nVoc gostaria de reiniciar agora? +ShowReadmeCheck=Sim, eu gostaria de visualizar o arquivo README +YesRadio=&Sim, reiniciar o computador agora +NoRadio=&No, eu reiniciarei o computador depois +; used for example as 'Run MyProg.exe' +RunEntryExec=Executar %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Visualizar %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=O Instalador Precisa do Prximo Disco +SelectDiskLabel2=Por favor insira o Disco %1 e clique em OK.%n%nSe os arquivos neste disco podem ser achados numa pasta diferente do que a exibida abaixo, insira o caminho correto ou clique em Procurar. +PathLabel=&Caminho: +FileNotInDir2=O arquivo "%1" no pde ser localizado em "%2". Por favor insira o disco correto ou selecione outra pasta. +SelectDirectoryLabel=Por favor especifique o local do prximo disco. + +; *** Installation phase messages +SetupAborted=A instalao no foi completada.%n%nPor favor corrija o problema e execute o instalador de novo. +AbortRetryIgnoreSelectAction=Selecionar ao +AbortRetryIgnoreRetry=&Tentar de novo +AbortRetryIgnoreIgnore=&Ignorar o erro e continuar +AbortRetryIgnoreCancel=Cancelar instalao + +; *** Installation status messages +StatusClosingApplications=Fechando aplicativos... +StatusCreateDirs=Criando diretrios... +StatusExtractFiles=Extraindo arquivos... +StatusCreateIcons=Criando atalhos... +StatusCreateIniEntries=Criando entradas INI... +StatusCreateRegistryEntries=Criando entradas do registro... +StatusRegisterFiles=Registrando arquivos... +StatusSavingUninstall=Salvando informaes de desinstalao... +StatusRunProgram=Concluindo a instalao... +StatusRestartingApplications=Reiniciando os aplicativos... +StatusRollback=Desfazendo as mudanas... + +; *** Misc. errors +ErrorInternal2=Erro interno: %1 +ErrorFunctionFailedNoCode=%1 falhou +ErrorFunctionFailed=%1 falhou; cdigo %2 +ErrorFunctionFailedWithMessage=%1 falhou; cdigo %2.%n%3 +ErrorExecutingProgram=Incapaz de executar o arquivo:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Erro ao abrir a chave do registro:%n%1\%2 +ErrorRegCreateKey=Erro ao criar a chave do registro:%n%1\%2 +ErrorRegWriteKey=Erro ao gravar a chave do registro:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Erro ao criar a entrada INI no arquivo "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Ignorar este arquivo (no recomendado) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorar o erro e continuar (no recomendado) +SourceIsCorrupted=O arquivo de origem est corrompido +SourceDoesntExist=O arquivo de origem "%1" no existe +ExistingFileReadOnly2=O arquivo existente no pde ser substitudo porque est marcado como somente-leitura. +ExistingFileReadOnlyRetry=&Remover o atributo somente-leitura e tentar de novo +ExistingFileReadOnlyKeepExisting=&Manter o arquivo existente +ErrorReadingExistingDest=Um erro ocorreu enquanto tentava ler o arquivo existente: +FileExistsSelectAction=Selecione a ao +FileExists2=O arquivo j existe. +FileExistsOverwriteExisting=&Sobrescrever o arquivo existente +FileExistsKeepExisting=&Mantenha o arquivo existente +FileExistsOverwriteOrKeepAll=&Faa isso para os prximos conflitos +ExistingFileNewerSelectAction=Selecione a ao +ExistingFileNewer2=O arquivo existente mais recente do que aquele que o Setup est tentando instalar. +ExistingFileNewerOverwriteExisting=&Sobrescrever o arquivo existente +ExistingFileNewerKeepExisting=&Mantenha o arquivo existente (recomendado) +ExistingFileNewerOverwriteOrKeepAll=&Faa isso para os prximos conflitos +ErrorChangingAttr=Um erro ocorreu enquanto tentava mudar os atributos do arquivo existente: +ErrorCreatingTemp=Um erro ocorreu enquanto tentava criar um arquivo no diretrio destino: +ErrorReadingSource=Um erro ocorreu enquanto tentava ler o arquivo de origem: +ErrorCopying=Um erro ocorreu enquanto tentava copiar um arquivo: +ErrorReplacingExistingFile=Um erro ocorreu enquanto tentava substituir o arquivo existente: +ErrorRestartReplace=ReiniciarSubstituir falhou: +ErrorRenamingTemp=Um erro ocorreu enquanto tentava renomear um arquivo no diretrio destino: +ErrorRegisterServer=Incapaz de registrar a DLL/OCX: %1 +ErrorRegSvr32Failed=O RegSvr32 falhou com o cdigo de sada %1 +ErrorRegisterTypeLib=Incapaz de registrar a biblioteca de tipos: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32 bits +UninstallDisplayNameMark64Bit=64 bits +UninstallDisplayNameMarkAllUsers=Todos os usurios +UninstallDisplayNameMarkCurrentUser=Usurio atual + +; *** Post-installation errors +ErrorOpeningReadme=Um erro ocorreu enquanto tentava abrir o arquivo README. +ErrorRestartingComputer=O instalador foi incapaz de reiniciar o computador. Por favor faa isto manualmente. + +; *** Uninstaller messages +UninstallNotFound=O arquivo "%1" no existe. No consegue desinstalar. +UninstallOpenError=O arquivo "%1" no pde ser aberto. No consegue desinstalar +UninstallUnsupportedVer=O arquivo do log da desinstalao "%1" est num formato no reconhecido por esta verso do desinstalador. No consegue desinstalar +UninstallUnknownEntry=Uma entrada desconhecida (%1) foi encontrada no log da desinstalao +ConfirmUninstall=Voc tem certeza que voc quer remover completamente o %1 e todos os seus componentes? +UninstallOnlyOnWin64=Esta instalao s pode ser desinstalada em Windows 64 bits. +OnlyAdminCanUninstall=Esta instalao s pode ser desinstalada por um usurio com privilgios administrativos. +UninstallStatusLabel=Por favor espere enquanto o %1 removido do seu computador. +UninstalledAll=O %1 foi removido com sucesso do seu computador. +UninstalledMost=Desinstalao do %1 completa.%n%nAlguns elementos no puderam ser removidos. Estes podem ser removidos manualmente. +UninstalledAndNeedsRestart=Pra completar a desinstalao do %1, seu computador deve ser reiniciado.%n%nVoc gostaria de reiniciar agora? +UninstallDataCorrupted=O arquivo "%1" est corrompido. No consegue desinstalar + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Remover Arquivo Compartilhado? +ConfirmDeleteSharedFile2=O sistema indica que o seguinte arquivo compartilhado no est mais em uso por quaisquer programas. Voc gostaria que a Desinstalao removesse este arquivo compartilhado?%n%nSe quaisquer programas ainda esto usando este arquivo e ele removido, esses programas podem no funcionar apropriadamente. Se voc no tiver certeza escolha No. Deixar o arquivo no seu sistema no causar qualquer dano. +SharedFileNameLabel=Nome do arquivo: +SharedFileLocationLabel=Local: +WizardUninstalling=Status da Desinstalao +StatusUninstalling=Desinstalando o %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Instalando o %1. +ShutdownBlockReasonUninstallingApp=Desinstalando o %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 verso %2 +AdditionalIcons=Atalhos adicionais: +CreateDesktopIcon=Criar um atalho &na rea de trabalho +CreateQuickLaunchIcon=Criar um atalho na &barra de inicializao rpida +ProgramOnTheWeb=%1 na Web +UninstallProgram=Desinstalar o %1 +LaunchProgram=Iniciar o %1 +AssocFileExtension=&Associar o %1 com a extenso do arquivo %2 +AssocingFileExtension=Associando o %1 com a extenso do arquivo %2... +AutoStartProgramGroupDescription=Inicializao: +AutoStartProgram=Iniciar o %1 automaticamente +AddonHostProgramNotFound=O %1 no pde ser localizado na pasta que voc selecionou.%n%nVoc quer continuar de qualquer maneira? diff --git a/installer/innosetup/Languages/Bulgarian.isl b/installer/innosetup/Languages/Bulgarian.isl index 65330ca41..923aee293 100644 --- a/installer/innosetup/Languages/Bulgarian.isl +++ b/installer/innosetup/Languages/Bulgarian.isl @@ -1,4 +1,4 @@ -; *** Inno Setup version 6.0.0+ Bulgarian messages *** +; *** Inno Setup version 6.1.0+ Bulgarian messages *** ; Ventsislav Dimitrov ; ; За да изтеглите преводи на този файл, предоставени от потребители, посетете: @@ -114,7 +114,7 @@ NewFolderName=Нова папка ; *** Страница "Добре дошли" на съветника WelcomeLabel1=Добре дошли при Съветника за инсталиране на [name] -WelcomeLabel2=Съветникът ще инсталира [name/ver] във вашия компютър.%n%nПрепоръчва се да затворите всички останали приложения, преди да продължите. +WelcomeLabel2=Съветникът ще инсталира [name/ver] във Вашия компютър.%n%nПрепоръчва се да затворите всички останали приложения, преди да продължите. ; *** Страница "Парола" на съветника WizardPassword=Парола @@ -151,6 +151,7 @@ WizardSelectDir=Избор на местоназначение SelectDirDesc=Къде да се инсталира [name]? SelectDirLabel3=[name] ще се инсталира в следната папка. SelectDirBrowseLabel=Натиснете "Напред", за да продължите. За да изберете друга папка, натиснете "Преглед". +DiskSpaceGBLabel=Изискват се поне [gb] ГБ свободно дисково пространство. DiskSpaceMBLabel=Изискват се поне [mb] МБ свободно дисково пространство. CannotInstallToNetworkDrive=Инсталаторът не може да инсталира на мрежово устройство. CannotInstallToUNCPath=Инсталаторът не може да инсталира в UNC път. @@ -171,13 +172,14 @@ WizardSelectComponents=Избор на компоненти SelectComponentsDesc=Кои компоненти да бъдат инсталирани? SelectComponentsLabel2=Изберете компонентите, които желаете да инсталирате, и откажете нежеланите. Натиснете "Напред", когато сте готов да продължите. FullInstallation=Пълна инсталация -; По възможност не превеждайте "Compact" като "Minimal" (има се предвид "Minimal" на вашия език) +; По възможност не превеждайте "Compact" като "Minimal" (има се предвид "Minimal" на Вашия език) CompactInstallation=Компактна инсталация CustomInstallation=Инсталация по избор NoUninstallWarningTitle=Компонентите съществуват NoUninstallWarning=Инсталаторът установи, че следните компоненти са вече инсталирани в компютърa:%n%n%1%n%nОтказването на тези компоненти няма да ги деинсталира.%n%nЖелаете ли все пак да продължите? ComponentSize1=%1 кБ ComponentSize2=%1 МБ +ComponentsDiskSpaceGBLabel=Направеният избор изисква поне [gb] ГБ дисково пространство. ComponentsDiskSpaceMBLabel=Направеният избор изисква поне [mb] МБ дисково пространство. ; *** Страница "Избор на допълнителни задачи" на съветника @@ -198,7 +200,7 @@ NoProgramGroupCheck2=И&нсталиране без папка в менюто " ; *** Страница "Готовност за инсталиране" на съветника WizardReady=Готовност за инсталиране -ReadyLabel1=Инсталаторът е готов да инсталира [name] във вашия компютър. +ReadyLabel1=Инсталаторът е готов да инсталира [name] във Вашия компютър. ReadyLabel2a=Натиснете "Инсталиране", за да продължите, или "Назад" за преглед или промяна на някои настройки. ReadyLabel2b=Натиснете "Инсталиране", за да продължите с инсталирането. ReadyMemoUserInfo=Данни за потребител: @@ -208,9 +210,21 @@ ReadyMemoComponents=Избрани компоненти: ReadyMemoGroup=Папка в менюто "Старт": ReadyMemoTasks=Допълнителни задачи: +; *** Страница "TDownloadWizardPage" на съветника и DownloadTemporaryFile +DownloadingLabel=Изтегляне на допълнителни файлове... +ButtonStopDownload=&Спри изтеглянето +StopDownload=Сигурни ли сте, че искате да спрете изтеглянето? +ErrorDownloadAborted=Изтеглянето беше прекъснато +ErrorDownloadFailed=Изтеглянето беше неуспешно: %1 %2 +ErrorDownloadSizeFailed=Неуспешно получаване на размер: %1 %2 +ErrorFileHash1=Неуспешна контролна сума на файл: %1 +ErrorFileHash2=Невалидна контролна сума на файл: очаквана %1, открита %2 +ErrorProgress=Невалиден напредък: %1 of %2 +ErrorFileSize=Невалиден размер на файл: очакван %1, открит %2 + ; *** Страница "Подготовка за инсталиране" на съветника WizardPreparing=Подготовка за инсталиране -PreparingDesc=Инсталаторът се подготвя да инсталира [name] във вашия компютър. +PreparingDesc=Инсталаторът се подготвя да инсталира [name] във Вашия компютър. PreviousInstallNotCompleted=Инсталиране или премахване на предишна програма не е завършило. Рестартирайте компютъра, за да може процесът да завърши.%n%nСлед като рестартирате, стартирайте инсталатора отново, за да довършите инсталирането на [name]. CannotContinue=Инсталирането не може да продължи. Моля, натиснете "Отказ" за изход. ApplicationsFound=Следните приложения използват файлове, които трябва да бъдат обновени от инсталатора. Препоръчва се да разрешите на инсталатора автоматично да затвори приложенията. @@ -218,15 +232,16 @@ ApplicationsFound2=Следните приложения използват фа CloseApplications=Приложенията да се затворят &автоматично DontCloseApplications=Приложенията да &не се затварят ErrorCloseApplications=Не бе възможно да се затворят автоматично всички приложения. Препоръчва се преди да продължите, да затворите всички приложения, използващи файлове, които инсталаторът трябва да обнови. +PrepareToInstallNeedsRestart=Инсталаторът трябва да ресартира Вашия компютър. След рестартирането, стартирайте инсталатора отново, за да завършите инсталацията на [name].%n%nЖелаете ли да рестартирате сега? ; *** Страница "Инсталиране" на съветника WizardInstalling=Инсталиране -InstallingLabel=Моля, изчакайте докато [name] се инсталира във вашия компютър. +InstallingLabel=Моля, изчакайте докато [name] се инсталира във Вашия компютър. ; *** Страница "Инсталирането завърши" на съветника FinishedHeadingLabel=Съветникът за инсталиране на [name] завърши -FinishedLabelNoIcons=Инсталирането на [name] във вашия компютър завърши. -FinishedLabel=Инсталирането на [name] във вашия компютър завърши. Можете да стартирате приложението чрез инсталираните икони. +FinishedLabelNoIcons=Инсталирането на [name] във Вашия компютър завърши. +FinishedLabel=Инсталирането на [name] във Вашия компютър завърши. Можете да стартирате приложението чрез инсталираните икони. ClickFinish=Натиснете "Готово", за да затворите инсталатора. FinishedRestartLabel=Инсталаторът трябва да рестартира компютъра, за да завърши инсталирането на [name]. Желаете ли да рестартирате сега? FinishedRestartMessage=Инсталаторът трябва да рестартира компютъра, за да завърши инсталирането на [name].%n%nЖелаете ли да рестартирате сега? @@ -289,8 +304,16 @@ ExistingFileReadOnly2=Съществуващият файл не беше зам ExistingFileReadOnlyRetry=&Премахни атрибута „само за четене“ и опитай отново ExistingFileReadOnlyKeepExisting=&Запази съществуващия файл ErrorReadingExistingDest=Грешка при опит за четене на съществуващ файл: -FileExists=Файлът вече съществува.%n%nЖелаете ли инсталаторът да го презапише? -ExistingFileNewer=Съществуващият файл е по-нов от този, който инсталаторът се опитва да инсталира. Препоръчва се да го запазите.%n%nЖелаете ли да запазите съществуващия файл? +FileExistsSelectAction=Изберете действие +FileExists2=Файлът вече съществува. +FileExistsOverwriteExisting=&Презапиши съществуващия файл +FileExistsKeepExisting=&Запази съществуващия файл +FileExistsOverwriteOrKeepAll=&Извършвай същото за останалите конфликти +ExistingFileNewerSelectAction=Изберете действие +ExistingFileNewer2=Съществуващият файл е по-нов от този, който инсталаторът се опитва да инсталира. +ExistingFileNewerOverwriteExisting=&Презапиши съществуващия файл +ExistingFileNewerKeepExisting=&Запази съществуващия файл (препоръчително) +ExistingFileNewerOverwriteOrKeepAll=&Извършвай същото за останалите конфликти ErrorChangingAttr=Грешка при опит за смяна на атрибути на съществуващ файл: ErrorCreatingTemp=Грешка при опит за създаване на файл в целевата директория: ErrorReadingSource=Грешка при опит за четене на файл - източник: @@ -322,10 +345,10 @@ UninstallUnknownEntry=Открит бе непознат запис (%1) в ре ConfirmUninstall=Наистина ли желаете да премахнете напълно %1 и всички прилежащи компоненти? UninstallOnlyOnWin64=Програмата може да бъде деинсталирана само под 64-битов Windows. OnlyAdminCanUninstall=Програмата може да бъде премахната само от потребител с администраторски права. -UninstallStatusLabel=Моля, изчакайте премахването на %1 от вашия компютър да приключи. -UninstalledAll=%1 беше премахната успешно от вашия компютър. +UninstallStatusLabel=Моля, изчакайте премахването на %1 от Вашия компютър да приключи. +UninstalledAll=%1 беше премахната успешно от Вашия компютър. UninstalledMost=Деинсталирането на %1 завърши.%n%nПремахването на някои елементи не бе възможно. Можете да ги отстраните ръчно. -UninstalledAndNeedsRestart=За да приключи деинсталирането на %1, трябва да рестартирате вашия компютър.%n%nЖелаете ли да рестартирате сега? +UninstalledAndNeedsRestart=За да приключи деинсталирането на %1, трябва да рестартирате Вашия компютър.%n%nЖелаете ли да рестартирате сега? UninstallDataCorrupted=Файлът "%1" е повреден. Деинсталирането е невъзможно ; *** Съобщения от фаза "Деинсталиране" diff --git a/installer/innosetup/Languages/Catalan.isl b/installer/innosetup/Languages/Catalan.isl new file mode 100644 index 000000000..5fc86822a --- /dev/null +++ b/installer/innosetup/Languages/Catalan.isl @@ -0,0 +1,371 @@ +; *** Inno Setup version 6.1.0+ Catalan messages *** +; +; Translated by Carles Millan (email: carles@carlesmillan.cat) +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno + +[LangOptions] + +LanguageName=Catal<00E0> +LanguageID=$0403 +LanguageCodePage=1252 + +[Messages] + +; *** Application titles +SetupAppTitle=Installaci +SetupWindowTitle=Installaci - %1 +UninstallAppTitle=Desinstallaci +UninstallAppFullTitle=Desinstalla %1 + +; *** Misc. common +InformationTitle=Informaci +ConfirmTitle=Confirmaci +ErrorTitle=Error + +; *** SetupLdr messages +SetupLdrStartupMessage=Aquest programa installar %1. Voleu continuar? +LdrCannotCreateTemp=No s'ha pogut crear un fitxer temporal. Installaci cancellada +LdrCannotExecTemp=No s'ha pogut executar el fitxer a la carpeta temporal. Installaci cancellada +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nError %2: %3 +SetupFileMissing=El fitxer %1 no es troba a la carpeta d'installaci. Resoleu el problema o obteniu una nova cpia del programa. +SetupFileCorrupt=Els fitxers d'installaci estan corromputs. Obteniu una nova cpia del programa. +SetupFileCorruptOrWrongVer=Els fitxers d'installaci estan espatllats, o sn incompatibles amb aquesta versi del programa. Resoleu el problema o obteniu una nova cpia del programa. +InvalidParameter=Un parmetre invlid ha estat passat a la lnia de comanda:%n%n%1 +SetupAlreadyRunning=La installaci ja est en curs. +WindowsVersionNotSupported=Aquest programa no suporta la versi de Windows installada al vostre ordinador. +WindowsServicePackRequired=Aquest programa necessita %1 Service Pack %2 o posterior. +NotOnThisPlatform=Aquest programa no funcionar sota %1. +OnlyOnThisPlatform=Aquest programa noms pot ser executat sota %1. +OnlyOnTheseArchitectures=Aquest programa noms pot ser installat en versions de Windows dissenyades per a les segents arquitectures de processador:%n%n%1 +WinVersionTooLowError=Aquest programa requereix %1 versi %2 o posterior. +WinVersionTooHighError=Aquest programa no pot ser installat sota %1 versi %2 o posterior. +AdminPrivilegesRequired=Cal que tingueu privilegis d'administrador per poder installar aquest programa. +PowerUserPrivilegesRequired=Cal que accediu com a administrador o com a membre del grup Power Users en installar aquest programa. +SetupAppRunningError=El programa d'installaci ha detectat que %1 s'est executant actualment.%n%nTanqueu el programa i premeu Accepta per a continuar o Cancella per a sortir. +UninstallAppRunningError=El programa de desinstallaci ha detectat que %1 s'est executant en aquest moment.%n%nTanqueu el programa i premeu Accepta per a continuar o Cancella per a sortir. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Selecci del Mode d'Installaci +PrivilegesRequiredOverrideInstruction=Trieu mode d'installaci +PrivilegesRequiredOverrideText1=%1 pot ser installat per a tots els usuaris (cal tenir privilegis d'administrador), o noms per a vs. +PrivilegesRequiredOverrideText2=%1 pot ser installat noms per a vs, o per a tots els usuaris (cal tenir privilegis d'administrador). +PrivilegesRequiredOverrideAllUsers=Installaci per a &tots els usuaris +PrivilegesRequiredOverrideAllUsersRecommended=Installaci per a &tots els usuaris (recomanat) +PrivilegesRequiredOverrideCurrentUser=Installaci noms per a &mi +PrivilegesRequiredOverrideCurrentUserRecommended=Installaci noms per a &mi (recomanat) + +; *** Misc. errors +ErrorCreatingDir=El programa d'installaci no ha pogut crear la carpeta "%1" +ErrorTooManyFilesInDir=No s'ha pogut crear un fitxer a la carpeta "%1" perqu cont massa fitxers + +; *** Setup common messages +ExitSetupTitle=Surt +ExitSetupMessage=La installaci no s'ha completat. Si sortiu ara, el programa no ser installat.%n%nPer a completar-la podreu tornar a executar el programa d'installaci quan vulgueu.%n%nVoleu sortir-ne? +AboutSetupMenuItem=&Sobre la installaci... +AboutSetupTitle=Sobre la installaci +AboutSetupMessage=%1 versi %2%n%3%n%nPgina web de %1:%n%4 +AboutSetupNote= +TranslatorNote=Catalan translation by Carles Millan (carles at carlesmillan.cat) + +; *** Buttons +ButtonBack=< &Enrere +ButtonNext=&Segent > +ButtonInstall=&Installa +ButtonOK=Accepta +ButtonCancel=Cancella +ButtonYes=&S +ButtonYesToAll=S a &tot +ButtonNo=&No +ButtonNoToAll=N&o a tot +ButtonFinish=&Finalitza +ButtonBrowse=&Explora... +ButtonWizardBrowse=&Cerca... +ButtonNewFolder=Crea &nova carpeta + +; *** "Select Language" dialog messages +SelectLanguageTitle=Trieu idioma +SelectLanguageLabel=Trieu idioma a emprar durant la installaci. + +; *** Common wizard text +ClickNext=Premeu Segent per a continuar o Cancella per a abandonar la installaci. +BeveledLabel= +BrowseDialogTitle=Trieu una carpeta +BrowseDialogLabel=Trieu la carpeta de destinaci i premeu Accepta. +NewFolderName=Nova carpeta + +; *** "Welcome" wizard page +WelcomeLabel1=Benvingut a l'assistent d'installaci de [name] +WelcomeLabel2=Aquest programa installar [name/ver] al vostre ordinador.%n%ns molt recomanable que abans de continuar tanqueu tots els altres programes oberts, per tal d'evitar conflictes durant el procs d'installaci. + +; *** "Password" wizard page +WizardPassword=Contrasenya +PasswordLabel1=Aquesta installaci est protegida amb una contrasenya. +PasswordLabel3=Indiqueu la contrasenya i premeu Segent per a continuar. Aquesta contrasenya distingeix entre majscules i minscules. +PasswordEditLabel=&Contrasenya: +IncorrectPassword=La contrasenya introduda no s correcta. Torneu-ho a intentar. + +; *** "License Agreement" wizard page +WizardLicense=Acord de Llicncia +LicenseLabel=Cal que llegiu aquesta informaci abans de continuar. +LicenseLabel3=Cal que llegiu l'Acord de Llicncia segent. Cal que n'accepteu els termes abans de continuar amb la installaci. +LicenseAccepted=&Accepto l'acord +LicenseNotAccepted=&No accepto l'acord + +; *** "Information" wizard pages +WizardInfoBefore=Informaci +InfoBeforeLabel=Llegiu la informaci segent abans de continuar. +InfoBeforeClickLabel=Quan estigueu preparat per a continuar, premeu Segent. +WizardInfoAfter=Informaci +InfoAfterLabel=Llegiu la informaci segent abans de continuar. +InfoAfterClickLabel=Quan estigueu preparat per a continuar, premeu Segent + +; *** "User Information" wizard page +WizardUserInfo=Informaci sobre l'usuari +UserInfoDesc=Introduu la vostra informaci. +UserInfoName=&Nom de l'usuari: +UserInfoOrg=&Organitzaci +UserInfoSerial=&Nmero de srie: +UserInfoNameRequired=Cal que hi introduu un nom + +; *** "Select Destination Location" wizard page +WizardSelectDir=Trieu Carpeta de Destinaci +SelectDirDesc=On s'ha d'installar [name]? +SelectDirLabel3=El programa d'installaci installar [name] a la carpeta segent. +SelectDirBrowseLabel=Per a continuar, premeu Segent. Si desitgeu triar una altra capeta, premeu Cerca. +DiskSpaceGBLabel=Aquest programa necessita un mnim de [gb] GB d'espai a disc. +DiskSpaceMBLabel=Aquest programa necessita un mnim de [mb] MB d'espai a disc. +CannotInstallToNetworkDrive=La installaci no es pot fer en un disc de xarxa. +CannotInstallToUNCPath=La installaci no es pot fer a una ruta UNC. +InvalidPath=Cal donar una ruta completa amb lletra d'unitat, per exemple:%n%nC:\Aplicaci%n%no b una ruta UNC en la forma:%n%n\\servidor\compartit +InvalidDrive=El disc o ruta de xarxa seleccionat no existeix, trieu-ne un altre. +DiskSpaceWarningTitle=No hi ha prou espai al disc +DiskSpaceWarning=El programa d'installaci necessita com a mnim %1 KB d'espai lliure, per el disc seleccionat noms t %2 KB disponibles.%n%nTot i amb aix, desitgeu continuar? +DirNameTooLong=El nom de la carpeta o de la ruta s massa llarg. +InvalidDirName=El nom de la carpeta no s vlid. +BadDirName32=Un nom de carpeta no pot contenir cap dels carcters segents:%n%n%1 +DirExistsTitle=La carpeta existeix +DirExists=La carpeta:%n%n%1%n%nja existeix. Voleu installar igualment el programa en aquesta carpeta? +DirDoesntExistTitle=La Carpeta No Existeix +DirDoesntExist=La carpeta:%n%n%1%n%nno existeix. Voleu que sigui creada? + +; *** "Select Program Group" wizard page +WizardSelectComponents=Trieu Components +SelectComponentsDesc=Quins components cal installar? +SelectComponentsLabel2=Trieu els components que voleu installar; elimineu els components que no voleu installar. Premeu Segent per a continuar. +FullInstallation=Installaci completa +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Installaci compacta +CustomInstallation=Installaci personalitzada +NoUninstallWarningTitle=Els components Existeixen +NoUninstallWarning=El programa d'installaci ha detectat que els components segents ja es troben al vostre ordinador:%n%n%1%n%nSi no estan seleccionats no seran desinstallats.%n%nVoleu continuar igualment? +ComponentSize1=%1 Kb +ComponentSize2=%1 Mb +ComponentsDiskSpaceGBLabel=Aquesta selecci requereix un mnim de [gb] GB d'espai al disc. +ComponentsDiskSpaceMBLabel=Aquesta selecci requereix un mnim de [mb] Mb d'espai al disc. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Trieu tasques addicionals +SelectTasksDesc=Quines tasques addicionals cal executar? +SelectTasksLabel2=Trieu les tasques addicionals que voleu que siguin executades mentre s'installa [name], i desprs premeu Segent. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Trieu la carpeta del Men Inici +SelectStartMenuFolderDesc=On cal situar els enllaos del programa? +SelectStartMenuFolderLabel3=El programa d'installaci crear l'accs directe al programa a la segent carpeta del men d'Inici. +SelectStartMenuFolderBrowseLabel=Per a continuar, premeu Segent. Si desitgeu triar una altra carpeta, premeu Cerca. +MustEnterGroupName=Cal que hi introduu un nom de carpeta. +GroupNameTooLong=El nom de la carpeta o de la ruta s massa llarg. +InvalidGroupName=El nom de la carpeta no s vlid. +BadGroupName=El nom del grup no pot contenir cap dels carcters segents:%n%n%1 +NoProgramGroupCheck2=&No cres una carpeta al Men Inici + +; *** "Ready to Install" wizard page +WizardReady=Preparat per a installar +ReadyLabel1=El programa d'installaci est preparat per a iniciar la installaci de [name] al vostre ordinador. +ReadyLabel2a=Premeu Installa per a continuar amb la installaci, o Enrere si voleu revisar o modificar les opcions d'installaci. +ReadyLabel2b=Premeu Installa per a continuar amb la installaci. +ReadyMemoUserInfo=Informaci de l'usuari: +ReadyMemoDir=Carpeta de destinaci: +ReadyMemoType=Tipus d'installaci: +ReadyMemoComponents=Components seleccionats: +ReadyMemoGroup=Carpeta del Men Inici: +ReadyMemoTasks=Tasques addicionals: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Descarregant els fitxers addicionals... +ButtonStopDownload=&Atura la descrrega +StopDownload=Esteu segur que voleu aturar la descrrega? +ErrorDownloadAborted=Descrrega cancellada +ErrorDownloadFailed=La descrrega ha fallat: %1 %2 +ErrorDownloadSizeFailed=La mesura de la descrrega ha fallat: %1 %2 +ErrorFileHash1=El hash del fitxer ha fallat: %1 +ErrorFileHash2=El hash del fitxer s invlid: s'esperava %1, s'ha trobat %2 +ErrorProgress=Progrs invlid: %1 de %2 +ErrorFileSize=Mida del fitxer invlida: s'esperava %1, s'ha trobat %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Preparant la installaci +PreparingDesc=Preparant la installaci de [name] al vostre ordinador. +PreviousInstallNotCompleted=La installaci o desinstallaci anterior no s'ha dut a terme. Caldr que reinicieu l'ordinador per a finalitzar aquesta installaci.%n%nDesprs de reiniciar l'ordinador, executeu aquest programa de nou per completar la installaci de [name]. +CannotContinue=La installaci no pot continuar. Premeu Cancella per a sortir. +ApplicationsFound=Les segents aplicacions estan fent servir fitxers que necessiten ser actualitzats per la installaci. Es recomana que permeteu a la installaci tancar automticament aquestes aplicacions. +ApplicationsFound2=Les segents aplicacions estan fent servir fitxers que necessiten ser actualitzats per la installaci. Es recomana que permeteu a la installaci tancar automticament aquestes aplicacions. Desprs de completar la installaci s'intentar reiniciar les aplicacions. +CloseApplications=&Tanca automticament les aplicacions +DontCloseApplications=&No tanquis les aplicacions +ErrorCloseApplications=El programa d'installaci no ha pogut tancar automticament totes les aplicacions. Es recomana que abans de continuar tanqueu totes les aplicacions que estan usant fitxers que han de ser actualitzats pel programa d'installaci. +PrepareToInstallNeedsRestart=El programa d'installaci ha de reiniciar l'ordinador. Desprs del reinici, executeu de nou l'installador per tal de completar la installaci de [name].%n%nVoleu reiniciar-lo ara? + +; *** "Installing" wizard page +WizardInstalling=Installant +InstallingLabel=Espereu mentre s'installa [name] al vostre ordinador. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Completant l'assistent d'installaci de [name] +FinishedLabelNoIcons=El programa ha finalitzat la installaci de [name] al vostre ordinador. +FinishedLabel=El programa ha finalitzat la installaci de [name] al vostre ordinador. L'aplicaci pot ser iniciada seleccionant les icones installades. +ClickFinish=Premeu Finalitza per a sortir de la installaci. +FinishedRestartLabel=Per a completar la installaci de [name] cal reiniciar l'ordinador. Voleu fer-ho ara? +FinishedRestartMessage=Per a completar la installaci de [name] cal reiniciar l'ordinador. Voleu fer-ho ara? +ShowReadmeCheck=S, vull visualitzar el fitxer LLEGIUME.TXT +YesRadio=&S, reiniciar l'ordinador ara +NoRadio=&No, reiniciar l'ordinador ms tard +; used for example as 'Run MyProg.exe' +RunEntryExec=Executa %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Visualitza %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=El programa d'installaci necessita el disc segent +SelectDiskLabel2=Introduiu el disc %1 i premeu Continua.%n%nSi els fitxers d'aquest disc es poden trobar en una carpeta diferent de la indicada tot seguit, introduu-ne la ruta correcta o b premeu Explora. +PathLabel=&Ruta: +FileNotInDir2=El fitxer "%1" no s'ha pogut trobar a "%2". Introduu el disc correcte o trieu una altra carpeta. +SelectDirectoryLabel=Indiqueu on es troba el disc segent. + +; *** Installation phase messages +SetupAborted=La installaci no s'ha completat.%n%n%Resoleu el problema i executeu de nou el programa d'installaci. +AbortRetryIgnoreSelectAction=Trieu acci +AbortRetryIgnoreRetry=&Torna-ho a intentar +AbortRetryIgnoreIgnore=&Ignora l'error i continua +AbortRetryIgnoreCancel=Cancella la installaci + +; *** Installation status messages +StatusClosingApplications=Tancant aplicacions... +StatusCreateDirs=Creant carpetes... +StatusExtractFiles=Extraient fitxers... +StatusCreateIcons=Creant enllaos del programa... +StatusCreateIniEntries=Creant entrades al fitxer INI... +StatusCreateRegistryEntries=Creant entrades de registre... +StatusRegisterFiles=Registrant fitxers... +StatusSavingUninstall=Desant informaci de desinstallaci... +StatusRunProgram=Finalitzant la installaci... +StatusRestartingApplications=Reiniciant aplicacions... +StatusRollback=Desfent els canvis... + +; *** Misc. errors +ErrorInternal2=Error intern: %1 +ErrorFunctionFailedNoCode=%1 ha fallat +ErrorFunctionFailed=%1 ha fallat; codi %2 +ErrorFunctionFailedWithMessage=%1 ha fallat; codi %2.%n%3 +ErrorExecutingProgram=No es pot executar el fitxer:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Error en obrir la clau de registre:%n%1\%2 +ErrorRegCreateKey=Error en crear la clau de registre:%n%1\%2 +ErrorRegWriteKey=Error en escriure a la clau de registre:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Error en crear l'entrada INI al fitxer "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Salta't aquest fitxer (no recomanat) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignora l'error i continua (no recomanat) +SourceIsCorrupted=El fitxer d'origen est corromput +SourceDoesntExist=El fitxer d'origen "%1" no existeix +ExistingFileReadOnly2=El fitxer existent no ha pogut ser substitut perqu est marcat com a noms lectura. +ExistingFileReadOnlyRetry=&Lleveu-li l'atribut de noms lectura i torneu-ho a intentar +ExistingFileReadOnlyKeepExisting=&Mant el fitxer existent +ErrorReadingExistingDest=S'ha produt un error en llegir el fitxer: +FileExistsSelectAction=Trieu acci +FileExists2=El fitxer ja existeix. +FileExistsOverwriteExisting=&Sobreescriu el fitxer existent +FileExistsKeepExisting=&Mant el fitxer existent +FileExistsOverwriteOrKeepAll=&Fes-ho tamb per als propers conflictes +ExistingFileNewerSelectAction=Trieu acci +ExistingFileNewer2=El fitxer existent s ms nou que el que s'intenta installar. +ExistingFileNewerOverwriteExisting=&Sobreescriu el fitxer existent +ExistingFileNewerKeepExisting=&Mant el fitxer existent (recomanat) +ExistingFileNewerOverwriteOrKeepAll=&Fes-ho tamb per als propers conflictes +ErrorChangingAttr=Hi ha hagut un error en canviar els atributs del fitxer: +ErrorCreatingTemp=Hi ha hagut un error en crear un fitxer a la carpeta de destinaci: +ErrorReadingSource=Hi ha hagut un error en llegir el fitxer d'origen: +ErrorCopying=Hi ha hagut un error en copiar un fitxer: +ErrorReplacingExistingFile=Hi ha hagut un error en reemplaar el fitxer existent: +ErrorRestartReplace=Ha fallat reemplaar: +ErrorRenamingTemp=Hi ha hagut un error en reanomenar un fitxer a la carpeta de destinaci: +ErrorRegisterServer=No s'ha pogut registrar el DLL/OCX: %1 +ErrorRegSvr32Failed=Ha fallat RegSvr32 amb el codi de sortida %1 +ErrorRegisterTypeLib=No s'ha pogut registrar la biblioteca de tipus: %1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Tots els usuaris +UninstallDisplayNameMarkCurrentUser=Usuari actual + +; *** Post-installation errors +ErrorOpeningReadme=Hi ha hagut un error en obrir el fitxer LLEGIUME.TXT. +ErrorRestartingComputer=El programa d'installaci no ha pogut reiniciar l'ordinador. Cal que ho feu manualment. + +; *** Uninstaller messages +UninstallNotFound=El fitxer "%1" no existeix. No es pot desinstallar. +UninstallOpenError=El fitxer "%1" no pot ser obert. No es pot desinstallar +UninstallUnsupportedVer=El fitxer de desinstallaci "%1" est en un format no reconegut per aquesta versi del desinstallador. No es pot desinstallar +UninstallUnknownEntry=S'ha trobat una entrada desconeguda (%1) al fitxer de desinstallaci. +ConfirmUninstall=Esteu segur de voler eliminar completament %1 i tots els seus components? +UninstallOnlyOnWin64=Aquest programa noms pot ser desinstallat en Windows de 64 bits. +OnlyAdminCanUninstall=Aquest programa noms pot ser desinstallat per un usuari amb privilegis d'administrador. +UninstallStatusLabel=Espereu mentre s'elimina %1 del vostre ordinador. +UninstalledAll=%1 ha estat desinstallat correctament del vostre ordinador. +UninstalledMost=Desinstallaci de %1 completada.%n%nAlguns elements no s'han pogut eliminar. Poden ser eliminats manualment. +UninstalledAndNeedsRestart=Per completar la installaci de %1, cal reiniciar el vostre ordinador.%n%nVoleu fer-ho ara? +UninstallDataCorrupted=El fitxer "%1" est corromput. No es pot desinstallar. + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Eliminar fitxer compartit? +ConfirmDeleteSharedFile2=El sistema indica que el fitxer compartit segent ja no s emprat per cap altre programa. Voleu que la desinstallaci elimini aquest fitxer?%n%nSi algun programa encara el fa servir i s eliminat, podria no funcionar correctament. Si no n'esteu segur, trieu No. Deixar el fitxer al sistema no far cap mal. +SharedFileNameLabel=Nom del fitxer: +SharedFileLocationLabel=Localitzaci: +WizardUninstalling=Estat de la desinstallaci +StatusUninstalling=Desinstallant %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Installant %1. +ShutdownBlockReasonUninstallingApp=Desinstallant %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 versi %2 +AdditionalIcons=Icones addicionals: +CreateDesktopIcon=Crea una icona a l'&Escriptori +CreateQuickLaunchIcon=Crea una icona a la &Barra de tasques +ProgramOnTheWeb=%1 a Internet +UninstallProgram=Desinstalla %1 +LaunchProgram=Obre %1 +AssocFileExtension=&Associa %1 amb l'extensi de fitxer %2 +AssocingFileExtension=Associant %1 amb l'extensi de fitxer %2... +AutoStartProgramGroupDescription=Inici: +AutoStartProgram=Inicia automticament %1 +AddonHostProgramNotFound=%1 no ha pogut ser trobat a la carpeta seleccionada.%n%nVoleu continuar igualment? diff --git a/installer/innosetup/Languages/ChineseSimplified.isl b/installer/innosetup/Languages/ChineseSimplified.isl index 1835c4f30..df711d51d 100644 --- a/installer/innosetup/Languages/ChineseSimplified.isl +++ b/installer/innosetup/Languages/ChineseSimplified.isl @@ -1,4 +1,12 @@ -; *** Inno Setup version 6.0.3+ Chinese Simplified messages *** +; *** Inno Setup version 6.1.0+ Chinese Simplified messages *** +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). ; ; Maintained by Zhenghan Yang ; Email: 847320916@QQ.com @@ -12,6 +20,8 @@ LanguageName=简体中文 ; If Language Name display incorrect, uncomment next line ; LanguageName=<7B80><4F53><4E2D><6587> +; About LanguageID, to reference link: +; https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c LanguageID=$0804 LanguageCodePage=936 ; If the language you are translating to requires special font faces or @@ -46,22 +56,22 @@ HelpTextNote= ; *** 启动错误消息 LastErrorMessage=%1.%n%n错误 %2: %3 -SetupFileMissing=安装目录中的文件 %1 丢失。请修正这个问题或获取一个新的程序副本。 -SetupFileCorrupt=安装文件已损坏。请获取一个新的程序副本。 +SetupFileMissing=安装目录中的文件 %1 丢失。请修正这个问题或者获取程序的新副本。 +SetupFileCorrupt=安装文件已损坏。请获取程序的新副本。 SetupFileCorruptOrWrongVer=安装文件已损坏,或是与这个安装程序的版本不兼容。请修正这个问题或获取新的程序副本。 -InvalidParameter=无效的命令行参数: %n%n%1 +InvalidParameter=无效的命令行参数:%n%n%1 SetupAlreadyRunning=安装程序正在运行。 -WindowsVersionNotSupported=这个程序不支持该版本的计算机运行。 -WindowsServicePackRequired=这个程序要求%1服务包%1或更高。 +WindowsVersionNotSupported=这个程序不支持当前计算机运行的Windows版本。 +WindowsServicePackRequired=这个程序需要 %1 服务包 %2 或更高。 NotOnThisPlatform=这个程序将不能运行于 %1。 OnlyOnThisPlatform=这个程序必须运行于 %1。 -OnlyOnTheseArchitectures=这个程序只能在为下列处理器结构设计的 Windows 版本中进行安装:%n%n%1 +OnlyOnTheseArchitectures=这个程序只能在为下列处理器结构设计的Windows版本中进行安装:%n%n%1 WinVersionTooLowError=这个程序需要 %1 版本 %2 或更高。 WinVersionTooHighError=这个程序不能安装于 %1 版本 %2 或更高。 AdminPrivilegesRequired=在安装这个程序时您必须以管理员身份登录。 PowerUserPrivilegesRequired=在安装这个程序时您必须以管理员身份或有权限的用户组身份登录。 -SetupAppRunningError=安装程序发现 %1 当前正在运行。%n%n请先关闭所有运行的窗口,然后单击“确定”继续,或按“取消”退出。 -UninstallAppRunningError=卸载程序发现 %1 当前正在运行。%n%n请先关闭所有运行的窗口,然后单击“确定”继续,或按“取消”退出。 +SetupAppRunningError=安装程序发现 %1 当前正在运行。%n%n请先关闭所有运行的窗口,然后点击“确定”继续,或按“取消”退出。 +UninstallAppRunningError=卸载程序发现 %1 当前正在运行。%n%n请先关闭所有运行的窗口,然后点击“确定”继续,或按“取消”退出。 ; *** 启动问题 PrivilegesRequiredOverrideTitle=选择安装程序模式 @@ -69,9 +79,9 @@ PrivilegesRequiredOverrideInstruction=选择安装模式 PrivilegesRequiredOverrideText1=%1 可以为所有用户安装(需要管理员权限),或仅为您安装。 PrivilegesRequiredOverrideText2=%1 只能为您安装,或为所有用户安装(需要管理员权限)。 PrivilegesRequiredOverrideAllUsers=为所有用户安装(&A) -PrivilegesRequiredOverrideAllUsersRecommended=为所有用户安装(建议选项)(&A) +PrivilegesRequiredOverrideAllUsersRecommended=为所有用户安装(&A) (建议选项) PrivilegesRequiredOverrideCurrentUser=只为我安装(&M) -PrivilegesRequiredOverrideCurrentUserRecommended=只为我安装(建议选项)(&M) +PrivilegesRequiredOverrideCurrentUserRecommended=只为我安装(&M) (建议选项) ; *** 其它错误 ErrorCreatingDir=安装程序不能创建目录“%1”。 @@ -79,10 +89,10 @@ ErrorTooManyFilesInDir=不能在目录“%1”中创建文件,因为里面的 ; *** 安装程序公共消息 ExitSetupTitle=退出安装程序 -ExitSetupMessage=安装程序未完成安装。如果您现在退出,您的程序将不能安装。%n%n您可以以后再运行安装程序完成安装。%n%n退出安装程序吗? +ExitSetupMessage=安装程序还未完成安装。如果您现在退出,程序将不能安装。%n%n您可以以后再运行安装程序完成安装。%n%n现在退出安装程序吗? AboutSetupMenuItem=关于安装程序(&A)... AboutSetupTitle=关于安装程序 -AboutSetupMessage=%1 版本 %2%n%3%n%n%1 主页:%n%4 +AboutSetupMessage=%1 版本 %2%n%3%n%n%1 主页:%n%4 AboutSetupNote= TranslatorNote= @@ -106,10 +116,10 @@ SelectLanguageTitle=选择安装语言 SelectLanguageLabel=选择安装时要使用的语言。 ; *** 公共向导文字 -ClickNext=单击“下一步”继续,或单击“取消”退出安装程序。 +ClickNext=点击“下一步”继续,或点击“取消”退出安装程序。 BeveledLabel= BrowseDialogTitle=浏览文件夹 -BrowseDialogLabel=在下列列表中选择一个文件夹,然后单击“确定”。 +BrowseDialogLabel=在下列列表中选择一个文件夹,然后点击“确定”。 NewFolderName=新建文件夹 ; *** “欢迎”向导页 @@ -119,9 +129,9 @@ WelcomeLabel2=现在将安装 [name/ver] 到您的电脑中。%n%n推荐您在 ; *** “密码”向导页 WizardPassword=密码 PasswordLabel1=这个安装程序有密码保护。 -PasswordLabel3=请输入密码,然后单击“下一步”继续。密码区分大小写。 -PasswordEditLabel=密码(&P): -IncorrectPassword=您输入的密码不正确,请重试。 +PasswordLabel3=请输入密码,然后点击“下一步”继续。密码区分大小写。 +PasswordEditLabel=密码(&P): +IncorrectPassword=您所输入的密码不正确,请重试。 ; *** “许可协议”向导页 WizardLicense=许可协议 @@ -133,50 +143,50 @@ LicenseNotAccepted=我不同意此协议(&D) ; *** “信息”向导页 WizardInfoBefore=信息 InfoBeforeLabel=请在继续安装前阅读下列重要信息。 -InfoBeforeClickLabel=如果您想继续安装,单击“下一步”。 +InfoBeforeClickLabel=如果您想继续安装,点击“下一步”。 WizardInfoAfter=信息 InfoAfterLabel=请在继续安装前阅读下列重要信息。 -InfoAfterClickLabel=如果您想继续安装,单击“下一步”。 +InfoAfterClickLabel=如果您想继续安装,点击“下一步”。 ; *** “用户信息”向导页 WizardUserInfo=用户信息 UserInfoDesc=请输入您的信息。 -UserInfoName=用户名(&U): -UserInfoOrg=组织(&O): -UserInfoSerial=序列号(&S): -UserInfoNameRequired=您必须输入名字。 +UserInfoName=用户名(&U): +UserInfoOrg=组织(&O): +UserInfoSerial=序列号(&S): +UserInfoNameRequired=您必须输入用户名。 -; *** “选择目标目录”向导面 +; *** “选择目标目录”向导页 WizardSelectDir=选择目标位置 -SelectDirDesc=您想将 [name] 安装在什么地方? +SelectDirDesc=您想将 [name] 安装在哪里? SelectDirLabel3=安装程序将安装 [name] 到下列文件夹中。 -SelectDirBrowseLabel=单击“下一步”继续。如果您想选择其它文件夹,单击“浏览”。 +SelectDirBrowseLabel=点击“下一步”继续。如果您想选择其它文件夹,点击“浏览”。 DiskSpaceGBLabel=至少需要有 [gb] GB 的可用磁盘空间。 DiskSpaceMBLabel=至少需要有 [mb] MB 的可用磁盘空间。 CannotInstallToNetworkDrive=安装程序无法安装到一个网络驱动器。 CannotInstallToUNCPath=安装程序无法安装到一个UNC路径。 -InvalidPath=您必须输入一个带驱动器卷标的完整路径,例如:%n%nC:\APP%n%n或下列形式的 UNC 路径:%n%n\\server\share +InvalidPath=您必须输入一个带驱动器卷标的完整路径,例如:%n%nC:\APP%n%n或下列形式的UNC路径:%n%n\\server\share InvalidDrive=您选定的驱动器或 UNC 共享不存在或不能访问。请选选择其它位置。 DiskSpaceWarningTitle=没有足够的磁盘空间 DiskSpaceWarning=安装程序至少需要 %1 KB 的可用空间才能安装,但选定驱动器只有 %2 KB 的可用空间。%n%n您一定要继续吗? -DirNameTooLong=文件夹名或路径太长。 -InvalidDirName=文件夹名是无效的。 -BadDirName32=文件夹名不能包含下列任何字符:%n%n%1 -DirExistsTitle=文件夹存在 -DirExists=文件夹:%n%n%1%n%n已经存在。您一定要安装到这个文件夹中吗? +DirNameTooLong=文件夹名称或路径太长。 +InvalidDirName=文件夹名称无效。 +BadDirName32=文件夹名称不能包含下列任何字符:%n%n%1 +DirExistsTitle=文件夹已存在 +DirExists=文件夹:%n%n%1%n%n已经存在。您一定要安装到这个文件夹中吗? DirDoesntExistTitle=文件夹不存在 -DirDoesntExist=文件夹:%n%n%1%n%n不存在。您想要创建此目录吗? +DirDoesntExist=文件夹:%n%n%1%n%n不存在。您想要创建此文件夹吗? ; *** “选择组件”向导页 WizardSelectComponents=选择组件 SelectComponentsDesc=您想安装哪些程序的组件? -SelectComponentsLabel2=选择您想要安装的组件;清除您不想安装的组件。然后单击“下一步”继续。 +SelectComponentsLabel2=选择您想要安装的组件;清除您不想安装的组件。然后点击“下一步”继续。 FullInstallation=完全安装 ; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) CompactInstallation=简洁安装 CustomInstallation=自定义安装 -NoUninstallWarningTitle=组件存在 -NoUninstallWarning=安装程序侦测到下列组件已在您的电脑中安装。:%n%n%1%n%n取消选定这些组件将不能卸载它们。%n%n您一定要继续吗? +NoUninstallWarningTitle=组件已存在 +NoUninstallWarning=安装程序检测到下列组件已在您的电脑中安装:%n%n%1%n%n取消选定这些组件将不能卸载它们。%n%n您一定要继续吗? ComponentSize1=%1 KB ComponentSize2=%1 MB ComponentsDiskSpaceGBLabel=当前选择的组件至少需要 [gb] GB 的磁盘空间。 @@ -185,40 +195,52 @@ ComponentsDiskSpaceMBLabel=当前选择的组件至少需要 [mb] MB 的磁盘 ; *** “选择附加任务”向导页 WizardSelectTasks=选择附加任务 SelectTasksDesc=您想要安装程序执行哪些附加任务? -SelectTasksLabel2=选择您想要安装程序在安装 [name] 时执行的附加任务,然后单击“下一步”。 +SelectTasksLabel2=选择您想要安装程序在安装 [name] 时执行的附加任务,然后点击“下一步”。 ; *** “选择开始菜单文件夹”向导页 WizardSelectProgramGroup=选择开始菜单文件夹 -SelectStartMenuFolderDesc=您想在哪里放置程序的快捷方式? +SelectStartMenuFolderDesc=安装程序应该在哪里放置程序的快捷方式? SelectStartMenuFolderLabel3=安装程序现在将在下列开始菜单文件夹中创建程序的快捷方式。 -SelectStartMenuFolderBrowseLabel=单击“下一步”继续。如果您想选择其它文件夹,单击“浏览”。 +SelectStartMenuFolderBrowseLabel=点击“下一步”继续。如果您想选择其它文件夹,点击“浏览”。 MustEnterGroupName=您必须输入一个文件夹名。 GroupNameTooLong=文件夹名或路径太长。 InvalidGroupName=文件夹名是无效的。 -BadGroupName=文件夹名不能包含下列任何字符:%n%n%1 +BadGroupName=文件夹名不能包含下列任何字符:%n%n%1 NoProgramGroupCheck2=不创建开始菜单文件夹(&D) ; *** “准备安装”向导页 WizardReady=准备安装 ReadyLabel1=安装程序现在准备开始安装 [name] 到您的电脑中。 -ReadyLabel2a=单击“安装”继续此安装程序。如果您想要回顾或改变设置,请单击“上一步”。 -ReadyLabel2b=单击“安装”继续此安装程序? -ReadyMemoUserInfo=用户信息: -ReadyMemoDir=目标位置: -ReadyMemoType=安装类型: -ReadyMemoComponents=选定组件: -ReadyMemoGroup=开始菜单文件夹: -ReadyMemoTasks=附加任务: +ReadyLabel2a=点击“安装”继续此安装程序。如果您想要回顾或修改设置,请点击“上一步”。 +ReadyLabel2b=点击“安装”继续此安装程序? +ReadyMemoUserInfo=用户信息: +ReadyMemoDir=目标位置: +ReadyMemoType=安装类型: +ReadyMemoComponents=选定组件: +ReadyMemoGroup=开始菜单文件夹: +ReadyMemoTasks=附加任务: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=正在下载附加文件... +ButtonStopDownload=停止下载(&S) +StopDownload=您确定要停止下载吗? +ErrorDownloadAborted=下载已中止 +ErrorDownloadFailed=下载失败:%1 %2 +ErrorDownloadSizeFailed=获取下载大小失败:%1 %2 +ErrorFileHash1=校验文件哈希失败:%1 +ErrorFileHash2=无效的文件哈希:预期 %1,实际 %2 +ErrorProgress=无效的进度:%1,总共%2 +ErrorFileSize=文件大小错误:预期 %1,实际 %2 ; *** “正在准备安装”向导页 WizardPreparing=正在准备安装 PreparingDesc=安装程序正在准备安装 [name] 到您的电脑中。 PreviousInstallNotCompleted=先前程序的安装/卸载未完成。您需要重新启动您的电脑才能完成安装。%n%n在重新启动电脑后,再运行安装完成 [name] 的安装。 -CannotContinue=安装程序不能继续。请单击“取消”退出。 +CannotContinue=安装程序不能继续。请点击“取消”退出。 ApplicationsFound=下列应用程序正在使用的文件需要更新设置。它是建议您允许安装程序自动关闭这些应用程序。 ApplicationsFound2=下列应用程序正在使用的文件需要更新设置。它是建议您允许安装程序自动关闭这些应用程序。安装完成后,安装程序将尝试重新启动应用程序。 CloseApplications=自动关闭该应用程序(&A) -DontCloseApplications=不要关闭该应用程序(D) +DontCloseApplications=不要关闭该应用程序(&D) ErrorCloseApplications=安装程序无法自动关闭所有应用程序。在继续之前,我们建议您关闭所有使用需要更新的安装程序文件。 PrepareToInstallNeedsRestart=安装程序必须重新启动计算机。重新启动计算机后,请再次运行安装程序以完成 [name] 的安装。%n%n是否立即重新启动? @@ -230,27 +252,27 @@ InstallingLabel=安装程序正在安装 [name] 到您的电脑中,请稍等 FinishedHeadingLabel=[name] 安装完成 FinishedLabelNoIcons=安装程序已在您的电脑中安装了 [name]。 FinishedLabel=安装程序已在您的电脑中安装了 [name]。此应用程序可以通过选择安装的快捷方式运行。 -ClickFinish=单击“完成”退出安装程序。 -FinishedRestartLabel=要完成 [name] 的安装,安装程序必须重新启动您的电脑。您想现在重新启动吗? -FinishedRestartMessage=要完成 [name] 的安装,安装程序必须重新启动您的电脑。%n%n您想现在重新启动吗? -ShowReadmeCheck=是,您想查阅自述文件 +ClickFinish=点击“完成”退出安装程序。 +FinishedRestartLabel=要完成 [name] 的安装,安装程序必须重新启动您的电脑。您想要立即重新启动吗? +FinishedRestartMessage=要完成 [name] 的安装,安装程序必须重新启动您的电脑。%n%n您想要立即重新启动吗? +ShowReadmeCheck=是,我想查阅自述文件 YesRadio=是,立即重新启动电脑(&Y) NoRadio=否,稍后重新启动电脑(&N) -; 用于象“运行 MyProg.exe” +; used for example as 'Run MyProg.exe' RunEntryExec=运行 %1 -; 用于象“查阅 Readme.txt” +; used for example as 'View Readme.txt' RunEntryShellExec=查阅 %1 ; *** “安装程序需要下一张磁盘”提示 ChangeDiskTitle=安装程序需要下一张磁盘 -SelectDiskLabel2=请插入磁盘 %1 并单击“确定”。%n%n如果这个磁盘中的文件不能在不同于下列显示的文件夹中找到,输入正确的路径或单击“浏览”。 -PathLabel=路径(&P): +SelectDiskLabel2=请插入磁盘 %1 并点击“确定”。%n%n如果这个磁盘中的文件可以在下列文件夹之外的文件夹中找到,请输入正确的路径或点击“浏览”。 +PathLabel=路径(&P): FileNotInDir2=文件“%1”不能在“%2”定位。请插入正确的磁盘或选择其它文件夹。 SelectDirectoryLabel=请指定下一张磁盘的位置。 ; *** 安装状态消息 SetupAborted=安装程序未完成安装。%n%n请修正这个问题并重新运行安装程序。 -AbortRetryIgnoreSelectAction=选项 +AbortRetryIgnoreSelectAction=选择操作 AbortRetryIgnoreRetry=重试(&T) AbortRetryIgnoreIgnore=忽略错误并继续(&I) AbortRetryIgnoreCancel=关闭安装程序 @@ -269,41 +291,49 @@ StatusRestartingApplications=正在重启应用程序... StatusRollback=正在撤销更改... ; *** 其它错误 -ErrorInternal2=内部错误: %1 +ErrorInternal2=内部错误:%1 ErrorFunctionFailedNoCode=%1 失败 ErrorFunctionFailed=%1 失败;错误代码 %2 ErrorFunctionFailedWithMessage=%1 失败;错误代码 %2.%n%3 -ErrorExecutingProgram=不能执行文件:%n%1 +ErrorExecutingProgram=不能执行文件:%n%1 ; *** 注册表错误 -ErrorRegOpenKey=打开注册表项时出错:%n%1\%2 -ErrorRegCreateKey=创建注册表项时出错:%n%1\%2 -ErrorRegWriteKey=写入注册表项时出错:%n%1\%2 +ErrorRegOpenKey=打开注册表项时出错:%n%1\%2 +ErrorRegCreateKey=创建注册表项时出错:%n%1\%2 +ErrorRegWriteKey=写入注册表项时出错:%n%1\%2 ; *** INI 错误 -ErrorIniEntry=在文件“%1”创建 INI 项目错误。 +ErrorIniEntry=在文件“%1”中创建INI条目时出错。 ; *** 文件复制错误 -FileAbortRetryIgnoreSkipNotRecommended=跳过这个文件 (不推荐)(&S) -FileAbortRetryIgnoreIgnoreNotRecommended=忽略错误并继续 (不推荐)(&I) +FileAbortRetryIgnoreSkipNotRecommended=跳过这个文件(&S) (不推荐) +FileAbortRetryIgnoreIgnoreNotRecommended=忽略错误并继续(&I) (不推荐) SourceIsCorrupted=源文件已损坏 SourceDoesntExist=源文件“%1”不存在 ExistingFileReadOnly2=无法替换现有文件,因为它是只读的。 ExistingFileReadOnlyRetry=移除只读属性并重试(&R) ExistingFileReadOnlyKeepExisting=保留现有文件(&K) -ErrorReadingExistingDest=尝试读取现有文件时发生一个错误: -FileExists=文件已经存在。%n%n您想要安装程序覆盖它吗? -ExistingFileNewer=现有的文件新与安装程序要安装的文件。推荐您保留现有文件。%n%n您想要保留现有的文件吗? -ErrorChangingAttr=尝试改变下列现有的文件的属性时发生一个错误: -ErrorCreatingTemp=尝试在目标目录创建文件时发生一个错误: -ErrorReadingSource=尝试读取下列源文件时发生一个错误: -ErrorCopying=尝试复制下列文件时发生一个错误: -ErrorReplacingExistingFile=尝试替换现有的文件时发生错误: -ErrorRestartReplace=重启电脑后替换文件失败: -ErrorRenamingTemp=尝试重新命名以下目标目录中的一个文件时发生错误: -ErrorRegisterServer=不能注册 DLL/OCX: %1 +ErrorReadingExistingDest=尝试读取现有文件时出错: +FileExistsSelectAction=选择操作 +FileExists2=文件已经存在。 +FileExistsOverwriteExisting=覆盖已经存在的文件(&O) +FileExistsKeepExisting=保留现有的文件(&K) +FileExistsOverwriteOrKeepAll=为所有的冲突文件执行此操作(&D) +ExistingFileNewerSelectAction=选择操作 +ExistingFileNewer2=现有的文件比安装程序将要安装的文件更新。 +ExistingFileNewerOverwriteExisting=覆盖已经存在的文件(&O) +ExistingFileNewerKeepExisting=保留现有的文件(&K) (推荐) +ExistingFileNewerOverwriteOrKeepAll=为所有的冲突文件执行此操作(&D) +ErrorChangingAttr=尝试改变下列现有的文件的属性时出错: +ErrorCreatingTemp=尝试在目标目录创建文件时出错: +ErrorReadingSource=尝试读取下列源文件时出错: +ErrorCopying=尝试复制下列文件时出错: +ErrorReplacingExistingFile=尝试替换现有的文件时出错: +ErrorRestartReplace=重新启动替换失败: +ErrorRenamingTemp=尝试重新命名以下目标目录中的一个文件时出错: +ErrorRegisterServer=无法注册 DLL/OCX:%1 ErrorRegSvr32Failed=RegSvr32 失败;退出代码 %1 -ErrorRegisterTypeLib=不能注册类型库: %1 +ErrorRegisterTypeLib=无法注册类型库:%1 ; *** 卸载显示名字标记 ; used for example as 'My Program (32-bit)' @@ -316,34 +346,34 @@ UninstallDisplayNameMarkAllUsers=所有用户 UninstallDisplayNameMarkCurrentUser=当前用户 ; *** 安装后错误 -ErrorOpeningReadme=当尝试打开自述文件时发生一个错误。 +ErrorOpeningReadme=尝试打开自述文件时出错。 ErrorRestartingComputer=安装程序不能重新启动电脑,请手动重启。 ; *** 卸载消息 -UninstallNotFound=文件“%1”不存在。不能卸载。 -UninstallOpenError=文件“%1”不能打开。不能卸载。 -UninstallUnsupportedVer=卸载日志文件“%1”有未被这个版本的卸载器承认的格式。不能卸载 +UninstallNotFound=文件“%1”不存在。无法卸载。 +UninstallOpenError=文件“%1”不能打开。无法卸载。 +UninstallUnsupportedVer=此版本的卸载程序无法识别卸载日志文件“%1”的格式。无法卸载 UninstallUnknownEntry=在卸载日志中遇到一个未知的条目 (%1) ConfirmUninstall=您确认想要完全删除 %1 及它的所有组件吗? -UninstallOnlyOnWin64=这个安装程序只能在 64 位 Windows 中进行卸载。 -OnlyAdminCanUninstall=这个安装的程序只能是有管理员权限的用户才能卸载。 -UninstallStatusLabel=正在从您的电脑中删除 %1,请等待。 +UninstallOnlyOnWin64=这个安装程序只能在64位Windows中进行卸载。 +OnlyAdminCanUninstall=这个安装的程序需要有管理员权限的用户才能卸载。 +UninstallStatusLabel=正在从您的电脑中删除 %1,请稍等。 UninstalledAll=%1 已顺利地从您的电脑中删除。 -UninstalledMost=%1 卸载完成。%n%n有一些内容不能被删除。您可以手工删除它们。 -UninstalledAndNeedsRestart=要完成 %1 的卸载,您的电脑必须重新启动。%n%n您现在想重新启动电脑吗? -UninstallDataCorrupted=“%1”文件被破坏,不能卸载 +UninstalledMost=%1 卸载完成。%n%n有一些内容无法被删除。您可以手动删除它们。 +UninstalledAndNeedsRestart=要完成 %1 的卸载,您的电脑必须重新启动。%n%n您想立即重新启动电脑吗? +UninstallDataCorrupted=文件“%1”已损坏,无法卸载 ; *** 卸载状态消息 ConfirmDeleteSharedFileTitle=删除共享文件吗? -ConfirmDeleteSharedFile2=系统中包含的下列共享文件已经不被其它程序使用。您想要卸载程序删除这些共享文件吗?%n%n如果这些文件被删除,但还有程序正在使用这些文件,这些程序可能不能正确执行。如果您不能确定,选择“否”。把这些文件保留在系统中以免引起问题。 -SharedFileNameLabel=文件名: -SharedFileLocationLabel=位置: +ConfirmDeleteSharedFile2=系统中包含的下列共享文件已经不再被其它程序使用。您想要卸载程序删除这些共享文件吗?%n%n如果这些文件被删除,但还有程序正在使用这些文件,这些程序可能不能正确执行。如果您不能确定,选择“否”。把这些文件保留在系统中以免引起问题。 +SharedFileNameLabel=文件名: +SharedFileLocationLabel=位置: WizardUninstalling=卸载状态 StatusUninstalling=正在卸载 %1... ; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=正在安装 %1. -ShutdownBlockReasonUninstallingApp=正在卸载 %1. +ShutdownBlockReasonInstallingApp=正在安装 %1。 +ShutdownBlockReasonUninstallingApp=正在卸载 %1。 ; The custom messages below aren't used by Setup itself, but if you make ; use of them in your scripts, you'll want to translate them. @@ -351,7 +381,7 @@ ShutdownBlockReasonUninstallingApp=正在卸载 %1. [CustomMessages] NameAndVersion=%1 版本 %2 -AdditionalIcons=附加快捷方式: +AdditionalIcons=附加快捷方式: CreateDesktopIcon=创建桌面快捷方式(&D) CreateQuickLaunchIcon=创建快速运行栏快捷方式(&Q) ProgramOnTheWeb=%1 网站 @@ -359,7 +389,6 @@ UninstallProgram=卸载 %1 LaunchProgram=运行 %1 AssocFileExtension=将 %2 文件扩展名与 %1 建立关联(&A) AssocingFileExtension=正在将 %2 文件扩展名与 %1 建立关联... -AutoStartProgramGroupDescription=启动组: +AutoStartProgramGroupDescription=启动组: AutoStartProgram=自动启动 %1 AddonHostProgramNotFound=%1无法找到您所选择的文件夹。%n%n您想要继续吗? - diff --git a/installer/innosetup/Languages/ChineseTraditional.isl b/installer/innosetup/Languages/ChineseTraditional.isl index 9c692956e..1663b45c8 100644 --- a/installer/innosetup/Languages/ChineseTraditional.isl +++ b/installer/innosetup/Languages/ChineseTraditional.isl @@ -1,27 +1,29 @@ -; *** Inno Setup version 6.0.0+ Chinese Traditional messages *** -; -; Name: John Wu, mr.johnwu@gmail.com -; Base on 5.5.3+ translations by Samuel Lee, Email: 751555749@qq.com +; *** Inno Setup version 6.1.0+ Chinese Traditional messages *** +; Name: Enfong Tsao, nelson22768384@gmail.com +; Based on 5.5.3+ translations by Samuel Lee, Email: 751555749@qq.com ; Translation based on network resource ; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). [LangOptions] ; The following three entries are very important. Be sure to read and ; understand the '[LangOptions] section' topic in the help file. -; If Language Name display incorrect, uncomment next line LanguageName=<7e41><9ad4><4e2d><6587> LanguageID=$0404 LanguageCodepage=950 ; If the language you are translating to requires special font faces or ; sizes, uncomment any of the following entries and change them accordingly. -DialogFontName=新細明體 -DialogFontSize=9 -TitleFontName=Arial -TitleFontSize=28 -WelcomeFontName=新細明體 -WelcomeFontSize=12 -CopyrightFontName=新細明體 -CopyrightFontSize=9 +;DialogFontName= +;DialogFontSize=8 +;TitleFontName=Arial +;TitleFontSize=29 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;CopyrightFontName=Arial +;CopyrightFontSize=8 [Messages] @@ -37,7 +39,7 @@ ConfirmTitle=確認 ErrorTitle=錯誤 ; *** SetupLdr messages -SetupLdrStartupMessage=這將會安裝 %1。您想要繼續嗎? +SetupLdrStartupMessage=這將會安裝 %1。您想要繼續嗎? LdrCannotCreateTemp=無法建立暫存檔案。安裝程式將會結束。 LdrCannotExecTemp=無法執行暫存檔案。安裝程式將會結束。 HelpTextNote= @@ -58,8 +60,8 @@ WinVersionTooLowError=這個程式必須在 %1 版本 %2 或以上的系統執 WinVersionTooHighError=這個程式無法安裝在 %1 版本 %2 或以上的系統。 AdminPrivilegesRequired=您必須登入成系統管理員以安裝這個程式。 PowerUserPrivilegesRequired=您必須登入成具有系統管理員或 Power User 權限的使用者以安裝這個程式。 -SetupAppRunningError=安裝程式偵測到 %1 正在執行。%n%n請關閉該程式後按 [確定] 繼續,或按 [取消] 離開。 -UninstallAppRunningError=解除安裝程式偵測到 %1 正在執行。%n%n請關閉該程式後按 [確定] 繼續,或按 [取消] 離開。 +SetupAppRunningError=安裝程式偵測到 %1 正在執行。%n%n請關閉該程式後按 「確定」 繼續,或按 「取消」 離開。 +UninstallAppRunningError=解除安裝程式偵測到 %1 正在執行。%n%n請關閉該程式後按 「確定」 繼續,或按 「取消」 離開。 ; *** Startup questions PrivilegesRequiredOverrideTitle=選擇安裝程式安裝模式 @@ -78,7 +80,7 @@ ErrorTooManyFilesInDir=無法在資料夾“%1”內建立檔案,因為資料 ; *** Setup common messages ExitSetupTitle=結束安裝程式 ExitSetupMessage=安裝尚未完成。如果您現在結束安裝程式,這個程式將不會被安裝。%n%n您可以稍後再執行安裝程式以完成安裝程序。您現在要結束安裝程式嗎? -AboutSetupMenuItem=關於安裝程式(&A)... +AboutSetupMenuItem=關於安裝程式 (&A)... AboutSetupTitle=關於安裝程式 AboutSetupMessage=%1 版本 %2%n%3%n%n%1 網址:%n%4 AboutSetupNote= @@ -91,23 +93,23 @@ ButtonNext=下一步(&N) > ButtonOK=確定 ButtonCancel=取消 ButtonYes=是(&Y) -ButtonYesToAll=全部皆是(&A) +ButtonYesToAll=全部皆是 (&A) ButtonNo=否(&N) -ButtonNoToAll=全部皆否(&O) -ButtonFinish=完成(&F) -ButtonBrowse=瀏覽(&B)... -ButtonWizardBrowse=瀏覽(&R)... -ButtonNewFolder=建立新資料夾(&M) +ButtonNoToAll=全部皆否 (&O) +ButtonFinish=完成 (&F) +ButtonBrowse=瀏覽 (&B)... +ButtonWizardBrowse=瀏覽 (&R)... +ButtonNewFolder=建立新資料夾 (&M) ; *** "Select Language" dialog messages SelectLanguageTitle=選擇安裝語言 SelectLanguageLabel=選擇在安裝過程中使用的語言: ; *** Common wizard text -ClickNext=按 [下一步] 繼續安裝,或按 [取消] 結束安裝程式。 +ClickNext=按 「下一步」 繼續安裝,或按 「取消」 結束安裝程式。 BeveledLabel= BrowseDialogTitle=瀏覽資料夾 -BrowseDialogLabel=在下面的資料夾列表中選擇一個資料夾,然後按 [確定]。 +BrowseDialogLabel=在下面的資料夾列表中選擇一個資料夾,然後按 「確定」。 NewFolderName=新資料夾 ; *** "Welcome" wizard page @@ -117,24 +119,24 @@ WelcomeLabel2=這個安裝程式將會安裝 [name/ver] 到您的電腦。%n%n ; *** "Password" wizard page WizardPassword=密碼 PasswordLabel1=這個安裝程式具有密碼保護。 -PasswordLabel3=請輸入密碼,然後按 [下一步] 繼續。密碼是區分大小寫的。 -PasswordEditLabel=密碼(&P): +PasswordLabel3=請輸入密碼,然後按 「下一步」 繼續。密碼是區分大小寫的。 +PasswordEditLabel=密碼 (&P): IncorrectPassword=您輸入的密碼不正確,請重新輸入。 ; *** "License Agreement" wizard page WizardLicense=授權合約 LicenseLabel=請閱讀以下授權合約。 LicenseLabel3=請閱讀以下授權合約,您必須接受合約的各項條款才能繼續安裝。 -LicenseAccepted=我同意(&A) -LicenseNotAccepted=我不同意(&D) +LicenseAccepted=我同意 (&A) +LicenseNotAccepted=我不同意 (&D) ; *** "Information" wizard pages WizardInfoBefore=訊息 InfoBeforeLabel=在繼續安裝之前請閱讀以下重要資訊。 -InfoBeforeClickLabel=當您準備好繼續安裝,請按 [下一步]。 +InfoBeforeClickLabel=當您準備好繼續安裝,請按 「下一步」。 WizardInfoAfter=訊息 InfoAfterLabel=在繼續安裝之前請閱讀以下重要資訊。 -InfoAfterClickLabel=當您準備好繼續安裝,請按 [下一步]。 +InfoAfterClickLabel=當您準備好繼續安裝,請按 「下一步」。 ; *** "User Information" wizard page WizardUserInfo=使用者資訊 @@ -148,14 +150,15 @@ UserInfoNameRequired=您必須輸入您的名稱。 WizardSelectDir=選擇目的資料夾 SelectDirDesc=選擇安裝程式安裝 [name] 的位置。 SelectDirLabel3=安裝程式將會把 [name] 安裝到下面的資料夾。 -SelectDirBrowseLabel=按 [下一步] 繼續,如果您想選擇另一個資料夾,請按 [瀏覽]。 +SelectDirBrowseLabel=按 「下一步」 繼續,如果您想選擇另一個資料夾,請按 「瀏覽」。 +DiskSpaceGBLabel=最少需要 [gb] GB 磁碟空間。 DiskSpaceMBLabel=最少需要 [mb] MB 磁碟空間。 CannotInstallToNetworkDrive=安裝程式無法安裝於網絡磁碟機。 CannotInstallToUNCPath=安裝程式無法安裝於 UNC 路徑。 InvalidPath=您必須輸入完整的路徑名稱及磁碟機代碼。%n%n例如 C:\App 或 UNC 路徑格式 \\伺服器\共用資料夾。 InvalidDrive=您選取的磁碟機或 UNC 名稱不存在或無法存取,請選擇其他的目的地。 DiskSpaceWarningTitle=磁碟空間不足 -DiskSpaceWarning=安裝程式需要至少 %1 KB 的磁碟空間,您所選取的磁碟只有 %2 KB 可用空間。%n%n您要繼續安裝嗎? +DiskSpaceWarning=安裝程式需要至少 %1 KB 的磁碟空間,您所選取的磁碟只有 %2 KB 可用空間。%n%n您要繼續安裝嗎? DirNameTooLong=資料夾名稱或路徑太長。 InvalidDirName=資料夾名稱不正確。 BadDirName32=資料夾名稱不得包含以下特殊字元:%n%n%1 @@ -167,38 +170,39 @@ DirDoesntExist=資料夾:%n%n%1%n%n 不存在。要建立該資料夾嗎? ; *** "Select Components" wizard page WizardSelectComponents=選擇元件 SelectComponentsDesc=選擇將會被安裝的元件。 -SelectComponentsLabel2=選擇您想要安裝的元件;清除您不想安裝的元件。然後按 [下一步] 繼續安裝。 +SelectComponentsLabel2=選擇您想要安裝的元件;清除您不想安裝的元件。然後按 「下一步」 繼續安裝。 FullInstallation=完整安裝 ; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) CompactInstallation=最小安裝 CustomInstallation=自訂安裝 NoUninstallWarningTitle=元件已存在 -NoUninstallWarning=安裝程式偵測到以下元件已經安裝在您的電腦上:%n%n%1%n%n取消選擇這些元件將不會移除它們。%n%n您仍然要繼續嗎? +NoUninstallWarning=安裝程式偵測到以下元件已經安裝在您的電腦上:%n%n%1%n%n取消選擇這些元件將不會移除它們。%n%n您仍然要繼續嗎? ComponentSize1=%1 KB ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=目前的選擇需要至少 [gb] GB 磁碟空間。 ComponentsDiskSpaceMBLabel=目前的選擇需要至少 [mb] MB 磁碟空間。 ; *** "Select Additional Tasks" wizard page WizardSelectTasks=選擇附加的工作 SelectTasksDesc=選擇要執行的附加工作。 -SelectTasksLabel2=選擇安裝程式在安裝 [name] 時要執行的附加工作,然後按 [下一步]。 +SelectTasksLabel2=選擇安裝程式在安裝 [name] 時要執行的附加工作,然後按 「下一步」。 ; *** "Select Start Menu Folder" wizard page WizardSelectProgramGroup=選擇「開始」功能表的資料夾 SelectStartMenuFolderDesc=選擇安裝程式建立程式的捷徑的位置。 SelectStartMenuFolderLabel3=安裝程式將會把程式的捷徑建立在下面的「開始」功能表資料夾。 -SelectStartMenuFolderBrowseLabel=按 [下一步] 繼續,如果您想選擇另一個資料夾,請按 [瀏覽]。 +SelectStartMenuFolderBrowseLabel=按 「下一步」 繼續,如果您想選擇另一個資料夾,請按 「瀏覽」。 MustEnterGroupName=您必須輸入一個資料夾的名稱。 GroupNameTooLong=資料夾名稱或路徑太長。 InvalidGroupName=資料夾名稱不正確。 BadGroupName=資料夾名稱不得包含下列字元:%n%n%1 -NoProgramGroupCheck2=不要在「開始」功能表中建立資料夾(&D) +NoProgramGroupCheck2=不要在「開始」功能表中建立資料夾 (&D) ; *** "Ready to Install" wizard page WizardReady=準備安裝 ReadyLabel1=安裝程式將開始安裝 [name] 到您的電腦中。 -ReadyLabel2a=按下 [安裝] 繼續安裝,或按 [上一步] 重新檢視或設定各選項的內容。 -ReadyLabel2b=按下 [安裝] 繼續安裝。 +ReadyLabel2a=按下 「安裝」 繼續安裝,或按 「上一步」 重新檢視或設定各選項的內容。 +ReadyLabel2b=按下 「安裝」 繼續安裝。 ReadyMemoUserInfo=使用者資訊 ReadyMemoDir=目的資料夾: ReadyMemoType=安裝型態: @@ -206,16 +210,29 @@ ReadyMemoComponents=選擇的元件: ReadyMemoGroup=「開始」功能表資料夾: ReadyMemoTasks=附加工作: +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=正在下載額外檔案... +ButtonStopDownload=停止下載 (&S) +StopDownload=您確定要停止下載嗎? +ErrorDownloadAborted=已停止下載 +ErrorDownloadFailed=下載失敗: %1 %2 +ErrorDownloadSizeFailed=取得檔案大小失敗: %1 %2 +ErrorFileHash1=檔案雜湊失敗: %1 +ErrorFileHash2=檔案雜湊無效: 必須為 %1,收到 %2 +ErrorProgress=進度無效: %1 之 %2 +ErrorFileSize=檔案大小無效: 必須為 %1,收到 %2 + ; *** "Preparing to Install" wizard page WizardPreparing=準備安裝程式 PreparingDesc=安裝程式準備將 [name] 安裝到您的電腦上。 PreviousInstallNotCompleted=先前的安裝/ 解除安裝尚未完成,您必須重新啟動電腦以完成該安裝。%n%n在重新啟動電腦之後,請再執行這個程式來安裝 [name]。 -CannotContinue=安裝程式無法繼續。請按 [取消] 離開。 -ApplicationsFound=下面的應用程式正在使用安裝程式所需要更新的文檔。建議您允許安裝程式自動關閉這些應用程式。 -ApplicationsFound2=下面的應用程式正在使用安裝程式所需要更新的文檔。建議您允許安裝程式自動關閉這些應用程式。當安裝過程結束後,本安裝程式將會嘗試重新開啟該應用程式。 -CloseApplications=關閉應用程式(&A) +CannotContinue=安裝程式無法繼續。請按 「取消」 離開。 +ApplicationsFound=下面的應用程式正在使用安裝程式所需要更新的檔案。建議您允許安裝程式自動關閉這些應用程式。 +ApplicationsFound2=下面的應用程式正在使用安裝程式所需要更新的檔案。建議您允許安裝程式自動關閉這些應用程式。當安裝過程結束後,本安裝程式將會嘗試重新開啟該應用程式。 +CloseApplications=關閉應用程式 (&A) DontCloseApplications=不要關閉應用程式 (&D) ErrorCloseApplications=安裝程式無法自動關閉所有應用程式。建議您在繼續前先關閉所有應用程式使用的檔案。 +PrepareToInstallNeedsRestart=安裝程式必須重新啟動您的電腦。重新啟動後,請再次執行安裝程式以完成 [name] 的安裝。%n%n您想要現在重新啟動電腦嗎? ; *** "Installing" wizard page WizardInstalling=正在安裝 @@ -225,9 +242,9 @@ InstallingLabel=請稍候,安裝程式正在將 [name] 安裝到您的電腦 FinishedHeadingLabel=安裝完成 FinishedLabelNoIcons=安裝程式已經將 [name] 安裝在您的電腦上。 FinishedLabel=安裝程式已經將 [name] 安裝在您的電腦中,您可以選擇程式的圖示來執行該應用程式。 -ClickFinish=按 [完成] 以結束安裝程式。 -FinishedRestartLabel=要完成 [name] 的安裝,安裝程式必須重新啟動您的電腦。您想要現在重新啟動電腦嗎? -FinishedRestartMessage=要完成 [name] 的安裝,安裝程式必須重新啟動您的電腦。%n%n您想要現在重新啟動電腦嗎? +ClickFinish=按 「完成」 以結束安裝程式。 +FinishedRestartLabel=要完成 [name] 的安裝,安裝程式必須重新啟動您的電腦。您想要現在重新啟動電腦嗎? +FinishedRestartMessage=要完成 [name] 的安裝,安裝程式必須重新啟動您的電腦。%n%n您想要現在重新啟動電腦嗎? ShowReadmeCheck=是,我要閱讀讀我檔案。 YesRadio=是,立即重新啟動電腦(&Y) NoRadio=否,我稍後重新啟動電腦(&N) @@ -238,7 +255,7 @@ RunEntryShellExec=檢視 %1 ; *** "Setup Needs the Next Disk" ChangeDiskTitle=安裝程式需要下一張磁片 -SelectDiskLabel2=請插入磁片 %1,然後按 [確定]。%n%n如果檔案不在以下所顯示的資料夾之中,請輸入正確的資料夾名稱或按 [瀏覽] 選取。 +SelectDiskLabel2=請插入磁片 %1,然後按 「確定」。%n%n如果檔案不在以下所顯示的資料夾之中,請輸入正確的資料夾名稱或按 [瀏覽] 選取。 PathLabel=路徑(&P): FileNotInDir2=檔案“%1”無法在“%2”找到。請插入正確的磁片或選擇其它的資料夾。 SelectDirectoryLabel=請指定下一張磁片的位置。 @@ -287,12 +304,20 @@ ExistingFileReadOnly2=無法取代現有檔案,因為檔案已標示為唯讀 ExistingFileReadOnlyRetry=移除唯讀屬性並重試 (&R) ExistingFileReadOnlyKeepExisting=保留現有檔案 (&K) ErrorReadingExistingDest=讀取一個已存在的檔案時發生錯誤: -FileExists=檔案已經存在。%n%n 要讓安裝程式加以覆寫嗎? -ExistingFileNewer=存在的檔案版本比較新,建議您保留目前已存在的檔案。%n%n您要保留目前已存在的檔案嗎? +FileExistsSelectAction=選擇操作 +FileExists2=檔案已存在。 +FileExistsOverwriteExisting=覆寫現有檔案 +FileExistsKeepExisting=保留現有檔案 (&O) +FileExistsOverwriteOrKeepAll=對下次衝突執行相同操作 (&D) +ExistingFileNewerSelectAction=選擇操作 +ExistingFileNewer2=現有檔案比安裝程式嘗試安裝的檔案還新。 +ExistingFileNewerOverwriteExisting=覆寫現有檔案 (&O) +ExistingFileNewerKeepExisting=保留現有檔案 (&K) (建議選項) +ExistingFileNewerOverwriteOrKeepAll=對下次衝突執行相同操作 (&D) ErrorChangingAttr=在變更檔案屬性時發生錯誤: ErrorCreatingTemp=在目的資料夾中建立檔案時發生錯誤: ErrorReadingSource=讀取原始檔案時發生錯誤: -ErrorCopying=復制檔案時發生錯誤: +ErrorCopying=複製檔案時發生錯誤: ErrorReplacingExistingFile=取代檔案時發生錯誤: ErrorRestartReplace=重新啟動電腦後取代檔案失敗: ErrorRenamingTemp=在目的資料夾變更檔案名稱時發生錯誤: @@ -305,28 +330,28 @@ ErrorRegisterTypeLib=無法注冊類型庫: %1。 UninstallDisplayNameMark=%1 (%2) ; used for example as 'My Program (32-bit, All users)' UninstallDisplayNameMarks=%1 (%2, %3) -UninstallDisplayNameMark32Bit=32-bit -UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMark32Bit=32 位元 +UninstallDisplayNameMark64Bit=64 位元 UninstallDisplayNameMarkAllUsers=所有使用者 UninstallDisplayNameMarkCurrentUser=目前使用者 ; *** Post-installation errors ErrorOpeningReadme=開啟讀我檔案時發生錯誤。 -ErrorRestartingComputer=安裝程式無法重新啟動電腦,請以手動方式自行重新啟動電腦。 +ErrorRestartingComputer=安裝程式無法重新啟動電腦,請自行重新啟動。 ; *** Uninstaller messages -UninstallNotFound=檔案“%1”不存在,無法移除程式。 -UninstallOpenError=無法開啟檔案“%1”,無法移除程式。 +UninstallNotFound=檔案“%1”不存在,無法解除安裝。 +UninstallOpenError=無法開啟檔案“%1”,無法解除安裝 UninstallUnsupportedVer=這個版本的解除安裝程式無法辨識記錄檔 “%1” 之格式,無法解除安裝。 UninstallUnknownEntry=解除安裝記錄檔中發現未知的記錄 (%1)。 -ConfirmUninstall=您確定要完全移除 %1 及其相關的檔案嗎? +ConfirmUninstall=您確定要完全移除 %1 及其相關的檔案嗎? UninstallOnlyOnWin64=這個程式只能在 64 位元的 Windows 上解除安裝。 OnlyAdminCanUninstall=這個程式要具備系統管理員權限的使用者方可解除安裝。 UninstallStatusLabel=正在從您的電腦移除 %1 中,請稍候... UninstalledAll=%1 已經成功從您的電腦中移除。 UninstalledMost=%1 解除安裝完成。%n%n某些檔案及元件無法移除,您可以自行刪除這些檔案。 -UninstalledAndNeedsRestart=要完成 %1 的解除安裝程序,您必須重新啟動電腦。%n%n您想要現在重新啟動電腦嗎? -UninstallDataCorrupted=檔案“%1”已經損毀,無法解除安裝。 +UninstalledAndNeedsRestart=要完成 %1 的解除安裝程序,您必須重新啟動電腦。%n%n您想要現在重新啟動電腦嗎? +UninstallDataCorrupted=檔案“%1”已經損毀,無法解除安裝 ; *** Uninstallation phase messages ConfirmDeleteSharedFileTitle=移除共用檔案 @@ -337,8 +362,8 @@ WizardUninstalling=解除安裝狀態 StatusUninstalling=正在解除安裝 %1... ; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=正在安裝 %1. -ShutdownBlockReasonUninstallingApp=正在解除安裝 %1. +ShutdownBlockReasonInstallingApp=正在安裝 %1。 +ShutdownBlockReasonUninstallingApp=正在解除安裝 %1。 ; The custom messages below aren't used by Setup itself, but if you make ; use of them in your scripts, you'll want to translate them. @@ -356,4 +381,4 @@ AssocFileExtension=將 %1 與檔案副檔名 %2 產生關聯(&A) AssocingFileExtension=正在將 %1 與檔案副檔名 %2 產生關聯... AutoStartProgramGroupDescription=開啟: AutoStartProgram=自動開啟 %1 -AddonHostProgramNotFound=%1 無法在您所選的資料夾中找到。%n%n您是否還要繼續? +AddonHostProgramNotFound=%1 無法在您所選的資料夾中找到。%n%n您是否還要繼續? \ No newline at end of file diff --git a/installer/innosetup/Languages/Corsican.isl b/installer/innosetup/Languages/Corsican.isl new file mode 100644 index 000000000..6f03bcaf3 --- /dev/null +++ b/installer/innosetup/Languages/Corsican.isl @@ -0,0 +1,399 @@ +; *** Inno Setup version 6.1.0+ Corsican messages *** +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +; Created and maintained by Patriccollu di Santa Maria è Sichè +; Schedariu di traduzzione in lingua corsa da Patriccollu +; E-mail: Patrick.Santa-Maria[at]LaPoste.Net +; +; Changes: +; November 14th, 2020 - Changes to current version 6.1.0+ +; July 25th, 2020 - Update to version 6.1.0+ +; July 1st, 2020 - Update to version 6.0.6+ +; October 6th, 2019 - Update to version 6.0.3+ +; January 20th, 2019 - Update to version 6.0.0+ +; April 9th, 2016 - Changes to current version 5.5.3+ +; January 3rd, 2013 - Update to version 5.5.3+ +; August 8th, 2012 - Update to version 5.5.0+ +; September 17th, 2011 - Creation for version 5.1.11 + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Corsu +LanguageID=$0483 +LanguageCodePage=1252 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=Assistente d’installazione +SetupWindowTitle=Assistente d’installazione - %1 +UninstallAppTitle=Disinstallà +UninstallAppFullTitle=Disinstallazione di %1 + +; *** Misc. common +InformationTitle=Infurmazione +ConfirmTitle=Cunfirmà +ErrorTitle=Sbagliu + +; *** SetupLdr messages +SetupLdrStartupMessage=St’assistente hà da installà %1. Vulete cuntinuà ? +LdrCannotCreateTemp=Impussibule di creà un cartulare timpurariu. Assistente d’installazione interrottu +LdrCannotExecTemp=Impussibule d’eseguisce u schedariu in u cartulare timpurariu. Assistente d’installazione interrottu +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nSbagliu %2 : %3 +SetupFileMissing=U schedariu %1 manca in u cartulare d’installazione. Ci vole à currege u penseru o ottene una nova copia di u prugramma. +SetupFileCorrupt=I schedarii d’installazione sò alterati. Ci vole à ottene una nova copia di u prugramma. +SetupFileCorruptOrWrongVer=I schedarii d’installazione sò alterati, o sò incumpatibule cù sta versione di l’assistente. Ci vole à currege u penseru o ottene una nova copia di u prugramma. +InvalidParameter=Un parametru micca accettevule hè statu passatu in a linea di cumanda :%n%n%1 +SetupAlreadyRunning=L’assistente d’installazione hè dighjà in corsu. +WindowsVersionNotSupported=Stu prugramma ùn pò micca funziunà cù a versione di Windows installata nant’à st’urdinatore. +WindowsServicePackRequired=Stu prugramma richiede %1 Service Pack %2 o più recente. +NotOnThisPlatform=Stu prugramma ùn funzionerà micca cù %1. +OnlyOnThisPlatform=Stu prugramma deve funzionà cù %1. +OnlyOnTheseArchitectures=Stu prugramma pò solu esse installatu nant’à e versioni di Windows fatte apposta per st’architetture di prucessore :%n%n%1 +WinVersionTooLowError=Stu prugramma richiede %1 versione %2 o più recente. +WinVersionTooHighError=Stu prugramma ùn pò micca esse installatu nant’à %1 version %2 o più recente. +AdminPrivilegesRequired=Ci vole à esse cunnettu cum’è un amministratore quandu voi installate stu prugramma. +PowerUserPrivilegesRequired=Ci vole à esse cunnettu cum’è un amministratore o fà parte di u gruppu « Utilizatori cù putere » quandu voi installate stu prugramma. +SetupAppRunningError=L’assistente hà vistu chì %1 era dighjà in corsu.%n%nCi vole à chjode tutte e so finestre avà, eppò sceglie Vai per cuntinuà, o Abbandunà per compie. +UninstallAppRunningError=A disinstallazione hà vistu chì %1 era dighjà in corsu.%n%nCi vole à chjode tutte e so finestre avà, eppò sceglie Vai per cuntinuà, o Abbandunà per compie. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Selezziunà u modu d’installazione di l’assistente +PrivilegesRequiredOverrideInstruction=Selezziunà u modu d’installazione +PrivilegesRequiredOverrideText1=%1 pò esse installatu per tutti l’utilizatore (richiede i diritti d’amministratore), o solu per voi. +PrivilegesRequiredOverrideText2=%1 pò esse installatu solu per voi, o per tutti l’utilizatore (richiede i diritti d’amministratore). +PrivilegesRequiredOverrideAllUsers=Installazione per &tutti l’utilizatori +PrivilegesRequiredOverrideAllUsersRecommended=Installazione per &tutti l’utilizatori (ricumandatu) +PrivilegesRequiredOverrideCurrentUser=Installazione solu per &mè +PrivilegesRequiredOverrideCurrentUserRecommended=Installazione solu per &mè (ricumandatu) + +; *** Misc. errors +ErrorCreatingDir=L’assistente ùn hà micca pussutu creà u cartulare « %1 » +ErrorTooManyFilesInDir=Impussibule di creà un schedariu in u cartulare « %1 » perchè ellu ne cuntene troppu + +; *** Setup common messages +ExitSetupTitle=Compie l’assistente +ExitSetupMessage=L’assistente ùn hè micca compiu bè. S’è voi escite avà, u prugramma ùn serà micca installatu.%n%nPudete impiegà l’assistente torna un altra volta per compie l’installazione.%n%nCompie l’assistente ? +AboutSetupMenuItem=&Apprupositu di l’assistente… +AboutSetupTitle=Apprupositu di l’assistente +AboutSetupMessage=%1 versione %2%n%3%n%n%1 pagina d’accolta :%n%4 +AboutSetupNote= +TranslatorNote=Traduzzione in lingua corsa da Patriccollu di Santa Maria è Sichè + +; *** Buttons +ButtonBack=< &Precedente +ButtonNext=&Seguente > +ButtonInstall=&Installà +ButtonOK=Vai +ButtonCancel=Abbandunà +ButtonYes=&Iè +ButtonYesToAll=Iè per &tutti +ButtonNo=I&nnò +ButtonNoToAll=Innò per t&utti +ButtonFinish=&Piantà +ButtonBrowse=&Sfuglià… +ButtonWizardBrowse=&Sfuglià… +ButtonNewFolder=&Creà un novu cartulare + +; *** "Select Language" dialog messages +SelectLanguageTitle=Definisce a lingua di l’assistente +SelectLanguageLabel=Selezziunà a lingua à impiegà per l’installazione. + +; *** Common wizard text +ClickNext=Sceglie Seguente per cuntinuà, o Abbandunà per compie l’assistente. +BeveledLabel= +BrowseDialogTitle=Sfuglià u cartulare +BrowseDialogLabel=Selezziunà un cartulare in a lista inghjò, eppò sceglie Vai. +NewFolderName=Novu cartulare + +; *** "Welcome" wizard page +WelcomeLabel1=Benvenuta in l’assistente d’installazione di [name] +WelcomeLabel2=Quessu installerà [name/ver] nant’à l’urdinatore.%n%nHè ricumandatu di chjode tutte l’altre appiecazioni nanzu di cuntinuà. + +; *** "Password" wizard page +WizardPassword=Parolla d’entrata +PasswordLabel1=L’installazione hè prutetta da una parolla d’entrata. +PasswordLabel3=Ci vole à pruvede a parolla d’entrata, eppò sceglie Seguente per cuntinuà. E parolle d’entrata ponu cuntene maiuscule è minuscule. +PasswordEditLabel=&Parolla d’entrata : +IncorrectPassword=A parolla d’entrata pruvista ùn hè micca curretta. Ci vole à pruvà torna. + +; *** "License Agreement" wizard page +WizardLicense=Cuntrattu di licenza +LicenseLabel=Ci vole à leghje l’infurmazione impurtante chì seguiteghja nanzu di cuntinuà. +LicenseLabel3=Ci vole à leghje u cuntrattu di licenza chì seguiteghja. Duvete accettà i termini di stu cuntrattu nanzu di cuntinuà l’installazione. +LicenseAccepted=Sò d’&accunsentu cù u cuntrattu +LicenseNotAccepted=Ùn sò &micca d’accunsentu cù u cuntrattu + +; *** "Information" wizard pages +WizardInfoBefore=Infurmazione +InfoBeforeLabel=Ci vole à leghje l’infurmazione impurtante chì seguiteghja nanzu di cuntinuà. +InfoBeforeClickLabel=Quandu site prontu à cuntinuà cù l’assistente, sciglite Seguente. +WizardInfoAfter=Infurmazione +InfoAfterLabel=Ci vole à leghje l’infurmazione impurtante chì seguiteghja nanzu di cuntinuà. +InfoAfterClickLabel=Quandu site prontu à cuntinuà cù l’assistente, sciglite Seguente. + +; *** "User Information" wizard page +WizardUserInfo=Infurmazioni di l’utilizatore +UserInfoDesc=Ci vole à scrive e vostre infurmazioni. +UserInfoName=&Nome d’utilizatore : +UserInfoOrg=&Urganismu : +UserInfoSerial=&Numeru di Seria : +UserInfoNameRequired=Ci vole à scrive un nome. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Selezziunà u locu di destinazione +SelectDirDesc=Induve [name] deve esse installatu ? +SelectDirLabel3=L’assistente installerà [name] in stu cartulare. +SelectDirBrowseLabel=Per cuntinuà, sceglie Seguente. S’è voi preferisce selezziunà un altru cartulare, sciglite Sfuglià. +DiskSpaceGBLabel=Hè richiestu omancu [gb] Go di spaziu liberu di discu. +DiskSpaceMBLabel=Hè richiestu omancu [mb] Mo di spaziu liberu di discu. +CannotInstallToNetworkDrive=L’assistente ùn pò micca installà nant’à un discu di a reta. +CannotInstallToUNCPath=L’assistente ùn pò micca installà in un chjassu UNC. +InvalidPath=Ci vole à scrive un chjassu cumplettu cù a lettera di u lettore ; per indettu :%n%nC:\APP%n%no un chjassu UNC in a forma :%n%n\\servitore\spartu +InvalidDrive=U lettore o u chjassu UNC spartu ùn esiste micca o ùn hè micca accessibule. Ci vole à selezziunane un altru. +DiskSpaceWarningTitle=Ùn basta u spaziu discu +DiskSpaceWarning=L’assistente richiede omancu %1 Ko di spaziu liberu per installà, ma u lettore selezziunatu hà solu %2 Ko dispunibule.%n%nVulete cuntinuà quantunque ? +DirNameTooLong=U nome di cartulare o u chjassu hè troppu longu. +InvalidDirName=U nome di cartulare ùn hè micca accettevule. +BadDirName32=I nomi di cartulare ùn ponu micca cuntene sti caratteri :%n%n%1 +DirExistsTitle=Cartulare esistente +DirExists=U cartulare :%n%n%1%n%nesiste dighjà. Vulete installà in stu cartulare quantunque ? +DirDoesntExistTitle=Cartulare inesistente +DirDoesntExist=U cartulare :%n%n%1%n%nùn esiste micca. Vulete chì stu cartulare sia creatu ? + +; *** "Select Components" wizard page +WizardSelectComponents=Selezzione di cumpunenti +SelectComponentsDesc=Chì cumpunenti devenu esse installati ? +SelectComponentsLabel2=Selezziunà i cumpunenti à installà ; deselezziunà quelli ch’ùn devenu micca esse installati. Sceglie Seguente quandu site prontu à cuntinuà. +FullInstallation=Installazione sana +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Installazione cumpatta +CustomInstallation=Installazione persunalizata +NoUninstallWarningTitle=Cumpunenti esistenti +NoUninstallWarning=L’assistente hà vistu chì sti cumpunenti sò dighjà installati nant’à l’urdinatore :%n%n%1%n%nDeselezziunà sti cumpunenti ùn i disinstallerà micca.%n%nVulete cuntinuà quantunque ? +ComponentSize1=%1 Ko +ComponentSize2=%1 Mo +ComponentsDiskSpaceGBLabel=A selezzione attuale richiede omancu [gb] Go di spaziu liberu nant’à u discu. +ComponentsDiskSpaceMBLabel=A selezzione attuale richiede omancu [mb] Mo di spaziu liberu nant’à u discu. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Selezziunà trattamenti addizziunali +SelectTasksDesc=Chì trattamenti addizziunali vulete fà ? +SelectTasksLabel2=Selezziunà i trattamenti addizziunali chì l’assistente deve fà durante l’installazione di [name], eppò sceglie Seguente. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Selezzione di u cartulare di u listinu « Démarrer » +SelectStartMenuFolderDesc=Induve l’assistente deve piazzà l’accurtatoghji di u prugramma ? +SelectStartMenuFolderLabel3=L’assistente piazzerà l’accurtatoghji di u prugramma in stu cartulare di u listinu « Démarrer ». +SelectStartMenuFolderBrowseLabel=Per cuntinuà, sceglie Seguente. S’è voi preferisce selezziunà un altru cartulare, sciglite Sfuglià. +MustEnterGroupName=Ci vole à scrive un nome di cartulare. +GroupNameTooLong=U nome di cartulare o u chjassu hè troppu longu. +InvalidGroupName=U nome di cartulare ùn hè micca accettevule. +BadGroupName=U nome di u cartulare ùn pò micca cuntene alcunu di sti caratteri :%n%n%1 +NoProgramGroupCheck2=Ùn creà &micca di cartulare in u listinu « Démarrer » + +; *** "Ready to Install" wizard page +WizardReady=Prontu à Installà +ReadyLabel1=Avà l’assistente hè prontu à principià l’installazione di [name] nant’à l’urdinatore. +ReadyLabel2a=Sceglie Installà per cuntinuà l’installazione, o nant’à Precedente per rivede o cambià qualchì preferenza. +ReadyLabel2b=Sceglie Installà per cuntinuà l’installazione. +ReadyMemoUserInfo=Infurmazioni di l’utilizatore : +ReadyMemoDir=Cartulare d’installazione : +ReadyMemoType=Tipu d’installazione : +ReadyMemoComponents=Cumpunenti selezziunati : +ReadyMemoGroup=Cartulare di u listinu « Démarrer » : +ReadyMemoTasks=Trattamenti addizziunali : + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Scaricamentu di i schedarii addiziunali… +ButtonStopDownload=&Piantà u scaricamentu +StopDownload=Site sicuru di vulè piantà u scaricamentu ? +ErrorDownloadAborted=Scaricamentu interrottu +ErrorDownloadFailed=Scaricamentu fiascu : %1 %2 +ErrorDownloadSizeFailed=Fiascu per ottene a dimensione : %1 %2 +ErrorFileHash1=Fiascu di u tazzeghju di u schedariu : %1 +ErrorFileHash2=Tazzeghju di u schedariu inaccettevule : aspettatu %1, trovu %2 +ErrorProgress=Prugressione inaccettevule : %1 di %2 +ErrorFileSize=Dimensione di u schedariu inaccettevule : aspettatu %1, trovu %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Preparazione di l’installazione +PreparingDesc=L’assistente appronta l’installazione di [name] nant’à l’urdinatore. +PreviousInstallNotCompleted=L’installazione o a cacciatura di un prugramma precedente ùn s’hè micca compia bè. Ci vulerà à ridimarrà l’urdinatore per compie st’installazione.%n%nDopu, ci vulerà à rilancià l’assistente per compie l’installazione di [name]. +CannotContinue=L’assistente ùn pò micca cuntinuà. Sceglie Abbandunà per esce. +ApplicationsFound=St’appiecazioni impieganu schedarii chì devenu esse mudificati da l’assistente. Hè ricumandatu di permette à l’assistente di chjode autumaticamente st’appiecazioni. +ApplicationsFound2=St’appiecazioni impieganu schedarii chì devenu esse mudificati da l’assistente. Hè ricumandatu di permette à l’assistente di chjode autumaticamente st’appiecazioni. S’è l’installazione si compie bè, l’assistente pruverà di rilancià l’appiecazioni. +CloseApplications=Chjode &autumaticamente l’appiecazioni +DontCloseApplications=Ùn chjode &micca l’appiecazioni +ErrorCloseApplications=L’assistente ùn hà micca pussutu chjode autumaticamente tutti l’appiecazioni. Nanzu di cuntinuà, hè ricumandatu di chjode tutti l’appiecazioni chì impieganu schedarii chì devenu esse mudificati da l’assistente durante l’installazione. +PrepareToInstallNeedsRestart=L’assistente deve ridimarrà l’urdinatore. Dopu, ci vulerà à rilancià l’assistente per compie l’installazione di [name].%n%nVulete ridimarrà l’urdinatore subitu ? + +; *** "Installing" wizard page +WizardInstalling=Installazione in corsu +InstallingLabel=Ci vole à aspettà durante l’installazione di [name] nant’à l’urdinatore. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Fine di l’installazione di [name] +FinishedLabelNoIcons=L’assistente hà compiu l’installazione di [name] nant’à l’urdinatore. +FinishedLabel=L’assistente hà compiu l’installazione di [name] nant’à l’urdinatore. L’appiecazione pò esse lanciata selezziunendu l’accurtatoghji installati. +ClickFinish=Sceglie Piantà per compie l’assistente. +FinishedRestartLabel=Per compie l’installazione di [name], l’assistente deve ridimarrà l’urdinatore. Vulete ridimarrà l’urdinatore subitu ? +FinishedRestartMessage=Per compie l’installazione di [name], l’assistente deve ridimarrà l’urdinatore.%n%nVulete ridimarrà l’urdinatore subitu ? +ShowReadmeCheck=Iè, vogliu leghje u schedariu LISEZMOI o README +YesRadio=&Iè, ridimarrà l’urdinatore subitu +NoRadio=I&nnò, preferiscu ridimarrà l’urdinatore dopu +; used for example as 'Run MyProg.exe' +RunEntryExec=Eseguisce %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Fighjà %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=L’assistente hà bisogniu di u discu seguente +SelectDiskLabel2=Mette u discu %1 è sceglie Vai.%n%nS’è i schedarii di stu discu si trovanu in un’altru cartulare chì quellu indicatu inghjò, scrive u chjassu currettu o sceglie Sfuglià. +PathLabel=&Chjassu : +FileNotInDir2=U schedariu « %1 » ùn si truva micca in « %2 ». Mette u discu curretu o sceglie un’altru cartulare. +SelectDirectoryLabel=Ci vole à specificà induve si trova u discu seguente. + +; *** Installation phase messages +SetupAborted=L’installazione ùn s’hè micca compia bè.%n%nCi vole à currege u penseru è eseguisce l’assistente torna. +AbortRetryIgnoreSelectAction=Selezziunate un’azzione +AbortRetryIgnoreRetry=&Pruvà torna +AbortRetryIgnoreIgnore=&Ignurà u sbagliu è cuntinuà +AbortRetryIgnoreCancel=Abbandunà l’installazione + +; *** Installation status messages +StatusClosingApplications=Chjusura di l’appiecazioni… +StatusCreateDirs=Creazione di i cartulari… +StatusExtractFiles=Estrazzione di i schedarii… +StatusCreateIcons=Creazione di l’accurtatoghji… +StatusCreateIniEntries=Creazione di l’elementi INI… +StatusCreateRegistryEntries=Creazione di l’elementi di u registru… +StatusRegisterFiles=Arregistramentu di i schedarii… +StatusSavingUninstall=Cunservazione di l’informazioni di disinstallazione… +StatusRunProgram=Cumpiera di l’installazione… +StatusRestartingApplications=Relanciu di l’appiecazioni… +StatusRollback=Annulazione di i mudificazioni… + +; *** Misc. errors +ErrorInternal2=Sbagliu internu : %1 +ErrorFunctionFailedNoCode=Fiascu di %1 +ErrorFunctionFailed=Fiascu di %1 ; codice %2 +ErrorFunctionFailedWithMessage=Fiascu di %1 ; codice %2.%n%3 +ErrorExecutingProgram=Impussibule d’eseguisce u schedariu :%n%1 + +; *** Registry errors +ErrorRegOpenKey=Sbagliu durante l’apertura di a chjave di registru :%n%1\%2 +ErrorRegCreateKey=Sbagliu durante a creazione di a chjave di registru :%n%1\%2 +ErrorRegWriteKey=Sbagliu durante a scrittura di a chjave di registru :%n%1\%2 + +; *** INI errors +ErrorIniEntry=Sbagliu durante a creazione di l’elementu INI in u schedariu « %1 ». + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=Ignurà stu &schedariu (micca ricumandatu) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignurà u sbagliu è cuntinuà (micca ricumandatu) +SourceIsCorrupted=U schedariu d’urigine hè alteratu +SourceDoesntExist=U schedariu d’urigine « %1 » ùn esiste micca +ExistingFileReadOnly2=U schedariu esistente hà un attributu di lettura-sola è ùn pò micca esse rimpiazzatu. +ExistingFileReadOnlyRetry=&Caccià l’attributu di lettura-sola è pruvà torna +ExistingFileReadOnlyKeepExisting=Cunservà u schedariu &esistente +ErrorReadingExistingDest=Un sbagliu hè accadutu pruvendu di leghje u schedariu esistente : +FileExistsSelectAction=Selezziunate un’azzione +FileExists2=U schedariu esiste dighjà. +FileExistsOverwriteExisting=&Rimpiazzà u schedariu chì esiste +FileExistsKeepExisting=Cunservà u schedariu &esistente +FileExistsOverwriteOrKeepAll=&Fà què per l’altri cunflitti +ExistingFileNewerSelectAction=Selezziunate un’azzione +ExistingFileNewer2=U schedariu esistente hè più recente chì quellu chì l’assistente prova d’installà. +ExistingFileNewerOverwriteExisting=&Rimpiazzà u schedariu chì esiste +ExistingFileNewerKeepExisting=Cunservà u schedariu &esistente (ricumandatu) +ExistingFileNewerOverwriteOrKeepAll=&Fà què per l’altri cunflitti +ErrorChangingAttr=Un sbagliu hè accadutu pruvendu di cambià l’attributi di u schedariu esistente : +ErrorCreatingTemp=Un sbagliu hè accadutu pruvendu di creà un schedariu in u cartulare di destinazione : +ErrorReadingSource=Un sbagliu hè accadutu pruvendu di leghje u schedariu d’urigine : +ErrorCopying=Un sbagliu hè accadutu pruvendu di cupià un schedariu : +ErrorReplacingExistingFile=Un sbagliu hè accadutu pruvendu di rimpiazzà u schedariu esistente : +ErrorRestartReplace=Fiascu di Rimpiazzamentu di schedariu à u riavviu di l’urdinatore : +ErrorRenamingTemp=Un sbagliu hè accadutu pruvendu di rinuminà un schedariu in u cartulare di destinazione : +ErrorRegisterServer=Impussibule d’arregistrà a bibliuteca DLL/OCX : %1 +ErrorRegSvr32Failed=Fiascu di RegSvr32 cù codice d’esciuta %1 +ErrorRegisterTypeLib=Impussibule d’arregistrà a bibliuteca di tipu : %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Tutti l’utilizatori +UninstallDisplayNameMarkCurrentUser=L’utilizatore attuale + +; *** Post-installation errors +ErrorOpeningReadme=Un sbagliu hè accadutu pruvendu d’apre u schedariu LISEZMOI o README. +ErrorRestartingComputer=L’assistente ùn hà micca pussutu ridimarrà l’urdinatore. Ci vole à fallu manualmente. + +; *** Uninstaller messages +UninstallNotFound=U schedariu « %1 » ùn esiste micca. Impussibule di disinstallà. +UninstallOpenError=U schedariu« %1 » ùn pò micca esse apertu. Impussibule di disinstallà +UninstallUnsupportedVer=U ghjurnale di disinstallazione « %1 » hè in una forma scunnisciuta da sta versione di l’assistente di disinstallazione. Impussibule di disinstallà +UninstallUnknownEntry=Un elementu scunisciutu (%1) hè statu trovu in u ghjurnale di disinstallazione +ConfirmUninstall=Site sicuru di vulè caccià cumpletamente %1 è tutti i so cumpunenti ? +UninstallOnlyOnWin64=St’appiecazione pò esse disinstallata solu cù una versione 64-bit di Windows. +OnlyAdminCanUninstall=St’appiecazione pò esse disinstallata solu da un utilizatore di u gruppu d’amministratori. +UninstallStatusLabel=Ci vole à aspettà chì %1 sia cacciatu di l’urdinatore. +UninstalledAll=%1 hè statu cacciatu bè da l’urdinatore. +UninstalledMost=A disinstallazione di %1 hè compia.%n%nQualchì elementu ùn pò micca esse cacciatu. Ci vole à cacciallu manualmente. +UninstalledAndNeedsRestart=Per compie a disinstallazione di %1, l’urdinatore deve esse ridimarratu.%n%nVulete ridimarrà l’urdinatore subitu ? +UninstallDataCorrupted=U schedariu « %1 » hè alteratu. Impussibule di disinstallà + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Caccià i schedarii sparti ? +ConfirmDeleteSharedFile2=U sistema indicheghja chì u schedariu spartu ùn hè più impiegatu da nisunu prugramma. Vulete chì a disinstallazione cacci stu schedariu spartu ?%n%nS’è qualchì prugramma impiegheghja sempre stu schedariu è ch’ellu hè cacciatu, quellu prugramma ùn puderà funziunà currettamente. S’è ùn site micca sicuru, sceglie Innò. Lascià stu schedariu nant’à u sistema ùn pò micca pruduce danni. +SharedFileNameLabel=Nome di schedariu : +SharedFileLocationLabel=Lucalizazione : +WizardUninstalling=Statu di disinstallazione +StatusUninstalling=Disinstallazione di %1… + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Installazione di %1. +ShutdownBlockReasonUninstallingApp=Disinstallazione di %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 versione %2 +AdditionalIcons=Accurtatoghji addizziunali : +CreateDesktopIcon=Creà un accurtatoghju nant’à u &scagnu +CreateQuickLaunchIcon=Creà un accurtatoghju nant’à a barra di &lanciu prontu +ProgramOnTheWeb=%1 nant’à u Web +UninstallProgram=Disinstallà %1 +LaunchProgram=Lancià %1 +AssocFileExtension=&Assucià %1 cù l’estensione di schedariu %2 +AssocingFileExtension=Associu di %1 cù l’estensione di schedariu %2… +AutoStartProgramGroupDescription=Lanciu autumaticu : +AutoStartProgram=Lanciu autumaticu di %1 +AddonHostProgramNotFound=Impussibule di truvà %1 in u cartulare selezziunatu.%n%nVulete cuntinuà l’installazione quantunque ? diff --git a/installer/innosetup/Languages/Croatian.isl b/installer/innosetup/Languages/Croatian.isl index b8d946b5a..7ebc5f41e 100644 --- a/installer/innosetup/Languages/Croatian.isl +++ b/installer/innosetup/Languages/Croatian.isl @@ -1,10 +1,10 @@ -; *** Inno Setup version 6.0.0+ Croatian messages *** +; *** Inno Setup version 6.1.0+ Croatian messages *** ; Translated by: Milo Ivir (mail@milotype.de) ; Based on translation by Elvis Gambiraža (el.gambo@gmail.com) ; Based on translation by Krunoslav Kanjuh (krunoslav.kanjuh@zg.t-com.hr) ; ; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ +; https://www.jrsoftware.org/files/istrans/ ; ; Note: When translating this text, do not add periods (.) to the end of ; messages that didn't have them already, because on those messages Inno @@ -42,7 +42,7 @@ ConfirmTitle=Potvrda ErrorTitle=Greška ; *** SetupLdr messages -SetupLdrStartupMessage=Ovime ćeš instalirati %1. Želiš li nastaviti? +SetupLdrStartupMessage=Ovime će se instalirati %1. Želiš li nastaviti? LdrCannotCreateTemp=Nije moguće stvoriti privremenu datoteku. Instalacija je prekinuta LdrCannotExecTemp=Nije moguće pokrenuti datoteku u privremenoj mapi. Instalacija je prekinuta HelpTextNote= @@ -54,23 +54,23 @@ SetupFileCorrupt=Datoteke instalacije su oštećene. Nabavi novu kopiju programa SetupFileCorruptOrWrongVer=Datoteke instalacije su oštećene ili nisu kompatibilne s ovom verzijom instalacije. Ispravi problem ili nabavi novu kopiju programa. InvalidParameter=Neispravan parametar je prenijet u naredbenom retku:%n%n%1 SetupAlreadyRunning=Instalacija je već pokrenuta. -WindowsVersionNotSupported=Program ne podržava verziju Windowsa koju koristite. +WindowsVersionNotSupported=Program ne podržava Windows verziju koju koristiš. WindowsServicePackRequired=Program zahtijeva %1 servisni paket %2 ili noviji. -NotOnThisPlatform=Ovaj program neće raditi na %1. -OnlyOnThisPlatform=Ovaj program se mora pokrenuti na %1. -OnlyOnTheseArchitectures=Ovaj program može biti instaliran na verziji Windowsa dizajniranim za sljedeću procesorsku arhitekturu:%n%n%1 -WinVersionTooLowError=Ovaj program zahtijeva %1 verziju %2 ili noviju. -WinVersionTooHighError=Ovaj program se ne može instalirati na %1 verziji %2 ili novijoj. -AdminPrivilegesRequired=Morate biti prijavljeni kao administrator prilikom instaliranja ovog programa. -PowerUserPrivilegesRequired=Morate biti prijavljeni kao administrator ili član grupe naprednih korisnika prilikom instaliranja ovog programa. -SetupAppRunningError=Instalacija je otkrila da je %1 pokrenut.%n%nZatvorite program i potom kliknite "Dalje" za nastavak ili "Odustani" za prekid instalacije. -UninstallAppRunningError=Deinstalacija je otkrila da je %1 pokrenut.%n%nZatvorite program i potom kliknite "Dalje" za nastavak ili "Odustani" za prekid instalacije. +NotOnThisPlatform=Program neće raditi na %1. +OnlyOnThisPlatform=Program se mora pokrenuti na %1. +OnlyOnTheseArchitectures=Program se može instalirati na Windows verzijama za sljedeće procesorske arhitekture:%n%n%1 +WinVersionTooLowError=Program zahtijeva %1 verziju %2 ili noviju. +WinVersionTooHighError=Program se ne može instalirati na %1 verziji %2 ili novijoj. +AdminPrivilegesRequired=Za instaliranje programa moraš biti prijavljen/a kao administrator. +PowerUserPrivilegesRequired=Za instaliranje programa moraš biti prijavljen/a kao administrator ili kao član grupe naprednih korisnika. +SetupAppRunningError=Instalacija je otkrila da je %1 trenutačno pokrenut.%n%nZatvori program i potom pritisni "Dalje" za nastavak ili "Odustani" za prekid. +UninstallAppRunningError=Deinstalacija je otkrila da je %1 trenutačno pokrenut.%n%nZatvori program i potom pritisni "Dalje" za nastavak ili "Odustani" za prekid. ; *** Startup questions -PrivilegesRequiredOverrideTitle=Odaberite način instaliranja -PrivilegesRequiredOverrideInstruction=Odaberite način instaliranja -PrivilegesRequiredOverrideText1=%1 se može instalirati za sve korisnike (zahtijeva administrativna prava) ili samo za vas. -PrivilegesRequiredOverrideText2=%1 se može instalirati samo za vas ili za sve korisnike (zahtijeva administrativna prava). +PrivilegesRequiredOverrideTitle=Odaberi način instaliranja +PrivilegesRequiredOverrideInstruction=Odaberi način instaliranja +PrivilegesRequiredOverrideText1=%1 se može instalirati za sve korisnike (potrebna su administratorska prava) ili samo za tebe. +PrivilegesRequiredOverrideText2=%1 se može instalirati samo za tebe ili za sve korisnike (potrebna su administratorska prava). PrivilegesRequiredOverrideAllUsers=Instaliraj z&a sve korisnike PrivilegesRequiredOverrideAllUsersRecommended=Instaliraj z&a sve korisnike (preporučeno) PrivilegesRequiredOverrideCurrentUser=Instaliraj samo za &mene @@ -78,14 +78,14 @@ PrivilegesRequiredOverrideCurrentUserRecommended=Instaliraj samo za &mene (prepo ; *** Misc. errors ErrorCreatingDir=Instalacija nije mogla stvoriti mapu "%1" -ErrorTooManyFilesInDir=Nemoguće stvaranje datoteke u mapi "%1", jer ona sadrži previše datoteka +ErrorTooManyFilesInDir=Datoteku nije moguće stvoriti u mapi "%1", jer mapa sadrži previše datoteka ; *** Setup common messages ExitSetupTitle=Prekini instalaciju -ExitSetupMessage=Instalacija nije završena. Ako sad izađete, program neće biti instaliran.%n%nInstalaciju možete pokrenuti kasnije, ukoliko ju želite završiti.%n%nPrekinuti instalaciju? +ExitSetupMessage=Instalacija nije završena. Ako sad izađeš, program neće biti instaliran.%n%nInstalaciju možeš pokrenuti kasnije, ukoliko je želiš dovršiti.%n%nPrekinuti instalaciju? AboutSetupMenuItem=&O instalaciji … AboutSetupTitle=O instalaciji -AboutSetupMessage=%1 verzija %2%n%3%n%n%1 početna stranica:%n%4 +AboutSetupMessage=%1 verzija %2%n%3%n%n%1 web-stranica:%n%4 AboutSetupNote= TranslatorNote=Prevodioci:%n%nKrunoslav Kanjuh%n%nElvis Gambiraža%n%nMilo Ivir @@ -105,105 +105,107 @@ ButtonWizardBrowse=Odabe&ri … ButtonNewFolder=&Stvori novu mapu ; *** "Select Language" dialog messages -SelectLanguageTitle=Odaberite jezik za instalaciju -SelectLanguageLabel=Odberite jezik koji želite koristiti tijekom instaliranja. +SelectLanguageTitle=Odaberi jezik za instalaciju +SelectLanguageLabel=Odaberi jezik koji želiš koristiti tijekom instaliranja. ; *** Common wizard text -ClickNext=Kliknite "Dalje" za nastavak ili "Odustani" za prekid instalacije. +ClickNext=Pritisni "Dalje" za nastavak ili "Odustani" za prekid instalacije. BeveledLabel= -BrowseDialogTitle=Odaberite mapu -BrowseDialogLabel=Odaberite mapu iz popisa te kliknite "U redu". +BrowseDialogTitle=Odaberi mapu +BrowseDialogLabel=Odaberi mapu iz popisa i pritisni "U redu". NewFolderName=Nova mapa ; *** "Welcome" wizard page -WelcomeLabel1=Dobro došli u instalaciju programa [name] -WelcomeLabel2=Ovaj program će instalirati [name/ver] na vaše računalo.%n%nPreporučamo da zatvorite sve programe prije nego što nastavite dalje. +WelcomeLabel1=Čarobnjak za instalaciju programa [name] +WelcomeLabel2=Ovime ćeš instalirati [name/ver].%n%nPreporučujemo da zatvoriš sve programe prije nego što nastaviš dalje. ; *** "Password" wizard page WizardPassword=Lozinka PasswordLabel1=Instalacija je zaštićena lozinkom. -PasswordLabel3=Upišite lozinku i kliknite "Dalje". Lozinke su osjetljive na mala i velika slova. +PasswordLabel3=Upiši lozinku i pritisni "Dalje". Lozinke su osjetljive na mala i velika slova. PasswordEditLabel=&Lozinka: -IncorrectPassword=Upisana je pogrešna lozinka. Pokušajte ponovo. +IncorrectPassword=Upisana je pogrešna lozinka. Pokušaj ponovo. ; *** "License Agreement" wizard page WizardLicense=Licencni ugovor -LicenseLabel=Prije nastavka pažljivo pročitajte sljedeće važne informacije. -LicenseLabel3=Pročitajte licencni ugovor. Morate prihvatiti uvjete ugovora kako biste nastavili s instaliranjem. +LicenseLabel=Prije nego što nastaviš dalje, pažljivo pročitaj sljedeće važne informacije. +LicenseLabel3=Pročitaj licencni ugovor. Moraš prihvatiti uvjete ugovora, ako želiš nastaviti instalirati. LicenseAccepted=&Prihvaćam ugovor LicenseNotAccepted=&Ne prihvaćam ugovor ; *** "Information" wizard pages WizardInfoBefore=Informacije -InfoBeforeLabel=Pročitajte sljedeće važne informacije prije nego što nastavite dalje. -InfoBeforeClickLabel=Kada ste spremni nastaviti s instaliranjem, kliknite "Dalje". +InfoBeforeLabel=Pročitaj sljedeće važne informacije prije nego što nastaviš dalje. +InfoBeforeClickLabel=Kad želiš nastaviti instalirati, pritisni "Dalje". WizardInfoAfter=Informacije -InfoAfterLabel=Pročitajte sljedeće važne informacije prije nego što nastavite dalje. -InfoAfterClickLabel=Kada ste spremni nastaviti s instaliranjem, kliknite "Dalje". +InfoAfterLabel=Pročitaj sljedeće važne informacije prije nego što nastaviš dalje. +InfoAfterClickLabel=Kad želiš nastaviti instalirati, pritisni "Dalje". ; *** "User Information" wizard page -WizardUserInfo=Informacije o korisniku -UserInfoDesc=Upišite informacije o vama. +WizardUserInfo=Korisnički podaci +UserInfoDesc=Upiši svoje podatke. UserInfoName=&Ime korisnika: UserInfoOrg=&Organizacija: UserInfoSerial=&Serijski broj: -UserInfoNameRequired=Morate upisati ime. +UserInfoNameRequired=Ime je obavezno polje. ; *** "Select Destination Location" wizard page -WizardSelectDir=Odaberite odredišno mjesto -SelectDirDesc=Gdje treba instalirati [name]? -SelectDirLabel3=Instalacija će instalirati [name] u sljedeću mapu. -SelectDirBrowseLabel=Za nastavak kliknite na "Dalje". Ako želite odabrati drugu mapu, kliknite na "Odaberi". +WizardSelectDir=Odaberi odredišno mjesto +SelectDirDesc=Gdje želiš instalirati [name]? +SelectDirLabel3=[name] će se instalirati u sljedeću mapu. +SelectDirBrowseLabel=Za nastavak instalacije, pritisni "Dalje". Za odabir jedne druge mape, pritisni "Odaberi". +DiskSpaceGBLabel=Potrebno je barem [gb] GB slobodnog prostora na disku. DiskSpaceMBLabel=Potrebno je barem [mb] MB slobodnog prostora na disku. CannotInstallToNetworkDrive=Instalacija ne može instalirati na mrežnu jedinicu. CannotInstallToUNCPath=Instalacija ne može instalirati na UNC stazu. -InvalidPath=Morate unijeti punu stazu zajedno sa slovom diska, npr.:%n%nC:\APP%n%nili UNC stazu u obliku:%n%n\\server\share -InvalidDrive=Disk koji ste odabrali ne postoji. Odaberite neki drugi. +InvalidPath=Moraš upisati punu stazu zajedno sa slovom diska, npr.:%n%nC:\APP%n%nili UNC stazu u obliku:%n%n\\server\share +InvalidDrive=Odabrani disk ne postoji. Odaberi jedan drugi. DiskSpaceWarningTitle=Nedovoljno prostora na disku -DiskSpaceWarning=Instalacija zahtijeva barem %1 KB slobodnog prostora, a odabrani disk ima samo %2 KB na raspolaganju.%n%nŽelite li svejedno nastaviti? +DiskSpaceWarning=Instalacija treba barem %1 KB slobodnog prostora, no odabrani disk ima samo %2 KB.%n%nSvejedno nastaviti? DirNameTooLong=Naziv mape ili staze je predugačak. InvalidDirName=Naziv mape je neispravan. -BadDirName32=Naziv mape ne smije sadržavati niti jedan od sljedećih znakova:%n%n%1 +BadDirName32=Naziv mape ne smije sadržavati sljedeće znakove:%n%n%1 DirExistsTitle=Mapa već postoji -DirExists=Mapa:%n%n%1%n%nveć postoji. Želite li svejedno u nju instalirati? +DirExists=Mapa:%n%n%1%n%nveć postoji. Želiš li svejedno u nju instalirati? DirDoesntExistTitle=Mapa ne postoji -DirDoesntExist=The folder:%n%n%1%n%nne postoji. Želite li ju stvoriti? +DirDoesntExist=Mapa:%n%n%1%n%nne postoji. Želiš li je stvoriti? ; *** "Select Components" wizard page -WizardSelectComponents=Odaberite komponente -SelectComponentsDesc=Koje komponente želite instalirati? -SelectComponentsLabel2=Odaberite komponente koje želite instalirati, isključite komponente koje ne želite instalirati. Za nastavak kliknite na "Dalje". +WizardSelectComponents=Odaberi komponente +SelectComponentsDesc=Koje komponente želiš instalirati? +SelectComponentsLabel2=Odaberi komponente koje želiš instalirati, isključi komponente koje ne želiš instalirati. Za nastavak instalacije pritisni "Dalje". FullInstallation=Kompletna instalacija ; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) CompactInstallation=Kompaktna instalacija CustomInstallation=Prilagođena instalacija NoUninstallWarningTitle=Postojeće komponente -NoUninstallWarning=Instalacija je utvrdila da na vašem računalu već postoje sljedeće komponente:%n%n%1%n%nIsključivanjem tih komponenata, one neće biti deinstalirane.%n%nŽelite li ipak nastaviti? +NoUninstallWarning=Instalacija je utvrdila da na tvom računalu već postoje sljedeće komponente:%n%n%1%n%nIsključivanjem tih komponenata, one se neće deinstalirati.%n%nŽeliš li svejedno nastaviti? ComponentSize1=%1 KB ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Trenutačni odabir zahtijeva barem [gb] GB na disku. ComponentsDiskSpaceMBLabel=Trenutačni odabir zahtijeva barem [mb] MB na disku. ; *** "Select Additional Tasks" wizard page -WizardSelectTasks=Odaberite dodatne zadatke -SelectTasksDesc=Koje dodatne zadatke želite izvršiti? -SelectTasksLabel2=Odaberite zadatke koje želite izvršiti tijekom instaliranja programa [name], zatim kliknite "Dalje". +WizardSelectTasks=Odaberi dodatne zadatke +SelectTasksDesc=Koje dodatne zadatke želiš izvršiti? +SelectTasksLabel2=Odaberi zadatke koje želiš izvršiti tijekom instaliranja programa [name], zatim pritisni "Dalje". ; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup=Odaberite mapu iz "Start" izbornika -SelectStartMenuFolderDesc=Gdje želite da instalacija spremi programske prečace? +WizardSelectProgramGroup=Odaberi mapu iz "Start" izbornika +SelectStartMenuFolderDesc=Gdje želiš da instalacija spremi programske prečace? SelectStartMenuFolderLabel3=Instalacija će stvoriti programske prečace u sljedeću mapu "Start" izbornika. -SelectStartMenuFolderBrowseLabel=Kliknite "Dalje" za nastavak ili "Odaberi" za odabir jedne druge mape. -MustEnterGroupName=Morate upisati naziv mape. -GroupNameTooLong=Naziv mape ili staze je predug. +SelectStartMenuFolderBrowseLabel=Ako želiš nastaviti, pritisni "Dalje". Ako želiš odabrati jednu drugu mapu, pritisni "Odaberi". +MustEnterGroupName=Moraš upisati naziv mape. +GroupNameTooLong=Naziv mape ili staze je predugačak. InvalidGroupName=Naziv mape nije ispravan. BadGroupName=Naziv mape ne smije sadržavati sljedeće znakove:%n%n%1 NoProgramGroupCheck2=&Ne stvaraj mapu u "Start" izborniku ; *** "Ready to Install" wizard page WizardReady=Sve je spremno za instaliranje -ReadyLabel1=Instalacija je spremna za instaliranje [name] na vaše računalo. -ReadyLabel2a=Kliknite "Instaliraj" ako želite instalirati program ili "Natrag" ako želite pregledati ili promijeniti postavke -ReadyLabel2b=Kliknite "Instaliraj" ako želite instalirati program. +ReadyLabel1=Instalacija je spremna za instaliranje programa [name]. +ReadyLabel2a=Pritisni "Instaliraj", ako želiš instalirati program. Pritisni "Natrag", ako želiš pregledati ili promijeniti postavke +ReadyLabel2b=Pritisni "Instaliraj", ako želiš instalirati program. ReadyMemoUserInfo=Korisnički podaci: ReadyMemoDir=Odredišno mjesto: ReadyMemoType=Vrsta instalacije: @@ -211,31 +213,44 @@ ReadyMemoComponents=Odabrane komponente: ReadyMemoGroup=Mapa u "Start" izborniku: ReadyMemoTasks=Dodatni zadaci: +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Preuzimanje dodatnih datoteka … +ButtonStopDownload=&Prekini preuzimanje +StopDownload=Stvarno želiš prekinuti preuzimanje? +ErrorDownloadAborted=Preuzimanje je prekinuto +ErrorDownloadFailed=Neuspjelo preuzimanje: %1 %2 +ErrorDownloadSizeFailed=Neuspjelo dohvaćanje veličine: %1 %2 +ErrorFileHash1=Izračunavanje kontrolnog zbroja datoteke neuspjelo: %1 +ErrorFileHash2=Neispravan kontrolni zbroj datoteke: očekivano %1, pronađeno %2 +ErrorProgress=Neispravan napredak: %1 od %2 +ErrorFileSize=Neispravna veličina datoteke: očekivano %1, pronađeno %2 + ; *** "Preparing to Install" wizard page WizardPreparing=Priprema za instaliranje -PreparingDesc=Instalacija se priprema za instaliranje [name] na vaše računalo. -PreviousInstallNotCompleted=The installation/removal of a previous program was not completed. You will need to restart your computer to complete that installation.%n%nAfter restarting your computer, run Setup again to complete the installation of [name]. -CannotContinue=Instalacija ne može nastaviti. Kliknite na "Odustani" za izlaz. -ApplicationsFound=Sljedeći programi koriste datoteke koje instalacija mora aktualiziranti. Preporučamo da dopustite instalaciji da zatvori ove programe. -ApplicationsFound2=Sljedeći programi koriste datoteke koje instalacija mora aktualiziranti. Preporučamo da dopustite instalaciji da zatvori ove programe. Kad instaliranje završi, instalacija će pokušati ponovo pokrenuti programe. +PreparingDesc=Instalacija se priprema za instaliranje programa [name]. +PreviousInstallNotCompleted=Instaliranje/uklanjanje jednog prethodnog programa nije bilo gotovo. Morat ćeš ponovo pokrenuti računalo i dovršiti to instaliranje.%n%nNakon ponovnog pokretanja računala, pokreni instalaciju ponovo, kako bi se dovršilo instaliranje programa [name]. +CannotContinue=Instalacija ne može nastaviti rad. Pritisni "Odustani" za izlaz iz instalacije. +ApplicationsFound=Sljedeći programi koriste datoteke koje instalacija mora aktualizirati. Preporučujemo da dopustiš instalaciji zatvoriti ove programe. +ApplicationsFound2=Sljedeći programi koriste datoteke koje instalacija mora aktualizirati. Preporučujemo da dopustiš instalaciji zatvoriti ove programe. Kad instaliranje završi, instalacija će pokušati ponovo pokrenuti programe. CloseApplications=&Zatvori programe automatski DontCloseApplications=&Ne zatvaraj programe -ErrorCloseApplications=Instalacija nij uspjela automatski zatvoriti programe. Preporučamo da zatvorite sve programe koji koriste datoteke, koje se moraju aktulaizirati. +ErrorCloseApplications=Instalacija nije uspjela automatski zatvoriti programe. Preporučujemo da zatvoriš sve programe koji koriste datoteke koje se moraju aktualizirati. +PrepareToInstallNeedsRestart=Instalacija mora ponovo pokrenuti računalo. Nakon ponovnog pokretanja računala, pokreni instalaciju ponovo, kako bi se dovršilo instaliranje programa [name].%n%nŽeliš li sada ponovo pokrenuti računalo? ; *** "Installing" wizard page WizardInstalling=Instaliranje -InstallingLabel=Pričekajte dok ne završi instaliranje programa [name] na vaše računalo. +InstallingLabel=Pričekaj dok ne završi instaliranje programa [name]. ; *** "Setup Completed" wizard page FinishedHeadingLabel=Završavanje instalacijskog čarobnjaka za [name] -FinishedLabelNoIcons=Instalacija je završila instaliranje programa [name] na vaše računalo. -FinishedLabel=Instalacija je završila instaliranje programa [name] na vaše računalo. Program se može pokrenuti pomoću instaliranih prečaca. -ClickFinish=Kliknite na "Završi" kako biste izašli iz instalacije. -FinishedRestartLabel=Kako biste završili instaliranje programa [name], potrebno je ponovo pokrenuti računalo. Želite li to sada učiniti? -FinishedRestartMessage=Kako biste završili instaliranje programa [name], potrebno je ponovo pokrenuti računalo.%n%nŽelite li to sada učiniti? +FinishedLabelNoIcons=Instalacija je završila instaliranje programa [name]. +FinishedLabel=Instalacija je završila instaliranje programa [name]. Program se može pokrenuti pomoću instaliranih prečaca. +ClickFinish=Za izlaz iz instalacije pritisni "Završi". +FinishedRestartLabel=Za završavanje instaliranja programa [name], instalacija mora ponovo pokrenuti računalo. Želiš li sada ponovo pokrenuti računalo? +FinishedRestartMessage=Za završavanje instaliranja programa [name], instalacija mora ponovo pokrenuti računalo.%n%nŽeliš li sada ponovo pokrenuti računalo? ShowReadmeCheck=Da, želim pročitati README datoteku -YesRadio=&Da, želim sad ponovo pokrenuti računalo -NoRadio=&Ne, kasnije ću ponovo pokrenuti računalo +YesRadio=&Da, sada ponovo pokrenuti računalo +NoRadio=&Ne, računalo ću kasnije ponovo pokrenuti ; used for example as 'Run MyProg.exe' RunEntryExec=Pokreni %1 ; used for example as 'View Readme.txt' @@ -243,14 +258,14 @@ RunEntryShellExec=Prikaži %1 ; *** "Setup Needs the Next Disk" stuff ChangeDiskTitle=Instalacija treba sljedeći disk -SelectDiskLabel2=Umetnite disk %1 i kliknite na "U redu".%n%nAko se datoteke s ovog diska nalaze na nekom drugom mjestu od prikazanog ispod, upišite ispravnu stazu ili kliknite na "Odaberi". +SelectDiskLabel2=Umetni disk %1 i pritisni "U redu".%n%nAko se datoteke s ovog diska nalaze na nekom drugom mjestu od dolje prikazanog, upiši ispravnu stazu ili pritisni "Odaberi". PathLabel=&Staza: -FileNotInDir2=Staza "%1" ne postoji u "%2". Umetnite odgovarajući disk ili odaberite jednu drugu mapu. -SelectDirectoryLabel=Odaberite mjesto sljedećeg diska. +FileNotInDir2=Staza "%1" ne postoji u "%2". Umetni odgovarajući disk ili odaberi jednu drugu mapu. +SelectDirectoryLabel=Odredi mjesto sljedećeg diska. ; *** Installation phase messages -SetupAborted=Instalacija nije završena.%n%nIspravite problem i ponovo pokrenite instalaciju. -AbortRetryIgnoreSelectAction=Odaberite radnju +SetupAborted=Instalacija nije završena.%n%nIspravi problem i ponovo pokreni instalaciju. +AbortRetryIgnoreSelectAction=Odaberi radnju AbortRetryIgnoreRetry=&Pokušaj ponovo AbortRetryIgnoreIgnore=&Zanemari grešku i nastavi AbortRetryIgnoreCancel=Prekini s instaliranjem @@ -270,10 +285,10 @@ StatusRollback=Poništavanje promjena … ; *** Misc. errors ErrorInternal2=Interna greška: %1 -ErrorFunctionFailedNoCode=%1 nije uspjelo -ErrorFunctionFailed=%1 nije uspjelo; kod %2 -ErrorFunctionFailedWithMessage=%1 failed; kod %2.%n%3 -ErrorExecutingProgram=Nije moguće pokrenuti datoteku:%n%1 +ErrorFunctionFailedNoCode=%1 – neuspjelo +ErrorFunctionFailed=%1 – neuspjelo; kod %2 +ErrorFunctionFailedWithMessage=%1 – neuspjelo; kod %2.%n%3 +ErrorExecutingProgram=Nije moguće izvršiti datoteku:%n%1 ; *** Registry errors ErrorRegOpenKey=Greška prilikom otvaranja ključa registra:%n%1\%2 @@ -284,17 +299,25 @@ ErrorRegWriteKey=Greška prilikom pisanja u ključ registra:%n%1\%2 ErrorIniEntry=Greška prilikom stvaranja INI unosa u datoteci "%1". ; *** File copying errors -FileAbortRetryIgnoreSkipNotRecommended=&Preskoči ovu datoteku (ne preporuča se) -FileAbortRetryIgnoreIgnoreNotRecommended=&Zanemari grešku i nastavi (ne preporuča se) -SourceIsCorrupted=Izvorišna datoteka je oštećena -SourceDoesntExist=Izvorišna datoteka "%1" ne postoji +FileAbortRetryIgnoreSkipNotRecommended=&Preskoči ovu datoteku (ne preporučuje se) +FileAbortRetryIgnoreIgnoreNotRecommended=&Zanemari grešku i nastavi (ne preporučuje se) +SourceIsCorrupted=Izvorna datoteka je oštećena +SourceDoesntExist=Izvorna datoteka "%1" ne postoji ExistingFileReadOnly2=Postojeću datoteku nije bilo moguće zamijeniti, jer je označena sa "samo-za-čitanje". -ExistingFileReadOnlyRetry=&Uklonite atribut "samo-za-čitanje" i pokušajte ponovo +ExistingFileReadOnlyRetry=&Ukloni svojstvo "samo-za-čitanje" i pokušaj ponovo ExistingFileReadOnlyKeepExisting=&Zadrži postojeću datoteku ErrorReadingExistingDest=Pojavila se greška prilikom pokušaja čitanja postojeće datoteke: -FileExists=The file already exists.%n%nŽelite li da ju instalacija prepiše? -ExistingFileNewer=Postojeća datoteka je novija od one, koju pokušavate instalirati. Preporuča se da zadržite postojeću datoteku.%n%nŽelite li zadržati postojeću datoteku? -ErrorChangingAttr=Pojavila se greška prilikom pokušaja promjene atributa postojeće datoteke: +FileExistsSelectAction=Odaberi radnju +FileExists2=Datoteka već postoji. +FileExistsOverwriteExisting=&Prepiši postojeću datoteku +FileExistsKeepExisting=&Zadrži postojeću datoteku +FileExistsOverwriteOrKeepAll=&Uradi to i u narednim slučajevima +ExistingFileNewerSelectAction=Odaberi radnju +ExistingFileNewer2=Postojeća datoteka je novija od one koja se pokušava instalirati. +ExistingFileNewerOverwriteExisting=&Prepiši postojeću datoteku +ExistingFileNewerKeepExisting=&Zadrži postojeću datoteku (preporučeno) +ExistingFileNewerOverwriteOrKeepAll=&Uradi to i u narednim slučajevima +ErrorChangingAttr=Pojavila se greška prilikom pokušaja promjene svojstva postojeće datoteke: ErrorCreatingTemp=Pojavila se greška prilikom pokušaja stvaranja datoteke u odredišnoj mapi: ErrorReadingSource=Pojavila se greška prilikom pokušaja čitanja izvorišne datoteke: ErrorCopying=Pojavila se greška prilikom pokušaja kopiranja datoteke: @@ -303,7 +326,7 @@ ErrorRestartReplace=Zamijenjivanje nakon ponovnog pokretanja nije uspjelo: ErrorRenamingTemp=Pojavila se greška prilikom pokušaja preimenovanja datoteke u odredišnoj mapi: ErrorRegisterServer=Nije moguće registrirati DLL/OCX: %1 ErrorRegSvr32Failed=Greška u RegSvr32. Izlazni kod %1 -ErrorRegisterTypeLib=Nije moguće registrirati type library: %1 +ErrorRegisterTypeLib=Nije moguće registrirati biblioteku vrsta: %1 ; *** Uninstall display name markings ; used for example as 'My Program (32-bit)' @@ -317,25 +340,25 @@ UninstallDisplayNameMarkCurrentUser=Trenutačni korisnik ; *** Post-installation errors ErrorOpeningReadme=Pojavila se greška prilikom pokušaja otvaranja README datoteke. -ErrorRestartingComputer=Instalacija nije mogla ponovo pokrenuti računalo. Učinite to ručno. +ErrorRestartingComputer=Instalacija nije mogla ponovo pokrenuti računalo. Učini to ručno. ; *** Uninstaller messages UninstallNotFound=Datoteka "%1" ne postoji. Deinstaliranje nije moguće. UninstallOpenError=Datoteku "%1" nije bilo moguće otvoriti. Deinstaliranje nije moguće UninstallUnsupportedVer=Deinstalacijska datoteka "%1" je u formatu koji ova verzija deinstalacijskog programa ne prepoznaje. Deinstaliranje nije moguće -UninstallUnknownEntry=Nepoznat zapis (%1) je pronađen u deinstalacijskoj datoteci -ConfirmUninstall=Zaista želite ukloniti %1 i sve pripadajuće komponente? +UninstallUnknownEntry=Pronađen je nepoznat zapis (%1) u deinstalacijskoj datoteci +ConfirmUninstall=Zaista želiš ukloniti %1 i sve pripadajuće komponente? UninstallOnlyOnWin64=Ovu instalaciju je moguće ukloniti samo na 64-bitnom Windows sustavu. -OnlyAdminCanUninstall=Ovu instalaciju je moguće ukloniti samo korisnik s administrativnim pravima. -UninstallStatusLabel=Pričekajte dok se %1 uklanja s vašeg računala. -UninstalledAll=%1 je uspješno uklonjen s vašeg računala. -UninstalledMost=Deinstaliranje programa %1 je završeno.%n%nNeke elemente nije bilo moguće ukloniti. Mogu se ukloniti ručno. -UninstalledAndNeedsRestart=Kako biste završili deinstalirati %1, morate ponovo pokrenuti vaše računalo%n%nŽelite li to sad učiniti? +OnlyAdminCanUninstall=Ovu instalaciju može ukloniti samo korisnik s administratorskim pravima. +UninstallStatusLabel=Pričekaj dok se %1 uklanja s računala. +UninstalledAll=%1 je uspješno uklonjen s računala. +UninstalledMost=Deinstaliranje programa %1 je završeno.%n%nNeke elemente nije bilo moguće ukloniti. Oni se mogu ukloniti ručno. +UninstalledAndNeedsRestart=Za završavanje deinstaliranja programa %1, potrebno je ponovo pokrenuti računalo.%n%nŽeliš li to sada učiniti? UninstallDataCorrupted="%1" datoteka je oštećena. Deinstaliranje nije moguće ; *** Uninstallation phase messages ConfirmDeleteSharedFileTitle=Ukloniti dijeljene datoteke? -ConfirmDeleteSharedFile2=Sustav ukazuje na to, da sljedeće dijeljenu datoteku ne koristi niti jedan program. Želite li ukloniti tu dijeljenu datoteku?%n%nAko neki programi i dalje koriste tu datoteku, a ona se izbriše, ti programi neće ispravno raditi. Ako niste sigurni, odaberite "Ne". Datoteka neće štetiti vašem sustavu. +ConfirmDeleteSharedFile2=Sustav ukazuje na to, da sljedeću dijeljenu datoteku ne koristi niti jedan program. Želiš li ukloniti tu dijeljenu datoteku?%n%nAko neki programi i dalje koriste tu datoteku, a ona se izbriše, ti programi neće ispravno raditi. Ako ne znaš, odaberi "Ne". Datoteka neće štetiti tvom sustavu. SharedFileNameLabel=Datoteka: SharedFileLocationLabel=Mjesto: WizardUninstalling=Stanje deinstalacije @@ -361,4 +384,4 @@ AssocFileExtension=&Poveži program %1 s datotečnim nastavkom %2 AssocingFileExtension=Povezivanje programa %1 s datotečnim nastavkom %2 … AutoStartProgramGroupDescription=Pokretanje: AutoStartProgram=Automatski pokreni %1 -AddonHostProgramNotFound=%1 nije nađen u odabranoj mapi.%n%nŽelite li svejedno nastaviti? +AddonHostProgramNotFound=%1 nije nađen u odabranoj mapi.%n%nŽeliš li svejedno nastaviti? diff --git a/installer/innosetup/Languages/Czech.isl b/installer/innosetup/Languages/Czech.isl new file mode 100644 index 000000000..9e37db5eb --- /dev/null +++ b/installer/innosetup/Languages/Czech.isl @@ -0,0 +1,378 @@ +; ******************************************************* +; *** *** +; *** Inno Setup version 6.1.0+ Czech messages *** +; *** *** +; *** Original Author: *** +; *** *** +; *** Ivo Bauer (bauer@ozm.cz) *** +; *** *** +; *** Contributors: *** +; *** *** +; *** Lubos Stanek (lubek@users.sourceforge.net) *** +; *** Vitezslav Svejdar (vitezslav.svejdar@cuni.cz) *** +; *** Jiri Fenz (jirifenz@gmail.com) *** +; *** *** +; ******************************************************* + +[LangOptions] +LanguageName=<010C>e<0161>tina +LanguageID=$0405 +LanguageCodePage=1250 + +[Messages] + +; *** Application titles +SetupAppTitle=Prvodce instalac +SetupWindowTitle=Prvodce instalac - %1 +UninstallAppTitle=Prvodce odinstalac +UninstallAppFullTitle=Prvodce odinstalac - %1 + +; *** Misc. common +InformationTitle=Informace +ConfirmTitle=Potvrzen +ErrorTitle=Chyba + +; *** SetupLdr messages +SetupLdrStartupMessage=Vt Vs prvodce instalac produktu %1. Chcete pokraovat? +LdrCannotCreateTemp=Nelze vytvoit doasn soubor. Prvodce instalac bude ukonen +LdrCannotExecTemp=Nelze spustit soubor v doasn sloce. Prvodce instalac bude ukonen +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nChyba %2: %3 +SetupFileMissing=Instalan sloka neobsahuje soubor %1. Opravte prosm tuto chybu nebo si opatete novou kopii tohoto produktu. +SetupFileCorrupt=Soubory prvodce instalac jsou pokozeny. Opatete si prosm novou kopii tohoto produktu. +SetupFileCorruptOrWrongVer=Soubory prvodce instalac jsou pokozeny nebo se nesluuj s touto verz prvodce instalac. Opravte prosm tuto chybu nebo si opatete novou kopii tohoto produktu. +InvalidParameter=Pkazov dek obsahuje neplatn parametr:%n%n%1 +SetupAlreadyRunning=Prvodce instalac je ji sputn. +WindowsVersionNotSupported=Tento produkt nepodporuje verzi MS Windows, kter b na Vaem potai. +WindowsServicePackRequired=Tento produkt vyaduje %1 Service Pack %2 nebo vy. +NotOnThisPlatform=Tento produkt nelze spustit ve %1. +OnlyOnThisPlatform=Tento produkt mus bt sputn ve %1. +OnlyOnTheseArchitectures=Tento produkt lze nainstalovat pouze ve verzch MS Windows s podporou architektury procesor:%n%n%1 +WinVersionTooLowError=Tento produkt vyaduje %1 verzi %2 nebo vy. +WinVersionTooHighError=Tento produkt nelze nainstalovat ve %1 verzi %2 nebo vy. +AdminPrivilegesRequired=K instalaci tohoto produktu muste bt pihleni s oprvnnmi sprvce. +PowerUserPrivilegesRequired=K instalaci tohoto produktu muste bt pihleni s oprvnnmi sprvce nebo lena skupiny Power Users. +SetupAppRunningError=Prvodce instalac zjistil, e produkt %1 je nyn sputn.%n%nZavete prosm vechny instance tohoto produktu a pak pokraujte klepnutm na tlatko OK, nebo ukonete instalaci tlatkem Zruit. +UninstallAppRunningError=Prvodce odinstalac zjistil, e produkt %1 je nyn sputn.%n%nZavete prosm vechny instance tohoto produktu a pak pokraujte klepnutm na tlatko OK, nebo ukonete odinstalaci tlatkem Zruit. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Vbr reimu prvodce instalac +PrivilegesRequiredOverrideInstruction=Zvolte reim instalace +PrivilegesRequiredOverrideText1=Produkt %1 lze nainstalovat pro vechny uivatele (muste bt pihleni s oprvnnmi sprvce), nebo pouze pro Vs. +PrivilegesRequiredOverrideText2=Produkt %1 lze nainstalovat pouze pro Vs, nebo pro vechny uivatele (muste bt pihleni s oprvnnmi sprvce). +PrivilegesRequiredOverrideAllUsers=Nainstalovat pro &vechny uivatele +PrivilegesRequiredOverrideAllUsersRecommended=Nainstalovat pro &vechny uivatele (doporuuje se) +PrivilegesRequiredOverrideCurrentUser=Nainstalovat pouze pro &m +PrivilegesRequiredOverrideCurrentUserRecommended=Nainstalovat pouze pro &m (doporuuje se) + +; *** Misc. errors +ErrorCreatingDir=Prvodci instalac se nepodailo vytvoit sloku "%1" +ErrorTooManyFilesInDir=Nelze vytvoit soubor ve sloce "%1", protoe tato sloka ji obsahuje pli mnoho soubor + +; *** Setup common messages +ExitSetupTitle=Ukonit prvodce instalac +ExitSetupMessage=Instalace nebyla zcela dokonena. Jestlie nyn prvodce instalac ukonte, produkt nebude nainstalovn.%n%nPrvodce instalac mete znovu spustit kdykoliv jindy a instalaci dokonit.%n%nChcete prvodce instalac ukonit? +AboutSetupMenuItem=&O prvodci instalac... +AboutSetupTitle=O prvodci instalac +AboutSetupMessage=%1 verze %2%n%3%n%n%1 domovsk strnka:%n%4 +AboutSetupNote= +TranslatorNote=Czech translation maintained by Ivo Bauer (bauer@ozm.cz), Lubos Stanek (lubek@users.sourceforge.net), Vitezslav Svejdar (vitezslav.svejdar@cuni.cz) and Jiri Fenz (jirifenz@gmail.com) + +; *** Buttons +ButtonBack=< &Zpt +ButtonNext=&Dal > +ButtonInstall=&Instalovat +ButtonOK=OK +ButtonCancel=Zruit +ButtonYes=&Ano +ButtonYesToAll=Ano &vem +ButtonNo=&Ne +ButtonNoToAll=N&e vem +ButtonFinish=&Dokonit +ButtonBrowse=&Prochzet... +ButtonWizardBrowse=&Prochzet... +ButtonNewFolder=&Vytvoit novou sloku + +; *** "Select Language" dialog messages +SelectLanguageTitle=Vbr jazyka prvodce instalac +SelectLanguageLabel=Zvolte jazyk, kter se m pout bhem instalace. + +; *** Common wizard text +ClickNext=Pokraujte klepnutm na tlatko Dal, nebo ukonete prvodce instalac tlatkem Zruit. +BeveledLabel= +BrowseDialogTitle=Vyhledat sloku +BrowseDialogLabel=Z ne uvedenho seznamu vyberte sloku a klepnte na tlatko OK. +NewFolderName=Nov sloka + +; *** "Welcome" wizard page +WelcomeLabel1=Vt Vs prvodce instalac produktu [name]. +WelcomeLabel2=Produkt [name/ver] bude nainstalovn na V pota.%n%nDve ne budete pokraovat, doporuuje se zavt veker sputn aplikace. + +; *** "Password" wizard page +WizardPassword=Heslo +PasswordLabel1=Tato instalace je chrnna heslem. +PasswordLabel3=Zadejte prosm heslo a pokraujte klepnutm na tlatko Dal. Pi zadvn hesla rozliujte mal a velk psmena. +PasswordEditLabel=&Heslo: +IncorrectPassword=Zadan heslo nen sprvn. Zkuste to prosm znovu. + +; *** "License Agreement" wizard page +WizardLicense=Licenn smlouva +LicenseLabel=Dve ne budete pokraovat, pette si prosm pozorn nsledujc dleit informace. +LicenseLabel3=Pette si prosm nsledujc licenn smlouvu. Aby instalace mohla pokraovat, muste souhlasit s podmnkami tto smlouvy. +LicenseAccepted=&Souhlasm s podmnkami licenn smlouvy +LicenseNotAccepted=&Nesouhlasm s podmnkami licenn smlouvy + +; *** "Information" wizard pages +WizardInfoBefore=Informace +InfoBeforeLabel=Dve ne budete pokraovat, pette si prosm pozorn nsledujc dleit informace. +InfoBeforeClickLabel=Pokraujte v instalaci klepnutm na tlatko Dal. +WizardInfoAfter=Informace +InfoAfterLabel=Dve ne budete pokraovat, pette si prosm pozorn nsledujc dleit informace. +InfoAfterClickLabel=Pokraujte v instalaci klepnutm na tlatko Dal. + +; *** "User Information" wizard page +WizardUserInfo=Informace o uivateli +UserInfoDesc=Zadejte prosm poadovan daje. +UserInfoName=&Uivatelsk jmno: +UserInfoOrg=&Spolenost: +UserInfoSerial=S&riov slo: +UserInfoNameRequired=Muste zadat uivatelsk jmno. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Zvolte clov umstn +SelectDirDesc=Kam m bt produkt [name] nainstalovn? +SelectDirLabel3=Prvodce nainstaluje produkt [name] do nsledujc sloky. +SelectDirBrowseLabel=Pokraujte klepnutm na tlatko Dal. Chcete-li zvolit jinou sloku, klepnte na tlatko Prochzet. +DiskSpaceGBLabel=Instalace vyaduje nejmn [gb] GB volnho msta na disku. +DiskSpaceMBLabel=Instalace vyaduje nejmn [mb] MB volnho msta na disku. +CannotInstallToNetworkDrive=Prvodce instalac neme instalovat do sov jednotky. +CannotInstallToUNCPath=Prvodce instalac neme instalovat do cesty UNC. +InvalidPath=Muste zadat plnou cestu vetn psmene jednotky; napklad:%n%nC:\Aplikace%n%nnebo cestu UNC ve tvaru:%n%n\\server\sdlen sloka +InvalidDrive=Vmi zvolen jednotka nebo cesta UNC neexistuje nebo nen dostupn. Zvolte prosm jin umstn. +DiskSpaceWarningTitle=Nedostatek msta na disku +DiskSpaceWarning=Prvodce instalac vyaduje nejmn %1 KB volnho msta pro instalaci produktu, ale na zvolen jednotce je dostupnch pouze %2 KB.%n%nChcete pesto pokraovat? +DirNameTooLong=Nzev sloky nebo cesta jsou pli dlouh. +InvalidDirName=Nzev sloky nen platn. +BadDirName32=Nzev sloky neme obsahovat dn z nsledujcch znak:%n%n%1 +DirExistsTitle=Sloka existuje +DirExists=Sloka:%n%n%1%n%nji existuje. M se pesto instalovat do tto sloky? +DirDoesntExistTitle=Sloka neexistuje +DirDoesntExist=Sloka:%n%n%1%n%nneexistuje. M bt tato sloka vytvoena? + +; *** "Select Components" wizard page +WizardSelectComponents=Zvolte sousti +SelectComponentsDesc=Jak sousti maj bt nainstalovny? +SelectComponentsLabel2=Zakrtnte sousti, kter maj bt nainstalovny; sousti, kter se nemaj instalovat, ponechte nezakrtnut. Pokraujte klepnutm na tlatko Dal. +FullInstallation=pln instalace +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Kompaktn instalace +CustomInstallation=Voliteln instalace +NoUninstallWarningTitle=Sousti existuj +NoUninstallWarning=Prvodce instalac zjistil, e nsledujc sousti jsou ji na Vaem potai nainstalovny:%n%n%1%n%nNezahrnete-li tyto sousti do vbru, nebudou nyn odinstalovny.%n%nChcete pesto pokraovat? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Vybran sousti vyaduj nejmn [gb] GB msta na disku. +ComponentsDiskSpaceMBLabel=Vybran sousti vyaduj nejmn [mb] MB msta na disku. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Zvolte dal lohy +SelectTasksDesc=Kter dal lohy maj bt provedeny? +SelectTasksLabel2=Zvolte dal lohy, kter maj bt provedeny v prbhu instalace produktu [name], a pak pokraujte klepnutm na tlatko Dal. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Vyberte sloku v nabdce Start +SelectStartMenuFolderDesc=Kam m prvodce instalac umstit zstupce aplikace? +SelectStartMenuFolderLabel3=Prvodce instalac vytvo zstupce aplikace v nsledujc sloce nabdky Start. +SelectStartMenuFolderBrowseLabel=Pokraujte klepnutm na tlatko Dal. Chcete-li zvolit jinou sloku, klepnte na tlatko Prochzet. +MustEnterGroupName=Muste zadat nzev sloky. +GroupNameTooLong=Nzev sloky nebo cesta jsou pli dlouh. +InvalidGroupName=Nzev sloky nen platn. +BadGroupName=Nzev sloky neme obsahovat dn z nsledujcch znak:%n%n%1 +NoProgramGroupCheck2=&Nevytvet sloku v nabdce Start + +; *** "Ready to Install" wizard page +WizardReady=Instalace je pipravena +ReadyLabel1=Prvodce instalac je nyn pipraven nainstalovat produkt [name] na V pota. +ReadyLabel2a=Pokraujte v instalaci klepnutm na tlatko Instalovat. Pejete-li si zmnit nkter nastaven instalace, klepnte na tlatko Zpt. +ReadyLabel2b=Pokraujte v instalaci klepnutm na tlatko Instalovat. +ReadyMemoUserInfo=Informace o uivateli: +ReadyMemoDir=Clov umstn: +ReadyMemoType=Typ instalace: +ReadyMemoComponents=Vybran sousti: +ReadyMemoGroup=Sloka v nabdce Start: +ReadyMemoTasks=Dal lohy: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Stahuj se dal soubory... +ButtonStopDownload=&Zastavit stahovn +StopDownload=Urit chcete stahovn zastavit? +ErrorDownloadAborted=Stahovn perueno +ErrorDownloadFailed=Stahovn selhalo: %1 %2 +ErrorDownloadSizeFailed=Nepodailo se zjistit velikost: %1 %2 +ErrorFileHash1=Nepodailo se urit kontroln souet souboru: %1 +ErrorFileHash2=Neplatn kontroln souet souboru: oekvno %1, nalezeno %2 +ErrorProgress=Neplatn prbh: %1 of %2 +ErrorFileSize=Neplatn velikost souboru: oekvno %1, nalezeno %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Pprava k instalaci +PreparingDesc=Prvodce instalac pipravuje instalaci produktu [name] na V pota. +PreviousInstallNotCompleted=Instalace/odinstalace pedchozho produktu nebyla zcela dokonena. Aby mohla bt dokonena, muste restartovat V pota.%n%nPo restartovn Vaeho potae spuste znovu prvodce instalac, aby bylo mon dokonit instalaci produktu [name]. +CannotContinue=Prvodce instalac neme pokraovat. Ukonete prosm prvodce instalac klepnutm na tlatko Zruit. +ApplicationsFound=Nsledujc aplikace pistupuj k souborm, kter je teba bhem instalace aktualizovat. Doporuuje se povolit prvodci instalac, aby tyto aplikace automaticky zavel. +ApplicationsFound2=Nsledujc aplikace pistupuj k souborm, kter je teba bhem instalace aktualizovat. Doporuuje se povolit prvodci instalac, aby tyto aplikace automaticky zavel. Po dokonen instalace se prvodce instalac pokus aplikace restartovat. +CloseApplications=&Zavt aplikace automaticky +DontCloseApplications=&Nezavrat aplikace +ErrorCloseApplications=Prvodci instalac se nepodailo automaticky zavt vechny aplikace. Dve ne budete pokraovat, doporuuje se zavt veker aplikace pistupujc k souborm, kter je teba bhem instalace aktualizovat. +PrepareToInstallNeedsRestart=Prvodce instalac mus restartovat V pota. Po restartovn Vaeho potae spuste prvodce instalac znovu, aby bylo mon dokonit instalaci produktu [name].%n%nChcete jej restartovat nyn? + +; *** "Installing" wizard page +WizardInstalling=Instalovn +InstallingLabel=ekejte prosm, dokud prvodce instalac nedokon instalaci produktu [name] na V pota. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Dokonuje se instalace produktu [name] +FinishedLabelNoIcons=Prvodce instalac dokonil instalaci produktu [name] na V pota. +FinishedLabel=Prvodce instalac dokonil instalaci produktu [name] na V pota. Produkt lze spustit pomoc nainstalovanch zstupc. +ClickFinish=Ukonete prvodce instalac klepnutm na tlatko Dokonit. +FinishedRestartLabel=K dokonen instalace produktu [name] je nezbytn, aby prvodce instalac restartoval V pota. Chcete jej restartovat nyn? +FinishedRestartMessage=K dokonen instalace produktu [name] je nezbytn, aby prvodce instalac restartoval V pota.%n%nChcete jej restartovat nyn? +ShowReadmeCheck=Ano, chci zobrazit dokument "TIMNE" +YesRadio=&Ano, chci nyn restartovat pota +NoRadio=&Ne, pota restartuji pozdji +; used for example as 'Run MyProg.exe' +RunEntryExec=Spustit %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Zobrazit %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Prvodce instalac vyaduje dal disk +SelectDiskLabel2=Vlote prosm disk %1 a klepnte na tlatko OK.%n%nPokud se soubory na tomto disku nachzej v jin sloce ne v t, kter je zobrazena ne, pak zadejte sprvnou cestu nebo ji zvolte klepnutm na tlatko Prochzet. +PathLabel=&Cesta: +FileNotInDir2=Soubor "%1" nelze najt v "%2". Vlote prosm sprvn disk nebo zvolte jinou sloku. +SelectDirectoryLabel=Specifikujte prosm umstn dalho disku. + +; *** Installation phase messages +SetupAborted=Instalace nebyla zcela dokonena.%n%nOpravte prosm chybu a spuste prvodce instalac znovu. +AbortRetryIgnoreSelectAction=Zvolte akci +AbortRetryIgnoreRetry=&Zopakovat akci +AbortRetryIgnoreIgnore=&Ignorovat chybu a pokraovat +AbortRetryIgnoreCancel=Zruit instalaci + +; *** Installation status messages +StatusClosingApplications=Zavraj se aplikace... +StatusCreateDirs=Vytvej se sloky... +StatusExtractFiles=Extrahuj se soubory... +StatusCreateIcons=Vytvej se zstupci... +StatusCreateIniEntries=Vytvej se zznamy v inicializanch souborech... +StatusCreateRegistryEntries=Vytvej se zznamy v systmovm registru... +StatusRegisterFiles=Registruj se soubory... +StatusSavingUninstall=Ukldaj se informace pro odinstalaci produktu... +StatusRunProgram=Dokonuje se instalace... +StatusRestartingApplications=Restartuj se aplikace... +StatusRollback=Proveden zmny se vracej zpt... + +; *** Misc. errors +ErrorInternal2=Intern chyba: %1 +ErrorFunctionFailedNoCode=Funkce %1 selhala +ErrorFunctionFailed=Funkce %1 selhala; kd %2 +ErrorFunctionFailedWithMessage=Funkce %1 selhala; kd %2.%n%3 +ErrorExecutingProgram=Nelze spustit soubor:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Dolo k chyb pi otevrn kle systmovho registru:%n%1\%2 +ErrorRegCreateKey=Dolo k chyb pi vytven kle systmovho registru:%n%1\%2 +ErrorRegWriteKey=Dolo k chyb pi zpisu do kle systmovho registru:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Dolo k chyb pi vytven zznamu v inicializanm souboru "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Peskoit tento soubor (nedoporuuje se) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorovat chybu a pokraovat (nedoporuuje se) +SourceIsCorrupted=Zdrojov soubor je pokozen +SourceDoesntExist=Zdrojov soubor "%1" neexistuje +ExistingFileReadOnly2=Nelze nahradit existujc soubor, protoe je uren pouze pro ten. +ExistingFileReadOnlyRetry=&Odstranit atribut "pouze pro ten" a zopakovat akci +ExistingFileReadOnlyKeepExisting=&Ponechat existujc soubor +ErrorReadingExistingDest=Dolo k chyb pi pokusu o ten existujcho souboru: +FileExistsSelectAction=Zvolte akci +FileExists2=Soubor ji existuje. +FileExistsOverwriteExisting=&Nahradit existujc soubor +FileExistsKeepExisting=&Ponechat existujc soubor +FileExistsOverwriteOrKeepAll=&Zachovat se stejn u dalch konflikt +ExistingFileNewerSelectAction=Zvolte akci +ExistingFileNewer2=Existujc soubor je novj ne ten, kter se prvodce instalac pokou instalovat. +ExistingFileNewerOverwriteExisting=&Nahradit existujc soubor +ExistingFileNewerKeepExisting=&Ponechat existujc soubor (doporuuje se) +ExistingFileNewerOverwriteOrKeepAll=&Zachovat se stejn u dalch konflikt +ErrorChangingAttr=Dolo k chyb pi pokusu o zmnu atribut existujcho souboru: +ErrorCreatingTemp=Dolo k chyb pi pokusu o vytvoen souboru v clov sloce: +ErrorReadingSource=Dolo k chyb pi pokusu o ten zdrojovho souboru: +ErrorCopying=Dolo k chyb pi pokusu o zkoprovn souboru: +ErrorReplacingExistingFile=Dolo k chyb pi pokusu o nahrazen existujcho souboru: +ErrorRestartReplace=Funkce "RestartReplace" prvodce instalac selhala: +ErrorRenamingTemp=Dolo k chyb pi pokusu o pejmenovn souboru v clov sloce: +ErrorRegisterServer=Nelze zaregistrovat DLL/OCX: %1 +ErrorRegSvr32Failed=Voln RegSvr32 selhalo s nvratovm kdem %1 +ErrorRegisterTypeLib=Nelze zaregistrovat typovou knihovnu: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32bitov +UninstallDisplayNameMark64Bit=64bitov +UninstallDisplayNameMarkAllUsers=Vichni uivatel +UninstallDisplayNameMarkCurrentUser=Aktuln uivatel + +; *** Post-installation errors +ErrorOpeningReadme=Dolo k chyb pi pokusu o oteven dokumentu "TIMNE". +ErrorRestartingComputer=Prvodci instalac se nepodailo restartovat V pota. Restartujte jej prosm run. + +; *** Uninstaller messages +UninstallNotFound=Soubor "%1" neexistuje. Produkt nelze odinstalovat. +UninstallOpenError=Soubor "%1" nelze otevt. Produkt nelze odinstalovat. +UninstallUnsupportedVer=Formt souboru se zznamy k odinstalaci produktu "%1" nebyl touto verz prvodce odinstalac rozpoznn. Produkt nelze odinstalovat +UninstallUnknownEntry=V souboru obsahujcm informace k odinstalaci produktu byla zjitna neznm poloka (%1) +ConfirmUninstall=Urit chcete produkt %1 a vechny jeho sousti odinstalovat? +UninstallOnlyOnWin64=Tento produkt lze odinstalovat pouze v 64-bitovch verzch MS Windows. +OnlyAdminCanUninstall=K odinstalaci tohoto produktu muste bt pihleni s oprvnnmi sprvce. +UninstallStatusLabel=ekejte prosm, dokud produkt %1 nebude odinstalovn z Vaeho potae. +UninstalledAll=Produkt %1 byl z Vaeho potae spn odinstalovn. +UninstalledMost=Produkt %1 byl odinstalovn.%n%nNkter jeho sousti se odinstalovat nepodailo. Mete je vak odstranit run. +UninstalledAndNeedsRestart=K dokonen odinstalace produktu %1 je nezbytn, aby prvodce odinstalac restartoval V pota.%n%nChcete jej restartovat nyn? +UninstallDataCorrupted=Soubor "%1" je pokozen. Produkt nelze odinstalovat + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Odebrat sdlen soubor? +ConfirmDeleteSharedFile2=Systm indikuje, e nsledujc sdlen soubor nen pouvn dnmi jinmi aplikacemi. M bt tento sdlen soubor prvodcem odinstalac odstrann?%n%nPokud nkter aplikace tento soubor pouvaj, pak po jeho odstrann nemusej pracovat sprvn. Pokud si nejste jisti, zvolte Ne. Ponechn tohoto souboru ve Vaem systmu nezpsob dnou kodu. +SharedFileNameLabel=Nzev souboru: +SharedFileLocationLabel=Umstn: +WizardUninstalling=Stav odinstalace +StatusUninstalling=Probh odinstalace produktu %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Probh instalace produktu %1. +ShutdownBlockReasonUninstallingApp=Probh odinstalace produktu %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 verze %2 +AdditionalIcons=Dal zstupci: +CreateDesktopIcon=Vytvoit zstupce na &ploe +CreateQuickLaunchIcon=Vytvoit zstupce na panelu &Snadn sputn +ProgramOnTheWeb=Aplikace %1 na internetu +UninstallProgram=Odinstalovat aplikaci %1 +LaunchProgram=Spustit aplikaci %1 +AssocFileExtension=Vytvoit &asociaci mezi soubory typu %2 a aplikac %1 +AssocingFileExtension=Vytv se asociace mezi soubory typu %2 a aplikac %1... +AutoStartProgramGroupDescription=Po sputn: +AutoStartProgram=Spoutt aplikaci %1 automaticky +AddonHostProgramNotFound=Aplikace %1 nebyla ve Vmi zvolen sloce nalezena.%n%nChcete pesto pokraovat? diff --git a/installer/innosetup/Languages/Danish.isl b/installer/innosetup/Languages/Danish.isl new file mode 100644 index 000000000..3939de267 --- /dev/null +++ b/installer/innosetup/Languages/Danish.isl @@ -0,0 +1,379 @@ +; *** Inno Setup version 6.1.0+ Danish messages *** +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). +; +; ID: Danish.isl,v 6.0.3+ 2020/07/26 Thomas Vedel, thomas@veco.dk +; Parts by scootergrisen, 2015 + +[LangOptions] +LanguageName=Dansk +LanguageID=$0406 +LanguageCodePage=1252 + +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] +; *** Application titles +SetupAppTitle=Installationsguide +SetupWindowTitle=Installationsguide - %1 +UninstallAppTitle=Afinstallr +UninstallAppFullTitle=Afinstallerer %1 + +; *** Misc. common +InformationTitle=Information +ConfirmTitle=Bekrft +ErrorTitle=Fejl + +; *** SetupLdr messages +SetupLdrStartupMessage=Denne guide installerer %1. Vil du fortstte? +LdrCannotCreateTemp=Kan ikke oprette en midlertidig fil. Installationen afbrydes +LdrCannotExecTemp=Kan ikke kre et program i den midlertidige mappe. Installationen afbrydes +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nFejl %2: %3 +SetupFileMissing=Filen %1 mangler i installationsmappen. Ret venligst problemet eller f en ny kopi af programmet. +SetupFileCorrupt=Installationsfilerne er beskadiget. F venligst en ny kopi af installationsprogrammet. +SetupFileCorruptOrWrongVer=Installationsfilerne er beskadiget, eller ogs er de ikke kompatible med denne version af installationsprogrammet. Ret venligst problemet eller f en ny kopi af installationsprogrammet. +InvalidParameter=En ugyldig parameter blev angivet p kommandolinjen:%n%n%1 +SetupAlreadyRunning=Installationsprogrammet krer allerede. +WindowsVersionNotSupported=Programmet understtter ikke den version af Windows, som denne computer krer. +WindowsServicePackRequired=Programmet krver %1 med Service Pack %2 eller senere. +NotOnThisPlatform=Programmet kan ikke anvendes p %1. +OnlyOnThisPlatform=Programmet kan kun anvendes p %1. +OnlyOnTheseArchitectures=Programmet kan kun installeres p versioner af Windows der anvender disse processor-arkitekturer:%n%n%1 +WinVersionTooLowError=Programmet krver %1 version %2 eller senere. +WinVersionTooHighError=Programmet kan ikke installeres p %1 version %2 eller senere. +AdminPrivilegesRequired=Du skal vre logget p som administrator imens programmet installeres. +PowerUserPrivilegesRequired=Du skal vre logget p som administrator eller vre medlem af gruppen Superbrugere imens programmet installeres. +SetupAppRunningError=Installationsprogrammet har registreret at %1 krer.%n%nLuk venligst alle forekomster af programmet, og klik s OK for at fortstte, eller Annuller for at afbryde. +UninstallAppRunningError=Afinstallationsprogrammet har registreret at %1 krer.%n%nLuk venligst alle forekomster af programmet, og klik s OK for at fortstte, eller Annuller for at afbryde. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Vlg guidens installationsmde +PrivilegesRequiredOverrideInstruction=Vlg installationsmde +PrivilegesRequiredOverrideText1=%1 kan installeres for alle brugere (krver administrator-rettigheder), eller for dig alene. +PrivilegesRequiredOverrideText2=%1 kan installeres for dig alene, eller for alle brugere p computeren (sidstnvnte krver administrator-rettigheder). +PrivilegesRequiredOverrideAllUsers=Installer for &alle brugere +PrivilegesRequiredOverrideAllUsersRecommended=Installer for &alle brugere (anbefales) +PrivilegesRequiredOverrideCurrentUser=Installer for &mig alene +PrivilegesRequiredOverrideCurrentUserRecommended=Installer for &mig alene (anbefales) + +; *** Misc. errors +ErrorCreatingDir=Installationsprogrammet kan ikke oprette mappen "%1" +ErrorTooManyFilesInDir=Kan ikke oprette en fil i mappen "%1". Mappen indeholder for mange filer + +; *** Setup common messages +ExitSetupTitle=Afbryd installationen +ExitSetupMessage=Installationen er ikke fuldfrt. Programmet installeres ikke, hvis du afbryder nu.%n%nDu kan kre installationsprogrammet igen p et andet tidspunkt for at udfre installationen.%n%nSkal installationen afbrydes? +AboutSetupMenuItem=&Om installationsprogrammet... +AboutSetupTitle=Om installationsprogrammet +AboutSetupMessage=%1 version %2%n%3%n%n%1 hjemmeside:%n%4 +AboutSetupNote= +TranslatorNote=Danish translation maintained by Thomas Vedel (thomas@veco.dk). Parts by scootergrisen. + +; *** Buttons +ButtonBack=< &Tilbage +ButtonNext=N&ste > +ButtonInstall=&Installer +ButtonOK=&OK +ButtonCancel=&Annuller +ButtonYes=&Ja +ButtonYesToAll=Ja til a&lle +ButtonNo=&Nej +ButtonNoToAll=Nej t&il alle +ButtonFinish=&Frdig +ButtonBrowse=&Gennemse... +ButtonWizardBrowse=G&ennemse... +ButtonNewFolder=&Opret ny mappe + +; *** "Select Language" dialog messages +SelectLanguageTitle=Vlg installationssprog +SelectLanguageLabel=Vlg det sprog der skal vises under installationen. + +; *** Common wizard text +ClickNext=Klik p Nste for at fortstte, eller Annuller for at afbryde installationen. +BeveledLabel= +BrowseDialogTitle=Vlg mappe +BrowseDialogLabel=Vlg en mappe fra nedenstende liste og klik p OK. +NewFolderName=Ny mappe + +; *** "Welcome" wizard page +WelcomeLabel1=Velkommen til installationsguiden for [name] +WelcomeLabel2=Guiden installerer [name/ver] p computeren.%n%nDet anbefales at lukke alle andre programmer inden du fortstter. + +; *** "Password" wizard page +WizardPassword=Adgangskode +PasswordLabel1=Installationen er beskyttet med adgangskode. +PasswordLabel3=Indtast venligst adgangskoden og klik p Nste for at fortstte. Der skelnes mellem store og sm bogstaver. +PasswordEditLabel=&Adgangskode: +IncorrectPassword=Den indtastede kode er forkert. Prv venligst igen. + +; *** "License Agreement" wizard page +WizardLicense=Licensaftale +LicenseLabel=Ls venligst flgende vigtige oplysninger inden du fortstter. +LicenseLabel3=Ls venligst licensaftalen. Du skal acceptere betingelserne i aftalen for at fortstte installationen. +LicenseAccepted=Jeg &accepterer aftalen +LicenseNotAccepted=Jeg accepterer &ikke aftalen + +; *** "Information" wizard pages +WizardInfoBefore=Information +InfoBeforeLabel=Ls venligst flgende information inden du fortstter. +InfoBeforeClickLabel=Klik p Nste, nr du er klar til at fortstte installationen. +WizardInfoAfter=Information +InfoAfterLabel=Ls venligst flgende information inden du fortstter. +InfoAfterClickLabel=Klik p Nste, nr du er klar til at fortstte installationen. + +; *** "User Information" wizard page +WizardUserInfo=Brugerinformation +UserInfoDesc=Indtast venligst dine oplysninger. +UserInfoName=&Brugernavn: +UserInfoOrg=&Organisation: +UserInfoSerial=&Serienummer: +UserInfoNameRequired=Du skal indtaste et navn. + +; *** "Select Destination Directory" wizard page +WizardSelectDir=Vlg installationsmappe +SelectDirDesc=Hvor skal [name] installeres? +SelectDirLabel3=Installationsprogrammet installerer [name] i flgende mappe. +SelectDirBrowseLabel=Klik p Nste for at fortstte. Klik p Gennemse, hvis du vil vlge en anden mappe. +DiskSpaceGBLabel=Der skal vre mindst [gb] GB fri diskplads. +DiskSpaceMBLabel=Der skal vre mindst [mb] MB fri diskplads. +CannotInstallToNetworkDrive=Guiden kan ikke installere programmet p et netvrksdrev. +CannotInstallToUNCPath=Guiden kan ikke installere programmet til en UNC-sti. +InvalidPath=Du skal indtaste en komplet sti med drevbogstav, f.eks.:%n%nC:\Program%n%neller et UNC-stinavn i formatet:%n%n\\server\share +InvalidDrive=Drevet eller UNC-stien du valgte findes ikke, eller der er ikke adgang til det lige nu. Vlg venligst en anden placering. +DiskSpaceWarningTitle=Ikke nok ledig diskplads. +DiskSpaceWarning=Guiden krver mindst %1 KB ledig diskplads for at kunne installere programmet, men det valgte drev har kun %2 KB ledig diskplads.%n%nVil du alligevel fortstte installationen? +DirNameTooLong=Navnet p mappen eller stien er for langt. +InvalidDirName=Navnet p mappen er ikke tilladt. +BadDirName32=Mappenavne m ikke indeholde flgende tegn:%n%n%1 +DirExistsTitle=Mappen findes +DirExists=Mappen:%n%n%1%n%nfindes allerede. Vil du alligevel installere i denne mappe? +DirDoesntExistTitle=Mappen findes ikke. +DirDoesntExist=Mappen:%n%n%1%n%nfindes ikke. Vil du oprette mappen? + +; *** "Select Components" wizard page +WizardSelectComponents=Vlg Komponenter +SelectComponentsDesc=Hvilke komponenter skal installeres? +SelectComponentsLabel2=Vlg de komponenter der skal installeres, og fjern markering fra dem der ikke skal installeres. Klik s p Nste for at fortstte. +FullInstallation=Fuld installation +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Kompakt installation +CustomInstallation=Tilpasset installation +NoUninstallWarningTitle=Komponenterne er installeret +NoUninstallWarning=Installationsprogrammet har registreret at flgende komponenter allerede er installeret p computeren:%n%n%1%n%nKomponenterne bliver ikke afinstalleret hvis de fravlges.%n%nFortst alligevel? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=De nuvrende valg krver mindst [gb] GB ledig diskplads. +ComponentsDiskSpaceMBLabel=De nuvrende valg krver mindst [mb] MB ledig diskplads. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Vlg supplerende opgaver +SelectTasksDesc=Hvilke supplerende opgaver skal udfres? +SelectTasksLabel2=Vlg de supplerende opgaver du vil have guiden til at udfre under installationen af [name] og klik p Nste. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Vlg mappe i menuen Start +SelectStartMenuFolderDesc=Hvor skal installationsprogrammet oprette genveje til programmet? +SelectStartMenuFolderLabel3=Installationsprogrammet opretter genveje til programmet i flgende mappe i menuen Start. +SelectStartMenuFolderBrowseLabel=Klik p Nste for at fortstte. Klik p Gennemse, hvis du vil vlge en anden mappe. +MustEnterGroupName=Du skal indtaste et mappenavn. +GroupNameTooLong=Mappens eller stiens navn er for langt. +InvalidGroupName=Mappenavnet er ugyldigt. +BadGroupName=Navnet p en programgruppe m ikke indeholde flgende tegn: %1. Angiv andet navn. +NoProgramGroupCheck2=Opret &ingen programgruppe i menuen Start + +; *** "Ready to Install" wizard page +WizardReady=Klar til at installere +ReadyLabel1=Installationsprogrammet er nu klar til at installere [name] p computeren. +ReadyLabel2a=Klik p Installer for at fortstte med installationen, eller klik p Tilbage hvis du vil se eller ndre indstillingerne. +ReadyLabel2b=Klik p Installer for at fortstte med installationen. +ReadyMemoUserInfo=Brugerinformation: +ReadyMemoDir=Installationsmappe: +ReadyMemoType=Installationstype: +ReadyMemoComponents=Valgte komponenter: +ReadyMemoGroup=Mappe i menuen Start: +ReadyMemoTasks=Valgte supplerende opgaver: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Downloader yderligere filer... +ButtonStopDownload=&Stop download +StopDownload=Er du sikker p at du nsker at afbryde download? +ErrorDownloadAborted=Download afbrudt +ErrorDownloadFailed=Fejl under download: %1 %2 +ErrorDownloadSizeFailed=Fejl ved lsning af filstrrelse: %1 %2 +ErrorFileHash1=Fejl i hash: %1 +ErrorFileHash2=Fejl i fil hash vrdi: forventet %1, fundet %2 +ErrorProgress=Fejl i trin: %1 af %2 +ErrorFileSize=Fejl i filstrrelse: forventet %1, fundet %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Klargring af installationen +PreparingDesc=Installationsprogrammet gr klar til at installere [name] p din computer. +PreviousInstallNotCompleted=Installation eller afinstallation af et program er ikke afsluttet. Du skal genstarte computeren for at afslutte den foregende installation.%n%nNr computeren er genstartet skal du kre installationsprogrammet til [name] igen. +CannotContinue=Installationsprogrammet kan ikke fortstte. Klik venligst p Fortryd for at afslutte. +ApplicationsFound=Flgende programmer bruger filer som skal opdateres. Det anbefales at du giver installationsprogrammet tilladelse til automatisk at lukke programmerne. +ApplicationsFound2=Flgende programmer bruger filer som skal opdateres. Det anbefales at du giver installationsprogrammet tilladelse til automatisk at lukke programmerne. Installationsguiden vil forsge at genstarte programmerne nr installationen er fuldfrt. +CloseApplications=&Luk programmerne automatisk +DontCloseApplications=Luk &ikke programmerne +ErrorCloseApplications=Installationsprogrammet kunne ikke lukke alle programmerne automatisk. Det anbefales at du lukker alle programmer som bruger filer der skal opdateres, inden installationsprogrammet fortstter. +PrepareToInstallNeedsRestart=Installationsprogrammet er ndt til at genstarte computeren. Efter genstarten skal du kre installationsprogrammet igen for at frdiggre installation af [name].%n%nVil du at genstarte nu? + +; *** "Installing" wizard page +WizardInstalling=Installerer +InstallingLabel=Vent venligst mens installationsprogrammet installerer [name] p computeren. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Fuldfrer installation af [name] +FinishedLabelNoIcons=Installationsguiden har fuldfrt installation af [name] p computeren. +FinishedLabel=Installationsguiden har fuldfrt installation af [name] p computeren. Programmet kan startes ved at vlge de oprettede ikoner. +ClickFinish=Klik p Frdig for at afslutte installationsprogrammet. +FinishedRestartLabel=Computeren skal genstartes for at fuldfre installation af [name]. Vil du genstarte computeren nu? +FinishedRestartMessage=Computeren skal genstartes for at fuldfre installation af [name].%n%nVil du genstarte computeren nu? +ShowReadmeCheck=Ja, jeg vil gerne se README-filen +YesRadio=&Ja, genstart computeren nu +NoRadio=&Nej, jeg genstarter computeren senere +; used for example as 'Run MyProg.exe' +RunEntryExec=Kr %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Vis %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Installationsprogrammet skal bruge den nste disk +SelectDiskLabel2=Indst disk %1 og klik p OK.%n%nHvis filerne findes i en anden mappe end den viste, s indtast stien eller klik Gennemse. +PathLabel=&Sti: +FileNotInDir2=Filen "%1" blev ikke fundet i "%2". Indst venligst den korrekte disk, eller vlg en anden mappe. +SelectDirectoryLabel=Angiv venligst placeringen af den nste disk. + +; *** Installation phase messages +SetupAborted=Installationen blev ikke fuldfrt.%n%nRet venligst de fundne problemer og kr installationsprogrammet igen. +AbortRetryIgnoreSelectAction=Vlg nsket handling +AbortRetryIgnoreRetry=&Forsg igen +AbortRetryIgnoreIgnore=&Ignorer fejlen og fortst +AbortRetryIgnoreCancel=Afbryd installationen + +; *** Installation status messages +StatusClosingApplications=Lukker programmer... +StatusCreateDirs=Opretter mapper... +StatusExtractFiles=Udpakker filer... +StatusCreateIcons=Opretter genveje... +StatusCreateIniEntries=Opretter poster i INI-filer... +StatusCreateRegistryEntries=Opretter poster i registreringsdatabasen... +StatusRegisterFiles=Registrerer filer... +StatusSavingUninstall=Gemmer information om afinstallation... +StatusRunProgram=Fuldfrer installation... +StatusRestartingApplications=Genstarter programmer... +StatusRollback=Fjerner ndringer... + +; *** Misc. errors +ErrorInternal2=Intern fejl: %1 +ErrorFunctionFailedNoCode=%1 fejlede +ErrorFunctionFailed=%1 fejlede; kode %2 +ErrorFunctionFailedWithMessage=%1 fejlede; kode %2.%n%3 +ErrorExecutingProgram=Kan ikke kre programfilen:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Fejl ved bning af ngle i registreringsdatabase:%n%1\%2 +ErrorRegCreateKey=Fejl ved oprettelse af ngle i registreringsdatabase:%n%1\%2 +ErrorRegWriteKey=Fejl ved skrivning til ngle i registreringsdatabase:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Fejl ved oprettelse af post i INI-filen "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Spring over denne fil (anbefales ikke) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorer fejlen og fortst (anbefales ikke) +SourceIsCorrupted=Kildefilen er beskadiget +SourceDoesntExist=Kildefilen "%1" findes ikke +ExistingFileReadOnly2=Den eksisterende fil er skrivebeskyttet og kan derfor ikke overskrives. +ExistingFileReadOnlyRetry=&Fjern skrivebeskyttelsen og forsg igen +ExistingFileReadOnlyKeepExisting=&Behold den eksisterende fil +ErrorReadingExistingDest=Der opstod en fejl ved lsning af den eksisterende fil: +FileExistsSelectAction=Vlg handling +FileExists2=Filen findes allerede. +FileExistsOverwriteExisting=&Overskriv den eksisterende fil +FileExistsKeepExisting=&Behold den eksiterende fil +FileExistsOverwriteOrKeepAll=&Gentag handlingen for de nste konflikter +ExistingFileNewerSelectAction=Vlg handling +ExistingFileNewer2=Den eksisterende fil er nyere end den som forsges installeret. +ExistingFileNewerOverwriteExisting=&Overskriv den eksisterende fil +ExistingFileNewerKeepExisting=&Behold den eksisterende fil (anbefales) +ExistingFileNewerOverwriteOrKeepAll=&Gentag handlingen for de nste konflikter +ErrorChangingAttr=Der opstod en fejl ved ndring af attributter for den eksisterende fil: +ErrorCreatingTemp=Der opstod en fejl ved oprettelse af en fil i mappen: +ErrorReadingSource=Der opstod en fejl ved lsning af kildefilen: +ErrorCopying=Der opstod en fejl ved kopiering af en fil: +ErrorReplacingExistingFile=Der opstod en fejl ved forsg p at erstatte den eksisterende fil: +ErrorRestartReplace=Erstatning af fil ved genstart mislykkedes: +ErrorRenamingTemp=Der opstod en fejl ved forsg p at omdbe en fil i installationsmappen: +ErrorRegisterServer=Kan ikke registrere DLL/OCX: %1 +ErrorRegSvr32Failed=RegSvr32 fejlede med exit kode %1 +ErrorRegisterTypeLib=Kan ikke registrere typebiblioteket: %1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Alle brugere +UninstallDisplayNameMarkCurrentUser=Nuvrende bruger + +; *** Post-installation errors +ErrorOpeningReadme=Der opstod en fejl ved forsg p at bne README-filen. +ErrorRestartingComputer=Installationsprogrammet kunne ikke genstarte computeren. Genstart venligst computeren manuelt. + +; *** Uninstaller messages +UninstallNotFound=Filen "%1" findes ikke. Kan ikke afinstalleres. +UninstallOpenError=Filen "%1" kunne ikke bnes. Kan ikke afinstalleres +UninstallUnsupportedVer=Afinstallations-logfilen "%1" er i et format der ikke genkendes af denne version af afinstallations-guiden. Afinstallationen afbrydes +UninstallUnknownEntry=Der er en ukendt post (%1) i afinstallerings-logfilen. +ConfirmUninstall=Er du sikker p at du vil fjerne %1 og alle tilhrende komponenter? +UninstallOnlyOnWin64=Denne installation kan kun afinstalleres p 64-bit Windows-versioner +OnlyAdminCanUninstall=Programmet kan kun afinstalleres af en bruger med administratorrettigheder. +UninstallStatusLabel=Vent venligst imens %1 afinstalleres fra computeren. +UninstalledAll=%1 er nu fjernet fra computeren. +UninstalledMost=%1 afinstallation er fuldfrt.%n%nNogle elementer kunne ikke fjernes. De kan fjernes manuelt. +UninstalledAndNeedsRestart=Computeren skal genstartes for at fuldfre afinstallation af %1.%n%nVil du genstarte nu? +UninstallDataCorrupted=Filen "%1" er beskadiget. Kan ikke afinstallere + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Fjern delt fil? +ConfirmDeleteSharedFile2=Systemet indikerer at flgende delte fil ikke lngere er i brug. Skal den/de delte fil(er) fjernes af guiden?%n%nHvis du er usikker s vlg Nej. Beholdes filen p maskinen, vil den ikke gre nogen skade, men hvis filen fjernes, selv om den stadig anvendes, bliver de programmer, der anvender filen, ustabile +SharedFileNameLabel=Filnavn: +SharedFileLocationLabel=Placering: +WizardUninstalling=Status for afinstallation +StatusUninstalling=Afinstallerer %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Installerer %1. +ShutdownBlockReasonUninstallingApp=Afinstallerer %1. + +[CustomMessages] +NameAndVersion=%1 version %2 +AdditionalIcons=Supplerende ikoner: +CreateDesktopIcon=Opret ikon p skrive&bordet +CreateQuickLaunchIcon=Opret &hurtigstart-ikon +ProgramOnTheWeb=%1 p internettet +UninstallProgram=Afinstaller (fjern) %1 +LaunchProgram=&Start %1 +AssocFileExtension=Sammen&kd %1 med filtypen %2 +AssocingFileExtension=Sammenkder %1 med filtypen %2... +AutoStartProgramGroupDescription=Start: +AutoStartProgram=Start automatisk %1 +AddonHostProgramNotFound=%1 blev ikke fundet i den valgte mappe.%n%nVil du alligevel fortstte? diff --git a/installer/innosetup/Languages/Dutch.isl b/installer/innosetup/Languages/Dutch.isl new file mode 100644 index 000000000..761528b2a --- /dev/null +++ b/installer/innosetup/Languages/Dutch.isl @@ -0,0 +1,359 @@ +; *** Inno Setup version 6.1.0+ Dutch messages *** +; +; This file is based on user-contributed translations by various authors +; +; Maintained by Martijn Laan (mlaan@jrsoftware.org) + +[LangOptions] +LanguageName=Nederlands +LanguageID=$0413 +LanguageCodePage=1252 + +[Messages] + +; *** Application titles +SetupAppTitle=Setup +SetupWindowTitle=Setup - %1 +UninstallAppTitle=Verwijderen +UninstallAppFullTitle=%1 verwijderen + +; *** Misc. common +InformationTitle=Informatie +ConfirmTitle=Bevestigen +ErrorTitle=Fout + +; *** SetupLdr messages +SetupLdrStartupMessage=Hiermee wordt %1 geïnstalleerd. Wilt u doorgaan? +LdrCannotCreateTemp=Kan geen tijdelijk bestand maken. Setup wordt afgesloten +LdrCannotExecTemp=Kan een bestand in de tijdelijke map niet uitvoeren. Setup wordt afgesloten + +; *** Startup error messages +LastErrorMessage=%1.%n%nFout %2: %3 +SetupFileMissing=Het bestand %1 ontbreekt in de installatiemap. Corrigeer dit probleem of gebruik een andere kopie van het programma. +SetupFileCorrupt=De installatiebestanden zijn beschadigd. Gebruik een andere kopie van het programma. +SetupFileCorruptOrWrongVer=De installatiebestanden zijn beschadigd, of zijn niet compatibel met deze versie van Setup. Corrigeer dit probleem of gebruik een andere kopie van het programma. +InvalidParameter=Er werd een ongeldige schakeloptie opgegeven op de opdrachtregel:%n%n%1 +SetupAlreadyRunning=Setup is al gestart. +WindowsVersionNotSupported=Dit programma ondersteunt de versie van Windows die u gebruikt niet. +WindowsServicePackRequired=Dit programma vereist %1 Service Pack %2 of hoger. +NotOnThisPlatform=Dit programma kan niet worden uitgevoerd onder %1. +OnlyOnThisPlatform=Dit programma moet worden uitgevoerd onder %1. +OnlyOnTheseArchitectures=Dit programma kan alleen geïnstalleerd worden onder versies van Windows ontworpen voor de volgende processor architecturen:%n%n%1 +WinVersionTooLowError=Dit programma vereist %1 versie %2 of hoger. +WinVersionTooHighError=Dit programma kan niet worden geïnstalleerd onder %1 versie %2 of hoger. +AdminPrivilegesRequired=U moet aangemeld zijn als een systeembeheerder om dit programma te kunnen installeren. +PowerUserPrivilegesRequired=U moet ingelogd zijn als systeembeheerder of als gebruiker met systeembeheerders rechten om dit programma te kunnen installeren. +SetupAppRunningError=Setup heeft vastgesteld dat %1 op dit moment actief is.%n%nSluit alle vensters hiervan, en klik daarna op OK om verder te gaan, of op Annuleren om Setup af te sluiten. +UninstallAppRunningError=Het verwijderprogramma heeft vastgesteld dat %1 op dit moment actief is.%n%nSluit alle vensters hiervan, en klik daarna op OK om verder te gaan, of op Annuleren om het verwijderen af te breken. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Selecteer installatie modus voor Setup +PrivilegesRequiredOverrideInstruction=Selecteer installatie modus +PrivilegesRequiredOverrideText1=%1 kan geïnstalleerd worden voor alle gebruikers (vereist aanmelding als een systeembeheerder), of voor u alleen. +PrivilegesRequiredOverrideText2=%1 kan geïnstalleerd worden voor u alleen, of voor alle gebruikers (vereist aanmelding als een systeembeheerder). +PrivilegesRequiredOverrideAllUsers=Installeer voor &alle gebruikers +PrivilegesRequiredOverrideAllUsersRecommended=Installeer voor &alle gebruikers (aanbevolen) +PrivilegesRequiredOverrideCurrentUser=Installeer voor &mij alleen +PrivilegesRequiredOverrideCurrentUserRecommended=Installeer voor &mij alleen (aanbevolen) + +; *** Misc. errors +ErrorCreatingDir=Setup kan de map "%1" niet maken +ErrorTooManyFilesInDir=Kan geen bestand maken in de map "%1" omdat deze te veel bestanden bevat + +; *** Setup common messages +ExitSetupTitle=Setup afsluiten +ExitSetupMessage=Setup is niet voltooid. Als u nu afsluit, wordt het programma niet geïnstalleerd.%n%nU kunt Setup later opnieuw uitvoeren om de installatie te voltooien.%n%nSetup afsluiten? +AboutSetupMenuItem=&Over Setup... +AboutSetupTitle=Over Setup +AboutSetupMessage=%1 versie %2%n%3%n%n%1-homepage:%n%4 +AboutSetupNote= +TranslatorNote=Dutch translation maintained by Martijn Laan (mlaan@jrsoftware.org) + +; *** Buttons +ButtonBack=< Vo&rige +ButtonNext=&Volgende > +ButtonInstall=&Installeren +ButtonOK=OK +ButtonCancel=Annuleren +ButtonYes=&Ja +ButtonYesToAll=Ja op &alles +ButtonNo=&Nee +ButtonNoToAll=N&ee op alles +ButtonFinish=&Voltooien +ButtonBrowse=&Bladeren... +ButtonWizardBrowse=B&laderen... +ButtonNewFolder=&Nieuwe map maken + +; *** "Select Language" dialog messages +SelectLanguageTitle=Selecteer taal voor Setup +SelectLanguageLabel=Selecteer de taal die Setup gebruikt tijdens de installatie. + +; *** Common wizard text +ClickNext=Klik op Volgende om verder te gaan of op Annuleren om Setup af te sluiten. +BeveledLabel= +BrowseDialogTitle=Map Selecteren +BrowseDialogLabel=Selecteer een map in onderstaande lijst en klik daarna op OK. +NewFolderName=Nieuwe map + +; *** "Welcome" wizard page +WelcomeLabel1=Welkom bij het installatieprogramma van [name]. +WelcomeLabel2=Hiermee wordt [name/ver] geïnstalleerd op deze computer.%n%nU wordt aanbevolen alle actieve programma's af te sluiten voordat u verder gaat. + +; *** "Password" wizard page +WizardPassword=Wachtwoord +PasswordLabel1=Deze installatie is beveiligd met een wachtwoord. +PasswordLabel3=Voer het wachtwoord in en klik op Volgende om verder te gaan. Wachtwoorden zijn hoofdlettergevoelig. +PasswordEditLabel=&Wachtwoord: +IncorrectPassword=Het ingevoerde wachtwoord is niet correct. Probeer het opnieuw. + +; *** "License Agreement" wizard page +WizardLicense=Licentieovereenkomst +LicenseLabel=Lees de volgende belangrijke informatie voordat u verder gaat. +LicenseLabel3=Lees de volgende licentieovereenkomst. Gebruik de schuifbalk of druk op de knop Page Down om de rest van de overeenkomst te zien. +LicenseAccepted=Ik &accepteer de licentieovereenkomst +LicenseNotAccepted=Ik accepteer de licentieovereenkomst &niet + +; *** "Information" wizard pages +WizardInfoBefore=Informatie +InfoBeforeLabel=Lees de volgende belangrijke informatie voordat u verder gaat. +InfoBeforeClickLabel=Klik op Volgende als u gereed bent om verder te gaan met Setup. +WizardInfoAfter=Informatie +InfoAfterLabel=Lees de volgende belangrijke informatie voordat u verder gaat. +InfoAfterClickLabel=Klik op Volgende als u gereed bent om verder te gaan met Setup. + +; *** "User Information" wizard page +WizardUserInfo=Gebruikersinformatie +UserInfoDesc=Vul hier uw informatie in. +UserInfoName=&Gebruikersnaam: +UserInfoOrg=&Organisatie: +UserInfoSerial=&Serienummer: +UserInfoNameRequired=U moet een naam invullen. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Kies de doelmap +SelectDirDesc=Waar moet [name] geïnstalleerd worden? +SelectDirLabel3=Setup zal [name] in de volgende map installeren. +SelectDirBrowseLabel=Klik op Volgende om door te gaan. Klik op Bladeren om een andere map te kiezen. +DiskSpaceGBLabel=Er is ten minste [gb] GB vrije schijfruimte vereist. +DiskSpaceMBLabel=Er is ten minste [mb] MB vrije schijfruimte vereist. +CannotInstallToNetworkDrive=Setup kan niet installeren naar een netwerkstation. +CannotInstallToUNCPath=Setup kan niet installeren naar een UNC-pad. +InvalidPath=U moet een volledig pad met stationsletter invoeren; bijvoorbeeld:%nC:\APP%n%nof een UNC-pad zoals:%n%n\\server\share +InvalidDrive=Het geselecteerde station bestaat niet. Kies een ander station. +DiskSpaceWarningTitle=Onvoldoende schijfruimte +DiskSpaceWarning=Setup vereist ten minste %1 kB vrije schijfruimte voor het installeren, maar het geselecteerde station heeft slechts %2 kB beschikbaar.%n%nWilt u toch doorgaan? +DirNameTooLong=De mapnaam of het pad is te lang. +InvalidDirName=De mapnaam is ongeldig. +BadDirName32=Mapnamen mogen geen van de volgende tekens bevatten:%n%n%1 +DirExistsTitle=Map bestaat al +DirExists=De map:%n%n%1%n%nbestaat al. Wilt u toch naar die map installeren? +DirDoesntExistTitle=Map bestaat niet +DirDoesntExist=De map:%n%n%1%n%nbestaat niet. Wilt u de map aanmaken? + +; *** "Select Components" wizard page +WizardSelectComponents=Selecteer componenten +SelectComponentsDesc=Welke componenten moeten geïnstalleerd worden? +SelectComponentsLabel2=Selecteer de componenten die u wilt installeren. Klik op Volgende als u klaar bent om verder te gaan. +FullInstallation=Volledige installatie +CompactInstallation=Compacte installatie +CustomInstallation=Aangepaste installatie +NoUninstallWarningTitle=Component bestaat +NoUninstallWarning=Setup heeft gedetecteerd dat de volgende componenten al geïnstalleerd zijn op uw computer:%n%n%1%n%nAls u de selectie van deze componenten ongedaan maakt, worden ze niet verwijderd.%n%nWilt u toch doorgaan? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=De huidige selectie vereist ten minste [gb] GB vrije schijfruimte. +ComponentsDiskSpaceMBLabel=De huidige selectie vereist ten minste [mb] MB vrije schijfruimte. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Selecteer extra taken +SelectTasksDesc=Welke extra taken moeten uitgevoerd worden? +SelectTasksLabel2=Selecteer de extra taken die u door Setup wilt laten uitvoeren bij het installeren van [name], en klik vervolgens op Volgende. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Selecteer menu Start map +SelectStartMenuFolderDesc=Waar moeten de snelkoppelingen van het programma geplaatst worden? +SelectStartMenuFolderLabel3=Setup plaatst de snelkoppelingen van het programma in de volgende menu Start map. +SelectStartMenuFolderBrowseLabel=Klik op Volgende om door te gaan. Klik op Bladeren om een andere map te kiezen. +MustEnterGroupName=U moet een mapnaam invoeren. +GroupNameTooLong=De mapnaam of het pad is te lang. +InvalidGroupName=De mapnaam is ongeldig. +BadGroupName=De mapnaam mag geen van de volgende tekens bevatten:%n%n%1 +NoProgramGroupCheck2=&Geen menu Start map maken + +; *** "Ready to Install" wizard page +WizardReady=Het voorbereiden van de installatie is gereed +ReadyLabel1=Setup is nu gereed om te beginnen met het installeren van [name] op deze computer. +ReadyLabel2a=Klik op Installeren om verder te gaan met installeren, of klik op Vorige als u instellingen wilt terugzien of veranderen. +ReadyLabel2b=Klik op Installeren om verder te gaan met installeren. +ReadyMemoUserInfo=Gebruikersinformatie: +ReadyMemoDir=Doelmap: +ReadyMemoType=Installatietype: +ReadyMemoComponents=Geselecteerde componenten: +ReadyMemoGroup=Menu Start map: +ReadyMemoTasks=Extra taken: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Bezig met het downloaden van extra bestanden... +ButtonStopDownload=&Stop download +StopDownload=Weet u zeker dat u de download wilt stoppen? +ErrorDownloadAborted=Download afgebroken +ErrorDownloadFailed=Download mislukt: %1 %2 +ErrorDownloadSizeFailed=Ophalen grootte mislukt: %1 %2 +ErrorFileHash1=Bestand hashing mislukt: %1 +ErrorFileHash2=Ongeldige bestandshash: %1 verwacht, %2 gevonden +ErrorProgress=Ongeldige voortgang: %1 van %2 +ErrorFileSize=Ongeldige bestandsgrootte: %1 verwacht, %2 gevonden + +; *** "Preparing to Install" wizard page +WizardPreparing=Bezig met het voorbereiden van de installatie +PreparingDesc=Setup is bezig met het voorbereiden van de installatie van [name]. +PreviousInstallNotCompleted=De installatie/verwijdering van een vorig programma is niet voltooid. U moet uw computer opnieuw opstarten om die installatie te voltooien.%n%nStart Setup nogmaals nadat uw computer opnieuw is opgestart om de installatie van [name] te voltooien. +CannotContinue=Setup kan niet doorgaan. Klik op annuleren om af te sluiten. +ApplicationsFound=De volgende programma's gebruiken bestanden die moeten worden bijgewerkt door Setup. U wordt aanbevolen Setup toe te staan om automatisch deze programma's af te sluiten. +ApplicationsFound2=De volgende programma's gebruiken bestanden die moeten worden bijgewerkt door Setup. U wordt aanbevolen Setup toe te staan om automatisch deze programma's af te sluiten. Nadat de installatie is voltooid zal Setup proberen de applicaties opnieuw op te starten. +CloseApplications=&Programma's automatisch afsluiten +DontCloseApplications=Programma's &niet afsluiten +ErrorCloseApplications=Setup kon niet alle programma's automatisch afsluiten. U wordt aanbevolen alle programma's die bestanden gebruiken die moeten worden bijgewerkt door Setup af te sluiten voordat u verder gaat. +PrepareToInstallNeedsRestart=Setup moet uw computer opnieuw opstarten. Start Setup nogmaals nadat uw computer opnieuw is opgestart om de installatie van [name] te voltooien.%n%nWilt u nu opnieuw opstarten? + +; *** "Installing" wizard page +WizardInstalling=Bezig met installeren +InstallingLabel=Setup installeert [name] op uw computer. Een ogenblik geduld... + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Setup heeft het installeren van [name] op deze computer voltooid. +FinishedLabelNoIcons=Setup heeft het installeren van [name] op deze computer voltooid. +FinishedLabel=Setup heeft het installeren van [name] op deze computer voltooid. U kunt het programma uitvoeren met de geïnstalleerde snelkoppelingen. +ClickFinish=Klik op Voltooien om Setup te beëindigen. +FinishedRestartLabel=Setup moet de computer opnieuw opstarten om de installatie van [name] te voltooien. Wilt u nu opnieuw opstarten? +FinishedRestartMessage=Setup moet uw computer opnieuw opstarten om de installatie van [name] te voltooien.%n%nWilt u nu opnieuw opstarten? +ShowReadmeCheck=Ja, ik wil het bestand Leesmij zien +YesRadio=&Ja, start de computer nu opnieuw op +NoRadio=&Nee, ik start de computer later opnieuw op +RunEntryExec=Start %1 +RunEntryShellExec=Bekijk %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Setup heeft de volgende diskette nodig +SelectDiskLabel2=Voer diskette %1 in en klik op OK.%n%nAls de bestanden op deze diskette in een andere map gevonden kunnen worden dan die hieronder wordt getoond, voer dan het juiste pad in of klik op Bladeren. +PathLabel=&Pad: +FileNotInDir2=Kan het bestand "%1" niet vinden in "%2". Voer de juiste diskette in of kies een andere map. +SelectDirectoryLabel=Geef de locatie van de volgende diskette. + +; *** Installation phase messages +SetupAborted=Setup is niet voltooid.%n%nCorrigeer het probleem en voer Setup opnieuw uit. +AbortRetryIgnoreSelectAction=Selecteer actie +AbortRetryIgnoreRetry=&Probeer opnieuw +AbortRetryIgnoreIgnore=&Negeer de fout en ga door +AbortRetryIgnoreCancel=Breek installatie af + +; *** Installation status messages +StatusClosingApplications=Programma's afsluiten... +StatusCreateDirs=Mappen maken... +StatusExtractFiles=Bestanden uitpakken... +StatusCreateIcons=Snelkoppelingen maken... +StatusCreateIniEntries=INI-gegevens instellen... +StatusCreateRegistryEntries=Registergegevens instellen... +StatusRegisterFiles=Bestanden registreren... +StatusSavingUninstall=Verwijderingsinformatie opslaan... +StatusRunProgram=Installatie voltooien... +StatusRestartingApplications=Programma's opnieuw starten... +StatusRollback=Veranderingen ongedaan maken... + +; *** Misc. errors +ErrorInternal2=Interne fout: %1 +ErrorFunctionFailedNoCode=%1 mislukt +ErrorFunctionFailed=%1 mislukt; code %2 +ErrorFunctionFailedWithMessage=%1 mislukt; code %2.%n%3 +ErrorExecutingProgram=Kan bestand niet uitvoeren:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Fout bij het openen van registersleutel:%n%1\%2 +ErrorRegCreateKey=Fout bij het maken van registersleutel:%n%1\%2 +ErrorRegWriteKey=Fout bij het schrijven naar registersleutel:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Fout bij het maken van een INI-instelling in bestand "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Sla dit bestand over (niet aanbevolen) +FileAbortRetryIgnoreIgnoreNotRecommended=&Negeer de fout en ga door (niet aanbevolen) +SourceIsCorrupted=Het bronbestand is beschadigd +SourceDoesntExist=Het bronbestand "%1" bestaat niet +ExistingFileReadOnly2=Het bestaande bestand kon niet vervangen worden omdat het een alleen-lezen markering heeft. +ExistingFileReadOnlyRetry=&Verwijder de alleen-lezen markering en probeer het opnieuw +ExistingFileReadOnlyKeepExisting=&Behoud het bestaande bestand +ErrorReadingExistingDest=Er is een fout opgetreden bij het lezen van het bestaande bestand: +FileExistsSelectAction=Selecteer actie +FileExists2=Het bestand bestaat al. +FileExistsOverwriteExisting=&Overschrijf het bestaande bestand +FileExistsKeepExisting=&Behoud het bestaande bestand +FileExistsOverwriteOrKeepAll=&Dit voor de volgende conflicten uitvoeren +ExistingFileNewerSelectAction=Selecteer actie +ExistingFileNewer2=Het bestaande bestand is nieuwer dan het bestand dat Setup probeert te installeren. +ExistingFileNewerOverwriteExisting=&Overschrijf het bestaande bestand +ExistingFileNewerKeepExisting=&Behoud het bestaande bestand (aanbevolen) +ExistingFileNewerOverwriteOrKeepAll=&Dit voor de volgende conflicten uitvoeren +ErrorChangingAttr=Er is een fout opgetreden bij het wijzigen van de kenmerken van het bestaande bestand: +ErrorCreatingTemp=Er is een fout opgetreden bij het maken van een bestand in de doelmap: +ErrorReadingSource=Er is een fout opgetreden bij het lezen van het bronbestand: +ErrorCopying=Er is een fout opgetreden bij het kopiëren van een bestand: +ErrorReplacingExistingFile=Er is een fout opgetreden bij het vervangen van het bestaande bestand: +ErrorRestartReplace=Vervangen na opnieuw starten is mislukt: +ErrorRenamingTemp=Er is een fout opgetreden bij het hernoemen van een bestand in de doelmap: +ErrorRegisterServer=Kan de DLL/OCX niet registreren: %1 +ErrorRegSvr32Failed=RegSvr32 mislukt met afsluitcode %1 +ErrorRegisterTypeLib=Kan de type library niet registreren: %1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Alle gebruikers +UninstallDisplayNameMarkCurrentUser=Huidige gebruiker + +; *** Post-installation errors +ErrorOpeningReadme=Er is een fout opgetreden bij het openen van het Leesmij-bestand. +ErrorRestartingComputer=Setup kan de computer niet opnieuw opstarten. Doe dit handmatig. + +; *** Uninstaller messages +UninstallNotFound=Bestand "%1" bestaat niet. Kan het programma niet verwijderen. +UninstallUnsupportedVer=Het installatie-logbestand "%1" heeft een formaat dat niet herkend wordt door deze versie van het verwijderprogramma. Kan het programma niet verwijderen +UninstallUnknownEntry=Er is een onbekend gegeven (%1) aangetroffen in het installatie-logbestand +ConfirmUninstall=Weet u zeker dat u %1 en alle bijbehorende componenten wilt verwijderen? +UninstallOnlyOnWin64=Deze installatie kan alleen worden verwijderd onder 64-bit Windows. +OnlyAdminCanUninstall=Deze installatie kan alleen worden verwijderd door een gebruiker met administratieve rechten. +UninstallStatusLabel=%1 wordt verwijderd van uw computer. Een ogenblik geduld. +UninstallOpenError=Bestand "%1" kon niet worden geopend. Kan het verwijderen niet voltooien. +UninstalledAll=%1 is met succes van deze computer verwijderd. +UninstalledMost=Het verwijderen van %1 is voltooid.%n%nEnkele elementen konden niet verwijderd worden. Deze kunnen handmatig verwijderd worden. +UninstalledAndNeedsRestart=Om het verwijderen van %1 te voltooien, moet uw computer opnieuw worden opgestart.%n%nWilt u nu opnieuw opstarten? +UninstallDataCorrupted="%1" bestand is beschadigd. Kan verwijderen niet voltooien + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Gedeeld bestand verwijderen? +ConfirmDeleteSharedFile2=Het systeem geeft aan dat het volgende gedeelde bestand niet langer gebruikt wordt door enig programma. Wilt u dat dit gedeelde bestand verwijderd wordt?%n%nAls dit bestand toch nog gebruikt wordt door een programma en het verwijderd wordt, werkt dat programma misschien niet meer correct. Als u het niet zeker weet, kies dan Nee. Bewaren van het bestand op dit systeem is niet schadelijk. +SharedFileNameLabel=Bestandsnaam: +SharedFileLocationLabel=Locatie: +WizardUninstalling=Verwijderingsstatus +StatusUninstalling=Verwijderen van %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Installeren van %1. +ShutdownBlockReasonUninstallingApp=Verwijderen van %1. + +[CustomMessages] + +NameAndVersion=%1 versie %2 +AdditionalIcons=Extra snelkoppelingen: +CreateDesktopIcon=Maak een snelkoppeling op het &bureaublad +CreateQuickLaunchIcon=Maak een snelkoppeling op de &Snel starten werkbalk +ProgramOnTheWeb=%1 op het Web +UninstallProgram=Verwijder %1 +LaunchProgram=&Start %1 +AssocFileExtension=&Koppel %1 aan de %2 bestandsextensie +AssocingFileExtension=Bezig met koppelen van %1 aan de %2 bestandsextensie... +AutoStartProgramGroupDescription=Opstarten: +AutoStartProgram=%1 automatisch starten +AddonHostProgramNotFound=%1 kon niet worden gevonden in de geselecteerde map.%n%nWilt u toch doorgaan? diff --git a/installer/innosetup/Languages/EnglishBritish.isl b/installer/innosetup/Languages/EnglishBritish.isl index 309c560ae..60a941064 100644 --- a/installer/innosetup/Languages/EnglishBritish.isl +++ b/installer/innosetup/Languages/EnglishBritish.isl @@ -1,6 +1,7 @@ -; *** Inno Setup version 5.5.3+ English (British) messages *** +; *** Inno Setup version 6.1.0+ English (British) messages *** ; ; Translated by Boris Kotov +; Translation updated by Andrew Truckle [LangOptions] ; The following three entries are very important. Be sure to read and @@ -49,7 +50,6 @@ WindowsServicePackRequired=This program requires %1 Service Pack %2 or later. NotOnThisPlatform=This program will not run on %1. OnlyOnThisPlatform=This program must be run on %1. OnlyOnTheseArchitectures=This program can only be installed on versions of Windows designed for the following processor architectures:%n%n%1 -MissingWOW64APIs=The version of Windows you are running does not include functionality required by Setup to perform a 64-bit installation. To correct this problem, please install Service Pack %1. WinVersionTooLowError=This program requires %1 version %2 or later. WinVersionTooHighError=This program cannot be installed on %1 version %2 or later. AdminPrivilegesRequired=You must be logged in as an administrator when installing this program. @@ -57,6 +57,16 @@ PowerUserPrivilegesRequired=You must be logged in as an administrator or as a me SetupAppRunningError=Setup has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit. UninstallAppRunningError=Uninstall has detected that %1 is currently running.%n%nPlease close all instances of it now, then click OK to continue, or Cancel to exit. +; *** Startup questions +PrivilegesRequiredOverrideTitle=Select Setup Install Mode +PrivilegesRequiredOverrideInstruction=Select install mode +PrivilegesRequiredOverrideText1=%1 can be installed for all users (requires administrative privileges), or for you only. +PrivilegesRequiredOverrideText2=%1 can be installed for you only, or for all users (requires administrative privileges). +PrivilegesRequiredOverrideAllUsers=Install for &all users +PrivilegesRequiredOverrideAllUsersRecommended=Install for &all users (recommended) +PrivilegesRequiredOverrideCurrentUser=Install for &me only +PrivilegesRequiredOverrideCurrentUserRecommended=Install for &me only (recommended) + ; *** Misc. errors ErrorCreatingDir=Setup was unable to create the directory "%1" ErrorTooManyFilesInDir=Unable to create a file in the directory "%1" because it contains too many files @@ -135,6 +145,7 @@ WizardSelectDir=Select Destination Location SelectDirDesc=Where should [name] be installed? SelectDirLabel3=Setup will install [name] into the following folder. SelectDirBrowseLabel=To continue, click Next. If you would like to select a different folder, click Browse. +DiskSpaceGBLabel=At least [gb] GB of free disk space is required. DiskSpaceMBLabel=At least [mb] MB of free disk space is required. CannotInstallToNetworkDrive=Setup cannot install to a network drive. CannotInstallToUNCPath=Setup cannot install to a UNC path. @@ -162,6 +173,7 @@ NoUninstallWarningTitle=Components Exist NoUninstallWarning=Setup has detected that the following components are already installed on your computer:%n%n%1%n%nDeselecting these components will not uninstall them.%n%nWould you like to continue anyway? ComponentSize1=%1 KB ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Current selection requires at least [gb] GB of disk space. ComponentsDiskSpaceMBLabel=Current selection requires at least [mb] MB of disk space. ; *** "Select Additional Tasks" wizard page @@ -192,6 +204,18 @@ ReadyMemoComponents=Selected components: ReadyMemoGroup=Start Menu folder: ReadyMemoTasks=Additional tasks: +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Downloading additional files... +ButtonStopDownload=&Stop download +StopDownload=Are you sure you want to stop the download? +ErrorDownloadAborted=Download aborted +ErrorDownloadFailed=Download failed: %1 %2 +ErrorDownloadSizeFailed=Getting size failed: %1 %2 +ErrorFileHash1=File hash failed: %1 +ErrorFileHash2=Invalid file hash: expected %1, found %2 +ErrorProgress=Invalid progress: %1 of %2 +ErrorFileSize=Invalid file size: expected %1, found %2 + ; *** "Preparing to Install" wizard page WizardPreparing=Preparing to Install PreparingDesc=Setup is preparing to install [name] on your computer. @@ -202,6 +226,7 @@ ApplicationsFound2=The following applications are using files that need to be up CloseApplications=&Automatically close the applications DontCloseApplications=&Do not close the applications ErrorCloseApplications=Setup was unable to automatically close all applications. It is recommended that you close all applications using files that need to be updated by Setup before continuing. +PrepareToInstallNeedsRestart=Setup must restart your computer. After restarting your computer, run Setup again to complete the installation of [name].%n%nWould you like to restart now? ; *** "Installing" wizard page WizardInstalling=Installing @@ -231,7 +256,10 @@ SelectDirectoryLabel=Please specify the location of the next disk. ; *** Installation phase messages SetupAborted=Setup was not completed.%n%nPlease correct the problem and run Setup again. -EntryAbortRetryIgnore=Click Retry to try again, Ignore to proceed anyway, or Abort to cancel installation. +AbortRetryIgnoreSelectAction=Select action +AbortRetryIgnoreRetry=&Try again +AbortRetryIgnoreIgnore=&Ignore the error and continue +AbortRetryIgnoreCancel=Cancel installation ; *** Installation status messages StatusClosingApplications=Closing applications... @@ -262,14 +290,24 @@ ErrorRegWriteKey=Error writing to registry key:%n%1\%2 ErrorIniEntry=Error creating INI entry in file "%1". ; *** File copying errors -FileAbortRetryIgnore=Click Retry to try again, Ignore to skip this file (not recommended), or Abort to cancel installation. -FileAbortRetryIgnore2=Click Retry to try again, Ignore to proceed anyway (not recommended), or Abort to cancel installation. +FileAbortRetryIgnoreSkipNotRecommended=&Skip this file (not recommended) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignore the error and continue (not recommended) SourceIsCorrupted=The source file is corrupted SourceDoesntExist=The source file "%1" does not exist -ExistingFileReadOnly=The existing file is marked as read-only.%n%nClick Retry to remove the read-only attribute and try again, Ignore to skip this file, or Abort to cancel installation. +ExistingFileReadOnly2=The existing file could not be replaced because it is marked read-only. +ExistingFileReadOnlyRetry=&Remove the read-only attribute and try again +ExistingFileReadOnlyKeepExisting=&Keep the existing file ErrorReadingExistingDest=An error occurred while trying to read the existing file: -FileExists=The file already exists.%n%nWould you like Setup to overwrite it? -ExistingFileNewer=The existing file is newer than the one Setup is trying to install. It is recommended that you keep the existing file.%n%nDo you want to keep the existing file? +FileExistsSelectAction=Select action +FileExists2=The file already exists. +FileExistsOverwriteExisting=&Overwrite the existing file +FileExistsKeepExisting=&Keep the existing file +FileExistsOverwriteOrKeepAll=&Do this for the next conflicts +ExistingFileNewerSelectAction=Select action +ExistingFileNewer2=The existing file is newer than the one Setup is trying to install. +ExistingFileNewerOverwriteExisting=&Overwrite the existing file +ExistingFileNewerKeepExisting=&Keep the existing file (recommended) +ExistingFileNewerOverwriteOrKeepAll=&Do this for the next conflicts ErrorChangingAttr=An error occurred while trying to change the attributes of the existing file: ErrorCreatingTemp=An error occurred while trying to create a file in the destination directory: ErrorReadingSource=An error occurred while trying to read the source file: @@ -281,6 +319,16 @@ ErrorRegisterServer=Unable to register the DLL/OCX: %1 ErrorRegSvr32Failed=RegSvr32 failed with exit code %1 ErrorRegisterTypeLib=Unable to register the type library: %1 +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=All users +UninstallDisplayNameMarkCurrentUser=Current user + ; *** Post-installation errors ErrorOpeningReadme=An error occurred while trying to open the README file. ErrorRestartingComputer=Setup was unable to restart the computer. Please do this manually. diff --git a/installer/innosetup/Languages/Esperanto.isl b/installer/innosetup/Languages/Esperanto.isl index 5896c824c..ec0c1c4e8 100644 --- a/installer/innosetup/Languages/Esperanto.isl +++ b/installer/innosetup/Languages/Esperanto.isl @@ -1,12 +1,14 @@ -; *** Inno Setup version 5.5.3+ Esperanto messages *** -; -; Author: Alexander Gritchin (E-mail - alexgrimo@mail.ru) +; Inno Setup version 6.1.0+ Esperanto messages *** ; -; Au`toro: Alexander Gritc`in (E-mail - alexgrimo@mail.ru) -; Versio del traduko - 15.06.08 +; Aŭtoro: Alexander Gritĉin +; Retpoŝto: alexgrimo@mail.ru +; Traduko: 15.06.2008 ; -; +; Aŭtoro: Wolfgang Pohl +; Retpoŝto: software@interpohl.net) +; Traduko: 15.04.2021 ; + ; Note: When translating this text, do not add periods (.) to the end of ; messages that didn't have them already, because on those messages Inno ; Setup adds the periods automatically (appending a period would result in @@ -16,8 +18,8 @@ ; The following three entries are very important. Be sure to read and ; understand the '[LangOptions] section' topic in the help file. LanguageName=Esperanto -LanguageID=$0 -LanguageCodePage=0 +LanguageID=$1000 +LanguageCodePage=28593 ; If the language you are translating to requires special font faces or ; sizes, uncomment any of the following entries and change them accordingly. ;DialogFontName= @@ -29,15 +31,13 @@ LanguageCodePage=0 ;CopyrightFontName=Arial ;CopyrightFontSize=8 - - [Messages] ; *** Application titles SetupAppTitle=Instalado SetupWindowTitle=Instalado de - %1 UninstallAppTitle=Forigado -UninstallAppFullTitle=Forigado de %1 +UninstallAppFullTitle=Forigado de %1 ; *** Misc. common InformationTitle=Informacio @@ -45,53 +45,63 @@ ConfirmTitle=Konfirmado ErrorTitle=Eraro ; *** SetupLdr messages -SetupLdrStartupMessage=Nun estos instalado de %1. C`u vi volas kontinui? -LdrCannotCreateTemp=Nepoveble estas krei tempan dosieron. La Majstro estas s`topita -LdrCannotExecTemp=Nepoveble estas plenumi la dosieron en tempa dosierujo. La Majstro estas s`topita +SetupLdrStartupMessage=Nun estos instalado de %1. Ĉu vi volas kontinui? +LdrCannotCreateTemp=Nepoveble estas krei tempan dosieron. La Majstro estas ŝtopita +LdrCannotExecTemp=Nepoveble estas plenumi la dosieron en tempa dosierujo. La Majstro estas ŝtopita +HelpTextNote= ; *** Startup error messages LastErrorMessage=%1.%n%nEraro %2: %3 -SetupFileMissing=La dosiero %1 estas preterpasita el instala dosierujo.Bonvolu korekti problemon au` ricevu novan kopion de programo. +SetupFileMissing=La dosiero %1 estas preterpasita el instala dosierujo.Bonvolu korekti problemon aŭ ricevu novan kopion de programo. SetupFileCorrupt=Instalaj dosieroj estas kriplitaj. Bonvolu ricevu novan kopion de programo. -SetupFileCorruptOrWrongVer=Instalaj dosieroj estas kriplitaj, au` ne komparablaj kun tia versio del Majstro. Bonvolu korekti problemon au` ricevu novan kopion de programo. -InvalidParameter=Malg`usta parametro estis en komandlinio:%n%n%1 +SetupFileCorruptOrWrongVer=Instalaj dosieroj estas kriplitaj, aŭ ne komparablaj kun tia versio del Majstro. Bonvolu korekti problemon aŭ ricevu novan kopion de programo. +InvalidParameter=Malĝusta parametro estis en komandlinio:%n%n%1 SetupAlreadyRunning=La Majstro jam funkcias. -WindowsVersionNotSupported=C`i tia programo ne povas subteni la version de Vindoso en via komputilo. -WindowsServicePackRequired=Por c`i tia programo bezonas %1 Service Pack %2 au` pli olda. -NotOnThisPlatform=C`i tia programo ne funkcios en %1. -OnlyOnThisPlatform=C`i tia programo devas funkcii en %1. -OnlyOnTheseArchitectures=C`i tia programo nur povas esti instalita en version de Vindoso por sekvaj procesoraj arkitekturoj:%n%n%1 -MissingWOW64APIs=La versio de Vindoso kian vi lanc`is, ne havas posedon bezonatan por ke Majstro plenumis 64-bit instaladon. Por korekti tian problemon bonvolu instali Service Pack %1. -WinVersionTooLowError=Por c`i tia programo bezonas %1 version %2 au` pli olda. -WinVersionTooHighError=C`i tia programo ne povas esti instalita en %1 versio %2 au` pli olda. -AdminPrivilegesRequired=Vi devas eniri kiel administranto kiam instalas c`i tian programon. -PowerUserPrivilegesRequired=Vi devas eniri kiel administranto au` kiel membro de grupo de Posedaj Uzantoj kiam instalas c`i tia programo. -SetupAppRunningError=La Majstro difinis ke %1 nun funkcias.%n%nBonvolu s`topi g`in, kaj poste kliku Jes por kontinui, au` S`topi por eliri. -UninstallAppRunningError=Forigados difinis ke %1 nun funkcias.%n%nBonvolu s`topi g`in, kaj poste kliku Jes por kontinui, au` S`topi por eliri. +WindowsVersionNotSupported=Ĉi tia programo ne povas subteni la version de Vindoso en via komputilo. +WindowsServicePackRequired=Por ĉi tia programo bezonas %1 Service Pack %2 aŭ pli olda. +NotOnThisPlatform=Ĉi tia programo ne funkcios en %1. +OnlyOnThisPlatform=Ĉi tia programo devas funkcii en %1. +OnlyOnTheseArchitectures=Ĉi tia programo nur povas esti instalita en version de Vindoso por sekvaj procesoraj arkitekturoj:%n%n%1 +WinVersionTooLowError=Por ĉi tia programo bezonas %1 version %2 aŭ pli olda. +WinVersionTooHighError=Ĉi tia programo ne povas esti instalita en %1 versio %2 aŭ pli olda. +AdminPrivilegesRequired=Vi devas eniri kiel administranto kiam instalas ĉi tian programon. +PowerUserPrivilegesRequired=Vi devas eniri kiel administranto aŭ kiel membro de grupo de Posedaj Uzantoj kiam instalas ĉi tia programo. +SetupAppRunningError=La Majstro difinis ke %1 nun funkcias.%n%nBonvolu ŝtopi ĝin, kaj poste kliku Jes por kontinui, aŭ Ŝtopi por eliri. +UninstallAppRunningError=Forigados difinis ke %1 nun funkcias.%n%nBonvolu ŝtopi ĝin, kaj poste kliku Jes por kontinui, aŭ Ŝtopi por eliri. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Elektu Instala Reĝimo +PrivilegesRequiredOverrideInstruction=Elektu instala reĝimo +PrivilegesRequiredOverrideText1=%1 povas esti instalita por ĉiuj uzantoj (postulas administrajn privilegiojn), aŭ nur por vi. +PrivilegesRequiredOverrideText2=%1 povas esti instalita nur por vi aŭ por ĉiuj uzantoj (postulas administrajn privilegiojn). +PrivilegesRequiredOverrideAllUsers=Instali por ĉiuj &uzantoj +PrivilegesRequiredOverrideAllUsersRecommended=Instali por ĉiuj &uzantoj (rekomendita) +PrivilegesRequiredOverrideCurrentUser=Instali nur por &mi +PrivilegesRequiredOverrideCurrentUserRecommended=Instali nur por &mi (rekomendita) ; *** Misc. errors ErrorCreatingDir=La Majstro ne povas krei dosierujon "%1" -ErrorTooManyFilesInDir=Estas nepoveble krei dosieron en dosierujo "%1" pro tio ke g`i havas tro multe da dosierojn +ErrorTooManyFilesInDir=Estas nepoveble krei dosieron en dosierujo "%1" pro tio ke ĝi havas tro multe da dosierojn ; *** Setup common messages -ExitSetupTitle=S`topo Majstron -ExitSetupMessage=La instalado ne estas plena. Se vi eliros nun, la programo ne estos instalita.%n%nPor vi bezonas s`alti Majstron denove en alia tempo por plenumi instaladon.%n%nC`u fini la Majstron? +ExitSetupTitle=Ŝtopo Majstron +ExitSetupMessage=La instalado ne estas plena. Se vi eliros nun, la programo ne estos instalita.%n%nPor vi bezonas ŝalti Majstron denove en alia tempo por plenumi instaladon.%n%nĈu fini la Majstron? AboutSetupMenuItem=&Pri instalo... AboutSetupTitle=Pri instalo -AboutSetupMessage=%1 version %2%n%3%n%n%1 hejma pag`o:%n%4 +AboutSetupMessage=%1 version %2%n%3%n%n%1 hejma paĝo:%n%4 AboutSetupNote= TranslatorNote= ; *** Buttons ButtonBack=< &Reen -ButtonNext=&Antau`en > +ButtonNext=&Antaŭen > ButtonInstall=&Instali ButtonOK=Jes -ButtonCancel=S`topi +ButtonCancel=Ŝtopi ButtonYes=&Jes -ButtonYesToAll=Jes por &c`iaj +ButtonYesToAll=Jes por &ĉiaj ButtonNo=&Ne -ButtonNoToAll=Ne por c`iaj +ButtonNoToAll=Ne por ĉiaj ButtonFinish=&Fino ButtonBrowse=&Elekto... ButtonWizardBrowse=Elekto... @@ -102,40 +112,40 @@ SelectLanguageTitle=Elektu la lingvon SelectLanguageLabel=Elektu la lingvon por uzo dum instalado: ; *** Common wizard text -ClickNext=Kliku Antau`en por kontinui, au` S`topi por eliri Instaladon. +ClickNext=Kliku Antaŭen por kontinui, aŭ Ŝtopi por eliri Instaladon. BeveledLabel= BrowseDialogTitle=Elekto de dosierujo BrowseDialogLabel=Elektu la dosierujon en listo malalte, kaj kliku Jes. NewFolderName=Nova dosierujo ; *** "Welcome" wizard page -WelcomeLabel1=Bonvenon al Majstro de instalado de [name] -WelcomeLabel2=Nun komencos instalado de [name/ver] en via komputilo.%n%nEstas rekomendite ke vi s`topu c`iajn viajn programojn antau` komenco. +WelcomeLabel1=Bonvenon al Majstro de instalado de [name] +WelcomeLabel2=Nun komencos instalado de [name/ver] en via komputilo.%n%nEstas rekomendite ke vi ŝtopu ĉiajn viajn programojn antaŭ komenco. ; *** "Password" wizard page WizardPassword=Pasvorto -PasswordLabel1=C`i tia instalado postulas pasvorton. -PasswordLabel3=Bonvolu tajpi pasvorton kaj poste kliku Antau`en por kontinui. La pasvortoj estas tajp sentemaj. +PasswordLabel1=Ĉi tia instalado postulas pasvorton. +PasswordLabel3=Bonvolu tajpi pasvorton kaj poste kliku Antaŭen por kontinui. La pasvortoj estas tajp sentemaj. PasswordEditLabel=&Pasvorto: -IncorrectPassword=La pasvorto, kian vi tajpis estas malg`usta. Bonvolu provi denove. +IncorrectPassword=La pasvorto, kian vi tajpis estas malĝusta. Bonvolu provi denove. ; *** "License Agreement" wizard page WizardLicense=Licenza konvenio -LicenseLabel=Bonvolu legi sekvan gravan informacion antau` komenci. -LicenseLabel3=Bonvolu legi sekvan Licenzan Konvenion. Vi devas akcepti dotaj`oj de tia konvenio antau` ke kontinui instaladon. +LicenseLabel=Bonvolu legi sekvan gravan informacion antaŭ komenci. +LicenseLabel3=Bonvolu legi sekvan Licenzan Konvenion. Vi devas akcepti dotaĵoj de tia konvenio antaŭ ke kontinui instaladon. LicenseAccepted=Mi akceptas konvenion LicenseNotAccepted=Mi ne akceptas konvenion ; *** "Information" wizard pages WizardInfoBefore=Informacio -InfoBeforeLabel=Bonvolu legi sekvan gravan informacion antau` komenci. -InfoBeforeClickLabel=Kiam vi estas preta por kontinui per instalo, kliku Antau`en. +InfoBeforeLabel=Bonvolu legi sekvan gravan informacion antaŭ komenci. +InfoBeforeClickLabel=Kiam vi estas preta por kontinui per instalo, kliku Antaŭen. WizardInfoAfter=Informacio -InfoAfterLabel=Bonvolu legi sekvan gravan informacion antau` komenci. -InfoAfterClickLabel=Kiam vi estas preta por kontinui per instalo, kliku Antau`en. +InfoAfterLabel=Bonvolu legi sekvan gravan informacion antaŭ komenci. +InfoAfterClickLabel=Kiam vi estas preta por kontinui per instalo, kliku Antaŭen. ; *** "User Information" wizard page -WizardUserInfo= Informacio pri uzanto +WizardUserInfo=Informacio pri uzanto UserInfoDesc=Bonvolu skribi vian informacion. UserInfoName=Nomo de uzanto: UserInfoOrg=&Organizacio: @@ -146,56 +156,58 @@ UserInfoNameRequired=Vi devas skribi nomon de uzanto. WizardSelectDir=Elektu Destinan Locon SelectDirDesc=Kie devos [name] esti instalita? SelectDirLabel3=La Majstro instalos [name] en sekvan dosierujon. -SelectDirBrowseLabel=Por kontinui, kliku Antau`en. Se vi volas elekti diversan dosierujon, kliku Elekto. -DiskSpaceMBLabel=Almenau` [mb] MB de neta diska spaco bezonas. +SelectDirBrowseLabel=Por kontinui, kliku Antaŭen. Se vi volas elekti diversan dosierujon, kliku Elekto. +DiskSpaceGBLabel=Almenaŭ [gb] GB de neta diska spaco bezonas. +DiskSpaceMBLabel=Almenaŭ [mb] MB de neta diska spaco bezonas. CannotInstallToNetworkDrive=Majstro ne povas instali lokan diskon. -CannotInstallToUNCPath=Majstro ne povas instali lau` UNC vojo. -InvalidPath=Vi devas skribi plenan vojon de diska litero; por ekzamplo:%n%nC:\APP%n%sed ne UNC vojo lau` formo:%n%n\\server\share -InvalidDrive=Disko au` UNC kian vi elektis ne ekzistas au` ne estas difinita. Bonvolu elekti denove. +CannotInstallToUNCPath=Majstro ne povas instali laŭ UNC vojo. +InvalidPath=Vi devas skribi plenan vojon de diska litero; por ekzamplo:%n%nC:\APP%n%sed ne UNC vojo laŭ formo:%n%n\\server\share +InvalidDrive=Disko aŭ UNC kian vi elektis ne ekzistas aŭ ne estas difinita. Bonvolu elekti denove. DiskSpaceWarningTitle=Mankas Diskan Spacon -DiskSpaceWarning=Por instalo bezonas almenau` %1 KB de neta spaco por instalado, sed electita disko havas nur %2 KB.%n%nC`u vi volas kontinui per c`iokaze? -DirNameTooLong=La nomo de dosierujo au` vojo estas tro longa. -InvalidDirName=La nomo de dosierujo estas malg`usta. +DiskSpaceWarning=Por instalo bezonas almenaŭ %1 KB de neta spaco por instalado, sed electita disko havas nur %2 KB.%n%nĈu vi volas kontinui per ĉiokaze? +DirNameTooLong=La nomo de dosierujo aŭ vojo estas tro longa. +InvalidDirName=La nomo de dosierujo estas malĝusta. BadDirName32=La nomoj de dosierujoj ne povas havi de sekvaj karakteroj:%n%n%1 DirExistsTitle=Dosierujo ekzistas -DirExists=La dosierujo:%n%n%1%n%njam ekzistas. C`u vi volas instali en g`i c`iokaze? +DirExists=La dosierujo:%n%n%1%n%njam ekzistas. Ĉu vi volas instali en ĝi ĉiokaze? DirDoesntExistTitle=La dosierujo ne ekzistas -DirDoesntExist=La dosierujo:%n%n%1%n%nne ekzistas. C`u vi volas por ke tia dosierujo estos farita? +DirDoesntExist=La dosierujo:%n%n%1%n%nne ekzistas. Ĉu vi volas por ke tia dosierujo estos farita? ; *** "Select Components" wizard page WizardSelectComponents=Elektu komponentoj SelectComponentsDesc=Kiaj komponentoj devas esti instalitaj? -SelectComponentsLabel2=Elektu komponentoj kiaj vi volas instali; forigu la komponentojn kiaj vi ne volas instali. Kliku Antau`en kiam vi estas preta por kontinui. +SelectComponentsLabel2=Elektu komponentoj kiaj vi volas instali; forigu la komponentojn kiaj vi ne volas instali. Kliku Antaŭen kiam vi estas preta por kontinui. FullInstallation=Tuta instalado ; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) CompactInstallation=Kompakta instalado CustomInstallation=Kutima instalado NoUninstallWarningTitle=Komponentoj ekzistas -NoUninstallWarning=La Majstro difinis ke sekvaj komponentoj jam estas instalitaj en via komputilo:%n%n%1%n%nNuligo de elekto de tiaj komponentoj ne forigos g`in.%n%nC`u vi volas kontinui c`iokaze? +NoUninstallWarning=La Majstro difinis ke sekvaj komponentoj jam estas instalitaj en via komputilo:%n%n%1%n%nNuligo de elekto de tiaj komponentoj ne forigos ĝin.%n%nĈu vi volas kontinui ĉiokaze? ComponentSize1=%1 KB ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel=Nuna elekto bezonas almenau` [mb] MB de diska spaco. +ComponentsDiskSpaceGBLabel=Nuna elekto bezonas almenaŭ [gb] GB de diska spaco. +ComponentsDiskSpaceMBLabel=Nuna elekto bezonas almenaŭ [mb] MB de diska spaco. ; *** "Select Additional Tasks" wizard page WizardSelectTasks=Elektu aldonaj taskoj SelectTasksDesc=Kiaj aldonaj taskoj devos esti montrotaj? -SelectTasksLabel2=Elektu aldonaj taskoj kiaj bezonas por ke Majstro montros dum instalado [name], kaj poste kliku Antau`en. +SelectTasksLabel2=Elektu aldonaj taskoj kiaj bezonas por ke Majstro montros dum instalado [name], kaj poste kliku Antaŭen. ; *** "Select Start Menu Folder" wizard page WizardSelectProgramGroup=Elektu dosierujon de starta menuo SelectStartMenuFolderDesc=Kie Majstro devas krei tujklavon de programo? SelectStartMenuFolderLabel3=La Majstro kreos tujklavojn de programo en sekva dosierujo de starta menuo. -SelectStartMenuFolderBrowseLabel=Por kontinui, kliku Antau`en. Se vi volas elekti alian dosierujon, kliku Elekto. -MustEnterGroupName=Vi devas skribi la nomo de dosierujo. -GroupNameTooLong=La nomo de dosierujo au` vojo estas tro longa. -InvalidGroupName=La nomo de dosierujo estas malg`usta. +SelectStartMenuFolderBrowseLabel=Por kontinui, kliku Antaŭen. Se vi volas elekti alian dosierujon, kliku Elekto. +MustEnterGroupName=Vi devas skribi la nomo de dosierujo. +GroupNameTooLong=La nomo de dosierujo aŭ vojo estas tro longa. +InvalidGroupName=La nomo de dosierujo estas malĝusta. BadGroupName=La nomoj de dosierujoj ne povas havi de sekvaj karakteroj:%n%n%1 NoProgramGroupCheck2=Ne krei dosierujon de starta menuo ; *** "Ready to Install" wizard page WizardReady=Preparado por Instalo -ReadyLabel1=Nun c`io estas preparita por komenci instaladon [name] en via komputilo. -ReadyLabel2a=Kliku Instali por kontinui instaladon, au`kliku Reen se vi volas rigardi au` s`ang`i ajnajn statojn. +ReadyLabel1=Nun ĉio estas preparita por komenci instaladon [name] en via komputilo. +ReadyLabel2a=Kliku Instali por kontinui instaladon, aŭkliku Reen se vi volas rigardi aŭ ŝanĝi ajnajn statojn. ReadyLabel2b=Kliku Instali por kontinui instaladon. ReadyMemoUserInfo=Informacio de uzanto: ReadyMemoDir=Destina loko: @@ -204,49 +216,65 @@ ReadyMemoComponents=Elektitaj komponentoj: ReadyMemoGroup=La dosierujo de starta menuo: ReadyMemoTasks=Aldonaj taskoj: +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Elŝuti pliajn dosierojn... +ButtonStopDownload=&Stopu elŝuti +StopDownload=Ĉu vi certas, ke vi volas stopi la elŝuton? +ErrorDownloadAborted=Elŝuto ĉesigita +ErrorDownloadFailed=Elŝuto malsukcesis: %1 %2 +ErrorDownloadSizeFailed=Akiri grandecon malsukcesis: %1 %2 +ErrorFileHash1=Dosiero haŝkodo malsukcesis: %1 +ErrorFileHash2=Nevalida dosiero haŝkodo: atendita %1, trovita %2 +ErrorProgress=Nevalida progreso: %1 de %2 +ErrorFileSize=Nevalida dosiergrandeco: atendita %1, trovita %2 + ; *** "Preparing to Install" wizard page WizardPreparing=Preparado por Instalo PreparingDesc=Majstro estas preparata por instalo [name] en via komputilo. -PreviousInstallNotCompleted=Instalado/Forigo de antau`a programo ne estas plena. Por vi bezonas relanc`i vian komputilon por plenigi tian instaladon.%n%nPost relanc`o de via komputilo, s`altu Majstron denove por finigi instaladon de [name]. +PreviousInstallNotCompleted=Instalado/Forigo de antaŭa programo ne estas plena. Por vi bezonas relanĉi vian komputilon por plenigi tian instaladon.%n%nPost relanĉo de via komputilo, ŝaltu Majstron denove por finigi instaladon de [name]. CannotContinue=La Majstro ne povas kontinui. Bonvolu kliki Fino por eliri. -ApplicationsFound=Sekvaj aplikaj`oj uzas dosierojn kiajn bezonas renovigi per Instalado. Estas rekomendite ke vi permesu al Majstro automate fermi tiajn aplikaj`ojn. -ApplicationsFound2=Sekvaj aplikaj`oj uzas dosierojn kiajn bezonas renovigi per Instalado. Estas rekomendite ke vi permesu al Majstro automate fermi tiajn aplikaj`ojn. Poste de instalado Majstro provos relanc`i aplikaj`ojn. -CloseApplications=&Automate fermi aplikaj`ojn -DontCloseApplications=Ne fermu aplikaj`ojn -ErrorCloseApplications=Majstro estis nepovebla au`tomate fermi c`iajn aplikaj`ojn. Estas rekomendite ke vi fermu c`iajn aplikaj`ojn, uzantaj dosierojn, kiaj estas bezonatajn por renovigo per la Majstro antau` kontinui. +ApplicationsFound=Sekvaj aplikaĵoj uzas dosierojn kiajn bezonas renovigi per Instalado. Estas rekomendite ke vi permesu al Majstro automate fermi tiajn aplikaĵojn. +ApplicationsFound2=Sekvaj aplikaĵoj uzas dosierojn kiajn bezonas renovigi per Instalado. Estas rekomendite ke vi permesu al Majstro automate fermi tiajn aplikaĵojn. Poste de instalado Majstro provos relanĉi aplikaĵojn. +CloseApplications=&Automate fermi aplikaĵojn +DontCloseApplications=Ne fermu aplikaĵojn +ErrorCloseApplications=Majstro estis nepovebla aŭtomate fermi ĉiajn aplikaĵojn. Estas rekomendite ke vi fermu ĉiajn aplikaĵojn, uzantaj dosierojn, kiaj estas bezonatajn por renovigo per la Majstro antaŭ kontinui. +PrepareToInstallNeedsRestart=Instalado devas restartigi vian komputilon. Post restartigi vian komputilon, rulu denove Instaladon por kompletigi la instaladon de [name].%n%nĈu vi ŝatus rekomenci nun? ; *** "Installing" wizard page WizardInstalling=Instalado InstallingLabel=Bonvolu atenti dum Majstro instalas [name] en via komputilo. ; *** "Setup Completed" wizard page -FinishedHeadingLabel= Fino de instalado +FinishedHeadingLabel=Fino de instalado FinishedLabelNoIcons=La Majstro finigis instaladon [name] en via komputilo. -FinishedLabel=La Majstro finigis instaladon [name] en via komputilo. La aplikaj`o povos esti lanc`ita per elekto de instalaj ikonoj. -ClickFinish= Kliku Fino por finigi instaladon. -FinishedRestartLabel=Por plenumigi instaladon de [name], Majstro devas relanc`i vian komputilon. C`u vi volas relanc`i nun? -FinishedRestartMessage=Por plenumigi instaladon de [name], Majstro devas relanc`i vian komputilon.%n%nC`u vi volas relanc`i nun? -ShowReadmeCheck=Jes, mi volas rigardi dosieron README -YesRadio=&Jes, relanc`u komputilon nun -NoRadio=&Ne, mi volas relanc`i komputilon poste +FinishedLabel=La Majstro finigis instaladon [name] en via komputilo. La aplikaĵo povos esti lanĉita per elekto de instalaj ikonoj. +ClickFinish=Kliku Fino por finigi instaladon. +FinishedRestartLabel=Por plenumigi instaladon de [name], Majstro devas relanĉi vian komputilon. Ĉu vi volas relanĉi nun? +FinishedRestartMessage=Por plenumigi instaladon de [name], Majstro devas relanĉi vian komputilon.%n%nĈu vi volas relanĉi nun? +ShowReadmeCheck=Jes, mi volas rigardi dosieron README +YesRadio=&Jes, relanĉu komputilon nun +NoRadio=&Ne, mi volas relanĉi komputilon poste ; used for example as 'Run MyProg.exe' -RunEntryExec=S`altu %1 +RunEntryExec=Ŝaltu %1 ; used for example as 'View Readme.txt' RunEntryShellExec=Rigardi %1 ; *** "Setup Needs the Next Disk" stuff ChangeDiskTitle=La Majstro postulas sekvan diskon -SelectDiskLabel2=Bonvolu inserti Diskon %1 kaj kliku Jes.%n%nSe dosieroj en tia disko povos esti diversaj de prezentitaj malalte, enskribu korektan vojon au` kliku Elekto. +SelectDiskLabel2=Bonvolu inserti Diskon %1 kaj kliku Jes.%n%nSe dosieroj en tia disko povos esti diversaj de prezentitaj malalte, enskribu korektan vojon aŭ kliku Elekto. PathLabel=&Vojo: -FileNotInDir2=Dosieron "%1" estas nepoveble lokigi en "%2". Bonvolu inserti korectan diskon au` elektu alian dosierujon. +FileNotInDir2=Dosieron "%1" estas nepoveble lokigi en "%2". Bonvolu inserti korectan diskon aŭ elektu alian dosierujon. SelectDirectoryLabel=Bonvolu difini lokon de alia disko. ; *** Installation phase messages -SetupAborted=Instalado ne estis plena.%n%nBonvolu korekti problemon kaj lanc`u Majstron denove. -EntryAbortRetryIgnore=Kliku Reen por provi ankorau`, Ignori por fari c`iokaze, au` S`topi por finigi instaladon. +SetupAborted=Instalado ne estis plena.%n%nBonvolu korekti problemon kaj lanĉu Majstron denove. +AbortRetryIgnoreSelectAction=Elektu agon +AbortRetryIgnoreRetry=&Provu denove +AbortRetryIgnoreIgnore=&Ignori la eraron kaj daŭrigi +AbortRetryIgnoreCancel=Nuligi instaladon ; *** Installation status messages -StatusClosingApplications=Fermado de aplikaj`oj... +StatusClosingApplications=Fermado de aplikaĵoj... StatusCreateDirs=Kreado de dosierujojn... StatusExtractFiles=Ekstraktado de dosierojn... StatusCreateIcons=Kreado de tujklavojn... @@ -254,9 +282,9 @@ StatusCreateIniEntries=Kreado de INI dosierojn... StatusCreateRegistryEntries=Kreado de registraj pointoj... StatusRegisterFiles=Registrado de dosierojn... StatusSavingUninstall=Konservas informacio por forigo... -StatusRunProgram=Finig`as instalado... -StatusRestartingApplications=Relanc`o de aplikaj`oj... -StatusRollback=Renovigo de s`ang`oj... +StatusRunProgram=Finiĝas instalado... +StatusRestartingApplications=Relanĉo de aplikaĵoj... +StatusRollback=Renovigo de ŝanĝoj... ; *** Misc. errors ErrorInternal2=Interna eraro: %1 @@ -266,54 +294,75 @@ ErrorFunctionFailedWithMessage=%1 estas kripligita; kodnomo %2.%n%3 ErrorExecutingProgram=Estas nepoveble plenumi dosieron:%n%1 ; *** Registry errors -ErrorRegOpenKey=Eraro dum malfermo de registra s`losilo:%n%1\%2 -ErrorRegCreateKey=Eraro dum kreado de registra s`losilo:%n%1\%2 -ErrorRegWriteKey=Eraro dum skribado en registra s`losilo:%n%1\%2 +ErrorRegOpenKey=Eraro dum malfermo de registra ŝlosilo:%n%1\%2 +ErrorRegCreateKey=Eraro dum kreado de registra ŝlosilo:%n%1\%2 +ErrorRegWriteKey=Eraro dum skribado en registra ŝlosilo:%n%1\%2 ; *** INI errors ErrorIniEntry=Eraro dum kreado de INI pointo en dosiero "%1". ; *** File copying errors -FileAbortRetryIgnore=Kliku Reen por provi denove, Ignori por lasi tian dosieron (ne estas rekomendite), au` S`topi por finigi instaladon. -FileAbortRetryIgnore2=Kliku Reen por provi denove, Ignori por plenumi c`iokaze (ne estas rekomendite), au` S`topi por finigi instaladon. +FileAbortRetryIgnoreSkipNotRecommended=&Preterpasi ĉi tiun dosieron (ne rekomendita) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignori la eraron kaj daŭrigi (ne rekomendita) SourceIsCorrupted=La fonta dosiero estas kripligita SourceDoesntExist=La fonta dosiero "%1" ne ekzistas -ExistingFileReadOnly=Ekzista dosiero estas markita kiel nurlega.%n%nKliku Reen por forigi la nurlegan atributon kaj provu reen, Ignori por lasi tian dosieron, au` S`topi por fini instaladon. +ExistingFileReadOnly=Ekzistanta dosiero estas markita nurlega.%n%nAlklaku Reen por forigi la nurlegeblan atributon kaj provu denove, Ignori por transsalti la dosieron aŭ Ĉesigi por kompletigi la instaladon. +ExistingFileReadOnly2=La ekzistanta dosiero ne povis esti anstataŭigita ĉar ĝi estas markita nurlega. +ExistingFileReadOnlyRetry=&Forigu la nurlegeblan atributon kaj reprovu +ExistingFileReadOnlyKeepExisting=&Konservu la ekzistantan dosieron ErrorReadingExistingDest=Eraro aperis dum legado de ekzista dosiero: -FileExists=La dosiero jam ekzistas.%n%nC`u vi volas ke Majstro reskribu g`in? -ExistingFileNewer=Ekzista dosiero estas pli nova ol Majstro provas instali. Estas rekomendita ke vi konservu ekzistan dosieron.%n%nC`u vi volas konservi ekzistan dosieron? -ErrorChangingAttr=Eraro aperis dum provo c`ang`i atributoj de ekzista dosiero: +FileExistsSelectAction=Elekti agon +FileExists2=La dosiero jam ekzistas. +FileExistsOverwriteExisting=&Anstataŭigu la ekzistantan dosieron +FileExistsKeepExisting=&Konservu la ekzistantan dosieron +FileExistsOverwriteOrKeepAll=&Faru ĉi tion por la venontaj konfliktoj +ExistingFileNewerSelectAction=Elekti agon +ExistingFileNewer2=La ekzistanta dosiero estas pli nova ol tiu instalilo provas instali. +ExistingFileNewerOverwriteExisting=&Anstataŭigu la ekzistantan dosieron +ExistingFileNewerKeepExisting=&Konservu la ekzistantan dosieron (recomendita) +ExistingFileNewerOverwriteOrKeepAll=&Faru ĉi tion por la venontaj konfliktoj +ErrorChangingAttr=Eraro aperis dum provo ĉanĝi atributoj de ekzista dosiero: ErrorCreatingTemp=Eraro aperis dum kreado dosieron en destina dosierujo: ErrorReadingSource=Eraro aperis dum legado de dosiero: ErrorCopying=Eraro aperis dum kopiado de dosiero: -ErrorReplacingExistingFile=Eraro aperis dum relokig`o de ekzistan dosieron: -ErrorRestartReplace=Relanc`o/Relokig`o estas kripligita: -ErrorRenamingTemp=Eraro aperis dum renomig`o del dosiero en destina dosierujo: -ErrorRegisterServer=Estas nepoveble registri DLL/OC`: %1 +ErrorReplacingExistingFile=Eraro aperis dum relokiĝo de ekzistan dosieron: +ErrorRestartReplace=Relanĉo/Relokiĝo estas kripligita: +ErrorRenamingTemp=Eraro aperis dum renomiĝo del dosiero en destina dosierujo: +ErrorRegisterServer=Estas nepoveble registri DLL/OĈ: %1 ErrorRegSvr32Failed=RegSvr32estas kripligita kun elira codo %1 ErrorRegisterTypeLib=Estas nepoveble registri bibliotekon de tipo : %1 +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bita +UninstallDisplayNameMark64Bit=64-bita +UninstallDisplayNameMarkAllUsers=Ĉiuj uzantoj +UninstallDisplayNameMarkCurrentUser=Nuna uzanto + ; *** Post-installation errors ErrorOpeningReadme=Eraro aperis dum malfermado de README dosiero. -ErrorRestartingComputer=Majstro ne povis relanc`i komputilo. Bonvolu fari tion permane. +ErrorRestartingComputer=Majstro ne povis relanĉi komputilo. Bonvolu fari tion permane. ; *** Uninstaller messages UninstallNotFound=Dosiero "%1" ne ekzistas. Estas nepoveble forigi. UninstallOpenError=Dosieron "%1" nepoveble estas malfermi. Estas nepoveble forigi -UninstallUnsupportedVer=\Foriga protokolo "%1" estas en nekonata formato per c`i tia versio de forigprogramo. Estas nepoveble forigi +UninstallUnsupportedVer=\Foriga protokolo "%1" estas en nekonata formato per ĉi tia versio de forigprogramo. Estas nepoveble forigi UninstallUnknownEntry=Ekzistas nekonata pointo (%1) en foriga protokolo -ConfirmUninstall=C`u vi reale volas tute forigi %1 kaj c`iaj komponentoj de g`i? -UninstallOnlyOnWin64=C`i tian instaladon povos forigi nur en 64-bit Vindoso. -OnlyAdminCanUninstall=C`i tian instaladon povos forigi nur uzanto kun administrantaj rajtoj. -UninstallStatusLabel=Bonvolu atendi dum %1 forig`os de via komputilo. +ConfirmUninstall=Ĉu vi reale volas tute forigi %1 kaj ĉiaj komponentoj de ĝi? +UninstallOnlyOnWin64=Ĉi tian instaladon povos forigi nur en 64-bit Vindoso. +OnlyAdminCanUninstall=Ĉi tian instaladon povos forigi nur uzanto kun administrantaj rajtoj. +UninstallStatusLabel=Bonvolu atendi dum %1 foriĝos de via komputilo. UninstalledAll=%1 estis sukcese forigita de via komputilo. -UninstalledMost=Forigo de %1 estas plena.%n%nKelkaj elementoj ne estis forigitaj. G`in poveble estas forigi permane. -UninstalledAndNeedsRestart=Por plenumi forigadon de %1, via komputilo devas esti relanc`ita.%n%nC`u vi volas relanc`i nun? +UninstalledMost=Forigo de %1 estas plena.%n%nKelkaj elementoj ne estis forigitaj. Ĝin poveble estas forigi permane. +UninstalledAndNeedsRestart=Por plenumi forigadon de %1, via komputilo devas esti relanĉita.%n%nĈu vi volas relanĉi nun? UninstallDataCorrupted="%1" dosiero estas kriplita. Estas nepoveble forigi ; *** Uninstallation phase messages ConfirmDeleteSharedFileTitle=Forigi komune uzatan dosieron? -ConfirmDeleteSharedFile2=La sistemo indikas ke sekva komune uzata dosiero jam ne estas uzata per neniel aplikaj`oj. C`u vi volas forigi c`i tian dosieron?%n%nSe ajna programo jam uzas tian dosieron, dum forigo g`i povos malg`uste funkcii. Se vi ne estas certa elektu Ne. Restante en via sistemo la dosiero ne damag`os g`in. +ConfirmDeleteSharedFile2=La sistemo indikas ke sekva komune uzata dosiero jam ne estas uzata per neniel aplikaĵoj. Ĉu vi volas forigi ĉi tian dosieron?%n%nSe ajna programo jam uzas tian dosieron, dum forigo ĝi povos malĝuste funkcii. Se vi ne estas certa elektu Ne. Restante en via sistemo la dosiero ne damaĝos ĝin. SharedFileNameLabel=nomo de dosiero: SharedFileLocationLabel=Loko: WizardUninstalling=Stato de forigo @@ -328,15 +377,15 @@ ShutdownBlockReasonUninstallingApp=Forigado %1. [CustomMessages] -NameAndVersion=%1 versio %2 +NameAndVersion=%1 versio %2 AdditionalIcons=Aldonaj ikonoj: -CreateDesktopIcon=Krei &Labortablan ikonon -CreateQuickLaunchIcon=Krei &Rapida lanc`o ikonon +CreateDesktopIcon=Krei &Labortablan ikonon +CreateQuickLaunchIcon=Krei &Rapida lanĉo ikonon ProgramOnTheWeb=%1 en Reto -UninstallProgram=Rorig`ado %1 -LaunchProgram=Lanc`o %1 -AssocFileExtension=&Asociigi %1 kun %2 dosieraj finaj`oj -AssocingFileExtension=Asociig`as %1 kun %2 dosiera finaj`o... -AutoStartProgramGroupDescription=Lanc`o: -AutoStartProgram=Automate s`alti %1 -AddonHostProgramNotFound=%1 nepoveble estas loki en dosierujo kian vi elektis.%n%nC`u vi volas kontinui c`iokaze? +UninstallProgram=Roriĝado %1 +LaunchProgram=Lanĉo %1 +AssocFileExtension=&Asociigi %1 kun %2 dosieraj finaĵoj +AssocingFileExtension=Asociiĝas %1 kun %2 dosiera finaĵo... +AutoStartProgramGroupDescription=Lanĉo: +AutoStartProgram=Automate ŝalti %1 +AddonHostProgramNotFound=%1 nepoveble estas loki en dosierujo kian vi elektis.%n%nĈu vi volas kontinui ĉiokaze? diff --git a/installer/innosetup/Languages/Farsi.isl b/installer/innosetup/Languages/Farsi.isl index 232a7ce3b..aaed6cd0b 100644 --- a/installer/innosetup/Languages/Farsi.isl +++ b/installer/innosetup/Languages/Farsi.isl @@ -1,13 +1,15 @@ -; *** Inno Setup version 5.5.3+ Farsi messages *** -;Translator:Hessam Mohamadi -;Email:hessam55@hotmail.com +; *** Inno Setup version 6.1.0+ Farsi messages *** +; ; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ +; https://jrsoftware.org/files/istrans/ ; ; Note: When translating this text, do not add periods (.) to the end of ; messages that didn't have them already, because on those messages Inno ; Setup adds the periods automatically (appending a period would result in ; two periods being displayed). +; +; Translated by: +; Peyman M. (peymanR34@outlook.com) [LangOptions] ; The following three entries are very important. Be sure to read and @@ -15,323 +17,372 @@ LanguageName=Farsi LanguageID=$0429 LanguageCodePage=1256 +RightToLeft=yes ; If the language you are translating to requires special font faces or ; sizes, uncomment any of the following entries and change them accordingly. -DialogFontName=Tahoma -DialogFontSize=8 -WelcomeFontName=Tahoma -WelcomeFontSize=11 -TitleFontName=Tahoma -TitleFontSize=28 -CopyrightFontName=Tahoma -CopyrightFontSize=8 +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 [Messages] ; *** Application titles -SetupAppTitle= -SetupWindowTitle=%1 - -UninstallAppTitle= -UninstallAppFullTitle=%1 +SetupAppTitle=نصب کننده +SetupWindowTitle=نصب کننده - %1 +UninstallAppTitle=حذف کننده +UninstallAppFullTitle=%1 حذف کننده ; *** Misc. common -InformationTitle= -ConfirmTitle= -ErrorTitle= +InformationTitle=اطلاعات +ConfirmTitle=تایید +ErrorTitle=خطا ; *** SetupLdr messages -SetupLdrStartupMessage= . Ͽ %1 -LdrCannotCreateTemp= . -LdrCannotExecTemp= . +SetupLdrStartupMessage=این %1 را نصب می‌کند. آیا مایل به ادامه هستید؟ +LdrCannotCreateTemp=خطا در ایجاد یک فایل موقت. برنامه نصب لغو شد +LdrCannotExecTemp=خطا در اجرای فایل در پوشه موقت. برنامه نصب لغو شد +HelpTextNote= ; *** Startup error messages -LastErrorMessage=%1.%n%n %2: %3 -SetupFileMissing= . Ԙ %1 -SetupFileCorrupt= ϡ -SetupFileCorruptOrWrongVer= ϡ . Ԙ -InvalidParameter= :%n%n%1 -SetupAlreadyRunning= -WindowsVersionNotSupported= ʡ -WindowsServicePackRequired= %1 %2 -NotOnThisPlatform= %1 -OnlyOnThisPlatform= %1 -OnlyOnTheseArchitectures= Ԑ ʡ :%n%n%1 -MissingWOW64APIs= %1 ǘ ʡ Ԙ -WinVersionTooLowError= %1 %2 -WinVersionTooHighError= %1 %2 -AdminPrivilegesRequired= -PowerUserPrivilegesRequired= -SetupAppRunningError=ǘ %1 %n%n Ӂ -UninstallAppRunningError=ǘ %1 %n%n Ӂ +LastErrorMessage=%1.%n%nخطا %2: %3 +SetupFileMissing=فایل %1 در پوشه نصب وجود ندارد. لطفاً مشکل را برطرف کرده و یا یک کپی جدید از برنامه را دریافت کنید. +SetupFileCorrupt=فایل های نصب کننده آسیب دیده‌اند. لطفاً یک کپی جدید از برنامه را دریافت کنید. +SetupFileCorruptOrWrongVer=فایل های نصب کننده آسیب دیده‌اند، یا با این نسخه از نصب کننده سازگار نیستند. لطفاً مشکل را برطرف کرده و یا یک کپی جدید از برنامه را دریافت کنید. +InvalidParameter=یک پارامتر نامعتبر به خط فرمان ارسال شده است:%n%n%1 +SetupAlreadyRunning=نصب کننده از قبل در حال اجراست. +WindowsVersionNotSupported=این برنامه از نسخه ویندوزی که بر روی کامپیوتر شما در حال اجراست پشتیبانی نمی‌کند. +WindowsServicePackRequired=این برنامه نیازمند %1 سرویس پک %2 یا بالاتر است. +NotOnThisPlatform=این برنامه روی %1 اجرا نمی‌شود. +OnlyOnThisPlatform=این برنامه باید بر روی %1 اجرا شود. +OnlyOnTheseArchitectures=این برنامه تنها می‌تواند بر روی نسخه های ویندوزی نصب شود که برای معماری های پردازنده زیر طراحی شده‌اند:%n%n%1 +WinVersionTooLowError=این برنامه نیازمند %1 نسخه %2 یا بالاتر است. +WinVersionTooHighError=این برنامه نمی‌تواند بر روی %1 نسخه %2 یا بالاتر نصب شود. +AdminPrivilegesRequired=هنگام نصب این برنامه، شما باید به عنوان یک کاربر مدیر وارد سیستم شده باشید. +PowerUserPrivilegesRequired=در هنگام نصب این برنامه، شما باید به عنوان کاربر مدیر وارد سیستم شده باشید و یا اینکه عضو گروه Power Users باشید. +SetupAppRunningError=نصب کننده %1 هم اکنون در حال اجراست.%n%nلطفاً اکنون تمام نمونه های آن را بسته، و سپس برای ادامه بر روی تایید، و یا برای خروج بر روی انصراف کلیک کنید. +UninstallAppRunningError=حذف کننده تشخیص داده است که %1 هم اکنون در حال اجراست.%n%nلطفاً اکنون تمام نمونه های آن را بسته، و سپس برای ادامه بر روی تایید، و یا برای خروج بر روی انصراف کلیک کنید. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=انتخاب نحوه نصب توسط نصب کننده +PrivilegesRequiredOverrideInstruction=انتخاب نحوه نصب +PrivilegesRequiredOverrideText1=%1 را می‌توان برای تمامی کاربران (نیازمند دسترسی مدیر سیستم)، و یا تنها برای شما نصب کرد.‏ +PrivilegesRequiredOverrideText2=%1 را می‌توان تنها برای شما، و یا تمامی کاربران (نیازمند دسترسی مدیر سیستم) است.‏ +PrivilegesRequiredOverrideAllUsers=نصب برای &تمامی کاربران +PrivilegesRequiredOverrideAllUsersRecommended=نصب برای &تمامی کاربران (پیشنهاد می‌شود)‏ +PrivilegesRequiredOverrideCurrentUser=نصب تنها برای &من +PrivilegesRequiredOverrideCurrentUserRecommended=نصب تنها برای &من (پیشنهاد می‌شود)‏ ; *** Misc. errors -ErrorCreatingDir= "%1" -ErrorTooManyFilesInDir= "%1" +ErrorCreatingDir=نصب کننده قادر به ایجاد پوشه نبود "%1" +ErrorTooManyFilesInDir=ایجاد یک فایل در پوشه "%1" بدلیل آنکه حاوی تعداد زیادی فایل است امکان پذیر نیست ; *** Setup common messages -ExitSetupTitle= -ExitSetupMessage= . ǐ ǘ ϡ %n%n . Ͽ -AboutSetupMenuItem=... & -AboutSetupTitle= -AboutSetupMessage=%2 %1%n%3%n%n%1 :%n%4 +ExitSetupTitle=خروج از نصب کننده +ExitSetupMessage=نصب به پایان نرسیده است. در صورتی که اکنون خارج شوید برنامه نصب نخواهد شد.‏%n%nشما می‌توانید نصب کننده را مجدداً در زمانی دیگر برای تکمیل عملیات نصب اجرا کنید.‏%n%nآیا مایل به خروج هستید؟ +AboutSetupMenuItem=&درباره نصب کننده... +AboutSetupTitle=درباره نصب کننده +AboutSetupMessage=%1 نسخه %2%n%3%n%n%1 وب سایت:%n%4 AboutSetupNote= TranslatorNote= ; *** Buttons -ButtonBack=< & -ButtonNext=& > -ButtonInstall=& -ButtonOK=& -ButtonCancel=& -ButtonYes=& -ButtonYesToAll= & -ButtonNo=& -ButtonNoToAll= & -ButtonFinish=& -ButtonBrowse=& -ButtonWizardBrowse=& -ButtonNewFolder= +ButtonBack=< &قبلی +ButtonNext=&بعدی > +ButtonInstall=&نصب +ButtonOK=تایید +ButtonCancel=انصراف +ButtonYes=&بله +ButtonYesToAll=بله برای &همه +ButtonNo=&خیر +ButtonNoToAll=ن&ه برای همه +ButtonFinish=&پایان +ButtonBrowse=&مرور... +ButtonWizardBrowse=م&رور...‏ +ButtonNewFolder=&ایجاد پوشه جدید ; *** "Select Language" dialog messages -SelectLanguageTitle= -SelectLanguageLabel= : +SelectLanguageTitle=انتخاب زبان نصب کننده +SelectLanguageLabel=زبانی را که می‌خواهید در حین نصب استفاده کنید را انتخاب کنید. ; *** Common wizard text -ClickNext= +ClickNext=برای ادامه بر روی بعدی کلیک کنید، برای خروج از نصب کننده بر روی انصراف کلیک کنید.‏ BeveledLabel= -BrowseDialogTitle= -BrowseDialogLabel= ϡ Ӂ -NewFolderName= +BrowseDialogTitle=مرور برای پوشه +BrowseDialogLabel=از لیست زیر یک پوشه را انتخاب کرده و سپس بر روی تایید کلیک کنید.‏ +NewFolderName=پوشه جدید ; *** "Welcome" wizard page -WelcomeLabel1= [name] -WelcomeLabel2= [name/ver] %n%n ϡ +WelcomeLabel1=به ویزارد نصب کننده [name] خوش آمدید +WelcomeLabel2=این [name/ver] را بر روی کامپیوتر شما نصب می‌کند.‏%n%nپیشنهاد می‌شود قبل از ادامه تمامی اپلیکیشن های دیگر را ببندید.‏ ; *** "Password" wizard page -WizardPassword= -PasswordLabel1= -PasswordLabel3= ϡӁ . 捘 ѐ -PasswordEditLabel=: -IncorrectPassword= . +WizardPassword=گذرواژه +PasswordLabel1=این نصب کننده با گذرواژه محافظت شده است.‏ +PasswordLabel3=لطفاً یک گذرواژه را وارد کنید، سپس بر روی بعدی کلیک کنید. گذرواژه ها حساس به حروف بزرگ و کوچک هستند.‏ +PasswordEditLabel=&گذرواژه:‏ +IncorrectPassword=گذرواژه وارد شده اشتباه است. لطفاً مجدداً تلاش کنید.‏ ; *** "License Agreement" wizard page -WizardLicense= -LicenseLabel= -LicenseLabel3= . ȁ -LicenseAccepted= &흁 -LicenseNotAccepted= &흁 +WizardLicense=توافقنامه استفاده +LicenseLabel=لطفاً اطلاعات مهم زیر را قبل از ادامه مطالعه کنید.‏ +LicenseLabel3=لطفاً توافقنامه زیر را مطالعه کنید. شما باید مفاد این توافقنامه را پیش از ادامه نصب برنامه بپذیرید. +LicenseAccepted=من توافقنامه را &می‌پذیرم +LicenseNotAccepted=من توافقنامه را &نمی‌پذیرم ; *** "Information" wizard pages -WizardInfoBefore= -InfoBeforeLabel= -InfoBeforeClickLabel= ϡ -WizardInfoAfter= -InfoAfterLabel= -InfoAfterClickLabel= ϡ +WizardInfoBefore=اطلاعات +InfoBeforeLabel=لطفاً اطلاعات مهم زیر را قبل از ادامه مطالعه کنید.‏‏ +InfoBeforeClickLabel=زمانی که آماده برای ادامه نصب هستید، بر روی بعدی کلیک کنید‏.‏ +WizardInfoAfter=اطلاعات +InfoAfterLabel=لطفاً اطلاعات مهم زیر را قبل از ادامه مطالعه کنید.‏ +InfoAfterClickLabel=زمانی که آماده برای ادامه‌ی نصب هستید، بر روی بعدی کلیک کنید‏.‏ ; *** "User Information" wizard page -WizardUserInfo= -UserInfoDesc= -UserInfoName= &: -UserInfoOrg=&: -UserInfoSerial= &: -UserInfoNameRequired= +WizardUserInfo=اطلاعات کاربر +UserInfoDesc=لطفاً اطلاعات خود را وارد کنید.‏ +UserInfoName=&نام کاربری:‏ +UserInfoOrg=&سازمان:‏ +UserInfoSerial=&شماره سریال:‏ +UserInfoNameRequired=شما باید یک نام را وارد کنید. ; *** "Select Destination Location" wizard page -WizardSelectDir= -SelectDirDesc= Ͽ [name] -SelectDirLabel3= [name] -SelectDirBrowseLabel= . ʡ -DiskSpaceMBLabel=ʝ [mb] -CannotInstallToNetworkDrive= Ș -CannotInstallToUNCPath= -InvalidPath= ϡ :%n%nC:\APP%n%n :%n%n\\server\share -InvalidDrive= ǘ ϡ . -DiskSpaceWarningTitle= -DiskSpaceWarning= %1 ʡ %2 .%n%n Ͽ -DirNameTooLong= -InvalidDirName= -BadDirName32= ǘ Ȑ:%n%n%1 -DirExistsTitle= -DirExists= :%n%n%1%n%nǘ . ϡ Ͽ -DirDoesntExistTitle= -DirDoesntExist= :%n%n%1%n%n . Ͽ +WizardSelectDir=انتخاب محل مقصد +SelectDirDesc=کجا باید [name] نصب شود؟ +SelectDirLabel3=نصب کننده [name] را در پوشه زیر نصب می‌کند.‏ +SelectDirBrowseLabel=برای ادامه، بر روی بعدی کلیک کنید. اگر مایل به انتخاب پوشه دیگری هستید، بر روی مرور کلیک کنید.‏ +DiskSpaceGBLabel=حداقل [gb] گیگابایت از فضای خالی دیسک مورد نیاز است.‏ +DiskSpaceMBLabel=حداقل [mb] مگابایت از فضای خالی دیسک مورد نیاز است.‏ +CannotInstallToNetworkDrive=نصب کننده نمی‌تواند در یک درایو شبکه نصب را انجام دهد. +CannotInstallToUNCPath=نصب کننده نمی‌تواند در یک UNC path نصب را انجام دهد. +InvalidPath=شما باید یک آدرس کامل همراه با اسم درایو وارد کنید؛ به عنوان مثال:%n%nC:\APP%n%nو یا یک مسیر UNC به شکل مقابل:%n%n\\server\share +InvalidDrive=درایو یا UNC share انتخاب شده وجود ندارد و یا غیر قابل دسترسی است. لطفاً یک مسیر دیگر را انتخاب کنید. +DiskSpaceWarningTitle=فضای خالی دیسک کافی نیست +DiskSpaceWarning=نصب کننده به حداقل %1 کیلوبایت فضای خالی برای نصب نیاز دارد، اما درایو انتخاب شده فقط %2 کیلوبایت فضای آزاد دارد.%n%nآیا مایل به ادامه هستید؟ +DirNameTooLong=نام پوشه یا مسیر بسیار طولانی است.‏ +InvalidDirName=نام پوشه صحیح نیست.‏ +BadDirName32=نام پوشه‌ها نمی‌تواند شامل کاراکتر های مقابل باشد:%n%n%1 +DirExistsTitle=پوشه از قبل وجود دارد +DirExists=این پوشه:%n%n%1%n%nاز قبل وجود دارد. آیا بهرحال مایل به نصب در آن پوشه هستید؟ +DirDoesntExistTitle=پوشه وجود ندارد +DirDoesntExist=این پوشه:%n%n%1%n%nوجود ندارد. آیا مایل به ساختن آن هستید؟ ; *** "Select Components" wizard page -WizardSelectComponents= -SelectComponentsDesc= Ͽ -SelectComponentsLabel2= ȡ ϡ . ϡ -FullInstallation= +WizardSelectComponents=انتخاب اجزاء +SelectComponentsDesc=کدام اجزاء باید نصب شوند؟ +SelectComponentsLabel2=اجزایی که مایل به نصب آن‌ها هستید را انتخاب کنید؛ اجزایی را که نمی‌خواهید نصب کنید را از حالت انتخاب بردارید.‏ زمانی که آماده برای ادامه بودید بر روی بعدی کلیک کنید. +FullInstallation=نصب کامل ; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation= -CustomInstallation= -NoUninstallWarningTitle= -NoUninstallWarning= ǘ :%n%n%1%n%n .%n%n Ͽ -ComponentSize1=%1 -ComponentSize2=%1 -ComponentsDiskSpaceMBLabel= ʝ [mb] Ә +CompactInstallation=نصب فشرده +CustomInstallation=نصب سفارشی +NoUninstallWarningTitle=اجزاء وجود دارند +NoUninstallWarning=نصب کننده تشخیص داده است که اجزای فوق از قبل بر روی کامپیوتر شما نصب شده است:%n%n%1%n%nعدم انتخاب این اجزاء باعث حذف شدن آن‌ها نمی‌شود.%n%nآیا مایل به ادامه هستید؟ +ComponentSize1=%1 کیلوبایت +ComponentSize2=%1 مگابایت +ComponentsDiskSpaceGBLabel=انتخاب فعلی به حداقل [gb] گیگابایت فضای خالی دیسک نیاز دارد.‏ +ComponentsDiskSpaceMBLabel=انتخاب فعلی به حداقل [mb] مگابایت فضای خالی دیسک نیاز دارد.‏ ; *** "Select Additional Tasks" wizard page -WizardSelectTasks= -SelectTasksDesc= Ͽ -SelectTasksLabel2= ȡӁ [name] +WizardSelectTasks=انتخاب وظایف اضافی +SelectTasksDesc=کدام وظایف اضافی باید انجام شود؟ +SelectTasksLabel2=وظایف اضافی را که تمایل دارید در هنگام نصب [name] انجام داده شود را انتخاب کرده، سپس بر روی بعدی کلیک کنید.‏ ; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup= -SelectStartMenuFolderDesc= Ͽ -SelectStartMenuFolderLabel3= ҡ -SelectStartMenuFolderBrowseLabel= . ʡ -MustEnterGroupName= -GroupNameTooLong= -InvalidGroupName= -BadGroupName= ǘ :%n%n%1 -NoProgramGroupCheck2= +WizardSelectProgramGroup=انتخاب پوشه منوی استارت +SelectStartMenuFolderDesc=نصب کننده در کجا باید میانبر های برنامه را قرار دهد؟ +SelectStartMenuFolderLabel3=نصب کننده میانبر های برنامه را در پوشه زیر در منوی استارت ایجاد خواهد کرد. +SelectStartMenuFolderBrowseLabel=برای ادامه، بر روی بعدی کلیک کنید. در صورتی که تمایل به انتخاب پوشه دیگری دارید، بر روی مرور کلیک کنید. +MustEnterGroupName=شما باید یک اسم پوشه را وارد کنید. +GroupNameTooLong=نام پوشه و یا مسیر آن بسیار طولانی است. +InvalidGroupName=نام پوشه صحیح نیست. +BadGroupName=نام پوشه نباید شامل هر یک از کاراکتر های زیر باشد:%n%n%1 +NoProgramGroupCheck2=پوشه‌ای در منوی استارت ایجاد &نشود ; *** "Ready to Install" wizard page -WizardReady= -ReadyLabel1= [name] ҡ -ReadyLabel2a= -ReadyLabel2b= ȡ -ReadyMemoUserInfo= : -ReadyMemoDir= : -ReadyMemoType= : -ReadyMemoComponents= : -ReadyMemoGroup= : -ReadyMemoTasks= : +WizardReady=آماده نصب +ReadyLabel1=نصب کننده آماده شروع نصب [name] بر روی کامپیوتر شماست.‏ +ReadyLabel2a=برای ادامه نصب بر روی نصب کلیک کنید، و یا اگر تمایل به بازبینی یا تغییر تنظیمات دارید بر روی قبلی کلیک کنید. +ReadyLabel2b=برای ادامه نصب بر روی نصب کلیک کنید.‏ +ReadyMemoUserInfo=اطلاعات کاربر: +ReadyMemoDir=محل مقصد: +ReadyMemoType=نوع نصب: +ReadyMemoComponents=اجزاء انتخاب شده: +ReadyMemoGroup=پوشه منوی استارت: +ReadyMemoTasks=وظایف اضافی: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=درحال دانلود فایل های اضافی... +ButtonStopDownload=&توقف دانلود +StopDownload=آیا مطمئن هستید که می‌خواهید دانلود را متوقف کنید؟ +ErrorDownloadAborted=دانلود متوقف شد +ErrorDownloadFailed=دانلود ناموفق بود: %1 %2 +ErrorDownloadSizeFailed=دریافت حجم ناموفق بود: %1 %2 +ErrorFileHash1=هش فایل ناموفق بود: %1 +ErrorFileHash2=هش نامعتبر فایل: مورد انتظار %، پیدا شده %2 +ErrorProgress=پیشرفت نامعتبر: %1 از %2 +ErrorFileSize=اندازه فایل نامعتبر: مورد انتظار %، پیدا شده %2 ; *** "Preparing to Install" wizard page -WizardPreparing= -PreparingDesc= [name] -PreviousInstallNotCompleted= ȡ %n%n [name] -CannotContinue= ϡ -ApplicationsFound= . Ϙ -ApplicationsFound2= . Ϙ . ȡ . -CloseApplications=& Ϙ -DontCloseApplications=& -ErrorCloseApplications= Ϙ . +WizardPreparing=در حال آماده سازی برای نصب +PreparingDesc=نصب کننده در حال آماده سازی برای نصب [name] بر روی کامپیوتر شماست. +PreviousInstallNotCompleted=نصب/حذف برنامه قبلی تکمیل نشده است. شما باید کامپیوتر خود را برای تکمیل عملیات نصب مجدداً راه‌اندازی کنید.%n%nپس از ری‌استارت کامپیوتر، نصب کننده را مجدداً برای تکمیل عملیات نصب [name] اجرا کنید. +CannotContinue=نصب کننده قادر به ادامه نیست. لطفاً برای خروج بر روی انصراف کلیک کنید. +ApplicationsFound=اپلیکیشن های زیر در حال استفاده از فایل هایی هستند که نیازمند بروزرسانی توسط نصب کننده هستند. پیشنهاد می‌شود به نصب کننده اجازه دهید تا این اپلیکیشن ها به صورت خودکار بسته شوند. +ApplicationsFound2=اپلیکیشن های زیر در حال استفاده از فایل هایی هستند که نیازمند بروزرسانی توسط نصب کننده هستند. پیشنهاد می‌شود به نصب کننده اجازه دهید تا این اپلیکیشن ها به صورت خودکار بسته شوند. پس از پایان نصب، نصب کننده تلاش می‌کند تا این اپلیکیشن ها را مجدداً اجرا کند. +CloseApplications=بستن &خودکار اپلیکیشن ها +DontCloseApplications=اپلیکیشن ها بسته &نشوند +ErrorCloseApplications=نصب کننده قادر به بستن خودکار تمام اپلیکیشن ها نبود. پیشنهاد می‌شود تمام اپلیکیشن هایی که از فایل هایی که نیاز به بروزرسانی توسط نصب کننده را دارند را قبل از ادامه ببندید. +PrepareToInstallNeedsRestart=نصب کننده باید کامپیوتر را مجدداً راه‌اندازی کند. پس از ری‌استارت کامپیوتر، نصب کننده را برای تکمیل عملیات نصب [name] مجدداً اجرا کنید.%n%nآیا مایل به راه‌اندازی مجدد هستید؟ ; *** "Installing" wizard page -WizardInstalling= -InstallingLabel= [name] +WizardInstalling=در حال نصب +InstallingLabel=لطفاً تا زمانی که نصب کننده [name] را بر روی کامپیوتر شما نصب می‌کند، صبر کنید. ; *** "Setup Completed" wizard page -FinishedHeadingLabel= [name] -FinishedLabelNoIcons= [name] -FinishedLabel= [name] -ClickFinish= -FinishedRestartLabel= . Ͽ [name] -FinishedRestartMessage= [name] %n%n Ͽ -ShowReadmeCheck= -YesRadio= -NoRadio=ѡ +FinishedHeadingLabel=در حال تکمیل ویزارد نصب کننده [name] +FinishedLabelNoIcons=نصب کننده، عملیات نصب [name] بر روی کامپیوتر شما را به پایان رساند. +FinishedLabel=نصب کننده، عملیات نصب [name] بر روی کامپیوتر شما را به پایان رساند. اپلیکیشن می‌تواند با انتخاب میانبر های نصب شده اجرا شود. +ClickFinish=برای خروج از نصب کننده بر روی پایان کلیک کنید. +FinishedRestartLabel=برای تکمیل عملیات نصب [name]، نصب کننده باید کامپیوتر شما راه مجدداً راه‌اندازی کند. آیا هم اکنون مایل به ری‌استارت هستید؟ +FinishedRestartMessage=برای تکمیل عملیات نصب [name]، نصب کننده باید کامپیوتر شما را مجدداً راه‌اندازی کند.%n%nآیا هم اکنون مایل به ری‌استارت هستید؟ +ShowReadmeCheck=بله، مایل به مشاهده فایل README هستم. +YesRadio=&بله، اکنون کامپیوتر را دوباره راه‌اندازی کن +NoRadio=&نه، بعداً خودم کامپیوتر را راه‌اندازی مجدد خواهم کرد ; used for example as 'Run MyProg.exe' -RunEntryExec=%1 +RunEntryExec=اجرای %1 ; used for example as 'View Readme.txt' -RunEntryShellExec=%1 +RunEntryShellExec=مشاهده %1 ; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle= Ә -SelectDiskLabel2= %1 Ә%n%nǐ Ә ϡ -PathLabel=&: -FileNotInDir2= "%1" "%2" . Ә -SelectDirectoryLabel= Ә +ChangeDiskTitle=نصب کننده به دیسک بعدی نیاز دارد +SelectDiskLabel2=لطفاً دیسک %1 را وارد کرده و بر روی تایید کلیک کنید.%n%nدر صورتی که فایل های روی این دیسک در پوشه‌ای غیر از پوشه نمایش داده شده قابل پیدا شدن است، مسیر صحیح را وارد کرده و یا بر روی مرور کلیک کنید. +PathLabel=&مسیر: +FileNotInDir2=فایل "%1" در مسیر "%2" پیدا نشد. لطفاً دیسک صحیح را وارد کرده و یا یک پوشه دیگر را انتخاب کنید. +SelectDirectoryLabel=لطفاً آدرس دیسک بعدی را تعیین کنید. ; *** Installation phase messages -SetupAborted= %n%n Ԙ -EntryAbortRetryIgnore= ʡ +SetupAborted=نصب کننده تکمیل نشد.%n%nلطفاً مشکل را برطرف کرده و سپس نصب کننده را مجدداً اجرا کنید. +AbortRetryIgnoreSelectAction=انتخاب عمل +AbortRetryIgnoreRetry=&تلاش مجدد +AbortRetryIgnoreIgnore=&صرف نظر از خطا و ادامه +AbortRetryIgnoreCancel=انصراف از عملیات نصب ; *** Installation status messages -StatusClosingApplications=... -StatusCreateDirs=... -StatusExtractFiles=... -StatusCreateIcons=... -StatusCreateIniEntries=...INI -StatusCreateRegistryEntries=.. -StatusRegisterFiles=... -StatusSavingUninstall=... -StatusRunProgram=... -StatusRestartingApplications=... -StatusRollback=... Ґ +StatusClosingApplications=درحال بستن اپلیکیشن ها... +StatusCreateDirs=ایجاد پوشه ها... +StatusExtractFiles=استخراج فایل ها... +StatusCreateIcons=ایجاد میانبر ها... +StatusCreateIniEntries=ایجاد ورودی های INI... +StatusCreateRegistryEntries=ایجاد ورودی های ریجستری... +StatusRegisterFiles=در حال ریجستر فایل ها... +StatusSavingUninstall=در حال ذخیره اطلاعات حذف کننده... +StatusRunProgram=در حال پایان نصب... +StatusRestartingApplications=در حال راه‌اندازی مجدد اپلیکیشن ها... +StatusRollback=درحال بازگردانی تغییرات... ; *** Misc. errors -ErrorInternal2= : %1 -ErrorFunctionFailedNoCode=%1 -ErrorFunctionFailed=%1 ϡ %2 -ErrorFunctionFailedWithMessage=%1 ϡ %2.%n%3 -ErrorExecutingProgram= :%n%1 +ErrorInternal2=خطای داخلی: %1 +ErrorFunctionFailedNoCode=%1 ناموفق +ErrorFunctionFailed=%1 ناموفق؛ کد %2 +ErrorFunctionFailedWithMessage=%1 ناموفق؛ کد %2.%n%3 +ErrorExecutingProgram=خطا در اجرای فایل:%n%1 ; *** Registry errors -ErrorRegOpenKey= Ҙ :%n%1\%2 -ErrorRegCreateKey= :%n%1\%2 -ErrorRegWriteKey= :%n%1\%2 +ErrorRegOpenKey=خطا در بازکردن کلید ریجستری:%n%1\%2 +ErrorRegCreateKey=خطا در ایجاد کلید ریجستری:%n%1\%2 +ErrorRegWriteKey=خطا در نوشتن در کلید ریجستری:%n%1\%2 ; *** INI errors -ErrorIniEntry=" "%1 +ErrorIniEntry=خطا در ایجاد ورودی INI در فایل "%1". ; *** File copying errors -FileAbortRetryIgnore= ( ) -FileAbortRetryIgnore2= ( ) -SourceIsCorrupted= -SourceDoesntExist= "%1" -ExistingFileReadOnly= %n%n 塍 -ErrorReadingExistingDest= : -FileExists= %n%n Ͽ -ExistingFileNewer= . .%n%n Ͽ -ErrorChangingAttr= : -ErrorCreatingTemp= : -ErrorReadingSource= : -ErrorCopying= : -ErrorReplacingExistingFile= : -ErrorRestartReplace= : -ErrorRenamingTemp= : -ErrorRegisterServer= / : %1 -ErrorRegSvr32Failed=%1 -ErrorRegisterTypeLib= : %1 +FileAbortRetryIgnoreSkipNotRecommended=&پرش از این فایل (پیشنهاد نمی‌شود) +FileAbortRetryIgnoreIgnoreNotRecommended=&نادیده گرفتن خطا و ادامه (پیشنهاد نمی‌شود) +SourceIsCorrupted=فایل منبع آسیب دیده است +SourceDoesntExist=فایل منبع "%1" وجود ندارد +ExistingFileReadOnly2=فایل موجود بدلیل فقط-خواندنی بودن قابل جایگزینی نیست. +ExistingFileReadOnlyRetry=&حذف خصوصیت فقط-خواندنی و تلاش مجدد +ExistingFileReadOnlyKeepExisting=&نگه داشتن فایل موجود +ErrorReadingExistingDest=در هنگام تلاش برای خواندن فایل موجود خطایی رخ داده است: +FileExistsSelectAction=انتخاب عمل +FileExists2=فایل از قبل وجود دارد. +FileExistsOverwriteExisting=&بازنویسی فایل موجود +FileExistsKeepExisting=&نگه‌داشتن فایل موجود +FileExistsOverwriteOrKeepAll=&این کار را برای تداخل های بعد انجام بده +ExistingFileNewerSelectAction=انتخاب عمل +ExistingFileNewer2=فایل موجود از فایلی که نصب کننده در تلاش برای نصب آن است جدیدتر است. +ExistingFileNewerOverwriteExisting=&بازنویسی فایل موجود +ExistingFileNewerKeepExisting=&نگه داشتن فایل موجود (پیشنهاد می‌شود) +ExistingFileNewerOverwriteOrKeepAll=&این کار را برای تداخل های بعدی انجام بده +ErrorChangingAttr=در هنگام تلاش برای تغییر خصوصیت فایل موجود خطایی رخ داده است: +ErrorCreatingTemp=در هنگام تلاش برای ایجاد یک فایل در پوشه مقصد خطایی رخ داده است: +ErrorReadingSource=در هنگام تلاش برای خواندن فایل مبداء خطایی رخ داده است: +ErrorCopying=در هنگام تلاش برای کپی فایل خطایی رخ داده است: +ErrorReplacingExistingFile=در هنگام تلاش برای جایگزینی فایل موجود خطایی رخ داده است: +ErrorRestartReplace=RestartReplace ناموفق بود: +ErrorRenamingTemp=در هنگام تلاش برای تغییر نام یک فایل در پوشه مقصد خطایی رخ داده است: +ErrorRegisterServer=خطا در ریجستر DLL/OCX برای: %1 +ErrorRegSvr32Failed=RegSvr32 با کد خطای ناموفق بود %1 +ErrorRegisterTypeLib=قادر به ریجستر کتابخانه نوع نبود: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2، %3) +UninstallDisplayNameMark32Bit=32-بیت +UninstallDisplayNameMark64Bit=64-بیت +UninstallDisplayNameMarkAllUsers=تمامی کاربران +UninstallDisplayNameMarkCurrentUser=کاربر فعلی ; *** Post-installation errors -ErrorOpeningReadme= -ErrorRestartingComputer= . +ErrorOpeningReadme=در هنگام تلاش برای بازکردن فایل README خطایی رخ داده است. +ErrorRestartingComputer=نصب کننده قادر به راه‌اندازی مجدد کامپیوتر نبود. لطفاً به صورت دستی ری‌استارت کنید. ; *** Uninstaller messages -UninstallNotFound= . "%1" -UninstallOpenError= . "%1" -UninstallUnsupportedVer= . "%1" -UninstallUnknownEntry= (%1) -ConfirmUninstall= Ͽ %1 -UninstallOnlyOnWin64= ҝ 64 -OnlyAdminCanUninstall= -UninstallStatusLabel= %1 -UninstalledAll= %1 -UninstalledMost= %1 %n%n ϡ -UninstalledAndNeedsRestart= %1 %n%n Ͽ -UninstallDataCorrupted= . "%1" +UninstallNotFound=فایل "%1" وجود ندارد. حذف امکان پذیر نیست. +UninstallOpenError=امکان باز کردن فایل"%1" وجود ندارد. حذف امکان پذیر نیست +UninstallUnsupportedVer=فایل لاگ حذف کننده "%1" در فرمتی قرار دارد که توسط این نسخه از حذف کننده قابل شناسایی نیست. حذف امکان پذیر نیست +UninstallUnknownEntry=با یک ورودی ناشناخته (%1) در فایل لاگ حذف مواجه شده است +ConfirmUninstall=آیا از حذف %1 و تمام اجزای آن اطمینان دارید؟ +UninstallOnlyOnWin64=این برنامه نصب شده تنها در ویندوز 64-بیت قابل حذف است. +OnlyAdminCanUninstall=این برنامه نصب شده، تنها توسط یک کاربر با دسترسی مدیر قابل حذف است. +UninstallStatusLabel=لطفاً تا زمان حذف %1 از کامپیوتر شما صبر کنید. +UninstalledAll=%1 با موفقیت از روی کامپیوتر شما حذف شد. +UninstalledMost=%1 حذف تکمیل شد.%n%nبرخی از اجزاء را نمی‌توان حذف کرد. این موارد به صورت جداگانه قابل حذف هستند. +UninstalledAndNeedsRestart=برای تکمیل حذف %1 کامپیوتر شما باید مجدداً راه‌اندازی شود.%n%nآیا مایل هستید هم‌اکنون ری‌استارت شود؟ +UninstallDataCorrupted="%1" فایل ناقص است. حذف امکان پذیر نیست ; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle= ј Ͽ -ConfirmDeleteSharedFile2= ǘ . ǘ Ͽ%n%nǐ 흘 ϡ . ǐ . Ԙ -SharedFileNameLabel= : -SharedFileLocationLabel=: -WizardUninstalling= -StatusUninstalling=...%1 +ConfirmDeleteSharedFileTitle=حذف فایل اشتراکی؟ +ConfirmDeleteSharedFile2=سیستم نشان می‌دهد که فایل اشتراکی زیر دیگر توسط هیچ برنامه دیگری در حال استفاده نیست. آیا مایل هستید که حذف کننده این فایل اشتراکی را حذف کند؟?%n%nاگر برنامه‌هایی هنوز از این فایل استفاده می‌کنند، با حذف این فایل این برنامه‌ها ممکن است به درستی کار نکنند. اگر مطمئن نیستید، خیر را انتخاب کنید. نگه‌داشتن فایل بر روی سیستم شما هیچ آسیبی نمی‌رساند. +SharedFileNameLabel=نام فایل: +SharedFileLocationLabel=محل فایل: +WizardUninstalling=وضعیت حذف +StatusUninstalling=در حال حذف %1... ; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=%1 -ShutdownBlockReasonUninstallingApp=%1 +ShutdownBlockReasonInstallingApp=در حال نصب %1. +ShutdownBlockReasonUninstallingApp=در حال حذف %1. ; The custom messages below aren't used by Setup itself, but if you make ; use of them in your scripts, you'll want to translate them. [CustomMessages] -NameAndVersion=%1 %2 -AdditionalIcons= : -CreateDesktopIcon= Әǁ -CreateQuickLaunchIcon= -ProgramOnTheWeb=%1 -UninstallProgram=%1 -LaunchProgram=%1 -AssocFileExtension= %1 %2 & -AssocingFileExtension= %1 %2 -AutoStartProgramGroupDescription= : -AutoStartProgram=%1 Ϙ -AddonHostProgramNotFound=%1 .%n%n Ͽ +NameAndVersion=%1 نسخه %2 +AdditionalIcons=میانبر های جانبی: +CreateDesktopIcon=ایجاد &میانبر روی دسکتاپ +CreateQuickLaunchIcon=ایجاد یک میانبر اجرای &سریع +ProgramOnTheWeb=%1 بر روی وب +UninstallProgram=حذف %1 +LaunchProgram=اجرای %1 +AssocFileExtension=&اختصاص دادن %1 با پسوند فایل %2 +AssocingFileExtension=در حال اختصاص %1 با پسوند فایل %2... +AutoStartProgramGroupDescription=شروع همراه با ویندوز: +AutoStartProgram=شروع خودکار %1 +AddonHostProgramNotFound=%1 در پوشه انتخاب شده یافت نشد.%n%nآیا بهرحال مایل به ادامه هستید؟ \ No newline at end of file diff --git a/installer/innosetup/Languages/Finnish.isl b/installer/innosetup/Languages/Finnish.isl new file mode 100644 index 000000000..17a5f2582 --- /dev/null +++ b/installer/innosetup/Languages/Finnish.isl @@ -0,0 +1,359 @@ +; *** Inno Setup version 6.1.0+ Finnish messages *** +; +; Finnish translation by Antti Karttunen +; E-mail: antti.j.karttunen@iki.fi +; Last modification date: 2020-08-02 + +[LangOptions] +LanguageName=Suomi +LanguageID=$040B +LanguageCodePage=1252 + +[Messages] + +; *** Application titles +SetupAppTitle=Asennus +SetupWindowTitle=%1 - Asennus +UninstallAppTitle=Asennuksen poisto +UninstallAppFullTitle=%1 - Asennuksen poisto + +; *** Misc. common +InformationTitle=Ilmoitus +ConfirmTitle=Varmistus +ErrorTitle=Virhe + +; *** SetupLdr messages +SetupLdrStartupMessage=Tll asennusohjelmalla asennetaan %1. Haluatko jatkaa? +LdrCannotCreateTemp=Vliaikaistiedostoa ei voitu luoda. Asennus keskeytettiin +LdrCannotExecTemp=Vliaikaisessa hakemistossa olevaa tiedostoa ei voitu suorittaa. Asennus keskeytettiin + +; *** Startup error messages +LastErrorMessage=%1.%n%nVirhe %2: %3 +SetupFileMissing=Tiedostoa %1 ei lydy asennushakemistosta. Korjaa ongelma tai hanki uusi kopio ohjelmasta. +SetupFileCorrupt=Asennustiedostot ovat vaurioituneet. Hanki uusi kopio ohjelmasta. +SetupFileCorruptOrWrongVer=Asennustiedostot ovat vaurioituneet tai ovat epyhteensopivia tmn Asennuksen version kanssa. Korjaa ongelma tai hanki uusi kopio ohjelmasta. +InvalidParameter=Virheellinen komentoriviparametri:%n%n%1 +SetupAlreadyRunning=Asennus on jo kynniss. +WindowsVersionNotSupported=Tm ohjelma ei tue kytss olevaa Windowsin versiota. +WindowsServicePackRequired=Tm ohjelma vaatii %1 Service Pack %2 -pivityksen tai myhemmn. +NotOnThisPlatform=Tm ohjelma ei toimi %1-kyttjrjestelmss. +OnlyOnThisPlatform=Tm ohjelma toimii vain %1-kyttjrjestelmss. +OnlyOnTheseArchitectures=Tm ohjelma voidaan asentaa vain niihin Windowsin versioihin, jotka on suunniteltu seuraaville prosessorityypeille:%n%n%1 +WinVersionTooLowError=Tm ohjelma vaatii version %2 tai myhemmn %1-kyttjrjestelmst. +WinVersionTooHighError=Tt ohjelmaa ei voi asentaa %1-kyttjrjestelmn versioon %2 tai myhempn. +AdminPrivilegesRequired=Sinun tytyy kirjautua sisn jrjestelmnvalvojana asentaaksesi tmn ohjelman. +PowerUserPrivilegesRequired=Sinun tytyy kirjautua sisn jrjestelmnvalvojana tai tehokyttjn asentaaksesi tmn ohjelman. +SetupAppRunningError=Asennus lysi kynniss olevan kopion ohjelmasta %1.%n%nSulje kaikki kynniss olevat kopiot ohjelmasta ja valitse OK jatkaaksesi, tai valitse Peruuta poistuaksesi. +UninstallAppRunningError=Asennuksen poisto lysi kynniss olevan kopion ohjelmasta %1.%n%nSulje kaikki kynniss olevat kopiot ohjelmasta ja valitse OK jatkaaksesi, tai valitse Peruuta poistuaksesi. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Valitse asennustapa +PrivilegesRequiredOverrideInstruction=Valitse, kenen kyttn ohjelma asennetaan +PrivilegesRequiredOverrideText1=%1 voidaan asentaa kaikille kyttjille (vaatii jrjestelmnvalvojan oikeudet) tai vain sinun kyttsi. +PrivilegesRequiredOverrideText2=%1 voidaan asentaa vain sinun kyttsi tai kaikille kyttjille (vaatii jrjestelmnvalvojan oikeudet). +PrivilegesRequiredOverrideAllUsers=Asenna &kaikille kyttjille +PrivilegesRequiredOverrideAllUsersRecommended=Asenna &kaikille kyttjille (suositus) +PrivilegesRequiredOverrideCurrentUser=Asenna vain &minun kyttni +PrivilegesRequiredOverrideCurrentUserRecommended=Asenna vain &minun kyttni (suositus) + +; *** Misc. errors +ErrorCreatingDir=Asennus ei voinut luoda hakemistoa "%1" +ErrorTooManyFilesInDir=Tiedoston luominen hakemistoon "%1" eponnistui, koska se sislt liian monta tiedostoa + +; *** Setup common messages +ExitSetupTitle=Poistu Asennuksesta +ExitSetupMessage=Asennus ei ole valmis. Jos lopetat nyt, ohjelmaa ei asenneta.%n%nVoit ajaa Asennuksen toiste asentaaksesi ohjelman.%n%nLopetetaanko Asennus? +AboutSetupMenuItem=&Tietoja Asennuksesta... +AboutSetupTitle=Tietoja Asennuksesta +AboutSetupMessage=%1 versio %2%n%3%n%n%1 -ohjelman kotisivu:%n%4 +AboutSetupNote= +TranslatorNote=Suomenkielinen knns: Antti Karttunen (antti.j.karttunen@iki.fi) + +; *** Buttons +ButtonBack=< &Takaisin +ButtonNext=&Seuraava > +ButtonInstall=&Asenna +ButtonOK=OK +ButtonCancel=Peruuta +ButtonYes=&Kyll +ButtonYesToAll=Kyll k&aikkiin +ButtonNo=&Ei +ButtonNoToAll=E&i kaikkiin +ButtonFinish=&Lopeta +ButtonBrowse=S&elaa... +ButtonWizardBrowse=S&elaa... +ButtonNewFolder=&Luo uusi kansio + +; *** "Select Language" dialog messages +SelectLanguageTitle=Valitse Asennuksen kieli +SelectLanguageLabel=Valitse asentamisen aikana kytettv kieli. + +; *** Common wizard text +ClickNext=Valitse Seuraava jatkaaksesi tai Peruuta poistuaksesi. +BeveledLabel= +BrowseDialogTitle=Selaa kansioita +BrowseDialogLabel=Valitse kansio allaolevasta listasta ja valitse sitten OK jatkaaksesi. +NewFolderName=Uusi kansio + +; *** "Welcome" wizard page +WelcomeLabel1=Tervetuloa [name] -asennusohjelmaan. +WelcomeLabel2=Tll asennusohjelmalla koneellesi asennetaan [name/ver]. %n%nOn suositeltavaa, ett suljet kaikki muut kynniss olevat sovellukset ennen jatkamista. Tm auttaa vlttmn ristiriitatilanteita asennuksen aikana. + +; *** "Password" wizard page +WizardPassword=Salasana +PasswordLabel1=Tm asennusohjelma on suojattu salasanalla. +PasswordLabel3=Anna salasana ja valitse sitten Seuraava jatkaaksesi.%n%nIsot ja pienet kirjaimet ovat eriarvoisia. +PasswordEditLabel=&Salasana: +IncorrectPassword=Antamasi salasana oli virheellinen. Anna salasana uudelleen. + +; *** "License Agreement" wizard page +WizardLicense=Kyttoikeussopimus +LicenseLabel=Lue seuraava trke tiedotus ennen kuin jatkat. +LicenseLabel3=Lue seuraava kyttoikeussopimus tarkasti. Sinun tytyy hyvksy sopimus, jos haluat jatkaa asentamista. +LicenseAccepted=&Hyvksyn sopimuksen +LicenseNotAccepted=&En hyvksy sopimusta + +; *** "Information" wizard pages +WizardInfoBefore=Tiedotus +InfoBeforeLabel=Lue seuraava trke tiedotus ennen kuin jatkat. +InfoBeforeClickLabel=Kun olet valmis jatkamaan asentamista, valitse Seuraava. +WizardInfoAfter=Tiedotus +InfoAfterLabel=Lue seuraava trke tiedotus ennen kuin jatkat. +InfoAfterClickLabel=Kun olet valmis jatkamaan asentamista, valitse Seuraava. + +; *** "Select Destination Directory" wizard page +WizardUserInfo=Kyttjtiedot +UserInfoDesc=Anna pyydetyt tiedot. +UserInfoName=Kyttjn &nimi: +UserInfoOrg=&Yritys: +UserInfoSerial=&Tunnuskoodi: +UserInfoNameRequired=Sinun tytyy antaa nimi. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Valitse kohdekansio +SelectDirDesc=Mihin [name] asennetaan? +SelectDirLabel3=[name] asennetaan thn kansioon. +SelectDirBrowseLabel=Valitse Seuraava jatkaaksesi. Jos haluat vaihtaa kansiota, valitse Selaa. +DiskSpaceGBLabel=Vapaata levytilaa tarvitaan vhintn [gb] Gt. +DiskSpaceMBLabel=Vapaata levytilaa tarvitaan vhintn [mb] Mt. +CannotInstallToNetworkDrive=Asennus ei voi asentaa ohjelmaa verkkoasemalle. +CannotInstallToUNCPath=Asennus ei voi asentaa ohjelmaa UNC-polun alle. +InvalidPath=Anna tydellinen polku levyaseman kirjaimen kanssa. Esimerkiksi %nC:\OHJELMA%n%ntai UNC-polku muodossa %n%n\\palvelin\resurssi +InvalidDrive=Valitsemaasi asemaa tai UNC-polkua ei ole olemassa tai sit ei voi kytt. Valitse toinen asema tai UNC-polku. +DiskSpaceWarningTitle=Ei tarpeeksi vapaata levytilaa +DiskSpaceWarning=Asennus vaatii vhintn %1 kt vapaata levytilaa, mutta valitulla levyasemalla on vain %2 kt vapaata levytilaa.%n%nHaluatko jatkaa tst huolimatta? +DirNameTooLong=Kansion nimi tai polku on liian pitk. +InvalidDirName=Virheellinen kansion nimi. +BadDirName32=Kansion nimess ei saa olla seuraavia merkkej:%n%n%1 +DirExistsTitle=Kansio on olemassa +DirExists=Kansio:%n%n%1%n%non jo olemassa. Haluatko kuitenkin suorittaa asennuksen thn kansioon? +DirDoesntExistTitle=Kansiota ei ole olemassa +DirDoesntExist=Kansiota%n%n%1%n%nei ole olemassa. Luodaanko kansio? + +; *** "Select Components" wizard page +WizardSelectComponents=Valitse asennettavat osat +SelectComponentsDesc=Mitk osat asennetaan? +SelectComponentsLabel2=Valitse ne osat, jotka haluat asentaa, ja poista niiden osien valinta, joita et halua asentaa. Valitse Seuraava, kun olet valmis. +FullInstallation=Normaali asennus +CompactInstallation=Suppea asennus +CustomInstallation=Mukautettu asennus +NoUninstallWarningTitle=Asennettuja osia lydettiin +NoUninstallWarning=Seuraavat osat on jo asennettu koneelle:%n%n%1%n%nNiden osien valinnan poistaminen ei poista niit koneelta.%n%nHaluatko jatkaa tst huolimatta? +ComponentSize1=%1 kt +ComponentSize2=%1 Mt +ComponentsDiskSpaceGBLabel=Nykyiset valinnat vaativat vhintn [gb] Gt levytilaa. +ComponentsDiskSpaceMBLabel=Nykyiset valinnat vaativat vhintn [mb] Mt levytilaa. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Valitse muut toiminnot +SelectTasksDesc=Mit muita toimintoja suoritetaan? +SelectTasksLabel2=Valitse muut toiminnot, jotka haluat Asennuksen suorittavan samalla kun [name] asennetaan. Valitse Seuraava, kun olet valmis. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Valitse Kynnist-valikon kansio +SelectStartMenuFolderDesc=Mihin ohjelman pikakuvakkeet sijoitetaan? +SelectStartMenuFolderLabel3=Ohjelman pikakuvakkeet luodaan thn Kynnist-valikon kansioon. +SelectStartMenuFolderBrowseLabel=Valitse Seuraava jatkaaksesi. Jos haluat vaihtaa kansiota, valitse Selaa. +MustEnterGroupName=Kansiolle pit antaa nimi. +GroupNameTooLong=Kansion nimi tai polku on liian pitk. +InvalidGroupName=Virheellinen kansion nimi. +BadGroupName=Kansion nimess ei saa olla seuraavia merkkej:%n%n%1 +NoProgramGroupCheck2=l luo k&ansiota Kynnist-valikkoon + +; *** "Ready to Install" wizard page +WizardReady=Valmiina asennukseen +ReadyLabel1=[name] on nyt valmis asennettavaksi. +ReadyLabel2a=Valitse Asenna jatkaaksesi asentamista tai valitse Takaisin, jos haluat tarkastella tekemisi asetuksia tai muuttaa niit. +ReadyLabel2b=Valitse Asenna jatkaaksesi asentamista. +ReadyMemoUserInfo=Kyttjtiedot: +ReadyMemoDir=Kohdekansio: +ReadyMemoType=Asennustyyppi: +ReadyMemoComponents=Asennettavaksi valitut osat: +ReadyMemoGroup=Kynnist-valikon kansio: +ReadyMemoTasks=Muut toiminnot: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Ladataan tarvittavia tiedostoja... +ButtonStopDownload=&Pysyt lataus +StopDownload=Oletko varma, ett haluat pysytt tiedostojen latauksen? +ErrorDownloadAborted=Tiedostojen lataaminen keskeytettiin +ErrorDownloadFailed=Tiedoston lataaminen eponnistui: %1 %2 +ErrorDownloadSizeFailed=Latauksen koon noutaminen eponnistui: %1 %2 +ErrorFileHash1=Tiedoston tiivisteen luominen eponnistui: %1 +ErrorFileHash2=Tiedoston tiiviste on virheellinen: odotettu %1, lydetty %2 +ErrorProgress=Virheellinen edistyminen: %1 / %2 +ErrorFileSize=Virheellinen tiedoston koko: odotettu %1, lydetty %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Valmistellaan asennusta +PreparingDesc=Valmistaudutaan asentamaan [name] koneellesi. +PreviousInstallNotCompleted=Edellisen ohjelman asennus tai asennuksen poisto ei ole valmis. Sinun tytyy kynnist kone uudelleen viimeistellksesi edellisen asennuksen.%n%nAja [name] -asennusohjelma uudestaan, kun olet kynnistnyt koneen uudelleen. +CannotContinue=Asennusta ei voida jatkaa. Valitse Peruuta poistuaksesi. +ApplicationsFound=Seuraavat sovellukset kyttvt tiedostoja, joita Asennuksen pit pivitt. On suositeltavaa, ett annat Asennuksen sulkea nm sovellukset automaattisesti. +ApplicationsFound2=Seuraavat sovellukset kyttvt tiedostoja, joita Asennuksen pit pivitt. On suositeltavaa, ett annat Asennuksen sulkea nm sovellukset automaattisesti. Valmistumisen jlkeen Asennus yritt uudelleenkynnist sovellukset. +CloseApplications=&Sulje sovellukset automaattisesti +DontCloseApplications=&l sulje sovelluksia +ErrorCloseApplications=Asennus ei pystynyt sulkemaan tarvittavia sovelluksia automaattisesti. On suositeltavaa, ett ennen jatkamista suljet sovellukset, jotka kyttvt asennuksen aikana pivitettvi tiedostoja. +PrepareToInstallNeedsRestart=Asennuksen tytyy kynnist tietokone uudelleen. Aja Asennus uudelleenkynnistyksen jlkeen, jotta [name] voidaan asentaa.%n%nHaluatko kynnist tietokoneen uudelleen nyt? + +; *** "Installing" wizard page +WizardInstalling=Asennus kynniss +InstallingLabel=Odota, kun [name] asennetaan koneellesi. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name] - Asennuksen viimeistely +FinishedLabelNoIcons=[name] on nyt asennettu koneellesi. +FinishedLabel=[name] on nyt asennettu. Sovellus voidaan kynnist valitsemalla jokin asennetuista kuvakkeista. +ClickFinish=Valitse Lopeta poistuaksesi Asennuksesta. +FinishedRestartLabel=Jotta [name] saataisiin asennettua loppuun, pit kone kynnist uudelleen. Haluatko kynnist koneen uudelleen nyt? +FinishedRestartMessage=Jotta [name] saataisiin asennettua loppuun, pit kone kynnist uudelleen.%n%nHaluatko kynnist koneen uudelleen nyt? +ShowReadmeCheck=Kyll, haluan nhd LUEMINUT-tiedoston +YesRadio=&Kyll, kynnist kone uudelleen +NoRadio=&Ei, kynnistn koneen uudelleen myhemmin +RunEntryExec=Kynnist %1 +RunEntryShellExec=Nyt %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Asennus tarvitsee seuraavan levykkeen +SelectDiskLabel2=Aseta levyke %1 asemaan ja valitse OK. %n%nJos joku toinen kansio sislt levykkeen tiedostot, anna oikea polku tai valitse Selaa. +PathLabel=&Polku: +FileNotInDir2=Tiedostoa "%1" ei lytynyt lhteest "%2". Aseta oikea levyke asemaan tai valitse toinen kansio. +SelectDirectoryLabel=Mrit seuraavan levykkeen sislln sijainti. + +; *** Installation phase messages +SetupAborted=Asennusta ei suoritettu loppuun.%n%nKorjaa ongelma ja suorita Asennus uudelleen. +AbortRetryIgnoreSelectAction=Valitse toiminto +AbortRetryIgnoreRetry=&Yrit uudelleen +AbortRetryIgnoreIgnore=&Jatka virheest huolimatta +AbortRetryIgnoreCancel=Peruuta asennus + +; *** Installation status messages +StatusClosingApplications=Suljetaan sovellukset... +StatusCreateDirs=Luodaan hakemistoja... +StatusExtractFiles=Puretaan tiedostoja... +StatusCreateIcons=Luodaan pikakuvakkeita... +StatusCreateIniEntries=Luodaan INI-merkintj... +StatusCreateRegistryEntries=Luodaan rekisterimerkintj... +StatusRegisterFiles=Rekisteridn tiedostoja... +StatusSavingUninstall=Tallennetaan Asennuksen poiston tietoja... +StatusRunProgram=Viimeistelln asennusta... +StatusRestartingApplications=Uudelleenkynnistetn sovellukset... +StatusRollback=Peruutetaan tehdyt muutokset... + +; *** Misc. errors +ErrorInternal2=Sisinen virhe: %1 +ErrorFunctionFailedNoCode=%1 eponnistui +ErrorFunctionFailed=%1 eponnistui; virhekoodi %2 +ErrorFunctionFailedWithMessage=%1 eponnistui; virhekoodi %2.%n%3 +ErrorExecutingProgram=Virhe suoritettaessa tiedostoa%n%1 + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Asennetaan %1. +ShutdownBlockReasonUninstallingApp=Poistetaan %1. + +; *** Registry errors +ErrorRegOpenKey=Virhe avattaessa rekisteriavainta%n%1\%2 +ErrorRegCreateKey=Virhe luotaessa rekisteriavainta%n%1\%2 +ErrorRegWriteKey=Virhe kirjoitettaessa rekisteriavaimeen%n%1\%2 + +; *** INI errors +ErrorIniEntry=Virhe luotaessa INI-merkint tiedostoon "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Ohita tm tiedosto (ei suositeltavaa) +FileAbortRetryIgnoreIgnoreNotRecommended=&Jatka virheest huolimatta (ei suositeltavaa) +SourceIsCorrupted=Lhdetiedosto on vaurioitunut +SourceDoesntExist=Lhdetiedostoa "%1" ei ole olemassa +ExistingFileReadOnly2=Nykyist tiedostoa ei voitu korvata, koska se on Vain luku -tiedosto. +ExistingFileReadOnlyRetry=&Poista Vain luku -asetus ja yrit uudelleen +ExistingFileReadOnlyKeepExisting=&Silyt nykyinen tiedosto +ErrorReadingExistingDest=Virhe luettaessa nykyist tiedostoa: +FileExistsSelectAction=Valitse toiminto +FileExists2=Tiedosto on jo olemassa. +FileExistsOverwriteExisting=Korvaa &olemassa oleva tiedosto +FileExistsKeepExisting=&Silyt olemassa oleva tiedosto +FileExistsOverwriteOrKeepAll=&Hoida muut vastaavat tilanteet samalla tavalla +ExistingFileNewerSelectAction=Valitse toiminto +ExistingFileNewer2=Olemassa oleva tiedosto on uudempi kuin Asennuksen sisltm tiedosto. +ExistingFileNewerOverwriteExisting=Korvaa &olemassa oleva tiedosto +ExistingFileNewerKeepExisting=&Silyt olemassa oleva tiedosto (suositeltavaa) +ExistingFileNewerOverwriteOrKeepAll=&Hoida muut vastaavat tilanteet samalla tavalla +ErrorChangingAttr=Virhe vaihdettaessa nykyisen tiedoston mritteit: +ErrorCreatingTemp=Virhe luotaessa tiedostoa kohdehakemistoon: +ErrorReadingSource=Virhe luettaessa lhdetiedostoa: +ErrorCopying=Virhe kopioitaessa tiedostoa: +ErrorReplacingExistingFile=Virhe korvattaessa nykyist tiedostoa: +ErrorRestartReplace=RestartReplace-komento eponnistui: +ErrorRenamingTemp=Virhe uudelleennimettess tiedostoa kohdehakemistossa: +ErrorRegisterServer=DLL/OCX -laajennuksen rekisterinti eponnistui: %1 +ErrorRegSvr32Failed=RegSvr32-toiminto eponnistui. Virhekoodi: %1 +ErrorRegisterTypeLib=Tyyppikirjaston rekisteriminen eponnistui: %1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bittinen +UninstallDisplayNameMark64Bit=64-bittinen +UninstallDisplayNameMarkAllUsers=Kaikki kyttjt +UninstallDisplayNameMarkCurrentUser=Tmnhetkinen kyttj + +; *** Post-installation errors +ErrorOpeningReadme=Virhe avattaessa LUEMINUT-tiedostoa. +ErrorRestartingComputer=Koneen uudelleenkynnistminen ei onnistunut. Suorita uudelleenkynnistys itse. + +; *** Uninstaller messages +UninstallNotFound=Tiedostoa "%1" ei lytynyt. Asennuksen poisto ei onnistu. +UninstallOpenError=Tiedostoa "%1" ei voitu avata. Asennuksen poisto ei onnistu. +UninstallUnsupportedVer=Tm versio Asennuksen poisto-ohjelmasta ei pysty lukemaan lokitiedostoa "%1". Asennuksen poisto ei onnistu +UninstallUnknownEntry=Asennuksen poisto-ohjelman lokitiedostosta lytyi tuntematon merkint (%1) +ConfirmUninstall=Poistetaanko %1 ja kaikki sen osat? +UninstallOnlyOnWin64=Tm ohjelma voidaan poistaa vain 64-bittisest Windowsista ksin. +OnlyAdminCanUninstall=Tmn asennuksen poistaminen vaatii jrjestelmnvalvojan oikeudet. +UninstallStatusLabel=Odota, kun %1 poistetaan koneeltasi. +UninstalledAll=%1 poistettiin onnistuneesti. +UninstalledMost=%1 poistettiin koneelta.%n%nJoitakin osia ei voitu poistaa. Voit poistaa osat itse. +UninstalledAndNeedsRestart=Kone tytyy kynnist uudelleen, jotta %1 voidaan poistaa kokonaan.%n%nHaluatko kynnist koneen uudeelleen nyt? +UninstallDataCorrupted=Tiedosto "%1" on vaurioitunut. Asennuksen poisto ei onnistu. + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Poistetaanko jaettu tiedosto? +ConfirmDeleteSharedFile2=Jrjestelmn mukaan seuraava jaettu tiedosto ei ole en minkn muun sovelluksen kytss. Poistetaanko tiedosto?%n%nJos jotkut sovellukset kyttvt viel tt tiedostoa ja se poistetaan, ne eivt vlttmtt toimi en kunnolla. Jos olet epvarma, valitse Ei. Tiedoston jttminen koneelle ei aiheuta ongelmia. +SharedFileNameLabel=Tiedoston nimi: +SharedFileLocationLabel=Sijainti: +WizardUninstalling=Asennuksen poiston tila +StatusUninstalling=Poistetaan %1... + +[CustomMessages] + +NameAndVersion=%1 versio %2 +AdditionalIcons=Liskuvakkeet: +CreateDesktopIcon=Lu&o kuvake typydlle +CreateQuickLaunchIcon=Luo kuvake &pikakynnistyspalkkiin +ProgramOnTheWeb=%1 Internetiss +UninstallProgram=Poista %1 +LaunchProgram=&Kynnist %1 +AssocFileExtension=&Yhdist %1 tiedostoptteeseen %2 +AssocingFileExtension=Yhdistetn %1 tiedostoptteeseen %2 ... +AutoStartProgramGroupDescription=Kynnistys: +AutoStartProgram=Kynnist %1 automaattisesti +AddonHostProgramNotFound=%1 ei ole valitsemassasi kansiossa.%n%nHaluatko jatkaa tst huolimatta? diff --git a/installer/innosetup/Languages/French.isl b/installer/innosetup/Languages/French.isl new file mode 100644 index 000000000..7c8db9232 --- /dev/null +++ b/installer/innosetup/Languages/French.isl @@ -0,0 +1,404 @@ +; *** Inno Setup version 6.1.0+ French messages *** +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). +; +; Maintained by Pierre Yager (pierre@levosgien.net) +; +; Contributors : Frédéric Bonduelle, Francis Pallini, Lumina, Pascal Peyrot +; +; Changes : +; + Accents on uppercase letters +; http://www.academie-francaise.fr/langue/questions.html#accentuation (lumina) +; + Typography quotes [see ISBN: 978-2-7433-0482-9] +; http://fr.wikipedia.org/wiki/Guillemet (lumina) +; + Binary units (Kio, Mio) [IEC 80000-13:2008] +; http://fr.wikipedia.org/wiki/Octet (lumina) +; + Reverted to standard units (Ko, Mo) to follow Windows Explorer Standard +; http://blogs.msdn.com/b/oldnewthing/archive/2009/06/11/9725386.aspx +; + Use more standard verbs for click and retry +; "click": "Clicker" instead of "Appuyer" +; "retry": "Recommencer" au lieu de "Réessayer" +; + Added new 6.0.0 messages +; + Added new 6.1.0 messages + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Français +LanguageID=$040C +LanguageCodePage=1252 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=Installation +SetupWindowTitle=Installation - %1 +UninstallAppTitle=Désinstallation +UninstallAppFullTitle=Désinstallation - %1 + +; *** Misc. common +InformationTitle=Information +ConfirmTitle=Confirmation +ErrorTitle=Erreur + +; *** SetupLdr messages +SetupLdrStartupMessage=Cet assistant va installer %1. Voulez-vous continuer ? +LdrCannotCreateTemp=Impossible de créer un fichier temporaire. Abandon de l'installation +LdrCannotExecTemp=Impossible d'exécuter un fichier depuis le dossier temporaire. Abandon de l'installation +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nErreur %2 : %3 +SetupFileMissing=Le fichier %1 est absent du dossier d'installation. Veuillez corriger le problème ou vous procurer une nouvelle copie du programme. +SetupFileCorrupt=Les fichiers d'installation sont altérés. Veuillez vous procurer une nouvelle copie du programme. +SetupFileCorruptOrWrongVer=Les fichiers d'installation sont altérés ou ne sont pas compatibles avec cette version de l'assistant d'installation. Veuillez corriger le problème ou vous procurer une nouvelle copie du programme. +InvalidParameter=Un paramètre non valide a été passé à la ligne de commande :%n%n%1 +SetupAlreadyRunning=L'assistant d'installation est déjà en cours d'exécution. +WindowsVersionNotSupported=Ce programme n'est pas prévu pour fonctionner avec la version de Windows utilisée sur votre ordinateur. +WindowsServicePackRequired=Ce programme a besoin de %1 Service Pack %2 ou d'une version plus récente. +NotOnThisPlatform=Ce programme ne fonctionne pas sous %1. +OnlyOnThisPlatform=Ce programme ne peut fonctionner que sous %1. +OnlyOnTheseArchitectures=Ce programme ne peut être installé que sur des versions de Windows qui supportent ces architectures : %n%n%1 +WinVersionTooLowError=Ce programme requiert la version %2 ou supérieure de %1. +WinVersionTooHighError=Ce programme ne peut pas être installé sous %1 version %2 ou supérieure. +AdminPrivilegesRequired=Vous devez disposer des droits d'administration de cet ordinateur pour installer ce programme. +PowerUserPrivilegesRequired=Vous devez disposer des droits d'administration ou faire partie du groupe « Utilisateurs avec pouvoir » de cet ordinateur pour installer ce programme. +SetupAppRunningError=L'assistant d'installation a détecté que %1 est actuellement en cours d'exécution.%n%nVeuillez fermer toutes les instances de cette application puis cliquer sur OK pour continuer, ou bien cliquer sur Annuler pour abandonner l'installation. +UninstallAppRunningError=La procédure de désinstallation a détecté que %1 est actuellement en cours d'exécution.%n%nVeuillez fermer toutes les instances de cette application puis cliquer sur OK pour continuer, ou bien cliquer sur Annuler pour abandonner la désinstallation. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Choix du Mode d'Installation +PrivilegesRequiredOverrideInstruction=Choisissez le mode d'installation +PrivilegesRequiredOverrideText1=%1 peut être installé pour tous les utilisateurs (nécessite des privilèges administrateur), ou seulement pour vous. +PrivilegesRequiredOverrideText2=%1 peut-être installé seulement pour vous, ou pour tous les utilisateurs (nécessite des privilèges administrateur). +PrivilegesRequiredOverrideAllUsers=Installer pour &tous les utilisateurs +PrivilegesRequiredOverrideAllUsersRecommended=Installer pour &tous les utilisateurs (recommandé) +PrivilegesRequiredOverrideCurrentUser=Installer seulement pour &moi +PrivilegesRequiredOverrideCurrentUserRecommended=Installer seulement pour &moi (recommandé) + +; *** Misc. errors +ErrorCreatingDir=L'assistant d'installation n'a pas pu créer le dossier "%1" +ErrorTooManyFilesInDir=L'assistant d'installation n'a pas pu créer un fichier dans le dossier "%1" car celui-ci contient trop de fichiers + +; *** Setup common messages +ExitSetupTitle=Quitter l'installation +ExitSetupMessage=L'installation n'est pas terminée. Si vous abandonnez maintenant, le programme ne sera pas installé.%n%nVous devrez relancer cet assistant pour finir l'installation.%n%nVoulez-vous quand même quitter l'assistant d'installation ? +AboutSetupMenuItem=À &propos... +AboutSetupTitle=À Propos de l'assistant d'installation +AboutSetupMessage=%1 version %2%n%3%n%nPage d'accueil de %1 :%n%4 +AboutSetupNote= +TranslatorNote=Traduction française maintenue par Pierre Yager (pierre@levosgien.net) + +; *** Buttons +ButtonBack=< &Précédent +ButtonNext=&Suivant > +ButtonInstall=&Installer +ButtonOK=OK +ButtonCancel=Annuler +ButtonYes=&Oui +ButtonYesToAll=Oui pour &tout +ButtonNo=&Non +ButtonNoToAll=N&on pour tout +ButtonFinish=&Terminer +ButtonBrowse=Pa&rcourir... +ButtonWizardBrowse=Pa&rcourir... +ButtonNewFolder=Nouveau &dossier + +; *** "Select Language" dialog messages +SelectLanguageTitle=Langue de l'assistant d'installation +SelectLanguageLabel=Veuillez sélectionner la langue qui sera utilisée par l'assistant d'installation. + +; *** Common wizard text +ClickNext=Cliquez sur Suivant pour continuer ou sur Annuler pour abandonner l'installation. +BeveledLabel= +BrowseDialogTitle=Parcourir les dossiers +BrowseDialogLabel=Veuillez choisir un dossier de destination, puis cliquez sur OK. +NewFolderName=Nouveau dossier + +; *** "Welcome" wizard page +WelcomeLabel1=Bienvenue dans l'assistant d'installation de [name] +WelcomeLabel2=Cet assistant va vous guider dans l'installation de [name/ver] sur votre ordinateur.%n%nIl est recommandé de fermer toutes les applications actives avant de continuer. + +; *** "Password" wizard page +WizardPassword=Mot de passe +PasswordLabel1=Cette installation est protégée par un mot de passe. +PasswordLabel3=Veuillez saisir le mot de passe (attention à la distinction entre majuscules et minuscules) puis cliquez sur Suivant pour continuer. +PasswordEditLabel=&Mot de passe : +IncorrectPassword=Le mot de passe saisi n'est pas valide. Veuillez essayer à nouveau. + +; *** "License Agreement" wizard page +WizardLicense=Accord de licence +LicenseLabel=Les informations suivantes sont importantes. Veuillez les lire avant de continuer. +LicenseLabel3=Veuillez lire le contrat de licence suivant. Vous devez en accepter tous les termes avant de continuer l'installation. +LicenseAccepted=Je comprends et j'&accepte les termes du contrat de licence +LicenseNotAccepted=Je &refuse les termes du contrat de licence + +; *** "Information" wizard pages +WizardInfoBefore=Information +InfoBeforeLabel=Les informations suivantes sont importantes. Veuillez les lire avant de continuer. +InfoBeforeClickLabel=Lorsque vous êtes prêt à continuer, cliquez sur Suivant. +WizardInfoAfter=Information +InfoAfterLabel=Les informations suivantes sont importantes. Veuillez les lire avant de continuer. +InfoAfterClickLabel=Lorsque vous êtes prêt à continuer, cliquez sur Suivant. + +; *** "User Information" wizard page +WizardUserInfo=Informations sur l'Utilisateur +UserInfoDesc=Veuillez saisir les informations qui vous concernent. +UserInfoName=&Nom d'utilisateur : +UserInfoOrg=&Organisation : +UserInfoSerial=Numéro de &série : +UserInfoNameRequired=Vous devez au moins saisir un nom. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Dossier de destination +SelectDirDesc=Où [name] doit-il être installé ? +SelectDirLabel3=L'assistant va installer [name] dans le dossier suivant. +SelectDirBrowseLabel=Pour continuer, cliquez sur Suivant. Si vous souhaitez choisir un dossier différent, cliquez sur Parcourir. +DiskSpaceGBLabel=Le programme requiert au moins [gb] Go d'espace disque disponible. +DiskSpaceMBLabel=Le programme requiert au moins [mb] Mo d'espace disque disponible. +CannotInstallToNetworkDrive=L'assistant ne peut pas installer sur un disque réseau. +CannotInstallToUNCPath=L'assistant ne peut pas installer sur un chemin UNC. +InvalidPath=Vous devez saisir un chemin complet avec sa lettre de lecteur ; par exemple :%n%nC:\APP%n%nou un chemin réseau de la forme :%n%n\\serveur\partage +InvalidDrive=L'unité ou l'emplacement réseau que vous avez sélectionné n'existe pas ou n'est pas accessible. Veuillez choisir une autre destination. +DiskSpaceWarningTitle=Espace disponible insuffisant +DiskSpaceWarning=L'assistant a besoin d'au moins %1 Ko d'espace disponible pour effectuer l'installation, mais l'unité que vous avez sélectionnée ne dispose que de %2 Ko d'espace disponible.%n%nSouhaitez-vous continuer malgré tout ? +DirNameTooLong=Le nom ou le chemin du dossier est trop long. +InvalidDirName=Le nom du dossier est invalide. +BadDirName32=Le nom du dossier ne doit contenir aucun des caractères suivants :%n%n%1 +DirExistsTitle=Dossier existant +DirExists=Le dossier :%n%n%1%n%nexiste déjà. Souhaitez-vous installer dans ce dossier malgré tout ? +DirDoesntExistTitle=Le dossier n'existe pas +DirDoesntExist=Le dossier %n%n%1%n%nn'existe pas. Souhaitez-vous que ce dossier soit créé ? + +; *** "Select Components" wizard page +WizardSelectComponents=Composants à installer +SelectComponentsDesc=Quels composants de l'application souhaitez-vous installer ? +SelectComponentsLabel2=Sélectionnez les composants que vous désirez installer ; décochez les composants que vous ne désirez pas installer. Cliquez ensuite sur Suivant pour continuer l'installation. +FullInstallation=Installation complète +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Installation compacte +CustomInstallation=Installation personnalisée +NoUninstallWarningTitle=Composants existants +NoUninstallWarning=L'assistant d'installation a détecté que les composants suivants sont déjà installés sur votre système :%n%n%1%n%nDésélectionner ces composants ne les désinstallera pas pour autant.%n%nVoulez-vous continuer malgré tout ? +ComponentSize1=%1 Ko +ComponentSize2=%1 Mo +ComponentsDiskSpaceGBLabel=Les composants sélectionnés nécessitent au moins [gb] Go d'espace disponible. +ComponentsDiskSpaceMBLabel=Les composants sélectionnés nécessitent au moins [mb] Mo d'espace disponible. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Tâches supplémentaires +SelectTasksDesc=Quelles sont les tâches supplémentaires qui doivent être effectuées ? +SelectTasksLabel2=Sélectionnez les tâches supplémentaires que l'assistant d'installation doit effectuer pendant l'installation de [name], puis cliquez sur Suivant. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Sélection du dossier du menu Démarrer +SelectStartMenuFolderDesc=Où l'assistant d'installation doit-il placer les raccourcis du programme ? +SelectStartMenuFolderLabel3=L'assistant va créer les raccourcis du programme dans le dossier du menu Démarrer indiqué ci-dessous. +SelectStartMenuFolderBrowseLabel=Cliquez sur Suivant pour continuer. Cliquez sur Parcourir si vous souhaitez sélectionner un autre dossier du menu Démarrer. +MustEnterGroupName=Vous devez saisir un nom de dossier du menu Démarrer. +GroupNameTooLong=Le nom ou le chemin du dossier est trop long. +InvalidGroupName=Le nom du dossier n'est pas valide. +BadGroupName=Le nom du dossier ne doit contenir aucun des caractères suivants :%n%n%1 +NoProgramGroupCheck2=Ne pas créer de &dossier dans le menu Démarrer + +; *** "Ready to Install" wizard page +WizardReady=Prêt à installer +ReadyLabel1=L'assistant dispose à présent de toutes les informations pour installer [name] sur votre ordinateur. +ReadyLabel2a=Cliquez sur Installer pour procéder à l'installation ou sur Précédent pour revoir ou modifier une option d'installation. +ReadyLabel2b=Cliquez sur Installer pour procéder à l'installation. +ReadyMemoUserInfo=Informations sur l'utilisateur : +ReadyMemoDir=Dossier de destination : +ReadyMemoType=Type d'installation : +ReadyMemoComponents=Composants sélectionnés : +ReadyMemoGroup=Dossier du menu Démarrer : +ReadyMemoTasks=Tâches supplémentaires : + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Téléchargement de fichiers supplémentaires... +ButtonStopDownload=&Arrêter le téléchargement +StopDownload=Êtes-vous sûr de vouloir arrêter le téléchargement ? +ErrorDownloadAborted=Téléchargement annulé +ErrorDownloadFailed=Le téléchargement a échoué : %1 %2 +ErrorDownloadSizeFailed=La récupération de la taille du fichier a échouée : %1 %2 +ErrorFileHash1=Le calcul de l'empreinte du fichier a échoué : %1 +ErrorFileHash2=Empreinte du fichier invalide : attendue %1, trouvée %2 +ErrorProgress=Progression invalide : %1 sur %2 +ErrorFileSize=Taille du fichier invalide : attendue %1, trouvée %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Préparation de l'installation +PreparingDesc=L'assistant d'installation prépare l'installation de [name] sur votre ordinateur. +PreviousInstallNotCompleted=L'installation ou la suppression d'un programme précédent n'est pas totalement achevée. Veuillez redémarrer votre ordinateur pour achever cette installation ou suppression.%n%nUne fois votre ordinateur redémarré, veuillez relancer cet assistant pour reprendre l'installation de [name]. +CannotContinue=L'assistant ne peut pas continuer. Veuillez cliquer sur Annuler pour abandonner l'installation. +ApplicationsFound=Les applications suivantes utilisent des fichiers qui doivent être mis à jour par l'assistant. Il est recommandé d'autoriser l'assistant à fermer ces applications automatiquement. +ApplicationsFound2=Les applications suivantes utilisent des fichiers qui doivent être mis à jour par l'assistant. Il est recommandé d'autoriser l'assistant à fermer ces applications automatiquement. Une fois l'installation terminée, l'assistant essaiera de relancer ces applications. +CloseApplications=&Arrêter les applications automatiquement +DontCloseApplications=&Ne pas arrêter les applications +ErrorCloseApplications=L'assistant d'installation n'a pas pu arrêter toutes les applications automatiquement. Nous vous recommandons de fermer toutes les applications qui utilisent des fichiers devant être mis à jour par l'assistant d'installation avant de continuer. +PrepareToInstallNeedsRestart=L'assistant d'installation doit redémarrer votre ordinateur. Une fois votre ordinateur redémarré, veuillez relancer cet assistant d'installation pour terminer l'installation de [name].%n%nVoulez-vous redémarrer votre ordinateur maintenant ? + +; *** "Installing" wizard page +WizardInstalling=Installation en cours +InstallingLabel=Veuillez patienter pendant que l'assistant installe [name] sur votre ordinateur. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Fin de l'installation de [name] +FinishedLabelNoIcons=L'assistant a terminé l'installation de [name] sur votre ordinateur. +FinishedLabel=L'assistant a terminé l'installation de [name] sur votre ordinateur. L'application peut être lancée à l'aide des icônes créées sur le Bureau par l'installation. +ClickFinish=Veuillez cliquer sur Terminer pour quitter l'assistant d'installation. +FinishedRestartLabel=L'assistant doit redémarrer votre ordinateur pour terminer l'installation de [name].%n%nVoulez-vous redémarrer maintenant ? +FinishedRestartMessage=L'assistant doit redémarrer votre ordinateur pour terminer l'installation de [name].%n%nVoulez-vous redémarrer maintenant ? +ShowReadmeCheck=Oui, je souhaite lire le fichier LISEZMOI +YesRadio=&Oui, redémarrer mon ordinateur maintenant +NoRadio=&Non, je préfère redémarrer mon ordinateur plus tard +; used for example as 'Run MyProg.exe' +RunEntryExec=Exécuter %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Voir %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=L'assistant a besoin du disque suivant +SelectDiskLabel2=Veuillez insérer le disque %1 et cliquer sur OK.%n%nSi les fichiers de ce disque se trouvent à un emplacement différent de celui indiqué ci-dessous, veuillez saisir le chemin correspondant ou cliquez sur Parcourir. +PathLabel=&Chemin : +FileNotInDir2=Le fichier "%1" ne peut pas être trouvé dans "%2". Veuillez insérer le bon disque ou sélectionner un autre dossier. +SelectDirectoryLabel=Veuillez indiquer l'emplacement du disque suivant. + +; *** Installation phase messages +SetupAborted=L'installation n'est pas terminée.%n%nVeuillez corriger le problème et relancer l'installation. +AbortRetryIgnoreSelectAction=Choisissez une action +AbortRetryIgnoreRetry=&Recommencer +AbortRetryIgnoreIgnore=&Ignorer l'erreur et continuer +AbortRetryIgnoreCancel=Annuler l'installation + +; *** Installation status messages +StatusClosingApplications=Ferme les applications... +StatusCreateDirs=Création des dossiers... +StatusExtractFiles=Extraction des fichiers... +StatusCreateIcons=Création des raccourcis... +StatusCreateIniEntries=Création des entrées du fichier INI... +StatusCreateRegistryEntries=Création des entrées de registre... +StatusRegisterFiles=Enregistrement des fichiers... +StatusSavingUninstall=Sauvegarde des informations de désinstallation... +StatusRunProgram=Finalisation de l'installation... +StatusRestartingApplications=Relance les applications... +StatusRollback=Annulation des modifications... + +; *** Misc. errors +ErrorInternal2=Erreur interne : %1 +ErrorFunctionFailedNoCode=%1 a échoué +ErrorFunctionFailed=%1 a échoué ; code %2 +ErrorFunctionFailedWithMessage=%1 a échoué ; code %2.%n%3 +ErrorExecutingProgram=Impossible d'exécuter le fichier :%n%1 + +; *** Registry errors +ErrorRegOpenKey=Erreur lors de l'ouverture de la clé de registre :%n%1\%2 +ErrorRegCreateKey=Erreur lors de la création de la clé de registre :%n%1\%2 +ErrorRegWriteKey=Erreur lors de l'écriture de la clé de registre :%n%1\%2 + +; *** INI errors +ErrorIniEntry=Erreur d'écriture d'une entrée dans le fichier INI "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Ignorer ce fichier (non recommandé) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorer l'erreur et continuer (non recommandé) +SourceIsCorrupted=Le fichier source est altéré +SourceDoesntExist=Le fichier source "%1" n'existe pas +ExistingFileReadOnly2=Le fichier existant ne peut pas être remplacé parce qu'il est protégé par l'attribut lecture seule. +ExistingFileReadOnlyRetry=&Supprimer l'attribut lecture seule et réessayer +ExistingFileReadOnlyKeepExisting=&Conserver le fichier existant +ErrorReadingExistingDest=Une erreur s'est produite lors de la tentative de lecture du fichier existant : +FileExistsSelectAction=Choisissez une action +FileExists2=Le fichier existe déjà. +FileExistsOverwriteExisting=&Ecraser le fichier existant +FileExistsKeepExisting=&Conserver le fichier existant +FileExistsOverwriteOrKeepAll=&Faire ceci pour les conflits à venir +ExistingFileNewerSelectAction=Choisissez une action +ExistingFileNewer2=Le fichier existant est plus récent que celui que l'assistant d'installation est en train d'installer. +ExistingFileNewerOverwriteExisting=&Ecraser le fichier existant +ExistingFileNewerKeepExisting=&Conserver le fichier existant (recommandé) +ExistingFileNewerOverwriteOrKeepAll=&Faire ceci pour les conflits à venir +ErrorChangingAttr=Une erreur est survenue en essayant de modifier les attributs du fichier existant : +ErrorCreatingTemp=Une erreur est survenue en essayant de créer un fichier dans le dossier de destination : +ErrorReadingSource=Une erreur est survenue lors de la lecture du fichier source : +ErrorCopying=Une erreur est survenue lors de la copie d'un fichier : +ErrorReplacingExistingFile=Une erreur est survenue lors du remplacement d'un fichier existant : +ErrorRestartReplace=Le marquage d'un fichier pour remplacement au redémarrage de l'ordinateur a échoué : +ErrorRenamingTemp=Une erreur est survenue en essayant de renommer un fichier dans le dossier de destination : +ErrorRegisterServer=Impossible d'enregistrer la bibliothèque DLL/OCX : %1 +ErrorRegSvr32Failed=RegSvr32 a échoué et a retourné le code d'erreur %1 +ErrorRegisterTypeLib=Impossible d'enregistrer la bibliothèque de type : %1 + +; *** Nom d'affichage pour la désinstallaton +; par exemple 'Mon Programme (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; ou par exemple 'Mon Programme (32-bit, Tous les utilisateurs)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Tous les utilisateurs +UninstallDisplayNameMarkCurrentUser=Utilisateur courant + +; *** Post-installation errors +ErrorOpeningReadme=Une erreur est survenue à l'ouverture du fichier LISEZMOI. +ErrorRestartingComputer=L'installation n'a pas pu redémarrer l'ordinateur. Merci de bien vouloir le faire vous-même. + +; *** Uninstaller messages +UninstallNotFound=Le fichier "%1" n'existe pas. Impossible de désinstaller. +UninstallOpenError=Le fichier "%1" n'a pas pu être ouvert. Impossible de désinstaller +UninstallUnsupportedVer=Le format du fichier journal de désinstallation "%1" n'est pas reconnu par cette version de la procédure de désinstallation. Impossible de désinstaller +UninstallUnknownEntry=Une entrée inconnue (%1) a été rencontrée dans le fichier journal de désinstallation +ConfirmUninstall=Voulez-vous vraiment désinstaller complètement %1 ainsi que tous ses composants ? +UninstallOnlyOnWin64=La désinstallation de ce programme ne fonctionne qu'avec une version 64 bits de Windows. +OnlyAdminCanUninstall=Ce programme ne peut être désinstallé que par un utilisateur disposant des droits d'administration. +UninstallStatusLabel=Veuillez patienter pendant que %1 est retiré de votre ordinateur. +UninstalledAll=%1 a été correctement désinstallé de cet ordinateur. +UninstalledMost=La désinstallation de %1 est terminée.%n%nCertains éléments n'ont pas pu être supprimés automatiquement. Vous pouvez les supprimer manuellement. +UninstalledAndNeedsRestart=Vous devez redémarrer l'ordinateur pour terminer la désinstallation de %1.%n%nVoulez-vous redémarrer maintenant ? +UninstallDataCorrupted=Le ficher "%1" est altéré. Impossible de désinstaller + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Supprimer les fichiers partagés ? +ConfirmDeleteSharedFile2=Le système indique que le fichier partagé suivant n'est plus utilisé par aucun programme. Souhaitez-vous que la désinstallation supprime ce fichier partagé ?%n%nSi des programmes utilisent encore ce fichier et qu'il est supprimé, ces programmes ne pourront plus fonctionner correctement. Si vous n'êtes pas sûr, choisissez Non. Laisser ce fichier dans votre système ne posera pas de problème. +SharedFileNameLabel=Nom du fichier : +SharedFileLocationLabel=Emplacement : +WizardUninstalling=État de la désinstallation +StatusUninstalling=Désinstallation de %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Installe %1. +ShutdownBlockReasonUninstallingApp=Désinstalle %1. + +; Les messages personnalisés suivants ne sont pas utilisé par l'installation +; elle-même, mais si vous les utilisez dans vos scripts, vous devez les +; traduire + +[CustomMessages] + +NameAndVersion=%1 version %2 +AdditionalIcons=Icônes supplémentaires : +CreateDesktopIcon=Créer une icône sur le &Bureau +CreateQuickLaunchIcon=Créer une icône dans la barre de &Lancement rapide +ProgramOnTheWeb=Page d'accueil de %1 +UninstallProgram=Désinstaller %1 +LaunchProgram=Exécuter %1 +AssocFileExtension=&Associer %1 avec l'extension de fichier %2 +AssocingFileExtension=Associe %1 avec l'extension de fichier %2... +AutoStartProgramGroupDescription=Démarrage : +AutoStartProgram=Démarrer automatiquement %1 +AddonHostProgramNotFound=%1 n'a pas été trouvé dans le dossier que vous avez choisi.%n%nVoulez-vous continuer malgré tout ? diff --git a/installer/innosetup/Languages/Galician.isl b/installer/innosetup/Languages/Galician.isl index fab5215e4..5d7bfeb99 100644 --- a/installer/innosetup/Languages/Galician.isl +++ b/installer/innosetup/Languages/Galician.isl @@ -1,7 +1,10 @@ -; *** Inno Setup version 6.0.3+ Galician messages *** +; *** Inno Setup version 6.1.0+ Galician messages *** ; ; Maintained by: Julio Mojon Fuentes ; (juliomf AT edu.xunta.gal) +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ [LangOptions] LanguageName=Galego @@ -191,6 +194,18 @@ ReadyMemoComponents=Compoñentes seleccionados: ReadyMemoGroup=Cartafol do Menú Inicio: ReadyMemoTasks=Tarefas adicionais: +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=A descargar arquivos adicionais... +ButtonStopDownload=&Deter descarga +StopDownload=Está seguro de que desexa deter a descarga? +ErrorDownloadAborted=Descarga cancelada +ErrorDownloadFailed=A descarga fallou: %1 %2 +ErrorDownloadSizeFailed=Non se puido determinar o tamaño: %1 %2 +ErrorFileHash1=Non se puido calcular o hash do arquivo: %1 +ErrorFileHash2=Hash do arquivo inválido: esperado %1, atopado %2 +ErrorProgress=Progreso inválido: %1 de %2 +ErrorFileSize=Tamaño de arquivo inválido: esperado %1, atopado %2 + ; *** "Preparing to Install" wizard page WizardPreparing=A prepararse para instalar PreparingDesc=O asistente de instalación está a prepararse para instalar [name] no seu computador. @@ -271,8 +286,16 @@ ExistingFileReadOnly2=Non foi posible substituír o arquivo existente porque est ExistingFileReadOnlyRetry=&Eliminar o atributo de só lectura e tentar de novo ExistingFileReadOnlyKeepExisting=&Manter o arquivo existente ErrorReadingExistingDest=Ocorreu un erro ao tentar ler o arquivo existente: -FileExists=O arquivo xa existe.%n%nDesexa que o asistente de instalación o sobrescriba? -ExistingFileNewer=O arquivo existente é máis novo ca o que o asistente de instalación tenta instalar. Recoméndaselle que manteña o arquivo existente.%n%nDesexa manter o arquivo existente? +FileExistsSelectAction=Seleccionar acción +FileExists2=O arquivo xa existe. +FileExistsOverwriteExisting=&Sobrescribir o arquivo existente +FileExistsKeepExisting=&Manter o arquivo existente +FileExistsOverwriteOrKeepAll=&Facer isto para os seguintes conflitos +ExistingFileNewerSelectAction=Seleccionar acción +ExistingFileNewer2=O arquivo existente é máis novo ca o que o asistente de instalación tenta instalar. +ExistingFileNewerOverwriteExisting=&Sobrescribir o arquivo existente +ExistingFileNewerKeepExisting=&Manter o arquivo existente (recomendado) +ExistingFileNewerOverwriteOrKeepAll=&Facer isto para os seguintes conflitos ErrorChangingAttr=Ocorreu un erro ao tentar mudar os atributos do arquivo existente: ErrorCreatingTemp=Ocorreu un erro ao tentar crear un arquivo no cartafol de destino: ErrorReadingSource=Ocorreu un erro ao tentar ler o arquivo orixe: diff --git a/installer/innosetup/Languages/Georgian.isl b/installer/innosetup/Languages/Georgian.isl new file mode 100644 index 000000000..785db127f --- /dev/null +++ b/installer/innosetup/Languages/Georgian.isl @@ -0,0 +1,384 @@ +; *** Inno Setup version 6.1.0+ Georgian *** +; Translated by Saba Khmaladze (skhmaladze@uglt.org) +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Georgian +LanguageID=$0437 +LanguageCodePage=0 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +DialogFontName=Sylfaen +;DialogFontSize=8 +WelcomeFontName=Sylfaen +;WelcomeFontSize=12 +TitleFontName=Sylfaen +;TitleFontSize=29 +CopyrightFontName=Sylfaen +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=ინსტალაცია +SetupWindowTitle=ინსტალდება - %1 +UninstallAppTitle=წაშლა +UninstallAppFullTitle=იშლება %1 + +; *** Misc. common +InformationTitle=ინფორმაცია +ConfirmTitle=დაზუსტება +ErrorTitle=შეცდომა + +; *** SetupLdr messages +SetupLdrStartupMessage=თქვენთან დაინსტალდება %1. გსურთ გაგრძელება? +LdrCannotCreateTemp=დროებითი ფაილი ვერ შეიქმნა. ინსტალაცია შეწყდა +LdrCannotExecTemp=დროებით საქაღალდეში ფაილი ვერ გაეშვა. ინსტალაცია შეწყდა +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nშეცდომა %2: %3 +SetupFileMissing=საინსტალაციო საქაღალდეში არ მოიძებნა ფაილი %1. გაასწორეთ პრობლემა ან გადმოწერეთ პროგრამის ახალი ვერსია. +SetupFileCorrupt=საინსტალაციო ფაილები დაზიანებულია. გაასწორეთ პრობლემა ან გადმოწერეთ პროგრამის ახალი ვერსია. +SetupFileCorruptOrWrongVer=საინსტალაციო ფაილები დაზიანებული ან არათავსებადია ამ ვერსიასთან. გაასწორეთ პრობლემა ან გადმოწერეთ პროგრამის ახალი ვერსია. +InvalidParameter=არასწორი პარამეტრი გადაეცა ბრძანებათა ველს:%n%n%1 +SetupAlreadyRunning=ინსტალაცია უკვე მიმდინარეობს. +WindowsVersionNotSupported=ეს პროგრამა Windows-ის ამ ვერსიაზე ვერ გაეშვება. +WindowsServicePackRequired=ამ პროგრამას სჭირდება %1 Service Pack %2 ან უფრო ახალი. +NotOnThisPlatform=ეს პროგრამა არ გაეშვება სისტემაზე %1. +OnlyOnThisPlatform=ეს პროგრამა უნდა გაეშვას სისტემაზე %1. +OnlyOnTheseArchitectures=ეს პროგრამა დაინსტალდება მხოლოდ Windows-ის შემდეგ არქიტექტურაზე:%n%n%1 +WinVersionTooLowError=ამ პროგრამას სჭირდება %1 ვერსია %2 ან უფრო ახალი. +WinVersionTooHighError=ეს პროგრამა ვერ დაინსტალდება %1 ვერსია %2-ზე ან უფრო ახალზე. +AdminPrivilegesRequired=ამ პროგრამის დასაინსტალებლად საჭიროა ადმინისტრატორის ანგარიში. +PowerUserPrivilegesRequired=ამ პროგრამის დასაინსტალებლად საჭიროა ადმინისტრატორის ან მძლავრი იუზერის (Power User) ანგარიში. +SetupAppRunningError=საინსტალაციომ დაადგინა რომ გაშვებულია %1.%n%nგთხოვთ დახურეთ გაშვებული პროცესები, გასაგრძელებლად დააჭირეთ ღილაკს კარგი ან გამოსასვლელად ღილაკს გაუქმება. +UninstallAppRunningError=ამომშლელმა დაადგინა რომ გაშვებულია %1.%n%nგთხოვთ დახურეთ გაშვებული პროცესები, გასაგრძელებლად დააჭირეთ ღილაკს კარგი ან გამოსასვლელად ღილაკს გაუქმება. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=აირჩიეთ ინსტალაციის რეჟიმი +PrivilegesRequiredOverrideInstruction=აირჩიეთ ინსტალაციის რეჟიმი +PrivilegesRequiredOverrideText1=%1 შეიძლება დაინსტალდეს ყველასთვის (საჭიროა ადმინისტრატორის უფლება) ან მხოლოდ თქვენთვის. +PrivilegesRequiredOverrideText2=%1 შეიძლება დაინსტალდეს მხოლოდ თქვენთვის ან ყველასთვის (საჭიროა ადმინისტრატორის უფლება). +PrivilegesRequiredOverrideAllUsers=დაინსტალება ყველა მომხმარებლისტვის +PrivilegesRequiredOverrideAllUsersRecommended=დაინსტალება ყველა მომხმარებლისთვის (რეკომენდებულია) +PrivilegesRequiredOverrideCurrentUser=დაინსტალება მხოლოდ ჩემთვის +PrivilegesRequiredOverrideCurrentUserRecommended=დაინსტალება მხოლოდ ჩემთვის (რეკომენდებულია) + +; *** Misc. errors +ErrorCreatingDir=საინსტალაციომ ვერ შექმნა საქაღალდე "%1" +ErrorTooManyFilesInDir=საქაღალდეში "%1" ვერ შეიქმნა ფაილი, რადგან ის შეიცავს ძალიან ბევრ ფაილს + +; *** Setup common messages +ExitSetupTitle=საინსტალაციოს გათიშვა +ExitSetupMessage=ინსტალაცია არ დასრულებულა, გათიშვის შემთხვევაში პროცესი გაუქმდება.%n%nინსტალაციის დასასრულებლად მოგიწევთ საინსტალაციოს თავიდან გაშვება.%n%nგსურთ გათიშვა? +AboutSetupMenuItem=&ინსტალაციის შეწყვეტა... +AboutSetupTitle=ინსტალაციის შეწყვეტა +AboutSetupMessage=%1 ვერსია %2%n%3%n%n%1 ვებ-გვერდი:%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< &უკან +ButtonNext=&შემდეგი > +ButtonInstall=&ინსტალაცია +ButtonOK=კარგი +ButtonCancel=გაუქმება +ButtonYes=&კი +ButtonYesToAll=კი ყველასთვის +ButtonNo=&არა +ButtonNoToAll=არა ყველასთვის +ButtonFinish=&დასრულება +ButtonBrowse=&მითითება... +ButtonWizardBrowse=მ&ითითება... +ButtonNewFolder=&ახალი საქაღალდე + +; *** "Select Language" dialog messages +SelectLanguageTitle=ინსტალაციის ენის არჩევა +SelectLanguageLabel=მიუთითეთ ენა, რომელზეც გაეშვება საინსტალაციო. + +; *** Common wizard text +ClickNext=გასაგრძელებლად დააჭირეთ შემდეგს, გასაუქმებლად გაუქმებას. +BeveledLabel= +BrowseDialogTitle=საქაღალდის მითითება +BrowseDialogLabel=აირჩიეთ საქაღალდე და დააჭირეთ ღილაკს კარგი. +NewFolderName=ახალი საქაღალდე + +; *** "Welcome" wizard page +WelcomeLabel1=მოგესალმებით [name]-(ი)ს საინსტალაციოში +WelcomeLabel2=საინსტალაციო დააინსტალებს [name/ver] კომპიუტერში.%n%nგაგრძელებამდე რეკომენდებულია დახუროთ გახსნილი პროგრამები. + +; *** "Password" wizard page +WizardPassword=პაროლი +PasswordLabel1=საინსტალაციო დაცულია პაროლით. +PasswordLabel3=შეიყვანეთ პაროლი და დააჭირეთ გაგრძელებას. +PasswordEditLabel=&პაროლი: +IncorrectPassword=შეყვანილი პაროლი არასწორია. + +; *** "License Agreement" wizard page +WizardLicense=სალიცენზიო შეთანხმება +LicenseLabel=გაგრძელებამდე ყურადღებით გაეცანით ქვემოთ მოცემულ ინფორმაციას. +LicenseLabel3=ყურადღებით წაიკითხეთ სალიცენზიო შეთანხმება. გაგრძელებისთვის თქვენ უნდა დაეთანხმოთ მას. +LicenseAccepted=ვეთანხმები სალიცენზიო შეთანხმებას +LicenseNotAccepted=არ ვეთანხმები სალიცენზიო შეთანხმებას + +; *** "Information" wizard pages +WizardInfoBefore=ინფორმაცია +InfoBeforeLabel=გაგრძელებამდე გთხოვთ წაიკითხოთ მნიშვნელოვანი ინფორმაცია. +InfoBeforeClickLabel=როცა მზად იქნები დააჭირე შემდეგს. +WizardInfoAfter=ინფორმაცია +InfoAfterLabel=გაგრძელებამდე გთხოვთ წაიკითხოთ მნიშვნელოვანი ინფორმაცია. +InfoAfterClickLabel=როცა მზად იქნები დააჭირე შემდეგს. + +; *** "User Information" wizard page +WizardUserInfo=ინფორმაცია მომხმარებელზე +UserInfoDesc=შეიყვანეთ ინფორმაცია თქვენზე. +UserInfoName=&სახელი: +UserInfoOrg=&ორგანიზაცია: +UserInfoSerial=სერიული &ნომერი: +UserInfoNameRequired=უნდა შეიყვანოთ სახელი. + +; *** "Select Destination Location" wizard page +WizardSelectDir=მიუთითეთ საინსტალაციო საქაღალდე +SelectDirDesc=სად დაინსტალდეს [name]? +SelectDirLabel3=საინსტალაციო დააინსტალებს [name]-(ი)ს მოცემულ საქაღალდეში. +SelectDirBrowseLabel=გასაგრძელებლად დააჭირეთ გაგრძელებას ან თუ გსურთ სხვა საქაღალდის მითითება - მითითებას. +DiskSpaceGBLabel=საჭიროა მინიმუმ [gb] გბ სივრცე. +DiskSpaceMBLabel=საჭიროა მინიმუმ [mb] მბ სივრცე. +CannotInstallToNetworkDrive=ვერ დაინსტალდება ქსელურ მისამართზე. +CannotInstallToUNCPath=ვერ დაინსტალდება UNC მისამართზე. +InvalidPath=უნდა შეიყვანეთ სრული მისამართი, დისკის სახელის ჩათვლით; მაგალითად:%n%nC:\APP%n%nან UNC მისამართი ფორმატში:%n%n\\server\share +InvalidDrive=დისკი ან UNC მისამართი არ არსებობს ან მიუწვდომელია. მიუთითეთ სხვა. +DiskSpaceWarningTitle=არასაკმარისი სივრცე დისკზე +DiskSpaceWarning=დასაინსტალებლად საჭიროა მინიმუმ %1 კბ სივრცე, მაგრამ ხელმისაწვდომია მხოლოდ %2 კბ.%n%nგსურთ გაგრძელება? +DirNameTooLong=საქაღალდის დასახელება ძალიან გრძელია. +InvalidDirName=საქაღალდის დასახელება არასწორია. +BadDirName32=საქაღალდის სახელში არ უნდა იყოს სიმბოლოები:%n%n%1 +DirExistsTitle=საქაღალდე არსებობს +DirExists=საქაღალდე:%n%n%1%n%nუკვე არსებობს. გსურთ მაგ საქაღალდეში დაინსტალება? +DirDoesntExistTitle=საქაღალდე არ არსებობს +DirDoesntExist=საქაღალდე:%n%n%1%n%nარ არსებობს. გსურთ შექმნა? + +; *** "Select Components" wizard page +WizardSelectComponents=აირჩიეთ კომპონენტები +SelectComponentsDesc=რომელი კომპონენტები დაინსტალდეს? +SelectComponentsLabel2=აირჩიეთ რომელი კომპონენტის დაინსტალებაც გსურთ; არ მონიშნოთ ის კომპონენტი რომლის დაინსტალებაც არ გსურთ. როცა მზად იქნებით დააჭირეთ გაგრძელებას. +FullInstallation=სრული ინსტალაცია +CompactInstallation=კომპაქტური ინსტალაცია +CustomInstallation=არჩევითი ინსტალაცია +NoUninstallWarningTitle=კომპონენტები არსებობს +NoUninstallWarning=საინსტალაციომ დაადგინა რომ ზოგიერთი კომპონენტი უკვე დაინსტალებულია:%n%n%1%n%nმათი არ მონიშვნა არ ნიშნავს რომ ისინი წაიშლება.%n%nგსურთ გაგრძელებას? +ComponentSize1=%1 კბ +ComponentSize2=%1 მბ +ComponentsDiskSpaceGBLabel=საჭიროა მინიმუმ [gb] გბ სივრცე. +ComponentsDiskSpaceMBLabel=საჭიროა მინიმუმ [mb] მბ სივრცე. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=მიუთითეთ დამატებითი დავალებები +SelectTasksDesc=რა დამატებითი დავალება შესრულდეს? +SelectTasksLabel2=აირჩიეთ თუ რომელიმე დამატებითი ფუნქციის შესრულება გსურთ [name]-(ი)ს ინსტალაციისას და დააჭირეთ შემდეგს. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=აირჩიეთ გაშვების მენიუს საქაღალდე +SelectStartMenuFolderDesc=სად დაინსტალდეს პროგრამის ხატულები? +SelectStartMenuFolderLabel3=საინსტალაციო პროგრამის ხატულებს გაშვების მენიუსთვის დააინსტალებს ქვემოთ მოცემულ საქაღალდეში. +SelectStartMenuFolderBrowseLabel=გასაგრძელებლად დააჭირეთ შემდეგს ან მიუთითეთ სხვა საქაღალდე. +MustEnterGroupName=ჩაწერეთ საქაღალდის სახელი. +GroupNameTooLong=საქაღალდის სახელი ან მისამართი ძალიან გრძელია. +InvalidGroupName=საქაღალდის სახელი არასწორია. +BadGroupName=სახელში არ უნდა იყოს შემდეგი სიმბოლოები:%n%n%1 +NoProgramGroupCheck2=&არ შეიქმნას საქაღალდე გაშვების მენიუში + +; *** "Ready to Install" wizard page +WizardReady=მზადაა დასაინსტალებლად +ReadyLabel1=საინსტალაციო მზადაა დააინსტალოს [name] თქვენს კომპიუტერში. +ReadyLabel2a=დასაინსტალებლად დააჭირეთ ინსტალაციას ან დაბრუნდით უკან და გადახედეთ პარამეტრებს. +ReadyLabel2b=დასაინსტალებლად დააჭირეთ ინსტალაციას. +ReadyMemoUserInfo=ინფორმაცია მომხმარებელზე: +ReadyMemoDir=ინფორმაცია საქაღალდეზე: +ReadyMemoType=ინსტალაციის სახეობა: +ReadyMemoComponents=არჩეული კომპონენტები: +ReadyMemoGroup=გაშვების მენიუს საქაღალდე: +ReadyMemoTasks=დამატებითი დავალებები: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=იწერება დამატებითი ფაილები... +ButtonStopDownload=&გადმოწერის შეწყვეტა +StopDownload=ნამდვილად გსურთ გადმოწერის შეწყვეტა? +ErrorDownloadAborted=გადმოწერა შეწყდა +ErrorDownloadFailed=არ გადმოიწერა: %1 %2 +ErrorDownloadSizeFailed=ზომის მონაცემები ვერ მივიღეთ: %1 %2 +ErrorFileHash1=ფაილის ჰეში არ ემთხვევა: %1 +ErrorFileHash2=ფაილის ჰეში არასწორია: ველოდებოდით %1, მივიღეთ %2 +ErrorProgress=არასწორი პროცესი: %1 of %2 +ErrorFileSize=ფაილის არასწორი ზომა: ველოდებოდთ %1, მივიღეთ %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=მზადდება დასაინსტალებლად +PreparingDesc=საინსტალაციო ემზადება რომ [name] დააინსტალოს კომპიუტერში. +PreviousInstallNotCompleted=წინა პროგრამის ინსტალაცია/წაშლა არ მოხერხდა. საჭიროა კომპიუტერის გადატვირთვა.%n%nკომპიუტერის გადატვირთვის შემდეგ ხელახლა გაუშვით [name]-(ი)ს საინსტალაციო. +CannotContinue=ინსტალაცია არ გაგრძელდა. გასაუქმებლად დააჭირეთ გაუქმებას. +ApplicationsFound=მოცემული პროგრამები იყენებენ ფაილებს რომელიც საინსტალაციომ უნდა განახლოს. რეკომენდებულია უფლება მისცეთ საინსტალაციოს გათიშოს ეს პროგრამები. +ApplicationsFound2=ოცემული პროგრამები იყენებენ ფაილებს რომელიც საინსტალაციომ უნდა განახლოს. რეკომენდებულია უფლება მისცეთ საინსტალაციოს გათიშოს ეს პროგრამები. ინსტალაციის დასრულების შემდეგ საინსტალაციო შეეცდება ხელახლა ჩართოს ეს პროგრამები. +CloseApplications=&აპლიკაციების ავტომატურად გათიშვა +DontCloseApplications=&არ გაითიშოს აპლიკაციები +ErrorCloseApplications=საინსტალაციომ ავტომატურად ვერ გათიშა ყველა აპლიკაცია. რეკომენდებულია რომ გათიშოთ ყველა აპლიკაცია. +PrepareToInstallNeedsRestart=საინსტალაციომ უნდა გადატვირთოს კომპიუტერი. კომპიუტერის გადატვირთვის შემდეგ ხელახლა გაუშვით საინსტალაციო რათა გაგრძელდეს [name]-(ი)ს ინსტალაცია.%n%nგსურთ ახლა გადატვირთვა? + +; *** "Installing" wizard page +WizardInstalling=ინსტალდება +InstallingLabel=მოითმინეთ სანამ საინსტალაციო დააინსტალებს [name]-(ი)ს კომპიუტერში. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=სრულდება [name]-(ი)ს ინსტალაცია +FinishedLabelNoIcons=საინსტალაციომ დაასრულა [name]-(ი)ს ინსტალაცია კომპიუტერში. +FinishedLabel=საინსტალაციომ დაასრულა [name]-(ი)ს ინსტალაცია კომპიუტერში. პროგრამა გაეშვება შესაბამისი ხატულას მონიშვნის შემთხვევაში. +ClickFinish=საინსტალაციოს გასათიშად დააჭირეთ დასრულებას. +FinishedRestartLabel=[name]-(ი)ს ინსტალაციის დასრულებისთვის საჭიროა კომპიუტეირს გადატვირთვა. გსურთ ახლა გადატვირთვა? +FinishedRestartMessage=[name]-(ი)ს ინსტალაციის დასრულებისთვის საჭიროა კომპიუტეირს გადატვირთვა.%n%nგსურთ ახლა გადატვირთვა? +ShowReadmeCheck=README ფაილის ჩვენება +YesRadio=&კი, გადაიტვირთოს კომპიუტერი +NoRadio=&არა, მოგვიანებით გადავტვირთავ კომპიუტერს +; used for example as 'Run MyProg.exe' +RunEntryExec=გაეშვას %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=%1-(ი)ს ნახვა + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=ინსტალაციისთვის საჭიროა შემდეგი დისკი +SelectDiskLabel2=ჩადეთ დისკი %1 და დააჭირეთ ღილაკს კარგი.%n%nთუ ფაილები არაა ქვემოთ მოცემულ მისამართზე დააჭირეთ მითითებას და მიუთითეთ სწორი მისამართი. +PathLabel=&მისამართი: +FileNotInDir2=ფაილი "%1" არ მოიძებნა "%2" მისამართზე. ჩადეთ სწორი დისკი და ან აირჩიეთ სხვა საქაღალდე. +SelectDirectoryLabel=მიუთითეთ შემდეგი დისკის მდებარეობა. + +; *** Installation phase messages +SetupAborted=ინსტალაცია არ დასრულდა.%n%nგაასწორეთ პრობლემა და გაუშვით ინსტალაცია ხელახლა. +AbortRetryIgnoreSelectAction=აირჩიეთ მოქმედება +AbortRetryIgnoreRetry=&ხელახლა ცდა +AbortRetryIgnoreIgnore=&შეცდომის უგულებელყოფა და გაგრძელება +AbortRetryIgnoreCancel=ინსტალაციის გაუქმება + +; *** Installation status messages +StatusClosingApplications=ითიშება პროგრამები... +StatusCreateDirs=მიმდინარეობს საქაღალდეების შექმნა... +StatusExtractFiles=მიმდინარეობს ფაილების ამოარქივება... +StatusCreateIcons=მიმდინარეობს ხატულების შექმნა... +StatusCreateIniEntries=იქმნება INI ჩანაწერები... +StatusCreateRegistryEntries=იქმნება რეესტრის ჩანაწერები... +StatusRegisterFiles=მიმდინარეობს ფაილების რეგისტრაცია... +StatusSavingUninstall=ინახება წასაშლელი ინფორმაცია... +StatusRunProgram=სრულდება ინსტალაცია... +StatusRestartingApplications=იტვირთება პროგრამები... +StatusRollback=უქმდება ცვლილებები... + +; *** Misc. errors +ErrorInternal2=შიდა შეცდომა: %1 +ErrorFunctionFailedNoCode=%1 არ შესრულდა +ErrorFunctionFailed=%1 არ შესრულდა; კოდი %2 +ErrorFunctionFailedWithMessage=%1 არ შესრულდა; კოდი %2.%n%3 +ErrorExecutingProgram=არ შესრულდა file:%n%1 + +; *** Registry errors +ErrorRegOpenKey=შეცდომა რეესტრის გასაღების გახსნისას:%n%1\%2 +ErrorRegCreateKey=შეცდომა რეესტრის გასაღების შექმნისას:%n%1\%2 +ErrorRegWriteKey=შეცდომა რეესტრის გასაღების ჩაწერისას:%n%1\%2 + +; *** INI errors +ErrorIniEntry=შეცდომა INI ჩანაწერის შექმნისას ფაილში "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&ფაილის გამოტოვება (არაა რეკომენდებული) +FileAbortRetryIgnoreIgnoreNotRecommended=&შეცდომის უგულებელყოფა და გამოტოვება (არაა რეკომენდებული) +SourceIsCorrupted=საწყისი ფაილი დაზიანებულია +SourceDoesntExist=საწყისი ფაილი "%1" არსებობს +ExistingFileReadOnly2=არსებული ფაილი არ ჩანაცვლდა, იმიტომ რომ ის არის მხოლოდ წაკითხვადი. +ExistingFileReadOnlyRetry=&მხოლოდ წაკითხვადის მოხსნა და ხელახლა ცდა +ExistingFileReadOnlyKeepExisting=&არსებული ფაილის დატოვება +ErrorReadingExistingDest=შეცდომა არსებული ფაილის წაკითხვისას: +FileExistsSelectAction=აირჩიეთ მოქმედება +FileExists2=ფაილი უკვე არსებობს. +FileExistsOverwriteExisting=&არსებულ ფაილზე გადაწერა +FileExistsKeepExisting=ა&რსებული ფაილის დატოვება +FileExistsOverwriteOrKeepAll=&მოქმედების გამეორება შემდეგი კონფლიქტის დროს +ExistingFileNewerSelectAction=აირჩიეთ მოქმედება +ExistingFileNewer2=არსებული ფაილი უფრო ახალია ვიდრე საინსტალაციოში მოცემული. +ExistingFileNewerOverwriteExisting=&არსებულ ფაილზე გადაწერა +ExistingFileNewerKeepExisting=ა&რსებული ფაილის დატოვება (რეკომენდებულია) +ExistingFileNewerOverwriteOrKeepAll=&მოქმედების გამეორება შემდეგი კონფლიქტის დროს +ErrorChangingAttr=შეცდომა არსებულ ფაილზე ატრიბუტის შეცვლისას: +ErrorCreatingTemp=შეცდომა საქაღალდეში ფაილის შექმნისას: +ErrorReadingSource=შეცდომა საწყისი ფაილის წაკითხვისას: +ErrorCopying=შეცდომა ფაილის კოპირებისას: +ErrorReplacingExistingFile=შეცდომა არსებულ ფაილზ გადაწერისას: +ErrorRestartReplace=გადაწერა არ მოხერხდა: +ErrorRenamingTemp=შეცდომა ფაილის სახელის შეცვლისას: +ErrorRegisterServer=არ დარეგისტრდა DLL/OCX: %1 +ErrorRegSvr32Failed=RegSvr32 არ გაეშვა, კოდი: %1 +ErrorRegisterTypeLib=არ დარეგისტრდა ბიბლიოთეკა: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=ყველა მომხმარებელი +UninstallDisplayNameMarkCurrentUser=ახლანდელი მომხმარებელი + +; *** Post-installation errors +ErrorOpeningReadme=შეცდომა Readme ფაილის გახსნისას. +ErrorRestartingComputer=საინსტალაციომ ვერ გადატვირთა კომპიუტერი. გადატვირთეთ ხელით. + +; *** Uninstaller messages +UninstallNotFound=ფაილი "%1" არ არსებობს. არ წაიშალა. +UninstallOpenError=ფაილი "%1" არ არსებობს. არ წაიშალა +UninstallUnsupportedVer=წასაშლელი ჟურნალის ფაილი "%1" ისეთ ფორმატშია რომ ამ ვერსიის წამშლელი ვერ აღიქვამს. არ წაიშალა +UninstallUnknownEntry=უცნობი ჩანაწერი (%1) +ConfirmUninstall=ნამდვილად გსურთ სრულად წაშალოთ %1 და ყველა მისი კომპონენტი? +UninstallOnlyOnWin64=ეს ინსტალაცია შეიძლება წაიშალოს მხოლოდ 64 ბიტიან Windows-ში. +OnlyAdminCanUninstall=ეს ინსტალაცია შეიძლება წაიშალოს მხოლოდ ადმინისტრატორის უფლებებით. +UninstallStatusLabel=მოითმინეთ სანამ %1 წაიშლება კომპიუტერიდან. +UninstalledAll=%1 წაიშალა კომპიუტერიდან. +UninstalledMost=%1-(ი)ს წაშლა დასრულდა.%n%nზოგიერთი ელემენტი არ წაიშალა და წაშალეთ ხელით. +UninstalledAndNeedsRestart=იმისთვის რომ %1 წაიშალოს საჭიროა კომპიუტერის გადატვირთვა.%n%nგსურთ ახლა გადატვირთვა? +UninstallDataCorrupted="%1" ფაილი დაზიანებულია. არ წაიშალა + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=წაიშალოს გაზიარებული ფაილი? +ConfirmDeleteSharedFile2=სისტემამ აღმოაჩინა რომ მოცემულ გაზიარებულ ფაილს არ იყენებს არც ერთი პროგრამა. გსურთ წამშლელმა წაშალოს გაზიარებული ფაილი?%n%nთუ რომელიმე პროგრამა ისევ იყენებს ამ ფაილს და მას წაშლით, ეს პროგრამები ვეღარ იმუშავებენ ნორმალურად. დარწმუნებული თუ არ ხართ დააჭირეთ არას. ფაილის დატოვება არაფერს გააფუჭებს. +SharedFileNameLabel=ფაილის სახელი: +SharedFileLocationLabel=მდებარეობა: +WizardUninstalling=წაშლის სტატუსი +StatusUninstalling=იშლება %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=ინსტალდება %1. +ShutdownBlockReasonUninstallingApp=იშლება %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 ვერსია %2 +AdditionalIcons=დამატებითი ხატულები: +CreateDesktopIcon=ხატულას შექმნა სამუშაო მაგიდაზე +CreateQuickLaunchIcon=სწრაფი გაშვების ხატულას შექმნა +ProgramOnTheWeb=%1 ვებ-გვერდზე +UninstallProgram=წაიშალოს %1 +LaunchProgram=გაეშვას %1 +AssocFileExtension=&ასოცირდეს %1 %2 ფაილის გაფართოებასთან? +AssocingFileExtension=%1 ასოცირდება %2 ფაილების გაფართოებასთან... +AutoStartProgramGroupDescription=გაშვება: +AutoStartProgram=ავტომატურად გაშვება %1 +AddonHostProgramNotFound=%1 არ მოიძებნა მითითებულ საქაღალდეში.%n%nგსურთ გაგრძელება? \ No newline at end of file diff --git a/installer/innosetup/Languages/German.isl b/installer/innosetup/Languages/German.isl new file mode 100644 index 000000000..9877b2b9c --- /dev/null +++ b/installer/innosetup/Languages/German.isl @@ -0,0 +1,406 @@ +; ****************************************************** +; *** *** +; *** Inno Setup version 6.1.0+ German messages *** +; *** *** +; *** Changes 6.0.0+ Author: *** +; *** *** +; *** Jens Brand (jens.brand@wolf-software.de) *** +; *** *** +; *** Original Authors: *** +; *** *** +; *** Peter Stadler (Peter.Stadler@univie.ac.at) *** +; *** Michael Reitz (innosetup@assimilate.de) *** +; *** *** +; *** Contributors: *** +; *** *** +; *** Roland Ruder (info@rr4u.de) *** +; *** Hans Sperber (Hans.Sperber@de.bosch.com) *** +; *** LaughingMan (puma.d@web.de) *** +; *** *** +; ****************************************************** +; +; Diese Übersetzung hält sich an die neue deutsche Rechtschreibung. + +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ + +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Deutsch +LanguageID=$0407 +LanguageCodePage=1252 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=Setup +SetupWindowTitle=Setup - %1 +UninstallAppTitle=Entfernen +UninstallAppFullTitle=%1 entfernen + +; *** Misc. common +InformationTitle=Information +ConfirmTitle=Bestätigen +ErrorTitle=Fehler + +; *** SetupLdr messages +SetupLdrStartupMessage=%1 wird jetzt installiert. Möchten Sie fortfahren? +LdrCannotCreateTemp=Es konnte keine temporäre Datei erstellt werden. Das Setup wurde abgebrochen +LdrCannotExecTemp=Die Datei konnte nicht im temporären Ordner ausgeführt werden. Das Setup wurde abgebrochen +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nFehler %2: %3 +SetupFileMissing=Die Datei %1 fehlt im Installationsordner. Bitte beheben Sie das Problem oder besorgen Sie sich eine neue Kopie des Programms. +SetupFileCorrupt=Die Setup-Dateien sind beschädigt. Besorgen Sie sich bitte eine neue Kopie des Programms. +SetupFileCorruptOrWrongVer=Die Setup-Dateien sind beschädigt oder inkompatibel zu dieser Version des Setups. Bitte beheben Sie das Problem oder besorgen Sie sich eine neue Kopie des Programms. +InvalidParameter=Ein ungültiger Parameter wurde auf der Kommandozeile übergeben:%n%n%1 +SetupAlreadyRunning=Setup läuft bereits. +WindowsVersionNotSupported=Dieses Programm unterstützt die auf Ihrem Computer installierte Windows-Version nicht. +WindowsServicePackRequired=Dieses Programm benötigt %1 Service Pack %2 oder höher. +NotOnThisPlatform=Dieses Programm kann nicht unter %1 ausgeführt werden. +OnlyOnThisPlatform=Dieses Programm muss unter %1 ausgeführt werden. +OnlyOnTheseArchitectures=Dieses Programm kann nur auf Windows-Versionen installiert werden, die folgende Prozessor-Architekturen unterstützen:%n%n%1 +WinVersionTooLowError=Dieses Programm benötigt %1 Version %2 oder höher. +WinVersionTooHighError=Dieses Programm kann nicht unter %1 Version %2 oder höher installiert werden. +AdminPrivilegesRequired=Sie müssen als Administrator angemeldet sein, um dieses Programm installieren zu können. +PowerUserPrivilegesRequired=Sie müssen als Administrator oder als Mitglied der Hauptbenutzer-Gruppe angemeldet sein, um dieses Programm installieren zu können. +SetupAppRunningError=Das Setup hat entdeckt, dass %1 zurzeit ausgeführt wird.%n%nBitte schließen Sie jetzt alle laufenden Instanzen und klicken Sie auf "OK", um fortzufahren, oder auf "Abbrechen", um zu beenden. +UninstallAppRunningError=Die Deinstallation hat entdeckt, dass %1 zurzeit ausgeführt wird.%n%nBitte schließen Sie jetzt alle laufenden Instanzen und klicken Sie auf "OK", um fortzufahren, oder auf "Abbrechen", um zu beenden. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Installationsmodus auswählen +PrivilegesRequiredOverrideInstruction=Bitte wählen Sie den Installationsmodus +PrivilegesRequiredOverrideText1=%1 kann für alle Benutzer (erfordert Administrationsrechte) oder nur für Sie installiert werden. +PrivilegesRequiredOverrideText2=%1 kann nur für Sie oder für alle Benutzer (erfordert Administrationsrechte) installiert werden. +PrivilegesRequiredOverrideAllUsers=Installation für &alle Benutzer +PrivilegesRequiredOverrideAllUsersRecommended=Installation für &alle Benutzer (empfohlen) +PrivilegesRequiredOverrideCurrentUser=Installation nur für &Sie +PrivilegesRequiredOverrideCurrentUserRecommended=Installation nur für &Sie (empfohlen) + +; *** Misc. errors +ErrorCreatingDir=Das Setup konnte den Ordner "%1" nicht erstellen. +ErrorTooManyFilesInDir=Das Setup konnte eine Datei im Ordner "%1" nicht erstellen, weil er zu viele Dateien enthält. + +; *** Setup common messages +ExitSetupTitle=Setup verlassen +ExitSetupMessage=Das Setup ist noch nicht abgeschlossen. Wenn Sie jetzt beenden, wird das Programm nicht installiert.%n%nSie können das Setup zu einem späteren Zeitpunkt nochmals ausführen, um die Installation zu vervollständigen.%n%nSetup verlassen? +AboutSetupMenuItem=&Über das Setup ... +AboutSetupTitle=Über das Setup +AboutSetupMessage=%1 Version %2%n%3%n%n%1 Webseite:%n%4 +AboutSetupNote= +TranslatorNote=German translation maintained by Jens Brand (jens.brand@wolf-software.de) + +; *** Buttons +ButtonBack=< &Zurück +ButtonNext=&Weiter > +ButtonInstall=&Installieren +ButtonOK=OK +ButtonCancel=Abbrechen +ButtonYes=&Ja +ButtonYesToAll=J&a für Alle +ButtonNo=&Nein +ButtonNoToAll=N&ein für Alle +ButtonFinish=&Fertigstellen +ButtonBrowse=&Durchsuchen ... +ButtonWizardBrowse=Du&rchsuchen ... +ButtonNewFolder=&Neuen Ordner erstellen + +; *** "Select Language" dialog messages +SelectLanguageTitle=Setup-Sprache auswählen +SelectLanguageLabel=Wählen Sie die Sprache aus, die während der Installation benutzt werden soll: + +; *** Common wizard text +ClickNext="Weiter" zum Fortfahren, "Abbrechen" zum Verlassen. +BeveledLabel= +BrowseDialogTitle=Ordner suchen +BrowseDialogLabel=Wählen Sie einen Ordner aus und klicken Sie danach auf "OK". +NewFolderName=Neuer Ordner + +; *** "Welcome" wizard page +WelcomeLabel1=Willkommen zum [name] Setup-Assistenten +WelcomeLabel2=Dieser Assistent wird jetzt [name/ver] auf Ihrem Computer installieren.%n%nSie sollten alle anderen Anwendungen beenden, bevor Sie mit dem Setup fortfahren. + +; *** "Password" wizard page +WizardPassword=Passwort +PasswordLabel1=Diese Installation wird durch ein Passwort geschützt. +PasswordLabel3=Bitte geben Sie das Passwort ein und klicken Sie danach auf "Weiter". Achten Sie auf korrekte Groß-/Kleinschreibung. +PasswordEditLabel=&Passwort: +IncorrectPassword=Das eingegebene Passwort ist nicht korrekt. Bitte versuchen Sie es noch einmal. + +; *** "License Agreement" wizard page +WizardLicense=Lizenzvereinbarung +LicenseLabel=Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren. +LicenseLabel3=Lesen Sie bitte die folgenden Lizenzvereinbarungen. Benutzen Sie bei Bedarf die Bildlaufleiste oder drücken Sie die "Bild Ab"-Taste. +LicenseAccepted=Ich &akzeptiere die Vereinbarung +LicenseNotAccepted=Ich &lehne die Vereinbarung ab + +; *** "Information" wizard pages +WizardInfoBefore=Information +InfoBeforeLabel=Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren. +InfoBeforeClickLabel=Klicken Sie auf "Weiter", sobald Sie bereit sind, mit dem Setup fortzufahren. +WizardInfoAfter=Information +InfoAfterLabel=Lesen Sie bitte folgende wichtige Informationen, bevor Sie fortfahren. +InfoAfterClickLabel=Klicken Sie auf "Weiter", sobald Sie bereit sind, mit dem Setup fortzufahren. + +; *** "User Information" wizard page +WizardUserInfo=Benutzerinformationen +UserInfoDesc=Bitte tragen Sie Ihre Daten ein. +UserInfoName=&Name: +UserInfoOrg=&Organisation: +UserInfoSerial=&Seriennummer: +UserInfoNameRequired=Sie müssen einen Namen eintragen. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Ziel-Ordner wählen +SelectDirDesc=Wohin soll [name] installiert werden? +SelectDirLabel3=Das Setup wird [name] in den folgenden Ordner installieren. +SelectDirBrowseLabel=Klicken Sie auf "Weiter", um fortzufahren. Klicken Sie auf "Durchsuchen", falls Sie einen anderen Ordner auswählen möchten. +DiskSpaceGBLabel=Mindestens [gb] GB freier Speicherplatz ist erforderlich. +DiskSpaceMBLabel=Mindestens [mb] MB freier Speicherplatz ist erforderlich. +CannotInstallToNetworkDrive=Das Setup kann nicht in einen Netzwerk-Pfad installieren. +CannotInstallToUNCPath=Das Setup kann nicht in einen UNC-Pfad installieren. Wenn Sie auf ein Netzlaufwerk installieren möchten, müssen Sie dem Netzwerkpfad einen Laufwerksbuchstaben zuordnen. +InvalidPath=Sie müssen einen vollständigen Pfad mit einem Laufwerksbuchstaben angeben, z. B.:%n%nC:\Beispiel%n%noder einen UNC-Pfad in der Form:%n%n\\Server\Freigabe +InvalidDrive=Das angegebene Laufwerk bzw. der UNC-Pfad existiert nicht oder es kann nicht darauf zugegriffen werden. Wählen Sie bitte einen anderen Ordner. +DiskSpaceWarningTitle=Nicht genug freier Speicherplatz +DiskSpaceWarning=Das Setup benötigt mindestens %1 KB freien Speicherplatz zum Installieren, aber auf dem ausgewählten Laufwerk sind nur %2 KB verfügbar.%n%nMöchten Sie trotzdem fortfahren? +DirNameTooLong=Der Ordnername/Pfad ist zu lang. +InvalidDirName=Der Ordnername ist nicht gültig. +BadDirName32=Ordnernamen dürfen keine der folgenden Zeichen enthalten:%n%n%1 +DirExistsTitle=Ordner existiert bereits +DirExists=Der Ordner:%n%n%1%n%n existiert bereits. Möchten Sie trotzdem in diesen Ordner installieren? +DirDoesntExistTitle=Ordner ist nicht vorhanden +DirDoesntExist=Der Ordner:%n%n%1%n%nist nicht vorhanden. Soll der Ordner erstellt werden? + +; *** "Select Components" wizard page +WizardSelectComponents=Komponenten auswählen +SelectComponentsDesc=Welche Komponenten sollen installiert werden? +SelectComponentsLabel2=Wählen Sie die Komponenten aus, die Sie installieren möchten. Klicken Sie auf "Weiter", wenn Sie bereit sind, fortzufahren. +FullInstallation=Vollständige Installation +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Kompakte Installation +CustomInstallation=Benutzerdefinierte Installation +NoUninstallWarningTitle=Komponenten vorhanden +NoUninstallWarning=Das Setup hat festgestellt, dass die folgenden Komponenten bereits auf Ihrem Computer installiert sind:%n%n%1%n%nDiese nicht mehr ausgewählten Komponenten werden nicht vom Computer entfernt.%n%nMöchten Sie trotzdem fortfahren? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Die aktuelle Auswahl erfordert mindestens [gb] GB Speicherplatz. +ComponentsDiskSpaceMBLabel=Die aktuelle Auswahl erfordert mindestens [mb] MB Speicherplatz. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Zusätzliche Aufgaben auswählen +SelectTasksDesc=Welche zusätzlichen Aufgaben sollen ausgeführt werden? +SelectTasksLabel2=Wählen Sie die zusätzlichen Aufgaben aus, die das Setup während der Installation von [name] ausführen soll, und klicken Sie danach auf "Weiter". + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Startmenü-Ordner auswählen +SelectStartMenuFolderDesc=Wo soll das Setup die Programm-Verknüpfungen erstellen? +SelectStartMenuFolderLabel3=Das Setup wird die Programm-Verknüpfungen im folgenden Startmenü-Ordner erstellen. +SelectStartMenuFolderBrowseLabel=Klicken Sie auf "Weiter", um fortzufahren. Klicken Sie auf "Durchsuchen", falls Sie einen anderen Ordner auswählen möchten. +MustEnterGroupName=Sie müssen einen Ordnernamen eingeben. +GroupNameTooLong=Der Ordnername/Pfad ist zu lang. +InvalidGroupName=Der Ordnername ist nicht gültig. +BadGroupName=Der Ordnername darf keine der folgenden Zeichen enthalten:%n%n%1 +NoProgramGroupCheck2=&Keinen Ordner im Startmenü erstellen + +; *** "Ready to Install" wizard page +WizardReady=Bereit zur Installation. +ReadyLabel1=Das Setup ist jetzt bereit, [name] auf Ihrem Computer zu installieren. +ReadyLabel2a=Klicken Sie auf "Installieren", um mit der Installation zu beginnen, oder auf "Zurück", um Ihre Einstellungen zu überprüfen oder zu ändern. +ReadyLabel2b=Klicken Sie auf "Installieren", um mit der Installation zu beginnen. +ReadyMemoUserInfo=Benutzerinformationen: +ReadyMemoDir=Ziel-Ordner: +ReadyMemoType=Setup-Typ: +ReadyMemoComponents=Ausgewählte Komponenten: +ReadyMemoGroup=Startmenü-Ordner: +ReadyMemoTasks=Zusätzliche Aufgaben: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Lade zusätzliche Dateien herunter... +ButtonStopDownload=Download &abbrechen +StopDownload=Sind Sie sicher, dass Sie den Download abbrechen wollen? +ErrorDownloadAborted=Download abgebrochen +ErrorDownloadFailed=Download fehlgeschlagen: %1 %2 +ErrorDownloadSizeFailed=Fehler beim Ermitteln der Größe: %1 %2 +ErrorFileHash1=Fehler beim Ermitteln der Datei-Prüfsumme: %1 +ErrorFileHash2=Ungültige Datei-Prüfsumme: erwartet %1, gefunden %2 +ErrorProgress=Ungültiger Fortschritt: %1 von %2 +ErrorFileSize=Ungültige Dateigröße: erwartet %1, gefunden %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Vorbereitung der Installation +PreparingDesc=Das Setup bereitet die Installation von [name] auf diesem Computer vor. +PreviousInstallNotCompleted=Eine vorherige Installation/Deinstallation eines Programms wurde nicht abgeschlossen. Der Computer muss neu gestartet werden, um die Installation/Deinstallation zu beenden.%n%nStarten Sie das Setup nach dem Neustart Ihres Computers erneut, um die Installation von [name] durchzuführen. +CannotContinue=Das Setup kann nicht fortfahren. Bitte klicken Sie auf "Abbrechen" zum Verlassen. +ApplicationsFound=Die folgenden Anwendungen benutzen Dateien, die aktualisiert werden müssen. Es wird empfohlen, Setup zu erlauben, diese Anwendungen zu schließen. +ApplicationsFound2=Die folgenden Anwendungen benutzen Dateien, die aktualisiert werden müssen. Es wird empfohlen, Setup zu erlauben, diese Anwendungen zu schließen. Nachdem die Installation fertiggestellt wurde, versucht Setup, diese Anwendungen wieder zu starten. +CloseApplications=&Schließe die Anwendungen automatisch +DontCloseApplications=Schließe die A&nwendungen nicht +ErrorCloseApplications=Das Setup konnte nicht alle Anwendungen automatisch schließen. Es wird empfohlen, alle Anwendungen zu schließen, die Dateien benutzen, die vom Setup vor einer Fortsetzung aktualisiert werden müssen. +PrepareToInstallNeedsRestart=Das Setup muss Ihren Computer neu starten. Führen Sie nach dem Neustart Setup erneut aus, um die Installation von [name] abzuschließen.%n%nWollen Sie jetzt neu starten? + +; *** "Installing" wizard page +WizardInstalling=Installiere ... +InstallingLabel=Warten Sie bitte, während [name] auf Ihrem Computer installiert wird. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Beenden des [name] Setup-Assistenten +FinishedLabelNoIcons=Das Setup hat die Installation von [name] auf Ihrem Computer abgeschlossen. +FinishedLabel=Das Setup hat die Installation von [name] auf Ihrem Computer abgeschlossen. Die Anwendung kann über die installierten Programm-Verknüpfungen gestartet werden. +ClickFinish=Klicken Sie auf "Fertigstellen", um das Setup zu beenden. +FinishedRestartLabel=Um die Installation von [name] abzuschließen, muss das Setup Ihren Computer neu starten. Möchten Sie jetzt neu starten? +FinishedRestartMessage=Um die Installation von [name] abzuschließen, muss das Setup Ihren Computer neu starten.%n%nMöchten Sie jetzt neu starten? +ShowReadmeCheck=Ja, ich möchte die LIESMICH-Datei sehen +YesRadio=&Ja, Computer jetzt neu starten +NoRadio=&Nein, ich werde den Computer später neu starten +; used for example as 'Run MyProg.exe' +RunEntryExec=%1 starten +; used for example as 'View Readme.txt' +RunEntryShellExec=%1 anzeigen + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Nächsten Datenträger einlegen +SelectDiskLabel2=Legen Sie bitte Datenträger %1 ein und klicken Sie auf "OK".%n%nWenn sich die Dateien von diesem Datenträger in einem anderen als dem angezeigten Ordner befinden, dann geben Sie bitte den korrekten Pfad ein oder klicken auf "Durchsuchen". +PathLabel=&Pfad: +FileNotInDir2=Die Datei "%1" befindet sich nicht in "%2". Bitte Ordner ändern oder richtigen Datenträger einlegen. +SelectDirectoryLabel=Geben Sie bitte an, wo der nächste Datenträger eingelegt wird. + +; *** Installation phase messages +SetupAborted=Das Setup konnte nicht abgeschlossen werden.%n%nBeheben Sie bitte das Problem und starten Sie das Setup erneut. +AbortRetryIgnoreSelectAction=Bitte auswählen +AbortRetryIgnoreRetry=&Nochmals versuchen +AbortRetryIgnoreIgnore=&Den Fehler ignorieren und fortfahren +AbortRetryIgnoreCancel=Installation abbrechen + +; *** Installation status messages +StatusClosingApplications=Anwendungen werden geschlossen ... +StatusCreateDirs=Ordner werden erstellt ... +StatusExtractFiles=Dateien werden entpackt ... +StatusCreateIcons=Verknüpfungen werden erstellt ... +StatusCreateIniEntries=INI-Einträge werden erstellt ... +StatusCreateRegistryEntries=Registry-Einträge werden erstellt ... +StatusRegisterFiles=Dateien werden registriert ... +StatusSavingUninstall=Deinstallationsinformationen werden gespeichert ... +StatusRunProgram=Installation wird beendet ... +StatusRestartingApplications=Neustart der Anwendungen ... +StatusRollback=Änderungen werden rückgängig gemacht ... + +; *** Misc. errors +ErrorInternal2=Interner Fehler: %1 +ErrorFunctionFailedNoCode=%1 schlug fehl +ErrorFunctionFailed=%1 schlug fehl; Code %2 +ErrorFunctionFailedWithMessage=%1 schlug fehl; Code %2.%n%3 +ErrorExecutingProgram=Datei kann nicht ausgeführt werden:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Registry-Schlüssel konnte nicht geöffnet werden:%n%1\%2 +ErrorRegCreateKey=Registry-Schlüssel konnte nicht erstellt werden:%n%1\%2 +ErrorRegWriteKey=Fehler beim Schreiben des Registry-Schlüssels:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Fehler beim Erstellen eines INI-Eintrages in der Datei "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=Diese Datei &überspringen (nicht empfohlen) +FileAbortRetryIgnoreIgnoreNotRecommended=Den Fehler &ignorieren und fortfahren (nicht empfohlen) +SourceIsCorrupted=Die Quelldatei ist beschädigt +SourceDoesntExist=Die Quelldatei "%1" existiert nicht +ExistingFileReadOnly2=Die vorhandene Datei kann nicht ersetzt werden, da sie schreibgeschützt ist. +ExistingFileReadOnlyRetry=&Den Schreibschutz entfernen und noch einmal versuchen +ExistingFileReadOnlyKeepExisting=Die &vorhandene Datei behalten +ErrorReadingExistingDest=Lesefehler in Datei: +FileExistsSelectAction=Aktion auswählen +FileExists2=Die Datei ist bereits vorhanden. +FileExistsOverwriteExisting=Vorhandene Datei &überschreiben +FileExistsKeepExisting=Vorhandene Datei &behalten +FileExistsOverwriteOrKeepAll=&Dies auch für die nächsten Konflikte ausführen +ExistingFileNewerSelectAction=Aktion auswählen +ExistingFileNewer2=Die vorhandene Datei ist neuer als die Datei, die installiert werden soll. +ExistingFileNewerOverwriteExisting=Vorhandene Datei &überschreiben +ExistingFileNewerKeepExisting=Vorhandene Datei &behalten (empfohlen) +ExistingFileNewerOverwriteOrKeepAll=&Dies auch für die nächsten Konflikte ausführen +ErrorChangingAttr=Fehler beim Ändern der Datei-Attribute: +ErrorCreatingTemp=Fehler beim Erstellen einer Datei im Ziel-Ordner: +ErrorReadingSource=Fehler beim Lesen der Quelldatei: +ErrorCopying=Fehler beim Kopieren einer Datei: +ErrorReplacingExistingFile=Fehler beim Ersetzen einer vorhandenen Datei: +ErrorRestartReplace="Ersetzen nach Neustart" fehlgeschlagen: +ErrorRenamingTemp=Fehler beim Umbenennen einer Datei im Ziel-Ordner: +ErrorRegisterServer=DLL/OCX konnte nicht registriert werden: %1 +ErrorRegSvr32Failed=RegSvr32-Aufruf scheiterte mit Exit-Code %1 +ErrorRegisterTypeLib=Typen-Bibliothek konnte nicht registriert werden: %1 + +; *** Uninstall display name markings +; used for example as 'Mein Programm (32 Bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'Mein Programm (32 Bit, Alle Benutzer)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32 Bit +UninstallDisplayNameMark64Bit=64 Bit +UninstallDisplayNameMarkAllUsers=Alle Benutzer +UninstallDisplayNameMarkCurrentUser=Aktueller Benutzer + +; *** Post-installation errors +ErrorOpeningReadme=Fehler beim Öffnen der LIESMICH-Datei. +ErrorRestartingComputer=Das Setup konnte den Computer nicht neu starten. Bitte führen Sie den Neustart manuell durch. + +; *** Uninstaller messages +UninstallNotFound=Die Datei "%1" existiert nicht. Entfernen der Anwendung fehlgeschlagen. +UninstallOpenError=Die Datei "%1" konnte nicht geöffnet werden. Entfernen der Anwendung fehlgeschlagen. +UninstallUnsupportedVer=Das Format der Deinstallationsdatei "%1" konnte nicht erkannt werden. Entfernen der Anwendung fehlgeschlagen. +UninstallUnknownEntry=In der Deinstallationsdatei wurde ein unbekannter Eintrag (%1) gefunden. +ConfirmUninstall=Sind Sie sicher, dass Sie %1 und alle zugehörigen Komponenten entfernen möchten? +UninstallOnlyOnWin64=Diese Installation kann nur unter 64-Bit-Windows-Versionen entfernt werden. +OnlyAdminCanUninstall=Diese Installation kann nur von einem Benutzer mit Administrator-Rechten entfernt werden. +UninstallStatusLabel=Warten Sie bitte, während %1 von Ihrem Computer entfernt wird. +UninstalledAll=%1 wurde erfolgreich von Ihrem Computer entfernt. +UninstalledMost=Entfernen von %1 beendet.%n%nEinige Komponenten konnten nicht entfernt werden. Diese können von Ihnen manuell gelöscht werden. +UninstalledAndNeedsRestart=Um die Deinstallation von %1 abzuschließen, muss Ihr Computer neu gestartet werden.%n%nMöchten Sie jetzt neu starten? +UninstallDataCorrupted="%1"-Datei ist beschädigt. Entfernen der Anwendung fehlgeschlagen. + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Gemeinsame Datei entfernen? +ConfirmDeleteSharedFile2=Das System zeigt an, dass die folgende gemeinsame Datei von keinem anderen Programm mehr benutzt wird. Möchten Sie diese Datei entfernen lassen?%nSollte es doch noch Programme geben, die diese Datei benutzen und sie wird entfernt, funktionieren diese Programme vielleicht nicht mehr richtig. Wenn Sie unsicher sind, wählen Sie "Nein", um die Datei im System zu belassen. Es schadet Ihrem System nicht, wenn Sie die Datei behalten. +SharedFileNameLabel=Dateiname: +SharedFileLocationLabel=Ordner: +WizardUninstalling=Entfernen (Status) +StatusUninstalling=Entferne %1 ... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Installation von %1. +ShutdownBlockReasonUninstallingApp=Deinstallation von %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 Version %2 +AdditionalIcons=Zusätzliche Symbole: +CreateDesktopIcon=&Desktop-Symbol erstellen +CreateQuickLaunchIcon=Symbol in der Schnellstartleiste erstellen +ProgramOnTheWeb=%1 im Internet +UninstallProgram=%1 entfernen +LaunchProgram=%1 starten +AssocFileExtension=&Registriere %1 mit der %2-Dateierweiterung +AssocingFileExtension=%1 wird mit der %2-Dateierweiterung registriert... +AutoStartProgramGroupDescription=Beginn des Setups: +AutoStartProgram=Starte automatisch%1 +AddonHostProgramNotFound=%1 konnte im ausgewählten Ordner nicht gefunden werden.%n%nMöchten Sie dennoch fortfahren? + diff --git a/installer/innosetup/Languages/Greek.isl b/installer/innosetup/Languages/Greek.isl index eef0cc8dd..8e603194f 100644 --- a/installer/innosetup/Languages/Greek.isl +++ b/installer/innosetup/Languages/Greek.isl @@ -1,7 +1,7 @@ -; *** Inno Setup version 6.0.0+ Greek messages *** +; *** Inno Setup version 6.1.0+ Greek messages *** ; ; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ +; https://jrsoftware.org/files/istrans/ ; ; Note: When translating this text, do not add periods (.) to the end of ; messages that didn't have them already, because on those messages Inno @@ -10,7 +10,7 @@ ; ; Originally translated by Anastasis Chatzioglou, baldycom@hotmail.com ; Updated by XhmikosR [XhmikosR, my_nickname at yahoo dot com] -; Updated to version 6.0.0+ by V. Karamichail, v.karamichail@outlook.com +; Updated to version 6.1.0+ by Vasileios Karamichail, v.karamichail@outlook.com ; [LangOptions] @@ -156,6 +156,7 @@ WizardSelectDir=Επιλογή Φακέλου Εγκατάστασης SelectDirDesc=Πού θέλετε να εγκατασταθεί το [name]; SelectDirLabel3=Ο Οδηγός Εγκατάστασης θα εγκαταστήσει το [name] στον ακόλουθο φάκελο. SelectDirBrowseLabel=Για να συνεχίσετε, πατήστε Επόμενο. Εάν θέλετε να επιλέξετε διαφορετικό φάκελο, πατήστε Αναζήτηση. +DiskSpaceGBLabel=Απαιτούνται τουλάχιστον [gb] GB ελεύθερου χώρου στο δίσκο. DiskSpaceMBLabel=Απαιτούνται τουλάχιστον [mb] MB ελεύθερου χώρου στο δίσκο. CannotInstallToNetworkDrive=Η εγκατάσταση δεν μπορεί να γίνει σε δίσκο δικτύου. CannotInstallToUNCPath=Η εγκατάσταση δεν μπορεί να γίνει σε διαδρομή UNC. @@ -183,6 +184,7 @@ NoUninstallWarningTitle=Οι Λειτουργικές Μονάδες Υπάρχ NoUninstallWarning=Ο Οδηγός Εγκατάστασης εντόπισε ότι τα ακόλουθα στοιχεία είναι ήδη εγκατεστημένα στον υπολογιστή σας:%n%n%1%n%nΑποεπιλέγοντας αυτά τα στοιχεία δεν θα απεγκατασταθούν.%n%nΘέλετε να συνεχίσετε παρόλα αυτά; ComponentSize1=%1 KB ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Η τρέχουσα επιλογή απαιτεί τουλάχιστον [gb] GB χώρου στο δίσκο. ComponentsDiskSpaceMBLabel=Η τρέχουσα επιλογή απαιτεί τουλάχιστον [mb] MB χώρου στο δίσκο. ; *** "Select Additional Tasks" wizard page @@ -213,6 +215,18 @@ ReadyMemoComponents=Επιλεγμένες λειτουργικές μονάδε ReadyMemoGroup=Φάκελος στο μενού Έναρξη: ReadyMemoTasks=Επιπλέον ενέργειες: +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Λήψη πρόσθετων αρχείων... +ButtonStopDownload=&Διακοπή λήψης +StopDownload=Είστε βέβαιοι ότι θέλετε να διακόψετε τη λήψη; +ErrorDownloadAborted=Η λήψη ακυρώθηκε +ErrorDownloadFailed=Η λήψη απέτυχε: %1 %2 +ErrorDownloadSizeFailed=Η λήψη του μεγέθους απέτυχε: %1 %2 +ErrorFileHash1=Αποτυχία υπολογισμού hash: %1 +ErrorFileHash2=Μη έγκυρο hash: αναμενόμενο %1, βρέθηκε %2 +ErrorProgress=Μη έγκυρη πρόοδος: %1 από %2 +ErrorFileSize=Μη έγκυρο μέγεθος αρχείου: αναμενόμενο %1, βρέθηκε %2 + ; *** "Preparing to Install" wizard page WizardPreparing=Προετοιμασία Εγκατάστασης PreparingDesc=Ο Οδηγός Εγκατάστασης προετοιμάζεται για την εγκατάσταση του [name] στον υπολογιστή σας. @@ -222,7 +236,8 @@ ApplicationsFound=Οι ακόλουθες εφαρμογές χρησιμοπο ApplicationsFound2=Οι ακόλουθες εφαρμογές χρησιμοποιούν αρχεία που πρέπει να ενημερωθούν από τον Οδηγό Εγκατάστασης. Συνιστάται να επιτρέψετε στον Οδηγό Εγκατάστασης να κλείσει αυτόματα αυτές τις εφαρμογές. Μετά την ολοκλήρωση της εγκατάστασης, ο Οδηγός Εγκατάστασης θα επιχειρήσει να κάνει επανεκκίνηση των εφαρμογών. CloseApplications=&Αυτόματο κλείσιμο των εφαρμογών DontCloseApplications=&Χωρίς κλείσιμο των εφαρμογών -ErrorCloseApplications=Η εγκατάσταση δεν μπόρεσε να κλείσει αυτόματα όλες τις εφαρμογές. Συνιστάται να κλείσετε όλες τις εφαρμογές που χρησιμοποιούν αρχεία που πρέπει να ενημερωθούν από τον Οδηγό Εγκατάστασης προτού συνεχίσετε. +ErrorCloseApplications=Ο Οδηγός Εγκατάστασης δεν μπόρεσε να κλείσει αυτόματα όλες τις εφαρμογές. Συνιστάται να κλείσετε όλες τις εφαρμογές που χρησιμοποιούν αρχεία που πρέπει να ενημερωθούν από τον Οδηγό Εγκατάστασης προτού συνεχίσετε. +PrepareToInstallNeedsRestart=Ο Οδηγός Εγκατάστασης πρέπει να κάνει επανεκκίνηση του υπολογιστή σας. Μετά την επανεκκίνηση του υπολογιστή σας, εκτελέστε ξανά τον Οδηγό Εγκατάστασης για να ολοκληρώσετε την εγκατάσταση του [name].%n%nΘα θέλατε να κάνετε επανεκκίνηση τώρα; ; *** "Installing" wizard page WizardInstalling=Εγκατάσταση @@ -294,8 +309,16 @@ ExistingFileReadOnly2=Το υπάρχον αρχείο δεν μπόρεσε ν ExistingFileReadOnlyRetry=&Καταργήστε το χαρακτηριστικό μόνο για ανάγνωση και δοκιμάστε ξανά ExistingFileReadOnlyKeepExisting=&Διατηρήστε το υπάρχον αρχείο ErrorReadingExistingDest=Παρουσιάστηκε σφάλμα κατά την προσπάθεια ανάγνωσης του υπάρχοντος αρχείου: -FileExists=Το αρχείο υπάρχει ήδη.%n%nΘα θέλατε ο Οδηγός Εγκατάστασης να το αντικαταστήσει; -ExistingFileNewer=Το υπάρχον αρχείο είναι νεότερο από αυτό που ο Οδηγός Εγκατάστασης που προσπαθεί να εγκαταστήσει. Συνιστάται να διατηρείτε το υπάρχον αρχείο.%n%nΘέλετε να διατηρήσετε το υπάρχον αρχείο; +FileExistsSelectAction=Επιλέξτε ενέργεια +FileExists2=Το αρχείο υπάρχει ήδη. +FileExistsOverwriteExisting=&Αντικατάσταση υπάρχοντος αρχείου +FileExistsKeepExisting=&Διατήρηση υπάρχοντος αρχείου +FileExistsOverwriteOrKeepAll=&Να γίνει το ίδιο για τις επόμενες διενέξεις +ExistingFileNewerSelectAction=Επιλέξτε ενέργεια +ExistingFileNewer2=Το υπάρχον αρχείο είναι νεότερο από αυτό που προσπαθεί να εγκαταστήσει ο Οδηγός Εγκατάστασης. +ExistingFileNewerOverwriteExisting=&Αντικατάσταση υπάρχοντος αρχείου +ExistingFileNewerKeepExisting=&Διατήρηση υπάρχοντος αρχείου (συνιστάται) +ExistingFileNewerOverwriteOrKeepAll=&Να γίνει το ίδιο για τις επόμενες διενέξεις ErrorChangingAttr=Παρουσιάστηκε σφάλμα κατά την προσπάθεια αλλαγής των χαρακτηριστικών του υπάρχοντος αρχείου: ErrorCreatingTemp=Παρουσιάστηκε σφάλμα κατά την προσπάθεια δημιουργίας ενός αρχείου στον φακέλο προορισμού: ErrorReadingSource=Παρουσιάστηκε σφάλμα κατά την προσπάθεια ανάγνωσης του αρχείου προέλευσης: @@ -364,3 +387,4 @@ AssocingFileExtension=Γίνεται συσχέτιση του %1 με την ε AutoStartProgramGroupDescription=Εκκίνηση: AutoStartProgram=Αυτόματη εκκίνηση του %1 AddonHostProgramNotFound=Το %1 δε βρέθηκε στο φάκελο που επιλέξατε.%n%nΘέλετε να συνεχίσετε παρόλα αυτά; + diff --git a/installer/innosetup/Languages/Hebrew.isl b/installer/innosetup/Languages/Hebrew.isl new file mode 100644 index 000000000..98d9b498f --- /dev/null +++ b/installer/innosetup/Languages/Hebrew.isl @@ -0,0 +1,377 @@ +; *** Inno Setup version 6.1.0+ Hebrew messages (s_h(at)enativ.com) *** +; +; https://jrsoftware.org/files/istrans/ +; Translated by s_h (s_h@enativ.com) (c) 2020 +; + + +[LangOptions] +LanguageName=<05E2><05D1><05E8><05D9><05EA> +LanguageID=$040D +LanguageCodePage=1255 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Tahoma +;WelcomeFontSize=11 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 +RightToLeft=yes + +[Messages] + +; *** Application titles +SetupAppTitle= +SetupWindowTitle= - %1 +UninstallAppTitle= +UninstallAppFullTitle= %1 + +; *** Misc. common +InformationTitle= +ConfirmTitle= +ErrorTitle= + +; *** SetupLdr messages +SetupLdrStartupMessage= %1 . ? +LdrCannotCreateTemp= . +LdrCannotExecTemp= . + +; *** Startup error messages +LastErrorMessage=%1.%n%n %2: %3 +SetupFileMissing= %1 . . +SetupFileCorrupt= . . +SetupFileCorruptOrWrongVer= , . . +InvalidParameter= :%n%n%1 +SetupAlreadyRunning= . +WindowsVersionNotSupported= . +WindowsServicePackRequired= %1 %2 . +NotOnThisPlatform= %1. +OnlyOnThisPlatform= %1. +OnlyOnTheseArchitectures= '' :%n%n%1 +WinVersionTooLowError= %1 %2. +WinVersionTooHighError= %1 %2 +AdminPrivilegesRequired= . +PowerUserPrivilegesRequired= , ' ' . +SetupAppRunningError= %1 .%n%n , '' , '' . +UninstallAppRunningError= %1 .%n%n , '' , '' . + +; *** Startup questions +PrivilegesRequiredOverrideTitle= +PrivilegesRequiredOverrideInstruction= +PrivilegesRequiredOverrideText1=%1 ( ), . +PrivilegesRequiredOverrideText2=%1 , ( ). +PrivilegesRequiredOverrideAllUsers= & +PrivilegesRequiredOverrideAllUsersRecommended= & () +PrivilegesRequiredOverrideCurrentUser= & +PrivilegesRequiredOverrideCurrentUserRecommended= & () + +; *** Misc. errors +ErrorCreatingDir= "%1" +ErrorTooManyFilesInDir= "%1" + +; *** Setup common messages +ExitSetupTitle= +ExitSetupMessage= . , .%n%n .%n%n ? +AboutSetupMenuItem=& ... +AboutSetupTitle= +AboutSetupMessage=%1 %2%n%3%n%n%1 :%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< & +ButtonNext=& > +ButtonInstall=& +ButtonOK= +ButtonCancel= +ButtonYes=& +ButtonYesToAll= & +ButtonNo=& +ButtonNoToAll=& +ButtonFinish=& +ButtonBrowse=&... +ButtonWizardBrowse=... +ButtonNewFolder=& + +; *** "Select Language" dialog messages +SelectLanguageTitle= +SelectLanguageLabel= . + +; *** Common wizard text +ClickNext= '' , '' . +BeveledLabel= +BrowseDialogTitle= +BrowseDialogLabel= '' +NewFolderName= + +; *** "Welcome" wizard page +WelcomeLabel1= [name] +WelcomeLabel2= [name/ver] .%n%n . + +; *** "Password" wizard page +WizardPassword= +PasswordLabel1= . +PasswordLabel3= , '' . , . +PasswordEditLabel=&: +IncorrectPassword= . . + +; *** "License Agreement" wizard page +WizardLicense= +LicenseLabel= . +LicenseLabel3= . . +LicenseAccepted= & +LicenseNotAccepted= & + +; *** "Information" wizard pages +WizardInfoBefore= +InfoBeforeLabel= . +InfoBeforeClickLabel= , ''. +WizardInfoAfter= +InfoAfterLabel= +InfoAfterClickLabel= , ''. + +; *** "User Information" wizard page +WizardUserInfo= +UserInfoDesc= . +UserInfoName=& : +UserInfoOrg=&: +UserInfoSerial=& : +UserInfoNameRequired= . + +; *** "Select Destination Location" wizard page +WizardSelectDir= +SelectDirDesc= [name]? +SelectDirLabel3= [name] . +SelectDirBrowseLabel=, ''. , ''. +DiskSpaceGBLabel= [gb] GB . +DiskSpaceMBLabel= [mb] MB . +CannotInstallToNetworkDrive= . +CannotInstallToUNCPath= UNC. +InvalidPath= ; :%n%nC:\APP%n%n UNC :%n%n\\server\share +InvalidDrive= -UNC . . +DiskSpaceWarningTitle= +DiskSpaceWarning= %1KB , %2KB . ? +DirNameTooLong= +InvalidDirName= . +BadDirName32= :%n%n%1 +DirExistsTitle= +DirExists=:%n%n%1%n%n . ? +DirDoesntExistTitle= +DirDoesntExist=:%n%n%1%n%n . ? + +; *** "Select Components" wizard page +WizardSelectComponents= +SelectComponentsDesc= ? +SelectComponentsLabel2= ; . '' . +FullInstallation= +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation= +CustomInstallation= +NoUninstallWarningTitle= +NoUninstallWarning= :%n%n%1%n .%n%n ? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel= [gb] GB . +ComponentsDiskSpaceMBLabel= [mb] MB . + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks= +SelectTasksDesc= ? +SelectTasksLabel2= [name], ''. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup= '' +SelectStartMenuFolderDesc= ? +SelectStartMenuFolderLabel3= ''. +SelectStartMenuFolderBrowseLabel=, ''. , ''. +MustEnterGroupName= . +GroupNameTooLong= +InvalidGroupName= -. +BadGroupName= :%n%n%1 +NoProgramGroupCheck2=& '' + +; *** "Ready to Install" wizard page +WizardReady= +ReadyLabel1= [name] . +ReadyLabel2a= '' , '' . +ReadyLabel2b= '' +ReadyMemoUserInfo= : +ReadyMemoDir= : +ReadyMemoType= : +ReadyMemoComponents= : +ReadyMemoGroup= '': +ReadyMemoTasks= : + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel= ... +ButtonStopDownload=& +StopDownload= ? +ErrorDownloadAborted= +ErrorDownloadFailed= : %1 %2 +ErrorDownloadSizeFailed= : %1 %2 +ErrorFileHash1= : %2 +ErrorFileHash2= : %2, %2 +ErrorProgress= : %1 %1 +ErrorFileSize= : %1, %1 + +; *** "Preparing to Install" wizard page +WizardPreparing= +PreparingDesc= [name] . +PreviousInstallNotCompleted=/ . .%n%n , [name]. +CannotContinue= . '' . +ApplicationsFound= . . +ApplicationsFound2= . . , . +CloseApplications=& +DontCloseApplications=& +ErrorCloseApplications= . . +PrepareToInstallNeedsRestart= . , [name].%n%n ? + +; *** "Installing" wizard page +WizardInstalling= +InstallingLabel= [name] . + +; *** "Setup Completed" wizard page +FinishedHeadingLabel= [name] +FinishedLabelNoIcons= [name] . +FinishedLabel= [name] . . +ClickFinish= '' . +FinishedRestartLabel= [name], . ? +FinishedRestartMessage= [name], .%n%n ? +ShowReadmeCheck=, -' ' +YesRadio=&, +NoRadio=&, +; used for example as 'Run MyProg.exe' +RunEntryExec= %1 +; used for example as 'View Readme.txt' +RunEntryShellExec= %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle= +SelectDiskLabel2= ' %1 ''.%n%n , ''. +PathLabel=&: +FileNotInDir2= "%1" "%2". . +SelectDirectoryLabel= . + +; *** Installation phase messages +SetupAborted= .%n%n . +AbortRetryIgnoreSelectAction= +AbortRetryIgnoreRetry=& +AbortRetryIgnoreIgnore=& +AbortRetryIgnoreCancel= + +; *** Installation status messages +StatusClosingApplications= ... +StatusCreateDirs= ... +StatusExtractFiles= ... +StatusCreateIcons= ... +StatusCreateIniEntries= INI... +StatusCreateRegistryEntries= ... +StatusRegisterFiles= ... +StatusSavingUninstall= ... +StatusRunProgram= ... +StatusRestartingApplications= ... +StatusRollback= ... + +; *** Misc. errors +ErrorInternal2= : %1 +ErrorFunctionFailedNoCode=%1 +ErrorFunctionFailed=%1 ; %2 +ErrorFunctionFailedWithMessage=%1 ; %2.%n%3 +ErrorExecutingProgram= :%n%1 + +; *** Registry errors +ErrorRegOpenKey= :%n%1\%2 +ErrorRegCreateKey= :%n%1\%2 +ErrorRegWriteKey= :%n%1\%2 + +; *** INI errors +ErrorIniEntry= INI "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=& ( ) +FileAbortRetryIgnoreIgnoreNotRecommended=& ( ) +SourceIsCorrupted= +SourceDoesntExist= "%1" +ExistingFileReadOnly2= . +ExistingFileReadOnlyRetry=& +ExistingFileReadOnlyKeepExisting=& +ErrorReadingExistingDest= : +FileExistsSelectAction= +FileExists2= . +FileExistsOverwriteExisting=& +FileExistsKeepExisting=& +FileExistsOverwriteOrKeepAll=& +ExistingFileNewerSelectAction= +ExistingFileNewer2= +ExistingFileNewerOverwriteExisting=& +ExistingFileNewerKeepExisting=& () +ExistingFileNewerOverwriteOrKeepAll=& +ErrorChangingAttr= : +ErrorCreatingTemp= : +ErrorReadingSource= : +ErrorCopying= : +ErrorReplacingExistingFile= : +ErrorRestartReplace= -RestartReplace: +ErrorRenamingTemp= : +ErrorRegisterServer= DLL/OCX: %1 +ErrorRegSvr32Failed=RegSvr32 %1 +ErrorRegisterTypeLib= : %1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers= +UninstallDisplayNameMarkCurrentUser= + +; *** Post-installation errors +ErrorOpeningReadme= ' '. +ErrorRestartingComputer= . . + +; *** Uninstaller messages +UninstallNotFound= "%1" . . +UninstallOpenError= "%1". . +UninstallUnsupportedVer= "%1" " . +UninstallUnknownEntry= (%1) . +ConfirmUninstall= %1 ? +UninstallOnlyOnWin64= '' 64-. +OnlyAdminCanUninstall= . +UninstallStatusLabel= %1 . +UninstalledAll=%1 . +UninstalledMost= %1 .%n%n " , . +UninstalledAndNeedsRestart= %1, .%n%n ? +UninstallDataCorrupted= "%1" . + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle= ? +ConfirmDeleteSharedFile2= . ?%n%n , . , ''. . +SharedFileNameLabel= : +SharedFileLocationLabel=: +WizardUninstalling= +StatusUninstalling= %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp= %1. +ShutdownBlockReasonUninstallingApp= %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 %2 +AdditionalIcons= : +CreateDesktopIcon= & +CreateQuickLaunchIcon= +ProgramOnTheWeb=%1 +UninstallProgram= %1 +LaunchProgram= %1 +AssocFileExtension=& %1 %2 +AssocingFileExtension= %1 %2 +AutoStartProgramGroupDescription= : +AutoStartProgram= %1 +AddonHostProgramNotFound=%1 .%n%n ? \ No newline at end of file diff --git a/installer/innosetup/Languages/Hungarian.isl b/installer/innosetup/Languages/Hungarian.isl index 7fdee0b99..e66ed76cd 100644 --- a/installer/innosetup/Languages/Hungarian.isl +++ b/installer/innosetup/Languages/Hungarian.isl @@ -1,6 +1,6 @@ -;Inno Setup version 6.0.3+ Hungarian messages -;Based on the translation of Kornl Pl, kornelpal@gmail.com -;Istvn Szab, E-mail: istvanszabo890629@gmail.com +; *** Inno Setup version 6.1.0+ Hungarian messages *** +; Based on the translation of Kornél Pál, kornelpal@gmail.com +; István Szabó, E-mail: istvanszabo890629@gmail.com ; ; To download user-contributed translations of this file, go to: ; http://www.jrsoftware.org/files/istrans/ @@ -30,282 +30,302 @@ LanguageCodePage=1250 [Messages] ; *** Application titles -SetupAppTitle=Telept -SetupWindowTitle=%1 - Telept -UninstallAppTitle=Eltvolt -UninstallAppFullTitle=%1 Eltvolt +SetupAppTitle=Telepítő +SetupWindowTitle=%1 - Telepítő +UninstallAppTitle=Eltávolító +UninstallAppFullTitle=%1 Eltávolító ; *** Misc. common -InformationTitle=Informcik -ConfirmTitle=Megerst +InformationTitle=Információk +ConfirmTitle=Megerősít ErrorTitle=Hiba ; *** SetupLdr messages -SetupLdrStartupMessage=%1 teleptve lesz. Szeretn folytatni? -LdrCannotCreateTemp=tmeneti fjl ltrehozsa nem lehetsges. A telepts megszaktva -LdrCannotExecTemp=Fjl futattsa nem lehetsges az tmeneti knyvtrban. A telepts megszaktva +SetupLdrStartupMessage=%1 telepítve lesz. Szeretné folytatni? +LdrCannotCreateTemp=Átmeneti fájl létrehozása nem lehetséges. A telepítés megszakítva +LdrCannotExecTemp=Fájl futattása nem lehetséges az átmeneti könyvtárban. A telepítés megszakítva HelpTextNote= ; *** Startup error messages LastErrorMessage=%1.%n%nHiba %2: %3 -SetupFileMissing=A(z) %1 fjl hinyzik a telept knyvtrbl. Krem hrtsa el a problmt, vagy szerezzen be egy msik pldnyt a programbl! -SetupFileCorrupt=A teleptsi fjlok srltek. Krem, szerezzen be j msolatot a programbl! -SetupFileCorruptOrWrongVer=A teleptsi fjlok srltek, vagy inkompatibilisek a telept ezen verzijval. Hrtsa el a problmt, vagy szerezzen be egy msik pldnyt a programbl! -InvalidParameter=A parancssorba tadott paramter rvnytelen:%n%n%1 -SetupAlreadyRunning=A Telept mr fut. -WindowsVersionNotSupported=A program nem tmogatja a Windows ezen verzijt. -WindowsServicePackRequired=A program futtatshoz %1 Service Pack %2 vagy jabb szksges. -NotOnThisPlatform=Ez a program nem futtathat %1 alatt. +SetupFileMissing=A(z) %1 fájl hiányzik a telepítő könyvtárából. Kérem hárítsa el a problémát, vagy szerezzen be egy másik példányt a programból! +SetupFileCorrupt=A telepítési fájlok sérültek. Kérem, szerezzen be új másolatot a programból! +SetupFileCorruptOrWrongVer=A telepítési fájlok sérültek, vagy inkompatibilisek a telepítő ezen verziójával. Hárítsa el a problémát, vagy szerezzen be egy másik példányt a programból! +InvalidParameter=A parancssorba átadott paraméter érvénytelen:%n%n%1 +SetupAlreadyRunning=A Telepítő már fut. +WindowsVersionNotSupported=A program nem támogatja a Windows ezen verzióját. +WindowsServicePackRequired=A program futtatásához %1 Service Pack %2 vagy újabb szükséges. +NotOnThisPlatform=Ez a program nem futtatható %1 alatt. OnlyOnThisPlatform=Ezt a programot %1 alatt kell futtatni. -OnlyOnTheseArchitectures=A program kizrlag a kvetkez processzor architektrkhoz tervezett Windows-on telepthet:%n%n%1 -WinVersionTooLowError=A program futtatshoz %1 %2 verzija vagy ksbbi szksges. -WinVersionTooHighError=Ez a program nem telepthet %1 %2 vagy ksbbire. -AdminPrivilegesRequired=Csak rendszergazdai mdban telepthet ez a program. -PowerUserPrivilegesRequired=Csak rendszergazdaknt vagy kiemelt felhasznlknt telepthet ez a program. -SetupAppRunningError=A telept gy szlelte %1 jelenleg fut.%n%nZrja be az sszes pldnyt, majd kattintson az 'OK'-ra a folytatshoz, vagy a 'Mgse'-re a kilpshez. -UninstallAppRunningError=Az eltvolt gy szlelte %1 jelenleg fut.%n%nZrja be az sszes pldnyt, majd kattintson az 'OK'-ra a folytatshoz, vagy a 'Mgse'-re a kilpshez. +OnlyOnTheseArchitectures=A program kizárólag a következő processzor architektúrákhoz tervezett Windows-on telepíthető:%n%n%1 +WinVersionTooLowError=A program futtatásához %1 %2 verziója vagy későbbi szükséges. +WinVersionTooHighError=Ez a program nem telepíthető %1 %2 vagy későbbire. +AdminPrivilegesRequired=Csak rendszergazdai módban telepíthető ez a program. +PowerUserPrivilegesRequired=Csak rendszergazdaként vagy kiemelt felhasználóként telepíthető ez a program. +SetupAppRunningError=A telepítő úgy észlelte %1 jelenleg fut.%n%nZárja be az összes példányt, majd kattintson az 'OK'-ra a folytatáshoz, vagy a 'Mégse'-re a kilépéshez. +UninstallAppRunningError=Az eltávolító úgy észlelte %1 jelenleg fut.%n%nZárja be az összes példányt, majd kattintson az 'OK'-ra a folytatáshoz, vagy a 'Mégse'-re a kilépéshez. ; *** Startup questions -PrivilegesRequiredOverrideTitle=Teleptsi md kivlasztsa -PrivilegesRequiredOverrideInstruction=Vlasszon teleptsi mdot -PrivilegesRequiredOverrideText1=%1 telepthet az sszes felhasznlnak (rendszergazdai jogok szksgesek), vagy csak magnak. -PrivilegesRequiredOverrideText2=%1 csak magnak telepthet, vagy az sszes felhasznlnak (rendszergazdai jogok szksgesek). -PrivilegesRequiredOverrideAllUsers=Telepts &mindenkinek -PrivilegesRequiredOverrideAllUsersRecommended=Telepts &mindenkinek (ajnlott) -PrivilegesRequiredOverrideCurrentUser=Telepts csak &nekem -PrivilegesRequiredOverrideCurrentUserRecommended=Telepts csak &nekem (ajnlott) +PrivilegesRequiredOverrideTitle=Telepítési mód kiválasztása +PrivilegesRequiredOverrideInstruction=Válasszon telepítési módot +PrivilegesRequiredOverrideText1=%1 telepíthető az összes felhasználónak (rendszergazdai jogok szükségesek), vagy csak magának. +PrivilegesRequiredOverrideText2=%1 csak magának telepíthető, vagy az összes felhasználónak (rendszergazdai jogok szükségesek). +PrivilegesRequiredOverrideAllUsers=Telepítés &mindenkinek +PrivilegesRequiredOverrideAllUsersRecommended=Telepítés &mindenkinek (ajánlott) +PrivilegesRequiredOverrideCurrentUser=Telepítés csak &nekem +PrivilegesRequiredOverrideCurrentUserRecommended=Telepítés csak &nekem (ajánlott) ; *** Misc. errors -ErrorCreatingDir=A Telept nem tudta ltrehozni a(z) "%1" knyvtrat -ErrorTooManyFilesInDir=Nem hozhat ltre fjl a(z) "%1" knyvtrban, mert az mr tl sok fjlt tartalmaz +ErrorCreatingDir=A Telepítő nem tudta létrehozni a(z) "%1" könyvtárat +ErrorTooManyFilesInDir=Nem hozható létre fájl a(z) "%1" könyvtárban, mert az már túl sok fájlt tartalmaz ; *** Setup common messages -ExitSetupTitle=Kilps a teleptbl -ExitSetupMessage=A telepts mg folyamatban van. Ha most kilp, a program nem kerl teleptsre.%n%nMsik alkalommal is futtathat a telepts befejezshez%n%nKilp a teleptbl? -AboutSetupMenuItem=&Nvjegy... -AboutSetupTitle=Telept nvjegye -AboutSetupMessage=%1 %2 verzi%n%3%n%nAz %1 honlapja:%n%4 +ExitSetupTitle=Kilépés a telepítőből +ExitSetupMessage=A telepítés még folyamatban van. Ha most kilép, a program nem kerül telepítésre.%n%nMásik alkalommal is futtatható a telepítés befejezéséhez%n%nKilép a telepítőből? +AboutSetupMenuItem=&Névjegy... +AboutSetupTitle=Telepítő névjegye +AboutSetupMessage=%1 %2 verzió%n%3%n%nAz %1 honlapja:%n%4 AboutSetupNote= TranslatorNote= ; *** Buttons ButtonBack=< &Vissza -ButtonNext=&Tovbb > -ButtonInstall=&Telept +ButtonNext=&Tovább > +ButtonInstall=&Telepít ButtonOK=OK -ButtonCancel=Mgse +ButtonCancel=Mégse ButtonYes=&Igen ButtonYesToAll=&Mindet ButtonNo=&Nem ButtonNoToAll=&Egyiket se -ButtonFinish=&Befejezs -ButtonBrowse=&Tallzs... -ButtonWizardBrowse=T&allzs... -ButtonNewFolder=j &knyvtr +ButtonFinish=&Befejezés +ButtonBrowse=&Tallózás... +ButtonWizardBrowse=T&allózás... +ButtonNewFolder=Új &könyvtár ; *** "Select Language" dialog messages -SelectLanguageTitle=Telept nyelvi bellts -SelectLanguageLabel=Vlassza ki a telepts alatt hasznlt nyelvet. +SelectLanguageTitle=Telepítő nyelvi beállítás +SelectLanguageLabel=Válassza ki a telepítés alatt használt nyelvet. ; *** Common wizard text -ClickNext=A folytatshoz kattintson a 'Tovbb'-ra, a kilpshez a 'Mgse'-re. +ClickNext=A folytatáshoz kattintson a 'Tovább'-ra, a kilépéshez a 'Mégse'-re. BeveledLabel= -BrowseDialogTitle=Vlasszon knyvtrt -BrowseDialogLabel=Vlasszon egy knyvtrat az albbi listbl, majd kattintson az 'OK'-ra. -NewFolderName=j knyvtr +BrowseDialogTitle=Válasszon könyvtárt +BrowseDialogLabel=Válasszon egy könyvtárat az alábbi listából, majd kattintson az 'OK'-ra. +NewFolderName=Új könyvtár ; *** "Welcome" wizard page -WelcomeLabel1=dvzli a(z) [name] Teleptvarzslja. -WelcomeLabel2=A(z) [name/ver] teleptsre kerl a szmtgpn.%n%nAjnlott minden, egyb fut alkalmazs bezrsa a folytats eltt. +WelcomeLabel1=Üdvözli a(z) [name] Telepítővarázslója. +WelcomeLabel2=A(z) [name/ver] telepítésre kerül a számítógépén.%n%nAjánlott minden, egyéb futó alkalmazás bezárása a folytatás előtt. ; *** "Password" wizard page -WizardPassword=Jelsz -PasswordLabel1=Ez a telepts jelszval vdett. -PasswordLabel3=Krem adja meg a jelszt, majd kattintson a 'Tovbb'-ra. A jelszavak kis- s nagy bet rzkenyek lehetnek. -PasswordEditLabel=&Jelsz: -IncorrectPassword=Az n ltal megadott jelsz helytelen. Prblja jra. +WizardPassword=Jelszó +PasswordLabel1=Ez a telepítés jelszóval védett. +PasswordLabel3=Kérem adja meg a jelszót, majd kattintson a 'Tovább'-ra. A jelszavak kis- és nagy betű érzékenyek lehetnek. +PasswordEditLabel=&Jelszó: +IncorrectPassword=Az ön által megadott jelszó helytelen. Próbálja újra. ; *** "License Agreement" wizard page -WizardLicense=Licencszerzds -LicenseLabel=Olvassa el figyelmesen az informcikat folytats eltt. -LicenseLabel3=Krem, olvassa el az albbi licencszerzdst. A telepts folytatshoz, el kell fogadnia a szerzdst. -LicenseAccepted=&Elfogadom a szerzdst -LicenseNotAccepted=&Nem fogadom el a szerzdst +WizardLicense=Licencszerződés +LicenseLabel=Olvassa el figyelmesen az információkat folytatás előtt. +LicenseLabel3=Kérem, olvassa el az alábbi licencszerződést. A telepítés folytatásához, el kell fogadnia a szerződést. +LicenseAccepted=&Elfogadom a szerződést +LicenseNotAccepted=&Nem fogadom el a szerződést ; *** "Information" wizard pages -WizardInfoBefore=Informcik -InfoBeforeLabel=Olvassa el a kvetkez fontos informcikat a folytats eltt. -InfoBeforeClickLabel=Ha kszen ll, kattintson a 'Tovbb'-ra. -WizardInfoAfter=Informcik -InfoAfterLabel=Olvassa el a kvetkez fontos informcikat a folytats eltt. -InfoAfterClickLabel=Ha kszen ll, kattintson a 'Tovbb'-ra. +WizardInfoBefore=Információk +InfoBeforeLabel=Olvassa el a következő fontos információkat a folytatás előtt. +InfoBeforeClickLabel=Ha készen áll, kattintson a 'Tovább'-ra. +WizardInfoAfter=Információk +InfoAfterLabel=Olvassa el a következő fontos információkat a folytatás előtt. +InfoAfterClickLabel=Ha készen áll, kattintson a 'Tovább'-ra. ; *** "User Information" wizard page -WizardUserInfo=Felhasznl adatai -UserInfoDesc=Krem, adja meg az adatait -UserInfoName=&Felhasznlnv: +WizardUserInfo=Felhasználó adatai +UserInfoDesc=Kérem, adja meg az adatait! +UserInfoName=&Felhasználónév: UserInfoOrg=&Szervezet: -UserInfoSerial=&Sorozatszm: -UserInfoNameRequired=Meg kell adnia egy nevet. +UserInfoSerial=&Sorozatszám: +UserInfoNameRequired=Meg kell adnia egy nevet! ; *** "Select Destination Location" wizard page -WizardSelectDir=Vlasszon clknyvtrat -SelectDirDesc=Hova telepljn a(z) [name]? -SelectDirLabel3=A(z) [name] az albbi knyvtrba lesz teleptve. -SelectDirBrowseLabel=A folytatshoz, kattintson a 'Tovbb'-ra. Ha msik knyvtrat vlasztana, kattintson a 'Tallzs'-ra. -DiskSpaceGBLabel=At least [gb] GB szabad terletre van szksg. -DiskSpaceMBLabel=Legalbb [mb] MB szabad terletre van szksg. -CannotInstallToNetworkDrive=A Telept nem tud hlzati meghajtra telepteni. -CannotInstallToUNCPath=A Telept nem tud hlzati UNC elrsi tra telepteni. -InvalidPath=Teljes tvonalat adjon meg, a meghajt betjelvel; pldul:%n%nC:\Alkalmazs%n%nvagy egy hlzati tvonalat a kvetkez alakban:%n%n\\kiszolgl\megoszts -InvalidDrive=A kivlasztott meghajt vagy hlzati megoszts nem ltezik vagy nem elrhet. Vlasszon egy msikat. -DiskSpaceWarningTitle=Nincs elg szabad terlet -DiskSpaceWarning=A Teleptnek legalbb %1 KB szabad lemezterletre van szksge, viszont a kivlasztott meghajtn csupn %2 KB ll rendelkezsre.%n%nMindenkppen folytatja? -DirNameTooLong=A knyvtr neve vagy az tvonal tl hossz. -InvalidDirName=A knyvtr neve rvnytelen. -BadDirName32=A knyvtrak nevei ezen karakterek egyikt sem tartalmazhatjk:%n%n%1 -DirExistsTitle=A knyvtr mr ltezik -DirExists=A knyvtr:%n%n%1%n%nmr ltezik. Mindenkpp ide akar telepteni? -DirDoesntExistTitle=A knyvtr nem ltezik -DirDoesntExist=A knyvtr:%n%n%1%n%nnem ltezik. Szeretn ltrehozni? +WizardSelectDir=Válasszon célkönyvtárat +SelectDirDesc=Hova települjön a(z) [name]? +SelectDirLabel3=A(z) [name] az alábbi könyvtárba lesz telepítve. +SelectDirBrowseLabel=A folytatáshoz, kattintson a 'Tovább'-ra. Ha másik könyvtárat választana, kattintson a 'Tallózás'-ra. +DiskSpaceGBLabel=Legalább [gb] GB szabad területre van szükség. +DiskSpaceMBLabel=Legalább [mb] MB szabad területre van szükség. +CannotInstallToNetworkDrive=A Telepítő nem tud hálózati meghajtóra telepíteni. +CannotInstallToUNCPath=A Telepítő nem tud hálózati UNC elérési útra telepíteni. +InvalidPath=Teljes útvonalat adjon meg, a meghajtó betűjelével; például:%n%nC:\Alkalmazás%n%nvagy egy hálózati útvonalat a következő alakban:%n%n\\kiszolgáló\megosztás +InvalidDrive=A kiválasztott meghajtó vagy hálózati megosztás nem létezik vagy nem elérhető. Válasszon egy másikat. +DiskSpaceWarningTitle=Nincs elég szabad terület +DiskSpaceWarning=A Telepítőnek legalább %1 KB szabad lemezterületre van szüksége, viszont a kiválasztott meghajtón csupán %2 KB áll rendelkezésre.%n%nMindenképpen folytatja? +DirNameTooLong=A könyvtár neve vagy az útvonal túl hosszú. +InvalidDirName=A könyvtár neve érvénytelen. +BadDirName32=A könyvtárak nevei ezen karakterek egyikét sem tartalmazhatják:%n%n%1 +DirExistsTitle=A könyvtár már létezik +DirExists=A könyvtár:%n%n%1%n%nmár létezik. Mindenképp ide akar telepíteni? +DirDoesntExistTitle=A könyvtár nem létezik +DirDoesntExist=A könyvtár:%n%n%1%n%nnem létezik. Szeretné létrehozni? ; *** "Select Components" wizard page -WizardSelectComponents=sszetevk kivlasztsa -SelectComponentsDesc=Mely sszetevk kerljenek teleptsre? -SelectComponentsLabel2=Jellje ki a teleptend sszetevket; trlje a telepteni nem kvnt sszetevket. Kattintson a 'Tovbb'-ra, ha kszen ll a folytatsra. -FullInstallation=Teljes telepts +WizardSelectComponents=Összetevők kiválasztása +SelectComponentsDesc=Mely összetevők kerüljenek telepítésre? +SelectComponentsLabel2=Jelölje ki a telepítendő összetevőket; törölje a telepíteni nem kívánt összetevőket. Kattintson a 'Tovább'-ra, ha készen áll a folytatásra. +FullInstallation=Teljes telepítés ; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) -CompactInstallation=Szoksos telepts -CustomInstallation=Egyni telepts -NoUninstallWarningTitle=Ltez sszetev -NoUninstallWarning=A telept gy tallta, hogy a kvetkez sszetevk mr teleptve vannak a szmtgpre:%n%n%1%n%nEzen sszetevk kijellsnek trlse, nem tvoltja el azokat a szmtgprl.%n%nMindenkppen folytatja? +CompactInstallation=Szokásos telepítés +CustomInstallation=Egyéni telepítés +NoUninstallWarningTitle=Létező összetevő +NoUninstallWarning=A telepítő úgy találta, hogy a következő összetevők már telepítve vannak a számítógépre:%n%n%1%n%nEzen összetevők kijelölésének törlése, nem távolítja el azokat a számítógépről.%n%nMindenképpen folytatja? ComponentSize1=%1 KB ComponentSize2=%1 MB -ComponentsDiskSpaceMBLabel=A jelenlegi kijells legalbb [gb] GB lemezterletet ignyel. -ComponentsDiskSpaceMBLabel=A jelenlegi kijells legalbb [mb] MB lemezterletet ignyel. +ComponentsDiskSpaceGBLabel=A jelenlegi kijelölés legalább [gb] GB lemezterületet igényel. +ComponentsDiskSpaceMBLabel=A jelenlegi kijelölés legalább [mb] MB lemezterületet igényel. ; *** "Select Additional Tasks" wizard page -WizardSelectTasks=Tovbbi feladatok -SelectTasksDesc=Mely kiegszt feladatok kerljenek vgrehajtsra? -SelectTasksLabel2=Jellje ki, mely kiegszt feladatokat hajtsa vgre a Telept a(z) [name] teleptse sorn, majd kattintson a 'Tovbb'-ra. +WizardSelectTasks=További feladatok +SelectTasksDesc=Mely kiegészítő feladatok kerüljenek végrehajtásra? +SelectTasksLabel2=Jelölje ki, mely kiegészítő feladatokat hajtsa végre a Telepítő a(z) [name] telepítése során, majd kattintson a 'Tovább'-ra. ; *** "Select Start Menu Folder" wizard page -WizardSelectProgramGroup=Start Men knyvtra -SelectStartMenuFolderDesc=Hova helyezze a Telept a program parancsikonjait? -SelectStartMenuFolderLabel3=A Telept a program parancsikonjait a Start men kvetkez mappjban fogja ltrehozni. -SelectStartMenuFolderBrowseLabel=A folytatshoz kattintson a 'Tovbb'-ra. Ha msik mappt vlasztana, kattintson a 'Tallzs'-ra. +WizardSelectProgramGroup=Start Menü könyvtára +SelectStartMenuFolderDesc=Hova helyezze a Telepítő a program parancsikonjait? +SelectStartMenuFolderLabel3=A Telepítő a program parancsikonjait a Start menü következő mappájában fogja létrehozni. +SelectStartMenuFolderBrowseLabel=A folytatáshoz kattintson a 'Tovább'-ra. Ha másik mappát választana, kattintson a 'Tallózás'-ra. MustEnterGroupName=Meg kell adnia egy mappanevet. -GroupNameTooLong=A knyvtr neve vagy az tvonal tl hossz. -InvalidGroupName=A knyvtr neve rvnytelen. -BadGroupName=A knyvtrak nevei ezen karakterek egyikt sem tartalmazhatjk:%n%n%1 -NoProgramGroupCheck2=&Ne hozzon ltre mappt a Start menben +GroupNameTooLong=A könyvtár neve vagy az útvonal túl hosszú. +InvalidGroupName=A könyvtár neve érvénytelen. +BadGroupName=A könyvtárak nevei ezen karakterek egyikét sem tartalmazhatják:%n%n%1 +NoProgramGroupCheck2=&Ne hozzon létre mappát a Start menüben ; *** "Ready to Install" wizard page -WizardReady=Kszen llunk a teleptsre -ReadyLabel1=A Telept kszen ll, a(z) [name] szmtgpre teleptshez. -ReadyLabel2a=Kattintson a 'Telepts'-re a folytatshoz, vagy a "Vissza"-ra a belltsok ttekintshez vagy megvltoztatshoz. -ReadyLabel2b=Kattintson a 'Telepts'-re a folytatshoz. -ReadyMemoUserInfo=Felhasznl adatai: -ReadyMemoDir=Telepts clknyvtra: -ReadyMemoType=Telepts tpusa: -ReadyMemoComponents=Vlasztott sszetevk: -ReadyMemoGroup=Start men mappja: -ReadyMemoTasks=Kiegszt feladatok: +WizardReady=Készen állunk a telepítésre +ReadyLabel1=A Telepítő készen áll, a(z) [name] számítógépre telepítéshez. +ReadyLabel2a=Kattintson a 'Telepítés'-re a folytatáshoz, vagy a "Vissza"-ra a beállítások áttekintéséhez vagy megváltoztatásához. +ReadyLabel2b=Kattintson a 'Telepítés'-re a folytatáshoz. +ReadyMemoUserInfo=Felhasználó adatai: +ReadyMemoDir=Telepítés célkönyvtára: +ReadyMemoType=Telepítés típusa: +ReadyMemoComponents=Választott összetevők: +ReadyMemoGroup=Start menü mappája: +ReadyMemoTasks=Kiegészítő feladatok: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=További fájlok letöltése... +ButtonStopDownload=&Letöltés megállítása +StopDownload=Biztos, hogy leakarja állítani a letöltést? +ErrorDownloadAborted=Letöltés megszakítva +ErrorDownloadFailed=A letöltés meghiúsult: %1 %2 +ErrorDownloadSizeFailed=Hiba a fájlméret lekérése során: %1 %2 +ErrorFileHash1=Fájl Hash (hasítóérték) hiba: %1 +ErrorFileHash2=Érvénytelen hash fájl, várt érték: %1, számított: %2 +ErrorProgress=Érvénytelen folyamat: %1 : %2 +ErrorFileSize=Érvénytelen fájlméret, várt méret %1, számított: %2 ; *** "Preparing to Install" wizard page -WizardPreparing=Felkszls a teleptsre -PreparingDesc=A Telept felkszl a(z) [name] szmtgpre trtn teleptshez. -PreviousInstallNotCompleted=gy korbbi program teleptse/eltvoltsa nem fejezdtt be. jra kell indtania a szmtgpt a msik telepts befejezshez.%n%nA szmtgpe jraindtsa utn ismt futtassa a Teleptt a(z) [name] teleptsnek befejezshez. -CannotContinue=A telepts nem folytathat. A kilpshez kattintson a 'Mgse'-re -ApplicationsFound=A kvetkez alkalmazsok olyan fjlokat hasznlnak, amelyeket a Teleptnek frissteni kell. Ajnlott, hogy engedlyezze a Teleptnek ezen alkalmazsok automatikus bezrst. -ApplicationsFound2=A kvetkez alkalmazsok olyan fjlokat hasznlnak, amelyeket a Teleptnek frissteni kell. Ajnlott, hogy engedlyezze a Teleptnek ezen alkalmazsok automatikus bezrst. A telepts befejezse utn a Telept megksrli az alkalmazsok jraindtst. -CloseApplications=&Alkalmazsok automatikus bezrsa -DontCloseApplications=&Ne zrja be az alkalmazsokat -ErrorCloseApplications=A Telept nem tudott minden alkalmazst automatikusan bezrni. A folytats eltt ajnlott minden, a Telept ltal frisstend fjlokat hasznl alkalmazst bezrni. -PrepareToInstallNeedsRestart=A teleptnek jra kell indtania a szmtgpet. jaindtst kveten, futassa jbl a teleptt, a [name] teleptsnek befejezshez .%n%njra szeretn indtani most a szmtgpet? +WizardPreparing=Felkészülés a telepítésre +PreparingDesc=A Telepítő felkészül a(z) [name] számítógépre történő telepítéshez. +PreviousInstallNotCompleted=gy korábbi program telepítése/eltávolítása nem fejeződött be. Újra kell indítania a számítógépét a másik telepítés befejezéséhez.%n%nA számítógépe újraindítása után ismét futtassa a Telepítőt a(z) [name] telepítésének befejezéséhez. +CannotContinue=A telepítés nem folytatható. A kilépéshez kattintson a 'Mégse'-re. +ApplicationsFound=A következő alkalmazások olyan fájlokat használnak, amelyeket a Telepítőnek frissíteni kell. Ajánlott, hogy engedélyezze a Telepítőnek ezen alkalmazások automatikus bezárását. +ApplicationsFound2=A következő alkalmazások olyan fájlokat használnak, amelyeket a Telepítőnek frissíteni kell. Ajánlott, hogy engedélyezze a Telepítőnek ezen alkalmazások automatikus bezárását. A telepítés befejezése után, a Telepítő megkísérli az alkalmazások újraindítását. +CloseApplications=&Alkalmazások automatikus bezárása +DontCloseApplications=&Ne zárja be az alkalmazásokat +ErrorCloseApplications=A Telepítő nem tudott minden alkalmazást automatikusan bezárni. A folytatás előtt ajánlott minden, a Telepítő által frissítendő fájlokat használó alkalmazást bezárni. +PrepareToInstallNeedsRestart=A telepítőnek most újra kell indítania a számítógépet. Az újraindítás után, futtassa újból ezt a telepítőt, hogy befejezze a [name] telepítését.%n%nÚjra szeretné most indítani a gépet? ; *** "Installing" wizard page -WizardInstalling=Telepts -InstallingLabel=Krem vrjon, amg a(z) [name] teleptse zajlik. +WizardInstalling=Telepítés +InstallingLabel=Kérem várjon, amíg a(z) [name] telepítése zajlik. ; *** "Setup Completed" wizard page -FinishedHeadingLabel=A(z) [name] teleptsnek befejezse -FinishedLabelNoIcons=A Telept vgzett a(z) [name] teleptsvel. -FinishedLabel=A Telept vgzett a(z) [name] teleptsvel. Az alkalmazst a ltrehozott ikonok kivlasztsval indthatja. -ClickFinish=Kattintson a 'Befejezs'-re a kilpshez. -FinishedRestartLabel=A(z) [name] teleptsnek befejezshez jra kell indtani a szmtgpet. jraindtja most? -FinishedRestartMessage=A(z) [name] teleptsnek befejezshez, a Teleptnek jra kell indtani a szmtgpet.%n%njraindtja most? -ShowReadmeCheck=Igen, szeretnm elolvasni a FONTOS fjlt -YesRadio=&Igen, jraindts most -NoRadio=&Nem, ksbb indtom jra +FinishedHeadingLabel=A(z) [name] telepítésének befejezése +FinishedLabelNoIcons=A Telepítő végzett a(z) [name] telepítésével. +FinishedLabel=A Telepítő végzett a(z) [name] telepítésével. Az alkalmazást a létrehozott ikonok kiválasztásával indíthatja. +ClickFinish=Kattintson a 'Befejezés'-re a kilépéshez. +FinishedRestartLabel=A(z) [name] telepítésének befejezéséhez újra kell indítani a számítógépet. Újraindítja most? +FinishedRestartMessage=A(z) [name] telepítésének befejezéséhez, a Telepítőnek újra kell indítani a számítógépet.%n%nÚjraindítja most? +ShowReadmeCheck=Igen, szeretném elolvasni a FONTOS fájlt +YesRadio=&Igen, újraindítás most +NoRadio=&Nem, később indítom újra ; used for example as 'Run MyProg.exe' -RunEntryExec=%1 futtatsa +RunEntryExec=%1 futtatása ; used for example as 'View Readme.txt' -RunEntryShellExec=%1 megtekintse +RunEntryShellExec=%1 megtekintése ; *** "Setup Needs the Next Disk" stuff -ChangeDiskTitle=A Teleptnek szksge van a kvetkez lemezre -SelectDiskLabel2=Helyezze be a(z) %1. lemezt s kattintson az 'OK'-ra.%n%nHa a fjlok a lemez egy a megjelentettl klnbz mappjban tallhatk, rja be a helyes tvonalat vagy kattintson a 'Tallzs'-ra. -PathLabel=&tvonal: -FileNotInDir2=A(z) "%1" fjl nem tallhat a kvetkez helyen: "%2". Helyezze be a megfelel lemezt vagy vlasszon egy msik mappt. -SelectDirectoryLabel=Adja meg a kvetkez lemez helyt. +ChangeDiskTitle=A Telepítőnek szüksége van a következő lemezre +SelectDiskLabel2=Helyezze be a(z) %1. lemezt és kattintson az 'OK'-ra.%n%nHa a fájlok a lemez egy a megjelenítettől különböző mappájában találhatók, írja be a helyes útvonalat vagy kattintson a 'Tallózás'-ra. +PathLabel=Ú&tvonal: +FileNotInDir2=A(z) "%1" fájl nem található a következő helyen: "%2". Helyezze be a megfelelő lemezt vagy válasszon egy másik mappát. +SelectDirectoryLabel=Adja meg a következő lemez helyét. ; *** Installation phase messages -SetupAborted=A telepts nem fejezdtt be.%n%nHrtsa el a hibt s futtassa jbl a Teleptt. -AbortRetryIgnoreSelectAction=Vlasszon mveletet -AbortRetryIgnoreRetry=&jra -AbortRetryIgnoreIgnore=&Hiba elvetse s folytats -AbortRetryIgnoreCancel=Telepts megszaktsa +SetupAborted=A telepítés nem fejeződött be.%n%nHárítsa el a hibát és futtassa újból a Telepítőt. +AbortRetryIgnoreSelectAction=Válasszon műveletet +AbortRetryIgnoreRetry=&Újra +AbortRetryIgnoreIgnore=&Hiba elvetése és folytatás +AbortRetryIgnoreCancel=Telepítés megszakítása ; *** Installation status messages -StatusClosingApplications=Alkalmazsok bezrsa... -StatusCreateDirs=Knyvtrak ltrehozsa... -StatusExtractFiles=Fjlok kibontsa... -StatusCreateIcons=Parancsikonok ltrehozsa... -StatusCreateIniEntries=INI bejegyzsek ltrehozsa... -StatusCreateRegistryEntries=Rendszerler bejegyzsek ltrehozsa... -StatusRegisterFiles=Fjlok regisztrlsa... -StatusSavingUninstall=Eltvolt informcik mentse... -StatusRunProgram=Telepts befejezse... -StatusRestartingApplications=Alkalmazsok jraindtsa... -StatusRollback=Vltoztatsok visszavonsa... +StatusClosingApplications=Alkalmazások bezárása... +StatusCreateDirs=Könyvtárak létrehozása... +StatusExtractFiles=Fájlok kibontása... +StatusCreateIcons=Parancsikonok létrehozása... +StatusCreateIniEntries=INI bejegyzések létrehozása... +StatusCreateRegistryEntries=Rendszerleíró bejegyzések létrehozása... +StatusRegisterFiles=Fájlok regisztrálása... +StatusSavingUninstall=Eltávolító információk mentése... +StatusRunProgram=Telepítés befejezése... +StatusRestartingApplications=Alkalmazások újraindítása... +StatusRollback=Változtatások visszavonása... ; *** Misc. errors -ErrorInternal2=Bels hiba: %1 +ErrorInternal2=Belső hiba: %1 ErrorFunctionFailedNoCode=Sikertelen %1 -ErrorFunctionFailed=Sikertelen %1; kd: %2 -ErrorFunctionFailedWithMessage=Sikertelen %1; kd: %2.%n%3 -ErrorExecutingProgram=Nem hajthat vgre a fjl:%n%1 +ErrorFunctionFailed=Sikertelen %1; kód: %2 +ErrorFunctionFailedWithMessage=Sikertelen %1; kód: %2.%n%3 +ErrorExecutingProgram=Nem hajtható végre a fájl:%n%1 ; *** Registry errors -ErrorRegOpenKey=Nem nyithat meg a rendszerler kulcs:%n%1\%2 -ErrorRegCreateKey=Nem hozhat ltre a rendszerler kulcs:%n%1\%2 -ErrorRegWriteKey=Nem mdosthat a rendszerler kulcs:%n%1\%2 +ErrorRegOpenKey=Nem nyitható meg a rendszerleíró kulcs:%n%1\%2 +ErrorRegCreateKey=Nem hozható létre a rendszerleíró kulcs:%n%1\%2 +ErrorRegWriteKey=Nem módosítható a rendszerleíró kulcs:%n%1\%2 ; *** INI errors -ErrorIniEntry=Bejegyzs ltrehozsa sikertelen a kvetkez INI fjlban: "%1". +ErrorIniEntry=Hiba lépett fel az INI bejegyzés során, ebben a fájlban: "%1". ; *** File copying errors -FileAbortRetryIgnoreSkipNotRecommended=&Fjl kihagysa (nem ajnlott) -FileAbortRetryIgnoreIgnoreNotRecommended=&Hiba elvetse s folytats (nem ajnlott) -SourceIsCorrupted=A forrsfjl megsrlt -SourceDoesntExist=A(z) "%1" forrsfjl nem ltezik -ExistingFileReadOnly2=A fjl csak olvashatknt van jellve. -ExistingFileReadOnlyRetry=Csak &olvashat tulajdonsg eltvoltsa s jra prblkozs -ExistingFileReadOnlyKeepExisting=&Ltez fjl megtartsa -ErrorReadingExistingDest=Hiba lpett fel a fjl olvassa kzben: -FileExists=A fjl mr ltezik.%n%nFell kvnja rni? -ExistingFileNewer=A ltez fjl jabb a teleptsre kerlnl. Ajnlott a ltez fjl megtartsa.%n%nMeg kvnja tartani a ltez fjlt? -ErrorChangingAttr=Hiba lpett fel a fjl attribtumnak mdostsa kzben: -ErrorCreatingTemp=Hiba lpett fel a fjl teleptsi knyvtrban trtn ltrehozsa kzben: -ErrorReadingSource=Hiba lpett fel a forrsfjl olvassa kzben: -ErrorCopying=Hiba lpett fel a fjl msolsa kzben: -ErrorReplacingExistingFile=Hiba lpett fel a ltez fjl cserje kzben: -ErrorRestartReplace=A fjl cserje az jraindts utn sikertelen volt: -ErrorRenamingTemp=Hiba lpett fel fjl teleptsi knyvtrban trtn tnevezse kzben: -ErrorRegisterServer=Nem lehet regisztrlni a DLL-t/OCX-et: %1 -ErrorRegSvr32Failed=Sikertelen RegSvr32. A visszaadott kd: %1 -ErrorRegisterTypeLib=Nem lehet regisztrlni a tpustrat: %1 +FileAbortRetryIgnoreSkipNotRecommended=&Fájl kihagyása (nem ajánlott) +FileAbortRetryIgnoreIgnoreNotRecommended=&Hiba elvetése és folytatás (nem ajánlott) +SourceIsCorrupted=A forrásfájl megsérült +SourceDoesntExist=A(z) "%1" forrásfájl nem létezik +ExistingFileReadOnly2=A fájl csak olvashatóként van jelölve, ezért nem cserélhető le. +ExistingFileReadOnlyRetry=Csak &olvasható tulajdonság eltávolítása és újra próbálkozás +ExistingFileReadOnlyKeepExisting=&Létező fájl megtartása +ErrorReadingExistingDest=Hiba lépett fel a fájl olvasása közben: +FileExistsSelectAction=Mit tegyünk? +FileExists2=A fájl már létezik. +FileExistsOverwriteExisting=A &létező fájl felülírása +FileExistsKeepExisting=A &már létező fájl megtartása +FileExistsOverwriteOrKeepAll=&Tegyük ezt, a következő fájlütközések esetén is +ExistingFileNewerSelectAction=Mit kíván tenni? +ExistingFileNewer2=A létező fájl újabb a telepítésre kerülőnél +ExistingFileNewerOverwriteExisting=A &létező fájl felülírása +ExistingFileNewerKeepExisting=&Tartsuk meg a létező fájlt (ajánlott) +ExistingFileNewerOverwriteOrKeepAll=&Tegyük ezt, a következő fájlütközések esetén is +ErrorChangingAttr=Hiba lépett fel a fájl attribútumának módosítása közben: +ErrorCreatingTemp=Hiba lépett fel a fájl telepítési könyvtárban történő létrehozása közben: +ErrorReadingSource=Hiba lépett fel a forrásfájl olvasása közben: +ErrorCopying=Hiba lépett fel a fájl másolása közben: +ErrorReplacingExistingFile=Hiba lépett fel a létező fájl cseréje közben: +ErrorRestartReplace=A fájl cseréje az újraindítás után sikertelen volt: +ErrorRenamingTemp=Hiba lépett fel fájl telepítési könyvtárban történő átnevezése közben: +ErrorRegisterServer=Nem lehet regisztrálni a DLL-t/OCX-et: %1 +ErrorRegSvr32Failed=Sikertelen RegSvr32. A visszaadott kód: %1 +ErrorRegisterTypeLib=Nem lehet regisztrálni a típustárat: %1 ; *** Uninstall display name markings ; used for example as 'My Program (32-bit)' @@ -314,53 +334,53 @@ UninstallDisplayNameMark=%1 (%2) UninstallDisplayNameMarks=%1 (%2, %3) UninstallDisplayNameMark32Bit=32-bit UninstallDisplayNameMark64Bit=64-bit -UninstallDisplayNameMarkAllUsers=Minden felhasznl -UninstallDisplayNameMarkCurrentUser=Jelenlegi felhasznl +UninstallDisplayNameMarkAllUsers=Minden felhasználó +UninstallDisplayNameMarkCurrentUser=Jelenlegi felhasználó ; *** Post-installation errors -ErrorOpeningReadme=Hiba lpett fel a FONTOS fjl megnyitsa kzben. -ErrorRestartingComputer=A Telept nem tudta jraindtani a szmtgpet. Indtsa jra kzileg. +ErrorOpeningReadme=Hiba lépett fel a FONTOS fájl megnyitása közben. +ErrorRestartingComputer=A Telepítő nem tudta újraindítani a számítógépet. Indítsa újra kézileg. ; *** Uninstaller messages -UninstallNotFound=A(z) "%1" fjl nem ltezik. Nem tvolthat el. -UninstallOpenError=A(z) "%1" fjl nem nyithat meg. Nem tvolthat el -UninstallUnsupportedVer=A(z) "%1" eltvoltsi naplfjl formtumt nem tudja felismerni az eltvolt jelen verzija. Az eltvolts nem folytathat -UninstallUnknownEntry=Egy ismeretlen bejegyzs (%1) tallhat az eltvoltsi naplfjlban -ConfirmUninstall=Biztosan el kvnja tvoltani a(z) %1 programot s minden sszetevjt? -UninstallOnlyOnWin64=Ezt a teleptst csak 64-bites Windowson lehet eltvoltani. -OnlyAdminCanUninstall=Ezt a teleptst csak adminisztrcis jogokkal rendelkez felhasznl tvolthatja el. -UninstallStatusLabel=Legyen trelemmel, amg a(z) %1 szmtgprl trtn eltvoltsa befejezdik. -UninstalledAll=A(z) %1 sikeresen el lett tvoltva a szmtgprl. -UninstalledMost=A(z) %1 eltvoltsa befejezdtt.%n%nNhny elemet nem lehetetett eltvoltani. Trlje kzileg. -UninstalledAndNeedsRestart=A(z) %1 eltvoltsnak befejezshez jra kell indtania a szmtgpt.%n%njraindtja most? -UninstallDataCorrupted=A(z) "%1" fjl srlt. Nem tvolthat el. +UninstallNotFound=A(z) "%1" fájl nem létezik. Nem távolítható el. +UninstallOpenError=A(z) "%1" fájl nem nyitható meg. Nem távolítható el +UninstallUnsupportedVer=A(z) "%1" eltávolítási naplófájl formátumát nem tudja felismerni az eltávolító jelen verziója. Az eltávolítás nem folytatható +UninstallUnknownEntry=Egy ismeretlen bejegyzés (%1) található az eltávolítási naplófájlban +ConfirmUninstall=Biztosan el kívánja távolítani a(z) %1 programot és minden összetevőjét? +UninstallOnlyOnWin64=Ezt a telepítést csak 64-bites Windows operációs rendszerről lehet eltávolítani. +OnlyAdminCanUninstall=Ezt a telepítést csak adminisztrációs jogokkal rendelkező felhasználó távolíthatja el. +UninstallStatusLabel=Legyen türelemmel, amíg a(z) %1 számítógépéről történő eltávolítása befejeződik. +UninstalledAll=A(z) %1 sikeresen el lett távolítva a számítógépről. +UninstalledMost=A(z) %1 eltávolítása befejeződött.%n%nNéhány elemet nem lehetettet eltávolítani. Törölje kézileg. +UninstalledAndNeedsRestart=A(z) %1 eltávolításának befejezéséhez újra kell indítania a számítógépét.%n%nÚjraindítja most? +UninstallDataCorrupted=A(z) "%1" fájl sérült. Nem távolítható el. ; *** Uninstallation phase messages -ConfirmDeleteSharedFileTitle=Trli a megosztott fjlt? -ConfirmDeleteSharedFile2=A rendszer azt jelzi, hogy a kvetkez megosztott fjlra mr nincs szksge egyetlen programnak sem. Eltvoltja a megosztott fjlt?%n%nHa ms programok mg mindig hasznljk a megosztott fjlt, akkor az eltvoltsa utn lehet, hogy nem fognak megfelelen mkdni. Ha bizonytalan, vlassza a Nemet. A fjl megtartsa nem okoz problmt a rendszerben. -SharedFileNameLabel=Fjlnv: +ConfirmDeleteSharedFileTitle=Törli a megosztott fájlt? +ConfirmDeleteSharedFile2=A rendszer azt jelzi, hogy a következő megosztott fájlra már nincs szüksége egyetlen programnak sem. Eltávolítja a megosztott fájlt?%n%nHa más programok még mindig használják a megosztott fájlt, akkor az eltávolítása után lehet, hogy nem fognak megfelelően működni. Ha bizonytalan, válassza a Nemet. A fájl megtartása nem okoz problémát a rendszerben. +SharedFileNameLabel=Fájlnév: SharedFileLocationLabel=Helye: -WizardUninstalling=Eltvolts llapota -StatusUninstalling=%1 eltvoltsa... +WizardUninstalling=Eltávolítás állapota +StatusUninstalling=%1 eltávolítása... ; *** Shutdown block reasons -ShutdownBlockReasonInstallingApp=%1 teleptse. -ShutdownBlockReasonUninstallingApp=%1 eltvoltsa. +ShutdownBlockReasonInstallingApp=%1 telepítése. +ShutdownBlockReasonUninstallingApp=%1 eltávolítása. ; The custom messages below aren't used by Setup itself, but if you make ; use of them in your scripts, you'll want to translate them. [CustomMessages] -NameAndVersion=%1, verzi: %2 -AdditionalIcons=Tovbbi parancsikonok: -CreateDesktopIcon=&Asztali ikon ltrehozsa -CreateQuickLaunchIcon=&Gyorsindts parancsikon ltrehozsa +NameAndVersion=%1, verzió: %2 +AdditionalIcons=További parancsikonok: +CreateDesktopIcon=&Asztali ikon létrehozása +CreateQuickLaunchIcon=&Gyorsindító parancsikon létrehozása ProgramOnTheWeb=%1 az interneten -UninstallProgram=Eltvolts - %1 -LaunchProgram=Indts %1 -AssocFileExtension=A(z) %1 &trstsa a(z) %2 fjlkiterjesztssel -AssocingFileExtension=A(z) %1 trstsa a(z) %2 fjlkiterjesztssel... -AutoStartProgramGroupDescription=Indtpult: -AutoStartProgram=%1 automatikus indtsa -AddonHostProgramNotFound=A(z) %1 nem tallhat a kivlasztott knyvtrban.%n%nMindenkppen folytatja? +UninstallProgram=Eltávolítás - %1 +LaunchProgram=Indítás %1 +AssocFileExtension=A(z) %1 &társítása a(z) %2 fájlkiterjesztéssel +AssocingFileExtension=A(z) %1 társítása a(z) %2 fájlkiterjesztéssel... +AutoStartProgramGroupDescription=Indítópult: +AutoStartProgram=%1 automatikus indítása +AddonHostProgramNotFound=A(z) %1 nem található a kiválasztott könyvtárban.%n%nMindenképpen folytatja? diff --git a/installer/innosetup/Languages/Icelandic.isl b/installer/innosetup/Languages/Icelandic.isl new file mode 100644 index 000000000..395a75761 --- /dev/null +++ b/installer/innosetup/Languages/Icelandic.isl @@ -0,0 +1,361 @@ +; *** Inno Setup version 6.1.0+ Icelandic messages *** +; +; Translator: Stefán Örvar Sigmundsson, eMedia Intellect +; Contact: emi@emi.is +; Date: 2020-07-25 + +[LangOptions] + +LanguageName=<00CD>slenska +LanguageID=$040F +LanguageCodePage=1252 + +[Messages] + +; *** Application titles +SetupAppTitle=Uppsetning +SetupWindowTitle=Uppsetning - %1 +UninstallAppTitle=Niðurtaka +UninstallAppFullTitle=%1-niðurtaka + +; *** Misc. common +InformationTitle=Upplýsingar +ConfirmTitle=Staðfesta +ErrorTitle=Villa + +; *** SetupLdr messages +SetupLdrStartupMessage=Þetta mun uppsetja %1. Vilt þú halda áfram? +LdrCannotCreateTemp=Ófært um að skapa tímabundna skrá. Uppsetningu hætt +LdrCannotExecTemp=Ófært um að keyra skrá í tímabundna skráasafninu. Uppsetningu hætt +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nVilla %2: %3 +SetupFileMissing=Skrána %1 vantar úr uppsetningarskráasafninu. Vinsamlega leiðréttu vandamálið eða fáðu nýtt afrita af forritinu. +SetupFileCorrupt=Uppsetningarskrárnar eru spilltar. Vinsamlega fáðu nýtt afrita af forritinu. +SetupFileCorruptOrWrongVer=Uppsetningarskrárnar eru spilltar eða eru ósamrýmanlegar við þessa útgáfu af Uppsetningu. Vinsamlega leiðréttu vandamálið eða fáðu nýtt afrit af forritinu. +InvalidParameter=Ógild færibreyta var afhend á skipanalínunni:%n%n%1 +SetupAlreadyRunning=Uppsetning er nú þegar keyrandi. +WindowsVersionNotSupported=Þetta forrit styður ekki útgáfuna af Windows sem tölvan þín er keyrandi. +WindowsServicePackRequired=Þetta forrit krefst Þjónustupakka %2 eða síðari. +NotOnThisPlatform=Þetta forrit mun ekki keyra á %1. +OnlyOnThisPlatform=Þetta forrit verður að keyra á %1. +OnlyOnTheseArchitectures=Þetta forrit er einungis hægt að uppsetja á útgáfur af Windows hannaðar fyrir eftirfarandi gjörvahannanir:%n%n%1 +WinVersionTooLowError=Þetta forrit krefst %1-útgáfu %2 eða síðari. +WinVersionTooHighError=Þetta forrit er ekki hægt að uppsetja á %1-útgáfu %2 eða síðari. +AdminPrivilegesRequired=Þú verður að vera innskráð(ur) sem stjórnandi meðan þú uppsetur þetta forrit. +PowerUserPrivilegesRequired=Þú verður að vera innskráð(ur) sem stjórnandi eða sem meðlimur Power Users-hópsins meðan þú uppsetur þetta forrit. +SetupAppRunningError=Uppsetning hefur greint að %1 er eins og er keyrandi.%n%nVinsamlega lokaðu öllum tilvikum þess núna, smelltu síðan á Í lagi til að halda áfram eða Hætta við til að hætta. +UninstallAppRunningError=Niðurtaka hefur greint að %1 er eins og er keyrandi.%n%nVinsamlega lokaðu öllum tilvikum þess núna, smelltu síðan á Í lagi til að halda áfram eða Hætta við til að hætta. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Veldu uppsetningarham +PrivilegesRequiredOverrideInstruction=Veldu uppsetningarham +PrivilegesRequiredOverrideText1=%1 er hægt að setja upp fyrir alla notendur (krefst stjórnandaréttinda) eða fyrir þig einungis. +PrivilegesRequiredOverrideText2=%1 er hægt að setja upp fyrir þig einungis eða fyrir alla notendur (krefst stjórnandaréttinda). +PrivilegesRequiredOverrideAllUsers=Uppsetja fyrir &alla notendur +PrivilegesRequiredOverrideAllUsersRecommended=Uppsetja fyrir &alla notendur (ráðlagt) +PrivilegesRequiredOverrideCurrentUser=Uppsetja fyrir &mig einungis +PrivilegesRequiredOverrideCurrentUserRecommended=Uppsetja fyrir &mig einungis (ráðlagt) + +; *** Misc. errors +ErrorCreatingDir=Uppsetningunni var ófært um að skapa skráasafnið „%1“ +ErrorTooManyFilesInDir=Ófært um að skapa skrá í skráasafninu „%1“ vegna þess það inniheldur of margar skrár + +; *** Setup common messages +ExitSetupTitle=Hætta í Uppsetningu +ExitSetupMessage=Uppsetningu er ekki lokið. Ef þú hættir núna mun forritið ekki vera uppsett.%n%nÞú getur keyrt Uppsetningu aftur síðar til að ljúka uppsetningunni.%n%nHætta í Uppsetningu? +AboutSetupMenuItem=&Um Uppsetningu… +AboutSetupTitle=Um Uppsetningu +AboutSetupMessage=%1 útgáfa %2%n%3%n%n%1 heimasíðu:%n%4 +AboutSetupNote= +TranslatorNote=Stefán Örvar Sigmundsson, eMedia Intellect + +; *** Buttons +ButtonBack=< &Fyrri +ButtonNext=&Næst > +ButtonInstall=&Uppsetja +ButtonOK=Í lagi +ButtonCancel=Hætta við +ButtonYes=&Já +ButtonYesToAll=Já við &öllu +ButtonNo=&Nei +ButtonNoToAll=&Nei við öllu +ButtonFinish=&Ljúka +ButtonBrowse=&Vafra… +ButtonWizardBrowse=&Vafra… +ButtonNewFolder=&Skapa nýja möppu + +; *** "Select Language" dialog messages +SelectLanguageTitle=Veldu tungumál Uppsetningar +SelectLanguageLabel=Veldu tungumálið sem nota á við uppsetninguna. + +; *** Common wizard text +ClickNext=Smelltu á Næst til að halda áfram eða Hætta við til að hætta Uppsetningu. +BeveledLabel= +BrowseDialogTitle=Vafra eftir möppu +BrowseDialogLabel=Veldu möppu í listanum fyrir neðan, smelltu síðan á Í lagi. +NewFolderName=Ný mappa + +; *** "Welcome" wizard page +WelcomeLabel1=Velkomin(n) í [name]-uppsetningaraðstoðarann +WelcomeLabel2=Þetta mun uppsetja [name/ver] á þína tölvu.%n%nÞað er ráðlagt að þú lokir öllum öðrum hugbúnaði áður en haldið er áfram. + +; *** "Password" wizard page +WizardPassword=Aðgangsorð +PasswordLabel1=Þessi uppsetning er aðgangsorðsvarin. +PasswordLabel3=Vinsamlega veitu aðgangsorðið, smelltu síðan á Næst til að halda áfram. Aðgangsorð eru hástafanæm. +PasswordEditLabel=&Aðgangsorð: +IncorrectPassword=Aðgangsorðið sem þú innslóst er ekki rétt. Vinsamlega reyndu aftur. + +; *** "License Agreement" wizard page +WizardLicense=Leyfissamningur +LicenseLabel=Vinsamlega lestu hinar eftirfarandi mikilvægu upplýsingar áður en haldið er áfram. +LicenseLabel3=Vinsamlega lestu eftirfarandi leyfissamning. Þú verður að samþykkja skilmála samningsins áður en haldið er áfram með uppsetninguna. +LicenseAccepted=Ég &samþykki samninginn +LicenseNotAccepted=Ég samþykki &ekki samninginn + +; *** "Information" wizard pages +WizardInfoBefore=Upplýsingar +InfoBeforeLabel=Vinsamlega lestu hinar eftirfarandi mikilvægu upplýsingar áður en haldið er áfram. +InfoBeforeClickLabel=Þegar þú ert tilbúin(n) til að halda áfram með Uppsetninguna, smelltu á Næst. +WizardInfoAfter=Upplýsingar +InfoAfterLabel=Vinsamlega lestu hinar eftirfarandi mikilvægu upplýsingar áður en haldið er áfram. +InfoAfterClickLabel=Þegar þú ert tilbúin(n) til að halda áfram með Uppsetninguna, smelltu á Næst. + +; *** "User Information" wizard page +WizardUserInfo=Notandaupplýsingar +UserInfoDesc=Vinsamlega innsláðu upplýsingarnar þínar. +UserInfoName=&Notandanafn: +UserInfoOrg=&Stofnun: +UserInfoSerial=&Raðnúmer: +UserInfoNameRequired=Þú verður að innslá nafn. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Velja staðsetningu +SelectDirDesc=Hvar ætti [name] að vera uppsettur? +SelectDirLabel3=Uppsetning mun uppsetja [name] í hina eftirfarandi möppu. +SelectDirBrowseLabel=Til að halda áfram, smelltu á Næst. Ef þú vilt velja aðra möppu, smelltu á Vafra. +DiskSpaceGBLabel=Að minnsta kosti [gb] GB af lausu diskplássi er krafist. +DiskSpaceMBLabel=Að minnsta kosti [mb] MB af lausu diskplássi er krafist. +CannotInstallToNetworkDrive=Uppsetning getur ekki uppsett á netdrif. +CannotInstallToUNCPath=Uppsetning getur ekki uppsett á UNC-slóð. +InvalidPath=Þú verður að innslá fulla slóð með drifstaf; til dæmis:%n%nC:\APP%n%neða UNC-slóð samkvæmt sniðinu:%n%n\\server\share +InvalidDrive=Drifið eða UNC-deilingin sem þú valdir er ekki til eða er ekki aðgengileg. Vinsamlega veldu annað. +DiskSpaceWarningTitle=Ekki nóg diskpláss +DiskSpaceWarning=Uppsetning krefst að minnsta kosti %1 KB af lausu plássi til að uppsetja, en hið valda drif hefur einungis %2 KB tiltæk.%n%nVilt þú halda áfram hvort sem er? +DirNameTooLong=Möppunafnið eða slóðin er of löng. +InvalidDirName=Möppunafnið er ekki gilt. +BadDirName32=Möppunöfn geta ekki innihaldið nein af hinum eftirfarandi rittáknum:%n%n%1 +DirExistsTitle=Mappa er til +DirExists=Mappan:%n%n%1%n%ner nú þegar til. Vilt þú uppsetja í þá möppu hvort sem er? +DirDoesntExistTitle=Mappa er ekki til +DirDoesntExist=Mappan:%n%n%1%n%ner ekki til. Vilt þú að mappan sé sköpuð? + +; *** "Select Components" wizard page +WizardSelectComponents=Velja atriði +SelectComponentsDesc=Hvaða atriði ætti að uppsetja? +SelectComponentsLabel2=Veldu atriðin sem þú vilt uppsetja; hreinsaðu atriðin sem þú vilt ekki uppsetja. Smelltu á Næst þegar þú ert tilbúin(n) til að halda áfram. +FullInstallation=Full uppsetning +CompactInstallation=Samanþjöppuð uppsetning +CustomInstallation=Sérsnídd uppsetning +NoUninstallWarningTitle=Atriði eru til +NoUninstallWarning=Uppsetning hefur greint það að eftirfarandi atriði eru nú þegar uppsett á tölvunni þinni:%n%n%1%n%nAð afvelja þessi atriði mun ekki niðurtaka þau.%n%nVilt þú halda áfram hvort sem er? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Núverandi val krefst að minnsta kosti [gb] GB af diskplássi. +ComponentsDiskSpaceMBLabel=Núverandi val krefst að minnsta kosti [mb] MB af diskplássi. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Veldu aukaleg verk +SelectTasksDesc=Hvaða aukalegu verk ættu að vera framkvæmd? +SelectTasksLabel2=Veldu hin aukalegu verk sem þú vilt að Uppsetning framkvæmi meðan [name] er uppsettur, ýttu síðan á Næst. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Veldu Upphafsvalmyndarmöppu +SelectStartMenuFolderDesc=Hvert ætti Uppsetning að setja skyndivísa forritsins? +SelectStartMenuFolderLabel3=Uppsetning mun skapa skyndivísa forritsins í hina eftirfarandi Upphafsvalmyndarmöppu. +SelectStartMenuFolderBrowseLabel=Til að halda áfram, smelltu á Næst. Ef þú vilt velja aðra möppu, smelltu á Vafra. +MustEnterGroupName=Þú verður að innslá möppunafn. +GroupNameTooLong=Möppunafnið eða slóðin er of löng. +InvalidGroupName=Möppunafnið er ekki gilt. +BadGroupName=Möppunafnið getur ekki innihaldið neitt af hinum eftirfarandi rittáknum:%n%n%1 +NoProgramGroupCheck2=&Ekki skapa Upphafsvalmyndarmöppu + +; *** "Ready to Install" wizard page +WizardReady=Tilbúin til að uppsetja +ReadyLabel1=Uppsetning er núna tilbúin til að hefja uppsetningu [name] á tölvuna þína. +ReadyLabel2a=Smelltu á Uppsetja til að halda áfram uppsetningunni eða smelltu á Til baka ef þú vilt endurskoða eða breyta einhverjum stillingum. +ReadyLabel2b=Smelltu á Uppsetja til að halda áfram uppsetningunni. +ReadyMemoUserInfo=Notandaupplýsingar: +ReadyMemoDir=Staðsetning: +ReadyMemoType=Uppsetningartegund: +ReadyMemoComponents=Valin atriði: +ReadyMemoGroup=Upphafsvalmyndarmappa: +ReadyMemoTasks=Aukaleg verk: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Niðurhlaðandi aukalegum skrám… +ButtonStopDownload=&Stöðva niðurhleðslu +StopDownload=Ert þú viss um að þú viljir stöðva niðurhleðsluna? +ErrorDownloadAborted=Niðurhleðslu hætt +ErrorDownloadFailed=Niðurhleðsla mistókst: %1 %2 +ErrorDownloadSizeFailed=Mistókst að sækja stærð: %1 %2 +ErrorFileHash1=Skráarhakk mistókst: %1 +ErrorFileHash2=Ógilt skráarhakk: bjóst við %1, fékk %2 +ErrorProgress=Ógild framvinda: %1 of %2 +ErrorFileSize=Ógild skráarstærð: bjóst við %1, fékk %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Undirbúandi uppsetningu +PreparingDesc=Uppsetning er undirbúandi uppsetningu [name] á tölvuna þína. +PreviousInstallNotCompleted=Uppsetningu/Fjarlægingu eftirfarandi forrits var ekki lokið. Þú þarft að endurræsa tölvuna þína til að ljúka þeirri uppsetningu.%n%nEftir endurræsingu tölvunnar þinnar, keyrðu Uppsetningu aftur til að ljúka uppsetningu [name]. +CannotContinue=Uppsetning getur ekki haldið áfram. Vinsamlega smelltu á Hætta við til að hætta. +ApplicationsFound=Eftirfarandi hugbúnaður er notandi skrár sem þurfa að vera uppfærðar af Uppsetningu. Það er ráðlagt að þú leyfir Uppsetningu sjálfvirkt að loka þessum hugbúnaði. +ApplicationsFound2=Eftirfarandi hugbúnaður er notandi skrár sem þurfa að vera uppfærðar af Uppsetningu. Það er ráðlagt að þú leyfir Uppsetningu sjálfvirkt að loka þessum hugbúnaði. Eftir að uppsetningunni lýkur mun Uppsetning reyna að endurræsa hugbúnaðinn. +CloseApplications=&Sjálfvirkt loka hugbúnaðinum +DontCloseApplications=&Ekki loka hugbúnaðinum +ErrorCloseApplications=Uppsetningu var ófært um að sjálfvirkt loka öllum hugbúnaði. Það er ráðlagt að þú lokir öllum hugbúnaði notandi skrár sem þurfa að vera uppfærðar af Uppsetningu áður en haldið er áfram. +PrepareToInstallNeedsRestart=Þú verður að endurræsa tölvuna þína. Eftir að hafa endurræst tölvuna þína, keyrðu Uppsetningu aftur til að ljúka uppsetningu [name].%n%nVilt þú endurræsa núna? + +; *** "Installing" wizard page +WizardInstalling=Uppsetjandi +InstallingLabel=Vinsamlega bíddu meðan Uppsetning uppsetur [name] á tölvuna þína. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Ljúkandi [name]-uppsetningaraðstoðaranum +FinishedLabelNoIcons=Uppsetning hefur lokið uppsetningu [name] á tölvuna þína. +FinishedLabel=Uppsetning hefur lokið uppsetningu [name] á þinni tölvu. Hugbúnaðurinn getur verið ræstur með því að velja hina uppsettu skyndivísa. +ClickFinish=Smelltu á Ljúka til að hætta í Uppsetningu. +FinishedRestartLabel=Til að ljúka uppsetningu [name] þarft Uppsetning að endurræsa tölvuna þína. Vilt þú endurræsa núna? +FinishedRestartMessage=Til að ljúka uppsetningu [name] þarf Uppsetning að endurræsa tölvuna þína.%n%nVilt þú endurræsa núna? +ShowReadmeCheck=Já, ég vil skoða README-skrána +YesRadio=&Já, endurræsa tölvuna núna +NoRadio=&Nei, ég mun endurræsa tölvuna síðar +RunEntryExec=Keyra %1 +RunEntryShellExec=Skoða %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Uppsetning þarfnast næsta disks +SelectDiskLabel2=Vinsamlega settu inn disk %1 og smelltu á Í lagi.%n%nEf skrárnar á þessum disk er hægt að finna í annarri möppu en þeirri sem birt er fyrir neðan, innsláðu réttu slóðina og smelltu á Vafra. +PathLabel=&Slóð: +FileNotInDir2=Skrána „%1“ var ekki hægt að staðsetja í „%2“. Vinsamlega settu inn rétta diskinn eða veldu aðra möppu. +SelectDirectoryLabel=Vinsamlega tilgreindu staðsetningu næsta disks. + +; *** Installation phase messages +SetupAborted=Uppsetningu var ekki lokið.%n%nVinsamlega leiðréttu vandamálið og keyrðu Uppsetningu aftur. +AbortRetryIgnoreSelectAction=Velja aðgerð +AbortRetryIgnoreRetry=&Reyna aftur +AbortRetryIgnoreIgnore=&Hunsa villuna og halda áfram +AbortRetryIgnoreCancel=Hætta við uppsetningu + +; *** Installation status messages +StatusClosingApplications=Lokandi hugbúnaði… +StatusCreateDirs=Skapandi skráasöfn… +StatusExtractFiles=Útdragandi skrár… +StatusCreateIcons=Skapandi skyndivísa… +StatusCreateIniEntries=Skapandi INI-færslur… +StatusCreateRegistryEntries=Skapandi Windows Registry-færslur… +StatusRegisterFiles=Skrásetjandi skrár… +StatusSavingUninstall=Vistandi niðurtekningarupplýsingar… +StatusRunProgram=Ljúkandi uppsetningu… +StatusRestartingApplications=Endurræsandi hugbúnað… +StatusRollback=Rúllandi aftur breytingum… + +; *** Misc. errors +ErrorInternal2=Innri villa: %1 +ErrorFunctionFailedNoCode=%1 mistókst +ErrorFunctionFailed=%1 mistókst; kóði %2 +ErrorFunctionFailedWithMessage=%1 mistókst; kóði %2.%n%3 +ErrorExecutingProgram=Ófært um að keyra skrá:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Villa við opnun Windows Registry-lykils:%n%1\%2 +ErrorRegCreateKey=Villa við sköpun Windows Registry-lykils:%n%1\%2 +ErrorRegWriteKey=Villa við ritun í Windows Registry-lykil:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Villa við sköpun INI-færslu í skrána „%1“. + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Sleppa þessari skrá (ekki ráðlagt) +FileAbortRetryIgnoreIgnoreNotRecommended=&Hunsa villuna og halda áfram (ekki ráðlagt) +SourceIsCorrupted=Upprunaskráin er spillt +SourceDoesntExist=Upprunaskráin „%1“ er ekki til +ExistingFileReadOnly2=Hina gildandi skrá var ekki hægt að yfirrita því hún er merkt sem lesa-einungis. +ExistingFileReadOnlyRetry=&Fjarlægja lesa-einungis eigindi og reyna aftur +ExistingFileReadOnlyKeepExisting=&Halda gildandi skrá +ErrorReadingExistingDest=Villa kom upp meðan reynt var að lesa gildandi skrána: +FileExistsSelectAction=Velja aðgerð +FileExists2=Skráin er nú þegar til. +FileExistsOverwriteExisting=&Yfirrita hina gildandi skrá +FileExistsKeepExisting=&Halda hinni gildandi skrá +FileExistsOverwriteOrKeepAll=&Gera þetta við næstu ósamstæður +ExistingFileNewerSelectAction=Velja aðgerð +ExistingFileNewer2=Hin gildandi skrá er nýrri en sú sem Uppsetning er að reyna að uppsetja. +ExistingFileNewerOverwriteExisting=&Yfirrita hina gildandi skrá +ExistingFileNewerKeepExisting=&Halda hinni gildandi skrá (ráðlagt) +ExistingFileNewerOverwriteOrKeepAll=&Gera þetta við næstu ósamstæður +ErrorChangingAttr=Villa kom upp meðan reynt var að breyta eigindum gildandi skráarinnar: +ErrorCreatingTemp=Villa kom upp meðan reynt var að skapa skrá í staðsetningarskráasafninu: +ErrorReadingSource=Villa kom upp meðan reynt var að lesa upprunaskrána: +ErrorCopying=Villa kom upp meðan reynt var að afrita skrána: +ErrorReplacingExistingFile=Villa kom upp meðan reynt var að yfirrita gildandi skrána: +ErrorRestartReplace=RestartReplace mistókst: +ErrorRenamingTemp=Villa kom upp meðan reynt var að endurnefna skrá í staðsetningarskráasafninu: +ErrorRegisterServer=Ófært um að skrá DLL/OCX: %1 +ErrorRegSvr32Failed=RegSvr32 mistókst með skilakóðann %1 +ErrorRegisterTypeLib=Ófært um að skrá tegundasafnið: $1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bita +UninstallDisplayNameMark64Bit=64-bita +UninstallDisplayNameMarkAllUsers=Allir notendur +UninstallDisplayNameMarkCurrentUser=Núverandi notandi + +; *** Post-installation errors +ErrorOpeningReadme=Villa kom upp meðan reynt var að opna README-skrána. +ErrorRestartingComputer=Uppsetningu tókst ekki að endurræsa tölvuna. Vinsamlega gerðu þetta handvirkt. + +; *** Uninstaller messages +UninstallNotFound=Skráin „%1“ er ekki til. Getur ekki niðurtekið. +UninstallOpenError=Skrána „%1“ var ekki hægt að opna. Getur ekki niðurtekið +UninstallUnsupportedVer=Niðurtökuatburðaskráin „%1“ er á sniði sem er ekki þekkt af þessari útgáfu af niðurtakaranum. Getur ekki niðurtekið +UninstallUnknownEntry=Óþekkt færsla (%1) var fundin í niðurtökuatburðaskránni +ConfirmUninstall=Ert þú viss um að þú viljir algjörlega fjarlægja %1 og öll atriði þess? +UninstallOnlyOnWin64=Þessa uppsetningu er einungis hægt að niðurtaka á 64-bita Windows. +OnlyAdminCanUninstall=Þessi uppsetning getur einungis verið niðurtekin af notanda með stjórnandaréttindi. +UninstallStatusLabel=Vinsamlega bíddu meðan %1 er fjarlægt úr tölvunni þinni. +UninstalledAll=%1 var færsællega fjarlægt af tölvunni þinni. +UninstalledMost=%1-niðurtöku lokið.%n%nSuma liði var ekki hægt að fjarlægja. Þá er hægt að fjarlægja handvirkt. +UninstalledAndNeedsRestart=Til að ljúka niðurtöku %1 þarf að endurræsa tölvuna þína.%n%nVilt þú endurræsa núna? +UninstallDataCorrupted=„%1“-skráin er spillt. Getur ekki niðurtekið + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Fjarlægja deilda skrá? +ConfirmDeleteSharedFile2=Kerfið gefur til kynna að hin eftirfarandi deilda skrá er ekki lengur í notkun hjá neinu forriti. Vilt þú að Niðurtakari fjarlægi þessa deildu skrá?%n%nEf einhver forrit eru enn notandi þessa skrá og hún er fjarlægð, kann að vera að þau forrit munu ekki virka almennilega. Ef þú ert óviss, veldu Nei. Að skilja skrána eftir á kerfinu þínu mun ekki valda skaða. +SharedFileNameLabel=Skráarnafn: +SharedFileLocationLabel=Staðsetning: +WizardUninstalling=Niðurtökustaða +StatusUninstalling=Niðurtakandi %1… + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Uppsetjandi %1. +ShutdownBlockReasonUninstallingApp=Niðurtakandi %1. + +[CustomMessages] + +NameAndVersion=%1 útgáfa %2 +AdditionalIcons=Aukalegir skyndivísir: +CreateDesktopIcon=Skapa &skjáborðsskyndivísi +CreateQuickLaunchIcon=Skapa &Skyndiræsitáknmynd +ProgramOnTheWeb=%1 á Vefnum +UninstallProgram=Niðurtaka %1 +LaunchProgram=Ræsa %1 +AssocFileExtension=&Tengja %1 við %2-skráarframlenginguna +AssocingFileExtension=&Tengjandi %1 við %2-skráarframlenginguna… +AutoStartProgramGroupDescription=Ræsing: +AutoStartProgram=Sjálfvikt ræsa %1 +AddonHostProgramNotFound=%1 gat ekki staðsett möppuna sem þú valdir.%n%nVilt þú halda áfram hvort sem er? \ No newline at end of file diff --git a/installer/innosetup/Languages/Indonesian.isl b/installer/innosetup/Languages/Indonesian.isl index b86e81e26..2dfc1c38c 100644 --- a/installer/innosetup/Languages/Indonesian.isl +++ b/installer/innosetup/Languages/Indonesian.isl @@ -1,364 +1,343 @@ -; *** Inno Setup version 6.0.3+ Indonesian messages *** +; *** Inno Setup version 6.1.0+ Indonesian messages *** ; -; Untuk mengunduh berkas terjemahan hasil konstribusi pengguna, kunjungi: +; Untuk mengunduh terjemahan kontribusi-pengguna dari berkas ini, buka: ; http://www.jrsoftware.org/files/istrans/ -; +; ; Alih bahasa oleh: MozaikTM (mozaik.tm@gmail.com) -; -; Catatan: Saat menerjemahkan pesan ini, jangan masukkan titik (.) pada -; akhir pesan tanpa titik, karena Inno Setup menambahkan titik pada pesan tersebut -; secara otomatis (menambahkan sebuah titik akan memunculkan dua titik). [LangOptions] -; Tiga baris berikut sangat penting. Pastikan untuk membaca dan -; memahami topik 'bagian [LangOption]' dalam berkas bantuan. LanguageName=Bahasa Indonesia LanguageID=$0421 LanguageCodePage=0 -; Bila target bahasa Anda memerlukan fon atau ukuran khusus, -; hapus tanda komentar (;) dari salah satu atau beberapa baris berikut dan ubah seperlunya. -;DialogFontName= -;DialogFontSize=8 -;WelcomeFontName=Verdana -;WelcomeFontSize=12 -;TitleFontName=Arial -;TitleFontSize=29 -;CopyrightFontName=Arial -;CopyrightFontSize=8 [Messages] - -; *** Judul aplikasi -SetupAppTitle=Pemasang -SetupWindowTitle=Pemasangan %1 +SetupAppTitle=Instalasi +SetupWindowTitle=Instalasi - %1 UninstallAppTitle=Pelepas UninstallAppFullTitle=Pelepasan %1 -; *** Misc. common InformationTitle=Informasi ConfirmTitle=Konfirmasi -ErrorTitle=Ada Masalah +ErrorTitle=Galat -; *** Pesan untuk SetupLdr -SetupLdrStartupMessage=Kami akan memasang %1. Lanjutkan? -LdrCannotCreateTemp=Tidak dapat membuat berkas sementara. Pemasangan dibatalkan -LdrCannotExecTemp=Tidak dapat mengeksekusi berkas di dalam direktori sementara. Pemasangan dibatalkan -HelpTextNote= +SetupLdrStartupMessage=Kami akan memasang %1. Teruskan? +LdrCannotCreateTemp=Tidak dapat membuat berkas sementara. Batal memasang +LdrCannotExecTemp=Tidak dapat menjalankan berkas di direktori sementara. Batal memasang -; *** Pesan kesalahan saat memuat Pemasang -LastErrorMessage=%1.%n%nKesalahan %2: %3 -SetupFileMissing=Berkas %1 hilang dari lokasi pemasangan. Silakan selesaikan masalah atau dapatkan salinan baru dari pemasang ini. -SetupFileCorrupt=Berkas Pemasang telah rusak. Silakan dapatkan salinan baru dari pemasang ini. -SetupFileCorruptOrWrongVer=Berkas-berkas pemasang telah rusak, atau tidak cocok dengan versi pemasang ini. Silakan selesaikan masalah atau dapatkan salinan baru dari berkas ini. -InvalidParameter=Ada parameter tidak sah pada baris perintah:%n%n%1 -SetupAlreadyRunning=Pemasang sudah berjalan. -WindowsVersionNotSupported=Program ini tidak mendukung Windows yang terpasang pada komputer ini. +LastErrorMessage=%1.%n%nGalat %2: %3 +SetupFileMissing=Berkas %1 hilang dari direktori instalasi. Silakan koreksi masalah atau dapatkan salinan program yang baru. +SetupFileCorrupt=Berkas pemandu telah rusak. Silakan dapatkan salinan program yang baru. +SetupFileCorruptOrWrongVer=Berkas pemandu telah rusak, atau tidak cocok dengan versi pemandu ini. Silakan koreksi masalah atau dapatkan salinan program yang baru. +InvalidParameter=Parameter tak sah terdapat pada baris perintah: %n%n%1 +SetupAlreadyRunning=Pemandu sudah berjalan. +WindowsVersionNotSupported=Program ini tidak mendukung versi Windows yang berjalan pada komputer Anda. WindowsServicePackRequired=Program ini memerlukan %1 Service Pack %2 atau yang terbaru. NotOnThisPlatform=Program ini tidak akan berjalan pada %1. OnlyOnThisPlatform=Program ini harus dijalankan pada %1. -OnlyOnTheseArchitectures=Program ini hanya dapat dipasang pada versi Windows yang didesain untuk arsitektur prosesor berikut:%n%n%1 +OnlyOnTheseArchitectures=Program ini hanya bisa dipasang pada versi Windows yang didesain untuk arsitektur prosesor berikut:%n%n%1 WinVersionTooLowError=Program ini memerlukan %1 versi %2 atau yang terbaru. WinVersionTooHighError=Program ini tidak dapat dipasang pada %1 versi %2 atau yang terbaru. -AdminPrivilegesRequired=Anda wajib masuk sebagai seorang administrator saat memasang program ini. -PowerUserPrivilegesRequired=Anda wajib masuk sebagai seorang administrator atau pengguna dari grup Power Users saat memasang program ini. -SetupAppRunningError=Pemasang mendeteksi bahwa %1 sedang berjalan.%n%nSilakan tutup semua program terkait, kemudian klik OK untuk lanjut, atau Batal untuk keluar. -UninstallAppRunningError=Pelepas mendeteksi bahwa %1 sedang berjalan.%n%nSilakan tutup semua program terkait, kemudian klik OK untuk lanjut, atau Batal untuk keluar. +AdminPrivilegesRequired=Anda harus masuk sebagai seorang administrator saat memasang program ini. +PowerUserPrivilegesRequired=Anda harus masuk sebagai seorang administrator atau anggota grup Power Users saat memasang program ini. +SetupAppRunningError=Kami mendeteksi bahwa %1 sedang berjalan.%n%nSilakan tutup semua instansi bersangkutan, lalu klik OK untuk meneruskan, atau Cancel untuk keluar. +UninstallAppRunningError=Pelepas mendeteksi bahwa %1 sedang berjalan.%n%nSilakan tutup semua instansi bersangkutan, lalu klik OK untuk meneruskan, atau Cancel untuk keluar. -; *** Pertanyaan saat memuat Pemasang -PrivilegesRequiredOverrideTitle=Pilih Mode Pemasang -PrivilegesRequiredOverrideInstruction=Pilih mode pemasangan -PrivilegesRequiredOverrideText1=%1 bisa dipasang untuk semua pengguna (perlu izin administratif), atau hanya untuk Anda. -PrivilegesRequiredOverrideText2=%1 bisa dipasang hanya untuk Anda, atau untuk semua pengguna (perlu izin administratif). +;Inno6 +PrivilegesRequiredOverrideTitle=Pilih Mode Instalasi +PrivilegesRequiredOverrideInstruction=Pilih mode instalasi +PrivilegesRequiredOverrideText1=%1 bisa dipasang untuk semua pengguna (perlu izin administratif), atau hanya Anda. +PrivilegesRequiredOverrideText2=%1 bisa dipasang hanya untuk Anda, atau semua pengguna (perlu izin administratif). PrivilegesRequiredOverrideAllUsers=Pasang untuk &semua pengguna PrivilegesRequiredOverrideAllUsersRecommended=Pasang untuk &semua pengguna (disarankan) -PrivilegesRequiredOverrideCurrentUser=Pasang hanya untuk saya -PrivilegesRequiredOverrideCurrentUserRecommended=Pasang hanya untuk saya (disarankan) +PrivilegesRequiredOverrideCurrentUser=Pasang &hanya untuk saya +PrivilegesRequiredOverrideCurrentUserRecommended=Pasang &hanya untuk saya (disarankan) +;Inno6 -; *** Macam-macam galat -ErrorCreatingDir=Pemasang tidak dapat membuat direktori "%1" -ErrorTooManyFilesInDir=Tidak dapat membuat berkas dalam direktori "%1" karena berisi terlalu banyak berkas. +ErrorCreatingDir=Kami tidak dapat membuat direktori "%1" +ErrorTooManyFilesInDir=Tidak dapat membuat berkas di direktori "%1" karena berisi terlalu banyak berkas -; *** Pesan umum pada Pemasamg -ExitSetupTitle=Tutup Pemasang -ExitSetupMessage=Pemasangan tidak lengkap. Bila Anda keluar sekarang, program tidak akan terpasang.%n%nAnda dapat menjalankan kembali Pemasang ini lain kali untuk melengkapi pemasangan.%n%nTutup Pemasang? -AboutSetupMenuItem=&Tentang Pemasang .... -AboutSetupTitle=Tentang Pemasang -AboutSetupMessage=%1 versi %2%n%3%n%n%1 laman muka:%n%4 +ExitSetupTitle=Keluar Pemandu +ExitSetupMessage=Instalasi tidak lengkap. Bila Anda keluar sekarang, program takkan terpasang.%n%nAnda bisa menjalankan Pemandu lagi lain kali untuk melengkapinya.%n%nKeluar? +AboutSetupMenuItem=&Tentang Pemandu... +AboutSetupTitle=Tentang Pemandu +AboutSetupMessage=%1 versi %2%n%3%n%n%1 laman beranda:%n%4 AboutSetupNote= -TranslatorNote=Bila Anda menemukan typo (kesalahan pengetikan), terjemahan yang salah atau kurang tepat, atau Anda ingin mendapatkan terjemahan untuk versi lawas, silakan kirimkan surel (email) ke mozaik(dot)tm(at)gmail(dot)com +TranslatorNote= -; *** Tombol-tombol -ButtonBack=< &Sebelumnya -ButtonNext=&Berikutnya > +ButtonBack=&Kembali +ButtonNext=&Maju ButtonInstall=&Pasang -ButtonOK=OK +ButtonOK=Oke ButtonCancel=Batal -ButtonYes=&Iya -ButtonYesToAll=Iya &semuanya +ButtonYes=&Ya +ButtonYesToAll=Y&a semuanya ButtonNo=&Tidak -ButtonNoToAll=&Tidak semuanya +ButtonNoToAll=T&idak semuanya ButtonFinish=&Selesai -ButtonBrowse=&Jelajahi .... -ButtonWizardBrowse=J&elajahi .... +ButtonBrowse=&Cari... +ButtonWizardBrowse=C&ari... ButtonNewFolder=&Buat Map Baru -; *** Halaman "Pilih Bahasa" -SelectLanguageTitle=Pilih Bahasa Pemasang -SelectLanguageLabel=Pilih bahasa untuk digunakan selama pemasangan. +SelectLanguageTitle=Pilih Bahasa Pemandu +SelectLanguageLabel=Pilih bahasa untuk digunakan ketika memasang. -; *** Pesan umum pada Pemasang -ClickNext=Klik Berikutnya untuk melanjutkan, atau Batal untuk menutup Pemasang. +ClickNext=Klik Maju untuk meneruskan, atau Batal untuk keluar. BeveledLabel= -BrowseDialogTitle=Pilih Map -BrowseDialogLabel=Pilih satu map dalam daftar di bawah, kemudian klik OK. +BrowseDialogTitle=Cari Map +BrowseDialogLabel=Pilih map dari daftar berikut, lalu klik OK. NewFolderName=Map Baru -; *** Halaman "Selamat Datang" -WelcomeLabel1=Selamat datang di Asisten Pemasangan [name] -WelcomeLabel2=Kami akan memasang [name/ver] pada komputer Anda.%n%nAnda disarankan untuk menutup semua aplikasi sebelum melanjutkan. +WelcomeLabel1=Selamat datang di Pemandu Instalasi [name] +WelcomeLabel2=Kami akan memasang [name/ver] pada komputer Anda.%n%nDisarankan untuk menutup semua aplikasi lainnya sebelum meneruskan. -; *** Halaman "Kata Sandi" WizardPassword=Kata Sandi -PasswordLabel1=Pemasang ini dilindungi kata sandi. -PasswordLabel3=Silakan masukkan kata sandi, lalu klik Berikutnya untuk melanjutkan. Kata sandi bersifat sensitif kapitalisasi. +PasswordLabel1=Instalasi ini dilindungi kata sandi. +PasswordLabel3=Silakan masukkan kata sandi, lalu klik Maju untuk meneruskan. Kata sandi bersifat sensitif-kapitalisasi. PasswordEditLabel=&Kata Sandi: IncorrectPassword=Kata sandi yang Anda masukkan salah. Silakan coba lagi. -; *** Halaman "Kesepakatan Lisensi" WizardLicense=Kesepakatan Lisensi -LicenseLabel=Silakan baca informasi penting berikut sebelum melanjutkan. -LicenseLabel3=Silakan baca Kesepakatan Lisensi berikut. Anda wajib menyetujui syarat-syarat kesepakatan ini sebelum melanjutkan pemasangan. -LicenseAccepted=Saya &setuju dengan kesepakatan ini -LicenseNotAccepted=Saya &tidak setuju dengan kesepakatan ini +LicenseLabel=Silakan baca informasi berikut sebelum meneruskan. +LicenseLabel3=Silakan baca Kesepakatan Lisensi berikut. Anda harus setuju dengan syarat dari kesepakatan ini sebelum meneruskan instalasi. +LicenseAccepted=Saya &setujui kesepakatan ini +LicenseNotAccepted=Saya &tidak setuju kesepakatan ini -; *** Halaman "Informasi" WizardInfoBefore=Informasi -InfoBeforeLabel=Silakan baca informasi penting berikut sebelum melanjutkan. -InfoBeforeClickLabel=Bila Anda sudah siap melanjutkan pemasangan, klik Berikutnya. +InfoBeforeLabel=Silakan baca informasi penting berikut sebelum meneruskan. +InfoBeforeClickLabel=Saat Anda siap meneruskan instalasi, klik Maju. WizardInfoAfter=Informasi -InfoAfterLabel=Silakan baca informasi penting berikut sebelum melanjutkan. -InfoAfterClickLabel=Bila Anda sudah siap melanjutkan pemasangan, klik Berikutnya. +InfoAfterLabel=Silakan baca informasi penting berikut sebelum meneruskan. +InfoAfterClickLabel=Saat Anda siap meneruskan instalasi, klik Maju. -; *** Halaman "Informasi Pengguna" WizardUserInfo=Informasi Pengguna UserInfoDesc=Silakan masukkan informasi Anda. UserInfoName=&Nama Pengguna: UserInfoOrg=&Organisasi: -UserInfoSerial=Nomor Seri: -UserInfoNameRequired=Anda wajib memasukkan nama. +UserInfoSerial=&Nomor Seri: +UserInfoNameRequired=Wajib memasukkan nama. -; *** Halaman "Pilih Lokasi Pemasangan" -WizardSelectDir=Pilih Lokasi Pemasangan +WizardSelectDir=Pilih Lokasi Tujuan SelectDirDesc=Di manakah [name] sebaiknya dipasang? -SelectDirLabel3=Kami akan memasang [name] di dalam map berikut. -SelectDirBrowseLabel=Klik Berikutnya untuk melanjutkan. Bila Anda ingin memilih map lain, klik Jelajahi. -DiskSpaceGBLabel=Diperlukan sedikitnya [gb] GB ruang kosong. -DiskSpaceMBLabel=Diperlukan sedikitnya [mb] MB ruang kosong. -CannotInstallToNetworkDrive=Kami tidak dapat memasang pada kandar jaringan. -CannotInstallToUNCPath=Kami tidak dapat memasang pada lokasi UNC. -InvalidPath=Anda wajib memasukkan lokasi map lengkap dengan nama kandar; misalnya:%n%nC:\APP%n%natau sebuah alamat UNC dengan format:%n%n\\server\share -InvalidDrive=Kandar atau alamat UNC yang Anda pilih tidak ada atau tidak dapat diakses. Silakan pilih yang lain. -DiskSpaceWarningTitle=Ruang Kosong Tidak Mencukupi -DiskSpaceWarning=Pemasang memerlukan sedikitnya %1 KB ruang kosong, tetapi kandar terpilih hanya memiliki %2 KB tersedia.%n%nTetap lanjutkan? -DirNameTooLong=Alamat atau nama map terlalu panjang. -InvalidDirName=Nama map ini tidak sah. -BadDirName32=Nama map dilarang berisi karakter berikut:%n%n%1 +SelectDirLabel3=Kami akan memasang [name] ke dalam map berikut. +SelectDirBrowseLabel=Untuk meneruskan, klik Maju. Bila Anda ingin memilih map lain, klik Cari. +;Inno6 +DiskSpaceGBLabel=Diperlukan sedikitnya [gb] GB ruang bebas. +;Inno6 +DiskSpaceMBLabel=Diperlukan sedikitnya [mb] MB ruang bebas. +CannotInstallToNetworkDrive=Kami tidak bisa memasang ke diska jaringan. +CannotInstallToUNCPath=Kami tidak bisa memasang ke alamat UNC. +InvalidPath=Anda wajib memasukkan alamat lengkap dengan huruf diska; contohnya:%n%nC:\APP%n%natau alamat UNC dalam bentuk:%n%n\\server\share +InvalidDrive=Diska atau alamat UNC yang Anda pilih tidak ada atau tidak dapat diakses. Silakan pilih yang lain. +DiskSpaceWarningTitle=Ruang Bebas Tidak Cukup +DiskSpaceWarning=Kami memerlukan sedikitnya %1 KB ruang bebas untuk memasang, namun diska yang Anda pilih hanya memiliki %2 KB tersedia.%n%nMaju terus? +DirNameTooLong=Nama map atau alamat terlalu panjang. +InvalidDirName=Nama map tidak sah. +BadDirName32=Nama map dilarang berisi karakter-karakter berikut:%n%n%1 DirExistsTitle=Map Sudah Ada DirExists=Map:%n%n%1%n%nsudah ada. Tetap pasang di map tersebut? -DirDoesntExistTitle=Map Belum Ada -DirDoesntExist=Map:%n%n%1%n%nbelum ada. Buat map tersebut? +DirDoesntExistTitle=Map Tidak Ada +DirDoesntExist=Map:%n%n%1%n%ntidak ada. Buat map? -; *** Halaman "Pilih Komponen" WizardSelectComponents=Pilih Komponen SelectComponentsDesc=Komponen mana sajakah yang sebaiknya dipasang? -SelectComponentsLabel2=Pilih komponen-komponen yang Anda ingin pasang; hapus centang pada komponen yang Anda tidak ingin pasang. Klik Berikutnya bila Anda siap melanjutkan. -FullInstallation=Pasang secara penuh -; kalau bisa, jangan terjemahkan "Padat" (Compact) menjadi "Minimal". Maksudnya, "Minimal" dalam bahasa Anda -CompactInstallation=Pemasangan Padat -CustomInstallation=Suka-suka saya -NoUninstallWarningTitle=Komponen Sudah Ada -NoUninstallWarning=Kami mendeteksi bahwa komponen-komponen berikut sudah terpasang pada komputer Anda:%n%n%1%n%nKomponen-komponen tersebut tidak akan dihapus walau Anda batal memilihnya.%n%nTetap lanjutkan? +SelectComponentsLabel2=Centang komponen yang Anda inginkan; batalkan centang dari komponen yang tidak Anda inginkan. Klik Maju saat Anda siap meneruskan. +FullInstallation=Instalasi penuh +CompactInstallation=Instalasi padat +CustomInstallation=Instalasi kustom +NoUninstallWarningTitle=Komponen Terpasang +NoUninstallWarning=Kami mendeteksi bahwa komponen berikut telah terpasang pada komputer Anda:%n%n%1%n%nMembatalkan pilihan atas komponen berikut bukan berarti melepasnya.%n%nMaju terus? ComponentSize1=%1 KB ComponentSize2=%1 MB -ComponentsDiskSpaceGBLabel=Pilihan Anda saat ini memerlukan sedikitnya [gb] GB ruang kosong. -ComponentsDiskSpaceMBLabel=Pilihan Anda saat ini memerlukan sedikitnya [mb] MB ruang kosong. +;Inno6 +ComponentsDiskSpaceGBLabel=Pilihan saat ini memerlukan sedikitnya [gb] GB ruang bebas. +;Inno6 +ComponentsDiskSpaceMBLabel=Pilihan saat ini memerlukan sedikitnya [mb] MB ruang bebas. -; *** Halaman "Pilih Tugas Tambahan" WizardSelectTasks=Pilih Tugas Tambahan -SelectTasksDesc=Tugas tambahan mana sajakah yang Anda ingin jalankan? -SelectTasksLabel2=Pilih tugas tambahan yang Anda ingin agar kami jalankan saat memasang [name], lalu klik Berikutnya. +SelectTasksDesc=Tugas tambahan mana sajakah yang sebaiknya dijalankan? +SelectTasksLabel2=Pilih tugas tambahan yang Anda ingin kami jalankan ketika memasang [name], lalu klik Maju. -; *** Halaman "Pilih Map Menu Start" WizardSelectProgramGroup=Pilih Map Menu Start -SelectStartMenuFolderDesc=Di manakah sebaiknya kami menempatkan pintasan program? -SelectStartMenuFolderLabel3=Kami akan membuat pintasan program di dalam map Menu Start berikut. -SelectStartMenuFolderBrowseLabel=Klik Berikutnya untuk melanjutkan. Bila Anda ingin memilih map lain, klik Jelajahi. +SelectStartMenuFolderDesc=Di manakah sebaiknya kami letakkan pintasan program? +SelectStartMenuFolderLabel3=Kami akan membuat pintasan program di map Menu Start berikut. +SelectStartMenuFolderBrowseLabel=Untuk meneruskan, klik Maju. Bila Anda ingin memilih map lain, klik Cari. MustEnterGroupName=Anda wajib memasukkan nama map. -GroupNameTooLong=Alamat atau nama map terlalu panjang. +GroupNameTooLong=Nama map atau alamat terlalu panjang. InvalidGroupName=Nama map tidak sah. -BadGroupName=Nama map dilarang berisi karakter berikut:%n%n%1 +BadGroupName=Nama map dilarang berisi karakter-karakter berikut:%n%n%1 NoProgramGroupCheck2=&Jangan buat map Menu Start -; *** Halaman "Siap Memasang" WizardReady=Siap Memasang -ReadyLabel1=Kami telah siap untuk mulai memasang [name] pada komputer Anda. -ReadyLabel2a=Klik Pasang untuk melanjutkan dengan pengaturan yang Anda pilih, atau klik Sebelumnya bila Anda ingin melihat ulang atau mengubah pengaturan. -ReadyLabel2b=Klik Pasang untuk melanjutkan dengan pengaturan yang Anda pilih +ReadyLabel1=Kami siap untuk memulai instalasi [name] pada komputer Anda. +ReadyLabel2a=Klik Pasang untuk meneruskan instalasi, atau klik Kembali bila Anda ingin menilik atau mengubah setelan. +ReadyLabel2b=Klik Pasang untuk meneruskan instalasi. ReadyMemoUserInfo=Informasi pengguna: -ReadyMemoDir=Lokasi pemasangan: -ReadyMemoType=Jenis pemasangan: +ReadyMemoDir=Lokasi tujuan: +ReadyMemoType=Tipe instalasi: ReadyMemoComponents=Komponen terpilih: ReadyMemoGroup=Map Menu Start: ReadyMemoTasks=Tugas Tambahan: -; *** Halaman "Bersiap Memasang" +;Inno6 +DownloadingLabel=Mengunduh berkas tambahan... +ButtonStopDownload=&Setop Unduhan +StopDownload=Anda yakin ingin berhenti mengunduh? +ErrorDownloadAborted=Unduhan dibatalkan +ErrorDownloadFailed=Gagal mengunduh: %1 %2 +ErrorDownloadSizeFailed=Gagal mendapatkan ukuran: %1 %2 +ErrorFileHash1=Ceksum berkas gagal: %1 +ErrorFileHash2=Ceksum berkas tidak sah: seharusnya %1, yang kami dapatkan %2 +ErrorProgress=Langkah tidak sah: %1 dari %2 +ErrorFileSize=Ukuran berkas tidak sah: seharusnya %1, yang kami dapatkan %2 +;Inno6 + WizardPreparing=Bersiap Memasang PreparingDesc=Kami sedang bersiap memasang [name] pada komputer Anda. -PreviousInstallNotCompleted=Pemasangan/pelepasan dari program sebelumnya tidaklah lengkap. Anda perlu memulai ulang komputer untuk melengkapi pemasangan tersebut.%n%nSeusai memulai ulang komputer, jalankan Pemasang ini lagi untuk melengkapi pemasangan [name]. -CannotContinue=Kami tidak dapat melanjutkan. Silakan klik Batal untuk keluar. -ApplicationsFound=Aplikasi-aplikasi berikut sedang memakai berkas-berkas yang perlu diperbarui oleh kami. Disarankan agar Anda mengizinkan kami untuk menutup aplikasi-aplikasi tersebut secara otomatis. -ApplicationsFound2=Aplikasi-aplikasi berikut sedang memakai berkas-berkas yang perlu diperbaru oleh kami. Disarankan agar Anda mengizinkan kami untuk menutup aplikasi-aplikasi tersebut secara otomatis. Seusai memasang, kami akan berusaha menjalankan ulang aplikasi-aplikasi tersebut. -CloseApplications=&Otomatis tutup aplikasi-aplikasi tersebut -DontCloseApplications=&Jangan tutup aplikasi-aplikasi tersebut -ErrorCloseApplications=Kami tidak dapat menutup semua aplikasi tersebut secara otomatis. Disarankan agar Anda menutup semua aplikasi yang memakai berkas-berkas yang perlu kami perbarui sebelum melanjutkan. -PrepareToInstallNeedsRestart=Kami harus memulai ulang komputer Anda. Seusai memulai ulang, jalankan kembali Pemasang ini untuk melengkapi pemasangan [name].%n%nMulai ulang sekarang? +PreviousInstallNotCompleted=Instalasi/pelepasan dari program sebelumnya tidak lengkap. Anda perlu memulai ulang komputer untuk melengkapinya nanti.%n%nSetelah itu, jalankan Pemandu kembali untuk melengkapi instalasi [name]. +CannotContinue=Kami tidak bisa meneruskan. Klik Batal untuk keluar. +ApplicationsFound=Aplikasi berikut tengah memakai berkas-berkas yang perlu kami perbarui. Disarankan agar Anda mengizinkan kami untuk menutupnya secara otomatis. +ApplicationsFound2=Aplikasi berikut tengah memakai berkas-berkas yang perlu kami perbarui. Disarankan agar Anda mengizinkan kami untuk menutupnya secara otomatis. Selengkapnya memasang, kami akan berusaha memulai ulang aplikasi-aplikasi tersebut. +CloseApplications=&Otomatis tutup aplikasi +DontCloseApplications=&Jangan tutup aplikasi +ErrorCloseApplications=Kami tidak dapat menutup semua aplikasi secara otomatis. Disarankan agar Anda menutup semua aplikasi yang memakai berkas-berkas yang perlu kami perbarui sebelum meneruskan. +;Inno6 +PrepareToInstallNeedsRestart=Kami perlu memulai ulang komputer Anda. Setelah itu, jalankan Pemandu kembali untuk melengkapi pemasangan [name].%n%nMulai ulang sekarang? +;Inno6 -; *** Halaman "Memasang" WizardInstalling=Memasang -InstallingLabel=Silakan tunggu sementara kami memasang [name] pada komputer Anda. +InstallingLabel=Silakan tunggu selagi kami memasang [name] pada komputer Anda. -; *** Halaman "Pemasangan Lengkap" -FinishedHeadingLabel=Menyelesaikan Asisten Pemasangan [name] +FinishedHeadingLabel=Mengakhiri Instalasi [name] FinishedLabelNoIcons=Kami telah selesai memasang [name] pada komputer Anda. -FinishedLabel=Kami telah selesai memasang [name] pada komputer Anda. Program tersebut dapat dijalankan dengan memilih pintasan yang terpasang. -ClickFinish=Klik Selesai untuk mengakhiri pemasangan. -FinishedRestartLabel=Agar pemasangan [name] lengkap, kami harus memulai ulang komputer Anda. Mulai ulang sekarang? -FinishedRestartMessage=Agar pemasangan [name] lengkap, kami harus memulai ulang komputer Anda.%n%nMulai ulang sekarang? -ShowReadmeCheck=Ya, saya mau membaca berkas README -YesRadio=&Ya, mulai ulang sekarang -NoRadio=&Tidak, saya akan memulai ulang nanti -; contoh: 'Jalankan MyProg.exe' +FinishedLabel=Kami telah selesai memasang [name] pada komputer Anda. Aplikasi tersebut bisa dijalankan dengan cara memilih pintasan yang terpasang. +ClickFinish=Klik Selesai untuk menutup instalasi. +FinishedRestartLabel=Demi melengkapi instalasi [name], kami perlu memulai ulang komputer Anda. Lakukan sekarang? +FinishedRestartMessage=Demi melengkapi instalasi [name], kami perlu memulai ulang komputer Anda.%n%nLakukan sekarang? +ShowReadmeCheck=Ya, saya ingin melihat berkas README +YesRadio=&Ya, mulai ulang komputer sekarang +NoRadio=&Tidak, saya akan memulai ulang komputer nanti RunEntryExec=Jalankan %1 -; contoh: 'Lihat Readme.txt' RunEntryShellExec=Lihat %1 -; *** Pesan yang berkaitan dengan "Setup Needs the Next Disk" -ChangeDiskTitle=Kami Memerlukan Kandar Lanjutan -SelectDiskLabel2=Silakan masukkan Kandar %1 dan klik OK.%n%nBila berkas-berkas pada kandar ini dapat ditemukan selain pada map berikut, masukkan alamat yang tepat atau klik Jelajahi. +ChangeDiskTitle=Kami Memerlukan Diska Sambungan +SelectDiskLabel2=Silakan masukkan Diska %1 dan klik OK.%n%nBila berkas-berkas di dalam diska ini dapat ditemukan di map lain selain yang ditampilkan di bawah, masukkan alamat yang benar atau klik Cari. PathLabel=&Alamat: -FileNotInDir2=Berkas "%1" tidak dapat ditemukan di dalam "%2". Silakan masukkan kandar yang tepat atau pilih map lain. -SelectDirectoryLabel=Silakan tunjukkan lokasi kandar lanjutan. +FileNotInDir2=Berkas "%1" tidak dapat ditemukan di "%2". Silakan masukkan diska yang benar atau pilih map lain. +SelectDirectoryLabel=Silakan tentukan lokasi diska berikutnya. -; *** Pesan untuk fase pemasangan -SetupAborted=Pemasangan tidak lengkap.%n%nSilakan selesaikan masalah dan jalankan Pemasang ini kembali. +SetupAborted=Instalasi tidak lengkap.%n%nSilakan koreksi masalah dan jalankan Pemandu kembali. +;Inno6 AbortRetryIgnoreSelectAction=Pilih tindakan AbortRetryIgnoreRetry=&Coba lagi -AbortRetryIgnoreIgnore=&Abaikan masalah dan lanjutkan +AbortRetryIgnoreIgnore=&Abaikan galat dan teruskan AbortRetryIgnoreCancel=Batalkan pemasangan +;Inno6 -; *** Pesan untuk status pemasangan -StatusClosingApplications=Menutup aplikasi .... -StatusCreateDirs=Membuat direktori .... -StatusExtractFiles=Mengekstrak berkas .... -StatusCreateIcons=Membuat pintasan .... -StatusCreateIniEntries=Membuat isi berkas INI ... -StatusCreateRegistryEntries=Membuat daftar registri .... -StatusRegisterFiles=Mendaftarkan berkas .... -StatusSavingUninstall=Menyimpan informasi pelepasan .... -StatusRunProgram=Mengakhiri pemasangan .... -StatusRestartingApplications=Memulai ulang aplikasi .... -StatusRollback=Membatalkan perubahan .... +StatusClosingApplications=Menutup aplikasi... +StatusCreateDirs=Membuat direktori... +StatusExtractFiles=Mengekstrak berkas... +StatusCreateIcons=Membuat pintasan... +StatusCreateIniEntries=Membuat catatan INI... +StatusCreateRegistryEntries=Membuat catatan Registry... +StatusRegisterFiles=Meregistrasi berkas... +StatusSavingUninstall=Menyimpan informasi pelepas... +StatusRunProgram=Mengakhiri instalasi... +StatusRestartingApplications=Menjalankan ulang aplikasi... +StatusRollback=Membatalkan perubahan... -; *** Masalah secara umum -ErrorInternal2=Masalah internal: %1 +ErrorInternal2=Galat internal: %1 ErrorFunctionFailedNoCode=%1 gagal ErrorFunctionFailed=%1 gagal; kode %2 ErrorFunctionFailedWithMessage=%1 gagal; kode %2.%n%3 ErrorExecutingProgram=Tidak dapat mengeksekusi berkas:%n%1 -; *** Masalah pada Registry -ErrorRegOpenKey=Masalah saat membuka kunci registri:%n%1\%2 -ErrorRegCreateKey=Masalah saat membuat kunci registri:%n%1\%2 -ErrorRegWriteKey=Masalah saat menulis pada kunci registri:%n%1\%2 +ErrorRegOpenKey=Galat membuka kunci Registry:%n%1\%2 +ErrorRegCreateKey=Galat membuat kunci Registry:%n%1\%2 +ErrorRegWriteKey=Galat menulis kunci Registry:%n%1\%2 -; *** Masalah pada INI -ErrorIniEntry=Terjadi masalah saat membuat entri INI dalam berkas "%1". +ErrorIniEntry=Galat membuat catatan INI dalam berkas "%1". -; *** Masalah saat menyalin berkas +;Inno6 FileAbortRetryIgnoreSkipNotRecommended=&Lewati berkas ini (tidak disarankan) -FileAbortRetryIgnoreIgnoreNotRecommended=&Abaikan masalah dan lanjutkan (tidak disarankan) -SourceIsCorrupted=Berkas sumber telah rusak -SourceDoesntExist=Berkas sumber "%1" tidak ada -ExistingFileReadOnly2=Berkas yang telah ada tidak bisa diganti karena ditandai hanya-baca. +FileAbortRetryIgnoreIgnoreNotRecommended=&Abaikan galat dan teruskan (tidak disarankan) +;Inno6 + +SourceIsCorrupted=Berkas asal telah rusak +SourceDoesntExist=Berkas asal "%1" tidak ada + +;Inno6 +ExistingFileReadOnly2=Berkas yang sudah ada tidak bisa ditimpa karena telah ditandai hanya-baca. ExistingFileReadOnlyRetry=&Hapus atribut hanya-baca dan coba lagi ExistingFileReadOnlyKeepExisting=&Pertahankan berkas yang sudah ada -ErrorReadingExistingDest=Terjadi masalah saat mencoba membaca berkas yang sudah ada: -FileExists=Berkas sudah ada.%n%nTimpa berkas tersebut? -ExistingFileNewer=Berkas yang sudah ada lebih baru dibanding dengan yang akan kami pasang. Disarankan agar Anda mempertahankan berkas tersebut.%n%nPertahankan berkas tersebut? -ErrorChangingAttr=Terjadi masalah saat mencoba mengubah atribut berkas yang sudah ada: -ErrorCreatingTemp=Terjadi masalah saat mencoba membuat berkas di dalam direktori pemasangan: -ErrorReadingSource=Terjadi masalah saat mencoba membaca berkas sumber: -ErrorCopying=Terjadi masalah saat mencoba menyalin berkas: -ErrorReplacingExistingFile=Terjadi masalah saat mencoba menimpa berkas yang sudah ada: -ErrorRestartReplace=Fungsi RestartReplace gagal: -ErrorRenamingTemp=Terjadi masalah saat mencoba mengubah nama berkas dalam direktori pemasangan: -ErrorRegisterServer=Tidak dapat mendaftarkan berkas DLL/OCX: %1 +ErrorReadingExistingDest=Terjadi galat saat berusaha membaca berkas yang sudah ada: +FileExistsSelectAction=Pilih tindakan +FileExists2=Berkas sudah ada. +FileExistsOverwriteExisting=&Timpa berkas yang sudah ada +FileExistsKeepExisting=&Pertahankan berkas yang sudah ada +FileExistsOverwriteOrKeepAll=&Lakukan ini untuk konflik (bentrok) berikutnya +ExistingFileNewerSelectAction=Pilih tindakan +ExistingFileNewer2=Berkas yang sudah ada lebih baru dari yang akan kami coba pasang. +ExistingFileNewerOverwriteExisting=&Timpa berkas yang sudah ada +ExistingFileNewerKeepExisting=&Pertahankan berkas yang sudah ada (disarankan) +ExistingFileNewerOverwriteOrKeepAll=&Lakukan ini untuk konflik (bentrok) berikutnya +;Inno6 +ErrorReadingExistingDest=Terjadi galat saat berusaha membaca berkas yang sudah ada: +ErrorChangingAttr=Terjadi galat saat berusaha mengubah atribusi berkas yang sudah ada: +ErrorCreatingTemp=Terjadi galat saat berusaha membuat berkas di direktori tujuan: +ErrorReadingSource=Terjadi galat saat berusaha membaca berkas asal: +ErrorCopying=Terjadi galat saat berusaha menyalin berkas: +ErrorReplacingExistingFile=Terjadi galat saat berusaha menimpa berkas yang sudah ada: +ErrorRestartReplace=RestartReplace gagal: +ErrorRenamingTemp=Terjadi galat saat berusaha mengubah nama berkas di direktori tujuan: +ErrorRegisterServer=Tidak dapat meregistrasi DLL/OCX: %1 ErrorRegSvr32Failed=RegSvr32 gagal dengan kode akhir %1 -ErrorRegisterTypeLib=Tidak dapat mendaftarkan pustaka: %1 +ErrorRegisterTypeLib=Tidak dapat meregistrasi berkas referensi: %1 -; *** Penandaan tampilan nama saat melepas -; contoh 'Program saya (32-bita)' +;Inno6 UninstallDisplayNameMark=%1 (%2) -; contoh 'Program saya (32-bita, Semua pengguna)' UninstallDisplayNameMarks=%1 (%2, %3) UninstallDisplayNameMark32Bit=32-bita UninstallDisplayNameMark64Bit=64-bita UninstallDisplayNameMarkAllUsers=Semua pengguna UninstallDisplayNameMarkCurrentUser=Pengguna saat ini +;Inno6 -; *** Masalah pasca-pemasangan -ErrorOpeningReadme=Terjadi masalah saat mencoba membuka berkas README. -ErrorRestartingComputer=Kami tidak dapat memulai ulang komputer. Silakan lakukan secara manual. +ErrorOpeningReadme=Terjadi galat saat berusaha membuka berkas README. +ErrorRestartingComputer=Kami gagal memulai ulang komputer. Silakan lakukan secara manual. -; *** Pesan untuk Pelepas -UninstallNotFound=Berkas "%1" tidak ada. Tidak bisa melepas. -UninstallOpenError=Berkas "%1" tidak bisa dibuka. Tidak bisa melepas -UninstallUnsupportedVer=Berkas catatan pelepas "%1" tertulis dalam format yang tak dikenali oleh pelepas versi ini. Tidak bisa melepas. +UninstallNotFound=Berkas "%1" tidak ada. Tidak bisa melepas +UninstallOpenError=Berkas "%1" tidak dapat dibuka. Tidak bisa melepas +UninstallUnsupportedVer=Berkas catatan pelepas "%1" tidak dalam format yang kami kenali. Tidak bisa melepas UninstallUnknownEntry=Entri tak dikenal (%1) ditemukan dalam catatan pelepas -ConfirmUninstall=Apakah Anda yakin hendak menghapus %1 beserta semua komponennya? -UninstallOnlyOnWin64=Instalasi ini hanya dapat dilepas pada Windows 64-bita. -OnlyAdminCanUninstall=Instalasi ini hanya dapat dilepas oleh pengguna dengan izin administratif. -UninstallStatusLabel=Silakan tunggu sementara %1 dihapus dari komputer Anda. -UninstalledAll=%1 berhasil dilepas dari komputer Anda. -UninstalledMost=Selesai melepas %1.%n%nBeberapa elemen tidak dapat dihapus. Anda dapat menghapusnya secara manual. -UninstalledAndNeedsRestart=Untuk melengkapi pelepasan %1, komputer Anda harus dimulai ulang.%n%nMulai ulang sekarang? -UninstallDataCorrupted=Berkas "%1" telah rusak. Tidak bisa melepas +ConfirmUninstall=Anda yakin ingin melepas %1 beserta semua komponennya? +UninstallOnlyOnWin64=Instalasi ini hanya bisa dilepas pada Windows 64-bita. +OnlyAdminCanUninstall=Instalasi ini hanya bisa dilepas oleh pengguna dengan izin administratif. +UninstallStatusLabel=Silakan tunggu selagi %1 dihapus dari komputer Anda. +UninstalledAll=%1 berhasil dihapus dari komputer Anda. +UninstalledMost=Selesai melepas %1.%n%nBeberapa elemen tidak dapat dihapus. Anda bisa menghapusnya secara manual. +UninstalledAndNeedsRestart=Untuk melengkapi pelepasan %1, komputer Anda perlu dimulai ulang.%n%nMulai ulang sekarang? +UninstallDataCorrupted=Berkas "%1" rusak. Tidak bisa melepas -; *** Pesan untuk fase pelepasan ConfirmDeleteSharedFileTitle=Hapus Berkas Bersama? -ConfirmDeleteSharedFile2=Sistem mengindikasi bahwa berkas-berkas bersama berikut tidak lagi dipakai oleh program apa pun. Apakah Anda ingin kami menghapus berkas-berkas tersebut?%n%nJika berkas-berkas tersebut dihapus dan masih ada program yang memakainya, program tersebut mungkin akan berjalan di luar semestinya. Bila Anda tidak yakin, pilih Tidak. Membiarkan berkas tersebut pada komputer Anda tidak akan menimbulkan masalah. +ConfirmDeleteSharedFile2=Sistem mengindikasi bahwa berkas bersama di bawah ini tidak lagi dipakai oleh program mana pun. Apa Anda ingin agar kami menghapusnya?%n%nBila masih ada program yang memakainya dan berkas ini dihapus, program tersebut dapat tidak berfungsi dengan semestinya. Bila Anda ragu, pilih No. Membiarkan berkas ini pada sistem Anda takkan membahayakan. SharedFileNameLabel=Nama berkas: SharedFileLocationLabel=Lokasi: WizardUninstalling=Status Pelepasan StatusUninstalling=Melepas %1... -; *** Blok alasan Shutdown ShutdownBlockReasonInstallingApp=Memasang %1. ShutdownBlockReasonUninstallingApp=Melepas %1. -; Pesan khusus berikut tidak digunakan oleh Pemasang itu sendiri, -; namun bila Anda memakainya di dalam skrip Anda, maka terjemahkan. - [CustomMessages] NameAndVersion=%1 versi %2 AdditionalIcons=Pintasan tambahan: -CreateDesktopIcon=Buat pintasan di &Desktop -CreateQuickLaunchIcon=Buat pintasan di &Quick Launch -ProgramOnTheWeb=%1 di web +CreateDesktopIcon=Buat pintasan &desktop +CreateQuickLaunchIcon=Buat pintasan Pelontar &Cepat +ProgramOnTheWeb=%1 di Web UninstallProgram=Lepas %1 LaunchProgram=Jalankan %1 -AssocFileExtension=&Asosiasikan %1 dengan ekstensi berkas %2 -AssocingFileExtension=Mengasosiasikan %1 dengan ekstensi berkas %2 .... +AssocFileExtension=&Kaitkan %1 dengan ekstensi berkas %2 +AssocingFileExtension=Mengaitkan %1 dengan ekstensi berkas %2... AutoStartProgramGroupDescription=Startup: -AutoStartProgram=Jalankan %1 secara otomatis -AddonHostProgramNotFound=%1 tidak dapat ditemukan di dalam map yang Anda pilih.%n%nTetap lanjutkan? +AutoStartProgram=Otomatis jalankan %1 +AddonHostProgramNotFound=%1 tidak dapat ditemukan di map yang Anda pilih.%n%nMaju terus? diff --git a/installer/innosetup/Languages/Italian.isl b/installer/innosetup/Languages/Italian.isl new file mode 100644 index 000000000..cfdf8b5ca --- /dev/null +++ b/installer/innosetup/Languages/Italian.isl @@ -0,0 +1,390 @@ +; bovirus@gmail.com +; *** Inno Setup version 6.1.0+ Italian messages *** +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). +; +; Italian.isl - Last Update: 25.07.2020 by bovirus (bovirus@gmail.com) +; +; Translator name: bovirus +; Translator e-mail: bovirus@gmail.com +; Based on previous translations of Rinaldo M. aka Whiteshark (based on ale5000 5.1.11+ translation) +; +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Italiano +LanguageID=$0410 +LanguageCodePage=1252 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=Installazione +SetupWindowTitle=Installazione di %1 +UninstallAppTitle=Disinstallazione +UninstallAppFullTitle=Disinstallazione di %1 + +; *** Misc. common +InformationTitle=Informazioni +ConfirmTitle=Conferma +ErrorTitle=Errore + +; *** SetupLdr messages +SetupLdrStartupMessage=Questa è l'installazione di %1.%n%nVuoi continuare? +LdrCannotCreateTemp=Impossibile creare un file temporaneo.%n%nInstallazione annullata. +LdrCannotExecTemp=Impossibile eseguire un file nella cartella temporanea.%n%nInstallazione annullata. + +; *** Startup error messages +LastErrorMessage=%1.%n%nErrore %2: %3 +SetupFileMissing=File %1 non trovato nella cartella di installazione.%n%nCorreggi il problema o richiedi una nuova copia del programma. +SetupFileCorrupt=I file di installazione sono danneggiati.%n%nRichiedi una nuova copia del programma. +SetupFileCorruptOrWrongVer=I file di installazione sono danneggiati, o sono incompatibili con questa versione del programma di installazione.%n%nCorreggi il problema o richiedi una nuova copia del programma. +InvalidParameter=È stato inserito nella riga di comando un parametro non valido:%n%n%1 +SetupAlreadyRunning=Il processo di installazione è già in funzione. +WindowsVersionNotSupported=Questo programma non supporta la versione di Windows installata nel computer. +WindowsServicePackRequired=Questo programma richiede %1 Service Pack %2 o successivo. +NotOnThisPlatform=Questo programma non è compatibile con %1. +OnlyOnThisPlatform=Questo programma richiede %1. +OnlyOnTheseArchitectures=Questo programma può essere installato solo su versioni di Windows progettate per le seguenti architetture della CPU:%n%n%1 +WinVersionTooLowError=Questo programma richiede %1 versione %2 o successiva. +WinVersionTooHighError=Questo programma non può essere installato su %1 versione %2 o successiva. +AdminPrivilegesRequired=Per installare questo programma sono richiesti privilegi di amministratore. +PowerUserPrivilegesRequired=Per poter installare questo programma sono richiesti i privilegi di amministratore o di Power Users. +SetupAppRunningError=%1 è attualmente in esecuzione.%n%nChiudi adesso tutte le istanze del programma e poi seleziona "OK", o seleziona "Annulla" per uscire. +UninstallAppRunningError=%1 è attualmente in esecuzione.%n%nChiudi adesso tutte le istanze del programma e poi seleziona "OK", o seleziona "Annulla" per uscire. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Seleziona modo installazione +PrivilegesRequiredOverrideInstruction=Seleziona modo installazione +PrivilegesRequiredOverrideText1=%1 può essere installato per tutti gli utenti (richiede privilegi di amministratore), o solo per l'utente attuale. +PrivilegesRequiredOverrideText2=%1 può essere installato solo per l'utente attuale, o per tutti gli utenti (richiede privilegi di amministratore). +PrivilegesRequiredOverrideAllUsers=Inst&alla per tutti gli utenti +PrivilegesRequiredOverrideAllUsersRecommended=Inst&alla per tutti gli utenti (suggerito) +PrivilegesRequiredOverrideCurrentUser=Installa solo per l'&utente attuale +PrivilegesRequiredOverrideCurrentUserRecommended=Installa solo per l'&utente attuale (suggerito) + +; *** Misc. errors +ErrorCreatingDir=Impossibile creare la cartella "%1" +ErrorTooManyFilesInDir=Impossibile creare i file nella cartella "%1" perché contiene troppi file. + +; *** Setup common messages +ExitSetupTitle=Uscita dall'installazione +ExitSetupMessage=L'installazione non è completa.%n%nUscendo dall'installazione in questo momento, il programma non sarà installato.%n%nÈ possibile eseguire l'installazione in un secondo tempo.%n%nVuoi uscire dall'installazione? +AboutSetupMenuItem=&Informazioni sull'installazione... +AboutSetupTitle=Informazioni sull'installazione +AboutSetupMessage=%1 versione %2%n%3%n%n%1 sito web:%n%4 +AboutSetupNote= +TranslatorNote=Traduzione italiana a cura di Rinaldo M. aka Whiteshark e bovirus (v. 11.09.2018) + +; *** Buttons +ButtonBack=< &Indietro +ButtonNext=&Avanti > +ButtonInstall=Inst&alla +ButtonOK=OK +ButtonCancel=Annulla +ButtonYes=&Si +ButtonYesToAll=Sì a &tutto +ButtonNo=&No +ButtonNoToAll=N&o a tutto +ButtonFinish=&Fine +ButtonBrowse=&Sfoglia... +ButtonWizardBrowse=S&foglia... +ButtonNewFolder=&Crea nuova cartella + +; *** "Select Language" dialog messages +SelectLanguageTitle=Seleziona la lingua dell'installazione +SelectLanguageLabel=Seleziona la lingua da usare durante l'installazione. + +; *** Common wizard text +ClickNext=Seleziona "Avanti" per continuare, o "Annulla" per uscire. +BeveledLabel= +BrowseDialogTitle=Sfoglia cartelle +BrowseDialogLabel=Seleziona una cartella nell'elenco, e quindi seleziona "OK". +NewFolderName=Nuova cartella + +; *** "Welcome" wizard page +WelcomeLabel1=Installazione di [name] +WelcomeLabel2=[name/ver] sarà installato sul computer.%n%nPrima di procedere chiudi tutte le applicazioni attive. + +; *** "Password" wizard page +WizardPassword=Password +PasswordLabel1=Questa installazione è protetta da password. +PasswordLabel3=Inserisci la password, quindi per continuare seleziona "Avanti".%nLe password sono sensibili alle maiuscole/minuscole. +PasswordEditLabel=&Password: +IncorrectPassword=La password inserita non è corretta. Riprova. + +; *** "License Agreement" wizard page +WizardLicense=Contratto di licenza +LicenseLabel=Prima di procedere leggi con attenzione le informazioni che seguono. +LicenseLabel3=Leggi il seguente contratto di licenza.%nPer procedere con l'installazione è necessario accettare tutti i termini del contratto. +LicenseAccepted=Accetto i termini del &contratto di licenza +LicenseNotAccepted=&Non accetto i termini del contratto di licenza + +; *** "Information" wizard pages +WizardInfoBefore=Informazioni +InfoBeforeLabel=Prima di procedere leggi le importanti informazioni che seguono. +InfoBeforeClickLabel=Quando sei pronto per proseguire, seleziona "Avanti". +WizardInfoAfter=Informazioni +InfoAfterLabel=Prima di procedere leggi le importanti informazioni che seguono. +InfoAfterClickLabel=Quando sei pronto per proseguire, seleziona "Avanti". + +; *** "User Information" wizard page +WizardUserInfo=Informazioni utente +UserInfoDesc=Inserisci le seguenti informazioni. +UserInfoName=&Nome: +UserInfoOrg=&Società: +UserInfoSerial=&Numero di serie: +UserInfoNameRequired=È necessario inserire un nome. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Selezione cartella di installazione +SelectDirDesc=Dove vuoi installare [name]? +SelectDirLabel3=[name] sarà installato nella seguente cartella. +SelectDirBrowseLabel=Per continuare seleziona "Avanti".%nPer scegliere un'altra cartella seleziona "Sfoglia". +DiskSpaceGBLabel=Sono richiesti almeno [gb] GB di spazio libero nel disco. +DiskSpaceMBLabel=Sono richiesti almeno [mb] MB di spazio libero nel disco. +CannotInstallToNetworkDrive=Non è possibile effettuare l'installazione in un disco in rete. +CannotInstallToUNCPath=Non è possibile effettuare l'installazione in un percorso UNC. +InvalidPath=Va inserito un percorso completo di lettera di unità; per esempio:%n%nC:\APP%n%no un percorso di rete nella forma:%n%n\\server\condivisione +InvalidDrive=L'unità o il percorso di rete selezionato non esiste o non è accessibile.%n%nSelezionane un altro. +DiskSpaceWarningTitle=Spazio su disco insufficiente +DiskSpaceWarning=L'installazione richiede per eseguire l'installazione almeno %1 KB di spazio libero, ma l'unità selezionata ha solo %2 KB disponibili.%n%nVuoi continuare comunque? +DirNameTooLong=Il nome della cartella o il percorso sono troppo lunghi. +InvalidDirName=Il nome della cartella non è valido. +BadDirName32=Il nome della cartella non può includere nessuno dei seguenti caratteri:%n%n%1 +DirExistsTitle=Cartella già esistente +DirExists=La cartella%n%n %1%n%nesiste già.%n%nVuoi comunque installare l'applicazione in questa cartella? +DirDoesntExistTitle=Cartella inesistente +DirDoesntExist=La cartella%n%n %1%n%nnon esiste. Vuoi creare la cartella? + +; *** "Select Components" wizard page +WizardSelectComponents=Selezione componenti +SelectComponentsDesc=Quali componenti vuoi installare? +SelectComponentsLabel2=Seleziona i componenti da installare, deseleziona quelli che non vuoi installare.%nPer continuare seleziona "Avanti". +FullInstallation=Installazione completa +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Installazione compatta +CustomInstallation=Installazione personalizzata +NoUninstallWarningTitle=Componente esistente +NoUninstallWarning=I seguenti componenti sono già installati nel computer:%n%n%1%n%nDeselezionando questi componenti essi non verranno rimossi.%n%nVuoi continuare comunque? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=La selezione attuale richiede almeno [gb] GB di spazio nel disco. +ComponentsDiskSpaceMBLabel=La selezione attuale richiede almeno [mb] MB di spazio nel disco. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Selezione processi aggiuntivi +SelectTasksDesc=Quali processi aggiuntivi vuoi eseguire? +SelectTasksLabel2=Seleziona i processi aggiuntivi che verranno eseguiti durante l'installazione di [name], quindi seleziona "Avanti". + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Selezione della cartella nel menu Avvio/Start +SelectStartMenuFolderDesc=Dove vuoi inserire i collegamenti al programma? +SelectStartMenuFolderLabel3=Verranno creati i collegamenti al programma nella seguente cartella del menu Avvio/Start. +SelectStartMenuFolderBrowseLabel=Per continuare, seleziona "Avanti".%nPer selezionare un'altra cartella, seleziona "Sfoglia". +MustEnterGroupName=Devi inserire il nome della cartella. +GroupNameTooLong=Il nome della cartella o il percorso sono troppo lunghi. +InvalidGroupName=Il nome della cartella non è valido. +BadGroupName=Il nome della cartella non può includere nessuno dei seguenti caratteri:%n%n%1 +NoProgramGroupCheck2=&Non creare una cartella nel menu Avvio/Start + +; *** "Ready to Install" wizard page +WizardReady=Pronto per l'installazione +ReadyLabel1=Il programma è pronto per iniziare l'installazione di [name] nel computer. +ReadyLabel2a=Seleziona "Installa" per continuare con l'installazione, o "Indietro" per rivedere o modificare le impostazioni. +ReadyLabel2b=Per procedere con l'installazione seleziona "Installa". +ReadyMemoUserInfo=Informazioni utente: +ReadyMemoDir=Cartella di installazione: +ReadyMemoType=Tipo di installazione: +ReadyMemoComponents=Componenti selezionati: +ReadyMemoGroup=Cartella del menu Avvio/Start: +ReadyMemoTasks=Processi aggiuntivi: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Download file aggiuntivi... +ButtonStopDownload=&Stop download +StopDownload=Sei sicuro di voler interrompere il download? +ErrorDownloadAborted=Download annullato +ErrorDownloadFailed=Download fallito: %1 %2 +ErrorDownloadSizeFailed=Rilevamento dimensione fallito: %1 %2 +ErrorFileHash1=Errore hash file: %1 +ErrorFileHash2=Hash file non valido: atteso %1, trovato %2 +ErrorProgress=Progresso non valido: %1 di %2 +ErrorFileSize=Dimensione file non valida: attesa %1, trovata %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Preparazione all'installazione +PreparingDesc=Preparazione all'installazione di [name] nel computer. +PreviousInstallNotCompleted=L'installazione/rimozione precedente del programma non è stata completata.%n%nÈ necessario riavviare il sistema per completare l'installazione.%n%nDopo il riavvio del sistema esegui di nuovo l'installazione di [name]. +CannotContinue=L'installazione non può continuare. Seleziona "Annulla" per uscire. +ApplicationsFound=Le seguenti applicazioni stanno usando file che devono essere aggiornati dall'installazione.%n%nTi consigliamo di permettere al processo di chiudere automaticamente queste applicazioni. +ApplicationsFound2=Le seguenti applicazioni stanno usando file che devono essere aggiornati dall'installazione.%n%nTi consigliamo di permettere al processo di chiudere automaticamente queste applicazioni.%n%nAl completamento dell'installazione, il processo tenterà di riavviare le applicazioni. +CloseApplications=Chiudi &automaticamente le applicazioni +DontCloseApplications=&Non chiudere le applicazioni +ErrorCloseApplications=L'installazione non è riuscita a chiudere automaticamente tutte le applicazioni.%n%nPrima di proseguire ti raccomandiamo di chiudere tutte le applicazioni che usano file che devono essere aggiornati durante l'installazione. +PrepareToInstallNeedsRestart=Il programma di installazione deve riavviare il computer.%nDopo aver riavviato il computer esegui di nuovo il programma di installazione per completare l'installazione di [name].%n%nVuoi riavviare il computer ora? + +; *** "Installing" wizard page +WizardInstalling=Installazione in corso +InstallingLabel=Attendi il completamento dell'installazione di [name] nel computer. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Installazione di [name] completata +FinishedLabelNoIcons=Installazione di [name] completata. +FinishedLabel=Installazione di [name] completata.%n%nL'applicazione può essere eseguita selezionando le relative icone. +ClickFinish=Seleziona "Fine" per uscire dall'installazione. +FinishedRestartLabel=Per completare l'installazione di [name], è necessario riavviare il sistema.%n%nVuoi riavviare adesso? +FinishedRestartMessage=Per completare l'installazione di [name], è necessario riavviare il sistema.%n%nVuoi riavviare adesso? +ShowReadmeCheck=Si, visualizza ora il file LEGGIMI +YesRadio=&Si, riavvia il sistema adesso +NoRadio=&No, riavvia il sistema più tardi +; used for example as 'Run MyProg.exe' +RunEntryExec=Esegui %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Visualizza %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=L'installazione necessita del disco successivo +SelectDiskLabel2=Inserisci il disco %1 e seleziona "OK".%n%nSe i file di questo disco si trovano in una cartella diversa da quella visualizzata sotto, inserisci il percorso corretto o seleziona "Sfoglia". +PathLabel=&Percorso: +FileNotInDir2=Il file "%1" non è stato trovato in "%2".%n%nInserisci il disco corretto o seleziona un'altra cartella. +SelectDirectoryLabel=Specifica il percorso del prossimo disco. + +; *** Installation phase messages +SetupAborted=L'installazione non è stata completata.%n%nCorreggi il problema e riesegui nuovamente l'installazione. +AbortRetryIgnoreSelectAction=Seleziona azione +AbortRetryIgnoreRetry=&Riprova +AbortRetryIgnoreIgnore=&Ignora questo errore e continua +AbortRetryIgnoreCancel=Annulla installazione + +; *** Installation status messages +StatusClosingApplications=Chiusura applicazioni... +StatusCreateDirs=Creazione cartelle... +StatusExtractFiles=Estrazione file... +StatusCreateIcons=Creazione icone... +StatusCreateIniEntries=Creazione voci nei file INI... +StatusCreateRegistryEntries=Creazione voci di registro... +StatusRegisterFiles=Registrazione file... +StatusSavingUninstall=Salvataggio delle informazioni di disinstallazione... +StatusRunProgram=Termine dell'installazione... +StatusRestartingApplications=Riavvio applicazioni... +StatusRollback=Recupero delle modifiche... + +; *** Misc. errors +ErrorInternal2=Errore interno %1 +ErrorFunctionFailedNoCode=%1 fallito +ErrorFunctionFailed=%1 fallito; codice %2 +ErrorFunctionFailedWithMessage=%1 fallito; codice %2.%n%3 +ErrorExecutingProgram=Impossibile eseguire il file:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Errore di apertura della chiave di registro:%n%1\%2 +ErrorRegCreateKey=Errore di creazione della chiave di registro:%n%1\%2 +ErrorRegWriteKey=Errore di scrittura della chiave di registro:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Errore nella creazione delle voci INI nel file "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Salta questo file (non suggerito) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignora questo errore e continua (non suggerito) +SourceIsCorrupted=Il file sorgente è danneggiato +SourceDoesntExist=Il file sorgente "%1" non esiste +ExistingFileReadOnly2=Il file esistente non può essere sostituito in quanto segnato come in sola lettura. +ExistingFileReadOnlyRetry=&Rimuovi attributo di sola lettura e riprova +ExistingFileReadOnlyKeepExisting=&Mantieni il file esistente +ErrorReadingExistingDest=Si è verificato un errore durante la lettura del file esistente: +FileExistsSelectAction=Seleziona azione +FileExists2=Il file esiste già. +FileExistsOverwriteExisting=S&ovrascrivi il file esistente +FileExistsKeepExisting=&Mantieni il file esistente +FileExistsOverwriteOrKeepAll=&Applica questa azione per i prossimi conflitti +ExistingFileNewerSelectAction=Seleziona azione +ExistingFileNewer2=Il file esistente è più recente del file che si sta cercando di installare. +ExistingFileNewerOverwriteExisting=S&ovrascrivi il file esistente +ExistingFileNewerKeepExisting=&Mantieni il file esistente (suggerito) +ExistingFileNewerOverwriteOrKeepAll=&Applica questa azione per i prossimi conflitti +ErrorChangingAttr=Si è verificato un errore durante il tentativo di modifica dell'attributo del file esistente: +ErrorCreatingTemp=Si è verificato un errore durante la creazione di un file nella cartella di installazione: +ErrorReadingSource=Si è verificato un errore durante la lettura del file sorgente: +ErrorCopying=Si è verificato un errore durante la copia di un file: +ErrorReplacingExistingFile=Si è verificato un errore durante la sovrascrittura del file esistente: +ErrorRestartReplace=Errore durante riavvio o sostituzione: +ErrorRenamingTemp=Si è verificato un errore durante il tentativo di rinominare un file nella cartella di installazione: +ErrorRegisterServer=Impossibile registrare la DLL/OCX: %1 +ErrorRegSvr32Failed=RegSvr32 è fallito con codice di uscita %1 +ErrorRegisterTypeLib=Impossibile registrare la libreria di tipo: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32bit +UninstallDisplayNameMark64Bit=64bit +UninstallDisplayNameMarkAllUsers=Tutti gli utenti +UninstallDisplayNameMarkCurrentUser=Utente attuale + +; *** Post-installation errors +ErrorOpeningReadme=Si è verificato un errore durante l'apertura del file LEGGIMI. +ErrorRestartingComputer=Impossibile riavviare il sistema. Riavvia il sistema manualmente. + +; *** Uninstaller messages +UninstallNotFound=Il file "%1" non esiste.%n%nImpossibile disinstallare. +UninstallOpenError=Il file "%1" non può essere aperto.%n%nImpossibile disinstallare +UninstallUnsupportedVer=Il file registro di disinstallazione "%1" è in un formato non riconosciuto da questa versione del programma di disinstallazione.%n%nImpossibile disinstallare +UninstallUnknownEntry=Trovata una voce sconosciuta (%1) nel file registro di disinstallazione +ConfirmUninstall=Vuoi rimuovere completamente %1 e tutti i suoi componenti? +UninstallOnlyOnWin64=Questa applicazione può essere disinstallata solo in Windows a 64-bit. +OnlyAdminCanUninstall=Questa applicazione può essere disinstallata solo da un utente con privilegi di amministratore. +UninstallStatusLabel=Attendi fino a che %1 è stato rimosso dal computer. +UninstalledAll=Disinstallazione di %1 completata. +UninstalledMost=Disinstallazione di %1 completata.%n%nAlcuni elementi non possono essere rimossi.%n%nDovranno essere rimossi manualmente. +UninstalledAndNeedsRestart=Per completare la disinstallazione di %1, è necessario riavviare il sistema.%n%nVuoi riavviare il sistema adesso? +UninstallDataCorrupted=Il file "%1" è danneggiato. Impossibile disinstallare + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Vuoi rimuovere il file condiviso? +ConfirmDeleteSharedFile2=Il sistema indica che il seguente file condiviso non è più usato da nessun programma.%nVuoi rimuovere questo file condiviso?%nSe qualche programma usasse questo file, potrebbe non funzionare più correttamente.%nSe non sei sicuro, seleziona "No".%nLasciare il file nel sistema non può causare danni. +SharedFileNameLabel=Nome del file: +SharedFileLocationLabel=Percorso: +WizardUninstalling=Stato disinstallazione +StatusUninstalling=Disinstallazione di %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Installazione di %1. +ShutdownBlockReasonUninstallingApp=Disinstallazione di %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 versione %2 +AdditionalIcons=Icone aggiuntive: +CreateDesktopIcon=Crea un'icona sul &desktop +CreateQuickLaunchIcon=Crea un'icona nella &barra 'Avvio veloce' +ProgramOnTheWeb=Sito web di %1 +UninstallProgram=Disinstalla %1 +LaunchProgram=Avvia %1 +AssocFileExtension=&Associa i file con estensione %2 a %1 +AssocingFileExtension=Associazione dei file con estensione %2 a %1... +AutoStartProgramGroupDescription=Esecuzione automatica: +AutoStartProgram=Esegui automaticamente %1 +AddonHostProgramNotFound=Impossibile individuare %1 nella cartella selezionata.%n%nVuoi continuare ugualmente? diff --git a/installer/innosetup/Languages/Japanese.isl b/installer/innosetup/Languages/Japanese.isl new file mode 100644 index 000000000..a1c150ae6 --- /dev/null +++ b/installer/innosetup/Languages/Japanese.isl @@ -0,0 +1,367 @@ +; *** Inno Setup version 6.1.0+ Japanese messages *** +; +; Maintained by Koichi Shirasuka (shirasuka@eugrid.co.jp) +; +; Translation based on Ryou Minakami (ryou32jp@yahoo.co.jp) +; +; $jrsoftware: issrc/Files/Languages/Japanese.isl,v 1.6 2010/03/08 07:50:01 mlaan Exp $ + +[LangOptions] +LanguageName=<65E5><672C><8A9E> +LanguageID=$0411 +LanguageCodePage=932 + +[Messages] + +; *** Application titles +SetupAppTitle=ZbgAbv +SetupWindowTitle=%1 ZbgAbv +UninstallAppTitle=ACXg[ +UninstallAppFullTitle=%1 ACXg[ + +; *** Misc. common +InformationTitle= +ConfirmTitle=mF +ErrorTitle=G[ + +; *** SetupLdr messages +SetupLdrStartupMessage=%1 CXg[܂Bs܂H +LdrCannotCreateTemp=ꎞt@C쐬ł܂BZbgAbv𒆎~܂B +LdrCannotExecTemp=ꎞtH_[̃t@Csł܂BZbgAbv𒆎~܂B + +; *** Startup error messages +LastErrorMessage=%1.%n%nG[ %2: %3 +SetupFileMissing=t@C %1 ‚܂B邩VZbgAbvvO肵ĂB +SetupFileCorrupt=ZbgAbvt@CĂ܂BVZbgAbvvO肵ĂB +SetupFileCorruptOrWrongVer=ZbgAbvt@CĂ邩Ão[W̃ZbgAbvƌ݊܂B邩VZbgAbvvO肵ĂB +InvalidParameter=R}hCɕsȃp[^[n܂:%n%n%1 +SetupAlreadyRunning=ZbgAbv͊ɎsłB +WindowsVersionNotSupported=̃vO͂g̃o[W Windows T|[gĂ܂B +WindowsServicePackRequired=̃vO̎sɂ %1 Service Pack %2 ȍ~KvłB +NotOnThisPlatform=̃vO %1 ł͓삵܂B +OnlyOnThisPlatform=̃vO̎sɂ %1 KvłB +OnlyOnTheseArchitectures=̃vO%n%n%1vZbT[ Windows ɂCXg[ł܂B +WinVersionTooLowError=̃vO̎sɂ %1 %2 ȍ~KvłB +WinVersionTooHighError=̃vO %1 %2 ȍ~ł͓삵܂B +AdminPrivilegesRequired=̃vOCXg[邽߂ɂ͊Ǘ҂ƂăOCKv܂B +PowerUserPrivilegesRequired=̃vOCXg[邽߂ɂ͊Ǘ҂܂̓p[[U[ƂăOCKv܂B +SetupAppRunningError=ZbgAbv͎s %1 o܂B%n%nJĂAvP[Vׂĕ‚ĂuOKvNbNĂBuLZvNbNƁAZbgAbvI܂B +UninstallAppRunningError=ACXg[͎s %1 o܂B%n%nJĂAvP[Vׂĕ‚ĂuOKvNbNĂBuLZvNbNƁAZbgAbvI܂B + +; *** Startup questions +PrivilegesRequiredOverrideTitle=CXg[[h̑I +PrivilegesRequiredOverrideInstruction=CXg[[hIĂ +PrivilegesRequiredOverrideText1=%1 ׂ͂Ẵ[U[ (ǗҌKvł) ܂݂͌̃[U[pɃCXg[ł܂B +PrivilegesRequiredOverrideText2=%1 ݂͌̃[U[܂ׂ͂Ẵ[U[p (ǗҌKvł) ɃCXg[ł܂B +PrivilegesRequiredOverrideAllUsers=ׂẴ[U[pɃCXg[(&A) +PrivilegesRequiredOverrideAllUsersRecommended=ׂẴ[U[pɃCXg[(&A) () +PrivilegesRequiredOverrideCurrentUser=݂̃[U[pɃCXg[(&M) +PrivilegesRequiredOverrideCurrentUserRecommended=݂̃[U[pɃCXg[(&M) () + +; *** Misc. errors +ErrorCreatingDir=fBNg %1 쐬ɃG[܂B +ErrorTooManyFilesInDir=fBNg %1 Ƀt@C쐬ɃG[܂Bt@C̐܂B + +; *** Setup common messages +ExitSetupTitle=ZbgAbvI +ExitSetupMessage=ZbgAbvƂ͊Ă܂BŃZbgAbv𒆎~ƃvO̓CXg[܂B%n%n߂ăCXg[ꍇ́AxZbgAbvsĂB%n%nZbgAbvI܂H +AboutSetupMenuItem=ZbgAbvɂ‚(&A)... +AboutSetupTitle=ZbgAbvɂ‚ +AboutSetupMessage=%1 %2%n%3%n%n%1 z[y[W:%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< ߂(&B) +ButtonNext=(&N) > +ButtonInstall=CXg[(&I) +ButtonOK=OK +ButtonCancel=LZ +ButtonYes=͂(&Y) +ButtonYesToAll=ׂĂ͂(&A) +ButtonNo=(&N) +ButtonNoToAll=ׂĂ(&O) +ButtonFinish=(&F) +ButtonBrowse=Q(&B)... +ButtonWizardBrowse=Q(&R) +ButtonNewFolder=VtH_[(&M) + +; *** "Select Language" dialog messages +SelectLanguageTitle=ZbgAbvɎgp錾̑I +SelectLanguageLabel=CXg[ɗp錾IłB + +; *** Common wizard text +ClickNext=sɂ́uցvAZbgAbvIɂ́uLZvNbNĂB +BeveledLabel= +BrowseDialogTitle=tH_[Q +BrowseDialogLabel=XgtH_[I OK ĂB +NewFolderName=VtH_[ + +; *** "Welcome" wizard page +WelcomeLabel1=[name] ZbgAbvEBU[h̊Jn +WelcomeLabel2=̃vO͂gp̃Rs[^[ [name/ver] CXg[܂B%n%nsOɑ̃AvP[VׂďIĂB + +; *** "Password" wizard page +WizardPassword=pX[h +PasswordLabel1=̃CXg[vO̓pX[hɂĕی삳Ă܂B +PasswordLabel3=pX[h͂āuցvNbNĂBpX[h͑啶Əʂ܂B +PasswordEditLabel=pX[h(&P): +IncorrectPassword=͂ꂽpX[h܂Bx͂ȂĂB + +; *** "License Agreement" wizard page +WizardLicense=gp_񏑂̓ +LicenseLabel=sOɈȉ̏dvȏǂ݂B +LicenseLabel3=ȉ̎gp_񏑂ǂ݂BCXg[𑱍sɂ͂̌_񏑂ɓӂKv܂B +LicenseAccepted=ӂ(&A) +LicenseNotAccepted=ӂȂ(&D) + +; *** "Information" wizard pages +WizardInfoBefore= +InfoBeforeLabel=sOɈȉ̏dvȏǂ݂B +InfoBeforeClickLabel=ZbgAbv𑱍sɂ́uցvNbNĂB +WizardInfoAfter= +InfoAfterLabel=sOɈȉ̏dvȏǂ݂B +InfoAfterClickLabel=ZbgAbv𑱍sɂ́uցvNbNĂB + +; *** "User Information" wizard page +WizardUserInfo=[U[ +UserInfoDesc=[U[͂ĂB +UserInfoName=[U[(&U): +UserInfoOrg=gD(&O): +UserInfoSerial=VAԍ(&S): +UserInfoNameRequired=[U[͂ĂB + +; *** "Select Destination Location" wizard page +WizardSelectDir=CXg[̎w +SelectDirDesc=[name] ̃CXg[w肵ĂB +SelectDirLabel3=[name] CXg[tH_w肵āAuցvNbNĂB +SelectDirBrowseLabel=ɂ́uցvNbNĂBʂ̃tH_[Iɂ́uQƁvNbNĂB +DiskSpaceGBLabel=̃vO͍Œ [gb] GB ̃fBXN󂫗̈KvƂ܂B +DiskSpaceMBLabel=̃vO͍Œ [mb] MB ̃fBXN󂫗̈KvƂ܂B +CannotInstallToNetworkDrive=lbg[NhCuɃCXg[邱Ƃ͂ł܂B +CannotInstallToUNCPath=UNC pXɃCXg[邱Ƃ͂ł܂B +InvalidPath=hCu܂ފSȃpX͂ĂB%n%nFC:\APP%n%n܂ UNC `̃pX͂ĂB%n%nF\\server\share +InvalidDrive=w肵hCu܂ UNC pX‚ȂANZXł܂Bʂ̃pXw肵ĂB +DiskSpaceWarningTitle=fBXN󂫗̈̕s +DiskSpaceWarning=CXg[ɂ͍Œ %1 KB ̃fBXN󂫗̈悪KvłAw肳ꂽhCuɂ %2 KB ̋󂫗̈悵܂B%n%n̂܂ܑs܂H +DirNameTooLong=hCu܂̓pX߂܂B +InvalidDirName=tH_[łB +BadDirName32=ȉ̕܂ރtH_[͎wł܂B:%n%n%1 +DirExistsTitle=̃tH_[ +DirExists=tH_[ %n%n%1%n%nɑ݂܂B̂܂܂̃tH_[փCXg[܂H +DirDoesntExistTitle=tH_[‚܂B +DirDoesntExist=tH_[ %n%n%1%n%n‚܂BVtH_[쐬܂H + +; *** "Select Components" wizard page +WizardSelectComponents=R|[lg̑I +SelectComponentsDesc=CXg[R|[lgIĂB +SelectComponentsLabel2=CXg[R|[lgIĂBCXg[Kv̂ȂR|[lg̓`FbNOĂBsɂ́uցvNbNĂB +FullInstallation=tCXg[ +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=RpNgCXg[ +CustomInstallation=JX^CXg[ +NoUninstallWarningTitle=̃R|[lg +NoUninstallWarning=ZbgAbv͈ȉ̃R|[lgɃCXg[Ă邱Ƃo܂B%n%n%1%n%ñR|[lg̑IĂACXg[͂܂B%n%n̂܂ܑs܂H +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=݂̑I͍Œ [gb] GB ̃fBXN󂫗̈KvƂ܂B +ComponentsDiskSpaceMBLabel=݂̑I͍Œ [mb] MB ̃fBXN󂫗̈KvƂ܂B + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=lj^XN̑I +SelectTasksDesc=slj^XNIĂB +SelectTasksLabel2=[name] CXg[Ɏslj^XNIāAuցvNbNĂB + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=X^[gj[tH_[̎w +SelectStartMenuFolderDesc=vÕV[gJbg쐬ꏊw肵ĂB +SelectStartMenuFolderLabel3=ZbgAbṽ͎X^[gj[tH_[ɃvÕV[gJbg쐬܂B +SelectStartMenuFolderBrowseLabel=ɂ́uցvNbNĂBႤtH_[Iɂ́uQƁvNbNĂB +MustEnterGroupName=tH_[w肵ĂB +GroupNameTooLong=tH_[܂̓pX߂܂B +InvalidGroupName=tH_[łB +BadGroupName=̕܂ރtH_[͎wł܂:%n%n%1 +NoProgramGroupCheck2=X^[gj[tH_[쐬Ȃ(&D) + +; *** "Ready to Install" wizard page +WizardReady=CXg[ +ReadyLabel1=gp̃Rs[^ [name] CXg[鏀ł܂B +ReadyLabel2a=CXg[𑱍sɂ́uCXg[vAݒ̊mFύXsɂ́u߂vNbNĂB +ReadyLabel2b=CXg[𑱍sɂ́uCXg[vNbNĂB +ReadyMemoUserInfo=[U[: +ReadyMemoDir=CXg[: +ReadyMemoType=ZbgAbv̎: +ReadyMemoComponents=IR|[lg: +ReadyMemoGroup=X^[gj[tH_[: +ReadyMemoTasks=lj^XNꗗ: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=lj̃t@C_E[hĂ܂... +ButtonStopDownload=_E[h𒆎~(&S) +StopDownload=_E[h𒆎~Ă낵łH +ErrorDownloadAborted=_E[h𒆎~܂ +ErrorDownloadFailed=_E[hɎs܂: %1 %2 +ErrorDownloadSizeFailed=TCY̎擾Ɏs܂: %1 %2 +ErrorFileHash1=t@C̃nbVɎs܂: %1 +ErrorFileHash2=ȃt@CnbV: \ꂽl %1, ۂ̒l %2 +ErrorProgress=Ȑis: %1 / %2 +ErrorFileSize=ȃt@CTCY: \ꂽl %1, ۂ̒l %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=CXg[ +PreparingDesc=gp̃Rs[^[ [name] CXg[鏀Ă܂B +PreviousInstallNotCompleted=OsAvP[ṼCXg[܂͍폜Ă܂Bɂ̓Rs[^[ċNKv܂B%n%n[name] ̃CXg[邽߂ɂ́AċNɂxZbgAbvsĂB +CannotContinue=ZbgAbv𑱍sł܂BuLZvNbNăZbgAbvIĂB +ApplicationsFound=ȉ̃AvP[VZbgAbvɕKvȃt@CgpĂ܂BZbgAbvɎIɃAvP[VI邱Ƃ𐄏܂B +ApplicationsFound2=ȉ̃AvP[VZbgAbvɕKvȃt@CgpĂ܂BZbgAbvɎIɃAvP[VI邱Ƃ𐄏܂BCXg[̊AZbgAbv̓AvP[V̍ċN݂܂B +CloseApplications=IɃAvP[VI(&A) +DontCloseApplications=AvP[VIȂ(&D) +ErrorCloseApplications=ZbgAbvׂ͂ẴAvP[VIɏI邱Ƃł܂łBZbgAbv𑱍sOɁAXV̕Kvȃt@CgpĂ邷ׂẴAvP[VI邱Ƃ𐄏܂B +PrepareToInstallNeedsRestart=ZbgAbv̓Rs[^[ċNKv܂BRs[^[ċNAZbgAbvēxs [name] ̃CXg[ĂB%n%nɍċN܂H? + +; *** "Installing" wizard page +WizardInstalling=CXg[ +InstallingLabel=gp̃Rs[^[ [name] CXg[Ă܂B΂炭҂B + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name] ZbgAbvEBU[h̊ +FinishedLabelNoIcons=gp̃Rs[^[ [name] ZbgAbv܂B +FinishedLabel=gp̃Rs[^[ [name] ZbgAbv܂BAvP[Vsɂ̓CXg[ꂽV[gJbgIĂB +ClickFinish=ZbgAbvIɂ́uvNbNĂB +FinishedRestartLabel=[name] ̃CXg[邽߂ɂ́ARs[^[ċNKv܂BɍċN܂H +FinishedRestartMessage=[name] ̃CXg[邽߂ɂ́ARs[^[ċNKv܂B%n%nɍċN܂H +ShowReadmeCheck=README t@C\B +YesRadio=ɍċN(&Y) +NoRadio=Ŏ蓮ōċN(&N) +; used for example as 'Run MyProg.exe' +RunEntryExec=%1 ̎s +; used for example as 'View Readme.txt' +RunEntryShellExec=%1 ̕\ + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=fBXN̑} +SelectDiskLabel2=fBXN %1 }AuOKvNbNĂB%n%ñfBXÑt@Cɕ\ĂtH_[ȊȌꏊɂꍇ́ApX͂邩uQƁv{^NbNĂB +PathLabel=pX(&P): +FileNotInDir2=t@C %1 %2 Ɍ‚܂BfBXN}邩Aʂ̃tH_[w肵ĂB +SelectDirectoryLabel=̃fBXN̂ꏊw肵ĂB + +; *** Installation phase messages +SetupAborted=ZbgAbv͊Ă܂B%n%nĂAxZbgAbvsĂB +AbortRetryIgnoreSelectAction=ANVIĂ +AbortRetryIgnoreRetry=Ďs(&T) +AbortRetryIgnoreIgnore=G[𖳎đs(&I) +AbortRetryIgnoreCancel=CXg[LZ + +; *** Installation status messages +StatusClosingApplications=AvP[VIĂ܂... +StatusCreateDirs=tH_[쐬Ă܂... +StatusExtractFiles=t@CWJĂ܂... +StatusCreateIcons=V|gJbg쐬Ă܂... +StatusCreateIniEntries=INIt@Cݒ肵Ă܂... +StatusCreateRegistryEntries=WXgݒ肵Ă܂... +StatusRegisterFiles=t@Co^Ă܂... +StatusSavingUninstall=ACXg[ۑĂ܂... +StatusRunProgram=CXg[Ă܂... +StatusRestartingApplications=AvP[VċNĂ܂... +StatusRollback=ύXɖ߂Ă܂... + +; *** Misc. errors +ErrorInternal2=G[: %1 +ErrorFunctionFailedNoCode=%1 G[ +ErrorFunctionFailed=%1 G[: R[h %2 +ErrorFunctionFailedWithMessage=%1 G[: R[h %2.%n%3 +ErrorExecutingProgram=t@CsG[:%n%1 + +; *** Registry errors +ErrorRegOpenKey=WXgL[I[vG[:%n%1\%2 +ErrorRegCreateKey=WXgL[쐬G[:%n%1\%2 +ErrorRegWriteKey=WXgL[݃G[:%n%1\%2 + +; *** INI errors +ErrorIniEntry=INIt@CGg쐬G[: t@C %1 + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=̃t@CXLbv(&S) (܂) +FileAbortRetryIgnoreIgnoreNotRecommended=G[𖳎đs(&I) (܂) +SourceIsCorrupted=Rs[̃t@CĂ܂B +SourceDoesntExist=Rs[̃t@C %1 ‚܂B +ExistingFileReadOnly2=̃t@C͓ǂݎp̂ߒuł܂B +ExistingFileReadOnlyRetry=ǂݎpĂxȂ(&R) +ExistingFileReadOnlyKeepExisting=̃t@Cc(&K) +ErrorReadingExistingDest=̃t@CǂݍݒɃG[܂: +FileExistsSelectAction=ANVIĂ +FileExists2=t@C͊ɑ݂܂B +FileExistsOverwriteExisting=̃t@C㏑(&O) +FileExistsKeepExisting=̃t@Cێ(&K) +FileExistsOverwriteOrKeepAll=ȍ~̋ɓs(&D) +ExistingFileNewerSelectAction=ANVIĂ +ExistingFileNewer2=ZbgAbvCXg[悤ƂĂ̂Vt@C܂B +ExistingFileNewerOverwriteExisting=̃t@C㏑(&O) +ExistingFileNewerKeepExisting=̃t@Cێ(&K) () +ExistingFileNewerOverwriteOrKeepAll=ȍ~̋ɓs(&D) +ErrorChangingAttr=t@C̑ύXɃG[܂: +ErrorCreatingTemp=Rs[̃tH_[Ƀt@C쐬ɃG[܂: +ErrorReadingSource=Rs[̃t@CǂݍݒɃG[܂: +ErrorCopying=t@CRs[ɃG[܂: +ErrorReplacingExistingFile=̃t@CuɃG[܂: +ErrorRestartReplace=ċNɂu̎sɎs܂: +ErrorRenamingTemp=Rs[tH_[̃t@CύXɃG[܂: +ErrorRegisterServer=DLL/OCX̓o^Ɏs܂: %1 +ErrorRegSvr32Failed=RegSvr32͏IR[h %1 ɂ莸s܂ +ErrorRegisterTypeLib=^CvCuւ̓o^Ɏs܂: %1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32 rbg +UninstallDisplayNameMark64Bit=64 rbg +UninstallDisplayNameMarkAllUsers=ׂẴ[U[ +UninstallDisplayNameMarkCurrentUser=݂̃[U[ + +; *** Post-installation errors +ErrorOpeningReadme=README t@C̃I[vɎs܂B +ErrorRestartingComputer=Rs[^[̍ċNɎs܂B蓮ōċNĂB + +; *** Uninstaller messages +UninstallNotFound=t@C "%1" ‚܂BACXg[sł܂B +UninstallOpenError=t@C "%1" JƂł܂BACXg[sł܂B +UninstallUnsupportedVer=ACXg[Ot@C "%1" ́Ão[W̃ACXg[vOFłȂ`łBACXg[sł܂B +UninstallUnknownEntry=ACXg[Oɕs̃Gg (%1) ‚܂B +ConfirmUninstall=%1 Ƃ̊֘AR|[lgׂč폜܂B낵łH +UninstallOnlyOnWin64=̃vO64 rbgWindowsł̂݃ACXg[邱Ƃł܂B +OnlyAdminCanUninstall=ACXg[邽߂ɂ͊ǗҌKvłB +UninstallStatusLabel=gp̃Rs[^[ %1 폜Ă܂B΂炭҂B +UninstalledAll=%1 ͂gp̃Rs[^[琳ɍ폜܂B +UninstalledMost=%1 ̃ACXg[܂B%n%n‚̍ڂ폜ł܂łB蓮ō폜ĂB +UninstalledAndNeedsRestart=%1 ̍폜邽߂ɂ́ARs[^[ċNKv܂BɍċN܂H +UninstallDataCorrupted=t@C "%1" Ă܂BACXg[sł܂B + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Lt@C̍폜 +ConfirmDeleteSharedFile2=VXeŁA̋Lt@C͂ǂ̃vOłgpĂ܂B̋Lt@C폜܂H%n%ñvO܂̃t@CgpꍇA폜ƃvO삵ȂȂ鋰ꂪ܂B܂młȂꍇ́uvIĂBVXeɃt@CcĂNƂ͂܂B +SharedFileNameLabel=t@C: +SharedFileLocationLabel=ꏊ: +WizardUninstalling=ACXg[ +StatusUninstalling=%1 ACXg[Ă܂... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=%1 CXg[łB +ShutdownBlockReasonUninstallingApp=%1 ACXg[łB + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 o[W %2 +AdditionalIcons=ACRlj: +CreateDesktopIcon=fXNgbvɃACR쐬(&D) +CreateQuickLaunchIcon=NCbNNACR쐬(&Q) +ProgramOnTheWeb=%1 on the Web +UninstallProgram=%1 ACXg[ +LaunchProgram=%1 s +AssocFileExtension=t@Cgq %2 %1 ֘At܂B +AssocingFileExtension=t@Cgq %2 %1 ֘AtĂ܂... +AutoStartProgramGroupDescription=X^[gAbv: +AutoStartProgram=%1 IɊJn +AddonHostProgramNotFound=IꂽtH_[ %1 ‚܂łB%n%n̂܂ܑs܂H \ No newline at end of file diff --git a/installer/innosetup/Languages/Lithuanian.isl b/installer/innosetup/Languages/Lithuanian.isl index b3e220036..74c99b2cd 100644 --- a/installer/innosetup/Languages/Lithuanian.isl +++ b/installer/innosetup/Languages/Lithuanian.isl @@ -1,7 +1,7 @@ -; *** Inno Setup version 6.0.3+ Lithuanian messages *** +; *** Inno Setup version 6.1.0+ Lithuanian messages *** ; ; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ +; https://jrsoftware.org/files/istrans/ ; ; Note: When translating this text, do not add periods (.) to the end of ; messages that didn't have them already, because on those messages Inno @@ -165,9 +165,9 @@ DiskSpaceWarning=Diegimui reikia bent %1 KB laisvos vietos, bet nurodytame diske DirNameTooLong=Katalogo pavadinimas ar kelias iki jo per ilgas. InvalidDirName=Nekorektikas katalogo pavadinimas. BadDirName32=Katalogo pavadinime neturi bti simboli:%n%n%1 -DirExistsTitle=Toks katalogas egzistuoja -DirExists=Katalogas:%n%n%1%n%n jau egzistuoja. Vis tiek norite diegti program tame kataloge? -DirDoesntExistTitle=Toks katalogas neegzistuoja. +DirExistsTitle=Tokio katalogo nra +DirExists=Katalogas:%n%n%1%n%n jau yra. Vis tiek norite diegti program tame kataloge? +DirDoesntExistTitle=Tokio katalogo nra. DirDoesntExist=Katalogas:%n%n%1%n%n neegzistuoja. Norite kad katalogas bt sukurtas? ; *** "Select Components" wizard page @@ -213,6 +213,18 @@ ReadyMemoComponents=Pasirinkti komponentai: ReadyMemoGroup=Start Menu katalogas: ReadyMemoTasks=Papildomi veiksmai: +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Parsisiuniami papildomi failai... +ButtonStopDownload=&Stabdyti parsisiuntim +StopDownload=Ar tikrai norite sustabdyti parsisiuntim? +ErrorDownloadAborted=Parsisiuntimas nutrauktas +ErrorDownloadFailed=Parsisisti nepavyko: %1 %2 +ErrorDownloadSizeFailed=Nepavyko gauti dydio: %1 %2 +ErrorFileHash1=Failo patikrinimas nepavyko: %1 +ErrorFileHash2=Neteisinga failo hash reikm: numatyta %1, rasta %2 +ErrorProgress=Netinkama eiga: %1 i %2 +ErrorFileSize=Neteisingas failo dydis: numatytas %1, rastas %2 + ; *** "Preparing to Install" wizard page WizardPreparing=Pasirengimas diegimui PreparingDesc=Diegimo programa pasirengusi [name] diegimui Js kompiuteryje. @@ -290,18 +302,27 @@ ErrorIniEntry=Klaida ra FileAbortRetryIgnoreSkipNotRecommended=Pralei&sti fail (nerekomenduojama) FileAbortRetryIgnoreIgnoreNotRecommended=&Ignoruoti klaid ir tsti (nerekomenduojama) SourceIsCorrupted=Pradinis failas sugadintas -SourceDoesntExist=Pradinis failas %1 neegzistuoja -ExistingFileReadOnly2=Egzistuojantis failas yra paymtas Tik skaitymui todl negali bti pakeistas. +SourceDoesntExist=Pradinio failo %1 nra +ExistingFileReadOnly2=Esamas failas yra paymtas Tik skaitymui todl negali bti pakeistas. ExistingFileReadOnlyRetry=Paalinkite at&ribut Tik skaitymui ir bandykite vl -ExistingFileReadOnlyKeepExisting=Pali&kti egzistuojant fail -ErrorReadingExistingDest=Skaitant egzistuojant fail vyko klaida: -FileExists=Toks failas jau egzistuoja.%n%nNorite, kad diegimo programa perrayt fail? -ExistingFileNewer=Egzistuojantis failas yra naujesnis u t, kur diegimo programa bando rayti. Rekomenduojama palikti esant naujesn fail.%n%nNorite palikti naujesn fail? +ExistingFileReadOnlyKeepExisting=Pali&kti esam fail +ErrorReadingExistingDest=Skaitant esam fail vyko klaida: +FileExistsSelectAction=Pasirinkite veiksm +FileExists2=Toks failas jau yra. +FileExistsOverwriteExisting=&Perrayti esam fail +FileExistsKeepExisting=Pali&kti esam fail +FileExistsOverwriteOrKeepAll=&Daryti taip ir esant kitiems konfliktams +ExistingFileNewerSelectAction=Pasirinkite veiksm +ExistingFileNewer=Esamas failas yra naujesnis u t, kur diegimo programa bando rayti. Rekomenduojama palikti esam fail.%n%nPalikti naujesn fail? +ExistingFileNewer2=Esamas failas yra naujesnis u t, kur diegimo programa bando rayti. +ExistingFileNewerOverwriteExisting=&Perrayti esam fail +ExistingFileNewerKeepExisting=Pali&kti esam fail (rekomenduojama) +ExistingFileNewerOverwriteOrKeepAll=&Daryti taip ir esant kitiems konfliktams ErrorChangingAttr=Keiiant failo atributus vyko klaida: ErrorCreatingTemp=Kuriant fail pasirinktame kataloge vyko klaida: ErrorReadingSource=Skaitant diegiamj fail vyko klaida: ErrorCopying=Kopijuojant fail vyko klaida: -ErrorReplacingExistingFile=Perraant egzistuojant fail vyko klaida: +ErrorReplacingExistingFile=Perraant esam fail vyko klaida: ErrorRestartReplace=Perkrovimas/Perraymas nepavyko: ErrorRenamingTemp=Pervadinant fail pasirinktame kataloge vyko klaida: ErrorRegisterServer=Nepavyko uregistruoti DLL/OCX bibliotekos: %1 @@ -323,7 +344,7 @@ ErrorOpeningReadme=Bandant atidaryti ErrorRestartingComputer=Diegimo programa negali perkrauti kompiuterio. Perkraukite kompiuter prastu bdu. ; *** Uninstaller messages -UninstallNotFound=%1 failas neegzistuoja. Paalinti nemanoma. +UninstallNotFound=%1 failo nra. Paalinti nemanoma. UninstallOpenError=%1 failas negali bti atidarytas. Paalinti nemanoma. UninstallUnsupportedVer=Paalinimo urnalo failas %1 yra paalinimo programai nesuprantamo formato. Paalinti nemanoma. UninstallUnknownEntry=Neinomas raas (%1) rastas paalinimo urnalo faile. @@ -362,6 +383,6 @@ UninstallProgram=Pa LaunchProgram=Paleisti %1 AssocFileExtension=&Susieti %1 program su failo pltiniu %2 AssocingFileExtension=%1 programa susiejama su failo pltiniu %2... -AutoStartProgramGroupDescription=Atomatin paleistis: -AutoStartProgram=Atomatikai paleisti %1 +AutoStartProgramGroupDescription=Automatin paleistis: +AutoStartProgram=Automatikai paleisti %1 AddonHostProgramNotFound=%1 nerasta Js nurodytame kataloge.%n%nVis tiek norite tsti? diff --git a/installer/innosetup/Languages/Montenegrin.isl b/installer/innosetup/Languages/Montenegrin.isl new file mode 100644 index 000000000..0a306d189 --- /dev/null +++ b/installer/innosetup/Languages/Montenegrin.isl @@ -0,0 +1,386 @@ +; *** Inno Setup version 6.1.0+ Montenegrin messages *** +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Translated by Drazen Djurisic (kntaur@gmail.com) +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Crnogorski +LanguageID=$081a +LanguageCodePage=1250 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=Instalacija +SetupWindowTitle=Instalacija - %1 +UninstallAppTitle=Deinstalacija +UninstallAppFullTitle=Deinstalacija programa %1 + +; *** Misc. common +InformationTitle=Podaci +ConfirmTitle=Potvrda +ErrorTitle=Greka + +; *** SetupLdr messages +SetupLdrStartupMessage=Instalirat e te %1. elite li da nastavite? +LdrCannotCreateTemp=Ne mogu da napravim privremenu datoteku. Instalacija obustavljena +LdrCannotExecTemp=Ne mogu da pokrenem datoteku u privremenom direktorijumu. Instalacija obustavljena +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nGreka %2: %3 +SetupFileMissing=Datoteka %1 nedostaje u instalacionom direktorijumu. Ispravite problem ili nabavite novi primjerak programa. +SetupFileCorrupt=Instalacione datoteke su otecene. Nabavite novi primjerak programa. +SetupFileCorruptOrWrongVer=Instalacione datoteke su otecene, ili su nekompatibilne sa ovom verzijom instalacije. Ispravite problem ili nabavite novi primjerak programa. +InvalidParameter=Neispravan parametar je prenijet na komandnu liniju:%n%n%1 +SetupAlreadyRunning=Instalacija je vec pokrenuta. +WindowsVersionNotSupported=Ova verzija programa nije kompatibilna sa verzijom windows'-a na vaem racunaru. +WindowsServicePackRequired=Ovaj program zahtijeva %1 servisni paket %2 ili noviji. +NotOnThisPlatform=Program nece raditi na %1. +OnlyOnThisPlatform=Program ce raditi na %1. +OnlyOnTheseArchitectures=Program se moe instalirati samo na verzijama windows-a koji rade na sledecim arhitekturama procesora:%n%n%1 +WinVersionTooLowError=Ovaj program zahtijeva %1 verziju %2 ili noviju. +WinVersionTooHighError=Program se ne moe instalirati na %1 verziju %2 ili noviju. +AdminPrivilegesRequired=Morate biti prijavljeni kao administrator da bi ste instalirali program. +PowerUserPrivilegesRequired=Morate biti prijavljeni kao administrator ili ovlaceni korisnik da bi ste instalirali ovaj program. +SetupAppRunningError=Program %1 je trenutno pokrenut.%n%nUgasite ga, kliknite "U redu", ili "Obustavi" za napustite instalaciju. +UninstallAppRunningError=Program %1 je trenutno pokrenut.%n%nUgasite ga, kliknite "U redu", ili "Obustavi" za napustite instalaciju. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Izaberite nacin instalacije +PrivilegesRequiredOverrideInstruction=Izaberite nacin instalacije +PrivilegesRequiredOverrideText1=%1 moe biti instaliran za sve korisnike (zahtijeva administratorske privilegije), ili samo za vas. +PrivilegesRequiredOverrideText2=%1 moe biti instaliran za vas samo, ili za sve korisnike (zahtijeva administratorske privilegije). +PrivilegesRequiredOverrideAllUsers=Instalacija za &sve korisnike +PrivilegesRequiredOverrideAllUsersRecommended=Instalacija za &sve korisnike (preporucuje se) +PrivilegesRequiredOverrideCurrentUser=Instalacija &za vas samo +PrivilegesRequiredOverrideCurrentUserRecommended=Instalacija &za vas samo (preporucuje se) + +; *** Misc. errors +ErrorCreatingDir=Instalacija ne moe da napravi direktorijum "%1" +ErrorTooManyFilesInDir=Ne mogu da napravim datoteku u direktorijumu "%1" zato to sadri previe datoteka + +; *** Setup common messages +ExitSetupTitle=Napusti instalaciju +ExitSetupMessage=Instalacija nije kompletna. Ako izadete sad, program nece biti instaliran.%n%nMoete pokrenuti instalaciju neki drugi put da zavrite instaliranje.%n%nNapusti instalaciju? +AboutSetupMenuItem=&O programu... +AboutSetupTitle=O programu +AboutSetupMessage=%1 verzija %2%n%3%n%n%1 internet stranica:%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< &Nazad +ButtonNext=&Dalje > +ButtonInstall=&Instaliraj +ButtonOK=U redu +ButtonCancel=Obustavi +ButtonYes=&Da +ButtonYesToAll=Da za &sve +ButtonNo=&Ne +ButtonNoToAll=N&e za sve +ButtonFinish=&Zavri +ButtonBrowse=&Pretrai... +ButtonWizardBrowse=P&retrai... +ButtonNewFolder=&Napravi novi direktorijum + +; *** "Select Language" dialog messages +SelectLanguageTitle=Izaberite jezik instalacije +SelectLanguageLabel=Izaberite jezik koji ce te koristiti tokom instalacije. + +; *** Common wizard text +ClickNext=Kliknite "Dalje" za nastavak, ili "Obustavi" da prekinete instalaciju. +BeveledLabel= +BrowseDialogTitle=Izaberite direktorijum +BrowseDialogLabel=Izaberite direktorijum sa liste ispod, onda kliknite na "U redu". +NewFolderName=Novi direktorijum + +; *** "Welcome" wizard page +WelcomeLabel1=Dobro doli na instalaciju programa [name] +WelcomeLabel2=Instalirat ce te [name/ver] na vaem racunaru.%n%nPreporucujemo da zatvorite sve ostale programe pa da nastavite sa instalacijom. + +; *** "Password" wizard page +WizardPassword=Lozinka +PasswordLabel1=Instalacija je zaticena lozinkom. +PasswordLabel3=Unesite lozinku i kliknite "Dalje" da nastavite. Lozinka je osjetljiva na velika i mala slova. +PasswordEditLabel=&Lozinka: +IncorrectPassword=Lozinka koju ste unijeli je netacna. Probajte opet. + +; *** "License Agreement" wizard page +WizardLicense=Ugovor o licenci +LicenseLabel=Paljivo procitajte sledece prije nego nastavite. +LicenseLabel3=Procitajte ugovor o licenci koji je ispod. Morate prihvatiti uslove ugovora ako elite da nastavite sa instalacijom. +LicenseAccepted=&Prihvatam ugovor +LicenseNotAccepted=&Ne prihvatam ugovor + +; *** "Information" wizard pages +WizardInfoBefore=Informacije +InfoBeforeLabel=Paljivo procitajte sledece prije nego nastavite. +InfoBeforeClickLabel=Kada budete spremni da nastavite instalaciju, kliknite "Dalje". +WizardInfoAfter=Informacije +InfoAfterLabel=Paljivo procitajte sledece prije nego nastavite. +InfoAfterClickLabel=Kada budete spremni da nastavite instalaciju, kliknite "Dalje". + +; *** "User Information" wizard page +WizardUserInfo=Podaci o korisniku +UserInfoDesc=Unesite vae podatke. +UserInfoName=&Korisnik: +UserInfoOrg=&Organizacija: +UserInfoSerial=&Serijski broj: +UserInfoNameRequired=Morate unijeti ime. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Izaberite lokaciju +SelectDirDesc=Gdje ce [name] biti instaliran? +SelectDirLabel3=Program [name] ce biti instaliran u direktorijumu. +SelectDirBrowseLabel=Za nastavak pritisnite "Dalje". Ako elite drugi direktorijum, pritisnite "Potrai". +DiskSpaceGBLabel=Potrebno je najmanje [gb] GB slobodnog prostora na disku. +DiskSpaceMBLabel=Potrebno je najmanje [mb] MB slobodnog prostora na disku. +CannotInstallToNetworkDrive=Program ne moete instalirati na mrenom disku. +CannotInstallToUNCPath=Program ne moete instalirati na UNC putanji. +InvalidPath=Morate navesti cijelu putanju sa oznakom diska; npr:%n%nC:\APP%n%nili UNC putanja u obliku:%n%n\\server\share +InvalidDrive=Disk ili UNC koji ste naveli ne postoji ili nije dostupan. Izaberite drugi. +DiskSpaceWarningTitle=Nema dovoljno prostora na disku +DiskSpaceWarning=Programu je potrebno %1 KB slobodnog prostora za instalaciju, ali izabrani disk ima samo %2 KB.%n%nDa li elite da nastavite bez obzira? +DirNameTooLong=Ime direktorijuma ili putanja je predugacka. +InvalidDirName=Ime direktorijuma nije valjano. +BadDirName32=Ime direktorijuma ne moe da sadri nijedan od sledecih karaktera:%n%n%1 +DirExistsTitle=Direktorijum vec postoji +DirExists=Direktorijum:%n%n%1%n%nvec postoji. elite ili da nastavite sa instalcijom u postojeci direktorijum? +DirDoesntExistTitle=Direktorijum ne postoji +DirDoesntExist=Direktorijum:%n%n%1%n%nne postoji. elite li da kreiramo navedeni direktorijum? + +; *** "Select Components" wizard page +WizardSelectComponents=Odabir komponenata +SelectComponentsDesc=Koje komponente elite da instalirate? +SelectComponentsLabel2=Izaberite komponente koje elite da instalirate; ocistite komponente koje ne elite. Kliknite "Dalje" za nastavak instalacije. +FullInstallation=Kompletna instalacija +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Podrazumijevana instalacija +CustomInstallation=Prilagodjena instalacija +NoUninstallWarningTitle=Komponenta postoji +NoUninstallWarning=Program je pronaao da su sledece komponente vec instalirane:%n%n%1%n%nŠtrikiranjem ovih komponenti one nece biti deinstalirane.%n%nDa li elite da nastavite? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Izabrane stavke zahtijevaju najmanje [gb] GB prostora na disku. +ComponentsDiskSpaceMBLabel=Izabrane stavke zahtijevaju najmanje [mb] MB prostora na disku. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Odabir dodatnih zadataka +SelectTasksDesc=Koje dodatne zadatke elite program da izvri? +SelectTasksLabel2=Izaberite dodatne zadatke koje zelite da [name] izvri, onda kliknite "Dalje". + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Odabir direktorijuma u meniju "Start" +SelectStartMenuFolderDesc=Izaberite mjesto gdje elite da budu precice? +SelectStartMenuFolderLabel3=Instalacija ce postaviti precice u sledecem direktorijumu "Start" menija. +SelectStartMenuFolderBrowseLabel=Za nastavak pritisnite "Dalje". Ako elite drugi direktorijum pritisnite "Potrai". +MustEnterGroupName=Morate unijeti ime direktorijuma. +GroupNameTooLong=Ime direktorijuma ili putanje je predugacko. +InvalidGroupName=Ime direktorijuma nije valjano. +BadGroupName=Naziv direktorijuma ne smije da sadri sledece karaktere:%n%n%1 +NoProgramGroupCheck2=&Nemoj kreirati direktorijum u "Start" meniju + +; *** "Ready to Install" wizard page +WizardReady=Spreman za instalaciju +ReadyLabel1=Program je spreman da instalira [name] na vaem racunaru. +ReadyLabel2a=Klikni "Instaliraj" da zapocnete instalaciju ili "Nazad" da ponovo pogledate i promijenite pojedine stavke. +ReadyLabel2b=Klikni "Instaliraj" da zapocnete instalaciju. +ReadyMemoUserInfo=Podaci o korisniku: +ReadyMemoDir=Lokacija direktorijuma: +ReadyMemoType=Vrsta instalacije: +ReadyMemoComponents=Izabrane komponente: +ReadyMemoGroup=Direktorijum u meniju "Start": +ReadyMemoTasks=Dodatni zadaci: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Snimam dodatne datoteke... +ButtonStopDownload=&Zaustavi snimanje +StopDownload=Jeste li sigurni da elite da zaustavite snimanje? +ErrorDownloadAborted=Snimanje obustavljeno +ErrorDownloadFailed=Snimanje neuspjeno: %1 %2 +ErrorDownloadSizeFailed=informacije o velicini netacne: %1 %2 +ErrorFileHash1=Hash identifikacija datoteke netacna: %1 +ErrorFileHash2=Netacna hash identifikacija datoteke: ocekivan %1, naden %2 +ErrorProgress=Neispravan progres: %1 of %2 +ErrorFileSize=Neispravna velicina datoteke: ocekivana %1, nadena %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Priprema za instalaciju +PreparingDesc=Program se sprema da instalira [name] na vaem racunaru. +PreviousInstallNotCompleted=Instalacija ili deinstalacija prethodnog programa nije zavrena. Potrebno je da restartujete racunar da bi se instalacija zavrila.%n%nNakon restarta racunara pokrenite instalaciju ponovo da bi se [name] instalirao. +CannotContinue=Instalacija nije moguca. Kliknite "Otkai" da izadete. +ApplicationsFound=Sledeci programi koriste datoteke koje treba da aurira instalacioni program. Preporucujemo da dozvolite instalacionom programu da zatvori ove programe. +ApplicationsFound2=Sledeci programi koriste datoteke koje treba da aurira instalacioni program. Preporucujemo da dozvolite instalacionom programu da zatvori ove programe. Nakon kompletirane instalacije, instalacija ce pokuati da restartuje program . +CloseApplications=&Automatski zatvorite program +DontCloseApplications=&Ne zatvaraj program +ErrorCloseApplications=Ne mogu da zatvorim sve programe. Preporucujemo da ugasite sve programe cije datoteke treba da nadogradi instlacija. +PrepareToInstallNeedsRestart=Instalacija mora da restartuje racunar. Nakon restarta racunara, pokrenite instalaciju [name] da bi dovrili instalaciju.%n%nelite li da restartujete racunar? + +; *** "Installing" wizard page +WizardInstalling=Instaliram +InstallingLabel=Sacekajte da program instalira [name] na va racunar. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Zavravam sa instalacijom [name] +FinishedLabelNoIcons=Instalacija [name] je zavrena na vaem racunaru. +FinishedLabel=Instalacija [name] je zavrena. Program moete startovati klikom na instaliranu precicu. +ClickFinish=Kliknite na "Zavri" da izadete. +FinishedRestartLabel=Da bi instalacija [name] bila kompletna, program mora restartovati racunar. Restartovanje racunara? +FinishedRestartMessage=Da bi instalacija [name] bila kompletna, program mora restartovati racunar.%n%nRestartovanje racunara? +ShowReadmeCheck=Da, elim da pogledam tekstualnu datoteku +YesRadio=&Da, restartovacu racunar sada +NoRadio=&Ne, restartovacu racunar kasnije +; used for example as 'Run MyProg.exe' +RunEntryExec=Run %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=View %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Sledeci disk +SelectDiskLabel2=Ubacite disk %1 i kliknite "U redu".%n%nAko se datoteke na ovom disku mogu pronaci u nekom drugom direktorijumu, unesite odgovarajucu putanju ili kliknite na „Potrai“ +PathLabel=&Path: +FileNotInDir2=Datoteka "%1" ne postoji na lokaciji "%2". Ubacite pravi disk ili izaberite drugi direktorijum. +SelectDirectoryLabel=Navedite lokaciju sledeceg diska. + +; *** Installation phase messages +SetupAborted=Instalacija nije kompletna.%n%nIspravite problem i pokrenite instalaciju ponovo. +AbortRetryIgnoreSelectAction=Odaberite radnju +AbortRetryIgnoreRetry=&pokuaj ponovo +AbortRetryIgnoreIgnore=&Ignorii greku i nastavi +AbortRetryIgnoreCancel=Prekini instalaciju + +; *** Installation status messages +StatusClosingApplications=Zatvaram programe... +StatusCreateDirs=Kreiram direktorijume... +StatusExtractFiles=Raspakujem datoteke... +StatusCreateIcons=Kreiram precice... +StatusCreateIniEntries=Kreiram INI unose... +StatusCreateRegistryEntries=Kreiram unose u registar... +StatusRegisterFiles=Registrujem datoteke... +StatusSavingUninstall=Snimam deinstalacione informacije... +StatusRunProgram=Yavravam sa instalacijom... +StatusRestartingApplications=Restartujem program... +StatusRollback=Ponitavam izmjene... + +; *** Misc. errors +ErrorInternal2=Interna greka: %1 +ErrorFunctionFailedNoCode=%1 neuspjeh +ErrorFunctionFailed=%1 neuspjeh; kod %2 +ErrorFunctionFailedWithMessage=%1 neuspjeh; kod %2.%n%3 +ErrorExecutingProgram=Ne mogu da pokrenem datoteku:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Greka pri unosu u registri:%n%1\%2 +ErrorRegCreateKey=Greka pri unosu u registri:%n%1\%2 +ErrorRegWriteKey=Greka pri unosu u registri:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Greka pri stvaranju INI unosa u datoteci "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Izostavite ovu datoteku (ne preporucuje se) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorii greku i nastaviti instalaciju (ne preporucuje se) +SourceIsCorrupted=Instalaciona datoteka je otecena +SourceDoesntExist=Instalaciona datoteka "%1" ne postoji +ExistingFileReadOnly2=Postojeca datoteka ne moe se presnimiti jer je oznacena kao samo za citanje. +ExistingFileReadOnlyRetry=&Uklonite atribut na datoteci samo za citanje i pokuajte ponovo +ExistingFileReadOnlyKeepExisting=&Zadrati postojecu datoteku +ErrorReadingExistingDest=Greka nastala pri citanju vec postojece datoteke: +FileExistsSelectAction=Izaberite operaciju +FileExists2=Datoteka vec postoji. +FileExistsOverwriteExisting=&Presnimite postojecu datoteku +FileExistsKeepExisting=&Zadrati postojecu datoteku +FileExistsOverwriteOrKeepAll=&Uradi ovo kod sledeceg problema +ExistingFileNewerSelectAction=Izaberi operaciju +ExistingFileNewer2=Postojeca datoteka je novija od ove koju elimo da instaliramo. +ExistingFileNewerOverwriteExisting=&Presnimite postojecu datoteku +ExistingFileNewerKeepExisting=&Zadrite postojecu datoteku (preporucujemo) +ExistingFileNewerOverwriteOrKeepAll=&Uradi ovo kod sledeceg problema +ErrorChangingAttr=Greka kod pokuaja da se promijeni atribut datoteke: +ErrorCreatingTemp=Greka kod kreiranja datoteke u navedenom direktorijumu: +ErrorReadingSource=Greka kod pokuaja citanja instalacione datoteke: +ErrorCopying=Greka kod pokuaja snimanja datoteke: +ErrorReplacingExistingFile=Greka kod pokuaja presnimavanja postojece datoteke: +ErrorRestartReplace=Ne mogu da zamijenim: +ErrorRenamingTemp=Dolo je do greke pri pokuaju da preimenujem datoteku u navedenom direktorijumu +ErrorRegisterServer=Ne mogu da registrujem DLL/OCX: %1 +ErrorRegSvr32Failed=RegSvr32 nije uspio. Greka %1 +ErrorRegisterTypeLib=Ne mogu da upiem biblioteku tipova: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Svi korisnici +UninstallDisplayNameMarkCurrentUser=Trenutni korisnik + +; *** Post-installation errors +ErrorOpeningReadme=Greka pri otvaranju tekstualne datoteke. +ErrorRestartingComputer=Instalacija ne moe da restartuje racunar. Uradite to sami. + +; *** Uninstaller messages +UninstallNotFound=Datoteka "%1" ne postoji. Ne mogu da deinstaliram. +UninstallOpenError=Datoteka "%1" se ne moe otvoriti. Ne mogu da deinstaliram +UninstallUnsupportedVer=Izvjetaj "%1" nije prepoznat ode ove verzije deinstalacije. Ne mogu da deinstaliram +UninstallUnknownEntry=Nepoznat unos (%1) se pojavio u izvjetaju deinstalacije +ConfirmUninstall=elite li da deinstalirate %1 kao i sve njegove komponente? +UninstallOnlyOnWin64=Ovu instalaciju je moguce deinstalirati samo na 64-bit Windows-u. +OnlyAdminCanUninstall=Ova instalacija se moe deinstalirati samo kao administrator. +UninstallStatusLabel=Sacekajte da se %1 deinstalira sa racunara. +UninstalledAll=%1 je uspjeno deinstaliran. +UninstalledMost=%1 deinstalacija uspjena.%n%nNeki elementi nijesu uklonjeni. Moete ih sami ukloniti. +UninstalledAndNeedsRestart=Da zavrite sa deinstlacijom %1, restartujte va racunar.%n%nelite li restart sada? +UninstallDataCorrupted="%1" datoteka je otecena. Ne mogu da deinstaliram + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Brisati dijeljenu datoteku? +ConfirmDeleteSharedFile2=Sistem je primijetio da sledecu dijeljenu datoteku vie ne koristi nijedan program. elite li da deinstaliram dijeljenu datoteku?%n%nAko je neki program koristio dijeljenu datoteku, moguce je da on vie nece raditi. Ako nijesi siguran izaberi "Ne". Ostavljanje datoteke na vaem racunaru ne moete imati problema. +SharedFileNameLabel=Ime datoteke: +SharedFileLocationLabel=Lokacija: +WizardUninstalling=Status deinstlacije +StatusUninstalling=Deinstaliram %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Instaliram %1. +ShutdownBlockReasonUninstallingApp=Deinstaliram %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 verzija %2 +AdditionalIcons=Dodatne precice: +CreateDesktopIcon=Kreiraj precicu na &desktop +CreateQuickLaunchIcon=Kreiraj precicu na paleti za &Brzo pokretanje +ProgramOnTheWeb=%1 na internetu +UninstallProgram=Deinstaliraj %1 +LaunchProgram=Pokreni %1 +AssocFileExtension=&Povei %1 sa datotekom %2 +AssocingFileExtension=Povezujem %1 sa datotekom %2 ... +AutoStartProgramGroupDescription=Pokretanje: +AutoStartProgram=Automatski pokreni %1 +AddonHostProgramNotFound=%1 nije naden u direktorijumu koji ste izabrali.%n%nelite li da nastavim? diff --git a/installer/innosetup/Languages/Norwegian.isl b/installer/innosetup/Languages/Norwegian.isl new file mode 100644 index 000000000..8141d45a8 --- /dev/null +++ b/installer/innosetup/Languages/Norwegian.isl @@ -0,0 +1,378 @@ +; *** Inno Setup version 6.1.0+ Norwegian (bokml) messages *** +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). +; +; Norwegian translation currently maintained by Eivind Bakkestuen +; E-mail: eivind.bakkestuen@gmail.com +; Many thanks to the following people for language improvements and comments: +; +; Harald Habberstad, Frode Weum, Morten Johnsen, +; Tore Ottinsen, Kristian Hyllestad, Thomas Kelso, Jostein Christoffer Andersen +; +; $jrsoftware: issrc/Files/Languages/Norwegian.isl,v 1.15 2007/04/23 15:03:35 josander+ Exp $ + +[LangOptions] +LanguageName=Norsk +LanguageID=$0414 +LanguageCodePage=1252 + +[Messages] + +; *** Application titles +SetupAppTitle=Installasjon +SetupWindowTitle=Installere - %1 +UninstallAppTitle=Avinstaller +UninstallAppFullTitle=%1 Avinstallere + +; *** Misc. common +InformationTitle=Informasjon +ConfirmTitle=Bekreft +ErrorTitle=Feil + +; *** SetupLdr messages +SetupLdrStartupMessage=Dette vil installere %1. Vil du fortsette? +LdrCannotCreateTemp=Kan ikke lage midlertidig fil, installasjonen er avbrutt +LdrCannotExecTemp=Kan ikke kjre fil i den midlertidige mappen, installasjonen er avbrutt + +; *** Startup error messages +LastErrorMessage=%1.%n%nFeil %2: %3 +SetupFileMissing=Filen %1 mangler i installasjonskatalogen. Vennligst korriger problemet eller skaff deg en ny kopi av programmet. +SetupFileCorrupt=Installasjonsfilene er delagte. Vennligst skaff deg en ny kopi av programmet. +SetupFileCorruptOrWrongVer=Installasjonsfilene er delagte eller ikke kompatible med dette installasjonsprogrammet. Vennligst korriger problemet eller skaff deg en ny kopi av programmet. +InvalidParameter=Kommandolinjen hadde en ugyldig parameter:%n%n%1 +SetupAlreadyRunning=Dette programmet kjrer allerede. +WindowsVersionNotSupported=Dette programmet sttter ikke Windows-versjonen p denne maskinen. +WindowsServicePackRequired=Dette programmet krever %1 Service Pack %2 eller nyere. +NotOnThisPlatform=Dette programmet kjrer ikke p %1. +OnlyOnThisPlatform=Dette programmet kjrer kun p %1. +OnlyOnTheseArchitectures=Dette programmet kan kun installeres i Windows-versjoner som er beregnet p flgende prossessorarkitekturer:%n%n%1 +WinVersionTooLowError=Dette programmet krever %1 versjon %2 eller nyere. +WinVersionTooHighError=Dette programmet kan ikke installeres p %1 versjon %2 eller nyere. +AdminPrivilegesRequired=Administrator-rettigheter kreves for installere dette programmet. +PowerUserPrivilegesRequired=Du m vre logget inn som administrator eller ha administrator-rettigheter nr du installerer dette programmet. +SetupAppRunningError=Installasjonsprogrammet har funnet ut at %1 kjrer.%n%nVennligst avslutt det n og klikk deretter OK for fortsette, eller Avbryt for avslutte. +UninstallAppRunningError=Avinstallasjonsprogrammet har funnet ut at %1 kjrer.%n%nVennligst avslutt det n og klikk deretter OK for fortsette, eller Avbryt for avslutte. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Velg Installasjon Type +PrivilegesRequiredOverrideInstruction=Installasjons Type +PrivilegesRequiredOverrideText1=%1 kan installeres for alle brukere (krever administrator-rettigheter), eller bare for deg. +PrivilegesRequiredOverrideText2=%1 kan installeres bare for deg, eller for alle brukere (krever administrator-rettigheter). +PrivilegesRequiredOverrideAllUsers=Installer for &alle brukere +PrivilegesRequiredOverrideAllUsersRecommended=Installer for &alle brukere (anbefalt) +PrivilegesRequiredOverrideCurrentUser=Installer bare for &meg +PrivilegesRequiredOverrideCurrentUserRecommended=Installer bare for &meg (anbefalt) + +; *** Misc. errors +ErrorCreatingDir=Installasjonsprogrammet kunne ikke lage mappen "%1" +ErrorTooManyFilesInDir=Kunne ikke lage en fil i mappen "%1" fordi den inneholder for mange filer + +; *** Setup common messages +ExitSetupTitle=Avslutt installasjonen +ExitSetupMessage=Installasjonen er ikke ferdig. Programmet installeres ikke hvis du avslutter n.%n%nDu kan installere programmet igjen senere hvis du vil.%n%nVil du avslutte? +AboutSetupMenuItem=&Om installasjonsprogrammet... +AboutSetupTitle=Om installasjonsprogrammet +AboutSetupMessage=%1 versjon %2%n%3%n%n%1 hjemmeside:%n%4 +AboutSetupNote= +TranslatorNote=Norwegian translation maintained by Eivind Bakkestuen (eivind.bakkestuen@gmail.com) + +; *** Buttons +ButtonBack=< &Tilbake +ButtonNext=&Neste > +ButtonInstall=&Installer +ButtonOK=OK +ButtonCancel=Avbryt +ButtonYes=&Ja +ButtonYesToAll=Ja til &alle +ButtonNo=&Nei +ButtonNoToAll=N&ei til alle +ButtonFinish=&Ferdig +ButtonBrowse=&Bla gjennom... +ButtonWizardBrowse=&Bla gjennom... +ButtonNewFolder=&Lag ny mappe + +; *** "Select Language" dialog messages +SelectLanguageTitle=Velg installasjonssprk +SelectLanguageLabel=Velg sprket som skal brukes under installasjonen. + +; *** Common wizard text +ClickNext=Klikk p Neste for fortsette, eller Avbryt for avslutte installasjonen. +BeveledLabel= +BrowseDialogTitle=Bla etter mappe +BrowseDialogLabel=Velg en mappe fra listen nedenfor, klikk deretter OK. +NewFolderName=Ny mappe + +; *** "Welcome" wizard page +WelcomeLabel1=Velkommen til installasjonsprogrammet for [name]. +WelcomeLabel2=Dette vil installere [name/ver] p din maskin.%n%nDet anbefales at du avslutter alle programmer som kjrer fr du fortsetter. + +; *** "Password" wizard page +WizardPassword=Passord +PasswordLabel1=Denne installasjonen er passordbeskyttet. +PasswordLabel3=Vennligst oppgi ditt passord og klikk p Neste for fortsette. Sm og store bokstaver behandles ulikt. +PasswordEditLabel=&Passord: +IncorrectPassword=Det angitte passordet er feil, vennligst prv igjen. + +; *** "License Agreement" wizard page +WizardLicense=Lisensbetingelser +LicenseLabel=Vennligst les flgende viktig informasjon fr du fortsetter. +LicenseLabel3=Vennligst les flgende lisensbetingelser. Du m godta innholdet i lisensbetingelsene fr du fortsetter med installasjonen. +LicenseAccepted=Jeg &aksepterer lisensbetingelsene +LicenseNotAccepted=Jeg aksepterer &ikke lisensbetingelsene + +; *** "Information" wizard pages +WizardInfoBefore=Informasjon +InfoBeforeLabel=Vennligst les flgende viktige informasjon fr du fortsetter. +InfoBeforeClickLabel=Klikk p Neste nr du er klar til fortsette. +WizardInfoAfter=Informasjon +InfoAfterLabel=Vennligst les flgende viktige informasjon fr du fortsetter. +InfoAfterClickLabel=Klikk p Neste nr du er klar til fortsette. + +; *** "User Information" wizard page +WizardUserInfo=Brukerinformasjon +UserInfoDesc=Vennligst angi informasjon. +UserInfoName=&Brukernavn: +UserInfoOrg=&Organisasjon: +UserInfoSerial=&Serienummer: +UserInfoNameRequired=Du m angi et navn. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Velg mappen hvor filene skal installeres: +SelectDirDesc=Hvor skal [name] installeres? +SelectDirLabel3=Installasjonsprogrammet vil installere [name] i flgende mappe. +SelectDirBrowseLabel=Klikk p Neste for fortsette. Klikk p Bla gjennom hvis du vil velge en annen mappe. +DiskSpaceGBLabel=Programmet krever minst [gb] GB med diskplass. +DiskSpaceMBLabel=Programmet krever minst [mb] MB med diskplass. +CannotInstallToNetworkDrive=Kan ikke installere p en nettverksstasjon. +CannotInstallToUNCPath=Kan ikke installere p en UNC-bane. Du m tilordne nettverksstasjonen hvis du vil installere i et nettverk. +InvalidPath=Du m angi en full bane med stasjonsbokstav, for eksempel:%n%nC:\APP%n%Du kan ikke bruke formen:%n%n\\server\share +InvalidDrive=Den valgte stasjonen eller UNC-delingen finnes ikke, eller er ikke tilgjengelig. Vennligst velg en annen +DiskSpaceWarningTitle=For lite diskplass +DiskSpaceWarning=Installasjonprogrammet krever minst %1 KB med ledig diskplass, men det er bare %2 KB ledig p den valgte stasjonen.%n%nvil du fortsette likevel? +DirNameTooLong=Det er for langt navn p mappen eller banen. +InvalidDirName=Navnet p mappen er ugyldig. +BadDirName32=Mappenavn m ikke inneholde noen av flgende tegn:%n%n%1 +DirExistsTitle=Eksisterende mappe +DirExists=Mappen:%n%n%1%n%nfinnes allerede. Vil du likevel installere der? +DirDoesntExistTitle=Mappen eksisterer ikke +DirDoesntExist=Mappen:%n%n%1%n%nfinnes ikke. Vil du at den skal lages? + +; *** "Select Components" wizard page +WizardSelectComponents=Velg komponenter +SelectComponentsDesc=Hvilke komponenter skal installeres? +SelectComponentsLabel2=Velg komponentene du vil installere; velg bort de komponentene du ikke vil installere. Nr du er klar, klikker du p Neste for fortsette. +FullInstallation=Full installasjon +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Kompakt installasjon +CustomInstallation=Egendefinert installasjon +NoUninstallWarningTitle=Komponenter eksisterer +NoUninstallWarning=Installasjonsprogrammet har funnet ut at flgende komponenter allerede er p din maskin:%n%n%1%n%nDisse komponentene avinstalleres ikke selv om du ikke velger dem.%n%nVil du likevel fortsette? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Valgte alternativer krever minst [gb] GB med diskplass. +ComponentsDiskSpaceMBLabel=Valgte alternativer krever minst [mb] MB med diskplass. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Velg tilleggsoppgaver +SelectTasksDesc=Hvilke tilleggsoppgaver skal utfres? +SelectTasksLabel2=Velg tilleggsoppgavene som skal utfres mens [name] installeres, klikk deretter p Neste. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Velg mappe p start-menyen +SelectStartMenuFolderDesc=Hvor skal installasjonsprogrammet plassere snarveiene? +SelectStartMenuFolderLabel3=Installasjonsprogrammet vil opprette snarveier p flgende startmeny-mappe. +SelectStartMenuFolderBrowseLabel=Klikk p Neste for fortsette. Klikk p Bla igjennom hvis du vil velge en annen mappe. +MustEnterGroupName=Du m skrive inn et mappenavn. +GroupNameTooLong=Det er for langt navn p mappen eller banen. +InvalidGroupName=Navnet p mappen er ugyldig. +BadGroupName=Mappenavnet m ikke inneholde flgende tegn:%n%n%1 +NoProgramGroupCheck2=&Ikke legg til mappe p start-menyen + +; *** "Ready to Install" wizard page +WizardReady=Klar til installere +ReadyLabel1=Installasjonsprogrammet er n klar til installere [name] p din maskin. +ReadyLabel2a=Klikk Installer for fortsette, eller Tilbake for se p eller forandre instillingene. +ReadyLabel2b=Klikk Installer for fortsette. +ReadyMemoUserInfo=Brukerinformasjon: +ReadyMemoDir=Installer i mappen: +ReadyMemoType=Installasjonstype: +ReadyMemoComponents=Valgte komponenter: +ReadyMemoGroup=Programgruppe: +ReadyMemoTasks=Tilleggsoppgaver: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Laster ned ekstra filer... +ButtonStopDownload=&Stopp nedlasting +StopDownload=Er du sikker p at du vil stoppe nedlastingen? +ErrorDownloadAborted=Nedlasting avbrutt +ErrorDownloadFailed=Nedlasting feilet: %1 %2 +ErrorDownloadSizeFailed=Kunne ikke finne filstrrelse: %1 %2 +ErrorFileHash1=Fil hash verdi feilet: %1 +ErrorFileHash2=Ugyldig fil hash verdi: forventet %1, fant %2 +ErrorProgress=Ugyldig fremdrift: %1 of %2 +ErrorFileSize=Ugyldig fil strrelse: forventet %1, fant %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Forbereder installasjonen +PreparingDesc=Installasjonsprogrammet forbereder installasjon av [name] p den maskin. +PreviousInstallNotCompleted=Installasjonen/fjerningen av et tidligere program ble ikke ferdig. Du m starte maskinen p nytt.%n%nEtter omstarten m du kjre installasjonsprogrammet p nytt for fullfre installasjonen av [name]. +CannotContinue=Installasjonsprogrammet kan ikke fortsette. Klikk p Avbryt for avslutte. +ApplicationsFound=Disse applikasjonene bruker filer som vil oppdateres av installasjonen. Det anbefales la installasjonen automatisk avslutte disse applikasjonene. +ApplicationsFound2=Disse applikasjonene bruker filer som vil oppdateres av installasjonen. Det anbefales la installasjonen automatisk avslutte disse applikasjonene. Installasjonen vil prve starte applikasjonene p nytt etter at installasjonen er avsluttet. +CloseApplications=Lukk applikasjonene &automatisk +DontCloseApplications=&Ikke lukk applikasjonene +ErrorCloseApplications=Installasjonsprogrammet kunne ikke lukke alle applikasjonene &automatisk. Det anbefales lukke alle applikasjoner som bruker filer som installasjonsprogrammet trenger oppdatere fr du fortsetter installasjonen. +PrepareToInstallNeedsRestart=Installasjonsprogrammet m gjre omstart av maskinen. Etter omstart av maskinen, kjr installasjonsprogrammet p nytt for ferdigstille installasjonen av [name].%n%nVil du gjre omstart av maskinen n? + +; *** "Installing" wizard page +WizardInstalling=Installerer +InstallingLabel=Vennligst vent mens [name] installeres p din maskin. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Fullfrer installasjonsprogrammet for [name] +FinishedLabelNoIcons=[name] er installert p din maskin. +FinishedLabel=[name] er installert p din maskin. Programmet kan kjres ved at du klikker p ett av de installerte ikonene. +ClickFinish=Klikk Ferdig for avslutte installasjonen. +FinishedRestartLabel=Maskinen m startes p nytt for at installasjonen skal fullfres. Vil du starte p nytt n? +FinishedRestartMessage=Maskinen m startes p nytt for at installasjonen skal fullfres.%n%nVil du starte p nytt n? +ShowReadmeCheck=Ja, jeg vil se p LESMEG-filen +YesRadio=&Ja, start maskinen p nytt n +NoRadio=&Nei, jeg vil starte maskinen p nytt senere +; used for example as 'Run MyProg.exe' +RunEntryExec=Kjr %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Se p %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Trenger neste diskett +SelectDiskLabel2=Vennligst sett inn diskett %1 og klikk OK.%n%nHvis filene p finnes et annet sted enn det som er angitt nedenfor, kan du skrive inn korrekt bane eller klikke p Bla Gjennom. +PathLabel=&Bane: +FileNotInDir2=Finner ikke filen "%1" i "%2". Vennligst sett inn riktig diskett eller velg en annen mappe. +SelectDirectoryLabel=Vennligst angi hvor den neste disketten er. + +; *** Installation phase messages +SetupAborted=Installasjonen ble avbrutt.%n%nVennligst korriger problemet og prv igjen. +AbortRetryIgnoreSelectAction=Velg aksjon +AbortRetryIgnoreRetry=&Prv Igjen +AbortRetryIgnoreIgnore=&Ignorer feil og fortsett +AbortRetryIgnoreCancel=Cancel installation + +; *** Installation status messages +StatusClosingApplications=Lukker applikasjoner... +StatusCreateDirs=Lager mapper... +StatusExtractFiles=Pakker ut filer... +StatusCreateIcons=Lager programikoner... +StatusCreateIniEntries=Lager INI-instillinger... +StatusCreateRegistryEntries=Lager innstillinger i registeret... +StatusRegisterFiles=Registrerer filer... +StatusSavingUninstall=Lagrer info for avinstallering... +StatusRunProgram=Gjr ferdig installasjonen... +StatusRestartingApplications=Restarter applikasjoner... +StatusRollback=Tilbakestiller forandringer... + +; *** Misc. errors +ErrorInternal2=Intern feil %1 +ErrorFunctionFailedNoCode=%1 gikk galt +ErrorFunctionFailed=%1 gikk galt; kode %2 +ErrorFunctionFailedWithMessage=%1 gikk galt; kode %2.%n%3 +ErrorExecutingProgram=Kan ikke kjre filen:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Feil under pning av registernkkel:%n%1\%2 +ErrorRegCreateKey=Feil under laging av registernkkel:%n%1\%2 +ErrorRegWriteKey=Feil under skriving til registernkkel:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Feil under laging av innstilling i filen "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Hopp over denne filen (ikke anbefalt) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorer feilen og fortsett (ikke anbefalt) +SourceIsCorrupted=Kildefilen er delagt +SourceDoesntExist=Kildefilen "%1" finnes ikke +ExistingFileReadOnly2=Den eksisterende filen er skrivebeskyttet og kan ikke erstattes. +ExistingFileReadOnlyRetry=&Fjern skrivebeskyttelse og prv igjen +ExistingFileReadOnlyKeepExisting=&Behold eksisterende fil +ErrorReadingExistingDest=En feil oppsto under lesing av den eksisterende filen: +FileExistsSelectAction=Velg aksjon +FileExists2=Filen eksisterer allerede. +FileExistsOverwriteExisting=&Overskriv den eksisterende filen +FileExistsKeepExisting=&Behold den eksisterende filen +FileExistsOverwriteOrKeepAll=&Gjr samme valg for pflgende konflikter +ExistingFileNewerSelectAction=Velg aksjon +ExistingFileNewer2=Den eksisterende filen er nyere enn filen Installasjonen prver installere. +ExistingFileNewerOverwriteExisting=&Overskriv den eksisterende filen +ExistingFileNewerKeepExisting=&Behold den eksisterende filen (anbefalt) +ExistingFileNewerOverwriteOrKeepAll=&Gjr samme valg for pflgende konflikter +ErrorChangingAttr=En feil oppsto da attributtene ble forskt forandret p den eksisterende filen: +ErrorCreatingTemp=En feil oppsto under forsket p lage en fil i ml-mappen: +ErrorReadingSource=En feil oppsto under forsket p lese kildefilen: +ErrorCopying=En feil oppsto under forsk p kopiere en fil: +ErrorReplacingExistingFile=En feil oppsto under forsket p erstatte den eksisterende filen: +ErrorRestartReplace=RestartReplace gikk galt: +ErrorRenamingTemp=En feil oppsto under omdping av fil i ml-mappen: +ErrorRegisterServer=Kan ikke registrere DLL/OCX: %1 +ErrorRegSvr32Failed=RegSvr32 gikk galt med avslutte kode %1 +ErrorRegisterTypeLib=Kan ikke registrere typebiblioteket: %1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Alle brukere +UninstallDisplayNameMarkCurrentUser=Aktiv bruker + +; *** Post-installation errors +ErrorOpeningReadme=En feil oppsto under forsket p pne LESMEG-filen. +ErrorRestartingComputer=Installasjonsprogrammet kunne ikke starte maskinen p nytt. Vennligst gjr dette manuelt. + +; *** Uninstaller messages +UninstallNotFound=Filen "%1" finnes ikke. Kan ikke avinstallere. +UninstallOpenError=Filen "%1" kunne ikke pnes. Kan ikke avinstallere. +UninstallUnsupportedVer=Kan ikke avinstallere. Avinstallasjons-loggfilen "%1" har et format som ikke gjenkjennes av denne versjonen av avinstallasjons-programmet +UninstallUnknownEntry=Et ukjent parameter (%1) ble funnet i Avinstallasjons-loggfilen +ConfirmUninstall=Er du sikker p at du helt vil fjerne %1 og alle tilhrende komponenter? +UninstallOnlyOnWin64=Denne installasjonen kan bare ufres p 64-bit Windows. +OnlyAdminCanUninstall=Denne installasjonen kan bare avinstalleres av en bruker med Administrator-rettigheter. +UninstallStatusLabel=Vennligst vent mens %1 fjernes fra maskinen. +UninstalledAll=Avinstallasjonen av %1 var vellykket +UninstalledMost=Avinstallasjonen av %1 er ferdig.%n%nEnkelte elementer kunne ikke fjernes. Disse kan fjernes manuelt. +UninstalledAndNeedsRestart=Du m starte maskinen p nytt for fullfre installasjonen av %1.%n%nVil du starte p nytt n? +UninstallDataCorrupted="%1"-filen er delagt. Kan ikke avinstallere. + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Fjerne delte filer? +ConfirmDeleteSharedFile2=Systemet indikerer at den flgende filen ikke lengre brukes av andre programmer. Vil du at avinstalleringsprogrammet skal fjerne den delte filen?%n%nHvis andre programmer bruker denne filen, kan du risikere at de ikke lengre vil virke som de skal. Velg Nei hvis du er usikker. Det vil ikke gjre noen skade hvis denne filen ligger p din maskin. +SharedFileNameLabel=Filnavn: +SharedFileLocationLabel=Plassering: +WizardUninstalling=Avinstallerings-status: +StatusUninstalling=Avinstallerer %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Installerer %1. +ShutdownBlockReasonUninstallingApp=Avinstallerer %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 versjon %2 +AdditionalIcons=Ekstra-ikoner: +CreateDesktopIcon=Lag ikon p &skrivebordet +CreateQuickLaunchIcon=Lag et &Hurtigstarts-ikon +ProgramOnTheWeb=%1 p nettet +UninstallProgram=Avinstaller %1 +LaunchProgram=Kjr %1 +AssocFileExtension=&Koble %1 med filetternavnet %2 +AssocingFileExtension=Kobler %1 med filetternavnet %2... +AutoStartProgramGroupDescription=Oppstart: +AutoStartProgram=Start %1 automatisk +AddonHostProgramNotFound=%1 ble ikke funnet i katalogen du valgte.%n%nVil du fortsette likevel? \ No newline at end of file diff --git a/installer/innosetup/Languages/Polish.isl b/installer/innosetup/Languages/Polish.isl new file mode 100644 index 000000000..b10281425 --- /dev/null +++ b/installer/innosetup/Languages/Polish.isl @@ -0,0 +1,377 @@ +; *** Inno Setup version 6.1.0+ Polish messages *** +; Krzysztof Cynarski +; Proofreading, corrections and 5.5.7-6.1.0+ updates: +; ukasz Abramczuk +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). +; last update: 2020/07/26 + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Polski +LanguageID=$0415 +LanguageCodePage=1250 + +[Messages] + +; *** Application titles +SetupAppTitle=Instalator +SetupWindowTitle=Instalacja - %1 +UninstallAppTitle=Dezinstalator +UninstallAppFullTitle=Dezinstalacja - %1 + +; *** Misc. common +InformationTitle=Informacja +ConfirmTitle=Potwierd +ErrorTitle=Bd + +; *** SetupLdr messages +SetupLdrStartupMessage=Ten program zainstaluje aplikacj %1. Czy chcesz kontynuowa? +LdrCannotCreateTemp=Nie mona utworzy pliku tymczasowego. Instalacja przerwana +LdrCannotExecTemp=Nie mona uruchomi pliku z folderu tymczasowego. Instalacja przerwana +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nBd %2: %3 +SetupFileMissing=W folderze instalacyjnym brakuje pliku %1.%nProsz o przywrcenie brakujcych plikw lub uzyskanie nowej kopii programu instalacyjnego. +SetupFileCorrupt=Pliki instalacyjne s uszkodzone. Zaleca si uzyskanie nowej kopii programu instalacyjnego. +SetupFileCorruptOrWrongVer=Pliki instalacyjne s uszkodzone lub niezgodne z t wersj instalatora. Prosz rozwiza problem lub uzyska now kopi programu instalacyjnego. +InvalidParameter=W linii komend przekazano nieprawidowy parametr:%n%n%1 +SetupAlreadyRunning=Instalator jest ju uruchomiony. +WindowsVersionNotSupported=Ta aplikacja nie wspiera aktualnie uruchomionej wersji Windows. +WindowsServicePackRequired=Ta aplikacja wymaga systemu %1 z dodatkiem Service Pack %2 lub nowszym. +NotOnThisPlatform=Tej aplikacji nie mona uruchomi w systemie %1. +OnlyOnThisPlatform=Ta aplikacja wymaga systemu %1. +OnlyOnTheseArchitectures=Ta aplikacja moe by uruchomiona tylko w systemie Windows zaprojektowanym dla procesorw o architekturze:%n%n%1 +WinVersionTooLowError=Ta aplikacja wymaga systemu %1 w wersji %2 lub nowszej. +WinVersionTooHighError=Ta aplikacja nie moe by zainstalowana w systemie %1 w wersji %2 lub nowszej. +AdminPrivilegesRequired=Aby przeprowadzi instalacj tej aplikacji, konto uytkownika systemu musi posiada uprawnienia administratora. +PowerUserPrivilegesRequired=Aby przeprowadzi instalacj tej aplikacji, konto uytkownika systemu musi posiada uprawnienia administratora lub uytkownika zaawansowanego. +SetupAppRunningError=Instalator wykry, i aplikacja %1 jest aktualnie uruchomiona.%n%nPrzed wciniciem przycisku OK zamknij wszystkie procesy aplikacji. Kliknij przycisk Anuluj, aby przerwa instalacj. +UninstallAppRunningError=Dezinstalator wykry, i aplikacja %1 jest aktualnie uruchomiona.%n%nPrzed wciniciem przycisku OK zamknij wszystkie procesy aplikacji. Kliknij przycisk Anuluj, aby przerwa dezinstalacj. + +; *** Startup questions --- +PrivilegesRequiredOverrideTitle=Wybierz typ instalacji aplikacji +PrivilegesRequiredOverrideInstruction=Wybierz typ instalacji +PrivilegesRequiredOverrideText1=Aplikacja %1 moe zosta zainstalowana dla wszystkich uytkownikw (wymagane s uprawnienia administratora) lub tylko dla biecego uytkownika. +PrivilegesRequiredOverrideText2=Aplikacja %1 moe zosta zainstalowana dla biecego uytkownika lub wszystkich uytkownikw (wymagane s uprawnienia administratora). +PrivilegesRequiredOverrideAllUsers=Zainstaluj dla &wszystkich uytkownikw +PrivilegesRequiredOverrideAllUsersRecommended=Zainstaluj dla &wszystkich uytkownikw (zalecane) +PrivilegesRequiredOverrideCurrentUser=Zainstaluj dla &biecego uytkownika +PrivilegesRequiredOverrideCurrentUserRecommended=Zainstaluj dla &biecego uytkownika (zalecane) + +; *** Misc. errors +ErrorCreatingDir=Instalator nie mg utworzy katalogu "%1" +ErrorTooManyFilesInDir=Nie mona utworzy pliku w katalogu "%1", poniewa zawiera on zbyt wiele plikw + +; *** Setup common messages +ExitSetupTitle=Zakocz instalacj +ExitSetupMessage=Instalacja nie zostaa zakoczona. Jeeli przerwiesz j teraz, aplikacja nie zostanie zainstalowana. Mona ponowi instalacj pniej poprzez uruchamianie instalatora.%n%nCzy chcesz przerwa instalacj? +AboutSetupMenuItem=&O instalatorze... +AboutSetupTitle=O instalatorze +AboutSetupMessage=%1 wersja %2%n%3%n%n Strona domowa %1:%n%4 +AboutSetupNote= +TranslatorNote=Wersja polska: Krzysztof Cynarski%n%nOd wersji 5.5.7: ukasz Abramczuk%n + +; *** Buttons +ButtonBack=< &Wstecz +ButtonNext=&Dalej > +ButtonInstall=&Instaluj +ButtonOK=OK +ButtonCancel=Anuluj +ButtonYes=&Tak +ButtonYesToAll=Tak na &wszystkie +ButtonNo=&Nie +ButtonNoToAll=N&ie na wszystkie +ButtonFinish=&Zakocz +ButtonBrowse=&Przegldaj... +ButtonWizardBrowse=P&rzegldaj... +ButtonNewFolder=&Utwrz nowy folder + +; *** "Select Language" dialog messages +SelectLanguageTitle=Jzyk instalacji +SelectLanguageLabel=Wybierz jzyk uywany podczas instalacji: + +; *** Common wizard text +ClickNext=Kliknij przycisk Dalej, aby kontynuowa, lub Anuluj, aby zakoczy instalacj. +BeveledLabel= +BrowseDialogTitle=Wska folder +BrowseDialogLabel=Wybierz folder z poniszej listy, a nastpnie kliknij przycisk OK. +NewFolderName=Nowy folder + +; *** "Welcome" wizard page +WelcomeLabel1=Witamy w instalatorze aplikacji [name] +WelcomeLabel2=Aplikacja [name/ver] zostanie teraz zainstalowana na komputerze.%n%nZalecane jest zamknicie wszystkich innych uruchomionych programw przed rozpoczciem procesu instalacji. + +; *** "Password" wizard page +WizardPassword=Haso +PasswordLabel1=Ta instalacja jest zabezpieczona hasem. +PasswordLabel3=Podaj haso, a nastpnie kliknij przycisk Dalej, aby kontynuowa. W hasach rozrniane s wielkie i mae litery. +PasswordEditLabel=&Haso: +IncorrectPassword=Wprowadzone haso jest nieprawidowe. Sprbuj ponownie. + +; *** "License Agreement" wizard page +WizardLicense=Umowa Licencyjna +LicenseLabel=Przed kontynuacj naley zapozna si z ponisz wan informacj. +LicenseLabel3=Prosz przeczyta tekst Umowy Licencyjnej. Przed kontynuacj instalacji naley zaakceptowa warunki umowy. +LicenseAccepted=&Akceptuj warunki umowy +LicenseNotAccepted=&Nie akceptuj warunkw umowy + +; *** "Information" wizard pages +WizardInfoBefore=Informacja +InfoBeforeLabel=Przed kontynuacj naley zapozna si z ponisz informacj. +InfoBeforeClickLabel=Kiedy bdziesz gotowy do instalacji, kliknij przycisk Dalej. +WizardInfoAfter=Informacja +InfoAfterLabel=Przed kontynuacj naley zapozna si z ponisz informacj. +InfoAfterClickLabel=Gdy bdziesz gotowy do zakoczenia instalacji, kliknij przycisk Dalej. + +; *** "User Information" wizard page +WizardUserInfo=Dane uytkownika +UserInfoDesc=Prosz poda swoje dane. +UserInfoName=Nazwa &uytkownika: +UserInfoOrg=&Organizacja: +UserInfoSerial=Numer &seryjny: +UserInfoNameRequired=Nazwa uytkownika jest wymagana. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Lokalizacja docelowa +SelectDirDesc=Gdzie ma zosta zainstalowana aplikacja [name]? +SelectDirLabel3=Instalator zainstaluje aplikacj [name] do wskazanego poniej folderu. +SelectDirBrowseLabel=Kliknij przycisk Dalej, aby kontynuowa. Jeli chcesz wskaza inny folder, kliknij przycisk Przegldaj. +DiskSpaceGBLabel=Instalacja wymaga przynajmniej [gb] GB wolnego miejsca na dysku. +DiskSpaceMBLabel=Instalacja wymaga przynajmniej [mb] MB wolnego miejsca na dysku. +CannotInstallToNetworkDrive=Instalator nie moe zainstalowa aplikacji na dysku sieciowym. +CannotInstallToUNCPath=Instalator nie moe zainstalowa aplikacji w ciece UNC. +InvalidPath=Naley wprowadzi pen ciek wraz z liter dysku, np.:%n%nC:\PROGRAM%n%nlub ciek sieciow (UNC) w formacie:%n%n\\serwer\udzia +InvalidDrive=Wybrany dysk lub udostpniony folder sieciowy nie istnieje. Prosz wybra inny. +DiskSpaceWarningTitle=Niewystarczajca ilo wolnego miejsca na dysku +DiskSpaceWarning=Instalator wymaga co najmniej %1 KB wolnego miejsca na dysku. Wybrany dysk posiada tylko %2 KB dostpnego miejsca.%n%nCzy mimo to chcesz kontynuowa? +DirNameTooLong=Nazwa folderu lub cieki jest za duga. +InvalidDirName=Niepoprawna nazwa folderu. +BadDirName32=Nazwa folderu nie moe zawiera adnego z nastpujcych znakw:%n%n%1 +DirExistsTitle=Folder ju istnieje +DirExists=Poniszy folder ju istnieje:%n%n%1%n%nCzy mimo to chcesz zainstalowa aplikacj w tym folderze? +DirDoesntExistTitle=Folder nie istnieje +DirDoesntExist=Poniszy folder nie istnieje:%n%n%1%n%nCzy chcesz, aby zosta utworzony? + +; *** "Select Components" wizard page +WizardSelectComponents=Komponenty instalacji +SelectComponentsDesc=Ktre komponenty maj zosta zainstalowane? +SelectComponentsLabel2=Zaznacz komponenty, ktre chcesz zainstalowa i odznacz te, ktrych nie chcesz zainstalowa. Kliknij przycisk Dalej, aby kontynuowa. +FullInstallation=Instalacja pena +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Instalacja podstawowa +CustomInstallation=Instalacja uytkownika +NoUninstallWarningTitle=Zainstalowane komponenty +NoUninstallWarning=Instalator wykry, e na komputerze s ju zainstalowane nastpujce komponenty:%n%n%1%n%nOdznaczenie ktregokolwiek z nich nie spowoduje ich dezinstalacji.%n%nCzy pomimo tego chcesz kontynuowa? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Wybrane komponenty wymagaj co najmniej [gb] GB na dysku. +ComponentsDiskSpaceMBLabel=Wybrane komponenty wymagaj co najmniej [mb] MB na dysku. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Zadania dodatkowe +SelectTasksDesc=Ktre zadania dodatkowe maj zosta wykonane? +SelectTasksLabel2=Zaznacz dodatkowe zadania, ktre instalator ma wykona podczas instalacji aplikacji [name], a nastpnie kliknij przycisk Dalej, aby kontynuowa. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Folder Menu Start +SelectStartMenuFolderDesc=Gdzie maj zosta umieszczone skrty do aplikacji? +SelectStartMenuFolderLabel3=Instalator utworzy skrty do aplikacji we wskazanym poniej folderze Menu Start. +SelectStartMenuFolderBrowseLabel=Kliknij przycisk Dalej, aby kontynuowa. Jeli chcesz wskaza inny folder, kliknij przycisk Przegldaj. +MustEnterGroupName=Musisz wprowadzi nazw folderu. +GroupNameTooLong=Nazwa folderu lub cieki jest za duga. +InvalidGroupName=Niepoprawna nazwa folderu. +BadGroupName=Nazwa folderu nie moe zawiera adnego z nastpujcych znakw:%n%n%1 +NoProgramGroupCheck2=&Nie twrz folderu w Menu Start + +; *** "Ready to Install" wizard page +WizardReady=Gotowy do rozpoczcia instalacji +ReadyLabel1=Instalator jest ju gotowy do rozpoczcia instalacji aplikacji [name] na komputerze. +ReadyLabel2a=Kliknij przycisk Instaluj, aby rozpocz instalacj lub Wstecz, jeli chcesz przejrze lub zmieni ustawienia. +ReadyLabel2b=Kliknij przycisk Instaluj, aby kontynuowa instalacj. +ReadyMemoUserInfo=Dane uytkownika: +ReadyMemoDir=Lokalizacja docelowa: +ReadyMemoType=Rodzaj instalacji: +ReadyMemoComponents=Wybrane komponenty: +ReadyMemoGroup=Folder w Menu Start: +ReadyMemoTasks=Dodatkowe zadania: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Pobieranie dodatkowych plikw... +ButtonStopDownload=&Zatrzymaj pobieranie +StopDownload=Czy na pewno chcesz zatrzyma pobieranie? +ErrorDownloadAborted=Pobieranie przerwane +ErrorDownloadFailed=Bd pobierania: %1 %2 +ErrorDownloadSizeFailed=Pobieranie informacji o rozmiarze nie powiodo si: %1 %2 +ErrorFileHash1=Bd sumy kontrolnej pliku: %1 +ErrorFileHash2=Nieprawidowa suma kontrolna pliku: oczekiwano %1, otrzymano %2 +ErrorProgress=Nieprawidowy postp: %1 z %2 +ErrorFileSize=Nieprawidowy rozmiar pliku: oczekiwano %1, otrzymano %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Przygotowanie do instalacji +PreparingDesc=Instalator przygotowuje instalacj aplikacji [name] na komputerze. +PreviousInstallNotCompleted=Instalacja/dezinstalacja poprzedniej wersji aplikacji nie zostaa zakoczona. Aby zakoczy instalacj, naley ponownie uruchomi komputer. %n%nNastpnie ponownie uruchom instalator, aby zakoczy instalacj aplikacji [name]. +CannotContinue=Instalator nie moe kontynuowa. Kliknij przycisk Anuluj, aby przerwa instalacj. +ApplicationsFound=Ponisze aplikacje uywaj plikw, ktre musz zosta uaktualnione przez instalator. Zaleca si zezwoli na automatyczne zamknicie tych aplikacji przez program instalacyjny. +ApplicationsFound2=Ponisze aplikacje uywaj plikw, ktre musz zosta uaktualnione przez instalator. Zaleca si zezwoli na automatyczne zamknicie tych aplikacji przez program instalacyjny. Po zakoczonej instalacji instalator podejmie prb ich ponownego uruchomienia. +CloseApplications=&Automatycznie zamknij aplikacje +DontCloseApplications=&Nie zamykaj aplikacji +ErrorCloseApplications=Instalator nie by w stanie automatycznie zamkn wymaganych aplikacji. Zalecane jest zamknicie wszystkich aplikacji, ktre aktualnie uywaj uaktualnianych przez program instalacyjny plikw. +PrepareToInstallNeedsRestart=Instalator wymaga ponownego uruchomienia komputera. Po restarcie komputera uruchom instalator ponownie, by dokoczy proces instalacji aplikacji [name].%n%nCzy chcesz teraz uruchomi komputer ponownie? + +; *** "Installing" wizard page +WizardInstalling=Instalacja +InstallingLabel=Poczekaj, a instalator zainstaluje aplikacj [name] na komputerze. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Zakoczono instalacj aplikacji [name] +FinishedLabelNoIcons=Instalator zakoczy instalacj aplikacji [name] na komputerze. +FinishedLabel=Instalator zakoczy instalacj aplikacji [name] na komputerze. Aplikacja moe by uruchomiona poprzez uycie zainstalowanych skrtw. +ClickFinish=Kliknij przycisk Zakocz, aby zakoczy instalacj. +FinishedRestartLabel=Aby zakoczy instalacj aplikacji [name], instalator musi ponownie uruchomi komputer. Czy chcesz teraz uruchomi komputer ponownie? +FinishedRestartMessage=Aby zakoczy instalacj aplikacji [name], instalator musi ponownie uruchomi komputer.%n%nCzy chcesz teraz uruchomi komputer ponownie? +ShowReadmeCheck=Tak, chc przeczyta dodatkowe informacje +YesRadio=&Tak, uruchom ponownie teraz +NoRadio=&Nie, uruchomi ponownie pniej +; used for example as 'Run MyProg.exe' +RunEntryExec=Uruchom aplikacj %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Wywietl plik %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Instalator potrzebuje kolejnego archiwum +SelectDiskLabel2=Prosz woy dysk %1 i klikn przycisk OK.%n%nJeli wymieniony poniej folder nie okrela pooenia plikw z tego dysku, prosz wprowadzi poprawn ciek lub klikn przycisk Przegldaj. +PathLabel=&cieka: +FileNotInDir2=cieka "%2" nie zawiera pliku "%1". Prosz woy waciwy dysk lub wybra inny folder. +SelectDirectoryLabel=Prosz okreli lokalizacj kolejnego archiwum instalatora. + +; *** Installation phase messages +SetupAborted=Instalacja nie zostaa zakoczona.%n%nProsz rozwiza problem i ponownie rozpocz instalacj. +AbortRetryIgnoreSelectAction=Wybierz operacj +AbortRetryIgnoreRetry=Sprbuj &ponownie +AbortRetryIgnoreIgnore=Z&ignoruj bd i kontynuuj +AbortRetryIgnoreCancel=Przerwij instalacj + +; *** Installation status messages +StatusClosingApplications=Zamykanie aplikacji... +StatusCreateDirs=Tworzenie folderw... +StatusExtractFiles=Dekompresja plikw... +StatusCreateIcons=Tworzenie skrtw aplikacji... +StatusCreateIniEntries=Tworzenie zapisw w plikach INI... +StatusCreateRegistryEntries=Tworzenie zapisw w rejestrze... +StatusRegisterFiles=Rejestracja plikw... +StatusSavingUninstall=Zapisywanie informacji o dezinstalacji... +StatusRunProgram=Koczenie instalacji... +StatusRestartingApplications=Ponowne uruchamianie aplikacji... +StatusRollback=Cofanie zmian... + +; *** Misc. errors +ErrorInternal2=Wewntrzny bd: %1 +ErrorFunctionFailedNoCode=Bd podczas wykonywania %1 +ErrorFunctionFailed=Bd podczas wykonywania %1; kod %2 +ErrorFunctionFailedWithMessage=Bd podczas wykonywania %1; kod %2.%n%3 +ErrorExecutingProgram=Nie mona uruchomi:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Bd podczas otwierania klucza rejestru:%n%1\%2 +ErrorRegCreateKey=Bd podczas tworzenia klucza rejestru:%n%1\%2 +ErrorRegWriteKey=Bd podczas zapisu do klucza rejestru:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Bd podczas tworzenia pozycji w pliku INI: "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Pomi plik (niezalecane) +FileAbortRetryIgnoreIgnoreNotRecommended=Z&ignoruj bd i kontynuuj (niezalecane) +SourceIsCorrupted=Plik rdowy jest uszkodzony +SourceDoesntExist=Plik rdowy "%1" nie istnieje +ExistingFileReadOnly2=Istniejcy plik nie moe zosta zastpiony, gdy jest oznaczony jako "Tylko do odczytu". +ExistingFileReadOnlyRetry=&Usu atrybut "Tylko do odczytu" i sprbuj ponownie +ExistingFileReadOnlyKeepExisting=&Zachowaj istniejcy plik +ErrorReadingExistingDest=Wystpi bd podczas prby odczytu istniejcego pliku: +FileExistsSelectAction=Wybierz czynno +FileExists2=Plik ju istnieje. +FileExistsOverwriteExisting=&Nadpisz istniejcy plik +FileExistsKeepExisting=&Zachowaj istniejcy plik +FileExistsOverwriteOrKeepAll=&Wykonaj t czynno dla kolejnych przypadkw +ExistingFileNewerSelectAction=Wybierz czynno +ExistingFileNewer2=Istniejcy plik jest nowszy ni ten, ktry instalator prbuje skopiowa. +ExistingFileNewerOverwriteExisting=&Nadpisz istniejcy plik +ExistingFileNewerKeepExisting=&Zachowaj istniejcy plik (zalecane) +ExistingFileNewerOverwriteOrKeepAll=&Wykonaj t czynno dla kolejnych przypadkw +ErrorChangingAttr=Wystpi bd podczas prby zmiany atrybutw pliku docelowego: +ErrorCreatingTemp=Wystpi bd podczas prby utworzenia pliku w folderze docelowym: +ErrorReadingSource=Wystpi bd podczas prby odczytu pliku rdowego: +ErrorCopying=Wystpi bd podczas prby kopiowania pliku: +ErrorReplacingExistingFile=Wystpi bd podczas prby zamiany istniejcego pliku: +ErrorRestartReplace=Prba zastpienia plikw przy ponownym uruchomieniu komputera nie powioda si. +ErrorRenamingTemp=Wystpi bd podczas prby zmiany nazwy pliku w folderze docelowym: +ErrorRegisterServer=Nie mona zarejestrowa DLL/OCX: %1 +ErrorRegSvr32Failed=Funkcja RegSvr32 zakoczya si z kodem bdu %1 +ErrorRegisterTypeLib=Nie mog zarejestrowa biblioteki typw: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=wersja 32-bitowa +UninstallDisplayNameMark64Bit=wersja 64-bitowa +UninstallDisplayNameMarkAllUsers=wszyscy uytkownicy +UninstallDisplayNameMarkCurrentUser=biecy uytkownik + +; *** Post-installation errors +ErrorOpeningReadme=Wystpi bd podczas prby otwarcia pliku z informacjami dodatkowymi. +ErrorRestartingComputer=Instalator nie mg ponownie uruchomi tego komputera. Prosz wykona t czynno samodzielnie. + +; *** Uninstaller messages +UninstallNotFound=Plik "%1" nie istnieje. Nie mona przeprowadzi dezinstalacji. +UninstallOpenError=Plik "%1" nie mg zosta otwarty. Nie mona przeprowadzi dezinstalacji. +UninstallUnsupportedVer=Ta wersja programu dezinstalacyjnego nie rozpoznaje formatu logu dezinstalacji w pliku "%1". Nie mona przeprowadzi dezinstalacji. +UninstallUnknownEntry=W logu dezinstalacji wystpia nieznana pozycja (%1) +ConfirmUninstall=Czy na pewno chcesz usun aplikacj %1 i wszystkie jej skadniki? +UninstallOnlyOnWin64=Ta aplikacja moe by odinstalowana tylko w 64-bitowej wersji systemu Windows. +OnlyAdminCanUninstall=Ta instalacja moe by odinstalowana tylko przez uytkownika z uprawnieniami administratora. +UninstallStatusLabel=Poczekaj, a aplikacja %1 zostanie usunita z komputera. +UninstalledAll=Aplikacja %1 zostaa usunita z komputera. +UninstalledMost=Dezinstalacja aplikacji %1 zakoczya si.%n%nNiektre elementy nie mogy zosta usunite. Naley usun je samodzielnie. +UninstalledAndNeedsRestart=Komputer musi zosta ponownie uruchomiony, aby zakoczy proces dezinstalacji aplikacji %1.%n%nCzy chcesz teraz ponownie uruchomi komputer? +UninstallDataCorrupted=Plik "%1" jest uszkodzony. Nie mona przeprowadzi dezinstalacji. + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Usun plik wspdzielony? +ConfirmDeleteSharedFile2=System wskazuje, i nastpujcy plik nie jest ju uywany przez aden program. Czy chcesz odinstalowa ten plik wspdzielony?%n%nJeli inne programy nadal uywaj tego pliku, a zostanie on usunity, mog one przesta dziaa prawidowo. W przypadku braku pewnoci, kliknij przycisk Nie. Pozostawienie tego pliku w systemie nie spowoduje adnych szkd. +SharedFileNameLabel=Nazwa pliku: +SharedFileLocationLabel=Pooenie: +WizardUninstalling=Stan dezinstalacji +StatusUninstalling=Dezinstalacja aplikacji %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Instalacja aplikacji %1. +ShutdownBlockReasonUninstallingApp=Dezinstalacja aplikacji %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 (wersja %2) +AdditionalIcons=Dodatkowe skrty: +CreateDesktopIcon=Utwrz skrt na &pulpicie +CreateQuickLaunchIcon=Utwrz skrt na pasku &szybkiego uruchamiania +ProgramOnTheWeb=Strona internetowa aplikacji %1 +UninstallProgram=Dezinstalacja aplikacji %1 +LaunchProgram=Uruchom aplikacj %1 +AssocFileExtension=&Przypisz aplikacj %1 do rozszerzenia pliku %2 +AssocingFileExtension=Przypisywanie aplikacji %1 do rozszerzenia pliku %2... +AutoStartProgramGroupDescription=Autostart: +AutoStartProgram=Automatycznie uruchamiaj aplikacj %1 +AddonHostProgramNotFound=Aplikacja %1 nie zostaa znaleziona we wskazanym przez Ciebie folderze.%n%nCzy pomimo tego chcesz kontynuowa? diff --git a/installer/innosetup/Languages/Portuguese.isl b/installer/innosetup/Languages/Portuguese.isl new file mode 100644 index 000000000..42d4e549c --- /dev/null +++ b/installer/innosetup/Languages/Portuguese.isl @@ -0,0 +1,366 @@ +; *** Inno Setup version 6.1.0+ Portuguese (Portugal) messages *** +; +; Maintained by Nuno Silva (nars AT gmx.net) + +[LangOptions] +LanguageName=Portugu<00EA>s (Portugal) +LanguageID=$0816 +LanguageCodePage=1252 + +[Messages] + +; *** Application titles +SetupAppTitle=Instalao +SetupWindowTitle=%1 - Instalao +UninstallAppTitle=Desinstalao +UninstallAppFullTitle=%1 - Desinstalao + +; *** Misc. common +InformationTitle=Informao +ConfirmTitle=Confirmao +ErrorTitle=Erro + +; *** SetupLdr messages +SetupLdrStartupMessage=Ir ser instalado o %1. Deseja continuar? +LdrCannotCreateTemp=No foi possvel criar um ficheiro temporrio. Instalao cancelada +LdrCannotExecTemp=No foi possvel executar um ficheiro na directoria temporria. Instalao cancelada +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nErro %2: %3 +SetupFileMissing=O ficheiro %1 no foi encontrado na pasta de instalao. Corrija o problema ou obtenha uma nova cpia do programa. +SetupFileCorrupt=Os ficheiros de instalao esto corrompidos. Obtenha uma nova cpia do programa. +SetupFileCorruptOrWrongVer=Os ficheiros de instalao esto corrompidos, ou so incompatveis com esta verso do Assistente de Instalao. Corrija o problema ou obtenha uma nova cpia do programa. +InvalidParameter=Foi especificado um parmetro invlido na linha de comando:%n%n%1 +SetupAlreadyRunning=A instalao j est em execuo. +WindowsVersionNotSupported=Este programa no suporta a verso do Windows que est a utilizar. +WindowsServicePackRequired=Este programa necessita de %1 Service Pack %2 ou mais recente. +NotOnThisPlatform=Este programa no pode ser executado no %1. +OnlyOnThisPlatform=Este programa deve ser executado no %1. +OnlyOnTheseArchitectures=Este programa s pode ser instalado em verses do Windows preparadas para as seguintes arquitecturas:%n%n%1 +WinVersionTooLowError=Este programa necessita do %1 verso %2 ou mais recente. +WinVersionTooHighError=Este programa no pode ser instalado no %1 verso %2 ou mais recente. +AdminPrivilegesRequired=Deve iniciar sesso como administrador para instalar este programa. +PowerUserPrivilegesRequired=Deve iniciar sesso como administrador ou membro do grupo de Super Utilizadores para instalar este programa. +SetupAppRunningError=O Assistente de Instalao detectou que o %1 est em execuo. Feche-o e de seguida clique em OK para continuar, ou clique em Cancelar para cancelar a instalao. +UninstallAppRunningError=O Assistente de Desinstalao detectou que o %1 est em execuo. Feche-o e de seguida clique em OK para continuar, ou clique em Cancelar para cancelar a desinstalao. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Seleccione o Modo de Instalao +PrivilegesRequiredOverrideInstruction=Seleccione o Modo de Instalao +PrivilegesRequiredOverrideText1=%1 pode ser instalado para todos os utilizadores (necessita de privilgios administrativos), ou s para si. +PrivilegesRequiredOverrideText2=%1 pode ser instalado s para si, ou para todos os utilizadores (necessita de privilgios administrativos). +PrivilegesRequiredOverrideAllUsers=Instalar para &todos os utilizadores +PrivilegesRequiredOverrideAllUsersRecommended=Instalar para &todos os utilizadores (recomendado) +PrivilegesRequiredOverrideCurrentUser=Instalar apenas para &mim +PrivilegesRequiredOverrideCurrentUserRecommended=Instalar apenas para &mim (recomendado) + +; *** Misc. errors +ErrorCreatingDir=O Assistente de Instalao no consegue criar a directoria "%1" +ErrorTooManyFilesInDir=No possvel criar um ficheiro na directoria "%1" porque esta contm demasiados ficheiros + +; *** Setup common messages +ExitSetupTitle=Terminar a instalao +ExitSetupMessage=A instalao no est completa. Se terminar agora, o programa no ser instalado.%n%nMais tarde poder executar novamente este Assistente de Instalao e concluir a instalao.%n%nDeseja terminar a instalao? +AboutSetupMenuItem=&Acerca de... +AboutSetupTitle=Acerca do Assistente de Instalao +AboutSetupMessage=%1 verso %2%n%3%n%n%1 home page:%n%4 +AboutSetupNote= +TranslatorNote=Portuguese translation maintained by NARS (nars@gmx.net) + +; *** Buttons +ButtonBack=< &Anterior +ButtonNext=&Seguinte > +ButtonInstall=&Instalar +ButtonOK=OK +ButtonCancel=Cancelar +ButtonYes=&Sim +ButtonYesToAll=Sim para &todos +ButtonNo=&No +ButtonNoToAll=N&o para todos +ButtonFinish=&Concluir +ButtonBrowse=&Procurar... +ButtonWizardBrowse=P&rocurar... +ButtonNewFolder=&Criar Nova Pasta + +; *** "Select Language" dialog messages +SelectLanguageTitle=Seleccione o Idioma do Assistente de Instalao +SelectLanguageLabel=Seleccione o idioma para usar durante a Instalao. + +; *** Common wizard text +ClickNext=Clique em Seguinte para continuar ou em Cancelar para cancelar a instalao. +BeveledLabel= +BrowseDialogTitle=Procurar Pasta +BrowseDialogLabel=Seleccione uma pasta na lista abaixo e clique em OK. +NewFolderName=Nova Pasta + +; *** "Welcome" wizard page +WelcomeLabel1=Bem-vindo ao Assistente de Instalao do [name] +WelcomeLabel2=O Assistente de Instalao ir instalar o [name/ver] no seu computador.%n%n recomendado que feche todas as outras aplicaes antes de continuar. + +; *** "Password" wizard page +WizardPassword=Palavra-passe +PasswordLabel1=Esta instalao est protegida por palavra-passe. +PasswordLabel3=Insira a palavra-passe e de seguida clique em Seguinte para continuar. Na palavra-passe existe diferena entre maisculas e minsculas. +PasswordEditLabel=&Palavra-passe: +IncorrectPassword=A palavra-passe que introduziu no est correcta. Tente novamente. + +; *** "License Agreement" wizard page +WizardLicense=Contrato de licena +LicenseLabel= importante que leia as seguintes informaes antes de continuar. +LicenseLabel3=Leia atentamente o seguinte contrato de licena. Deve aceitar os termos do contrato antes de continuar a instalao. +LicenseAccepted=A&ceito o contrato +LicenseNotAccepted=&No aceito o contrato + +; *** "Information" wizard pages +WizardInfoBefore=Informao +InfoBeforeLabel= importante que leia as seguintes informaes antes de continuar. +InfoBeforeClickLabel=Quando estiver pronto para continuar clique em Seguinte. +WizardInfoAfter=Informao +InfoAfterLabel= importante que leia as seguintes informaes antes de continuar. +InfoAfterClickLabel=Quando estiver pronto para continuar clique em Seguinte. + +; *** "User Information" wizard page +WizardUserInfo=Informaes do utilizador +UserInfoDesc=Introduza as suas informaes. +UserInfoName=Nome do &utilizador: +UserInfoOrg=&Organizao: +UserInfoSerial=&Nmero de srie: +UserInfoNameRequired=Deve introduzir um nome. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Seleccione a localizao de destino +SelectDirDesc=Onde dever ser instalado o [name]? +SelectDirLabel3=O [name] ser instalado na seguinte pasta. +SelectDirBrowseLabel=Para continuar, clique em Seguinte. Se desejar seleccionar uma pasta diferente, clique em Procurar. +DiskSpaceGBLabel= necessrio pelo menos [gb] GB de espao livre em disco. +DiskSpaceMBLabel= necessrio pelo menos [mb] MB de espao livre em disco. +CannotInstallToNetworkDrive=O Assistente de Instalao no pode instalar numa unidade de rede. +CannotInstallToUNCPath=O Assistente de Instalao no pode instalar num caminho UNC. +InvalidPath= necessrio indicar o caminho completo com a letra de unidade; por exemplo:%n%nC:\APP%n%nou um caminho UNC no formato:%n%n\\servidor\partilha +InvalidDrive=A unidade ou partilha UNC seleccionada no existe ou no est acessvel. Seleccione outra. +DiskSpaceWarningTitle=No h espao suficiente no disco +DiskSpaceWarning=O Assistente de Instalao necessita de pelo menos %1 KB de espao livre, mas a unidade seleccionada tem apenas %2 KB disponveis.%n%nDeseja continuar de qualquer forma? +DirNameTooLong=O nome ou caminho para a pasta demasiado longo. +InvalidDirName=O nome da pasta no vlido. +BadDirName32=O nome da pasta no pode conter nenhum dos seguintes caracteres:%n%n%1 +DirExistsTitle=A pasta j existe +DirExists=A pasta:%n%n%1%n%nj existe. Pretende instalar nesta pasta? +DirDoesntExistTitle=A pasta no existe +DirDoesntExist=A pasta:%n%n%1%n%nno existe. Pretende que esta pasta seja criada? + +; *** "Select Components" wizard page +WizardSelectComponents=Seleccione os componentes +SelectComponentsDesc=Que componentes devero ser instalados? +SelectComponentsLabel2=Seleccione os componentes que quer instalar e desseleccione os componentes que no quer instalar. Clique em Seguinte quando estiver pronto para continuar. +FullInstallation=Instalao Completa +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Instalao Compacta +CustomInstallation=Instalao Personalizada +NoUninstallWarningTitle=Componentes Encontrados +NoUninstallWarning=O Assistente de Instalao detectou que os seguintes componentes esto instalados no seu computador:%n%n%1%n%nSe desseleccionar estes componentes eles no sero desinstalados.%n%nDeseja continuar? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=A seleco actual necessita de pelo menos [gb] GB de espao em disco. +ComponentsDiskSpaceMBLabel=A seleco actual necessita de pelo menos [mb] MB de espao em disco. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Seleccione tarefas adicionais +SelectTasksDesc=Que tarefas adicionais devero ser executadas? +SelectTasksLabel2=Seleccione as tarefas adicionais que deseja que o Assistente de Instalao execute na instalao do [name] e em seguida clique em Seguinte. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Seleccione a pasta do Menu Iniciar +SelectStartMenuFolderDesc=Onde devero ser colocados os cones de atalho do programa? +SelectStartMenuFolderLabel3=Os cones de atalho do programa sero criados na seguinte pasta do Menu Iniciar. +SelectStartMenuFolderBrowseLabel=Para continuar, clique em Seguinte. Se desejar seleccionar uma pasta diferente, clique em Procurar. +MustEnterGroupName= necessrio introduzir um nome para a pasta. +GroupNameTooLong=O nome ou caminho para a pasta demasiado longo. +InvalidGroupName=O nome da pasta no vlido. +BadGroupName=O nome da pasta no pode conter nenhum dos seguintes caracteres:%n%n%1 +NoProgramGroupCheck2=&No criar nenhuma pasta no Menu Iniciar + +; *** "Ready to Install" wizard page +WizardReady=Pronto para Instalar +ReadyLabel1=O Assistente de Instalao est pronto para instalar o [name] no seu computador. +ReadyLabel2a=Clique em Instalar para continuar a instalao, ou clique em Anterior se desejar rever ou alterar alguma das configuraes. +ReadyLabel2b=Clique em Instalar para continuar a instalao. +ReadyMemoUserInfo=Informaes do utilizador: +ReadyMemoDir=Localizao de destino: +ReadyMemoType=Tipo de instalao: +ReadyMemoComponents=Componentes seleccionados: +ReadyMemoGroup=Pasta do Menu Iniciar: +ReadyMemoTasks=Tarefas adicionais: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=A transferir ficheiros adicionais... +ButtonStopDownload=&Parar transferncia +StopDownload=Tem a certeza que deseja parar a transferncia? +ErrorDownloadAborted=Transferncia cancelada +ErrorDownloadFailed=Falha na transferncia: %1 %2 +ErrorDownloadSizeFailed=Falha ao obter tamanho: %1 %2 +ErrorFileHash1=Falha de verificao do ficheiro: %1 +ErrorFileHash2=Hash do ficheiro invlida: experado %1, encontrado %2 +ErrorProgress=Progresso invlido: %1 de %2 +ErrorFileSize=Tamanho de ficheiro invlido: experado %1, encontrado %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Preparando-se para instalar +PreparingDesc=Preparando-se para instalar o [name] no seu computador. +PreviousInstallNotCompleted=A instalao/remoo de um programa anterior no foi completada. Necessitar de reiniciar o computador para completar essa instalao.%n%nDepois de reiniciar o computador, execute novamente este Assistente de Instalao para completar a instalao do [name]. +CannotContinue=A instalao no pode continuar. Clique em Cancelar para sair. +ApplicationsFound=As seguintes aplicaes esto a utilizar ficheiros que necessitam ser actualizados pelo Assistente de Instalao. recomendado que permita que o Assistente de Instalao feche estas aplicaes. +ApplicationsFound2=As seguintes aplicaes esto a utilizar ficheiros que necessitam ser actualizados pelo Assistente de Instalao. recomendado que permita que o Assistente de Instalao feche estas aplicaes. Depois de completar a instalao, o Assistente de Instalao tentar reiniciar as aplicaes. +CloseApplications=&Fechar as aplicaes automaticamente +DontCloseApplications=&No fechar as aplicaes +ErrorCloseApplications=O Assistente de Instalao no conseguiu fechar todas as aplicaes automaticamente. Antes de continuar recomendado que feche todas as aplicaes que utilizem ficheiros que necessitem de ser actualizados pelo Assistente de Instalao. +PrepareToInstallNeedsRestart=O Assistente de Instalao necessita reiniciar o seu computador. Depois de reiniciar o computador, execute novamente o Assistente de Instalao para completar a instalao do [name].%n%nDeseja reiniciar agora? + +; *** "Installing" wizard page +WizardInstalling=A instalar +InstallingLabel=Aguarde enquanto o Assistente de Instalao instala o [name] no seu computador. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Instalao do [name] concluda +FinishedLabelNoIcons=O Assistente de Instalao concluiu a instalao do [name] no seu computador. +FinishedLabel=O Assistente de Instalao concluiu a instalao do [name] no seu computador. A aplicao pode ser iniciada atravs dos cones de atalho instalados. +ClickFinish=Clique em Concluir para finalizar o Assistente de Instalao. +FinishedRestartLabel=Para completar a instalao do [name], o Assistente de Instalao dever reiniciar o seu computador. Deseja reiniciar agora? +FinishedRestartMessage=Para completar a instalao do [name], o Assistente de Instalao dever reiniciar o seu computador.%n%nDeseja reiniciar agora? +ShowReadmeCheck=Sim, desejo ver o ficheiro LEIAME +YesRadio=&Sim, desejo reiniciar o computador agora +NoRadio=&No, desejo reiniciar o computador mais tarde +; used for example as 'Run MyProg.exe' +RunEntryExec=Executar %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Visualizar %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=O Assistente de Instalao precisa do disco seguinte +SelectDiskLabel2=Introduza o disco %1 e clique em OK.%n%nSe os ficheiros deste disco estiverem num local diferente do mostrado abaixo, indique o caminho correcto ou clique em Procurar. +PathLabel=&Caminho: +FileNotInDir2=O ficheiro "%1" no foi encontrado em "%2". Introduza o disco correcto ou seleccione outra pasta. +SelectDirectoryLabel=Indique a localizao do disco seguinte. + +; *** Installation phase messages +SetupAborted=A instalao no est completa.%n%nCorrija o problema e execute o Assistente de Instalao novamente. +AbortRetryIgnoreSelectAction=Seleccione uma aco +AbortRetryIgnoreRetry=&Tentar novamente +AbortRetryIgnoreIgnore=&Ignorar o erro e continuar +AbortRetryIgnoreCancel=Cancelar a instalao + +; *** Installation status messages +StatusClosingApplications=A fechar aplicaes... +StatusCreateDirs=A criar directorias... +StatusExtractFiles=A extrair ficheiros... +StatusCreateIcons=A criar atalhos... +StatusCreateIniEntries=A criar entradas em INI... +StatusCreateRegistryEntries=A criar entradas no registo... +StatusRegisterFiles=A registar ficheiros... +StatusSavingUninstall=A guardar informaes para desinstalao... +StatusRunProgram=A concluir a instalao... +StatusRestartingApplications=A reiniciar aplicaes... +StatusRollback=A anular as alteraes... + +; *** Misc. errors +ErrorInternal2=Erro interno: %1 +ErrorFunctionFailedNoCode=%1 falhou +ErrorFunctionFailed=%1 falhou; cdigo %2 +ErrorFunctionFailedWithMessage=%1 falhou; cdigo %2.%n%3 +ErrorExecutingProgram=No possvel executar o ficheiro:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Erro ao abrir a chave de registo:%n%1\%2 +ErrorRegCreateKey=Erro ao criar a chave de registo:%n%1\%2 +ErrorRegWriteKey=Erro ao escrever na chave de registo:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Erro ao criar entradas em INI no ficheiro "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Ignorar este ficheiro (no recomendado) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorar este erro e continuar (no recomendado) +SourceIsCorrupted=O ficheiro de origem est corrompido +SourceDoesntExist=O ficheiro de origem "%1" no existe +ExistingFileReadOnly2=O ficheiro existente no pode ser substitudo porque tem o atributo "s de leitura". +ExistingFileReadOnlyRetry=&Remover o atributo "s de leitura" e tentar novamente +ExistingFileReadOnlyKeepExisting=&Manter o ficheiro existente +ErrorReadingExistingDest=Ocorreu um erro ao tentar ler o ficheiro existente: +FileExistsSelectAction=Seleccione uma aco +FileExists2=O ficheiro j existe. +FileExistsOverwriteExisting=&Substituir o ficheiro existente +FileExistsKeepExisting=&Manter o ficheiro existente +FileExistsOverwriteOrKeepAll=&Fazer isto para os prximos conflitos +ExistingFileNewerSelectAction=Seleccione uma aco +ExistingFileNewer2=O ficheiro existente mais recente que o que est a ser instalado. +ExistingFileNewerOverwriteExisting=&Substituir o ficheiro existente +ExistingFileNewerKeepExisting=&Manter o ficheiro existente (recomendado) +ExistingFileNewerOverwriteOrKeepAll=&Fazer isto para os prximos conflitos +ErrorChangingAttr=Ocorreu um erro ao tentar alterar os atributos do ficheiro existente: +ErrorCreatingTemp=Ocorreu um erro ao tentar criar um ficheiro na directoria de destino: +ErrorReadingSource=Ocorreu um erro ao tentar ler o ficheiro de origem: +ErrorCopying=Ocorreu um erro ao tentar copiar um ficheiro: +ErrorReplacingExistingFile=Ocorreu um erro ao tentar substituir o ficheiro existente: +ErrorRestartReplace=RestartReplace falhou: +ErrorRenamingTemp=Ocorreu um erro ao tentar mudar o nome de um ficheiro na directoria de destino: +ErrorRegisterServer=No possvel registar o DLL/OCX: %1 +ErrorRegSvr32Failed=O RegSvr32 falhou com o cdigo de sada %1 +ErrorRegisterTypeLib=No foi possvel registar a livraria de tipos: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Todos os utilizadores +UninstallDisplayNameMarkCurrentUser=Utilizador actual + +; *** Post-installation errors +ErrorOpeningReadme=Ocorreu um erro ao tentar abrir o ficheiro LEIAME. +ErrorRestartingComputer=O Assistente de Instalao no consegue reiniciar o computador. Por favor reinicie manualmente. + +; *** Uninstaller messages +UninstallNotFound=O ficheiro "%1" no existe. No possvel desinstalar. +UninstallOpenError=No foi possvel abrir o ficheiro "%1". No possvel desinstalar. +UninstallUnsupportedVer=O ficheiro log de desinstalao "%1" est num formato que no reconhecido por esta verso do desinstalador. No possvel desinstalar +UninstallUnknownEntry=Foi encontrada uma entrada desconhecida (%1) no ficheiro log de desinstalao +ConfirmUninstall=Tem a certeza que deseja remover completamente o %1 e todos os seus componentes? +UninstallOnlyOnWin64=Esta desinstalao s pode ser realizada na verso de 64-bit's do Windows. +OnlyAdminCanUninstall=Esta desinstalao s pode ser realizada por um utilizador com privilgios administrativos. +UninstallStatusLabel=Por favor aguarde enquanto o %1 est a ser removido do seu computador. +UninstalledAll=O %1 foi removido do seu computador com sucesso. +UninstalledMost=A desinstalao do %1 est concluda.%n%nAlguns elementos no puderam ser removidos. Estes elementos podem ser removidos manualmente. +UninstalledAndNeedsRestart=Para completar a desinstalao do %1, o computador deve ser reiniciado.%n%nDeseja reiniciar agora? +UninstallDataCorrupted=O ficheiro "%1" est corrompido. No possvel desinstalar + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Remover ficheiro partilhado? +ConfirmDeleteSharedFile2=O sistema indica que o seguinte ficheiro partilhado j no est a ser utilizado por nenhum programa. Deseja remov-lo?%n%nSe algum programa ainda necessitar deste ficheiro, poder no funcionar correctamente depois de o remover. Se no tiver a certeza, seleccione No. Manter o ficheiro no causar nenhum problema. +SharedFileNameLabel=Nome do ficheiro: +SharedFileLocationLabel=Localizao: +WizardUninstalling=Estado da desinstalao +StatusUninstalling=A desinstalar o %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=A instalar %1. +ShutdownBlockReasonUninstallingApp=A desinstalar %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 verso %2 +AdditionalIcons=Atalhos adicionais: +CreateDesktopIcon=Criar atalho no Ambiente de &Trabalho +CreateQuickLaunchIcon=&Criar atalho na barra de Iniciao Rpida +ProgramOnTheWeb=%1 na Web +UninstallProgram=Desinstalar o %1 +LaunchProgram=Executar o %1 +AssocFileExtension=Associa&r o %1 aos ficheiros com a extenso %2 +AssocingFileExtension=A associar o %1 aos ficheiros com a extenso %2... +AutoStartProgramGroupDescription=Inicializao Automtica: +AutoStartProgram=Iniciar %1 automaticamente +AddonHostProgramNotFound=No foi possvel localizar %1 na pasta seleccionada.%n%nDeseja continuar de qualquer forma? diff --git a/installer/innosetup/Languages/Russian.isl b/installer/innosetup/Languages/Russian.isl new file mode 100644 index 000000000..bf086d065 --- /dev/null +++ b/installer/innosetup/Languages/Russian.isl @@ -0,0 +1,370 @@ +; *** Inno Setup version 6.1.0+ Russian messages *** +; +; Translated from English by Dmitry Kann, yktooo at gmail.com +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +LanguageName=<0420><0443><0441><0441><043A><0438><0439> +LanguageID=$0419 +LanguageCodePage=1251 + +[Messages] + +; *** Application titles +SetupAppTitle= +SetupWindowTitle= %1 +UninstallAppTitle= +UninstallAppFullTitle= %1 + +; *** Misc. common +InformationTitle= +ConfirmTitle= +ErrorTitle= + +; *** SetupLdr messages +SetupLdrStartupMessage= %1 , ? +LdrCannotCreateTemp= . +LdrCannotExecTemp= . +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%n %2: %3 +SetupFileMissing= %1 . , . +SetupFileCorrupt= . , . +SetupFileCorruptOrWrongVer= . , . +InvalidParameter= :%n%n%1 +SetupAlreadyRunning= . +WindowsVersionNotSupported= Windows, . +WindowsServicePackRequired= %1 Service Pack %2 . +NotOnThisPlatform= %1. +OnlyOnThisPlatform= %1. +OnlyOnTheseArchitectures= Windows :%n%n%1 +WinVersionTooLowError= %1 %2 . +WinVersionTooHighError= %1 %2 . +AdminPrivilegesRequired= , . +PowerUserPrivilegesRequired= , (Power Users). +SetupAppRunningError= %1.%n%n, , OK, , , . +UninstallAppRunningError= %1.%n%n, , OK, , , . + +; *** Startup questions +PrivilegesRequiredOverrideTitle= +PrivilegesRequiredOverrideInstruction= +PrivilegesRequiredOverrideText1=%1 ( ), . +PrivilegesRequiredOverrideText2=%1 , ( ). +PrivilegesRequiredOverrideAllUsers= & +PrivilegesRequiredOverrideAllUsersRecommended= & () +PrivilegesRequiredOverrideCurrentUser= & +PrivilegesRequiredOverrideCurrentUserRecommended= & () + +; *** Misc. errors +ErrorCreatingDir= "%1" +ErrorTooManyFilesInDir= "%1", + +; *** Setup common messages +ExitSetupTitle= +ExitSetupMessage= . , .%n%n , .%n%n ? +AboutSetupMenuItem=& ... +AboutSetupTitle= +AboutSetupMessage=%1, %2%n%3%n%n %1:%n%4 +AboutSetupNote= +TranslatorNote=Russian translation by Dmitry Kann, http://www.dk-soft.org/ + +; *** Buttons +ButtonBack=< & +ButtonNext=& > +ButtonInstall=& +ButtonOK=OK +ButtonCancel= +ButtonYes=& +ButtonYesToAll= & +ButtonNo=& +ButtonNoToAll=& +ButtonFinish=& +ButtonBrowse=&... +ButtonWizardBrowse=&... +ButtonNewFolder=& + +; *** "Select Language" dialog messages +SelectLanguageTitle= +SelectLanguageLabel= , . + +; *** Common wizard text +ClickNext= , , , . +BeveledLabel= +BrowseDialogTitle= +BrowseDialogLabel= ʻ. +NewFolderName= + +; *** "Welcome" wizard page +WelcomeLabel1= [name] +WelcomeLabel2= [name/ver] .%n%n , . + +; *** "Password" wizard page +WizardPassword= +PasswordLabel1= . +PasswordLabel3=, , . . +PasswordEditLabel=&: +IncorrectPassword= . , . + +; *** "License Agreement" wizard page +WizardLicense= +LicenseLabel=, , . +LicenseLabel3=, . , . +LicenseAccepted= & +LicenseNotAccepted= & + +; *** "Information" wizard pages +WizardInfoBefore= +InfoBeforeLabel=, , . +InfoBeforeClickLabel= , . +WizardInfoAfter= +InfoAfterLabel=, , . +InfoAfterClickLabel= , . + +; *** "User Information" wizard page +WizardUserInfo= +UserInfoDesc=, . +UserInfoName=& : +UserInfoOrg=&: +UserInfoSerial=& : +UserInfoNameRequired= . + +; *** "Select Destination Location" wizard page +WizardSelectDir= +SelectDirDesc= [name]? +SelectDirLabel3= [name] . +SelectDirBrowseLabel= , . , . +DiskSpaceGBLabel= [gb] . +DiskSpaceMBLabel= [mb] . +CannotInstallToNetworkDrive= . +CannotInstallToUNCPath= UNC-. +InvalidPath= ; :%n%nC:\APP%n%n UNC:%n%n\\_\_ +InvalidDrive= . , . +DiskSpaceWarningTitle= +DiskSpaceWarning= %1 , %2 .%n%n ? +DirNameTooLong= . +InvalidDirName= . +BadDirName32= : %n%n%1 +DirExistsTitle= +DirExists=%n%n%1%n%n . ? +DirDoesntExistTitle= +DirDoesntExist=%n%n%1%n%n . ? + +; *** "Select Components" wizard page +WizardSelectComponents= +SelectComponentsDesc= ? +SelectComponentsLabel2= , ; , . , . +FullInstallation= +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation= +CustomInstallation= +NoUninstallWarningTitle= +NoUninstallWarning= , :%n%n%1%n%n .%n%n? +ComponentSize1=%1 +ComponentSize2=%1 +ComponentsDiskSpaceGBLabel= [gb] . +ComponentsDiskSpaceMBLabel= [mb] . + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks= +SelectTasksDesc= ? +SelectTasksLabel2= , [name], : + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup= +SelectStartMenuFolderDesc= ? +SelectStartMenuFolderLabel3= . +SelectStartMenuFolderBrowseLabel= , . , . +MustEnterGroupName= . +GroupNameTooLong= . +InvalidGroupName= . +BadGroupName= :%n%n%1 +NoProgramGroupCheck2=& + +; *** "Ready to Install" wizard page +WizardReady= +ReadyLabel1= [name] . +ReadyLabel2a= , , , . +ReadyLabel2b= , . +ReadyMemoUserInfo= : +ReadyMemoDir= : +ReadyMemoType= : +ReadyMemoComponents= : +ReadyMemoGroup= : +ReadyMemoTasks= : + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel= ... +ButtonStopDownload=& +StopDownload= ? +ErrorDownloadAborted= +ErrorDownloadFailed= : %1 %2 +ErrorDownloadSizeFailed= : %1 %2 +ErrorFileHash1= : %1 +ErrorFileHash2= : %1, %2 +ErrorProgress= : %1 %2 +ErrorFileSize= : %1, %2 + +; *** "Preparing to Install" wizard page +WizardPreparing= +PreparingDesc= [name] . +PreviousInstallNotCompleted= . , .%n%n , [name]. +CannotContinue= . . +ApplicationsFound= , . . +ApplicationsFound2= , . . , . +CloseApplications=& +DontCloseApplications=& +ErrorCloseApplications= . , , . +PrepareToInstallNeedsRestart= . , , , [name].%n%n ? + +; *** "Installing" wizard page +WizardInstalling=... +InstallingLabel=, , [name] . + +; *** "Setup Completed" wizard page +FinishedHeadingLabel= [name] +FinishedLabelNoIcons= [name] . +FinishedLabel= [name] . . +ClickFinish= , . +FinishedRestartLabel= [name] . ? +FinishedRestartMessage= [name] .%n%n ? +ShowReadmeCheck= README +YesRadio=&, +NoRadio=&, +; used for example as 'Run MyProg.exe' +RunEntryExec= %1 +; used for example as 'View Readme.txt' +RunEntryShellExec= %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle= +SelectDiskLabel2=, %1 OK.%n%n , , . +PathLabel=&: +FileNotInDir2= "%1" "%2". , . +SelectDirectoryLabel=, . + +; *** Installation phase messages +SetupAborted= .%n%n, . +AbortRetryIgnoreSelectAction= +AbortRetryIgnoreRetry= & +AbortRetryIgnoreIgnore=& +AbortRetryIgnoreCancel= + +; *** Installation status messages +StatusClosingApplications= ... +StatusCreateDirs= ... +StatusExtractFiles= ... +StatusCreateIcons= ... +StatusCreateIniEntries= INI-... +StatusCreateRegistryEntries= ... +StatusRegisterFiles= ... +StatusSavingUninstall= ... +StatusRunProgram= ... +StatusRestartingApplications= ... +StatusRollback= ... + +; *** Misc. errors +ErrorInternal2= : %1 +ErrorFunctionFailedNoCode=%1: +ErrorFunctionFailed=%1: ; %2 +ErrorFunctionFailedWithMessage=%1: ; %2.%n%3 +ErrorExecutingProgram= :%n%1 + +; *** Registry errors +ErrorRegOpenKey= :%n%1\%2 +ErrorRegCreateKey= :%n%1\%2 +ErrorRegWriteKey= :%n%1\%2 + +; *** INI errors +ErrorIniEntry= INI- "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=& ( ) +FileAbortRetryIgnoreIgnoreNotRecommended=& ( ) +SourceIsCorrupted= +SourceDoesntExist= "%1" +ExistingFileReadOnly2= , . +ExistingFileReadOnlyRetry=& +ExistingFileReadOnlyKeepExisting=& +ErrorReadingExistingDest= : +FileExistsSelectAction= +FileExists2= . +FileExistsOverwriteExisting=& +FileExistsKeepExisting=& +FileExistsOverwriteOrKeepAll=& +ExistingFileNewerSelectAction= +ExistingFileNewer2= , . +ExistingFileNewerOverwriteExisting=& +ExistingFileNewerKeepExisting=& () +ExistingFileNewerOverwriteOrKeepAll=& +ErrorChangingAttr= : +ErrorCreatingTemp= : +ErrorReadingSource= : +ErrorCopying= : +ErrorReplacingExistingFile= : +ErrorRestartReplace= RestartReplace: +ErrorRenamingTemp= : +ErrorRegisterServer= DLL/OCX: %1 +ErrorRegSvr32Failed= RegSvr32, %1 +ErrorRegisterTypeLib= (Type Library): %1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32 +UninstallDisplayNameMark64Bit=64 +UninstallDisplayNameMarkAllUsers= +UninstallDisplayNameMarkCurrentUser= + +; *** Post-installation errors +ErrorOpeningReadme= README. +ErrorRestartingComputer= . , . + +; *** Uninstaller messages +UninstallNotFound= "%1" , . +UninstallOpenError= "%1". +UninstallUnsupportedVer= "%1" -. +UninstallUnknownEntry= (%1) +ConfirmUninstall= %1 ? +UninstallOnlyOnWin64= 64- Windows. +OnlyAdminCanUninstall= . +UninstallStatusLabel=, , %1 . +UninstalledAll= %1 . +UninstalledMost= %1 .%n%n . . +UninstalledAndNeedsRestart= %1 .%n%n ? +UninstallDataCorrupted= "%1" . + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle= ? +ConfirmDeleteSharedFile2= , . ?%n%n - , , . , . . +SharedFileNameLabel= : +SharedFileLocationLabel=: +WizardUninstalling= +StatusUninstalling= %1... + + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp= %1. +ShutdownBlockReasonUninstallingApp= %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1, %2 +AdditionalIcons= : +CreateDesktopIcon= & +CreateQuickLaunchIcon= & +ProgramOnTheWeb= %1 +UninstallProgram= %1 +LaunchProgram= %1 +AssocFileExtension=& %1 , %2 +AssocingFileExtension= %1 %2... +AutoStartProgramGroupDescription=: +AutoStartProgram= %1 +AddonHostProgramNotFound=%1 .%n%n ? diff --git a/installer/innosetup/Languages/SerbianCyrillic.isl b/installer/innosetup/Languages/SerbianCyrillic.isl index 0ea72f5e0..743212575 100644 --- a/installer/innosetup/Languages/SerbianCyrillic.isl +++ b/installer/innosetup/Languages/SerbianCyrillic.isl @@ -1,9 +1,9 @@ -; *** Inno Setup version 5.5.3+ Serbian (Cyrillic) messages *** +; *** Inno Setup version 6.1.0+ Serbian (Cyrillic) messages *** ; ; To download user-contributed translations of this file, go to: ; http://www.jrsoftware.org/files/istrans/ ; -; Translated by Rancher (theranchcowboy@gmail.com). +; Translated by Rancher (theranchcowboy@gmail.com) and Davor (davornik@yahoo.com). ; ; Note: When translating this text, do not add periods (.) to the end of ; messages that didn't have them already, because on those messages Inno @@ -44,6 +44,7 @@ ErrorTitle= SetupLdrStartupMessage= %1. ? LdrCannotCreateTemp= . . LdrCannotExecTemp= . . +HelpTextNote= ; *** Startup error messages LastErrorMessage=%1.%n%n %2: %3 @@ -57,13 +58,21 @@ WindowsServicePackRequired= NotOnThisPlatform= %1. OnlyOnThisPlatform= %1. OnlyOnTheseArchitectures= :%n%n%1 -MissingWOW64APIs= 64- . %1 . WinVersionTooLowError= %1, %2 . WinVersionTooHighError= %1 %2 . AdminPrivilegesRequired= . PowerUserPrivilegesRequired= . SetupAppRunningError= %1 .%n%n . UninstallAppRunningError= %1 .%n%n . +; *** Startup questions +PrivilegesRequiredOverrideTitle= +PrivilegesRequiredOverrideInstruction= +PrivilegesRequiredOverrideText1=%1 ( ) . +PrivilegesRequiredOverrideText2=%1 ( ). +PrivilegesRequiredOverrideAllUsers= & +PrivilegesRequiredOverrideAllUsersRecommended= & () +PrivilegesRequiredOverrideCurrentUser= & +PrivilegesRequiredOverrideCurrentUserRecommended= & () ; *** Misc. errors ErrorCreatingDir= %1. @@ -76,7 +85,7 @@ AboutSetupMenuItem=& AboutSetupTitle= AboutSetupMessage=%1 %2%n%3%n%n%1 :%n%4 AboutSetupNote= -TranslatorNote=Serbian translation by Rancher. +TranslatorNote= ; *** Buttons ButtonBack=< & @@ -143,6 +152,7 @@ WizardSelectDir= SelectDirDesc= [name]. SelectDirLabel3= [name] . SelectDirBrowseLabel= . , 腓. +DiskSpaceGBLabel= [gb] GB . DiskSpaceMBLabel= [mb] MB . CannotInstallToNetworkDrive= . CannotInstallToUNCPath= UNC . @@ -170,6 +180,7 @@ NoUninstallWarningTitle= NoUninstallWarning= :%n%n%1%n%n .%n%n ? ComponentSize1=%1 kB ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel= [gb] GB . ComponentsDiskSpaceMBLabel= [mb] MB . ; *** "Select Additional Tasks" wizard page @@ -200,6 +211,18 @@ ReadyMemoComponents= ReadyMemoGroup= : ReadyMemoTasks= : +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel= ... +ButtonStopDownload=& +StopDownload= ? +ErrorDownloadAborted= +ErrorDownloadFailed= : %1 %2 +ErrorDownloadSizeFailed= : %1 %2 +ErrorFileHash1= : %1 +ErrorFileHash2= : %1, %2 +ErrorProgress= : %1 %2 +ErrorFileSize= : %1, %2 + ; *** "Preparing to Install" wizard page WizardPreparing= PreparingDesc= [name] . @@ -210,6 +233,7 @@ ApplicationsFound2= CloseApplications=& DontCloseApplications=& ErrorCloseApplications= . , . +PrepareToInstallNeedsRestart= . , [name].%n%n ? ; *** "Installing" wizard page WizardInstalling= @@ -239,7 +263,10 @@ SelectDirectoryLabel= ; *** Installation phase messages SetupAborted= .%n%n . -EntryAbortRetryIgnore= , . +AbortRetryIgnoreSelectAction= +AbortRetryIgnoreRetry=& +AbortRetryIgnoreIgnore=& +AbortRetryIgnoreCancel= ; *** Installation status messages StatusClosingApplications= @@ -270,14 +297,24 @@ ErrorRegWriteKey= ErrorIniEntry= INI %1. ; *** File copying errors -FileAbortRetryIgnore= , ( ) . -FileAbortRetryIgnore2= , ( ) . +FileAbortRetryIgnoreSkipNotRecommended=& ( ) +FileAbortRetryIgnoreIgnoreNotRecommended=& ( ) SourceIsCorrupted= SourceDoesntExist= %1 -ExistingFileReadOnly= .%n%n , . +ExistingFileReadOnly2= . +ExistingFileReadOnlyRetry=& +ExistingFileReadOnlyKeepExisting=& ErrorReadingExistingDest= : -FileExists= .%n%n ? -ExistingFileNewer= . .%n%n ? +FileExistsSelectAction= +FileExists2= . +FileExistsOverwriteExisting=& +FileExistsKeepExisting=& +FileExistsOverwriteOrKeepAll=& +ExistingFileNewerSelectAction= +ExistingFileNewer2= . +ExistingFileNewerOverwriteExisting=& +ExistingFileNewerKeepExisting=& () +ExistingFileNewerOverwriteOrKeepAll=& ErrorChangingAttr= : ErrorCreatingTemp= : ErrorReadingSource= : @@ -289,6 +326,16 @@ ErrorRegisterServer= ErrorRegSvr32Failed=RegSvr32 . %1 ErrorRegisterTypeLib= : %1 +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers= +UninstallDisplayNameMarkCurrentUser= + ; *** Post-installation errors ErrorOpeningReadme= . ErrorRestartingComputer= . . diff --git a/installer/innosetup/Languages/SerbianLatin.isl b/installer/innosetup/Languages/SerbianLatin.isl index 4c28549d7..55ebbb8f5 100644 --- a/installer/innosetup/Languages/SerbianLatin.isl +++ b/installer/innosetup/Languages/SerbianLatin.isl @@ -1,9 +1,9 @@ -; *** Inno Setup version 5.5.3+ Serbian (Latin) messages *** +; *** Inno Setup version 6.1.0+ Serbian (Latin) messages *** ; ; To download user-contributed translations of this file, go to: ; http://www.jrsoftware.org/files/istrans/ ; -; Translated by Rancher (theranchcowboy@gmail.com). +; Translated by Rancher (theranchcowboy@gmail.com) and Davor (davornik@yahoo.com). ; ; Note: When translating this text, do not add periods (.) to the end of ; messages that didn't have them already, because on those messages Inno @@ -44,6 +44,7 @@ ErrorTitle=Gre SetupLdrStartupMessage=Instaliraete %1. elite li da nastavite? LdrCannotCreateTemp=Ne mogu da napravim privremenu datoteku. Instalacija je prekinuta. LdrCannotExecTemp=Ne mogu da pokrenem datoteku u privremenoj fascikli. Instalacija je prekinuta. +HelpTextNote= ; *** Startup error messages LastErrorMessage=%1.%n%nGreka %2: %3 @@ -52,12 +53,11 @@ SetupFileCorrupt=Instalacione datoteke su o SetupFileCorruptOrWrongVer=Instalacione datoteke su oteene ili nisu saglasne s ovom verzijom instalacije. Ispravite problem ili nabavite novi primerak programa. InvalidParameter=Neispravan parametar je prenet na komandnu liniju: %n%n%1 SetupAlreadyRunning=Instalacija je ve pokrenuta. -WindowsVersionNotSupported=Program ne podrava izdanje vindousa koje koristite. +WindowsVersionNotSupported=Program ne podrava izdanje Windows-a koje koristite. WindowsServicePackRequired=Program zahteva %1 servisni paket %2 ili noviji. NotOnThisPlatform=Program nee raditi na %1. OnlyOnThisPlatform=Program e raditi na %1. -OnlyOnTheseArchitectures=Program se moe instalirati samo na izdanjima vindousa koji rade na sledeim arhitekturama procesora:%n%n%1 -MissingWOW64APIs=Izdanje vindousa koje koristite ne sadri funkcionalnost potrebnu za izvravanje 64-bitnih instalacija. Instalirajte servisni paket %1 da biste reili ovaj problem. +OnlyOnTheseArchitectures=Program se moe instalirati samo na izdanjima Windows-a koji rade na sledeim arhitekturama procesora:%n%n%1 WinVersionTooLowError=Program zahteva %1, izdanje %2 ili novije. WinVersionTooHighError=Program ne moete instalirati na %1 izdanju %2 ili novijem. AdminPrivilegesRequired=Morate biti prijavljeni kao administrator da biste instalirali program. @@ -65,6 +65,16 @@ PowerUserPrivilegesRequired=Morate biti prijavljeni kao administrator ili ovla SetupAppRunningError=Program %1 je trenutno pokrenut.%n%nZatvorite ga i kliknite na dugme U redu da nastavite ili Otkai da napustite instalaciju. UninstallAppRunningError=Program %1 je trenutno pokrenut.%n%nZatvorite ga i kliknite na dugme U redu da nastavite ili Otkai da napustite instalaciju. +; *** Startup questions +PrivilegesRequiredOverrideTitle=Odaberite nain instalacije +PrivilegesRequiredOverrideInstruction=Odaberite nain instalacije +PrivilegesRequiredOverrideText1=%1 moe biti instaliran za sve korisnike (zahteva administrativne privilegije) ili samo za vas. +PrivilegesRequiredOverrideText2=%1 moe da se instalira samo za vas ili za sve korisnike (zahteva administrativne privilegije). +PrivilegesRequiredOverrideAllUsers=Instaliraj za &sve korisnike +PrivilegesRequiredOverrideAllUsersRecommended=Instaliraj za &sve korisnike (preporueno) +PrivilegesRequiredOverrideCurrentUser=Instaliraj samo za &mene +PrivilegesRequiredOverrideCurrentUserRecommended=Instaliraj samo za &mene (preporueno) + ; *** Misc. errors ErrorCreatingDir=Ne mogu da napravim fasciklu %1. ErrorTooManyFilesInDir=Ne mogu da napravim datoteku u fascikli %1 jer sadri previe datoteka. @@ -74,9 +84,9 @@ ExitSetupTitle=Napu ExitSetupMessage=Instalacija nije zavrena. Ako sada izaete, program nee biti instaliran.%n%nInstalaciju moete pokrenuti i dovriti nekom dugom prilikom.%n%nelite li da je zatvorite? AboutSetupMenuItem=&O programu AboutSetupTitle=Podaci o programu -AboutSetupMessage=%1 verzija %2%n%3%n%n%1 matina stranica:%n%4 +AboutSetupMessage=%1 verzija %2%n%3%n%n%1 internet stranica:%n%4 AboutSetupNote= -TranslatorNote=Serbian translation by Rancher. +TranslatorNote= ; *** Buttons ButtonBack=< &Nazad @@ -89,13 +99,13 @@ ButtonYesToAll=D&a za sve ButtonNo=&Ne ButtonNoToAll=N&e za sve ButtonFinish=&Zavri -ButtonBrowse=&Potrai -ButtonWizardBrowse=&Potrai +ButtonBrowse=&Pretrai +ButtonWizardBrowse=&Pretrai ButtonNewFolder=&Napravi fasciklu ; *** "Select Language" dialog messages SelectLanguageTitle=Odabir jezika -SelectLanguageLabel=Izaberite jezik tokom instalacije: +SelectLanguageLabel=Izaberite jezik za korienje tokom instalacije: ; *** Common wizard text ClickNext=Kliknite na Dalje da nastavite ili Otkai da napustite instalaciju. @@ -143,6 +153,7 @@ WizardSelectDir=Odabir odredi SelectDirDesc=Izaberite mesto na kom elite da instalirate [name]. SelectDirLabel3=Program e instalirati [name] u sledeu fasciklu. SelectDirBrowseLabel=Kliknite na Dalje da nastavite. Ako elite da izaberete drugu fasciklu, kliknite na Potrai. +DiskSpaceGBLabel=Potrebno je najmanje [gb] GB slobodnog prostora na disku. DiskSpaceMBLabel=Potrebno je najmanje [mb] MB slobodnog prostora na disku. CannotInstallToNetworkDrive=Ne mogu da instaliram na mrenu jedinicu. CannotInstallToUNCPath=Ne mogu da instaliram na UNC putanju. @@ -170,6 +181,7 @@ NoUninstallWarningTitle=Komponente ve NoUninstallWarning=Sledee komponente ve postoje na raunaru:%n%n%1%n%nDetrikliranje ovih komponenti ih nee ukloniti.%n%nelite li da nastavite? ComponentSize1=%1 kB ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Izabrane stavke zahtevaju najmanje [gb] GB slobodnog prostora. ComponentsDiskSpaceMBLabel=Izabrane stavke zahtevaju najmanje [mb] MB slobodnog prostora. ; *** "Select Additional Tasks" wizard page @@ -200,6 +212,18 @@ ReadyMemoComponents=Izabrane komponente: ReadyMemoGroup=Fascikla u meniju Start: ReadyMemoTasks=Dodatni zadaci: +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Preuzimanje dodatnih datoteka... +ButtonStopDownload=&Zaustavi preuzimanje +StopDownload=Da li ste sigurni da elite da zaustavite preuzimanje? +ErrorDownloadAborted=Preuzimanje je prekinuto +ErrorDownloadFailed=Preuzimanje nije uspelo: %1 %2 +ErrorDownloadSizeFailed=Dobijanje veliine nije uspelo: %1 %2 +ErrorFileHash1=He datoteke nije uspeo: %1 +ErrorFileHash2=Neispravan he datoteke: oekivan %1, pronaen %2 +ErrorProgress=Neispravan napredak: %1 od %2 +ErrorFileSize=Neispravna veliina datoteke: oekivan %1, pronaen %2 + ; *** "Preparing to Install" wizard page WizardPreparing=Priprema za instalaciju PreparingDesc=Program se priprema da instalira [name] na raunar. @@ -210,6 +234,7 @@ ApplicationsFound2=Slede CloseApplications=&Zatvori programe DontCloseApplications=&Ne zatvaraj programe ErrorCloseApplications=Ne mogu da zatvorim sve programe. Pre nego to nastavite, preporuujemo vam da zatvorite sve programe koji koriste datoteke koje treba da aurira instalacioni program. +PrepareToInstallNeedsRestart=Instalacija mora da ponovo pokrene raunar. Nakon ponovnog pokretanja raunara, ponovo pokrenite instalaciju da biste dovrili instalaciju [name].%n%nelite li da ponovo pokrenete raunar sada? ; *** "Installing" wizard page WizardInstalling=Instaliranje @@ -239,7 +264,10 @@ SelectDirectoryLabel=Izaberite mesto slede ; *** Installation phase messages SetupAborted=Instalacija nije zavrena.%n%nIspravite problem i pokrenite je ponovo. -EntryAbortRetryIgnore=Kliknite na Pokuaj opet da ponovite radnju, Zanemari da nastavite u svakom sluaju ili Prekini da obustavite instalaciju. +AbortRetryIgnoreSelectAction=Odaberite radnju +AbortRetryIgnoreRetry=&Pokuaj opet +AbortRetryIgnoreIgnore=&Zanemari greku i nastavi +AbortRetryIgnoreCancel=Prekini instalaciju ; *** Installation status messages StatusClosingApplications=Zatvaram programe @@ -270,14 +298,24 @@ ErrorRegWriteKey=Gre ErrorIniEntry=Greka pri stvaranju INI unosa u datoteci %1. ; *** File copying errors -FileAbortRetryIgnore=Kliknite na Pokuaj opet da ponovite radnju, Zanemari da preskoite datoteku (ne preporuuje se) ili Prekini da obustavite instalaciju. -FileAbortRetryIgnore2=Kliknite na Pokuaj opet da ponovite radnju, Zanemari da nastavite u svakom sluaju (ne preporuuje se) ili Prekini da obustavite instalaciju. +FileAbortRetryIgnoreSkipNotRecommended=&Preskoite ovu datoteku (ne preporuuje se) +FileAbortRetryIgnoreIgnoreNotRecommended=&Zanemari greku i nastavi (ne preporuuje se) SourceIsCorrupted=Izvorna datoteka je oteena SourceDoesntExist=Izvorna datoteka %1 ne postoji -ExistingFileReadOnly=Postojea datoteka je samo za itanje.%n%nKliknite na Pokuaj opet da uklonite osobinu samo za itanje i ponovite radnju, Zanemari da preskoite datoteku ili Prekini da obustavite instalaciju. +ExistingFileReadOnly2=Postojea datoteka ne moe da se zameni jer je samo za itanje. +ExistingFileReadOnlyRetry=&Uklonite atribut samo za itanje i pokuajte ponovo +ExistingFileReadOnlyKeepExisting=&Zadrite postojeu datoteku ErrorReadingExistingDest=Dolo je do greke pri pokuaju itanja postojee datoteke: -FileExists=Datoteka ve postoji.%n%nelite li da je zamenite? -ExistingFileNewer=Postojea datoteka je novija od one koju treba postaviti. Preporuujemo vam da zadrite postojeu datoteku.%n%nelite li to da uradite? +FileExistsSelectAction=Odaberi akciju +FileExists2=Datoteka ve postoji. +FileExistsOverwriteExisting=&Zameni postojeu datoteku +FileExistsKeepExisting=&Zadri postojeu datoteku +FileExistsOverwriteOrKeepAll=&Uradi ovo i ubudue +ExistingFileNewerSelectAction=Odaberi akciju +ExistingFileNewer2=Postojea datoteka je novija od one koju treba instalirati. +ExistingFileNewerOverwriteExisting=&Zameni postojeu datoteku +ExistingFileNewerKeepExisting=&Zadri postojeu datoteku (preporueno) +ExistingFileNewerOverwriteOrKeepAll=&Uradi ovo i ubudue ErrorChangingAttr=Dolo je do greke pri izmeni osobine sledee datoteke: ErrorCreatingTemp=Dolo je do greke pri stvaranju datoteke u odredinoj fascikli: ErrorReadingSource=Dolo je do greke pri itanju izvorne datoteke: @@ -289,6 +327,16 @@ ErrorRegisterServer=Ne mogu da upi ErrorRegSvr32Failed=RegSvr32 nije uspeo. Greka %1 ErrorRegisterTypeLib=Ne mogu da upiem biblioteku tipova: %1 +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Svi korisnici +UninstallDisplayNameMarkCurrentUser=Trenutni korisnik + ; *** Post-installation errors ErrorOpeningReadme=Dolo je do greke pri otvaranju tekstualne datoteke. ErrorRestartingComputer=Ne mogu ponovo da pokrenem raunar. Uradite to sami. diff --git a/installer/innosetup/Languages/Slovak.isl b/installer/innosetup/Languages/Slovak.isl new file mode 100644 index 000000000..fab212ebf --- /dev/null +++ b/installer/innosetup/Languages/Slovak.isl @@ -0,0 +1,385 @@ +; ****************************************************** +; *** *** +; *** Inno Setup version 6.1.0+ Slovak messages *** +; *** *** +; *** Original Author: *** +; *** *** +; *** Milan Potancok (milan.potancok AT gmail.com) *** +; *** *** +; *** Contributors: *** +; *** *** +; *** Ivo Bauer (bauer AT ozm.cz) *** +; *** *** +; *** Tomas Falb (tomasf AT pobox.sk) *** +; *** Slappy (slappy AT pobox.sk) *** +; *** Comments: (mitems58 AT gmail.com) *** +; *** *** +; *** Update: 28.01.2021 *** +; *** *** +; ****************************************************** +; +; + +[LangOptions] +LanguageName=Sloven<010D>ina +LanguageID=$041b +LanguageCodePage=1250 + +[Messages] + +; *** Application titles +SetupAppTitle=Sprievodca inštaláciou +SetupWindowTitle=Sprievodca inštaláciou - %1 +UninstallAppTitle=Sprievodca odinštaláciou +UninstallAppFullTitle=Sprievodca odinštaláciou - %1 + +; *** Misc. common +InformationTitle=Informácie +ConfirmTitle=Potvrdenie +ErrorTitle=Chyba + +; *** SetupLdr messages +SetupLdrStartupMessage=Víta Vás Sprievodca inštaláciou produktu %1. Prajete si pokračovať? +LdrCannotCreateTemp=Nie je možné vytvoriť dočasný súbor. Sprievodca inštaláciou sa ukončí +LdrCannotExecTemp=Nie je možné spustiť súbor v dočasnom adresári. Sprievodca inštaláciou sa ukončí +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nChyba %2: %3 +SetupFileMissing=Inštalačný adresár neobsahuje súbor %1. Opravte túto chybu, alebo si zaobstarajte novú kópiu tohto produktu. +SetupFileCorrupt=Súbory Sprievodcu inštaláciou sú poškodené. Zaobstarajte si novú kópiu tohto produktu. +SetupFileCorruptOrWrongVer=Súbory Sprievodcu inštaláciou sú poškodené alebo sa nezhodujú s touto verziou Sprievodcu inštaláciou. Opravte túto chybu, alebo si zaobstarajte novú kópiu tohto produktu. +InvalidParameter=Nesprávny parameter na príkazovom riadku: %n%n%1 +SetupAlreadyRunning=Inštalácia už prebieha. +WindowsVersionNotSupported=Tento program nepodporuje vašu verziu systému Windows. +WindowsServicePackRequired=Tento program vyžaduje %1 Service Pack %2 alebo novší. +NotOnThisPlatform=Tento produkt sa nedá spustiť v %1. +OnlyOnThisPlatform=Tento produkt musí byť spustený v %1. +OnlyOnTheseArchitectures=Tento produkt je možné nainštalovať iba vo verziách MS Windows s podporou architektúry procesorov:%n%n%1 +WinVersionTooLowError=Tento produkt vyžaduje %1 verzie %2 alebo vyššej. +WinVersionTooHighError=Tento produkt sa nedá nainštalovať vo %1 verzie %2 alebo vyššej. +AdminPrivilegesRequired=Na inštaláciu tohto produktu musíte byť prihlásený s právami administrátora. +PowerUserPrivilegesRequired=Na inštaláciu tohto produktu musíte byť prihlásený s právami Administrátora alebo člena skupiny Power Users. +SetupAppRunningError=Sprievodca inštaláciou zistil, že produkt %1 je teraz spustený.%n%nUkončte všetky spustené inštancie tohto produktu a pokračujte kliknutím na tlačidlo "OK", alebo ukončte inštaláciu tlačidlom "Zrušiť". +UninstallAppRunningError=Sprievodca odinštaláciou zistil, že produkt %1 je teraz spustený.%n%nUkončte všetky spustené inštancie tohto produktu a pokračujte kliknutím na tlačidlo "OK", alebo ukončte inštaláciu tlačidlom "Zrušiť". + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Vyberte inštalačný mód inštalátora +PrivilegesRequiredOverrideInstruction=Vyberte inštalačný mód +PrivilegesRequiredOverrideText1=%1 sa môže nainštalovať pre všetkých užívateľov (vyžaduje administrátorské práva), alebo len pre Vás. +PrivilegesRequiredOverrideText2=%1 sa môže nainštalovať len pre Vás, alebo pre všetkých užívateľov (vyžadujú sa Administrátorské práva). +PrivilegesRequiredOverrideAllUsers=Inštalovať pre &všetkých užívateľov +PrivilegesRequiredOverrideAllUsersRecommended=Inštalovať pre &všetkých užívateľov (odporúčané) +PrivilegesRequiredOverrideCurrentUser=Inštalovať len pre &mňa +PrivilegesRequiredOverrideCurrentUserRecommended=Inštalovať len pre &mňa (odporúčané) + +; *** Misc. errors +ErrorCreatingDir=Sprievodca inštaláciou nemohol vytvoriť adresár "%1" +ErrorTooManyFilesInDir=Nedá sa vytvoriť súbor v adresári "%1", pretože tento adresár už obsahuje príliš veľa súborov + +; *** Setup common messages +ExitSetupTitle=Ukončiť Sprievodcu inštaláciou +ExitSetupMessage=Inštalácia nebola kompletne dokončená. Ak teraz ukončíte Sprievodcu inštaláciou, produkt nebude nainštalovaný.%n%nSprievodcu inštaláciou môžete znovu spustiť neskôr a dokončiť tak inštaláciu.%n%nUkončiť Sprievodcu inštaláciou? +AboutSetupMenuItem=&O Sprievodcovi inštalácie... +AboutSetupTitle=O Sprievodcovi inštalácie +AboutSetupMessage=%1 verzia %2%n%3%n%n%1 domovská stránka:%n%4 +AboutSetupNote= +TranslatorNote=Slovak translation maintained by Milan Potancok (milan.potancok AT gmail.com), Ivo Bauer (bauer AT ozm.cz), Tomas Falb (tomasf AT pobox.sk) + Slappy (slappy AT pobox.sk) + +; *** Buttons +ButtonBack=< &Späť +ButtonNext=&Ďalej > +ButtonInstall=&Inštalovať +ButtonOK=OK +ButtonCancel=Zrušiť +ButtonYes=&Áno +ButtonYesToAll=Áno &všetkým +ButtonNo=&Nie +ButtonNoToAll=Ni&e všetkým +ButtonFinish=&Dokončiť +ButtonBrowse=&Prechádzať... +ButtonWizardBrowse=&Prechádzať... +ButtonNewFolder=&Vytvoriť nový adresár + +; *** "Select Language" dialog messages +SelectLanguageTitle=Výber jazyka Sprievodcu inštaláciou +SelectLanguageLabel=Zvoľte jazyk, ktorý sa má použiť pri inštalácii. + +; *** Common wizard text +ClickNext=Pokračujte kliknutím na tlačidlo "Ďalej", alebo ukončte sprievodcu inštaláciou tlačidlom "Zrušiť". +BeveledLabel= +BrowseDialogTitle=Nájsť adresár +BrowseDialogLabel=Z dole uvedeného zoznamu vyberte adresár a kliknite na "OK". +NewFolderName=Nový adresár + +; *** "Welcome" wizard page +WelcomeLabel1=Víta Vás Sprievodca inštaláciou produktu [name]. +WelcomeLabel2=Produkt [name/ver] sa nainštaluje do tohto počítača.%n%nSkôr, ako budete pokračovať, odporúčame ukončiť všetky spustené aplikácie. + +; *** "Password" wizard page +WizardPassword=Heslo +PasswordLabel1=Táto inštalácia je chránená heslom. +PasswordLabel3=Zadajte heslo a pokračujte kliknutím na tlačidlo "Ďalej". Pri zadávaní hesla rozlišujte malé a veľké písmená. +PasswordEditLabel=&Heslo: +IncorrectPassword=Zadané heslo nie je správne. Skúste to ešte raz prosím. + +; *** "License Agreement" wizard page +WizardLicense=Licenčná zmluva +LicenseLabel=Skôr, ako budete pokračovať, prečítajte si tieto dôležité informácie, prosím. +LicenseLabel3=Prečítajte si túto Licenčnú zmluvu prosím. Aby mohla inštalácia pokračovať, musíte súhlasiť s podmienkami tejto zmluvy. +LicenseAccepted=&Súhlasím s podmienkami Licenčnej zmluvy +LicenseNotAccepted=&Nesúhlasím s podmienkami Licenčnej zmluvy + +; *** "Information" wizard pages +WizardInfoBefore=Informácie +InfoBeforeLabel=Skôr, ako budete pokračovať, prečítajte si tieto dôležité informácie, prosím. +InfoBeforeClickLabel=Pokračujte v inštalácii kliknutím na tlačidlo "Ďalej". +WizardInfoAfter=Informácie +InfoAfterLabel=Skôr, ako budete pokračovať, prečítajte si tieto dôležité informácie prosím. +InfoAfterClickLabel=Pokračujte v inštalácii kliknutím na tlačidlo "Ďalej". + +; *** "User Information" wizard page +WizardUserInfo=Informácie o používateľovi +UserInfoDesc=Zadajte požadované informácie prosím. +UserInfoName=&Používateľské meno: +UserInfoOrg=&Organizácia: +UserInfoSerial=&Sériové číslo: +UserInfoNameRequired=Meno používateľa musí byť zadané. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Vyberte cieľový adresár +SelectDirDesc=Kde má byť produkt [name] nainštalovaný? +SelectDirLabel3=Sprievodca nainštaluje produkt [name] do nasledujúceho adresára. +SelectDirBrowseLabel=Pokračujte kliknutím na tlačidlo "Ďalej". Ak chcete vybrať iný adresár, kliknite na tlačidlo "Prechádzať". +DiskSpaceGBLabel=Inštalácia vyžaduje najmenej [gb] GB miesta v disku. +DiskSpaceMBLabel=Inštalácia vyžaduje najmenej [mb] MB miesta v disku. +CannotInstallToNetworkDrive=Sprievodca inštaláciou nemôže inštalovať do sieťovej jednotky. +CannotInstallToUNCPath=Sprievodca inštaláciou nemôže inštalovať do UNC umiestnenia. +InvalidPath=Musíte zadať úplnú cestu vrátane písmena jednotky; napríklad:%n%nC:\Aplikácia%n%nalebo cestu UNC v tvare:%n%n\\Server\Zdieľaný adresár +InvalidDrive=Vami vybraná jednotka alebo cesta UNC neexistuje, alebo nie je dostupná. Vyberte iné umiestnenie prosím. +DiskSpaceWarningTitle=Nedostatok miesta v disku +DiskSpaceWarning=Sprievodca inštaláciou vyžaduje najmenej %1 KB voľného miesta pre inštaláciu produktu, ale vo vybranej jednotke je dostupných iba %2 KB.%n%nAj napriek tomu chcete pokračovať? +DirNameTooLong=Názov adresára alebo cesta sú príliš dlhé. +InvalidDirName=Názov adresára nie je správny. +BadDirName32=Názvy adresárov nesmú obsahovať žiadny z nasledujúcich znakov:%n%n%1 +DirExistsTitle=Adresár už existuje +DirExists=Adresár:%n%n%1%n%nuž existuje. Aj napriek tomu chcete nainštalovať produkt do tohto adresára? +DirDoesntExistTitle=Adresár neexistuje +DirDoesntExist=Adresár: %n%n%1%n%nešte neexistuje. Má sa tento adresár vytvoriť? + +; *** "Select Components" wizard page +WizardSelectComponents=Vyberte komponenty +SelectComponentsDesc=Aké komponenty majú byť nainštalované? +SelectComponentsLabel2=Zaškrtnite iba komponenty, ktoré chcete nainštalovať; komponenty, ktoré se nemajú inštalovať, nechajte nezaškrtnuté. Pokračujte kliknutím na tlačidlo "Ďalej". +FullInstallation=Úplná inštalácia +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Kompaktná inštalácia +CustomInstallation=Voliteľná inštalácia +NoUninstallWarningTitle=Komponenty existujú +NoUninstallWarning=Sprievodca inštaláciou zistil že nasledujúce komponenty už sú v tomto počítači nainštalované:%n%n%1%n%nAk ich teraz nezahrniete do výberu, nebudú neskôr odinštalované.%n%nAj napriek tomu chcete pokračovať? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Vybrané komponenty vyžadujú najmenej [gb] GB miesta v disku. +ComponentsDiskSpaceMBLabel=Vybrané komponenty vyžadujú najmenej [mb] MB miesta v disku. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Vyberte ďalšie úlohy +SelectTasksDesc=Ktoré ďalšie úlohy majú byť vykonané? +SelectTasksLabel2=Vyberte ďalšie úlohy, ktoré majú byť vykonané počas inštalácie produktu [name] a pokračujte kliknutím na tlačidlo "Ďalej". + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Vyberte skupinu v ponuke Štart +SelectStartMenuFolderDesc=Kam má sprievodca inštalácie umiestniť zástupcov aplikácie? +SelectStartMenuFolderLabel3=Sprievodca inštaláciou vytvorí zástupcov aplikácie v nasledujúcom adresári ponuky Štart. +SelectStartMenuFolderBrowseLabel=Pokračujte kliknutím na tlačidlo Ďalej. Ak chcete zvoliť iný adresár, kliknite na tlačidlo "Prechádzať". +MustEnterGroupName=Musíte zadať názov skupiny. +GroupNameTooLong=Názov adresára alebo cesta sú príliš dlhé. +InvalidGroupName=Názov adresára nie je správny. +BadGroupName=Názov skupiny nesmie obsahovať žiadny z nasledujúcich znakov:%n%n%1 +NoProgramGroupCheck2=&Nevytvárať skupinu v ponuke Štart + +; *** "Ready to Install" wizard page +WizardReady=Inštalácia je pripravená +ReadyLabel1=Sprievodca inštaláciou je teraz pripravený nainštalovať produkt [name] na Váš počítač. +ReadyLabel2a=Pokračujte v inštalácii kliknutím na tlačidlo "Inštalovať". Ak chcete zmeniť niektoré nastavenia inštalácie, kliknite na tlačidlo "< Späť". +ReadyLabel2b=Pokračujte v inštalácii kliknutím na tlačidlo "Inštalovať". +ReadyMemoUserInfo=Informácie o používateľovi: +ReadyMemoDir=Cieľový adresár: +ReadyMemoType=Typ inštalácie: +ReadyMemoComponents=Vybrané komponenty: +ReadyMemoGroup=Skupina v ponuke Štart: +ReadyMemoTasks=Ďalšie úlohy: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Sťahovanie dodatočných súborov... +ButtonStopDownload=&Zastaviť sťahovanie +StopDownload=Naozaj chcete zastaviť sťahovanie? +ErrorDownloadAborted=Sťahovanie prerušené +ErrorDownloadFailed=Sťahovanie zlyhalo: %1 %2 +ErrorDownloadSizeFailed=Zlyhalo získanie veľkosti: %1 %2 +ErrorFileHash1=Kontrola hodnoty súboru zlyhala: %1 +ErrorFileHash2=Nesprávna kontrolná hodnota: očakávala sa %1, zistená %2 +ErrorProgress=Nesprávny priebeh: %1 z %2 +ErrorFileSize=Nesprávna veľkosť súboru: očakávala sa %1, zistená %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Príprava inštalácie +PreparingDesc=Sprievodca inštaláciou pripravuje inštaláciu produktu [name] do tohto počítača. +PreviousInstallNotCompleted=Inštalácia/odinštalácia predošlého produktu nebola úplne dokončená. Dokončenie tohto procesu vyžaduje reštart počítača.%n%nPo reštartovaní počítača znovu spustite Sprievodcu inštaláciou, aby bolo možné kompletne dokončiť inštaláciu produktu [name]. +CannotContinue=Sprievodca inštaláciou nemôže pokračovať. Ukončite, prosím, sprievodcu inštaláciou kliknutím na tlačidlo "Zrušiť". +ApplicationsFound=Nasledujúce aplikácie pracujú so súbormi, ktoré musí Sprievodca inštaláciou aktualizovať. Odporúčame, aby ste povolili Sprievodcovi inštaláciou automaticky ukončiť tieto aplikácie. +ApplicationsFound2=Nasledujúce aplikácie pracujú so súbormi, ktoré musí Sprievodca inštaláciou aktualizovať. Odporúčame, aby ste povolili Sprievodcovi inštaláciou automaticky ukončiť tieto aplikácie. Po dokončení inštalácie sa Sprievodca inštaláciou pokúsi tieto aplikácie opätovne spustiť. +CloseApplications=&Automaticky ukončiť aplikácie +DontCloseApplications=&Neukončovať aplikácie +ErrorCloseApplications=Sprievodca inštaláciou nemohol automaticky zatvoriť všetky aplikácie. Odporúčame, aby ste ručne ukončili všetky aplikácie, ktoré používajú súbory a ktoré má Sprievodca aktualizovať. +PrepareToInstallNeedsRestart=Sprievodca inštaláciou potrebuje reštartovať tento počítač. Po reštartovaní počítača znovu spustite tohto Sprievodcu inštaláciou, aby sa inštalácia [name] dokončila.%n%nChcete teraz reštartovať tento počítač? + +; *** "Installing" wizard page +WizardInstalling=Inštalujem +InstallingLabel=Počkajte prosím, pokiaľ Sprievodca inštaláciou dokončí inštaláciu produktu [name] do tohto počítača. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Dokončuje sa inštalácia produktu [name] +FinishedLabelNoIcons=Sprievodca inštaláciou dokončil inštaláciu produktu [name] do tohto počítača. +FinishedLabel=Sprievodca inštaláciou dokončil inštaláciu produktu [name] do tohto počítača. Produkt je možné spustiť pomocou nainštalovaných ikon a zástupcov. +ClickFinish=Ukončte Sprievodcu inštaláciou kliknutím na tlačidlo "Dokončiť". +FinishedRestartLabel=Pre dokončenie inštalácie produktu [name] je nutné reštartovať tento počítač. Želáte si teraz reštartovať tento počítač? +FinishedRestartMessage=Pre dokončenie inštalácie produktu [name] je nutné reštartovať tento počítač.%n%nŽeláte si teraz reštartovať tento počítač? +ShowReadmeCheck=Áno, chcem zobraziť dokument "ČITAJMA" +YesRadio=&Áno, chcem teraz reštartovať počítač +NoRadio=&Nie, počítač reštartujem neskôr + +; used for example as 'Run MyProg.exe' +RunEntryExec=Spustiť %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Zobraziť %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Sprievodca inštaláciou vyžaduje ďalší disk +SelectDiskLabel2=Vložte prosím, disk %1 a kliknite na tlačidlo "OK".%n%nAk sa súbory tohto disku nachádzajú v inom adresári ako v tom, ktorý je zobrazený nižšie, zadajte správnu cestu alebo kliknite na tlačidlo "Prechádzať". +PathLabel=&Cesta: +FileNotInDir2=Súbor "%1" sa nedá nájsť v "%2". Vložte prosím, správny disk, alebo zvoľte iný adresár. +SelectDirectoryLabel=Špecifikujte prosím, umiestnenie ďalšieho disku. + +; *** Installation phase messages +SetupAborted=Inštalácia nebola úplne dokončená.%n%nOpravte chybu a opäť spustite Sprievodcu inštaláciou prosím. +AbortRetryIgnoreSelectAction=Vyberte akciu +AbortRetryIgnoreRetry=&Skúsiť znovu +AbortRetryIgnoreIgnore=&Ignorovať chybu a pokračovať +AbortRetryIgnoreCancel=Zrušiť inštaláciu + +; *** Installation status messages +StatusClosingApplications=Ukončovanie aplikácií... +StatusCreateDirs=Vytvárajú sa adresáre... +StatusExtractFiles=Rozbaľujú sa súbory... +StatusCreateIcons=Vytvárajú sa ikony a zástupcovia... +StatusCreateIniEntries=Vytvárajú sa záznamy v konfiguračných súboroch... +StatusCreateRegistryEntries=Vytvárajú sa záznamy v systémovom registri... +StatusRegisterFiles=Registrujú sa súbory... +StatusSavingUninstall=Ukladajú sa informácie potrebné pre neskoršie odinštalovanie produktu... +StatusRunProgram=Dokončuje sa inštalácia... +StatusRestartingApplications=Reštartovanie aplikácií... +StatusRollback=Vykonané zmeny sa vracajú späť... + +; *** Misc. errors +ErrorInternal2=Interná chyba: %1 +ErrorFunctionFailedNoCode=%1 zlyhala +ErrorFunctionFailed=%1 zlyhala; kód %2 +ErrorFunctionFailedWithMessage=%1 zlyhala; kód %2.%n%3 +ErrorExecutingProgram=Nedá sa spustiť súbor:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Došlo k chybe pri otváraní kľúča systémového registra:%n%1\%2 +ErrorRegCreateKey=Došlo k chybe pri vytváraní kľúča systémového registra:%n%1\%2 +ErrorRegWriteKey=Došlo k chybe pri zápise kľúča do systémového registra:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Došlo k chybe pri vytváraní záznamu v konfiguračnom súbore "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Preskočiť tento súbor (neodporúčané) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorovať chybu a pokračovať (neodporúčané) +SourceIsCorrupted=Zdrojový súbor je poškodený +SourceDoesntExist=Zdrojový súbor "%1" neexistuje +ExistingFileReadOnly2=Existujúci súbor nie je možné prepísať, pretože je označený atribútom Iba na čítanie. +ExistingFileReadOnlyRetry=&Odstrániť atribút Iba na čítanie a skúsiť znovu +ExistingFileReadOnlyKeepExisting=&Ponechať existujúci súbor +ErrorReadingExistingDest=Došlo k chybe pri pokuse o čítanie existujúceho súboru: +FileExistsSelectAction=Vyberte akciu +FileExists2=Súbor už existuje. +FileExistsOverwriteExisting=&Prepísať existujúci súbor +FileExistsKeepExisting=Ponechať &existujúci súbor +FileExistsOverwriteOrKeepAll=&Vykonať pre všetky ďalšie konflikty +ExistingFileNewerSelectAction=Vyberte akciu +ExistingFileNewer2=Existujúci súbor je novší ako súbor, ktorý sa Sprievodca inštaláciou pokúša nainštalovať. +ExistingFileNewerOverwriteExisting=&Prepísať existujúci súbor +ExistingFileNewerKeepExisting=Ponechať &existujúci súbor (odporúčané) +ExistingFileNewerOverwriteOrKeepAll=&Vykonať pre všetky ďalšie konflikty +ErrorChangingAttr=Došlo k chybe pri pokuse o modifikáciu atribútov existujúceho súboru: +ErrorCreatingTemp=Došlo k chybe pri pokuse o vytvorenie súboru v cieľovom adresári: +ErrorReadingSource=Došlo k chybe pri pokuse o čítanie zdrojového súboru: +ErrorCopying=Došlo k chybe pri pokuse o skopírovanie súboru: +ErrorReplacingExistingFile=Došlo k chybe pri pokuse o nahradenie existujúceho súboru: +ErrorRestartReplace=Zlyhala funkcia "RestartReplace" Sprievodcu inštaláciou: +ErrorRenamingTemp=Došlo k chybe pri pokuse o premenovanie súboru v cieľovom adresári: +ErrorRegisterServer=Nedá sa vykonať registrácia DLL/OCX: %1 +ErrorRegSvr32Failed=Volanie RegSvr32 zlyhalo s návratovým kódom %1 +ErrorRegisterTypeLib=Nedá sa vykonať registrácia typovej knižnice: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32bitový +UninstallDisplayNameMark64Bit=64bitový +UninstallDisplayNameMarkAllUsers=Všetci užívatelia +UninstallDisplayNameMarkCurrentUser=Aktuálny užívateľ + +; *** Post-installation errors +ErrorOpeningReadme=Došlo k chybe pri pokuse o otvorenie dokumentu "ČITAJMA". +ErrorRestartingComputer=Sprievodcovi inštaláciou sa nepodarilo reštartovať tento počítač. Reštartujte ho manuálne prosím. + +; *** Uninstaller messages +UninstallNotFound=Súbor "%1" neexistuje. Produkt sa nedá odinštalovať. +UninstallOpenError=Súbor "%1" nie je možné otvoriť. Produkt nie je možné odinštalovať. +UninstallUnsupportedVer=Sprievodcovi odinštaláciou sa nepodarilo rozpoznať formát súboru obsahujúceho informácie na odinštalovanie produktu "%1". Produkt sa nedá odinštalovať +UninstallUnknownEntry=V súbore obsahujúcom informácie na odinštalovanie produktu bola zistená neznáma položka (%1) +ConfirmUninstall=Naozaj chcete odinštalovať %1 a všetky jeho komponenty? +UninstallOnlyOnWin64=Tento produkt je možné odinštalovať iba v 64-bitových verziách MS Windows. +OnlyAdminCanUninstall=K odinštalovaniu tohto produktu musíte byť prihlásený s právami Administrátora. +UninstallStatusLabel=Počkajte prosím, kým produkt %1 nebude odinštalovaný z tohto počítača. +UninstalledAll=%1 bol úspešne odinštalovaný z tohto počítača. +UninstalledMost=%1 bol odinštalovaný z tohto počítača.%n%nNiektoré jeho komponenty sa však nepodarilo odinštalovať. Môžete ich odinštalovať manuálne. +UninstalledAndNeedsRestart=Na dokončenie odinštalácie produktu %1 je potrebné reštartovať tento počítač.%n%nChcete ihneď reštartovať tento počítač? +UninstallDataCorrupted=Súbor "%1" je poškodený. Produkt sa nedá odinštalovať + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Odinštalovať zdieľaný súbor? +ConfirmDeleteSharedFile2=Systém indikuje, že nasledujúci zdieľaný súbor nie je používaný žiadnymi inými aplikáciami. Má Sprievodca odinštaláciou tento zdieľaný súbor odstrániť?%n%nAk niektoré aplikácie tento súbor používajú, nemusia po jeho odinštalovaní pracovať správne. Pokiaľ to neviete správne posúdiť, odporúčame zvoliť "Nie". Ponechanie tohto súboru v systéme nespôsobí žiadnu škodu. +SharedFileNameLabel=Názov súboru: +SharedFileLocationLabel=Umiestnenie: +WizardUninstalling=Stav odinštalovania +StatusUninstalling=Prebieha odinštalovanie %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Inštalovanie %1. +ShutdownBlockReasonUninstallingApp=Odinštalovanie %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 verzia %2 +AdditionalIcons=Ďalší zástupcovia: +CreateDesktopIcon=Vytvoriť zástupcu na &ploche +CreateQuickLaunchIcon=Vytvoriť zástupcu na paneli &Rýchle spustenie +ProgramOnTheWeb=Aplikácia %1 na internete +UninstallProgram=Odinštalovať aplikáciu %1 +LaunchProgram=Spustiť aplikáciu %1 +AssocFileExtension=Vytvoriť &asociáciu medzi súbormi typu %2 a aplikáciou %1 +AssocingFileExtension=Vytvára sa asociácia medzi súbormi typu %2 a aplikáciou %1... +AutoStartProgramGroupDescription=Pri spustení: +AutoStartProgram=Automaticky spustiť %1 +AddonHostProgramNotFound=Nepodarilo sa nájsť %1 v adresári, ktorý ste zvolili.%n%nChcete napriek tomu pokračovať? diff --git a/installer/innosetup/Languages/Slovenian.isl b/installer/innosetup/Languages/Slovenian.isl new file mode 100644 index 000000000..248b688ca --- /dev/null +++ b/installer/innosetup/Languages/Slovenian.isl @@ -0,0 +1,370 @@ +; *** Inno Setup version 6.1.0+ Slovenian messages *** +; +; To download user-contributed translations of this file, go to: +; http://www.jrsoftware.org/is3rdparty.php +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). +; +; Maintained by Jernej Simoncic (jernej+s-innosetup@eternallybored.org) + +[LangOptions] +LanguageName=Slovenski +LanguageID=$0424 +LanguageCodePage=1250 + +DialogFontName= +[Messages] + +; *** Application titles +SetupAppTitle=Namestitev +SetupWindowTitle=Namestitev - %1 +UninstallAppTitle=Odstranitev +UninstallAppFullTitle=Odstranitev programa %1 + +; *** Misc. common +InformationTitle=Informacija +ConfirmTitle=Potrditev +ErrorTitle=Napaka + +; *** SetupLdr messages +SetupLdrStartupMessage=V raunalnik boste namestili program %1. elite nadaljevati? +LdrCannotCreateTemp=Ni bilo mogoe ustvariti zaasne datoteke. Namestitev je prekinjena +LdrCannotExecTemp=Ni bilo mogoe zagnati datoteke v zaasni mapi. Namestitev je prekinjena + +; *** Startup error messages +LastErrorMessage=%1.%n%nNapaka %2: %3 +SetupFileMissing=Datoteka %1 manjka. Odpravite napako ali si priskrbite drugo kopijo programa. +SetupFileCorrupt=Datoteke namestitvenega programa so okvarjene. Priskrbite si drugo kopijo programa. +SetupFileCorruptOrWrongVer=Datoteke so okvarjene ali nezdruljive s to razliico namestitvenega programa. Odpravite napako ali si priskrbite drugo kopijo programa. +InvalidParameter=Naveden je bil napaen parameter ukazne vrstice:%n%n%1 +SetupAlreadyRunning=Namestitveni program se e izvaja. +WindowsVersionNotSupported=Program ne deluje na vai razliici sistema Windows. +WindowsServicePackRequired=Program potrebuje %1 s servisnim paketom %2 ali novejo razliico. +NotOnThisPlatform=Program ni namenjen za uporabo v %1. +OnlyOnThisPlatform=Program je namenjen le za uporabo v %1. +OnlyOnTheseArchitectures=Program lahko namestite le na Windows sistemih, na naslednjih vrstah procesorjev:%n%n%1 +WinVersionTooLowError=Ta program zahteva %1 razliico %2 ali novejo. +WinVersionTooHighError=Tega programa ne morete namestiti v %1 razliice %2 ali noveje. +AdminPrivilegesRequired=Za namestitev programa morate biti prijavljeni v raun s skrbnikimi pravicami. +PowerUserPrivilegesRequired=Za namestitev programa morate biti prijavljeni v raun s skrbnikimi ali power user pravicami. +SetupAppRunningError=Program %1 je trenutno odprt.%n%nZaprite program, nato kliknite V redu za nadaljevanje ali Preklii za izhod. +UninstallAppRunningError=Program %1 je trenutno odprt.%n%nZaprite program, nato kliknite V redu za nadaljevanje ali Preklii za izhod. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Izberite nain namestitve +PrivilegesRequiredOverrideInstruction=Izberite nain namestitve +PrivilegesRequiredOverrideText1=Program %1 lahko namestite za vse uporabnike (potrebujete skrbnike pravice), ali pa samo za vas. +PrivilegesRequiredOverrideText2=Program %1 lahko namestite samo za vas, ali pa za vse uporabnike (potrebujete skrbnike pravice). +PrivilegesRequiredOverrideAllUsers=N&amesti za vse uporabnike +PrivilegesRequiredOverrideAllUsersRecommended=N&amesti za vse uporabnike (priporoeno) +PrivilegesRequiredOverrideCurrentUser=Namesti samo za&me +PrivilegesRequiredOverrideCurrentUserRecommended=Namesti samo za&me (priporoeno) + +; *** Misc. errors +ErrorCreatingDir=Namestitveni program ni mogel ustvariti mape %1 +ErrorTooManyFilesInDir=Namestitveni program ne more ustvariti nove datoteke v mapi %1, ker vsebuje preve datotek + +; *** Setup common messages +ExitSetupTitle=Prekini namestitev +ExitSetupMessage=Namestitev ni konana. e jo boste prekinili, program ne bo nameen.%n%nPonovno namestitev lahko izvedete kasneje.%n%nelite prekiniti namestitev? +AboutSetupMenuItem=&O namestitvenem programu... +AboutSetupTitle=O namestitvenem programu +AboutSetupMessage=%1 razliica %2%n%3%n%n%1 domaa stran:%n%4 +AboutSetupNote= +TranslatorNote=Slovenski prevod:%nMiha Remec%nJernej Simoni + +; *** Buttons +ButtonBack=< Na&zaj +ButtonNext=&Naprej > +ButtonInstall=&Namesti +ButtonOK=V redu +ButtonCancel=Preklii +ButtonYes=&Da +ButtonYesToAll=Da za &vse +ButtonNo=&Ne +ButtonNoToAll=N&e za vse +ButtonFinish=&Konaj +ButtonBrowse=Pre&brskaj... +ButtonWizardBrowse=Pre&brskaj... +ButtonNewFolder=&Ustvari novo mapo + +; *** "Select Language" dialog messages +SelectLanguageTitle=Izbira jezika namestitve +SelectLanguageLabel=Izberite jezik, ki ga elite uporabljati med namestitvijo. + +; *** Common wizard text +ClickNext=Kliknite Naprej za nadaljevanje namestitve ali Preklii za prekinitev namestitve. +BeveledLabel= +BrowseDialogTitle=Izbira mape +BrowseDialogLabel=Izberite mapo s spiska, nato kliknite V redu. +NewFolderName=Nova mapa + +; *** "Welcome" wizard page +WelcomeLabel1=Dobrodoli v namestitev programa [name]. +WelcomeLabel2=V raunalnik boste namestili program [name/ver].%n%nPriporoljivo je, da pred zaetkom namestitve zaprete vse odprte programe. + +; *** "Password" wizard page +WizardPassword=Geslo +PasswordLabel1=Namestitev je zaitena z geslom. +PasswordLabel3=Vnesite geslo, nato kliknite Naprej za nadaljevanje. Pri vnaanju pazite na male in velike rke. +PasswordEditLabel=&Geslo: +IncorrectPassword=Vneseno geslo ni pravilno. Poizkusite ponovno. + +; *** "License Agreement" wizard page +WizardLicense=Licenna pogodba +LicenseLabel=Pred nadaljevanjem preberite licenno pogodbo za uporabo programa. +LicenseLabel3=Preberite licenno pogodbo za uporabo programa. Program lahko namestite le, e se s pogodbo v celoti strinjate. +LicenseAccepted=&Da, sprejemam vse pogoje licenne pogodbe +LicenseNotAccepted=N&e, pogojev licenne pogodbe ne sprejmem + +; *** "Information" wizard pages +WizardInfoBefore=Informacije +InfoBeforeLabel=Pred nadaljevanjem preberite naslednje pomembne informacije. +InfoBeforeClickLabel=Ko boste pripravljeni na nadaljevanje namestitve, kliknite Naprej. +WizardInfoAfter=Informacije +InfoAfterLabel=Pred nadaljevanjem preberite naslednje pomembne informacije. +InfoAfterClickLabel=Ko boste pripravljeni na nadaljevanje namestitve, kliknite Naprej. + +; *** "User Information" wizard page +WizardUserInfo=Podatki o uporabniku +UserInfoDesc=Vnesite svoje podatke. +UserInfoName=&Ime: +UserInfoOrg=&Podjetje: +UserInfoSerial=&Serijska tevilka: +UserInfoNameRequired=Vnos imena je obvezen. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Izbira ciljnega mesta +SelectDirDesc=Kam elite namestiti program [name]? +SelectDirLabel3=Program [name] bo nameen v naslednjo mapo. +SelectDirBrowseLabel=Za nadaljevanje kliknite Naprej. e elite izbrati drugo mapo, kliknite Prebrskaj. +DiskSpaceGBLabel=Na disku mora biti vsaj [gb] GB prostora. +DiskSpaceMBLabel=Na disku mora biti vsaj [mb] MB prostora. +CannotInstallToNetworkDrive=Programa ni mogoe namestiti na mreni pogon. +CannotInstallToUNCPath=Programa ni mogoe namestiti v UNC pot. +InvalidPath=Vpisati morate polno pot vkljuno z oznako pogona. Primer:%n%nC:\PROGRAM%n%nali UNC pot v obliki:%n%n\\strenik\mapa_skupne_rabe +InvalidDrive=Izbrani pogon ali omreno sredstvo UNC ne obstaja ali ni dostopno. Izberite drugega. +DiskSpaceWarningTitle=Na disku ni dovolj prostora +DiskSpaceWarning=Namestitev potrebuje vsaj %1 KB prostora, toda na izbranem pogonu je na voljo le %2 KB.%n%nelite kljub temu nadaljevati? +DirNameTooLong=Ime mape ali poti je predolgo. +InvalidDirName=Ime mape ni veljavno. +BadDirName32=Ime mape ne sme vsebovati naslednjih znakov:%n%n%1 +DirExistsTitle=Mapa e obstaja +DirExists=Mapa%n%n%1%n%ne obstaja. elite program vseeno namestiti v to mapo? +DirDoesntExistTitle=Mapa ne obstaja +DirDoesntExist=Mapa %n%n%1%n%nne obstaja. Ali jo elite ustvariti? + +; *** "Select Components" wizard page +WizardSelectComponents=Izbira komponent +SelectComponentsDesc=Katere komponente elite namestiti? +SelectComponentsLabel2=Oznaite komponente, ki jih elite namestiti; odznaite komponente, ki jih ne elite namestiti. Kliknite Naprej, ko boste pripravljeni za nadaljevanje. +FullInstallation=Popolna namestitev +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Osnovna namestitev +CustomInstallation=Namestitev po meri +NoUninstallWarningTitle=Komponente e obstajajo +NoUninstallWarning=Namestitveni program je ugotovil, da so naslednje komponente e nameene v raunalniku:%n%n%1%n%nNamestitveni program teh e nameenih komponent ne bo odstranil.%n%nelite vseeno nadaljevati? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Za izbrano namestitev potrebujete vsaj [gb] GB prostora na disku. +ComponentsDiskSpaceMBLabel=Za izbrano namestitev potrebujete vsaj [mb] MB prostora na disku. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Izbira dodatnih opravil +SelectTasksDesc=Katera dodatna opravila elite izvesti? +SelectTasksLabel2=Izberite dodatna opravila, ki jih bo namestitveni program opravil med namestitvijo programa [name], nato kliknite Naprej. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Izbira mape v meniju Zaetek +SelectStartMenuFolderDesc=Kje naj namestitveni program ustvari blinjice? +SelectStartMenuFolderLabel3=Namestitveni program bo ustvaril blinjice v naslednji mapi v meniju Start. +SelectStartMenuFolderBrowseLabel=Za nadaljevanje kliknite Naprej. e elite izbrati drugo mapo, kliknite Prebrskaj. +MustEnterGroupName=Ime skupine mora biti vpisano. +GroupNameTooLong=Ime mape ali poti je predolgo. +InvalidGroupName=Ime mape ni veljavno. +BadGroupName=Ime skupine ne sme vsebovati naslednjih znakov:%n%n%1 +NoProgramGroupCheck2=&Ne ustvari mape v meniju Start + +; *** "Ready to Install" wizard page +WizardReady=Pripravljen za namestitev +ReadyLabel1=Namestitveni program je pripravljen za namestitev programa [name] v va raunalnik. +ReadyLabel2a=Kliknite Namesti za zaetek nameanja. Kliknite Nazaj, e elite pregledati ali spremeniti katerokoli nastavitev. +ReadyLabel2b=Kliknite Namesti za zaetek nameanja. +ReadyMemoUserInfo=Podatki o uporabniku: +ReadyMemoDir=Ciljno mesto: +ReadyMemoType=Vrsta namestitve: +ReadyMemoComponents=Izbrane komponente: +ReadyMemoGroup=Mapa v meniju Zaetek: +ReadyMemoTasks=Dodatna opravila: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Prenaam dodatne datoteke... +ButtonStopDownload=Prekini preno&s +StopDownload=Ali res elite prekiniti prenos? +ErrorDownloadAborted=Prenos prekinjen +ErrorDownloadFailed=Prenos ni uspel: %1 %2 +ErrorDownloadSizeFailed=Pridobivanje velikosti ni uspelo: %1 %2 +ErrorFileHash1=Pridobivanje zgoene vrednosti ni uspelo: %1 +ErrorFileHash2=Neveljavna zgoena vrednost: priakovana %1, dobljena %2 +ErrorProgress=Neveljaven potek: %1 od %2 +ErrorFileSize=Neveljavna velikost datoteke: priakovana %1, dobljena %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Pripravljam za namestitev +PreparingDesc=Namestitveni program je pripravljen za namestitev programa [name] v va raunalnik. +PreviousInstallNotCompleted=Namestitev ali odstranitev prejnjega programa ni bila konana. Da bi jo dokonali, morate raunalnik znova zagnati.%n%nPo ponovnem zagonu raunalnika znova zaenite namestitveni program, da boste konali namestitev programa [name]. +CannotContinue=Namestitveni program ne more nadaljevati. Pritisnite Preklii za izhod. + +; *** "Installing" wizard page +ApplicationsFound=Naslednji programi uporabljajo datoteke, ki jih mora namestitveni program posodobiti. Priporoljivo je, da namestitvenemu programu dovolite, da te programe kona. +ApplicationsFound2=Naslednji programi uporabljajo datoteke, ki jih mora namestitveni program posodobiti. Priporoljivo je, da namestitvenemu programu dovolite, da te programe kona. Po koncu namestitve bo namestitveni program poizkusil znova zagnati te programe. +CloseApplications=S&amodejno zapri programe +DontCloseApplications=&Ne zapri programov +ErrorCloseApplications=Namestitvenemu programu ni uspelo samodejno zapreti vseh programov. Priporoljivo je, da pred nadaljevanjem zaprete vse programe, ki uporabljajo datoteke, katere mora namestitev posodobiti. +PrepareToInstallNeedsRestart=Namestitveni program mora znova zagnati va raunalnik. Za dokonanje namestitve programa [name], po ponovnem zagonu znova zaenite namestitveni program.%n%nAli elite zdaj znova zagnati raunalnik? + +WizardInstalling=Nameanje +InstallingLabel=Poakajte, da bo program [name] nameen v va raunalnik. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Zakljuek namestitve programa [name] +FinishedLabelNoIcons=Program [name] je nameen v va raunalnik. +FinishedLabel=Program [name] je nameen v va raunalnik. Program zaenete tako, da odprete pravkar ustvarjene programske ikone. +ClickFinish=Kliknite tipko Konaj za zakljuek namestitve. +FinishedRestartLabel=Za dokonanje namestitve programa [name] morate raunalnik znova zagnati. Ali ga elite znova zagnati zdaj? +FinishedRestartMessage=Za dokonanje namestitve programa [name] morate raunalnik znova zagnati. %n%nAli ga elite znova zagnati zdaj? +ShowReadmeCheck=elim prebrati datoteko BERIME +YesRadio=&Da, raunalnik znova zaeni zdaj +NoRadio=&Ne, raunalnik bom znova zagnal pozneje + +; used for example as 'Run MyProg.exe' +RunEntryExec=Zaeni %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Preglej %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=Namestitveni program potrebuje naslednji disk +SelectDiskLabel2=Vstavite disk %1 in kliknite V redu.%n%ne se datoteke s tega diska nahajajo v drugi mapi kot je navedena spodaj, vnesite pravilno pot ali kliknite Prebrskaj. +PathLabel=&Pot: +FileNotInDir2=Datoteke %1 ni v mapi %2. Vstavite pravilni disk ali izberite drugo mapo. +SelectDirectoryLabel=Vnesite mesto naslednjega diska. + +; *** Installation phase messages +SetupAborted=Namestitev ni bila konana.%n%nOdpravite teavo in znova odprite namestitveni program. +AbortRetryIgnoreSelectAction=Izberite dejanje +AbortRetryIgnoreRetry=Poizkusi &znova +AbortRetryIgnoreIgnore=&Prezri napako in nadaljuj +AbortRetryIgnoreCancel=Preklii namestitev + +; *** Installation status messages +StatusClosingApplications=Zapiranje programov... +StatusCreateDirs=Ustvarjanje map... +StatusExtractFiles=Razirjanje datotek... +StatusCreateIcons=Ustvarjanje blinjic... +StatusCreateIniEntries=Vpisovanje v INI datoteke... +StatusCreateRegistryEntries=Ustvarjanje vnosov v register... +StatusRegisterFiles=Registriranje datotek... +StatusSavingUninstall=Zapisovanje podatkov za odstranitev... +StatusRunProgram=Zakljuevanje namestitve... +StatusRestartingApplications=Zaganjanje programov... +StatusRollback=Obnavljanje prvotnega stanja... + +; *** Misc. errors +ErrorInternal2=Interna napaka: %1 +ErrorFunctionFailedNoCode=%1 ni uspel(a) +ErrorFunctionFailed=%1 ni uspel(a); koda %2 +ErrorFunctionFailedWithMessage=%1 ni uspela; koda %2.%n%3 +ErrorExecutingProgram=Ne morem zagnati programa:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Napaka pri odpiranju kljua v registru:%n%1\%2 +ErrorRegCreateKey=Napaka pri ustvarjanju kljua v registru:%n%1\%2 +ErrorRegWriteKey=Napaka pri pisanju kljua v registru:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Napaka pri vpisu v INI datoteko %1. + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=Pre&skoi to datoteko (ni priporoeno) +FileAbortRetryIgnoreIgnoreNotRecommended=Prezr&i napako in nadaljuj (ni priporoeno) +SourceIsCorrupted=Izvorna datoteka je okvarjena +SourceDoesntExist=Izvorna datoteka %1 ne obstaja +ExistingFileReadOnly2=Obstojee datoteke ni mogoe nadomestiti, ker ima oznako samo za branje. +ExistingFileReadOnlyRetry=Odst&rani oznako samo za branje in poizkusi ponovno +ExistingFileReadOnlyKeepExisting=&Ohrani obstojeo datoteko +ErrorReadingExistingDest=Pri branju obstojee datoteke je prilo do napake: +FileExistsSelectAction=Izberite dejanje +FileExists2=Datoteka e obstaja. +FileExistsOverwriteExisting=&Prepii obstojeo datoteko +FileExistsKeepExisting=&Ohrani trenutno datoteko +FileExistsOverwriteOrKeepAll=&To naredite za preostale spore +ExistingFileNewerSelectAction=Izberite dejanje +ExistingFileNewer2=Obstojea datoteka je noveja, kot datoteka, ki se namea. +ExistingFileNewerOverwriteExisting=&Prepii obstojeo datoteko +ExistingFileNewerKeepExisting=&Ohrani trenutno datoteko (priporoeno) +ExistingFileNewerOverwriteOrKeepAll=&To naredite za preostale spore +ErrorChangingAttr=Pri poskusu spremembe lastnosti datoteke je prilo do napake: +ErrorCreatingTemp=Pri ustvarjanju datoteke v ciljni mapi je prilo do napake: +ErrorReadingSource=Pri branju izvorne datoteke je prilo do napake: +ErrorCopying=Pri kopiranju datoteke je prilo do napake: +ErrorReplacingExistingFile=Pri poskusu zamenjave obstojee datoteke je prilo do napake: +ErrorRestartReplace=Napaka RestartReplace: +ErrorRenamingTemp=Pri poskusu preimenovanja datoteke v ciljni mapi je prilo do napake: +ErrorRegisterServer=Registracija DLL/OCX ni uspela: %1 +ErrorRegSvr32Failed=RegSvr32 ni uspel s kodo napake %1 +ErrorRegisterTypeLib=Registracija TypeLib ni uspela: %1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bitno +UninstallDisplayNameMark64Bit=64-bitno +UninstallDisplayNameMarkAllUsers=vsi uporabniki +UninstallDisplayNameMarkCurrentUser=trenutni uporabnik + +; *** Post-installation errors +ErrorOpeningReadme=Pri odpiranju datoteke BERIME je prilo do napake. +ErrorRestartingComputer=Namestitvenemu programu ni uspelo znova zagnati raunalnika. Sami znova zaenite raunalnik. + +; *** Uninstaller messages +UninstallNotFound=Datoteka %1 ne obstaja. Odstranitev ni mogoa. +UninstallOpenError=Datoteke %1 ne morem odpreti. Ne morem odstraniti +UninstallUnsupportedVer=Dnevnika datoteka %1 je v obliki, ki je ta razliica odstranitvenega programa ne razume. Programa ni mogoe odstraniti +UninstallUnknownEntry=V dnevniki datoteki je bil najden neznani vpis (%1) +ConfirmUninstall=Ste prepriani, da elite v celoti odstraniti program %1 in pripadajoe komponente? +UninstallOnlyOnWin64=To namestitev je mogoe odstraniti le v 64-bitni razliici sistema Windows. +OnlyAdminCanUninstall=Za odstranitev tega programa morate imeti skrbnike pravice. +UninstallStatusLabel=Poakajte, da se program %1 odstrani iz vaega raunalnika. +UninstalledAll=Program %1 je bil uspeno odstranjen iz vaega raunalnika. +UninstalledMost=Odstranjevanje programa %1 je konano.%n%nNekatere datoteke niso bile odstranjene in jih lahko odstranite rono. +UninstalledAndNeedsRestart=Za dokonanje odstranitve programa %1 morate raunalnik znova zagnati.%n%nAli ga elite znova zagnati zdaj? +UninstallDataCorrupted=Datoteka %1 je okvarjena. Odstranitev ni mona + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=elite odstraniti datoteko v skupni rabi? +ConfirmDeleteSharedFile2=Spodaj izpisane datoteke v skupni rabi ne uporablja ve noben program. elite odstraniti to datoteko?%n%ne jo uporablja katerikoli program in jo boste odstranili, ta program verjetno ne bo ve deloval pravilno. e niste prepriani, kliknite Ne. e boste datoteko ohranili v raunalniku, ne bo ni narobe. +SharedFileNameLabel=Ime datoteke: +SharedFileLocationLabel=Mesto: +WizardUninstalling=Odstranjevanje programa +StatusUninstalling=Odstranjujem %1... + +ShutdownBlockReasonInstallingApp=Nameam %1. +ShutdownBlockReasonUninstallingApp=Odstranjujem %1. + +[CustomMessages] + +NameAndVersion=%1 razliica %2 +AdditionalIcons=Dodatne ikone: +CreateDesktopIcon=Ustvari ikono na &namizju +CreateQuickLaunchIcon=Ustvari ikono za &hitri zagon +ProgramOnTheWeb=%1 na spletu +UninstallProgram=Odstrani %1 +LaunchProgram=Odpri %1 +AssocFileExtension=&Povei %1 s pripono %2 +AssocingFileExtension=Povezujem %1 s pripono %2... +AutoStartProgramGroupDescription=Zagon: +AutoStartProgram=Samodejno zaeni %1 +AddonHostProgramNotFound=Programa %1 ni bilo mogoe najti v izbrani mapi.%n%nAli elite vseeno nadaljevati? diff --git a/installer/innosetup/Languages/Spanish.isl b/installer/innosetup/Languages/Spanish.isl new file mode 100644 index 000000000..6fff47c7b --- /dev/null +++ b/installer/innosetup/Languages/Spanish.isl @@ -0,0 +1,383 @@ +; *** Inno Setup version 6.1.0+ Spanish messages *** +; +; Maintained by Jorge Andres Brugger (jbrugger@ideaworks.com.ar) +; Spanish.isl version 1.5.2 (20211123) +; Default.isl version 6.1.0 +; +; Thanks to Germn Giraldo, Jordi Latorre, Ximo Tamarit, Emiliano Llano, +; Ramn Verduzco, Graciela Garca, Carles Millan and Rafael Barranco-Droege + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Espa<00F1>ol +LanguageID=$0c0a +LanguageCodePage=1252 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=Instalar +SetupWindowTitle=Instalar - %1 +UninstallAppTitle=Desinstalar +UninstallAppFullTitle=Desinstalar - %1 + +; *** Misc. common +InformationTitle=Informacin +ConfirmTitle=Confirmar +ErrorTitle=Error + +; *** SetupLdr messages +SetupLdrStartupMessage=Este programa instalar %1. Desea continuar? +LdrCannotCreateTemp=Imposible crear archivo temporal. Instalacin interrumpida +LdrCannotExecTemp=Imposible ejecutar archivo en la carpeta temporal. Instalacin interrumpida +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nError %2: %3 +SetupFileMissing=El archivo %1 no se encuentra en la carpeta de instalacin. Por favor, solucione el problema u obtenga una copia nueva del programa. +SetupFileCorrupt=Los archivos de instalacin estn daados. Por favor, obtenga una copia nueva del programa. +SetupFileCorruptOrWrongVer=Los archivos de instalacin estn daados o son incompatibles con esta versin del programa de instalacin. Por favor, solucione el problema u obtenga una copia nueva del programa. +InvalidParameter=Se ha utilizado un parmetro no vlido en la lnea de comandos:%n%n%1 +SetupAlreadyRunning=El programa de instalacin an est ejecutndose. +WindowsVersionNotSupported=Este programa no es compatible con la versin de Windows de su equipo. +WindowsServicePackRequired=Este programa requiere %1 Service Pack %2 o posterior. +NotOnThisPlatform=Este programa no se ejecutar en %1. +OnlyOnThisPlatform=Este programa debe ejecutarse en %1. +OnlyOnTheseArchitectures=Este programa solo puede instalarse en versiones de Windows diseadas para las siguientes arquitecturas de procesadores:%n%n%1 +WinVersionTooLowError=Este programa requiere %1 versin %2 o posterior. +WinVersionTooHighError=Este programa no puede instalarse en %1 versin %2 o posterior. +AdminPrivilegesRequired=Debe iniciar la sesin como administrador para instalar este programa. +PowerUserPrivilegesRequired=Debe iniciar la sesin como administrador o como miembro del grupo de Usuarios Avanzados para instalar este programa. +SetupAppRunningError=El programa de instalacin ha detectado que %1 est ejecutndose.%n%nPor favor, cirrelo ahora, luego haga clic en Aceptar para continuar o en Cancelar para salir. +UninstallAppRunningError=El desinstalador ha detectado que %1 est ejecutndose.%n%nPor favor, cirrelo ahora, luego haga clic en Aceptar para continuar o en Cancelar para salir. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=Seleccin del Modo de Instalacin +PrivilegesRequiredOverrideInstruction=Seleccione el modo de instalacin +PrivilegesRequiredOverrideText1=%1 puede ser instalado para todos los usuarios (requiere privilegios administrativos), o solo para Ud. +PrivilegesRequiredOverrideText2=%1 puede ser instalado solo para Ud, o para todos los usuarios (requiere privilegios administrativos). +PrivilegesRequiredOverrideAllUsers=Instalar para &todos los usuarios +PrivilegesRequiredOverrideAllUsersRecommended=Instalar para &todos los usuarios (recomendado) +PrivilegesRequiredOverrideCurrentUser=Instalar para &m solamente +PrivilegesRequiredOverrideCurrentUserRecommended=Instalar para &m solamente (recomendado) + +; *** Misc. errors +ErrorCreatingDir=El programa de instalacin no pudo crear la carpeta "%1" +ErrorTooManyFilesInDir=Imposible crear un archivo en la carpeta "%1" porque contiene demasiados archivos + +; *** Setup common messages +ExitSetupTitle=Salir de la Instalacin +ExitSetupMessage=La instalacin no se ha completado an. Si cancela ahora, el programa no se instalar.%n%nPuede ejecutar nuevamente el programa de instalacin en otra ocasin para completarla.%n%nSalir de la instalacin? +AboutSetupMenuItem=&Acerca de Instalar... +AboutSetupTitle=Acerca de Instalar +AboutSetupMessage=%1 versin %2%n%3%n%n%1 sitio Web:%n%4 +AboutSetupNote= +TranslatorNote=Spanish translation maintained by Jorge Andres Brugger (jbrugger@gmx.net) + +; *** Buttons +ButtonBack=< &Atrs +ButtonNext=&Siguiente > +ButtonInstall=&Instalar +ButtonOK=Aceptar +ButtonCancel=Cancelar +ButtonYes=&S +ButtonYesToAll=S a &Todo +ButtonNo=&No +ButtonNoToAll=N&o a Todo +ButtonFinish=&Finalizar +ButtonBrowse=&Examinar... +ButtonWizardBrowse=&Examinar... +ButtonNewFolder=&Crear Nueva Carpeta + +; *** "Select Language" dialog messages +SelectLanguageTitle=Seleccione el Idioma de la Instalacin +SelectLanguageLabel=Seleccione el idioma a utilizar durante la instalacin. + +; *** Common wizard text +ClickNext=Haga clic en Siguiente para continuar o en Cancelar para salir de la instalacin. +BeveledLabel= +BrowseDialogTitle=Buscar Carpeta +BrowseDialogLabel=Seleccione una carpeta y luego haga clic en Aceptar. +NewFolderName=Nueva Carpeta + +; *** "Welcome" wizard page +WelcomeLabel1=Bienvenido al asistente de instalacin de [name] +WelcomeLabel2=Este programa instalar [name/ver] en su sistema.%n%nSe recomienda cerrar todas las dems aplicaciones antes de continuar. + +; *** "Password" wizard page +WizardPassword=Contrasea +PasswordLabel1=Esta instalacin est protegida por contrasea. +PasswordLabel3=Por favor, introduzca la contrasea y haga clic en Siguiente para continuar. En las contraseas se hace diferencia entre maysculas y minsculas. +PasswordEditLabel=&Contrasea: +IncorrectPassword=La contrasea introducida no es correcta. Por favor, intntelo nuevamente. + +; *** "License Agreement" wizard page +WizardLicense=Acuerdo de Licencia +LicenseLabel=Es importante que lea la siguiente informacin antes de continuar. +LicenseLabel3=Por favor, lea el siguiente acuerdo de licencia. Debe aceptar las clusulas de este acuerdo antes de continuar con la instalacin. +LicenseAccepted=A&cepto el acuerdo +LicenseNotAccepted=&No acepto el acuerdo + +; *** "Information" wizard pages +WizardInfoBefore=Informacin +InfoBeforeLabel=Es importante que lea la siguiente informacin antes de continuar. +InfoBeforeClickLabel=Cuando est listo para continuar con la instalacin, haga clic en Siguiente. +WizardInfoAfter=Informacin +InfoAfterLabel=Es importante que lea la siguiente informacin antes de continuar. +InfoAfterClickLabel=Cuando est listo para continuar, haga clic en Siguiente. + +; *** "User Information" wizard page +WizardUserInfo=Informacin de Usuario +UserInfoDesc=Por favor, introduzca sus datos. +UserInfoName=Nombre de &Usuario: +UserInfoOrg=&Organizacin: +UserInfoSerial=Nmero de &Serie: +UserInfoNameRequired=Debe introducir un nombre. + +; *** "Select Destination Location" wizard page +WizardSelectDir=Seleccione la Carpeta de Destino +SelectDirDesc=Dnde debe instalarse [name]? +SelectDirLabel3=El programa instalar [name] en la siguiente carpeta. +SelectDirBrowseLabel=Para continuar, haga clic en Siguiente. Si desea seleccionar una carpeta diferente, haga clic en Examinar. +DiskSpaceGBLabel=Se requieren al menos [gb] GB de espacio libre en el disco. +DiskSpaceMBLabel=Se requieren al menos [mb] MB de espacio libre en el disco. +CannotInstallToNetworkDrive=El programa de instalacin no puede realizar la instalacin en una unidad de red. +CannotInstallToUNCPath=El programa de instalacin no puede realizar la instalacin en una ruta de acceso UNC. +InvalidPath=Debe introducir una ruta completa con la letra de la unidad; por ejemplo:%n%nC:\APP%n%no una ruta de acceso UNC de la siguiente forma:%n%n\\servidor\compartido +InvalidDrive=La unidad o ruta de acceso UNC que seleccion no existe o no es accesible. Por favor, seleccione otra. +DiskSpaceWarningTitle=Espacio Insuficiente en Disco +DiskSpaceWarning=La instalacin requiere al menos %1 KB de espacio libre, pero la unidad seleccionada solo cuenta con %2 KB disponibles.%n%nDesea continuar de todas formas? +DirNameTooLong=El nombre de la carpeta o la ruta son demasiado largos. +InvalidDirName=El nombre de la carpeta no es vlido. +BadDirName32=Los nombres de carpetas no pueden incluir los siguientes caracteres:%n%n%1 +DirExistsTitle=La Carpeta Ya Existe +DirExists=La carpeta:%n%n%1%n%nya existe. Desea realizar la instalacin en esa carpeta de todas formas? +DirDoesntExistTitle=La Carpeta No Existe +DirDoesntExist=La carpeta:%n%n%1%n%nno existe. Desea crear esa carpeta? + +; *** "Select Components" wizard page +WizardSelectComponents=Seleccione los Componentes +SelectComponentsDesc=Qu componentes deben instalarse? +SelectComponentsLabel2=Seleccione los componentes que desea instalar y desmarque los componentes que no desea instalar. Haga clic en Siguiente cuando est listo para continuar. +FullInstallation=Instalacin Completa +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=Instalacin Compacta +CustomInstallation=Instalacin Personalizada +NoUninstallWarningTitle=Componentes Encontrados +NoUninstallWarning=El programa de instalacin ha detectado que los siguientes componentes ya estn instalados en su sistema:%n%n%1%n%nDesmarcar estos componentes no los desinstalar.%n%nDesea continuar de todos modos? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=La seleccin actual requiere al menos [gb] GB de espacio en disco. +ComponentsDiskSpaceMBLabel=La seleccin actual requiere al menos [mb] MB de espacio en disco. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=Seleccione las Tareas Adicionales +SelectTasksDesc=Qu tareas adicionales deben realizarse? +SelectTasksLabel2=Seleccione las tareas adicionales que desea que se realicen durante la instalacin de [name] y haga clic en Siguiente. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=Seleccione la Carpeta del Men Inicio +SelectStartMenuFolderDesc=Dnde deben colocarse los accesos directos del programa? +SelectStartMenuFolderLabel3=El programa de instalacin crear los accesos directos del programa en la siguiente carpeta del Men Inicio. +SelectStartMenuFolderBrowseLabel=Para continuar, haga clic en Siguiente. Si desea seleccionar una carpeta distinta, haga clic en Examinar. +MustEnterGroupName=Debe proporcionar un nombre de carpeta. +GroupNameTooLong=El nombre de la carpeta o la ruta son demasiado largos. +InvalidGroupName=El nombre de la carpeta no es vlido. +BadGroupName=El nombre de la carpeta no puede incluir ninguno de los siguientes caracteres:%n%n%1 +NoProgramGroupCheck2=&No crear una carpeta en el Men Inicio + +; *** "Ready to Install" wizard page +WizardReady=Listo para Instalar +ReadyLabel1=Ahora el programa est listo para iniciar la instalacin de [name] en su sistema. +ReadyLabel2a=Haga clic en Instalar para continuar con el proceso o haga clic en Atrs si desea revisar o cambiar alguna configuracin. +ReadyLabel2b=Haga clic en Instalar para continuar con el proceso. +ReadyMemoUserInfo=Informacin del usuario: +ReadyMemoDir=Carpeta de Destino: +ReadyMemoType=Tipo de Instalacin: +ReadyMemoComponents=Componentes Seleccionados: +ReadyMemoGroup=Carpeta del Men Inicio: +ReadyMemoTasks=Tareas Adicionales: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Descargando archivos adicionales... +ButtonStopDownload=&Detener descarga +StopDownload=Est seguiro que desea detener la descarga? +ErrorDownloadAborted=Descarga cancelada +ErrorDownloadFailed=Fall descarga: %1 %2 +ErrorDownloadSizeFailed=Fall obtencin de tamao: %1 %2 +ErrorFileHash1=Fall hash del archivo: %1 +ErrorFileHash2=Hash de archivo no vlido: esperado %1, encontrado %2 +ErrorProgress=Progreso no vlido: %1 de %2 +ErrorFileSize=Tamao de archivo no vlido: esperado %1, encontrado %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=Preparndose para Instalar +PreparingDesc=El programa de instalacin est preparndose para instalar [name] en su sistema. +PreviousInstallNotCompleted=La instalacin/desinstalacin previa de un programa no se complet. Deber reiniciar el sistema para completar esa instalacin.%n%nUna vez reiniciado el sistema, ejecute el programa de instalacin nuevamente para completar la instalacin de [name]. +CannotContinue=El programa de instalacin no puede continuar. Por favor, presione Cancelar para salir. +ApplicationsFound=Las siguientes aplicaciones estn usando archivos que necesitan ser actualizados por el programa de instalacin. Se recomienda que permita al programa de instalacin cerrar automticamente estas aplicaciones. +ApplicationsFound2=Las siguientes aplicaciones estn usando archivos que necesitan ser actualizados por el programa de instalacin. Se recomienda que permita al programa de instalacin cerrar automticamente estas aplicaciones. Al completarse la instalacin, el programa de instalacin intentar reiniciar las aplicaciones. +CloseApplications=&Cerrar automticamente las aplicaciones +DontCloseApplications=&No cerrar las aplicaciones +ErrorCloseApplications=El programa de instalacin no pudo cerrar de forma automtica todas las aplicaciones. Se recomienda que, antes de continuar, cierre todas las aplicaciones que utilicen archivos que necesitan ser actualizados por el programa de instalacin. +PrepareToInstallNeedsRestart=El programa de instalacin necesita reiniciar el sistema. Una vez que se haya reiniciado ejecute nuevamente el programa de instalacin para completar la instalacin de [name].%n%nDesea reiniciar el sistema ahora? + +; *** "Installing" wizard page +WizardInstalling=Instalando +InstallingLabel=Por favor, espere mientras se instala [name] en su sistema. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=Completando la instalacin de [name] +FinishedLabelNoIcons=El programa complet la instalacin de [name] en su sistema. +FinishedLabel=El programa complet la instalacin de [name] en su sistema. Puede ejecutar la aplicacin utilizando los accesos directos creados. +ClickFinish=Haga clic en Finalizar para salir del programa de instalacin. +FinishedRestartLabel=Para completar la instalacin de [name], su sistema debe reiniciarse. Desea reiniciarlo ahora? +FinishedRestartMessage=Para completar la instalacin de [name], su sistema debe reiniciarse.%n%nDesea reiniciarlo ahora? +ShowReadmeCheck=S, deseo ver el archivo LAME +YesRadio=&S, deseo reiniciar el sistema ahora +NoRadio=&No, reiniciar el sistema ms tarde +; used for example as 'Run MyProg.exe' +RunEntryExec=Ejecutar %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Ver %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=El Programa de Instalacin Necesita el Siguiente Disco +SelectDiskLabel2=Por favor, inserte el Disco %1 y haga clic en Aceptar.%n%nSi los archivos pueden ser hallados en una carpeta diferente a la indicada abajo, introduzca la ruta correcta o haga clic en Examinar. +PathLabel=&Ruta: +FileNotInDir2=El archivo "%1" no se ha podido hallar en "%2". Por favor, inserte el disco correcto o seleccione otra carpeta. +SelectDirectoryLabel=Por favor, especifique la ubicacin del siguiente disco. + +; *** Installation phase messages +SetupAborted=La instalacin no se ha completado.%n%nPor favor solucione el problema y ejecute nuevamente el programa de instalacin. +AbortRetryIgnoreSelectAction=Seleccione accin +AbortRetryIgnoreRetry=&Reintentar +AbortRetryIgnoreIgnore=&Ignorar el error y continuar +AbortRetryIgnoreCancel=Cancelar instalacin + +; *** Installation status messages +StatusClosingApplications=Cerrando aplicaciones... +StatusCreateDirs=Creando carpetas... +StatusExtractFiles=Extrayendo archivos... +StatusCreateIcons=Creando accesos directos... +StatusCreateIniEntries=Creando entradas INI... +StatusCreateRegistryEntries=Creando entradas de registro... +StatusRegisterFiles=Registrando archivos... +StatusSavingUninstall=Guardando informacin para desinstalar... +StatusRunProgram=Terminando la instalacin... +StatusRestartingApplications=Reiniciando aplicaciones... +StatusRollback=Deshaciendo cambios... + +; *** Misc. errors +ErrorInternal2=Error interno: %1 +ErrorFunctionFailedNoCode=%1 fall +ErrorFunctionFailed=%1 fall; cdigo %2 +ErrorFunctionFailedWithMessage=%1 fall; cdigo %2.%n%3 +ErrorExecutingProgram=Imposible ejecutar el archivo:%n%1 + +; *** Registry errors +ErrorRegOpenKey=Error al abrir la clave del registro:%n%1\%2 +ErrorRegCreateKey=Error al crear la clave del registro:%n%1\%2 +ErrorRegWriteKey=Error al escribir la clave del registro:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Error al crear entrada INI en el archivo "%1". + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&Omitir este archivo (no recomendado) +FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorar el error y continuar (no recomendado) +SourceIsCorrupted=El archivo de origen est daado +SourceDoesntExist=El archivo de origen "%1" no existe +ExistingFileReadOnly2=El archivo existente no puede ser reemplazado debido a que est marcado como solo-lectura. +ExistingFileReadOnlyRetry=&Elimine el atributo de solo-lectura y reintente +ExistingFileReadOnlyKeepExisting=&Mantener el archivo existente +ErrorReadingExistingDest=Ocurri un error mientras se intentaba leer el archivo: +FileExistsSelectAction=Seleccione accin +FileExists2=El archivo ya existe. +FileExistsOverwriteExisting=&Sobreescribir el archivo existente +FileExistsKeepExisting=&Mantener el archivo existente +FileExistsOverwriteOrKeepAll=&Hacer lo mismo para lo siguientes conflictos +ExistingFileNewerSelectAction=Seleccione accin +ExistingFileNewer2=El archivo existente es ms reciente que el que se est tratando de instalar. +ExistingFileNewerOverwriteExisting=&Sobreescribir el archivo existente +ExistingFileNewerKeepExisting=&Mantener el archivo existente (recomendado) +ExistingFileNewerOverwriteOrKeepAll=&Hacer lo mismo para lo siguientes conflictos +ErrorChangingAttr=Ocurri un error al intentar cambiar los atributos del archivo: +ErrorCreatingTemp=Ocurri un error al intentar crear un archivo en la carpeta de destino: +ErrorReadingSource=Ocurri un error al intentar leer el archivo de origen: +ErrorCopying=Ocurri un error al intentar copiar el archivo: +ErrorReplacingExistingFile=Ocurri un error al intentar reemplazar el archivo existente: +ErrorRestartReplace=Fall reintento de reemplazar: +ErrorRenamingTemp=Ocurri un error al intentar renombrar un archivo en la carpeta de destino: +ErrorRegisterServer=Imposible registrar el DLL/OCX: %1 +ErrorRegSvr32Failed=RegSvr32 fall con el cdigo de salida %1 +ErrorRegisterTypeLib=Imposible registrar la librera de tipos: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=Todos los usuarios +UninstallDisplayNameMarkCurrentUser=Usuario actual + +; *** Post-installation errors +ErrorOpeningReadme=Ocurri un error al intentar abrir el archivo LAME. +ErrorRestartingComputer=El programa de instalacin no pudo reiniciar el equipo. Por favor, hgalo manualmente. + +; *** Uninstaller messages +UninstallNotFound=El archivo "%1" no existe. Imposible desinstalar. +UninstallOpenError=El archivo "%1" no pudo ser abierto. Imposible desinstalar +UninstallUnsupportedVer=El archivo de registro para desinstalar "%1" est en un formato no reconocido por esta versin del desinstalador. Imposible desinstalar +UninstallUnknownEntry=Se encontr una entrada desconocida (%1) en el registro de desinstalacin +ConfirmUninstall=Est seguro que desea desinstalar completamente %1 y todos sus componentes? +UninstallOnlyOnWin64=Este programa solo puede ser desinstalado en Windows de 64-bits. +OnlyAdminCanUninstall=Este programa solo puede ser desinstalado por un usuario con privilegios administrativos. +UninstallStatusLabel=Por favor, espere mientras %1 es desinstalado de su sistema. +UninstalledAll=%1 se desinstal satisfactoriamente de su sistema. +UninstalledMost=La desinstalacin de %1 ha sido completada.%n%nAlgunos elementos no pudieron eliminarse, pero podr eliminarlos manualmente si lo desea. +UninstalledAndNeedsRestart=Para completar la desinstalacin de %1, su sistema debe reiniciarse.%n%nDesea reiniciarlo ahora? +UninstallDataCorrupted=El archivo "%1" est daado. No puede desinstalarse + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=Eliminar Archivo Compartido? +ConfirmDeleteSharedFile2=El sistema indica que el siguiente archivo compartido no es utilizado por ningn otro programa. Desea eliminar este archivo compartido?%n%nSi elimina el archivo y hay programas que lo utilizan, esos programas podran dejar de funcionar correctamente. Si no est seguro, elija No. Dejar el archivo en su sistema no producir ningn dao. +SharedFileNameLabel=Archivo: +SharedFileLocationLabel=Ubicacin: +WizardUninstalling=Estado de la Desinstalacin +StatusUninstalling=Desinstalando %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=Instalando %1. +ShutdownBlockReasonUninstallingApp=Desinstalando %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 versin %2 +AdditionalIcons=Accesos directos adicionales: +CreateDesktopIcon=Crear un acceso directo en el &escritorio +CreateQuickLaunchIcon=Crear un acceso directo en &Inicio Rpido +ProgramOnTheWeb=%1 en la Web +UninstallProgram=Desinstalar %1 +LaunchProgram=Ejecutar %1 +AssocFileExtension=&Asociar %1 con la extensin de archivo %2 +AssocingFileExtension=Asociando %1 con la extensin de archivo %2... +AutoStartProgramGroupDescription=Inicio: +AutoStartProgram=Iniciar automticamente %1 +AddonHostProgramNotFound=%1 no pudo ser localizado en la carpeta seleccionada.%n%nDesea continuar de todas formas? diff --git a/installer/innosetup/Languages/Swedish.isl b/installer/innosetup/Languages/Swedish.isl index f89324798..f458ca651 100644 --- a/installer/innosetup/Languages/Swedish.isl +++ b/installer/innosetup/Languages/Swedish.isl @@ -1,4 +1,4 @@ -; *** Inno Setup version 6.0.0+ Swedish messages *** +; *** Inno Setup version 6.1.0+ Swedish messages *** ; ; To download user-contributed translations of this file, go to: ; http://www.jrsoftware.org/files/istrans/ @@ -151,6 +151,9 @@ IncorrectPassword=L ; *** "License Agreement" wizard page + + + WizardLicense=Licensavtal LicenseLabel=Var god och ls fljande viktiga information innan du fortstter. LicenseLabel3=Var god och ls fljande licensavtal. Du mste acceptera villkoren i avtalet innan du kan fortstta med installationen. @@ -160,6 +163,9 @@ LicenseNotAccepted=Jag accepterar &inte avtalet ; *** "Information" wizard pages + + + WizardInfoBefore=Information InfoBeforeLabel=Var god ls fljande viktiga information innan du fortstter. InfoBeforeClickLabel=Nr du r klar att fortstta med installationen klickar du p Nsta. @@ -170,6 +176,9 @@ InfoAfterClickLabel=N ; *** "User Information" wizard page + + + WizardUserInfo=Anvndarinformation UserInfoDesc=Var god och fyll i fljande uppgifter. UserInfoName=&Namn: @@ -180,10 +189,14 @@ UserInfoNameRequired=Du m ; *** "Select Destination Directory" wizard page + + + WizardSelectDir=Vlj installationsplats SelectDirDesc=Var skall [name] installeras? SelectDirLabel3=Installationsprogrammet kommer att installera [name] i fljande katalog SelectDirBrowseLabel=Fr att fortstta klickar du p Nsta. Om du vill vlja en annan katalog klickar du p Blddra. +DiskSpaceGBLabel=Programmet krver minst [gb] MB hrddiskutrymme. DiskSpaceMBLabel=Programmet krver minst [mb] MB hrddiskutrymme. CannotInstallToNetworkDrive=Setup kan inte installeras p ntverksdisk. CannotInstallToUNCPath=Setup kan inte installeras p UNC skvg. @@ -202,6 +215,9 @@ DirDoesntExist=Katalogen:%n%n%1%n%nfinns inte. Vill du skapa den? ; *** "Select Components" wizard page + + + WizardSelectComponents=Vlj komponenter SelectComponentsDesc=Vilka komponenter skall installeras? SelectComponentsLabel2=Vlj de komponenter som du vill ska installeras; avmarkera de komponenter som du inte vill ha. Klicka sedan p Nsta nr du r klar att fortstta. @@ -209,17 +225,24 @@ FullInstallation=Fullst ; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) + + + CompactInstallation=Kompakt installation CustomInstallation=Anpassad installation NoUninstallWarningTitle=Komponenter finns NoUninstallWarning=Installationsprogrammet har upptckt att fljande komponenter redan finns installerade p din dator:%n%n%1%n%nAtt avmarkera dessa komponenter kommer inte att avinstallera dom.%n%nVill du fortstta nd? ComponentSize1=%1 KB ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Aktuella val krver minst [gb] GB diskutrymme. ComponentsDiskSpaceMBLabel=Aktuella val krver minst [mb] MB diskutrymme. ; *** "Select Additional Tasks" wizard page + + + WizardSelectTasks=Vlj extra uppgifter SelectTasksDesc=Vilka extra uppgifter skall utfras? SelectTasksLabel2=Markera ytterligare uppgifter att utfra vid installation av [name], tryck sedan p Nsta. @@ -227,6 +250,9 @@ SelectTasksLabel2=Markera ytterligare uppgifter att utf ; *** "Select Start Menu Folder" wizard page + + + WizardSelectProgramGroup=Vlj Startmenykatalogen SelectStartMenuFolderDesc=Var skall installationsprogrammet placera programmets genvgar? SelectStartMenuFolderLabel3=Installationsprogrammet kommer att skapa programmets genvgar i fljande katalog. @@ -240,6 +266,9 @@ NoProgramGroupCheck2=&Skapa ingen Startmenykatalog ; *** "Ready to Install" wizard page + + + WizardReady=Redo att installera ReadyLabel1=Installationsprogrammet r nu redo att installera [name] p din dator. ReadyLabel2a=Tryck p Installera om du vill fortstta, eller p g Tillbaka om du vill granska eller ndra p ngot. @@ -250,10 +279,23 @@ ReadyMemoType=Installationstyp: ReadyMemoComponents=Valda komponenter: ReadyMemoGroup=Startmenykatalog: ReadyMemoTasks=Extra uppgifter: +DownloadingLabel=Laddar ner ytterligare filer... +ButtonStopDownload=&Stoppa nedladdning +StopDownload=r du sker p att du vill stoppa nedladdningen? +ErrorDownloadAborted=Nedladdningen avbruten +ErrorDownloadFailed=Nedladdningen misslyckades: %1 %2 +ErrorDownloadSizeFailed=F storlek misslyckades: %1 %2 +ErrorFileHash1=Filhash misslyckades: %1 +ErrorFileHash2=Ogiltig filhash: frvntat %1, hittat %2 +ErrorProgress=Ogiltig framfart: %1 of %2 +ErrorFileSize=Ogiltig filstorlek: frvntad %1, hittad %2 ; *** "Preparing to Install" wizard page + + + WizardPreparing=Frbereder installationen PreparingDesc=Installationsprogrammet frbereder installationen av [name] p din dator. PreviousInstallNotCompleted=Installationen/avinstallationen av ett tidigare program har inte slutfrts. Du mste starta om datorn fr att avsluta den installationen.%n%nEfter att ha startat om datorn kr du installationsprogrammet igen fr att slutfra installationen av [name]. @@ -263,16 +305,23 @@ ApplicationsFound2=F CloseApplications=&Stng programmen automatiskt DontCloseApplications=&Stng inte programmen ErrorCloseApplications=Installationsprogrammet kunde inte stnga alla program. Innan installationen fortstter rekommenderar vi att du stnger alla program som anvnder filer som Setup behver uppdatera. +PrepareToInstallNeedsRestart=Installationen mste starta om din dator. Nr du har startat om datorn kr du Setup igen fr att slutfra installationen av [name].%n%nVill du starta om nu? ; *** "Installing" wizard page + + + WizardInstalling=Installerar InstallingLabel=Vnta medan [name] installeras p din dator. ; *** "Setup Completed" wizard page + + + FinishedHeadingLabel=Avslutar installationen av [name] FinishedLabelNoIcons=[name] har nu installerats p din dator. FinishedLabel=[name] har nu installerats p din dator. Programmet kan startas genom att vlja ngon av ikonerna. @@ -285,15 +334,24 @@ NoRadio=&Nej, jag startar sj ; used for example as 'Run MyProg.exe' + + + RunEntryExec=Kr %1 ; used for example as 'View Readme.txt' + + + RunEntryShellExec=Ls %1 ; *** "Setup Needs the Next Disk" stuff + + + ChangeDiskTitle=Installationsprogrammet behver nsta diskett SelectDiskLabel2=Var god stt i diskett %1 och tryck OK.%n%nOm filerna kan hittas i en annan katalog n den som visas nedan, skriv in rtt skvg eller vlj Blddra. PathLabel=&Skvg: @@ -303,6 +361,9 @@ SelectDirectoryLabel=Var god ange s ; *** Installation phase messages + + + SetupAborted=Installationen slutfrdes inte.%n%nVar god rtta till felet och kr installationen igen. AbortRetryIgnoreSelectAction=Vlj tgrd AbortRetryIgnoreRetry=&Frsk igen @@ -312,6 +373,9 @@ AbortRetryIgnoreCancel=Avbryt installationen ; *** Installation status messages + + + StatusClosingApplications=Stnger program... StatusCreateDirs=Skapar kataloger... StatusExtractFiles=Packar upp filer... @@ -327,6 +391,9 @@ StatusRollback= ; *** Misc. errors + + + ErrorInternal2=Internt fel: %1 ErrorFunctionFailedNoCode=%1 misslyckades ErrorFunctionFailed=%1 misslyckades; kod %2 @@ -336,6 +403,9 @@ ErrorExecutingProgram=Kan inte k ; *** Registry errors + + + ErrorRegOpenKey=Fel vid ppning av registernyckel:%n%1\%2 ErrorRegCreateKey=Kan ej skapa registernyckel:%n%1\%2 ErrorRegWriteKey=Kan ej skriva till registernyckel:%n%1\%2 @@ -343,6 +413,9 @@ ErrorRegWriteKey=Kan ej skriva till registernyckel:%n%1\%2 ; *** INI errors + + + ErrorIniEntry=Kan inte skriva nytt INI-vrde i filen "%1". FileAbortRetryIgnoreSkipNotRecommended=&Hoppa ver den hr filen (rekommenderas inte) FileAbortRetryIgnoreIgnoreNotRecommended=&Ignorera felet och fortstt (rekommenderas inte) @@ -352,8 +425,16 @@ ExistingFileReadOnly2=Den befintliga filen kunde inte bytas ut eftersom den ExistingFileReadOnlyRetry=&Ta bort skrivskyddad attributet och frsk igen ExistingFileReadOnlyKeepExisting=&Behll den befintliga filen ErrorReadingExistingDest=Ett fel uppstod vid frsk att lsa den befintliga filen: -FileExists=Filen finns redan.%n%nVill du skriva ver den? -ExistingFileNewer=Den befintliga filen r nyare n den som ska installeras. Du rekommenderas att behlla den befintliga filen. %n%nVill Du behlla den befintliga filen? +FileExistsSelectAction=Vlj tgrd +FileExists2=Filen finns redan. +FileExistsOverwriteExisting=&Skriv ver den befintliga filen +FileExistsKeepExisting=&Behll befintlig fil +FileExistsOverwriteOrKeepAll=&Gr detta fr nsta konflikt +ExistingFileNewerSelectAction=Vlj tgrd +ExistingFileNewer2=Den befintliga filen r nyare n den som Setup frsker installera. +ExistingFileNewerOverwriteExisting=&Skriv ver den befintliga filen +ExistingFileNewerKeepExisting=&Behll befintlig fil (rekommenderas) +ExistingFileNewerOverwriteOrKeepAll=&Gr detta fr nsta konflikt ErrorChangingAttr=Ett fel uppstod vid frsk att ndra attribut p den befintliga filen: ErrorCreatingTemp=Ett fel uppstod vid ett frsk att skapa installationskatalogen: ErrorReadingSource=Ett fel uppstod vid ett frsk att lsa kllfilen: @@ -374,12 +455,18 @@ UninstallDisplayNameMarkCurrentUser=Nuvarande anv ; *** Post-installation errors + + + ErrorOpeningReadme=Ett fel uppstod vid ppnandet av LS MIG-filen. ErrorRestartingComputer=Installationsprogrammet kunde inte starta om datorn. Var god gr det manuellt. ; *** Uninstaller messages + + + UninstallNotFound=Filen "%1" finns inte. Kan inte avinstallera. UninstallOpenError=Filen "%1" kan inte ppnas. Kan inte avinstallera. UninstallUnsupportedVer=Avinstallationsloggen "%1" r i ett format som denna version inte knner igen. Kan ej avinstallera @@ -396,6 +483,9 @@ UninstallDataCorrupted=Filen "%1" ; *** Uninstallation phase messages + + + ConfirmDeleteSharedFileTitle=Ta bort delad fil? ConfirmDeleteSharedFile2=Systemet indikerar att fljande delade fil inte lngre anvnds av ngra program. Vill du ta bort den delade filen?%n%n%1%n%nOm ngot program fortfarande anvnder denna fil och den raderas, kommer programmet kanske att sluta fungera. Om du r osker, vlj Nej. Att lta filen ligga kvar i systemet kommer inte att orsaka ngon skada. SharedFileNameLabel=Filnamn: @@ -406,6 +496,9 @@ StatusUninstalling=Avinstallerar %1... ; *** Shutdown block reasons + + + ShutdownBlockReasonInstallingApp=Installerar %1. ShutdownBlockReasonUninstallingApp=Avinstallerar %1. @@ -415,11 +508,14 @@ ShutdownBlockReasonUninstallingApp=Avinstallerar %1. + + + [CustomMessages] NameAndVersion=%1 version %2 AdditionalIcons=terstende ikoner: -CreateDesktopIcon=Skapa en ikon p skrivbordet -CreateQuickLaunchIcon=Skapa en ikon i Snabbstartfltet +CreateDesktopIcon=Skapa en genvg p skrivbordet +CreateQuickLaunchIcon=Skapa en genvg i Snabbstartfltet ProgramOnTheWeb=%1 p Webben UninstallProgram=Avinstallera %1 LaunchProgram=Starta %1 diff --git a/installer/innosetup/Languages/Turkish.isl b/installer/innosetup/Languages/Turkish.isl new file mode 100644 index 000000000..932c705bd --- /dev/null +++ b/installer/innosetup/Languages/Turkish.isl @@ -0,0 +1,384 @@ +; *** Inno Setup version 6.1.0+ Turkish messages *** +; Language "Turkce" Turkish Translate by "Ceviren" Kaya Zeren translator@zeron.net +; To download user-contributed translations of this file, go to: +; https://www.jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=T<00FC>rk<00E7>e +LanguageID=$041f +LanguageCodePage=1254 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** Uygulama balklar +SetupAppTitle=Kurulum Yardmcs +SetupWindowTitle=%1 - Kurulum Yardmcs +UninstallAppTitle=Kaldrma Yardmcs +UninstallAppFullTitle=%1 Kaldrma Yardmcs + +; *** eitli ortak metinler +InformationTitle=Bilgi +ConfirmTitle=Onay +ErrorTitle=Hata + +; *** Kurulum ykleyici iletileri +SetupLdrStartupMessage=%1 uygulamas kurulacak. Devam etmek istiyor musunuz? +LdrCannotCreateTemp=Geici dosya oluturulamadndan kurulum iptal edildi +LdrCannotExecTemp=Geici klasrdeki dosya altrlamadndan kurulum iptal edildi +HelpTextNote= + +; *** Balang hata iletileri +LastErrorMessage=%1.%n%nHata %2: %3 +SetupFileMissing=Kurulum klasrnde %1 dosyas eksik. Ltfen sorunu zn ya da uygulamann yeni bir kopyasyla yeniden deneyin. +SetupFileCorrupt=Kurulum dosyalar bozulmu. Ltfen uygulamann yeni bir kopyasyla yeniden kurmay deneyin. +SetupFileCorruptOrWrongVer=Kurulum dosyalar bozulmu ya da bu kurulum yardmcs srm ile uyumlu deil. Ltfen sorunu zn ya da uygulamann yeni bir kopyasyla yeniden kurmay deneyin. +InvalidParameter=Komut satrnda geersiz bir parametre yazlm:%n%n%1 +SetupAlreadyRunning=Kurulum yardmcs zaten alyor. +WindowsVersionNotSupported=Bu uygulama, bilgisayarnzda ykl olan Windows srm ile uyumlu deil. +WindowsServicePackRequired=Bu uygulama, %1 Hizmet Paketi %2 ve zerindeki srmler ile alr. +NotOnThisPlatform=Bu uygulama, %1 zerinde almaz. +OnlyOnThisPlatform=Bu uygulama, %1 zerinde altrlmaldr. +OnlyOnTheseArchitectures=Bu uygulama, yalnz u ilemci mimarileri iin tasarlanm Windows srmleriyle alr:%n%n%1 +WinVersionTooLowError=Bu uygulama iin %1 srm %2 ya da zeri gereklidir. +WinVersionTooHighError=Bu uygulama, '%1' srm '%2' ya da zerine kurulamaz. +AdminPrivilegesRequired=Bu uygulamay kurmak iin Ynetici olarak oturum alm olmas gereklidir. +PowerUserPrivilegesRequired=Bu uygulamay kurarken, Ynetici ya da Gl Kullanclar grubunun bir yesi olarak oturum alm olmas gereklidir. +SetupAppRunningError=Kurulum yardmcs %1 uygulamasnn almakta olduunu alglad.%n%nLtfen uygulamann alan tm kopyalarn kapatp, devam etmek iin Tamam, kurulum yardmcsndan kmak iin ptal zerine tklayn. +UninstallAppRunningError=Kaldrma yardmcs, %1 uygulamasnn almakta olduunu alglad.%n%nLtfen uygulamann alan tm kopyalarn kapatp, devam etmek iin Tamam ya da kaldrma yardmcsndan kmak iin ptal zerine tklayn. + +; *** Balang sorular +PrivilegesRequiredOverrideTitle=Kurulum Kipini Sein +PrivilegesRequiredOverrideInstruction=Kurulum kipini sein +PrivilegesRequiredOverrideText1=%1 tm kullanclar iin (ynetici izinleri gerekir) ya da yalnz sizin hesabnz iin kurulabilir. +PrivilegesRequiredOverrideText2=%1 yalnz sizin hesabnz iin ya da tm kullanclar iin (ynetici izinleri gerekir) kurulabilir. +PrivilegesRequiredOverrideAllUsers=&Tm kullanclar iin kurulsun +PrivilegesRequiredOverrideAllUsersRecommended=&Tm kullanclar iin kurulsun (nerilir) +PrivilegesRequiredOverrideCurrentUser=&Yalnz benim kullancm iin kurulsun +PrivilegesRequiredOverrideCurrentUserRecommended=&Yalnz benim kullancm iin kurulsun (nerilir) + +; *** eitli hata metinleri +ErrorCreatingDir=Kurulum yardmcs "%1" klasrn oluturamad. +ErrorTooManyFilesInDir="%1" klasr iinde ok sayda dosya olduundan bir dosya oluturulamad + +; *** Ortak kurulum iletileri +ExitSetupTitle=Kurulum Yardmcsndan k +ExitSetupMessage=Kurulum tamamlanmad. imdi karsanz, uygulama kurulmayacak.%n%nKurulumu tamamlamak iin istediiniz zaman kurulum yardmcsn yeniden altrabilirsiniz.%n%nKurulum yardmcsndan klsn m? +AboutSetupMenuItem=Kurulum H&akknda... +AboutSetupTitle=Kurulum Hakknda +AboutSetupMessage=%1 %2 srm%n%3%n%n%1 ana sayfa:%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Dmeler +ButtonBack=< &nceki +ButtonNext=&Sonraki > +ButtonInstall=&Kur +ButtonOK=Tamam +ButtonCancel=ptal +ButtonYes=E&vet +ButtonYesToAll=&Tmne Evet +ButtonNo=&Hayr +ButtonNoToAll=Tmne Ha&yr +ButtonFinish=&Bitti +ButtonBrowse=&Gzat... +ButtonWizardBrowse=Gza&t... +ButtonNewFolder=Ye&ni Klasr Olutur + +; *** "Kurulum Dilini Sein" sayfas iletileri +SelectLanguageTitle=Kurulum Yardmcs Dilini Sein +SelectLanguageLabel=Kurulum sresince kullanlacak dili sein. + +; *** Ortak metinler +ClickNext=Devam etmek iin Sonraki, kmak iin ptal zerine tklayn. +BeveledLabel= +BrowseDialogTitle=Klasre Gzat +BrowseDialogLabel=Aadaki listeden bir klasr seip, Tamam zerine tklayn. +NewFolderName=Yeni Klasr + +; *** "Ho geldiniz" sayfas +WelcomeLabel1=[name] Kurulum Yardmcsna Hogeldiniz. +WelcomeLabel2=Bilgisayarnza [name/ver] uygulamas kurulacak.%n%nDevam etmeden nce alan dier tm uygulamalar kapatmanz nerilir. + +; *** "Parola" sayfas +WizardPassword=Parola +PasswordLabel1=Bu kurulum parola korumaldr. +PasswordLabel3=Ltfen parolay yazn ve devam etmek iin Sonraki zerine tklayn. Parolalar byk kk harflere duyarldr. +PasswordEditLabel=&Parola: +IncorrectPassword=Yazdnz parola doru deil. Ltfen yeniden deneyin. + +; *** "Lisans Anlamas" sayfas +WizardLicense=Lisans Anlamas +LicenseLabel=Ltfen devam etmeden nce aadaki nemli bilgileri okuyun. +LicenseLabel3=Ltfen Aadaki Lisans Anlamasn okuyun. Kuruluma devam edebilmek iin bu anlamay kabul etmelisiniz. +LicenseAccepted=Anlamay kabul &ediyorum. +LicenseNotAccepted=Anlamay kabul et&miyorum. + +; *** "Bilgiler" sayfas +WizardInfoBefore=Bilgiler +InfoBeforeLabel=Ltfen devam etmeden nce aadaki nemli bilgileri okuyun. +InfoBeforeClickLabel=Kuruluma devam etmeye hazr olduunuzda Sonraki zerine tklayn. +WizardInfoAfter=Bilgiler +InfoAfterLabel=Ltfen devam etmeden nce aadaki nemli bilgileri okuyun. +InfoAfterClickLabel=Kuruluma devam etmeye hazr olduunuzda Sonraki zerine tklayn. + +; *** "Kullanc Bilgileri" sayfas +WizardUserInfo=Kullanc Bilgileri +UserInfoDesc=Ltfen bilgilerinizi yazn. +UserInfoName=K&ullanc Ad: +UserInfoOrg=Ku&rum: +UserInfoSerial=&Seri Numaras: +UserInfoNameRequired=Bir ad yazmalsnz. + +; *** "Hedef Konumunu Sein" sayfas +WizardSelectDir=Hedef Konumunu Sein +SelectDirDesc=[name] nereye kurulsun? +SelectDirLabel3=[name] uygulamas u klasre kurulacak. +SelectDirBrowseLabel=Devam etmek icin Sonraki zerine tklayn. Farkl bir klasr semek iin Gzat zerine tklayn. +DiskSpaceGBLabel=En az [gb] GB bo disk alan gereklidir. +DiskSpaceMBLabel=En az [mb] MB bo disk alan gereklidir. +CannotInstallToNetworkDrive=Uygulama bir a srcs zerine kurulamaz. +CannotInstallToUNCPath=Uygulama bir UNC yolu zerine (\\yol gibi) kurulamaz. +InvalidPath=Src ad ile tam yolu yazmalsnz; rnein: %n%nC:\APP%n%n ya da u ekilde bir UNC yolu:%n%n\\sunucu\paylam +InvalidDrive=Src ya da UNC paylam yok ya da eriilemiyor. Ltfen baka bir tane sein. +DiskSpaceWarningTitle=Yeterli Bo Disk Alan Yok +DiskSpaceWarning=Kurulum iin %1 KB bo alan gerekli, ancak seilmi srcde yalnz %2 KB bo alan var.%n%nGene de devam etmek istiyor musunuz? +DirNameTooLong=Klasr ad ya da yol ok uzun. +InvalidDirName=Klasr ad geersiz. +BadDirName32=Klasr adlarnda u karakterler bulunamaz:%n%n%1 +DirExistsTitle=Klasr Zaten Var" +DirExists=Klasr:%n%n%1%n%zaten var. Kurulum iin bu klasr kullanmak ister misiniz? +DirDoesntExistTitle=Klasr Bulunamad +DirDoesntExist=Klasr:%n%n%1%n%nbulunamad.Klasrn oluturmasn ister misiniz? + +; *** "Bileenleri Sein" sayfas +WizardSelectComponents=Bileenleri Sein +SelectComponentsDesc=Hangi bileenler kurulacak? +SelectComponentsLabel2=Kurmak istediiniz bileenleri sein; kurmak istemediiniz bileenlerin iaretini kaldrn. Devam etmeye hazr olduunuzda Sonraki zerine tklayn. +FullInstallation=Tam Kurulum +; Mmknse 'Compact' ifadesini kendi dilinizde 'Minimal' anlamnda evirmeyin +CompactInstallation=Normal kurulum +CustomInstallation=zel kurulum +NoUninstallWarningTitle=Bileenler Zaten Var +NoUninstallWarning=u bileenlerin bilgisayarnzda zaten kurulu olduu algland:%n%n%1%n%n Bu bileenlerin iaretlerinin kaldrlmas bileenleri kaldrmaz.%n%nGene de devam etmek istiyor musunuz? +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=Seili bileenler iin diskte en az [gb] GB bo alan bulunmas gerekli. +ComponentsDiskSpaceMBLabel=Seili bileenler iin diskte en az [mb] MB bo alan bulunmas gerekli. + +; *** "Ek lemleri Sein" sayfas +WizardSelectTasks=Ek lemleri Sein +SelectTasksDesc=Baka hangi ilemler yaplsn? +SelectTasksLabel2=[name] kurulumu srasnda yaplmasn istediiniz ek ileri sein ve Sonraki zerine tklayn. + +; *** "Balat Mens Klasrn Sein" sayfas +WizardSelectProgramGroup=Balat Mens Klasrn Sein +SelectStartMenuFolderDesc=Uygulamann ksayollar nereye eklensin? +SelectStartMenuFolderLabel3=Kurulum yardmcs uygulama ksayollarn aadaki Balat Mens klasrne ekleyecek. +SelectStartMenuFolderBrowseLabel=Devam etmek iin Sonraki zerine tklayn. Farkl bir klasr semek iin Gzat zerine tklayn. +MustEnterGroupName=Bir klasr ad yazmalsnz. +GroupNameTooLong=Klasr ad ya da yol ok uzun. +InvalidGroupName=Klasr ad geersiz. +BadGroupName=Klasr adnda u karakterler bulunamaz:%n%n%1 +NoProgramGroupCheck2=Balat Mens klasr &oluturulmasn + +; *** "Kurulmaya Hazr" sayfas +WizardReady=Kurulmaya Hazr +ReadyLabel1=[name] bilgisayarnza kurulmaya hazr. +ReadyLabel2a=Kuruluma devam etmek iin Sonraki zerine, ayarlar gzden geirip deitirmek iin nceki zerine tklayn. +ReadyLabel2b=Kuruluma devam etmek iin Sonraki zerine tklayn. +ReadyMemoUserInfo=Kullanc bilgileri: +ReadyMemoDir=Hedef konumu: +ReadyMemoType=Kurulum tr: +ReadyMemoComponents=Seilmi bileenler: +ReadyMemoGroup=Balat Mens klasr: +ReadyMemoTasks=Ek ilemler: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=Ek dosyalar indiriliyor... +ButtonStopDownload=ndirmeyi &durdur +StopDownload=ndirmeyi durdurmak istediinize emin misiniz? +ErrorDownloadAborted=ndirme durduruldu +ErrorDownloadFailed=ndirilemedi: %1 %2 +ErrorDownloadSizeFailed=Boyut alnamad: %1 %2 +ErrorFileHash1=Dosya karmas dorulanamad: %1 +ErrorFileHash2=Dosya karmas geersiz: %1 olmas gerekirken %2 +ErrorProgress=Adm geersiz: %1 / %2 +ErrorFileSize=Dosya boyutu geersiz: %1 olmas gerekirken %2 + +; *** "Kuruluma Hazrlanlyor" sayfas +WizardPreparing=Kuruluma Hazrlanlyor +PreparingDesc=[name] bilgisayarnza kurulmaya hazrlanyor. +PreviousInstallNotCompleted=nceki uygulama kurulumu ya da kaldrlmas tamamlanmam. Bu kurulumun tamamlanmas iin bilgisayarnz yeniden balatmalsnz.%n%nBilgisayarnz yeniden balattktan sonra ilemi tamamlamak iin [name] kurulum yardmcsn yeniden altrn. +CannotContinue=Kuruluma devam edilemiyor. kmak iin ptal zerine tklayn. +ApplicationsFound=Kurulum yardmcs tarafndan gncellenmesi gereken dosyalar, u uygulamalar tarafndan kullanyor. Kurulum yardmcsnn bu uygulamalar otomatik olarak kapatmasna izin vermeniz nerilir. +ApplicationsFound2=Kurulum yardmcs tarafndan gncellenmesi gereken dosyalar, u uygulamalar tarafndan kullanyor. Kurulum yardmcsnn bu uygulamalar otomatik olarak kapatmasna izin vermeniz nerilir. Kurulum tamamlandktan sonra, uygulamalar yeniden balatlmaya allacak. +CloseApplications=&Uygulamalar kapatlsn +DontCloseApplications=Uygulamalar &kapatlmasn +ErrorCloseApplications=Kurulum yardmcs uygulamalar kapatamad. Kurulum yardmcs tarafndan gncellenmesi gereken dosyalar kullanan uygulamalar el ile kapatmanz nerilir. +PrepareToInstallNeedsRestart=Kurulum iin bilgisayarn yeniden balatlmas gerekiyor. Bilgisayar yeniden balattktan sonra [name] kurulumunu tamamlamak iin kurulum yardmcsn yeniden altrn.%n%nBilgisayar imdi yeniden balatmak ister misiniz? + +; *** "Kuruluyor" sayfas +WizardInstalling=Kuruluyor +InstallingLabel=Ltfen [name] bilgisayarnza kurulurken bekleyin. + +; *** "Kurulum Tamamland" sayfas +FinishedHeadingLabel=[name] kurulum yardmcs tamamlanyor +FinishedLabelNoIcons=Bilgisayarnza [name] kurulumu tamamland. +FinishedLabel=Bilgisayarnza [name] kurulumu tamamland. Simgeleri yklemeyi setiyseniz, simgelere tklayarak uygulamay balatabilirsiniz. +ClickFinish=Kurulum yardmcsndan kmak iin Bitti zerine tklayn. +FinishedRestartLabel=[name] kurulumunun tamamlanmas iin, bilgisayarnz yeniden balatlmal. imdi yeniden balatmak ister misiniz? +FinishedRestartMessage=[name] kurulumunun tamamlanmas iin, bilgisayarnz yeniden balatlmal.%n%nimdi yeniden balatmak ister misiniz? +ShowReadmeCheck=Evet README dosyas grntlensin +YesRadio=&Evet, bilgisayar imdi yeniden balatlsn +NoRadio=&Hayr, bilgisayar daha sonra yeniden balatacam +; used for example as 'Run MyProg.exe' +RunEntryExec=%1 altrlsn +; used for example as 'View Readme.txt' +RunEntryShellExec=%1 grntlensin + +; *** "Kurulum iin Sradaki Disk Gerekli" iletileri +ChangeDiskTitle=Kurulum Yardmcs Sradaki Diske Gerek Duyuyor +SelectDiskLabel2=Ltfen %1 numaral diski takp Tamam zerine tklayn.%n%nDiskteki dosyalar aadakinden farkl bir klasrde bulunuyorsa, doru yolu yazn ya da Gzat zerine tklayarak doru klasr sein. +PathLabel=&Yol: +FileNotInDir2="%1" dosyas "%2" iinde bulunamad. Ltfen doru diski takn ya da baka bir klasr sein. +SelectDirectoryLabel=Ltfen sonraki diskin konumunu belirtin. + +; *** Kurulum aamas iletileri +SetupAborted=Kurulum tamamlanamad.%n%nLtfen sorunu dzelterek kurulum yardmcsn yeniden altrn. +AbortRetryIgnoreSelectAction=Yaplacak ilemi sein +AbortRetryIgnoreRetry=&Yeniden denensin +AbortRetryIgnoreIgnore=&Sorun yok saylp devam edilsin +AbortRetryIgnoreCancel=Kurulum iptal edilsin + +; *** Kurulum durumu iletileri +StatusClosingApplications=Uygulamalar kapatlyor... +StatusCreateDirs=Klasrler oluturuluyor... +StatusExtractFiles=Dosyalar ayklanyor... +StatusCreateIcons=Ksayollar oluturuluyor... +StatusCreateIniEntries=INI kaytlar oluturuluyor... +StatusCreateRegistryEntries=Kayt Defteri kaytlar oluturuluyor... +StatusRegisterFiles=Dosyalar kaydediliyor... +StatusSavingUninstall=Kaldrma bilgileri kaydediliyor... +StatusRunProgram=Kurulum tamamlanyor... +StatusRestartingApplications=Uygulamalar yeniden balatlyor... +StatusRollback=Deiiklikler geri alnyor... + +; *** eitli hata iletileri +ErrorInternal2= hata: %1 +ErrorFunctionFailedNoCode=%1 tamamlanamad. +ErrorFunctionFailed=%1 tamamlanamad; kod %2 +ErrorFunctionFailedWithMessage=%1 tamamlanamad; kod %2.%n%3 +ErrorExecutingProgram=u dosya yrtlemedi:%n%1 + +; *** Kayt defteri hatalar +ErrorRegOpenKey=Kayt defteri anahtar alrken bir sorun kt:%n%1%2 +ErrorRegCreateKey=Kayt defteri anahtar eklenirken bir sorun kt:%n%1%2 +ErrorRegWriteKey=Kayt defteri anahtar yazlrken bir sorun kt:%n%1%2 + +; *** INI hatalar +ErrorIniEntry="%1" dosyasna INI kayd eklenirken bir sorun kt. + +; *** Dosya kopyalama hatalar +FileAbortRetryIgnoreSkipNotRecommended=&Bu dosya atlansn (nerilmez) +FileAbortRetryIgnoreIgnoreNotRecommended=&Sorun yok saylp devam edilsin (nerilmez) +SourceIsCorrupted=Kaynak dosya bozulmu +SourceDoesntExist="%1" kaynak dosyas bulunamad +ExistingFileReadOnly2=Var olan dosya salt okunabilir olarak iaretlenmi olduundan zerine yazlamad. +ExistingFileReadOnlyRetry=&Salt okunur iareti kaldrlp yeniden denensin +ExistingFileReadOnlyKeepExisting=&Var olan dosya korunsun +ErrorReadingExistingDest=Var olan dosya okunmaya allrken bir sorun kt. +FileExistsSelectAction=Yaplacak ilemi sein +FileExists2=Dosya zaten var. +FileExistsOverwriteExisting=&Var olan dosyann zerine yazlsn +FileExistsKeepExisting=Var &olan dosya korunsun +FileExistsOverwriteOrKeepAll=&Sonraki akmalarda da bu ilem yaplsn +ExistingFileNewerSelectAction=Yaplacak ilemi sein +ExistingFileNewer2=Var olan dosya, kurulum yardmcs tarafndan yazlmaya allandan daha yeni. +ExistingFileNewerOverwriteExisting=&Var olan dosyann zerine yazlsn +ExistingFileNewerKeepExisting=Var &olan dosya korunsun (nerilir) +ExistingFileNewerOverwriteOrKeepAll=&Sonraki akmalarda bu ilem yaplsn +ErrorChangingAttr=Var olan dosyann znitelikleri deitirilirken bir sorun kt: +ErrorCreatingTemp=Hedef klasrde bir dosya oluturulurken bir sorun kt: +ErrorReadingSource=Kaynak dosya okunurken bir sorun kt: +ErrorCopying=Dosya kopyalanrken bir sorun kt: +ErrorReplacingExistingFile=Var olan dosya deitirilirken bir sorun kt: +ErrorRestartReplace=Yeniden balatmada zerine yazlamad: +ErrorRenamingTemp=Hedef klasrdeki bir dosyann ad deitirilirken sorun kt: +ErrorRegisterServer=DLL/OCX kayt edilemedi: %1 +ErrorRegSvr32Failed=RegSvr32 ilemi u kod ile tamamlanamad: %1 +ErrorRegisterTypeLib=Tr kitapl kayt defterine eklenemedi: %1 + +; *** Kaldrma srasnda grntlenecek ad iaretleri +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32 bit +UninstallDisplayNameMark64Bit=64 bit +UninstallDisplayNameMarkAllUsers=Tm kullanclar +UninstallDisplayNameMarkCurrentUser=Geerli kullanc + +; *** Kurulum sonras hatalar +ErrorOpeningReadme=README dosyas alrken bir sorun kt. +ErrorRestartingComputer=Kurulum yardmcs bilgisayarnz yeniden balatamyor. Ltfen bilgisayarnz yeniden balatn. + +; *** Kaldrma yardmcs iletileri +UninstallNotFound="%1" dosyas bulunamad. Uygulama kaldrlamyor. +UninstallOpenError="%1" dosyas alamad. Uygulama kaldrlamyor. +UninstallUnsupportedVer="%1" uygulama kaldrma gnlk dosyasnn biimi, bu kaldrma yardmcs srm tarafndan anlalamad. Uygulama kaldrlamyor. +UninstallUnknownEntry=Kaldrma gnlnde bilinmeyen bir kayt (%1) bulundu. +ConfirmUninstall=%1 uygulamasn tm bileenleri ile birlikte tamamen kaldrmak istediinize emin misiniz? +UninstallOnlyOnWin64=Bu kurulum yalnz 64 bit Windows zerinden kaldrlabilir. +OnlyAdminCanUninstall=Bu kurulum yalnz ynetici haklarna sahip bir kullanc tarafndan kaldrlabilir. +UninstallStatusLabel=Ltfen %1 uygulamas bilgisayarnzdan kaldrlrken bekleyin. +UninstalledAll=%1 uygulamas bilgisayarnzdan kaldrld. +UninstalledMost=%1 uygulamas kaldrld.%n%nBaz bileenler kaldrlamad. Bunlar el ile silebilirsiniz. +UninstalledAndNeedsRestart=%1 kaldrma ileminin tamamlanmas iin bilgisayarnzn yeniden balatlmas gerekli.%n%nimdi yeniden balatmak ister misiniz? +UninstallDataCorrupted="%1" dosyas bozulmu. Kaldrlamyor. + +; *** Kaldrma aamas iletileri +ConfirmDeleteSharedFileTitle=Paylalan Dosya Silinsin mi? +ConfirmDeleteSharedFile2=Sisteme gre, paylalan u dosya baka bir uygulama tarafndan kullanlmyor ve kaldrlabilir. Bu paylalm dosyay silmek ister misiniz?%n%nBu dosya, baka herhangi bir uygulama tarafndan kullanlyor ise, silindiinde dier uygulama dzgn almayabilir. Emin deilseniz Hayr zerine tklayn. Dosyay sisteminizde brakmann bir zarar olmaz. +SharedFileNameLabel=Dosya ad: +SharedFileLocationLabel=Konum: +WizardUninstalling=Kaldrma Durumu +StatusUninstalling=%1 kaldrlyor... + +; *** Kapatmay engelleme nedenleri +ShutdownBlockReasonInstallingApp=%1 kuruluyor. +ShutdownBlockReasonUninstallingApp=%1 kaldrlyor. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 %2 srm +AdditionalIcons=Ek simgeler: +CreateDesktopIcon=Masast simg&esi oluturulsun +CreateQuickLaunchIcon=Hzl Balat simgesi &oluturulsun +ProgramOnTheWeb=%1 Web Sitesi +UninstallProgram=%1 Uygulamasn Kaldr +LaunchProgram=%1 Uygulamasn altr +AssocFileExtension=%1 &uygulamas ile %2 dosya uzants ilikilendirilsin +AssocingFileExtension=%1 uygulamas ile %2 dosya uzants ilikilendiriliyor... +AutoStartProgramGroupDescription=Balang: +AutoStartProgram=%1 otomatik olarak balatlsn +AddonHostProgramNotFound=%1 setiiniz klasrde bulunamad.%n%nYine de devam etmek istiyor musunuz? \ No newline at end of file diff --git a/installer/innosetup/Languages/Ukrainian.isl b/installer/innosetup/Languages/Ukrainian.isl new file mode 100644 index 000000000..c12c6ebf3 --- /dev/null +++ b/installer/innosetup/Languages/Ukrainian.isl @@ -0,0 +1,385 @@ +; *** Inno Setup version 6.1.0+ Ukrainian messages *** +; Author: Dmytro Onyshchuk +; E-Mail: mrlols3@gmail.com +; Please report all spelling/grammar errors, and observations. +; Version 2020.08.04 + +; *** Inno Setup 6.1.0 *** +; : +; E-Mail: mrlols3@gmail.com +; , . +; 2020.08.04 + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=<0423><043A><0440><0430><0457><043D><0441><044C><043A><0430> +LanguageID=$0422 +LanguageCodePage=1251 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 + +[Messages] + +; *** +SetupAppTitle= +SetupWindowTitle= %1 +UninstallAppTitle= +UninstallAppFullTitle= %1 + +; *** Misc. common +InformationTitle= +ConfirmTitle=ϳ +ErrorTitle= + +; *** SetupLdr messages +SetupLdrStartupMessage= %1 ', ? +LdrCannotCreateTemp= . +LdrCannotExecTemp= . +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%n %2: %3 +SetupFileMissing= %1 . , . +SetupFileCorrupt= . , . +SetupFileCorruptOrWrongVer= . , . +InvalidParameter= :%n%n%1 +SetupAlreadyRunning= . +WindowsVersionNotSupported= Windows, '. +WindowsServicePackRequired= %1 Service Pack %2 . +NotOnThisPlatform= %1. +OnlyOnThisPlatform= %1. +OnlyOnTheseArchitectures= ' Windows :%n%n%1 +WinVersionTooLowError= %1 %2 . +WinVersionTooHighError= %1 %2 . +AdminPrivilegesRequired= . +PowerUserPrivilegesRequired= . +SetupAppRunningError=, %1 .%n%n , ﳿ OK , . +UninstallAppRunningError=, %1 .%n%n , ﳿ OK , . + +; *** Startup questions +PrivilegesRequiredOverrideTitle= +PrivilegesRequiredOverrideInstruction= +PrivilegesRequiredOverrideText1=%1 ( ), . +PrivilegesRequiredOverrideText2=%1 , ( ). +PrivilegesRequiredOverrideAllUsers= & +PrivilegesRequiredOverrideAllUsersRecommended= & () +PrivilegesRequiredOverrideCurrentUser= +PrivilegesRequiredOverrideCurrentUserRecommended= & () + +; *** г +ErrorCreatingDir= "%1" +ErrorTooManyFilesInDir= "%1", + +; *** +ExitSetupTitle= +ExitSetupMessage= . , .%n%n .%n%n ? +AboutSetupMenuItem=& ... +AboutSetupTitle= +AboutSetupMessage=%1 %2%n%3%n%n%1 :%n%4 +AboutSetupNote= +TranslatorNote=Ukrainian translation by Dmytro Onyshchuk + +; *** +ButtonBack=< & +ButtonNext=& > +ButtonInstall=& +ButtonOK=OK +ButtonCancel= +ButtonYes=& +ButtonYesToAll= & +ButtonNo=&ͳ +ButtonNoToAll=& +ButtonFinish=& +ButtonBrowse=&... +ButtonWizardBrowse=&... +ButtonNewFolder=& + +; *** ij " " +SelectLanguageTitle= +SelectLanguageLabel= , . + +; *** +ClickNext= 볻, , . +BeveledLabel= +BrowseDialogTitle= +BrowseDialogLabel= ʻ. +NewFolderName= + +; *** "" +WelcomeLabel1= [name]. +WelcomeLabel2= [name/ver] .%n%n . + +; *** "" +WizardPassword= +PasswordLabel1= . +PasswordLabel3= , 볻, . . +PasswordEditLabel=&: +IncorrectPassword= . , . + +; *** "˳ " +WizardLicense=˳ +LicenseLabel= , . +LicenseLabel3= , . , . +LicenseAccepted= & +LicenseNotAccepted= & + +; *** "" +WizardInfoBefore= +InfoBeforeLabel= , , . +InfoBeforeClickLabel= , 볻. +WizardInfoAfter= +InfoAfterLabel= , , . +InfoAfterClickLabel= , 볻. + +; *** " " +WizardUserInfo= +UserInfoDesc= , . +UserInfoName=& : +UserInfoOrg=&: +UserInfoSerial=& : +UserInfoNameRequired= '. + +; *** " " +WizardSelectDir= +SelectDirDesc= [name]? +SelectDirLabel3= [name] . +SelectDirBrowseLabel= 볻, . , . +DiskSpaceGBLabel= [gb] . +DiskSpaceMBLabel= [mb] M . +CannotInstallToNetworkDrive= . +CannotInstallToUNCPath= . +InvalidPath= , :%n%nC:\APP%n%n UNC:%n%n\\\ +InvalidDrive= , . , . +DiskSpaceWarningTitle= +DiskSpaceWarning= %1 , %2 .%n%n ? +DirNameTooLong=' . +InvalidDirName= . +BadDirName32=' :%n%n%1 +DirExistsTitle= +DirExists=:%n%n%1%n%n . ? +DirDoesntExistTitle= +DirDoesntExist=:%n%n%1%n%n . ? + +; *** " " +WizardSelectComponents= +SelectComponentsDesc= ? +SelectComponentsLabel2= ; . 볻, . +FullInstallation= +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation= +CustomInstallation= +NoUninstallWarningTitle= +NoUninstallWarning=, :%n%n%1%n%n³ .%n%n ? +ComponentSize1=%1 K +ComponentSize2=%1 M +ComponentsDiskSpaceGBLabel= [gb] . +ComponentsDiskSpaceMBLabel= [mb] M . + +; *** " " +WizardSelectTasks= +SelectTasksDesc= ? +SelectTasksLabel2= [name] , 볻. + +; *** " " +WizardSelectProgramGroup= +SelectStartMenuFolderDesc= ? +SelectStartMenuFolderLabel3= . +SelectStartMenuFolderBrowseLabel= 볻, . , . +MustEnterGroupName= ' . +GroupNameTooLong= . +InvalidGroupName= . +BadGroupName=' :%n%n%1 +NoProgramGroupCheck2=& + +; *** " " +WizardReady= +ReadyLabel1= [name] . +ReadyLabel2a= , , . +ReadyLabel2b= . +ReadyMemoUserInfo= : +ReadyMemoDir= : +ReadyMemoType= : +ReadyMemoComponents= : +ReadyMemoGroup= : +ReadyMemoTasks= : + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel= ... +ButtonStopDownload=& +StopDownload= ? +ErrorDownloadAborted= +ErrorDownloadFailed= : %1 %2 +ErrorDownloadSizeFailed= : %1 %2 +ErrorFileHash1= : %1 +ErrorFileHash2= : %1, %2 +ErrorProgress= : %1 %2 +ErrorFileSize= : %1, %2 + +; *** "ϳ " +WizardPreparing=ϳ +PreparingDesc= [name] . +PreviousInstallNotCompleted= . .%n%nϳ , [name]. +CannotContinue= . , . +ApplicationsFound= , . . +ApplicationsFound2= , . . ϳ , . +CloseApplications=& +DontCloseApplications=& +ErrorCloseApplications= . , , , . +PrepareToInstallNeedsRestart= . ϳ , [name]%n%n ? + +; *** "" +WizardInstalling= +InstallingLabel= , , [name] '. + +; *** " " +FinishedHeadingLabel= [name] +FinishedLabelNoIcons= [name] . +FinishedLabel= [name] . . +ClickFinish= . +FinishedRestartLabel= [name] . ? +FinishedRestartMessage= [name] .%n%n ? +ShowReadmeCheck=, README +YesRadio=&, +NoRadio=&ͳ, +; used for example as 'Run MyProg.exe' +RunEntryExec=³ %1 +; used for example as 'View Readme.txt' +RunEntryShellExec= %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle= +SelectDiskLabel2= , %1 OK.%n%n , , . +PathLabel=&: +FileNotInDir2= "%1" "%2". , . +SelectDirectoryLabel= , . + +; *** Installation phase messages +SetupAborted= .%n%n , . +AbortRetryIgnoreSelectAction= +AbortRetryIgnoreRetry=& +AbortRetryIgnoreIgnore=& +AbortRetryIgnoreCancel=³ + +; *** +StatusClosingApplications= ... +StatusCreateDirs= ... +StatusExtractFiles= ... +StatusCreateIcons= ... +StatusCreateIniEntries= INI ... +StatusCreateRegistryEntries= ... +StatusRegisterFiles= ... +StatusSavingUninstall= ... +StatusRunProgram= ... +StatusRestartingApplications= ... +StatusRollback= ... + +; *** г +ErrorInternal2= : %1 +ErrorFunctionFailedNoCode=%1 +ErrorFunctionFailed=%1 ; %2 +ErrorFunctionFailedWithMessage=%1 ; %2.%n%3 +ErrorExecutingProgram= :%n%1 + +; *** +ErrorRegOpenKey= :%n%1\%2 +ErrorRegCreateKey= :%n%1\%2 +ErrorRegWriteKey= :%n%1\%2 + +; *** INI +ErrorIniEntry= INI- "%1". + +; *** +FileAbortRetryIgnoreSkipNotRecommended=& ( ) +FileAbortRetryIgnoreIgnoreNotRecommended=& ( ) +SourceIsCorrupted= +SourceDoesntExist= "%1" +ExistingFileReadOnly2= , . +ExistingFileReadOnlyRetry=& " " +ExistingFileReadOnlyKeepExisting=& +ErrorReadingExistingDest= : +FileExistsSelectAction= +FileExists2= . +FileExistsOverwriteExisting=& +FileExistsKeepExisting=& +FileExistsOverwriteOrKeepAll=& +ExistingFileNewerSelectAction= +ExistingFileNewer2= , . +ExistingFileNewerOverwriteExisting=& +ExistingFileNewerKeepExisting=& () +ExistingFileNewerOverwriteOrKeepAll=& +ErrorChangingAttr= : +ErrorCreatingTemp= : +ErrorReadingSource= : +ErrorCopying= : +ErrorReplacingExistingFile= : +ErrorRestartReplace= RestartReplace: +ErrorRenamingTemp= : +ErrorRegisterServer= DLL/OCX: %1 +ErrorRegSvr32Failed= RegSvr32, %1 +ErrorRegisterTypeLib= : %1 + +; *** Uninstall display name markings +UninstallDisplayNameMark=%1 (%2) +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32- +UninstallDisplayNameMark64Bit=64- +UninstallDisplayNameMarkAllUsers= +UninstallDisplayNameMarkCurrentUser= + +; *** Post-installation errors +ErrorOpeningReadme= README. +ErrorRestartingComputer= '. , . + +; *** +UninstallNotFound= "%1" , . +UninstallOpenError= "%1". +UninstallUnsupportedVer= "%1" . +UninstallUnknownEntry= (%1) +ConfirmUninstall= , %1 ? +UninstallOnlyOnWin64= 64- Windows. +OnlyAdminCanUninstall= . +UninstallStatusLabel= , , %1 '. +UninstalledAll=%1 '. +UninstalledMost= %1 .%n%n . . +UninstalledAndNeedsRestart= %1 .%n%n ? +UninstallDataCorrupted= "%1" . + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle= ? +ConfirmDeleteSharedFile2= , . ?%n%n , . , ͳ. . +SharedFileNameLabel=' : +SharedFileLocationLabel=: +WizardUninstalling= +StatusUninstalling= %1... + + +; *** +ShutdownBlockReasonInstallingApp= %1. +ShutdownBlockReasonUninstallingApp= %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1, %2 +AdditionalIcons= : +CreateDesktopIcon= & +CreateQuickLaunchIcon= & +ProgramOnTheWeb= %1 +UninstallProgram= %1 +LaunchProgram=³ %1 +AssocFileExtension=& %1 %2 +AssocingFileExtension= %1 %2... +AutoStartProgramGroupDescription=: +AutoStartProgram= %1 +AddonHostProgramNotFound=%1 %n%n ? diff --git a/installer/innosetup/Languages/Urdu.isl b/installer/innosetup/Languages/Urdu.isl new file mode 100644 index 000000000..4f4cc1d37 --- /dev/null +++ b/installer/innosetup/Languages/Urdu.isl @@ -0,0 +1,388 @@ +; *** Inno Setup version 6.1.0+ Urdu messages *** +; +;Translated by Hamza Hayat +;E-mail: hayat9437786878@gmail.com +;Last Modified: 02-10-2020 (21:18 AM) +; +; To download user-contributed translations of this file, go to: +; https://jrsoftware.org/files/istrans/ +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). + +[LangOptions] +; The following three entries are very important. Be sure to read and +; understand the '[LangOptions] section' topic in the help file. +LanguageName=Urdu +LanguageID=$0420 +LanguageCodePage=0 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName= +;WelcomeFontSize=12 +;TitleFontName= +;TitleFontSize=29 +;CopyrightFontName= +;CopyrightFontSize=8 + +[Messages] + +; *** Application titles +SetupAppTitle=سیٹ اپ +SetupWindowTitle=سیٹ اپ - %1 +UninstallAppTitle=ناتنصیب +UninstallAppFullTitle=%1 ناتنصیب + +; *** Misc. common +InformationTitle=معلومات +ConfirmTitle=تصدیق +ErrorTitle=نقص + +; *** SetupLdr messages +SetupLdrStartupMessage=یہ تنصیب کرے گا %1. کیا آپ جاری رکھنا چاہتے ہیں؟ +LdrCannotCreateTemp=ایک عارضی مسل نہیں بنا سکے. سیٹ اپ ساقط +LdrCannotExecTemp=عارضی ڈائریکٹری میں مسل کا نفاذ نہیں کر سکتا. سیٹ اپ ساقط +HelpTextNote= + +; *** Startup error messages +LastErrorMessage=%1.%n%nنقص %2: %3 +SetupFileMissing=مسل %1 تنصیب ڈائریکٹری سے غائب ہے. مسئلہ کی تصحیح کریں یا پروگرام کی نئی نقل حاصل کریں. +SetupFileCorrupt=سیٹ اپ مسلیں خراب ہیں. برائے مہربانی پروگرام کی ایک نئی نقل حاصل کریں. +SetupFileCorruptOrWrongVer=سیٹ اپ مسلیں خراب ہیں، یا سیٹ اپ کے اس ورژن کے ساتھ مطابقت نہیں ہے. برائے مہربانی مسئلہ کی تصحیح کریں یا پروگرام کی نئی نقل حاصل کریں. +InvalidParameter=حکم لائن پر ایک ناجائز پیرامیٹر منظور کیا گیا:%n%n%1 +SetupAlreadyRunning=سیٹ اپ پہلے ہی چل رہا ہے. +WindowsVersionNotSupported=یہ پروگرام Windows کے اس ورژن کی معاونت نہیں کرتا جس پرآپ کا کمپیوٹر چل رہا ہے. +WindowsServicePackRequired=اس پروگرام کو %1 خدمت پیک %2 یا اس کے بعد کی درکار ہے. +NotOnThisPlatform=یہ پروگرام %1 پر نہیں چلایا جائے گا. +OnlyOnThisPlatform=اس پروگرام کی چلت %1 پر ہونی چاہیئے. +OnlyOnTheseArchitectures=یہ پروگرام صرف مندرجہ ذیل پروسیسر کے لئے ڈیزائن کیا گیا ونڈوز کے ورژن پر نصب کیا جا سکتا ہے:%n%n%1 +WinVersionTooLowError=اس پروگرام کو %1 ورژن %2 یا اس کے بعد کی ضرورت ہے. +WinVersionTooHighError=یہ پروگرام تنصیب نہیں کیا جا سکتا بر %1 ورژن %2 یا بعد. +AdminPrivilegesRequired=یہ پروگرام نصب کرتے وقت آپ کو بطور منتظم لاگ ان ہونا چاہیے. +PowerUserPrivilegesRequired=یہ پروگرام نصب کرتے وقت آپ کو بطور منتظم یا بجلی صارفین گروپ کے رکن کے طور پر لاگ ان ہونا چاہیے. +SetupAppRunningError=سیٹ اپ نے کھوج لگایا ہے کہ %1 اس وقت چل رہا ہے.%n%nبرائے مہربانی ابھی اس کی تمام مثالیں بند کریں، پھر کلک کریں ٹھيک ہے جاری رکھنے کے لئے، یا خروج کے لیے منسوخ کریں. +UninstallAppRunningError=ناتنصیب کاری نے کھوج لگایا ہے کہ %1 اس وقت چل رہا ہے.%n%nبرائے مہربانی ابھی اس کی تمام مثالیں بند کریں، پھر کلک کریں ٹھيک ہے جاری رکھنے کے لئے، یا خروج کے لیے منسوخ کریں. + +; *** Startup questions +PrivilegesRequiredOverrideTitle=سیٹ اپ تنصیب موڈ منتخب کریں +PrivilegesRequiredOverrideInstruction=تنصیب موڈ منتخب کریں +PrivilegesRequiredOverrideText1=%1 تمام صارفین کے لیے تنصیب کی جا سکتی ہے (انتظامی استحقاق کی ضرورت ہوتی ہے)، یا صرف آپ کے لئے. +PrivilegesRequiredOverrideText2=%1 صرف آپ کے لیے تنصیب کیا جا سکتا ہے، یا تمام صارفین کے لئے (انتظامی استحقاق کی ضرورت ہوتی ہے). +PrivilegesRequiredOverrideAllUsers=تمام صارفین &کے لیے تنصیب کریں +PrivilegesRequiredOverrideAllUsersRecommended=تمام صارفین &کے لیے تنصیب کریں (تجویز) +PrivilegesRequiredOverrideCurrentUser=فقط میرے &لیے تنصیب کریں +PrivilegesRequiredOverrideCurrentUserRecommended=فقط میرے &لیے تنصیب کریں (تجویز) + +; *** Misc. errors +ErrorCreatingDir=سیٹ اپ ڈائریکٹری "%1" بنانے میں نااہل ہے +ErrorTooManyFilesInDir=ڈائریکٹری "%1" میں مسل نہیں بنا سکے کیونکہ یہ بہت زیادہ مسلوں کا حامل ہے + +; *** Setup common messages +ExitSetupTitle=سیٹ اپ خروج کریں +ExitSetupMessage=سیٹ اپ مکمل نہیں ہوا ہے. اگر آپ اب خروج کریں گے تو, پروگرام تنصیب نہیں کیا جائے گا.%n%nتنصیب مکمل کرنے کے لیے آپ ایک اور بار سیٹ اپ چلا سکتے ہیں.%n%nسیٹ اپ خروج کریں؟ +AboutSetupMenuItem=&سیٹ اپ کے بارے میں... +AboutSetupTitle=سیٹ اپ کے بارے میں +AboutSetupMessage=%1 ورژن %2%n%3%n%n%1 ابتدائی صفحہ:%n%4 +AboutSetupNote= +TranslatorNote= + +; *** Buttons +ButtonBack=< &پچھلا +ButtonNext=&اگلا > +ButtonInstall=&تنصیب کریں +ButtonOK=ٹھيک ہے +ButtonCancel=منسوخ +ButtonYes=&ہاں +ButtonYesToAll=ہاں &تمام +ButtonNo=&نہيں +ButtonNoToAll=تم&ام کے لیے نہیں +ButtonFinish=&تکمیل +ButtonBrowse=&براؤز... +ButtonWizardBrowse=ب&راؤز... +ButtonNewFolder=&نیا پوشہ بنائیں + +; *** "Select Language" dialog messages +SelectLanguageTitle=سیٹ اپ زبان منتخب کریں +SelectLanguageLabel=تنصیب کے دوران استعمال کرنے کے لیے زبان منتخب کریں. + +; *** Common wizard text +ClickNext=جاری رکھنے کے لیے اگلا پر کلک کریں، یا سیٹ اپ سے باہر نکلنے کے لیے منسوخ کریں. +BeveledLabel= +BrowseDialogTitle=پوشہ کے لیے براؤز کریں +BrowseDialogLabel=نیچے فہرست میں ایک پوشہ منتخب کریں، پھر کلک کریں ٹھيک ہے. +NewFolderName=نیا پوشہ + +; *** "Welcome" wizard page +WelcomeLabel1=[name] سیٹ اپ مددگار میں خوش آمدید +WelcomeLabel2=یہ آپ کے کمپیوٹر پر [name/ver] نصب کرے گا.%n%nیہ سفارش کی جاتی ہے کہ آپ جاری رکھنے سے قبل دیگر تمام ایپلی کیشن بند کریں. + +; *** "Password" wizard page +WizardPassword=پاس ورڈ +PasswordLabel1=اس تنصیب ویں پاس ورڈ کی حفاظت ہے. +PasswordLabel3=براہ مہربانی پاس ورڈ فراہم کریں، پھر جاری رکھنے کے لیے اگلا پر کلک کریں. پاس ورڈ کیس-حساس ہے. +PasswordEditLabel=&پاس ورڈ: +IncorrectPassword=داخل کردہ پاس ورڈ صحیح نہیں ہے. دوبارہ کوشش کریں. + +; *** "License Agreement" wizard page +WizardLicense=لائسنس معاہدہ +LicenseLabel=جاری رکھنے سے قبل درج ذیل اہم معلومات پڑھیں. +LicenseLabel3=براہ کرم مندرجہ ذیل لائسنس کے معاہدے کو پڑھیں. تنصیب کے ساتھ جاری رکھنے سے قبل اس معاہدے کی شرائط قبول کریں. +LicenseAccepted=میں &معاہدہ قبول کرتا ہوں +LicenseNotAccepted=میں &معاہدہ قبول نہیں کتا ہوں + +; *** "Information" wizard pages +WizardInfoBefore=معلومات +InfoBeforeLabel=جاری رکھنے سے قبل درج ذیل اہم معلومات پڑھیں. +InfoBeforeClickLabel=جب آپ سیٹ اپ کے ساتھ جاری رکھنے کے لیے تیار ہوں تو، کلک کریں اگلا. +WizardInfoAfter=معلومات +InfoAfterLabel=جاری رکھنے سے قبل درج ذیل اہم معلومات پڑھیں. +InfoAfterClickLabel=جب آپ سیٹ اپ کے ساتھ جاری رکھنے کے لیے تیار ہوں تو، کلک کریں اگلا. + +; *** "User Information" wizard page +WizardUserInfo=معلومات صارف +UserInfoDesc=براہ مہربانی اپنی معلومات درج کریں. +UserInfoName=&صارف نام: +UserInfoOrg=&تنظیم: +UserInfoSerial=&سیریل نمبر: +UserInfoNameRequired=آپ کو ایک نام داخل کرنا چاہیئے. + +; *** "Select Destination Location" wizard page +WizardSelectDir=مقصود محل وقوع منتخب کریں +SelectDirDesc=جہاں [name] نصب کیا جانا ہے؟ +SelectDirLabel3=سیٹ اپ درج ذیل پوشہ میں [name] تنصیب کرے گا. +SelectDirBrowseLabel=جاری رکھنے کے لیے، کلک کریں اگلا. اگر آپ مختلف فولڈر کو منتخب کرنا چاہتے ہیں، تو براؤز پر کلک کریں. +DiskSpaceGBLabel=کم ازکم [gb] GB مفت ڈسک گنجایش مطلوب ہے. +DiskSpaceMBLabel=کم ازکم [mb] MB مفت ڈسک گنجایش مطلوب ہے. +CannotInstallToNetworkDrive=سیٹ اپ نیٹ ورک ڈرائیو پر تنصیب نہیں کر سکتا. +CannotInstallToUNCPath=سیٹ اپ UNC راہ پر تنصیب نہیں کر سکتا. +InvalidPath=ڈرائیو حرف کے ساتھ ایک مکمل راہ داخل کریں; مثال ک لیے:%n%nC:\APP%n%UNC راستہ نہیں ہے کے فارم میں:%n%n\\server\share +InvalidDrive=آپ کی منتخب ڈرائیو یا UNC حصہ داری موجود نہیں یا قابل رسائی نہیں ہے. کوئی اور منتخب کریں. +DiskSpaceWarningTitle=کافی ڈسک گنجایش نہیں +DiskSpaceWarning=سیٹ اپ تنصیب کرنے کے لیے کم ازکم %1 KB خالی جگہ کی ضرورت ہے، لیکن منتخب ڈرائیو فقط %2 KB دستیاب ہے.%n%nکیا آپ بہرصورت جاری رکھنا چاہتے ہیں؟ +DirNameTooLong=نام پوشہ یا راہ بہت طویل ہے. +InvalidDirName=نام پوشہ جائز نہیں. +BadDirName32=نام پوشہ درج ذیل کریکٹروں میں سے کوئی شامل نہیں ہو سکتا:%n%n%1 +DirExistsTitle=پوشہ موجود ہے +DirExists=وہ پوشہ:%n%n%1%n%nپہلے ہی موجود ہے. کیا آپ بہرصورت پوشہ کو تنصیب کرنا چاہتے ہیں؟ +DirDoesntExistTitle=پوشہ موجود نہیں +DirDoesntExist=وہ پوشہ:%n%n%1%n%nموجود نہیں ہے. کیا آپ پوشہ بنانا چاہتے ہیں؟ + +; *** "Select Components" wizard page +WizardSelectComponents=اجزاء منتخب کریں +SelectComponentsDesc=کون سا اجزاء نصب کیا جانا چاہئے؟ +SelectComponentsLabel2=وہ اجزاء منتخب کریں جو آپ تنصیب کرنا چاہتے ہیں; وہ اجزاء صاف کریں جو آپ تنصیب نہیں کرنا چاہتے. جب آپ جاری رکھنے کے لیے تیار ہوں تو اگلا پر کلک کریں. +FullInstallation=مکمل تنصیب +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=کومپیکٹ تنصیب +CustomInstallation=مخصوص تنصیب +NoUninstallWarningTitle=اجزاء موجود ہیں +NoUninstallWarning=سیٹ اپ نے کھوج لگایا ہے کہ درج ذیل اجزاء آپ کے کمپیوٹر پر پہلے ہی نصب ہیں:%n%n%1%n%nان اجزاء کو غیر منتخب کرنے سے ان کو ناتنصیب نہیں کرے گا.%n%nکیا آپ بہرصورت جاری رکھنا چاہیں گے؟ +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceGBLabel=حالیہ انتخاب کو کم ازکم [gb] GB ڈسک گنجایش کی درکار ہے. +ComponentsDiskSpaceMBLabel=حالیہ انتخاب کو کم ازکم [mb] MB ڈسک گنجایش کی درکار ہے. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=اضافی مجموعہ کار منتخب کریں +SelectTasksDesc=کونسی اضافی کاموں کو انجام دیا جانا چاہئے؟ +SelectTasksLabel2=اس اضافی مجموعہ کار کو منتخب کریں جو آپ [name] نصب کرتے وقت انجام دینے کے لیے سیٹ اپ چاہتے ہیں، پھر کلک کریں اگلا. + +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=شروع مینیو پوشہ منتخب کریں +SelectStartMenuFolderDesc=پروگرام کی تیز راہیں کہاں سیٹ کریں؟ +SelectStartMenuFolderLabel3=سیٹ اپ درج ذیل شروع مینیو پوشہ میں پروگرام کا تیز راہیں بنا دے گا. +SelectStartMenuFolderBrowseLabel=جاری رکھنے کے لیے، کلک کریں اگلا. اگر آپ مختلف پوشہ منتخب کرنا چاہتے ہیں، براؤز پر کلک کریں. +MustEnterGroupName=آپ کو پوشہ نام داخل کرنا چاہیئے. +GroupNameTooLong=نام پوشہ یا راہ بہت طویل ہے. +InvalidGroupName=نام پوشہ جائز نہیں. +BadGroupName=نام پوشہ میں درج ذیل کریکٹروں میں سے کوئی بھی شامل نہیں ہو سکتا:%n%n%1 +NoProgramGroupCheck2=&شروع مینیو پوشہ مت بنائیں + +; *** "Ready to Install" wizard page +WizardReady=تنصیب کے لیے تیار +ReadyLabel1=سیٹ اپ اب آپ کے کمپیوٹر پر [name] نصب کرنے کے لیے تیار ہے. +ReadyLabel2a=تنصیب کے ساتھ جاری رکھنے کے لیے تنصیب پر کلک کریں، یا اگر آپ کوئی سیٹنگیں جائزہ یا تبدیل کرنا چاہتے ہیں تو واپس پر کلک کریں. +ReadyLabel2b=تنصیب کے ساتھ جاری رکھنے کے لیے تنصیب پر کلک کریں. +ReadyMemoUserInfo=معلومات صارف: +ReadyMemoDir=مقصود محل وقوع: +ReadyMemoType=سیٹ اپ قسم: +ReadyMemoComponents=منتخب اجزاء: +ReadyMemoGroup=شروع مینیو پوشہ: +ReadyMemoTasks=اضافی کام: + +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=اضافی مسلیں ڈاؤن لوڈ کر رہا ہے... +ButtonStopDownload=&ڈاؤن لوڈ روکیں +StopDownload=آپ کو یقین ہے کہ آپ ڈاؤن لوڈ روکنا چاہتے ہیں؟ +ErrorDownloadAborted=ڈاؤن لوڈ ساقط +ErrorDownloadFailed=ڈاؤن لوڈ ناکام: %1 %2 +ErrorDownloadSizeFailed=سائز کے حصول میں ناکامی: %1 %2 +ErrorFileHash1=مسل ہیش ناکام: %1 +ErrorFileHash2=ناجائز مسل ہیش: expected %1, found %2 +ErrorProgress=ناجائز پیش رفت: %1 of %2 +ErrorFileSize=ناجائز مسل سائز: expected %1, found %2 + +; *** "Preparing to Install" wizard page +WizardPreparing=تنصیب کی تیاری کررہا ہے +PreparingDesc=سیٹ اپ آپ کے کمپیوٹر پر [name] نصب کرنے کی تیاری کر رہا ہے. +PreviousInstallNotCompleted=پچھلے پروگرام کی تنصیب/ہٹانا مکمل نہیں ہوئی. تنصیب مکمل کرنے کے لیے آپ کو کمپیوٹر پھر شروع کرنے کی ضرورت ہو گی.%n%nاپنے کمپیوٹر کو دوبارہ شروع کرنے کے بعد، [name] کی تنصیب مکمل کرنے کے لیے سیٹ اپ پھر چلائیں. +CannotContinue=سیٹ اپ جاری نہیں رہ سکتا. خروج کے لیے منسوخ پر کلک کریں. +ApplicationsFound=درج ذیل ایپلی کیشن ایسی مسلوں کا استعمال کر رہے ہیں جس کی سیٹ اپ کی طرف سے تازہ کاری کی ضرورت ہے. سفارش کی جاتی ہے کہ آپ ان ایپلی کیشنز کو خود بخود بند کرنے کے لیے سیٹ اپ کو اجازت دیں. +ApplicationsFound2=درج ذیل ایپلی کیشن ایسی مسلوں کا استعمال کر رہے ہیں جس کی سیٹ اپ کی طرف سے تازہ کاری کی ضرورت ہے. سفارش کی جاتی ہے کہ آپ ان ایپلی کیشنز کو خود بخود بند کرنے کے لیے سیٹ اپ کو اجازت دیں. تنصیب مکمل ہونے کے بعد، سیٹ اپ ایپلی کیشن پھر شروع کرنے کی کوشش کرے گا. +CloseApplications=&خود بخود ایپلی کیشنوں کو بند کریں +DontCloseApplications=&ایپلی کیشنوں کو بند نہ کریں +ErrorCloseApplications=سیٹ اپ خود بخود تمام ایپلی کیشنوں کو بند نہیں کر سکا. سفارش کی جاتی ہے کہ آپ مسلوں کا استعمال کر رہے تمام ایپلی کیشنز کو بند کریں جس کو جاری رکھنے سے قبل سیٹ اپ کی طرف سے تازہ کاری کی ضرورت ہے. +PrepareToInstallNeedsRestart=سیٹ اپ آپ کے کمپیوٹر کو پھر شروع کرنا چاہے گا. اپنے کمپیوٹر کو دوبارہ شروع کرنے کے بعد، [name] کی تنصیب مکمل کرنے کے لیے سیٹ اپ پھر چلائیں.%n%nکیا آپ ابھی پھر شروع کرنا چاہتے ہیں؟ + +; *** "Installing" wizard page +WizardInstalling=تنصیب کر رہا ہے +InstallingLabel=انتظار کریں جب تک سیٹ اپ آپ کے کمپیوٹر پر [name] تنصیب کتا ہے. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name] سیٹ اپ مددگار مکمل کیا جارہا ہے +FinishedLabelNoIcons=سیٹ اپ نے آپ کے کمپیوٹر پر [name] تنصیب کاری ختم کر دی ہے. +FinishedLabel=سیٹ اپ نے آپ کے کمپیوٹر پر [name] تنصیب کاری ختم کر دی ہے. ایپلی کیشن تنصیب شدہ تیزراہ منتخب کر کے شروع کی جا سکتی ہے. +ClickFinish=سیٹ اپ سے باہر نکلنے کے لیے تکمیل پر کلک کریں. +FinishedRestartLabel=[name] کی تنصیب مکمل کرنے کے لیے، سیٹ اپ آپ کے کمپیوٹر کو پھر شروع کرنا چاہے گا. کیا آپ ابھی پھر شروع کرنا چاہتے ہیں؟ +FinishedRestartMessage=[name] کی تنصیب مکمل کرنے کے لیے، سیٹ اپ آپ کے کمپیوٹر کو پھر شروع کرنا چاہے گا.%n%nکیا آپ ابھی پھر شروع کرنا چاہتے ہیں؟ +ShowReadmeCheck=جی ہاں، میں README فائل دیکھنا چاہتا ہوں +YesRadio=&ہاں، ابھی کمپیوٹر پھر شروع کریں +NoRadio=&نہیں، میں بعد میں کمپیوٹر پھر شروع کروں گا +; used for example as 'Run MyProg.exe' +RunEntryExec=چلایئں %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=دیکھیں %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=سیٹ اپ کو اگلے ڈسک کی ضرورت ہے +SelectDiskLabel2=ڈسک %1 داخل کریں اور ٹھیک ہے پر کلک کریں.%n%nاگر اس ڈسک پر مسلیں نیچے دکھائے گئے ایک کے علاوہ پوشہ میں موجود ہیں، صحیح راہ داخل کریں یا براؤز پر کلک کریں. +PathLabel=&راہ: +FileNotInDir2=مسل "%1" "%2" میں نہیں مل سکی. صحیح ڈسک داخل کریں یا کسی اور پوشہ کا انتخاب کریں. +SelectDirectoryLabel=اگلی ڈسک محل وقوع کی اختصاص کریں. + +; *** Installation phase messages +SetupAborted=سیٹ اپ مکمل نہیں ہوا.%n%nمسئلہ درست کریں اور سیٹ اپ پھر چلائیں. +AbortRetryIgnoreSelectAction=عمل منتخب کریں +AbortRetryIgnoreRetry=&دوبارہ کوشش کریں +AbortRetryIgnoreIgnore=&نقص نظرانداز کریں اور جاری رکھیں +AbortRetryIgnoreCancel=تنصیب منسوخ کریں + +; *** Installation status messages +StatusClosingApplications=اختتامی ایپلی کیشنوں... +StatusCreateDirs=ڈائریکٹریز بنانا... +StatusExtractFiles=مسلیں نکالنا... +StatusCreateIcons=شارٹ کٹ بنانا... +StatusCreateIniEntries=INI اندراجات بناناs... +StatusCreateRegistryEntries=رجسٹری اندراجات بنانا... +StatusRegisterFiles=مسل رجسٹر کر رہا ہے... +StatusSavingUninstall=ناتنصیب معلومات محفوظ کر رہا ہےناتنصیب معلومات محفوظ کر رہا ہے... +StatusRunProgram=تنصیب مکمل... +StatusRestartingApplications=ایپلی کیشن پھر شروع... +StatusRollback=تبدیلیوں کو رولنگ بیک... + +; *** Misc. errors +ErrorInternal2=اندرونی نقص: %1 +ErrorFunctionFailedNoCode=%1 ناکام +ErrorFunctionFailed=%1 ناکام; کوڈ %2 +ErrorFunctionFailedWithMessage=%1 ناکام; کوڈ %2.%n%3 +ErrorExecutingProgram=مسل کے نفاذ میں ناکام:%n%1 + +; *** Registry errors +ErrorRegOpenKey=رجسٹری کلید کھولنے میں نقص:%n%1\%2 +ErrorRegCreateKey=رجسٹری کلید بنانے میں نقص:%n%1\%2 +ErrorRegWriteKey=رجسٹری کلید میں تحریر میں نقص:%n%1\%2 + +; *** INI errors +ErrorIniEntry=مسل "%1" INI اندراج بنانے میں نقص. + +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=&یہ مسل چھوڑیں (سفارش کی نہیں) +FileAbortRetryIgnoreIgnoreNotRecommended=&نقص نظرانداز کریں اور جاری رکھیں (سفارش کی نہیں) +SourceIsCorrupted=ماخذ مسل خراب ہے +SourceDoesntExist=ماخذ مسل "%1" موجود نہیں +ExistingFileReadOnly2=موجود مسل تبدیل نہیں کی جا سکی کیونکہ اسے read-only نشان زد کیا گیا ہے. +ExistingFileReadOnlyRetry=&read-only خاصیت ہٹائیں اور پھر کوشش کریں +ExistingFileReadOnlyKeepExisting=&موجودہ مسل رکھیں +ErrorReadingExistingDest=موجود مسل کو پڑھنے کی کوشش کے دوران ایک نقص واقع ہوا: +FileExistsSelectAction=عمل منتخب کریں +FileExists2=مسل پہلے ہی موجود ہے. +FileExistsOverwriteExisting=&موجود مسل پر برتحریر کریں +FileExistsKeepExisting=&موجودہ مسل رکھیں +FileExistsOverwriteOrKeepAll=&اگلے تنازعات کے لئے یہ کریں +ExistingFileNewerSelectAction=عمل منتخب کریں +ExistingFileNewer2=موجودہ مسل ایک سیٹ اپ کے لیے نیا ہے جو تنصیب کی کوشش کر رہا ہے. +ExistingFileNewerOverwriteExisting=&موجود مسل پر برتحریر کریں +ExistingFileNewerKeepExisting=&موجودہ مسل رکھیں (تجویز) +ExistingFileNewerOverwriteOrKeepAll=&اگلے تنازعات کے لئے یہ کریں +ErrorChangingAttr=موجود مسل کے اوصاف تبدیل کرنے کی کوشش کے دوران نقص واقع ہوا: +ErrorCreatingTemp=مقصود ڈائریکٹری میں مسل بنانے کی کوشش کے دوران نقص واقع ہوا: +ErrorReadingSource=ماخذ مسل پڑھنے کی کوشش کے دوران نقص واقع ہوا: +ErrorCopying=مسل نقل کرنے کی کوشش کے دوران نقص واقع ہوا: +ErrorReplacingExistingFile=موجود مسل کی جگہ بنانے کی کوشش میں ایک نقص واقع ہوا: +ErrorRestartReplace=RestartReplace ناکام: +ErrorRenamingTemp=مقصود ڈائریکٹری میں مسل کا نام تبدیل کرنے کی کوشش کے دوران نقص واقع ہوا: +ErrorRegisterServer=DLL/OCX رجسٹر نہیں کر سکا: %1 +ErrorRegSvr32Failed=RegSvr32 خروج ضابطہ کے ساتھ ناکام %1 +ErrorRegisterTypeLib=قسم لائبریری رجسٹر نہیں کر سکا: %1 + +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2, %3) +UninstallDisplayNameMark32Bit=32-bit +UninstallDisplayNameMark64Bit=64-bit +UninstallDisplayNameMarkAllUsers=تمام صارفین +UninstallDisplayNameMarkCurrentUser=موجودہ صارف + +; *** Post-installation errors +ErrorOpeningReadme=README مسل کھولنے کی کوشش کے دوران نقص واقع ہوا. +ErrorRestartingComputer=سیٹ اپ کمپیوٹر پھر شروع نہیں کر سکا. براہ کرم اسے دستی طور پر کریں. + +; *** Uninstaller messages +UninstallNotFound=مسل "%1" موجود نہیں. ناتنصیب نہیں کر سکتے. +UninstallOpenError=مسل "%1" نہیں کھولی جا سکی. ناتنصیب نہیں کر سکتے +UninstallUnsupportedVer=ناتنصیب لاگ مسل "%1" ناتنصیبکار کے اس ورژن کی طرف سے تسلیم شدہ وضع میں ہے. ناتنصیب نہیں کر سکتے +UninstallUnknownEntry=ایک نامعلوم اندراج (%1) ناتنصیب لاگ میں سامنا کیا گیا +ConfirmUninstall=آپ کو یقین کے آپ %1 اور اس کے تمام اجزاء کو مکمل طور پر ہٹانا چاہتے ہیں؟ +UninstallOnlyOnWin64=یہ تنصیب صرف 64-bit Windows پر ناتنصیب کی جا سکتی ہے. +OnlyAdminCanUninstall=یہ تنصیب صرف ایک صارف کی طرف سے انتظامی استحقاق کے ساتھ نا تنصیب کی جا سکتی ہے. +UninstallStatusLabel=انتظار کریں جبکہ %1 آپ کے کمپیوٹر سے ہٹا دیا جاۓ. +UninstalledAll=%1 آپ کے کمپیوٹر سے کامیابی سے ہٹا دیا گیا. +UninstalledMost=%1 ناتنصیب مکمل.%n%nکچھ عناصر نہیں ہٹایا جا سکا. یہ دستی طور پر ہٹا دیا جا سکتا ہے. +UninstalledAndNeedsRestart=%1 کی ناتنصیب مکمل کرنے کے لیے، آپ کا کمپیوٹر پھر شروع ہونا چاہیے.%n%nکیا آپ ابھی پھر شروع کرنا چاہتے ہیں؟ +UninstallDataCorrupted="%1" مسل خراب ہے. ناتنصیب نہیں کر سکتے + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=حصہ دارانہ مسل ہٹائیں? +ConfirmDeleteSharedFile2=نظام نشاندہی کرتا ہے کہ درج ذیل مشترکہ مسل کسی بھی پروگرام کے استعمال میں نہیں ہے. کیا آپ اس حصہ دارانہ مسل کو ہٹانے کے لیے ناتنصیب کرنا چاہیں گے?%n%nاگر کوئی پروگرام اب بھی اس مسل کا استعمال کر رہے ہیں اور اسے ہٹا دیا جاتا ہے، وہ پروگرام ٹھیک سے کام نہیں کر سکتے. اگر آپ کو یقین نہیں ہے، منتخب کریں نہیں. آپ کے سسٹم پر مسل چھوڑنا کسی بھی نقصان کا سبب نہیں ہوگا. +SharedFileNameLabel=مسل کا نام: +SharedFileLocationLabel=محل وقوع: +WizardUninstalling=غیر تنصیب حالت +StatusUninstalling=ناتنصیب %1... + +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=تنصیب %1. +ShutdownBlockReasonUninstallingApp=ناتنصیب %1. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. + +[CustomMessages] + +NameAndVersion=%1 ورژن %2 +AdditionalIcons=اضافی شارٹ کٹس: +CreateDesktopIcon=ایک ڈیسک ٹاپ &تیز راہ بنائیں +CreateQuickLaunchIcon=ایک سریع &شروع تیز راہ بنائیں +ProgramOnTheWeb=%1 ویب پر +UninstallProgram=ناتنصیب %1 +LaunchProgram=شروع %1 +AssocFileExtension=&واپستہ %1 مع %2 مسل توسیع کریں +AssocingFileExtension=واپستہ %1 مع %2 مسل توسیع... +AutoStartProgramGroupDescription=آغاز: +AutoStartProgram=خودبخود شروع کریں %1 +AddonHostProgramNotFound=%1 آپ کی منتخب پوشہ میں نہیں واقع ہو سکا.%n%nکیا آپ بہرصورت جاری رکھنا چاہتے ہیں؟ diff --git a/installer/innosetup/Languages/Uyghur.islu b/installer/innosetup/Languages/Uyghur.islu index 1f702c7a5..e9f288dc1 100644 --- a/installer/innosetup/Languages/Uyghur.islu +++ b/installer/innosetup/Languages/Uyghur.islu @@ -1,9 +1,9 @@ -; *** Inno Setup version 5.5.3+ Uyghur messages *** -; Translated by Irshat ghalib [ uqkun09@msn.cn ] +; *** Inno Setup version 6.1.0+ Uyghur messages *** +; Translated by Irshat Ghalip (uqkun09@msn.cn) ; To download user-contributed translations of this file, go to: -; http://www.jrsoftware.org/files/istrans/ +; https://jrsoftware.org/files/istrans/ ; -; Note:When translating this text, do not add periods (.) to the end of +; Note: When translating this text, do not add periods (.) to the end of ; messages that didn't have them already, because on those messages Inno ; Setup adds the periods automatically (appending a period would result in ; two periods being displayed). @@ -11,328 +11,375 @@ [LangOptions] ; The following three entries are very important. Be sure to read and ; understand the '[LangOptions] section' topic in the help file. - LanguageName=ئۇيغۇرچە LanguageID=$0480 LanguageCodePage=0 - -;If the language you are translating to requires special font faces or +RightToLeft=yes +; If the language you are translating to requires special font faces or ; sizes, uncomment any of the following entries and change them accordingly. -DialogFontName=ALKATIP -;DialogFontSize=12 -WelcomeFontName=ALKATIP -;WelcomeFontSize=18 -TitleFontName=ALKATIP -;TitleFontSize=35 -CopyrightFontName=ALKATIP -;CopyrightFontSize=11 +;DialogFontName= +;DialogFontSize=8 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;TitleFontName=Arial +;TitleFontSize=29 +;CopyrightFontName=Arial +;CopyrightFontSize=8 [Messages] -; ‫*** ‫Application ‫titles -SetupAppTitle=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى -SetupWindowTitle=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫- ‫%1 -UninstallAppTitle=‫‮‫‫‮‫ئۆچۈرۈش ‫يېتەكچىسى -UninstallAppFullTitle=‫‮‫‫‮‫%1 ‫ئۆچۈرۈش ‫يېتەكچىسى +; *** Application titles +SetupAppTitle=قاچىلاش +SetupWindowTitle=%1 - قاچىلاش +UninstallAppTitle=چىقىرىۋېتىش +UninstallAppFullTitle=%1 نى چىقىرىۋېتىش -; ‫*** ‫Misc. ‫common -InformationTitle=‫‮‫‫‮‫ئۇچۇر -ConfirmTitle=‫‮‫‫‮‫جەزىملەش -ErrorTitle=‫‮‫‫‮‫خاتالىق +; *** Misc. common +InformationTitle=ئۇچۇر +ConfirmTitle=جەزملەشتۈرۈش +ErrorTitle=خاتالىق -; ‫*** ‫SetupLdr ‫messages -SetupLdrStartupMessage=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫سىزنىڭ ‫كومپيۇتېرىڭىزغا ‫%1نى ‫قاچىلايدۇ. ‫راستتىنلا ‫داۋاملاشتۇرامسىز؟ -LdrCannotCreateTemp=‫‮‫‫‮‫ۋاقىتلىق ‫ھۆججەت ‫قۇرالمىدى. ‫قاچىلاش ‫توختىتىلدى -LdrCannotExecTemp=‫‮‫‫‮‫ۋاقىتلىق ‫ھۆججەت ‫قىسقۇچتىكى ‫ھۆججەت ‫ئىجرا ‫بولمىدى. ‫قاچىلاش ‫توختىتىلدى +; *** SetupLdr messages +SetupLdrStartupMessage=ھازىر %1 قاچىلىنىدۇ. داۋاملاشتۇرامسىز؟ +LdrCannotCreateTemp=ۋاقىتلىق ھۆججەت قۇرالمىدى. قاچىلاش توختىتىلدى +LdrCannotExecTemp=ۋاقىتلىق مۇندەرىجىدىكى ھۆججەت ئىجرا بولمىدى. قاچىلاش توختىتىلدى +HelpTextNote= -; ‫*** ‫Startup ‫error ‫messages ‫خاتالىق ‫كۆزنىكى -LastErrorMessage=‫‮‫‫‮‫%1.%n%n ‫خاتالىق ‫%2:%3 -SetupFileMissing=‫‮‫‫‮‫قاچىلاش ‫مۇندەرىجىسىدە ‫%1 ‫ھۆججىتى ‫يوق. ‫بۇ ‫مەسىلىنى ‫ھەل ‫قىلىڭ ‫ياكى ‫قايتىدىن ‫بىر ‫نۇسخا ‫كۆچۈرۈلمە ‫دېتالغا ‫ئېرىشىڭ. -SetupFileCorrupt=‫‮‫‫‮‫قاچىلاش ‫ھۆججىتى ‫بۇزۇلغان. ‫قايتىدىن ‫بىر ‫نۇسخا ‫كۆچۈرۈلمە ‫دېتالغا ‫ئېرىشىڭ. -SetupFileCorruptOrWrongVer=‫‮‫‫‮‫قاچىلاش ‫ھۆججىتى ‫بۇزۇلغان، ‫ياكى ‫بۇ ‫قاچىلاش ‫ھۆججىتى ‫مۇقىم ‫ئەمەس. ‫بۇ ‫مەسىلىنى ‫ھەل ‫قىلىڭ، ‫ياكى ‫قاچىلاش ‫ھۆججىتىنى ‫قايتىدىن ‫چۈشۈرۈڭ. -InvalidParameter=‫‮‫‫‮‫ئۈنۈمسىز ‫بۇيرۇق ‫پارامېتىرى:%n%n%1 -SetupAlreadyRunning=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫ئىجرا ‫بولۇۋاتىدۇ. -WindowsVersionNotSupported=‫‮‫‫‮‫دېتال ‫بۇ ‫كومپيۇتېرنىڭ ‫نەشرىنى ‫قوللىمايدۇ. -WindowsServicePackRequired=‫‮‫‫‮‫دېتال ‫%1 ‫Service ‫Pack ‫%2 ‫ياكى ‫ئۇنىڭدىن ‫يۇقىرى ‫نەشرىنى ‫تەلەپ ‫قىلىدۇ. -NotOnThisPlatform=‫‮‫‫‮‫دېتال ‫%1 ‫دە ‫ئىجرا ‫بولمايدۇ. -OnlyOnThisPlatform=‫‮‫‫‮‫دېتال ‫چوقۇم ‫%1دە ‫ئىجرا ‫بولىدۇ. -OnlyOnTheseArchitectures=‫‮‫‫‮‫دېتال ‫پەقەت ‫تۆۋەندىكى ‫CPU ‫بولغان ‫Windows ‫نەشرىگە ‫قاچىلىغىلى ‫بولىدۇ:%n%n%1 -MissingWOW64APIs=‫‮‫‫‮‫كومپيۇتېرىڭىزدا ‫Windows ‫نىڭ ‫64 ‫لىك ‫دېتاللىرى ‫ئىجرا ‫بولمايدۇ.Service ‫Pack ‫%1 ‫ئارقىلىق ‫مەسىلىڭىزنى ‫ھەل ‫قىلىڭ. -WinVersionTooLowError=‫‮‫‫‮‫دېتال ‫%2 ‫نەشرىدىن ‫يۇقىرى ‫بولغان ‫%1 ‫نى ‫تەلەپ ‫قىلىدۇ. -WinVersionTooHighError=‫‮‫‫‮‫دېتال ‫%2 ‫نەشرى ‫ياكى ‫%1 ‫دىن ‫يۇقىرى ‫نەشىرىدە ‫ئىجرا ‫بولىدۇ. -AdminPrivilegesRequired=‫‮‫‫‮‫باشقۇرغۇچىلىق ‫سالاھىيتىدە ‫كىرگەندىن ‫كېيىن ‫ئاندىن ‫بۇ ‫دېتالنى ‫قاچىلالايسىز. -PowerUserPrivilegesRequired=‫‮‫‫‮‫باشقۇرغۇچىلىق ‫سالاھىيتىدە ‫ياكى ‫ئۇنىڭدىن ‫يۇقىرى ‫سالاھىيەتتە ‫كىرگەندىن ‫كېيىن ‫ئاندىن ‫بۇ ‫دېتالنى ‫قاچىلالايسىز. -SetupAppRunningError=‫‮‫‫‮‫دېتال ‫%1 ‫تېخى ‫ئىجرا ‫بولۇۋېتىپتۇ.%n%n ‫بارلىق ‫ئېچىلغان ‫كۆزنەكلەرنى ‫تاقىۋېتىڭ، ‫ئاندىن ‫"مۇقىملاش" ‫نى ‫چېكىپ ‫داۋاملاشتۇرۇڭ، ‫ياكى ‫"قالدۇرۇش" ‫نى ‫چېكىپ ‫چېكىنىڭ. -UninstallAppRunningError=‫‮‫‫‮‫دېتال ‫%1 ‫تېخى ‫ئىجرا ‫بولۇۋېتىپتۇ.%n%n ‫بارلىق ‫ئېچىلغان ‫كۆزنەكلەرنى ‫تاقىۋېتىڭ، ‫ئاندىن ‫"مۇقىملاش" ‫نى ‫چېكىپ ‫داۋاملاشتۇرۇڭ، ‫ياكى ‫"قالدۇرۇش" ‫نى ‫چېكىپ ‫چېكىنىڭ. +; *** Startup error messages +LastErrorMessage=%1.%n%nخاتالىق %2: %3 +SetupFileMissing=قاچىلاش مۇندەرىجىسىدە %1 ھۆججىتى يوق. مەسىلىنى تۈزۈتۈڭ ياكى پىروگراممىنىڭ يېڭى نۇسخىسىغا ئېرىشىڭ. +SetupFileCorrupt=قاچىلاش ھۆججەتلىرى بۇزۇلغان. پىروگراممىنىڭ يېڭى نۇسخىسىغا ئېرىشىڭ. +SetupFileCorruptOrWrongVer=قاچىلاش ھۆججەتلىرى بۇزۇلغان ياكى بۇ نەشرى بىلەن ماسلاشمايدۇ. مەسىلىنى تۈزۈتۈڭ ياكى پىروگراممىنىڭ يېڭى نۇسخىسىغا ئېرىشىڭ. +InvalidParameter=بۇيرۇق قۇرىدا ئىناۋەتسىز پارامېتىر بار:%n%n%1 +SetupAlreadyRunning=قاچىلاش پىروگراممىسى ئىجرا بولۇۋاتىدۇ. +WindowsVersionNotSupported=بۇ پىروگرامما كومپيۇتېرىڭىزدا ئىجرا بولۇۋاتقان Windows نەشرىنى قوللىمايدۇ. +WindowsServicePackRequired=بۇ پىروگرامما %1 مۇلازىمەت بولىقى %2 ياكى يېڭىسىنى تەلەپ قىلىدۇ. +NotOnThisPlatform=بۇ پىروگرامما %1 دا ئىجرا بولمايدۇ. +OnlyOnThisPlatform=بۇ پىروگرامما چوقۇم %1 دا ئىجرا قىلىنىشى كېرەك. +OnlyOnTheseArchitectures=بۇ پىروگراممىنى پەقەت تۆۋەندىكى بىر تەرەپ قىلغۇچ قۇرۇلمىسى ئۈچۈن لايىھەلەنگەن Windows نەشرىگە قاچىلاشقا بولىدۇ:%n%n%1 +WinVersionTooLowError=بۇ پىروگرامما %1 نەشرى %2 ياكى يېڭىسىنى تەلەپ قىلىدۇ. +WinVersionTooHighError=بۇ پىروگرامما %1 نەشرى %2 ياكى يېڭىسىغا قاچىلانمايدۇ. +AdminPrivilegesRequired=بۇ پىروگراممىنى قاچىلىغاندا چوقۇم باشقۇرغۇچى سالاھىيىتىدە كىرىشىڭىز كېرەك. +PowerUserPrivilegesRequired=بۇ پىروگراممىنى قاچىلىغاندا چوقۇم باشقۇرغۇچى ياكى ھوقۇقلۇق ئىشلەتكۈچىلەر گۇرۇپپىسىنىڭ ئەزاسى سالاھىيىتىدە كىرىشىڭىز كېرەك. +SetupAppRunningError=قاچىلاش پىروگراممىسى %1 نىڭ ئىجرا بولۇۋاتقانلىقىنى بايقىدى.%n%nئۇنىڭ ھەممە جەريانلىرىنى تاقاڭ ھەمدە «ماقۇل» نى چېكىپ داۋاملاشتۇرۇڭ. ياكى «ئىناۋەتسىز» نى چېكىپ چېكىنىڭ. +UninstallAppRunningError=چىقىرىۋېتىش پىروگراممىسى %1 نىڭ ئىجرا بولۇۋاتقانلىقىنى بايقىدى.%n%nئۇنىڭ ھەممە جەريانلىرىنى تاقاڭ ھەمدە «ماقۇل» نى چېكىپ داۋاملاشتۇرۇڭ. ياكى «ئىناۋەتسىز» نى چېكىپ چېكىنىڭ. -; ‫*** ‫Misc. ‫errors -ErrorCreatingDir=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى"%1" -ErrorTooManyFilesInDir=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ"%1"نىڭ ‫ئىچىدە ‫ھۆججەت ‫بەك ‫كۆپكەن، ‫ئىچىگە ‫ھۆججەت ‫قۇرغىلى ‫بولمىدى +; *** Startup questions +PrivilegesRequiredOverrideTitle=قاچىلاش پىروگراممىسىنىڭ قاچىلاش ھالىتىنى تاللاش +PrivilegesRequiredOverrideInstruction=قاچىلاش ھالىتىنى تاللاش +PrivilegesRequiredOverrideText1=%1 نى بارلىق ئىشلەتكۈچىلەر (باشقۇرغۇچىلىق ھوقۇقى تەلەپ قىلىدۇ) ئۈچۈن ياكى سىز ئۈچۈنلا قاچىلاشقا بولىدۇ. +PrivilegesRequiredOverrideText2=%1 نى سىز ئۈچۈنلا ياكى بارلىق ئىشلەتكۈچىلەر (باشقۇرغۇچىلىق ھوقۇقى تەلەپ قىلىدۇ) ئۈچۈن قاچىلاشقا بولىدۇ. +PrivilegesRequiredOverrideAllUsers=بارلىق ئىشلەتكۈچىلەرگە قاچىلاش(&A) +PrivilegesRequiredOverrideAllUsersRecommended=بارلىق ئىشلەتكۈچىلەرگە قاچىلاش(&A) (تەۋسىيە) +PrivilegesRequiredOverrideCurrentUser=پەقەت مەن ئۈچۈنلا قاچىلاش(&M) +PrivilegesRequiredOverrideCurrentUserRecommended=پەقەت مەن ئۈچۈنلا قاچىلاش(&M) (تەۋسىيە) -; ‫*** ‫Setup ‫common ‫messages -ExitSetupTitle=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسىدىن ‫چېكىنىش -ExitSetupMessage=‫‮‫‫‮‫قاچىلاش ‫تاماملانمىدى. ‫ئەگەر ‫ھازىر ‫چېكىنسىڭىز، ‫دېتال ‫قاچىلانمايدۇ.%n%nسىز ‫كېلەر ‫قېتىمدا ‫قاچىلاش ‫يېتەكچىسىنى ‫قايتا ‫قوزغىتىپ ‫قاچىلاشنى ‫تاماملىسىڭىز ‫بولىدۇ.%n%nقاچىلاش ‫يېتەكچىسىدىن ‫راستتىنلا ‫چېكىنەمسىز؟ -AboutSetupMenuItem=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫ھەققىدە(&A)… -AboutSetupTitle=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫ھەققىدە -AboutSetupMessage=‫‮‫‫‮‫%1 ‫نەشرى ‫%2%n%3%n%n%1 ‫تور ‫بېكىتى:%n%4 -AboutSetupNote=‫‮‫‫‮‫ -TranslatorNote=‫‮‫‫‮‫ +; *** Misc. errors +ErrorCreatingDir=قاچىلاش پىروگراممىسى «%1» مۇندەرىجىسىنى قۇرالمىدى +ErrorTooManyFilesInDir=«%1» مۇندەرىجىسىگە ھۆججەت قۇرالمىدى، چۈنكى ئۇنىڭدا بەك كۆپ ھۆججەت بار -; ‫*** ‫Buttons ‫كۇنۇپكىلار -ButtonBack=<ئالدىنقى قەدەم(&B) -ButtonNext=كېيىنكى قەدەم(&N)> +; *** Setup common messages +ExitSetupTitle=قاچىلاشتىن چېكىنىش +ExitSetupMessage=قاچىلاش تاماملانمىدى. ئەگەر ھازىر چېكىنسىڭىز، پىروگرامما قاچىلانمايدۇ.%n%nقاچىلاشنى تاماملاش ئۈچۈن، كېلەر قېتىم قاچىلاش پىروگراممىسىنى قايتا ئىجرا قىلسىڭىز بولىدۇ.%n%nقاچىلاشتىن چېكىنەمسىز؟ +AboutSetupMenuItem=قاچىلاش پىروگراممىسى ھەققىدە(&A)... +AboutSetupTitle=قاچىلاش پىروگراممىسى ھەققىدە +AboutSetupMessage=%1 نەشرى %2%n%3%n%n%1 باش بەت:%n%4 +AboutSetupNote= +TranslatorNote=Uyghur translation by Irshat Ghalip (uqkun09@msn.cn) + +; *** Buttons +ButtonBack=< قايتىش(&B) +ButtonNext=كېيىنكى(&N) > ButtonInstall=قاچىلاش(&I) -ButtonOK=جەزىملەش +ButtonOK=ماقۇل ButtonCancel=ئىناۋەتسىز ButtonYes=ھەئە(&Y) -ButtonYesToAll=ھەممىنى تاللاش(&A) +ButtonYesToAll=ھەممىگە ھەئە(&A) ButtonNo=ياق(&N) -ButtonNoToAll=ھەممىنى قالدۇرۇش(&O) +ButtonNoToAll=ھەممىگە ياق(&O) ButtonFinish=تامام(&F) -ButtonBrowse=…كۆرۈش(&B) -ButtonWizardBrowse=…كۆرۈش(&R) -ButtonNewFolder=ھۆججەت قىسقۇچ قۇرۇش(&M) +ButtonBrowse=كۆرۈش(&B)... +ButtonWizardBrowse=كۆرۈش(&R)... +ButtonNewFolder=يېڭى قىسقۇچ قۇرۇش(&M) -; ‫*** ‫"Select ‫Language" ‫dialog ‫messages -SelectLanguageTitle=‫‮‫‫‮‫تىل ‫تاللاڭ -SelectLanguageLabel=‫‮‫‫‮‫قاچىلاش ‫جەريانىدا ‫ئىشلىتىدىغان ‫تىلنى ‫تاللاڭ: +; *** "Select Language" dialog messages +SelectLanguageTitle=قاچىلاش تىلىنى تاللاش +SelectLanguageLabel=قاچىلاش جەريانىدا ئىشلىتىدىغان تىلنى تاللاڭ. -; ‫*** ‫Common ‫wizard ‫text -ClickNext=‫‮‫‫‮‫"كېيىنكى ‫قەدەم"نى ‫چېكىپ ‫داۋاملاشتۇرۇڭ ‫ياكى ‫"ئىناۋەتسىز"نى ‫چېكىپ ‫قاچىلاش ‫يېتەكچىسىدىن ‫چېكىنىڭ. -BeveledLabel=‫‮‫‫‮‫ -BrowseDialogTitle=‫‮‫‫‮‫تاللانغان ‫ھۆججەت ‫قىسقۇچنى ‫كۆرۈش -BrowseDialogLabel=‫‮‫‫‮‫تۆۋەندىكى ‫تىزىملىكتىن ‫ھۆججەت ‫قىسقۇچتىن ‫بىرنى ‫تاللاڭ ‫ھەمدە ‫"جەزىملەش"نى ‫چېكىڭ. -NewFolderName=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ ‫قۇرۇش +; *** Common wizard text +ClickNext=«كېيىنكى» نى چېكىپ داۋاملاشتۇرۇڭ ياكى «ئىناۋەتسىز» نى چېكىپ قاچىلاشتىن چېكىنىڭ. +BeveledLabel= +BrowseDialogTitle=قىسقۇچ كۆرۈش +BrowseDialogLabel=تۆۋەندىكى تىزىملىكتىن قىسقۇچ تاللاڭ ھەمدە «ماقۇل» نى چېكىڭ. +NewFolderName=يېڭى قىسقۇچ -; ‫*** ‫"Welcome" ‫wizard ‫page -WelcomeLabel1=‫‮‫‫‮‫[name]نىڭ ‫قاچىلاش ‫يېتەكچىسىنى ‫ئىشلىتىشىڭىزنى ‫قارشى ‫ئالىمىز -WelcomeLabel2=‫‮‫‫‮‫مەزكۇر ‫قاچىلاش ‫يېتەكچىسى ‫سىزنىڭ ‫كومپيۇتېرىڭىزغا ‫[name/ver]نى ‫قاچىلىماقچى.%n%nمەشغۇلاتنى ‫داۋاملاشتۇرۇشتىن ‫ئىلگىرى ‫باشقا ‫بارلىق ‫دېتاللارنى ‫ئۆچۈرۈۋېتىشىڭىزنى ‫تەۋسىيە ‫قىلىمىز. +; *** "Welcome" wizard page +WelcomeLabel1=[name] نى قاچىلاش يېتەكچىسىگە خۇش كېلىپسىز +WelcomeLabel2=كومپيۇتېرىڭىزغا [name/ver] نى قاچىلايدۇ.%n%nداۋاملاشتۇرۇشتىن ئىلگىرى باشقا بارلىق دېتاللارنى تاقاش تەۋسىيە قىلىنىدۇ. -; ‫*** ‫"Password" ‫wizard ‫page -WizardPassword=‫‮‫‫‮‫پارول -PasswordLabel1=‫‮‫‫‮‫مەزكۇر ‫دېتال ‫پارول ‫بىلەن ‫قوغدالغان. -PasswordLabel3=‫‮‫‫‮‫پارولنى ‫كىرگۈزۈڭ ‫ھەمدە ‫"كېيىنكى ‫قەدەم"نى ‫چېكىڭ. ‫پارول ‫چوڭ-كىچىك ‫ھەرپنى ‫پەرقلەندۈرىدۇ. +; *** "Password" wizard page +WizardPassword=پارول +PasswordLabel1=بۇ قاچىلاش پارول بىلەن قوغدالغان. +PasswordLabel3=پارولنى كىرگۈزۈڭ ھەمدە «كېيىنكى» نى چېكىپ داۋاملاشتۇرۇڭ. پارول چوڭ-كىچىك ھەرپنى پەرقلەندۈرىدۇ. PasswordEditLabel=پارول(&P): -IncorrectPassword=‫‮‫‫‮‫كىرگۈزگەن ‫پارولىڭىز ‫توغرا ‫بولمىدى. ‫قايتا ‫سىناڭ. +IncorrectPassword=كىرگۈزگەن پارولىڭىز خاتا. قايتا سىناپ بېقىڭ. -; ‫*** ‫"License ‫Agreement" ‫wizard ‫page -WizardLicense=‫‮‫‫‮‫ئىجازەت ‫كېلىشىمنامىسى -LicenseLabel=‫‮‫‫‮‫تۆۋەندىكى ‫ئۇچۇرلارنى ‫ئوقۇڭ، ‫ئاندىن ‫كېيىنكى ‫قەدەمگە ‫ئۆتۈڭ. -LicenseLabel3=‫‮‫‫‮‫تۆۋەندىكى ‫ئىجازەت ‫كېلىشىمنامىسىنى ‫ئوقۇڭ. ‫سىز ‫كېلىشىمنامىدىكى ‫ماددىلارغا ‫قوشۇلغاندىلا، ‫قاچىلاشنى ‫داۋاملاشتۇرالايسىز. +; *** "License Agreement" wizard page +WizardLicense=ئىجازەت كېلىشىمى +LicenseLabel=داۋاملاشتۇرۇشتىن ئىلگىرى تۆۋەندىكى مۇھىم ئۇچۇرلارنى ئوقۇڭ. +LicenseLabel3=تۆۋەندىكى ئىجازەت كېلىشىمىنى ئوقۇڭ. قاچىلاشنى داۋاملاشتۇرۇشتىن ئىلگىرى چوقۇم بۇ كېلىشىمنىڭ ماددىلىرىغا قوشۇلۇشىڭىز كېرەك. LicenseAccepted=كېلىشىمگە قوشۇلىمەن(&A) LicenseNotAccepted=كېلىشىمگە قوشۇلمايمەن(&D) -; ‫*** ‫"Information" ‫wizard ‫pages +; *** "Information" wizard pages WizardInfoBefore=ئۇچۇر -InfoBeforeLabel=‫‮‫‫‮‫تۆۋەندىكى ‫ئۇچۇرلارنى ‫ئوقۇپ، ‫كېيىنكى ‫قەدەمگە ‫ئۆتۈڭ. -InfoBeforeClickLabel=‫‮‫‫‮‫قاچىلاشنى ‫داۋاملاشتۇرۇشقا ‫تەييارلىنىپ ‫بولۇپ، ‫"كېيىنكى ‫قەدەم"نى ‫چېكىڭ. -WizardInfoAfter=‫‮‫‫‮‫ئۇچۇر -InfoAfterLabel=‫‮‫‫‮‫تۆۋەندىكى ‫ئۇچۇرلارنى ‫ئوقۇپ، ‫كېيىنكى ‫قەدەمگە ‫ئۆتۈڭ. -InfoAfterClickLabel=‫‮‫‫‮‫قاچىلاشنى ‫داۋاملاشتۇرۇشقا ‫تەييارلىنىپ ‫بولۇپ، ‫"كېيىنكى ‫قەدەم"نى ‫چېكىڭ. +InfoBeforeLabel=داۋاملاشتۇرۇشتىن ئىلگىرى تۆۋەندىكى مۇھىم ئۇچۇرلارنى ئوقۇڭ. +InfoBeforeClickLabel=قاچىلاشنى داۋاملاشتۇرۇشقا تەييارلانغاندا، «كېيىنكى» نى چېكىڭ. +WizardInfoAfter=ئۇچۇر +InfoAfterLabel=داۋاملاشتۇرۇشتىن ئىلگىرى تۆۋەندىكى مۇھىم ئۇچۇرلارنى ئوقۇڭ. +InfoAfterClickLabel=قاچىلاشنى داۋاملاشتۇرۇشقا تەييارلانغاندا، «كېيىنكى» نى چېكىڭ. -; ‫*** ‫"User ‫Information" ‫wizard ‫page -WizardUserInfo=‫‮‫‫‮‫ئابۇنت ‫ئۇچۇرى -UserInfoDesc=‫‮‫‫‮‫ئۇچۇرىڭىزنى ‫تولدۇرۇڭ -UserInfoName=ئابۇنت نامى(&U): -UserInfoOrg=ئورگان نامى(&O): +; *** "User Information" wizard page +WizardUserInfo=ئىشلەتكۈچى ئۇچۇرى +UserInfoDesc=ئۇچۇرىڭىزنى كىرگۈزۈڭ. +UserInfoName=ئىشلەتكۈچى نامى(&U): +UserInfoOrg=ئىدارە(&O): UserInfoSerial=تەرتىپ نومۇرى(&S): -UserInfoNameRequired=‫‮‫‫‮‫ئابۇنت ‫نامىنى ‫چوقۇم ‫تولدۇرىسىز +UserInfoNameRequired=نامىنى كىرگۈزۈشىڭىز كېرەك. -; ‫*** ‫"Select ‫Destination ‫Location" ‫wizard ‫page -WizardSelectDir=‫‮‫‫‮‫قاچىلاش ‫ئورنىنى ‫تاللاڭ -SelectDirDesc=‫‮‫‫‮‫[name]نى ‫قەيەرگە ‫قاچىلايسىز؟ -SelectDirLabel3=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫[name]نى ‫تۆۋەندىكى ‫ھۆججەت ‫قىسقۇچقا ‫قاچىلايدۇ. -SelectDirBrowseLabel=‫‮‫‫‮‫"كېيىنكى ‫قەدەم"نى ‫چېكىپ ‫داۋاملاشتۇرۇڭ. ‫ئەگەر ‫باشقا ‫ھۆججەت ‫قىسقۇچنى ‫تاللىماقچى ‫بولسىڭىز ‫"كۆرۈش"نى ‫چېكىڭ. -DiskSpaceMBLabel=‫‮‫‫‮‫دىسكا ‫بوشلۇقىڭىزدا ‫كەم ‫دېگەندە ‫[mb]مېگابايت(MB) ‫بوشلۇقىڭىز ‫بولۇشى ‫كېرەك. -CannotInstallToNetworkDrive=‫‮‫‫‮‫تور ‫قوزغاتقۇچىغا ‫قاچىلىيالمايدۇ. -CannotInstallToUNCPath=‫‮‫‫‮‫UNCيولىغا ‫قاچىلىيالايدۇ. -InvalidPath=‫‮‫‫‮‫دىسكا ‫بەلگىسىنى ‫ئۆز ‫ئىچىگە ‫ئالغان ‫مۇكەممەل ‫يولنى ‫تولدۇرۇشىڭىز ‫كېرەك، ‫مەسىلەن:%n%nC:\دېتال%n%nياكى ‫تۆۋەندىكى ‫فورماتتىكى ‫UNCيولى:%n%n\\مۇلازىمىتېر ‫نامى\ئورتاقلاشقان ‫مۇندەرىجە ‫نامى -InvalidDrive=‫‮‫‫‮‫سىز ‫تاللىغان ‫قوزغاتقۇچ ‫ياكى ‫UNC ‫مەۋجۇت ‫ئەمەس ‫ياكى ‫زىيارەت ‫قىلغىلى ‫بولمايدۇ.باشقا ‫بىرىنى ‫تاللاڭ. -DiskSpaceWarningTitle=‫‮‫‫‮‫دىسكا ‫بوشلۇقى ‫يېتىشمىدى -DiskSpaceWarning=‫‮‫‫‮‫ئاز ‫دېگەندە%1(KB) ‫بوشلۇق ‫بولغاندا ‫ئاندىن ‫قاچىلغىلى ‫بولىدۇ، ‫نۆۋەتتىكى ‫دىسكىدا%2(KB) ‫ئىشلەتكىلى ‫بولىدىغان ‫بوشلۇق ‫بار.%n%n ‫داۋاملاشتۇرامسىز؟ -DirNameTooLong=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ ‫نامى ‫ياكى ‫يولى ‫بەك ‫ئۇزۇن ‫بولۇپ ‫كەتتى. -InvalidDirName=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ ‫نامى ‫ئۈنۈمسىز. -BadDirName32=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ ‫نامى ‫تۆۋەندىكى ‫ھەرپ-بەلگىلەرنى ‫ئۆز ‫ئىچىگە ‫ئالالمايدۇ:%n%n%1 -DirExistsTitle=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ ‫قۇرۇلۇپ ‫بولغان -DirExists=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ%n%n%1%n%nقۇرۇلۇپ ‫بولغان. ‫راستتىنلا ‫مۇشۇ ‫ھۆججەت ‫قىسقۇچقا ‫قاچىلامسىز؟ -DirDoesntExistTitle=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ ‫يوق -DirDoesntExist=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ%n%n%1%n%nيوق. ‫بۇ ‫ھۆججەت ‫قىسقۇچنى ‫قۇرامسىز؟ +; *** "Select Destination Location" wizard page +WizardSelectDir=قاچىلاش ئورنىنى تاللاش +SelectDirDesc=[name] نى قەيەرگە قاچىلاش كېرەك؟ +SelectDirLabel3=قاچىلاش پىروگراممىسى [name] نى تۆۋەندىكى قىسقۇچقا قاچىلايدۇ. +SelectDirBrowseLabel=«كېيىنكى» نى چېكىپ داۋاملاشتۇرۇڭ. باشقا قىسقۇچ تاللىماقچى بولسىڭىز، «كۆرۈش» نى چېكىڭ. +DiskSpaceGBLabel=كەم دېگەندە [gb]GB بىكار دىسكا بوشلۇقى تەلەپ قىلىنىدۇ. +DiskSpaceMBLabel=كەم دېگەندە [mb]MB بىكار دىسكا بوشلۇقى تەلەپ قىلىنىدۇ. +CannotInstallToNetworkDrive=قاچىلاش پىروگراممىسى تور دىسكىسىغا قاچىلىيالمايدۇ. +CannotInstallToUNCPath=قاچىلاش پىروگراممىسى UNC يولىغا قاچىلىيالمايدۇ. +InvalidPath=دىسكا بەلگىسى بار تولۇق يولىنى كىرگۈزۈشىڭىز كېرەك؛ مەسىلەن:%n%nC:\APP%n%nياكى تۆۋەندىكىدەك UNC يولى:%n%n\\server\share +InvalidDrive=سىز تاللىغان دىسكا ياكى UNC ئورتاقلىشىش يوق ياكى زىيارەت قىلغىلى بولمايدۇ. باشقا بىرىنى تاللاڭ. +DiskSpaceWarningTitle=دىسكا بوشلۇقى يېتىشمىدى +DiskSpaceWarning=قاچىلاش ئۈچۈن كەم دېگەندە %1KB بىكار بوشلۇق كېتىدۇ، بىراق تاللانغان دىسكىدا ئاران %2KB بىكار بوشلۇق بار.%n%nشۇنداقتىمۇ داۋاملاشتۇرامسىز؟ +DirNameTooLong=قىسقۇچ نامى ياكى يولى بەك ئۇزۇن. +InvalidDirName=قىسقۇچ نامى ئىناۋەتسىز. +BadDirName32=قىسقۇچ نامى تۆۋەندىكى ھەرپ-بەلگىلەرنى ئۆز ئىچىگە ئالالمايدۇ:%n%n%1 +DirExistsTitle=قىسقۇچ بار +DirExists=قىسقۇچ:%n%n%1%n%nباركەن. شۇنداقتىمۇ مۇشۇ قىسقۇچقا قاچىلامسىز؟ +DirDoesntExistTitle=قىسقۇچ يوق +DirDoesntExist=قىسقۇچ:%n%n%1%n%nيوقكەن. بۇ قىسقۇچنى قۇرامسىز؟ -; ‫*** ‫"Select ‫Components" ‫wizard ‫page -WizardSelectComponents=‫‮‫‫‮‫قىستۇرما ‫تاللاش -SelectComponentsDesc=‫‮‫‫‮‫قايسى ‫قىستۇرمىلارنى ‫قاچىلايسىز؟ -SelectComponentsLabel2=‫‮‫‫‮‫قاچىلىماقچى ‫بولغان ‫قىستۇرمىنى ‫تاللاڭ، ‫قاچىلىمايدىغان ‫قىستۇرمىلارنى ‫تازىلىۋىتىڭ. ‫تەييارلىنىپ ‫بولغاندىن ‫كېيىن ‫"كېيىنكى ‫قەدەم"نى ‫چېكىڭ. -FullInstallation=‫‮‫‫‮‫ھەممىنى ‫قاچىلاش -; ‫if ‫possible ‫don't ‫translate ‫'Compact' ‫as ‫'Minimal' ‫(I ‫mean ‫'Minimal' ‫in ‫your ‫language) -CompactInstallation=‫‮‫‫‮‫ئاددىي ‫قاچىلاش -CustomInstallation=‫‮‫‫‮‫ئۆزى ‫بەلگىلەپ ‫قاچىلاش -NoUninstallWarningTitle=‫‮‫‫‮‫قىستۇرما ‫بار -NoUninstallWarning=‫‮‫‫‮‫تۆۋەندىكى ‫سەپلىمىلەرنى ‫قاچىلاپ ‫بولۇپسىز:%n%n%1%n%n ‫تاللاشنى ‫بىكار ‫قىلىڭ.%n%n ‫داۋاملاشتۇرامسىز؟ -ComponentSize1=‫‮‫‫‮‫%1كىلوبايت(KB) -ComponentSize2=‫‮‫‫‮‫%1مېگابايت(MB) -ComponentsDiskSpaceMBLabel=‫‮‫‫‮‫بۇ ‫تۈرگە ‫ئەڭ ‫ئاز ‫بولغاندا ‫[mb](MB) ‫بوشلۇق ‫كېتىدۇ. +; *** "Select Components" wizard page +WizardSelectComponents=بىرىكمە تاللاش +SelectComponentsDesc=قايسى بىرىكمىلەرنى قاچىلاش كېرەك؟ +SelectComponentsLabel2=قاچىلايدىغان بىرىكمىلەرنى تاللاڭ؛ قاچىلىمايدىغان بىرىكمىلەرنى تاللىماڭ. داۋاملاشتۇرۇشقا تەييارلانغاندا «كېيىنكى» نى چېكىڭ. +FullInstallation=تولۇق قاچىلاش +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=ئىخچام قاچىلاش +CustomInstallation=ئىختىيارى قاچىلاش +NoUninstallWarningTitle=بىرىكمە بار +NoUninstallWarning=قاچىلاش پىروگراممىسى كومپيۇتېرىڭىزغا تۆۋەندىكى بىرىكمىلەرنىڭ قاچىلانغانلىقىنى بايقىدى:%n%n%1%n%nبۇ بىرىكمىلەرنى تاللىمىغاندا ئۇلارنى چىقىرىۋەتمەيدۇ.%n%nشۇنداقتىمۇ داۋاملاشتۇرامسىز؟ +ComponentSize1=%1KB +ComponentSize2=%1MB +ComponentsDiskSpaceGBLabel=نۆۋەتتىكى تاللاش كەم دېگەندە [gb]GB دىسكا بوشلۇقى تەلەپ قىلىدۇ. +ComponentsDiskSpaceMBLabel=نۆۋەتتىكى تاللاش كەم دېگەندە [mb]MB دىسكا بوشلۇقى تەلەپ قىلىدۇ. -; ‫*** ‫"Select ‫Additional ‫Tasks" ‫wizard ‫page -WizardSelectTasks=‫‮‫‫‮‫قوشۇمچە ‫ۋەزىپە ‫تاللاڭ -SelectTasksDesc=‫‮‫‫‮‫قايسى ‫قوشۇمچە ‫ۋەزىپىلەرنى ‫ئىجرا ‫قىلدۇرىسىز؟ -SelectTasksLabel2=‫‮‫‫‮‫[name]نى ‫قاچىلاۋاتقان ‫ۋاقىتتا ‫ئىجرا ‫قىلدۇرماقچى ‫بولغان ‫ۋەزىپىلەرنى ‫تاللاڭ، ‫ئاندىن ‫"كېيىنكى ‫قەدەم"نى ‫چېكىڭ. +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=قوشۇمچە ۋەزىپىلەرنى تاللاش +SelectTasksDesc=قايسى قوشۇمچە ۋەزىپىلەرنى قىلىش كېرەك؟ +SelectTasksLabel2=[name] نى قاچىلاۋاتقاندا قىلىدىغان ۋەزىپىلەرنى تاللاڭ ھەمدە «كېيىنكى» نى چېكىڭ. -; ‫*** ‫"Select ‫Start ‫Menu ‫Folder" ‫wizard ‫page -WizardSelectProgramGroup=‫‮‫‫‮‫باشلاش ‫تىزىملىكىدىكى ‫ھۆججەت ‫قىسقۇچنى ‫تاللاڭ -SelectStartMenuFolderDesc=‫‮‫‫‮‫دېتالنىڭ ‫قىسقا ‫يولىنى ‫قەيەرگە ‫قۇرىسىز؟ -SelectStartMenuFolderLabel3=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫تۆۋەندىكى ‫باشلاش ‫تىزىملىكىدىكى ‫ھۆججەت ‫قىسقۇچقا ‫دېتالنىڭ ‫قىسقا ‫يولىنى ‫قۇرىدۇ. -SelectStartMenuFolderBrowseLabel=‫‮‫‫‮‫"كېيىنكى ‫قەدەم"نى ‫چېكىپ ‫داۋاملاشتۇرۇڭ. ‫ئەگەر ‫باشقا ‫ھۆججەت ‫قىسقۇچنى ‫تاللىماقچى ‫بولسىڭىز ‫"كۆرۈش"نى ‫چېكىڭ. -MustEnterGroupName=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچنىڭ ‫نامىنى ‫چوقۇم ‫تولدۇرۇشىڭىز ‫كېرەك -GroupNameTooLong=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ ‫نامى ‫ياكى ‫يولى ‫بەك ‫ئۇزۇن ‫بولۇپ ‫كەتتى. -InvalidGroupName=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ ‫نامى ‫ئۈنۈمسىز. -BadGroupName=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ ‫نامى ‫تۆۋەندىكى ‫ھەرپ-بەلگىلەرنى ‫ئۆز ‫ئىچىگە ‫ئالالمايدۇ:%n%n%1 -NoProgramGroupCheck2=باشلاش تىزىملىكىگە ھۆججەت قىسقۇچ قۇرمايمەن(&D) +; *** "Select Start Menu Folder" wizard page +WizardSelectProgramGroup=باشلاش تىزىملىكىگە قىسقۇچ تاللاش +SelectStartMenuFolderDesc=پىروگراممىنىڭ قىسقا يولىنى قەيەرگە قۇرۇش كېرەك؟ +SelectStartMenuFolderLabel3=قاچىلاش پىروگراممىسى باشلاش تىزىملىكىدىكى تۆۋەندىكى قىسقۇچقا پىروگراممىنىڭ قىسقا يولىنى قۇرىدۇ. +SelectStartMenuFolderBrowseLabel=«كېيىنكى» نى چېكىپ داۋاملاشتۇرۇڭ. باشقا قىسقۇچ تاللىماقچى بولسىڭىز، «كۆرۈش» نى چېكىڭ. +MustEnterGroupName=قىسقۇچ نامىنى كىرگۈزۈشىڭىز كېرەك. +GroupNameTooLong=قىسقۇچ نامى ياكى يولى بەك ئۇزۇن. +InvalidGroupName=قىسقۇچ نامى ئىناۋەتسىز. +BadGroupName=قىسقۇچ نامى تۆۋەندىكى ھەرپ-بەلگىلەرنى ئۆز ئىچىگە ئالالمايدۇ:%n%n%1 +NoProgramGroupCheck2=باشلاش تىزىملىكىگە قىسقۇچ قۇرمايمەن(&D) -; ‫*** ‫"Ready ‫to ‫Install" ‫wizard ‫page -WizardReady=‫‮‫‫‮‫قاچىلاش ‫تاماملىنىشقا ‫تەييارلاندى -ReadyLabel1=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫تاماملىنىشقا ‫تەييارلاندى، ‫سىزنىڭ ‫كومپيۇتېرىڭىزغا ‫[name]نى ‫قاچىلاشنى ‫باشلايدۇ. -ReadyLabel2a=تەييارلىق پۈتكەن بولسا ‫‮‫‫‮‫"قاچىلاش"نى ‫چېكىپ ‫قاچىلاشنى ‫باشلاڭ. ‫ئەگەر ‫تەڭشەشنى ‫ئۆزگەرتمەكچى ‫ياكى ‫تەكشۈرمەكچى ‫بولسىڭىز ‫"ئالدىنقى ‫قەدەم"نى ‫چېكىڭ. -ReadyLabel2b=‫‮‫‫‮‫"قاچىلاش"نى ‫چېكىپ ‫قاچىلاشنى ‫باشلاڭ. -ReadyMemoUserInfo=‫‮‫‫‮‫ئابۇنت ‫ئۇچۇرى: -ReadyMemoDir=‫‮‫‫‮‫قاچىلاش ‫ئورنى: -ReadyMemoType=‫‮‫‫‮‫قاچىلاش ‫تىپى: -ReadyMemoComponents=‫‮‫‫‮‫تاللانغان ‫قىستۇرمىلار: -ReadyMemoGroup=‫‮‫‫‮‫باشلاش ‫تىزىملىكىدىكى ‫ھۆججەت ‫قىسقۇچ: -ReadyMemoTasks=‫‮‫‫‮‫قوشۇمچە ‫ۋەزىپە: +; *** "Ready to Install" wizard page +WizardReady=قاچىلاشقا تەييارلاندى +ReadyLabel1=قاچىلاش پىروگراممىسى كومپيۇتېرىڭىزغا [name] نى قاچىلاشقا تەييارلاندى. +ReadyLabel2a=قاچىلاشنى داۋاملاشتۇرۇش ئۈچۈن «قاچىلاش» نى چېكىڭ. تەڭشەكلەرنى تەكشۈرمەكچى ياكى ئۆزگەرتمەكچى بولسىڭىز «قايتىش» نى چېكىڭ. +ReadyLabel2b=قاچىلاشنى داۋاملاشتۇرۇش ئۈچۈن «قاچىلاش» نى چېكىڭ. +ReadyMemoUserInfo=ئىشلەتكۈچى ئۇچۇرى: +ReadyMemoDir=قاچىلاش ئورنى: +ReadyMemoType=قاچىلاش تىپى: +ReadyMemoComponents=تاللانغان بىرىكمىلەر: +ReadyMemoGroup=باشلاش تىزىملىكىدىكى قىسقۇچ: +ReadyMemoTasks=قوشۇمچە ۋەزىپىلەر: -; ‫*** ‫"Preparing ‫to ‫Install" ‫wizard ‫page -WizardPreparing=‫‮‫‫‮‫قاچىلاشقا ‫تەييارلاندى -PreparingDesc=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫سىزنىڭ ‫كومپيۇتېرىڭىزغا ‫[name]نى ‫قاچىلاشقا ‫تەييارلىنىۋاتىدۇ. -PreviousInstallNotCompleted=‫‮‫‫‮‫ئالدىنقى ‫قېتىملىق ‫دېتال ‫قاچىلاش/ئۆچۈرۈش ‫تاماملىنالمىدى. ‫سىز ‫كومپيۇتېرنى ‫قايتا ‫قوزغىتىپ ‫ئالدىنقى ‫قېتىملىق ‫قاچىلاشنى ‫تاماملىشىڭىز ‫كېرەك.%n%nكومپيۇتېر ‫قايتا ‫قوزغالغاندىن ‫كېيىن، ‫قاچىلاش ‫يېتەكچىسىنى ‫قايتا ‫ئىجرا ‫قىلىپ ‫[name]نى ‫قاچىلاڭ. -CannotContinue=‫‮‫‫‮‫قاچىلاش ‫داۋاملىشالمايدۇ. ‫"ئىناۋەتسىز"نى ‫چېكىپ ‫چېكىنىڭ. -ApplicationsFound=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫يېڭىلاشتا ‫ئىشلىتىدىغان ‫ھۆججەتنى ‫باشقا ‫دېتال ‫ئىشلىتىۋېتىپتۇ. ‫قاچىلاش ‫يېتەكچىسىنىڭ ‫بۇ ‫پىروگراممىلارنى ‫مەجبۇرىي ‫ئۆچۈرۋېتىشىگە ‫يول ‫قويىشىڭىز ‫كېرەك. -ApplicationsFound2=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫يېڭىلاشتا ‫ئىشلىتىدىغان ‫ھۆججەتنى ‫باشقا ‫دېتال ‫ئىشلىتىۋېتىپتۇ. ‫قاچىلاش ‫يېتەكچىسىنىڭ ‫بۇ ‫پىروگراممىلارنى ‫مەجبۇرىي ‫ئۆچۈرۋېتىشىگە ‫يول ‫قويىشىڭىز ‫كېرەك. ‫قاچىلاش ‫تۈگىگەندە ‫بۇ ‫پىروگراممىلارنى ‫قايتىدىن ‫قوزغىتىدۇ. -CloseApplications=دېتالنى ئاپتوماتىك ئۆچۈرسۇن(&A) -DontCloseApplications=دېتالنى ئاپتوماتىك ئۆچۈرمىسۇن(&D) -ErrorCloseApplications=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫بارلىق ‫پىروگراممىلارنى ‫ئاپتوماتىك ‫ئۆچۈرەلمىدى. ‫كېيىنكى ‫باسقۇچقا ‫ئۆتۈشتى ‫ئاۋۋال ‫بۇ ‫پىروگراممىلارنى ‫چوقۇم ‫ئۆچۈرۋېتىشىڭىز ‫كېرەك. +; *** TDownloadWizardPage wizard page and DownloadTemporaryFile +DownloadingLabel=قوشۇمچە ھۆججەتلەرنى چۈشۈرۈۋاتىدۇ... +ButtonStopDownload=چۈشۈرۈشنى توختىتىش(&S) +StopDownload=چۈشۈرۈشنى راستتىنلا توختىتامسىز؟ +ErrorDownloadAborted=چۈشۈرۈش توختىتىلدى +ErrorDownloadFailed=چۈشۈرەلمىدى: %1 %2 +ErrorDownloadSizeFailed=چوڭلۇقىغا ئېرىشەلمىدى: %1 %2 +ErrorFileHash1=ھۆججەت Hash نى تەكشۈرەلمىدى: %1 +ErrorFileHash2=ئىناۋەتسىز ھۆججەت Hash: كۈتكىنى %1، تېپىلغىنى %2 +ErrorProgress=ئىناۋەتسىز ئىلگىرىلەش: %1، جەمئىي: %2 +ErrorFileSize=ئىناۋەتسىز ھۆججەت چوڭلۇقى: كۈتكىنى %1، تېپىلغىنى %2 -; ‫*** ‫"Installing" ‫wizard ‫page -WizardInstalling=‫‮‫‫‮‫قاچىلاۋاتىدۇ -InstallingLabel=‫‮‫‫‮‫سەل ‫ساقلاڭ، ‫قاچىلاش ‫يېتەكچىسى ‫كومپيۇتېرىڭىزغا ‫[name]نى ‫قاچىلاۋاتىدۇ. +; *** "Preparing to Install" wizard page +WizardPreparing=قاچىلاشقا تەييارلىنىۋاتىدۇ +PreparingDesc=قاچىلاش پىروگراممىسى كومپيۇتېرىڭىزغا [name] نى قاچىلاشقا تەييارلىنىۋاتىدۇ. +PreviousInstallNotCompleted=ئالدىنقى پىروگراممىنى قاچىلاش ياكى چىقىرىۋېتىش تاماملانمىدى. قاچىلاشنى تاماملاش ئۈچۈن كومپيۇتېرىڭىزنى قايتا قوزغىتىشىڭىز كېرەك.%n%nكومپيۇتېرىڭىز قايتا قوزغالغاندىن كېيىن، قاچىلاش پىروگراممىسىنى قايتا ئىجرا قىلىپ [name] نى قاچىلاشنى تاماملاڭ. +CannotContinue=قاچىلاش پىروگراممىسىنى داۋاملاشتۇرغىلى بولمايدۇ. چېكىنىش ئۈچۈن «ئىناۋەتسىز» نى چېكىڭ. +ApplicationsFound=تۆۋەندىكى دېتاللار قاچىلاش پىروگراممىسى يېڭىلايدىغان ھۆججەتلەرنى ئىشلىتىۋاتىدۇ. قاچىلاش پىروگراممىسىنىڭ بۇ دېتاللارنى ئاپتوماتىك تاقىشىغا يول قويۇشىڭىز تەۋسىيە قىلىنىدۇ. +ApplicationsFound2=تۆۋەندىكى دېتاللار قاچىلاش پىروگراممىسى يېڭىلايدىغان ھۆججەتلەرنى ئىشلىتىۋاتىدۇ. قاچىلاش پىروگراممىسىنىڭ بۇ دېتاللارنى ئاپتوماتىك تاقىشىغا يول قويۇشىڭىز تەۋسىيە قىلىنىدۇ. قاچىلاش تاماملانغاندىن كېيىن، قاچىلاش پىروگراممىسى بۇ دېتاللارنى قايتا قوزغىتىشقا ئۇرۇنىدۇ. +CloseApplications=دېتاللارنى ئاپتوماتىك تاقاش(&A) +DontCloseApplications=دېتاللارنى تاقىماسلىق(&D) +ErrorCloseApplications=قاچىلاش پىروگراممىسى بارلىق دېتاللارنى ئاپتوماتىك تاقىيالمىدى. داۋاملاشتۇرۇشتىن بۇرۇن بۇ دېتاللارنى تاقاش تەۋسىيە قىلىنىدۇ. +PrepareToInstallNeedsRestart=قاچىلاش پىروگراممىسى كومپيۇتېرىڭىزنى قايتا قوزغىتىشى كېرەك. كومپيۇتېرىڭىز قايتا قوزغالغاندىن كېيىن، قاچىلاش پىروگراممىسىنى قايتا ئىجرا قىلىپ [name] نى قاچىلاشنى تاماملاڭ.%n%nھازىرلا قايتا قوزغىتامسىز؟ -; ‫*** ‫"Setup ‫Completed" ‫wizard ‫page -FinishedHeadingLabel=‫‮‫‫‮‫[name]نى ‫قاچىلاش ‫تامام -FinishedLabelNoIcons=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫كومپيۇتېرىڭىزغا ‫[name]نى ‫قاچىلاپ ‫بولدى. -FinishedLabel=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫كومپيۇتېرىڭىزغا ‫[name]نى ‫قاچىلاپ ‫بولدى. ‫سىز ‫قۇرىۋالغان ‫قىسقا ‫يول ‫ئارقىلىق ‫بۇ ‫دېتالنى ‫ئاچالايسىز. -ClickFinish=‫‮‫‫‮‫"تامام"نى ‫چېكىپ ‫قاچىلاشنى ‫تاماملاڭ. -FinishedRestartLabel=‫‮‫‫‮‫[name]نى ‫قاچىلاشنى ‫تاماملاش ‫ئۈچۈن، ‫قاچىلاش ‫يېتەكچىسى ‫كومپيۇتېرىڭىزنى ‫ ‫قايتا ‫قوزغىتىشى ‫كېرەك. ‫ھازىرلا ‫قايتا ‫قوزغىتامسىز؟ -FinishedRestartMessage=‫‮‫‫‮‫[name]نى ‫قاچىلاشنى ‫تاماملاش ‫ئۈچۈن، ‫قاچىلاش ‫يېتەكچىسى ‫كومپيۇتېرىڭىزنى ‫ ‫قايتا ‫قوزغىتىشى ‫كېرەك.%n%nھازىرلا ‫قايتا ‫قوزغىتامسىز؟ -ShowReadmeCheck=‫‮‫‫‮‫ھەئە، ‫تونۇشتۇرۇش ‫ھۆججىتىنى ‫ئوقۇيمەن +; *** "Installing" wizard page +WizardInstalling=قاچىلاۋاتىدۇ +InstallingLabel=قاچىلاش پىروگراممىسى كومپيۇتېرىڭىزغا [name] نى قاچىلاۋاتىدۇ، سەل ساقلاڭ. + +; *** "Setup Completed" wizard page +FinishedHeadingLabel=[name] نى قاچىلاش تامام +FinishedLabelNoIcons=قاچىلاش پىروگراممىسى كومپيۇتېرىڭىزغا [name] نى قاچىلاپ بولدى. +FinishedLabel=قاچىلاش پىروگراممىسى كومپيۇتېرىڭىزغا [name] نى قاچىلاپ بولدى. قاچىلانغان قىسقا يوللارنى تاللاش ئارقىلىق دېتالنى قوزغىتالايسىز. +ClickFinish=«تامام» نى چېكىپ قاچىلاش پىروگراممىسىدىن چېكىنىڭ. +FinishedRestartLabel=[name] نى قاچىلاشنى تاماملاش ئۈچۈن، قاچىلاش پىروگراممىسى كومپيۇتېرىڭىزنى قايتا قوزغىتىشى كېرەك. ھازىرلا قايتا قوزغىتامسىز؟ +FinishedRestartMessage=[name] نى قاچىلاشنى تاماملاش ئۈچۈن، قاچىلاش پىروگراممىسى كومپيۇتېرىڭىزنى قايتا قوزغىتىشى كېرەك.%n%nھازىرلا قايتا قوزغىتامسىز؟ +ShowReadmeCheck=ھەئە، چۈشەندۈرۈش ھۆججىتىنى ئوقۇيمەن YesRadio=ھەئە، كومپيۇتېرنى ھازىرلا قايتا قوزغىتىمەن(&Y) -NoRadio=ياق، سەل تۇرۇپ ئۆزۈم قايتا قوزغىتىمەن(&N) -; ‫used ‫for ‫example ‫as ‫'Run ‫MyProg.exe' -RunEntryExec=‫‮‫‫‮‫%1نى ‫ئىجرا ‫قىلىش -; ‫used ‫for ‫example ‫as ‫'View ‫Readme.txt' -RunEntryShellExec=‫‮‫‫‮‫تەكشۈرۈۋاتىدۇ ‫%1 +NoRadio=ياق، كومپيۇتېرنى سەل تۇرۇپ قايتا قوزغىتىمەن(&N) +; used for example as 'Run MyProg.exe' +RunEntryExec=%1 نى ئىجرا قىلىش +; used for example as 'View Readme.txt' +RunEntryShellExec=%1 نى كۆرۈش -; ‫*** ‫"Setup ‫Needs ‫the ‫Next ‫Disk" ‫stuff -ChangeDiskTitle=‫‮‫‫‮‫تاللانغان ‫دىسكىنى ‫ئۆزگەرتىڭ -SelectDiskLabel2=‫‮‫‫‮‫دىسكىنى ‫سېلىپ%1 ‫"مۇقىملاش" ‫نى ‫چېكىڭ.%n%n ‫ئەگەر ‫دىسكىدا ‫تۆۋەندىكى ‫ھۆججەت ‫قىسقۇچ ‫يوق ‫بولسا، ‫"كۆرۈش" ‫دىن ‫تاللاڭ. -PathLabel=مۇندەرىجە(&P): -FileNotInDir2=‫‮‫‫‮‫ھۆججەت"%1" ‫"%2"نىڭ ‫ئىچىدە ‫يوقكەن. ‫توغرا ‫بولغان ‫دىسكىنى ‫سېلىڭ ‫ياكى ‫توغرا ‫بولغان ‫ھۆججەت ‫قىسقۇچنى ‫تاللاڭ. -SelectDirectoryLabel=‫‮‫‫‮‫بىر ‫دىسكىنى ‫تاللاڭ +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=قاچىلاش پىروگراممىسىغا كېيىنكى دىسكا لازىم +SelectDiskLabel2=%1 دىسكىنى سېلىپ، «ماقۇل» نى چېكىڭ.%n%nئەگەر بۇ دىسكىدىكى ھۆججەتلەرنى تۆۋەندىكى قىسقۇچلاردىن باشقىسىدا تاپقىلى بولسا، توغرا يولىنى كىرگۈزۈڭ ياكى «كۆرۈش» نى چېكىڭ. +PathLabel=يولى(&P): +FileNotInDir2=«%1» ھۆججىتى «%2» دىن تېپىلمىدى. توغرا دىسكىنى سېلىڭ ياكى باشقا قىسقۇچنى تاللاڭ. +SelectDirectoryLabel=كېيىنكى دىسكىنىڭ ئورنىنى بەلگىلەڭ. -; ‫*** ‫Installation ‫phase ‫messages -SetupAborted=‫‮‫‫‮‫قاچىلاش ‫تولۇق ‫تاماملانمىدى.%n%nتۆۋەندىكى ‫مەسىلىلەرنى ‫ھەل ‫قىلىپ ‫قايتا ‫قاچىلاڭ. -EntryAbortRetryIgnore=‫‮‫‫‮‫"قايتا ‫سىناش" ‫نى ‫چېكىپ ‫قايتا ‫سىناڭ، ‫"ئۆتكۈزۋېتىش" ‫نى ‫چېكىپ ‫داۋاملاشتۇرۇڭ، ‫"ئاخىرلاشتۇرۇش" ‫نى ‫چېكىپ ‫قاچىلاشنى ‫ئاخىرلاشتۇرۇڭ. +; *** Installation phase messages +SetupAborted=قاچىلاش پىروگراممىسى تاماملانمىدى.%n%nمەسىلىنى تۈزىتىپ، قاچىلاش پىروگراممىسىنى قايتا ئىجرا قىلىڭ. +AbortRetryIgnoreSelectAction=مەشغۇلات تاللاش +AbortRetryIgnoreRetry=قايتا سىناش(&T) +AbortRetryIgnoreIgnore=خاتالىققا پەرۋا قىلماي داۋاملاشتۇرۇش(&I) +AbortRetryIgnoreCancel=قاچىلاشنى بىكار قىلىش -; ‫*** ‫Installation ‫status ‫messages -StatusClosingApplications=‫‮‫‫‮‫دېتالنى ‫ئۆچۈرۈۋاتىدۇ… -StatusCreateDirs=‫‮‫‫‮‫ھۆججەت ‫قىسقۇچ ‫قۇرۇۋاتىدۇ… -StatusExtractFiles=‫‮‫‫‮‫ھۆججەتنى ‫چىقىرىۋاتىدۇ… -StatusCreateIcons=‫‮‫‫‮‫قىسقا ‫يولىنى ‫قۇرۇۋاتىدۇ… -StatusCreateIniEntries=‫‮‫‫‮‫INI ‫كۆرسەتكۈچىنى ‫قۇرۇۋاتىدۇ… -StatusCreateRegistryEntries=‫‮‫‫‮‫تىزىملاش ‫جەدۋەل ‫كۆرسەتكۈچىنى ‫قۇرۇۋاتىدۇ… -StatusRegisterFiles=‫‮‫‫‮‫تىزىملاش ‫جەدۋەل ‫تۈرىنى ‫قۇرۇۋاتىدۇ… -StatusSavingUninstall=‫‮‫‫‮‫ئۆچۈرۈش ‫ئۇچۇرىنى ‫ساقلاۋاتىدۇ… -StatusRunProgram=‫‮‫‫‮‫قاچىلاشنى ‫تاماملاۋاتىدۇ… -StatusRestartingApplications=‫‮‫‫‮‫دېتالنى ‫قايتا ‫قوزغىتىۋاتىدۇ… -StatusRollback=‫‮‫‫‮‫ئۆزگەرتىشنى ‫بىكار ‫قىلىۋاتىدۇ… +; *** Installation status messages +StatusClosingApplications=دېتاللارنى تاقاۋاتىدۇ... +StatusCreateDirs=مۇندەرىجىلەرنى قۇرۇۋاتىدۇ... +StatusExtractFiles=ھۆججەتلەرنى يېيىۋاتىدۇ... +StatusCreateIcons=قىسقا يوللىرىنى قۇرۇۋاتىدۇ... +StatusCreateIniEntries=INI مەزمۇنلىرىنى قۇرۇۋاتىدۇ... +StatusCreateRegistryEntries=تىزىملاش جەدۋىلىنى قۇرۇۋاتىدۇ... +StatusRegisterFiles=ھۆججەتلەرنى تىزىملاۋاتىدۇ... +StatusSavingUninstall=چىقىرىۋېتىش ئۇچۇرىنى ساقلاۋاتىدۇ... +StatusRunProgram=قاچىلاشنى تاماملاۋاتىدۇ... +StatusRestartingApplications=دېتاللارنى قايتا قوزغىتىۋاتىدۇ... +StatusRollback=ئۆزگەرتىشلەرنى قايتۇرۇۋاتىدۇ... -; ‫*** ‫Misc. ‫errors -ErrorInternal2=‫‮‫‫‮‫ئىچكى ‫خاتالىق:%1 -ErrorFunctionFailedNoCode=‫‮‫‫‮‫%1 ‫مەغلۇپ ‫بولدى -ErrorFunctionFailed=‫‮‫‫‮‫%1 ‫مەغلۇپ ‫بولدى، ‫خاتالىق ‫نومۇرى ‫%2 -ErrorFunctionFailedWithMessage=‫‮‫‫‮‫%1مەغلۇپ ‫بولدى، ‫خاتالىق ‫نومۇرى ‫%2.%n%3 -ErrorExecutingProgram=‫‮‫‫‮‫ئىجرا ‫بولمىغان ‫دېتال:%n%1 +; *** Misc. errors +ErrorInternal2=ئىچكى خاتالىق: %1 +ErrorFunctionFailedNoCode=%1 مەغلۇپ بولدى +ErrorFunctionFailed=%1 مەغلۇپ بولدى؛ كودى %2 +ErrorFunctionFailedWithMessage=%1 مەغلۇپ بولدى؛ كودى %2.%n%3 +ErrorExecutingProgram=ئىجرا قىلالمىغان ھۆججەت:%n%1 -; ‫*** ‫Registry ‫errors -ErrorRegOpenKey=‫‮‫‫‮‫تىزىملاش ‫جەدۋىلىنى ‫ئاچقاندا ‫يۈز ‫بەرگەن ‫خاتالىق:%n%1\%2 -ErrorRegCreateKey=‫‮‫‫‮‫تىزىملاش ‫جەدۋىلىنى ‫قۇرغاندا ‫يۈز ‫بەرگەن ‫خاتالىق:%n%1\%2 -ErrorRegWriteKey=‫‮‫‫‮‫تىزىملاش ‫جەدۋىلىنى ‫يازغاندا ‫يۈز ‫بەرگەن ‫خاتالىق:%n%1\%2 +; *** Registry errors +ErrorRegOpenKey=تىزىملاش جەدۋىلىنى ئېچىش خاتالىقى:%n%1\%2 +ErrorRegCreateKey=تىزىملاش جەدۋىلىنى قۇرۇش خاتالىقى:%n%1\%2 +ErrorRegWriteKey=تىزىملاش جەدۋىلىنى يېزىش خاتالىقى:%n%1\%2 -; ‫*** ‫INI ‫errors -ErrorIniEntry=‫‮‫‫‮‫ھۆججەت"%1"نىڭINI ‫تۈرىنى ‫قۇرۇشتا ‫خاتالىق ‫كۆرۈلدى. +; *** INI errors +ErrorIniEntry=«%1» ھۆججىتىگە INI مەزمۇنىنى قۇرۇش خاتالىقى. -; ‫*** ‫File ‫copying ‫errors -FileAbortRetryIgnore=‫‮‫‫‮‫"قايتا ‫سىناش" ‫نى ‫چېكىپ ‫قايتا ‫سىناڭ، ‫"ئۆتكۈزۋېتىش" ‫نى ‫چېكىپ ‫داۋاملاشتۇرۇڭ(تەۋسىيە ‫قىلىنمايدۇ)، ‫"ئاخىرلاشتۇرۇش" ‫نى ‫چېكىپ ‫قاچىلاشنى ‫ئاخىرلاشتۇرۇڭ. -FileAbortRetryIgnore2=‫‮‫‫‮‫"قايتا ‫سىناش" ‫نى ‫چېكىپ ‫قايتا ‫سىناڭ، ‫"ئۆتكۈزۋېتىش" ‫نى ‫چېكىپ ‫داۋاملاشتۇرۇڭ(تەۋسىيە ‫قىلىنمايدۇ)، ‫"ئاخىرلاشتۇرۇش" ‫نى ‫چېكىپ ‫قاچىلاشنى ‫ئاخىرلاشتۇرۇڭ. -SourceIsCorrupted=‫‮‫‫‮‫ھۆججەت ‫بۇزۇلۇپ ‫كېتىپتۇ -SourceDoesntExist=‫‮‫‫‮‫ھۆججەت ‫"%1" ‫مەۋجۇت ‫ئەمەسكەن -ExistingFileReadOnly=‫‮‫‫‮‫ھازىر ‫بار ‫بولغان ‫ھۆججەتنى ‫پەقەت ‫ئوقۇغىلى ‫بولىدىكەن.%n%n ‫ھۆججەتنىڭ ‫پەقەت ‫ئوقۇغىلى ‫بولىدىغان ‫خاسلىقىنى ‫ئېلىۋېتىپ ‫"قايتا ‫سىناش" ‫نى ‫چېكىڭ, ‫ياكى ‫"ئۆتكۈزۋېتىش" ‫نى ‫چېكىپ ‫ئاتلاپ ‫ئۆتۈپ ‫كېتىڭ, ‫ياكى ‫"ئاخىرلاشتۇرۇش" ‫نى ‫چېكىپ ‫قاچىلاشنى ‫ئاخىرلاشتۇرۇڭ. -ErrorReadingExistingDest=‫‮‫‫‮‫ھۆججەت ‫ئوقۇشتا ‫خاتالىق ‫كۆرۈلدى: -FileExists=‫‮‫‫‮‫ھۆججەت ‫مەۋجۇتكەن.%n%n ‫باستۇرۋېتەمسىز؟ -ExistingFileNewer=‫‮‫‫‮‫ئەسلىدە ‫بار ‫ھۆججەت ‫نەشرى ‫ھازىر ‫قاچىلىماقچى ‫بولغان ‫ھۆججەت ‫نەشرىدىن ‫يېڭىكەن. ‫چوقۇم ‫ساقلاپ ‫قېلىشىڭىز ‫كېرەك.%n%nساقلاپ ‫قالامسىز؟ -ErrorChangingAttr=‫‮‫‫‮‫ھۆججەت ‫خاسلىقىنى ‫ئۆزگەرتىشتە ‫خاتالىق ‫كۆرۈلدى: -ErrorCreatingTemp=‫‮‫‫‮‫ھۆججەت ‫قۇرۇش ‫مەغلۇپ ‫بولدى: -ErrorReadingSource=‫‮‫‫‮‫ھۆججەت ‫ئوقۇشتا ‫خاتالىق ‫كۆرۈلدى: -ErrorCopying=‫‮‫‫‮‫ھۆججەت ‫كۆچۈرۈشتە ‫خاتالىق ‫كۆرۈلدى: -ErrorReplacingExistingFile=‫‮‫‫‮‫ھۆججەت ‫ئالماشتۇرۇش ‫مەغلۇپ ‫بولدى: -ErrorRestartReplace=‫‮‫‫‮‫قايتا ‫ئالماشتۇرۇش ‫مەغلۇپ ‫بولدى: -ErrorRenamingTemp=‫‮‫‫‮‫نىشان ‫مۇندەرىجىنىڭ ‫نامىنى ‫ئۆزگەرتىشتە ‫خاتالىق ‫كۆرۈلدى: -ErrorRegisterServer=‫‮‫‫‮‫تىزىملاش ‫مەغلۇپ ‫بولغان ‫كونتروللار ‫(DLL/OCX):%1 -ErrorRegSvr32Failed=‫‮‫‫‮‫RegSvr32 ‫نى ‫ئىجرا ‫قىلىش ‫مەغلۇپ ‫بولدى، ‫قايتۇرغان ‫قىممەت:%1 -ErrorRegisterTypeLib=‫‮‫‫‮‫تىزىملاش ‫مەغلۇپ ‫بولغان ‫تۈرلەر:%1 +; *** File copying errors +FileAbortRetryIgnoreSkipNotRecommended=بۇ ھۆججەتنى ئۆتكۈزۈۋېتىش(&S) (تەۋسىيە قىلىنمايدۇ) +FileAbortRetryIgnoreIgnoreNotRecommended=خاتالىققا پەرۋا قىلماي داۋاملاشتۇرۇش(&I) (تەۋسىيە قىلىنمايدۇ) +SourceIsCorrupted=مەنبە ھۆججەت بۇزۇلغان +SourceDoesntExist=مەنبە ھۆججەت «%1» يوق +ExistingFileReadOnly2=بار ھۆججەتنى پەقەت ئوقۇشقىلا بولىدىغان بولغاچقا ئالماشتۇرغىلى بولمايدۇ. +ExistingFileReadOnlyRetry=ئوقۇشقىلا بولىدىغان خاسلىقنى چىقىرىۋېتىپ قايتا سىناش(&R) +ExistingFileReadOnlyKeepExisting=بار ھۆججەتنى ساقلاپ قىلىش(&K) +ErrorReadingExistingDest=بار ھۆججەتنى ئوقۇشتا خاتالىق كۆرۈلدى: +FileExistsSelectAction=مەشغۇلات تاللاش +FileExists2=ھۆججەت ئاللىبۇرۇن بار. +FileExistsOverwriteExisting=بار ھۆججەتنى قاپلىۋېتىش(&O) +FileExistsKeepExisting=بار ھۆججەتنى ساقلاپ قىلىش(&K) +FileExistsOverwriteOrKeepAll=كېيىنكى توقۇنۇشقا بۇنى قىلىش(&D) +ExistingFileNewerSelectAction=مەشغۇلات تاللاش +ExistingFileNewer2=بار ھۆججەت قاچىلىماقچى بولغان ھۆججەتتىن يېڭى. +ExistingFileNewerOverwriteExisting=بار ھۆججەتنى قاپلىۋېتىش(&O) +ExistingFileNewerKeepExisting=بار ھۆججەتنى ساقلاپ قىلىش(&K) (تەۋسىيە) +ExistingFileNewerOverwriteOrKeepAll=كېيىنكى توقۇنۇشقا بۇنى قىلىش(&D) +ErrorChangingAttr=بار ھۆججەتنىڭ خاسلىقىنى ئۆزگەرتىشتە خاتالىق كۆرۈلدى: +ErrorCreatingTemp=نىشان مۇندەرىجىگە ھۆججەت قۇرۇشتا خاتالىق كۆرۈلدى: +ErrorReadingSource=مەنبە ھۆججەتنى ئوقۇشتا خاتالىق كۆرۈلدى: +ErrorCopying=ھۆججەت كۆچۈرۈشتە خاتالىق كۆرۈلدى: +ErrorReplacingExistingFile=بار ھۆججەتنى ئالماشتۇرۇشتا خاتالىق كۆرۈلدى: +ErrorRestartReplace=قايتا ئالماشتۇرالمىدى: +ErrorRenamingTemp=نىشان مۇندەرىجىدىكى ھۆججەتنىڭ نامىنى ئۆزگەرتىشتە خاتالىق كۆرۈلدى: +ErrorRegisterServer=DLL/OCX نى تىزىملىتالمىدى: %1 +ErrorRegSvr32Failed=RegSvr32 مەغلۇپ بولدى، چېكىنىش كودى %1 +ErrorRegisterTypeLib=تىپ ئامبىرىنى تىزىملىتالمىدى: %1 -; ‫*** ‫Post-installation ‫errors -ErrorOpeningReadme=‫‮‫‫‮‫چۈشەندۈرۈش ‫قوللانمىسىنى ‫ئېچىشتا ‫خاتالىق ‫كۆرۈلدى. -ErrorRestartingComputer=‫‮‫‫‮‫قاچىلاش ‫يېتەكچىسى ‫كومپيۇتېرنى ‫قايتا ‫قوزغىتالمىدى. ‫قول ‫ئارقىلىق ‫قايتا ‫قوزغىتىڭ. +; *** Uninstall display name markings +; used for example as 'My Program (32-bit)' +UninstallDisplayNameMark=%1 (%2) +; used for example as 'My Program (32-bit, All users)' +UninstallDisplayNameMarks=%1 (%2، %3) +UninstallDisplayNameMark32Bit=32 بىت +UninstallDisplayNameMark64Bit=64 بىت +UninstallDisplayNameMarkAllUsers=بارلىق ئىشلەتكۈچى +UninstallDisplayNameMarkCurrentUser=نۆۋەتتىكى ئىشلەتكۈچى -; ‫*** ‫Uninstaller ‫messages -UninstallNotFound=‫‮‫‫‮‫"%1" ‫ھۆججىتى ‫يوق. ‫ئۆچۈرەلمەيدۇ. -UninstallOpenError=‫‮‫‫‮‫"%1" ‫ھۆججىتىنى ‫ئاچالمىدى. ‫ئۆچۈرەلمەيدۇ. -UninstallUnsupportedVer=‫‮‫‫‮‫بۇ ‫قاچىلاش ‫يېتەكچىسى"%1" ‫شەكىلدىكى ‫ئۆچۈرۈش ‫خاتىرىسىنى ‫تونۇيالمىدى.ئۆچۈرۈش ‫مەغلۇپ ‫بولدى. -UninstallUnknownEntry=‫‮‫‫‮‫ئۆچۈرۈش ‫خاتىرىسىدە ‫نامەلۇم ‫تۈر ‫(%1) ‫بايقالدى -ConfirmUninstall=‫‮‫‫‮‫سىز ‫راستتىنلا ‫%1 ‫ۋە ‫بارلىق ‫قىستۇرمىلارنى ‫پاكىز ‫ئۆچۈرۈۋەتمەكچىمۇ؟ -UninstallOnlyOnWin64=‫‮‫‫‮‫بۇ ‫قاچىلانما ‫پەقەت ‫64بىتلىق ‫Windows ‫مۇھىتىدا ‫ئۆچۈرۈلىدۇ. -OnlyAdminCanUninstall=‫‮‫‫‮‫بۇ ‫دېتالنى ‫پەقەت ‫باشقۇرغۇچىلىق ‫سالاھىيتىدىكى ‫ئىشلەتكۈچىلەرلا ‫ئۆچۈرەلەيدۇ. -UninstallStatusLabel=‫‮‫‫‮‫سەل ‫ساقلاڭ، ‫%1نى ‫ئۆچۈرۈۋاتىدۇ. -UninstalledAll=‫‮‫‫‮‫سىزنىڭ ‫كومپيۇتېرىڭىزدىن ‫%1نى ‫ئۆچۈرۈش ‫مۇۋەپپەقىيەتلىك ‫بولدى. -UninstalledMost=‫‮‫‫‮‫%1 ‫ئۆچۈرۈش ‫تاماملاندى.%n%nمەلۇم ‫تۈرلەرنى ‫ئۆچۈرۈش ‫جەريانىدا ‫ئۆچۈرەلمىدى. ‫بۇلارنى ‫قولدا ‫ئۆچۈرۈۋەتسىڭىز ‫بولىدۇ. -UninstalledAndNeedsRestart=‫‮‫‫‮‫%1نى ‫ئۆچۈرۈشنى ‫تاماملاش ‫ئۈچۈن، ‫كومپيۇتېرنى ‫قايتا ‫قوزغىتىشىڭىز ‫كېرەك. ‫%n%nھازىرلا ‫قايتا ‫قوزغىتامسىز؟ -UninstallDataCorrupted=‫‮‫‫‮‫"%1" ‫ھۆججىتى ‫بۇزۇلغان. ‫ئۆچۈرەلمەيدۇ +; *** Post-installation errors +ErrorOpeningReadme=چۈشەندۈرۈش ھۆججىتىنى ئېچىشتا خاتالىق كۆرۈلدى. +ErrorRestartingComputer=قاچىلاش پىروگراممىسى كومپيۇتېرنى قايتا قوزغىتالمىدى. بۇنى ئۆزىڭىز قىلىڭ. -; ‫*** ‫Uninstallation ‫phase ‫messages -ConfirmDeleteSharedFileTitle=‫‮‫‫‮‫ئورتاقلاشقان ‫ھۆججەتنى ‫ئۆچۈرەمسىز؟ -ConfirmDeleteSharedFile2=‫‮‫‫‮‫سىستېما ‫تۆۋەندىكى ‫ئورتاق ‫ھۆججەتنى ‫ئىشلەتمەيدۇ. ‫بۇ ‫ئورتاق ‫ھۆججەتنى ‫ئۆچۈرەمسىز؟%n%nئەگەر ‫سىستېما ‫بۇ ‫ھۆججەتنى ‫ئىشلەتسە، ‫ئۆچۈرۈۋەتكەندىن ‫كېيىن ‫سىستېما ‫نورمال ‫ئىشلىمەسلىكى ‫مۇمكىن. ‫مۇقۇملاشتۇرالمىسىڭىز ‫"ياق" ‫نى ‫تاللاڭ. ‫بۇ ‫ھۆججەت ‫قېلىپ ‫قالسا ‫سىستېمىغا ‫ھېچ ‫قانداق ‫ئەكس ‫تەسىرى ‫يوق. -SharedFileNameLabel=‫‮‫‫‮‫ھۆججەت ‫نامى: -SharedFileLocationLabel=‫‮‫‫‮‫ئورنى: -WizardUninstalling=‫‮‫‫‮‫ئۆچۈرۈش ‫ھالىتى -StatusUninstalling=‫‮‫‫‮‫%1نى ‫ئۆچۈرۈۋاتىدۇ… +; *** Uninstaller messages +UninstallNotFound=«%1» ھۆججىتى يوق. چىقىرىۋېتەلمەيدۇ. +UninstallOpenError=«%1» ھۆججىتىنى ئاچالمىدى. چىقىرىۋېتەلمەيدۇ +UninstallUnsupportedVer=چىقىرىۋېتىش خاتىرە ھۆججىتى «%1» نىڭ فورماتىنى بۇ نەشرىدىكى چىقىرىۋەتكۈچ تونۇيالمىدى. چىقىرىۋېتەلمەيدۇ +UninstallUnknownEntry=چىقىرىۋېتىش خاتىرىسىدە نامەلۇم مەزمۇنغا (%1) يولۇقتى +ConfirmUninstall=%1 ۋە ئۇنىڭ بارلىق بىرىكمىلىرىنى پۈتۈنلەي چىقىرىۋېتەمسىز؟ +UninstallOnlyOnWin64=بۇ قاچىلاشنى پەقەت 64 بىتلىق Windows دا چىقىرىۋەتكىلى بولىدۇ. +OnlyAdminCanUninstall=بۇ قاچىلاشنى پەقەت باشقۇرغۇچىلىق ھوقۇقى بار ئىشلەتكۈچى چىقىرىۋېتەلەيدۇ. +UninstallStatusLabel=كومپيۇتېرىڭىزدىن %1 چىقىرىلىۋاتىدۇ، سەل ساقلاڭ. +UninstalledAll=%1 نى كومپيۇتېرىڭىزدىن ئوڭۇشلۇق چىقىرىۋەتتى. +UninstalledMost=%1 چىقىرىۋەتتى.%n%nبەزى ئېلېمېنتلارنى چىقىرىۋېتەلمىدى. بۇلارنى ئۆزىڭىز چىقىرىۋەتسىڭىز بولىدۇ. +UninstalledAndNeedsRestart=%1 نى چىقىرىۋېتىش ئۈچۈن، كومپيۇتېرىڭىزنى قايتا قوزغىتىش كېرەك.%n%nھازىرلا قايتا قوزغىتامسىز؟ +UninstallDataCorrupted=«%1» ھۆججىتى بۇزۇلغان. چىقىرىۋېتەلمەيدۇ -; ‫*** ‫Shutdown ‫block ‫reasons -ShutdownBlockReasonInstallingApp=‫‮‫‫‮‫%1نى ‫قاچىلاۋاتىدۇ. -ShutdownBlockReasonUninstallingApp=‫‮‫‫‮‫%1نى ‫ئۆچۈرۈۋاتىدۇ. +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=ئورتاقلاشقان ھۆججەتنى چىقىرىۋېتەمسىز؟ +ConfirmDeleteSharedFile2=سىستېما تۆۋەندىكى ئورتاقلاشقان ھۆججەتنى ھېچقانداق پىروگراممىنىڭ ئىشلەتمەيدىغانلىقىنى كۆرسەتتى. بۇ ئورتاقلاشقان ھۆججەتنى چىقىرىۋېتەمسىز؟%n%nئەگەر بۇ ھۆججەتنى چىقىرىۋەتكەندىن كېيىن بىرەر پىروگرامما ئىشلەتسە، شۇ پىروگراممىدا نورمالسىزلىق چىقىشى مۇمكىن. ئەگەر ئىككىلەنسىڭىز، «ياق» نى تاللاڭ. ھۆججەت سىستېمىڭىزدا قالسا ھېچقانداق زىيىنى يوق. +SharedFileNameLabel=ھۆججەت نامى: +SharedFileLocationLabel=ئورنى: +WizardUninstalling=چىقىرىۋېتىش ھالىتى +StatusUninstalling=%1 نى چىقىرىۋاتىدۇ... -; ‫The ‫custom ‫messages ‫below ‫aren't ‫used ‫by ‫Setup ‫itself, ‫but ‫if ‫you ‫make -; ‫use ‫of ‫them ‫in ‫your ‫scripts, ‫you'll ‫want ‫to ‫translate ‫them. +; *** Shutdown block reasons +ShutdownBlockReasonInstallingApp=%1 نى قاچىلاۋاتىدۇ. +ShutdownBlockReasonUninstallingApp=%1 نى چىقىرىۋاتىدۇ. + +; The custom messages below aren't used by Setup itself, but if you make +; use of them in your scripts, you'll want to translate them. [CustomMessages] -NameAndVersion=‫‮‫‫‮‫%1نىڭ ‫%2 نەشىرى -AdditionalIcons=‫‮‫‫‮‫قوشۇمچە ‫قىسقا ‫يولى: +NameAndVersion=%1 نەشرى %2 +AdditionalIcons=قوشۇمچە قىسقا يولى: CreateDesktopIcon=ئۈستەليۈزىگە قىسقا يول قۇرۇش(&D) -CreateQuickLaunchIcon=تېز قوزغىتىش بالدىقىغا قىسقا يول قۇرۇش(&Q) -ProgramOnTheWeb=‫‮‫‫‮‫%1تور ‫بېكەت -UninstallProgram=‫‮‫‫‮‫%1نى ‫ئۆچۈرۈش -LaunchProgram=‫‮‫‫‮‫%1نى ‫ئىجرا ‫قىلىش -AssocFileExtension=‫‮‫‫‮‫%1 ‫بىلەن ‫%2 ‫بولغان ‫ھۆججەت ‫نامىنى ‫باغلاش (&A) -AssocingFileExtension=‫‮‫‫‮‫ھازىر%1 ‫بىلەن ‫%2 ‫بولغان ‫ھۆججەت ‫نامى ‫باغلىنىۋاتىدۇ...… -AutoStartProgramGroupDescription=‫‮‫‫‮‫قوزغىتىش: -AutoStartProgram=‫‮‫‫‮‫%1 ‫نى ‫ئاپتوماتىك ‫قوزغىتىش -AddonHostProgramNotFound=‫‮‫‫‮‫سىز ‫تاللىغان ‫ھۆججەت ‫قىسقۇچتا ‫%1نى ‫تاپالمىدى.%n%nشۇنداقتىمۇ ‫داۋاملاشتۇرامسىز؟ \ No newline at end of file +CreateQuickLaunchIcon=تېز قوزغىتىشقا قىسقا يول قۇرۇش(&Q) +ProgramOnTheWeb=توردىكى %1 +UninstallProgram=%1 نى چىقىرىۋېتىش +LaunchProgram=%1 نى قوزغىتىش +AssocFileExtension=%1 نى %2 ھۆججەت كېڭەيتمە نامى بىلەن باغلاش(&A) +AssocingFileExtension=%1 نى %2 ھۆججەت كېڭەيتمە نامى بىلەن باغلاۋاتىدۇ... +AutoStartProgramGroupDescription=قوزغىتىش: +AutoStartProgram=%1 نى ئاپتوماتىك قوزغىتىش +AddonHostProgramNotFound=سىز تاللىغان قىسقۇچتا %1 تېپىلمىدى.%n%nشۇنداقتىمۇ داۋاملاشتۇرامسىز؟ diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index 449cf2014..23788205e 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -26,6 +26,7 @@ Source: {#ReleaseDir}\Greenshot.Editor.dll; DestDir: {app}; Components: greensho Source: {#ReleaseDir}\Greenshot.exe.config; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\log4net.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Dapplo.*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion +Source: {#ReleaseDir}\System.*.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Svg.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\Fizzler.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion Source: {#ReleaseDir}\HtmlAgilityPack.dll; DestDir: {app}; Components: greenshot; Flags: overwritereadonly ignoreversion replacesameversion diff --git a/src/.editorconfig b/src/.editorconfig index f399b08bb..0141618f9 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -47,11 +47,6 @@ dotnet_style_explicit_tuple_names = true:suggestion # CSharp code style settings: [*.cs] -# Prefer "var" everywhere -csharp_style_var_for_built_in_types = true:suggestion -csharp_style_var_when_type_is_apparent = true:suggestion -csharp_style_var_elsewhere = true:suggestion - # Prefer method-like constructs to have a block body csharp_style_expression_bodied_methods = false:none csharp_style_expression_bodied_constructors = false:none diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs index 02911f058..a990beca3 100644 --- a/src/Greenshot.Base/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -1083,7 +1083,7 @@ EndSelection:<<<<<<<4 public static bool ContainsFormat(IDataObject dataObject, string[] formats) { bool formatFound = false; - List currentFormats = GetFormats(dataObject); + var currentFormats = GetFormats(dataObject); if (currentFormats == null || currentFormats.Count == 0 || formats == null || formats.Length == 0) { return false; diff --git a/src/Greenshot.Base/Core/EnvironmentInfo.cs b/src/Greenshot.Base/Core/EnvironmentInfo.cs index 3452180fa..b1e907912 100644 --- a/src/Greenshot.Base/Core/EnvironmentInfo.cs +++ b/src/Greenshot.Base/Core/EnvironmentInfo.cs @@ -73,7 +73,7 @@ namespace Greenshot.Base.Core { greenshotVersion = assemblyFileVersion.ToString(3); } - catch (Exception ex) + catch (Exception) { // Ignore } @@ -94,7 +94,7 @@ namespace Greenshot.Base.Core public static string EnvironmentToString(bool newline) { - StringBuilder environment = new StringBuilder(); + StringBuilder environment = new(); environment.Append("Software version: " + GetGreenshotVersion()); if (IniConfig.IsPortable) { @@ -208,7 +208,7 @@ namespace Greenshot.Base.Core if (ex == null) return "null\r\n"; - StringBuilder report = new StringBuilder(); + StringBuilder report = new(); report.AppendLine("Exception: " + ex.GetType()); report.AppendLine("Message: " + ex.Message); @@ -254,7 +254,7 @@ namespace Greenshot.Base.Core public static string BuildReport(Exception exception) { - StringBuilder exceptionText = new StringBuilder(); + StringBuilder exceptionText = new(); exceptionText.AppendLine(EnvironmentToString(true)); exceptionText.AppendLine(ExceptionToString(exception)); exceptionText.AppendLine("Configuration dump:"); diff --git a/src/Greenshot.Base/Core/WindowDetails.cs b/src/Greenshot.Base/Core/WindowDetails.cs index be244bb6f..0063e3edb 100644 --- a/src/Greenshot.Base/Core/WindowDetails.cs +++ b/src/Greenshot.Base/Core/WindowDetails.cs @@ -817,14 +817,11 @@ namespace Greenshot.Base.Core public ICapture CaptureGdiWindow(ICapture capture) { Image capturedImage = PrintWindow(); - if (capturedImage != null) - { - capture.Image = capturedImage; - capture.Location = Location; - return capture; - } + if (capturedImage == null) return null; + capture.Image = capturedImage; + capture.Location = Location; + return capture; - return null; } /// @@ -1069,7 +1066,7 @@ namespace Greenshot.Base.Core { if (thumbnailHandle != IntPtr.Zero) { - // Unregister (cleanup), as we are finished we don't need the form or the thumbnail anymore + // Un-register (cleanup), as we are finished we don't need the form or the thumbnail anymore DWM.DwmUnregisterThumbnail(thumbnailHandle); } @@ -1081,7 +1078,6 @@ namespace Greenshot.Base.Core } tempForm.Dispose(); - tempForm = null; } } diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index 958e14fcf..1c9b9b84c 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Greenshot.Base/Interfaces/Drawing/EditStatus.cs b/src/Greenshot.Base/Interfaces/Drawing/EditStatus.cs new file mode 100644 index 000000000..60f2c2af1 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Drawing/EditStatus.cs @@ -0,0 +1,32 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Interfaces.Drawing +{ + public enum EditStatus + { + UNDRAWN, + DRAWING, + MOVING, + RESIZING, + IDLE + }; +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Drawing/ICursorContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/ICursorContainer.cs new file mode 100644 index 000000000..4051203c5 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Drawing/ICursorContainer.cs @@ -0,0 +1,31 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Windows.Forms; + +namespace Greenshot.Base.Interfaces.Drawing +{ + public interface ICursorContainer : IDrawableContainer + { + Cursor Cursor { get; set; } + void Load(string filename); + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs new file mode 100644 index 000000000..1742b8054 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs @@ -0,0 +1,79 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using Greenshot.Base.Interfaces.Drawing.Adorners; + +namespace Greenshot.Base.Interfaces.Drawing +{ + public interface IDrawableContainer : INotifyPropertyChanged, IDisposable + { + ISurface Parent { get; set; } + bool Selected { get; set; } + + int Left { get; set; } + + int Top { get; set; } + + int Width { get; set; } + + int Height { get; set; } + + Point Location { get; } + + Size Size { get; } + + Rectangle Bounds { get; } + + Rectangle DrawingBounds { get; } + + void ApplyBounds(RectangleF newBounds); + + bool HasFilters { get; } + + EditStatus Status { get; set; } + void Invalidate(); + bool ClickableAt(int x, int y); + void MoveBy(int x, int y); + void Transform(Matrix matrix); + bool HandleMouseDown(int x, int y); + void HandleMouseUp(int x, int y); + bool HandleMouseMove(int x, int y); + bool InitContent(); + void MakeBoundsChangeUndoable(bool allowMerge); + EditStatus DefaultEditMode { get; } + + /// + /// Available adorners for the DrawableContainer + /// + IList Adorners { get; } + + /// + /// Adjust UI elements to the supplied DPI settings + /// + /// uint + void AdjustToDpi(uint dpi); + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Drawing/Container.cs b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainerList.cs similarity index 55% rename from src/Greenshot.Base/Interfaces/Drawing/Container.cs rename to src/Greenshot.Base/Interfaces/Drawing/IDrawableContainerList.cs index 4f653ac8a..39235f63b 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/Container.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainerList.cs @@ -21,78 +21,12 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; -using Greenshot.Base.Interfaces.Drawing.Adorners; namespace Greenshot.Base.Interfaces.Drawing { - public enum RenderMode - { - EDIT, - EXPORT - }; - - public enum EditStatus - { - UNDRAWN, - DRAWING, - MOVING, - RESIZING, - IDLE - }; - - public interface IDrawableContainer : INotifyPropertyChanged, IDisposable - { - ISurface Parent { get; set; } - bool Selected { get; set; } - - int Left { get; set; } - - int Top { get; set; } - - int Width { get; set; } - - int Height { get; set; } - - Point Location { get; } - - Size Size { get; } - - Rectangle Bounds { get; } - - Rectangle DrawingBounds { get; } - - void ApplyBounds(RectangleF newBounds); - - bool hasFilters { get; } - - EditStatus Status { get; set; } - void Invalidate(); - bool ClickableAt(int x, int y); - void MoveBy(int x, int y); - void Transform(Matrix matrix); - bool HandleMouseDown(int x, int y); - void HandleMouseUp(int x, int y); - bool HandleMouseMove(int x, int y); - bool InitContent(); - void MakeBoundsChangeUndoable(bool allowMerge); - EditStatus DefaultEditMode { get; } - - /// - /// Available adorners for the DrawableContainer - /// - IList Adorners { get; } - - /// - /// Adjust UI elements to the supplied DPI settings - /// - /// uint - void AdjustToDpi(uint dpi); - } - public interface IDrawableContainerList : IList, IDisposable { Guid ParentID { get; } @@ -126,28 +60,4 @@ namespace Greenshot.Base.Interfaces.Drawing void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e); void AdjustToDpi(uint dpi); } - - public interface ITextContainer : IDrawableContainer - { - string Text { get; set; } - void FitToText(); - } - - public interface IImageContainer : IDrawableContainer - { - Image Image { get; set; } - void Load(string filename); - } - - public interface ICursorContainer : IDrawableContainer - { - Cursor Cursor { get; set; } - void Load(string filename); - } - - public interface IIconContainer : IDrawableContainer - { - Icon Icon { get; set; } - void Load(string filename); - } } \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Drawing/IIconContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/IIconContainer.cs new file mode 100644 index 000000000..886dcf35c --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Drawing/IIconContainer.cs @@ -0,0 +1,31 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; + +namespace Greenshot.Base.Interfaces.Drawing +{ + public interface IIconContainer : IDrawableContainer + { + Icon Icon { get; set; } + void Load(string filename); + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Drawing/IImageContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/IImageContainer.cs new file mode 100644 index 000000000..a16379dce --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Drawing/IImageContainer.cs @@ -0,0 +1,31 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Drawing; + +namespace Greenshot.Base.Interfaces.Drawing +{ + public interface IImageContainer : IDrawableContainer + { + Image Image { get; set; } + void Load(string filename); + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Drawing/ITextContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/ITextContainer.cs new file mode 100644 index 000000000..ff5c84c43 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Drawing/ITextContainer.cs @@ -0,0 +1,29 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Interfaces.Drawing +{ + public interface ITextContainer : IDrawableContainer + { + string Text { get; set; } + void FitToText(); + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Drawing/RenderMode.cs b/src/Greenshot.Base/Interfaces/Drawing/RenderMode.cs new file mode 100644 index 000000000..c0b1dd99a --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Drawing/RenderMode.cs @@ -0,0 +1,29 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Interfaces.Drawing +{ + public enum RenderMode + { + EDIT, + EXPORT + } +} \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index b7202b23e..029a48d43 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -385,7 +385,7 @@ namespace Greenshot.Editor.Drawing Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight)); } - public bool hasFilters => Filters.Count > 0; + public bool HasFilters => Filters.Count > 0; public abstract void Draw(Graphics graphics, RenderMode renderMode); @@ -467,13 +467,6 @@ namespace Greenshot.Editor.Drawing g.DrawRectangle(pen, rect); } - - public void ResizeTo(int width, int height, int anchorPosition) - { - Width = width; - Height = height; - } - /// /// Make a following bounds change on this drawablecontainer undoable! /// diff --git a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs index a7ed4f75b..e89b78b70 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs @@ -42,7 +42,7 @@ namespace Greenshot.Editor.Drawing [Serializable] public class DrawableContainerList : List, IDrawableContainerList { - private static readonly ComponentResourceManager EditorFormResources = new ComponentResourceManager(typeof(ImageEditorForm)); + private static readonly ComponentResourceManager EditorFormResources = new(typeof(ImageEditorForm)); public Guid ParentID { get; private set; } @@ -252,7 +252,7 @@ namespace Greenshot.Editor.Drawing { foreach (var dc in this) { - if (dc.DrawingBounds.IntersectsWith(clipRectangle) && dc.hasFilters && dc.Status == EditStatus.IDLE) + if (dc.DrawingBounds.IntersectsWith(clipRectangle) && dc.HasFilters && dc.Status == EditStatus.IDLE) { return true; } @@ -711,7 +711,7 @@ namespace Greenshot.Editor.Drawing public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface) { - if (!(iSurface is Surface surface)) + if (iSurface is not Surface surface) { return; } diff --git a/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs b/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs index 825d1aae7..944269625 100644 --- a/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs +++ b/src/Greenshot.Plugin.Confluence/Support/TranslationManager.cs @@ -8,25 +8,6 @@ namespace Greenshot.Plugin.Confluence.Support public event EventHandler LanguageChanged; - /*public CultureInfo CurrentLanguage { - get { return Thread.CurrentThread.CurrentUICulture; } - set { - if( value != Thread.CurrentThread.CurrentUICulture) { - Thread.CurrentThread.CurrentUICulture = value; - OnLanguageChanged(); - } - } - } - - public IEnumerable Languages { - get { - if( TranslationProvider != null) { - return TranslationProvider.Languages; - } - return Enumerable.Empty(); - } - }*/ - public static TranslationManager Instance => _translationManager ??= new TranslationManager(); public ITranslationProvider TranslationProvider { get; set; } From a32cc1888b594b57db309eee105e19b65f0a9bdd Mon Sep 17 00:00:00 2001 From: Christian Schulz <32000301+Christian-Schulz@users.noreply.github.com> Date: Sat, 19 Feb 2022 01:25:07 +0100 Subject: [PATCH 172/232] Fix exception when rotating when counter are used, by prevent negative fontsize (#382) --- src/Greenshot.Editor/Drawing/StepLabelContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Greenshot.Editor/Drawing/StepLabelContainer.cs b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs index 0e7c27516..4f95e0437 100644 --- a/src/Greenshot.Editor/Drawing/StepLabelContainer.cs +++ b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs @@ -204,7 +204,7 @@ namespace Greenshot.Editor.Drawing EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false); } - float fontSize = Math.Min(Width, Height) / 1.4f; + float fontSize = Math.Min(Math.Abs(Width), Math.Abs(Height)) / 1.4f; using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name); using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel); TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font); From 60956771c85b6a104e9547d033d71cf76557056d Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 20 Feb 2022 13:21:32 +0100 Subject: [PATCH 173/232] Feature Improve file format support (#385) This feature will make it easier to support different file formats later on, and also adds a "VectorGraphicsContainer" base class to better support non pixel graphics in the editor. Examples are SVG, WMF/EMF and Emoji which scale automatically to the correct size and are not resized from pixels. Multiple new formats have been added for reading, Jpeg XR for writing. --- .../Controls/SaveImageFileDialog.cs | 3 +- src/Greenshot.Base/Core/ClipboardHelper.cs | 518 +++++++++++------- .../Core/Enums/ExifOrientations.cs | 36 ++ src/Greenshot.Base/Core/Enums/OutputFormat.cs | 1 + .../FileFormatHandlerExtensions.cs | 163 ++++++ src/Greenshot.Base/Core/IImage.cs | 2 +- src/Greenshot.Base/Core/ImageHelper.cs | 391 ++++--------- .../Core/{ImageOutput.cs => ImageIO.cs} | 508 ++++++++--------- src/Greenshot.Base/Core/ImageWrapper.cs | 77 --- src/Greenshot.Base/Core/NetworkHelper.cs | 104 +++- src/Greenshot.Base/Core/PluginUtils.cs | 2 +- .../Core/SimpleServiceProvider.cs | 11 +- src/Greenshot.Base/Core/SvgImage.cs | 117 ---- src/Greenshot.Base/Core/WindowDetails.cs | 4 +- .../Interfaces/Drawing/IDrawableContainer.cs | 17 + .../Interfaces/Drawing/IFieldAggregator.cs | 33 ++ .../Interfaces/IFileFormatHandler.cs | 88 +++ .../Interfaces/IServiceLocator.cs | 2 +- src/Greenshot.Base/Interfaces/ISurface.cs | 10 + .../Plugin/SurfaceOutputSettings.cs | 23 +- .../Enums/WindowStyleFlags.cs | 2 +- src/Greenshot.Base/UnmanagedHelpers/User32.cs | 12 +- .../Drawing/ArrowContainer.cs | 3 +- src/Greenshot.Editor/Drawing/CropContainer.cs | 3 +- .../Drawing/CursorContainer.cs | 5 +- .../Drawing/DrawableContainer.cs | 15 +- .../Drawing/EllipseContainer.cs | 3 +- .../Drawing/Fields/FieldAggregator.cs | 11 +- .../Drawing/FilterContainer.cs | 3 +- .../Drawing/FreehandContainer.cs | 3 +- .../Drawing/HighlightContainer.cs | 3 +- src/Greenshot.Editor/Drawing/IconContainer.cs | 22 +- .../Drawing/ImageContainer.cs | 38 +- src/Greenshot.Editor/Drawing/LineContainer.cs | 3 +- .../Drawing/MetafileContainer.cs | 81 +++ .../Drawing/ObfuscateContainer.cs | 5 +- .../Drawing/RectangleContainer.cs | 3 +- .../Drawing/SpeechbubbleContainer.cs | 4 +- .../Drawing/StepLabelContainer.cs | 26 +- src/Greenshot.Editor/Drawing/Surface.cs | 109 ++-- src/Greenshot.Editor/Drawing/SvgContainer.cs | 61 +++ src/Greenshot.Editor/Drawing/TextContainer.cs | 31 +- .../Drawing/VectorGraphicsContainer.cs | 117 ++++ src/Greenshot.Editor/EditorInitialize.cs | 50 ++ .../AbstractFileFormatHandler.cs | 66 +++ .../DefaultFileFormatHandler.cs | 137 +++++ .../DibFileFormatHandler.cs} | 105 +++- .../GreenshotFileFormatHandler.cs | 133 +++++ .../IconFileFormatHandler.cs | 218 ++++++++ .../MetaFileFormatHandler.cs | 81 +++ .../SvgFileFormatHandler.cs | 89 +++ .../WpfFileFormatHandler.cs | 144 +++++ src/Greenshot.Editor/Forms/ImageEditorForm.cs | 24 +- src/Greenshot.Editor/Greenshot.Editor.csproj | 3 + .../Memento/AddElementMemento.cs | 7 +- .../Memento/AddElementsMemento.cs | 6 +- .../Memento/DeleteElementMemento.cs | 6 +- .../Memento/DeleteElementsMemento.cs | 6 +- .../Memento/SurfaceBackgroundChangeMemento.cs | 6 +- .../Forms/SettingsForm.Designer.cs | 4 +- .../ConfluenceDestination.cs | 4 +- ...nfiguration.cs => DropboxConfiguration.cs} | 145 +++-- .../DropboxDestination.cs | 2 +- src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs | 4 +- src/Greenshot.Plugin.Dropbox/DropboxUtils.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 4 +- .../ExternalCommandDestination.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 14 +- .../Forms/SettingsForm.Designer.cs | 4 +- .../Forms/SettingsForm.Designer.cs | 6 +- src/Greenshot.Plugin.Imgur/ImgurUtils.cs | 5 +- .../Forms/SettingsForm.Designer.cs | 4 +- .../Destinations/ExcelDestination.cs | 4 +- .../Destinations/OutlookDestination.cs | 2 +- .../Destinations/PowerpointDestination.cs | 2 +- .../Destinations/WordDestination.cs | 2 +- .../OfficeExport/OneNoteExporter.cs | 2 +- .../Forms/SettingsForm.Designer.cs | 4 +- .../Destinations/Win10ShareDestination.cs | 6 +- .../Win10OcrProvider.cs | 4 +- src/Greenshot/App.config | 1 - src/Greenshot/Destinations/FileDestination.cs | 8 +- .../Destinations/FileWithDialogDestination.cs | 2 +- src/Greenshot/Forms/MainForm.cs | 23 +- .../Forms/PrintOptionsDialog.Designer.cs | 17 +- src/Greenshot/Forms/SettingsForm.Designer.cs | 77 +-- src/Greenshot/Forms/SettingsForm.cs | 14 +- src/Greenshot/Helpers/CaptureHelper.cs | 7 +- src/Greenshot/Helpers/MailHelper.cs | 2 +- src/Greenshot/Helpers/PrintHelper.cs | 2 +- 90 files changed, 2793 insertions(+), 1340 deletions(-) create mode 100644 src/Greenshot.Base/Core/Enums/ExifOrientations.cs create mode 100644 src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerExtensions.cs rename src/Greenshot.Base/Core/{ImageOutput.cs => ImageIO.cs} (60%) delete mode 100644 src/Greenshot.Base/Core/ImageWrapper.cs delete mode 100644 src/Greenshot.Base/Core/SvgImage.cs create mode 100644 src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs create mode 100644 src/Greenshot.Base/Interfaces/IFileFormatHandler.cs create mode 100644 src/Greenshot.Editor/Drawing/MetafileContainer.cs create mode 100644 src/Greenshot.Editor/Drawing/SvgContainer.cs create mode 100644 src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs create mode 100644 src/Greenshot.Editor/EditorInitialize.cs create mode 100644 src/Greenshot.Editor/FileFormatHandlers/AbstractFileFormatHandler.cs create mode 100644 src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs rename src/{Greenshot.Base/Core/DibHelper.cs => Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs} (59%) create mode 100644 src/Greenshot.Editor/FileFormatHandlers/GreenshotFileFormatHandler.cs create mode 100644 src/Greenshot.Editor/FileFormatHandlers/IconFileFormatHandler.cs create mode 100644 src/Greenshot.Editor/FileFormatHandlers/MetaFileFormatHandler.cs create mode 100644 src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs create mode 100644 src/Greenshot.Editor/FileFormatHandlers/WpfFileFormatHandler.cs rename src/Greenshot.Plugin.Dropbox/{DropboxPluginConfiguration.cs => DropboxConfiguration.cs} (92%) diff --git a/src/Greenshot.Base/Controls/SaveImageFileDialog.cs b/src/Greenshot.Base/Controls/SaveImageFileDialog.cs index 3c9b2780e..091152d64 100644 --- a/src/Greenshot.Base/Controls/SaveImageFileDialog.cs +++ b/src/Greenshot.Base/Controls/SaveImageFileDialog.cs @@ -120,6 +120,7 @@ namespace Greenshot.Base.Controls private void PrepareFilterOptions() { + // TODO: Change to the FileFormatHandlerRegistry to look for all the supported extensions OutputFormat[] supportedImageFormats = (OutputFormat[]) Enum.GetValues(typeof(OutputFormat)); _filterOptions = new FilterOption[supportedImageFormats.Length]; for (int i = 0; i < _filterOptions.Length; i++) @@ -166,7 +167,7 @@ namespace Greenshot.Base.Controls // if the filename contains a valid extension, which is the same like the selected filter item's extension, the filename is okay if (fn.EndsWith(Extension, StringComparison.CurrentCultureIgnoreCase)) return fn; // otherwise we just add the selected filter item's extension - else return fn + "." + Extension; + return fn + "." + Extension; } set { diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs index a990beca3..a6e1da2a0 100644 --- a/src/Greenshot.Base/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -31,8 +31,10 @@ using System.Text; using System.Threading; using System.Windows.Forms; using Greenshot.Base.Core.Enums; +using Greenshot.Base.Core.FileFormatHandlers; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.UnmanagedHelpers; using log4net; @@ -63,7 +65,8 @@ namespace Greenshot.Base.Core //private static readonly string FORMAT_HTML = "HTML Format"; // Template for the HTML Text on the clipboard - // see: https://msdn.microsoft.com/en-us/library/ms649015%28v=vs.85%29.aspx + // see: https://msdn.microsoft.com/en-us/library/ms649015%28v=v + // s.85%29.aspx // or: https://msdn.microsoft.com/en-us/library/Aa767917.aspx private const string HtmlClipboardString = @"Version:0.9 StartHTML:<<<<<<<1 @@ -298,14 +301,15 @@ EndSelection:<<<<<<<4 { return true; } - - foreach (var fileData in IterateClipboardContent(dataObject)) + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList(); + foreach (var (stream, filename) in IterateClipboardContent(dataObject)) { try { - using (ImageHelper.FromStream(fileData)) + var extension = Path.GetExtension(filename)?.ToLowerInvariant(); + if (supportedExtensions.Contains(extension)) { - // If we get here, there is an image return true; } } @@ -315,7 +319,7 @@ EndSelection:<<<<<<<4 } finally { - fileData?.Dispose(); + stream?.Dispose(); } } @@ -327,7 +331,8 @@ EndSelection:<<<<<<<4 var imageStream = clipboardContent as MemoryStream; if (IsValidStream(imageStream)) { - using (ImageHelper.FromStream(imageStream)) + // TODO: How to check if we support "just a stream"? + using (ImageIO.FromStream(imageStream)) { // If we get here, there is an image return true; @@ -373,8 +378,8 @@ EndSelection:<<<<<<<4 /// Iterate the clipboard content /// /// IDataObject - /// IEnumerable{MemoryStream} - private static IEnumerable IterateClipboardContent(IDataObject dataObject) + /// IEnumerable{(MemoryStream,string)} + private static IEnumerable<(MemoryStream stream,string filename)> IterateClipboardContent(IDataObject dataObject) { var fileDescriptors = AvailableFileDescriptors(dataObject); if (fileDescriptors == null) yield break; @@ -413,8 +418,8 @@ EndSelection:<<<<<<<4 /// /// IEnumerable{FileDescriptor} /// IDataObject - /// IEnumerable{MemoryStream} - private static IEnumerable IterateFileDescriptors(IEnumerable fileDescriptors, IDataObject dataObject) + /// IEnumerable{(MemoryStream stream, string filename)} + private static IEnumerable<(MemoryStream stream, string filename)> IterateFileDescriptors(IEnumerable fileDescriptors, IDataObject dataObject) { if (fileDescriptors == null) { @@ -445,7 +450,7 @@ EndSelection:<<<<<<<4 if (fileData?.Length > 0) { fileData.Position = 0; - yield return fileData; + yield return (fileData, fileDescriptor.FileName); } fileIndex++; @@ -490,7 +495,7 @@ EndSelection:<<<<<<<4 { IDataObject clipboardData = GetDataObject(); // Return the first image - foreach (Image clipboardImage in GetImages(clipboardData)) + foreach (var clipboardImage in GetImages(clipboardData)) { return clipboardImage; } @@ -503,57 +508,154 @@ EndSelection:<<<<<<<4 /// Returned images must be disposed by the calling code! /// /// - /// IEnumerable of Image - public static IEnumerable GetImages(IDataObject dataObject) + /// IEnumerable of Bitmap + public static IEnumerable GetImages(IDataObject dataObject) { // Get single image, this takes the "best" match - Image singleImage = GetImage(dataObject); + Bitmap singleImage = GetImage(dataObject); if (singleImage != null) { - Log.InfoFormat("Got image from clipboard with size {0} and format {1}", singleImage.Size, singleImage.PixelFormat); + Log.InfoFormat($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}"); yield return singleImage; + yield break; } - else + + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList(); + + foreach (var (stream, filename) in IterateClipboardContent(dataObject)) { - foreach (var fileData in IterateClipboardContent(dataObject)) + var extension = Path.GetExtension(filename)?.ToLowerInvariant(); + if (!supportedExtensions.Contains(extension)) { - Image image; - try - { - image = ImageHelper.FromStream(fileData); - } - catch (Exception ex) - { - Log.Error("Couldn't read file contents", ex); - continue; - } - finally - { - fileData?.Dispose(); - } - // If we get here, there is an image - yield return image; + continue; } - // check if files are supplied - foreach (string imageFile in GetImageFilenames(dataObject)) + Bitmap bitmap = null; + + try { - Image returnImage = null; - try + if (!fileFormatHandlers.TryLoadFromStream(stream, extension, out bitmap)) { - returnImage = ImageHelper.LoadImage(imageFile); - } - catch (Exception streamImageEx) - { - Log.Error("Problem retrieving Image from clipboard.", streamImageEx); + continue; } - if (returnImage != null) + } + catch (Exception ex) + { + Log.Error("Couldn't read file contents", ex); + continue; + } + finally + { + stream?.Dispose(); + } + // If we get here, there is an image + yield return bitmap; + } + + // check if files are supplied + foreach (string imageFile in GetImageFilenames(dataObject)) + { + var extension = Path.GetExtension(imageFile)?.ToLowerInvariant(); + if (!supportedExtensions.Contains(extension)) + { + continue; + } + + Bitmap bitmap = null; + using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read); + try + { + if (!fileFormatHandlers.TryLoadFromStream(fileStream, extension, out bitmap)) { - Log.InfoFormat("Got image from clipboard with size {0} and format {1}", returnImage.Size, returnImage.PixelFormat); - yield return returnImage; + continue; } } + catch (Exception ex) + { + Log.Error("Couldn't read file contents", ex); + continue; + } + // If we get here, there is an image + yield return bitmap; + } + } + + /// + /// Get all images (multiple if file names are available) from the dataObject + /// Returned images must be disposed by the calling code! + /// + /// + /// IEnumerable of IDrawableContainer + public static IEnumerable GetDrawables(IDataObject dataObject) + { + // Get single image, this takes the "best" match + IDrawableContainer singleImage = GetDrawable(dataObject); + if (singleImage != null) + { + Log.InfoFormat($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}"); + yield return singleImage; + yield break; + } + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadDrawableFromStream).ToList(); + + foreach (var (stream, filename) in IterateClipboardContent(dataObject)) + { + var extension = Path.GetExtension(filename)?.ToLowerInvariant(); + if (!supportedExtensions.Contains(extension)) + { + continue; + } + + IEnumerable drawableContainers; + try + { + drawableContainers = fileFormatHandlers.LoadDrawablesFromStream(stream, extension); + } + catch (Exception ex) + { + Log.Error("Couldn't read file contents", ex); + continue; + } + finally + { + stream?.Dispose(); + } + // If we get here, there is an image + foreach (var container in drawableContainers) + { + yield return container; + } + } + + // check if files are supplied + foreach (string imageFile in GetImageFilenames(dataObject)) + { + var extension = Path.GetExtension(imageFile)?.ToLowerInvariant(); + if (!supportedExtensions.Contains(extension)) + { + continue; + } + + IDrawableContainer drawableContainer = null; + using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read); + IEnumerable drawableContainers; + try + { + drawableContainers = fileFormatHandlers.LoadDrawablesFromStream(fileStream, extension); + } + catch (Exception ex) + { + Log.Error("Couldn't read file contents", ex); + continue; + } + // If we get here, there is an image + foreach (var container in drawableContainers) + { + yield return container; + } } } @@ -562,51 +664,50 @@ EndSelection:<<<<<<<4 /// /// /// Image or null - private static Image GetImage(IDataObject dataObject) + private static Bitmap GetImage(IDataObject dataObject) { - Image returnImage = null; - if (dataObject != null) - { - IList formats = GetFormats(dataObject); - string[] retrieveFormats; + if (dataObject == null) return null; - // Found a weird bug, where PNG's from Outlook 2010 are clipped - // So I build some special logic to get the best format: - if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) + Bitmap returnImage = null; + IList formats = GetFormats(dataObject); + string[] retrieveFormats; + + // Found a weird bug, where PNG's from Outlook 2010 are clipped + // So I build some special logic to get the best format: + if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) + { + // Outlook ?? + Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front..."); + retrieveFormats = new[] { - // Outlook ?? - Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front..."); - retrieveFormats = new[] - { - DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, - DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML - }; + DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, + DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML + }; + } + else + { + retrieveFormats = new[] + { + FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, + FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML + }; + } + + foreach (string currentFormat in retrieveFormats) + { + if (formats != null && formats.Contains(currentFormat)) + { + Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat); + returnImage = GetImageForFormat(currentFormat, dataObject); } else { - retrieveFormats = new[] - { - FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, - FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML - }; + Log.DebugFormat("Couldn't find format {0}.", currentFormat); } - foreach (string currentFormat in retrieveFormats) + if (returnImage != null) { - if (formats != null && formats.Contains(currentFormat)) - { - Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat); - returnImage = GetImageForFormat(currentFormat, dataObject); - } - else - { - Log.DebugFormat("Couldn't find format {0}.", currentFormat); - } - - if (returnImage != null) - { - return returnImage; - } + return returnImage; } } @@ -614,15 +715,72 @@ EndSelection:<<<<<<<4 } /// - /// Helper method to try to get an image in the specified format from the dataObject + /// Get an IDrawableContainer from the IDataObject, don't check for FileDrop + /// + /// + /// Image or null + private static IDrawableContainer GetDrawable(IDataObject dataObject) + { + if (dataObject == null) return null; + + IDrawableContainer returnImage = null; + IList formats = GetFormats(dataObject); + string[] retrieveFormats; + + // Found a weird bug, where PNG's from Outlook 2010 are clipped + // So I build some special logic to get the best format: + if (formats != null && formats.Contains(FORMAT_PNG_OFFICEART) && formats.Contains(DataFormats.Dib)) + { + // Outlook ?? + Log.Info("Most likely the current clipboard contents come from Outlook, as this has a problem with PNG and others we place the DIB format to the front..."); + retrieveFormats = new[] + { + DataFormats.Dib, FORMAT_BITMAP, FORMAT_FILECONTENTS, FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, + DataFormats.Tiff, FORMAT_GIF, FORMAT_HTML + }; + } + else + { + retrieveFormats = new[] + { + FORMAT_PNG_OFFICEART, FORMAT_PNG, FORMAT_17, FORMAT_JFIF_OFFICEART, FORMAT_JPG, FORMAT_JPEG, FORMAT_JFIF, DataFormats.Tiff, DataFormats.Dib, FORMAT_BITMAP, + FORMAT_FILECONTENTS, FORMAT_GIF, FORMAT_HTML + }; + } + + foreach (string currentFormat in retrieveFormats) + { + if (formats != null && formats.Contains(currentFormat)) + { + Log.InfoFormat("Found {0}, trying to retrieve.", currentFormat); + returnImage = GetDrawableForFormat(currentFormat, dataObject); + } + else + { + Log.DebugFormat("Couldn't find format {0}.", currentFormat); + } + + if (returnImage != null) + { + return returnImage; + } + } + + return null; + } + + /// + /// Helper method to try to get an Bitmap in the specified format from the dataObject /// the DIB reader should solve some issues /// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591 /// /// string with the format /// IDataObject - /// Image or null - private static Image GetImageForFormat(string format, IDataObject dataObject) + /// Bitmap or null + private static Bitmap GetImageForFormat(string format, IDataObject dataObject) { + Bitmap bitmap = null; + if (format == FORMAT_HTML) { var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); @@ -638,10 +796,10 @@ EndSelection:<<<<<<<4 var srcAttribute = imgNode.Attributes["src"]; var imageUrl = srcAttribute.Value; Log.Debug(imageUrl); - var image = NetworkHelper.DownloadImage(imageUrl); - if (image != null) + bitmap = NetworkHelper.DownloadImage(imageUrl); + if (bitmap != null) { - return image; + return bitmap; } } } @@ -652,111 +810,80 @@ EndSelection:<<<<<<<4 var imageStream = clipboardObject as MemoryStream; if (!IsValidStream(imageStream)) { - // TODO: add "HTML Format" support here... - return clipboardObject as Image; + return clipboardObject as Bitmap; } + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); - if (CoreConfig.EnableSpecialDIBClipboardReader) + // From here, imageStream is a valid stream + if (!fileFormatHandlers.TryLoadFromStream(imageStream, format, out bitmap)) { - if (format == FORMAT_17 || format == DataFormats.Dib) + return bitmap; + } + return null; + } + + /// + /// Helper method to try to get an IDrawableContainer in the specified format from the dataObject + /// the DIB reader should solve some issues + /// It also supports Format17/DibV5, by using the following information: https://stackoverflow.com/a/14335591 + /// + /// string with the format + /// IDataObject + /// IDrawableContainer or null + private static IDrawableContainer GetDrawableForFormat(string format, IDataObject dataObject) + { + IDrawableContainer drawableContainer = null; + + if (format == FORMAT_HTML) + { + var textObject = ContentAsString(dataObject, FORMAT_HTML, Encoding.UTF8); + if (textObject != null) { - Log.Info("Found DIB stream, trying to process it."); - try + var doc = new HtmlDocument(); + doc.LoadHtml(textObject); + var imgNodes = doc.DocumentNode.SelectNodes("//img"); + if (imgNodes != null) { - if (imageStream != null) + foreach (var imgNode in imgNodes) { - byte[] dibBuffer = new byte[imageStream.Length]; - _ = imageStream.Read(dibBuffer, 0, dibBuffer.Length); - var infoHeader = BinaryStructHelper.FromByteArray(dibBuffer); - if (!infoHeader.IsDibV5) + var srcAttribute = imgNode.Attributes["src"]; + var imageUrl = srcAttribute.Value; + Log.Debug(imageUrl); + drawableContainer = NetworkHelper.DownloadImageAsDrawableContainer(imageUrl); + if (drawableContainer != null) { - Log.InfoFormat("Using special DIB (); + + return fileFormatHandlers.LoadDrawablesFromStream(imageStream, format).FirstOrDefault(); } /// @@ -840,7 +967,7 @@ EndSelection:<<<<<<<4 { SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); // Create the image which is going to be saved so we don't create it multiple times - disposeImage = ImageOutput.CreateImageFromSurface(surface, outputSettings, out imageToSave); + disposeImage = ImageIO.CreateImageFromSurface(surface, outputSettings, out imageToSave); try { // Create PNG stream @@ -849,7 +976,7 @@ EndSelection:<<<<<<<4 pngStream = new MemoryStream(); // PNG works for e.g. Powerpoint SurfaceOutputSettings pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); - ImageOutput.SaveToStream(imageToSave, null, pngStream, pngOutputSettings); + ImageIO.SaveToStream(imageToSave, null, pngStream, pngOutputSettings); pngStream.Seek(0, SeekOrigin.Begin); // Set the PNG stream dataObject.SetData(FORMAT_PNG, false, pngStream); @@ -866,11 +993,18 @@ EndSelection:<<<<<<<4 { // Create the stream for the clipboard dibStream = new MemoryStream(); - var dibBytes = ((Bitmap)imageToSave).ConvertToDib(); - dibStream.Write(dibBytes,0, dibBytes.Length); + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); - // Set the DIB to the clipboard DataObject - dataObject.SetData(DataFormats.Dib, false, dibStream); + if (!fileFormatHandlers.TrySaveToStream((Bitmap)imageToSave, dibStream, DataFormats.Dib)) + { + dibStream.Dispose(); + dibStream = null; + } + else + { + // Set the DIB to the clipboard DataObject + dataObject.SetData(DataFormats.Dib, false, dibStream); + } } } catch (Exception dibEx) @@ -924,7 +1058,7 @@ EndSelection:<<<<<<<4 // Set the HTML if (CoreConfig.ClipboardFormats.Contains(ClipboardFormat.HTML)) { - string tmpFile = ImageOutput.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null); + string tmpFile = ImageIO.SaveToTmpFile(surface, new SurfaceOutputSettings(OutputFormat.png, 100, false), null); string html = GetHtmlString(surface, tmpFile); dataObject.SetText(html, TextDataFormat.Html); } @@ -942,11 +1076,11 @@ EndSelection:<<<<<<<4 // Check if we can use the previously used image if (imageToSave.PixelFormat != PixelFormat.Format8bppIndexed) { - ImageOutput.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings); + ImageIO.SaveToStream(imageToSave, surface, tmpPngStream, pngOutputSettings); } else { - ImageOutput.SaveToStream(surface, tmpPngStream, pngOutputSettings); + ImageIO.SaveToStream(surface, tmpPngStream, pngOutputSettings); } html = GetHtmlDataUrlString(surface, tmpPngStream); @@ -1125,15 +1259,15 @@ EndSelection:<<<<<<<4 public static IEnumerable GetImageFilenames(IDataObject dataObject) { string[] dropFileNames = (string[])dataObject.GetData(DataFormats.FileDrop); - if (dropFileNames != null && dropFileNames.Length > 0) - { - return dropFileNames - .Where(filename => !string.IsNullOrEmpty(filename)) - .Where(Path.HasExtension) - .Where(filename => ImageHelper.StreamConverters.Keys.Contains(Path.GetExtension(filename).ToLowerInvariant().Substring(1))); - } + if (dropFileNames is not { Length: > 0 }) return Enumerable.Empty(); + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + + var supportedExtensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).ToList(); + return dropFileNames + .Where(filename => !string.IsNullOrEmpty(filename)) + .Where(Path.HasExtension) + .Where(filename => supportedExtensions.Contains(Path.GetExtension(filename))); - return Enumerable.Empty(); } /// diff --git a/src/Greenshot.Base/Core/Enums/ExifOrientations.cs b/src/Greenshot.Base/Core/Enums/ExifOrientations.cs new file mode 100644 index 000000000..b566619da --- /dev/null +++ b/src/Greenshot.Base/Core/Enums/ExifOrientations.cs @@ -0,0 +1,36 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Core.Enums +{ + internal enum ExifOrientations : byte + { + Unknown = 0, + TopLeft = 1, + TopRight = 2, + BottomRight = 3, + BottomLeft = 4, + LeftTop = 5, + RightTop = 6, + RightBottom = 7, + LeftBottom = 8, + } +} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/Enums/OutputFormat.cs b/src/Greenshot.Base/Core/Enums/OutputFormat.cs index 64d8a614b..6e2353eb8 100644 --- a/src/Greenshot.Base/Core/Enums/OutputFormat.cs +++ b/src/Greenshot.Base/Core/Enums/OutputFormat.cs @@ -31,6 +31,7 @@ namespace Greenshot.Base.Core.Enums jpg, png, tiff, + jxr, greenshot, ico } diff --git a/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerExtensions.cs b/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerExtensions.cs new file mode 100644 index 000000000..8941c7184 --- /dev/null +++ b/src/Greenshot.Base/Core/FileFormatHandlers/FileFormatHandlerExtensions.cs @@ -0,0 +1,163 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Base.Core.FileFormatHandlers +{ + /// + /// This is the registry where all IFileFormatHandler are registered and can be used + /// + public static class FileFormatHandlerExtensions + { + /// + /// Make sure we handle the input extension always the same, by "normalizing" it + /// + /// string + /// string + public static string NormalizeExtension(string extension) + { + if (string.IsNullOrEmpty(extension)) + { + return null; + } + + extension = extension.ToLowerInvariant(); + return !extension.StartsWith(".") ? $".{extension}" : extension; + } + + /// + /// Return the extensions that the provided IFileFormatHandlers can accept for the specified action + /// + /// IEnumerable{IFileFormatHandler} + /// + /// + public static IEnumerable ExtensionsFor(this IEnumerable fileFormatHandlers, FileFormatHandlerActions fileFormatHandlerAction) + { + return fileFormatHandlers.Where(ffh => ffh.SupportedExtensions.ContainsKey(fileFormatHandlerAction)).SelectMany(ffh => ffh.SupportedExtensions[fileFormatHandlerAction]).Distinct().OrderBy(e => e); + } + + /// + /// Extension method to check if a certain IFileFormatHandler supports a certain action with a specific extension + /// + /// IFileFormatHandler + /// FileFormatHandlerActions + /// string + /// bool + public static bool Supports(this IFileFormatHandler fileFormatHandler, FileFormatHandlerActions fileFormatHandlerAction, string extension) + { + extension = NormalizeExtension(extension); + return fileFormatHandler.SupportedExtensions.ContainsKey(fileFormatHandlerAction) && fileFormatHandler.SupportedExtensions[fileFormatHandlerAction].Contains(extension); + } + + /// + /// This wrapper method for TrySaveToStream will do: + /// Find all the IFileFormatHandler which support the action for the supplied extension. + /// Take the first, to call the TrySaveToStream on. + /// + /// IEnumerable{IFileFormatHandler} + /// Bitmap + /// Stream + /// string + /// ISurface + /// bool + public static bool TrySaveToStream(this IEnumerable fileFormatHandlers, Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null) + { + extension = NormalizeExtension(extension); + + var saveFileFormatHandlers = fileFormatHandlers + .Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension)) + .OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension)).ToList(); + + if (!saveFileFormatHandlers.Any()) + { + return false; + } + + foreach (var fileFormatHandler in saveFileFormatHandlers) + { + if (fileFormatHandler.TrySaveToStream(bitmap, destination, extension, surface)) + { + return true; + } + } + + return false; + } + + /// + /// Try to load a drawable container from the stream + /// + /// IEnumerable{IFileFormatHandler} + /// Stream + /// string + /// ISurface + /// IEnumerable{IDrawableContainer} + public static IEnumerable LoadDrawablesFromStream(this IEnumerable fileFormatHandlers, Stream stream, string extension, ISurface parentSurface = null) + { + extension = NormalizeExtension(extension); + + var loadfileFormatHandler = fileFormatHandlers + .Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadDrawableFromStream, extension)) + .OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadDrawableFromStream, extension)) + .FirstOrDefault(); + + if (loadfileFormatHandler != null) + { + return loadfileFormatHandler.LoadDrawablesFromStream(stream, extension, parentSurface); + } + + return Enumerable.Empty(); + } + + /// + /// Try to load a Bitmap from the stream + /// + /// IEnumerable{IFileFormatHandler} + /// Stream + /// string + /// Bitmap out + /// bool true if it was successful + public static bool TryLoadFromStream(this IEnumerable fileFormatHandlers, Stream stream, string extension, out Bitmap bitmap) + { + extension = NormalizeExtension(extension); + + var loadFileFormatHandler = fileFormatHandlers + .Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension)) + .OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension)) + .FirstOrDefault(); + + if (loadFileFormatHandler == null) + { + bitmap = null; + return false; + } + + return loadFileFormatHandler.TryLoadFromStream(stream, extension, out bitmap); + } + } +} diff --git a/src/Greenshot.Base/Core/IImage.cs b/src/Greenshot.Base/Core/IImage.cs index d6b30c667..20aa320d9 100644 --- a/src/Greenshot.Base/Core/IImage.cs +++ b/src/Greenshot.Base/Core/IImage.cs @@ -61,7 +61,7 @@ namespace Greenshot.Base.Core float HorizontalResolution { get; } /// - /// Unterlying image, or an on demand rendered version with different attributes as the original + /// Underlying image, or an on demand rendered version with different attributes as the original /// Image Image { get; } } diff --git a/src/Greenshot.Base/Core/ImageHelper.cs b/src/Greenshot.Base/Core/ImageHelper.cs index 7565694e3..a4055f2c9 100644 --- a/src/Greenshot.Base/Core/ImageHelper.cs +++ b/src/Greenshot.Base/Core/ImageHelper.cs @@ -24,28 +24,24 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; -using System.IO; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using Greenshot.Base.Core.Enums; using Greenshot.Base.Effects; using Greenshot.Base.IniFile; -using Greenshot.Base.Interfaces; using Greenshot.Base.UnmanagedHelpers; using log4net; +using Brush = System.Drawing.Brush; +using Color = System.Drawing.Color; +using Matrix = System.Drawing.Drawing2D.Matrix; +using Pen = System.Drawing.Pen; +using PixelFormat = System.Drawing.Imaging.PixelFormat; +using Point = System.Drawing.Point; +using Size = System.Drawing.Size; namespace Greenshot.Base.Core { - internal enum ExifOrientations : byte - { - Unknown = 0, - TopLeft = 1, - TopRight = 2, - BottomRight = 3, - BottomLeft = 4, - LeftTop = 5, - RightTop = 6, - RightBottom = 7, - LeftBottom = 8, - } - /// /// Description of ImageHelper. /// @@ -55,83 +51,6 @@ namespace Greenshot.Base.Core private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); private const int ExifOrientationId = 0x0112; - static ImageHelper() - { - StreamConverters["greenshot"] = (stream, s) => - { - var surface = SimpleServiceProvider.Current.GetInstance>().Invoke(); - return surface.GetImageForExport(); - }; - - // Add a SVG converter - StreamConverters["svg"] = (stream, s) => - { - stream.Position = 0; - try - { - return SvgImage.FromStream(stream).Image; - } - catch (Exception ex) - { - Log.Error("Can't load SVG", ex); - } - - return null; - }; - - static Image DefaultConverter(Stream stream, string s) - { - stream.Position = 0; - using var tmpImage = Image.FromStream(stream, true, true); - Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - return Clone(tmpImage, PixelFormat.Format32bppArgb); - } - - // Fallback - StreamConverters[string.Empty] = DefaultConverter; - StreamConverters["gif"] = DefaultConverter; - StreamConverters["bmp"] = DefaultConverter; - StreamConverters["jpg"] = DefaultConverter; - StreamConverters["jpeg"] = DefaultConverter; - StreamConverters["png"] = DefaultConverter; - StreamConverters["wmf"] = DefaultConverter; - - StreamConverters["ico"] = (stream, extension) => - { - // Icon logic, try to get the Vista icon, else the biggest possible - try - { - using Image tmpImage = ExtractVistaIcon(stream); - if (tmpImage != null) - { - return Clone(tmpImage, PixelFormat.Format32bppArgb); - } - } - catch (Exception vistaIconException) - { - Log.Warn("Can't read icon", vistaIconException); - } - - try - { - // No vista icon, try normal icon - stream.Position = 0; - // We create a copy of the bitmap, so everything else can be disposed - using Icon tmpIcon = new Icon(stream, new Size(1024, 1024)); - using Image tmpImage = tmpIcon.ToBitmap(); - return Clone(tmpImage, PixelFormat.Format32bppArgb); - } - catch (Exception iconException) - { - Log.Warn("Can't read icon", iconException); - } - - stream.Position = 0; - return DefaultConverter(stream, extension); - }; - } - - public static IDictionary> StreamConverters { get; } = new Dictionary>(); /// /// Make sure the image is orientated correctly @@ -371,127 +290,6 @@ namespace Greenshot.Base.Core return cropRectangle; } - /// - /// Load an image from file - /// - /// - /// - public static Image LoadImage(string filename) - { - if (string.IsNullOrEmpty(filename)) - { - return null; - } - - if (!File.Exists(filename)) - { - return null; - } - - Image fileImage; - Log.InfoFormat("Loading image from file {0}", filename); - // Fixed lock problem Bug #3431881 - using (Stream imageFileStream = File.OpenRead(filename)) - { - fileImage = FromStream(imageFileStream, Path.GetExtension(filename)); - } - - if (fileImage != null) - { - Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat, - fileImage.HorizontalResolution, fileImage.VerticalResolution); - } - - return fileImage; - } - - /// - /// Based on: https://www.codeproject.com/KB/cs/IconExtractor.aspx - /// And a hint from: https://www.codeproject.com/KB/cs/IconLib.aspx - /// - /// Stream with the icon information - /// Bitmap with the Vista Icon (256x256) - private static Bitmap ExtractVistaIcon(Stream iconStream) - { - const int sizeIconDir = 6; - const int sizeIconDirEntry = 16; - Bitmap bmpPngExtracted = null; - try - { - byte[] srcBuf = new byte[iconStream.Length]; - iconStream.Read(srcBuf, 0, (int) iconStream.Length); - int iCount = BitConverter.ToInt16(srcBuf, 4); - for (int iIndex = 0; iIndex < iCount; iIndex++) - { - int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex]; - int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1]; - if (iWidth == 0 && iHeight == 0) - { - int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); - int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); - using MemoryStream destStream = new MemoryStream(); - destStream.Write(srcBuf, iImageOffset, iImageSize); - destStream.Seek(0, SeekOrigin.Begin); - bmpPngExtracted = new Bitmap(destStream); // This is PNG! :) - break; - } - } - } - catch - { - return null; - } - - return bmpPngExtracted; - } - - /// - /// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx - /// - /// The file (EXE or DLL) to get the icon from - /// Index of the icon - /// true if the large icon is wanted - /// Icon - public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) - { - Shell32.ExtractIconEx(location, index, out var large, out var small, 1); - Icon returnIcon = null; - bool isLarge = false; - bool isSmall = false; - try - { - if (takeLarge && !IntPtr.Zero.Equals(large)) - { - returnIcon = Icon.FromHandle(large); - isLarge = true; - } - else if (!IntPtr.Zero.Equals(small)) - { - returnIcon = Icon.FromHandle(small); - isSmall = true; - } - else if (!IntPtr.Zero.Equals(large)) - { - returnIcon = Icon.FromHandle(large); - isLarge = true; - } - } - finally - { - if (isLarge && !IntPtr.Zero.Equals(small)) - { - User32.DestroyIcon(small); - } - - if (isSmall && !IntPtr.Zero.Equals(large)) - { - User32.DestroyIcon(large); - } - } - - return returnIcon; - } - /// /// Apply the effect to the bitmap /// @@ -563,8 +361,7 @@ namespace Greenshot.Base.Core /// Changed bitmap public static Image CreateTornEdge(Image sourceImage, int toothHeight, int horizontalToothRange, int verticalToothRange, bool[] edges) { - Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, - sourceImage.VerticalResolution); + Image returnImage = CreateEmpty(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb, Color.Empty, sourceImage.HorizontalResolution, sourceImage.VerticalResolution); using (var path = new GraphicsPath()) { Random random = new Random(); @@ -1396,7 +1193,7 @@ namespace Greenshot.Base.Core } // If no pixelformat is supplied - if (PixelFormat.DontCare == targetFormat || PixelFormat.Undefined == targetFormat) + if (targetFormat is PixelFormat.DontCare or PixelFormat.Undefined) { if (SupportsPixelFormat(sourceImage.PixelFormat)) { @@ -1517,10 +1314,10 @@ namespace Greenshot.Base.Core /// /// /// The color to fill with, or Color.Empty to take the default depending on the pixel format - /// - /// + /// float + /// float /// Bitmap - public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution, float verticalResolution) + public static Bitmap CreateEmpty(int width, int height, PixelFormat format, Color backgroundColor, float horizontalResolution = 96f, float verticalResolution = 96f) { // Create a new "clean" image Bitmap newImage = new Bitmap(width, height, format); @@ -1709,100 +1506,108 @@ namespace Greenshot.Base.Core return newImage; } - + /// - /// Load a Greenshot surface from a stream + /// Rotate the image /// - /// Stream - /// - /// ISurface - public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface) + /// Input image + /// Angle in degrees + /// Rotated image + public static Image Rotate(this Image image, float rotationAngle) { - Image fileImage; - // Fixed problem that the bitmap stream is disposed... by Cloning the image - // This also ensures the bitmap is correctly created + var bitmap = CreateEmptyLike(image, Color.Transparent); - // We create a copy of the bitmap, so everything else can be disposed - surfaceFileStream.Position = 0; - using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) - { - Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - fileImage = Clone(tmpImage); - } + using var graphics = Graphics.FromImage(bitmap); + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) - const int markerSize = 14; - surfaceFileStream.Seek(-markerSize, SeekOrigin.End); - using (StreamReader streamReader = new StreamReader(surfaceFileStream)) - { - var greenshotMarker = streamReader.ReadToEnd(); - if (!greenshotMarker.StartsWith("Greenshot")) - { - throw new ArgumentException("Stream is not a Greenshot file!"); - } + graphics.TranslateTransform((float)bitmap.Width / 2, (float)bitmap.Height / 2); + graphics.RotateTransform(rotationAngle); + graphics.TranslateTransform(-(float)bitmap.Width / 2, -(float)bitmap.Height / 2); - Log.InfoFormat("Greenshot file format: {0}", greenshotMarker); - const int filesizeLocation = 8 + markerSize; - surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); - using BinaryReader reader = new BinaryReader(surfaceFileStream); - long bytesWritten = reader.ReadInt64(); - surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End); - returnSurface.LoadElementsFromStream(surfaceFileStream); - } + graphics.DrawImage(image, new Point(0, 0)); - if (fileImage != null) - { - returnSurface.Image = fileImage; - Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat, - fileImage.HorizontalResolution, fileImage.VerticalResolution); - } - - return returnSurface; + return bitmap; } /// - /// Create an image from a stream, if an extension is supplied more formats are supported. + /// Map a System.Drawing.Imaging.PixelFormat to a System.Windows.Media.PixelFormat /// - /// Stream - /// - /// Image - public static Image FromStream(Stream stream, string extension = null) + /// System.Drawing.Imaging.PixelFormat + /// System.Windows.Media.PixelFormat + /// + public static System.Windows.Media.PixelFormat Map(this PixelFormat pixelFormat) => + pixelFormat switch + { + PixelFormat.Format32bppArgb => PixelFormats.Bgra32, + PixelFormat.Format24bppRgb => PixelFormats.Bgr24, + PixelFormat.Format32bppRgb => PixelFormats.Bgr32, + _ => throw new NotSupportedException($"Can't map {pixelFormat}.") + }; + + /// + /// Map a System.Windows.Media.PixelFormat to a System.Drawing.Imaging.PixelFormat + /// + /// System.Windows.Media.PixelFormat + /// System.Drawing.Imaging.PixelFormat + /// + public static PixelFormat Map(this System.Windows.Media.PixelFormat pixelFormat) { - if (stream == null) + if (pixelFormat == PixelFormats.Bgra32) { - return null; + return PixelFormat.Format32bppArgb; + } + if (pixelFormat == PixelFormats.Bgr24) + { + return PixelFormat.Format24bppRgb; + } + if (pixelFormat == PixelFormats.Bgr32) + { + return PixelFormat.Format32bppRgb; } - if (!string.IsNullOrEmpty(extension)) + throw new NotSupportedException($"Can't map {pixelFormat}."); + } + + /// + /// Convert a Bitmap to a BitmapSource + /// + /// Bitmap + /// BitmapSource + public static BitmapSource ToBitmapSource(this Bitmap bitmap) + { + var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); + + BitmapSource bitmapSource; + try { - extension = extension.Replace(".", string.Empty); + bitmapSource = BitmapSource.Create( + bitmapData.Width, bitmapData.Height, + bitmap.HorizontalResolution, bitmap.VerticalResolution, + bitmap.PixelFormat.Map(), null, + bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride); + } + finally + { + bitmap.UnlockBits(bitmapData); } - // Make sure we can try multiple times - if (!stream.CanSeek) - { - var memoryStream = new MemoryStream(); - stream.CopyTo(memoryStream); - stream = memoryStream; - } + return bitmapSource; + } - Image returnImage = null; - if (StreamConverters.TryGetValue(extension ?? string.Empty, out var converter)) - { - returnImage = converter(stream, extension); - } + /// + /// Convert a BitmapSource to a Bitmap + /// + /// BitmapSource + /// Bitmap + public static Bitmap ToBitmap(this BitmapSource bitmapSource) + { + var pixelFormat = bitmapSource.Format.Map(); - // Fallback - if (returnImage == null) - { - // We create a copy of the bitmap, so everything else can be disposed - stream.Position = 0; - using var tmpImage = Image.FromStream(stream, true, true); - Log.DebugFormat("Loaded bitmap with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); - returnImage = Clone(tmpImage, PixelFormat.Format32bppArgb); - } - - return returnImage; + Bitmap bitmap = new Bitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight, pixelFormat); + BitmapData data = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.WriteOnly, pixelFormat); + bitmapSource.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); + bitmap.UnlockBits(data); + return bitmap; } } } \ No newline at end of file diff --git a/src/Greenshot.Base/Core/ImageOutput.cs b/src/Greenshot.Base/Core/ImageIO.cs similarity index 60% rename from src/Greenshot.Base/Core/ImageOutput.cs rename to src/Greenshot.Base/Core/ImageIO.cs index 39c4896c1..16f69c0fe 100644 --- a/src/Greenshot.Base/Core/ImageOutput.cs +++ b/src/Greenshot.Base/Core/ImageIO.cs @@ -20,12 +20,11 @@ */ using System; -using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; @@ -33,20 +32,21 @@ using System.Text.RegularExpressions; using System.Windows.Forms; using Greenshot.Base.Controls; using Greenshot.Base.Core.Enums; +using Greenshot.Base.Core.FileFormatHandlers; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Base.UnmanagedHelpers; using log4net; -using Encoder = System.Drawing.Imaging.Encoder; namespace Greenshot.Base.Core { /// /// Description of ImageOutput. /// - public static class ImageOutput + public static class ImageIO { - private static readonly ILog Log = LogManager.GetLogger(typeof(ImageOutput)); + private static readonly ILog Log = LogManager.GetLogger(typeof(ImageIO)); private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); private static readonly int PROPERTY_TAG_SOFTWARE_USED = 0x0131; private static readonly Cache TmpFileCache = new Cache(10 * 60 * 60, RemoveExpiredTmpFile); @@ -54,7 +54,7 @@ namespace Greenshot.Base.Core /// /// Creates a PropertyItem (Metadata) to store with the image. /// For the possible ID's see: https://msdn.microsoft.com/de-de/library/system.drawing.imaging.propertyitem.id(v=vs.80).aspx - /// This code uses Reflection to create a PropertyItem, although it's not adviced it's not as stupid as having a image in the project so we can read a PropertyItem from that! + /// This code uses Reflection to create a PropertyItem, although it's not advised it's not as stupid as having a image in the project so we can read a PropertyItem from that! /// /// ID /// Text @@ -124,102 +124,21 @@ namespace Greenshot.Base.Core try { - var imageFormat = outputSettings.Format switch - { - OutputFormat.bmp => ImageFormat.Bmp, - OutputFormat.gif => ImageFormat.Gif, - OutputFormat.jpg => ImageFormat.Jpeg, - OutputFormat.tiff => ImageFormat.Tiff, - OutputFormat.ico => ImageFormat.Icon, - _ => ImageFormat.Png - }; - Log.DebugFormat("Saving image to stream with Format {0} and PixelFormat {1}", imageFormat, imageToSave.PixelFormat); - - // Check if we want to use a memory stream, to prevent issues with non seakable streams + // Check if we want to use a memory stream, to prevent issues with non seekable streams // The save is made to the targetStream, this is directed to either the MemoryStream or the original Stream targetStream = stream; if (!stream.CanSeek) { useMemoryStream = true; - Log.Warn("Using memorystream prevent an issue with saving to a non seekable stream."); + Log.Warn("Using a memory stream prevent an issue with saving to a non seekable stream."); memoryStream = new MemoryStream(); targetStream = memoryStream; } - if (Equals(imageFormat, ImageFormat.Jpeg)) + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + if (!fileFormatHandlers.TrySaveToStream(imageToSave as Bitmap, targetStream, outputSettings.Format.ToString(), surface, outputSettings)) { - bool foundEncoder = false; - foreach (ImageCodecInfo imageCodec in ImageCodecInfo.GetImageEncoders()) - { - if (imageCodec.FormatID == imageFormat.Guid) - { - EncoderParameters parameters = new EncoderParameters(1) - { - Param = - { - [0] = new EncoderParameter(Encoder.Quality, outputSettings.JPGQuality) - } - }; - // Removing transparency if it's not supported in the output - if (Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) - { - Image nonAlphaImage = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); - AddTag(nonAlphaImage); - nonAlphaImage.Save(targetStream, imageCodec, parameters); - nonAlphaImage.Dispose(); - } - else - { - AddTag(imageToSave); - imageToSave.Save(targetStream, imageCodec, parameters); - } - - foundEncoder = true; - break; - } - } - - if (!foundEncoder) - { - throw new ApplicationException("No JPG encoder found, this should not happen."); - } - } - else if (Equals(imageFormat, ImageFormat.Icon)) - { - // FEATURE-916: Added Icon support - IList images = new List - { - imageToSave - }; - WriteIcon(stream, images); - } - else - { - bool needsDispose = false; - // Removing transparency if it's not supported in the output - if (!Equals(imageFormat, ImageFormat.Png) && Image.IsAlphaPixelFormat(imageToSave.PixelFormat)) - { - imageToSave = ImageHelper.Clone(imageToSave, PixelFormat.Format24bppRgb); - needsDispose = true; - } - - AddTag(imageToSave); - // Added for OptiPNG - bool processed = false; - if (Equals(imageFormat, ImageFormat.Png) && !string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) - { - processed = ProcessPngImageExternally(imageToSave, targetStream); - } - - if (!processed) - { - imageToSave.Save(targetStream, imageFormat); - } - - if (needsDispose) - { - imageToSave.Dispose(); - } + return; } // If we used a memory stream, we need to stream the memory stream to the original stream. @@ -227,21 +146,6 @@ namespace Greenshot.Base.Core { memoryStream.WriteTo(stream); } - - // Output the surface elements, size and marker to the stream - if (outputSettings.Format != OutputFormat.greenshot) - { - return; - } - - using MemoryStream tmpStream = new MemoryStream(); - long bytesWritten = surface.SaveElementsToStream(tmpStream); - using BinaryWriter writer = new BinaryWriter(tmpStream); - writer.Write(bytesWritten); - Version v = Assembly.GetExecutingAssembly().GetName().Version; - byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); - writer.Write(marker); - tmpStream.WriteTo(stream); } finally { @@ -249,89 +153,6 @@ namespace Greenshot.Base.Core } } - /// - /// Write the passed Image to a tmp-file and call an external process, than read the file back and write it to the targetStream - /// - /// Image to pass to the external process - /// stream to write the processed image to - /// - private static bool ProcessPngImageExternally(Image imageToProcess, Stream targetStream) - { - if (string.IsNullOrEmpty(CoreConfig.OptimizePNGCommand)) - { - return false; - } - - if (!File.Exists(CoreConfig.OptimizePNGCommand)) - { - Log.WarnFormat("Can't find 'OptimizePNGCommand' {0}", CoreConfig.OptimizePNGCommand); - return false; - } - - string tmpFileName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".png"); - try - { - using (FileStream tmpStream = File.Create(tmpFileName)) - { - Log.DebugFormat("Writing png to tmp file: {0}", tmpFileName); - imageToProcess.Save(tmpStream, ImageFormat.Png); - if (Log.IsDebugEnabled) - { - Log.DebugFormat("File size before processing {0}", new FileInfo(tmpFileName).Length); - } - } - - if (Log.IsDebugEnabled) - { - Log.DebugFormat("Starting : {0}", CoreConfig.OptimizePNGCommand); - } - - ProcessStartInfo processStartInfo = new ProcessStartInfo(CoreConfig.OptimizePNGCommand) - { - Arguments = string.Format(CoreConfig.OptimizePNGCommandArguments, tmpFileName), - CreateNoWindow = true, - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false - }; - using Process process = Process.Start(processStartInfo); - if (process != null) - { - process.WaitForExit(); - if (process.ExitCode == 0) - { - if (Log.IsDebugEnabled) - { - Log.DebugFormat("File size after processing {0}", new FileInfo(tmpFileName).Length); - Log.DebugFormat("Reading back tmp file: {0}", tmpFileName); - } - - byte[] processedImage = File.ReadAllBytes(tmpFileName); - targetStream.Write(processedImage, 0, processedImage.Length); - return true; - } - - Log.ErrorFormat("Error while processing PNG image: {0}", process.ExitCode); - Log.ErrorFormat("Output: {0}", process.StandardOutput.ReadToEnd()); - Log.ErrorFormat("Error: {0}", process.StandardError.ReadToEnd()); - } - } - catch (Exception e) - { - Log.Error("Error while processing PNG image: ", e); - } - finally - { - if (File.Exists(tmpFileName)) - { - Log.DebugFormat("Cleaning up tmp file: {0}", tmpFileName); - File.Delete(tmpFileName); - } - } - - return false; - } - /// /// Create an image from a surface with the settings from the output settings applied /// @@ -429,20 +250,18 @@ namespace Greenshot.Base.Core /// Add the greenshot property! /// /// - private static void AddTag(Image imageToSave) + public static void AddTag(this Image imageToSave) { // Create meta-data PropertyItem softwareUsedPropertyItem = CreatePropertyItem(PROPERTY_TAG_SOFTWARE_USED, "Greenshot"); - if (softwareUsedPropertyItem != null) + if (softwareUsedPropertyItem == null) return; + try { - try - { - imageToSave.SetPropertyItem(softwareUsedPropertyItem); - } - catch (Exception) - { - Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id); - } + imageToSave.SetPropertyItem(softwareUsedPropertyItem); + } + catch (Exception) + { + Log.WarnFormat("Couldn't set property {0}", softwareUsedPropertyItem.Id); } } @@ -463,7 +282,7 @@ namespace Greenshot.Base.Core // Fixed lock problem Bug #3431881 using (Stream surfaceFileStream = File.OpenRead(fullPath)) { - returnSurface = ImageHelper.LoadGreenshotSurface(surfaceFileStream, returnSurface); + returnSurface = LoadGreenshotSurface(surfaceFileStream, returnSurface); } if (returnSurface != null) @@ -547,27 +366,25 @@ namespace Greenshot.Base.Core using (SaveImageFileDialog saveImageFileDialog = new SaveImageFileDialog(captureDetails)) { DialogResult dialogResult = saveImageFileDialog.ShowDialog(); - if (dialogResult.Equals(DialogResult.OK)) + if (!dialogResult.Equals(DialogResult.OK)) return returnValue; + try { - try + string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; + SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension)); + if (CoreConfig.OutputFilePromptQuality) { - string fileNameWithExtension = saveImageFileDialog.FileNameWithExtension; - SurfaceOutputSettings outputSettings = new SurfaceOutputSettings(FormatForFilename(fileNameWithExtension)); - if (CoreConfig.OutputFilePromptQuality) - { - QualityDialog qualityDialog = new QualityDialog(outputSettings); - qualityDialog.ShowDialog(); - } + QualityDialog qualityDialog = new QualityDialog(outputSettings); + qualityDialog.ShowDialog(); + } - // TODO: For now we always overwrite, should be changed - Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); - returnValue = fileNameWithExtension; - IniConfig.Save(); - } - catch (ExternalException) - { - MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error")); - } + // TODO: For now we always overwrite, should be changed + Save(surface, fileNameWithExtension, true, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); + returnValue = fileNameWithExtension; + IniConfig.Save(); + } + catch (ExternalException) + { + MessageBox.Show(Language.GetFormattedString("error_nowriteaccess", saveImageFileDialog.FileName).Replace(@"\\", @"\"), Language.GetString("error")); } } @@ -709,91 +526,218 @@ namespace Greenshot.Base.Core } /// - /// Write the images to the stream as icon - /// Every image is resized to 256x256 (but the content maintains the aspect ratio) + /// Load an image from file /// - /// Stream to write to - /// List of images - public static void WriteIcon(Stream stream, IList images) + /// + /// + public static Image LoadImage(string filename) { - var binaryWriter = new BinaryWriter(stream); - // - // ICONDIR structure - // - binaryWriter.Write((short) 0); // reserved - binaryWriter.Write((short) 1); // image type (icon) - binaryWriter.Write((short) images.Count); // number of images - - IList imageSizes = new List(); - IList encodedImages = new List(); - foreach (var image in images) + if (string.IsNullOrEmpty(filename)) { - // Pick the best fit - var sizes = new[] + return null; + } + + if (!File.Exists(filename)) + { + return null; + } + + Image fileImage; + Log.InfoFormat("Loading image from file {0}", filename); + // Fixed lock problem Bug #3431881 + using (Stream imageFileStream = File.OpenRead(filename)) + { + fileImage = FromStream(imageFileStream, Path.GetExtension(filename)); + } + + if (fileImage != null) + { + Log.InfoFormat("Information about file {0}: {1}x{2}-{3} Resolution {4}x{5}", filename, fileImage.Width, fileImage.Height, fileImage.PixelFormat, + fileImage.HorizontalResolution, fileImage.VerticalResolution); + } + + return fileImage; + } + + /// + /// Based on: https://www.codeproject.com/KB/cs/IconExtractor.aspx + /// And a hint from: https://www.codeproject.com/KB/cs/IconLib.aspx + /// + /// Stream with the icon information + /// Bitmap with the Vista Icon (256x256) + private static Bitmap ExtractVistaIcon(Stream iconStream) + { + const int sizeIconDir = 6; + const int sizeIconDirEntry = 16; + Bitmap bmpPngExtracted = null; + try + { + byte[] srcBuf = new byte[iconStream.Length]; + iconStream.Read(srcBuf, 0, (int)iconStream.Length); + int iCount = BitConverter.ToInt16(srcBuf, 4); + for (int iIndex = 0; iIndex < iCount; iIndex++) { - 16, 32, 48 - }; - int size = 256; - foreach (var possibleSize in sizes) - { - if (image.Width <= possibleSize && image.Height <= possibleSize) + int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex]; + int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1]; + if (iWidth == 0 && iHeight == 0) { - size = possibleSize; + int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); + int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); + using MemoryStream destStream = new MemoryStream(); + destStream.Write(srcBuf, iImageOffset, iImageSize); + destStream.Seek(0, SeekOrigin.Begin); + bmpPngExtracted = new Bitmap(destStream); // This is PNG! :) break; } } + } + catch + { + return null; + } - var imageStream = new MemoryStream(); - if (image.Width == size && image.Height == size) + return bmpPngExtracted; + } + + /// + /// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx + /// + /// The file (EXE or DLL) to get the icon from + /// Index of the icon + /// true if the large icon is wanted + /// Icon + public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) + { + Shell32.ExtractIconEx(location, index, out var large, out var small, 1); + Icon returnIcon = null; + bool isLarge = false; + bool isSmall = false; + try + { + if (takeLarge && !IntPtr.Zero.Equals(large)) { - using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); - clonedImage.Save(imageStream, ImageFormat.Png); - imageSizes.Add(new Size(size, size)); + returnIcon = Icon.FromHandle(large); + isLarge = true; } - else + else if (!IntPtr.Zero.Equals(small)) { - // Resize to the specified size, first make sure the image is 32bpp - using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); - using var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null); - resizedImage.Save(imageStream, ImageFormat.Png); - imageSizes.Add(resizedImage.Size); + returnIcon = Icon.FromHandle(small); + isSmall = true; + } + else if (!IntPtr.Zero.Equals(large)) + { + returnIcon = Icon.FromHandle(large); + isLarge = true; + } + } + finally + { + if (isLarge && !IntPtr.Zero.Equals(small)) + { + User32.DestroyIcon(small); } - imageStream.Seek(0, SeekOrigin.Begin); - encodedImages.Add(imageStream); + if (isSmall && !IntPtr.Zero.Equals(large)) + { + User32.DestroyIcon(large); + } } - // - // ICONDIRENTRY structure - // - const int iconDirSize = 6; - const int iconDirEntrySize = 16; + return returnIcon; + } - var offset = iconDirSize + (images.Count * iconDirEntrySize); - for (int i = 0; i < images.Count; i++) + /// + /// Create an image from a stream, if an extension is supplied more formats are supported. + /// + /// Stream + /// + /// Image + public static Image FromStream(Stream stream, string extension = null) + { + if (stream == null) { - var imageSize = imageSizes[i]; - // Write the width / height, 0 means 256 - binaryWriter.Write(imageSize.Width == 256 ? (byte) 0 : (byte) imageSize.Width); - binaryWriter.Write(imageSize.Height == 256 ? (byte) 0 : (byte) imageSize.Height); - binaryWriter.Write((byte) 0); // no pallete - binaryWriter.Write((byte) 0); // reserved - binaryWriter.Write((short) 0); // no color planes - binaryWriter.Write((short) 32); // 32 bpp - binaryWriter.Write((int) encodedImages[i].Length); // image data length - binaryWriter.Write(offset); - offset += (int) encodedImages[i].Length; + return null; } - binaryWriter.Flush(); - // - // Write image data - // - foreach (var encodedImage in encodedImages) + if (!string.IsNullOrEmpty(extension)) { - encodedImage.WriteTo(stream); - encodedImage.Dispose(); + extension = extension.Replace(".", string.Empty); } + + var startingPosition = stream.Position; + + // Make sure we can try multiple times + if (!stream.CanSeek) + { + var memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + stream = memoryStream; + // As we are if a different stream, which starts at 0, change the starting position + startingPosition = 0; + } + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + foreach (var fileFormatHandler in fileFormatHandlers + .Where(ffh => ffh.Supports(FileFormatHandlerActions.LoadFromStream, extension)) + .OrderBy(ffh => ffh.PriorityFor(FileFormatHandlerActions.LoadFromStream, extension))) + { + stream.Seek(startingPosition, SeekOrigin.Begin); + if (fileFormatHandler.TryLoadFromStream(stream, extension, out var bitmap)) + { + return bitmap; + } + } + + return null; + } + + /// + /// Load a Greenshot surface from a stream + /// + /// Stream + /// + /// ISurface + public static ISurface LoadGreenshotSurface(Stream surfaceFileStream, ISurface returnSurface) + { + Image fileImage; + // Fixed problem that the bitmap stream is disposed... by Cloning the image + // This also ensures the bitmap is correctly created + + // We create a copy of the bitmap, so everything else can be disposed + surfaceFileStream.Position = 0; + using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) + { + Log.DebugFormat("Loaded .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); + fileImage = ImageHelper.Clone(tmpImage); + } + + // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) + const int markerSize = 14; + surfaceFileStream.Seek(-markerSize, SeekOrigin.End); + using (StreamReader streamReader = new StreamReader(surfaceFileStream)) + { + var greenshotMarker = streamReader.ReadToEnd(); + if (!greenshotMarker.StartsWith("Greenshot")) + { + throw new ArgumentException("Stream is not a Greenshot file!"); + } + + Log.InfoFormat("Greenshot file format: {0}", greenshotMarker); + const int filesizeLocation = 8 + markerSize; + surfaceFileStream.Seek(-filesizeLocation, SeekOrigin.End); + using BinaryReader reader = new BinaryReader(surfaceFileStream); + long bytesWritten = reader.ReadInt64(); + surfaceFileStream.Seek(-(bytesWritten + filesizeLocation), SeekOrigin.End); + returnSurface.LoadElementsFromStream(surfaceFileStream); + } + + if (fileImage != null) + { + returnSurface.Image = fileImage; + Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", fileImage.Width, fileImage.Height, fileImage.PixelFormat, + fileImage.HorizontalResolution, fileImage.VerticalResolution); + } + + return returnSurface; } } } \ No newline at end of file diff --git a/src/Greenshot.Base/Core/ImageWrapper.cs b/src/Greenshot.Base/Core/ImageWrapper.cs deleted file mode 100644 index 517249534..000000000 --- a/src/Greenshot.Base/Core/ImageWrapper.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Drawing; -using System.Drawing.Imaging; - -namespace Greenshot.Base.Core -{ - /// - /// Wrap an image, make it resizeable - /// - public class ImageWrapper : IImage - { - // Underlying image, is used to generate a resized version of it when needed - private readonly Image _image; - private Image _imageClone; - - public ImageWrapper(Image image) - { - // Make sure the orientation is set correctly so Greenshot can process the image correctly - ImageHelper.Orientate(image); - _image = image; - Width = _image.Width; - Height = _image.Height; - } - - public void Dispose() - { - _image.Dispose(); - _imageClone?.Dispose(); - } - - /// - /// Height of the image, can be set to change - /// - public int Height { get; set; } - - /// - /// Width of the image, can be set to change. - /// - public int Width { get; set; } - - /// - /// Size of the image - /// - public Size Size => new Size(Width, Height); - - /// - /// Pixelformat of the underlying image - /// - public PixelFormat PixelFormat => Image.PixelFormat; - - public float HorizontalResolution => Image.HorizontalResolution; - public float VerticalResolution => Image.VerticalResolution; - - public Image Image - { - get - { - if (_imageClone == null) - { - if (_image.Height == Height && _image.Width == Width) - { - return _image; - } - } - - if (_imageClone?.Height == Height && _imageClone?.Width == Width) - { - return _imageClone; - } - - // Calculate new image clone - _imageClone?.Dispose(); - _imageClone = ImageHelper.ResizeImage(_image, false, Width, Height, null); - return _imageClone; - } - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/NetworkHelper.cs b/src/Greenshot.Base/Core/NetworkHelper.cs index 5170db504..88cfff569 100644 --- a/src/Greenshot.Base/Core/NetworkHelper.cs +++ b/src/Greenshot.Base/Core/NetworkHelper.cs @@ -24,11 +24,14 @@ using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.IO; +using System.Linq; using System.Net; using System.Text; using System.Text.RegularExpressions; +using Greenshot.Base.Core.FileFormatHandlers; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Plugin; using log4net; @@ -87,24 +90,14 @@ namespace Greenshot.Base.Core } /// - /// Download the uri to Bitmap + /// Download the uri to build an IDrawableContainer /// /// Of an image - /// Bitmap - public static Image DownloadImage(string url) + /// IDrawableContainer + public static IDrawableContainer DownloadImageAsDrawableContainer(string url) { - var extensions = new StringBuilder(); - foreach (var extension in ImageHelper.StreamConverters.Keys) - { - if (string.IsNullOrEmpty(extension)) - { - continue; - } - - extensions.AppendFormat(@"\.{0}|", extension); - } - - extensions.Length--; + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + var extensions = string.Join("|", fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream)); var imageUrlRegex = new Regex($@"(http|https)://.*(?{extensions})"); var match = imageUrlRegex.Match(url); @@ -113,7 +106,12 @@ namespace Greenshot.Base.Core using var memoryStream = GetAsMemoryStream(url); try { - return ImageHelper.FromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null); + var extension = match.Success ? match.Groups["extension"]?.Value : null; + var drawableContainer = fileFormatHandlers.LoadDrawablesFromStream(memoryStream, extension).FirstOrDefault(); + if (drawableContainer != null) + { + return drawableContainer; + } } catch (Exception) { @@ -136,7 +134,71 @@ namespace Greenshot.Base.Core } using var memoryStream2 = GetAsMemoryStream(match.Value); - return ImageHelper.FromStream(memoryStream2, match.Groups["extension"]?.Value); + + var extension = match.Success ? match.Groups["extension"]?.Value : null; + var drawableContainer = fileFormatHandlers.LoadDrawablesFromStream(memoryStream2, extension).FirstOrDefault(); + if (drawableContainer != null) + { + return drawableContainer; + } + } + } + catch (Exception e) + { + Log.Error("Problem downloading the image from: " + url, e); + } + + return null; + } + + /// + /// Download the uri to create a Bitmap + /// + /// Of an image + /// Bitmap + public static Bitmap DownloadImage(string url) + { + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + + var extensions = string.Join("|", fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream)); + + var imageUrlRegex = new Regex($@"(http|https)://.*(?{extensions})"); + var match = imageUrlRegex.Match(url); + try + { + using var memoryStream = GetAsMemoryStream(url); + try + { + if (fileFormatHandlers.TryLoadFromStream(memoryStream, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap)) + { + return bitmap; + } + } + catch (Exception) + { + // If we arrive here, the image loading didn't work, try to see if the response has a http(s) URL to an image and just take this instead. + string content; + using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8, true)) + { + content = streamReader.ReadLine(); + } + + if (string.IsNullOrEmpty(content)) + { + throw; + } + + match = imageUrlRegex.Match(content); + if (!match.Success) + { + throw; + } + + using var memoryStream2 = GetAsMemoryStream(match.Value); + if (fileFormatHandlers.TryLoadFromStream(memoryStream2, match.Success ? match.Groups["extension"]?.Value : null, out var bitmap)) + { + return bitmap; + } } } catch (Exception e) @@ -670,7 +732,7 @@ namespace Greenshot.Base.Core public string ToBase64String(Base64FormattingOptions formattingOptions) { using MemoryStream stream = new MemoryStream(); - ImageOutput.SaveToStream(_surface, stream, _outputSettings); + ImageIO.SaveToStream(_surface, stream, _outputSettings); return Convert.ToBase64String(stream.GetBuffer(), 0, (int) stream.Length, formattingOptions); } @@ -682,7 +744,7 @@ namespace Greenshot.Base.Core public byte[] ToByteArray() { using MemoryStream stream = new MemoryStream(); - ImageOutput.SaveToStream(_surface, stream, _outputSettings); + ImageIO.SaveToStream(_surface, stream, _outputSettings); return stream.ToArray(); } @@ -698,7 +760,7 @@ namespace Greenshot.Base.Core string header = $"--{boundary}\r\nContent-Disposition: form-data; name=\"{name}\"; filename=\"{Filename ?? name}\";\r\nContent-Type: {ContentType}\r\n\r\n"; formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, Encoding.UTF8.GetByteCount(header)); - ImageOutput.SaveToStream(_surface, formDataStream, _outputSettings); + ImageIO.SaveToStream(_surface, formDataStream, _outputSettings); } /// @@ -708,7 +770,7 @@ namespace Greenshot.Base.Core public void WriteToStream(Stream dataStream) { // Write the file data directly to the Stream, rather than serializing it to a string. - ImageOutput.SaveToStream(_surface, dataStream, _outputSettings); + ImageIO.SaveToStream(_surface, dataStream, _outputSettings); } /// diff --git a/src/Greenshot.Base/Core/PluginUtils.cs b/src/Greenshot.Base/Core/PluginUtils.cs index 3d3ec79f2..cb09cd8af 100644 --- a/src/Greenshot.Base/Core/PluginUtils.cs +++ b/src/Greenshot.Base/Core/PluginUtils.cs @@ -158,7 +158,7 @@ namespace Greenshot.Base.Core try { - using (Icon appIcon = ImageHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) + using (Icon appIcon = ImageIO.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) { if (appIcon != null) { diff --git a/src/Greenshot.Base/Core/SimpleServiceProvider.cs b/src/Greenshot.Base/Core/SimpleServiceProvider.cs index bff814540..084f5b1fd 100644 --- a/src/Greenshot.Base/Core/SimpleServiceProvider.cs +++ b/src/Greenshot.Base/Core/SimpleServiceProvider.cs @@ -10,22 +10,19 @@ namespace Greenshot.Base.Core /// public class SimpleServiceProvider : IServiceLocator { - private readonly Dictionary> _services = new Dictionary>(); + private readonly Dictionary> _services = new(); public static IServiceLocator Current { get; } = new SimpleServiceProvider(); - public IEnumerable GetAllInstances() + public IReadOnlyList GetAllInstances() { var typeOfService = typeof(TService); if (!_services.TryGetValue(typeOfService, out var results)) { - yield break; + return Array.Empty(); } - foreach (TService result in results) - { - yield return result; - } + return results.Cast().ToArray(); } public TService GetInstance() diff --git a/src/Greenshot.Base/Core/SvgImage.cs b/src/Greenshot.Base/Core/SvgImage.cs deleted file mode 100644 index 25f98b212..000000000 --- a/src/Greenshot.Base/Core/SvgImage.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using Svg; - -namespace Greenshot.Base.Core -{ - /// - /// Create an image look like of the SVG - /// - public sealed class SvgImage : IImage - { - private readonly SvgDocument _svgDocument; - - private Image _imageClone; - - /// - /// Factory to create via a stream - /// - /// Stream - /// IImage - public static IImage FromStream(Stream stream) - { - return new SvgImage(stream); - } - - /// - /// Default constructor - /// - /// - public SvgImage(Stream stream) - { - _svgDocument = SvgDocument.Open(stream); - Height = (int) _svgDocument.ViewBox.Height; - Width = (int) _svgDocument.ViewBox.Width; - } - - /// - /// Height of the image, can be set to change - /// - public int Height { get; set; } - - /// - /// Width of the image, can be set to change. - /// - public int Width { get; set; } - - /// - /// Size of the image - /// - public Size Size => new Size(Width, Height); - - /// - /// Pixelformat of the underlying image - /// - public PixelFormat PixelFormat => Image.PixelFormat; - - /// - /// Horizontal resolution of the underlying image - /// - public float HorizontalResolution => Image.HorizontalResolution; - - /// - /// Vertical resolution of the underlying image - /// - public float VerticalResolution => Image.VerticalResolution; - - /// - /// Underlying image, or an on demand rendered version with different attributes as the original - /// - public Image Image - { - get - { - if (_imageClone?.Height == Height && _imageClone?.Width == Width) - { - return _imageClone; - } - - // Calculate new image clone - _imageClone?.Dispose(); - _imageClone = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent, 96, 96); - _svgDocument.Draw((Bitmap) _imageClone); - return _imageClone; - } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - _imageClone?.Dispose(); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/WindowDetails.cs b/src/Greenshot.Base/Core/WindowDetails.cs index 0063e3edb..905ab1099 100644 --- a/src/Greenshot.Base/Core/WindowDetails.cs +++ b/src/Greenshot.Base/Core/WindowDetails.cs @@ -782,7 +782,9 @@ namespace Greenshot.Base.Core /// public WindowStyleFlags WindowStyle { - get => (WindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE); + get => unchecked( + (WindowStyleFlags)User32.GetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_STYLE).ToInt64() + ); set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE, new IntPtr((long) value)); } diff --git a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs index 1742b8054..24abc2d25 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs @@ -30,7 +30,14 @@ namespace Greenshot.Base.Interfaces.Drawing { public interface IDrawableContainer : INotifyPropertyChanged, IDisposable { + /// + /// The parent surface where this IDrawableContainer is on + /// ISurface Parent { get; set; } + + /// + /// Is this IDrawableContainer selected on the surface + /// bool Selected { get; set; } int Left { get; set; } @@ -54,15 +61,25 @@ namespace Greenshot.Base.Interfaces.Drawing bool HasFilters { get; } EditStatus Status { get; set; } + void Invalidate(); + bool ClickableAt(int x, int y); + void MoveBy(int x, int y); + void Transform(Matrix matrix); + bool HandleMouseDown(int x, int y); + void HandleMouseUp(int x, int y); + bool HandleMouseMove(int x, int y); + bool InitContent(); + void MakeBoundsChangeUndoable(bool allowMerge); + EditStatus DefaultEditMode { get; } /// diff --git a/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs b/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs new file mode 100644 index 000000000..fdbf72847 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs @@ -0,0 +1,33 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Base.Interfaces.Drawing +{ + public interface IFieldAggregator + { + void UnbindElement(IDrawableContainer dc); + void BindElements(IDrawableContainerList dcs); + void BindElement(IDrawableContainer dc); + IField GetField(IFieldType fieldType); + + event FieldChangedEventHandler FieldChanged; + } +} diff --git a/src/Greenshot.Base/Interfaces/IFileFormatHandler.cs b/src/Greenshot.Base/Interfaces/IFileFormatHandler.cs new file mode 100644 index 000000000..bd5558857 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/IFileFormatHandler.cs @@ -0,0 +1,88 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Plugin; + +namespace Greenshot.Base.Interfaces +{ + /// + /// The possible actions a IFileFormatHandler might support + /// + public enum FileFormatHandlerActions + { + SaveToStream, + LoadFromStream, + LoadDrawableFromStream + } + + /// + /// This interface is for code to implement the loading and saving of certain file formats + /// + public interface IFileFormatHandler + { + /// + /// Registry for all the extensions this IFileFormatHandler support + /// + IDictionary> SupportedExtensions { get; } + + /// + /// Priority (from high int.MinValue, low int.MaxValue) of this IFileFormatHandler for the specified action and extension + /// This should be used to sort the possible IFileFormatHandler + /// + /// FileFormatHandlerActions + /// string + /// int specifying the priority for the action and extension + public int PriorityFor(FileFormatHandlerActions fileFormatHandlerAction, string extension); + + /// + /// Try to save the specified bitmap to the stream in the format belonging to the extension + /// + /// Bitmap + /// Stream + /// extension + /// ISurface with the elements for those file types which can store a surface (.greenshot) + /// SurfaceOutputSettings + /// bool true if it was successful + public bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null); + + /// + /// + /// + /// + /// + /// + /// bool true if it was successful + public bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap); + + /// + /// Try to load a drawable container from the stream + /// + /// Stream + /// string + /// ISurface + /// IEnumerable{IDrawableContainer} + public IEnumerable LoadDrawablesFromStream(Stream stream, string extension, ISurface parentSurface = null); + } +} diff --git a/src/Greenshot.Base/Interfaces/IServiceLocator.cs b/src/Greenshot.Base/Interfaces/IServiceLocator.cs index c22e3463b..5cf1fb529 100644 --- a/src/Greenshot.Base/Interfaces/IServiceLocator.cs +++ b/src/Greenshot.Base/Interfaces/IServiceLocator.cs @@ -32,7 +32,7 @@ namespace Greenshot.Base.Interfaces /// /// Service to find /// IEnumerable{TService} - IEnumerable GetAllInstances(); + IReadOnlyList GetAllInstances(); /// /// Get the only instance of the specified service diff --git a/src/Greenshot.Base/Interfaces/ISurface.cs b/src/Greenshot.Base/Interfaces/ISurface.cs index d5df7ff44..85cefe452 100644 --- a/src/Greenshot.Base/Interfaces/ISurface.cs +++ b/src/Greenshot.Base/Interfaces/ISurface.cs @@ -21,6 +21,7 @@ using System; using System.Drawing; +using System.Drawing.Drawing2D; using System.IO; using System.Windows.Forms; using Greenshot.Base.Core; @@ -201,5 +202,14 @@ namespace Greenshot.Base.Interfaces Rectangle ToImageCoordinates(Rectangle rc); void MakeUndoable(IMemento memento, bool allowMerge); + + IFieldAggregator FieldAggregator { get; } + + /// + /// This reverses a change of the background image + /// + /// Image + /// Matrix + void UndoBackgroundChange(Image previous, Matrix matrix); } } \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs b/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs index ef2a58e2f..efce47bbb 100644 --- a/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs +++ b/src/Greenshot.Base/Interfaces/Plugin/SurfaceOutputSettings.cs @@ -1,4 +1,25 @@ -using System.Collections.Generic; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.Effects; diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs index 603e58196..3efca68e0 100644 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs @@ -32,7 +32,7 @@ namespace Greenshot.Base.UnmanagedHelpers.Enums public enum WindowStyleFlags : int { //WS_OVERLAPPED = 0x00000000, - WS_POPUP = -2147483648, + WS_POPUP = -2147483648, // 0x80000000 WS_CHILD = 0x40000000, WS_MINIMIZE = 0x20000000, WS_VISIBLE = 0x10000000, diff --git a/src/Greenshot.Base/UnmanagedHelpers/User32.cs b/src/Greenshot.Base/UnmanagedHelpers/User32.cs index 9764c3a89..58e89a115 100644 --- a/src/Greenshot.Base/UnmanagedHelpers/User32.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/User32.cs @@ -127,7 +127,7 @@ namespace Greenshot.Base.UnmanagedHelpers public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")] - public static extern int GetWindowLong(IntPtr hWnd, int index); + public static extern IntPtr GetWindowLong(IntPtr hWnd, int index); [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")] public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); @@ -276,16 +276,14 @@ namespace Greenshot.Base.UnmanagedHelpers /// /// /// - public static long GetWindowLongWrapper(IntPtr hWnd, int nIndex) + public static IntPtr GetWindowLongWrapper(IntPtr hWnd, int nIndex) { if (IntPtr.Size == 8) { - return GetWindowLongPtr(hWnd, nIndex).ToInt64(); - } - else - { - return GetWindowLong(hWnd, nIndex); + return GetWindowLongPtr(hWnd, nIndex); } + + return GetWindowLong(hWnd, nIndex); } /// diff --git a/src/Greenshot.Editor/Drawing/ArrowContainer.cs b/src/Greenshot.Editor/Drawing/ArrowContainer.cs index f285d28bc..eb1e10e2f 100644 --- a/src/Greenshot.Editor/Drawing/ArrowContainer.cs +++ b/src/Greenshot.Editor/Drawing/ArrowContainer.cs @@ -22,6 +22,7 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; @@ -43,7 +44,7 @@ namespace Greenshot.Editor.Drawing private static readonly AdjustableArrowCap ARROW_CAP = new AdjustableArrowCap(4, 6); - public ArrowContainer(Surface parent) : base(parent) + public ArrowContainer(ISurface parent) : base(parent) { } diff --git a/src/Greenshot.Editor/Drawing/CropContainer.cs b/src/Greenshot.Editor/Drawing/CropContainer.cs index 1aa4e06c2..2324331f0 100644 --- a/src/Greenshot.Editor/Drawing/CropContainer.cs +++ b/src/Greenshot.Editor/Drawing/CropContainer.cs @@ -21,6 +21,7 @@ using System.Drawing; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -32,7 +33,7 @@ namespace Greenshot.Editor.Drawing /// public class CropContainer : DrawableContainer { - public CropContainer(Surface parent) : base(parent) + public CropContainer(ISurface parent) : base(parent) { Init(); } diff --git a/src/Greenshot.Editor/Drawing/CursorContainer.cs b/src/Greenshot.Editor/Drawing/CursorContainer.cs index d2e19adba..0eda46085 100644 --- a/src/Greenshot.Editor/Drawing/CursorContainer.cs +++ b/src/Greenshot.Editor/Drawing/CursorContainer.cs @@ -25,6 +25,7 @@ using System.Drawing.Drawing2D; using System.IO; using System.Runtime.Serialization; using System.Windows.Forms; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using log4net; @@ -40,7 +41,7 @@ namespace Greenshot.Editor.Drawing protected Cursor cursor; - public CursorContainer(Surface parent) : base(parent) + public CursorContainer(ISurface parent) : base(parent) { Init(); } @@ -56,7 +57,7 @@ namespace Greenshot.Editor.Drawing CreateDefaultAdorners(); } - public CursorContainer(Surface parent, string filename) : this(parent) + public CursorContainer(ISurface parent, string filename) : this(parent) { Load(filename); } diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index 029a48d43..08abba3e2 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -126,12 +126,17 @@ namespace Greenshot.Editor.Drawing } } - [NonSerialized] internal Surface _parent; + [NonSerialized] internal ISurface _parent; public ISurface Parent { get => _parent; - set => SwitchParent((Surface) value); + set => SwitchParent(value); + } + + protected Surface InternalParent + { + get => (Surface)_parent; } [NonSerialized] private TargetAdorner _targetAdorner; @@ -277,7 +282,7 @@ namespace Greenshot.Editor.Drawing Height = Round(newBounds.Height); } - public DrawableContainer(Surface parent) + public DrawableContainer(ISurface parent) { InitializeFields(); _parent = parent; @@ -505,7 +510,7 @@ namespace Greenshot.Editor.Drawing { Invalidate(); - // reset "workrbench" rectangle to current bounds + // reset "workbench" rectangle to current bounds _boundsAfterResize.X = _boundsBeforeResize.Left; _boundsAfterResize.Y = _boundsBeforeResize.Top; _boundsAfterResize.Width = x - _boundsAfterResize.Left; @@ -529,7 +534,7 @@ namespace Greenshot.Editor.Drawing { } - protected virtual void SwitchParent(Surface newParent) + protected virtual void SwitchParent(ISurface newParent) { if (newParent == Parent) { diff --git a/src/Greenshot.Editor/Drawing/EllipseContainer.cs b/src/Greenshot.Editor/Drawing/EllipseContainer.cs index f7799ac71..b32ecffd3 100644 --- a/src/Greenshot.Editor/Drawing/EllipseContainer.cs +++ b/src/Greenshot.Editor/Drawing/EllipseContainer.cs @@ -23,6 +23,7 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -35,7 +36,7 @@ namespace Greenshot.Editor.Drawing [Serializable()] public class EllipseContainer : DrawableContainer { - public EllipseContainer(Surface parent) : base(parent) + public EllipseContainer(ISurface parent) : base(parent) { Init(); } diff --git a/src/Greenshot.Editor/Drawing/Fields/FieldAggregator.cs b/src/Greenshot.Editor/Drawing/Fields/FieldAggregator.cs index 2df16d46f..96a19b7b9 100644 --- a/src/Greenshot.Editor/Drawing/Fields/FieldAggregator.cs +++ b/src/Greenshot.Editor/Drawing/Fields/FieldAggregator.cs @@ -42,7 +42,7 @@ namespace Greenshot.Editor.Drawing.Fields /// If the property values of the selected elements differ, the value of the last bound element wins. /// [Serializable] - public sealed class FieldAggregator : AbstractFieldHolder + public sealed class FieldAggregator : AbstractFieldHolder, IFieldAggregator { private readonly IDrawableContainerList _boundContainers; private bool _internalUpdateRunning; @@ -117,11 +117,10 @@ namespace Greenshot.Editor.Drawing.Fields public void UnbindElement(IDrawableContainer dc) { - if (_boundContainers.Contains(dc)) - { - _boundContainers.Remove(dc); - UpdateFromBoundElements(); - } + if (!_boundContainers.Contains(dc)) return; + + _boundContainers.Remove(dc); + UpdateFromBoundElements(); } public void Clear() diff --git a/src/Greenshot.Editor/Drawing/FilterContainer.cs b/src/Greenshot.Editor/Drawing/FilterContainer.cs index 3bdb5a5fd..c6d1f8f26 100644 --- a/src/Greenshot.Editor/Drawing/FilterContainer.cs +++ b/src/Greenshot.Editor/Drawing/FilterContainer.cs @@ -23,6 +23,7 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -51,7 +52,7 @@ namespace Greenshot.Editor.Drawing MAGNIFICATION }; - public FilterContainer(Surface parent) : base(parent) + public FilterContainer(ISurface parent) : base(parent) { Init(); } diff --git a/src/Greenshot.Editor/Drawing/FreehandContainer.cs b/src/Greenshot.Editor/Drawing/FreehandContainer.cs index e37221551..ef1c69ff3 100644 --- a/src/Greenshot.Editor/Drawing/FreehandContainer.cs +++ b/src/Greenshot.Editor/Drawing/FreehandContainer.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -50,7 +51,7 @@ namespace Greenshot.Editor.Drawing /// /// Constructor /// - public FreehandContainer(Surface parent) : base(parent) + public FreehandContainer(ISurface parent) : base(parent) { Width = parent.Image.Width; Height = parent.Image.Height; diff --git a/src/Greenshot.Editor/Drawing/HighlightContainer.cs b/src/Greenshot.Editor/Drawing/HighlightContainer.cs index 417725322..58cf792ba 100644 --- a/src/Greenshot.Editor/Drawing/HighlightContainer.cs +++ b/src/Greenshot.Editor/Drawing/HighlightContainer.cs @@ -21,6 +21,7 @@ using System; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Filters; @@ -33,7 +34,7 @@ namespace Greenshot.Editor.Drawing [Serializable] public class HighlightContainer : FilterContainer { - public HighlightContainer(Surface parent) : base(parent) + public HighlightContainer(ISurface parent) : base(parent) { Init(); } diff --git a/src/Greenshot.Editor/Drawing/IconContainer.cs b/src/Greenshot.Editor/Drawing/IconContainer.cs index e98b37f82..dd6668ce9 100644 --- a/src/Greenshot.Editor/Drawing/IconContainer.cs +++ b/src/Greenshot.Editor/Drawing/IconContainer.cs @@ -24,6 +24,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.IO; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using log4net; @@ -39,7 +40,7 @@ namespace Greenshot.Editor.Drawing protected Icon icon; - public IconContainer(Surface parent) : base(parent) + public IconContainer(ISurface parent) : base(parent) { Init(); } @@ -55,11 +56,16 @@ namespace Greenshot.Editor.Drawing CreateDefaultAdorners(); } - public IconContainer(Surface parent, string filename) : base(parent) + public IconContainer(ISurface parent, string filename) : base(parent) { Load(filename); } + public IconContainer(ISurface parent, Stream stream) : base(parent) + { + Load(stream); + } + public Icon Icon { set @@ -99,6 +105,18 @@ namespace Greenshot.Editor.Drawing Log.Debug("Loaded file: " + filename + " with resolution: " + Height + "," + Width); } + public void Load(Stream iconStream) + { + if (iconStream == null) + { + return; + } + + using Icon fileIcon = new Icon(iconStream); + Icon = fileIcon; + Log.Debug("Loaded stream: with resolution: " + Height + "," + Width); + } + public override void Draw(Graphics graphics, RenderMode rm) { if (icon == null) diff --git a/src/Greenshot.Editor/Drawing/ImageContainer.cs b/src/Greenshot.Editor/Drawing/ImageContainer.cs index a46b0dae5..5def5578b 100644 --- a/src/Greenshot.Editor/Drawing/ImageContainer.cs +++ b/src/Greenshot.Editor/Drawing/ImageContainer.cs @@ -26,6 +26,7 @@ using System.IO; using System.Runtime.Serialization; using Greenshot.Base.Core; using Greenshot.Base.Effects; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using log4net; @@ -40,7 +41,7 @@ namespace Greenshot.Editor.Drawing { private static readonly ILog Log = LogManager.GetLogger(typeof(ImageContainer)); - private Image image; + private Image _image; /// /// This is the shadow version of the bitmap, rendered once to save performance @@ -54,12 +55,12 @@ namespace Greenshot.Editor.Drawing /// [NonSerialized] private Point _shadowOffset = new Point(-1, -1); - public ImageContainer(Surface parent, string filename) : this(parent) + public ImageContainer(ISurface parent, string filename) : this(parent) { Load(filename); } - public ImageContainer(Surface parent) : base(parent) + public ImageContainer(ISurface parent) : base(parent) { FieldChanged += BitmapContainer_OnFieldChanged; Init(); @@ -107,8 +108,8 @@ namespace Greenshot.Editor.Drawing } else { - Width = image.Width; - Height = image.Height; + Width = _image.Width; + Height = _image.Height; if (_shadowBitmap != null) { Left += _shadowOffset.X; @@ -124,13 +125,13 @@ namespace Greenshot.Editor.Drawing // Remove all current bitmaps DisposeImage(); DisposeShadow(); - image = ImageHelper.Clone(value); + _image = ImageHelper.Clone(value); bool shadow = GetFieldValueAsBool(FieldType.SHADOW); CheckShadow(shadow); if (!shadow) { - Width = image.Width; - Height = image.Height; + Width = _image.Width; + Height = _image.Height; } else { @@ -140,7 +141,7 @@ namespace Greenshot.Editor.Drawing Top -= _shadowOffset.Y; } } - get { return image; } + get { return _image; } } /// @@ -162,8 +163,8 @@ namespace Greenshot.Editor.Drawing private void DisposeImage() { - image?.Dispose(); - image = null; + _image?.Dispose(); + _image = null; } private void DisposeShadow() @@ -186,9 +187,9 @@ namespace Greenshot.Editor.Drawing Log.DebugFormat("Rotating element with {0} degrees.", rotateAngle); DisposeShadow(); using var tmpMatrix = new Matrix(); - using (image) + using (_image) { - image = ImageHelper.ApplyEffect(image, new RotateEffect(rotateAngle), tmpMatrix); + _image = ImageHelper.ApplyEffect(_image, new RotateEffect(rotateAngle), tmpMatrix); } } @@ -208,7 +209,8 @@ namespace Greenshot.Editor.Drawing // Always make sure ImageHelper.LoadBitmap results are disposed some time, // as we close the bitmap internally, we need to do it afterwards - using (var tmpImage = ImageHelper.LoadImage(filename)) + // TODO: Replace with some other code, like the file format handler, or move it completely outside of this class + using (var tmpImage = ImageIO.LoadImage(filename)) { Image = tmpImage; } @@ -228,7 +230,7 @@ namespace Greenshot.Editor.Drawing } using var matrix = new Matrix(); - _shadowBitmap = ImageHelper.ApplyEffect(image, new DropShadowEffect(), matrix); + _shadowBitmap = ImageHelper.ApplyEffect(_image, new DropShadowEffect(), matrix); } /// @@ -238,7 +240,7 @@ namespace Greenshot.Editor.Drawing /// public override void Draw(Graphics graphics, RenderMode rm) { - if (image == null) + if (_image == null) { return; } @@ -256,12 +258,12 @@ namespace Greenshot.Editor.Drawing } else { - graphics.DrawImage(image, Bounds); + graphics.DrawImage(_image, Bounds); } } public override bool HasDefaultSize => true; - public override Size DefaultSize => image?.Size ?? new Size(32, 32); + public override Size DefaultSize => _image?.Size ?? new Size(32, 32); } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/LineContainer.cs b/src/Greenshot.Editor/Drawing/LineContainer.cs index 1bcf25a81..729872be6 100644 --- a/src/Greenshot.Editor/Drawing/LineContainer.cs +++ b/src/Greenshot.Editor/Drawing/LineContainer.cs @@ -23,6 +23,7 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Adorners; using Greenshot.Editor.Drawing.Fields; @@ -36,7 +37,7 @@ namespace Greenshot.Editor.Drawing [Serializable()] public class LineContainer : DrawableContainer { - public LineContainer(Surface parent) : base(parent) + public LineContainer(ISurface parent) : base(parent) { Init(); } diff --git a/src/Greenshot.Editor/Drawing/MetafileContainer.cs b/src/Greenshot.Editor/Drawing/MetafileContainer.cs new file mode 100644 index 000000000..4372ce24d --- /dev/null +++ b/src/Greenshot.Editor/Drawing/MetafileContainer.cs @@ -0,0 +1,81 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Svg; + +namespace Greenshot.Editor.Drawing +{ + /// + /// This provides a resizable SVG container, redrawing the SVG in the size the container takes. + /// + [Serializable] + public class MetafileContainer : VectorGraphicsContainer + { + private readonly Metafile _metafile; + + public MetafileContainer(Metafile metafile, ISurface parent) : base(parent) + { + _metafile = metafile; + Size = new Size(metafile.Width/4, metafile.Height/4); + } + + protected override Image ComputeBitmap() + { + var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent); + + var dstRect = new Rectangle(0, 0, Width, Height); + using (Graphics graphics = Graphics.FromImage(image)) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.DrawImage(_metafile, dstRect); + } + + if (RotationAngle == 0) return image; + + var newImage = image.Rotate(RotationAngle); + image.Dispose(); + return newImage; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _metafile?.Dispose(); + } + + base.Dispose(disposing); + } + + public override bool HasDefaultSize => true; + + public override Size DefaultSize => new Size(_metafile.Width, _metafile.Height); + } +} \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/ObfuscateContainer.cs b/src/Greenshot.Editor/Drawing/ObfuscateContainer.cs index 1754ba650..b0c890ffc 100644 --- a/src/Greenshot.Editor/Drawing/ObfuscateContainer.cs +++ b/src/Greenshot.Editor/Drawing/ObfuscateContainer.cs @@ -21,6 +21,7 @@ using System; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Drawing.Filters; @@ -28,12 +29,12 @@ using Greenshot.Editor.Drawing.Filters; namespace Greenshot.Editor.Drawing { /// - /// Description of ObfuscateContainer. + /// This is a FilterContainer for the obfuscator filters like blur and pixelate. /// [Serializable] public class ObfuscateContainer : FilterContainer { - public ObfuscateContainer(Surface parent) : base(parent) + public ObfuscateContainer(ISurface parent) : base(parent) { Init(); } diff --git a/src/Greenshot.Editor/Drawing/RectangleContainer.cs b/src/Greenshot.Editor/Drawing/RectangleContainer.cs index 5e38fcf4b..4dd6543a7 100644 --- a/src/Greenshot.Editor/Drawing/RectangleContainer.cs +++ b/src/Greenshot.Editor/Drawing/RectangleContainer.cs @@ -23,6 +23,7 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -35,7 +36,7 @@ namespace Greenshot.Editor.Drawing [Serializable] public class RectangleContainer : DrawableContainer { - public RectangleContainer(Surface parent) : base(parent) + public RectangleContainer(ISurface parent) : base(parent) { Init(); } diff --git a/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs b/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs index 2b189945d..0a19805e7 100644 --- a/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs +++ b/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs @@ -24,6 +24,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -64,8 +65,7 @@ namespace Greenshot.Editor.Drawing InitAdorner(Color.Green, _storedTargetGripperLocation); } - public SpeechbubbleContainer(Surface parent) - : base(parent) + public SpeechbubbleContainer(ISurface parent) : base(parent) { } diff --git a/src/Greenshot.Editor/Drawing/StepLabelContainer.cs b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs index 4f95e0437..c6812f12b 100644 --- a/src/Greenshot.Editor/Drawing/StepLabelContainer.cs +++ b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs @@ -24,6 +24,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -41,9 +42,9 @@ namespace Greenshot.Editor.Drawing private readonly bool _drawAsRectangle = false; - public StepLabelContainer(Surface parent) : base(parent) + public StepLabelContainer(ISurface parent) : base(parent) { - parent.AddStepLabel(this); + InternalParent?.AddStepLabel(this); InitContent(); Init(); } @@ -72,11 +73,10 @@ namespace Greenshot.Editor.Drawing [OnSerializing] private void SetValuesOnSerializing(StreamingContext context) { - if (Parent != null) - { - Number = ((Surface) Parent).CountStepLabels(this); - _counterStart = ((Surface) Parent).CounterStart; - } + if (InternalParent == null) return; + + Number = InternalParent.CountStepLabels(this); + _counterStart = InternalParent.CounterStart; } /// @@ -97,23 +97,23 @@ namespace Greenshot.Editor.Drawing /// Add the StepLabel to the parent /// /// - protected override void SwitchParent(Surface newParent) + protected override void SwitchParent(ISurface newParent) { if (newParent == Parent) { return; } - ((Surface) Parent)?.RemoveStepLabel(this); - base.SwitchParent(newParent); - if (newParent == null) + if (newParent is not Surface newParentSurface) { return; } + InternalParent?.RemoveStepLabel(this); + base.SwitchParent(newParent); // Make sure the counter start is restored (this unfortunately happens multiple times... -> hack) - newParent.CounterStart = _counterStart; - newParent.AddStepLabel(this); + newParentSurface.CounterStart = _counterStart; + newParentSurface.AddStepLabel(this); } public override Size DefaultSize => new Size(30, 30); diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index 5093ed201..7c27c8ce1 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -49,7 +49,6 @@ namespace Greenshot.Editor.Drawing public sealed class Surface : Control, ISurface, INotifyPropertyChanged { private static readonly ILog LOG = LogManager.GetLogger(typeof(Surface)); - public static int Count; private static readonly CoreConfiguration conf = IniConfig.GetIniSection(); // Property to identify the Surface ID @@ -207,7 +206,7 @@ namespace Greenshot.Editor.Drawing [NonSerialized] private IDrawableContainer _undrawnElement; /// - /// the cropcontainer, when cropping this is set, do not serialize + /// the crop container, when cropping this is set, do not serialize /// [NonSerialized] private IDrawableContainer _cropContainer; @@ -294,7 +293,7 @@ namespace Greenshot.Editor.Drawing /// /// all elements on the surface, needed with serialization /// - private FieldAggregator _fieldAggregator; + private IFieldAggregator _fieldAggregator; /// /// the cursor container, needed with serialization as we need a direct acces to it. @@ -355,7 +354,7 @@ namespace Greenshot.Editor.Drawing /// The field aggregator is that which is used to have access to all the fields inside the currently selected elements. /// e.g. used to decided if and which line thickness is shown when multiple elements are selected. /// - public FieldAggregator FieldAggregator + public IFieldAggregator FieldAggregator { get => _fieldAggregator; set => _fieldAggregator = value; @@ -467,7 +466,6 @@ namespace Greenshot.Editor.Drawing public Surface() { _fieldAggregator = new FieldAggregator(this); - Count++; _elements = new DrawableContainerList(_uniqueId); selectedElements = new DrawableContainerList(_uniqueId); LOG.Debug("Creating surface!"); @@ -550,7 +548,6 @@ namespace Greenshot.Editor.Drawing { if (disposing) { - Count--; LOG.Debug("Disposing surface!"); if (_buffer != null) { @@ -913,6 +910,27 @@ namespace Greenshot.Editor.Drawing } } + /// + /// This will help to fit the container to the surface + /// + /// IDrawableContainer + private void FitContainer(IDrawableContainer drawableContainer) + { + double factor = 1; + if (drawableContainer.Width > this.Width) + { + factor = drawableContainer.Width / (double)Width; + } + if (drawableContainer.Height > this.Height) + { + var otherFactor = drawableContainer.Height / (double)Height; + factor = Math.Max(factor, otherFactor); + } + + drawableContainer.Width = (int)(drawableContainer.Width / factor); + drawableContainer.Height = (int)(drawableContainer.Height / factor); + } + /// /// Handle the drag/drop /// @@ -927,20 +945,25 @@ namespace Greenshot.Editor.Drawing // Test if it's an url and try to download the image so we have it in the original form if (possibleUrl != null && possibleUrl.StartsWith("http")) { - using Image image = NetworkHelper.DownloadImage(possibleUrl); - if (image != null) + var drawableContainer = NetworkHelper.DownloadImageAsDrawableContainer(possibleUrl); + if (drawableContainer != null) { - AddImageContainer(image, mouse.X, mouse.Y); + drawableContainer.Left = Location.X; + drawableContainer.Top = Location.Y; + FitContainer(drawableContainer); + AddElement(drawableContainer); return; } } } - foreach (Image image in ClipboardHelper.GetImages(e.Data)) + foreach (var drawableContainer in ClipboardHelper.GetDrawables(e.Data)) { - AddImageContainer(image, mouse.X, mouse.Y); + drawableContainer.Left = mouse.X; + drawableContainer.Top = mouse.Y; + FitContainer(drawableContainer); + AddElement(drawableContainer); mouse.Offset(10, 10); - image.Dispose(); } } @@ -987,13 +1010,11 @@ namespace Greenshot.Editor.Drawing { //create a blank bitmap the same size as original Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty); - if (newBitmap != null) - { - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false); - SetImage(newBitmap, false); - Invalidate(); - } + if (newBitmap == null) return; + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false); + SetImage(newBitmap, false); + Invalidate(); } /// @@ -2057,17 +2078,16 @@ namespace Greenshot.Editor.Drawing { Point pasteLocation = GetPasteLocation(0.1f, 0.1f); - foreach (Image clipboardImage in ClipboardHelper.GetImages(clipboard)) + foreach (var drawableContainer in ClipboardHelper.GetDrawables(clipboard)) { - if (clipboardImage != null) - { - DeselectAllElements(); - IImageContainer container = AddImageContainer(clipboardImage as Bitmap, pasteLocation.X, pasteLocation.Y); - SelectElement(container); - clipboardImage.Dispose(); - pasteLocation.X += 10; - pasteLocation.Y += 10; - } + if (drawableContainer == null) continue; + DeselectAllElements(); + drawableContainer.Left = pasteLocation.X; + drawableContainer.Top = pasteLocation.Y; + AddElement(drawableContainer); + SelectElement(drawableContainer); + pasteLocation.X += 10; + pasteLocation.Y += 10; } } else if (ClipboardHelper.ContainsText(clipboard)) @@ -2208,24 +2228,23 @@ namespace Greenshot.Editor.Drawing /// false to skip event generation public void SelectElement(IDrawableContainer container, bool invalidate = true, bool generateEvents = true) { - if (!selectedElements.Contains(container)) - { - selectedElements.Add(container); - container.Selected = true; - FieldAggregator.BindElement(container); - if (generateEvents && _movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs - { - Elements = selectedElements - }; - _movingElementChanged(this, eventArgs); - } + if (selectedElements.Contains(container)) return; - if (invalidate) + selectedElements.Add(container); + container.Selected = true; + FieldAggregator.BindElement(container); + if (generateEvents && _movingElementChanged != null) + { + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs { - container.Invalidate(); - } + Elements = selectedElements + }; + _movingElementChanged(this, eventArgs); + } + + if (invalidate) + { + container.Invalidate(); } } diff --git a/src/Greenshot.Editor/Drawing/SvgContainer.cs b/src/Greenshot.Editor/Drawing/SvgContainer.cs new file mode 100644 index 000000000..f98f03a32 --- /dev/null +++ b/src/Greenshot.Editor/Drawing/SvgContainer.cs @@ -0,0 +1,61 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Svg; + +namespace Greenshot.Editor.Drawing +{ + /// + /// This provides a resizable SVG container, redrawing the SVG in the size the container takes. + /// + [Serializable] + public class SvgContainer : VectorGraphicsContainer + { + private SvgDocument _svgDocument; + + public SvgContainer(SvgDocument svgDocument, ISurface parent) : base(parent) + { + _svgDocument = svgDocument; + Size = new Size((int)svgDocument.Width, (int)svgDocument.Height); + } + + protected override Image ComputeBitmap() + { + //var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent); + + var image = _svgDocument.Draw(Width, Height); + + if (RotationAngle == 0) return image; + + var newImage = image.Rotate(RotationAngle); + image.Dispose(); + return newImage; + } + + public override bool HasDefaultSize => true; + + public override Size DefaultSize => new Size((int)_svgDocument.Width, (int)_svgDocument.Height); + } +} \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/TextContainer.cs b/src/Greenshot.Editor/Drawing/TextContainer.cs index 4d670b4e0..fdb718cbe 100644 --- a/src/Greenshot.Editor/Drawing/TextContainer.cs +++ b/src/Greenshot.Editor/Drawing/TextContainer.cs @@ -28,6 +28,7 @@ using System.Drawing.Text; using System.Runtime.Serialization; using System.Windows.Forms; using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -83,7 +84,7 @@ namespace Greenshot.Editor.Drawing OnPropertyChanged("Text"); } - public TextContainer(Surface parent) : base(parent) + public TextContainer(ISurface parent) : base(parent) { Init(); } @@ -154,17 +155,17 @@ namespace Greenshot.Editor.Drawing FieldChanged += TextContainer_FieldChanged; } - protected override void SwitchParent(Surface newParent) + protected override void SwitchParent(ISurface newParent) { - if (_parent != null) + if (InternalParent != null) { - _parent.SizeChanged -= Parent_SizeChanged; + InternalParent.SizeChanged -= Parent_SizeChanged; } base.SwitchParent(newParent); - if (_parent != null) + if (InternalParent != null) { - _parent.SizeChanged += Parent_SizeChanged; + InternalParent.SizeChanged += Parent_SizeChanged; } } @@ -221,10 +222,10 @@ namespace Greenshot.Editor.Drawing { ShowTextBox(); } - else if (_parent != null && Selected && Status == EditStatus.IDLE && _textBox.Visible) + else if (InternalParent != null && Selected && Status == EditStatus.IDLE && _textBox.Visible) { // Fix (workaround) for BUG-1698 - _parent.KeysLocked = true; + InternalParent.KeysLocked = true; } } @@ -295,10 +296,10 @@ namespace Greenshot.Editor.Drawing private void ShowTextBox() { - if (_parent != null) + if (InternalParent != null) { - _parent.KeysLocked = true; - _parent.Controls.Add(_textBox); + InternalParent.KeysLocked = true; + InternalParent.Controls.Add(_textBox); } EnsureTextBoxContrast(); @@ -332,15 +333,15 @@ namespace Greenshot.Editor.Drawing private void HideTextBox() { - _parent?.Focus(); + InternalParent?.Focus(); _textBox?.Hide(); - if (_parent == null) + if (InternalParent == null) { return; } - _parent.KeysLocked = false; - _parent.Controls.Remove(_textBox); + InternalParent.KeysLocked = false; + InternalParent.Controls.Remove(_textBox); } /// diff --git a/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs b/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs new file mode 100644 index 000000000..0c467c0b8 --- /dev/null +++ b/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs @@ -0,0 +1,117 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.Serialization; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; + +namespace Greenshot.Editor.Drawing +{ + /// + /// This is the base container for vector graphics, these ae graphics which can resize without loss of quality. + /// Examples for this are SVG, WMF or EMF, but also graphics based on fonts (e.g. Emoji) + /// + [Serializable] + public abstract class VectorGraphicsContainer : DrawableContainer + { + protected int RotationAngle; + + /// + /// This is the cached version of the bitmap, pre-rendered to save performance + /// Do not serialized, it can be rebuild with some other information. + /// + [NonSerialized] private Image _cachedImage; + + public VectorGraphicsContainer(ISurface parent) : base(parent) + { + Init(); + } + + protected override void OnDeserialized(StreamingContext streamingContext) + { + base.OnDeserialized(streamingContext); + Init(); + } + + private void Init() + { + CreateDefaultAdorners(); + } + + /// + /// The bulk of the clean-up code is implemented in Dispose(bool) + /// This Dispose is called from the Dispose and the Destructor. + /// When disposing==true all non-managed resources should be freed too! + /// + /// + + protected override void Dispose(bool disposing) + { + if (disposing) + { + ResetCachedBitmap(); + } + + base.Dispose(disposing); + } + + /// + public override void Transform(Matrix matrix) + { + RotationAngle += CalculateAngle(matrix); + RotationAngle %= 360; + + ResetCachedBitmap(); + + base.Transform(matrix); + } + + /// + public override void Draw(Graphics graphics, RenderMode rm) + { + if (_cachedImage != null && _cachedImage.Size != Bounds.Size) + { + ResetCachedBitmap(); + } + + _cachedImage ??= ComputeBitmap(); + + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + + graphics.DrawImage(_cachedImage, Bounds); + } + + protected abstract Image ComputeBitmap(); + + private void ResetCachedBitmap() + { + _cachedImage?.Dispose(); + _cachedImage = null; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Editor/EditorInitialize.cs b/src/Greenshot.Editor/EditorInitialize.cs new file mode 100644 index 000000000..c1ee27db8 --- /dev/null +++ b/src/Greenshot.Editor/EditorInitialize.cs @@ -0,0 +1,50 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Editor.FileFormatHandlers; + +namespace Greenshot.Editor +{ + public static class EditorInitialize + { + public static void Initialize() + { + SimpleServiceProvider.Current.AddService( + // All generic things, like gif, png, jpg etc. + new DefaultFileFormatHandler(), + // Greenshot format + new GreenshotFileFormatHandler(), + // For .svg support + new SvgFileFormatHandler(), + // For clipboard support + new DibFileFormatHandler(), + // .ico + new IconFileFormatHandler(), + // EMF & WMF + new MetaFileFormatHandler(), + // JPG XR + new WpfFileFormatHandler() + ); + } + } +} diff --git a/src/Greenshot.Editor/FileFormatHandlers/AbstractFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/AbstractFileFormatHandler.cs new file mode 100644 index 000000000..fff576267 --- /dev/null +++ b/src/Greenshot.Editor/FileFormatHandlers/AbstractFileFormatHandler.cs @@ -0,0 +1,66 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Editor.Drawing; + +namespace Greenshot.Editor.FileFormatHandlers +{ + public abstract class AbstractFileFormatHandler : IFileFormatHandler + { + /// + public IDictionary> SupportedExtensions { get; } = new Dictionary>(); + + /// + public virtual int PriorityFor(FileFormatHandlerActions fileFormatHandlerAction, string extension) + { + return 0; + } + + public abstract bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null); + + public abstract bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap); + + /// + /// Default implementation taking the TryLoadFromStream image and placing it in an ImageContainer + /// + /// Stream + /// string + /// ISurface + /// IEnumerable{IDrawableContainer} + public virtual IEnumerable LoadDrawablesFromStream(Stream stream, string extension, ISurface parent = null) + { + if (TryLoadFromStream(stream, extension, out var bitmap)) + { + var imageContainer = new ImageContainer(parent) + { + Image = bitmap + }; + yield return imageContainer; + } + } + } +} diff --git a/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs new file mode 100644 index 000000000..30d785bb5 --- /dev/null +++ b/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs @@ -0,0 +1,137 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using log4net; + +namespace Greenshot.Editor.FileFormatHandlers +{ + /// + /// This is the default .NET bitmap file format handler + /// + public class DefaultFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler + { + private static readonly ILog Log = LogManager.GetLogger(typeof(DefaultFileFormatHandler)); + private readonly IReadOnlyCollection _ourExtensions = new[] { ".png", ".bmp", ".gif", ".jpg", ".jpeg", ".tiff", ".tif" }; + public DefaultFileFormatHandler() + { + SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.SaveToStream] = _ourExtensions; + } + + /// + public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null) + { + ImageFormat imageFormat = extension switch + { + ".png" => ImageFormat.Png, + ".bmp" => ImageFormat.Bmp, + ".gif" => ImageFormat.Gif, + ".jpg" => ImageFormat.Jpeg, + ".jpeg" => ImageFormat.Jpeg, + ".tiff" => ImageFormat.Tiff, + ".tif" => ImageFormat.Tiff, + _ => null + }; + + if (imageFormat == null) + { + return false; + } + surfaceOutputSettings ??= new SurfaceOutputSettings(); + var imageEncoder = ImageCodecInfo.GetImageEncoders().FirstOrDefault(ie => ie.FilenameExtension.ToLowerInvariant().Contains(extension)); + if (imageEncoder == null) + { + return false; + } + EncoderParameters parameters = new EncoderParameters(1) + { + Param = + { + [0] = new EncoderParameter(Encoder.Quality, surfaceOutputSettings.JPGQuality) + } + }; + // For those images which are with Alpha, but the format doesn't support this, change it to 24bpp + if (imageFormat.Guid == ImageFormat.Jpeg.Guid && Image.IsAlphaPixelFormat(bitmap.PixelFormat)) + { + var nonAlphaImage = ImageHelper.Clone(bitmap, PixelFormat.Format24bppRgb) as Bitmap; + try + { + // Set that this file was written by Greenshot + nonAlphaImage.AddTag(); + } + catch (Exception ex) + { + Log.Warn("Couldn't set 'software used' tag on image.", ex); + } + + try + { + nonAlphaImage.Save(destination, imageEncoder, parameters); + } + catch (Exception ex) + { + Log.Error("Couldn't save image: ", ex); + } + finally + { + nonAlphaImage.Dispose(); + } + } + else + { + // Set that this file was written by Greenshot + bitmap.AddTag(); + bitmap.Save(destination, imageEncoder, parameters); + } + + return true; + } + + /// + public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) + { + try + { + using var tmpImage = Image.FromStream(stream, true, true); + bitmap = ImageHelper.Clone(tmpImage, PixelFormat.DontCare); + + return true; + } + catch (Exception ex) + { + Log.Error("Couldn't load image: ", ex); + } + + bitmap = null; + return false; + } + } +} diff --git a/src/Greenshot.Base/Core/DibHelper.cs b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs similarity index 59% rename from src/Greenshot.Base/Core/DibHelper.cs rename to src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs index 59af37414..8d7ad7790 100644 --- a/src/Greenshot.Base/Core/DibHelper.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs @@ -1,48 +1,131 @@ /* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * + * * For more information see: https://getgreenshot.org/ * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using System; +using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; +using System.IO; using System.Runtime.InteropServices; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.UnmanagedHelpers; +using log4net; -namespace Greenshot.Base.Core +namespace Greenshot.Editor.FileFormatHandlers { /// - /// Though Greenshot implements the specs for the DIB image format, - /// it seems to cause a lot of issues when using the clipboard. - /// There is some research done about the DIB on the clipboard, this code is based upon the information - /// here + /// This handles creating a DIB (Device Independent Bitmap) on the clipboard /// - internal static class DibHelper + public class DibFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler { private const double DpiToPelsPerMeter = 39.3701; + private static readonly ILog Log = LogManager.GetLogger(typeof(DibFileFormatHandler)); + + private readonly IReadOnlyCollection _ourExtensions = new[] { ".dib", ".format17" }; + + public DibFileFormatHandler() + { + SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.SaveToStream] = _ourExtensions; + } + + /// + public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null) + { + var dibBytes = ConvertToDib(bitmap); + destination.Write(dibBytes, 0, dibBytes.Length); + return true; + } + + /// + public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) + { + byte[] dibBuffer = new byte[stream.Length]; + _ = stream.Read(dibBuffer, 0, dibBuffer.Length); + var infoHeader = BinaryStructHelper.FromByteArray(dibBuffer); + if (!infoHeader.IsDibV5) + { + Log.InfoFormat("Using special DIB /// Converts the Bitmap to a Device Independent Bitmap format of type BITFIELDS. /// /// Bitmap to convert to DIB /// byte{} with the image converted to DIB - public static byte[] ConvertToDib(this Bitmap sourceBitmap) + private static byte[] ConvertToDib(Bitmap sourceBitmap) { if (sourceBitmap == null) throw new ArgumentNullException(nameof(sourceBitmap)); diff --git a/src/Greenshot.Editor/FileFormatHandlers/GreenshotFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/GreenshotFileFormatHandler.cs new file mode 100644 index 000000000..0b956c001 --- /dev/null +++ b/src/Greenshot.Editor/FileFormatHandlers/GreenshotFileFormatHandler.cs @@ -0,0 +1,133 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Reflection; +using System.Text; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using log4net; + +namespace Greenshot.Editor.FileFormatHandlers +{ + public class GreenshotFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler + { + private static readonly ILog Log = LogManager.GetLogger(typeof(GreenshotFileFormatHandler)); + private readonly IReadOnlyCollection _ourExtensions = new [] { ".greenshot" }; + public GreenshotFileFormatHandler() + { + SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.SaveToStream] = _ourExtensions; + } + + public override bool TrySaveToStream(Bitmap bitmap, Stream stream, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null) + { + if (surface == null) + { + return false; + } + + try + { + bitmap.Save(stream, ImageFormat.Png); + using MemoryStream tmpStream = new MemoryStream(); + long bytesWritten = surface.SaveElementsToStream(tmpStream); + using BinaryWriter writer = new BinaryWriter(tmpStream); + writer.Write(bytesWritten); + Version v = Assembly.GetExecutingAssembly().GetName().Version; + byte[] marker = Encoding.ASCII.GetBytes($"Greenshot{v.Major:00}.{v.Minor:00}"); + writer.Write(marker); + tmpStream.WriteTo(stream); + return true; + } + catch (Exception ex) + { + Log.Error("Couldn't save surface as .greenshot: ", ex); + } + + return false; + } + + public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) + { + try + { + var surface = LoadSurface(stream); + bitmap = (Bitmap)surface.GetImageForExport(); + return true; + } + catch (Exception ex) + { + Log.Error("Couldn't load .greenshot: ", ex); + } + bitmap = null; + return false; + } + + private ISurface LoadSurface(Stream surfaceFileStream) + { + var returnSurface = SimpleServiceProvider.Current.GetInstance>().Invoke(); + Bitmap captureBitmap; + + // Fixed problem that the bitmap stream is disposed... by Cloning the image + // This also ensures the bitmap is correctly created + using (Image tmpImage = Image.FromStream(surfaceFileStream, true, true)) + { + Log.DebugFormat("Loaded capture from .greenshot file with Size {0}x{1} and PixelFormat {2}", tmpImage.Width, tmpImage.Height, tmpImage.PixelFormat); + captureBitmap = ImageHelper.Clone(tmpImage) as Bitmap; + } + + // Start at -14 read "GreenshotXX.YY" (XX=Major, YY=Minor) + const int markerSize = 14; + surfaceFileStream.Seek(-markerSize, SeekOrigin.End); + using (var streamReader = new StreamReader(surfaceFileStream)) + { + var greenshotMarker = streamReader.ReadToEnd(); + if (!greenshotMarker.StartsWith("Greenshot")) + { + throw new ArgumentException("Stream is not a Greenshot file!"); + } + + Log.InfoFormat("Greenshot file format: {0}", greenshotMarker); + const int fileSizeLocation = 8 + markerSize; + surfaceFileStream.Seek(-fileSizeLocation, SeekOrigin.End); + using BinaryReader reader = new BinaryReader(surfaceFileStream); + long bytesWritten = reader.ReadInt64(); + surfaceFileStream.Seek(-(bytesWritten + fileSizeLocation), SeekOrigin.End); + returnSurface.LoadElementsFromStream(surfaceFileStream); + } + + if (captureBitmap != null) + { + returnSurface.Image = captureBitmap; + Log.InfoFormat("Information about .greenshot file: {0}x{1}-{2} Resolution {3}x{4}", captureBitmap.Width, captureBitmap.Height, captureBitmap.PixelFormat, captureBitmap.HorizontalResolution, captureBitmap.VerticalResolution); + } + + return returnSurface; + } + } +} diff --git a/src/Greenshot.Editor/FileFormatHandlers/IconFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/IconFileFormatHandler.cs new file mode 100644 index 000000000..d2769d5f0 --- /dev/null +++ b/src/Greenshot.Editor/FileFormatHandlers/IconFileFormatHandler.cs @@ -0,0 +1,218 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Plugin; +using log4net; + +namespace Greenshot.Editor.FileFormatHandlers +{ + /// + /// THis is the .ico format handler + /// + public class IconFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler + { + private static readonly ILog Log = LogManager.GetLogger(typeof(IconFileFormatHandler)); + + private readonly IReadOnlyCollection _ourExtensions = new[] { ".ico" }; + + public IconFileFormatHandler() + { + SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.SaveToStream] = _ourExtensions; + } + + public override bool TrySaveToStream(Bitmap bitmap, Stream stream, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null) + { + IList images = new List + { + bitmap + }; + + var binaryWriter = new BinaryWriter(stream); + // + // ICONDIR structure + // + binaryWriter.Write((short)0); // reserved + binaryWriter.Write((short)1); // image type (icon) + binaryWriter.Write((short)images.Count); // number of images + + IList imageSizes = new List(); + IList encodedImages = new List(); + foreach (var image in images) + { + // Pick the best fit + var sizes = new[] + { + 16, 32, 48 + }; + int size = 256; + foreach (var possibleSize in sizes) + { + if (image.Width <= possibleSize && image.Height <= possibleSize) + { + size = possibleSize; + break; + } + } + + var imageStream = new MemoryStream(); + if (image.Width == size && image.Height == size) + { + using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); + clonedImage.Save(imageStream, ImageFormat.Png); + imageSizes.Add(new Size(size, size)); + } + else + { + // Resize to the specified size, first make sure the image is 32bpp + using var clonedImage = ImageHelper.Clone(image, PixelFormat.Format32bppArgb); + using var resizedImage = ImageHelper.ResizeImage(clonedImage, true, true, Color.Empty, size, size, null); + resizedImage.Save(imageStream, ImageFormat.Png); + imageSizes.Add(resizedImage.Size); + } + + imageStream.Seek(0, SeekOrigin.Begin); + encodedImages.Add(imageStream); + } + + // + // ICONDIRENTRY structure + // + const int iconDirSize = 6; + const int iconDirEntrySize = 16; + + var offset = iconDirSize + (images.Count * iconDirEntrySize); + for (int i = 0; i < images.Count; i++) + { + var imageSize = imageSizes[i]; + // Write the width / height, 0 means 256 + binaryWriter.Write(imageSize.Width == 256 ? (byte)0 : (byte)imageSize.Width); + binaryWriter.Write(imageSize.Height == 256 ? (byte)0 : (byte)imageSize.Height); + binaryWriter.Write((byte)0); // no pallete + binaryWriter.Write((byte)0); // reserved + binaryWriter.Write((short)0); // no color planes + binaryWriter.Write((short)32); // 32 bpp + binaryWriter.Write((int)encodedImages[i].Length); // image data length + binaryWriter.Write(offset); + offset += (int)encodedImages[i].Length; + } + + binaryWriter.Flush(); + // + // Write image data + // + foreach (var encodedImage in encodedImages) + { + encodedImage.WriteTo(stream); + encodedImage.Dispose(); + } + + // TODO: Implement this + return true; + } + + public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) + { + _ = stream.Seek(0, SeekOrigin.Current); + + // Icon logic, try to get the Vista icon, else the biggest possible + try + { + using Image tmpImage = ExtractVistaIcon(stream); + if (tmpImage != null) + { + bitmap = ImageHelper.Clone(tmpImage, PixelFormat.Format32bppArgb); + return true; + } + } + catch (Exception vistaIconException) + { + Log.Warn("Can't read icon", vistaIconException); + } + + try + { + // No vista icon, try normal icon + stream.Position = stream.Seek(0, SeekOrigin.Begin); + // We create a copy of the bitmap, so everything else can be disposed + using Icon tmpIcon = new Icon(stream, new Size(1024, 1024)); + using Image tmpImage = tmpIcon.ToBitmap(); + bitmap = ImageHelper.Clone(tmpImage, PixelFormat.Format32bppArgb); + return true; + } + catch (Exception iconException) + { + Log.Warn("Can't read icon", iconException); + } + + bitmap = null; + return false; + } + + /// + /// Based on: https://www.codeproject.com/KB/cs/IconExtractor.aspx + /// And a hint from: https://www.codeproject.com/KB/cs/IconLib.aspx + /// + /// Stream with the icon information + /// Bitmap with the Vista Icon (256x256) + private static Bitmap ExtractVistaIcon(Stream iconStream) + { + const int sizeIconDir = 6; + const int sizeIconDirEntry = 16; + Bitmap bmpPngExtracted = null; + try + { + byte[] srcBuf = new byte[iconStream.Length]; + // TODO: Check if there is a need to process the result + _ = iconStream.Read(srcBuf, 0, (int)iconStream.Length); + int iCount = BitConverter.ToInt16(srcBuf, 4); + for (int iIndex = 0; iIndex < iCount; iIndex++) + { + int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex]; + int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1]; + if (iWidth != 0 || iHeight != 0) continue; + + int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); + int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); + using MemoryStream destStream = new MemoryStream(); + destStream.Write(srcBuf, iImageOffset, iImageSize); + destStream.Seek(0, SeekOrigin.Begin); + bmpPngExtracted = new Bitmap(destStream); // This is PNG! :) + break; + } + } + catch + { + return null; + } + + return bmpPngExtracted; + } + } +} diff --git a/src/Greenshot.Editor/FileFormatHandlers/MetaFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/MetaFileFormatHandler.cs new file mode 100644 index 000000000..04c3825b3 --- /dev/null +++ b/src/Greenshot.Editor/FileFormatHandlers/MetaFileFormatHandler.cs @@ -0,0 +1,81 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Editor.Drawing; + +namespace Greenshot.Editor.FileFormatHandlers +{ + /// + /// This handles the Windows metafile files + /// + public class MetaFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler + { + private readonly IReadOnlyCollection _ourExtensions = new[] { ".wmf", ".emf" }; + + public MetaFileFormatHandler() + { + SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions; + } + + /// + public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null) + { + return false; + } + + /// + public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) + { + try + { + if (Image.FromStream(stream, true, true) is Metafile metaFile) + { + bitmap = ImageHelper.Clone(metaFile, PixelFormat.Format32bppArgb); + return true; + } + } + catch + { + // Ignore + } + bitmap = null; + return false; + } + + /// + public override IEnumerable LoadDrawablesFromStream(Stream stream, string extension, ISurface surface = null) + { + if (Image.FromStream(stream, true, true) is Metafile metaFile) + { + yield return new MetafileContainer(metaFile, surface); + } + } + } +} diff --git a/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs new file mode 100644 index 000000000..14a33246e --- /dev/null +++ b/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs @@ -0,0 +1,89 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Editor.Drawing; +using log4net; +using Svg; + +namespace Greenshot.Editor.FileFormatHandlers +{ + /// + /// This handled the loading of SVG images to the editor + /// + public class SvgFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler + { + private static readonly ILog Log = LogManager.GetLogger(typeof(SvgFileFormatHandler)); + private readonly IReadOnlyCollection _ourExtensions = new[] { ".svg" }; + + public SvgFileFormatHandler() + { + SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions; + } + + public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) + { + var svgDocument = SvgDocument.Open(stream); + + try + { + bitmap = svgDocument.Draw(); + return true; + } + catch (Exception ex) + { + Log.Error("Can't load SVG", ex); + } + bitmap = null; + return false; + } + + public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null) + { + // TODO: Implement this + return false; + } + + public override IEnumerable LoadDrawablesFromStream(Stream stream, string extension, ISurface parent = null) + { + SvgDocument svgDocument = null; + try + { + svgDocument = SvgDocument.Open(stream); + } + catch (Exception ex) + { + Log.Error("Can't load SVG", ex); + } + if (svgDocument != null) + { + yield return new SvgContainer(svgDocument, parent); + } + } + } +} diff --git a/src/Greenshot.Editor/FileFormatHandlers/WpfFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/WpfFileFormatHandler.cs new file mode 100644 index 000000000..2d655bb1b --- /dev/null +++ b/src/Greenshot.Editor/FileFormatHandlers/WpfFileFormatHandler.cs @@ -0,0 +1,144 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Windows.Media.Imaging; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Core; +using Greenshot.Base.Interfaces.Plugin; +using log4net; +using Microsoft.Win32; + +namespace Greenshot.Editor.FileFormatHandlers +{ + /// + /// This is the System.Windows.Media.Imaging (WPF) file format handler, which uses WIC + /// + public class WpfFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler + { + private static readonly ILog Log = LogManager.GetLogger(typeof(WpfFileFormatHandler)); + private const string HeifDecoder = "{E9A4A80A-44FE-4DE4-8971-7150B10A5199}"; + private const string WicDecoderCategory = "{7ED96837-96F0-4812-B211-F13C24117ED3}"; + + private IReadOnlyCollection LoadFromStreamExtensions { get; } = new []{ ".jxr", ".dds", ".hdp", ".wdp", ".wmp"}; + private IReadOnlyCollection SaveToStreamExtensions { get; } = new[] { ".jxr" }; + + public WpfFileFormatHandler() + { + LoadFromStreamExtensions = LoadFromStreamExtensions.ToList().Concat(RetrieveSupportedExtensions()).OrderBy(e => e).Distinct().ToArray(); + + SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = LoadFromStreamExtensions; + SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = LoadFromStreamExtensions; + SupportedExtensions[FileFormatHandlerActions.SaveToStream] = SaveToStreamExtensions; + } + + /// + /// Detect all the formats WIC supports + /// + /// IEnumerable{string} + private IEnumerable RetrieveSupportedExtensions() + { + string baseKeyPath; + if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess) + { + baseKeyPath = "Wow6432Node\\CLSID"; + } + else + { + baseKeyPath = "CLSID"; + } + + using RegistryKey baseKey = Registry.ClassesRoot.OpenSubKey(baseKeyPath, false); + if (baseKey == null) yield break; + + var wicDecoderCategoryPath = Path.Combine(baseKeyPath, WicDecoderCategory, "instance"); + using RegistryKey categoryKey = Registry.ClassesRoot.OpenSubKey(wicDecoderCategoryPath, false); + if (categoryKey == null) + { + yield break; + } + foreach (var codecGuid in categoryKey.GetSubKeyNames()) + { + // Read the properties of the single registered decoder + using var codecKey = baseKey.OpenSubKey(codecGuid); + if (codecKey == null) continue; + + var fileExtensions = Convert.ToString(codecKey.GetValue("FileExtensions", "")).ToLowerInvariant(); + foreach (var fileExtension in fileExtensions.Split(',')) + { + yield return fileExtension; + } + } + var heifDecoderPath = Path.Combine(baseKeyPath, HeifDecoder); + + using RegistryKey heifKey = Registry.ClassesRoot.OpenSubKey(heifDecoderPath, false); + if (heifKey == null) yield break; + + yield return ".heic"; + yield return ".heif"; + } + + /// + public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null) + { + surfaceOutputSettings ??= new SurfaceOutputSettings(); + try + { + var bitmapSource = bitmap.ToBitmapSource(); + var bitmapFrame = BitmapFrame.Create(bitmapSource); + var jpegXrEncoder = new WmpBitmapEncoder(); + jpegXrEncoder.Frames.Add(bitmapFrame); + // TODO: Support supplying a quality + jpegXrEncoder.ImageQualityLevel = surfaceOutputSettings.JPGQuality / 100f; + jpegXrEncoder.Save(destination); + return true; + } + catch (Exception ex) + { + Log.Error("Couldn't save image as JPEG XR: ", ex); + return false; + } + } + + /// + public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) + { + try + { + var bitmapDecoder = BitmapDecoder.Create(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None); + var bitmapSource = bitmapDecoder.Frames[0]; + bitmap = bitmapSource.ToBitmap(); + return true; + } + catch (Exception ex) + { + Log.Error("Couldn't load image: ", ex); + } + + bitmap = null; + return false; + } + } +} diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index 3e1be9489..8ab283d0b 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -56,13 +56,13 @@ namespace Greenshot.Editor.Forms private static readonly ILog Log = LogManager.GetLogger(typeof(ImageEditorForm)); private static readonly EditorConfiguration EditorConfiguration = IniConfig.GetIniSection(); - private static readonly List IgnoreDestinations = new List + private static readonly List IgnoreDestinations = new() { nameof(WellKnownDestinations.Picker), EditorDestination.DESIGNATION }; - private static readonly List EditorList = new List(); + private static readonly List EditorList = new(); private Surface _surface; private GreenshotToolStripButton[] _toolbarButtons; @@ -78,7 +78,7 @@ namespace Greenshot.Editor.Forms // whether part of the editor controls are disabled depending on selected item(s) private bool _controlsDisabledDueToConfirmable; - // Used for tracking the mouse scrollwheel changes + // Used for tracking the mouse scroll wheel changes private DateTime _zoomStartTime = DateTime.Now; /// @@ -181,6 +181,20 @@ namespace Greenshot.Editor.Forms UpdateUi(); + // Use best fit, for those capture modes where we can get huge images + bool useBestFit = _surface.CaptureDetails.CaptureMode switch + { + CaptureMode.File => true, + CaptureMode.Clipboard => true, + CaptureMode.IE => true, + _ => false + }; + + if (useBestFit) + { + ZoomBestFitMenuItemClick(this, EventArgs.Empty); + } + // Workaround: As the cursor is (mostly) selected on the surface a funny artifact is visible, this fixes it. HideToolstripItems(); } @@ -1290,7 +1304,7 @@ namespace Greenshot.Editor.Forms propertiesToolStrip.SuspendLayout(); if (_surface.HasSelectedElements || _surface.DrawingMode != DrawingModes.None) { - FieldAggregator props = _surface.FieldAggregator; + var props = (FieldAggregator)_surface.FieldAggregator; btnFillColor.Visible = props.HasFieldValue(FieldType.FILL_COLOR); btnLineColor.Visible = props.HasFieldValue(FieldType.LINE_COLOR); lineThicknessLabel.Visible = lineThicknessUpDown.Visible = props.HasFieldValue(FieldType.LINE_THICKNESS); @@ -1350,7 +1364,7 @@ namespace Greenshot.Editor.Forms btnStepLabel.Image = icon; addCounterToolStripMenuItem.Image = icon; - FieldAggregator props = _surface.FieldAggregator; + FieldAggregator props = (FieldAggregator)_surface.FieldAggregator; // if a confirmable element is selected, we must disable most of the controls // since we demand confirmation or cancel for confirmable element if (props.HasFieldValue(FieldType.FLAGS) && ((FieldFlag) props.GetFieldValue(FieldType.FLAGS) & FieldFlag.CONFIRMABLE) == FieldFlag.CONFIRMABLE) diff --git a/src/Greenshot.Editor/Greenshot.Editor.csproj b/src/Greenshot.Editor/Greenshot.Editor.csproj index 768bdb99d..7da9d555d 100644 --- a/src/Greenshot.Editor/Greenshot.Editor.csproj +++ b/src/Greenshot.Editor/Greenshot.Editor.csproj @@ -1,4 +1,7 @@  + + True + PreserveNewest diff --git a/src/Greenshot.Editor/Memento/AddElementMemento.cs b/src/Greenshot.Editor/Memento/AddElementMemento.cs index dbee523a6..1a95d19ce 100644 --- a/src/Greenshot.Editor/Memento/AddElementMemento.cs +++ b/src/Greenshot.Editor/Memento/AddElementMemento.cs @@ -20,9 +20,8 @@ */ using System; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; -using Greenshot.Editor.Drawing; - namespace Greenshot.Editor.Memento { /// @@ -31,9 +30,9 @@ namespace Greenshot.Editor.Memento public class AddElementMemento : IMemento { private IDrawableContainer _drawableContainer; - private Surface _surface; + private ISurface _surface; - public AddElementMemento(Surface surface, IDrawableContainer drawableContainer) + public AddElementMemento(ISurface surface, IDrawableContainer drawableContainer) { _surface = surface; _drawableContainer = drawableContainer; diff --git a/src/Greenshot.Editor/Memento/AddElementsMemento.cs b/src/Greenshot.Editor/Memento/AddElementsMemento.cs index 80c9d3d99..8649dec9b 100644 --- a/src/Greenshot.Editor/Memento/AddElementsMemento.cs +++ b/src/Greenshot.Editor/Memento/AddElementsMemento.cs @@ -19,8 +19,8 @@ * along with this program. If not, see . */ +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; -using Greenshot.Editor.Drawing; namespace Greenshot.Editor.Memento { @@ -30,9 +30,9 @@ namespace Greenshot.Editor.Memento public class AddElementsMemento : IMemento { private IDrawableContainerList _containerList; - private Surface _surface; + private ISurface _surface; - public AddElementsMemento(Surface surface, IDrawableContainerList containerList) + public AddElementsMemento(ISurface surface, IDrawableContainerList containerList) { _surface = surface; _containerList = containerList; diff --git a/src/Greenshot.Editor/Memento/DeleteElementMemento.cs b/src/Greenshot.Editor/Memento/DeleteElementMemento.cs index ade27b23a..0acc19f83 100644 --- a/src/Greenshot.Editor/Memento/DeleteElementMemento.cs +++ b/src/Greenshot.Editor/Memento/DeleteElementMemento.cs @@ -20,8 +20,8 @@ */ using System; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; -using Greenshot.Editor.Drawing; namespace Greenshot.Editor.Memento { @@ -31,9 +31,9 @@ namespace Greenshot.Editor.Memento public class DeleteElementMemento : IMemento { private IDrawableContainer _drawableContainer; - private readonly Surface _surface; + private readonly ISurface _surface; - public DeleteElementMemento(Surface surface, IDrawableContainer drawableContainer) + public DeleteElementMemento(ISurface surface, IDrawableContainer drawableContainer) { _surface = surface; _drawableContainer = drawableContainer; diff --git a/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs b/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs index d4d4a3be1..e4b0b747e 100644 --- a/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs +++ b/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs @@ -19,8 +19,8 @@ * along with this program. If not, see . */ +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; -using Greenshot.Editor.Drawing; namespace Greenshot.Editor.Memento { @@ -30,9 +30,9 @@ namespace Greenshot.Editor.Memento public class DeleteElementsMemento : IMemento { private IDrawableContainerList _containerList; - private Surface _surface; + private ISurface _surface; - public DeleteElementsMemento(Surface surface, IDrawableContainerList containerList) + public DeleteElementsMemento(ISurface surface, IDrawableContainerList containerList) { _surface = surface; _containerList = containerList; diff --git a/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs b/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs index 71d2e9f36..c6ba814c3 100644 --- a/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs +++ b/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs @@ -21,8 +21,8 @@ using System.Drawing; using System.Drawing.Drawing2D; +using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; -using Greenshot.Editor.Drawing; namespace Greenshot.Editor.Memento { @@ -32,10 +32,10 @@ namespace Greenshot.Editor.Memento public class SurfaceBackgroundChangeMemento : IMemento { private Image _image; - private Surface _surface; + private ISurface _surface; private Matrix _matrix; - public SurfaceBackgroundChangeMemento(Surface surface, Matrix matrix) + public SurfaceBackgroundChangeMemento(ISurface surface, Matrix matrix) { _surface = surface; _image = surface.Image; diff --git a/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs index de492dde4..940eaccb6 100644 --- a/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Box/Forms/SettingsForm.Designer.cs @@ -87,7 +87,7 @@ namespace Greenshot.Plugin.Box.Forms { this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.Location = new System.Drawing.Point(208, 12); this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; - this.combobox_uploadimageformat.PropertyName = "UploadFormat"; + this.combobox_uploadimageformat.PropertyName = nameof(BoxConfiguration.UploadFormat); this.combobox_uploadimageformat.SectionName = "Box"; this.combobox_uploadimageformat.Size = new System.Drawing.Size(215, 21); this.combobox_uploadimageformat.TabIndex = 5; @@ -115,7 +115,7 @@ namespace Greenshot.Plugin.Box.Forms { this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "box.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(208, 45); this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; - this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard"; + this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(BoxConfiguration.AfterUploadLinkToClipBoard); this.checkboxAfterUploadLinkToClipBoard.SectionName = "Box"; this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17); this.checkboxAfterUploadLinkToClipBoard.TabIndex = 10; diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs index ddcb66530..669087901 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceDestination.cs @@ -54,8 +54,8 @@ namespace Greenshot.Plugin.Confluence Uri confluenceIconUri = new Uri("/Greenshot.Plugin.Confluence;component/Images/Confluence.ico", UriKind.Relative); using (Stream iconStream = Application.GetResourceStream(confluenceIconUri)?.Stream) { - // TODO: Check what to do with the IImage - ConfluenceIcon = ImageHelper.FromStream(iconStream); + // TODO: Replace with FileFormatHandler + ConfluenceIcon = ImageIO.FromStream(iconStream); } IsInitialized = true; diff --git a/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs b/src/Greenshot.Plugin.Dropbox/DropboxConfiguration.cs similarity index 92% rename from src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs rename to src/Greenshot.Plugin.Dropbox/DropboxConfiguration.cs index 996b964f0..b9dd8bf0c 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxPluginConfiguration.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxConfiguration.cs @@ -1,74 +1,73 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Windows.Forms; -using Greenshot.Base.Core; -using Greenshot.Base.Core.Enums; -using Greenshot.Base.IniFile; -using Greenshot.Plugin.Dropbox.Forms; - -namespace Greenshot.Plugin.Dropbox -{ - /// - /// Description of ImgurConfiguration. - /// - [IniSection("Dropbox", Description = "Greenshot Dropbox Plugin configuration")] - public class DropboxPluginConfiguration : IniSection - { - [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] - public OutputFormat UploadFormat { get; set; } - - [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] - public int UploadJpegQuality { get; set; } - - [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Dropbox link to clipboard.", DefaultValue = "true")] - public bool AfterUploadLinkToClipBoard { get; set; } - - [IniProperty("RefreshToken", Description = "Dropbox refresh Token", Encrypted = true, ExcludeIfNull = true)] - public string RefreshToken { get; set; } - - /// - /// AccessToken, not stored - /// - public string AccessToken { get; set; } - - /// - /// AccessTokenExpires, not stored - /// - public DateTimeOffset AccessTokenExpires { get; set; } - - /// - /// A form for token - /// - /// bool true if OK was pressed, false if cancel - public bool ShowConfigDialog() - { - DialogResult result = new SettingsForm().ShowDialog(); - if (result == DialogResult.OK) - { - return true; - } - - return false; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Windows.Forms; +using Greenshot.Base.Core.Enums; +using Greenshot.Base.IniFile; +using Greenshot.Plugin.Dropbox.Forms; + +namespace Greenshot.Plugin.Dropbox +{ + /// + /// The configuration for Dropbox + /// + [IniSection("Dropbox", Description = "Greenshot Dropbox Plugin configuration")] + public class DropboxConfiguration : IniSection + { + [IniProperty("UploadFormat", Description = "What file type to use for uploading", DefaultValue = "png")] + public OutputFormat UploadFormat { get; set; } + + [IniProperty("UploadJpegQuality", Description = "JPEG file save quality in %.", DefaultValue = "80")] + public int UploadJpegQuality { get; set; } + + [IniProperty("AfterUploadLinkToClipBoard", Description = "After upload send Dropbox link to clipboard.", DefaultValue = "true")] + public bool AfterUploadLinkToClipBoard { get; set; } + + [IniProperty("RefreshToken", Description = "Dropbox refresh Token", Encrypted = true, ExcludeIfNull = true)] + public string RefreshToken { get; set; } + + /// + /// AccessToken, not stored + /// + public string AccessToken { get; set; } + + /// + /// AccessTokenExpires, not stored + /// + public DateTimeOffset AccessTokenExpires { get; set; } + + /// + /// A form for token + /// + /// bool true if OK was pressed, false if cancel + public bool ShowConfigDialog() + { + DialogResult result = new SettingsForm().ShowDialog(); + if (result == DialogResult.OK) + { + return true; + } + + return false; + } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs index 59f6c45b1..d29c3cbd0 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxDestination.cs @@ -29,7 +29,7 @@ namespace Greenshot.Plugin.Dropbox { internal class DropboxDestination : AbstractDestination { - private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection(); + private static readonly DropboxConfiguration DropboxConfig = IniConfig.GetIniSection(); private readonly DropboxPlugin _plugin; diff --git a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs index 9a82b0f40..69026066c 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxPlugin.cs @@ -37,7 +37,7 @@ namespace Greenshot.Plugin.Dropbox public class DropboxPlugin : IGreenshotPlugin { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxPlugin)); - private static DropboxPluginConfiguration _config; + private static DropboxConfiguration _config; private ComponentResourceManager _resources; private ToolStripMenuItem _itemPlugInConfig; @@ -71,7 +71,7 @@ namespace Greenshot.Plugin.Dropbox public bool Initialize() { // Register configuration (don't need the configuration itself) - _config = IniConfig.GetIniSection(); + _config = IniConfig.GetIniSection(); _resources = new ComponentResourceManager(typeof(DropboxPlugin)); SimpleServiceProvider.Current.AddService(new DropboxDestination(this)); _itemPlugInConfig = new ToolStripMenuItem diff --git a/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs index 4b5eb4d60..c7f6dcfe9 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxUtils.cs @@ -37,7 +37,7 @@ namespace Greenshot.Plugin.Dropbox public class DropboxUtils { private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(typeof(DropboxUtils)); - private static readonly DropboxPluginConfiguration DropboxConfig = IniConfig.GetIniSection(); + private static readonly DropboxConfiguration DropboxConfig = IniConfig.GetIniSection(); private DropboxUtils() { diff --git a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs index 174342a90..e65cba1ec 100644 --- a/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Dropbox/Forms/SettingsForm.Designer.cs @@ -86,7 +86,7 @@ namespace Greenshot.Plugin.Dropbox.Forms { this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.Location = new System.Drawing.Point(116, 9); this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; - this.combobox_uploadimageformat.PropertyName = "UploadFormat"; + this.combobox_uploadimageformat.PropertyName = nameof(DropboxConfiguration.UploadFormat); this.combobox_uploadimageformat.SectionName = "Dropbox"; this.combobox_uploadimageformat.Size = new System.Drawing.Size(309, 21); this.combobox_uploadimageformat.TabIndex = 1; @@ -112,7 +112,7 @@ namespace Greenshot.Plugin.Dropbox.Forms { this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "dropbox.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(116, 37); this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; - this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard"; + this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(DropboxConfiguration.AfterUploadLinkToClipBoard); this.checkboxAfterUploadLinkToClipBoard.SectionName = "Dropbox"; this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17); this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2; diff --git a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs index 273535952..4083827e3 100644 --- a/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs +++ b/src/Greenshot.Plugin.ExternalCommand/ExternalCommandDestination.cs @@ -77,7 +77,7 @@ namespace Greenshot.Plugin.ExternalCommand } bool runInBackground = config.RunInbackground[_presetCommand]; - string fullPath = captureDetails.Filename ?? ImageOutput.SaveNamedTmpFile(surface, captureDetails, outputSettings); + string fullPath = captureDetails.Filename ?? ImageIO.SaveNamedTmpFile(surface, captureDetails, outputSettings); string output; string error; diff --git a/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs index 46549f943..5eed52b57 100644 --- a/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Flickr/Forms/SettingsForm.Designer.cs @@ -93,7 +93,7 @@ namespace Greenshot.Plugin.Flickr.Forms { this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.Location = new System.Drawing.Point(174, 6); this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; - this.combobox_uploadimageformat.PropertyName = "UploadFormat"; + this.combobox_uploadimageformat.PropertyName = nameof(FlickrConfiguration.UploadFormat); this.combobox_uploadimageformat.SectionName = "Flickr"; this.combobox_uploadimageformat.Size = new System.Drawing.Size(251, 21); this.combobox_uploadimageformat.TabIndex = 1; @@ -111,7 +111,7 @@ namespace Greenshot.Plugin.Flickr.Forms { this.checkBoxPublic.LanguageKey = "flickr.public"; this.checkBoxPublic.Location = new System.Drawing.Point(174, 88); this.checkBoxPublic.Name = "checkBoxPublic"; - this.checkBoxPublic.PropertyName = "flickrIsPublic"; + this.checkBoxPublic.PropertyName = nameof(FlickrConfiguration.IsPublic); this.checkBoxPublic.SectionName = "Flickr"; this.checkBoxPublic.Size = new System.Drawing.Size(55, 17); this.checkBoxPublic.TabIndex = 4; @@ -122,7 +122,7 @@ namespace Greenshot.Plugin.Flickr.Forms { this.checkBoxFamily.LanguageKey = "flickr.family"; this.checkBoxFamily.Location = new System.Drawing.Point(265, 88); this.checkBoxFamily.Name = "checkBoxFamily"; - this.checkBoxFamily.PropertyName = "flickrIsFamily"; + this.checkBoxFamily.PropertyName = nameof(FlickrConfiguration.IsFamily); this.checkBoxFamily.SectionName = "Flickr"; this.checkBoxFamily.Size = new System.Drawing.Size(55, 17); this.checkBoxFamily.TabIndex = 5; @@ -133,7 +133,7 @@ namespace Greenshot.Plugin.Flickr.Forms { this.checkBoxFriend.LanguageKey = "flickr.friend"; this.checkBoxFriend.Location = new System.Drawing.Point(350, 88); this.checkBoxFriend.Name = "checkBoxFriend"; - this.checkBoxFriend.PropertyName = "flickrIsFriend"; + this.checkBoxFriend.PropertyName = nameof(FlickrConfiguration.IsFriend); this.checkBoxFriend.SectionName = "Flickr"; this.checkBoxFriend.Size = new System.Drawing.Size(55, 17); this.checkBoxFriend.TabIndex = 6; @@ -155,7 +155,7 @@ namespace Greenshot.Plugin.Flickr.Forms { this.combobox_safetyLevel.FormattingEnabled = true; this.combobox_safetyLevel.Location = new System.Drawing.Point(174, 33); this.combobox_safetyLevel.Name = "combobox_safetyLevel"; - this.combobox_safetyLevel.PropertyName = "SafetyLevel"; + this.combobox_safetyLevel.PropertyName = nameof(FlickrConfiguration.SafetyLevel); this.combobox_safetyLevel.SectionName = "Flickr"; this.combobox_safetyLevel.Size = new System.Drawing.Size(251, 21); this.combobox_safetyLevel.TabIndex = 2; @@ -173,7 +173,7 @@ namespace Greenshot.Plugin.Flickr.Forms { this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "flickr.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(173, 116); this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; - this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard"; + this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(FlickrConfiguration.AfterUploadLinkToClipBoard); this.checkboxAfterUploadLinkToClipBoard.SectionName = "Flickr"; this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17); this.checkboxAfterUploadLinkToClipBoard.TabIndex = 7; @@ -184,7 +184,7 @@ namespace Greenshot.Plugin.Flickr.Forms { this.checkBox_hiddenfromsearch.LanguageKey = "flickr.label_HiddenFromSearch"; this.checkBox_hiddenfromsearch.Location = new System.Drawing.Point(174, 60); this.checkBox_hiddenfromsearch.Name = "checkBox_hiddenfromsearch"; - this.checkBox_hiddenfromsearch.PropertyName = "HiddenFromSearch"; + this.checkBox_hiddenfromsearch.PropertyName = nameof(FlickrConfiguration.HiddenFromSearch); this.checkBox_hiddenfromsearch.SectionName = "Flickr"; this.checkBox_hiddenfromsearch.Size = new System.Drawing.Size(118, 17); this.checkBox_hiddenfromsearch.TabIndex = 3; diff --git a/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs index 7b0325981..23e68012f 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Forms/SettingsForm.Designer.cs @@ -86,7 +86,7 @@ namespace Greenshot.Plugin.GooglePhotos.Forms { this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.Location = new System.Drawing.Point(197, 12); this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; - this.combobox_uploadimageformat.PropertyName = "UploadFormat"; + this.combobox_uploadimageformat.PropertyName = nameof(GooglePhotosConfiguration.UploadFormat); this.combobox_uploadimageformat.SectionName = "GooglePhotos"; this.combobox_uploadimageformat.Size = new System.Drawing.Size(225, 21); this.combobox_uploadimageformat.TabIndex = 1; @@ -114,7 +114,7 @@ namespace Greenshot.Plugin.GooglePhotos.Forms { this.checkboxAfterUploadLinkToClipBoard.LanguageKey = "googlephotos.label_AfterUploadLinkToClipBoard"; this.checkboxAfterUploadLinkToClipBoard.Location = new System.Drawing.Point(197, 50); this.checkboxAfterUploadLinkToClipBoard.Name = "checkboxAfterUploadLinkToClipBoard"; - this.checkboxAfterUploadLinkToClipBoard.PropertyName = "AfterUploadLinkToClipBoard"; + this.checkboxAfterUploadLinkToClipBoard.PropertyName = nameof(GooglePhotosConfiguration.AfterUploadLinkToClipBoard); this.checkboxAfterUploadLinkToClipBoard.SectionName = "GooglePhotos"; this.checkboxAfterUploadLinkToClipBoard.Size = new System.Drawing.Size(104, 17); this.checkboxAfterUploadLinkToClipBoard.TabIndex = 2; diff --git a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs index f40ee6460..1b9b52c42 100644 --- a/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Imgur/Forms/SettingsForm.Designer.cs @@ -86,7 +86,7 @@ namespace Greenshot.Plugin.Imgur.Forms { this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.Location = new System.Drawing.Point(168, 7); this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; - this.combobox_uploadimageformat.PropertyName = "UploadFormat"; + this.combobox_uploadimageformat.PropertyName = nameof(ImgurConfiguration.UploadFormat); this.combobox_uploadimageformat.SectionName = "Imgur"; this.combobox_uploadimageformat.Size = new System.Drawing.Size(210, 21); this.combobox_uploadimageformat.TabIndex = 1; @@ -115,7 +115,7 @@ namespace Greenshot.Plugin.Imgur.Forms { this.checkbox_anonymous_access.LanguageKey = "imgur.anonymous_access"; this.checkbox_anonymous_access.Location = new System.Drawing.Point(15, 38); this.checkbox_anonymous_access.Name = "checkbox_anonymous_access"; - this.checkbox_anonymous_access.PropertyName = "AnonymousAccess"; + this.checkbox_anonymous_access.PropertyName = nameof(ImgurConfiguration.AnonymousAccess); this.checkbox_anonymous_access.SectionName = "Imgur"; this.checkbox_anonymous_access.Size = new System.Drawing.Size(139, 17); this.checkbox_anonymous_access.TabIndex = 2; @@ -126,7 +126,7 @@ namespace Greenshot.Plugin.Imgur.Forms { this.checkbox_usepagelink.LanguageKey = "imgur.use_page_link"; this.checkbox_usepagelink.Location = new System.Drawing.Point(15, 57); this.checkbox_usepagelink.Name = "checkbox_usepagelink"; - this.checkbox_usepagelink.PropertyName = "UsePageLink"; + this.checkbox_usepagelink.PropertyName = nameof(ImgurConfiguration.UsePageLink); this.checkbox_usepagelink.SectionName = "Imgur"; this.checkbox_usepagelink.Size = new System.Drawing.Size(251, 17); this.checkbox_usepagelink.TabIndex = 3; diff --git a/src/Greenshot.Plugin.Imgur/ImgurUtils.cs b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs index a2156d6d0..02af34e56 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurUtils.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurUtils.cs @@ -179,7 +179,7 @@ namespace Greenshot.Plugin.Imgur { using (var requestStream = webRequest.GetRequestStream()) { - ImageOutput.SaveToStream(surfaceToUpload, requestStream, outputSettings); + ImageIO.SaveToStream(surfaceToUpload, requestStream, outputSettings); } using WebResponse response = webRequest.GetResponse(); @@ -265,7 +265,8 @@ namespace Greenshot.Plugin.Imgur Stream responseStream = response.GetResponseStream(); if (responseStream != null) { - imgurInfo.Image = ImageHelper.FromStream(responseStream); + // TODO: Replace with some other code, like the file format handler + imgurInfo.Image = ImageIO.FromStream(responseStream); } } diff --git a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs index 945abe034..6903f74fd 100644 --- a/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Jira/Forms/SettingsForm.Designer.cs @@ -94,7 +94,7 @@ namespace Greenshot.Plugin.Jira.Forms { this.textBoxUrl.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.textBoxUrl.Location = new System.Drawing.Point(164, 21); this.textBoxUrl.Name = "textBoxUrl"; - this.textBoxUrl.PropertyName = "Url"; + this.textBoxUrl.PropertyName = nameof(JiraConfiguration.Url); this.textBoxUrl.SectionName = "Jira"; this.textBoxUrl.Size = new System.Drawing.Size(214, 20); this.textBoxUrl.TabIndex = 6; @@ -105,7 +105,7 @@ namespace Greenshot.Plugin.Jira.Forms { this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.Location = new System.Drawing.Point(164, 47); this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; - this.combobox_uploadimageformat.PropertyName = "UploadFormat"; + this.combobox_uploadimageformat.PropertyName = nameof(JiraConfiguration.UploadFormat); this.combobox_uploadimageformat.SectionName = "Jira"; this.combobox_uploadimageformat.Size = new System.Drawing.Size(214, 21); this.combobox_uploadimageformat.TabIndex = 8; diff --git a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs index cf09272e2..fb1930c8c 100644 --- a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs @@ -89,7 +89,7 @@ namespace Greenshot.Plugin.Office.Destinations string imageFile = captureDetails.Filename; if (imageFile == null || surface.Modified || !Regex.IsMatch(imageFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { - imageFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + imageFile = ImageIO.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); createdFile = true; } @@ -107,7 +107,7 @@ namespace Greenshot.Plugin.Office.Destinations // Cleanup imageFile if we created it here, so less tmp-files are generated and left if (createdFile) { - ImageOutput.DeleteNamedTmpFile(imageFile); + ImageIO.DeleteNamedTmpFile(imageFile); } return exportInformation; diff --git a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs index da694be62..6d93c4096 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs @@ -160,7 +160,7 @@ namespace Greenshot.Plugin.Office.Destinations string tmpFile = captureDetails.Filename; if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { - tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + tmpFile = ImageIO.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); } else { diff --git a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs index a151d3388..3b9ce4bc8 100644 --- a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs @@ -114,7 +114,7 @@ namespace Greenshot.Plugin.Office.Destinations Size imageSize = Size.Empty; if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { - tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + tmpFile = ImageIO.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); imageSize = surface.Image.Size; } diff --git a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs index fd91295be..99cf4693c 100644 --- a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs @@ -88,7 +88,7 @@ namespace Greenshot.Plugin.Office.Destinations string tmpFile = captureDetails.Filename; if (tmpFile == null || surface.Modified || !Regex.IsMatch(tmpFile, @".*(\.png|\.gif|\.jpg|\.jpeg|\.tiff|\.bmp)$")) { - tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); + tmpFile = ImageIO.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings().PreventGreenshotFormat()); } if (_documentCaption != null) diff --git a/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs index 305888ee2..645623780 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/OneNoteExporter.cs @@ -97,7 +97,7 @@ namespace Greenshot.Plugin.Office.OfficeExport using var pngStream = new MemoryStream(); var pngOutputSettings = new SurfaceOutputSettings(OutputFormat.png, 100, false); - ImageOutput.SaveToStream(surfaceToUpload, pngStream, pngOutputSettings); + ImageIO.SaveToStream(surfaceToUpload, pngStream, pngOutputSettings); var base64String = Convert.ToBase64String(pngStream.GetBuffer()); var imageXmlStr = string.Format(XmlImageContent, base64String, surfaceToUpload.Image.Width, surfaceToUpload.Image.Height); var pageChangesXml = string.Format(XmlOutline, imageXmlStr, page.Id, OnenoteNamespace2010, page.Name); diff --git a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs index 9376f693e..1fff9f5c3 100644 --- a/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot.Plugin.Photobucket/Forms/SettingsForm.Designer.cs @@ -84,7 +84,7 @@ namespace Greenshot.Plugin.Photobucket.Forms { this.combobox_uploadimageformat.FormattingEnabled = true; this.combobox_uploadimageformat.Location = new System.Drawing.Point(102, 11); this.combobox_uploadimageformat.Name = "combobox_uploadimageformat"; - this.combobox_uploadimageformat.PropertyName = "UploadFormat"; + this.combobox_uploadimageformat.PropertyName = nameof(PhotobucketConfiguration.UploadFormat); this.combobox_uploadimageformat.SectionName = "Photobucket"; this.combobox_uploadimageformat.Size = new System.Drawing.Size(276, 21); this.combobox_uploadimageformat.TabIndex = 1; @@ -102,7 +102,7 @@ namespace Greenshot.Plugin.Photobucket.Forms { this.checkbox_usepagelink.LanguageKey = "photobucket.use_page_link"; this.checkbox_usepagelink.Location = new System.Drawing.Point(15, 43); this.checkbox_usepagelink.Name = "checkbox_usepagelink"; - this.checkbox_usepagelink.PropertyName = "UsePageLink"; + this.checkbox_usepagelink.PropertyName = nameof(PhotobucketConfiguration.UsePageLink); this.checkbox_usepagelink.SectionName = "Photobucket"; this.checkbox_usepagelink.Size = new System.Drawing.Size(251, 17); this.checkbox_usepagelink.TabIndex = 2; diff --git a/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs index 0f2557da2..0574a6d0c 100644 --- a/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs +++ b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs @@ -151,7 +151,7 @@ namespace Greenshot.Plugin.Win10.Destinations outputSettings.PreventGreenshotFormat(); // Create capture for export - ImageOutput.SaveToStream(surface, imageStream, outputSettings); + ImageIO.SaveToStream(surface, imageStream, outputSettings); imageStream.Position = 0; Log.Debug("Created RandomAccessStreamReference for the image"); var imageRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(imageStream); @@ -161,7 +161,7 @@ namespace Greenshot.Plugin.Win10.Destinations using (var tmpImageForThumbnail = surface.GetImageForExport()) using (var thumbnail = ImageHelper.CreateThumbnail(tmpImageForThumbnail, 240, 160)) { - ImageOutput.SaveToStream(thumbnail, null, thumbnailStream, outputSettings); + ImageIO.SaveToStream(thumbnail, null, thumbnailStream, outputSettings); thumbnailStream.Position = 0; thumbnailRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(thumbnailStream); Log.Debug("Created RandomAccessStreamReference for the thumbnail"); @@ -172,7 +172,7 @@ namespace Greenshot.Plugin.Win10.Destinations using (var logo = GreenshotResources.GetGreenshotIcon().ToBitmap()) using (var logoThumbnail = ImageHelper.CreateThumbnail(logo, 30, 30)) { - ImageOutput.SaveToStream(logoThumbnail, null, logoStream, outputSettings); + ImageIO.SaveToStream(logoThumbnail, null, logoStream, outputSettings); logoStream.Position = 0; logoRandomAccessStreamReference = RandomAccessStreamReference.CreateFromStream(logoStream); Log.Info("Created RandomAccessStreamReference for the logo"); diff --git a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs index 77aa0d663..fdc0c07fa 100644 --- a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs +++ b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs @@ -97,7 +97,7 @@ namespace Greenshot.Plugin.Win10 IEffect effect = new ResizeCanvasEffect(addedWidth, addedWidth, addedHeight, addedHeight); outputSettings.Effects.Add(effect); } - ImageOutput.SaveToStream(surface, imageStream, outputSettings); + ImageIO.SaveToStream(surface, imageStream, outputSettings); imageStream.Position = 0; var randomAccessStream = imageStream.AsRandomAccessStream(); @@ -117,7 +117,7 @@ namespace Greenshot.Plugin.Win10 OcrInformation result; using (var imageStream = new MemoryStream()) { - ImageOutput.SaveToStream(image, null, imageStream, new SurfaceOutputSettings()); + ImageIO.SaveToStream(image, null, imageStream, new SurfaceOutputSettings()); imageStream.Position = 0; var randomAccessStream = imageStream.AsRandomAccessStream(); diff --git a/src/Greenshot/App.config b/src/Greenshot/App.config index 3b81b058d..80b985a5c 100644 --- a/src/Greenshot/App.config +++ b/src/Greenshot/App.config @@ -1,7 +1,6 @@ - diff --git a/src/Greenshot/Destinations/FileDestination.cs b/src/Greenshot/Destinations/FileDestination.cs index 9389c3d26..64f8f21a9 100644 --- a/src/Greenshot/Destinations/FileDestination.cs +++ b/src/Greenshot/Destinations/FileDestination.cs @@ -68,7 +68,7 @@ namespace Greenshot.Destinations overwrite = true; Log.InfoFormat("Using previous filename"); fullPath = captureDetails.Filename; - outputSettings.Format = ImageOutput.FormatForFilename(fullPath); + outputSettings.Format = ImageIO.FormatForFilename(fullPath); } else { @@ -87,7 +87,7 @@ namespace Greenshot.Destinations // This is done for e.g. bugs #2974608, #2963943, #2816163, #2795317, #2789218, #3004642 try { - ImageOutput.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); + ImageIO.Save(surface, fullPath, overwrite, outputSettings, CoreConfig.OutputFileCopyPathToClipboard); outputMade = true; } catch (ArgumentException ex1) @@ -95,7 +95,7 @@ namespace Greenshot.Destinations // Our generated filename exists, display 'save-as' Log.InfoFormat("Not overwriting: {0}", ex1.Message); // when we don't allow to overwrite present a new SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); + fullPath = ImageIO.SaveWithDialog(surface, captureDetails); outputMade = fullPath != null; } catch (Exception ex2) @@ -104,7 +104,7 @@ namespace Greenshot.Destinations // Show the problem MessageBox.Show(Language.GetString(LangKey.error_save), Language.GetString(LangKey.error)); // when save failed we present a SaveWithDialog - fullPath = ImageOutput.SaveWithDialog(surface, captureDetails); + fullPath = ImageIO.SaveWithDialog(surface, captureDetails); outputMade = fullPath != null; } diff --git a/src/Greenshot/Destinations/FileWithDialogDestination.cs b/src/Greenshot/Destinations/FileWithDialogDestination.cs index 3a8520fb0..72924689f 100644 --- a/src/Greenshot/Destinations/FileWithDialogDestination.cs +++ b/src/Greenshot/Destinations/FileWithDialogDestination.cs @@ -57,7 +57,7 @@ namespace Greenshot.Destinations { ExportInformation exportInformation = new ExportInformation(Designation, Description); // Bug #2918756 don't overwrite path if SaveWithDialog returns null! - var savedTo = ImageOutput.SaveWithDialog(surface, captureDetails); + var savedTo = ImageIO.SaveWithDialog(surface, captureDetails); if (savedTo != null) { exportInformation.ExportMade = true; diff --git a/src/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs index f1c4f8bbc..fc7fb046d 100644 --- a/src/Greenshot/Forms/MainForm.cs +++ b/src/Greenshot/Forms/MainForm.cs @@ -36,6 +36,7 @@ using Greenshot.Base; using Greenshot.Base.Controls; using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; +using Greenshot.Base.Core.FileFormatHandlers; using Greenshot.Base.Help; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; @@ -43,6 +44,7 @@ using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.UnmanagedHelpers; using Greenshot.Configuration; using Greenshot.Destinations; +using Greenshot.Editor; using Greenshot.Editor.Destinations; using Greenshot.Editor.Drawing; using Greenshot.Editor.Forms; @@ -162,7 +164,7 @@ namespace Greenshot.Forms if (argument.ToLower().Equals("/exit")) { - // unregister application on uninstall (allow uninstall) + // un-register application on uninstall (allow uninstall) try { LOG.Info("Sending all instances the exit command."); @@ -387,6 +389,8 @@ namespace Greenshot.Forms _instance = this; + EditorInitialize.Initialize(); + // Factory for surface objects ISurface SurfaceFactory() => new Surface(); @@ -922,11 +926,11 @@ namespace Greenshot.Forms { Hide(); ShowInTaskbar = false; - - - using var loProcess = Process.GetCurrentProcess(); - loProcess.MaxWorkingSet = (IntPtr)750000; - loProcess.MinWorkingSet = (IntPtr)300000; + + // TODO: Do we really need this? + //using var loProcess = Process.GetCurrentProcess(); + //loProcess.MaxWorkingSet = (IntPtr)750000; + //loProcess.MinWorkingSet = (IntPtr)300000; } private void CaptureRegion() @@ -936,9 +940,12 @@ namespace Greenshot.Forms private void CaptureFile(IDestination destination = null) { + var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); + var extensions = fileFormatHandlers.ExtensionsFor(FileFormatHandlerActions.LoadFromStream).Select(e => $"*{e}").ToList(); + var openFileDialog = new OpenFileDialog { - Filter = @"Image files (*.greenshot, *.png, *.jpg, *.gif, *.bmp, *.ico, *.tiff, *.wmf)|*.greenshot; *.png; *.jpg; *.jpeg; *.gif; *.bmp; *.ico; *.tiff; *.tif; *.wmf" + Filter = @$"Image files ({string.Join(", ", extensions)})|{string.Join("; ", extensions)}" }; if (openFileDialog.ShowDialog() != DialogResult.OK) { @@ -1904,7 +1911,7 @@ namespace Greenshot.Forms LOG.Error("Error closing application!", e); } - ImageOutput.RemoveTmpFiles(); + ImageIO.RemoveTmpFiles(); // Store any open configuration changes try diff --git a/src/Greenshot/Forms/PrintOptionsDialog.Designer.cs b/src/Greenshot/Forms/PrintOptionsDialog.Designer.cs index 9cb5cc43d..9f9d0a13a 100644 --- a/src/Greenshot/Forms/PrintOptionsDialog.Designer.cs +++ b/src/Greenshot/Forms/PrintOptionsDialog.Designer.cs @@ -89,7 +89,7 @@ namespace Greenshot.Forms this.checkboxAllowShrink.LanguageKey = "printoptions_allowshrink"; this.checkboxAllowShrink.Location = new System.Drawing.Point(13, 23); this.checkboxAllowShrink.Name = "checkboxAllowShrink"; - this.checkboxAllowShrink.PropertyName = "OutputPrintAllowShrink"; + this.checkboxAllowShrink.PropertyName = nameof(coreConfiguration.OutputPrintAllowShrink); this.checkboxAllowShrink.Size = new System.Drawing.Size(168, 17); this.checkboxAllowShrink.TabIndex = 2; this.checkboxAllowShrink.Text = "Shrink printout to fit paper size"; @@ -103,7 +103,7 @@ namespace Greenshot.Forms this.checkboxAllowEnlarge.LanguageKey = "printoptions_allowenlarge"; this.checkboxAllowEnlarge.Location = new System.Drawing.Point(13, 46); this.checkboxAllowEnlarge.Name = "checkboxAllowEnlarge"; - this.checkboxAllowEnlarge.PropertyName = "OutputPrintAllowEnlarge"; + this.checkboxAllowEnlarge.PropertyName = nameof(coreConfiguration.OutputPrintAllowEnlarge); this.checkboxAllowEnlarge.Size = new System.Drawing.Size(174, 17); this.checkboxAllowEnlarge.TabIndex = 3; this.checkboxAllowEnlarge.Text = "Enlarge printout to fit paper size"; @@ -117,7 +117,7 @@ namespace Greenshot.Forms this.checkboxAllowCenter.LanguageKey = "printoptions_allowcenter"; this.checkboxAllowCenter.Location = new System.Drawing.Point(13, 92); this.checkboxAllowCenter.Name = "checkboxAllowCenter"; - this.checkboxAllowCenter.PropertyName = "OutputPrintCenter"; + this.checkboxAllowCenter.PropertyName = nameof(coreConfiguration.OutputPrintCenter); this.checkboxAllowCenter.Size = new System.Drawing.Size(137, 17); this.checkboxAllowCenter.TabIndex = 5; this.checkboxAllowCenter.Text = "Center printout on page"; @@ -131,7 +131,7 @@ namespace Greenshot.Forms this.checkboxAllowRotate.LanguageKey = "printoptions_allowrotate"; this.checkboxAllowRotate.Location = new System.Drawing.Point(13, 69); this.checkboxAllowRotate.Name = "checkboxAllowRotate"; - this.checkboxAllowRotate.PropertyName = "OutputPrintAllowRotate"; + this.checkboxAllowRotate.PropertyName = nameof(coreConfiguration.OutputPrintAllowRotate); this.checkboxAllowRotate.Size = new System.Drawing.Size(187, 17); this.checkboxAllowRotate.TabIndex = 4; this.checkboxAllowRotate.Text = "Rotate printout to page orientation"; @@ -158,7 +158,7 @@ namespace Greenshot.Forms this.checkboxDateTime.LanguageKey = "printoptions_timestamp"; this.checkboxDateTime.Location = new System.Drawing.Point(13, 115); this.checkboxDateTime.Name = "checkboxDateTime"; - this.checkboxDateTime.PropertyName = "OutputPrintFooter"; + this.checkboxDateTime.PropertyName = nameof(coreConfiguration.OutputPrintFooter); this.checkboxDateTime.Size = new System.Drawing.Size(187, 17); this.checkboxDateTime.TabIndex = 6; this.checkboxDateTime.Text = "Print date / time at bottom of page"; @@ -184,7 +184,7 @@ namespace Greenshot.Forms this.checkboxPrintInverted.LanguageKey = "printoptions_inverted"; this.checkboxPrintInverted.Location = new System.Drawing.Point(13, 88); this.checkboxPrintInverted.Name = "checkboxPrintInverted"; - this.checkboxPrintInverted.PropertyName = "OutputPrintInverted"; + this.checkboxPrintInverted.PropertyName = nameof(coreConfiguration.OutputPrintInverted); this.checkboxPrintInverted.Size = new System.Drawing.Size(141, 17); this.checkboxPrintInverted.TabIndex = 14; this.checkboxPrintInverted.Text = "Print with inverted colors"; @@ -198,7 +198,7 @@ namespace Greenshot.Forms this.radioBtnGrayScale.LanguageKey = "printoptions_printgrayscale"; this.radioBtnGrayScale.Location = new System.Drawing.Point(13, 42); this.radioBtnGrayScale.Name = "radioBtnGrayScale"; - this.radioBtnGrayScale.PropertyName = "OutputPrintGrayscale"; + this.radioBtnGrayScale.PropertyName = nameof(coreConfiguration.OutputPrintGrayscale); this.radioBtnGrayScale.Size = new System.Drawing.Size(137, 17); this.radioBtnGrayScale.TabIndex = 12; this.radioBtnGrayScale.Text = "Force grayscale printing"; @@ -212,7 +212,7 @@ namespace Greenshot.Forms this.radioBtnMonochrome.LanguageKey = "printoptions_printmonochrome"; this.radioBtnMonochrome.Location = new System.Drawing.Point(13, 65); this.radioBtnMonochrome.Name = "radioBtnMonochrome"; - this.radioBtnMonochrome.PropertyName = "OutputPrintMonochrome"; + this.radioBtnMonochrome.PropertyName = nameof(coreConfiguration.OutputPrintMonochrome); this.radioBtnMonochrome.Size = new System.Drawing.Size(148, 17); this.radioBtnMonochrome.TabIndex = 13; this.radioBtnMonochrome.Text = "Force black/white printing"; @@ -255,7 +255,6 @@ namespace Greenshot.Forms this.radioBtnColorPrint.LanguageKey = "printoptions_printcolor"; this.radioBtnColorPrint.Location = new System.Drawing.Point(13, 19); this.radioBtnColorPrint.Name = "radioBtnColorPrint"; - this.radioBtnColorPrint.PropertyName = "OutputPrintColor"; this.radioBtnColorPrint.Size = new System.Drawing.Size(90, 17); this.radioBtnColorPrint.TabIndex = 11; this.radioBtnColorPrint.TextAlign = System.Drawing.ContentAlignment.TopLeft; diff --git a/src/Greenshot/Forms/SettingsForm.Designer.cs b/src/Greenshot/Forms/SettingsForm.Designer.cs index e8f284850..6bea356df 100644 --- a/src/Greenshot/Forms/SettingsForm.Designer.cs +++ b/src/Greenshot/Forms/SettingsForm.Designer.cs @@ -20,6 +20,8 @@ */ using Greenshot.Base.Controls; +using Greenshot.Base.Core; +using Greenshot.Editor.Configuration; using Greenshot.Editor.Controls; namespace Greenshot.Forms { @@ -235,7 +237,7 @@ namespace Greenshot.Forms { // this.textbox_screenshotname.Location = new System.Drawing.Point(138, 41); this.textbox_screenshotname.Name = "textbox_screenshotname"; - this.textbox_screenshotname.PropertyName = "OutputFileFilenamePattern"; + this.textbox_screenshotname.PropertyName = nameof(CoreConfiguration.OutputFileFilenamePattern); this.textbox_screenshotname.Size = new System.Drawing.Size(233, 20); this.textbox_screenshotname.TabIndex = 3; this.textbox_screenshotname.TextChanged += new System.EventHandler(this.FilenamePatternChanged); @@ -264,7 +266,7 @@ namespace Greenshot.Forms { this.combobox_primaryimageformat.FormattingEnabled = true; this.combobox_primaryimageformat.Location = new System.Drawing.Point(138, 64); this.combobox_primaryimageformat.Name = "combobox_primaryimageformat"; - this.combobox_primaryimageformat.PropertyName = "OutputFileFormat"; + this.combobox_primaryimageformat.PropertyName = nameof(CoreConfiguration.OutputFileFormat); this.combobox_primaryimageformat.Size = new System.Drawing.Size(268, 21); this.combobox_primaryimageformat.TabIndex = 5; // @@ -309,7 +311,7 @@ namespace Greenshot.Forms { this.checkbox_copypathtoclipboard.LanguageKey = "settings_copypathtoclipboard"; this.checkbox_copypathtoclipboard.Location = new System.Drawing.Point(12, 89); this.checkbox_copypathtoclipboard.Name = "checkbox_copypathtoclipboard"; - this.checkbox_copypathtoclipboard.PropertyName = "OutputFileCopyPathToClipboard"; + this.checkbox_copypathtoclipboard.PropertyName = nameof(CoreConfiguration.OutputFileCopyPathToClipboard); this.checkbox_copypathtoclipboard.Size = new System.Drawing.Size(394, 24); this.checkbox_copypathtoclipboard.TabIndex = 6; this.checkbox_copypathtoclipboard.UseVisualStyleBackColor = true; @@ -374,7 +376,7 @@ namespace Greenshot.Forms { this.checkbox_reducecolors.LanguageKey = "settings_reducecolors"; this.checkbox_reducecolors.Location = new System.Drawing.Point(12, 72); this.checkbox_reducecolors.Name = "checkbox_reducecolors"; - this.checkbox_reducecolors.PropertyName = "OutputFileReduceColors"; + this.checkbox_reducecolors.PropertyName = nameof(CoreConfiguration.OutputFileReduceColors); this.checkbox_reducecolors.Size = new System.Drawing.Size(394, 25); this.checkbox_reducecolors.TabIndex = 10; this.checkbox_reducecolors.UseVisualStyleBackColor = true; @@ -384,7 +386,7 @@ namespace Greenshot.Forms { this.checkbox_alwaysshowqualitydialog.LanguageKey = "settings_alwaysshowqualitydialog"; this.checkbox_alwaysshowqualitydialog.Location = new System.Drawing.Point(12, 50); this.checkbox_alwaysshowqualitydialog.Name = "checkbox_alwaysshowqualitydialog"; - this.checkbox_alwaysshowqualitydialog.PropertyName = "OutputFilePromptQuality"; + this.checkbox_alwaysshowqualitydialog.PropertyName = nameof(CoreConfiguration.OutputFilePromptQuality); this.checkbox_alwaysshowqualitydialog.Size = new System.Drawing.Size(394, 25); this.checkbox_alwaysshowqualitydialog.TabIndex = 9; this.checkbox_alwaysshowqualitydialog.UseVisualStyleBackColor = true; @@ -526,7 +528,7 @@ namespace Greenshot.Forms { this.checkbox_usedefaultproxy.LanguageKey = "settings_usedefaultproxy"; this.checkbox_usedefaultproxy.Location = new System.Drawing.Point(7, 11); this.checkbox_usedefaultproxy.Name = "checkbox_usedefaultproxy"; - this.checkbox_usedefaultproxy.PropertyName = "UseProxy"; + this.checkbox_usedefaultproxy.PropertyName = nameof(CoreConfiguration.UseProxy); this.checkbox_usedefaultproxy.Size = new System.Drawing.Size(397, 25); this.checkbox_usedefaultproxy.TabIndex = 7; this.checkbox_usedefaultproxy.UseVisualStyleBackColor = true; @@ -564,7 +566,7 @@ namespace Greenshot.Forms { this.lastregion_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None; this.lastregion_hotkeyControl.Location = new System.Drawing.Point(224, 94); this.lastregion_hotkeyControl.Name = "lastregion_hotkeyControl"; - this.lastregion_hotkeyControl.PropertyName = "LastregionHotkey"; + this.lastregion_hotkeyControl.PropertyName = nameof(CoreConfiguration.LastregionHotkey); this.lastregion_hotkeyControl.Size = new System.Drawing.Size(179, 20); this.lastregion_hotkeyControl.TabIndex = 5; // @@ -582,7 +584,7 @@ namespace Greenshot.Forms { this.ie_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None; this.ie_hotkeyControl.Location = new System.Drawing.Point(224, 120); this.ie_hotkeyControl.Name = "ie_hotkeyControl"; - this.ie_hotkeyControl.PropertyName = "IEHotkey"; + this.ie_hotkeyControl.PropertyName = nameof(CoreConfiguration.IEHotkey); this.ie_hotkeyControl.Size = new System.Drawing.Size(179, 20); this.ie_hotkeyControl.TabIndex = 6; // @@ -616,7 +618,7 @@ namespace Greenshot.Forms { this.region_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None; this.region_hotkeyControl.Location = new System.Drawing.Point(224, 68); this.region_hotkeyControl.Name = "region_hotkeyControl"; - this.region_hotkeyControl.PropertyName = "RegionHotkey"; + this.region_hotkeyControl.PropertyName = nameof(CoreConfiguration.RegionHotkey); this.region_hotkeyControl.Size = new System.Drawing.Size(179, 20); this.region_hotkeyControl.TabIndex = 4; // @@ -626,7 +628,7 @@ namespace Greenshot.Forms { this.window_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None; this.window_hotkeyControl.Location = new System.Drawing.Point(224, 42); this.window_hotkeyControl.Name = "window_hotkeyControl"; - this.window_hotkeyControl.PropertyName = "WindowHotkey"; + this.window_hotkeyControl.PropertyName = nameof(CoreConfiguration.WindowHotkey); this.window_hotkeyControl.Size = new System.Drawing.Size(179, 20); this.window_hotkeyControl.TabIndex = 3; // @@ -636,7 +638,7 @@ namespace Greenshot.Forms { this.fullscreen_hotkeyControl.HotkeyModifiers = System.Windows.Forms.Keys.None; this.fullscreen_hotkeyControl.Location = new System.Drawing.Point(224, 16); this.fullscreen_hotkeyControl.Name = "fullscreen_hotkeyControl"; - this.fullscreen_hotkeyControl.PropertyName = "FullscreenHotkey"; + this.fullscreen_hotkeyControl.PropertyName = nameof(CoreConfiguration.FullscreenHotkey); this.fullscreen_hotkeyControl.Size = new System.Drawing.Size(179, 20); this.fullscreen_hotkeyControl.TabIndex = 2; // @@ -668,7 +670,7 @@ namespace Greenshot.Forms { this.checkbox_editor_match_capture_size.LanguageKey = "editor_match_capture_size"; this.checkbox_editor_match_capture_size.Location = new System.Drawing.Point(6, 19); this.checkbox_editor_match_capture_size.Name = "checkbox_editor_match_capture_size"; - this.checkbox_editor_match_capture_size.PropertyName = "MatchSizeToCapture"; + this.checkbox_editor_match_capture_size.PropertyName = nameof(EditorConfiguration.MatchSizeToCapture); this.checkbox_editor_match_capture_size.SectionName = "Editor"; this.checkbox_editor_match_capture_size.Size = new System.Drawing.Size(397, 24); this.checkbox_editor_match_capture_size.TabIndex = 11; @@ -689,7 +691,7 @@ namespace Greenshot.Forms { this.checkbox_ie_capture.LanguageKey = "settings_iecapture"; this.checkbox_ie_capture.Location = new System.Drawing.Point(6, 19); this.checkbox_ie_capture.Name = "checkbox_ie_capture"; - this.checkbox_ie_capture.PropertyName = "IECapture"; + this.checkbox_ie_capture.PropertyName = nameof(CoreConfiguration.IECapture); this.checkbox_ie_capture.Size = new System.Drawing.Size(404, 24); this.checkbox_ie_capture.TabIndex = 10; this.checkbox_ie_capture.UseVisualStyleBackColor = true; @@ -732,7 +734,7 @@ namespace Greenshot.Forms { this.radiobuttonInteractiveCapture.LanguageKey = "settings_capture_windows_interactive"; this.radiobuttonInteractiveCapture.Location = new System.Drawing.Point(11, 20); this.radiobuttonInteractiveCapture.Name = "radiobuttonInteractiveCapture"; - this.radiobuttonInteractiveCapture.PropertyName = "CaptureWindowsInteractive"; + this.radiobuttonInteractiveCapture.PropertyName = nameof(CoreConfiguration.CaptureWindowsInteractive); this.radiobuttonInteractiveCapture.Size = new System.Drawing.Size(203, 17); this.radiobuttonInteractiveCapture.TabIndex = 6; this.radiobuttonInteractiveCapture.TabStop = true; @@ -770,7 +772,7 @@ namespace Greenshot.Forms { this.checkbox_zoomer.LanguageKey = "settings_zoom"; this.checkbox_zoomer.Location = new System.Drawing.Point(11, 79); this.checkbox_zoomer.Name = "checkbox_zoomer"; - this.checkbox_zoomer.PropertyName = "ZoomerEnabled"; + this.checkbox_zoomer.PropertyName = nameof(CoreConfiguration.ZoomerEnabled); this.checkbox_zoomer.Size = new System.Drawing.Size(399, 24); this.checkbox_zoomer.TabIndex = 4; this.checkbox_zoomer.UseVisualStyleBackColor = true; @@ -780,7 +782,7 @@ namespace Greenshot.Forms { this.checkbox_notifications.LanguageKey = "settings_shownotify"; this.checkbox_notifications.Location = new System.Drawing.Point(11, 59); this.checkbox_notifications.Name = "checkbox_notifications"; - this.checkbox_notifications.PropertyName = "ShowTrayNotification"; + this.checkbox_notifications.PropertyName = nameof(CoreConfiguration.ShowTrayNotification); this.checkbox_notifications.Size = new System.Drawing.Size(399, 24); this.checkbox_notifications.TabIndex = 3; this.checkbox_notifications.UseVisualStyleBackColor = true; @@ -790,7 +792,7 @@ namespace Greenshot.Forms { this.checkbox_playsound.LanguageKey = "settings_playsound"; this.checkbox_playsound.Location = new System.Drawing.Point(11, 39); this.checkbox_playsound.Name = "checkbox_playsound"; - this.checkbox_playsound.PropertyName = "PlayCameraSound"; + this.checkbox_playsound.PropertyName = nameof(CoreConfiguration.PlayCameraSound); this.checkbox_playsound.Size = new System.Drawing.Size(399, 24); this.checkbox_playsound.TabIndex = 2; this.checkbox_playsound.UseVisualStyleBackColor = true; @@ -800,7 +802,7 @@ namespace Greenshot.Forms { this.checkbox_capture_mousepointer.LanguageKey = "settings_capture_mousepointer"; this.checkbox_capture_mousepointer.Location = new System.Drawing.Point(11, 19); this.checkbox_capture_mousepointer.Name = "checkbox_capture_mousepointer"; - this.checkbox_capture_mousepointer.PropertyName = "CaptureMousepointer"; + this.checkbox_capture_mousepointer.PropertyName = nameof(CoreConfiguration.CaptureMousepointer); this.checkbox_capture_mousepointer.Size = new System.Drawing.Size(394, 24); this.checkbox_capture_mousepointer.TabIndex = 1; this.checkbox_capture_mousepointer.UseVisualStyleBackColor = true; @@ -887,7 +889,7 @@ namespace Greenshot.Forms { this.checkboxPrintInverted.LanguageKey = "printoptions_inverted"; this.checkboxPrintInverted.Location = new System.Drawing.Point(13, 88); this.checkboxPrintInverted.Name = "checkboxPrintInverted"; - this.checkboxPrintInverted.PropertyName = "OutputPrintInverted"; + this.checkboxPrintInverted.PropertyName = nameof(CoreConfiguration.OutputPrintInverted); this.checkboxPrintInverted.Size = new System.Drawing.Size(141, 17); this.checkboxPrintInverted.TabIndex = 14; this.checkboxPrintInverted.TextAlign = System.Drawing.ContentAlignment.TopLeft; @@ -900,7 +902,6 @@ namespace Greenshot.Forms { this.radioBtnColorPrint.LanguageKey = "printoptions_printcolor"; this.radioBtnColorPrint.Location = new System.Drawing.Point(13, 19); this.radioBtnColorPrint.Name = "radioBtnColorPrint"; - this.radioBtnColorPrint.PropertyName = "OutputPrintColor"; this.radioBtnColorPrint.Size = new System.Drawing.Size(90, 17); this.radioBtnColorPrint.TabIndex = 11; this.radioBtnColorPrint.TextAlign = System.Drawing.ContentAlignment.TopLeft; @@ -913,7 +914,7 @@ namespace Greenshot.Forms { this.radioBtnGrayScale.LanguageKey = "printoptions_printgrayscale"; this.radioBtnGrayScale.Location = new System.Drawing.Point(13, 42); this.radioBtnGrayScale.Name = "radioBtnGrayScale"; - this.radioBtnGrayScale.PropertyName = "OutputPrintGrayscale"; + this.radioBtnGrayScale.PropertyName = nameof(coreConfiguration.OutputPrintGrayscale); this.radioBtnGrayScale.Size = new System.Drawing.Size(137, 17); this.radioBtnGrayScale.TabIndex = 12; this.radioBtnGrayScale.Text = "Force grayscale printing"; @@ -927,7 +928,7 @@ namespace Greenshot.Forms { this.radioBtnMonochrome.LanguageKey = "printoptions_printmonochrome"; this.radioBtnMonochrome.Location = new System.Drawing.Point(13, 65); this.radioBtnMonochrome.Name = "radioBtnMonochrome"; - this.radioBtnMonochrome.PropertyName = "OutputPrintMonochrome"; + this.radioBtnMonochrome.PropertyName = nameof(coreConfiguration.OutputPrintMonochrome); this.radioBtnMonochrome.Size = new System.Drawing.Size(148, 17); this.radioBtnMonochrome.TabIndex = 13; this.radioBtnMonochrome.TextAlign = System.Drawing.ContentAlignment.TopLeft; @@ -954,7 +955,7 @@ namespace Greenshot.Forms { this.checkboxDateTime.LanguageKey = "printoptions_timestamp"; this.checkboxDateTime.Location = new System.Drawing.Point(13, 115); this.checkboxDateTime.Name = "checkboxDateTime"; - this.checkboxDateTime.PropertyName = "OutputPrintFooter"; + this.checkboxDateTime.PropertyName = nameof(coreConfiguration.OutputPrintFooter); this.checkboxDateTime.Size = new System.Drawing.Size(187, 17); this.checkboxDateTime.TabIndex = 6; this.checkboxDateTime.TextAlign = System.Drawing.ContentAlignment.TopLeft; @@ -967,7 +968,7 @@ namespace Greenshot.Forms { this.checkboxAllowShrink.LanguageKey = "printoptions_allowshrink"; this.checkboxAllowShrink.Location = new System.Drawing.Point(13, 23); this.checkboxAllowShrink.Name = "checkboxAllowShrink"; - this.checkboxAllowShrink.PropertyName = "OutputPrintAllowShrink"; + this.checkboxAllowShrink.PropertyName = nameof(coreConfiguration.OutputPrintAllowShrink); this.checkboxAllowShrink.Size = new System.Drawing.Size(168, 17); this.checkboxAllowShrink.TabIndex = 2; this.checkboxAllowShrink.TextAlign = System.Drawing.ContentAlignment.TopLeft; @@ -980,7 +981,7 @@ namespace Greenshot.Forms { this.checkboxAllowEnlarge.LanguageKey = "printoptions_allowenlarge"; this.checkboxAllowEnlarge.Location = new System.Drawing.Point(13, 46); this.checkboxAllowEnlarge.Name = "checkboxAllowEnlarge"; - this.checkboxAllowEnlarge.PropertyName = "OutputPrintAllowEnlarge"; + this.checkboxAllowEnlarge.PropertyName = nameof(coreConfiguration.OutputPrintAllowEnlarge); this.checkboxAllowEnlarge.Size = new System.Drawing.Size(174, 17); this.checkboxAllowEnlarge.TabIndex = 3; this.checkboxAllowEnlarge.TextAlign = System.Drawing.ContentAlignment.TopLeft; @@ -993,7 +994,7 @@ namespace Greenshot.Forms { this.checkboxAllowRotate.LanguageKey = "printoptions_allowrotate"; this.checkboxAllowRotate.Location = new System.Drawing.Point(13, 69); this.checkboxAllowRotate.Name = "checkboxAllowRotate"; - this.checkboxAllowRotate.PropertyName = "OutputPrintAllowRotate"; + this.checkboxAllowRotate.PropertyName = nameof(coreConfiguration.OutputPrintAllowRotate); this.checkboxAllowRotate.Size = new System.Drawing.Size(187, 17); this.checkboxAllowRotate.TabIndex = 4; this.checkboxAllowRotate.TextAlign = System.Drawing.ContentAlignment.TopLeft; @@ -1006,7 +1007,7 @@ namespace Greenshot.Forms { this.checkboxAllowCenter.LanguageKey = "printoptions_allowcenter"; this.checkboxAllowCenter.Location = new System.Drawing.Point(13, 92); this.checkboxAllowCenter.Name = "checkboxAllowCenter"; - this.checkboxAllowCenter.PropertyName = "OutputPrintCenter"; + this.checkboxAllowCenter.PropertyName = nameof(coreConfiguration.OutputPrintCenter); this.checkboxAllowCenter.Size = new System.Drawing.Size(137, 17); this.checkboxAllowCenter.TabIndex = 5; this.checkboxAllowCenter.TextAlign = System.Drawing.ContentAlignment.TopLeft; @@ -1017,7 +1018,7 @@ namespace Greenshot.Forms { this.checkbox_alwaysshowprintoptionsdialog.LanguageKey = "settings_alwaysshowprintoptionsdialog"; this.checkbox_alwaysshowprintoptionsdialog.Location = new System.Drawing.Point(19, 293); this.checkbox_alwaysshowprintoptionsdialog.Name = "checkbox_alwaysshowprintoptionsdialog"; - this.checkbox_alwaysshowprintoptionsdialog.PropertyName = "OutputPrintPromptOptions"; + this.checkbox_alwaysshowprintoptionsdialog.PropertyName = nameof(coreConfiguration.OutputPrintPromptOptions); this.checkbox_alwaysshowprintoptionsdialog.Size = new System.Drawing.Size(394, 20); this.checkbox_alwaysshowprintoptionsdialog.TabIndex = 15; this.checkbox_alwaysshowprintoptionsdialog.Text = "Show print options dialog every time an image is printed"; @@ -1114,7 +1115,7 @@ namespace Greenshot.Forms { this.checkbox_reuseeditor.LanguageKey = "expertsettings_reuseeditorifpossible"; this.checkbox_reuseeditor.Location = new System.Drawing.Point(10, 225); this.checkbox_reuseeditor.Name = "checkbox_reuseeditor"; - this.checkbox_reuseeditor.PropertyName = "ReuseEditor"; + this.checkbox_reuseeditor.PropertyName = nameof(EditorConfiguration.ReuseEditor); this.checkbox_reuseeditor.SectionName = "Editor"; this.checkbox_reuseeditor.Size = new System.Drawing.Size(394, 24); this.checkbox_reuseeditor.TabIndex = 9; @@ -1125,7 +1126,7 @@ namespace Greenshot.Forms { this.checkbox_minimizememoryfootprint.LanguageKey = "expertsettings_minimizememoryfootprint"; this.checkbox_minimizememoryfootprint.Location = new System.Drawing.Point(10, 206); this.checkbox_minimizememoryfootprint.Name = "checkbox_minimizememoryfootprint"; - this.checkbox_minimizememoryfootprint.PropertyName = "MinimizeWorkingSetSize"; + this.checkbox_minimizememoryfootprint.PropertyName = nameof(coreConfiguration.MinimizeWorkingSetSize); this.checkbox_minimizememoryfootprint.Size = new System.Drawing.Size(394, 24); this.checkbox_minimizememoryfootprint.TabIndex = 8; this.checkbox_minimizememoryfootprint.UseVisualStyleBackColor = true; @@ -1135,7 +1136,7 @@ namespace Greenshot.Forms { this.checkbox_checkunstableupdates.LanguageKey = "expertsettings_checkunstableupdates"; this.checkbox_checkunstableupdates.Location = new System.Drawing.Point(10, 187); this.checkbox_checkunstableupdates.Name = "checkbox_checkunstableupdates"; - this.checkbox_checkunstableupdates.PropertyName = "CheckForUnstable"; + this.checkbox_checkunstableupdates.PropertyName = nameof(coreConfiguration.CheckForUnstable); this.checkbox_checkunstableupdates.Size = new System.Drawing.Size(394, 24); this.checkbox_checkunstableupdates.TabIndex = 7; this.checkbox_checkunstableupdates.UseVisualStyleBackColor = true; @@ -1145,7 +1146,7 @@ namespace Greenshot.Forms { this.checkbox_suppresssavedialogatclose.LanguageKey = "expertsettings_suppresssavedialogatclose"; this.checkbox_suppresssavedialogatclose.Location = new System.Drawing.Point(10, 168); this.checkbox_suppresssavedialogatclose.Name = "checkbox_suppresssavedialogatclose"; - this.checkbox_suppresssavedialogatclose.PropertyName = "SuppressSaveDialogAtClose"; + this.checkbox_suppresssavedialogatclose.PropertyName = nameof(EditorConfiguration.SuppressSaveDialogAtClose); this.checkbox_suppresssavedialogatclose.SectionName = "Editor"; this.checkbox_suppresssavedialogatclose.Size = new System.Drawing.Size(394, 24); this.checkbox_suppresssavedialogatclose.TabIndex = 6; @@ -1163,7 +1164,7 @@ namespace Greenshot.Forms { // this.textbox_counter.Location = new System.Drawing.Point(259, 282); this.textbox_counter.Name = "textbox_counter"; - this.textbox_counter.PropertyName = "OutputFileIncrementingNumber"; + this.textbox_counter.PropertyName = nameof(coreConfiguration.OutputFileIncrementingNumber); this.textbox_counter.Size = new System.Drawing.Size(141, 20); this.textbox_counter.TabIndex = 11; // @@ -1180,7 +1181,7 @@ namespace Greenshot.Forms { // this.textbox_footerpattern.Location = new System.Drawing.Point(138, 256); this.textbox_footerpattern.Name = "textbox_footerpattern"; - this.textbox_footerpattern.PropertyName = "OutputPrintFooterPattern"; + this.textbox_footerpattern.PropertyName = nameof(coreConfiguration.OutputPrintFooterPattern); this.textbox_footerpattern.Size = new System.Drawing.Size(262, 20); this.textbox_footerpattern.TabIndex = 10; // @@ -1189,7 +1190,7 @@ namespace Greenshot.Forms { this.checkbox_thumbnailpreview.LanguageKey = "expertsettings_thumbnailpreview"; this.checkbox_thumbnailpreview.Location = new System.Drawing.Point(10, 149); this.checkbox_thumbnailpreview.Name = "checkbox_thumbnailpreview"; - this.checkbox_thumbnailpreview.PropertyName = "ThumnailPreview"; + this.checkbox_thumbnailpreview.PropertyName = nameof(coreConfiguration.ThumnailPreview); this.checkbox_thumbnailpreview.Size = new System.Drawing.Size(394, 24); this.checkbox_thumbnailpreview.TabIndex = 5; this.checkbox_thumbnailpreview.UseVisualStyleBackColor = true; @@ -1199,7 +1200,7 @@ namespace Greenshot.Forms { this.checkbox_optimizeforrdp.LanguageKey = "expertsettings_optimizeforrdp"; this.checkbox_optimizeforrdp.Location = new System.Drawing.Point(10, 130); this.checkbox_optimizeforrdp.Name = "checkbox_optimizeforrdp"; - this.checkbox_optimizeforrdp.PropertyName = "OptimizeForRDP"; + this.checkbox_optimizeforrdp.PropertyName = nameof(coreConfiguration.OptimizeForRDP); this.checkbox_optimizeforrdp.Size = new System.Drawing.Size(394, 24); this.checkbox_optimizeforrdp.TabIndex = 4; this.checkbox_optimizeforrdp.UseVisualStyleBackColor = true; @@ -1209,7 +1210,7 @@ namespace Greenshot.Forms { this.checkbox_autoreducecolors.LanguageKey = "expertsettings_autoreducecolors"; this.checkbox_autoreducecolors.Location = new System.Drawing.Point(10, 111); this.checkbox_autoreducecolors.Name = "checkbox_autoreducecolors"; - this.checkbox_autoreducecolors.PropertyName = "OutputFileAutoReduceColors"; + this.checkbox_autoreducecolors.PropertyName = nameof(coreConfiguration.OutputFileAutoReduceColors); this.checkbox_autoreducecolors.Size = new System.Drawing.Size(408, 24); this.checkbox_autoreducecolors.TabIndex = 3; this.checkbox_autoreducecolors.UseVisualStyleBackColor = true; @@ -1257,7 +1258,7 @@ namespace Greenshot.Forms { // // SettingsForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 14F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(451, 431); this.Controls.Add(this.tabcontrol); diff --git a/src/Greenshot/Forms/SettingsForm.cs b/src/Greenshot/Forms/SettingsForm.cs index 7fecda8e2..272c2fde1 100644 --- a/src/Greenshot/Forms/SettingsForm.cs +++ b/src/Greenshot/Forms/SettingsForm.cs @@ -37,7 +37,6 @@ using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; using Greenshot.Base.UnmanagedHelpers; using Greenshot.Configuration; -using Greenshot.Destinations; using Greenshot.Helpers; using log4net; @@ -320,7 +319,7 @@ namespace Greenshot.Forms combobox_language.SelectedValue = Language.CurrentLanguage; } - // Delaying the SelectedIndexChanged events untill all is initiated + // Delaying the SelectedIndexChanged events until all is initiated combobox_language.SelectedIndexChanged += Combobox_languageSelectedIndexChanged; UpdateDestinationDescriptions(); UpdateClipboardFormatDescriptions(); @@ -829,22 +828,19 @@ namespace Greenshot.Forms { public int Compare(object x, object y) { - if (!(x is ListViewItem)) + if (x is not ListViewItem listViewItemX) { return 0; } - if (!(y is ListViewItem)) + if (y is not ListViewItem listViewItemY) { return 0; } - ListViewItem l1 = (ListViewItem) x; - ListViewItem l2 = (ListViewItem) y; + IDestination firstDestination = listViewItemX.Tag as IDestination; - IDestination firstDestination = l1.Tag as IDestination; - - if (!(l2.Tag is IDestination secondDestination)) + if (listViewItemY.Tag is not IDestination secondDestination) { return 1; } diff --git a/src/Greenshot/Helpers/CaptureHelper.cs b/src/Greenshot/Helpers/CaptureHelper.cs index 3d0d3385d..20496a839 100644 --- a/src/Greenshot/Helpers/CaptureHelper.cs +++ b/src/Greenshot/Helpers/CaptureHelper.cs @@ -389,6 +389,7 @@ namespace Greenshot.Helpers HandleCapture(); break; case CaptureMode.Clipboard: + // TODO: Fix getting image vs. drawablecontainer Image clipboardImage = ClipboardHelper.GetImage(); if (clipboardImage != null) { @@ -430,12 +431,13 @@ namespace Greenshot.Helpers if (!string.IsNullOrEmpty(filename)) { + // TODO: Fix that the Greenshot format needs a separate code path try { if (filename.ToLower().EndsWith("." + OutputFormat.greenshot)) { ISurface surface = new Surface(); - surface = ImageOutput.LoadGreenshotSurface(filename, surface); + surface = ImageIO.LoadGreenshotSurface(filename, surface); surface.CaptureDetails = _capture.CaptureDetails; DestinationHelper.GetDestination(EditorDestination.DESIGNATION).ExportCapture(true, surface, _capture.CaptureDetails); break; @@ -447,9 +449,10 @@ namespace Greenshot.Helpers MessageBox.Show(Language.GetFormattedString(LangKey.error_openfile, filename)); } + // TODO: Remove Image loading for here try { - fileImage = ImageHelper.LoadImage(filename); + fileImage = ImageIO.LoadImage(filename); } catch (Exception e) { diff --git a/src/Greenshot/Helpers/MailHelper.cs b/src/Greenshot/Helpers/MailHelper.cs index f3975a205..39aa3c150 100644 --- a/src/Greenshot/Helpers/MailHelper.cs +++ b/src/Greenshot/Helpers/MailHelper.cs @@ -82,7 +82,7 @@ namespace Greenshot.Helpers /// ICaptureDetails public static void SendImage(ISurface surface, ICaptureDetails captureDetails) { - string tmpFile = ImageOutput.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings()); + string tmpFile = ImageIO.SaveNamedTmpFile(surface, captureDetails, new SurfaceOutputSettings()); if (tmpFile == null) return; diff --git a/src/Greenshot/Helpers/PrintHelper.cs b/src/Greenshot/Helpers/PrintHelper.cs index 9e6a43a7f..36bf8257b 100644 --- a/src/Greenshot/Helpers/PrintHelper.cs +++ b/src/Greenshot/Helpers/PrintHelper.cs @@ -187,7 +187,7 @@ namespace Greenshot.Helpers ApplyEffects(printOutputSettings); - bool disposeImage = ImageOutput.CreateImageFromSurface(_surface, printOutputSettings, out var image); + bool disposeImage = ImageIO.CreateImageFromSurface(_surface, printOutputSettings, out var image); try { ContentAlignment alignment = CoreConfig.OutputPrintCenter ? ContentAlignment.MiddleCenter : ContentAlignment.TopLeft; From 8014199bb694eb8c4c0dddf9185820ece926974d Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 22 Mar 2022 11:32:30 +0100 Subject: [PATCH 174/232] Fix for #390 by limiting the length of the displayed title. --- src/Greenshot.Editor/Destinations/EditorDestination.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Greenshot.Editor/Destinations/EditorDestination.cs b/src/Greenshot.Editor/Destinations/EditorDestination.cs index 326397ec9..bfc143d88 100644 --- a/src/Greenshot.Editor/Destinations/EditorDestination.cs +++ b/src/Greenshot.Editor/Destinations/EditorDestination.cs @@ -64,7 +64,7 @@ namespace Greenshot.Editor.Destinations return Language.GetString(LangKey.settings_destination_editor); } - return Language.GetString(LangKey.settings_destination_editor) + " - " + editor.CaptureDetails.Title; + return Language.GetString(LangKey.settings_destination_editor) + " - " + editor.CaptureDetails.Title?.Substring(0, Math.Min(20, editor.CaptureDetails.Title.Length)); } } From 4a66a4dbe24400d2cda1e2cd7f7e28a20448a34c Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 22 Mar 2022 11:42:52 +0100 Subject: [PATCH 175/232] Removed some chattiness in the log. [skip ci] --- .../Core/WmInputLangChangeRequestFilter.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs b/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs index a76fcdf21..a0488cd3f 100644 --- a/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs +++ b/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs @@ -51,16 +51,13 @@ namespace Greenshot.Base.Core public static bool PreFilterMessageExternal(ref Message m) { WindowsMessages message = (WindowsMessages) m.Msg; - if (message == WindowsMessages.WM_INPUTLANGCHANGEREQUEST || message == WindowsMessages.WM_INPUTLANGCHANGE) - { - LOG.WarnFormat("Filtering: {0}, {1:X} - {2:X} - {3:X}", message, m.LParam.ToInt64(), m.WParam.ToInt64(), m.HWnd.ToInt64()); - // For now we always return true - return true; - // But it could look something like this: - //return (m.LParam.ToInt64() | 0x7FFFFFFF) != 0; - } + if (message != WindowsMessages.WM_INPUTLANGCHANGEREQUEST && message != WindowsMessages.WM_INPUTLANGCHANGE) return false; - return false; + LOG.DebugFormat("Filtering: {0}, {1:X} - {2:X} - {3:X}", message, m.LParam.ToInt64(), m.WParam.ToInt64(), m.HWnd.ToInt64()); + // For now we always return true + return true; + // But it could look something like this: + //return (m.LParam.ToInt64() | 0x7FFFFFFF) != 0; } } } \ No newline at end of file From 56c26ac0383159cc793adf775e7b34b7cd53401c Mon Sep 17 00:00:00 2001 From: Christian Schulz <32000301+Christian-Schulz@users.noreply.github.com> Date: Tue, 22 Mar 2022 11:57:01 +0100 Subject: [PATCH 176/232] Enhanced ability to crop an image vertically and horizontally. #249 (#388) Co-authored-by: Robin Krom --- src/Greenshot.Base/Core/ImageHelper.cs | 40 +- .../Interfaces/Drawing/IDrawableContainer.cs | 5 + .../Interfaces/Drawing/IFieldAggregator.cs | 3 + src/Greenshot.Base/Interfaces/ISurface.cs | 8 + .../Configuration/LanguageKeys.cs | 1 + src/Greenshot.Editor/Drawing/CropContainer.cs | 185 +++++- .../Drawing/DrawableContainer.cs | 25 +- .../Drawing/DrawableContainerList.cs | 40 +- .../Drawing/Fields/FieldType.cs | 44 +- src/Greenshot.Editor/Drawing/Surface.cs | 540 ++++++++++++------ src/Greenshot.Editor/Drawing/TextContainer.cs | 2 +- .../Forms/ImageEditorForm.Designer.cs | 77 ++- src/Greenshot.Editor/Forms/ImageEditorForm.cs | 76 ++- .../Forms/ImageEditorForm.resx | 9 + .../Memento/AddElementMemento.cs | 2 +- .../Memento/AddElementsMemento.cs | 2 +- .../Memento/ChangeFieldHolderMemento.cs | 2 +- .../Memento/DeleteElementMemento.cs | 2 +- .../Memento/DeleteElementsMemento.cs | 2 +- .../DrawableContainerBoundsChangeMemento.cs | 26 +- .../Memento/SurfaceBackgroundChangeMemento.cs | 2 +- .../Memento/TextChangeMemento.cs | 2 +- .../Resources/AutoCrop.Image.png | Bin 0 -> 3164 bytes .../Resources/CropHorizontal.Image.png | Bin 0 -> 2786 bytes .../Resources/CropVertical.Image.png | Bin 0 -> 3176 bytes src/Greenshot/Languages/language-ar-SY.xml | 1 + src/Greenshot/Languages/language-ca-CA.xml | 2 + src/Greenshot/Languages/language-cs-CZ.xml | 2 + src/Greenshot/Languages/language-da-DK.xml | 3 + src/Greenshot/Languages/language-de-DE.xml | 6 + .../Languages/language-de-x-franconia.xml | 2 + src/Greenshot/Languages/language-el-GR.xml | 2 + src/Greenshot/Languages/language-en-US.xml | 6 + src/Greenshot/Languages/language-es-ES.xml | 2 + src/Greenshot/Languages/language-et-EE.xml | 2 + src/Greenshot/Languages/language-fa-IR.xml | 1 + src/Greenshot/Languages/language-fi-FI.xml | 1 + src/Greenshot/Languages/language-fr-FR.xml | 2 + src/Greenshot/Languages/language-fr-QC.xml | 2 + src/Greenshot/Languages/language-he-IL.xml | 1 + src/Greenshot/Languages/language-hu-HU.xml | 1 + src/Greenshot/Languages/language-id-ID.xml | 2 + src/Greenshot/Languages/language-it-IT.xml | 2 + src/Greenshot/Languages/language-ja-JP.xml | 2 + src/Greenshot/Languages/language-kab-DZ.xml | 2 + src/Greenshot/Languages/language-ko-KR.xml | 2 + src/Greenshot/Languages/language-lt-LT.xml | 1 + src/Greenshot/Languages/language-lv-LV.xml | 2 + src/Greenshot/Languages/language-nl-NL.xml | 2 + src/Greenshot/Languages/language-nn-NO.xml | 2 + src/Greenshot/Languages/language-pl-PL.xml | 2 + src/Greenshot/Languages/language-pt-BR.xml | 1 + src/Greenshot/Languages/language-pt-PT.xml | 2 + src/Greenshot/Languages/language-ro-RO.xml | 3 + src/Greenshot/Languages/language-ru-RU.xml | 2 + src/Greenshot/Languages/language-sk-SK.xml | 2 + src/Greenshot/Languages/language-sl-SI.xml | 2 + src/Greenshot/Languages/language-sr-RS.xml | 2 + src/Greenshot/Languages/language-sv-SE.xml | 2 + src/Greenshot/Languages/language-tr-TR.xml | 2 + src/Greenshot/Languages/language-uk-UA.xml | 2 + src/Greenshot/Languages/language-vi-VN.xml | 1 + src/Greenshot/Languages/language-zh-CN.xml | 2 + src/Greenshot/Languages/language-zh-TW.xml | 2 + 64 files changed, 865 insertions(+), 310 deletions(-) create mode 100644 src/Greenshot.Editor/Resources/AutoCrop.Image.png create mode 100644 src/Greenshot.Editor/Resources/CropHorizontal.Image.png create mode 100644 src/Greenshot.Editor/Resources/CropVertical.Image.png diff --git a/src/Greenshot.Base/Core/ImageHelper.cs b/src/Greenshot.Base/Core/ImageHelper.cs index a4055f2c9..38c77d950 100644 --- a/src/Greenshot.Base/Core/ImageHelper.cs +++ b/src/Greenshot.Base/Core/ImageHelper.cs @@ -190,12 +190,14 @@ namespace Greenshot.Base.Core /// /// Private helper method for the FindAutoCropRectangle /// - /// - /// - /// + /// IFastBitmap + /// Point + /// int + /// Rectangle with optional area to scan in /// Rectangle - private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference) + private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference, Rectangle? area = null) { + area ??= new Rectangle(0, 0, fastBitmap.Width, fastBitmap.Height); Rectangle cropRectangle = Rectangle.Empty; Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); Point min = new Point(int.MaxValue, int.MaxValue); @@ -203,9 +205,9 @@ namespace Greenshot.Base.Core if (cropDifference > 0) { - for (int y = 0; y < fastBitmap.Height; y++) + for (int y = area.Value.Top; y < area.Value.Bottom; y++) { - for (int x = 0; x < fastBitmap.Width; x++) + for (int x = area.Value.Left; x < area.Value.Right; x++) { Color currentColor = fastBitmap.GetColorAt(x, y); int diffR = Math.Abs(currentColor.R - referenceColor.R); @@ -225,9 +227,9 @@ namespace Greenshot.Base.Core } else { - for (int y = 0; y < fastBitmap.Height; y++) + for (int y = area.Value.Top; y < area.Value.Bottom; y++) { - for (int x = 0; x < fastBitmap.Width; x++) + for (int x = area.Value.Left; x < area.Value.Right; x++) { Color currentColor = fastBitmap.GetColorAt(x, y); if (!referenceColor.Equals(currentColor)) @@ -243,7 +245,7 @@ namespace Greenshot.Base.Core } } - if (!(Point.Empty.Equals(min) && max.Equals(new Point(fastBitmap.Width - 1, fastBitmap.Height - 1)))) + if (!(Point.Empty.Equals(min) && max.Equals(new Point(area.Value.Width - 1, area.Value.Height - 1)))) { if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) { @@ -257,18 +259,20 @@ namespace Greenshot.Base.Core /// /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 /// - /// - /// + /// Image + /// int + /// Rectangle with optional area /// Rectangle - public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) + public static Rectangle FindAutoCropRectangle(Image image, int cropDifference, Rectangle? area = null) { + area ??= new Rectangle(0, 0, image.Width, image.Height); Rectangle cropRectangle = Rectangle.Empty; var checkPoints = new List { - new Point(0, 0), - new Point(0, image.Height - 1), - new Point(image.Width - 1, 0), - new Point(image.Width - 1, image.Height - 1) + new Point(area.Value.Left, area.Value.Top), + new Point(area.Value.Left, area.Value.Bottom - 1), + new Point(area.Value.Right - 1, area.Value.Top), + new Point(area.Value.Right - 1, area.Value.Bottom - 1) }; // Top Left // Bottom Left @@ -279,7 +283,7 @@ namespace Greenshot.Base.Core // find biggest area foreach (Point checkPoint in checkPoints) { - var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference); + var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference, area); if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) { cropRectangle = currentRectangle; @@ -295,7 +299,7 @@ namespace Greenshot.Base.Core /// /// Bitmap /// IEffect - /// + /// Matrix /// Bitmap public static Image ApplyEffect(Image sourceImage, IEffect effect, Matrix matrix) { diff --git a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs index 24abc2d25..3d420bfa3 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs @@ -78,6 +78,11 @@ namespace Greenshot.Base.Interfaces.Drawing bool InitContent(); + /// + /// Defines if the drawable container participates in undo / redo + /// + bool IsUndoable { get; } + void MakeBoundsChangeUndoable(bool allowMerge); EditStatus DefaultEditMode { get; } diff --git a/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs b/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs index fdbf72847..5af83b39e 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IFieldAggregator.cs @@ -21,6 +21,9 @@ namespace Greenshot.Base.Interfaces.Drawing { + /// + /// The IFieldAggregator defines the connections between fields and containers + /// public interface IFieldAggregator { void UnbindElement(IDrawableContainer dc); diff --git a/src/Greenshot.Base/Interfaces/ISurface.cs b/src/Greenshot.Base/Interfaces/ISurface.cs index 85cefe452..396a5702f 100644 --- a/src/Greenshot.Base/Interfaces/ISurface.cs +++ b/src/Greenshot.Base/Interfaces/ISurface.cs @@ -201,8 +201,16 @@ namespace Greenshot.Base.Interfaces /// A rectangle in the coordinate space of the surface. Rectangle ToImageCoordinates(Rectangle rc); + /// + /// Make it possible to undo the specified IMemento + /// + /// IMemento + /// bool to specify if the action can be merged, e.g. we do not want an undo for every part of a resize void MakeUndoable(IMemento memento, bool allowMerge); + /// + /// The IFieldAggregator + /// IFieldAggregator FieldAggregator { get; } /// diff --git a/src/Greenshot.Editor/Configuration/LanguageKeys.cs b/src/Greenshot.Editor/Configuration/LanguageKeys.cs index f15b113d4..b1f410e66 100644 --- a/src/Greenshot.Editor/Configuration/LanguageKeys.cs +++ b/src/Greenshot.Editor/Configuration/LanguageKeys.cs @@ -33,6 +33,7 @@ namespace Greenshot.Editor.Configuration contextmenu_capturefullscreen_right, contextmenu_capturefullscreen_bottom, contextmenu_captureie, + editor_autocrop_not_possible, editor_clipboardfailed, editor_close_on_save, editor_close_on_save_title, diff --git a/src/Greenshot.Editor/Drawing/CropContainer.cs b/src/Greenshot.Editor/Drawing/CropContainer.cs index 2324331f0..936a1a2c8 100644 --- a/src/Greenshot.Editor/Drawing/CropContainer.cs +++ b/src/Greenshot.Editor/Drawing/CropContainer.cs @@ -19,10 +19,12 @@ * along with this program. If not, see . */ + using System.Drawing; using System.Runtime.Serialization; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Editor.Drawing.Adorners; using Greenshot.Editor.Drawing.Fields; using Greenshot.Editor.Helpers; @@ -33,6 +35,29 @@ namespace Greenshot.Editor.Drawing /// public class CropContainer : DrawableContainer { + /// + /// Available Crop modes + /// + public enum CropModes + { + /// + /// crop all outside the selection rectangle + /// + Default, + /// + /// like default, but initially creates the selection rectangle + /// + AutoCrop, + /// + /// crop all inside the selection, anchors the selection to the top and bottom edges + /// + Vertical, + /// + /// crop all inside the selection, anchors the selection to the left and right edges + /// + Horizontal + } + public CropContainer(ISurface parent) : base(parent) { Init(); @@ -46,12 +71,65 @@ namespace Greenshot.Editor.Drawing private void Init() { - CreateDefaultAdorners(); + switch (GetFieldValue(FieldType.CROPMODE)) + { + case CropModes.Horizontal: + { + InitHorizontalCropOutStyle(); + break; + } + case CropModes.Vertical: + { + InitVerticalCropOutStyle(); + break; + } + default: + { + CreateDefaultAdorners(); + break; + } + } + } + + private void InitHorizontalCropOutStyle() + { + const int defaultHeight = 25; + + if (_parent?.Image is { } image) + { + Size = new Size(image.Width, defaultHeight); + } + CreateTopBottomAdorners(); + } + + private void InitVerticalCropOutStyle() + { + const int defaultWidth = 25; + + if (_parent?.Image is { } image) + { + Size = new Size(defaultWidth, image.Height); + } + + CreateLeftRightAdorners(); + } + + private void CreateTopBottomAdorners() + { + Adorners.Add(new ResizeAdorner(this, Positions.TopCenter)); + Adorners.Add(new ResizeAdorner(this, Positions.BottomCenter)); + } + + private void CreateLeftRightAdorners() + { + Adorners.Add(new ResizeAdorner(this, Positions.MiddleLeft)); + Adorners.Add(new ResizeAdorner(this, Positions.MiddleRight)); } protected override void InitializeFields() { AddField(GetType(), FieldType.FLAGS, FieldFlag.CONFIRMABLE); + AddField(GetType(), FieldType.CROPMODE, CropModes.Default); } public override void Invalidate() @@ -83,6 +161,7 @@ namespace Greenshot.Editor.Drawing return; } + using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100)); Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); Rectangle selectionRect = new Rectangle(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1); @@ -90,20 +169,104 @@ namespace Greenshot.Editor.Drawing DrawSelectionBorder(g, selectionRect); - // top - g.FillRectangle(cropBrush, new Rectangle(0, 0, imageSize.Width, cropRectangle.Top)); - // left - g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); - // right - g.FillRectangle(cropBrush, - new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); - // bottom - g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height))); + switch (GetFieldValue(FieldType.CROPMODE)) + { + case CropModes.Horizontal: + case CropModes.Vertical: + { + //draw inside + g.FillRectangle(cropBrush, cropRectangle); + break; + } + default: + { + //draw outside + // top + g.FillRectangle(cropBrush, new Rectangle(0, 0, imageSize.Width, cropRectangle.Top)); + // left + g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top, cropRectangle.Left, cropRectangle.Height)); + // right + g.FillRectangle(cropBrush, new Rectangle(cropRectangle.Left + cropRectangle.Width, cropRectangle.Top, imageSize.Width - (cropRectangle.Left + cropRectangle.Width), cropRectangle.Height)); + // bottom + g.FillRectangle(cropBrush, new Rectangle(0, cropRectangle.Top + cropRectangle.Height, imageSize.Width, imageSize.Height - (cropRectangle.Top + cropRectangle.Height))); + break; + } + } + + } /// /// No context menu for the CropContainer /// public override bool HasContextMenu => false; + + public override bool HandleMouseDown(int x, int y) + { + return GetFieldValue(FieldType.CROPMODE) switch + { + //force horizontal crop to left edge + CropModes.Horizontal => base.HandleMouseDown(0, y), + //force vertical crop to top edge + CropModes.Vertical => base.HandleMouseDown(x, 0), + _ => base.HandleMouseDown(x, y), + }; + } + + public override bool HandleMouseMove(int x, int y) + { + Invalidate(); + + switch (GetFieldValue(FieldType.CROPMODE)) + { + case CropModes.Horizontal: + { + //stick on left and right + //allow only horizontal changes + if (_parent?.Image is { } image) + { + _boundsAfterResize.X = 0; + _boundsAfterResize.Y = _boundsBeforeResize.Top; + _boundsAfterResize.Width = image.Width; + _boundsAfterResize.Height = y - _boundsAfterResize.Top; + } + break; + } + case CropModes.Vertical: + { + //stick on top and bottom + //allow only vertical changes + if (_parent?.Image is { } image) + { + _boundsAfterResize.X = _boundsBeforeResize.Left; + _boundsAfterResize.Y = 0; + _boundsAfterResize.Width = x - _boundsAfterResize.Left; + _boundsAfterResize.Height = image.Height; + } + break; + } + default: + { + // reset "workbench" rectangle to current bounds + _boundsAfterResize.X = _boundsBeforeResize.Left; + _boundsAfterResize.Y = _boundsBeforeResize.Top; + _boundsAfterResize.Width = x - _boundsAfterResize.Left; + _boundsAfterResize.Height = y - _boundsAfterResize.Top; + break; + } + + } + ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); + + // apply scaled bounds to this DrawableContainer + ApplyBounds(_boundsAfterResize); + + Invalidate(); + return true; + } + + /// + /// Make sure this container is not undoable + public override bool IsUndoable => false; } -} \ No newline at end of file +} diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index 08abba3e2..b07974e61 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -472,13 +472,20 @@ namespace Greenshot.Editor.Drawing g.DrawRectangle(pen, rect); } + /// + public virtual bool IsUndoable => true; + /// /// Make a following bounds change on this drawablecontainer undoable! /// /// true means allow the moves to be merged - public void MakeBoundsChangeUndoable(bool allowMerge) + public virtual void MakeBoundsChangeUndoable(bool allowMerge) { - _parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); + if (!IsUndoable) + { + return; + } + _parent?.MakeUndoable(new DrawableContainerBoundsChangeMemento(this), allowMerge); } public void MoveBy(int dx, int dy) @@ -552,11 +559,10 @@ namespace Greenshot.Editor.Drawing protected void OnPropertyChanged(string propertyName) { - if (_propertyChanged != null) - { - _propertyChanged(this, new PropertyChangedEventArgs(propertyName)); - Invalidate(); - } + if (_propertyChanged == null) return; + + _propertyChanged(this, new PropertyChangedEventArgs(propertyName)); + Invalidate(); } /// @@ -567,7 +573,10 @@ namespace Greenshot.Editor.Drawing /// The new value public virtual void BeforeFieldChange(IField fieldToBeChanged, object newValue) { - _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); + if (IsUndoable) + { + _parent?.MakeUndoable(new ChangeFieldHolderMemento(this, fieldToBeChanged), true); + } Invalidate(); } diff --git a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs index e89b78b70..9ab825e4a 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; +using System.Linq; using System.Threading; using System.Windows.Forms; using Greenshot.Base.Core; @@ -50,6 +51,11 @@ namespace Greenshot.Editor.Drawing { } + public DrawableContainerList(IEnumerable elements) + { + AddRange(elements); + } + public DrawableContainerList(Guid parentId) { ParentID = parentId; @@ -130,17 +136,21 @@ namespace Greenshot.Editor.Drawing } /// - /// Make a following bounds change on this containerlist undoable! + /// Make a following bounds change on this DrawableContainerList undoable! /// /// true means allow the moves to be merged public void MakeBoundsChangeUndoable(bool allowMerge) { - if (Count > 0 && Parent != null) + if (Count <= 0 || Parent == null) return; + // Take all containers to make undoable + var containersToClone = this.Where(c => c.IsUndoable).ToList(); + if (!containersToClone.Any()) { - var clone = new DrawableContainerList(); - clone.AddRange(this); - Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge); + return; } + var clone = new DrawableContainerList(); + clone.AddRange(containersToClone); + Parent.MakeUndoable(new DrawableContainerBoundsChangeMemento(clone), allowMerge); } /// @@ -291,16 +301,14 @@ namespace Greenshot.Editor.Drawing { return Rectangle.Empty; } - else - { - var result = this[0].DrawingBounds; - for (int i = 1; i < Count; i++) - { - result = Rectangle.Union(result, this[i].DrawingBounds); - } - return result; + var result = this[0].DrawingBounds; + for (int i = 1; i < Count; i++) + { + result = Rectangle.Union(result, this[i].DrawingBounds); } + + return result; } } @@ -309,7 +317,7 @@ namespace Greenshot.Editor.Drawing /// /// the to the bitmap related Graphics object /// Bitmap to draw - /// the rendermode in which the element is to be drawn + /// the RenderMode in which the element is to be drawn /// public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle) { @@ -574,9 +582,7 @@ namespace Greenshot.Editor.Drawing return; } - var dc = this[index1]; - this[index1] = this[index2]; - this[index2] = dc; + (this[index1], this[index2]) = (this[index2], this[index1]); Parent.Modified = true; } diff --git a/src/Greenshot.Editor/Drawing/Fields/FieldType.cs b/src/Greenshot.Editor/Drawing/Fields/FieldType.cs index c3b732f4b..eead7452a 100644 --- a/src/Greenshot.Editor/Drawing/Fields/FieldType.cs +++ b/src/Greenshot.Editor/Drawing/Fields/FieldType.cs @@ -31,31 +31,33 @@ namespace Greenshot.Editor.Drawing.Fields [Serializable] public class FieldType : IFieldType { - public static readonly IFieldType ARROWHEADS = new FieldType("ARROWHEADS"); - public static readonly IFieldType BLUR_RADIUS = new FieldType("BLUR_RADIUS"); - public static readonly IFieldType BRIGHTNESS = new FieldType("BRIGHTNESS"); - public static readonly IFieldType FILL_COLOR = new FieldType("FILL_COLOR"); - public static readonly IFieldType FONT_BOLD = new FieldType("FONT_BOLD"); - public static readonly IFieldType FONT_FAMILY = new FieldType("FONT_FAMILY"); - public static readonly IFieldType FONT_ITALIC = new FieldType("FONT_ITALIC"); - public static readonly IFieldType FONT_SIZE = new FieldType("FONT_SIZE"); - public static readonly IFieldType TEXT_HORIZONTAL_ALIGNMENT = new FieldType("TEXT_HORIZONTAL_ALIGNMENT"); - public static readonly IFieldType TEXT_VERTICAL_ALIGNMENT = new FieldType("TEXT_VERTICAL_ALIGNMENT"); - public static readonly IFieldType HIGHLIGHT_COLOR = new FieldType("HIGHLIGHT_COLOR"); - public static readonly IFieldType LINE_COLOR = new FieldType("LINE_COLOR"); - public static readonly IFieldType LINE_THICKNESS = new FieldType("LINE_THICKNESS"); - public static readonly IFieldType MAGNIFICATION_FACTOR = new FieldType("MAGNIFICATION_FACTOR"); - public static readonly IFieldType PIXEL_SIZE = new FieldType("PIXEL_SIZE"); - public static readonly IFieldType PREVIEW_QUALITY = new FieldType("PREVIEW_QUALITY"); - public static readonly IFieldType SHADOW = new FieldType("SHADOW"); - public static readonly IFieldType PREPARED_FILTER_OBFUSCATE = new FieldType("PREPARED_FILTER_OBFUSCATE"); - public static readonly IFieldType PREPARED_FILTER_HIGHLIGHT = new FieldType("PREPARED_FILTER_HIGHLIGHT"); - public static readonly IFieldType FLAGS = new FieldType("FLAGS"); + public static readonly IFieldType ARROWHEADS = new FieldType(nameof(ARROWHEADS)); + public static readonly IFieldType BLUR_RADIUS = new FieldType(nameof(BLUR_RADIUS)); + public static readonly IFieldType BRIGHTNESS = new FieldType(nameof(BRIGHTNESS)); + public static readonly IFieldType FILL_COLOR = new FieldType(nameof(FILL_COLOR)); + public static readonly IFieldType FONT_BOLD = new FieldType(nameof(FONT_BOLD)); + public static readonly IFieldType FONT_FAMILY = new FieldType(nameof(FONT_FAMILY)); + public static readonly IFieldType FONT_ITALIC = new FieldType(nameof(FONT_ITALIC)); + public static readonly IFieldType FONT_SIZE = new FieldType(nameof(FONT_SIZE)); + public static readonly IFieldType TEXT_HORIZONTAL_ALIGNMENT = new FieldType(nameof(TEXT_HORIZONTAL_ALIGNMENT)); + public static readonly IFieldType TEXT_VERTICAL_ALIGNMENT = new FieldType(nameof(TEXT_VERTICAL_ALIGNMENT)); + public static readonly IFieldType HIGHLIGHT_COLOR = new FieldType(nameof(HIGHLIGHT_COLOR)); + public static readonly IFieldType LINE_COLOR = new FieldType(nameof(LINE_COLOR)); + public static readonly IFieldType LINE_THICKNESS = new FieldType(nameof(LINE_THICKNESS)); + public static readonly IFieldType MAGNIFICATION_FACTOR = new FieldType(nameof(MAGNIFICATION_FACTOR)); + public static readonly IFieldType PIXEL_SIZE = new FieldType(nameof(PIXEL_SIZE)); + public static readonly IFieldType PREVIEW_QUALITY = new FieldType(nameof(PREVIEW_QUALITY)); + public static readonly IFieldType SHADOW = new FieldType(nameof(SHADOW)); + public static readonly IFieldType PREPARED_FILTER_OBFUSCATE = new FieldType(nameof(PREPARED_FILTER_OBFUSCATE)); + public static readonly IFieldType PREPARED_FILTER_HIGHLIGHT = new FieldType(nameof(PREPARED_FILTER_HIGHLIGHT)); + public static readonly IFieldType FLAGS = new FieldType(nameof(FLAGS)); + public static readonly IFieldType CROPMODE = new FieldType(nameof(CROPMODE)); + public static IFieldType[] Values = { ARROWHEADS, BLUR_RADIUS, BRIGHTNESS, FILL_COLOR, FONT_BOLD, FONT_FAMILY, FONT_ITALIC, FONT_SIZE, TEXT_HORIZONTAL_ALIGNMENT, TEXT_VERTICAL_ALIGNMENT, HIGHLIGHT_COLOR, - LINE_COLOR, LINE_THICKNESS, MAGNIFICATION_FACTOR, PIXEL_SIZE, PREVIEW_QUALITY, SHADOW, PREPARED_FILTER_OBFUSCATE, PREPARED_FILTER_HIGHLIGHT, FLAGS + LINE_COLOR, LINE_THICKNESS, MAGNIFICATION_FACTOR, PIXEL_SIZE, PREVIEW_QUALITY, SHADOW, PREPARED_FILTER_OBFUSCATE, PREPARED_FILTER_HIGHLIGHT, FLAGS, CROPMODE }; public string Name { get; set; } diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index 7c27c8ce1..be40c7d1c 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -26,6 +26,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; +using System.Linq; using System.Runtime.Serialization.Formatters.Binary; using System.Windows.Forms; using Greenshot.Base.Controls; @@ -710,7 +711,7 @@ namespace Greenshot.Editor.Drawing BinaryFormatter binaryRead = new BinaryFormatter(); IDrawableContainerList loadedElements = (IDrawableContainerList) binaryRead.Deserialize(streamRead); loadedElements.Parent = this; - // Make sure the steplabels are sorted accoring to their number + // Make sure the steplabels are sorted according to their number _stepLabels.Sort((p1, p2) => p1.Number.CompareTo(p2.Number)); DeselectAllElements(); AddElements(loadedElements); @@ -972,16 +973,17 @@ namespace Greenshot.Editor.Drawing /// /// Auto crop the image /// + /// Rectangle with optional area to find a crop region /// true if cropped - public bool AutoCrop() + public bool AutoCrop(Rectangle? cropArea = null) { Rectangle cropRectangle; using (Image tmpImage = GetImageForExport()) { - cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference); + cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference, cropArea); } - if (!IsCropPossible(ref cropRectangle)) + if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.AutoCrop)) { return false; } @@ -1060,11 +1062,13 @@ namespace Greenshot.Editor.Drawing /// /// check if a crop is possible /// - /// + /// Rectangle adapted to the dimensions of the image + /// CropModes /// true if this is possible - public bool IsCropPossible(ref Rectangle cropRectangle) + public bool IsCropPossible(ref Rectangle cropRectangle, CropContainer.CropModes cropMode) { cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); + //Fitting the rectangle to the dimensions of the image if (cropRectangle.Left < 0) { cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); @@ -1085,6 +1089,21 @@ namespace Greenshot.Editor.Drawing cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top); } + // special condition for vertical + if(cropMode == CropContainer.CropModes.Vertical && cropRectangle.Width == Image.Width) + { + //crop out the hole image is not allowed + return false; + } + + // special condition for vertical + if (cropMode == CropContainer.CropModes.Horizontal && cropRectangle.Height == Image.Height) + { + //crop out the hole image is not allowed + return false; + } + + //condition for all other crop modes if (cropRectangle.Height > 0 && cropRectangle.Width > 0) { return true; @@ -1101,16 +1120,15 @@ namespace Greenshot.Editor.Drawing /// Message itself public void SendMessageEvent(object source, SurfaceMessageTyp messageType, string message) { - if (_surfaceMessage != null) + if (_surfaceMessage == null) return; + + var eventArgs = new SurfaceMessageEventArgs { - var eventArgs = new SurfaceMessageEventArgs - { - Message = message, - MessageType = messageType, - Surface = this - }; - _surfaceMessage(source, eventArgs); - } + Message = message, + MessageType = messageType, + Surface = this + }; + _surfaceMessage(source, eventArgs); } /// @@ -1118,16 +1136,15 @@ namespace Greenshot.Editor.Drawing /// /// Who send /// new color - public void UpdateForegroundColorEvent(object source, Color color) + private void UpdateForegroundColorEvent(object source, Color color) { - if (_foregroundColorChanged != null) + if (_foregroundColorChanged == null) return; + + var eventArgs = new SurfaceForegroundColorEventArgs { - var eventArgs = new SurfaceForegroundColorEventArgs - { - Color = color, - }; - _foregroundColorChanged(source, eventArgs); - } + Color = color, + }; + _foregroundColorChanged(source, eventArgs); } /// @@ -1135,16 +1152,15 @@ namespace Greenshot.Editor.Drawing /// /// Who send /// new color - public void UpdateBackgroundColorEvent(object source, Color color) + private void UpdateBackgroundColorEvent(object source, Color color) { - if (_lineThicknessChanged != null) + if (_lineThicknessChanged == null) return; + + var eventArgs = new SurfaceBackgroundColorEventArgs { - var eventArgs = new SurfaceBackgroundColorEventArgs - { - Color = color, - }; - _backgroundColorChanged(source, eventArgs); - } + Color = color, + }; + _backgroundColorChanged(source, eventArgs); } /// @@ -1152,16 +1168,15 @@ namespace Greenshot.Editor.Drawing /// /// Who send /// new thickness - public void UpdateLineThicknessEvent(object source, int thickness) + private void UpdateLineThicknessEvent(object source, int thickness) { - if (_lineThicknessChanged != null) + if (_lineThicknessChanged == null) return; + + var eventArgs = new SurfaceLineThicknessEventArgs { - var eventArgs = new SurfaceLineThicknessEventArgs - { - Thickness = thickness, - }; - _lineThicknessChanged(source, eventArgs); - } + Thickness = thickness, + }; + _lineThicknessChanged(source, eventArgs); } /// @@ -1169,61 +1184,173 @@ namespace Greenshot.Editor.Drawing /// /// Who send /// has shadow - public void UpdateShadowEvent(object source, bool hasShadow) + private void UpdateShadowEvent(object source, bool hasShadow) { - if (_shadowChanged != null) - { - var eventArgs = new SurfaceShadowEventArgs - { - HasShadow = hasShadow, - }; - _shadowChanged(source, eventArgs); - } + if (_shadowChanged == null) return; + + var eventArgs = new SurfaceShadowEventArgs + { + HasShadow = hasShadow, + }; + _shadowChanged(source, eventArgs); } /// /// Crop the surface /// - /// - /// + /// rectangle that remains + /// bool public bool ApplyCrop(Rectangle cropRectangle) { - if (IsCropPossible(ref cropRectangle)) + if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.Default)) return false; + + Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); + Bitmap tmpImage; + // Make sure we have information, this this fails + try { - Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); - Bitmap tmpImage; - // Make sure we have information, this this fails - try - { - tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); - } - catch (Exception ex) - { - ex.Data.Add("CropRectangle", cropRectangle); - ex.Data.Add("Width", Image.Width); - ex.Data.Add("Height", Image.Height); - ex.Data.Add("Pixelformat", Image.PixelFormat); - throw; - } - - Matrix matrix = new Matrix(); - matrix.Translate(-cropRectangle.Left, -cropRectangle.Top, MatrixOrder.Append); - // Make undoable - MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); - - // Do not dispose otherwise we can't undo the image! - SetImage(tmpImage, false); - _elements.Transform(matrix); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) - { - _surfaceSizeChanged(this, null); - } - - Invalidate(); - return true; + tmpImage = ImageHelper.CloneArea(Image, cropRectangle, PixelFormat.DontCare); + } + catch (Exception ex) + { + ex.Data.Add("CropRectangle", cropRectangle); + ex.Data.Add("Width", Image.Width); + ex.Data.Add("Height", Image.Height); + ex.Data.Add("Pixelformat", Image.PixelFormat); + throw; } - return false; + var matrix = new Matrix(); + matrix.Translate(-cropRectangle.Left, -cropRectangle.Top, MatrixOrder.Append); + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); + + // Do not dispose otherwise we can't undo the image! + SetImage(tmpImage, false); + _elements.Transform(matrix); + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) + { + _surfaceSizeChanged(this, null); + } + + Invalidate(); + return true; + } + + /// + /// Crop out the surface + /// Splits the image in 3 parts(top, middle, bottom). Crop out the middle and joins top and bottom. + /// + /// rectangle of the middle part + /// bool + private bool ApplyHorizontalCrop(Rectangle cropRectangle) + { + if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.Horizontal)) return false; + + var imageRectangle = new Rectangle(Point.Empty, Image.Size); + var topRectangle = new Rectangle(0, 0, Image.Size.Width, cropRectangle.Top); + var bottomRectangle = new Rectangle(0, cropRectangle.Top + cropRectangle.Height, Image.Size.Width, Image.Size.Height - cropRectangle.Top - cropRectangle.Height); + + Bitmap newImage; + try + { + newImage = new Bitmap(Image.Size.Width, Image.Size.Height - cropRectangle.Height); + + using var graphics = Graphics.FromImage(newImage); + + var insertPositionTop = 0; + if (topRectangle.Height > 0) + { + graphics.DrawImage(Image, new Rectangle(0, insertPositionTop, topRectangle.Width, topRectangle.Height), topRectangle, GraphicsUnit.Pixel); + insertPositionTop += topRectangle.Height; + } + if (bottomRectangle.Height > 0) + { + graphics.DrawImage(Image, new Rectangle(0, insertPositionTop, bottomRectangle.Width, bottomRectangle.Height), bottomRectangle, GraphicsUnit.Pixel); + } + } + catch (Exception ex) + { + ex.Data.Add("CropRectangle", cropRectangle); + ex.Data.Add("Width", Image.Width); + ex.Data.Add("Height", Image.Height); + ex.Data.Add("Pixelformat", Image.PixelFormat); + throw; + } + var matrix = new Matrix(); + matrix.Translate(0, -(cropRectangle.Top + cropRectangle.Height), MatrixOrder.Append); + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); + + // Do not dispose otherwise we can't undo the image! + SetImage(newImage, false); + + _elements.Transform(matrix); + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) + { + _surfaceSizeChanged(this, null); + } + + Invalidate(); + return true; + } + + /// + /// Crop out the surface + /// Splits the image in 3 parts(left, middle, right). Crop out the middle and joins top and bottom. + /// + /// rectangle of the middle part + /// bool + private bool ApplyVerticalCrop(Rectangle cropRectangle) + { + if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.Vertical)) return false; + + var imageRectangle = new Rectangle(Point.Empty, Image.Size); + var leftRectangle = new Rectangle(0, 0, cropRectangle.Left, Image.Size.Height); + var rightRectangle = new Rectangle(cropRectangle.Left + cropRectangle.Width, 0, Image.Size.Width - cropRectangle.Width - cropRectangle.Left, Image.Size.Height); + Bitmap newImage; + try + { + newImage = new Bitmap(Image.Size.Width - cropRectangle.Width, Image.Size.Height); + + using var graphics = Graphics.FromImage(newImage); + + var insertPositionLeft = 0; + if (leftRectangle.Width > 0) + { + graphics.DrawImage(Image, new Rectangle(insertPositionLeft, 0, leftRectangle.Width, leftRectangle.Height), leftRectangle , GraphicsUnit.Pixel); + insertPositionLeft += leftRectangle.Width; + } + + if (rightRectangle.Width > 0) + { + graphics.DrawImage(Image, new Rectangle(insertPositionLeft, 0, rightRectangle.Width, rightRectangle.Height), rightRectangle, GraphicsUnit.Pixel); + } + } + catch (Exception ex) + { + ex.Data.Add("CropRectangle", cropRectangle); + ex.Data.Add("Width", Image.Width); + ex.Data.Add("Height", Image.Height); + ex.Data.Add("Pixelformat", Image.PixelFormat); + throw; + } + var matrix = new Matrix(); + matrix.Translate(-cropRectangle.Left - cropRectangle.Width, 0, MatrixOrder.Append); + // Make undoable + MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); + + // Do not dispose otherwise we can't undo the image! + SetImage(newImage, false); + + _elements.Transform(matrix); + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) + { + _surfaceSizeChanged(this, null); + } + + Invalidate(); + return true; } /// @@ -1255,15 +1382,14 @@ namespace Greenshot.Editor.Drawing { foreach (IAdorner adorner in drawableContainer.Adorners) { - if (adorner.IsActive || adorner.HitTest(mouseEventArgs.Location)) + if (!adorner.IsActive && !adorner.HitTest(mouseEventArgs.Location)) continue; + + if (adorner.Cursor != null) { - if (adorner.Cursor != null) - { - Cursor = adorner.Cursor; - } - - return adorner; + Cursor = adorner.Cursor; } + + return adorner; } } @@ -1494,48 +1620,47 @@ namespace Greenshot.Editor.Drawing Cursor = DrawingMode != DrawingModes.None ? Cursors.Cross : Cursors.Default; - if (_mouseDown) + if (!_mouseDown) return; + + if (_mouseDownElement != null) { - if (_mouseDownElement != null) + // an element is currently dragged + _mouseDownElement.Invalidate(); + selectedElements.Invalidate(); + // Move the element + if (_mouseDownElement.Selected) { - // an element is currently dragged - _mouseDownElement.Invalidate(); - selectedElements.Invalidate(); - // Move the element - if (_mouseDownElement.Selected) + if (!_isSurfaceMoveMadeUndoable) { - if (!_isSurfaceMoveMadeUndoable) - { - // Only allow one undoable per mouse-down/move/up "cycle" - _isSurfaceMoveMadeUndoable = true; - selectedElements.MakeBoundsChangeUndoable(false); - } - - // dragged element has been selected before -> move all - selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); - } - else - { - if (!_isSurfaceMoveMadeUndoable) - { - // Only allow one undoable per mouse-down/move/up "cycle" - _isSurfaceMoveMadeUndoable = true; - _mouseDownElement.MakeBoundsChangeUndoable(false); - } - - // dragged element is not among selected elements -> just move dragged one - _mouseDownElement.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); + // Only allow one undoable per mouse-down/move/up "cycle" + _isSurfaceMoveMadeUndoable = true; + selectedElements.MakeBoundsChangeUndoable(false); } - _mouseStart = currentMouse; - _mouseDownElement.Invalidate(); - _modified = true; + // dragged element has been selected before -> move all + selectedElements.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); } - else if (_drawingElement != null) + else { - _drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); - _modified = true; + if (!_isSurfaceMoveMadeUndoable) + { + // Only allow one undoable per mouse-down/move/up "cycle" + _isSurfaceMoveMadeUndoable = true; + _mouseDownElement.MakeBoundsChangeUndoable(false); + } + + // dragged element is not among selected elements -> just move dragged one + _mouseDownElement.MoveBy(currentMouse.X - _mouseStart.X, currentMouse.Y - _mouseStart.Y); } + + _mouseStart = currentMouse; + _mouseDownElement.Invalidate(); + _modified = true; + } + else if (_drawingElement != null) + { + _drawingElement.HandleMouseMove(currentMouse.X, currentMouse.Y); + _modified = true; } } @@ -1795,7 +1920,7 @@ namespace Greenshot.Editor.Drawing element.Invalidate(); } - if (makeUndoable) + if (makeUndoable && element.IsUndoable) { MakeUndoable(new AddElementMemento(this, element), false); } @@ -1811,11 +1936,17 @@ namespace Greenshot.Editor.Drawing public void RemoveElements(IDrawableContainerList elementsToRemove, bool makeUndoable = true) { // fix potential issues with iterating a changing list - DrawableContainerList cloned = new DrawableContainerList(); - cloned.AddRange(elementsToRemove); + DrawableContainerList cloned = new DrawableContainerList(elementsToRemove); + if (makeUndoable) { - MakeUndoable(new DeleteElementsMemento(this, cloned), false); + // Take all containers to make undoable + var undoableContainers = elementsToRemove.Where(c => c.IsUndoable).ToList(); + if (undoableContainers.Any()) + { + var undoableContainerList = new DrawableContainerList(undoableContainers); + MakeUndoable(new DeleteElementsMemento(this, undoableContainerList), false); + } } SuspendLayout(); @@ -1863,7 +1994,7 @@ namespace Greenshot.Editor.Drawing Invalidate(); } - if (makeUndoable) + if (makeUndoable && elementToRemove is { IsUndoable: true }) { MakeUndoable(new DeleteElementMemento(this, elementToRemove), false); } @@ -1879,11 +2010,16 @@ namespace Greenshot.Editor.Drawing public void AddElements(IDrawableContainerList elementsToAdd, bool makeUndoable = true) { // fix potential issues with iterating a changing list - DrawableContainerList cloned = new DrawableContainerList(); - cloned.AddRange(elementsToAdd); + DrawableContainerList cloned = new DrawableContainerList(elementsToAdd); if (makeUndoable) { - MakeUndoable(new AddElementsMemento(this, cloned), false); + // Take all containers to make undoable + var undoableContainers = elementsToAdd.Where(c => c.IsUndoable).ToList(); + if (undoableContainers.Any()) + { + var undoableContainerList = new DrawableContainerList(undoableContainers); + MakeUndoable(new AddElementsMemento(this, undoableContainerList), false); + } } SuspendLayout(); @@ -1925,11 +2061,9 @@ namespace Greenshot.Editor.Drawing /// public void CutSelectedElements() { - if (HasSelectedElements) - { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); - RemoveSelectedElements(); - } + if (!HasSelectedElements) return; + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); + RemoveSelectedElements(); } /// @@ -1937,38 +2071,96 @@ namespace Greenshot.Editor.Drawing /// public void CopySelectedElements() { - if (HasSelectedElements) + if (!HasSelectedElements) return; + ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); + } + + /// + /// This method is called to confirm/cancel. + /// Called when pressing enter or using the "check" in the editor. + /// redirects to the specialized confirm/cancel method + /// + /// bool + public void Confirm(bool confirm) + { + if (DrawingMode == DrawingModes.Crop) { - ClipboardHelper.SetClipboardData(typeof(IDrawableContainerList), selectedElements); + ConfirmCrop(confirm); + } + else + { + ConfirmSelectedConfirmableElements(confirm); } } /// - /// This method is called to confirm/cancel "confirmable" elements, like the crop-container. + /// This method is called to confirm/cancel "confirmable" elements /// Called when pressing enter or using the "check" in the editor. + ///
+ /// For crop-container there is a dedicated method . ///
- /// + /// bool public void ConfirmSelectedConfirmableElements(bool confirm) { // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel) List selectedDCs = new List(selectedElements); foreach (IDrawableContainer dc in selectedDCs) - { - if (dc.Equals(_cropContainer)) - { - DrawingMode = DrawingModes.None; - // No undo memento for the cropcontainer itself, only for the effect - RemoveElement(_cropContainer, false); - if (confirm) - { - ApplyCrop(_cropContainer.Bounds); - } - - _cropContainer.Dispose(); - _cropContainer = null; - break; - } + { + throw new NotImplementedException($"No confirm/cancel defined for Container type {dc.GetType()}"); } + + // maybe the undo button has to be enabled + if (_movingElementChanged != null) + { + _movingElementChanged(this, new SurfaceElementEventArgs()); + } + } + + /// + /// This method is called to confirm/cancel the crop-container. + /// Called when pressing enter or using the "check" in the editor. + /// + /// bool + public void ConfirmCrop(bool confirm) + { + if (_cropContainer is not CropContainer e) return; + + if (confirm && selectedElements.Count > 0) + { + // No undo memento for the cropcontainer itself, only for the effect + RemoveElement(_cropContainer, false); + + _ = e.GetFieldValue(FieldType.CROPMODE) switch + { + CropContainer.CropModes.Horizontal => ApplyHorizontalCrop(_cropContainer.Bounds), + CropContainer.CropModes.Vertical => ApplyVerticalCrop(_cropContainer.Bounds), + _ => ApplyCrop(_cropContainer.Bounds) + }; + + _cropContainer.Dispose(); + _cropContainer = null; + } + else + { + RemoveCropContainer(); + } + + DrawingMode = DrawingModes.None; + + // maybe the undo button has to be enabled + if (_movingElementChanged != null) + { + _movingElementChanged(this, new SurfaceElementEventArgs()); + } + } + + public void RemoveCropContainer() + { + if (_cropContainer == null) return; + + RemoveElement(_cropContainer, false); + _cropContainer.Dispose(); + _cropContainer = null; } /// @@ -2144,13 +2336,13 @@ namespace Greenshot.Editor.Drawing /// /// Get the rectangle bounding all selected elements (in surface coordinates space), - /// or empty rectangle if nothing is selcted. + /// or empty rectangle if nothing is selected. /// public Rectangle GetSelectionRectangle() => ToSurfaceCoordinates(selectedElements.DrawingBounds); /// - /// Duplicate all the selecteded elements + /// Duplicate all the selected elements /// public void DuplicateSelectedElements() { @@ -2289,7 +2481,7 @@ namespace Greenshot.Editor.Drawing /// false if no keys were processed public bool ProcessCmdKey(Keys k) { - if (selectedElements.Count <= 0) return false; + if (selectedElements.Count <= 0 && k != Keys.Escape) return false; bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; int px = shiftModifier ? 10 : 1; @@ -2325,10 +2517,10 @@ namespace Greenshot.Editor.Drawing PushElementsToBottom(); break; case Keys.Enter: - ConfirmSelectedConfirmableElements(true); + Confirm(true); break; case Keys.Escape: - ConfirmSelectedConfirmableElements(false); + Confirm(false); break; case Keys.D0 | Keys.Control: case Keys.D0 | Keys.Shift | Keys.Control: @@ -2487,7 +2679,7 @@ namespace Greenshot.Editor.Drawing return _elements.CanPushDown(selectedElements); } - public void Element_FieldChanged(object sender, FieldChangedEventArgs e) + private void Element_FieldChanged(object sender, FieldChangedEventArgs e) { selectedElements.HandleFieldChangedEvent(sender, e); } @@ -2545,20 +2737,18 @@ namespace Greenshot.Editor.Drawing { return rc; } - else + + Point[] points = { - Point[] points = - { - rc.Location, rc.Location + rc.Size - }; - _inverseZoomMatrix.TransformPoints(points); - return new Rectangle( - points[0].X, - points[0].Y, - points[1].X - points[0].X, - points[1].Y - points[0].Y - ); - } + rc.Location, rc.Location + rc.Size + }; + _inverseZoomMatrix.TransformPoints(points); + return new Rectangle( + points[0].X, + points[0].Y, + points[1].X - points[0].X, + points[1].Y - points[0].Y + ); } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/TextContainer.cs b/src/Greenshot.Editor/Drawing/TextContainer.cs index fdb718cbe..5a1f755ef 100644 --- a/src/Greenshot.Editor/Drawing/TextContainer.cs +++ b/src/Greenshot.Editor/Drawing/TextContainer.cs @@ -74,7 +74,7 @@ namespace Greenshot.Editor.Drawing { if ((text != null || newText == null) && string.Equals(text, newText)) return; - if (makeUndoable && allowUndoable) + if (makeUndoable && allowUndoable && IsUndoable) { makeUndoable = false; _parent.MakeUndoable(new TextChangeMemento(this), false); diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs index 82fecf559..90f62493e 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs @@ -98,8 +98,6 @@ namespace Greenshot.Editor.Forms { this.toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator(); this.preferencesToolStripMenuItem = new GreenshotToolStripMenuItem(); this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); - this.autoCropToolStripMenuItem = new GreenshotToolStripMenuItem(); - this.toolStripSeparator17 = new System.Windows.Forms.ToolStripSeparator(); this.insert_window_toolstripmenuitem = new GreenshotToolStripMenuItem(); this.objectToolStripMenuItem = new GreenshotToolStripMenuItem(); this.addRectangleToolStripMenuItem = new GreenshotToolStripMenuItem(); @@ -144,8 +142,13 @@ namespace Greenshot.Editor.Forms { this.btnHelp = new GreenshotToolStripButton(); this.propertiesToolStrip = new ToolStripEx(); this.obfuscateModeButton = new BindableToolStripDropDownButton(); + this.cropModeButton = new BindableToolStripDropDownButton(); this.pixelizeToolStripMenuItem = new GreenshotToolStripMenuItem(); this.blurToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.defaultCropModeToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.verticalCropModeToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.horizontalCropModeToolStripMenuItem = new GreenshotToolStripMenuItem(); + this.autoCropModeToolStripMenuItem = new GreenshotToolStripMenuItem(); this.highlightModeButton = new BindableToolStripDropDownButton(); this.textHighlightMenuItem = new GreenshotToolStripMenuItem(); this.areaHighlightMenuItem = new GreenshotToolStripMenuItem(); @@ -593,8 +596,6 @@ namespace Greenshot.Editor.Forms { this.toolStripSeparator12, this.preferencesToolStripMenuItem, this.toolStripSeparator5, - this.autoCropToolStripMenuItem, - this.toolStripSeparator17, this.insert_window_toolstripmenuitem}); this.editToolStripMenuItem.LanguageKey = "editor_edit"; this.editToolStripMenuItem.Name = "editToolStripMenuItem"; @@ -678,16 +679,6 @@ namespace Greenshot.Editor.Forms { // this.toolStripSeparator5.Name = "toolStripSeparator5"; // - // autoCropToolStripMenuItem - // - this.autoCropToolStripMenuItem.LanguageKey = "editor_autocrop"; - this.autoCropToolStripMenuItem.Name = "autoCropToolStripMenuItem"; - this.autoCropToolStripMenuItem.Click += new System.EventHandler(this.AutoCropToolStripMenuItemClick); - // - // toolStripSeparator17 - // - this.toolStripSeparator17.Name = "toolStripSeparator17"; - // // insert_window_toolstripmenuitem // this.insert_window_toolstripmenuitem.LanguageKey = "editor_insertwindow"; @@ -1082,6 +1073,7 @@ namespace Greenshot.Editor.Forms { this.toolStripSeparator10, this.btnConfirm, this.btnCancel, + this.cropModeButton, this.counterLabel, this.counterUpDown}); // @@ -1098,6 +1090,7 @@ namespace Greenshot.Editor.Forms { this.obfuscateModeButton.SelectedTag = FilterContainer.PreparedFilter.BLUR; this.obfuscateModeButton.Tag = FilterContainer.PreparedFilter.BLUR; // + this.obfuscateModeButton.DropDownItemClicked += FilterPresetDropDownItemClicked; // pixelizeToolStripMenuItem // this.pixelizeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("pixelizeToolStripMenuItem.Image"))); @@ -1111,6 +1104,55 @@ namespace Greenshot.Editor.Forms { this.blurToolStripMenuItem.LanguageKey = "editor_obfuscate_blur"; this.blurToolStripMenuItem.Name = "blurToolStripMenuItem"; this.blurToolStripMenuItem.Tag = FilterContainer.PreparedFilter.BLUR; + + // + // cropModeButton + // + this.cropModeButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.cropModeButton.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.defaultCropModeToolStripMenuItem, + this.verticalCropModeToolStripMenuItem, + this.horizontalCropModeToolStripMenuItem, + this.autoCropModeToolStripMenuItem}); + this.cropModeButton.Image = ((System.Drawing.Image)(resources.GetObject("btnCrop.Image"))); + this.cropModeButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.cropModeButton.LanguageKey = "editor_crop_mode"; + this.cropModeButton.Name = "cropModeButton"; + this.cropModeButton.SelectedTag = CropContainer.CropModes.Default; + this.cropModeButton.Tag = CropContainer.CropModes.Default; + this.cropModeButton.DropDownItemClicked += CropStyleDropDownItemClicked; + // + // defaultCropStyleToolStripMenuItem + // + this.defaultCropModeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("btnCrop.Image"))); + this.defaultCropModeToolStripMenuItem.LanguageKey = "editor_cropmode_default"; + this.defaultCropModeToolStripMenuItem.Name = "defaultCropModeToolStripMenuItem"; + this.defaultCropModeToolStripMenuItem.Tag = CropContainer.CropModes.Default; + + // + // verticalCropStyleToolStripMenuItem + // + this.verticalCropModeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("CropVertical.Image"))); + this.verticalCropModeToolStripMenuItem.LanguageKey = "editor_cropmode_vertical"; + this.verticalCropModeToolStripMenuItem.Name = "verticalCropModeToolStripMenuItem"; + this.verticalCropModeToolStripMenuItem.Tag = CropContainer.CropModes.Vertical; + + // + // horizontalCropStyleToolStripMenuItem + // + this.horizontalCropModeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("CropHorizontal.Image"))); + this.horizontalCropModeToolStripMenuItem.LanguageKey = "editor_cropmode_horizontal"; + this.horizontalCropModeToolStripMenuItem.Name = "horizontalCropModeToolStripMenuItem"; + this.horizontalCropModeToolStripMenuItem.Tag = CropContainer.CropModes.Horizontal; + + // + // autoCropModeToolStripMenuItem + // + this.autoCropModeToolStripMenuItem.Image = ((System.Drawing.Image)(resources.GetObject("AutoCrop.Image"))); + this.autoCropModeToolStripMenuItem.LanguageKey = "editor_cropmode_auto"; + this.autoCropModeToolStripMenuItem.Name = "autoCropModeToolStripMenuItem"; + this.autoCropModeToolStripMenuItem.Tag = CropContainer.CropModes.AutoCrop; + // // highlightModeButton // @@ -1126,6 +1168,7 @@ namespace Greenshot.Editor.Forms { this.highlightModeButton.Name = "highlightModeButton"; this.highlightModeButton.SelectedTag = FilterContainer.PreparedFilter.TEXT_HIGHTLIGHT; this.highlightModeButton.Tag = FilterContainer.PreparedFilter.TEXT_HIGHTLIGHT; + this.highlightModeButton.DropDownItemClicked += FilterPresetDropDownItemClicked; // // textHighlightMenuItem // @@ -1233,6 +1276,7 @@ namespace Greenshot.Editor.Forms { this.fontFamilyComboBox.Padding = new System.Windows.Forms.Padding(2,0,0,2); this.fontFamilyComboBox.GotFocus += new System.EventHandler(this.ToolBarFocusableElementGotFocus); this.fontFamilyComboBox.LostFocus += new System.EventHandler(this.ToolBarFocusableElementLostFocus); + this.fontFamilyComboBox.PropertyChanged += FontPropertyChanged; // // fontSizeLabel // @@ -1873,6 +1917,11 @@ namespace Greenshot.Editor.Forms { private BindableToolStripButton btnConfirm; private GreenshotToolStripMenuItem selectAllToolStripMenuItem; private BindableToolStripDropDownButton highlightModeButton; + private BindableToolStripDropDownButton cropModeButton; + private GreenshotToolStripMenuItem defaultCropModeToolStripMenuItem; + private GreenshotToolStripMenuItem verticalCropModeToolStripMenuItem; + private GreenshotToolStripMenuItem horizontalCropModeToolStripMenuItem; + private GreenshotToolStripMenuItem autoCropModeToolStripMenuItem; private GreenshotToolStripMenuItem pixelizeToolStripMenuItem; private GreenshotToolStripMenuItem blurToolStripMenuItem; private BindableToolStripDropDownButton obfuscateModeButton; diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index 8ab283d0b..98a12a204 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -25,6 +25,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; +using System.Linq; using System.Threading; using System.Windows.Forms; using Greenshot.Base; @@ -181,6 +182,9 @@ namespace Greenshot.Editor.Forms UpdateUi(); + // Workaround: for the MouseWheel event which doesn't get to the panel + MouseWheel += PanelMouseWheel; + // Use best fit, for those capture modes where we can get huge images bool useBestFit = _surface.CaptureDetails.CaptureMode switch { @@ -280,11 +284,6 @@ namespace Greenshot.Editor.Forms // a smaller size than the initial panel size (as set by the forms designer) panel1.Height = 10; - fontFamilyComboBox.PropertyChanged += FontPropertyChanged; - - obfuscateModeButton.DropDownItemClicked += FilterPresetDropDownItemClicked; - highlightModeButton.DropDownItemClicked += FilterPresetDropDownItemClicked; - _toolbarButtons = new[] { btnCursor, btnRect, btnEllipse, btnText, btnLine, btnArrow, btnFreehand, btnHighlight, btnObfuscate, btnCrop, btnStepLabel, btnSpeechBubble @@ -293,9 +292,6 @@ namespace Greenshot.Editor.Forms pluginToolStripMenuItem.Visible = pluginToolStripMenuItem.DropDownItems.Count > 0; - // Workaround: for the MouseWheel event which doesn't get to the panel - MouseWheel += PanelMouseWheel; - // Make sure the value is set correctly when starting if (Surface != null) { @@ -727,7 +723,10 @@ namespace Greenshot.Editor.Forms private void BtnCropClick(object sender, EventArgs e) { + if (_surface.DrawingMode == DrawingModes.Crop) return; + _surface.DrawingMode = DrawingModes.Crop; + InitCropMode((CropContainer.CropModes)_surface.FieldAggregator.GetField(FieldType.CROPMODE).Value); RefreshFieldControls(); } @@ -1292,6 +1291,7 @@ namespace Greenshot.Editor.Forms new BidirectionalBinding(previewQualityUpDown, "Value", _surface.FieldAggregator.GetField(FieldType.PREVIEW_QUALITY), "Value", DecimalDoublePercentageConverter.GetInstance(), NotNullValidator.GetInstance()); new BidirectionalBinding(obfuscateModeButton, "SelectedTag", _surface.FieldAggregator.GetField(FieldType.PREPARED_FILTER_OBFUSCATE), "Value"); + new BidirectionalBinding(cropModeButton, "SelectedTag", _surface.FieldAggregator.GetField(FieldType.CROPMODE), "Value"); new BidirectionalBinding(highlightModeButton, "SelectedTag", _surface.FieldAggregator.GetField(FieldType.PREPARED_FILTER_HIGHLIGHT), "Value"); new BidirectionalBinding(counterUpDown, "Value", _surface, "CounterStart", DecimalIntConverter.GetInstance(), NotNullValidator.GetInstance()); } @@ -1321,12 +1321,13 @@ namespace Greenshot.Editor.Forms textHorizontalAlignmentButton.Visible = props.HasFieldValue(FieldType.TEXT_HORIZONTAL_ALIGNMENT); textVerticalAlignmentButton.Visible = props.HasFieldValue(FieldType.TEXT_VERTICAL_ALIGNMENT); shadowButton.Visible = props.HasFieldValue(FieldType.SHADOW); - counterLabel.Visible = counterUpDown.Visible = props.HasFieldValue(FieldType.FLAGS) - && ((FieldFlag) props.GetFieldValue(FieldType.FLAGS) & FieldFlag.COUNTER) == FieldFlag.COUNTER; - btnConfirm.Visible = btnCancel.Visible = props.HasFieldValue(FieldType.FLAGS) - && ((FieldFlag) props.GetFieldValue(FieldType.FLAGS) & FieldFlag.CONFIRMABLE) == FieldFlag.CONFIRMABLE; + counterLabel.Visible = counterUpDown.Visible = props.HasFieldValue(FieldType.FLAGS) && ((FieldFlag)props.GetFieldValue(FieldType.FLAGS)).HasFlag(FieldFlag.COUNTER); + + btnConfirm.Visible = btnCancel.Visible = props.HasFieldValue(FieldType.FLAGS) && ((FieldFlag) props.GetFieldValue(FieldType.FLAGS)).HasFlag(FieldFlag.CONFIRMABLE); + btnConfirm.Enabled = _surface.HasSelectedElements; obfuscateModeButton.Visible = props.HasFieldValue(FieldType.PREPARED_FILTER_OBFUSCATE); + cropModeButton.Visible = props.HasFieldValue(FieldType.CROPMODE); highlightModeButton.Visible = props.HasFieldValue(FieldType.PREPARED_FILTER_HIGHLIGHT); } else @@ -1582,6 +1583,39 @@ namespace Greenshot.Editor.Forms Invalidate(true); } + protected void CropStyleDropDownItemClicked(object sender, ToolStripItemClickedEventArgs e) + { + InitCropMode((CropContainer.CropModes)e.ClickedItem.Tag); + + RefreshFieldControls(); + Invalidate(true); + } + + private void InitCropMode(CropContainer.CropModes mode) + { + var cropArea = _surface.Elements.FirstOrDefault(c => c is CropContainer)?.Bounds; + + _surface.DrawingMode = DrawingModes.None; + _surface.RemoveCropContainer(); + + if (mode == CropContainer.CropModes.AutoCrop) + { + if (!_surface.AutoCrop(cropArea)) + { + //not AutoCrop possible automatic switch to default crop mode + _surface.DrawingMode = DrawingModes.Crop; + _surface.FieldAggregator.GetField(FieldType.CROPMODE).Value = CropContainer.CropModes.Default; + this.cropModeButton.SelectedTag = CropContainer.CropModes.Default; + this.statusLabel.Text = Language.GetString(LangKey.editor_autocrop_not_possible); + } + } + else + { + _surface.DrawingMode = DrawingModes.Crop; + } + RefreshEditorControls(); + } + private void SelectAllToolStripMenuItemClick(object sender, EventArgs e) { _surface.SelectAllElements(); @@ -1590,14 +1624,14 @@ namespace Greenshot.Editor.Forms private void BtnConfirmClick(object sender, EventArgs e) { - _surface.ConfirmSelectedConfirmableElements(true); - RefreshFieldControls(); + _surface.Confirm(true); + RefreshEditorControls(); } private void BtnCancelClick(object sender, EventArgs e) { - _surface.ConfirmSelectedConfirmableElements(false); - RefreshFieldControls(); + _surface.Confirm(false); + RefreshEditorControls(); } private void Insert_window_toolstripmenuitemMouseEnter(object sender, EventArgs e) @@ -1643,14 +1677,6 @@ namespace Greenshot.Editor.Forms } } - private void AutoCropToolStripMenuItemClick(object sender, EventArgs e) - { - if (_surface.AutoCrop()) - { - RefreshFieldControls(); - } - } - private void AddBorderToolStripMenuItemClick(object sender, EventArgs e) { _surface.ApplyBitmapEffect(new BorderEffect()); @@ -1681,7 +1707,7 @@ namespace Greenshot.Editor.Forms cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, coreConfiguration.AutoCropDifference); } - if (_surface.IsCropPossible(ref cropRectangle)) + if (_surface.IsCropPossible(ref cropRectangle, CropContainer.CropModes.AutoCrop)) { _surface.ApplyCrop(cropRectangle); UpdateUndoRedoSurfaceDependencies(); diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.resx b/src/Greenshot.Editor/Forms/ImageEditorForm.resx index 57fe2f2c7..1c5b104fd 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.resx +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.resx @@ -1107,4 +1107,13 @@ 782, 17 + + ..\Resources\AutoCrop.Image.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\CropHorizontal.Image.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\CropVertical.Image.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/src/Greenshot.Editor/Memento/AddElementMemento.cs b/src/Greenshot.Editor/Memento/AddElementMemento.cs index 1a95d19ce..b76858780 100644 --- a/src/Greenshot.Editor/Memento/AddElementMemento.cs +++ b/src/Greenshot.Editor/Memento/AddElementMemento.cs @@ -44,7 +44,7 @@ namespace Greenshot.Editor.Memento GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { //if (disposing) { } _drawableContainer = null; diff --git a/src/Greenshot.Editor/Memento/AddElementsMemento.cs b/src/Greenshot.Editor/Memento/AddElementsMemento.cs index 8649dec9b..0b11fac15 100644 --- a/src/Greenshot.Editor/Memento/AddElementsMemento.cs +++ b/src/Greenshot.Editor/Memento/AddElementsMemento.cs @@ -43,7 +43,7 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { diff --git a/src/Greenshot.Editor/Memento/ChangeFieldHolderMemento.cs b/src/Greenshot.Editor/Memento/ChangeFieldHolderMemento.cs index 1ffa8c16e..70dba9252 100644 --- a/src/Greenshot.Editor/Memento/ChangeFieldHolderMemento.cs +++ b/src/Greenshot.Editor/Memento/ChangeFieldHolderMemento.cs @@ -44,7 +44,7 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { diff --git a/src/Greenshot.Editor/Memento/DeleteElementMemento.cs b/src/Greenshot.Editor/Memento/DeleteElementMemento.cs index 0acc19f83..1d744239d 100644 --- a/src/Greenshot.Editor/Memento/DeleteElementMemento.cs +++ b/src/Greenshot.Editor/Memento/DeleteElementMemento.cs @@ -45,7 +45,7 @@ namespace Greenshot.Editor.Memento GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!disposing) return; diff --git a/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs b/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs index e4b0b747e..509bbb016 100644 --- a/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs +++ b/src/Greenshot.Editor/Memento/DeleteElementsMemento.cs @@ -43,7 +43,7 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { diff --git a/src/Greenshot.Editor/Memento/DrawableContainerBoundsChangeMemento.cs b/src/Greenshot.Editor/Memento/DrawableContainerBoundsChangeMemento.cs index 428b0ff3d..b5b97e4cf 100644 --- a/src/Greenshot.Editor/Memento/DrawableContainerBoundsChangeMemento.cs +++ b/src/Greenshot.Editor/Memento/DrawableContainerBoundsChangeMemento.cs @@ -34,30 +34,30 @@ namespace Greenshot.Editor.Memento { private readonly List _points = new(); private readonly List _sizes = new(); - private IDrawableContainerList _listOfdrawableContainer; + private IDrawableContainerList _listOfDrawableContainer; private void StoreBounds() { - foreach (IDrawableContainer drawableContainer in _listOfdrawableContainer) + foreach (IDrawableContainer drawableContainer in _listOfDrawableContainer) { _points.Add(drawableContainer.Location); _sizes.Add(drawableContainer.Size); } } - public DrawableContainerBoundsChangeMemento(IDrawableContainerList listOfdrawableContainer) + public DrawableContainerBoundsChangeMemento(IDrawableContainerList listOfDrawableContainer) { - _listOfdrawableContainer = listOfdrawableContainer; + _listOfDrawableContainer = listOfDrawableContainer; StoreBounds(); } public DrawableContainerBoundsChangeMemento(IDrawableContainer drawableContainer) { - _listOfdrawableContainer = new DrawableContainerList + _listOfDrawableContainer = new DrawableContainerList { drawableContainer }; - _listOfdrawableContainer.Parent = drawableContainer.Parent; + _listOfDrawableContainer.Parent = drawableContainer.Parent; StoreBounds(); } @@ -66,21 +66,21 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { - _listOfdrawableContainer?.Dispose(); + _listOfDrawableContainer?.Dispose(); } - _listOfdrawableContainer = null; + _listOfDrawableContainer = null; } public bool Merge(IMemento otherMemento) { if (otherMemento is not DrawableContainerBoundsChangeMemento other) return false; - if (ObjectExtensions.CompareLists(_listOfdrawableContainer, other._listOfdrawableContainer)) + if (ObjectExtensions.CompareLists(_listOfDrawableContainer, other._listOfDrawableContainer)) { // Lists are equal, as we have the state already we can ignore the new memento return true; @@ -91,10 +91,10 @@ namespace Greenshot.Editor.Memento public IMemento Restore() { - var oldState = new DrawableContainerBoundsChangeMemento(_listOfdrawableContainer); - for (int index = 0; index < _listOfdrawableContainer.Count; index++) + var oldState = new DrawableContainerBoundsChangeMemento(_listOfDrawableContainer); + for (int index = 0; index < _listOfDrawableContainer.Count; index++) { - IDrawableContainer drawableContainer = _listOfdrawableContainer[index]; + IDrawableContainer drawableContainer = _listOfDrawableContainer[index]; // Before drawableContainer.Invalidate(); drawableContainer.Left = _points[index].X; diff --git a/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs b/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs index c6ba814c3..8c49614b4 100644 --- a/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs +++ b/src/Greenshot.Editor/Memento/SurfaceBackgroundChangeMemento.cs @@ -52,7 +52,7 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!disposing) return; diff --git a/src/Greenshot.Editor/Memento/TextChangeMemento.cs b/src/Greenshot.Editor/Memento/TextChangeMemento.cs index 411dde53c..46f33592b 100644 --- a/src/Greenshot.Editor/Memento/TextChangeMemento.cs +++ b/src/Greenshot.Editor/Memento/TextChangeMemento.cs @@ -43,7 +43,7 @@ namespace Greenshot.Editor.Memento Dispose(true); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { diff --git a/src/Greenshot.Editor/Resources/AutoCrop.Image.png b/src/Greenshot.Editor/Resources/AutoCrop.Image.png new file mode 100644 index 0000000000000000000000000000000000000000..1f9d86c4d8711de86e90e08b6e20e3dbba7c8908 GIT binary patch literal 3164 zcmV-i45RajP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1bvk}M|-{O1%t0*F<|VG$9&fsgM5M0L;R=jZU$ zbW`jiGbPbR{`zy8Kk!E(6cb`DiBq!p3mlj#UWz?`yuY0d`&%pazIbjvc<1f@E@zBiAM$mV6`z7}&L_M_@67JFC<2fV$9n*@?*M%O z`M#OY=s$0tz^AJ1{u7o-F~ZBY9WH(k{)YH%WB*u0A3I`w82$qCoTJPs=X5nBAevNB z)?9Sf91LuL-0x`#PsS(WJ@1F{6kBZv<->N{@N~zHz{)f(xZ$dsPIlQ{hlzoNGD@OO zezz5$iK+X=Q&^9ils)_53;63K#(Ol=V~gAS^4_nzf}MxMP;ywzZTf$B%s+Mh&SU26 z3nFLBgB9$eB~h5Mm|Nc%1w!0Z-r@%MK1#oR(+{Ky2IGdg;DFV(vqX#Tr7gdC_81pY z9v5;Z4_yEdVebfIoCgDNARpcGBBJaZa4aCG!gBI~8W?af(twc^yia5@!DX;F=47|W zQlvzy8Lk;=mPXCD&|*t1x6-)P4*B%ZV^2Nz z(z(|`!w-askwzY6@TlU9AW}$>C`qyuVW|^Zn|_8FXPSAI$+JGJDXU+e-(bxtYqXhK zH9Lt84dfVwm9mTrdI4;4#u)5FQm z_~az)eazd0UzJWI9*er?39Yqs))#SNK=rue;#A8KrTcU>YZY$;u$);T@bv!8qG*5D zqBqO(yJfr8M8My6Gj26<+RPvCDCCq4#|$w88MCTn9!4sgTy6;mm26@4SqD8mF={!q@UhmXRt=* z>6D3EM?Gj0l}S2EmLj{a=~QtJKg3t-w2Ha&9xHMg=OLYJDv5y)t9e zI^0ug$!ATVnYwOVBp+N7k!eR-joAsu*CBf5tJ}Da*VQWohiyFWi7ZQmK+_WBRwxEX zxRIW0@Nyx(*sd=m-=+rS{?gy2_RIBk?GDMBhh!oF#)z(Rl_uXR9Cw08k`8XRJJ8 ze7N$Poo^2Cgc0{ReNWI~$;~NXZE+co2^O0?fiW{^$*kI0q07`BrqY}%KQS(h+nDlw z8y9!@P@{AQ11R{mSqJRJkA!riytf5g_>9woS4tPoFl+OpY>Q2uF#zg*dT|S#nmpRX z1qwl0vW6J02(W%ox-0t20L|gdIm)`c?$aXIGT{(6TqDGfWKYmos$%!@lnPH)S&eFt zi^7c~pUX!-3r%Ds>FPpoVK}2dkfnl9;f?NqFbw8%ZBacTWOq@ftJ6Ln#g=(Zam%=o zHH=8?$l$oKTw9plTn0zD^BBCR?@nOO5iUe-1+SM3hg%C-U8PdCPryud!5PlHMBX%Y z7AZxDG?}mX)4w7%bvs_Vm9_FEdhAOCR^cF)ZpvsKp~gO={M8M;yWtGig4Abq-W1IT z1KEZAut$_5bgZB&ub(}msjnh^3G}4lEPDLvYU|Z3kB-ka?us!Y!L2|bH*T|+9@^tL z7dOWvNO_bK`n+bglR)VP)S2WAaHVT zW@&6?004NLeUUv#!$2IxUsFYqN{4n3=@6tkSr8R*lqwd%LTM|s>R@u|7c^-|Qd}Gb z*Mfr|i&X~~XI&j!1wrrw#L>w~(M3x9Us7lhs^dzd7t}p3@Qba0X~st?f%Ws@Z4huXpY-H2(#9?Bw)Wvcav$CNQPZLKKRik_%=d!|i zi?dp-v-Umt3j+mhCBt=^5hSpLBvKF|qmBxyun?nFBgI6T_TwJ@VaJ~$mrSk-7&#VD zg9^#K-LC&sz}00Rt3L_t(I%Y~C|Xj@enfS=nN(h<_c zvaC{MqtwPyY|zSdjW}G_;pWU@ozvQYkxs;kV{D@6^hfa<{9tYrSLcr?ncZ5~&2}B5 zr9sEgb|8(A+OT$=`)r$dTiQAka_>F&_`_yp;PCnL!uy`{obw*uqp--2+ig1(Dene| zdQ%U+T_y%J=U(AtPja8+>ThY`nfpYF7=UbTco)o>Ln2V1GF-CyQ(xXXaebAM$Szno^nrd@pcw9gK-02Ek~0-@^&A&^3F zZSpsMPZd(?zK8iK4I`5wnMjfxyUM+rb}@AHJt~Xm{^*VHFo5lyY+sH1KvE}HreCSK zR5E9z@ZXsre7GKf?7}s!B!;;%(#h#BcT@X76;%CQgvy7#5suz`jP54&(86G=9E^lz zb+B75raJ){4u|D3k6&Jm?UVCAACSjGwnM!U+5igj0uxlrG%3HUid@bBps=v;nNTQ1 zG#aJ4%s`*l5T=P;ks{E{j#~u6LbZfoM$?#^j^lE zJ;!K!JwQX9g{Jl6@pz~|_z0=%*C}$jXkI;1yl+E-ldXGa@+|~UjLI7S`X@Nu{XL)T z4D#5TN-~)Y4u^wGCWGDXWVy$KB?LL$z|eIT42o<(5IEr57+Q9&r`>q2Qn@%e)HVCv z(5*9XFMZyhPNi@SFv)*1tIYQ{6 zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1bxmMkX@{AU%j1SDQ!IXusq9eDW@fXJ?@d)sc0 zU3oGgfs}+o3Q=bK@!x6wgCBGB#)l*^$7u2M*=H{3h&{i&pJe@h>WjUdw{i1KFoqmj zcV1J`^#$YM>w~L<>if76oncWySF#FpOEaU>UyZ~#pKwr)2QV&q%n1>^0_fyUqw{CW2w*|Lg9l3-)IW~LZS^|f>ZSQfQeRa^A zlW)&_djIKtIG>A-yANMR^$|M1ouKf0=WiFkD0YuU{610Ck#F14d(JL%j4 zqO7^zS>Iq`h0ERkEaFPI1Nv!S8JE~%8zAqt*@~-CCI%|gkf%D$1jBZ-V1vchBccZSiY>Qsc32nC zo)jXJx(a}cpgX`AazFqH(K5xCuZ67m-f_gbKj&J|KRQ7sOBrF8B~a3@L~SIh5$4k0HjG;v%_{T=FTTm{O9I zQxPX#f<#FolBHzM4jdSA%qdIGxfC`9iV9>EtS=a;TwV1w)L2uMnrmqYpXOU=v85(0 zx6--04w~q(r!GDBGRO=t#qcAHIMR@jN12GV>877y#+jzfJj;WcqWa7AH&7!*jW<$j zU3yT%s7dLHphYKPVFtw56A(`e0R%KJ%&d_2ypUU%+000az%Vi_Y)q$x7$Ee6I81u5 z`$FzVxS1e7!j1n5IkTYqH;^-c?pNG?gIZs8u5H9l7A~J!hwQ`rkYZTMDr)7Qwnxwm zd5v%#O(y#;=WSAiWyrYw?wxk9-Zou7EKIg|F}SVWqyMaZ6Xbe4#?A`*%x(y&X&~59 zT2_mEk`f4}hCzA2tCYQ21F1KVc3V?EtaAR|0?YH+bT)MYQSY}5^v0GfARIIIYA<$f zhz7!R+h(C;(c4nVxX%Z}L1_5!jLYir zj^lwCwXU`3)i^40ty??UA|3U!&)Z?j;jVh}A!@A(rS@jVX_}Bm+1r^H~?TRBS-R;>7>QYrU)+4+57*$K_Cy|7G%U9g0 z>1)=s^*dsyz%8ev z(2_34nWw0;*^KL*r~z%OQ*U!r`>CB(p@UzCQ==O^iX>5|n$%jJKBm%6>~)_UvBsfI zGER4v@|un*S4}^Hons05NYAG8p!dwFs`LpMW+=*9IopNkSNh9EjTR65hz6nxc8uit zikaG#Mm)9l^IiOQ6GnIOj92@*o0hWfZpCfO-zAmhf0W^?4UJjF;2|a?k5|=yLTuK3<{aB^>EVIj zEc(KR{+5+yX?R54t+wVncwA^z85W{-4!N{rm< zWF+1?^}zw-ha8am&PKB&^r-|0_tVgHNux+=iALhEGZVpm-jaUMZ1yQt?hq+F2q^PlEX>4Tx0C=2zkv&MmKpe$iQ$>+VhjtL@5TrU;5EXHhDi*;)X)CnqU~=gf zG-*guTpR`0f`cE6RR0!X5l%$?&0I>U5saWpZjwRDg~1PK9P8i>4rtT zK|Hf*>74h8!>lYR#OK8023?T&k?XR{Z=6dG3p_JyWYhD+VPdh=#c~(3vY`@B6Gs(Q zqkJLfvch?bvs$gQ_C5Iv0|jj*!*!YwB(Q`eQV=1djtZ)<5TjKi#YCF+;~xHD$DbmX zOs)zTITlcZ3d!+<|H1EW&EnLgn-quxy)U-?F$(nU0jdyW16NwdUuy!h zpQJZBTJ#7AZUYzB9ZlW?E_Z;TCtWfmNAlAYibdf4jJ_!kgl>U>HMh6+K29HiEOoVf z0~{OzVsH|aP00006VoOIv00000008+zyMF)x010qN zS#tmY4#EHc4#EKyC`y0;000McNliru<^miL3q_ZDu~tG$Y)sQ?ku?31naqrf(wA;};c^dmap0bFu3&|=@6;=KGu9qR0a6GKKd1p9 zS4t2P28S-)C)4!^5rzwUF%NDX6~t{wTA(y&30g{&gr4A~dVh61P>~3)@81diN*Sw^ zMGAp<)2Xiwj`9D-jG>Uv zQ#FP{E{AIj`O#54V;Ik7@jY)*gM;VB`s2au{&XGoA1}hE(XRwSl`!;CN?_X-v6%DG zahyGgL;}Z&6N@=mk;vO`!{s>PYXg1*!L*>T~)peXm-M z!@#}HC{WEj^lQsp=*|cL+0l6+=y=iwV2$)1^OleR)IUA_t~B=SW-as3Up&FmHeRiI z$aTxi^$e~%yX=%yY7@3yH?zG?id@->E8nlqqCV*BYHRPxCuKooVJkKMMNKi3`Rmmh(V@Rb^ zxW-VwW(}?}G&DB;m(XQF+K}EN949(1grMv?vvx4G%by+_RuW$-d>!HoMIZ&ie2~O^ zgg2zO@MSm~ZEbD!T8^BsTkr1n?yf%JDG5@64nZjR_nBDg!mBF>nCk0cd;5!({up{5 oCZP+JMXUl1z~`D2ta-v9sr07*qoM6N<$f(zO)tN;K2 literal 0 HcmV?d00001 diff --git a/src/Greenshot.Editor/Resources/CropVertical.Image.png b/src/Greenshot.Editor/Resources/CropVertical.Image.png new file mode 100644 index 0000000000000000000000000000000000000000..fe1dea06e4bc9c0700b7e8cf4e34d8fc41f176b2 GIT binary patch literal 3176 zcmV-u443nXP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1bx~a7#}cE(pD(^}#Y49HuU!Ah`s=^G*z@pV+}sn4A&0x$ zuc_+#it+GlI5Mbx95-2KIO{>@WIfO=$&82oRubd9$I0tKW$cGoa(b)Uc;7`AUaIIX zl1+Np-ivqh9`Fe$^#DPRc{pUsbmg6sfg;P9RhKrYaVBIZN{95V>2(43v;1_meu?og7wbCFGAgbZY3Poirr z2addkk()q7a1rs8!B7QR-Us+k@)*DOmQW-nq2ZJq?l65 zsic}+_BrI3Q_i{MTDUmmz))gIC6`iaWm6%j;;f4G6(fzCYrcgRTWYzLRt4@OUV=nP zlBG!P++9bS=&`4sd+BwM8ORjFk1*m$Babrbgs)9E{R}hCH1jO8-mEFBU#>r3jg&RM zm|E-7%^F5cO6Le#=_D-9z!-Z1<7qJfhvvnZ&E!2V<`!p&ZUjYOC>a(vrqf~!6#79N zCf(dU%>5Q`Cgk7ZjsJ@|v#9$&m@}a6D{tSh)>oaAi?JPr3sdV5eV8A)8qReUwR+tr zO2T?>gJdGFTrc^{opT@`D9qN%ER6<$Fl#7@r6GIPugBuA;XVt>5!74bkPOSUI_4FKD^wM~LEnxTC|JT*c~$ zZ$;0w1D<$mX||fF@SYY%hvoM!1XHSGn>Mf|!MV1W+(3h(-4`RohL1U6nd49-_dK|y zJe?d4$&Hw2X!^dQp*&pEGy>Y*DA{FiLYwu$ zzEl@^hjmM@85KVA<8IBmaLdk9F*I&P z*|_$g*8ml&d7=k0Z^}e7R@*+N6+s@~!0-bYY();eGZ9)W1=1mn=IM7D!Mo(ie#Wy6{l;k0ce2bd z(5rz3BE@Zw^+4Sp27(*L=g%qc7QB}&!JtQ+YSaaCLsU8h&M$szR0!_SZy!P)Kw>zM zkwA$%U{T`~$rYWc6CEywd68i;tLP0+qpEwMUZOQsjM28DfzpHDce7K&kwg_ve*34) zs8yv$Bvfun9#Up_(|`n>%p3n39e-%)pa@{SV_xhlBlmdx*ffu}>{8oNgAMIvga6Kk zZ34edSZ-nz1W|@7(9UsN>XGoWdKl8!Wjv;|qFhE_9Gkdkjw%E1}Mp+vB+Feh0V zUQR!XFNKkwq(1SHgXl+Jde%ci9nY~U9NyEs0x0qW{N_s$e2U@FM2(1>@k??GYST=~ zO&5)msQO$@@2me+D^cep@<~+L)2#k;B_IB*g4M;fWqgXwXvn)nha=3i&G+wVxc z9UuSz0fcEoLr_UWLm+T+Z)Rz1WdHzpoPCi!NW(xJ#a~lJkxGYl5a|%4I$01Eag-_+ z!9r;(wCZ4T=@&F?0bcP2!a?vNMfd*%q(W%Ilk`UGi+qj^Tc6dvDC$K z7qhaV5>FFH6;-2rA?LEfd5g1Jt+Vz$`3nODZ6(8Xnh_+hgd|cBA)}58s<05FRU^ej zn)c%!{$a& z@IM1rTE|~&0<)i_H#%DM2ncQi7uOw4-UBXofT1T{G9*Xx(-ewD;QfrgDG!8hfq^x* zxAs0xAAl@%wR{5{90Fq{%3k+)cYk+p|DI|0_XC7ba;~VXVPXIP00v@9M??Ss00000 z`9r&Z00009a7bBm000ic000ic0Tn1pfB*mh2XskIMF-{r91sf+1FMcw0008hNklF8l);B&Mc_1nEYE z;yNG|A#MuAEEH-+x)?B^m12?BgvM!NCX8t^&Ac=3+cp+Da}xmL@2%%Q^G@emzVi$EFwSooVlA%YY@L1g$}GThh4k93rmq9@ z^4WK;3yu!YBYxO?|VL==N&JV>F*nA78+Te z@;Set0dU1y#%HeK9ZRF4;S;9OU}JTaS}g`h<=(jD52aOA#W5<55qpr+k}DQWqrod5 zeB^k?(vL)h-fWgQu5#|;LjBEe$D{juVz;-p5D~07$TPs|el zMxeg?_ifRduH(l^5_K5lI3E8Lix{o(x^riYJOQ9Znsmdzbh3PxNC`-z*);}6S zgBE--hTWYVTsH-fy8iZ$gkgrB-d@BQthLCs3_=!Kt#wy5idUT zJeS9=K7D=R>Q*@LA={-AnM{T_t`FY*?QQ^=ifS97ng9@45k!Qppn+2201}32ve_(3 zDIONr>xDuA&ud%a>`hBG;hyorN|@=Y6!%EJzxGu$m$w9d>gT$3E5=V%stNZV z7T1`|TV`+CqYeN@b6)xWcb|L-P<7v$n9JKg0hCVotNA~g^C+wz9m0PLVr>gJjf@@u O0000انسخ المسار الي الذاكرة نسخ قص (C) + قص اداة التحديد (ESC) قص احذف diff --git a/src/Greenshot/Languages/language-ca-CA.xml b/src/Greenshot/Languages/language-ca-CA.xml index 9f92f7446..423c55006 100644 --- a/src/Greenshot/Languages/language-ca-CA.xml +++ b/src/Greenshot/Languages/language-ca-CA.xml @@ -92,6 +92,8 @@ Abans de crear un nou informe d'error, us agrairem que comproveu que l'error no Copia el camí al porta-retalls Copia Retalla(C) + Retalla + Autorretalla Eina de selecció (ESC) Retalla Esborra diff --git a/src/Greenshot/Languages/language-cs-CZ.xml b/src/Greenshot/Languages/language-cs-CZ.xml index 915fd3fe0..86d7f2207 100644 --- a/src/Greenshot/Languages/language-cs-CZ.xml +++ b/src/Greenshot/Languages/language-cs-CZ.xml @@ -93,6 +93,8 @@ Také bychom velmi ocenili, kdybyste zkontrolovali, zda tato chyba již není ev Kopírovat cestu do schránky Kopírovat Oříznout (C) + Oříznout + Automatické oříznutí Výběr objektů (ESC) Vystřihnout Odstranit diff --git a/src/Greenshot/Languages/language-da-DK.xml b/src/Greenshot/Languages/language-da-DK.xml index 166774d34..b032e8aff 100644 --- a/src/Greenshot/Languages/language-da-DK.xml +++ b/src/Greenshot/Languages/language-da-DK.xml @@ -469,6 +469,9 @@ tidspunktet, fx 11_58_32 (plus filendelsen angivet i indstillingerne). Beskær (C) + + Beskær + Åbn billede fra udklipsholder diff --git a/src/Greenshot/Languages/language-de-DE.xml b/src/Greenshot/Languages/language-de-DE.xml index 062cdd6a5..a50ad0119 100644 --- a/src/Greenshot/Languages/language-de-DE.xml +++ b/src/Greenshot/Languages/language-de-DE.xml @@ -77,6 +77,7 @@ schnell zu finden. Vielen Dank :) Keine Anfangspunkt Automatisch zuschneiden + Automatisches Zuschneiden nicht möglich Hintergrundfarbe (0-9) Weichzeichner-Radius Fett @@ -92,6 +93,11 @@ schnell zu finden. Vielen Dank :) Pfad in Zwischenablage kopieren Kopieren Zuschneiden (C) + Zuschneiden - Modus + Zuschneiden + Vertikal ausschneiden + Horizontal ausschneiden + Automatisch zuschneiden Auswahlwerkzeug (Esc) Ausschneiden Gewähltes Element löschen diff --git a/src/Greenshot/Languages/language-de-x-franconia.xml b/src/Greenshot/Languages/language-de-x-franconia.xml index b989bcfe7..34da6f0b7 100644 --- a/src/Greenshot/Languages/language-de-x-franconia.xml +++ b/src/Greenshot/Languages/language-de-x-franconia.xml @@ -88,6 +88,8 @@ Dangschee, wassd scho :) Bfad in däi Zwischnblach nei Kobiern Zamschneidn (C) + Zamschneidn + Audomadisch zamschneidn Angriffln (ESC) Ausschneidn Wech mid dem Ding! diff --git a/src/Greenshot/Languages/language-el-GR.xml b/src/Greenshot/Languages/language-el-GR.xml index 14cb68bef..1feb74b51 100644 --- a/src/Greenshot/Languages/language-el-GR.xml +++ b/src/Greenshot/Languages/language-el-GR.xml @@ -93,6 +93,8 @@ Αντιγραφή της θέσης του αρχείου στο πρόχειρο Αντιγραφή Περικοπή (C) + Περικοπή + Αυτόματη Περικοπή Εργαλείο Επιλογής (ESC) Αποκοπή Διαγραφή diff --git a/src/Greenshot/Languages/language-en-US.xml b/src/Greenshot/Languages/language-en-US.xml index b575f549b..5cac2280d 100644 --- a/src/Greenshot/Languages/language-en-US.xml +++ b/src/Greenshot/Languages/language-en-US.xml @@ -78,6 +78,7 @@ Also, we would highly appreciate if you checked whether a tracker item already e None Start point Auto crop + Auto crop not possible Fill color (0-9) Blur radius Bold @@ -93,6 +94,11 @@ Also, we would highly appreciate if you checked whether a tracker item already e Copy path to clipboard Copy Crop (C) + Crop mode + Crop + Crop out vertically + Crop out horizontally + Auto crop Selection Tool (ESC) Cut Delete diff --git a/src/Greenshot/Languages/language-es-ES.xml b/src/Greenshot/Languages/language-es-ES.xml index b84aee912..0badf64a4 100644 --- a/src/Greenshot/Languages/language-es-ES.xml +++ b/src/Greenshot/Languages/language-es-ES.xml @@ -80,6 +80,8 @@ Antes de crear un nuevo informe de error, te agradeceríamos que comprobaras que Copiar ruta al portapapeles Copiar Recortar(C) + Recortar + Autorrecortar Herramienta de selección (ESC) Cortar Borrar diff --git a/src/Greenshot/Languages/language-et-EE.xml b/src/Greenshot/Languages/language-et-EE.xml index b358977e8..7a4b0dcc3 100644 --- a/src/Greenshot/Languages/language-et-EE.xml +++ b/src/Greenshot/Languages/language-et-EE.xml @@ -92,6 +92,8 @@ Me oleksime väga tänulik, kui te enne kontrolliksite, ega sellest veast pole j Kopeerige asukoht lõikelauale Kopeeri Lõika (C) + Lõika + Automaatne lõikus Valiku tööriist (ESC) Lõika Kustuta diff --git a/src/Greenshot/Languages/language-fa-IR.xml b/src/Greenshot/Languages/language-fa-IR.xml index 20e1da09f..2ab2c8242 100644 --- a/src/Greenshot/Languages/language-fa-IR.xml +++ b/src/Greenshot/Languages/language-fa-IR.xml @@ -67,6 +67,7 @@ Could not save Greenshot's configuration file. Please check access permissions f رونویس چیدن (C دکمه) + چیدن انتخابگر (ESC دکمه) برش diff --git a/src/Greenshot/Languages/language-fi-FI.xml b/src/Greenshot/Languages/language-fi-FI.xml index f66cc5013..a2f211b03 100644 --- a/src/Greenshot/Languages/language-fi-FI.xml +++ b/src/Greenshot/Languages/language-fi-FI.xml @@ -62,6 +62,7 @@ Olisi myös hyvä jos voisit tarkistaa onko virhe jo raportoitu aikaisemmin (voi Kopioi tiedostopolku leikepöydälle Kopioi Rajaa (C) + Rajaa Valintatyökalu (ESC) Leikkaa Poista diff --git a/src/Greenshot/Languages/language-fr-FR.xml b/src/Greenshot/Languages/language-fr-FR.xml index 53f8e21f6..50cde5788 100644 --- a/src/Greenshot/Languages/language-fr-FR.xml +++ b/src/Greenshot/Languages/language-fr-FR.xml @@ -93,6 +93,8 @@ De plus, nous apprécierions beaucoup que vous preniez la peine de vérifier si Copier Ajouter un compteur Recadrer (C) + Recadrer + Cadrage automatique Outil de sélection (ESC) Couper Supprimer diff --git a/src/Greenshot/Languages/language-fr-QC.xml b/src/Greenshot/Languages/language-fr-QC.xml index 17c0e5537..cf822fa16 100644 --- a/src/Greenshot/Languages/language-fr-QC.xml +++ b/src/Greenshot/Languages/language-fr-QC.xml @@ -78,6 +78,8 @@ De plus, nous apprécierions beaucoup que vous preniez la peine de vérifier si Copier le chemin vers le presse-papier Copier Rogner (C) + Rogner + Rognage automatique Outil de sélection (ESC) Couper Supprimer diff --git a/src/Greenshot/Languages/language-he-IL.xml b/src/Greenshot/Languages/language-he-IL.xml index 4df909d37..537f77067 100644 --- a/src/Greenshot/Languages/language-he-IL.xml +++ b/src/Greenshot/Languages/language-he-IL.xml @@ -63,6 +63,7 @@ Details about the GNU General Public License: העתק נתיב אל הלוח העתקה חתוך (C) + חתוך כלי בחירה (ESC) חיתוך מחיקה diff --git a/src/Greenshot/Languages/language-hu-HU.xml b/src/Greenshot/Languages/language-hu-HU.xml index 0d5a06df9..20035f3c5 100644 --- a/src/Greenshot/Languages/language-hu-HU.xml +++ b/src/Greenshot/Languages/language-hu-HU.xml @@ -63,6 +63,7 @@ Kérjük adjon összefoglaló leírást és csatoljon minden olyan információt Másolja a vágólapra Másolás Vágás eszköz (C) + Vágás eszköz Kiválasztó eszköz (ESC) Kivágás Törlés diff --git a/src/Greenshot/Languages/language-id-ID.xml b/src/Greenshot/Languages/language-id-ID.xml index e474cae59..df31cd624 100644 --- a/src/Greenshot/Languages/language-id-ID.xml +++ b/src/Greenshot/Languages/language-id-ID.xml @@ -93,6 +93,8 @@ Juga, kami sangat terbantu apabila anda mengecek laporan lain yang sama dengan k Kopi Buat penomor Potong (C) + Potong + Auto potong Alat seleksi (ESC) Gunting Hapus diff --git a/src/Greenshot/Languages/language-it-IT.xml b/src/Greenshot/Languages/language-it-IT.xml index 53fa10837..e52ecb1e1 100644 --- a/src/Greenshot/Languages/language-it-IT.xml +++ b/src/Greenshot/Languages/language-it-IT.xml @@ -98,6 +98,8 @@ Controlla i permessi di accesso per '{0}'. Copia percorso negli appunti Copia Ritaglia (C) + Ritaglia + Ritaglia Automaticamente Strumento di selezione (ESC) Taglia Elimina diff --git a/src/Greenshot/Languages/language-ja-JP.xml b/src/Greenshot/Languages/language-ja-JP.xml index c894b9573..03638f0dc 100644 --- a/src/Greenshot/Languages/language-ja-JP.xml +++ b/src/Greenshot/Languages/language-ja-JP.xml @@ -92,6 +92,8 @@ Greenshot には一切の保障がありません。GNU General Public License コピー カウンターを挿入する (I) 切り抜き (C) + 切り抜き + 自動切り抜き 選択ツール (ESC) 切り取り 削除 diff --git a/src/Greenshot/Languages/language-kab-DZ.xml b/src/Greenshot/Languages/language-kab-DZ.xml index 31930d2db..e3366a18a 100644 --- a/src/Greenshot/Languages/language-kab-DZ.xml +++ b/src/Greenshot/Languages/language-kab-DZ.xml @@ -93,6 +93,8 @@ Rnu ɣur-s, nḥemmel aṭas ma yella tesneqdeḍ aneqqis igebren ugur-agi. (Tze Nɣel Rnu Amesmiḍan Seggem (C) + Seggem + Aseggem awurman Afecku n ufran (ESC) Gzem Kkes diff --git a/src/Greenshot/Languages/language-ko-KR.xml b/src/Greenshot/Languages/language-ko-KR.xml index a332cea33..0bf90570e 100644 --- a/src/Greenshot/Languages/language-ko-KR.xml +++ b/src/Greenshot/Languages/language-ko-KR.xml @@ -92,6 +92,8 @@ Also, we would highly appreciate if you checked whether a tracker item already e 경로를 클립보드로 복사 복사 잘라내기 (C) + 잘라내기 + 자동 잘라내기 선택도구 (ESC) 잘라내기 삭제 diff --git a/src/Greenshot/Languages/language-lt-LT.xml b/src/Greenshot/Languages/language-lt-LT.xml index e84388901..9b1089811 100644 --- a/src/Greenshot/Languages/language-lt-LT.xml +++ b/src/Greenshot/Languages/language-lt-LT.xml @@ -61,6 +61,7 @@ Dėkojame už pagalbą :) Kopijuoti pilną failo vardą Коpijuoti Iškirpti (C) + Iškirpti Objektų pasirinkimas (ESC) Apkirpti Naikinti diff --git a/src/Greenshot/Languages/language-lv-LV.xml b/src/Greenshot/Languages/language-lv-LV.xml index c74e41326..acbe9eacb 100644 --- a/src/Greenshot/Languages/language-lv-LV.xml +++ b/src/Greenshot/Languages/language-lv-LV.xml @@ -92,6 +92,8 @@ Mēs būtu Tev pateicīgi, ja Tu vispirms pārbaudītu, vai kāds cits jau nav z Ievietot ceļu starpliktuvē Kopēt Apcirst (C) + Apcirst + Automātiski apcirst Atlases rīks (ESC) Izgriezt Izdzēst diff --git a/src/Greenshot/Languages/language-nl-NL.xml b/src/Greenshot/Languages/language-nl-NL.xml index 52e12a895..65c008c01 100644 --- a/src/Greenshot/Languages/language-nl-NL.xml +++ b/src/Greenshot/Languages/language-nl-NL.xml @@ -93,6 +93,8 @@ Controleer ook even of dit probleem mogelijk al gemeld is! Gebruik de zoekfuncti Locatie naar klembord kopiëren Kopiëren Bijsnijden (C) + Bijsnijden + Automatisch bijsnijden Selectiegereedschap (ESC) Knippen Verwijderen diff --git a/src/Greenshot/Languages/language-nn-NO.xml b/src/Greenshot/Languages/language-nn-NO.xml index 003b11b9a..edd8f31e7 100644 --- a/src/Greenshot/Languages/language-nn-NO.xml +++ b/src/Greenshot/Languages/language-nn-NO.xml @@ -80,6 +80,8 @@ Me sett òg pris på om du ved hjelp av søkefunksjonen på sida kan sjekke om d Kopier filstigen til utklyppstavla Kopier Skjer bildet [C] + Skjer bildet + Auto-skjer Peikarverktøy [Esc] Klypp ut Slett diff --git a/src/Greenshot/Languages/language-pl-PL.xml b/src/Greenshot/Languages/language-pl-PL.xml index 54e2fd993..7f908dba8 100644 --- a/src/Greenshot/Languages/language-pl-PL.xml +++ b/src/Greenshot/Languages/language-pl-PL.xml @@ -93,6 +93,8 @@ Będziemy wdzięczni, jeśli najpierw sprawdzisz, czy takie zdarzenie nie zosta Kopiuj ścieżkę do schowka Kopiuj Przytnij (C) + Przytnij (C) + Przytnij automatycznie Narzędzie wyboru (ESC) Wytnij Usuń diff --git a/src/Greenshot/Languages/language-pt-BR.xml b/src/Greenshot/Languages/language-pt-BR.xml index 8bfd938ed..e53603ccc 100644 --- a/src/Greenshot/Languages/language-pt-BR.xml +++ b/src/Greenshot/Languages/language-pt-BR.xml @@ -89,6 +89,7 @@ Copiar o caminho da pasta atual do arquivo para a Área de transferência Copiar Cortar (C) + Cortar Ferramenta de Seleção (ESC) Cortar Apagar diff --git a/src/Greenshot/Languages/language-pt-PT.xml b/src/Greenshot/Languages/language-pt-PT.xml index dabc42762..53a3ea424 100644 --- a/src/Greenshot/Languages/language-pt-PT.xml +++ b/src/Greenshot/Languages/language-pt-PT.xml @@ -92,6 +92,8 @@ Também apreciaremos muito se puder verificar se não existe já um relatório d Copiar atalho para a Área de transferência Copiar Recortar (C) + Recortar + Recortar auto Ferramenta de Selecção (ESC) Cortar Eliminar diff --git a/src/Greenshot/Languages/language-ro-RO.xml b/src/Greenshot/Languages/language-ro-RO.xml index 7e67ecb52..02fe86c3f 100644 --- a/src/Greenshot/Languages/language-ro-RO.xml +++ b/src/Greenshot/Languages/language-ro-RO.xml @@ -471,6 +471,9 @@ timpul curent, ex. 11_58_32 (plus extensia fișierului definită în setări) Taie (C) + + Taie + Deschide imaginea din clipboard diff --git a/src/Greenshot/Languages/language-ru-RU.xml b/src/Greenshot/Languages/language-ru-RU.xml index 42d85df80..f9973f349 100644 --- a/src/Greenshot/Languages/language-ru-RU.xml +++ b/src/Greenshot/Languages/language-ru-RU.xml @@ -93,6 +93,8 @@ Greenshot поставляется БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. Копировать путь в буфер обмена Копировать Обрезка (C) + Обрезка + Автообрезка Инструмент «Выделение» (ESC) Вырезать Удалить diff --git a/src/Greenshot/Languages/language-sk-SK.xml b/src/Greenshot/Languages/language-sk-SK.xml index f47c2bd5b..01c68e9ed 100644 --- a/src/Greenshot/Languages/language-sk-SK.xml +++ b/src/Greenshot/Languages/language-sk-SK.xml @@ -80,6 +80,8 @@ Tiež by sme velmi ocenili, keby ste najskôr skontrolovali, či už neexistuje Kopírovať cestu do schránky Kopírovať Orezať (C) + Orezať + Automatické orezanie Nástroj pre výber (ESC) Vystrihnúť Zmazať diff --git a/src/Greenshot/Languages/language-sl-SI.xml b/src/Greenshot/Languages/language-sl-SI.xml index fd0dc2bc4..ac102397a 100644 --- a/src/Greenshot/Languages/language-sl-SI.xml +++ b/src/Greenshot/Languages/language-sl-SI.xml @@ -78,6 +78,8 @@ Pred objavo preverite tudi ali je napaka že prijavlja s strani kakšnega drugeg Kopiraj pot na odložišče Kopiraj Obreži (C) + Obreži + Samodejno obreži Orodje za izbor (ESC) Kopiraj Briši diff --git a/src/Greenshot/Languages/language-sr-RS.xml b/src/Greenshot/Languages/language-sr-RS.xml index 6b624dd9c..9c669dba8 100644 --- a/src/Greenshot/Languages/language-sr-RS.xml +++ b/src/Greenshot/Languages/language-sr-RS.xml @@ -78,6 +78,8 @@ Умножи путању Умножи Опсеци (C) + Опсеци + Аутоматско опсецање Алатка за одабир (ESC) Исеци Обриши diff --git a/src/Greenshot/Languages/language-sv-SE.xml b/src/Greenshot/Languages/language-sv-SE.xml index 3fe2df709..c67bfe8fe 100644 --- a/src/Greenshot/Languages/language-sv-SE.xml +++ b/src/Greenshot/Languages/language-sv-SE.xml @@ -93,6 +93,8 @@ Innan du skickar uppskattar vi verkligen om du kontrollerar om felet redan blivi Kopiera sökväg till urklipp Kopiera Beskär (C) + Beskär + Autobeskärning Markeringsverktyg (ESC) Klipp ut Radera diff --git a/src/Greenshot/Languages/language-tr-TR.xml b/src/Greenshot/Languages/language-tr-TR.xml index b5a43f083..56011063c 100644 --- a/src/Greenshot/Languages/language-tr-TR.xml +++ b/src/Greenshot/Languages/language-tr-TR.xml @@ -78,6 +78,8 @@ Ayrıca bu hata için bir izleyici kaydının açılmış olup olmadığını da Yolu panoya kopyala Kopyala Kırp (C) + Kırp + Otomatik kırpma Seçim Aracı (ESC) Kes Sil diff --git a/src/Greenshot/Languages/language-uk-UA.xml b/src/Greenshot/Languages/language-uk-UA.xml index 850a5ea7f..1eae26c97 100644 --- a/src/Greenshot/Languages/language-uk-UA.xml +++ b/src/Greenshot/Languages/language-uk-UA.xml @@ -92,6 +92,8 @@ Greenshot постачається АБСОЛЮТНО БЕЗ ГАРАНТІЇ. Копіювати шлях у буфер обміну Копіювати Обрізати (С) + Обрізати + Автоматичне обрізання Інструмент вибору (Esc) Вирізати Видалити diff --git a/src/Greenshot/Languages/language-vi-VN.xml b/src/Greenshot/Languages/language-vi-VN.xml index a4b1a73c2..6ddfc7f9d 100644 --- a/src/Greenshot/Languages/language-vi-VN.xml +++ b/src/Greenshot/Languages/language-vi-VN.xml @@ -58,6 +58,7 @@ Chép đuờng dẫn tới clipboard. Chép Cắt (C) + Cắt Công cụ chọn (ESC) Cắt Xóa diff --git a/src/Greenshot/Languages/language-zh-CN.xml b/src/Greenshot/Languages/language-zh-CN.xml index 7325fff33..e69489c8c 100644 --- a/src/Greenshot/Languages/language-zh-CN.xml +++ b/src/Greenshot/Languages/language-zh-CN.xml @@ -84,6 +84,8 @@ 复制路径到剪贴板 复制 裁剪 (C) + 裁剪 + 自动裁剪 选择工具 (ESC) 剪切 刪除物件 diff --git a/src/Greenshot/Languages/language-zh-TW.xml b/src/Greenshot/Languages/language-zh-TW.xml index da3881d2c..69f5e6696 100644 --- a/src/Greenshot/Languages/language-zh-TW.xml +++ b/src/Greenshot/Languages/language-zh-TW.xml @@ -93,6 +93,8 @@ Greenshot 不對這個程式做任何擔保。這個程式是自由軟體,您 複製路徑到剪貼簿 複製 裁剪 (C) + 裁剪 + 自動裁剪 選取工具 (ESC) 剪下 刪除 From 5bc52e4d55b44e1c46264d284f88658f45b06bf0 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 23 Mar 2022 09:45:28 +0100 Subject: [PATCH 177/232] Validate the FreehandSensitivity as was reported in BUG-2923. [skip ci] --- .../Configuration/EditorConfiguration.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Greenshot.Editor/Configuration/EditorConfiguration.cs b/src/Greenshot.Editor/Configuration/EditorConfiguration.cs index c36794a5d..9dfb09c23 100644 --- a/src/Greenshot.Editor/Configuration/EditorConfiguration.cs +++ b/src/Greenshot.Editor/Configuration/EditorConfiguration.cs @@ -64,10 +64,7 @@ namespace Greenshot.Editor.Configuration [IniProperty("ReuseEditor", Description = "Reuse already open editor", DefaultValue = "false")] public bool ReuseEditor { get; set; } - [IniProperty("FreehandSensitivity", - Description = - "The smaller this number, the less smoothing is used. Decrease for detailed drawing, e.g. when using a pen. Increase for smoother lines. e.g. when you want to draw a smooth line.", - DefaultValue = "3")] + [IniProperty("FreehandSensitivity", Description = "The smaller this number, the less smoothing is used. Decrease for detailed drawing, e.g. when using a pen. Increase for smoother lines. e.g. when you want to draw a smooth line. Minimal value is 1, max is 2147483647.", DefaultValue = "3")] public int FreehandSensitivity { get; set; } [IniProperty("SuppressSaveDialogAtClose", Description = "Suppressed the 'do you want to save' dialog when closing the editor.", DefaultValue = "False")] @@ -86,9 +83,11 @@ namespace Greenshot.Editor.Configuration public override void AfterLoad() { base.AfterLoad(); - if (RecentColors == null) + RecentColors ??= new List(); + + if (FreehandSensitivity < 1) { - RecentColors = new List(); + FreehandSensitivity = 1; } } @@ -137,10 +136,7 @@ namespace Greenshot.Editor.Configuration { string requestedField = field.Scope + "." + field.FieldType.Name; // Check if the configuration exists - if (LastUsedFieldValues == null) - { - LastUsedFieldValues = new Dictionary(); - } + LastUsedFieldValues ??= new Dictionary(); // check if settings for the requesting type exist, if not create! if (LastUsedFieldValues.ContainsKey(requestedField)) From 2721ee06a2513710b15e4dbd5796f1e05a23b59f Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 23 Mar 2022 21:59:18 +0100 Subject: [PATCH 178/232] Fix #392 , The DibFileFormatHandler wasn't registered with the name which is stored in DataFormats.Dib --- .../FileFormatHandlers/DefaultFileFormatHandler.cs | 2 +- src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs index 30d785bb5..115b5328f 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/DefaultFileFormatHandler.cs @@ -81,7 +81,7 @@ namespace Greenshot.Editor.FileFormatHandlers // For those images which are with Alpha, but the format doesn't support this, change it to 24bpp if (imageFormat.Guid == ImageFormat.Jpeg.Guid && Image.IsAlphaPixelFormat(bitmap.PixelFormat)) { - var nonAlphaImage = ImageHelper.Clone(bitmap, PixelFormat.Format24bppRgb) as Bitmap; + var nonAlphaImage = ImageHelper.Clone(bitmap, PixelFormat.Format24bppRgb); try { // Set that this file was written by Greenshot diff --git a/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs index 8d7ad7790..1e7515e8d 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs @@ -41,7 +41,7 @@ namespace Greenshot.Editor.FileFormatHandlers private const double DpiToPelsPerMeter = 39.3701; private static readonly ILog Log = LogManager.GetLogger(typeof(DibFileFormatHandler)); - private readonly IReadOnlyCollection _ourExtensions = new[] { ".dib", ".format17" }; + private readonly IReadOnlyCollection _ourExtensions = new[] { ".dib", ".format17", ".deviceindependentbitmap" }; public DibFileFormatHandler() { From d6055416c8cd2a7a71c0c3b300f6b7656512fd09 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 28 Mar 2022 14:53:17 +0200 Subject: [PATCH 179/232] Enhanced the adorner interface and the drawing to make it easier to configure with different colors. [skip ci] --- .../Interfaces/Drawing/Adorners/IAdorner.cs | 10 +++++++ .../Drawing/Adorners/AbstractAdorner.cs | 24 +++++++++++++++++ .../Drawing/Adorners/MoveAdorner.cs | 26 ------------------- .../Drawing/Adorners/ResizeAdorner.cs | 18 ------------- .../Drawing/Adorners/TargetAdorner.cs | 19 +++----------- .../Drawing/DrawableContainer.cs | 3 ++- .../Drawing/SpeechbubbleContainer.cs | 4 +-- 7 files changed, 42 insertions(+), 62 deletions(-) diff --git a/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs b/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs index 624c156b1..4dfa4811d 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs @@ -98,5 +98,15 @@ namespace Greenshot.Base.Interfaces.Drawing.Adorners /// /// void AdjustToDpi(uint dpi); + + /// + /// The color of the lines around the adorner + /// + Color OutlineColor { get; set; } + + /// + /// The color of the fill of the adorner + /// + Color FillColor { get; set; } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs index 028306e24..dde10bb84 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs @@ -137,12 +137,36 @@ namespace Greenshot.Editor.Drawing.Adorners _size = DpiHelper.ScaleWithDpi(DefaultSize, dpi); } + public Color OutlineColor { get; set; } = Color.White; + public Color FillColor { get; set; } = Color.Black; + /// /// Draw the adorner /// /// PaintEventArgs public virtual void Paint(PaintEventArgs paintEventArgs) { + Graphics targetGraphics = paintEventArgs.Graphics; + + var bounds = BoundsOnSurface; + GraphicsState state = targetGraphics.Save(); + + targetGraphics.CompositingMode = CompositingMode.SourceCopy; + + try + { + using var fillBrush = new SolidBrush(FillColor); + targetGraphics.FillRectangle(fillBrush, bounds); + using var lineBrush = new SolidBrush(OutlineColor); + using var pen = new Pen(lineBrush); + targetGraphics.DrawRectangle(pen, bounds); + } + catch + { + // Ignore, BUG-2065 + } + + targetGraphics.Restore(state); } /// diff --git a/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs index ad1355ced..7c20e6722 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs @@ -136,31 +136,5 @@ namespace Greenshot.Editor.Drawing.Adorners return new Point(x, y); } } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = BoundsOnSurface; - GraphicsState state = targetGraphics.Save(); - - targetGraphics.CompositingMode = CompositingMode.SourceCopy; - - try - { - targetGraphics.FillRectangle(Brushes.Black, bounds); - targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); - } - catch - { - // Ignore, BUG-2065 - } - - targetGraphics.Restore(state); - } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs index 052abaaa4..c99d4440f 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs @@ -164,23 +164,5 @@ namespace Greenshot.Editor.Drawing.Adorners return new Point(x, y); } } - - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = BoundsOnSurface; - GraphicsState state = targetGraphics.Save(); - - targetGraphics.CompositingMode = CompositingMode.SourceCopy; - - targetGraphics.FillRectangle(Brushes.Black, bounds); - targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); - targetGraphics.Restore(state); - } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs index 0dec40a5f..f39f535e6 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs @@ -29,11 +29,13 @@ namespace Greenshot.Editor.Drawing.Adorners /// /// This implements the special "gripper" for the Speech-Bubble tail /// - public class TargetAdorner : AbstractAdorner + public sealed class TargetAdorner : AbstractAdorner { - public TargetAdorner(IDrawableContainer owner, Point location) : base(owner) + public TargetAdorner(IDrawableContainer owner, Point location, Color? fillColor = null, Color? outlineColor = null) : base(owner) { Location = location; + FillColor = fillColor ?? Color.Green; + OutlineColor = outlineColor ?? Color.White; } /// @@ -90,19 +92,6 @@ namespace Greenshot.Editor.Drawing.Adorners Owner.Invalidate(); } - /// - /// Draw the adorner - /// - /// PaintEventArgs - public override void Paint(PaintEventArgs paintEventArgs) - { - Graphics targetGraphics = paintEventArgs.Graphics; - - var bounds = BoundsOnSurface; - targetGraphics.FillRectangle(Brushes.Green, bounds); - targetGraphics.DrawRectangle(new Pen(Brushes.White), bounds); - } - /// /// Made sure this adorner is transformed /// diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index b07974e61..38eab8b3f 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -363,7 +363,8 @@ namespace Greenshot.Editor.Drawing /// /// Initialize a target gripper /// - protected void InitAdorner(Color gripperColor, Point location) + /// Point + protected void InitTargetAdorner(Point location) { _targetAdorner = new TargetAdorner(this, location); Adorners.Add(_targetAdorner); diff --git a/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs b/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs index 0a19805e7..0e60765e9 100644 --- a/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs +++ b/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs @@ -62,7 +62,7 @@ namespace Greenshot.Editor.Drawing protected override void OnDeserialized(StreamingContext streamingContext) { base.OnDeserialized(streamingContext); - InitAdorner(Color.Green, _storedTargetGripperLocation); + InitTargetAdorner(_storedTargetGripperLocation); } public SpeechbubbleContainer(ISurface parent) : base(parent) @@ -95,7 +95,7 @@ namespace Greenshot.Editor.Drawing if (TargetAdorner == null) { _initialGripperPoint = new Point(mouseX, mouseY); - InitAdorner(Color.Green, new Point(mouseX, mouseY)); + InitTargetAdorner(new Point(mouseX, mouseY)); } return base.HandleMouseDown(mouseX, mouseY); From 83b308cb4b4d10b39e61f7c5ad8ee78e88f5b0d7 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 28 Mar 2022 16:00:51 +0200 Subject: [PATCH 180/232] Boolean logic fix to help with #396, this at least should solve the issue for .PNG, other formats are pending. [skip ci] --- src/Greenshot.Base/Core/ClipboardHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs index a6e1da2a0..75019befb 100644 --- a/src/Greenshot.Base/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -815,7 +815,7 @@ EndSelection:<<<<<<<4 var fileFormatHandlers = SimpleServiceProvider.Current.GetAllInstances(); // From here, imageStream is a valid stream - if (!fileFormatHandlers.TryLoadFromStream(imageStream, format, out bitmap)) + if (fileFormatHandlers.TryLoadFromStream(imageStream, format, out bitmap)) { return bitmap; } From 9ae5598ab8cdd27b30d726bfbf58fcab41bcc416 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 29 Mar 2022 09:05:25 +0200 Subject: [PATCH 181/232] Solved the clipboard loading for the DIB file format too, this is related to #396 --- .../FileFormatHandlers/DibFileFormatHandler.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs index 1e7515e8d..cf18cddb7 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs @@ -87,8 +87,9 @@ namespace Greenshot.Editor.FileFormatHandlers bitmapStream.Write(dibBuffer, 0, dibBuffer.Length); bitmapStream.Seek(0, SeekOrigin.Begin); // TODO: Replace with a FileFormatHandler - bitmap = ImageIO.FromStream(bitmapStream) as Bitmap; - return true; + using var beforeCloneImage = Image.FromStream(bitmapStream); + bitmap = ImageHelper.Clone(beforeCloneImage) as Bitmap; + return bitmap != null; } Log.Info("Using special DIBV5 / Format17 format reader"); // CF_DIBV5 From 78cbb055cb0ae851309baa3faf12bff0a9afd53c Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 29 Mar 2022 20:35:43 +0200 Subject: [PATCH 182/232] Added better error handling for reading the bitmap [skip ci] --- .../FileFormatHandlers/DibFileFormatHandler.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs index cf18cddb7..5061d7744 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs @@ -86,10 +86,18 @@ namespace Greenshot.Editor.FileFormatHandlers bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize); bitmapStream.Write(dibBuffer, 0, dibBuffer.Length); bitmapStream.Seek(0, SeekOrigin.Begin); - // TODO: Replace with a FileFormatHandler - using var beforeCloneImage = Image.FromStream(bitmapStream); - bitmap = ImageHelper.Clone(beforeCloneImage) as Bitmap; - return bitmap != null; + try + { + using var beforeCloneImage = Image.FromStream(bitmapStream); + bitmap = ImageHelper.Clone(beforeCloneImage) as Bitmap; + return bitmap != null; + } + catch (Exception ex) + { + Log.Error("Problem retrieving Format17 from clipboard.", ex); + bitmap = null; + return false; + } } Log.Info("Using special DIBV5 / Format17 format reader"); // CF_DIBV5 From 64c77ea8d91a746eefba695b95f03e98e9071127 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 29 Mar 2022 22:38:28 +0200 Subject: [PATCH 183/232] Some code improvements which make some later features possible (maybe having a bezier for a line) [skip ci] --- src/Greenshot.Base/Controls/GreenshotForm.cs | 2 +- src/Greenshot.Base/Core/Language.cs | 2 +- .../Interfaces/Drawing/Adorners/IAdorner.cs | 5 ++ .../Interfaces/Drawing/IDrawableContainer.cs | 9 ++ src/Greenshot.Base/Interfaces/ISurface.cs | 36 ++++++++ .../UnmanagedHelpers/Enums/RegionResult.cs | 2 + .../Drawing/Adorners/AbstractAdorner.cs | 5 ++ .../Drawing/Adorners/TargetAdorner.cs | 10 +-- .../Drawing/ArrowContainer.cs | 60 +++++++------- .../Drawing/DrawableContainer.cs | 7 ++ .../Drawing/DrawableContainerList.cs | 83 ++++++++----------- src/Greenshot.Editor/Drawing/Surface.cs | 24 +++--- 12 files changed, 146 insertions(+), 99 deletions(-) diff --git a/src/Greenshot.Base/Controls/GreenshotForm.cs b/src/Greenshot.Base/Controls/GreenshotForm.cs index eff79e975..42b2719ce 100644 --- a/src/Greenshot.Base/Controls/GreenshotForm.cs +++ b/src/Greenshot.Base/Controls/GreenshotForm.cs @@ -350,7 +350,7 @@ namespace Greenshot.Base.Controls { if (!Language.TryGetString(languageKey, out langString)) { - LOG.WarnFormat("Unknown language key '{0}' configured for control '{1}', this might be okay.", languageKey, applyTo.Name); + LOG.DebugFormat("Unknown language key '{0}' configured for control '{1}', this might be okay.", languageKey, applyTo.Name); return; } diff --git a/src/Greenshot.Base/Core/Language.cs b/src/Greenshot.Base/Core/Language.cs index 8037393ad..4627a10fc 100644 --- a/src/Greenshot.Base/Core/Language.cs +++ b/src/Greenshot.Base/Core/Language.cs @@ -470,7 +470,7 @@ namespace Greenshot.Base.Core languageFile }; LanguageFiles.Add(languageFile.Ietf, currentFiles); - Log.InfoFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); + Log.DebugFormat("Added language definition {0} from: {1}", languageFile.Description, languageFile.Filepath); } } } diff --git a/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs b/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs index 4dfa4811d..c55044928 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs @@ -108,5 +108,10 @@ namespace Greenshot.Base.Interfaces.Drawing.Adorners /// The color of the fill of the adorner /// Color FillColor { get; set; } + + /// + /// This is to TAG the adorner so we know the type + /// + string Tag { get; set; } } } \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs index 3d420bfa3..2363b7ac9 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; +using System.Windows.Forms; using Greenshot.Base.Interfaces.Drawing.Adorners; namespace Greenshot.Base.Interfaces.Drawing @@ -97,5 +98,13 @@ namespace Greenshot.Base.Interfaces.Drawing /// /// uint void AdjustToDpi(uint dpi); + + /// + /// Enable a way for elements to add a context menu entry + /// + /// ContextMenuStrip + /// ISurface + /// MouseEventArgs + void AddContextMenuItems(ContextMenuStrip menu, ISurface surface, MouseEventArgs mouseEventArgs); } } \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/ISurface.cs b/src/Greenshot.Base/Interfaces/ISurface.cs index 396a5702f..4ec000ed9 100644 --- a/src/Greenshot.Base/Interfaces/ISurface.cs +++ b/src/Greenshot.Base/Interfaces/ISurface.cs @@ -101,13 +101,49 @@ namespace Greenshot.Base.Interfaces long SaveElementsToStream(Stream stream); void LoadElementsFromStream(Stream stream); + /// + /// Provides the selected elements + /// + IDrawableContainerList SelectedElements { get; } + + /// + /// Is there an element selected on the surface? + /// bool HasSelectedElements { get; } + + /// + /// Remove all selected elements + /// void RemoveSelectedElements(); + + /// + /// Cut the selected elements to the clipboard + /// void CutSelectedElements(); + + /// + /// Copy the selected elements to the clipboard + /// void CopySelectedElements(); + + /// + /// Paste the elements from the clipboard + /// void PasteElementFromClipboard(); + + /// + /// Duplicate the selected elements + /// void DuplicateSelectedElements(); + + /// + /// Deselected the specified element + /// void DeselectElement(IDrawableContainer container, bool generateEvents = true); + + /// + /// Deselected all elements + /// void DeselectAllElements(); /// diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs index 013f70ef3..f9c0e5a1f 100644 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs +++ b/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs @@ -28,5 +28,7 @@ namespace Greenshot.Base.UnmanagedHelpers.Enums { REGION_ERROR = 0, REGION_NULLREGION = 1, + SIMPLEREGION = 2, + COMPLEXREGION = 3 } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs index dde10bb84..0890a87d9 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs @@ -176,5 +176,10 @@ namespace Greenshot.Editor.Drawing.Adorners public virtual void Transform(Matrix matrix) { } + + /// + /// This is to TAG the adorner so we know the type + /// + public string Tag { get; set; } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs index f39f535e6..c59fc43ef 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs @@ -27,7 +27,7 @@ using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Editor.Drawing.Adorners { /// - /// This implements the special "gripper" for the Speech-Bubble tail + /// This implements the special target "gripper", e.g. used for the Speech-Bubble tail /// public sealed class TargetAdorner : AbstractAdorner { @@ -41,8 +41,8 @@ namespace Greenshot.Editor.Drawing.Adorners /// /// Handle the mouse down /// - /// - /// + /// object + /// MouseEventArgs public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) { EditStatus = EditStatus.MOVING; @@ -51,8 +51,8 @@ namespace Greenshot.Editor.Drawing.Adorners /// /// Handle the mouse move /// - /// - /// + /// object + /// MouseEventArgs public override void MouseMove(object sender, MouseEventArgs mouseEventArgs) { if (EditStatus != EditStatus.MOVING) diff --git a/src/Greenshot.Editor/Drawing/ArrowContainer.cs b/src/Greenshot.Editor/Drawing/ArrowContainer.cs index eb1e10e2f..9907ad106 100644 --- a/src/Greenshot.Editor/Drawing/ArrowContainer.cs +++ b/src/Greenshot.Editor/Drawing/ArrowContainer.cs @@ -66,44 +66,40 @@ namespace Greenshot.Editor.Drawing int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - if (lineThickness > 0) + if (lineThickness <= 0) return; + + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + ArrowHeadCombination heads = (ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS); + if (shadow) { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - ArrowHeadCombination heads = (ArrowHeadCombination) GetFieldValue(FieldType.ARROWHEADS); - if (lineThickness > 0) + //draw shadow first + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = 1; + while (currentStep <= steps) { - if (shadow) - { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = 1; - while (currentStep <= steps) - { - using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); - SetArrowHeads(heads, shadowCapPen); + using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); + SetArrowHeads(heads, shadowCapPen); - graphics.DrawLine(shadowCapPen, - Left + currentStep, - Top + currentStep, - Left + currentStep + Width, - Top + currentStep + Height); + graphics.DrawLine(shadowCapPen, + Left + currentStep, + Top + currentStep, + Left + currentStep + Width, + Top + currentStep + Height); - currentStep++; - alpha -= basealpha / steps; - } - } - - using Pen pen = new Pen(lineColor, lineThickness); - SetArrowHeads(heads, pen); - graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); + currentStep++; + alpha -= basealpha / steps; } } + + using Pen pen = new Pen(lineColor, lineThickness); + SetArrowHeads(heads, pen); + graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); } private void SetArrowHeads(ArrowHeadCombination heads, Pen pen) diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index 38eab8b3f..f8a14052b 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -26,6 +26,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Runtime.Serialization; +using System.Windows.Forms; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; @@ -448,6 +449,12 @@ namespace Greenshot.Editor.Drawing } } + /// + public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface, MouseEventArgs mouseEventArgs) + { + // Empty as we do not want to add something to the context menu for every element + } + public virtual bool Contains(int x, int y) { return Bounds.Contains(x, y); diff --git a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs index 9ab825e4a..4da98fa37 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs @@ -589,9 +589,10 @@ namespace Greenshot.Editor.Drawing /// /// Add items to a context menu for the selected item /// - /// - /// - public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface) + /// ContextMenuStrip + /// ISurface + /// MouseEventArgs + public virtual void AddContextMenuItems(ContextMenuStrip menu, ISurface surface, MouseEventArgs mouseEventArgs) { bool push = surface.Elements.CanPushDown(this); bool pull = surface.Elements.CanPullUp(this); @@ -678,15 +679,7 @@ namespace Greenshot.Editor.Drawing menu.Items.Add(item); // Reset - bool canReset = false; - foreach (var drawableContainer in this) - { - var container = (DrawableContainer) drawableContainer; - if (container.HasDefaultSize) - { - canReset = true; - } - } + bool canReset = this.Cast().Any(container => container.HasDefaultSize); if (canReset) { @@ -713,48 +706,40 @@ namespace Greenshot.Editor.Drawing }; menu.Items.Add(item); } + + // "ask" the containers to add to the context menu + foreach (var surfaceElement in surface.Elements) + { + surfaceElement.AddContextMenuItems(menu, surface, mouseEventArgs); + } } - public virtual void ShowContextMenu(MouseEventArgs e, ISurface iSurface) + public virtual void ShowContextMenu(MouseEventArgs mouseEventArgs, ISurface iSurface) { if (iSurface is not Surface surface) { return; } - bool hasMenu = false; - foreach (var drawableContainer in this) + bool hasMenu = this.Cast().Any(container => container.HasContextMenu); + + if (!hasMenu) return; + + ContextMenuStrip menu = new ContextMenuStrip(); + AddContextMenuItems(menu, surface, mouseEventArgs); + if (menu.Items.Count <= 0) return; + menu.Show(surface, surface.ToSurfaceCoordinates(mouseEventArgs.Location)); + while (true) { - var container = (DrawableContainer) drawableContainer; - if (!container.HasContextMenu) + if (menu.Visible) { - continue; + Application.DoEvents(); + Thread.Sleep(100); } - - hasMenu = true; - break; - } - - if (hasMenu) - { - ContextMenuStrip menu = new ContextMenuStrip(); - AddContextMenuItems(menu, surface); - if (menu.Items.Count > 0) + else { - menu.Show(surface, surface.ToSurfaceCoordinates(e.Location)); - while (true) - { - if (menu.Visible) - { - Application.DoEvents(); - Thread.Sleep(100); - } - else - { - menu.Dispose(); - break; - } - } + menu.Dispose(); + break; } } } @@ -763,18 +748,16 @@ namespace Greenshot.Editor.Drawing protected virtual void Dispose(bool disposing) { - if (!_disposedValue) + if (_disposedValue) return; + if (disposing) { - if (disposing) + foreach (var drawableContainer in this) { - foreach (var drawableContainer in this) - { - drawableContainer.Dispose(); - } + drawableContainer.Dispose(); } - - _disposedValue = true; } + + _disposedValue = true; } // This code added to correctly implement the disposable pattern. diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index be40c7d1c..8eb2a872e 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -2036,23 +2036,27 @@ namespace Greenshot.Editor.Drawing /// /// Returns if this surface has selected elements /// - /// - public bool HasSelectedElements => (selectedElements != null && selectedElements.Count > 0); + /// bool + public bool HasSelectedElements => selectedElements is { Count: > 0 }; + + /// + /// Provides the selected elements + /// + public IDrawableContainerList SelectedElements => selectedElements; /// /// Remove all the selected elements /// public void RemoveSelectedElements() { - if (HasSelectedElements) + if (!HasSelectedElements) return; + + // As RemoveElement will remove the element from the selectedElements list we need to copy the element to another list. + RemoveElements(selectedElements); + if (_movingElementChanged != null) { - // As RemoveElement will remove the element from the selectedElements list we need to copy the element to another list. - RemoveElements(selectedElements); - if (_movingElementChanged != null) - { - SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); - _movingElementChanged(this, eventArgs); - } + SurfaceElementEventArgs eventArgs = new SurfaceElementEventArgs(); + _movingElementChanged(this, eventArgs); } } From 15db5a1a3f9c94e001e2348054f9ecdec447a805 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Sat, 2 Apr 2022 21:15:15 +0200 Subject: [PATCH 184/232] Update Italian language (#394) --- src/Greenshot/Languages/language-it-IT.xml | 36 ++++++++++++---------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Greenshot/Languages/language-it-IT.xml b/src/Greenshot/Languages/language-it-IT.xml index e52ecb1e1..b0cb0e96f 100644 --- a/src/Greenshot/Languages/language-it-IT.xml +++ b/src/Greenshot/Languages/language-it-IT.xml @@ -6,7 +6,7 @@ Greenshot è disponibile nel repository GitHub Libreria icone del set icone Fugue di Yusuke Kamiyamane (Creative Commons Attribution 3.0 license) Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom -Greenshot viene fornito SENZA ALCUNA GARANZIA. +Greenshot viene fornito SENZA ALCUNA GARANZIA. Questo software è gratuito", e potete ri-distribuirlo secondo certe condizioni. Dettagli della General Public License GNU: Info su Greenshot @@ -19,8 +19,7 @@ La buona notizia è che puoi aiutarci ad eliminarlo segnalandoci l'errore. Visita la pagina internet qui sotto, crea una nuova segnalazione errore e copia nella descrizione il contenuto preso dall'area di testo. Aggiungi un riepilogo significativo e includi qualsiasi informazione tu consideri possa esserci d'aiuto per risolvere il problema. -Inoltre apprezzeremo molto, se prima di inserire la segnalazione, controllassi se esiste già una segnalazione per questo tipo di errore (puoi usare la ricerca) -Grazie :) +Inoltre apprezzeremo molto, se prima di inserire la segnalazione, controllassi se esiste già una segnalazione per questo tipo di errore (puoi usare la ricerca). Grazie :) Errore Annulla Si è verificato un errore inaspettato durante la scrittura negli Appunti. @@ -82,7 +81,8 @@ Controlla i permessi di accesso per '{0}'. Punto finale Nessuna Punto iniziale - Ritaglia Automaticamente + Ritaglia automaticamente + Ritaglio automatico non possibile Colore di riempimento Raggio sfumatura Grassetto @@ -99,7 +99,9 @@ Controlla i permessi di accesso per '{0}'. Copia Ritaglia (C) Ritaglia - Ritaglia Automaticamente + Ritaglia verticalmente + Ritaglia orizzontalmente + Ritaglia automaticamente Strumento di selezione (ESC) Taglia Elimina @@ -131,8 +133,8 @@ Controlla i permessi di accesso per '{0}'. Negativo Corsivo Carica oggetti da file - Fattore di ingrandimento - Adatta a dimensioni di cattura + Fattore ingrandimento + Adatta a dimensioni cattura Offusca (O) Sfuma Modalità offuscamento @@ -177,17 +179,17 @@ Verifica l'accesso in scrittura nel percorso di salvataggio. Il nome file o cartella generato non è valido. Correggi la maschera noem file e riprova. Utente esperto - Crea una immagine a 8bit se i colori sono meno di 256 e l'immagine ha > 8 bit + Crea immagine a 8bit se immagine ha meno di 256 colori Controlla disponibilità aggiornamenti versioni beta - Formati degli Appunti - Numero per var. ${NUM} nel modello del nome file + Formato Appunti + Numero var. ${NUM} modello nome file Sono consapevole di ciò che sto facendo! - Modello piè di pagina + Modello piè pagina Riduci uso della memoria perdendo però in prestazioni (sconsigliato). Esegui ottimizzazioni per uso con desktop remoto Riutilizza se possibile la gestione immagini Evita avviso di salvataggio in chiusura della gestione immagini - Visualizza anteprima finestra nel menù contestuale (Vista e Windows 7) + Visualizza anteprima finestra menù contestuale (Vista/Windows 7) Esportato in: {0} Si è verificato un errore durante l'esportazione in {0}: Guida in linea Greenshot @@ -217,7 +219,7 @@ Correggi la maschera noem file e riprova. Esegui Greenshot all'avvio del sistema Cattura Cattura puntatore mouse - Usa la modalità di cattura via finestra interattiva + Usa modalità cattura via finestra interattiva Intervallo controllo aggiornamento in giorni (0=nessun controllo) Imposta Ogni volta che una immagine viene salvata copia percorso file negli Appunti @@ -267,7 +269,7 @@ impostazioni) Stampante Opzioni di stampa Impostazioni qualità - Riduci i colori a un massimo di 256 + Riduci i colori ad un massimo di 256 Registra scorciatoie tastiera Visualizza torcia elettrica Visualizza notifiche @@ -296,8 +298,8 @@ In alternativa alle scorciatoie di tastiera, tutte le funzioni di Greenshot sono Usa colori personalizzati Mantieni trasparenza - Automaticamente - Usa i colori predefiniti + Automatica + Usa colori predefiniti Come visualizzata @@ -325,7 +327,7 @@ In alternativa alle scorciatoie di tastiera, tutte le funzioni di Greenshot sono Mantieni rapporto dimensioni Larghezza Altezza - Dimensione icona + Dimensione icona (pixel) From 8aca1c82828b5a8df785423763cd8edcbde1c8f8 Mon Sep 17 00:00:00 2001 From: Christian Schulz <32000301+Christian-Schulz@users.noreply.github.com> Date: Wed, 13 Apr 2022 09:53:46 +0200 Subject: [PATCH 185/232] DrawableContainer extended to indicate if confirm/cancel is available. #397 (#399) --- .../Interfaces/Drawing/IDrawableContainer.cs | 5 +++++ src/Greenshot.Editor/Drawing/CropContainer.cs | 13 +++++++++++-- src/Greenshot.Editor/Drawing/DrawableContainer.cs | 5 ++++- src/Greenshot.Editor/Drawing/Surface.cs | 2 +- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs index 2363b7ac9..b42192916 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs @@ -93,6 +93,11 @@ namespace Greenshot.Base.Interfaces.Drawing /// IList Adorners { get; } + /// + /// Is confirm/cancel possible for this container + /// + bool IsConfirmable { get; } + /// /// Adjust UI elements to the supplied DPI settings /// diff --git a/src/Greenshot.Editor/Drawing/CropContainer.cs b/src/Greenshot.Editor/Drawing/CropContainer.cs index 936a1a2c8..f33045b61 100644 --- a/src/Greenshot.Editor/Drawing/CropContainer.cs +++ b/src/Greenshot.Editor/Drawing/CropContainer.cs @@ -264,9 +264,18 @@ namespace Greenshot.Editor.Drawing Invalidate(); return true; } - - /// + /// + /// + /// /// Make sure this container is not undoable + /// public override bool IsUndoable => false; + + /// + /// + /// + /// See dedicated confirm method + /// + public override bool IsConfirmable => true; } } diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index f8a14052b..7ae58bfe6 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -480,9 +480,12 @@ namespace Greenshot.Editor.Drawing g.DrawRectangle(pen, rect); } - /// + /// public virtual bool IsUndoable => true; + /// + public virtual bool IsConfirmable => false; + /// /// Make a following bounds change on this drawablecontainer undoable! /// diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index 8eb2a872e..ead40e74f 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -2108,7 +2108,7 @@ namespace Greenshot.Editor.Drawing { // create new collection so that we can iterate safely (selectedElements might change due with confirm/cancel) List selectedDCs = new List(selectedElements); - foreach (IDrawableContainer dc in selectedDCs) + foreach (IDrawableContainer dc in selectedDCs.Where(c => c.IsConfirmable)) { throw new NotImplementedException($"No confirm/cancel defined for Container type {dc.GetType()}"); } From 13e2e67e7c065e9657e60a9aa4834415f8430d80 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 13 Apr 2022 09:56:00 +0200 Subject: [PATCH 186/232] Refactoring to use Dapplo.Windows (#398) * Removed a LOT of the native "Win32" invokes in favor of Dapplo.Windows which was created mainly for Greenshot. * Changed all usages of Point, Rectangle, RectangleF, Size to the Native versions of those from Dapplo.Windows.Common. * Small fix for the OCR text feature. --- src/Greenshot.Base/Controls/GreenshotForm.cs | 47 +- src/Greenshot.Base/Controls/ThumbnailForm.cs | 31 +- .../Core/AbstractDestination.cs | 31 +- src/Greenshot.Base/Core/AnimationHelpers.cs | 39 +- src/Greenshot.Base/Core/Capture.cs | 29 +- src/Greenshot.Base/Core/CaptureHandler.cs | 5 +- src/Greenshot.Base/Core/ClipboardHelper.cs | 32 +- src/Greenshot.Base/Core/CoreConfiguration.cs | 18 +- src/Greenshot.Base/Core/DpiHelper.cs | 203 ------ src/Greenshot.Base/Core/EffectConverter.cs | 8 +- src/Greenshot.Base/Core/Enums/HResult.cs | 33 - .../Core/Enums/MonitorDpiType.cs | 41 -- src/Greenshot.Base/Core/Enums/MonitorFrom.cs | 31 - .../Core/Enums/PrintWindowFlags.cs | 38 -- src/Greenshot.Base/Core/EnvironmentInfo.cs | 318 ++-------- src/Greenshot.Base/Core/FastBitmap.cs | 107 ++-- src/Greenshot.Base/Core/FileDescriptor.cs | 10 +- src/Greenshot.Base/Core/HResultExtensions.cs | 52 -- src/Greenshot.Base/Core/ImageHelper.cs | 206 +++--- src/Greenshot.Base/Core/ImageIO.cs | 90 +-- src/Greenshot.Base/Core/PluginUtils.cs | 57 +- src/Greenshot.Base/Core/WindowCapture.cs | 132 ++-- src/Greenshot.Base/Core/WindowDetails.cs | 334 +++++----- src/Greenshot.Base/Core/WindowsEnumerator.cs | 23 +- .../Core/WmInputLangChangeRequestFilter.cs | 2 +- .../Effects/DropShadowEffect.cs | 3 +- src/Greenshot.Base/Greenshot.Base.csproj | 10 +- .../Hooking/WindowsEventHook.cs | 151 ----- .../Hooking/WindowsOpenCloseMonitor.cs | 180 ------ .../Hooking/WindowsTitleMonitor.cs | 165 ----- .../Interfaces/Drawing/Adorners/IAdorner.cs | 7 +- .../Interfaces/Drawing/IDrawableContainer.cs | 16 +- .../Drawing/IDrawableContainerList.cs | 11 +- src/Greenshot.Base/Interfaces/ICapture.cs | 11 +- .../IProvideDeviceDpi.cs} | 19 +- src/Greenshot.Base/Interfaces/ISurface.cs | 27 +- src/Greenshot.Base/Interfaces/Ocr/Line.cs | 40 +- .../Interfaces/Ocr/OcrInformation.cs | 23 +- src/Greenshot.Base/Interfaces/Ocr/Word.cs | 25 +- .../SurfaceLineThicknessEventArgs.cs | 1 - .../Interfaces/SurfaceShadowEventArgs.cs | 1 - src/Greenshot.Base/UnmanagedHelpers/DWM.cs | 123 ---- .../UnmanagedHelpers/Enums/ClassLongIndex.cs | 32 - .../Enums/DWMWINDOWATTRIBUTE.cs | 46 -- .../Enums/DWM_THUMBNAIL_PROPERTIES.cs | 111 ---- .../Enums/DesktopAccessRight.cs | 45 -- .../UnmanagedHelpers/Enums/DeviceCaps.cs | 43 -- .../UnmanagedHelpers/Enums/EventObjects.cs | 34 - .../Enums/ExtendedWindowStyleFlags.cs | 71 --- .../Enums/ProcessAccessFlags.cs | 34 - .../UnmanagedHelpers/Enums/RegionResult.cs | 34 - .../Enums/SendMessageTimeoutFlags.cs | 36 -- .../Enums/ShowWindowCommand.cs | 110 ---- .../UnmanagedHelpers/Enums/SoundFlags.cs | 39 -- .../UnmanagedHelpers/Enums/ThreadAccess.cs | 31 - .../UnmanagedHelpers/Enums/Win32Error.cs | 89 --- .../UnmanagedHelpers/Enums/WinEvent.cs | 37 -- .../Enums/WinEventHookFlags.cs | 18 - .../UnmanagedHelpers/Enums/WindowLongIndex.cs | 32 - .../Enums/WindowPlacementFlags.cs | 42 -- .../UnmanagedHelpers/Enums/WindowPos.cs | 36 -- .../Enums/WindowStyleFlags.cs | 52 -- .../UnmanagedHelpers/Enums/WindowsMessages.cs | 26 - src/Greenshot.Base/UnmanagedHelpers/GDI32.cs | 596 ------------------ .../UnmanagedHelpers/GDIplus.cs | 387 ------------ .../UnmanagedHelpers/Kernel32.cs | 135 ---- src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs | 56 -- .../SafeCurrentInputDesktopHandle.cs | 45 -- .../UnmanagedHelpers/SafeIconHandle.cs | 33 - .../UnmanagedHelpers/SafeWindowDcHandle.cs | 66 -- .../UnmanagedHelpers/Shell32.cs | 123 ---- .../UnmanagedHelpers/Structs/CursorInfo.cs | 35 - .../UnmanagedHelpers/Structs/IconInfo.cs | 36 -- .../UnmanagedHelpers/Structs/POINT.cs | 66 -- .../UnmanagedHelpers/Structs/RECT.cs | 176 ------ .../UnmanagedHelpers/Structs/RECTF.cs | 131 ---- .../UnmanagedHelpers/Structs/SCROLLINFO.cs | 38 -- .../UnmanagedHelpers/Structs/SIZE.cs | 51 -- .../UnmanagedHelpers/Structs/WindowInfo.cs | 52 -- .../Structs/WindowPlacement.cs | 80 --- src/Greenshot.Base/UnmanagedHelpers/User32.cs | 331 ---------- src/Greenshot.Base/UnmanagedHelpers/Win32.cs | 69 -- .../UnmanagedHelpers/WinEventDelegate.cs | 17 - src/Greenshot.Base/UnmanagedHelpers/WinMM.cs | 38 -- .../Configuration/EditorConfiguration.cs | 37 +- src/Greenshot.Editor/Controls/ColorButton.cs | 3 +- .../Controls/FontFamilyComboBox.cs | 13 +- src/Greenshot.Editor/Controls/MenuStripEx.cs | 2 +- src/Greenshot.Editor/Controls/Pipette.cs | 24 +- .../Controls/ToolStripColorButton.cs | 3 +- .../Drawing/Adorners/AbstractAdorner.cs | 37 +- .../Drawing/Adorners/MoveAdorner.cs | 17 +- .../Drawing/Adorners/ResizeAdorner.cs | 42 +- .../Drawing/Adorners/TargetAdorner.cs | 16 +- .../Drawing/ArrowContainer.cs | 11 +- src/Greenshot.Editor/Drawing/CropContainer.cs | 30 +- .../Drawing/CursorContainer.cs | 3 +- .../Drawing/DrawableContainer.cs | 55 +- .../Drawing/DrawableContainerList.cs | 26 +- .../Drawing/EllipseContainer.cs | 12 +- .../Drawing/FilterContainer.cs | 55 +- .../Drawing/Filters/AbstractFilter.cs | 3 +- .../Drawing/Filters/BlurFilter.cs | 11 +- .../Drawing/Filters/BrightnessFilter.cs | 7 +- .../Drawing/Filters/GrayscaleFilter.cs | 7 +- .../Drawing/Filters/HighlightFilter.cs | 10 +- .../Drawing/Filters/IFilter.cs | 3 +- .../Drawing/Filters/MagnifierFilter.cs | 10 +- .../Drawing/Filters/PixelizationFilter.cs | 6 +- .../Drawing/FreehandContainer.cs | 21 +- src/Greenshot.Editor/Drawing/IconContainer.cs | 3 +- .../Drawing/ImageContainer.cs | 5 +- src/Greenshot.Editor/Drawing/LineContainer.cs | 47 +- .../Drawing/MetafileContainer.cs | 8 +- .../Drawing/RectangleContainer.cs | 17 +- .../Drawing/SpeechbubbleContainer.cs | 51 +- .../Drawing/StepLabelContainer.cs | 9 +- src/Greenshot.Editor/Drawing/Surface.cs | 196 +++--- src/Greenshot.Editor/Drawing/SvgContainer.cs | 5 +- src/Greenshot.Editor/Drawing/TextContainer.cs | 35 +- .../DibFileFormatHandler.cs | 65 +- src/Greenshot.Editor/Forms/ColorDialog.cs | 1 - .../Forms/ColorPickerToolStripButton.cs | 44 +- .../Forms/DropShadowSettingsForm.cs | 3 +- .../Forms/ImageEditorForm.Designer.cs | 13 +- src/Greenshot.Editor/Forms/ImageEditorForm.cs | 52 +- .../Forms/MovableShowColorForm.cs | 72 ++- .../Forms/TornEdgeSettingsForm.cs | 4 +- src/Greenshot.Editor/Helpers/GuiRectangle.cs | 53 -- src/Greenshot.Editor/Helpers/ScaleHelper.cs | 109 ++-- src/Greenshot.Plugin.Box/BoxConfiguration.cs | 1 - .../ConfluenceConfiguration.cs | 1 - .../FlickrConfiguration.cs | 1 - src/Greenshot.Plugin.Flickr/FlickrPlugin.cs | 1 - .../GooglePhotosConfiguration.cs | 1 - .../ImgurConfiguration.cs | 1 - src/Greenshot.Plugin.Jira/Forms/JiraForm.cs | 3 +- .../Greenshot.Plugin.Jira.csproj | 4 +- .../JiraConfiguration.cs | 1 - src/Greenshot.Plugin.Jira/JiraConnector.cs | 8 +- src/Greenshot.Plugin.Jira/JiraMonitor.cs | 16 +- src/Greenshot.Plugin.Office/Com/Ole32Api.cs | 4 +- .../Com/OleAut32Api.cs | 4 +- .../OfficeExport/ExcelExporter.cs | 4 +- .../Destinations/Win10ShareDestination.cs | 22 +- .../Native/DataTransferManagerHelper.cs | 2 +- .../Native/IDataTransferManagerInterOp.cs | 2 +- .../Win10OcrProvider.cs | 3 +- ...ontextMenuToolStripProfessionalRenderer.cs | 17 +- src/Greenshot/Forms/AboutForm.cs | 61 +- src/Greenshot/Forms/CaptureForm.cs | 174 +++-- src/Greenshot/Forms/MainForm.Designer.cs | 4 +- src/Greenshot/Forms/MainForm.cs | 124 ++-- src/Greenshot/Forms/SettingsForm.cs | 7 +- .../Forms/ToolStripMenuSelectList.cs | 21 +- src/Greenshot/Helpers/CaptureHelper.cs | 55 +- src/Greenshot/Helpers/IECaptureHelper.cs | 27 +- .../Helpers/IEInterop/IEContainer.cs | 80 +-- src/Greenshot/Helpers/SoundHelper.cs | 12 +- 159 files changed, 1646 insertions(+), 6560 deletions(-) delete mode 100644 src/Greenshot.Base/Core/DpiHelper.cs delete mode 100644 src/Greenshot.Base/Core/Enums/HResult.cs delete mode 100644 src/Greenshot.Base/Core/Enums/MonitorDpiType.cs delete mode 100644 src/Greenshot.Base/Core/Enums/MonitorFrom.cs delete mode 100644 src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs delete mode 100644 src/Greenshot.Base/Core/HResultExtensions.cs delete mode 100644 src/Greenshot.Base/Hooking/WindowsEventHook.cs delete mode 100644 src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs delete mode 100644 src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs rename src/Greenshot.Base/{UnmanagedHelpers/EnumWindowsProc.cs => Interfaces/IProvideDeviceDpi.cs} (76%) delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/DWM.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/DesktopAccessRight.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/DeviceCaps.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/ProcessAccessFlags.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/ThreadAccess.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/WinEventHookFlags.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPlacementFlags.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/GDI32.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Shell32.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Structs/CursorInfo.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Structs/POINT.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Structs/RECT.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Structs/RECTF.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Structs/SCROLLINFO.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Structs/SIZE.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Structs/WindowInfo.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Structs/WindowPlacement.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/User32.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/Win32.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/WinEventDelegate.cs delete mode 100644 src/Greenshot.Base/UnmanagedHelpers/WinMM.cs delete mode 100644 src/Greenshot.Editor/Helpers/GuiRectangle.cs diff --git a/src/Greenshot.Base/Controls/GreenshotForm.cs b/src/Greenshot.Base/Controls/GreenshotForm.cs index 42b2719ce..85bc6bd4d 100644 --- a/src/Greenshot.Base/Controls/GreenshotForm.cs +++ b/src/Greenshot.Base/Controls/GreenshotForm.cs @@ -102,6 +102,20 @@ namespace Greenshot.Base.Controls ///
protected bool ToFront { get; set; } + protected GreenshotForm() + { + DpiChanged += (sender, dpiChangedEventArgs) => DpiChangedHandler(dpiChangedEventArgs.DeviceDpiOld, dpiChangedEventArgs.DeviceDpiNew); + } + + /// + /// This is the basic DpiChangedHandler responsible for all the DPI relative changes + /// + /// + /// + protected virtual void DpiChangedHandler(int oldDpi, int newDpi) + { + } + #if DEBUG /// /// Code to initialize the language etc during design time @@ -382,10 +396,10 @@ namespace Greenshot.Base.Controls protected void ApplyLanguage(Control applyTo) { - if (!(applyTo is IGreenshotLanguageBindable languageBindable)) + if (applyTo is not IGreenshotLanguageBindable languageBindable) { // check if it's a menu! - if (!(applyTo is ToolStrip toolStrip)) + if (applyTo is not ToolStrip toolStrip) { return; } @@ -402,20 +416,14 @@ namespace Greenshot.Base.Controls ApplyLanguage(applyTo, languageBindable.LanguageKey); // Repopulate the combox boxes - if (applyTo is IGreenshotConfigBindable configBindable && applyTo is GreenshotComboBox comboxBox) - { - if (!string.IsNullOrEmpty(configBindable.SectionName) && !string.IsNullOrEmpty(configBindable.PropertyName)) - { - IniSection section = IniConfig.GetIniSection(configBindable.SectionName); - if (section != null) - { - // Only update the language, so get the actual value and than repopulate - Enum currentValue = comboxBox.GetSelectedEnum(); - comboxBox.Populate(section.Values[configBindable.PropertyName].ValueType); - comboxBox.SetValue(currentValue); - } - } - } + if (applyTo is not (IGreenshotConfigBindable configBindable and GreenshotComboBox comboxBox)) return; + if (string.IsNullOrEmpty(configBindable.SectionName) || string.IsNullOrEmpty(configBindable.PropertyName)) return; + IniSection section = IniConfig.GetIniSection(configBindable.SectionName); + if (section == null) return; + // Only update the language, so get the actual value and than repopulate + Enum currentValue = comboxBox.GetSelectedEnum(); + comboxBox.Populate(section.Values[configBindable.PropertyName].ValueType); + comboxBox.SetValue(currentValue); } /// @@ -458,10 +466,9 @@ namespace Greenshot.Base.Controls continue; } - if (!(controlObject is Control applyToControl)) + if (controlObject is not Control applyToControl) { - ToolStripItem applyToItem = controlObject as ToolStripItem; - if (applyToItem == null) + if (controlObject is not ToolStripItem applyToItem) { LOG.DebugFormat("No Control or ToolStripItem: {0}", field.Name); continue; @@ -530,7 +537,7 @@ namespace Greenshot.Base.Controls /// /// Fill all GreenshotControls with the values from the configuration /// - protected void FillFields() + private void FillFields() { foreach (FieldInfo field in GetCachedFields(GetType())) { diff --git a/src/Greenshot.Base/Controls/ThumbnailForm.cs b/src/Greenshot.Base/Controls/ThumbnailForm.cs index c8f22f1f1..d5b8c50e8 100644 --- a/src/Greenshot.Base/Controls/ThumbnailForm.cs +++ b/src/Greenshot.Base/Controls/ThumbnailForm.cs @@ -22,12 +22,15 @@ using System; using System.Drawing; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.DesktopWindowsManager; +using Dapplo.Windows.DesktopWindowsManager.Structs; +using Dapplo.Windows.User32; +using Dapplo.Windows.User32.Enums; using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; -using Greenshot.Base.UnmanagedHelpers; -using Greenshot.Base.UnmanagedHelpers.Enums; -using Greenshot.Base.UnmanagedHelpers.Structs; namespace Greenshot.Base.Controls { @@ -70,7 +73,7 @@ namespace Greenshot.Base.Controls { if (_thumbnailHandle == IntPtr.Zero) return; - DWM.DwmUnregisterThumbnail(_thumbnailHandle); + DwmApi.DwmUnregisterThumbnail(_thumbnailHandle); _thumbnailHandle = IntPtr.Zero; } @@ -83,19 +86,19 @@ namespace Greenshot.Base.Controls { UnregisterThumbnail(); - DWM.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle); + DwmApi.DwmRegisterThumbnail(Handle, window.Handle, out _thumbnailHandle); if (_thumbnailHandle == IntPtr.Zero) return; - var result = DWM.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize); + var result = DwmApi.DwmQueryThumbnailSourceSize(_thumbnailHandle, out var sourceSize); if (result.Failed()) { - DWM.DwmUnregisterThumbnail(_thumbnailHandle); + DwmApi.DwmUnregisterThumbnail(_thumbnailHandle); return; } if (sourceSize.IsEmpty) { - DWM.DwmUnregisterThumbnail(_thumbnailHandle); + DwmApi.DwmUnregisterThumbnail(_thumbnailHandle); return; } @@ -110,17 +113,17 @@ namespace Greenshot.Base.Controls Width = thumbnailWidth; Height = thumbnailHeight; // Prepare the displaying of the Thumbnail - var dwmThumbnailProperties = new DWM_THUMBNAIL_PROPERTIES + var dwmThumbnailProperties = new DwmThumbnailProperties() { Opacity = 255, Visible = true, SourceClientAreaOnly = false, - Destination = new RECT(0, 0, thumbnailWidth, thumbnailHeight) + Destination = new NativeRect(0, 0, thumbnailWidth, thumbnailHeight) }; - result = DWM.DwmUpdateThumbnailProperties(_thumbnailHandle, ref dwmThumbnailProperties); + result = DwmApi.DwmUpdateThumbnailProperties(_thumbnailHandle, ref dwmThumbnailProperties); if (result.Failed()) { - DWM.DwmUnregisterThumbnail(_thumbnailHandle); + DwmApi.DwmUnregisterThumbnail(_thumbnailHandle); return; } @@ -137,13 +140,13 @@ namespace Greenshot.Base.Controls // Make sure it's on "top"! if (parentControl != null) { - User32.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE); + User32Api.SetWindowPos(Handle, parentControl.Handle, 0, 0, 0, 0, WindowPos.SWP_NOMOVE | WindowPos.SWP_NOSIZE | WindowPos.SWP_NOACTIVATE); } } public void AlignToControl(Control alignTo) { - var screenBounds = WindowCapture.GetScreenBounds(); + var screenBounds = DisplayInfo.ScreenBounds; if (screenBounds.Contains(alignTo.Left, alignTo.Top - Height)) { Location = new Point(alignTo.Left + (alignTo.Width / 2) - (Width / 2), alignTo.Top - Height); diff --git a/src/Greenshot.Base/Core/AbstractDestination.cs b/src/Greenshot.Base/Core/AbstractDestination.cs index 96eaf46bc..c76574bab 100644 --- a/src/Greenshot.Base/Core/AbstractDestination.cs +++ b/src/Greenshot.Base/Core/AbstractDestination.cs @@ -24,15 +24,18 @@ using System.Collections.Generic; using System.Drawing; using System.Threading; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Dpi; +using Dapplo.Windows.User32; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; -using Greenshot.Base.UnmanagedHelpers; using log4net; namespace Greenshot.Base.Core { /// - /// Description of AbstractDestination. + /// The AbstractDestination is a default implementation of IDestination /// public abstract class AbstractDestination : IDestination { @@ -41,7 +44,7 @@ namespace Greenshot.Base.Core public virtual int CompareTo(object obj) { - if (!(obj is IDestination other)) + if (obj is not IDestination other) { return 1; } @@ -176,7 +179,7 @@ namespace Greenshot.Base.Core ExportInformation exportInformation = new ExportInformation(Designation, Language.GetString("settings_destination_picker")); var menu = new ContextMenuStrip { - ImageScalingSize = CoreConfig.ScaledIconSize, + ImageScalingSize = CoreConfig.IconSize, Tag = null, TopLevel = true }; @@ -184,10 +187,10 @@ namespace Greenshot.Base.Core menu.Opening += (sender, args) => { // find the DPI settings for the screen where this is going to land - var screenDpi = DpiHelper.GetDpi(menu.Location); - var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, screenDpi); + var screenDpi = NativeDpiMethods.GetDpi(menu.Location); + var scaledIconSize = DpiCalculator.ScaleWithDpi(CoreConfig.IconSize, screenDpi); menu.SuspendLayout(); - var fontSize = DpiHelper.ScaleWithDpi(12f, screenDpi); + var fontSize = DpiCalculator.ScaleWithDpi(12f, screenDpi); menu.Font = new Font(FontFamily.GenericSansSerif, fontSize, FontStyle.Regular, GraphicsUnit.Pixel); menu.ImageScalingSize = scaledIconSize; menu.ResumeLayout(); @@ -304,7 +307,7 @@ namespace Greenshot.Base.Core ShowMenuAtCursor(menu); return exportInformation; } - + /// /// This method will show the supplied context menu at the mouse cursor, also makes sure it has focus and it's not visible in the taskbar. /// @@ -312,21 +315,21 @@ namespace Greenshot.Base.Core private static void ShowMenuAtCursor(ContextMenuStrip menu) { // find a suitable location - Point location = Cursor.Position; - Rectangle menuRectangle = new Rectangle(location, menu.Size); + NativePoint location = Cursor.Position; + var menuRectangle = new NativeRect(location, menu.Size); - menuRectangle.Intersect(WindowCapture.GetScreenBounds()); + menuRectangle = menuRectangle.Intersect(DisplayInfo.ScreenBounds); if (menuRectangle.Height < menu.Height) { - location.Offset(-40, -(menuRectangle.Height - menu.Height)); + location = location.Offset(-40, -(menuRectangle.Height - menu.Height)); } else { - location.Offset(-40, -10); + location = location.Offset(-40, -10); } // This prevents the problem that the context menu shows in the task-bar - User32.SetForegroundWindow(SimpleServiceProvider.Current.GetInstance().ContextMenuStrip.Handle); + User32Api.SetForegroundWindow(SimpleServiceProvider.Current.GetInstance().ContextMenuStrip.Handle); menu.Show(location); menu.Focus(); diff --git a/src/Greenshot.Base/Core/AnimationHelpers.cs b/src/Greenshot.Base/Core/AnimationHelpers.cs index 8b58a1c34..fd693683f 100644 --- a/src/Greenshot.Base/Core/AnimationHelpers.cs +++ b/src/Greenshot.Base/Core/AnimationHelpers.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using Dapplo.Windows.Common.Structs; namespace Greenshot.Base.Core { @@ -280,19 +281,19 @@ namespace Greenshot.Base.Core /// /// Implementation of the RectangleAnimator /// - public class RectangleAnimator : AnimatorBase + public class RectangleAnimator : AnimatorBase { - public RectangleAnimator(Rectangle first, Rectangle last, int frames) + public RectangleAnimator(NativeRect first, NativeRect last, int frames) : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) { } - public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType) + public RectangleAnimator(NativeRect first, NativeRect last, int frames, EasingType easingType) : base(first, last, frames, easingType, EasingMode.EaseIn) { } - public RectangleAnimator(Rectangle first, Rectangle last, int frames, EasingType easingType, EasingMode easingMode) + public RectangleAnimator(NativeRect first, NativeRect last, int frames, EasingType easingType, EasingMode easingMode) : base(first, last, frames, easingType, easingMode) { } @@ -300,8 +301,8 @@ namespace Greenshot.Base.Core /// /// Calculate the next frame object /// - /// Rectangle - public override Rectangle Next() + /// NativeRect + public override NativeRect Next() { if (!NextFrame) { @@ -317,7 +318,7 @@ namespace Greenshot.Base.Core double dh = Last.Height - First.Height; int width = First.Width + (int) (easingValue * dw); int height = First.Height + (int) (easingValue * dh); - Current = new Rectangle(x, y, width, height); + Current = new NativeRect(x, y, width, height); return Current; } @@ -326,19 +327,19 @@ namespace Greenshot.Base.Core /// /// Implementation of the PointAnimator /// - public class PointAnimator : AnimatorBase + public class PointAnimator : AnimatorBase { - public PointAnimator(Point first, Point last, int frames) + public PointAnimator(NativePoint first, NativePoint last, int frames) : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) { } - public PointAnimator(Point first, Point last, int frames, EasingType easingType) + public PointAnimator(NativePoint first, NativePoint last, int frames, EasingType easingType) : base(first, last, frames, easingType, EasingMode.EaseIn) { } - public PointAnimator(Point first, Point last, int frames, EasingType easingType, EasingMode easingMode) + public PointAnimator(NativePoint first, NativePoint last, int frames, EasingType easingType, EasingMode easingMode) : base(first, last, frames, easingType, easingMode) { } @@ -347,7 +348,7 @@ namespace Greenshot.Base.Core /// Calculate the next frame value /// /// Point - public override Point Next() + public override NativePoint Next() { if (NextFrame) { @@ -357,7 +358,7 @@ namespace Greenshot.Base.Core int x = First.X + (int) (easingValue * dx); int y = First.Y + (int) (easingValue * dy); - Current = new Point(x, y); + Current = new NativePoint(x, y); } return Current; @@ -367,19 +368,19 @@ namespace Greenshot.Base.Core /// /// Implementation of the SizeAnimator /// - public class SizeAnimator : AnimatorBase + public class SizeAnimator : AnimatorBase { - public SizeAnimator(Size first, Size last, int frames) + public SizeAnimator(NativeSize first, NativeSize last, int frames) : base(first, last, frames, EasingType.Linear, EasingMode.EaseIn) { } - public SizeAnimator(Size first, Size last, int frames, EasingType easingType) + public SizeAnimator(NativeSize first, NativeSize last, int frames, EasingType easingType) : base(first, last, frames, easingType, EasingMode.EaseIn) { } - public SizeAnimator(Size first, Size last, int frames, EasingType easingType, EasingMode easingMode) + public SizeAnimator(NativeSize first, NativeSize last, int frames, EasingType easingType, EasingMode easingMode) : base(first, last, frames, easingType, easingMode) { } @@ -388,7 +389,7 @@ namespace Greenshot.Base.Core /// Calculate the next frame values /// /// Size - public override Size Next() + public override NativeSize Next() { if (NextFrame) { @@ -397,7 +398,7 @@ namespace Greenshot.Base.Core double dh = Last.Height - First.Height; int width = First.Width + (int) (easingValue * dw); int height = First.Height + (int) (easingValue * dh); - Current = new Size(width, height); + Current = new NativeSize(width, height); } return Current; diff --git a/src/Greenshot.Base/Core/Capture.cs b/src/Greenshot.Base/Core/Capture.cs index 347cd0067..0be688727 100644 --- a/src/Greenshot.Base/Core/Capture.cs +++ b/src/Greenshot.Base/Core/Capture.cs @@ -22,6 +22,9 @@ using System; using System.Drawing; using System.Drawing.Imaging; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.User32; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Ocr; using log4net; @@ -36,18 +39,18 @@ namespace Greenshot.Base.Core { private static readonly ILog Log = LogManager.GetLogger(typeof(Capture)); - private Rectangle _screenBounds; + private NativeRect _screenBounds; /// /// Get/Set the screen bounds /// - public Rectangle ScreenBounds + public NativeRect ScreenBounds { get { - if (_screenBounds == Rectangle.Empty) + if (_screenBounds.IsEmpty) { - _screenBounds = WindowCapture.GetScreenBounds(); + _screenBounds = DisplayInfo.ScreenBounds; } return _screenBounds; @@ -124,23 +127,23 @@ namespace Greenshot.Base.Core ///
public bool CursorVisible { get; set; } - private Point _cursorLocation = Point.Empty; + private NativePoint _cursorLocation = NativePoint.Empty; /// /// Get/Set the CursorLocation /// - public Point CursorLocation + public NativePoint CursorLocation { get => _cursorLocation; set => _cursorLocation = value; } - private Point _location = Point.Empty; + private NativePoint _location = NativePoint.Empty; /// /// Get/set the Location /// - public Point Location + public NativePoint Location { get => _location; set => _location = value; @@ -162,7 +165,7 @@ namespace Greenshot.Base.Core ///
public Capture() { - _screenBounds = WindowCapture.GetScreenBounds(); + _screenBounds = DisplayInfo.ScreenBounds; _captureDetails = new CaptureDetails(); } @@ -214,8 +217,8 @@ namespace Greenshot.Base.Core /// /// Crops the capture to the specified rectangle (with Bitmap coordinates!) /// - /// Rectangle with bitmap coordinates - public bool Crop(Rectangle cropRectangle) + /// NativeRect with bitmap coordinates + public bool Crop(NativeRect cropRectangle) { Log.Debug("Cropping to: " + cropRectangle); if (!ImageHelper.Crop(ref _image, ref cropRectangle)) @@ -245,7 +248,7 @@ namespace Greenshot.Base.Core /// y coordinates to move the mouse public void MoveMouseLocation(int x, int y) { - _cursorLocation.Offset(x, y); + _cursorLocation = _cursorLocation.Offset(x, y); } // TODO: Enable when the elements are usable again. @@ -261,7 +264,7 @@ namespace Greenshot.Base.Core //private void MoveElements(List listOfElements, int x, int y) { // foreach(ICaptureElement childElement in listOfElements) { - // Rectangle bounds = childElement.Bounds; + // NativeRect bounds = childElement.Bounds; // bounds.Offset(x, y); // childElement.Bounds = bounds; // MoveElements(childElement.Children, x, y); diff --git a/src/Greenshot.Base/Core/CaptureHandler.cs b/src/Greenshot.Base/Core/CaptureHandler.cs index f807666c7..74f58b555 100644 --- a/src/Greenshot.Base/Core/CaptureHandler.cs +++ b/src/Greenshot.Base/Core/CaptureHandler.cs @@ -20,15 +20,16 @@ */ using System.Drawing; +using Dapplo.Windows.Common.Structs; namespace Greenshot.Base.Core { /// /// This is the method signature which is used to capture a rectangle from the screen. /// - /// + /// NativeRect /// Captured Bitmap - public delegate Bitmap CaptureScreenRectangleHandler(Rectangle captureBounds); + public delegate Bitmap CaptureScreenRectangleHandler(NativeRect captureBounds); /// /// This is a hack to experiment with different screen capture routines diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs index 75019befb..7a30a1143 100644 --- a/src/Greenshot.Base/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -30,13 +30,17 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Windows.Forms; +using Dapplo.Windows.Clipboard; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Gdi32.Enums; +using Dapplo.Windows.Gdi32.Structs; +using Dapplo.Windows.User32; using Greenshot.Base.Core.Enums; using Greenshot.Base.Core.FileFormatHandlers; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Plugin; -using Greenshot.Base.UnmanagedHelpers; using log4net; using HtmlDocument = HtmlAgilityPack.HtmlDocument; @@ -115,12 +119,12 @@ EndSelection:<<<<<<<4 string owner = null; try { - IntPtr hWnd = User32.GetClipboardOwner(); + IntPtr hWnd = ClipboardNative.CurrentOwner; if (hWnd != IntPtr.Zero) { try { - User32.GetWindowThreadProcessId(hWnd, out var pid); + User32Api.GetWindowThreadProcessId(hWnd, out var pid); using Process me = Process.GetCurrentProcess(); using Process ownerProcess = Process.GetProcessById(pid); // Exclude myself @@ -142,9 +146,7 @@ EndSelection:<<<<<<<4 catch (Exception e) { Log.Warn("Non critical error: Couldn't get clipboard process, trying to use the title.", e); - var title = new StringBuilder(260, 260); - User32.GetWindowText(hWnd, title, title.Capacity); - owner = title.ToString(); + owner = User32Api.GetText(hWnd); } } } @@ -282,6 +284,9 @@ EndSelection:<<<<<<<4 { if (dataObject == null) return false; + IList formats = GetFormats(dataObject); + Log.DebugFormat("Found formats: {0}", string.Join(",", formats)); + if (dataObject.GetDataPresent(DataFormats.Bitmap) || dataObject.GetDataPresent(DataFormats.Dib) || dataObject.GetDataPresent(DataFormats.Tiff) @@ -638,8 +643,6 @@ EndSelection:<<<<<<<4 { continue; } - - IDrawableContainer drawableContainer = null; using FileStream fileStream = new FileStream(imageFile, FileMode.Open, FileAccess.Read, FileShare.Read); IEnumerable drawableContainers; try @@ -1021,20 +1024,17 @@ EndSelection:<<<<<<<4 dibV5Stream = new MemoryStream(); // Create the BITMAPINFOHEADER - var header = new BITMAPINFOHEADERV5(imageToSave.Width, imageToSave.Height, 32) - { - // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? - biCompression = BI_COMPRESSION.BI_BITFIELDS - }; + var header = BitmapV5Header.Create(imageToSave.Width, imageToSave.Height, 32); + // Make sure we have BI_BITFIELDS, this seems to be normal for Format17? + header.Compression = BitmapCompressionMethods.BI_BITFIELDS; // Create a byte[] to write byte[] headerBytes = BinaryStructHelper.ToByteArray(header); // Write the BITMAPINFOHEADER to the stream dibV5Stream.Write(headerBytes, 0, headerBytes.Length); // As we have specified BI_COMPRESSION.BI_BITFIELDS, the BitfieldColorMask needs to be added + // This also makes sure the default values are set BitfieldColorMask colorMask = new BitfieldColorMask(); - // Make sure the values are set - colorMask.InitValues(); // Create the byte[] from the struct byte[] colorMaskBytes = BinaryStructHelper.ToByteArray(colorMask); Array.Reverse(colorMaskBytes); @@ -1125,7 +1125,7 @@ EndSelection:<<<<<<<4 private static byte[] BitmapToByteArray(Bitmap bitmap) { // Lock the bitmap's bits. - Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); + var rect = new NativeRect(0, 0, bitmap.Width, bitmap.Height); BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat); int absStride = Math.Abs(bmpData.Stride); diff --git a/src/Greenshot.Base/Core/CoreConfiguration.cs b/src/Greenshot.Base/Core/CoreConfiguration.cs index ead32a464..580af8918 100644 --- a/src/Greenshot.Base/Core/CoreConfiguration.cs +++ b/src/Greenshot.Base/Core/CoreConfiguration.cs @@ -24,9 +24,9 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; -using System.Linq; using System.Reflection; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; @@ -322,17 +322,17 @@ namespace Greenshot.Base.Core public bool ProcessEXIFOrientation { get; set; } [IniProperty("LastCapturedRegion", Description = "The last used region, for reuse in the capture last region")] - public Rectangle LastCapturedRegion { get; set; } + public NativeRect LastCapturedRegion { get; set; } [IniProperty("Win10BorderCrop", Description = "The capture is cropped with these settings, e.g. when you don't want to color around it -1,-1"), DefaultValue("0,0")] - public Size Win10BorderCrop { get; set; } + public NativeSize Win10BorderCrop { get; set; } - private Size _iconSize; + private NativeSize _iconSize; [IniProperty("BaseIconSize", Description = "Defines the base size of the icons (e.g. for the buttons in the editor), default value 16,16 and it's scaled to the current DPI", DefaultValue = "16,16")] - public Size IconSize + public NativeSize IconSize { get { return _iconSize; } set @@ -369,13 +369,11 @@ namespace Greenshot.Base.Core } } } - - public Size ScaledIconSize => DpiHelper.ScaleWithCurrentDpi(_iconSize); - - [IniProperty("WebRequestTimeout", Description = "The connect timeout value for webrequets, these are seconds", DefaultValue = "100")] + + [IniProperty("WebRequestTimeout", Description = "The connect timeout value for web requests, these are seconds", DefaultValue = "100")] public int WebRequestTimeout { get; set; } - [IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for webrequets, these are seconds", DefaultValue = "100")] + [IniProperty("WebRequestReadWriteTimeout", Description = "The read/write timeout value for web requests, these are seconds", DefaultValue = "100")] public int WebRequestReadWriteTimeout { get; set; } public bool UseLargeIcons => IconSize.Width >= 32 || IconSize.Height >= 32; diff --git a/src/Greenshot.Base/Core/DpiHelper.cs b/src/Greenshot.Base/Core/DpiHelper.cs deleted file mode 100644 index d3c7e61b6..000000000 --- a/src/Greenshot.Base/Core/DpiHelper.cs +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using Greenshot.Base.Core.Enums; -using Greenshot.Base.UnmanagedHelpers; -using Greenshot.Base.UnmanagedHelpers.Enums; -using Greenshot.Base.UnmanagedHelpers.Structs; - -namespace Greenshot.Base.Core -{ - /// - /// This handles DPI changes see - /// Writing DPI-Aware Desktop and Win32 Applications - /// - public static class DpiHelper - { - /// - /// This is the default DPI for the screen - /// - public const uint DefaultScreenDpi = 96; - - /// - /// Retrieve the current DPI for the UI element which is related to this DpiHandler - /// - public static uint Dpi { get; private set; } = WindowsVersion.IsWindows10OrLater ? GetDpiForSystem() : DefaultScreenDpi; - - /// - /// Calculate a DPI scale factor - /// - /// uint - /// double - public static float DpiScaleFactor(uint dpi) - { - if (dpi == 0) - { - dpi = Dpi; - } - - return (float) dpi / DefaultScreenDpi; - } - - /// - /// Scale the supplied number according to the supplied dpi - /// - /// double with e.g. the width 16 for 16x16 images - /// current dpi, normal is 96. - /// A function which can modify the scale factor - /// double with the scaled number - public static float ScaleWithDpi(float someNumber, uint dpi, Func scaleModifier = null) - { - var dpiScaleFactor = DpiScaleFactor(dpi); - if (scaleModifier != null) - { - dpiScaleFactor = scaleModifier(dpiScaleFactor); - } - - return dpiScaleFactor * someNumber; - } - - /// - /// Scale the supplied Size according to the supplied dpi - /// - /// Size to resize - /// current dpi, normal is 96. - /// A function which can modify the scale factor - /// NativeSize scaled - public static Size ScaleWithDpi(Size size, uint dpi, Func scaleModifier = null) - { - var dpiScaleFactor = DpiScaleFactor(dpi); - if (scaleModifier != null) - { - dpiScaleFactor = scaleModifier(dpiScaleFactor); - } - - return new Size((int) (dpiScaleFactor * size.Width), (int) (dpiScaleFactor * size.Height)); - } - - /// - /// Scale the supplied NativeSize to the current dpi - /// - /// NativeSize to scale - /// A function which can modify the scale factor - /// NativeSize scaled - public static Size ScaleWithCurrentDpi(Size size, Func scaleModifier = null) - { - return ScaleWithDpi(size, Dpi, scaleModifier); - } - - /// - /// Return the DPI for the screen which the location is located on - /// - /// POINT - /// uint - public static uint GetDpi(POINT location) - { - if (!WindowsVersion.IsWindows81OrLater) - { - return DefaultScreenDpi; - } - RECT rect = new RECT(location.X, location.Y, 1, 1); - IntPtr hMonitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONEAREST); - var result = GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY); - if (result.Succeeded()) - { - return dpiX; - } - - return DefaultScreenDpi; - } - - - /// - /// Retrieve the DPI value for the supplied window handle - /// - /// IntPtr - /// dpi value - public static uint GetDpi(IntPtr hWnd) - { - if (!User32.IsWindow(hWnd)) - { - return DefaultScreenDpi; - } - - // Use the easiest method, but this only works for Windows 10 - if (WindowsVersion.IsWindows10OrLater) - { - return GetDpiForWindow(hWnd); - } - - // Use the second easiest method, but this only works for Windows 8.1 or later - if (WindowsVersion.IsWindows81OrLater) - { - var hMonitor = User32.MonitorFromWindow(hWnd, MonitorFrom.DefaultToNearest); - // ReSharper disable once UnusedVariable - var result = GetDpiForMonitor(hMonitor, MonitorDpiType.EffectiveDpi, out var dpiX, out var dpiY); - if (result.Succeeded()) - { - return dpiX; - } - } - - // Fallback to the global DPI settings - using var hdc = SafeWindowDcHandle.FromWindow(hWnd); - if (hdc == null) - { - return DefaultScreenDpi; - } - - return (uint) GDI32.GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX); - } - - /// - /// See more at GetDpiForWindow function - /// Returns the dots per inch (dpi) value for the associated window. - /// - /// IntPtr - /// uint with dpi - [DllImport("user32.dll")] - private static extern uint GetDpiForWindow(IntPtr hWnd); - - /// - /// See - /// GetDpiForMonitor function - /// Queries the dots per inch (dpi) of a display. - /// - /// IntPtr - /// MonitorDpiType - /// out int for the horizontal dpi - /// out int for the vertical dpi - /// true if all okay - [DllImport("shcore.dll", SetLastError = true)] - private static extern HResult GetDpiForMonitor(IntPtr hMonitor, MonitorDpiType dpiType, out uint dpiX, out uint dpiY); - - /// - /// See GetDpiForSystem function - /// Returns the system DPI. - /// - /// uint with the system DPI - [DllImport("user32.dll")] - private static extern uint GetDpiForSystem(); - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/EffectConverter.cs b/src/Greenshot.Base/Core/EffectConverter.cs index 40cb1f5ae..e5742b803 100644 --- a/src/Greenshot.Base/Core/EffectConverter.cs +++ b/src/Greenshot.Base/Core/EffectConverter.cs @@ -3,6 +3,8 @@ using System.ComponentModel; using System.Drawing; using System.Globalization; using System.Text; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Effects; namespace Greenshot.Base.Core @@ -136,16 +138,16 @@ namespace Greenshot.Base.Core break; case "ShadowOffset": - Point shadowOffset = new Point(); + NativePoint shadowOffset = new NativePoint(); string[] coordinates = pair[1].Split(','); if (int.TryParse(coordinates[0], out var shadowOffsetX)) { - shadowOffset.X = shadowOffsetX; + shadowOffset = shadowOffset.ChangeX(shadowOffsetX); } if (int.TryParse(coordinates[1], out var shadowOffsetY)) { - shadowOffset.Y = shadowOffsetY; + shadowOffset = shadowOffset.ChangeY(shadowOffsetY); } effect.ShadowOffset = shadowOffset; diff --git a/src/Greenshot.Base/Core/Enums/HResult.cs b/src/Greenshot.Base/Core/Enums/HResult.cs deleted file mode 100644 index a971c8801..000000000 --- a/src/Greenshot.Base/Core/Enums/HResult.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom -// -// For more information see: https://getgreenshot.org/ -// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 1 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.Core.Enums -{ - /// - /// The HRESULT represents Windows error codes - /// See wikipedia - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum HResult - { - S_OK = 0, - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/Enums/MonitorDpiType.cs b/src/Greenshot.Base/Core/Enums/MonitorDpiType.cs deleted file mode 100644 index e434f5bb3..000000000 --- a/src/Greenshot.Base/Core/Enums/MonitorDpiType.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Dapplo and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; - -namespace Greenshot.Base.Core.Enums -{ - /// - /// See - /// - /// MONITOR_DPI_TYPE - /// enumeration - /// - /// - [Flags] - public enum MonitorDpiType - { - /// - /// The effective DPI. - /// This value should be used when determining the correct scale factor for scaling UI elements. - /// This incorporates the scale factor set by the user for this specific display. - /// - EffectiveDpi = 0, - - /// - /// The angular DPI. - /// This DPI ensures rendering at a compliant angular resolution on the screen. - /// This does not include the scale factor set by the user for this specific display - /// - AngularDpi = 1, - - /// - /// The raw DPI. - /// This value is the linear DPI of the screen as measured on the screen itself. - /// Use this value when you want to read the pixel density and not the recommended scaling setting. - /// This does not include the scale factor set by the user for this specific display and is not guaranteed to be a - /// supported DPI value. - /// - RawDpi = 2 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/Enums/MonitorFrom.cs b/src/Greenshot.Base/Core/Enums/MonitorFrom.cs deleted file mode 100644 index f9d9fcc2b..000000000 --- a/src/Greenshot.Base/Core/Enums/MonitorFrom.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Dapplo and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; - -namespace Greenshot.Base.Core.Enums -{ - /// - /// Flags for the MonitorFromRect / MonitorFromWindow "flags" field - /// see MonitorFromRect function - /// or see MonitorFromWindow function - /// - [Flags] - public enum MonitorFrom : uint - { - /// - /// Returns a handle to the display monitor that is nearest to the rectangle. - /// - DefaultToNearest = 0, - - /// - /// Returns NULL. (why??) - /// - DefaultToNull = 1, - - /// - /// Returns a handle to the primary display monitor. - /// - DefaultToPrimary = 2 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs b/src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs deleted file mode 100644 index 6d18cdbe6..000000000 --- a/src/Greenshot.Base/Core/Enums/PrintWindowFlags.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace Greenshot.Base.Core.Enums -{ - [Flags] - public enum PrintWindowFlags : uint - { - /// Render the entire window. - PW_ENTIREWINDOW = 0, - - /// Only the client area of the window is copied to hdcBlt. By default, the entire window is copied. - PW_CLIENTONLY = 1, - - /// Undocumented - PW_RENDERFULLCONTENT = 0x00000002, - } -} diff --git a/src/Greenshot.Base/Core/EnvironmentInfo.cs b/src/Greenshot.Base/Core/EnvironmentInfo.cs index b1e907912..30811fb69 100644 --- a/src/Greenshot.Base/Core/EnvironmentInfo.cs +++ b/src/Greenshot.Base/Core/EnvironmentInfo.cs @@ -23,8 +23,12 @@ using System; using System.Reflection; using System.Runtime.InteropServices; using System.Text; +using Dapplo.Windows.Kernel32; +using Dapplo.Windows.Kernel32.Enums; +using Dapplo.Windows.Kernel32.Structs; +using Dapplo.Windows.User32; +using Dapplo.Windows.Common.Extensions; using Greenshot.Base.IniFile; -using Greenshot.Base.UnmanagedHelpers; using Microsoft.Win32; namespace Greenshot.Base.Core @@ -163,7 +167,7 @@ namespace Greenshot.Base.Core } // Get some important information for fixing GDI related Problems - environment.AppendFormat("GDI object count: {0}", User32.GetGuiResourcesGDICount()); + environment.AppendFormat("GDI object count: {0}", User32Api.GetGuiResourcesGdiCount()); if (newline) { environment.AppendLine(); @@ -173,7 +177,7 @@ namespace Greenshot.Base.Core environment.Append(", "); } - environment.AppendFormat("User object count: {0}", User32.GetGuiResourcesUserCount()); + environment.AppendFormat("User object count: {0}", User32Api.GetGuiResourcesUserCount()); } else { @@ -291,33 +295,33 @@ namespace Greenshot.Base.Core string edition = string.Empty; OperatingSystem osVersion = Environment.OSVersion; - OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create(); + var osVersionInfo = OsVersionInfoEx.Create(); - if (GetVersionEx(ref osVersionInfo)) + if (Kernel32Api.GetVersionEx(ref osVersionInfo)) { int majorVersion = osVersion.Version.Major; int minorVersion = osVersion.Version.Minor; - byte productType = osVersionInfo.ProductType; - ushort suiteMask = osVersionInfo.SuiteMask; + var productType = osVersionInfo.ProductType; + var suiteMask = osVersionInfo.SuiteMask; if (majorVersion == 4) { - if (productType == VER_NT_WORKSTATION) + if (productType == WindowsProductTypes.VER_NT_WORKSTATION) { // Windows NT 4.0 Workstation edition = "Workstation"; } - else if (productType == VER_NT_SERVER) + else if (productType == WindowsProductTypes.VER_NT_SERVER) { - edition = (suiteMask & VER_SUITE_ENTERPRISE) != 0 ? "Enterprise Server" : "Standard Server"; + edition = (suiteMask & WindowsSuites.Enterprise) != 0 ? "Enterprise Server" : "Standard Server"; } } else if (majorVersion == 5) { - if (productType == VER_NT_WORKSTATION) + if (productType == WindowsProductTypes.VER_NT_WORKSTATION) { - if ((suiteMask & VER_SUITE_PERSONAL) != 0) + if ((suiteMask & WindowsSuites.Personal) != 0) { // Windows XP Home Edition edition = "Home"; @@ -328,16 +332,16 @@ namespace Greenshot.Base.Core edition = "Professional"; } } - else if (productType == VER_NT_SERVER) + else if (productType == WindowsProductTypes.VER_NT_SERVER) { if (minorVersion == 0) { - if ((suiteMask & VER_SUITE_DATACENTER) != 0) + if ((suiteMask & WindowsSuites.DataCenter) != 0) { // Windows 2000 Datacenter Server edition = "Datacenter Server"; } - else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0) + else if ((suiteMask & WindowsSuites.Enterprise) != 0) { // Windows 2000 Advanced Server edition = "Advanced Server"; @@ -350,17 +354,17 @@ namespace Greenshot.Base.Core } else { - if ((suiteMask & VER_SUITE_DATACENTER) != 0) + if ((suiteMask & WindowsSuites.DataCenter) != 0) { // Windows Server 2003 Datacenter Edition edition = "Datacenter"; } - else if ((suiteMask & VER_SUITE_ENTERPRISE) != 0) + else if ((suiteMask & WindowsSuites.Enterprise) != 0) { // Windows Server 2003 Enterprise Edition edition = "Enterprise"; } - else if ((suiteMask & VER_SUITE_BLADE) != 0) + else if ((suiteMask & WindowsSuites.Blade) != 0) { // Windows Server 2003 Web Edition edition = "Web Edition"; @@ -376,122 +380,9 @@ namespace Greenshot.Base.Core else if (majorVersion == 6) { - if (GetProductInfo(majorVersion, minorVersion, osVersionInfo.ServicePackMajor, osVersionInfo.ServicePackMinor, out var ed)) + if (Kernel32Api.GetProductInfo(majorVersion, minorVersion, osVersionInfo.ServicePackMajor, osVersionInfo.ServicePackMinor, out var windowsProduct)) { - switch (ed) - { - case PRODUCT_BUSINESS: - edition = "Business"; - break; - case PRODUCT_BUSINESS_N: - edition = "Business N"; - break; - case PRODUCT_CLUSTER_SERVER: - edition = "HPC Edition"; - break; - case PRODUCT_DATACENTER_SERVER: - edition = "Datacenter Server"; - break; - case PRODUCT_DATACENTER_SERVER_CORE: - edition = "Datacenter Server (core installation)"; - break; - case PRODUCT_ENTERPRISE: - edition = "Enterprise"; - break; - case PRODUCT_ENTERPRISE_N: - edition = "Enterprise N"; - break; - case PRODUCT_ENTERPRISE_SERVER: - edition = "Enterprise Server"; - break; - case PRODUCT_ENTERPRISE_SERVER_CORE: - edition = "Enterprise Server (core installation)"; - break; - case PRODUCT_ENTERPRISE_SERVER_CORE_V: - edition = "Enterprise Server without Hyper-V (core installation)"; - break; - case PRODUCT_ENTERPRISE_SERVER_IA64: - edition = "Enterprise Server for Itanium-based Systems"; - break; - case PRODUCT_ENTERPRISE_SERVER_V: - edition = "Enterprise Server without Hyper-V"; - break; - case PRODUCT_HOME_BASIC: - edition = "Home Basic"; - break; - case PRODUCT_HOME_BASIC_N: - edition = "Home Basic N"; - break; - case PRODUCT_HOME_PREMIUM: - edition = "Home Premium"; - break; - case PRODUCT_HOME_PREMIUM_N: - edition = "Home Premium N"; - break; - case PRODUCT_HYPERV: - edition = "Microsoft Hyper-V Server"; - break; - case PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT: - edition = "Windows Essential Business Management Server"; - break; - case PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING: - edition = "Windows Essential Business Messaging Server"; - break; - case PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY: - edition = "Windows Essential Business Security Server"; - break; - case PRODUCT_SERVER_FOR_SMALLBUSINESS: - edition = "Windows Essential Server Solutions"; - break; - case PRODUCT_SERVER_FOR_SMALLBUSINESS_V: - edition = "Windows Essential Server Solutions without Hyper-V"; - break; - case PRODUCT_SMALLBUSINESS_SERVER: - edition = "Windows Small Business Server"; - break; - case PRODUCT_STANDARD_SERVER: - edition = "Standard Server"; - break; - case PRODUCT_STANDARD_SERVER_CORE: - edition = "Standard Server (core installation)"; - break; - case PRODUCT_STANDARD_SERVER_CORE_V: - edition = "Standard Server without Hyper-V (core installation)"; - break; - case PRODUCT_STANDARD_SERVER_V: - edition = "Standard Server without Hyper-V"; - break; - case PRODUCT_STARTER: - edition = "Starter"; - break; - case PRODUCT_STORAGE_ENTERPRISE_SERVER: - edition = "Enterprise Storage Server"; - break; - case PRODUCT_STORAGE_EXPRESS_SERVER: - edition = "Express Storage Server"; - break; - case PRODUCT_STORAGE_STANDARD_SERVER: - edition = "Standard Storage Server"; - break; - case PRODUCT_STORAGE_WORKGROUP_SERVER: - edition = "Workgroup Storage Server"; - break; - case PRODUCT_UNDEFINED: - edition = "Unknown product"; - break; - case PRODUCT_ULTIMATE: - edition = "Ultimate"; - break; - case PRODUCT_ULTIMATE_N: - edition = "Ultimate N"; - break; - case PRODUCT_WEB_SERVER: - edition = "Web Server"; - break; - case PRODUCT_WEB_SERVER_CORE: - edition = "Web Server (core installation)"; - break; - } + edition = windowsProduct.GetEnumDescription(); } } } @@ -518,13 +409,13 @@ namespace Greenshot.Base.Core string name = "unknown"; OperatingSystem osVersion = Environment.OSVersion; - OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create(); - if (GetVersionEx(ref osVersionInfo)) + var osVersionInfo = OsVersionInfoEx.Create(); + if (Kernel32Api.GetVersionEx(ref osVersionInfo)) { int majorVersion = osVersion.Version.Major; int minorVersion = osVersion.Version.Minor; - byte productType = osVersionInfo.ProductType; - ushort suiteMask = osVersionInfo.SuiteMask; + var productType = osVersionInfo.ProductType; + var suiteMask = osVersionInfo.SuiteMask; switch (osVersion.Platform) { case PlatformID.Win32Windows: @@ -563,10 +454,10 @@ namespace Greenshot.Base.Core case 4: switch (productType) { - case 1: + case WindowsProductTypes.VER_NT_WORKSTATION: name = "Windows NT 4.0"; break; - case 3: + case WindowsProductTypes.VER_NT_SERVER: name = "Windows NT 4.0 Server"; break; } @@ -581,18 +472,18 @@ namespace Greenshot.Base.Core case 1: name = suiteMask switch { - 0x0200 => "Windows XP Professional", + WindowsSuites.Personal => "Windows XP Professional", _ => "Windows XP" }; break; case 2: name = suiteMask switch { - 0x0200 => "Windows XP Professional x64", - 0x0002 => "Windows Server 2003 Enterprise", - 0x0080 => "Windows Server 2003 Data Center", - 0x0400 => "Windows Server 2003 Web Edition", - 0x8000 => "Windows Home Server", + WindowsSuites.Personal => "Windows XP Professional x64", + WindowsSuites.Enterprise => "Windows Server 2003 Enterprise", + WindowsSuites.DataCenter => "Windows Server 2003 Data Center", + WindowsSuites.Blade => "Windows Server 2003 Web Edition", + WindowsSuites.WHServer => "Windows Home Server", _ => "Windows Server 2003" }; break; @@ -605,14 +496,14 @@ namespace Greenshot.Base.Core case 0: name = productType switch { - 3 => "Windows Server 2008", + WindowsProductTypes.VER_NT_SERVER => "Windows Server 2008", _ => "Windows Vista" }; break; case 1: name = productType switch { - 3 => "Windows Server 2008 R2", + WindowsProductTypes.VER_NT_SERVER => "Windows Server 2008 R2", _ => "Windows 7" }; break; @@ -640,134 +531,6 @@ namespace Greenshot.Base.Core } } - [DllImport("Kernel32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool GetProductInfo( - int osMajorVersion, - int osMinorVersion, - int spMajorVersion, - int spMinorVersion, - out int edition); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetVersionEx(ref OSVERSIONINFOEX osVersionInfo); - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - private unsafe struct OSVERSIONINFOEX - { - /// - /// The size of this data structure, in bytes. Set this member to sizeof(OSVERSIONINFOEX). - /// - private int _dwOSVersionInfoSize; - - private readonly int _dwMajorVersion; - private readonly int _dwMinorVersion; - private readonly int _dwBuildNumber; - private readonly int _dwPlatformId; - private fixed char _szCSDVersion[128]; - private readonly short _wServicePackMajor; - private readonly short _wServicePackMinor; - private readonly ushort _wSuiteMask; - private readonly byte _wProductType; - private readonly byte _wReserved; - - /// A null-terminated string, such as "Service Pack 3", that indicates the latest Service Pack installed on the system. - /// If no Service Pack has been installed, the string is empty. - /// - public string ServicePackVersion - { - get - { - fixed (char* servicePackVersion = _szCSDVersion) - { - return new string(servicePackVersion); - } - } - } - - /// - /// The major version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the - /// major version number is 3. - /// If no Service Pack has been installed, the value is zero. - /// - public short ServicePackMajor => _wServicePackMajor; - - /// - /// The minor version number of the latest Service Pack installed on the system. For example, for Service Pack 3, the - /// minor version number is 0. - /// - public short ServicePackMinor => _wServicePackMinor; - - /// - /// A bit mask that identifies the product suites available on the system. This member can be a combination of the - /// following values. - /// - public ushort SuiteMask => _wSuiteMask; - - /// - /// Any additional information about the system. - /// - public byte ProductType => _wProductType; - - /// - /// Factory for an empty OsVersionInfoEx - /// - /// OSVERSIONINFOEX - public static OSVERSIONINFOEX Create() - { - return new OSVERSIONINFOEX - { - _dwOSVersionInfoSize = Marshal.SizeOf(typeof(OSVERSIONINFOEX)) - }; - } - } - - private const int PRODUCT_UNDEFINED = 0x00000000; - private const int PRODUCT_ULTIMATE = 0x00000001; - private const int PRODUCT_HOME_BASIC = 0x00000002; - private const int PRODUCT_HOME_PREMIUM = 0x00000003; - private const int PRODUCT_ENTERPRISE = 0x00000004; - private const int PRODUCT_HOME_BASIC_N = 0x00000005; - private const int PRODUCT_BUSINESS = 0x00000006; - private const int PRODUCT_STANDARD_SERVER = 0x00000007; - private const int PRODUCT_DATACENTER_SERVER = 0x00000008; - private const int PRODUCT_SMALLBUSINESS_SERVER = 0x00000009; - private const int PRODUCT_ENTERPRISE_SERVER = 0x0000000A; - private const int PRODUCT_STARTER = 0x0000000B; - private const int PRODUCT_DATACENTER_SERVER_CORE = 0x0000000C; - private const int PRODUCT_STANDARD_SERVER_CORE = 0x0000000D; - private const int PRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E; - private const int PRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F; - private const int PRODUCT_BUSINESS_N = 0x00000010; - private const int PRODUCT_WEB_SERVER = 0x00000011; - private const int PRODUCT_CLUSTER_SERVER = 0x00000012; - private const int PRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014; - private const int PRODUCT_STORAGE_STANDARD_SERVER = 0x00000015; - private const int PRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016; - private const int PRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017; - private const int PRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018; - private const int PRODUCT_HOME_PREMIUM_N = 0x0000001A; - private const int PRODUCT_ENTERPRISE_N = 0x0000001B; - private const int PRODUCT_ULTIMATE_N = 0x0000001C; - private const int PRODUCT_WEB_SERVER_CORE = 0x0000001D; - private const int PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E; - private const int PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F; - private const int PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020; - private const int PRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023; - private const int PRODUCT_STANDARD_SERVER_V = 0x00000024; - private const int PRODUCT_ENTERPRISE_SERVER_V = 0x00000026; - private const int PRODUCT_STANDARD_SERVER_CORE_V = 0x00000028; - private const int PRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029; - private const int PRODUCT_HYPERV = 0x0000002A; - - private const int VER_NT_WORKSTATION = 1; - private const int VER_NT_SERVER = 3; - private const int VER_SUITE_ENTERPRISE = 2; - private const int VER_SUITE_DATACENTER = 128; - private const int VER_SUITE_PERSONAL = 512; - private const int VER_SUITE_BLADE = 1024; - /// /// Gets the service pack information of the operating system running on this computer. /// @@ -776,9 +539,9 @@ namespace Greenshot.Base.Core get { string servicePack = string.Empty; - OSVERSIONINFOEX osVersionInfo = OSVERSIONINFOEX.Create(); + OsVersionInfoEx osVersionInfo = OsVersionInfoEx.Create(); - if (GetVersionEx(ref osVersionInfo)) + if (Kernel32Api.GetVersionEx(ref osVersionInfo)) { servicePack = osVersionInfo.ServicePackVersion; } @@ -787,6 +550,7 @@ namespace Greenshot.Base.Core } } + /// /// Gets the full version string of the operating system running on this computer. /// public static string VersionString diff --git a/src/Greenshot.Base/Core/FastBitmap.cs b/src/Greenshot.Base/Core/FastBitmap.cs index 3875e6203..c0309763f 100644 --- a/src/Greenshot.Base/Core/FastBitmap.cs +++ b/src/Greenshot.Base/Core/FastBitmap.cs @@ -23,6 +23,8 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; namespace Greenshot.Base.Core { @@ -84,7 +86,7 @@ namespace Greenshot.Base.Core /// /// Size of the underlying image /// - Size Size { get; } + NativeSize Size { get; } /// /// Height of the image area that this fastbitmap covers @@ -127,19 +129,19 @@ namespace Greenshot.Base.Core bool HasAlphaChannel { get; } /// - /// Draw the stored bitmap to the destionation bitmap at the supplied point + /// Draw the stored bitmap to the destination bitmap at the supplied point /// /// Graphics - /// Point with location - void DrawTo(Graphics graphics, Point destination); + /// NativePoint with location + void DrawTo(Graphics graphics, NativePoint destination); /// /// Draw the stored Bitmap on the Destination bitmap with the specified rectangle /// Be aware that the stored bitmap will be resized to the specified rectangle!! /// /// Graphics - /// Rectangle with destination - void DrawTo(Graphics graphics, Rectangle destinationRect); + /// NativeRect with destination + void DrawTo(Graphics graphics, NativeRect destinationRect); /// /// Return true if the coordinates are inside the FastBitmap @@ -214,7 +216,7 @@ namespace Greenshot.Base.Core /// public interface IFastBitmapWithClip : IFastBitmap { - Rectangle Clip { get; set; } + NativeRect Clip { get; set; } bool InvertClip { get; set; } @@ -267,14 +269,14 @@ namespace Greenshot.Base.Core public const int ColorIndexB = 2; public const int ColorIndexA = 3; - protected Rectangle Area; + protected NativeRect Area; /// /// If this is set to true, the bitmap will be disposed when disposing the IFastBitmap /// public bool NeedsDispose { get; set; } - public Rectangle Clip { get; set; } + public NativeRect Clip { get; set; } public bool InvertClip { get; set; } @@ -290,7 +292,7 @@ namespace Greenshot.Base.Core public static IFastBitmap Create(Bitmap source) { - return Create(source, Rectangle.Empty); + return Create(source, NativeRect.Empty); } public void SetResolution(float horizontal, float vertical) @@ -303,44 +305,37 @@ namespace Greenshot.Base.Core /// The supplied rectangle specifies the area for which the FastBitmap does its thing /// /// Bitmap to access - /// Rectangle which specifies the area to have access to, can be Rectangle.Empty for the whole image + /// NativeRect which specifies the area to have access to, can be NativeRect.Empty for the whole image /// IFastBitmap - public static IFastBitmap Create(Bitmap source, Rectangle area) - { - switch (source.PixelFormat) + public static IFastBitmap Create(Bitmap source, NativeRect area) => + source.PixelFormat switch { - case PixelFormat.Format8bppIndexed: - return new FastChunkyBitmap(source, area); - case PixelFormat.Format24bppRgb: - return new Fast24RgbBitmap(source, area); - case PixelFormat.Format32bppRgb: - return new Fast32RgbBitmap(source, area); - case PixelFormat.Format32bppArgb: - case PixelFormat.Format32bppPArgb: - return new Fast32ArgbBitmap(source, area); - default: - throw new NotSupportedException($"Not supported Pixelformat {source.PixelFormat}"); - } - } + PixelFormat.Format8bppIndexed => new FastChunkyBitmap(source, area), + PixelFormat.Format24bppRgb => new Fast24RgbBitmap(source, area), + PixelFormat.Format32bppRgb => new Fast32RgbBitmap(source, area), + PixelFormat.Format32bppArgb => new Fast32ArgbBitmap(source, area), + PixelFormat.Format32bppPArgb => new Fast32ArgbBitmap(source, area), + _ => throw new NotSupportedException($"Not supported PixelFormat {source.PixelFormat}") + }; /// /// Factory for creating a FastBitmap as a destination for the source /// /// Bitmap to clone - /// new Pixelformat + /// new PixelFormat /// IFastBitmap public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat) { - return CreateCloneOf(source, pixelFormat, Rectangle.Empty); + return CreateCloneOf(source, pixelFormat, NativeRect.Empty); } /// /// Factory for creating a FastBitmap as a destination for the source /// /// Bitmap to clone - /// Area of the bitmap to access, can be Rectangle.Empty for the whole + /// Area of the bitmap to access, can be NativeRect.Empty for the whole /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, Rectangle area) + public static IFastBitmap CreateCloneOf(Image source, NativeRect area) { return CreateCloneOf(source, PixelFormat.DontCare, area); } @@ -350,9 +345,9 @@ namespace Greenshot.Base.Core ///
/// Bitmap to clone /// Pixelformat of the cloned bitmap - /// Area of the bitmap to access, can be Rectangle.Empty for the whole + /// Area of the bitmap to access, can be NativeRect.Empty for the whole /// IFastBitmap - public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, Rectangle area) + public static IFastBitmap CreateCloneOf(Image source, PixelFormat pixelFormat, NativeRect area) { Bitmap destination = ImageHelper.CloneArea(source, area, pixelFormat); FastBitmap fastBitmap = Create(destination) as FastBitmap; @@ -369,11 +364,11 @@ namespace Greenshot.Base.Core /// /// Factory for creating a FastBitmap as a destination /// - /// - /// - /// + /// NativeSize + /// PixelFormat + /// Color /// IFastBitmap - public static IFastBitmap CreateEmpty(Size newSize, PixelFormat pixelFormat, Color backgroundColor) + public static IFastBitmap CreateEmpty(NativeSize newSize, PixelFormat pixelFormat, Color backgroundColor) { Bitmap destination = ImageHelper.CreateEmpty(newSize.Width, newSize.Height, pixelFormat, backgroundColor, 96f, 96f); IFastBitmap fastBitmap = Create(destination); @@ -385,14 +380,14 @@ namespace Greenshot.Base.Core /// Constructor which stores the image and locks it when called ///
/// Bitmap - /// Rectangle - protected FastBitmap(Bitmap bitmap, Rectangle area) + /// NativeRect + protected FastBitmap(Bitmap bitmap, NativeRect area) { Bitmap = bitmap; - Rectangle bitmapArea = new Rectangle(Point.Empty, bitmap.Size); - if (area != Rectangle.Empty) + var bitmapArea = new NativeRect(NativePoint.Empty, bitmap.Size); + if (area != NativeRect.Empty) { - area.Intersect(bitmapArea); + area = area.Intersect(bitmapArea); Area = area; } else @@ -413,11 +408,11 @@ namespace Greenshot.Base.Core /// /// Return the size of the image /// - public Size Size + public NativeSize Size { get { - if (Area == Rectangle.Empty) + if (Area == NativeRect.Empty) { return Bitmap.Size; } @@ -433,7 +428,7 @@ namespace Greenshot.Base.Core { get { - if (Area == Rectangle.Empty) + if (Area == NativeRect.Empty) { return Bitmap.Width; } @@ -449,7 +444,7 @@ namespace Greenshot.Base.Core { get { - if (Area == Rectangle.Empty) + if (Area == NativeRect.Empty) { return Bitmap.Height; } @@ -596,13 +591,13 @@ namespace Greenshot.Base.Core } /// - /// Draw the stored bitmap to the destionation bitmap at the supplied point + /// Draw the stored bitmap to the destination bitmap at the supplied point /// /// /// - public void DrawTo(Graphics graphics, Point destination) + public void DrawTo(Graphics graphics, NativePoint destination) { - DrawTo(graphics, new Rectangle(destination, Area.Size)); + DrawTo(graphics, new NativeRect(destination, Area.Size)); } /// @@ -610,8 +605,8 @@ namespace Greenshot.Base.Core /// Be aware that the stored bitmap will be resized to the specified rectangle!! /// /// - /// - public void DrawTo(Graphics graphics, Rectangle destinationRect) + /// NativeRect + public void DrawTo(Graphics graphics, NativeRect destinationRect) { // Make sure this.bitmap is unlocked, if it was locked bool isLocked = BitsLocked; @@ -715,7 +710,7 @@ namespace Greenshot.Base.Core } /// - /// This is the implementation of the FastBitmat for the 8BPP pixelformat + /// This is the implementation of the FastBitmap for the 8BPP pixelformat /// public unsafe class FastChunkyBitmap : FastBitmap { @@ -723,7 +718,7 @@ namespace Greenshot.Base.Core private readonly Color[] _colorEntries; private readonly Dictionary _colorCache = new Dictionary(); - public FastChunkyBitmap(Bitmap source, Rectangle area) : base(source, area) + public FastChunkyBitmap(Bitmap source, NativeRect area) : base(source, area) { _colorEntries = Bitmap.Palette.Entries; } @@ -825,7 +820,7 @@ namespace Greenshot.Base.Core ///
public unsafe class Fast24RgbBitmap : FastBitmap { - public Fast24RgbBitmap(Bitmap source, Rectangle area) : base(source, area) + public Fast24RgbBitmap(Bitmap source, NativeRect area) : base(source, area) { } @@ -891,7 +886,7 @@ namespace Greenshot.Base.Core ///
public unsafe class Fast32RgbBitmap : FastBitmap { - public Fast32RgbBitmap(Bitmap source, Rectangle area) : base(source, area) + public Fast32RgbBitmap(Bitmap source, NativeRect area) : base(source, area) { } @@ -961,7 +956,7 @@ namespace Greenshot.Base.Core public Color BackgroundBlendColor { get; set; } - public Fast32ArgbBitmap(Bitmap source, Rectangle area) : base(source, area) + public Fast32ArgbBitmap(Bitmap source, NativeRect area) : base(source, area) { BackgroundBlendColor = Color.White; } diff --git a/src/Greenshot.Base/Core/FileDescriptor.cs b/src/Greenshot.Base/Core/FileDescriptor.cs index 5306cf3b8..750cbab4d 100644 --- a/src/Greenshot.Base/Core/FileDescriptor.cs +++ b/src/Greenshot.Base/Core/FileDescriptor.cs @@ -22,7 +22,7 @@ using System; using System.IO; using System.Text; -using Greenshot.Base.UnmanagedHelpers.Structs; +using Dapplo.Windows.Common.Structs; namespace Greenshot.Base.Core { @@ -30,8 +30,8 @@ namespace Greenshot.Base.Core { public FileDescriptorFlags Flags { get; set; } public Guid ClassId { get; set; } - public SIZE Size { get; set; } - public POINT Point { get; set; } + public NativeSize Size { get; set; } + public NativePoint Point { get; set; } public FileAttributes FileAttributes { get; set; } public DateTime CreationTime { get; set; } public DateTime LastAccessTime { get; set; } @@ -46,9 +46,9 @@ namespace Greenshot.Base.Core //ClassID ClassId = new Guid(reader.ReadBytes(16)); //Size - Size = new SIZE(reader.ReadInt32(), reader.ReadInt32()); + Size = new NativeSize(reader.ReadInt32(), reader.ReadInt32()); //Point - Point = new POINT(reader.ReadInt32(), reader.ReadInt32()); + Point = new NativePoint(reader.ReadInt32(), reader.ReadInt32()); //FileAttributes FileAttributes = (FileAttributes)reader.ReadUInt32(); //CreationTime diff --git a/src/Greenshot.Base/Core/HResultExtensions.cs b/src/Greenshot.Base/Core/HResultExtensions.cs deleted file mode 100644 index c3300e80f..000000000 --- a/src/Greenshot.Base/Core/HResultExtensions.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Greenshot - a free and open source screenshot tool -// Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom -// -// For more information see: https://getgreenshot.org/ -// The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 1 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -using System.Diagnostics.Contracts; -using Greenshot.Base.Core.Enums; - -namespace Greenshot.Base.Core -{ - /// - /// Extensions to handle the HResult - /// - public static class HResultExtensions - { - /// - /// Test if the HResult represents a fail - /// - /// HResult - /// bool - [Pure] - public static bool Failed(this HResult hResult) - { - return hResult < 0; - } - - /// - /// Test if the HResult represents a success - /// - /// HResult - /// bool - [Pure] - public static bool Succeeded(this HResult hResult) - { - return hResult >= HResult.S_OK; - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/Core/ImageHelper.cs b/src/Greenshot.Base/Core/ImageHelper.cs index 38c77d950..f75cc9def 100644 --- a/src/Greenshot.Base/Core/ImageHelper.cs +++ b/src/Greenshot.Base/Core/ImageHelper.cs @@ -27,18 +27,18 @@ using System.Drawing.Imaging; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Gdi32; using Greenshot.Base.Core.Enums; using Greenshot.Base.Effects; using Greenshot.Base.IniFile; -using Greenshot.Base.UnmanagedHelpers; using log4net; using Brush = System.Drawing.Brush; using Color = System.Drawing.Color; using Matrix = System.Drawing.Drawing2D.Matrix; using Pen = System.Drawing.Pen; using PixelFormat = System.Drawing.Imaging.PixelFormat; -using Point = System.Drawing.Point; -using Size = System.Drawing.Size; namespace Greenshot.Base.Core { @@ -157,7 +157,7 @@ namespace Greenshot.Base.Core graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - Rectangle rectDestination = new Rectangle(0, 0, thumbWidth, thumbHeight); + NativeRect rectDestination = new NativeRect(0, 0, thumbWidth, thumbHeight); graphics.DrawImage(image, rectDestination, 0, 0, srcWidth, srcHeight, GraphicsUnit.Pixel); } @@ -165,18 +165,18 @@ namespace Greenshot.Base.Core } /// - /// Crops the image to the specified rectangle + /// Crops the image to the specified NativeRect /// /// Image to crop - /// Rectangle with bitmap coordinates, will be "intersected" to the bitmap - public static bool Crop(ref Image image, ref Rectangle cropRectangle) + /// NativeRect with bitmap coordinates, will be "intersected" to the bitmap + public static bool Crop(ref Image image, ref NativeRect cropNativeRect) { if (image is Bitmap && (image.Width * image.Height > 0)) { - cropRectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height)); - if (cropRectangle.Width != 0 || cropRectangle.Height != 0) + cropNativeRect = cropNativeRect.Intersect(new NativeRect(0, 0, image.Width, image.Height)); + if (cropNativeRect.Width != 0 || cropNativeRect.Height != 0) { - Image returnImage = CloneArea(image, cropRectangle, PixelFormat.DontCare); + Image returnImage = CloneArea(image, cropNativeRect, PixelFormat.DontCare); image.Dispose(); image = returnImage; return true; @@ -188,20 +188,20 @@ namespace Greenshot.Base.Core } /// - /// Private helper method for the FindAutoCropRectangle + /// Private helper method for the FindAutoCropNativeRect /// /// IFastBitmap - /// Point + /// NativePoint /// int - /// Rectangle with optional area to scan in - /// Rectangle - private static Rectangle FindAutoCropRectangle(IFastBitmap fastBitmap, Point colorPoint, int cropDifference, Rectangle? area = null) + /// NativeRect with optional area to scan in + /// NativeRect + private static NativeRect FindAutoCropNativeRect(IFastBitmap fastBitmap, NativePoint colorPoint, int cropDifference, NativeRect? area = null) { - area ??= new Rectangle(0, 0, fastBitmap.Width, fastBitmap.Height); - Rectangle cropRectangle = Rectangle.Empty; + area ??= new NativeRect(0, 0, fastBitmap.Width, fastBitmap.Height); + NativeRect cropNativeRect = NativeRect.Empty; Color referenceColor = fastBitmap.GetColorAt(colorPoint.X, colorPoint.Y); - Point min = new Point(int.MaxValue, int.MaxValue); - Point max = new Point(int.MinValue, int.MinValue); + NativePoint min = new NativePoint(int.MaxValue, int.MaxValue); + NativePoint max = new NativePoint(int.MinValue, int.MinValue); if (cropDifference > 0) { @@ -218,10 +218,10 @@ namespace Greenshot.Base.Core continue; } - if (x < min.X) min.X = x; - if (y < min.Y) min.Y = y; - if (x > max.X) max.X = x; - if (y > max.Y) max.Y = y; + if (x < min.X) min = min.ChangeX(x); + if (y < min.Y) min = min.ChangeY(y); + if (x > max.X) max = max.ChangeX(x); + if (y > max.Y) max = max.ChangeY(y); } } } @@ -237,43 +237,44 @@ namespace Greenshot.Base.Core continue; } - if (x < min.X) min.X = x; - if (y < min.Y) min.Y = y; - if (x > max.X) max.X = x; - if (y > max.Y) max.Y = y; + if (x < min.X) min = min.ChangeX(x); + if (y < min.Y) min = min.ChangeY(y); + if (x > max.X) max = max.ChangeX(x); + if (y > max.Y) max = max.ChangeY(y); } } } - if (!(Point.Empty.Equals(min) && max.Equals(new Point(area.Value.Width - 1, area.Value.Height - 1)))) + if (!(NativePoint.Empty.Equals(min) && max.Equals(new NativePoint(area.Value.Width - 1, area.Value.Height - 1)))) { if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) { - cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); + cropNativeRect = new NativeRect(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); } } - return cropRectangle; + return cropNativeRect; } /// - /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 + /// Get a NativeRect for the image which crops the image of all colors equal to that on 0,0 /// /// Image /// int - /// Rectangle with optional area - /// Rectangle - public static Rectangle FindAutoCropRectangle(Image image, int cropDifference, Rectangle? area = null) + /// NativeRect with optional area + /// NativeRect + public static NativeRect FindAutoCropRectangle(Image image, int cropDifference, NativeRect? area = null) { - area ??= new Rectangle(0, 0, image.Width, image.Height); - Rectangle cropRectangle = Rectangle.Empty; - var checkPoints = new List + area ??= new NativeRect(0, 0, image.Width, image.Height); + NativeRect cropNativeRect = NativeRect.Empty; + var checkPoints = new List { - new Point(area.Value.Left, area.Value.Top), - new Point(area.Value.Left, area.Value.Bottom - 1), - new Point(area.Value.Right - 1, area.Value.Top), - new Point(area.Value.Right - 1, area.Value.Bottom - 1) + new(area.Value.Left, area.Value.Top), + new(area.Value.Left, area.Value.Bottom - 1), + new(area.Value.Right - 1, area.Value.Top), + new(area.Value.Right - 1, area.Value.Bottom - 1) }; + // Top Left // Bottom Left // Top Right @@ -281,17 +282,17 @@ namespace Greenshot.Base.Core using (IFastBitmap fastBitmap = FastBitmap.Create((Bitmap) image)) { // find biggest area - foreach (Point checkPoint in checkPoints) + foreach (var checkPoint in checkPoints) { - var currentRectangle = FindAutoCropRectangle(fastBitmap, checkPoint, cropDifference, area); - if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) + var currentNativeRect = FindAutoCropNativeRect(fastBitmap, checkPoint, cropDifference, area); + if (currentNativeRect.Width * currentNativeRect.Height > cropNativeRect.Width * cropNativeRect.Height) { - cropRectangle = currentRectangle; + cropNativeRect = currentNativeRect; } } } - return cropRectangle; + return cropNativeRect; } /// @@ -345,7 +346,7 @@ namespace Greenshot.Base.Core /// /// Path to draw to /// Points for the lines to draw - private static void DrawLines(GraphicsPath path, List points) + private static void DrawLines(GraphicsPath path, List points) { path.AddLine(points[0], points[1]); for (int i = 0; i < points.Count - 1; i++) @@ -372,12 +373,12 @@ namespace Greenshot.Base.Core int horizontalRegions = (int) Math.Round((float) sourceImage.Width / horizontalToothRange); int verticalRegions = (int) Math.Round((float) sourceImage.Height / verticalToothRange); - Point topLeft = new Point(0, 0); - Point topRight = new Point(sourceImage.Width, 0); - Point bottomLeft = new Point(0, sourceImage.Height); - Point bottomRight = new Point(sourceImage.Width, sourceImage.Height); + var topLeft = new NativePoint(0, 0); + var topRight = new NativePoint(sourceImage.Width, 0); + var bottomLeft = new NativePoint(0, sourceImage.Height); + var bottomRight = new NativePoint(sourceImage.Width, sourceImage.Height); - List points = new List(); + var points = new List(); if (edges[0]) { @@ -388,15 +389,15 @@ namespace Greenshot.Base.Core } else { - points.Add(new Point(random.Next(1, toothHeight), random.Next(1, toothHeight))); + points.Add(new NativePoint(random.Next(1, toothHeight), random.Next(1, toothHeight))); } for (int i = 1; i < horizontalRegions - 1; i++) { - points.Add(new Point(i * horizontalToothRange, random.Next(1, toothHeight))); + points.Add(new NativePoint(i * horizontalToothRange, random.Next(1, toothHeight))); } - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight))); + points.Add(new NativePoint(sourceImage.Width - random.Next(1, toothHeight), random.Next(1, toothHeight))); } else { @@ -410,10 +411,10 @@ namespace Greenshot.Base.Core { for (int i = 1; i < verticalRegions - 1; i++) { - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange)); + points.Add(new NativePoint(sourceImage.Width - random.Next(1, toothHeight), i * verticalToothRange)); } - points.Add(new Point(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); + points.Add(new NativePoint(sourceImage.Width - random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); } else { @@ -428,10 +429,10 @@ namespace Greenshot.Base.Core { for (int i = 1; i < horizontalRegions - 1; i++) { - points.Add(new Point(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight))); + points.Add(new NativePoint(sourceImage.Width - i * horizontalToothRange, sourceImage.Height - random.Next(1, toothHeight))); } - points.Add(new Point(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); + points.Add(new NativePoint(random.Next(1, toothHeight), sourceImage.Height - random.Next(1, toothHeight))); } else { @@ -447,7 +448,7 @@ namespace Greenshot.Base.Core // One fewer as the end point is the starting point for (int i = 1; i < verticalRegions - 1; i++) { - points.Add(new Point(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange)); + points.Add(new NativePoint(random.Next(1, toothHeight), points[points.Count - 1].Y - verticalToothRange)); } } else @@ -768,19 +769,18 @@ namespace Greenshot.Base.Core /// /// /// - /// - public static Rectangle CreateIntersectRectangle(Size applySize, Rectangle rect, bool invert) + /// NativeRect + public static NativeRect CreateIntersectRectangle(NativeSize applySize, NativeRect rect, bool invert) { - Rectangle myRect; + NativeRect myRect; if (invert) { - myRect = new Rectangle(0, 0, applySize.Width, applySize.Height); + myRect = new NativeRect(0, 0, applySize.Width, applySize.Height); } else { - Rectangle applyRect = new Rectangle(0, 0, applySize.Width, applySize.Height); - myRect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); - myRect.Intersect(applyRect); + NativeRect applyRect = new NativeRect(0, 0, applySize.Width, applySize.Height); + myRect = new NativeRect(rect.X, rect.Y, rect.Width, rect.Height).Intersect(applyRect); } return myRect; @@ -796,11 +796,9 @@ namespace Greenshot.Base.Core /// /// The transform matrix which describes how the elements need to be transformed to stay at the same location /// Bitmap with the shadow, is bigger than the sourceBitmap!! - public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, Point shadowOffset, Matrix matrix, PixelFormat targetPixelformat) + public static Bitmap CreateShadow(Image sourceBitmap, float darkness, int shadowSize, NativePoint shadowOffset, Matrix matrix, PixelFormat targetPixelformat) { - Point offset = shadowOffset; - offset.X += shadowSize - 1; - offset.Y += shadowSize - 1; + NativePoint offset = shadowOffset.Offset(shadowSize - 1, shadowSize - 1); matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); // Create a new "clean" image Bitmap returnImage = CreateEmpty(sourceBitmap.Width + shadowSize * 2, sourceBitmap.Height + shadowSize * 2, targetPixelformat, Color.Empty, @@ -811,7 +809,7 @@ namespace Greenshot.Base.Core shadowSize++; } - bool useGdiBlur = GDIplus.IsBlurPossible(shadowSize); + bool useGdiBlur = GdiPlusApi.IsBlurPossible(shadowSize); // Create "mask" for the shadow ColorMatrix maskMatrix = new ColorMatrix { @@ -828,20 +826,20 @@ namespace Greenshot.Base.Core maskMatrix.Matrix33 = darkness; } - Rectangle shadowRectangle = new Rectangle(new Point(shadowSize, shadowSize), sourceBitmap.Size); - ApplyColorMatrix((Bitmap) sourceBitmap, Rectangle.Empty, returnImage, shadowRectangle, maskMatrix); + NativeRect shadowNativeRect = new NativeRect(new NativePoint(shadowSize, shadowSize), sourceBitmap.Size); + ApplyColorMatrix((Bitmap) sourceBitmap, NativeRect.Empty, returnImage, shadowNativeRect, maskMatrix); // blur "shadow", apply to whole new image if (useGdiBlur) { // Use GDI Blur - Rectangle newImageRectangle = new Rectangle(0, 0, returnImage.Width, returnImage.Height); - GDIplus.ApplyBlur(returnImage, newImageRectangle, shadowSize + 1, false); + NativeRect newImageNativeRect = new NativeRect(0, 0, returnImage.Width, returnImage.Height); + GdiPlusApi.ApplyBlur(returnImage, newImageNativeRect, shadowSize + 1, false); } else { // try normal software blur - //returnImage = CreateBlur(returnImage, newImageRectangle, true, shadowSize, 1d, false, newImageRectangle); + //returnImage = CreateBlur(returnImage, newImageNativeRect, true, shadowSize, 1d, false, newImageNativeRect); ApplyBoxBlur(returnImage, shadowSize); } @@ -905,18 +903,18 @@ namespace Greenshot.Base.Core /// ColorMatrix to apply public static void ApplyColorMatrix(Bitmap source, ColorMatrix colorMatrix) { - ApplyColorMatrix(source, Rectangle.Empty, source, Rectangle.Empty, colorMatrix); + ApplyColorMatrix(source, NativeRect.Empty, source, NativeRect.Empty, colorMatrix); } /// /// Apply a color matrix by copying from the source to the destination /// /// Image to copy from - /// Rectangle to copy from - /// Rectangle to copy to + /// NativeRect to copy from + /// NativeRect to copy to /// Image to copy to /// ColorMatrix to apply - public static void ApplyColorMatrix(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ColorMatrix colorMatrix) + public static void ApplyColorMatrix(Bitmap source, NativeRect sourceRect, Bitmap dest, NativeRect destRect, ColorMatrix colorMatrix) { using ImageAttributes imageAttributes = new ImageAttributes(); imageAttributes.ClearColorMatrix(); @@ -928,15 +926,15 @@ namespace Greenshot.Base.Core /// Apply a color matrix by copying from the source to the destination ///
/// Image to copy from - /// Rectangle to copy from - /// Rectangle to copy to + /// NativeRect to copy from + /// NativeRect to copy to /// Image to copy to /// ImageAttributes to apply - public static void ApplyImageAttributes(Bitmap source, Rectangle sourceRect, Bitmap dest, Rectangle destRect, ImageAttributes imageAttributes) + public static void ApplyImageAttributes(Bitmap source, NativeRect sourceRect, Bitmap dest, NativeRect destRect, ImageAttributes imageAttributes) { - if (sourceRect == Rectangle.Empty) + if (sourceRect == NativeRect.Empty) { - sourceRect = new Rectangle(0, 0, source.Width, source.Height); + sourceRect = new NativeRect(0, 0, source.Width, source.Height); } if (dest == null) @@ -944,9 +942,9 @@ namespace Greenshot.Base.Core dest = source; } - if (destRect == Rectangle.Empty) + if (destRect == NativeRect.Empty) { - destRect = new Rectangle(0, 0, dest.Width, dest.Height); + destRect = new NativeRect(0, 0, dest.Width, dest.Height); } using Graphics graphics = Graphics.FromImage(dest); @@ -995,7 +993,7 @@ namespace Greenshot.Base.Core public static Image CreateBorder(Image sourceImage, int borderSize, Color borderColor, PixelFormat targetPixelformat, Matrix matrix) { // "return" the shifted offset, so the caller can e.g. move elements - Point offset = new Point(borderSize, borderSize); + NativePoint offset = new NativePoint(borderSize, borderSize); matrix.Translate(offset.X, offset.Y, MatrixOrder.Append); // Create a new "clean" image @@ -1010,7 +1008,7 @@ namespace Greenshot.Base.Core graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; using (GraphicsPath path = new GraphicsPath()) { - path.AddRectangle(new Rectangle(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize)); + path.AddRectangle(new NativeRect(borderSize >> 1, borderSize >> 1, newImage.Width - borderSize, newImage.Height - borderSize)); using Pen pen = new Pen(borderColor, borderSize) { LineJoin = LineJoin.Round, @@ -1090,7 +1088,7 @@ namespace Greenshot.Base.Core sourceImage.VerticalResolution); using (ImageAttributes adjustAttributes = CreateAdjustAttributes(brightness, contrast, gamma)) { - ApplyImageAttributes((Bitmap) sourceImage, Rectangle.Empty, newBitmap, Rectangle.Empty, adjustAttributes); + ApplyImageAttributes((Bitmap) sourceImage, NativeRect.Empty, newBitmap, NativeRect.Empty, adjustAttributes); } return newBitmap; @@ -1156,7 +1154,7 @@ namespace Greenshot.Base.Core return (Image) sourceImage.Clone(); } - return CloneArea(sourceImage, Rectangle.Empty, PixelFormat.DontCare); + return CloneArea(sourceImage, NativeRect.Empty, PixelFormat.DontCare); } /// @@ -1167,7 +1165,7 @@ namespace Greenshot.Base.Core /// Bitmap with clone image data public static Bitmap Clone(Image sourceBitmap, PixelFormat targetFormat) { - return CloneArea(sourceBitmap, Rectangle.Empty, targetFormat); + return CloneArea(sourceBitmap, NativeRect.Empty, targetFormat); } /// @@ -1178,22 +1176,22 @@ namespace Greenshot.Base.Core /// 2) When going from a transparent to a non transparent bitmap, we draw the background white! /// /// Source bitmap to clone - /// Rectangle to copy from the source, use Rectangle.Empty for all + /// NativeRect to copy from the source, use NativeRect.Empty for all /// Target Format, use PixelFormat.DontCare if you want the original (or a default if the source PixelFormat is not supported) /// - public static Bitmap CloneArea(Image sourceImage, Rectangle sourceRect, PixelFormat targetFormat) + public static Bitmap CloneArea(Image sourceImage, NativeRect sourceRect, PixelFormat targetFormat) { Bitmap newImage; - Rectangle bitmapRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); + NativeRect bitmapRect = new NativeRect(0, 0, sourceImage.Width, sourceImage.Height); - // Make sure the source is not Rectangle.Empty - if (Rectangle.Empty.Equals(sourceRect)) + // Make sure the source is not NativeRect.Empty + if (NativeRect.Empty.Equals(sourceRect)) { - sourceRect = new Rectangle(0, 0, sourceImage.Width, sourceImage.Height); + sourceRect = new NativeRect(0, 0, sourceImage.Width, sourceImage.Height); } else { - sourceRect.Intersect(bitmapRect); + sourceRect = sourceRect.Intersect(bitmapRect); } // If no pixelformat is supplied @@ -1505,7 +1503,7 @@ namespace Greenshot.Base.Core graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; using ImageAttributes wrapMode = new ImageAttributes(); wrapMode.SetWrapMode(WrapMode.TileFlipXY); - graphics.DrawImage(sourceImage, new Rectangle(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode); + graphics.DrawImage(sourceImage, new NativeRect(destX, destY, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, wrapMode); } return newImage; @@ -1528,7 +1526,7 @@ namespace Greenshot.Base.Core graphics.RotateTransform(rotationAngle); graphics.TranslateTransform(-(float)bitmap.Width / 2, -(float)bitmap.Height / 2); - graphics.DrawImage(image, new Point(0, 0)); + graphics.DrawImage(image, new NativePoint(0, 0)); return bitmap; } @@ -1579,7 +1577,7 @@ namespace Greenshot.Base.Core /// BitmapSource public static BitmapSource ToBitmapSource(this Bitmap bitmap) { - var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); + var bitmapData = bitmap.LockBits(new NativeRect(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); BitmapSource bitmapSource; try @@ -1608,7 +1606,7 @@ namespace Greenshot.Base.Core var pixelFormat = bitmapSource.Format.Map(); Bitmap bitmap = new Bitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight, pixelFormat); - BitmapData data = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.WriteOnly, pixelFormat); + BitmapData data = bitmap.LockBits(new NativeRect(NativePoint.Empty, bitmap.Size), ImageLockMode.WriteOnly, pixelFormat); bitmapSource.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); bitmap.UnlockBits(data); return bitmap; diff --git a/src/Greenshot.Base/Core/ImageIO.cs b/src/Greenshot.Base/Core/ImageIO.cs index 16f69c0fe..9d6bbf1cd 100644 --- a/src/Greenshot.Base/Core/ImageIO.cs +++ b/src/Greenshot.Base/Core/ImageIO.cs @@ -36,13 +36,12 @@ using Greenshot.Base.Core.FileFormatHandlers; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; -using Greenshot.Base.UnmanagedHelpers; using log4net; namespace Greenshot.Base.Core { /// - /// Description of ImageOutput. + /// This contains all io related logic for image /// public static class ImageIO { @@ -559,93 +558,6 @@ namespace Greenshot.Base.Core return fileImage; } - /// - /// Based on: https://www.codeproject.com/KB/cs/IconExtractor.aspx - /// And a hint from: https://www.codeproject.com/KB/cs/IconLib.aspx - /// - /// Stream with the icon information - /// Bitmap with the Vista Icon (256x256) - private static Bitmap ExtractVistaIcon(Stream iconStream) - { - const int sizeIconDir = 6; - const int sizeIconDirEntry = 16; - Bitmap bmpPngExtracted = null; - try - { - byte[] srcBuf = new byte[iconStream.Length]; - iconStream.Read(srcBuf, 0, (int)iconStream.Length); - int iCount = BitConverter.ToInt16(srcBuf, 4); - for (int iIndex = 0; iIndex < iCount; iIndex++) - { - int iWidth = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex]; - int iHeight = srcBuf[sizeIconDir + sizeIconDirEntry * iIndex + 1]; - if (iWidth == 0 && iHeight == 0) - { - int iImageSize = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 8); - int iImageOffset = BitConverter.ToInt32(srcBuf, sizeIconDir + sizeIconDirEntry * iIndex + 12); - using MemoryStream destStream = new MemoryStream(); - destStream.Write(srcBuf, iImageOffset, iImageSize); - destStream.Seek(0, SeekOrigin.Begin); - bmpPngExtracted = new Bitmap(destStream); // This is PNG! :) - break; - } - } - } - catch - { - return null; - } - - return bmpPngExtracted; - } - - /// - /// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648069%28v=vs.85%29.aspx - /// - /// The file (EXE or DLL) to get the icon from - /// Index of the icon - /// true if the large icon is wanted - /// Icon - public static Icon ExtractAssociatedIcon(string location, int index, bool takeLarge) - { - Shell32.ExtractIconEx(location, index, out var large, out var small, 1); - Icon returnIcon = null; - bool isLarge = false; - bool isSmall = false; - try - { - if (takeLarge && !IntPtr.Zero.Equals(large)) - { - returnIcon = Icon.FromHandle(large); - isLarge = true; - } - else if (!IntPtr.Zero.Equals(small)) - { - returnIcon = Icon.FromHandle(small); - isSmall = true; - } - else if (!IntPtr.Zero.Equals(large)) - { - returnIcon = Icon.FromHandle(large); - isLarge = true; - } - } - finally - { - if (isLarge && !IntPtr.Zero.Equals(small)) - { - User32.DestroyIcon(small); - } - - if (isSmall && !IntPtr.Zero.Equals(large)) - { - User32.DestroyIcon(large); - } - } - - return returnIcon; - } - /// /// Create an image from a stream, if an extension is supplied more formats are supported. /// diff --git a/src/Greenshot.Base/Core/PluginUtils.cs b/src/Greenshot.Base/Core/PluginUtils.cs index cb09cd8af..d41e545a5 100644 --- a/src/Greenshot.Base/Core/PluginUtils.cs +++ b/src/Greenshot.Base/Core/PluginUtils.cs @@ -25,8 +25,8 @@ using System.ComponentModel; using System.Drawing; using System.IO; using System.Windows.Forms; +using Dapplo.Windows.Icons; using Greenshot.Base.IniFile; -using Greenshot.Base.UnmanagedHelpers; using log4net; using Microsoft.Win32; @@ -113,7 +113,7 @@ namespace Greenshot.Base.Core /// /// path to the exe or dll /// index of the icon - /// Bitmap with the icon or null if something happended + /// Bitmap with the icon or null if something happened public static Image GetCachedExeIcon(string path, int index) { string cacheKey = $"{path}:{index}"; @@ -148,7 +148,7 @@ namespace Greenshot.Base.Core ///
/// path to the exe or dll /// index of the icon - /// Bitmap with the icon or null if something happended + /// Bitmap with the icon or null if something happened private static Bitmap GetExeIcon(string path, int index) { if (!File.Exists(path)) @@ -158,20 +158,11 @@ namespace Greenshot.Base.Core try { - using (Icon appIcon = ImageIO.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons)) + var appIcon = IconHelper.ExtractAssociatedIcon(path, index, CoreConfig.UseLargeIcons); + if (appIcon != null) { - if (appIcon != null) - { - return appIcon.ToBitmap(); - } - } - - using (Icon appIcon = Shell32.GetFileIcon(path, CoreConfig.UseLargeIcons ? Shell32.IconSize.Large : Shell32.IconSize.Small, false)) - { - if (appIcon != null) - { - return appIcon.ToBitmap(); - } + Log.DebugFormat("Loaded icon for {0}, with dimensions {1}x{2}", path, appIcon.Width, appIcon.Height); + return appIcon; } } catch (Exception exIcon) @@ -195,27 +186,25 @@ namespace Greenshot.Base.Core // Try to find a separator, so we insert ourselves after it for (int i = 0; i < contextMenu.Items.Count; i++) { - if (contextMenu.Items[i].GetType() == typeof(ToolStripSeparator)) + if (contextMenu.Items[i].GetType() != typeof(ToolStripSeparator)) continue; + // Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore" + if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag)) { - // Check if we need to add a new separator, which is done if the first found has a Tag with the value "PluginsAreAddedBefore" - if ("PluginsAreAddedBefore".Equals(contextMenu.Items[i].Tag)) + var separator = new ToolStripSeparator { - var separator = new ToolStripSeparator - { - Tag = "PluginsAreAddedAfter", - Size = new Size(305, 6) - }; - contextMenu.Items.Insert(i, separator); - } - else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag)) - { - continue; - } - - contextMenu.Items.Insert(i + 1, item); - addedItem = true; - break; + Tag = "PluginsAreAddedAfter", + Size = new Size(305, 6) + }; + contextMenu.Items.Insert(i, separator); } + else if (!"PluginsAreAddedAfter".Equals(contextMenu.Items[i].Tag)) + { + continue; + } + + contextMenu.Items.Insert(i + 1, item); + addedItem = true; + break; } // If we didn't insert the item, we just add it... diff --git a/src/Greenshot.Base/Core/WindowCapture.cs b/src/Greenshot.Base/Core/WindowCapture.cs index a6b846fd4..01e1bce56 100644 --- a/src/Greenshot.Base/Core/WindowCapture.cs +++ b/src/Greenshot.Base/Core/WindowCapture.cs @@ -26,10 +26,20 @@ using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Gdi32; +using Dapplo.Windows.Gdi32.Enums; +using Dapplo.Windows.Gdi32.SafeHandles; +using Dapplo.Windows.Gdi32.Structs; +using Dapplo.Windows.Icons; +using Dapplo.Windows.Icons.SafeHandles; +using Dapplo.Windows.Kernel32; +using Dapplo.Windows.User32; +using Dapplo.Windows.User32.Enums; +using Dapplo.Windows.User32.Structs; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; -using Greenshot.Base.UnmanagedHelpers; -using Greenshot.Base.UnmanagedHelpers.Structs; using log4net; namespace Greenshot.Base.Core @@ -42,35 +52,6 @@ namespace Greenshot.Base.Core private static readonly ILog Log = LogManager.GetLogger(typeof(WindowCapture)); private static readonly CoreConfiguration Configuration = IniConfig.GetIniSection(); - /// - /// Used to cleanup the unmanaged resource in the iconInfo for the CaptureCursor method - /// - /// - /// - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); - - /// - /// Get the bounds of all screens combined. - /// - /// A Rectangle of the bounds of the entire display area. - public static Rectangle GetScreenBounds() - { - int left = 0, top = 0, bottom = 0, right = 0; - foreach (Screen screen in Screen.AllScreens) - { - left = Math.Min(left, screen.Bounds.X); - top = Math.Min(top, screen.Bounds.Y); - int screenAbsRight = screen.Bounds.X + screen.Bounds.Width; - int screenAbsBottom = screen.Bounds.Y + screen.Bounds.Height; - right = Math.Max(right, screenAbsRight); - bottom = Math.Max(bottom, screenAbsBottom); - } - - return new Rectangle(left, top, (right + Math.Abs(left)), (bottom + Math.Abs(top))); - } - /// /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. This implementation /// can conveniently be used when the cursor location is needed to deal with a fullscreen bitmap. @@ -78,9 +59,9 @@ namespace Greenshot.Base.Core /// /// Point with cursor location, relative to the top left corner of the monitor setup (which itself might actually not be on any screen) /// - public static Point GetCursorLocationRelativeToScreenBounds() + public static NativePoint GetCursorLocationRelativeToScreenBounds() { - return GetLocationRelativeToScreenBounds(User32.GetCursorLocation()); + return GetLocationRelativeToScreenBounds(User32Api.GetCursorLocation()); } /// @@ -90,12 +71,10 @@ namespace Greenshot.Base.Core /// /// /// Point - public static Point GetLocationRelativeToScreenBounds(Point locationRelativeToScreenOrigin) + public static NativePoint GetLocationRelativeToScreenBounds(NativePoint locationRelativeToScreenOrigin) { - Point ret = locationRelativeToScreenOrigin; - Rectangle bounds = GetScreenBounds(); - ret.Offset(-bounds.X, -bounds.Y); - return ret; + NativeRect bounds = DisplayInfo.ScreenBounds; + return locationRelativeToScreenOrigin.Offset(-bounds.X, -bounds.Y); } /// @@ -110,36 +89,26 @@ namespace Greenshot.Base.Core capture = new Capture(); } - var cursorInfo = new CursorInfo(); - cursorInfo.cbSize = Marshal.SizeOf(cursorInfo); - if (!User32.GetCursorInfo(out cursorInfo)) return capture; - if (cursorInfo.flags != User32.CURSOR_SHOWING) return capture; + var cursorInfo = CursorInfo.Create(); + if (!NativeCursorMethods.GetCursorInfo(ref cursorInfo)) return capture; + if (cursorInfo.Flags != CursorInfoFlags.Showing) return capture; - using SafeIconHandle safeIcon = User32.CopyIcon(cursorInfo.hCursor); - if (!User32.GetIconInfo(safeIcon, out var iconInfo)) return capture; + using SafeIconHandle safeIcon = NativeIconMethods.CopyIcon(cursorInfo.CursorHandle); + if (!NativeIconMethods.GetIconInfo(safeIcon, out var iconInfo)) return capture; - Point cursorLocation = User32.GetCursorLocation(); + NativePoint cursorLocation = User32Api.GetCursorLocation(); // Align cursor location to Bitmap coordinates (instead of Screen coordinates) - var x = cursorLocation.X - iconInfo.xHotspot - capture.ScreenBounds.X; - var y = cursorLocation.Y - iconInfo.yHotspot - capture.ScreenBounds.Y; + var x = cursorLocation.X - iconInfo.Hotspot.X - capture.ScreenBounds.X; + var y = cursorLocation.Y - iconInfo.Hotspot.Y - capture.ScreenBounds.Y; // Set the location - capture.CursorLocation = new Point(x, y); + capture.CursorLocation = new NativePoint(x, y); using (Icon icon = Icon.FromHandle(safeIcon.DangerousGetHandle())) { capture.Cursor = icon; } - - if (iconInfo.hbmMask != IntPtr.Zero) - { - DeleteObject(iconInfo.hbmMask); - } - - if (iconInfo.hbmColor != IntPtr.Zero) - { - DeleteObject(iconInfo.hbmColor); - } - + iconInfo.BitmaskBitmapHandle.Dispose(); + iconInfo.ColorBitmapHandle.Dispose(); return capture; } @@ -161,11 +130,11 @@ namespace Greenshot.Base.Core /// Helper method to create an exception that might explain what is wrong while capturing /// /// string with current method - /// Rectangle of what we want to capture + /// NativeRect of what we want to capture /// - private static Exception CreateCaptureException(string method, Rectangle captureBounds) + private static Exception CreateCaptureException(string method, NativeRect captureBounds) { - Exception exceptionToThrow = User32.CreateWin32Exception(method); + Exception exceptionToThrow = User32Api.CreateWin32Exception(method); if (!captureBounds.IsEmpty) { exceptionToThrow.Data.Add("Height", captureBounds.Height); @@ -233,9 +202,9 @@ namespace Greenshot.Base.Core /// This method will use User32 code to capture the specified captureBounds from the screen /// /// ICapture where the captured Bitmap will be stored - /// Rectangle with the bounds to capture + /// NativeRect with the bounds to capture /// A Capture Object with a part of the Screen as an Image - public static ICapture CaptureRectangle(ICapture capture, Rectangle captureBounds) + public static ICapture CaptureRectangle(ICapture capture, NativeRect captureBounds) { if (capture == null) { @@ -271,9 +240,9 @@ namespace Greenshot.Base.Core /// This method will use User32 code to capture the specified captureBounds from the screen ///
/// ICapture where the captured Bitmap will be stored - /// Rectangle with the bounds to capture + /// NativeRect with the bounds to capture /// A Capture Object with a part of the Screen as an Image - public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, Rectangle captureBounds) + public static ICapture CaptureRectangleFromDesktopScreen(ICapture capture, NativeRect captureBounds) { if (capture == null) { @@ -288,9 +257,9 @@ namespace Greenshot.Base.Core /// /// This method will use User32 code to capture the specified captureBounds from the screen /// - /// Rectangle with the bounds to capture + /// NativeRect with the bounds to capture /// Bitmap which is captured from the screen at the location specified by the captureBounds - public static Bitmap CaptureRectangle(Rectangle captureBounds) + public static Bitmap CaptureRectangle(NativeRect captureBounds) { Bitmap returnBitmap = null; if (captureBounds.Height <= 0 || captureBounds.Width <= 0) @@ -321,7 +290,7 @@ namespace Greenshot.Base.Core } // create a device context we can copy to - using SafeCompatibleDCHandle safeCompatibleDcHandle = GDI32.CreateCompatibleDC(desktopDcHandle); + using SafeCompatibleDcHandle safeCompatibleDcHandle = Gdi32Api.CreateCompatibleDC(desktopDcHandle); // Check if the device context is there, if not throw an error with as much info as possible! if (safeCompatibleDcHandle.IsInvalid) { @@ -332,13 +301,13 @@ namespace Greenshot.Base.Core } // Create BITMAPINFOHEADER for CreateDIBSection - BITMAPINFOHEADERV5 bmi = new BITMAPINFOHEADERV5(captureBounds.Width, captureBounds.Height, 24); + var bitmapInfoHeader = BitmapV5Header.Create(captureBounds.Width, captureBounds.Height, 24); // Make sure the last error is set to 0 - Win32.SetLastError(0); + Kernel32Api.SetLastError(0); // create a bitmap we can copy it to, using GetDeviceCaps to get the width/height - using SafeDibSectionHandle safeDibSectionHandle = GDI32.CreateDIBSection(desktopDcHandle, ref bmi, BITMAPINFOHEADERV5.DIB_RGB_COLORS, out _, IntPtr.Zero, 0); + using SafeDibSectionHandle safeDibSectionHandle = Gdi32Api.CreateDIBSection(desktopDcHandle, ref bitmapInfoHeader, DibColors.RgbColors, out _, IntPtr.Zero, 0); if (safeDibSectionHandle.IsInvalid) { // Get Exception before the error is lost @@ -355,8 +324,8 @@ namespace Greenshot.Base.Core { // bitblt over (make copy) // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags - GDI32.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y, - CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt); + Gdi32Api.BitBlt(safeCompatibleDcHandle, 0, 0, captureBounds.Width, captureBounds.Height, desktopDcHandle, captureBounds.X, captureBounds.Y, + RasterOperations.SourceCopy | RasterOperations.CaptureBlt); } // get a .NET image object for it @@ -388,7 +357,7 @@ namespace Greenshot.Base.Core } // If the region is not empty, we have "offscreenContent" - using Graphics screenGraphics = Graphics.FromHwnd(User32.GetDesktopWindow()); + using Graphics screenGraphics = Graphics.FromHwnd(User32Api.GetDesktopWindow()); offscreenContent = !captureRegion.IsEmpty(screenGraphics); } @@ -397,17 +366,16 @@ namespace Greenshot.Base.Core { using Bitmap tmpBitmap = Image.FromHbitmap(safeDibSectionHandle.DangerousGetHandle()); // Create a new bitmap which has a transparent background - returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, - tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution); + returnBitmap = ImageHelper.CreateEmpty(tmpBitmap.Width, tmpBitmap.Height, PixelFormat.Format32bppArgb, Color.Transparent, tmpBitmap.HorizontalResolution, tmpBitmap.VerticalResolution); // Content will be copied here using Graphics graphics = Graphics.FromImage(returnBitmap); // For all screens copy the content to the new bitmap - foreach (Screen screen in Screen.AllScreens) + + foreach (var displayInfo in DisplayInfo.AllDisplayInfos) { - Rectangle screenBounds = screen.Bounds; - // Make sure the bounds are offsetted to the capture bounds - screenBounds.Offset(-captureBounds.X, -captureBounds.Y); - graphics.DrawImage(tmpBitmap, screenBounds, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height, GraphicsUnit.Pixel); + // Make sure the bounds are offset to the capture bounds + var displayBounds = displayInfo.Bounds.Offset(-captureBounds.X, -captureBounds.Y); + graphics.DrawImage(tmpBitmap, displayBounds, displayBounds.X, displayBounds.Y, displayBounds.Width, displayBounds.Height, GraphicsUnit.Pixel); } } else diff --git a/src/Greenshot.Base/Core/WindowDetails.cs b/src/Greenshot.Base/Core/WindowDetails.cs index 905ab1099..281dde6f4 100644 --- a/src/Greenshot.Base/Core/WindowDetails.cs +++ b/src/Greenshot.Base/Core/WindowDetails.cs @@ -7,13 +7,25 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; +using Dapplo.Windows.Common; +using Dapplo.Windows.Common.Enums; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.DesktopWindowsManager; +using Dapplo.Windows.DesktopWindowsManager.Enums; +using Dapplo.Windows.DesktopWindowsManager.Structs; +using Dapplo.Windows.Gdi32; +using Dapplo.Windows.Gdi32.SafeHandles; +using Dapplo.Windows.Kernel32; +using Dapplo.Windows.Kernel32.Enums; +using Dapplo.Windows.Messages.Enumerations; +using Dapplo.Windows.User32; +using Dapplo.Windows.User32.Enums; +using Dapplo.Windows.User32.Structs; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interop; -using Greenshot.Base.UnmanagedHelpers; -using Greenshot.Base.UnmanagedHelpers.Enums; -using Greenshot.Base.UnmanagedHelpers.Structs; using log4net; namespace Greenshot.Base.Core @@ -187,8 +199,8 @@ namespace Greenshot.Base.Core } // Get the process id - User32.GetWindowThreadProcessId(Handle, out var processId); - return Kernel32.GetProcessPath(processId); + User32Api.GetWindowThreadProcessId(Handle, out var processId); + return Kernel32Api.GetProcessPath(processId); } } @@ -248,35 +260,35 @@ namespace Greenshot.Base.Core IntPtr iconHandle; if (Conf.UseLargeIcons) { - iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); + iconHandle = User32Api.SendMessage(hWnd, WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICON); + iconHandle = User32Api.GetClassLongWrapper(hWnd, ClassLongIndex.IconHandle); } } else { - iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconSmall2, IntPtr.Zero); + iconHandle = User32Api.SendMessage(hWnd, WindowsMessages.WM_GETICON, iconSmall2, IntPtr.Zero); } if (iconHandle == IntPtr.Zero) { - iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconSmall, IntPtr.Zero); + iconHandle = User32Api.SendMessage(hWnd, WindowsMessages.WM_GETICON, iconSmall, IntPtr.Zero); } if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICONSM); + iconHandle = User32Api.GetClassLongWrapper(hWnd, ClassLongIndex.IconHandle); } if (iconHandle == IntPtr.Zero) { - iconHandle = User32.SendMessage(hWnd, (int) WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); + iconHandle = User32Api.SendMessage(hWnd, WindowsMessages.WM_GETICON, iconBig, IntPtr.Zero); } if (iconHandle == IntPtr.Zero) { - iconHandle = User32.GetClassLongWrapper(hWnd, (int) ClassLongIndex.GCL_HICON); + iconHandle = User32Api.GetClassLongWrapper(hWnd, ClassLongIndex.IconHandle); } if (iconHandle == IntPtr.Zero) @@ -342,7 +354,7 @@ namespace Greenshot.Base.Core { if (_parentHandle == IntPtr.Zero) { - _parentHandle = User32.GetParent(Handle); + _parentHandle = User32Api.GetParent(Handle); _parent = null; } @@ -368,7 +380,7 @@ namespace Greenshot.Base.Core { if (_parentHandle == IntPtr.Zero) { - _parentHandle = User32.GetParent(Handle); + _parentHandle = User32Api.GetParent(Handle); } if (_parentHandle != IntPtr.Zero) @@ -434,9 +446,7 @@ namespace Greenshot.Base.Core { if (_text == null) { - var title = new StringBuilder(260, 260); - User32.GetWindowText(Handle, title, title.Capacity); - _text = title.ToString(); + _text = User32Api.GetText(Handle); } return _text; @@ -448,7 +458,7 @@ namespace Greenshot.Base.Core /// /// Gets the window's class name. /// - public string ClassName => _className ??= GetClassName(Handle); + public string ClassName => _className ??= User32Api.GetClassname(Handle); /// /// Gets/Sets whether the window is iconic (minimized) or not. @@ -462,17 +472,17 @@ namespace Greenshot.Base.Core return !Visible; } - return User32.IsIconic(Handle) || Location.X <= -32000; + return User32Api.IsIconic(Handle) || Location.X <= -32000; } set { if (value) { - User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MINIMIZE, IntPtr.Zero); + User32Api.SendMessage(Handle, WindowsMessages.WM_SYSCOMMAND, SysCommands.SC_MINIMIZE, IntPtr.Zero); } else { - User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_RESTORE, IntPtr.Zero); + User32Api.SendMessage(Handle, WindowsMessages.WM_SYSCOMMAND, SysCommands.SC_RESTORE, IntPtr.Zero); } } } @@ -488,15 +498,11 @@ namespace Greenshot.Base.Core { if (Visible) { - Rectangle windowRectangle = WindowRectangle; - foreach (var screen in Screen.AllScreens) + foreach (var displayInfo in DisplayInfo.AllDisplayInfos) { - if (screen.Bounds.Contains(windowRectangle)) + if (WindowRectangle.Equals(displayInfo.Bounds)) { - if (windowRectangle.Equals(screen.Bounds)) - { - return true; - } + return true; } } } @@ -504,17 +510,17 @@ namespace Greenshot.Base.Core return false; } - return User32.IsZoomed(Handle); + return User32Api.IsZoomed(Handle); } set { if (value) { - User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MAXIMIZE, IntPtr.Zero); + User32Api.SendMessage(Handle, WindowsMessages.WM_SYSCOMMAND, SysCommands.SC_MAXIMIZE, IntPtr.Zero); } else { - User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_MINIMIZE, IntPtr.Zero); + User32Api.SendMessage(Handle, WindowsMessages.WM_SYSCOMMAND, SysCommands.SC_MINIMIZE, IntPtr.Zero); } } } @@ -524,7 +530,7 @@ namespace Greenshot.Base.Core /// public bool IsCloaked { - get => DWM.IsWindowCloaked(Handle); + get => DwmApi.IsWindowCloaked(Handle); } /// @@ -542,32 +548,31 @@ namespace Greenshot.Base.Core if (IsApp) { - Rectangle windowRectangle = WindowRectangle; - foreach (Screen screen in Screen.AllScreens) + var windowRectangle = WindowRectangle; + + foreach (var displayInfo in DisplayInfo.AllDisplayInfos) { - if (screen.Bounds.Contains(windowRectangle)) + if (!displayInfo.Bounds.Contains(windowRectangle)) continue; + if (windowRectangle.Equals(displayInfo.Bounds)) { - if (windowRectangle.Equals(screen.Bounds)) + // Fullscreen, it's "visible" when AppVisibilityOnMonitor says yes + // Although it might be the other App, this is not "very" important + NativeRect rect = displayInfo.Bounds; + IntPtr monitor = User32Api.MonitorFromRect(ref rect, MonitorFrom.DefaultToNull); + if (monitor != IntPtr.Zero) { - // Fullscreen, it's "visible" when AppVisibilityOnMonitor says yes - // Although it might be the other App, this is not "very" important - RECT rect = new RECT(screen.Bounds); - IntPtr monitor = User32.MonitorFromRect(ref rect, User32.MONITOR_DEFAULTTONULL); - if (monitor != IntPtr.Zero) + MONITOR_APP_VISIBILITY? monitorAppVisibility = AppVisibility?.GetAppVisibilityOnMonitor(monitor); + //LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds); + if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) { - MONITOR_APP_VISIBILITY? monitorAppVisibility = AppVisibility?.GetAppVisibilityOnMonitor(monitor); - //LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds); - if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) - { - return true; - } + return true; } } - else - { - // Is only partly on the screen, when this happens the app is always visible! - return true; - } + } + else + { + // Is only partly on the screen, when this happens the app is always visible! + return true; } } @@ -585,7 +590,7 @@ namespace Greenshot.Base.Core return IsAppLauncherVisible; } - return User32.IsWindowVisible(Handle); + return User32Api.IsWindowVisible(Handle); } } @@ -602,7 +607,7 @@ namespace Greenshot.Base.Core { get { - User32.GetWindowThreadProcessId(Handle, out var processId); + User32Api.GetWindowThreadProcessId(Handle, out var processId); return processId; } } @@ -613,7 +618,7 @@ namespace Greenshot.Base.Core { try { - User32.GetWindowThreadProcessId(Handle, out var processId); + User32Api.GetWindowThreadProcessId(Handle, out var processId); return Process.GetProcessById(processId); } catch (Exception ex) @@ -625,14 +630,14 @@ namespace Greenshot.Base.Core } } - private Rectangle _previousWindowRectangle = Rectangle.Empty; + private NativeRect _previousWindowRectangle = NativeRect.Empty; private long _lastWindowRectangleRetrieveTime; private const long CacheTime = TimeSpan.TicksPerSecond * 2; /// /// Gets the bounding rectangle of the window /// - public Rectangle WindowRectangle + public NativeRect WindowRectangle { get { @@ -644,9 +649,8 @@ namespace Greenshot.Base.Core { return _previousWindowRectangle; } - - Rectangle windowRect = Rectangle.Empty; - if (DWM.IsDwmEnabled) + NativeRect windowRect = new(); + if (DwmApi.IsDwmEnabled) { bool gotFrameBounds = GetExtendedFrameBounds(out windowRect); if (IsApp) @@ -661,9 +665,9 @@ namespace Greenshot.Base.Core if (gotFrameBounds && WindowsVersion.IsWindows10OrLater && !Maximised) { - // Somehow DWM doesn't calculate it corectly, there is a 1 pixel border around the capture + // Somehow DWM doesn't calculate it correctly, there is a 1 pixel border around the capture // Remove this border, currently it's fixed but TODO: Make it depend on the OS? - windowRect.Inflate(Conf.Win10BorderCrop); + windowRect = windowRect.Inflate(Conf.Win10BorderCrop); _previousWindowRectangle = windowRect; _lastWindowRectangleRetrieveTime = now; return windowRect; @@ -685,13 +689,13 @@ namespace Greenshot.Base.Core // Only if the border size can be retrieved if (GetBorderSize(out var size)) { - windowRect = new Rectangle(windowRect.X + size.Width, windowRect.Y + size.Height, windowRect.Width - (2 * size.Width), + windowRect = new NativeRect(windowRect.X + size.Width, windowRect.Y + size.Height, windowRect.Width - (2 * size.Width), windowRect.Height - (2 * size.Height)); } } _lastWindowRectangleRetrieveTime = now; - // Try to return something valid, by getting returning the previous size if the window doesn't have a Rectangle anymore + // Try to return something valid, by getting returning the previous size if the window doesn't have a NativeRect anymore if (windowRect.IsEmpty) { return _previousWindowRectangle; @@ -708,31 +712,23 @@ namespace Greenshot.Base.Core /// /// Gets the location of the window relative to the screen. /// - public Point Location + public NativePoint Location { - get - { - Rectangle tmpRectangle = WindowRectangle; - return new Point(tmpRectangle.Left, tmpRectangle.Top); - } + get => WindowRectangle.Location; } /// /// Gets the size of the window. /// - public Size Size + public NativeSize Size { - get - { - Rectangle tmpRectangle = WindowRectangle; - return new Size(tmpRectangle.Right - tmpRectangle.Left, tmpRectangle.Bottom - tmpRectangle.Top); - } + get => WindowRectangle.Size; } /// /// Get the client rectangle, this is the part of the window inside the borders (drawable area) /// - public Rectangle ClientRectangle + public NativeRect ClientRectangle { get { @@ -751,7 +747,7 @@ namespace Greenshot.Base.Core /// /// Point with the coordinates to check /// true if the point lies within - public bool Contains(Point p) + public bool Contains(NativePoint p) { return WindowRectangle.Contains(p); } @@ -764,11 +760,11 @@ namespace Greenshot.Base.Core { if (Iconic) { - User32.SendMessage(Handle, (int) WindowsMessages.WM_SYSCOMMAND, (IntPtr) User32.SC_RESTORE, IntPtr.Zero); + User32Api.SendMessage(Handle, WindowsMessages.WM_SYSCOMMAND, SysCommands.SC_RESTORE, IntPtr.Zero); } - User32.BringWindowToTop(Handle); - User32.SetForegroundWindow(Handle); + User32Api.BringWindowToTop(Handle); + User32Api.SetForegroundWindow(Handle); // Make sure windows has time to perform the action // TODO: this is BAD practice! while (Iconic) @@ -783,9 +779,9 @@ namespace Greenshot.Base.Core public WindowStyleFlags WindowStyle { get => unchecked( - (WindowStyleFlags)User32.GetWindowLongWrapper(Handle, (int)WindowLongIndex.GWL_STYLE).ToInt64() + (WindowStyleFlags)User32Api.GetWindowLongWrapper(Handle, WindowLongIndex.GWL_STYLE).ToInt64() ); - set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_STYLE, new IntPtr((long) value)); + set => User32Api.SetWindowLongWrapper(Handle, WindowLongIndex.GWL_STYLE, new IntPtr((long) value)); } /// @@ -795,11 +791,11 @@ namespace Greenshot.Base.Core { get { - var placement = WindowPlacement.Default; - User32.GetWindowPlacement(Handle, ref placement); + var placement = WindowPlacement.Create(); + User32Api.GetWindowPlacement(Handle, ref placement); return placement; } - set { User32.SetWindowPlacement(Handle, ref value); } + set { User32Api.SetWindowPlacement(Handle, ref value); } } /// @@ -807,8 +803,8 @@ namespace Greenshot.Base.Core /// public ExtendedWindowStyleFlags ExtendedWindowStyle { - get => (ExtendedWindowStyleFlags) User32.GetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_EXSTYLE); - set => User32.SetWindowLongWrapper(Handle, (int) WindowLongIndex.GWL_EXSTYLE, new IntPtr((uint) value)); + get => (ExtendedWindowStyleFlags) User32Api.GetWindowLongWrapper(Handle, WindowLongIndex.GWL_EXSTYLE); + set => User32Api.SetWindowLongWrapper(Handle, WindowLongIndex.GWL_EXSTYLE, new IntPtr((uint) value)); } /// @@ -848,10 +844,10 @@ namespace Greenshot.Base.Core }; // Register the Thumbnail - DWM.DwmRegisterThumbnail(tempForm.Handle, Handle, out thumbnailHandle); + DwmApi.DwmRegisterThumbnail(tempForm.Handle, Handle, out thumbnailHandle); // Get the original size - DWM.DwmQueryThumbnailSourceSize(thumbnailHandle, out var sourceSize); + DwmApi.DwmQueryThumbnailSourceSize(thumbnailHandle, out var sourceSize); if (sourceSize.Width <= 0 || sourceSize.Height <= 0) { @@ -859,9 +855,9 @@ namespace Greenshot.Base.Core } // Calculate the location of the temp form - Rectangle windowRectangle = WindowRectangle; - Point formLocation = windowRectangle.Location; - Size borderSize = new Size(); + NativeRect windowRectangle = WindowRectangle; + NativePoint formLocation = windowRectangle.Location; + NativeSize borderSize = new NativeSize(); bool doesCaptureFit = false; if (!Maximised) { @@ -882,12 +878,13 @@ namespace Greenshot.Base.Core if (!workingArea.AreRectangleCornersVisisble(windowRectangle)) { // If none found we find the biggest screen - foreach (Screen screen in Screen.AllScreens) + + foreach (var displayInfo in DisplayInfo.AllDisplayInfos) { - Rectangle newWindowRectangle = new Rectangle(screen.WorkingArea.Location, windowRectangle.Size); + var newWindowRectangle = new NativeRect(displayInfo.WorkingArea.Location, windowRectangle.Size); if (workingArea.AreRectangleCornersVisisble(newWindowRectangle)) { - formLocation = screen.Bounds.Location; + formLocation = displayInfo.Bounds.Location; doesCaptureFit = true; break; } @@ -902,26 +899,26 @@ namespace Greenshot.Base.Core { //GetClientRect(out windowRectangle); GetBorderSize(out borderSize); - formLocation = new Point(windowRectangle.X - borderSize.Width, windowRectangle.Y - borderSize.Height); + formLocation = new NativePoint(windowRectangle.X - borderSize.Width, windowRectangle.Y - borderSize.Height); } tempForm.Location = formLocation; - tempForm.Size = sourceSize.ToSize(); + tempForm.Size = sourceSize; // Prepare rectangle to capture from the screen. - Rectangle captureRectangle = new Rectangle(formLocation.X, formLocation.Y, sourceSize.Width, sourceSize.Height); + var captureRectangle = new NativeRect(formLocation.X, formLocation.Y, sourceSize.Width, sourceSize.Height); if (Maximised) { // Correct capture size for maximized window by offsetting the X,Y with the border size // and subtracting the border from the size (2 times, as we move right/down for the capture without resizing) - captureRectangle.Inflate(borderSize.Width, borderSize.Height); + captureRectangle = captureRectangle.Inflate(borderSize.Width, borderSize.Height); } else { // TODO: Also 8.x? if (WindowsVersion.IsWindows10OrLater) { - captureRectangle.Inflate(Conf.Win10BorderCrop); + captureRectangle = captureRectangle.Inflate(Conf.Win10BorderCrop); } if (autoMode) @@ -941,18 +938,18 @@ namespace Greenshot.Base.Core } // Prepare the displaying of the Thumbnail - DWM_THUMBNAIL_PROPERTIES props = new DWM_THUMBNAIL_PROPERTIES + var props = new DwmThumbnailProperties() { Opacity = 255, Visible = true, - Destination = new RECT(0, 0, sourceSize.Width, sourceSize.Height) + Destination = new NativeRect(0, 0, sourceSize.Width, sourceSize.Height) }; - DWM.DwmUpdateThumbnailProperties(thumbnailHandle, ref props); + DwmApi.DwmUpdateThumbnailProperties(thumbnailHandle, ref props); tempForm.Show(); tempFormShown = true; // Intersect with screen - captureRectangle.Intersect(capture.ScreenBounds); + captureRectangle = captureRectangle.Intersect(capture.ScreenBounds); // Destination bitmap for the capture Bitmap capturedBitmap = null; @@ -1009,10 +1006,9 @@ namespace Greenshot.Base.Core } else { - Color colorizationColor = DWM.ColorizationColor; + var colorizationColor = DwmApi.ColorizationColor; // Modify by losing the transparency and increasing the intensity (as if the background color is white) - colorizationColor = Color.FromArgb(255, (colorizationColor.R + 255) >> 1, (colorizationColor.G + 255) >> 1, (colorizationColor.B + 255) >> 1); - tempForm.BackColor = colorizationColor; + tempForm.BackColor = Color.FromArgb(255, (colorizationColor.R + 255) >> 1, (colorizationColor.G + 255) >> 1, (colorizationColor.B + 255) >> 1); } // Make sure everything is visible @@ -1069,7 +1065,7 @@ namespace Greenshot.Base.Core if (thumbnailHandle != IntPtr.Zero) { // Un-register (cleanup), as we are finished we don't need the form or the thumbnail anymore - DWM.DwmUnregisterThumbnail(thumbnailHandle); + DwmApi.DwmUnregisterThumbnail(thumbnailHandle); } if (tempForm != null) @@ -1108,7 +1104,7 @@ namespace Greenshot.Base.Core /// /// Apply transparency by comparing a transparent capture with a black and white background /// A "Math.min" makes sure there is no overflow, but this could cause the picture to have shifted colors. - /// The pictures should have been taken without differency, except for the colors. + /// The pictures should have been taken without difference, except for the colors. /// /// Bitmap with the black image /// Bitmap with the black image @@ -1161,46 +1157,46 @@ namespace Greenshot.Base.Core /// /// Helper method to get the window size for DWM Windows /// - /// out Rectangle + /// out NativeRect /// bool true if it worked - private bool GetExtendedFrameBounds(out Rectangle rectangle) + private bool GetExtendedFrameBounds(out NativeRect rectangle) { - int result = DWM.DwmGetWindowAttribute(Handle, DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out RECT rect, Marshal.SizeOf(typeof(RECT))); - if (result >= 0) + var result = DwmApi.DwmGetWindowAttribute(Handle, DwmWindowAttributes.ExtendedFrameBounds, out NativeRect rect, Marshal.SizeOf(typeof(NativeRect))); + if (result.Succeeded()) { - rectangle = rect.ToRectangle(); + rectangle = rect; return true; } - rectangle = Rectangle.Empty; + rectangle = NativeRect.Empty; return false; } /// /// Helper method to get the window size for GDI Windows /// - /// out Rectangle + /// out NativeRect /// bool true if it worked - private bool GetClientRect(out Rectangle rectangle) + private bool GetClientRect(out NativeRect rectangle) { var windowInfo = new WindowInfo(); // Get the Window Info for this window - bool result = User32.GetWindowInfo(Handle, ref windowInfo); - rectangle = result ? windowInfo.rcClient.ToRectangle() : Rectangle.Empty; + bool result = User32Api.GetWindowInfo(Handle, ref windowInfo); + rectangle = result ? windowInfo.ClientBounds : NativeRect.Empty; return result; } /// /// Helper method to get the window size for GDI Windows /// - /// out Rectangle + /// out NativeRect /// bool true if it worked - private bool GetWindowRect(out Rectangle rectangle) + private bool GetWindowRect(out NativeRect rectangle) { var windowInfo = new WindowInfo(); // Get the Window Info for this window - bool result = User32.GetWindowInfo(Handle, ref windowInfo); - rectangle = result ? windowInfo.rcWindow.ToRectangle() : Rectangle.Empty; + bool result = User32Api.GetWindowInfo(Handle, ref windowInfo); + rectangle = result ? windowInfo.Bounds : NativeRect.Empty; return result; } @@ -1209,12 +1205,12 @@ namespace Greenshot.Base.Core /// /// out Size /// bool true if it worked - private bool GetBorderSize(out Size size) + private bool GetBorderSize(out NativeSize size) { var windowInfo = new WindowInfo(); // Get the Window Info for this window - bool result = User32.GetWindowInfo(Handle, ref windowInfo); - size = result ? new Size((int) windowInfo.cxWindowBorders, (int) windowInfo.cyWindowBorders) : Size.Empty; + bool result = User32Api.GetWindowInfo(Handle, ref windowInfo); + size = result ? windowInfo.BorderSize : NativeSize.Empty; return result; } @@ -1224,7 +1220,7 @@ namespace Greenshot.Base.Core /// hWnd of the window to bring to the foreground public static void ToForeground(IntPtr hWnd) { - var foregroundWindow = User32.GetForegroundWindow(); + var foregroundWindow = User32Api.GetForegroundWindow(); if (hWnd == foregroundWindow) { return; @@ -1237,22 +1233,22 @@ namespace Greenshot.Base.Core return; } - var threadId1 = User32.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero); - var threadId2 = User32.GetWindowThreadProcessId(hWnd, IntPtr.Zero); + var threadId1 = User32Api.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero); + var threadId2 = User32Api.GetWindowThreadProcessId(hWnd, IntPtr.Zero); // Show window in foreground. if (threadId1 != threadId2) { - User32.AttachThreadInput(threadId1, threadId2, 1); - User32.SetForegroundWindow(hWnd); - User32.AttachThreadInput(threadId1, threadId2, 0); + User32Api.AttachThreadInput(threadId1, threadId2, 1); + User32Api.SetForegroundWindow(hWnd); + User32Api.AttachThreadInput(threadId1, threadId2, 0); } else { - User32.SetForegroundWindow(hWnd); + User32Api.SetForegroundWindow(hWnd); } - User32.BringWindowToTop(hWnd); + User32Api.BringWindowToTop(hWnd); if (window.Iconic) { @@ -1273,12 +1269,12 @@ namespace Greenshot.Base.Core /// private Region GetRegion() { - using (SafeRegionHandle region = GDI32.CreateRectRgn(0, 0, 0, 0)) + using (SafeRegionHandle region = Gdi32Api.CreateRectRgn(0, 0, 0, 0)) { if (!region.IsInvalid) { - RegionResult result = User32.GetWindowRgn(Handle, region); - if (result != RegionResult.REGION_ERROR && result != RegionResult.REGION_NULLREGION) + var result = User32Api.GetWindowRgn(Handle, region); + if (result != RegionResults.Error && result != RegionResults.NullRegion) { return Region.FromHrgn(region.DangerousGetHandle()); } @@ -1338,7 +1334,7 @@ namespace Greenshot.Base.Core foreach (ProcessThread pT in proc.Threads) { - IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); + IntPtr pOpenThread = Kernel32Api.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); if (pOpenThread == IntPtr.Zero) { @@ -1346,7 +1342,7 @@ namespace Greenshot.Base.Core } frozen = true; - Kernel32.SuspendThread(pOpenThread); + Kernel32Api.SuspendThread(pOpenThread); pT.Dispose(); } } @@ -1377,14 +1373,14 @@ namespace Greenshot.Base.Core foreach (ProcessThread pT in proc.Threads) { - IntPtr pOpenThread = Kernel32.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); + IntPtr pOpenThread = Kernel32Api.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint) pT.Id); if (pOpenThread == IntPtr.Zero) { break; } - Kernel32.ResumeThread(pOpenThread); + Kernel32Api.ResumeThread(pOpenThread); } } @@ -1395,7 +1391,7 @@ namespace Greenshot.Base.Core ///
public Image PrintWindow() { - Rectangle windowRect = WindowRectangle; + NativeRect windowRect = WindowRectangle; // Start the capture Exception exceptionOccurred = null; Image returnImage; @@ -1412,14 +1408,14 @@ namespace Greenshot.Base.Core returnImage = ImageHelper.CreateEmpty(windowRect.Width, windowRect.Height, pixelFormat, backgroundColor, 96,96); using Graphics graphics = Graphics.FromImage(returnImage); - using (SafeDeviceContextHandle graphicsDc = graphics.GetSafeDeviceContext()) + using (SafeGraphicsDcHandle graphicsDc = graphics.GetSafeDeviceContext()) { - var pwFlags = WindowsVersion.IsWindows10OrLater ? PrintWindowFlags.PW_RENDERFULLCONTENT : PrintWindowFlags.PW_ENTIREWINDOW; - bool printSucceeded = User32.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), pwFlags); + var pwFlags = WindowsVersion.IsWindows10OrLater ? PrintWindowFlags.PW_RENDERFULLCONTENT : PrintWindowFlags.PW_COMPLETE; + bool printSucceeded = User32Api.PrintWindow(Handle, graphicsDc.DangerousGetHandle(), pwFlags); if (!printSucceeded) { // something went wrong, most likely a "0x80004005" (Access Denied) when using UAC - exceptionOccurred = User32.CreateWin32Exception("PrintWindow"); + exceptionOccurred = User32Api.CreateWin32Exception("PrintWindow"); } } @@ -1443,10 +1439,9 @@ namespace Greenshot.Base.Core if (!HasParent && Maximised) { - Log.Debug("Correcting for maximalization"); + Log.Debug("Correcting for maximized window"); GetBorderSize(out var borderSize); - Rectangle borderRectangle = new Rectangle(borderSize.Width, borderSize.Height, windowRect.Width - (2 * borderSize.Width), - windowRect.Height - (2 * borderSize.Height)); + NativeRect borderRectangle = new NativeRect(borderSize.Width, borderSize.Height, windowRect.Width - (2 * borderSize.Width), windowRect.Height - (2 * borderSize.Height)); ImageHelper.Crop(ref returnImage, ref borderRectangle); } @@ -1469,7 +1464,7 @@ namespace Greenshot.Base.Core /// WindowDetails of the current window public static WindowDetails GetActiveWindow() { - IntPtr hWnd = User32.GetForegroundWindow(); + IntPtr hWnd = User32Api.GetForegroundWindow(); if (hWnd != IntPtr.Zero) { if (IgnoreHandles.Contains(hWnd)) @@ -1496,7 +1491,7 @@ namespace Greenshot.Base.Core /// WindowDetails for the desktop window public static WindowDetails GetDesktopWindow() { - return new WindowDetails(User32.GetDesktopWindow()); + return new WindowDetails(User32Api.GetDesktopWindow()); } /// @@ -1520,9 +1515,9 @@ namespace Greenshot.Base.Core /// /// Recursive "find children which" /// - /// point to check for - /// - public WindowDetails FindChildUnderPoint(Point point) + /// NativePoint to check for + /// WindowDetails + public WindowDetails FindChildUnderPoint(NativePoint point) { if (!Contains(point)) { @@ -1548,25 +1543,13 @@ namespace Greenshot.Base.Core return this; } - /// - /// Retrieves the classname for a hWnd - /// - /// IntPtr with the windows handle - /// String with ClassName - public static string GetClassName(IntPtr hWnd) - { - var classNameBuilder = new StringBuilder(260, 260); - User32.GetClassName(hWnd, classNameBuilder, classNameBuilder.Capacity); - return classNameBuilder.ToString(); - } - /// /// Helper method to decide if a top level window is visible /// /// /// /// - private static bool IsVisible(WindowDetails window, Rectangle screenBounds) + private static bool IsVisible(WindowDetails window, NativeRect screenBounds) { // Ignore invisible if (!window.Visible) @@ -1586,8 +1569,7 @@ namespace Greenshot.Base.Core } // On windows which are visible on the screen - var windowRect = window.WindowRectangle; - windowRect.Intersect(screenBounds); + var windowRect = window.WindowRectangle.Intersect(screenBounds); if (windowRect.IsEmpty) { return false; @@ -1609,7 +1591,7 @@ namespace Greenshot.Base.Core /// List WindowDetails with all the visible top level windows public static IEnumerable GetVisibleWindows() { - Rectangle screenBounds = WindowCapture.GetScreenBounds(); + var screenBounds = DisplayInfo.ScreenBounds; foreach (var window in GetAppWindows()) { if (IsVisible(window, screenBounds)) @@ -1640,7 +1622,7 @@ namespace Greenshot.Base.Core yield break; } - var nextHandle = User32.FindWindow(AppWindowClass, null); + var nextHandle = User32Api.FindWindow(AppWindowClass, null); while (nextHandle != IntPtr.Zero) { var metroApp = new WindowDetails(nextHandle); @@ -1648,14 +1630,14 @@ namespace Greenshot.Base.Core // Check if we have a gutter! if (metroApp.Visible && !metroApp.Maximised) { - var gutterHandle = User32.FindWindow(GutterClass, null); + var gutterHandle = User32Api.FindWindow(GutterClass, null); if (gutterHandle != IntPtr.Zero) { yield return new WindowDetails(gutterHandle); } } - nextHandle = User32.FindWindowEx(IntPtr.Zero, nextHandle, AppWindowClass, null); + nextHandle = User32Api.FindWindowEx(IntPtr.Zero, nextHandle, AppWindowClass, null); } } @@ -1820,7 +1802,7 @@ namespace Greenshot.Base.Core return null; } - IntPtr appLauncher = User32.FindWindow(ApplauncherClass, null); + IntPtr appLauncher = User32Api.FindWindow(ApplauncherClass, null); if (appLauncher != IntPtr.Zero) { return new WindowDetails(appLauncher); @@ -1862,7 +1844,7 @@ namespace Greenshot.Base.Core result.AppendLine($"IsWin10App: {IsWin10App}"); result.AppendLine($"IsApp: {IsApp}"); result.AppendLine($"Visible: {Visible}"); - result.AppendLine($"IsWindowVisible: {User32.IsWindowVisible(Handle)}"); + result.AppendLine($"IsWindowVisible: {User32Api.IsWindowVisible(Handle)}"); result.AppendLine($"IsCloaked: {IsCloaked}"); result.AppendLine($"Iconic: {Iconic}"); result.AppendLine($"IsBackgroundWin10App: {IsBackgroundWin10App}"); diff --git a/src/Greenshot.Base/Core/WindowsEnumerator.cs b/src/Greenshot.Base/Core/WindowsEnumerator.cs index df3de72b0..1db1f5007 100644 --- a/src/Greenshot.Base/Core/WindowsEnumerator.cs +++ b/src/Greenshot.Base/Core/WindowsEnumerator.cs @@ -21,8 +21,7 @@ using System; using System.Collections.Generic; -using System.Text; -using Greenshot.Base.UnmanagedHelpers; +using Dapplo.Windows.User32; namespace Greenshot.Base.Core { @@ -44,15 +43,13 @@ namespace Greenshot.Base.Core public WindowsEnumerator GetWindows(IntPtr hWndParent, string classname) { Items = new List(); - User32.EnumChildWindows(hWndParent, WindowEnum, IntPtr.Zero); + User32Api.EnumChildWindows(hWndParent, OnWindowEnum, IntPtr.Zero); bool hasParent = !IntPtr.Zero.Equals(hWndParent); string parentText = null; if (hasParent) { - var title = new StringBuilder(260, 260); - User32.GetWindowText(hWndParent, title, title.Capacity); - parentText = title.ToString(); + parentText = User32Api.GetText(hWndParent); } var windows = new List(); @@ -74,17 +71,6 @@ namespace Greenshot.Base.Core return this; } - /// - /// The enum Windows callback. - /// - /// Window Handle - /// Application defined value - /// 1 to continue enumeration, 0 to stop - private int WindowEnum(IntPtr hWnd, int lParam) - { - return OnWindowEnum(hWnd) ? 1 : 0; - } - /// /// Called whenever a new window is about to be added /// by the Window enumeration called from GetWindows. @@ -94,8 +80,9 @@ namespace Greenshot.Base.Core /// be empty. /// /// Window handle to add + /// /// True to continue enumeration, False to stop - private bool OnWindowEnum(IntPtr hWnd) + private bool OnWindowEnum(IntPtr hWnd, IntPtr lParam) { if (!WindowDetails.IsIgnoreHandle(hWnd)) { diff --git a/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs b/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs index a0488cd3f..fb95dccb3 100644 --- a/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs +++ b/src/Greenshot.Base/Core/WmInputLangChangeRequestFilter.cs @@ -20,7 +20,7 @@ */ using System.Windows.Forms; -using Greenshot.Base.UnmanagedHelpers.Enums; +using Dapplo.Windows.Messages.Enumerations; using log4net; namespace Greenshot.Base.Core diff --git a/src/Greenshot.Base/Effects/DropShadowEffect.cs b/src/Greenshot.Base/Effects/DropShadowEffect.cs index 8f69854bc..b597e4463 100644 --- a/src/Greenshot.Base/Effects/DropShadowEffect.cs +++ b/src/Greenshot.Base/Effects/DropShadowEffect.cs @@ -23,6 +23,7 @@ using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; namespace Greenshot.Base.Effects @@ -42,7 +43,7 @@ namespace Greenshot.Base.Effects public int ShadowSize { get; set; } - public Point ShadowOffset { get; set; } + public NativePoint ShadowOffset { get; set; } public virtual void Reset() { diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index 1c9b9b84c..169bd9395 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -5,10 +5,16 @@ - + + + + + + + - + diff --git a/src/Greenshot.Base/Hooking/WindowsEventHook.cs b/src/Greenshot.Base/Hooking/WindowsEventHook.cs deleted file mode 100644 index 7982cc35a..000000000 --- a/src/Greenshot.Base/Hooking/WindowsEventHook.cs +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using Greenshot.Base.UnmanagedHelpers.Enums; - -namespace Greenshot.Base.Hooking -{ - /// - /// The WinEventHook can register handlers to become important windows events - /// This makes it possible to know a.o. when a window is created, moved, updated and closed. - /// - public class WindowsEventHook : IDisposable - { - private readonly WinEventDelegate _winEventHandler; - private GCHandle _gcHandle; - - /// - /// Used with Register hook - /// - /// - /// - /// - /// - /// - /// - public delegate void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); - - /// - /// Create a WindowsEventHook object - /// - public WindowsEventHook() - { - _winEventHandler = WinEventDelegateHandler; - _gcHandle = GCHandle.Alloc(_winEventHandler); - } - - [DllImport("user32", SetLastError = true)] - private static extern bool UnhookWinEvent(IntPtr hWinEventHook); - - [DllImport("user32", SetLastError = true)] - private static extern IntPtr SetWinEventHook(WinEvent eventMin, WinEvent eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, int idProcess, int idThread, - WinEventHookFlags dwFlags); - - /// - /// Used with SetWinEventHook - /// - /// - /// - /// - /// - /// - /// - /// - private delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); - - private readonly IDictionary _winEventHandlers = new Dictionary(); - - /// - /// Are hooks active? - /// - public bool IsHooked => _winEventHandlers.Count > 0; - - /// - /// Hook a WinEvent - /// - /// - /// - /// true if success - public void Hook(WinEvent winEvent, WinEventHandler winEventHandler) - { - Hook(winEvent, winEvent, winEventHandler); - } - - /// - /// Hook a WinEvent - /// - /// - /// - /// - public void Hook(WinEvent winEventStart, WinEvent winEventEnd, WinEventHandler winEventHandler) - { - var hookPtr = SetWinEventHook(winEventStart, winEventEnd, IntPtr.Zero, _winEventHandler, 0, 0, - WinEventHookFlags.WINEVENT_SKIPOWNPROCESS | WinEventHookFlags.WINEVENT_OUTOFCONTEXT); - _winEventHandlers.Add(hookPtr, winEventHandler); - } - - /// - /// Remove all hooks - /// - private void Unhook() - { - foreach (var hookPtr in _winEventHandlers.Keys) - { - if (hookPtr != IntPtr.Zero) - { - UnhookWinEvent(hookPtr); - } - } - - _winEventHandlers.Clear(); - _gcHandle.Free(); - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Unhook(); - } - - /// - /// Call the WinEventHandler for this event - /// - /// - /// - /// - /// - /// - /// - /// - private void WinEventDelegateHandler(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) - { - if (_winEventHandlers.TryGetValue(hWinEventHook, out var handler)) - { - handler(eventType, hWnd, idObject, idChild, dwEventThread, dwmsEventTime); - } - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs b/src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs deleted file mode 100644 index b8a4781a3..000000000 --- a/src/Greenshot.Base/Hooking/WindowsOpenCloseMonitor.cs +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using Greenshot.Base.Core; -using Greenshot.Base.UnmanagedHelpers.Enums; - -namespace Greenshot.Base.Hooking -{ - /// - /// Event arguments for the WindowOpenCloseEvent - /// - public class WindowOpenCloseEventArgs : EventArgs - { - public bool IsOpen { get; set; } - - /// - /// HWnd of the window which has a changed title - /// - public IntPtr HWnd { get; set; } - - /// - /// Title which is changed - /// - public string Title { get; set; } - - public string ClassName { get; set; } - } - - /// - /// Delegate for the window open close event - /// - /// - public delegate void WindowOpenCloseEventDelegate(WindowOpenCloseEventArgs eventArgs); - - /// - /// Monitor all new and destroyed windows - /// - public sealed class WindowsOpenCloseMonitor : IDisposable - { - private WindowsEventHook _hook; - private readonly object _lockObject = new object(); - - // ReSharper disable once InconsistentNaming - private event WindowOpenCloseEventDelegate _windowOpenCloseEvent; - - /// - /// Add / remove event handler to the title monitor - /// - public event WindowOpenCloseEventDelegate WindowOpenCloseChangeEvent - { - add - { - lock (_lockObject) - { - if (_hook == null) - { - _hook = new WindowsEventHook(); - _hook.Hook(WinEvent.EVENT_OBJECT_CREATE, WinEvent.EVENT_OBJECT_DESTROY, WinEventHandler); - } - - _windowOpenCloseEvent += value; - } - } - remove - { - lock (_lockObject) - { - _windowOpenCloseEvent -= value; - if (_windowOpenCloseEvent == null || _windowOpenCloseEvent.GetInvocationList().Length == 0) - { - if (_hook != null) - { - _hook.Dispose(); - _hook = null; - } - } - } - } - } - - /// - /// WinEventDelegate for the creation and destruction - /// - /// - /// - /// - /// - /// - /// - private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) - { - if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) - { - return; - } - - if (eventType == WinEvent.EVENT_OBJECT_CREATE) - { - if (_windowOpenCloseEvent != null) - { - var windowsDetails = new WindowDetails(hWnd); - _windowOpenCloseEvent(new WindowOpenCloseEventArgs - { - HWnd = hWnd, - IsOpen = true, - Title = windowsDetails.Text, - ClassName = windowsDetails.ClassName - }); - } - } - - if (eventType == WinEvent.EVENT_OBJECT_DESTROY) - { - _windowOpenCloseEvent?.Invoke(new WindowOpenCloseEventArgs - { - HWnd = hWnd, - IsOpen = false - }); - } - } - - private bool _disposedValue; // To detect redundant calls - - /// - /// Dispose the underlying hook - /// - public void Dispose(bool disposing) - { - if (_disposedValue) - { - return; - } - - lock (_lockObject) - { - _hook?.Dispose(); - } - - _disposedValue = true; - } - - /// - /// Make sure the finalizer disposes the underlying hook - /// - ~WindowsOpenCloseMonitor() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(false); - } - - /// - /// Dispose the underlying hook - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs b/src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs deleted file mode 100644 index f93542228..000000000 --- a/src/Greenshot.Base/Hooking/WindowsTitleMonitor.cs +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using Greenshot.Base.Core; -using Greenshot.Base.UnmanagedHelpers.Enums; - -namespace Greenshot.Base.Hooking -{ - /// - /// Event arguments for the TitleChangeEvent - /// - public class TitleChangeEventArgs : EventArgs - { - /// - /// HWnd of the window which has a changed title - /// - public IntPtr HWnd { get; set; } - - /// - /// Title which is changed - /// - public string Title { get; set; } - } - - /// - /// Delegate for the title change event - /// - /// - public delegate void TitleChangeEventDelegate(TitleChangeEventArgs eventArgs); - - /// - /// Monitor all title changes - /// - public sealed class WindowsTitleMonitor : IDisposable - { - private WindowsEventHook _hook; - private readonly object _lockObject = new object(); - - // ReSharper disable once InconsistentNaming - private event TitleChangeEventDelegate _titleChangeEvent; - - /// - /// Add / remove event handler to the title monitor - /// - public event TitleChangeEventDelegate TitleChangeEvent - { - add - { - lock (_lockObject) - { - if (_hook == null) - { - _hook = new WindowsEventHook(); - _hook.Hook(WinEvent.EVENT_OBJECT_NAMECHANGE, WinEventHandler); - } - - _titleChangeEvent += value; - } - } - remove - { - lock (_lockObject) - { - _titleChangeEvent -= value; - if (_titleChangeEvent == null || _titleChangeEvent.GetInvocationList().Length == 0) - { - if (_hook != null) - { - _hook.Dispose(); - _hook = null; - } - } - } - } - } - - /// - /// WinEventDelegate for the creation & destruction - /// - /// - /// - /// - /// - /// - /// - private void WinEventHandler(WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime) - { - if (hWnd == IntPtr.Zero || idObject != EventObjects.OBJID_WINDOW) - { - return; - } - - if (eventType == WinEvent.EVENT_OBJECT_NAMECHANGE) - { - if (_titleChangeEvent != null) - { - string newTitle = new WindowDetails(hWnd).Text; - _titleChangeEvent(new TitleChangeEventArgs - { - HWnd = hWnd, - Title = newTitle - }); - } - } - } - - private bool _disposedValue; // To detect redundant calls - - /// - /// Dispose the underlying hook - /// - public void Dispose(bool disposing) - { - if (_disposedValue) - { - return; - } - - lock (_lockObject) - { - _hook?.Dispose(); - } - - _disposedValue = true; - } - - /// - /// Make sure the finalizer disposes the underlying hook - /// - ~WindowsTitleMonitor() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(false); - } - - /// - /// Dispose the underlying hook - /// - public void Dispose() - { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - GC.SuppressFinalize(this); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs b/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs index c55044928..1894eb647 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/Adorners/IAdorner.cs @@ -22,6 +22,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; namespace Greenshot.Base.Interfaces.Drawing.Adorners { @@ -35,7 +36,7 @@ namespace Greenshot.Base.Interfaces.Drawing.Adorners /// /// These are the bounds of the adorner /// - Rectangle Bounds { get; } + NativeRect Bounds { get; } /// /// The current edit status, this is needed to locate the adorner to send events to @@ -53,7 +54,7 @@ namespace Greenshot.Base.Interfaces.Drawing.Adorners /// /// Point to test /// true if so - bool HitTest(Point point); + bool HitTest(NativePoint point); /// /// Handle the MouseDown event @@ -97,7 +98,7 @@ namespace Greenshot.Base.Interfaces.Drawing.Adorners /// Adjust UI elements to the supplied DPI settings /// /// - void AdjustToDpi(uint dpi); + void AdjustToDpi(int dpi); /// /// The color of the lines around the adorner diff --git a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs index b42192916..80e2bd140 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainer.cs @@ -22,9 +22,9 @@ using System; using System.Collections.Generic; using System.ComponentModel; -using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces.Drawing.Adorners; namespace Greenshot.Base.Interfaces.Drawing @@ -49,15 +49,15 @@ namespace Greenshot.Base.Interfaces.Drawing int Height { get; set; } - Point Location { get; } + NativePoint Location { get; } - Size Size { get; } + NativeSize Size { get; } - Rectangle Bounds { get; } + NativeRect Bounds { get; } - Rectangle DrawingBounds { get; } + NativeRect DrawingBounds { get; } - void ApplyBounds(RectangleF newBounds); + void ApplyBounds(NativeRectFloat newBounds); bool HasFilters { get; } @@ -101,8 +101,8 @@ namespace Greenshot.Base.Interfaces.Drawing /// /// Adjust UI elements to the supplied DPI settings /// - /// uint - void AdjustToDpi(uint dpi); + /// int + void AdjustToDpi(int dpi); /// /// Enable a way for elements to add a context menu entry diff --git a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainerList.cs b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainerList.cs index 39235f63b..795c36afe 100644 --- a/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainerList.cs +++ b/src/Greenshot.Base/Interfaces/Drawing/IDrawableContainerList.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; namespace Greenshot.Base.Interfaces.Drawing { @@ -35,16 +36,16 @@ namespace Greenshot.Base.Interfaces.Drawing ISurface Parent { get; set; } EditStatus Status { get; set; } - Rectangle DrawingBounds { get; } + NativeRect DrawingBounds { get; } void MakeBoundsChangeUndoable(bool allowMerge); void Transform(Matrix matrix); void MoveBy(int dx, int dy); bool ClickableAt(int x, int y); IDrawableContainer ClickableElementAt(int x, int y); void OnDoubleClick(); - bool HasIntersectingFilters(Rectangle clipRectangle); - bool IntersectsWith(Rectangle clipRectangle); - void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle); + bool HasIntersectingFilters(NativeRect clipRectangle); + bool IntersectsWith(NativeRect clipRectangle); + void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, NativeRect clipRectangle); void SetForegroundColor(Color color); void SetBackgroundColor(Color color); int IncreaseLineThickness(int increaseBy); @@ -58,6 +59,6 @@ namespace Greenshot.Base.Interfaces.Drawing void PushElementsToBottom(IDrawableContainerList elements); void ShowContextMenu(MouseEventArgs e, ISurface surface); void HandleFieldChangedEvent(object sender, FieldChangedEventArgs e); - void AdjustToDpi(uint dpi); + void AdjustToDpi(int dpi); } } \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/ICapture.cs b/src/Greenshot.Base/Interfaces/ICapture.cs index 6e4fc31b2..d1c8881a8 100644 --- a/src/Greenshot.Base/Interfaces/ICapture.cs +++ b/src/Greenshot.Base/Interfaces/ICapture.cs @@ -21,6 +21,7 @@ using System; using System.Drawing; +using Dapplo.Windows.Common.Structs; namespace Greenshot.Base.Interfaces { @@ -47,7 +48,7 @@ namespace Greenshot.Base.Interfaces /// /// Bounds on the screen from which the capture comes /// - Rectangle ScreenBounds { get; set; } + NativeRect ScreenBounds { get; set; } /// /// The cursor @@ -62,18 +63,18 @@ namespace Greenshot.Base.Interfaces /// /// Location of the cursor /// - Point CursorLocation { get; set; } + NativePoint CursorLocation { get; set; } /// /// Location of the capture /// - Point Location { get; set; } + NativePoint Location { get; set; } /// /// Crops the capture to the specified rectangle (with Bitmap coordinates!) /// - /// Rectangle with bitmap coordinates - bool Crop(Rectangle cropRectangle); + /// NativeRect with bitmap coordinates + bool Crop(NativeRect cropRectangle); /// /// Apply a translate to the mouse location. e.g. needed for crop diff --git a/src/Greenshot.Base/UnmanagedHelpers/EnumWindowsProc.cs b/src/Greenshot.Base/Interfaces/IProvideDeviceDpi.cs similarity index 76% rename from src/Greenshot.Base/UnmanagedHelpers/EnumWindowsProc.cs rename to src/Greenshot.Base/Interfaces/IProvideDeviceDpi.cs index 9d5b10b92..73db77af6 100644 --- a/src/Greenshot.Base/UnmanagedHelpers/EnumWindowsProc.cs +++ b/src/Greenshot.Base/Interfaces/IProvideDeviceDpi.cs @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * @@ -19,15 +19,16 @@ * along with this program. If not, see . */ -using System; - -namespace Greenshot.Base.UnmanagedHelpers +namespace Greenshot.Base.Interfaces { /// - /// Used with EnumWindows or EnumChildWindows + /// IProvideDeviceDpi can provide the current DPI for a component /// - /// IntPtr - /// int - /// int - public delegate int EnumWindowsProc(IntPtr hWnd, int lParam); + public interface IProvideDeviceDpi + { + /// + /// A simple getter for the current DPI + /// + int DeviceDpi { get; } + } } \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/ISurface.cs b/src/Greenshot.Base/Interfaces/ISurface.cs index 4ec000ed9..cedb8f51c 100644 --- a/src/Greenshot.Base/Interfaces/ISurface.cs +++ b/src/Greenshot.Base/Interfaces/ISurface.cs @@ -24,6 +24,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.IO; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Effects; using Greenshot.Base.Interfaces.Drawing; @@ -185,8 +186,8 @@ namespace Greenshot.Base.Interfaces /// Invalidates the specified region of the Surface. /// Takes care of the Surface zoom level, accepts rectangle in the coordinate space of the Image. /// - /// Bounding rectangle for updated elements, in the coordinate space of the Image. - void InvalidateElements(Rectangle rectangleToInvalidate); + /// NativeRect Bounding rectangle for updated elements, in the coordinate space of the Image. + void InvalidateElements(NativeRect rectangleToInvalidate); bool Modified { get; set; } string LastSaveFullPath { get; set; } @@ -214,28 +215,28 @@ namespace Greenshot.Base.Interfaces Fraction ZoomFactor { get; set; } /// - /// Translate a point from image coorditate space to surface coordinate space. + /// Translate a point from image coordinate space to surface coordinate space. /// /// A point in the coordinate space of the image. - Point ToSurfaceCoordinates(Point point); + NativePoint ToSurfaceCoordinates(NativePoint point); /// - /// Translate a rectangle from image coorditate space to surface coordinate space. + /// Translate a rectangle from image coordinate space to surface coordinate space. /// - /// A rectangle in the coordinate space of the image. - Rectangle ToSurfaceCoordinates(Rectangle rc); + /// NativeRect in the coordinate space of the image. + NativeRect ToSurfaceCoordinates(NativeRect rc); /// - /// Translate a point from surface coorditate space to image coordinate space. + /// Translate a point from surface coordinate space to image coordinate space. /// - /// A point in the coordinate space of the surface. - Point ToImageCoordinates(Point point); + /// NativePoint in the coordinate space of the surface. + NativePoint ToImageCoordinates(NativePoint point); /// - /// Translate a rectangle from surface coorditate space to image coordinate space. + /// Translate a NativeRect from surface coordinate space to image coordinate space. /// - /// A rectangle in the coordinate space of the surface. - Rectangle ToImageCoordinates(Rectangle rc); + /// NativeRect in the coordinate space of the surface. + NativeRect ToImageCoordinates(NativeRect rc); /// /// Make it possible to undo the specified IMemento diff --git a/src/Greenshot.Base/Interfaces/Ocr/Line.cs b/src/Greenshot.Base/Interfaces/Ocr/Line.cs index fc21f72ae..ff5914a4e 100644 --- a/src/Greenshot.Base/Interfaces/Ocr/Line.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/Line.cs @@ -1,4 +1,26 @@ -using System.Drawing; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; namespace Greenshot.Base.Interfaces.Ocr { @@ -7,7 +29,7 @@ namespace Greenshot.Base.Interfaces.Ocr /// public class Line { - private Rectangle? _calculatedBounds; + private NativeRect? _calculatedBounds; /// /// Constructor will preallocate the number of words @@ -35,18 +57,18 @@ namespace Greenshot.Base.Interfaces.Ocr /// /// Calculate the bounds of the words /// - /// Rectangle - private Rectangle CalculateBounds() + /// NativeRect + private NativeRect CalculateBounds() { if (Words.Length == 0) { - return Rectangle.Empty; + return NativeRect.Empty; } var result = Words[0].Bounds; for (var index = 0; index < Words.Length; index++) { - result = Rectangle.Union(result, Words[index].Bounds); + result = result.Union(Words[index].Bounds); } return result; @@ -55,7 +77,7 @@ namespace Greenshot.Base.Interfaces.Ocr /// /// Return the calculated bounds for the whole line /// - public Rectangle CalculatedBounds + public NativeRect CalculatedBounds { get { return _calculatedBounds ??= CalculateBounds(); } } @@ -69,9 +91,7 @@ namespace Greenshot.Base.Interfaces.Ocr { foreach (var word in Words) { - var location = word.Bounds; - location.Offset(x, y); - word.Bounds = location; + word.Bounds = word.Bounds.Offset(x, y); } _calculatedBounds = null; diff --git a/src/Greenshot.Base/Interfaces/Ocr/OcrInformation.cs b/src/Greenshot.Base/Interfaces/Ocr/OcrInformation.cs index d7cb82559..216265099 100644 --- a/src/Greenshot.Base/Interfaces/Ocr/OcrInformation.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/OcrInformation.cs @@ -1,4 +1,25 @@ -using System.Collections.Generic; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/Greenshot.Base/Interfaces/Ocr/Word.cs b/src/Greenshot.Base/Interfaces/Ocr/Word.cs index 467b5278b..0e6920f40 100644 --- a/src/Greenshot.Base/Interfaces/Ocr/Word.cs +++ b/src/Greenshot.Base/Interfaces/Ocr/Word.cs @@ -1,4 +1,25 @@ -using System.Drawing; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Dapplo.Windows.Common.Structs; namespace Greenshot.Base.Interfaces.Ocr { @@ -15,6 +36,6 @@ namespace Greenshot.Base.Interfaces.Ocr /// /// The bounds of the word /// - public Rectangle Bounds { get; set; } + public NativeRect Bounds { get; set; } } } \ No newline at end of file diff --git a/src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventArgs.cs index 5fd5694ba..61ac1a848 100644 --- a/src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventArgs.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceLineThicknessEventArgs.cs @@ -20,7 +20,6 @@ */ using System; -using System.Drawing; namespace Greenshot.Base.Interfaces { diff --git a/src/Greenshot.Base/Interfaces/SurfaceShadowEventArgs.cs b/src/Greenshot.Base/Interfaces/SurfaceShadowEventArgs.cs index a7bd682b7..5159d4d05 100644 --- a/src/Greenshot.Base/Interfaces/SurfaceShadowEventArgs.cs +++ b/src/Greenshot.Base/Interfaces/SurfaceShadowEventArgs.cs @@ -20,7 +20,6 @@ */ using System; -using System.Drawing; namespace Greenshot.Base.Interfaces { diff --git a/src/Greenshot.Base/UnmanagedHelpers/DWM.cs b/src/Greenshot.Base/UnmanagedHelpers/DWM.cs deleted file mode 100644 index 5a2b59d87..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/DWM.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using Greenshot.Base.Core; -using Greenshot.Base.Core.Enums; -using Greenshot.Base.UnmanagedHelpers.Enums; -using Greenshot.Base.UnmanagedHelpers.Structs; -using Microsoft.Win32; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// Desktop Window Manager helper code - /// - public static class DWM - { - // DWM - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb); - - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmUnregisterThumbnail(IntPtr thumb); - - [DllImport("dwmapi", SetLastError = true)] - public static extern HResult DwmQueryThumbnailSourceSize(IntPtr thumb, out SIZE size); - - [DllImport("dwmapi", SetLastError = true)] - public static extern HResult DwmUpdateThumbnailProperties(IntPtr hThumb, ref DWM_THUMBNAIL_PROPERTIES props); - - // Deprecated as of Windows 8 Release Preview - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmIsCompositionEnabled(out bool enabled); - - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT lpRect, int size); - - [DllImport("dwmapi", SetLastError = true)] - public static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool pvAttribute, int cbAttribute); - - // Key to ColorizationColor for DWM - private const string COLORIZATION_COLOR_KEY = @"SOFTWARE\Microsoft\Windows\DWM"; - - /// - /// Checks if the window is cloaked, this should solve some issues with the window selection code - /// - /// IntPtr as hWmd - /// bool - public static bool IsWindowCloaked(IntPtr hWnd) - { - if (!WindowsVersion.IsWindows8OrLater) - { - return false; - } - - DwmGetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_CLOAKED, out bool isCloaked, Marshal.SizeOf(typeof(bool))); - return isCloaked; - } - - /// - /// Helper method for an easy DWM check - /// - /// bool true if DWM is available AND active - public static bool IsDwmEnabled - { - get - { - // According to: https://technet.microsoft.com/en-us/subscriptions/aa969538%28v=vs.85%29.aspx - // And: https://docs.microsoft.com/en-gb/windows/win32/api/dwmapi/nf-dwmapi-dwmenablecomposition - // DMW is always enabled on Windows 8! So return true and save a check! ;-) - if (WindowsVersion.IsWindows8OrLater) - { - return true; - } - - if (WindowsVersion.IsWindowsVistaOrLater) - { - DwmIsCompositionEnabled(out var dwmEnabled); - return dwmEnabled; - } - - return false; - } - } - - public static Color ColorizationColor - { - get - { - using (RegistryKey key = Registry.CurrentUser.OpenSubKey(COLORIZATION_COLOR_KEY, false)) - { - object dwordValue = key?.GetValue("ColorizationColor"); - if (dwordValue != null) - { - return Color.FromArgb((int) dwordValue); - } - } - - return Color.White; - } - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs deleted file mode 100644 index 76676d157..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/ClassLongIndex.cs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ClassLongIndex - { - GCL_HICON = -14, // a handle to the icon associated with the class. - GCL_HICONSM = -34, // a handle to the small icon associated with the class. - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs deleted file mode 100644 index 5b6ee9900..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/DWMWINDOWATTRIBUTE.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DWMWINDOWATTRIBUTE : uint - { - DWMWA_NCRENDERING_ENABLED = 1, - DWMWA_NCRENDERING_POLICY, - DWMWA_TRANSITIONS_FORCEDISABLED, - DWMWA_ALLOW_NCPAINT, - DWMWA_CAPTION_BUTTON_BOUNDS, - DWMWA_NONCLIENT_RTL_LAYOUT, - DWMWA_FORCE_ICONIC_REPRESENTATION, - DWMWA_FLIP3D_POLICY, - DWMWA_EXTENDED_FRAME_BOUNDS, // This is the one we need for retrieving the Window size since Windows Vista - DWMWA_HAS_ICONIC_BITMAP, // Since Windows 7 - DWMWA_DISALLOW_PEEK, // Since Windows 7 - DWMWA_EXCLUDED_FROM_PEEK, // Since Windows 7 - DWMWA_CLOAK, // Since Windows 8 - DWMWA_CLOAKED, // Since Windows 8 - DWMWA_FREEZE_REPRESENTATION, // Since Windows 8 - DWMWA_LAST - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs deleted file mode 100644 index 615c2d7fa..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/DWM_THUMBNAIL_PROPERTIES.cs +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Runtime.InteropServices; -using Greenshot.Base.UnmanagedHelpers.Structs; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - /// - /// See DWM_THUMBNAIL_PROPERTIES - /// - [StructLayout(LayoutKind.Sequential)] - public struct DWM_THUMBNAIL_PROPERTIES - { - // A bitwise combination of DWM thumbnail constant values that indicates which members of this structure are set. - public int dwFlags; - - // The area in the destination window where the thumbnail will be rendered. - public RECT rcDestination; - - // The region of the source window to use as the thumbnail. By default, the entire window is used as the thumbnail. - public RECT rcSource; - - // The opacity with which to render the thumbnail. 0 is fully transparent while 255 is fully opaque. The default value is 255. - public byte opacity; - - // TRUE to make the thumbnail visible; otherwise, FALSE. The default is FALSE. - public bool fVisible; - - // TRUE to use only the thumbnail source's client area; otherwise, FALSE. The default is FALSE. - public bool fSourceClientAreaOnly; - - public RECT Destination - { - set - { - dwFlags |= DWM_TNP_RECTDESTINATION; - rcDestination = value; - } - } - - public RECT Source - { - set - { - dwFlags |= DWM_TNP_RECTSOURCE; - rcSource = value; - } - } - - public byte Opacity - { - set - { - dwFlags |= DWM_TNP_OPACITY; - opacity = value; - } - } - - public bool Visible - { - set - { - dwFlags |= DWM_TNP_VISIBLE; - fVisible = value; - } - } - - public bool SourceClientAreaOnly - { - set - { - dwFlags |= DWM_TNP_SOURCECLIENTAREAONLY; - fSourceClientAreaOnly = value; - } - } - - // A value for the rcDestination member has been specified. - public const int DWM_TNP_RECTDESTINATION = 0x00000001; - - // A value for the rcSource member has been specified. - public const int DWM_TNP_RECTSOURCE = 0x00000002; - - // A value for the opacity member has been specified. - public const int DWM_TNP_OPACITY = 0x00000004; - - // A value for the fVisible member has been specified. - public const int DWM_TNP_VISIBLE = 0x00000008; - - // A value for the fSourceClientAreaOnly member has been specified. - public const int DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010; - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/DesktopAccessRight.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DesktopAccessRight.cs deleted file mode 100644 index c99ddb149..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/DesktopAccessRight.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DesktopAccessRight : uint - { - DESKTOP_READOBJECTS = 0x00000001, - DESKTOP_CREATEWINDOW = 0x00000002, - DESKTOP_CREATEMENU = 0x00000004, - DESKTOP_HOOKCONTROL = 0x00000008, - DESKTOP_JOURNALRECORD = 0x00000010, - DESKTOP_JOURNALPLAYBACK = 0x00000020, - DESKTOP_ENUMERATE = 0x00000040, - DESKTOP_WRITEOBJECTS = 0x00000080, - DESKTOP_SWITCHDESKTOP = 0x00000100, - - GENERIC_ALL = (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | - DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | - DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP) - }; -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/DeviceCaps.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/DeviceCaps.cs deleted file mode 100644 index 2f2df7994..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/DeviceCaps.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - /// - /// Used by GDI32.GetDeviceCaps - /// See GetDeviceCaps - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum DeviceCaps - { - /// - /// Logical pixels inch in X - /// - LOGPIXELSX = 88, - - /// - /// Current vertical refresh rate of the display device (for displays only) in Hz - /// - VREFRESH = 116 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs deleted file mode 100644 index c9bf33cfc..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/EventObjects.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - /// - /// See Object Identifiers - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum EventObjects - { - OBJID_WINDOW = 0 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs deleted file mode 100644 index aaeb23fa9..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/ExtendedWindowStyleFlags.cs +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ExtendedWindowStyleFlags : uint - { - WS_EX_DLGMODALFRAME = 0x00000001, - WS_EX_NOPARENTNOTIFY = 0x00000004, - WS_EX_TOPMOST = 0x00000008, - WS_EX_ACCEPTFILES = 0x00000010, - WS_EX_TRANSPARENT = 0x00000020, - - //#if(WINVER >= 0x0400) - WS_EX_MDICHILD = 0x00000040, - WS_EX_TOOLWINDOW = 0x00000080, - WS_EX_WINDOWEDGE = 0x00000100, - WS_EX_CLIENTEDGE = 0x00000200, - WS_EX_CONTEXTHELP = 0x00000400, - - WS_EX_RIGHT = 0x00001000, - WS_EX_LEFT = 0x00000000, - WS_EX_RTLREADING = 0x00002000, - WS_EX_LTRREADING = 0x00000000, - WS_EX_LEFTSCROLLBAR = 0x00004000, - WS_EX_RIGHTSCROLLBAR = 0x00000000, - - WS_EX_CONTROLPARENT = 0x00010000, - WS_EX_STATICEDGE = 0x00020000, - WS_EX_APPWINDOW = 0x00040000, - - //WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE), - //WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST), - - WS_EX_LAYERED = 0x00080000, - WS_EX_NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children - WS_EX_NOREDIRECTIONBITMAP = 0x00200000, //The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual. - WS_EX_LAYOUTRTL = 0x00400000, // Right to left mirroring - /// - /// Paints all descendants of a window in bottom-to-top painting order using double-buffering. - /// Bottom-to-top painting order allows a descendent window to have translucency (alpha) and transparency (color-key) effects, but only if the descendent window also has the WS_EX_TRANSPARENT bit set. - /// Double-buffering allows the window and its descendents to be painted without flicker. - /// This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC. - /// - WS_EX_COMPOSITED = 0x02000000, - WS_EX_NOACTIVATE = 0x08000000 // A top-level window created with this style does not become the foreground window when the user clicks it. The system does not bring this window to the foreground when the user minimizes or closes the foreground window. - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/ProcessAccessFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ProcessAccessFlags.cs deleted file mode 100644 index c8795e33c..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/ProcessAccessFlags.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ProcessAccessFlags : uint - { - VMRead = 0x00000010, - QueryInformation = 0x00000400, - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs deleted file mode 100644 index f9c0e5a1f..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/RegionResult.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum RegionResult - { - REGION_ERROR = 0, - REGION_NULLREGION = 1, - SIMPLEREGION = 2, - COMPLEXREGION = 3 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs deleted file mode 100644 index 64e01979a..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/SendMessageTimeoutFlags.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - /// - /// See: https://www.pinvoke.net/default.aspx/Enums/SendMessageTimeoutFlags.html - /// - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SendMessageTimeoutFlags : uint - { - SMTO_NORMAL = 0x0 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs deleted file mode 100644 index 5faf95e03..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/ShowWindowCommand.cs +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum ShowWindowCommand : uint - { - /// - /// Hides the window and activates another window. - /// - Hide = 0, - - /// - /// Activates and displays a window. If the window is minimized or - /// maximized, the system restores it to its original size and position. - /// An application should specify this flag when displaying the window - /// for the first time. - /// - Normal = 1, - - /// - /// Activates the window and displays it as a minimized window. - /// - ShowMinimized = 2, - - /// - /// Maximizes the specified window. - /// - Maximize = 3, // is this the right value? - - /// - /// Activates the window and displays it as a maximized window. - /// - ShowMaximized = 3, - - /// - /// Displays a window in its most recent size and position. This value - /// is similar to , except - /// the window is not actived. - /// - ShowNoActivate = 4, - - /// - /// Activates the window and displays it in its current size and position. - /// - Show = 5, - - /// - /// Minimizes the specified window and activates the next top-level - /// window in the Z order. - /// - Minimize = 6, - - /// - /// Displays the window as a minimized window. This value is similar to - /// , except the - /// window is not activated. - /// - ShowMinNoActive = 7, - - /// - /// Displays the window in its current size and position. This value is - /// similar to , except the - /// window is not activated. - /// - ShowNA = 8, - - /// - /// Activates and displays the window. If the window is minimized or - /// maximized, the system restores it to its original size and position. - /// An application should specify this flag when restoring a minimized window. - /// - Restore = 9, - - /// - /// Sets the show state based on the SW_* value specified in the - /// STARTUPINFO structure passed to the CreateProcess function by the - /// program that started the application. - /// - ShowDefault = 10, - - /// - /// Windows 2000/XP: Minimizes a window, even if the thread - /// that owns the window is not responding. This flag should only be - /// used when minimizing windows from a different thread. - /// - ForceMinimize = 11 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs deleted file mode 100644 index 0ea597d08..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/SoundFlags.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - /// - /// See: https://msdn.microsoft.com/en-us/library/aa909766.aspx - /// - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum SoundFlags - { - SND_ASYNC = 0x0001, // play asynchronously - SND_MEMORY = 0x0004, // pszSound points to a memory file - SND_NOSTOP = 0x0010, // don't stop any currently playing sound - SND_NOWAIT = 0x00002000, // don't wait if the driver is busy - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/ThreadAccess.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/ThreadAccess.cs deleted file mode 100644 index 415e1f494..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/ThreadAccess.cs +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [Flags] - public enum ThreadAccess : int - { - SUSPEND_RESUME = (0x0002), - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs deleted file mode 100644 index 87259b3a9..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/Win32Error.cs +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - /// - /// A Win32 error code. - /// - public enum Win32Error : uint - { - Success = 0x0, - InvalidFunction = 0x1, - FileNotFound = 0x2, - PathNotFound = 0x3, - TooManyOpenFiles = 0x4, - AccessDenied = 0x5, - InvalidHandle = 0x6, - ArenaTrashed = 0x7, - NotEnoughMemory = 0x8, - InvalidBlock = 0x9, - BadEnvironment = 0xa, - BadFormat = 0xb, - InvalidAccess = 0xc, - InvalidData = 0xd, - OutOfMemory = 0xe, - InvalidDrive = 0xf, - CurrentDirectory = 0x10, - NotSameDevice = 0x11, - NoMoreFiles = 0x12, - WriteProtect = 0x13, - BadUnit = 0x14, - NotReady = 0x15, - BadCommand = 0x16, - Crc = 0x17, - BadLength = 0x18, - Seek = 0x19, - NotDosDisk = 0x1a, - SectorNotFound = 0x1b, - OutOfPaper = 0x1c, - WriteFault = 0x1d, - ReadFault = 0x1e, - GenFailure = 0x1f, - SharingViolation = 0x20, - LockViolation = 0x21, - WrongDisk = 0x22, - SharingBufferExceeded = 0x24, - HandleEof = 0x26, - HandleDiskFull = 0x27, - NotSupported = 0x32, - RemNotList = 0x33, - DupName = 0x34, - BadNetPath = 0x35, - NetworkBusy = 0x36, - DevNotExist = 0x37, - TooManyCmds = 0x38, - FileExists = 0x50, - CannotMake = 0x52, - AlreadyAssigned = 0x55, - InvalidPassword = 0x56, - InvalidParameter = 0x57, - NetWriteFault = 0x58, - NoProcSlots = 0x59, - TooManySemaphores = 0x64, - ExclSemAlreadyOwned = 0x65, - SemIsSet = 0x66, - TooManySemRequests = 0x67, - InvalidAtInterruptTime = 0x68, - SemOwnerDied = 0x69, - SemUserLimit = 0x6a - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs deleted file mode 100644 index 73b47c2aa..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEvent.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - /// - /// Used for User32.SetWinEventHook - /// See MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/dd318066%28v=vs.85%29.aspx - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WinEvent : uint - { - EVENT_OBJECT_CREATE = 32768, - EVENT_OBJECT_DESTROY = 32769, - EVENT_OBJECT_NAMECHANGE = 32780, - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEventHookFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEventHookFlags.cs deleted file mode 100644 index 809cb5248..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/WinEventHookFlags.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - /// - /// Used for User32.SetWinEventHook - /// See: https://msdn.microsoft.com/en-us/library/windows/desktop/dd373640%28v=vs.85%29.aspx - /// - [SuppressMessage("ReSharper", "InconsistentNaming"), Flags] - public enum WinEventHookFlags - { - WINEVENT_SKIPOWNTHREAD = 1, - WINEVENT_SKIPOWNPROCESS = 2, - WINEVENT_OUTOFCONTEXT = 0, - WINEVENT_INCONTEXT = 4 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs deleted file mode 100644 index 6af978b3e..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowLongIndex.cs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowLongIndex - { - GWL_EXSTYLE = -20, // Sets a new extended window style. - GWL_STYLE = -16, // Sets a new window style. - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPlacementFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPlacementFlags.cs deleted file mode 100644 index e59c9c6c1..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPlacementFlags.cs +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowPlacementFlags : uint - { - // The coordinates of the minimized window may be specified. - // This flag must be specified if the coordinates are set in the ptMinPosition member. - WPF_SETMINPOSITION = 0x0001, - - // If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. This prevents the calling thread from blocking its execution while other threads process the request. - WPF_ASYNCWINDOWPLACEMENT = 0x0004, - - // The restored window will be maximized, regardless of whether it was maximized before it was minimized. This setting is only valid the next time the window is restored. It does not change the default restoration behavior. - // This flag is only valid when the SW_SHOWMINIMIZED value is specified for the showCmd member. - WPF_RESTORETOMAXIMIZED = 0x0002 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs deleted file mode 100644 index 5d7a3caa2..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowPos.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowPos - { - SWP_NOACTIVATE = - 0x0010, // Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter parameter). - SWP_NOMOVE = 0x0002, //Retains the current position (ignores X and Y parameters). - SWP_NOSIZE = 0x0001, // Retains the current size (ignores the cx and cy parameters). - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs deleted file mode 100644 index 3efca68e0..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowStyleFlags.cs +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - /// - /// Window Style Flags - /// - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowStyleFlags : int - { - //WS_OVERLAPPED = 0x00000000, - WS_POPUP = -2147483648, // 0x80000000 - WS_CHILD = 0x40000000, - WS_MINIMIZE = 0x20000000, - WS_VISIBLE = 0x10000000, - WS_DISABLED = 0x08000000, - WS_CLIPSIBLINGS = 0x04000000, - WS_CLIPCHILDREN = 0x02000000, - WS_MAXIMIZE = 0x01000000, - WS_BORDER = 0x00800000, - WS_DLGFRAME = 0x00400000, - WS_VSCROLL = 0x00200000, - WS_HSCROLL = 0x00100000, - WS_SYSMENU = 0x00080000, - WS_THICKFRAME = 0x00040000, - WS_GROUP = 0x00020000, - WS_TABSTOP = 0x00010000 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs b/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs deleted file mode 100644 index 2aff5fe19..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Enums/WindowsMessages.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace Greenshot.Base.UnmanagedHelpers.Enums -{ - /// - /// All possible windows messages - /// See also here - /// - [SuppressMessage("ReSharper", "InconsistentNaming")] - public enum WindowsMessages : uint - { - WM_MOUSEACTIVATE = 0x0021, - WM_INPUTLANGCHANGEREQUEST = 0x0050, - WM_INPUTLANGCHANGE = 0x0051, - - - /// - /// Sent to a window to retrieve a handle to the large or small icon associated with a window. The system displays the large icon in the ALT+TAB dialog, and the small icon in the window caption. - /// A window receives this message through its WindowProc function. - /// WM_GETICON message - /// - WM_GETICON = 0x007F, - WM_CHAR = 0x0102, - WM_SYSCOMMAND = 0x0112 - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs b/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs deleted file mode 100644 index 3f483ff20..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/GDI32.cs +++ /dev/null @@ -1,596 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Security; -using Greenshot.Base.UnmanagedHelpers.Enums; -using Microsoft.Win32.SafeHandles; - -namespace Greenshot.Base.UnmanagedHelpers -{ - public static class GDIExtensions - { - /// - /// Check if all the corners of the rectangle are visible in the specified region. - /// Not a perfect check, but this currently a workaround for checking if a window is completely visible - /// - /// - /// - /// - public static bool AreRectangleCornersVisisble(this Region region, Rectangle rectangle) - { - Point topLeft = new Point(rectangle.X, rectangle.Y); - Point topRight = new Point(rectangle.X + rectangle.Width, rectangle.Y); - Point bottomLeft = new Point(rectangle.X, rectangle.Y + rectangle.Height); - Point bottomRight = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height); - bool topLeftVisible = region.IsVisible(topLeft); - bool topRightVisible = region.IsVisible(topRight); - bool bottomLeftVisible = region.IsVisible(bottomLeft); - bool bottomRightVisible = region.IsVisible(bottomRight); - - return topLeftVisible && topRightVisible && bottomLeftVisible && bottomRightVisible; - } - - /// - /// Get a SafeHandle for the GetHdc, so one can use using to automatically cleanup the devicecontext - /// - /// - /// SafeDeviceContextHandle - public static SafeDeviceContextHandle GetSafeDeviceContext(this Graphics graphics) - { - return SafeDeviceContextHandle.FromGraphics(graphics); - } - } - - /// - /// Abstract class SafeObjectHandle which contains all handles that are cleaned with DeleteObject - /// - public abstract class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid - { - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteObject(IntPtr hObject); - - protected SafeObjectHandle(bool ownsHandle) : base(ownsHandle) - { - } - - protected override bool ReleaseHandle() - { - return DeleteObject(handle); - } - } - - /// - /// A hbitmap SafeHandle implementation - /// - public class SafeHBitmapHandle : SafeObjectHandle - { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeHBitmapHandle() : base(true) - { - } - - [SecurityCritical] - public SafeHBitmapHandle(IntPtr preexistingHandle) : base(true) - { - SetHandle(preexistingHandle); - } - } - - /// - /// A hRegion SafeHandle implementation - /// - public class SafeRegionHandle : SafeObjectHandle - { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeRegionHandle() : base(true) - { - } - - [SecurityCritical] - public SafeRegionHandle(IntPtr preexistingHandle) : base(true) - { - SetHandle(preexistingHandle); - } - } - - /// - /// A dibsection SafeHandle implementation - /// - public class SafeDibSectionHandle : SafeObjectHandle - { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeDibSectionHandle() : base(true) - { - } - - [SecurityCritical] - public SafeDibSectionHandle(IntPtr preexistingHandle) : base(true) - { - SetHandle(preexistingHandle); - } - } - - /// - /// A select object safehandle implementation - /// This impl will select the passed SafeHandle to the HDC and replace the returned value when disposing - /// - public class SafeSelectObjectHandle : SafeHandleZeroOrMinusOneIsInvalid - { - [DllImport("gdi32", SetLastError = true)] - private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); - - private readonly SafeHandle _hdc; - - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeSelectObjectHandle() : base(true) - { - } - - [SecurityCritical] - public SafeSelectObjectHandle(SafeDCHandle hdc, SafeHandle newHandle) : base(true) - { - _hdc = hdc; - SetHandle(SelectObject(hdc.DangerousGetHandle(), newHandle.DangerousGetHandle())); - } - - protected override bool ReleaseHandle() - { - SelectObject(_hdc.DangerousGetHandle(), handle); - return true; - } - } - - public abstract class SafeDCHandle : SafeHandleZeroOrMinusOneIsInvalid - { - protected SafeDCHandle(bool ownsHandle) : base(ownsHandle) - { - } - } - - /// - /// A CompatibleDC SafeHandle implementation - /// - public class SafeCompatibleDCHandle : SafeDCHandle - { - [DllImport("gdi32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DeleteDC(IntPtr hDC); - - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeCompatibleDCHandle() : base(true) - { - } - - [SecurityCritical] - public SafeCompatibleDCHandle(IntPtr preexistingHandle) : base(true) - { - SetHandle(preexistingHandle); - } - - public SafeSelectObjectHandle SelectObject(SafeHandle newHandle) - { - return new SafeSelectObjectHandle(this, newHandle); - } - - protected override bool ReleaseHandle() - { - return DeleteDC(handle); - } - } - - /// - /// A DeviceContext SafeHandle implementation - /// - public class SafeDeviceContextHandle : SafeDCHandle - { - private readonly Graphics _graphics; - - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeDeviceContextHandle() : base(true) - { - } - - [SecurityCritical] - public SafeDeviceContextHandle(Graphics graphics, IntPtr preexistingHandle) : base(true) - { - _graphics = graphics; - SetHandle(preexistingHandle); - } - - protected override bool ReleaseHandle() - { - _graphics.ReleaseHdc(handle); - return true; - } - - public static SafeDeviceContextHandle FromGraphics(Graphics graphics) - { - return new SafeDeviceContextHandle(graphics, graphics.GetHdc()); - } - } - - /// - /// GDI32 Helpers - /// - public static class GDI32 - { - [DllImport("gdi32", SetLastError = true)] - public static extern bool BitBlt(SafeHandle hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, SafeHandle hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop); - - [DllImport("gdi32", SetLastError = true)] - public static extern SafeCompatibleDCHandle CreateCompatibleDC(SafeHandle hDC); - - [DllImport("gdi32", SetLastError = true)] - public static extern SafeDibSectionHandle CreateDIBSection(SafeHandle hdc, ref BITMAPINFOHEADERV5 bmi, uint usage, out IntPtr bits, IntPtr hSection, uint dwOffset); - - [DllImport("gdi32", SetLastError = true)] - public static extern SafeRegionHandle CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); - - [DllImport("gdi32", SetLastError = true)] - public static extern uint GetPixel(SafeHandle hdc, int nXPos, int nYPos); - - [DllImport("gdi32", SetLastError = true)] - public static extern int GetDeviceCaps(SafeHandle hdc, DeviceCaps nIndex); - } - - [StructLayout(LayoutKind.Sequential, Pack = 2)] - public struct BITMAPFILEHEADER - { - public static readonly short BM = 0x4d42; // BM - public short bfType; - public int bfSize; - public short bfReserved1; - public short bfReserved2; - public int bfOffBits; - } - - [StructLayout(LayoutKind.Sequential)] - public struct BitfieldColorMask - { - public uint blue; - public uint green; - public uint red; - - public void InitValues() - { - red = (uint) 255 << 8; - green = (uint) 255 << 16; - blue = (uint) 255 << 24; - } - } - - [StructLayout(LayoutKind.Sequential)] - public struct CIEXYZ - { - public uint ciexyzX; //FXPT2DOT30 - public uint ciexyzY; //FXPT2DOT30 - public uint ciexyzZ; //FXPT2DOT30 - - public CIEXYZ(uint FXPT2DOT30) - { - ciexyzX = FXPT2DOT30; - ciexyzY = FXPT2DOT30; - ciexyzZ = FXPT2DOT30; - } - } - - [StructLayout(LayoutKind.Sequential)] - public struct RGBQUAD - { - public byte rgbBlue; - public byte rgbGreen; - public byte rgbRed; - public byte rgbReserved; - } - - [StructLayout(LayoutKind.Sequential)] - public struct CIEXYZTRIPLE - { - public CIEXYZ ciexyzRed; - public CIEXYZ ciexyzGreen; - public CIEXYZ ciexyzBlue; - } - - public enum BI_COMPRESSION : uint - { - BI_RGB = 0, // Uncompressed - BI_RLE8 = 1, // RLE 8BPP - BI_RLE4 = 2, // RLE 4BPP - - BI_BITFIELDS = - 3, // Specifies that the bitmap is not compressed and that the color table consists of three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bpp bitmaps. - BI_JPEG = 4, // Indicates that the image is a JPEG image. - BI_PNG = 5 // Indicates that the image is a PNG image. - } - - [StructLayout(LayoutKind.Explicit)] - public struct BITMAPINFOHEADER - { - [FieldOffset(0)] public uint biSize; - [FieldOffset(4)] public int biWidth; - [FieldOffset(8)] public int biHeight; - [FieldOffset(12)] public ushort biPlanes; - [FieldOffset(14)] public ushort biBitCount; - [FieldOffset(16)] public BI_COMPRESSION biCompression; - [FieldOffset(20)] public uint biSizeImage; - [FieldOffset(24)] public int biXPelsPerMeter; - [FieldOffset(28)] public int biYPelsPerMeter; - [FieldOffset(32)] public uint biClrUsed; - [FieldOffset(36)] public uint biClrImportant; - - public const int DIB_RGB_COLORS = 0; - - public BITMAPINFOHEADER(int width, int height, ushort bpp) - { - biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); // BITMAPINFOHEADER < DIBV4 is 40 bytes - biPlanes = 1; // Should allways be 1 - biCompression = BI_COMPRESSION.BI_RGB; - biWidth = width; - biHeight = height; - biBitCount = bpp; - biSizeImage = (uint)(width * height * (bpp >> 3)); - biXPelsPerMeter = 0; - biYPelsPerMeter = 0; - biClrUsed = 0; - biClrImportant = 0; - } - - public bool IsDibV4 - { - get - { - uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4)); - return biSize >= sizeOfBMI; - } - } - public bool IsDibV5 - { - get - { - uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV5)); - return biSize >= sizeOfBMI; - } - } - - public uint OffsetToPixels - { - get - { - if (biCompression == BI_COMPRESSION.BI_BITFIELDS) - { - // Add 3x4 bytes for the bitfield color mask - return biSize + 3 * 4; - } - - return biSize; - } - } - } - - [StructLayout(LayoutKind.Explicit)] - public struct BITMAPINFOHEADERV4 - { - [FieldOffset(0)] public uint biSize; - [FieldOffset(4)] public int biWidth; - [FieldOffset(8)] public int biHeight; - [FieldOffset(12)] public ushort biPlanes; - [FieldOffset(14)] public ushort biBitCount; - [FieldOffset(16)] public BI_COMPRESSION biCompression; - [FieldOffset(20)] public uint biSizeImage; - [FieldOffset(24)] public int biXPelsPerMeter; - [FieldOffset(28)] public int biYPelsPerMeter; - [FieldOffset(32)] public uint biClrUsed; - [FieldOffset(36)] public uint biClrImportant; - [FieldOffset(40)] public uint bV4RedMask; - [FieldOffset(44)] public uint bV4GreenMask; - [FieldOffset(48)] public uint bV4BlueMask; - [FieldOffset(52)] public uint bV4AlphaMask; - [FieldOffset(56)] public uint bV4CSType; - [FieldOffset(60)] public CIEXYZTRIPLE bV4Endpoints; - [FieldOffset(96)] public uint bV4GammaRed; - [FieldOffset(100)] public uint bV4GammaGreen; - [FieldOffset(104)] public uint bV4GammaBlue; - - public const int DIB_RGB_COLORS = 0; - - public BITMAPINFOHEADERV4(int width, int height, ushort bpp) - { - biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4)); // BITMAPINFOHEADER < DIBV5 is 40 bytes - biPlanes = 1; // Should allways be 1 - biCompression = BI_COMPRESSION.BI_RGB; - biWidth = width; - biHeight = height; - biBitCount = bpp; - biSizeImage = (uint)(width * height * (bpp >> 3)); - biXPelsPerMeter = 0; - biYPelsPerMeter = 0; - biClrUsed = 0; - biClrImportant = 0; - - // V4 - bV4RedMask = (uint)255 << 16; - bV4GreenMask = (uint)255 << 8; - bV4BlueMask = 255; - bV4AlphaMask = (uint)255 << 24; - bV4CSType = 0x73524742; // LCS_sRGB - bV4Endpoints = new CIEXYZTRIPLE - { - ciexyzBlue = new CIEXYZ(0), - ciexyzGreen = new CIEXYZ(0), - ciexyzRed = new CIEXYZ(0) - }; - bV4GammaRed = 0; - bV4GammaGreen = 0; - bV4GammaBlue = 0; - } - - public bool IsDibV4 - { - get - { - uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4)); - return biSize >= sizeOfBMI; - } - } - public bool IsDibV5 - { - get - { - uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV5)); - return biSize >= sizeOfBMI; - } - } - - public uint OffsetToPixels - { - get - { - if (biCompression == BI_COMPRESSION.BI_BITFIELDS) - { - // Add 3x4 bytes for the bitfield color mask - return biSize + 3 * 4; - } - - return biSize; - } - } - } - - [StructLayout(LayoutKind.Explicit)] - public struct BITMAPINFOHEADERV5 - { - [FieldOffset(0)] public uint biSize; - [FieldOffset(4)] public int biWidth; - [FieldOffset(8)] public int biHeight; - [FieldOffset(12)] public ushort biPlanes; - [FieldOffset(14)] public ushort biBitCount; - [FieldOffset(16)] public BI_COMPRESSION biCompression; - [FieldOffset(20)] public uint biSizeImage; - [FieldOffset(24)] public int biXPelsPerMeter; - [FieldOffset(28)] public int biYPelsPerMeter; - [FieldOffset(32)] public uint biClrUsed; - [FieldOffset(36)] public uint biClrImportant; - [FieldOffset(40)] public uint bV4RedMask; - [FieldOffset(44)] public uint bV4GreenMask; - [FieldOffset(48)] public uint bV4BlueMask; - [FieldOffset(52)] public uint bV4AlphaMask; - [FieldOffset(56)] public uint bV4CSType; - [FieldOffset(60)] public CIEXYZTRIPLE bV4Endpoints; - [FieldOffset(96)] public uint bV4GammaRed; - [FieldOffset(100)] public uint bV4GammaGreen; - [FieldOffset(104)] public uint bV4GammaBlue; - [FieldOffset(108)] public uint bV5Intent; // Rendering intent for bitmap - [FieldOffset(112)] public uint bV5ProfileData; - [FieldOffset(116)] public uint bV5ProfileSize; - [FieldOffset(120)] public uint bV5Reserved; - - public const int DIB_RGB_COLORS = 0; - - public BITMAPINFOHEADERV5(int width, int height, ushort bpp) - { - biSize = (uint) Marshal.SizeOf(typeof(BITMAPINFOHEADERV5)); // BITMAPINFOHEADER < DIBV5 is 40 bytes - biPlanes = 1; // Should allways be 1 - biCompression = BI_COMPRESSION.BI_RGB; - biWidth = width; - biHeight = height; - biBitCount = bpp; - biSizeImage = (uint) (width * height * (bpp >> 3)); - biXPelsPerMeter = 0; - biYPelsPerMeter = 0; - biClrUsed = 0; - biClrImportant = 0; - - // V4 - bV4RedMask = (uint) 255 << 16; - bV4GreenMask = (uint) 255 << 8; - bV4BlueMask = 255; - bV4AlphaMask = (uint) 255 << 24; - bV4CSType = 0x73524742; // LCS_sRGB - bV4Endpoints = new CIEXYZTRIPLE - { - ciexyzBlue = new CIEXYZ(0), - ciexyzGreen = new CIEXYZ(0), - ciexyzRed = new CIEXYZ(0) - }; - bV4GammaRed = 0; - bV4GammaGreen = 0; - bV4GammaBlue = 0; - // V5 - bV5Intent = 4; - bV5ProfileData = 0; - bV5ProfileSize = 0; - bV5Reserved = 0; - } - - public bool IsDibV4 - { - get - { - uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV4)); - return biSize >= sizeOfBMI; - } - } - public bool IsDibV5 - { - get - { - uint sizeOfBMI = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADERV5)); - return biSize >= sizeOfBMI; - } - } - - public uint OffsetToPixels - { - get - { - if (biCompression == BI_COMPRESSION.BI_BITFIELDS) - { - // Add 3x4 bytes for the bitfield color mask - return biSize + 3 * 4; - } - - return biSize; - } - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs b/src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs deleted file mode 100644 index 6bf30fdcc..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/GDIplus.cs +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.Reflection; -using System.Runtime.InteropServices; -using Greenshot.Base.UnmanagedHelpers.Structs; -using log4net; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// Contains members that specify the nature of a Gaussian blur. - /// - /// Cannot be pinned with GCHandle due to bool value. - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct BlurParams - { - /// - /// Real number that specifies the blur radius (the radius of the Gaussian convolution kernel) in - /// pixels. The radius must be in the range 0 through 255. As the radius increases, the resulting - /// bitmap becomes more blurry. - /// - public float Radius; - - /// - /// Boolean value that specifies whether the bitmap expands by an amount equal to the blur radius. - /// If TRUE, the bitmap expands by an amount equal to the radius so that it can have soft edges. - /// If FALSE, the bitmap remains the same size and the soft edges are clipped. - /// - public bool ExpandEdges; - } - - /// - /// GDI Plus unit description. - /// - public enum GpUnit - { - /// - /// World coordinate (non-physical unit). - /// - UnitWorld, - - /// - /// Variable - for PageTransform only. - /// - UnitDisplay, - - /// - /// Each unit is one device pixel. - /// - UnitPixel, - - /// - /// Each unit is a printer's point, or 1/72 inch. - /// - UnitPoint, - - /// - /// Each unit is 1 inch. - /// - UnitInch, - - /// - /// Each unit is 1/300 inch. - /// - UnitDocument, - - /// - /// Each unit is 1 millimeter. - /// - UnitMillimeter - } - - /// - /// GDIplus Helpers - /// - public static class GDIplus - { - private static readonly ILog Log = LogManager.GetLogger(typeof(GDIplus)); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipBitmapApplyEffect(IntPtr bitmap, IntPtr effect, ref RECT rectOfInterest, bool useAuxData, IntPtr auxData, int auxDataSize); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipDrawImageFX(IntPtr graphics, IntPtr bitmap, ref RECTF source, IntPtr matrix, IntPtr effect, IntPtr imageAttributes, GpUnit srcUnit); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipSetEffectParameters(IntPtr effect, IntPtr parameters, uint size); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipCreateEffect(Guid guid, out IntPtr effect); - - [DllImport("gdiplus.dll", SetLastError = true, ExactSpelling = true)] - private static extern int GdipDeleteEffect(IntPtr effect); - - private static readonly Guid BlurEffectGuid = new Guid("{633C80A4-1843-482B-9EF2-BE2834C5FDD4}"); - - // Constant "FieldInfo" for getting the nativeImage from the Bitmap - private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGE = typeof(Bitmap).GetField("nativeImage", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - - // Constant "FieldInfo" for getting the NativeGraphics from the Graphics - private static readonly FieldInfo FIELD_INFO_NATIVE_GRAPHICS = - typeof(Graphics).GetField("nativeGraphics", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - - // Constant "FieldInfo" for getting the nativeMatrix from the Matrix - private static readonly FieldInfo FIELD_INFO_NATIVE_MATRIX = - typeof(Matrix).GetField("nativeMatrix", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - - // Constant "FieldInfo" for getting the nativeImageAttributes from the ImageAttributes - private static readonly FieldInfo FIELD_INFO_NATIVE_IMAGEATTRIBUTES = - typeof(ImageAttributes).GetField("nativeImageAttributes", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic); - - private static bool _isBlurEnabled = Environment.OSVersion.Version.Major >= 6; - - /// - /// Get the nativeImage field from the bitmap - /// - /// - /// IntPtr - private static IntPtr GetNativeImage(Bitmap bitmap) - { - if (bitmap == null) - { - return IntPtr.Zero; - } - - return (IntPtr) FIELD_INFO_NATIVE_IMAGE.GetValue(bitmap); - } - - /// - /// Get the NativeGraphics field from the graphics - /// - /// - /// IntPtr - private static IntPtr GetNativeGraphics(Graphics graphics) - { - if (graphics == null) - { - return IntPtr.Zero; - } - - return (IntPtr) FIELD_INFO_NATIVE_GRAPHICS.GetValue(graphics); - } - - /// - /// Get the nativeMatrix field from the matrix - /// - /// - /// IntPtr - private static IntPtr GetNativeMatrix(Matrix matrix) - { - if (matrix == null) - { - return IntPtr.Zero; - } - - return (IntPtr) FIELD_INFO_NATIVE_MATRIX.GetValue(matrix); - } - - /// - /// Get the nativeImageAttributes field from the ImageAttributes - /// - /// - /// IntPtr - private static IntPtr GetNativeImageAttributes(ImageAttributes imageAttributes) - { - if (imageAttributes == null) - { - return IntPtr.Zero; - } - - return (IntPtr) FIELD_INFO_NATIVE_IMAGEATTRIBUTES.GetValue(imageAttributes); - } - - /// - /// Returns if a GDIPlus blur can be made for the supplied radius. - /// This accounts for the "bug" I reported here: https://social.technet.microsoft.com/Forums/en/w8itprogeneral/thread/99ddbe9d-556d-475a-8bab-84e25aa13a2c - /// - /// - /// false if blur is not possible - public static bool IsBlurPossible(int radius) - { - if (!_isBlurEnabled) - { - return false; - } - - if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2) - { - return true; - } - - return Environment.OSVersion.Version.Major > 6 && radius >= 20; - } - - /// - /// Use the GDI+ blur effect on the bitmap - /// - /// Bitmap to apply the effect to - /// Rectangle to apply the blur effect to - /// 0-255 - /// bool true if the edges are expanded with the radius - /// false if there is no GDI+ available or an exception occurred - public static bool ApplyBlur(Bitmap destinationBitmap, Rectangle area, int radius, bool expandEdges) - { - if (!IsBlurPossible(radius)) - { - return false; - } - - IntPtr hBlurParams = IntPtr.Zero; - IntPtr hEffect = IntPtr.Zero; - - try - { - // Create the GDI+ BlurEffect, using the Guid - int status = GdipCreateEffect(BlurEffectGuid, out hEffect); - if (status != 0) - { - return false; - } - - // Create a BlurParams struct and set the values - var blurParams = new BlurParams - { - Radius = radius, - ExpandEdges = expandEdges - }; - - // Allocate space in unmanaged memory - hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); - // Copy the structure to the unmanaged memory - Marshal.StructureToPtr(blurParams, hBlurParams, false); - - - // Set the blurParams to the effect - GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams)); - - // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! - // Get the private nativeImage property from the Bitmap - IntPtr hBitmap = GetNativeImage(destinationBitmap); - - // Create a RECT from the Rectangle - RECT rec = new RECT(area); - // Apply the effect to the bitmap in the specified area - GdipBitmapApplyEffect(hBitmap, hEffect, ref rec, false, IntPtr.Zero, 0); - - // Everything worked, return true - return true; - } - catch (Exception ex) - { - _isBlurEnabled = false; - Log.Error("Problem using GdipBitmapApplyEffect: ", ex); - return false; - } - finally - { - try - { - if (hEffect != IntPtr.Zero) - { - // Delete the effect - GdipDeleteEffect(hEffect); - } - - if (hBlurParams != IntPtr.Zero) - { - // Free the memory - Marshal.FreeHGlobal(hBlurParams); - } - } - catch (Exception ex) - { - _isBlurEnabled = false; - Log.Error("Problem cleaning up ApplyBlur: ", ex); - } - } - } - - /// - /// Draw the image on the graphics with GDI+ blur effect - /// - /// false if there is no GDI+ available or an exception occurred - public static bool DrawWithBlur(Graphics graphics, Bitmap image, Rectangle source, Matrix transform, ImageAttributes imageAttributes, int radius, bool expandEdges) - { - if (!IsBlurPossible(radius)) - { - return false; - } - - IntPtr hBlurParams = IntPtr.Zero; - IntPtr hEffect = IntPtr.Zero; - - try - { - // Create the GDI+ BlurEffect, using the Guid - int status = GdipCreateEffect(BlurEffectGuid, out hEffect); - if (status != 0) - { - return false; - } - - // Create a BlurParams struct and set the values - var blurParams = new BlurParams - { - Radius = radius, - ExpandEdges = false - }; - //blurParams.Padding = radius; - - // Allocate space in unmanaged memory - hBlurParams = Marshal.AllocHGlobal(Marshal.SizeOf(blurParams)); - // Copy the structure to the unmanaged memory - Marshal.StructureToPtr(blurParams, hBlurParams, true); - - // Set the blurParams to the effect - GdipSetEffectParameters(hEffect, hBlurParams, (uint) Marshal.SizeOf(blurParams)); - - // Somewhere it said we can use destinationBitmap.GetHbitmap(), this doesn't work!! - // Get the private nativeImage property from the Bitmap - IntPtr hBitmap = GetNativeImage(image); - IntPtr hGraphics = GetNativeGraphics(graphics); - IntPtr hMatrix = GetNativeMatrix(transform); - IntPtr hAttributes = GetNativeImageAttributes(imageAttributes); - - // Create a RECT from the Rectangle - RECTF sourceRecf = new RECTF(source); - // Apply the effect to the bitmap in the specified area - GdipDrawImageFX(hGraphics, hBitmap, ref sourceRecf, hMatrix, hEffect, hAttributes, GpUnit.UnitPixel); - - // Everything worked, return true - return true; - } - catch (Exception ex) - { - _isBlurEnabled = false; - Log.Error("Problem using GdipDrawImageFX: ", ex); - return false; - } - finally - { - try - { - if (hEffect != IntPtr.Zero) - { - // Delete the effect - GdipDeleteEffect(hEffect); - } - - if (hBlurParams != IntPtr.Zero) - { - // Free the memory - Marshal.FreeHGlobal(hBlurParams); - } - } - catch (Exception ex) - { - _isBlurEnabled = false; - Log.Error("Problem cleaning up DrawWithBlur: ", ex); - } - } - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs b/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs deleted file mode 100644 index 310864c75..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Kernel32.cs +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Greenshot.Base.UnmanagedHelpers.Enums; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// Description of Kernel32. - /// - public class Kernel32 - { - public const uint ATTACHCONSOLE_ATTACHPARENTPROCESS = 0x0ffffffff; // default value if not specifing a process ID - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool AttachConsole(uint dwProcessId); - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool AllocConsole(); - - [DllImport("kernel32", SetLastError = true)] - public static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); - - [DllImport("kernel32", SetLastError = true)] - public static extern uint SuspendThread(IntPtr hThread); - - [DllImport("kernel32", SetLastError = true)] - public static extern int ResumeThread(IntPtr hThread); - - [DllImport("kernel32", SetLastError = true)] - public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId); - - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize); - - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, uint uuchMax); - - [DllImport("kernel32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CloseHandle(IntPtr hObject); - - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)] - public static extern int GetPackageFullName(IntPtr hProcess, ref Int32 packageFullNameLength, StringBuilder fullName); - - - /// - /// Method to get the process path - /// - /// - /// - public static string GetProcessPath(int processid) - { - StringBuilder _PathBuffer = new StringBuilder(512); - // Try the GetModuleFileName method first since it's the fastest. - // May return ACCESS_DENIED (due to VM_READ flag) if the process is not owned by the current user. - // Will fail if we are compiled as x86 and we're trying to open a 64 bit process...not allowed. - IntPtr hprocess = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VMRead, false, processid); - if (hprocess != IntPtr.Zero) - { - try - { - if (PsAPI.GetModuleFileNameEx(hprocess, IntPtr.Zero, _PathBuffer, (uint) _PathBuffer.Capacity) > 0) - { - return _PathBuffer.ToString(); - } - } - finally - { - CloseHandle(hprocess); - } - } - - hprocess = OpenProcess(ProcessAccessFlags.QueryInformation, false, processid); - if (hprocess != IntPtr.Zero) - { - try - { - // Try this method for Vista or higher operating systems - uint size = (uint) _PathBuffer.Capacity; - if ((Environment.OSVersion.Version.Major >= 6) && (QueryFullProcessImageName(hprocess, 0, _PathBuffer, ref size) && (size > 0))) - { - return _PathBuffer.ToString(); - } - - // Try the GetProcessImageFileName method - if (PsAPI.GetProcessImageFileName(hprocess, _PathBuffer, (uint) _PathBuffer.Capacity) > 0) - { - string dospath = _PathBuffer.ToString(); - foreach (string drive in Environment.GetLogicalDrives()) - { - if (QueryDosDevice(drive.TrimEnd('\\'), _PathBuffer, (uint) _PathBuffer.Capacity) > 0) - { - if (dospath.StartsWith(_PathBuffer.ToString())) - { - return drive + dospath.Remove(0, _PathBuffer.Length); - } - } - } - } - } - finally - { - CloseHandle(hprocess); - } - } - - return string.Empty; - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs b/src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs deleted file mode 100644 index 9ae782b86..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/PsAPI.cs +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; -using log4net; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// Description of PsAPI. - /// - public class PsAPI - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(PsAPI)); - - [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, StringBuilder lpFilename, uint nSize); - - [DllImport("psapi", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint GetProcessImageFileName(IntPtr hProcess, StringBuilder lpImageFileName, uint nSize); - - [DllImport("psapi")] - private static extern int EmptyWorkingSet(IntPtr hwProc); - - /// - /// Make the process use less memory by emptying the working set - /// - public static void EmptyWorkingSet() - { - LOG.Info("Calling EmptyWorkingSet"); - using Process currentProcess = Process.GetCurrentProcess(); - EmptyWorkingSet(currentProcess.Handle); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs b/src/Greenshot.Base/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs deleted file mode 100644 index 113117eae..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/SafeCurrentInputDesktopHandle.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Security.Permissions; -using Greenshot.Base.UnmanagedHelpers.Enums; -using log4net; -using Microsoft.Win32.SafeHandles; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// A SafeHandle class implementation for the current input desktop - /// - public class SafeCurrentInputDesktopHandle : SafeHandleZeroOrMinusOneIsInvalid - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(SafeCurrentInputDesktopHandle)); - - public SafeCurrentInputDesktopHandle() : base(true) - { - IntPtr hDesktop = User32.OpenInputDesktop(0, true, DesktopAccessRight.GENERIC_ALL); - if (hDesktop != IntPtr.Zero) - { - SetHandle(hDesktop); - if (User32.SetThreadDesktop(hDesktop)) - { - LOG.DebugFormat("Switched to desktop {0}", hDesktop); - } - else - { - LOG.WarnFormat("Couldn't switch to desktop {0}", hDesktop); - LOG.Error(User32.CreateWin32Exception("SetThreadDesktop")); - } - } - else - { - LOG.Warn("Couldn't get current desktop."); - LOG.Error(User32.CreateWin32Exception("OpenInputDesktop")); - } - } - - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - protected override bool ReleaseHandle() - { - return User32.CloseDesktop(handle); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs b/src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs deleted file mode 100644 index acb280287..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/SafeIconHandle.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Security; -using System.Security.Permissions; -using Microsoft.Win32.SafeHandles; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// A SafeHandle class implementation for the hIcon - /// - public class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid - { - /// - /// Needed for marshalling return values - /// - [SecurityCritical] - public SafeIconHandle() : base(true) - { - } - - - public SafeIconHandle(IntPtr hIcon) : base(true) - { - SetHandle(hIcon); - } - - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - protected override bool ReleaseHandle() - { - return User32.DestroyIcon(handle); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs b/src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs deleted file mode 100644 index 7ccdbf684..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/SafeWindowDcHandle.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Security; -using System.Security.Permissions; -using Microsoft.Win32.SafeHandles; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// A WindowDC SafeHandle implementation - /// - public class SafeWindowDcHandle : SafeHandleZeroOrMinusOneIsInvalid - { - [DllImport("user32", SetLastError = true)] - private static extern IntPtr GetWindowDC(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - private static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); - - private readonly IntPtr _hWnd; - - /// - /// Needed for marshalling return values - /// - public SafeWindowDcHandle() : base(true) - { - } - - [SecurityCritical] - public SafeWindowDcHandle(IntPtr hWnd, IntPtr preexistingHandle) : base(true) - { - _hWnd = hWnd; - SetHandle(preexistingHandle); - } - - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - protected override bool ReleaseHandle() - { - bool returnValue = ReleaseDC(_hWnd, handle); - return returnValue; - } - - /// - /// Creates a DC as SafeWindowDcHandle for the whole of the specified hWnd - /// - /// IntPtr - /// SafeWindowDcHandle - public static SafeWindowDcHandle FromWindow(IntPtr hWnd) - { - if (hWnd == IntPtr.Zero) - { - return null; - } - - var hDcDesktop = GetWindowDC(hWnd); - return new SafeWindowDcHandle(hWnd, hDcDesktop); - } - - public static SafeWindowDcHandle FromDesktop() - { - IntPtr hWndDesktop = User32.GetDesktopWindow(); - IntPtr hDCDesktop = GetWindowDC(hWndDesktop); - return new SafeWindowDcHandle(hWndDesktop, hDCDesktop); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Shell32.cs b/src/Greenshot.Base/UnmanagedHelpers/Shell32.cs deleted file mode 100644 index 528cf89eb..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Shell32.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.IO; -using System.Runtime.InteropServices; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// Description of Shell32. - /// - public static class Shell32 - { - [DllImport("shell32", CharSet = CharSet.Unicode)] - public static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons); - - [DllImport("shell32", CharSet = CharSet.Unicode)] - private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - private struct SHFILEINFO - { - public readonly IntPtr hIcon; - public readonly int iIcon; - public readonly uint dwAttributes; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public readonly string szDisplayName; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] - public readonly string szTypeName; - }; - - // Browsing for directory. - - private const uint SHGFI_ICON = 0x000000100; // get icon - private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon - private const uint SHGFI_LARGEICON = 0x000000000; // get large icon - private const uint SHGFI_SMALLICON = 0x000000001; // get small icon - private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute - private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; - - /// - /// Options to specify the size of icons to return. - /// - public enum IconSize - { - /// - /// Specify large icon - 32 pixels by 32 pixels. - /// - Large = 0, - - /// - /// Specify small icon - 16 pixels by 16 pixels. - /// - Small = 1 - } - - /// - /// Returns an icon for a given file extension - indicated by the name parameter. - /// See: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx - /// - /// Filename - /// Large or small - /// Whether to include the link icon - /// System.Drawing.Icon - public static Icon GetFileIcon(string filename, IconSize size, bool linkOverlay) - { - SHFILEINFO shfi = new SHFILEINFO(); - // SHGFI_USEFILEATTRIBUTES makes it simulate, just gets the icon for the extension - uint flags = SHGFI_ICON | SHGFI_USEFILEATTRIBUTES; - - if (linkOverlay) - { - flags += SHGFI_LINKOVERLAY; - } - - // Check the size specified for return. - if (IconSize.Small == size) - { - flags += SHGFI_SMALLICON; - } - else - { - flags += SHGFI_LARGEICON; - } - - SHGetFileInfo(Path.GetFileName(filename), FILE_ATTRIBUTE_NORMAL, ref shfi, (uint) Marshal.SizeOf(shfi), flags); - - // Only return an icon if we really got one - if (shfi.hIcon != IntPtr.Zero) - { - // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly - Icon icon = (Icon) Icon.FromHandle(shfi.hIcon).Clone(); - // Cleanup - User32.DestroyIcon(shfi.hIcon); - return icon; - } - - return null; - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Structs/CursorInfo.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/CursorInfo.cs deleted file mode 100644 index 219a634f6..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Structs/CursorInfo.cs +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace Greenshot.Base.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential)] - public struct CursorInfo - { - public int cbSize; - public int flags; - public IntPtr hCursor; - public POINT ptScreenPos; - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs deleted file mode 100644 index 470862304..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Structs/IconInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace Greenshot.Base.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential)] - public struct IconInfo - { - public bool fIcon; - public int xHotspot; - public int yHotspot; - public IntPtr hbmMask; - public IntPtr hbmColor; - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Structs/POINT.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/POINT.cs deleted file mode 100644 index fe65a6b8d..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Structs/POINT.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace Greenshot.Base.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct POINT - { - public int X; - public int Y; - - public POINT(int x, int y) - { - X = x; - Y = y; - } - - public POINT(Point point) - { - X = point.X; - Y = point.Y; - } - - public static implicit operator Point(POINT p) - { - return new Point(p.X, p.Y); - } - - public static implicit operator POINT(Point p) - { - return new POINT(p.X, p.Y); - } - - public Point ToPoint() - { - return new Point(X, Y); - } - - public override string ToString() - { - return X + "," + Y; - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Structs/RECT.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/RECT.cs deleted file mode 100644 index d28f11d2b..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Structs/RECT.cs +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace Greenshot.Base.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct RECT - { - private int _Left; - private int _Top; - private int _Right; - private int _Bottom; - - public RECT(RECT rectangle) - : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) - { - } - - public RECT(Rectangle rectangle) - : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom) - { - } - - public RECT(int left, int top, int right, int bottom) - { - _Left = left; - _Top = top; - _Right = right; - _Bottom = bottom; - } - - public int X - { - get { return _Left; } - set { _Left = value; } - } - - public int Y - { - get { return _Top; } - set { _Top = value; } - } - - public int Left - { - get { return _Left; } - set { _Left = value; } - } - - public int Top - { - get { return _Top; } - set { _Top = value; } - } - - public int Right - { - get { return _Right; } - set { _Right = value; } - } - - public int Bottom - { - get { return _Bottom; } - set { _Bottom = value; } - } - - public int Height - { - get { return _Bottom - _Top; } - set { _Bottom = value - _Top; } - } - - public int Width - { - get { return _Right - _Left; } - set { _Right = value + _Left; } - } - - public Point Location - { - get { return new Point(Left, Top); } - set - { - _Left = value.X; - _Top = value.Y; - } - } - - public Size Size - { - get { return new Size(Width, Height); } - set - { - _Right = value.Width + _Left; - _Bottom = value.Height + _Top; - } - } - - public static implicit operator Rectangle(RECT rectangle) - { - return new Rectangle(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height); - } - - public static implicit operator RECT(Rectangle rectangle) - { - return new RECT(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); - } - - public static bool operator ==(RECT rectangle1, RECT rectangle2) - { - return rectangle1.Equals(rectangle2); - } - - public static bool operator !=(RECT rectangle1, RECT rectangle2) - { - return !rectangle1.Equals(rectangle2); - } - - public override string ToString() - { - return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}"; - } - - public override int GetHashCode() - { - return ToString().GetHashCode(); - } - - public bool Equals(RECT rectangle) - { - return rectangle.Left == _Left && rectangle.Top == _Top && rectangle.Right == _Right && rectangle.Bottom == _Bottom; - } - - public Rectangle ToRectangle() - { - return new Rectangle(Left, Top, Width, Height); - } - - public override bool Equals(object Object) - { - if (Object is RECT) - { - return Equals((RECT) Object); - } - else if (Object is Rectangle) - { - return Equals(new RECT((Rectangle) Object)); - } - - return false; - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Structs/RECTF.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/RECTF.cs deleted file mode 100644 index 26be5eb63..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Structs/RECTF.cs +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; -using System.Runtime.InteropServices; - -namespace Greenshot.Base.UnmanagedHelpers.Structs -{ - /// - /// A floating point GDI Plus width/hight based rectangle. - /// - [StructLayout(LayoutKind.Sequential)] - public struct RECTF - { - /// - /// The X corner location of the rectangle. - /// - public float X; - - /// - /// The Y corner location of the rectangle. - /// - public float Y; - - /// - /// The width of the rectangle. - /// - public float Width; - - /// - /// The height of the rectangle. - /// - public float Height; - - /// - /// Creates a new GDI Plus rectangle. - /// - /// The X corner location of the rectangle. - /// The Y corner location of the rectangle. - /// The width of the rectangle. - /// The height of the rectangle. - public RECTF(float x, float y, float width, float height) - { - X = x; - Y = y; - Width = width; - Height = height; - } - - /// - /// Creates a new GDI Plus rectangle from a System.Drawing.RectangleF. - /// - /// The rectangle to base this GDI Plus rectangle on. - public RECTF(RectangleF rect) - { - X = rect.X; - Y = rect.Y; - Width = rect.Width; - Height = rect.Height; - } - - /// - /// Creates a new GDI Plus rectangle from a System.Drawing.Rectangle. - /// - /// The rectangle to base this GDI Plus rectangle on. - public RECTF(Rectangle rect) - { - X = rect.X; - Y = rect.Y; - Width = rect.Width; - Height = rect.Height; - } - - /// - /// Returns a RectangleF for this GDI Plus rectangle. - /// - /// A System.Drawing.RectangleF structure. - public RectangleF ToRectangle() - { - return new RectangleF(X, Y, Width, Height); - } - - /// - /// Returns a RectangleF for a GDI Plus rectangle. - /// - /// The GDI Plus rectangle to get the RectangleF for. - /// A System.Drawing.RectangleF structure. - public static RectangleF ToRectangle(RECTF rect) - { - return rect.ToRectangle(); - } - - /// - /// Returns a GDI Plus rectangle for a RectangleF structure. - /// - /// The RectangleF to get the GDI Plus rectangle for. - /// A GDI Plus rectangle structure. - public static RECTF FromRectangle(RectangleF rect) - { - return new RECTF(rect); - } - - /// - /// Returns a GDI Plus rectangle for a Rectangle structure. - /// - /// The Rectangle to get the GDI Plus rectangle for. - /// A GDI Plus rectangle structure. - public static RECTF FromRectangle(Rectangle rect) - { - return new RECTF(rect); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Structs/SCROLLINFO.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/SCROLLINFO.cs deleted file mode 100644 index cf9eaa937..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Structs/SCROLLINFO.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace Greenshot.Base.UnmanagedHelpers.Structs -{ - [Serializable, StructLayout(LayoutKind.Sequential)] - public struct SCROLLINFO - { - public int cbSize; - public int fMask; - public int nMin; - public int nMax; - public int nPage; - public int nPos; - public int nTrackPos; - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Structs/SIZE.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/SIZE.cs deleted file mode 100644 index a5a59b63f..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Structs/SIZE.cs +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Drawing; -using System.Runtime.InteropServices; - -namespace Greenshot.Base.UnmanagedHelpers.Structs -{ - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct SIZE - { - public int Width; - public int Height; - - public SIZE(Size size) : this(size.Width, size.Height) - { - } - - public SIZE(int width, int height) - { - Width = width; - Height = height; - } - - public Size ToSize() - { - return new Size(Width, Height); - } - - public bool IsEmpty => Width * Height == 0; - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowInfo.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowInfo.cs deleted file mode 100644 index f0b85cf2e..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowInfo.cs +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace Greenshot.Base.UnmanagedHelpers.Structs -{ - /// - /// The structure for the WindowInfo - /// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms632610%28v=vs.85%29.aspx - /// - [StructLayout(LayoutKind.Sequential), Serializable] - public struct WindowInfo - { - public uint cbSize; - public RECT rcWindow; - public RECT rcClient; - public uint dwStyle; - public uint dwExStyle; - public uint dwWindowStatus; - public uint cxWindowBorders; - public uint cyWindowBorders; - public ushort atomWindowType; - - public ushort wCreatorVersion; - - // Allows automatic initialization of "cbSize" with "new WINDOWINFO(null/true/false)". - public WindowInfo(bool? filler) : this() - { - cbSize = (uint) (Marshal.SizeOf(typeof(WindowInfo))); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowPlacement.cs b/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowPlacement.cs deleted file mode 100644 index a542a8cf0..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Structs/WindowPlacement.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; -using Greenshot.Base.UnmanagedHelpers.Enums; - -namespace Greenshot.Base.UnmanagedHelpers.Structs -{ - /// - /// Contains information about the placement of a window on the screen. - /// - [StructLayout(LayoutKind.Sequential), Serializable()] - public struct WindowPlacement - { - /// - /// The length of the structure, in bytes. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT). - /// - /// GetWindowPlacement and SetWindowPlacement fail if this member is not set correctly. - /// - /// - public int Length; - - /// - /// Specifies flags that control the position of the minimized window and the method by which the window is restored. - /// - public WindowPlacementFlags Flags; - - /// - /// The current show state of the window. - /// - public ShowWindowCommand ShowCmd; - - /// - /// The coordinates of the window's upper-left corner when the window is minimized. - /// - public POINT MinPosition; - - /// - /// The coordinates of the window's upper-left corner when the window is maximized. - /// - public POINT MaxPosition; - - /// - /// The window's coordinates when the window is in the restored position. - /// - public RECT NormalPosition; - - /// - /// Gets the default (empty) value. - /// - public static WindowPlacement Default - { - get - { - WindowPlacement result = new WindowPlacement(); - result.Length = Marshal.SizeOf(result); - return result; - } - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/User32.cs b/src/Greenshot.Base/UnmanagedHelpers/User32.cs deleted file mode 100644 index 58e89a115..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/User32.cs +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Text; -using System.Windows.Forms; -using Greenshot.Base.Core.Enums; -using Greenshot.Base.UnmanagedHelpers.Enums; -using Greenshot.Base.UnmanagedHelpers.Structs; -using log4net; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// User32 Wrappers - /// - public static class User32 - { - private static readonly ILog LOG = LogManager.GetLogger(typeof(User32)); - private static bool _CanCallGetPhysicalCursorPos = true; - public const int SC_RESTORE = 0xF120; - public const int SC_MAXIMIZE = 0xF030; - public const int SC_MINIMIZE = 0xF020; - - // For MonitorFromWindow - public const int MONITOR_DEFAULTTONULL = 0; - public const int MONITOR_DEFAULTTONEAREST = 2; - public const int CURSOR_SHOWING = 0x00000001; - - /// - /// Determines whether the specified window handle identifies an existing window. - /// - /// A handle to the window to be tested. - /// - /// If the window handle identifies an existing window, the return value is true. - /// If the window handle does not identify an existing window, the return value is false. - /// - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindow(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindowVisible(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId); - - [DllImport("user32", SetLastError = true)] - public static extern int GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId); - - [DllImport("user32")] - public static extern IntPtr AttachThreadInput(int idAttach, int idAttachTo, int fAttach); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetParent(IntPtr hWnd); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int cch); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool BringWindowToTop(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetForegroundWindow(); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetDesktopWindow(); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetForegroundWindow(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WindowPlacement lpwndpl); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsIconic(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsZoomed(IntPtr hWnd); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); - - [DllImport("user32", SetLastError = true)] - public static extern uint GetClassLong(IntPtr hWnd, int nIndex); - - [DllImport("user32", SetLastError = true, EntryPoint = "GetClassLongPtr")] - public static extern IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool PrintWindow(IntPtr hWnd, IntPtr hDc, PrintWindowFlags pwFlags); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern IntPtr SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLong")] - public static extern IntPtr GetWindowLong(IntPtr hWnd, int index); - - [DllImport("user32", SetLastError = true, EntryPoint = "GetWindowLongPtr")] - public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int SetWindowLong(IntPtr hWnd, int index, int styleFlags); - - [DllImport("user32", SetLastError = true, EntryPoint = "SetWindowLongPtr")] - public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int index, IntPtr styleFlags); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr MonitorFromWindow(IntPtr hWnd, MonitorFrom dwFlags); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr MonitorFromRect([In] ref RECT lprc, uint dwFlags); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowInfo(IntPtr hWnd, ref WindowInfo pwi); - - [DllImport("user32", SetLastError = true)] - public static extern int EnumChildWindows(IntPtr hWndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); - - [DllImport("user32", SetLastError = true)] - public static extern RegionResult GetWindowRgn(IntPtr hWnd, SafeHandle hRgn); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, WindowPos uFlags); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr GetClipboardOwner(); - - // Added for finding Metro apps, Greenshot 1.1 - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow); - - /// uiFlags: 0 - Count of GDI objects - /// uiFlags: 1 - Count of USER objects - /// - Win32 GDI objects (pens, brushes, fonts, palettes, regions, device contexts, bitmap headers) - /// - Win32 USER objects: - /// - WIN32 resources (accelerator tables, bitmap resources, dialog box templates, font resources, menu resources, raw data resources, string table entries, message table entries, cursors/icons) - /// - Other USER objects (windows, menus) - /// - [DllImport("user32", SetLastError = true)] - public static extern uint GetGuiResources(IntPtr hProcess, uint uiFlags); - - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern uint RegisterWindowMessage(string lpString); - - [DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult); - - [DllImport("user32", SetLastError = true)] - private static extern bool GetPhysicalCursorPos(out POINT cursorLocation); - - /// - /// The following is used for Icon handling - /// - /// - /// - [DllImport("user32", SetLastError = true)] - public static extern SafeIconHandle CopyIcon(IntPtr hIcon); - - [DllImport("user32", SetLastError = true)] - public static extern bool DestroyIcon(IntPtr hIcon); - - [DllImport("user32", SetLastError = true)] - public static extern bool GetCursorInfo(out CursorInfo cursorInfo); - - [DllImport("user32", SetLastError = true)] - public static extern bool GetIconInfo(SafeIconHandle iconHandle, out IconInfo iconInfo); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr SetCapture(IntPtr hWnd); - - [DllImport("user32", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool ReleaseCapture(); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr CreateIconIndirect(ref IconInfo icon); - - [DllImport("user32", SetLastError = true)] - public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, DesktopAccessRight dwDesiredAccess); - - [DllImport("user32", SetLastError = true)] - public static extern bool SetThreadDesktop(IntPtr hDesktop); - - [DllImport("user32", SetLastError = true)] - public static extern bool CloseDesktop(IntPtr hDesktop); - - /// - /// Retrieves the cursor location safely, accounting for DPI settings in Vista/Windows 7. - /// - /// Point with cursor location, relative to the origin of the monitor setup - /// (i.e. negative coordinates arepossible in multiscreen setups) - public static Point GetCursorLocation() - { - if (Environment.OSVersion.Version.Major >= 6 && _CanCallGetPhysicalCursorPos) - { - try - { - if (GetPhysicalCursorPos(out var cursorLocation)) - { - return new Point(cursorLocation.X, cursorLocation.Y); - } - - Win32Error error = Win32.GetLastErrorCode(); - LOG.ErrorFormat("Error retrieving PhysicalCursorPos : {0}", Win32.GetMessage(error)); - } - catch (Exception ex) - { - LOG.Error("Exception retrieving PhysicalCursorPos, no longer calling this. Cause :", ex); - _CanCallGetPhysicalCursorPos = false; - } - } - - return new Point(Cursor.Position.X, Cursor.Position.Y); - } - - /// - /// Wrapper for the GetClassLong which decides if the system is 64-bit or not and calls the right one. - /// - /// IntPtr - /// int - /// IntPtr - public static IntPtr GetClassLongWrapper(IntPtr hWnd, int nIndex) - { - if (IntPtr.Size > 4) - { - return GetClassLongPtr(hWnd, nIndex); - } - else - { - return new IntPtr(GetClassLong(hWnd, nIndex)); - } - } - - /// - /// Wrapper for the GetWindowLong which decides if the system is 64-bit or not and calls the right one. - /// - /// - /// - /// - public static IntPtr GetWindowLongWrapper(IntPtr hWnd, int nIndex) - { - if (IntPtr.Size == 8) - { - return GetWindowLongPtr(hWnd, nIndex); - } - - return GetWindowLong(hWnd, nIndex); - } - - /// - /// Wrapper for the SetWindowLong which decides if the system is 64-bit or not and calls the right one. - /// - /// - /// - /// - public static void SetWindowLongWrapper(IntPtr hWnd, int nIndex, IntPtr styleFlags) - { - if (IntPtr.Size == 8) - { - SetWindowLongPtr(hWnd, nIndex, styleFlags); - } - else - { - SetWindowLong(hWnd, nIndex, styleFlags.ToInt32()); - } - } - - public static uint GetGuiResourcesGDICount() - { - using var currentProcess = Process.GetCurrentProcess(); - return GetGuiResources(currentProcess.Handle, 0); - } - - public static uint GetGuiResourcesUserCount() - { - using var currentProcess = Process.GetCurrentProcess(); - return GetGuiResources(currentProcess.Handle, 1); - } - - /// - /// Helper method to create a Win32 exception with the windows message in it - /// - /// string with current method - /// Exception - public static Exception CreateWin32Exception(string method) - { - var exceptionToThrow = new Win32Exception(); - exceptionToThrow.Data.Add("Method", method); - return exceptionToThrow; - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/Win32.cs b/src/Greenshot.Base/UnmanagedHelpers/Win32.cs deleted file mode 100644 index d5b3def78..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/Win32.cs +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; -using System.Text; -using Greenshot.Base.UnmanagedHelpers.Enums; - -namespace Greenshot.Base.UnmanagedHelpers -{ - public static class Win32 - { - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - private static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer, int nSize, IntPtr arguments); - - [DllImport("kernel32.dll")] - public static extern void SetLastError(uint dwErrCode); - - public static Win32Error GetLastErrorCode() - { - return (Win32Error) Marshal.GetLastWin32Error(); - } - - public static string GetMessage(Win32Error errorCode) - { - var buffer = new StringBuilder(0x100); - - if (FormatMessage(0x3200, IntPtr.Zero, (uint) errorCode, 0, buffer, buffer.Capacity, IntPtr.Zero) == 0) - { - return "Unknown error (0x" + ((int) errorCode).ToString("x") + ")"; - } - - var result = new StringBuilder(); - int i = 0; - - while (i < buffer.Length) - { - if (!char.IsLetterOrDigit(buffer[i]) && - !char.IsPunctuation(buffer[i]) && - !char.IsSymbol(buffer[i]) && - !char.IsWhiteSpace(buffer[i])) - break; - - result.Append(buffer[i]); - i++; - } - - return result.ToString().Replace("\r\n", string.Empty); - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/WinEventDelegate.cs b/src/Greenshot.Base/UnmanagedHelpers/WinEventDelegate.cs deleted file mode 100644 index bd54923f7..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/WinEventDelegate.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Greenshot.Base.UnmanagedHelpers.Enums; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// Used with SetWinEventHook - /// - /// - /// - /// - /// - /// - /// - /// - public delegate void WinEventDelegate(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd, EventObjects idObject, int idChild, uint dwEventThread, uint dwmsEventTime); -} \ No newline at end of file diff --git a/src/Greenshot.Base/UnmanagedHelpers/WinMM.cs b/src/Greenshot.Base/UnmanagedHelpers/WinMM.cs deleted file mode 100644 index bee586bda..000000000 --- a/src/Greenshot.Base/UnmanagedHelpers/WinMM.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Runtime.InteropServices; - -namespace Greenshot.Base.UnmanagedHelpers -{ - /// - /// Windows Media - /// - public class WinMM - { - [DllImport("winmm.dll", SetLastError = true)] - public static extern bool PlaySound(byte[] ptrToSound, UIntPtr hmod, uint fdwSound); - - [DllImport("winmm.dll", SetLastError = true)] - public static extern bool PlaySound(IntPtr ptrToSound, UIntPtr hmod, uint fdwSound); - } -} \ No newline at end of file diff --git a/src/Greenshot.Editor/Configuration/EditorConfiguration.cs b/src/Greenshot.Editor/Configuration/EditorConfiguration.cs index 9dfb09c23..3a516797c 100644 --- a/src/Greenshot.Editor/Configuration/EditorConfiguration.cs +++ b/src/Greenshot.Editor/Configuration/EditorConfiguration.cs @@ -22,11 +22,12 @@ using System; using System.Collections.Generic; using System.Drawing; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.User32.Enums; +using Dapplo.Windows.User32.Structs; using Greenshot.Base.Effects; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces.Drawing; -using Greenshot.Base.UnmanagedHelpers.Enums; -using Greenshot.Base.UnmanagedHelpers.Structs; using Greenshot.Editor.Drawing.Fields; namespace Greenshot.Editor.Configuration @@ -50,16 +51,16 @@ namespace Greenshot.Editor.Configuration public WindowPlacementFlags WindowPlacementFlags { get; set; } [IniProperty("WindowShowCommand", Description = "Show command", DefaultValue = "Normal")] - public ShowWindowCommand ShowWindowCommand { get; set; } + public ShowWindowCommands ShowWindowCommand { get; set; } [IniProperty("WindowMinPosition", Description = "Position of minimized window", DefaultValue = "-1,-1")] - public Point WindowMinPosition { get; set; } + public NativePoint WindowMinPosition { get; set; } [IniProperty("WindowMaxPosition", Description = "Position of maximized window", DefaultValue = "-1,-1")] - public Point WindowMaxPosition { get; set; } + public NativePoint WindowMaxPosition { get; set; } [IniProperty("WindowNormalPosition", Description = "Position of normal window", DefaultValue = "100,100,400,400")] - public Rectangle WindowNormalPosition { get; set; } + public NativeRect WindowNormalPosition { get; set; } [IniProperty("ReuseEditor", Description = "Reuse already open editor", DefaultValue = "false")] public bool ReuseEditor { get; set; } @@ -77,7 +78,7 @@ namespace Greenshot.Editor.Configuration public TornEdgeEffect TornEdgeEffectSettings { get; set; } [IniProperty("DefaultEditorSize", Description = "The size for the editor when it's opened without a capture", DefaultValue = "500,500")] - public Size DefaultEditorSize { get; set; } + public NativeSize DefaultEditorSize { get; set; } public override void AfterLoad() @@ -151,19 +152,19 @@ namespace Greenshot.Editor.Configuration public void ResetEditorPlacement() { - WindowNormalPosition = new Rectangle(100, 100, 400, 400); - WindowMaxPosition = new Point(-1, -1); - WindowMinPosition = new Point(-1, -1); + WindowNormalPosition = new NativeRect(100, 100, 400, 400); + WindowMaxPosition = new NativePoint(-1, -1); + WindowMinPosition = new NativePoint(-1, -1); WindowPlacementFlags = 0; - ShowWindowCommand = ShowWindowCommand.Normal; + ShowWindowCommand = ShowWindowCommands.Normal; } public WindowPlacement GetEditorPlacement() { - WindowPlacement placement = WindowPlacement.Default; - placement.NormalPosition = new RECT(WindowNormalPosition); - placement.MaxPosition = new POINT(WindowMaxPosition); - placement.MinPosition = new POINT(WindowMinPosition); + WindowPlacement placement = WindowPlacement.Create(); + placement.NormalPosition = WindowNormalPosition; + placement.MaxPosition = WindowMaxPosition; + placement.MinPosition = WindowMinPosition; placement.ShowCmd = ShowWindowCommand; placement.Flags = WindowPlacementFlags; return placement; @@ -171,9 +172,9 @@ namespace Greenshot.Editor.Configuration public void SetEditorPlacement(WindowPlacement placement) { - WindowNormalPosition = placement.NormalPosition.ToRectangle(); - WindowMaxPosition = placement.MaxPosition.ToPoint(); - WindowMinPosition = placement.MinPosition.ToPoint(); + WindowNormalPosition = placement.NormalPosition; + WindowMaxPosition = placement.MaxPosition; + WindowMinPosition = placement.MinPosition; ShowWindowCommand = placement.ShowCmd; WindowPlacementFlags = placement.Flags; } diff --git a/src/Greenshot.Editor/Controls/ColorButton.cs b/src/Greenshot.Editor/Controls/ColorButton.cs index 849395330..9e968afbc 100644 --- a/src/Greenshot.Editor/Controls/ColorButton.cs +++ b/src/Greenshot.Editor/Controls/ColorButton.cs @@ -24,6 +24,7 @@ using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Controls; using ColorDialog = Greenshot.Editor.Forms.ColorDialog; @@ -65,7 +66,7 @@ namespace Greenshot.Editor.Controls if (Image != null) { using Graphics graphics = Graphics.FromImage(Image); - graphics.FillRectangle(brush, new Rectangle(4, 17, 16, 3)); + graphics.FillRectangle(brush, new NativeRect(4, 17, 16, 3)); } // cleanup GDI Object diff --git a/src/Greenshot.Editor/Controls/FontFamilyComboBox.cs b/src/Greenshot.Editor/Controls/FontFamilyComboBox.cs index b57d52e75..cabb40e49 100644 --- a/src/Greenshot.Editor/Controls/FontFamilyComboBox.cs +++ b/src/Greenshot.Editor/Controls/FontFamilyComboBox.cs @@ -23,6 +23,7 @@ using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; namespace Greenshot.Editor.Controls { @@ -113,12 +114,12 @@ namespace Greenshot.Editor.Controls /// /// Helper method to draw the string /// - /// - /// - /// - /// - /// - private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, Rectangle bounds, string text) + /// Graphics + /// FontFamily + /// FontStyle + /// NativeRect + /// string + private void DrawText(Graphics graphics, FontFamily fontFamily, FontStyle fontStyle, NativeRect bounds, string text) { using Font font = new Font(fontFamily, Font.Size + 5, fontStyle, GraphicsUnit.Pixel); // Make sure the text is visible by centering it in the line diff --git a/src/Greenshot.Editor/Controls/MenuStripEx.cs b/src/Greenshot.Editor/Controls/MenuStripEx.cs index 9af1da2cf..c140416f6 100644 --- a/src/Greenshot.Editor/Controls/MenuStripEx.cs +++ b/src/Greenshot.Editor/Controls/MenuStripEx.cs @@ -21,7 +21,7 @@ using System; using System.Windows.Forms; -using Greenshot.Base.UnmanagedHelpers.Enums; +using Dapplo.Windows.Messages.Enumerations; namespace Greenshot.Editor.Controls { diff --git a/src/Greenshot.Editor/Controls/Pipette.cs b/src/Greenshot.Editor/Controls/Pipette.cs index d31017b92..dc1ae1046 100644 --- a/src/Greenshot.Editor/Controls/Pipette.cs +++ b/src/Greenshot.Editor/Controls/Pipette.cs @@ -23,8 +23,11 @@ using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; -using Greenshot.Base.UnmanagedHelpers; -using Greenshot.Base.UnmanagedHelpers.Enums; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Icons; +using Dapplo.Windows.Icons.SafeHandles; +using Dapplo.Windows.Messages.Enumerations; +using Dapplo.Windows.User32; using Greenshot.Editor.Forms; using ColorDialog = Greenshot.Editor.Forms.ColorDialog; @@ -65,11 +68,10 @@ namespace Greenshot.Editor.Controls private static Cursor CreateCursor(Bitmap bitmap, int hotspotX, int hotspotY) { using SafeIconHandle iconHandle = new SafeIconHandle(bitmap.GetHicon()); - User32.GetIconInfo(iconHandle, out var iconInfo); - iconInfo.xHotspot = hotspotX; - iconInfo.yHotspot = hotspotY; - iconInfo.fIcon = false; - var icon = User32.CreateIconIndirect(ref iconInfo); + NativeIconMethods.GetIconInfo(iconHandle, out var iconInfo); + iconInfo.Hotspot = new NativePoint(hotspotX, hotspotY); + iconInfo.IsIcon = false; + var icon = NativeIconMethods.CreateIconIndirect(ref iconInfo); return new Cursor(icon); } @@ -110,7 +112,7 @@ namespace Greenshot.Editor.Controls { if (e.Button == MouseButtons.Left) { - User32.SetCapture(Handle); + User32Api.SetCapture(Handle); _movableShowColorForm.MoveTo(PointToScreen(new Point(e.X, e.Y))); } @@ -126,8 +128,8 @@ namespace Greenshot.Editor.Controls if (e.Button == MouseButtons.Left) { //Release Capture should consume MouseUp when canceled with the escape key - User32.ReleaseCapture(); - PipetteUsed?.Invoke(this, new PipetteUsedArgs(_movableShowColorForm.color)); + User32Api.ReleaseCapture(); + PipetteUsed?.Invoke(this, new PipetteUsedArgs(_movableShowColorForm.Color)); } base.OnMouseUp(e); @@ -183,7 +185,7 @@ namespace Greenshot.Editor.Controls { if ((int) m.WParam == VkEsc) { - User32.ReleaseCapture(); + User32Api.ReleaseCapture(); } } } diff --git a/src/Greenshot.Editor/Controls/ToolStripColorButton.cs b/src/Greenshot.Editor/Controls/ToolStripColorButton.cs index 91386b4f4..eb05a0fcc 100644 --- a/src/Greenshot.Editor/Controls/ToolStripColorButton.cs +++ b/src/Greenshot.Editor/Controls/ToolStripColorButton.cs @@ -24,6 +24,7 @@ using System.ComponentModel; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Controls; using ColorDialog = Greenshot.Editor.Forms.ColorDialog; @@ -63,7 +64,7 @@ namespace Greenshot.Editor.Controls if (Image != null) { using Graphics graphics = Graphics.FromImage(Image); - graphics.FillRectangle(brush, new Rectangle(0, 13, 16, 3)); + graphics.FillRectangle(brush, new NativeRect(0, 13, 16, 3)); } // cleanup GDI Object diff --git a/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs index 0890a87d9..aa023b19c 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs @@ -22,7 +22,9 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; -using Greenshot.Base.Core; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Dpi; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing.Adorners; @@ -32,12 +34,12 @@ namespace Greenshot.Editor.Drawing.Adorners { public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE; - private static readonly Size DefaultSize = new Size(6, 6); - protected Size _size; + private static readonly NativeSize DefaultSize = new NativeSize(6, 6); + protected NativeSize _size; public AbstractAdorner(IDrawableContainer owner) { - _size = DpiHelper.ScaleWithDpi(DefaultSize, 0); + _size = DpiCalculator.ScaleWithDpi(DefaultSize, 0); Owner = owner; } @@ -54,12 +56,11 @@ namespace Greenshot.Editor.Drawing.Adorners /// /// Test if the point is inside the adorner /// - /// - /// - public virtual bool HitTest(Point point) + /// NativePoint + /// bool + public virtual bool HitTest(NativePoint point) { - Rectangle hitBounds = Bounds; - hitBounds.Inflate(3, 3); + NativeRect hitBounds = Bounds.Inflate(3, 3); return hitBounds.Contains(point); } @@ -94,29 +95,29 @@ namespace Greenshot.Editor.Drawing.Adorners /// /// Return the location of the adorner /// - public virtual Point Location { get; set; } + public virtual NativePoint Location { get; set; } /// /// Return the bounds of the Adorner /// - public virtual Rectangle Bounds + public virtual NativeRect Bounds { get { - Point location = Location; - return new Rectangle(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height); + NativePoint location = Location; + return new NativeRect(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height); } } /// /// Return the bounds of the Adorner as displayed on the parent Surface /// - protected virtual Rectangle BoundsOnSurface + protected virtual NativeRect BoundsOnSurface { get { - Point displayLocation = Owner.Parent.ToSurfaceCoordinates(Location); - return new Rectangle(displayLocation.X - _size.Width / 2, displayLocation.Y - _size.Height / 2, _size.Width, _size.Height); + NativePoint displayLocation = Owner.Parent.ToSurfaceCoordinates(Location); + return new NativeRect(displayLocation.X - _size.Width / 2, displayLocation.Y - _size.Height / 2, _size.Width, _size.Height); } } @@ -132,9 +133,9 @@ namespace Greenshot.Editor.Drawing.Adorners /// Adjust UI elements to the supplied DPI settings /// /// uint - public void AdjustToDpi(uint dpi) + public void AdjustToDpi(int dpi) { - _size = DpiHelper.ScaleWithDpi(DefaultSize, dpi); + _size = DpiCalculator.ScaleWithDpi(DefaultSize, dpi); } public Color OutlineColor { get; set; } = Color.White; diff --git a/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs index 7c20e6722..46fcdb1b0 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs @@ -20,8 +20,8 @@ */ using System.Drawing; -using System.Drawing.Drawing2D; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Helpers; @@ -32,8 +32,8 @@ namespace Greenshot.Editor.Drawing.Adorners /// public class MoveAdorner : AbstractAdorner { - private Rectangle _boundsBeforeResize = Rectangle.Empty; - private RectangleF _boundsAfterResize = RectangleF.Empty; + private NativeRect _boundsBeforeResize = NativeRect.Empty; + private NativeRectFloat _boundsAfterResize = NativeRectFloat.Empty; public Positions Position { get; private set; } @@ -55,7 +55,7 @@ namespace Greenshot.Editor.Drawing.Adorners public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) { EditStatus = EditStatus.RESIZING; - _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); + _boundsBeforeResize = new NativeRect(Owner.Left, Owner.Top, Owner.Width, Owner.Height); _boundsAfterResize = _boundsBeforeResize; } @@ -75,10 +75,7 @@ namespace Greenshot.Editor.Drawing.Adorners Owner.MakeBoundsChangeUndoable(false); // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.X; - _boundsAfterResize.Y = _boundsBeforeResize.Y; - _boundsAfterResize.Width = _boundsBeforeResize.Width; - _boundsAfterResize.Height = _boundsBeforeResize.Height; + _boundsAfterResize = _boundsBeforeResize; // calculate scaled rectangle ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); @@ -92,7 +89,7 @@ namespace Greenshot.Editor.Drawing.Adorners /// /// Return the location of the adorner /// - public override Point Location + public override NativePoint Location { get { @@ -133,7 +130,7 @@ namespace Greenshot.Editor.Drawing.Adorners break; } - return new Point(x, y); + return new NativePoint(x, y); } } } diff --git a/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs index c99d4440f..aaad53355 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs @@ -20,8 +20,8 @@ */ using System.Drawing; -using System.Drawing.Drawing2D; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Helpers; @@ -32,8 +32,8 @@ namespace Greenshot.Editor.Drawing.Adorners /// public class ResizeAdorner : AbstractAdorner { - private Rectangle _boundsBeforeResize = Rectangle.Empty; - private RectangleF _boundsAfterResize = RectangleF.Empty; + private NativeRect _boundsBeforeResize = NativeRect.Empty; + private NativeRectFloat _boundsAfterResize = NativeRectFloat.Empty; public Positions Position { get; private set; } @@ -55,23 +55,18 @@ namespace Greenshot.Editor.Drawing.Adorners isNotSwitched = !isNotSwitched; } - switch (Position) + return Position switch { - case Positions.TopLeft: - case Positions.BottomRight: - return isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW; - case Positions.TopRight: - case Positions.BottomLeft: - return isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE; - case Positions.MiddleLeft: - case Positions.MiddleRight: - return Cursors.SizeWE; - case Positions.TopCenter: - case Positions.BottomCenter: - return Cursors.SizeNS; - default: - return Cursors.SizeAll; - } + Positions.TopLeft => isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW, + Positions.BottomRight => isNotSwitched ? Cursors.SizeNWSE : Cursors.SizeNESW, + Positions.TopRight => isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE, + Positions.BottomLeft => isNotSwitched ? Cursors.SizeNESW : Cursors.SizeNWSE, + Positions.MiddleLeft => Cursors.SizeWE, + Positions.MiddleRight => Cursors.SizeWE, + Positions.TopCenter => Cursors.SizeNS, + Positions.BottomCenter => Cursors.SizeNS, + _ => Cursors.SizeAll + }; } } @@ -83,7 +78,7 @@ namespace Greenshot.Editor.Drawing.Adorners public override void MouseDown(object sender, MouseEventArgs mouseEventArgs) { EditStatus = EditStatus.RESIZING; - _boundsBeforeResize = new Rectangle(Owner.Left, Owner.Top, Owner.Width, Owner.Height); + _boundsBeforeResize = new NativeRect(Owner.Left, Owner.Top, Owner.Width, Owner.Height); _boundsAfterResize = _boundsBeforeResize; } @@ -103,10 +98,7 @@ namespace Greenshot.Editor.Drawing.Adorners Owner.MakeBoundsChangeUndoable(false); // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.X; - _boundsAfterResize.Y = _boundsBeforeResize.Y; - _boundsAfterResize.Width = _boundsBeforeResize.Width; - _boundsAfterResize.Height = _boundsBeforeResize.Height; + _boundsAfterResize = _boundsBeforeResize; // calculate scaled rectangle ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); @@ -120,7 +112,7 @@ namespace Greenshot.Editor.Drawing.Adorners /// /// Return the location of the adorner /// - public override Point Location + public override NativePoint Location { get { diff --git a/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs index c59fc43ef..864ff28c5 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/TargetAdorner.cs @@ -22,6 +22,8 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Editor.Drawing.Adorners @@ -61,30 +63,30 @@ namespace Greenshot.Editor.Drawing.Adorners } Owner.Invalidate(); - Point newGripperLocation = new Point(mouseEventArgs.X, mouseEventArgs.Y); - Rectangle imageBounds = new Rectangle(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height); + NativePoint newGripperLocation = new NativePoint(mouseEventArgs.X, mouseEventArgs.Y); + NativeRect imageBounds = new NativeRect(0, 0, Owner.Parent.Image.Width, Owner.Parent.Image.Height); // Check if gripper inside the parent (surface), if not we need to move it inside // This was made for BUG-1682 if (!imageBounds.Contains(newGripperLocation)) { if (newGripperLocation.X > imageBounds.Right) { - newGripperLocation.X = imageBounds.Right - 5; + newGripperLocation = newGripperLocation.ChangeX(imageBounds.Right - 5); } if (newGripperLocation.X < imageBounds.Left) { - newGripperLocation.X = imageBounds.Left; + newGripperLocation = newGripperLocation.ChangeX(imageBounds.Left); } if (newGripperLocation.Y > imageBounds.Bottom) { - newGripperLocation.Y = imageBounds.Bottom - 5; + newGripperLocation = newGripperLocation.ChangeY(imageBounds.Bottom - 5); } if (newGripperLocation.Y < imageBounds.Top) { - newGripperLocation.Y = imageBounds.Top; + newGripperLocation = newGripperLocation.ChangeY(imageBounds.Top); } } @@ -103,7 +105,7 @@ namespace Greenshot.Editor.Drawing.Adorners return; } - Point[] points = new[] + Point[] points = new Point[] { Location }; diff --git a/src/Greenshot.Editor/Drawing/ArrowContainer.cs b/src/Greenshot.Editor/Drawing/ArrowContainer.cs index 9907ad106..91c76366b 100644 --- a/src/Greenshot.Editor/Drawing/ArrowContainer.cs +++ b/src/Greenshot.Editor/Drawing/ArrowContainer.cs @@ -22,6 +22,8 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; @@ -115,7 +117,7 @@ namespace Greenshot.Editor.Drawing } } - public override Rectangle DrawingBounds + public override NativeRect DrawingBounds { get { @@ -130,12 +132,11 @@ namespace Greenshot.Editor.Drawing using GraphicsPath path = new GraphicsPath(); path.AddLine(Left, Top, Left + Width, Top + Height); using Matrix matrix = new Matrix(); - Rectangle drawingBounds = Rectangle.Round(path.GetBounds(matrix, pen)); - drawingBounds.Inflate(2, 2); - return drawingBounds; + NativeRect drawingBounds = Rectangle.Round(path.GetBounds(matrix, pen)); + return drawingBounds.Inflate(2, 2); } - return Rectangle.Empty; + return NativeRect.Empty; } } diff --git a/src/Greenshot.Editor/Drawing/CropContainer.cs b/src/Greenshot.Editor/Drawing/CropContainer.cs index f33045b61..f72f4e72c 100644 --- a/src/Greenshot.Editor/Drawing/CropContainer.cs +++ b/src/Greenshot.Editor/Drawing/CropContainer.cs @@ -22,6 +22,8 @@ using System.Drawing; using System.Runtime.Serialization; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Adorners; @@ -141,16 +143,16 @@ namespace Greenshot.Editor.Drawing /// We need to override the DrawingBound, return a rectangle in the size of the image, to make sure this element is always draw /// (we create a transparent brown over the complete picture) /// - public override Rectangle DrawingBounds + public override NativeRect DrawingBounds { get { if (_parent?.Image is { } image) { - return new Rectangle(0, 0, image.Width, image.Height); + return new NativeRect(0, 0, image.Width, image.Height); } - return Rectangle.Empty; + return NativeRect.Empty; } } @@ -163,8 +165,8 @@ namespace Greenshot.Editor.Drawing using Brush cropBrush = new SolidBrush(Color.FromArgb(100, 150, 150, 100)); - Rectangle cropRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Rectangle selectionRect = new Rectangle(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1); + var cropRectangle = new NativeRect(Left, Top, Width, Height).Normalize(); + var selectionRect = new NativeRect(cropRectangle.Left - 1, cropRectangle.Top - 1, cropRectangle.Width + 1, cropRectangle.Height + 1); Size imageSize = _parent.Image.Size; DrawSelectionBorder(g, selectionRect); @@ -225,10 +227,7 @@ namespace Greenshot.Editor.Drawing //allow only horizontal changes if (_parent?.Image is { } image) { - _boundsAfterResize.X = 0; - _boundsAfterResize.Y = _boundsBeforeResize.Top; - _boundsAfterResize.Width = image.Width; - _boundsAfterResize.Height = y - _boundsAfterResize.Top; + _boundsAfterResize = new NativeRectFloat(0, _boundsBeforeResize.Top, image.Width, y - _boundsAfterResize.Top); } break; } @@ -238,23 +237,18 @@ namespace Greenshot.Editor.Drawing //allow only vertical changes if (_parent?.Image is { } image) { - _boundsAfterResize.X = _boundsBeforeResize.Left; - _boundsAfterResize.Y = 0; - _boundsAfterResize.Width = x - _boundsAfterResize.Left; - _boundsAfterResize.Height = image.Height; + _boundsAfterResize = new NativeRectFloat(_boundsBeforeResize.Left, 0, x - _boundsAfterResize.Left, image.Height); } break; } default: { // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.Left; - _boundsAfterResize.Y = _boundsBeforeResize.Top; - _boundsAfterResize.Width = x - _boundsAfterResize.Left; - _boundsAfterResize.Height = y - _boundsAfterResize.Top; + _boundsAfterResize = new NativeRectFloat( + _boundsBeforeResize.Left, _boundsBeforeResize.Top, + x - _boundsAfterResize.Left, y - _boundsAfterResize.Top); break; } - } ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); diff --git a/src/Greenshot.Editor/Drawing/CursorContainer.cs b/src/Greenshot.Editor/Drawing/CursorContainer.cs index 0eda46085..e8914eb75 100644 --- a/src/Greenshot.Editor/Drawing/CursorContainer.cs +++ b/src/Greenshot.Editor/Drawing/CursorContainer.cs @@ -25,6 +25,7 @@ using System.Drawing.Drawing2D; using System.IO; using System.Runtime.Serialization; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using log4net; @@ -124,6 +125,6 @@ namespace Greenshot.Editor.Drawing cursor.DrawStretched(graphics, Bounds); } - public override Size DefaultSize => cursor?.Size ?? new Size(16, 16); + public override NativeSize DefaultSize => cursor?.Size ?? new NativeSize(16, 16); } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index 7ae58bfe6..f80831df2 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -27,6 +27,8 @@ using System.Drawing.Drawing2D; using System.Linq; using System.Runtime.Serialization; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; @@ -228,9 +230,9 @@ namespace Greenshot.Editor.Drawing } } - public Point Location + public NativePoint Location { - get => new Point(left, top); + get => new NativePoint(left, top); set { left = value.X; @@ -238,9 +240,9 @@ namespace Greenshot.Editor.Drawing } } - public Size Size + public NativeSize Size { - get => new Size(width, height); + get => new NativeSize(width, height); set { width = value.Width; @@ -257,15 +259,15 @@ namespace Greenshot.Editor.Drawing [NonSerialized] // will store current bounds of this DrawableContainer before starting a resize - protected Rectangle _boundsBeforeResize = Rectangle.Empty; + protected NativeRect _boundsBeforeResize = NativeRect.Empty; [NonSerialized] // "workbench" rectangle - used for calculating bounds during resizing (to be applied to this DrawableContainer afterwards) - protected RectangleF _boundsAfterResize = RectangleF.Empty; + protected NativeRectFloat _boundsAfterResize = NativeRectFloat.Empty; - public Rectangle Bounds + public NativeRect Bounds { - get => GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + get => new NativeRect(Left, Top, Width, Height).Normalize(); set { Left = Round(value.Left); @@ -275,7 +277,7 @@ namespace Greenshot.Editor.Drawing } } - public virtual void ApplyBounds(RectangleF newBounds) + public virtual void ApplyBounds(NativeRectFloat newBounds) { Left = Round(newBounds.Left); Top = Round(newBounds.Top); @@ -308,7 +310,7 @@ namespace Greenshot.Editor.Drawing private bool accountForShadowChange; - public virtual Rectangle DrawingBounds + public virtual NativeRect DrawingBounds { get { @@ -316,7 +318,7 @@ namespace Greenshot.Editor.Drawing { if (filter.Invert) { - return new Rectangle(Point.Empty, _parent.Image.Size); + return new NativeRect(Point.Empty, _parent.Image.Size); } } @@ -340,7 +342,7 @@ namespace Greenshot.Editor.Drawing shadow += 10; } - return new Rectangle(Bounds.Left - offset, Bounds.Top - offset, Bounds.Width + lineThickness + shadow, Bounds.Height + lineThickness + shadow); + return new NativeRect(Bounds.Left - offset, Bounds.Top - offset, Bounds.Width + lineThickness + shadow, Bounds.Height + lineThickness + shadow); } } @@ -364,8 +366,8 @@ namespace Greenshot.Editor.Drawing /// /// Initialize a target gripper /// - /// Point - protected void InitTargetAdorner(Point location) + /// NativePoint + protected void InitTargetAdorner(NativePoint location) { _targetAdorner = new TargetAdorner(this, location); Adorners.Add(_targetAdorner); @@ -396,7 +398,7 @@ namespace Greenshot.Editor.Drawing public abstract void Draw(Graphics graphics, RenderMode renderMode); - public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, Rectangle clipRectangle) + public virtual void DrawContent(Graphics graphics, Bitmap bmp, RenderMode renderMode, NativeRect clipRectangle) { if (Children.Count > 0) { @@ -416,8 +418,7 @@ namespace Greenshot.Editor.Drawing } else { - Rectangle drawingRect = new Rectangle(Bounds.Location, Bounds.Size); - drawingRect.Intersect(clipRectangle); + var drawingRect = new NativeRect(Bounds.Location, Bounds.Size).Intersect(clipRectangle); if (filter is MagnifierFilter) { // quick&dirty bugfix, because MagnifierFilter behaves differently when drawn only partially @@ -441,7 +442,7 @@ namespace Greenshot.Editor.Drawing /// Adjust UI elements to the supplied DPI settings /// /// uint with dpi value - public void AdjustToDpi(uint dpi) + public void AdjustToDpi(int dpi) { foreach (var adorner in Adorners) { @@ -462,12 +463,12 @@ namespace Greenshot.Editor.Drawing public virtual bool ClickableAt(int x, int y) { - Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - r.Inflate(5, 5); + var r = new NativeRect(Left, Top, Width, Height).Normalize(); + r = r.Inflate(5, 5); return r.Contains(x, y); } - protected void DrawSelectionBorder(Graphics g, Rectangle rect) + protected void DrawSelectionBorder(Graphics g, NativeRect rect) { using Pen pen = new Pen(Color.MediumSeaGreen) { @@ -513,8 +514,9 @@ namespace Greenshot.Editor.Drawing /// true if the event is handled, false if the surface needs to handle it public virtual bool HandleMouseDown(int x, int y) { - Left = _boundsBeforeResize.X = x; - Top = _boundsBeforeResize.Y = y; + _boundsBeforeResize = _boundsBeforeResize.MoveTo(x, y); + Left = x; + Top = y; return true; } @@ -529,10 +531,7 @@ namespace Greenshot.Editor.Drawing Invalidate(); // reset "workbench" rectangle to current bounds - _boundsAfterResize.X = _boundsBeforeResize.Left; - _boundsAfterResize.Y = _boundsBeforeResize.Top; - _boundsAfterResize.Width = x - _boundsAfterResize.Left; - _boundsAfterResize.Height = y - _boundsAfterResize.Top; + _boundsAfterResize = _boundsBeforeResize; ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); @@ -676,7 +675,7 @@ namespace Greenshot.Editor.Drawing public virtual bool HasDefaultSize => false; - public virtual Size DefaultSize => throw new NotSupportedException("Object doesn't have a default size"); + public virtual NativeSize DefaultSize => throw new NotSupportedException("Object doesn't have a default size"); /// /// Allows to override the initializing of the fields, so we can actually have our own defaults diff --git a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs index 4da98fa37..ef30c037f 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainerList.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainerList.cs @@ -27,6 +27,8 @@ using System.Drawing.Drawing2D; using System.Linq; using System.Threading; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; @@ -258,7 +260,7 @@ namespace Greenshot.Editor.Drawing /// /// /// true if an filter intersects - public bool HasIntersectingFilters(Rectangle clipRectangle) + public bool HasIntersectingFilters(NativeRect clipRectangle) { foreach (var dc in this) { @@ -274,9 +276,9 @@ namespace Greenshot.Editor.Drawing /// /// Check if any of the drawableContainers are inside the rectangle /// - /// + /// NativeRect /// - public bool IntersectsWith(Rectangle clipRectangle) + public bool IntersectsWith(NativeRect clipRectangle) { foreach (var dc in this) { @@ -293,19 +295,19 @@ namespace Greenshot.Editor.Drawing /// A rectangle containing DrawingBounds of all drawableContainers in this list, /// or empty rectangle if nothing is there. ///
- public Rectangle DrawingBounds + public NativeRect DrawingBounds { get { if (Count == 0) { - return Rectangle.Empty; + return NativeRect.Empty; } var result = this[0].DrawingBounds; for (int i = 1; i < Count; i++) { - result = Rectangle.Union(result, this[i].DrawingBounds); + result = result.Union(this[i].DrawingBounds); } return result; @@ -318,8 +320,8 @@ namespace Greenshot.Editor.Drawing /// the to the bitmap related Graphics object /// Bitmap to draw /// the RenderMode in which the element is to be drawn - /// - public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, Rectangle clipRectangle) + /// NativeRect + public void Draw(Graphics g, Bitmap bitmap, RenderMode renderMode, NativeRect clipRectangle) { if (Parent == null) { @@ -365,10 +367,10 @@ namespace Greenshot.Editor.Drawing return; } - Rectangle region = Rectangle.Empty; + NativeRect region = NativeRect.Empty; foreach (var dc in this) { - region = Rectangle.Union(region, dc.DrawingBounds); + region = region.Union(dc.DrawingBounds); } Parent.InvalidateElements(region); @@ -770,8 +772,8 @@ namespace Greenshot.Editor.Drawing /// /// Adjust UI elements to the supplied DPI settings /// - /// - public void AdjustToDpi(uint dpi) + /// int + public void AdjustToDpi(int dpi) { foreach (var drawableContainer in this) { diff --git a/src/Greenshot.Editor/Drawing/EllipseContainer.cs b/src/Greenshot.Editor/Drawing/EllipseContainer.cs index b32ecffd3..c421515d9 100644 --- a/src/Greenshot.Editor/Drawing/EllipseContainer.cs +++ b/src/Greenshot.Editor/Drawing/EllipseContainer.cs @@ -23,6 +23,8 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; @@ -71,7 +73,7 @@ namespace Greenshot.Editor.Drawing Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); DrawEllipse(rect, graphics, renderMode, lineThickness, lineColor, fillColor, shadow); } @@ -85,7 +87,7 @@ namespace Greenshot.Editor.Drawing /// /// /// - public static void DrawEllipse(Rectangle rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow) + public static void DrawEllipse(NativeRect rect, Graphics graphics, RenderMode renderMode, int lineThickness, Color lineColor, Color fillColor, bool shadow) { bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); // draw shadow before anything else @@ -101,7 +103,7 @@ namespace Greenshot.Editor.Drawing { Width = lineVisible ? lineThickness : 1 }; - Rectangle shadowRect = GuiRectangle.GetGuiRectangle(rect.Left + currentStep, rect.Top + currentStep, rect.Width, rect.Height); + var shadowRect = new NativeRect(rect.Left + currentStep, rect.Top + currentStep, rect.Width, rect.Height).Normalize(); graphics.DrawEllipse(shadowPen, shadowRect); currentStep++; alpha -= basealpha / steps; @@ -146,11 +148,11 @@ namespace Greenshot.Editor.Drawing { int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); return EllipseClickableAt(rect, lineThickness, fillColor, x, y); } - public static bool EllipseClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) + public static bool EllipseClickableAt(NativeRect rect, int lineThickness, Color fillColor, int x, int y) { // If we clicked inside the rectangle and it's visible we are clickable at. if (!Color.Transparent.Equals(fillColor)) diff --git a/src/Greenshot.Editor/Drawing/FilterContainer.cs b/src/Greenshot.Editor/Drawing/FilterContainer.cs index c6d1f8f26..4b846fe66 100644 --- a/src/Greenshot.Editor/Drawing/FilterContainer.cs +++ b/src/Greenshot.Editor/Drawing/FilterContainer.cs @@ -23,6 +23,8 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; @@ -79,38 +81,37 @@ namespace Greenshot.Editor.Drawing { int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - if (lineVisible) - { - graphics.SmoothingMode = SmoothingMode.HighSpeed; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.None; - //draw shadow first - if (shadow) - { - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = lineVisible ? 1 : 0; - while (currentStep <= steps) - { - using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); - Rectangle shadowRect = GuiRectangle.GetGuiRectangle(Left + currentStep, Top + currentStep, Width, Height); - graphics.DrawRectangle(shadowPen, shadowRect); - currentStep++; - alpha -= basealpha / steps; - } - } + if (!lineVisible) return; + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - if (lineThickness > 0) + graphics.SmoothingMode = SmoothingMode.HighSpeed; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.None; + //draw shadow first + if (shadow) + { + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = lineVisible ? 1 : 0; + while (currentStep <= steps) { - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawRectangle(pen, rect); + using Pen shadowPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); + var shadowRect = new NativeRect(Left + currentStep, Top + currentStep, Width, Height).Normalize(); + graphics.DrawRectangle(shadowPen, shadowRect); + currentStep++; + alpha -= basealpha / steps; } } + + if (lineThickness > 0) + { + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); + using Pen pen = new Pen(lineColor, lineThickness); + graphics.DrawRectangle(pen, rect); + } } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/Filters/AbstractFilter.cs b/src/Greenshot.Editor/Drawing/Filters/AbstractFilter.cs index 17517b971..c972ed77d 100644 --- a/src/Greenshot.Editor/Drawing/Filters/AbstractFilter.cs +++ b/src/Greenshot.Editor/Drawing/Filters/AbstractFilter.cs @@ -22,6 +22,7 @@ using System; using System.ComponentModel; using System.Drawing; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; @@ -73,7 +74,7 @@ namespace Greenshot.Editor.Drawing.Filters return parent; } - public abstract void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode); + public abstract void Apply(Graphics graphics, Bitmap applyBitmap, NativeRect rect, RenderMode renderMode); protected void OnPropertyChanged(string propertyName) { diff --git a/src/Greenshot.Editor/Drawing/Filters/BlurFilter.cs b/src/Greenshot.Editor/Drawing/Filters/BlurFilter.cs index ac0e26a64..010cfd2cb 100644 --- a/src/Greenshot.Editor/Drawing/Filters/BlurFilter.cs +++ b/src/Greenshot.Editor/Drawing/Filters/BlurFilter.cs @@ -22,9 +22,10 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Gdi32; using Greenshot.Base.Core; using Greenshot.Base.Interfaces.Drawing; -using Greenshot.Base.UnmanagedHelpers; using Greenshot.Editor.Drawing.Fields; namespace Greenshot.Editor.Drawing.Filters @@ -50,10 +51,10 @@ namespace Greenshot.Editor.Drawing.Filters AddField(GetType(), FieldType.PREVIEW_QUALITY, 1.0d); } - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + public override void Apply(Graphics graphics, Bitmap applyBitmap, NativeRect rect, RenderMode renderMode) { int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + var applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); if (applyRect.Width == 0 || applyRect.Height == 0) { return; @@ -66,9 +67,9 @@ namespace Greenshot.Editor.Drawing.Filters graphics.ExcludeClip(rect); } - if (GDIplus.IsBlurPossible(blurRadius)) + if (GdiPlusApi.IsBlurPossible(blurRadius)) { - GDIplus.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false); + GdiPlusApi.DrawWithBlur(graphics, applyBitmap, applyRect, null, null, blurRadius, false); } else { diff --git a/src/Greenshot.Editor/Drawing/Filters/BrightnessFilter.cs b/src/Greenshot.Editor/Drawing/Filters/BrightnessFilter.cs index cfdf7b025..639b0e5ac 100644 --- a/src/Greenshot.Editor/Drawing/Filters/BrightnessFilter.cs +++ b/src/Greenshot.Editor/Drawing/Filters/BrightnessFilter.cs @@ -23,6 +23,7 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; @@ -42,11 +43,11 @@ namespace Greenshot.Editor.Drawing.Filters ///
/// /// - /// + /// NativeRect /// - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + public override void Apply(Graphics graphics, Bitmap applyBitmap, NativeRect rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + var applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); if (applyRect.Width == 0 || applyRect.Height == 0) { diff --git a/src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs b/src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs index 5ed195fc7..441102980 100644 --- a/src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs +++ b/src/Greenshot.Editor/Drawing/Filters/GrayscaleFilter.cs @@ -23,13 +23,14 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Editor.Drawing.Filters { /// - /// Description of GrayscaleFilter. + /// GrayscaleFilter makes the image grey /// [Serializable()] public class GrayscaleFilter : AbstractFilter @@ -38,9 +39,9 @@ namespace Greenshot.Editor.Drawing.Filters { } - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + public override void Apply(Graphics graphics, Bitmap applyBitmap, NativeRect rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + var applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); if (applyRect.Width == 0 || applyRect.Height == 0) { diff --git a/src/Greenshot.Editor/Drawing/Filters/HighlightFilter.cs b/src/Greenshot.Editor/Drawing/Filters/HighlightFilter.cs index 32337fb98..24624d193 100644 --- a/src/Greenshot.Editor/Drawing/Filters/HighlightFilter.cs +++ b/src/Greenshot.Editor/Drawing/Filters/HighlightFilter.cs @@ -22,12 +22,16 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; namespace Greenshot.Editor.Drawing.Filters { + /// + /// This filter highlights an area + /// [Serializable()] public class HighlightFilter : AbstractFilter { @@ -41,11 +45,11 @@ namespace Greenshot.Editor.Drawing.Filters ///
/// /// - /// + /// NativeRect /// - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + public override void Apply(Graphics graphics, Bitmap applyBitmap, NativeRect rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + var applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); if (applyRect.Width == 0 || applyRect.Height == 0) { diff --git a/src/Greenshot.Editor/Drawing/Filters/IFilter.cs b/src/Greenshot.Editor/Drawing/Filters/IFilter.cs index 144732761..8c6d3d21d 100644 --- a/src/Greenshot.Editor/Drawing/Filters/IFilter.cs +++ b/src/Greenshot.Editor/Drawing/Filters/IFilter.cs @@ -21,6 +21,7 @@ using System.ComponentModel; using System.Drawing; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces.Drawing; namespace Greenshot.Editor.Drawing.Filters @@ -28,7 +29,7 @@ namespace Greenshot.Editor.Drawing.Filters public interface IFilter : INotifyPropertyChanged, IFieldHolder { DrawableContainer Parent { get; set; } - void Apply(Graphics graphics, Bitmap bmp, Rectangle rect, RenderMode renderMode); + void Apply(Graphics graphics, Bitmap bmp, NativeRect rect, RenderMode renderMode); DrawableContainer GetParent(); bool Invert { get; set; } } diff --git a/src/Greenshot.Editor/Drawing/Filters/MagnifierFilter.cs b/src/Greenshot.Editor/Drawing/Filters/MagnifierFilter.cs index f76640820..70d829a2e 100644 --- a/src/Greenshot.Editor/Drawing/Filters/MagnifierFilter.cs +++ b/src/Greenshot.Editor/Drawing/Filters/MagnifierFilter.cs @@ -22,12 +22,16 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; namespace Greenshot.Editor.Drawing.Filters { + /// + /// Magnify an area + /// [Serializable] public class MagnifierFilter : AbstractFilter { @@ -36,9 +40,9 @@ namespace Greenshot.Editor.Drawing.Filters AddField(GetType(), FieldType.MAGNIFICATION_FACTOR, 2); } - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + public override void Apply(Graphics graphics, Bitmap applyBitmap, NativeRect rect, RenderMode renderMode) { - Rectangle applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); + var applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); if (applyRect.Width == 0 || applyRect.Height == 0) { @@ -62,7 +66,7 @@ namespace Greenshot.Editor.Drawing.Filters int halfHeight = rect.Height / 2; int newWidth = rect.Width / magnificationFactor; int newHeight = rect.Height / magnificationFactor; - Rectangle source = new Rectangle(rect.X + halfWidth - newWidth / 2, rect.Y + halfHeight - newHeight / 2, newWidth, newHeight); + var source = new NativeRect(rect.X + halfWidth - newWidth / 2, rect.Y + halfHeight - newHeight / 2, newWidth, newHeight); graphics.DrawImage(applyBitmap, rect, source, GraphicsUnit.Pixel); graphics.Restore(state); } diff --git a/src/Greenshot.Editor/Drawing/Filters/PixelizationFilter.cs b/src/Greenshot.Editor/Drawing/Filters/PixelizationFilter.cs index d0b88d4f7..fa677b128 100644 --- a/src/Greenshot.Editor/Drawing/Filters/PixelizationFilter.cs +++ b/src/Greenshot.Editor/Drawing/Filters/PixelizationFilter.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; @@ -29,6 +30,9 @@ using Greenshot.Editor.Helpers; namespace Greenshot.Editor.Drawing.Filters { + /// + /// Pixelate an area + /// [Serializable()] public class PixelizationFilter : AbstractFilter { @@ -37,7 +41,7 @@ namespace Greenshot.Editor.Drawing.Filters AddField(GetType(), FieldType.PIXEL_SIZE, 5); } - public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) + public override void Apply(Graphics graphics, Bitmap applyBitmap, NativeRect rect, RenderMode renderMode) { int pixelSize = GetFieldValueAsInt(FieldType.PIXEL_SIZE); ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); diff --git a/src/Greenshot.Editor/Drawing/FreehandContainer.cs b/src/Greenshot.Editor/Drawing/FreehandContainer.cs index ef1c69ff3..b8a66be4e 100644 --- a/src/Greenshot.Editor/Drawing/FreehandContainer.cs +++ b/src/Greenshot.Editor/Drawing/FreehandContainer.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; @@ -43,8 +44,8 @@ namespace Greenshot.Editor.Drawing }; [NonSerialized] private GraphicsPath freehandPath = new GraphicsPath(); - private Rectangle myBounds = Rectangle.Empty; - private Point lastMouse = Point.Empty; + private NativeRect myBounds = NativeRect.Empty; + private NativePoint lastMouse = NativePoint.Empty; private readonly List capturePoints = new List(); private bool isRecalculated; @@ -256,26 +257,24 @@ namespace Greenshot.Editor.Drawing /// /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds... /// - public override Rectangle DrawingBounds + public override NativeRect DrawingBounds { get { if (!myBounds.IsEmpty) { int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS)); - int safetymargin = 10; - return new Rectangle(myBounds.Left + Left - (safetymargin + lineThickness), myBounds.Top + Top - (safetymargin + lineThickness), - myBounds.Width + 2 * (lineThickness + safetymargin), myBounds.Height + 2 * (lineThickness + safetymargin)); + int safetyMargin = 10; + return new NativeRect(myBounds.Left + Left - (safetyMargin + lineThickness), myBounds.Top + Top - (safetyMargin + lineThickness), + myBounds.Width + 2 * (lineThickness + safetyMargin), myBounds.Height + 2 * (lineThickness + safetyMargin)); } if (_parent?.Image is Image image) { - return new Rectangle(0, 0, image.Width, image.Height); - } - else - { - return Rectangle.Empty; + return new NativeRect(0, 0, image.Width, image.Height); } + + return NativeRect.Empty; } } diff --git a/src/Greenshot.Editor/Drawing/IconContainer.cs b/src/Greenshot.Editor/Drawing/IconContainer.cs index dd6668ce9..185c17cd2 100644 --- a/src/Greenshot.Editor/Drawing/IconContainer.cs +++ b/src/Greenshot.Editor/Drawing/IconContainer.cs @@ -24,6 +24,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.IO; using System.Runtime.Serialization; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using log4net; @@ -133,6 +134,6 @@ namespace Greenshot.Editor.Drawing public override bool HasDefaultSize => true; - public override Size DefaultSize => icon?.Size ?? new Size(16, 16); + public override NativeSize DefaultSize => icon?.Size ?? new NativeSize(16, 16); } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/ImageContainer.cs b/src/Greenshot.Editor/Drawing/ImageContainer.cs index 5def5578b..21f8d2fa6 100644 --- a/src/Greenshot.Editor/Drawing/ImageContainer.cs +++ b/src/Greenshot.Editor/Drawing/ImageContainer.cs @@ -24,6 +24,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.IO; using System.Runtime.Serialization; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Effects; using Greenshot.Base.Interfaces; @@ -53,7 +54,7 @@ namespace Greenshot.Editor.Drawing /// This is the offset for the shadow version of the bitmap /// Do not serialize, as the offset is recreated ///
- [NonSerialized] private Point _shadowOffset = new Point(-1, -1); + [NonSerialized] private NativePoint _shadowOffset = new NativePoint(-1, -1); public ImageContainer(ISurface parent, string filename) : this(parent) { @@ -264,6 +265,6 @@ namespace Greenshot.Editor.Drawing public override bool HasDefaultSize => true; - public override Size DefaultSize => _image?.Size ?? new Size(32, 32); + public override NativeSize DefaultSize => _image?.Size ?? new NativeSize(32, 32); } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/LineContainer.cs b/src/Greenshot.Editor/Drawing/LineContainer.cs index 729872be6..5029870a0 100644 --- a/src/Greenshot.Editor/Drawing/LineContainer.cs +++ b/src/Greenshot.Editor/Drawing/LineContainer.cs @@ -62,41 +62,40 @@ namespace Greenshot.Editor.Drawing public override void Draw(Graphics graphics, RenderMode rm) { + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + + if (lineThickness <= 0) return; graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.None; - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - - if (lineThickness > 0) + if (shadow) { - if (shadow) + //draw shadow first + int basealpha = 100; + int alpha = basealpha; + int steps = 5; + int currentStep = 1; + while (currentStep <= steps) { - //draw shadow first - int basealpha = 100; - int alpha = basealpha; - int steps = 5; - int currentStep = 1; - while (currentStep <= steps) - { - using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); - graphics.DrawLine(shadowCapPen, - Left + currentStep, - Top + currentStep, - Left + currentStep + Width, - Top + currentStep + Height); + using Pen shadowCapPen = new Pen(Color.FromArgb(alpha, 100, 100, 100), lineThickness); + graphics.DrawLine(shadowCapPen, + Left + currentStep, + Top + currentStep, + Left + currentStep + Width, + Top + currentStep + Height); - currentStep++; - alpha -= basealpha / steps; - } + currentStep++; + alpha -= basealpha / steps; } - - using Pen pen = new Pen(lineColor, lineThickness); - graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); } + + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + using Pen pen = new Pen(lineColor, lineThickness); + graphics.DrawLine(pen, Left, Top, Left + Width, Top + Height); } public override bool ClickableAt(int x, int y) diff --git a/src/Greenshot.Editor/Drawing/MetafileContainer.cs b/src/Greenshot.Editor/Drawing/MetafileContainer.cs index 4372ce24d..3225c4700 100644 --- a/src/Greenshot.Editor/Drawing/MetafileContainer.cs +++ b/src/Greenshot.Editor/Drawing/MetafileContainer.cs @@ -23,9 +23,9 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces; -using Svg; namespace Greenshot.Editor.Drawing { @@ -40,14 +40,14 @@ namespace Greenshot.Editor.Drawing public MetafileContainer(Metafile metafile, ISurface parent) : base(parent) { _metafile = metafile; - Size = new Size(metafile.Width/4, metafile.Height/4); + Size = new NativeSize(metafile.Width/4, metafile.Height/4); } protected override Image ComputeBitmap() { var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent); - var dstRect = new Rectangle(0, 0, Width, Height); + var dstRect = new NativeRect(0, 0, Width, Height); using (Graphics graphics = Graphics.FromImage(image)) { graphics.SmoothingMode = SmoothingMode.HighQuality; @@ -76,6 +76,6 @@ namespace Greenshot.Editor.Drawing public override bool HasDefaultSize => true; - public override Size DefaultSize => new Size(_metafile.Width, _metafile.Height); + public override NativeSize DefaultSize => new NativeSize(_metafile.Width, _metafile.Height); } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/RectangleContainer.cs b/src/Greenshot.Editor/Drawing/RectangleContainer.cs index 4dd6543a7..717e1a593 100644 --- a/src/Greenshot.Editor/Drawing/RectangleContainer.cs +++ b/src/Greenshot.Editor/Drawing/RectangleContainer.cs @@ -23,6 +23,8 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Runtime.Serialization; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; @@ -70,7 +72,7 @@ namespace Greenshot.Editor.Drawing Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR, Color.Red); Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR, Color.Transparent); bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); DrawRectangle(rect, graphics, rm, lineThickness, lineColor, fillColor, shadow); } @@ -78,14 +80,14 @@ namespace Greenshot.Editor.Drawing /// /// This method can also be used from other containers, if the right values are passed! /// - /// + /// NativeRect /// /// /// /// /// /// - public static void DrawRectangle(Rectangle rect, Graphics graphics, RenderMode rm, int lineThickness, Color lineColor, Color fillColor, bool shadow) + public static void DrawRectangle(NativeRect rect, Graphics graphics, RenderMode rm, int lineThickness, Color lineColor, Color fillColor, bool shadow) { graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; @@ -106,11 +108,11 @@ namespace Greenshot.Editor.Drawing { Width = lineVisible ? lineThickness : 1 }; - Rectangle shadowRect = GuiRectangle.GetGuiRectangle( + var shadowRect = new NativeRect( rect.Left + currentStep, rect.Top + currentStep, rect.Width, - rect.Height); + rect.Height).Normalize(); graphics.DrawRectangle(shadowPen, shadowRect); currentStep++; alpha -= basealpha / steps; @@ -134,15 +136,14 @@ namespace Greenshot.Editor.Drawing public override bool ClickableAt(int x, int y) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS) + 10; Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); return RectangleClickableAt(rect, lineThickness, fillColor, x, y); } - - public static bool RectangleClickableAt(Rectangle rect, int lineThickness, Color fillColor, int x, int y) + public static bool RectangleClickableAt(NativeRect rect, int lineThickness, Color fillColor, int x, int y) { // If we clicked inside the rectangle and it's visible we are clickable at. if (!Color.Transparent.Equals(fillColor)) diff --git a/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs b/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs index 0e60765e9..22dd13379 100644 --- a/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs +++ b/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs @@ -24,6 +24,8 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.Serialization; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; @@ -37,10 +39,10 @@ namespace Greenshot.Editor.Drawing [Serializable] public class SpeechbubbleContainer : TextContainer { - private Point _initialGripperPoint; + private NativePoint _initialGripperPoint; // Only used for serializing the TargetGripper location - private Point _storedTargetGripperLocation; + private NativePoint _storedTargetGripperLocation; /// /// Store the current location of the target gripper @@ -94,8 +96,8 @@ namespace Greenshot.Editor.Drawing { if (TargetAdorner == null) { - _initialGripperPoint = new Point(mouseX, mouseY); - InitTargetAdorner(new Point(mouseX, mouseY)); + _initialGripperPoint = new NativePoint(mouseX, mouseY); + InitTargetAdorner(_initialGripperPoint); } return base.HandleMouseDown(mouseX, mouseY); @@ -118,8 +120,7 @@ namespace Greenshot.Editor.Drawing int xOffset = leftAligned ? -20 : 20; int yOffset = topAligned ? -20 : 20; - Point newGripperLocation = _initialGripperPoint; - newGripperLocation.Offset(xOffset, yOffset); + NativePoint newGripperLocation = _initialGripperPoint.Offset(xOffset, yOffset); if (TargetAdorner.Location != newGripperLocation) { @@ -134,23 +135,27 @@ namespace Greenshot.Editor.Drawing /// /// The DrawingBound should be so close as possible to the shape, so we don't invalidate to much. /// - public override Rectangle DrawingBounds + public override NativeRect DrawingBounds { get { - if (Status != EditStatus.UNDRAWN) - { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - bool shadow = GetFieldValueAsBool(FieldType.SHADOW); - using Pen pen = new Pen(lineColor, lineThickness); - int inflateValue = lineThickness + 2 + (shadow ? 6 : 0); - using GraphicsPath tailPath = CreateTail(); - return Rectangle.Inflate(Rectangle.Union(Rectangle.Round(tailPath.GetBounds(new Matrix(), pen)), GuiRectangle.GetGuiRectangle(Left, Top, Width, Height)), - inflateValue, inflateValue); - } + if (Status == EditStatus.UNDRAWN) return NativeRect.Empty; + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + bool shadow = GetFieldValueAsBool(FieldType.SHADOW); + using Pen pen = new Pen(lineColor, lineThickness); + int inflateValue = lineThickness + 2 + (shadow ? 6 : 0); + using GraphicsPath tailPath = CreateTail(); + + var bubbleBounds = new NativeRect(Left, Top, Width, Height).Normalize(); + using var matrix = new Matrix(); + + var tailBounds = Rectangle.Round(tailPath.GetBounds(matrix, pen)); + + var drawingBoundsWithoutSafety = bubbleBounds.Union(tailBounds); + return drawingBoundsWithoutSafety.Inflate(inflateValue, inflateValue); - return Rectangle.Empty; } } @@ -162,9 +167,9 @@ namespace Greenshot.Editor.Drawing private GraphicsPath CreateBubble(int lineThickness) { GraphicsPath bubble = new GraphicsPath(); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); - Rectangle bubbleRect = GuiRectangle.GetGuiRectangle(0, 0, rect.Width, rect.Height); + var bubbleRect = new NativeRect(0, 0, rect.Width, rect.Height).Normalize(); // adapt corner radius to small rectangle dimensions int smallerSideLength = Math.Min(bubbleRect.Width, bubbleRect.Height); int cornerRadius = Math.Min(30, smallerSideLength / 2 - lineThickness); @@ -196,7 +201,7 @@ namespace Greenshot.Editor.Drawing /// private GraphicsPath CreateTail() { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); int tailLength = GeometryHelper.Distance2D(rect.Left + (rect.Width / 2), rect.Top + (rect.Height / 2), TargetAdorner.Location.X, TargetAdorner.Location.Y); int tailWidth = (Math.Abs(rect.Width) + Math.Abs(rect.Height)) / 20; @@ -246,7 +251,7 @@ namespace Greenshot.Editor.Drawing int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); bool lineVisible = lineThickness > 0 && Colors.IsVisible(lineColor); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); if (Selected && renderMode == RenderMode.EDIT) { diff --git a/src/Greenshot.Editor/Drawing/StepLabelContainer.cs b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs index c6812f12b..e5d93e514 100644 --- a/src/Greenshot.Editor/Drawing/StepLabelContainer.cs +++ b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs @@ -24,10 +24,11 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.Serialization; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; -using Greenshot.Editor.Helpers; namespace Greenshot.Editor.Drawing { @@ -116,7 +117,7 @@ namespace Greenshot.Editor.Drawing newParentSurface.AddStepLabel(this); } - public override Size DefaultSize => new Size(30, 30); + public override NativeSize DefaultSize => new NativeSize(30, 30); public override bool InitContent() { @@ -192,7 +193,7 @@ namespace Greenshot.Editor.Drawing graphics.PixelOffsetMode = PixelOffsetMode.None; graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; string text = ((Surface) Parent).CountStepLabels(this).ToString(); - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); if (_drawAsRectangle) @@ -212,7 +213,7 @@ namespace Greenshot.Editor.Drawing public override bool ClickableAt(int x, int y) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); Color fillColor = GetFieldValueAsColor(FieldType.FILL_COLOR); if (_drawAsRectangle) { diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index ead40e74f..399d60dad 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -29,6 +29,8 @@ using System.IO; using System.Linq; using System.Runtime.Serialization.Formatters.Binary; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Controls; using Greenshot.Base.Core; using Greenshot.Base.Effects; @@ -38,7 +40,6 @@ using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing.Adorners; using Greenshot.Editor.Configuration; using Greenshot.Editor.Drawing.Fields; -using Greenshot.Editor.Helpers; using Greenshot.Editor.Memento; using log4net; @@ -453,7 +454,7 @@ namespace Greenshot.Editor.Drawing /// Adjust UI elements to the supplied DPI settings /// /// - public void AdjustToDpi(uint dpi) + public void AdjustToDpi(int dpi) { foreach (var element in this._elements) { @@ -529,8 +530,8 @@ namespace Greenshot.Editor.Drawing // check if cursor is captured, and visible if (capture.Cursor != null && capture.CursorVisible) { - Rectangle cursorRect = new Rectangle(capture.CursorLocation, capture.Cursor.Size); - Rectangle captureRect = new Rectangle(Point.Empty, capture.Image.Size); + var cursorRect = new NativeRect(capture.CursorLocation, capture.Cursor.Size); + var captureRect = new NativeRect(NativePoint.Empty, capture.Image.Size); // check if cursor is on the capture, otherwise we leave it out. if (cursorRect.IntersectsWith(captureRect)) { @@ -939,7 +940,7 @@ namespace Greenshot.Editor.Drawing /// private void OnDragDrop(object sender, DragEventArgs e) { - Point mouse = PointToClient(new Point(e.X, e.Y)); + NativePoint mouse = PointToClient(new NativePoint(e.X, e.Y)); if (e.Data.GetDataPresent("Text")) { string possibleUrl = ClipboardHelper.GetText(e.Data); @@ -964,7 +965,7 @@ namespace Greenshot.Editor.Drawing drawableContainer.Top = mouse.Y; FitContainer(drawableContainer); AddElement(drawableContainer); - mouse.Offset(10, 10); + mouse = mouse.Offset(10, 10); } } @@ -973,11 +974,11 @@ namespace Greenshot.Editor.Drawing /// /// Auto crop the image /// - /// Rectangle with optional area to find a crop region + /// NativeRect with optional area to find a crop region /// true if cropped - public bool AutoCrop(Rectangle? cropArea = null) + public bool AutoCrop(NativeRect? cropArea = null) { - Rectangle cropRectangle; + NativeRect cropRectangle; using (Image tmpImage = GetImageForExport()) { cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, conf.AutoCropDifference, cropArea); @@ -1011,7 +1012,7 @@ namespace Greenshot.Editor.Drawing public void Clear(Color newColor) { //create a blank bitmap the same size as original - Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, Color.Empty); + Bitmap newBitmap = ImageHelper.CreateEmptyLike(Image, newColor); if (newBitmap == null) return; // Make undoable MakeUndoable(new SurfaceBackgroundChangeMemento(this, null), false); @@ -1030,7 +1031,7 @@ namespace Greenshot.Editor.Drawing Application.DoEvents(); try { - Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); + var imageRectangle = new NativeRect(NativePoint.Empty, Image.Size); Matrix matrix = new Matrix(); Image newImage = ImageHelper.ApplyEffect(Image, effect, matrix); if (newImage != null) @@ -1041,7 +1042,7 @@ namespace Greenshot.Editor.Drawing MakeUndoable(new SurfaceBackgroundChangeMemento(this, matrix), false); SetImage(newImage, false); Invalidate(); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new NativeRect(NativePoint.Empty, newImage.Size))) { _surfaceSizeChanged(this, null); } @@ -1065,28 +1066,28 @@ namespace Greenshot.Editor.Drawing /// Rectangle adapted to the dimensions of the image /// CropModes /// true if this is possible - public bool IsCropPossible(ref Rectangle cropRectangle, CropContainer.CropModes cropMode) + public bool IsCropPossible(ref NativeRect cropRectangle, CropContainer.CropModes cropMode) { - cropRectangle = GuiRectangle.GetGuiRectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height); + cropRectangle = new NativeRect(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, cropRectangle.Height).Normalize(); //Fitting the rectangle to the dimensions of the image if (cropRectangle.Left < 0) { - cropRectangle = new Rectangle(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); + cropRectangle = new NativeRect(0, cropRectangle.Top, cropRectangle.Width + cropRectangle.Left, cropRectangle.Height); } if (cropRectangle.Top < 0) { - cropRectangle = new Rectangle(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); + cropRectangle = new NativeRect(cropRectangle.Left, 0, cropRectangle.Width, cropRectangle.Height + cropRectangle.Top); } if (cropRectangle.Left + cropRectangle.Width > Image.Width) { - cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height); + cropRectangle = new NativeRect(cropRectangle.Left, cropRectangle.Top, Image.Width - cropRectangle.Left, cropRectangle.Height); } if (cropRectangle.Top + cropRectangle.Height > Image.Height) { - cropRectangle = new Rectangle(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top); + cropRectangle = new NativeRect(cropRectangle.Left, cropRectangle.Top, cropRectangle.Width, Image.Height - cropRectangle.Top); } // special condition for vertical @@ -1198,13 +1199,13 @@ namespace Greenshot.Editor.Drawing /// /// Crop the surface /// - /// rectangle that remains + /// NativeRect that remains /// bool - public bool ApplyCrop(Rectangle cropRectangle) + public bool ApplyCrop(NativeRect cropRectangle) { if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.Default)) return false; - Rectangle imageRectangle = new Rectangle(Point.Empty, Image.Size); + var imageRectangle = new NativeRect(NativePoint.Empty, Image.Size); Bitmap tmpImage; // Make sure we have information, this this fails try @@ -1228,7 +1229,7 @@ namespace Greenshot.Editor.Drawing // Do not dispose otherwise we can't undo the image! SetImage(tmpImage, false); _elements.Transform(matrix); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, tmpImage.Size))) + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new NativeRect(NativePoint.Empty, tmpImage.Size))) { _surfaceSizeChanged(this, null); } @@ -1241,15 +1242,15 @@ namespace Greenshot.Editor.Drawing /// Crop out the surface /// Splits the image in 3 parts(top, middle, bottom). Crop out the middle and joins top and bottom. ///
- /// rectangle of the middle part + /// NativeRect of the middle part /// bool - private bool ApplyHorizontalCrop(Rectangle cropRectangle) + private bool ApplyHorizontalCrop(NativeRect cropRectangle) { if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.Horizontal)) return false; - var imageRectangle = new Rectangle(Point.Empty, Image.Size); - var topRectangle = new Rectangle(0, 0, Image.Size.Width, cropRectangle.Top); - var bottomRectangle = new Rectangle(0, cropRectangle.Top + cropRectangle.Height, Image.Size.Width, Image.Size.Height - cropRectangle.Top - cropRectangle.Height); + var imageRectangle = new NativeRect(NativePoint.Empty, Image.Size); + var topRectangle = new NativeRect(0, 0, Image.Size.Width, cropRectangle.Top); + var bottomRectangle = new NativeRect(0, cropRectangle.Top + cropRectangle.Height, Image.Size.Width, Image.Size.Height - cropRectangle.Top - cropRectangle.Height); Bitmap newImage; try @@ -1261,12 +1262,12 @@ namespace Greenshot.Editor.Drawing var insertPositionTop = 0; if (topRectangle.Height > 0) { - graphics.DrawImage(Image, new Rectangle(0, insertPositionTop, topRectangle.Width, topRectangle.Height), topRectangle, GraphicsUnit.Pixel); + graphics.DrawImage(Image, new NativeRect(0, insertPositionTop, topRectangle.Width, topRectangle.Height), topRectangle, GraphicsUnit.Pixel); insertPositionTop += topRectangle.Height; } if (bottomRectangle.Height > 0) { - graphics.DrawImage(Image, new Rectangle(0, insertPositionTop, bottomRectangle.Width, bottomRectangle.Height), bottomRectangle, GraphicsUnit.Pixel); + graphics.DrawImage(Image, new NativeRect(0, insertPositionTop, bottomRectangle.Width, bottomRectangle.Height), bottomRectangle, GraphicsUnit.Pixel); } } catch (Exception ex) @@ -1286,7 +1287,7 @@ namespace Greenshot.Editor.Drawing SetImage(newImage, false); _elements.Transform(matrix); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new NativeRect(NativePoint.Empty, newImage.Size))) { _surfaceSizeChanged(this, null); } @@ -1299,15 +1300,15 @@ namespace Greenshot.Editor.Drawing /// Crop out the surface /// Splits the image in 3 parts(left, middle, right). Crop out the middle and joins top and bottom. ///
- /// rectangle of the middle part + /// NativeRect of the middle part /// bool - private bool ApplyVerticalCrop(Rectangle cropRectangle) + private bool ApplyVerticalCrop(NativeRect cropRectangle) { if (!IsCropPossible(ref cropRectangle, CropContainer.CropModes.Vertical)) return false; - var imageRectangle = new Rectangle(Point.Empty, Image.Size); - var leftRectangle = new Rectangle(0, 0, cropRectangle.Left, Image.Size.Height); - var rightRectangle = new Rectangle(cropRectangle.Left + cropRectangle.Width, 0, Image.Size.Width - cropRectangle.Width - cropRectangle.Left, Image.Size.Height); + var imageRectangle = new NativeRect(NativePoint.Empty, Image.Size); + var leftRectangle = new NativeRect(0, 0, cropRectangle.Left, Image.Size.Height); + var rightRectangle = new NativeRect(cropRectangle.Left + cropRectangle.Width, 0, Image.Size.Width - cropRectangle.Width - cropRectangle.Left, Image.Size.Height); Bitmap newImage; try { @@ -1318,13 +1319,13 @@ namespace Greenshot.Editor.Drawing var insertPositionLeft = 0; if (leftRectangle.Width > 0) { - graphics.DrawImage(Image, new Rectangle(insertPositionLeft, 0, leftRectangle.Width, leftRectangle.Height), leftRectangle , GraphicsUnit.Pixel); + graphics.DrawImage(Image, new NativeRect(insertPositionLeft, 0, leftRectangle.Width, leftRectangle.Height), leftRectangle , GraphicsUnit.Pixel); insertPositionLeft += leftRectangle.Width; } if (rightRectangle.Width > 0) { - graphics.DrawImage(Image, new Rectangle(insertPositionLeft, 0, rightRectangle.Width, rightRectangle.Height), rightRectangle, GraphicsUnit.Pixel); + graphics.DrawImage(Image, new NativeRect(insertPositionLeft, 0, rightRectangle.Width, rightRectangle.Height), rightRectangle, GraphicsUnit.Pixel); } } catch (Exception ex) @@ -1344,7 +1345,7 @@ namespace Greenshot.Editor.Drawing SetImage(newImage, false); _elements.Transform(matrix); - if (_surfaceSizeChanged != null && !imageRectangle.Equals(new Rectangle(Point.Empty, newImage.Size))) + if (_surfaceSizeChanged != null && !imageRectangle.Equals(new NativeRect(NativePoint.Empty, newImage.Size))) { _surfaceSizeChanged(this, null); } @@ -1707,9 +1708,9 @@ namespace Greenshot.Editor.Drawing return GetImage(RenderMode.EXPORT); } - private static Rectangle ZoomClipRectangle(Rectangle rc, double scale, int inflateAmount = 0) + private static NativeRect ZoomClipRectangle(NativeRect rc, double scale, int inflateAmount = 0) { - rc = new Rectangle( + rc = new NativeRect( (int) (rc.X * scale), (int) (rc.Y * scale), (int) (rc.Width * scale) + 1, @@ -1720,11 +1721,10 @@ namespace Greenshot.Editor.Drawing inflateAmount = (int) (inflateAmount * scale); } - rc.Inflate(inflateAmount, inflateAmount); - return rc; + return rc.Inflate(inflateAmount, inflateAmount); } - public void InvalidateElements(Rectangle rc) + public void InvalidateElements(NativeRect rc) => Invalidate(ZoomClipRectangle(rc, _zoomFactor, 1)); /// @@ -1735,8 +1735,8 @@ namespace Greenshot.Editor.Drawing private void SurfacePaint(object sender, PaintEventArgs paintEventArgs) { Graphics targetGraphics = paintEventArgs.Graphics; - Rectangle targetClipRectangle = paintEventArgs.ClipRectangle; - if (Rectangle.Empty.Equals(targetClipRectangle)) + NativeRect targetClipRectangle = paintEventArgs.ClipRectangle; + if (targetClipRectangle.IsEmpty) { LOG.Debug("Empty cliprectangle??"); return; @@ -1750,18 +1750,16 @@ namespace Greenshot.Editor.Drawing int verticalCorrection = targetClipRectangle.Top % (int) _zoomFactor.Numerator; if (horizontalCorrection != 0) { - targetClipRectangle.X -= horizontalCorrection; - targetClipRectangle.Width += horizontalCorrection; + targetClipRectangle = targetClipRectangle.ChangeX(-horizontalCorrection).ChangeWidth(horizontalCorrection); } if (verticalCorrection != 0) { - targetClipRectangle.Y -= verticalCorrection; - targetClipRectangle.Height += verticalCorrection; + targetClipRectangle = targetClipRectangle.ChangeY(-verticalCorrection).ChangeHeight(verticalCorrection); } } - Rectangle imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2); + NativeRect imageClipRectangle = ZoomClipRectangle(targetClipRectangle, _zoomFactor.Inverse(), 2); if (_elements.HasIntersectingFilters(imageClipRectangle) || _zoomFactor > Fraction.Identity) { @@ -1842,7 +1840,7 @@ namespace Greenshot.Editor.Drawing } } - private void DrawSmoothImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) + private void DrawSmoothImage(Graphics targetGraphics, Image image, NativeRect imageClipRectangle) { var state = targetGraphics.Save(); targetGraphics.SmoothingMode = SmoothingMode.HighQuality; @@ -1855,7 +1853,7 @@ namespace Greenshot.Editor.Drawing targetGraphics.Restore(state); } - private void DrawSharpImage(Graphics targetGraphics, Image image, Rectangle imageClipRectangle) + private void DrawSharpImage(Graphics targetGraphics, Image image, NativeRect imageClipRectangle) { var state = targetGraphics.Save(); targetGraphics.SmoothingMode = SmoothingMode.None; @@ -1868,7 +1866,7 @@ namespace Greenshot.Editor.Drawing targetGraphics.Restore(state); } - private void DrawBackground(Graphics targetGraphics, Rectangle clipRectangle) + private void DrawBackground(Graphics targetGraphics, NativeRect clipRectangle) { // check if we need to draw the checkerboard if (Image.IsAlphaPixelFormat(Image.PixelFormat) && _transparencyBackgroundBrush != null) @@ -2114,10 +2112,7 @@ namespace Greenshot.Editor.Drawing } // maybe the undo button has to be enabled - if (_movingElementChanged != null) - { - _movingElementChanged(this, new SurfaceElementEventArgs()); - } + _movingElementChanged?.Invoke(this, new SurfaceElementEventArgs()); } /// @@ -2152,10 +2147,7 @@ namespace Greenshot.Editor.Drawing DrawingMode = DrawingModes.None; // maybe the undo button has to be enabled - if (_movingElementChanged != null) - { - _movingElementChanged(this, new SurfaceElementEventArgs()); - } + _movingElementChanged?.Invoke(this, new SurfaceElementEventArgs()); } public void RemoveCropContainer() @@ -2197,34 +2189,33 @@ namespace Greenshot.Editor.Drawing // Make element(s) only move 10,10 if the surface is the same bool isSameSurface = (dcs.ParentID == _uniqueId); dcs.Parent = this; - var moveOffset = isSameSurface ? new Point(10, 10) : Point.Empty; + var moveOffset = isSameSurface ? new NativePoint(10, 10) : NativePoint.Empty; // Here a fix for bug #1475, first calculate the bounds of the complete IDrawableContainerList - Rectangle drawableContainerListBounds = Rectangle.Empty; + NativeRect drawableContainerListBounds = NativeRect.Empty; foreach (var element in dcs) { - drawableContainerListBounds = drawableContainerListBounds == Rectangle.Empty + drawableContainerListBounds = drawableContainerListBounds == NativeRect.Empty ? element.DrawingBounds - : Rectangle.Union(drawableContainerListBounds, element.DrawingBounds); + : drawableContainerListBounds.Union(element.DrawingBounds); } // And find a location inside the target surface to paste to bool containersCanFit = drawableContainerListBounds.Width < Bounds.Width && drawableContainerListBounds.Height < Bounds.Height; if (!containersCanFit) { - Point containersLocation = drawableContainerListBounds.Location; + NativePoint containersLocation = drawableContainerListBounds.Location; containersLocation.Offset(moveOffset); if (!Bounds.Contains(containersLocation)) { // Easy fix for same surface moveOffset = isSameSurface - ? new Point(-10, -10) - : new Point(-drawableContainerListBounds.Location.X + 10, -drawableContainerListBounds.Location.Y + 10); + ? new NativePoint(-10, -10) + : new NativePoint(-drawableContainerListBounds.Location.X + 10, -drawableContainerListBounds.Location.Y + 10); } } else { - Rectangle moveContainerListBounds = drawableContainerListBounds; - moveContainerListBounds.Offset(moveOffset); + NativeRect moveContainerListBounds = drawableContainerListBounds.Offset(moveOffset); // check if the element is inside if (!Bounds.Contains(moveContainerListBounds)) { @@ -2272,7 +2263,7 @@ namespace Greenshot.Editor.Drawing } else if (ClipboardHelper.ContainsImage(clipboard)) { - Point pasteLocation = GetPasteLocation(0.1f, 0.1f); + NativePoint pasteLocation = GetPasteLocation(0.1f, 0.1f); foreach (var drawableContainer in ClipboardHelper.GetDrawables(clipboard)) { @@ -2282,13 +2273,12 @@ namespace Greenshot.Editor.Drawing drawableContainer.Top = pasteLocation.Y; AddElement(drawableContainer); SelectElement(drawableContainer); - pasteLocation.X += 10; - pasteLocation.Y += 10; + pasteLocation = pasteLocation.Offset(10, 10); } } else if (ClipboardHelper.ContainsText(clipboard)) { - Point pasteLocation = GetPasteLocation(0.4f, 0.4f); + NativePoint pasteLocation = GetPasteLocation(0.4f, 0.4f); string text = ClipboardHelper.GetText(clipboard); if (text != null) @@ -2308,13 +2298,13 @@ namespace Greenshot.Editor.Drawing /// /// 0.0f for the left edge of visible area, 1.0f for the right edge of visible area. /// 0.0f for the top edge of visible area, 1.0f for the bottom edge of visible area. - private Point GetPasteLocation(float horizontalRatio = 0.5f, float verticalRatio = 0.5f) + private NativePoint GetPasteLocation(float horizontalRatio = 0.5f, float verticalRatio = 0.5f) { var point = PointToClient(MousePosition); var rc = GetVisibleRectangle(); if (!rc.Contains(point)) { - point = new Point( + point = new NativePoint( rc.Left + (int) (rc.Width * horizontalRatio), rc.Top + (int) (rc.Height * verticalRatio) ); @@ -2326,11 +2316,11 @@ namespace Greenshot.Editor.Drawing /// /// Get the rectangle bounding the part of this Surface currently visible in the editor (in surface coordinate space). /// - public Rectangle GetVisibleRectangle() + public NativeRect GetVisibleRectangle() { var bounds = Bounds; var clientArea = Parent.ClientRectangle; - return new Rectangle( + return new NativeRect( Math.Max(0, -bounds.Left), Math.Max(0, -bounds.Top), clientArea.Width, @@ -2342,7 +2332,7 @@ namespace Greenshot.Editor.Drawing /// Get the rectangle bounding all selected elements (in surface coordinates space), /// or empty rectangle if nothing is selected. /// - public Rectangle GetSelectionRectangle() + public NativeRect GetSelectionRectangle() => ToSurfaceCoordinates(selectedElements.DrawingBounds); /// @@ -2489,24 +2479,24 @@ namespace Greenshot.Editor.Drawing bool shiftModifier = (ModifierKeys & Keys.Shift) == Keys.Shift; int px = shiftModifier ? 10 : 1; - Point moveBy = Point.Empty; + NativePoint moveBy = NativePoint.Empty; switch (k) { case Keys.Left: case Keys.Left | Keys.Shift: - moveBy = new Point(-px, 0); + moveBy = new NativePoint(-px, 0); break; case Keys.Up: case Keys.Up | Keys.Shift: - moveBy = new Point(0, -px); + moveBy = new NativePoint(0, -px); break; case Keys.Right: case Keys.Right | Keys.Shift: - moveBy = new Point(px, 0); + moveBy = new NativePoint(px, 0); break; case Keys.Down: case Keys.Down | Keys.Shift: - moveBy = new Point(0, px); + moveBy = new NativePoint(0, px); break; case Keys.PageUp: PullElementsUp(); @@ -2584,7 +2574,7 @@ namespace Greenshot.Editor.Drawing return false; } - if (!Point.Empty.Equals(moveBy)) + if (moveBy != NativePoint.Empty) { selectedElements.MakeBoundsChangeUndoable(true); selectedElements.MoveBy(moveBy.X, moveBy.Y); @@ -2693,7 +2683,7 @@ namespace Greenshot.Editor.Drawing return _elements.Contains(container); } - public Point ToSurfaceCoordinates(Point point) + public NativePoint ToSurfaceCoordinates(NativePoint point) { Point[] points = { @@ -2703,29 +2693,27 @@ namespace Greenshot.Editor.Drawing return points[0]; } - public Rectangle ToSurfaceCoordinates(Rectangle rc) + public NativeRect ToSurfaceCoordinates(NativeRect rc) { if (_zoomMatrix.IsIdentity) { return rc; } - else + + Point[] points = { - Point[] points = - { - rc.Location, rc.Location + rc.Size - }; - _zoomMatrix.TransformPoints(points); - return new Rectangle( - points[0].X, - points[0].Y, - points[1].X - points[0].X, - points[1].Y - points[0].Y - ); - } + rc.Location, rc.Location.Offset(rc.Size.Width, rc.Size.Height) + }; + _zoomMatrix.TransformPoints(points); + return new NativeRect( + points[0].X, + points[0].Y, + points[1].X - points[0].X, + points[1].Y - points[0].Y + ); } - public Point ToImageCoordinates(Point point) + public NativePoint ToImageCoordinates(NativePoint point) { Point[] points = { @@ -2735,7 +2723,7 @@ namespace Greenshot.Editor.Drawing return points[0]; } - public Rectangle ToImageCoordinates(Rectangle rc) + public NativeRect ToImageCoordinates(NativeRect rc) { if (_inverseZoomMatrix.IsIdentity) { @@ -2744,10 +2732,10 @@ namespace Greenshot.Editor.Drawing Point[] points = { - rc.Location, rc.Location + rc.Size + rc.Location, rc.Location.Offset(rc.Size.Width, rc.Size.Height) }; _inverseZoomMatrix.TransformPoints(points); - return new Rectangle( + return new NativeRect( points[0].X, points[0].Y, points[1].X - points[0].X, diff --git a/src/Greenshot.Editor/Drawing/SvgContainer.cs b/src/Greenshot.Editor/Drawing/SvgContainer.cs index f98f03a32..283f755e8 100644 --- a/src/Greenshot.Editor/Drawing/SvgContainer.cs +++ b/src/Greenshot.Editor/Drawing/SvgContainer.cs @@ -21,6 +21,7 @@ using System; using System.Drawing; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces; using Svg; @@ -33,7 +34,7 @@ namespace Greenshot.Editor.Drawing [Serializable] public class SvgContainer : VectorGraphicsContainer { - private SvgDocument _svgDocument; + private readonly SvgDocument _svgDocument; public SvgContainer(SvgDocument svgDocument, ISurface parent) : base(parent) { @@ -56,6 +57,6 @@ namespace Greenshot.Editor.Drawing public override bool HasDefaultSize => true; - public override Size DefaultSize => new Size((int)_svgDocument.Width, (int)_svgDocument.Height); + public override NativeSize DefaultSize => new NativeSize((int)_svgDocument.Width, (int)_svgDocument.Height); } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/TextContainer.cs b/src/Greenshot.Editor/Drawing/TextContainer.cs index 5a1f755ef..a49fd4bee 100644 --- a/src/Greenshot.Editor/Drawing/TextContainer.cs +++ b/src/Greenshot.Editor/Drawing/TextContainer.cs @@ -27,11 +27,12 @@ using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.Serialization; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Editor.Drawing.Fields; -using Greenshot.Editor.Helpers; using Greenshot.Editor.Memento; namespace Greenshot.Editor.Drawing @@ -175,7 +176,7 @@ namespace Greenshot.Editor.Drawing UpdateTextBoxFont(); } - public override void ApplyBounds(RectangleF newBounds) + public override void ApplyBounds(NativeRectFloat newBounds) { base.ApplyBounds(newBounds); UpdateTextBoxPosition(); @@ -290,7 +291,7 @@ namespace Greenshot.Editor.Drawing }; _textBox.DataBindings.Add("Text", this, "Text", false, DataSourceUpdateMode.OnPropertyChanged); - _textBox.LostFocus += textBox_LostFocus; + _textBox.LostFocus += TextBox_LostFocus; _textBox.KeyDown += textBox_KeyDown; } @@ -341,7 +342,10 @@ namespace Greenshot.Editor.Drawing } InternalParent.KeysLocked = false; - InternalParent.Controls.Remove(_textBox); + if (_textBox != null) + { + InternalParent.Controls.Remove(_textBox); + } } /// @@ -350,12 +354,12 @@ namespace Greenshot.Editor.Drawing /// public override void Transform(Matrix matrix) { - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); int pixelsBefore = rect.Width * rect.Height; // Transform this container base.Transform(matrix); - rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + rect = new NativeRect(Left, Top, Width, Height).Normalize(); int pixelsAfter = rect.Width * rect.Height; float factor = pixelsAfter / (float) pixelsBefore; @@ -505,8 +509,8 @@ namespace Greenshot.Editor.Drawing correction = -1; } - Rectangle absRectangle = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - Rectangle displayRectangle = Parent.ToSurfaceCoordinates(absRectangle); + var absRectangle = new NativeRect(Left, Top, Width, Height).Normalize(); + var displayRectangle = Parent.ToSurfaceCoordinates(absRectangle); _textBox.Left = displayRectangle.X + lineWidth; _textBox.Top = displayRectangle.Y + lineWidth; if (lineThickness <= 1) @@ -581,7 +585,7 @@ namespace Greenshot.Editor.Drawing } } - private void textBox_LostFocus(object sender, EventArgs e) + private void TextBox_LostFocus(object sender, EventArgs e) { // next change will be made undoable makeUndoable = true; @@ -598,7 +602,7 @@ namespace Greenshot.Editor.Drawing graphics.PixelOffsetMode = PixelOffsetMode.None; graphics.TextRenderingHint = TextRenderingHint.SystemDefault; - Rectangle rect = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); + var rect = new NativeRect(Left, Top, Width, Height).Normalize(); if (Selected && rm == RenderMode.EDIT) { DrawSelectionBorder(graphics, rect); @@ -630,7 +634,7 @@ namespace Greenshot.Editor.Drawing /// /// /// - public static void DrawText(Graphics graphics, Rectangle drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text, + public static void DrawText(Graphics graphics, NativeRect drawingRectange, int lineThickness, Color fontColor, bool drawShadow, StringFormat stringFormat, string text, Font font) { #if DEBUG @@ -652,10 +656,10 @@ namespace Greenshot.Editor.Drawing while (currentStep <= steps) { int offset = currentStep; - Rectangle shadowRect = GuiRectangle.GetGuiRectangle(drawingRectange.Left + offset, drawingRectange.Top + offset, drawingRectange.Width, drawingRectange.Height); + NativeRect shadowRect = new NativeRect(drawingRectange.Left + offset, drawingRectange.Top + offset, drawingRectange.Width, drawingRectange.Height).Normalize(); if (lineThickness > 0) { - shadowRect.Inflate(-textOffset, -textOffset); + shadowRect = shadowRect.Inflate(-textOffset, -textOffset); } using Brush fontBrush = new SolidBrush(Color.FromArgb(alpha, 100, 100, 100)); graphics.DrawString(text, font, fontBrush, shadowRect, stringFormat); @@ -667,7 +671,7 @@ namespace Greenshot.Editor.Drawing if (lineThickness > 0) { - drawingRectange.Inflate(-textOffset, -textOffset); + drawingRectange = drawingRectange.Inflate(-textOffset, -textOffset); } using (Brush fontBrush = new SolidBrush(fontColor)) { @@ -684,8 +688,7 @@ namespace Greenshot.Editor.Drawing public override bool ClickableAt(int x, int y) { - Rectangle r = GuiRectangle.GetGuiRectangle(Left, Top, Width, Height); - r.Inflate(5, 5); + var r = new NativeRect(Left, Top, Width, Height).Normalize().Inflate(5, 5); return r.Contains(x, y); } } diff --git a/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs index 5061d7744..ad129c4ba 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs @@ -25,10 +25,12 @@ using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Gdi32.Enums; +using Dapplo.Windows.Gdi32.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; -using Greenshot.Base.UnmanagedHelpers; using log4net; namespace Greenshot.Editor.FileFormatHandlers @@ -63,27 +65,16 @@ namespace Greenshot.Editor.FileFormatHandlers { byte[] dibBuffer = new byte[stream.Length]; _ = stream.Read(dibBuffer, 0, dibBuffer.Length); - var infoHeader = BinaryStructHelper.FromByteArray(dibBuffer); + var infoHeader = BinaryStructHelper.FromByteArray(dibBuffer); if (!infoHeader.IsDibV5) { - Log.InfoFormat("Using special DIB (fullBmpSpan); + var bitmapInfoHeader = MemoryMarshal.Cast(fullBmpSpan); // Fill up the bitmap info header - bitmapInfoHeader[0].biSize = (uint)bitmapInfoHeaderSize; - bitmapInfoHeader[0].biWidth = sourceBitmap.Width; - bitmapInfoHeader[0].biHeight = sourceBitmap.Height; - bitmapInfoHeader[0].biPlanes = 1; - bitmapInfoHeader[0].biBitCount = 32; - bitmapInfoHeader[0].biCompression = BI_COMPRESSION.BI_BITFIELDS; - bitmapInfoHeader[0].biSizeImage = (uint)bitmapSize; - bitmapInfoHeader[0].biXPelsPerMeter = (int)(sourceBitmap.HorizontalResolution * DpiToPelsPerMeter); - bitmapInfoHeader[0].biYPelsPerMeter = (int)(sourceBitmap.VerticalResolution * DpiToPelsPerMeter); + bitmapInfoHeader[0].Size = (uint)bitmapInfoHeaderSize; + bitmapInfoHeader[0].Width = sourceBitmap.Width; + bitmapInfoHeader[0].Height = sourceBitmap.Height; + bitmapInfoHeader[0].Planes = 1; + bitmapInfoHeader[0].BitCount = 32; + bitmapInfoHeader[0].Compression = BitmapCompressionMethods.BI_BITFIELDS; + bitmapInfoHeader[0].SizeImage = (uint)bitmapSize; + bitmapInfoHeader[0].XPelsPerMeter = (int)(sourceBitmap.HorizontalResolution * DpiToPelsPerMeter); + bitmapInfoHeader[0].YPelsPerMeter = (int)(sourceBitmap.VerticalResolution * DpiToPelsPerMeter); // Specify the color masks applied to the Int32 pixel value to get the R, G and B values. - var rgbQuads = MemoryMarshal.Cast(fullBmpSpan.Slice(Marshal.SizeOf(typeof(BITMAPINFOHEADER)))); - rgbQuads[0].rgbRed = 255; - rgbQuads[1].rgbGreen = 255; - rgbQuads[2].rgbBlue = 255; + var rgbQuads = MemoryMarshal.Cast(fullBmpSpan.Slice(Marshal.SizeOf(typeof(BitmapInfoHeader)))); + rgbQuads[0].Red = 255; + rgbQuads[1].Green = 255; + rgbQuads[2].Blue = 255; // Now copy the lines, in reverse (bmp is upside down) to the byte array var sourceBitmapData = sourceBitmap.LockBits(area, ImageLockMode.ReadOnly, sourceBitmap.PixelFormat); diff --git a/src/Greenshot.Editor/Forms/ColorDialog.cs b/src/Greenshot.Editor/Forms/ColorDialog.cs index ce8dd4b4c..2a146012a 100644 --- a/src/Greenshot.Editor/Forms/ColorDialog.cs +++ b/src/Greenshot.Editor/Forms/ColorDialog.cs @@ -21,7 +21,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Drawing; using System.Globalization; using System.Threading; diff --git a/src/Greenshot.Editor/Forms/ColorPickerToolStripButton.cs b/src/Greenshot.Editor/Forms/ColorPickerToolStripButton.cs index 7a5123893..858be9c3a 100644 --- a/src/Greenshot.Editor/Forms/ColorPickerToolStripButton.cs +++ b/src/Greenshot.Editor/Forms/ColorPickerToolStripButton.cs @@ -20,10 +20,11 @@ */ using System; -using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; namespace Greenshot.Editor.Forms { @@ -32,7 +33,7 @@ namespace Greenshot.Editor.Forms public class ColorPickerToolStripButton : ToolStripButton { private Color _color; - public Point Offset = new Point(0, 0); + public NativePoint Offset = new NativePoint(0, 0); public event ColorPickerEventHandler ColorPicked; private readonly ColorDialog _cd; @@ -56,29 +57,24 @@ namespace Greenshot.Editor.Forms protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); - if (_color != null) + if (_color == null) return; + // replace transparent color with selected color + Graphics g = e.Graphics; + ColorMap[] colorMap = new ColorMap[1]; + colorMap[0] = new ColorMap { - // replace transparent color with selected color - Graphics g = e.Graphics; - //Graphics g = Graphics.FromImage(Image); - ColorMap[] colorMap = new ColorMap[1]; - colorMap[0] = new ColorMap - { - OldColor = Color.Magenta, //this.ImageTransparentColor; - NewColor = _color - }; - ImageAttributes attr = new ImageAttributes(); - attr.SetRemapTable(colorMap); - Rectangle rect = new Rectangle(0, 0, Image.Width, Image.Height); - // todo find a way to retrieve transparency offset automatically - // for now, we use the public variable Offset to define this manually - rect.Offset(Offset.X, Offset.Y); - //Image. - Debug.WriteLine("paint!" + Text + ": " + _color); - //ssif(color.Equals(Color.Transparent)) ((Bitmap)Image).MakeTransparent(Color.Magenta); - g.DrawImage(Image, rect, 0, 0, rect.Width, rect.Height, GraphicsUnit.Pixel, attr); - //this.Image.In - } + OldColor = Color.Magenta, //this.ImageTransparentColor; + NewColor = _color + }; + ImageAttributes attr = new ImageAttributes(); + attr.SetRemapTable(colorMap); + var rect = new NativeRect(0, 0, Image.Width, Image.Height); + // todo find a way to retrieve transparency offset automatically + // for now, we use the public variable Offset to define this manually + rect = rect.Offset(Offset.X, Offset.Y); + //ssif(color.Equals(Color.Transparent)) ((Bitmap)Image).MakeTransparent(Color.Magenta); + g.DrawImage(Image, rect, 0, 0, rect.Width, rect.Height, GraphicsUnit.Pixel, attr); + //this.Image.In } void ToolStripButton1Click(object sender, EventArgs e) diff --git a/src/Greenshot.Editor/Forms/DropShadowSettingsForm.cs b/src/Greenshot.Editor/Forms/DropShadowSettingsForm.cs index fcec47c95..c05852109 100644 --- a/src/Greenshot.Editor/Forms/DropShadowSettingsForm.cs +++ b/src/Greenshot.Editor/Forms/DropShadowSettingsForm.cs @@ -22,6 +22,7 @@ using System; using System.Drawing; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Effects; namespace Greenshot.Editor.Forms @@ -51,7 +52,7 @@ namespace Greenshot.Editor.Forms private void ButtonOK_Click(object sender, EventArgs e) { _effect.Darkness = trackBar1.Value / (float) 40; - _effect.ShadowOffset = new Point((int) offsetX.Value, (int) offsetY.Value); + _effect.ShadowOffset = new NativePoint((int) offsetX.Value, (int) offsetY.Value); _effect.ShadowSize = (int) thickness.Value; DialogResult = DialogResult.OK; } diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs index 90f62493e..c0a8f8a63 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.Designer.cs @@ -38,7 +38,6 @@ namespace Greenshot.Editor.Forms { protected override void Dispose(bool disposing) { if (disposing) { - DpiChanged -= AdjustToDpi; if (components != null) { components.Dispose(); } @@ -322,7 +321,7 @@ namespace Greenshot.Editor.Forms { // toolsToolStrip // this.toolsToolStrip.ClickThrough = true; - this.toolsToolStrip.ImageScalingSize = coreConfiguration.ScaledIconSize; + this.toolsToolStrip.ImageScalingSize = coreConfiguration.IconSize; this.toolsToolStrip.Dock = System.Windows.Forms.DockStyle.None; this.toolsToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; this.toolsToolStrip.Renderer = new CustomToolStripProfessionalRenderer(); @@ -558,7 +557,7 @@ namespace Greenshot.Editor.Forms { // menuStrip1 // this.menuStrip1.ClickThrough = true; - this.menuStrip1.ImageScalingSize = coreConfiguration.ScaledIconSize; + this.menuStrip1.ImageScalingSize = coreConfiguration.IconSize; this.menuStrip1.Dock = System.Windows.Forms.DockStyle.Fill; this.menuStrip1.Stretch = true; this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -876,7 +875,7 @@ namespace Greenshot.Editor.Forms { // destinationsToolStrip // this.destinationsToolStrip.ClickThrough = true; - this.destinationsToolStrip.ImageScalingSize = coreConfiguration.ScaledIconSize; + this.destinationsToolStrip.ImageScalingSize = coreConfiguration.IconSize; this.destinationsToolStrip.Dock = System.Windows.Forms.DockStyle.Fill; this.destinationsToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; this.destinationsToolStrip.Name = "toolStrip1"; @@ -1031,10 +1030,10 @@ namespace Greenshot.Editor.Forms { // propertiesToolStrip // this.propertiesToolStrip.ClickThrough = true; - this.propertiesToolStrip.ImageScalingSize = coreConfiguration.ScaledIconSize; + this.propertiesToolStrip.ImageScalingSize = coreConfiguration.IconSize; this.propertiesToolStrip.Dock = System.Windows.Forms.DockStyle.Fill; this.propertiesToolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; - this.propertiesToolStrip.MinimumSize = new System.Drawing.Size(150, coreConfiguration.ScaledIconSize.Height + 10); + this.propertiesToolStrip.MinimumSize = new System.Drawing.Size(150, coreConfiguration.IconSize.Height + 10); this.propertiesToolStrip.Name = "propertiesToolStrip"; this.propertiesToolStrip.Stretch = true; this.propertiesToolStrip.TabIndex = 2; @@ -2031,8 +2030,6 @@ namespace Greenshot.Editor.Forms { private NonJumpingPanel panel1; private ToolStripColorButton btnFillColor; private ToolStripColorButton btnLineColor; - private GreenshotToolStripMenuItem autoCropToolStripMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator17; private System.Windows.Forms.ContextMenuStrip zoomMenuStrip; private System.Windows.Forms.ToolStripMenuItem zoomInMenuItem; private System.Windows.Forms.ToolStripMenuItem zoomOutMenuItem; diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index 98a12a204..9c627accc 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -28,6 +28,12 @@ using System.IO; using System.Linq; using System.Threading; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Dpi; +using Dapplo.Windows.Kernel32; +using Dapplo.Windows.User32; +using Dapplo.Windows.User32.Structs; using Greenshot.Base; using Greenshot.Base.Controls; using Greenshot.Base.Core; @@ -37,8 +43,6 @@ using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Forms; -using Greenshot.Base.UnmanagedHelpers; -using Greenshot.Base.UnmanagedHelpers.Structs; using Greenshot.Editor.Configuration; using Greenshot.Editor.Destinations; using Greenshot.Editor.Drawing; @@ -50,7 +54,7 @@ using log4net; namespace Greenshot.Editor.Forms { /// - /// Description of ImageEditorForm. + /// The ImageEditorForm is the editor for Greenshot /// public partial class ImageEditorForm : EditorForm, IImageEditor { @@ -110,19 +114,17 @@ namespace Greenshot.Editor.Forms /// /// Adjust the icons etc to the supplied DPI settings /// - /// - /// DpiChangedEventArgs - private void AdjustToDpi(object sender, DpiChangedEventArgs dpiChangedEventArgs) + /// + /// + protected override void DpiChangedHandler(int oldDpi, int newDpi) { - var dpi = DpiHelper.GetDpi(Handle); - var newSize = DpiHelper.ScaleWithDpi(coreConfiguration.IconSize, dpi); + var newSize = DpiCalculator.ScaleWithDpi(coreConfiguration.IconSize, newDpi); toolsToolStrip.ImageScalingSize = newSize; menuStrip1.ImageScalingSize = newSize; destinationsToolStrip.ImageScalingSize = newSize; propertiesToolStrip.ImageScalingSize = newSize; propertiesToolStrip.MinimumSize = new Size(150, newSize.Height + 10); - - _surface?.AdjustToDpi(dpi); + _surface?.AdjustToDpi(newDpi); UpdateUi(); } @@ -148,7 +150,6 @@ namespace Greenshot.Editor.Forms ManualLanguageApply = true; InitializeComponent(); // Make sure we change the icon size depending on the scaling - DpiChanged += AdjustToDpi; Load += delegate { var thread = new Thread(AddDestinations) @@ -156,21 +157,19 @@ namespace Greenshot.Editor.Forms Name = "add destinations" }; thread.Start(); - - AdjustToDpi(null, null); }; // Make sure the editor is placed on the same location as the last editor was on close // But only if this still exists, else it will be reset (BUG-1812) WindowPlacement editorWindowPlacement = EditorConfiguration.GetEditorPlacement(); - Rectangle screenBounds = WindowCapture.GetScreenBounds(); + NativeRect screenBounds = DisplayInfo.ScreenBounds; if (!screenBounds.Contains(editorWindowPlacement.NormalPosition)) { EditorConfiguration.ResetEditorPlacement(); } // ReSharper disable once UnusedVariable - WindowDetails thisForm = new WindowDetails(Handle) + WindowDetails thisForm = new(Handle) { WindowPlacement = EditorConfiguration.GetEditorPlacement() }; @@ -313,9 +312,8 @@ namespace Greenshot.Editor.Forms // Loop over all items in the propertiesToolStrip foreach (ToolStripItem item in propertiesToolStrip.Items) { - var cb = item as ToolStripComboBox; // Only ToolStripComboBox that are visible - if (cb == null || !cb.Visible) + if (item is not ToolStripComboBox { Visible: true } cb) { continue; } @@ -323,7 +321,7 @@ namespace Greenshot.Editor.Forms if (cb.ComboBox == null) continue; // Calculate the rectangle - Rectangle r = new Rectangle(cb.ComboBox.Location.X - 1, cb.ComboBox.Location.Y - 1, cb.ComboBox.Size.Width + 1, cb.ComboBox.Size.Height + 1); + var r = new NativeRect(cb.ComboBox.Location.X - 1, cb.ComboBox.Location.Y - 1, cb.ComboBox.Size.Width + 1, cb.ComboBox.Size.Height + 1); // Draw the rectangle e.Graphics.DrawRectangle(cbBorderPen, r); @@ -372,7 +370,7 @@ namespace Greenshot.Editor.Forms { if (toolstripDestination.IsDynamic) { - ToolStripSplitButton destinationButton = new ToolStripSplitButton + ToolStripSplitButton destinationButton = new() { DisplayStyle = ToolStripItemDisplayStyle.Image, Size = new Size(23, 22), @@ -976,7 +974,7 @@ namespace Greenshot.Editor.Forms GC.Collect(); if (coreConfiguration.MinimizeWorkingSetSize) { - PsAPI.EmptyWorkingSet(); + PsApi.EmptyWorkingSet(); } } @@ -1701,7 +1699,7 @@ namespace Greenshot.Editor.Forms /// private void ShrinkCanvasToolStripMenuItemClick(object sender, EventArgs e) { - Rectangle cropRectangle; + NativeRect cropRectangle; using (Image tmpImage = GetImageForExport()) { cropRectangle = ImageHelper.FindAutoCropRectangle(tmpImage, coreConfiguration.AutoCropDifference); @@ -1956,8 +1954,7 @@ namespace Greenshot.Editor.Forms private void ZoomSetValue(Fraction value) { var surface = Surface as Surface; - var panel = surface?.Parent as Panel; - if (panel == null) + if (surface?.Parent is not Panel panel) { return; } @@ -1972,9 +1969,8 @@ namespace Greenshot.Editor.Forms var size = surface.Size; if (value > Surface.ZoomFactor) // being smart on zoom-in { - var selection = surface.GetSelectionRectangle(); - selection.Intersect(rc); - if (selection != Rectangle.Empty) + var selection = surface.GetSelectionRectangle().Intersect(rc); + if (selection != NativeRect.Empty) { rc = selection; // zoom to visible part of selection } @@ -1984,12 +1980,12 @@ namespace Greenshot.Editor.Forms // - prefer top left corner to zoom-in as less disorienting for screenshots if (size.Width < rc.Width) { - rc.Width = 0; + rc = rc.ChangeWidth(0); } if (size.Height < rc.Height) { - rc.Height = 0; + rc = rc.ChangeHeight(0); } } } diff --git a/src/Greenshot.Editor/Forms/MovableShowColorForm.cs b/src/Greenshot.Editor/Forms/MovableShowColorForm.cs index fb7962a91..416ec6407 100644 --- a/src/Greenshot.Editor/Forms/MovableShowColorForm.cs +++ b/src/Greenshot.Editor/Forms/MovableShowColorForm.cs @@ -22,7 +22,11 @@ using System; using System.Drawing; using System.Windows.Forms; -using Greenshot.Base.UnmanagedHelpers; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Gdi32; +using Dapplo.Windows.Gdi32.SafeHandles; +using Dapplo.Windows.User32; namespace Greenshot.Editor.Forms { @@ -32,7 +36,7 @@ namespace Greenshot.Editor.Forms /// public partial class MovableShowColorForm : Form { - public Color color + public Color Color { get { return preview.BackColor; } } @@ -45,8 +49,8 @@ namespace Greenshot.Editor.Forms /// /// Move the MovableShowColorForm to the specified location and display the color under the (current mouse) coordinates /// - /// Coordinates - public void MoveTo(Point screenCoordinates) + /// NativePoint with Coordinates + public void MoveTo(NativePoint screenCoordinates) { Color c = GetPixelColor(screenCoordinates); preview.BackColor = c; @@ -56,38 +60,36 @@ namespace Greenshot.Editor.Forms green.Text = string.Empty + c.G; alpha.Text = string.Empty + c.A; - Size cursorSize = Cursor.Current.Size; - Point hotspot = Cursor.Current.HotSpot; + NativeSize cursorSize = Cursor.Current.Size; + NativePoint hotspot = Cursor.Current.HotSpot; - Point zoomerLocation = new Point(screenCoordinates.X, screenCoordinates.Y); - zoomerLocation.X += cursorSize.Width + 5 - hotspot.X; - zoomerLocation.Y += cursorSize.Height + 5 - hotspot.Y; + var zoomerLocation = new NativePoint(screenCoordinates.X, screenCoordinates.Y) + .Offset(cursorSize.Width + 5 - hotspot.X, cursorSize.Height + 5 - hotspot.Y); - foreach (Screen screen in Screen.AllScreens) + foreach (var displayInfo in DisplayInfo.AllDisplayInfos) { - Rectangle screenRectangle = screen.Bounds; - if (screen.Bounds.Contains(screenCoordinates)) + NativeRect screenRectangle = displayInfo.Bounds; + if (!displayInfo.Bounds.Contains(screenCoordinates)) continue; + + if (zoomerLocation.X < screenRectangle.X) { - if (zoomerLocation.X < screenRectangle.X) - { - zoomerLocation.X = screenRectangle.X; - } - else if (zoomerLocation.X + Width > screenRectangle.X + screenRectangle.Width) - { - zoomerLocation.X = screenCoordinates.X - Width - 5 - hotspot.X; - } - - if (zoomerLocation.Y < screenRectangle.Y) - { - zoomerLocation.Y = screenRectangle.Y; - } - else if (zoomerLocation.Y + Height > screenRectangle.Y + screenRectangle.Height) - { - zoomerLocation.Y = screenCoordinates.Y - Height - 5 - hotspot.Y; - } - - break; + zoomerLocation = zoomerLocation.ChangeX(screenRectangle.X); } + else if (zoomerLocation.X + Width > screenRectangle.X + screenRectangle.Width) + { + zoomerLocation = zoomerLocation.ChangeX(screenCoordinates.X - Width - 5 - hotspot.X); + } + + if (zoomerLocation.Y < screenRectangle.Y) + { + zoomerLocation = zoomerLocation.ChangeY(screenRectangle.Y); + } + else if (zoomerLocation.Y + Height > screenRectangle.Y + screenRectangle.Height) + { + zoomerLocation = zoomerLocation.ChangeY(screenCoordinates.Y - Height - 5 - hotspot.Y); + } + + break; } Location = zoomerLocation; @@ -97,14 +99,14 @@ namespace Greenshot.Editor.Forms /// /// Get the color from the pixel on the screen at "x,y" /// - /// Point with the coordinates + /// NativePoint with the coordinates /// Color at the specified screenCoordinates - private static Color GetPixelColor(Point screenCoordinates) + private static Color GetPixelColor(NativePoint screenCoordinates) { - using SafeWindowDcHandle screenDC = SafeWindowDcHandle.FromDesktop(); + using SafeWindowDcHandle safeWindowDcHandle = SafeWindowDcHandle.FromDesktop(); try { - uint pixel = GDI32.GetPixel(screenDC, screenCoordinates.X, screenCoordinates.Y); + uint pixel = Gdi32Api.GetPixel(safeWindowDcHandle, screenCoordinates.X, screenCoordinates.Y); Color color = Color.FromArgb(255, (int) (pixel & 0xFF), (int) (pixel & 0xFF00) >> 8, (int) (pixel & 0xFF0000) >> 16); return color; } diff --git a/src/Greenshot.Editor/Forms/TornEdgeSettingsForm.cs b/src/Greenshot.Editor/Forms/TornEdgeSettingsForm.cs index db29c227f..46638fc6e 100644 --- a/src/Greenshot.Editor/Forms/TornEdgeSettingsForm.cs +++ b/src/Greenshot.Editor/Forms/TornEdgeSettingsForm.cs @@ -20,8 +20,8 @@ */ using System; -using System.Drawing; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Effects; namespace Greenshot.Editor.Forms @@ -56,7 +56,7 @@ namespace Greenshot.Editor.Forms private void ButtonOK_Click(object sender, EventArgs e) { _effect.Darkness = shadowDarkness.Value / (float) 40; - _effect.ShadowOffset = new Point((int) offsetX.Value, (int) offsetY.Value); + _effect.ShadowOffset = new NativePoint((int) offsetX.Value, (int) offsetY.Value); _effect.ShadowSize = (int) thickness.Value; _effect.ToothHeight = (int) toothsize.Value; _effect.VerticalToothRange = (int) verticaltoothrange.Value; diff --git a/src/Greenshot.Editor/Helpers/GuiRectangle.cs b/src/Greenshot.Editor/Helpers/GuiRectangle.cs deleted file mode 100644 index d5855afb5..000000000 --- a/src/Greenshot.Editor/Helpers/GuiRectangle.cs +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System.Drawing; - -namespace Greenshot.Editor.Helpers -{ - /// - /// Helper class for creating rectangles with positive dimensions, regardless of input coordinates - /// - public static class GuiRectangle - { - public static Rectangle GetGuiRectangle(int x, int y, int w, int h) - { - var rect = new Rectangle(x, y, w, h); - MakeGuiRectangle(ref rect); - return rect; - } - - public static void MakeGuiRectangle(ref Rectangle rect) - { - if (rect.Width < 0) - { - rect.X += rect.Width; - rect.Width = -rect.Width; - } - - if (rect.Height < 0) - { - rect.Y += rect.Height; - rect.Height = -rect.Height; - } - } - } -} \ No newline at end of file diff --git a/src/Greenshot.Editor/Helpers/ScaleHelper.cs b/src/Greenshot.Editor/Helpers/ScaleHelper.cs index 423fdf075..b75e8caad 100644 --- a/src/Greenshot.Editor/Helpers/ScaleHelper.cs +++ b/src/Greenshot.Editor/Helpers/ScaleHelper.cs @@ -22,6 +22,8 @@ using System; using System.Drawing; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Editor.Drawing; namespace Greenshot.Editor.Helpers @@ -118,7 +120,7 @@ namespace Greenshot.Editor.Helpers /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT /// coordinates of the used handle/gripper /// ScaleOptions to use when scaling - public static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords, ScaleOptions? options) + public static void Scale(ref NativeRectFloat originalRectangle, Positions resizeHandlePosition, NativePointFloat resizeHandleCoords, ScaleOptions? options) { options ??= GetScaleOptions(); @@ -135,8 +137,7 @@ namespace Greenshot.Editor.Helpers // scale rectangle using handle coordinates Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); // mirror handle coordinates via rectangle center coordinates - resizeHandleCoords.X -= 2 * (resizeHandleCoords.X - rectCenterX); - resizeHandleCoords.Y -= 2 * (resizeHandleCoords.Y - rectCenterY); + resizeHandleCoords = resizeHandleCoords.Offset(-2 * (resizeHandleCoords.X - rectCenterX), -2 * (resizeHandleCoords.Y - rectCenterY)); // scale again with opposing handle and mirrored coordinates resizeHandlePosition = (Positions) ((((int) resizeHandlePosition) + 4) % 8); Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); @@ -153,50 +154,72 @@ namespace Greenshot.Editor.Helpers /// bounds of the current rectangle, scaled values will be written to this reference /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT /// coordinates of the used handle/gripper - private static void Scale(ref RectangleF originalRectangle, Positions resizeHandlePosition, PointF resizeHandleCoords) + private static void Scale(ref NativeRectFloat originalRectangle, Positions resizeHandlePosition, NativePointFloat resizeHandleCoords) { switch (resizeHandlePosition) { case Positions.TopLeft: - originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; - originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; - originalRectangle.X = resizeHandleCoords.X; - originalRectangle.Y = resizeHandleCoords.Y; + originalRectangle = new NativeRectFloat( + resizeHandleCoords.X, + resizeHandleCoords.Y, + originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X, + originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y); break; case Positions.TopCenter: - originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; - originalRectangle.Y = resizeHandleCoords.Y; + originalRectangle = new NativeRectFloat( + originalRectangle.X, + resizeHandleCoords.Y, + originalRectangle.Width, + originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y); break; case Positions.TopRight: - originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; - originalRectangle.Height = originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y; - originalRectangle.Y = resizeHandleCoords.Y; + originalRectangle = new NativeRectFloat( + originalRectangle.X, + resizeHandleCoords.Y, + resizeHandleCoords.X - originalRectangle.Left, + originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y); break; case Positions.MiddleLeft: - originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; - originalRectangle.X = resizeHandleCoords.X; + originalRectangle = new NativeRectFloat( + resizeHandleCoords.X, + originalRectangle.Y, + originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X, + originalRectangle.Height); break; case Positions.MiddleRight: - originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; + originalRectangle = new NativeRectFloat( + originalRectangle.X, + originalRectangle.Y, + resizeHandleCoords.X - originalRectangle.Left, + originalRectangle.Height); break; case Positions.BottomLeft: - originalRectangle.Width = originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X; - originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; - originalRectangle.X = resizeHandleCoords.X; + originalRectangle = new NativeRectFloat( + resizeHandleCoords.X, + originalRectangle.Y, + originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X, + resizeHandleCoords.Y - originalRectangle.Top); break; case Positions.BottomCenter: - originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + originalRectangle = new NativeRectFloat( + originalRectangle.X, + originalRectangle.Y, + originalRectangle.Width, + resizeHandleCoords.Y - originalRectangle.Top); break; case Positions.BottomRight: - originalRectangle.Width = resizeHandleCoords.X - originalRectangle.Left; - originalRectangle.Height = resizeHandleCoords.Y - originalRectangle.Top; + originalRectangle = new NativeRectFloat( + originalRectangle.X, + originalRectangle.Y, + resizeHandleCoords.X - originalRectangle.Left, + resizeHandleCoords.Y - originalRectangle.Top); break; default: @@ -213,7 +236,7 @@ namespace Greenshot.Editor.Helpers /// bounds of the current rectangle /// position of the handle/gripper being used for resized, see Position /// coordinates of the used handle/gripper, adjusted coordinates will be written to this reference - private static void AdjustCoordsForRationalScale(RectangleF originalRectangle, Positions resizeHandlePosition, ref PointF resizeHandleCoords) + private static void AdjustCoordsForRationalScale(NativeRectFloat originalRectangle, Positions resizeHandlePosition, ref NativePointFloat resizeHandleCoords) { SizeF selectedRectangle, newSize; @@ -222,29 +245,25 @@ namespace Greenshot.Editor.Helpers case Positions.TopLeft: selectedRectangle = new SizeF(originalRectangle.Right - resizeHandleCoords.X, originalRectangle.Bottom - resizeHandleCoords.Y); newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); - resizeHandleCoords.X = originalRectangle.Right - newSize.Width; - resizeHandleCoords.Y = originalRectangle.Bottom - newSize.Height; + resizeHandleCoords = new NativePointFloat(originalRectangle.Right - newSize.Width, originalRectangle.Bottom - newSize.Height); break; case Positions.TopRight: selectedRectangle = new SizeF(resizeHandleCoords.X - originalRectangle.Left, originalRectangle.Bottom - resizeHandleCoords.Y); newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); - resizeHandleCoords.X = originalRectangle.Left + newSize.Width; - resizeHandleCoords.Y = originalRectangle.Bottom - newSize.Height; + resizeHandleCoords = new NativePointFloat(originalRectangle.Left + newSize.Width, originalRectangle.Bottom - newSize.Height); break; case Positions.BottomLeft: selectedRectangle = new SizeF(originalRectangle.Right - resizeHandleCoords.X, resizeHandleCoords.Y - originalRectangle.Top); newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); - resizeHandleCoords.X = originalRectangle.Right - newSize.Width; - resizeHandleCoords.Y = originalRectangle.Top + newSize.Height; + resizeHandleCoords = new NativePointFloat(originalRectangle.Right - newSize.Width, originalRectangle.Top + newSize.Height); break; case Positions.BottomRight: selectedRectangle = new SizeF(resizeHandleCoords.X - originalRectangle.Left, resizeHandleCoords.Y - originalRectangle.Top); newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); - resizeHandleCoords.X = originalRectangle.Left + newSize.Width; - resizeHandleCoords.Y = originalRectangle.Top + newSize.Height; + resizeHandleCoords = new NativePointFloat(originalRectangle.Left + newSize.Width, originalRectangle.Top + newSize.Height); break; } } @@ -254,12 +273,12 @@ namespace Greenshot.Editor.Helpers /// * has the same aspect ratio as the original /// * fits into selected size /// - /// size to be considered for keeping aspect ratio - /// selection size (i.e. the size we'd produce if we wouldn't keep aspect ratio) + /// NativeSizeFloat to be considered for keeping aspect ratio + /// NativeSizeFloat selection size (i.e. the size we'd produce if we wouldn't keep aspect ratio) /// - private static SizeF GetNewSizeForRationalScale(SizeF originalSize, SizeF selectedSize) + private static NativeSizeFloat GetNewSizeForRationalScale(NativeSizeFloat originalSize, NativeSizeFloat selectedSize) { - SizeF newSize = selectedSize; + NativeSizeFloat newSize = selectedSize; float originalRatio = originalSize.Width / originalSize.Height; float selectedRatio = selectedSize.Width / selectedSize.Height; // will fix orientation if the scaling causes size to be flipped in any direction @@ -268,29 +287,29 @@ namespace Greenshot.Editor.Helpers { // scaled rectangle (ratio) would be wider than original // keep height and tweak width to maintain aspect ratio - newSize.Width = selectedSize.Height * originalRatio * flippedRatioSign; + newSize = newSize.ChangeWidth(selectedSize.Height * originalRatio * flippedRatioSign); } else if (Math.Abs(selectedRatio) < Math.Abs(originalRatio)) { // scaled rectangle (ratio) would be taller than original // keep width and tweak height to maintain aspect ratio - newSize.Height = selectedSize.Width / originalRatio * flippedRatioSign; + newSize = newSize.ChangeWidth(selectedSize.Width / originalRatio * flippedRatioSign); } return newSize; } - public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize) + public static void Scale(NativeRect boundsBeforeResize, int cursorX, int cursorY, ref NativeRectFloat boundsAfterResize) { Scale(boundsBeforeResize, cursorX, cursorY, ref boundsAfterResize, null); } - public static void Scale(Rectangle boundsBeforeResize, int cursorX, int cursorY, ref RectangleF boundsAfterResize, IDoubleProcessor angleRoundBehavior) + public static void Scale(NativeRect boundsBeforeResize, int cursorX, int cursorY, ref NativeRectFloat boundsAfterResize, IDoubleProcessor angleRoundBehavior) { Scale(boundsBeforeResize, Positions.TopLeft, cursorX, cursorY, ref boundsAfterResize, angleRoundBehavior); } - public static void Scale(Rectangle boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, ref RectangleF boundsAfterResize, + public static void Scale(NativeRect boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, ref NativeRectFloat boundsAfterResize, IDoubleProcessor angleRoundBehavior) { ScaleOptions opts = GetScaleOptions(); @@ -309,18 +328,16 @@ namespace Greenshot.Editor.Helpers int dist = GeometryHelper.Distance2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); - boundsAfterResize.Width = (int) Math.Round(dist * Math.Cos(angle / 180 * Math.PI)); - boundsAfterResize.Height = (int) Math.Round(dist * Math.Sin(angle / 180 * Math.PI)); + boundsAfterResize = boundsAfterResize + .ChangeWidth((int)Math.Round(dist * Math.Cos(angle / 180 * Math.PI))) + .ChangeHeight((int) Math.Round(dist * Math.Sin(angle / 180 * Math.PI))); } if (centeredScale) { float wdiff = boundsAfterResize.Width - boundsBeforeResize.Width; float hdiff = boundsAfterResize.Height - boundsBeforeResize.Height; - boundsAfterResize.Width += wdiff; - boundsAfterResize.Height += hdiff; - boundsAfterResize.X -= wdiff; - boundsAfterResize.Y -= hdiff; + boundsAfterResize = boundsAfterResize.Inflate(wdiff, hdiff); } } diff --git a/src/Greenshot.Plugin.Box/BoxConfiguration.cs b/src/Greenshot.Plugin.Box/BoxConfiguration.cs index 34ae4afc9..fdef95ae5 100644 --- a/src/Greenshot.Plugin.Box/BoxConfiguration.cs +++ b/src/Greenshot.Plugin.Box/BoxConfiguration.cs @@ -21,7 +21,6 @@ using System; using System.Windows.Forms; -using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Plugin.Box.Forms; diff --git a/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs index f2212126d..8176ebe6e 100644 --- a/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs +++ b/src/Greenshot.Plugin.Confluence/ConfluenceConfiguration.cs @@ -20,7 +20,6 @@ */ using System; -using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; diff --git a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs index 8eedbf768..e4f602796 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs @@ -20,7 +20,6 @@ */ using System.Windows.Forms; -using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Plugin.Flickr.Forms; diff --git a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs index 1939fba22..dcad49473 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrPlugin.cs @@ -30,7 +30,6 @@ using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; using log4net; -using log4net.Config; namespace Greenshot.Plugin.Flickr { diff --git a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs index 91892f136..5765544b9 100644 --- a/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs +++ b/src/Greenshot.Plugin.GooglePhotos/GooglePhotosConfiguration.cs @@ -20,7 +20,6 @@ using System; using System.Windows.Forms; -using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Plugin.GooglePhotos.Forms; diff --git a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs index 7635ee3de..3bb695672 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs @@ -22,7 +22,6 @@ using System; using System.Collections.Generic; using System.Windows.Forms; -using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Plugin.Imgur.Forms; diff --git a/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs index 5830eb1dc..29b75e9bb 100644 --- a/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs +++ b/src/Greenshot.Plugin.Jira/Forms/JiraForm.cs @@ -26,6 +26,7 @@ using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; using Dapplo.Jira.Entities; +using Dapplo.Windows.Dpi; using Greenshot.Base.Controls; using Greenshot.Base.Core; using Greenshot.Base.IniFile; @@ -173,7 +174,7 @@ namespace Greenshot.Plugin.Jira.Forms jiraListView.Columns.Add(translation); } - var scaledIconSize = DpiHelper.ScaleWithDpi(CoreConfig.IconSize, DpiHelper.GetDpi(Handle)); + var scaledIconSize = DpiCalculator.ScaleWithDpi(CoreConfig.IconSize, NativeDpiMethods.GetDpi(Handle)); var imageList = new ImageList { ImageSize = scaledIconSize diff --git a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj index e75002ed7..40f2caf2d 100644 --- a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj +++ b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj @@ -6,7 +6,7 @@ - - + + \ No newline at end of file diff --git a/src/Greenshot.Plugin.Jira/JiraConfiguration.cs b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs index 069cc3263..7163924c5 100644 --- a/src/Greenshot.Plugin.Jira/JiraConfiguration.cs +++ b/src/Greenshot.Plugin.Jira/JiraConfiguration.cs @@ -19,7 +19,6 @@ * along with this program. If not, see . */ -using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; diff --git a/src/Greenshot.Plugin.Jira/JiraConnector.cs b/src/Greenshot.Plugin.Jira/JiraConnector.cs index ad48a09fa..fbfd42543 100644 --- a/src/Greenshot.Plugin.Jira/JiraConnector.cs +++ b/src/Greenshot.Plugin.Jira/JiraConnector.cs @@ -63,8 +63,8 @@ namespace Greenshot.Plugin.Jira var jiraConnector = SimpleServiceProvider.Current.GetInstance(); jiraConnector._jiraClient?.Behaviour.SetConfig(new SvgConfiguration { - Width = CoreConfig.ScaledIconSize.Width, - Height = CoreConfig.ScaledIconSize.Height + Width = CoreConfig.IconSize.Width, + Height = CoreConfig.IconSize.Height }); } }; @@ -112,8 +112,8 @@ namespace Greenshot.Plugin.Jira _jiraClient = JiraClient.Create(new Uri(JiraConfig.Url)); _jiraClient.Behaviour.SetConfig(new SvgConfiguration { - Width = CoreConfig.ScaledIconSize.Width, - Height = CoreConfig.ScaledIconSize.Height + Width = CoreConfig.IconSize.Width, + Height = CoreConfig.IconSize.Height }); _jiraClient.SetBasicAuthentication(user, password); diff --git a/src/Greenshot.Plugin.Jira/JiraMonitor.cs b/src/Greenshot.Plugin.Jira/JiraMonitor.cs index 17cc20d16..81a62b759 100644 --- a/src/Greenshot.Plugin.Jira/JiraMonitor.cs +++ b/src/Greenshot.Plugin.Jira/JiraMonitor.cs @@ -27,7 +27,9 @@ using System.Threading; using System.Threading.Tasks; using Dapplo.Jira; using Dapplo.Log; -using Greenshot.Base.Hooking; +using Dapplo.Windows.Desktop; +using Dapplo.Windows.Structs; +using Dapplo.Windows.User32; namespace Greenshot.Plugin.Jira { @@ -40,7 +42,7 @@ namespace Greenshot.Plugin.Jira { private static readonly LogSource Log = new LogSource(); private readonly Regex _jiraKeyPattern = new Regex(@"[A-Z][A-Z0-9]+\-[0-9]+"); - private readonly WindowsTitleMonitor _monitor; + private readonly IDisposable _monitor; private readonly IList _jiraInstances = new List(); private readonly IDictionary _projectJiraClientMap = new Dictionary(); @@ -56,9 +58,8 @@ namespace Greenshot.Plugin.Jira public JiraMonitor(int maxEntries = 40) { + _monitor = WinEventHook.WindowTitleChangeObservable().Subscribe(wei => MonitorTitleChangeEvent(wei)); _maxEntries = maxEntries; - _monitor = new WindowsTitleMonitor(); - _monitor.TitleChangeEvent += MonitorTitleChangeEvent; } /// @@ -82,7 +83,6 @@ namespace Greenshot.Plugin.Jira } // free managed resources - _monitor.TitleChangeEvent -= MonitorTitleChangeEvent; _monitor.Dispose(); // free native resources if there are any. } @@ -162,10 +162,10 @@ namespace Greenshot.Plugin.Jira /// /// Handle title changes, check for JIRA /// - /// - private void MonitorTitleChangeEvent(TitleChangeEventArgs eventArgs) + /// WinEventInfo + private void MonitorTitleChangeEvent(WinEventInfo winEventInfo) { - string windowTitle = eventArgs.Title; + string windowTitle = User32Api.GetText(winEventInfo.Handle); if (string.IsNullOrEmpty(windowTitle)) { return; diff --git a/src/Greenshot.Plugin.Office/Com/Ole32Api.cs b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs index 07d807ee2..1a57aa6c9 100644 --- a/src/Greenshot.Plugin.Office/Com/Ole32Api.cs +++ b/src/Greenshot.Plugin.Office/Com/Ole32Api.cs @@ -3,8 +3,8 @@ using System; using System.Runtime.InteropServices; -using Greenshot.Base.Core; -using Greenshot.Base.Core.Enums; +using Dapplo.Windows.Common.Enums; +using Dapplo.Windows.Common.Extensions; namespace Greenshot.Plugin.Office.Com { diff --git a/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs index c32b11a19..ea0f1b0c9 100644 --- a/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs +++ b/src/Greenshot.Plugin.Office/Com/OleAut32Api.cs @@ -3,8 +3,8 @@ using System; using System.Runtime.InteropServices; -using Greenshot.Base.Core; -using Greenshot.Base.Core.Enums; +using Dapplo.Windows.Common.Enums; +using Dapplo.Windows.Common.Extensions; namespace Greenshot.Plugin.Office.Com { diff --git a/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs index 48b7d994b..cfffff5f6 100644 --- a/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs +++ b/src/Greenshot.Plugin.Office/OfficeExport/ExcelExporter.cs @@ -20,7 +20,7 @@ using System; using System.Collections.Generic; using System.Drawing; -using Greenshot.Base.UnmanagedHelpers; +using Dapplo.Windows.User32; using Greenshot.Plugin.Office.Com; using Greenshot.Plugin.Office.OfficeInterop; using Microsoft.Office.Core; @@ -177,7 +177,7 @@ namespace Greenshot.Plugin.Office.OfficeExport shape.ComObject.ScaleWidth(1, MsoTriState.msoTrue, MsoScaleFrom.msoScaleFromTopLeft); workbook.ComObject.Activate(); using var application = DisposableCom.Create(workbook.ComObject.Application); - User32.SetForegroundWindow((IntPtr) application.ComObject.Hwnd); + User32Api.SetForegroundWindow((IntPtr) application.ComObject.Hwnd); } /// diff --git a/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs index 0574a6d0c..fa31d3a11 100644 --- a/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs +++ b/src/Greenshot.Plugin.Win10/Destinations/Win10ShareDestination.cs @@ -29,9 +29,11 @@ using System.Windows.Interop; using System.Windows.Media; using Windows.Storage; using Windows.Storage.Streams; +using Dapplo.Windows.Desktop; +using Dapplo.Windows.Enums; +using Dapplo.Windows.User32; using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; -using Greenshot.Base.Hooking; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; using Greenshot.Plugin.Win10.Internal; @@ -82,24 +84,22 @@ namespace Greenshot.Plugin.Win10.Destinations triggerWindow.Show(); - var focusMonitor = new WindowsOpenCloseMonitor(); var windowHandle = new WindowInteropHelper(triggerWindow).Handle; // This is a bad trick, but don't know how else to do it. // Wait for the focus to return, and depending on the state close the window! - focusMonitor.WindowOpenCloseChangeEvent += e => + var createDestroyMonitor = WinEventHook.WindowTitleChangeObservable().Subscribe(wei => { - if (e.IsOpen) + if (wei.WinEvent == WinEvents.EVENT_OBJECT_CREATE) { - if ("Windows Shell Experience Host" == e.Title) + var windowTitle = User32Api.GetText(wei.Handle); + if ("Windows Shell Experience Host" == windowTitle) { - shareInfo.SharingHwnd = e.HWnd; + shareInfo.SharingHwnd = wei.Handle; } - return; } - - if (e.HWnd == shareInfo.SharingHwnd) + if (wei.Handle == shareInfo.SharingHwnd) { if (shareInfo.ApplicationName != null) { @@ -108,12 +108,12 @@ namespace Greenshot.Plugin.Win10.Destinations shareInfo.ShareTask.TrySetResult(false); } - }; + }); Share(shareInfo, windowHandle, surface, captureDetails).GetAwaiter().GetResult(); Log.Debug("Sharing finished, closing window."); triggerWindow.Close(); - focusMonitor.Dispose(); + createDestroyMonitor.Dispose(); if (string.IsNullOrWhiteSpace(shareInfo.ApplicationName)) { exportInformation.ExportMade = false; diff --git a/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs index a03b07266..1ef1059c4 100644 --- a/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs +++ b/src/Greenshot.Plugin.Win10/Native/DataTransferManagerHelper.cs @@ -22,7 +22,7 @@ using System; using System.Runtime.InteropServices.WindowsRuntime; using Windows.ApplicationModel.DataTransfer; -using Greenshot.Base.Core; +using Dapplo.Windows.Common.Extensions; namespace Greenshot.Plugin.Win10.Native { diff --git a/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs index bba908bb8..408f5f451 100644 --- a/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs +++ b/src/Greenshot.Plugin.Win10/Native/IDataTransferManagerInterOp.cs @@ -20,7 +20,7 @@ using System; using System.Runtime.InteropServices; using Windows.ApplicationModel.DataTransfer; -using Greenshot.Base.Core.Enums; +using Dapplo.Windows.Common.Enums; namespace Greenshot.Plugin.Win10.Native { diff --git a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs index fdc0c07fa..e33909581 100644 --- a/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs +++ b/src/Greenshot.Plugin.Win10/Win10OcrProvider.cs @@ -26,6 +26,7 @@ using System.Threading.Tasks; using Windows.Graphics.Imaging; using Windows.Media.Ocr; using Windows.Storage.Streams; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.Effects; @@ -169,7 +170,7 @@ namespace Greenshot.Plugin.Win10 for (var index = 0; index < ocrLine.Words.Count; index++) { var ocrWord = ocrLine.Words[index]; - var location = new Rectangle((int) ocrWord.BoundingRect.X, (int) ocrWord.BoundingRect.Y, + var location = new NativeRect((int) ocrWord.BoundingRect.X, (int) ocrWord.BoundingRect.Y, (int) ocrWord.BoundingRect.Width, (int) ocrWord.BoundingRect.Height); var word = line.Words[index]; diff --git a/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs b/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs index 2c0446d09..0a9a511c7 100644 --- a/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs +++ b/src/Greenshot/Controls/ContextMenuToolStripProfessionalRenderer.cs @@ -21,8 +21,11 @@ using System.Drawing; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Dpi; using Greenshot.Base.Core; using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; namespace Greenshot.Controls { @@ -31,19 +34,25 @@ namespace Greenshot.Controls /// public class ContextMenuToolStripProfessionalRenderer : ToolStripProfessionalRenderer { + private readonly IProvideDeviceDpi _provideDeviceDpi; private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); private static Image _scaledCheckbox; + public ContextMenuToolStripProfessionalRenderer(IProvideDeviceDpi provideDeviceDpi) + { + _provideDeviceDpi = provideDeviceDpi; + } protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) { - if (_scaledCheckbox == null || _scaledCheckbox.Size != CoreConfig.ScaledIconSize) + var newSize = DpiCalculator.ScaleWithDpi(CoreConfig.IconSize, _provideDeviceDpi.DeviceDpi); + if (_scaledCheckbox == null || _scaledCheckbox.Size != newSize) { _scaledCheckbox?.Dispose(); - _scaledCheckbox = ImageHelper.ResizeImage(e.Image, true, CoreConfig.ScaledIconSize.Width, CoreConfig.ScaledIconSize.Height, null); + _scaledCheckbox = ImageHelper.ResizeImage(e.Image, true, newSize.Width, newSize.Height, null); } - Rectangle old = e.ImageRectangle; - ToolStripItemImageRenderEventArgs clone = new ToolStripItemImageRenderEventArgs(e.Graphics, e.Item, _scaledCheckbox, new Rectangle(old.X, 0, old.Width, old.Height)); + NativeRect old = e.ImageRectangle; + ToolStripItemImageRenderEventArgs clone = new ToolStripItemImageRenderEventArgs(e.Graphics, e.Item, _scaledCheckbox, new NativeRect(old.X, 0, old.Width, old.Height)); base.OnRenderItemCheck(clone); } } diff --git a/src/Greenshot/Forms/AboutForm.cs b/src/Greenshot/Forms/AboutForm.cs index edb00a6ac..a9cfc2cfc 100644 --- a/src/Greenshot/Forms/AboutForm.cs +++ b/src/Greenshot/Forms/AboutForm.cs @@ -28,6 +28,7 @@ using System.Drawing.Imaging; using System.IO; using System.Security.Permissions; using System.Windows.Forms; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.IniFile; using Greenshot.Configuration; @@ -69,43 +70,43 @@ namespace Greenshot.Forms /// /// The location of every dot in the "G" /// - private readonly List _gSpots = new List + private readonly List _gSpots = new List { // Top row - new Point(P2, P1), // 0 - new Point(P3, P1), // 1 - new Point(P4, P1), // 2 - new Point(P5, P1), // 3 - new Point(P6, P1), // 4 + new(P2, P1), // 0 + new(P3, P1), // 1 + new(P4, P1), // 2 + new(P5, P1), // 3 + new(P6, P1), // 4 // Second row - new Point(P1, P2), // 5 - new Point(P2, P2), // 6 + new(P1, P2), // 5 + new(P2, P2), // 6 // Third row - new Point(P1, P3), // 7 - new Point(P2, P3), // 8 + new(P1, P3), // 7 + new(P2, P3), // 8 // Fourth row - new Point(P1, P4), // 9 - new Point(P2, P4), // 10 - new Point(P5, P4), // 11 - new Point(P6, P4), // 12 - new Point(P7, P4), // 13 + new(P1, P4), // 9 + new(P2, P4), // 10 + new(P5, P4), // 11 + new(P6, P4), // 12 + new(P7, P4), // 13 // Fifth row - new Point(P1, P5), // 14 - new Point(P2, P5), // 15 - new Point(P6, P5), // 16 - new Point(P7, P5), // 17 + new(P1, P5), // 14 + new(P2, P5), // 15 + new(P6, P5), // 16 + new(P7, P5), // 17 // Sixth row - new Point(P1, P6), // 18 - new Point(P2, P6), // 19 - new Point(P3, P6), // 20 - new Point(P4, P6), // 21 - new Point(P5, P6), // 22 - new Point(P6, P6) // 23 + new(P1, P6), // 18 + new(P2, P6), // 19 + new(P3, P6), // 20 + new(P4, P6), // 21 + new(P5, P6), // 22 + new(P6, P6) // 23 }; // 0 1 2 3 4 @@ -165,7 +166,7 @@ namespace Greenshot.Forms for (int index = 0; index < _gSpots.Count; index++) { // Read the pixels in the order of the flow - Point gSpot = _gSpots[_flowOrder[index]]; + NativePoint gSpot = _gSpots[_flowOrder[index]]; // Create the animation, first we do nothing (on the final destination) RectangleAnimator pixelAnimation; @@ -176,15 +177,15 @@ namespace Greenshot.Forms if (IsTerminalServerSession) { // No animation - pixelAnimation = new RectangleAnimator(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic, EasingMode.EaseIn); + pixelAnimation = new RectangleAnimator(new NativeRect(gSpot.X, gSpot.Y, W - 2, W - 2), new NativeRect(gSpot.X, gSpot.Y, W - 2, W - 2), 1, EasingType.Cubic, EasingMode.EaseIn); } else { // Create the animation, first we do nothing (on the final destination) - Rectangle standingStill = new Rectangle(gSpot.X + offset, gSpot.Y + offset, 0, 0); + NativeRect standingStill = new NativeRect(gSpot.X + offset, gSpot.Y + offset, 0, 0); pixelAnimation = new RectangleAnimator(standingStill, standingStill, pixelWaitFrames, EasingType.Quintic, EasingMode.EaseIn); // And than we size to the wanted size. - pixelAnimation.QueueDestinationLeg(new Rectangle(gSpot.X, gSpot.Y, W - 2, W - 2), frames); + pixelAnimation.QueueDestinationLeg(new NativeRect(gSpot.X, gSpot.Y, W - 2, W - 2), frames); } // Increase the wait frames @@ -218,7 +219,7 @@ namespace Greenshot.Forms /// private void LinkLabelClicked(object sender, LinkLabelLinkClickedEventArgs e) { - if (!(sender is LinkLabel linkLabel)) return; + if (sender is not LinkLabel linkLabel) return; var link = linkLabel.Tag?.ToString() ?? linkLabel.Text; try { diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs index f8b2c004b..68e57f040 100644 --- a/src/Greenshot/Forms/CaptureForm.cs +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -30,14 +30,15 @@ using System.Security.Permissions; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.User32; +using Dapplo.Windows.User32.Enums; using Greenshot.Base.Controls; using Greenshot.Base.Core; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Ocr; -using Greenshot.Base.UnmanagedHelpers; -using Greenshot.Base.UnmanagedHelpers.Enums; -using Greenshot.Editor.Helpers; namespace Greenshot.Forms { @@ -72,15 +73,15 @@ namespace Greenshot.Forms private int _mX; private int _mY; - private Point _mouseMovePos = Point.Empty; - private Point _cursorPos; + private NativePoint _mouseMovePos = NativePoint.Empty; + private NativePoint _cursorPos; private CaptureMode _captureMode; private readonly List _windows; private WindowDetails _selectedCaptureWindow; private bool _mouseDown; - private Rectangle _captureRect = Rectangle.Empty; + private NativeRect _captureRect = NativeRect.Empty; private readonly ICapture _capture; - private Point _previousMousePos = Point.Empty; + private NativePoint _previousMousePos = NativePoint.Empty; private FixMode _fixMode = FixMode.None; private RectangleAnimator _windowAnimator; private RectangleAnimator _zoomAnimator; @@ -91,7 +92,7 @@ namespace Greenshot.Forms /// /// Property to access the selected capture rectangle /// - public Rectangle CaptureRectangle => _captureRect; + public NativeRect CaptureRectangle => _captureRect; /// /// Property to access the used capture mode @@ -181,7 +182,7 @@ namespace Greenshot.Forms // Initialize the animations, the window capture zooms out from the cursor to the window under the cursor if (_captureMode == CaptureMode.Window) { - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); + _windowAnimator = new RectangleAnimator(new NativeRect(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); } // Set the zoomer animation @@ -225,12 +226,12 @@ namespace Greenshot.Forms if (isOn) { // Initialize the zoom with a invalid position - _zoomAnimator = new RectangleAnimator(Rectangle.Empty, new Rectangle(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut); + _zoomAnimator = new RectangleAnimator(NativeRect.Empty, new NativeRect(int.MaxValue, int.MaxValue, 0, 0), FramesForMillis(1000), EasingType.Quintic, EasingMode.EaseOut); VerifyZoomAnimation(_cursorPos, false); } else { - _zoomAnimator?.ChangeDestination(new Rectangle(Point.Empty, Size.Empty), FramesForMillis(1000)); + _zoomAnimator?.ChangeDestination(new NativeRect(NativePoint.Empty, NativeSize.Empty), FramesForMillis(1000)); } } @@ -319,8 +320,8 @@ namespace Greenshot.Forms // "Fade out" Zoom InitializeZoomer(false); // "Fade in" window - _windowAnimator = new RectangleAnimator(new Rectangle(_cursorPos, Size.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); - _captureRect = Rectangle.Empty; + _windowAnimator = new RectangleAnimator(new NativeRect(_cursorPos, NativeSize.Empty), _captureRect, FramesForMillis(700), EasingType.Quintic, EasingMode.EaseOut); + _captureRect = NativeRect.Empty; Invalidate(); break; case CaptureMode.Text: @@ -332,10 +333,10 @@ namespace Greenshot.Forms // Set the region capture mode _captureMode = CaptureMode.Region; // "Fade out" window - _windowAnimator.ChangeDestination(new Rectangle(_cursorPos, Size.Empty), FramesForMillis(700)); + _windowAnimator.ChangeDestination(new NativeRect(_cursorPos, NativeSize.Empty), FramesForMillis(700)); // Fade in zoom InitializeZoomer(Conf.ZoomerEnabled); - _captureRect = Rectangle.Empty; + _captureRect = NativeRect.Empty; Invalidate(); break; } @@ -403,7 +404,7 @@ namespace Greenshot.Forms private void HandleMouseDown() { - Point tmpCursorLocation = WindowCapture.GetCursorLocationRelativeToScreenBounds(); + NativePoint tmpCursorLocation = WindowCapture.GetCursorLocationRelativeToScreenBounds(); _mX = tmpCursorLocation.X; _mY = tmpCursorLocation.Y; _mouseDown = true; @@ -426,8 +427,7 @@ namespace Greenshot.Forms // correct the GUI width to real width if Region mode if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) { - _captureRect.Width += 1; - _captureRect.Height += 1; + _captureRect = _captureRect.Inflate(1, 1); } // Go and process the capture @@ -436,7 +436,7 @@ namespace Greenshot.Forms else if (_captureMode == CaptureMode.Text && IsWordUnderCursor(_mouseMovePos)) { // Handle a click on a single word - _captureRect = new Rectangle(_mouseMovePos, new Size(1, 1)); + _captureRect = new NativeRect(_mouseMovePos, new NativeSize(1, 1)); // Go and process the capture DialogResult = DialogResult.OK; } @@ -447,11 +447,11 @@ namespace Greenshot.Forms } /// - /// + /// Check if there is a word under the specified location /// - /// - /// - private bool IsWordUnderCursor(Point cursorLocation) + /// NativePoint + /// bool true if there is a word + private bool IsWordUnderCursor(NativePoint location) { if (_captureMode != CaptureMode.Text || _capture.CaptureDetails.OcrInformation == null) return false; @@ -462,10 +462,10 @@ namespace Greenshot.Forms var lineBounds = line.CalculatedBounds; if (lineBounds.IsEmpty) continue; // Highlight the text which is selected - if (!lineBounds.Contains(cursorLocation)) continue; + if (!lineBounds.Contains(location)) continue; foreach (var word in line.Words) { - if (word.Bounds.Contains(cursorLocation)) + if (word.Bounds.Contains(location)) { return true; } @@ -493,7 +493,7 @@ namespace Greenshot.Forms /// /// /// - private Point FixMouseCoordinates(Point currentMouse) + private NativePoint FixMouseCoordinates(NativePoint currentMouse) { if (_fixMode == FixMode.Initiated) { @@ -508,11 +508,11 @@ namespace Greenshot.Forms } else if (_fixMode == FixMode.Vertical) { - currentMouse = new Point(currentMouse.X, _previousMousePos.Y); + currentMouse = new NativePoint(currentMouse.X, _previousMousePos.Y); } else if (_fixMode == FixMode.Horizontal) { - currentMouse = new Point(_previousMousePos.X, currentMouse.Y); + currentMouse = new NativePoint(_previousMousePos.X, currentMouse.Y); } _previousMousePos = currentMouse; @@ -527,7 +527,7 @@ namespace Greenshot.Forms private void OnMouseMove(object sender, MouseEventArgs e) { // Make sure the mouse coordinates are fixed, when pressing shift - var mouseMovePos = FixMouseCoordinates(User32.GetCursorLocation()); + var mouseMovePos = FixMouseCoordinates(User32Api.GetCursorLocation()); _mouseMovePos = WindowCapture.GetLocationRelativeToScreenBounds(mouseMovePos); } @@ -551,7 +551,7 @@ namespace Greenshot.Forms /// protected override void Animate() { - Point lastPos = _cursorPos; + NativePoint lastPos = _cursorPos; _cursorPos = _mouseMovePos; if (_selectedCaptureWindow != null && lastPos.Equals(_cursorPos) && !IsAnimating(_zoomAnimator) && !IsAnimating(_windowAnimator)) @@ -575,11 +575,11 @@ namespace Greenshot.Forms if ((_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) && _mouseDown) { - _captureRect = GuiRectangle.GetGuiRectangle(_cursorPos.X, _cursorPos.Y, _mX - _cursorPos.X, _mY - _cursorPos.Y); + _captureRect = new NativeRect(_cursorPos.X, _cursorPos.Y, _mX - _cursorPos.X, _mY - _cursorPos.Y).Normalize(); } // Iterate over the found windows and check if the current location is inside a window - Point cursorPosition = Cursor.Position; + NativePoint cursorPosition = Cursor.Position; _selectedCaptureWindow = null; lock (_windows) { @@ -605,11 +605,11 @@ namespace Greenshot.Forms // Here we want to capture the window which is under the mouse _captureRect = _selectedCaptureWindow.WindowRectangle; // As the ClientRectangle is not in Bitmap coordinates, we need to correct. - _captureRect.Offset(-_capture.ScreenBounds.Location.X, -_capture.ScreenBounds.Location.Y); + _captureRect = _captureRect.Offset(-_capture.ScreenBounds.Location.X, -_capture.ScreenBounds.Location.Y); } } - Rectangle invalidateRectangle; + NativeRect invalidateRectangle; if (_mouseDown && (_captureMode != CaptureMode.Window)) { int x1 = Math.Min(_mX, lastPos.X); @@ -640,32 +640,32 @@ namespace Greenshot.Forms y1 -= measureHeight.Height + 10; } - invalidateRectangle = new Rectangle(x1, y1, x2 - x1, y2 - y1); + invalidateRectangle = new NativeRect(x1, y1, x2 - x1, y2 - y1); Invalidate(invalidateRectangle); } else if (_captureMode != CaptureMode.Window) { if (!IsTerminalServerSession) { - Rectangle allScreenBounds = WindowCapture.GetScreenBounds(); - allScreenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(allScreenBounds.Location); + var allScreenBounds = DisplayInfo.ScreenBounds; + allScreenBounds = allScreenBounds.MoveTo(WindowCapture.GetLocationRelativeToScreenBounds(allScreenBounds.Location)); if (verticalMove) { // Before - invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, lastPos.Y - 2, Width + 2, 45); + invalidateRectangle = new NativeRect(allScreenBounds.Left, lastPos.Y - 2, Width + 2, 45).Normalize(); Invalidate(invalidateRectangle); // After - invalidateRectangle = GuiRectangle.GetGuiRectangle(allScreenBounds.Left, _cursorPos.Y - 2, Width + 2, 45); + invalidateRectangle = new NativeRect(allScreenBounds.Left, _cursorPos.Y - 2, Width + 2, 45).Normalize(); Invalidate(invalidateRectangle); } if (horizontalMove) { // Before - invalidateRectangle = GuiRectangle.GetGuiRectangle(lastPos.X - 2, allScreenBounds.Top, 75, Height + 2); + invalidateRectangle = new NativeRect(lastPos.X - 2, allScreenBounds.Top, 75, Height + 2).Normalize(); Invalidate(invalidateRectangle); // After - invalidateRectangle = GuiRectangle.GetGuiRectangle(_cursorPos.X - 2, allScreenBounds.Top, 75, Height + 2); + invalidateRectangle = new NativeRect(_cursorPos.X - 2, allScreenBounds.Top, 75, Height + 2).Normalize(); Invalidate(invalidateRectangle); } } @@ -685,11 +685,9 @@ namespace Greenshot.Forms // Check if the animation needs to be drawn if (IsAnimating(_windowAnimator)) { - invalidateRectangle = _windowAnimator.Current; - invalidateRectangle.Inflate(safetySize, safetySize); + invalidateRectangle = _windowAnimator.Current.Inflate(safetySize, safetySize); Invalidate(invalidateRectangle); - invalidateRectangle = _windowAnimator.Next(); - invalidateRectangle.Inflate(safetySize, safetySize); + invalidateRectangle = _windowAnimator.Next().Inflate(safetySize, safetySize); Invalidate(invalidateRectangle); // Check if this was the last of the windows animations in the normal region capture. if (_captureMode != CaptureMode.Window && !IsAnimating(_windowAnimator)) @@ -701,8 +699,7 @@ namespace Greenshot.Forms if (_zoomAnimator != null && (IsAnimating(_zoomAnimator) || _captureMode != CaptureMode.Window)) { // Make sure we invalidate the old zoom area - invalidateRectangle = _zoomAnimator.Current; - invalidateRectangle.Offset(lastPos); + invalidateRectangle = _zoomAnimator.Current.Offset(lastPos); Invalidate(invalidateRectangle); // Only verify if we are really showing the zoom, not the outgoing animation if (Conf.ZoomerEnabled && _captureMode != CaptureMode.Window) @@ -713,7 +710,7 @@ namespace Greenshot.Forms // The following logic is not needed, next always returns the current if there are no frames left // but it makes more sense if we want to change something in the logic invalidateRectangle = IsAnimating(_zoomAnimator) ? _zoomAnimator.Next() : _zoomAnimator.Current; - invalidateRectangle.Offset(_cursorPos); + invalidateRectangle = invalidateRectangle.Offset(_cursorPos); Invalidate(invalidateRectangle); } @@ -722,7 +719,7 @@ namespace Greenshot.Forms { var ocrInfo = _capture.CaptureDetails.OcrInformation; - invalidateRectangle = Rectangle.Empty; + invalidateRectangle = NativeRect.Empty; foreach (var line in ocrInfo.Lines) { var lineBounds = line.CalculatedBounds; @@ -733,22 +730,20 @@ namespace Greenshot.Forms if (_mouseDown) { // Highlight the text which is selected - if (lineBounds.IntersectsWith(_captureRect)) + if (!lineBounds.IntersectsWith(_captureRect)) continue; + foreach (var word in line.Words) { - foreach (var word in line.Words) + if (!word.Bounds.IntersectsWith(_captureRect)) { - if (!word.Bounds.IntersectsWith(_captureRect)) - { - continue; - } - if (invalidateRectangle.IsEmpty) - { - invalidateRectangle = word.Bounds; - } - else - { - invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); - } + continue; + } + if (invalidateRectangle.IsEmpty) + { + invalidateRectangle = word.Bounds; + } + else + { + invalidateRectangle = invalidateRectangle.Union(word.Bounds); } } } @@ -763,7 +758,7 @@ namespace Greenshot.Forms } else { - invalidateRectangle = Rectangle.Union(invalidateRectangle, word.Bounds); + invalidateRectangle = invalidateRectangle.Union(word.Bounds); } break; @@ -794,52 +789,51 @@ namespace Greenshot.Forms ///
/// preferred destination location for the zoom area /// false to try to find a location which is neither out of screen bounds nor intersects with the selected rectangle - private void VerifyZoomAnimation(Point pos, bool allowZoomOverCaptureRect) + private void VerifyZoomAnimation(NativePoint pos, bool allowZoomOverCaptureRect) { - Rectangle screenBounds = Screen.GetBounds(MousePosition); + NativeRect screenBounds = DisplayInfo.GetBounds(MousePosition); // convert to be relative to top left corner of all screen bounds - screenBounds.Location = WindowCapture.GetLocationRelativeToScreenBounds(screenBounds.Location); + screenBounds = screenBounds.MoveTo(WindowCapture.GetLocationRelativeToScreenBounds(screenBounds.Location)); int relativeZoomSize = Math.Min(screenBounds.Width, screenBounds.Height) / 5; // Make sure the final size is a plural of 4, this makes it look better relativeZoomSize -= relativeZoomSize % 4; - Size zoomSize = new Size(relativeZoomSize, relativeZoomSize); - Point zoomOffset = new Point(20, 20); + var zoomSize = new NativeSize(relativeZoomSize, relativeZoomSize); + var zoomOffset = new NativePoint(20, 20); - Rectangle targetRectangle = _zoomAnimator.Final; - targetRectangle.Offset(pos); + NativeRect targetRectangle = _zoomAnimator.Final.Offset(pos); if (screenBounds.Contains(targetRectangle) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(targetRectangle))) { return; } - Point destinationLocation = Point.Empty; - Rectangle tl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); - Rectangle tr = new Rectangle(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); - Rectangle bl = new Rectangle(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); - Rectangle br = new Rectangle(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); + var destinationLocation = NativePoint.Empty; + var tl = new NativeRect(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); + var tr = new NativeRect(pos.X + zoomOffset.X, pos.Y - (zoomOffset.Y + zoomSize.Height), zoomSize.Width, zoomSize.Height); + var bl = new NativeRect(pos.X - (zoomOffset.X + zoomSize.Width), pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); + var br = new NativeRect(pos.X + zoomOffset.X, pos.Y + zoomOffset.Y, zoomSize.Width, zoomSize.Height); if (screenBounds.Contains(br) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(br))) { - destinationLocation = new Point(zoomOffset.X, zoomOffset.Y); + destinationLocation = new NativePoint(zoomOffset.X, zoomOffset.Y); } else if (screenBounds.Contains(bl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(bl))) { - destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, zoomOffset.Y); + destinationLocation = new NativePoint(-zoomOffset.X - zoomSize.Width, zoomOffset.Y); } else if (screenBounds.Contains(tr) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tr))) { - destinationLocation = new Point(zoomOffset.X, -zoomOffset.Y - zoomSize.Width); + destinationLocation = new NativePoint(zoomOffset.X, -zoomOffset.Y - zoomSize.Width); } else if (screenBounds.Contains(tl) && (allowZoomOverCaptureRect || !_captureRect.IntersectsWith(tl))) { - destinationLocation = new Point(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width); + destinationLocation = new NativePoint(-zoomOffset.X - zoomSize.Width, -zoomOffset.Y - zoomSize.Width); } - if (destinationLocation == Point.Empty && !allowZoomOverCaptureRect) + if (destinationLocation == NativePoint.Empty && !allowZoomOverCaptureRect) { VerifyZoomAnimation(pos, true); } else { - _zoomAnimator.ChangeDestination(new Rectangle(destinationLocation, zoomSize)); + _zoomAnimator.ChangeDestination(new NativeRect(destinationLocation, zoomSize)); } } @@ -849,7 +843,7 @@ namespace Greenshot.Forms /// /// /// - private void DrawZoom(Graphics graphics, Rectangle sourceRectangle, Rectangle destinationRectangle) + private void DrawZoom(Graphics graphics, NativeRect sourceRectangle, NativeRect destinationRectangle) { if (_capture.Image == null) { @@ -962,7 +956,7 @@ namespace Greenshot.Forms private void OnPaint(object sender, PaintEventArgs e) { Graphics graphics = e.Graphics; - Rectangle clipRectangle = e.ClipRectangle; + NativeRect clipRectangle = e.ClipRectangle; //graphics.BitBlt((Bitmap)buffer, Point.Empty); graphics.DrawImageUnscaled(_capture.Image, Point.Empty); @@ -1010,14 +1004,14 @@ namespace Greenshot.Forms } // Only draw Cursor if it's (partly) visible - if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new Rectangle(_capture.CursorLocation, _capture.Cursor.Size))) + if (_capture.Cursor != null && _capture.CursorVisible && clipRectangle.IntersectsWith(new NativeRect(_capture.CursorLocation, _capture.Cursor.Size))) { graphics.DrawIcon(_capture.Cursor, _capture.CursorLocation.X, _capture.CursorLocation.Y); } if (_mouseDown || _captureMode == CaptureMode.Window || IsAnimating(_windowAnimator)) { - _captureRect.Intersect(new Rectangle(Point.Empty, _capture.ScreenBounds.Size)); // crop what is outside the screen + _captureRect = _captureRect.Intersect(new NativeRect(Point.Empty, _capture.ScreenBounds.Size)); // crop what is outside the screen var fixedRect = IsAnimating(_windowAnimator) ? _windowAnimator.Current : _captureRect; @@ -1146,7 +1140,7 @@ namespace Greenshot.Forms using (Pen pen = new Pen(Color.LightSeaGreen)) { pen.DashStyle = DashStyle.Dot; - Rectangle screenBounds = _capture.ScreenBounds; + NativeRect screenBounds = _capture.ScreenBounds; graphics.DrawLine(pen, _cursorPos.X, screenBounds.Y, _cursorPos.X, screenBounds.Height); graphics.DrawLine(pen, screenBounds.X, _cursorPos.Y, screenBounds.Width, _cursorPos.Y); } @@ -1175,10 +1169,10 @@ namespace Greenshot.Forms const int zoomSourceWidth = 25; const int zoomSourceHeight = 25; - Rectangle sourceRectangle = new Rectangle(_cursorPos.X - zoomSourceWidth / 2, _cursorPos.Y - zoomSourceHeight / 2, zoomSourceWidth, zoomSourceHeight); + var sourceRectangle = new NativeRect(_cursorPos.X - zoomSourceWidth / 2, _cursorPos.Y - zoomSourceHeight / 2, zoomSourceWidth, zoomSourceHeight); - Rectangle destinationRectangle = _zoomAnimator.Current; - destinationRectangle.Offset(_cursorPos); + var destinationRectangle = _zoomAnimator.Current; + destinationRectangle = destinationRectangle.Offset(_cursorPos); DrawZoom(graphics, sourceRectangle, destinationRectangle); } } diff --git a/src/Greenshot/Forms/MainForm.Designer.cs b/src/Greenshot/Forms/MainForm.Designer.cs index 015e0060b..b558bf4f9 100644 --- a/src/Greenshot/Forms/MainForm.Designer.cs +++ b/src/Greenshot/Forms/MainForm.Designer.cs @@ -106,7 +106,7 @@ namespace Greenshot.Forms { this.contextMenu.Name = "contextMenu"; this.contextMenu.Closing += new System.Windows.Forms.ToolStripDropDownClosingEventHandler(this.ContextMenuClosing); this.contextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.ContextMenuOpening); - this.contextMenu.Renderer = new Greenshot.Controls.ContextMenuToolStripProfessionalRenderer(); + this.contextMenu.Renderer = new Greenshot.Controls.ContextMenuToolStripProfessionalRenderer(this); // // contextmenu_capturearea // @@ -204,7 +204,7 @@ namespace Greenshot.Forms { // contextmenu_quicksettings // this.contextmenu_quicksettings.Name = "contextmenu_quicksettings"; - this.contextmenu_quicksettings.Size = new System.Drawing.Size(170, coreConfiguration.ScaledIconSize.Height + 8); + this.contextmenu_quicksettings.Size = new System.Drawing.Size(170, coreConfiguration.IconSize.Height + 8); // // contextmenu_settings // diff --git a/src/Greenshot/Forms/MainForm.cs b/src/Greenshot/Forms/MainForm.cs index fc7fb046d..081084d0b 100644 --- a/src/Greenshot/Forms/MainForm.cs +++ b/src/Greenshot/Forms/MainForm.cs @@ -32,6 +32,11 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.Integration; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.DesktopWindowsManager; +using Dapplo.Windows.Dpi; +using Dapplo.Windows.Kernel32; +using Dapplo.Windows.User32; using Greenshot.Base; using Greenshot.Base.Controls; using Greenshot.Base.Core; @@ -41,7 +46,6 @@ using Greenshot.Base.Help; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; -using Greenshot.Base.UnmanagedHelpers; using Greenshot.Configuration; using Greenshot.Destinations; using Greenshot.Editor; @@ -58,7 +62,7 @@ namespace Greenshot.Forms /// /// This is the MainForm, the shell of Greenshot /// - public partial class MainForm : BaseForm, IGreenshotMainForm, ICaptureHelper + public partial class MainForm : BaseForm, IGreenshotMainForm, ICaptureHelper, IProvideDeviceDpi { private static ILog LOG; private static ResourceMutex _applicationMutex; @@ -116,11 +120,11 @@ namespace Greenshot.Forms if (argument.ToLower().Equals("/help") || argument.ToLower().Equals("/h") || argument.ToLower().Equals("/?")) { // Try to attach to the console - bool attachedToConsole = Kernel32.AttachConsole(Kernel32.ATTACHCONSOLE_ATTACHPARENTPROCESS); + bool attachedToConsole = Kernel32Api.AttachConsole(); // If attach didn't work, open a console if (!attachedToConsole) { - Kernel32.AllocConsole(); + Kernel32Api.AllocConsole(); } var helpOutput = new StringBuilder(); @@ -250,7 +254,7 @@ namespace Greenshot.Forms { try { - instanceInfo.Append(index++ + ": ").AppendLine(Kernel32.GetProcessPath(greenshotProcess.Id)); + instanceInfo.Append(index++ + ": ").AppendLine(Kernel32Api.GetProcessPath(greenshotProcess.Id)); if (currentProcessId == greenshotProcess.Id) { matchedThisProcess = true; @@ -267,7 +271,7 @@ namespace Greenshot.Forms if (!matchedThisProcess) { using Process currentProcess = Process.GetCurrentProcess(); - instanceInfo.Append(index + ": ").AppendLine(Kernel32.GetProcessPath(currentProcess.Id)); + instanceInfo.Append(index + ": ").AppendLine(Kernel32Api.GetProcessPath(currentProcess.Id)); } // A dirty fix to make sure the message box is visible as a Greenshot window on the taskbar @@ -378,8 +382,7 @@ namespace Greenshot.Forms { var uiContext = TaskScheduler.FromCurrentSynchronizationContext(); SimpleServiceProvider.Current.AddService(uiContext); - DpiChanged += (e, o) => ApplyDpiScaling(); - + // The most important form is this SimpleServiceProvider.Current.AddService(this); // Also as itself @@ -503,7 +506,7 @@ namespace Greenshot.Forms // Make Greenshot use less memory after startup if (_conf.MinimizeWorkingSetSize) { - PsAPI.EmptyWorkingSet(); + PsApi.EmptyWorkingSet(); } } @@ -528,7 +531,7 @@ namespace Greenshot.Forms int len = 250; var stringBuilder = new StringBuilder(len); using var proc = Process.GetCurrentProcess(); - var err = Kernel32.GetPackageFullName(proc.Handle, ref len, stringBuilder); + var err = Kernel32Api.GetPackageFullName(proc.Handle, ref len, stringBuilder); if (err != 0) { useEditor = true; @@ -744,7 +747,7 @@ namespace Greenshot.Forms return; } - ApplyDpiScaling(); + DpiChangedHandler(96, DeviceDpi); string ieExePath = PluginUtils.GetExePath("iexplore.exe"); if (!string.IsNullOrEmpty(ieExePath)) { @@ -755,10 +758,10 @@ namespace Greenshot.Forms /// /// Modify the DPI settings depending in the current value /// - private void ApplyDpiScaling() + protected override void DpiChangedHandler(int oldDpi, int newDpi) { - var scaledIconSize = DpiHelper.ScaleWithDpi(coreConfiguration.IconSize, DpiHelper.GetDpi(Handle)); - contextMenu.ImageScalingSize = scaledIconSize; + var newSize = DpiCalculator.ScaleWithDpi(coreConfiguration.IconSize, newDpi); + contextMenu.ImageScalingSize = newSize; } /// @@ -1002,7 +1005,7 @@ namespace Greenshot.Forms var factor = DeviceDpi / 96f; contextMenu.Scale(new SizeF(factor, factor)); contextmenu_captureclipboard.Enabled = ClipboardHelper.ContainsImage(); - contextmenu_capturelastregion.Enabled = coreConfiguration.LastCapturedRegion != Rectangle.Empty; + contextmenu_capturelastregion.Enabled = coreConfiguration.LastCapturedRegion != NativeRect.Empty; // IE context menu code try @@ -1124,51 +1127,50 @@ namespace Greenshot.Forms { ToolStripMenuItem captureScreenMenuItem = (ToolStripMenuItem) sender; captureScreenMenuItem.DropDownItems.Clear(); - if (Screen.AllScreens.Length > 1) - { - Rectangle allScreensBounds = WindowCapture.GetScreenBounds(); + if (DisplayInfo.AllDisplayInfos.Length <= 1) return; - var captureScreenItem = new ToolStripMenuItem(Language.GetString(LangKey.contextmenu_capturefullscreen_all)); - captureScreenItem.Click += delegate { - BeginInvoke((MethodInvoker) delegate { - CaptureHelper.CaptureFullscreen(false, ScreenCaptureMode.FullScreen); + var allScreensBounds = DisplayInfo.ScreenBounds; + + var captureScreenItem = new ToolStripMenuItem(Language.GetString(LangKey.contextmenu_capturefullscreen_all)); + captureScreenItem.Click += delegate { + BeginInvoke((MethodInvoker) delegate { + CaptureHelper.CaptureFullscreen(false, ScreenCaptureMode.FullScreen); + }); + }; + + captureScreenMenuItem.DropDownItems.Add(captureScreenItem); + foreach (var displayInfo in DisplayInfo.AllDisplayInfos) + { + var displayToCapture = displayInfo; + string deviceAlignment = displayToCapture.DeviceName; + + if (displayInfo.Bounds.Top == allScreensBounds.Top && displayInfo.Bounds.Bottom != allScreensBounds.Bottom) + { + deviceAlignment += " " + Language.GetString(LangKey.contextmenu_capturefullscreen_top); + } + else if (displayInfo.Bounds.Top != allScreensBounds.Top && displayInfo.Bounds.Bottom == allScreensBounds.Bottom) + { + deviceAlignment += " " + Language.GetString(LangKey.contextmenu_capturefullscreen_bottom); + } + + if (displayInfo.Bounds.Left == allScreensBounds.Left && displayInfo.Bounds.Right != allScreensBounds.Right) + { + deviceAlignment += " " + Language.GetString(LangKey.contextmenu_capturefullscreen_left); + } + else if (displayInfo.Bounds.Left != allScreensBounds.Left && displayInfo.Bounds.Right == allScreensBounds.Right) + { + deviceAlignment += " " + Language.GetString(LangKey.contextmenu_capturefullscreen_right); + } + + captureScreenItem = new ToolStripMenuItem(deviceAlignment); + captureScreenItem.Click += delegate + { + BeginInvoke((MethodInvoker) delegate + { + CaptureHelper.CaptureRegion(false, displayToCapture.Bounds); }); }; - captureScreenMenuItem.DropDownItems.Add(captureScreenItem); - foreach (Screen screen in Screen.AllScreens) - { - Screen screenToCapture = screen; - string deviceAlignment = screenToCapture.DeviceName; - - if (screen.Bounds.Top == allScreensBounds.Top && screen.Bounds.Bottom != allScreensBounds.Bottom) - { - deviceAlignment += " " + Language.GetString(LangKey.contextmenu_capturefullscreen_top); - } - else if (screen.Bounds.Top != allScreensBounds.Top && screen.Bounds.Bottom == allScreensBounds.Bottom) - { - deviceAlignment += " " + Language.GetString(LangKey.contextmenu_capturefullscreen_bottom); - } - - if (screen.Bounds.Left == allScreensBounds.Left && screen.Bounds.Right != allScreensBounds.Right) - { - deviceAlignment += " " + Language.GetString(LangKey.contextmenu_capturefullscreen_left); - } - else if (screen.Bounds.Left != allScreensBounds.Left && screen.Bounds.Right == allScreensBounds.Right) - { - deviceAlignment += " " + Language.GetString(LangKey.contextmenu_capturefullscreen_right); - } - - captureScreenItem = new ToolStripMenuItem(deviceAlignment); - captureScreenItem.Click += delegate - { - BeginInvoke((MethodInvoker) delegate - { - CaptureHelper.CaptureRegion(false, screenToCapture.Bounds); - }); - }; - captureScreenMenuItem.DropDownItems.Add(captureScreenItem); - } } } @@ -1237,7 +1239,7 @@ namespace Greenshot.Forms { menuItem.DropDownItems.Clear(); // check if thumbnailPreview is enabled and DWM is enabled - bool thumbnailPreview = _conf.ThumnailPreview && DWM.IsDwmEnabled; + bool thumbnailPreview = _conf.ThumnailPreview && DwmApi.IsDwmEnabled; foreach (var window in WindowDetails.GetTopLevelWindows()) { @@ -1499,7 +1501,7 @@ namespace Greenshot.Forms if (!_conf.Values["Destinations"].IsFixed) { // screenshot destination - selectList = new ToolStripMenuSelectList("destinations", true) + selectList = new ToolStripMenuSelectList("destinations", true, this) { Text = Language.GetString(LangKey.settings_destination) }; @@ -1516,7 +1518,7 @@ namespace Greenshot.Forms if (!_conf.Values["WindowCaptureMode"].IsFixed) { // Capture Modes - selectList = new ToolStripMenuSelectList("capturemodes", false) + selectList = new ToolStripMenuSelectList("capturemodes", false, this) { Text = Language.GetString(LangKey.settings_window_capture_mode) }; @@ -1531,7 +1533,7 @@ namespace Greenshot.Forms } // print options - selectList = new ToolStripMenuSelectList("printoptions", true) + selectList = new ToolStripMenuSelectList("printoptions", true, this) { Text = Language.GetString(LangKey.settings_printoptions) }; @@ -1556,7 +1558,7 @@ namespace Greenshot.Forms } // effects - selectList = new ToolStripMenuSelectList("effects", true) + selectList = new ToolStripMenuSelectList("effects", true, this) { Text = Language.GetString(LangKey.settings_visualization) }; diff --git a/src/Greenshot/Forms/SettingsForm.cs b/src/Greenshot/Forms/SettingsForm.cs index 272c2fde1..12f2f07cb 100644 --- a/src/Greenshot/Forms/SettingsForm.cs +++ b/src/Greenshot/Forms/SettingsForm.cs @@ -28,6 +28,8 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; +using Dapplo.Windows.DesktopWindowsManager; +using Dapplo.Windows.Dpi; using Greenshot.Base; using Greenshot.Base.Controls; using Greenshot.Base.Core; @@ -35,7 +37,6 @@ using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Plugin; -using Greenshot.Base.UnmanagedHelpers; using Greenshot.Configuration; using Greenshot.Helpers; using log4net; @@ -224,7 +225,7 @@ namespace Greenshot.Forms private void SetWindowCaptureMode(WindowCaptureMode selectedWindowCaptureMode) { WindowCaptureMode[] availableModes; - if (!DWM.IsDwmEnabled) + if (!DwmApi.IsDwmEnabled) { // Remove DWM from configuration, as DWM is disabled! if (coreConfiguration.WindowCaptureMode == WindowCaptureMode.Aero || coreConfiguration.WindowCaptureMode == WindowCaptureMode.AeroTransparent) @@ -420,7 +421,7 @@ namespace Greenshot.Forms checkbox_picker.Checked = false; listview_destinations.Items.Clear(); - var scaledIconSize = DpiHelper.ScaleWithDpi(coreConfiguration.IconSize, DpiHelper.GetDpi(Handle)); + var scaledIconSize = DpiCalculator.ScaleWithDpi(coreConfiguration.IconSize, NativeDpiMethods.GetDpi(Handle)); listview_destinations.ListViewItemSorter = new ListviewWithDestinationComparer(); ImageList imageList = new ImageList { diff --git a/src/Greenshot/Forms/ToolStripMenuSelectList.cs b/src/Greenshot/Forms/ToolStripMenuSelectList.cs index db6f8a184..2e2c9845c 100644 --- a/src/Greenshot/Forms/ToolStripMenuSelectList.cs +++ b/src/Greenshot/Forms/ToolStripMenuSelectList.cs @@ -23,8 +23,10 @@ using System; using System.Collections; using System.Drawing; using System.Windows.Forms; +using Dapplo.Windows.Dpi; using Greenshot.Base.Core; using Greenshot.Base.IniFile; +using Greenshot.Base.Interfaces; namespace Greenshot.Forms { @@ -35,6 +37,7 @@ namespace Greenshot.Forms { private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); private readonly bool _multiCheckAllowed; + private readonly IProvideDeviceDpi _provideDeviceDpi; private bool _updateInProgress; private static Image _defaultImage; @@ -45,25 +48,29 @@ namespace Greenshot.Forms public object Identifier { get; private set; } - public ToolStripMenuSelectList(object identifier, bool allowMultiCheck) + public ToolStripMenuSelectList(object identifier, bool allowMultiCheck, IProvideDeviceDpi provideDeviceDpi) { Identifier = identifier; CheckOnClick = false; _multiCheckAllowed = allowMultiCheck; - if (_defaultImage == null || _defaultImage.Size != CoreConfig.ScaledIconSize) + _provideDeviceDpi = provideDeviceDpi; + UpdateImage(); + } + + + private void UpdateImage() + { + var newSize = DpiCalculator.ScaleWithDpi(CoreConfig.IconSize, _provideDeviceDpi.DeviceDpi); + if (_defaultImage == null || _defaultImage.Size != newSize) { _defaultImage?.Dispose(); - _defaultImage = ImageHelper.CreateEmpty(CoreConfig.ScaledIconSize.Width, CoreConfig.ScaledIconSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb, + _defaultImage = ImageHelper.CreateEmpty(newSize.Width, newSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb, Color.Transparent, 96f, 96f); } Image = _defaultImage; } - public ToolStripMenuSelectList() : this(null, false) - { - } - private void ItemCheckStateChanged(object sender, EventArgs e) { if (_updateInProgress) diff --git a/src/Greenshot/Helpers/CaptureHelper.cs b/src/Greenshot/Helpers/CaptureHelper.cs index 20496a839..c002c62ef 100644 --- a/src/Greenshot/Helpers/CaptureHelper.cs +++ b/src/Greenshot/Helpers/CaptureHelper.cs @@ -28,12 +28,16 @@ using System.IO; using System.Text; using System.Threading; using System.Windows.Forms; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.DesktopWindowsManager; +using Dapplo.Windows.Kernel32; +using Dapplo.Windows.User32; using Greenshot.Base; using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; -using Greenshot.Base.UnmanagedHelpers; using Greenshot.Configuration; using Greenshot.Editor.Destinations; using Greenshot.Editor.Drawing; @@ -52,7 +56,7 @@ namespace Greenshot.Helpers private List _windows = new(); private WindowDetails _selectedCaptureWindow; - private Rectangle _captureRect = Rectangle.Empty; + private NativeRect _captureRect = NativeRect.Empty; private readonly bool _captureMouseCursor; private ICapture _capture; private CaptureMode _captureMode; @@ -89,7 +93,7 @@ namespace Greenshot.Helpers // Empty working set after capturing if (CoreConfig.MinimizeWorkingSetSize) { - PsAPI.EmptyWorkingSet(); + PsApi.EmptyWorkingSet(); } } @@ -116,7 +120,7 @@ namespace Greenshot.Helpers captureHelper.MakeCapture(); } - public static void CaptureRegion(bool captureMouse, Rectangle region) + public static void CaptureRegion(bool captureMouse, NativeRect region) { using CaptureHelper captureHelper = new CaptureHelper(CaptureMode.Region, captureMouse); captureHelper.MakeCapture(region); @@ -243,8 +247,8 @@ namespace Greenshot.Helpers /// /// Make Capture for region /// - /// Rectangle - private void MakeCapture(Rectangle region) + /// NativeRect + private void MakeCapture(NativeRect region) { _captureRect = region; MakeCapture(); @@ -276,7 +280,7 @@ namespace Greenshot.Helpers { case CaptureMode.Region: // Check if a region is pre-supplied! - if (Rectangle.Empty.Equals(_captureRect)) + if (_captureRect.IsEmpty) { retrieveWindowDetailsThread = PrepareForCaptureWithFeedback(); } @@ -351,7 +355,7 @@ namespace Greenshot.Helpers switch (_screenCaptureMode) { case ScreenCaptureMode.Auto: - Point mouseLocation = User32.GetCursorLocation(); + NativePoint mouseLocation = User32Api.GetCursorLocation(); foreach (Screen screen in Screen.AllScreens) { if (screen.Bounds.Contains(mouseLocation)) @@ -359,8 +363,7 @@ namespace Greenshot.Helpers _capture = WindowCapture.CaptureRectangle(_capture, screen.Bounds); captureTaken = true; // As the screen shot might be on a different monitor we need to correct the mouse location - var correctedCursorLocation = _capture.CursorLocation; - correctedCursorLocation.Offset(-screen.Bounds.Location.X, -screen.Bounds.Location.Y); + var correctedCursorLocation = _capture.CursorLocation.Offset(-screen.Bounds.Location.X, -screen.Bounds.Location.Y); _capture.CursorLocation = correctedCursorLocation; break; } @@ -504,14 +507,12 @@ namespace Greenshot.Helpers // Set capture title, fixing bug #3569703 foreach (WindowDetails window in WindowDetails.GetVisibleWindows()) { - Point estimatedLocation = new Point(CoreConfig.LastCapturedRegion.X + CoreConfig.LastCapturedRegion.Width / 2, + NativePoint estimatedLocation = new NativePoint(CoreConfig.LastCapturedRegion.X + CoreConfig.LastCapturedRegion.Width / 2, CoreConfig.LastCapturedRegion.Y + CoreConfig.LastCapturedRegion.Height / 2); - if (window.Contains(estimatedLocation)) - { - _selectedCaptureWindow = window; - _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; - break; - } + if (!window.Contains(estimatedLocation)) continue; + _selectedCaptureWindow = window; + _capture.CaptureDetails.Title = _selectedCaptureWindow.Text; + break; } // Move cursor, fixing bug #3569703 @@ -526,7 +527,7 @@ namespace Greenshot.Helpers break; case CaptureMode.Region: // Check if a region is pre-supplied! - if (Rectangle.Empty.Equals(_captureRect)) + if (_captureRect.IsEmpty) { _capture = WindowCapture.CaptureScreen(_capture); _capture.CaptureDetails.AddMetaData("source", "screen"); @@ -685,7 +686,7 @@ namespace Greenshot.Helpers if (_capture.CaptureDetails.CaptureMode == CaptureMode.Text) { - var selectionRectangle = new Rectangle(Point.Empty, _capture.Image.Size); + var selectionRectangle = new NativeRect(NativePoint.Empty, _capture.Image.Size); var ocrInfo = _capture.CaptureDetails.OcrInformation; if (ocrInfo != null) { @@ -712,7 +713,10 @@ namespace Greenshot.Helpers textResult.AppendLine(); } - Clipboard.SetText(textResult.ToString()); + if (textResult.Length > 0) + { + Clipboard.SetText(textResult.ToString()); + } } // Disable capturing @@ -873,7 +877,7 @@ namespace Greenshot.Helpers /// WindowDetails with the target Window OR a replacement public static WindowDetails SelectCaptureWindow(WindowDetails windowToCapture) { - Rectangle windowRectangle = windowToCapture.WindowRectangle; + NativeRect windowRectangle = windowToCapture.WindowRectangle; if (windowRectangle.Width == 0 || windowRectangle.Height == 0) { Log.WarnFormat("Window {0} has nothing to capture, using workaround to find other window of same process.", windowToCapture.Text); @@ -939,10 +943,10 @@ namespace Greenshot.Helpers captureForWindow = new Capture(); } - Rectangle windowRectangle = windowToCapture.WindowRectangle; + NativeRect windowRectangle = windowToCapture.WindowRectangle; // When Vista & DWM (Aero) enabled - bool dwmEnabled = DWM.IsDwmEnabled; + bool dwmEnabled = DwmApi.IsDwmEnabled; // get process name to be able to exclude certain processes from certain capture modes using (Process process = windowToCapture.Process) { @@ -1024,7 +1028,7 @@ namespace Greenshot.Helpers Log.InfoFormat("Capturing window with mode {0}", windowCaptureMode); bool captureTaken = false; - windowRectangle.Intersect(captureForWindow.ScreenBounds); + windowRectangle = windowRectangle.Intersect(captureForWindow.ScreenBounds); // Try to capture while (!captureTaken) { @@ -1216,8 +1220,7 @@ namespace Greenshot.Helpers // save for re-capturing later and show recapture context menu option // Important here is that the location needs to be offsetted back to screen coordinates! - Rectangle tmpRectangle = _captureRect; - tmpRectangle.Offset(_capture.ScreenBounds.Location.X, _capture.ScreenBounds.Location.Y); + NativeRect tmpRectangle = _captureRect.Offset(_capture.ScreenBounds.Location.X, _capture.ScreenBounds.Location.Y); CoreConfig.LastCapturedRegion = tmpRectangle; } diff --git a/src/Greenshot/Helpers/IECaptureHelper.cs b/src/Greenshot/Helpers/IECaptureHelper.cs index 3bb5e4eee..0da3d35dc 100644 --- a/src/Greenshot/Helpers/IECaptureHelper.cs +++ b/src/Greenshot/Helpers/IECaptureHelper.cs @@ -25,14 +25,17 @@ using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Runtime.InteropServices; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; +using Dapplo.Windows.Messages; +using Dapplo.Windows.User32; +using Dapplo.Windows.User32.Enums; using Greenshot.Base.Controls; using Greenshot.Base.Core; using Greenshot.Base.IEInterop; using Greenshot.Base.IniFile; using Greenshot.Base.Interfaces; using Greenshot.Base.Interop; -using Greenshot.Base.UnmanagedHelpers; -using Greenshot.Base.UnmanagedHelpers.Enums; using Greenshot.Configuration; using Greenshot.Helpers.IEInterop; using log4net; @@ -205,7 +208,7 @@ namespace Greenshot.Helpers return null; } - uint windowMessage = User32.RegisterWindowMessage("WM_HTML_GETOBJECT"); + uint windowMessage = WindowsMessage.RegisterWindowsMessage("WM_HTML_GETOBJECT"); if (windowMessage == 0) { Log.WarnFormat("Couldn't register WM_HTML_GETOBJECT"); @@ -213,7 +216,7 @@ namespace Greenshot.Helpers } Log.DebugFormat("Trying WM_HTML_GETOBJECT on {0}", ieServer.ClassName); - User32.SendMessageTimeout(ieServer.Handle, windowMessage, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_NORMAL, 5000, out var response); + User32Api.SendMessageTimeout(ieServer.Handle, windowMessage, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.Normal, 5000, out UIntPtr response); IHTMLDocument2 document2; if (response != UIntPtr.Zero) { @@ -719,14 +722,14 @@ namespace Greenshot.Helpers int horizontalPage = 0; // The location of the browser, used as the destination into the bitmap target - Point targetOffset = new Point(); + NativePoint targetOffset = NativePoint.Empty; // Loop of the pages and make a copy of the visible viewport while (horizontalPage * viewportWidth < pageWidth) { // Scroll to location documentContainer.ScrollLeft = viewportWidth * horizontalPage; - targetOffset.X = documentContainer.ScrollLeft; + targetOffset = targetOffset.ChangeX(documentContainer.ScrollLeft); // Variable used for looping vertically int verticalPage = 0; @@ -735,11 +738,11 @@ namespace Greenshot.Helpers // Scroll to location documentContainer.ScrollTop = viewportHeight * verticalPage; //Shoot visible window - targetOffset.Y = documentContainer.ScrollTop; + targetOffset = targetOffset.ChangeY(documentContainer.ScrollTop); // Draw the captured fragment to the target, but "crop" the scrollbars etc while capturing - Size viewPortSize = new Size(viewportWidth, viewportHeight); - Rectangle clientRectangle = new Rectangle(documentContainer.SourceLocation, viewPortSize); + NativeSize viewPortSize = new NativeSize(viewportWidth, viewportHeight); + NativeRect clientRectangle = new NativeRect(documentContainer.SourceLocation, viewPortSize); Image fragment = contentWindowDetails.PrintWindow(); if (fragment != null) { @@ -747,7 +750,7 @@ namespace Greenshot.Helpers try { // cut all junk, due to IE "border" we need to remove some parts - Rectangle viewportRect = documentContainer.ViewportRectangle; + NativeRect viewportRect = documentContainer.ViewportRectangle; if (!viewportRect.IsEmpty) { Log.DebugFormat("Cropping to viewport: {0}", viewportRect); @@ -758,9 +761,9 @@ namespace Greenshot.Helpers // Crop to clientRectangle if (ImageHelper.Crop(ref fragment, ref clientRectangle)) { - Point targetLocation = new Point(documentContainer.DestinationLocation.X, documentContainer.DestinationLocation.Y); + NativePoint targetLocation = new NativePoint(documentContainer.DestinationLocation.X, documentContainer.DestinationLocation.Y); Log.DebugFormat("Fragment targetLocation is {0}", targetLocation); - targetLocation.Offset(targetOffset); + targetLocation = targetLocation.Offset(targetOffset); Log.DebugFormat("After offsetting the fragment targetLocation is {0}", targetLocation); Log.DebugFormat("Drawing fragment of size {0} to {1}", fragment.Size, targetLocation); graphicsTarget.DrawImage(fragment, targetLocation); diff --git a/src/Greenshot/Helpers/IEInterop/IEContainer.cs b/src/Greenshot/Helpers/IEInterop/IEContainer.cs index 77e20d695..178dc5643 100644 --- a/src/Greenshot/Helpers/IEInterop/IEContainer.cs +++ b/src/Greenshot/Helpers/IEInterop/IEContainer.cs @@ -24,6 +24,8 @@ using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.Runtime.InteropServices; +using Dapplo.Windows.Common.Extensions; +using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.IEInterop; using log4net; @@ -38,12 +40,12 @@ namespace Greenshot.Helpers.IEInterop private static readonly Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046"); private static readonly Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"); private static int _counter; + private readonly NativePoint _startLocation = NativePoint.Empty; private IHTMLDocument2 _document2; private IHTMLDocument3 _document3; - private Point _sourceLocation; - private Point _destinationLocation; - private Point _startLocation = Point.Empty; - private Rectangle _viewportRectangle = Rectangle.Empty; + private NativePoint _sourceLocation; + private NativePoint _destinationLocation; + private NativeRect _viewportRectangle = NativeRect.Empty; private bool _isDtd; private DocumentContainer _parent; private WindowDetails _contentWindow; @@ -88,15 +90,15 @@ namespace Greenshot.Helpers.IEInterop // Calculate startLocation for the frames IHTMLWindow2 window2 = document2.parentWindow; IHTMLWindow3 window3 = (IHTMLWindow3) window2; - Point contentWindowLocation = contentWindow.WindowRectangle.Location; + NativePoint contentWindowLocation = contentWindow.WindowRectangle.Location; int x = window3.screenLeft - contentWindowLocation.X; int y = window3.screenTop - contentWindowLocation.Y; // Release IHTMLWindow 2+3 com objects - releaseCom(window2); - releaseCom(window3); + ReleaseCom(window2); + ReleaseCom(window3); - _startLocation = new Point(x, y); + _startLocation = new NativePoint(x, y); Init(document2, contentWindow); } @@ -110,7 +112,7 @@ namespace Greenshot.Helpers.IEInterop /// Helper method to release com objects /// /// - private void releaseCom(object comObject) + private void ReleaseCom(object comObject) { if (comObject != null) { @@ -148,7 +150,7 @@ namespace Greenshot.Helpers.IEInterop // Do not release IHTMLDocument5 com object, as this also gives problems with the document2! //Marshal.ReleaseComObject(document5); - Rectangle clientRectangle = contentWindow.WindowRectangle; + NativeRect clientRectangle = contentWindow.WindowRectangle; try { IHTMLWindow2 window2 = document2.parentWindow; @@ -180,20 +182,20 @@ namespace Greenshot.Helpers.IEInterop int diffY = clientRectangle.Height - ClientHeight; // If there is a border around the inner window, the diff == 4 // If there is a border AND a scrollbar the diff == 20 - if ((diffX == 4 || diffX >= 20) && (diffY == 4 || diffY >= 20)) + if (diffX is 4 or >= 20 && diffY is 4 or >= 20) { - Point viewportOffset = new Point(2, 2); - Size viewportSize = new Size(ClientWidth, ClientHeight); - _viewportRectangle = new Rectangle(viewportOffset, viewportSize); + var viewportOffset = new NativePoint(2, 2); + var viewportSize = new NativeSize(ClientWidth, ClientHeight); + _viewportRectangle = new NativeRect(viewportOffset, viewportSize); LOG.DebugFormat("viewportRect {0}", _viewportRectangle); } } LOG.DebugFormat("Zoomlevel {0}, {1}", _zoomLevelX, _zoomLevelY); // Release com objects - releaseCom(window2); - releaseCom(screen); - releaseCom(screen2); + ReleaseCom(window2); + ReleaseCom(screen); + ReleaseCom(screen2); } catch (Exception e) { @@ -223,8 +225,8 @@ namespace Greenshot.Helpers.IEInterop LOG.Warn("Problem while trying to get document url!", e); } - _sourceLocation = new Point(ScaleX(_startLocation.X), ScaleY(_startLocation.Y)); - _destinationLocation = new Point(ScaleX(_startLocation.X), ScaleY(_startLocation.Y)); + _sourceLocation = new NativePoint(ScaleX(_startLocation.X), ScaleY(_startLocation.Y)); + _destinationLocation = new NativePoint(ScaleX(_startLocation.X), ScaleY(_startLocation.Y)); if (_parent != null) { @@ -252,7 +254,7 @@ namespace Greenshot.Helpers.IEInterop } // Clean up frameWindow - releaseCom(frameWindow); + ReleaseCom(frameWindow); } catch (Exception e) { @@ -261,7 +263,7 @@ namespace Greenshot.Helpers.IEInterop } // Clean up collection - releaseCom(frameCollection); + ReleaseCom(frameCollection); } catch (Exception ex) { @@ -277,7 +279,7 @@ namespace Greenshot.Helpers.IEInterop { CorrectFrameLocations(frameElement); // Clean up frameElement - releaseCom(frameElement); + ReleaseCom(frameElement); } catch (Exception e) { @@ -292,7 +294,7 @@ namespace Greenshot.Helpers.IEInterop } /// - /// Corrent the frame locations with the information + /// Correct the frame locations with the information /// /// private void CorrectFrameLocations(IHTMLElement frameElement) @@ -309,22 +311,22 @@ namespace Greenshot.Helpers.IEInterop // Release element, but prevent the frameElement to be released if (oldElement != null) { - releaseCom(oldElement); + ReleaseCom(oldElement); } oldElement = element; } while (element != null); - Point elementLocation = new Point((int) x, (int) y); + var elementLocation = new NativePoint((int) x, (int) y); IHTMLElement2 element2 = (IHTMLElement2) frameElement; IHTMLRect rec = element2.getBoundingClientRect(); - Point elementBoundingLocation = new Point(rec.left, rec.top); + var elementBoundingLocation = new NativePoint(rec.left, rec.top); // Release IHTMLRect - releaseCom(rec); + ReleaseCom(rec); LOG.DebugFormat("Looking for iframe to correct at {0}", elementBoundingLocation); foreach (DocumentContainer foundFrame in _frames) { - Point frameLocation = foundFrame.SourceLocation; + NativePoint frameLocation = foundFrame.SourceLocation; if (frameLocation.Equals(elementBoundingLocation)) { // Match found, correcting location @@ -425,7 +427,7 @@ namespace Greenshot.Helpers.IEInterop } } - public Rectangle ViewportRectangle => _viewportRectangle; + public NativeRect ViewportRectangle => _viewportRectangle; public WindowDetails ContentWindow => _contentWindow; @@ -473,7 +475,7 @@ namespace Greenshot.Helpers.IEInterop var element = !_isDtd ? _document2.body : _document3.documentElement; element.setAttribute(attribute, value, 1); // Release IHTMLElement com object - releaseCom(element); + ReleaseCom(element); } /// @@ -486,7 +488,7 @@ namespace Greenshot.Helpers.IEInterop var element = !_isDtd ? _document2.body : _document3.documentElement; var retVal = element.getAttribute(attribute, 1); // Release IHTMLElement com object - releaseCom(element); + ReleaseCom(element); return retVal; } @@ -515,15 +517,15 @@ namespace Greenshot.Helpers.IEInterop public int ScrollHeight => ScaleY(GetAttributeAsInt("scrollHeight")); - public Point SourceLocation + public NativePoint SourceLocation { get { return _sourceLocation; } set { _sourceLocation = value; } } - public Size SourceSize => new Size(ClientWidth, ClientHeight); + public NativeSize SourceSize => new NativeSize(ClientWidth, ClientHeight); - public Rectangle SourceRectangle => new Rectangle(SourceLocation, SourceSize); + public NativeRect SourceRectangle => new NativeRect(SourceLocation, SourceSize); public int SourceLeft => _sourceLocation.X; @@ -533,26 +535,26 @@ namespace Greenshot.Helpers.IEInterop public int SourceBottom => _sourceLocation.Y + ClientHeight; - public Point DestinationLocation + public NativePoint DestinationLocation { get { return _destinationLocation; } set { _destinationLocation = value; } } - public Size DestinationSize => new Size(ScrollWidth, ScrollHeight); + public NativeSize DestinationSize => new NativeSize(ScrollWidth, ScrollHeight); - public Rectangle DestinationRectangle => new Rectangle(DestinationLocation, DestinationSize); + public NativeRect DestinationRectangle => new NativeRect(DestinationLocation, DestinationSize); public int DestinationLeft { get { return _destinationLocation.X; } - set { _destinationLocation.X = value; } + set { _destinationLocation = _destinationLocation.ChangeX(value); } } public int DestinationTop { get { return _destinationLocation.Y; } - set { _destinationLocation.Y = value; } + set { _destinationLocation = _destinationLocation.ChangeY(value); } } public int DestinationRight => _destinationLocation.X + ScrollWidth; diff --git a/src/Greenshot/Helpers/SoundHelper.cs b/src/Greenshot/Helpers/SoundHelper.cs index 69e42850f..796aec077 100644 --- a/src/Greenshot/Helpers/SoundHelper.cs +++ b/src/Greenshot/Helpers/SoundHelper.cs @@ -24,10 +24,10 @@ using System.Reflection; using System.Resources; using System.Runtime.InteropServices; using System.IO; +using Dapplo.Windows.Multimedia; +using Dapplo.Windows.Multimedia.Enums; using Greenshot.Base.Core; using Greenshot.Base.IniFile; -using Greenshot.Base.UnmanagedHelpers; -using Greenshot.Base.UnmanagedHelpers.Enums; using log4net; namespace Greenshot.Helpers @@ -82,10 +82,10 @@ namespace Greenshot.Helpers if (_soundBuffer != null) { //Thread playSoundThread = new Thread(delegate() { - SoundFlags flags = SoundFlags.SND_ASYNC | SoundFlags.SND_MEMORY | SoundFlags.SND_NOWAIT | SoundFlags.SND_NOSTOP; + var flags = SoundSettings.Async | SoundSettings.Memory| SoundSettings.NoWait| SoundSettings.NoStop; try { - if (_gcHandle != null) WinMM.PlaySound(_gcHandle.Value.AddrOfPinnedObject(), (UIntPtr) 0, (uint) flags); + if (_gcHandle != null) WinMm.Play(_gcHandle.Value.AddrOfPinnedObject(), flags); } catch (Exception e) { @@ -105,14 +105,14 @@ namespace Greenshot.Helpers { if (_gcHandle != null) { - WinMM.PlaySound(null, (UIntPtr) 0, 0); + WinMm.StopPlaying(); _gcHandle.Value.Free(); _gcHandle = null; } } catch (Exception e) { - Log.Error("Error in deinitialize.", e); + Log.Error("Error in de-initialize.", e); } } } From acdbdeca3c542d3f2119808e8373a7dd7f2c4dd8 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 13 Apr 2022 15:32:36 +0200 Subject: [PATCH 187/232] Fix drawing (dragging) a new element on the surface, which happened after the previous larger PR. Note: the adorners are somehow not visible yet. [skip ci] --- .../Drawing/Adorners/MoveAdorner.cs | 2 +- .../Drawing/Adorners/ResizeAdorner.cs | 2 +- src/Greenshot.Editor/Drawing/CropContainer.cs | 2 +- .../Drawing/DrawableContainer.cs | 10 +- src/Greenshot.Editor/Drawing/LineContainer.cs | 2 +- src/Greenshot.Editor/Forms/ImageEditorForm.cs | 9 +- src/Greenshot.Editor/Helpers/ScaleHelper.cs | 192 ++++++------------ 7 files changed, 72 insertions(+), 147 deletions(-) diff --git a/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs index 46fcdb1b0..61fc8de11 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/MoveAdorner.cs @@ -78,7 +78,7 @@ namespace Greenshot.Editor.Drawing.Adorners _boundsAfterResize = _boundsBeforeResize; // calculate scaled rectangle - ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); + _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); // apply scaled bounds to this DrawableContainer Owner.ApplyBounds(_boundsAfterResize); diff --git a/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs index aaad53355..523684232 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs @@ -101,7 +101,7 @@ namespace Greenshot.Editor.Drawing.Adorners _boundsAfterResize = _boundsBeforeResize; // calculate scaled rectangle - ScaleHelper.Scale(ref _boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); + _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); // apply scaled bounds to this DrawableContainer Owner.ApplyBounds(_boundsAfterResize); diff --git a/src/Greenshot.Editor/Drawing/CropContainer.cs b/src/Greenshot.Editor/Drawing/CropContainer.cs index f72f4e72c..2aee4252f 100644 --- a/src/Greenshot.Editor/Drawing/CropContainer.cs +++ b/src/Greenshot.Editor/Drawing/CropContainer.cs @@ -250,7 +250,7 @@ namespace Greenshot.Editor.Drawing break; } } - ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); + _boundsAfterResize = ScaleHelper.Scale(_boundsBeforeResize, x, y, GetAngleRoundProcessor()); // apply scaled bounds to this DrawableContainer ApplyBounds(_boundsAfterResize); diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index f80831df2..be4638164 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -488,7 +488,7 @@ namespace Greenshot.Editor.Drawing public virtual bool IsConfirmable => false; /// - /// Make a following bounds change on this drawablecontainer undoable! + /// Make a following bounds change on this DrawableContainer undoable! /// /// true means allow the moves to be merged public virtual void MakeBoundsChangeUndoable(bool allowMerge) @@ -514,7 +514,7 @@ namespace Greenshot.Editor.Drawing /// true if the event is handled, false if the surface needs to handle it public virtual bool HandleMouseDown(int x, int y) { - _boundsBeforeResize = _boundsBeforeResize.MoveTo(x, y); + _boundsBeforeResize = Bounds.MoveTo(x, y); Left = x; Top = y; return true; @@ -531,9 +531,9 @@ namespace Greenshot.Editor.Drawing Invalidate(); // reset "workbench" rectangle to current bounds - _boundsAfterResize = _boundsBeforeResize; + _boundsAfterResize = new NativeRectFloat(_boundsBeforeResize.Left, _boundsBeforeResize.Top, x - _boundsAfterResize.Left, y - _boundsAfterResize.Top); - ScaleHelper.Scale(_boundsBeforeResize, x, y, ref _boundsAfterResize, GetAngleRoundProcessor()); + _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, x, y, GetAngleRoundProcessor()); // apply scaled bounds to this DrawableContainer ApplyBounds(_boundsAfterResize); @@ -668,7 +668,7 @@ namespace Greenshot.Editor.Drawing protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() { - return ScaleHelper.ShapeAngleRoundBehavior.Instance; + return ScaleHelper.ShapeAngleRoundBehavior.INSTANCE; } public virtual bool HasContextMenu => true; diff --git a/src/Greenshot.Editor/Drawing/LineContainer.cs b/src/Greenshot.Editor/Drawing/LineContainer.cs index 5029870a0..ef4a68707 100644 --- a/src/Greenshot.Editor/Drawing/LineContainer.cs +++ b/src/Greenshot.Editor/Drawing/LineContainer.cs @@ -117,7 +117,7 @@ namespace Greenshot.Editor.Drawing protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() { - return ScaleHelper.LineAngleRoundBehavior.Instance; + return ScaleHelper.LineAngleRoundBehavior.INSTANCE; } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index 9c627accc..87c3813c7 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -1096,13 +1096,8 @@ namespace Greenshot.Editor.Forms /// /// This is a "work-around" for the MouseWheel event which doesn't get to the panel /// - /// - /// - /// - /// This is a "work-around" for the MouseWheel event which doesn't get to the panel - /// - /// - /// + /// object + /// MouseEventArgs private void PanelMouseWheel(object sender, MouseEventArgs e) { if (System.Windows.Forms.Control.ModifierKeys.Equals(Keys.Control)) diff --git a/src/Greenshot.Editor/Helpers/ScaleHelper.cs b/src/Greenshot.Editor/Helpers/ScaleHelper.cs index b75e8caad..4f4e7dc7a 100644 --- a/src/Greenshot.Editor/Helpers/ScaleHelper.cs +++ b/src/Greenshot.Editor/Helpers/ScaleHelper.cs @@ -59,13 +59,13 @@ namespace Greenshot.Editor.Helpers /// the target size of the element /// in case the aspect ratio of currentSize and targetSize differs: shall the scaled size fit into targetSize (i.e. that one of its dimensions is smaller - false) or vice versa (true) /// a new SizeF object indicating the width and height the element should be scaled to - public static SizeF GetScaledSize(SizeF currentSize, SizeF targetSize, bool crop) + public static NativeSizeFloat GetScaledSize(NativeSizeFloat currentSize, NativeSizeFloat targetSize, bool crop) { float wFactor = targetSize.Width / currentSize.Width; float hFactor = targetSize.Height / currentSize.Height; float factor = crop ? Math.Max(wFactor, hFactor) : Math.Min(wFactor, hFactor); - return new SizeF(currentSize.Width * factor, currentSize.Height * factor); + return new NativeSizeFloat(currentSize.Width * factor, currentSize.Height * factor); } /// @@ -75,58 +75,39 @@ namespace Greenshot.Editor.Helpers /// the rectangle reference for alignment of the element /// the System.Drawing.ContentAlignment value indicating how the element is to be aligned should the width or height differ from targetSize /// a new RectangleF object with Location aligned aligned to targetRect - public static RectangleF GetAlignedRectangle(RectangleF currentRect, RectangleF targetRect, ContentAlignment alignment) + public static NativeRectFloat GetAlignedRectangle(NativeRectFloat currentRect, NativeRectFloat targetRect, ContentAlignment alignment) { - RectangleF newRect = new RectangleF(targetRect.Location, currentRect.Size); - switch (alignment) + var newRect = new NativeRectFloat(targetRect.Location, currentRect.Size); + return alignment switch { - case ContentAlignment.TopCenter: - newRect.X = (targetRect.Width - currentRect.Width) / 2; - break; - case ContentAlignment.TopRight: - newRect.X = targetRect.Width - currentRect.Width; - break; - case ContentAlignment.MiddleLeft: - newRect.Y = (targetRect.Height - currentRect.Height) / 2; - break; - case ContentAlignment.MiddleCenter: - newRect.Y = (targetRect.Height - currentRect.Height) / 2; - newRect.X = (targetRect.Width - currentRect.Width) / 2; - break; - case ContentAlignment.MiddleRight: - newRect.Y = (targetRect.Height - currentRect.Height) / 2; - newRect.X = targetRect.Width - currentRect.Width; - break; - case ContentAlignment.BottomLeft: - newRect.Y = targetRect.Height - currentRect.Height; - break; - case ContentAlignment.BottomCenter: - newRect.Y = targetRect.Height - currentRect.Height; - newRect.X = (targetRect.Width - currentRect.Width) / 2; - break; - case ContentAlignment.BottomRight: - newRect.Y = targetRect.Height - currentRect.Height; - newRect.X = targetRect.Width - currentRect.Width; - break; - } - - return newRect; + // TODO: Can ContentAlignment be replaced with Positions? + ContentAlignment.TopCenter => newRect.ChangeX((targetRect.Width - currentRect.Width) / 2), + ContentAlignment.TopRight => newRect.ChangeX(targetRect.Width - currentRect.Width), + ContentAlignment.MiddleLeft => newRect.ChangeY((targetRect.Height - currentRect.Height) / 2), + ContentAlignment.MiddleCenter => newRect.ChangeY((targetRect.Height - currentRect.Height) / 2).ChangeX((targetRect.Width - currentRect.Width) / 2), + ContentAlignment.MiddleRight => newRect.ChangeY((targetRect.Height - currentRect.Height) / 2).ChangeX(targetRect.Width - currentRect.Width), + ContentAlignment.BottomLeft => newRect.ChangeY(targetRect.Height - currentRect.Height), + ContentAlignment.BottomCenter => newRect.ChangeY(targetRect.Height - currentRect.Height).ChangeX((targetRect.Width - currentRect.Width) / 2), + ContentAlignment.BottomRight => newRect.ChangeY(targetRect.Height - currentRect.Height).ChangeX(targetRect.Width - currentRect.Width), + _ => newRect + }; } /// /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) /// - /// bounds of the current rectangle, scaled values will be written to this reference + /// bounds of the current rectangle /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT /// coordinates of the used handle/gripper /// ScaleOptions to use when scaling - public static void Scale(ref NativeRectFloat originalRectangle, Positions resizeHandlePosition, NativePointFloat resizeHandleCoords, ScaleOptions? options) + /// NativeRectFloat scaled originalRectangle + public static NativeRectFloat Scale(NativeRectFloat originalRectangle, Positions resizeHandlePosition, NativePointFloat resizeHandleCoords, ScaleOptions? options) { options ??= GetScaleOptions(); if ((options & ScaleOptions.Rational) == ScaleOptions.Rational) { - AdjustCoordsForRationalScale(originalRectangle, resizeHandlePosition, ref resizeHandleCoords); + resizeHandleCoords = AdjustCoordsForRationalScale(originalRectangle, resizeHandlePosition, resizeHandleCoords); } if ((options & ScaleOptions.Centered) == ScaleOptions.Centered) @@ -135,96 +116,40 @@ namespace Greenshot.Editor.Helpers float rectCenterX = originalRectangle.Left + originalRectangle.Width / 2; float rectCenterY = originalRectangle.Top + originalRectangle.Height / 2; // scale rectangle using handle coordinates - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + originalRectangle = Scale(originalRectangle, resizeHandlePosition, resizeHandleCoords); // mirror handle coordinates via rectangle center coordinates resizeHandleCoords = resizeHandleCoords.Offset(-2 * (resizeHandleCoords.X - rectCenterX), -2 * (resizeHandleCoords.Y - rectCenterY)); // scale again with opposing handle and mirrored coordinates resizeHandlePosition = (Positions) ((((int) resizeHandlePosition) + 4) % 8); - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + originalRectangle = Scale(originalRectangle, resizeHandlePosition, resizeHandleCoords); } else { - Scale(ref originalRectangle, resizeHandlePosition, resizeHandleCoords); + originalRectangle = Scale(originalRectangle, resizeHandlePosition, resizeHandleCoords); } + + return originalRectangle; } /// /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) /// - /// bounds of the current rectangle, scaled values will be written to this reference + /// bounds of the current rectangle /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT /// coordinates of the used handle/gripper - private static void Scale(ref NativeRectFloat originalRectangle, Positions resizeHandlePosition, NativePointFloat resizeHandleCoords) + /// NativeRectFloat with the scaled originalRectangle + private static NativeRectFloat Scale(NativeRectFloat originalRectangle, Positions resizeHandlePosition, NativePointFloat resizeHandleCoords) { - switch (resizeHandlePosition) + return resizeHandlePosition switch { - case Positions.TopLeft: - originalRectangle = new NativeRectFloat( - resizeHandleCoords.X, - resizeHandleCoords.Y, - originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X, - originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y); - break; - - case Positions.TopCenter: - originalRectangle = new NativeRectFloat( - originalRectangle.X, - resizeHandleCoords.Y, - originalRectangle.Width, - originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y); - break; - - case Positions.TopRight: - originalRectangle = new NativeRectFloat( - originalRectangle.X, - resizeHandleCoords.Y, - resizeHandleCoords.X - originalRectangle.Left, - originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y); - break; - - case Positions.MiddleLeft: - originalRectangle = new NativeRectFloat( - resizeHandleCoords.X, - originalRectangle.Y, - originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X, - originalRectangle.Height); - break; - - case Positions.MiddleRight: - originalRectangle = new NativeRectFloat( - originalRectangle.X, - originalRectangle.Y, - resizeHandleCoords.X - originalRectangle.Left, - originalRectangle.Height); - break; - - case Positions.BottomLeft: - originalRectangle = new NativeRectFloat( - resizeHandleCoords.X, - originalRectangle.Y, - originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X, - resizeHandleCoords.Y - originalRectangle.Top); - break; - - case Positions.BottomCenter: - originalRectangle = new NativeRectFloat( - originalRectangle.X, - originalRectangle.Y, - originalRectangle.Width, - resizeHandleCoords.Y - originalRectangle.Top); - break; - - case Positions.BottomRight: - originalRectangle = new NativeRectFloat( - originalRectangle.X, - originalRectangle.Y, - resizeHandleCoords.X - originalRectangle.Left, - resizeHandleCoords.Y - originalRectangle.Top); - break; - - default: - throw new ArgumentException("Position cannot be handled: " + resizeHandlePosition); - } + Positions.TopLeft => new NativeRectFloat(resizeHandleCoords.X, resizeHandleCoords.Y, originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X, originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y), + Positions.TopCenter => new NativeRectFloat(originalRectangle.X, resizeHandleCoords.Y, originalRectangle.Width, originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y), + Positions.TopRight => new NativeRectFloat(originalRectangle.X, resizeHandleCoords.Y, resizeHandleCoords.X - originalRectangle.Left, originalRectangle.Top + originalRectangle.Height - resizeHandleCoords.Y), + Positions.MiddleLeft => new NativeRectFloat(resizeHandleCoords.X, originalRectangle.Y, originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X, originalRectangle.Height), + Positions.MiddleRight => new NativeRectFloat(originalRectangle.X, originalRectangle.Y, resizeHandleCoords.X - originalRectangle.Left, originalRectangle.Height), Positions.BottomLeft => new NativeRectFloat(resizeHandleCoords.X, originalRectangle.Y, originalRectangle.Left + originalRectangle.Width - resizeHandleCoords.X, resizeHandleCoords.Y - originalRectangle.Top), + Positions.BottomCenter => new NativeRectFloat(originalRectangle.X, originalRectangle.Y, originalRectangle.Width, resizeHandleCoords.Y - originalRectangle.Top), Positions.BottomRight => new NativeRectFloat(originalRectangle.X, originalRectangle.Y, resizeHandleCoords.X - originalRectangle.Left, resizeHandleCoords.Y - originalRectangle.Top), + _ => throw new ArgumentException("Position cannot be handled: " + resizeHandlePosition) + }; } /// @@ -235,37 +160,40 @@ namespace Greenshot.Editor.Helpers /// /// bounds of the current rectangle /// position of the handle/gripper being used for resized, see Position - /// coordinates of the used handle/gripper, adjusted coordinates will be written to this reference - private static void AdjustCoordsForRationalScale(NativeRectFloat originalRectangle, Positions resizeHandlePosition, ref NativePointFloat resizeHandleCoords) + /// coordinates of the used handle/gripper + /// NativePointFloat with the adjusted coordinates + private static NativePointFloat AdjustCoordsForRationalScale(NativeRectFloat originalRectangle, Positions resizeHandlePosition, NativePointFloat resizeHandleCoords) { - SizeF selectedRectangle, newSize; + NativeSizeFloat selectedRectangle, newSize; switch (resizeHandlePosition) { case Positions.TopLeft: - selectedRectangle = new SizeF(originalRectangle.Right - resizeHandleCoords.X, originalRectangle.Bottom - resizeHandleCoords.Y); + selectedRectangle = new NativeSizeFloat(originalRectangle.Right - resizeHandleCoords.X, originalRectangle.Bottom - resizeHandleCoords.Y); newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); resizeHandleCoords = new NativePointFloat(originalRectangle.Right - newSize.Width, originalRectangle.Bottom - newSize.Height); break; case Positions.TopRight: - selectedRectangle = new SizeF(resizeHandleCoords.X - originalRectangle.Left, originalRectangle.Bottom - resizeHandleCoords.Y); + selectedRectangle = new NativeSizeFloat(resizeHandleCoords.X - originalRectangle.Left, originalRectangle.Bottom - resizeHandleCoords.Y); newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); resizeHandleCoords = new NativePointFloat(originalRectangle.Left + newSize.Width, originalRectangle.Bottom - newSize.Height); break; case Positions.BottomLeft: - selectedRectangle = new SizeF(originalRectangle.Right - resizeHandleCoords.X, resizeHandleCoords.Y - originalRectangle.Top); + selectedRectangle = new NativeSizeFloat(originalRectangle.Right - resizeHandleCoords.X, resizeHandleCoords.Y - originalRectangle.Top); newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); resizeHandleCoords = new NativePointFloat(originalRectangle.Right - newSize.Width, originalRectangle.Top + newSize.Height); break; case Positions.BottomRight: - selectedRectangle = new SizeF(resizeHandleCoords.X - originalRectangle.Left, resizeHandleCoords.Y - originalRectangle.Top); + selectedRectangle = new NativeSizeFloat(resizeHandleCoords.X - originalRectangle.Left, resizeHandleCoords.Y - originalRectangle.Top); newSize = GetNewSizeForRationalScale(originalRectangle.Size, selectedRectangle); resizeHandleCoords = new NativePointFloat(originalRectangle.Left + newSize.Width, originalRectangle.Top + newSize.Height); break; } + + return resizeHandleCoords; } /// @@ -299,21 +227,21 @@ namespace Greenshot.Editor.Helpers return newSize; } - public static void Scale(NativeRect boundsBeforeResize, int cursorX, int cursorY, ref NativeRectFloat boundsAfterResize) + public static NativeRectFloat Scale(NativeRect boundsBeforeResize, int cursorX, int cursorY) { - Scale(boundsBeforeResize, cursorX, cursorY, ref boundsAfterResize, null); + return Scale(boundsBeforeResize, cursorX, cursorY, null); } - public static void Scale(NativeRect boundsBeforeResize, int cursorX, int cursorY, ref NativeRectFloat boundsAfterResize, IDoubleProcessor angleRoundBehavior) + public static NativeRectFloat Scale(NativeRect boundsBeforeResize, int cursorX, int cursorY, IDoubleProcessor angleRoundBehavior) { - Scale(boundsBeforeResize, Positions.TopLeft, cursorX, cursorY, ref boundsAfterResize, angleRoundBehavior); + return Scale(boundsBeforeResize, Positions.TopLeft, cursorX, cursorY, angleRoundBehavior); } - public static void Scale(NativeRect boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, ref NativeRectFloat boundsAfterResize, - IDoubleProcessor angleRoundBehavior) + public static NativeRectFloat Scale(NativeRect boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, IDoubleProcessor angleRoundBehavior) { ScaleOptions opts = GetScaleOptions(); + NativeRectFloat result = boundsBeforeResize; bool rationalScale = (opts & ScaleOptions.Rational) == ScaleOptions.Rational; bool centeredScale = (opts & ScaleOptions.Centered) == ScaleOptions.Centered; @@ -328,17 +256,19 @@ namespace Greenshot.Editor.Helpers int dist = GeometryHelper.Distance2D(boundsBeforeResize.X, boundsBeforeResize.Y, cursorX, cursorY); - boundsAfterResize = boundsAfterResize + result = result .ChangeWidth((int)Math.Round(dist * Math.Cos(angle / 180 * Math.PI))) .ChangeHeight((int) Math.Round(dist * Math.Sin(angle / 180 * Math.PI))); } if (centeredScale) { - float wdiff = boundsAfterResize.Width - boundsBeforeResize.Width; - float hdiff = boundsAfterResize.Height - boundsBeforeResize.Height; - boundsAfterResize = boundsAfterResize.Inflate(wdiff, hdiff); + float wdiff = result.Width - result.Width; + float hdiff = result.Height - result.Height; + result = result.Inflate(wdiff, hdiff); } + + return result; } /// the current ScaleOptions depending on modifier keys held down @@ -359,7 +289,7 @@ namespace Greenshot.Editor.Helpers public class ShapeAngleRoundBehavior : IDoubleProcessor { - public static ShapeAngleRoundBehavior Instance = new(); + public static readonly ShapeAngleRoundBehavior INSTANCE = new(); private ShapeAngleRoundBehavior() { @@ -373,7 +303,7 @@ namespace Greenshot.Editor.Helpers public class LineAngleRoundBehavior : IDoubleProcessor { - public static LineAngleRoundBehavior Instance = new(); + public static readonly LineAngleRoundBehavior INSTANCE = new(); private LineAngleRoundBehavior() { From 8880578f7742c2e592f2ff381605fcc4d365374b Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 13 Apr 2022 20:42:33 +0200 Subject: [PATCH 188/232] Fixed an issue with the adorner size, which stayed on 0, so it wasn't visible. --- src/Greenshot.Base/Interfaces/ISurface.cs | 8 ++++++++ .../Drawing/Adorners/AbstractAdorner.cs | 19 ++++++++++++------- src/Greenshot.Editor/Drawing/Surface.cs | 12 ++++++++++++ 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/Greenshot.Base/Interfaces/ISurface.cs b/src/Greenshot.Base/Interfaces/ISurface.cs index cedb8f51c..4b39fb9b8 100644 --- a/src/Greenshot.Base/Interfaces/ISurface.cs +++ b/src/Greenshot.Base/Interfaces/ISurface.cs @@ -256,5 +256,13 @@ namespace Greenshot.Base.Interfaces /// Image /// Matrix void UndoBackgroundChange(Image previous, Matrix matrix); + + /// + /// The most recent DPI value that was used + /// + public int CurrentDpi + { + get; + } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs index aa023b19c..a2dd980a6 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/AbstractAdorner.cs @@ -34,12 +34,17 @@ namespace Greenshot.Editor.Drawing.Adorners { public virtual EditStatus EditStatus { get; protected set; } = EditStatus.IDLE; - private static readonly NativeSize DefaultSize = new NativeSize(6, 6); - protected NativeSize _size; + private static readonly NativeSize DefaultSize = new(6, 6); + + protected NativeSize Size + { + get; + set; + } public AbstractAdorner(IDrawableContainer owner) { - _size = DpiCalculator.ScaleWithDpi(DefaultSize, 0); + Size = DpiCalculator.ScaleWithDpi(DefaultSize, owner?.Parent?.CurrentDpi ?? 96); Owner = owner; } @@ -51,7 +56,7 @@ namespace Greenshot.Editor.Drawing.Adorners get { return Cursors.SizeAll; } } - public virtual IDrawableContainer Owner { get; set; } + public IDrawableContainer Owner { get; set; } /// /// Test if the point is inside the adorner @@ -105,7 +110,7 @@ namespace Greenshot.Editor.Drawing.Adorners get { NativePoint location = Location; - return new NativeRect(location.X - (_size.Width / 2), location.Y - (_size.Height / 2), _size.Width, _size.Height); + return new NativeRect(location.X - (Size.Width / 2), location.Y - (Size.Height / 2), Size.Width, Size.Height); } } @@ -117,7 +122,7 @@ namespace Greenshot.Editor.Drawing.Adorners get { NativePoint displayLocation = Owner.Parent.ToSurfaceCoordinates(Location); - return new NativeRect(displayLocation.X - _size.Width / 2, displayLocation.Y - _size.Height / 2, _size.Width, _size.Height); + return new NativeRect(displayLocation.X - Size.Width / 2, displayLocation.Y - Size.Height / 2, Size.Width, Size.Height); } } @@ -135,7 +140,7 @@ namespace Greenshot.Editor.Drawing.Adorners /// uint public void AdjustToDpi(int dpi) { - _size = DpiCalculator.ScaleWithDpi(DefaultSize, dpi); + Size = DpiCalculator.ScaleWithDpi(DefaultSize, dpi); } public Color OutlineColor { get; set; } = Color.White; diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index 399d60dad..f050374a6 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -145,6 +145,17 @@ namespace Greenshot.Editor.Drawing remove => _shadowChanged -= value; } + + [NonSerialized] private int _currentDpi = 96; + /// + /// The most recent DPI value that was used + /// + public int CurrentDpi + { + get => _currentDpi; + set => _currentDpi = value; + } + /// /// inUndoRedo makes sure we don't undo/redo while in a undo/redo action /// @@ -456,6 +467,7 @@ namespace Greenshot.Editor.Drawing /// public void AdjustToDpi(int dpi) { + CurrentDpi = dpi; foreach (var element in this._elements) { element.AdjustToDpi(dpi); From 94591e5b1414c0dd9ee97843476795dd4802672e Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 14 Apr 2022 11:58:52 +0200 Subject: [PATCH 189/232] Small fixes to the VectorGraphicsContainer, to align it with the possible coming EmojiContainer. Still having issues with Scaling code, this needs to be fixed. [skip ci] --- src/Greenshot.Base/Greenshot.Base.csproj | 14 +++--- src/Greenshot.Editor/Drawing/CropContainer.cs | 2 +- .../Drawing/DrawableContainer.cs | 2 +- .../Drawing/VectorGraphicsContainer.cs | 49 ++++++++++++++++--- src/Greenshot.Editor/Helpers/ScaleHelper.cs | 47 +++++++++--------- 5 files changed, 75 insertions(+), 39 deletions(-) diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index 169bd9395..805098491 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -6,15 +6,15 @@ - - - - - - + + + + + + - + diff --git a/src/Greenshot.Editor/Drawing/CropContainer.cs b/src/Greenshot.Editor/Drawing/CropContainer.cs index 2aee4252f..d450e9dd2 100644 --- a/src/Greenshot.Editor/Drawing/CropContainer.cs +++ b/src/Greenshot.Editor/Drawing/CropContainer.cs @@ -250,7 +250,7 @@ namespace Greenshot.Editor.Drawing break; } } - _boundsAfterResize = ScaleHelper.Scale(_boundsBeforeResize, x, y, GetAngleRoundProcessor()); + _boundsAfterResize = ScaleHelper.Scale(_boundsBeforeResize, Positions.TopLeft, x, y, GetAngleRoundProcessor()); // apply scaled bounds to this DrawableContainer ApplyBounds(_boundsAfterResize); diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index be4638164..c9737f9e3 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -533,7 +533,7 @@ namespace Greenshot.Editor.Drawing // reset "workbench" rectangle to current bounds _boundsAfterResize = new NativeRectFloat(_boundsBeforeResize.Left, _boundsBeforeResize.Top, x - _boundsAfterResize.Left, y - _boundsAfterResize.Top); - _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, x, y, GetAngleRoundProcessor()); + _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, Positions.TopLeft, x, y, GetAngleRoundProcessor()); // apply scaled bounds to this DrawableContainer ApplyBounds(_boundsAfterResize); diff --git a/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs b/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs index 0c467c0b8..45238caaf 100644 --- a/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs +++ b/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs @@ -25,6 +25,7 @@ using System.Drawing.Drawing2D; using System.Runtime.Serialization; using Greenshot.Base.Interfaces; using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Editor.Drawing.Adorners; namespace Greenshot.Editor.Drawing { @@ -35,28 +36,54 @@ namespace Greenshot.Editor.Drawing [Serializable] public abstract class VectorGraphicsContainer : DrawableContainer { - protected int RotationAngle; + private int _rotationAngle; + protected int RotationAngle + { + get => _rotationAngle; + set => _rotationAngle = value; + } /// /// This is the cached version of the bitmap, pre-rendered to save performance - /// Do not serialized, it can be rebuild with some other information. + /// Do not serialized, it can be rebuild with other information. /// [NonSerialized] private Image _cachedImage; + /// + /// Constructor takes care of calling Init + /// + /// ISurface public VectorGraphicsContainer(ISurface parent) : base(parent) { Init(); } + /// + /// Make sure Init is called after deserializing + /// + /// StreamingContext protected override void OnDeserialized(StreamingContext streamingContext) { base.OnDeserialized(streamingContext); Init(); } - private void Init() + /// + /// Init is called after creating the instance, and from OnDeserialized + /// This is the place to generate your adorners + /// + protected virtual void Init() { - CreateDefaultAdorners(); + // Check if the adorners are already defined! + if (Adorners.Count > 0) + { + return; + } + + Adorners.Add(new ResizeAdorner(this, Positions.TopLeft)); + Adorners.Add(new ResizeAdorner(this, Positions.TopRight)); + Adorners.Add(new ResizeAdorner(this, Positions.BottomLeft)); + Adorners.Add(new ResizeAdorner(this, Positions.BottomRight)); } /// @@ -96,7 +123,10 @@ namespace Greenshot.Editor.Drawing } _cachedImage ??= ComputeBitmap(); - + if (_cachedImage == null) + { + return; + } graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.CompositingQuality = CompositingQuality.HighQuality; @@ -106,9 +136,16 @@ namespace Greenshot.Editor.Drawing graphics.DrawImage(_cachedImage, Bounds); } + /// + /// Implement this to compute the new bitmap according to the size of the container + /// + /// Image protected abstract Image ComputeBitmap(); - private void ResetCachedBitmap() + /// + /// Dispose of the cached bitmap, forcing the code to regenerate it + /// + protected void ResetCachedBitmap() { _cachedImage?.Dispose(); _cachedImage = null; diff --git a/src/Greenshot.Editor/Helpers/ScaleHelper.cs b/src/Greenshot.Editor/Helpers/ScaleHelper.cs index 4f4e7dc7a..63f25d0a0 100644 --- a/src/Greenshot.Editor/Helpers/ScaleHelper.cs +++ b/src/Greenshot.Editor/Helpers/ScaleHelper.cs @@ -58,7 +58,7 @@ namespace Greenshot.Editor.Helpers /// the size of the element to be resized /// the target size of the element /// in case the aspect ratio of currentSize and targetSize differs: shall the scaled size fit into targetSize (i.e. that one of its dimensions is smaller - false) or vice versa (true) - /// a new SizeF object indicating the width and height the element should be scaled to + /// NativeSizeFloat object indicating the width and height the element should be scaled to public static NativeSizeFloat GetScaledSize(NativeSizeFloat currentSize, NativeSizeFloat targetSize, bool crop) { float wFactor = targetSize.Width / currentSize.Width; @@ -71,10 +71,10 @@ namespace Greenshot.Editor.Helpers /// /// calculates the position of an element depending on the desired alignment within a RectangleF /// - /// the bounds of the element to be aligned - /// the rectangle reference for alignment of the element + /// NativeRectFloat the bounds of the element to be aligned + /// NativeRectFloat with the rectangle for alignment of the element /// the System.Drawing.ContentAlignment value indicating how the element is to be aligned should the width or height differ from targetSize - /// a new RectangleF object with Location aligned aligned to targetRect + /// NativeRectFloat object with Location aligned aligned to targetRect public static NativeRectFloat GetAlignedRectangle(NativeRectFloat currentRect, NativeRectFloat targetRect, ContentAlignment alignment) { var newRect = new NativeRectFloat(targetRect.Location, currentRect.Size); @@ -96,9 +96,9 @@ namespace Greenshot.Editor.Helpers /// /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) /// - /// bounds of the current rectangle - /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT - /// coordinates of the used handle/gripper + /// NativeRectFloat bounds of the current rectangle + /// Positions with the position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT + /// NativePointFloat coordinates of the used handle/gripper /// ScaleOptions to use when scaling /// NativeRectFloat scaled originalRectangle public static NativeRectFloat Scale(NativeRectFloat originalRectangle, Positions resizeHandlePosition, NativePointFloat resizeHandleCoords, ScaleOptions? options) @@ -134,9 +134,9 @@ namespace Greenshot.Editor.Helpers /// /// Calculates target size of a given rectangle scaled by dragging one of its handles (corners) /// - /// bounds of the current rectangle - /// position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT - /// coordinates of the used handle/gripper + /// NativeRectFloat bounds of the current rectangle + /// Positions with the position of the handle/gripper being used for resized, see constants in Gripper.cs, e.g. Gripper.POSITION_TOP_LEFT + /// NativePointFloat with coordinates of the used handle/gripper /// NativeRectFloat with the scaled originalRectangle private static NativeRectFloat Scale(NativeRectFloat originalRectangle, Positions resizeHandlePosition, NativePointFloat resizeHandleCoords) { @@ -158,9 +158,9 @@ namespace Greenshot.Editor.Helpers /// To avoid objects growing near infinity unexpectedly in certain combinations, the adjustment will choose the /// option resulting in the smaller rectangle. /// - /// bounds of the current rectangle - /// position of the handle/gripper being used for resized, see Position - /// coordinates of the used handle/gripper + /// NativeRectFloat with the bounds of the current rectangle + /// Positions with the position of the handle/gripper being used for resized, see Position + /// NativePointFloat with coordinates of the used handle/gripper /// NativePointFloat with the adjusted coordinates private static NativePointFloat AdjustCoordsForRationalScale(NativeRectFloat originalRectangle, Positions resizeHandlePosition, NativePointFloat resizeHandleCoords) { @@ -203,7 +203,7 @@ namespace Greenshot.Editor.Helpers /// /// NativeSizeFloat to be considered for keeping aspect ratio /// NativeSizeFloat selection size (i.e. the size we'd produce if we wouldn't keep aspect ratio) - /// + /// NativeSizeFloat private static NativeSizeFloat GetNewSizeForRationalScale(NativeSizeFloat originalSize, NativeSizeFloat selectedSize) { NativeSizeFloat newSize = selectedSize; @@ -227,16 +227,15 @@ namespace Greenshot.Editor.Helpers return newSize; } - public static NativeRectFloat Scale(NativeRect boundsBeforeResize, int cursorX, int cursorY) - { - return Scale(boundsBeforeResize, cursorX, cursorY, null); - } - - public static NativeRectFloat Scale(NativeRect boundsBeforeResize, int cursorX, int cursorY, IDoubleProcessor angleRoundBehavior) - { - return Scale(boundsBeforeResize, Positions.TopLeft, cursorX, cursorY, angleRoundBehavior); - } - + /// + /// Scale the boundsBeforeResize with the specified position and new location, using the angle angleRoundBehavior + /// + /// NativeRect + /// Positions + /// int + /// int + /// IDoubleProcessor + /// NativeRectFloat public static NativeRectFloat Scale(NativeRect boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, IDoubleProcessor angleRoundBehavior) { ScaleOptions opts = GetScaleOptions(); From bd03e18ddccd1daaf145a95156fe8b6dc47e7f2a Mon Sep 17 00:00:00 2001 From: Christian Schulz <32000301+Christian-Schulz@users.noreply.github.com> Date: Sat, 21 May 2022 22:57:20 +0200 Subject: [PATCH 190/232] Bugfix crop selection scaling #404 (#407) Disable scaling for horizontal and vertical crop modes. --- src/Greenshot.Editor/Drawing/CropContainer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Greenshot.Editor/Drawing/CropContainer.cs b/src/Greenshot.Editor/Drawing/CropContainer.cs index d450e9dd2..c513b171f 100644 --- a/src/Greenshot.Editor/Drawing/CropContainer.cs +++ b/src/Greenshot.Editor/Drawing/CropContainer.cs @@ -247,10 +247,11 @@ namespace Greenshot.Editor.Drawing _boundsAfterResize = new NativeRectFloat( _boundsBeforeResize.Left, _boundsBeforeResize.Top, x - _boundsAfterResize.Left, y - _boundsAfterResize.Top); + + _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, Positions.TopLeft, x, y, GetAngleRoundProcessor()); break; } } - _boundsAfterResize = ScaleHelper.Scale(_boundsBeforeResize, Positions.TopLeft, x, y, GetAngleRoundProcessor()); // apply scaled bounds to this DrawableContainer ApplyBounds(_boundsAfterResize); From 3f6f9863f885dac7127bcffc6853c719705bb319 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Fri, 3 Jun 2022 11:23:27 +0200 Subject: [PATCH 191/232] Removed copying all the dependencies for every plugin, this should fix #413. --- installer/innosetup/setup.iss | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index 23788205e..bf49ea5ed 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -82,33 +82,34 @@ Source: {#LanguagesDir}\*zh-CN*; Excludes: "*installer*,*website*"; DestDir: {ap Source: {#LanguagesDir}\*zh-TW*; Excludes: "*installer*,*website*"; DestDir: {app}\Languages; Components: languages\zhTW; Flags: overwritereadonly ignoreversion replacesameversion; ;Office Plugin -Source: {#PluginDir}\Greenshot.Plugin.Office\*.dll; DestDir: {app}\Plugins\Office; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Office\Greenshot.Plugin.Office.dll; DestDir: {app}\Plugins\Office; Components: plugins\office; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; ;JIRA Plugin -Source: {#PluginDir}\Greenshot.Plugin.Jira\*.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Jira\*Jira*.dll; DestDir: {app}\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Jira\Languages\language_jira*.xml; DestDir: {app}\Languages\Plugins\Jira; Components: plugins\jira; Flags: overwritereadonly ignoreversion replacesameversion; ;Imgur Plugin -Source: {#PluginDir}\Greenshot.Plugin.Imgur\*.dll; DestDir: {app}\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Imgur\Greenshot.Plugin.Imgur.dll; DestDir: {app}\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Imgur\Languages\language_imgur*.xml; DestDir: {app}\Languages\Plugins\Imgur; Components: plugins\imgur; Flags: overwritereadonly ignoreversion replacesameversion; ;Box Plugin -Source: {#PluginDir}\Greenshot.Plugin.Box\*.dll; DestDir: {app}\Plugins\Box; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Box\Greenshot.Plugin.Box.dll; DestDir: {app}\Plugins\Box; Components: plugins\box; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Box\Languages\language_box*.xml; DestDir: {app}\Languages\Plugins\Box; Components: plugins\box; Flags: overwritereadonly ignoreversion replacesameversion; ;DropBox Plugin -Source: {#PluginDir}\Greenshot.Plugin.DropBox\*.dll; DestDir: {app}\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.DropBox\Greenshot.Plugin.DropBox.dll; DestDir: {app}\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.DropBox\Languages\language_dropbox*.xml; DestDir: {app}\Languages\Plugins\DropBox; Components: plugins\dropbox; Flags: overwritereadonly ignoreversion replacesameversion; ;Flickr Plugin -Source: {#PluginDir}\Greenshot.Plugin.Flickr\*.dll; DestDir: {app}\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Flickr\Greenshot.Plugin.Flickr.dll; DestDir: {app}\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Flickr\Languages\language_flickr*.xml; DestDir: {app}\Languages\Plugins\Flickr; Components: plugins\flickr; Flags: overwritereadonly ignoreversion replacesameversion; ;Photobucket Plugin -Source: {#PluginDir}\Greenshot.Plugin.Photobucket\*.dll; DestDir: {app}\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Photobucket\Greenshot.Plugin.Photobucket.dll; DestDir: {app}\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Photobucket\Languages\language_photo*.xml; DestDir: {app}\Languages\Plugins\Photobucket; Components: plugins\photobucket; Flags: overwritereadonly ignoreversion replacesameversion; ;Confluence Plugin -Source: {#PluginDir}\Greenshot.Plugin.Confluence\*.dll; DestDir: {app}\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Confluence\Greenshot.Plugin.Confluence.dll; DestDir: {app}\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.Confluence\Languages\language_confluence*.xml; DestDir: {app}\Languages\Plugins\Confluence; Components: plugins\confluence; Flags: overwritereadonly ignoreversion replacesameversion; ;ExternalCommand Plugin -Source: {#PluginDir}\Greenshot.Plugin.ExternalCommand\*.dll; DestDir: {app}\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.ExternalCommand\Greenshot.Plugin.ExternalCommand.dll; DestDir: {app}\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; Source: {#BaseDir}\Greenshot.Plugin.ExternalCommand\Languages\language_externalcommand*.xml; DestDir: {app}\Languages\Plugins\ExternalCommand; Components: plugins\externalcommand; Flags: overwritereadonly ignoreversion replacesameversion; ;Win 10 Plugin -Source: {#PluginDir}\Greenshot.Plugin.Win10\*.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Win10\Greenshot.Plugin.Win10.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; +Source: {#PluginDir}\Greenshot.Plugin.Win10\Microsoft.Toolkit.Uwp.Notifications.dll; DestDir: {app}\Plugins\Win10; Components: plugins\win10; Flags: overwritereadonly recursesubdirs ignoreversion replacesameversion; [Setup] ; changes associations is used when the installer installs new extensions, it clears the explorer icon cache From 4c7494dd7486030e03d18aa561bc9a01b65c754a Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 26 Jun 2022 01:40:53 +0200 Subject: [PATCH 192/232] Some left over fixes for the move to Dapplo.Windows, also updated dependencies. --- src/Directory.Build.props | 2 +- src/Greenshot.Base/Greenshot.Base.csproj | 14 ++--- .../Drawing/Adorners/ResizeAdorner.cs | 4 +- src/Greenshot.Editor/Drawing/CropContainer.cs | 2 +- .../Drawing/DrawableContainer.cs | 7 ++- src/Greenshot.Editor/Drawing/LineContainer.cs | 4 +- .../Helpers/IDoubleProcessor.cs | 28 +++++++++ .../Helpers/IHaveScaleOptions.cs | 28 +++++++++ .../Helpers/LineAngleRoundBehavior.cs | 39 ++++++++++++ src/Greenshot.Editor/Helpers/ScaleHelper.cs | 62 ++----------------- src/Greenshot.Editor/Helpers/ScaleOptions.cs | 44 +++++++++++++ .../Helpers/ShapeAngleRoundBehavior.cs | 39 ++++++++++++ .../Greenshot.Plugin.Office.csproj | 10 +-- src/Greenshot/App.config | 3 +- src/Greenshot/Greenshot.csproj | 2 +- 15 files changed, 208 insertions(+), 80 deletions(-) create mode 100644 src/Greenshot.Editor/Helpers/IDoubleProcessor.cs create mode 100644 src/Greenshot.Editor/Helpers/IHaveScaleOptions.cs create mode 100644 src/Greenshot.Editor/Helpers/LineAngleRoundBehavior.cs create mode 100644 src/Greenshot.Editor/Helpers/ScaleOptions.cs create mode 100644 src/Greenshot.Editor/Helpers/ShapeAngleRoundBehavior.cs diff --git a/src/Directory.Build.props b/src/Directory.Build.props index b6533ddd7..f5b9f2e1c 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -46,7 +46,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index 805098491..a698b8e0b 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -6,13 +6,13 @@ - - - - - - - + + + + + + + diff --git a/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs b/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs index 523684232..263d5a31e 100644 --- a/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs +++ b/src/Greenshot.Editor/Drawing/Adorners/ResizeAdorner.cs @@ -100,8 +100,10 @@ namespace Greenshot.Editor.Drawing.Adorners // reset "workbench" rectangle to current bounds _boundsAfterResize = _boundsBeforeResize; + var scaleOptions = (Owner as IHaveScaleOptions)?.GetScaleOptions(); + // calculate scaled rectangle - _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, Position, new PointF(mouseEventArgs.X, mouseEventArgs.Y), ScaleHelper.GetScaleOptions()); + _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, Position, new NativePointFloat(mouseEventArgs.X, mouseEventArgs.Y), scaleOptions); // apply scaled bounds to this DrawableContainer Owner.ApplyBounds(_boundsAfterResize); diff --git a/src/Greenshot.Editor/Drawing/CropContainer.cs b/src/Greenshot.Editor/Drawing/CropContainer.cs index c513b171f..eb2f7179e 100644 --- a/src/Greenshot.Editor/Drawing/CropContainer.cs +++ b/src/Greenshot.Editor/Drawing/CropContainer.cs @@ -248,7 +248,7 @@ namespace Greenshot.Editor.Drawing _boundsBeforeResize.Left, _boundsBeforeResize.Top, x - _boundsAfterResize.Left, y - _boundsAfterResize.Top); - _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, Positions.TopLeft, x, y, GetAngleRoundProcessor()); + _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, x, y, GetAngleRoundProcessor()); break; } } diff --git a/src/Greenshot.Editor/Drawing/DrawableContainer.cs b/src/Greenshot.Editor/Drawing/DrawableContainer.cs index c9737f9e3..cac23dc3a 100644 --- a/src/Greenshot.Editor/Drawing/DrawableContainer.cs +++ b/src/Greenshot.Editor/Drawing/DrawableContainer.cs @@ -533,7 +533,8 @@ namespace Greenshot.Editor.Drawing // reset "workbench" rectangle to current bounds _boundsAfterResize = new NativeRectFloat(_boundsBeforeResize.Left, _boundsBeforeResize.Top, x - _boundsAfterResize.Left, y - _boundsAfterResize.Top); - _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, Positions.TopLeft, x, y, GetAngleRoundProcessor()); + var scaleOptions = (this as IHaveScaleOptions)?.GetScaleOptions(); + _boundsAfterResize = ScaleHelper.Scale(_boundsAfterResize, x, y, GetAngleRoundProcessor(), scaleOptions); // apply scaled bounds to this DrawableContainer ApplyBounds(_boundsAfterResize); @@ -666,9 +667,9 @@ namespace Greenshot.Editor.Drawing Height = points[1].Y - points[0].Y; } - protected virtual ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() + protected virtual IDoubleProcessor GetAngleRoundProcessor() { - return ScaleHelper.ShapeAngleRoundBehavior.INSTANCE; + return ShapeAngleRoundBehavior.INSTANCE; } public virtual bool HasContextMenu => true; diff --git a/src/Greenshot.Editor/Drawing/LineContainer.cs b/src/Greenshot.Editor/Drawing/LineContainer.cs index ef4a68707..f48dddec7 100644 --- a/src/Greenshot.Editor/Drawing/LineContainer.cs +++ b/src/Greenshot.Editor/Drawing/LineContainer.cs @@ -115,9 +115,9 @@ namespace Greenshot.Editor.Drawing return false; } - protected override ScaleHelper.IDoubleProcessor GetAngleRoundProcessor() + protected override IDoubleProcessor GetAngleRoundProcessor() { - return ScaleHelper.LineAngleRoundBehavior.INSTANCE; + return LineAngleRoundBehavior.INSTANCE; } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Helpers/IDoubleProcessor.cs b/src/Greenshot.Editor/Helpers/IDoubleProcessor.cs new file mode 100644 index 000000000..beb426c68 --- /dev/null +++ b/src/Greenshot.Editor/Helpers/IDoubleProcessor.cs @@ -0,0 +1,28 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Editor.Helpers +{ + public interface IDoubleProcessor + { + double Process(double d); + } +} \ No newline at end of file diff --git a/src/Greenshot.Editor/Helpers/IHaveScaleOptions.cs b/src/Greenshot.Editor/Helpers/IHaveScaleOptions.cs new file mode 100644 index 000000000..3f1ed03ff --- /dev/null +++ b/src/Greenshot.Editor/Helpers/IHaveScaleOptions.cs @@ -0,0 +1,28 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +namespace Greenshot.Editor.Helpers +{ + public interface IHaveScaleOptions + { + ScaleOptions GetScaleOptions(); + } +} diff --git a/src/Greenshot.Editor/Helpers/LineAngleRoundBehavior.cs b/src/Greenshot.Editor/Helpers/LineAngleRoundBehavior.cs new file mode 100644 index 000000000..6811f66cf --- /dev/null +++ b/src/Greenshot.Editor/Helpers/LineAngleRoundBehavior.cs @@ -0,0 +1,39 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Editor.Helpers +{ + public class LineAngleRoundBehavior : IDoubleProcessor + { + public static readonly LineAngleRoundBehavior INSTANCE = new(); + + private LineAngleRoundBehavior() + { + } + + public double Process(double angle) + { + return Math.Round(angle / 15) * 15; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Editor/Helpers/ScaleHelper.cs b/src/Greenshot.Editor/Helpers/ScaleHelper.cs index 63f25d0a0..8403bd939 100644 --- a/src/Greenshot.Editor/Helpers/ScaleHelper.cs +++ b/src/Greenshot.Editor/Helpers/ScaleHelper.cs @@ -33,25 +33,6 @@ namespace Greenshot.Editor.Helpers /// public static class ScaleHelper { - [Flags] - public enum ScaleOptions - { - /// - /// Default scale behavior. - /// - Default = 0x00, - - /// - /// Scale a rectangle in two our four directions, mirrored at it's center coordinates - /// - Centered = 0x01, - - /// - /// Scale a rectangle maintaining it's aspect ratio - /// - Rational = 0x02 - } - /// /// calculates the Size an element must be resized to, in order to fit another element, keeping aspect ratio /// @@ -231,18 +212,18 @@ namespace Greenshot.Editor.Helpers /// Scale the boundsBeforeResize with the specified position and new location, using the angle angleRoundBehavior /// /// NativeRect - /// Positions /// int /// int /// IDoubleProcessor + /// ScaleOptions /// NativeRectFloat - public static NativeRectFloat Scale(NativeRect boundsBeforeResize, Positions gripperPosition, int cursorX, int cursorY, IDoubleProcessor angleRoundBehavior) + public static NativeRectFloat Scale(NativeRect boundsBeforeResize, int cursorX, int cursorY, IDoubleProcessor angleRoundBehavior, ScaleOptions? scaleOptions = null) { - ScaleOptions opts = GetScaleOptions(); + scaleOptions ??= GetScaleOptions(); NativeRectFloat result = boundsBeforeResize; - bool rationalScale = (opts & ScaleOptions.Rational) == ScaleOptions.Rational; - bool centeredScale = (opts & ScaleOptions.Centered) == ScaleOptions.Centered; + bool rationalScale = (scaleOptions & ScaleOptions.Rational) == ScaleOptions.Rational; + bool centeredScale = (scaleOptions & ScaleOptions.Centered) == ScaleOptions.Centered; if (rationalScale) { @@ -280,38 +261,5 @@ namespace Greenshot.Editor.Helpers if (maintainAspectRatio) opts |= ScaleOptions.Rational; return opts; } - - public interface IDoubleProcessor - { - double Process(double d); - } - - public class ShapeAngleRoundBehavior : IDoubleProcessor - { - public static readonly ShapeAngleRoundBehavior INSTANCE = new(); - - private ShapeAngleRoundBehavior() - { - } - - public double Process(double angle) - { - return Math.Round((angle + 45) / 90) * 90 - 45; - } - } - - public class LineAngleRoundBehavior : IDoubleProcessor - { - public static readonly LineAngleRoundBehavior INSTANCE = new(); - - private LineAngleRoundBehavior() - { - } - - public double Process(double angle) - { - return Math.Round(angle / 15) * 15; - } - } } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Helpers/ScaleOptions.cs b/src/Greenshot.Editor/Helpers/ScaleOptions.cs new file mode 100644 index 000000000..1f47f5c02 --- /dev/null +++ b/src/Greenshot.Editor/Helpers/ScaleOptions.cs @@ -0,0 +1,44 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Editor.Helpers +{ + [Flags] + public enum ScaleOptions + { + /// + /// Default scale behavior. + /// + Default = 0x00, + + /// + /// Scale a rectangle in two our four directions, mirrored at it's center coordinates + /// + Centered = 0x01, + + /// + /// Scale a rectangle maintaining it's aspect ratio + /// + Rational = 0x02 + } +} \ No newline at end of file diff --git a/src/Greenshot.Editor/Helpers/ShapeAngleRoundBehavior.cs b/src/Greenshot.Editor/Helpers/ShapeAngleRoundBehavior.cs new file mode 100644 index 000000000..ba173df9f --- /dev/null +++ b/src/Greenshot.Editor/Helpers/ShapeAngleRoundBehavior.cs @@ -0,0 +1,39 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Editor.Helpers +{ + public class ShapeAngleRoundBehavior : IDoubleProcessor + { + public static readonly ShapeAngleRoundBehavior INSTANCE = new(); + + private ShapeAngleRoundBehavior() + { + } + + public double Process(double angle) + { + return Math.Round((angle + 45) / 90) * 90 - 45; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj index fdb555adc..347a58339 100644 --- a/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj +++ b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj @@ -78,23 +78,23 @@ - + true runtime - + true runtime - + true runtime - + true runtime - + true runtime diff --git a/src/Greenshot/App.config b/src/Greenshot/App.config index 80b985a5c..ab8a7c40c 100644 --- a/src/Greenshot/App.config +++ b/src/Greenshot/App.config @@ -11,8 +11,7 @@ - - + \ No newline at end of file diff --git a/src/Greenshot/Greenshot.csproj b/src/Greenshot/Greenshot.csproj index 78fa3f6c6..fc4dd90d1 100644 --- a/src/Greenshot/Greenshot.csproj +++ b/src/Greenshot/Greenshot.csproj @@ -17,7 +17,7 @@ - + From f50f205b706aec10a9f9314eaa246b48668c4d39 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 28 Jun 2022 16:28:26 +0200 Subject: [PATCH 193/232] Removed old Windows 8 logic, which caused #403 (which is a very unlucky issue number LOL) This should actually make Greenshot a tiny bit faster and use less resources, but I am not 100% sure about the effects as some windows still seem to have the window class for Windows 8. --- src/Greenshot.Base/Core/WindowDetails.cs | 210 ++++------------------- src/Greenshot/Helpers/CaptureHelper.cs | 16 +- 2 files changed, 34 insertions(+), 192 deletions(-) diff --git a/src/Greenshot.Base/Core/WindowDetails.cs b/src/Greenshot.Base/Core/WindowDetails.cs index 281dde6f4..98416c105 100644 --- a/src/Greenshot.Base/Core/WindowDetails.cs +++ b/src/Greenshot.Base/Core/WindowDetails.cs @@ -42,8 +42,6 @@ namespace Greenshot.Base.Core { private const string AppWindowClass = "Windows.UI.Core.CoreWindow"; //Used for Windows 8(.1) private const string AppFrameWindowClass = "ApplicationFrameWindow"; // Windows 10 uses ApplicationFrameWindow - private const string ApplauncherClass = "ImmersiveLauncher"; - private const string GutterClass = "ImmersiveGutter"; private static readonly IList IgnoreClasses = new List(new[] { @@ -89,13 +87,7 @@ namespace Greenshot.Base.Core private IntPtr _parentHandle = IntPtr.Zero; private WindowDetails _parent; private bool _frozen; - - /// - /// This checks if the window is a Windows 8 App - /// For Windows 10 most normal code works, as it's hosted inside "ApplicationFrameWindow" - /// - public bool IsApp => AppWindowClass.Equals(ClassName); - + /// /// This checks if the window is a Windows 10 App /// For Windows 10 apps are hosted inside "ApplicationFrameWindow" @@ -108,20 +100,6 @@ namespace Greenshot.Base.Core public bool IsBackgroundWin10App => WindowsVersion.IsWindows10OrLater && AppFrameWindowClass.Equals(ClassName) && !Children.Any(window => string.Equals(window.ClassName, AppWindowClass)); - /// - /// Check if the window is the metro gutter (sizeable separator) - /// - public bool IsGutter => GutterClass.Equals(ClassName); - - /// - /// Test if this window is for the App-Launcher - /// - public bool IsAppLauncher => ApplauncherClass.Equals(ClassName); - - /// - /// Check if this window is the window of a metro app - /// - public bool IsMetroApp => IsAppLauncher || IsApp; /// /// To allow items to be compared, the hash code @@ -226,12 +204,6 @@ namespace Greenshot.Base.Core Log.Warn(ex); } - if (IsMetroApp) - { - // No method yet to get the metro icon - return null; - } - try { return PluginUtils.GetCachedExeIcon(ProcessPath, 0); @@ -467,11 +439,6 @@ namespace Greenshot.Base.Core { get { - if (IsMetroApp) - { - return !Visible; - } - return User32Api.IsIconic(Handle) || Location.X <= -32000; } set @@ -494,22 +461,6 @@ namespace Greenshot.Base.Core { get { - if (IsApp) - { - if (Visible) - { - foreach (var displayInfo in DisplayInfo.AllDisplayInfos) - { - if (WindowRectangle.Equals(displayInfo.Bounds)) - { - return true; - } - } - } - - return false; - } - return User32Api.IsZoomed(Handle); } set @@ -546,50 +497,6 @@ namespace Greenshot.Base.Core return false; } - if (IsApp) - { - var windowRectangle = WindowRectangle; - - foreach (var displayInfo in DisplayInfo.AllDisplayInfos) - { - if (!displayInfo.Bounds.Contains(windowRectangle)) continue; - if (windowRectangle.Equals(displayInfo.Bounds)) - { - // Fullscreen, it's "visible" when AppVisibilityOnMonitor says yes - // Although it might be the other App, this is not "very" important - NativeRect rect = displayInfo.Bounds; - IntPtr monitor = User32Api.MonitorFromRect(ref rect, MonitorFrom.DefaultToNull); - if (monitor != IntPtr.Zero) - { - MONITOR_APP_VISIBILITY? monitorAppVisibility = AppVisibility?.GetAppVisibilityOnMonitor(monitor); - //LOG.DebugFormat("App {0} visible: {1} on {2}", Text, monitorAppVisibility, screen.Bounds); - if (monitorAppVisibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE) - { - return true; - } - } - } - else - { - // Is only partly on the screen, when this happens the app is always visible! - return true; - } - } - - return false; - } - - if (IsGutter) - { - // gutter is only made available when it's visible - return true; - } - - if (IsAppLauncher) - { - return IsAppLauncherVisible; - } - return User32Api.IsWindowVisible(Handle); } } @@ -653,7 +560,7 @@ namespace Greenshot.Base.Core if (DwmApi.IsDwmEnabled) { bool gotFrameBounds = GetExtendedFrameBounds(out windowRect); - if (IsApp) + if (IsWin10App) { // Pre-Cache for maximized call, this is only on Windows 8 apps (full screen) if (gotFrameBounds) @@ -683,8 +590,8 @@ namespace Greenshot.Base.Core } } - // Correction for maximized windows, only if it's not an app - if (!HasParent && !IsApp && Maximised) + // Correction for maximized windows + if (!HasParent && Maximised) { // Only if the border size can be retrieved if (GetBorderSize(out var size)) @@ -928,7 +835,7 @@ namespace Greenshot.Base.Core { // if GDI is allowed.. (a screenshot won't be better than we comes if we continue) using Process thisWindowProcess = Process; - if (!IsMetroApp && WindowCapture.IsGdiAllowed(thisWindowProcess)) + if (WindowCapture.IsGdiAllowed(thisWindowProcess)) { // we return null which causes the capturing code to try another method. return null; @@ -973,11 +880,8 @@ namespace Greenshot.Base.Core tempForm.BackColor = Color.Black; // Make sure everything is visible tempForm.Refresh(); - if (!IsMetroApp) - { - // Make sure the application window is active, so the colors & buttons are right - ToForeground(); - } + // Make sure the application window is active, so the colors & buttons are right + ToForeground(); // Make sure all changes are processed and visible Application.DoEvents(); @@ -1013,11 +917,8 @@ namespace Greenshot.Base.Core // Make sure everything is visible tempForm.Refresh(); - if (!IsMetroApp) - { - // Make sure the application window is active, so the colors & buttons are right - ToForeground(); - } + // Make sure the application window is active, so the colors & buttons are right + ToForeground(); // Make sure all changes are processed and visible Application.DoEvents(); @@ -1154,6 +1055,13 @@ namespace Greenshot.Base.Core return targetBuffer.UnlockAndReturnBitmap(); } + /// + /// If a window is hidden (Iconic), it also has the specified dimensions. + /// + /// NativeRect + /// bool true if hidden + private bool IsHidden(NativeRect rect) => rect.Width == 65535 && rect.Height == 65535 && rect.Left == 32767 && rect.Top == 32767; + /// /// Helper method to get the window size for DWM Windows /// @@ -1164,6 +1072,10 @@ namespace Greenshot.Base.Core var result = DwmApi.DwmGetWindowAttribute(Handle, DwmWindowAttributes.ExtendedFrameBounds, out NativeRect rect, Marshal.SizeOf(typeof(NativeRect))); if (result.Succeeded()) { + if (IsHidden(rect)) + { + rect = NativeRect.Empty; + } rectangle = rect; return true; } @@ -1196,7 +1108,14 @@ namespace Greenshot.Base.Core var windowInfo = new WindowInfo(); // Get the Window Info for this window bool result = User32Api.GetWindowInfo(Handle, ref windowInfo); - rectangle = result ? windowInfo.Bounds : NativeRect.Empty; + if (IsHidden(windowInfo.Bounds)) + { + rectangle = NativeRect.Empty; + } + else + { + rectangle = result ? windowInfo.Bounds : NativeRect.Empty; + } return result; } @@ -1577,7 +1496,7 @@ namespace Greenshot.Base.Core // Skip everything which is not rendered "normally", trying to fix BUG-2017 var exWindowStyle = window.ExtendedWindowStyle; - if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) + if (!window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) { return false; } @@ -1592,13 +1511,6 @@ namespace Greenshot.Base.Core public static IEnumerable GetVisibleWindows() { var screenBounds = DisplayInfo.ScreenBounds; - foreach (var window in GetAppWindows()) - { - if (IsVisible(window, screenBounds)) - { - yield return window; - } - } foreach (var window in GetAllWindows()) { @@ -1609,38 +1521,6 @@ namespace Greenshot.Base.Core } } - /// - /// Get the WindowDetails for all Metro Apps - /// These are all Windows with Classname "Windows.UI.Core.CoreWindow" - /// - /// List WindowDetails with visible metro apps - public static IEnumerable GetAppWindows() - { - // if the appVisibility != null we have Windows 8. - if (AppVisibility == null) - { - yield break; - } - - var nextHandle = User32Api.FindWindow(AppWindowClass, null); - while (nextHandle != IntPtr.Zero) - { - var metroApp = new WindowDetails(nextHandle); - yield return metroApp; - // Check if we have a gutter! - if (metroApp.Visible && !metroApp.Maximised) - { - var gutterHandle = User32Api.FindWindow(GutterClass, null); - if (gutterHandle != IntPtr.Zero) - { - yield return new WindowDetails(gutterHandle); - } - } - - nextHandle = User32Api.FindWindowEx(IntPtr.Zero, nextHandle, AppWindowClass, null); - } - } - /// /// Check if the window is a top level /// @@ -1671,7 +1551,7 @@ namespace Greenshot.Base.Core } // Skip everything which is not rendered "normally", trying to fix BUG-2017 - if (!window.IsApp && !window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) + if (!window.IsWin10App && (exWindowStyle & ExtendedWindowStyleFlags.WS_EX_NOREDIRECTIONBITMAP) != 0) { return false; } @@ -1707,14 +1587,6 @@ namespace Greenshot.Base.Core /// List WindowDetails with all the top level windows public static IEnumerable GetTopLevelWindows() { - foreach (var possibleTopLevel in GetAppWindows()) - { - if (IsTopLevel(possibleTopLevel)) - { - yield return possibleTopLevel; - } - } - foreach (var possibleTopLevel in GetAllWindows()) { if (IsTopLevel(possibleTopLevel)) @@ -1790,27 +1662,6 @@ namespace Greenshot.Base.Core } } - /// - /// Get the AppLauncher - /// - /// - public static WindowDetails GetAppLauncher() - { - // Only if Windows 8 (or higher) - if (AppVisibility == null) - { - return null; - } - - IntPtr appLauncher = User32Api.FindWindow(ApplauncherClass, null); - if (appLauncher != IntPtr.Zero) - { - return new WindowDetails(appLauncher); - } - - return null; - } - /// /// Return true if the metro-app-launcher is visible /// @@ -1842,7 +1693,6 @@ namespace Greenshot.Base.Core result.AppendLine($"Size: {WindowRectangle.Size}"); result.AppendLine($"HasParent: {HasParent}"); result.AppendLine($"IsWin10App: {IsWin10App}"); - result.AppendLine($"IsApp: {IsApp}"); result.AppendLine($"Visible: {Visible}"); result.AppendLine($"IsWindowVisible: {User32Api.IsWindowVisible(Handle)}"); result.AppendLine($"IsCloaked: {IsCloaked}"); diff --git a/src/Greenshot/Helpers/CaptureHelper.cs b/src/Greenshot/Helpers/CaptureHelper.cs index c002c62ef..e51b51ebe 100644 --- a/src/Greenshot/Helpers/CaptureHelper.cs +++ b/src/Greenshot/Helpers/CaptureHelper.cs @@ -564,14 +564,6 @@ namespace Greenshot.Helpers { _windows = new List(); - // If the App Launcher is visible, no other windows are active - WindowDetails appLauncherWindow = WindowDetails.GetAppLauncher(); - if (appLauncherWindow != null && appLauncherWindow.Visible) - { - _windows.Add(appLauncherWindow); - return null; - } - Thread getWindowDetailsThread = new Thread(RetrieveWindowDetails) { Name = "Retrieve window details", @@ -984,7 +976,7 @@ namespace Greenshot.Helpers else { // Change to GDI, if allowed - if (!windowToCapture.IsMetroApp && WindowCapture.IsGdiAllowed(process)) + if (WindowCapture.IsGdiAllowed(process)) { if (!dwmEnabled && IsWpf(process)) { @@ -1000,7 +992,7 @@ namespace Greenshot.Helpers // Change to DWM, if enabled and allowed if (dwmEnabled) { - if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) + if (WindowCapture.IsDwmAllowed(process)) { windowCaptureMode = WindowCaptureMode.Aero; } @@ -1009,7 +1001,7 @@ namespace Greenshot.Helpers } else if (windowCaptureMode == WindowCaptureMode.Aero || windowCaptureMode == WindowCaptureMode.AeroTransparent) { - if (!dwmEnabled || (!windowToCapture.IsMetroApp && !WindowCapture.IsDwmAllowed(process))) + if (!dwmEnabled || !WindowCapture.IsDwmAllowed(process)) { // Take default screen windowCaptureMode = WindowCaptureMode.Screen; @@ -1115,7 +1107,7 @@ namespace Greenshot.Helpers break; case WindowCaptureMode.Aero: case WindowCaptureMode.AeroTransparent: - if (windowToCapture.IsMetroApp || WindowCapture.IsDwmAllowed(process)) + if (WindowCapture.IsDwmAllowed(process)) { tmpCapture = windowToCapture.CaptureDwmWindow(captureForWindow, windowCaptureMode, isAutoMode); } From 36a285ebd4b9a8da071996d0b70c8be6e80e031d Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Tue, 28 Jun 2022 22:17:56 +0200 Subject: [PATCH 194/232] Fix capturing Maximised windows. --- src/Greenshot.Base/Core/WindowDetails.cs | 91 ++++++++++-------------- 1 file changed, 39 insertions(+), 52 deletions(-) diff --git a/src/Greenshot.Base/Core/WindowDetails.cs b/src/Greenshot.Base/Core/WindowDetails.cs index 98416c105..9cdf5f370 100644 --- a/src/Greenshot.Base/Core/WindowDetails.cs +++ b/src/Greenshot.Base/Core/WindowDetails.cs @@ -550,69 +550,56 @@ namespace Greenshot.Base.Core { // Try to return a cached value long now = DateTime.Now.Ticks; - if (_previousWindowRectangle.IsEmpty || !_frozen) - { - if (!_previousWindowRectangle.IsEmpty && now - _lastWindowRectangleRetrieveTime <= CacheTime) - { - return _previousWindowRectangle; - } - NativeRect windowRect = new(); - if (DwmApi.IsDwmEnabled) - { - bool gotFrameBounds = GetExtendedFrameBounds(out windowRect); - if (IsWin10App) - { - // Pre-Cache for maximized call, this is only on Windows 8 apps (full screen) - if (gotFrameBounds) - { - _previousWindowRectangle = windowRect; - _lastWindowRectangleRetrieveTime = now; - } - } + if (!_previousWindowRectangle.IsEmpty && _frozen) return _previousWindowRectangle; - if (gotFrameBounds && WindowsVersion.IsWindows10OrLater && !Maximised) + if (!_previousWindowRectangle.IsEmpty && now - _lastWindowRectangleRetrieveTime <= CacheTime) + { + return _previousWindowRectangle; + } + NativeRect windowRect = new(); + if (DwmApi.IsDwmEnabled) + { + bool gotFrameBounds = GetExtendedFrameBounds(out windowRect); + if (IsWin10App) + { + // Pre-Cache for maximized call, this is only on Windows 8 apps (full screen) + if (gotFrameBounds) { - // Somehow DWM doesn't calculate it correctly, there is a 1 pixel border around the capture - // Remove this border, currently it's fixed but TODO: Make it depend on the OS? - windowRect = windowRect.Inflate(Conf.Win10BorderCrop); _previousWindowRectangle = windowRect; _lastWindowRectangleRetrieveTime = now; - return windowRect; } } - if (windowRect.IsEmpty) + if (gotFrameBounds && WindowsVersion.IsWindows10OrLater && !Maximised) { - if (!GetWindowRect(out windowRect)) - { - Win32Error error = Win32.GetLastErrorCode(); - Log.WarnFormat("Couldn't retrieve the windows rectangle: {0}", Win32.GetMessage(error)); - } + // Somehow DWM doesn't calculate it correctly, there is a 1 pixel border around the capture + // Remove this border, currently it's fixed but TODO: Make it depend on the OS? + windowRect = windowRect.Inflate(Conf.Win10BorderCrop); + _previousWindowRectangle = windowRect; + _lastWindowRectangleRetrieveTime = now; + return windowRect; } - - // Correction for maximized windows - if (!HasParent && Maximised) - { - // Only if the border size can be retrieved - if (GetBorderSize(out var size)) - { - windowRect = new NativeRect(windowRect.X + size.Width, windowRect.Y + size.Height, windowRect.Width - (2 * size.Width), - windowRect.Height - (2 * size.Height)); - } - } - - _lastWindowRectangleRetrieveTime = now; - // Try to return something valid, by getting returning the previous size if the window doesn't have a NativeRect anymore - if (windowRect.IsEmpty) - { - return _previousWindowRectangle; - } - - _previousWindowRectangle = windowRect; - return windowRect; } - return _previousWindowRectangle; + if (windowRect.IsEmpty) + { + if (!GetWindowRect(out windowRect)) + { + Win32Error error = Win32.GetLastErrorCode(); + Log.WarnFormat("Couldn't retrieve the windows rectangle: {0}", Win32.GetMessage(error)); + } + } + + _lastWindowRectangleRetrieveTime = now; + // Try to return something valid, by getting returning the previous size if the window doesn't have a NativeRect anymore + if (windowRect.IsEmpty) + { + return _previousWindowRectangle; + } + + _previousWindowRectangle = windowRect; + return windowRect; + } } From 48675b01f0621172678ee359caeecb71a035a743 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 30 Jun 2022 22:57:55 +0200 Subject: [PATCH 195/232] Modified the configuration handling, added code to remove tokens when upgrading from 1.2 as these no longer work. See #421 --- src/Greenshot.Base/Core/CoreConfiguration.cs | 132 +++++++----------- src/Greenshot.Plugin.Box/BoxConfiguration.cs | 16 +++ .../DropboxConfiguration.cs | 16 +++ .../FlickrConfiguration.cs | 17 +++ .../ImgurConfiguration.cs | 19 ++- 5 files changed, 121 insertions(+), 79 deletions(-) diff --git a/src/Greenshot.Base/Core/CoreConfiguration.cs b/src/Greenshot.Base/Core/CoreConfiguration.cs index 580af8918..80ad3b719 100644 --- a/src/Greenshot.Base/Core/CoreConfiguration.cs +++ b/src/Greenshot.Base/Core/CoreConfiguration.cs @@ -388,89 +388,64 @@ namespace Greenshot.Base.Core return ExperimentalFeatures != null && ExperimentalFeatures.Contains(experimentalFeature); } + private string CreateOutputFilePath() + { + if (IniConfig.IsPortable) + { + string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots"); + if (!Directory.Exists(pafOutputFilePath)) + { + try + { + Directory.CreateDirectory(pafOutputFilePath); + return pafOutputFilePath; + } + catch (Exception ex) + { + // Problem creating directory, fallback to Desktop + LOG.Warn(ex); + } + } + else + { + return pafOutputFilePath; + } + } + + return Environment.GetFolderPath(Environment.SpecialFolder.Desktop); + } + /// /// Supply values we can't put as defaults /// /// The property to return a default for /// object with the default value for the supplied property - public override object GetDefault(string property) - { - switch (property) + public override object GetDefault(string property) => + property switch { - case nameof(ExcludePlugins): - case nameof(IncludePlugins): - return new List(); - case nameof(OutputFileAsFullpath): - if (IniConfig.IsPortable) - { - return Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png"); - } - - return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "dummy.png"); - case nameof(OutputFilePath): - if (IniConfig.IsPortable) - { - string pafOutputFilePath = Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots"); - if (!Directory.Exists(pafOutputFilePath)) - { - try - { - Directory.CreateDirectory(pafOutputFilePath); - return pafOutputFilePath; - } - catch (Exception ex) - { - LOG.Warn(ex); - // Problem creating directory, fallback to Desktop - } - } - else - { - return pafOutputFilePath; - } - } - - return Environment.GetFolderPath(Environment.SpecialFolder.Desktop); - case nameof(DWMBackgroundColor): - return Color.Transparent; - case nameof(ActiveTitleFixes): - return new List - { - "Firefox", - "IE", - "Chrome" - }; - case nameof(TitleFixMatcher): - return new Dictionary - { - { - "Firefox", " - Mozilla Firefox.*" - }, - { - "IE", " - (Microsoft|Windows) Internet Explorer.*" - }, - { - "Chrome", " - Google Chrome.*" - } - }; - case nameof(TitleFixReplacer): - return new Dictionary - { - { - "Firefox", string.Empty - }, - { - "IE", string.Empty - }, - { - "Chrome", string.Empty - } - }; - } - - return null; - } - + nameof(ExcludePlugins) => new List(), + nameof(IncludePlugins) => new List(), + nameof(OutputFileAsFullpath) => IniConfig.IsPortable ? Path.Combine(Application.StartupPath, @"..\..\Documents\Pictures\Greenshots\dummy.png") : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "dummy.png"), + nameof(OutputFilePath) => CreateOutputFilePath(), + nameof(DWMBackgroundColor) => Color.Transparent, + nameof(ActiveTitleFixes) => new List { + "Firefox", + "IE", + "Chrome" + }, + nameof(TitleFixMatcher) => new Dictionary { + { "Firefox", " - Mozilla Firefox.*" }, + { "IE", " - (Microsoft|Windows) Internet Explorer.*" }, + { "Chrome", " - Google Chrome.*" } + }, + nameof(TitleFixReplacer) => new Dictionary { + { "Firefox", string.Empty }, + { "IE", string.Empty }, + { "Chrome", string.Empty } + }, + _ => null + }; + /// /// This method will be called before converting the property, making to possible to correct a certain value /// Can be used when migration is needed @@ -540,8 +515,9 @@ namespace Greenshot.Base.Core OutputFileAutoReduceColors = false; } + bool isUpgradeFrom12 = LastSaveWithVersion?.StartsWith("1.2") ?? false; // Fix for excessive feed checking - if (UpdateCheckInterval != 0 && UpdateCheckInterval <= 7 && LastSaveWithVersion.StartsWith("1.2")) + if (UpdateCheckInterval != 0 && UpdateCheckInterval <= 7 && isUpgradeFrom12) { UpdateCheckInterval = 14; } diff --git a/src/Greenshot.Plugin.Box/BoxConfiguration.cs b/src/Greenshot.Plugin.Box/BoxConfiguration.cs index fdef95ae5..c745fe985 100644 --- a/src/Greenshot.Plugin.Box/BoxConfiguration.cs +++ b/src/Greenshot.Plugin.Box/BoxConfiguration.cs @@ -21,6 +21,7 @@ using System; using System.Windows.Forms; +using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Plugin.Box.Forms; @@ -75,5 +76,20 @@ namespace Greenshot.Plugin.Box return false; } + + /// + /// Upgrade certain values + /// + public override void AfterLoad() + { + var coreConfiguration = IniConfig.GetIniSection(); + bool isUpgradeFrom12 = coreConfiguration.LastSaveWithVersion?.StartsWith("1.2") ?? false; + // Clear token when we upgrade from 1.2 to 1.3 as it is no longer valid, discussed in #421 + if (!isUpgradeFrom12) return; + + // We have an upgrade, remove all previous credentials. + RefreshToken = null; + AccessToken = null; + } } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/DropboxConfiguration.cs b/src/Greenshot.Plugin.Dropbox/DropboxConfiguration.cs index b9dd8bf0c..d79db8686 100644 --- a/src/Greenshot.Plugin.Dropbox/DropboxConfiguration.cs +++ b/src/Greenshot.Plugin.Dropbox/DropboxConfiguration.cs @@ -21,6 +21,7 @@ using System; using System.Windows.Forms; +using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Plugin.Dropbox.Forms; @@ -69,5 +70,20 @@ namespace Greenshot.Plugin.Dropbox return false; } + + /// + /// Upgrade certain values + /// + public override void AfterLoad() + { + var coreConfiguration = IniConfig.GetIniSection(); + bool isUpgradeFrom12 = coreConfiguration.LastSaveWithVersion?.StartsWith("1.2") ?? false; + // Clear token when we upgrade from 1.2 to 1.3 as it is no longer valid, discussed in #421 + if (!isUpgradeFrom12) return; + + // We have an upgrade, remove all previous credentials. + RefreshToken = null; + AccessToken = null; + } } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs index e4f602796..df5a428fa 100644 --- a/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs +++ b/src/Greenshot.Plugin.Flickr/FlickrConfiguration.cs @@ -20,6 +20,7 @@ */ using System.Windows.Forms; +using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Plugin.Flickr.Forms; @@ -86,5 +87,21 @@ namespace Greenshot.Plugin.Flickr return false; } + + /// + /// Upgrade certain values + /// + public override void AfterLoad() + { + var coreConfiguration = IniConfig.GetIniSection(); + bool isUpgradeFrom12 = coreConfiguration.LastSaveWithVersion?.StartsWith("1.2") ?? false; + // Clear token when we upgrade from 1.2 to 1.3 as it is no longer valid, discussed in #421 + if (!isUpgradeFrom12) return; + + // We have an upgrade, remove all previous credentials. + FlickrToken = null; + FlickrTokenSecret = null; + } + } } \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs index 3bb695672..3dc145d0b 100644 --- a/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs +++ b/src/Greenshot.Plugin.Imgur/ImgurConfiguration.cs @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.Windows.Forms; +using Greenshot.Base.Core; using Greenshot.Base.Core.Enums; using Greenshot.Base.IniFile; using Greenshot.Plugin.Imgur.Forms; @@ -84,6 +85,22 @@ namespace Greenshot.Plugin.Imgur public Dictionary runtimeImgurHistory = new Dictionary(); public int Credits { get; set; } + /// + /// Upgrade certain values + /// + public override void AfterLoad() + { + var coreConfiguration = IniConfig.GetIniSection(); + bool isUpgradeFrom12 = coreConfiguration.LastSaveWithVersion?.StartsWith("1.2") ?? false; + // Clear token when we upgrade from 1.2 to 1.3 as it is no longer valid, discussed in #421 + if (!isUpgradeFrom12) return; + + // We have an upgrade, remove all previous credentials. + AccessToken = null; + RefreshToken = null; + AccessTokenExpires = default; + } + /// /// Supply values we can't put as defaults /// @@ -92,7 +109,7 @@ namespace Greenshot.Plugin.Imgur public override object GetDefault(string property) => property switch { - "ImgurUploadHistory" => new Dictionary(), + nameof(ImgurUploadHistory) => new Dictionary(), _ => null }; From bfa8e2444e7d704f51e255765a812aa827416642 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 30 Jun 2022 23:34:51 +0200 Subject: [PATCH 196/232] This should hopefully fix an overflow exception while decoding the dib format. --- .../FileFormatHandlers/DibFileFormatHandler.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs index ad129c4ba..b14a33bd0 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/DibFileFormatHandler.cs @@ -100,8 +100,7 @@ namespace Greenshot.Editor.FileFormatHandlers bitmap = new Bitmap(infoHeader.Width, infoHeader.Height, -(int)(infoHeader.SizeImage / infoHeader.Height), infoHeader.BitCount == 32 ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb, - new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + - (infoHeader.Height - 1) * (int)(infoHeader.SizeImage / infoHeader.Height)) + IntPtr.Add(handle.AddrOfPinnedObject(), (int)infoHeader.OffsetToPixels + (infoHeader.Height - 1) * (int)(infoHeader.SizeImage / infoHeader.Height)) ); } catch (Exception ex) From 2b5e45e33e87ee156edd2b28eaa392d5461775ef Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Thu, 30 Jun 2022 23:47:38 +0200 Subject: [PATCH 197/232] Fixed a log error, and made the ClipboardHotkey optional. --- src/Greenshot.Base/Core/ClipboardHelper.cs | 2 +- src/Greenshot.Base/Core/CoreConfiguration.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs index 7a30a1143..ed9f2c3e9 100644 --- a/src/Greenshot.Base/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -520,7 +520,7 @@ EndSelection:<<<<<<<4 Bitmap singleImage = GetImage(dataObject); if (singleImage != null) { - Log.InfoFormat($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}"); + Log.Info($"Got {singleImage.GetType()} from clipboard with size {singleImage.Size}"); yield return singleImage; yield break; } diff --git a/src/Greenshot.Base/Core/CoreConfiguration.cs b/src/Greenshot.Base/Core/CoreConfiguration.cs index 80ad3b719..3e085bc9b 100644 --- a/src/Greenshot.Base/Core/CoreConfiguration.cs +++ b/src/Greenshot.Base/Core/CoreConfiguration.cs @@ -59,7 +59,7 @@ namespace Greenshot.Base.Core [IniProperty("IEHotkey", Description = "Hotkey for starting the IE capture", DefaultValue = "Shift + Ctrl + PrintScreen")] public string IEHotkey { get; set; } - [IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor")] + [IniProperty("ClipboardHotkey", Description = "Hotkey for opening the clipboard contents into the editor", ExcludeIfNull = true)] public string ClipboardHotkey { get; set; } [IniProperty("IsFirstLaunch", Description = "Is this the first time launch?", DefaultValue = "true")] From ba8ed074c8b3078a25c5abe9c2448c37bb492a6c Mon Sep 17 00:00:00 2001 From: jdavila71 <49653176+jdavila71@users.noreply.github.com> Date: Wed, 17 Aug 2022 16:01:01 -0400 Subject: [PATCH 198/232] Fix of BUG-2951, issues with finding Office installations (#431) --- src/Greenshot.Base/Core/PluginUtils.cs | 74 ++++++++++++++++++- .../Destinations/ExcelDestination.cs | 5 +- .../Destinations/OneNoteDestination.cs | 4 +- .../Destinations/OutlookDestination.cs | 5 +- .../Destinations/PowerpointDestination.cs | 4 +- .../Destinations/WordDestination.cs | 4 +- 6 files changed, 89 insertions(+), 7 deletions(-) diff --git a/src/Greenshot.Base/Core/PluginUtils.cs b/src/Greenshot.Base/Core/PluginUtils.cs index d41e545a5..6a2755d50 100644 --- a/src/Greenshot.Base/Core/PluginUtils.cs +++ b/src/Greenshot.Base/Core/PluginUtils.cs @@ -40,13 +40,85 @@ namespace Greenshot.Base.Core private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils)); private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\"; + private static string[] strRootKeys = { @"SOFTWARE\Microsoft\Office", @"SOFTWARE\WOW6432Node\Microsoft\Office" }; private static readonly IDictionary ExeIconCache = new Dictionary(); static PluginUtils() { CoreConfig.PropertyChanged += OnIconSizeChanged; } + /// + /// Clear icon cache + /// + /// + /// + public static string GetOfficeExePath(string keyname) + { + string strKeyName = keyname switch + { + "WINWORD.EXE" => "Word", + "EXCEL.EXE" => "Excel", + "POWERPNT.EXE" => "PowerPoint", + "OUTLOOK.EXE" => "Outlook", + "ONENOTE.EXE" => "OneNote", + _ => "" + }; + RegistryKey rootKey = null; + RegistryKey officeKey = null; + RegistryKey programKey = null; + RegistryKey installRootKey = null; + string retValue = string.Empty; + + foreach (string strRootKey in strRootKeys) + { + rootKey = Registry.LocalMachine.OpenSubKey(strRootKey); + + if (rootKey != null) + { + string[] officeVersions = rootKey.GetSubKeyNames(); + if (officeVersions is null) + continue; + officeVersions = Array.FindAll(officeVersions, r => r.Contains(".")); + Array.Reverse(officeVersions); + // string latestOfficeVersion = officeVersions.Where(r => r.Contains(".")).Max(); + + foreach (string officeVersion in officeVersions) + { + officeKey = Registry.LocalMachine.OpenSubKey(strRootKey + "\\" + officeVersion); + + if (officeKey is null) + continue; + + programKey = officeKey.OpenSubKey(strKeyName); + + if (programKey is null) + continue; + + installRootKey = programKey.OpenSubKey("InstallRoot"); + + if (installRootKey != null) + { + retValue = installRootKey.GetValue("Path").ToString() + "\\" + keyname; + break; + + } + + } + + + } + } + if (rootKey != null) + rootKey.Dispose(); + if (officeKey != null) + officeKey.Dispose(); + if (programKey != null) + programKey.Dispose(); + if (installRootKey != null) + installRootKey.Dispose(); + return retValue; + } /// /// Clear icon cache /// @@ -84,7 +156,7 @@ namespace Greenshot.Base.Core if (key != null) { // "" is the default key, which should point to the requested location - return (string) key.GetValue(string.Empty); + return (string)key.GetValue(string.Empty); } } diff --git a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs index fb1930c8c..8c13e4754 100644 --- a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs @@ -42,7 +42,10 @@ namespace Greenshot.Plugin.Office.Destinations static ExcelDestination() { - ExePath = PluginUtils.GetExePath("EXCEL.EXE"); + ExePath = PluginUtils.GetOfficeExePath("EXCEL.EXE"); + if (ExePath == null) + ExePath = PluginUtils.GetExePath("EXCEL.EXE"); + if (ExePath != null && File.Exists(ExePath)) { WindowDetails.AddProcessToExcludeFromFreeze("excel"); diff --git a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs index 387810494..a2ab24937 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs @@ -41,7 +41,9 @@ namespace Greenshot.Plugin.Office.Destinations static OneNoteDestination() { - exePath = PluginUtils.GetExePath("ONENOTE.EXE"); + exePath = PluginUtils.GetOfficeExePath("ONENOTE.EXE"); + if (exePath == null) + exePath = PluginUtils.GetExePath("ONENOTE.EXE"); if (exePath != null && File.Exists(exePath)) { WindowDetails.AddProcessToExcludeFromFreeze("onenote"); diff --git a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs index 6d93c4096..68cdd706b 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs @@ -58,8 +58,9 @@ namespace Greenshot.Plugin.Office.Destinations { IsActiveFlag = true; } - - ExePath = PluginUtils.GetExePath("OUTLOOK.EXE"); + ExePath = PluginUtils.GetOfficeExePath("OUTLOOK.EXE"); + if (ExePath == null) + ExePath = PluginUtils.GetExePath("OUTLOOK.EXE"); if (ExePath != null && File.Exists(ExePath)) { WindowDetails.AddProcessToExcludeFromFreeze("outlook"); diff --git a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs index 3b9ce4bc8..34f734cc4 100644 --- a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs @@ -45,7 +45,9 @@ namespace Greenshot.Plugin.Office.Destinations static PowerpointDestination() { - ExePath = PluginUtils.GetExePath("POWERPNT.EXE"); + ExePath = PluginUtils.GetOfficeExePath("POWERPNT.EXE"); + if (ExePath == null) + ExePath = PluginUtils.GetExePath("POWERPNT.EXE"); if (ExePath != null && File.Exists(ExePath)) { WindowDetails.AddProcessToExcludeFromFreeze("powerpnt"); diff --git a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs index 99cf4693c..34dfebad7 100644 --- a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs @@ -46,7 +46,9 @@ namespace Greenshot.Plugin.Office.Destinations static WordDestination() { - ExePath = PluginUtils.GetExePath("WINWORD.EXE"); + ExePath = PluginUtils.GetOfficeExePath("WINWORD.EXE"); + if (ExePath == null) + ExePath = PluginUtils.GetExePath("WINWORD.EXE"); if (ExePath != null && !File.Exists(ExePath)) { ExePath = null; From 3e8809384692a713eb42f6b992cd1c4f43808a28 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 17 Aug 2022 23:01:24 +0200 Subject: [PATCH 199/232] Some aftercare for #431, moved the code to find the path for the office executables to the office plugin, as this is where it's needed. Also optimized the code a bit, using modern features. --- src/Directory.Build.props | 4 +- src/Greenshot.Base/Core/PluginUtils.cs | 77 +------------------ src/Greenshot.Base/Greenshot.Base.csproj | 4 +- .../Destinations/ExcelDestination.cs | 4 +- .../Destinations/OneNoteDestination.cs | 4 +- .../Destinations/OutlookDestination.cs | 4 +- .../Destinations/PowerpointDestination.cs | 4 +- .../Destinations/WordDestination.cs | 6 +- src/Greenshot.Plugin.Office/OfficeUtils.cs | 52 +++++++++++++ 9 files changed, 65 insertions(+), 94 deletions(-) create mode 100644 src/Greenshot.Plugin.Office/OfficeUtils.cs diff --git a/src/Directory.Build.props b/src/Directory.Build.props index f5b9f2e1c..2fbce49ed 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -7,7 +7,7 @@ git https://github.com/greenshot/greenshot GPL-3.0-only - 9 + 10 true true win10-x64;win10-x86;win-x64;win-x86 @@ -46,7 +46,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/src/Greenshot.Base/Core/PluginUtils.cs b/src/Greenshot.Base/Core/PluginUtils.cs index 6a2755d50..76f08422b 100644 --- a/src/Greenshot.Base/Core/PluginUtils.cs +++ b/src/Greenshot.Base/Core/PluginUtils.cs @@ -24,6 +24,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; +using System.Linq; using System.Windows.Forms; using Dapplo.Windows.Icons; using Greenshot.Base.IniFile; @@ -39,86 +40,14 @@ namespace Greenshot.Base.Core { private static readonly ILog Log = LogManager.GetLogger(typeof(PluginUtils)); private static readonly CoreConfiguration CoreConfig = IniConfig.GetIniSection(); - private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\"; - private static string[] strRootKeys = { @"SOFTWARE\Microsoft\Office", @"SOFTWARE\WOW6432Node\Microsoft\Office" }; private static readonly IDictionary ExeIconCache = new Dictionary(); - + private const string PathKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\"; + static PluginUtils() { CoreConfig.PropertyChanged += OnIconSizeChanged; } - /// - /// Clear icon cache - /// - /// - /// - public static string GetOfficeExePath(string keyname) - { - string strKeyName = keyname switch - { - "WINWORD.EXE" => "Word", - "EXCEL.EXE" => "Excel", - "POWERPNT.EXE" => "PowerPoint", - "OUTLOOK.EXE" => "Outlook", - "ONENOTE.EXE" => "OneNote", - _ => "" - }; - RegistryKey rootKey = null; - RegistryKey officeKey = null; - RegistryKey programKey = null; - RegistryKey installRootKey = null; - string retValue = string.Empty; - - foreach (string strRootKey in strRootKeys) - { - rootKey = Registry.LocalMachine.OpenSubKey(strRootKey); - - if (rootKey != null) - { - string[] officeVersions = rootKey.GetSubKeyNames(); - if (officeVersions is null) - continue; - officeVersions = Array.FindAll(officeVersions, r => r.Contains(".")); - Array.Reverse(officeVersions); - // string latestOfficeVersion = officeVersions.Where(r => r.Contains(".")).Max(); - - foreach (string officeVersion in officeVersions) - { - officeKey = Registry.LocalMachine.OpenSubKey(strRootKey + "\\" + officeVersion); - - if (officeKey is null) - continue; - - programKey = officeKey.OpenSubKey(strKeyName); - - if (programKey is null) - continue; - - installRootKey = programKey.OpenSubKey("InstallRoot"); - - if (installRootKey != null) - { - retValue = installRootKey.GetValue("Path").ToString() + "\\" + keyname; - break; - - } - - } - - - } - } - if (rootKey != null) - rootKey.Dispose(); - if (officeKey != null) - officeKey.Dispose(); - if (programKey != null) - programKey.Dispose(); - if (installRootKey != null) - installRootKey.Dispose(); - return retValue; - } /// /// Clear icon cache /// diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index a698b8e0b..021ea53ec 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs index 8c13e4754..1a671cf7a 100644 --- a/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/ExcelDestination.cs @@ -42,9 +42,7 @@ namespace Greenshot.Plugin.Office.Destinations static ExcelDestination() { - ExePath = PluginUtils.GetOfficeExePath("EXCEL.EXE"); - if (ExePath == null) - ExePath = PluginUtils.GetExePath("EXCEL.EXE"); + ExePath = OfficeUtils.GetOfficeExePath("EXCEL.EXE") ?? PluginUtils.GetExePath("EXCEL.EXE"); if (ExePath != null && File.Exists(ExePath)) { diff --git a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs index a2ab24937..5f8da7a67 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OneNoteDestination.cs @@ -41,9 +41,7 @@ namespace Greenshot.Plugin.Office.Destinations static OneNoteDestination() { - exePath = PluginUtils.GetOfficeExePath("ONENOTE.EXE"); - if (exePath == null) - exePath = PluginUtils.GetExePath("ONENOTE.EXE"); + exePath = OfficeUtils.GetOfficeExePath("ONENOTE.EXE") ?? PluginUtils.GetExePath("ONENOTE.EXE"); if (exePath != null && File.Exists(exePath)) { WindowDetails.AddProcessToExcludeFromFreeze("onenote"); diff --git a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs index 68cdd706b..3c77ea4f1 100644 --- a/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/OutlookDestination.cs @@ -58,9 +58,7 @@ namespace Greenshot.Plugin.Office.Destinations { IsActiveFlag = true; } - ExePath = PluginUtils.GetOfficeExePath("OUTLOOK.EXE"); - if (ExePath == null) - ExePath = PluginUtils.GetExePath("OUTLOOK.EXE"); + ExePath = OfficeUtils.GetOfficeExePath("OUTLOOK.EXE") ?? PluginUtils.GetExePath("OUTLOOK.EXE"); if (ExePath != null && File.Exists(ExePath)) { WindowDetails.AddProcessToExcludeFromFreeze("outlook"); diff --git a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs index 34f734cc4..010093027 100644 --- a/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/PowerpointDestination.cs @@ -45,9 +45,7 @@ namespace Greenshot.Plugin.Office.Destinations static PowerpointDestination() { - ExePath = PluginUtils.GetOfficeExePath("POWERPNT.EXE"); - if (ExePath == null) - ExePath = PluginUtils.GetExePath("POWERPNT.EXE"); + ExePath = OfficeUtils.GetOfficeExePath("POWERPNT.EXE") ?? PluginUtils.GetExePath("POWERPNT.EXE"); if (ExePath != null && File.Exists(ExePath)) { WindowDetails.AddProcessToExcludeFromFreeze("powerpnt"); diff --git a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs index 34dfebad7..d6220a302 100644 --- a/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs +++ b/src/Greenshot.Plugin.Office/Destinations/WordDestination.cs @@ -46,9 +46,7 @@ namespace Greenshot.Plugin.Office.Destinations static WordDestination() { - ExePath = PluginUtils.GetOfficeExePath("WINWORD.EXE"); - if (ExePath == null) - ExePath = PluginUtils.GetExePath("WINWORD.EXE"); + ExePath = OfficeUtils.GetOfficeExePath("WINWORD.EXE") ?? PluginUtils.GetExePath("WINWORD.EXE"); if (ExePath != null && !File.Exists(ExePath)) { ExePath = null; @@ -120,7 +118,7 @@ namespace Greenshot.Plugin.Office.Destinations if (!manuallyInitiated) { var documents = _wordExporter.GetWordDocuments().ToList(); - if (documents != null && documents.Count > 0) + if (documents is { Count: > 0 }) { var destinations = new List { diff --git a/src/Greenshot.Plugin.Office/OfficeUtils.cs b/src/Greenshot.Plugin.Office/OfficeUtils.cs new file mode 100644 index 000000000..770f8b1e8 --- /dev/null +++ b/src/Greenshot.Plugin.Office/OfficeUtils.cs @@ -0,0 +1,52 @@ +using System.Linq; +using Microsoft.Win32; + +namespace Greenshot.Plugin.Office; + +/// +/// A small utility class for helping with office +/// +internal static class OfficeUtils +{ + private static readonly string[] OfficeRootKeys = { @"SOFTWARE\Microsoft\Office", @"SOFTWARE\WOW6432Node\Microsoft\Office" }; + + /// + /// Get the path to the office exe + /// + /// Name of the office executable + public static string GetOfficeExePath(string exeName) + { + string strKeyName = exeName switch + { + "WINWORD.EXE" => "Word", + "EXCEL.EXE" => "Excel", + "POWERPNT.EXE" => "PowerPoint", + "OUTLOOK.EXE" => "Outlook", + "ONENOTE.EXE" => "OneNote", + _ => "" + }; + + foreach (string strRootKey in OfficeRootKeys) + { + using RegistryKey rootKey = Registry.LocalMachine.OpenSubKey(strRootKey); + + if (rootKey is null) continue; + + + foreach (string officeVersion in rootKey.GetSubKeyNames().Where(r => r.Contains(".")).Reverse()) + { + using RegistryKey officeKey = Registry.LocalMachine.OpenSubKey(strRootKey + "\\" + officeVersion); + if (officeKey is null) continue; + + using RegistryKey programKey = officeKey.OpenSubKey(strKeyName); + if (programKey is null) continue; + + using RegistryKey installRootKey = programKey.OpenSubKey("InstallRoot"); + if (installRootKey == null) continue; + + return installRootKey.GetValue("Path") + "\\" + exeName; + } + } + return string.Empty; + } +} From af3c22c38c33ffdd88c77f7d97d20531a1dff5f8 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 17 Aug 2022 23:08:59 +0200 Subject: [PATCH 200/232] Optimized the code to find the office executable even more. --- src/Greenshot.Plugin.Office/OfficeUtils.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Greenshot.Plugin.Office/OfficeUtils.cs b/src/Greenshot.Plugin.Office/OfficeUtils.cs index 770f8b1e8..4b828c558 100644 --- a/src/Greenshot.Plugin.Office/OfficeUtils.cs +++ b/src/Greenshot.Plugin.Office/OfficeUtils.cs @@ -35,16 +35,9 @@ internal static class OfficeUtils foreach (string officeVersion in rootKey.GetSubKeyNames().Where(r => r.Contains(".")).Reverse()) { - using RegistryKey officeKey = Registry.LocalMachine.OpenSubKey(strRootKey + "\\" + officeVersion); - if (officeKey is null) continue; - - using RegistryKey programKey = officeKey.OpenSubKey(strKeyName); - if (programKey is null) continue; - - using RegistryKey installRootKey = programKey.OpenSubKey("InstallRoot"); + using RegistryKey installRootKey = Registry.LocalMachine.OpenSubKey($@"{strRootKey}\{officeVersion}\{strKeyName}\InstallRoot"); if (installRootKey == null) continue; - - return installRootKey.GetValue("Path") + "\\" + exeName; + return $@"{installRootKey.GetValue("Path")}\{exeName}"; } } return string.Empty; From 296dc9f34083dea09b819d91fe45f5b9031cad0c Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 17 Aug 2022 23:09:44 +0200 Subject: [PATCH 201/232] Formatting --- src/Greenshot.Plugin.Office/OfficeUtils.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Greenshot.Plugin.Office/OfficeUtils.cs b/src/Greenshot.Plugin.Office/OfficeUtils.cs index 4b828c558..78be20557 100644 --- a/src/Greenshot.Plugin.Office/OfficeUtils.cs +++ b/src/Greenshot.Plugin.Office/OfficeUtils.cs @@ -29,10 +29,8 @@ internal static class OfficeUtils foreach (string strRootKey in OfficeRootKeys) { using RegistryKey rootKey = Registry.LocalMachine.OpenSubKey(strRootKey); - if (rootKey is null) continue; - foreach (string officeVersion in rootKey.GetSubKeyNames().Where(r => r.Contains(".")).Reverse()) { using RegistryKey installRootKey = Registry.LocalMachine.OpenSubKey($@"{strRootKey}\{officeVersion}\{strKeyName}\InstallRoot"); From 511034a34be0b87c28bb6a093026e75a40aa5b90 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 17 Aug 2022 23:12:55 +0200 Subject: [PATCH 202/232] Fixed the return value of the GetOfficeExePath, this should be null so it's clear the file hasn't been found. --- src/Greenshot.Plugin.Office/OfficeUtils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Greenshot.Plugin.Office/OfficeUtils.cs b/src/Greenshot.Plugin.Office/OfficeUtils.cs index 78be20557..52ca8d7cb 100644 --- a/src/Greenshot.Plugin.Office/OfficeUtils.cs +++ b/src/Greenshot.Plugin.Office/OfficeUtils.cs @@ -38,6 +38,6 @@ internal static class OfficeUtils return $@"{installRootKey.GetValue("Path")}\{exeName}"; } } - return string.Empty; + return null; } } From 029d47f479abadf5382daddc456790ad43a2e798 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sat, 3 Sep 2022 15:11:16 +0200 Subject: [PATCH 203/232] Added some NPE protections for BUG-2991 --- src/Greenshot.Base/Core/ClipboardHelper.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Greenshot.Base/Core/ClipboardHelper.cs b/src/Greenshot.Base/Core/ClipboardHelper.cs index ed9f2c3e9..bfe13c121 100644 --- a/src/Greenshot.Base/Core/ClipboardHelper.cs +++ b/src/Greenshot.Base/Core/ClipboardHelper.cs @@ -386,6 +386,7 @@ EndSelection:<<<<<<<4 /// IEnumerable{(MemoryStream,string)} private static IEnumerable<(MemoryStream stream,string filename)> IterateClipboardContent(IDataObject dataObject) { + if (dataObject == null) yield break; var fileDescriptors = AvailableFileDescriptors(dataObject); if (fileDescriptors == null) yield break; @@ -499,6 +500,10 @@ EndSelection:<<<<<<<4 public static Image GetImage() { IDataObject clipboardData = GetDataObject(); + if (clipboardData == null) + { + return null; + } // Return the first image foreach (var clipboardImage in GetImages(clipboardData)) { From 9634f8abbc119959d84b940c14f8abcad0b709ff Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Sun, 4 Sep 2022 15:35:38 +0200 Subject: [PATCH 204/232] Updated dependencies. --- src/Directory.Build.props | 4 ++-- src/Greenshot.Base/Greenshot.Base.csproj | 16 ++++++++-------- .../Greenshot.Plugin.Jira.csproj | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 2fbce49ed..869f3b94d 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,13 +1,13 @@  - Copyright © Greenshot 2004-2021 + Copyright © Greenshot 2004-2022 Greenshot https://getgreenshot.org/favicon.ico https://github.com/greenshot/greenshot git https://github.com/greenshot/greenshot GPL-3.0-only - 10 + latest true true win10-x64;win10-x86;win-x64;win-x86 diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index 021ea53ec..15910a7d2 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -5,14 +5,14 @@ - - - - - - - - + + + + + + + + diff --git a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj index 40f2caf2d..a06e33882 100644 --- a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj +++ b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj @@ -6,7 +6,7 @@ - - + + \ No newline at end of file From 4c6707b468561207d553e56314817020661c7ba8 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 28 Sep 2022 20:53:57 +0200 Subject: [PATCH 205/232] Fixed #432, inflate is not the best way of increasing a rectangle size. --- src/Greenshot/Forms/CaptureForm.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs index 68e57f040..47dc6e0f6 100644 --- a/src/Greenshot/Forms/CaptureForm.cs +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -197,7 +197,7 @@ namespace Greenshot.Forms private void CaptureForm_Resize(object sender, EventArgs e) { Log.DebugFormat("Resize was called, new size: {0}", this.Bounds); - if (Bounds.Equals(_capture.ScreenBounds)) + if (_capture.ScreenBounds.Equals(Bounds)) { // We have the correct size return; @@ -425,9 +425,11 @@ namespace Greenshot.Forms else if (_captureRect.Height > 0 && _captureRect.Width > 0) { // correct the GUI width to real width if Region mode - if (_captureMode == CaptureMode.Region || _captureMode == CaptureMode.Text) + if (_captureMode is CaptureMode.Region or CaptureMode.Text) { - _captureRect = _captureRect.Inflate(1, 1); + // Correct the rectangle size, by making it 1 pixel bigger + // We cannot use inflate, this would make the rect bigger to all sizes. + _captureRect = new NativeRect(_captureRect.Top, _captureRect.Left, _captureRect.Width+1, _captureRect.Height+1); } // Go and process the capture From 7e005f741a3f009a1f974ac80d6f6018fdc7528d Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Wed, 5 Oct 2022 22:29:01 +0200 Subject: [PATCH 206/232] Fixed #441, swapped left & top. --- src/Directory.Build.props | 2 +- src/Greenshot.Base/Greenshot.Base.csproj | 2 +- src/Greenshot/Forms/CaptureForm.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 869f3b94d..131878749 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -46,7 +46,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index 15910a7d2..7e55c1dbc 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/Greenshot/Forms/CaptureForm.cs b/src/Greenshot/Forms/CaptureForm.cs index 47dc6e0f6..107aa9096 100644 --- a/src/Greenshot/Forms/CaptureForm.cs +++ b/src/Greenshot/Forms/CaptureForm.cs @@ -429,7 +429,7 @@ namespace Greenshot.Forms { // Correct the rectangle size, by making it 1 pixel bigger // We cannot use inflate, this would make the rect bigger to all sizes. - _captureRect = new NativeRect(_captureRect.Top, _captureRect.Left, _captureRect.Width+1, _captureRect.Height+1); + _captureRect = new NativeRect(_captureRect.Left, _captureRect.Top, _captureRect.Width+1, _captureRect.Height+1); } // Go and process the capture From a152e2883fca7f78051b3bd6b1e5cc57355cb44c Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 27 Mar 2023 21:51:01 +0200 Subject: [PATCH 207/232] This should improve the backwards compatibility for the .greenshot file from earlier versions. This was also addressed in #375 --- .../Drawing/FreehandContainer.cs | 646 +++++++++--------- .../Drawing/SpeechbubbleContainer.cs | 7 +- src/Greenshot.Editor/Drawing/Surface.cs | 7 + .../Helpers/BinaryFormatterHelper.cs | 111 +++ 4 files changed, 446 insertions(+), 325 deletions(-) create mode 100644 src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs diff --git a/src/Greenshot.Editor/Drawing/FreehandContainer.cs b/src/Greenshot.Editor/Drawing/FreehandContainer.cs index b8a66be4e..9c66e1a8e 100644 --- a/src/Greenshot.Editor/Drawing/FreehandContainer.cs +++ b/src/Greenshot.Editor/Drawing/FreehandContainer.cs @@ -1,323 +1,325 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Runtime.Serialization; -using Dapplo.Windows.Common.Structs; -using Greenshot.Base.Interfaces; -using Greenshot.Base.Interfaces.Drawing; -using Greenshot.Editor.Drawing.Fields; -using Greenshot.Editor.Helpers; - -namespace Greenshot.Editor.Drawing -{ - /// - /// Description of PathContainer. - /// - [Serializable] - public class FreehandContainer : DrawableContainer - { - private static readonly float[] PointOffset = - { - 0.5f, 0.25f, 0.75f - }; - - [NonSerialized] private GraphicsPath freehandPath = new GraphicsPath(); - private NativeRect myBounds = NativeRect.Empty; - private NativePoint lastMouse = NativePoint.Empty; - private readonly List capturePoints = new List(); - private bool isRecalculated; - - /// - /// Constructor - /// - public FreehandContainer(ISurface parent) : base(parent) - { - Width = parent.Image.Width; - Height = parent.Image.Height; - Top = 0; - Left = 0; - } - - protected override void InitializeFields() - { - AddField(GetType(), FieldType.LINE_THICKNESS, 3); - AddField(GetType(), FieldType.LINE_COLOR, Color.Red); - } - - public override void Transform(Matrix matrix) - { - Point[] points = capturePoints.ToArray(); - - matrix.TransformPoints(points); - capturePoints.Clear(); - capturePoints.AddRange(points); - RecalculatePath(); - } - - protected override void OnDeserialized(StreamingContext context) - { - RecalculatePath(); - } - - /// - /// This Dispose is called from the Dispose and the Destructor. - /// - /// When disposing==true all non-managed resources should be freed too! - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - freehandPath?.Dispose(); - } - - freehandPath = null; - } - - /// - /// Called from Surface (the parent) when the drawing begins (mouse-down) - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseDown(int mouseX, int mouseY) - { - lastMouse = new Point(mouseX, mouseY); - capturePoints.Add(lastMouse); - return true; - } - - /// - /// Called from Surface (the parent) if a mouse move is made while drawing - /// - /// true if the surface doesn't need to handle the event - public override bool HandleMouseMove(int mouseX, int mouseY) - { - Point previousPoint = capturePoints[capturePoints.Count - 1]; - - if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= 2 * EditorConfig.FreehandSensitivity) - { - capturePoints.Add(new Point(mouseX, mouseY)); - } - - if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) < EditorConfig.FreehandSensitivity) - { - return true; - } - - //path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)}); - lastMouse = new Point(mouseX, mouseY); - freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY)); - // Only re-calculate the bounds & redraw when we added something to the path - myBounds = Rectangle.Round(freehandPath.GetBounds()); - - Invalidate(); - return true; - } - - /// - /// Called when the surface finishes drawing the element - /// - public override void HandleMouseUp(int mouseX, int mouseY) - { - // Make sure we don't loose the ending point - if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) >= EditorConfig.FreehandSensitivity) - { - capturePoints.Add(new Point(mouseX, mouseY)); - } - - RecalculatePath(); - } - - /// - /// Here we recalculate the freehand path by smoothing out the lines with Beziers. - /// - private void RecalculatePath() - { - // Store the previous path, to dispose it later when we are finished - var previousFreehandPath = freehandPath; - var newFreehandPath = new GraphicsPath(); - - // Here we can put some cleanup... like losing all the uninteresting points. - if (capturePoints.Count >= 3) - { - int index = 0; - while ((capturePoints.Count - 1) % 3 != 0) - { - // duplicate points, first at 50% than 25% than 75% - capturePoints.Insert((int) (capturePoints.Count * PointOffset[index]), capturePoints[(int) (capturePoints.Count * PointOffset[index++])]); - } - - newFreehandPath.AddBeziers(capturePoints.ToArray()); - } - else if (capturePoints.Count == 2) - { - newFreehandPath.AddLine(capturePoints[0], capturePoints[1]); - } - - // Recalculate the bounds - myBounds = Rectangle.Round(newFreehandPath.GetBounds()); - - // assign - isRecalculated = true; - freehandPath = newFreehandPath; - - // dispose previous - previousFreehandPath?.Dispose(); - } - - /// - /// Do the drawing of the freehand "stroke" - /// - /// - /// - public override void Draw(Graphics graphics, RenderMode renderMode) - { - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); - using var pen = new Pen(lineColor) - { - Width = lineThickness - }; - if (!(pen.Width > 0)) - { - return; - } - - // Make sure the lines are nicely rounded - pen.EndCap = LineCap.Round; - pen.StartCap = LineCap.Round; - pen.LineJoin = LineJoin.Round; - // Move to where we need to draw - graphics.TranslateTransform(Left, Top); - var currentFreehandPath = freehandPath; - if (currentFreehandPath != null) - { - if (isRecalculated && Selected && renderMode == RenderMode.EDIT) - { - isRecalculated = false; - DrawSelectionBorder(graphics, pen, currentFreehandPath); - } - - graphics.DrawPath(pen, currentFreehandPath); - } - - // Move back, otherwise everything is shifted - graphics.TranslateTransform(-Left, -Top); - } - - /// - /// Draw a selectionborder around the freehand path - /// - /// Graphics - /// Pen - /// GraphicsPath - protected static void DrawSelectionBorder(Graphics graphics, Pen linePen, GraphicsPath path) - { - using var selectionPen = (Pen) linePen.Clone(); - using var selectionPath = (GraphicsPath) path.Clone(); - selectionPen.Width += 5; - selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen); - graphics.DrawPath(selectionPen, selectionPath); - selectionPath.Widen(selectionPen); - selectionPen.DashPattern = new float[] - { - 2, 2 - }; - selectionPen.Color = Color.LightSeaGreen; - selectionPen.Width = 1; - graphics.DrawPath(selectionPen, selectionPath); - } - - /// - /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds... - /// - public override NativeRect DrawingBounds - { - get - { - if (!myBounds.IsEmpty) - { - int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS)); - int safetyMargin = 10; - return new NativeRect(myBounds.Left + Left - (safetyMargin + lineThickness), myBounds.Top + Top - (safetyMargin + lineThickness), - myBounds.Width + 2 * (lineThickness + safetyMargin), myBounds.Height + 2 * (lineThickness + safetyMargin)); - } - - if (_parent?.Image is Image image) - { - return new NativeRect(0, 0, image.Width, image.Height); - } - - return NativeRect.Empty; - } - } - - /// - /// FreehandContainer are regarded equal if they are of the same type and their paths are equal. - /// - /// object - /// bool - public override bool Equals(object obj) - { - bool ret = false; - if (obj == null || GetType() != obj.GetType()) - { - return false; - } - - if (obj is FreehandContainer other && Equals(freehandPath, other.freehandPath)) - { - ret = true; - } - - return ret; - } - - public override int GetHashCode() - { - return freehandPath?.GetHashCode() ?? 0; - } - - public override bool ClickableAt(int x, int y) - { - bool returnValue = base.ClickableAt(x, y); - if (returnValue) - { - int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); - using var pen = new Pen(Color.White) - { - Width = lineThickness + 10 - }; - returnValue = freehandPath.IsOutlineVisible(x - Left, y - Top, pen); - } - - return returnValue; - } - } +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.Serialization; +using Dapplo.Windows.Common.Structs; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Editor.Drawing.Fields; +using Greenshot.Editor.Helpers; + +namespace Greenshot.Editor.Drawing +{ + /// + /// Description of PathContainer. + /// + [Serializable] + public class FreehandContainer : DrawableContainer + { + private static readonly float[] PointOffset = + { + 0.5f, 0.25f, 0.75f + }; + + [NonSerialized] + private GraphicsPath freehandPath = new GraphicsPath(); + + private Rectangle myBounds = NativeRect.Empty; + private Point lastMouse = NativePoint.Empty; + private List capturePoints = new List(); + private bool isRecalculated; + + /// + /// Constructor + /// + public FreehandContainer(ISurface parent) : base(parent) + { + Width = parent.Image.Width; + Height = parent.Image.Height; + Top = 0; + Left = 0; + } + + protected override void InitializeFields() + { + AddField(GetType(), FieldType.LINE_THICKNESS, 3); + AddField(GetType(), FieldType.LINE_COLOR, Color.Red); + } + + public override void Transform(Matrix matrix) + { + Point[] points = capturePoints.ToArray(); + + matrix.TransformPoints(points); + capturePoints.Clear(); + capturePoints.AddRange(points); + RecalculatePath(); + } + + protected override void OnDeserialized(StreamingContext context) + { + RecalculatePath(); + } + + /// + /// This Dispose is called from the Dispose and the Destructor. + /// + /// When disposing==true all non-managed resources should be freed too! + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + freehandPath?.Dispose(); + } + + freehandPath = null; + } + + /// + /// Called from Surface (the parent) when the drawing begins (mouse-down) + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseDown(int mouseX, int mouseY) + { + lastMouse = new Point(mouseX, mouseY); + capturePoints.Add(lastMouse); + return true; + } + + /// + /// Called from Surface (the parent) if a mouse move is made while drawing + /// + /// true if the surface doesn't need to handle the event + public override bool HandleMouseMove(int mouseX, int mouseY) + { + Point previousPoint = capturePoints[capturePoints.Count - 1]; + + if (GeometryHelper.Distance2D(previousPoint.X, previousPoint.Y, mouseX, mouseY) >= 2 * EditorConfig.FreehandSensitivity) + { + capturePoints.Add(new Point(mouseX, mouseY)); + } + + if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) < EditorConfig.FreehandSensitivity) + { + return true; + } + + //path.AddCurve(new Point[]{lastMouse, new Point(mouseX, mouseY)}); + lastMouse = new Point(mouseX, mouseY); + freehandPath.AddLine(lastMouse, new Point(mouseX, mouseY)); + // Only re-calculate the bounds & redraw when we added something to the path + myBounds = Rectangle.Round(freehandPath.GetBounds()); + + Invalidate(); + return true; + } + + /// + /// Called when the surface finishes drawing the element + /// + public override void HandleMouseUp(int mouseX, int mouseY) + { + // Make sure we don't loose the ending point + if (GeometryHelper.Distance2D(lastMouse.X, lastMouse.Y, mouseX, mouseY) >= EditorConfig.FreehandSensitivity) + { + capturePoints.Add(new Point(mouseX, mouseY)); + } + + RecalculatePath(); + } + + /// + /// Here we recalculate the freehand path by smoothing out the lines with Beziers. + /// + private void RecalculatePath() + { + // Store the previous path, to dispose it later when we are finished + var previousFreehandPath = freehandPath; + var newFreehandPath = new GraphicsPath(); + + // Here we can put some cleanup... like losing all the uninteresting points. + if (capturePoints.Count >= 3) + { + int index = 0; + while ((capturePoints.Count - 1) % 3 != 0) + { + // duplicate points, first at 50% than 25% than 75% + capturePoints.Insert((int) (capturePoints.Count * PointOffset[index]), capturePoints[(int) (capturePoints.Count * PointOffset[index++])]); + } + + newFreehandPath.AddBeziers(capturePoints.ToArray()); + } + else if (capturePoints.Count == 2) + { + newFreehandPath.AddLine(capturePoints[0], capturePoints[1]); + } + + // Recalculate the bounds + myBounds = Rectangle.Round(newFreehandPath.GetBounds()); + + // assign + isRecalculated = true; + freehandPath = newFreehandPath; + + // dispose previous + previousFreehandPath?.Dispose(); + } + + /// + /// Do the drawing of the freehand "stroke" + /// + /// + /// + public override void Draw(Graphics graphics, RenderMode renderMode) + { + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + Color lineColor = GetFieldValueAsColor(FieldType.LINE_COLOR); + using var pen = new Pen(lineColor) + { + Width = lineThickness + }; + if (!(pen.Width > 0)) + { + return; + } + + // Make sure the lines are nicely rounded + pen.EndCap = LineCap.Round; + pen.StartCap = LineCap.Round; + pen.LineJoin = LineJoin.Round; + // Move to where we need to draw + graphics.TranslateTransform(Left, Top); + var currentFreehandPath = freehandPath; + if (currentFreehandPath != null) + { + if (isRecalculated && Selected && renderMode == RenderMode.EDIT) + { + isRecalculated = false; + DrawSelectionBorder(graphics, pen, currentFreehandPath); + } + + graphics.DrawPath(pen, currentFreehandPath); + } + + // Move back, otherwise everything is shifted + graphics.TranslateTransform(-Left, -Top); + } + + /// + /// Draw a selectionborder around the freehand path + /// + /// Graphics + /// Pen + /// GraphicsPath + protected static void DrawSelectionBorder(Graphics graphics, Pen linePen, GraphicsPath path) + { + using var selectionPen = (Pen) linePen.Clone(); + using var selectionPath = (GraphicsPath) path.Clone(); + selectionPen.Width += 5; + selectionPen.Color = Color.FromArgb(120, Color.LightSeaGreen); + graphics.DrawPath(selectionPen, selectionPath); + selectionPath.Widen(selectionPen); + selectionPen.DashPattern = new float[] + { + 2, 2 + }; + selectionPen.Color = Color.LightSeaGreen; + selectionPen.Width = 1; + graphics.DrawPath(selectionPen, selectionPath); + } + + /// + /// Get the bounds in which we have something drawn, plus safety margin, these are not the normal bounds... + /// + public override NativeRect DrawingBounds + { + get + { + if (!myBounds.IsEmpty) + { + int lineThickness = Math.Max(10, GetFieldValueAsInt(FieldType.LINE_THICKNESS)); + int safetyMargin = 10; + return new NativeRect(myBounds.Left + Left - (safetyMargin + lineThickness), myBounds.Top + Top - (safetyMargin + lineThickness), + myBounds.Width + 2 * (lineThickness + safetyMargin), myBounds.Height + 2 * (lineThickness + safetyMargin)); + } + + if (_parent?.Image is Image image) + { + return new NativeRect(0, 0, image.Width, image.Height); + } + + return NativeRect.Empty; + } + } + + /// + /// FreehandContainer are regarded equal if they are of the same type and their paths are equal. + /// + /// object + /// bool + public override bool Equals(object obj) + { + bool ret = false; + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + + if (obj is FreehandContainer other && Equals(freehandPath, other.freehandPath)) + { + ret = true; + } + + return ret; + } + + public override int GetHashCode() + { + return freehandPath?.GetHashCode() ?? 0; + } + + public override bool ClickableAt(int x, int y) + { + bool returnValue = base.ClickableAt(x, y); + if (returnValue) + { + int lineThickness = GetFieldValueAsInt(FieldType.LINE_THICKNESS); + using var pen = new Pen(Color.White) + { + Width = lineThickness + 10 + }; + returnValue = freehandPath.IsOutlineVisible(x - Left, y - Top, pen); + } + + return returnValue; + } + } } \ No newline at end of file diff --git a/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs b/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs index 22dd13379..e1f37544b 100644 --- a/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs +++ b/src/Greenshot.Editor/Drawing/SpeechbubbleContainer.cs @@ -39,10 +39,10 @@ namespace Greenshot.Editor.Drawing [Serializable] public class SpeechbubbleContainer : TextContainer { - private NativePoint _initialGripperPoint; + private Point _initialGripperPoint; // Only used for serializing the TargetGripper location - private NativePoint _storedTargetGripperLocation; + private Point _storedTargetGripperLocation; /// /// Store the current location of the target gripper @@ -120,7 +120,8 @@ namespace Greenshot.Editor.Drawing int xOffset = leftAligned ? -20 : 20; int yOffset = topAligned ? -20 : 20; - NativePoint newGripperLocation = _initialGripperPoint.Offset(xOffset, yOffset); + NativePoint initialGripperPoint = _initialGripperPoint; + NativePoint newGripperLocation = initialGripperPoint.Offset(xOffset, yOffset); if (TargetAdorner.Location != newGripperLocation) { diff --git a/src/Greenshot.Editor/Drawing/Surface.cs b/src/Greenshot.Editor/Drawing/Surface.cs index f050374a6..6d47a67a6 100644 --- a/src/Greenshot.Editor/Drawing/Surface.cs +++ b/src/Greenshot.Editor/Drawing/Surface.cs @@ -28,6 +28,7 @@ using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Runtime.Serialization.Formatters.Binary; +using System.ServiceModel.Security; using System.Windows.Forms; using Dapplo.Windows.Common.Extensions; using Dapplo.Windows.Common.Structs; @@ -40,6 +41,7 @@ using Greenshot.Base.Interfaces.Drawing; using Greenshot.Base.Interfaces.Drawing.Adorners; using Greenshot.Editor.Configuration; using Greenshot.Editor.Drawing.Fields; +using Greenshot.Editor.Helpers; using Greenshot.Editor.Memento; using log4net; @@ -722,6 +724,7 @@ namespace Greenshot.Editor.Drawing try { BinaryFormatter binaryRead = new BinaryFormatter(); + binaryRead.Binder = new BinaryFormatterHelper(); IDrawableContainerList loadedElements = (IDrawableContainerList) binaryRead.Deserialize(streamRead); loadedElements.Parent = this; // Make sure the steplabels are sorted according to their number @@ -731,6 +734,10 @@ namespace Greenshot.Editor.Drawing SelectElements(loadedElements); FieldAggregator.BindElements(loadedElements); } + catch (SecurityAccessDeniedException) + { + throw; + } catch (Exception e) { LOG.Error("Error serializing elements from stream.", e); diff --git a/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs b/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs new file mode 100644 index 000000000..7f677367e --- /dev/null +++ b/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs @@ -0,0 +1,111 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.ServiceModel.Security; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Editor.Drawing; +using Greenshot.Editor.Drawing.Fields; +using Greenshot.Editor.Drawing.Filters; +using log4net; +using static Greenshot.Editor.Drawing.FilterContainer; + +namespace Greenshot.Editor.Helpers +{ + internal class BinaryFormatterHelper : SerializationBinder + { + private static readonly ILog LOG = LogManager.GetLogger(typeof(BinaryFormatterHelper)); + private static readonly IDictionary TypeMapper = new Dictionary + { + {"System.Guid",typeof(Guid) }, + {"System.Drawing.Rectangle",typeof(System.Drawing.Rectangle) }, + {"System.Drawing.Point",typeof(System.Drawing.Point) }, + {"System.Drawing.Color",typeof(System.Drawing.Color) }, + {"System.Drawing.Bitmap",typeof(System.Drawing.Bitmap) }, + {"System.Drawing.StringAlignment",typeof(System.Drawing.StringAlignment) }, + {"System.Collections.Generic.List`1[[Greenshot.Base.Interfaces.Drawing.IFieldHolder", typeof(List)}, + {"System.Collections.Generic.List`1[[Greenshot.Base.Interfaces.Drawing.IField", typeof(List)}, + {"System.Collections.Generic.List`1[[System.Drawing.Point", typeof(List)}, + {"Greenshot.Editor.Drawing.ArrowContainer", typeof(ArrowContainer) }, + {"Greenshot.Editor.Drawing.LineContainer", typeof(LineContainer) }, + {"Greenshot.Editor.Drawing.TextContainer", typeof(TextContainer) }, + {"Greenshot.Editor.Drawing.SpeechbubbleContainer", typeof(SpeechbubbleContainer) }, + {"Greenshot.Editor.Drawing.RectangleContainer", typeof(RectangleContainer) }, + {"Greenshot.Editor.Drawing.EllipseContainer", typeof(EllipseContainer) }, + {"Greenshot.Editor.Drawing.FreehandContainer", typeof(FreehandContainer) }, + {"Greenshot.Editor.Drawing.HighlightContainer", typeof(HighlightContainer) }, + {"Greenshot.Editor.Drawing.IconContainer", typeof(IconContainer) }, + {"Greenshot.Editor.Drawing.ObfuscateContainer", typeof(ObfuscateContainer) }, + {"Greenshot.Editor.Drawing.StepLabelContainer", typeof(StepLabelContainer) }, + {"Greenshot.Editor.Drawing.SvgContainer", typeof(SvgContainer) }, + {"Greenshot.Editor.Drawing.VectorGraphicsContainer", typeof(VectorGraphicsContainer) }, + {"Greenshot.Editor.Drawing.MetafileContainer", typeof(MetafileContainer) }, + {"Greenshot.Editor.Drawing.ImageContainer", typeof(ImageContainer) }, + {"Greenshot.Editor.Drawing.FilterContainer", typeof(FilterContainer) }, + {"Greenshot.Editor.Drawing.DrawableContainer", typeof(DrawableContainer) }, + {"Greenshot.Editor.Drawing.DrawableContainerList", typeof(DrawableContainerList) }, + {"Greenshot.Editor.Drawing.CursorContainer", typeof(CursorContainer) }, + {"Greenshot.Editor.Drawing.Filters.HighlightFilter", typeof(HighlightFilter) }, + {"Greenshot.Editor.Drawing.Filters.GrayscaleFilter", typeof(GrayscaleFilter) }, + {"Greenshot.Editor.Drawing.Filters.MagnifierFilter", typeof(MagnifierFilter) }, + {"Greenshot.Editor.Drawing.Filters.BrightnessFilter", typeof(BrightnessFilter) }, + {"Greenshot.Editor.Drawing.Filters.BlurFilter", typeof(BlurFilter) }, + {"Greenshot.Editor.Drawing.Filters.PixelizationFilter", typeof(PixelizationFilter) }, + {"Greenshot.Base.Interfaces.Drawing.IDrawableContainer", typeof(IDrawableContainer) }, + {"Greenshot.Base.Interfaces.Drawing.EditStatus", typeof(EditStatus) }, + {"Greenshot.Base.Interfaces.Drawing.IFieldHolder", typeof(IFieldHolder) }, + {"Greenshot.Base.Interfaces.Drawing.IField", typeof(IField) }, + {"Greenshot.Base.Interfaces.Drawing.FieldFlag", typeof(FieldFlag) }, + {"Greenshot.Editor.Drawing.Fields.Field", typeof(Field) }, + {"Greenshot.Editor.Drawing.Fields.FieldType", typeof(FieldType) }, + {"Greenshot.Editor.Drawing.FilterContainer+PreparedFilter", typeof(PreparedFilter) }, + }; + // Greenshot.Plugin.Drawing.EditStatus -> Greenshot.Base.Interfaces.Drawing.EditStatus + // GreenshotPlugin.Interfaces.Drawing.IFieldHolder -> Greenshot.Base.Interfaces.Drawing.IFieldHolder + // Greenshot.Drawing.FilterContainer+PreparedFilter -> Greenshot.Editor.Drawing + public override Type BindToType(string assemblyName, string typeName) + { + if (string.IsNullOrEmpty(typeName)) + { + return null; + } + var typeNameCommaLocation = typeName.IndexOf(","); + var comparingTypeName = typeName.Substring(0, typeNameCommaLocation > 0 ? typeNameCommaLocation : typeName.Length); + + // Correct wrong types + comparingTypeName = comparingTypeName.Replace("Greenshot.Drawing", "Greenshot.Editor.Drawing"); + comparingTypeName = comparingTypeName.Replace("Greenshot.Plugin.Drawing", "Greenshot.Base.Interfaces.Drawing"); + comparingTypeName = comparingTypeName.Replace("GreenshotPlugin.Interfaces.Drawing", "Greenshot.Base.Interfaces.Drawing"); + comparingTypeName = comparingTypeName.Replace("Greenshot.Drawing.Fields", "Greenshot.Editor.Drawing.Fields"); + comparingTypeName = comparingTypeName.Replace("Greenshot.Drawing.Filters", "Greenshot.Editor.Drawing.Filters"); + + if (TypeMapper.TryGetValue(comparingTypeName, out var returnType)) + { + LOG.Info($"Mapped {assemblyName} - {typeName} to {returnType.FullName}"); + return returnType; + } + LOG.Warn($"Unexpected Greenshot type in .greenshot file detected, maybe vulnerability attack created with ysoserial? Suspicious type: {assemblyName} - {typeName}"); + throw new SecurityAccessDeniedException($"Suspicious type in .greenshot file: {assemblyName} - {typeName}"); + } + } +} From 099e6569633d8bc678f96d066d0cdcc744698638 Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 27 Mar 2023 22:27:02 +0200 Subject: [PATCH 208/232] Brought back IconContainer support to the .greenshot format, Svg is still causing issue. --- .../Helpers/BinaryFormatterHelper.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs b/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs index 7f677367e..8e21bee76 100644 --- a/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs +++ b/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs @@ -32,6 +32,10 @@ using static Greenshot.Editor.Drawing.FilterContainer; namespace Greenshot.Editor.Helpers { + /// + /// This helps to map the serialization of the old .greenshot file to the newer. + /// It also prevents misuse. + /// internal class BinaryFormatterHelper : SerializationBinder { private static readonly ILog LOG = LogManager.GetLogger(typeof(BinaryFormatterHelper)); @@ -42,6 +46,8 @@ namespace Greenshot.Editor.Helpers {"System.Drawing.Point",typeof(System.Drawing.Point) }, {"System.Drawing.Color",typeof(System.Drawing.Color) }, {"System.Drawing.Bitmap",typeof(System.Drawing.Bitmap) }, + {"System.Drawing.Icon",typeof(System.Drawing.Icon) }, + {"System.Drawing.Size",typeof(System.Drawing.Size) }, {"System.Drawing.StringAlignment",typeof(System.Drawing.StringAlignment) }, {"System.Collections.Generic.List`1[[Greenshot.Base.Interfaces.Drawing.IFieldHolder", typeof(List)}, {"System.Collections.Generic.List`1[[Greenshot.Base.Interfaces.Drawing.IField", typeof(List)}, @@ -80,9 +86,14 @@ namespace Greenshot.Editor.Helpers {"Greenshot.Editor.Drawing.Fields.FieldType", typeof(FieldType) }, {"Greenshot.Editor.Drawing.FilterContainer+PreparedFilter", typeof(PreparedFilter) }, }; - // Greenshot.Plugin.Drawing.EditStatus -> Greenshot.Base.Interfaces.Drawing.EditStatus - // GreenshotPlugin.Interfaces.Drawing.IFieldHolder -> Greenshot.Base.Interfaces.Drawing.IFieldHolder - // Greenshot.Drawing.FilterContainer+PreparedFilter -> Greenshot.Editor.Drawing + + /// + /// Do the type mapping + /// + /// Assembly for the type that was serialized + /// Type that was serialized + /// Type which was mapped + /// If something smells fishy public override Type BindToType(string assemblyName, string typeName) { if (string.IsNullOrEmpty(typeName)) From f862e794858631c2e2ebdb2678617071208cfd8b Mon Sep 17 00:00:00 2001 From: Robin Krom Date: Mon, 27 Mar 2023 22:43:03 +0200 Subject: [PATCH 209/232] Fixed SvgContainer support for the .greenshot file --- src/Greenshot.Editor/Drawing/SvgContainer.cs | 29 ++- .../Drawing/VectorGraphicsContainer.cs | 3 +- .../SvgFileFormatHandler.cs | 178 +++++++++--------- .../Helpers/BinaryFormatterHelper.cs | 1 + 4 files changed, 116 insertions(+), 95 deletions(-) diff --git a/src/Greenshot.Editor/Drawing/SvgContainer.cs b/src/Greenshot.Editor/Drawing/SvgContainer.cs index 283f755e8..85b8cb43d 100644 --- a/src/Greenshot.Editor/Drawing/SvgContainer.cs +++ b/src/Greenshot.Editor/Drawing/SvgContainer.cs @@ -21,6 +21,7 @@ using System; using System.Drawing; +using System.IO; using Dapplo.Windows.Common.Structs; using Greenshot.Base.Core; using Greenshot.Base.Interfaces; @@ -34,14 +35,32 @@ namespace Greenshot.Editor.Drawing [Serializable] public class SvgContainer : VectorGraphicsContainer { - private readonly SvgDocument _svgDocument; + private MemoryStream _svgContent; - public SvgContainer(SvgDocument svgDocument, ISurface parent) : base(parent) + [NonSerialized] + private SvgDocument _svgDocument; + + public SvgContainer(Stream stream, ISurface parent) : base(parent) { - _svgDocument = svgDocument; - Size = new Size((int)svgDocument.Width, (int)svgDocument.Height); + _svgContent = new MemoryStream(); + stream.CopyTo(_svgContent); + Init(); + Size = new Size((int)_svgDocument.Width, (int)_svgDocument.Height); } - + + protected override void Init() + { + base.Init(); + // Do nothing when there is no content + if (_svgContent == null) + { + return; + } + _svgContent.Position = 0; + + _svgDocument = SvgDocument.Open(_svgContent); + } + protected override Image ComputeBitmap() { //var image = ImageHelper.CreateEmpty(Width, Height, PixelFormat.Format32bppArgb, Color.Transparent); diff --git a/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs b/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs index 45238caaf..43da94c7d 100644 --- a/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs +++ b/src/Greenshot.Editor/Drawing/VectorGraphicsContainer.cs @@ -47,7 +47,8 @@ namespace Greenshot.Editor.Drawing /// This is the cached version of the bitmap, pre-rendered to save performance /// Do not serialized, it can be rebuild with other information. /// - [NonSerialized] private Image _cachedImage; + [NonSerialized] + private Image _cachedImage; /// /// Constructor takes care of calling Init diff --git a/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs b/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs index 14a33246e..76c5e85b9 100644 --- a/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs +++ b/src/Greenshot.Editor/FileFormatHandlers/SvgFileFormatHandler.cs @@ -1,89 +1,89 @@ -/* - * Greenshot - a free and open source screenshot tool - * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom - * - * For more information see: https://getgreenshot.org/ - * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.IO; -using Greenshot.Base.Interfaces; -using Greenshot.Base.Interfaces.Drawing; -using Greenshot.Base.Interfaces.Plugin; -using Greenshot.Editor.Drawing; -using log4net; -using Svg; - -namespace Greenshot.Editor.FileFormatHandlers -{ - /// - /// This handled the loading of SVG images to the editor - /// - public class SvgFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler - { - private static readonly ILog Log = LogManager.GetLogger(typeof(SvgFileFormatHandler)); - private readonly IReadOnlyCollection _ourExtensions = new[] { ".svg" }; - - public SvgFileFormatHandler() - { - SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions; - SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions; - } - - public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) - { - var svgDocument = SvgDocument.Open(stream); - - try - { - bitmap = svgDocument.Draw(); - return true; - } - catch (Exception ex) - { - Log.Error("Can't load SVG", ex); - } - bitmap = null; - return false; - } - - public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null) - { - // TODO: Implement this - return false; - } - - public override IEnumerable LoadDrawablesFromStream(Stream stream, string extension, ISurface parent = null) - { - SvgDocument svgDocument = null; - try - { - svgDocument = SvgDocument.Open(stream); - } - catch (Exception ex) - { - Log.Error("Can't load SVG", ex); - } - if (svgDocument != null) - { - yield return new SvgContainer(svgDocument, parent); - } - } - } -} +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using Greenshot.Base.Interfaces; +using Greenshot.Base.Interfaces.Drawing; +using Greenshot.Base.Interfaces.Plugin; +using Greenshot.Editor.Drawing; +using log4net; +using Svg; + +namespace Greenshot.Editor.FileFormatHandlers +{ + /// + /// This handled the loading of SVG images to the editor + /// + public class SvgFileFormatHandler : AbstractFileFormatHandler, IFileFormatHandler + { + private static readonly ILog Log = LogManager.GetLogger(typeof(SvgFileFormatHandler)); + private readonly IReadOnlyCollection _ourExtensions = new[] { ".svg" }; + + public SvgFileFormatHandler() + { + SupportedExtensions[FileFormatHandlerActions.LoadDrawableFromStream] = _ourExtensions; + SupportedExtensions[FileFormatHandlerActions.LoadFromStream] = _ourExtensions; + } + + public override bool TryLoadFromStream(Stream stream, string extension, out Bitmap bitmap) + { + var svgDocument = SvgDocument.Open(stream); + + try + { + bitmap = svgDocument.Draw(); + return true; + } + catch (Exception ex) + { + Log.Error("Can't load SVG", ex); + } + bitmap = null; + return false; + } + + public override bool TrySaveToStream(Bitmap bitmap, Stream destination, string extension, ISurface surface = null, SurfaceOutputSettings surfaceOutputSettings = null) + { + // TODO: Implement this + return false; + } + + public override IEnumerable LoadDrawablesFromStream(Stream stream, string extension, ISurface parent = null) + { + SvgContainer svgContainer = null; + try + { + svgContainer = new SvgContainer(stream, parent); + } + catch (Exception ex) + { + Log.Error("Can't load SVG", ex); + } + if (svgContainer != null) + { + yield return svgContainer; + } + } + } +} diff --git a/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs b/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs index 8e21bee76..279e8b1a5 100644 --- a/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs +++ b/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs @@ -48,6 +48,7 @@ namespace Greenshot.Editor.Helpers {"System.Drawing.Bitmap",typeof(System.Drawing.Bitmap) }, {"System.Drawing.Icon",typeof(System.Drawing.Icon) }, {"System.Drawing.Size",typeof(System.Drawing.Size) }, + {"System.IO.MemoryStream",typeof(System.IO.MemoryStream) }, {"System.Drawing.StringAlignment",typeof(System.Drawing.StringAlignment) }, {"System.Collections.Generic.List`1[[Greenshot.Base.Interfaces.Drawing.IFieldHolder", typeof(List)}, {"System.Collections.Generic.List`1[[Greenshot.Base.Interfaces.Drawing.IField", typeof(List)}, From a3e65fee6f21b321daeb0eba9b6871396b60e1d6 Mon Sep 17 00:00:00 2001 From: Jens Glathe Date: Sun, 16 Apr 2023 19:25:14 +0200 Subject: [PATCH 210/232] add install option to disable the default win11 prtscr tool (#484) Signed-off-by: Jens Glathe --- installer/innosetup/setup.iss | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index bf49ea5ed..59363446f 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -181,6 +181,8 @@ Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: " Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser Root: HKCU; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE,0"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser Root: HKCU; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser +; Disable the default PRTSCR Snipping Tool in Windows 11 +Root: HKCU; Subkey: Control Panel\Keyboard; ValueType: dword; ValueName: "PrintScreenKeyForSnippingEnabled"; ValueData: "0"; Flags: uninsdeletevalue; Check: ShouldDisableSnippingTool ; HKEY_LOCAL_MACHINE - for all users when admin Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser @@ -269,6 +271,7 @@ en.win10=Windows 10 plug-in en.UninstallIconDescription=Uninstall en.ShowLicense=Show license en.ShowReadme=Show Readme +en.disablewin11snippingtool=Disable Win11 default PrtScr snipping tool de.confluence=Confluence Plug-in de.default=Standard installation @@ -281,6 +284,7 @@ de.optimize=Optimierung der Leistung, kann etwas dauern. de.startgreenshot={#ExeName} starten de.startup={#ExeName} starten wenn Windows hochfährt de.win10=Windows 10 Plug-in +de.disablewin11snippingtool=Deaktiviere das Standard Windows 11 Snipping Tool auf "Druck" es.confluence=Extensión para Confluence es.default=${default} @@ -482,6 +486,7 @@ Name: "compact"; Description: "{code:CompactInstall}" Name: "custom"; Description: "{code:CustomInstall}"; Flags: iscustom [Components] +Name: "disablesnippingtool"; Description: {cm:disablewin11snippingtool}; Flags: disablenouninstallwarning; Types: default full custom; Check: IsWindows11OrNewer() Name: "greenshot"; Description: "Greenshot"; Types: default full compact custom; Flags: fixed ;Name: "plugins\networkimport"; Description: "Network Import Plugin"; Types: full Name: "plugins\box"; Description: {cm:box}; Types: full custom; Flags: disablenouninstallwarning @@ -531,6 +536,7 @@ Name: "languages\ukUA"; Description: {cm:ukUA}; Types: full custom; Flags: disab Name: "languages\viVN"; Description: {cm:viVN}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('e') Name: "languages\zhCN"; Description: {cm:zhCN}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('a') Name: "languages\zhTW"; Description: {cm:zhTW}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('9') + [Code] // Do we have a regular user trying to install this? function IsRegularUser(): Boolean; @@ -745,6 +751,19 @@ begin Result := IsWindowsVersionOrNewer(10, 0); end; +function IsWindows11OrNewer: Boolean; +var + WindowsVersion: TWindowsVersion; +begin + GetWindowsVersionEx(WindowsVersion); + Result := (WindowsVersion.Major >= 10) and (WindowsVersion.Build >= 22000); +end; + +function ShouldDisableSnippingTool: Boolean; +begin + Result := IsComponentSelected('disablesnippingtool'); +end; + [Run] Filename: "{app}\{#ExeName}.exe"; Description: "{cm:startgreenshot}"; Parameters: "{code:GetParamsForGS}"; WorkingDir: "{app}"; Flags: nowait postinstall runasoriginaluser Filename: "https://getgreenshot.org/thank-you/?language={language}&version={#Version}"; Flags: shellexec runasoriginaluser From bb7a3743905f80ec8459771aa49cb24c55e60cc7 Mon Sep 17 00:00:00 2001 From: jklingen Date: Tue, 3 Oct 2023 16:11:09 +0200 Subject: [PATCH 211/232] Create SECURITY.md --- SECURITY.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..324758e42 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +If you think you found a security issue in Greenshot, please report it responsibly [in our security section](https://github.com/greenshot/greenshot/security). We try to look into it as soon as possible - please give us some time for reaction, though. From 245f6f261bb49a7ba6f51cd6de488af411a1bd6f Mon Sep 17 00:00:00 2001 From: jklingen Date: Sun, 18 Aug 2024 11:22:45 +0200 Subject: [PATCH 212/232] Enhance Readme with Link to Releases (#549) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 1f47983e3..90fff9b6f 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,9 @@ Being easy to understand and configurable, Greenshot is an efficient tool for pr About this repository --------------------- This repository is for Greenshot 1.3, currently in development, but is the next planned release + +Releases +-------- + +You can find a list of all releases (stable and unstable) in the [Github releases](https://github.com/greenshot/greenshot/releases) or in the [version history on our website](https://getgreenshot.org/version-history/). +The [downloads page on our website](https://getgreenshot.org/downloads/) always links to the latest stable release. From cac566c70a57c7ed4dd4b7263832f9f072c7359b Mon Sep 17 00:00:00 2001 From: jklingen Date: Fri, 16 May 2025 15:17:26 +0200 Subject: [PATCH 213/232] Add Release Script (#581) --- .github/workflows/release.yml | 126 +++++++++++++++ .github/workflows/update-gh-pages.yml | 18 +++ .gitignore | 4 +- azure-pipelines.yml | 106 ------------- build-and-deploy.ps1 | 149 ++++++++++++++++++ installer/innosetup/setup.iss | 3 +- nuget.config | 6 + src/Directory.Build.targets | 64 +++++++- .../Drawing/StepLabelContainer.cs | 2 +- .../Greenshot.Plugin.Box.Credentials.template | 2 +- src/Greenshot.Plugin.Office/OfficeUtils.cs | 60 +++---- src/Greenshot.sln | 5 +- src/Greenshot/Greenshot.csproj | 2 + 13 files changed, 400 insertions(+), 147 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/update-gh-pages.yml delete mode 100644 azure-pipelines.yml create mode 100644 build-and-deploy.ps1 create mode 100644 nuget.config diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..345c0cae9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,126 @@ +name: Build and Deploy + +on: + push: + branches: + - 'release/1.*' + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v2 + + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '7.x' + + - name: Restore NuGet packages + run: msbuild src/Greenshot.sln /p:Configuration=Release /restore /t:PrepareForBuild + env: + Box13_ClientId: ${{ secrets.Box13_ClientId }} + Box13_ClientSecret: ${{ secrets.Box13_ClientSecret }} + DropBox13_ClientId: ${{ secrets.DropBox13_ClientId }} + DropBox13_ClientSecret: ${{ secrets.DropBox13_ClientSecret }} + Flickr_ClientId: ${{ secrets.Flickr_ClientId }} + Flickr_ClientSecret: ${{ secrets.Flickr_ClientSecret }} + Imgur13_ClientId: ${{ secrets.Imgur13_ClientId }} + Imgur13_ClientSecret: ${{ secrets.Imgur13_ClientSecret }} + Photobucket_ClientId: ${{ secrets.Photobucket_ClientId }} + Photobucket_ClientSecret: ${{ secrets.Photobucket_ClientSecret }} + Picasa_ClientId: ${{ secrets.Picasa_ClientId }} + Picasa_ClientSecret: ${{ secrets.Picasa_ClientSecret }} + + - name: Build and package + run: msbuild src/Greenshot.sln /p:Configuration=Release /t:Rebuild /v:normal + env: + Box13_ClientId: ${{ secrets.Box13_ClientId }} + Box13_ClientSecret: ${{ secrets.Box13_ClientSecret }} + DropBox13_ClientId: ${{ secrets.DropBox13_ClientId }} + DropBox13_ClientSecret: ${{ secrets.DropBox13_ClientSecret }} + Flickr_ClientId: ${{ secrets.Flickr_ClientId }} + Flickr_ClientSecret: ${{ secrets.Flickr_ClientSecret }} + Imgur13_ClientId: ${{ secrets.Imgur13_ClientId }} + Imgur13_ClientSecret: ${{ secrets.Imgur13_ClientSecret }} + Photobucket_ClientId: ${{ secrets.Photobucket_ClientId }} + Photobucket_ClientSecret: ${{ secrets.Photobucket_ClientSecret }} + Picasa_ClientId: ${{ secrets.Picasa_ClientId }} + Picasa_ClientSecret: ${{ secrets.Picasa_ClientSecret }} + + - name: Copy Files + run: | + mkdir -p ${{ github.workspace }}/artifacts + cp installer/Greenshot-INSTALLER-*.exe ${{ github.workspace }}/artifacts/ + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: drop + path: ${{ github.workspace }}/artifacts + +# deploy: +# runs-on: windows-latest +# needs: build +# +# steps: +# +# - name: Checkout repository +# uses: actions/checkout@v2 +# with: +# fetch-depth: 0 +# +# - name: Download build artifacts +# uses: actions/download-artifact@v4 +# with: +# name: drop Name of the artifact uploaded in previous steps +# path: drop Local folder where artifacts are downloaded +# +# - name: Extract version from file name +# id: extract_version +# run: | +# $file = Get-ChildItem drop -Filter "Greenshot-INSTALLER-*.exe" | Select-Object -First 1 +# if (-not $file) { +# throw "No matching file found in 'drop' directory." +# } +# if ($file.Name -match "Greenshot-INSTALLER-([\d\.]+).*\.exe") { +# echo "version=$($matches[1])" >> $Env:GITHUB_OUTPUT +# } else { +# throw "Version number could not be extracted from file name: $($file.Name)" +# } +# shell: pwsh +# +# - name: Create tag +# run: | +# git config user.name "github-actions[bot]" +# git config user.email "github-actions[bot]@users.noreply.github.com" +# git tag -a "v${{ steps.extract_version.outputs.version }}" -m "v${{ steps.extract_version.outputs.version }}" +# git push origin "v${{ steps.extract_version.outputs.version }}" +# +# - name: Create GitHub Release +# uses: softprops/action-gh-release@v2 +# with: +# name: "Greenshot ${{ steps.extract_version.outputs.version }} unstable" +# tag_name: "v${{ steps.extract_version.outputs.version }}" +# files: drop/*.exe +# generate_release_notes: true +# draft: true +# prerelease: true +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# +# - name: Trigger GitHub Pages rebuild +# shell: bash +# run: | +# curl -X POST \ +# -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ +# -H "Accept: application/vnd.github+json" \ +# https://api.github.com/repos/${{ github.repository }}/pages/builds + diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml new file mode 100644 index 000000000..6c9666223 --- /dev/null +++ b/.github/workflows/update-gh-pages.yml @@ -0,0 +1,18 @@ +name: Update GitHub Pages + +on: + workflow_dispatch: + release: + types: [published] + +jobs: + update-gh-pages: + runs-on: ubuntu-latest + steps: + - name: Trigger GitHub Pages rebuild + shell: bash + run: | + curl -X POST \ + -H "Authorization: Bearer ${{ secrets.GH_PAT_JKL }}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/pages/builds diff --git a/.gitignore b/.gitignore index 3afd2d7ab..7e96d5501 100644 --- a/.gitignore +++ b/.gitignore @@ -214,4 +214,6 @@ ModelManifest.xml *.credentials.cs # Rider files -.idea \ No newline at end of file +.idea + +/installer/Greenshot-INSTALLER-*.exe diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 558d40760..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,106 +0,0 @@ -# .NET Desktop -# Build and run tests for .NET Desktop or Windows classic desktop solutions. -# Add steps that publish symbols, save build artifacts, and more: -# https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net - -trigger: - batch: true - branches: - include: - - 'release/1.*' - exclude: - - 'develop' - -stages: -- stage: Build - jobs: - - job: Build - variables: - - group: 'Plug-in Credentials' - - name: solution - value: 'src/Greenshot.sln' - - name: buildPlatform - value: 'Any CPU' - - name: buildConfiguration - value: 'Release' - - pool: - vmImage: 'Windows-latest' - - steps: - - task: MSBuild@1 - displayName: Restore nuget packages and generate credential templates - inputs: - solution: '$(solution)' - platform: $(buildPlatform) - configuration: $(buildConfiguration) - msbuildArguments: '/restore /t:PrepareForBuild' - - - task: MSBuild@1 - displayName: Build and package - inputs: - solution: '$(solution)' - platform: $(buildPlatform) - configuration: $(buildConfiguration) - env: - Box13_ClientId: $(Box13_ClientId) - Box13_ClientSecret: $(Box13_ClientSecret) - DropBox13_ClientId: $(DropBox13_ClientId) - DropBox13_ClientSecret: $(DropBox13_ClientSecret) - Flickr_ClientId: $(Flickr_ClientId) - Flickr_ClientSecret: $(Flickr_ClientSecret) - Imgur13_ClientId: $(Imgur13_ClientId) - Imgur13_ClientSecret: $(Imgur13_ClientSecret) - Photobucket_ClientId: $(Photobucket_ClientId) - Photobucket_ClientSecret: $(Photobucket_ClientSecret) - Picasa_ClientId: $(Picasa_ClientId) - Picasa_ClientSecret: $(Picasa_ClientSecret) - - - task: CopyFiles@2 - displayName: 'Copy Files to: $(build.artifactstagingdirectory)' - inputs: - SourceFolder: '$(Build.SourcesDirectory)\installer' - Contents: Greenshot-INSTALLER-*.exe - TargetFolder: '$(build.artifactstagingdirectory)' - flattenFolders: true - - - task: PublishBuildArtifacts@1 - displayName: 'Publish Artifact: drop' - inputs: - PathtoPublish: '$(build.artifactstagingdirectory)' - -- stage: Deploy - jobs: - - deployment: GitHub_Release - pool: - vmImage: 'Windows-latest' - - environment: 'GitHub Release' - strategy: - # default deployment strategy - runOnce: - deploy: - steps: - - download: current - artifact: drop - - # Create a GitHub release - - task: GitHubRelease@0 - inputs: - gitHubConnection: GitHub Release - repositoryName: '$(Build.Repository.Name)' - action: 'create' # Options: create, edit, delete - target: '$(Build.SourceVersion)' # Required when action == Create || Action == Edit - tagSource: 'manual' # Required when action == Create# Options: auto, manual - tag: 'v$(Build.BuildNumber)' # Required when action == Edit || Action == Delete || TagSource == Manual - title: Greenshot $(Build.BuildNumber) unstable # Optional - #releaseNotesSource: 'file' # Optional. Options: file, input - #releaseNotesFile: # Optional - #releaseNotes: # Optional - assets: '$(Pipeline.Workspace)/drop/*.exe' - #assetUploadMode: 'delete' # Optional. Options: delete, replace - isDraft: true # Optional - isPreRelease: true # Optional - addChangeLog: true # Optional - #compareWith: 'lastFullRelease' # Required when addChangeLog == True. Options: lastFullRelease, lastRelease, lastReleaseByTag - #releaseTag: # Required when compareWith == LastReleaseByTag diff --git a/build-and-deploy.ps1 b/build-and-deploy.ps1 new file mode 100644 index 000000000..5e373949b --- /dev/null +++ b/build-and-deploy.ps1 @@ -0,0 +1,149 @@ +# USAGE +# * Enable script execution in Powershell: 'Set-ExecutionPolicy RemoteSigned' +# * Create a GitHub personal access token (PAT) for greenshot repository +# * user must be owner of the repository +# * token needs read and write permissions ""for Contents"" and ""Pages"" +# * Execute the script and paste your token + +# Prompt the user to securely input the Github token +$SecureToken = Read-Host "Please enter your GitHub personal access token" -AsSecureString +$ReleaseToken = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureToken)) + +# Variables +$RepoPath = "." # Replace with your local repo path +$ArtifactsPath = "$RepoPath\artifacts" +$SolutionFile = "$RepoPath\src\Greenshot.sln" + +# Step 0: Update Local Repository +git pull + +# Step 1: Restore NuGet Packages +Write-Host "Restoring NuGet packages..." +msbuild "$SolutionFile" /p:Configuration=Release /restore /t:PrepareForBuild +if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to restore NuGet packages." + exit $LASTEXITCODE +} + +# Step 2: Build and Package +Write-Host "Building and packaging the solution..." +msbuild "$SolutionFile" /p:Configuration=Release /t:Rebuild /v:normal +if ($LASTEXITCODE -ne 0) { + Write-Error "Build failed." + exit $LASTEXITCODE +} + +# Step 3: Copy Installer Files +Write-Host "Copying installer files..." +if (-not (Test-Path $ArtifactsPath)) { + New-Item -ItemType Directory -Force -Path $ArtifactsPath +} +Copy-Item "$RepoPath\installer\Greenshot-INSTALLER-*.exe" -Destination $ArtifactsPath -Force +if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to copy installer files." + exit $LASTEXITCODE +} + +# Step 4: Extract Version from File Name +Write-Host "Extracting version from installer file name..." +$InstallerFile = Get-ChildItem $ArtifactsPath -Filter "Greenshot-INSTALLER-*.exe" | Select-Object -Last 1 +if (-not $InstallerFile) { + Write-Error "No matching installer file found in '$ArtifactsPath'." + exit 1 +} + +if ($InstallerFile.Name -match "Greenshot-INSTALLER-([\d\.]+).*\.exe") { + $Version = $matches[1] + Write-Host "Extracted version: $Version" +} else { + Write-Error "Version number could not be extracted from file name: $($InstallerFile.Name)" + exit 1 +} + +# Step 5: Create Git Tag +Write-Host "Creating Git tag..." +cd $RepoPath +#git config user.name "local-script" +#git config user.email "local-script@example.com" +git tag -a "v$Version" -m "v$Version" +git push origin "v$Version" +if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to create Git tag." + exit $LASTEXITCODE +} + +# Step 6: Create GitHub Release +Write-Host "Creating GitHub release..." +$Headers = @{ + Authorization = "Bearer $ReleaseToken" + Accept = "application/vnd.github+json" +} +$ReleaseData = @{ + tag_name = "v$Version" + name = "Greenshot $Version unstable" + body = "Pre-release of Greenshot $Version." + draft = $true + prerelease = $true + generate_release_notes = $true +} +$ReleaseResponse = Invoke-RestMethod ` + -Uri "https://api.github.com/repos/jklingen/greenshot/releases" ` + -Method POST ` + -Headers $Headers ` + -Body (ConvertTo-Json $ReleaseData -Depth 10) + +if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to create GitHub release." + exit $LASTEXITCODE +} + +Write-Host "Release created successfully." + +# Get the release ID from the response +$ReleaseId = $ReleaseResponse.id +Write-Host "Release ID: $ReleaseId" + +# Step 7: Upload .exe File to Release +Write-Host "Uploading .exe file to GitHub release..." +$ExeFilePath = "$ArtifactsPath\$($InstallerFile.Name)" +if (-Not (Test-Path $ExeFilePath)) { + Write-Error "Built .exe file not found: $ExeFilePath" + exit 1 +} + +# GitHub API for uploading release assets +$UploadUrl = $ReleaseResponse.upload_url -replace "{.*}", "" + +# Upload the file +$FileHeaders = @{ + Authorization = "Bearer $ReleaseToken" + ContentType = "application/octet-stream" +} +$FileName = [System.IO.Path]::GetFileName($ExeFilePath) + +Invoke-RestMethod ` + -Uri "$($UploadUrl)?name=$FileName" ` + -Method POST ` + -Headers $FileHeaders ` + -InFile $ExeFilePath ` + -ContentType "application/octet-stream" + +if ($LASTEXITCODE -ne 0) { + Write-Error "Failed to upload .exe file to release." + exit $LASTEXITCODE +} + +Write-Host "File uploaded successfully: $FileName" + +# Step 7: Trigger GitHub Pages Rebuild +#Write-Host "Triggering GitHub Pages rebuild..." +#Invoke-RestMethod ` +# -Uri "https://api.github.com/repos/jklingen/greenshot/pages/builds" ` +# -Method POST ` +# -Headers $Headers +#if ($LASTEXITCODE -ne 0) { +# Write-Error "Failed to trigger GitHub Pages rebuild." +# exit $LASTEXITCODE +#} +# +#Write-Host "GitHub Pages rebuild triggered successfully." \ No newline at end of file diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index 59363446f..fb77b0103 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -140,7 +140,8 @@ SetupIconFile=..\..\src\Greenshot\icons\applicationIcon\icon.ico ; SignTool=SignTool sign /debug /fd sha1 /tr https://time.certum.pl /td sha1 $f ; Append a SHA256 to the previous SHA1 signature (this is what as does) ; SignTool=SignTool sign /debug /as /fd sha256 /tr https://time.certum.pl /td sha256 $f -; SignedUninstaller=yes +SignTool=SignTool sign /sha1 "{#GetEnv('CertumThumbprint')}" /tr http://time.certum.pl /td sha256 /fd sha256 /v $f +;SignedUninstaller=yes UninstallDisplayIcon={app}\{#ExeName}.exe Uninstallable=true VersionInfoCompany={#ExeName} diff --git a/nuget.config b/nuget.config new file mode 100644 index 000000000..554c2f634 --- /dev/null +++ b/nuget.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index f2ce406a1..caa6a3db3 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,13 +1,65 @@ + + + + + + + + + + (); + foreach (var line in InputLines) + { + string text = line.ItemSpec; + foreach (var token in Tokens) + { + string tokenName = token.ItemSpec; + // Skip if tokenName is null or empty + if (string.IsNullOrEmpty(tokenName)) + continue; + + string replacementValue = token.GetMetadata("ReplacementValue"); + if (!string.IsNullOrEmpty(replacementValue)) + { + string placeholder = "$"+ "{"+tokenName+"}"; // Token-Format wie $(Box13_ClientId) + text = text.Replace(placeholder, replacementValue); + } + } + output.Add(new Microsoft.Build.Utilities.TaskItem(text)); + } + OutputLines = output.ToArray(); + ]]> + + + - $(PkgMSBuildTasks)\tools\ + $(NuGetPackageRoot)msbuildtasks/1.5.0.235/tools/ - - + + - - + + + + + + + + + + + + - \ No newline at end of file + + + + + diff --git a/src/Greenshot.Editor/Drawing/StepLabelContainer.cs b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs index e5d93e514..e907d237b 100644 --- a/src/Greenshot.Editor/Drawing/StepLabelContainer.cs +++ b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs @@ -205,7 +205,7 @@ namespace Greenshot.Editor.Drawing EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false); } - float fontSize = Math.Min(Math.Abs(Width), Math.Abs(Height)) / 1.4f; + float fontSize = Math.Min(Math.Abs(Width), Math.Abs(Height)) / 3f; using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name); using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel); TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font); diff --git a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template index df6eaa0bd..da2dbc7ae 100644 --- a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template +++ b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.Credentials.template @@ -1,4 +1,4 @@ -/* +/* * Greenshot - a free and open source screenshot tool * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom * diff --git a/src/Greenshot.Plugin.Office/OfficeUtils.cs b/src/Greenshot.Plugin.Office/OfficeUtils.cs index 52ca8d7cb..305611c5d 100644 --- a/src/Greenshot.Plugin.Office/OfficeUtils.cs +++ b/src/Greenshot.Plugin.Office/OfficeUtils.cs @@ -1,43 +1,45 @@ using System.Linq; using Microsoft.Win32; -namespace Greenshot.Plugin.Office; - -/// -/// A small utility class for helping with office -/// -internal static class OfficeUtils +namespace Greenshot.Plugin.Office { - private static readonly string[] OfficeRootKeys = { @"SOFTWARE\Microsoft\Office", @"SOFTWARE\WOW6432Node\Microsoft\Office" }; /// - /// Get the path to the office exe + /// A small utility class for helping with office /// - /// Name of the office executable - public static string GetOfficeExePath(string exeName) + internal static class OfficeUtils { - string strKeyName = exeName switch - { - "WINWORD.EXE" => "Word", - "EXCEL.EXE" => "Excel", - "POWERPNT.EXE" => "PowerPoint", - "OUTLOOK.EXE" => "Outlook", - "ONENOTE.EXE" => "OneNote", - _ => "" - }; + private static readonly string[] OfficeRootKeys = { @"SOFTWARE\Microsoft\Office", @"SOFTWARE\WOW6432Node\Microsoft\Office" }; - foreach (string strRootKey in OfficeRootKeys) + /// + /// Get the path to the office exe + /// + /// Name of the office executable + public static string GetOfficeExePath(string exeName) { - using RegistryKey rootKey = Registry.LocalMachine.OpenSubKey(strRootKey); - if (rootKey is null) continue; - - foreach (string officeVersion in rootKey.GetSubKeyNames().Where(r => r.Contains(".")).Reverse()) + string strKeyName = exeName switch { - using RegistryKey installRootKey = Registry.LocalMachine.OpenSubKey($@"{strRootKey}\{officeVersion}\{strKeyName}\InstallRoot"); - if (installRootKey == null) continue; - return $@"{installRootKey.GetValue("Path")}\{exeName}"; + "WINWORD.EXE" => "Word", + "EXCEL.EXE" => "Excel", + "POWERPNT.EXE" => "PowerPoint", + "OUTLOOK.EXE" => "Outlook", + "ONENOTE.EXE" => "OneNote", + _ => "" + }; + + foreach (string strRootKey in OfficeRootKeys) + { + using RegistryKey rootKey = Registry.LocalMachine.OpenSubKey(strRootKey); + if (rootKey is null) continue; + + foreach (string officeVersion in rootKey.GetSubKeyNames().Where(r => r.Contains(".")).Reverse()) + { + using RegistryKey installRootKey = Registry.LocalMachine.OpenSubKey($@"{strRootKey}\{officeVersion}\{strKeyName}\InstallRoot"); + if (installRootKey == null) continue; + return $@"{installRootKey.GetValue("Path")}\{exeName}"; + } } + return null; } - return null; } -} +} \ No newline at end of file diff --git a/src/Greenshot.sln b/src/Greenshot.sln index 91ddf4314..b71e79bd3 100644 --- a/src/Greenshot.sln +++ b/src/Greenshot.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29728.190 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34009.444 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot", "Greenshot\Greenshot.csproj", "{CD642BF4-D815-4D67-A0B5-C69F0B8231AF}" ProjectSection(ProjectDependencies) = postProject @@ -48,6 +48,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\azure-pipelines.yml = ..\azure-pipelines.yml Directory.Build.props = Directory.Build.props Directory.Build.targets = Directory.Build.targets + ..\.github\workflows\release.yml = ..\.github\workflows\release.yml EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greenshot.Editor", "Greenshot.Editor\Greenshot.Editor.csproj", "{148D3C8B-D6EC-4A7D-80E9-243A81F19DD2}" diff --git a/src/Greenshot/Greenshot.csproj b/src/Greenshot/Greenshot.csproj index fc4dd90d1..334bfc0f0 100644 --- a/src/Greenshot/Greenshot.csproj +++ b/src/Greenshot/Greenshot.csproj @@ -17,6 +17,7 @@ + @@ -75,6 +76,7 @@ + From 262307e61e1575b749af094996b7d26781b7a8b0 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 16 May 2025 15:34:51 +0200 Subject: [PATCH 214/232] fixed branch changes --- .github/workflows/update-gh-pages.yml | 2 +- build-and-deploy.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index 6c9666223..a7e2b42cb 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -13,6 +13,6 @@ jobs: shell: bash run: | curl -X POST \ - -H "Authorization: Bearer ${{ secrets.GH_PAT_JKL }}" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ -H "Accept: application/vnd.github+json" \ https://api.github.com/repos/${{ github.repository }}/pages/builds diff --git a/build-and-deploy.ps1 b/build-and-deploy.ps1 index 5e373949b..7645259c5 100644 --- a/build-and-deploy.ps1 +++ b/build-and-deploy.ps1 @@ -87,7 +87,7 @@ $ReleaseData = @{ generate_release_notes = $true } $ReleaseResponse = Invoke-RestMethod ` - -Uri "https://api.github.com/repos/jklingen/greenshot/releases" ` + -Uri "https://api.github.com/repos/greenshot/greenshot/releases" ` -Method POST ` -Headers $Headers ` -Body (ConvertTo-Json $ReleaseData -Depth 10) @@ -138,7 +138,7 @@ Write-Host "File uploaded successfully: $FileName" # Step 7: Trigger GitHub Pages Rebuild #Write-Host "Triggering GitHub Pages rebuild..." #Invoke-RestMethod ` -# -Uri "https://api.github.com/repos/jklingen/greenshot/pages/builds" ` +# -Uri "https://api.github.com/repos/greenshot/greenshot/pages/builds" ` # -Method POST ` # -Headers $Headers #if ($LASTEXITCODE -ne 0) { From c8f424b72ee671a2e2470c5df772ea76c473d042 Mon Sep 17 00:00:00 2001 From: jklingen Date: Fri, 16 May 2025 15:49:26 +0200 Subject: [PATCH 215/232] Fix Reference to Token --- .github/workflows/update-gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index a7e2b42cb..71a25b2e7 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -13,6 +13,6 @@ jobs: shell: bash run: | curl -X POST \ - -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ -H "Accept: application/vnd.github+json" \ https://api.github.com/repos/${{ github.repository }}/pages/builds From 15d58880902108bf87c323f20391d4b8b64c03ea Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Fri, 16 May 2025 15:52:31 +0200 Subject: [PATCH 216/232] changed token --- .github/workflows/update-gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index a7e2b42cb..5026ffb18 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -13,6 +13,6 @@ jobs: shell: bash run: | curl -X POST \ - -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "Authorization: Bearer ${{ secrets.GH_PAGES_TOKEN }}" \ -H "Accept: application/vnd.github+json" \ https://api.github.com/repos/${{ github.repository }}/pages/builds From cc063b6426e75be003e54f868b22f4549681077e Mon Sep 17 00:00:00 2001 From: Christian Schulz Date: Wed, 21 May 2025 07:40:19 +0200 Subject: [PATCH 217/232] Calculate optimal font size for StepLabel #457 (#460) --- .../Drawing/StepLabelContainer.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Greenshot.Editor/Drawing/StepLabelContainer.cs b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs index e907d237b..7edecc4f8 100644 --- a/src/Greenshot.Editor/Drawing/StepLabelContainer.cs +++ b/src/Greenshot.Editor/Drawing/StepLabelContainer.cs @@ -24,6 +24,7 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Text; using System.Runtime.Serialization; +using System.Windows.Forms; using Dapplo.Windows.Common.Extensions; using Dapplo.Windows.Common.Structs; using Greenshot.Base.Interfaces; @@ -187,6 +188,8 @@ namespace Greenshot.Editor.Drawing /// public override void Draw(Graphics graphics, RenderMode rm) { + if (Width == 0 || Height == 0) { return; } + graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.CompositingQuality = CompositingQuality.HighQuality; @@ -205,9 +208,17 @@ namespace Greenshot.Editor.Drawing EllipseContainer.DrawEllipse(rect, graphics, rm, 0, Color.Transparent, fillColor, false); } - float fontSize = Math.Min(Math.Abs(Width), Math.Abs(Height)) / 3f; - using FontFamily fam = new FontFamily(FontFamily.GenericSansSerif.Name); - using Font font = new Font(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel); + using FontFamily fam = new(FontFamily.GenericSansSerif.Name); + + //calculate new font size based on ratio from text height and text width + float initialFontSize = Math.Min(Math.Abs(Width), Math.Abs(Height)); + using Font Measurefont = new(fam, initialFontSize, FontStyle.Bold, GraphicsUnit.Pixel); + var fontSize = initialFontSize * TextRenderer.MeasureText(text, Measurefont).Height / TextRenderer.MeasureText(text, Measurefont).Width; + + //static scale for optimal fit + fontSize *= 0.7f; + + using Font font = new(fam, fontSize, FontStyle.Bold, GraphicsUnit.Pixel); TextContainer.DrawText(graphics, rect, 0, lineColor, false, _stringFormat, text, font); } From 95d4c1c2d199bddb0dec1a6b72a34f5464a4e649 Mon Sep 17 00:00:00 2001 From: jklingen Date: Wed, 21 May 2025 12:53:32 +0200 Subject: [PATCH 218/232] Publish Unsigned Release on Commit and Purge CloudFlare Cache on Pages Build (#583) --- .github/workflows/purge-cloudflare-cache.yml | 14 +++ .github/workflows/release.yml | 114 +++++++++---------- installer/innosetup/setup.iss | 15 +-- src/Greenshot/Greenshot.csproj | 2 +- 4 files changed, 80 insertions(+), 65 deletions(-) create mode 100644 .github/workflows/purge-cloudflare-cache.yml diff --git a/.github/workflows/purge-cloudflare-cache.yml b/.github/workflows/purge-cloudflare-cache.yml new file mode 100644 index 000000000..a2d288faf --- /dev/null +++ b/.github/workflows/purge-cloudflare-cache.yml @@ -0,0 +1,14 @@ +name: Purge CloudFlare Cache + +on: + page_build: + +jobs: + purge_cache: + runs-on: ubuntu-latest + steps: + - name: purge + uses: jakejarvis/cloudflare-purge-action@master + env: + CLOUDFLARE_ZONE: ${{ secrets.CLOUDFLARE_ZONE }} + CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 345c0cae9..2ff412d91 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -66,61 +66,61 @@ jobs: name: drop path: ${{ github.workspace }}/artifacts -# deploy: -# runs-on: windows-latest -# needs: build -# -# steps: -# -# - name: Checkout repository -# uses: actions/checkout@v2 -# with: -# fetch-depth: 0 -# -# - name: Download build artifacts -# uses: actions/download-artifact@v4 -# with: -# name: drop Name of the artifact uploaded in previous steps -# path: drop Local folder where artifacts are downloaded -# -# - name: Extract version from file name -# id: extract_version -# run: | -# $file = Get-ChildItem drop -Filter "Greenshot-INSTALLER-*.exe" | Select-Object -First 1 -# if (-not $file) { -# throw "No matching file found in 'drop' directory." -# } -# if ($file.Name -match "Greenshot-INSTALLER-([\d\.]+).*\.exe") { -# echo "version=$($matches[1])" >> $Env:GITHUB_OUTPUT -# } else { -# throw "Version number could not be extracted from file name: $($file.Name)" -# } -# shell: pwsh -# -# - name: Create tag -# run: | -# git config user.name "github-actions[bot]" -# git config user.email "github-actions[bot]@users.noreply.github.com" -# git tag -a "v${{ steps.extract_version.outputs.version }}" -m "v${{ steps.extract_version.outputs.version }}" -# git push origin "v${{ steps.extract_version.outputs.version }}" -# -# - name: Create GitHub Release -# uses: softprops/action-gh-release@v2 -# with: -# name: "Greenshot ${{ steps.extract_version.outputs.version }} unstable" -# tag_name: "v${{ steps.extract_version.outputs.version }}" -# files: drop/*.exe -# generate_release_notes: true -# draft: true -# prerelease: true -# env: -# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -# -# - name: Trigger GitHub Pages rebuild -# shell: bash -# run: | -# curl -X POST \ -# -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ -# -H "Accept: application/vnd.github+json" \ -# https://api.github.com/repos/${{ github.repository }}/pages/builds + deploy: + runs-on: windows-latest + needs: build + + steps: + + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: drop # Name of the artifact uploaded in previous steps + path: drop # Local folder where artifacts are downloaded + + - name: Extract version from file name + id: extract_version + run: | + $file = Get-ChildItem drop -Filter "Greenshot-INSTALLER-*.exe" | Select-Object -First 1 + if (-not $file) { + throw "No matching file found in 'drop' directory." + } + if ($file.Name -match "Greenshot-INSTALLER-([\d\.]+)(.*)\.exe") { + echo "version=$($matches[1])" >> $Env:GITHUB_OUTPUT + } else { + throw "Version number could not be extracted from file name: $($file.Name)" + } + shell: pwsh + + - name: Create tag + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "v${{ steps.extract_version.outputs.version }}" -m "v${{ steps.extract_version.outputs.version }}" + git push origin "v${{ steps.extract_version.outputs.version }}" + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + name: "Greenshot ${{ steps.extract_version.outputs.version }} (continuous build)" + tag_name: "v${{ steps.extract_version.outputs.version }}" + files: drop/*.exe + generate_release_notes: true + draft: false + prerelease: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Trigger GitHub Pages rebuild + shell: bash + run: | + curl -X POST \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github+json" \ + https://api.github.com/repos/${{ github.repository }}/pages/builds diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index fb77b0103..428caa5c0 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -7,6 +7,7 @@ #define BinDir "bin\Release\net472" #define ReleaseDir "..\..\src\Greenshot\bin\Release\net472" #define PluginDir "..\..\src\Greenshot\bin\Release\net472\Plugins" +#define CertumThumbprint GetEnv('CertumThumbprint') ; Include the scripts to install .NET Framework ; See https://www.codeproject.com/KB/install/dotnetfx_innosetup_instal.aspx @@ -132,16 +133,16 @@ InfoBeforeFile=..\additional_files\readme.txt LicenseFile=..\additional_files\license.txt LanguageDetectionMethod=uilanguage MinVersion=6.1sp1 -OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE OutputDir=..\ PrivilegesRequired=lowest SetupIconFile=..\..\src\Greenshot\icons\applicationIcon\icon.ico -; Create a SHA1 signature -; SignTool=SignTool sign /debug /fd sha1 /tr https://time.certum.pl /td sha1 $f -; Append a SHA256 to the previous SHA1 signature (this is what as does) -; SignTool=SignTool sign /debug /as /fd sha256 /tr https://time.certum.pl /td sha256 $f -SignTool=SignTool sign /sha1 "{#GetEnv('CertumThumbprint')}" /tr http://time.certum.pl /td sha256 /fd sha256 /v $f -;SignedUninstaller=yes +#if CertumThumbprint != "" + OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE + SignTool=SignTool sign /sha1 "{#CertumThumbprint}" /tr http://time.certum.pl /td sha256 /fd sha256 /v $f + SignedUninstaller=yes +#else + OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE-UNSIGNED +#endif UninstallDisplayIcon={app}\{#ExeName}.exe Uninstallable=true VersionInfoCompany={#ExeName} diff --git a/src/Greenshot/Greenshot.csproj b/src/Greenshot/Greenshot.csproj index 334bfc0f0..0bda5ae2c 100644 --- a/src/Greenshot/Greenshot.csproj +++ b/src/Greenshot/Greenshot.csproj @@ -76,7 +76,7 @@ - + From 1f0ae08a527cdf61bbab601bc898b7679c57d188 Mon Sep 17 00:00:00 2001 From: Nathan_B <54860453+FF-Brown@users.noreply.github.com> Date: Thu, 22 May 2025 09:42:02 -0700 Subject: [PATCH 219/232] #572 Fix Error when Opening .greenshot File with Arrows --- src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs b/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs index 279e8b1a5..11c7dbae6 100644 --- a/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs +++ b/src/Greenshot.Editor/Helpers/BinaryFormatterHelper.cs @@ -54,6 +54,7 @@ namespace Greenshot.Editor.Helpers {"System.Collections.Generic.List`1[[Greenshot.Base.Interfaces.Drawing.IField", typeof(List)}, {"System.Collections.Generic.List`1[[System.Drawing.Point", typeof(List)}, {"Greenshot.Editor.Drawing.ArrowContainer", typeof(ArrowContainer) }, + {"Greenshot.Editor.Drawing.ArrowContainer+ArrowHeadCombination", typeof(ArrowContainer.ArrowHeadCombination) }, {"Greenshot.Editor.Drawing.LineContainer", typeof(LineContainer) }, {"Greenshot.Editor.Drawing.TextContainer", typeof(TextContainer) }, {"Greenshot.Editor.Drawing.SpeechbubbleContainer", typeof(SpeechbubbleContainer) }, From 6400b08a8cffdb62fd81ed6c95ee5771feb1c3c7 Mon Sep 17 00:00:00 2001 From: Julien Richard Date: Fri, 23 May 2025 14:43:28 +0200 Subject: [PATCH 220/232] Fix scaling with fixed ratio (#514) --- src/Greenshot.Editor/Helpers/ScaleHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Greenshot.Editor/Helpers/ScaleHelper.cs b/src/Greenshot.Editor/Helpers/ScaleHelper.cs index 8403bd939..8e4a76a13 100644 --- a/src/Greenshot.Editor/Helpers/ScaleHelper.cs +++ b/src/Greenshot.Editor/Helpers/ScaleHelper.cs @@ -202,7 +202,7 @@ namespace Greenshot.Editor.Helpers { // scaled rectangle (ratio) would be taller than original // keep width and tweak height to maintain aspect ratio - newSize = newSize.ChangeWidth(selectedSize.Width / originalRatio * flippedRatioSign); + newSize = newSize.ChangeHeight(selectedSize.Width / originalRatio * flippedRatioSign); } return newSize; From 789a5697060cc2f6f21d71bcf2b9fc6ae08a379a Mon Sep 17 00:00:00 2001 From: Jens Glathe Date: Fri, 23 May 2025 14:55:54 +0200 Subject: [PATCH 221/232] fix: handle picky Win11 ToastNotificationService (#487) --- .../ToastNotificationService.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Greenshot.Plugin.Win10/ToastNotificationService.cs b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs index b9120fee7..52005356c 100644 --- a/src/Greenshot.Plugin.Win10/ToastNotificationService.cs +++ b/src/Greenshot.Plugin.Win10/ToastNotificationService.cs @@ -95,7 +95,17 @@ namespace Greenshot.Plugin.Win10 } // Prepare the toast notifier. Be sure to specify the AppUserModelId on your application's shortcut! - var toastNotifier = ToastNotificationManagerCompat.CreateToastNotifier(); + Microsoft.Toolkit.Uwp.Notifications.ToastNotifierCompat toastNotifier = null; + try + { + toastNotifier = ToastNotificationManagerCompat.CreateToastNotifier(); + } + catch (Exception ex) + { + Log.Warn("Could not create a toast notifier.", ex); + + return; + } // Here is an interesting article on reading the settings: https://www.rudyhuyn.com/blog/2018/02/10/toastnotifier-and-settings-careful-with-non-uwp-applications/ try From 8e98cdbfb55440d68617854fc35e4c3ed1fa8b3a Mon Sep 17 00:00:00 2001 From: Nathan_B <54860453+FF-Brown@users.noreply.github.com> Date: Fri, 23 May 2025 06:02:44 -0700 Subject: [PATCH 222/232] Add Hotkey for Resize Button in Editor (#480) --- src/Greenshot.Editor/Forms/ImageEditorForm.cs | 3 +++ src/Greenshot/Languages/language-ca-CA.xml | 2 +- src/Greenshot/Languages/language-cs-CZ.xml | 2 +- src/Greenshot/Languages/language-de-DE.xml | 2 +- src/Greenshot/Languages/language-en-US.xml | 2 +- src/Greenshot/Languages/language-fr-FR.xml | 2 +- src/Greenshot/Languages/language-id-ID.xml | 2 +- src/Greenshot/Languages/language-it-IT.xml | 2 +- src/Greenshot/Languages/language-ja-JP.xml | 2 +- src/Greenshot/Languages/language-kab-DZ.xml | 2 +- src/Greenshot/Languages/language-ko-KR.xml | 2 +- src/Greenshot/Languages/language-lv-LV.xml | 2 +- src/Greenshot/Languages/language-nl-NL.xml | 2 +- src/Greenshot/Languages/language-pt-PT.xml | 2 +- src/Greenshot/Languages/language-sv-SE.xml | 2 +- src/Greenshot/Languages/language-uk-UA.xml | 2 +- src/Greenshot/Languages/language-zh-TW.xml | 2 +- 17 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/Greenshot.Editor/Forms/ImageEditorForm.cs b/src/Greenshot.Editor/Forms/ImageEditorForm.cs index 87c3813c7..97263d8c2 100644 --- a/src/Greenshot.Editor/Forms/ImageEditorForm.cs +++ b/src/Greenshot.Editor/Forms/ImageEditorForm.cs @@ -1023,6 +1023,9 @@ namespace Greenshot.Editor.Forms case Keys.C: BtnCropClick(sender, e); break; + case Keys.Z: + BtnResizeClick(sender, e); + break; } } else if (e.Modifiers.Equals(Keys.Control)) diff --git a/src/Greenshot/Languages/language-ca-CA.xml b/src/Greenshot/Languages/language-ca-CA.xml index 423c55006..323f7849f 100644 --- a/src/Greenshot/Languages/language-ca-CA.xml +++ b/src/Greenshot/Languages/language-ca-CA.xml @@ -305,7 +305,7 @@ Malgrat això, encara es poden utilitzar totes les característiques de Greensho Afegeix un comptador (I) Afegeix una bafarada (S) - Canvia la mida + Canvia la mida (Z) Configuració del canvi de mida Manté la relació d'aspecte Amplada diff --git a/src/Greenshot/Languages/language-cs-CZ.xml b/src/Greenshot/Languages/language-cs-CZ.xml index 86d7f2207..cc409c66f 100644 --- a/src/Greenshot/Languages/language-cs-CZ.xml +++ b/src/Greenshot/Languages/language-cs-CZ.xml @@ -308,7 +308,7 @@ Všechny funkce Greenshotu jsou stále dostupné přímo z místní nabídky bez Přidat počítadlo (I) Přidat textovou bublinu (S) - Změnit velikost + Změnit velikost (Z) Nastavení změny velikosti Zachovat poměr stran Šířka diff --git a/src/Greenshot/Languages/language-de-DE.xml b/src/Greenshot/Languages/language-de-DE.xml index a50ad0119..b636da112 100644 --- a/src/Greenshot/Languages/language-de-DE.xml +++ b/src/Greenshot/Languages/language-de-DE.xml @@ -312,7 +312,7 @@ Sie können aber auch alle Greenshot-Funktionen über das Kontextmenü des Green Zähler hinzufügen (I) Sprechblase hinzufügen (S) - Skalieren + Skalieren (Z) Einstellungen für Skalierung Seitenverhältnis beibehalten Breite diff --git a/src/Greenshot/Languages/language-en-US.xml b/src/Greenshot/Languages/language-en-US.xml index 5cac2280d..1403d3e9c 100644 --- a/src/Greenshot/Languages/language-en-US.xml +++ b/src/Greenshot/Languages/language-en-US.xml @@ -312,7 +312,7 @@ All Greenshot features still work directly from the tray icon context menu witho Add counter (I) Add speechbubble (S) - Resize + Resize (Z) Resize settings Maintain aspect ratio Width diff --git a/src/Greenshot/Languages/language-fr-FR.xml b/src/Greenshot/Languages/language-fr-FR.xml index 50cde5788..4ef502438 100644 --- a/src/Greenshot/Languages/language-fr-FR.xml +++ b/src/Greenshot/Languages/language-fr-FR.xml @@ -144,7 +144,7 @@ De plus, nous apprécierions beaucoup que vous preniez la peine de vérifier si Imprimer Rétablir {0} Réinitialiser la taille - Redimensionner + Redimensionner (Z) Maintenir le rapport L / H Hauteur Pourcentage diff --git a/src/Greenshot/Languages/language-id-ID.xml b/src/Greenshot/Languages/language-id-ID.xml index df31cd624..fcb887082 100644 --- a/src/Greenshot/Languages/language-id-ID.xml +++ b/src/Greenshot/Languages/language-id-ID.xml @@ -144,7 +144,7 @@ Juga, kami sangat terbantu apabila anda mengecek laporan lain yang sama dengan k Cetak Ulang {0} Reset ukuran - Ubah ukuran + Ubah ukuran (Z) Pertahankan aspek rasio Tinggi Persen diff --git a/src/Greenshot/Languages/language-it-IT.xml b/src/Greenshot/Languages/language-it-IT.xml index b0cb0e96f..89d68c988 100644 --- a/src/Greenshot/Languages/language-it-IT.xml +++ b/src/Greenshot/Languages/language-it-IT.xml @@ -322,7 +322,7 @@ In alternativa alle scorciatoie di tastiera, tutte le funzioni di Greenshot sono Aggiungi conteggio Aggiungi nuvoletta - Ridimensiona + Ridimensiona (Z) Impostazioni ridimensionamento Mantieni rapporto dimensioni Larghezza diff --git a/src/Greenshot/Languages/language-ja-JP.xml b/src/Greenshot/Languages/language-ja-JP.xml index 03638f0dc..36f5231f2 100644 --- a/src/Greenshot/Languages/language-ja-JP.xml +++ b/src/Greenshot/Languages/language-ja-JP.xml @@ -143,7 +143,7 @@ Greenshot には一切の保障がありません。GNU General Public License 印刷 やり直し{0} サイズをリセット - リサイズ + リサイズ (Z) 縦横比を維持する 高さ パーセント diff --git a/src/Greenshot/Languages/language-kab-DZ.xml b/src/Greenshot/Languages/language-kab-DZ.xml index e3366a18a..8a690952c 100644 --- a/src/Greenshot/Languages/language-kab-DZ.xml +++ b/src/Greenshot/Languages/language-kab-DZ.xml @@ -144,7 +144,7 @@ Rnu ɣur-s, nḥemmel aṭas ma yella tesneqdeḍ aneqqis igebren ugur-agi. (Tze Siggez Err-d {0} Wennez teɣzi - Snifel tahri/teɣzi + Snifel tahri/teɣzi (Z) Eǧǧ afmiḍi Teɣ / Teh Awrir Afmiḍi diff --git a/src/Greenshot/Languages/language-ko-KR.xml b/src/Greenshot/Languages/language-ko-KR.xml index 0bf90570e..144188ad8 100644 --- a/src/Greenshot/Languages/language-ko-KR.xml +++ b/src/Greenshot/Languages/language-ko-KR.xml @@ -304,7 +304,7 @@ ${hostname} PC명 카운터 더하기 (I) 설명선 더하기(S) - 크기조정 + 크기조정 (Z) 크기조정 설정 종횡비 유지 너비 diff --git a/src/Greenshot/Languages/language-lv-LV.xml b/src/Greenshot/Languages/language-lv-LV.xml index acbe9eacb..dea057944 100644 --- a/src/Greenshot/Languages/language-lv-LV.xml +++ b/src/Greenshot/Languages/language-lv-LV.xml @@ -306,7 +306,7 @@ Arī bez karstiem taustiņiem visas darbības iespējams veikt izmantojot „Gre Pievienot skaitli (I) Pievienot teksta norādi (S) - Mainīt izmēru + Mainīt izmēru (Z) Izmēra maiņas iestatījumi Saglabāt izmēru attiecības Platums diff --git a/src/Greenshot/Languages/language-nl-NL.xml b/src/Greenshot/Languages/language-nl-NL.xml index 65c008c01..d640b0a42 100644 --- a/src/Greenshot/Languages/language-nl-NL.xml +++ b/src/Greenshot/Languages/language-nl-NL.xml @@ -307,7 +307,7 @@ Alle Greenshot functies werken ook zonder sneltoetsen via het context menu.Teller toevoegen (I) Tekstballon toevoegen (S) - Grootte + Grootte (Z) Vergrotingsinstellingen Verhouding behouden Breedte diff --git a/src/Greenshot/Languages/language-pt-PT.xml b/src/Greenshot/Languages/language-pt-PT.xml index 53a3ea424..4da21743d 100644 --- a/src/Greenshot/Languages/language-pt-PT.xml +++ b/src/Greenshot/Languages/language-pt-PT.xml @@ -305,7 +305,7 @@ Todas as funcionalidades do Greenshot funcionam directamente através do menu de Adicionar contador (I) Adicionar balão de texto (S) - Redimensionar + Redimensionar (Z) Definições de Redimensionamento Manter proporções Largura diff --git a/src/Greenshot/Languages/language-sv-SE.xml b/src/Greenshot/Languages/language-sv-SE.xml index c67bfe8fe..c5b1517e2 100644 --- a/src/Greenshot/Languages/language-sv-SE.xml +++ b/src/Greenshot/Languages/language-sv-SE.xml @@ -305,7 +305,7 @@ Alla Greenshots funktioner fungerar fortfarande från snabbmenyn i aktivitetsfä Lägg till räknare Lägg till pratbubbla - Anpassa storlek + Anpassa storlek (Z) Storleksinställningar Behåll bildförhållande Bredd diff --git a/src/Greenshot/Languages/language-uk-UA.xml b/src/Greenshot/Languages/language-uk-UA.xml index 1eae26c97..057927676 100644 --- a/src/Greenshot/Languages/language-uk-UA.xml +++ b/src/Greenshot/Languages/language-uk-UA.xml @@ -306,7 +306,7 @@ ${hostname} назва комп’ютера Додати лічильник (Ш) Додати словесну бульбашку (І) - Змінити розмір + Змінити розмір (Z) Параметри зміни розміру Зберігати пропорції Ширина diff --git a/src/Greenshot/Languages/language-zh-TW.xml b/src/Greenshot/Languages/language-zh-TW.xml index 69f5e6696..63f8fce2f 100644 --- a/src/Greenshot/Languages/language-zh-TW.xml +++ b/src/Greenshot/Languages/language-zh-TW.xml @@ -307,7 +307,7 @@ Greenshot 所有功能仍然可以直接從通知區圖示的內容功能表動 加入計數器 (I) 加入對話框 (S) - 縮放 + 縮放 (Z) 縮放設定 維持長寬比 長度 From af04773497cad50baa509ad86d5fd44eac1d48c6 Mon Sep 17 00:00:00 2001 From: jklingen Date: Tue, 15 Jul 2025 12:38:22 +0200 Subject: [PATCH 223/232] Add workflow_dispatch Trigger to Build and Deploy Workflow --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2ff412d91..06bc7342a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,7 @@ name: Build and Deploy on: + workflow_dispatch: push: branches: - 'release/1.*' From 2121547387e8867ba4f379fc5f8a7f1bcdd45982 Mon Sep 17 00:00:00 2001 From: Thomas Braun Date: Wed, 16 Jul 2025 12:11:18 +0200 Subject: [PATCH 224/232] added PrivilegesRequiredOverridesAllowed=commandline --- installer/innosetup/setup.iss | 1 + 1 file changed, 1 insertion(+) diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index 428caa5c0..6bb0d0fe5 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -135,6 +135,7 @@ LanguageDetectionMethod=uilanguage MinVersion=6.1sp1 OutputDir=..\ PrivilegesRequired=lowest +PrivilegesRequiredOverridesAllowed=commandline SetupIconFile=..\..\src\Greenshot\icons\applicationIcon\icon.ico #if CertumThumbprint != "" OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE From dbfdfe9a05d19da557f8350e6de815df3774724e Mon Sep 17 00:00:00 2001 From: jklingen Date: Thu, 17 Jul 2025 17:40:11 +0200 Subject: [PATCH 225/232] Chore: Enhance Github Pages Rebuild Trigger with other release types ... to make sure the list on the website is always up to date, without manual interaction. --- .github/workflows/update-gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-gh-pages.yml b/.github/workflows/update-gh-pages.yml index 5026ffb18..ba45b70d1 100644 --- a/.github/workflows/update-gh-pages.yml +++ b/.github/workflows/update-gh-pages.yml @@ -3,7 +3,7 @@ name: Update GitHub Pages on: workflow_dispatch: release: - types: [published] + types: [published, unpublished, created, edited, deleted, prereleased, released] jobs: update-gh-pages: From aa98a7ce789d1beaf486f40c845c0fe62cd8d27d Mon Sep 17 00:00:00 2001 From: jklingen Date: Fri, 18 Jul 2025 11:24:21 +0200 Subject: [PATCH 226/232] Add Trademark and Logo Usage Policy --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 90fff9b6f..a3e9696c7 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,25 @@ Being easy to understand and configurable, Greenshot is an efficient tool for pr About this repository --------------------- -This repository is for Greenshot 1.3, currently in development, but is the next planned release +This is the development branch is for Greenshot 1.3, which has been first released on 2025-07-14. Releases -------- You can find a list of all releases (stable and unstable) in the [Github releases](https://github.com/greenshot/greenshot/releases) or in the [version history on our website](https://getgreenshot.org/version-history/). The [downloads page on our website](https://getgreenshot.org/downloads/) always links to the latest stable release. + +Trademark and Logo Usage Policy +------------------------------- + +The Greenshot logo and trademark are the property of the Greenshot development team. Unauthorized use of the logo and trademark is generally prohibited. However, we allow the use of the Greenshot name and logo in the following contexts: + +* In blog posts, articles, or reviews that discuss or promote the Greenshot, provided that the usage is fair and does not imply endorsement by Greenshot. +* In educational materials or presentations that accurately represent the project. + +Please refrain from using the Greenshot logo and trademark in any promotional materials, products, or in a manner that may cause confusion or imply endorsement without prior written permission. + +If you have any questions or wish to seek permission for other uses, please contact us. + +Thank you for your understanding and cooperation. + From 7360791872538a0e3d15ec8d058b9b875107dfce Mon Sep 17 00:00:00 2001 From: jklingen Date: Thu, 24 Jul 2025 18:04:11 +0200 Subject: [PATCH 227/232] Add Possibility to Publish Test Releases from Branches (#631) ... without causing a mess and a lot of confusion by using the same build numbers as in release branch. --- .github/workflows/release.yml | 48 ++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 06bc7342a..9a92223ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,7 @@ +env: + IS_RELEASE_BRANCH: ${{ startsWith(github.ref, 'refs/heads/release/') }} + BRANCH_NAME: ${{ github.ref_name }} + name: Build and Deploy on: @@ -5,6 +9,12 @@ on: push: branches: - 'release/1.*' + paths-ignore: + - '.github/**' + - '.gitignore' + - '*.md' + - 'LICENSE' + - 'build-and-deploy.ps1' jobs: build: @@ -85,7 +95,8 @@ jobs: path: drop # Local folder where artifacts are downloaded - name: Extract version from file name - id: extract_version + if: env.IS_RELEASE_BRANCH == 'true' + id: version_from_filename run: | $file = Get-ChildItem drop -Filter "Greenshot-INSTALLER-*.exe" | Select-Object -First 1 if (-not $file) { @@ -97,22 +108,47 @@ jobs: throw "Version number could not be extracted from file name: $($file.Name)" } shell: pwsh + + - name: Set version from sanitized branch name + if: env.IS_RELEASE_BRANCH != 'true' + id: version_from_branchname + run: | + $branch = "${{ github.ref }}" -replace '^refs/heads/', '' + $sanitized = $branch -replace '[^a-zA-Z0-9._-]', '_' + echo "version=$sanitized" >> $Env:GITHUB_OUTPUT + shell: pwsh + + - name: Set version info + id: version_info + run: | + echo "version=${{ steps.version_from_filename.outputs.version || steps.version_from_branchname.outputs.version }}" >> $GITHUB_OUTPUT + shell: bash + - name: Create tag + if: env.IS_RELEASE_BRANCH == 'true' run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git tag -a "v${{ steps.extract_version.outputs.version }}" -m "v${{ steps.extract_version.outputs.version }}" - git push origin "v${{ steps.extract_version.outputs.version }}" + git tag -a "v${{ steps.version_info.outputs.version }}" -m "v${{ steps.version_info.outputs.version }}" + git push origin "v${{ steps.version_info.outputs.version }}" + + - name: Rename installer for non-release branch + if: env.IS_RELEASE_BRANCH != 'true' + run: | + branch="${BRANCH_NAME:-${GITHUB_REF#refs/heads/}}" + sanitized=$(echo "$branch" | sed 's/[^a-zA-Z0-9._-]/_/g') + mv drop/Greenshot-INSTALLER-*.exe "drop/Greenshot-INSTALLER-${sanitized}.exe" + shell: bash - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: - name: "Greenshot ${{ steps.extract_version.outputs.version }} (continuous build)" - tag_name: "v${{ steps.extract_version.outputs.version }}" + name: "Greenshot ${{ steps.version_info.outputs.version }} (continuous build)" + tag_name: ${{ env.IS_RELEASE_BRANCH == 'true' && format('v{0}', steps.version_info.outputs.version) || env.BRANCH_NAME }} files: drop/*.exe generate_release_notes: true - draft: false + draft: ${{ env.IS_RELEASE_BRANCH != 'true' }} prerelease: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From dbbfbb654e7f3640d3fe66459f75d7f8988fe170 Mon Sep 17 00:00:00 2001 From: jklingen Date: Sat, 26 Jul 2025 16:17:08 +0200 Subject: [PATCH 228/232] Installer: Allow Choice between All-Users (Administrative) and Current-User Installation #625 (#641) Also fixes #546, #611, #598 --- installer/innosetup/setup.iss | 45 ++++++++++------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/installer/innosetup/setup.iss b/installer/innosetup/setup.iss index 6bb0d0fe5..fa358ee7b 100644 --- a/installer/innosetup/setup.iss +++ b/installer/innosetup/setup.iss @@ -127,15 +127,19 @@ AppVersion={#Version} ArchitecturesInstallIn64BitMode=x64 Compression=lzma2/ultra64 SolidCompression=yes -DefaultDirName={code:DefDirRoot}\{#ExeName} +DefaultDirName={autopf}\{#ExeName} DefaultGroupName={#ExeName} InfoBeforeFile=..\additional_files\readme.txt LicenseFile=..\additional_files\license.txt LanguageDetectionMethod=uilanguage MinVersion=6.1sp1 OutputDir=..\ +; user may choose between all-users vs. current-user installation in a dialog or by using the /ALLUSERS flag (on the command line) +; in registry section, HKA will take care of the appropriate root key (HKLM vs. HKCU), see https://jrsoftware.org/ishelp/index.php?topic=admininstallmode +PrivilegesRequiredOverridesAllowed=dialog +; admin privileges not required, unless user chooses all-users installation +; the installer will ask for elevation if needed PrivilegesRequired=lowest -PrivilegesRequiredOverridesAllowed=commandline SetupIconFile=..\..\src\Greenshot\icons\applicationIcon\icon.ico #if CertumThumbprint != "" OutputBaseFilename={#ExeName}-INSTALLER-{#Version}-UNSTABLE @@ -155,6 +159,7 @@ VersionInfoVersion={#Version} WizardImageFile=installer-large.bmp ; Reference a bitmap, max size 55x58 WizardSmallImageFile=installer-small.bmp + [Registry] ; Delete all startup entries, so we don't have leftover values Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; @@ -173,24 +178,16 @@ Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: none; ValueName: {#E Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: none; ValueName: {#ExeName}; Flags: deletevalue noerror; ; Create the startup entries if requested to do so -; HKEY_LOCAL_USER - for current user only -Root: HKCU; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: """{app}\{#ExeName}.exe"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: IsRegularUser -; HKEY_LOCAL_MACHINE - for all users when admin -Root: HKLM; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: """{app}\{#ExeName}.exe"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Tasks: startup; Check: not IsRegularUser +Root: HKA; Subkey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: {#ExeName}; ValueData: """{app}\{#ExeName}.exe"""; Flags: uninsdeletevalue noerror; Tasks: startup ; Register our own filetype for all users -; HKEY_LOCAL_USER - for current user only -Root: HKCU; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser -Root: HKCU; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser -Root: HKCU; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE,0"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser -Root: HKCU; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: users-modify; Flags: uninsdeletevalue noerror; Check: IsRegularUser +Root: HKA; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Flags: uninsdeletevalue noerror +Root: HKA; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Flags: uninsdeletevalue noerror +Root: HKA; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE,0"""; Flags: uninsdeletevalue noerror +Root: HKA; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Flags: uninsdeletevalue noerror + ; Disable the default PRTSCR Snipping Tool in Windows 11 Root: HKCU; Subkey: Control Panel\Keyboard; ValueType: dword; ValueName: "PrintScreenKeyForSnippingEnabled"; ValueData: "0"; Flags: uninsdeletevalue; Check: ShouldDisableSnippingTool -; HKEY_LOCAL_MACHINE - for all users when admin -Root: HKLM; Subkey: Software\Classes\.greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser -Root: HKLM; Subkey: Software\Classes\Greenshot; ValueType: string; ValueName: ""; ValueData: "Greenshot File"; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser -Root: HKLM; Subkey: Software\Classes\Greenshot\DefaultIcon; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE,0"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser -Root: HKLM; Subkey: Software\Classes\Greenshot\shell\open\command; ValueType: string; ValueName: ""; ValueData: """{app}\Greenshot.EXE"" --openfile ""%1"""; Permissions: admins-modify; Flags: uninsdeletevalue noerror; Check: not IsRegularUser [Icons] Name: {group}\{#ExeName}; Filename: {app}\{#ExeName}.exe; WorkingDir: {app}; AppUserModelID: "{#ExeName}" @@ -541,22 +538,6 @@ Name: "languages\zhCN"; Description: {cm:zhCN}; Types: full custom; Flags: disab Name: "languages\zhTW"; Description: {cm:zhTW}; Types: full custom; Flags: disablenouninstallwarning; Check: hasLanguageGroup('9') [Code] -// Do we have a regular user trying to install this? -function IsRegularUser(): Boolean; -begin - Result := not (IsAdmin or IsAdminInstallMode); -end; - -// The following code is used to select the installation path, this is localappdata if non poweruser -function DefDirRoot(Param: String): String; -begin - if IsRegularUser then - Result := ExpandConstant('{localappdata}') - else - Result := ExpandConstant('{pf}') -end; - - function FullInstall(Param : String) : String; begin result := SetupMessage(msgFullInstallation); From e81abdcd7bb15714ee408922ddb4d31a14f3d178 Mon Sep 17 00:00:00 2001 From: jklingen Date: Sat, 9 Aug 2025 16:29:55 +0200 Subject: [PATCH 229/232] Chore: Update Change Log with Latest Releases --- installer/additional_files/readme.txt | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/installer/additional_files/readme.txt b/installer/additional_files/readme.txt index 1215789b6..6b558bda2 100644 --- a/installer/additional_files/readme.txt +++ b/installer/additional_files/readme.txt @@ -7,7 +7,28 @@ CHANGE LOG: All details to our tickets can be found here: https://greenshot.atlassian.net -# Release notes for Greenshot 1.3 +# Greenshot 1.x.xxx + +Bugs fixed: + +Features added: + +# Greenshot 1.3.296 + +Bugs fixed +* Fix Administrative installation via user interface [#546](https://github.com/greenshot/greenshot/issues/546) [#611](https://github.com/greenshot/greenshot/issues/611) [#598](https://github.com/greenshot/greenshot/issues/598) + +Features added: +* Installer: Allow Choice between All-Users (Administrative) and Current-User Installation [#625](https://github.com/greenshot/greenshot/pull/625) + +# Greenshot 1.3.292 + +Bugs fixed: +* Fix Administrative installation via command line using /ALLUSERS [#601](https://github.com/greenshot/greenshot/issues/601) [#619](https://github.com/greenshot/greenshot/issues/619) + +# Greenshot 1.3.290 + +Note: the version information for the first 1.3 release is outdated/incomplete. Due to the long timespan and large amount of changes between 1.2 and 1.3 we lost track. Sorry. Greenshot 1.3 is the first Greenshot which targets .NET 4.7.2 which just by doing to solves some general issues in the area of Internet Explorer capturing, TLS communication and some other minor issues. @@ -646,3 +667,4 @@ Features added: * when clicking two overlapping elements, the one created later gets selected [ 1725175 ] * created textboxes can now be edited with a doubleclick [ 1704408 ] * selected font is now stored in the application config file [ 1704411 ] + From b69c415669600361e43065772f182d093d40923e Mon Sep 17 00:00:00 2001 From: Christian Schulz Date: Sat, 9 Aug 2025 16:38:32 +0200 Subject: [PATCH 230/232] Fix: Define plugin name for exclusion in INI (#644) Fixes #642 #648 --- .../AssemblyPluginIdentifierAttribute.cs | 46 ++++++++++++++ .../Properties/AssemblyInfo.cs | 2 + .../Properties/AssemblyInfo.cs | 34 ++++++++++ .../Properties/AssemblyInfo.cs | 2 + .../Properties/AssemblyInfo.cs | 34 ++++++++++ .../Properties/AssemblyInfo.cs | 2 + .../Properties/AssemblyInfo.cs | 5 ++ .../Properties/AssemblyInfo.cs | 2 + .../Properties/AssemblyInfo.cs | 34 ++++++++++ .../Properties/AssemblyInfo.cs | 2 + .../Properties/AssemblyInfo.cs | 2 + .../Properties/AssemblyInfo.cs | 25 +++++++- src/Greenshot/Helpers/PluginHelper.cs | 62 ++++++++++++++++--- 13 files changed, 243 insertions(+), 9 deletions(-) create mode 100644 src/Greenshot.Base/Interfaces/Plugin/AssemblyPluginIdentifierAttribute.cs create mode 100644 src/Greenshot.Plugin.Confluence/Properties/AssemblyInfo.cs create mode 100644 src/Greenshot.Plugin.ExternalCommand/Properties/AssemblyInfo.cs create mode 100644 src/Greenshot.Plugin.Jira/Properties/AssemblyInfo.cs diff --git a/src/Greenshot.Base/Interfaces/Plugin/AssemblyPluginIdentifierAttribute.cs b/src/Greenshot.Base/Interfaces/Plugin/AssemblyPluginIdentifierAttribute.cs new file mode 100644 index 000000000..2be14c7a8 --- /dev/null +++ b/src/Greenshot.Base/Interfaces/Plugin/AssemblyPluginIdentifierAttribute.cs @@ -0,0 +1,46 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2025 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; + +namespace Greenshot.Base.Interfaces.Plugin +{ + /// + /// Attribute to specify a custom plugin identifier at assembly level + /// + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] + public class AssemblyPluginIdentifierAttribute : Attribute + { + /// + /// The identifier used for the plugin in configuration + /// + public string Identifier { get; } + + /// + /// Constructor for the plugin identifier attribute + /// + /// The identifier for the plugin in configuration + public AssemblyPluginIdentifierAttribute(string identifier) + { + Identifier = identifier; + } + } +} \ No newline at end of file diff --git a/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs index 2ffb6f6fd..0379e4a65 100644 --- a/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Box/Properties/AssemblyInfo.cs @@ -21,11 +21,13 @@ using System.Reflection; using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyDescription("A plugin to upload images to Box")] +[assembly: AssemblyPluginIdentifier("Box Plugin")] // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. diff --git a/src/Greenshot.Plugin.Confluence/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Confluence/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..8d2833e17 --- /dev/null +++ b/src/Greenshot.Plugin.Confluence/Properties/AssemblyInfo.cs @@ -0,0 +1,34 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2021 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Reflection; +using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyDescription("A plugin to upload images to Confluence")] +[assembly: AssemblyPluginIdentifier("Confluence Plugin")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs index d01359e25..b95b9af6d 100644 --- a/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Dropbox/Properties/AssemblyInfo.cs @@ -21,11 +21,13 @@ using System.Reflection; using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyDescription("A plugin to upload images to Dropbox")] +[assembly: AssemblyPluginIdentifier("Dropbox Plugin")] // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. diff --git a/src/Greenshot.Plugin.ExternalCommand/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.ExternalCommand/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..acbe80370 --- /dev/null +++ b/src/Greenshot.Plugin.ExternalCommand/Properties/AssemblyInfo.cs @@ -0,0 +1,34 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2025 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Reflection; +using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyDescription("A plugin to send screenshots to other applications")] +[assembly: AssemblyPluginIdentifier("External command Plugin")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs index 30eafc83e..9701ef654 100644 --- a/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Flickr/Properties/AssemblyInfo.cs @@ -21,11 +21,13 @@ using System.Reflection; using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyDescription("A plugin to upload images to Flickr")] +[assembly: AssemblyPluginIdentifier("Flickr Plugin")] // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. diff --git a/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs index a49045818..3ff014500 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.GooglePhotos/Properties/AssemblyInfo.cs @@ -21,12 +21,17 @@ using System.Reflection; using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyDescription("A plugin to upload images to GooglePhotos")] +// Still using the old name 'Picasa-Web Plugin' as identifier for backwards compatibility +// TODO: replace plugin identifier with "GooglePhotos Plugin" in the future +[assembly: AssemblyPluginIdentifier("Picasa-Web Plugin")] + // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. [assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs index befa881fd..4f9d4afb5 100644 --- a/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Imgur/Properties/AssemblyInfo.cs @@ -21,11 +21,13 @@ using System.Reflection; using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyDescription("A plugin to upload images to Imgur")] +[assembly: AssemblyPluginIdentifier("Imgur Plugin")] // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. diff --git a/src/Greenshot.Plugin.Jira/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Jira/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..44f8800ce --- /dev/null +++ b/src/Greenshot.Plugin.Jira/Properties/AssemblyInfo.cs @@ -0,0 +1,34 @@ +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2025 Thomas Braun, Jens Klingen, Robin Krom, Francis Noel + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Reflection; +using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyDescription("A plugin to upload images to Jira")] +[assembly: AssemblyPluginIdentifier("Jira Plugin")] + +// This sets the default COM visibility of types in the assembly to invisible. +// If you need to expose a type to COM, use [ComVisible(true)] on that type. +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs index 9dcc75892..6b14a40f5 100644 --- a/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Office/Properties/AssemblyInfo.cs @@ -21,11 +21,13 @@ using System.Reflection; using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyDescription("A plugin to export images to Office applications")] +[assembly: AssemblyPluginIdentifier("Office Plugin")] // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. diff --git a/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs index 783762320..231ca594d 100644 --- a/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Photobucket/Properties/AssemblyInfo.cs @@ -21,12 +21,14 @@ using System.Reflection; using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyDescription("A plugin to upload images to Photobucket")] +[assembly: AssemblyPluginIdentifier("Photobucket Plugin")] // This sets the default COM visibility of types in the assembly to invisible. // If you need to expose a type to COM, use [ComVisible(true)] on that type. diff --git a/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs b/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs index d1b6cbd1b..3f4b5bef2 100644 --- a/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs +++ b/src/Greenshot.Plugin.Win10/Properties/AssemblyInfo.cs @@ -1,10 +1,33 @@ -using System.Reflection; +/* + * Greenshot - a free and open source screenshot tool + * Copyright (C) 2007-2025 Thomas Braun, Jens Klingen, Robin Krom + * + * For more information see: https://getgreenshot.org/ + * The Greenshot project is hosted on GitHub https://github.com/greenshot/greenshot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System.Reflection; using System.Runtime.InteropServices; +using Greenshot.Base.Interfaces.Plugin; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyDescription("A plug-in for Windows 10 only functionality")] +[assembly: AssemblyPluginIdentifier("Win10 Plugin")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/src/Greenshot/Helpers/PluginHelper.cs b/src/Greenshot/Helpers/PluginHelper.cs index 3ed3d97c3..e5724a4f5 100644 --- a/src/Greenshot/Helpers/PluginHelper.cs +++ b/src/Greenshot/Helpers/PluginHelper.cs @@ -219,17 +219,14 @@ namespace Greenshot.Helpers { var assembly = Assembly.LoadFrom(pluginFile); - var assemblyName = assembly.GetName().Name; - - var pluginEntryName = $"{assemblyName}.{assemblyName.Replace("Greenshot.Plugin.", string.Empty)}Plugin"; - var pluginEntryType = assembly.GetType(pluginEntryName, false, true); - - if (CoreConfig.ExcludePlugins != null && CoreConfig.ExcludePlugins.Contains(pluginEntryName)) + if (IsPluginExcludedByConfig(assembly, pluginFile) ) { - Log.WarnFormat("Exclude list: {0}", string.Join(",", CoreConfig.ExcludePlugins)); - Log.WarnFormat("Skipping the excluded plugin {0} with version {1} from {2}", pluginEntryName, assembly.GetName().Version, pluginFile); continue; } + + var assemblyName = assembly.GetName().Name; + var pluginEntryName = $"{assemblyName}.{assemblyName.Replace("Greenshot.Plugin.", string.Empty)}Plugin"; + var pluginEntryType = assembly.GetType(pluginEntryName, false, true); var plugin = (IGreenshotPlugin) Activator.CreateInstance(pluginEntryType); if (plugin != null) @@ -255,5 +252,54 @@ namespace Greenshot.Helpers } } } + /// + /// This method checks the plugin against the configured include and exclude plugin + /// lists. If a plugin is excluded, a warning is logged with details about the exclusion. + /// + private bool IsPluginExcludedByConfig(Assembly assembly, string pluginFile) + { + // Get plugin identifier from assembly attributes + string pluginConfigIdentifier = GetPluginIdentifier(assembly, pluginFile); + + if (CoreConfig.IncludePlugins is { } includePlugins + && includePlugins.Count(p => !string.IsNullOrWhiteSpace(p)) > 0 // ignore empty entries i.e. a whitespace + && !includePlugins.Contains(pluginConfigIdentifier)) + { + Log.WarnFormat("Include plugin list: {0}", string.Join(",", includePlugins)); + Log.WarnFormat("Skipping the not included plugin '{0}' with version {1} from {2}", pluginConfigIdentifier, assembly.GetName().Version, pluginFile); + return true; + } + + if (CoreConfig.ExcludePlugins is { } excludePlugins + && excludePlugins.Contains(pluginConfigIdentifier)) + { + Log.WarnFormat("Exclude plugin list: {0}", string.Join(",", excludePlugins)); + Log.WarnFormat("Skipping the excluded plugin '{0}' with version {1} from {2}", pluginConfigIdentifier, assembly.GetName().Version, pluginFile); + return true; + } + + return false; + } + + /// + /// Retrieves the plugin identifier for the specified assembly. + /// + private string GetPluginIdentifier(Assembly assembly, string pluginFile) + { + // Try to find PluginIdentifierAttribute + var attribute = assembly + .GetCustomAttributes() + .FirstOrDefault(); + + if (!string.IsNullOrEmpty(attribute?.Identifier)) + { + return attribute.Identifier; + } + + // If no attribute found, fall back to the sub namespace + var pluginSubNamespace = assembly.GetName().Name.Replace("Greenshot.Plugin.", string.Empty); + Log.WarnFormat("No '{0}' found in '{1}'. Use plugin namespace '{2}' as fallback.", nameof(AssemblyPluginIdentifierAttribute), pluginFile, pluginSubNamespace); + return pluginSubNamespace; + } } } \ No newline at end of file From 82702c4830ab07314b8ea0ea1bcefe2e99044127 Mon Sep 17 00:00:00 2001 From: jklingen Date: Sat, 9 Aug 2025 16:43:42 +0200 Subject: [PATCH 231/232] Chore: Update Change Log --- installer/additional_files/readme.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/installer/additional_files/readme.txt b/installer/additional_files/readme.txt index 6b558bda2..bdb64e2c4 100644 --- a/installer/additional_files/readme.txt +++ b/installer/additional_files/readme.txt @@ -7,9 +7,10 @@ CHANGE LOG: All details to our tickets can be found here: https://greenshot.atlassian.net -# Greenshot 1.x.xxx +# Greenshot 1.3.xxx Bugs fixed: +* greenshot.ini: Exclude Plugins and Include Plugins setting broken [#648](https://github.com/greenshot/greenshot/issues/648) [#642](https://github.com/greenshot/greenshot/issues/642) thanks to @Christian-Schulz for providing the fix Features added: @@ -668,3 +669,4 @@ Features added: * created textboxes can now be edited with a doubleclick [ 1704408 ] * selected font is now stored in the application config file [ 1704411 ] + From c1ad1d4a9309cab26143ad4ee8b239ff1686c491 Mon Sep 17 00:00:00 2001 From: jklingen Date: Sun, 10 Aug 2025 17:11:30 +0200 Subject: [PATCH 232/232] Remove Debug Info from Release Builds --- src/Greenshot.Base/Greenshot.Base.csproj | 4 ++++ src/Greenshot.Editor/Greenshot.Editor.csproj | 4 ++++ src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj | 4 ++++ .../Greenshot.Plugin.Confluence.csproj | 4 ++++ src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj | 4 ++++ .../Greenshot.Plugin.ExternalCommand.csproj | 4 ++++ src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj | 4 ++++ .../Greenshot.Plugin.GooglePhotos.csproj | 4 ++++ src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj | 4 ++++ src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj | 4 ++++ src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj | 4 ++++ .../Greenshot.Plugin.Photobucket.csproj | 4 ++++ src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj | 4 ++++ src/Greenshot/Greenshot.csproj | 4 ++++ 14 files changed, 56 insertions(+) diff --git a/src/Greenshot.Base/Greenshot.Base.csproj b/src/Greenshot.Base/Greenshot.Base.csproj index 7e55c1dbc..550682cd0 100644 --- a/src/Greenshot.Base/Greenshot.Base.csproj +++ b/src/Greenshot.Base/Greenshot.Base.csproj @@ -3,6 +3,10 @@ true + + none + false + diff --git a/src/Greenshot.Editor/Greenshot.Editor.csproj b/src/Greenshot.Editor/Greenshot.Editor.csproj index 7da9d555d..5dcd99bc1 100644 --- a/src/Greenshot.Editor/Greenshot.Editor.csproj +++ b/src/Greenshot.Editor/Greenshot.Editor.csproj @@ -2,6 +2,10 @@ True + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj index fced869ad..2b3410c8f 100644 --- a/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj +++ b/src/Greenshot.Plugin.Box/Greenshot.Plugin.Box.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj b/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj index d885ea3f5..0734c44e9 100644 --- a/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj +++ b/src/Greenshot.Plugin.Confluence/Greenshot.Plugin.Confluence.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj index 09eb988a5..7437b64aa 100644 --- a/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj +++ b/src/Greenshot.Plugin.Dropbox/Greenshot.Plugin.Dropbox.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj b/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj index 50e39b62a..d0151b7c0 100644 --- a/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj +++ b/src/Greenshot.Plugin.ExternalCommand/Greenshot.Plugin.ExternalCommand.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj index 5bc629bf1..8bdb8bcb4 100644 --- a/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj +++ b/src/Greenshot.Plugin.Flickr/Greenshot.Plugin.Flickr.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj index f2bfb8be5..154410dd2 100644 --- a/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj +++ b/src/Greenshot.Plugin.GooglePhotos/Greenshot.Plugin.GooglePhotos.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj index e0696e270..5cb8e0baa 100644 --- a/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj +++ b/src/Greenshot.Plugin.Imgur/Greenshot.Plugin.Imgur.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj index a06e33882..d38eb063a 100644 --- a/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj +++ b/src/Greenshot.Plugin.Jira/Greenshot.Plugin.Jira.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj index 347a58339..982b86833 100644 --- a/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj +++ b/src/Greenshot.Plugin.Office/Greenshot.Plugin.Office.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj index 50e39b62a..d0151b7c0 100644 --- a/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj +++ b/src/Greenshot.Plugin.Photobucket/Greenshot.Plugin.Photobucket.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj index c1c1729e0..14126adb3 100644 --- a/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj +++ b/src/Greenshot.Plugin.Win10/Greenshot.Plugin.Win10.csproj @@ -1,4 +1,8 @@  + + none + false + PreserveNewest diff --git a/src/Greenshot/Greenshot.csproj b/src/Greenshot/Greenshot.csproj index 0bda5ae2c..f0d97afe9 100644 --- a/src/Greenshot/Greenshot.csproj +++ b/src/Greenshot/Greenshot.csproj @@ -9,6 +9,10 @@ false false + + none + false +